Dmitry Maslennikov · Feb 21, 2018 go to post

I hope this can explain

USER>zzdump $lb(100,200,50)

0000: 03 04 64 03 04 C8 03 04 32                              ..d..È..2

USER>zzdump $lb("100","200","50")

0000: 05 01 31 30 30 05 01 32 30 30 04 01 35 30               ..100..200..50

USER>k  set mem=$s,mem=$s set a=1234567890 write mem-$s
8

USER>k  set mem=$s,mem=$s set a="1234567890" write mem-$s
32

storing numbers as numbers in $listbuild, is a bit cheapier in memory

But sorry, I don't understand your worry about, how numbers were stored. It mostly does not matter. If I not mistaken, only one place where numbers as numbers are matter is $ZHEX function, which returns different result for string and for a number.

Dmitry Maslennikov · Feb 19, 2018 go to post

you can generate script right before call csession, but you don't need to save it to file.

echo -e "Write \"CurrentPath = ${PWD}\"\n" \
        "Write \"CurrentShell = ${SHELL}\"\n" \
        "halt\n" \
| csession cache -U%SYS

Or if you already have some script file as a template, you can use command envsubst (maybe you have to install it), which will replace these variables with real values.

envsubst text.txt | csession cache -U%SYS
Dmitry Maslennikov · Feb 16, 2018 go to post

replace Hyphen to tab may help

write $tr($zcvt($tr("JOHN SMITH-DOW", "-", $c(9)), "W"), $c(9), "-")
John Smith-Dow
Dmitry Maslennikov · Feb 14, 2018 go to post

This error will happen on Windows and macOS, due to docker uses overlay driver there, which is not supported. You should configure Docker daemon to use aufs as storage driver instead.

This screenshot from macOS, on Windows a bit different, but anyway, you should choose Daemon, and switch to advanced mode, where you can use daemon settings in JSON format, just add "storage-driver": "aufs", and Apply this changes. It will apply and restart daemon. After that it should work.

Dmitry Maslennikov · Feb 11, 2018 go to post

I think it would be better to rename AngularJS to Angular. 

Angular is the name for the Angular of today and tomorrow. AngularJS is the name for all v1.x versions of Angular.

Dmitry Maslennikov · Feb 11, 2018 go to post

With Base64 possible to encode everything, text or binary data, such as PNG. To store it you should first decode it. But, if your image in DataURI format, first, you have to get only base64.

set png="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="
set b64=$piece(png,"base64,", 2)

To encode Base64 in Caché you can use $system.Encryption.Base64Encode(), and $system.Encryption.Base64Decode()  to decode.

set binary=$system.Encryption.Base64Decode(b64)

But these methods support only string and does not support streams. So, you have to write this encoded data, to your file content. Do not forget to use Binary stream classes (%Stream.FileBinary, %Stream.GLobalBinary) to store binary information.

set file=##class(%Stream.GlobalBinary).%New()
do file.Write(binary)

But if your Base64 too long, you can decode by parts with length divisible by 3.

Sorry Nicole, it is planned for version 1.5. While we waited for current version 1.1 since 1.0 one year. So, it will be solved in 4 years. Please correct me if I'm wrong.

And about issues on WRC. I really don't like an idea to fill issues with Atelier with WRC. This issues should be publicly available, where users of this IDE can even vote for some issues.  It would be much better if InterSystems will open special repository on GitHub for issues in Atelier. 

USER>write $zcvt("mY sImPlE eXaMpLe", "W")
My Simple Example

$ZCONVERT

W or w Word translation: Convert the first character of each word in string to uppercase. Any character preceded by a blank space, a quotation mark ("), an apostrophe ('), or an open parenthesis (() is considered the first character of a word. Word translation converts all other characters to lowercase. Word translation is locale specific ; the above syntax rules for English may differ for other language locales.
S or s Sentence translation: Convert the first character of each sentence in string to uppercase. The first non-blank character of string, and any character preceded by a period (.), question mark (?), or exclamation mark (!) is considered the first character of a sentence. (Blank spaces between the preceding punctuation character and the letter are ignored.) If this character is a letter, it is converted to uppercase. Sentence translation converts all other letter characters to lowercase. Sentence translation is locale specific ; the above syntax rules for English may differ for other language locales.

Wireshark is a good tool, but it covers all network. And maybe too much for you. And not so much suitable for HTTP requests inspections. I can suggest you use something like Fiddler. And you should look at this article.

It will not work with Angular or any other modern web application and developed in right way. All pages opened without Cache at all. Web Application is made from static JavaScript, and this app can some time call REST on the server to fetch some data. And sessions now should be endless and stateless. You can only measure server's time.

It should not be a problem. I do Angular2+ application, but I have not done this logging. But, as far as I know, it is possible to subscribe to any routing changes.

import 'rxjs/add/operator/pairwise';
import { Router, ActivatedRoute } from '@angular/router;

export class AppComponent {

  constructor(
    private router: Router,
    private activatedRoute: ActivatedRoute) {
    
    this.router.events
        .filter(event => event instanceof NavigationStart)
        .subscribe((event:NavigationStart) => {
          console.log(event.url)
        });

    // OR
    this.activatedRoute.url.subscribe(url =>{
      console.log(url);
    });
  }

}

And you can then call any API as you want

I don't know what another telnet client you are using, but I suggest that in this client used some special font, which supports to show such invisible chars. ZWrite shows non-display characters as $char and ZZDump can just show everything as hex dump. 

root@bca19b7cb221:/# du -hd1 /usr/cachesys/ | sort -h
12K     /usr/cachesys/devuser
92K     /usr/cachesys/SNMP
112K    /usr/cachesys/patrol
264K    /usr/cachesys/lib
300K    /usr/cachesys/samples
400K    /usr/cachesys/doc
1.2M    /usr/cachesys/docs
3.9M    /usr/cachesys/httpd
33M     /usr/cachesys/fop
49M     /usr/cachesys/dist
58M     /usr/cachesys/dev
85M     /usr/cachesys/csp
241M    /usr/cachesys/bin
642M    /usr/cachesys/mgr
1.1G    /usr/cachesys/

root@bca19b7cb221:/# find /usr/cachesys/mgr/ -name *.DAT -exec ls -lah {} \;
-rw-rw---- 1 root cacheusr 888K Jan 29 22:43 /usr/cachesys/mgr/cachetemp/CACHE.DAT
-rw-rw---- 1 root cacheusr 160M Jan 29 22:43 /usr/cachesys/mgr/enslib/CACHE.DAT
-rw-rw---- 1 root cacheusr 385M Jan 29 22:43 /usr/cachesys/mgr/cachelib/CACHE.DAT
-rw-rw---- 1 root cacheusr 1.0M Jan 29 22:43 /usr/cachesys/mgr/user/CACHE.DAT
-rw-rw---- 1 root cacheusr 1.0M Jan 29 22:43 /usr/cachesys/mgr/cacheaudit/CACHE.DAT
-rw-rw---- 1 root cacheusr 1.0M Jan 29 22:43 /usr/cachesys/mgr/cache/CACHE.DAT
-rw-r----- 1 root cacheusr 65M Jan 29 22:43 /usr/cachesys/mgr/CACHE.DAT

root@bca19b7cb221:/# du -h /usr/local/etc/cachesys/
106M    /usr/local/etc/cachesys/

I am not sure if I really need everything in /usr/cachesys/bin/ - 241MB
 and /usr/local/etc/cachesys/ - 106MB, this two folders plus CACHESYS - 65MB and CACHELIB - 385MB (how much it will be if separate DeepSee and other unnecessary staff), will be around 800MB. While currently image layer size 1.24GB.

Container was started with entrypoint bash. So IRIS has not started, yet.

Yes, in this key it is a good idea to use a password. But I would prefer to have unauthenticated access locally inside the container with csession. So, in this case, I can install and configure everything that I need in my image. But, the instance still will be secured from outside.

But anyway I need more control on what should appear in IRIS. If I don't need yet DeepSee, Ensemble features and so on. Installed IRIS inside container have size more than 1GB,  but even just remove not needed files for me dev folder, even maybe whole CSP folder (offered external CSPgateway container, should be interesting to inspect). It is possible to reduce size in few hundreds of megabytes more.

Instead of your query, I would recommend using query from INFORMATION_SCHEMA.Tables table

SELECT
  TABLE_SCHEMA,
  TABLE_NAME,
  CLASSNAME
FROM INFORMATION_SCHEMA.Tables

In Cache we don't have a table with the number of rows in each table, you have to measure it by yourself for each table. But you can write SQL Function which will count it for you, and you can use this function in the query above.

SELECT count(*) FROM Sample.Person

So, it means that you don't have licence, and you have only one license unit available. You have activate licence to get it worked together.

Dmitry Maslennikov · Jan 31, 2018 go to post

Is it possible to create own image with IRIS based on Ubuntu? Currently available distributive does not support it, and where to get isc-main.

It is good that you prepared the image, but you also set a password there, so, to use this image I have to change a password, and it means that my image will be uselessly bigger with at least about 176Mb in my case. I changed a password by instruction in the documentation.

Dmitry Maslennikov · Jan 31, 2018 go to post

What happens with ZEN in IRIS? %ZEN classes hidden in Class Reference and nothing in the documentation. Is it deprecated, anything else also disappear since Caché/Ensemble?

Dmitry Maslennikov · Jan 31, 2018 go to post

This error happens because you got another error in the request, do not forget to check status.

But anyway. As you need to call https, you should first configure SSL Configuration manually through management portal. You have to fill only Name field, any name on your choice.

Or the same but programmatically.

 ClassMethod GetSSLConfiguration(Server As %String) As %String
{
  new $namespace
  znspace "%SYS"
  do {
    quit:##class(Security.SSLConfigs).Exists(Server)

    set tSC=##class(Security.SSLConfigs).Create(Server)
    $$$ThrowOnError(tSC)
  while 0
  
  quit Server
}

And full working example 

 Class User.Google Extends %RegisteredObject
{

/// Google API key
Parameter KEY = "Put Your Google Maps API Key here";

ClassMethod GetDistanceMatrix(Origins As %String, Destinations As %String, Output Status As %Status) As %DynamicObject
{
  set params("origins")=Origins
  set params("destinations")=Destinations
  set Status=..CallGoogleMapsAPI("/maps/api/distancematrix/json", .params, .data) 
  quit data
}

ClassMethod CallGoogleMapsAPI(Url As %String, ByRef Params, Output Data) As %Status
{
  set Data={}
  set ht=##class(%Net.HttpRequest).%New()
  set ht.Server="maps.googleapis.com"
  set ht.Https=1
  set ht.SSLConfiguration=..GetSSLConfiguration(ht.Server)
  
  set param=""
  for {
    set param=$order(Params(param),1,value)
    quit:param=""
    do ht.SetParam(param, value)
  }
  do ht.SetParam("key", ..#KEY)
  
  set sc=ht.Get(Url)
  if $$$ISERR(sc) quit sc
  
  set Data={}.%FromJSON(ht.HttpResponse.Data)

  quit $$$OK
}

ClassMethod GetSSLConfiguration(Server As %String) As %String
{
  new $namespace
  znspace "%SYS"
  do {
    quit:##class(Security.SSLConfigs).Exists(Server)

    set tSC=##class(Security.SSLConfigs).Create(Server)
    $$$ThrowOnError(tSC)
  while 0
  
  quit Server
}

}

And call in terminal

USER>set data=##class(Google).GetDistanceMatrix("BRISTOL", "LONDON", .sc)

USER>w data.%ToJSON()
{"destination_addresses":["London, UK"],"origin_addresses":["Bristol, UK"],"rows":[{"elements":[{"distance":{"text":"190 km","value":189925},"duration":{"text":"2 hours 23 mins","value":8582},"status":"OK"}]}],"status":"OK"}

My example should work on versions 2016.2 and later, tested on 2017.2

Dmitry Maslennikov · Jan 30, 2018 go to post

It's quite easy to do so. You have to use %Net.HttpRequest class for this. I think it would be better if you try to do it yourself first with knowing how to start. You can find some simple examples in documentation by provided link. And you don't need Ensemble.

Dmitry Maslennikov · Jan 29, 2018 go to post

Right, the problem was in the compilation. In this case, you can't see this property, but you can have access to book from the chapter. Look at this article in the documentation to get more information about SQL access with relationships

Dmitry Maslennikov · Jan 29, 2018 go to post

Could you repeat my commands?

USER>do $system.OBJ.Compile("Test.*","cdk-u")

Compilation started on 01/29/2018 08:42:30 with qualifiers 'cdk-u'
Compiling 2 classes, using 2 worker jobs
Compiling class Test.Book
Compiling class Test.Chapter
Compiling table Test.Book
Compiling table Test.Chapter
Compiling routine Test.Book.1
Compiling routine Test.Chapter.1
Compilation finished successfully in 0.691s.

USER>set b = ##class(Test.Book).%New()

USER>w b.Chapters
7@%Library.RelationshipObject

If you got almost the same, your Insert should work

Dmitry Maslennikov · Jan 29, 2018 go to post

It would be better if you would show the original error message. Something like this

 ​W b.Chapters1.Insert(c1)
^
<PROPERTY DOES NOT EXIST> *Chapters1,Test.Book

I see only that the problem may happen only if you have not compiled sources. 

Dmitry Maslennikov · Jan 28, 2018 go to post

It does not matter where you edit your code, only matter where your Caché server installed. Because all code will be executed only on the server, not on your machine. And if you installed Caché on your mac as well, so, you should use UNIX way for the path.

Dmitry Maslennikov · Jan 27, 2018 go to post

In first you used wrong slashes for windows and macOS. For windows should be "\" and for macOS "/"

For macOS you should use Unix style, where did you find this macOS style with colons? I have never seen such way.

And do not forget, that you can use methods NormalizeFilename and NormalizeDirectory in the class %File. These methods can help you to fix platform differences.