Find

Article
· Nov 16 3m read

Network Debugging for Beginners - 1

Chasing errors or misbehavior in the network can be quite a challenge.
Differently to  a local application on the DB server, you always have at least 3 players:

  • A client  to place a request 
  • some kind of transport layer
  • and a server to provide a reply.

This results in a minimum of 3 possible communication layers

  • Client <---> Transport
  • Server <---> Transport
  • Client <---> Server

The last one is probably the easiest  to check, while the other 
two deal with the same counterpart just from opposite sides.

?  Do both ends use the same communication protocol ?

I met more than once that one end expected to use TCP protocol,
but the other side was using UDP or WS (WebSockets) or whatever.
And IF they match ?

? How does the request look?

You may direct a request for a CSP page to a private port
Using 773 instead of 52773 for the IRIS Management Portal

USER>set port="|TCP|777"
USER>open port:(:773):1 write  $t
1
USER>use port read what  

Now  you launch your request from the browser  http://localhost:777/csp/sys/UtilHome.cs
and see

USER>write what
GET /csp/sys/UtilHome.csp HTTP/1.1
Host: localhost:773
Connection: keep-alive
sec-ch-ua: "Chromium";v="142", "Google Chrome";v="142", "Not_A Brand";v="99"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br, zstd
Accept-Language: en-US,en;q=0.9,de-AT;q=0.8,de;q=0.7
Cookie: state-B88AC959-5DBA-11F0-86C0-0242C0A80002=/5jOrv7mM4MMdJCVpOCgtb1j0WTGCB4RZF2IHT4Og+4%3D%3ASYSEXP%3A; state-84BBBB0F-94B2-11F0-BAB4-0242C0A80006=/5jOrv7mM4MMdJCVpOCgtb1j0WTGCB4RZF2IHT4Og+4%3D%3ASYSEXP%3A; state-1E3B3956-9A2D-11F0-AD45-0242C0A8000B=7xLBuIkd9LEHE63vfvhZkekO0SUMlGruyPOWuYCUrt8%3D%3ASYSEXP%3A;
USER>

The first lines tell you that your request is using HTML on top of HTTP
That means that HTML is used as the content protocol embedded in HTTP

Your port 773 is bi-directional.
So you might be tempted to compose an HTML wrapped reply and send it back just like  

USE port WRITE "<H1>some friendly welcome</H1>",!

As this is not proper HTML and as you miss all required headers and other credentials
for a clean HTTP communication, your Browser may dislike it at least.
Therefore, the next question:

? How does the proper reply look like ?

There is a utility tool in IRIS  to examine the reply to some level.

USER>DO $system.CSP.Shell()
CSP:USER>>>GET /csp/sys/UtilHome.csp

HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Set-Cookie: CSPSESSIONID-UP-csp-sys-=3100      3100; path=/csp/sys/;  httpOnly; sameSite=strict;
Cache-Control: no-cache,no-store
Date: Sun, 16 Nov 2025 15:05:37 GMT
Expires: -1
X-Frame-Options: SAMEORIGIN
<html lang="de" >
<head>
<title>IRIS - Home</title>
<link rel="stylesheet" type="text/css" 
. . . . . . . . .

You should enable logging for the terminal to study this 120k byte reply in detail

Now it is your next step to dig deeper.

For our example with the CSP page and a browser client, you have 3 options:

  1. :  Use your browser development tools to examine the content
  2. :  Use JavaScript alert()  to display some inner invisible content
  3. :  Use JavaScript combined with HTML textarea for more content   

At the server end in IRIS, it's a bit easier.

Every CSP page generates a class, which also generates an INT routine
You have the option to add debugging code at all levels
Just as you would do for any normal background job.
Most likely, this is a sequence that is looping until manually released,
or just some kind of individual tracing with ^ERN or a similar approach.

And this works not just for CSP pages but also for %REST processing.

? And what about the Transport step ?

See part 2 of Network Debugging for Beginners 
Network Debugging for Beginners - 2

Discussion (0)1
Log in or sign up to continue
Article
· Nov 15 1m read

Amostra de código para concatenar arrays JSON

O ObjectScript não inclui nenhum método embutido para anexar um array dinâmico JSON a outro. Aqui está um trecho de código que uso, que é equivalente ao método concat() do JavaScript.

Chame-o com qualquer número de argumentos para concatená-los em um novo array. Se um argumento for um array dinâmico, seus elementos serão adicionados. Caso contrário, o próprio argumento será adicionado.

Discussion (0)1
Log in or sign up to continue
Article
· Nov 14 5m read

CNPJ Será Alfanumérico a partir de julho de 2026 - Classe Atualizada

Pessoal, segue Classe para validar CNPJ alfanumérico Receita Federal, que entra em vigor a partir de julho de 2026.

link: CNPJ Alfanumérico — Receita Federal

Class Utils.Br.Validador
{ /// <summary>
/// Valida um CPF, CNPJ numérico ou CNPJ alfanumérico.
/// Detecta o tipo (11 ou 14 dígitos) e chama o validador apropriado.
/// Retorna 1 (true) se válido, 0 (false) se inválido.
/// </summary>
/// <param name="documento">O número do CPF ou CNPJ, com ou sem formatação.</param>
ClassMethod Validar(documento As %String) As %Boolean
{
    // 1. Limpa a formatação (pontos, traços, barras) e converte para MAIÚSCULO
    Set docLimpo = ..LimparFormatacao(documento)
    Set len = $LENGTH(docLimpo)
    
    // 2. Direciona para o método correto baseado no tamanho
    If len = 11 {
        Quit ..ValidarCPF(docLimpo)
    }
    
    If len = 14 {
        Quit ..ValidarCNPJ(docLimpo)
    }
    
    // Se não tiver 11 ou 14 dígitos, é inválido
    Quit 0
} /// <summary>
/// Valida um número de CPF (11 dígitos).
/// </summary>
/// <param name="cpf">O CPF (idealmente já sem formatação).</param>
ClassMethod ValidarCPF(cpf As %String) As %Boolean [ Private ]
{
    Set cpf = ..LimparFormatacao(cpf) // Garante limpeza extra
    If $LENGTH(cpf) '= 11 Quit 0 }
    
    // CORREÇÃO: Verifica se todos os dígitos são iguais (ex: "11111111111")
    If $TRANSLATE(cpf, $EXTRACT(cpf, 1), "") = "" Quit 0 }
    
    // Cálculo DV1
    Set soma = 0
    For = 1:1:9 {
        Set soma = soma + ($EXTRACT(cpf, i) * (11 - i))
    }
    Set resto = soma # 11
    Set dv1 = $SELECT(resto < 2: 0, 1: 11 - resto)
    If dv1 '= $EXTRACT(cpf, 10) Quit 0 }
    
    // Cálculo DV2
    Set soma = 0
    For = 1:1:10 {
        Set soma = soma + ($EXTRACT(cpf, i) * (12 - i))
    }
    Set resto = soma # 11
    Set dv2 = $SELECT(resto < 2: 0, 1: 11 - resto)
    If dv2 '= $EXTRACT(cpf, 11) Quit 0 }
    
    Quit 1
} /// <summary>
/// Valida um número de CNPJ (14 posições), numérico ou alfanumérico,
/// conforme o Anexo XV da IN RFB nº 2.119/2022 (adicionado pela IN RFB nº 2229/2024).
/// </summary>
/// <param name="cnpj">O CNPJ (já limpo e em maiúsculas).</param>
ClassMethod ValidarCNPJ(cnpj As %String) As %Boolean [ Private ]
{
    If $LENGTH(cnpj) '= 14
     Quit 0
     }     // CORREÇÃO: Verifica sequências de caracteres idênticos (ex: "AAAA...")
    If $TRANSLATE(cnpj, $EXTRACT(cnpj, 1), "") = "" {
    Quit 0
    }
    
    // 3. Cálculo do 1º Dígito Verificador (DV1)
    Set soma = 0
    Set pesos = "543298765432"
    For = 1:1:12 {
        Set char = $EXTRACT(cnpj, i)
        Set valor = $ASCII(char) - 48
        Set soma = soma + (valor * $EXTRACT(pesos, i))
    }
    
    Set resto = soma # 11
    Set dv1 = $SELECT(resto < 2: 0, 1: 11 - resto)
    
    // 4. Verifica o DV1
    If dv1 '= $EXTRACT(cnpj, 13) Quit 0 }
    
    // 5. Cálculo do 2º Dígito Verificador (DV2)
    Set soma = 0
    Set pesos = "6543298765432"
    For = 1:1:13 {
        Set char = $EXTRACT(cnpj, i)
        Set valor = $ASCII(char) - 48
        Set soma = soma + (valor * $EXTRACT(pesos, i))
    }
    
    Set resto = soma # 11
    Set dv2 = $SELECT(resto < 2: 0, 1: 11 - resto)
    
    // 6. Verifica o DV2
    If dv2 '= $EXTRACT(cnpj, 14) Quit 0 }
    
    // Se passou por tudo, é válido
    Quit 1
} /// <summary>
/// Remove caracteres de formatação (., -, /) e converte para MAIÚSCULAS.
/// </summary>
ClassMethod LimparFormatacao(valor As %String) As %String [ Private ]
{
    Set valorLimpo = $TRANSLATE(valor, ".-/", "")
    Quit $ZCONVERT(valorLimpo, "U")
} }
 

// Testando um CNPJ numérico antigo (ainda válido)

USER> WRITE ##class(Utils.BR.Validador).Validar("33.000.167/0001-01")

USER>1

// Testando um CPF (não mudou)

USER> WRITE ##class(Utils.BR.Validador).Validar("123.456.789-00")

USER>1

// NOVO TESTE: O CNPJ Alfanumérico do Exemplo 2 da RFB [cite: 44]

USER> WRITE ##class(Utils.BR.Validador).Validar("12.ABC.345/01DE-35")

USER>1

// NOVO TESTE: O mesmo CNPJ com dígito verificador errado

USER> WRITE ##class(Utils.BR.Validador).Validar("12.ABC.345/01DE-30")

USER>0

// NOVO TESTE: Com letras minúsculas (será tratado)

USER> WRITE ##class(Utils.BR.Validador).Validar("12.abc.345/01de-35")

USER>1

 

Se houver necessidade de ajuste, fiquem a vontade para informar.

Obrigado.

Discussion (0)1
Log in or sign up to continue
Article
· Nov 14 3m read

[DOCKER] Framework de développement conteneurisé

Bonjour à tous,

Je m’adresse à vous, la communauté technique francophone pour vous présenter une réflexion et une proposition de réponse que j’ai apporté pour utiliser docker dans un environnement de développement avec plusieurs développeurs.

Ma réponse se compose en 2 parties, une architecture du repository GIT d’un namespace et un repository lié à DOCKER. La première partie, je pense, peut être utile au-delà d’un contexte docker.

La complexité de ce projet réside dans le fait d’avoir une solution permettant de conteneuriser un nombre “infini” de namespace et éviter d’avoir un conteneur par namespace.

Présentation du framework

Dans chacun de mes projets, je crée un dossier à la racine nommé Config. 

Dans ce dossier va se trouver toute la configuration du namespace avec les fichiers suivants 

  • Les WebApps
  • Les default Settings
  • Le deployer
  • L’installer
  • Les packages (ce fichier sert à dire au plugin docker GIT quels packages il doit exporter dans le repository. L’intérêt est de ne pas polluer le repo avec toutes les classes du namespaces, mais bien seulement celles que je crée.)

Attention, il est extrêmement important de respecter le nommage de chaque fichier avec le nom du namespace et le reste du nom du fichier. Je me sert de cette convention pour détecter automatiquement les namespaces.

Les intérêts sont les suivants

1- Dans mon dossier DOCKER, je n’ai AUCUN fichier de config (à part celui permettant l’affichage dans VSCODE)

Pour chaque namespace présent dans mon workspace respectant le framework, il sera automatiquement déployé lors des commandes docker

2- Chaque namespace peut posséder son propre GIT qui est totalement omnipotent puisqu’il possède également la configuration. Cela permet de résoudre les soucis de gestion des différentes configurations. Dans un contexte multi-développeur sur un même namespace, cela permet d’ajouter automatiquement les nouveaux default settings présent dans la version déployée par exemple.

3- Le repo GIt de chaque namespace n’est pas “pollué” avec de la config docker, il peut très bien être utilisé dans un monde non conteneurisé, toute la complexité de la conteneurisation est portée par le repo DOCKER

Je ne rentre pas pour le moment dans le détail de la solution. Elle n’est pas spécialement complexe mais elle est très fournie. Je peux vous donner les différentes choses à regarder si cela vous intéresse 

  • La classe File.CLS qui me permet de faire toutes les actions requises
  • Les deux scripts (Install et Deploy) qui orchestrent les appels à la classe File pour l’installation.
  • Le Readme qui explique techniquement comment démarrer le projet.
  • A noter que j’utilise un fork personnel du projet MW-de/git-for-iris qui ne gère la les arborescences et le contexte multi namespace (En tout cas à l’époque où j’ai mené ce projet). Toute la complexité de GIt est porté part ce projet. La façon donc les fichiers locaux sont compilés dans la BDD IRIS où comment une modification dans la BDD IRIS (Ajout d’un composant en production) est automatiquement exporté dans un fichier local pour être “commitable”.

Si ce projet vous intéresse, je pourrai aller plus dans le détail de l’explication et/ou faire une vidéo où je présente l’exhaustivité des étapes de conception.

Je vous invite à “jouer” avec mon repo Git prévu à cet effet. Dans ce contexte, j’ai tout réuni au sein d’un même repo pour simplifier le test, mais dans le monde réel, j’ai bien un répo par namespace + un DOCKER. Il n’y a plus qu’à suivre le readme 🙂

https://github.com/ArchiMatt/Framework-docker

C’est un projet que j’ai mené il y a très longtemps pour résoudre nos problématiques projets. Je n’ai plus la chance de travailler sur les technologies InterSystems régulièrement mais je tenais à vous partager ce bout de réflexion. N’hésitez pas à réagir, c’est un projet qui n’est pas terminé, il y a encore plein de choses à améliorer / nettoyer. Peut être que les dernières version d’IRIS sont venues faire évoluer cette vision 🙂


 

Discussion (0)1
Log in or sign up to continue
Question
· Nov 14

How can I code "IF Studio"?

Studio's Output window is interactive, and code can ask questions there if it is a Studio environment. How do I check for that?

19 Comments
Discussion (19)2
Log in or sign up to continue