Eduard Lebedyuk · Sep 29, 2017 go to post

You can use pure javascript to do that:

function PrintAll() {
    var files = ["file1.pdf", "file2.pdf", "file3.pdf"];
    for (var i = 0; i < files.length; i++) {
        var newWindow = window.open(files[i], "print");
        newWindow.print();
        newWindow.close();
    }
}
Eduard Lebedyuk · Sep 29, 2017 go to post

Your options are:

  • Try to compile crypt only under win x64 (libc as a whole can't be compiled under windows, but maybe you can compile crypt module)
  • PHP doc you referenced states that PHP has it's own fallback implementation when OS does not provide crypt implementation. Check where does PHP search for crypt implementation on windows - it's probably some C lib and call it too
  • Write the algorithm yourself, here's  a good guide on that
  • Use another more secure hashing algorithm, for example SHA-512
Eduard Lebedyuk · Sep 28, 2017 go to post

There is also CNA project - it provides an interface for using native C-compatible shared libraries without anything but Caché ObjectScript code. CNA is a wrapper for libffi. CNA consists of native library (libcna) and Caché class (CNA.CNA). It is a wrapper around $zf functions (you can use them directly too).

Here's the code to call crypt using CNA:

Class CNA.Crypt
{

/// do ##class(CNA.Crypt).Crypt()
ClassMethod Crypt(key = "2Ggaobjb", salt = "$1$1a2b3c4d$")
{
    set cna = ##class(CNA.CNA).%New("/InterSystems/forCLM/libcna.so") ; Creates object of CNA.CNA class.
    do cna.LoadLibrary("/lib/x86_64-linux-gnu/libcrypt-2.23.so")      ; Loads C standard library (crypto) in CNA

    set keyPointer = cna.ConvertStringToPointer(key) ; Converts the string into char array, and saves pointer to the first element

    set saltPointer = cna.ConvertStringToPointer(salt)

    set argTypes = $lb(cna.#POINTER, cna.#POINTER)   ; function argument types
    set result = cna.CallFunction("crypt",          ; Passes the name of the function,
                                cna.#POINTER,       ; type of return value,
                                argTypes,         ; list of argument types,
                                keyPointer, saltPointer)           ; and comma-separated arguments */    
    write cna.ConvertPointerToString(result), !      
   
    do cna.FreeLibrary()
}

}

Sample output:

do ##class(CNA.Crypt).Crypt()
>$1$1a2b3c4d$Y5tt50CQ12xW2saeYnI43.

do ##class(CNA.Crypt).Crypt("ABC", "$1$12345678$") 
>$1$12345678$0QgUhxfT5h1pvtkhF5pzx/ 
Eduard Lebedyuk · Sep 27, 2017 go to post
Write ##class(Security.Resources).Export("C:\Resources.xml")
Write ##class(Security.Resources).Import("C:\Resources.xml")
Eduard Lebedyuk · Sep 27, 2017 go to post

"Print" SVG to file or stream. It depends on what you want to do with the image.

For example opening this popup as a separate tab and capturing all web page with auto-scroll would yield a complete bp image.

 

If you're talking about nested whiles and such, I don't think there's an easy way  to expand them all into one diagram.

Eduard Lebedyuk · Sep 27, 2017 go to post

This condition is insufficient for multi-level inheritance (C is a subclass of B, B is subclass of A. So C is subclass of A but Super wouldn't show this information). More on that in here.

Eduard Lebedyuk · Sep 27, 2017 go to post

SMP -> Ensemble -> Build -> Business Processes -> [Open your BP] -> Show print friendly version of diagram -> Print that page.

EnsPortal.SVG.SVGPrint.zen page outputs the SVG image so if you need you can subclass it to print SVG to file or inject into some document.

Eduard Lebedyuk · Sep 26, 2017 go to post

SQL gateway connections settings are stored in %SQLConnection class and the corresponding %Library.sys_SQLConnection table. Note that passwords are stored in encrypted form, so you can't get them as a plaintext. Also password may be stored as a part of system ODBC configuration, so there would be no password at all stored in Caché.

Eduard Lebedyuk · Sep 22, 2017 go to post

Assuming  you're on 2016.2+:

set payload = "{""profile_id"":""9XOzzcI8NfSUjxAhEt0cTLRejwmp6HPi"",""biometrics"":[{""timestamp"":""2017-05-17T13:45:40"",""utc_offset"":""+02:00"",""resting_heartrate"":120.0,""spo2"":98.0,""activity_id"":""591c540aac8f295479ee14ce""}]}"
set obj = {}.%FromJSON(payload)
write obj."profile_id"
>9XOzzcI8NfSUjxAhEt0cTLRejwmp6HPi
write obj.biometrics.%Get(0).timestamp
>2017-05-17T13:45:40
Eduard Lebedyuk · Sep 21, 2017 go to post

It's really not.

You can have "On Demand" task and call it from %ZSTART. This way you can have task scheduler reporting and execute task only when it's required.

Eduard Lebedyuk · Sep 20, 2017 go to post

Is there any reason to use Task Manager instead of %ZSTART?

 

Anyway you can have a task that runs hourly, and checks for existence of ^CacheTemp.MyTask global. If the global does not exist, set it and execute the task. If the global exists - quit. Since restart wipes CacheTemp, the global wouldn't exist on startup.

Eduard Lebedyuk · Sep 20, 2017 go to post

What if I have extra properties such as InsertTime in the Test.cvs class?

What about them? When you call %SQL.Util.Procedures:CSVTOCLASS you need to specify rowtype, corresponding to your CSV structure. If you have InsertTime property you need to reflect it and any other properties CSV has in your rowtype.

Eduard Lebedyuk · Sep 20, 2017 go to post

In Ensemble Visual Trace you can filter by Business Host. To do that:

  1. Open Ensemble Visual Trace
  2. Click on the Business Host you need
  3. In Apply Filter dropdown choose the  filter you need (Host or Corresponding)
  4. Visual trace would be filtered to messages sent to/from specified Business Host

 

Eduard Lebedyuk · Sep 20, 2017 go to post

 Here's how:

  1. SMP > Ensemble > Production Configuration > Your Business Service > Settings > Additional Settings > Schedule > Press on the the looking glass
  2. In Schedule Spec Editor press "New"
  3. Specify Schedule name and press OK
  4. Set "Raw String" schedule or use "Add action" specify a schedule
  5. Press "Save spec"
  6. Schedule setting in your Business Service should be set now
  7. Restart your Business Service
Eduard Lebedyuk · Sep 20, 2017 go to post

To run Business Service once an hour:

  1. Specify Ens.InboundAdapter as an adapter for your Business Service
  2. On Production Configuration page, in Business Service configuration set Call Interval to 3600.
  3. Restart Business Service. It would now be run once an hour (every 36000 seconds)
Eduard Lebedyuk · Sep 20, 2017 go to post

To convert string of any format into $horolog, use TO_DATE function:

w $SYSTEM.SQL.TODATE("20160105125915","YYYYMMDD")
>63922

To convert string of any format to timestamp use TO_TIMESTAMP function:

w $SYSTEM.SQL.TOTIMESTAMP("20160105125915","YYYYMMDDHHMISS")
>2016-01-05 12:59:15

These functions are available in Caché ObjectScript and SQL.

Eduard Lebedyuk · Sep 20, 2017 go to post

Provided you have this csv:

car,2000,100.51,27.10.2016,
phone,2003,65.8,15.01.2017,

You can import it into class Test.CSV:

1. Generate a persistent class Test.CSV

set rowtype = "name VARCHAR(50),year INTEGER,amount NUMERIC(9,2),date DATE"
set filename = "D:\data.csv"
do ##class(%SQL.Util.Procedures).CSVTOCLASS(2, .rowtype, filename,,,,"Test.CSV")

2. Import file or files

do ##class(Test.CSV).Import(2,filename)

 

Usually you can't import your CSV right away - the dates are in a different format, etc. You need to modify Import method and property definitions. For example I often:

  • Add FORMAT=4 property parameter for dates to import dates in dd/mm/yyyy format.
  • Find&replace Library.
  • Add this else line in Import method:
if $$$ISOK(tStatus) { set tCounter = tCounter + 1 } else { w $System.Status.GetErrorText(tStatus) return}

 

If you have a tab separated file, you need to change Import method signature from:

pDelimiter As %String = ","

to:

pDelimiter As %String = {$c(9)}
Eduard Lebedyuk · Sep 19, 2017 go to post

Check out Demo.ZenService.Zen.WeatherReportForm class in ENSDEMO namespace. GetWeatherReport method there creates a BS and sends a message to a BP outside of Ensemble context. You need to send an object and not a datatype, so in your example:

Set tSC = tService.ProcessInput(datePurge,.output)

Should be instead:

Set message = ##class(Ens.StringContainer).%New(datePurge)
Set tSC = tService.ProcessInput(message,.output)

If you want to send a message to a BP or BO you can do that too, just create an Ensemble message and use SendSync or SendAsync to send it from BS:

Set message = ##class(Ens.StringContainer).%New(datePurge)
Set targetHostName = "Name of BP or BO"
Set description = "My request description"
// Set timeout = 10 // how long to wait for a Sync call response, skip to wait forever
// Set tSC = tService.SendRequestSync(targetHostName, message, .response, timeout, description)
Set tSC = tService.SendRequestAsync(targetHostName, message, description)

That said, Ensemble hosts can run on schedule so you can use built-in Ensemble scheduler and not a system task manager.

Eduard Lebedyuk · Sep 19, 2017 go to post

How does Vue.JS stacks against other popular JS frameworks like Angular2, React, etc.?

Eduard Lebedyuk · Sep 19, 2017 go to post

I prefer %SQL.Util.Procedures because it is easier to use and it generates classes and methods that can be easily modified.

Eduard Lebedyuk · Sep 18, 2017 go to post

Ensure that user, which you are using to access the database has apropriate permissions to connect and access data.

Eduard Lebedyuk · Sep 16, 2017 go to post

> Would you have three branches for the code or 3 repo's.


Please describe differences between your DEV, TEST, PROD code. Still, I'd probably recommend one repo and 3 branches.

>Would you have three projects in Atelier to communicate with the environments and GitHub?


No, there would be one Atelier project for DEV. All other code propagation should be done automatically by Continuous Integration/Continuous Delivery solution.

Eduard Lebedyuk · Sep 12, 2017 go to post

That may mean one of the several things:

  • You're not specifying or specifyiong incorrectly one or several request header parameters. One of the most often encountered errors is not specifying ContentType as application/json.
  • Request content is formed incorrectly

Anyway, to solve this problem you need to make a correct request to the target system, record it and compare to the Ensemble request. Here's an article on that.