24
Tue, Dec
1 New Articles

The CL Corner: Getting Your Commands Out to the World

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

Learn about some additional capabilities related to user commands.

 

In the last article, "Need Some Help with That Command? Part II," we concluded our introduction to the User Interface Manager (UIM) as it relates to providing command help text for the command TRMLFTCHR. The complete source for the TRMLFTCHR panel group, which has only been published in pieces in past articles, is this:

The TRMLFTCHR UIM Source

:pnlgrp submsgf='VINING/USERMSGF'.                                    

.**********************************************************************

.*  Help for command TRMLFTCHR                                        

.**********************************************************************

:help name='TRMLFTCHR'.                                               

&msg(TRM0001). - Help                                                  

:p.The &msg(TRM0001). (TRMLFTCHR) command changes the value of a CL   

character variable by trimming (removing) specified characters from the

left of the specified CL variable.  The result is returned left       

adjusted and blank padded.                                            

:p.:hp2.Restrictions::ehp2.                                           

:ul.                                                                  

:li.                                                                   

The TRMLFTCHR command is valid only in CL programs.                   

:eul.                                                                 

:ehelp.                                                               

.*******************************************                        

.*   Help for parameter VAR                                         

.*******************************************                        

:help name='TRMLFTCHR/VAR'.                                          

&msg(TRM0002). (VAR) - Help                                         

:xh3.&msg(TRM0002). (VAR)                                           

:p.Specifies the CL character variable whose value is to be changed.

:p.This is a required parameter.                                     

:parml.                                                             

:pt.:pv.character-value:epv.                                        

:pd.                                                                

Specify the name of the character variable.                         

:eparml.                                                            

:ehelp.                                                             

.*******************************************                         

.*   Help for parameter TRMCHR                                      

.*******************************************                        

:help name='TRMLFTCHR/TRMCHR'.                                       

&msg(TRM0003). (TRMCHR) - Help                                        

:xh3.&msg(TRM0003). (TRMCHR)                                         

:p.Specifies one or more character values to be trimmed from the left

of the CL variable identified by the VAR parameter. Trimming of       

characters will end when a character value of the VAR parameter does 

not match any of the specified TRMCHR values.                        

:p.You can specify 50 values for this parameter.                     

:parml.                                                               

:pt.:pk def.0:epk.                                                   

:pd.                                                                 

Remove zero (0) values starting from the left of the VAR parameter   

value.                                                                

:pt.:pv.character-value:epv.                                         

:pd.                                                                 

Specify the characters to be trimmed from the left of the VAR         

parameter.                                                           

:eparml.                                                             

:ehelp.                                                              

.*******************************************                         

.*   Help for parameter ALLTRMCHR                                    

.*******************************************                         

:help name='TRMLFTCHR/ALLTRMCHR'.                                    

&msg(TRM0004). (ALLTRMCHR) - Help                                    

:xh3.&msg(TRM0004). (ALLTRMCHR)                                      

:p.Specifies the left adjusted value to be returned in the VAR       

parameter when only characters specified by the TRMCHR parameter are 

found in the VAR parameter. This character value will be returned in 

the leftmost position of the VAR parameter with all following        

character positions set to blanks.                                   

:parml.                                                               

:pt.:pk def.*TRMCHR:epk.                                             

:pd.                                                                 

The first specified TRMCHR parameter value is to be used when all    

characters of the VAR parameter are trimmed.                         

:pt.:pv.character-value:epv.                                         

:pd.                                                                 

Specify the character value to be returned when all characters of the

VAR parameter are trimmed.                                           

:eparml.                                                             

:ehelp.                                                              

.**************************************************                  

.*                                                                   

.* Examples for TRMLFTCHR                                            

.*                                                                    

.**************************************************                  

:help name='TRMLFTCHR/COMMAND/EXAMPLES'.                             

Examples for TRMLFTCHR - Help                                        

:xh3.Examples for TRMLFTCHR                                           

:p.:hp2.Example 1: Simple Command Example:ehp2.                      

:xmp.                                                                

TRMLFTCHR  VAR(&CHAR10)                                              

:exmp.                                                               

:p.This command will trim all leading zero (0) values from the       

CL variable &CHAR10 and return the remaining characters left         

adjusted.                                                             

.*                                                                   

:p.:hp2.Example 2: More Complex Command Example:ehp2.                

:xmp.                                                                

TRMLFTCHR   VAR(&CHAR10) TRMCHR(* ' ')                               

            ALLTRMCHR(X)                                             

:exmp.                                                               

:p.This command will trim all leading blanks and asterisks from the  

CL variable &CHAR10 and return the remaining characters left adjusted.

If only blanks and asterisks are found in the &CHAR10 variable then  

the left adjusted value 'X' is to be returned.                       

:ehelp.                                                               

.**************************************************                  

.*                                                              

.* Error messages for TRMLFTCHR                                 

.*                                                               

.**************************************************             

:help name='TRMLFTCHR/ERROR/MESSAGES'.                          

&msg(CPX0005,QCPFMSG). TRMLFTCHR - Help                         

:xh3.&msg(CPX0005,QCPFMSG). TRMLFTCHR                           

:p.:hp3.*ESCAPE &msg(CPX0006,QCPFMSG).:ehp3.                    

:DL COMPACT.                                                    

:DT.TRM0009                                                      

:DD.&MSG(TRM0009).                                              

:EDL.                                                           

:ehelp.                                                         

:epnlgrp.                                                        

 

Assuming that the preceding source is stored in member TRMLFTCHR of source file QPNLSRC, you can create the TRMLFTCHR panel group with the following command:

 

CRTPNLGRP PNLGRP(TRMLFTCHR)

The TRMLFTCHR CPP Source

The previous column on this topic also introduced a change to the command processing program (CPP) for the TRMLFTCHR command. The change was to send the escape message TRM0009 in the case of an unexpected error. This is the complete source for the TRMLFTCHR CPP:

 

      Pgm        Parm(&Char_Parm &TrmChrParm &All_TrmChr)        

      Dcl        Var(&Char_Parm)  Type(*Char) Len(5)             

        Dcl        Var(&Char_Siz)   Type(*Int) Stg(*Defined) +   

                     DefVar(&Char_Parm 1)                        

        Dcl        Var(&First_Char) Type(*Char) Len(1) +         

                     Stg(*Defined)    DefVar(&Char_Parm 5)       

                                                                 

      Dcl        Var(&TrmChrParm) Type(*Char) Len(3)             

        Dcl        Var(&NbrTrmChr)  Type(*UInt) Len(2) +         

                     Stg(*Defined)    DefVar(&TrmChrParm 1)      

        Dcl        Var(&First_Trm)  Type(*Char) Len(1) +         

                     Stg(*Defined)    DefVar(&TrmChrParm 3)      

                                                                 

      Dcl        Var(&All_TrmChr) Type(*Char) Len(1)             

                                                                 

      Dcl        Var(&Char_Ptr)   Type(*Ptr)                     

      Dcl        Var(&Char)       Type(*Char) Len(1) +             

                   Stg(*Based)    BasPtr(&Char_Ptr)                

                                                                   

      Dcl        Var(&CharTgtPtr) Type(*Ptr)                       

      Dcl        Var(&Char_Tgt)   Type(*Char) Len(1) +             

                   Stg(*Based)    BasPtr(&CharTgtPtr)              

                                                                   

      Dcl        Var(&TrmChrPtr)  Type(*Ptr)                       

      Dcl        Var(&TrmChr)     Type(*Char) Len(1) +             

                   Stg(*Based)    BasPtr(&TrmChrPtr)               

                                                                    

      Dcl        Var(&Char_Pos)   Type(*UInt)                      

      Dcl        Var(&Char_Rem)   Type(*UInt)                      

      Dcl        Var(&Trm_Pos)    Type(*UInt)                      

      Dcl        Var(&XFF)        Type(*Char) Len(1) Value(x'FF')  

                                                                   

      MonMsg     MsgID(CPF0000 MCH0000) Exec(Goto CmdLbl(Error))   

                                                                    

      ChgVar     Var(&Char_Ptr) Value(%addr(&First_Char))           

      ChgVar     Var(&CharTgtPtr) Value(%addr(&First_Char))         

                                                                    

Trim: DoFor      Var(&Char_Pos) From(1) To(&Char_Siz)                

                 ChgVar Var(&TrmChrPtr) Value(%addr(&First_Trm))    

                 DoFor Var(&Trm_Pos) From(1) To(&NbrTrmChr)         

                       If Cond(&Char *EQ &TrmChr) Then(Do)          

                          ChgVar Var(%ofs(&Char_Ptr)) +             

                                   Value(%ofs(&Char_Ptr) + 1)       

                          Iterate CmdLbl(Trim)                      

                          EndDo                                     

                       Else Cmd(Do)                                 

                            ChgVar Var(%ofs(&TrmChrPtr)) +          

                                     Value(%ofs(&TrmChrPtr) + 1)    

                            Iterate                                  

                            EndDo                                   

                       EndDo                                          

                       Leave                                          

                 EndDo                                                 

                                                                      

      If         Cond(&Char_Pos *LE &Char_Siz) Then(Do)               

                 DoFor Var(&Char_Pos) From(&Char_Pos) To(&Char_Siz)    

                       ChgVar Var(&Char_Tgt) Value(&Char)             

                       ChgVar Var(%ofs(&CharTgtPtr)) +                

                                Value(%ofs(&CharTgtPtr) + 1)          

                       ChgVar Var(%ofs(&Char_Ptr)) +                  

                                Value(%ofs(&Char_Ptr) + 1)            

                       EndDo                                          

                                                                      

                 If    Cond(&Char_Ptr *NE &CharTgtPtr) Then(Do)       

                       ChgVar Var(&Char_Rem) Value( +                 

                                (%ofs(&Char_Ptr) - %ofs(&CharTgtPtr)))

                       DoFor Var(&Char_Pos) From(1) To(&Char_Rem)     

                             ChgVar Var(&Char_Tgt) Value(' ')       

                             ChgVar Var(%ofs(&CharTgtPtr)) +        

                                      Value(%ofs(&CharTgtPtr) + 1)  

                             EndDo                                  

                       EndDo                                        

                 EndDo                                              

                                                                     

      Else       Cmd(Do)                                            

                 If Cond(&All_TrmChr *EQ &XFF) Then(Do)             

                    ChgVar Var(&TrmChrPtr) Value(%addr(&First_Trm)) 

                    ChgVar Var(&Char_Tgt) Value(&TrmChr)            

                    EndDo                                           

                 Else Cmd( +                                        

                      ChgVar Var(&Char_Tgt) Value(&All_TrmChr))     

                 ChgVar Var(%ofs(&CharTgtPtr)) +                    

                          Value(%ofs(&CharTgtPtr) + 1)              

                 DoFor Var(&Char_Pos) From(2) To(&Char_Siz)         

                       ChgVar Var(&Char_Tgt) Value(' ')           

                       ChgVar Var(%ofs(&CharTgtPtr)) +           

                                Value(%ofs(&CharTgtPtr) + 1)     

                       EndDo                                     

                 EndDo                                            

      Return                                                     

                                                                 

Error:                                                           

      SndPgmMsg  MsgID(TRM0009) MsgF(Vining/UserMsgf) +          

                          MsgType(*Escape)                       

                                                                 

      EndPgm                                                     

 

Assuming that the preceding source is stored in member TRMLFTCHR of source file QCLSRC, you can create the TRMLFTCHR CPP with either of the following commands:

 

CRTBNDCL PGM(TRMLFTCHR)

 

or

 

CRTCLPGM PGM(TRMLFTCHR)

The TRMLFTCHR Command Source

And as long as we're providing complete source examples, here is the source for the TRMLFTCHR command:

 

Cmd        Prompt(TRM0001)                           

Parm       Kwd(Var) Type(*Char) Len(1) RtnVal(*Yes) +

             Min(1) Vary(*Yes *Int4) Prompt(TRM0002) 

Parm       Kwd(TrmChr) Type(*Char) Len(1) Dft(0) +   

             SpcVal((0)) Max(50) Prompt(TRM0003)     

Parm       Kwd(AllTrmChr) Type(*Char) Len(1) +       

             Dft(*TrmChr) SpcVal((*TRMCHR X'FF')) +  

             Prompt(TRM0004)                         

 

Assuming that the preceding source is stored in member TRMLFTCHR of source file QCMDSRC, you can create the TRMLFTCHR command, linking it to the TRMLFTCHR help panel group and TRMLFTCHR CPP, with the following command:

 

CRTCMD CMD(TRMLFTCHR) PGM(TRMLFTCHR) ALLOW(*IPGM *BPGM *IMOD *BMOD) +

PMTFILE(USERMSGF)HLPPNLGRP(TRMLFTCHR) HLPID(*CMD)    

 

At the conclusion of last month's article, it was also pointed out that while providing help text for the TRMLFTCHR command was reasonably easy, the help text wouldn't be of much aid if you weren't on an IBM i where you could prompt the command. The question posed then was "Wouldn't it be nice to also provide the help text on the Web?" This would enable just about anyone, anywhere, to access it at any time. Well, it turns out that putting the command help text on the Web (assuming you have a Web presence and are currently serving Web pages) is roughly one command away!

Generating TRMLFTCHR HTML Documentation

Recall that back in the article "Providing Help Text for a User Command," we used the Generate Command Documentation (GENCMDDOC) command to provide the initial UIM source for the TRMLFTCHR panel group. This is the command used at that time:

 

 GENCMDDOC CMD(TRMLFTCHR) TODIR('/QSYS.LIB/VINING.LIB/QPNLSRC.FILE')

  GENOPT(*UIM)

 

Having now created our help panel group, and associating our panel group with the TRMLFCHR command with the HLPPNLGRP and HLPID parameters of CRTCMD, we can now again use the GENCMDDOC command. But this time, we'll have an HTML document generated based on the contents of our panel group. To generate the file TrmLftChr.html in the root directory of the IFS, you could use the following command:

 

GENCMDDOC CMD(TRMLFTCHR) TODIR(/) TOSTMF(TrmLftChr.html) GENOPT(*HTML) 

 

This will create a UTF-8 encoded HTML file whose source starts as shown below:

 

<!doctype html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>

<head><META http-equiv="Content-Type" content="text/html; charset=utf-8">

<title>Trim Left Characters  (TRMLFTCHR)</title>

</head>

<body bgcolor="white">

<a></a>

<h2>Trim Left Characters  (TRMLFTCHR)</h2>

<table width="100%">

<tr>

<td valign="top" align="left"><b>Where allowed to run:  </b>

<ul><li>Batch program (*BPGM)</li>

<li>Interactive program (*IPGM)</li>

<li>Batch ILE CL module (*BMOD)</li>

<li>Interactive ILE CL module (*IMOD)</li>

</ul><b>Threadsafe:  </b>No

</td>

<td valign="top" align="right">

<a href="#TRMLFTCHR.PARAMETERS.TABLE">Parameters</a><br>

<a href="#TRMLFTCHR.COMMAND.EXAMPLES">Examples</a><br>

<a href="#TRMLFTCHR.ERROR.MESSAGES">Error messages</a></td>

</tr>

</table>

 

What you have here is a "ready to go" HTML file that, if opened by a browser, will present the TRMLFTCHR command documentation in a style that is amazingly similar to the style used by sites such as the IBM Information Center and PowerCL.com. It just doesn't get much easier than that!

Supporting Multiple Language Environments

While we're on the topic of expanded access to command documentation, let's return to a topic that was mentioned back in the article "Providing Help Text for a User Command" under the heading "Do You Support Multiple Language Environments?" If you have reviewed the compiler listing from creating the panel group TRMLFTCHR, you may have noticed that many of the TRM messages that are referenced using the UIM &msg symbol result in the warning message CPD5BCB – A CCSID conversion error occured [sic] when message TRMxxxx was retrieved. This warning is due to message files defaulting to a CCSID of *HEX when created, which is really CCSID 65535, which essentially turns off CCSID conversions and results in the potential for incorrect message text in the panel group if variant characters exist in the first-level text of the referenced message description. That is, message text created by a U.S. job that contains the U.S. dollar sign ($) may, when used by a UK job running with a different CCSID, show the UK pound sign (£). As with the previously cited article, if all of your users run in the same national language. then you can skip to the next topic: Seeing the Forest Rather Than the Trees. But if you do have users running with different job CCSIDs, then continue reading.

 

Avoiding this potential error in data representation, and getting rid of the CPD5BCB warning message, is quite easy to do if you followed my earlier suggestion of using a non-65535 job CCSID when adding the various TRM* message descriptions. The Add Message Description (ADDMSGD) command actually records, by default, the job CCSID that is in effect when the message is added. In order to start using these stored message description level CCSIDs, rather than the message file CCSID of 65535, is as simple as using the Change Message File (CHGMSGF) command and specifying a CCSID of *MSGD, which equates to CCSID 65534. While many developers are familiar with CCSID 65535 and its behavior of turning off CCSID conversions, not as many have run into CCSID 65534. CCSID 65534 is a special CCSID that indicates to the system that the actual CCSID value to use can be found at the "next lower" level of the object. In the case of a message file, this "next lower" level is the specific message description.

Seeing the Forest Rather Than the Trees

When developing the TRMLFTCHR command, we started with the command definition, then developed the CPP, and ended by creating the help text for the command. I used this particular sequence in the hope that it would make it easier for most readers to understand how the various pieces work in providing a complete command (and of course to demonstrate some of the capabilities in command definition, CL, and UIM that are available to you). This sequence of development actions, however, is not what I would recommend when "really" developing a new command.

 

In my experience, I have found that creating the help text immediately after defining the command, rather than coding the CPP prior to the help text, is much more productive. Trying to express the function of the command, and the parameters, in a written form typically gets me thinking a lot more (and earlier) about the interplay of the parameters (and often the need for additional parameters and/or keywords) than if I simply start coding the CPP to my initial command design. That is, coding the CPP prior to the help text tends to focus me on the implementation of the discrete parameters (an individual tree or a specific cluster of trees), and I often don't realize the need for an additional parameter or keyword until I've gone quite a way down an implementation path—a path that then needs to be reworked (or more often rewritten) to accommodate my late discovery. Writing out the help text prior to writing the CPP helps me keep the big picture or "forest" in mind and often results in a much better design when I do start coding the CPP.

 

Writing out the help text prior to implementing the CPP also provides some additional benefits. One is that you can then distribute the help text out to others for their review and suggestions. Early critiquing of your design by way of sharing your written command help text documentation is generally much easier (and more productive) than by sharing a verbal description of your command. And certainly beats a code review as the first opportunity for others to comment on your code (though code reviews are certainly important, they're often done a bit late for you to easily accommodate new features in the command). A second benefit that I've seen is that help text written after the CPP has been coded tends to be more a guide to the user describing what you did rather than a guide to the user describing what they can do, which is what they really want from the help text.

 

As you code the CPP, you will of course encounter the need to occasionally update the command documentation. That's to be expected and, in my case, quite often involves the error message section of the command documentation. But I believe it's quite important to write out, early on, the command description, the parameter descriptions, and the examples section of the panel group.

The End

This concludes the saga of our TRMLFTCHR command. Over the course of several articles, we've taken advantage of many features available to you. Some of these features included command parameter lists, CL pointers, CL-based and defined storage, structured operators such as DOFOR, UIM help text, and HTML help text generation. Hopefully, besides being a learning opportunity for these features, TRMLFTCHR might even be a command that you can use within a CL program or two of your own.

 

Wondering how to accomplish a function in CL? Send your CL-related questions to me at This email address is being protected from spambots. You need JavaScript enabled to view it.. I'll try to answer your burning questions in future columns.

as/400, os/400, iseries, system i, i5/os, ibm i, power systems, 6.1, 7.1, V7,

 

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: