GIDForums  

Go Back   GIDForums > Computer Programming Forums > Miscellaneous Programming Forum
User Name
Password
Register FAQ Members List Calendar Search Today's Posts Mark Forums Read

 
 
Thread Tools Search this Thread Rate Thread
  #1  
Old 24-Oct-2006, 02:01
Justin Fox Justin Fox is offline
Junior Member
 
Join Date: Sep 2006
Posts: 46
Justin Fox is on a distinguished road

Fortran problem...


Code:
Print *, '-------------------------------' Print *, " SIMULATION STATISTICS" Print *, "-------------------------------" Print *, " High-Q: Low_Q: Total:" Print 777, 'JOBS PROCESSED: ', JOBS, JOBS(1)+JOBS(2) 777 Format (1X, A, 3I8) Print 788, 'AVERAGE QUEUE SIZES:', 1.0*TOTAL(1)/TotalTime, 1.0*TOTAL(2)/TotalTime, 0.5*(TOTAL(1) + TOTAL(2))/TotalTime 788 Format (1X, A, 3F8.2) Print 788, 'AVERAGE WAITING TIMES:', 1.0*(WAIT(1)/JOBS(1)), 1.0*(WAIT(2)/JOBS(2)), 1.0*(WAIT(1)+WAIT(2))/(JOBS(1)+JOBS(2)) Print 888, 'IDLE TIME PERCENTS:::', 100.0*IDLETIME/TotalTime 888 Format (1X, A, F10.2, "%") END DO !!!END OF ALL SIMULATION RUNS 9999 Print * Print *, "SIMULATION OVER AFTER PROCESSING", Inputs, "INPUTS." !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!


ok in the above code, I'm getting <END OF EXPRESSION> errors
and subscript errors...

I'm super confused, this code is suposed to compile, but it had a crap load
of errors...

im using f90 on a open VMS system...

here is the rest of the code...

Code:
!******************PARTIAL SOLUTION******************** ! Single-server queueing system simulation. ! Module events Implicit None Type Event Integer:: EType Integer:: OccurTime Type(Event), Pointer:: Next End Type Event Contains Subroutine Initialize (Head,Tail) Type(Event), Pointer :: Head, Tail Nullify (Head,Tail) Return End Subroutine Initialize !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Recursive Subroutine InsertEvent (Node, Head, Tail) ! Inserts the given event-node into the list ! in ascending order of occurrence time of scheduled events Type(Event), pointer :: Head, Tail Type(Event), pointer :: Node, NewHead ! Rest is left out for you to fill in !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! End Subroutine InsertEvent Subroutine DeleteEvent (H,T,Delete) ! This subroutine simply removes the first event from ! the event-queue and returns it Type(Event), pointer :: H,T Type(Event), pointer :: Delete if (.NOT.Associated(H)) then ! queue-empty and an error Print *, "ERROR:::EVENT-QUEUE IS ALREADY EMPTY" Return end if Delete => H H => H%Next ! If this new head is empty, Tail must become empty as well if (.NOT. Associated(H)) Nullify(T) return End Subroutine DeleteEvent !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! End Module Events !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! !! START OF MAIN singleServer !! Program SingleServer Use Events Implicit None Integer, parameter :: Hq=2000, Lq=4000 LOGICAL IDLE Integer HIGHQ(Hq,2), LOWQ(Lq,2), TOTAL(2),TotalTime, Inputs, K !CUMULATIVE QUEUE SIZES Integer QSIZE(2), QMAX(2), FRONT(2), JOBS(2) Integer WAIT(2) !CUMULATIVE WAITING TIMES IN EACH QUE Integer LASTCH(2) !LAST QUEUE SIZE CHANGE TIME Integer TIME ! CURRENT SIMULATION TIME Integer LASTIDLE !LAST server IDLE TIME Integer IDLETIME !CUMULATIVE server IDLE TIMES Integer OFTEN ! INTERARRIVAL TIME UpperBound Integer ServHigh !Service time upperbound Logical More Type(Event), Pointer :: Head, Tail, Node, Current Integer testing /0/ ! INITIALIZATIONS Qmax = (/Hq, Lq/) totaltime=500000 Inputs=0 More = .true. Do while(More) Print *, "--------------------------------" Print *, 'Type in' Print *, "The InterArrival Time Upperbound" Print *, 'And Service Time Upperbound!' Read(5,*,End=9999) Often, ServHigh print *, '------------------------------------------' PRINT 999, 'UPPER BOUND FOR INTERARRIVAL TIME :::', OFTEN Print 999, 'UPPER BOUND FOR SERVICE TIME:::::::::', ServHigh 999 Format (1X, A, I5) Inputs = Inputs+1 LASTIDLE=0 TIME=0 IDLETIME=0 IDLE= .TRUE. DO K=1,2 QSIZE(K)=0 TOTAL(K)=0 LASTCH(K)=0 JOBS(K)=0 WAIT(K)=0 FRONT(K)=0 end do ! Call Initialize (Head,Tail) Call MakeNode(1,0,Node) CALL InsertEvent (Node,Head,Tail) !FIRST ARRIVAL EVENT SCHEDULED Call MakeNode(2,0,Node) CALL InsertEvent (Node,Head,Tail) !FIRST FINISHING EVENT SCHEDULED Call MakeNode(3,TotalTime,Node) CALL InsertEvent (Node,Head,Tail) !SIMULATION TERMINATION ! ! LOOP TO CONTINUE THE SIMULATION BY PICKING UP AN EVENT ! after another until simulation total time comes up. TIME=Head%OccurTime DO WHILE (TIME .LT. totaltime) Select Case (Head%EType) 100 Case(1) ! NEW ARRIVAL CALL ARRIVAL IF (IDLE) CALL FINISHING 200 Case(2) ! FINISHING EVENT CALL FINISHING Case(3) ! Termination Event Call Finishing ! Just update statistics Call Qdelete(1) Call Qdelete(2) Exit Case Default ! Safety measure Print *, "ERROR: ILLEGAL EVENT TYPE IN EVENT-QUEUE:" End Select Call DeleteEvent (Head,Tail,Current) Time=Head%OccurTime ! Advance the simulation time in all cases ! unless it is over END DO !END OF ONE SIMULATION RUN ! ! END OF ONE SIMULATION RUN!!!!! ! Print *, '-------------------------------' Print *, " SIMULATION STATISTICS" Print *, "-------------------------------" Print *, " High-Q: Low_Q: Total:" Print 777, 'JOBS PROCESSED: ', JOBS, JOBS(1)+JOBS(2) 777 Format (1X, A, 3I8) Print 788, 'AVERAGE QUEUE SIZES:', 1.0*TOTAL(1)/TotalTime, 1.0*TOTAL(2)/TotalTime, 0.5*(TOTAL(1) + TOTAL(2))/TotalTime 788 Format (1X, A, 3F8.2) Print 788, 'AVERAGE WAITING TIMES:', 1.0*(WAIT(1)/JOBS(1)), 1.0*(WAIT(2)/JOBS(2)), 1.0*(WAIT(1)+WAIT(2))/(JOBS(1)+JOBS(2)) Print 888, 'IDLE TIME PERCENTS:::', 100.0*IDLETIME/TotalTime 888 Format (1X, A, F10.2, "%") END DO !!!END OF ALL SIMULATION RUNS 9999 Print * Print *, "SIMULATION OVER AFTER PROCESSING", Inputs, "INPUTS." !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Stop ! Just in case. Contains Subroutine MakeNode (EventType, EventTime, Item) Type(Event), pointer :: Item Integer EventType, EventTime, Err Allocate (Item, Stat=Err) if (Err /= 0) then Print *, "MEMORY ALLOCATION FAILURE:::" Stop end if Item%EType = EventType Item%OccurTime = EventTime Nullify (Item%Next) return End Subroutine ! Mandatory !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! SUBROUTINE QINSERT(Q,REQUEST) Integer Q, Loc, Request IF (QSIZE(Q) .GE. QMAX(Q)) THEN !QUEUE IS FULL PRINT*, 'ERROR::: QUEUE IS FULL::::', Q RETURN END IF QSIZE(Q)=QSIZE(Q)+1 LOC=FRONT(Q)+QSIZE(Q) IF (LOC .GT. QMAX(Q)) LOC=LOC-QMAX(Q) IF (Q .EQ. 1) THEN !!HIGHQ!!! HIGHQ(LOC,1)=TIME !ARRIVAL TIME!!! HIGHQ(LOC,2)=REQUEST !Service REQUEST TIME!!! ELSE LOWQ(LOC,1)=TIME LOWQ(LOC,2)=REQUEST END IF ! UPDATE CUMULATIVE QUEUE SIZE TOTAL(Q)=TOTAL(Q)+ (TIME-LASTCH(Q))*(QSIZE(Q)-1) LASTCH(Q)=TIME RETURN END Subroutine !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! SUBROUTINE QDELETE(Q) Integer Q ! This subroutine does the following: ! 1. Check to see If the given queue is empty. ! If it is then an ERROR-CASE and return. ! 2. Else ! 2.a update Front and Qsize of the queue to get the request ! time to schedule a FINISHING event by: ! Call MakeNode(2, Time+Request, Node) ! CALL InsertEvent(Node, Head, Tail) ! 2.b Update ! Total(Q) ! JOBS(Q) ! WAIT(Q) ! LastCh(Q) ! if (Qsize(Q) == 0) Front(Q) = 0 END Subroutine !********************************************* ! SUBROUTINE ARRIVAL !********************************************* SUBROUTINE ARRIVAL Integer Request, After, Type REQUEST=KRAND(ServHigh-10)+10 TYPE=1 IF (REQUEST .GT. 0.2*(ServHigh-10)+10.001) TYPE=2 CALL QINSERT(TYPE,REQUEST) AFTER=KRAND(OFTEN)! It is between 0 and OFTEN Call MakeNode(1,Time+After,Node) CALL InsertEvent(Node,Head,Tail) RETURN END Subroutine !******************************************** ! FUNCTION KRAND(MAX) !******************************************** Integer FUNCTION KRAND(MAX) ! Computes and returns an integer between ! 0 and the given MAX Integer Max Integer SEED/9753135/ Krand = Ran(Seed) * Max + 0.0001 RETURN END Function !********************************************* ! SUBROUTINE FINISHING !********************************************* SUBROUTINE FINISHING Integer front1, front2 ! THIS SUBROUTINE IS CALLED WHENEVER A JOB HAS BEEN FINISHED, ! OR THE SIMULATION IS OVER. ! HENCE, IT DOES: ! 1. IF server HAS BEEN IDLE, UPDATE CUMULATIVE IDLE TIME ! AND RESET THE LAST IDLE TIME. ! 2. IF BOTH QUEUES ARE EMPTY, RESET IDLE AND LASTIDLE, ! AND RETURN. ! 3. ELSE, IF THE LOWQUE IS EMPTY, THEN DELETE THE HIGHQUE ! 4. ELSE, IF THE HIGHQUE IS EMPTY, DELETE THE LOWQUE. ! 5. ELSE, (BOTH QUEUES ARE NON-EMPTY) SO DECIDE WHICH ! QUEUE HAS TO BE DELETED. AND DELETE THAT QUEUE AND ! RESET IDLE INDICATOR. ! In all, this subroutine deletes a queue if both are not empty ! by calling Qdelete(Q) and updates if necessary ! IdleTime ! LastIdle and ! Idle end SUBROUTINE FINISHING end Program singleServer

it's really really long, so if you can help, please do : )

Thanks,

Justin
  #2  
Old 24-Oct-2006, 10:06
davekw7x davekw7x is offline
Outstanding Member
 
Join Date: Feb 2004
Location: Left Coast, USA
Posts: 5,217
davekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to behold

Re: Fortran problem...


I don't know about your FORTRAN, but for mine (GNU f95) the old punched-card tradition of ignoring anything after column 71 still holds.

Try breaking up the statements with continuation characters in column 6:

Code:
Print 788, 'AVERAGE QUEUE SIZES:', + 1.0*TOTAL(1)/TotalTime, + 1.0*TOTAL(2)/TotalTime, + 0.5*(TOTAL(1) + TOTAL(2))/TotalTime 788 Format (1X, A, 3F8.2) Print 788, 'AVERAGE WAITING TIMES:', 1.0*(WAIT(1)/JOBS(1)), + 1.0*(WAIT(2)/JOBS(2)), + 1.0*(WAIT(1)+WAIT(2))/(JOBS(1)+JOBS(2)) Print 888, 'IDLE TIME PERCENTS:::', 100.0*IDLETIME/TotalTime 888 Format (1X, A, F10.2, "%") END DO !!!END OF ALL SIMULATION RUNS

Note that your "END DO" statement started before column 7, and was also flagged as an error (since columns 1-5 of non-comment statements are reserved for statement numbers).

Regards,

Dave


P.S.
The error message from f95 was:
Code:
In file z.f:141 Print 788, 'AVERAGE QUEUE SIZES:', 1.0*TOTAL(1)/TotalTime, 1.0* 1 Error: Syntax error in PRINT statement at (1)

Indicating an error at column 72 (Meaning that it had reached the end of the statement, and the next line was not a continuation line, so that's an error.)

I'm wondering what your error messages were (the first few anyhow).

P.S.S.
After further investigation, I found that if I put 6 or more spaces at the beginning of a line (not a tab char, but actual spaces), lines longer than 72 columns seem to be accepted (but that's for my compiler, f95; I don't know how other compilers will act.)

Bottom line: pretend you are using punched cards and look in an old 1965 FORTRAN book to see how to format your source code so that it's portable. <=== That's a joke, you know.

Daniel D. McKracken, where are you now?
Last edited by davekw7x : 24-Oct-2006 at 10:36.
  #3  
Old 24-Oct-2006, 12:54
Justin Fox Justin Fox is offline
Junior Member
 
Join Date: Sep 2006
Posts: 46
Justin Fox is on a distinguished road

Re: Fortran problem...


ok i only have one error left...

and its another <END OF STATEMENT>


here is the line of code

and error:

Code:
Print 788,'AVERAGE WAITING TIMES:',1.0*WAIT(1)/JOBS(1),1.0*WAIT(2)/JOBS(2),1.0*WAIT(1)+WAIT(2)/JOBS(1)+JOBS(2) Error: HAL> f90 singleServer.f;1 Print 788,'AVERAGE WAITING TIMES:',1.0*WAIT(1)/JOBS(1),1.0*WAIT(2)/JOBS(2 ),1.0*WAIT(1)+WAIT(2)/JOBS(1)+JOBS(2) ................................................................................ ..........................................^ %F90-E-ERROR, Syntax error, found END-OF-STATEMENT when expecting one of: :: , : ) at line number 143 in file BT22:[JXF5375]singleServer.f;1 HAL>

Justin

help me lol
  #4  
Old 24-Oct-2006, 14:17
davekw7x davekw7x is offline
Outstanding Member
 
Join Date: Feb 2004
Location: Left Coast, USA
Posts: 5,217
davekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to behold

Re: Fortran problem...


Quote:
Originally Posted by Justin Fox
ok i only have one error left...

and its another <END OF STATEMENT>

Did you try breaking it up into shorter lines with continuation statements?
Code:
Print 788,'AVERAGE WAITING TIMES:', + 1.0*WAIT(1)/JOBS(1), + 1.0*WAIT(2)/JOBS(2), + 1.0*WAIT(1)+WAIT(2)/JOBS(1)+JOBS(2)


Regards,

Dave
  #5  
Old 24-Oct-2006, 15:20
Justin Fox Justin Fox is offline
Junior Member
 
Join Date: Sep 2006
Posts: 46
Justin Fox is on a distinguished road

Re: Fortran problem...


yes, the '&' doesn't work, it throws errors, and so does the '+'

and I dont understand the use of format() so i dont really know how
to modify the output of the print statement if i wanted to shorten
the print statement that is catching a <END OF STATEMENT> ERROR..

but if I were to do that, would it still print on the same line?


Justin
  #6  
Old 24-Oct-2006, 16:21
davekw7x davekw7x is offline
Outstanding Member
 
Join Date: Feb 2004
Location: Left Coast, USA
Posts: 5,217
davekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to behold

Re: Fortran problem...


Quote:
Originally Posted by Justin Fox
yes, the '&' doesn't work, it throws errors, and so does the '+'

and I dont understand the use of format() so i dont really know how
to modify the output of the print statement if i wanted to shorten
the print statement that is catching a <END OF STATEMENT> ERROR..

but if I were to do that, would it still print on the same line?


Justin

I thought this was a course you are taking. What reference material do you have? Have you looked? Rather than just throwing something together and hoping for the best, I respectfully suggest a little study might be in order.

I'll tell you a few things that I know. Keep in mind that I learned FORTRAN many years ago, before FORTRAN 95; before FORTRAN 90; before FORTRAN 77. Some of my techniques are not really necessary, but I have never found a compiler that didn't work as long as I made my program statements like the following:

A 'C' in column 1 indicates a comment statement

If there isn't a 'C' in column 1, then columns 1-5 are reserved for statement numbers.

If columns 1-5 are blank, then a character in column 6 indicates that this is a continuation of the previous statement.

Note that in FORTRAN (at least in my FORTRAN), spaces are completely irrelevant except in character fields (stuff between quote marks). In the original FORTRAN there were no character fields in quote marks; string literals were called "Hollerith" fields and were of the form 5HHello Where there was always an integer constant, the character 'H', then the number of characters indicated by the constant. The only place where spaces were not ignored was in Hollerith fields.

Columns 7-72 are for FORTRAN stuff and columns 73 and beyond are completely ignored by the compiler. (Originally these columns were used for sequencing on the punched card decks --- not part of FORTRAN.) My advice would be to go through any FORTRAN program and if any line extends beyond column 72, then break it up into shorter lines with continuation statements.


Now as far as the FORMAT statement

Code:
788 Format (1X, A, 3F8.2)

1X means that it's a regular line. In original FORTRAN, column 1 of each line of printed output was not part of the stuff that is going to be printed, it's a "carriage control" character, so a space in the first position of the printed output told the printer that it's a regular line. A '1' in the first position told the line printer to "eject" the current page. Nowadays we might call this a "form feed" or some such thing. There were other special characters for double spacing, no spacing (that's how we got "bold face" type on line printers: print the same line twice, so that the line would look darker), and maybe even a couple more. It is very likely that modern FORTRAN output handlers simply print exactly what you give it (so a 1X would actually print a space in column 1). But traditionalists always put '1X' or some equivalent in column 1 of the output statements.

In this program's FORMAT statement number 788, the first thing (after the space in column 1) to be printed is a character field; that's what the 'A' means. So anything that uses this format statement will put some kind of character field first.

The 3F8.2 means that there are three fields for "real" variables (that's what FORTRAN calls its floating point data type --- at least it did in the old days). Each field is eight columns wide and prints its number in fixed point format with 2 decimal digits after the decimal point.

Note that a print statement that uses this format statement can have any number of floating point number values. If there are fewer than 3, then that number is printed. If there are more variables than there are fields in the FORMAT statement, the FORMAT scanner starts all over again. It goes back to the first field of the FORMAT statement (the character field) and picks up the same sequence of variables all over again. (You can cause different behavior by putting parentheses around the numerical field specifications.)

I'll show an example. I use "engineering" notation (e15.7 would print in "scientific" notation with a zero and a decimal fraction and an exponent. 1pe1t.7 prints with a single-digit integer before the decimal point and the exponent).
Code:
x = 1.0 y = 2.0 z = 3.0 PRINT 999, 'Hi! : ', x, y, z PRINT 999, 'Second time : ', x PRINT 999, 'Third time : ', x, y, z, More stuff : ', x+y, x+y+z 999 FORMAT (1X, A, 1p3e15.7) STOP END

Note that the longest line goes exactly to column 72

Output
Code:
Hi! : 1.0000000E+00 2.0000000E+00 3.0000000E+00 Second time : 1.0000000E+00 Third time : 1.0000000E+00 2.0000000E+00 3.0000000E+00 More stuff : 3.0000000E+00 6.0000000E+00

Now change the third print statement to
Code:
PRINT 999, 'Third time : ', x, y, z, 'Continuing : ', x+y, x+y+z*3

The output is exactly the same as before, since the compiler ignored columns 73 and beyond (it doesn't know about the *3). Note that this isn't an error, since the compiler stopped scanning at the end of a perfectly valid statement. In the case of GNU f95, if I turn on the warning messages (use f95 -W on the command line), it gives me a warning:

Code:
In file z.f:6 PRINT 999, 'Third time : ', x, y, z, 'More stuff : ', x+y, x+y+z 1 Warning: Line truncated at (1)

So I can see what is wrong. If your compiler has command-line switches to make it emit warnings, I strongly suggest that you use them.

I can break it up into two lines with a continuation statement:
Code:
PRINT 999, 'Third time : ', x, y, z, + 'More stuff : ', x+y, x+y+z*3

Note that the '+' must be in column 6 for my compiler, as it did in the old days.

Code:
Hi! : 1.0000000E+00 2.0000000E+00 3.0000000E+00 Second time : 1.0000000E+00 Third time : 1.0000000E+00 2.0000000E+00 3.0000000E+00 More stuff : 3.0000000E+00 1.2000000E+01

Note that I can break the source line anywhere I want to, but I choose to break it in some way that allows me to inspect it alongside my printout so that I can see what the heck is going on and where the heck the output came from.

Regards,

Dave
Last edited by davekw7x : 24-Oct-2006 at 17:28.
  #7  
Old 24-Oct-2006, 16:30
davekw7x davekw7x is offline
Outstanding Member
 
Join Date: Feb 2004
Location: Left Coast, USA
Posts: 5,217
davekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to behold

Re: Fortran problem...


Quote:
Originally Posted by Justin Fox
yes, the '&' doesn't work, it throws errors, and so does the '+'

Did you paste my statements into your program exactly as I showed? (continuation character in column 6)

Quote:
Originally Posted by Justin Fox
and I dont understand the use of format()

Quote:
Originally Posted by Justin Fox
so i dont really know how
to modify the output of the print statement if i wanted to shorten
the print statement that is catching a <END OF STATEMENT> ERROR..

Making the statement continue onto the next line has nothing to do with the nature of the statement itself. You can use continuation for any FORTRAN statement.
 
 

Recent GIDBlogProblems with the Navy (Chiefs) by crystalattice

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
Buffer problem with CD-RWriter KieranC Computer Software Forum - Windows 2 07-Jan-2006 02:45
Graphic problem in Unreal Tournament 2004 zerox Computer Software Forum - Games 10 09-Oct-2005 13:31
Runtime Problem involving "printf" in C Program supamakia C Programming Language 2 09-Oct-2005 11:09
a significant problem after installing Xp mohammad Computer Software Forum - Windows 10 09-Aug-2005 08:03

Network Sites: GIDNetwork · GIDWebHosts · GIDSearch · Learning Journal by J de Silva, The

All times are GMT -6. The time now is 06:15.


vBulletin, Copyright © 2000 - 2009, Jelsoft Enterprises Ltd.