Jon Willeke · Jan 11, 2018 go to post

That's precisely the intended meaning of orthogonal in this context. All four combinations of public/private and class/instance are distinctly meaningful and useful in their own right. The concepts are separate, independent.

Jon Willeke · Feb 1, 2018 go to post

Argumentless DO is still the simplest way to introduce a scope to NEW a variable, including $namespace or $roles. Yes, you can extract that out to another procedure or method, but I often prefer to do it inline.

Jon Willeke · Feb 21, 2018 go to post

$double and dynamic objects also poke holes in the idea that everything is a string:

USER>w [1,"2"].%ToJSON()
[1,"2"]
USER>s d=1,b=$double(d) w d," ",d/3,!,b," ",b/3
1 .3333333333333333333
1 .33333333333333331482
Jon Willeke · Mar 13, 2018 go to post

You can use the $ziswide intrinsic function to check whether a global is portable to an eight-bit instance.

Jon Willeke · Jun 5, 2018 go to post

I encourage you to get in touch with the WRC, but if you post more information, we might be able to make some progress. For starters, what version of Caché and Python, and what kind of errors are you seeing?

I successfully built the binding using the following:

  • macOS 10.12.6 (Sierra)
  • Python 2.7.10 (built-in version)
  • command line tools for Xcode 8.3.3
  • Cache 2017.2.1 build 801U

It looks like I got a total of eleven compiler warnings.

As described here, it's a bit tricky to actually use the binding with the system version of Python due to Apple's System Integrity Protection (SIP):

https://community.intersystems.com/post/installing-intersystems-python-binding-mac-el-capitan-1011-or-later

This may be fixable with some install_name_tool surgery, but a separate installation is recommended.

Jon Willeke · Jun 6, 2018 go to post

Yes, if you're getting errors about print in Python 3, I second Iain's suggestion to look for the setup3.py script. I just did this successfully using an Anaconda 4.4 install of Python 3.6.1.

Jon Willeke · Aug 8, 2018 go to post

Compared to a delimited string, lists have the overhead of storing the length of each element, typically one extra byte. Numbers and Unicode characters are also stored differently, sometimes more efficiently, sometimes less. Otherwise, there is no difference between fetching a delimited string or a list.

The DataBlkRd and DataBlkBuf columns shows that ^StringGlobal was read entirely from global buffers, whereas ^ListGlobal had to read over 9,000 blocks. In each case, it seems that the global occupies about 17,000 blocks; about 136 MB, assuming 8 KB blocks.

I suggest that you do the following:

  • configure 256 MB or more of global buffers
  • restart the instance
  • run one of the tests twice
  • restart the instance
  • run the other test twice

Based on your numbers, the first runs will be cold, and should take a minute or two. The second runs should be essentially instantaneous.

Jon Willeke · Aug 9, 2018 go to post

I'm not sure I'm reading this correctly, but I believe the key difference in the cold runs is 10,399 vs 5,853, again suggesting that ^ListData went to disk more often.

I'm surprised that it makes such a big difference, but I suspect what's happening here is that your copy of ^ListData into ^StringData resulted in a more space-efficient organization. You might want to look at the packing column of a detailed report from the %GSIZE utility.

It's possible that something about your data causes $list to store it less efficiently, but your data hasn't convinced me of that. If you copied ^ListData unchanged into, say, ^ListData2, my guess is that you would see a similar improvement.

Jon Willeke · Aug 16, 2018 go to post

The %UnitTest package is designed such that each suite stands alone: it is loaded, compiled, run, and deleted, independent of any other suite. Deleting the test classes is just part of cleaning up.

You can pass the /nodelete qualifier, or even set it as a default using $system.OBJ.SetQualifiers(). Given that deletion is the default behavior, however, I suggest that you adjust your workflow accordingly. I edit XML export files directly. Some people maintain a development and test namespace, with the classes being exported from development, and imported into test.

Jon Willeke · Sep 10, 2018 go to post

Your code creates a property when getting the property returns a 404. However, I'm getting a 400 when a property doesn't exist:

$ curl --user _system:SYS -w "\n***\n%{http_code}\n" 'http://127.0.0.1:52773/api/docdb/v1/DEMO/prop/DEMO.TEST11/Ergebniszuf'
{"status":{"errors":[{"error":"ERROR #25541: DocDB Property 'Ergebniszuf' does not exist in 'Demo.TEST11'","code":25541,"domain":"%ObjectErrors","id":"DocumentDatabasePropertyNotValid","params":["Demo.TEST11","Ergebniszuf"]}],"summary":"ERROR #25541: DocDB Property 'Ergebniszuf' does not exist in 'Demo.TEST11'"},"content":null}
***
400
Jon Willeke · Sep 26, 2018 go to post

I second the recommendation to comb through the upgrade checklist archive. A couple of big ones are that 2014.1 dropped support for database extents, and for 2 KB databases.

Jon Willeke · Oct 24, 2018 go to post

%DynamicAbstractObject is not intended to be subclassed by end users. It serves as a base for %DynamicArray and %DynamicObject, which provide JSON-style dynamic objects without a fixed schema.

You seem to be looking for a way to map between JSON and plain old registered objects. We haven't yet released such a feature, but you can do something kind of similar using DocDB, which I think first shipped in IRIS 2018.1:

https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=GDOCDB

This feature helps to define a class that stores a JSON document in a persistent object and extract fields from the document into properties of the object.

Jon Willeke · Jan 18, 2019 go to post

Even if you store the current password encrypted, consider storing just the hashes for old passwords. You might use $system.Encryption.PBKDF2() for this purpose, perhaps with fewer iterations than you'd otherwise use for a live password.

Jon Willeke · Jan 31, 2019 go to post

The --volume and --env switches are handled by the docker command. They should come before the image name.

Jon Willeke · Feb 1, 2019 go to post

It looks like you're trying to run an image identified as efca5c59cbb7, but in this segment of the command line, iris is taken as the image name:

    --env ICM_SENTINEL_DIR=/license iris
Jon Willeke · Feb 1, 2019 go to post

You're sort of back to where you were before, with Docker switches occurring after the image name, although you now have the image name in there twice. I don't have your environment, so I can't test this exact command, but I think you want something like this:

    docker run -d --privileged -v /nfs/IRIS:/IRIS \
    --env ISC_DATA_DIRECTORY=/IRIS/iconfig \
    --env ICM_SENTINEL_DIR=/license \
    -p 52774:52774 --name IRIS4 efca5c59cbb7 \
    --key /IRIS/iris.key ...

If you're still having trouble, back up and build the command line incrementally. Start simple:

    docker run -d --name IRIS4 efca5c59cbb7

Then add in your Docker switches (-v, -e, -p, etc.), and finally add in the IRIS arguments (--key, etc.). That way you can tell which switch or argument is causing a problem.

Jon Willeke · Feb 5, 2019 go to post

I'm finding it hard to read the output images, but every one of the commands that you listed has a Docker option after the image name. The form of the command should be:

    docker run <Docker opts> image_name <IRIS args>

To be clear, the -e (--env), -p (--publish), and -v (--volume) switches are Docker options; they go before the image name. The --key and --before switches are IRIS arguments; they go after the image name.

Jon Willeke · Feb 6, 2019 go to post

Take heart, I think you're getting close. I think all you need now is to quote the arguments to the --before switch, as shown in the documentation:

    --before "/usr/irissys/dev/Cloud/ICM/changePassword.sh /IRIS/pwd.txt"

If you're still having trouble, build up the command incrementally, as I previously suggested, being careful to follow the correct form of the command.

Dmitry's answer about looking at log files will also give you more information than simply noticing in docker ps that the container has exited.

Jon Willeke · Apr 9, 2019 go to post

My hunch is that XSLT is not the right tool for the job, but it's not clear to me what you're trying to do. What is the input encoding, what is the desired output encoding, and what do you mean by non-standard characters? Are these characters that don't exist in the output encoding?

Jon Willeke · Apr 9, 2019 go to post

So the input is Windows-1252, and the output is Windows-1252 in which certain characters are mapped to their numerical escape sequence? You could do this with XSLT 2.0 using character maps.

Given this input (presented here as UTF-8 for visibility on the forum):

<?xml version="1.0"?>
<Recordset>
• coffee €5,• tea €4
</Recordset>

This stylesheet will escape the bullets and euro signs:

<?xml version="1.0"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:character-map name="a">
    <xsl:output-character character="€" string="&amp;#128;"/>
    <xsl:output-character character="•" string="&amp;#149;"/>
  </xsl:character-map>
  <xsl:output encoding="Windows-1252" indent="yes" use-character-maps="a"/>
  <xsl:template match="/">
    <Recordset>
      <xsl:value-of select="/Recordset"/>
    </Recordset>
  </xsl:template>
</xsl:stylesheet>

Output:

<?xml version="1.0" encoding="Windows-1252"?>
<Recordset>
&#149; coffee &#128;5,&#149; tea &#128;4
</Recordset>
Jon Willeke · Apr 12, 2019 go to post

I thought there was a method to do just this in the TestInstance class, but it's actually in %UnitTest.Portal package:

USER>w ##class(%UnitTest.Portal.standardPage).GetTestStatus(^UnitTest.Result)
0

Up to you if you want to depend on an implementation detail of the portal. It is a public method that's been there since 2012.

Jon Willeke · Jun 14, 2019 go to post

Interesting question. I think the idea is that the output is not just a number, but the second field of a $horolog/$ztimestamp string, where the convention is to include the leading zero if necessary.

If you repeat the experiment with $zdth, or you catch the value of $zts just after midnight UTC, you should see a zero after the comma.

Jon Willeke · Jul 9, 2019 go to post

I would look at the implementations that do not depend on a "big number" package. Java and C# use BigInteger; Python uses long; Ada, C, and others use GMP; etc. You might try porting the Pascal implementation to ObjectScript. Where you see div, use the "" operator, and be aware of operator precedence.

Jon Willeke · Jul 10, 2019 go to post

It occurs to me that the Visual Basic solution works with minimal modification as Caché Basic: weaken the DIM statements, change Debug.Print to Print, and replace the call to Format$().

Option Explicit

Const VECSIZE = 3350
Const BUFSIZE = 201
Dim buffer
Dim vect
Dim more, karray, num, k, l, n

  For n = 1 To VECSIZE
    vect(n) = 2
  Next n
  For n = 1 To BUFSIZE
    karray = 0
    For l = VECSIZE To 1 Step -1
      num = 100000 * vect(l) + karray * l
      karray = num \ (2 * l - 1)
      vect(l) = num - karray * (2 * l - 1)
    Next l
    k = karray \ 100000
    buffer(n) = more + k
    more = karray - k * 100000
  Next n
  Print buffer(1)
  Print "."
  l = 0
  For n = 2 To BUFSIZE
    Print Right("00000" & buffer(n), 5)
    l = l + 1
    If l = 10 Then
      l = 0
      Print 'line feed
    End If
  Next n
Jon Willeke · Jul 25, 2019 go to post

You can also change it after installation by running cinstall setserviceusername in the bin directory.

Jon Willeke · Aug 29, 2019 go to post

There is a way to do something similar in Caché and IRIS. In a Russian locale, you have access to the "KOI8R" I/O translation table. KOI8-R has the funny property that if you mask out the high-order bit, you get a sort of readable transliteration. Here's an example using a Unicode instance in the "rusw" locale:

    USER>s koi8=$zcvt("Пример для Кода","O","KOI8R")

    USER>s ascii="" f i=1:1:$l(koi8) s ascii=ascii_$c($zb($a(koi8,i),127,1))

    USER>zw ascii
    ascii="pRIMER DLQ kODA"
Jon Willeke · Sep 5, 2019 go to post

set count=count+1 and set count=1+count generate identical object code, so I think we found your margin of error.

if $increment(count) has to set $test, so I would expect it to be slower for a local variable. (I'm not sure about a global.) In IRIS 2018.2 and later, do $increment(count) may close the gap a bit.

Jon Willeke · Sep 6, 2019 go to post

Interesting. I added a loop for if $increment(num) {} (i.e., a new-style if statement that doesn't set $test): no measurable improvement over legacy if.

I also added a loop for do $increment(num) (i.e., a do statement that neither sets $test nor returns a value): ever so slightly slower.

USER>d ^Times(1,8)
   count   num+1   1+num   =$i()    $i()  $i(){}  d $i()
               times in microseconds
--------------------------------------------------------
       1   1.000   0.000   1.000   0.000   0.000   1.000
      10   0.000   0.000   0.100   0.100   0.000   0.000
     100   0.010   0.010   0.490   0.030   0.030   0.040
    1000   0.042   0.011   0.029   0.034   0.029   0.033
   10000   0.011   0.010   0.030   0.032   0.032   0.031
  100000   0.009   0.010   0.030   0.028   0.027   0.031
 1000000   0.009   0.010   0.028   0.028   0.027   0.031
10000000   0.010   0.010   0.028   0.028   0.028   0.031

Incidentally, here are some results with num renamed to ^num:

USER>d ^Times(1,8)
   count   num+1   1+num   =$i()    $i()  $i(){}  d $i()
               times in microseconds
--------------------------------------------------------
       1   2.000   0.000   2.000   1.000   0.000   0.000
      10   0.100   0.200   0.100   0.100   0.100   0.100
     100   1.070   0.280   0.130   0.110   0.100   0.110
    1000   0.142   0.144   0.142   0.102   0.102   0.106
   10000   0.142   0.141   0.110   0.116   0.104   0.108
  100000   0.142   0.141   0.102   0.101   0.100   0.104
 1000000   0.139   0.140   0.100   0.098   0.100   0.102
10000000   0.138   0.138   0.098   0.098   0.099   0.102

For "=$i()", I assigned a local, rather than redundantly assigning the global.