Thursday, October 26, 2017
moment of duh: search across ALL javascript in chrome dev tools
I was a little nonplussed at not seeing a widget (or having my normal keyboard shortcuts seem to work) for search ALL the scripts for a bit of javascript... but if you click on the vertical ... box under developer tools, there's a "Search all files".
Wednesday, October 25, 2017
clever UI for tight quarters and fat fingers
One of the few paper puzzle games I like goes by several different names - Nonograms, Picross (Nintendo calls it that in its digital versions), Paint-By-Number... actually the Wikipedia Page lists about 30 names for it- I feel like the branding is one of the reasons why it hasn't reached the popularity of, say, Sudoku - for my money, uncovering a small pixelated picture is immensely more satisfying than making yet another grid of numbers.
If you don't know, Picross gives you an empty grid, and then numbers for the rows and columns - so if a grid is 10 squares wide, and to the side of that row it says "10" you know the whole row is filled in - or if says "5 4" you know it's 5 squares and then 4 squares, and since there must be a blank between, you know the pattern exactly, since 5 + (1 blank) + 4 = 10. Usually there's some ambiguity, like "1 3 1" and you have to cross correlate with the columns to figure out what's going on exactly
I found a decent version for iOS called "Picture Cross" - it's free, but for a any purchase (as cheap as 99 cents) the annoying advertisements go away. By default a simple puzzle in it looks something like this:
The UI is pretty easy, the center "Fill In" and "Blank X" buttons are modals - the checkbox shows you which mode it's in - click any empty square, or drag across squares, and it gets filled in with marks or blanks.
That's tricky once you start getting more squares (15x15 or more) or if you have a small phone, so they include an "Alternate" control scheme that takes a second to figure out but then works really well. The mode adds a "pin" button and a cursor:
The nice thing is, the cursor moves from its location no matter where on the screen you swipe, so you can see exactly what square you're talking about it without your finger blocking it. So from there you can go ahead and click the Mark or X button and it toggles the state of the box under the cursor.
In this mode, the pin button is what's modal. Click it, drag-swipe, and an entire region is selected, with the first square being where the cursor started: (in this case, according to the rules of Picross, we know that all 10 squares along the bottom are due for being marked...)
If you don't know, Picross gives you an empty grid, and then numbers for the rows and columns - so if a grid is 10 squares wide, and to the side of that row it says "10" you know the whole row is filled in - or if says "5 4" you know it's 5 squares and then 4 squares, and since there must be a blank between, you know the pattern exactly, since 5 + (1 blank) + 4 = 10. Usually there's some ambiguity, like "1 3 1" and you have to cross correlate with the columns to figure out what's going on exactly
I found a decent version for iOS called "Picture Cross" - it's free, but for a any purchase (as cheap as 99 cents) the annoying advertisements go away. By default a simple puzzle in it looks something like this:
The UI is pretty easy, the center "Fill In" and "Blank X" buttons are modals - the checkbox shows you which mode it's in - click any empty square, or drag across squares, and it gets filled in with marks or blanks.
That's tricky once you start getting more squares (15x15 or more) or if you have a small phone, so they include an "Alternate" control scheme that takes a second to figure out but then works really well. The mode adds a "pin" button and a cursor:
The nice thing is, the cursor moves from its location no matter where on the screen you swipe, so you can see exactly what square you're talking about it without your finger blocking it. So from there you can go ahead and click the Mark or X button and it toggles the state of the box under the cursor.
In this mode, the pin button is what's modal. Click it, drag-swipe, and an entire region is selected, with the first square being where the cursor started: (in this case, according to the rules of Picross, we know that all 10 squares along the bottom are due for being marked...)
Then you can click the "Mark" button, and all the square are set.
So when you have a base like that in Picross, the next step is easy, since we've anchored all the bottom numbers along the top - the 1 and1 is set, the 4 and the 6 we know how they'll go.. so I'll unpin the selection, and go to the column of the 4..., pin and drag...
Mark as filled...
Here's a detail that's cool - I know there's nothing but the 4 in that column, so I can should the rest with X blanks. I just drag up to the top of the column, and hit the X button...
The clever part of this UI is that it doesn't undo what I've already marked. I feel like a more naive UI would just do "whatever is selected, change its state" but Picross encourages being conservative in how you mark things, so you don't want them casually unmarked - that would be super confusing.
That "don't change state directly from marked to X" rule applies even if you're checking squares one by one, for similar reasons.
techie cheatsheets galore!
https://devhints.io/ - TL;DR for developer documentation
"A ridiculous collection of web development cheatsheets"
"A ridiculous collection of web development cheatsheets"
Monday, October 23, 2017
sublime - autosave when you change apps
The new hotness standard brought by IntelliJ seems to be autosave, cmd-s is old and busted. For a while I thought this was black magic but I think sometimes it's as simple as a "save when you lose focus".
I still use sublime for other work, and among some other tips this page tells me I can just add
"save_on_focus_lost": true
to my preferences>settings (currently set to
{
"auto_match_enabled": false,
"color_scheme": "Packages/Color Scheme - Default/Solarized (Light).tmTheme",
"font_size": 15,
"auto_close_tags": false,
"save_on_focus_lost": true
}
for what it's worth.
From a UX standpoint, autosave is kind of an paradigm shift, but in an age of really good cmd-z undo, it's not as problematic as my old self would have thought.
I still use sublime for other work, and among some other tips this page tells me I can just add
"save_on_focus_lost": true
to my preferences>settings (currently set to
{
"auto_match_enabled": false,
"color_scheme": "Packages/Color Scheme - Default/Solarized (Light).tmTheme",
"font_size": 15,
"auto_close_tags": false,
"save_on_focus_lost": true
}
for what it's worth.
From a UX standpoint, autosave is kind of an paradigm shift, but in an age of really good cmd-z undo, it's not as problematic as my old self would have thought.
Friday, October 20, 2017
a little light reading
Articles on stuff my company is looking into...
Oh and https://www.fullstackreact.com/30-days-of-react/ and https://learnredux.com/ oh and then https://cssgrid.io/
- https://medium.com/@addyosmani/progressive-web-apps-with-react-js-part-i-introduction-50679aef2b12
- https://developers.google.com/web/fundamentals/performance/prpl-pattern/
- http://redux.js.org/docs/basics/UsageWithReact.html
- https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API
- https://blogs.akamai.com/2017/03/http2-server-push-the-what-how-and-why.html
- http://redux.js.org/docs/recipes/ServerRendering.html
- https://developers.google.com/web/fundamentals/architecture/app-shell
- https://developers.google.com/web/fundamentals/push-notifications/
- https://developers.google.com/web/fundamentals/web-app-manifest/
- https://developers.google.com/web/fundamentals/performance/rendering/
Oh and https://www.fullstackreact.com/30-days-of-react/ and https://learnredux.com/ oh and then https://cssgrid.io/
local music fingerprinting in 1/2 a GB?
Huh - Google's Pixel 2 does Shazam/Soundhound style audio fingerprinting locally? And that db for that is only half a GB? I never would have suspected the numbers were like that (even knowing factoids how like a simple formula "does the subsequent note in series go up or down, note by note makes a unique key for melodies in a surprisingly small number of notes")
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);
foreach($orphanedMacrosInFile as $file => $countOrphans){
$countCalled = 0;
if(array_key_exists($file, $calledMacrosInFile)){
$countCalled = $calledMacrosInFile[$file];
}
$percentOrphans[$file] = (100.0 * ($countOrphans) / ($countCalled +$countOrphans ));
$orphanDesc[$file] = "$countOrphans orphans / ".($countCalled +$countOrphans)." defs";
}
arsort($percentOrphans);
$keys = array_keys($percentOrphans);
foreach($keys as $file){
print round($percentOrphans[$file],3)."\t".$orphanDesc[$file]."\t".$file."\n";;
}
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);
}
?>
<#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);
foreach($orphanedMacrosInFile as $file => $countOrphans){
$countCalled = 0;
if(array_key_exists($file, $calledMacrosInFile)){
$countCalled = $calledMacrosInFile[$file];
}
$percentOrphans[$file] = (100.0 * ($countOrphans) / ($countCalled +$countOrphans ));
$orphanDesc[$file] = "$countOrphans orphans / ".($countCalled +$countOrphans)." defs";
}
arsort($percentOrphans);
$keys = array_keys($percentOrphans);
foreach($keys as $file){
print round($percentOrphans[$file],3)."\t".$orphanDesc[$file]."\t".$file."\n";;
}
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)
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:
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 / duplicate 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.
$('[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.
Subscribe to:
Posts (Atom)