go to post Mike Wragg · Apr 23, 2021 Hi. I've never come across any automatic conversion from character user interface (CHUI) to any web-based one. You might stand a chance if the screens were written in some sort of "screen generator" framework, but most I've seen are basically hand-coded, and the problem is that they work on a field-by-field basis. So they read one field, validate input, update bits of the screen and data, and then move to the next field. This does not match well with web pages that tend to work a screen at a time, so automatic conversion is impossible. Sorry about that. I'd like to be proved wrong, of course - maybe some of the systems I work on could be converted! Anyone?
go to post Mike Wragg · Apr 23, 2021 The reason that there is no sort "function", is that sorting is part of the basic storage structure that the whole system is built on. Arrays, both global and local, are automatically sorted as you set them up (effectively by an insertion sort). No need for a separate program or request. Just set up the data in an array as you go along and it will be sorted when you need it. This has always been a basic idea in the language, right from the original MUMPS, so the documentation may well skip over it a bit. However, when you get used to it, it works well.
go to post Mike Wragg · Nov 19, 2020 Hi. If all you need is to set global nodes on a remote instance, then you could just set it up as a remote database and namespace and use Extended Global References to access it. No need to run code on the remote system. Or have I missed something?
go to post Mike Wragg · Nov 19, 2020 We still have green-screen parts of the app, so interested in the answer. And is there a way to tie the Windows command app into running cache? (I know very little about Windows.). Thanks.
go to post Mike Wragg · Mar 13, 2020 Hi, I don't want to achieve anything else, it's just that "cache being cache" there's often another way to do the same thing and it might be easier. :-) Mike
go to post Mike Wragg · Mar 12, 2020 Hi, I recently needed a temporary class (not just a table) to store data while it was manipulated (imported, queried, modified, etc. and eventually exported) . I eventually set up all the storage locations with PPG refs as noted above, which works, but did wonder if there was a class parameter I had missed that just indicated the extent was temporary. Or maybe an alternative to extending %Persistent? Mike
go to post Mike Wragg · Mar 12, 2020 Hi Stuart, As others have said, it's best practice to build a new variable, rather than amending what you have (there's some fancy name for the rule, I think, or maybe just "functional programming"). Looking at the string, I assume it is HealthShare HL7 message format, so the contents are pretty limited. In which case maybe a shortcut could be used: s out=$Replace($Replace(list,"~]",""),"~[","") Here's another alternative: w $ZSTRIP($ZSTRIP(list,"*","[]"),"=>P") I admit it could go horribly wrong with multiple nesting (I don't remember all the possible formats), so needs some testing. Hope you're keeping well, Mike
go to post Mike Wragg · Oct 25, 2019 Sadly, in my team we've all been writing MUMPS for so long that the abbreviated style comes naturally and is a hard habit to break. Yes, expanded is better for new starters in the language. However... Playing devil's advocate you could say that abbreviated commands are: 1. Faster to type (as you said). 2. More compact. Allowing the reader to "see" more of the structure in one go. You see, you can expand things out too much, in my opinion. Also, it only takes a few minutes for a (reasonable) programmer to get that "S" means "set", "I" means "if", etc. Commands always appear in the same part of the code (unlike some languages), there are not that many to learn, and once you know them, you can read them! So why bother with extra letters? After all "set" is itself only a token for "put the value on the right of the = into the variable on the left" or something like that. It could be "make" or "update" or "<-" (look up the programming language "APL" on Wikipedia if you want a real scare). I think the main problem with "old fashioned" code is usually poor label/variable names, squeezing too much on one line, and lack of indenting. It's hard to read mainly because of the other parts of the code, not because the commands are single characters. Some things should be longer to better convey what they are for (though not as long as COBOL), and more lines can help convey program structure. While I'm here, I'm not that keen on spurious spaces in "set x = 1", as opposed to "set x=1". It just spreads out the important stuff - spaces are there to split out the commands. :-) Mike
go to post Mike Wragg · Oct 4, 2019 Hi. It depends on what you mean by "certain criteria". If it's a special file name then you could amend the FileSpec property to skip the ones you don't want yet. If it's in the content, then maybe you should be reading in the file (creating a copy or allowing archive so the original continues to exist) and sending it as a message into Ensemble that can then be held up in a business process until ready to send out to an Operation that creates an output file. That is the way ensemble is supposed to work, so you get a full record of what happened, etc. (Otherwise, I'm pretty certain that there are actions that reset the list of processed files - maybe resetting that file path or restarting the job - but I cannot find the documentation about it at the moment. )
go to post Mike Wragg · Jun 28, 2019 Hi.Recently, well yesterday, I needed to do exactly the same , and on a class property as well! I found an answer more by accident than design: s data=$LB(1,2,3) s data=$LI(data,1,*-1) zw data data=$lb(1,2) When I saw the other answer, I worried that this might not work when the result is only one item, but it does, as confirmed by the documentation for the $LIST function. If you supply all three parameters - list, position, end - then it always returns another list. I was pleasantly surprised! Mike
go to post Mike Wragg · May 3, 2019 Hi / It sounds like a good idea! I can think of a number of interfaces I've seen where the target application - a small local system - struggled to keep up with the flow of updates from a large PAS.The only thing I've done like it was complicated, and had to use a proper Business Process. In that case the "department" was neonatal, so we were only interested in patients admitted to a particular ward. The solution looked for HL7 admissions and transfers to that ward, and when found used the data to create a local record in Caché. Then all other types of message could be checked against those records to see if it needed further processing and passing on (to "BadgerNet" eventually when a full episode was built up). Of course this only works if you can define a clear "starting point" that can be spotted in the message stream. / Mike
go to post Mike Wragg · May 3, 2019 Hi. The "clean code" people would recommend just one parameter max, and better would be none! But I think that's going a bit far, and agree that 3, or maybe 4, maximum should be aimed for to keep things easy to understand when reading, though there may be exceptions.The array passing is a good idea to reduce the number for normal routines, but I think the ideal for classes is using objects. If you are truly embracing objects, and self-documenting code, then new classes are usually needed and what used to be parameters become the setting of properties, like this: S table=##class(CMT.UI.Table).%New()S table.TopLine=10,table.BottomLine=21S table.HeaderFormat="Underline"D table.DefineQuery("CMT.UI.PatchSite:MyList") D table.AddColumn(3,,"BOLD")...etc. D table.Display()It works well in some cases, but I have to admit that there is a tendency for the number of classes to get a bit silly if you take it to the extreme. Sometimes simple code is best. :-) / Mike
go to post Mike Wragg · Oct 25, 2018 I think that is my preferred method as well, but it depends to some extent what you are going to do with the result, and what you want to happen if the input number is too big. This $J solution will always return all the characters input, which may be the safest thing. (Though any space characters inside the input will get converted to zeros.)When the fail mode needs to still return the same length string, e.g. to avoid messing up some fixed length message format, it might be best to use $E(), e.g. W $E("0000"_number,$L(a)+1,*) I've also seen the following used, but I'm not sure I recommend it. So many interesting ways it could go wrong! w $E(number+10000,2,999)
go to post Mike Wragg · Oct 18, 2018 Hi. I was actually looking up some information about pattern matching, but came across this warning:If a call attempts to use indirection to get or set the value of object properties, it may result in an error. Do not use calls of this kind, as they attempt to bypass property accessor methods (<PropertyName>Get and <PropertyName>Set). Instead, use the $CLASSMETHOD, $METHOD, and $PROPERTY) functions, which are designed for this purposeThis was from https://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=GCOS_operators#GCOS_operators_patternSo it looks like it may well work now, but there's no guarantee it will always work.Surely there is a $method() call you can use to get the next item in the array?
go to post Mike Wragg · Jul 27, 2018 Hi, I also help support an NHS trust using Ensemble, and it also has ever-growing PDF files in messages. We have our incoming PDFs as external file streams and it helps, though you have to bear in mind that the files are not going to be part of the cache backup for Disaster Recovery, etc. (Not sure about mirroring. I'd assume they don't get mirrored either as the contents are not in the journal.)As yet, we don't have as big a problem as you - less messages and we only keep 92 days - but that is just as well as the PDF files are converted to base64 encoded in HL7 v2 messages, so they then do take up space in the database, and the journal, and the backup, which has resulted in the need to expand the disk space recently. I can recommend keeping Ensemble on a virtual server with disk expansion on demand.I tend to think the problem is not going to go away whatever you do. I assume, like us, the PDFs come from 3rd party applications and they are always going to be producing ever more and prettier documents as time goes by. So I recommend looking at more disk. :-) / Mike
go to post Mike Wragg · Jun 15, 2018 Hi,I won't claim this is an answer, because it's not quite the same and people may object to the structure, but here is one solution that is used quite a lot in code I look after. Basically, a subroutine is called and then tests are done and a Quit is used to drop out when a match is found. Often used for validation, something like this that returns a result in the zER variable:V1 ; Validate ORGC S ORG=zORG D WC2^hZUTV I zER'="" Q I IPACC<9,'$D(^hIW(WAID)) S zER="No details set up for ward" Q D WARDON^hILO1 I LOCK S zER="Ward in use" QVQ2 QApologies for the old-fashioned code! However, you can see each test can be quite complex and using lots of variables, but it is easy to understand as long as you expect the structure to work that way.This is very similar to the "clean code" solution of making the whole thing into a function that returns a value: ClassMethod Main(val1 As %String, val2 As %String) { write ..MyOutput(val1,val2) } ClassMethod MyOutput(val1 As %String, val2 As %String) As %String { if val1 = 1 return "case 1" if val1 = 2, val2="*" return "case 2" return "default match" } Of course there are probably as many answers as there are Cache programmers! :-)
go to post Mike Wragg · Apr 20, 2018 Yes, we have something like that, except we use the letter "q" as the prefix, and we follow it by the programmer's initials so that it becomes a "personal" set that is left alone in all namespaces, dev-test and live. We also extend this to rule to globals and things inside the application like functions, screens, tasks, etc. The in-house configuration management system we use ignores them so they are left untouched. It's a useful convention.(We might have used "z" like you, but it was already taken for "utility/library" stuff.)
go to post Mike Wragg · Apr 19, 2018 Neither - I think it best to just remove all the code and leave a stub with just a comment (usually with the change request id and reason).That ensures the unused code is removed from all downstream libraries, so does not pop up in searches and testing, and yet keeps a record of its previous existence. I've always been against leaving unused code in source files, even if it's "commented out".
go to post Mike Wragg · Feb 21, 2018 Anyone know why we ended up with this strange behaviour? Why doesn't COS store 2 and "2" in the same way in lists? The rest of the programming environment is based around them being the same - (2="2") - as everything is a string until used otherwise. It may use "an optimized binary representation", but surely that's not really an excuse. Just curious.
go to post Mike Wragg · Feb 21, 2018 An alternative solution that works for us is to use the "Schedule" setting to run it for 30m (to allow some leeway as the job takes a while), and then set the "Call Interval" setting to something very large like "999999". This is for an Inbound SQL adaptor. (If something goes wrong with this overnight run then we manually remove the "Schedule" setting and restart the Service. Once complete, we put back the setting ready for the next night.)