go to post Julius Kavay · Mar 23, 2020 $listbuild() and all other functions, like $length(), $char() etc. are (I call them) basic functions of COS and have nothing to do with objects. The language of Cache (and of course IRIS ) handles data as raw (basic) data and not as objects, like some other (but not all) languages. For example, in JavaScript you can do var text="Some text"; alert("'" + text + "' has "+text.length + " characters"); alert("'Some text' has " + "Some text".length + " characters"); because both, a (text)variable and a (text)string have an (object)property name 'length'. Beside the raw data type COS also has object data type and most of the standard COS functions will accept an object property as argument, for example: Class Test.Class Extends %RegisteredObject { Property Data as %String; } set text="Some text" set obj = ##class(Test.Class).%New() set obj.Data = "Some text"; write $length(text),! write $length(obj.Data),!
go to post Julius Kavay · Mar 19, 2020 JavaScript, as your code shows, is compiled and executed on client side (in the browser). The part of the code #()# you use is CSP (CacheServerPages), which is compiled and prepared by the server for execution by client. Hence, you can't use the #()# syntax in a pure JavaScript code.
go to post Julius Kavay · Mar 17, 2020 $lb(data1, data2, data3, ... dataN) is built as a string of item1 item2 item3 ... itemN itemN:= <len> <type> <dataN> assuming, you are on a little-endian CPU and l1 = $length(data) l2 = l1 + 1 // for type byte l3 = l2 + 1 // for the length itself then the length is as follows if l1<=253 then len: <l3> elseif l1<=65534 len:= <0> <l2-lowbyte> <l2-highbyte> else len:= <0> <0> <0> <l2-lowbyte-loworderword> ... <l2-highbyte-highorderword> And don't forget,$lb(123) is not the same as $lb(1230/10), hence we have a $ls() function!
go to post Julius Kavay · Mar 14, 2020 set x="1.2.3", y=$name(tmp) for i=1:1:$length(x,".") { set y=$name(@y@($piece(x,".",i))) } set @y="" kill x,y,i You can put al the above in one line, if you are in terminal. Or put it in a method ClassMethod setTemp(x) [ PublicList = tmp] { set y=$name(tmp) for i=1:1:$length(x,".") { set y=$name(@y@($piece(x,".",i))) } set @y="" } Or you take the shorthand set x="1.2.3", @("tmp("_$tr(x,".",",")_")=""""") But this works only as long as x contains number_period_numeber_period_...No leading zeros, no alphabetics...
go to post Julius Kavay · Jan 12, 2020 A warning about long time open transactions will be placed in cconsole.log and alerts.log (both files in $system.Util.InstallDirectory()_"mgr" directory) - at least this is the case what I see on a customers system. The entries look like this: 04/05/19-02:31:34:470 (21012) 1 [SYSTEM MONITOR] TransOpenSecs Warning: One or more transactions open longer than 10 minutes. Process id 18624 22208 (only top 5 shown) 08/29/19-14:31:03:802 (18576) 1 [SYSTEM MONITOR] TransOpenSecs Warning: One or more transactions open longer than 10 minutes. Process id 4128 (only top 5 shown) 09/04/19-17:16:19:090 (21344) 1 [SYSTEM MONITOR] TransOpenSecs Warning: One or more transactions open longer than 10 minutes. Process id 25872 (only top 5 shown) So it should be as easy as monitoring those two logfiles. But how it looks like on an ECP server, don't ask me.
go to post Julius Kavay · Dec 21, 2019 I'm not that java guy, so just a hint only. There should be a public static java.lang.String PetNameLogicalToDisplay(...) method, so use/call this method to display your pets.
go to post Julius Kavay · Sep 22, 2019 If your routine works in a terminal session (by issuing a DO ^Routinname command) but does not work, when the same routine is started via the Job commannd (JOB ^Routinname) then you lack something in background, what you have in the foreground. Put an errortrap in your routine and simple report a possible error (and if you wich, additionally the execution progress of your routine). rvExt2012 ; Test set $zt="bgErr" // ... // ... do signal("checkpoint 1") // this is optional // ... // ... do signal("checkpoint 2") // this is optional // ... // ... do signal("Done") quit bgErr do signal("Error: "_$ze) quit signal(msg) do $system.Event.Signal($zp, $username_", "_$roles_", "_msg) quit Now, in the terminal session enter following line job ^rvExt2012 do { set $lb(s,m)=$system.Event.WaitMsg("",1) write m,! } while s
go to post Julius Kavay · Sep 14, 2019 A little bit $translate(), a little bit of $zstrip() and the job is done (in the example below, I want to keep parenthesis) set str="abcd(123)/,op(56)*&^%$987ABC" write $tr(str,$zstrip(str,"*AN","()"),$j("",$l(str))) what to keep generell ------^^^ what to keep extra --------------^^
go to post Julius Kavay · Sep 10, 2019 The intention behind my post was, to give you one idea (of many other possibilities), how to convert XML to CSV. A empty (chars) element is just one of some other unhandled cases (missing tags, other tags inside of COLx tag, etc.).If you need some speed and your XML-File obeys following constraints:- the file is a correct XML-File- contains only the 'Data', 'Details' and 'ColX' tags- no selfclosing tags, like <sometag/>then you could try the QAD-way (quick-and-dirty) of conversion.Again, below an example routine (without excessive testing).All ISC people and ordinary programer, please look the other way ;-)) Convert() Public { set len=32000 // chunk size, a safe value is: // 32767 - longestColumnValue - tagSizes set fi="c:\temp\example-t.xml" // inp file (xml) set fo="c:\temp\example-t.csv" // output file (csv) open fi:"ru":1 open:$t fo:"nw":1 if '$t close fi quit set xml=$$inp(fi,len) // first xml-chunk set i=0, p=0 while 1 { set i=$locate(xml,"\<\/?\w+\>",i,j,v) // next (opening or closing) tag if i { // let see, what we got if v="<Details>" { set row="", p=-1 // start a new row } elseif v="</Details>" { d out(fo,row) s p=0 // complete, write out } elseif p,v["<Col" { s p=j, o=$zstrip(v,"*AP") // new column, keep start } elseif p,v["</Col" {s $li(row,o)=$$val($e(xml,p,i-1)) // get value } // everything else is don't care set i=j } else { set tmp=$$inp(fi,len) // next xml-chunk if tmp="" quit // done // remove processed data, add new one if p>0 { set xml=$e(xml,p,*)_tmp,p=1,i=0 } else { s xml=$e(xml,i,*)_tmp,i=0 } } } close fi close fo } val(val) { quit $zstrip(val,"<>w") // add handling of charcter entities like < etc. } out(fo,row) { use fo write $listtostring(row,";",1),! // delimiter! } inp(fn,len) { use fn try { read xml#len } catch { s xml="" } // in case, $zeof-mode is off quit xml } The above converter reads a simple test XML-file with two million 'ColX' items in 5 seconds and creates a CSV file with 100000 rows and 20 columns (in each row). Instead of file you can also use an stream.
go to post Julius Kavay · Sep 8, 2019 The short answer is: NO.The long answer is:if you try to make a trick, like the below code: it won't work. ClassMethod name() { set mynull={"def":null} set result={"value1":123, "value2":(mynull.def) } quit result } now the surprise: write mynull.%GetTypeOf("def") ---> null write result.%GetTypeOf("value2") --> string
go to post Julius Kavay · Aug 13, 2019 If you work in Cache-Terminal, go to: ManagementPortal-->SystemAdmin-->Configurations-->DeviceSettings-->DeviceSubtypes Select: C-Cache-Terminal, click on Edit Go to bottom line (Caption: ZUFormFeed) and change the value from $C(27,91,72,27,91,74) to your needs. For example, if you want to retain the first and the second lines, to: $C(27,91,51,59,48,72,27,91,74). In case, your device type is not the Cache-Terminal, search for your device in ManagementPortal-->SystemAdmin-->Configurations-->DeviceSettings-->Devices Select your device, for example TERM, |TNT| or whatever device type you have. Click on edit and notice the Sub-Type. Now, as above, go to the sub-types, and change the ZUFormFeed field. In case, you wont find your device and/or device sub-type, there is a direct way too, to set the desired FormFeed (i.e. write #) and the Backspace behavior: do ##class(%Device).SetFFBS($C(27,91,51,59,48,72,27,91,74),$c(8,32,8)) The first sequence, as the method name implies, is the FormFeed sequence and the second is the Backspace sequence
go to post Julius Kavay · Aug 13, 2019 If you have your binary or character data in (sequential) global nodes, then: - create your own stream clas -in the %OnNew() method fetch the data from your global and voila, you are ready to use your data with stream methods. set ^mydata(1)="abcd" set ^mydata(2)="efgh" set ^yourdata("id",1)="1234" set ^yourdata("id",2)="5678" Class Test.Stream Extends %Stream.TmpBinary { Method %OnNew(Global, initval As %String = "") As %Status [ Private ] { Set i%%Location=$select(initval="":$$$streamGlobal,1:initval) do ..Clear() for set Global=$query(@Global,1,data) quit:Global="" do ..Write(data) do ..Rewind() Quit $$$OK } } set stream=##class(Test.Stream).%New($na(^mydata)) while 'stream.AtEnd { write stream.Read(5) } abcdefgh set stream=##class(Test.Stream).%New($na(^yourdata("id"))) while 'stream.AtEnd { write stream.Read(5) } 12345678
go to post Julius Kavay · Aug 10, 2019 set a=1.2 // your numberwrite a\1+''(a#1) // this is a NOT NOT and not a quote!
go to post Julius Kavay · Mar 13, 2019 As Jeffrey already wrote, this is charCode x2022 (hex) but take a look at https://www.unicode.org/Public/12.0.0/charts/CodeCharts.pdf There you will find many punctuation and mathematical characters and geometric shapes. For web developers, this is like the land of plenty. My favorit characters are x2700 - x27ff (hex, of course) ✔ ✘ ✆ etc.
go to post Julius Kavay · Mar 1, 2019 The correct way is: ClassMethod ind() [ PublicList = (active,reactive) ] { new active,reactive kill info // the above command (kill info) is a kind of NOP (no-operation) // at the time of entry into a methode there are no variables, // except those in the public list (if defined) set active = 1 set reactive = 2 for i="active","reactive" { set info(i)= @i } zw info break } If you want to use name-indirection in a procedure block, then - variables, used by indirection, must be made public (via PublicList) - and, depending on the situation, should be saved with the NEW command
go to post Julius Kavay · Feb 21, 2019 Maybe you want something like this: set data1 = "%sqlcq.something.value.foo" set data2 = "sqlcq.something.value.bar" for x=data1, data2 { if x ? .1"%"1"sqlcq".e { write "OK" } else { write "NOT" } w ! } Your output should be: OK OK Regards
go to post Julius Kavay · Jan 17, 2019 "like a centipede with a wooden leg: 99 times tic and 1 toc the stream is then truncated and still requires extra coding" That's the whole point! If we turncate the stream to $$$MaxStringLength, no matter where (in a calculated property or in a GETter method), just to present this (string)value to a variable, a function or whatever, then we can instantly stick to a string. By the way, it's possible to store $$$MaxStringLength bytes in a local or global variable. Properties of classes are stored in globals as $listelements, so the maxlength for a single string property depends on things like count and types of other properties in the class and not least, does this class extends %Persistent or extends another class(es) which extends %Persistent - in this case we need some extra bytes for those (extended) class names too.
go to post Julius Kavay · Sep 27, 2018 HANG command exists. You can put between each command (if you have enought time ;-)) ) an hang command: while response.StringValue="Processing" { hang 5 // pause for 5 seconds // get new response } Regards and have a nice day Julius
go to post Julius Kavay · Sep 20, 2018 Hello Kevin, if I anderstand you correctly, several your Cache systems (development, life, ...) will store their files on a third server (possibly on a file server) and you want to put the files from each (source) Cache (instance) into a different (target) folder, where the folder name being the "name" of the source Cache system - am I correct? If yes, I think, your best choice ist: ...\hostNameOfCache\instanceNameofCache... or, as John Murray suggested ...\GUIDofCacheInstance... or just a fixed string like ...\kevinNotebook(development)... You can put (John's) GUID or my "fixed string" in a (possibly system) Global like ^%Zconfig("path")=... Why? Things like MAC- or IP-Addresses can change more often then you think. Especially IP-Addresses will change, hence are there DNS servers. On the other hand, it's uncommon to change host- or instance names (of Cache or of whatever installation). Your IP-Address preference has an other downside too. Many servers have more then one IP-Address (and if they do not have one today, maybe tomorrow!). If you persist to take the systems IP-Address, here is, what you wanted: set iplist = $system.INetInfo.GetListOfConfiguredInterfaces(0) for i = 1:1:$listlength(iplist) zw $list(iplist,i) Regards and have a nice day Julius
go to post Julius Kavay · Sep 14, 2018 You can do it either this way: set OrgTypeId = $piece(line, ",", 2) // assuming, item 2 is an OID of ZenCrm.OrgType if ##class(ZenCrm.OrgType).ExistsId(OrgTypeId) { set rec.OrgType = ##class(ZenCrm.OrgType).%OpenId(OrgTypeId,0) } or this way: do rec.OrgTypeSetObjectId($piece(line, ",", 2))