Title
Introduction
Hop Primer
Web Programming
Multitier programming
Hop
Diffuse Programming
HopSlide Help (v2.5.7)
Keyboard
Toggle this help
alt-h
Reload slides
alt-r
Toggle slide selector
alt-s
alt-t
Open a full screen window
alt-w
Update size
alt-u
Toggle big cursor
alt-m
Toggle focus
alt-f
Toggle drawing area
alt-c
Next slide
PgDn
Ret
Enter
Space
Previous slide
PgUp
alt-p
First slide
Home
Last slide
End
Close slide
Esc
Mouse
Reload slides
shift Button1
Slides selector
crtl Button1
Focus enlarge/shrink
Button4
Button5
gnF36H4J1T8H7pFAAHEONDdc4AAAwCErwrFI1ExuQAAAABJRU5ErkJggg==
f83cyUw3hWh3qTYCQABBgAAGnnjiX1UpQAAAABJRU5ErkJggg==
oTQwvEAAAAASUVORK5CYII=
PQpAYQAAxDnTnFCCABrxzChBAA+4AgAADAN6IbfrsVDB3AAAAAElFTkSuQmCC
AeHxm5gUXjm4ZPP+Q8ff4oDRs9WoNhLjCru939IIxUNAAQQ40B3TgECaMD7hgABNOAOAAgwAOIo9yyRalo+AAAAAElFTkSuQmCC
z+V8PIw8L0n4kxGSh6B6NjAmohs0D0oXdMAAKIcaA7pwABNOB9Q4AAGnAHAAQYABaU9vBbRzekAAAAAElFTkSuQmCC
ADi8NuBl72pcAE+htbHicGAAQQ40B3TgECaMD7hgABNOAOAAgwANtDcqAqYx6xAAAAAElFTkSuQmCC
ARPp5s07HsgBLdwOTGiNwIR5C+xYbOAn1rgHRegOIH4LEwAIIMaB7pwCBNCA9w0BAmjAHQAQYABMAqbWGPAKOwAAAABJRU5ErkJggg==
IRyAEAAcQ40D0jgAAa8FYxQAANuAMAAmjAHQAQQAPuAIAAGnAHAAQYAOJ5EYdTDOvTAAAAAElFTkSuQmCC
gEQYAA1+Dm3GSWUswAAAABJRU5ErkJggg==
iTECIIAocwAEAPMcgzIQc0Lz+EtCwY4MAAIMAFAjCls0Uia9AAAAAElFTkSuQmCC
+MpwGSoPwffRsRggABBBJDoAFBhDLg1q0oEIX6ltQyfaDnM4pQAAxDnT3HCDAANr5Kk2SE6QoAAAAAElFTkSuQmCC
0xM+w0gwAANGVpo2ifr1AAAAABJRU5ErkJggg==
KP8B4jPBcKUstbkAAAAASUVORK5CYII=
QaClO4HqHkJKReQmN6YDAAKIcaB7xwABNOC9Y4AAAwAOHvV3Gx3bfwAAAABJRU5ErkJggg==
big-pointer.png
Title
Programming the Diffuse Web
EJCP'2013
Manuel Serrano
image/svg+xml
Roadmap
  1. Diffuse Computing
  2. Hop Primer
    • Functional Programming
    • Data structures
    • Lists
    • Functions
    • Exceptions, escapes, continuations
    • Modules
  3. Programming the Web
    • HTTP
    • HTML
    • CGI
    • Ajax
  4. Multi-tier programming
    • GWT
    • Links
    • Hop
  5. Hop, programming the Web
    • Syntax and Semantics
    • Services
    • Events
    • DOM
    • API
    • HSS
  6. Hop, programming the diffuse Web
    • Weblets
    • JavaScript interoperability
    • Demos Implementation
    • Mobile Phone
introprimerwebmtierhopdiffuse
HOP home pageINRIA2 of 138
References
Books to read
  • Structure and Interpretation of Computer Programs, Abelson, H. and Sussman, G. -- MIT Press, 1985.
  • Lisp In Small Pieces, Queinnec, C. -- Cambridge University Press, 1996
Papers to read
  • Multitier Programming in Hop, Serrano, M. and Berry, G. -- Communications of the ACM'12
  • Hop, a Fast Server for the Diffuse Web, Serrano, M. -- COORDINATION'09
  • HOP, a language for programming the Web 2.0, Serrano, M., Gallesio, E. and Loitsch, F. -- DLS'06
Useful references
  • JavaScript -- The definitive guide (4th edition), Flanagan, D. -- O'Reilly, 2002.
introprimerwebmtierhopdiffuse
HOP home pageINRIA3 of 138
Introduction
The Web
The Web exists and it is ubiquitous!
  • Portable (PC, smartphones, modems, ...)
  • Everywhere (houses, offices, internet cafés, cities, ...)
  • International (data and services)
introprimerwebmtierhopdiffuse
HOP home pageINRIA4 of 138
Web Architecture
Web 3 tiers
001001000111 image/svg+xml DB Client Server Broker lo Bluetooth 0m 10,000km 5m Ethernet Ethernet 500km 10,000km Ethernet
introprimerwebmtierhopdiffuse
HOP home pageINRIA5 of 138
babel.png
Programming the Static Web
image/svg+xml HTTP response HTML Client Server HTTP request
  • The program is in the server
  • The client cannot be programmed
  • Static content (texts, pictures)
  • Few interactions (links)
introprimerwebmtierhopdiffuse
HOP home pageINRIA7 of 138
Programmming the Dynamic Web
image/svg+xml HTML HTML HTML Client Server modify exec JS mouse JS JS JS JS JS request response begin
  • Bicephalous program
  • The content changes dynamically (partially, events)
  • Constant communications
introprimerwebmtierhopdiffuse
HOP home pageINRIA8 of 138
Programming the Diffuse Web
image/svg+xml HTML HTML HTML Client mouse JS JS JS JS JS request response Broker
  • Distributed program
  • Frequent errors
  • Hazardous world
  • Dangerous world
introprimerwebmtierhopdiffuse
HOP home pageINRIA9 of 138
Programming the Web with Hop
  • Multitier language
  • Security by compilation
  • Orchestration
introprimerwebmtierhopdiffuse
HOP home pageINRIA10 of 138
Hop Primer
Hop Primer
(Monotier programming)
Roadmap - Hop Primer
  1. Diffuse Computing
  2. Hop Primer
    • Functional Programming
    • Data structures
    • Lists
    • Functions
    • Exceptions, escapes, continuations
    • Modules
  3. Programming the Web
    • HTTP
    • HTML
    • CGI
    • Ajax
  4. Multi-tier programming
    • GWT
    • Links
    • Hop
  5. Hop, programming the Web
    • Syntax and Semantics
    • Services
    • Events
    • DOM
    • API
    • HSS
  6. Hop, programming the diffuse Web
    • Weblets
    • JavaScript interoperability
    • Demos Implementation
    • Mobile Phone
introprimerwebmtierhopdiffuse
HOP home pageINRIA12 of 138
Functional Languages
A Family of Languages...
  • Lazy (Haskell, Miranda, ...)
    • pure (close to math models)
    • concurrency support
    • difficult to implement efficiently
    • difficult to debug
  • Strict, static type check (ML, F#)
    • programs don't crash at runtime
    • lack of flexibility
  • Strict, dynamic type check (Lisp, Erlang, JavaScript, Hop, ...)
    • programs may crash at runtime
    • highlgy flexible
introprimerwebmtierhopdiffuse
HOP home pageINRIA13 of 138
Functional Languages
Characterisitics...
  • Functions are first class values
  • Polymorphic
  • Garbage collector
introprimerwebmtierhopdiffuse
HOP home pageINRIA14 of 138
Hello World, 1
"Hello World" in C...
saveuseedit
#include <stdio.h>

/* a forward definition */
static void hello_world();

/* the entry point of the application */
int( int argc, char *argv[], char *env[] ) {
   hello_world();
   return 0;
}

void hello_world() {
   puts( "hello, world!" );
}
introprimerwebmtierhopdiffuse
HOP home pageINRIA15 of 138
Hello World, 2
"Hello World" in JavaScript...
saveuseedit
function hello_world() {
   alert( "hello, world!" );
}

// a top-level expression
hello_world();
introprimerwebmtierhopdiffuse
HOP home pageINRIA16 of 138
Hello World, 3
"Hello World" in Hop...
saveuseedit
(module hello)

(define (hello-word)
   (print "hello, world!"))

;; a top-level expression
(hello-world)
introprimerwebmtierhopdiffuse
HOP home pageINRIA17 of 138
Hello World, 4
"Hello World" in Hop, some remarks
  • Hop enjoys a weird infix syntax
  • Hop uses modules
introprimerwebmtierhopdiffuse
HOP home pageINRIA18 of 138
Fibonacci, 1
"Fibonacci" in C...
saveuseedit
#include <stdio.h>
#include <stdlib.h>

int fib( int n ) {
   if( n < 2 ) {
      return 1;
   } else {
      return fib( n - 1 ) + fib( n - 2 );
   }
}

int main( int argc, char *argv[], char *env[] ) {
   printf( "fib: %d\n", fib( atoi( argv[ 1 ] ) ) );
}
introprimerwebmtierhopdiffuse
HOP home pageINRIA19 of 138
Fibonacci, 2
"Fibonacci" in JavaScript...
saveuseedit
function fib( n ) {
   if( n < 2 ) {
      return 1;
   } else {
      return fib( n - 1 ) + fib( n - 2 );
   }
}

alert( "fib: " + fib( Math.parseInt( "20" ) ) );
introprimerwebmtierhopdiffuse
HOP home pageINRIA20 of 138
Fibonacci, 3
"Fibonacci" in Hop...
saveuseedit
(module fib
   (main start))

(define (fib n)
   (if (< n 2)
       1
       (+ (fib (- n 1)) (fib (- n 2)))))

(define (start args)
   (print "fib: " (fib (string->number (cadr args)))))
introprimerwebmtierhopdiffuse
HOP home pageINRIA21 of 138
Remark 1
Idents...
  • C: [_a-zA-Z][_a-zA-Z0-9]*
  • JS: [_a-zA-Z$][_a-zA-Z0-9$]*
  • Hop: [0-9]*[a-zA-Z!@$%^&><?/-_+\=?.:][a-zA-Z0-9!@$%^&></-_+\=?:'`]*
    Examples: foo, null?, <, +, string->number, <div>
  • Hop idents are first class values: symbols and keywords
    • Converted from and to strings
    • Unique (hashed)
    • Syntactically noted: 'ident and :ident
introprimerwebmtierhopdiffuse
HOP home pageINRIA22 of 138
Remark 2
Expressions vs statments...
  • Hop is an expression-based language but...
saveuseedit
#include <stdio.h>
#include <stdlib.h>

int fib( int n ) {
   return n < 2 ? 1 : fib( n - 1 ) + fib( n - 2 );
}

int( int argc, char *argv[], char *env[] ) {
   printf( "fib: %s\n", fib( atoi( argv[ 1 ] ) ) );
}
introprimerwebmtierhopdiffuse
HOP home pageINRIA23 of 138
Remark 3
Type annotations...
  • C code contains types
  • JavaScript doesn't
  • They are optional in Hop...
saveuseedit
(module fib-typed
   (main start))

(define (fib::int n::int)
   (if (< n 2)
       1
       (+ (fib (- n 1)) (fib (- n 2)))))

(define (start args::pair)
   (print "fib: " (fib (string->number (cadr args)))))
introprimerwebmtierhopdiffuse
HOP home pageINRIA24 of 138
Remark, datatypes
  • Pointers are ubiquitous in C
  • Vectors are ubiquitous in JavaScript
  • Lists are ubiquitous in Hop
List API (summary)
% (cons 1 (cons 2 '())) (1 2)
% (list 'foo 'bar 'gee) (foo bar gee)
% (car (list 'foo 'bar 'gee)) foo
% (cdr (list "foo" "bar" "gee")) ("bar" "gee")
% (cadr (list :foo :bar :gee)) :bar
% (pair? (list 1 2 3)) #t
% (null? (list 1 2 3)) #f
% (reverse (list 1 2 3)) (3 2 1)
% (append (list 'foo 'bar) '(gee hux)) (foo bar gee hux)
% `(1 ,(+ 2 3) ,@(list 6 7)) (1 5 6 7)
introprimerwebmtierhopdiffuse
HOP home pageINRIA25 of 138
Loops and strings, 1
"URL scheme extractor" in C...
saveuseedit
// return a new string composed of the scheme of a URL
// url_scheme( "http://hop.inria.fr" ) -> "http"
char *url_scheme( char *url ) {
   char *s = url, *res;
   int i;

   while( *s++ != ':' );

   i = s - url;
   res = malloc( i );
   res[ i - 1 ] = 0;
   
   memcpy( res, url, i - 1 );
   
   return res;
}
introprimerwebmtierhopdiffuse
HOP home pageINRIA26 of 138
Loops and strings, 2
"URL scheme extractor" in JS
saveuseedit
// return a new string composed of the scheme of a URL
// url_scheme( "http://hop.inria.fr" ) -> "http"
function url_scheme( url ) {
   for( var i = 0; url.charAt( i ) != ":"; i++ );

   return url.substring( 0, i );
}
with regexp...
saveuseedit
// return a new string composed of the scheme of a URL
// url_scheme( "http://hop.inria.fr" ) -> "http"
function url_scheme( url ) {
   var m = url.match( new Regexp( "(^[^:]+)://" ) );

   return m[ 1 ];
}
introprimerwebmtierhopdiffuse
HOP home pageINRIA27 of 138
Loops and strings, 3
"URL scheme extractor" in JS
saveuseedit
;; return a new string composed of the scheme of a URL
;; url_scheme( "http://hop.inria.fr" ) -> "http"
(define (url-scheme url)
   (let loop ((i 0))
      (if (char=? (string-ref url i) #\:)
	  (substring url 0 i)
	  (loop (+ i 1)))))
with regexp...
saveuseedit
;; return a new string composed of the scheme of a URL
;; url_scheme( "http://hop.inria.fr" ) -> "http"
(define (url-scheme url)
   (cadr (pregexp-match url "(^[^:]+)://")))
introprimerwebmtierhopdiffuse
HOP home pageINRIA28 of 138
Variable arity
Several ways of defining variable arity functions
  • Dot notation:
    The last formal is bound to the list of the optional actuals.
    Example: a function that requires at least 1 argument
    (define (plus x . y) ...)
    
    (plus 1 2 3 4 5)
  • Optional arguments:
    (define (plus #!optional (x 0) (y 0)) ...)
    
    (plus 30)
  • Named arguments (e.g., URL arguments):
    (define (plus #!key (x 0) (y 0)) ...)
    
    (plus :y 14 :x 30)
introprimerwebmtierhopdiffuse
HOP home pageINRIA29 of 138
Functions
JavaScript and Hop functions are similar:
  • functions are first class values;
  • functions can be anonymous;
  • Hop functions are defined by the constructor lambda (respec. function for JavaScript).
introprimerwebmtierhopdiffuse
HOP home pageINRIA30 of 138
Functions, examples
  • First order:
    • JavaScript
      var sqr = function( x ) { return x * x; }
      alert( sqr( 5 ) );
    • Hop
      (let ((sqr (lambda (x) (* x x))))
        (print (sqr 5)))
  • Higher order:
    • JavaScript
      function o( f, g ) {
        return function( x ) { f( g( x ) ); }
      }
    • Hop
      (define (o f g)
         (lambda (x)
            (f (g x))))
introprimerwebmtierhopdiffuse
HOP home pageINRIA31 of 138
Exceptions, Errors, and Escapes
  • The function raise raises a signal
  • The function error raises a signal whose value is an instance of the class &error
  • The form with-handler intercepts signals
  • The form unwind-protect installs a protected block on the execution stack
  • The form bind-exit binds a dynamic escape
introprimerwebmtierhopdiffuse
HOP home pageINRIA32 of 138
Exceptions, example
Count the number of expressions in a file
(define (open path)
   (if (file-exists? path)
       (open-input-file path)
       (raise 'file-not-found-error)))

(define (expression-count path)
   (with-handler
      (lambda (e)
	 (if (eq? e 'file-not-found-error)
	     0
	     (raise e)))
      (let ((p (open path)))
	 (unwind-protect
	    (let loop ((count 0))
	       (let ((o (read p)))
		  (if (eof-object? o)
		      count
		      (loop (+ count 1)))))
	    (close-output-port p)))))
introprimerwebmtierhopdiffuse
HOP home pageINRIA33 of 138
Exceptions, example2
Return all the numbers of a file or the first string
saveuseedit
(define (numbers-or-string path)
   (let ((p (open path)))
      (bind-exit (escape)
 	 (unwind-protect
	    (let loop ((o (read p)))
		  (cond
		     ((eof-object? o)
		      '())
		     ((number? o)
		      (cons o (loop (read p))))
		     ((string? o)
		      (escape o))
		     (else
		      (loop (read p)))))
	    (close-output-port p)))))
introprimerwebmtierhopdiffuse
HOP home pageINRIA34 of 138
From escapes to continuations
Dynamic extent vs infinite extent
  • What about?
    (define esc #f)
    			
    (if (bind-exit (escape)
           (begin
              (set! esc escape)
    	  #t))
        (esc #f)
        "pas glop")
  • ...it fails:
    *** ERROR:unwind-until!:
    exit out of dynamic scope -- #f
introprimerwebmtierhopdiffuse
HOP home pageINRIA35 of 138
Continuations
call-with-current-continuation (aka call/cc)
Rational
invokes its argument with the current continuation, reified as a unary function
Prototype
(proc → val) → val
Examples
% (call/cc (lambda (k) (+ 1 (+ 2 3)))) 6
% (call/cc (lambda (k) (+ 1 (k (+ 2 3))))) 5
% (+ 1 (call/cc (lambda (k) (+ 2 (k (+ 3 4)))))) 8
introprimerwebmtierhopdiffuse
HOP home pageINRIA36 of 138
Infinite extent
The extent of continuations being infinite, they can be used even out of the scope of the capture...
(define kont #f)

(if (call/cc (lambda (k)
                (begin
                   (set! kont k)
	           #t)))
    (kont #f)
    "pas glop")
introprimerwebmtierhopdiffuse
HOP home pageINRIA37 of 138
Modules
Modules organize the program source code
  • A module is defined in a file
  • A file defines one module
  • A module is defined by a module clause
  • The module clause is the first of the file
  • A module clause gives
    • the module name
    • the library is uses
    • the modules it imports
    • the variables, functions, and classes it exports
introprimerwebmtierhopdiffuse
HOP home pageINRIA38 of 138
An example of module
saveuseedit
(module myapp
   
   (library multimedia
	    hopdroid)

   (import utils
	   telephony)

   (export (compose-sms ::bstring ::bstring)
	   (read-sms ::bstring)))


(define (compose-sms number::bstring text::bstring)
   ...)

(define (read-sms text::bstring)
   ...)
introprimerwebmtierhopdiffuse
HOP home pageINRIA39 of 138
Module access file
  • File names and module names are unrelated
  • The tool bglafile creates an association table
  • Hop reads the association table when importing modules
$ bglafile *.hop -o .afile
$ cat .afile
((myapp "myapp.hop")
 (utils "utils.hop")
 ...)
introprimerwebmtierhopdiffuse
HOP home pageINRIA40 of 138
Web Programming
Web Programming
Roadmap - Web Programming
  1. Diffuse Computing
  2. Hop Primer
    • Functional Programming
    • Data structures
    • Lists
    • Functions
    • Exceptions, escapes, continuations
    • Modules
  3. Programming the Web
    • HTTP
    • HTML
    • CGI
    • Ajax
  4. Multi-tier programming
    • GWT
    • Links
    • Hop
  5. Hop, programming the Web
    • Syntax and Semantics
    • Services
    • Events
    • DOM
    • API
    • HSS
  6. Hop, programming the diffuse Web
    • Weblets
    • JavaScript interoperability
    • Demos Implementation
    • Mobile Phone
introprimerwebmtierhopdiffuse
HOP home pageINRIA42 of 138
At first was HTTP/1.0
image/svg+xml HTTP response HTML Client Server HTTP request
  • Response is a HTML static document
  • Stateless connections
  • Responses made of texts and images
introprimerwebmtierhopdiffuse
HOP home pageINRIA43 of 138
HTTP/1.0 (RFC 1945)
The server REPL (Read Eval Print Loop)
  1. wait for a socket connection
  2. parse the HTTP request
  3. send the response
  4. goto 1
The syntax of the request
GET|HEAD|POST <path> HTTP/1.0\r\n
The response
..., 2xx success, ..., 4xx error, ...
introprimerwebmtierhopdiffuse
HOP home pageINRIA44 of 138
HTTP/1.0 example
A Request
GET /html/rfc1945 HTTP/1.0
Host: tools.ietf.org
User-Agent: Mozilla/5.0
Accept-Encoding: gzip, deflate
Accept-Charset: utf-8...
A Response
HTTP/1.0 200 OK
Server: Apache/2.2.12 (Debian)
Content-Length: 174663

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<HTML>
<HEAD>
<TITLE>RFC 1945 (rfc1945) - Hypertext Transfer Protocol...
introprimerwebmtierhopdiffuse
HOP home pageINRIA45 of 138
Implementing HTTP/1.0
saveuseedit
(define (make-http-server port)
   (wait-http-connection (make-server-socket port)))

(define (wait-http-connection srv)
   (let ((sock (socket-accept srv)))
      (send-http-response (parse-http-request sock) sock)
      (wait-http-connection srv)))

(define (parse-http-request sock)
   (let* ((l (read-line (socket-input sock)))
	  (m (pregexp-match "^GET ([^ ]+) HTTP/1.0$" l)))
      (and (pair? m) (cadr m))))

(define (send-http-response path sock)
   (let ((out (socket-output sock)))
      (if (and (string? path) (file-exists? path))
	  (let ((len (file-length path)))
	     (display "HTTP/1.0 200 ok\r\n" out)
	     (display* "Content-Length: " len "\r\n" out)
	     (display "\r\n" out)
	     (send-file path out))
	  (display "HTTP/1.0 404 Not Found\r\n" out))
      (close-output-port out)))
introprimerwebmtierhopdiffuse
HOP home pageINRIA46 of 138
Multi-threaded HTTP/1.0
saveuseedit
(define (make-http-server port)
   (wait-http-connection (make-server-socket port)))

(define (wait-http-connection srv)
   (let ((sock (socket-accept srv)))
      (thread-start!
       (instantiate::pthread
	  (body
	   (lambda ()
	      (send-http-response (parse-http-request sock) sock)))))
      (wait-http-connection srv)))

(define (parse-http-request sock)
   ...)

(define (send-http-response path sock)
   ...)
introprimerwebmtierhopdiffuse
HOP home pageINRIA47 of 138
HTML(s)
introprimerwebmtierhopdiffuse
HOP home pageINRIA48 of 138
HTML structure
A XML header
<!DOCTYPE HTML PUBLIC
  "-//W3C//DTD HTML 4.01 Transitional//EN">

<!DOCTYPE html PUBLIC
  "-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN"
  "http://www.w3.org/2002/04/xhtml-math/xhtml-math.dtd"
  [<!ENTITY nbsp "&#160;">]>
Two HTML sections
<HTML>
   <HEAD> ... </HEAD>
   <BODY> ... </BODY>
</HTML>
introprimerwebmtierhopdiffuse
HOP home pageINRIA49 of 138
HTML4.01 <HEAD>
An example
<HEAD>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
  <title>RFC 1945 - Hypertext Transfer Protocol -- HTTP/1.0</title>
  <link rel="shortcut icon" href="/images/rfc.png" type="image/png"/>
  <link rel="stylesheet" href="default.css" type="text/css">
  ...
</HEAD>
    
introprimerwebmtierhopdiffuse
HOP home pageINRIA50 of 138
HTML4.01 <BODY>
An example (inspired by W3C's HTML 4.01 Specification)
<TABLE border="1"
  summary="This table gives some statistics about fruit
           flies: average height and weight, and percentage
           with red eyes (for both males and females).">
  <CAPTION><EM>A test table with merged cells</EM></CAPTION>
  <TR><TH rowspan="2"><TH colspan="2">Average
      <TH rowspan="2">Red<BR>eyes
  <TR><TH>height<TH>weight
  <TR<TH>Males<TD>1.9<TD>0.003<TD>40%
  <TR><TH>Females<TD>1.7<TD>0.002<TD>43%
</TABLE>
  • Permissive syntax
  • Automatic corrections
  • security flaws
    JavaScript instrumentation for browser security, Yu, D. and Chander, A. and Islam, N. and Serikov, I. -- POPL 2007.
introprimerwebmtierhopdiffuse
HOP home pageINRIA51 of 138
Common Gateway Interface (CGI)
Dynamic Pages
image/svg+xml HTTP response HTML Client Server HTTP GET/POST request CGI
  • Dynamic HTML generated by remote processes
  • HTTP POST + enctype="application/x-www-form-urlencoded"
introprimerwebmtierhopdiffuse
HOP home pageINRIA52 of 138
CGI: Inbound blending
Embed HTML inside any general purpose language
  • Perl
    print "<p>Hello ";
    print $firstname, " ", $name;
    print ",</p> <div> How do you do? <br> ... ";
    
  • C
    int main ( int argc, char *argv[] ) {
      char *firstname = cgi_args( argc, argv, "firstname" );
      char *name = cgi_args( argc, argv, "name" );
    
       printf( "<p>Hello %s %s,</p>\n"
               "<div> How to you do? <br>\n"
               "... ", firstname, name );
    }
    
introprimerwebmtierhopdiffuse
HOP home pageINRIA53 of 138
Servlets: Outbound blending
Extend HTML with alien markups
  • JSP = HTML + Java (Java Server Page)
  • Perl + HTML: HTML::Embperl
  • Apache::ASP, HTML::Template, Template Toolkit
  • Shervlet = HTML + sh
  • PHP = HTML + Perl-like language (Personal Home Page)
<p> Hello <?php echo $firstname ?>, <?php echo $name ?>, </p>
  <div> How do you do? <br> ...
introprimerwebmtierhopdiffuse
HOP home pageINRIA54 of 138
Servlets implementation
implementation of Shervlet = sh+HTML...
<html><head><title> shervlet </title></head><body> 
It is <?sh date + '%l'?> o'clock now<br>
says <?sh uname -a ?></body></html>

<html><head><title> shervlet </title></head><body> 
<?sh if [ "$REMOTE_HOST" = '1.2.3.4' ] ; then ?>
Hello pal, <?sh ;else ?>
Hi, <?sh fi ?> </body></html>
The first program can be compiled as:
#!/bin/sh
  echo -n "<html><head><title> shervlet </title></head><body> 
It is "
  date + '%l'
  echo -n " o'clock<br>
says "
  uname -a 
  echo -n "</body></html>"
introprimerwebmtierhopdiffuse
HOP home pageINRIA55 of 138
CGI Sessions and States
How to implement States?
Using cookies
<------------- 200 OK
Set-Cookie: NGUserID=3e17099b-28471-1016452371-1;
   expires=Wednesday, 30-Dec-2037 16:00:00 GMT;
   path=/; domain=www.hi-media.com

-------------> GET www.hi-media.com/url
Cookie: NGUserID=3e17099b-28471-1016452371-1
  • 20 cookies max per domain,
  • 4Kb max per cookie.
introprimerwebmtierhopdiffuse
HOP home pageINRIA56 of 138
Back, clone, and State
Back button and multi-browsing is error prone
image/svg+xml SUBMIT! SUBMIT! D ABCEGHF SUM?SUM?+++++ SumServlet (I)A number please? A number please?SumServlet (I) SumServlet (III) SumServlet (III) SumServlet (III)SumServlet (II)SumServlet (II)123100100661001661231442166123201123201324
The influence of browsers on evaluators, Queinnec, C.-- ICFP 2000.
introprimerwebmtierhopdiffuse
HOP home pageINRIA57 of 138
Continuations
The solution is to capture continuations
(let ((n1 (read1stNumber)))
  (let ((n2 (read2ndNumber n1)))
    (displaySum n1 n2) ) )

(define (read1stNumber)
  (define (create-page kUrl)
    (html (head (title "First number?"))
          (body (form action: kUrl "A number please? "
                  (input type: 'text name: "n1")
                  (input type: 'submit value: "go!") ))))
  (let ((request (show create-page)))
    (string->number 
     (request-parameter-get request "n1") ) ) )

(define (show page-creator)
  (call/cc
   (lambda (k)
     (answer-then-wait (page-creator (register! k))))))
Modeling Web Interfactions, Graunke, P. and Findler, R. and Krishnamurthi, S. and Felleisen, M.-- ESOP 2003.
introprimerwebmtierhopdiffuse
HOP home pageINRIA58 of 138
Then came Ajax...
googleSuggest1small.png
introprimerwebmtierhopdiffuse
HOP home pageINRIA59 of 138
HTTP/1.1 + Interactions
image/svg+xml starts program HTML HTML HTML Client Server graft run JS event JS JS JS JS JS request response same server
  • Click, text input, mouse movements fire events
  • Events trigger Javascript listeners
  • Javascript may request
  • Responses may update or replace parts of the HTML tree
introprimerwebmtierhopdiffuse
HOP home pageINRIA60 of 138
Client-Side Computing
JavaScript
  • A C-like syntax
  • A functional language (Scheme-like)
  • An OO language (prototypes based)
  • Fully polymorphic
  • Highly dynamic
    • Types are checked at runtime
    • Variables can be declared at runtime
    • Properties can be added at runtime
ECMA-262: ECMAScript Language Specification, ECMA -- 3d edition, 1999
introprimerwebmtierhopdiffuse
HOP home pageINRIA61 of 138
JavaScript Popularity
introprimerwebmtierhopdiffuse
HOP home pageINRIA62 of 138
JavaScript and HTML
Tightly integrated into HTML
<HTML>
  <HEAD>
    <SCRIPT src='client.js' type='text/javascript'></SCRIPT>
    <SCRIPT type='text/javascript'>var ldate = new Date();</SCRIPT>
  </HEAD>
  <BODY>
    <SCRIPT type='text/javascript'>var idate = new Date();</SCRIPT>
    <SPAN onclick='alert( "load: " + ldate + " init: " + idate )'>
      Client Date
    </SPAN>
    <A href='javascript:this.href="http://hop.inria.fr"'>
      <TT>http://www.inria.fr</TT>
    </A>
  </BODY>
</HTML>
introprimerwebmtierhopdiffuse
HOP home pageINRIA63 of 138
Document Object Model (DOM)
In-memory HTML representation
image/svg+xml NodeList Node Node Node Node childNodes firstChild previousSibling nextSibling parentNode lastChild
introprimerwebmtierhopdiffuse
HOP home pageINRIA64 of 138
JavaScript + DOM
The whole DOM is supported by JS
<HTML>
  <SCRIPT>
function clicklistener( obj, event ) {
  var el = document.getElementById( "myelement" );

  el.style.color = "red";
  el.replaceNode( el.firstChild, el.lastChild );
  
  obj.innerHTML = "<span class='myclass'>a text</span>";
}
  </SCRIPT>
  ...
  <DIV onclick='clicklistener( this, event )'> ... </DIV>
  ...
  <SPAN id='myelement'> ... </SPAN>
</HTML>
introprimerwebmtierhopdiffuse
HOP home pageINRIA65 of 138
AJAX
XmlHttpRequest
(invented by Microsoft)
saveuseedit
var httpRequest = new XMLHttpRequest();

handler = function() {
  if( httpRequest.readyState ==  4 ) { // reponse OK
    if( httpRequest.status == 200 ) {
      httpRequest.responseText        // -> String
      httpRequest.responseXML         // -> DOM
    }
  }
}

httpRequest.onreadystatechange = handler;
httpRequest.open( "GET", "http://www.example.org/something" );
httpRequest.send();
introprimerwebmtierhopdiffuse
HOP home pageINRIA66 of 138
JSON
  • A convention for exchanging data
  • The syntax of JavaScript declarations
    • Arrays in angle brackets
    • Associative set in curly brackets
    • numbers, booleans, and strings
    [ { a: 1, foo: [-1e-23, 2.0, true] },
      'and even \nUnicode \uABCD!' ]
  • Natively supported by some browsers (JSON.parse)
introprimerwebmtierhopdiffuse
HOP home pageINRIA67 of 138
Comet
Servers push
  • In opposition to the original HTTP design
  • Implemented using standard HTTP techniques
    • hidden IFRAME + chunked responses
    • dynamic SCRIPT
    • Ajax long polling
    • Ajax XMLHttpRequest - multipart/x-mixed-replace
  • Flash sockets
  • Websockets
introprimerwebmtierhopdiffuse
HOP home pageINRIA68 of 138
Multitier programming
Multitier
Roadmap - Multitier Programming
  1. Diffuse Computing
  2. Hop Primer
    • Functional Programming
    • Data structures
    • Lists
    • Functions
    • Exceptions, escapes, continuations
    • Modules
  3. Programming the Web
    • HTTP
    • HTML
    • CGI
    • Ajax
  4. Multi-tier programming
    • GWT
    • Links
    • Hop
  5. Hop, programming the Web
    • Syntax and Semantics
    • Services
    • Events
    • DOM
    • API
    • HSS
  6. Hop, programming the diffuse Web
    • Weblets
    • JavaScript interoperability
    • Demos Implementation
    • Mobile Phone
introprimerwebmtierhopdiffuse
HOP home pageINRIA70 of 138
Ajax main difficulties
  • Generate well-formed HTML...
  • ... and correct Javascript fragments
  • Reduce the number of languages
  • Ease communications between clients and servers
  • ... and so many other aspects
    • separate event-handling from rendering
    • be efficient on either side
    • allow for good programming practices
    • ...
introprimerwebmtierhopdiffuse
HOP home pageINRIA71 of 138
Multitier Languages
  • GWT: Java-like multitier programming
    The Google Web Toolkit, Google -- http://code.google.com/webtoolkit
  • Links
    Links: Web Programming Without Tiers, Cooper, E. and Lindley, S. and Wadler, P. and Yallop, J. -- FMCO'06
  • Hop: diffuse web programming
    HOP, a language for programming the Web 2.0, Serrano, M. and Gallesio, E. and Loitsch, F. -- DLS'06
introprimerwebmtierhopdiffuse
HOP home pageINRIA72 of 138
Goggle Web Toolkit
  • The Java way-of-life on the Web
  • Client side are bundled in a /client/ package compiled to JavaScript
  • JavaScript runtime implementing subset of JRE
    • java.lang.{Boolean, Class, Number, Integer, StringBuffer, ...}
    • java.util.{Collections, Date, Vector, HashMap, ...}
    • Button, TextBox, TextArea, Grid, ...
introprimerwebmtierhopdiffuse
HOP home pageINRIA73 of 138
GWT main HTML page
saveuseedit
<html>
  <head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <link type="text/css" rel="stylesheet" href="Dict.css">
    <title>Dictionary Suggest</title>
    <script type="text/javascript" src="dict/dict.nocache.js"></script>
  </head>
  <body>
    <iframe src="javascript:''" id="__gwt_historyFrame" tabIndex='-1' 
            style="position:absolute;width:0;height:0;border:0"></iframe>
    <h1>Dictionary suggest</h1>
    <table align="center">
      <tr>
        <td colspan="2" style="font-weight:bold;">name:</td>  
      </tr>
      <tr>
        <td id="nameFieldContainer"></td>
        <td id="sendButtonContainer"></td>
      </tr>
    </table>
  </body>
</html>
introprimerwebmtierhopdiffuse
HOP home pageINRIA74 of 138
GWT client code
saveuseedit
package org.nohwere.client;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
...

public class Dict implements EntryPoint {
  private static final String SERVER_ERROR = "An error occurred while "
      + "attempting to contact the server. Please check your network "
      + "connection and try again.";

  private final GreetingServiceAsync greetingService =
     GWT.create(GreetingService.class);

  public void onModuleLoad() {
    final Button sendButton = new Button("Send");
    final TextBox nameField = new TextBox();

    sendButton.addStyleName("sendButton");

    RootPanel.get("nameFieldContainer").add(nameField);
    RootPanel.get("sendButtonContainer").add(sendButton);
    ...
  }
}   
introprimerwebmtierhopdiffuse
HOP home pageINRIA75 of 138
GWT module
saveuseedit
<module rename-to='dict'>
  <!-- Inherit the core Web Toolkit stuff.                        -->
  <inherits name='com.google.gwt.user.User'/>

  <!-- Inherit the default GWT style sheet.  You can change       -->
  <!-- the theme of your GWT application by uncommenting          -->
  <!-- any one of the following lines.                            -->
  <inherits name='com.google.gwt.user.theme.standard.Standard'/>
  <!-- <inherits name='com.google.gwt.user.theme.chrome.Chrome'/> -->
  <!-- <inherits name='com.google.gwt.user.theme.dark.Dark'/>     -->

  <!-- Other module inherits                                      -->

  <!-- Specify the app entry point class.                         -->
  <entry-point class='org.nohwere.client.Dict'/>
</module>
introprimerwebmtierhopdiffuse
HOP home pageINRIA76 of 138
GWT server code
saveuseedit
package org.nohwere.server;

import org.nohwere.client.GreetingService;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;

@SuppressWarnings("serial")
public class GreetingServiceImpl extends RemoteServiceServlet implements
    GreetingService {

  public String greetServer(String input) {
    String serverInfo = getServletContext().getServerInfo();
    String userAgent = getThreadLocalRequest().getHeader("User-Agent");
    return "Hello, " + input + "!<br><br>I am running " + serverInfo
        + ".<br><br>It looks like you are using:<br>" + userAgent;
  }
}
introprimerwebmtierhopdiffuse
HOP home pageINRIA77 of 138
GWT RPC
saveuseedit
package org.nohwere.client;

import com.google.gwt.user.client.rpc.AsyncCallback;

public interface GreetingServiceAsync {
  void greetServer(String input, AsyncCallback<String> callback);
}
introprimerwebmtierhopdiffuse
HOP home pageINRIA78 of 138
JavaScript Native Interface
saveuseedit
package mypackage;

public MyUtilityClass {
  public static int computeLoanInterest(int amt, float interestRate, int term) { ... }
  public static native void defineBridgeMethod() /*-{
   $wnd.computeLoanInterest = function(amt, intRate, term) {
      return @mypackage.MyUtilityClass::computeLoanInterest(IFI)(amt, intRate, term);
   }
  }-*/;
}

public static native String myMethod(String arg) /*-{
  eval("var myVar = 'arg is " + arg + "';");
  return myVar;
}-*/;

class C {
  void doCallback(String callbackData) { ..... }
  native void invokeExternal(String data) /*-{
    $wnd.externalJsFunction(data, @p.C::doCallback(Ljava/lang/String;));
  }-*/;
}
introprimerwebmtierhopdiffuse
HOP home pageINRIA79 of 138
GWT Pros and Cons
  • Pros
    • Java Development model
    • Java Development environment (Eclipse)
  • Cons
    • Weak HTML integration
    • Weak JavaScript integration
introprimerwebmtierhopdiffuse
HOP home pageINRIA80 of 138
Links
  • Adresses the three tiers of Web applications
  • A strict, typed, functional language
  • Session and state stored on clients (URL encoded continuations)
    http://groups.inf.ed.ac.uk/links/examples/wine.links?_cont=AtEUA7gOAAADATS5DgAAAwMyMDi6DgAAAwItMfoUAA==
  • Functions labeled with locations but invokable by both ends
  • Client-code compiled to JavaScript, database-code to SQL
  • Client-side concurrency inspired by Erlang
    Concurrent Programming in ERLANG, Armstrong, J. and Virding, R. and Wikstrom, C. and Williams, M. -- Prentrice Hall, 1996
introprimerwebmtierhopdiffuse
HOP home pageINRIA81 of 138
Links Dictionary suggest (1)
A lightweight Google Suggest
<!-- dictionary.html -->
<html>
  <head>
   <title>Dictionary suggest</title>
  </head>
  <body>
   <h1>Dictionary suggest</h1>
   <form l:onkeyup="{handler!Suggest(pre)}">
    <input type="text" l:name="pre" autocomplete="off"/>
   </form>
   <div id="suggestions"/>
  </body>
</html>
introprimerwebmtierhopdiffuse
HOP home pageINRIA82 of 138
Links Dictionary suggest (2)
## dictionary.links
var handler = spawn {
 fun receiver() {
  receive { case Suggest(pre) -> suggest(pre); receiver() }
 }
 receiver()
};

fun lowercase(s) {
  for (c <- s) [toLower(c)]
}

fun suggest(pre) client {
 replaceChildren( format(completions(lowercase(pre))), 
                  getNodeById("suggestions") )
} 

fun format(words) {
 for (w <- words)
  <div>
   <b> {stringToXml(w.word)} </b>
   <i> {stringToXml(w.type)} </i>: {stringToXml(w.meaning)}
  </div>
}
introprimerwebmtierhopdiffuse
HOP home pageINRIA83 of 138
Links Dictionary suggest (3)

## dictionary.links (follow)
fun completions(pre) server {
 var wordlist = table "wordlist" with (
   word : String, 
   type : String, 
   meaning : String
 ) from (database "dictionary");

 if (pre == "") []
 else {
  query [10] {
   for (w <-- wordlist)
    where (w.word =~ /^{pre}.*/)
    orderby (w.word)
     [w]
  }
 }
}
introprimerwebmtierhopdiffuse
HOP home pageINRIA84 of 138
Hop
  • A dynamically type checked functional language
  • Relies on standard Web technologies
  • Relies on the traditional Web development model
    • Use the HTTP protocol
    • Generate HTML and client-side code
    • Generate CSS
    • Rely on the Web security model
  • Symmetric
    • HTML is a first class value
    • DOM available on both sides
introprimerwebmtierhopdiffuse
HOP home pageINRIA85 of 138
Hop - Dictionary suggest
saveuseedit
(module dict
   (library sqlite))

(define-service (dict/completions pre)
   (sqlite-map (instantiate::sqlite (path "dictionary"))
	 cons (format "SELECT word, type
                         FROM dictionary
                        WHERE word like ~a" pre)))

(define-service (dict)
   (let ((suggest (<DIV>)))
      (<HTML>
	 (<HEAD> :title "Dictionary suggest"
	    ~(define (suggest pre)
		(with-hop ($dict/completions (string-downcase pre))
		   (lambda (v)
		      (innerHTML-set! $suggest (format v)))))
	    ~(define (format words)
		(map (lambda (w)
			(<DIV> (<B> (car w)) (<I> (cdr w))))
		     words)))
	 (<BODY>
	    (<H1> "Dictionary suggest")
	    (<INPUT> :type 'text :onkeyup ~(suggest this.value))
	    suggest))))
introprimerwebmtierhopdiffuse
HOP home pageINRIA86 of 138
Hop
Hop
(multitier programming)
Roadmap - Hop
  1. Diffuse Computing
  2. Hop Primer
    • Functional Programming
    • Data structures
    • Lists
    • Functions
    • Exceptions, escapes, continuations
    • Modules
  3. Programming the Web
    • HTTP
    • HTML
    • CGI
    • Ajax
  4. Multi-tier programming
    • GWT
    • Links
    • Hop
  5. Hop, programming the Web
    • Syntax and Semantics
    • Services
    • Events
    • DOM
    • API
    • HSS
  6. Hop, programming the diffuse Web
    • Weblets
    • JavaScript interoperability
    • Demos Implementation
    • Mobile Phone
introprimerwebmtierhopdiffuse
HOP home pageINRIA88 of 138
Hop, a Functional Language
  • Strict
  • Types checked at runtime
    • untyped λ-calculus
  • Impure
    • Side effects
  • Infix syntax
    • Inspired by the λ-calculus
introprimerwebmtierhopdiffuse
HOP home pageINRIA89 of 138
Hop, a Web Language
  • UIs based on HTML and CSS
    • but HTML is a value of the language
  • UIs rely on event loops
  • Web sessions
  • Web security
    • authentication mecanisms
    • same origin policy
introprimerwebmtierhopdiffuse
HOP home pageINRIA90 of 138
Hop, a multitier Language
  • Unique formalism
    • A unique syntax
    • A unique semantics
  • Asymetric
    • The client for the GUI
    • The server for other resources
  • Explicit partionning
    • Syntactic annotations $ et ~
  • The server generates the client
    • Client-side programs are values of the server
introprimerwebmtierhopdiffuse
HOP home pageINRIA91 of 138
The syntax
H::=v | int | string | ...
|(lambda (v ...) H ...)
|(if H H H)
|(set! v H)
|(H H ...)
|(with-hop H H)
|s(service [:url H] (v ...) H ...)
|s~H
|c$H
introprimerwebmtierhopdiffuse
HOP home pageINRIA92 of 138
Hop Programming
Hop = Html with a revisited syntax + ...
  • The HTML version
    <HTML>
       <BODY>
          <TABLE>
             <TR><TD onclick="alert( '1' )">1</TD></TR>
             <TR><TD onclick="alert( '2' )">2</TD></TR>
             <TR><TD onclick="alert( '3' )">3</TD></TR>
          </TABLE>
       </BODY>
    </HTML>
    
  • The Hop version demo
    saveuseedit
    (<HTML>
       (<BODY>
          (<TABLE>
             (<TR> (<TD> :onclick ~(alert "1") 1))
             (<TR> (<TD> :onclick ~(alert "2") 2))
             (<TR> (<TD> :onclick ~(alert "3") 3)))))
    
introprimerwebmtierhopdiffuse
HOP home pageINRIA93 of 138
Hop Dom
a DOM at both ends
  • ASP, JSP, PHP, ...
    <HTML>
       <BODY>
          <TABLE>
    <?php
    for( $i=1; $i<4; $i++ )
       echo "<TR><TD onclick='alert( $i )'>$i</TD></TR>"
    ?>
          </TABLE>
       </BODY>
    </HTML>
    
  • The Hop version
    (<HTML>
       (<BODY>
          (<TABLE>
    	 (map (lambda (i)
    		 (<TR> (<TD> :onclick ~(alert $i) i)))
    	      (iota 3 1)))))
    
introprimerwebmtierhopdiffuse
HOP home pageINRIA94 of 138
Hop Dom, 2
Dynamic structural changes of the GUI demo
saveuseedit
(let ((el (<UL>
	     (<LI> "foo")
	     (<LI> "bar")
	     (<LI> "gee"))))
   (<DIV>
      el
      (<BUTTON>
	 :onclick ~(let* ((cs (dom-child-nodes $el))
			  (c0 (car cs))
			  (c1 (cadr cs)))
		      (dom-replace-child! $el c1 c0)
		      (dom-append-child! $el c0))
	 "rotate")))
introprimerwebmtierhopdiffuse
HOP home pageINRIA95 of 138
The Services
  • (lambda (x y ...) ...)=
    val x val x ... val
    ((lambda (a) (+ 1 a)) 4)
       5
  • (service (x y ...) ...)=
    val x val x ... url
    ((service (a) (+ 1 a)) 4)
       http://localhost:8080/hop/svc-23ab4c7?a=4
  • (with-hop u k)=
    val
    (with-hop ($(service (a) (+ 1 a)) 4) (lambda (v) v))
       5
introprimerwebmtierhopdiffuse
HOP home pageINRIA96 of 138
Hop Ajax
An example of service invocation demo
saveuseedit
(define cmd
   (service (dir)
      (map (lambda (path) (list (basename path) (file-size path)))
         (directory->path-list dir))))

(let ((console (<DIV>)))
  (<DIV>
    (<BUTTON> "du -sk"
       :onclick ~(with-hop ($cmd "/tmp")
	           (lambda (v)
	      	     (dom-set-child-node! $console 
		       (<TABLE>
			 (map (lambda (r)
				 (<TR> (<TH> (car r)) (<TD> (cadr r))))
			      v))))))
    console))
introprimerwebmtierhopdiffuse
HOP home pageINRIA97 of 138
Hop Comet
Intrinsic GUI events demo
saveuseedit
(let ((canvas (<CANVAS> :width 650 :height 200)))
   (<HTML>
      canvas
      ~(let ((ctx ($canvas.getContext "2d")))
	  (set! ctx.lineWidth 10)
	  (add-event-listener! $canvas "mousedown"
	     (lambda (evt)
		(ctx.lineTo (event-mouse-x evt) (event-mouse-y evt))
		(ctx.stroke))))))
introprimerwebmtierhopdiffuse
HOP home pageINRIA98 of 138
Hop Comet, 2
Server Side Events
saveuseedit
(let ((canvas (<CANVAS> :width 650 :height 200)))
   (<HTML>
      canvas
      ~(let ((ctx ($canvas.getContext "2d")))
	  (set! ctx.lineWidth 10)
	  (add-event-listener! $canvas "mousedown"
	     (lambda (evt)
		(ctx.lineTo (event-mouse-x evt) (event-mouse-y evt))
		(ctx.stroke))))
		
      ~(add-event-listener! $canvas "mousedown"
	  (lambda (evt)
	     (with-hop ($(service (e)
			    (hop-event-broadcast! "draw" e))
	        (cons (event-mouse-x evt) (event-mouse-y evt))))))
		
      ~(window-open :src $reactive-canvas :title "canvas1")
      ~(window-open :src $reactive-canvas :title "canvas2")))
introprimerwebmtierhopdiffuse
HOP home pageINRIA99 of 138
Hop Comet, 3
Client side API demo
(define-service (reactive-canvas)
   (let ((canvas (<CANVAS> :width 650 :height 200)))
      (<HTML>
	 canvas
	 ~(let ((ctx ($canvas.getContext "2d")))
	     (set! ctx.lineWidth 10)
	     (set! ctx.strokeStyle "rgba(0,200,0)")
	     (add-event-listener! server "draw" 
	        (lambda (evt)
		   (ctx.lineTo (car evt) (cdr evt))
		   (ctx.stroke)))))))
introprimerwebmtierhopdiffuse
HOP home pageINRIA100 of 138
Hop modules
A library module
(module string-lib
   (export (number->string/padding nunmber size padding)))

(define (number->string/padding number size padding)
   (let* ((s (number->string number))
	  (l (string-length s)))
      (if (>= l size)
	  s
	  (blit! (make-string size padding) s))))

(define (blit! dest src)
   (let loop ((i (- (string-length dest) 1))
	      (j (- (string-length src) 1)))
      (if (> j 0)
	  (begin
	     (string-set! dest i (string-ref src j))
	     (loop (- i 1) (- j 1)))
	  dest)))
introprimerwebmtierhopdiffuse
HOP home pageINRIA101 of 138
Hop modules 2/3
A server module
(module web-server
   (import string-lib)
   ~(import string-lib)
   (export web-app/service))

(define-service (web-app n)
   (<HTML>
      (<BODY> (number->string/padding n #\0 10))))

(define-service (web-app/service n)
   (<SPAN> n :onclick ~(alert (number->string/padding n #\0 10)))))
   
introprimerwebmtierhopdiffuse
HOP home pageINRIA102 of 138
Hop modules 3/3
A client module
(module web-client
   $(import web-server)
   (import string-lib)
   (export (web-client str)))

(define (web-client str)
   (<BUTTON> :onclick (with-hop ($web-app/service (string->integer str))
			 (lambda (n)
			    (dom-append-child! document.body n)))
      str))
   
introprimerwebmtierhopdiffuse
HOP home pageINRIA103 of 138
Hop Implementation
Multitier compilation
(define cmd
   (service (dir)
      (map file-size (directory->path-list dir))))

(let ((console (<DIV>)))
  (<DIV>
    (<BUTTON> "du -sk"
       :onclick ~(with-hop ($cmd "/tmp")
	           (lambda (v)
	      	     (dom-set-child-node! $console
		       (<TABLE>
			 (map (lambda (r) (<TR> (<TH> r))) v))))))
    console))
  • image/svg+xml
    Broker-side native code compilation
  • image/svg+xml
    Client-side JavaScript compilation
  • image/svg+xml
    Broker-side byte code interpretation
introprimerwebmtierhopdiffuse
HOP home pageINRIA104 of 138
HTML
(define (hello1 x)
   (<HTML> (<BODY> "Hello " x "!")))

(define-service (shello1 #!key x)
   (hello1 x))
Broker
image/svg+xml
Client
image/svg+xml
image/svg+xml <HTML> <BODY> "Hello" x "!"
<HTML>
 <BODY>
  Hello world!
 </BODY>
</HTML>
begin='' id='W5M0MpCehiHzreSzNTczkc9d' Adobe PDF library 5.00 2004-01-26T11:58:28+02:00 2004-03-28T20:37:32Z Adobe Illustrator 10.0 2004-02-16T21:16:04+01:00 JPEG 256 256 /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBAAEAAwER AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7 FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYqlvmDzFo 3l7TJdT1e5W1tItuTbszHoiKN2Y+AxV4j5g/5ydvTcMnl/SYlgU0Se/LOzDxMcTIF/4M4qk//QzP nv8A5YNL/wCRVx/2UYq7/oZnz3/ywaX/AMirj/soxV3/AEMz57/5YNL/AORVx/2UYq7/AKGZ89/8 sGl/8irj/soxV3/QzPnv/lg0v/kVcf8AZRirv+hmfPf/ACwaX/yKuP8AsoxV3/QzPnv/AJYNL/5F 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 uuid:aa51a61e-0ed7-4f03-8413-cc6baaffa58c image/svg+xml mime.ai image/svg+xml end='w'
introprimerwebmtierhopdiffuse
HOP home pageINRIA105 of 138
Client-side actions
(define-service (shello2 #!key x)
   (<HTML>
      (<BODY> :onclick ~(alert "Goodbye")
	 "Hello " x "!")))
Broker
image/svg+xml
Client
image/svg+xml
image/svg+xml <HTML> <BODY> "Hello" x "!" alert('Goodbye')
<HTML>
 <BODY onclick="alert('Goodbye')">
  Hello world!
 </BODY>
</HTML>
begin='' id='W5M0MpCehiHzreSzNTczkc9d' Adobe PDF library 5.00 2004-01-26T11:58:28+02:00 2004-03-28T20:37:32Z Adobe Illustrator 10.0 2004-02-16T21:16:04+01:00 JPEG 256 256 /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBAAEAAwER AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7 FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYqlvmDzFo 3l7TJdT1e5W1tItuTbszHoiKN2Y+AxV4j5g/5ydvTcMnl/SYlgU0Se/LOzDxMcTIF/4M4qk//QzP nv8A5YNL/wCRVx/2UYq7/oZnz3/ywaX/AMirj/soxV3/AEMz57/5YNL/AORVx/2UYq7/AKGZ89/8 sGl/8irj/soxV3/QzPnv/lg0v/kVcf8AZRirv+hmfPf/ACwaX/yKuP8AsoxV3/QzPnv/AJYNL/5F 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 uuid:aa51a61e-0ed7-4f03-8413-cc6baaffa58c image/svg+xml mime.ai image/svg+xml end='w'
introprimerwebmtierhopdiffuse
HOP home pageINRIA106 of 138
Client-side actions, 2
(define-service (shello3 #!key x)
   (<HTML>
      ~(define x "Goodbye")
      (<BODY> :onclick ~(alert x)
	 "Hello " x "!")))
Broker
image/svg+xml
Client
image/svg+xml
image/svg+xml <HTML> <BODY> "Hello" x "!" alert(x) var x='Goodbye'
<HTML>
 <SCRIPT>var x='Goodbye'</SCRIPT>
 <BODY onclick="alert(x)">
  Hello world!
 </BODY>
</HTML>
begin='' id='W5M0MpCehiHzreSzNTczkc9d' Adobe PDF library 5.00 2004-01-26T11:58:28+02:00 2004-03-28T20:37:32Z Adobe Illustrator 10.0 2004-02-16T21:16:04+01:00 JPEG 256 256 /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBAAEAAwER AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7 FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYqlvmDzFo 3l7TJdT1e5W1tItuTbszHoiKN2Y+AxV4j5g/5ydvTcMnl/SYlgU0Se/LOzDxMcTIF/4M4qk//QzP nv8A5YNL/wCRVx/2UYq7/oZnz3/ywaX/AMirj/soxV3/AEMz57/5YNL/AORVx/2UYq7/AKGZ89/8 sGl/8irj/soxV3/QzPnv/lg0v/kVcf8AZRirv+hmfPf/ACwaX/yKuP8AsoxV3/QzPnv/AJYNL/5F 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 uuid:aa51a61e-0ed7-4f03-8413-cc6baaffa58c image/svg+xml mime.ai image/svg+xml end='w'
introprimerwebmtierhopdiffuse
HOP home pageINRIA107 of 138
Staged execution
(define-service (shello4)
   (let ((hello (<SPAN> "Hello")))
      (<HTML>
	 (<BODY> :onclick
	    ~(innerHTML-set! $hello "Goodbye")
	    hello " world!"))))
Broker
image/svg+xml
Client
image/svg+xml
image/svg+xml <HTML> <BODY> "Hello" " world!" g23.innerHTML='Goodbye' <SPAN > id='g23'
<HTML>
 <BODY onclick="g23.innerHTML='Goodbye'">
  <SPAN id='g23'>Hello</SPAN> world!
 </BODY>
</HTML>
begin='' id='W5M0MpCehiHzreSzNTczkc9d' Adobe PDF library 5.00 2004-01-26T11:58:28+02:00 2004-03-28T20:37:32Z Adobe Illustrator 10.0 2004-02-16T21:16:04+01:00 JPEG 256 256 /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBAAEAAwER AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7 FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYqlvmDzFo 3l7TJdT1e5W1tItuTbszHoiKN2Y+AxV4j5g/5ydvTcMnl/SYlgU0Se/LOzDxMcTIF/4M4qk//QzP nv8A5YNL/wCRVx/2UYq7/oZnz3/ywaX/AMirj/soxV3/AEMz57/5YNL/AORVx/2UYq7/AKGZ89/8 sGl/8irj/soxV3/QzPnv/lg0v/kVcf8AZRirv+hmfPf/ACwaX/yKuP8AsoxV3/QzPnv/AJYNL/5F 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 uuid:aa51a61e-0ed7-4f03-8413-cc6baaffa58c image/svg+xml mime.ai image/svg+xml end='w'
begin='' id='W5M0MpCehiHzreSzNTczkc9d' Adobe PDF library 5.00 2004-01-26T11:58:28+02:00 2004-03-28T20:37:32Z Adobe Illustrator 10.0 2004-02-16T21:16:04+01:00 JPEG 256 256 /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBAAEAAwER AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7 FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYqlvmDzFo 3l7TJdT1e5W1tItuTbszHoiKN2Y+AxV4j5g/5ydvTcMnl/SYlgU0Se/LOzDxMcTIF/4M4qk//QzP nv8A5YNL/wCRVx/2UYq7/oZnz3/ywaX/AMirj/soxV3/AEMz57/5YNL/AORVx/2UYq7/AKGZ89/8 sGl/8irj/soxV3/QzPnv/lg0v/kVcf8AZRirv+hmfPf/ACwaX/yKuP8AsoxV3/QzPnv/AJYNL/5F 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 uuid:aa51a61e-0ed7-4f03-8413-cc6baaffa58c image/svg+xml mime.ai image/svg+xml end='w'
introprimerwebmtierhopdiffuse
HOP home pageINRIA108 of 138
Sharing
(define hello (<SPAN> "Hello"))

(define-service (shello5/set x)
   (innerHTML-set! hello x))

(define-service (shello5 #!key x)
   (<HTML>
      (<BODY> :onclick
	 ~(with-hop ($shello5/set $x)
	     (lambda (span)
		(dom-replace-child! document.body span $hello)))
	 hello " world!")))
begin='' id='W5M0MpCehiHzreSzNTczkc9d' Adobe PDF library 5.00 2004-01-26T11:58:28+02:00 2004-03-28T20:37:32Z Adobe Illustrator 10.0 2004-02-16T21:16:04+01:00 JPEG 256 256 /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBAAEAAwER AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7 FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYqlvmDzFo 3l7TJdT1e5W1tItuTbszHoiKN2Y+AxV4j5g/5ydvTcMnl/SYlgU0Se/LOzDxMcTIF/4M4qk//QzP nv8A5YNL/wCRVx/2UYq7/oZnz3/ywaX/AMirj/soxV3/AEMz57/5YNL/AORVx/2UYq7/AKGZ89/8 sGl/8irj/soxV3/QzPnv/lg0v/kVcf8AZRirv+hmfPf/ACwaX/yKuP8AsoxV3/QzPnv/AJYNL/5F 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 uuid:aa51a61e-0ed7-4f03-8413-cc6baaffa58c image/svg+xml mime.ai image/svg+xml end='w'
begin='' id='W5M0MpCehiHzreSzNTczkc9d' Adobe PDF library 5.00 2004-01-26T11:58:28+02:00 2004-03-28T20:37:32Z Adobe Illustrator 10.0 2004-02-16T21:16:04+01:00 JPEG 256 256 /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBAAEAAwER AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7 FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYqlvmDzFo 3l7TJdT1e5W1tItuTbszHoiKN2Y+AxV4j5g/5ydvTcMnl/SYlgU0Se/LOzDxMcTIF/4M4qk//QzP nv8A5YNL/wCRVx/2UYq7/oZnz3/ywaX/AMirj/soxV3/AEMz57/5YNL/AORVx/2UYq7/AKGZ89/8 sGl/8irj/soxV3/QzPnv/lg0v/kVcf8AZRirv+hmfPf/ACwaX/yKuP8AsoxV3/QzPnv/AJYNL/5F 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 uuid:aa51a61e-0ed7-4f03-8413-cc6baaffa58c image/svg+xml mime.ai image/svg+xml end='w'
introprimerwebmtierhopdiffuse
HOP home pageINRIA109 of 138
Hop widgets (1/3)
A set of additional widgets
audio, video, notepad, tree, slider, foldlist, pan, ...
The tree widget
markup → ... | tree

tree → (<TREE> tree-head tree-body)
tree-head → (<TRHEAD> markup)
tree-body → (<TRBODY> leaf-or-tree*)
leaf-or-tree → leaf | tree
leaf → (<TRLEAF> markup)
introprimerwebmtierhopdiffuse
HOP home pageINRIA110 of 138
Hop widgets (2/3)
A Static Tree
(define (dir->tree dir)
   (<TREE>
      (<TRHEAD> (basename dir))
      (<TRBODY>
         (map (lambda (p)
                 (if (directory? p)
                     (dir->tree p)
                     (<TRLEAF> :value p
			(basename p))))
	      (directory->path-list dir)))))

(dir->tree
 (dirname (dirname (the-loading-file))))
introprimerwebmtierhopdiffuse
HOP home pageINRIA111 of 138
Hop widgets (3/3)
A Dynamic Tree
(define (dir->tree dir)
   (<TREE>
      (<TRHEAD> (basename dir))
      (<TRBODY>
	 (service ()
	    (map (lambda (p)
		    (if (directory? p)
			(dir->tree p)
			(<TRLEAF> :value p
			   (basename p))))
	       (directory->path-list dir))))))

(dir->tree "/")
introprimerwebmtierhopdiffuse
HOP home pageINRIA112 of 138
Other widgets...
For the complete description have a look a the online documentation or the test suite.
introprimerwebmtierhopdiffuse
HOP home pageINRIA113 of 138
Requests and Responses
(current-request)
(abstract-class %http-message
   (seconds::elong read-only (default (current-seconds)))
   (header::pair-nil (default '()))
   (content-length::elong read-only (default #e-1))
   (charset (default #f)))

(class http-request::%http-message
   (user::user read-only (default (class-nil user)))
   (localclientp::bool (default #f))
   (http::symbol (default 'HTTP/1.1))
   (host::bstring (default "localhost"))
   (scheme::symbol (default 'http))
   (port::bint (default 80))
   (method::symbol read-only (default 'GET))
   (abspath::bstring (default ""))
   (connection::symbol (default 'keep-alive)))

(final-class http-server-request::http-request
   (authorization (default #f))
   (service::obj (default #unspecified)))

(class http-proxy-request::http-request
   (proxy-authorization (default #f)))
introprimerwebmtierhopdiffuse
HOP home pageINRIA114 of 138
Responses
(abstract-class %http-response::%http-message
   (content-type::obj read-only (default #f))
   (request::http-request (default (class-nil http-request)))
   (bodyp::bool read-only (default #t)))

(abstract-class %http-response-local::%http-response
   (server::bstring (default (hop-server-name)))
   (start-line::bstring read-only (default "HTTP/1.1 200 Ok")))

(class http-response-hop::%http-response-local
   (backend read-only)
   (value::obj read-only))
	   
(class http-response-procedure::%http-response-local
   (proc::procedure read-only))
	   
(class http-response-file::%http-response-local
   (file::bstring read-only))
	   
(class http-response-string::%http-response-local
   (body::bstring read-only (default "")))

(class http-response-authentication::http-response-string)

introprimerwebmtierhopdiffuse
HOP home pageINRIA115 of 138
Authorization
Access control
(define-service (service)
   (if (authorized-service? (current-request) 'service)
       ;; access authorized
       ... the actual implementation ...
       ;; return a "401 Unauthorized"
       (user-access-denied (current-request))))

(define-service (service2)
   (let ((req (current-request)))
      (with-access::http-request req (user localclientp abspath)
	 (if (or localclientp
		 (and (user-authorized-request? user req)
		      (user-authorized-path? user abspath)))
	     ... the actual implementation ...
	     (user-access-denied req)))))

(define (user-access-denied req)
   (instantiate::http-response-authentication
      (header (authenticate-header req))
      (start-line "HTTP/1.0 401 Unauthorized")
      (request req)
      (body "Protected Area! Authentication required.")))
introprimerwebmtierhopdiffuse
HOP home pageINRIA116 of 138
HSS
HTML for the content.
CSS for the rendering.
HSS a compiler for CSS. Serrano, M. -- PPDP 2010.
introprimerwebmtierhopdiffuse
HOP home pageINRIA117 of 138
Diffuse Programming
Hop
(diffuse programming)
Roadmap - Diffuse
  1. Diffuse Computing
  2. Hop Primer
    • Functional Programming
    • Data structures
    • Lists
    • Functions
    • Exceptions, escapes, continuations
    • Modules
  3. Programming the Web
    • HTTP
    • HTML
    • CGI
    • Ajax
  4. Multi-tier programming
    • GWT
    • Links
    • Hop
  5. Hop, programming the Web
    • Syntax and Semantics
    • Services
    • Events
    • DOM
    • API
    • HSS
  6. Hop, programming the diffuse Web
    • Weblets
    • JavaScript interoperability
    • Demos Implementation
    • Mobile Phone
introprimerwebmtierhopdiffuse
HOP home pageINRIA119 of 138
Install Hop
introprimerwebmtierhopdiffuse
HOP home pageINRIA120 of 138
Weblets
Weblets = Hop programs ready to be shipped
  • A source code and some conventions
  • Example
    example
    |-- config.hop
    |-- etc
    |   |-- favicon.png
    |   |-- example.wiki
    |   |-- homepage
    |   |   |-- 01-homepage.png
    |   |   `-- 01-homepage.wiki
    |   |-- logo.png
    |   `-- weblet.info
    |-- example.hop
    `-- example.hss
  • The Hop development environment
introprimerwebmtierhopdiffuse
HOP home pageINRIA121 of 138
JavaScript interoperability
Hop (client-side) and JavaScript share:
  • Variables,
  • Functions,
  • Basic data structures (numbers, strings, arrays, ...),
  • Exceptions.
introprimerwebmtierhopdiffuse
HOP home pageINRIA122 of 138
QR code example
http://d-project.googlecode.com/svn/trunk/misc/qrcode/js/qrcode.js
//---------------------------------------------------------------------
// QRCode for JavaScript
//
// Copyright (c) 2009 Kazuhiko Arase
//
// URL: http://www.d-project.com/
//
// Licensed under the MIT license:
//   http://www.opensource.org/licenses/mit-license.php
//
// The word "QR Code" is registered trademark of 
// DENSO WAVE INCORPORATED
//   http://www.denso-wave.com/qrcode/faqpatent-e.html
//
//---------------------------------------------------------------------

//---------------------------------------------------------------------
// QR8bitByte
//---------------------------------------------------------------------

function QR8bitByte(data) {
	this.mode = QRMode.MODE_8BIT_BYTE;
	this.data = data;
}

QR8bitByte.prototype = {

	getLength : function(buffer) {
		return this.data.length;
	},
	
	write : function(buffer) {
		for (var i = 0; i < this.data.length; i++) {
			// not JIS ...
			buffer.put(this.data.charCodeAt(i), 8);
		}
	}
};

//---------------------------------------------------------------------
// QRCode
//---------------------------------------------------------------------

function QRCode(typeNumber, errorCorrectLevel) {
	this.typeNumber = typeNumber;
	this.errorCorrectLevel = errorCorrectLevel;
	this.modules = null;
	this.moduleCount = 0;
	this.dataCache = null;
	this.dataList = new Array();
}

QRCode.prototype = {
	
	addData : function(data) {
		var newData = new QR8bitByte(data);
		this.dataList.push(newData);
		this.dataCache = null;
	},
	
	isDark : function(row, col) {
		if (row < 0 || this.moduleCount <= row || col < 0 || this.moduleCount <= col) {
			throw new Error(row + "," + col);
		}
		return this.modules[row][col];
	},

	getModuleCount : function() {
		return this.moduleCount;
	},
	
	make : function() {
		this.makeImpl(false, this.getBestMaskPattern() );
	},
	
	makeImpl : function(test, maskPattern) {
		
		this.moduleCount = this.typeNumber * 4 + 17;
		this.modules = new Array(this.moduleCount);
		
		for (var row = 0; row < this.moduleCount; row++) {
			
			this.modules[row] = new Array(this.moduleCount);
			
			for (var col = 0; col < this.moduleCount; col++) {
				this.modules[row][col] = null;//(col + row) % 3;
			}
		}
	
		this.setupPositionProbePattern(0, 0);
		this.setupPositionProbePattern(this.moduleCount - 7, 0);
		this.setupPositionProbePattern(0, this.moduleCount - 7);
		this.setupPositionAdjustPattern();
		this.setupTimingPattern();
		this.setupTypeInfo(test, maskPattern);
		
		if (this.typeNumber >= 7) {
			this.setupTypeNumber(test);
		}
	
		if (this.dataCache == null) {
			this.dataCache = QRCode.createData(this.typeNumber, this.errorCorrectLevel, this.dataList);
		}
	
		this.mapData(this.dataCache, maskPattern);
	},

	setupPositionProbePattern : function(row, col)  {
		
		for (var r = -1; r <= 7; r++) {
			
			if (row + r <= -1 || this.moduleCount <= row + r) continue;
			
			for (var c = -1; c <= 7; c++) {
				
				if (col + c <= -1 || this.moduleCount <= col + c) continue;
				
				if ( (0 <= r && r <= 6 && (c == 0 || c == 6) )
						|| (0 <= c && c <= 6 && (r == 0 || r == 6) )
						|| (2 <= r && r <= 4 && 2 <= c && c <= 4) ) {
					this.modules[row + r][col + c] = true;
				} else {
					this.modules[row + r][col + c] = false;
				}
			}		
		}		
	},
	
	getBestMaskPattern : function() {
	
		var minLostPoint = 0;
		var pattern = 0;
	
		for (var i = 0; i < 8; i++) {
			
			this.makeImpl(true, i);
	
			var lostPoint = QRUtil.getLostPoint(this);
	
			if (i == 0 || minLostPoint >  lostPoint) {
				minLostPoint = lostPoint;
				pattern = i;
			}
		}
	
		return pattern;
	},
	
	createMovieClip : function(target_mc, instance_name, depth) {
	
		var qr_mc = target_mc.createEmptyMovieClip(instance_name, depth);
		var cs = 1;
	
		this.make();

		for (var row = 0; row < this.modules.length; row++) {
			
			var y = row * cs;
			
			for (var col = 0; col < this.modules[row].length; col++) {
	
				var x = col * cs;
				var dark = this.modules[row][col];
			
				if (dark) {
					qr_mc.beginFill(0, 100);
					qr_mc.moveTo(x, y);
					qr_mc.lineTo(x + cs, y);
					qr_mc.lineTo(x + cs, y + cs);
					qr_mc.lineTo(x, y + cs);
					qr_mc.endFill();
				}
			}
		}
		
		return qr_mc;
	},

	setupTimingPattern : function() {
		
		for (var r = 8; r < this.moduleCount - 8; r++) {
			if (this.modules[r][6] != null) {
				continue;
			}
			this.modules[r][6] = (r % 2 == 0);
		}
	
		for (var c = 8; c < this.moduleCount - 8; c++) {
			if (this.modules[6][c] != null) {
				continue;
			}
			this.modules[6][c] = (c % 2 == 0);
		}
	},
	
	setupPositionAdjustPattern : function() {
	
		var pos = QRUtil.getPatternPosition(this.typeNumber);
		
		for (var i = 0; i < pos.length; i++) {
		
			for (var j = 0; j < pos.length; j++) {
			
				var row = pos[i];
				var col = pos[j];
				
				if (this.modules[row][col] != null) {
					continue;
				}
				
				for (var r = -2; r <= 2; r++) {
				
					for (var c = -2; c <= 2; c++) {
					
						if (r == -2 || r == 2 || c == -2 || c == 2 
								|| (r == 0 && c == 0) ) {
							this.modules[row + r][col + c] = true;
						} else {
							this.modules[row + r][col + c] = false;
						}
					}
				}
			}
		}
	},
	
	setupTypeNumber : function(test) {
	
		var bits = QRUtil.getBCHTypeNumber(this.typeNumber);
	
		for (var i = 0; i < 18; i++) {
			var mod = (!test && ( (bits >> i) & 1) == 1);
			this.modules[Math.floor(i / 3)][i % 3 + this.moduleCount - 8 - 3] = mod;
		}
	
		for (var i = 0; i < 18; i++) {
			var mod = (!test && ( (bits >> i) & 1) == 1);
			this.modules[i % 3 + this.moduleCount - 8 - 3][Math.floor(i / 3)] = mod;
		}
	},
	
	setupTypeInfo : function(test, maskPattern) {
	
		var data = (this.errorCorrectLevel << 3) | maskPattern;
		var bits = QRUtil.getBCHTypeInfo(data);
	
		// vertical		
		for (var i = 0; i < 15; i++) {
	
			var mod = (!test && ( (bits >> i) & 1) == 1);
	
			if (i < 6) {
				this.modules[i][8] = mod;
			} else if (i < 8) {
				this.modules[i + 1][8] = mod;
			} else {
				this.modules[this.moduleCount - 15 + i][8] = mod;
			}
		}
	
		// horizontal
		for (var i = 0; i < 15; i++) {
	
			var mod = (!test && ( (bits >> i) & 1) == 1);
			
			if (i < 8) {
				this.modules[8][this.moduleCount - i - 1] = mod;
			} else if (i < 9) {
				this.modules[8][15 - i - 1 + 1] = mod;
			} else {
				this.modules[8][15 - i - 1] = mod;
			}
		}
	
		// fixed module
		this.modules[this.moduleCount - 8][8] = (!test);
	
	},
	
	mapData : function(data, maskPattern) {
		
		var inc = -1;
		var row = this.moduleCount - 1;
		var bitIndex = 7;
		var byteIndex = 0;
		
		for (var col = this.moduleCount - 1; col > 0; col -= 2) {
	
			if (col == 6) col--;
	
			while (true) {
	
				for (var c = 0; c < 2; c++) {
					
					if (this.modules[row][col - c] == null) {
						
						var dark = false;
	
						if (byteIndex < data.length) {
							dark = ( ( (data[byteIndex] >>> bitIndex) & 1) == 1);
						}
	
						var mask = QRUtil.getMask(maskPattern, row, col - c);
	
						if (mask) {
							dark = !dark;
						}
						
						this.modules[row][col - c] = dark;
						bitIndex--;
	
						if (bitIndex == -1) {
							byteIndex++;
							bitIndex = 7;
						}
					}
				}
								
				row += inc;
	
				if (row < 0 || this.moduleCount <= row) {
					row -= inc;
					inc = -inc;
					break;
				}
			}
		}
		
	}

};

QRCode.PAD0 = 0xEC;
QRCode.PAD1 = 0x11;

QRCode.createData = function(typeNumber, errorCorrectLevel, dataList) {
	
	var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, errorCorrectLevel);
	
	var buffer = new QRBitBuffer();
	
	for (var i = 0; i < dataList.length; i++) {
		var data = dataList[i];
		buffer.put(data.mode, 4);
		buffer.put(data.getLength(), QRUtil.getLengthInBits(data.mode, typeNumber) );
		data.write(buffer);
	}

	// calc num max data.
	var totalDataCount = 0;
	for (var i = 0; i < rsBlocks.length; i++) {
		totalDataCount += rsBlocks[i].dataCount;
	}

	if (buffer.getLengthInBits() > totalDataCount * 8) {
		throw new Error("code length overflow. ("
			+ buffer.getLengthInBits()
			+ ">"
			+  totalDataCount * 8
			+ ")");
	}

	// end code
	if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) {
		buffer.put(0, 4);
	}

	// padding
	while (buffer.getLengthInBits() % 8 != 0) {
		buffer.putBit(false);
	}

	// padding
	while (true) {
		
		if (buffer.getLengthInBits() >= totalDataCount * 8) {
			break;
		}
		buffer.put(QRCode.PAD0, 8);
		
		if (buffer.getLengthInBits() >= totalDataCount * 8) {
			break;
		}
		buffer.put(QRCode.PAD1, 8);
	}

	return QRCode.createBytes(buffer, rsBlocks);
}

QRCode.createBytes = function(buffer, rsBlocks) {

	var offset = 0;
	
	var maxDcCount = 0;
	var maxEcCount = 0;
	
	var dcdata = new Array(rsBlocks.length);
	var ecdata = new Array(rsBlocks.length);
	
	for (var r = 0; r < rsBlocks.length; r++) {

		var dcCount = rsBlocks[r].dataCount;
		var ecCount = rsBlocks[r].totalCount - dcCount;

		maxDcCount = Math.max(maxDcCount, dcCount);
		maxEcCount = Math.max(maxEcCount, ecCount);
		
		dcdata[r] = new Array(dcCount);
		
		for (var i = 0; i < dcdata[r].length; i++) {
			dcdata[r][i] = 0xff & buffer.buffer[i + offset];
		}
		offset += dcCount;
		
		var rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount);
		var rawPoly = new QRPolynomial(dcdata[r], rsPoly.getLength() - 1);

		var modPoly = rawPoly.mod(rsPoly);
		ecdata[r] = new Array(rsPoly.getLength() - 1);
		for (var i = 0; i < ecdata[r].length; i++) {
            var modIndex = i + modPoly.getLength() - ecdata[r].length;
			ecdata[r][i] = (modIndex >= 0)? modPoly.get(modIndex) : 0;
		}

	}
	
	var totalCodeCount = 0;
	for (var i = 0; i < rsBlocks.length; i++) {
		totalCodeCount += rsBlocks[i].totalCount;
	}

	var data = new Array(totalCodeCount);
	var index = 0;

	for (var i = 0; i < maxDcCount; i++) {
		for (var r = 0; r < rsBlocks.length; r++) {
			if (i < dcdata[r].length) {
				data[index++] = dcdata[r][i];
			}
		}
	}

	for (var i = 0; i < maxEcCount; i++) {
		for (var r = 0; r < rsBlocks.length; r++) {
			if (i < ecdata[r].length) {
				data[index++] = ecdata[r][i];
			}
		}
	}

	return data;

}

//---------------------------------------------------------------------
// QRMode
//---------------------------------------------------------------------

var QRMode = {
	MODE_NUMBER :		1 << 0,
	MODE_ALPHA_NUM : 	1 << 1,
	MODE_8BIT_BYTE : 	1 << 2,
	MODE_KANJI :		1 << 3
};

//---------------------------------------------------------------------
// QRErrorCorrectLevel
//---------------------------------------------------------------------
 
var QRErrorCorrectLevel = {
	L : 1,
	M : 0,
	Q : 3,
	H : 2
};

//---------------------------------------------------------------------
// QRMaskPattern
//---------------------------------------------------------------------

var QRMaskPattern = {
	PATTERN000 : 0,
	PATTERN001 : 1,
	PATTERN010 : 2,
	PATTERN011 : 3,
	PATTERN100 : 4,
	PATTERN101 : 5,
	PATTERN110 : 6,
	PATTERN111 : 7
};

//---------------------------------------------------------------------
// QRUtil
//---------------------------------------------------------------------
 
var QRUtil = {

    PATTERN_POSITION_TABLE : [
	    [],
	    [6, 18],
	    [6, 22],
	    [6, 26],
	    [6, 30],
	    [6, 34],
	    [6, 22, 38],
	    [6, 24, 42],
	    [6, 26, 46],
	    [6, 28, 50],
	    [6, 30, 54],		
	    [6, 32, 58],
	    [6, 34, 62],
	    [6, 26, 46, 66],
	    [6, 26, 48, 70],
	    [6, 26, 50, 74],
	    [6, 30, 54, 78],
	    [6, 30, 56, 82],
	    [6, 30, 58, 86],
	    [6, 34, 62, 90],
	    [6, 28, 50, 72, 94],
	    [6, 26, 50, 74, 98],
	    [6, 30, 54, 78, 102],
	    [6, 28, 54, 80, 106],
	    [6, 32, 58, 84, 110],
	    [6, 30, 58, 86, 114],
	    [6, 34, 62, 90, 118],
	    [6, 26, 50, 74, 98, 122],
	    [6, 30, 54, 78, 102, 126],
	    [6, 26, 52, 78, 104, 130],
	    [6, 30, 56, 82, 108, 134],
	    [6, 34, 60, 86, 112, 138],
	    [6, 30, 58, 86, 114, 142],
	    [6, 34, 62, 90, 118, 146],
	    [6, 30, 54, 78, 102, 126, 150],
	    [6, 24, 50, 76, 102, 128, 154],
	    [6, 28, 54, 80, 106, 132, 158],
	    [6, 32, 58, 84, 110, 136, 162],
	    [6, 26, 54, 82, 110, 138, 166],
	    [6, 30, 58, 86, 114, 142, 170]
    ],

    G15 : (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0),
    G18 : (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0),
    G15_MASK : (1 << 14) | (1 << 12) | (1 << 10)	| (1 << 4) | (1 << 1),

    getBCHTypeInfo : function(data) {
	    var d = data << 10;
	    while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) >= 0) {
		    d ^= (QRUtil.G15 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) ) ); 	
	    }
	    return ( (data << 10) | d) ^ QRUtil.G15_MASK;
    },

    getBCHTypeNumber : function(data) {
	    var d = data << 12;
	    while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) >= 0) {
		    d ^= (QRUtil.G18 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) ) ); 	
	    }
	    return (data << 12) | d;
    },

    getBCHDigit : function(data) {

	    var digit = 0;

	    while (data != 0) {
		    digit++;
		    data >>>= 1;
	    }

	    return digit;
    },

    getPatternPosition : function(typeNumber) {
	    return QRUtil.PATTERN_POSITION_TABLE[typeNumber - 1];
    },

    getMask : function(maskPattern, i, j) {
	    
	    switch (maskPattern) {
		    
	    case QRMaskPattern.PATTERN000 : return (i + j) % 2 == 0;
	    case QRMaskPattern.PATTERN001 : return i % 2 == 0;
	    case QRMaskPattern.PATTERN010 : return j % 3 == 0;
	    case QRMaskPattern.PATTERN011 : return (i + j) % 3 == 0;
	    case QRMaskPattern.PATTERN100 : return (Math.floor(i / 2) + Math.floor(j / 3) ) % 2 == 0;
	    case QRMaskPattern.PATTERN101 : return (i * j) % 2 + (i * j) % 3 == 0;
	    case QRMaskPattern.PATTERN110 : return ( (i * j) % 2 + (i * j) % 3) % 2 == 0;
	    case QRMaskPattern.PATTERN111 : return ( (i * j) % 3 + (i + j) % 2) % 2 == 0;

	    default :
		    throw new Error("bad maskPattern:" + maskPattern);
	    }
    },

    getErrorCorrectPolynomial : function(errorCorrectLength) {

	    var a = new QRPolynomial([1], 0);

	    for (var i = 0; i < errorCorrectLength; i++) {
		    a = a.multiply(new QRPolynomial([1, QRMath.gexp(i)], 0) );
	    }

	    return a;
    },

    getLengthInBits : function(mode, type) {

	    if (1 <= type && type < 10) {

		    // 1 - 9

		    switch(mode) {
		    case QRMode.MODE_NUMBER 	: return 10;
		    case QRMode.MODE_ALPHA_NUM 	: return 9;
		    case QRMode.MODE_8BIT_BYTE	: return 8;
		    case QRMode.MODE_KANJI  	: return 8;
		    default :
			    throw new Error("mode:" + mode);
		    }

	    } else if (type < 27) {

		    // 10 - 26

		    switch(mode) {
		    case QRMode.MODE_NUMBER 	: return 12;
		    case QRMode.MODE_ALPHA_NUM 	: return 11;
		    case QRMode.MODE_8BIT_BYTE	: return 16;
		    case QRMode.MODE_KANJI  	: return 10;
		    default :
			    throw new Error("mode:" + mode);
		    }

	    } else if (type < 41) {

		    // 27 - 40

		    switch(mode) {
		    case QRMode.MODE_NUMBER 	: return 14;
		    case QRMode.MODE_ALPHA_NUM	: return 13;
		    case QRMode.MODE_8BIT_BYTE	: return 16;
		    case QRMode.MODE_KANJI  	: return 12;
		    default :
			    throw new Error("mode:" + mode);
		    }

	    } else {
		    throw new Error("type:" + type);
	    }
    },

    getLostPoint : function(qrCode) {
	    
	    var moduleCount = qrCode.getModuleCount();
	    
	    var lostPoint = 0;
	    
	    // LEVEL1
	    
	    for (var row = 0; row < moduleCount; row++) {

		    for (var col = 0; col < moduleCount; col++) {

			    var sameCount = 0;
			    var dark = qrCode.isDark(row, col);

				for (var r = -1; r <= 1; r++) {

				    if (row + r < 0 || moduleCount <= row + r) {
					    continue;
				    }

				    for (var c = -1; c <= 1; c++) {

					    if (col + c < 0 || moduleCount <= col + c) {
						    continue;
					    }

					    if (r == 0 && c == 0) {
						    continue;
					    }

					    if (dark == qrCode.isDark(row + r, col + c) ) {
						    sameCount++;
					    }
				    }
			    }

			    if (sameCount > 5) {
				    lostPoint += (3 + sameCount - 5);
			    }
		    }
	    }

	    // LEVEL2

	    for (var row = 0; row < moduleCount - 1; row++) {
		    for (var col = 0; col < moduleCount - 1; col++) {
			    var count = 0;
			    if (qrCode.isDark(row,     col    ) ) count++;
			    if (qrCode.isDark(row + 1, col    ) ) count++;
			    if (qrCode.isDark(row,     col + 1) ) count++;
			    if (qrCode.isDark(row + 1, col + 1) ) count++;
			    if (count == 0 || count == 4) {
				    lostPoint += 3;
			    }
		    }
	    }

	    // LEVEL3

	    for (var row = 0; row < moduleCount; row++) {
		    for (var col = 0; col < moduleCount - 6; col++) {
			    if (qrCode.isDark(row, col)
					    && !qrCode.isDark(row, col + 1)
					    &&  qrCode.isDark(row, col + 2)
					    &&  qrCode.isDark(row, col + 3)
					    &&  qrCode.isDark(row, col + 4)
					    && !qrCode.isDark(row, col + 5)
					    &&  qrCode.isDark(row, col + 6) ) {
				    lostPoint += 40;
			    }
		    }
	    }

	    for (var col = 0; col < moduleCount; col++) {
		    for (var row = 0; row < moduleCount - 6; row++) {
			    if (qrCode.isDark(row, col)
					    && !qrCode.isDark(row + 1, col)
					    &&  qrCode.isDark(row + 2, col)
					    &&  qrCode.isDark(row + 3, col)
					    &&  qrCode.isDark(row + 4, col)
					    && !qrCode.isDark(row + 5, col)
					    &&  qrCode.isDark(row + 6, col) ) {
				    lostPoint += 40;
			    }
		    }
	    }

	    // LEVEL4
	    
	    var darkCount = 0;

	    for (var col = 0; col < moduleCount; col++) {
		    for (var row = 0; row < moduleCount; row++) {
			    if (qrCode.isDark(row, col) ) {
				    darkCount++;
			    }
		    }
	    }
	    
	    var ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5;
	    lostPoint += ratio * 10;

	    return lostPoint;		
    }

};


//---------------------------------------------------------------------
// QRMath
//---------------------------------------------------------------------

var QRMath = {

	glog : function(n) {
	
		if (n < 1) {
			throw new Error("glog(" + n + ")");
		}
		
		return QRMath.LOG_TABLE[n];
	},
	
	gexp : function(n) {
	
		while (n < 0) {
			n += 255;
		}
	
		while (n >= 256) {
			n -= 255;
		}
	
		return QRMath.EXP_TABLE[n];
	},
	
	EXP_TABLE : new Array(256),
	
	LOG_TABLE : new Array(256)

};
	
for (var i = 0; i < 8; i++) {
	QRMath.EXP_TABLE[i] = 1 << i;
}
for (var i = 8; i < 256; i++) {
	QRMath.EXP_TABLE[i] = QRMath.EXP_TABLE[i - 4]
		^ QRMath.EXP_TABLE[i - 5]
		^ QRMath.EXP_TABLE[i - 6]
		^ QRMath.EXP_TABLE[i - 8];
}
for (var i = 0; i < 255; i++) {
	QRMath.LOG_TABLE[QRMath.EXP_TABLE[i] ] = i;
}

//---------------------------------------------------------------------
// QRPolynomial
//---------------------------------------------------------------------

function QRPolynomial(num, shift) {

	if (num.length == undefined) {
		throw new Error(num.length + "/" + shift);
	}

	var offset = 0;

	while (offset < num.length && num[offset] == 0) {
		offset++;
	}

	this.num = new Array(num.length - offset + shift);
	for (var i = 0; i < num.length - offset; i++) {
		this.num[i] = num[i + offset];
	}
}

QRPolynomial.prototype = {

	get : function(index) {
		return this.num[index];
	},
	
	getLength : function() {
		return this.num.length;
	},
	
	multiply : function(e) {
	
		var num = new Array(this.getLength() + e.getLength() - 1);
	
		for (var i = 0; i < this.getLength(); i++) {
			for (var j = 0; j < e.getLength(); j++) {
				num[i + j] ^= QRMath.gexp(QRMath.glog(this.get(i) ) + QRMath.glog(e.get(j) ) );
			}
		}
	
		return new QRPolynomial(num, 0);
	},
	
	mod : function(e) {
	
		if (this.getLength() - e.getLength() < 0) {
			return this;
		}
	
		var ratio = QRMath.glog(this.get(0) ) - QRMath.glog(e.get(0) );
	
		var num = new Array(this.getLength() );
		
		for (var i = 0; i < this.getLength(); i++) {
			num[i] = this.get(i);
		}
		
		for (var i = 0; i < e.getLength(); i++) {
			num[i] ^= QRMath.gexp(QRMath.glog(e.get(i) ) + ratio);
		}
	
		// recursive call
		return new QRPolynomial(num, 0).mod(e);
	}
};

//---------------------------------------------------------------------
// QRRSBlock
//---------------------------------------------------------------------

function QRRSBlock(totalCount, dataCount) {
	this.totalCount = totalCount;
	this.dataCount  = dataCount;
}

QRRSBlock.RS_BLOCK_TABLE = [

	// L
	// M
	// Q
	// H

	// 1
	[1, 26, 19],
	[1, 26, 16],
	[1, 26, 13],
	[1, 26, 9],
	
	// 2
	[1, 44, 34],
	[1, 44, 28],
	[1, 44, 22],
	[1, 44, 16],

	// 3
	[1, 70, 55],
	[1, 70, 44],
	[2, 35, 17],
	[2, 35, 13],

	// 4		
	[1, 100, 80],
	[2, 50, 32],
	[2, 50, 24],
	[4, 25, 9],
	
	// 5
	[1, 134, 108],
	[2, 67, 43],
	[2, 33, 15, 2, 34, 16],
	[2, 33, 11, 2, 34, 12],
	
	// 6
	[2, 86, 68],
	[4, 43, 27],
	[4, 43, 19],
	[4, 43, 15],
	
	// 7		
	[2, 98, 78],
	[4, 49, 31],
	[2, 32, 14, 4, 33, 15],
	[4, 39, 13, 1, 40, 14],
	
	// 8
	[2, 121, 97],
	[2, 60, 38, 2, 61, 39],
	[4, 40, 18, 2, 41, 19],
	[4, 40, 14, 2, 41, 15],
	
	// 9
	[2, 146, 116],
	[3, 58, 36, 2, 59, 37],
	[4, 36, 16, 4, 37, 17],
	[4, 36, 12, 4, 37, 13],
	
	// 10		
	[2, 86, 68, 2, 87, 69],
	[4, 69, 43, 1, 70, 44],
	[6, 43, 19, 2, 44, 20],
	[6, 43, 15, 2, 44, 16]

];

QRRSBlock.getRSBlocks = function(typeNumber, errorCorrectLevel) {
	
	var rsBlock = QRRSBlock.getRsBlockTable(typeNumber, errorCorrectLevel);
	
	if (rsBlock == undefined) {
		throw new Error("bad rs block @ typeNumber:" + typeNumber + "/errorCorrectLevel:" + errorCorrectLevel);
	}

	var length = rsBlock.length / 3;
	
	var list = new Array();
	
	for (var i = 0; i < length; i++) {

		var count = rsBlock[i * 3 + 0];
		var totalCount = rsBlock[i * 3 + 1];
		var dataCount  = rsBlock[i * 3 + 2];

		for (var j = 0; j < count; j++) {
			list.push(new QRRSBlock(totalCount, dataCount) );	
		}
	}
	
	return list;
}

QRRSBlock.getRsBlockTable = function(typeNumber, errorCorrectLevel) {

	switch(errorCorrectLevel) {
	case QRErrorCorrectLevel.L :
		return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0];
	case QRErrorCorrectLevel.M :
		return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1];
	case QRErrorCorrectLevel.Q :
		return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2];
	case QRErrorCorrectLevel.H :
		return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3];
	default :
		return undefined;
	}
}

//---------------------------------------------------------------------
// QRBitBuffer
//---------------------------------------------------------------------

function QRBitBuffer() {
	this.buffer = new Array();
	this.length = 0;
}

QRBitBuffer.prototype = {

	get : function(index) {
		var bufIndex = Math.floor(index / 8);
		return ( (this.buffer[bufIndex] >>> (7 - index % 8) ) & 1) == 1;
	},
	
	put : function(num, length) {
		for (var i = 0; i < length; i++) {
			this.putBit( ( (num >>> (length - i - 1) ) & 1) == 1);
		}
	},
	
	getLengthInBits : function() {
		return this.length;
	},
	
	putBit : function(bit) {
	
		var bufIndex = Math.floor(this.length / 8);
		if (this.buffer.length <= bufIndex) {
			this.buffer.push(0);
		}
	
		if (bit) {
			this.buffer[bufIndex] |= (0x80 >>> (this.length % 8) );
		}
	
		this.length++;
	}
};
introprimerwebmtierhopdiffuse
HOP home pageINRIA123 of 138
QR code
Adapt
(module qrcode
   ~(javascript QRCode)
   (export (<QRCODE> url)))

~(define (<QRCODE> url)
    (let ((qr (new QRCode 4 "L")))
       (qr.addData $url)
       (qr.make)
       (let ((l (iota (qr.getModuleCount))))
          (dom-append-child! document
             (<TABLE> :class "qrcode"
                (map (lambda (r)
                        (<TR>
                           (map (lambda (c)
				   (<TD> :class
				      (if (qr.isDark r c) "B" "W")))
			      l)))
                     l))))))
introprimerwebmtierhopdiffuse
HOP home pageINRIA124 of 138
QR code
Reuse
(module qrcode-expample
   (import qrcode))

(<HTML>
   (<HEAD> :jscript "http://d-project.goog.../sample.js")
   ~(<QRCODE> "http://hop.inria.fr"))
introprimerwebmtierhopdiffuse
HOP home pageINRIA125 of 138
Multimedia programming
introprimerwebmtierhopdiffuse
HOP home pageINRIA126 of 138
Multimedia, server side
(define-service (hopvidemo)
   (<HTML>
      (<HEAD> :include "hop-canvas" :include "hopvidemo")
      (<BODY>
	 
	 ~(add-event-listener! window "load" hopvidemo-init)

         (<H1> "A plain video")
         (<DIV> :style "text-align: center"
            (<VIDEO>  :src
               (service-resource hopvidemo "hopx10.ogv")
               :width 320 :height 200
               :controls #t))
         (<H1> "A video with a reflection effect")
         (<DIV> :style "text-align: center"
            (<VIDEO> :id "video" :src
               (service-resource hopvidemo "hopx10.ogv")
               :width 320 :height 200
               :controls #t)
            (<DIV> 
               (<CANVAS> :id "c1" :style "display: none")
               (<CANVAS> :id "c2" :style "height: 67px"))))))
introprimerwebmtierhopdiffuse
HOP home pageINRIA127 of 138
Multimedia, client side (init)
(define video #unspecified)
(define c1 #unspecified)
(define c2 #unspecified)
(define ctx1 #unspecified)
(define ctx2 #unspecified)

(define (hopvidemo-init)
   (set! video (dom-get-element-by-id "video"))
   (set! c1 (dom-get-element-by-id "c1"))
   (set! ctx1 (canvas-get-context c1 "2d"))
   (set! c2 (dom-get-element-by-id "c2"))
   (set! ctx2 (canvas-get-context c2 "2d"))
   (add-event-listener! video "play"
      (lambda ()
         (let ((height (min 256 (/ video.height 3))))
            (set! c1.width video.width)
            (set! c1.height height)
            (set! c2.width video.width)
            (set! c2.height height)
            (let loop ()
               (unless (or video.paused video.ended)
                  (compute-frame)
                  (after 0 loop)))))))
introprimerwebmtierhopdiffuse
HOP home pageINRIA128 of 138
Multimedia, visual effect
(define (compute-frame)
   (canvas-save ctx1)
   (canvas-set-transform ctx1 1 0 0 -1 0 video.height)
   (canvas-draw-image ctx1 video 0 0 video.width video.height)
   (canvas-restore ctx1)
   (let* ((frame (canvas-get-image-data ctx1 0 0 c1.width c1.height))
          (data frame.data)
          (l (/ data.length 4))
          (step (round (/ 256 c2.height))))
      ;; shaded rows
      (let loop ((j 0))
         (when (< j c2.height)
            (let ((alpha (max 0 (- 256 (* step j)))))
               (alpha-row data video.width j alpha)
               (loop (+ j 1)))))
      ;; draw the image
      (canvas-put-image-data ctx2 frame 0 0)))

(define (alpha-row data width j a)
   (let loop ((i 0))
      (when (< i (+ j width))
         (vector-set! data (+ 3 (* 4 (+ i (* width j)))) a)
         (loop (+ i 1)))))
introprimerwebmtierhopdiffuse
HOP home pageINRIA129 of 138
Third Party Services (JSON)
demo Online Translation
  • http://mymemory.translated.net
  • JSON parsing,
  • Locale aware.
(module translate)

(define-service (translate)
   (let ((input (<INPUT> :type 'text))
	 (output (<DIV> :id "result")))
      (<HTML>
	 input
	 output
	 (<BUTTON> :onclick ~(with-hop ($translate/text $input.value)
				(lambda (v)
				   (innerHTML-set! $output v)))
	    "translate"))))
introprimerwebmtierhopdiffuse
HOP home pageINRIA130 of 138
Third Party Services (JSON)
The server-side computation
(define-service (translate/text text)
   (with-url (format "http://mymemory.translated.net/api/get?&q=~a&langpair=~a" 
		(url-path-encode text)
		(url-path-encode "fr|en"))
      (lambda (o)
	 (let* ((k (cadr (assq :responseStatus o)))
		(d (cadr (assq :responseData o))))
	    (if (and (integer? k) (= k 200))
		(let ((t (cadr (assq :translatedText d))))
		   (charset-convert (html-string-decode t) 'UTF-8
		      (hop-charset)))
		"")))))
introprimerwebmtierhopdiffuse
HOP home pageINRIA131 of 138
Third Party JavaScript
demo PDF reader
(module pdfbook
   ~(import (pdfjs-api_client "pdfjs-api-1.*.*.hz"))
   (import (pdfjs-api "pdfjs-api-1.*.*.hz"))
   (import (turnjs-api "turnjs-api-1.*.*.hz")))

(define-service (pdfbook #!key src)
   (<HTML>
      (<HEAD> :title "PDFBOOK"
	 :include "turnjs-api-1.*.*.hz" "pdfjs-api-1.*.*.hz")
      (<DIV>
	 ~(add-event-listener! window "load"
	     (lambda ()
		(let ((mag ((@ jQuery js) "#paper")))
		   (mag.turn (alist->jsobject
				'((acceleration: #t)
				  (duration: 5000)))))))
	 (<DIV> :id "paper"
	    (map (lambda (i)
		    (<PDF> :controls #f :src src :page i))
	       (iota 10 1))))))
introprimerwebmtierhopdiffuse
HOP home pageINRIA132 of 138
HopDroid
introprimerwebmtierhopdiffuse
HOP home pageINRIA133 of 138
HopDroid
Initialization
  • Uses the phone and hopdroid libraries
  • Optionally uses the mail library
  • Create the wrapper to the phone internal
(module androidemo
   (library mail phone hopdroid)
   (import androidemo_config))

(define android
   (instantiate::androidphone))

(define atts
   (instantiate::androidtts
      (phone android)))
introprimerwebmtierhopdiffuse
HOP home pageINRIA134 of 138
HopDroid, Text-to-Speech
(<DIV>
   (<TEXTAREA> :id "speech" "")
   (<DIV> "language: "
      (let ((locale (phone-current-locale android)))
	 (<SELECT>
	    :onchange ~(with-hop ($(service (s)
				      (let ((l (call-with-input-string s read)))
					 (tts-locale-set! atts l)))
				    this.value))
	    (filter-map (lambda (l)
			   (when (eq? (tts-locale-check atts l) 'lang-country)
			      (<OPTION>
				 :label (list-ref l 3)
				 :value (with-output-to-string
					   (lambda () (write l)))
				 :selected (equal? l locale)
				 (list-ref l 3))))
	       (phone-locales android)))))
   (<BUTTON>
      :onclick ~(let ((el (dom-get-element-by-id "speech")))
		   (with-hop ($(service (text) (tts-speak atts text)) el.value)))
      "Speak"))
introprimerwebmtierhopdiffuse
HOP home pageINRIA135 of 138
HopDroid, SMS
Server-side and Client-sider listeners
(add-event-listener! android "sms-received"
   (lambda (e)
      (let ((val (event-value e)))
	 (hop-event-broadcast! "sms-received" val)
	 (tts-speak atts (cadr val)))))

(<DIV>
   ~(add-event-listener! server "sms-received" 
       (lambda (e)
	  (innerHTML-set! "sms-received-no" (car (event-value e)))
	  (innerHTML-set! "sms-received-text" (cadr (event-value e)))))
   (<DIV> "From: " (<SPAN> :id "sms-received-no"))
   (<PRE> :id "sms-received-text" ""))
introprimerwebmtierhopdiffuse
HOP home pageINRIA136 of 138
Connected
Devices
introprimerwebmtierhopdiffuse
HOP home pageINRIA137 of 138
Implementation
Architecture
001001000111 image/svg+xml DB Server lo Bluetooth 0m 10,000km 5m Ethernet Ethernet 500km 10,000km Ethernet
  • image/svg+xml
    SmartPhone
    ~(add-event-listener! window "deviceorientation"
        (lambda (e)
           (with-hop ($(service (x)
                          (hop-event-signal! "orientation" x))
                       e.gamma))))
    
  • image/svg+xml
    Laptop
    ~(add-event-listener! server "orientation"
        (lambda (e)
           (node-style-set! (hopslide-current-slide)
    	  :MozTransform (format "rotate: (~adeg)" e.value))))
    
introprimerwebmtierhopdiffuse
HOP home pageINRIA138 of 138