Thursday, October 19, 2017

more quick and dirty php: finding matching tags

Just here for my future reference - did another "PHP as command line scripting tool to recursively go over directories", this one to get a rough idea of, in our Freemarket Template codebase, how many
<#macro fooBar blah blah>
macro definitions were orphans, and never called with a
<@foobar blah blah >
tag. (Freemarker is hella flexible in terms of how you build a macro name to call, though, so this is far from bullet proof...)

<?
$directory = "/Users/kisrael/cargurus/cg-main/cargurus-site-static/templates/";

$macroDefLocations = array();
$macroCallLocations = array();

#checkfile("inventorylisting/ocrFilterMacros.ftl");

$it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory));
while($it->valid()) {
    $pathname = $it->getSubPathName();
    if (endsWith($pathname, ".ftl")) {
    checkfile($pathname);
    }
    $it->next();
}

function checkfile($pathname){
global $macroDefLocations, $macroCallLocations;
    lookForMatches($pathname,$macroDefLocations,"/\<\#macro.*?\>/s","/\<\#macro\s(\w*)\W/s");
    lookForMatches($pathname,$macroCallLocations,"/\<\@.*?\>/s","/\<\@(\w*)\W/s");
}

foreach($macroDefLocations as $definedMacro => $usages){
if(! array_key_exists($definedMacro, $macroCallLocations)){
$file = array_keys($macroDefLocations[$definedMacro])[0];
print "[".$definedMacro."]\t".$file."\n";
$orphanedMacrosInFile[$file]++;
$orphan++;
} else {
$calledMacrosInFile[$file]++;
$wellcalled++;
}
}
print "$orphan orphans $wellcalled called\n";
print "CALLED:\n";
print_r($calledMacrosInFile);
print "ORPHANED:\n";
print_r($orphanedMacrosInFile);



function lookForMatches($pathname,&$results,$regexFind,$regexExtract){
global $directory;
$content = file_get_contents($directory.$pathname);
preg_match_all($regexFind,$content,$matches);
foreach ($matches[0] as $key => $tag){
preg_match($regexExtract,$tag,$finds);
$macro = $finds[1];
#print "vvv\n$tag\n^^^\n";
if (! array_key_exists($macro,$results)){
$results[$macro] = array();

if (! array_key_exists($pathname,$results[$macro])){
$results[$macro][$pathname] = 0;
}
$results[$macro][$pathname]++;
}
}

function endsWith($haystack, $needle) {
    return $needle === "" || (($temp = strlen($haystack) - strlen($needle)) >= 0 && strpos($haystack, $needle, $temp) !== false);
}
?>

Tuesday, October 10, 2017

The one true Javascript exception handler:
try {
  something
} catch(e) {
  window.location.href = "http://stackoverflow.com/search?q=[js] +" e.message;
}
(via)

Monday, October 2, 2017

what perl taught me (in the early-mid-90s)

Perl was the first language I learned after the "C" that was taught in my Intro to Computer Science class (so probably my fourth language overall, after BASIC and Logo growing up.)

Compared to C of that era, it was like manna from heaven. Here's what it gave me that C lacked:

  • Maps, or as Perl called them, Associative Arrays. Key/Value pairs are such an ENORMOUSLY powerful concept, and this was my first exposure to them.
  • Regular Expressions - being able to match strings is also very powerful and fundamental
  • Strings as first class entities - compared to C saying "you can make a string as an array of strings ending with a \0 character", this was great. In this way too, C was oddly inferior to the BASICs I grew up with.
  • Duck-Typing. I'm not as sold on the importance of duck-typing as I used to be, but I liked it. I especially like Perl's habit of quiet context-based assumptions... assuming false-y or null things are zero if you're trying to do math, compared to Javascripts tendency to panic with "NaN" is more robust and less error-prone than some purists probably realize.
  • Not having to micromanage memory. Man, was C annoying in this regard; having to carefully de-allocate every hunk of memory explicitly was a real pain. (In retrospect, Perl may have gotten away with this more because of its "script" feeling... in general things that do some work than quit can be more forgiving than long-running processes...
Such a breath of fresh air... and then when I learned I could rent cheap webspace that would let me run Perl and that CGI mapped fairly wonderfully to that Key/Value concept... the sky was the limit. I could do nearly anything the web could do.

I was shocked a decade later when a coworker pointed out that most of that stuff I loved about Perl was actually from its history as a glue language, wrapping C(!)-based Unix system calls.  That stunned me... I knew the wonky syntax came from Perl's history as a bit of a mongrel, but compared to other stuff (especially early PHP) it always felt very professional, you hardly ever saw the skeleton, and there wasn't much in it that was obviously for the convenience of the language implementer rather than the programmer. And all these new tricks felt like the very opposite of C...

These days, my Perl is decidedly rusty. PHP eventually matured and having all the stuff for webtasks baked into the language rather than the ugliness of CPAN module compiling was great. Also I'm worried I should have been learning Python, rather than blowing it off because the given task was easier in more familiar Perl. And I never did get my head wrapped around Perl's flavor of Object Oriented thinking. Still, I'll always be grateful to it for opening my eyes to new ways of thinking about programming, which is what the worthy languages and frameworks do.



quick jquery check for repeated ids in DOM

Coworker suggested this console-code proof that ids were being duplicated:
  $('[id]').each(function(){
var ids = $('[id="'+this.id+'"]');
if(ids.length>1 && ids[0]==this)
console.warn('Multiple IDs #'+this.id);
});

If I was less lazy I'd cook up the non-jQuery version.

Tuesday, September 26, 2017

p5 editor to programmatically make a downloadable image in the browser

QUICK HACK: I have a lot of decent art programs for my iPad, but it seems like like such programs no longer come with tools for making simple shapes, like circles and squares. That made my inner child a little sad! Paint programs used to be fun, you know? Like just tooling around throwing shapes and patterns on the screen...

It's tough enough to find programs with flood fill, actually.... it seems like almost every art program is either imitating "real" art tools, aimed at photo retouching, or tries to get you to think in their weird interface for vectors.

Anyway, I wanted a colored circle as a base for a Jack-O-Lantern tuba cover I'm making, and the easiest way was to go to the online p5 editor and enter the following:

function setup() { 
  createCanvas(3000, 3000);
noSmooth();


function draw() { 
  background(255);
noStroke();
fill(255,140,0);
ellipse(1500,1500,2500,2500);
saveCanvas("art.png");
noLoop();
}

That actually generates a file "art.png" which the browser will offer to download.
I then used Dropbox to transfer it to my iPad.

UPDATE:  Did a bit more work...

So, I'm making up designs for tuba covers (as printed by the fine folks at http://stretchablecovers.net/) Before I mentioned the first step for a Jack-O-Lantern (drawn in by hand)

But a few years ago I had a DIY craft project (felt crudely stapled onto the blank side of a cover) skull for my tuba:


I lost it in my recent move, and decided I'd get it printed up, and that I'd use another p5.js program to do it. (I liked the idea of using shapes rather than being quite hand drawn).

Net, net, you can see and play with the p5.js program here. The moderately clever bit is using a technique to let me finesse the placement of a piece via "map()"ing the X and Y mouse position to appropriate values, and then building a string for the corresponding ellipse() or line() command. I then both print the screen and run javascript's "eval()" on it. Once I get the fragement where I like it, I copy and paste the printed version of the statement and place it into the code, so it's kind of baked into the place and then I repeat the technique for the next fragment.


Oh, also for funsies check out my old Carve Your Own Jack-O-Lantern Processing Program... very similar in spirit to all this.

For reference (since I guess I shouldn't an  account on a "alpha version" editor as a code repository) here is the code... it's not (quite) as hackish as it looks.

var BASE;
var s;
function setup() { 
  BASE = 30;// random(38,58);
  createCanvas(BASE*10, BASE*10);
strokeCap(SQUARE);


function draw() { 
  //BASE += random(-.1,.1);
  background(200);
noStroke();
translate(width/2,height/2);
fill(255);
ellipse(0,0,BASE*8,BASE*8);
fill(0);
push();
  var f1 = map(mouseX,0,width, -5,5).toFixed(3);;
  var f2 = map(mouseY,0,height, -5,5).toFixed(3);
  var s;
//var s = "bigEye("+f1+","+f2+");";
  s = "bigEye(1.835,-1.239);";
  eval(s);
  s = "nose(-1.867,0.824)";
  eval(s);
  
  //s = "smallEye("+f1+","+f2+")";
  s = "smallEye(-2.037,-0.947)";
  eval(s);
  
  s = "mouth()";
  eval(s);
  
  s = "crack("+f1+","+(f2)+");"
  eval(s);


}

function mousePressed(){
  noLoop(); 
}

function crack(a,b){
    strokeWeight(BASE/5);
  stroke(0);
  noFill();
  push();
 // print (a+":"+b);
  translate(BASE*.137,BASE*.44);
beginShape();
  push();
 vertex(BASE*-3.392,BASE*-4.471);
vertex(BASE*-1.704,BASE*-3.673);
vertex(BASE*-1.367,BASE*-3.895);
vertex(BASE*-1.316,BASE*-3.14);
vertex(BASE*-0.497,BASE*-3.36);
  vertex(BASE*0.084,BASE*-2.65);
//vertex(BASE*-0.894,BASE*-2.657);
vertex(BASE*-0.497,BASE*-3.36);
  vertex(BASE*0.143,BASE*-3.791);

  s = "vertex(BASE*"+a+",BASE*"+b+");";
 // eval(s);
 // print(s);
  endShape();
  pop();
  
  
    noLoop(); 
 saveCanvas("skull.png");

}


function mouth(){
  strokeWeight(BASE/2.8);
  stroke(0);
  line(-BASE*4,BASE*2,BASE*4,BASE*2);
  
  line(0,BASE*1.35,0,BASE*2.65);
  line(-BASE,BASE*1.45,-BASE,BASE*2.55);
  line(-2*BASE,BASE*1.4,-2*BASE,BASE*2.55);
  line(BASE,BASE*1.45,BASE,BASE*2.65);
  line(2*BASE,BASE*1.45,2*BASE,BASE*2.55);
}



function nose(a,b){
  push();
  push();
  rotate(a);
  ellipse(0,BASE/4,BASE*2,BASE);
  pop();
  push();
  rotate(-a);
  ellipse(0,+BASE/4,BASE*2,BASE);
  pop();
}

function bigEye(f1,f2){
  var g = 2.5;
  push();
  translate(f1* BASE,f2*BASE);
rotate(0.1);
  ellipse(0,0,BASE*g,BASE*g*1.3);
pop();
}

function smallEye(f1,f2){
  var g = 2.2;
  push();
  translate(f1* BASE,f2*BASE);
rotate(0.1);
  ellipse(0,0,BASE*g*1.1,BASE*g);
pop();
}

Monday, September 25, 2017

json junk

Heh, JSON Generator is a cool way of making fake-y data that follows your JSON structures...

Wednesday, September 20, 2017

trivial php router for local dev and under apache

I wanted to make a PHP app so that I could work on it online and offline, with or without Apache, and that maybe it would be cool to have a centralized controller... do things a bit MVCishly rather than just having a pile of .php scripts (in particular, my first attempt for chart-o-tron did a lot of htaccess hackery to allow for pretty URLs, but the other URLs were all .php which looks pretty janky these days)

The page on the PHP built-in webserver mentions you can run PHP from the command line, and have every request be piped into a router
php -S localhost:8000 router.php
and here's their sample router script:
<?php
// router.php
if (preg_match('/\.(?:png|jpg|jpeg|gif)$/', $_SERVER["REQUEST_URI"])) {
    return false;    // serve the requested resource as-is.
} else { 
    echo "<p>Welcome to PHP</p>";
}
?>
The trouble was when I setup .htaccess to have Apache send all requests to it, the idea of "return false;" doesn't mean anything when Apache has already ceded control. In theory I could have used readfile() to handle PHP stream up static files, but it seemed weird, not leveraging Apache's optimization in serving static content, and a potential security weakpoint.

I decide to put all my static content under /static/ rather than worry about file extensions, or regular expressions to tell Apache to treat .php files differently... It took some fumbling to get the regex quite right:
RewriteEngine On
RewriteRule !^static router.php [L]

I then fiddled with the router script to do the parallel thing when I'm running locally:
<?php
if (preg_match('/^\/static\//', $_SERVER["REQUEST_URI"])) {
    return false;    // serve the requested resource as-is.
} else { 
    echo "<p>Welcome to PHP</p>".$_SERVER["REQUEST_URI"];
}
?>
Seems like a good start. There are other PHP router scripts that are configurable, but I kind of like this low level of control.