go to post Rubens Silva · Jul 17, 2017 Great article right there. But hey @Sergey Kamenev, could you put a reference the other two parts that you made as well?
go to post Rubens Silva · Jul 14, 2017 If you want to work on a project basis and versionate it, but still want to work with Studio, you can try using Port to test if it satisfies you. By default Port will export your project using UDL format and also a XML for backward compability. If you want to export only files that ends with .csp, you can save your current project with another name and use the Remove classes, Remove routines. From the Source Control menu. Remember though, that Port is made to be ran locally instead of making your pc work like a thin client for Caché. That means your Source code should preferably be local and not remote.Also, you're welcome to open issues. And, even though there's an alert about the nightly branch is pretty stable for now, since I have been working mostly on adding unit tests and fixing minor bugs.P.S: Just to take a note. The Port repository is exported using itself.
go to post Rubens Silva · Jul 14, 2017 /// Returns a list of the Globals in a Cache NameSpace (used for GUI display)<br>/// <br>/// <b>Parameters:</b> <br>/// NameSpace - a Cache namespace. Default is current namespace. <br>/// Mask - a mask, or comma-separated list of masks, to select globals. Default is "*" for all.<br>/// SystemGlobals - boolean flag to include system globals in the results. Default is "0".<br>/// UnavailableDatabases - a returned local array of any databases not currently accessible, i.e. array(name)=status.<br>/// Index - Internal use only.<br>/// IgnoreHasData - For faster list of Globals set this to 1 and the HasData column will always be FALSE.<br>/// Mapped - Return all mapped global nodes when set to 1, the default value of this parameter is 1./// <br>/// Valid masks are as follows:/// <br>/// ABC* - All strings starting with ABC<br>/// A:D - All strings between A and D<br>/// A:D,Y* - All strings between A and D, and all strings starting with Y<br>/// A:D,'C* - All strings between A and D, except those starting with CQuery NameSpaceList( NameSpace As %String, Mask As %String, SystemGlobals As %Boolean, ByRef UnavailableDatabases As %String, Index As %Integer, IgnoreHasData As %Boolean = 0, Mapped As %Boolean = 1) As %Query(ROWSPEC = "Name:%String,Location:%String,ResourceName:%String,Permission:%String,Empty:%String,Keep:%String,Collation:%String,PointerBlock:%String,GrowthBlock:%String,HasData:%Boolean,Journal:%String,LockLocation:%String,HasSubscripts:%Boolean") [ SqlProc ]{}set s = ##class(%SQL.Statement).%New()do s.%PrepareClassQuery("%SYS.GlobalQuery", "NameSpaceList")set r = s.%Execute("SAMPLE", "*")set $namespace = "SAMPLE"while r.%Next() { kill @r.%Get("Name") }
go to post Rubens Silva · Jul 14, 2017 You can use value positioning to match their $list index according to their property definition index. But you will need to describe each property to detect their types and if they are instantiable. In case they do, you can use the value to open the instance and the property type. E.g:set properties = ##class(%Dictionary.CompiledClass).%OpenId("SQLUser.Table").Propertiesfor i=1:1:propeties.Count() { set listValue = $lg(SQLUser^TableD(1) , i) set property = propeties.GetAt(i) // if property.Type inherits from %RegisteredObject set value = $System.OBJ.OpenId(property.Type, listValue) // else set value = listValue}If you don't want to open the class descriptor instance you can also use macros from %occReference.inc. But you will have to deal with $order.My suggestion takes the longest path. You will need a method that supports each property type behavior, like that lb(,,"bla","20050502123400").But why can't you use an instance? Is it because the structure is too old and there isn't any %Persistent class to represent it?
go to post Rubens Silva · Jul 12, 2017 "The following example uses relative dot syntax (..) to refer to a method of the current object."If so, it's pretty misleading. But I accept your answer and will mark it as well.
go to post Rubens Silva · Jul 11, 2017 Oh crap! I knew I had seen it somewhere.EDIT: Ahh, btw... it's Util, not Utils.
go to post Rubens Silva · Jul 11, 2017 On %CSP.Session /// Specifies the timeout value for the session in seconds./// <P>If no user requests are received within the specified time period, /// then the session will end. The default value comes from the CSP application/// setting for the application that the session starts in which is set in the/// Cache configuration manager, this is often 900 seconds or 15 minutes./// Note that if you start a session in one applicaiton and move to another application/// the AppTimeout will not be changed to the new applications timeout value, if you wish/// to modify this when the application changes you can use the session events 'OnApplicationChange'/// method./// <P>For no timeout, set this property to 0.Property AppTimeout As %Integer [ InitialExpression = 900 ];You can also specify the timeout for your App as a whole: <your server ip:57772>/csp/sys/sec/%25CSP.UI.Portal.Applications.Web.zen?PID=%2Fcsp%2Fuser
go to post Rubens Silva · Jul 11, 2017 Since you didn't specified which service you're using it's hard to simulate your doubt.However I did a quick research and noticed that 'padding' actually refers to OAEP, this could be the method you want to use to encrypt. I'm not sure though. /// This method performs RSA encryption as specified in/// PKCS #1 v2.1: RSA Cryptography Specifications, section 7 Encryption Schemes./// <br><br>/// Input parameters:/// <br><br>/// Plaintext - Data to be encrypted./// <br><br>/// Certificate - An X.509 certificate containing the RSA public key to be used for encryption,/// in PEM encoded or binary DER format./// Note that the length of the plaintext can not be greater than the length of the modulus of/// the RSA public key contained in the certificate minus 42 bytes. /// <br><br>/// CAfile - The name of a file containing trusted Certificate Authority X.509 Certificates in PEM-encoded format, one of which was/// used to sign the Certificate (optional)./// <br><br>/// CRLfile - The name of a file containing X.509 Certificate Revocation Lists in PEM-encoded format that should be checked/// to verify the status of the Certificate (optional)./// <br><br>/// Encoding - PKCS #1 v2.1 encoding method (optional):<br>/// 1 = OAEP (default)<br>/// 2 = PKCS1-v1_5<br>/// <br><br>/// Return value: Ciphertext.ClassMethod RSAEncrypt(Plaintext As %String,Certificate As %String,CAfile As %String,CRLfile As %String,Encoding As %Integer) As %String{}
go to post Rubens Silva · Jul 7, 2017 I don't think there's an implementation for Caché for now. Can't you try using bindings? Google provides a code generator for C++ and Java as well.From here: https://developers.google.com/protocol-buffers/docs/cpptutorialAnd bindings here: http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=...
go to post Rubens Silva · Jul 4, 2017 I just posted my implementation on Git for analysis.https://github.com/rfns/cache-fp-poc
go to post Rubens Silva · Jul 4, 2017 As long as there's an abstract API for parsing, lexing, transpiling and serializing. It would be possible to even port any FP or FRP language to Caché.Since you demo'ed JavaScript, it seems programming on a functional way could be possible if we could simply pass methods as parameters.Well, that's actually the core rule for a language that supports functional paradigms.Since there's no current support for such paradigm. Maybe we could wrap it using indirections or xecutes? set array = []do a.%Push({ "value": "some value to be replaced" })set result = ##class(FP.Functor).%New()From(array).Map($this, "...ValueWithIndex", scopeParam)Method ValueWithIndex(item As %DynamicObject, index As %Integer, scopeParams... As %String) { // Second core rule: always keep it pure. Map should always Clone the item, which could be implicit for Map. // But for this case I'll demonstrate it manually. set clonedItem = item.Clone() // Or %ConstructClone if possible. set clonedItem .%Set("value", "modified with "_index) return clonedItem}Please note that this still doesn't provide the possibility to use high-order functions. The closest we could have I think is embedding subroutines within your context method. Which could also be reproduced as: // Can also be Method.ClassMethod YourContextMethod() As %String{set scopeParam = "blahblahblah"// Now assume we're using %ZEN.proxyObject. Omitted for brevity.set result = ##class(FP.Functor).From(array).Map("$$HOMapWithScopeParam", scopeParam)HOMapWithScopeParam(result, item, value, scopeParam...) // Now Implicitly cloned into result param. set result.value = scopeParam(0) // Could be improved. quit result}Nope, I forgot that procedures are exclusive for the subroutine that's defining them.
go to post Rubens Silva · Jul 4, 2017 I did a little experiment and here's the result: ClassMethod testing(item){ set array = ##class(%ListOfObjects).%New() for i=1:1:10 { set proxy = ##class(%ZEN.proxyObject).%New() set proxy.value = i do array.Insert(proxy) } set DoubleItemValueSumTwo = $classname()_":DoubleItemValueSumTwo" set Odds = $classname()_":Odds" set BiggerThanFive = $classname()_":BiggerThanFive" set result = ##class(FP.Functor).From(array).Map(DoubleItemValueSumTwo).Filter(Odds).Every(BiggerThanFive).Result() quit result}ClassMethod DoubleItemValueSumTwo(item As %ZEN.proxyObject,i){ set item.value = (item.value * 2) + $random(2) quit item}ClassMethod Odds(item As %ZEN.proxyObject,i){ quit (item.value # 2 '= 0)}ClassMethod BiggerThanFive(item As %ZEN.proxyObject,i As %Integer){ quit item.value > 5}There is space for a lot of improvements I think. It's not exactly what you would call a performatic implementation. But that's a beginning.
go to post Rubens Silva · Jul 4, 2017 Instead of creating multiple repositories. Can't you just create a single repository and keep all projects inside it?This is what a monorepository approach does.Big companies like Google opted-out for using this approach because they started to find it too hard to manage issues across multiple repositories, since one should clone the issued repository along with a tree of dependencies to make it testable. And that's only one use case.Some few examples:https://eng.uber.com/ios-monorepo/https://medium.com/@pejvan/monorepos-85e608d43b57https://blog.ghaering.de/post/monorepo-march/Now you must consider if that's a option for your company. Since using monorepo actually seems to be a trend and can lead you into traps.
go to post Rubens Silva · Jul 3, 2017 Though, I do think Google I/O and Apple are also streamed over YouTube.Can't say much about Oracle...
go to post Rubens Silva · Jul 3, 2017 set key = "" set var1 = "code2" for { set key = $order(^myglobal(key), 1, list) quit:key="" if $listget(list, 1) = var2 kill ^myglobal(key) } Use $order to iterate over global subscripts.
go to post Rubens Silva · Jul 3, 2017 Although Caché does have a %DataTypes layer for SQL, the database engine itself is purely based on globals, which is losely typed.Thus, what I can say for you is:Local variables (memory) is by default around 32 kilobytes, you can upgrade this amount up to 50x.So, straight from the documentation: Caché supports two maximum string length options:The traditional maximum string length of 32,767 characters.Long Strings maximum string length of 3,641,144 characters.Globals can go way beyond, since it's persisted.How huge a number can go? I suppose you're talking about floating precision.This might help you.And this explains about how Caché manages variables.Caché also provides you the possibility to redefine the memory allocation size for the context process.
go to post Rubens Silva · Jul 3, 2017 Yeah. I actually prefer using $$$GeneralError than creating my own error and having it display with <domain> before it's message. I think that" <domain>-errorcode: Message" pollutes the message for the end-user.I did a test using the tutorial you posted (which is great by the way!), but the way the Status API display the error by default kind made me fallback to 5001, which is cleaner.
go to post Rubens Silva · Jul 3, 2017 You can't use positive numbers because most of them are already defined inside %occErrors.inc and there's no way to inform which domain should the Error() use.