fyp final presentation
TRANSCRIPT
![Page 1: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/1.jpg)
Language Extensions and Abstractions�
OCaml �
![Page 2: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/2.jpg)
PROJECT OBJECTIVES�
![Page 3: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/3.jpg)
DEBUGGING�EXTENSION�
![Page 4: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/4.jpg)
LAZY EVALUATION�EXTENSION�
![Page 5: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/5.jpg)
WHAT IS CAMLP4?�
![Page 6: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/6.jpg)
WHAT IS CAMLP4?�Caml Preprocessor and Pretty
Printer�
![Page 7: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/7.jpg)
let rec fib = | 0 -‐> 0 | 1 -‐> 1 | n when n > 1 -‐> fib (n -‐ 1) + fib (n -‐ 2)
![Page 8: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/8.jpg)
let rec fib = memo | 0 -‐> 0 | 1 -‐> 1 | n when n > 1 -‐> fib (n -‐ 1) + fib (n -‐ 2)
![Page 9: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/9.jpg)
let rec fib = let tbl = Hashtbl.create 100 in fun x -‐> try Hashtbl.find tbl x with Not_found -‐> let result = match x with | 0 -‐> 0 | 1 -‐> 1 | n when n > 1 -‐> fib (n -‐ 1) + fib (n -‐ 2) in do { Hashtbl.replace tbl x result; ;result }
![Page 10: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/10.jpg)
let rec fib = let tbl = Hashtbl.create 100 in fun x -‐> try Hashtbl.find tbl x with Not_found -‐> let result = match x with | 0 -‐> 0 | 1 -‐> 1 | n when n > 1 -‐> fib (n -‐ 1) + fib (n -‐ 2) in do { Hashtbl.replace tbl x result; ;result }
![Page 11: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/11.jpg)
THINK MACROS�
![Page 12: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/12.jpg)
C MACROS?�
![Page 13: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/13.jpg)
LISP MACROS�For a statically typed language�
![Page 14: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/14.jpg)
let simple_optimize = object inherit Ast.map as super method expr e = match super#expr e with | <:expr< 1 * $e$ >> -‐> <:expr< $e$ >> | <:expr< 0 + $e$ >> -‐> <:expr< $e$ >> | e -‐> e end
![Page 15: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/15.jpg)
let simple_optimize = object inherit Ast.map as super method expr e = match super#expr e with | <:expr< 1 * $e$ >> -‐> <:expr< $e$ >> | <:expr< 0 + $e$ >> -‐> <:expr< $e$ >> | e -‐> e end
![Page 16: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/16.jpg)
let simple_optimize = object inherit Ast.map as super method expr e = match super#expr e with | <:expr< 1 * $e$ >> -‐> <:expr< $e$ >> | <:expr< 0 + $e$ >> -‐> <:expr< $e$ >> | e -‐> e end
1 * humblepi BECOMES humblepi 0 + humblepi BECOMES humblepi
![Page 17: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/17.jpg)
DEBUGGING EXTENSION�Easier function tracing and debugging
using annotations�
![Page 18: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/18.jpg)
PROBLEM�Functions are hard�
to debug�
![Page 19: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/19.jpg)
type env = (string * expr) list and expr = | Var of string | IntConst of int | Plus of expr * expr | Minus of expr * expr | Lambda of string * expr | Apply of expr * expr | Closure of env * string * expr
![Page 20: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/20.jpg)
let rec eval env e = let rec aux env e = match e with | IntConst _ -‐> e | Plus (e1, e2) -‐> ... in aux env e
![Page 21: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/21.jpg)
NO GENERIC PRINTERS�
![Page 22: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/22.jpg)
let rec string_of_expr e =! match e with! ... (* for every variant *)!and string_of_env env =! (* Map string_of_expr over elements *)!
![Page 23: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/23.jpg)
let rec eval env e = let rec aux env e = match e with | IntConst _ -‐> e | Plus (e1, e2) -‐> … in let _ = printf "Input: env = %s, e = %s" (string_of_env env) (string_of_expr e) in let out = aux env e in let _ = printf "Output: %s" (string_of_expr e) in out
![Page 24: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/24.jpg)
let rec eval env e = let rec aux env e = match e with | IntConst _ -‐> e | Plus (e1, e2) -‐> … in let _ = printf "Input: env = %s, e = %s" (string_of_env env) (string_of_expr e) in let out = aux env e in let _ = printf "Output: %s" (string_of_expr e) in out
![Page 25: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/25.jpg)
let rec eval env e = let rec aux env e = match e with | IntConst _ -‐> e | Plus (e1, e2) -‐> … in let _ = printf "Input: env = %s, e = %s" (string_of_env env) (string_of_expr e) in let out = aux env e in let _ = printf "Output: %s" (string_of_expr e) in out
Tedious and Cumbersome�
![Page 26: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/26.jpg)
SOLUTION�Generate debugging code from function�
annotated with debug keyword�
![Page 27: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/27.jpg)
let rec eval env e = let rec aux env e = match e with | IntConst _ -‐> e | Plus (e1, e2) -‐> ... in aux env e
![Page 28: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/28.jpg)
let debug rec eval env e = let rec aux env e = match e with | IntConst _ -‐> e | Plus (e1, e2) -‐> ... in aux env e
![Page 29: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/29.jpg)
DEMO�
![Page 30: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/30.jpg)
HOW DOES IT WORK?�
![Page 31: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/31.jpg)
Annotated�Expression�
![Page 32: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/32.jpg)
Camlp4 Lexer & Parser �
Annotated�Expression�
![Page 33: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/33.jpg)
Camlp4 Lexer & Parser �
Type Inference �
Annotated�Expression�
![Page 34: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/34.jpg)
Camlp4 Lexer & Parser �
Type Inference �
Deriving Library�
Annotated�Expression�
![Page 35: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/35.jpg)
Camlp4 Lexer & Parser �
Type Inference �
Deriving Library�
AST Transformer �
Annotated�Expression�
![Page 36: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/36.jpg)
Camlp4 Lexer & Parser �
Type Inference �
Deriving Library�
AST Transformer �
Annotated�Expression�
Generated�OCaml Code �
![Page 37: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/37.jpg)
Camlp4 Lexer & Parser �
Type Inference �
Deriving Library�
AST Transformer �
Annotated�Expression�
Generated�OCaml Code �
![Page 38: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/38.jpg)
Camlp4 Lexer & Parser �
Type Inference �
Deriving Library�
AST Transformer �
Annotated�Expression�
Generated�OCaml Code �
![Page 39: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/39.jpg)
TYPE INFERENCE�
![Page 40: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/40.jpg)
let sqr x = x * x!
TYPE INFERENCE STEP�RETURNS�[“int”; “int”]!
![Page 41: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/41.jpg)
let fact count x = match x with | 1 -> x | n -> fact (count – 1) (n * x)!
![Page 42: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/42.jpg)
let fact count x = match x with | 1 -> x | n -> fact (count – 1) (n * x)!
TYPE INFERENCE STEP�RETURNS�[“int”; “int”; “int”]!
![Page 43: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/43.jpg)
Camlp4 Lexer & Parser �
Type Inference �
Deriving Library�
AST Transformer �
Annotated�Expression�
Generated�OCaml Code �
![Page 44: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/44.jpg)
DERIVING LIBRARY�Third party open source library that
generates printing functions from types�
![Page 45: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/45.jpg)
type env = (string * expr) list and expr = | Var of string | IntConst of int | Plus of expr * expr | Minus of expr * expr | Lambda of string * expr | Apply of expr * expr | Closure of env * string * expr deriving (Show)
![Page 46: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/46.jpg)
Show.show<expr> (Plus (IntConst 40) (IntConst 2))
![Page 47: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/47.jpg)
LAZY EVALUATION EXTENSION�Automatic generation �
of lazy and force �
![Page 48: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/48.jpg)
PROBLEM�Lazy streams are�
difficult to work with�
![Page 49: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/49.jpg)
type 'a node_t = | Nil | Cons of 'a * ('a node_t)!
![Page 50: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/50.jpg)
type 'a node_t = | Nil | Cons of 'a * ('a node_t) Lazy.t!
![Page 51: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/51.jpg)
let map f l = let rec aux rest = match Lazy.force rest with | Cons (x, r) -> Cons (f x, lazy (aux r)) | Nil -> Nil in lazy (aux l)!
![Page 52: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/52.jpg)
let map f l = let rec aux rest = match Lazy.force rest with | Cons (x, r) -> Cons (f x, lazy (aux r)) | Nil -> Nil in lazy (aux l)!
![Page 53: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/53.jpg)
let zipwith f l1 l2 = let rec aux r1 r2 = match Lazy.force r1, Lazy.force r2 with | Cons (x1, r1), Cons (x2, r2) -> Cons ((f x1 x2), lazy (aux r1 r2)) | Cons (x, r), Nil -> Cons (x, lazy (aux r (lazy Nil))) | Nil, Cons (x, r) -> Cons (x, lazy (aux (lazy Nil) r)) | Nil, Nil -> Nil in lazy (aux l1 l2)!
![Page 54: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/54.jpg)
let zipwith f l1 l2 = let rec aux r1 r2 = match Lazy.force r1, Lazy.force r2 with | Cons (x1, r1), Cons (x2, r2) -> Cons ((f x1 x2), lazy (aux r1 r2)) | Cons (x, r), Nil -> Cons (x, lazy (aux r (lazy Nil))) | Nil, Cons (x, r) -> Cons (x, lazy (aux (lazy Nil) r)) | Nil, Nil -> Nil in lazy (aux l1 l2)!
![Page 55: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/55.jpg)
SOLUTION�Annotate with keyword�and insert lazy and force when type error occurs�
![Page 56: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/56.jpg)
let ilazy map f l = let rec aux rest = match rest with | Cons (x, r) -> Cons (f x, aux r) | Nil -> Nil in aux l!
![Page 57: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/57.jpg)
let ilazy zipwith f l1 l2 = let rec aux r1 r2 = match r1, r2 with | Cons (x1, r1), Cons (x2, r2) -> Cons ((f x1 x2), (aux r1 r2)) | Cons (x, r), Nil -> Cons (x, (aux r Nil)) | Nil, Cons (x, r) -> Cons (x, (aux Nil r)) | Nil, Nil -> Nil in (aux l1 l2)!
![Page 58: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/58.jpg)
HOW DOES IT WORK?�
![Page 59: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/59.jpg)
Annotated�Expression�
![Page 60: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/60.jpg)
Camlp4 Lexer & Parser �
Annotated�Expression�
![Page 61: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/61.jpg)
Camlp4 Lexer & Parser �
Type Checker�
Annotated�Expression�
![Page 62: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/62.jpg)
Camlp4 Lexer & Parser �
Type Checker�
AST Transformer �
Annotated�Expression�
![Page 63: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/63.jpg)
Camlp4 Lexer & Parser �
Type Checker�
AST Transformer �
Annotated�Expression�
Generated�OCaml Code �
![Page 64: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/64.jpg)
Camlp4 Lexer & Parser �
Type Checker�
AST Transformer �
Annotated�Expression�
Generated�OCaml Code �
![Page 65: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/65.jpg)
TYPE CHECKER�OUTPUT�
![Page 66: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/66.jpg)
Error: This expression has type 'a lazy_t! but an expression was expected of type! 'b Batteries.LazyList.node_t = 'b BatLazyList.node_t!
![Page 67: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/67.jpg)
Error: This expression has type 'a lazy_t! but an expression was expected of type! 'b node_t!
THIS SAYS INSERT Lazy.force!
![Page 68: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/68.jpg)
Error: This expression has type! 'a node_t! but an expression was expected of type!! ! !int node_t lazy_t!
![Page 69: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/69.jpg)
Error: This expression has type! 'a node_t! but an expression was expected of type!! ! !int node_t lazy_t!
THIS SAYS INSERT�lazy!
![Page 70: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/70.jpg)
TYPE CHECKER�OUTPUT�
Output is in the form of a typed tree�
![Page 71: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/71.jpg)
TECHNICAL CHALLENGES�
![Page 72: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/72.jpg)
UNFAMILIARITY�WITH LANGUAGE�
Lots of mucking around�
![Page 73: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/73.jpg)
OPEN RECURSION�A feature in most OO languages�
![Page 74: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/74.jpg)
let insert_lazy_at loc = object inherit Ast.map as super method expr e = match super#expr e with | <:expr@_loc< $e1$ $e2$ >> when _loc = loc -‐> <:expr< lazy ($e1$ $e2$) >> | <:expr@_loc< $id:i$ >> when _loc = loc -‐> <:expr< lazy $id:i$ >> | e -‐> e end
![Page 75: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/75.jpg)
LACK OF DOCUMENTATION�
Lots of code reading�
![Page 76: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/76.jpg)
ASKING QUESTIONS ON IRC�
![Page 77: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/77.jpg)
SEARCHING AND READING COMPILER SOURCE CODE�
![Page 78: FYP Final Presentation](https://reader030.vdocuments.mx/reader030/viewer/2022032615/55a2c83a1a28aba95d8b45e0/html5/thumbnails/78.jpg)
QUESTIONS?�