The TSO/ISPF Client Gateway
The inspiration for version 2 of my ‘ISPF on the web’ experiment is a feature of TSO/ISPF called the “TSO/ISPF client gateway”.
What caught my eye about it initially was a comment to the effect of “access ISPF from the web” and so of course I thought “cool, that’s just what I need”. It is, or course, not quite that simple and there are a few things to consider when using the gateway that I shall write about more in upcoming posts.
You can read about the gateway here:
ftp://public.dhe.ibm.com/software/websphere/awdtools/ispf/ispfgw10.pdf
Context/Tools Menus
I am continuing to work on my web interface to ISPF and one of the things I wanted to do was add popup tool menus to things like data set and PDS member lists. I found a couple of nice examples on the web but they either broke my web page or I was just not happy with them. So I tried to create my own. Fail! A lot of work and it really was not what I wanted. I guess I ‘could’ write a jQuery plugin to do it but in the end I found this, somewhat old but perfectly adequate example:
http://www.trendskitchens.co.nz/jquery/contextmenu/
The only problem I had was that it only worked for a ‘right click’ and I wanted it to work for a left click. After starting at it for hours I realized that it it is ‘this’ piece of code (the bind in fact) that controls the popup:
$(this).bind('contextmenu', function(e) {
// Check if onContextMenu() defined
var bShowContext = (!!hash[index].onContextMenu) ? hash[index].onContextMenu(e) : true;
if (bShowContext) display(index, this, e, options);
return false;
});
In fact, it is the ‘contexmenu’ event that controls it. So I changed that line to read like this:
$(this).bind('contextmenu click', function(e) {
And voila, I get the popup menu with both a left and a right click:
Now on to making the tools actually do something….
The case of the wrong case…
This has been a bit of a detective story so I thought I’d mention it here in case it helps anyone.
As part of my efforts to move my web based ISPF interface to the stand alone IBM HTTP server I needed to run the REXX execs under USS. Now to be honest I rarely ever touch USS on z/OS but that’s where I needed to be so that’s where I am.
I typically write my REXX execs in lower case so I might end up with one exec invoking another with something like this:
data=myfunc(parm1,parm2,etc)
Where myfunc is another REXX exec in the standard search order (SYSPROC and SYSEXEC typically). This works fine because even though the function name is written in lower case, REXX converts it to upper case and that matches the member name in the library just fine. Everything works great.
BUT! Move over to USS land and things are not so simple. REXX in USS land is case sensitive. Using the example above, I had created the ‘myfunc’ exec file in USS with a lower case file name and was surprised when the calling exec could not find it.
Eventually (after two days) I found that by default, REXX makes function names coded like this into UPPER CASE before searching for them (I knew this, I had just forgotten about it) so REXX was searching for a file called ‘MYFUNC’ whilst the file I had created was called ‘myfunc’. Not the same animal in a case sensitive environment.
I could make all my exec file names upper case to address this, but in the event you need to call a lower case function name you can code it like this:
data='myfunc'(parm1,parm2,etc)
And amazingly it will now find the lower case exec file.
ISPF on the web – Version 2
Just a quick update, more details and info to follow soon.
My initial iteration of ISPF on the web required the user to still log on to TSO/ISPF on a 3270 and then start the web server inside their TSO/ISPF session before accessing it via a browser.
Whilst this was an interesting exercise and learning experience, obviously it’s about as useful as a chocolate fireguard in practice.
Hence the move to version 2!
The UI experience in the browser is the same but the back end is significantly different, running inside the IBM stand alone HTTP web server.
I am still developing this in my spare time, but as soon as I get a demo up and running I shall be adding more information so stay tuned.
As technology marches on, what will be lost?
From my internal work blog some time ago:-
Then we had 3480 cartridges (do we still? I have a couple somewhere).
Now we’ve got? Well it does not matter really. The point is, technology moved on.
Then CD’s
Then DVD’s
VHS tape player anyone?
Super 8 film?
But there is still plenty of data (and music) around on these old media.
Anyone got a wax cylinder player anymore?
Success and Failures. Not two sides of the same coin…
A post on an internal blog at work recently referred to this post by Seth Godin where success and failure are like two sides of the same coin. A quick Google search revealed many articles along the same vein. However after some thought, I have to disagree with this analogy.
The general consensus is that you can succeed or you can fail, that they are in some way opposites of each other. At first glance that would seem to be true but I choose to look at it this way…
Failure is where we find out how NOT to do something. Failure in itself is a learning experience, it teaches us something about what we are trying to achieve and about ourselves. Failure is simply a step on the road towards success.
The difference between success and failure is the point at which you give up and accept the current outcome. If you give up at any point before achieving your desired outcome (the successful one) then you have failed. Therefore the difference between success and failure is not that they are polar opposites but that you did not see that task through to the end and accepted an undesirable outcome over the preferred one.
You cannot have success without failure but you can have failure without success.
As for the coin analogy, my solution is simple. Change the shape of the coin. Make it a sphere (we ‘could’ have spherical coins, we just don’t). Only one side so only one outcome. Which it is is up to you. Where will you choose to end the journey?
XMITing multiple files
One of the things I sometimes need to do is transfer multiple sequential or PDS data sets between machines, or create a ‘package’ of data sets that can easily be downloaded from the web and restored on a host z/OS machine.
Typically on z/OS you might use the XMIT command to export a data set such as a PDS into a sequential form that can then be transferred between systems as a binary file. However to transfer multiple files you need to unload and transfer each one in turn and then restore it on the target host system. Even if you package all the files into a single zip file (on a Windows machine for example) you must still transfer each file to the host individually and receive it there.
In order to reduce the number of files I have to transfer from and to the host system I came up with the following packaging technique that basically ‘nests’ xmited files inside a PDS that itself is then xmited to make it into a sequential file.
1. XMIT each file to be transferred into a sequential XMIT dataset using a command like this:
XMIT IBM.SOMEID DATASET(‘sourcedsn’) OUTDSN(‘targetdsn’)
2. Create a PDS.
2. Copy each XMITed dataset from step 1 as a member to a new PDS, give each member a unique name.
3. XMIT the PDS to a sequential data set.
You can then transfer the final xmit file to a windows or other non z/OS machine, zip it up and move it around quite happily. The zip file of course only contains ONE file, the final xmited dataset from the host.
To restore it, pre allocate a sequential file on the host (FB, LRECL 80, BLKSIZE 3120) and transfer the file as binary to it from the off platform system using FTP or something similar.
Then receive the file using:
RECEIVE INDATASET(‘your dataset name’)
That restores the PDS containing the original xmited files.
Then receive each member in turn from that PDS to restore the dataset:
RECEIVE INDATASET(‘restoredPDS(member)’)
Some JCL and a little REXX makes it pretty easy to automate this whole process. I’ll post the JCL and REXX code that I use in a future article.
Finding out where a Rexx exec was loaded from
I had a need to find out which data set a Rexx exec was being loaded from within the exec. Whilst there are examples out there that trawl through the TIOT, since I was in an ISPF environment I came up with the following little bit of code:
/* rexx */
/* Find out where I came from. */
address ispexec
PARSE SOURCE . . pgm execdd .
"qbaselib "execdd" id(dsns)"
dsns = Translate(DSNS,' ',',')
dsnum = words(dsns)
do n = 1 to dsnum
dsn = strip(word(dsns,n),"B","'")
"lminit dataid(id) dataset('"||dsn||"')"
"lmopen dataid("id")"
"lmmfind dataid("id") member("pgm") stats(yes)"
findrc=rc
"lmclose dataid("id")"
"lmfree dataid("id")"
if findrc = 0 then leave
end /* do dsnum */
if findrc = 0 then do
say pgm "was loaded from <"dsn">"
return 0
end
else do
say "cannot determine where "pgm" was loaded from"
return 4
end
It would be easy to make this into a function to return the data set name (in the dsn variable).
360 degree photographs and 3D
360 degree photographs have been around for quite a while. Here’s a hi res image of St Pauls Cathedral.
The problem is of course that you can only see everything from the position of the camera. I got to thinking how neat it would be if you could actually move around the image and see things from different points of view. This would of course require that you take millions of 360 degree pictures from pretty much every physical point within the area you are photographing. Not entirely practical.
But then I got to thinking about the sort of technology being used by numerous people in conjunction with the Microsoft Kinect to generate 3D images. Some cleaver mapping software lets the the viewer see things from points other than the Kinnct’s physical location.
So here’s my thought. Merge 360 degree photography with the 3d software being used by Kinect hackers to generate a virtual 3d environment. You would only need a limited number of actual 360 degree photographs in order to dynamically recreate a 3d space by dynamically generating the view for points between the actual photographs.
Scenario and work flow driven development. The ‘Just Enough’ model.
I really must get back to the code I was working on but in the meantime, some thoughts on software development.
I am a developer, I code in (mostly) assembler on z/OS. I love it. I like 3270 green screens too and do a lot of my work using them. I also like the web 2.0 stuff (I don’t do Java though!) but mostly just for interest. I am used to looking at a problem and writing some code to address it. I want my code to be perfect and do everything (or it seems that way). I have spent my life looking at how to address a problem from the code perspective and it has worked fine for a long time.
I think the first revelation I had was the idea of forgetting about the interface to solve a problem. This may seem obvious but we (or I do anyway) spend so much time working with a particular framework, environment or UI that whenever we think about a problem we invariably tie any solution to the environment it will live in. As developers we (well, I) tend to think of solutions in terms of code. If the only tool you have is a hammer, everything starts to look like a nail. When you are a programmer, every solution involves code.
The automatic association between UI, framework etc and the problem may not be a conscious one but it colors everything we do. Now this next step may seem blindingly obvious but in fact I found it very hard to do, and that is to forget about code, the UI, the framework etc and just concentrate of the data and the problem.
It (sort of) works like this:
You have a problem to solve.
You have ‘some’ data related to that problem.
How would you use that data (lets say it’s printed out so no code here) to resolve the problem? During this phase you may discover that certain information you need is missing.
What you end up with is an understanding of how to work through the data to solve the problem (the work flow) and also, an understanding of what additional data you need in order to do that. You may find you need a certain piece of data in order to decide what piece of data to look at next.
Notice that this has nothing to do with code, data collection, frameworks, presentation etc. You are just looking at the data and how to use it to solve the problem.
What you DO NOT end up with are requirements for data that you do not need! Since collecting data requires additional coding, testing, documentation etc; anything you can do to reduce those requirements will reduce your development time and costs and also increase the quality of your code since the less code you write, the less there is to go wrong (another of those blindingly obvious facts!).
The next phase is to take the problem and using the UI (NOT the framework, NOT the code), that is just the presentation interface, be it 3270, web, java, whatever and using the UI services it would ‘reasonably ‘ have (eg check boxes, buttons on a web or PC type app) within the framework you develop for and come up with a work flow that lets you work through the data that you have already identified you need, in order to solve the problem.
The idea here is NOT to think “Oh, the UI only has this function so I have to do something this way or present the data this way”. UI’s can be changed, that’s the whole point of this. Instead think about how you WANT it to work, how you want the user to navigate through various screens etc to complete the task. You may find it makes more sense to move some of the data you identified earlier to different places. You may find the interface simply does not (currently) do what you need to implement the work flow.
The idea here is find the best way for the user to use the UI to work through the data you have already identified to complete the task. Regardless of whether it is actually possible today.
What you are going to end up with is a list or requirements for changes and additions to various components that, when done will enable you to use the interface work flow you came up withe to solve the problem. It will be ‘just enough’. It will do what it is supposed to do, not more. The code will be ‘just enough’, it will do what it needs to do, not more. the data will be ‘just enough’ to solve the problem. You won’t be collecting data you don’t need.
Well, that’s my thought for the day. None of this is really new and it may be blindingly obvious to some, it wasn’t for me. Maybe all I’ve done is express it in a simplistic way (simple is always good in my book). After thirty odd years as a developer I think I have realized that I’ve been doing it ‘wrong’ all these years.
