go to post Alex Woodhead · Sep 26, 2022 Could "docker commit" help out as an image snapshot that you can simply resume later. Would an image saved to tar or pushed to a repo make itteration portable also? More simpler for a stopped container locally is to just start it again? Assuming the container is allowed to cache and not too much time has passed to allow the space to have been automatically reclaimed.
go to post Alex Woodhead · Sep 21, 2022 Hi Phillip, This can be done locally and depending on access, remotely also. From a windows host running commands against a Linux Database can use a file for example: SC_ImportBase.txt Could use os authentication but including credentials as an example for what is possible: cd /tmp; sudo -u irisowner iris session Instance -U "USER" << EOFsuperuserSYS zn "USER"set schedule=##class(ompare.Schedule).%New()set schedule.Environment="BASELABDB"set schedule.Namespaces="APPONE,INTEG-*"set schedule.RunSourceHandlers=0set schedule.ExportToFile=0set schedule.ExportDirectory="/home/irisowner/SourceCompare"set schedule.ImportDirectory="/home/irisowner/SourceCompare"set schedule.ImportFromFile=1set schedule.ReImportUpdatedFiles=0set schedule.DeleteImportedFiles=0set schedule.RetainExportDays=1set schedule.EnableLogging=0set schedule.IncludeSourceCode=1set schedule.RetainSigSrcHistoricVersions=-1set schedule.BackupSourceCode=0set schedule.Debug=1set schedule.OverwriteSourceOnReLoad=1Do:\$NAMESPACE="USER" schedule.OnTask()W !,"Completed"HALTexitEOF And can launch this script against a remote Linux instance using plink from a local batch file: "%cmdPLINK%" -v account@10.123.456.789 -pw %LinuxPass% -m "%cmdBase%scr\SC_ImportBase.txt" > "%cmdBase%out\SC_ImportBasePlink.log" Where: cmdPLINK = C:\Program Files\PuTTY\plink.exeLinuxPass = LinuxPasscmdBase = Local Directory with source commands and for screen output log Hope this gives some ideas.
go to post Alex Woodhead · Sep 21, 2022 Great spot @Timothy Leavitt Extra syntax sugar, can project as method expression to make more transparently embedded. ClassMethod makeComplement(d As %String) As %String [CodeMode = expression] { $tr(d,"ATGC","TACG") } Also I believe Java lacks convenience of compile time ObjectScript macros: #define DNAComplement(%dna) $tr(%dna,"ATGC","TACG") Write $$$DNAComplement("ATC")
go to post Alex Woodhead · Sep 19, 2022 Revisiting challenge in Erlang. Tail recursive (no increase in stack height), single pass of string, using language primitives only. -module(shortest_word).-export([v/1]). v([])->0;v(T)->v(T,0,999).v([],C,M) when C>0,M>C->C;v([],_,M)->M;v([32|T],C,M) when C>0,C<M->v(T,0,C);v([32|T],_,M)->v(T,0,M);v([_|T],C,M)->v(T,C+1,M). -------------- >shortest_word:v("abc deff"). 3
go to post Alex Woodhead · Sep 14, 2022 Sharing for readers, an alternative code approach, to generate a pad-string without Translate and Justify, uses another application of the Piece function. set $Piece(replace,",",81)="" This is sets a comma delimited string, at piece 81, to an empty string. Which effectively results in a string of 80 commas. So: Parameter WhiteSpace = {$C(9,10,13,32,160)}; ClassMethod Short(t) As %Integer { s $P(replace,",",$L(..#WhiteSpace)+1)="" s t=$zstrip($TR(t,..#WhiteSpace,replace),"<=>",",") q:'$L($TR(t,",")) 0 s l=$L(t,","),m=$L($P(t,",")) f i=1:1:l {s n=$L($P(t,",",i)) s:((n>0)&&(n<m)) m=n} q m } Regarding input. I don't trust calling code to never provide an empty string :) Example updated as feedback.
go to post Alex Woodhead · Sep 13, 2022 I have an example implemetation in the Ompare tool. See: https://github.com/alexatwoodhead/ompare/blob/main/src/cls/ompare/Schedu... Extends: %SYS.Task.Definition Implements: OnTask method By the way, you can run Schedules programatically from IRIS Session outside of the Task Scheduler if you are investigating / debugging the behaviour. For example: set tBASE=##class(ompare.Schedule).%New() set tBASE.Environment="BASE" set tBASE.Namespaces="OMPARE-BASE,INST-*,-INST-TEMP" set tBASE.RunSourceHandlers=1 set tBASE.ExportToFile=1 set tBASE.ExportDirectory="C:\TMP\ompare\" set tBASE.ExportCompression=0 set tBASE.DiscardProfileData=1 set tBASE.RetainExportDays=0 set tBASE.IncludeSourceCode=1 set tSC1=tBASE.OnTask() The reason I would subclass %SYS.Task.Definition is that the Management Portal knows how to display input configuration fields for your class properties. This is more visably useful / supportable. Easier to see the task paramaters. They can have validation also (Required, Pattern, MINLEN, MAXLEN, Setter methods, %OnSave methods). Hope that helps :)
go to post Alex Woodhead · Sep 13, 2022 Thanks for recommendations. Taking these changes onboard think I would then make the whitespace characters configurable. Then others can just override this behaviour in a subclass or maintain the original a bit easier. Parameters are a great ObjectScript syntactic sugar :) Parameter WhiteSpace = {$C(9,10,13,32,160)}; ClassMethod Short(t) As %Integer { s t=$zstrip($TR(t,..#WhiteSpace,",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"),"<=>",",") q:'$L($TR(t,",")) 0 s l=$L(t,","),m=$L($P(t,",")) f i=1:1:l {s n=$L($P(t,",",i)) s:((n>0)&&(n<m)) m=n} q m }
go to post Alex Woodhead · Sep 13, 2022 ClassMethod Short(t) As %Integer{ s t=$TR(t,$C(9,10,13,32,160),",,,,,") q:'$L($TR(t,",")) 0 s l=$L(t,","),m=200 f i=1:1:l {s n=$L($P(t,",",i)) s:((n>0)&&(n<m)) m=n} q m}
go to post Alex Woodhead · Sep 6, 2022 Hi Jimmy, Yes this is using the router context to test if a message has some invalid characters. As an example I simply used the content "BAD" in the message to demonstrate. If you want to identify specific characters by numeric code-point an additional FunctionSet method could be employed. For example: /// RuleSet function to evaluate whether a given raw input string contains unwanted characters /// Unwanted characters are supplied as a comma delimited string. /// For example detect "9,32" would match any ASCII Tab and ASCII space characters /// The $ASCII function can be used to identify the numeric code point of a character, to be supplied in the detect parameter. ClassMethod ContainsChars(rawData As %String = "", detect As %String = "") As %Boolean { quit:$Length(rawData)<1 0 quit:$Length(detect)<1 0 set found=0 set len=$Length(detect,",") for item=1:1:len { set charNum=$Piece(detect,",",item) continue:charNum'?1.N set char=$Char(charNum) if rawData[char { $$$TRACE("Found Character "_charNum_" in rawData") set found=1 quit } } quit found } Usage example: Cheers, Alex
go to post Alex Woodhead · Aug 30, 2022 Thanks @Sean Connelly Reminded within a "csp page" context can use the following to output context information when not in error. set %response.TraceDump=1
go to post Alex Woodhead · Aug 26, 2022 This is sucessful if no longer showing class not found error. It found the class and ran the method sucessfully. Set rowId=1 If ##class(EnsLib.HL7.Message).%ExistsId(rowId)=0 or 1 then The class EnsLib.HL7.Message has been mapped to the current namespace. It is giving 0 because there has been no HL7 messages created yet (with rowId 1) or message rowId 1 has been purged from namespace. A better non-error prone way to programatically test whether the class is available to the namespace could use: write ##class(%Dictionary.CompiledClass).%ExistsId("EnsLib.HL7.Message")
go to post Alex Woodhead · Aug 26, 2022 Some ideas for general configuration. In a target namespace can test integration is enabled with:write ##class(%EnsembleMgr).IsEnsembleNamespace() Can enable integration for an existing namespace with:do ##class(%EnsembleMgr).EnableNamespace($NAMESPACE) When enabled, as a test can Run a integration method from mapped class:write ##class(EnsLib.HL7.Message).%ExistsId(1)
go to post Alex Woodhead · Aug 24, 2022 Suggest try Edit in settings.json "pathPrefix": "/[Instance Name]", For example:"intersystems.servers": { "test1": { "webServer": { "scheme": "http", "pathPrefix": "/IRIS", "host": "localhost", "port": ... } }}
go to post Alex Woodhead · Aug 19, 2022 Hi Michael, Anastasia mentioned rerun is at: https://youtu.be/DBGvt0jd4yI
go to post Alex Woodhead · Aug 18, 2022 Hi Scott, Many thanks for reporting this. Yes this is unintuitive. I have updated the implementation so: 1. Method GenerateTestCases now has additional parameter autocompile which is default yes. 2. Method AddTestFromMessageBody now has additonal parameter recompile default no. Now when you generate new TestCases by default they will be auto-compiled and ready to accept attaching new HL7 messages for testing. For clarity the message id "1218515" will be an EnsLib.HL7.Message RowId. This is the same ID seen in System Management Portal Integration Messages view as MessageBodyId. To have added messages immediately ready (compiled) for next test run can use: set recompile=1 set tSC=##class(UnitTest.Test.DTL.TestTrans.TransformSource2).AddTestFromMessageBody("EnsLib.HL7.Message",1218515,1,.sourceXdataName,.targetXdataName,recompile) The class "UnitTest.Test.DTL.TestTrans.TransformSource2" was generated from an an HL7 DTL class "UnitTest.DTL.TestTrans.TransformSource2" in my test environment. I have also added reference test class: UnitTest.DTL.TestTrans.TransformSource2.xml to github, # Example Generate from reference class:Do ##class(UnitTest.DTL.HL7TestCase).GenerateTestCases("UnitTest.DTL.TestTrans.TransformSource2", "UnitTest.DTL.Test2.TestTrans.", 0 , , 0,1, 1, .pStatus) Skipping class UnitTest.DTL.TestTrans.seg.MSH not matchedSkipping class UnitTest.DTL.TestTrans.seg.PID not matchedCreated TestCase: UnitTest.DTL.Test2.TestTrans.TransformSource2Compilation started on 08/18/2022 19:56:23 with qualifiers 'ckf'Compiling class UnitTest.DTL.Test2.TestTrans.TransformSource2Compiling routine UnitTest.DTL.Test2.TestTrans.TransformSource2.1Compilation finished successfully in 0.031s. # Add a new test message pair from an existing HL7 message with rowid 189set tSC=##class(UnitTest.DTL.Test2.TestTrans.TransformSource2).AddTestFromMessageBody("EnsLib.HL7.Message",189,1,.sourceXdataName,.targetXdataName,1) # Run UnitTestdo ##class(UnitTest.DTL.Test2.TestTrans.TransformSource2).Debug() # There will be one intentional error as the original template for manually adding messages is still present. But it does demonstrate attempting to process both pairs of message blocks.# Perhaps this placeholder template should be suppressable when generating new TestCases if always programatically adding them. XData TESTMessageSource { <test><![CDATA[ <!-- Your Source HL7 Message or Segment content goes here --> ]]></test> } XData TESTMessageTarget { <test><![CDATA[ <!-- Your Expected output for HL7 Message or Segment content goes here --> ]]></test> } Thank you for trying out the utility.
go to post Alex Woodhead · Aug 18, 2022 Hi Rochdi, If you have a look at class ompare.SourceHandler.Class, in Open Exchange app https://openexchange.intersystems.com/package/ompare. It has a range of functionality for decomposing classes into their different components. Extracting functional lines of source code but discarding comments and empty lines. It could be enhanced to add a counter to method lines extracted in the profile class. The schedule also happily jumps namespaces to build report information for multiple namespaces in an environment. Kind regards, Alex
go to post Alex Woodhead · Aug 17, 2022 Hi Jimmy, One approach could be to define a FunctionSet method: Class MyRule.FunctionSet Extends Ens.Rule.FunctionSet { ClassMethod StopService(serviceName As %String = "") As %Boolean { job ##class(Ens.Director).EnableConfigItem(serviceName,0,1) quit 1 } } Then in your routing rule that is recieving bad messages from your service you could use the new function: You might also decide to simply match and suspend bad messages or route to a bad message handler if sequence is not an issue. Assumes the characters are within the first 10,000 characters of HL7 message. Hope this helped inspire some ideas. Cheers, Alex
go to post Alex Woodhead · Aug 15, 2022 Hi Scott, Have now opensourced the utility for generating and running message driven DTL TestCases from existing DTL transforms. https://openexchange.intersystems.com/package/UnitTest-DTL-HL7 Kind regards, Alex
go to post Alex Woodhead · Aug 11, 2022 Try: $SYSTEM.Process.ClientIPAddress($J) As replacement for: $ZUTIL(67,15,$J)