Buscar

Limpiar filtro
Anuncio
Esther Sanchez · 3 ago, 2021

Problema Técnico Global

¡Hola Comunidad! Estamos experimentando algunos problemas técnicos y hemos sufrido un corte de servicio en la red corporativa. Por este motivo, podéis tener problemas al iniciar sesión en nuestros sitios web globales, incluyendo la Comunidad de Desarrolladores. Nuestros especialistas técnicos están trabajando para resolver las incidencias y esperamos restablecer pronto el funcionamiento normal. Para seguir informados, podéis entrar en el Servidor de Discord de la Comunidad de Desarrolladores de InterSystems 👈 ¡Gracias por vuestra paciencia! Lamentamos los inconvenientes que esto os pueda ocasionar.

#Valor clave

1 Publicaciones0 Seguidores

#Analítica convergente

1 Publicaciones0 Seguidores
Artículo
Luis Angel Pérez Ramos · 14 dic, 2022

Cómo subir y descargar archivos a través de HTTP

En este artículo, mostraré cómo subir y descargar archivos vía http desde los productos de InterSystems. A menudo desde la comunidad surgen preguntas sobre como trabajar con archivos a través de http y normalmente os emplazamos a revisar el proyecto FileServer, que muestra la subida/descarga de archivos. Pero me gustaría hablar un poco más de cómo podemos enviar y recibir archivos desde los productos de InterSystems. Cómo descargar un archivo Si tenéis un archivo en un sistema de archivos y conocéis su ruta, podéis enviarlo vía REST o en el contexto de CSP llamando a este método: ClassMethod serve(name As %String) As %Status { #dim sc As %Status = $$$OK #dim %response As %CSP.Response kill %request.Data set %request.Data("STREAMOID",1)= ##class(%CSP.StreamServer).Encrypt(##class(%CSP.StreamServer).GetOidForFile(name)) if ##class(%CSP.StreamServer).OnPreHTTP() { set %response.Headers("Content-Disposition")="attachment; filename*=UTF-8''" _ ##class(%CSP.Page).EscapeURL(##class(%File).GetFilename(name), "UTF8") set sc = ##class(%CSP.StreamServer).OnPage() } quit sc } Si tenéis un stream en lugar de un nombre de fichero, podéis reemplazar ##class(%CSP.StreamServer).GetOidForFile(name) por stream.%Oid() ¡Y eso es todo! En un navegador, el usuario verá un cuadro de diálogo de descarga. Cómo subir un archivo En el lado del cliente (asumiendo el uso de JS/HTML), cread un input de tipo file: <input id="myFile" type="file"> y escribid un código JavaScript para enviar solicitudes POST al servidor (depende del framework): function FileLoad(){ var formData = new FormData(); formData.append("file", document.getElementById("myFile").files[0]); var xhr = new XMLHttpRequest(); // Upload data to server xhr.open("POST", "/rest/path", true); xhr.send(formData); xhr.onload = function(e) { if (this.status == 200) { // everything is OK } else { alert(this.status + ' ' + this.statusText); } }; } En el lado del servidor, podéis obtener el stream de una forma tan sencilla como la siguiente #dim %request As %CSP.Request #dim stream As %CSP.BinaryStream set stream = %request.GetMimeData("file") Después, podéis guardar este stream a un archvo, en una base de datos o simplemente procesarlo sin guardarlo. Enlaces de interéss FileServer MIME Form data WebDAV implementation para InterSystems Este artículo ha sido etiquetado como "Mejores prácticas" ("Best practices"). Los artículos con la etiqueta "Mejores prácticas" incluyen recomendaciones sobre cómo desarrollar, probar, implementar y administrar mejor las soluciones de InterSystems.
Anuncio
Esther Sanchez · 4 oct, 2019

Nuevo vídeo: Desarrollo multi-modelo

¡Hola a tod@s! Tenemos un nuevo vídeo en el Canal de YouTube de la Comunidad de Desarrolladores en inglés: Desarrollo multi-modelo El vídeo muestra los distintos modelos de datos que se pueden usar con InterSystems IRIS y cómo permiten crear excelentes aplicaciones. Además, repasa las diferentes tendencias en la industria, en las que el enfoque multi-modelo se está imponiendo sobre la persistencia políglota. Ponentes: @Jeffrey.Fried, Director of Product Management, y @Alain.Houf, Senior Sales Engineer ¡Esperamos que os resulte útil!
Artículo
Robert Cemper · 7 feb, 2022

GlobalToJSON-embedded-Python

Este es un paquete para exportar un Global a un archivo de objeto JSON y volver a crearlo recargando desde este archivo embeddedPython se refiere a las nuevas tecnologías disponibles. Debe entenderse como un ejercicio de aprendizaje decómo manejar las diferentes interfaces. Solo los nodos de Global que contienen datos se presentan en el archivo JSON generado. Exportamos este Global Este es el contenido del archivo. El Loader relacionado crea exactamente el mismo Global El ejemplo es una clase en la que se mezclan Intersystems Object Script y Embedded Python.Así que es un código híbrido. Intersystems Object Script se usa para iterar a través de Global con $QUERY().También escribe datos con una estructura $LISTBUILD(). El objeto JSON corresponde así al modelo Eficiente. Embedded Python se utiliza para escribir y leer el archivo de datos. Y también se genera el objeto JSONy su resolución se realiza con Embedded Python. Una tarea especial es la conversión correcta de una estructura de subíndice convencional (sub,sub,sub,..) en una lista de Python [sub,sub,sub, ...]. Esta lista de Python es obligatoria para cualquier acceso directoa los nodos de Global.¡Y al nodo superior del Global, que por definición no tiene subíndice, se accede con esta lista especial [None]! Puede ser beneficioso mirar el código en detalle. Vídeo (en inglés)
Anuncio
Esther Sanchez · 31 ago, 2022

Recompensa en Global Masters: Te ayudamos a organizar un webinar

¡Hola Comunidad! ¿Sabíais que en Global Masters se pueden conseguir recompensas para las empresas? Hoy os explicamos una de ellas: ⚡️ Organiza un webinar con el soporte de InterSystems ⚡️ Si estáis interesados en organizar un webinar profesional para desarrolladores sobre vuestra solución/herramienta y vuestros servicios... Podéis canjear este premio por 3 000 puntos y os ayudamos a organizarlo. Qué ofrecemos: Promoción del webinar en la Comunidad de Desarrolladores y en sus redes sociales; Página de registro al webinar; Prueba antes del evento y soporte técnico durante el webinar. Requisitos: La aplicación de la empresa interesada debe funcionar en InterSystems IRIS/IRIS for Health o ser una herramienta para gestionar/desarrollar con IRIS. Los webinars son una excelente forma de dar a conocer productos y servicios para generar interés y nuevos contactos. Así que... si siempre quisisteis hacer un webinar pero no sabéis por donde empezar... aprovechad esta recompensa en Global Masters! Si aún no sois miembro de Global Masters, nuestra plataforma de fidelización, podéis registraros ahora mismo! En esta publicación os explicamos todos los detalles sobre Global Masters. Más información sobre Global Masters: Descripción de los niveles de Global Masters Descripción de las insignias de Global Masters y cómo conseguirlas
Artículo
Ricardo Paiva · 2 dic, 2022

Herramienta de migración de datos - Part III: de DB2 a IRIS

Esta es la tercera parte de una serie de artículos sobre migración desde las principales bases de datos del mercado a InterSystems IRIS. En esta parte, explicaré los pasos para migrar desde DB2. Como describí en los anteriores artículos, actualmente hay varias opciones para hacer la migración. Sin embargo, las dos opciones más populares incluyen el uso de DBeaver (https://openexchange.intersystems.com/package/DBeaver) o SQLGateway. Explicaremos la primera opción aquí. La segunda opción fue explicada por @Robert.Cemper1003 en un excelente artículo: Migración de base de datos usando SQLgateway. Obtención de los datos de muestra para el proceso de migración En Github es posible descargar un proyecto de docker-compose para crear y ejecutar dos bases de datos: Source Database (Base de datos de origen): Instancia Docker de la base de datos DB2 con una base de datos de muestra. Target Database (Base de datos objetivo): Instancia Docker de InterSystems IRIS con un esquema preparado para recibir la base de datos de origen. Para obtener la muestra y ejecutarla, sigue estos pasos:1. Ve al repositorio git: https://github.com/yurimarx/migration-db2-iris.2. Clona el proyecto: git clone https://github.com/yurimarx/migration-db2-iris.git. 3. Ve a la carpeta del proyecto migration-db2-iris.4. Realiza el build: docker-compose build.5. Ejecuta los contenedores: docker-compose up -d.6. Comprueba en el escritorio de tu docker con las instancias si todo está bien: Sobre los datos que se van a migrar En las dos primeras partes, trabajamos con una base de datos de ventas. Sin embargo, DB2, cuando se instala, viene con una base de datos de muestra (es una base de datos de ventas más completa), y será la que usemos en este artículo. Los datos que se van a migrar se representan aquí: Por lo tanto, el proceso de migración de DB2 a IRIS incluirá 22 tablas.El destino de la migración será el esquema dc_test que se encuentra dentro del namespace USER en la base de datos de InterSystems IRIS. Herramienta open-source para migrar de DB2 a IRIS: DBeaver DBeaver es una herramienta de bases de datos para conectar, crear, descartar, seleccionar, actualizar y eliminar objetos de datos en las principales bases de datos del mercado. Se puede descargar en Open Exchange: https://openexchange.intersystems.com/package/DBeaver. Y sigue las instrucciones de instalación para tener este magnífico producto en tu portátil o equipo de sobremesa.DBeaver puede utilizarse para migrar datos entre conexiones de bases de datos, incluso si son de diferentes fabricantes y versiones. Cómo conectar las bases de datos de origen y destino mediante DBeaver Ahora vamos a establecer las conexiones de bases de datos que se van a migrar.Para establecer la conexión de DB2 a DBeaver:1. Antes de conectar DB2 por primera vez, espera de 5 a 10 minutos. Este es el tiempo que el script de DB2 necesita para construir la base de datos de muestra después de la creación de la instancia de Docker.2. En DBeaver, ve a File > New.3. Selecciona Database Connection y haz clic en Next: 4. Haz clic en la pestaña SQL > DB2 LUW y luego en Next: 5. Completa los campos de conexión a DB2 en la pestaña Main, como se muestra en esta imagen : ● Host: localhost● Port: 50000● Database: sample● Username: db2inst1● Password: password● Haz clic en Finish. Para configurar la conexión de InterSystems IRIS a DBeaver:1. En DBeaver, ve a File > New.2. Selecciona Database Connection y haz clic en Next: 3. Haz clic en la pestaña SQL > InterSystems IRIS y luego en Next: 4. Si DBeaver solicita descargar el driver de InterSystems IRIS, haz clic en Sí u Ok.5. Completa los campos de conexión de InterSystems IRIS como se muestra en esta imagen: ● Host: localhost● Database/Schema: user● Username: _SYSTEM● Password: SYS● Haz clic en Test Connection y en Finish Las conexiones (db y user) están disponibles en Database Navigator: Realizar la migración Para realizar la migración hay que seguir estos pasos:1. Expande la conexión de muestra (DB2 connection) > public y selecciona todas las tablas. Haz clic derecho con el ratón sobre las tablas seleccionadas y elige Export Data, así: 2. Selecciona Database, como se ve en esta imagen, y haz clic en Next: 3. Haz clic en el botón Choose: 4. Selecciona dc_test y haz clic en Ok. 5. Ahora será necesario cambiar algunas configuraciones de tipos de datos para la base de datos de destino, porque IRIS y DB2 utilizan diferentes tipos de datos para almacenar valores XML.6. Expande la tabla DB2INST1.CATALOG, selecciona el campo CATALOG (es un tipo de campo XML) y haz clic en Columns… 7. Cambia el Target Type de LONGVARBINARY a VARCHAR(10000) y haz clic en Ok. 8. Repite el proceso con las tablas a. CUSTOMER, campos INFO y HISTORY.b. PRODUCT, campo DESCRIPTION.c. SUPPLIERS, campo ADDR.d. PURCHASEORDER, campo PORDER. 9. Ahora, con los Target Data Types cambiados, haz clic en Next. 10. Establece el Fetch size en 1000000 y haz clic en Next. 11. Acepta los valores predeterminados de Data load settings y haz clic en Next. 12. En Confirm haz clic en Proceed. 13. Ahora podrás ver en el Navegador de bases de datos todas las tablas DB2 que se encuentran dentro del esquema de InterSystems IRIS dc_test El proceso de migración es muy sencillo en el caso de las tablas, pero en el caso de las vistas, funciones, triggers y procedimientos almacenados, será necesario reescribir el código fuente SQL utilizando ObjectScript o SQL.
Anuncio
Esther Sanchez · 30 jun, 2020

Nuevo vídeo: IntegratedML - Predicción de readmisiones de pacientes

¡Hola Comunidad! Os traemos un nuevo vídeo, disponible en el canal de YouTube de la Comunidad de Desarrolladores en inglés sobre el módulo IntegratedML: ⏯ IntegratedML: Predicción de readmisiones de pacientes El vídeo muestra cómo IntegratedML puede usarse para hacer predicciones basándose en los datos de una tabla, directamente en el entorno SQL de InterSystems IRIS; en este ejemplo, se utilizan datos de pacientes para predecir sus readmisiones. Para saber más, podéis echar un vistazo a esta serie de recursos para IntegratedML. Esperamos que os resulte útil 👍🏼
Anuncio
Esther Sanchez · 23 nov, 2020

Nuevo vídeo: Demo de ZPMshow

¡Hola Comunidad! Os traemos un nuevo vídeo, grabado por Robert Cemper y disponible en el canal de YouTube de la Comunidad de Desarrolladores en inglés: ⏯ ZPMshow Demo El vídeo es una demo de ZPMshow – un asistente para registrar, instalar y desinstalar InterSystems Package Manager (ZPM). ⬇️ ZPMshow en Open Exchange Para cualquier duda o consulta, escribid por favor a Robert a robert.cemper@chello o con un Mensaje Directo en la Comunidad. ¡Un fuerte aplauso a Robert! 👏🏼 Y esperamos que os resulte útil
Pregunta
Kurro Lopez · 14 mar, 2023

Error al instalar ZPM

Buenas, Estoy intentando instalar en una nueva instancia de IRIS el ZPM para poder importar paquetes de utilidades en nuestro servidor de desarrollo. Al importar el fichero zpm-0.5.3.xml me está dando este error. ¿Alguien puede ayudar? Gracias Hola Kurro, Has visto esta issue https://github.com/intersystems/ipm/issues/367 no se si es un error "falso" en tu caso Saludos El primero error me lo da cuando instalo el ZPM, y si intento incluir algun paquete me devuelve el mismo error pero no se instala nada
Artículo
Ricardo Paiva · 6 dic, 2019

Tutorial de WebSockets

¡Hola Comunidad! La mayor parte de las comunicaciones servidor-cliente en la web se basan en una estructura de solicitud y respuesta. El cliente envía una solicitud al servidor y el servidor responde a esta solicitud. El protocolo WebSocket ofrece un canal bidireccional de comunicación entre un servidor y un cliente, lo que permite a los servidores enviar mensajes a los clientes sin antes haber recibido una solicitud. Por más información sobre el protocolo WebSocket y su implementación en InterSystems IRIS, vea los siguientes enlaces: WebSocket protocol WebSockets in InterSystems IRIS documentation Este tutorial es una actualización del tutorial rápido "Asynchronous Websockets -- a quick tutorial" para Caché 2016.2+ e InterSystems IRIS 2018.1+. Funcionamiento asíncrono vs síncrono En InterSystems IRIS, una conexión WebSocket puede implementarse de forma síncrona o asíncrona. El tipo de funcionamiento de la conexión WebSocket entre el cliente y el servidor está determinada por la propiedad “SharedConnection” de la clase %CSP.WebSocket. SharedConnection=1 : funcionamiento asíncrono SharedConnection=0: funcionamiento síncrono Una conexión WebSocket entre un cliente y un servidor basado en InterSystems IRIS incluye una conexión entre la instancia de InterSystems IRIS y la Puerta de enlace web. En la forma de funcionamiento síncrona de WebSocket, la conexión usa un canal privado. En el funcionamiento asíncrono de WebSocket, un grupo de clientes WebSocket comparten un conjunto de conexiones entre la instancia de InterSystems IRIS y la Puerta de enlace web. La ventaja de la implementación asíncrona de WebSockets se hace más notoria cuando uno tiene varios clientes que se conectan al mismo servidor, ya que esta implementación no requiere que cada cliente cuente con una conexión exclusiva entre la Puerta de enlace web y la instancia de InterSystems IRIS.En este tutorial implementaré WebSockets de forma asíncrona. Por lo tanto, todas las ventanas de chat abiertas comparten un conjunto de conexiones entre la Puerta de enlace web y la instancia de InterSystems IRIS que aloja la clase de servidor de WebSocket. Resumen de la aplicación de chat El "hola mundo" de WebSockets es una aplicación de chat en la que el usuario puede enviar mensajes que se transmiten a todos los usuarios que hayan iniciado sesión en la aplicación. En este tutorial, los componentes de la aplicación de chat incluyen: Servidor: implementado en una clase que extiende a %CSP.WebSocket Cliente: implementado por una página CSP La implementación de esta aplicación de chat logrará lo siguiente: Los usuarios podrán transmitir mensajes a todas las ventanas de chat abiertas a la vez (broadcast) Los usuarios conectados aparecerán en la lista de usuarios conectados ("Online Users") de todas las ventanas de chat abiertas Los usuarios podrán cambiar su nombre de usuario con solo escribir un mensaje que comience con la palabra clave "alias" y este mensaje no se transmitirá, pero actualizará la lista de usuarios conectados Cuando los usuarios cierren su ventana de chat, se eliminarán de la lista de usuarios conectados Para ver el código fuente de la aplicación de chat, visite este repositorio de GitHub. El cliente El lado cliente de nuestra aplicación de chat lo implementa una página CSP que contiene la información de estilo de la ventana de chat, la declaración de la conexión WebSocket, los eventos y métodos de WebSocket que manejan la comunicación hacia y desde el servidor y las funciones de ayuda que empaquetan los mensajes enviados al servidor y procesan los mensajes entrantes.Primero analizaremos cómo la aplicación inicia la conexión WebSocket usando una biblioteca de WebSocket para Javascript. ws = new WebSocket(((window.location.protocol === "https:")? "wss:":"ws:") + "//"+ window.location.host + "/csp/user/Chat.Server.cls"); new crea una nueva instancia de la clase WebSocket. Esto abre una conexión de WebSocket al servidor usando el protocolo "wss" (indica el uso de TLS para el canal de comunicación de WebSocket) o el "ws". El servidor queda determinado por el número de puerto de servidor web y el nombre de host de la instancia que define la clase Chat.Server (esta información está incluida en la variable window.location.host. El nombre de nuestra clase (Chat.Server.cls) está incluido en la URI de apertura del WebSocket como una solicitud GET del recurso en el servidor.El evento ws.onopen se dispara cuando la conexión de WebSocket se establece con éxito, y pasa del estado connecting (conectando) a open (abierta). ws.onopen = function(event){ document.getElementById("headline").innerHTML = "CHAT - CONNECTED"; }; Este evento actualiza el encabezado de la ventana de chat de forma de indicar que el cliente y el servidor están conectados. Envío de mensajes La acción de que un usuario envíe un mensaje dispara la función send (enviar). Esta función sirve como envoltorio del método ws.send, que contiene las mecánicas para enviar el mensaje al servidor sobre una conexión WebSocket. function send() { var line=$("#inputline").val(); if (line.substr(0,5)=="alias"){ alias=line.split(" ")[1]; if (alias==""){ alias="default"; } var data = {} data.User = alias ws.send(JSON.stringify(data)); } else { var msg=btoa(line); var data={}; data.Message=msg; data.Author=alias; if (ws && msg!="") { ws.send(JSON.stringify(data)); } } $("#inputline").val(""); } send empaqueta la información a enviar al servidor en un objeto JSON, para lo cual define pares de clave/valor de acuerdo con el tipo de información a enviar (actualización de alias o mensaje general). btoa traduce el contenido de un mensaje general a una cadena de texto ASCII con cifrado de base 64. Recepción de mensajes Cuando el cliente recibe un mensaje del servidor, se dispara el evento ws.onmessage. ws.onmessage = function(event) { var d=JSON.parse(event.data); if (d.Type=="Chat") { $("#chat").append(wrapmessage(d)); $("#chatdiv").animate({ scrollTop: $('#chatdiv').prop("scrollHeight")}, 1000); } else if(d.Type=="userlist") { var ul = document.getElementById("userlist"); while(ul.firstChild){ul.removeChild(ul.firstChild)}; $("#userlist").append(wrapuser(d.Users)); } else if(d.Type=="Status"){ document.getElementById("headline").innerHTML = "CHAT - connected - "+d.WSID; } }; Dependiendo del tipo de mensaje recibido por el cliente (“Chat”, “userlist” o “status”), el evento onmessage llama a wrapmessage o wrapuser para poblar las secciones apropiadas de la ventana de chat con los datos entrantes. Si el mensaje entrante es una actualización de estado, el encabezado de estado de la ventana de chat se actualiza con el ID de WebSocket, lo que define la conexión WebSocket bidireccional asociada con la ventana de chat. Componentes adicionales del cliente Un error en la comunicación entre el cliente y el servidor dispara el método onerror de WebSocket, que emite un alerta para notificarnos del error y actualiza el encabezado de estado de la página. ws.onerror = function(event) { document.GetElementById("headline").innerHTML = "CHAT - error"; alert("Received error"); }; Cuando la conexión WebSocket entre el cliente y el servidor se cierra, el método onclose se dispara y actualiza el encabezado de estado. ws.onclose = function(event) { ws = null; document.getElementById("headline").innerHTML = "CHAT - disconnected"; } El servidor El lado servidor de la aplicación de chat es implementado por la clase Chat.Server, que extiende a %CSP.WebSocket. Nuestra clase de servidor hereda varias propiedades y métodos de %CSP.WebSocket, algunas de las cuales analizaré a continuación. Chat.Server también implementa métodos personalizados para procesar mensajes provenientes de, y transmitir mensajes hacia, los clientes. Antes de iniciar el servidor OnPreServer() se ejecuta antes de crearse el WebSocket y se hereda de la clase %CSP.WebSocket. Method OnPreServer() As %Status { set ..SharedConnection=1 if (..WebSocketID '= ""){ set ^Chat.WebSocketConnections(..WebSocketID)="" } else { set ^Chat.Errors($INCREMENT(^Chat.Errors),"no websocketid defined")=$HOROLOG } Quit $$$OK } Este método establece en 1 el parámetro de clase SharedConnection, lo que indica que nuestra conexión WebSocket será asíncrona y soportada por múltiples procesos que definen las conexiones entre la instancia de InterSystems IRIS y la puerta de enlace web. El parámetro SharedConnection solo se puede modificar en OnPreServer(). OnPreServer() también almacena el ID de WebSocket asociado con el cliente en la global ^Chat.WebSocketConnections. El método Server El método Server() contiene el cuerpo de lógica principal ejecutado por el servidor. Method Server() As %Status { do ..StatusUpdate(..WebSocketID) for { set data=..Read(.size,.sc,1) if ($$$ISERR(sc)){ if ($$$GETERRORCODE(sc)=$$$CSPWebSocketTimeout) { //$$$DEBUG("no data") } if ($$$GETERRORCODE(sc)=$$$CSPWebSocketClosed){ kill ^Chat.WebSocketConnections(..WebSocketID) do ..RemoveUser($g(^Chat.Users(..WebSocketID))) kill ^Chat.Users(..WebSocketID) quit // Client closed WebSocket } } else{ if data["User"{ do ..AddUser(data,..WebSocketID) } else { set mid=$INCREMENT(^Chat.Messages) set ^Chat.Messages(mid)=data do ..ProcessMessage(mid) } } } Quit $$$OK } Este método lee los mensajes entrantes desde el cliente (usando el método`Read de la clase %CSP.WebSockets), agrega los objetos JSON recibidos al global ^Chat.Messages y llama a ProcessMessage() para reenviar el mensaje a todos los demás clientes de chat conectados. Cuando un usuario cierra su ventana de chat (lo que finaliza la conexión WebSocket al servidor), la llamada del método Server() a Read devuelve un código de error que se evalúa en la macro $$$CSPWebSocketClosed y el método procede a manejar el cierre de forma acorde. Procesamiento y distribución de mensajes ProcessMessage() agrega metadatos al mensaje de chat entrante y llama a SendData(), al que le pasa el mensaje como parámetro. ClassMethod ProcessMessage(mid As %String) { set msg = ##class(%DynamicObject).%FromJSON($GET(^Chat.Messages(mid))) set msg.Type="Chat" set msg.Sent=$ZDATETIME($HOROLOG,3) do ..SendData(msg) } ProcessMessage() recupera el mensaje con formato JSON desde el global ^Chat.Messages y lo convierte en un objeto de InterSystems IRIS usando el método %FromJSON de la clase %DynamicObject. Esto nos permite editar los datos fácilmente antes de reenviar el mensaje a todos los clientes de chat conectados. Agregamos un atributo `Type` (tipo) con el valor “Chat,” que el cliente usará para determinar qué hacer con el mensaje entrante. SendData() envía el mensaje a todos los demás clientes de chat conectados. ClassMethod SendData(data As %DynamicObject) { set c = "" for { set c = $order(^Chat.WebSocketConnections(c)) if c="" Quit set ws = ..%New() set sc = ws.OpenServer(c) if $$$ISERR(sc) { do ..HandleError(c,"open") } set sc = ws.Write(data.%ToJSON()) if $$$ISERR(sc) { do ..HandleError(c,"write") } } } SendData() vuelve a convertir el objeto de InterSystems IRIS en una cadena JSON (data.%ToJSON()) y hace un envío push del mensaje a todos los clientes del chat. SendData() recibe el ID de WebSocket ID asociado a cada conexión cliente-servidor desde el global ^Chat.WebSocketConnections y usa el ID para abrir una conexión WebSocket mediante el método OpenServer de la clase %CSP.WebSocket. Para hacer esto podemos usar el método OpenServer, porque nuestras conexiones WebSocket son asíncronas: tomamos uno del conjunto compartido existente de procesos InterSystems IRIS-Puerta de enlace web y le asignamos el ID de WebSocket que identifica la conexión del servidor a un cliente de chat específico. Finalmente, el método Write() de %CSP.WebSocket hace un envío push al cliente de la representación del mensaje como cadena JSON. Conclusión Esta aplicación de chat demuestra cómo establecer conexiones WebSocket entre un cliente y un servidor alojado en InterSystems IRIS. Para leer más sobre el protocolo y su implementación en InterSystems IRIS, siga los enlaces que dejé en la introducción.
Artículo
Alberto Fuentes · 15 mayo, 2020

Un contenedor para probar Machine Learning ML con IRIS, Spark y Zeppelin

¡Muy buenas! Repasemos hoy un genial artículo de David E. Nelson sobre cómo montar un entorno de pruebas utilizando contenedores Docker para experimentar con IRIS, Spark y Zeppelin. Gracias a la creciente disponibilidad de contenedores y el cada vez más útil Docker para Windows / MacOs, tengo mi propia selección de entornos preconfigurados para aprendizaje automático y *data science*. Por ejemplo, [Jupyter Docker Stacks](https://jupyter-docker-stacks.readthedocs.io/en/latest/index.html) y [Zeppelin](https://hub.docker.com/r/apache/zeppelin) en Docker Hub. Gracias también a la edición IRIS Community en un contenedor, tenemos un práctico acceso a una plataforma de datos que admite tanto el aprendizaje automático y análisis junto con otras muchas funciones. Al usar contenedores, no necesito preocuparme por actualizaciones automáticas que puedan arruinar mi área de pruebas. Si mi oficina se inundara y el portátil quedara inservible, podría recrear fácilmente el área de pruebas con un único archivo de texto, que por supuesto subí a un sistema de control de versiones ;-) A continuación compartiré el archivo de Docker Compose que usé para crear un área de pruebas basada en un contenedor para Machine Learning. El área de pruebas comprende dos contenedores: uno con un entorno Zeppelin y Spark, el otro con la plataforma de datos InterSystems IRIS community. Ambos usan imágenes disponibles en Docker Hub. Luego mostraré cómo configurar el InterSystems Spark Connector para conectarlos entre sí. Para terminar, cargaré algunos datos en InterSystems IRIS y usaré Spark para hacer exploración y visualización de datos y algún aprendizaje automático muy básico. Por supuesto, mi ejemplo apenas tocará la superficie de las capacidades tanto de Spark como de InterSystems IRIS. Sin embargo, espero que el artículo sea útil para que otros comiencen a realizar tareas más complejas y útiles. ## Archivo Docker Compose * Dos contenedores: uno contiene InterSystems IRIS Community Edition y el otro contiene tanto el entorno de bloc de notas Zeppelin y Apache Spark. Ambos contenedores se basan en imágenes tomadas de la tienda de Docker. * Una conexión de red entre ambos contenedores. Con esta técnica, podemos usar los nombres de los contenedores como nombres de host al configurar la comunicación entre los contenedores. * Directorios locales montados en cada contenedor. Podemos usar estos directorios para hacer que los archivos jar queden disponibles para el entorno Spark y para que algunos archivos de datos queden disponibles para el entorno IRIS. * Un volumen con nombre para la funcionalidad duradera %SYS que requiere InterSystems IRIS. InterSystems IRIS requiere volúmenes con nombres cuando se ejecuta dentro de contenedores en Docker para Windows. Por más información sobre este tema, consulte abajo los enlaces a otros artículos de la comunidad. * Mapear algunos puertos de red dentro de los contenedores a puertos disponibles fuera de los contenedores para brindar un fácil acceso. ``` version: '3.2' services: # contenedor con InterSystems IRIS iris: # imagen de iris community edition a extraer de la tienda Docker. image: store/intersystems/iris:2019.1.0.510.0-community container_name: iris-community ports: # 51773 es el puerto predeterminado del superserver - "51773:51773" # 52773 es el puerto predeterminado del webserver/portal de gestión - "52773:52773" volumes: # Crea un volumen con nombre durable_data que guardará los datos duraderos %SYS - durable:/durable # Mapea un directorio /local para permitir el fácil traspaso de archivos y scripts de prueba - ./local/samples:/samples/local environment: # Configurar la variable ISC_DATA_DIRECTORY al volumen durable_data que definimos antes para usar %SYS duradero - ISC_DATA_DIRECTORY=/durable/irissys # Agrega el contenedor IRIS a la red definida a continuación. networks: - mynet # contenedor con Zeppelin y Spark zeppelin: # bloc de notas zeppelin con imagen de spark para extraer desde docker store. image: apache/zeppelin:0.8.1 container_name: spark-zeppelin # Puertos para acceder al entorno Zeppelin ports: # Puerto para bloc de notas Zeppelin - "8080:8080" # Puerto para página de trabajos Spark - "4040:4040" # Mapea directorios /local para guardar blocs de notas y acceder a archivos jar. volumes: - ./local/notebooks:/zeppelin/notebook - ./local/jars:/home/zeppelin/jars # Agrega el contenedor Spark y Zeppelin a la red definida a continuación. networks: - mynet #Declara el volumen con nombre para el %SYS duradero de IRIS volumes: durable: # Define una conexión de red entre ambos contenedores. networks: mynet: ipam: config: - subnet: 172.179.0.0/16 ``` ## Puesta en funcionamiento Coloca el archivo compose en un directorio. El nombre del directorio se convierte en el nombre del proyecto Docker. Deberá crear subdirectorios que coincidan con los mencionados en el archivo docker-compose.yml. Por lo tanto, la estructura de directorio se ve así: ``` |_local |_ jars |_notebooks |_samples |_ docker-compose.yml ``` Para iniciar los contenedores, ejecuta esta comando dentro del directorio del proyecto: ```console $ docker-compose up –d ``` El *flag*` -d` inicia los contenedores en modo *detached* (estarán ejecutando en *background*). Puedes usar el comando logs de docker para los registros de log: ```console $ docker logs iris-community ``` Para inspeccionar el estado de los contenedores, podemos ejecutar lo siguiente: ```console $ docker container ls ``` Accederemos al Portal de gestión de IRIS con la URL: http://localhost:52773/csp/sys/UtilHome.csp La primera vez que iniciemos sesión en IRIS, entraremos con `superUser / SYS`. A continuación se nos pedirá modificar la contraseña por defecto. Al bloc de notas Zeppelin accedemos a través de la URL: http://localhost:8080 ### Copiar algunos archivos jar Para usar el InterSystems Spark Connector, el entorno Spark debe acceder a dos archivos jar: * intersystems-jdbc-3.0.0.jar * intersystems-spark-1.0.0.jar Estos archivos jar están dentro de IRIS en el contenedor iris-community. Debemos copiarlos al directorio localmente mapeado, para que el contenedor spark-zeppelin pueda acceder a ellos. Para esto, podemos usar el comando cp de Docker para copiar todos los archivos desde dentro del contenedor iris-community hacia uno de los directorios locales visibles para el contenedor spark-zeppelin: ```console $ docker cp iris-community:/usr/irissys/dev/java/lib/JDK18 local/jars ``` ## Agregar datos Sin datos no hay Machine Learning. Podemos usar los directorios locales montados por el contenedor iris-community para agregar datos a IRIS. Utilizaremos el clásico [conjunto de datos sobre la flor Iris](https://en.wikipedia.org/wiki/Iris_flower_data_set). Desde hace tiempo este conjunto de datos cumple la función de ejemplo "Hola Mundo" para Machine Learning. Puedes descargar o extraer una definición de clase de InterSystems para generar los datos, junto con código para varios ejemplos relacionados, de GitHub ([Samples-Data-Mining](https://github.com/intersystems/Samples-Data-Mining)). Nos interesa únicamente un archivo de este conjunto: `DataMining.IrisDataset.cls`. Copia `DataMining.IrisDataset.cls` al directorio `/local/samples`. A continuación, para abrir un intérprete bash dentro del contenedor iris-community, ejecuta: ```console $ docker exec –it iris-community bash ``` Desde el intérprete bash, inicia una sesión de terminal IRIS con el usuario *superuser* y la contraseña que cambiaste anteriormente en el portal de gestión. ```console /# iris session iris ``` Cargamos la clase para generar los datos en IRIS: ``` USER>Do $System.OBJ.Load(“/samples/local/IrisDataset.cls”,”ck”) ``` A continuación, generamos los datos: ``` USER>Set status = ##class(DataMining.IrisDataset).load() USER>Write status ``` La base de datos ahora debería contener ahora datos de 150 ejemplos de flores Iris. ## Lanzar Zeppelin y Configurar nuestro bloc de notas En primer lugar, descarga la nota "Machine Learning Hello World" de Zeppelin disponibles https://github.com/denelson/DevCommunity. Podrás abrir el bloc de notas Zeppelin en su navegador web en la URL http://localhost:8080. Debería verse algo parecido a esto: ![](https://community.intersystems.com/sites/default/files/inline/images/images/image(103).png "Bloc de notas Zeppelin") Hacemos click en *Import note* e importamos la nota “Machine Learning Hello World.json” que habíamos descargado antes. En el primer párrafo de código cargaremos el controlador de InterSystems JDBC y Spark Connector. Por defecto, los blocs de notas Zeppelin ofrecen la variable `z` para acceder al contexto Zeppelin. Tienes más información disponible sobre [contexto Zeppelin](https://zeppelin.apache.org/docs/0.8.0/usage/other_features/zeppelin_context.html) en la documentación. ``` %spark.dep //z supplies Zeppelin context z.reset() z.load("/home/zeppelin/jars/JDK18/intersystems-jdbc-3.0.0.jar") z.load("/home/zeppelin/jars/JDK18/intersystems-spark-1.0.0.jar") ``` Antes de ejecutar el párrafo de código, hacemos click en la flecha abajo que se encuentra al lado de la palabra *anonymous* y escogemos *Interpreter*. ![](https://community.intersystems.com/sites/default/files/inline/images/images/image(104).png "Acceder a la configuración de intérpretes de Zeppelin") En la página *Intepreters*, buscamos *spark*, hacemos click en el botón *restart* (reiniciar) del lado derecho y luego en OK en el cuadro emergente que aparecerá. ![](https://community.intersystems.com/sites/default/files/inline/images/images/image(105).png) Regresamos al bloc de notas "Machine Learning Hello World" y hacemos clic en la pequeña flecha de la derecha para ejecutar el párrafo. Debería resultar algo parecido a esto: ![](https://community.intersystems.com/sites/default/files/inline/images/images/image(107).png) ## Conectar con IRIS y explorar los datos Ya está todo configurado. Ahora podemos conectar el código que se ejecuta en el contenedor *spark-zeppelin* con InterSystems IRIS, que se ejecuta en nuestro contenedor iris-community, y comenzar a explorar los datos que agregamos antes. El siguiente código Python se conecta con InterSystems IRIS y lee la tabla de datos que cargamos en un paso anterior (`DataMining.IrisDataset`), para luego mostrar las primeras diez filas. A continuación dejo algunas notas sobre el siguiente código: * Necesitamos pasar el usuario y la contraseña en la conexión a IRIS. Utiliza la contraseña que hayas establecido en pasos anteriores. En el ejemplo usamos SuperUser/SYS1. * El `iris` dentro del fragmento de código `spark.read.format(“iris”)` es un alias para la clase `com.intersystems.spark`, el conector *spark*. * La URL de conexión, incluyendo "IRIS" al inicio, especifica la ubicación del servidor maestro Spark predeterminado de InterSystems IRIS. * La variable `spark` apunta a la sesión Spark brindada por el intérprete Spark de Zeppelin. ``` %pyspark uname = "SuperUser" pwd = "SYS1" # sesión spark disponible de forma predeterminada a través de la variable spark. # La URL usa el nombre del contenedor, iris-community, como nombre de host. iris = spark.read.format("iris").option("url","IRIS://iris-community:51773/USER").option("dbtable","DataMining.IrisDataset").option("user",uname).option("password",pwd).load() iris.show(10) ``` Nota: tienes más información dispone en [Uso de InterSystems Spark Connector](https://irisdocs.intersystems.com/iris20191/csp/docbook/DocBook.UI.Page.cls?KEY=BSPK_intro) y [SparkContext, SQLContext, SparkSession, ZeppelinContext](http://SparkContext,%20SQLContext,%20SparkSession,%20ZeppelinContext). Al ejecutar el párrafo anterior se obtiene la siguiente salida: ![](https://community.intersystems.com/sites/default/files/inline/images/images/image(108).png) Cada fila representa una flor individual y registra el largo y ancho de sus pétalos, su largo y ancho de sépalo, y la especie de Iris a la que pertenece. ``` %pyspark iris.groupBy("Species").count().show() ``` ![](https://community.intersystems.com/sites/default/files/inline/images/images/image(111).png) Así, hay tres especies de Iris distintas representadas en los datos. Los datos representan a cada especie por igual. Incluso podemos usar la biblioteca *matplotlib* de Python para dibujar algunas gráficas. Este es el código para representar Largo de pétalo (*Petal length*) frente a Ancho de pétalo (*Petal width*): ``` %pyspark %matplotlib inline import matplotlib.pyplot as plt #Recuperar una matriz de objetos de fila desde el DataFrame items = iris.collect() petal_length = [] petal_width = [] for item in items: petal_length.append(item['PetalLength']) petal_width.append(item['PetalWidth']) plt.scatter(petal_width,petal_length) plt.xlabel("Petal Width") plt.ylabel("Petal Length") plt.show() ``` ![](https://community.intersystems.com/sites/default/files/inline/images/images/image(112).png) Incluso para el ojo no entrenado, parece haber una fuerte correlación entre largo y ancho de pétalo. Deberíamos poder predecir de forma confiable el largo de pétalo en base al ancho de pétalo. ## Un poco de aprendizaje automático Para predecir el largo de pétalo en base al ancho de pétalo, necesitamos un modelo de la relación entre ambos. Podemos usar Spark para crear dicho modelo muy fácilmente. A continuación utilizamos un código que usa la API de regresión lineal de Spark para entrenar un modelo de regresión. El código hace lo siguiente: 1. Crea un nuevo *DataFrame* de Spark que contiene las columnas de largo y ancho de pétalo. La columna de ancho de pétalo representa la "característica" y la columna de largo de pétalo representa las "etiquetas". Usamos las características para predecir las etiquetas. 2. Divide los datos aleatoriamente en un conjunto de entrenamiento (70%) y uno de pruebas (30%). 3. Usa los datos de entrenamiento para ajustar el modelo de regresión lineal. 4. Aplica el modelo a los datos de prueba y luego muestra el largo de pétalo, ancho de pétalo, características y predicciones. ``` %pyspark from pyspark.ml.regression import LinearRegression from pyspark.ml.feature import VectorAssembler # Transformar la(s) columna(s) de "Características" (Features) al formato vectorial correcto df = iris.select('PetalLength','PetalWidth') vectorAssembler = VectorAssembler(inputCols=["PetalWidth"], outputCol="features") data=vectorAssembler.transform(df) # Dividir los datos entre conjuntos de entrenamiento y prueba. trainingData,testData = data.randomSplit([0.7, 0.3], 0.0) # Configurar el modelo. lr = LinearRegression().setFeaturesCol("features").setLabelCol("PetalLength").setMaxIter(10) # Entrenar el modelo con los datos de entrenamiento. lrm = lr.fit(trainingData) # Aplicar el modelo a los datos de prueba y mostrar sus predicciones de largo de pétalo (PetalLength). predictions = lrm.transform(testData) predictions.show(10) ``` ![](https://community.intersystems.com/sites/default/files/inline/images/images/image(114).png) ## La línea de regresión El "modelo" no es más que una línea de regresión a través de los datos. Sería interesante conocer la pendiente y punto de intersección con el eje vertical de esa línea. También sería interesante poder visualizar la línea superpuesta a nuestro diagrama de dispersión. El siguiente código recupera la pendiente e intersección con el eje vertical del modelo entrenado y luego las usa para agregar una línea de regresión al diagrama de dispersión de los datos de largo y ancho de pétalo. ``` %pyspark %matplotlib inline import matplotlib.pyplot as plt # recuperar la pendiente e intersección con el eje vertical de la línea de regresión del modelo. slope = lrm.coefficients[0] intercept = lrm.intercept print("slope of regression line: %s" % str(slope)) print("y-intercept of regression line: %s" % str(intercept)) items = iris.collect() petal_length = [] petal_width = [] petal_features = [] for item in items: petal_length.append(item['PetalLength']) petal_width.append(item['PetalWidth']) fig, ax = plt.subplots() ax.scatter(petal_width,petal_length) plt.xlabel("Petal Width") plt.ylabel("Petal Length") y = [slope*x+intercept for x in petal_width] ax.plot(petal_width, y, color='red') plt.show() ``` ![](https://community.intersystems.com/sites/default/files/inline/images/images/image(117).png) ## ¿Qué más podemos hacer? Hay mucho más que podemos hacer. Obviamente, podemos cargar conjuntos de datos mucho más grandes e interesantes en IRIS. Vea, por ejemplo, los conjuntos de datos Kaggle (https://www.kaggle.com/datasets). Con una licencia completa de IRIS podríamos configurar la fragmentación y ver cómo Spark aprovecha el paralelismo que permite la fragmentación al ejecutarse a través del InterSystems Spark Connector. Spark, por supuesto, brinda muchos otros algoritmos de aprendizaje automático y análisis de datos. Admite varios otros lenguajes, incluyendo Scala y R.
Anuncio
David Reche · 30 oct, 2020

Séptimo Concurso para Desarrolladores: Interoperabilidad

¡Hola Desarrolladores! Ya está listo el nuevo concurso para crear soluciones de código abierto utilizando InterSystems IRIS o IRIS for Health. El tema de este séptimo concurso es Interoperabilidad. Estará activo durante tres semanas: del 2 al 22 de noviembre de 2020. Premios 1. Nominación de los expertos - los ganadores serán elegidos por un jurado especialmente formado para el concurso. Los premios serán: 🥇 1er puesto - $2,000 🥈 2º puesto - $1,000 🥉 3er puesto - $500 2. Nominación de la Comunidad - ganará la aplicación que obtenga el mayor número total de votos. Los premios serán: 🥇 1er puesto - $1,000 🥈 2º puesto - $500 🥉 3er puesto - $250 Si dos o más participantes obtienen la misma cantidad de votos, todos serán considerados ganadores y el dinero del premio se repartirá entre todos. ¿Quién puede participar? Cualquier miembro registrado en la Comunidad de Desarrolladores de cualquier país puede participar en el concurso, excepto los empleados de InterSystems. Regístrate aquí en la Comunidad si aún no tienes una cuenta. Duración del concurso Del 2 al 15 de noviembre: Dos semanas para subir las aplicaciones a Open Exchange (durante este período, se pueden modificar los proyectos). Del 16 al 22 de noviembre: Una semana para votar. Los ganadores serán anunciados el lunes 23 de noviembre. Tema del concurso 💡 Soluciones de interoperabilidad para InterSystems IRIS e IRIS for Health 💡 Desarrollo de una solución de interoperabilidad o una solución que ayude a desarrollar y/o mantener soluciones de interoperabilidad, usando InterSystems IRIS o InterSystems IRIS for Health. La aplicación debe funcionar en IRIS Community Edition o IRIS for Health Community Edition o IRIS Advanced Analytics Community Edition. La aplicación debe ser Open Source y publicarse en GitHub. Y las aplicaciones que implementen unos requisitos tecnológicos adicionales, obtendrán bonus tecnológicos. Recursos adicionales 1. Aplicaciones de ejemplo: IRIS-Interoperability-template ETL-Interoperability-Adapter HL7 and SMS Interoperability Demo Twitter Sentiment Analysis with IRIS Healthcare HL7 XML RabbitMQ adapter PEX demo 2. Cómo enviar una aplicación al concurso: How to publish an application on Open Exchange How to submit an application for the contest 3. Cursos online: Interoperability for Business Interoperability QuickStart Interoperability Resource Guide - 2019 4. Vídeos: Intelligent Interoperability Interoperability for Health Overview Jurado Consulta los Criterios del jurado y las Reglas sobre los votos. Así que... Ready. Set. Code! ¡Suerte a todos! ❗️ Echa un vistazo a los Términos Oficiales del Concurso.❗️ Ya ha empezado el concurso para desarrolladores. ¡Estamos deseando ver vuestros proyectos! Bonus tecnológicos para el concurso ¡Hola desarrolladores! Aún queda esta semana para que envieis vuestras aplicaciones al concurso sobre Interoperabilidad. Y no os preocupeis si no habéis terminado el proyecto – podéis modificar vuestras aplicaciones hasta el 22 de noviembre Cómo participar en los concursos Inicia sesión en Open Exchange, ve a "Applications" en tu perfil. Abre la aplicación con la que quieres participar en el concurso y haz clic en "Apply for Contest". Asegúrate de que el estado ha pasado a 'Published'. La aplicación pasará a ser revisada y si encaja en el tema del concurso, se añadirá a la lista del contest board.
Artículo
Muhammad Waseem · 1 dic, 2021

Cómo crear usuarios, conceder privilegios, habilitar/deshabilitar y autentificar/invalidar aplicaciones web mediante programación

En este artículo explicaré cómo, mediante programación, creé el usuario, concedí privilegios, habilité/deshabilité y autentifiqué/invalidé una aplicación web en mi aplicación Data_APP_Security (https://openexchange.intersystems.com/package/Data_APP_Security) Empecemos por la autentificación La autenticación verifica la identidad de cualquier usuario o entidad que intente conectarse a InterSystems IRIS®. Como se dice a menudo, la autentificación es la forma de demostrar que eres quien dices ser. Hay varias formas de autentificar a un usuario; cada uno se conoce como un mecanismo de autenticación. InterSystems IRIS admite varios mecanismos de autenticación: Kerberos — El protocolo Kerberos fue diseñado para proporcionar autentificación segura a los servicios a través de una red no segura. Kerberos usa tickets para autentificar a un usuario y evita el intercambio de contraseñas en la red. Basado en el sistema operativo— La autenticación basada en el SO utiliza la identidad del sistema operativo de cada usuario para identificar a ese usuario en InterSystems IRIS. Autentificación de instancia — Con la autenticación de instancia, InterSystems IRIS solicita al usuario una contraseña y compara un hash de la contraseña proporcionada con un valor que ha almacenado. Protocolo Ligero de Acceso a Directorios (LDAP) — Con el Protocolo Ligero de Acceso a Directorios, InterSystems IRIS autentifica al usuario basándose en la información de un repositorio central, conocido como servidor LDAP. Autenticación delegada— La autenticación delegada proporciona un medio para crear mecanismos de autenticación personalizados. El desarrollador de la aplicación controla por completo el contenido del código de autentificación delegado. Estoy usando Autentificación de instancia, para la creación de usuarios, podemos usar el siguiente comando de ObjectScript : &sql(CREATE USER TestUser IDENTIFY BY demo) Creamos TestUser con contraseña de demostración Autorización Una vez que se realiza la autenticación, debemos crear roles y otorgar privilegios a los roles y luego vincular los roles con los usuarios (Autorización). Esto lo haremos en tres pasos. Paso 1: Crear un rol usando el siguiente comando de ObjectScript. Estamos creando un rol de lectura y escritura &sql(CREATE ROLE ReadWrite) Paso 2: Conceder privilegios SELECT, UPDATE, INSERT en la tabla al rol. Estamos asignando privilegios de la tabla scw.Patient al rol ReadWrite &sql(GRANT SELECT,UPDATE,INSERT ON scw.Patient TO ReadWrite) Paso 3: Conceder rol al usuario. Estamos asignando el rol de lectura y escritura al usuario TestUser &sql(GRANT ReadWrite To TestUser) Habilitar/deshabilitar la aplicación web Podemos habilitar o deshabilitar la aplicación web usando el siguiente código de ObjectScript New $Namespace Set $Namespace = "%SYS" Set App = ##class(Security.Applications).%OpenId("/terminal") Set App.Enabled=0 Do App.%Save() aquí "/terminal" es el nombre de nuestra aplicación. La aplicación se puede deshabilitar configurando "App.Enabled" en 0 y habilitarla configurando el valor en 1 Autentificar/invalidar la aplicación web Podemos configurar la autentificación mediante el siguiente código de ObjectScript New $Namespace Set $Namespace = "%SYS" Set App = ##class(Security.Applications).%OpenId("/terminal") Set App.AutheEnabled=0 Do App.%Save() aquí "/terminal" es el nombre de nuestra aplicación. La autentificación se puede establecer mediante la propiedad "App.AutheEnabled". Se pueden configurar los siguientes valores numéricos property AutheEnabled as Security.Datatype.Authentication [ InitialExpression = 64 ]; Authentication and Session mechanisms enabled (CSP Only). Bit 2 = AutheK5API Bit 5 - AutheCache Bit 6 = AutheUnauthenticated Bit 11 = AutheLDAP Bit 13 = AutheDelegated Bit 14 = LoginToken Bit 20 = TwoFactorSMS Bit 21 = TwoFactorPW Gracias