making bytes out of bits

G

George

I continue to try to implement a black word/white word encoding similar to
the treatment given in chp. 18 of _unleashed_.

#include <stdio.h>
#include <stdlib.h>

#define PATH "george.txt"
#define NUMBER 100
#define MAXFMTLEN 2000

int main(void)
{
FILE *fp;
char pattern[MAXFMTLEN];
char lbin[NUMBER];
char line[MAXFMTLEN];

if ((fp = fopen(PATH, "r")) == NULL ) {
fprintf(stderr, "can't open file\n");
exit(1);
}

sprintf(pattern, "%%*s %%%ds", NUMBER-1);



while(fgets(line, MAXFMTLEN, fp) == line){
sscanf(line, pattern , lbin);

printf("%s\n", lbin);
}



fclose(fp);
return 0;
}

// gcc -o x.exe chad6.c

output is:

C:\MinGW\source>gcc -o x.exe chad6.c

C:\MinGW\source>x
0001000000000000001
0001000000000000001
10000011001000000000000001
10000011001000000000000001
10000011001000000000000001
10000011001000000000000001
10000011001000000000000001
10000011001000000000000001
10000011001000000000000001
10000011001000000000000001
100000001111100
100000001111100
100000001111100
1000001110110111100000000000001
1000001110110111100000000000001
1000001110110111100000000000001
1000001110110111100000000000001
1000001110110111100000000000001
1000001110110111100000000000001
0001000000000000001

The next step is to herd these into bytes. I tried to follow what Jack
Klein does, but his encode.c is too complex for me to follow, and it's 20
K. I'm able to do it in fortran and know that the file I want looks like:

C:\MinGW\source>od -tx1 -Ax -v bin3.dat

C:\MinGW\source>dump bin3.dat

000000 0d 0a 10 00 22 00 06 0c 80 01 83 20 00 60 c8 00
000010 18 32 00 06 0c 80 01 83 20 00 60 c8 00 18 32 00
000020 06 03 e4 20 c8 0f 90 76 f0 00 60 ed e0 00 c1 db
000030 c0 01 83 b7 80 03 20 6f 00 06 0e de 00 08 80 01
000040

, without the initial crlf. I added that because encode.c to try to be
kosher with the usage (it would make my code garbage). Maybe, hints of of
why I don't succeed follow:

C:\MinGW\source>gcc encode1.c -o prog.exe

C:\MinGW\source>prog
usage: encode binary-input-file, t4-output-file

C:\MinGW\source>prog bin3.dat out.t4
encoded 0 rows from bin3.dat to out.t4


It's kind of a rambling post; let me restate my intent. I'd like to herd
the ones and zeroes in char lbin[NUMBER] into bytes. I have 8 bit bytes,
but there isn't any reason not to write it portably. The final byte is to
be padded with zeroes to the left. The output I believe to be correct is
the last 62 values in the hex dump.

Thanks for your comment.
--
George

I will never relent in defending America - whatever it takes.
George W. Bush

Picture of the Day http://apod.nasa.gov/apod/

--
George

Some folks look at me and see a certain swagger, which in Texas is called
"walking."
George W. Bush

Picture of the Day http://apod.nasa.gov/apod/
 
B

Barry Schwarz

I continue to try to implement a black word/white word encoding similar to
the treatment given in chp. 18 of _unleashed_.
snip code that reads a file and produces the following output
0001000000000000001
0001000000000000001
10000011001000000000000001
10000011001000000000000001
10000011001000000000000001
10000011001000000000000001
10000011001000000000000001
10000011001000000000000001
10000011001000000000000001
10000011001000000000000001
100000001111100
100000001111100
100000001111100
1000001110110111100000000000001
1000001110110111100000000000001
1000001110110111100000000000001
1000001110110111100000000000001
1000001110110111100000000000001
1000001110110111100000000000001
0001000000000000001

The next step is to herd these into bytes. I tried to follow what Jack
Klein does, but his encode.c is too complex for me to follow, and it's 20
K. I'm able to do it in fortran and know that the file I want looks like:

C:\MinGW\source>od -tx1 -Ax -v bin3.dat

C:\MinGW\source>dump bin3.dat

000000 0d 0a 10 00 22 00 06 0c 80 01 83 20 00 60 c8 00
000010 18 32 00 06 0c 80 01 83 20 00 60 c8 00 18 32 00
000020 06 03 e4 20 c8 0f 90 76 f0 00 60 ed e0 00 c1 db
000030 c0 01 83 b7 80 03 20 6f 00 06 0e de 00 08 80 01
000040

, without the initial crlf. I added that because encode.c to try to be
kosher with the usage (it would make my code garbage). Maybe, hints of of
why I don't succeed follow:

In view of the fact that line boundaries can occur in the middle of a
byte and the file can end in the middle of a byte, something like the
following could work:

Create a function
int charget(void);
which gives you the integer value of the next character of interest (0
for '0' and 1 for '1') from your input file (and EOF at the end).
Include in this function your code to populate pattern, call fgets to
fill lbin when necessary, handle input errors, etc. Most of the
variables in this function will probably need to be static.
(Alternately you could change the function signature so that the
variables are in the calling function and passed as arguments.)

In the calling program, create an outer loop that only terminates when
there is no more input data. Nest an inner loop that will execute
CHAR_BIT iterations. In each first iteration of the inner loop, set
an unsigned char to 0. In each iteration, call charget, double the
unsigned char, and add the value returned by charget. When the inner
loop terminates, write the character to your output file.

Remember to open the output file for binary.
 
B

Ben Bacarisse

George said:
I continue to try to implement a black word/white word encoding similar to
the treatment given in chp. 18 of _unleashed_.

Not everyone has that book.

It's kind of a rambling post; let me restate my intent. I'd like to herd
the ones and zeroes in char lbin[NUMBER] into bytes. I have 8 bit bytes,
but there isn't any reason not to write it portably. The final byte is to
be padded with zeroes to the left. The output I believe to be correct is
the last 62 values in the hex dump.

You don't post the code that does not work and the only description of
the task is "to herd" the zero and one characters into bytes. In
short you are limiting the help to be from people who are prepared to
intuit what you need to do (or who know by other means) and are
prepared to guess where the error might be in your code from the
sample output. I think that group is quite small.

If you post the code and a description of the task it should perform
you stand more chance of getting an answer (though probably not from
me).
 
B

Ben Bacarisse

pete said:
Ben said:
George said:
I continue to try to implement a black word/white word encoding
similar to the treatment given in chp. 18 of _unleashed_.

Not everyone has that book.

It's kind of a rambling post; let me restate my intent. I'd like
to herd the ones and zeroes in char lbin[NUMBER] into bytes. I
have 8 bit bytes, but there isn't any reason not to write it
portably. The final byte is to be padded with zeroes to the left.
The output I believe to be correct is the last 62 values in the hex
dump.

You don't post the code that does not work and the only description of
the task is "to herd" the zero and one characters into bytes. In
short you are limiting the help to be from people who are prepared to
intuit what you need to do (or who know by other means) and are
prepared to guess where the error might be in your code from the
sample output. I think that group is quite small.

If you post the code and a description of the task it should perform
you stand more chance of getting an answer (though probably not from
me).

I think he wants to write atob(),
which would be something like atoi().

If atob() is what I think, it would be even more like strtoul(line,
NULL, 2) :)
 
G

George

[5 quoted lines suppressed]
snip code that reads a file and produces the following output
[38 quoted lines suppressed]

In view of the fact that line boundaries can occur in the middle of a
byte and the file can end in the middle of a byte, something like the
following could work:

Create a function
int charget(void);
which gives you the integer value of the next character of interest (0
for '0' and 1 for '1') from your input file (and EOF at the end).
Include in this function your code to populate pattern, call fgets to
fill lbin when necessary, handle input errors, etc. Most of the
variables in this function will probably need to be static.
(Alternately you could change the function signature so that the
variables are in the calling function and passed as arguments.)

In the calling program, create an outer loop that only terminates when
there is no more input data. Nest an inner loop that will execute
CHAR_BIT iterations. In each first iteration of the inner loop, set
an unsigned char to 0. In each iteration, call charget, double the
unsigned char, and add the value returned by charget. When the inner
loop terminates, write the character to your output file.

Remember to open the output file for binary.

Thanks, Barry, I wasn't able to implement as much of this as I'd hoped.

One critical thing I don't understand is how to reshape arrays in C.

int charget(void)
{
;
}


#include <stdio.h>
#include <stdlib.h>

#define PATH "george.txt"
#define NUMBER 100
#define MAXFMTLEN 2000
#define MAXBITS NUMBER * MAXFMTLEN

int main(void)
{
FILE *fp;
char pattern[MAXFMTLEN];
char lbin[NUMBER];
char line[MAXFMTLEN];
char satz[MAXBITS];
char c;

unsigned char u;
int i, j, counter;

if ((fp = fopen(PATH, "r")) == NULL ) {
fprintf(stderr, "can't open file\n");
exit(1);
}

sprintf(pattern, "%%*s %%%ds", NUMBER-1);



while(fgets(line, MAXFMTLEN, fp) == line){
sscanf(line, pattern , lbin);


// populate satz with line
printf("%s\n", lbin);
}

while (c = charget() != EOF)

{

test to see whether zero or one
if not, write the character to a log
if yes then call a routine that iterates
through char_bits and comes out with abyte
write byte



} // end while



fclose(fp);
return 0;
}

// gcc -Wall schwartz1.c -o x.exe

I was thinking that if I created a vector that had enough bits to do the
whole thing flat, it would help.
--
George

I believe the most solemn duty of the American president is to protect the
American people. If America shows uncertainty and weakness in this decade,
the world will drift toward tragedy. This will not happen on my watch.
George W. Bush

Picture of the Day http://apod.nasa.gov/apod/
 
B

Barry Schwarz

[5 quoted lines suppressed]
snip code that reads a file and produces the following output
[38 quoted lines suppressed]

In view of the fact that line boundaries can occur in the middle of a
byte and the file can end in the middle of a byte, something like the
following could work:

Create a function
int charget(void);
which gives you the integer value of the next character of interest (0
for '0' and 1 for '1') from your input file (and EOF at the end).
Include in this function your code to populate pattern, call fgets to
fill lbin when necessary, handle input errors, etc. Most of the
variables in this function will probably need to be static.
(Alternately you could change the function signature so that the
variables are in the calling function and passed as arguments.)

In the calling program, create an outer loop that only terminates when
there is no more input data. Nest an inner loop that will execute
CHAR_BIT iterations. In each first iteration of the inner loop, set
an unsigned char to 0. In each iteration, call charget, double the
unsigned char, and add the value returned by charget. When the inner
loop terminates, write the character to your output file.

Remember to open the output file for binary.

Thanks, Barry, I wasn't able to implement as much of this as I'd hoped.

One critical thing I don't understand is how to reshape arrays in C.

What does reshape arrays mean?

snip 80+ lines of code that is both incomplete and fundamentally
inconsistent with suggested design.
 
G

George

[36 quoted lines suppressed]

What does reshape arrays mean?

Here I believe to have a char array that is x by y. You've snipped away
things I thought relevant, so let's assume they're not.

When you have a char array in C, you have a pointer to the the first
element of this array.

Maybe an eight by 5 array of chars is exactly the same as a vector of
length 40 * sizeof(char)

How does C know if an array is 4 x 2 x 3 as opposed to a vector the length
of their product?
snip 80+ lines of code that is both incomplete and fundamentally
inconsistent with suggested design.

Rats. My only reference is_unleashed_ § 11.


--
George

We will build new ships to carry man forward into the universe, to gain a
new foothold on the moon and to prepare for new journeys to the worlds
beyond our own.
George W. Bush

Picture of the Day http://apod.nasa.gov/apod/
 
T

Triple-DES

[36 quoted lines suppressed]
What does reshape arrays mean?

Here I believe to have a char array that is x by y.  You've snipped away
things I thought relevant, so let's assume they're not.  

When you have a char array in C, you have a pointer to the the first
element of this array.

An array is not a pointer. This is a FAQ.
Maybe an eight by 5 array of chars is exactly the same as a vector of
length 40 * sizeof(char)

It can't be, because a "two-dimensional" array of chars is actually an
array of arrays of char, while an array of char is just that.
How does C know if an array is 4 x 2 x 3 as opposed to a vector the length
of their product?

They are of different type.
 
G

Guest

Here I believe to have a char array that is x by y.  You've snipped away
things I thought relevant, so let's assume they're not.  

When you have a char array in C, you have a pointer to the the first
element of this array.

no. an-array-is-not-a-pointer-a-pointer-is-not-an-array.
Seee the comp.lang.c FAQ for more details. really. It explains
it much better than I could.
Maybe an eight by 5 array of chars is exactly the same as a vector of
length 40 * sizeof(char)

no. They may occupy the same amount of memory but they are not
the same thing. C soesn't have reshapable arrays. If you want one
you'll have to implement it yourself. You could declare an array
then walk a pointer to element type over it. This might do what you
want.
How does C know if an array is 4 x 2 x 3 as opposed to a vector the length
of their product?

because of how you declared it.
Rats.  My only reference is_unleashed_ § 11.

get K&R. Rea dthe FAQ.
 
G

George

no. an-array-is-not-a-pointer-a-pointer-is-not-an-array.
Seee the comp.lang.c FAQ for more details. really. It explains
it much better than I could.


Your response motivated me to go to th less-heated portion of my house to
get a hard copy of Steve Summit.
no. They may occupy the same amount of memory but they are not
the same thing. C soesn't have reshapable arrays. If you want one
you'll have to implement it yourself. You could declare an array
then walk a pointer to element type over it. This might do what you
want.

Please elaborate.

get K&R. Rea dthe FAQ.

It doesn't lend itself to serial reading as might a book. Do you have a
reference?

--
George

We don't believe in planners and deciders making the decisions on behalf of
Americans.
George W. Bush

Picture of the Day http://apod.nasa.gov/apod/
 
G

Guest

Your response motivated me to go to th less-heated portion of my house to
get a hard copy of Steve Summit.  



Please elaborate.

<snip>

I'm not sure what you are trying to do, but this reads in
a "vector" (1-d array) and prints it as a 2-d array

#include <stdlib.h>
#include <stdio.h>

#define ROWS 8
#define COLS 5

void load_flat_array (int *a, int n)
{
int i;

for (i = 0; i < n; i++)
{
if (scanf("%d", &a) != 1)
{
fprintf (stderr, "error reading number\n");
exit (EXIT_FAILURE);
}
}
}

void dump_array (int array[][COLS], int rows)
{
int i, j;

printf ("\n");

for (i = 0; i < rows; i++)
{
for (j = 0; j < COLS; j++)
printf ("%d ", array[j]);

printf ("\n");
}
}

int main (void)
{
int array [ROWS][COLS];

load_flat_array (&array[0][0], ROWS * COLS);
dump_array (array, ROWS);

return 0;
}


read sections 5.7 and 5.9
Read the FAQ.

It doesn't lend itself to serial reading as might a book.  Do you have a
reference?

well you can read it serially. And you have the FAQ book which is
more
than I do.

The FAQ may be found at http://c-faq.com/

FAQ 6.2 "But I heard that char a[] was identical to char *a"
then FAQs 6.3, 6.4, 6.8... well pretty much the whole section
 
K

Keith Thompson

Triple-DES said:
An array is not a pointer. This is a FAQ.
[...]

George didn't actually claim otherwise, and his statement is probably
true (depending on how you interpret it).

Certainly an array is not a pointer, but:

char arr[10];

when you have a char array, you (also) have (or can trivially obtain)
a pointer to the first element of this array. In particular, the
expression ``arr'', in most contexts, evaluates to a pointer to the
first element of the array object.

I'm not sure what George *meant*, and if he doesn't already know that
an array is not a pointer he certainly needs to understand that fact
(I recommend section 6 of the comp.lang.c FAQ).
 
B

Barry Schwarz

Your response motivated me to go to th less-heated portion of my house to
get a hard copy of Steve Summit.

Please elaborate.

char a[40]
char b[8][5];
char *p1;
char (*p2)[5];
p1 = a; /* legal because a is converted to char* */
p1 = b; /* illegal because b is converted to char(*)[5] */
p2 = b; /* legal as noted above */
p1 = (char*)b; /* legal because the cast changes the type */

Think about the difference between p1++ and p2++.
 
G

George

[code elided and paragraphs reordered for thematic reasons]
FAQ 6.2 "But I heard that char a[] was identical to char *a"
then FAQs 6.3, 6.4, 6.8... well pretty much the whole section

I got to that last night. It certainly makes for a better read as a hard
copy next to a fire. Given that I'm burning books based on lack of
relevacne to C, I think Steve's work will survive the heating season.
read sections 5.7 and 5.9

I think this is getting really close to what I'm not getting here.

q1) I don't understand the first example in 5.9. B is declared as
int *b[10];
and b[3][4] is syntactically legal. What gives? Is twelve less than or
equal to ten?
I'm not sure what you are trying to do, but this reads in
a "vector" (1-d array) and prints it as a 2-d array

Thanks, Nick, that's a nice little program. Output:


C:\MinGW\source>x
1
2
3
4
5
6
6
6
5
4
3
3
4
5
5
6
6
6
6
6
6
5
4
34
3
3
3
3
3
3
3
3
3
3
3
3
5
56
6


7

1 2 3 4 5
6 6 6 5 4
3 3 4 5 5
6 6 6 6 6
6 5 4 34 3
3 3 3 3 3
3 3 3 3 3
3 5 56 6 7

C:\MinGW\source>

I'll see if I can adapt it.
--
George

After the chaos and carnage of September 11th, it is not enough to serve
our enemies with legal papers.
George W. Bush

Picture of the Day http://apod.nasa.gov/apod/
 
G

George

Barry Schwarz said:


"C Unleashed" is *not* a reference book. I agree, however, that any serious
C programmer needs a high quality reference book.

I blew my standardized programming language reference book budget with a
fortran purchase that explains the standard chapter for chapter. It's been
invaluable. I put it on the floor and read it for the fifteen minutes that
they give you e-stim on your back before undergoing physical therapy (plus
you don't have to put your nose in that smothering place). And then
waiting for the American bus that doesn't come on time.

There are two titles for C I would buy regardless of my means:

1) The C 99 Handbook
, which does for C what my latest pruchase does for fortran, and,

2) The Essential Knuth in C

I've asked Santa for Harbison and Steele 5 for X-mas. If I were him, I
wouldn't come to New Mexico when they aren't just low-mentality,
aggressive, impatient, stupid, but drunk for the holidays as well. Just
because he can survive temperatures of 2000 degrees in chimneys doesn't
mean that he and his companions can't get run over by people who don't feel
the need to look in the direction in which they accelerate.
--
George

The true history of my administration will be written 50 years from now,
and you and I will not be around to see it.
George W. Bush

Picture of the Day http://apod.nasa.gov/apod/
 
G

George

char a[40]
char b[8][5];
char *p1;
char (*p2)[5];
p1 = a; /* legal because a is converted to char* */
p1 = b; /* illegal because b is converted to char(*)[5] */
p2 = b; /* legal as noted above */
p1 = (char*)b; /* legal because the cast changes the type */

Well, I tried to populate these arrays, but I get no output:



#include <stdio.h>

int main(void)
{
char a[40];
char b[8][5];


char *p1;
char (*p2)[5];

int i;
char c;

for (i=60; i = 60 + 40 ; ++ i)
{
a[i-60] = i;
}

for(i = 0; i = 40; ++ i)
{
putchar(a);
}

putchar('\n');




p1 = a; /* legal because a is converted to char* */
p1 = b; /* illegal because b is converted to char(*)[5] */
p2 = b; /* legal as noted above */
p1 = (char*)b; /* legal because the cast
changes the type */
return 0;
}
// gcc -Wall schwartz2.c -o x.exe

This compiles with the following warnings, but hangs.


C:\MinGW\source> gcc -Wall schwartz2.c -o x.exe
schwartz2.c: In function `main':
schwartz2.c:17: warning: suggest parentheses around assignment used as
truth val
ue
schwartz2.c:22: warning: suggest parentheses around assignment used as
truth val
ue
schwartz2.c:33: warning: assignment from incompatible pointer type
schwartz2.c:15: warning: unused variable `c'

C:\MinGW\source>

I usually populate integer arrays by assigning them to the index of a loop
that runs the range. I thought it would be a good thing to avoid the first
32 chars and start with sixty instead, which is zero on my implementation.

??

Think about the difference between p1++ and p2++.

One is legal; the other is not? They vary by one degree of indirection?
The drapes don't match the curtains?
--
George

States should have the right to enact laws... particularly to end the
inhumane practice of ending a life that otherwise could live.
George W. Bush

Picture of the Day http://apod.nasa.gov/apod/
 
G

George

Triple-DES <[email protected]> writes:
Certainly an array is not a pointer, but:

char arr[10];

when you have a char array, you (also) have (or can trivially obtain)
a pointer to the first element of this array. In particular, the
expression ``arr'', in most contexts, evaluates to a pointer to the
first element of the array object.

I'm not sure what George *meant*, and if he doesn't already know that
an array is not a pointer he certainly needs to understand that fact
(I recommend section 6 of the comp.lang.c FAQ).

Yeah, I've read that now and re-recommend Steve Summit to those who need a
refresher.

How is this expression legal:
5["abcdef]"
?

I was thinking about how one passes an array from C as opposed to deals
with them in the syntax in which they were defined. The way I might
distinguish the array from the pointer is like unto my trade as a builder.
You have this massive structure drawn in 3-d. The way the builder lines up
the subs is the 4th dimension, and these 2 meet when a guy like me
prominently displays the address on the house.

If C builds the array, it is guaranteed to have a pointer to (0,0,0, ...)

If, however, you're given an address, then you've got to malloc space and
fill the dimensions appropriately, which is no small feat.
--
George

Any government that supports, protects or harbours terrorists is complicit
in the murder of the innocent and equally guilty of terrorist crimes.
George W. Bush

Picture of the Day http://apod.nasa.gov/apod/
 
J

James Kuyper

George wrote:
....
q1) I don't understand the first example in 5.9. B is declared as
int *b[10];
and b[3][4] is syntactically legal. What gives? Is twelve less than or
equal to ten?

With that declaration, b is an array of 10 pointers to int. b[3] refers
to the fourth pointer in that array. b[3][4] is equivalent to *(b[3]+4),
which refers to the fourth 'int' after the one pointed at by b[3].
Whether or not such an 'int' exists and can legally be referred to
depends upon how b[3] was given it's value; it has nothing to do with
the 10 which describes the number of pointers in the array b.
 
K

Keith Thompson

James Kuyper said:
George wrote:
...
q1) I don't understand the first example in 5.9. B is declared as
int *b[10];
and b[3][4] is syntactically legal. What gives? Is twelve less than or
equal to ten?

With that declaration, b is an array of 10 pointers to int. b[3]
refers to the fourth pointer in that array. b[3][4] is equivalent to
*(b[3]+4), which refers to the fourth 'int' after the one pointed at
by b[3]. Whether or not such an 'int' exists and can legally be
referred to depends upon how b[3] was given it's value; it has nothing
to do with the 10 which describes the number of pointers in the array
b.

Right.

To elaborate a bit, the expression

b[3][4]

can actually have any of 4 different meanings, depending on how b is
declared.

The [] operator takes two operands, a pointer value and an integer
value (in either order, but we'll ignore that):
pointer_value[integer_value]
which is by definition equivalent to:
*(pointer_value + integer_value)

It's very common for the pointer value to be the result of the
implicit pointer-to-array conversion that occurs in most contexts:

double arr[10];
arr[5]; /* arr is converted from double[5] to double*,
becoming a pointer value */

But it's also common for the pointer value to be just a pointer value,
such as the value of a pointer object (which should point to the first
element of an array, but it doesn't have to be a declared array
object):

double *ptr = malloc(10 * sizeof *ptr);
if (ptr == NULL) exit(EXIT_FAILURE);
ptr[5]; /* no conversion needed, ptr is already a pointer value */

b[3][4] obviously has two [] operators, so there are four
possibilities:

1. b is a pointer, and b[3] is also a pointer.
b must therefore be a pointer to pointer, such as a char**.
char **b;

2. b is a pointer to an array.
char *b[10];

3. b is an array of pointers.
char (*b)[10];

4. b is an array of arrays, i.e., a two-dimensional array.
char b[5][6];

In all cases involving pointers, you are responsible making sure that
the pointer points to a sufficiently large object, either by
allocating memory, by assigning it to point to a declared object, or
by some other method.

When you see the expression b[3][4] (or b[x][y], or whatever), you
can't tell which of the four cases you're dealing with unless you look
at the declaration of b. But that's not much different than x + y,
where you can't tell what kind of addition is being done without
knowing the types of x and y.
 
K

Keith Thompson

George said:
Yeah, I've read that now and re-recommend Steve Summit to those who need a
refresher.

How is this expression legal:
5["abcdef]"
?
[...]

You've obviously read question 6.11. Have you read the answer? Or
was your question rhetorical?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,020
Latest member
GenesisGai

Latest Threads

Top