go to post Jeffrey Drumm · Jul 16, 2019 Just an observation ... generally speaking, the reasoning behind the repetition delimiters in OBX:5 is to provide a form of line-orientation to the resulted report; sort of like <br/> tags in HTML. The receiving system can use these as guidelines for displaying text that should display as separate lines. The repetitions are rarely more than 80 characters long, the "standard" reading width for a fixed-pitch terminal. "Empty" delimiters ("~~") often serve to indicate paragraph endings, aka "blank lines."Separating the repetitions into individual segments is also a common method of keeping report formatting intact. However, I've yet to see a vendor expecting each segment to represent a "paragraph."I'm concerned that the vendor you're working with will be presenting the result report in a format other than as intended by the source.
go to post Jeffrey Drumm · Jul 16, 2019 I updated my comment and turned it into an answer ... with DTL rather than ObjectScript since I didn't realize that was the specific type of solution you were looking for. Let me know if that doesn't get you where you need to be ...
go to post Jeffrey Drumm · Jul 16, 2019 Is that screen shot from the Ensemble Message Viewer? If yes, than what you're seeing is Ensemble's visualization of an empty field/component/subcomponent/repetition. The tilde (~) character is the repetition delimiter at the field level; InterSystems uses the "·" character as an indicator that the repetition was left empty. There's no actual character there to split on, but you can certainly iterate through repetitions within OBX:5 and build a new message segment for each.The DTL would be something like this:
go to post Jeffrey Drumm · Jul 9, 2019 OK, it's quick and dirty and I'm probably doing something that will make the old-timers here laugh hysterically, but it works. The caveats are:It only cares about word wrapping on the space character. Punctuation adjacent to non-space characters will stay with the adjacent characters.It totally ignores things like \.br\ tags. they're just text as far as it's concerned.It returns a $LIST, where each list element is a line of text from the source string, no longer than the width specified. You can iterate through it with $LISTNEXT or $LISTGET and populate your OBX segments, but you'll probably have to do that in a CODE rule.So anyway ... ClassMethod WordWrap(pTxt As %String, pWidth As %Integer) As %List { If $LENGTH(pTxt) > pWidth { set tLine = "" Set tCnt = 0 Set tWordList = $LFS(pTxt," ") Set tListLen = $LISTLENGTH(tWordList) Set tWordPtr = 0 Set tWordCur = "" While $LISTNEXT(tWordList,tWordPtr,tWordCur) { If $LENGTH(tLine_tWordCur) > pWidth { Set $LIST(tList,*+1) = $ZSTRIP(tLine,">W") Set tLine = tWordCur_" " Set tLastCnt = tCnt } Else { Set tLine = tLine_tWordCur_" " } Set tCnt = tCnt + 1 } } Else { Set tList = $LB(pTxt) Set (tLastCnt,tListLen) = 0 } If tLastCnt < tListLen { Set $LIST(tList,*+1) = $LTS($LIST(tWordList,tLastCnt + 1,tListLen)," ") } Return tList } Have fun!
go to post Jeffrey Drumm · Jul 8, 2019 Scott, is there any requirement that this field be split along word boundaries such as whitespace and punctuation characters? That makes it a bit more challenging :)
go to post Jeffrey Drumm · Jul 3, 2019 No impact that I've seen. It simply adds a button to the Message Viewer that displays the SQL used to select the message list.
go to post Jeffrey Drumm · Jul 3, 2019 So ... before you go changing those globals (if you haven't done so already), try TIE> do ##class(Ens.Queue).AbortQueue("queuename") Once you've turned down all of the inbound services/processes. If that doesn't work, use my previous suggestion. I do think you should shut down the services and processes feeding the routers. And it wouldn't hurt to shut down the routers as well. If the count is still at 1 after you do that, set the value to 0. And I actually think that the job IDs are from the source services and processes, not the routers themselves.
go to post Jeffrey Drumm · Jul 3, 2019 I'm reasonably confident this will fix the issue without any side effects ... TIE> Set ^Ens.Queue("ClinicomMsgRouter",0,"count")=0 TIE> Set ^Ens.Queue("PathologyRouter",0,"count")=0 Question though ... do you have the pool size for these routers set higher than 1? I'm concerned about the number of job entries under each queue. This could have an impact on FIFO, and may have something to do with the erroneous queue counts.
go to post Jeffrey Drumm · Jul 2, 2019 From the Cache prompt in your production's namespace, what do you see when you type: PROD> zw ^Ens.Queue("QueueName") ? Replace QueueName with the name of the queue in question ...
go to post Jeffrey Drumm · Jul 2, 2019 Hi Ed,If you have the Show Query option enabled in Message Viewer, you can build your criteria for extracting the message data there, then click the button to see the SQL it generates. The default EnsLib.HL7.SearchTable indexes the Patient ID, but it includes PID:2.1, PID:3.1 (all iterations) and PID:4.1 (all iterations). If you're searching for specific IDs or ranges you may get unintended duplicates.You don't need a custom SearchTable to filter the messages, but it sure helps.If you don't have it enabled, you can turn it on for your production's namespace: USER > zn "PROD" PROD > set ^Ens.Debug("UtilEnsMessages","sql")=1 The Message Viewer is a powerful tool and gives you access for query and display of every HL7 field. The SQL it generates should put you on the right track.
go to post Jeffrey Drumm · Jul 2, 2019 So when you select the queue in the Queues page, it shows no messages in the Queue Contents column?
go to post Jeffrey Drumm · Jul 1, 2019 The "N" parameter always creates a new file. If you want to open a file (optionally creating it if it doesn't exist), use "E" instead, and if you intend to Append to it, include the "A" parameter: open file:("EWA"):1. You don't need the "R" parameter unless you intend to read from it using the same device.Depending on your Cache configuration, you may not even need the "E" parameter. The default behavior in my Windows installation is to create the file if it doesn't exist, with or without the "E" parameter (the documentation refers to "E" as "UNIX-only", FYI).
go to post Jeffrey Drumm · Jun 21, 2019 Adding categories will have no direct impact on message processing. As you noted, there may be a tiny incremental increase in overhead temporarily if you query for them, and you may see a slight delay in the drop-down list ... but only if you're talking about multiple hundreds of them.If the intent is to better document your interfaces, though, take a look at the Business Partner configuration. It's an often-overlooked option to keep details regarding the vendor, its contacts, and other information associated with each interface. This may help make the number of categories more manageable.
go to post Jeffrey Drumm · Jun 20, 2019 Yes, the fact that the Output window lets you interactively enter commands makes "hacking" a bit easier, but so do the "Run" and "Debug" menu options I'm curious to know if there's a way to limit a user to writing COS while prohibiting compilation or execution ...And a server -side configuration option that makes the Output window read-only
go to post Jeffrey Drumm · Jun 20, 2019 Wow, I would think this is a potential security risk. I'm assuming the smart IRIS/Cache Administrator would remove any permissions to create or modify web app settings ...The answer, while very clever, also assumes access to tools other than Studio. Can the requested solution be provided with Studio alone, and, more importantly, will it be possible for the administrator to prevent this sort of access?
go to post Jeffrey Drumm · Jun 18, 2019 The other thing that just occurred to me is that the vendor is dumping a stack trace that may contain print control characters such as carriage returns, and the operation is simply treating the first \x0d as the end of the segment. That would effectively exclude the rest of the stack trace from the message body for conventional parsing purposes. The data is likely still there, but it can't be parsed out as part of MSA;3 with the parsing rules defined in the ACK's schema.
go to post Jeffrey Drumm · Jun 18, 2019 I haven't had the need to do this yet, but my guess is you're going to have to create a custom operation that modifies the received NAK via the OnReplyDocument() method. If the stack trace is really big, it may be stored as a Stream Object rather than a %String. And if that's the case, you're going to have to scan the Stream for the string you need, and replace the contents of the MSA:3 with that string.I'd whip up an example for you but I'm headed out the door and will be OoO for the day. I'll check back tonight to see if anyone's beaten me to it :D
go to post Jeffrey Drumm · May 20, 2019 As @Eduard Lebedyuk pointed out, the method should return a status as indicated by its signature, so at the very minimum you should have a "Return $$$OK" at the end of the method.That said, %FromJSON() throws an exception when it fails, and the generic error you'll get in the Event Log won't tell you (or your support team) much. You may want to wrap a try/catch around the call to %FromJSON() so that you can return a status that provides a little more insight: ... Try { set tJSON = {}.%FromJSON(pInput) } Catch { Return $$$ERROR($$$GeneralError,"Badly formed JSON") } ... Return $$$OK }