go to post Roger Merchberger · 10 hr ago With more recent versions, yes. The user didn't state what version Ensemble was in use, so I figured offering a solution that would work as far back as Ensemble 2009 wouldn't necessarily be a bad thing. I still have to support Ensemble 2012 and I did test the *-1 functionality there, and in that version this functionality did not yet exist. (Actually, a few sites I support are still using Cache 5.x. It may be geriatric, but it keeps on plugging along... :-) )
go to post Roger Merchberger · 10 hr ago The $LENGTH function can give you the number of PIECEs in a string, and the $PIECE function can grab multiple pieces, so for your example: S DELIM="D" S STRING="aaDtext1Dtext2" W $PIECE(STRING,DELIM,1,($LENGTH(STRING,DELIM)-1)) Edit: Links to documentation for the $PIECE and $LENGTH functions: $PIECE: https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=RCOS_fpiece $LENGTH: https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=RCOS_flength Hope this helps!
go to post Roger Merchberger · Mar 15 If you're asking what to do to only have one double-quote in the result, you could use this: s b="""Cat" w b Basically, wherever you want a double-quote in the output string, put two double-quotes together in the string. So, if you wanted the string to say: Cat"so"only"one you would use this: s b="Cat""so""only""one" When I write code that needs to output comma separated value files, I often create variables to hold both the double-quote and comma characters, to me the resulting code is much easier to read. For example: S Q="""",C=",",QCQ=Q_C_Q ; Sets Q to " char, C to comma, and QCQ to "," ; so when I need to output some strings, I just use the variables: W Q_"string1"_QCQ_"string2"_QCQ_"string3"_Q,! To me, it's easier to read than a whole bunch of imbedded double-quotes all strung together. Hope this helps!
go to post Roger Merchberger · Jan 29 Anyway, here's my solution - maybe it'll help someone make theirs even shorter. ClassMethod ToKeyPad(phrase) As %String { S Q=" 0^1^ABC2^DEF3^GHI4^JKL5^MNO6^PQRS7^TUV8^WXYZ9",P=$ZCVT(phrase,"U") F I=1:1:$L(P){S C=$E(P,I) F J=1:1:10{S K=$F($P(Q,"^",J),C) F L=1:1:K-1 S X=$G(X)_(J-1)}} Return X }
go to post Roger Merchberger · Jan 26 I can't get the test case code to work (maybe because I only have access to 2017.2...) but manually executing the tests like this: w ##class(CodeGolf.MultiTap).ToKeyPad("L33T C0d3r")="55533333333802220033333777" and verifying that the output was '1' instead of '0', my code does pass the test cases. I was able to get a length of 173...
go to post Roger Merchberger · Dec 21, 2023 I'm hoping this will be enough to at least "get you started" - so here's a programming example that will handle either a single or dual \x notation code: ZUNICODE ; DECODE HEX/UNICODE SEQUENCES IN A STRING Q ; CVT(TEXT) ; ENTRY POINT FOR EXTRINSIC FUNCTION TO CONVERT HEX CODE(S) ; IN A STRING. ONLY CONVERTS FIRST SET - IMPROVEMENT OF ; ROUTINE LEFT AS AN EXERCISE TO THE READER. N P1,P2,C1,C2,OUT I $L(TEXT,"\x")=1 W "NO USABLE HEX MARKERS FOUND - DID NOT CONVERT TEXT.",! Q TEXT I $L(TEXT,"\x")=2 W "SINGLE HEX MARKER FOUND. CONVERTING.",! D . S P1=$P(TEXT,"\x",1) . S P2=$P(TEXT,"\x",2) . S C1=$E(P2,1,2) . S P2=$E(P2,3,$L(P2)) . S OUT=P1_$C($ZHEX(C1))_P2 I $G(OUT)'="" Q OUT I $L(TEXT,"\x")=3 W "DUAL UNICODE MARKER FOUND. CONVERTING.",! D . S P1=$P(TEXT,"\x",1) . S C1=$P(TEXT,"\x",2) . S P2=$P(TEXT,"\x",3) . S C2=$E(P2,1,2) . S P2=$E(P2,3,$L(P2)) . S OUT=P1_$C($ZHEX(C1_C2))_P2 I $G(OUT)'="" Q OUT W "MORE THAN TWO UNICODE MARKERS FOUND - LOOPS WOULD HELP. DID NOT CONVERT TEXT.",! Q TEXT Here's some examples on how it's called: USER>S BB="Hello World" USER>S BB="Hello \xc2\xa3 World" USER>S OUT=$$CVT^ZUNICODE(BB) DUAL UNICODE MARKER FOUND. CONVERTING. USER>W OUT Hello 슣 World USER>S BB="Hello \xc2 World" USER>S OUT=$$CVT^ZUNICODE(BB) SINGLE HEX MARKER FOUND. CONVERTING. USER>W OUT Hello  World USER>S BB="Hello \xa3 World" USER>S OUT=$$CVT^ZUNICODE(BB) SINGLE HEX MARKER FOUND. CONVERTING. USER>W OUT Hello £ World USER>S BB="Hello World" USER>S OUT=$$CVT^ZUNICODE(BB) NO USABLE HEX MARKERS FOUND - DID NOT CONVERT TEXT. USER>W OUT Hello World Now, the output above seems to show that the pound symbol is a single hex character \xa3, at least on the Windows system that I am using. Maybe the \xa3 means "special character coming next" as at least in the charmap utility on Windows Server 2016 shows the U+C2A3 character as "Hangul Syllable Sios Yu Hieuh" (font: Gulim) and on my Ubuntu Linux 20.04 system it says "HANGUL SYLLABLE SYUH" (fonts: Trebuchet MS and Noto Serif CJK SC, pasted into LibreOffice Writer). There are limitations to this code that could be improved. For one example, it doesn't handle multiple codes (single or unicode)... but hopefully this will give you (if nothing else) a good troubleshooting tool to get you started.
go to post Roger Merchberger · Nov 17, 2023 First, just to let you know that even back with Cache 2017.x.x, $ZF(-1) & $ZF(-2) are deprecated and shouldn't be used for new code. $ZF(-100) should be used instead. As $ZF(-100) is more powerful anyway, I would suggest reading up on it: https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=RCOS_fzf-100 With $ZF(-100) you can redirect input and output to files or other devices which may help you run the task you're requiring in the background. Note that I don't know (at least in a Windows environment) if you can successfully run a job in the background and still have interactive access to that process. There's a note in the documentation above that states that /ASYNC jobs use the null device for input if it's not redirected from a file. I don't know if you can redirect from a device instead. Hope this helps!
go to post Roger Merchberger · Aug 31, 2023 There are provisions in the $ZDATEH function to cover the "two-digit-year" century issue. If you need all two-digit years to equate to 20xx, try this: $ZDATEH("01/01/23",,,3,58074,94598) As in, set the 'yearopt' parameter to 3, then set the startwin & endwin dates (in $H format) to the beginning and ending window to interpret the two-digit years. If you need a specific range 100 year range - for this example, to evaluate two-digit years between 01/01/1950 and 12/31/2049, you'll need the $H values of those dates: W $ZDATEH("1/1/1950") 39812 W $ZDATEH("12/31/2049") 76336 Then use those $H values in the window of the $ZDATEH command: $ZDATEH("01/01/23",,,3,39812,76336) Here's more documentation on the $ZDATEH command: https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=RCOS_fzdateh Hope this helps!
go to post Roger Merchberger · Mar 20, 2023 Give me a couple-three days - working on spinning up a couple Raspberry Pi's with IRIS in containers for testing; one with Ubuntu and one with Debian.
go to post Roger Merchberger · Mar 17, 2023 One option would just be a straight telnet session (swap 10.10.10.10 with the IP address of your system): telnet 10.10.10.10 1972 If the port is closed, you should get the error: "telnet: Unable to connect to remote host: Connection refused" - but if successful you should get the "Connected to 10.10.10.10" you'll know it's open. To exit, type <CTRL>] for a telnet prompt, then type 'quit'. Hope this helps!
go to post Roger Merchberger · Mar 16, 2023 Robert, I'm not sure if this helps your particular situation, but if it's "OK" to manually tell your container what the local hostname of the host is, then you could try this: set ip=$SYSTEM.INetInfo.HostNameToAddr("**local_name_NotFQDN**") with just the local hostname (not the FQDN) of the host machine in quotes... and that should give you the IP address of the active ethernet/wireless adapter. I tried this in a container running IRIS on a Raspberry Pi and the local hostname is "Iris2" (so, it is running Linux, I don't have any container systems running on Windows... sorry!) and this is what I got: USER> Set ip=$SYSTEM.InetInfo.HostNameToAddr("Iris2") USER> zw ip ip="192.168.1.236" On my network, 172.17.0.x is the internal Docker bridge, 192.168.1.x is my wireless network, and 10.1.2.x is my desktop wired network. (I have many servers, printers & whatnot, so I have multiple VLANs on my home network.) Now... I'm not sure if this is good or bad for your situation, but in my example, if I were to shutdown the container, disable the wireless, hook up an ethernet cable to the network and restart everything, the listed IP from this command would change from the 192.168.1.x to a 10.1.2.x IP address. This could be good if you wanted to know how the main machine was externally connected; or it could be bad if you're using awk/grep/findstr on logs looking for a particular IP. As I said, I'm unsure of your actual use case, so if this had to be portable across several containers and several machines unchanged, this may not help you as you'll manually have to change the machine name in your code. Hope this helps!
go to post Roger Merchberger · Jan 10, 2023 Sure, the $Increment command can also decrement, and the values don't have to be 'just 1.' Here's the documentation for the $Increment command: https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=RCOS_FINCREMENT Simply, you can do this to decrement by 1: Set TEMP=$INCREMENT(^test,-1) If you wanted to increment by 10, the command would be this: Set TEMP=$INCREMENT(^test,10) To test, try this: S ^test=0 F S TEMP=$INCREMENT(^test,10) Q:$G(^test)>100 W ^test,! Hope this helps!
go to post Roger Merchberger · Jan 9, 2023 If you have multiple subscript levels, this may help: SET I=0,G="^test("""")" FOR {SET G=$QUERY(@G) Q:G="" SET I=I+1 WRITE G,!} WRITE "Total: ",I,! Here's the data: set ^test(1)="aa" set ^test(1,1,1)="aa" set ^test(2)="aa" set ^test(2,1)="aa" set ^test(2,2,1)="aa" set ^test(3,1)="aa" set ^test(4,1)="aa" And here's the output: ^test(1) ^test(1,1,1) ^test(2) ^test(2,1) ^test(2,2,1) ^test(3,1) ^test(4,1) Total: 7 If you only wanted the total (especially if the global is much larger) omit the 'WRITE G,!' portion out of the line of code above. Hope this helps!
go to post Roger Merchberger · Oct 20, 2022 Another possibility might be to see if there's been backups of the routines being saved. It won't give you the "who" but it could at least give you the "when" a routine was modified & compiled. You could use the 'Global Lister' and check the rBACKUP global. Here's an example (you may need to tinker with the the global lister input - taking a deeper dive into the ^rBACKUP global may help): ZZZ>D ^%G Device: Right margin: 80 => Screen size for paging (0=nopaging)? 24 => For help on global specifications DO HELP^%G Global ^rBACKUP("TEST","INT",,0) or maybe Global ^rBACKUP("TEST.1","INT",,0) To really get all the functionality you're looking for, you may need to set up a version control system like git or somesuch. Hope this helps!
go to post Roger Merchberger · Jun 6, 2022 Would this be acceptable? W $TRANSLATE($ZDATETIME($HOROLOG,8)," :") Hope this helps!
go to post Roger Merchberger · Apr 26, 2022 @Robert Cemper - I have verified that the query Detail does exist in 2017.2 (closest I can get) but you are spot on that it needs to be run from the %SYS namespace; I tried two other Ensemble-capable namespaces and it errored out both times.
go to post Roger Merchberger · Apr 25, 2022 I'm not sure I understand the class examples you have listed, but there's a possibility that you may not need to do this in a class. Ensemble / HealthShare has a couple different ways that you can send a process output to multiple operations. The first is if you're not using any form of data translation, you can send the output right from the BP configuration screen: Under the Response Target Config Names, I've selected two different targets here, and you can see that the connectivity verifies this - but I'm sending the output to more than two targets! How can that be? Simple, you can also select different targets in the Ensemble Rule Editor - this can be handy if you wanted to apply two different DTL transformations to two different targets. My example is super-simple (as in I'm not applying different rules or DTLs per target) but with multiple Send directives we can specify multiple targets: You can have different rules with different constraints going to different operations - but I just added a send directive to a sample ruleset to show how to configure multiple targets - and as you can see between the two screenshots how Ensemble is sending the data to 4 different targets in two different ways. Hope this helps!
go to post Roger Merchberger · Apr 4, 2022 upgrading to a version where you can safely compact/truncate If you're not able to upgrade to a newer version, there's still the option of using the ^GBLOCKCOPY utility in the %SYS namespace. Unfortunately, you'll need downtime to use the utility but if you have databases with a high amount of free space, this will make a new copy of a database using the minimal amount of disk space. Then just replace the new database file with the old**, remount the database and Bob's your uncle! Here's InterSystem's Documentation page for the utility: https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=GSTU_remote_gblockcopy Hope this helps! ** P.S. If you did want to save the old database, 7zip is quite good at compressing CACHE.DAT (and IRIS.DAT) database files. Be sure to use the LZMA2 compression method as it works well with multiple threads/cores, and I usually use a 'light' compression level - Fast or Fastest if in windows, -mx=3 if in Linux/Unix.
go to post Roger Merchberger · Mar 25, 2022 Token, If you saved it as generatePass.mac and compiled it, try this to generate a single password: W $$^generatePass and if you wanted to generate 20 passwords, you'd call it like this: D LOTS^generatePass(20) Hope this helps!
go to post Roger Merchberger · Mar 24, 2022 Julian, I've tested the method above, and depending on a user's needs, it may not be the best fit. I've run it several times, and I've not seen a lower case character and it's really 'heavy' on the punctuation, some of which may not work well with some websites' password requirements. Here's one example: ZZZ>W ##CLASS(%PopulateUtils).VarString(120) %%XDY^F;="#GO=A<B89&K\ZE&3192R8J+9QFO#7J>M0+W=JW%^CL%BGO.1.W1EJ@7Z3,HS0F(<E?UIAE*+[3"CLD$"'\U Token, Years ago I created a password generator utility - it's by no means perfect and it's kind of 'tailored' to my use - I do prefer passwords that alternate left hand then right hand to attempt a bit easier manual typing, and even then the randomization doesn't always create a good 'mix' of characters, so I usually have the utility print 10 passwords (or more) and then I choose the 'best' for character mix, punctuation, etc. The routine could be modified for longer passwords, more/different punctuation characters, etc. It's not the _most_ secure, but it works well for my purposes. Feel free to use/modify it, but use it at your own risk. :-) PASSWD() ; N LEFT,RIGHT,CENTER,LORR,I,J,PASSWD S LEFT="QAZWSXEDCRFVTGBqazwsxedcrfvtgb234" S RIGHT="YHNUJMIK,OL.Pyhnujmikolp789" S CENTER="123456789*-+" S LORR=$R(2) S PASSWD="" I LORR D . F I=1:1:4 D . . S PASSWD=PASSWD_$E(LEFT,($R($L(LEFT))+1))_$E(RIGHT,($R($L(RIGHT))+1)) E D . F I=1:1:4 D . . S PASSWD=PASSWD_$E(RIGHT,($R($L(RIGHT))+1))_$E(LEFT,($R($L(LEFT))+1)) F I=1:1:4 D . S PASSWD=PASSWD_$E(CENTER,($R($L(CENTER))+1)) Q PASSWD ; LOTS(HOWMANY) N I,J,PASSWD I +$G(HOWMANY)=0 S HOWMANY=10 W ! F I=1:1:HOWMANY W $$PASSWD,! W ! Q ; To run the utility for one password, just execute this: W $$^PASSWD But, I generally just print 10 at a time and choose one. To do that, do the LOTS subroutine (which defaults to 10): ZZZ>D LOTS^PASSWD J3PwIQnX9*76 nzJWPFyt+31+ [[ snippage for brevity ]] If you want more than 10, add a parameter for the number of passwords you want: ZZZ>D LOTS^PASSWD(20) Hope this helps!