Robert Cemper · Mar 8, 2019 go to post

Hi Tim

write $d(^|"%SYS"|SYS("Security","SSLConfigsD",<my config> ),settings)

provided you have access rights

Cheers, Robert

Robert Cemper · Mar 4, 2019 go to post

You have to set your DB to be in Primary MIRROR before the copy.
Otherwise, you may miss some kind of "Mirror-Marker" / Timestamp. 

I hit this trap also on my first trials.

Robert Cemper · Mar 2, 2019 go to post

I just realized that this method doesn't check the existence of the ID.

therefore:

write:##class(Abstract.Class).%ExistsId(id) $li(##class(Abstract.Class).%ComposeOid(id),2)

or any equivalent construct.

Robert Cemper · Mar 2, 2019 go to post

OID contains the class name. So this should do it.

write $li(##class(Abstract.Class).%ComposeOid(id),2)

Robert Cemper · Mar 2, 2019 go to post

You are totally right.

With Parent-Child your data are not only logical but also physically tied to each other.

One-to-many allows you more flexible handling of Relations.

Just one out of many examples   M:N Relationship

Robert Cemper · Mar 1, 2019 go to post

Exactly 4 weeks before UK is leaving the European Union on Friday, March 29th this sounds like kind of British humor to me.

Robert Cemper · Feb 25, 2019 go to post

Thanks @Jeffrey Drumm  !

I always distrusted HL7 separators and ESC chars. when I first met them ages back as they carry the same limit as $PIECE() with them:
"There is always somewhere some odd case where your separator turns up as content. "  
Praise $LB()  wink !  
 

Robert Cemper · Feb 25, 2019 go to post
set remove="\E"
set hl7="OBX|1|RP|ECG||CARDIO ECG^APPLICATION^PDF^^\E\\E\sitehopital.org\E\files\E\cardio\E\022018\E\GE274583.PDF|"
set clean=$replace(hl7,remove,"")
 write clean
OBX|1|RP|ECG||CARDIO ECG^APPLICATION^PDF^^\\sitehopital.org\files\cardio\022018\GE274583.PDF|
Robert Cemper · Feb 21, 2019 go to post

for that case passing the variables by reference should be sufficient. 

ClassMethod Main() 
{
    Do ..InvokedMethod(,var1,.var2)
    W !,var1
}
ClassMethod InvokedMethod(byRef var1, byRef var2) 
{
    Set var1 = "ChangedInInvoked"
}
Robert Cemper · Feb 21, 2019 go to post

I see 5 options :

  • any classmethod can be projected as SQL Procedure. So using your ODBC adapter you may communicate that way with Caché
    based on rather poor personal experience of PHP & ODBC it is definitely not my favorite.
  • With Angular & PHP you are in the Web environment. So SOAP Webservices may be useful.
    I had a very positive experience with that approach. see it here  Feeling the power of Caché
  • Actually I would rather use REST in combination with JSON
  • If rather synchronous interaction between both sides is required AJAX (+JSON) could be a way 
  • Or for longer lasting asynchronous communication WebSockets might be appropriate.

So you have a choice what fits best to your needs.

Robert Cemper · Feb 19, 2019 go to post

interesting observation  with CHPC 65001:

a loop USER>for i=1:1:255 write i," ",$c(i),!   stops the session with any character > $c(127).

I'd suggest forget that M$ crap.
Use Putty or any thing else.

Cache for Windows (x86-64) 2018.1.1 (Build 312U) Thu Jan 3 2019 14:34:00 EST

Robert Cemper · Feb 19, 2019 go to post

BTW.

zwrite @reader.GlobalName

USER>zwrite @reader.GlobalName
^||CacheTemp=5
^||CacheTemp(5,1)=$lb("element","","Oceano","Oceano",0,1)
^||CacheTemp(5,2)=$lb("element","","Header","Header",0,2)
^||CacheTemp(5,3)=$lb("element","","DataSource","DataSource",0,3)
^||CacheTemp(5,4)=$lb("chars","Oceano","")
^||CacheTemp(5,5)=$lb("endelement","","DataSource","DataSource")
^||CacheTemp(5,6)=$lb("element","","DataType","DataType",0,3)
^||CacheTemp(5,7)=$lb("chars","EDAttendance","")
^||CacheTemp(5,8)=$lb("endelement","","DataType","DataType")
^||CacheTemp(5,9)=$lb("endelement","","Header","Header")
^||CacheTemp(5,10)=$lb("element","","Body","Body",0,2)
^||CacheTemp(5,11)=$lb("element","","MIU","MIU",0,3)
^||CacheTemp(5,12)=$lb("element","","Department","Department",0,4)
^||CacheTemp(5,13)=$lb("chars","BCH","")
^||CacheTemp(5,14)=$lb("endelement","","Department","Department")
^||CacheTemp(5,15)=$lb("element","","TotalNumber","TotalNumber",0,4)
^||CacheTemp(5,16)=$lb("chars","6","")
^||CacheTemp(5,17)=$lb("endelement","","TotalNumber","TotalNumber")
^||CacheTemp(5,18)=$lb("element","","NumberWaitingToBeSeen","NumberWaitingToBeSeen",0,4)
^||CacheTemp(5,19)=$lb("endelement","","NumberWaitingToBeSeen","NumberWaitingToBeSeen")
^||CacheTemp(5,20)=$lb("element","","LongestWaitMin","LongestWaitMin",0,4)
^||CacheTemp(5,21)=$lb("endelement","","LongestWaitMin","LongestWaitMin")
^||CacheTemp(5,22)=$lb("endelement","","MIU","MIU")
^||CacheTemp(5,23)=$lb("element","","MIU","MIU",0,3)
^||CacheTemp(5,24)=$lb("element","","Department","Department",0,4)
^||CacheTemp(5,25)=$lb("chars","BOS","")
^||CacheTemp(5,26)=$lb("endelement","","Department","Department")
^||CacheTemp(5,27)=$lb("element","","TotalNumber","TotalNumber",0,4)
^||CacheTemp(5,28)=$lb("chars","1","")
^||CacheTemp(5,29)=$lb("endelement","","TotalNumber","TotalNumber")
^||CacheTemp(5,30)=$lb("element","","NumberWaitingToBeSeen","NumberWaitingToBeSeen",0,4)
^||CacheTemp(5,31)=$lb("chars","1","")
^||CacheTemp(5,32)=$lb("endelement","","NumberWaitingToBeSeen","NumberWaitingToBeSeen")
^||CacheTemp(5,33)=$lb("element","","LongestWaitMin","LongestWaitMin",0,4)
^||CacheTemp(5,34)=$lb("chars","109293","")
^||CacheTemp(5,35)=$lb("endelement","","LongestWaitMin","LongestWaitMin")
^||CacheTemp(5,36)=$lb("endelement","","MIU","MIU")
^||CacheTemp(5,37)=$lb("endelement","","Body","Body")
^||CacheTemp(5,38)=$lb("endelement","","Oceano","Oceano")

Robert Cemper · Feb 19, 2019 go to post

structure is OK, and it worked for me.

Removing all CR,LF,TAB,BLANK still looks good here. 
Could you have some control  characters in your string ?

USER>ZZDUMP myfile may show it

USER>write $TR(myfile,$c(13,10,9,32))
<Oceano><Header><DataSource>Oceano</DataSource><DataType>EDAttendance</DataType></Header><Body><MIU><Department>BCH</Department><TotalNumber>6</TotalNumber><NumberWaitingToBeSeen/><LongestWaitMin/></MIU><MIU><Department>BOS</Department><TotalNumber>1</TotalNumber><NumberWaitingToBeSeen>1</NumberWaitingToBeSeen><LongestWaitMin>109293</LongestWaitMin></MIU></Body></Oceano>

Robert Cemper · Feb 18, 2019 go to post

By XML bit I understand you have some myfile="<mynode>anytext</mynode>" or similar in hands

so this should cover your needs:

USER>set sc=##class(%XML.TextReader).ParseString(myfile,.reader)
USER>zwrite @reader.GlobalName
^||CacheTemp=1
^||CacheTemp(1,1)=$lb("element","","mynode","mynode",0,1)
^||CacheTemp(1,2)=$lb("chars","anytext","")
^||CacheTemp(1,3)=$lb("endelement","","mynode","mynode")

or is the content of myfile something else ?? 

Robert Cemper · Feb 12, 2019 go to post

First, CACHETEMP doesn't maintain a Journal. (could be a minor advantage) .

Second, CACHETEMP follows a different storage strategy as it is kept in memory (global buffers) as long as affordable.
While for the other DBs data (global buffer blocks) get written to disk as soon as possible it is the opposite for CACHETEMP.

Third, CACHETEMP is common to all namespaces.

Forth, CACHETEMP is cleared at every restart and total empty after.
 I doubt that this could be useful in an ECP setup. 

Robert Cemper · Feb 12, 2019 go to post

to my understanding, there is no technical limit.
Though I believe to remember that it used to be ~16.000 some time in past.

Class SYS.Database maps to ^SYS("CONFIG","IRIS","Databases",<DBNAME>) and has NO  limit there

similar Namespaces are stored in SYS("CONFIG","IRIS","Namespaces",<NSPCE>) an are covered by %SYS.Namespace

If there is any limit it must be related to internal memory structures.  (gmheap ??)

Robert Cemper · Feb 6, 2019 go to post

In addition to the reply from @Evgeny Shvarov  :

INT is highly important to identify error locations.
eg. <DIVIDE>label+5^routinename refers to the location in routinename.INT  

Robert Cemper · Feb 5, 2019 go to post

Out of curiosity, I have built a  more exotic solution that is easier to understand. (At least for me)
I don't like so much this protocol upgrade stuff and encrypting and simulation of a browser.

My personal workaround:

  • start browser over ZF(-1, "start chrome http://.................my csp......")
  • the page gets my request passed with the URL. very simple just as a Hash
  • the page does all the WS stuff via JavaScript
  • the reply is returned using Hyperevent #call(....) 

It works fine and is rather "classic CSP" style.

Robert Cemper · Feb 5, 2019 go to post

OK.

I tried it and found:  sock.Open(  does not accept "/ws/v2/?&token=<token>"  only the server name

USER>set sock = ##class(%IO.Socket).%New()
USER>do sock.Open("localhost/csp/samples/Web.SocketTest.cls",8080,5,.sc)  //// >>> Timeout
/// but this works
USER>do sock.Open("10.10.12.87",57772,5,.sc) zw sc
sc=1
USER>zw sock
sock=<OBJECT REFERENCE>[2@%IO.Socket]
+----------------- general information ---------------
|      oref value: 2
|      class name: %IO.Socket
| reference count: 2
+----------------- attribute values ------------------
|        (%Attached) = ""
|(%CurrLineTerminator) = ""
|              AtEnd = 0
|       CharEncoding = "Native"  <Set>
|               Host = "10.10.12.87"
|    InputBufferSize = 32767
|             IsOpen = 1  <Get>
|       IsSingleByte = ""
|  KeepAliveInterval = 0
|     LineTerminator = $c(10)
|     LocalInterface = ""
|               Name = "|TCP|57772|20242"
|   OutputBufferSize = 32767
|               Port = 57772
|             Remote = "2019-02-05 10:33:35.212|10.10.12.87:57772"
|          SSLConfig = ""
|   TCPReceiveBuffer = 0
|      TCPSendBuffer = 0
|   TranslationTable = "RAW"  <Set>
+----------------- swizzled references ---------------
|i%DisconnectHandler = ""
|r%DisconnectHandler = ""
+--------------- calculated references ---------------
|DefaultFlushOnWrite   <Get>
|        IsCharacter   <Get>
+-----------------------------------------------------
USER>

Now you have the connection BUT no server to take care of it as you see:

USER>do sock.WriteLine("/csp/samples/Web.SocketTest.cls",1,.sc) zw sc
sc=1
USER>write sock.ReadAny(32000,5,.rSC) zw rSC
HTTP/0.9 404 Stream Not Found
Content-Type: text/html; charset=utf-8
Date: Tue, 05 Feb 2019 10:45:16 GMT
Expires: Tue, 05 Feb 2019 11:45:16 GMT
rSC=1


Investigating the browser it became clear what's going on:
- you begin with HTTP to start your WebSocketServer
- an then initiate the WS connection.

This is the output from TcpTrace: 

>>>>>  GET /csp/samples/websocketdemo.csp HTTP/1.1 >> .......

>>>>>  GET /csp/samples/Web.SocketTest.cls HTTP/1.1  >> ... >> Upgrade: websocket

That's my point:
      With the actual approach starting the requres WS Server is missing. 

Robert Cemper · Feb 4, 2019 go to post

To me, this looks like your port doesn't like WS as initial connection protocol but expect the switch from HTTPS -> WSS or the port is just wrong.

several suggestions for the investigation to get it moving:

#1) verify your server from a normal web page (e.g. based websocketdem.csp in Samples) especially the port !!!!

#2) If you have control over your server then skip SSL and get running over HTTP -> WS first. You can add this once it works.

#3) If you have no server just use Caché / SAMPLES /  Web.SocketTest.cls 
I found it very useful to have control over both ends and now I own several variants for testing.

Staying tuned yes