It's not a bad idea, but the last value has very little chance of appearing

FOR I=1:1:100 {W $Piece("SAD,MED,TEN,BOB,RAN",",",$r(4)+1),"-" }

TEN-TEN-BOB-TEN-SAD-MED-MED-MED-MED-MED-TEN-MED-BOB-MED-MED-TEN-TEN-MED-SAD-BOB-MED-SAD-BOB-
TEN-TEN-BOB-BOB-SAD-BOB-TEN-MED-BOB-BOB-MED-TEN-MED-SAD-BOB-BOB-BOB-MED-MED-TEN-MED-TEN-MED-
TEN-BOB-MED-TEN-SAD-MED-MED-MED-BOB-SAD-SAD-MED-SAD-BOB-SAD-TEN-BOB-BOB-TEN-BOB-TEN-BOB-SAD-
SAD-TEN-MED-TEN-SAD-BOB-MED-SAD-SAD-BOB-MED-TEN-TEN-SAD-SAD-SAD-BOB-BOB-BOB-TEN-MED-BOB-BOB-
TEN-BOB-SAD-SAD-BOB-BOB-BOB-MED

SAD    20%
MED    27%
TEN    23%
BOB    30%
RAN    0%

I've tried to user other way, for example, using a GUID, get the checksum and get the module 5

Something like $Piece("SAD,MED,TEN,BOB,RAN",",",($ZCRC(##class(%SYSTEM.Util).CreateGUID(),0)#5) + 1)

for i=1:1:100 {W $Piece("SAD,MED,TEN,BOB,RAN",",",($ZCRC(##class(%SYSTEM.Util).CreateGUID(),0)#5) + 1),"-"}

TEN-SAD-BOB-MED-BOB-BOB-MED-MED-BOB-RAN-MED-BOB-RAN-MED-RAN-BOB-BOB-MED-RAN-SAD-RAN-MED-MED-
BOB-TEN-BOB-RAN-MED-TEN-TEN-TEN-SAD-BOB-MED-BOB-BOB-BOB-RAN-RAN-TEN-MED-RAN-RAN-BOB-RAN-TEN-
MED-TEN-TEN-MED-RAN-BOB-TEN-SAD-SAD-TEN-TEN-TEN-BOB-RAN-MED-SAD-MED-SAD-RAN-RAN-RAN-BOB-MED-
SAD-MED-RAN-RAN-SAD-RAN-RAN-BOB-MED-TEN-TEN-RAN-BOB-TEN-TEN-RAN-BOB-BOB-TEN-MED-SAD-SAD-BOB-
BOB-BOB-SAD-TEN-MED-TEN-BOB-SAD

SAD    13%
MED    20%
TEN    20%
BOB    25%
RAN    22%

I have best percentage to get a different value.

Hi,

Indeed, the problem was caused because the address to which it is going to connect is variable, so the component is not configured with the Server or URL parameters.

I've solved it by the following way:

set ..Adapter.HTTPServer = pRequest.Url
Set URL = pRequest.Url_"/search"
set tHttpResponse = ##class(%Net.HttpResponse).%New()
set tSC = ..Adapter.SendFormDataArray(.tHttpResponse,"POST",tHttpRequest,,,URL)

if $$$ISERR(tSC) && (tHttpResponse="") $$$ThrowStatus(tSC)

// Check what is the status code
set content = ""
while (tHttpResponse.Data.AtEnd = 0) { 
    set content = content_tHttpResponse.Data.Read() 
}

do pResponse.%JSONImport(content)
set pResponse.StatusCode = tHttpResponse.StatusCode

Regards,
Kurro Lopez

Thanks Robert but it wasn't a firewall problem.

The problem was due the instalation didn't compile the code correctly. It doesn't get the version of ISC as expected.

I'm using the version WebTerminal-v4.9.3, in the line 1507 there is a initialization of the parameter iscProductVersion

<Parameter name="iscProductVersion">
<Description>
In older Cache versions, method "GetISCProduct" does not exists</Description>
<Expression>$case(
        ##class(%Dictionary.CompiledMethod).IDKEYExists("%SYSTEM.Version", "GetISCProduct"),
        1: $CLASSMETHOD("%SYSTEM.Version", "GetISCProduct"),
        : 2
    )</Expression>
</Parameter>

Later, in line 1611, it checks what is the version to set the role required:

set requiredRole = $case(..#iscProductVersion >= 4, 1: "%DB_IRISSYS", : "%DB_CACHESYS")

But, if I check what is my version, the answer is 3, instead of 4, so it was trying to set %DB_CACHESYS instead of %DB_IRISSYS, so the compilation didn't end.

w ##class(%SYSTEM.Version).GetISCProduct() 
3

Then, I've modified the file and change the comparison  ..#iscProductVersion to check if is equal or upper than 3, and it works.

In the line 1730, there is other comparison to set the dbPrefix, so I've modified this line also.

set dbPrefix = $case(..#iscProductVersion >= 3, 1: "IRIS", : "CACHE")

Now, I have the Webterminal worning fine.

Note: I'm using IRIS for Windows (x86-64) 2021.1 (Build 215U) Wed Jun 9 2021 09:39:22 EDT

Best regards,
Francisco Lopez

Hi,

The $HOROLOG is the cache datetime format, then the first part is de date and the second part is the time. The time is in seconds, then if you want to increase 15 minutes, you should to plus the time (15*60)

This is a example:

It only works if you are in the same day, because it raises an error

The best way to increase minutes, days, months, etc... is using $system.SQL.DATEADD method

https://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY...

Best regards,
Kurro

Delete class from Ensemble

set classToDelete = "mypackage.myclass"
if ($$$ISOK($system.OBJ.IsValidClassname(classToDelete)))
{
    do $system.OBJ.Delete(classToDelete,"e")
}

Remove a Host from production

set productionName = "mypackage.myproduction"
set itemName = "NameItemInProduction"

If ##class(Ens.Config.Item).NameExists(productionName,itemName,.idItem)
{
    Set production = ##class(Ens.Config.Production).%OpenId(productionName)
    Set objItem = production.FindItemByConfigName(itemName)
    Do production.RemoveItem(objItem)
    Set st = production.%Save()
    Do ##class(Ens.Director).RestartProduction(0,1)
}

I hope this code helps you.

Best regards,
Kurro Lopez

Hi.

Try use this command from console (Powershell, console Linux, etc..) for Intersytems Ensemble

ccontrol.exe force HEALTHSHARE

HEALTHSHARE is the name of your instance

This command should be executed in bin folder (ex. c:\Intersystems\Healthshare\bin)

For IRIS the command is

iris.exe forece IRISHealth

IRISHealth is the name of your instance, it is in the folder bin (ex. c:\Intersystems\IRISHealth\bin)

Best regards
Francisco Lopez

Hi,

if you read your requirements, that is that you have to write in your DTL

The first line copy all your PID in the new destination (green box)

the condition, check if the 11(1).8 has value, in this case, concatenate PID:11(1).1_PID:11(1).2 to new PID:11(1).1

I understand, when you say "move 11(1).8 to 11(1).2 means that the value in 11(1).8 will be empty (red box), if it is not the case, don't use this line.

For other case (step 7). remove the value of the PID:11(1).8

The DTL conditions are executed in order, It means, that the value in PID:11(1).2 in step 3 is the original then it is replaced by PID:11(1).8 in the following step.

This is the test result:

I hope it helps you,

Regards,

Kurro Lopez

Hi Tim,

I know that is a old question, and I don't know if you have resolved your problem.

I have something like you are asking in a process. Maybe it could help you.

I created a persistent class with theses properties, also add a Query to retrieve info from a ProcessId:

Class FtpFileReport Extends %Persistent
{

/// ProcessId
Property ProcessId As %String;

/// Filename
Property FileName As %String;

/// Retrieve records of a ProcessId
Query GetRecordsByProcessId(pProcessId As %String) As %SQLQuery
{
    SELECT ProcessId, FileName
    FROM FtpFileReport
    WHERE ProcessId = :pProcessId
}

}

Then, when my process start to grabs the file, create a ProcessId, for example, using a combination of horolog and cryptotoken, to create an unique Id.

set pProcessId = "ID"_$PIECE($HOROLOG,",")_$PIECE($HOROLOG,",",*)_$SYSTEM.Encryption.GenCryptToken()

For each file grabbed, you save a record in your persistent class

set obj=##class(FtpFileReport).%New()

set obj.ProcessId = pProcessId    ;pProcessId is the variable with the Id created previously

set obj.FileName =  pFileName   ;if you are using retrieveFile method, it is the name the file that is grabbing

do obj.%Save()

Afterward, create a message to a BO that send the email with the ID of the process and create the message body based on ProcessId files:

Class SendEmail Extends Ens.BusinessOperation
{

Parameter ADAPTER = "EnsLib.EMail.OutboundAdapter";

Parameter INVOCATION = "Queue";

/// Send email of FTP Report
Method SendFtpReport(pRequest As Ens.StringRequest, Output pResponse As Ens.StringResponse) As %Status
{
    #dim myList As %Library.ListOfObjects

    set report  = ##class(FtpFileReport).%New()
    set myList = ##class(%Library.ListOfObjects).%New()
    set resultset = report.GetRecordsByProcessId(pRequest.StringValue)
    set data = ##class(%Stream.GlobalCharacter).%New()
    while resultset.%Next()
    {
        set fileNum = $Increment(fileNum)
        do data.Write("<b>"_fileNum_":</b><p>"_resultset.%Get("FileName")_"</p><hr>")
        do myList.Insert(data)
    }

    set msg = ##class(%Net.MailMessage).%New()
    set msg.IsHTML = 1
    do msg.TextData.WriteLine("<h1>FileReport</h1><br><h2>This is the FTP report: <h2><br><br>")    ; This is the body of the email

    for pos=1:1:myList.Size
    {
        do msg.TextData.Write(myList.GetAt(pos).Read())
    }

    set msg.To = ##class(%Library.ListOfObjects).%New()  ;Destinations address
    do msg.To.Insert("destination@mydomain.com")
    set msg.Subject= "File report"
    do ..Adapter.SendMail(msg)

    set pResponse = ##Class(Ens.StringResponse).%New("Ok")
    quit $$$OK
}

XData MessageMap
{
<MapItems>
  <MapItem MessageType="Ens.StringRequest">
    <Method>SendFtpReport</Method>
  </MapItem>

</MapItems>
}

}

I hope helps you.

Regards,
Francisco Lopez

Indeed.

The parameter 3 in $ZDATE and $ZDATEH is the format of the date YYYY-MM-DD ODBC format

$HOROLOG retrieves the system datetime, so $ZDATE($HOROLOG,3) gives the current sytem date

Usually, HL7.{PID.7} uses the format YYYY-MM-DD, so it converts the string into a datetime variable ($ZDATEH(dob,3))

Please, find out the info in $ZDATE and $ZDATEH documentation.

Best regards,
Francisco Lopez

P.S. Don't forget mark the answer as accepted wink

Last time, we have a value of 10 and the error increases more frequently, even when I was loading files.

So, the idea is to put a value like 30 seconds to allow that time the TCP disconnection. If I change the value to 30 (or 60), can the process open the TCP connection automatically and try to connect to FTP? If I leave it indefinitely (-1), is there a way to make the connection again?

Well, next time I need to read the documentation in depth.

There is a base method to check if a class extends of other one

set obj = ##class(MyLibrary.ChildClass01).%New()

## this retrieves 1
w obj.%Extends("MyLibrary.ParentClass")

## this retrieves 0
w obj.%Extends("MyLibrary.ParentClassFake")

This has been a "Rubber duck", this is a sample of guide-book of rubber duck. wink

More info Clase %Library.SystemBase

Best regards,

Francisco López