3.5

20
4.5 - 1 Chapter 3.5 Programming Paradigms 3.5 Introduction 3.5 (a) Programming Paradigms Programming paradigms are simply methods of programming. Initially, computers were programmed using binary. This was difficult and led to many errors that were difficult to find. Programs written in binary are said to be written in machine code, this is a very low-level programming paradigm. To make programming easier, assembly languages were developed. These replaced machine code functions with mnemonics and addresses with labels. Assembly language programming is also a low-level paradigm although it is a second generation paradigm. Figure 3.5.a.1 shows an assembly language program that adds together two numbers and stores the result. Label Function Address Comments LDA X Load the accumulator with the value of X ADD Y Add the value of Y to the accumulator STA Z Store the result in Z STOP Stop the program X: 20 Value of X = 20 Y: 35 Value of Y = 35 Z: Location for result Figure 3.5.a.1 Although this assembly language is an improvement over machine code, it is still prone to errors and code is difficult to debug, correct and maintain. The next advance was the development of procedural languages. These are third generation languages and are also known as high-level languages. These languages are problem oriented as they use terms appropriate to the type of problem being solved. For example, COBOL (Common Business Oriented Language) uses the language of business. It uses terms like file, move and copy. FORTRAN (FORmula TRANslation) and ALGOL (ALGOrithmic Language) were developed mainly for scientific and engineering problems. Although one of the ideas behind the development of ALGOL was that it was an appropriate language to define algorithms. BASIC (Beginners All purpose Symbolic Instruction Code) was developed to enable more people to write programs. All these languages follow the procedural paradigm. That is, they describe, step by step, exactly the procedure that should be followed to solve a problem. The problem with procedural languages is that it can be difficult to reuse code and to modify solutions when better methods of solution are developed. In order to address these problems, object-oriented languages (like Eiffel, Smalltalk and Java) were developed. In these languages, data and methods of manipulating the data, are kept as

Upload: samimvez

Post on 02-Jun-2015

390 views

Category:

Documents


1 download

TRANSCRIPT

Page 1: 3.5

4.5 - 1

Chapter 3.5 Programming Paradigms

3.5 Introduction

3.5 (a) Programming Paradigms

Programming paradigms are simply methods of programming. Initially, computers

were programmed using binary. This was difficult and led to many errors that were

difficult to find. Programs written in binary are said to be written in machine code,

this is a very low-level programming paradigm.

To make programming easier, assembly languages were developed. These replaced

machine code functions with mnemonics and addresses with labels. Assembly

language programming is also a low-level paradigm although it is a second generation

paradigm. Figure 3.5.a.1 shows an assembly language program that adds together two

numbers and stores the result.

Label Function Address Comments

LDA X Load the accumulator with the value of X

ADD Y Add the value of Y to the accumulator

STA Z Store the result in Z

STOP Stop the program

X: 20 Value of X = 20

Y: 35 Value of Y = 35

Z: Location for result

Figure 3.5.a.1

Although this assembly language is an improvement over machine code, it is still

prone to errors and code is difficult to debug, correct and maintain.

The next advance was the development of procedural languages. These are third

generation languages and are also known as high-level languages. These languages

are problem oriented as they use terms appropriate to the type of problem being

solved. For example, COBOL (Common Business Oriented Language) uses the

language of business. It uses terms like file, move and copy.

FORTRAN (FORmula TRANslation) and ALGOL (ALGOrithmic Language) were

developed mainly for scientific and engineering problems. Although one of the ideas

behind the development of ALGOL was that it was an appropriate language to define

algorithms. BASIC (Beginners All purpose Symbolic Instruction Code) was

developed to enable more people to write programs. All these languages follow the

procedural paradigm. That is, they describe, step by step, exactly the procedure that

should be followed to solve a problem.

The problem with procedural languages is that it can be difficult to reuse code and to

modify solutions when better methods of solution are developed. In order to address

these problems, object-oriented languages (like Eiffel, Smalltalk and Java) were

developed. In these languages, data and methods of manipulating the data, are kept as

Page 2: 3.5

4.5 - 2

a single unit called an object. The only way that a user can access the data is via the

object's methods. This means that, once an object is fully working, it cannot be

corrupted by the user. It also means that the internal workings of an object may be

changed without affecting any code that uses the object.

A further advance was made when declarative programming paradigms were

developed. In these languages the computer is told what the problem is, not how to

solve the problem. Given a database the computer searches for a solution. The

computer is not given a procedure to follow as in the languages discussed so far.

3.5 (b) Programming Paradigms and examples.

Procedural languages specify, exactly, the steps required to solve a problem. These

languages use the constructs: sequence, selection and repetition (see Section 1.3 in the

AS text). For example, to find the area of a rectangle the steps are

1. Read the length

2. Read the breadth

3. Multiply the length by the breadth

4. Output the result

In C++ this can be coded as

cout << "Enter the length: ";

cin >> Length;

cout << "Enter the breadth: ";

cin >> Breadth;

Area = Length * Breadth;

cout << "The area is "

<< Area << endl;

Here each line of code is executed one after the other in sequence.

Most procedural languages have two methods of selection. These are the IF …

THEN … ELSE statement and the SWITCH or CASE statement. For example, in

C++, we have

IF (Number > 0)

cout << "The number is positive.";

ELSE

{

IF (Number = = 0)

cout << "The number is zero.";

ELSE

cout << "The number is negative.";

}

Page 3: 3.5

4.5 - 3

In C++ multiple selections can be programmed using the SWITCH statement. For

example, suppose a user enters a single letter and the output depends on that letter, a

typical piece of code could be

switch (UserChoice)

{

case 'A':

cout << "A is for Apple.";

break;

case 'B':

cout << "B is for Banana.";

break;

case 'C':

cout << "C is for Cat.";

break;

default:

cout << "I don't recognise that letter.";

}

Repetition (or iteration) is another standard construct. Most procedural languages

have many forms of this construct such as

FOR … NEXT

REPEAT … UNTIL …

WHILE … ENDWHILE

A typical use of a loop is to add a series of numbers. The following pieces of C++

code add the first ten positive integers.

//Using a FOR loop

Sum = 0;

FOR (int i = 1; i <= 10; i++)

{

Sum = Sum + i;

}

cout << "The sum is "

<< Sum;

//Using a WHILE loop

Sum = 0;

i = 1;

while (i <= 10)

{

Sum = Sum + i;

i++;

}

cout << "The sum is "

<< Sum;

Page 4: 3.5

4.5 - 4

In procedural languages is that the programmer has to specify exactly what the

computer is to do.

Another programming paradigm is the declarative one. Declarative languages tell the

computer what is wanted but do not provide the details of how to do it. These

languages are particularly useful when solving problems in artificial intelligence such

as medical diagnosis, fault finding in equipment and oil exploration. The method is

also used in robot control. An example of a declarative language is Prolog. The idea

behind declarative languages is shown in Fig. 3.5.b.1.

Fig. 3.5.b.1

Here the user inputs a query to the search engine, which then searches the database for

the answers and returns them to the user. For example, using Prolog, suppose the

database is

female(jane).

female(anne).

female(sandip).

male(charnjit).

male(jaz).

male(tom).

Note that in Prolog values start with a lowercase letter and variables start with an

uppercase letter. A user may want to know the names of all the males. The query

male(X).

will return

X = charnjit

X = jaz

X = tom

Notice that the user does not have to tell Prolog how to search for the values of X that

satisfy the query. This is fairly straightforward. However, suppose we now add to the

Prolog database the following data.

parent(jane,mary).

parent(jane, rajinder).

parent(charnjit, mary).

parent(charnjit, rajinder).

parent(sandip, atif).

User

Search Engine

Database

Page 5: 3.5

4.5 - 5

parent(jaz, atif).

and suppose we wish to know the name of the mother of Atif. In Prolog we use the

query

parent(X, atif), female(X).

Prolog will output

X = sandip

Try writing a Visual Basic program to do this.

To get a list of all the fathers, we can simply write

parent(X, Y), male(X).

The result is

X = charnjit Y = mary

X = charnjit Y = rajinder

X = jaz Y = atif

If we only want a list of fathers we use the underscore and create the query

parent(X, _ ), male(X).

and the result is

X = charnjit

X = charnjit

X = jaz

3.5 (d) Standard Programming Techniques.

Let us consider how data can be input to a function or procedure. This is done by

means of parameters. The function below, written in Visual Basic, finds the perimeter

of a rectangle given its length and breadth. This is not the only way of finding the

perimeter and it probably is not the best way. However, it has been written like this in

order to illustrate certain programming points.

Public Function PerimeterOfRectangle(X As Integer, Y As Integer) As Integer

X = 2 * X

Y = 2 * Y

PerimeterOfRectangle = X + Y

End Function

Page 6: 3.5

4.5 - 6

In this function X and Y are integers the values of which must be passed to the

function before it can find the area of the rectangle. These variables are called formal

parameters. To use this function, another program will have to call it and provide the

values for X and Y. This can be done by means of a statement of the form

Perimeter = PerimeterOfRectangle(4, 6)

or we can use

A = 3

B = 4

Perimeter = PerimeterOfRectangle(A, B)

In both of these statements the variables inside the parentheses ( 4 and 6 in the first

example and A and B in the second) are called actual parameters.

Visual Basic is said to pass parameters by reference (or address) and C++ passes them

by value. It is interesting to see the effect of passing values by address. Here is the

function described above and a copy of the calling function in Visual Basic.

Public Function PerimeterOfRectangle(X As Integer, Y As Integer) As Integer

X = 2 * X

Y = 2 * Y

PerimeterOfRectangle = X + Y

End Function

Private Sub cmdShow_Click()

Dim A As Integer

Dim B As Integer

Dim Perimeter As Integer

A = 3

B = 4

picResults.Print "Before call to Sub A = "; A; " and B = "; B

Perimeter = PerimeterOfRectangle(A, B)

picResults.Print "Perimeter = "; Perimeter

picResults.Print "After call to Sub A = "; A; " and B = "; B;

End Sub

Fig.3.5.d.3 shows the output when this program is run.

Page 7: 3.5

4.5 - 7

Fig.3.5.d.3

Notice that after the function has been run the values of A and B have changed. This

is because the addresses of A and B were passed not their actual values.

Visual Basic can pass parameters by value and C++ can pass parameters by reference.

In Visual Basic we have to use the ByVal key word if we want values to be passed by

value. Here is a modified form of the Visual Basic function together with the output

from running the modified program.

Public Function PerimeterOfRectangle(ByVal X As Integer, ByVal Y As

Integer) As Integer

X = 2 * X

Y = 2 * Y

PerimeterOfRectangle = X + Y

End Function

Fig. 3.5.d.4

Page 8: 3.5

4.5 - 8

3.5 (f) Object-Oriented Programming (OOP)

Fig. 3.5.f.2

Now suppose we want a class Employee that requires the same data and methods as

Person and also needs to store and output an employee's National Insurance number.

Clearly, we do not wish to rewrite the contents of the class person. We can do this by

creating a class called Employee that inherits all the details of the class Person and

adds on the extra data and methods needed. This is shown in Fig. 3.5.f.3 where the

arrow signifies that Employee inherits the data and methods provided by the class

Person. Person is called the super-class of Employee and Employee is the derived

class from Person. An object of type Employee can use the methods provided by

Employee and those provided by Person.

Fig. 3.5.f.3

Person

name

address

outputData( )

getName( )

getAddress( )

Employee

NINumber

outputData( )

getNINumber( )

Person

name

address

outputData( )

getName( )

getAddress( )

Data

Methods

Class name

Page 9: 3.5

4.5 - 9

Notice that we now have two methods with the same name. How does the program

determine which one to use? If myPerson is an instantiation of the Person class, then

myPerson.outputData( );

will use the outputData( ) method from the Person class. The statement

myEmp.outputData( );

will use the method outputData( ) from the Employee class if myEmp is an

instantiation of the Employee class.

The concept of a method having two different meanings is called polymorphism.

Now suppose we have two types of employee; one is hourly paid and the other is paid

a salary. Both of these require the data and methods of the classes Person and

Employee but they also need different data to one another. This is shown in Fig.

3.5.f.4.

Person

name

address

outputData( )

getName( )

getAddress( )

Employee

NINumber

outputData( )

getNINumber( )

HourlyPaidEmp

hourlyRate

outputData( )

getHourlyRate( )

SalariedEmp

salary

outputData( )

getSalary( )

Page 10: 3.5

4.5 - 10

How can an object of type Employee output the name and address as well as the N.I.

number? The outputData( ) method in class Employee can refer to the outputData( )

method of its superclass. This is done by writing a method, in class Employee, of the

form

void outputData( ) {

super.outputData( );

System.out.println("The N.I. number is " + NINumber);

}//end of outputData method.

Here super. outputData( ) calls the outputData( ) method of the super-class and then

outputs the N.I. number. Similarly, the other derived classes can call the methods of

their super classes.

Definitions

Data encapsulation is the combining together of the variables and the methods that

can operate on the variables so that the methods are the only ways of using the

variables..

A class describes the variables and methods appropriate to some real-world entity.

An object is an instance of a class and is an actual real-world entity.

Inheritance is the ability of a class to use the variables and methods of a class from

which the new class is derived.

3.5 (g) Declarative Languages

In Section 4.5.1, we saw that, in declarative languages, the programmer can simply

state what is wanted having declared a set of facts and rules. We now look at how

this works using examples of Prolog scripts. In order to do this, we shall use the

following facts.

female(jane).

female(anne).

female(sandip).

male(charnjit).

male(jaz).

male(tom).

parent(jane,mary).

parent(jane, rajinder).

parent(charnjit, mary).

parent(charnjit, rajinder).

parent(sandip, atif).

Page 11: 3.5

4.5 - 11

parent(jaz, atif).

Remember that variables must start with an uppercase letter; constants start with a

lowercase letter.

Suppose we ask

male(X).

Prolog starts searching the database and finds male(charnjit) matches male(X) if X is

given the value charnjit. We say that X is instantiated to charnjit. Prolog now

outputs

X = charnjit

Prolog then goes back to the database and continues its search. It finds male(jaz) so

outputs

X = jaz

and again continues its search. It continues in this way until the whole database has

been searched. The complete output is

X = charnjit

X = jaz

X = tom

No

The last line means that there are no more solutions.

The query male(X) is known as a goal to be tested. That is, the goal is to find all X

that satisfy male(X). If Prolog finds a match, we say that the search has succeeded

and the goal is true. When the goal is true, Prolog outputs the corresponding values of

the variables.

Now we shall add the rule

father(X, Y) :- parent(X, Y), male(X).

This rule states that X is father of Y if (the :- symbol) X is a parent of Y AND (the

comma) X is male.

The database now looks like this.

female(jane).

female(anne).

female(sandip).

male(charnjit).

male(jaz).

male(tom).

parent(jane,mary).

Page 12: 3.5

4.5 - 12

parent(jane, rajinder).

parent(charnjit, mary).

parent(charnjit, rajinder).

parent(sandip, atif).

parent(jaz, atif).

father(X, Y) :- parent(X, Y), male(X).

Suppose our goal is to find the father of rajinder. That is, our goal is to find all X that

satisfy

father(X, rajinder).

In the database and the rule the components female, male, parent and father are called

predicates and the values inside the parentheses are called arguments. Prolog now

looks for the predicate father and finds the rule

father(X, Y) :- parent(X, Y), male(X).

In this rule Y is instantiated to rajinder and Prolog starts to search the data base for

parent(X, rajinder)

This is the new goal. Prolog finds the match

parent(jane, rajinder)

if X is instantiated to jane. Prolog now uses the second part of the rule

male(X)

with X = jane. That is, Prolog's new goal is male(jane) which fails. Prolog does not

give up at this stage but backtracks to the match

parent(jane, rajinder)

and starts again, from this point in the database, to try to match the goal

parent(X, rajinder)

This time Prolog finds the match

parent(charnjit, rajinder)

with X instantiated to charnjit. The next step is to try to satisfy the goal

male(charnjit)

This is successful so

parent(charnjit, rajinder) and male(charnjit)

Page 13: 3.5

4.5 - 13

are true. Thus father(charnjit, rajinder) is true and Prolog returns

X = charnjit

Prolog continues to see if there are any more matches. There are no more matches so

Prolog outputs

No

Definitions: Instantiation is giving a variable in a statement a value.

Predicate logic is a branch of mathematics that manipulates logical statements that

can be either True or False.

A goal is a statement that we are trying to prove whether or not it is True or False.

3.5 (i) Third and Fourth Generation Languages

Third generation languages are those that use a structured syntax such as C, C++ and

Pascal. Early versions of Fortran and BASIC were not structured and are usually

treated as second generation languages. However, Visual Basic is structured and can

be treated as a third generation language.

Third generation languages need the user to specify clearly all the steps that need to

be taken to solve a problem. Fourth generation languages do not do this. Languages

that accompany modern database, word processing and spreadsheet packages do not

need the user to do this. The users of these packages tell the application what they

want to do not how to do it. An example is mail merge . Here all the user has to do is

tell the software what table or database to use and the mail merge will take place.

Databases often use query by example (QBE). Here the user simply states what is

required and the software will do the task. For example, Microsoft Access lets a user

specify conditions such as DOB < 01/01/90 and the necessary coding will be done. In

fact Access uses the Structured Query Language (SQL) to create the queries.

Consider the following table called Students.

Now suppose we wish to find the names of all those students who have a height

greater than 150. In Access we could simply create a query with columns for name

and height and in the height column we would write

> 150

name height weight

Alan 150 31.2

Brenda 140 27.8

Charnjit 148 30.7

Dalvinder 152 32.8

Elmira 143 28.1

Frank 158 33.4

Georgina 151 28.2

Page 14: 3.5

4.5 - 14

for the criteria. We could also specify, by means of a check box, that only the name

should be printed. The result would be

Dalvinder

Frank

Georgina

In fact, we can write the query in SQL as

SELECT name

FROM Students

WHERE height > 150;

This is what Access does.

Notice that we do not have to give the steps needed to check each entry in the table

Students. A more complicated query is

SELECT name

FROM Students

WHERE height > 145

AND

weight > 32;

Again, we do not tell the computer exactly how to find the answer required as we

would with a third generation language.

The development of fourth generation languages has meant that people who are not

programmers can produce useful results.

3.5 (j) Backus Naur Form and Syntax Diagrams

Since all programming languages have to be translated to machine code by means of a

computer, they must be clearly defined. Each statement must be of a prescribed form.

An example of the start of a FOR loop in Visual Basic is

For count = 1 To 10

but C++ expects

for (count = 1, count <= 10, count++)

A Visual Basic compiler would not understand the C++ syntax and vice versa. We

therefore need, for each language, a set of rules that specify precisely every part of the

language. These rules are specified using Backus Naur Form (BNF) or syntax

diagrams.

All languages use integers, so we shall start with the definition of an integer. An

integer is a sequence of the digits 0, 1, 2, … , 9. Now the number of digits in an

Page 15: 3.5

4.5 - 15

integer is arbitrary. That is, it can be any number. A particular compiler will restrict

the number of digits only because of the storage space set aside for an integer. But a

computer language does not restrict the number of digits. Thus the following are all

valid integers.

0

2

415

3040513002976

0000000123

Thus, an integer can be a single digit. We can write this as

<integer> ::= <digit>

This is read 'an integer is defined to be (::=) a digit'.

But we must now define a digit. A digit is 0 or 1 or 2 or … or 9 and we write this as

<digit> ::= 0|1|2|3|4|5|6|7|8|9

where the vertical line is read as OR. Notice that all the digits have to be specified and

that they are not inside angle brackets (< and >) like <integer> and <digit>. This is

because integer and digit have definitions elsewhere; the digits 0, 1, 2, … , 9 do not.

Our full definition of a single digit integer is

<integer> ::= <digit>

<digit> ::= 0|1|2|3|4|5|6|7|8|9

This is called Backus Naur Form (BNF).

But how are we going to specify integers of any length? Consider the integer

147

This is a single digit integer ( 1 ) followed by the integer 47. But 47 is a single digit

integer ( 4 ) followed by a single digit integer ( 7 ). Thus, all integers of more than

one digit start with a single digit and are followed by an integer. Eventually the final

integer is a single digit integer. Thus, an indefinitely long integer is defined as

<integer> ::= <digit><integer>

This is a recursive definition as integer is defined in terms of itself. Applying this

definition several times produces the sequence

<integer> ::= <digit><integer>

=<digit><digit><integer>

Page 16: 3.5

4.5 - 16

=<digit><digit><digit><integer>

To stop this we use the fact that, eventually, <integer> is a single digit and write

<integer> ::= <digit>|<digit><integer>

That is, <integer> is a <digit> OR a <digit> followed by an <integer>. This means

that at any time <integer> can be replaced by <digit> and the recursion stops. Strictly

speaking we have defined an unsigned integer as we have not allowed a leading plus

sign ( + ) or minus sign ( - ). This will be dealt with later. We now have the full

definition of an unsigned integer which, in BNF, is

<unsigned integer> ::= <digit>|<digit><unsigned integer>

<digit> ::= 0|1|2|3|4|5|6|7|8|9

This definition of an unsigned integer can also be described by means of syntax

diagrams as shown in Fig. 3.5.k.1.

Fig. 3.5.j.1

Now we shall define a signed integer such as

+27

-3415

digit

integer digit

0

1

2

3

4

5

6

7

8

9

Page 17: 3.5

4.5 - 17

This is simply an unsigned integer preceded by a + or – sign. Thus

<signed integer> ::= + <unsigned integer>| - <unsigned integer>

and we can use the earlier definition of an <unsigned integer>. It is usual to say that

an integer is an unsigned integer or a signed integer. If we do this we get the

following definition, in BNF, of an integer.

<integer> ::= <unsigned integer>|<signed integer>

<signed integer> ::= + <unsigned integer>| - <unsigned integer>

<unsigned integer> ::= <digit>|<digit><unsigned integer>

<digit> ::= 0|1|2|3|4|5|6|7|8|9

There are other valid ways of writing these definitions. However, it is better to use

several definitions than try to put all the possibilities into a single definition. In other

words, try to start at the top with a general definition and then try to break the

definitions down into simpler and simpler ones. That is, we have used top-down

design when creating these definitions. We have broken the definitions down until we

have terms whose values can be easily determined.

Fig. 3.5.j.2 shows the corresponding syntax diagrams.

digit

0

1

2

3

4

5

6

7

8

9

digit

integer

+

-

Page 18: 3.5

4.5 - 18

Care must be taken when positioning the recursion in the definitions using BNF.

Suppose we define a variable as a sequence of one or more characters starting with a

letter. The characters can be any letter, digit or the underscore. Valid examples are

A

x

sum

total24

mass_of_product

MyAge

Let us see what happens if we use a similar definition to that for an unsigned integer.

<variable> ::= <letter>|<character><variable>

<character> ::= <letter>|<digit>|<under-score>

Now 2Sum is valid as we use

<character><variable>

with <character> = 2 and <variable> = Sum. Continuing in this way we use 2, S and

u for <character> and then m for <letter>. This means that our definition simply

means that we must end with a letter not start with one. We must rewrite our

definition in such a way as to ensure that the first character is a letter. Moving the

recursive call to the front of <character> can do this. This means that the last time it

is called it will be a letter and this will be at the head of the variable. The correct

definition is

<variable> ::= <letter>|<variable><character>

<character> ::= <letter>|<digit>|<under-score>

<letter> ::= <uppercase>|<lowercase>

<uppercase> ::= A|B|C|D|E|F|G|H|I|J|K|ZL|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z

<lowercase> ::= a|b|c|d|e|f|g|h|i|j|k|zl|m|n|o|p|q|r|s|t|u|v|w|x|y|z

<digit> ::= 0|1|2|3|4|5|6|7|8|9

<under-score> ::= _

A syntax diagram can also represent this. This is left as an exercise. You should also

note that, in the definition of integer, we used tail recursion, but here we have used

head recursion.

Let us now use our definition of an integer to define a real number such as

0.347

-2.862

+14.34

00235.006

The result is very simple, it is

<real number> ::= <integer> . <unsigned integer>

Page 19: 3.5

4.5 - 19

Finally, suppose we do not want to allow leading zeros in our integers. That is

00135 is not allowed

0 is allowed.

This means that an integer can be a

zero digit

non-zero digit

non-zero digit followed by any digit.

This means that an integer is

zero or digits

where digits must start with a non-zero digit. In BNF, this is

<integer> ::= <zero>|<digits>

<digits> must be a single non-zero digit or a non-zero digit followed by any digits.

This gives us

<digits> ::= <non-zero digit>|<digits><digit>

where

<zero> ::= 0

<non-zero integer> ::= 1|2|3|4|5|6|7|8|9

<digit> ::= <zero>|<non-zero digit>

Fig. 3.5.j.4 shows the corresponding syntax diagram.

Page 20: 3.5

4.5 - 20

0

digits

integer

digits 1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9