Software Developer/Oru Kayaker. Every keystroke at this site came from me. I'm the sole proprietor.
Employment Blog
Front/Back End Web 2.0 PWA developer.
Troubleshooter
Lifecycle Documentation
Availability and Best Way to Contact:
Paul is available for remote work or onsite work local to Orange County CA. Not considering other locations.
USA Citizenship
Best way to contact: tetraInfoTech@gmail.com
I get lots of calls and emails from all over the planet every day. Few are a fit. Use email. Do NOT phone please ... its on DND.
Please put summary info in Title; for example: 1099 Go FullStack in Seattle GOOG, FTE FrontEnd Redmond MSFT, w2 Contract PreactJS Tetra Tech Bellevue.
Then, list the rate to be paid. Standard rates appear below.
For immediate consideration, include the name/acronym of my company. Plural is ok too :-) ....
Rates: 1099: $85/hour; W2 Contract: $75 per hour onsite, $60 remote.
Wish I could: Write a PreactJS UI for a Loihi Neuromorphic Computing Project, with a service worker talking to a Golang API endpoint. Lately, doing a native JavaScript UI implementing the Bluetooth API, storing locally and sending telemetry to MongoDB Atlas Data API.
Highlights From a Diverse Career:
- Fred Hutch Cancer Research Center Developed the Hutch Grants Funding Proposal System. Customized the Huron Click Grants 8 Portal Web Application (.NET entity-framework) using Jscript, C#, HTML, CSS, entity-management, site-designer. Developed comprehensive Protractor Automated Test Suite; I can now apply for a Federal Grant in my sleep :-)
- Agilysys Rebuilt an existing (OpenTable-like) public facing reservation widget in AngularJS and .Net MVC C#. Then rapidly prototyped an enterprise availability system with NodeJS reusing key parts of the earlier project.
- Lexipol Helped get this noble Knowledge Management web application for Police and Fire Agencies back on its feet. Did major refactoring to make the UI more obvious and intuitive, faster, .... ExtJS JavaScript and Java API Backend. Was interesting to see the Use of Force policies and training at various agencies.
- Thales In Flight Entertainment. Our team wrote a Single Page Web Application to track on-aircraft Entertainment System maintenance using AngularJS and Bootstrap. Wrote Angular Directives, Services, Controllers, etc. Wrote backend MVC in Java. The App had over 60 data models, yet it was live in 50 days.
- Sperion. Our team wrote a Single Page Web Application in EXT-JS for aftermarket vehicle telematics. Used by lenders to locate vehicles via embedded GPS/cell-network connection. API in Groovy.
- MaestroDev.com. Part of a small start up creating an enterprise DevOps CI/CD application. Maintained and upgraded UI for Maestro J2EE/JRuby application (not the public website). Added dynamic information features using jQuery. Resolved memory leak and performance issues.
- Intuit #2. Updated public-facing support site to use out new Q & A search capability. Created mobile-ready First-Class Agent support application. Featured JSPs, AJAX, HTML5, JavaScript and CSS.
- Green Acre Farms. Authored a mobile chemical spray web database application.
- Level Studios. Authored UI forms and widgets for (Qualcomm) mobile application marketplace. Featured static html, dynamic html, REST, AJAX, jQuery library
- Intuit. Authored static and dynamic web pages for secure credit card website. Featured Apache-proxy to REST, AJAX, jQuery library
- Verizon Wireless. Authored dynamically-constructed, CMS-driven, Web 2.0 front-end for a high-volume Section 508-compliant eCommerce website; featured REST, AJAX, Mootools JS library, SWF embedding with seemless JavasScript failover for low-bandwidth connections, and distribution via Content Delivery Network. Later various JSP/JSTL pages.
- AT&T. J2EE (Web Service/SyncML) architect.
- Trane. Member of an allstar JavaScript team that decreased application response time of a highly visible RIA SOA Web 2.0 embedded application from 8 seconds to 1.2 seconds -- in a matter of 6 weeks. Included embedded Flash animations and charting.
- Roy Farms. Created/rolled-out out bilingual client/web application for the food-safety traceability of hops. Created a directory framework to organize the 70+ Lotus Notes/Domino workflow, bonded wine storage, inventory and tracking applications that I have developed as a part-time contractor over the past decade.
- Boeing.
Authored J5J Search, a multi-datastore colimation tool, in Java. Performed the heavy-lifting to enable a 19 database web application to work offline and synchronize large volumes of data with multiple peer supplier applications. Initial architect of a web-enabled Project Management Information System that has produced over 120 instances. Part of a team that rebuilt, reduced and migrated a 135 database application to a framework of 25 databases. Conceptualized and implemented a data synchronization Web Service suite between a Domino and .NET application.
- Unisys. Single-handedly developed a complete Notes-based Project Management System (Data, Schedule, Budget) in less then 3 months.
- PDA Solutions. Created FieldChart, a hand-held electronic medical record system that synchronized with a relational DB and produced audit-proof medical records and reduced the pay cycle from 180 days to 30 days.
- Direct Current To Light. Designed low-cost digital circuitry and singly-coded EPROM resident controller for a TV-FM converter in 2 months (via an object-oriented 8051 assembler I wrote in HyperCard)
- Infotec Development. Invented and built a novel technology for measuring
Instrument Landing System signals (US Patent #5,323,332) (PIR IDI Contract). Earlier, lead a team that reverse engineered the software in a Mission Critical radar system controller – the originating aerospace company didn't believe it could be done.
- CAST.
Managed a soft team of gifted individuals that created some of the first GPS Navigation User Equipment software.
-
Hughes.
Solved a difficult problem that had stymied a team of over 100 programmers from delivering a complex classified multi-processing system. Created the first automated software for estimating the cost and schedule for creation and maintenance of technical manuals.
- Outstanding Master's Thesis Award. A detailed study of a 128 node Dataflow computer designed and analyzed down to the gate level. Side effect: purchased an Osborne to write the 132 page document, starting my journey into software.
Technical Skill Summary
Front End: PreactJS is my current favorite. Ready-made for PWA. Tiny, pages dance and a pleasent syntax. Historically am a Web 2.0 SPA client-side dev type ... tools are object-oriented dynamic JavaScript, AJAX/ XHR, CSS/SASS, HTML5, JSON, JSONP, AngularJS, jQuery, and DOM-native.
Backend Persistence: SQL, NoSql, Entity-Framework, Object
Backend Languages: Golang. JavaScript 1.7, JScript, Java, LotusScript, C# (novice)
Payload Architect: Use Cases, Interface Specs, Functional Specs, REST Payload Optimization, Presentations, User Manuals
Mark-Up: XML, XPATH
Source Control: Git, Team Studio, Subversion
Embedded: C, Unix/Linux, NewtonScript, WINce, Assembly 8051/68000/Z80
>
Protocols: TCP/IP, TLS, FTP
Other: Expert Systems, Neural Networks (aka Machine Learning), Hardware Design
Education
Recent IDEs: Visual Studio Code, Huron Click, Visual Studio, Go IDE, JetBrains, Playframework, Eclipse, Notepad++
Soft Skill Summary
- Writing: Use Case, Specifications, Bid & Proposal, White Papers, and Technical Manuals.
- Customers: Technical Support and Resolution
- People: Group/Team Lead, and Technical Program Manager (28 reports).
Older Skills
- Hardware Design: Analog and Digital Hardware
- Niches: Master troubleshooter
Computer Technician, Network Administrator, Server Administrator
- Builds commodity servers from scratch
- Installs network wiring, configures wireless
- Installs VM, server OS, web servers, component containers
- Configures routers, VPNs and VoIP.
- Configures Cloud Environments
- Troubleshoots PC issues
He can be contacted directly at tetrambs@gmail.com.
Education: B.S. Bellevue College 2020, A+ Certification, several Microsoft Certifications
GIS Technician, Photo Analyst, Data Entry Tech, QA
Details. Heather does them well.
Snippets of code from Antiquity...
A simple JavaScript Ajax demo
This sample demonstrates the use of a view object and an xhr object.
In Modern JavaScript, done with the more obvious Async/Await syntax.
Before that done with Promises.
Before that done with function Callback, often from some library.
xhr = {
//normally we would use a platform (jQuery or dojo xhr) AJAX call,
//but for purposes of showing how it really works, I've rolled my own
serviceURL: "services/experDemo.json",
get: function(service,param) {
if (typeof window.ActiveXObject != 'undefined' ) {
xmlDoc = new ActiveXObject("Microsoft.XMLHTTP");
xmlDoc.onreadystatechange = this.callback ;
}
else {
xmlDoc = new XMLHttpRequest();
xmlDoc.onload = this.callback;
}
//stub file for this demo
var url=this.serviceURL + '?' + service + '=' + param;
xmlDoc.open( "GET", url, true );
xmlDoc.send( null );
},
callback: function() {
//asysnchronus callback
if ( xmlDoc.readyState != 4 ) return ;
var respObj=eval(xmlDoc.responseText);
view.setResult(respObj);
}
};
view = {
getCityList: function() {
var zip=document.forms[0].zipCode;
xhr.get('zipCode',zip.value);
},
setResult: function(obj){
var label=document.getElementById('label');
label.style.display='inline';
var target=document.getElementById('CityList');
target.innerHTML="";
if (obj==null) {
target.innerHTML="none found matching zip";
}
else {
for (i=0; i<obj.length;i++) {
target.innerHTML+=obj[i].cityName+", "+obj[i].stateCode+<br />';
}
}
}
};
Compare with a 2020 Preact Component's componentDidMount async await fetch built into the browser
async componentDidMount() {
let response = await fetch(API + this.state.verb + "=" + this.state.text);
let json = await response.json();
if (json && json.count > 0) {
let rows = json.payload;
this.setState( { rows } )
for (var i=0; i< rows.length; i++){
rows[i].city = rows[i].consumer.city;
rows[i].make = rows[i].vehicle[0].make;
rows[i].rgn = rows[i].consumer.state;
rows[i].formerInsurer = rows[i].coverage.former_insurer;
}
}
else {
this.setState( { rows: [] } )
}
}
|
MySQL Trigger:
This sample records a history of changes to data in a ticket table into another table that records the revisions.
MySQL Trigger:
This sample records a history of changes to data in a ticket table into another table that records the revisions.
CREATE TRIGGER chg AFTER UPDATE ON tickets
FOR EACH ROW BEGIN
INSERT INTO revision
(ticketID, event, empID, dt) VALUES
(OLD.ticketID, 'MODIFY', OLD.empID, OLD.dt);
END;
|
An Oracle OUTER JOIN or LEFT JOIN Example:
This sample shows how to get the names for a transaction table after May 12 in descending order
even if there isn't a nameidx in the right-side fc_name table
SELECT p.empnameidx as 'Emp ID', p.rate, p.amt, p.phaseidx as 'Phase ID', n.lastname
FROM pr_trx_detail p LEFT JOIN fc_name n
ON p.empnameidx = n.nameidx
WHERE p.trxdate > '12-MAY-2008'
ORDER BY p.amt DESC
|
An example of a API URL that generates a Domino report from a Java Agent
This url that can be sent via email for example:
http://royfarms.com/mdwinestore/portal.nsf/report?openagent&query:[form]%3Dlot+or+([form]%3Dload+and
+[type]%3DIncoming)+and+[_CreationDate].GT._30DaysPast+and+[customerIdent]%3D98072& ....
The url corresponds to a Domino Full Text Query
[form]=lot or ([form]=load and [type]=Incoming) and [_CreationDate]>_30DaysPast and [customerIdent]=98072
that returns a tabular report ... most folks don't realize Domino can be programmed "relationally" ...
afterall, it's all just *SET THEORY*
|
And the Java that parsed it ...
package urlParser;
import java.util.*;
/**
* StringUtils
* A collection of useful string utilities developed in prehistoric Java days.
* @author Paul Smith
*
*/
class StringUtils{
/**
* parseURL
* Parse a set of url symbol:value pairs into a Hashtable so that it be accessed by symbol
* @param str string of symbol-value pairs; i.e. &symbol_1:val_1&symbol_2:val_2
* @param delimRow typically an ampersand &
* @param delimCols typically a colon :
* @return a Hashtable of the symbol-value pairs
*/
public Hashtable parseURL(String str, String delimRows, String delimCols) {
Hashtable table = new Hashtable();
try
{
StringTokenizer tableRows = new StringTokenizer(str, delimRows);
int numRows = tableRows.countTokens();
int i = 0;
final int PAIR=2;
do
{
String row = tableRows.nextToken();
StringTokenizer tableCols = new StringTokenizer(row,delimCols);
int numCols = tableCols.countTokens();
if (numCols == PAIR)
{
String label = tableCols.nextToken();
String content = tableCols.nextToken();
table.put(label,content);
}
i++;
tableCols=null;
} while (i < numRows);
}
catch(Exception e)
{
System.out.println("Exception thrown in parseURL");
}
return table;
}
// ...
}
|
An example of some PHP code that connects to a MySQL db
<?php
//this code shows how to:
//receive input via a xhrget
//connect to a db
//determine if its an update or insert
//respond with a table of data
header('Content-type: application/json');
function showerror()
{
die("Error " . mysql_errno() . " : " . mysql_error());
}
//(1) open the database connection
$connection=mysql_connect("localhost","userName","password");
//(2) open connection and select binticket database
mysql_select_db("binticket",$connection);
//(3) set target table for data to be inserted or updated
$targetTable="tickets";
//(4) retreive from url of xhr get
$ticket=$_GET["ticket"];
//pad leading zeros if necessary
$ticket=str_pad($ticket,5,"0",STR_PAD_LEFT);
//samething, but padding incorporated in input line
$emp=$_GET["emp"];
if (strtolower($emp)=="void")
{
$emp="void ";
}
else
{
$empval=intval($emp);
$emp=str_pad($empval,5,"0",STR_PAD_LEFT);
}
//(5) see if the row with primary key ticketID already exists
$searchQuery = "SELECT ticketID FROM {$targetTable} WHERE ticketID={$ticket}";
$result=mysql_query($searchQuery,$connection);
if(mysql_num_rows($result)==0)
{
print "Inserted Data";
$insertData="INSERT INTO {$targetTable}
(ticketID,empID)
VALUES ('{$ticket}','{$emp}')";
}
else
{
print "Existing Data, updated if new empID";
$insertData="UPDATE {$targetTable}
SET empID='{$emp}'
WHERE ticketID={$ticket}";
}
//(6) interface with the database table
if (!mysql_query($insertData,$connection))
showerror();
//(7) Query the database and output to the xhr handler as a table
$query="SELECT ticketID, empID, dt FROM tickets order by ticketID";
$result=mysql_query ($query, $connection);
print "<Table border=1 cellspacing=0 cellpadding=3>";
print "<TH>Bin Ticket</TH><TH>Employee ID</TH><TH>Date</TH>";
//While there are still rows in the result set, get the current row into the array $row
while ($row=mysql_fetch_array($result))
{
print "<TR><TD> {$row["ticketID"]} </TD><TD> {$row["empID"]} </TD><TD> {$row["dt"]} </TD></TR>";
}
print "</Table>";
?>
|
AJAX with a LotusScript Agent as the backend.
Note: even works without modification in the Domino Offline Services mode, so the Web Application functions in a disconnected environment like an aircraft.
Sub Initialize
'note the colon : char seems to interrupt the xml stream
'this AJAX agent uses the bems, list of source fields and list of target symbols
'to provide a web server for various name related pickers
Dim s As New NotesSession
Dim db As NotesDatabase
Dim doc As notesdocument
Dim qString As String
Dim thisAgent As String
Dim bems As String
Dim fieldList As String
Dim symbolList As String
Print "Content-Type: text/xml" 'xml output
Set doc = s.documentcontext
Set db = s.currentdatabase
qString = doc.QUERY_STRING(0) + "&"
thisAgent = takeFromFifo(qString,"&")
bems=takeFromFifo(qString,"&")
fieldList=takeFromFifo(qString,"&")
symbolList=takeFromFifo(qString,"&")
''fieldList and symbol list might look like this:
''fieldList ="EmailAddr,RepTelNbr,MsCd,RepDsgntdTtl,repnm,repnm,"
''symbolList="RegMgrEmail,RegMgrTel,RegMgrMailCd,RegMgrTtl,RegMgrDisp,RegMgr,"
Print ""
Print getAJAXinfo(s, db, bems, fieldList, symbolList)
Print ""
End Sub
Function getAJAXinfo(s As notessession, db As notesdatabase, bems As String, fieldList As String, symbolList As String) As String
'this function will return a formatted string consisting
'of info from the rep data document as described in fieldList
'and return a keyed list as set in symbolList
Dim vStatic As notesview
Dim staticData As notesdocument
Dim path As String
Dim lookupDB As NotesDatabase
Dim vBEMS As notesView
Dim repDataDoc As notesdocument
Dim field As String
Dim symbol As String
Dim fieldVal As String
Dim tv As String
On Error Goto ErrorHandler
Set vBEMS=db.GetView("BEMS")
Set repDataDoc=vBEMS.getDocumentByKey(bems,True)
If repDataDoc Is Nothing Then
getAJAXinfo="Error=not found"
End If
'systematically find the info in the doc and tag with the symbol = value &~
tv=""
field=takeFromFifo(fieldList,",")
While Not field=""
fieldVal=Cstr(repDataDoc.getItemValue(field)(0))
symbol=takeFromFifo(symbolList,",")
tv=tv & symbol & "=" & fieldVal & "~~"
field=takeFromFifo(fieldList,",")
Wend
getAJAXinfo=tv
Exit Function
ErrorHandler:
Print "Error=repdataAJAX.getAJAXInfo agent at line " + Cstr(Erl) + Error
End Function
Function takeFromFifo(fifo As String, delim As String) As String
'return the first item in the queue and delete it from the queue
Dim takeStr As String
Dim x As Integer
x = Instr(fifo, delim)
If x > 1 Then
takeStr = Left(fifo, x - 1)
fifo = Right(fifo, Len(fifo) - x)
TakeFromFifo = takeStr
Else
TakeFromFifo = ""
End If
End Function
|
Perhaps an interesting C/C++ web demo ...
//potential web demo ... have a uav fly inside a dojo animation on the web
//then let people fly the uav over google earth
#include
using namespace std;
// typedef allows us to give something a new simpler name
typedef struct position UAVState;
typedef struct weapon WEAPON;
typedef struct inventory INVENTORY;
//a global data element
struct position {
float lat;
float lon;
};
//many weapons in a in single mission's worth of UAVWeapons
struct weapon {
int ammoCount;
char *name;
int damage;
};
struct inventory {
WEAPON weapon1; /* struct within a struct */
char *name;
int missionIDent;
};
//declare prototype global functions
void info(UAVState uav);
UAVState update(UAVState *r);
UAVState init();
int main() {
UAVState uav= init();
printf("\nPosition After Init ");
info(uav);
update(&uav);
printf("\nPosition After Update ");
info(uav);
//initialization should be moved to a sub
INVENTORY manifest = {
{100, /* onboard.weapons.count */
"GPS Guided Grenades", /* onboard.weapons.name */
16}, /* onboard.weapons.damage =16 ft circle*/
"IED Positioning Deter", /* onboard.name */
867}; /* onboard.missionID */
INVENTORY *onboard;
WEAPON *weapons;
onboard = &manifest;
weapons = &manifest.weapon1;
printf("Goal: %s\n", onboard->name);
printf("Mission ID: %d\n", onboard->missionIDent);
printf("Weapons: %s\n", weapons->name);
printf("Damage radius: %d meters\n", weapons->damage);
printf("Inventory remaining: %d\n", onboard->weapon1.ammoCount);
return 0;
}
void info(UAVState uav) {
printf("%f %f\n", uav.lat, uav.lon);
}
//this creates and returns a new static UAVState object
UAVState init() {
UAVState uav={33,68};
return uav;
}
//this updates an existing UAVState object
//note: we pass a handle to an existing object
UAVState update(UAVState *uav) {
//for example
uav->lat =33.551667; //normally a device output read
uav->lon =68.536611;
}
|
Various Collected Go Recursion Snips ...
package main
import "fmt"
import "math/rand"
func factorial(i int)int {
if(i <= 1) {
return 1
}
return i * factorial(i - 1)
}
func sum(numbers []int) int {
if len(numbers) <= 1 {
return numbers[0]
}
return numbers[0] + sum(numbers[1:])
}
func max(list []int) int {
if len(list) == 2 {
if list[0] > list[1]{
return list[0]
}
return list[1]
}
subMax := max(list[1:])
if list[0] > subMax {
return list[0]
}
return subMax
}
func count(list []int) int {
if len(list) == 0 {
return 0
}
return 1 + count(list[1:])
}
func binarySearch(list []int, target int, low int, high int) (index int, found bool) {
if low > high { //indexes crossed over, item not found
index = -1
found = false
} else {
mid := (high + low) / 2
if target < list[mid] {
index, found = binarySearch(list, target, low, mid + 1)
} else if target > list[mid] {
index, found = binarySearch(list, target, mid + 1, high)
} else if target == list[mid] {
index = mid
found = true
} else {
index = -1
found = false
}
}
return
}
//for a given ordinate, returns its corresonding fib number
func fibonacciRecursion(n int) int {
if n <= 1 {
return n
}
return fibonacciRecursion(n-1) + fibonacciRecursion(n-2)
}
func quickSort(arrayz []int) []int {
if len(arrayz) <= 1 {
return arrayz
}
median := arrayz[rand.Intn(len(arrayz))]
low := make([]int, 0, len(arrayz))
high := make([]int, 0, len(arrayz))
middle := make([]int, 0, len(arrayz))
for _, item := range arrayz {
switch {
case item < median:
low = append(low, item)
case item == median:
middle = append(middle, item)
case item > median:
high = append(high, item)
}
}
low = quickSort(low)
high = quickSort(high)
low = append(low, middle...)
low = append(low, high...)
return low
}
func main() {
i := 5 //factoral
fmt.Printf("Factorial of %d is %d\n", i, factorial(i))
numbers := []int{4,6,8,100, 101}
fmt.Println("Sum is: ", sum(numbers))
fmt.Println("Max is: ", max(numbers))
fmt.Println("Count is ", count(numbers))
target := 100;
index, found := binarySearch ( numbers, target, 0, len(numbers)-1 )
fmt.Println("Search index is", index , found)
//generate the sequence for the first n numbers
const SLEN int = 8
fmt.Printf("Fibonacci Recursion:")
for n:=0; n < SLEN; n++ {
fmt.Print(" ", fibonacciRecursion(n))
}
randArray := []int { 100, 200, 30, 40, 45, 2, 0}
fmt.Println("")
fmt.Println("Sorted array is", quickSort(randArray))
}
|
I've learned a few things over the last 30 years. These tips have worked with:
-Punch card environments
-Bare-bones assembly language environments; i.e. CPU/RAM/ROM/IO on a chip
-mini-computer terminal environments
-real-time embedded systems
-client server systems
-handheld systems
-enterprise systems
They are:
-
Maintain a forward velocity of "working stuff". Problems are best introduced and resolved one at a time. It's perfectly OK to write a simple test case, write a bit of code and then see if the machine does what you expected it to do. Then add more test cases, a few more lines of complexity and see how that works. Repeat again and again until the system is solid and polished.
-
If you can't figure out where it's broken, determine where it's NOT broken. That leaves a smaller space to focus on.
-
It's OK to think outside your box. Your brain only has 3-bits, a FINITE small cache that takes 2 weeks to rebuild, and a big tape archive that can be reloaded into cache. It's merely HUMAN to rely on more then your memory to recall or retrieve the specifics of a syntactical pattern.
Before Internet Search, that meant consulting a reference book or looking at some reference code. But now one can just Google-around for the meta pattern. The code will often come together much faster and better. For example, Google on: "example of looping construct in python".
-
Your personal spiking neural net is the ultimate classification engine. But Software can only do 4 things: assign, branch, loop and call another piece of software. Classify complex problems into smaller/simpler problems that you can hold in your head.
-
In order to master some unfamiliar technology, read what documentation there is Five Times. Then "discover" its working principals Three more times. Neuron pathways strengthen with use.
Questions and Observations
"Problems are solved by insight, yes. But there's no insight that doesn't go back to some actual experience sometime, somewhere." -- Rudolf Flesch, The Art of Clear Thinking, 1951. Robots, Apes and You.
Do New Products and Tool-Uses happen by Accident or by Design?
10 Products Discovered By Accident
I recall from my stint at Boeing that the fuel savings feature of the Boeing 787 (product trademark) were discovered accidently while searching for a way to make a subsonic jetliner. And, of course, that notorius incident from Antiquity involving the tub and Archimedes :-).
With that in mind I allow myself the freedom and time to explore, looking for the three dimensional sweet spot.
- Content is King
- Speed Is Life
- Just Enough Information
Doing it this way allows me to minimize the Activation Energy, which is key to retention.
Then comes the Creative Part.
- First, I rough sketch a layout in a notebook.
- Then, I mock up the page in HTML directly with an editor, like Visual Strudio Code.
- Then Discover interesting looks by playing with it in Chrome; throw in a Canvas or SVG directive if it needs to move.
- Then see what sticks in the foreground.
- Then see what sticks in the background.
Costly PhotoShop (registered mark of Adobe Inc) license, design agency and overly-complex design not required.
This is my playground. A couple of UI projects written in JavaScript that will solely execute in your browser, not requiring a backend. And some tongue-in-cheek Golang source code. Some test-driver code from the Grants project. For UI demos below ... right click and open your browser's Inspector. With the exception of the recent Preact project, source code is available under the Sources Tab.
Think of this page as a museum exibition of UI Code Over Time. Hover over each link.
Lately I want to skip the modern bloatware platforms and instead make applications that are small and fast.
The native DOM has grown up. Browsers have unified. NodeJS tools unnecessary. "Circling-back" as it were.
That's why I like PreactJS. Less is more. Closer to the metal, as they say.
-
2007. JavaScript DHTML Date Time Setter Widget Demo
-
2009. jQuery plugin for a canvas element button
-
2012. Simple notepad component using HTML5, native JavaScript and CSS3. Buggy.
-
2014. Angular JS Bootstrap and Local Storage Setup Demo
-
2016. Angular JS Circa 2020 Online Healthcare Encounter
-
2018. Angular JS Bootstrap Responsive Gallery
-
2015. Golang Interface Humor. Structs and receiver methods (Source code).
-
2015. Responsive Styling Demo
-
2018. One of many, Protractor Automated Tests (Test-driver source code)
-
2019. Recent: Preact Floater Demo *
-
2020. Recent: Preact Concentration Game *
-
2020. Preact Puzzle *
Puzzle Component Source Code
-
2022. Recent: A Study in Native JavaScript, Canvas, Bluetooth telemetry, Geolocation, Offline Storage, and MongoDBAtlas Upload. Single file design pattern.
Less is More: Single File Design Pattern.
1. No tooling required. Fast to load.
-No toolchain exploits
-No toolchain knowledge required.
-Page load times around 30 ms. Open the app, right click on Inspect and checkout the Network panel.
2. Source code NOT obscured.
-one file only. VS Code allows code blocks to be hidden from view with the - and plus controls.
-readable source code is automatically compressed by GZIP; compressing twice yields nothing.
-concerns are separated into JavaScript objects.
-simplified troubleshooting: you always know what file has the error. Finding references between pieces is simple.
-DOM objects are referenced by an IDENT attribute mapped into parent object in a white-listed fashion.
-so simple, a third grader could learn to code and debug.
* Source code can be found on Github at tetrainfo