Jochen Roese · Sep 15, 2025 go to post

Thank you. I thought im stupid because I introduced GIT in another company and we didnt had that bug. 

Now I need to find a way to fix it in the repo without cousing too much trouble

Jochen Roese · Mar 20, 2023 go to post

The <DIRECTORY> error means that the directory or file couldn't be found. Make sure IRIS has access to this file.

Jochen Roese · Aug 3, 2020 go to post

I'm not sure if I'm correct here but I think you can eliminate 2 for-loops and the call to getArticle():

In SD031 there should be only one key for "x" (should be a 1:1 relationship), also try to avoid setting up a list just to .count() to see if "dataExists". You should use something like $data (in ^SB02906 there could be one dataset for every item you sale, for every customer). That should speed everything up a little.

My approach:

set a = $order(^SD031S("0","7",x,a))

        if (a '="") {

            set b = $order(^SD031S("0","7",x,a,b))

            if (b '= "") {

                if ($piece($get(^SD031("0",a,b,1)),Y,9) = x) {

                    set c = a

                    set d = ""

                    for {

                        set d = $order(^FA060S("0","22",c,b,c,d))

                        if (d = "") { quit }

                        if ($piece($get(^FA060("0",c,d,2),""),Y,25) = b) {

                            #dim innerObject = ##class(%ZEN.proxyObject).%New()

                            set innerObject.d = d

                            set innerObject.c = c

                            set k = $o(^SB02906("0",c,d,""))

                            if (k'="") {

                                set innerObject.dataExist = ($d(^SB02906("0",c,d,k,"EUR","0","1"))'=0)

                            } else {

                                set innerObject.dataExist = 0

                            }

                            do responseList.Insert(innerObject)

                        }

                    }

                }     

            }   

        }

Also that caching problem should not exist in production because FA060 and SD031 are read for almost everything in your ERP so it stays in the cache. Otherwise you probably need to create a background-job that reads a few global-nodes every 5-10 minutes to get it cached.

Jochen Roese · Aug 28, 2019 go to post

I reinstalled my machine. Somehow Windows Updates didn't installed as well before. I wish I could check these Kaspersky-Logs, but now it's too late. Maybe it's really something that they prevented. Nevertheless our group-policy should've uninstalled it months ago. Didn't work either. 

So a clean install of Windows 10 was a good solution here. 

Jochen Roese · Aug 27, 2019 go to post

I already saw that post. I should've scrolled further. There was a msiexec.exe frown

But now I have the "Cache initialisation finished-problem"

Edit on post coming as soon as I have the error.

Jochen Roese · Mar 8, 2019 go to post

Would be nice to have it. 

$$$TOE(sc, method()) gives a warning "Consider inlining/replacing this macro to make the code more readable".

It is more readable but I want to use the macro: 

set sc = method()

if ('sc) {

throw ##class(%Exception.StatusException).CreateFromStatus(sc)

}

It's just a rule to eliminate macros in my opinion :/

Other example:

Method has too many lines (93 > 50). Am I not allowed to write methods bigger 50 lines?

Method declares too many variables? Also a rule I can't understand. Sure you need to minimize but it's not always possible. 

I really like sonarlint but I can't use it at 100% because I can't disable specific rules in specific circumstances, 

Jochen Roese · Mar 8, 2019 go to post

I think that should work much better. Didn't test but that is how I would do it with CSP-Method #call / #server

It's also asynch so you browser still reacts while getting the data. 

I'm using innerHTML instead of the table-functions. innerHTML is the fastest way to render HTML actually. It's faster than jQueries $('query').html('htmlcontent');

<!--Demo of (re-)loading a table dynamically in a page-->
<html>
<head>
<title>   Cache Server Page To Demo Table Re-Render</title>
</head>
<body>
<table id="TEST" border="1">
  <thead>
    <tr>
        <td>SSN</td><td>Name</td>
    </tr>
  </thead>
  <tbody id="tablebody">
  </tbody>
</table>
<hr>
<!-- changed to call bc asynchronous -->
<input type="Button" name="render" value="Create Table"
    OnClick="#call(..renderTable())#;">
 
<script language = Cache method = renderTable arguments = "">
    #dim data = []
    #dim sql = "SELECT SSN,Name FROM Sample.Person"
    #dim rset AS %SQL.StatmentResult = ##class(%SQL.Statement).%ExecDirect(, sql)
    while (rset.%Next()) {
        d data.%Push({
            "SSN": (rset.%GetData(1)),
            "Name": (rset.%GetData(2))
        });
    }
    // create callback-function for rendering
    &js<
        function cb(data) {
            var tableBody = document.getElementById("tablebody");
            // clear tablebody
            var html = [];
            tableBody.innerHTML = html.join('');
            for (var i in data) {
                html.push('<tr><td>'+data[i].SNN+'</td><td>'+data[i].Name+'</td></tr>');
            }
            // innerHTML is way faster than using the functions from table or creating javascript objects like HTMLTableRow or innerText
            tableBody.innerHTML = html.join('');
        };
    >
    // calling the cb with data
    w !,"cb("_data.%ToJSON()_")"
</script>
         
</body>
</html>
Jochen Roese · Mar 5, 2019 go to post

Any way to suppress warnings without sonarQube?

//@SupressWarnings("cachequality:OS0001")

//@SupressWarnings("all")

or 

//NOSONAR

is not working

Jochen Roese · May 4, 2018 go to post

Hi,

this should give you an idea on how to achieve "popups" in HTML. This code is untested but it should give you a start.
First of all you need 2 containers (DIV) at the end of your document:

<div id="backdrop" class="backdrop"></div>

<div id="popup" class="popup">
    <div id="popup_container"></div>
    <button id="popup_btn1"></button>
    <button id="popup_btn2"></button>
</div>


in css you need 4 classes:

.backdrop {
    position: fixed;
    opacity: 0.3;
    background-color: rgb(0,0,0);
    top: 0;
    left: 0;
    width:100%;
    height: 100%
    display: none;
}

.backdrop.active {
    display: block;
}

.popup.active {
    display:block;
}

.popup {
    display:none;
    <!-- add your styling here -->
}

In Javascript you need something like this:

function showConfirm(message, callback) {
    showPopup(message, "Yes", "No", callback);
}

function showPopup(content, button1desc, button2desc, callback) {
    $('#popup').addClass("active");
    $('#backdrop').addClass("active");
    $('#popup_container').html(content);
    $('#popup_btn1').html(button1desc);
    if (button2desc) {
        $('#popup_btn2').html(button2desc).show();
    } else {
        //If we don't get a 2nd description it's a alert-message with one button
        $('#popup_btn2').hide();
    }
    $('#popup_btn1').off().on('click', function() {
        disable(); //First disable our popup
        if (callback) callback(0); //Returns the index of the button clicked
    });

    $('#popup_btn2').off().on('click', function() {
        disable();
        if (callback) callback(1);
    });

    var disable = function() {  
         $('#popup').removeClass("active");
         $('#backdrop').removeClass("active");
         $('#popup_container').html('');
    }
}

//Example of calling the confirm-message

showConfirm("Do you really want to delete?", function(choice) {
    if (choice===0) 
        alert("You pressed yes");
    } else {
        alert("You pressed no");
    }
});

Edit: You can achieve this also by using native-javascript: document.getElementById("popup_container").innerHTML = content; for example

Jochen Roese · Feb 28, 2018 go to post

Hei,

if you want to use Darkest-Dark theme:

Go to <eclipse-workspace>/.metadata/.plugin/org.eclipse.core.runtime/.settings/com.intersys.eclipse.studio.ui.prefs

and add this. I didn't found all colors but It's a good start. Edit theme in preferences if you find a color that you don't like or maybe isn't set by me. You can also reset to default-settings by removing every Studio_Color-Setting.

I also tweaked the colors for specific things because using the theme strictly results in too much blue ($-commands was blue etc.)

Studio_Color_BG_false=0,0,0

Studio_Color_BG_true=37,37,37

Studio_Color_brace=255,255,255

Studio_Color_bracket=255,255,255

Studio_Color_classmethodname=189,214,255

Studio_Color_classname=210,81,81

Studio_Color_collationname=189,214,255

Studio_Color_cosBitlogicOperator=210,81,81

Studio_Color_cosClassName=239,191,143

Studio_Color_cosCommandWordDeprecated=210,81,81

Studio_Color_cosCommandword=210,81,81

Studio_Color_cosDollarName=210,81,81

Studio_Color_cosDollarNameDeprecated=210,81,81

Studio_Color_cosEmbedDelim=0,128,0

Studio_Color_cosEmbeddingStartOrEnd=210,81,81

Studio_Color_cosExtrinsic=210,81,81

Studio_Color_cosGlobalname=141,203,226

Studio_Color_cosGlobalname_bold=true

Studio_Color_cosIOFormat=255,255,255

Studio_Color_cosJsonBrace=255,255,255

Studio_Color_cosJsonBracket=255,255,255

Studio_Color_cosJsonKeyword=210,81,81

Studio_Color_cosKeyword=210,81,81

Studio_Color_cosLabel=210,81,81

Studio_Color_cosLabelname=141,203,226

Studio_Color_cosLocalname=136,214,255

Studio_Color_cosMacroArgsAnything=136,214,255

Studio_Color_cosMacroCall=210,81,81

Studio_Color_cosOperator=255,255,255

Studio_Color_cosPPCommand=141,203,226

Studio_Color_cosPPFunc=210,81,81

Studio_Color_cosPattern=210,81,81

Studio_Color_cosSQLFieldName=210,81,81

Studio_Color_cosstring=255,198,0

Studio_Color_csqlIdentifier=255,198,0

Studio_Color_delim=255,255,255

Studio_Color_foreignkeyname=121,171,255

Studio_Color_htmlAttributeName=121,171,255

Studio_Color_htmlAttributeValue=255,255,255

Studio_Color_indexname=189,214,255

Studio_Color_indexpropertyname=255,255,255

Studio_Color_jsKeyword=141,203,226

Studio_Color_jsOperator=255,255,255

Studio_Color_jsString=255,198,0

Studio_Color_jsonString=255,198,0

Studio_Color_methodname=255,255,255

Studio_Color_name=255,255,255

Studio_Color_number=129,180,71

Studio_Color_parameter=121,171,255

Studio_Color_parametername=189,214,255

Studio_Color_paren=255,255,255

Studio_Color_propertyname=189,214,255

Studio_Color_queryname=189,214,255

Studio_Color_sqlstring=255,255,128

Studio_Color_storagename=189,214,255

Studio_Color_triggername=189,214,255

Studio_Color_udlDocComment=201,222,12

Studio_Color_udlKeyword=80,175,226

Studio_Color_udlMCKeywordName=255,255,255

Studio_Color_udlMCKeywordValue=129,180,71

Studio_Color_udlNumericLiteral=129,180,71

Studio_Color_udlStringLiteral=255,198,0

Studio_Color_xdataname=189,214,255

Studio_Color_xmlAttributeName=255,255,255
Jochen Roese · Nov 9, 2017 go to post

That's not garbage. It's the ZIP-File itself I think. It's in binary and compressed. You need to decompress it. 

I would do it like that:

s sc=$zf(-1, "sftp command here &>/dev/null; unzip cmd here &>/dev/null")

Jochen Roese · Aug 25, 2016 go to post

I prefer REST. 

The built-in transportation is good way for ZEN but the fact that the most plugins can't handle it well is a good reason to use REST. Some plugins just want an URL to do a simple jQuery-AJAX-Call and parsing that into a callback function. I some cases you can submit a function serving the data instead of an URL but working that around that is a bit harsh and not really comfortable in my opinion (Typeahead for example). 

Let's assume that you code a ZEN-App working with Cordova and in the Browser as well. The data comes from the built-in feature of ZEN-Mojo. Everything works fine. 

Now a new iOS or Android-Update is distributed that have new security guidelines and Cordova dies out of it (maybe some stuff in the webview are not allowed anymore but is needed). That's why I keep my data-transportation as flexible as possible. Always thinking of "This 3rd party tool is maybe not supported anymore in the future. What are my alternatives?". In this case a native app without ZEN. 

You can still use the built-in feature by calling the methods that the REST calls. You are in the CSP-Enviroment in both cases. 

Jochen Roese · Jun 2, 2016 go to post

We are using Hashtags to load the templates.  

Thats the URL for example:

www(.)mypage.com/myzenapp/mojoclass.cls#Login?r=Dashboard

or

www(.)mypage.com/myzenapp/mojoclass.cls#Dashboard

or

www(.)mypage.com/myzenapp/mojoclass.cls

Our custom-script CAJAXNavigation uses onHashChange-Callback (that we bound to zenPage.onHashChanged). There we change the layout with pop and push document. This works very well with the browser history stack. The browser manages hashtag-changes automatically.

With this concept we are changing the layout by simply clicking an anchor with href="#MyLayout"

 <mojo:documentView
 id="mainView"
ongetdata="return zenPage.getContent('data',key,criteria);"
ongetlayout="return zenPage.getContent('layout',key,criteria);"
developerMode="false"
effectsEnabled="false"
maxPanels="2"
onload="zen('mainView').setDocumentKey(CAJAXNavigation.GetInstance().GetCurrentPage() || 'Home');zen('mainView').setLayoutKey(CAJAXNavigation.GetInstance().GetCurrentPage() || 'Home')"
>

Jochen Roese · May 27, 2016 go to post

Hi Fabio,

in template dispatch mode you can have a super layout class where you can have a collection of clientmethods implemented in every layout extending from it. Our menu is initialized by every layout each time it loads. You can define a method that initialize the menuitems as active for example or load dynamic data.

I'm sure that there is a better way of handling menus with onepage-concepts. Menus in general are difficult in client oriented template systems.

We implemented a way to display two layouts in a single pane; a detail part in a modal for example. I think this technique can be used to display a dynamic-menu. Just create a menu-layout that just provide the layout by criteria-parameters. In your superclass add a method that calls this layout and injects it into a div provided by every layout. Example:

Content-Layout:

var that = this;

return {...,children:[{type:'$div',id:'menu'}], $executeCodeAfterChildren: function() {  that.initMenu({"parm":"value"}) }}

Super-Layout:

ClientMethod initMenu(view, criteria) [ language = "javascript] 

{

    var layout = zenPage.getContent("layout","Menu",criteria)

     view = view || zen('mainView');
     var menucontainer view.getComponentById("menu"); *****

    //Empty all children-elements first before refresh and add the layout

    menucontainer.$children = menucontainer.children = layout.children;

    //rerenders menu

    menucontainer.$refresh();

}

***** I added following code in createLayoutObjects before return in bootstrap-plugin to get layout-elements by id instead of index:

var mainView instance.$documentView; //zen('mainView');
if (typeof mainView._IDIndex === "undefined") {
mainView._IDIndex [];
}
if (instance && instance.id) {
mainView._IDIndex[instance.id]=instance;
}
if (!mainView.getComponentById) {
mainView.getComponentById function(id) {
return this._IDIndex[id] || null;
}
}

Jochen Roese · Apr 29, 2016 go to post

Can you post the original SQL? Maybe I can find some joins that missbehaviours. In some cases a select to a specific field in joins let the query-optimizer run the false index. My experience is that the query-opt. somehow decides to use the extend-index instead of an property-index. 

Jochen Roese · Apr 21, 2016 go to post

Ahhh. That's why I never changed a namespace with $namespace. I always used ZN

Does it revert the namespace after the method finished?

Jochen Roese · Apr 21, 2016 go to post

It's to change the namespace later back to the namespace you're comming from.

ClassMethod DoIt() As %Status
{
    //Current Namespace = "A"
    Do ..MethodThatChangesNamespace()
    //Namespace is now "B"
    Do ##class(Class).AnotherMethod()
    //Results in "NOT FOUND"
}

Edit: I don't know if "new $namespace" results in changing back the namespace. I got some problems changing namespaces in methods. Maybe it's changed since Version 2008.

Jochen Roese · Apr 21, 2016 go to post

Here is an example how you should code in ObjectScript:

ClassMethod listClasses(ns As %String = {$namespace}, projectName As %String) As %Status
{
    #dim tSC As %Status = $$$OK
    #dim tException As %Exception.StatusException = $$$NULLOREF
    #dim tOrigNS = $namespace
    try {
        // Switch namespaces to the new one
        set $namespace = ns

        // Grab our project, by name; fail otherwise
        // TODO: failing is CRUDE at this point...
        #dim project as %Studio.Project
        #dim status as %Status

        // TODO: note sure what the "concurrency" parameter is; leave the default which is -1
        set project = ##class(%Studio.Project).%OpenId(projectName,, .status)
        if ($$$ISERR(status)) {
            Throw ##class(%Exception.StatusException).CreateFromStatus(status)
        }
        #dim item as %Studio.ProjectItem

        #dim key = ""

        while (project.Items.GetNext(key)'="") {
            set key = project.Items.GetNext(key)
            set item = project.Items.GetAt(key)
            if ($IsObject(item)) {
                write "Name: " _ item.Name _ ", type: " _ item.Type, !
            }
        }
    } catch (tException) {
        Set tSC = tException.AsStatus()
    }
    set $namespace = tOrigNS
    quit tSC
}

Jochen Roese · Apr 15, 2016 go to post

Hi,

you need to re-render all components of header and footer on each layout-change. But there is a way to initialize the header and footer once and outside of the zen-pane.

In your zenPage create a ClientMethod that pushes html-code outside of the panes:

ClientMethod InitHeader(force) [ language = javascript ]
{
     if (force || !zenPage._zHeaderInit) {
        var head_html = [];
        var footer_html = [];
        head_html.push('<div id="header">');
        head_html.push('...things...')
        head_html.push('</div>');
        footer_html.push('<div id="header">...things...</div>')
        $('#zen1').html(head_html.join('') + $('#zen1').html() + footer_html.join(''));
        //init client-code here like onclick
        $('#header').find('a').each(function() {
            $(this).on('click',function() {
                //I clicked a emnu-item
            })
        });
        zenPage._zHeaderInit = true;
    }
}

In $executeCodeAfterChildren in getLayout() you can execute zenPage.InitHeader()

Jochen Roese · Mar 23, 2016 go to post

Hi Daniel,

use bootstrap and javascript. There are a lot of frameworks out there. You can use ZEN-Mojo as framework for example. I wouldn't try to work with angular.js because it's more expert-level Javascript and templating. But when you do it correctly it could be the best option out there.

Responsive apps need a lot of CSS and Javascript-Knowledge. Bootstrap gives you an idea and a good basic on how to achieve that. Maybe it's enough to redesign your old CSP-Pages to bootstrap to make it responsive enough.

The easiest way to work with an REST-API is jQuery-ajax (for http-requests in general)

I also use a Java-Class like structure for my scripts. Here is an example:

function MyClass(initParm, initListener) {
    var m_PrivateProperty = initParm || null;
    var m_EventListener = (typeof initListener === "function" ? initListener : new MyClass.OnEventListener())
    this.PublicProperty = "Hello World";
    
    this.getOnEventListener = function() {
        return m_EventListener;
    }
    this.setOnEventListener = function(EventListener) {
        m_EventListener = EventListener;
    }
    
    var privateFunc = function(parms) {
        return stuff;
    }
    this.publicFunction = function(parms) {
        return privateFunc(stuff)
    }
    
    this.getPrivateProperty = function() {
        return m_PrivateProperty;
    }
    this.setPrivateProperty = function(PrivateProperty) {
        m_PrivateProperty;
    }
    
    this.sendToServer = function() {
        var that = this;
        jQuery.ajax("/rest/do/things/", {
            method : "GET",
            asynch : true,
            data : {
                parm1 : this.getPrivateProperty()
            }
        }).done(function(a,b,c) {
            //we need "that" here. "this" is not MyClass anymore; could be jqXHR-Object or window
            that.getOnEventListener().OnThingsListener(a);
        }).error(function(a,b,c) { 
            //read jquery-doc
        })
    }
    
}
MyClass.OnEventListener = function() {
    this.OnClickListener = function(parms) { };
    this.OnThingsListener = function(parms) { };
}
 
var a = new MyClass(parm1,parm2)
Jochen Roese · Mar 17, 2016 go to post

#dim url = request.Server_":"_request.Port_"/"_request.Location

Or do you mean something else?

Jochen Roese · Mar 17, 2016 go to post

Atelier is it's own modified Eclipse IDE. It's like Android-Studio. It's based on Eclipse but it's not the same.

I think Intersystems need to code extra libs for Eclipse to get this thing to work or modify/add another repository with the needed libs as plugin. 

The repos you added is the Atelier-Executable itself. It's not a Plugin-Repository like the Android-Plugin for Eclipse.

Jochen Roese · Mar 15, 2016 go to post

The Method already was in a try and catch block. No Error. 

Well I edited the post. javac using different output-methods. Redirecting these to a file and reading the file afterwards solved my problem.

Jochen Roese · Mar 10, 2016 go to post

That should do it for both types:

ClientMethod StartEvent(
key,
eventType,
value) [ Language = javascript ]
{
if (zenPage.templateDispatchMode) {
var newArea "events-" key.split(":")[0];
if (zenPage.currArea!==newArea) {
zenPage.currArea newArea;
zenPage.loadTemplateNS(zenPage.templateDispatchBaseNamespace+"/events",key.split(":")[0],newArea);
}
}
var st zenPage.getTemplate();
st[eventType](key,value,'mainView');
}
Jochen Roese · Mar 9, 2016 go to post

As temp  solution you can use href:"javascript:zenPage.StartEvent('yourkey','onclick','yourvalue');"

In your Zenpage add following ClientMethod to call events (sometimes useful for handling zen-events with bootstrap-plugins):

ClientMethod StartEvent(
key,
eventType,
value) [ Language = javascript ]
{
var newArea "events-" key.split(":")[0];
if (zenPage.currArea!==newArea) {
zenPage.currArea newArea;
zenPage.loadTemplateNS(zenPage.templateDispatchBaseNamespace+"/events",key.split(":")[0],newArea);
}
var st zenPage.getTemplate();
st[eventType](key,value,'mainView');
}