Dmitry Maslennikov · Nov 12, 2017 go to post

As far as I understood, they discussing mounting volumes from another container.

As I know some kind of this possibility was in some previous versions of docker-compose. When you can configure to start multiple containers, and it offered to mount volumes_from another container in this configuration. But now docker-compose becomes bigger and supports swarm configuration, they decided to change volumes_from, to just named volumes. In this way, you can define one volume, and use it in different containers at the same time. And it works pretty well. And I think, it is quite enough, with different drivers available for volumes, you can use data from almost everywhere.

And it is now possible even with current Caché versions.

But I think, that way offered in the article could be less effective. You still have to mount volume but in some different way, but what important is how real storage is used.

If these data containers are just a connectors between cluster storage and application. A think it still possible to use it as a mounted volume, or you can configure mounting during the build of an image.

Dmitry Maslennikov · Nov 11, 2017 go to post

To release all LOCK's for your current process, you can use argumentless LOCK command.

To rollback all transactions in the current process, you can use TROLLBACK also without any arguments.

If you want to control locks outside, you can look at class SYS.Lock in %SYS namespace.

To find active locks, you can use either special global ^$LOCK or queries in the class %SYS.LockQuery

You can get transaction level with special variable $tlevel. For other processes, you can use class %SYS.ProcessQuery. To check if the process in a transaction or not. But you can't just rollback transaction inside another process, you can terminate it and transaction will be automatically rollbacked.

Dmitry Maslennikov · Nov 11, 2017 go to post
  kill
  set fs = ##Class(%Stream.FileCharacter).%New()
  set sc=fs.LinkToFile("c:\advent\input\day10.txt")
  while 'fs.AtEnd {
    set line = fs.ReadLine()
    if $e(line)="v" {
      set $lb(,value,,,type,bot)=$lfs(line," ")
      set list(type, bot, value)=""
    else {
      set $lb(,bot,,,,lowTo,low,,,,highTo,high)=$lfs(line," ")
      set instructions(bot, "low") = $lb(lowTo, low)
      set instructions(bot, "high") = $lb(highTo, high)
    }
  }
  while $d(instructions) {
    set bot=""
    for {
      set bot = $o(list("bot", bot))
      quit:bot=""
      set low = $o(list("bot", bot, ""))
      set high = $o(list("bot", bot, ""), -1)
      continue:low=high
      if low=17,high=61 set result = bot
      set $lb(type, num) = instructions(bot, "low")
      set list(type, num, low) = ""
      set $lb(type, num) = instructions(bot, "high")
      set list(type, num, high) = ""
      kill list("bot", bot)
      kill instructions(bot)
    }
  }
  write !,"Result1 = ",result
  set result2 = 1
  for i=0,1,2 set result2 = result2 * $o(list("output", i, ""))
  write !,"Result2 = ",result2
  quit
Dmitry Maslennikov · Nov 11, 2017 go to post

and using $lb on a right side, can help, when you need to swap values without using the third variable.

set $lb(b,a)=$lb(a,b)
Dmitry Maslennikov · Nov 10, 2017 go to post

Interesting, you decided to use a regex here. My code looks very similar to your, but in my case, I just replaced parens and 'x' to '|' and use $lb/$lfs to catch values.

  set fs = ##Class(%Stream.FileCharacter).%New()
  set sc=fs.LinkToFile("c:\development\day9.txt")
  set compressed = fs.Read(fs.Size)
  set compressed = $tr(compressed, "(x)", "|||")
  write !,"Length = ",$$uncompress(compressed)
  write !,"Full Length = ",$$uncompress(compressed, 1)
  quituncompress(str, deep = 0) public {
  set length = 0
  while $l(str) {
    if $e(str)="|" {
      set $lb(,count,times)=$lfs($p(str, "|", 1, 3), "|")
      set $e(str, 1, $l($p(str, "|", 1, 3)) + 1) = ""
      set tmp = $e(str, 1, count)
      set length = length + $s(deep:$$uncompress(tmp,1) * times, 1: count * times)
      set $e(str, 1, count) = ""
    else {
      set size = $l($p(str, "|"))
      if $i(length, size)
      set $e(str, 1, size) = ""
    }
  }
  quit length}

InterSystems delivered Cache distributive as a DMG file until 2016.2. And fortunately, they decided do not do it anymore.

But all the time, it was also available as tar.gz. Which is working in exactly the same way as any other Linux version.

So, you can use ccontrol tool, to see a list of instances, their status and start or stop.

csession can be used as a terminal in windows.

To open System Management Portal, you can just this URL in a Browser - http://localhost:57772/csp/sys/UtilHome.csp

I think could be even shorter, but as is

  set sum = 0, north = ""
  set fs = ##Class(%Stream.FileCharacter).%New()
  set sc=fs.LinkToFile("day4.txt")
  while 'fs.AtEnd {
    set line = fs.ReadLine()
    do line(line)
  }
  !,"Sum = ",sum
  !,"North = ",north
  qline(line) [ sum, north ] {
  set name = $p(line, "-", 1, * -1)
  set checkSumm = $piece($piece(line, "]"), "[", *)
  for i=1:1:5 {
    set char = $e(checkSumm, i)
    set count = $l(name) - $l($tr(name, char))
    set order( - count, char) = ""
  }
  set testSumm = ""
  set i=""
  for {
    set = $o(order(i))
    quit:i=""
    quit:i=0
    set = ""
    for {
      set = $o(order(i, c))
      quit:c=""
      set testSumm = testSumm _ c
    }
  }
  if testSumm=checkSumm {
    set sector = $piece($piece(line, "["), "-", *)
    set sum = sum + sector
    for i=1:1:sector set name = $tr(name, "zabcdefghijklmnopqrstuvwxy-", "abcdefghijklmnopqrstuvwxyz ")
    if name["north" set north = sector
  }}

One code for both passwords

  set doorId = "reyedfim"
  set (pass1,pass2) = ""
  for i=1:1 {
    set hash = $system.Encryption.MD5Hash(doorId _ i)
    set key1 = $zla($reverse($e(hash, 1, 3))_$c(0))
    continue:key1>15
    if $l(pass1)<8 set pass1 = pass1 _ $zhex(key1)
    continue:key1>7
    continue:$tr($e(pass2, key1 + 1)," ")'=""
    set $e(pass2, key1 + 1)=$zhex($a($e(hash,4))\16)
    quit:($l($tr(pass2," "))=8)
  }
  !,"Password #1 = ",pass1
  !,"Password #2 = ",pass2

Mine

  set fs = ##Class(%Stream.FileCharacter).%New()
  set sc=fs.LinkToFile("day6.txt")
  while 'fs.AtEnd {
    set line = fs.ReadLine()
    do line(line)
  }
  set (msg1,msg2)=""
  for i=1:1 {
    quit:'$d(count1(i))
    if $o(count1(i, ""), -1, char) set msg1 = msg1 _ char
    set msg2 = msg2 _ $o(count2(i, $o(count2(i, "")), ""))
  }
  !,"msg1 = ",msg1
  !,"msg2 = ",msg2
  qline(line) [symbols, count1, count2 ] {
  i=1:1:$l(line) {
    set char = $e(line, i)
    set count = +$get(symbols(i, char))
    kill count2(i, count, char)
    set count = $i(symbols(i, char))
    set count1(i, count) = char
    set count2(i, count, char) = ""
  }}

Look at my solution for this task

   k
  set fs = ##Class(%Stream.FileCharacter).%New()
  set sc=fs.LinkToFile("day8.txt")
  set count=0,width=50,height=6
  for = 1:1:width for = 1:1:height set screen(x,y) = 0
  while 'fs.AtEnd {
    set line = fs.ReadLine()
    do line(line)
  }
  do draw()
  set count = 0
  for x=1:1:width for = 1:1:height set count = count + screen(x,y)
  !!,"Count = ", count 
  quitline(line) [screen, width, height, x, y] {
  set $lb(cmd, size, pos, , by) = $lfs(line, " ")
  if cmd = "rect" {
    set $lb(mx, my) = $lfs(size, "x")
    = 1:1:mx y=1:1:my set screen(x,y) = 1
  else {
    set $lb(v1, pos) = $lfs(pos, "=")
    set v2=$case(v1, "x":"y", :"x")
    set max = $case(v1,"x":height, :width)
    set @v1 = pos + 1, @v2 = 1
    for i=1:1:by {
      set prev = $g(screen(x,y))
      for @v2 = 2:1:max set $lb(screen(x,y), prev) = $lb(prev, screen(x,y))
      set @v2 = 1
      set screen(x, y) = prev
    }
  }}draw() [screen, width, height] {
  = 1:1:height {
    !
    = 1:1:width {
      write $case($get(screen(x,y)), 1:"#", :" ")
    }
  }}

And for the second part, a bit different.

set fs = ##Class(%Stream.FileCharacter).%New()
  set sc=fs.LinkToFile("day7.txt")
  set count=0
  while 'fs.AtEnd {    set line = fs.ReadLine()    if $locate(line, "(\w)(?!\1)(\w)\1\w*(?:\[\w+\]\w*)*\[\w*\2\1\2\w*\]")||$locate(line, "\[\w*(\w)(?!\1)(\w)\1\w*\](?:\w*\[\w+])*\w*\2\1\2"), $i(count)
  }
  !,count 

Interesting, but I don't understand why you still trying to parse strings manually when InterSystems already supports Regex.

 set fs = ##Class(%Stream.FileCharacter).%New() set sc=fs.LinkToFile("day7.txt") set count=0 set abba = ##class(%Regex.Matcher).%New("(\w)(?!\1)(\w)\2\1") set hyper = ##class(%Regex.Matcher).%New("\[\w*(\w)(?!\1)(\w)\2\1\w*\]")while 'fs.AtEnd {   set line = fs.ReadLine()   set abba.Text = line   set hyper.Text = line   if abba.Locate(),'hyper.Locate(),$i(count)
 }
 !,count 

So simple, isn't it?

For regex maniac, maybe possible to join both regex's to one to get fewer operations. But anyway, in this simple example you can see the power of Regex.

And even shorter

set fs = ##Class(%Stream.FileCharacter).%New()
 set sc=fs.LinkToFile("day7.txt")
 set count=0while 'fs.AtEnd {   set line = fs.ReadLine()   if $locate(line, "(\w)(?!\1)(\w)\2\1"), '$locate(line, "\[\w*(\w)(?!\1)(\w)\2\1\w*\]"), $i(count)
 }
 !,count 

I think it mostly depends on your task, how strongly you should care about duplications.

And I think that SHA1 should be enough

Documentation now looks quite pure about Atelier. 

As far as I know, Studio does lock for any files which in edit mode, not just opened but after some changes. While Atelier does not. When you save the file in Studio, it does not care what did you have before it just overrides. When Atelier checks if server's version was changed it offers to compare and choose what should be stored on server.

Yep, right, looks like Index can't help here and problem not only 511(and this length could be different on different strings).
But, you still can use Index but you should set length which should be stored. But find duplicates you can do without SQL, just by reading this index, it should be much faster, to find, all duplicates by indexed value, and then you can compare real values.

For best performance, you need index on this property. And request something like this.

SELECT Home_City,list(ID) ids 
FROM sample.person
GROUP BY Home_City
HAVING count(*)>1

And result will be something like this

Danny, 
 

Thanks, It's amazing, to see such articles. 

But how about coding style. If to be honest, your code looks like a mess of old-school code and modern.

As this articles mostly for beginners, it would be much better to have also modern style. Instead of OPEN/USE/READ use %Stream classes. I see this way as much readable.

And about how you use standalone ELSE command without brackets, not sure that beginners, can quickly get the trick here.

Open file:"R":1 Else  Use 0 Write "Could not open file ",file Quit

You can remove saved password from windows registry

  • run regedit.
  • open path HKEY_CURRENT_USER\Software\InterSystems\Cache\Servers\
  • choose server
  • remove Server Password

I would recommend instead of mark such object as deleted, with such flag like this. Just "move" it to another table some kind of Trash, when you can store this object as a serialized string for example. In this case object will really disappear from his table and will not be availble with via SQL or any other accesses. But in this Trash, you can have information about deletion data, who deleted and information to restore it.

Dmitry Maslennikov · Oct 27, 2017 go to post

To have a possibility to edit files, you have to create a project, and copy existed classes to this project.

You can look at this youtube playlist, to get more information about working with Atelier.

Dmitry Maslennikov · Oct 18, 2017 go to post

Why you have two different ways to create objects?

If you have class, you should use object or SQL way to create or change objects.

If you add it manually through direct access to global, you should also create all indexes, this way.

Instead of %BuildIndices, you can try to use method %FileIndices, with Object's id as a first argument.

Dmitry Maslennikov · Oct 16, 2017 go to post

It depends on, how long this string should be, and what do you expect to see there.

The simplest way is just generating it with $random.

set string=""
set length=100
for i=1:1:length set string=string_$char($random(26)+97)
Dmitry Maslennikov · Oct 15, 2017 go to post

Unfortunately, downloading distributions from WRC is not so easy. For example, you can look at my article Containerization Caché, where I gave an example how to download and install Caché automatically.

Before, we need some variables

product=cache
version=2017.2.0.744.0
arch=lnxrhx64

Download distribution

# WRC Authorization
WRC_USERNAME="user@somecompany.com"
WRC_PASSWORD="password"

wget -qO /dev/null --keep-session-cookies --save-cookies /dev/stdout --post-data="UserName=$WRC_USERNAME&Password=$WRC_PASSWORD" 'https://login.intersystems.com/login/SSO.UI.Login.cls?referrer=https%253A//wrc.intersystems.com/wrc/login.csp' \
 | wget -O - --load-cookies /dev/stdin "https://wrc.intersystems.com/wrc/WRC.StreamServer.cls?FILE=/wrc/distrib/$product-$version-$arch.tar.gz" \
 | tar xvfzC - .

before an upgrade, you should define at least one variable as defined in documentation by your link.

ISC_PACKAGE_INSTANCENAME=$product

for install new instance, you should define more variables

ISC_PACKAGE_INSTALLDIR="/usr/cachesys/"
ISC_PACKAGE_UNICODE="Y"

so, finally, the script will be

#!/bin/bash

product=cache
version=2017.2.0.744.0
arch=lnxrhx64

# WRC Authorization
WRC_USERNAME="user@somecompany.com"
WRC_PASSWORD="password"

wget -qO /dev/null --keep-session-cookies --save-cookies /dev/stdout --post-data="UserName=$WRC_USERNAME&Password=$WRC_PASSWORD" 'https://login.intersystems.com/login/SSO.UI.Login.cls?referrer=https%253A//wrc.intersystems.com/wrc/login.csp' \
 | wget -O - --load-cookies /dev/stdin "https://wrc.intersystems.com/wrc/WRC.StreamServer.cls?FILE=/wrc/distrib/$product-$version-$arch.tar.gz" \
 | tar xvfzC - .


ISC_PACKAGE_INSTANCENAME=$product

/tmp/dsitrib/$product-$version-$arch/cinstall_silent

But it is just a simple example and not covers everything. But can be easily extended by your needs.

Dmitry Maslennikov · Oct 15, 2017 go to post

Almost the same as you do on Windows, or as clean install. Just call

./cinstall

And installer will offer to choose instance name, and if you put the same will offer to upgrade it.