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.

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" << EOF
superuser
SYS

zn "USER"
set schedule=##class(ompare.Schedule).%New()
set schedule.Environment="BASELABDB"
set schedule.Namespaces="APPONE,INTEG-*"
set schedule.RunSourceHandlers=0
set schedule.ExportToFile=0
set schedule.ExportDirectory="/home/irisowner/SourceCompare"
set schedule.ImportDirectory="/home/irisowner/SourceCompare"
set schedule.ImportFromFile=1
set schedule.ReImportUpdatedFiles=0
set schedule.DeleteImportedFiles=0
set schedule.RetainExportDays=1
set schedule.EnableLogging=0
set schedule.IncludeSourceCode=1
set schedule.RetainSigSrcHistoricVersions=-1
set schedule.BackupSourceCode=0
set schedule.Debug=1
set schedule.OverwriteSourceOnReLoad=1
Do:\$NAMESPACE="USER" schedule.OnTask()
W !,"Completed"
HALT
exit
EOF

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.exe
LinuxPass = LinuxPass
cmdBase = Local Directory with source commands and for screen output log

Hope this gives some ideas.

Great spot @Timothy Leavitt 

Extra syntax sugar, can project as method expression to make more transparently embedded.

 ClassMethod makeComplement(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")

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

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
{
  $P(replace,",",$L(..#WhiteSpace)+1)=""
  t=$zstrip($TR(t,..#WhiteSpace,replace),"<=>",",")
  q:'$L($TR(t,",")) 0
  l=$L(t,","),m=$L($P(t,","))
  i=1:1:{n=$L($P(t,",",i)) s:((n>0)&&(n<m)) m=n}
  m
}

Regarding input. I don't trust calling code to never provide an empty string :)

Example updated as feedback.

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 :)

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
{
  t=$zstrip($TR(t,..#WhiteSpace,",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"),"<=>",",")
  q:'$L($TR(t,",")) 0
  l=$L(t,","),m=$L($P(t,","))
  i=1:1:{n=$L($P(t,",",i)) s:((n>0)&&(n<m)) m=n}
  m
}

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

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")

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)

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 matched
Skipping class UnitTest.DTL.TestTrans.seg.PID not matched
Created TestCase: UnitTest.DTL.Test2.TestTrans.TransformSource2
Compilation started on 08/18/2022 19:56:23 with qualifiers 'ckf'
Compiling class UnitTest.DTL.Test2.TestTrans.TransformSource2
Compiling routine UnitTest.DTL.Test2.TestTrans.TransformSource2.1
Compilation finished successfully in 0.031s.

# Add a new test message pair from an existing HL7 message with rowid 189
set tSC=##class(UnitTest.DTL.Test2.TestTrans.TransformSource2).AddTestFromMessageBody("EnsLib.HL7.Message",189,1,.sourceXdataName,.targetXdataName,1)

# Run UnitTest
do ##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.

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

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