Upgrade to Pro — share decks privately, control downloads, hide ads and more …

1.21 Gigawatts

1.21 Gigawatts

Lightning strikes 11 times! Almost a dozen short talks about stuff that I was thinking about in 2013.

Ricardo Signes

January 23, 2014
Tweet

More Decks by Ricardo Signes

Other Decks in Programming

Transcript

  1. use List::Util; my $x = first { $_ > 1

    } @list; my $y = min @list;
  2. use List::Util; my $x = first { $_ > 1

    } @list; my $y = min @list; die if any { $_ < 0 } @list;
  3. use List::MoreUtils; my ($min, $max) = minmax(@list); my @header =

    before { $_ eq ‘’ } @input; die if any { $_ < 0 } @list;
  4. use List::MoreUtils; my ($min, $max) = minmax(@list); my @header =

    before { $_ eq ‘’ } @input; die if any { $_ < 0 } @list; @x = uniq @x;
  5. ! ! my $fh = IO::Uncompress::Gunzip ->new("myfile.csv.gz"); ! my $fh

    = IO::Compress::Gzip ->new("output.txt.gz"); !
  6. use autodie; ! my $fh = IO::Uncompress::Gunzip ->new("myfile.csv.gz"); ! my

    $fh = IO::Compress::Gzip ->new("output.txt.gz"); !
  7. use autodie; ! my $fh = IO::Uncompress::Gunzip ->new("myfile.csv.gz"); ! my

    $fh = IO::Compress::Gzip ->new("output.txt.gz"); !
  8. use autodie; # <-- won't help ! my $fh =

    IO::Uncompress::Gunzip ->new("myfile.csv.gz"); ! my $fh = IO::Compress::Gzip ->new("output.txt.gz"); !
  9. use PerlIO::gzip; ! ! open my $fh, '<:gzip', "myfile.csv.gz"; !

    open my $fh, '>:gzip', "output.txt.gz";
  10. $ cpan Dist::Zilla installing 10% of CPAN... installing 20% of

    CPAN... installing 30% of CPAN... installing 40% of CPAN...
  11. Checking if you have ExtUtils::MakeMaker 6.30 ... Yes (6.86) Running

    Makefile.PL Configuring superclass-0.002 ... Checking if your kit is complete... Looks good Generating a Unix-style Makefile Writing Makefile for superclass Writing MYMETA.yml and MYMETA.json OK Checking dependencies from MYMETA.json ... Checking if you have version 0.9901 ... Yes (0.9906) Checking if you have File::Temp 0 ... Yes (0.2304) Checking if you have warnings 0 ... Yes (1.18) Checking if you have Module::Load 0.24 ... Yes (0.28) Checking if you have Config 0 ... Yes (5.018002) Checking if you have vars 0 ... Yes (1.03) Checking if you have File::Spec::Functions 0 ... Yes (3.40) Checking if you have strict 0 ... Yes (1.07) Checking if you have File::Find 0 ... Yes (1.23) Checking if you have ExtUtils::MakeMaker 0 ... Yes (6.86) Checking if you have List::Util 0 ... Yes (1.35) Checking if you have Test::More 0 ... Yes (1.001002) Building and testing superclass-0.002 ... cp lib/superclass.pm blib/lib/superclass.pm Manifying blib/man3/superclass.3 PERL_DL_NONLAZY=1 /Users/rjbs/.plenv/versions/18.2/bin/perl5.18.2 "-MExtUtils::Command::MM" "-MTest::Harness" "-e" "undef *Test::Harness::Switches; test_harness(0, 'blib/lib', 'blib/arch')" t/*.t t/00-compile.t .................. ok t/00-report-prereqs.t ........... # Prerequisite Report: # Version Module # -------- --------------------- # 5.018002 Config # 6.86 ExtUtils::MakeMaker # 1.23 File::Find # 3.40 File::Spec::Functions # 0.2304 File::Temp # 1.35 List::Util # 0.28 Module::Load # 1.001002 Test::More # 1.07 strict # 1.03 vars # 0.9906 version # 1.18 warnings t/00-report-prereqs.t ........... ok t/compile-time-file.t ........... ok t/compile-time.t ................ ok t/inherit-classfromclassfile.t .. ok t/inherit-classfromfile.t ....... ok t/inherit-pmc.t ................. ok t/inherit-returns-false.t ....... ok t/inherit.t ..................... ok t/version-check.t ............... ok All tests successful. Files=10, Tests=50, 1 wallclock secs ( 0.04 usr 0.02 sys + 0.36 cusr 0.05 csys = 0.47 CPU) Result: PASS Manifying blib/man3/superclass.3 Installing /Users/rjbs/.plenv/versions/18.2/lib/perl5/site_perl/5.18.2/superclass.pm Installing /Users/rjbs/.plenv/versions/18.2/man/man3/superclass.3 Appending installation info to /Users/rjbs/.plenv/versions/18.2/lib/perl5/5.18.2/darwin-2level/perllocal.pod OK Successfully installed superclass-0.002 Installing /Users/rjbs/.plenv/versions/18.2/lib/perl5/site_perl/5.18.2/darwin-2level/.meta/superclass-0.002/install.json Installing /Users/rjbs/.plenv/versions/18.2/lib/perl5/site_perl/5.18.2/darwin-2level/.meta/superclass-0.002/MYMETA.json Building and testing TAP-Harness-Restricted-0.002 ... cp lib/TAP/Harness/Restricted.pm blib/lib/TAP/Harness/Restricted.pm Manifying blib/man3/TAP::Harness::Restricted.3 PERL_DL_NONLAZY=1 /Users/rjbs/.plenv/versions/18.2/bin/perl5.18.2 "-MExtUtils::Command::MM" "-MTest::Harness" "-e" "undef *Test::Harness::Switches; test_harness(0, 'blib/lib', 'blib/arch')" t/*.t t/00-compile.t ......... ok t/00-report-prereqs.t .. # Prerequisite Report: # Version Module # -------- --------------------- # 6.86 ExtUtils::MakeMaker # 1.23 File::Find # 3.40 File::Spec::Functions # 0.2304 File::Temp # 1.005 File::pushd # 1.35 List::Util # 0.051 Path::Tiny # 3.30 TAP::Harness # 0.008 Test::FailWarnings # 1.001002 Test::More # 1.07 strict # 0.002 superclass # 1.18 warnings t/00-report-prereqs.t .. ok t/test.t ............... ok All tests successful. Files=3, Tests=3, 0 wallclock secs ( 0.03 usr 0.01 sys + 0.24 cusr 0.03 csys = 0.31 CPU) Result: PASS Installing /Users/rjbs/.plenv/versions/18.2/lib/perl5/site_perl/5.18.2/TAP/Harness/Restricted.pm Installing /Users/rjbs/.plenv/versions/18.2/man/man3/TAP::Harness::Restricted.3 Appending installation info to /Users/rjbs/.plenv/versions/18.2/lib/perl5/5.18.2/darwin-2level/perllocal.pod OK Successfully installed TAP-Harness-Restricted-0.002 Installing /Users/rjbs/.plenv/versions/18.2/lib/perl5/site_perl/5.18.2/darwin-2level/.meta/TAP-Harness-Restricted-0.002/install.json Installing /Users/rjbs/.plenv/versions/18.2/lib/perl5/site_perl/5.18.2/darwin-2level/.meta/TAP-Harness-Restricted-0.002/MYMETA.json Expiring 2 work directories. 2 distributions installed
  12. t/00-report-prereqs.t ........... ok t/compile-time-file.t ........... ok t/compile-time.t ................ ok t/inherit-classfromclassfile.t

    .. ok t/inherit-classfromfile.t ....... ok t/inherit-pmc.t ................. ok t/inherit-returns-false.t ....... ok t/inherit.t ..................... ok t/version-check.t ............... ok All tests successful. Files=10, Tests=50, 1 wallclock secs ( 0.04 usr 0.02 sys + 0.36 cusr 0.05 csys = 0.47 CPU) Result: PASS Manifying blib/man3/superclass.3 Installing /Users/rjbs/.plenv/versions/18.2/lib/perl5/site_perl/5.18.2/superclass.pm Installing /Users/rjbs/.plenv/versions/18.2/man/man3/superclass.3 Appending installation info to /Users/rjbs/.plenv/versions/18.2/lib/perl5/5.18.2/darwin-2level/ perllocal.pod OK Successfully installed superclass-0.002 Installing /Users/rjbs/.plenv/versions/18.2/lib/perl5/site_perl/5.18.2/darwin-2level/.meta/ superclass-0.002/install.json Installing /Users/rjbs/.plenv/versions/18.2/lib/perl5/site_perl/5.18.2/darwin-2level/.meta/ superclass-0.002/MYMETA.json Building and testing TAP-Harness-Restricted-0.002 ... cp lib/TAP/Harness/Restricted.pm blib/lib/TAP/ Harness/Restricted.pm Manifying blib/man3/TAP::Harness::Restricted.3 PERL_DL_NONLAZY=1 /Users/rjbs/.plenv/versions/18.2/bin/perl5.18.2 "-MExtUtils::Command::MM" "- MTest::Harness" "-e" "undef *Test::Harness::Switches; test_harness(0, 'blib/lib', 'blib/arch')" t/*.t t/00-compile.t ......... ok t/00-report-prereqs.t .. # Prerequisite Report: # Version Module # -------- --------------------- # 6.86 ExtUtils::MakeMaker # 1.23 File::Find # 3.40 File::Spec::Functions
  13. t/00-compile.t ......... ok t/00-report-prereqs.t .. # Prerequisite Report: # Version

    Module # -------- --------------------- # 6.86 ExtUtils::MakeMaker # 1.23 File::Find # 3.40 File::Spec::Functions # 0.2304 File::Temp # 1.35 List::Util # 0.28 Module::Load # 1.001002 Test::More # 1.07 strict # 1.03 vars # 0.9906 version # 1.18 warnings t/00-report-prereqs.t ........... ok t/compile-time-file.t ........... ok t/compile-time.t ................ ok t/inherit-classfromclassfile.t .. ok t/inherit-classfromfile.t ....... ok t/inherit-pmc.t ................. ok t/inherit-returns-false.t ....... ok t/inherit.t ..................... ok t/version-check.t ............... ok t/pod-syntax .................... not ok ha ha ha sucker
  14. ! ! system(cowsay => $motto); if ($?) { my $exit

    = $? >> 8; die "it exited $exit"; }
  15. ! ! system(cowsay => $motto); if ($?) { my $exit

    = $? >> 8; my $signal = $? & 127; die "it exited $exit" . ", signal $signal"; }
  16. my @todo = sort { $a->todo eq 'eat pie' ?

    -1 : $b->todo eq 'eat pie' ? 1 : $a->priority <=> $b->priority } stuff_i_gotta_do;
  17. use Sort::ByExample 'sbe'; ! my $sorter = sbe( [ 'eat

    pie', 'eat cake' ], { xform => sub { $_[0]->todo }, fallback => sub { $_[3]->priority <=> $_[2]->priority }, } ); ! my @todo = $sorter->( stuff_i_gotta_do );
  18. use Sort::ByExample 'sbe'; ! my $sorter = sbe( [ 'eat

    pie', 'eat cake' ], # <---- { xform => sub { $_[0]->todo }, fallback => sub { $_[3]->priority <=> $_[2]->priority }, } ); ! my @todo = $sorter->( stuff_i_gotta_do );
  19. not ok - matching text # got: 'Everything is okay!'

    # expected: 'Everything is okay!'
  20. use Test::BinaryData; ! my $want = read_expected_file; my $have =

    perform_some_operation; ! is_binary($have, $want, "matching text"); !
  21. # have (hex) have want (hex) want # 457665727974 Everyt

    = 457665727974 Everyt # 68696e67a069 hing.i ! 68696e672069 hing i # 73a06f6b6179 s.okay ! 73206f6b6179 s okay # 21---------- ! = 21---------- !
  22. # have (hex) have want (hex) want # 457665727974 Everyt

    = 457665727974 Everyt # 68696e67a069 hing.i ! 68696e672069 hing i # 73a06f6b6179 s.okay ! 73206f6b6179 s okay # 21---------- ! = 21---------- !
  23. # have (hex) have want (hex) want # 457665727974 Everyt

    = 457665727974 Everyt # 68696e67a069 hing.i ! 68696e672069 hing i # 73a06f6b6179 s.okay ! 73206f6b6179 s okay # 21---------- ! = 21---------- !
  24. • locking over NFS is "interesting • SQL locks are

    released if your connection is interrutped
  25. • locking over NFS is "interesting • SQL locks are

    released if your connection is interrutped • (use autoreconnect? you won't notice!)
  26. • locking over NFS is "interesting • SQL locks are

    released if your connection is interrutped • (use autoreconnect? you won't notice!) • sometimes a really stupid hack is good enough
  27. use DBIx::Locker; ! my $locker = DBIx::Locker->new(\%arg); ! for my

    $todo (@agenda) { my $lock = $locker->lock($todo->id); ... }
  28. CREATE TABLE semaphores ( id int PRIMARY KEY AUTO_INCREMENT, lockstring

    varchar(128) UNIQUE, created datetime NOT NULL, expires datetime NOT NULL, locked_by text NOT NULL );
  29. CREATE TABLE semaphores ( id int PRIMARY KEY AUTO_INCREMENT, lockstring

    varchar(128) UNIQUE, created datetime NOT NULL, expires datetime NOT NULL, locked_by text NOT NULL );
  30. use less 'cpu'; ! use less 'memory'; ! use less

    'stack'; ! use less 'processes';
  31. use less 'cpu'; ! use less 'memory'; ! use less

    'stack'; ! use fewer 'processes';
  32. $sock->send("UPDATE $key $value"); ! Use of uninitialized value ($key) in

    concatenation (.) or string 5.10's Best Change (that's 5.8-safe)
  33. ! ! if (length $xyz) { ... } ! !

    ! ! ! 5.12's Best Change (that's 5.8-safe)
  34. ! if (length $xyz) { ... } ! if (length($xyz

    // $xyz)) { ... } ! ! 5.12's Best Change (that's 5.8-safe)
  35. ! if (length $xyz) { ... } ! if (length($xyz

    // $xyz)) { ... } ! if (defined $xyz && length $xyz) { ... } 5.12's Best Change (that's 5.8-safe)
  36. if (length $xyz) { ... } ! if (length($xyz //

    $xyz)) { ... } ! if (defined $xyz && length $xyz) { ... } ! if (length $xyx > 0) { ... } 5.12's Best Change (that's 5.8-safe)
  37. package Mr::Fusion 1.234; use strict; sub produce_energy { my ($self,

    garbage) = @_; ... return $Watt * 1.21 * (10 ** 9); } 5.14's Best Change (it's a tie)
  38. package Mr::Fusion 1.234 { use strict; sub produce_energy { my

    ($self, garbage) = @_; ... return $Watt * 1.21 * (10 ** 9); } } 5.14's Best Change (it's a tie)
  39. (my $y2013 = $y2012) =~ s!Mario!Luigi!g; ! my $y2013 =

    $y2012 =~ s!Mario!Luigi!gr; ! 5.14's Best Change (it's a tie)
  40. (my $y2013 = $y2012) =~ s!Mario!Luigi!g; ! my $y2013 =

    $y2012 =~ s!Mario!Luigi!gr; ! my @y2013 = map {s!Mario!Luigi!gr} @y2012; 5.14's Best Change (it's a tie)
  41. my $fact = sub { my $n = shift; $n

    == 1 ? 1 : $n * __SUB__->( $n - 1 ); }; 5.16's Best Change (the other one)
  42. my %hash = (a => 1, b => 2, c

    => 3); 5.20's Best Change??
  43. my %hash = (a => 1, b => 2, c

    => 3); @hash{ qw( a c ) } ➜ (1, 3) 5.20's Best Change??
  44. my %hash = (a => 1, b => 2, c

    => 3); @hash{ qw( a c ) } ➜ (1, 3) %hash{ qw( a c ) } ➜ (a => 1, c => 3); 5.20's Best Change??
  45. my %hash = (a => 1, b => 2, c

    => 3); @hash{ qw( a c ) } ➜ (1, 3) %hash{ qw( a c ) } ➜ (a => 1, c => 3); @array = qw( a b c d ); 5.20's Best Change??
  46. my %hash = (a => 1, b => 2, c

    => 3); @hash{ qw( a c ) } ➜ (1, 3) %hash{ qw( a c ) } ➜ (a => 1, c => 3); @array = qw( a b c d ); %array[ 0, 2, 1 ] 5.20's Best Change??
  47. my %hash = (a => 1, b => 2, c

    => 3); @hash{ qw( a c ) } ➜ (1, 3) %hash{ qw( a c ) } ➜ (a => 1, c => 3); @array = qw( a b c d ); %array[ 0, 2, 1 ] ➜ (0 => 'a', 2 => 'c', 1 => 'd' ); 5.20's Best Change??
  48. my $user = { ... rjbs => { ..., goals

    => [ "eat risotto", "eat pie", ] }, };
  49. use experimental 'postderef'; $array_ref->@[ 0, 1, 5 ]; $hash__ref->@{ qw(a

    b) ]; $array_ref->%[ 0, 1, 5 ]; $hash__ref->%{ qw(a b) ];
  50. use experimental 'postderef'; $array_ref->@[ 0, 1, 5 ]; $hash__ref->@{ qw(a

    b) ]; $array_ref->%[ 0, 1, 5 ]; $hash__ref->%{ qw(a b) ]; $glob_ref->*{SCALAR}; # Sorry!
  51. $ perl -Dspot your-program.plx $ perl -d:Xyz your-program.plx -D is

    for debugging perl's code -d is for debugging Perl code
  52. $^P

  53. 0x001 debug sub entry/leave 0x002 call DB::DB per statement 0x004

    turn off optimizer 0x008 save more stuff 0x010 keep sub definition info 0x020 single-step 0x040 use subroutine addrs 0x080 report "goto &sub" 0x100 better eval names 0x200 better sub names 0x400 source in @{"_<$file"}
  54. 0x001 debug sub entry/leave 0x002 call DB::DB per statement 0x004

    turn off optimizer 0x008 save more stuff 0x010 keep sub definition info 0x020 single-step 0x040 use subroutine addrs 0x080 report "goto &sub" 0x100 better eval names 0x200 better sub names 0x400 source in @{"_<$file"}
  55. 0x001 debug sub entry/leave 0x002 call DB::DB per statement 0x004

    turn off optimizer 0x008 save more stuff 0x010 keep sub definition info 0x020 single-step 0x040 use subroutine addrs 0x080 report "goto &sub" 0x100 better eval names 0x200 better sub names 0x400 source in @{"_<$file"}
  56. package Devel::Stupid; ! package DB { sub DB { my

    ($package, $filename, $line) = caller; return unless $filename eq $0; Devel::LineTimer::emit_trace($filename, $line); } }
  57. sub emit_trace { my ($filename, $line) = @_; state $prev;

    @code = @{"::_<$filename"}; my $now = Time::HiRes:time();
  58. sub emit_trace { my ($filename, $line) = @_; state $prev;

    @code = @{"::_<$filename"}; my $now = Time::HiRes:time(); $line_of_code = $code[ $line ];
  59. sub emit_trace { my ($filename, $line) = @_; state $prev;

    @code = @{"::_<$filename"}; my $now = Time::HiRes:time(); $line_of_code = $code[ $line ]; if ($prev) {
  60. sub emit_trace { my ($filename, $line) = @_; state $prev;

    @code = @{"::_<$filename"}; my $now = Time::HiRes:time(); $line_of_code = $code[ $line ]; if ($prev) { my $took = $time - $prev{time};
  61. sub emit_trace { my ($filename, $line) = @_; state $prev;

    @code = @{"::_<$filename"}; my $now = Time::HiRes:time(); $line_of_code = $code[ $line ]; if ($prev) { my $took = $time - $prev{time}; printf "%8.04f %s", $took, $prev{code}; }
  62. sub emit_trace { my ($filename, $line) = @_; state $prev;

    @code = @{"::_<$filename"}; my $now = Time::HiRes:time(); $line_of_code = $code[ $line ]; if ($prev) { my $took = $time - $prev{time}; printf "%8.04f %s", $took, $prev{code}; } $prev = { time => $time, code => $line_of_code }; }
  63. if ( $not_likely && $really_rare && $does_this_ever_happen ) { #

    some really # annoying-to-maintain # code }
  64. sub alive { my ($ident) = @_; ! my $sock

    = IO::Socket::INET->new( Proto => 'udp', PeerAddr => "$HOST:$PORT", ); ! unless ($sock) { warn "error opening UDP socket: $!"; return; } ! my $data = JSON->new->encode({ ident => $ident, user => getpwuid($>) || '(unknown)', }); ! $sock->send($data) or warn "couldn't send: $!"; }
  65. my $sock = IO::Socket::INET->new( Proto => 'udp', LocalHost => 0,

    LocalPort => 3030, MultiHomed => 1, ); while (1) { my $addr = $sock->recv(my $data, 1024); my (undef, $remote) = sockaddr_in($addr); my $ip_addr = inet_ntoa($remote_addr); ! ## log data and ip_addr to file }
  66. my $f = 20; ! # prepare for spawning! !

    while ($f--) { if (fork) { next; } else { # do stuff sleep 30; exit; } } ! while (1) { my $pid = wait; last if $pid == -1; say "$pid exited"; }
  67. my $f = 20; ! # prepare for spawning! !

    while ($f--) { if (fork) { next; } else { # do stuff sleep 30; exit; } } ! while (1) { my $pid = wait; last if $pid == -1; say "$pid exited"; }
  68. my $f = 20; ! # prepare for spawning! !

    while ($f--) { if (fork) { next; } else { require Dist::Zilla; sleep 30; exit; } } ! while (1) { my $pid = wait; last if $pid == -1; say "$pid exited"; }
  69. my $f = 20; ! # prepare for spawning! !

    while ($f--) { if (fork) { next; } else { require Dist::Zilla; sleep 30; exit; } } ! while (1) { my $pid = wait; last if $pid == -1; say "$pid exited"; }
  70. my $f = 20; ! # prepare for spawning! require

    Dist::Zilla; ! while ($f--) { if (fork) { next; } else { # do work exit; } } ! while (1) { my $pid = wait; last if $pid == -1; say "$pid exited"; }
  71. package PostForkINC; ! sub import { my ($self, $code) =

    @_; ! my $pid = $$; ! my $callback = sub { return if $pid == $$; my (undef, $filename) = @_; $code->($filename); return; }; ! unshift @INC, $callback; };
  72. package PostForkINC::Alive; ! sub import { my ($class, $ident) =

    @_; ! require PostForkINC; PostForkINC->import(sub { my ($filename) = @_; $filename =~ s{\.pm\z}{}; alive("postfork.$ident.$filename"); }); } use PostForkINC::Alive 'pie-eater';
  73. postfork.riddle-mda.Class-ISA postfork.riddle-mda.Crypt-SSLeay postfork.riddle-mda.Crypt-SSLeay-CTX postfork.riddle-mda.Crypt-SSLeay-MainContext postfork.riddle-mda.Crypt-SSLeay-X509 postfork.riddle-mda.DBD-mysql-GetInfo postfork.riddle-mda.DBIx-Class-Cursor postfork.riddle-mda.DBIx-Class-SQLMaker postfork.riddle-mda.DBIx-Class-SQLMaker-LimitDialects postfork.riddle-mda.DBIx-Class-SQLMaker-MySQL

    postfork.riddle-mda.DBIx-Class-Storage-DBI-Cursor postfork.riddle-mda.DBIx-Class-Storage-DBI-mysql postfork.riddle-mda.Data-Hive-PathPacker postfork.riddle-mda.Data-Hive-PathPacker-Strict postfork.riddle-mda.Email-Date-Format postfork.riddle-mda.Encode-Byte postfork.riddle-mda.Encode-CJKConstants postfork.riddle-mda.Encode-CN postfork.riddle-mda.Encode-CN-HZ postfork.riddle-mda.Encode-JP postfork.riddle-mda.Encode-JP-JIS7 postfork.riddle-mda.Encode-KR postfork.riddle-mda.Encode-KR-2022_KR postfork.riddle-mda.Encode-MIME-Header postfork.riddle-mda.Encode-TW postfork.riddle-mda.HTML-Entities postfork.riddle-mda.HTML-HeadParser postfork.riddle-mda.HTML-Parser postfork.riddle-mda.HTTP-Config postfork.riddle-mda.HTTP-Headers-Util postfork.riddle-mda.HTTP-Request-Common postfork.riddle-mda.Hash-Merge postfork.riddle-mda.LWP-Protocol-https postfork.riddle-mda.Net-DNS-RR-A postfork.riddle-mda.Net-DNS-RR-CNAME postfork.riddle-mda.Net-DNS-RR-MX postfork.riddle-mda.Net-DNS-RR-PTR postfork.riddle-mda.Net-DNS-RR-SOA postfork.riddle-mda.Net-HTTPS
  74. [alias] ci = commit -a cl = clean -dfx cc

    = cherry-pick ff = merge --ff-only fx = commit -a --amend -C HEAD ix = diff --cached st = status -sb fap = fetch --all --prune wip = commit -a -m WIP git = !git
  75. hist = log --graph --all \ --color=always \ --decorate !

    shist = log --graph \ --color=always \ --decorate
  76. $ git re-edit • if there are dirty files, edit

    them • otherwise, edit the files edited in last commit • or supply a commit to edit the files changed in it
  77. if ($commit) { chomp(@changed = grep /\S/, qx{git show --pretty="format:"

    --name-only $commit}); } else { chomp(@changed = qx{git status -- porcelain}); exit 1 unless $? == 0; @changed = grep !/^\?\? /, @changed unless $opt{q}; s/^.. // or die "<$_>???\n" for @changed; s/.* -> // for @changed; die "Fucking shell, how does it work?\n" if grep / /, @changed; ! chomp(@changed = qx{find @changed -type f }) if @changed; exit 1 unless $? == 0; }
  78. extending git is easy • the git-* convention • it's

    all built on mostly-simple commands • (even if some of them are sort of dumb) • look at the commands I showed for examples
  79. • brand new server every time! • user accounts created

    automatically • vim, emacs, whatever you need: installed
  80. • brand new server every time! • user accounts created

    automatically • vim, emacs, whatever you need: installed • all thrown away when you're done
  81. • brand new server every time! • user accounts created

    automatically • vim, emacs, whatever you need: installed • all thrown away when you're done
  82. • brand new server every time! • user accounts created

    automatically • vim, emacs, whatever you need: installed • all thrown away when you're done • but where are my dotfiles?
  83. ! dots: ! - repo: [email protected]:rjbs/rjbs-dots.git - repo: [email protected]:rjbs/rjbs-osx-dots.git -

    repo: [email protected]:rjbs/rjbs-vim-dots.git - repo: [email protected]:git/rjbs-mail-dots.git - repo: [email protected]:git/rjbs-private-dots.git ! - repo: [email protected]:git/rjbs-work-dots.git
  84. Dude, where's my .zshrc? ! ! dots: ! - repo:

    [email protected]:rjbs/rjbs-dots.git - repo: [email protected]:rjbs/rjbs-osx-dots.git - repo: [email protected]:rjbs/rjbs-vim-dots.git - repo: [email protected]:git/rjbs-mail-dots.git - repo: [email protected]:git/rjbs-private-dots.git ! ! !
  85. use ... • get your dotfiles under version control •

    …and shared between your computers
  86. use ... • get your dotfiles under version control •

    …and shared between your computers • …but still with per-host-specific stuff
  87. use ... • get your dotfiles under version control •

    …and shared between your computers • …but still with per-host-specific stuff • …and split between shareable and private
  88. use ... • get your dotfiles under version control •

    …and shared between your computers • …but still with per-host-specific stuff • …and split between shareable and private • …so you can share your config!
  89. use ... • get your dotfiles under version control •

    …and shared between your computers • …but still with per-host-specific stuff • …and split between shareable and private • …so you can share your config! • …and maybe do more pairing!
  90. You already produce a lot of data, that can tell

    you a lot about what you're doing! (that's the point)
  91. sub did_reading { my ($self, $prev) = @_; # Recorded

    is the number of items that were 14 days old yesterday. The # number of items 15 days old today should be fewer. my %count; # stupid passing of $self is a temporary situation -- rjbs, 2013-11-04 my @bookmarks = Ywar::Instapaper->bookmark_list($self); my $old_14 = grep { $_->{time} < $^T - 14 * 86_400 } @bookmarks; my $old_15 = grep { $_->{time} < $^T - 15 * 86_400 } @bookmarks; my $last = $prev->{measured_value}; my %result; if ($old_15 < $last) { my $closed = $last - $old_15; @result{ qw(note met_goal) } = ("items read or deleted: $closed", 1); } $result{value} = $old_14; return \%result; }
  92. sub bookmark_list { my ($self, $configger) = @_; my $c_key

    = $configger->consumer_key; my $c_secret = $configger->consumer_secret; my $ua = LWP::Authen::OAuth->new( oauth_consumer_secret => $c_secret, oauth_token => $configger->oauth_token, oauth_token_secret => $configger->oauth_token_secret, ); my $r = $ua->post( 'https://www.instapaper.com/api/1/bookmarks/list', [ limit => 200, oauth_consumer_key => $c_key, ], ); my @bookmarks = sort {; $a->{time} <=> $b->{time} } grep {; $_->{type} eq 'bookmark' } @{ JSON->new->decode($r->decoded_content) }; return @bookmarks; }
  93. sub bookmark_list { my ($self, $configger) = @_; my $c_key

    = $configger->consumer_key; my $c_secret = $configger->consumer_secret; my $ua = LWP::Authen::OAuth->new( oauth_consumer_secret => $c_secret, oauth_token => $configger->oauth_token, oauth_token_secret => $configger->oauth_token_secret, ); my $r = $ua->post( 'https://www.instapaper.com/api/1/bookmarks/list', [ limit => 200, oauth_consumer_key => $c_key, ], ); my @bookmarks = sort {; $a->{time} <=> $b->{time} } grep {; $_->{type} eq 'bookmark' } @{ JSON->new->decode($r->decoded_content) }; return @bookmarks; } LWP::Authen::OAuth
  94. API Auth • Basic HTTP Authentication: means sharing pw •

    In-site token generation: user as token broker
  95. API Auth • Basic HTTP Authentication: means sharing pw •

    In-site token generation: user as token broker • OAuth 1: strict protocol, complex helper libs
  96. API Auth • Basic HTTP Authentication: means sharing pw •

    In-site token generation: user as token broker • OAuth 1: strict protocol, complex helper libs • OAuth 2: it's more like a state of mind
  97. sub bookmark_list { my ($self, $configger) = @_; my $c_key

    = $configger->consumer_key; my $c_secret = $configger->consumer_secret; my $ua = LWP::Authen::OAuth->new( oauth_consumer_secret => $c_secret, oauth_token => $configger->oauth_token, oauth_token_secret => $configger->oauth_token_secret, ); my $r = $ua->post( 'https://www.instapaper.com/api/1/bookmarks/list', [ limit => 200, oauth_consumer_key => $c_key, ], ); my @bookmarks = sort {; $a->{time} <=> $b->{time} } grep {; $_->{type} eq 'bookmark' } @{ JSON->new->decode($r->decoded_content) }; return @bookmarks; }
  98. my $client = Net::OAuth::Client->new( $self->api_key, $self->secret, site => 'https://oauth.withings.com/', request_token_path

    => '/account/request_token', authorize_path => '/account/authorize', access_token_path => '/account/access_token', callback => 'oob', );
  99. my $client = OAuth::Lite2::Client::WebServer->new( id => $id, secret => $secret,

    authorize_uri => q{https://runkeeper.com/apps/authorize}, access_token_uri => q{https://runkeeper.com/apps/token}, ); ! my $url = $client->uri_to_redirect( redirect_uri => q{http://rjbs.manxome.org/}, ); ! say $url; chomp( my $code = <STDIN> ); ! my $access_token = $client->get_access_token( code => $code, redirect_uri => q{http://rjbs.manxome.org/}, ) or die $client->errstr; ! print Dumper({ access_token => $access_token->access_token, expires_at => time() + $access_token->expires_in, refresh_token => $access_token->refresh_token, });
  100. my $auth = base64_encode("$user:$pass", ""); my $ua = LWP::UserAgent->new(keep_alive =>

    1); $ua->default_header(Authorization => "Basic $auth"); my $res = $ua->get("https://api.feedbin.me/v2/entries.json");
  101. package SampleBot; use Moses; server 'irc.perl.org'; nickname 'sample-bot'; channels '#bots';

    event irc_bot_addressed => sub { my ($self, $nickstr, $channel, $msg) = @_[OBJECT, ARG0, ARG1, ARG2]; my ($nick) = split /!/, $nickstr; $self->privmsg( $channel => "$nick: Hey there." ); }; SampleBot->run;
  102. event START => sub { my ($self) = $_[OBJECT]; $self->delay(300

    => 'consider_nagging'); }; ! event consider_nagging => sub { my ($self) = $_[OBJECT]; $self->delay(300 => 'consider_nagging'); return if $self->timer_running; return if $self->nagged_recently; $self->send_angry_privmsg; };
  103. event consider_nagging => sub { my ($self) = $_[OBJECT]; $self->delay(300

    => 'consider_nagging'); return if $self->timer_running; return if $self->nagged_recently; $self->send_angry_privmsg; };
  104. event consider_nagging => sub { my ($self) = $_[OBJECT]; $self->delay(300

    => 'consider_nagging'); return if $self->timer_running; return if $self->nagged_recently; if ($self->being_ignored) { $self->send_angry_sms; } else { $self->send_angry_privmsg; $self->being_ignored(1); } };
  105. event consider_nagging => sub { my ($self) = $_[OBJECT]; $self->delay(300

    => 'consider_nagging'); return if $self->timer_running; return if $self->nagged_recently; if ($self->being_ignored) { $self->send_angry_sms; } else { $self->send_angry_privmsg; $self->being_ignored(1); } };
  106. sub sms { my ($self, $number, $msg) = @_; !

    my $ua = LWP::UserAgent->new; my $res = $ua->post( "https://api.twilio.com/2010-04-01/Accounts/$SID/SMS/Messages", { From => $my_twilio_number, To => $number, Body => $msg, }, Authorization => "Basic $AUTH}", ); }
  107. POE::Component::Server::SimpleHTTP->new( ALIAS => 'httpd', ADDRESS => 0, PORT => $self->httpd_port,

    HANDLERS => [ { DIR => '^/sms$', SESSION => 'Synergy', EVENT => '_http_sms', }, ], );
  108. POE::Component::Server::SimpleHTTP->new( ALIAS => 'httpd', ADDRESS => 0, PORT => $self->httpd_port,

    HANDLERS => [ { DIR => '^/sms$', SESSION => 'Synergy', EVENT => '_http_sms', }, ], ); event _http_sms => sub { my ($kernel, $self, $req, $res) = @_[KERNEL, OBJECT, ARG0, ARG1]; $response->code(200); $response->content( $self->response_for($req) ); $kernel->call( 'httpd', 'DONE', $response ); };
  109. If you're not mashing up web service APIs with an

    asynchronous daemon… …you are living a half life.
  110. If you're not mashing up web service APIs with an

    asynchronous daemon… …you are living a half life.