Bandera: Extracting Finite-state Models from Java Source Code James Corbett Matthew Dwyer John Hatcliff Shawn Laubach Corina Pasareanu Robby Hongjun Zheng.

Slides:



Advertisements
Similar presentations
Abstraction of Source Code (from Bandera lectures and talks)
Advertisements

Abstraction and Modular Reasoning for the Verification of Software Corina Pasareanu NASA Ames Research Center.
1 1 Regression Verification for Multi-Threaded Programs Sagar Chaki, SEI-Pittsburgh Arie Gurfinkel, SEI-Pittsburgh Ofer Strichman, Technion-Haifa Originally.
1 Symbolic Execution for Model Checking and Testing Corina Păsăreanu (Kestrel) Joint work with Sarfraz Khurshid (MIT) and Willem Visser (RIACS)
Carnegie Mellon University Java PathFinder and Model Checking of Programs Guillaume Brat, Dimitra Giannakopoulou, Klaus Havelund, Mike Lowry, Phil Oh,
1/1/ / faculty of Electrical Engineering eindhoven university of technology Introduction Part 3: Input/output and co-processors dr.ir. A.C. Verschueren.
1 Spin Model Checker Samaneh Navabpour Electrical and Computer Engineering Department University of Waterloo SE-464 Summer 2011.
Bandera: Extracting Finite-state Models from Java Source Code James C. Corbett (Hawai’i) Matthew B. Dwyer, John Hatcliff, Shawn Laubach, Corina S. Păsăreanu,
Software Model Checking for Embedded Systems PIs: Matthew Dwyer 1, John Hatcliff 1, and George Avrunin 2 Post-docs: Steven Seigel 2, Radu Iosif 1 Students:
Automated creation of verification models for C-programs Yury Yusupov Saint-Petersburg State Polytechnic University The Second Spring Young Researchers.
1 Carnegie Mellon UniversitySPINFlavio Lerda SPIN An explicit state model checker.
What Went Wrong? Alex Groce Carnegie Mellon University Willem Visser NASA Ames Research Center.
Houdini: An Annotation Assistant for ESC/Java Cormac Flanagan and K. Rustan M. Leino Compaq Systems Research Center.
Toward Dependable Software: Cyberinfrastructure Support for Controlled Experimentation with Testing and Analysis Techniques Gregg Rothermel and Matt Dwyer.
Synthesis of Interface Specifications for Java Classes Rajeev Alur University of Pennsylvania Joint work with P. Cerny, G. Gupta, P. Madhusudan, W. Nam,
Bandera Tool Set Presented by: Dor Nir. Outline Specification Language (LTL) Software verification problems Introduction to Bandera tool Set Bandera Specification.
Formal Verification of SpecC Programs using Predicate Abstraction Himanshu Jain Daniel Kroening Edmund Clarke Carnegie Mellon University.
© 2008 IBM Corporation Behavioral Models for Software Development Andrei Kirshin, Dolev Dotan, Alan Hartman January 2008.
Abstraction and Modular Reasoning for the Verification of Software Corina Pasareanu, October, 2001 Thesis Committee: Matthew Dwyer, Major Advisor David.
272: Software Engineering Fall 2012 Instructor: Tevfik Bultan Lecture 4: SMT-based Bounded Model Checking of Concurrent Software.
A Portable Virtual Machine for Program Debugging and Directing Camil Demetrescu University of Rome “La Sapienza” Irene Finocchi University of Rome “Tor.
C++ Code Analysis: an Open Architecture for the Verification of Coding Rules Paolo Tonella ITC-irst, Centro per la Ricerca Scientifica e Tecnologica
Using Model-Checking to Debug Device Firmware Sanjeev Kumar Microprocessor Research Labs, Intel Kai Li Princeton University.
Chapter 1 Introduction Dr. Frank Lee. 1.1 Why Study Compiler? To write more efficient code in a high-level language To provide solid foundation in parsing.
Lifecycle Verification of the NASA Ames K9 Rover Executive Dimitra Giannakopoulou Mike Lowry Corina Păsăreanu Rich Washington.
1 Module Objective & Outline Module Objective: After completing this Module, you will be able to, appreciate java as a programming language, write java.
Software Engineering Research paper presentation Ali Ahmad Formal Approaches to Software Testing Hierarchal GUI Test Case Generation Using Automated Planning.
Joseph Cordina 1/11 The Use of Model-Checking for the Verification of Concurrent Algorithms Joseph Cordina Department of C.S.&A.I.
Finding Feasible Counter-examples when Model Checking Abstracted Java Programs Corina S. Pasareanu, Matthew B. Dwyer (Kansas State University) and Willem.
1 Program Slicing Amir Saeidi PhD Student UTRECHT UNIVERSITY.
Copyright 2001, Matt Dwyer, John Hatcliff, and Radu Iosif. The syllabus and all lectures for this course are copyrighted materials and may not be used.
Model construction and verification for dynamic programming languages Radu Iosif
An extensible and highly-modular model checking framework SAnToS Laboratory, Kansas State University, USA Matt Dwyer.
1 Qualitative Reasoning of Distributed Object Design Nima Kaveh & Wolfgang Emmerich Software Systems Engineering Dept. Computer Science University College.
CIS 842: Specification and Verification of Reactive Systems Lecture 1: Course Overview Copyright 2001, Matt Dwyer, John Hatcliff, and Radu Iosif. The.
Software Model-checking: The SAnToS/Bandera Perspective Matt Dwyer John Hatcliff Principal Investigators Support US National.
Semantics In Text: Chapter 3.
1 Compiler Design (40-414)  Main Text Book: Compilers: Principles, Techniques & Tools, 2 nd ed., Aho, Lam, Sethi, and Ullman, 2007  Evaluation:  Midterm.
1 CSEP590 – Model Checking and Automated Verification Lecture outline for August 6, 2003.
Bandera: Extracting Finite-state Models from Java Source Code. Paper By: James C. Corbett, Mathew Dwyer, John Hatcliff, Shawn Laubach, Corina Pasareanu,
Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University IWPSE 2003 Program.
1 Software Model Checking Guillaume Brat, Dimitra Giannakopoulou, Klaus Havelund, Mike Lowry, Phil Oh, Corina Pasareanu, Charles Pecheur, John Penix, Willem.
CSCI1600: Embedded and Real Time Software Lecture 11: Modeling IV: Concurrency Steven Reiss, Fall 2015.
Tool-supported Program Abstraction for Finite-state Verification Matthew Dwyer 1, John Hatcliff 1, Corina Pasareanu 1, Robby 1, Roby Joehanes 1, Shawn.
Model-checking Concurrent Java Software Using the Bandera Tool Set Matthew Dwyer John Hatcliff Radu Iosif Yu Chen Georg Jung Todd Wallentine FacultyStudents.
Using Symbolic PathFinder at NASA Corina Pãsãreanu Carnegie Mellon/NASA Ames.
Lecture 4 Introduction to Promela. Promela and Spin Promela - process meta language G. Holzmann, Bell Labs (Lucent) C-like language + concurrency dyamic.
USING MODEL CHECKING TO DISCOVER AUTOMATION SURPRISES Java class User: - getExpectation() - checkExpectation() FAULTY EXECUTION start incrMCPAlt pullAltKnob.
Grigore Rosu Founder, President and CEO Professor of Computer Science, University of Illinois
Static Techniques for V&V. Hierarchy of V&V techniques Static Analysis V&V Dynamic Techniques Model Checking Simulation Symbolic Execution Testing Informal.
Software Systems Verification and Validation Laboratory Assignment 4 Model checking Assignment date: Lab 4 Delivery date: Lab 4, 5.
Tool-supported Program Abstraction for Finite-state Verification Matthew Dwyer 1, John Hatcliff 1, Corina Pasareanu 1, Robby 1, Roby Joehanes 1, Shawn.
Chapter – 8 Software Tools.
Model-checking Concurrent Java Software Using the Bandera Tool Set Matthew Dwyer John Hatcliff Radu Iosif Hongjun Zheng Shawn Laubach Corina Pasareanu.
Agenda  Quick Review  Finish Introduction  Java Threads.
24 September 2002© Willem Visser Program Model Checking Enabling Technology Abstraction void add(Object o) { buffer[head] = o; head = (head+1)%size;
The Bandera Model Reduction Tools James Corbett Matthew Dwyer John Hatcliff Shawn Laubach Corina Pasareanu Robby Hongjun Zheng Faculty Students and Post-docs.
Sung-Dong Kim, Dept. of Computer Engineering, Hansung University Java - Introduction.
Chapter 1 Introduction.
Authors :John Hatcliff and Mattew Dwyer presented by Slava Yablonovich
Abstraction of Source Code
Bandera: Extracting Finite-state Models from Java Code
Chapter 1 Introduction.
runtime verification Brief Overview Grigore Rosu
Model Checking for an Executable Subset of UML
Automatic Derivation, Integration and Verification
An explicit state model checker
The Bogor Model Checking Framework
Rich Model Toolkit – An Infrastructure for Reliable Computer Systems
Presentation transcript:

Bandera: Extracting Finite-state Models from Java Source Code James Corbett Matthew Dwyer John Hatcliff Shawn Laubach Corina Pasareanu Robby Hongjun Zheng Faculty Students and Post-docs Roby Joehanes Ritesh Desai Venkatesh Ranganath Oksana Tkachuk

Goal: Increase Software Reliability Trends: Size, complexity, concurrency, distributed Cost of software engineer………………………. Cost of CPU cycle……………………………….. Future: Automated Fault Detection

The Dream Program Requirement Checker OK Error trace or void add(Object o) { buffer[head] = o; head = (head+1)%size; } Object take() { … tail=(tail+1)%size; return buffer[tail]; } Property 1: … Property 2: … …

Model Checking OK Error trace or Finite-state model Temporal logic formula Model Checker  Line 5: … Line 12: … Line 15:… Line 21:… Line 25:… Line 27:… … Line 41:… Line 47:…

Why use Model Checking? In contrast to testing, gives complete coverage by exhaustively exploring all paths in system, It’s been used for years with good success in hardware and protocol design Automatically check, e.g., –invariants, simple safety & liveness properties –absence of dead-lock and live-lock, –complex event sequencing properties, “Between the window open and the window close, button X can be pushed at most twice.” This suggests that model-checking can complement existing software quality assurance techniques.

What makes model-checking software difficult? Model construction OK Error trace or Finite-state model Temporal logic formula Model Checker  State explosion Problems using existing checkers: Property specification Output interpretation Line 5: … Line 12: … Line 15:… Line 21:…

Model Construction Problem Semantic gap: Model Description Model Checker Program void add(Object o) { buffer[head] = o; head = (head+1)%size; } Object take() { … tail=(tail+1)%size; return buffer[tail]; } Gap Programming Languages Model Description Languages methods, inheritance, dynamic creation, exceptions, etc. automata

What makes model-checking software difficult? Model construction OK Error trace or Finite-state model Temporal logic formula Model Checker  State explosion Problems using existing checkers: Property specification Output interpretation Line 5: … Line 12: … Line 15:… Line 21:…

Property Specification Problem Difficult to formalize a requirement in temporal logic “Between the window open and the window close, button X can be pushed at most twice.” []((open /\ <>close) -> ((!pushX /\ !close) U (close \/ ((pushX /\ !close) U (close \/ ((!pushX /\ !close) U (close \/ ((pushX /\ !close) U (close \/ (!pushX U close)))))))))) …is rendered in LTL as...

Property Specification Problem We want to write source level specifications... (((_collect(heap_b) == 1)\ && (BoundedBuffer_col.instance[_index(heap _b)].head == BoundedBuffer_col.instance[_index(heap _b)].tail) )\ || ((_collect(heap _b) == 3)\ && (BoundedBuffer_col_0.instance[_index(heap _b)].head == BoundedBuffer_col_0.instance[_index(heap _b)].tail) )\ || ((_collect(heap _b) == 0) && TRAP)) Heap.b.head == Heap.b.tail We are forced to write model level specifications... Forced to state property in terms of model rather than source:

What makes model-checking software difficult? Model construction OK Error trace or Finite-state model Temporal logic formula Model Checker  State explosion Problems using existing checkers: Property specification Output interpretation Line 5: … Line 12: … Line 15:… Line 21:…

State Explosion Problem Moore’s law and algorithm advances can help –Holzmann: 7 days (1980) ==> 7 seconds (2000) Explosive state growth in software limits scalability Bit x1,…,xN2^N states Cost is exponential in the number of components

What makes model-checking software difficult? Model construction OK Error trace or Finite-state model Temporal logic formula Model Checker  State explosion Problems using existing checkers: Property specification Output interpretation Line 5: … Line 12: … Line 15:… Line 21:…

Output Interpretation Problem Raw error trace may be 1000’s of steps long Model Description Program void add(Object o) { buffer[head] = o; head = (head+1)%size; } Object take() { … tail=(tail+1)%size; return buffer[tail]; } Gap Error trace Line 5: … Line 12: … Line 15:… Line 21:… Line 25:… Line 27:… … Line 41:… Line 47:… Must map line listing onto model description Mapping to source is made difficult by –Semantic gap & clever encodings of complex features –multiple optimizations and transformations

Bandera: An open tool set for model-checking Java source code Checker Inputs Checker Outputs Optimization Control Transformation & Abstraction Tools Model Checkers Java Source void add(Object o) { buffer[head] = o; head = (head+1)%size; } Object take() { … tail=(tail+1)%size; return buffer[tail]; } Bandera Temporal Specification Graphical User Interface Error Trace Mapping Bandera

Addressing the Model Construction Problem Numerous analyses, optimizations, two intermediate languages, multiple back-ends Slicing, abstract interpretation, specialization Variety of usage modes: simple...highly tuned Model extraction: compiling to model checker inputs: Java Source void add(Object o) { buffer[head] = o; head = (head+1)%size; } Object take() { … tail=(tail+1)%size; return buffer[tail]; } Model DescriptionModel Compiler Static Analyses Abstract Interpretation Slicing Optimizations

Addressing the Property Specification Problem An extensible language based on field-tested temporal property specification patterns []((open /\ <>close) -> ((!pushX /\ !close) U (close \/ ((pushX /\ !close) U (close \/ ((!pushX /\ !close) U (close \/ ((pushX /\ !close) U (close \/ (!pushX U close)))))))))) Using the pattern system: 2-bounded existence Between {open} and {close} {pushX} exists atMost {2} times;

Addressing the State Explosion Problem Aggressive customization via slicing, abstract interpretation, program specialization Java Source void add(Object o) { buffer[head] = o; head = (head+1)%size; } … Model DescriptionsModel Compiler Property Generate models customized wrt property! Result: multiple models --- even as many as one per property

Addressing the Output Interpretation Problem Run error traces forwards and backwards Program state queried Heap structures navigated Locks, wait sets, blocked sets displayed Like a debugger: error traces mapped back to source Java Source void add(Object o) { buffer[head] = o; head = (head+1)%size; } Object take() { … tail=(tail+1)%size; return buffer[tail]; } Model Compiler Model Checker Intermediate Representations Error trace Line 5: … Line 12: … Line 15:… Line 21:… Model Description + simulator

Bandera Architecture BIRC BIR Simulator Abstraction Engine Slicer Analyses Translators SPIN dSPIN SMV JPF Property Tool Java Jimple Parser Error Trace Display

Property Specification /** * observable * EXP Full: (head == tail); */ class BoundedBuffer { Object [] buffer; int head, tail, bound; public synchronized void add(Object o) {…} public synchronized Object take () {…} } Requirement: If a buffer becomes full, it will eventually become non-full. Bandera Specification: FullToNonFull: forall[b:BoundedBuffer]. {!Full(b)} responds to {Full(b)} globally;

Property Specification

Property-directed Slicing slicing criterion generated automatically from observables mentioned in the property backwards slicing automatically finds all components that might influence the observables. Source program Resulting slice Slice mentioned in property indirectly relevant

Property-directed Slicing /** EXP Full: (head == tail) */ class BoundedBuffer { Object [] buffer_; int bound; int head, tail; public synchronized void add(Object o) { while ( tail == head ) try { wait(); } catch ( InterruptedException ex) {} buffer_[head] = o; head = (head+1) % bound; notifyAll(); }... } Included in slicing critirion Slicing Criterion All statements that assign to head, tail. indirectly relevant removed by slicing

Property-directed Slicing Thread 1Thread 2 Data Dependence x := 3; y = x + 1; Control Dependence z<0 Interference Dependence x := z; z := 4; Synchronization Dependence enter monitor(o) Ready Dependence notify(o) wait(o) [SAS’99] Dependencies for concurrent Java

Abstraction Engine int x = 0; if (x == 0) x = x + 1; Data domains (n<0) : neg (n==0): zero (n>0) : pos Signs negposzero int Code Signs x = zero; if (x == zero) x = pos; Collapses data domains via abstract interpretation:

Abstraction Component Functionality Variable Concrete Type Abstract Type Inferred Type Abstraction Library Bandera Abstraction Specification Language BASL Compiler PVS Jimple Abstraction Engine Abstracted Jimple x y done count o b int bool Object Buffer int …. Signs intAbs Bool …. Point Buffer

Abstraction Specification abstraction Signs abstracts int begin TOKENS = { NEG, ZERO, POS }; abstract(n) begin n {NEG}; n == 0 -> {ZERO}; n > 0 -> {POS}; end operator + add begin (NEG, NEG) -> {NEG} ; (NEG, ZERO) -> {NEG} ; (ZERO, NEG) -> {NEG} ; (ZERO, ZERO) -> {ZERO} ; (ZERO, POS) -> {POS} ; (POS, ZERO) -> {POS} ; (POS, POS) -> {POS} ; (_,_)-> {NEG, ZERO, POS}; /* case (POS,NEG), (NEG,POS) */ end public class Signs { public static final int NEG = 0; // mask 1 public static final int ZERO = 1; // mask 2 public static final int POS = 2; // mask 4 public static int abstract(int n) { if (n < 0) return NEG; if (n == 0) return ZERO; if (n > 0) return POS; } public static int add(int arg1, int arg2) { if (arg1==NEG && arg2==NEG) return NEG; if (arg1==NEG && arg2==ZERO) return NEG; if (arg1==ZERO && arg2==NEG) return NEG; if (arg1==ZERO && arg2==ZERO) return ZERO; if (arg1==ZERO && arg2==POS) return POS; if (arg1==POS && arg2==ZERO) return POS; if (arg1==POS && arg2==POS) return POS; return Bandera.choose(7); /* case (POS,NEG), (NEG,POS) */ } Compiled

Specification Creation Tools abstraction Signs abstracts int begin TOKENS = { NEG, ZERO, POS }; abstract(n) begin n {NEG}; n == 0 -> {ZERO}; n > 0 -> {POS}; end operator + add begin (NEG, NEG) -> {NEG} ; (NEG, ZERO) -> {NEG} ; (ZERO, NEG) -> {NEG} ; (ZERO, ZERO) -> {ZERO} ; (ZERO, POS) -> {POS} ; (POS, ZERO) -> {POS} ; (POS, POS) -> {POS} ; (_,_)-> {NEG, ZERO, POS}; end Automatic Generation Forall n1,n2: neg?(n1) and neg?(n2) implies not pos?(n1+n2) Forall n1,n2: neg?(n1) and neg?(n2) implies not zero?(n1+n2) Forall n1,n2: neg?(n1) and neg?(n2) implies not neg?(n1+n2) Proof obligations submitted to PVS... Example: Start safe, then refine: +(NEG,NEG)={NEG,ZERO,POS}

Abstraction Library Current Library Contains : Range(i,j) : i..j modeled precisely, e.g., –Range(0,0) is the signs abstraction –Range(2,4) has tokens {lt2,2,3,4,gt4} Modulo(k), e.g., –Modulo(2) is the even-odd abstraction Specific(v,…) : identifies values of interest, e.g., –Specific(10) has tokens {eq10,not10} User extendable for base type predicates

Back End Bandera Intermediate Representation (BIR) –guarded command language –includes: locks, threads, references, heap –info to help translators (live vars, invisible) entermonitor r0 r1.count = 0; … loc s5: live { r0, r1 } when lockAvail(r0.lock) do { lock(r0.lock); } goto s6; loc s6: live { r1 } when true do invisible { r1.count = 0;} goto s7; Jimple BIR

Bounded Buffer BIR process BoundedB() BoundedBuffer_ref = ref { BoundedBuffer_col, BoundedBuffer_col_0 }; BoundedBuffer_rec = record { bound_ : range -1..4; head_ : range -1..4; tail_ : range -1..4; BIRLock : lock wait reentrant; }; BoundedBuffer_col : collection [3] of BoundedBuffer_rec; BoundedBuffer_col_0 : collection [3] of BoundedBuffer_rec; ……. ………. loc s34: live { b2, b1, add_JJJCTEMP_0, add_JJJCTEMP_6, add_JJJCTEMP_8 } when true do invisible { add_JJJCTEMP_8 := (add_JJJCTEMP_6 % add_JJJCTEMP_8); } goto s35; loc s35: live { b2, b1, add_JJJCTEMP_0, add_JJJCTEMP_8 } when true do { add_JJJCTEMP_0.head_ := add_JJJCTEMP_8; } goto s36; loc s36: live { b2, b1, add_JJJCTEMP_0 } when true do { notifyAll(add_JJJCTEMP_0.BIRLock); } goto s37; loc s37: live { b2, b1, add_JJJCTEMP_0 } when true do { unlock(add_JJJCTEMP_0.BIRLock); } goto s38;

Bounded Buffer Promela typedef BoundedBuffer_rec { type_8 bound_; type_8 head_; type_8 tail_; type_18 BIRLock; } … loc_25: atomic { printf("BIR: OK\n"); if :: (_collect(add_JJJCTEMP_0) == 1) -> add_JJJCTEMP_8 = BoundedBuffer_col. instance[_index(add_JJJCTEMP_0)].tail_; :: (_collect(add_JJJCTEMP_0) == 2) -> add_JJJCTEMP_8 = BoundedBuffer_col_0. instance[_index(add_JJJCTEMP_0)].tail_; :: else -> printf("BIR: NullPointerException\n"); assert(0); fi; goto loc_26; }

Translators Plug-in component that interfaces to specific model checker –Translates BIR to checker input language –Parses output of checker for error trace Currently –SPIN, dSPIN, SMV translators complete –JPF (from NASA Ames) integrated –XMC, FDR translators in progress

Case Studies Small examples thus far (< 2000 loc) –illustrating use of property-pattern system and other components Scheduler from DEOS real-time OS kernel –(1600, 22 classes, seven tasks) Now trying systems up to 20,000 loc –collection of 15 open-source 100% pure Java –Jigsaw web-server from W3C –Tomcat, James (from Apache/Jakarta) In general, 1-2 minutes for model extraction on (~2000k systems) State space reductions can dramatically reduce cost

Summary Bandera provides an open platform for experimentation Separates model checking from extraction –uses existing model checkers –supports multiple model checkers Specialize models for specific properties using automated support for slicing, abstraction, etc. Designed for extensibility –well-defined internal representations and interfaces We hope this will contribute to the definition of APIs for software model-checkers

Other Work on Software Model-checking Java –JPF (NASA Ames) –JCAT (Torino) –Java to SAL (Stanford) C –SLAM (Microsoft Research) –AX, FeaVer (Lucent)

Current Status A reasonable subset of concurrent Java –not handled: recursive methods, exceptions, inner classes, native methods, libraries(*) Public release: October 2000 Demo tomorrow morning

Ongoing Work Property specification –Define state predicates –Quantify over class instances More sophisticated abstractions Translators to more model checkers

Design Goals Separate model checking from extraction –Use existing model checkers –Support multiple model checkers Provide automated support for abstraction –Slicing –Abstract interpretation –Specialization Specialize models for specific properties Design for extensibility –Well-defined internal representations and interfaces

Lack of Integration Problem Existing Quality Assurance techniques and tools: Testing Debugging Simulation Run-time monitoring Visualization Monitoring drives checker path selection Model checking tools and artifacts should be integrated: Error traces drive test case generation Debugging/Visualization of error traces Closing environments test harnesses Static Analysis

Bandera Toolset Model Checkers Property Source code Checker Inputs Checker Outputs Source trace Bandera

What makes model-checking software difficult? Model construction OK Error trace or Finite-state model Temporal logic formula Model Checker  State Explosion Problems using existing checkers: Property specification Output Interpretation

Goal: Increase Software Reliability Trends: Software Size Concurrency Complexity Cost of Engineer Cost of CPU cycle Future: Automated Fault Detection

Front End Translates Java source to Jimple IR Supports specification of property Provides debugger-like step facilities for error traces if (x > 0) x = y * 2; Label1: if (x <= 0) goto Label2; t0 = y * 2; x = t0; Label2: … Java Jimple

Model Checking OK Error trace or Finite-state model Temporal logic formula Model Checker  Line 5: … Line 12: … Line 15:… Line 21:… Line 25:… Line 27:… … Line 41:… Line 47:…