SlideShare a Scribd company logo
1 of 155
Download to read offline
App::Cmd
Writing Maintainable Commands
TMTOWTDI
There’s More Than
 One Way To Do It
Web
Web

• Mason
Web

• Mason
• Catalyst
Web

• Mason
• Catalyst
• CGI::Application
Web

• Mason
• Catalyst
• CGI::Application
• Maypole
Web

• Mason
• Catalyst
• CGI::Application
• Maypole
• Continuity
Web

• Mason              • RayApp
• Catalyst
• CGI::Application
• Maypole
• Continuity
Web

• Mason              • RayApp
• Catalyst           • Gantry
• CGI::Application
• Maypole
• Continuity
Web

• Mason              • RayApp
• Catalyst           • Gantry
• CGI::Application   • Tripletail
• Maypole
• Continuity
Web

• Mason              • RayApp
• Catalyst           • Gantry
• CGI::Application   • Tripletail
• Maypole            • CGI::ExApp
• Continuity
Web

• Mason              • RayApp
• Catalyst           • Gantry
• CGI::Application   • Tripletail
• Maypole            • CGI::ExApp
• Continuity         • OpenInteract
Daemons
Daemons

• POE
Daemons

• POE
• Danga
Daemons

• POE
• Danga
• Net::Server
Daemons

• POE
• Danga
• Net::Server
• Daemon::Generic
Daemons

• POE               • Proc::Daemon
• Danga
• Net::Server
• Daemon::Generic
Daemons

• POE               • Proc::Daemon
• Danga             • Net::Daemon
• Net::Server
• Daemon::Generic
Daemons

• POE               • Proc::Daemon
• Danga             • Net::Daemon
• Net::Server       • MooseX::Daemonize
• Daemon::Generic
Daemons

• POE               • Proc::Daemon
• Danga             • Net::Daemon
• Net::Server       • MooseX::Daemonize
• Daemon::Generic   • Event
TMTOWTDI
TMTOWTDI


• All the big problem sets have a few solutions!
TMTOWTDI


• All the big problem sets have a few solutions!
• So, when I needed to write a CLI app, I
  checked CPAN...
Command-Line Apps
Command-Line Apps


• App::CLI
Command-Line Apps
Command-Line Apps



    :-(
Everybody writes
command-line apps!
Why are there no
  good tools?
Second-Class Citizens
Second-Class Citizens

• That’s how we view them.
Second-Class Citizens

• That’s how we view them.
• They’re
Second-Class Citizens

• That’s how we view them.
• They’re
 • hard to test
Second-Class Citizens

• That’s how we view them.
• They’re
 • hard to test
 • not reusable components
Second-Class Citizens

• That’s how we view them.
• They’re
 • hard to test
 • not reusable components
 • hard to add more behavior later
Here’s an Example
Example Script


$ sink 30min “server mx-pa-1 crashed!”
Example Script

$ sink --list

who   | time | event
------+-------+----------------------------
rjbs | 30min | server mx-pa-1 crashed!
Example Script

GetOptions(%opt, ...);

if ($opt{list}) {
  die if @ARGV;
  @events = Events->get_all;
} else {
  my ($duration, $desc) = @ARGV;
  Event->new($duration, $desc);
}
Example Script

$ sink --list --user jcap

who   | time | event
------+-------+----------------------------
jcap | 2hr    | redeploy exigency subsystem
Example Script
GetOptions(%opt, ...);

if ($opt{list}) {
  die if @ARGV;
  @events = $opt{user}
          ? Events->get(user => $opt{user})
          : Events->get_all;
} else {
  my ($duration, $desc) = @ARGV;
  Event->new($duration, $desc);
}
Example Script
GetOptions(%opt, ...);

if ($opt{list}) {
  die if @ARGV;
  @events = $opt{user}
          ? Events->get(user => $opt{user})
          : Events->get_all;
} else {
  my ($duration, $desc) = @ARGV;
  die if $opt{user};
  Event->new($duration, $desc);
}
Example Script

$ sink --start ‘putting out oil fire‘
Event begun! use --finish to finish event

$ sink --list --open
18. putting out oil fire

$ sink --finish 18
Event finished! Total time taken: 23 min
Insult to Injury
Insult to Injury

• ...well, that’s going to take a lot of
  testing.
Insult to Injury

• ...well, that’s going to take a lot of
  testing.
• How can we test it?
Insult to Injury

• ...well, that’s going to take a lot of
  testing.
• How can we test it?
• my $output = `sink @args`;
Insult to Injury

• ...well, that’s going to take a lot of
  testing.
• How can we test it?
• my $output = `sink @args`;
• IPC::Run3 (or one of those)
Here’s a Solution
Command Breakdown


$ sink do --for 1hr --ago 1d ‘rebuild raid’
Command Breakdown


$ sink do --for 1hr --ago 1d ‘rebuild raid’

  App
Command Breakdown


$ sink do --for 1hr --ago 1d ‘rebuild raid’

    Command
Command Breakdown


$ sink do --for 1hr --ago 1d ‘rebuild raid’

                Options
Command Breakdown


$ sink do --for 1hr --ago 1d ‘rebuild raid’

                                 Args
Command Breakdown


$ sink do --for 1hr --ago 1d ‘rebuild raid’
“do” command
“do” command
sub run {
“do” command
sub run {
  my ($self, $opt, $args) = @_;
“do” command
sub run {
  my ($self, $opt, $args) = @_;
“do” command
sub run {
  my ($self, $opt, $args) = @_;

  my $start   = parse_ago($opt->{ago});
“do” command
sub run {
  my ($self, $opt, $args) = @_;

  my $start = parse_ago($opt->{ago});
  my $length = parse_duration($opt->{for});
“do” command
sub run {
  my ($self, $opt, $args) = @_;

  my $start = parse_ago($opt->{ago});
  my $length = parse_duration($opt->{for});
  my $desc   = $args->[0];
“do” command
sub run {
  my ($self, $opt, $args) = @_;

  my $start = parse_ago($opt->{ago});
  my $length = parse_duration($opt->{for});
  my $desc   = $args->[0];
“do” command
sub run {
  my ($self, $opt, $args) = @_;

  my $start = parse_ago($opt->{ago});
  my $length = parse_duration($opt->{for});
  my $desc   = $args->[0];

  Sink::Event->create(
“do” command
sub run {
  my ($self, $opt, $args) = @_;

  my $start = parse_ago($opt->{ago});
  my $length = parse_duration($opt->{for});
  my $desc   = $args->[0];

  Sink::Event->create(
    start => $start,
“do” command
sub run {
  my ($self, $opt, $args) = @_;

  my $start = parse_ago($opt->{ago});
  my $length = parse_duration($opt->{for});
  my $desc   = $args->[0];

  Sink::Event->create(
    start => $start,
    finish => $start + $length,
“do” command
sub run {
  my ($self, $opt, $args) = @_;

  my $start = parse_ago($opt->{ago});
  my $length = parse_duration($opt->{for});
  my $desc   = $args->[0];

  Sink::Event->create(
    start => $start,
    finish => $start + $length,
    desc   => $desc;
“do” command
sub run {
  my ($self, $opt, $args) = @_;

  my $start = parse_ago($opt->{ago});
  my $length = parse_duration($opt->{for});
  my $desc   = $args->[0];

  Sink::Event->create(
     start => $start,
     finish => $start + $length,
     desc   => $desc;
  );
“do” command
sub run {
  my ($self, $opt, $args) = @_;

  my $start = parse_ago($opt->{ago});
  my $length = parse_duration($opt->{for});
  my $desc   = $args->[0];

  Sink::Event->create(
     start => $start,
     finish => $start + $length,
     desc   => $desc;
  );
“do” command
sub run {
  my ($self, $opt, $args) = @_;

  my $start = parse_ago($opt->{ago});
  my $length = parse_duration($opt->{for});
  my $desc   = $args->[0];

  Sink::Event->create(
     start => $start,
     finish => $start + $length,
     desc   => $desc;
  );

  print “event created!”;
“do” command
sub run {
  my ($self, $opt, $args) = @_;

    my $start = parse_ago($opt->{ago});
    my $length = parse_duration($opt->{for});
    my $desc   = $args->[0];

    Sink::Event->create(
       start => $start,
       finish => $start + $length,
       desc   => $desc;
    );

    print “event created!”;
}
“do” command
“do” command

sub opt_desc {
“do” command

sub opt_desc {
  [ “start=s”, “when you started doing this” ],
“do” command

sub opt_desc {
  [ “start=s”, “when you started doing this” ],
  [ “for=s”,   “how long you did this for”,
“do” command

sub opt_desc {
  [ “start=s”, “when you started doing this” ],
  [ “for=s”,   “how long you did this for”,
    { required => 1} ],
“do” command

sub opt_desc {
  [ “start=s”, “when you started doing this” ],
  [ “for=s”,   “how long you did this for”,
    { required => 1} ],
}
“do” command
“do” command

sub validate_args {
“do” command

sub validate_args {
  my ($self, $opt, $args) = @_;
“do” command

sub validate_args {
  my ($self, $opt, $args) = @_;
“do” command

sub validate_args {
  my ($self, $opt, $args) = @_;

  if (@$args != 1) {
“do” command

sub validate_args {
  my ($self, $opt, $args) = @_;

  if (@$args != 1) {
    $self->usage_error(“provide one argument”);
“do” command

sub validate_args {
  my ($self, $opt, $args) = @_;

  if (@$args != 1) {
    $self->usage_error(“provide one argument”);
  }
“do” command

sub validate_args {
  my ($self, $opt, $args) = @_;

    if (@$args != 1) {
      $self->usage_error(“provide one argument”);
    }
}
package Sink::Command::Do;
use base ‘App::Cmd::Command’;

sub opt_desc {
  [ “start=s”, “when you started doing this” ],
  [ “for=s”,   “how long you did this for”,
    { required => 1} ],
}

sub validate_args {
  my ($self, $opt, $args) = @_;

    if (@$args != 1) {
      $self->usage_error(“provide one argument”);
    }
}

sub run {
  my ($self, $opt, $args) = @_;

    my $start = parse_ago($opt->{ago});
    my $length = parse_duration($opt->{for});
    my $desc   = $args->[0];

    Sink::Event->create(
       start => $start,
       finish => $start + $length,
       desc   => $desc;
    );

    print “event created!”;
}

1;
package Sink::Command::Do;
use base ‘App::Cmd::Command’;

sub opt_desc {
  [ “start=s”, “when you started doing this” ],
  [ “for=s”,   “how long you did this for”,
    { required => 1} ],
}

sub validate_args {
  my ($self, $opt, $args) = @_;

    if (@$args != 1) {
      $self->usage_error(“provide one argument”);
    }
}

sub run {
  my ($self, $opt, $args) = @_;

    my $start = parse_ago($opt->{ago});
    my $length = parse_duration($opt->{for});
    my $desc   = $args->[0];

    Sink::Event->create(
       start => $start,
       finish => $start + $length,
       desc   => $desc;
    );

    print “event created!”;
}

1;
Extra Scaffolding
Extra Scaffolding
package Sink;
Extra Scaffolding
package Sink;
use base ‘App::Cmd’;
Extra Scaffolding
package Sink;
use base ‘App::Cmd’;




1;
Extra Scaffolding


use Sink;
Sink->run;
Testing Your App
Testing App::Cmd
Testing App::Cmd
use Test::More tests => 3;
Testing App::Cmd
use Test::More tests => 3;
use Test::Output;
Testing App::Cmd
use Test::More tests => 3;
use Test::Output;
Testing App::Cmd
use Test::More tests => 3;
use Test::Output;

my $error;
Testing App::Cmd
use Test::More tests => 3;
use Test::Output;

my $error;
my $stdout = do {
Testing App::Cmd
use Test::More tests => 3;
use Test::Output;

my $error;
my $stdout = do {
  local @ARGV = qw(do --for 8hr ‘sleeping’);
Testing App::Cmd
use Test::More tests => 3;
use Test::Output;

my $error;
my $stdout = do {
  local @ARGV = qw(do --for 8hr ‘sleeping’);
  stdout_from(sub {
Testing App::Cmd
use Test::More tests => 3;
use Test::Output;

my $error;
my $stdout = do {
  local @ARGV = qw(do --for 8hr ‘sleeping’);
  stdout_from(sub {
    eval { Sink->run; 1 } or $error = $@;
Testing App::Cmd
use Test::More tests => 3;
use Test::Output;

my $error;
my $stdout = do {
  local @ARGV = qw(do --for 8hr ‘sleeping’);
  stdout_from(sub {
    eval { Sink->run; 1 } or $error = $@;
  });
Testing App::Cmd
use Test::More tests => 3;
use Test::Output;

my $error;
my $stdout = do {
  local @ARGV = qw(do --for 8hr ‘sleeping’);
  stdout_from(sub {
    eval { Sink->run; 1 } or $error = $@;
  });
}
Testing App::Cmd
use Test::More tests => 3;
use Test::Output;

my $error;
my $stdout = do {
  local @ARGV = qw(do --for 8hr ‘sleeping’);
  stdout_from(sub {
    eval { Sink->run; 1 } or $error = $@;
  });
}
Testing App::Cmd
use Test::More tests => 3;
use Test::Output;

my $error;
my $stdout = do {
  local @ARGV = qw(do --for 8hr ‘sleeping’);
  stdout_from(sub {
    eval { Sink->run; 1 } or $error = $@;
  });
}

like $stdout, qr/^event created!$/;
Testing App::Cmd
use Test::More tests => 3;
use Test::Output;

my $error;
my $stdout = do {
  local @ARGV = qw(do --for 8hr ‘sleeping’);
  stdout_from(sub {
    eval { Sink->run; 1 } or $error = $@;
  });
}

like $stdout, qr/^event created!$/;
is   Sink::Event->get_count, 1;
Testing App::Cmd
use Test::More tests => 3;
use Test::Output;

my $error;
my $stdout = do {
  local @ARGV = qw(do --for 8hr ‘sleeping’);
  stdout_from(sub {
    eval { Sink->run; 1 } or $error = $@;
  });
}

like $stdout, qr/^event created!$/;
is   Sink::Event->get_count, 1;
ok   ! $error;
Testing App::Cmd

use Test::More tests => 3;
use Test::App::Cmd;
use Sink;

my ($stdout, $error) = test_app(
   Sink => qw(do --for 8hr ‘sleeping’)
);

like $stdout, qr/^event created!$/;
is   Sink::Event->get_count, 1;
ok   ! $error;
Testing App::Cmd

use Test::More tests => π;
use Sink::Command::Do;

eval {
   Sink::Command::Do->validate_args(
      { for => ‘1hr’ },
      [ 1, 2, 3 ],
   );
};

like $@, qr/one arg/;
Growing Your App
Command Breakdown


$ sink do --for 1hr --ago 1d ‘rebuild raid’
Command Breakdown


$ sink do --for 1hr --ago 1d ‘rebuild raid’

    Command
package Sink::Command::List;
use base ‘App::Cmd::Command’;

sub opt_desc { ... }

sub validate_args { ... }

sub run { ... }

1;
package Sink::Command::List;
use base ‘App::Cmd::Command’;

sub opt_desc {
  [ “open”,     “only unfinished events”    ],
  [ “user|u=s”, “only events for this user” ],
}

sub validate_args {
  shift->usage_error(’no args allowed’)
    if @{ $_[1] }
}

sub run { ... }

1;
package Sink::Command::Start;
use base ‘App::Cmd::Command’;

sub opt_desc { ... }

sub validate_args { ... }

sub run { ... }

1;
package Sink::Command::Start;
use base ‘App::Cmd::Command’;

sub opt_desc { return }

sub validate_args {
  shift->usage_error(’one args required’)
    if @{ $_[1] } != 1
}

sub run { ... }

1;
More Commands!

$ sink do --for 1hr --ago 1d ‘rebuild raid’

$ sink list --open

$ sink start ‘porting PHP to ASP.NET’
More Commands!
$ sink
sink help <command>

Available commands:
  commands: list the application’s commands
      help: display a command’s help screen

       do: (unknown)
     list: (unknown)
    start: (unknown)
Command Listing

package Sink::Command::Start;

=head1 NAME

Sink::Command::Start - start a new task

=cut
Command Listing


package Sink::Command::Start;

sub abstract { ‘start a new task’; }
Command Listing

$ sink commands

Available commands:
  commands: list the application’s commands
      help: display a command’s help screen

       do: record that you did something
     list: list existing events
    start: start a new task
Command Listing
Command Listing

$ sink help list
Command Listing

$ sink help list
Command Listing

$ sink help list

sink list [long options...]
Command Listing

$ sink help list

sink list [long options...]
    -u --user     only events for this user
Command Listing

$ sink help list

sink list [long options...]
    -u --user     only events for this user
    --open        only unfinished events
Core Commands
Core Commands

• Where did “help” and “commands”
  come from?
Core Commands

• Where did “help” and “commands”
  come from?
• App::Cmd::Command::help
Core Commands

• Where did “help” and “commands”
  come from?
• App::Cmd::Command::help
• App::Cmd::Command::commands
Default Command
package Sink;
use base ‘App::Cmd’;




1;
Default Command
package Sink;
use base ‘App::Cmd’;

sub default_command { ‘help’ } # default




1;
Default Command
package Sink;
use base ‘App::Cmd’;

sub default_command { ‘list’ }




1;
One-Command
 Applications
Simple Example


$ ckmail check -a work -a home
No new mail.
Simple Example


$ ckmail -a work -a home
No new mail.
The Lousy Way
The Lousy Way

• create Ckmail::Command::Check
The Lousy Way

• create Ckmail::Command::Check
• make empty Ckmail.pm
The Lousy Way

• create Ckmail::Command::Check
• make empty Ckmail.pm
• make “check” the default command
The Simple Way

package Ckmail::Command::Check;
use base ‘App::Cmd::Command’;

sub opt_desc { ... }

sub run { ... }

1;
The Simple Way

package Ckmail::Command::Check;
use base ‘App::Cmd::Simple’;

sub opt_desc { ... }

sub run { ... }

1;
The Simple Way


use Ckmail;
Ckmail->run;
The Simple Way


use Ckmail::Command::Check;
Ckmail::Command::Check->run;
App::Cmd::Simple
App::Cmd::Simple

• You write a command...
App::Cmd::Simple

• You write a command...
• ...but you use it like an App::Cmd.
App::Cmd::Simple

• You write a command...
• ...but you use it like an App::Cmd.
• Later, you can just demote it.
Any
Questions?
Thank
 You!

More Related Content

What's hot

Fewer cables
Fewer cablesFewer cables
Fewer cablesacme
 
Command
CommandCommand
Commandgajshield
 
Any event intro
Any event introAny event intro
Any event introqiang
 
Keep it simple web development stack
Keep it simple web development stackKeep it simple web development stack
Keep it simple web development stackEric Ahn
 
Modern Getopt for Command Line Processing in Perl
Modern Getopt for Command Line Processing in PerlModern Getopt for Command Line Processing in Perl
Modern Getopt for Command Line Processing in PerlNova Patch
 
Asynchronous Programming FTW! 2 (with AnyEvent)
Asynchronous Programming FTW! 2 (with AnyEvent)Asynchronous Programming FTW! 2 (with AnyEvent)
Asynchronous Programming FTW! 2 (with AnyEvent)xSawyer
 
Exploiting the newer perl to improve your plugins
Exploiting the newer perl to improve your pluginsExploiting the newer perl to improve your plugins
Exploiting the newer perl to improve your pluginsMarian Marinov
 
Perl web frameworks
Perl web frameworksPerl web frameworks
Perl web frameworksdiego_k
 
The promise of asynchronous php
The promise of asynchronous phpThe promise of asynchronous php
The promise of asynchronous phpWim Godden
 
Building Better Applications with Data::Manager
Building Better Applications with Data::ManagerBuilding Better Applications with Data::Manager
Building Better Applications with Data::ManagerJay Shirley
 
Smolder @Silex
Smolder @SilexSmolder @Silex
Smolder @SilexJeen Lee
 
My app is secure... I think
My app is secure... I thinkMy app is secure... I think
My app is secure... I thinkWim Godden
 
10 Catalyst Tips
10 Catalyst Tips10 Catalyst Tips
10 Catalyst TipsJay Shirley
 
Perl 6 by example
Perl 6 by examplePerl 6 by example
Perl 6 by exampleAndrew Shitov
 
Hypers and Gathers and Takes! Oh my!
Hypers and Gathers and Takes! Oh my!Hypers and Gathers and Takes! Oh my!
Hypers and Gathers and Takes! Oh my!Workhorse Computing
 
Logstash for SEO: come monitorare i Log del Web Server in realtime
Logstash for SEO: come monitorare i Log del Web Server in realtimeLogstash for SEO: come monitorare i Log del Web Server in realtime
Logstash for SEO: come monitorare i Log del Web Server in realtimeAndrea Cardinale
 
Teaching Your Machine To Find Fraudsters
Teaching Your Machine To Find FraudstersTeaching Your Machine To Find Fraudsters
Teaching Your Machine To Find FraudstersIan Barber
 
The promise of asynchronous php
The promise of asynchronous phpThe promise of asynchronous php
The promise of asynchronous phpWim Godden
 
Debugging: Rules And Tools - PHPTek 11 Version
Debugging: Rules And Tools - PHPTek 11 VersionDebugging: Rules And Tools - PHPTek 11 Version
Debugging: Rules And Tools - PHPTek 11 VersionIan Barber
 

What's hot (20)

Fewer cables
Fewer cablesFewer cables
Fewer cables
 
Command
CommandCommand
Command
 
Any event intro
Any event introAny event intro
Any event intro
 
Keep it simple web development stack
Keep it simple web development stackKeep it simple web development stack
Keep it simple web development stack
 
Modern Getopt for Command Line Processing in Perl
Modern Getopt for Command Line Processing in PerlModern Getopt for Command Line Processing in Perl
Modern Getopt for Command Line Processing in Perl
 
Asynchronous Programming FTW! 2 (with AnyEvent)
Asynchronous Programming FTW! 2 (with AnyEvent)Asynchronous Programming FTW! 2 (with AnyEvent)
Asynchronous Programming FTW! 2 (with AnyEvent)
 
Exploiting the newer perl to improve your plugins
Exploiting the newer perl to improve your pluginsExploiting the newer perl to improve your plugins
Exploiting the newer perl to improve your plugins
 
Perl web frameworks
Perl web frameworksPerl web frameworks
Perl web frameworks
 
The promise of asynchronous php
The promise of asynchronous phpThe promise of asynchronous php
The promise of asynchronous php
 
Building Better Applications with Data::Manager
Building Better Applications with Data::ManagerBuilding Better Applications with Data::Manager
Building Better Applications with Data::Manager
 
Smolder @Silex
Smolder @SilexSmolder @Silex
Smolder @Silex
 
My app is secure... I think
My app is secure... I thinkMy app is secure... I think
My app is secure... I think
 
10 Catalyst Tips
10 Catalyst Tips10 Catalyst Tips
10 Catalyst Tips
 
Perl 6 by example
Perl 6 by examplePerl 6 by example
Perl 6 by example
 
Hypers and Gathers and Takes! Oh my!
Hypers and Gathers and Takes! Oh my!Hypers and Gathers and Takes! Oh my!
Hypers and Gathers and Takes! Oh my!
 
Logstash for SEO: come monitorare i Log del Web Server in realtime
Logstash for SEO: come monitorare i Log del Web Server in realtimeLogstash for SEO: come monitorare i Log del Web Server in realtime
Logstash for SEO: come monitorare i Log del Web Server in realtime
 
Teaching Your Machine To Find Fraudsters
Teaching Your Machine To Find FraudstersTeaching Your Machine To Find Fraudsters
Teaching Your Machine To Find Fraudsters
 
The promise of asynchronous php
The promise of asynchronous phpThe promise of asynchronous php
The promise of asynchronous php
 
Anyevent
AnyeventAnyevent
Anyevent
 
Debugging: Rules And Tools - PHPTek 11 Version
Debugging: Rules And Tools - PHPTek 11 VersionDebugging: Rules And Tools - PHPTek 11 Version
Debugging: Rules And Tools - PHPTek 11 Version
 

Viewers also liked

Windows command prompt a to z
Windows command prompt a to zWindows command prompt a to z
Windows command prompt a to zSubuh Kurniawan
 
cmd commands
cmd commandscmd commands
cmd commandsRAJ ANAND
 
Sly and the RoarVM: Exploring the Manycore Future of Programming
Sly and the RoarVM: Exploring the Manycore Future of ProgrammingSly and the RoarVM: Exploring the Manycore Future of Programming
Sly and the RoarVM: Exploring the Manycore Future of ProgrammingStefan Marr
 
Fixing mobile phones
Fixing mobile phonesFixing mobile phones
Fixing mobile phonestheviolet
 
SyScan 2015 Bonus Slides - death of the vmsize=0 dyld trick
SyScan 2015 Bonus Slides - death of the vmsize=0 dyld trickSyScan 2015 Bonus Slides - death of the vmsize=0 dyld trick
SyScan 2015 Bonus Slides - death of the vmsize=0 dyld trickStefan Esser
 
Introduction to Processing and creative coding
Introduction to Processing and creative codingIntroduction to Processing and creative coding
Introduction to Processing and creative codingJerome Herr
 
Powershell
PowershellPowershell
PowershellUGAIA
 
Ensuring data integrity in pharmaceutical environment
Ensuring data integrity in pharmaceutical environmentEnsuring data integrity in pharmaceutical environment
Ensuring data integrity in pharmaceutical environmentdeepak mishra
 
Chapter 03 - Program Coding and Design
Chapter 03 - Program Coding and DesignChapter 03 - Program Coding and Design
Chapter 03 - Program Coding and Designpatf719
 
Junos vs ios Troubleshooting comands
Junos vs ios Troubleshooting comands Junos vs ios Troubleshooting comands
Junos vs ios Troubleshooting comands sandeep kumar
 
Pharma data integrity
Pharma data integrityPharma data integrity
Pharma data integrityGirish Swami
 
Comandos ms dos(simbolo de sistema)
Comandos ms dos(simbolo de sistema)Comandos ms dos(simbolo de sistema)
Comandos ms dos(simbolo de sistema)castillodavid
 

Viewers also liked (18)

Windows command prompt a to z
Windows command prompt a to zWindows command prompt a to z
Windows command prompt a to z
 
CMD Command
CMD CommandCMD Command
CMD Command
 
cmd commands
cmd commandscmd commands
cmd commands
 
Sly and the RoarVM: Exploring the Manycore Future of Programming
Sly and the RoarVM: Exploring the Manycore Future of ProgrammingSly and the RoarVM: Exploring the Manycore Future of Programming
Sly and the RoarVM: Exploring the Manycore Future of Programming
 
CMD in 2013
CMD in 2013CMD in 2013
CMD in 2013
 
12 Reasons Why Hot Entrepreneurs Fail
12 Reasons Why Hot Entrepreneurs Fail12 Reasons Why Hot Entrepreneurs Fail
12 Reasons Why Hot Entrepreneurs Fail
 
Fixing mobile phones
Fixing mobile phonesFixing mobile phones
Fixing mobile phones
 
SyScan 2015 Bonus Slides - death of the vmsize=0 dyld trick
SyScan 2015 Bonus Slides - death of the vmsize=0 dyld trickSyScan 2015 Bonus Slides - death of the vmsize=0 dyld trick
SyScan 2015 Bonus Slides - death of the vmsize=0 dyld trick
 
Introduction to Processing and creative coding
Introduction to Processing and creative codingIntroduction to Processing and creative coding
Introduction to Processing and creative coding
 
Cmd v2.0
Cmd v2.0Cmd v2.0
Cmd v2.0
 
Powershell
PowershellPowershell
Powershell
 
DNS,SMTP and POP3
DNS,SMTP and POP3DNS,SMTP and POP3
DNS,SMTP and POP3
 
Ensuring data integrity in pharmaceutical environment
Ensuring data integrity in pharmaceutical environmentEnsuring data integrity in pharmaceutical environment
Ensuring data integrity in pharmaceutical environment
 
Chapter 03 - Program Coding and Design
Chapter 03 - Program Coding and DesignChapter 03 - Program Coding and Design
Chapter 03 - Program Coding and Design
 
Junos vs ios Troubleshooting comands
Junos vs ios Troubleshooting comands Junos vs ios Troubleshooting comands
Junos vs ios Troubleshooting comands
 
Pharma data integrity
Pharma data integrityPharma data integrity
Pharma data integrity
 
Introduction to Coding
Introduction to CodingIntroduction to Coding
Introduction to Coding
 
Comandos ms dos(simbolo de sistema)
Comandos ms dos(simbolo de sistema)Comandos ms dos(simbolo de sistema)
Comandos ms dos(simbolo de sistema)
 

Similar to Writing Modular Command-line Apps with App::Cmd

Perl.Hacks.On.Vim
Perl.Hacks.On.VimPerl.Hacks.On.Vim
Perl.Hacks.On.VimLin Yo-An
 
Dealing with Legacy Perl Code - Peter Scott
Dealing with Legacy Perl Code - Peter ScottDealing with Legacy Perl Code - Peter Scott
Dealing with Legacy Perl Code - Peter ScottO'Reilly Media
 
What's up with Prototype and script.aculo.us?
What's up with Prototype and script.aculo.us?What's up with Prototype and script.aculo.us?
What's up with Prototype and script.aculo.us?Christophe Porteneuve
 
Good Evils In Perl
Good Evils In PerlGood Evils In Perl
Good Evils In PerlKang-min Liu
 
The $path to knowledge: What little it take to unit-test Perl.
The $path to knowledge: What little it take to unit-test Perl.The $path to knowledge: What little it take to unit-test Perl.
The $path to knowledge: What little it take to unit-test Perl.Workhorse Computing
 
Rack Middleware
Rack MiddlewareRack Middleware
Rack MiddlewareLittleBIGRuby
 
The Dom Scripting Toolkit J Query
The Dom Scripting Toolkit J QueryThe Dom Scripting Toolkit J Query
The Dom Scripting Toolkit J QueryQConLondon2008
 
Beijing Perl Workshop 2008 Hiveminder Secret Sauce
Beijing Perl Workshop 2008 Hiveminder Secret SauceBeijing Perl Workshop 2008 Hiveminder Secret Sauce
Beijing Perl Workshop 2008 Hiveminder Secret SauceJesse Vincent
 
Method::Signatures
Method::SignaturesMethod::Signatures
Method::SignaturesMichael Schwern
 
Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)Kang-min Liu
 
Crafting Custom Interfaces with Sub::Exporter
Crafting Custom Interfaces with Sub::ExporterCrafting Custom Interfaces with Sub::Exporter
Crafting Custom Interfaces with Sub::ExporterRicardo Signes
 
Perl Sucks - and what to do about it
Perl Sucks - and what to do about itPerl Sucks - and what to do about it
Perl Sucks - and what to do about it2shortplanks
 
Barely Legal Xxx Perl Presentation
Barely Legal Xxx Perl PresentationBarely Legal Xxx Perl Presentation
Barely Legal Xxx Perl PresentationAttila Balazs
 
Postman On Steroids
Postman On SteroidsPostman On Steroids
Postman On SteroidsSara Tornincasa
 
Vim Hacks
Vim HacksVim Hacks
Vim HacksLin Yo-An
 
Remy Sharp The DOM scripting toolkit jQuery
Remy Sharp The DOM scripting toolkit jQueryRemy Sharp The DOM scripting toolkit jQuery
Remy Sharp The DOM scripting toolkit jQuerydeimos
 
Why Perl, when you can use bash+awk+sed? :P
Why Perl, when you can use bash+awk+sed? :PWhy Perl, when you can use bash+awk+sed? :P
Why Perl, when you can use bash+awk+sed? :PLuciano Rocha
 
R57php 1231677414471772-2
R57php 1231677414471772-2R57php 1231677414471772-2
R57php 1231677414471772-2ady36
 

Similar to Writing Modular Command-line Apps with App::Cmd (20)

Perl.Hacks.On.Vim
Perl.Hacks.On.VimPerl.Hacks.On.Vim
Perl.Hacks.On.Vim
 
Dealing with Legacy Perl Code - Peter Scott
Dealing with Legacy Perl Code - Peter ScottDealing with Legacy Perl Code - Peter Scott
Dealing with Legacy Perl Code - Peter Scott
 
What's up with Prototype and script.aculo.us?
What's up with Prototype and script.aculo.us?What's up with Prototype and script.aculo.us?
What's up with Prototype and script.aculo.us?
 
Good Evils In Perl
Good Evils In PerlGood Evils In Perl
Good Evils In Perl
 
The $path to knowledge: What little it take to unit-test Perl.
The $path to knowledge: What little it take to unit-test Perl.The $path to knowledge: What little it take to unit-test Perl.
The $path to knowledge: What little it take to unit-test Perl.
 
Rack Middleware
Rack MiddlewareRack Middleware
Rack Middleware
 
The Dom Scripting Toolkit J Query
The Dom Scripting Toolkit J QueryThe Dom Scripting Toolkit J Query
The Dom Scripting Toolkit J Query
 
Beijing Perl Workshop 2008 Hiveminder Secret Sauce
Beijing Perl Workshop 2008 Hiveminder Secret SauceBeijing Perl Workshop 2008 Hiveminder Secret Sauce
Beijing Perl Workshop 2008 Hiveminder Secret Sauce
 
EC2
EC2EC2
EC2
 
Method::Signatures
Method::SignaturesMethod::Signatures
Method::Signatures
 
Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)
 
Crafting Custom Interfaces with Sub::Exporter
Crafting Custom Interfaces with Sub::ExporterCrafting Custom Interfaces with Sub::Exporter
Crafting Custom Interfaces with Sub::Exporter
 
Perl Sucks - and what to do about it
Perl Sucks - and what to do about itPerl Sucks - and what to do about it
Perl Sucks - and what to do about it
 
Barely Legal Xxx Perl Presentation
Barely Legal Xxx Perl PresentationBarely Legal Xxx Perl Presentation
Barely Legal Xxx Perl Presentation
 
Postman On Steroids
Postman On SteroidsPostman On Steroids
Postman On Steroids
 
Vim Hacks
Vim HacksVim Hacks
Vim Hacks
 
Vim Hacks
Vim HacksVim Hacks
Vim Hacks
 
Remy Sharp The DOM scripting toolkit jQuery
Remy Sharp The DOM scripting toolkit jQueryRemy Sharp The DOM scripting toolkit jQuery
Remy Sharp The DOM scripting toolkit jQuery
 
Why Perl, when you can use bash+awk+sed? :P
Why Perl, when you can use bash+awk+sed? :PWhy Perl, when you can use bash+awk+sed? :P
Why Perl, when you can use bash+awk+sed? :P
 
R57php 1231677414471772-2
R57php 1231677414471772-2R57php 1231677414471772-2
R57php 1231677414471772-2
 

More from Ricardo Signes

Perl 5: Today, Tomorrow, and Christmas
Perl 5: Today, Tomorrow, and ChristmasPerl 5: Today, Tomorrow, and Christmas
Perl 5: Today, Tomorrow, and ChristmasRicardo Signes
 
What's New in Perl? v5.10 - v5.16
What's New in Perl?  v5.10 - v5.16What's New in Perl?  v5.10 - v5.16
What's New in Perl? v5.10 - v5.16Ricardo Signes
 
Perl 5.14 for Pragmatists
Perl 5.14 for PragmatistsPerl 5.14 for Pragmatists
Perl 5.14 for PragmatistsRicardo Signes
 
Dist::Zilla - Maximum Overkill for CPAN Distributions
Dist::Zilla - Maximum Overkill for CPAN DistributionsDist::Zilla - Maximum Overkill for CPAN Distributions
Dist::Zilla - Maximum Overkill for CPAN DistributionsRicardo Signes
 
Perl 5.12 for Everyday Use
Perl 5.12 for Everyday UsePerl 5.12 for Everyday Use
Perl 5.12 for Everyday UseRicardo Signes
 
Antediluvian Unix: A Guide to Unix Fundamentals
Antediluvian Unix: A Guide to Unix FundamentalsAntediluvian Unix: A Guide to Unix Fundamentals
Antediluvian Unix: A Guide to Unix FundamentalsRicardo Signes
 
Perl 5.10 for People Who Aren't Totally Insane
Perl 5.10 for People Who Aren't Totally InsanePerl 5.10 for People Who Aren't Totally Insane
Perl 5.10 for People Who Aren't Totally InsaneRicardo Signes
 
How I Learned to Stop Worrying and Love Email::: The 2007 PEP Talk!!
How I Learned to Stop Worrying and Love Email::: The 2007 PEP Talk!!How I Learned to Stop Worrying and Love Email::: The 2007 PEP Talk!!
How I Learned to Stop Worrying and Love Email::: The 2007 PEP Talk!!Ricardo Signes
 

More from Ricardo Signes (10)

Perl 5: Today, Tomorrow, and Christmas
Perl 5: Today, Tomorrow, and ChristmasPerl 5: Today, Tomorrow, and Christmas
Perl 5: Today, Tomorrow, and Christmas
 
What's New in Perl? v5.10 - v5.16
What's New in Perl?  v5.10 - v5.16What's New in Perl?  v5.10 - v5.16
What's New in Perl? v5.10 - v5.16
 
Perl 5.14 for Pragmatists
Perl 5.14 for PragmatistsPerl 5.14 for Pragmatists
Perl 5.14 for Pragmatists
 
Dist::Zilla - Maximum Overkill for CPAN Distributions
Dist::Zilla - Maximum Overkill for CPAN DistributionsDist::Zilla - Maximum Overkill for CPAN Distributions
Dist::Zilla - Maximum Overkill for CPAN Distributions
 
Perl 5.12 for Everyday Use
Perl 5.12 for Everyday UsePerl 5.12 for Everyday Use
Perl 5.12 for Everyday Use
 
i &lt;3 email
i &lt;3 emaili &lt;3 email
i &lt;3 email
 
Dist::Zilla
Dist::ZillaDist::Zilla
Dist::Zilla
 
Antediluvian Unix: A Guide to Unix Fundamentals
Antediluvian Unix: A Guide to Unix FundamentalsAntediluvian Unix: A Guide to Unix Fundamentals
Antediluvian Unix: A Guide to Unix Fundamentals
 
Perl 5.10 for People Who Aren't Totally Insane
Perl 5.10 for People Who Aren't Totally InsanePerl 5.10 for People Who Aren't Totally Insane
Perl 5.10 for People Who Aren't Totally Insane
 
How I Learned to Stop Worrying and Love Email::: The 2007 PEP Talk!!
How I Learned to Stop Worrying and Love Email::: The 2007 PEP Talk!!How I Learned to Stop Worrying and Love Email::: The 2007 PEP Talk!!
How I Learned to Stop Worrying and Love Email::: The 2007 PEP Talk!!
 

Recently uploaded

The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
Maximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxMaximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxOnBoard
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhisoniya singh
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Alan Dix
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityPrincipled Technologies
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfEnterprise Knowledge
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024Scott Keck-Warren
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Igalia
 
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersEnhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersThousandEyes
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitecturePixlogix Infotech
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slidevu2urc
 

Recently uploaded (20)

The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
Maximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxMaximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptx
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
 
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersEnhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC Architecture
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 

Writing Modular Command-line Apps with App::Cmd