go to post Alexey Maslov · Nov 28, 2018 Hi everybody,I worked on similar task for Cyrillic (CP-1251 encoded) database last fall. My approach was very close to yours, while I did not see any reason to separate Group 1 from Group 2, so all data was converted on fly, without global export/import.
go to post Alexey Maslov · Nov 20, 2018 If so, I'd just put an icon which points to 'ccontrol stop ...' command file on the Work Table accessible to all users, or (to keep it secured better) on individual Work Tables of those ones who permitted to initiate the shutdown.
go to post Alexey Maslov · Nov 20, 2018 Dmitry and Ed,I'm just curious: why do you recommend the OP to use an entry point which is provided mostly for recovering from errors? In most cases we do *want* the user code to be executed, don't we? job INT^SHUTDOWN ; is the right code (corrected by Dmitry)
go to post Alexey Maslov · Nov 20, 2018 Hi Alexi, It sounds like you are wanted to:run the task in Caché Task Manager which does external call to some *.bat/.cmd file (so, calling out Caché)this .bat file should run some code inside Caché (so, calling in Caché back again)This scenario is possible (despite some security caveats), but (pardon me) - just rises unneeded difficulties. If your task can be solved easier than it initially seemed to be, why not take the easier (and more secure) way?
go to post Alexey Maslov · Nov 20, 2018 Remove ZNamespace "%SYS"from the ExecuteCode line. You may want to do it for either of two reasons:if you scheduled a new task using Task manager's defaults for startup namespace as "%SYS", it is not neededthis construction in syntactically wrong; zn "%SYS" or new $namespace set $namespace="%SYS" should be used instead.
go to post Alexey Maslov · Nov 20, 2018 best stay away from doing anything too clever as it can lead to unreadable codeNo, as staying away you are getting untrained, so you can loose an ability to read unreadable code written by others very soon
go to post Alexey Maslov · Nov 16, 2018 Documentation is not too verbose about it, do you agree? A small sample would be very helpful. E.g., how can one use it to recognize which of his/her classes was changed sinse some <timestamp>?
go to post Alexey Maslov · Nov 9, 2018 Evgeny --Thanks, I've already tried it before writing here. My current settings were: Prospect Accepted Unsubscribe from all except privacy, security, and account emailswhile I still received eMails about new challenges, etc. Just tried to turn off "Prospect Accepted", guessing that it can help, but this setting seems to be unswitchable (still active). It is hardly the source of a "problem" as I was never notified on the "prospect" stuff, even don't know its meaning.All these eMails are not a great deal of disturbance, I just dislike when I can't control their frequency. I don't insist on correction, if it causes extra efforts of your team - just sign me off from GM.
go to post Alexey Maslov · Nov 7, 2018 I joined Global Masters ages ago, but still can't find a way how to suppress it's notifications. How can I do it?
go to post Alexey Maslov · Nov 2, 2018 Hi Tomas,Your solution, despite its beauty, is correct for single digit numbers only: USER>set number="",$p(number,0,4)=1 w number 0001 USER>set number="",$p(number,0,4)=999 w number 000999 Its correct flavor (initially published by Larry Faraci) was included in my "code base" as #5, see https://community.intersystems.com/post/add-leading-zeros#comment-59096
go to post Alexey Maslov · Nov 1, 2018 Ben, thanks, I use the same approach.Nothing to add to the "code base" as this solution is already here by #1 (John was the first).
go to post Alexey Maslov · Nov 1, 2018 Thanks, Larry,Adding your variant to the "code base".As most of others, your solution needs * length correction * which I'm putting aside from Xecute to improve readability. lpad(number=1,length=4) new code,i,z,sign set number=+number set sign="" set:number<0 sign="-",number=-number set code($increment(code))="w sign_$tr($j(number,length),"" "",""0"")" set:length<$l(number) length=$l( number) ;* length correction * set code($increment(code))="w sign_$e(1E"_length_"+number,2,*)" set code($increment(code))="w sign_$e(10**length+number,2,*)" set code($increment(code))="w sign_$e($tr($j("""",length),"" "",0)_number,*-length+1,*)" set code($increment(code))="s $P(z,""0"",length)=number w sign_$E(z,*-(length-1),*)" for i=1:1:code write code(i)," => ",?60 xecute code(i) write ! quit
go to post Alexey Maslov · Nov 1, 2018 If we are looking for more generic solution, e.g. pad <number> by zeroes yielding to the field of given <length>, let's try: lpad(number=1,length=4) new code set code($increment(code))="w $tr($j(number,length),"" "",""0"")" set code($increment(code))="w $e(1E"_length_"+number,2,*)" set code($increment(code))="w $e(10**length+number,2,*)" set code($increment(code))="w $e($tr($j("""",length),"" "",0)_number,*-length+1,*)" for i=1:1:code write code(i)," => " xecute code(i) write ! quit Some results are: for n=999,9999,99999 d lpad^ztest(n,4) w ! w $tr($j(number,length)," ","0") => 0999 w $e(1E4+number,2,*) => 0999 w $e(10**length+number,2,*) => 0999 w $e($tr($j("",length)," ",0)_number,*-length+1,*) => 0999 w $tr($j(number,length)," ","0") => 9999 w $e(1E4+number,2,*) => 9999 w $e(10**length+number,2,*) => 9999 w $e($tr($j("",length)," ",0)_number,*-length+1,*) => 9999 w $tr($j(number,length)," ","0") => 99999 w $e(1E4+number,2,*) => 09999 w $e(10**length+number,2,*) => 09999 w $e($tr($j("",length)," ",0)_number,*-length+1,*) => 9999 Only the first solution (John's one) provides valid result even with "bad" input data ($length(99999) > 4). Others can't be amended this way without extra efforts irrelevant to this tiny task. Just to complete it: lpad(number=1,length=4) new code,i set code($i(code))="w $tr($j(number,length),"" "",""0"")" set code($i(code))="w $e(1E"_$s(length>$l(number):length,1:$l(number))_"+number,2,*)" set code($i(code))="w $e(10**$s(length>$l(number):length,1:$l(number))+number,2,*)" set code($i(code))="w $e($tr($j("""",$s(length>$l(number):length,1:$l(number))),"" "",0)_number,*-$s(length>$l(number):length,1:$l(number))+1,*)" for i=1:1:code write code(i)," => ",?60 xecute code(i) write ! quit Now all solutions become correct even with the <number> >= 99999, but only the first one keeps its simplicity.
go to post Alexey Maslov · Oct 25, 2018 Rosti,Your third option is the most generic and seems to be followed if you are developing from scratch because it keeps the door open for future extensions. E.g., imagine that a venue aggregator which provides on-line event search / ticket selling service would like to work with you. If you deploy your app as a separated instance or database for each venue, you would implement multi-database search for aggregating the events. Such technologies as containerization can help to organize the development/testing/[deployment(?)] better, but IMHO should not be of great impact on the app/database design. "The cart should not run in front of the horse", as old Russian proverb says.
go to post Alexey Maslov · Oct 22, 2018 Hi Pete,we have implemented the model that's very similar to yours with slight differences:we use it at home only, where we have several development and testing Caché instances;most of them are not connected using Mirroring and/or ECP;all Caché users are LDAP users, so we need not bother of creating/modifying users on per instance basis;one instance is used as a repository of roles definition (so called Roles Repository); it "knows" about each role that should be defined on each instance; this repository is wrapped with a REST service;each role has a "standard" name, e.g. roleDEV, roleUSER, roleADM; these names are used in LDAP users' definition and retrieved during LDAP authentication process;the resources lists for each standard role are stored in the Roles Repository; those lists are associated with instance addresses (server+port), so each role can be differently defined for different Caché instances; therefore, a user with the role roleDEV can have different privileges on different servers;each Caché instance queries the Roles Repository at startup; after getting the current definitions of its roles, it applies it to its Caché Security database.This solution is used in our company's Dev & Testing environment more than a year without great problems. It is rather flexible and doesn't depend on proprietary transport protocols. The only drawbacks found are:the Roles Repository is automatically queried at Caché startup only, so if something in role(s) definition(s) should be changed on fly, manual querying is needed;sometimes InterSystems introduces new security caveats with the new versions of its products; one of them was a subject of an article here: https://community.intersystems.com/post/implicit-privileges-developer-ro....
go to post Alexey Maslov · Oct 19, 2018 Hi Pavel,your solution sounds interesting.2) when mirror/backup goes up we use ZMIRROR hooksDo you scan the queue only on the backup node startup, as this is the time when ZMIRROR hooks are called? What if the node does not restarted several months, can the queue become too long to delay the startup completeness?
go to post Alexey Maslov · Oct 2, 2018 Vitaliy, thanks for the contribution. It seems that it ruins another myth, that Xecute is always slower than $[class]method. I've slightly reformatted an output of your ClassVsInst() method just to make it easier to compare results. Here are mine (using i5-4460 3.20 GHz): USER>d ##class(Scratch.test).ClassVsInst(1e7) Cache for Windows (x86-64) 2017.2.2 dummyClass10* total time = 2.669215 avg time = .0000002669215 dummyClass10 total time = 2.375893 avg time = .0000002375893 XdummyClass10 total time = 2.676997 avg time = .0000002676997 dummyInst10 total time = 2.221366 avg time = .0000002221366 XdummyInst10 total time = 2.276357 avg time = .0000002276357 dummyClass5* total time = 2.540907 avg time = .0000002540907 dummyClass5 total time = 2.232347 avg time = .0000002232347 XdummyClass5 total time = 2.541123 avg time = .0000002541123 dummyInst5 total time = 2.070013 avg time = .0000002070013 XdummyInst5 total time = 2.049437 avg time = .0000002049437 dummyClassNull* total time = 2.362451 avg time = .0000002362451 dummyClassNull total time = 2.097653 avg time = .0000002097653 XdummyClassNull total time = 2.352748 avg time = .0000002352748 dummyInstNull total time = 2.018773 avg time = .0000002018773 XdummyInstNull total time = 2.056379 avg time = .0000002056379 It seems that Xecute is (not surprisingly) very close to $classmethod and usually slower than $method. But what are we talking about? The difference is about several nanoseconds per call only.
go to post Alexey Maslov · Oct 1, 2018 Dear colleagues,Thank you for paying so much attention to this tiny question. Maybe it was too tiny formulated: I should mention that objects instantiation impact is beyond the scope of the question as all of them are instantiated once; correspondent OREFs are stored in global scope variables for "public" use.Going deep inside with %SYS.MONLBL is possible, while I'm too lazy to do it having no real performance problem. So, I've wrote several dummy methods, doubling instance and class ones, with different numbers of formal arguments, from 0 to 10. Here is the code I managed to write. Class Scratch.test Extends %Library.RegisteredObject [ ProcedureBlock ] ClassMethod dummyClassNull() As %String { q 1 } Method dummyInstNull() As %String { q 1 } ClassMethod dummyClass5(a1, a2, a3, a4, a5) As %String { q 1 } Method dummyInst5(a1, a2, a3, a4, a5) As %String { q 1 } ClassMethod dummyClass10(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) As %String { q 1 } Method dummyInst10(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) As %String { q 1 } } My testing routine was: ClassVsInst s p1="пропоывшыщзшвыщшв" s p2="гшщыгвыовлдыовдьыовдлоыдлв" s p3="widuiowudoiwudoiwudoiwud" s p4="прпроыпворыпворыпворыпв" s p5="uywyiusywisywzxbabzjhagjЭ" s p6="пропоывшыщзшвыщшв" s p7="гшщыгвыовлдыовдьыовдлоыдлв" s p8="widuiowudoiwudoiwudoiwud" s p9="прпроыпворыпворыпворыпв" s p10="uywyiusywisywzxbabzjhagjЭ" d run^zmawr("s sc=##class(Scratch.test).dummyClass10(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10)",1000000,"dummyClass10 "_$p($zv,"(Build")) n st s st=##class(Scratch.test).%New() d run^zmawr("s sc=st.dummyInst10(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10)",1000000,"dummyInst10 "_$p($zv,"(Build")) s st="" d run^zmawr("s sc=##class(Scratch.test).dummyClass5(p1,p2,p3,p4,p5)",1000000,"dummyClass5 "_$p($zv,"(Build")) n st s st=##class(Scratch.test).%New() d run^zmawr("s sc=st.dummyInst5(p1,p2,p3,p4,p5)",1000000,"dummyInst5 "_$p($zv,"(Build")) s st="" d run^zmawr("s sc=##class(Scratch.test).dummyClassNull()",1000000,"dummyClassNull "_$p($zv,"(Build")) n st s st=##class(Scratch.test).%New() d run^zmawr("s sc=st.dummyInstNull()",1000000,"dummyInstNull "_$p($zv,"(Build")) q run(what, n, comment) ; execute line 'what' 'n' times n i s n=$g(n,1) s comment=$g(comment,"********** "_what_" "_n_" run(s) **********") w comment,! s zzh0=$zh f i=1:1:n x what s zzdt=$zh-zzh0 w "total time = "_zzdt_" avg time = "_(zzdt/n),! q The results were: USER>d ClassVsInst^zmawr dummyClass10 Cache for Windows (x86-64) 2017.2.2 total time = .377751 avg time = .000000377751 dummyInst10 Cache for Windows (x86-64) 2017.2.2 total time = .338336 avg time = .000000338336 dummyClass5 Cache for Windows (x86-64) 2017.2.2 total time = .335734 avg time = .000000335734 dummyInst5 Cache for Windows (x86-64) 2017.2.2 total time = .280145 avg time = .000000280145 dummyClassNull Cache for Windows (x86-64) 2017.2.2 total time = .256858 avg time = .000000256858 dummyInstNull Cache for Windows (x86-64) 2017.2.2 total time = .225813 avg time = .000000225813 So, despite my expectations, oref.Method() call turned to be quicker than its ##class(myClass).myMethod() analogue. As there is only less than microsecond effect per call, I don't see any reason for refactoring.
go to post Alexey Maslov · Aug 25, 2018 Task Manager Email facility supports plain authentication only, despite %Net.SMTP supports it for ages. That's true up to 2017.2, not sure about more recent version (2018.1). Therefore if you need STARTTLS or other SSL/TLS stuff you need to write your own eMail notificator for your task(s).
go to post Alexey Maslov · Aug 23, 2018 Timur would unlikely be notified on your comment as he has two profiles here: .../user/timur-safin-0 (with more recent activity) and .../user/timur-safin, an older one, where the site points to when the user '@ Timur . Safin' is mentioned.Besides, it seems that Timur was moving farther and farther away from Caché during last 2 years...