JML: Expressive, Modular Reasoning for Java

About This Presentation
Title:

JML: Expressive, Modular Reasoning for Java

Description:

JML: Expressive, Modular Reasoning. for Java. Gary T. Leavens. Iowa State University ... Tortoise. invariant 0 = age && age = 150; FemalePatient. Initially ... – PowerPoint PPT presentation

Number of Views:88
Avg rating:3.0/5.0
Slides: 76
Provided by: Gary220
Learn more at: https://www.cs.ucf.edu

less

Transcript and Presenter's Notes

Title: JML: Expressive, Modular Reasoning for Java


1
JML Expressive, Modular Reasoning for Java
  • Gary T. LeavensIowa State University Support
    from US National Science FoundationStanford
    University, March 5, 2007

jmlspecs.org
www.cs.iastate.edu/leavens
2
Java Modeling LanguageJML
  • Formal specification language for Java
  • Functional behavior
  • Sequential
  • Goals
  • Practical, effective for detailed designs
  • Existing code
  • Wide range of tools
  • Hoare-style
  • Method pre- and postconditions
  • Type invariants

3
Example JML Specification
  • public class Animal implements Gendered
    protected /_at_ spec_public _at_/ int age 0
  • /_at_ requires 0 lt yrs _at_ ensures age
    \old(age yrs) _at_/public void older(final
    int yrs) age age yrs
  • / /

4
Behavioral Interface Specification
JML Specification
Syntactic Interface
Functional Behavior
Java Code
5
Behavioral Interface Specification
/_at_ requires 0 lt yrs _at_ ensures age
\old(age yrs) _at_/public void older(final
int yrs)
requires yrs gt 0ensures age \old(age) yrs
public void older(final int yrs)
public void older(final int yrs) age age
yrs
6
Like But for Java and
  • VDM, but
  • OO features
  • Eiffel, but
  • Features for formal verification
  • Spec, but
  • Different invariant methodology
  • More features for formal verification

7
Research Community
  • 23 groups, worldwide
  • Open
  • Join us
  • Over 125 papers
  • See jmlspecs.org for details

8
Many tools, One Language
Warnings
JML Annotated Java
ESC/Java2
public class Animal implements Gendered //
... protected /_at_ spec_public _at_/ int age 0
/_at_ requires 0 lt a a lt 150 _at_
ensures age a _at_ also _at_ requires
a lt 0 _at_ ensures age \old(age)
_at_/ public void setAge(final int a) if
(0 lt a) age a
jmldoc
Web pages
Daikon
jmlunit
Data trace file
Unit tests
jmlc
JACK, Jive, Krakatoa, KeY, LOOP
Bogor
Class file
Correctness proof
Model checking
XVP
9
Problems for this Talk
  • Modular Specification, Verification
  • Recording detailed designs
  • Specifying subtypes
  • Verification with OO features

10
Problem 1Recording Detailed Designs
  • Precise, sequential behavior
  • Hide details
  • Approach
  • Model fields
  • Assertions

11
Model Fields, Ensures
  • public interface Gendered
  • //_at_ model instance String gender//_at_ ensures
    \result gender.equals(female)/_at_ pure _at_/
    boolean isFemale()

12
Represents Clauses
  • public class Animal implements Gendered
  • protected boolean gen //_at_ in gender
  • /_at_ protected represents gender _at_
    lt- (gen ? female male) _at_/
  • // ...

13
Use of Model Fields
  • public class Animal implements Gendered
  • protected boolean gen //_at_ in gender
  • /_at_ protected represents gender _at_
    lt- (gen ? female male) _at_/
  • public /_at_ pure _at_/ boolean isFemale() return
    gen
  • // ...

14
Correctness with Model Fields
isFemalesspecification
female
gender
true
represents

isFemalescode
gen
true
true
15
Requires Clauses
  • public class Animal implements Gendered
  • protected boolean gen //_at_ in gender
  • /_at_ protected represents gender _at_
    lt- (gen ? female male) _at_/
  • //_at_ requires g.equals(female)g.equals(male)
    //_at_ ensures gender.equals(g)public
    Animal(final String g) gen
    g.equals(female)

16
Data Groups and Assignable
  • Problem
  • Hide field names
  • Subtypes add fields
  • Data group
  • Membership by in clauses
  • Contains fields used in represents

17
Pure Methods
  • public /_at_ pure _at_/ boolean isFemale() //
  • Can use in assertions
  • Must satisfy
  • assignable \nothing
  • May not
  • Assign existing (non-local) locations
  • Perform input/output

18
Assignable is a Shorthand
  • assignable genderensures gender.equals(g)
  • means
  • ensures \only_assigned(gender)
    gender.equals(g)

19
Model of Method Specifications
  • public interface T //_at_ requires pre //_at_
    ensures post void m()
  • T ? (pre, post)

20
Model of Method Specifications
output
post-state
input pre-state
21
spec_public Shorthand
  • Instead of
  • //_at_ public model int age protected int
    _age 0 //_at_ in age //_at_ protected represents
    age lt- _age
  • Write
  • protected /_at_ spec_public _at_/ int age 0

22
Specification Cases, also
  • public class Animal implements Gendered
    protected /_at_ spec_public _at_/ int age 0
  • /_at_ requires 0 lt a a lt 150 _at_ ensures
    age a _at_ also _at_ requires a lt 0 _at_
    ensures age \old(age) _at_/public void
    setAge(final int a) if (0 lt a) age a

23
Join of Specification Cases
  • requires 0 lt a a lt 150 ensures age
    a also requires a lt 0 ensures age
    \old(age)
  • means
  • requires (0 lt a a lt 150) a lt 0
    ensures (\old(0 lt a a lt 150) gt age a)
    (\old(a lt 0) gt age \old(age))

24
Join of Specification Cases
post post'
post
pre'
pre
pre pre'
25
Join of Specification Cases, ?S
  • If T' ? (pre', post' ), T ? (pre, post ), S T',
    S T,
  • then
  • (pre', post' ) ?S (pre, post ) (p, q)
  • where p pre' preand q (\old(pre' ) gt
    post' ) (\old(pre) gt post )and
    S ? (p, q)

26
Type SpecificationsInvariants
  • import java.util.
  • public class Patient extends Animal
  • //_at_ public invariant 0 lt age age lt 150
  • protected /_at_ spec_public _at_/ List log
  • /_at_ public invariant (\forall int i _at_
    0 lt i i lt log.size() _at_
    log.get(i) instanceof String)
    _at_/
  • //

27
Invariants
  • Hold in visible states
  • Method pre- post-, Constructor post-states
  • Obeyed by subtypes

28
Invariants Obeyed by Subtypes
Not a Sugar LW94
Animal
Patient
Tortoise
invariant 0 lt age age lt 150
FemalePatient
29
Initially
  • public class Patient extends Animal // ...
  • protected /_at_ spec_public _at_/ List log
  • //_at_ public initially log.size() 0
  • True in constructor post-states
  • Basis for datatype induction
  • Not a sugar

30
History Constraints LW94
  • public class Patient extends Animal // ...
  • /_at_ public constraint _at_ \old(log.size()) lt
    log.size()
  • _at_ public constraint _at_ (\forall int i
    _at_ 0 lt i i lt \old(log.size())
    _at_ log.get(i).equals(\old(log.get(i))))
  • _at_/

31
History Constraints
  • Relate pre-states and post-states
  • Inductive step for datatype induction
  • Not a sugar

32
Problem 2 Specifying Subtypes
  • Avoid repetition
  • (Force behavioral subtyping)
  • Approach
  • Specification Inheritance
  • Fields, type specifications
  • Method specification cases

33
Ts Added Specifications
  • Declared in T (without inheritance)
  • added_invT invariant
  • added_hcT history constraint
  • added_initT initially predicate
  • ms specification
  • Other Notations
  • supers(T ) U T ? U
  • methods(T ) m m declared in T?T

34
Specification Inheritances MeaningExtended
Specification of T
  • Methods for all m ? methods(supers(T))
  • ?T
    U?supers(T)
  • Invariant
  • ext_invT ? added_invU U?supers(T)
  • History constraint
  • ext_hcT ? added_hcU U?supers(T)
  • Initially
  • ext_initT ? added_initU U?supers(T)

35
Invariant Inheritance
  • public class FemalePatient extends Patient
  • //_at_ public invariant gender.equals(female)//
  • Extended invariant
  • added_invGendered added_invAnimal
  • added_invPatient
  • added_invFemalePatient

36
Invariant Inheritance
  • public class FemalePatient extends Patient
  • //_at_ public invariant gender.equals(female)//
  • Extended invariant
  • true true
  • 0 lt age age lt 150 (\forall int
    i 0 lt i i lt log.size()
  • log.get(i) instanceof
    String)
  • gender.equals(female)

37
Invariant Inheritance
  • public class FemalePatient extends Patient
  • //_at_ public invariant gender.equals(female)//
  • Extended invariant
  • 0 lt age age lt 150 (\forall int
    i 0 lt i i lt log.size()
  • log.get(i) instanceof
    String)
  • gender.equals(female)

38
Method Specification InheritanceSupertypes
added_spec
  • public class Animal implements Gendered //
  • /_at_ requires 0 lt a a lt 150 _at_ ensures
    age a _at_ also _at_ requires a lt 0 _at_
    ensures age \old(age) _at_/public void
    setAge(final int a) / /

39
Method Specification InheritanceSubtypes
added_spec
  • public class Patient extends Animal //
  • protected /_at_ spec_public _at_/ boolean
    ageDiscount false //_at_ in age/_at_ also _at_
    requires 0 lt a a lt 150 a lt 0 _at_
    ensures 65 lt age gt ageDiscount _at_/public
    void setAge(final int a) super.setAge(a) if
    (65 lt age) ageDiscount true

40
Method Specification InheritanceExtended
Specification
  • ?Patient
    ,


41
Method Specification InheritanceExtended
Specification
  • requires 0 lt a a lt 150 ensures age
    a also requires a lt 0 ensures age
    \old(age)also requires 0 lt a a lt 150
    a lt 0 ensures 65 lt age gt ageDiscount

42
Use of \same
  • requires 0 lt a a lt 150 ensures age
    a also requires a lt 0 ensures age
    \old(age)also requires \same ensures 65
    lt age gt ageDiscount

43
Meaning of \same
  • requires 0 lt a a lt 150 ensures age
    a also requires a lt 0 ensures age
    \old(age)also requires 0 lt a a lt 150
    a lt 0 ensures 65 lt age gt ageDiscount

44
Problem 3 Verification with OO features
  • Subtyping
  • Dynamic Dispatch
  • Approach LN06
  • Supertype abstraction
  • Validity
  • Assumptions about Invariants, etc.,
  • Behavioral subtyping
  • Behavioral subtypingfrom specification
    inheritance

45
Supertype Abstraction
  • Reasoning about dynamic dispatch
  • Gendered e (Gendered)elems.next()if
    (e.isFemale()) //_at_ assert e.gender.equals(fema
    le) // ...
  • Supertype abstraction
  • Static type of e is Gendered
  • Use specification from Gendered

46
Static Types Specification
  • public interface Gendered
  • //_at_ model instance String gender//_at_ ensures
    \result gender.equals(female)/_at_ pure _at_/
    boolean isFemale()

47
Supertype Abstraction in General
  • Use static types specifications to reason about
  • Method calls,
  • Invariants,
  • History constraints,
  • Initially predicates

48
Supertype Abstraction in General
  • T o / create a new object /
  • //_at_ assume o.ext_initT o.ext_invT
  • / /
  • //_at_ assert o.m()//_at_ assume
    //_at_ assume o.ext_invT o.ext_hcT

49
Supertype Abstractionfor Initially Predicates
  • Givenpublic class Patient extends Animal //
    ... protected /_at_ spec_public _at_/ List log
    //_at_ public initially log.size() 0
  • Verify
  • Patient pif (B) p new Patient(male)
    else p new FemalePatient() //_at_ assert
    p.log.size() 0

50
Reasoning withoutSupertype Abstraction?
  • Case analysis
  • Case for each potential dynamic type
  • Can exploit dynamic types specifications

51
Case Analysis Supertype Abstraction
  • Use instanceof for case analysis
  • Downcast, use supertype abstraction
  • /_at_ requires p instanceof Doctor _at_
    p instanceof Nurse _at_/public boolean
    isHead(final Staff p) if (p instanceof Doctor)
    Doctor doc (Doctor) p return
    doc.getTitle().startsWith(Head) else
    Nurse nrs (Nurse) p return
    nrs.isChief()

52
Supertype Abstractions Soundness
  • Valid if
  • Invariants etc. hold as needed, and
  • Each subtype is a behavioral subtype

53
Assumption about Invariants
  • assert Pre
  • assume Pre Inv
  • assert Post Inv
  • assume Post

54
Invariant Methodology
  • Potential problems
  • Representation exposure
  • Reentrance
  • Relevant invariant semantics Mül02,MPHL06
  • Ownership type system
  • Re-establish invariant when call
  • Guarantees
  • invariant holds at start of method

55
Initially Predicates,History Constraints
  • Similar problems?
  • Similar solutions?

56
Behavioral Subtypes
  • Subtypes obey supertype specification
  • Subtypes
  • Refine method specifications
  • Strengthen invariants, etc.

57
Method Specification Refinement with respect to
T'
  • Notation
  • (pre', post' ) ?T' (pre, post )

58
Method Specification Refinement with respect to
T'
  • Definition Suppose T' T, andT' ? (pre',
    post' ), T ? (pre, post ) specify m
  • then
  • (pre', post' ) ?T' (pre, post )
  • if and only if
  • for all calls of m on a subtype of T' , every
    correct implementation of (pre', post' )
    satisfies (pre, post )

59
Refinement with respect to T'
post
pre
60
Refinement with respect to T'
post
pre'
pre
61
Refinement with respect to T'
post'
post
pre'
pre
62
Proving Method Refinements
  • Theorem 1. Suppose T' T, andT' ? (pre', post'
    ), T ? (pre, post ) specify m.
  • Then (pre', post' ) ?T' (pre, post )
  • if and only if
  • Spec(T' ) - pre (this instanceof T' ) ?
    pre',
  • and
  • Spec(T' ) - \old(pre (this instanceof T'
    )) ? (post' ? post ).

63
Refinement of Assignable Clauses
  • When T' T, andassignable L' in T'
    .massignable L in T.m
  • Can prove
  • Spec(T' ) - \old(pre (this instanceof T'
    )) ? (\only_assigned(L' ) ?
    (\only_assigned(L )).
  • Subtypes frame more restrictive.
  • Datagroups matter

64
Validity of Supertype AbstractionClient
(Supertype) view
  • T o / create a new object /
  • //_at_ assume o.ext_initT o.ext_invT
  • / /
  • //_at_ assert o.m()//_at_ assume
    //_at_ assume o.ext_invT o.ext_hcT

65
Validity of Supertype AbstractionImplementation
(Subtype) View
  • T o new T' ()
  • //_at_ assert o.ext_initT' o.ext_invT'
  • / /
  • //_at_ assume o.m()//_at_ assert
    //_at_ assert o.ext_invT' o.ext_hcT'

66
Behavioral Subtyping for JML
  • Definition. Suppose T' T. Then T' is a
    strong behavioral subtype of T if and only if
  • for all instance methods m in T, ?T'
  • whenever this has type T' ext_invT' ?
    ext_invT, ext_hcT' ? ext_hcT, and ext_initT'
    ? ext_initT.

67
Extended Specification of T
  • Methods for all m ? methods(supers(T))
  • ?T
    U?supers(T)
  • Invariant
  • ext_invT ? added_invU U?supers(T)
  • History constraint
  • ext_hcT ? added_hcU U?supers(T)
  • Initially
  • ext_initT ? added_initU U?supers(T)

68
Ensuring Validity
  • Method specification inheritancemust make
    refinements
  • also must make refinements

69
also Makes Refinements
  • Theorem 2. Suppose \old is monotonic.Suppose T'
    T, andT' ? (pre', post' ), T ? (pre, post )
    specify m.
  • Then
  • (pre', post' ) ?T' (pre, post ) ?T' (pre,
    post ).

70
Proof Using Theorem 1
  • Preconditionspre (this instanceof T' ) ?
    pre ? (pre pre)
  • PostconditionsAssume \old(pre (this
    instanceof T' )), hence \old(pre).
  • (\old(pre) gt post)) (\old(pre gt post)) ?
    \old(pre) gt post) ? post

71
also Makes Refinements
post post'
post
post'
pre'
pre
pre pre'
72
Specification Inheritance Forces Behavioral
Subtyping
  • Theorem 3. Suppose T' T . Thenthe extended
    specification of T' is a strong behavioral
    subtype ofthe extended specification of T.
  • Proof Use Theorem 2 and definition of extended
    specification.

73
Discussion
  • Every subtype inherits
  • Every subtype is a behavioral subtype
  • Not all satisfiable
  • Supertype must allow refinement

74
Unsatisfiable Refinements
post post'
post
post'
pre'
pre
pre pre'
75
Unrefinable Binary Method Specification
  • /_at_ also _at_ ensures obj instanceof
    Gendered _at_ gt (\result _at_
    gender.equals( _at_
    ((Gendered)obj).gender)) _at_/public /_at_
    pure _at_/ boolean equals(/_at_ nullable _at_/ Object
    obj)
  • Says only gender matters
  • Refinements cant use other attributes

76
Unrefinable Binary Method Specification
true
false
(f,f)
(m,m)
(f,m)
(m,f)
77
Better, Refinable Binary Method Specification
  • /_at_ also _at_ ensures obj instanceof
    Gendered _at_ gt (\result _at_
    gt gender.equals( _at_
    ((Gendered)obj).gender)) _at_/public /_at_
    pure _at_/ boolean equals(/_at_ nullable _at_/ Object
    obj)
  • Says gender must be equal
  • Refinements can use other attributes

78
Better, Refinable Binary Method Specification
true
false
Allowedresult
(f,f)
(m,m)
(f,m)
(m,f)
79
Extension Subtype Example
  • public abstract class Dog extends Animal public
    static final int D2PY 7private /_at_
    spec_public _at_/ int dogAge 0 //_at_ in age
  • //_at_ ensures \result dogAgepublic int
    getDogAge() return dogAge
  • public void setAge(final int a)
    super.setAge(a) dogAge D2PYage

80
Related Work
  • Work with Naumann LN06, basis for this
    talk.Proved exact conditions on behavioral
    subtyping for validity of supertype abstraction
  • Liskov and Wing LW94 subtype requirement
    like supertype abstraction.Abstraction
    functions implicit in JML.
  • Several program logics for Java,Mül02 Par05
    Pie06 PHM99,use supertype abstraction.
  • Work with Dhara DL96proved specification
    inheritanceforces behavioral subtyping.

81
More Related Work
  • Willss Fresco Wil92 introduced specification
    inheritance.
  • Wings dissertation Win83combined
    specification cases like also.
  • Eiffel Mey97 has behavioral subtypingand a
    form of specification inheritance.
  • America Ame87 Ame91 firstproved soundness
    with behavioral subtyping.
  • See survey with Dhara LD00.

82
Future Work
  • Warn if attempt to strengthen preconditions
    FF01.
  • Warn if subtype is unsatisfiable.
  • Methodology for
  • history constraints and
  • initially predicates

83
Conclusions
  • Supertype abstractionallows modular reasoning.
  • Supertype abstraction is valid if
  • methodology enforced, and
  • subtypes are behavioral subtypes.
  • JMLs also makes refinements.
  • Specification inheritance in JMLforces
    behavioral subtyping.
  • Supertype abstraction automatically valid in JML.

84
Acknowledgments
  • Thanks to David Naumann, William Weihl, Krishna
    Kishore Dhara, Cesare Tinelli, Don Pigiozzi,
    Barbara Liskov, Jeannette Wing, Yoonsik Cheon, Al
    Baker, Clyde Ruby, Tim Wahls, Patrice Chalin,
    Curtis Clifton, David Cok, Joseph Kiniry,
    Rustan Leino, Peter Müller, Arnd
    Poetzsch-Heffter, Erik Poll, andthe rest of the
    JML community.
  • Join us at...
  • jmlspecs.org

85
Future Work on JML
  • Tools
  • Java 1.5 support
  • Eclipse support
  • Documentation
  • Concurrency support
  • Semantic details
  • Theorem proving tie-ins, Static analysis tie-ins
  • Inference of specifications
  • Tools that give more benefits

86
References
  • Ame87 Pierre America. Inheritance and subtyping
    in a parallel object-oriented language. In Jean
    Bezivin et al., editors, ECOOP 87, European
    Conference on Object-Oriented Programming, Paris,
    France, pages 234242, New York, NY, June 1987.
    Springer-Verlag. Lecture Notes in Computer
    Science, volume 276.
  • Ame91 Pierre America. Designing an
    object-oriented programming language with
    behavioural subtyping. In J. W. de Bakker, W. P.
    de Roever, and G. Rozenberg, editors,
    Foundations of Object-Oriented Languages, REX
    School/Workshop, Noordwijkerhout, The
    Netherlands, May/June 1990, volume 489 of Lecture
    Notes in Computer Science, pages 6090.
    Springer-Verlag, New York, NY, 1991.
  • BCC05 Lilian Burdy, Yoonsik Cheon, David R.
    Cok, Michael D. Ernst, Joeseph R. Kiniry, Gary T.
    Leavens, K. Rustan M. Leino, and Erik Poll. An
    overview of JML tools and applications.
    International Journal on Software Tools for
    Technology Transfer, 7(3)212232, June 2005.
  • DL96 Krishna Kishore Dhara and Gary T. Leavens.
    Forcing behavioral subtyping through
    specification inheritance. In Proceedings of the
    18th International Conference on Software
    Engineering, Berlin, Germany, pages 258267. IEEE
    Computer Society Press, March 1996. A corrected
    version is ISU CS TR 95-20c, rlhttp//tinyurl.com
    /s2krg.
  • FF01 Robert Bruce Findler and Matthias
    Felleisen. Contract soundness for object-oriented
    languages. In OOPSLA 01 Conference Proceedings,
    Object-Oriented Programming, Systems, Languages,
    and Applications, October 14-18, 2001, Tampa Bay,
    Florida, USA, pages 115, October 2001.
  • Hoa69 C. A. R. Hoare. An axiomatic basis for
    computer programming. Communications of the ACM,
    12(10)576580,583, October 1969.
  • Hoa72 C. A. R. Hoare. Proof of correctness of
    data representations. Acta Informatica,
    1(4)271281, 1972.
  • LD00 Gary T. Leavens and Krishna Kishore Dhara.
    Concepts of behavioral subtyping and a sketch of
    their extension to component-based systems. In
    Gary T. Leavens and Murali Sitaraman, editors,
    Foundations of Component-Based Systems,
    chapter 6, pages 113135. Cambridge University
    Press, 2000.
  • Lei98 K. Rustan M. Leino. Data groups
    Specifying the modification of extended state. In
    OOPSLA 98 Conference Proceedings, volume 33(10)
    of ACM SIGPLAN Notices, pages 144153. ACM,
    October 1998.
  • LN06 Gary T. Leavens and David A. Naumann.
    Behavioral subtyping, specification inheritance,
    and modular reasoning. Technical Report 06-20b,
    Department of Computer Science, Iowa State
    University, Ames, Iowa, 50011, September 2006.
  • LW94 Barbara H. Liskov and Jeannette M. Wing. A
    behavioral notion of subtyping. ACM Transactions
    on Programming Languages and Systems,
    16(6)18111841, November 1994.
  • Mey97 Bertrand Meyer. Object-oriented Software
    Construction. Prentice Hall, New York, NY, second
    edition, 1997.
  • MPHL06 Peter Müller, Arnd Poetzsch-Heffter, and
    Gary T. Leavens. Modular invariants for layered
    object structures. Science of Computer
    Programming, 62(3)253 286, October 2006.
  • Mül02 Peter Müller. Modular Specification and
    Verification of Object-Oriented Programs, volume
    2262 of Lecture Notes in Computer Science.
    Springer-Verlag, 2002.
  • Par05 Matthew J. Parkinson. Local reasoning for
    Java. Technical Report 654, University of
    Cambridge Computer Laboratory, November 2005. The
    authors Ph.D. dissertation.
  • PHM99 A. Poetzsch-Heffter and P. Müller. A
    programming logic for sequential Java. In S. D.
    Swierstra, editor, European Symposium on
    Programming (ESOP 99), volume 1576 of Lecture
    Notes in Computer Science, pages 162176.
    Springer-Verlag, 1999.
  • Pie06 Cees Pierik. Validation Techniques for
    Object-Oriented Proof Outlines. PhD thesis,
    Universiteit Utrecht, 2006.
  • SBC92 Susan Stepney, Rosalind Barden, and David
    Cooper, editors. Object Orientation in Z.
    Workshops in Computing. Springer-Verlag,
    Cambridge CB2 1LQ, UK, 1992.
  • Wil92 Alan Wills. Specification in Fresco. In
    Stepney et al. SBC92, chapter 11, pages
    127135.
Write a Comment
User Comments (0)