Building a desktop app with
                   HTTP::Engine, SQLite & jQuery
                              Tatsuhiko Miyag...
Tatsuhiko Miyagawa



Wednesday, June 24, 2009
Wednesday, June 24, 2009
Software Engineer, TypePad
Wednesday, June 24, 2009
cpan: MIYAGAWA



Wednesday, June 24, 2009
Acme-DateTime-Duration-Numeric Acme-Module-Authors Acme-Sneeze Acme-Sneeze-JP Apache-ACEProxy Apache-
          AntiSpam A...
twitter.com/miyagawa
                           (Slides will be linked. Follow me!)




Wednesday, June 24, 2009
Remedie

Wednesday, June 24, 2009
remediecode.org
                           Slides/Video in OSDC.TW




Wednesday, June 24, 2009
Building a desktop app with
                   HTTP::Engine, SQLite & jQuery
                              Tatsuhiko Miyag...
Desktop GUI apps



Wednesday, June 24, 2009
MFC/.NET
                           Visual C++,VB


Wednesday, June 24, 2009
wxWidgets



Wednesday, June 24, 2009
Objective-C
                               Cocoa
                           (PyObjC/RubyCocoa)



Wednesday, June 24, 2009
Adobe AIR



Wednesday, June 24, 2009
I’m a Perl guy
                    who knows JavaScript.


Wednesday, June 24, 2009
Web Developers!
Wednesday, June 24, 2009
Web app!



Wednesday, June 24, 2009
“Web 2.0 iPhone App”
                           Steve Jobs at WWDC 2007
Wednesday, June 24, 2009
Wednesday, June 24, 2009
PhoneGap
Wednesday, June 24, 2009
HTML5
                           geolocation, videos
                              local storage



Wednesday, June 24, 20...
HTML5 = Future
                             ??? = 2009


Wednesday, June 24, 2009
micro Web app = 2009



Wednesday, June 24, 2009
(2 min Demo video)
Wednesday, June 24, 2009
How I built this



Wednesday, June 24, 2009
Building a desktop app with
                   HTTP::Engine, SQLite & jQuery
                              Tatsuhiko Miyag...
“The most important
               project in Perl recently”
                      - jrockway


Wednesday, June 24, 2009
Based on
                           Catalyst::Engine


Wednesday, June 24, 2009
Ruby’s Rack
                           Python’s WSGI


Wednesday, June 24, 2009
use HTTP::Engine;
                  my $engine = HTTP::Engine‐>new(
                      interface => {
                 ...
sub handle_request {
                      my $req = shift;
                      return HTTP::Engine::Response‐>new(
    ...
Standalone,
                           ServerSimple, POE,
                           FastCGI, mod_perl


Wednesday, June 2...
Desktop app:
                             ServerSimple
                           POE (non-blocking)


Wednesday, June 24,...
Serve static files
                           (HTML/CSS/JS)


Wednesday, June 24, 2009
sub handle_request {
          my($self, $req) = @_;

          my $path = $req‐>path;
          my $res = HTTP::Engine::R...
use Path::Class;
                sub serve_static_file {
                    my($self, $path, $req, $res) = @_;

         ...
See Also:
                           HTTP::Engine::Middleware::Static




Wednesday, June 24, 2009
Implement Ajax
                           backend actions
                            (JSON-REST)


Wednesday, June 24, 20...
sub handle_request {
                my($self, $req) = @_;

                my $path = $req‐>path;

                my $re...
sub dispatch_rpc {
                my($self, $path, $req, $res) = @_;

                my @class  = split '/', $path;
    ...
Problem (1):
                           Dirty API routing


Wednesday, June 24, 2009
Path::Router, Path::Dispatcher,
                        HTTP::Dispatcher, JSORB




Wednesday, June 24, 2009
Problem (2):
                           Vulnerable (CSRF)


Wednesday, June 24, 2009
Authentication
                             Special Headers
                           Switch to JSONRPC


Wednesday, June...
Bonjour
               (based on HTTP::Server::Simple::Bonjour)




Wednesday, June 24, 2009
Auto Discovery
                           Share subscriptions


Wednesday, June 24, 2009
Wednesday, June 24, 2009
Building a desktop app with
                   HTTP::Engine, SQLite & jQuery
                              Tatsuhiko Miyag...
SQL DB choices



Wednesday, June 24, 2009
MySQL/PostgreSQL
                           Good for Web apps.


Wednesday, June 24, 2009
SQLite:
                           file-based, type-less
                              Transactional


Wednesday, June 24, ...
SQLite:
                      best for desktop apps


Wednesday, June 24, 2009
SQLite for desktop:
                           Firefox, Mail.app, iCal


Wednesday, June 24, 2009
End-users don’t want
                        to run *SQL server


Wednesday, June 24, 2009
Bonus:
                           Easy backup,
                           Dropbox sync


Wednesday, June 24, 2009
DB Schema



Wednesday, June 24, 2009
You don’t need DBA.
                     Make it simple, flexible and extensible.




Wednesday, June 24, 2009
Remedie schema
                              Few indexes
                            JSON key-values



Wednesday, June 24...
CREATE TABLE channel (
       id      INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
       type    INTEGER NOT NULL,
       ...
CREATE TABLE item (
       id         INTEGER NOT NULL PRIMARY KEY 
     AUTOINCREMENT,
       channel_id INTEGER NOT NULL...
Key-Value is HOT



Wednesday, June 24, 2009
CouchDB, MongoDB
                          TokyoTyrant
                           (Need servers though)




Wednesday, Jun...
SQLite for Key-Value



Wednesday, June 24, 2009
ORM?



Wednesday, June 24, 2009
Anything you like.



Wednesday, June 24, 2009
DBIx::Class
                           Rose::DB::Object


Wednesday, June 24, 2009
Rose::DB::Object
                            (I wanted some excuse)




Wednesday, June 24, 2009
See Also:
                           KiokuDB


Wednesday, June 24, 2009
KiokuDB
                           DBI / SQLite backend
                            Key-Value JSPON



Wednesday, June 24,...
Building a desktop app with
                   HTTP::Engine, SQLite & jQuery
                              Tatsuhiko Miyag...
Just use normal HTML
                    and CSS to design UI


Wednesday, June 24, 2009
Manipulate DOM
                           $.ajax to do Ajax


Wednesday, June 24, 2009
DOM Manipulation sucks.




Wednesday, June 24, 2009
jQuery.flydom



Wednesday, June 24, 2009
$("#channel‐pane").createAppend(
       'div', { className: 'channel‐header',
                id: 'channel‐header‐' + chan...
jQuery.hotkeys



Wednesday, June 24, 2009
$(document).bind(‘keydown’, ‘shift+n’, function(ev){
        // ‘N’ is entered
     });




Wednesday, June 24, 2009
jQuery.contextMenu



Wednesday, June 24, 2009
Wednesday, June 24, 2009
jQuery.corners



Wednesday, June 24, 2009
Wednesday, June 24, 2009
$.event.trigger
                           $(document).bind


Wednesday, June 24, 2009
jQuery UI



Wednesday, June 24, 2009
Fancy stuff
                           like Drag & Drop


Wednesday, June 24, 2009
jQuery.blockUI
                           jQuery.scrollTo
                            jQuery.jgrowl


Wednesday, June 24, ...
Building a desktop app with
                   HTTP::Engine, SQLite & jQuery
                              Tatsuhiko Miyag...
More like
                           “Desktop app”


Wednesday, June 24, 2009
Client-Server



Wednesday, June 24, 2009
Web Client as “app”



Wednesday, June 24, 2009
Site Specific Browser



Wednesday, June 24, 2009
Fluid
                           Prism


Wednesday, June 24, 2009
Wednesday, June 24, 2009
Customize
               Userscripts / Userstyles


Wednesday, June 24, 2009
Fluid hooks
                           Growl integration
                             Dock menu


Wednesday, June 24, 2009
Wednesday, June 24, 2009
Client-Server
                           Decoupled via APIs


Wednesday, June 24, 2009
More Clients
                           More “Views”


Wednesday, June 24, 2009
iPhone



Wednesday, June 24, 2009
Wednesday, June 24, 2009
Wednesday, June 24, 2009
120 lines of HTML/JS
                         using iUI project


Wednesday, June 24, 2009
Server as “app”



Wednesday, June 24, 2009
Packaging a server



Wednesday, June 24, 2009
local::lib
                      build & install all deps


Wednesday, June 24, 2009
Also:
                           Shipwright


Wednesday, June 24, 2009
Platypus
                           Make .app


Wednesday, June 24, 2009
Download .zip, copy .app to
                             /Applications, Run it.
Wednesday, June 24, 2009
Also:
                      github.com/miyagawa/perl-app-builder




Wednesday, June 24, 2009
Summary

                   • micro web server as a desktop app
                   • HTTP::Engine, JSONRPC and router
    ...
That’s it!
                           Questions?


Wednesday, June 24, 2009
Thank you!
                     twitter.com/miyagawa


Wednesday, June 24, 2009
Upcoming SlideShare
Loading in...5
×

Building a desktop app with HTTP::Engine, SQLite and jQuery

23,021

Published on

Published in: Business, Technology
1 Comment
7 Likes
Statistics
Notes
No Downloads
Views
Total Views
23,021
On Slideshare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
121
Comments
1
Likes
7
Embeds 0
No embeds

No notes for slide

Building a desktop app with HTTP::Engine, SQLite and jQuery

  1. 1. Building a desktop app with HTTP::Engine, SQLite & jQuery Tatsuhiko Miyagawa YAPC::NA 2009 Pittsburgh Wednesday, June 24, 2009
  2. 2. Tatsuhiko Miyagawa Wednesday, June 24, 2009
  3. 3. Wednesday, June 24, 2009
  4. 4. Software Engineer, TypePad Wednesday, June 24, 2009
  5. 5. cpan: MIYAGAWA Wednesday, June 24, 2009
  6. 6. Acme-DateTime-Duration-Numeric Acme-Module-Authors Acme-Sneeze Acme-Sneeze-JP Apache-ACEProxy Apache- AntiSpam Apache-Clickable Apache-CustomKeywords Apache-DefaultCharset Apache-GuessCharset Apache-JavaScript- DocumentWrite Apache-No404Proxy Apache-Profiler Apache-Session-CacheAny Apache-Session-Generate-ModUniqueId Apache-Session-Generate-ModUsertrack Apache-Session-PHP Apache-Session-Serialize-YAML Apache-Singleton Apache- StickyQuery Archive-Any-Create Attribute-Profiled Attribute-Protected Attribute-Unimplemented Bundle-Sledge CGI- Untaint-email CPAN-Mini-Growl Catalyst-Plugin-Authentication-Credential-AOL Catalyst-Plugin-Authentication-Credential- OpenID Catalyst-Plugin-JSONRPC Catalyst-View-JSON Catalyst-View-Jemplate Class-DBI-AbstractSearch Class-DBI- Extension Class-DBI-Pager Class-DBI-Replication Class-DBI-SQLite Class-DBI-View Class-Trigger Convert-Base32 Convert- DUDE Convert-RACE Data-YUID Date-Japanese-Era Date-Range-Birth DateTime-Span-Birthdate Device-KeyStroke-Mobile Dunce-time Email-Find Email-Valid-Loose Encode-DoubleEncodedUTF8 Encode-First Encode-JP-Mobile Encode-JavaScript- UCS Encode-Punycode File-Find-Rule-Digest File-Spotlight Geo-Coder-Google HTML-AutoPagerize HTML-Entities- ImodePictogram HTML-RelExtor HTML-ResolveLink HTML-Selector-XPath HTML-XSSLint HTTP-MobileAgent HTTP- ProxyPAC HTTP-Server-Simple-Authen HTTP-Server-Simple-Bonjour IDNA-Punycode Inline-Basic Inline-TT JSON-Syck Kwiki-Emoticon Kwiki-Export Kwiki-Footnote Kwiki-OpenSearch Kwiki-OpenSearch-Service Kwiki-TypeKey Kwiki-URLBL LWP-UserAgent-Keychain Lingua-JA-Hepburn-Passport Log-Dispatch-Config Log-Dispatch-DBI MSIE-MenuExt Mac- Macbinary Mail-Address-MobileJp Mail-ListDetector-Detector-Fml Module-Install-Repository Net-DAAP-Server-AAC Net- IDN-Nameprep Net-IPAddr-Find Net-Twitter-OAuth Net-YahooMessenger NetAddr-IP-Find P2P-Transmission-Remote PHP-Session POE-Component-Client-AirTunes POE-Component-Client-Lingr POE-Component-YahooMessenger Path- Class-URI Plagger RPC-XML-Parser-LibXML Template-Plugin-Clickable Template-Plugin-Comma Template-Plugin-FillInForm Template-Plugin-HTML-Template Template-Plugin-JavaScript Template-Plugin-MobileAgent Template-Plugin-ResolveLink Template-Plugin-Shuffle Template-Provider-Encoding Term-Encoding Term-TtyRec Test-Synopsis Text-Emoticon Text- Emoticon-GoogleTalk Text-Emoticon-MSN Text-Emoticon-Yahoo Text-MessageFormat TheSchwartz-Simple Time-Duration- Parse Time-Duration-ja URI-Find-UTF8 URI-git URI-tag URI-urn-uuid Video-Subtitle-SRT WWW-Baseball-NPB WWW-Blog- Metadata-MobileLinkDiscovery WWW-Blog-Metadata-OpenID WWW-Blog-Metadata-OpenSearch WWW-Cache-Google WWW-Mechanize-AutoPager WWW-Mechanize-DecodedContent WWW-NicoVideo-Download WWW-OpenSearch WWW-Shorten-RevCanonical WWW-Shorten-Simple Web-Scraper Web-oEmbed WebService-Bloglines WebService- ChangesXml WebService-Google-Suggest WebService-Lingr XML-Atom XML-Atom-Lifeblog XML-Atom-Stream XML- Liberal XML-OPML-LibXML abbreviation autobox-DateTime-Duration capitalization plagger Wednesday, June 24, 2009
  7. 7. twitter.com/miyagawa (Slides will be linked. Follow me!) Wednesday, June 24, 2009
  8. 8. Remedie Wednesday, June 24, 2009
  9. 9. remediecode.org Slides/Video in OSDC.TW Wednesday, June 24, 2009
  10. 10. Building a desktop app with HTTP::Engine, SQLite & jQuery Tatsuhiko Miyagawa YAPC::NA 2009 Pittsburgh Wednesday, June 24, 2009
  11. 11. Desktop GUI apps Wednesday, June 24, 2009
  12. 12. MFC/.NET Visual C++,VB Wednesday, June 24, 2009
  13. 13. wxWidgets Wednesday, June 24, 2009
  14. 14. Objective-C Cocoa (PyObjC/RubyCocoa) Wednesday, June 24, 2009
  15. 15. Adobe AIR Wednesday, June 24, 2009
  16. 16. I’m a Perl guy who knows JavaScript. Wednesday, June 24, 2009
  17. 17. Web Developers! Wednesday, June 24, 2009
  18. 18. Web app! Wednesday, June 24, 2009
  19. 19. “Web 2.0 iPhone App” Steve Jobs at WWDC 2007 Wednesday, June 24, 2009
  20. 20. Wednesday, June 24, 2009
  21. 21. PhoneGap Wednesday, June 24, 2009
  22. 22. HTML5 geolocation, videos local storage Wednesday, June 24, 2009
  23. 23. HTML5 = Future ??? = 2009 Wednesday, June 24, 2009
  24. 24. micro Web app = 2009 Wednesday, June 24, 2009
  25. 25. (2 min Demo video) Wednesday, June 24, 2009
  26. 26. How I built this Wednesday, June 24, 2009
  27. 27. Building a desktop app with HTTP::Engine, SQLite & jQuery Tatsuhiko Miyagawa YAPC::NA 2009 Pittsburgh Wednesday, June 24, 2009
  28. 28. “The most important project in Perl recently” - jrockway Wednesday, June 24, 2009
  29. 29. Based on Catalyst::Engine Wednesday, June 24, 2009
  30. 30. Ruby’s Rack Python’s WSGI Wednesday, June 24, 2009
  31. 31. use HTTP::Engine; my $engine = HTTP::Engine‐>new(     interface => {         module => 'ServerSimple',         args   => {             host => 'localhost',             port => 9898,         },     request_handler => &handle_request, }); $engine‐>run; Wednesday, June 24, 2009
  32. 32. sub handle_request {     my $req = shift;     return HTTP::Engine::Response‐>new(         body => “Hello World”,     ); } Wednesday, June 24, 2009
  33. 33. Standalone, ServerSimple, POE, FastCGI, mod_perl Wednesday, June 24, 2009
  34. 34. Desktop app: ServerSimple POE (non-blocking) Wednesday, June 24, 2009
  35. 35. Serve static files (HTML/CSS/JS) Wednesday, June 24, 2009
  36. 36. sub handle_request {     my($self, $req) = @_;     my $path = $req‐>path;     my $res = HTTP::Engine::Response‐>new;     if ($path =~ s!^/static/!!) {         $self‐>serve_static_file($path, $req, $res);     };     return $res; } Wednesday, June 24, 2009
  37. 37. use Path::Class; sub serve_static_file {     my($self, $path, $req, $res) = @_;     my $root = $self‐>conf‐>{root};     my $file = file($root, "static", $path);     my $size  = ‐s _;     my $mtime = (stat(_))[9];     my $ext = ($file =~ /.(w+)$/)[0];     $res‐>content_type( MIME::Types‐>new‐>mimeTypeOf($ext)         || "text/plain" );     # ...     open my $fh, "<:raw", $file         or die "$file: $!";     $res‐>headers‐>header('Last‐Modified' =>          HTTP::Date::time2str($mtime));     $res‐>headers‐>header('Content‐Length' => $size);     $res‐>body( join '', <$fh> ); } Wednesday, June 24, 2009
  38. 38. See Also: HTTP::Engine::Middleware::Static Wednesday, June 24, 2009
  39. 39. Implement Ajax backend actions (JSON-REST) Wednesday, June 24, 2009
  40. 40. sub handle_request {     my($self, $req) = @_;     my $path = $req‐>path;     my $res = HTTP::Engine::Response‐>new;     if ($path =~ s!^/rpc/!!) {         $self‐>dispatch_rpc($path, $req, $res);     } } Wednesday, June 24, 2009
  41. 41. sub dispatch_rpc {     my($self, $path, $req, $res) = @_;     my @class  = split '/', $path;     my $method = pop @class;     die "Access to non‐public methods" if $method =~ /^_/;     my $rpc_class = $self‐>load_rpc_class(@class);     my $rpc = $rpc_class‐>new( conf => $self‐>conf );     my $result = eval { $rpc‐>$method($req, $res) };     unless ( $res‐>body ) {         $res‐>status(200);         $res‐>content_type("application/json; charset=utf‐8");         $res‐>body( Remedie::JSON‐>encode($result) );     } } Wednesday, June 24, 2009
  42. 42. Problem (1): Dirty API routing Wednesday, June 24, 2009
  43. 43. Path::Router, Path::Dispatcher, HTTP::Dispatcher, JSORB Wednesday, June 24, 2009
  44. 44. Problem (2): Vulnerable (CSRF) Wednesday, June 24, 2009
  45. 45. Authentication Special Headers Switch to JSONRPC Wednesday, June 24, 2009
  46. 46. Bonjour (based on HTTP::Server::Simple::Bonjour) Wednesday, June 24, 2009
  47. 47. Auto Discovery Share subscriptions Wednesday, June 24, 2009
  48. 48. Wednesday, June 24, 2009
  49. 49. Building a desktop app with HTTP::Engine, SQLite & jQuery Tatsuhiko Miyagawa YAPC::NA 2009 Pittsburgh Wednesday, June 24, 2009
  50. 50. SQL DB choices Wednesday, June 24, 2009
  51. 51. MySQL/PostgreSQL Good for Web apps. Wednesday, June 24, 2009
  52. 52. SQLite: file-based, type-less Transactional Wednesday, June 24, 2009
  53. 53. SQLite: best for desktop apps Wednesday, June 24, 2009
  54. 54. SQLite for desktop: Firefox, Mail.app, iCal Wednesday, June 24, 2009
  55. 55. End-users don’t want to run *SQL server Wednesday, June 24, 2009
  56. 56. Bonus: Easy backup, Dropbox sync Wednesday, June 24, 2009
  57. 57. DB Schema Wednesday, June 24, 2009
  58. 58. You don’t need DBA. Make it simple, flexible and extensible. Wednesday, June 24, 2009
  59. 59. Remedie schema Few indexes JSON key-values Wednesday, June 24, 2009
  60. 60. CREATE TABLE channel (   id      INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,   type    INTEGER NOT NULL,   parent  INTEGER NOT NULL,   ident   TEXT NOT NULL,   name    TEXT NOT NULL,   props   TEXT ); CREATE UNIQUE INDEX channel_ident ON channel (ident); Wednesday, June 24, 2009
  61. 61. CREATE TABLE item (   id         INTEGER NOT NULL PRIMARY KEY  AUTOINCREMENT,   channel_id INTEGER NOT NULL,   type       INTEGER NOT NULL,   ident      TEXT NOT NULL,   name       TEXT NOT NULL,   status     INTEGER NOT NULL,   props      TEXT ); CREATE INDEX item_status ON item (status) CREATE UNIQUE INDEX item_ident ON item (channel_id,  ident); Wednesday, June 24, 2009
  62. 62. Key-Value is HOT Wednesday, June 24, 2009
  63. 63. CouchDB, MongoDB TokyoTyrant (Need servers though) Wednesday, June 24, 2009
  64. 64. SQLite for Key-Value Wednesday, June 24, 2009
  65. 65. ORM? Wednesday, June 24, 2009
  66. 66. Anything you like. Wednesday, June 24, 2009
  67. 67. DBIx::Class Rose::DB::Object Wednesday, June 24, 2009
  68. 68. Rose::DB::Object (I wanted some excuse) Wednesday, June 24, 2009
  69. 69. See Also: KiokuDB Wednesday, June 24, 2009
  70. 70. KiokuDB DBI / SQLite backend Key-Value JSPON Wednesday, June 24, 2009
  71. 71. Building a desktop app with HTTP::Engine, SQLite & jQuery Tatsuhiko Miyagawa YAPC::NA 2009 Pittsburgh Wednesday, June 24, 2009
  72. 72. Just use normal HTML and CSS to design UI Wednesday, June 24, 2009
  73. 73. Manipulate DOM $.ajax to do Ajax Wednesday, June 24, 2009
  74. 74. DOM Manipulation sucks. Wednesday, June 24, 2009
  75. 75. jQuery.flydom Wednesday, June 24, 2009
  76. 76. $("#channel‐pane").createAppend(   'div', { className: 'channel‐header',            id: 'channel‐header‐' + channel.id  }, [     'div', { className: 'channel‐header‐thumb' }, [        'img', { src: "/static/images/feed.png",                 alt: channel.name }, null     ],   ] ); Wednesday, June 24, 2009
  77. 77. jQuery.hotkeys Wednesday, June 24, 2009
  78. 78. $(document).bind(‘keydown’, ‘shift+n’, function(ev){    // ‘N’ is entered }); Wednesday, June 24, 2009
  79. 79. jQuery.contextMenu Wednesday, June 24, 2009
  80. 80. Wednesday, June 24, 2009
  81. 81. jQuery.corners Wednesday, June 24, 2009
  82. 82. Wednesday, June 24, 2009
  83. 83. $.event.trigger $(document).bind Wednesday, June 24, 2009
  84. 84. jQuery UI Wednesday, June 24, 2009
  85. 85. Fancy stuff like Drag & Drop Wednesday, June 24, 2009
  86. 86. jQuery.blockUI jQuery.scrollTo jQuery.jgrowl Wednesday, June 24, 2009
  87. 87. Building a desktop app with HTTP::Engine, SQLite & jQuery Tatsuhiko Miyagawa YAPC::NA 2009 Pittsburgh Wednesday, June 24, 2009
  88. 88. More like “Desktop app” Wednesday, June 24, 2009
  89. 89. Client-Server Wednesday, June 24, 2009
  90. 90. Web Client as “app” Wednesday, June 24, 2009
  91. 91. Site Specific Browser Wednesday, June 24, 2009
  92. 92. Fluid Prism Wednesday, June 24, 2009
  93. 93. Wednesday, June 24, 2009
  94. 94. Customize Userscripts / Userstyles Wednesday, June 24, 2009
  95. 95. Fluid hooks Growl integration Dock menu Wednesday, June 24, 2009
  96. 96. Wednesday, June 24, 2009
  97. 97. Client-Server Decoupled via APIs Wednesday, June 24, 2009
  98. 98. More Clients More “Views” Wednesday, June 24, 2009
  99. 99. iPhone Wednesday, June 24, 2009
  100. 100. Wednesday, June 24, 2009
  101. 101. Wednesday, June 24, 2009
  102. 102. 120 lines of HTML/JS using iUI project Wednesday, June 24, 2009
  103. 103. Server as “app” Wednesday, June 24, 2009
  104. 104. Packaging a server Wednesday, June 24, 2009
  105. 105. local::lib build & install all deps Wednesday, June 24, 2009
  106. 106. Also: Shipwright Wednesday, June 24, 2009
  107. 107. Platypus Make .app Wednesday, June 24, 2009
  108. 108. Download .zip, copy .app to /Applications, Run it. Wednesday, June 24, 2009
  109. 109. Also: github.com/miyagawa/perl-app-builder Wednesday, June 24, 2009
  110. 110. Summary • micro web server as a desktop app • HTTP::Engine, JSONRPC and router • SQLite to store key-value • jQuery plugins to enable desktop UIs • More tools to make it really “.app” Wednesday, June 24, 2009
  111. 111. That’s it! Questions? Wednesday, June 24, 2009
  112. 112. Thank you! twitter.com/miyagawa Wednesday, June 24, 2009
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×