Why not make your own DE9? - An insight into ServiceWindows and more.
Earlier today we had a meeting with one of our partners about DE9 and the future. A lot of things came up and one thing they wanted to learn more about was ServiceWindows. They had got that it was a game changer but couldn't get their head around how and what etc...
We guess that might be the same for a lot of you. However much we talk and explain and saying that DE9 is made in DE9 and it is all servicewindows etc... what does it really mean and isn't it really just salesman's s....t?
So to show them how true this is we made them a sample there and then where the entire DE9 is and editable application.
The DE9 you have seen so far is just a "meagre" bodywork around the DE9 V12 that is under it.
ServiceWindow
A service window is simply a web browser window that has full access to DEGUIAPI (DataEase GUI API) and PRISMAPI. So basically you can reach outwards to the web and use any web feature when at the same time you have full two way communication with the DE9 API's that it is built upon.
Service Windows can be dymaically sized and shown/hidden and can even be floating. If we mention that execdql() in de9 can of course be executed in a service window and can return the entire "product" i.e. list out produced in the DQL (the phone book in reverse order for instance) you kind of get the gist of it.
$('#mydiv').html(execdql('@telefonbookall')) ;
Would be the javascript way of telling DE9 to produce the phonebook and put it into the HTML div mydiv.
We won't spend too much time on all the aspects of service windows here - it is just a teaser anyhow - but there is little you can't achieve or acomplish in them when it comes to control your application.
Dataease has always lacked a top down control of an app and with service windows you have finally got this and some...
Did we mention that you have an event model which you can piggyback onto and even drive?
Anyhow as this is just a quick teaser to change you mindset we decided as I had 5 minutes free now before my head goes into a tail spin so decided to show you how easy it is to reverse engineer DE9 into JosefEase.
What I have done is simply to create a new application and copied from DATAEASE.INI into RDRRxAAA.INI the same settings and then copied the HTML files and the Static directory into the app.
And voila, you have a DE9 you can tailor to your own need.
I think a lot of people think that DE9 is just another DFW with a glitzy new paintjob, but in reality it is a glitzy new product dressed up in DE8 cloths ;-)
As you see, there is nothing we do in the GUI which is not something you cant change. The entire GUI is just a Web application on top of DEGUI API and PRISM API.
As we progress there will be tools for editing toolbars/filemenus and other service windows in situ and to develop them outright etc.
As you said earlier, the sky is the limit and it might not be a better way than to show that the entire DE9 is an application built in DE9 ;-)
http://www.dataease.com/static/files/JosefEase.zip
Here is for instance JosefEase with only one line difference in the catalog.html code… ;-)
In ./static/js/jsBridge.js you will find all the defined functions and actions.
var NEW_FORM = BASE_PLUS + 91;
var NEW_REPORT = BASE_PLUS + 92;
var NEW_MENU = BASE_PLUS + 93;
var NEW_SCRIPT = BASE_PLUS + 640;
var NEW_DBRFILE = BASE_PLUS + 641;
var OPEN = BASE_PLUS + 94;
var CLOSE = BASE_PLUS + 98;
var DELETE = BASE_PLUS + 99;
var PREVIEW = BASE_PLUS + 352;
var PRINT = BASE_PLUS + 104;
var PRINTERSETUP = BASE_PLUS + 103;
var IMPORT = BASE_PLUS + 101;
var EXPORT = BASE_PLUS + 102;
var TEST_DESIGN = BASE_PLUS + 267;
var CLOSEAPP = BASE_PLUS + 231;
var EXIT = BASE_PLUS + 107;
var POPUP_EDIT = BASE_PLUS + 116;
var UNDO = BASE_PLUS + 117;
var CUT = BASE_PLUS + 119;
var COPY = BASE_PLUS + 120;
var COPY_RECORD = BASE_PLUS + 320;
var COPY_SPECIAL = BASE_PLUS + 321;
var PASTE = BASE_PLUS + 121;
var CLEARFIELD = BASE_PLUS + 123;
var NEWRECORD = BASE_PLUS + 136;
var SAVERECORD = BASE_PLUS + 137;
var SAVEASNEWRECORD = BASE_PLUS + 158;
var DELETERECORD = BASE_PLUS + 148;
var RESTORERECORD = BASE_PLUS + 159;
var LINKS = BASE_PLUS + 125;
var POPUP_EDIT_OBJECT = BASE_PLUS + 402;
var POPUP_MULTIUSER = BASE_PLUS + 353;
var ALL_RECORDS = BASE_PLUS + 354;
var READ_RECORDS = BASE_PLUS + 355;
var NO_RECORDS = BASE_PLUS + 356;
var REFRESH = BASE_PLUS + 152;
var REFRESH_AUTO = BASE_PLUS + 151;
var REFRESH_TIME = BASE_PLUS + 357;
var REFRESH_FORM = BASE_PLUS + 423;
var RETRIEVE_DEF_FIELD = BASE_PLUS + 651;
var RETRIEVE_DEF_RECORD = BASE_PLUS + 652;
var SAVE_DEF_RECORD = BASE_PLUS + 653;
var DELETE_DEF_RECORD = BASE_PLUS + 654;
var TABLE_GRID_DISPLAY = BASE_PLUS + 655;
var POPUP_VIEW = BASE_PLUS + 128;
var FORMVIEW = BASE_PLUS + 130;
var LISTVIEW = BASE_PLUS + 131;
var NOFILTERING = BASE_PLUS + 143;
var FILTERING = BASE_PLUS + 142;
var POPUP_VIEW_ZOOM = BASE_PLUS + 358;
var ZOOM_NORMAL = BASE_PLUS + 359;
var ZOOM_IN = BASE_PLUS + 370;
var ZOOM_OUT = BASE_PLUS + 371;
var ZOOM_FILL = BASE_PLUS + 372;
var ZOOM_CUSTOM = BASE_PLUS + 373;
var TOOLBAR = BASE_PLUS + 211;
var TABBAR = BASE_PLUS + 282;
var MENUBAR = BASE_PLUS + 283;
var STATUSBAR = BASE_PLUS + 212;
var CATALOG = BASE_PLUS + 264;
var SQL = BASE_PLUS + 311;
var POPUP_GOTO = BASE_PLUS + 135;
var FIRSTRECORD = BASE_PLUS + 140;
var PREV_PG = BASE_PLUS + 269;
var PREVIOUSRECORD = BASE_PLUS + 139;
var NEXTRECORD = BASE_PLUS + 138;
var NEXT_PG = BASE_PLUS + 268;
var LASTRECORD = BASE_PLUS + 141;
var RELATEDFORM = BASE_PLUS + 149;
var RETURNTOPARENT = BASE_PLUS + 160;
var LOOKUP = BASE_PLUS + 150;
var RETURNDATA = BASE_PLUS + 157;
var DONE = BASE_PLUS + 360;
var POPUP_QUERY = BASE_PLUS + 374;
var SETFILTERS = BASE_PLUS + 144;
var SETORDER = BASE_PLUS + 146;
var ASCENDING = BASE_PLUS + 154;
var DESCENDING = BASE_PLUS + 155;
var DATAFILTER = BASE_PLUS + 132;
var DATAMODEL = BASE_PLUS + 156;
var CLEARFILTERS = BASE_PLUS + 145;
var CLEARORDER = BASE_PLUS + 147;
var POPUP_APPLICATION = BASE_PLUS + 228;
var USERS = BASE_PLUS + 238;
var RELATIONSHIPS = BASE_PLUS + 232;
var CUSTOM_FUNCTIONS = BASE_PLUS + 233;
var DATABASE_LINKS = BASE_PLUS + 234;
var RELATIONDIAG = BASE_PLUS + 235;
var POPUP_APP_UTILITIES = BASE_PLUS + 375;
var REORG = BASE_PLUS + 243;
var BACKUP = BASE_PLUS + 376;
var RESTORE = BASE_PLUS + 242;
var INSTALL_APP = BASE_PLUS + 244;
var LOCKAPP = BASE_PLUS + 241;
var UNLOCKAPP = BASE_PLUS + 377;
var INSTALL = BASE_PLUS + 424;
var RENAMEAPP = BASE_PLUS + 245;
var POPUP_APP_STATUS = BASE_PLUS + 378;
var APPSTAT_RECINFO = BASE_PLUS + 379;
var APPSTAT_SERVINFO = BASE_PLUS + 380;
var APPSTAT_DOCINFO = BASE_PLUS + 381;
var APPSTAT_IMPORTINFO = BASE_PLUS + 382;
var APPSTAT_TABLEINFO = BASE_PLUS + 642;
var APPSTAT_ACTINFO = BASE_PLUS + 639;
var APPSTAT_DQLINFO = BASE_PLUS + 643;
var APPSTAT_OMLINFO = BASE_PLUS + 644;
var APPSTAT_OBJINFO = BASE_PLUS + 645;
var APPSTAT_BRLINFO = BASE_PLUS + 646;
var APPSTAT_RNGINFO = BASE_PLUS + 647;
var APPSTAT_REFRESHINFO = BASE_PLUS + 648;
var APPSTAT_DELETEINFO = BASE_PLUS + 649;
var PREDEFINED_PRINTERS = BASE_PLUS + 871;
var PREFERENCES = BASE_PLUS + 240;
var POPUP_WINDOW = BASE_PLUS + 258;
var TILEHORIZ = BASE_PLUS + 260;
var TILEVERT = BASE_PLUS + 259;
var CASCADE = BASE_PLUS + 261;
var ARRANGE = BASE_PLUS + 262;
var CLOSEALL = BASE_PLUS + 263;
var POPUP_HELP = BASE_PLUS + 247;
var HELP_INDEX = BASE_PLUS + 248;
var HELP_DESKTOP = BASE_PLUS + 249;
var HELP_MENUS = BASE_PLUS + 250;
var HELP_TOOLBAR = BASE_PLUS + 251;
var HELP_HOWTO = BASE_PLUS + 252;
var HELP_GLOSSARY = BASE_PLUS + 253;
var HELP_ONLINE = BASE_PLUS + 255;
var USER_HELP = BASE_PLUS + 280;
var ABOUTDATAEASE = BASE_PLUS + 254;
var CHANGE_KEY = BASE_PLUS + 281;
var SAVE = BASE_PLUS + 96;
var SAVEAS = BASE_PLUS + 97;
var STYLE_SAVEAS = BASE_PLUS + 225;
var TEST_RUN = BASE_PLUS + 266;
var REDO = BASE_PLUS + 118;
var PASTELINK = BASE_PLUS + 124;
var PASTE_SPECIAL = BASE_PLUS + 126;
var CLEAR = BASE_PLUS + 122;
var POPUP_EDIT_ALIGN = BASE_PLUS + 193;
var RIGHTEDGES = BASE_PLUS + 194;
var LEFTEDGES = BASE_PLUS + 195;
var HORIZCENTER = BASE_PLUS + 196;
var TOPEDGES = BASE_PLUS + 197;
var BOTTOMEDGES = BASE_PLUS + 198;
var VERTCENTER = BASE_PLUS + 199;
var GRIDSNAP = BASE_PLUS + 216;
var POPUP_EDIT_SIZE = BASE_PLUS + 383;
var HORIZONTAL = BASE_PLUS + 200;
var VERTICAL = BASE_PLUS + 201;
var BOTH = BASE_PLUS + 202;
var SELECTALL = BASE_PLUS + 127;
var FIND = BASE_PLUS + 630;
var REPLACE = BASE_PLUS + 633;
var FIND_NEXT = BASE_PLUS + 631;
var FIND_PREV = BASE_PLUS + 632;
var COLOR = BASE_PLUS + 219;
var LAYOUT = BASE_PLUS + 129;
var ACTION = BASE_PLUS + 220;
var FONT = BASE_PLUS + 218;
var DEFINE = BASE_PLUS + 400;
var TEXT = BASE_PLUS + 401;
var DOCUMENT = BASE_PLUS + 275;
var PROCEDURE = BASE_PLUS + 307;
var HEADER = BASE_PLUS + 276;
var FOOTER = BASE_PLUS + 277;
var DATAENTRY = BASE_PLUS + 384;
var OUTLINES = BASE_PLUS + 213;
var LABELING = BASE_PLUS + 385;
var RULERS = BASE_PLUS + 214;
var GRIDS = BASE_PLUS + 215;
var GRIDOPTIONS = BASE_PLUS + 217;
var POPUP_OBJECTS = BASE_PLUS + 386;
var TEXT_OBJ = BASE_PLUS + 168;
var FIELD_OBJ = BASE_PLUS + 167;
var SUBFORM_OBJ = BASE_PLUS + 166;
var BUTTON_OBJ = BASE_PLUS + 169;
var PICTURE_OBJ = BASE_PLUS + 170;
var LINE_OBJ = BASE_PLUS + 171;
var RECTANGLE_OBJ = BASE_PLUS + 172;
var ELLIPSE_OBJ = BASE_PLUS + 173;
var VARIABLE_OBJ = BASE_PLUS + 174;
var SUMMARY_OBJ = BASE_PLUS + 176;
var GRAPH_OBJ = BASE_PLUS + 387;
var OLE_OBJ = BASE_PLUS + 388;
var CUSTOM_OBJ = BASE_PLUS + 175;
var IMAGE_FLD_OBJ = BASE_PLUS + 389;
var CHECK_FLD_OBJ = BASE_PLUS + 390;
var LIST_FLD_OBJ = BASE_PLUS + 391;
var RADIO_FLD_OBJ = BASE_PLUS + 392;
var SPIN_FLD_OBJ = BASE_PLUS + 393;
var POPUP_STYLE = BASE_PLUS + 221;
var TABOBJ_OBJ = BASE_PLUS + 927 ;
var WEB_FLD_OBJ = BASE_PLUS + 929 ;
var AWEB_FLD_OBJ = BASE_PLUS + 930 ;
var HTMLED_FLD_OBJ = BASE_PLUS + 931 ;
var MULTIBOX_FLD_OBJ = 21948 ;
var STYLE_CREATE = BASE_PLUS + 222;
var STYLE_UPDATE = BASE_PLUS + 223;
var STYLE_DELETE = BASE_PLUS + 224;
var STYLE_APPLY = BASE_PLUS + 310;
var POPUP_DOCUMENT = BASE_PLUS + 394;
var FORMUSAGE = BASE_PLUS + 300;
var PRTSPEC = BASE_PLUS + 302;
var SECURITY = BASE_PLUS + 304;
var P_DATAMODEL = BASE_PLUS + 301;
var SET_TABS = BASE_PLUS + 305;
var CLEAR_TABS = BASE_PLUS + 306;
var PERFORMANCE = BASE_PLUS + 395;
var CUSTMENU = BASE_PLUS + 303;
var CUSTTOOLBAR = BASE_PLUS + 396;
var HELP_SEARCH = BASE_PLUS + 397;
var HELP_DQL = BASE_PLUS + 398;
var POPUP_SCRIPT = BASE_PLUS + 399;
var COMPILE = BASE_PLUS + 650;
var POPUP_PICK_LISTS = BASE_PLUS + 410;
var PICKLISTS = BASE_PLUS + 411;
var COMMANDS = BASE_PLUS + 412;
var SQL_COMMANDS = BASE_PLUS + 413;
var FUNCTIONS = BASE_PLUS + 414;
var OPERATORS = BASE_PLUS + 415;
var DOCUMENTS = BASE_PLUS + 416;
var TABLES = BASE_PLUS + 417;
var COLUMNS = BASE_PLUS + 418;
var S_RELATIONSHIPS = BASE_PLUS + 419;
var KEYPAD = BASE_PLUS + 420;
var ALPHABETIC = BASE_PLUS + 421;
var OPEN_TEXTFILE = BASE_PLUS + 600;
var SAVE_TEXTFILE = BASE_PLUS + 602;
var S_NEW_SCRIPT = BASE_PLUS + 422;
var S_PREFERENCES = BASE_PLUS + 425;
var HISTORY_NEXT = BASE_PLUS + 8992;
var HISTORY_PREV = BASE_PLUS + 8993;
var POPUP_FILE_FRAME = BASE_PLUS + 227;
var NEWAPP = BASE_PLUS + 229;
var OPENAPP = BASE_PLUS + 230;
var DELETEAPP = BASE_PLUS + 246;
var INST_OPTIONS = BASE_PLUS + 426;
var STYLES_LISTBOX = BASE_PLUS + 799;
var SCRIPT = BASE_PLUS + 721;
var SCRIPT_METHOD_NEXT = BASE_PLUS + 710;
var SCRIPT_METHOD_PREVIOUS = BASE_PLUS + 711;
var SCRIPT_METHOD_OPTIONS = BASE_PLUS + 712;
var BROWSER = BASE_PLUS + 713;
var OBJECTS = BASE_PLUS + 714;
var PROPS = BASE_PLUS + 715;
var CLASSES = BASE_PLUS + 716;
var PROCS = BASE_PLUS + 717;
var METHODS = BASE_PLUS + 718;
var EVENTS = BASE_PLUS + 719;
var TEMPLATES = BASE_PLUS + 720;
var RENAME_OBJECT = BASE_PLUS + 722;
var START_FIELD_DEFN = BASE_PLUS + 723;
var SE_ADD_REFRESH = BASE_PLUS + 724;
var SE_DELETE_REFRESH = BASE_PLUS + 725;
var RD_CREATE = BASE_PLUS + 726;
var RD_BROWSE = BASE_PLUS + 727;
var EXECUTE = BASE_PLUS + 800;
var EXPRESSION = BASE_PLUS + 801;
var ADDFILTER_AND = BASE_PLUS + 802;
var ADDFILTER_OR = BASE_PLUS + 803;
var FIRSTRECORD_P = BASE_PLUS + 804;
var PREVIOUSRECORD_P = BASE_PLUS + 805;
var NEXTRECORD_P = BASE_PLUS + 806;
var LASTRECORD_P = BASE_PLUS + 807;
var PREV_PG_P = BASE_PLUS + 808;
var NEXT_PG_P = BASE_PLUS + 809;
var CLEARDATAFILTER = BASE_PLUS + 810;
var ZOOM_TO = BASE_PLUS + 811;
var ZOOM_BY = BASE_PLUS + 812;
var ZOOM_PREVIOUS = BASE_PLUS + 813;
var ZOOM_FILL_HEIGHT = BASE_PLUS + 814;
var ZOOM_FILL_WIDTH = BASE_PLUS + 815;
var OPEN_MENU = BASE_PLUS + 816;
var OPEN_FORM = BASE_PLUS + 817;
var OPEN_REPORT = BASE_PLUS + 818;
var OPEN_PROCEDURE = BASE_PLUS + 819;
var BANDHEADER = BASE_PLUS + 820;
var BANDFOOTER = BASE_PLUS + 821;
var OBJECTPALETTE = BASE_PLUS + 822;
var ACTIVEDOCSTATE = 30005;
var ACTIVEDOCTYPE = 30006 ;
var DESELECT_OBJ = 7000;
var ALLBAR = 30008;
var GETBARSTATUS = 30009; // A2 String: TABBAR,STATUSBAR,TOOLBAR,MENUBAR,ALLBARS
var SORTASCENDING = 30011; // SortAscebding/SortDescending (sortCommand) are implemented for call from Service Window. Usage: jsActionExt("30011", sortString)/ jsActionExt("30012", sortString)
var SORTDESCEDING = 30012; // SortAscebding/SortDescending (sortCommand) are implemented for call from Service Window. Usage: jsActionExt("30011", sortString)/ jsActionExt("30012", sortString)
var OPENTABLE = 21942 ;
var OPTENTABLELIST = 21943 ;
var QUERYSELECTFIELDS = 21944 ; // Switch To Field Select Mode
var SETSTYLE=30002 ; //DT
var GETALLWINDOWTITLES = 31000 ;
var GETSTYLESFROMSELECTED = 31001 ;
var SWITCHWINDOW = 21946 ; // A2 WindowID ref
var CLOSEWINDOW = 21947 ; // A2 WindowID ref Close Window indicated by WindowHandle (A2)
var GETPOSFROMSELECTED = 31002 ; //Return JSON for Postion of Active/Selected object
var GETLICENSE = 31005 ; //used to get and register a license when no license exists
var CHECKLICENSE = 31006 ; // used to check for roaming conflicts, will popover the LoginRoaming.html when conflict is detected
var TAKELICENSE = 31007 ; //used to take back the licenses for roaming user and is called from LoginRoaming.html
var OPENAPPDIALOG = 31009 ; // for opening a app dialog implemented. Takes no parmeters or 1 paremeter with start folder.
var GETSTYLENAMES = 31010 ; //return a json array with all styles that can be set in the application.
var NOTIFYSERVICEWINDOW = 310111 ; //
var REGISTERNEWUSER = 31012 ; // The first uses https://license.dataease.com/licensecheck/newuser/?& with input json sting with username : email and password : password. It will set a retruned trial key as the license on return if email not used before and json Result : "ok". If not Result : "fail"
var RESETPASSWORD = 31013 ; // The second asks for reset password https://license.dataease.com/licensecheck/resetpassword/?& with string parameter for the email address to send the reset link to. If email found Result : "ok" else Result : "fail"
var GETOBJECTINFO = 31014 ; // Not to be used directly, use via GetCurrent()
var GETCURRENTOBJECTSTRING = 31015 ;// Not to be used directly, use via GetCurrent()
var GETCURRENTFILTER = 31016 ; // get the current filter of Active Document.
Here you can see how they are used in a toolbar.
<div id="tb0001" title="Go to Design View" onclick='jsAction(TEST_DESIGN);'><i class="fa fa-object-group" aria-hidden="true" ></i></div>
<div id="tb0002" class="fa fa-hover saction" title="Save current record(s)" onclick='jsAction(SAVERECORD)'><i class="fa fa-save"></i></div>
The icons are picked from FontAwsome, you can of course use anything you want but in the code we support font-awesome with different hover and click classes etc, so you will get animation etc (all this is easy to make to be honest) ;-)
https://fontawesome.com/v4.7.0/icons/
Font awesome 4.7 is the one included so you can use anything you find in the website directly with result.
FileMenu is equally simple.
<style>
.center {
display: block;
margin-left: auto;
margin-right: auto;
width: 67%;
}
</style>
<img src="./static/images/dataease9.png">
<!-- This is a sample of a menu ITEM with SubMenu.-->
<li >
<a href="#" ><i class="menu-icon mdi mdi-file"></i><span>File</span><span class="menu-arrow fa fa-angle-down"></span></a>
<ul>
<li><a href="#" onClick="jsActionS2(NEW_FORM);">New</a></li>
<li><a href="#" onClick="jsActionS2(OPEN);">Open... <small>(CTRL+O)</small></a></li>
<li ><a href="#" onClick="jsActionS2(CLOSE);">Close</a></li>
<li style="border-bottom:solid 1px grey;"><a href="#" onClick="jsActionS2(DELETE);">Delete...</a></li>
<li ><a href="#" onClick="jsActionS2(PRINT);">Print... <small>(CTRL+P)</small></a></a></li>
<li style="border-bottom:solid 1px grey;"><a href="#" onClick="jsActionS2(PRINTERSETUP);">Print Setup...</a></li>
<li ><a href="#" onClick="jsActionS2(IMPORT);">Import... <small>(CTRL+I)</small></a></a></li>
<li style="border-bottom:solid 1px grey;"><a href="#" onClick="jsActionS2(EXPORT);">Export... <small>(CTRL+E)</small></a></li>
<li style="border-bottom:solid 1px grey;"><a href="#" onClick="jsActionS2(TEST_DESIGN);">Designer View <small>(F4)</small></a></li>
<li ><a href="#" onClick="jsActionS2(CLOSEAPP);">Close Application</a></li>
</ul>
</li>
<!-- This is a sample of a menu ITEM without submenu.-->
<li >
<a href="#" onClick='jsDocumentOpen("*")'><i class="menu-icon mdi mdi-file-document-box"></i><span>Document</span></a>
I cant remember why I use the jsActionS2 function rather than jsAction but most likely some early problem that I worked around. Pretty sure jsAction would do the trick now.
Here we use mdi (material design icons)
https://material.io/resources/icons/?style=baseline
This should keep you occupied through the weekend…. ;-)
Re:Why not make your own DE9? - An insight into ServiceWindows and more.
Ahh... you wondered why your sample is not black?
Just add this line in the header of your Catlog.html
<link rel="stylesheet" href="./static/assets/styles/style-black.css">
Like this...
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=yes">
<meta name="description" content="">
<meta name="author" content="">
<title>DataEase Professional</title>
<!-- Main Styles-->
<link rel="stylesheet" href="./static/assets/styles/style.css">
<link rel="stylesheet" href="./static/assets/styles/style-black.css">
Re:Re:Why not make your own DE9? - An insight into ServiceWindows and more.
will try ;)
every operating system and even processors (now) has the tool to stop infinite recursion btw ;)
also will try to recollect in my mind that recurrent language (with reverse polish notation) ..known from the times of DOS
... Forth ...