Yes I'm still here. So what's been going on these past Six Years?
Well there has been some updating to PortCommodore.com, I updated the Programs and have added a bit or two but I can see it's time to go through and do some refining.
I guess the biggest project has been doPlaces.com, when I started doPlaces I was unemployed while having well over a decade of experience programming, database and web work, and discovered I really needed something of my own that I could direct people to and say, “this is what I can make.” So came the idea to make a better local community directory. I have been doing directories and event calendars on various platforms for years, so I knew much of that. The challenge was to make a better web-based one that what I had seen before.
Most of the web stuff I had done had been pretty vanilla HTML and some awesome PHP in the back, doPlaces was going to be more public facing, so I finally took the plunge into a better style. I found a lot of CSS, as a programmer who works with logical environments, to be pretty brain damaged. I can now see a lot of it was non-programmers (web designers) hacking together their CSS and making a confusing mess then teaching people how to implement it their way. Some also came from the popularity of old versions of Windows' Internet Explorer which didn't always do things like Firefox, Safari, and Chrome did. Unfortunately a lot of unnecessary styling is still out there, exacerbated by people mixing multiple CSS/JavaScript libraries/templates, and also adding in CSS augmentation tools which makes it much easier to complicate the style-sheet even further. (I can't say doPlaces is perfection, but if you ever look at the CSS in it you should find it refreshing)
That also goes for JavaScript, many designers like the fancy animations but don't realize they can be loading in hundreds of kilobytes of unnecessary/unused code by using libraries like jQuery. All this stuff adds up and down the line it makes it a big mess to unravel if you have changes. So, again I have been frugal in my JavaScript finding the meat of whatever bits I need and only implementing that without the overhead (or external dependency). These external dependencies on libraries and templates will haunt you if you do anything long term.
One of the more interesting challenges has been developing for use on phones ant tablets. Not everything that is possible in HTML translates to a phone or tablet. Web controls have to be left-click mostly, there is no easy drag select, control-click select, etc. Then there is screen size, probably the smallest of mobile web displays is about 320pixels wide (just like the Commodore 64!) then if it goes to the desktop you could be on a screen 2000 pixels wide… how do you make it all keep looking good? Again finding good CSS examples of responsive web design and then adopting a design for mobile-first strategy helps a lot.
Looks good and is responsive is where most web designers/developers say “good enough” and walk away. One big part I see lacking in most sites is making it look good on print too, there is another “media” style that you can create so when you print out a page it can look awesome on the printer too, covered that, you don't get exactly the same page when you print on doPlaces (or here for that matter) you get a page that looks good in print.
Next: reporting, to make something that presents a lot of data more useful you should let the user not have to take out a pen and transcribe the data, this has been addressed on doPlaces with the Picks feature where you can select things you like and then create a printable page (with all the phone numbers/address so you don't have to worry about having connection while on the back roads.) You can also email a friend a specially generated link with your picks so you don't have to copy/paste a bunch of links, just copy the convenient “picks URL” and send that.
Common Locations and Maps - Early on I wanted to get into more location savvy functionality so facilities have been created so events link back to the locations where they happen, you can quickly search “nearby” to find things in the area, and you can see where things are on a map.
Promoting the Community - Businesses can print out signs that will let customers scan a QR code and then they quickly find other local businesses/groups/events nearby. There's also signs to let costumers “vote” for their business as a popular top “pick” on doPlaces.
Another aspect is the design of doPlaces originally it was “doItInCalaveras.com” over the years I have been lucky enough to hone down my registration to just “doPlaces.com,” much easier to type and remember. Making Logos and working up unique promotional texts and materials and doing no-budget marketing strategies. (I had learned you can go broke really quickly trying to market a new business in traditional markets).
There is so much more, I could go on, and probably will later - it's late now.
In the meantime check out https://doPlaces.com
~~LINKBACK~~
For those wondering where my Facebook presence is, it isn't anymore.
I don't know how people don't go crazy with all the stuff that comes through their feed. Self indulgent whining, lousy humor, politics, game requests, etc. etc. etc. Maybe its the general political times right now (call it economy if you prefer that word) For me it wasn't all that productive. So I left.
I do have a Google Plus presence, but that one is still working on making their own groove, and don't check in all that much, though I hold hope that it becomes something more worthwhile.
The one that fits me sees to be Tumblr lot less whining, no games and much more tagging and sharing of ideas, things and concepts (check out my follows to see what I mean. If you haven't tried it (and maybe are tiring of Facebook friendship overload) check it out and see if you like it. See something you like, most peoples pages you can click on it and see who else re-blogged it and check out their blog, when you find someone who is interesting you follow them, etc. Don't lie their stuff, don't follow - no harm.
So far I'm finding the positive/creative community I've been wanting from Facebook.. Though there seems to be a lack of Classic computing stuff (in English) will need to help contribute to that community - maybe I'll see you there.
~~LINKBACK~~ ~~DISCUSSION~~
Of all the things about CommVEx I have one “PET” peeve (well pet peeve, but couldn't stop thinking about the Commodore PET) that has bugged me (and from mutterings, a couple other folks share in the frustration). It is the doorprize program. I love the idea that the program is ran on the Commodore, I like that the computer randomly chooses… but.. I've noticed (like most random programs) it favors the center of the distribution and also can pick the same person twice… (unless you keep the program running… which isn't feasible).
So one of my self-inflicted projects is to make a 21st century doorprize drawing program for the 64.
Well that's the working name. This is about version .7 as not all the features or interface has been implemented, but enough where it could be put to work right now.
Let me go over the features so far:
Heres my code so far:
{renumber} {alpha:upper} {number:10} {step:10} rem *** random draw *** rem by larry anderson v.07 9/25/2011 rem designed to have a non-repeating random door prize draw rem which includes tracking of winners rem with the ability to save/load draws in progress rem ========== rem formatted for C64list by Jeff Hoag rem conversion command: C64List randomdraw.txt -prg:random.prg rem poke 53280,15:poke 53281,0:print"{white}{clear}" print "random drawing program - by larry anderson 9/2011" gosub {:initvars} {:mainmenu} print "{rvrs on}draw menu---------{rvrs off} print " 1 - draw prize" print " 2 - list names" print " 3 - list winners" print " 4 - add names" print " 6 - load data" print " 7 - save data" print " 8 - produce report" print " 0 - reset draw stats" print " q - quit program" print "enter option:";:inputm$ ifm$="1" then gosub {:drawprize} ifm$="2" then gosub {:listnames} ifm$="3" then gosub {:listwinners} ifm$="4" then gosub {:addnames} rem ifm$="5" then gosub ifm$="6" then gosub {:diskload} ifm$="7" then gosub {:disksave} ifm$="8" then gosub {:makereport} rem ifm$="9" then gosub ifm$="0" then gosub {:resetdraw} ifm$="q" then gosub {:endroutine} goto {:mainmenu} end {number:500} {:endroutine} ifdc%=0 then goto {:endroutine1} print "!!!!!data has not been saved, exit anyway? (y/n)"; input q$ if q$<>"y" then print "exit aborted.":return {:endroutine1} end {number:1000} {:initvars} rem *** initialize variables *** rem arrays - names, current draw status, prize names, prize winners, temp dim nm$(200), dr%(200), pz$(100), pw%(100), tp%(200) nn%=0: nw%=0: rem number of names, number of winners dv%=peek(186):fi$="namefile":rem default device and file name dc%=0:rem data change flag if 1, data has changed since last save. return {number:1500} {:drawprize} print "{rvrs on}draw for prize{rvrs off}" print " options: yes/no/reset list/cancel" print " (y/n/r/c)" if nn%=0 then print "!-no names in database":return gosub {:getdrawlist}:rem *** get draw list rem *** if all have been drawn, reset draw list if tc%=0 then rd%=1:gosub {:getdrawlist} if tc%=0 then print "!-no eligible names to draw":return {:drawprize1} rem *** select randome winner *** wn% = int(rnd(1)*tc%) rem confirm winner? print "from "+str$(tc%)+" names; "; print "is "+nm$(tp%(wn%))+" present ";:input a$ if a$="y" then goto {:drawprize2} if a$="r" then rd%=1:gosub getdrawlist:goto {:drawprize1} if a$="c" then return print "!-name not selected... redraw":goto {:drawprize1} {:drawprize2} print "enter prize won: ";:input pn$ rem record changes dr%(tp%(wn%))=1:pw%(nw%)=tp%(wn%):pz$(nw%)=pn$:nw%=nw%+1:dc%=1 return {number:2000} {:listnames} print "participant list:" for x=0to nn%-1 print str$(x+1)+" "+nm$(x); if dr%(x)=2 then print " {red}(win disabled){white}"; if dr%(x)=1 then print " {yellow}(selected this round){white}"; print next x print "==========" return {number:2500} {:addnames} print"{rvrs on}add new participants{rvrs off} enter zz to exit" print"enter name, short with no commas or quotes:" {:addnames1} print"enter name: ";:input n$ if n$="zz" then goto {:addnames3} ifnn%=0then goto {:addnames2} ne% = 0 for x=0to nn%-1 if nm$(x) = n$ then ne%=1 next x if ne%=1 then print"!-name exists, enter a unique one.":goto {:addnames1} {:addnames2} nm$(nn%) = n$:nn%=nn%+1:print"+-name "+str$(nn%)+" added":dc%=1 goto{:addnames1} {:addnames3} print "==========" return {number:3000} {:listwinners} print "{rvrs on}winners list{rvrs off}" for x=0to nw%-1 print str$(x+1)+" "+pz$(x)+"->"+nm$(pw%(x)) next x print "==========" return {number:3500} {:makereport} print "report coming soon" return {number:4000} {:resetdraw} rd%=1:gosub{:getdrawlist} print "{rvrs on}draw list has been reset{rvrs off} "+str$(tc%)+" names eligible."; return {number:4500} {:getdrawlist} tc%=0:rem *** reset draw list and get names not already drawn *** for x=0 to nn%-1 if dr%(x)=1 and rd%=1 then dr%(x)=0: if dr%(x)=0 then tp%(tc%)=x:tc%=tc%+1 next x rd%=0 return {number:5000} {:disksave} rem *** record data to disk *** print "device #: "+str$(dv%) print "{up}{right:10}";:input dv% print "file name: "+fi$ print "{up}{right:11}";:input fi$ open 15,dv%,15,"s0:rd-"+fi$:close15 gosub {:errorcheck} open 2,dv%,2,"0:rd-"+fi$+",s,w" gosub {:errorcheck} if e%<>0 then goto {:disksave2} rem store number of names and names print#2, nn% for x=0 to nn%-1 print#2,nm$(x):print#2,dr%(x) next x rem store number of winners list and name number print#2, nw% if nw%=0 then goto {:disksave1} for x=0 to nw%-1 print#2,pz$(x):print#2,pw%(x) next x {:disksave1} print#2,"" :rem extra line for padding. gosub {:errorcheck} {:disksave2} close 2 if e%<>0 then print "!-device error "+e$: goto {:disksave3} print "data saved, no errors.":dc%=0 {:disksave3} return {number:5500} {:diskload} print "device #: "+str$(dv%) print "{up}{right:10}";:input dv% print "file name: "+fi$ print "{up}{right:11}";:input fi$ nn%=0:nw%=0:rd%=0 rem *** load data from disk *** open 2,dv%,2,"0:rd-"+fi$+",s,r":gosub {:errorcheck} if e% <> 0 goto {:diskloaderror} rem number of names, names and thier current draw status input#2, nn% for x=0 to nn%-1 input#2,nm$(x):input#2,dr%(x) next x rem number of winners and prizes, winner number if winners input#2, nw% if nw%=0 then goto {:diskload1} for x=0 to nw%-1 input#2, pz$(x):input#2,pw%(x) next x {:diskload1} gosub {:errorcheck} if e%<>0 then {:diskloaderror} print "data loaded sucessfully.":dc%=0 close 2: return {:diskloaderror} print "!-device error: "+e$ close 2:return {number:6000} {:errorcheck} open 15,dv%,15 input#15, e%,e$,t%,s% print e%,e$,t%,s% close15 return
Nice thing about C64List is that I can do formatting for the non-commodore text version for readability, do search and replace (like when I hit a reserved variable) and scroll about quite easily. Also given that I have more stretching room I am working on saving variable space by using integers when possible, working on good naming and labeling, etc. This also gives me a better “big picture” view to reduce redundancy of common routines. Sill getting a handle on the pseudo op tokens (like changing colors, etc), its pretty straightforward.
Whats next? Better formatting, an option to skip over names (i.e. they were present on the first day, but not on the second, so we want them still listed in history but not considered for the later draws… you will notice I have some code to handle that circumstance already, but nothing to flag them yet). As well as a report producer suitable for printing or as text for a news article. Also it still uses Commodore BASIC's RND function which isn't optimal… that will be enhanced too.
Transfer from Linux to the 64 is via an SD card with a uIEC-SD drive http://store.go4retro.com/products/uIEC_SD.html on the 64 or testing locally in the VICE Commdore emulator http://www.viceteam.org/ in immediate mode.
~~LINKBACK~~ ~~DISCUSSION~~
(sorry if this is a bit nonsensical as I am working out my terminology still)
In order to access pages below the root we need to have the code collect a list of pages accessible
There is one main direct access rout via a “?do=directname” parameter, as well as script-defined routes via a “?go=#######” parameter.
The do parameters are stored in the /wanda/app/.. directories below the root in the info.php file, these also include the access group information as well as a user access menu list for building “go” lists… more or less the “drag and drop entry” for that application.
here is an example of a an info.php file,
INFO.PHP in (/wanda/app/calendar/)
// group settings for application group 'calendar': // note application group is the same name as the directory... $wandagroup['calendar'] = array( 'name' => 'Event Calendar' ,'description' => '' ,'level' => array( 1 => 'Guest - Can view Calendars' ,2 => 'User Access - Can see Email addresses' ,3 => 'Data Access - Can add to Calendars within department' ,4 => 'Manager Access - Can manage calendars' ,5 => 'Admin - can do all administrative functions.' ) ); // menu information for the application: // for group - Calendar $wandamenu['calendar'] = array( //main menu entry information, application name, menu description, and app icon (in public_html/wanda/icon/) 'name' => 'Event Calendar' ,'description' => 'Event Tracking Calendar' ,'icon' => 'calendar.png' // the user access scripts in the menu // name, icon, link (init means they begin the page chain) // minimum user level to access. ,'submenu' => array( 'calendar' => array( 'name' => 'Calendar' ,'icon' => 'calendar.png' ,'link' => 'init' ,'level' => 1 ) ,'search' => array( 'name' => 'Calendar Search' ,'icon' => 'calendar_edit.png' ,'link' => 'init' ,'level' => 1 ) ,'report' => array( 'name' => 'Calendar Reports & Tools' ,'icon' => 'page_white_text.png' ,'link' => 'init' ,'level' => 1 ) ) ); // direct-access entries via the go? parameter ( i.e. wanda.php?go=calendar) $wandadirect['calendar'] = 'calendar/pubcal.php';
So to build a list of all the direct links we include in all the info.phps in all the subdirectories of /wanda/app:
PAGELIB.PHP (continued)
//if "do" read in direct links, then, if it exists, go to it. if(isset($_GET['do']) || isset($_POST['do'])) { //read in app defaults... $wandagroup = array(); $wandamenu = array(); $wandadirdata = opendir( WANDA_APPS ); while (false !== ($wandafile = readdir($wandadirdata))) { if ($wandafile != "." && $wandafile != "..") { $wandainfo = WANDA_APPS.$wandafile.'/info.php'; if(is_file($wandainfo)) { include $wandainfo; } } } $wandadocode = cleanValue((isset($_GET['do']) ? $_GET['do'] : $_POST['do'] )); if(isset($wandadirect[$wandadocode])) { define('WANDA_APP' ,WANDA_APPS.substr($wandafile,0,strpos($wandafile,'/')+1)); include WANDA_APPS.$wandadirect[$wandadocode]; exit(); } }
In older version of WANDA I had the menus and such in a database table, which would be prone to problems if the DB was damaged or could be compromised by another rouge script. This feels more sturdy as well as secure.
Scripts that are direct access with forms can just use (as an example) wanda.php?do=calendar for their form action, it will submit back to the same page (or use another direct page entry if that is your thing)
If we fail this part we will leave direct access (except at the end to force login), so in next part we will go to user access, using links with sessions, and all that other goodness.
~~LINKBACK~~ ~~DISCUSSION~~
In the last part I discussed the file structure. Everything will come from one main script, (i.e. index.php)
that script will have the minimum of code, everything else will be fed from deeper libraries.
session_start(); ini_set('display_errors', 1); // define base wanda path, below web root $home = $_SERVER['SCRIPT_FILENAME']; $loc = explode('/',$home); define('WANDA_BASE', implode('/',array_slice($loc,0,-2)).'/'); // Hand over to the page handler require WANDA_BASE.'wanda/inc/pagelib.php';
Thats it. What it does is define the path WANDA_BASE to below web root, then goes and includes the pagelib.php file, which partly includes much of what is needed to get around in the directories.
//define directory constants // home page define('WANDA_INDEX', $home); // above root libraries define('WANDA_LIB', implode('/',array_slice($loc,0,-1)).'/wanda2/'); // above root icon images define('WANDA_ICON', 'wanda2/icon/'); // above root images define('WANDA_IMAGE', 'wanda2/image/'); // below root apps folder define('WANDA_APPS', WANDA_BASE.'wanda/app/'); // below root includes (function libraries) folder define('WANDA_INC', WANDA_BASE.'wanda/inc/'); // System configurations folder (db settings, etc. define('WANDA_CONF', WANDA_BASE.'wanda/conf/');
so to call different programs we will need to have a system to have the core script make available or access the programs that will not be browser accessible.
The big challenge was figuring out where to go from here. I've devised three modes:
Next up I will go about highlighting some of the page access magic.
~~LINKBACK~~ ~~DISCUSSION~~