Showing posts with label GitHub. Show all posts
Showing posts with label GitHub. Show all posts

Sunday, August 10, 2025

It is twenty-six to one — A retro clock built with COBOL

πŸ“Έ Heads up! This is a highly visual post! Expect plenty of screenshots and photos from my gallery to make the walkthrough more fun and easy to follow.

Since the first image in a blog post often becomes its thumbnail, I wanted something deliberate—not a random, awkwardly cropped photo. So, I made this πŸ‘‡ one in Canva.

The Spark ✨

I started collecting watches in 2021. I started off this hobby by collecting HMT watches, and now my collection includes HMT, a bunch of G-Shocks and Casio watches, a few Timex models, and watches from microbrands like Pagani Design. I like collecting watches with unique designs. Here are the pics of some unique watches from my collection.

Picto Stick and Ball watch

Kalaksh Time-Turner

Titan Geometrix

Casio G-Shock GA-V01

Fastrack x Coca-Cola


The latest one that I added to my collection was the SKMEI 2312

SKMEI is a Chinese watch brand known for offering a wide variety of affordable timepieces. They make watches that look very similar to popular brands (like Casio) but are affordable and considered homage. SKMEI 2312 is an homage to the QlockTwo W Watch, which is a unique watch that doesn't use hands or digital numbers to tell the time. Then, how does it show the time, you may wonder? It tells time in words like "IT IS FIVE PAST ONE." 



Here πŸ‘‡ are some pics of the SKMEI 2312.

Wrist Shot



My inspiration for this little project, which, btw, you're reading as a blog post now, came from the SKMEI 2312, which got me thinking, if a watch can tell time in words, why not make a COBOL program do the same? 

First time with OpenCOBOL IDE

I usually prefer JDoodle's Online COBOL compiler to write COBOL programs on the go. But, for this project, I thought of trying the OpenCOBOL IDE on my personal laptop. I really loved the coding experience. It's a lightweight IDE with some useful features like a syntax highlighter, vertical grid lines indicating Area A and Area B, a navigation window showing the structure of the program with collapsible buttons, an offset calculator, etc. It would've been fantastic if there was an in-built debugger.

Here is a snapshot of my code on OpenCobolIDE.

The Logic 🧠 

The initial idea was to use the intrinsic function, FUNCTION CURRENT-DATE in COBOL, to get the hour and minute. Process the hour and minute separately to determine how to express them in words. The code heavily relies on several EVALs, which do the magic of expressing the time in words. 
Click on this -> link to execute the code on JDoodle. 

Please note that this code displays the time in words the moment you hit the Execute button, referring to the hour and minute during that moment. It doesn't act like an actual clock (which updates the time every minute). 

Testing Like a Modern Mainframer

After coding the logic, I decided to test it for every possible minute in the day. I asked ChatGPT to generate an input file of LRECL 4, with each line having the time in HHMM format starting from 0000 to 2359. I also shared the COBOL logic I created on OpenCobolIDE and asked the AI assistant to modify the code to accommodate logic for reading the input file and writing to the output file. The intent was to write a record to the output file with the time expressed in words for each record read from the input file. For example, "IT IS TWELVE IN THE MORNING" for 0000. 

Screenshot of the input file that ChatGPT generated.


Screenshot of the output file generated by the program that ChatGPT helped modify by adding code to read the input file and write to the output file. The code did have some mistakes (not major ones, though), and I corrected them with several trials and errors. 

The logic that I wrote in COBOL expresses the time in words for each minute of the day. The program handles the AM/PM by representing the time period at the end of the sentence, like this:
  • Hours < 12 → “IN THE MORNING”
  • Hour = 12 → “IN THE NOON”
  • Hours > 12 & < 17 → “IN THE AFTERNOON”
  • Hours ≥ 17 & < 21 → “IN THE EVENING”
  • Hours ≥ 21 → “IN THE NIGHT”
The SKMEI 2312 watch (or the QlockTwo W watch for that matter) doesn't express the time in words for each minute. The watch displays the time in five-minute intervals. For example, it will show the time as "IT IS FIVE PAST TWO.", then "IT IS TEN PAST TWO." To indicate the exact minutes, there are 4 dots at each corner of the square grid of letters. The number of dots lit up at a specific time equals that many minutes plus the minute part of the time expressed in words. For example, if the time is displayed as "IT IS FIVE PAST TWO" with two dots lit up, the exact time is "IT IS SEVEN PAST TWO."

The watch displays "IT IS    TO TWO" with a dot lit up on the top left corner of the watch. This means, "IT IS ONE TO TWO" i.e., 01:59. 

The Blog widget idea πŸ’‘

I'm running this blog on Blogger by Google. It allows me to edit the layout of the site. I can add/edit gadgets to my blog. For example, the IBM Champions badge that you see on the right side (if you're reading this post using the web version of this blog) is an HTML/Javascript gadget. IBM provided this badge through Credly, and Credly provides me with the code to display the badge on a web page, blog, or anywhere else that accepts HTML.



Since I had already added a number of gadgets to my blog, I thought, "Why not add this Time In words gadget as well?" 

Once the logic was stable, I leaned on ChatGPT (again) with the following prompt:
How can I show this time-in-words as a live widget on my blog?
Out of many ideas that it provided,  I chose the one that suggested,
  • hosting OUTPUT.txt file on GitHub Pages
  • Use Javascript to read the current time (in HHMM format)
  • Use the HHMM value to look up the matching line in the file hosted on GitHub Pages
  • Display the time in words, updating every minute

First time with GitHub Pages

I had never used GitHub Pages before, but it turned out to be perfect. In a nutshell, GitHub Pages is like a website for your GitHub repository. 

I created this GitHub repo and added the COBOL program and input/output files. I set up the GitHub Pages on my repo to host the OUTPUT.txt file so that it's available in public and can be fetched by the blog widget. 

GitHub Pages on the repo is disabled by default, and you can enable it by configuring a publishing source for your site. Publishing source, in my case, is the main branch root folder of the repo. All the files that I added/will be adding to the repo will be immediately published on the site. 

Settings on the GitHub Pages on my repo.

Here is the link to the site.

If you know the exact filename in the repository, you can view its contents directly by appending the filename to the site’s URL.
For example, starting from the main site URL, https://jvsrinivasan.github.io/time-in-words/ adding OUTPUT.txt at the end (https://jvsrinivasan.github.io/time-in-words/OUTPUT.txt) will open that file’s contents in your browser.

It's time to show time πŸ• 

After hosting the OUTPUT.txt file using GitHub Pages, I asked ChatGPT to help me with the HTML/JavaScript code for the blog's widget. 

After some interaction, I was able to obtain a working code that,
  • Runs every minute (setInterval)
  • Gets the current time (new Date())
  • Formats it to HHMM
  • Looks up the matching line from OUTPUT.txt
  • Displays the time in words in a black background with green monospaced text to give the blog widget that nostalgic Mainframe terminal look 😎🟩⬛
Here is the code:
 <div id="time-in-words-widget" style="background-color:black; color:#00ff00; font-family:monospace; font-size:20px; padding:10px; border-radius:5px; text-align:center;">  
  Loading time in words...  
 </div>  
   
 <script>  
  async function showTimeInWords() {  
   const now = new Date();  
   const hours = now.getHours().toString().padStart(2, '0');  
   const minutes = now.getMinutes().toString().padStart(2, '0');  
   const hhmm = hours + minutes;  
   
   try {  
    const response = await fetch("https://your-username.github.io/time-in-words/OUTPUT.txt?cache=" + Date.now());  
    const text = await response.text();  
    const lines = text.split('\n');  
    const match = lines.find(line => line.startsWith(hhmm));  
    const output = match ? match.substring(5).trim() : "Time not found";  
   
    document.getElementById("time-in-words-widget").innerText = output;  
   } catch (error) {  
    document.getElementById("time-in-words-widget").innerText = "Error loading time.";  
   }  
  }  
   
  showTimeInWords();  
   
  // Align with start of next minute  
  const delay = (60 - new Date().getSeconds()) * 1000;  
  setTimeout(() => {  
   showTimeInWords();  
   setInterval(showTimeInWords, 60000);  
  }, delay);  
 </script>  
   

Here is a pic of the blog with the gadget in action:



Closer look at the 'Time in Words' Gadget


Closing thoughts

I could’ve done this in Python/Javascript. But I blog about COBOL—not because it’s trendy, but because it powers the systems most people don’t realize they depend on. This was my way of showing that COBOL can still surprise you. And sometimes, inspiration (for a little project) comes from something as simple as your watch. 

As a side note, a big thank you to IBM for sending me the IBM Champion merch package. This year marks my 4th consecutive year as an IBM Champion. Here is a pic of everything that IBM sent me in the package:

Thanks for reading! Should you have any comments, please write them in the Comments section below. 


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.


Wednesday, March 24, 2021

Printing the pattern of letters from A to Z using the respective letter itself

Hiya! Hope 🀞 this blog post will be fun πŸ˜€ as I really enjoyed writing this particular code which you will be witnessing shortly. 

When I saw the black screens πŸ’» for the first time when I was trained on Mainframe (that was in 2014 πŸ“…), I was totally amused.  The logon screen had something similar to what we have got now on the logon screen of IBM's Master the Mainframe 2020 system.

Click on the image for a larger version.

Each letter's shape in the string 'z/OS' is printed using the same letter, that too in Italics. 

Intro

I was longing to write a COBOL program which would print the ASCII character strings (just the letters A-Z for now) in large size to the output, using the respective letter itself (sometimes people prefer asterisk '*' or '#' to print shapes). This blog post is all about the approach I took to come up with such a program. 

At the end of this post, there's a short write-up on publishing a code on GitHub as I'm used to Endevor and GitHub (a code hosting platform) is new to me. 

Approach

Printing just one letter's shape in the output is simple. All you need is a PERFORM VARYING loop in COBOL, a logic to form the letter's shape and a DISPLAY statement printing the lines for each iteration of the loop. An example can be found πŸ‘‰ here.  

However, printing each letter's shape, of the string, from left to right is little bit tricky. I chose 7 x 7 cell to spread out the shape of each letter. An excel sheet, in which I drew all the 26 letter's shapes, came in handy as I referred the sheet before going to code the logic for each letter. 

An excel sheet with each alphabet's pattern spread out in a 7 x 7 cell.

I leveraged the two-dimensional table, to store the letter's shape. The COBOL code is as follows:


WS-LINE is an element of one-dimensional table that occurs 7 times. Assume each element of WS-LINE as a row.
 
WS-LETTER is an element of a two-dimensional table that occurs 70 times in each occurence of WS-LINE. Assume each element of WS-LETTER as a column. 

For readability, I've limited the maximum length of the string, input by the user, to 10 bytes. Hence, each line is 70 bytes long. 

When I was halfway with my code, I ran πŸƒ some tests only to realize that a space in between each letter's shape would be clear enough to read. 

That isn't easy to read. BAD πŸ™ˆ


Hence, I came up with yet another multi-dimensional table solely for printing purpose. 


This table gets data from the former 2D table (which we've already seen before) only at the point of displaying the entire stuff. 

In the PROCEDURE DIVISION, there are references to 3 para's,
  1. which would ask for the input string from the user; validate it. Upon successful validation of user input (read the next item),
  2. go through each letter of the string one by one with help of Reference Modification in COBOL; call the para corresponding to each letter - to print its shape - with the help of EVALUATE verb.
  3. display output and STOP RUN.
There are 26 para's coded to print the shape of 26 alphabets in English. A lot of PERFORM VARYING loops and COMPUTE statements are used to build 🧱 the logic in each para. Let's look at the code for one of those para.


This πŸ‘† part of code prints the shape of letter T. There are 2 PERFORM VARYING loops ➿. 
Let's look at the first loop ➰. 
  • The first loop iterates for 7 times with WS-J data item's value ranging from 0 to 6 and forms the horizontal line of letter T's shape.
  • WS-I data item holds the position of the letter in the string entered by the user. WS-I data item's value is multiplied with 7 to put the letter's shape in the right set of rows and columns. 
  • COMPUTE statement is coded before the MOVE statement because arithmetic expressions aren't supported (on IBM Enterprise COBOL for z/OS  6.3.0 compiler) in the subscripting.
  • The MOVE statement moves the letter T to WS-LETTER which is an element of two-dimensional table. In a two-dimensional table, the two subscripts correspond to the row and column numbers.
Given the following 7x7 cell:



The following happens in each iteration of the first loop, if WS-I's value is assumed as 1:

1st iteration:
WS-I = 1
WS-J = 0
WS-TEMP = 7
Letter T is moved to WS-LETTER(1, 7)

2nd iteration:
WS-I = 1
WS-J = 1
WS-TEMP = 6
Letter T is moved to WS-LETTER(1, 6)

3rd iteration:
WS-I = 1
WS-J = 2
WS-TEMP = 5
Letter T is moved to WS-LETTER(1, 5)

4th iteration:
WS-I = 1
WS-J = 3
WS-TEMP = 4
Letter T is moved to WS-LETTER(1, 4)

5th iteration:
WS-I = 1
WS-J = 4
WS-TEMP = 3
Letter T is moved to WS-LETTER(1, 3)

6th iteration:
WS-I = 1
WS-J = 5
WS-TEMP = 2
Letter T is moved to WS-LETTER(1, 2)

7th iteration:
WS-I = 1
WS-J = 6
WS-TEMP = 1
Letter T is moved to WS-LETTER(1, 1)

At the end of first loop, the cell will look like below:


The second loop does something similar to the first loop and it moves the letter to all the rows in 4th column of 7x7 cell. At the end of second loop, the shape of letter will be formed. 



Executing the code..

The full code is available πŸ‘‰ here in JDOODLE, an online compiler and editor for many programming langauges including COBOL. 

The COBOL program that I've written mimics the functionality of Banner command in Linux.

After clicking on the link, just scroll to the bottom of the code and give a string, max. of 10 characters, in Stdin Inputs and click Execute button in the blue box. After the execution, the result will be displayed in the Result area (black colored rectangle box). 

Output after running the code in JDOODLE.

Please note the following before providing input in Stdin Inputs tab:
  • Numbers and symbols like hyphen (-), dollar ($) etc., aren't supposed to be entered. The program code is hardwired with logics to form shapes only for the 26 alphabets (in upper-case). If numbers and symbols are part of the string, they will be replaced with spaces. 
  • I've used an intrinsic function (FUNCTION UPPER-CASE) to convert any string entered by the user to upper-case.
  • Please limit the input string to a maximum of 10 characters. String with length beyond 10 will be truncated.
  • If there are spaces in between the string, user will be prompted to re-enter another string without spaces in between. 
Stdin Inputs has got 3 lines of input string; first 2 lines has got strings with a space in between. Note the messages in the Result area.


Scope for improvement

  • Improvements can be made to the existing code to shorten the total number of lines.
  • Logics for lower-case alphabets, numbers and symbols can be added.
  • Length of the string, input by the user can be extended. 
  • The height and width of the cell is fixed for now and can be made scalable by altering the code.

GitHub

GitHub hosts millions of projects written in different programming languages. Each project is placed in its own container called a repository (repo) that can store code and other files of the project. Any changes to the files within a repo will be tracked via version control.

Each repo has got a name. There can be lots of repositories with same name. Hence, it's always better to use a link to locate the repo you're looking for. 

Go ahead and open this πŸ‘‰ repo I've created for this project. 

By default, this repository which I've created has got only one branch named main. Having the code in main branch is similar to having the code in the Production stage of  CA Endevor, a source code management tool for z/OS. 

If you want to do some edits on the code, you take a copy of the code residing in the Production stage of CA Endevor to your personal PDS. Likewise, in GitHub we use branches to make edits before commiting them to main. When a new branch is created, a new copy or snapshot of main is made.

There are 2 files in the main branch of the repository I've created for this project. A README file - which describes the project -  and a file named CBL1 which has got the COBOL program. 

All you need is an account on GitHub to create new branch for yourself in order to suggest edits/improvements for the code. commit by saving your changes. Open a pull request to propose your changes and request someone to review by using GitHub's @mention system. pull requests are merged  to the main branch when the new changes are reviewed and are good to go πŸ‘ .


That's it for now! πŸ”š

Hope you liked this post. Should you have any questions/suggestions, please post it in the comments section below.

ThxπŸ‘!