×
INTELLIGENT WORK FORUMS
FOR COMPUTER PROFESSIONALS

Contact US

Log In

Come Join Us!

Are you a
Computer / IT professional?
Join Tek-Tips Forums!
  • Talk With Other Members
  • Be Notified Of Responses
    To Your Posts
  • Keyword Search
  • One-Click Access To Your
    Favorite Forums
  • Automated Signatures
    On Your Posts
  • Best Of All, It's Free!

*Tek-Tips's functionality depends on members receiving e-mail. By joining you are opting in to receive e-mail.

Posting Guidelines

Promoting, selling, recruiting, coursework and thesis posting is forbidden.

Students Click Here

calculate average

calculate average

calculate average

(OP)
Hello eyeryone,

i've tried to calculate an average of hourly meteorological values to a daily value.

here is an example of the ascii file:

                                             pres2  wdsp
12100  2000010106    0.5   -0.3     -9.0     -9.0    2  -9.0    1.5    0.0   1.0
12100  2000010107    0.2   -0.6     -9.0     -9.0    4  -9.0  -99.0  -99.0  -5.0
12100  2000010108    0.2   -0.6     -9.0   1023.3    3  -9.0  -99.0  -99.0  -5.0
12100  2000010109    0.2   -0.6     -9.0     -9.0    3  -9.0  -99.0  -99.0  -5.0
12100  2000010110    0.6   -0.2     -9.0     -9.0    3  -9.0  -99.0  -99.0  -5.0
12100  2000010111    0.9   -0.1   1021.9     -9.0    3  -9.0  -99.0  -99.0  -5.0
12100  2000010112    1.1    0.1     -9.0     -9.0    4  -9.0  -99.0  -99.0  -5.0
12100  2000010113    1.2    0.0     -9.0   1023.3    4  -9.0  -99.0  -99.0  -5.0
12100  2000010114    1.2    0.0     -9.0     -9.0    2  -9.0  -99.0  -99.0  -5.0
12100  2000010115    1.0    0.3     -9.0     -9.0    3  -9.0  -99.0  -99.0  -5.0
12100  2000010116    0.8    0.0     -9.0     -9.0    3  -9.0  -99.0  -99.0  -5.0
12100  2000010117    0.6    0.1     -9.0   1019.8    3  -9.0  -99.0  -99.0  -5.0
12100  2000010118    0.5   -0.3     -9.0     -9.0    3  -9.0    1.4   -0.1  -5.0
12100  2000010206    2.4    2.2   1023.3   1022.6    2  -9.0    2.5    0.0   2.5
12100  2000010207    3.2    3.0   1023.8   1023.1    2  -9.0  -99.0  -99.0  -5.0
12100  2000010208    3.4    2.9     -9.0     -9.0    4  -9.0  -99.0  -99.0  -5.0
12100  2000010209    3.6    2.9   1024.5   1023.8    2  -9.0  -99.0  -99.0  -5.0
12100  2000010210    3.5    3.0   1024.0   1023.3    4  -9.0  -99.0  -99.0  -5.0

I want the daily value of the 6th and 7th column. So I write a fortran program. Here's an extract:

       days=0
       valu=pres2(0)
5     CONTINUE
       DO j=1,length
         IF (pres2(j) <= 0) THEN
         GOTO 5
           IF (day(j) == day(j-1) .AND. j /= length) THEN
             counter=counter+1
             valu=valu+pres2(j)
           ELSEIF (day(j) /= day(j-1) .OR. j == length) THEN
               days=days+1
                 tgl(days)=valu/REAL(counter)
                 y(days)=year(j-1)
                 m(days)=month(j-1)
                 d(days)=day(j-1)
             counter=1
             valu=pres2(j)
           
           ENDIF
         ENDIF
       ENDDO

       days=0
       valu=wdsp(0)
       DO j=1,length
         IF (day(j) == day(j-1) .AND. j /= length) THEN
           counter=counter+1
           valu=valu+wdsp(j)
         ELSEIF (day(j) /= day(j-1) .OR. j == length) THEN
             days=days+1
               tgl(days)=wert/REAL(counter)
               y(days)=jahr(j-1)
               m(days)=monat1(j-1)
               d(days)=tag1(j-1)
           counter=1
           wert=wdsp1(j)
         ENDIF
       ENDDO



When I run the program i get this outfile:

   00000         NaN      0.00        0.00
20000101      12100.      3.08      228.85
20000102      12100.      2.50      764.75

The 7th column is calculate correctly but the 6th isn't. It's because of the -9.0 values (-9.0 values mean there are no values for this hour so the program should skip this value)

How can I solve this problem correctly?

Thank you in advance
 

RE: calculate average

Well, you know IF statement so what's a problem to add "if abs(value-9) >= eps tnen don't add value to sum" condition in the code?

What happens with day(j-1) when j == 1 in your loops?
 

RE: calculate average

(OP)
Hello ArkM,

thanks for your answer. I've tried to do but it didn't work. I am a Fortran Newbe. Maybe I upload the Program and the Ascii File.

CODE

        PROGRAM taeglich
       
       IMPLICIT NONE
!***********************************************************************
!****************       Variablendeklaration       *********************
!***********************************************************************
       INTEGER                              :: i, eps=-9
       INTEGER, PARAMETER                   :: Anz=1000
       INTEGER                              :: year, month, day, hour
       INTEGER                              :: bed,rich,wdsp
       INTEGER                              :: statNr
       REAL                                 :: temp,tau,druck1,druck2,tmin,tmax,rr24,rr6,sndur,tm,rboe,rboeh
       
       
       INTEGER                                          :: j, length, counter, days, valu
       INTEGER, PARAMETER                               :: z=1000
       INTEGER, ALLOCATABLE, DIMENSION (:)              :: year1, month1, day1, hour1
       INTEGER, ALLOCATABLE, DIMENSION (:)              :: statNr1  ! WMO Nummer
       INTEGER, ALLOCATABLE, DIMENSION (:)              :: wdsp1    ! Windspeed
       REAL, ALLOCATABLE, DIMENSION (:)                 :: temp1    ! Temperature
       REAL, ALLOCATABLE, DIMENSION (:)                 :: tau1     ! Dew Point
       REAL, ALLOCATABLE, DIMENSION (:)                 :: druck11  ! Pressure11
       REAL, ALLOCATABLE, DIMENSION (:)                 :: druck21  ! Pressure21
       REAL, ALLOCATABLE, DIMENSION (:)                 :: tmin1    ! Minimum Temperatur
       REAL, ALLOCATABLE, DIMENSION (:)                 :: tmax1    ! Maximum Temperatur
       REAL, ALLOCATABLE, DIMENSION (:)                 :: rr241    ! Pricipitation
       REAL, ALLOCATABLE, DIMENSION (:)                 :: rboe1    ! Gust
       REAL, ALLOCATABLE, DIMENSION (:)                 :: daily
       INTEGER, ALLOCATABLE, DIMENSION (:)              :: y, m, d
       
   
! ----> Outputfile


       OPEN(20,FILE='poland_red.txt')
       
! ----> Opening Landfile

       OPEN(10,FILE='poland_copy.txt')
       
! ----> Read and Write File

       DO i=1,Anz
         READ(10,'(I4,I2,I2,I2,2X,I5,2X,I2,2X,I2,1X,I3,2X,F5.1,2X, '//&
                  'F5.1,1X,F7.1,1X,F7.1,2X,F5.1,2X,F5.1,3X,F4.1,3X, '//&
                  'F4.1,3X,F4.1,2X,F5.1,2X,F4.1,2X,F4.1)',END=1) year,month,&
                  day,hour,statNr,bed,rich,wdsp,temp,tau,druck1,druck2,&
                  tmin,tmax,rr24,rr6,sndur,tm,rboe,rboeh
         WRITE(20,'(I5,2X,I4,I2.2,I2.2,I2.2,2X,F5.1,2X,F5.1,2X,F7.1, '//&
                  '2X,F7.1,2X,I3,2X,F4.1,2X,F5.1,2X,F5.1,2X,F4.1)') statNr,&
                  year,month,day,hour,temp,tau,druck1,druck2,wdsp,rboe,&
                  tmax,tmin,rr24
       
       ENDDO
       
1      CONTINUE

       PRINT*, '----->  Umwandlung fertig <-----'
      
       CLOSE(10)
       CLOSE(20)
       
       
!-----> Speicher fuer die Variablen der eingelesenen Dateien reservieren

       ALLOCATE (year1(z))
       ALLOCATE (month1(z))
       ALLOCATE (day1(z))
       ALLOCATE (hour1(z))
       ALLOCATE (statNr1(z))
       ALLOCATE (wdsp1(z))
       ALLOCATE (temp1(z))
       ALLOCATE (tau1(z))
       ALLOCATE (druck11(z))
       ALLOCATE (druck21(z))
       ALLOCATE (tmin1(z))
       ALLOCATE (tmax1(z))
       ALLOCATE (rr241(z))
       ALLOCATE (rboe1(z))      
       
       OPEN(30,FILE='poland_red.txt',STATUS='OLD')
         DO j=1,z
           READ(30,'(I5,2X,I4,I2.2,I2.2,I2.2,2X,F5.1,2X,F5.1,2X,F7.1, '//&
                   '2X,F7.1,2X,I3,2X,F4.1,2X,F5.1,2X,F5.1,2X,F4.1)',END=2) statNr1(j),&
                    year1(j),month1(j),day1(j),hour1(j),temp1(j),tau1(j),&
                    druck11(j),druck21(j),wdsp1(j),rboe1(j),tmax1(j),tmin1(j),rr241(j)
           length=j
         ENDDO

2        CONTINUE

         CLOSE(30)
         
!-----> Speicher fuer die Output-Datein reservieren

        ALLOCATE (daily(CEILING(length/3.)))
        ALLOCATE (y(CEILING(length/3.)))
        ALLOCATE (m(CEILING(length/3.)))
        ALLOCATE (d(CEILING(length/3.)))
        
!-----> Mittelwerte werden berechnet

       

       days=0
       valu=wdsp1(0)
       DO j=1,length
         IF (day1(j) == day1(j-1) .AND. j /= length .AND. abs(valu-9) > eps) THEN
           counter=counter+1
           valu=valu+wdsp1(j)
         ELSEIF (day1(j) /= day1(j-1) .OR. j == length) THEN
             days=days+1
               daily(days)=valu/REAL(counter)
               y(days)=year1(j-1)
               m(days)=month1(j-1)
               d(days)=day1(j-1)
           counter=1
           valu=wdsp1(j)
         ENDIF
       ENDDO
       

       
!-----> Speicher wieder freimachen


       DEALLOCATE (year1)
       DEALLOCATE (month1)
       DEALLOCATE (day1)
       DEALLOCATE (hour1)
       DEALLOCATE (statNr1)
       DEALLOCATE (wdsp1)
       DEALLOCATE (temp1)
       DEALLOCATE (tau1)
       DEALLOCATE (druck11)
       DEALLOCATE (druck21)
       DEALLOCATE (tmin1)
       DEALLOCATE (tmax1)
       DEALLOCATE (rr241)
       DEALLOCATE (rboe1)


       OPEN(40,FILE='poland_test.txt')
       DO j=1,days
         WRITE(40,'(I4,I2.2,I2.2,6X,F6.2)') y(j),m(j),d(j),daily(j)
       ENDDO
       CLOSE(40)
       

       DEALLOCATE (daily)
       DEALLOCATE (y)
       DEALLOCATE (m)
       DEALLOCATE (d)

       
       END PROGRAM taeglich


 

RE: calculate average

Wait a bit, sorry. Do you want to calculate an average of all wdsp1 elements except -9?

If so
1. Why wdsp1 is an INTEGER array? I see that correspondent column contains REAL values.
2. wdsp1 indicies range is 1 to z. No such element as vdsp1(0).
3. I can't understand what DO j=1,length loop calculates...

Some correction to my previous post. If you want to test reals x and y on "is equal", use a SMALL real number (called eps in my post - 1D-6 or 1E-6, for example) and use an abs difference x-y:

CODE

IF (abs(x-y) < eps) THEN ! yes, x == y (almost equal to;)
...
! or
IF (abs(x-y) > eps) THEN ! no, x != y (I'm sure;)
...

Don't add wdsp1 values -9 to sum, skip them - that's all. Calculate sum of k values then divide sum/k to get an average...
 

RE: calculate average

(OP)
Hello ArkM,

it is not so easy you just described.

First of all: The first column in poland_copy.txt is the "date" in format YYYYMMDDHH. So there exists hourly measurments. I want calculate a DAILY average, not just an average of all wdsp1. Thats why i need the loop j=1,length. (It should check when a new day start so that the counter can be set to counter=1 again)

In the inputfile (poland_copy.txt) wdsp1 (column 5) is an integer. When i do calculate the DAILY average the output has to be real.

I hope it is now clear what i want to do

Cheers

 

RE: calculate average

Hallo KyrieXuX,

Your data file seems to be sorted according to date field (2.column).
If it's true, then you can use the technique called Control Break Processing.
/In german - I see some german words in your source smile - it's known as Normierte Programmierung or Gruppenwechsel/

Example::
For the given data file, sorted according to date in format YYYYMMDDhh (2.column)
control_break.dat

CODE

12100  2000010106    0.5   -0.3     -9.0     -9.0    2  -9.0    1.5    0.0   1.0
12100  2000010107    0.2   -0.6     -9.0     -9.0    4  -9.0  -99.0  -99.0  -5.0
12100  2000010108    0.2   -0.6     -9.0   1023.3    3  -9.0  -99.0  -99.0  -5.0
12100  2000010109    0.2   -0.6     -9.0     -9.0    3  -9.0  -99.0  -99.0  -5.0
12100  2000010110    0.6   -0.2     -9.0     -9.0    3  -9.0  -99.0  -99.0  -5.0
12100  2000010111    0.9   -0.1   1021.9     -9.0    3  -9.0  -99.0  -99.0  -5.0
12100  2000010112    1.1    0.1     -9.0     -9.0    4  -9.0  -99.0  -99.0  -5.0
12100  2000010113    1.2    0.0     -9.0   1023.3    4  -9.0  -99.0  -99.0  -5.0
12100  2000010114    1.2    0.0     -9.0     -9.0    2  -9.0  -99.0  -99.0  -5.0
12100  2000010115    1.0    0.3     -9.0     -9.0    3  -9.0  -99.0  -99.0  -5.0
12100  2000010116    0.8    0.0     -9.0     -9.0    3  -9.0  -99.0  -99.0  -5.0
12100  2000010117    0.6    0.1     -9.0   1019.8    3  -9.0  -99.0  -99.0  -5.0
12100  2000010118    0.5   -0.3     -9.0     -9.0    3  -9.0    1.4   -0.1  -5.0
12100  2000010206    2.4    2.2   1023.3   1022.6    2  -9.0    2.5    0.0   2.5
12100  2000010207    3.2    3.0   1023.8   1023.1    2  -9.0  -99.0  -99.0  -5.0
12100  2000010208    3.4    2.9     -9.0     -9.0    4  -9.0  -99.0  -99.0  -5.0
12100  2000010209    3.6    2.9   1024.5   1023.8    2  -9.0  -99.0  -99.0  -5.0
12100  2000010210    3.5    3.0   1024.0   1023.3    4  -9.0  -99.0  -99.0  -5.0
you have one key (i.e. the date in format YYYYMMDD as a portion of 2.column), so you will only have to program one group change (Gruppenwechsel), i.e. print the summary when this key changes. Something like this:
control_break.f95

CODE

program control_break
  ! Single-Level Control Break Processing

  implicit none

  integer :: stat, nr_records
  real :: dummy
  ! global variables  
  integer :: date, date_save, col02, nr_col06, nr_col07, tnr_col06, tnr_col07
  real :: col06, col07, sum_col06, sum_col07, tsum_col06, tsum_col07
  common date, date_save, col02, col06, col07, &
         nr_col06, nr_col07, sum_col06, sum_col07, &
         tnr_col06, tnr_col07, tsum_col06, tsum_col07

  ! open file
  open (1, file='control_break.dat', status='old', iostat=stat)
  if (stat .ne. 0) then
    write(*,*) 'File cannot be opened !'
    go to 99
  end if

  write(*, '(80A)') '*******************************************************'
  ! process file
  nr_records = 0
  date_save = 0

  do while (.true.)
    ! read record
    read(1, *, end=99) dummy, col02, dummy, dummy, dummy, col06, col07
    nr_records = nr_records + 1
    call process_record
    call save_keys
  enddo

  99 continue
  ! at end print totals
  call print_daily_summary
  call print_total_summary  
  write(*, 10) nr_records
  write(*, '(80A)') '*******************************************************'
  ! close file
  close(1)

  10 format('Processing of',1X, I0, 1X, 'lines finished.')
end program control_break

subroutine process_record
  implicit none
  ! global variables
  integer :: date, date_save, col02, nr_col06, nr_col07, tnr_col06, tnr_col07
  real :: col06, col07, sum_col06, sum_col07, tsum_col06, tsum_col07
  common date, date_save, col02, col06, col07, &
         nr_col06, nr_col07, sum_col06, sum_col07, &
         tnr_col06, tnr_col07, tsum_col06, tsum_col07

  ! compute date
  date = col02/100

  ! if not on first record
  if (date_save .ne. 0) then
    ! process control break
    call process_control_break
  end if

  ! print line
  write(*, 10) col02, col06, col07

  ! compute sum of col06
  if (col06 .ne. -9.0) then
    nr_col06 = nr_col06 + 1
    sum_col06 = sum_col06 + col06
    tnr_col06 = tnr_col06 + 1
    tsum_col06 = tsum_col06 + col06
  end if

  ! compute sum of col07
  if (col07 .ne. -9.0) then
    nr_col07 = nr_col07 + 1
    sum_col07 = sum_col07 + col07
    tnr_col07 = tnr_col07 + 1
    tsum_col07 = tsum_col07 + col07
  end if

  10 format(5X, I10, 1X, f8.2, 1X, f8.2)
end subroutine process_record

subroutine process_control_break
  implicit none
  ! global variables
  integer :: date, date_save, col02, nr_col06, nr_col07, tnr_col06, tnr_col07
  real :: col06, col07, sum_col06, sum_col07, tsum_col06, tsum_col07
  common date, date_save, col02, col06, col07, &
         nr_col06, nr_col07, sum_col06, sum_col07, &
         tnr_col06, tnr_col07, tsum_col06, tsum_col07

  if (date .ne. date_save) then
     call print_daily_summary
  end if
end subroutine process_control_break

subroutine print_daily_summary
  implicit none
  ! global variables
  integer :: date, date_save, col02, nr_col06, nr_col07, tnr_col06, tnr_col07
  real :: col06, col07, sum_col06, sum_col07, tsum_col06, tsum_col07
  common date, date_save, col02, col06, col07, &
         nr_col06, nr_col07, sum_col06, sum_col07, &
         tnr_col06, tnr_col07, tsum_col06, tsum_col07

  write(*, *)
  write(*, 10) date_save
  write(*, 20) sum_col06, sum_col07
  write(*, 30) nr_col06, nr_col07
  write(*, 40) sum_col06/nr_col06, sum_col07/nr_col07
  write(*, *)

  10 format('*  Summary for date',1x,I8,':')
  20 format('*  sum:',9x, f8.2, 1x, f8.2)
  30 format('*  count:',7x,I8,1x,I8)
  40 format('*  average:',5x, f8.2, 1x, f8.2)

  ! initialize gloabal variables
  sum_col06 = 0
  sum_col07 = 0
  nr_col06 = 0
  nr_col07 = 0
end subroutine print_daily_summary

subroutine print_total_summary
  implicit none
  ! global variables
  integer :: date, date_save, col02, nr_col06, nr_col07, tnr_col06, tnr_col07
  real :: col06, col07, sum_col06, sum_col07, tsum_col06, tsum_col07
  common date, date_save, col02, col06, col07, &
         nr_col06, nr_col07, sum_col06, sum_col07, &
         tnr_col06, tnr_col07, tsum_col06, tsum_col07

  write(*, 10)
  write(*, 20) tsum_col06, tsum_col07
  write(*, 30) tnr_col06, tnr_col07
  write(*, 40) tsum_col06/tnr_col06, tsum_col07/tnr_col07

  10 format('** Summary for all dates:')
  20 format('** sum:',9x, f8.2, 1x, f8.2)
  30 format('** count:',7x,I8,1x,I8)
  40 format('** average:',5x, f8.2, 1x, f8.2)
end subroutine print_total_summary

subroutine save_keys
  implicit none
  ! global variables
  integer :: date, date_save, col02, nr_col06, nr_col07, tnr_col06, tnr_col07
  real :: col06, col07, sum_col06, sum_col07, tsum_col06, tsum_col07
  common date, date_save, col02, col06, col07, &
         nr_col06, nr_col07, sum_col06, sum_col07, &
         tnr_col06, tnr_col07, tsum_col06, tsum_col07

  date_save = date
end subroutine save_keys
The output is:

CODE

$ gfortran control_break.f95 -o control_break

$ control_break
*******************************************************
     2000010106    -9.00     2.00
     2000010107    -9.00     4.00
     2000010108  1023.30     3.00
     2000010109    -9.00     3.00
     2000010110    -9.00     3.00
     2000010111    -9.00     3.00
     2000010112    -9.00     4.00
     2000010113  1023.30     4.00
     2000010114    -9.00     2.00
     2000010115    -9.00     3.00
     2000010116    -9.00     3.00
     2000010117  1019.80     3.00
     2000010118    -9.00     3.00

*  Summary for date 20000101:
*  sum:          3066.40    40.00
*  count:              3       13
*  average:      1022.13     3.08

     2000010206  1022.60     2.00
     2000010207  1023.10     2.00
     2000010208    -9.00     4.00
     2000010209  1023.80     2.00
     2000010210  1023.30     4.00

*  Summary for date 20000102:
*  sum:          4092.80    14.00
*  count:              4        5
*  average:      1023.20     2.80

** Summary for all dates:
** sum:          7159.20    54.00
** count:              7       18
** average:      1022.74     3.00
Processing of 18 lines finished.
*******************************************************
However, I used common block for global variables, which is not very nice in modern fortran, so I suggest you rather to use module.

RE: calculate average

a subtle note i thought might be worth mentioning.

the above programs by KyrieXuX and mikrom basically have the same purpose and outcome. but, one small difference i noticed between the programs is the way in which the input data is read in -- KyrieXuX uses 'FORMATTED input' READ statements, whereas mikrom uses 'UNFORMATTED input' READ statements. for example:


FORMATTED input READ statement
READ(10,(I5,2X,I4,2X,F5.1,etc))var1,var2,var3,...


UNFORMATTED input READ statement
READ(10,*)var1,var2,var3,...



when i was taught fortran (many years ago!), i was told that, with FORMATTED input/READ, the input must be 'exactly' as you specify in your READ statement (i.e. if it's not, then it might not all get read in properly). with UNFORMATTED input, however, the input does not have to be as 'exact' (i.e. you can be sloppy with the amount of space there is between different variable values in the input data file, as long as there IS space between them).

i was also told that using UNFORMATTED input/READ is generally safer, although there may be some instances when FORMATTED input/READ should be used instead. i was also told that it is usually best to use FORMATTING with output only (i.e. FORMATTED output, using WRITE statements, like it is used in the above programs by KyrieXuX and mikrom), rather than input.


anyway, i don't know whether this could also have been affecting the results that KyrieXuX is trying to achieve.

RE: calculate average

Yes I used unformatted read, because I don't know exactly format of the input file, i.e. how many white spaces are between the numeric columns.

Other difference is in the processing:

Classical quick approach is first to read a file into one or more arrays and then process the arrays, but with large files this could be very memory consument, could have limitations with allocating large arrays...etc.

With Control Break Processing technique we don't need to use arrays. The file is readed and processed at naturally way - in one pass. There are not limits concerning the file size.
 

RE: calculate average

just a remark about the wording : read(10,*) is NOT an unformatted reading but a list directed reading using a default free format. There is a format represented by "*". Such reading form is sometimes called the free format reading (but "list directed" is the official name). The two forms mentioned by billgray1234 (fixed format and list directed) are both useful to read formatted files (usually human readable files).

An unformatted reading is performed when reading an unformatted file. In that case,the read statement looks like : read(10) a,b... Here there is no format at all ! And such a file is not human readable (except if you are able to understand binary coding).

François Jacq

RE: calculate average

good points, FJacq and mikrom. thank you for clearing that up.

Red Flag This Post

Please let us know here why this post is inappropriate. Reasons such as off-topic, duplicates, flames, illegal, vulgar, or students posting their homework.

Red Flag Submitted

Thank you for helping keep Tek-Tips Forums free from inappropriate posts.
The Tek-Tips staff will check this out and take appropriate action.

Reply To This Thread

Posting in the Tek-Tips forums is a member-only feature.

Click Here to join Tek-Tips and talk with other members! Already a Member? Login

Close Box

Join Tek-Tips® Today!

Join your peers on the Internet's largest technical computer professional community.
It's easy to join and it's free.

Here's Why Members Love Tek-Tips Forums:

Register now while it's still free!

Already a member? Close this window and log in.

Join Us             Close