KludgeCode

is Ben Rudgers

Remarks: Epigram 2

This is part of a writing exercise around Alan Perlis‘s Epigrams in Programming.

Functions delay binding. Data structures induce binding. Moral: Structure data late in the programming process.

Maybe I know what it means, or rather I know the starting point for figuring out what it means to me right now. If I have the expression:

(setq y (foo x))

Then I have to wait for foo to do its work before I do the binding of its output to y. Furthermore, I can modify foo to get exactly what I want bound to y – I can get y just right – up until the moment foo returns.

So y could bind to an atom or a list or a structure or a hashtable depending on what is needed (and assuming no <type> safety is needed or imposed despite no need. Conversely, if I use something like:

(setq y (list :print poo :format foo :dependency doo))

I need to use a specific form (getf y :print) embedded in my program (or something which evaluates identically in order to do my printing [I am locked in to a specific implementation once I create the alist]. My program has become more brittle at this point in development – i.e. the point where I structured my data.

At some point of course, my data may need to be structured. But the structuring of my data is for the benefit of the user, not the programmer. Structuring data produces predictable behavior which benefits the user, and rigidity which is to the detriment of the program development process. [Although as a constraint it may be beneficial  from a program design standpoint].

Some other Preference Toggles

All these files are dated 2009/8/18

 

   Auto Join Walls


Procedure toggle_pref_Auto_Join_Walls;

BEGIN

    SetPref(33, NOT GetPref(33));

END;

Run (toggle_pref_Auto_Join_Walls);

Display Default Content


Procedure toggle_pref_Display_Default_Content;

BEGIN

    SetPref(130, NOT GetPref(130));

END;

Run (toggle_pref_Display_Default_Content);

 

Show Other Objects in Groups


Procedure toggle_pref_Show_Other_Objects_While_In_Group;

BEGIN

   SetPref(14, NOT GetPref(14));

END;

Run (toggle_pref_Show_Other_Objects_While_In_Group);

 

Have a Bad Day: VectorScript’s OpenURL

So playing around with writing demoWare got me thinking about how much foresight went into VectorScript’s architecture. Like the rest of VectorWorks, it’s really just a mashup of features. Among them is the wonderful “OpenURL.”

According to the documenation : Opens a web page or file using the default browser or appropriate application (e.g. Adobe Acrobat).

A web page or a file? What could possibly go wrong?

Here’s the nice version which asks you to pick the file [dated 2009/8/20]:


Procedure launch_a_file;

VAR
	filename	:string;
	urlstring	:string;
	status 		:boolean;

BEGIN
GetFile(fileName);
IF NOT DidCancel THEN 
	BEGIN
	urlstring := Concat('file:\\\',filename);
	message (launch_file);
	status:= OpenURL(urlstring);
	END;
END;
RUN(launch_a_file);

A not so nice version might do all sorts of things. Without letting the user select the file.

Vectorworks was my first exposure to Mac partisanship. Windows users were always clearly seen second class citizens both within discussions and by Nemetschek – even though they denied it. When I released the code and Icon for the run command, I made sure it didn’t work on the Mac by wrapping it thusly [dated 2009/8/20]:


VAR
	{bad_mac variables}
	appMajor, appMinor, appMaint, platform : integer;

	{run_on_windows variables}
	filename	:string;
	urlstring	:string;
	status 		:boolean;

Procedure run_on_windows;
BEGIN
GetFile(fileName);
IF NOT DidCancel THEN 
	BEGIN
		urlstring := Concat('file:\\\',filename);
		status:= OpenURL(urlstring);
	END;
END;

PROCEDURE bad_mac;
BEGIN
	alrtdialog ('OSX not Supported');
	alrtdialog ('Ending Program');
END;

BEGIN {main loop}
GetVersion(appMajor, appMinor, appMaint, platform);
		IF (platform = 1) 
		THEN bad_mac
		ELSE run_on_windows;
END;

RUN(launch_a_file);

The older version of bad_mac was less civil and was part of my investigation into VectorScript’s OpenURL [dated 2009/8/18]:



Procedure Mac_filter;

VAR
appMajor, appMinor, appMaint, platform : integer;

PROCEDURE microsoft_url;
{////  Open microsoft.com  /////}
VAR
  status : boolean;
  urlstring : string;
Begin
  urlstring := 'http:\\www.microsoft.com';
  status:= OpenURL(urlstring);
END;

PROCEDURE bad_mac;
BEGIN
  alrtdialog ('Operating System is Error - Getting Upgrade');
  microsoft_url;
END;

BEGIN
GetVersion(appMajor, appMinor, appMaint, platform);
		IF (platform = 1) 
		THEN bad_mac
		ELSE message('execute program');
END;

RUN (Mac_filter);

And here is the icon for the nice version of Run:    

 

HP11C

This post has been a long time on the back burner. It started as a response to something on HN about how marvelous the iPhone’s skeuomorhic interface is – something long since forgotten – and probably about how wonderful the iPhone and Apple are in general.

image HP11C front
HP11C User Interface

Like an iPhone, my HP 11c fits comfortably into a shirt pocket. I have been using it for almost 25 years. It uses batteries sparingly, and is often just powerful enough to keep me from firing up a spreadsheet. I paid $90 for it in the fall of 1988. It’s sister, the HP12C is still relevant and still manufactured. Mine [which is not as pretty the Computer Museum’s photos] sits on my desk. I use it for most things which don’t require a spreadsheet.

image HP11C back
HP11C mini manual

Unlike the iPhone however, it as designed as a tool not a piece of consumer electronics. The HP11C was designed to give the user as much power as the hardware would allow. Including the power to program it. The interface is simple, but not easy. Writing programs takes physical and mental effort. The calculator is not designed to accommodate ignorance – e.g. it uses RPN.

The Argument Button: Toggle Black and White Preferences

I wrote some useful code [all files dated 2009/8/18]  – actually auto-generated it for all the preferences, more on that below – added a nice icon and posted it up with instructions on how to use it.

What do you get for writing a simple tool which attempted to hack it’s way past the limitations of VectorScript? Zealous defense of that limitation as rational. By Royals no less.

Here’s the offending code which cannot be run from an icon :


Procedure toggle_pref_Black_and_White_Only;

BEGIN

   SetPref(10, NOT GetPref(10));

END;

Run (toggle_pref_Black_and_White_Only);

And the icon    

As I suggested earlier, I generated commands for all the preference files:

  1. Copy the html documentation – an older version of this.
  2. Paste massage it into Excel.
  3. Use Word to mail merge it with a VectorScript code template and output it to a single file.
    
    V:\vector Scripts\toggle prefs\«function_name».txt
    Procedure toggle_pref_«function_name»;
    BEGIN
    	SetPref(«selector_», NOT GetPref(«selector_»));
    END;
    Run (toggle_pref_«function_name»);
    
  4. Run this Vectorscript against the output file:
    
    PROCEDURE bar_parse_mergefile;
    
    VAR
     	i : INTEGER;
    	merge_source_file : STRING;
    	vs_output_file : STRING;
    	bar_readline1,bar_readline2,bar_readline3,bar_readline4,bar_readline5  : string;
    
    BEGIN
    	merge_source_file := 'V:\vector Scripts\toggle prefs\master parts\proceduremenu.txt';
    
    OPEN (merge_source_file);
    
    FOR i:=1 TO 131 DO BEGIN
    
    READLN (vs_output_file);
    READLN (bar_readline1,bar_readline2,bar_readline3,bar_readline4,bar_readline5); 
    
    {//////
    ALRTDIALOG (vs_output_file);
    ALRTDIALOG (bar_readline5);
    /////}
    
    REWRITE (vs_output_file);
    WRITELN (bar_readline1,CHR(13));
    WRITELN (bar_readline2,CHR(13));
    WRITELN (bar_readline3,CHR(13));
    WRITELN (bar_readline4,CHR(13));
    WRITELN (bar_readline5,CHR(13));
    
    CLOSE (vs_output_file);
    
    {\\\\\\\ALRTDIALOG (vs_output_file);\\\\\\\\\\\}
    
    END; 
    
    ALRTDIALOG ('ended loop');
    
    CLOSE (merge_source_file);
    
    END;
    RUN (bar_parse_mergefile);
    
  5. This generated a separate VectorScript file for each available preference. One of which was the offending code. Being mentally in VectorScript mode, it was much easier to generate the files using Vectorscript than to attempt to program Word to handle them just the way I wanted.

A similar technique was used for commands – and ultimately for the Kludge-o-matic. More on that, hopefully, later.

The Production Code for KludgeCode Extrude

The key to making the program do what I really required digging around in VectorScript’s abysmal documentation and crap examples until I found the “Array of Handles”.

And here’s the thing I struggle with – 1000 handles seems like a lot. So many in fact that I fear crashing the computer. My personal legacy of learning programming on the TRS-80 with 4kb of RAM is that I naturally count allocated resources as “one, two and many.”

I have a million times more RAM. I am always concerned about using too much. A 1000 element array seems inconceivably wasteful.

Here’s the actual production code for the extrude without the demo constraints:


PROCEDURE super;

   VAR
      index : integer;
	handleBin:ARRAY[1..1000] of HANDLE;
	Obj_class : string;
	Start_class : string;
	End;

Procedure loadBin(h1:HANDLE);
   Begin
      index:=index+1;
      handleBin[index]:=h1;
   End;

PROCEDURE change_it(objectHand:HANDLE);
   Begin
		dselectall;
		obj_class := getclass (objectHand);
		Nameclass (obj_class);
		setselect (objectHand);
		domenutextbyname ('extrude and edit', 0);
	End;      

BEGIN
       Start_class := ActiveClass;  
	index:=0;
         ForEachObject(loadBin,sel=true);
         index:=1;
		 while handleBin[index] <> nil Do begin	
			change_it (handleBin[index]);
			index := index+1;
		end;
	Nameclass (Start_class);
 	End;
Run (super);

It’s no accident that I called the main routine “super”. I was pretty damn pleased with myself.

Remarks on the Extrude Demo

A first attempt at writing a limited demo – in order to force the user to buy my wonderful utility. Writing the demo wrapper was the bulk of the effort:


PROCEDURE super;

   VAR
    index : integer;
    handleBin:ARRAY[1..1000] of HANDLE;
    Obj_class : string;
    Start_class : string;

Procedure Democode;

var
    strTime : string;
    strTest : string;
    intTest : integer;
    intLen : integer;
    status : boolean; {for openURL call}
Begin
    strTime := Date (2,2);
    intLen := Len (strTime);

    {Check for Time ends 40-49 seconds and run popup if it is}
    strTest := copy (strTime, (intLen - 4), 1);
    If str2num (strTest) = 4 Then
    AlrtDialog ('Demo Version:  Purchase Full Version at KludgeCode.com');

    {Check for Time ends with 4 minutes and open URL if it is}
    strTest := copy (strTime, (intLen - 5), 1);
    If str2num (strTest) = 4 Then
    status := OpenURL ('http://www.kludgecode.com');

  End;

Procedure loadBin(h1:HANDLE);
   Begin
      index:=index+1;
      handleBin[index]:=h1;
   End;

PROCEDURE change_it(objectHand:HANDLE);
   Begin
        dselectall;
        obj_class := getclass (objectHand);
        Nameclass (obj_class);
        setselect (objectHand);
        domenutextbyname ('extrude and edit', 0);
    End;      

BEGIN
       Start_class := ActiveClass;  
    index:=0;
         ForEachObject(loadBin,sel=true);
         index:=1;
         while handleBin[index] <> nil Do begin    
            change_it (handleBin[index]);
            index := index+1;
            DEMOCODE;
        end;
    Nameclass (Start_class);
     End;
Run (super);

 

Remarks on the Kludgecode Extrude command

I had the software dream of writing nickle and dime code for Vectorworks. The idea of multiple extrude came up in this discussion. It’s not a bad little program, and got me started learning Vectorscript.

Vectorscript like most aspects of vectorworks is a feature. It was executed in the easiest way in terms of improving marketing collateral. As a scripting language it’s abysmal because it requires compilation and thus makes interactive development impossible.

The first pass at the code for the kludgecode extrude command is:


Procedure main;


Procedure something (h : handle);

    Begin
    
        setselect (h);

        domenutextbyname ('extrude and edit', 0);

    End; {something}


Begin {main}

    Foreachobject(something, sel=true);     

End; {main}

run (main);

But it didn’t do everything I wanted.

 Page 6 of 8  « First  ... « 4  5  6  7  8 »