nix, shell, perl, php, mysql and mac os x tips and tricks

Saturday, August 5, 2017

Array: remove empty, remove whitespace out of each slice

For dealing with arrays with IDs (that have been touched by humans somewhere along the way)
@array = grep /\S/, @array; # remove empty
s/\s$// for @array; # remove whitespace out of each slot

Monday, July 31, 2017

Ember.js stateful image loading component

Not sure how useful this is, but this uses javascript Image() and a promise to load an image. Allows you to set loading and error states.
import Ember from 'ember';

const {
    Component,
    get,
    set
} = Ember;

export default Component.extend({

    isLoading: true,
    isError: false,

    /* JavaScript Image Object used to do the loading */
    imageLoader: Ember.computed(function() {
        return new Image();
    },

    getImage(url, _this) {
        return new Ember.RSVP.Promise((resolve, reject) => {
            let img = _this.get('imageLoader');
            img.onload = function() {
                resolve(url)
            }
            img.onerror = function() {
                reject(url)
            }
            img.src = url
        });
    },

    didInsertElement() {
        this._super(...arguments);
        let _this = this;

        let src = get(_this, 'src');
        _this.get('getImage')(src, _this).then(success => {
            console.log("success", success);
            set(_this, 'isLoading', false);
        }).catch(error => {
            console.log("fail", error);
            set(_this, 'isLoading', false);
            set(_this, 'isError', true);
        })
    },

    willDestroyElement() {
        this._super(...arguments);
        let img = get(this, 'imageLoader');
        if (img) {
            img = img.onload = img.onerror = null;
            this.set('imageLoader', null);
        }
    }
});
Then in the template you could do something like:
{{#if isLoading}}
 
loading...
{{else}} {{#if isError}} {{else}} {{/if}} {{/if}}
If the component is called "product-render" you could use it in parent template like:
{{product-render src=myImage}}

MySQL select records with timestamp in the previous day, no matter what time of day it is now

WHERE timestamp >= DATE_SUB(CONCAT(CURDATE(), ' 00:00:00'), INTERVAL 24 HOUR) AND timestamp < DATE_ADD(DATE_SUB(CONCAT(CURDATE(), ' 00:00:00'), INTERVAL 24 HOUR), INTERVAL 24 HOUR)

Sunday, July 2, 2017

Create Self-Signed Cert on OSX and tell the OS to trust it

Not as easy as you might think. Let's say you wanted to create a self-signed cert for a local domain called "my.webtool"... First create a file called v3.ext with these contents:
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names

[alt_names]
DNS.1 = my.webtool
DNS.2 = localhost
DNS.3 = 127.0.0.1
Then run these commands. This assumes you have openSSL installed:
openssl genrsa -des3 -passout pass:x -out my.webtool.pass.key 2048
openssl rsa -passin pass:x -in my.webtool.pass.key -out my.webtool.key
rm my.webtool.pass.key
openssl req -new -key my.webtool.key -out my.webtool.csr
openssl x509 -req -days 1000 -in my.webtool.csr -signkey my.webtool.key -out my.webtool.crt -extfile v3.ext
Then install the .key and .crt files in whatever server you're running. THEN you have to tell your system to trust the certificate by importing it into your keychain AND change the "trust" settings on it. See http://www.accuweaver.com/2014/09/19/make-chrome-accept-a-self-signed-certificate-on-osx/

Monday, February 27, 2017

clean the apache cache nicely

/usr/local/apache/bin/htcacheclean -vn -p/var/cache/apache -l500M

Kinda rough regex for pattern matching and capturing apache log info

the IP is parsed into \2 \3 and \4
^(((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)) \- \- (\[.*?\]) "(.*?)" (\d+) (\d+) "(.*?)" "(.*?)"$

Geocode a batch of addresses with perl and Google

I am working with this store locator and needed a way to geocode 7k addresses, so I wrote this quick-n-dirty script. Google only lets you geocode 2500 addresses a day. The script will start where it left off, then quit when you hit the query limit. So it feasibly could be run on a cron until all your addresses are coded.
#!/usr/bin/perl

use strict;
use DBI;
use Google::GeoCoder::Smart;

my $geo = Google::GeoCoder::Smart->new();

my $host =""; 
my $database =""; 
my $user =""; 
my $mysqlpassword ="";

my $dbh = DBI->connect("DBI:mysql:database=$database;host=$host","$user","$mysqlpassword",{'RaiseError'=>1}); 

 my $ctr= 0;
 my $sql = "SELECT * FROM sb_locations WHERE lat = \"\"";  
 my $sth = &db_query($sql);
 while (my $ref = $sth->fetchrow_hashref) {
        my ($num, $error, @results, $returntext) = $geo->geocode(
        "address" => stripChars($ref->{'address'}), 
        "city" => stripChars($ref->{'city'}), 
        "state" => stripChars($ref->{'state'}), 
        "zip" => stripChars($ref->{'postal'})
        );
        my $lat;
        my $lng;
        eval {
         $lat = $results[0]{geometry}{location}{lat};
        };
        eval {
         $lng = $results[0]{geometry}{location}{lng};
        };  
        print "id: $ref->{'id'} returntext?: $returntext error?: $error lat: $lat lng: $lng\n";
        if ($error eq 'OVER_QUERY_LIMIT') {
         last;
        }         
        if (($lat) && ($lng)) {
         $lat = $dbh->quote($lat);
         $lng = $dbh->quote($lng);
         my $upd_q = "UPDATE sb_locations SET lat = $lat, lng = $lng WHERE id = $ref->{'id'}";
         my $sth2 = &db_query($upd_q);
         $sth2->finish();
        }
        $ctr++;
        if (($ctr%10)==0) {
         print "sleeping\n";
         sleep 5;
        }
 }
 $sth->finish();
 undef ($sql);
 undef ($sth);

$dbh->disconnect();

sub stripChars {
        my($text) = @_;
        $text =~ s/^\s*//; # strip out leading space if there is one
        $text =~ s/\n/ /g; # strip carraige returns
        $text =~ s/\t/ /g; # strip tabs
        $text =~ s/\a/ /g; # strip carraige returns
  $text =~ s/"/'/g; # strip quotes and replace with single quotes
        $text =~ s/\s+/ /g; # strip repeating spaces and replace with one
        $text =~ s/[^[:ascii:]]+//g;
        return ($text);
 
} # end sub strip chars

sub db_query {
 my ($query) = @_;
 my $sth = $dbh->prepare("$query"); 
 #print $query;
 $sth->execute;
 #print $dbh->err; 
 my $err = $dbh->err;  
 my $errstr = $dbh->errstr;
 if ($err) { print "$err: $errstr on query $query"; }
 return $sth;
 
} # end sub db_query