Introduction to VDM2, Simple AST extensions and Concurrency in VDM - PowerPoint PPT Presentation

1 / 64
About This Presentation
Title:

Introduction to VDM2, Simple AST extensions and Concurrency in VDM

Description:

Title: Defining Data and Functionality Author: Peter Gorm Larsen Last modified by: pgl Created Date: 2/9/2006 2:47:36 PM Document presentation format – PowerPoint PPT presentation

Number of Views:145
Avg rating:3.0/5.0
Slides: 65
Provided by: PeterG172
Category:

less

Transcript and Presenter's Notes

Title: Introduction to VDM2, Simple AST extensions and Concurrency in VDM


1
Introduction to VDM2, Simple AST extensions and
Concurrency in VDM
  • Professor Peter Gorm Larsen
  • (pgl_at_iha.dk)

2
Agenda
  • Administrative information about the course
  • Simple AST Extensions
  • Concurrency primitives in VDM
  • Example POP3 Server
  • Example MSAWConc
  • Concurrency and Overture
  • Feedback on abstraction test and VDM1 reports

3
Teaching Material
  • John Fitzgerald, Peter Gorm Larsen, Paul
    Mukherjee, Nico Plat and Marcel Verhoef
    Validated Designs for Object-oriented Systems.
    Springer Verlag, 2005. (second part)
  • Development Process of Distributed Embedded
    Systems using VDM, Peter Gorm Larsen et al, 2010.
  • The Overture tool (v0.2) used during the course
  • Enterprise Architect

4
TIVDM2 web pages
  • All information concerning this course including
    lecture notes, assignments announcements, etc.
    can be found on the TIVDM2 web pages
    http//kurser.iha.dk/eit/tivdm2/
  • You should check this site frequently for new
    information and changes. It will be your main
    source of information for this unit. The layout
    of the WebPages should be fairly self explanatory
  • Campus WebPages will be used only for mailing
    information

5
Education Form
  • Confrontation with the teacher
  • Thursdays 800 1600 in Room 316
  • Read in advance of each lecture
  • Combination of
  • Lessons teaching theory
  • Strategy for lessons quick intro to concepts and
    then usage in larger examples
  • Continuation of projects where theory is turned
    into practice
  • Using Overture for projects
  • Exam form
  • 15 minutes oral examination without preparation
    5 minutes for evaluation
  • Oral examination will be centered around projects
    performed
  • Projects reused from TIVDM1 and extended further
  • Exam will be on the 10th of June 2010

6
Learning Objectives
  • The participants must at the end of the course be
    able to
  • Discuss and compare different abstract models
    (sequential, concurrent and distributed) in
    relation to each other.
  • Explain constructs and concepts in the
    concurrent, real-time and distributed part of the
    modelling language VDM.
  • Define and explain syntax and semantics for the
    concurrent, real-time and distributed subset of
    VDM.
  • Apply VDM and UML with the associated tool
    support for either the description of semantics
    of a programming language or for abstract and
    precise modelling and validation of concurrent,
    real-time and distributed systems.
  • Evaluate practical use of VDM for the
    validation of concrete distributed and embedded
    systems.

7
Evaluation principles
  • The project reports will be evaluated against
  • Mastering abstraction
  • Testability of the VDM models
  • Use of basic VDM structures
  • Use of VDM concurrency principles (for RT
    projects)
  • Use of VDM real-time primitives (for RT
    projects)
  • Exploration of alternative distributive
    architectures (RT)
  • Using VDM for prog lang semantics issues (for AST
    projects)
  • VDM/UML model quality considerations
  • Refection of pros and cons with the VDM-RT
    approach (RT)
  • Report quality including the use of logfile
    analysis (RT)
  • The exam will be evaluated against
  • The project report
  • The project presentation by the student
  • The students ability to show understanding of
    VDM/UML

8
Focus in this course
  • Focus is on
  • Abstract modeling of realistic systems
  • Understanding the VDM concepts for AST handling,
    concurrency, real-time and distribution
  • Learning how to read models made in VDM/UML
  • Learning how to write models in VDM/UML
  • Learning how to move from a sequential model, via
    a concurrent model to a real-time distributed
    model
  • Learning how to validate all these models
  • Focus is not on
  • Toy examples
  • Implementation

9
Why have this course?
  • To understand the underlying primitives for being
    able to model complex concurrent and distributed
    computer systems
  • To understand how language semantics can be
    described using VDM concepts
  • To be able to comprehend the formulation of
    important desirable properties precisely
  • To be able to express important desirable
    properties (including real-time) precisely
  • To enable the formulation of abstract models in
    an industrially applicable formal notation
  • To validate those models to increase confidence
    in their correctness and eliminate potential
    architectural bottlenecks

10
Structure of the course
  • Week
  • Introduction, Concurrency in VDM, AST simple
    extensions (chap 12)
  • Real-time and distributed modelling in VDM
    (additional notes)
  • Model Quality (chap 13)
  • More about semantics about different language
    constructs in VDM
  • Model Structuring and Combining Views (chap 910)
  • Report writing
  • Course evaluation and repetition (if desired)

11
Anticipated Plan with Projects
  • Week 1 Revisit the model from TIVDM1
  • Week 2 Add concurrency to the model and validate
    it
  • Week 3 Add real-time and distribution to the
    model Present initial ideas and get feedback on
    distributed real-time models. Validate the model
    and experiment with alternative distribution
    architectures
  • Week 4 Work on your project
  • Week 5 Present final distributed real-time
    models
  • Week 6 Write report for the project
  • Week 7 Project report is handed in to the
    teacher. Evaluation of insight gained by using
    the VDM-RT extensions to VDM

12
Agenda
  • Administrative information about the course
  • Simple AST Extensions
  • Concurrency primitives in VDM
  • Example POP3 Server
  • Example MSAWConc
  • Concurrency and Overture
  • Feedback on abstraction test and VDM1 reports

13
Extensions of Simple
  • Introduction of operations
  • Notion of state
  • Block statements
  • Assignment statements
  • Operation calls and return statements
  • Introduction of set expressions
  • Both enumeration and comprehensions
  • Also set type in type system
  • Introduction of higher-order functions
  • Functions that yield functions as results
  • Typically used in functional programming languages

14
Introduction of operations
  • Notion of state
  • ltstate definitiongt ltidentifiergt "" lttypegt
    "" ltexpressiongt
  • Operation definition
  • ltoperation definitiongt
  • ltidentifiergt ltparamlistgt "" ltstatementgt
  • Statements
  • ltstatementgt ltblock statementgt ltassignment
    statementgt
  • ltcall statementgt ltreturn statementgt
  • ltblock statementgt ltstatementgt "("
    ltstatementgt ")"
  • ltassignment statementgt ltidentifiergt ""
    ltexpressiongt
  • ltcall statementgt
  • ltidentifiergt "(" ltexpressiongt ","
    ltexpressiongt ")"
  • ltreturn statementgt "return" ltexpressiongt

15
Introduction of set expressions
  • Set enumerations
  • ltset enumerationgt
  • "" ltexpressiongt "," ltexpressiongt ""
  • Set Comprehensions
  • ltset comprehensiongt
  • "" ltexpressiongt
  • "" ltidentifiergt "in set" ltexpressiongt
  • "" ltexpressiongt "
  • Set types
  • lttypegt "real" "int" "nat" "bool" "set
    of" lttypegt ltidentifiergt

16
Introduction of higher-order functions
  • Higher order functions
  • ltfunction definitiongt
  • ltidentifiergt ltparamlistgt ltparamlistgt ""
    ltexpressiongt
  • Parameter lists
  • ltparamlistgt "(" ltparametergt "," ltparametergt
    ")"
  • Example of a higher order function
  • Add(x int)(y int) x y
  • Here Add(7) is similar to a new function like
  • lambda y int 7 y
  • Which is a new function that can be passed around
    as an argument or called with other arguments

17
Agenda
  • Administrative information about the course
  • Simple AST Extensions
  • Concurrency primitives in VDM
  • Example POP3 Server
  • Example MSAWConc
  • Concurrency and Overture
  • Feedback on abstraction test and VDM1 reports

18
Concurrency Primitives in VDM
  • Concurrency in VDM is based on threads
  • Threads communicate using shared objects
  • Synchronization on shared objects is specified
    using permission predicates

19
Threads
  • Modelled by a class with a thread section
  • class SimpleThread
  • thread
  • IOprint(Hello World)
  • end SimpleThread
  • Thread execution begins using start statement
    with an instance of a class with a thread
    definition
  • start(new SimpleThread())
  • Note that execution ends when debug thread is
    finished

20
Thread Communication
  • Threads operating in isolation have limited use.
  • In VDM threads communicate using shared
    objects.

21
A Producer-Consumer Example
  • Concurrent threads must be synchronized
  • Illustrate with a producer-consumer example
  • Produce before consumption
  • Assume a single producer and a single consumer
  • Producer has a thread which repeatedly places
    data in a buffer
  • Consumer has a thread which repeatedly fetches
    data from a buffer

22
The Producer Class
  • class Producer
  • instance variables
  • b Buffer
  • operations
  • Produce () gt seq of char
  • Produce() ...
  • thread
  • while true do
  • b.Put(Produce())
  • end Producer

23
The Consumer Class
  • class Consumer
  • instance variables
  • b Buffer
  • operations
  • Consume seq of char gt ()
  • Consume(d) ...
  • thread
  • while true do
  • Consume(b.Get())
  • end Consumer

24
The Buffer Class
  • class Buffer
  • instance variables
  • data seq of char nil
  • operations
  • public Put seq of char gt ()
  • Put(newData)
  • data newData
  • public Get () gt seq of char
  • Get()
  • let oldData data
  • in
  • ( data nil
  • return oldData
  • )

25
Permission Predicates
  • What if the producer thread generates values
    faster than the consumer thread can consume them?
  • Shared objects require synchronization.
  • Synchronization is achieved in VDM using
    permission predicates.
  • A permission predicate describes when an
    operation call may be executed.
  • If a permission predicate is not satisfied, the
    operation call blocks.

26
Permission Predicates
  • Permission predicates are described in the sync
    section of a class
  • sync
  • per ltoperation namegt gt predicate
  • The predicate may refer to the classs instance
    variables.
  • The predicate may also refer to special variables
    known as history counters.

27
History Counters
Counter Description
req op The number of times that op has been requested
act op The number of times that op has been activated
fin op The number of times that op has been completed
active op The number of active executions of op
waiting op The number of waiting executions of op
active op act op - fin op
waiting op req op - act op
28
The Buffer Synchronized
  • Assuming the buffer does not lose data, there are
    two requirements
  • It should only be possible to get data, when the
    producer has placed data in the buffer.
  • It should only be possible to put data when the
    consumer has fetched data from the buffer.
  • The following permission predicates could model
    these requirements
  • per Put gt data nil
  • per Get gt data ltgt nil

29
The Buffer Synchronized (2)
  • The previous predicates could also have been
    written using history counters
  • For example
  • per Get gt fin(Put) - fin(Get) 1

30
Mutual Exclusion
  • Another problem could arise with the buffer what
    if the producer produces and the consumer
    consumes at the same time?
  • The result could be non-deterministic and/or
    counter-intuitive.
  • VDM provides the keyword mutex
  • mutex(Put, Get)
  • Shorthand for
  • per Put gt active(Get) 0
  • per Get gt active(Put) 0

31
Agenda
  • Administrative information about the course
  • Simple AST Extensions
  • Concurrency primitives in VDM
  • Example POP3 Server
  • Example MSAWConc
  • Concurrency and Overture
  • Feedback on abstraction test and VDM1 reports

32
Example POP3 Server
  • Protocol which allows email clients to fetch
    messages from a server.
  • Server contains a collection of messages for a
    number of users.
  • Server is typically capable of communicating with
    multiple clients concurrently.

33
Overall Class Structure
34
Behaviour
  • The server listens constantly for clients.
  • When a client initiates contact, a client handler
    is spawned.
  • The client handler then responds to commands from
    the client, until the client terminates the
    session.

35
The POP3Server Instance Variables
  • class POP3Server
  • instance variables
  • maildrop MailDrop
  • passwords map POP3TypesUserName to
    POP3TypesPassword
  • locks map ClientHandlerId to
    POP3TypesUserName
  • serverStarted bool false
  • types
  • public MailDrop map POP3TypesUserName to
    MailBox
  • public MailBox
  • msgs seq of POP3Message
  • locked bool
  • public ClientHandlerId nat
  • end POP3Server

36
The POP3Server Basic Synchronization
  • class POP3Server
  • operations
  • SetUserMessages POP3TypesUserName seq of
    POP3Message gt ()
  • SetUserMessages(user, newMsgs)
  • maildrop(user) mu(maildrop(user), msgs -gt
    newMsgs)
  • pre user in set dom maildrop
  • GetUserMail POP3TypesUserName gt MailBox
  • GetUserMail(user)
  • return maildrop(user)
  • pre user in set dom maildrop
  • sync
  • mutex(SetUserMessages)
  • mutex(SetUserMessages, GetUserMail)
  • end POP3Server

37
Synchronization of Locking
  • class POP3Server
  • operations
  • public AcquireLock ClientHandlerId
    POP3TypesUserName gt ()
  • AcquireLock (clId, user)
  • locks locks clId -gt user
  • pre clId not in set dom locks
  • public ReleaseLock ClientHandlerId gt ()
  • ReleaseLock(clId)
  • locks clId lt- locks
  • pre clId in set dom locks
  • public IsLocked POP3TypesUserName gt bool
  • IsLocked(user)
  • return user in set rng locks
  • sync
  • mutex(AcquireLock)
  • mutex(ReleaseLock)

38
Client Handler States
  • Three states
  • Authorisation The client has not yet been
    authorised by the client handler.
  • Transaction The client is able to interrogate
    the client handler about the contents of the
    mail box for the client's user.
  • UpdateThe client has ended the session messages
    marked for deletion are actually deleted from the
    server, then the thread dies.
  • class POP3ClientHandler
  • ServerState ltAuthorizationgt ltTransactiongt
    ltUpdategt
  • end POP3ClientHandler

39
Starting a Client Session
  • class POP3Server
  • thread
  • while true do
  • ( let msgChannel connChannel.Get()
  • in
  • CreateClientHandler(msgChannel)
  • serverStarted true
  • )
  • instance variables
  • connChannel MessageChannelBuffer
  • operations
  • CreateClientHandler MessageChannel gt ()
  • CreateClientHandler(mc)
  • start(new POP3ClientHandler(self, mc))

40
Interacting with the Client 1
  • class POP3Types
  • types
  • public ClientCommand StandardClientCommand
  • OptionalClientCommand
  • public StandardClientCommand QUIT STAT LIST
    RETR
  • DELE NOOP
    RSET
  • public OptionalClientCommand TOP UIDL USER
    PASS
  • APOP
  • public RETR messageNumber nat
  • public ServerResponse OkResponse ErrResponse
  • public OkResponse data seq of char
  • public ErrResponse data seq of char
  • end POP3Types

41
Interacting with the Client 2
  • class POP3ClientHandler
  • thread
  • ( dcl cmd POP3TypesClientCommand
  • id threadid
  • cmd msgChannel.ServerListen()
  • while (cmd ltgt mk_POP3TypesQUIT()) do
  • ( msgChannel.ServerSend(ReceiveCommand(cmd))
  • cmd msgChannel.ServerListen()
  • )
  • msgChannel.ServerSend(ReceiveCommand(cmd))
  • )
  • operations
  • ReceiveCommand POP3TypesClientCommand gt
    POP3TypesServerResponse
  • ReceiveCommand(c)
  • cases c
  • mk_POP3TypesQUIT() -gt ReceiveQUIT(c),
  • mk_POP3TypesSTAT() -gt ReceiveSTAT(c),
  • mk_POP3TypesLIST(-) -gt ReceiveLIST(c),
  • mk_POP3TypesRETR(-) -gt ReceiveRETR(c),

42
Interacting with the Client 3
  • class POP3ClientHandler
  • instance variables
  • ss ServerState
  • parent POP3Server
  • user POP3TypesUserName
  • id POP3ServerClientHandlerId
  • operations
  • ReceiveRETR POP3TypesRETR gt
    POP3TypesServerResponse
  • ReceiveRETR(retr)
  • if ss ltTransactiongt
  • then if parent.IsValidMessageNumber(user,
    retr.messageNumber)
  • then let msgText parent.GetMessageText(u
    ser, retr.messageNumber),
  • sizeText int2string(parent.GetMe
    ssageSize(user,

  • retr.messageNumber))
  • in
  • return mk_POP3TypesOkResponse(sizeT
    ext "\n" msgText)

43
Synchronized Communicationin the POP3 Server 1
  • class MessageChannel
  • instance variables
  • data POP3TypesClientCommand
    POP3TypesServerResponse nil
  • operations
  • Send POP3TypesClientCommand
    POP3TypesServerResponse gt ()
  • Send(msg)
  • data msg
  • Listen () gt POP3TypesClientCommand
    POP3TypesServerResponse
  • Listen()
  • let d data in
  • ( data nil return d
  • )
  • end MessageChannel

44
Synchronized Communicationin the POP3 Server 2
  • class MessageChannel
  • operations
  • public ServerSend POP3TypesServerResponse gt
    ()
  • ServerSend(p)
  • Send(p)
  • public ServerListen () gt POP3TypesClientComman
    d
  • ServerListen()
  • Listen()
  • sync
  • per ClientSend gt fin(ServerSend)
    fin(ClientListen) and
  • fin(ClientSend)
    fin(ServerListen) and
  • fin(ServerSend)
    fin(ClientSend)
  • per ServerListen gt fin(ClientSend) - 1
    fin(ServerListen)
  • end MessageChannel

45
Sequence Diagram
46
Agenda
  • Administrative information about the course
  • Simple AST Extensions
  • Concurrency primitives in VDM
  • Example POP3 Server
  • Example MSAWConc
  • Concurrency and Overture
  • Feedback on abstraction test and VDM1 reports

47
The TimeStamp Class (1/3)
  • class TimeStamp
  • instance variables
  • currentTime nat 0
  • wakeUpMap map nat to nat -gt
  • operations
  • public WaitRelative nat gt ()
  • WaitRelative(val)
  • AddToWakeUpMap(threadid, currentTime val)
  • public WaitAbsolute nat gt ()
  • WaitAbsolute(val)
  • AddToWakeUpMap(threadid, val)
  • AddToWakeUpMap nat nat gt ()
  • AddToWakeUpMap(tId, val)

48
The TimeStamp Class (2/3)
  • public NotifyThread nat gt ()
  • NotifyThread(tId)
  • wakeUpMap tId lt- wakeUpMap
  • public NotifyAll () gt ()
  • NotifyAll()
  • let threadSet set of nat th th in set
    dom wakeUpMap

  • wakeUpMap(th) lt currentTime
  • in
  • for all t in set threadSet
  • do
  • NotifyThread(t)
  • NotifyAndIncTime () gt ()
  • NotifyAndIncTime()
  • ( currentTime currentTime 1
  • NotifyAll()
  • )

49
The TimeStamp Class (3/3)
  • public GetTime () gt nat
  • GetTime()
  • return currentTime
  • sync
  • mutex(NotifyAll)
  • mutex(AddToWakeUpMap)
  • mutex(AddToWakeUpMap, NotifyAll)
  • end TimeStamp

50
The ClockTick Class
  • class ClockTick is subclass of GLOBAL
  • instance variables
  • tid int -1
  • operations
  • public ClockTick Time gt ClockTick
  • ClockTick (t) tid t
  • thread
  • while true do
  • (WorldtimerRef.NotifyThread(tid)
  • WorldtimerRef.WaitRelative(1)
  • )
  • end ClockTick

51
The World Class
  • class World
  • public World () gt World
  • World()
  • ( env new Environment("scenario.txt")
  • env.setAirSpace(MSAWairspace)
  • MSAWatc.addObstacle(MSAWmilitaryZone)
  • MSAWatc.addRadar(MSAWradar1)
  • MSAWatc.addRadar(MSAWradar2)
  • )
  • public Run () gt ()
  • Run()
  • (start(env)
  • start(MSAWatc)
  • env.isFinished()
  • MSAWatc.isFinished()
  • env.showResult()
  • )

52
The Environment Thread
  • class Environment
  • thread
  • (start(new ClockTick(threadid))
  • while WorldtimerRef.GetTime() lt simtime do
  • (updateFOs()
  • if updating
  • then (WorldtimerRef.WaitRelative(0)
  • updating false)
  • WorldtimerRef.NotifyAndIncTime()
  • WorldtimerRef.Awake()
  • )
  • busy false
  • )
  • end Environment

53
The Environment Synchronisation
  • class Environment
  • ...
  • public isFinished () gt ()
  • isFinished() skip
  • sync
  • mutex(handleFOWarningEvent)
  • per isFinished gt not busy
  • mutex(handleRadarWarningEvent)
  • mutex(handleRadarWarningEvent,
  • handleFOWarningEvent)
  • end Environment

54
Air Traffic Controller (1/2)
  • class AirTrafficController is subclass of GLOBAL
  • ...
  • operations
  • public isFinished () gt ()
  • isFinished()
  • for all r in set radars do
  • r.isFinished()
  • public Step () gt ()
  • Step()
  • ( for all r in set radars
  • do
  • r.Scan(MSAWairspace)
  • updateHistory()
  • findThreats()
  • busy false
  • )

55
Air Traffic Controller (2/2)
  • thread
  • (for all r in set radars do
  • start(r)
  • while true do
  • Step()
  • )
  • sync
  • per isFinished gt not busy
  • per Step gt busy
  • end AirTrafficController

56
The Radar Class Thread Sync
  • class Radar
  • ...
  • thread
  • while true do
  • (let as MSAWairspace
  • in
  • (detected x.getId() -gt x x in set
    as.getAirspace() InRange(x)
  • UpdatePriorityList()
  • WorldtimerRef.WaitRelative(TimeStampstepLengt
    h)
  • WorldtimerRef.NotifyAll()
  • WorldtimerRef.Awake()
  • )
  • )
  • sync
  • per isFinished gt not busy
  • mutex(removeNotDetected)
  • mutex(addNewlyDetected)
  • mutex(UpdatePriorityList)

57
Agenda
  • Administrative information about the course
  • Simple AST Extensions
  • Concurrency primitives in VDM
  • Example POP3 Server
  • Example MSAWConc
  • Concurrency and Overture
  • Feedback on abstraction test and VDM1 reports

58
Concurrency and Overture
  • Overture provides
  • Type checking of thread and sync sections of a
    class.
  • Interpretation of threads in a deterministic
    fashion.
  • All threads are stopped when a breakpoint is
    reached.
  • Threadid and information for the broken thread
    can be inspected in the debug perspective.
  • Note that the scheduler for concurrency is VERY
    new
  • VDMTools additionally provide code generation of
    thread and sync sections of a class (Java only).

59
Agenda
  • Administrative information about the course
  • Simple AST Extensions
  • Concurrency primitives in VDM
  • Example POP3 Server
  • Example MSAWConc
  • Concurrency and Overture
  • Feedback on abstraction test and VDM1 reports

60
Answers for the Libary questions
  • On the basis of your understanding of the text,
    which of the following statements do you agree
    with?
  • Multiple copies can exist for the same book
  • Do the requirements say anything about the order
    used for transaction 3?
  • No
  • Can an ordinary borrower return a book?
  • Yes, if he delegates it to a staff user
  • Can new users be added to the library?
  • Not clear from the text
  • Can staff users also be ordinary borrowers?
  • Not clear from the text
  • Is there a limit for how many books a staff user
    may borrow?
  • No
  • What information can we deduce from the text that
    we need to record for a book? (check all that
    apply)
  • Author
  • Subject
  • Copies of it

61
Answers for the Student questions
  • On the basis of your understanding of the text,
    which of the following statements do you agree
    with?
  • Multiple occurrences of course occurrences can
    exist of the same course
  • Do the requirements say anything about the order
    in the list of courses used for function 3?
  • No
  • Can an ordinary student enrol in a course?
  • Yes, if it is done with the help of a staff user
  • Can new students be added to the system?
  • Not clear from the text
  • Can staff users also be students?
  • Not clear from the text
  • Is there a limit on how many enrolments a student
    may have overall?
  • No
  • What information can we deduce from the text that
    we need to have for a course or course
    occurrence?
  • Teacher(s)
  • Title
  • Study program
  • State of a course

62
Student performances
63
Summary
  • What have I presented today?
  • Administrative information about the course
  • Simple Extensions
  • Concurrency primitives in VDM
  • The POP3 and MSAW Concur examples
  • Concurrency support in Overture
  • Feedback on abstraction test and VDM1 reports
  • What do you need to do now?
  • Inspect the electronic copy of the POP3 example
  • Get new version of Overture installed and start
    looking at the language manual
  • Revisit your project
  • Present your project selection to all of us

64
Quote of the day
Its different, in that we take on novel tasks
every time. The number of times civil engineers
make mistakes is very small. And at first you
think, whats wrong with us? Its because its
like were building the first skyscraper
every time.
Bill Gates
Write a Comment
User Comments (0)
About PowerShow.com