go to post Eduard Lebedyuk · Jun 21, 2016 Zen Mojo is a set of classes that enable you to create web pages, suitable for either mobile devices or desktops.ZEN Mojo is a new and improved ZEN.
go to post Eduard Lebedyuk · Jun 21, 2016 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.
go to post Eduard Lebedyuk · Jun 21, 2016 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.
go to post Eduard Lebedyuk · Jun 21, 2016 Here's a good article on pagination I read recently. tl;dr other approaches than row numbering do exist.
go to post Eduard Lebedyuk · Jun 20, 2016 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 GitHub.
go to post Eduard Lebedyuk · Jun 18, 2016 Use EnableConfigItem method of Ens.Director class to enable/disable business hosts programmatically.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.
go to post Eduard Lebedyuk · Jun 18, 2016 HTTP debug proxies can and do work with https traffic, for example Charles. You need to install the certificate for that, but it's definitely doable.
go to post Eduard Lebedyuk · Jun 16, 2016 Template is most probably a string, so the usual $find would work.
go to post Eduard Lebedyuk · Jun 16, 2016 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.
go to post Eduard Lebedyuk · Jun 16, 2016 You can use any ODBC/JDBC database management software. I use DataGrip. It has code completion for table/field names and standard SQL syntax.
go to post Eduard Lebedyuk · Jun 16, 2016 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:Create result streamFind positions of the beginning and the end of the first placeholder in the templateWrite template from the start to the beginning of the first placeholderCopy data stream into result streamRepeat 2-4 till you have no more placeholders (if there's more than one placeholder per template)Send result stream out via a soap webserviceIt can be done as one method with this signature ( so it would be possible to pass any number of data streams for one template):ClassMethod FillTemplate(Template As %String, Data... As %Stream.GlobalCharacter) As %Stream.GlobalCharacter {}
go to post Eduard Lebedyuk · Jun 14, 2016 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 }
go to post Eduard Lebedyuk · Jun 13, 2016 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 b
go to post Eduard Lebedyuk · Jun 12, 2016 Great 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 = {} Quit and 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), ! } } Github repo.
go to post Eduard Lebedyuk · Jun 10, 2016 Both BuildValueArray and LogicalToDisplay work with serialized form of %ListOfDataTypes object - $list string: do ##class(%ListOfDataTypes).BuildValueArray($lb("a","b","c"), .out) zw out Outputs: out(1)="a" out(2)="b" out(3)="c" To sum up: %ListOfDataTypes - objectserialized %ListOfDataTypes - $list$list - a string (with special properties, but not an object)%List - $list
go to post Eduard Lebedyuk · Jun 9, 2016 Follow up on that. Can I store MD5/SHA in a database as is or do I need to convert it to base64 first?
go to post Eduard Lebedyuk · Jun 9, 2016 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
go to post Eduard Lebedyuk · Jun 9, 2016 Unfortunately there is no such thing. Would be great to have this feature. Currently in my projects I manually write all possible paths, for example here.
go to post Eduard Lebedyuk · Jun 9, 2016 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 }