Eduard Lebedyuk · Sep 6, 2018 go to post

Usually response does contain status information in StatusCode and StatusLine properties.

You need to change this line

Set httpResponse = httpRequest.Post("/sample/", 2)

to

#dim sc As %Status = $$$OK
Set sc = httpRequest.Post("/sample/", 2)
Write $System.Status.GetErrorText(sc)

As Post method returns status.

After debugging you can use

write $$$ISERR(sc)

macro to check if result of some operation is an error.

Eduard Lebedyuk · Sep 6, 2018 go to post

The easiest solution would be

set net.SSLCheckServerIdentity=0

that disables server cert checking. Not very secure obviously.

Eduard Lebedyuk · Sep 5, 2018 go to post

Do you want to change ROWSPEC depending on passed argument?

ROWSPEC can be changed on compilation only and it's rather static. At least xDBC clients depend on declared schema/query info and so it cannot be changed dynamically.

Eduard Lebedyuk · Sep 5, 2018 go to post

it causes error messages as something in the class is not correct,

What error messages?

Also try calling

zwrite %objlasterror

it may contain additional information.

Eduard Lebedyuk · Sep 4, 2018 go to post

You can use methods of %Activate.TLEnumerator class to load libraries programmatically.

Eduard Lebedyuk · Sep 4, 2018 go to post

I think you'll need a full fledged orchestrator for that. Docker run always starts one container, bit several volumes could be mounted, some of them RW, some RO. I'm not sure about mounting the same folder into several containers (again, orchestration).

You can also use volumes_from argument to mount directory from one container to another.

Eduard Lebedyuk · Sep 3, 2018 go to post

Redefine HTTP adapter like this:

Class Production.Adapter.HTTPOutboundAdapter Extends EnsLib.HTTP.OutboundAdapter
{

/// Send a POST to the configured Server, Port and URL, sending form data to the named form variables.
Method Post(Output pHttpResponse As %Net.HttpResponse, pFormVarNames As %String, pData...) As %Status
{

    quit ..SendFormDataArray(.pHttpResponse, "POST", ..GetRequest(), .pFormVarNames, .pData)
}

ClassMethod GetRequest() As %Net.HttpRequest
{
    set request = ##class(%Net.HttpRequest).%New()
    set request.ContentType = "application/json"
    quit request
}

}

And use it instead of default adapter.

Eduard Lebedyuk · Aug 31, 2018 go to post

Similar script is used in InterSystems IRIS docker image to scramble passwords on startup.

Eduard Lebedyuk · Aug 31, 2018 go to post

Try this:

1. Write stream to string

2. Use $zcvt on string $zcvt(string,"O","UTF8")

3. Send this stream to XSLT

Eduard Lebedyuk · Aug 29, 2018 go to post

Speed comparison:

Class POI.Test
{

/// do ##class(POI.Test).main()
ClassMethod main(rounds As %Integer = 1000, size As %Integer = 10, nullPercent As %Integer = 20)
{
    set list = ..getList(size, nullPercent)
    
    write !,"Rounds: ", rounds
    write !,"Size: ", size
    write !,"NullPercent: ", nullPercent
    write !,"List: "
    zwrite list
        
    set ways = $lb("listnext", "listfind", "lfs", "base")
    for i=1:1:$ll(ways) {
        set way = $lg(ways, i)
        set start = $zh
        
        set list2 = $classmethod(,way, rounds, list)
        
        set end = $zh
        
        set time = end - start
        
        write !,"Way: ", way
        write !,"Time: ", time
        write !,"List: "
        zwrite list2
        write !
    }
}

ClassMethod base(rounds As %Integer = 1000, list As %List) As %List
{
    for i=1:1:rounds {
        set origList = list
    }
    quit origList
}

ClassMethod listfind(rounds As %Integer = 1000, list As %List)
{
    for i=1:1:rounds {
        set origList = list
        set ptr=0
        for  set ptr=$LISTFIND(origList, $c(0), ptr) quit:'ptr  set $LIST(origList, ptr, ptr)=$lb()
    }
    quit origList
}

ClassMethod listnext(rounds As %Integer = 1000, list As %List)
{
    for i=1:1:rounds {
        set list2 = ""
        set ptr = 0
        while $listnext(list, ptr, elem) {
            if elem'=$C(0) {
                set list2 = list2 _ $LB(elem)
            } else {
                set list2 = list2 _ $LB()
            }
        }
    }
    quit list2
}

ClassMethod lfs(rounds As %Integer = 1000, list As %List)
{
    for i=1:1:rounds {
        set str = $lts(list)
        set str = $tr(str, $c(0))
        set list2 = $lfs(str)    
    }
    quit list2
}

ClassMethod getList(size As %Integer = 10, nullPercent As %Integer = 20) As %List
{
    set list = ""
    for i=1:1:size {
        set list = list _ $lb($select($random(101)<=nullPercent:$c(0),1:$random(50)))
    }
    quit list
}

Results:

POI>do ##class(POI.Test).main(1000000)
 
Rounds: 1000000
Size: 10
NullPercent: 20
List: list=$lb(25,20,$c(0),$c(0),4,42,$c(0),28,44,3)
 
Way: listnext
Time: .944814
List: list2=$lb(25,20,,,4,42,,28,44,3)
 
 
Way: listfind
Time: .610244
List: list2=$lb(25,20,,,4,42,,28,44,3)
 
 
Way: lfs
Time: .430088
List: list2=$lb("25","20","","","4","42","","28","44","3")
 
 
Way: base
Time: .032151
List: list2=$lb(25,20,$c(0),$c(0),4,42,$c(0),28,44,3)

listfind solution seems optimal.

Eduard Lebedyuk · Aug 28, 2018 go to post

Develop client part (angular, etc) in your favorite editor, build it there and set build directory as a CSP Files Physical Path for CSP application.

Additionally set Serve Files to Always and Serve Files Timeout to 0.

Eduard Lebedyuk · Aug 28, 2018 go to post

Terminal works under your own OS user.

Studio pseudo-terminal works under Cache system account.

They may have different access levels.

Eduard Lebedyuk · Aug 27, 2018 go to post

From windows error codes

2 (0x2)
The system cannot find the file specified.
ERROR_PATH_NOT_FOUND

Check your path, also Caché may not have access to the directory or file.

Eduard Lebedyuk · Aug 27, 2018 go to post

Please check the output:

set result = ##Class(%File).Delete(fileNamewithPath, .status)
zw result
zw status
Eduard Lebedyuk · Aug 24, 2018 go to post

Well, updating to a newer version is definetly recommended.

This feature (SSLCheckServerIdentity) appeared in 2013.2.

That said, comments to the feature state that the new default is to check the name where as before we did not perform this check.

So on older version request should be working by default. What error are you getting on old version?

Eduard Lebedyuk · Aug 24, 2018 go to post

There are several ways to do that. Let's say you have a persistent property

Property Problem As %String;

That you don't want anyone to see.

1. Make it private:

Property Problem As %String [ Private ];

It would not be displayed altogether

2. Add accessor methods:

Property Problem As %String;

Method ProblemGet() As %String [ ServerOnly = 1 ]
{
    Quit "****"
}

Method ProblemRealGet()
{
    Quit i%Problem2
}

Method ProblemSet(Arg As %String) As %Status [ ServerOnly = 1 ]
{
    Set i%Problem2 = Arg
    Quit $$$OK
}

This way default callers would get **** and only your app code can access the real value.

3. Do not project property to XML

Property Problem As %String(XMLPROJECTION = "none");

As ensemble message viewer is XML-based it would hide property from it.

4. Create a special datatype. For example MyApp.Datatype.Password datatype returns **** as Display and ODBC values:

Class MyApp.Datatype.Password Extends %String
{

ClassMethod LogicalToDisplay(%val As %String) As %String [ Internal ]
{
    q $case(%val,"":"",:"*****")
}

ClassMethod LogicalToOdbc(%val As %String) As %String [ Internal ]
{
    q $case(%val,"":"",:"*****")
}

}

To use it:

Property Problem As MyApp.Datatypes.Password;

5. Extract the property into a separate class and reference the object of that class.

These approaches could be combined.