Showing posts with label REXX. Show all posts
Showing posts with label REXX. Show all posts

Wednesday, December 7, 2022

Are you ready to solve Christmas-themed programming puzzles? Advent Of Code 2022 is live!

Vibin' with AoC 

I came upon a piece by Herbert Daly a few days ago when browsing my LinkedIn feed. I read the description of a puzzle in the photo that was uploaded with the post since it was intriguing. The puzzle's focus on the holiday season and Christmas kept me interested. I dug more after that and discovered Advent of Code (often referred using its acronym, AoC). I just felt good about AoC and the theme behind it. It is the sole reason behind my inspiration to reactivate this blog after it had been dormant for months.


What is Advent Of Code? 

Advent of Code is series of Christmas-themed programming puzzles that is released one at each day between December 1st and December 25th. Each puzzle consists of two parts; the second portion, which is typically a setting established by the first half of the puzzle, is disclosed after the first part has been solved. You receive a Star ⭐ for each part of the puzzle you successfully solve. Over the course of a season, up to 50 stars can be earned. You can use any programming language of your choice to solve the puzzles. A point system is available to score the players according to how long it takes them to finish the puzzles. On a leaderboard that is accessible through the website, the top 100 players are distributed. There's even a wonderful Advent calendar that list the days 1 to 25 arranged from bottom to top. A Christmas-themed artwork is hidden behind a sequence of @'s and #'s on the Calendar. As you complete a puzzle each day, the artwork is exposed one piece at a time.

Advent Calendar for 2022


Eric Wastl introduced Advent of Code on December 1, 2015. The eighth edition, Advent of Code 2022, is now available! The website still allows the users to solve the puzzles of previous years. 

What is in it for Mainframers?

When I first entered the website of AoC, I had a feeling of familiarity with the look because it appeared like a Mainframe screen. I (selfishly) assumed  that the site and theme were designed for Mainframers, but I was mistaken. The puzzles are available to everyone, including those with limited programming experience and problem-solving abilities.

Nonetheless, AoC has a lot to offer for Mainframers.  All the puzzles can be solved using Mainframe programming languages such as COBOL, REXX, ICETOOL/DFSORT, and so on. There is even a private leaderboard where you may compete with other Mainframers. Continue reading to learn how to join up for AoC and the exclusive leaderboard for Mainframers.

Signing up for AoC and the exclusive leaderboard for Mainframers

To begin solving the puzzles, you must first register with AoC. You may sign up using either of the following accounts by clicking here.
  • GitHub
  • Google
  • Twitter
  • Reddit 
questionnaire must be completed in order to join the exclusive private Leaderboard for Mainframers. After submitting the form, a secret code will be sent to you through email. Simply copy the code and go to https://adventofcode.com/2022/leaderboard/private to join the board. 

Herbert Daly and Henri Kuiper, two Mainframe enthusiasts, maintain the private leaderboard. They've even stated that some folks at MicroFocus will be supporting the private leaderboard (again!) by providing some awesome swag and prizes to those who solve this year's tasks using the language that runs the world: COBOL.

"HELP will always be given at Hogwarts to those who ask for it" - Albus Dumbledore

If you get stuck when solving the puzzles, feel free to join these Subreddits and ask for hints.
I've started adding the code for each day's puzzle to my Git repository. At the time of writing this post, code till Day 6 puzzles are available on the Git. You may use them as a reference material.  

I even intend to write a post every day until December 25th to walk through my approach to tackling these puzzles. 

So, what are you waiting for 🤔? See you (your name) on the Leaderboard 👍

If you have any queries about the content of this page, please leave them in the Comments area below.


Saturday, January 9, 2021

Writing a REXX Program to create a Valid Luhn Number generator | Master the Mainframe 2020 | Level 3.3: REXX2: Nexxt Level Rexx

Welcome to my blog! This is my first post of this new year, 2021. Happy New Year to one and all 😄

In this post, we'll look at Level 3.3 of Master the Mainframe 2020. If you haven't registered for MTM2020 yet, then you're missing the fun 😐. Master the Mainframe has been a lot interesting this year (2020) as we are using Visual Studio Code (for the first time) to establish a connection with z/OS. Hit this link to register.

Level 3.3: REXX2: Nexxt Level Rexx is all about building complex logic and functionality using REXX. The task is to write a REXX Exec that acts as a generator, which when executed, will output Luhn-Algorithm compatible 16 digit numbers. The code shouldn't take any parameters though.



If you do not have prior experience in writing REXX exec's, do not worry at all. 

  • MTM2020 is the right place to get your hands on REXX. There are couple of challenges in Level 3 which will improve your REXX skills in the best way possible.
  • Advertisement alert ⚠: I also recommend you to read a blog post of mine 😀 which is intended for beginners in REXX. 
  • Jim Barry's REXX tutorial is my personal favourite, so I recommend that as well. 


It's time ⏰ to go further... 

The first step in the challenge instructions will ask you to copy a member named CCVIEW from MTM2020.PUBLIC.SOURCE to your own SOURCE dataset. Let's take a look at the REXX Exec residing in CCVIEW member, section by section.

 In a nutshell, this REXX Exec reads an input file, MTM2020.PUBLIC.CUST16, line by line over a do while loop until end of the file and writes each line to an output file, if the read line is longer than 10 characters. We should be aware of few commands in REXX before venturing into a REXX Exec that is dealing with files (like this one 👆). 

First things first, the dataset(s) that you're going to use in a REXX Exec should be allocated to the address space that the REXX is running under. This is usually done using the ALLOC command as shown in the lines 11 and 12. The ALLOC command can be used by a REXX program to dynamically allocate necessary datasets. 

Defining ALLOC command for a dataset in REXX Exec is very much similar to defining a dataset in a JCL DD statement for I/O. 

Let's go thru the command given in line 11. 

"ALLOC FI(indd) DA('MTM2020.PUBLIC.CUST16') SHR REUSE" 

FI refers to the name that will be used by other commands in this REXX Exec, like EXECIO,  to refer to this file (Kinda shorthand 😉). DA refers to the real dataset name. The disposition SHR indicates that the file is intended for reading. It is imperative to note that any dataset allocated within a REXX Program using the ALLOC command should be released back to the system using the FREE command, after the file has been used. More about ALLOC can be found 👉 here.

After the dataset is allocated, we can read the file by the EXECIO command using the DISKR parameter. Let's look at line 23. 

"EXECIO 0 DISKR indd (OPEN"

The EXECIO command is used for processing files. 0 along with DISKR indicates that 0 records should be read from the file referenced by indd DD name.
R in the DISKR is for Read. Similarly, W in the DISKW is for write. X in the DISKX will issue an error because there is no such thing as DISKX 😅. Just DISKW and DISKR.
(OPEN indicates that the file should be opened for future use. Another example of EXECIO command can be found in line 31. 

"EXECIO 1 DISKR indd"

This EXECIO command resides within a DO loop ➿. Under each iteration, this EXECIO reads 1 record from indd. The records read will be written to the stack on a first-in, first-out basis . The records are then available by using the PULL or PARSE PULL instructions. 

Lines 30-45 are already explained in the challenge instructions. Shamelessly copying it here 😒. 
There are three nested DO statetments here. The outermost loop is just a check to make sure there are more lines to read, the middle loop iterates through those lines, and the innermost loop checks if the length of the line is greater than 10 characters, before writing it to the output file.

Make note of line 41 which is commented out. 

call INSPECT

The call instruction calls 📞 an internal routine named as INSPECT. Routines are made up of sequence of instructions that can receive data, process it, and return a value. INSPECT label with a colon can be found at line 80. When REXX executes the call instruction at line 41, the control passes to line 80. The instructions under the INSPECT routine are then executed, in this case, just a SAY instruction, which outputs a message to user. RETURN statement at line 82 returns back the control to the CALL instruction. 

Both the input and output files are closed in lines 46 and 57 respectively. FINIS in the command indicates that the dataset should be closed after use. If FINIS is omitted, the datset will remain open for future use. 

The datasets are freed by FREE instruction in lines 76 and 77 🆓. 

When you run this REXX Exec after replacing ZXXXXX with your user ID in line 12, you will notice that the output file looks the same as the input file. You now have a code that runs and it's time to build upon that foundation to make it do something else. 

What's the ask?

Your first task is to add a logic to this program that checks whether the credit card number being read in satisfies the Luhn algorithm. You may probably have the logic for validation coded inside the INSPECT routine. 

Once you have the logic for validating input for a Luhn number, the final task of this challenge is to build a generator that outputs Luhn-algorithm compatible 16 digit numbers. The final task should not read any input files or parameters. When the code is executed, it should write 500 unique numbers, one on each line, to a PDS member (ZXXXXX.OUTPUT(CUST16)). You have to use the ALLOC command to allocate the PDS member. 

Reading the challenge instructions carefully plays a vital role in finishing this challenge successfully. You have got several hints 💡 in there and let me list them out here. 

  • REXX is a dynamically typed language. This means you are able to store several values of different types in a single variable during your code execution and no errors will occur. 
    • For example, consider the following 2 lines.

       odd_digits = 0
       odd_digits = odd_digits + substr(cc_digits,5,1)

    • In the second line, REXX actually understands the data by its usage. It automatically converts the type of the output from the second operand (substr() function) to perform the arithmetic operation. 
  • Step 9 in the challenge instructions list out some built-in functions which you may find useful to accomplish the task.
    • SUBSTR – Substring – returns just the characters at a specific location within a string. There’s an example of this in action at line 40. 
    • LENGTH – Returns the total length, in characters, of a string. 
    • MATH OPERATORS – In particular, the // symbol, which returns the remainder after dividing by a number.
    • RANDOM – is a built-in function in REXX and it is used to generate a random non-negative whole number between the min and max range that are provided as arguments. 


What was my approach to finish this challenge 🤔? 

I came across the Credit card anatomy which goes like below:

Perceive lines 4 thru 16 as a Credit Card 💳. The first number is Major Industry Identifier (MII) which tells you what sort of institution issued the card. Lines 21 thru 27 shows the list of institutions. 

The first six digits are the Issuer Identification Number (IIN). These can be used to look up where the card originated from. Lines 31 thru 35 might ring some bells 🔔.

The 7th digit to second-to-last digit is the customer account number. Most companies use just 9 digits for the account number, thereby making the Credit card number as 16 digits. But, it's possible to use up to 12 digits for the account number. 

The last digit of a credit card is the check digit or checksum. 

With this info in hand, I generated the random credit card number in the following way: 

/* Major Industry Identifier */                               
random1 = random(1,9)                                         
                                                              
/* random1 to random3 together generates BIN */               
random2 = random(111,999)                                     
random3 = random(10,99)                                       
                                                              
/* random4 to random6 together generates account identifier */
random4 = random(1,9)                                         
random5 = random(1111,9999)                                   
random6 = random(1111,9999)                                   
part2 = random1||random2||random3||random4||random5||random6  
cc_digits = '000' || substr(part2,1,15)    

Note that I had generated only 15 digits of the credit card number using random built-in function (exclude the first 3 digits, 000). The last digit, checksum is calculated using a formula, 

c = (10 − (s mod 10) mod 10)      

where,
c is checksum,
s is  (sum of digits placed in odd positions) + (sum of each digit placed in even positions multiplied by 2) 
Note: if value of each digit placed in even positions multiplied by 2 is greater than 9, then subtract the value by 9. 

After the checksum is calcualted, the 16 digits of credit card number is formed by concatenating the 15 digits, generated out of the random function, with the checksum digit. 

cc_digits = strip(cc_digits||strip(checksum))

strip is a built-in function in REXX which is used to remove the leading and trailing spaces.
|| is the operator used for concatenating 2 strings. 

I had created a separate routine to calculate the checksum. Once the checksum is calculated, the 16 digit credit card number is passed on to another routine, which will validate the number to check if it is Luhn-compatible or not. If the number is valid, it will be written to a compound variable. 

Compound variables:

Variables are treated as compound variables if the variable name ends with a "." (period). All the 500 Luhn-compatible numbers are written to a compound variable named 'out.'. I had used do loops in combination with compound variables to write the numbers. After writing, if you refer to, out.1, it will fetch you the first Luhn-compatible number. Likewise, out.499 will fetch you the 499th Luhn-compatible number. out.0 will give you the count of total number of records present in the compound varaible, 'out.'. 

After storing 500 Luhn compatible numbers in the compound variable, I used the EXECIO command to write the compound variable to the output file. 

"EXECIO * DISKW outdd (STEM out."

The * and DISKW indicates that all the records from the STEM (i.e., compound variable), OUT. should be written to the output file outdd.

Some useful tips:

  • Try this website to validate the 500 numbers you generate out of your code, to be Luhn-compatible or not. 
  • I recommend you to use Vista TN3270 terminal for this challenge to logon to the MTM system (IP: 192.86.32.153 PORT: 623) rather than VS code. Coding and running your REXX exec will be a lot easier in TN3270 terminal. 
  • Coding TRACE I in the 2nd line of your REXX Exec and executing the code will result in debugging mode. This might help you in understanding the program's flow, if things are not working out. More about TRACE can be found here.
  • Bonus hint: While using DO loops to traverse across the even and odd positions of the 19 digit credit card number, you may have to step 2 times in each iteration. The syntax in such cases is as follows:
                    do i = 5 by 2 to 17
            (......)
         end
         
         
         do j = 4 by to 18
            (......)
         end

About sharing my solution.. 

Nope😐, I respect the individuality and the fun element in coding these challenges and have opted not to share the complete code. Instead, I believe I've done my best in explaining several jargons used in REXX and those which, when understood, might be of help to you in finishing this challenge. If you still need clarity on any topics, please let me know. 

Hope this helps. Should you have any questions, please post it in the comments section below. Thx.  


Sunday, December 20, 2020

Writing a REXX program to copy Mainframe tape dataset to DASD

Hiya! 👋 Welcome to my blog. In this post, let's look at a REXX (not T-REX🦖) code which will take a Mainframe tape dataset name as input and let you copy it to a DASD dataset.  

Mainframe tape datasets  can't be browsed like a PS dataset. To view the contents of the tape dataset, we need to copy the tape dataset to a DASD first. 

I hope this post will be of help to those who don't have prior experience in writing REXX programs. If you read till the bottom of this post, you'll get a fair idea on the following stuff:

  • Usage of REXX in IBM z/OS. 
  • Defining File-tailoring skeletons. 
  • Addressing environments in REXX. 
  • Built-in functions.
  • IF/THEN/ELSE instructions in REXX. 
  • Invoking REXX Exec.

A short intro about REXX:

  • REXX is a programming language that was developed by IBM. 
  • REXX is easy to learn and use. To prove this, let's write the traditional Hello World🌍 program in REXX.

    • Create a new member in your own PDS

      The first line of the REXX program SHOULD be a comment (delimited by /* and */) and it must contain characters  'REXX' in it. say in the second line is a REXX function that is used to print messages to the console.

      Save the member and press F3 to go back to PDS members list view. In the line command area, type ex to execute the member.

      No caption needed😎

  • REXX is very readable, REXX instructions are based on English. 
  • REXX has powerful set of built-in functions. 
  • REXX is an interpreted language that does not require compilation. Each line of code is checked and interpreted into "machine understandable code" before being executed. 
  • REXX runs in all MVS address spaces and on many platforms (there's one for Android too 👀). 
REXX is a program langauge swiss army knife for z/OS System Programmers and System Administrators.  

I guess it's enough talking about REXX. Let's begin writing ✍ the program itself. The entire program is shown below and we will go through the program section by section. 


Lines 1 thru 16: 

In REXX, comment is a sequence of characters delimited by /* and */. The first 16 lines are comments and they tell the modifications that have been made to this code right from the creation of this REXX Exec. Wait, What is a REXX Exec? (you may be asking yourself 🤔). 

Well, a REXX Exec contain REXX language instructions plus commands that are executed by the host environment. 

💡IBM recommends that all REXX execs start with a comment that includes the characters 'REXX' within the first line (line 1) of the exec. Failure to do so can lead to unexpected or unintended results in your REXX exec. 


Lines 17 thru 19: 

One of the strengths of REXX is that you can use it to invoke the functions of other products. ADDRESS command temporarily or permanently changes the destination of the commands that are followed next. Commands are strings sent to an external environment. 

💡ADDRESS statement is more similar to sudo (Switch User and DO this) command in Linux, which will make you the root user briefly to perform root user actions like installing a package. 

To use DB2 commands in REXX, you must first address that environment. Likewise, in Line #17, address ispexec is coded to execute the command in line #18 in ISPF environment, the full panel application that we all are addicted to😀. 

LIBDEF command is used to define the application-level libraries that will be in effect when the application is running. In Line #18, we use the LIBDEF command to define the Skeleton Library 💀. Gotcha! A Skeleton library is used to store skeleton files. A Skeleton file can be a JCL like the below: 


This is pretty much a simple job that has a SORT step in it to copy an input dataset, provided in SORTIN DD statement, to the output dataset, defined in SORTOUT DD statement. But, something here is so weird, isn't it?🤔 You see a lot of ampersands, don't you? Let me list out all the variable names preceded by an ampersand. 

  • &JNUM
  • &DSNME
  • &USRID
  • &MON
  • &DY
  • &HH
  • &MM
  • &SS 

There isn't an input dataset name defined in SORTIN. Instead, you've got &DSNME. You'll be issued with JCL errors when you manually submit this JCL. So, please don't do that ⚠. 

This JCL is meant for REXX. When our REXX exec is running, this skeleton file will be scanned record-by-record by the File-tailoring services in REXX (more about File Tailoring services will be covered later in this post). Each record will be scanned to find any dialog variable names, which are names preceded by an ampersand. When a variable name is found, it's current value is substituted from the REXX exec. 

💡A skeleton file can be assumed as a template that is non-functional on its own. File-tailoring services read skeleton files and write tailored output that can be used to drive other functions. 

Do you get the whole picture now? We'll use File-Tailoring services in Rexx to substitute values in all those variable names, preceded by an ampersand, in the skeleton file. We'll then have a functional JCL which upon submission will copy the input dataset to the output dataset. Simple! 😎  


Line #19 uses the ARG instruction. ARG retrieves the argument strings provided to a program or internal routine and assigns them to variables. For example, if you pass the string "IBM z/OS" to the statement, arg company product, then

company contains 'IBM'

product contains 'z/OS'

Line #19 is used to pull the input dataset name and assign it to the variable, dsn.


Lines 20 thru 26 in REXX exec: 

We need an input tape dataset name for the REXX exec to copy it to an output dataset. When the REXX exec is invoked without an argment (i.e., an input dataset name), we should tell the user to invoke the REXX exec with an argument and exit the exec. Line 20 thru 26 does that with the help of say instruction in REXX. 

IF/THEN/ELSE instruction in REXX is used to vaildate the dsn variable. When you have more than one statement under an IF condition, enclose them between a DO and END. 


Lines 27 thru 41 in REXX exec: 

The else part starting from line #27 is executed when the user has invoked the REXX exec with an argument. 

STRIP() is a built-in function in REXX and it is being used in line #29 to remove the leading spaces and trailing spaces as well as single quotes (if any) that surrounds the input argument. The stripped value is assigned to variable, a.

RANDOM() is a built-in function in REXX and it is being used in line #30 to generate a random non-negative whole number between the min and max range that are provided as arguments i.e., 001 and 999 respectively. The random number is assigned to a variable JNUM and this variable name, preceded by an ampersand, is present in the first line of the skeleton file. The usage of RANDOM()function in this exec ensures that the job name is unique every time when the output JCL is created by the file-tailoring services. 

USERID() is a built-in function in REXX and it is being used in line #31. This function returns the TSO User ID. Note that the return value of the function is being assigned to variable that is used in the Skeleton file. 

In line #32, the stripped input dataset name available in the variable a is being assigned to the Skeleton file's variable, DSNME

Pause! Let's do a status check to see where we are right now ✅. 

Till now, we only have a valid job name and an input dataset name to be assigned to the JCL in the skeleton file. We need an output dataset name. The output dataset name should be unique every time when the REXX exec is invoked. To do that, we will be adding the Date and Time values at the last 2 qualifiers of the dataset name. At the time of writing this line, I invoked the REXX exec against a dataset and got the output dataset name as 'Z01071.TAPE.COPY.Z01071.DDEC20.T053624'. The last but 1 qualifier has got the date as 20th December and  the last qualifier contains the time in Thhmmss format. Let's continue. 

In line #33, a variable upper is assigned with sequence of characters from a to z in upper case and in line #34, a variable lower is assigned with sequence of characters from a to z in lower case. We'll be using these variables as argumens to the TRANSLATE() built-in function in REXX.  

In line #35, two built-in functions are used. SUBSTR() and DATE(),

DATE() function returns the local date in dd mon yyyy format by default. When 'U' is passed as an argument to the DATE() function, the local date will be returned in MM/DD/YY format.   The return value from the DATE() function is being used as the string for SUBSTR() function. SUBSTR() function is used to extract a portion of the string. Therefore, line #35 is used to extract the MM from the date string (in MM/DD/YY format) and value is assigned to a variable named m

The CALL instruction in line #36 calls an internal routine, find_month


This routine uses the SELECT instruction in REXX to choose one of the 12 months based on the value in variable, m. return statement at the end of the routine, returns back the control to the line next to CALL instruction. 

Line #37, translates the month value from upper case to lower case using the TRANSLATE()built-in function.  

I hope you will be able to decode the lines 38 thru 41. They use the DATE(), TIME() and SUBSTR() functions to assign values to variables that are used in the Skeleton file.

At the end of line #41, we would have assigned values to all the dialog variable names, preceded by an ampersand, in the skeleton file. It's now time to use the File-tailoring services of REXX to write a tailored JCL that can be edited and submitted by the user. 

Lines 42 thru 47:

File-tailoring services:

To use the file-tailoring services, we must first address the ISPEXEC environment. After addressing the environment, the host environment's commands are passed as strings from the lines 43 thru 47. 

  • FTOPEN TEMPPrepares the file-tailoring process and specifies whether the temporary file is to be used for output. 
  • FTINCL TCSKEL - Specifies the skeleton file named TCSKEL from the skeleton library to be used and starts the file tailoring process. The skeleton file is read record-by-record and the dialog variable names in the skeleton file are assigned with values from the variable pool created by the REXX exec.
  • FTCLOSE -  Ends the file-tailoring process. 
  • VGET ZTEMPF - The file tailoring output is directed to a temporary sequential file. The file name of the temporary file is available in the system variable ZTEMPF. Before editing or submitting the job from the temp. dataset, the VGET service should be invoked to initialize the ZTEMPF.  

In line #48, we have issued EDIT dataset command so that the temporary file will be opened in edit mode for the user. The user after checking the JCL can submit the job by issuing SUB command. 

Invoking the REXX exec:

There are several ways of invoking a REXX exec from foreground or background. 

  1. Easiest of the lot is, after saving a REXX exec, you can issue an ex  command on the member to execute the exec in foreground mode. 
  2. When you want to use the member name of the REXX exec as a line command, you must first allocate your private PDS that contain the REXX Exec(s) to the system libraries SYSEXEC/SYSPROC. Refer the first step in this link for more details on how to do that. You might have to copy paste the REXX exec to your PDS and provide you REXX PDS in the DATASET parameter of the ALLOC command. After the allocation, when you type the member name of a REXX exec, you're private PDS will be scanned by the system and the REXX exec will be executed if it's found in the PDS. 
Only option 2 works with the REXX exec that we've prepared. Invoking the exec will be lot easier when you allocate your private PDS to the system libraries. Let's see how our REXX exec fares out.

First, let's assign the private PDS to system library. 

Note that I've provided my PDS in the DATASET parameter of ALLOC command. 

Type ex on the member to execute the REXX exec. 

Allocation successful! Now, we can use the member name TC as a line command.


Type tc on a tape dataset or a DASD dataset that you want to make a copy. 


Tada! Here is the file tailored output. You may type SUB on the command line to submit this job. You may also type some SORT statements before submitting the job.  


Thx for reading. Please share your thoughts in the comments section. I would be glad to answer to your questions if any. Happy Holidays!