If you are familiar (proficent) with ZEN use ZEN Mojo.
If not, write HTML/JS/CSS client and REST server.
That said, DeepSee would definitely be an easier solution to implement and more robust overall.
- Log in to post comments
If you are familiar (proficent) with ZEN use ZEN Mojo.
If not, write HTML/JS/CSS client and REST server.
That said, DeepSee would definitely be an easier solution to implement and more robust overall.
Use DeepSee - Intersystems analytics technology. It can be embedded in transactional systems to enable users to make decisions based on real-time analysis of structured and unstructured data.
There's a sample Patients cube in samples namespace.
Here's how it can look for end user.

Here's a good article on pagination I read recently. tl;dr other approaches than row numbering do exist.
Replace full reference to a global with one zn.
Consider the following code:
Class Utils.Global
{
/// Do ##class(Utils.Global).Generate()
ClassMethod Generate(NS = "SAMPLES", Count = 100000000)
{
New $namespace
Zn NS
Kill ^LAB
For i=1:1:Count {
Set ^LAB(i) = i
}
}
/// Do ##class(Utils.Global).Test()
ClassMethod Test(NS = "SAMPLES")
{
Set time = $p($h,",",2)
Do ..Ref1(NS)
Set time1 = $p($h,",",2)
Do ..Ref2(NS)
Set time2 = $p($h,",",2)
Write "Full ref time ",time1-time,!,"ZN time ",time2-time1
}
ClassMethod Ref1(NS)
{
Set PIDX=""
For {
Set PIDX=$ORDER(^[NS]LAB(PIDX))
Quit:PIDX=""
}
}
ClassMethod Ref2(NS)
{
New $namespace
Zn NS
Set PIDX=""
For {
Set PIDX=$ORDER(^LAB(PIDX))
Quit:PIDX=""
}
}
}When I run Do ##class(Utils.Global).Test() in a terminal I get the following results:
Full ref time 38 ZN time 35
even better difference on smaller loops (10000000):
Full ref time 3 ZN time 2
Use
It can possibly be called from OnStart method in production class, from where you can determine an environment (DEV or PROD) and enable/disable correct business hosts based on that.
Template is most probably a string, so the usual $find would work.
Yes, both %Collection.ListOfDT and %Library.ListOfDataTypes classes implement LogicalToDisplay method. I recommend you read class documentation, or read the class definitions themselves, it's the easiest way of understanding of what goes on inside Caché classes.
If data is too big for a string then result would also be too big for a string.
I think something like this would work:
It can be done as one method with this signature ( so it would be possible to pass any number of data streams for one template):
Check if variable is defined beforehand and generate/use a new variable name if required:
ClassMethod GetNewVarName() As %String
{
Set Name = "Temp"
While $Data(@Name) {
Set Name = Name _ $Random(100)
}
Return Name
}The easy way to display list object:
for i=1:1:user.Roles.Count() w user.Roles.GetAt(i),!You can also serialize list object to $list and display it:
zw user.Roles.Serialize()Also note that lists of datatypes defined as class properties are of %Collection.ListOfDT class (which is somewhat similar but not identical to %ListOfDataTypes class).
You can also get all information on %ListOfDataTypes objects with zw command:
s b=##class(%ListOfDataTypes).%New()
do b.Insert(1)
do b.Insert(2)
do b.Insert(3)
zw bGreat article, I find this feature very useful too, here's my %ZLANGC00:
; %ZLANGC00
; custom commands for ObjectScript
; http://localhost:57772/csp/docbook/DocBook.UI.Page.cls?KEY=GSTU_customize
Quit
/// Execute Query and display the results
/// Call like this:
/// zsql "SELECT TOP 10 Name FROM Sample.Person"
ZSQL(Query)
#Dim ResultSet As %SQL.StatementResult
Set ResultSet = ##class(%SQL.Statement).%ExecDirect(, Query)
Do ResultSet.%Display()
Quit
/// Move user to a namespace of his choice
/// Call like this:
/// zm "s"
ZM(Namespace)
Do MoveToNamespace^%ZSTART(Namespace)
Quit
/// Move to Samples namespace and set a as a Samples.Person object
/// Set b as %ZEN.proxyObject
/// Set c as %Object
ZO(move = 1) Public
ZN:move "SAMPLES"
If ##class(%Dictionary.CompiledClass).%ExistsId("Sample.Person") {
Set p = ##class(Sample.Person).%OpenId(1)
}
Set a = ##class(%ZEN.proxyObject).%New()
Set b = {}
Quitand related %ZSTART:
%ZSTART() {
Quit
}
/// This entry point is invoked on user login
/// offering user to choose a namespace
LOGIN() Public {
Set Timeout = 3
Write "Namespace <" _ $Namespace _ ">: "
Read Namespace:Timeout // Get value of a Namespace variable
Quit:Namespace=""
Do MoveToNamespace(Namespace)
}
/// Does actual moving to a chosen namespace
/// This is an entry point, for cases where
/// Namespace value is already aquired
MoveToNamespace(Namespace = "") Public {
Set Timeout = 3
#Dim List As %ListOfDataTypes
Set List = $$GetNamespaceList(Namespace)
Set Count = List.Count()
If Count = 1 {
Set Choice = 1
} ElseIf Count > 1 {
Do DisplayList(List)
// If there is less then 10 results, then we need only 1 digit
// Otherwise we need 2 digits
// It is assumed that no more then 99 results would be returned
Read "Select number <1>: ", Choice#$Select(Count < 10:1, 1:2):Timeout
// If the user entered nothing or not a valid number
// we select first namespace in a list to go to
Set:((Choice = "") || ('$IsValidNum(Choice, 0, 1, Count))) Choice = 1
} Else {
// No namespaces found
Quit
}
Zn List.GetAt(Choice)
}
/// Get all availible namespaces that satisfy
/// "Name %STARTSWITH Namespace" condition
/// as %ListOfDataTypes
GetNamespaceList(Namespace = "") {
New $Namespace
Set $Namespace = "%SYS"
#Dim List As %ListOfDataTypes
#Dim ResultSet As %SQL.StatementResult
Set List = ##class(%ListOfDataTypes).%New()
Set UserCondition = "%UPPER(Name) %STARTSWITH %UPPER(?)" // Or [ if you wish
Set Condition="(" _ UserCondition _ ") AND (SectionHeader='Namespaces') AND (%UPPER(Name)!='%ALL')"
Set SQL = "SELECT Name FROM Config.Namespaces WHERE " _ Condition
Set ResultSet = ##class(%SQL.Statement).%ExecDirect(, SQL, Namespace)
While ResultSet.%Next() {
Do List.Insert(ResultSet.%Get("Name"))
}
Quit List
}
/// Display %ListOfDataTypes in a format:
/// 1 item
/// 2 item
/// ...
DisplayList(List) {
#Dim List As %ListOfDataTypes
Write !
For i = 1:1:List.Count() {
Write i, $C(9), List.GetAt(i), !
}
}
Both BuildValueArray and LogicalToDisplay work with serialized form of %ListOfDataTypes object - $list string:
do ##class(%ListOfDataTypes).BuildValueArray($lb("a","b","c"), .out)
zw outOutputs:
out(1)="a" out(2)="b" out(3)="c"
To sum up:
Follow up on that. Can I store MD5/SHA in a database as is or do I need to convert it to base64 first?
Hello.
Can you please publish it as a GitHub repository?
Yes, I'm aware of that. There is not that much records (hundreds of thousands tops). Still, decided to do a comparison:
ClassMethod Time(count = 100000000)
{
Set str = "111111111111111111111111111111111111111111111111111111111"
Set time1 = $P($h, ",", 2)
For i=1:1:count {
s a = $zcrc(str, 7)
}
Set time2 = $P($h, ",", 2)
For i=1:1:count {
s a = $System.Encryption.MD5Hash(str)
}
Set time3 = $P($h, ",", 2)
For i=1:1:count {
s a = $System.Encryption.SHA1Hash(str)
}
Set time4 = $P($h, ",", 2)
For i=1:1:count {
s a = $System.Encryption.SHAHash(256, str)
}
Set time5 = $P($h, ",", 2)
Write !,"CRC: ",time2-time1,!,"MD5: ",time3-time2,!,"SHA1: ",time4-time3,!,"SHA2: ",time5-time4
}It outputs the following results:
CRC: 14 MD5: 72 SHA1: 119 SHA2: 140
A maximum of 254 arguments can be passed to a method:
ClassMethod Gen(count = 255)
{
set out = "w ..hash("
for i=1:1:count-1 {
set out = out _ "1,"
}
set out = out _ "1)"
x out
}
ClassMethod hash(in...)
{
set crc = 0
for i=1:1:in {
set crc = $zcrc($char(i#256)_in(i), 7, crc)
}
return crc
}> EnsLib.SQL.Snapshot.GetRowList().
Thank you.
> additional field in the external database
Would have been nice, but not happening unfortunately.
Here's CRC hashing method (accepts any number of arguments):
ClassMethod hash(in...)
{
set delimiter = $c(255)
set str = delimiter
for i=1:1:in {
set str = str _ in(i) _ delimiter
}
return $zcrc(str, 7)
}Yes. Use resources instead. Read the docs. $ZPARENT value is also a "resource" that's getting created with the process, so children processes can communicate events to a parent process easily. As processes you want to pass messages between are not parent and child, you need to create and use explicitly named resources.
I think only profiler for the exact case can really answer this kind of questions. Too many nuances in the real-life code for one-fits-all solution of any kind to be feasible.
> one "extremum" version:
Does not really count. The method signature must be:
ClassMethod ToPhone(t As %String) As %String {}Hello.
While there is currently no way to it, you can see %DeepSee.UI.MDXExcel class, which does excel export and write your own csv exporter. It would be a simplified copy of %DeepSee.UI.MDXExcel.
All output is done via &html so you need to replace that with the usual write.
I knew about the second option (my original question was not clear on that I guess), but I'm really interested in the first option: how do I open *.cls directly?
Here's the sample process:

when I click on ContractFinalApprovalProcess BPL opens instead of cls.