02
Sat, Nov
2 New Articles

TechTip: Dynamic Menu Using Tree Data Structure

Typography
  • Smaller Small Medium Big Bigger
  • Default Helvetica Segoe Georgia Times

This method for deploying menus uses only three objects to represent as many menus as needed. And menus can be changed by editing the file's records, instead of the code.

 

A menu is a list of options from which the user makes a selection. Each option is a brief description of the job that will be run when the user makes that selection. An option can lead to a program or to another menu of options. In IBM i, a menu consists of one display file, one message file, and one *MENU object [1]. In the IBM i environment, the display file contains the menu image, the message file contains the commands, and the *MENU object contains the name of the display file and the message file. In order to create one menu, we have to create a source file for the specified menu, define prompts for the menu image, define the command source for the menu, and finally save and compile the menu and command sources. If we want to change the menu, we have to reedit the code and recompile objects. This method is inconvenient if there's a large amount of menus, if we need to change options, or even if we want to avoid editing code.

  

Here, we present an alternative method for deploying menus in IBM i. All menus in our system can be stored in one DDS file and displayed by an array-subfile program. Each menu is stored as a tree-like form in the DDS file. Thus, the Dynamic Menu program can assign a menu with its options and can be easily navigated.

Graph and Tree Data Structure Theory

The Tree Data Structure (T-DS) is one of the most powerful data structures; it's often used in advanced tasks such as AI and compiler design [2, 3, 4]. Rooted trees can be used to store data in the computer's memory in many different ways. Unlike array, linked list, stack, and queue, which are linear data structures, tree is a hierarchical data structure. But what exactly is a tree? A graph is considered a set of vertices/nodes, which represent objects, data, or even operations, and edges/links, which represent links between the nodes.

 

A tree is a special kind of graph that follows a particular set of rules and definitions (Figure 1):

  • ConnectedA graph can be a tree if it is connected. Each node is connected with a link to at least one other node.
  • AcyclicA graph can be a tree if is acyclic. That means there's only one route from any node to any other node.
  • Root: The term root commonly refers to a top-most node. In Figure 1, node F is the root of the tree.
  • DescendantA descendant is a node that is farther away from the root than some other node. The term descendant is always in reference to another node. In Figure 1, nodes I and H are descendants of node G.
  • ParentParent is considered the node that is closer to the root node by one link or vertex. In Figure 1, node B is the parent of nodes A and D.
  • SiblingSibling nodes share the same parent. In the example, nodes A and D are siblings.
  • AncestorAn ancestor is any node between a given node and the root, including the root. In the example, the ancestors of node H are nodes I, G, and F.
  • Leaf or Terminal NodeA node is terminal if it has no children. In the example, node C is a leaf.
  • HeightThe height of a tree is defined as the number of vertices traversed to get to the most distant node. In Figure 1, the height of the tree is equal to three.

 

122013KarkavitsasFigure1

Figure 1: This is an example of a tree data structure.

Dynamic Menu

In menus, information naturally forms a hierarchy; objects are ordered "above" or "below" other objects. Tree data structure is a very efficient way to represent this type of information. In the problem at hand, each menu is a rooted tree. Root can represent the base menu while descendants of the nearest lower level can represent the options of the base menu. In this TechTip, nodes represent menu's options and new sub-menus, while leafs represent programs.

  

To store information in a hierarchical manner, a DDS file with the following fields will be used. Each record in this file represents one vertex (node or leaf) of the tree.

  • DYNFUNCT (not unique key)Since Dynamic Menu is designed to hold all of our system's root menus, we need a field to classify the records and assign them to a specific root menu. This segregation can be done based upon this field.
  • DYNSTYPEThis field holds the record's type. A record can be either node type (new sub-menu) or leaf type (program to be called or command).
  • DYNSCODEThis is the record's code ID. If this record is a leaf type record, it holds the name of the program that will be called. If this record is a node record, it holds the name of the new sub-menu.
  • DYNCFROMThis field displays the node (menu or sub-menu) in which this record belongs. In other words, this field holds the code ID of this record's parent node.
  • DYNLEVELEach record has a level. For example, root record belongs to the first level.
  • DYNSDESC This field is the option's brief description. If the record is a root menu or sub-menu, this description is shown as screen header.
  • DYNSSORTThis is for the menu options order. For example, the record with sort value equal to 2 will be displayed higher than its sibling record with sort value equal to 5.

  

Listing 1 shows an example of the DDS file code. Of course, the file and the logic can be expanded to deal with authority issues or to call leaf programs with additional input parameters, commands, etc. See the example data displayed in Listing 2.

 

     A         R DYN0001                   TEXT('Menu Tree file')

     A           DYNSCODE     10A         TEXT('Screen Code (NAME)')

     A           DYNCFROM     10A         TEXT('Called From')

     A           DYNLEVEL       1S 0       TEXT('Screen Level')

     A           DYNSTYPE       1A         TEXT('Screen Type')

     A           DYNSDESC     50A         TEXT('Screen Description')

     A           DYNPARAM       1S 0       TEXT('Program Parameters')

     A           DYNSSORT       3S 0       TEXT('Program Sort List')

     A           DYNFUNCT     10A         TEXT('Calling Function')

Listing 1: DDS file code

 

 

DYNSCODE  DYNCFROM DYNLEVEL DYNSTYPE DYNSDESC       DYNPARAM DYNSSORT DYNFUNCT APSMN01                 1       N     Root menu          0         1     950030

PGMNAME1   APSMN01       2       L     Leaf program 1     0         5     950030

APSMN02    APSMN01       2       N     Sub-Menu 1         0         6     950030

PGMNAME2   APSMN01       2       L     Leaf program 2     0         1     950030

PGMNAME3   APSMN01       2       L     Leaf program 3     0         2     950030

APSMN03   APSMN01       2       N     Sub-Menu 2         0         4     950030

APSMN05   APSMN03       3       N     Sub-Menu 2.1       0         1     950030

PGMNAME4   APSMN03       3       L     Leaf program 4     0         7     950030

PGMNAME5   APSMN05       4       L     Leaf program 5     0         1     950030

PGMNAME6   APSMN05       4       L     Leaf program 6     0         2     950030

PGMNAME7   APSMN05       4       L     Leaf program 7     0         3     950030

PGMNAME8   APSMN05       4       L     Leaf program 8     0         4     950030

Listing 2: Example of file's data

 

The program that manipulates the file's data is in essence an array-subfile program [5]. The dynamic menu (DMenu) program uses one main array as a pool and one screen array to fill the screen subfile. Initially, all records related to the root menu are loaded in a main array. Each time, the dynamic menu program reads the appropriate records from the main array and creates a subfile of output records via the screen array. When the entire subfile is written, the program sends the entire subfile to the display device [6]. The flow diagram is displayed in Figure 2. Please note that this TechTip is not intended to explain how an array-subfile program works.

 

122013KarkavitsasFigure2

Figure 2: Dynamic menu flow diagram

 

As mentioned before, the dynamic menu can be used to display all menus in a system. Thus, DMenu should be called with at least one input parameter (of course, entry parameters can be expanded to return errors or messages to the previous program, etc.) in order to select only the records that are needed for the specified root menu.

 

Two basic arrays are used. Initially, all records related with the root menu are loaded in the main array. In addition, all option records related with a sub-menu (or root menu) are loaded to the screen array in order to be displayed on screen. The options from the screen array are loaded to the screen subfile. The screen heading is loaded from the description of the submenu's (level one) root record. An example of the arrays definition is shown in Listing 3.

  

     * Work Array for Main File

     D I               S             5I 0 Inz(*Zeros)

     D SavI           S             5I 0 Inz(*Zeros)

     D WrkMenu         DS                 QUALIFIED

     D ArrAll                       81A   DIM(32676)

     D MenCode                             Overlay(ArrAll)

     D                                    Like(DYNSCODE)

     D MenFrom                             Overlay(ArrAll:*Next)

     D                                     Like(DYNCFROM)

     D MenSort                             Overlay(ArrAll:*Next)

     D                                    Like(DYNSSORT)

     D MenLeve                             Overlay(ArrAll:*Next)

     D                                     Like(DYNLEVEL)

     D MenType                             Overlay(ArrAll:*Next)

     D                                     Like(DYNSTYPE)

     D MenDesc                             Overlay(ArrAll:*Next)

     D                                     Like(DYNSDESC)

     D MenI                               Overlay(ArrAll:*Next)

     D                                     Like(I)

     D MenPara                       1S 0 Overlay(ArrAll:*Next)

     * Work Array for Screen fields

     D SI             S             5I 0 Inz(*Zeros)

     D SavSI           S             5I 0 Inz(*Zeros)

     D WrkScrn         DS                 QUALIFIED

     D ArrSAll                       68A   DIM(32676)

     D ScrSort                             Overlay(ArrSAll)

     D                                     Like(DYNSSORT)

     D ScrSI                               Overlay(ArrSAll:*Next)

     D                                    Like(SI)

     D ScrDesc                             Overlay(ArrSAll:*Next)

     D                                     Like(DYNSDESC)

     D ScrCode                             Overlay(ArrSAll:*Next)

     D                                    Like

(DYNSCODE)

Listing 3: Main and Screen arrays definition in D-spec

 

When a user selects an option, the program will check the field that shows the type (DYNTYPE) of the corresponding record to see if the option is a node (value 'N') or a leaf (value 'L'). When the option is a leaf, DMenu calls the program whose name appears in the code ID field (DYNSCODE) of the option's corresponding record. On the other hand, if the option is a node, screen array is reloaded with root record equal to the corresponding record of the user's option.

  

Let's look at the following example, which is based on the data of Listing 2. Call the dynamic menu with the appropriate input value (Listing 4):

 

CALL DYNMENU PARM('950030')

Listing 4: Calling the dynamic menu

 

All records from the DDS file are copied to the main array. This is happening because the DYNFUNCT field value is equal to 950030 in all records. Thus, all records in the DDS file belong to only one root menu. The root record's description is displayed in the screen's header, while the records that are assigned to the root menu (e.g., rrn: 2 to 6, DYNCFROM = "APSMN01") are passed to the screen array. The screen array is sorted by the DYNSSORT field. The screen subfile is filled by the screen array (Figure 3).

 

122013KarkavitsasFigure3 

Figure 3: Root menu

 

By selecting option 3, the procedure is repeated. The description of the Sub-Menu 2 is displayed in the screen's header, while the records that are assigned to this sub-menu (rrn: 7, 8) are passed to the screen array. The screen array is sorted by the DYNSSORT field, and it fills the screen's subfile (Figure 4).

 

122013KarkavitsasFigure4

Figure 4: Sub-Menu 2

 

When the user presses F12-Cancel, the program searches the main array for the corresponding record of the Sub-Menu 2 node. That is, it searches the record with a DYNSCODE value equal to APSMN03, which is the code ID of the Sub-Menu 2 node. The new menu is defined by the DYNCFROM value. The root menu screen is diplayed again (Figure 3).  

Dynamic Menu Code

Of course, there are many ways to implement the code of a dynamic menu. The following snippets of code constitute a simple DMenu creation example. 

 

As mentioned before, initially the main array must be loaded with all the root menu's related records. Listing 5 shows a code snippet for loading the main array from the file, where variable InpEntry is the program’s input parameter (e.g., 950030) and DYN00L4 is a logical file with one key (DYNFUNCT). The code ID of the root menu record is stored in the FirstScreen global variable.

 

     P LoadMainA       B

     D                 PI

 

     C                   Clear                   I

     C                   Clear                   SavI

     C                   Clear                   WrkMenu

     C                   Clear                   FirstScreen

     C     InpEntry     SetLL     DYN000L4

     C                   DoU       %EoF(DYN000L4) Or InpEntry <> DYNFUNCT

     C                   Read     DYN000L4

     C                   If       Not %EoF(DYN000L4) And

     C                             InpEntry = DYNFUNCT

     C                   If       DYNLEVEL = 1

     C                   Eval     FirstScreen = DYNSCODE

     C                  EndIf

     C                   Eval     I = I + 1

     C                   Eval     WrkMenu.MenCode(I) = DYNSCODE

     C                   Eval     WrkMenu.MenFrom(I) = DYNCFROM

     C                   Eval     WrkMenu.MenSort(I) = DYNSSORT

    C                   Eval     WrkMenu.MenLeve(I) = DYNLEVEL

     C                   Eval     WrkMenu.MenType(I) = DYNSTYPE

     C                   Eval     WrkMenu.MenDesc(I) = DYNSDESC

     C                   Eval     WrkMenu.MenPara(I) = DYNPARAM

     C                   Eval     WrkMenu.MenI(I)   = I

     C                   EndIf

     C                   EndDo

     C                   Eval     SavI = I

 

     P   

E

 

Listing 5: Load Main array example.

 

The screen array's loading procedure can be called with the menu's code ID as an input parameter (e.g., FirstScreen variable). This procedure is divided in two sections (Listing 6). The first section is responsible for filling the screen array if the input node is a root node, while the second section is responsible for filling the screen array in every other case. At the end, the screen array is sorted by the DYNSSORT file's sort field. In addition, a fold/unfold indicator is used to leave a blank between the menu's options. If the menu doesn't have many options (e.g., '7' in this example), then this indicator goes *On and the subfile displays the options with a blank record between them (Figure 3).

 

     P LoadArray       B

     D                 PI                 Like(SI)

     D InpFrom                             Like(DYNSCODE) Const

     * Local Variables

     D WrkLevel       S                   Like(DYNLEVEL)

     D                                     Inz(*Zeros)

     D TemLevel       S                   Like(DYNLEVEL)

     D                                     Inz(*Zeros)

     D WrkName         S                   Like(DYNSCODE)

     D                                     Inz(*Blanks)

     D TemName         S                   Like(DYNSCODE)

     D                                     Inz(*Blanks)

     D WrkI           S                  Like(I)

     D WrkSI           S                   Like(SI)

 

     C                   Clear                   SI

     C                   Clear                   SavSI

     C                   Clear                   WrkSI

     C                   Clear                   WrkScrn

     C                   Clear                   WrkI

     C                   Clear                   WrkName

     C                   Clear                   TemName

     C                   Clear                   FoldR

      * Check if Init

     C                   Select

     C                   When     InpFrom = *Blanks

     *         Sort By Level (Care only for Level 1)

     C                   SortA     %SUBARR(WrkMenu.MenLeve:1:SavI)

     C                   Eval     WrkLevel = 1

     C                   DoU       WrkLevel <> TemLevel

     C                   Eval     WrkI = WrkI + 1

     C                   Eval     TemLevel = WrkMenu.MenLeve(WrkI)

     C                   If       TemLevel = WrkLevel

     C                  Eval     SI = SI + 1

     C                   Eval     WrkScrn.ScrSI(SI) = SI

     C                   Eval     WrkScrn.ScrDesc(SI) = WrkMenu.MenDesc(WrkI)

     C                   EndIf

     C                   EndDo

     C                  Eval     SavSI = SI

     C                   Other

     C                   If       SavI > 0

     *         Sort By Name (Code)

     C                   SortA     %SUBARR(WrkMenu.MenFrom:1:SavI)

     *         Find Name (Code) Line

     C                  Eval     WrkI = %LookUp(InpFrom:WrkMenu.MenFrom:1:

     C                                           SavI)

     C                   If       WrkI > 0

     C                   Eval     WrkName = InpFrom

     C                   DoU       WrkName <> TemName

     C                   Eval     TemName = WrkMenu.MenFrom(WrkI)

     C                   If       TemName = WrkName

     C                   Eval     SI = SI + 1

     C                   Eval     WrkScrn.ScrDesc(SI) = WrkMenu.MenDesc(WrkI)

     C                   Eval     WrkScrn.ScrCode(SI) = WrkMenu.MenCode(WrkI)

     C                   Eval     WrkScrn.ScrSort(SI) = WrkMenu.MenSort(WrkI)

     C                   EndIf

     C                   Eval     WrkI = WrkI + 1

     C                  EndDo

     C                   Eval     SavSI = SI

     C                   EndIf

     C                   EndIf

     C                   EndSl

     C                   If       SavSI > 0

     C                   SortA     %SUBARR(WrkScrn.ScrSort:1:SavSI)

     C                   For       WrkI = 1 to SavSI

     C                   Eval     WrkScrn.ScrSI(WrkI) = WrkI

     C                   EndFor

     C                   If       SavSI > 7

     C                   Eval     FoldR = *Off                                

     C                   Else

     C                   Eval     FoldR = *On                                

     C                   EndIf

     C                   EndIf

     C                   Eval     SavCurrPGM = InpFrom

     C                   Return   SavSI

 

     P                

E

Listing 6: Load Screen array

 

It must be noted that the input record's code ID is stored in the SavCurrPGM global variable.  

  

Another important procedure is the Get Previous Sub-Menu procedure (Listing 7). It takes as input the SavCurrPGM global variable and updates the SavPrevPGM global variable. Then the SavPrevPGM variable can be used as an input in the Load Screen Array procedure to load the previous menu.  

 

     P GetPr           B

     D                 PI                 Like(DYNSCODE)

     D InpCode                             Like(DYNSCODE) Const

     * Local Variables

     D WrkI           S                   Like(I) Inz(*Zeros)

     C                   Eval     WrkI = 0

     C                   Eval     WrkI = %LookUp(InpCode:WrkMenu.MenCode:1:

     C                                           SavI)

     C                   If       WrkI > 0

     C                   Return   WrkMenu.MenFrom(WrkI)

     C                   Else

     C                   Return   *Blanks

     C                   EndIf

     P               E

Listing 7: Get previous sub-menu

 

The Call Leaf Program procedure takes as an input the code ID of a leaf record and calls the program that the leaf record indicates.

 

     P CallingPGM     B

     D                 PI

     D InpCode                             Like(DYNSCODE) Const

     * Local Variables

     D WrkI           S                   Like(I) Inz(*Zeros)

     D WrkError       S             7A   Inz(*Blanks)

 

     *    General Calling Procedure for Programs without I-O Variables

     D PgmName         S             10A   Inz(*Blanks)

     D CallPGM         PR                 EXTPGM(PgmName)

 

     C                   Eval     WrkI = 0

     C                   Eval     WrkI = %LookUp(InpCode:WrkMenu.MenCode:1:

     C                                          SavI)

     C                   If       WrkI > 0

     C                   If       WrkMenu.MenPara(WrkI) = 0

     C                   Eval     PgmName = WrkMenu.MenCode(WrkI)

     C                   CallP     CallPGM()

     C                  Else

     *If option's leaf program has more than zero inputs we can call it here

     C                   EndIf

     C                   EndIf

 

     P    

E

Listing 8: Call leaf program

 

Finally, the following procedure takes as an input the code ID of a record and returns *On if the record is a leaf record.

 

     P IsTypeL         B

     D                 PI                 Like(WrkInd)

     D InpCode                             Like(DYNSCODE) Const

     * Local Variables

     D WrkI           S                   Like(I) Inz(*Zeros)

     C                   Eval     WrkI = 0

     C                   Eval     WrkI = %LookUp(InpCode:WrkMenu.MenCode:1:

     C                                           SavI)

     C                   If       WrkI > 0

     C                   If       WrkMenu.MenType(WrkI) = 'L'

     C                   Return   *On

     C                   Else

     C                   Return   *Off

     C                   EndIf

     C                   EndIf

     P                 E

 

Listing 9: Check if a record is a type leaf record

Summary

This TechTip presents an alternative method for deploying menus in IBM i. In IBM i, each menu is composed of three different types of objects (*MSGF, *FILE, *MENU). Each time we need to maintain a menu, we have to edit the code and recompile the objects. Instead of creating different objects with different source types for each different menu, by employing the proposed method we need only three objects (one screen, one program, one file) to represent as many menus as we like. All the menus are stored in one DDS file, and we can edit them without an intervention in the code. Finally, this method prevents the repeated programs' call, resulting in better performance and in avoiding the "many calls" limit.

References

[1]        John Enck, (1997), Navigating the AS/400: A Hands-On Guide, Prentice Hall PTR, ISBN 10: 0138625581

[2]        Gersting,J.L., (2007), Mathematical Structures for Computer Science, W.H. Freeman and Company.

[3]        Diestel, Reinhard, (2005), Graph Theory (3rd ed.), Berlin, New York: Springer-Verlag, ISBN 978-3-540-26183-4.

[4]        Steven S. Skiena, (2008), The Algorithm Design Manual (2nd Edition), Springer, ISBN: 978-1848000698

[5]        Kevin Vandever, (2011), Subfiles in Free-Format RPG, MC Press, ISBN-10: 1583470948

[6]        IBM, (2006), WebSphere Development Studio Client for iSeriesUsing Subfiles, IBM Corporation 1992, 2006

 

 

George Karkavitsas

George Karkavitsas is a PhD candidate in Computer Science at University of Piraeus. Email: This email address is being protected from spambots. You need JavaScript enabled to view it.

BLOG COMMENTS POWERED BY DISQUS

LATEST COMMENTS

Support MC Press Online

$

Book Reviews

Resource Center

  • SB Profound WC 5536 Have you been wondering about Node.js? Our free Node.js Webinar Series takes you from total beginner to creating a fully-functional IBM i Node.js business application. You can find Part 1 here. In Part 2 of our free Node.js Webinar Series, Brian May teaches you the different tooling options available for writing code, debugging, and using Git for version control. Brian will briefly discuss the different tools available, and demonstrate his preferred setup for Node development on IBM i or any platform. Attend this webinar to learn:

  • SB Profound WP 5539More than ever, there is a demand for IT to deliver innovation. Your IBM i has been an essential part of your business operations for years. However, your organization may struggle to maintain the current system and implement new projects. The thousands of customers we've worked with and surveyed state that expectations regarding the digital footprint and vision of the company are not aligned with the current IT environment.

  • SB HelpSystems ROBOT Generic IBM announced the E1080 servers using the latest Power10 processor in September 2021. The most powerful processor from IBM to date, Power10 is designed to handle the demands of doing business in today’s high-tech atmosphere, including running cloud applications, supporting big data, and managing AI workloads. But what does Power10 mean for your data center? In this recorded webinar, IBMers Dan Sundt and Dylan Boday join IBM Power Champion Tom Huntington for a discussion on why Power10 technology is the right strategic investment if you run IBM i, AIX, or Linux. In this action-packed hour, Tom will share trends from the IBM i and AIX user communities while Dan and Dylan dive into the tech specs for key hardware, including:

  • Magic MarkTRY the one package that solves all your document design and printing challenges on all your platforms. Produce bar code labels, electronic forms, ad hoc reports, and RFID tags – without programming! MarkMagic is the only document design and print solution that combines report writing, WYSIWYG label and forms design, and conditional printing in one integrated product. Make sure your data survives when catastrophe hits. Request your trial now!  Request Now.

  • SB HelpSystems ROBOT GenericForms of ransomware has been around for over 30 years, and with more and more organizations suffering attacks each year, it continues to endure. What has made ransomware such a durable threat and what is the best way to combat it? In order to prevent ransomware, organizations must first understand how it works.

  • SB HelpSystems ROBOT GenericIT security is a top priority for businesses around the world, but most IBM i pros don’t know where to begin—and most cybersecurity experts don’t know IBM i. In this session, Robin Tatam explores the business impact of lax IBM i security, the top vulnerabilities putting IBM i at risk, and the steps you can take to protect your organization. If you’re looking to avoid unexpected downtime or corrupted data, you don’t want to miss this session.

  • SB HelpSystems ROBOT GenericCan you trust all of your users all of the time? A typical end user receives 16 malicious emails each month, but only 17 percent of these phishing campaigns are reported to IT. Once an attack is underway, most organizations won’t discover the breach until six months later. A staggering amount of damage can occur in that time. Despite these risks, 93 percent of organizations are leaving their IBM i systems vulnerable to cybercrime. In this on-demand webinar, IBM i security experts Robin Tatam and Sandi Moore will reveal:

  • FORTRA Disaster protection is vital to every business. Yet, it often consists of patched together procedures that are prone to error. From automatic backups to data encryption to media management, Robot automates the routine (yet often complex) tasks of iSeries backup and recovery, saving you time and money and making the process safer and more reliable. Automate your backups with the Robot Backup and Recovery Solution. Key features include:

  • FORTRAManaging messages on your IBM i can be more than a full-time job if you have to do it manually. Messages need a response and resources must be monitored—often over multiple systems and across platforms. How can you be sure you won’t miss important system events? Automate your message center with the Robot Message Management Solution. Key features include:

  • FORTRAThe thought of printing, distributing, and storing iSeries reports manually may reduce you to tears. Paper and labor costs associated with report generation can spiral out of control. Mountains of paper threaten to swamp your files. Robot automates report bursting, distribution, bundling, and archiving, and offers secure, selective online report viewing. Manage your reports with the Robot Report Management Solution. Key features include:

  • FORTRAFor over 30 years, Robot has been a leader in systems management for IBM i. With batch job creation and scheduling at its core, the Robot Job Scheduling Solution reduces the opportunity for human error and helps you maintain service levels, automating even the biggest, most complex runbooks. Manage your job schedule with the Robot Job Scheduling Solution. Key features include:

  • LANSA Business users want new applications now. Market and regulatory pressures require faster application updates and delivery into production. Your IBM i developers may be approaching retirement, and you see no sure way to fill their positions with experienced developers. In addition, you may be caught between maintaining your existing applications and the uncertainty of moving to something new.

  • LANSAWhen it comes to creating your business applications, there are hundreds of coding platforms and programming languages to choose from. These options range from very complex traditional programming languages to Low-Code platforms where sometimes no traditional coding experience is needed. Download our whitepaper, The Power of Writing Code in a Low-Code Solution, and:

  • LANSASupply Chain is becoming increasingly complex and unpredictable. From raw materials for manufacturing to food supply chains, the journey from source to production to delivery to consumers is marred with inefficiencies, manual processes, shortages, recalls, counterfeits, and scandals. In this webinar, we discuss how:

  • The MC Resource Centers bring you the widest selection of white papers, trial software, and on-demand webcasts for you to choose from. >> Review the list of White Papers, Trial Software or On-Demand Webcast at the MC Press Resource Center. >> Add the items to yru Cart and complet he checkout process and submit

  • Profound Logic Have you been wondering about Node.js? Our free Node.js Webinar Series takes you from total beginner to creating a fully-functional IBM i Node.js business application.

  • SB Profound WC 5536Join us for this hour-long webcast that will explore:

  • Fortra IT managers hoping to find new IBM i talent are discovering that the pool of experienced RPG programmers and operators or administrators with intimate knowledge of the operating system and the applications that run on it is small. This begs the question: How will you manage the platform that supports such a big part of your business? This guide offers strategies and software suggestions to help you plan IT staffing and resources and smooth the transition after your AS/400 talent retires. Read on to learn: