Madinventions
|
| posted on 6/1/10 at 11:48 PM |
|
|
Flick back to page 2... there's been some editing!
You need to do something like this to check for numstr [ i ] = 0 every time around the loop. If the terminator is found, the routine stops
printing.
--CODE--
i=0;
while(numstr [ i ]!=0 && i<4)
{
lcd_gotoxy(i,1);
lcd_putc(numstr[ i ]);
i++;
}
--END OF CODE--
Ed.
Mojo build diary: http://www.madinventions.co.uk
Solo music project: Syrrenfor http://www.reverbnation.com/syrrenfor
View my band website:
http://www.shadowlight.org.uk
http://www.eastangliankitcars.co.uk/
|
|
|
|
|
iank
|
| posted on 6/1/10 at 11:49 PM |
|
|
[quote][i]Originally posted by AdrianH[/i]
How do I cope with the variable null position?
Or changing null position even
[Edited on 6-1-10 by AdrianH] [/quote]
i=0;
while(numstr[i])
{
lcd_goto...;
lcd_putc...;
i++;
}
This trundles through the string stopping when it gets to the first NULL. itoa had better be putting one in (or you are clearing the string out
first as shown in my last post). madinventions code will work fine, but will add code that should never be called if itoa is doing its job.
Out of order threads are sooo hard to read 
[Edited on 6/1/10 by iank]
[Edited on 6/1/10 by iank]
--
Never argue with an idiot. They drag you down to their level, then beat you with experience.
Anonymous
|
|
|
AdrianH
|
| posted on 6/1/10 at 11:53 PM |
|
|
I am editing code and trying out in the next few minutes. Will report back, yes posts are getting fun to follow, going back over them and can now see
the code from a few posts ago.
Need two computers one to follow and one to programme.
Why do I have to make the tools to finish the job? More time then money.
|
|
|
AdrianH
|
| posted on 7/1/10 at 12:12 AM |
|
|
YIPEEEEE!
Here is the code section.
code:
if(plen==0){
lcd_clrscr();
lcd_puts("Xacc Yacc Zacc" ;
//select ADC1 and Use 3.3 Vcc as reference with cap at AREF pin
//Also set right adjusted in the result
ADMUX =0x41; //ADC1
delay_ms(1);
// start the conversion
ADCSRA |= 0x40;
while((ADCSRA&0x40) == 0x40){
continue;
}
xacc = (ADC/25)-19; //put value into xacc
itoa(xacc,numstr,10); // convert integer to string
i=0;
while(numstr [ i ]!=0 && i<4)
{
lcd_gotoxy(i,1);
lcd_putc(numstr[ i ]);
i++;
}
// ADC2
ADMUX =0x42; //ADC2
delay_ms(1);
// start the conversion
ADCSRA |= 0x40;
while((ADCSRA&0x40) == 0x40){
continue;
}
yacc = 0; //put value into xacc
itoa(yacc,numstr,10); // convert integer to string
i=0;
while(numstr [ i ]!=0 && i<4)
{
lcd_gotoxy(i+5,1);
lcd_putc(numstr[ i ]);
i++;
}
// ADC3
ADMUX =0x43; //ADC3
delay_ms(1);
// start the conversion
ADCSRA |= 0x40;
while((ADCSRA&0x40) == 0x40){
continue;
}
zacc = -5; //put value into xacc
itoa(zacc,numstr,10); // convert integer to string
i=0;
while(numstr [ i ]!=0 && i<4)
{
lcd_gotoxy(i+10,1);
lcd_putc(numstr[ i ]);
i++;
}
delay_ms(500);
// Ending accellerometer section here
continue;
}
the display works
code:
Xacc Yacc Zacc
0 0 -5
or
Xacc Yacc Zacc
4 0 -5
depending on ADC in Xacc as others still fixed
[Edited on 7-1-10 by AdrianH]
[Edited on 7-1-10 by AdrianH]
Why do I have to make the tools to finish the job? More time then money.
|
|
|
Madinventions
|
| posted on 7/1/10 at 12:13 AM |
|
|
EDIT to say 'Yippee!' too!
Ok, there's going to be a formatting problem with my previous code as it doesn't do the decimal point positons for you.
Here's some code that should do it and includes the numstr clearing correctly suggested earlier. Again, I've unwrapped the code to make
it easier to follow (hopefully)!! It's not pretty, but...
--CODE--
int16_t xacc=0, // signed integer value for g
char numstr[4]; // string variable
numstr[0]=0;
numstr[1]=0;
numstr[2]=0;
numstr[3]=0;
xacc = (adc/25)-19;
itoa(xacc,numstr,10); // convert integer to string
// 0 = "0", -1 = "-1", -10 = "-10", 1 = "1", 10 = "10"
// Modify so 0 = " 0.0", -1 = "-0.1", -10="-1.0", 1=" 0.1", 10 = " 1.0"
// This will get messy!
if (xacc>=0 && xacc<10) // 0 to 9 -> " 0.0" to " 0.9"
{
lcd_gotoyxy(0,1);
lcd_putc( ' ' ) ;
lcd_gotoyxy(1,1);
lcd_putc( '0' ) ;
lcd_gotoyxy(2,1);
lcd_putc( '.' ) ;
lcd_gotoyxy(3,1);
lcd_putc( numstr[0] ) ;
}
if (xacc>=10) // 10 to 99 -> " 1.0" to " 9.9"
{
lcd_gotoyxy(0,1);
lcd_putc( ' ' ) ;
lcd_gotoyxy(1,1);
lcd_putc( numstr[0] ) ;
lcd_gotoyxy(2,1);
lcd_putc( '.' ) ;
lcd_gotoyxy(3,1);
lcd_putc( numstr[1] ) ;
}
if (xacc>=-10 && xacc<0) // -9 to 0 -> "-0.9" to "-0.1"
{
lcd_gotoyxy(0,1);
lcd_putc( '-' ) ; // could use numstr[0] here...
lcd_gotoyxy(1,1);
lcd_putc( '0' ) ;
lcd_gotoyxy(2,1);
lcd_putc( '.' ) ;
lcd_gotoyxy(3,1);
lcd_putc( numstr[1] ) ;
}
if (xacc<-10) // -10 to -99 -> "-1.0" to "-9.9"
{
lcd_gotoyxy(0,1);
lcd_putc( '-' ) ; // could use numstr[0] here...
lcd_gotoyxy(1,1);
lcd_putc( numstr[1] ) ;
lcd_gotoyxy(2,1);
lcd_putc( '.' ) ;
lcd_gotoyxy(3,1);
lcd_putc( numstr[2] ) ;
}
--END OF CODE--
Ed.
[Edited on 7/1/10 by Madinventions]
Mojo build diary: http://www.madinventions.co.uk
Solo music project: Syrrenfor http://www.reverbnation.com/syrrenfor
View my band website:
http://www.shadowlight.org.uk
http://www.eastangliankitcars.co.uk/
|
|
|
AdrianH
|
| posted on 7/1/10 at 12:14 AM |
|
|
Can I thank you all enough!
Why do I have to make the tools to finish the job? More time then money.
|
|
|
iank
|
| posted on 7/1/10 at 12:18 AM |
|
|
Excellent
There's plenty of tidying up/optimisation possible but that's easy once it's producing the right results.
--
Never argue with an idiot. They drag you down to their level, then beat you with experience.
Anonymous
|
|
|
Madinventions
|
| posted on 7/1/10 at 12:22 AM |
|
|
No problem, glad we could help!
It just goes to show that LocostBuilders can normally come up with an answer for anything!
Ed.
Mojo build diary: http://www.madinventions.co.uk
Solo music project: Syrrenfor http://www.reverbnation.com/syrrenfor
View my band website:
http://www.shadowlight.org.uk
http://www.eastangliankitcars.co.uk/
|
|
|
ashg
|
| posted on 7/1/10 at 12:24 AM |
|
|
how did i miss this one you guys had all the fun without me.
oh that was it i was out dragging the other half home.
Anything With Tits or Wheels Will cost you MONEY!!
Haynes Roadster (Finished)
Exocet (Finished & Sold)
New Project (Started)
|
|
|
AdrianH
|
| posted on 7/1/10 at 12:27 AM |
|
|
Just re tied thexacc (ADC-480)/25 and whilst it goes positive when I go negative it displays 2612.
So that is another evening play, the display being sorted goes a lot further to my understanding of it all.
The project when completed will hopefully have, and this will be many moons away, a 3 axis g meter, rev counter and a wheel turns counter providing
mph.
In effect a simple tech meter along the lines of the Gtech gear.
Also plan to send data to USB stick if at all possible for Excell work.
It keeps the grety matter ticking and at passed mid-life I need it.
Thanks again for the help from you.
Hi Ash you can tell the weather is crap, I'm back at the computer for hours!
[Edited on 7-1-10 by AdrianH]
Why do I have to make the tools to finish the job? More time then money.
|
|
|
Madinventions
|
| posted on 7/1/10 at 12:42 AM |
|
|
Oooh this is starting to sound stunningly familiar! I made a touchscreen controller for my Mojo that reads a 3 axis accelerometer, tacho, speed and
the OBD data from the Ford ECU! It also had datalogging to a SD card, and I added shift lights and a 0-60 timer just for fun. The code for this will
be getting an overview soon as I'm upgrading to a Megasquirt system so I need to rehash it all to interface with that to get coolant
temperatures etc. I used a PIC 18F8722 for my board and coded it all with the Swordfish PICBasic compiler.
Link to my website...
Anyhoo - I couldn't resist having another little fiddle with the code so far!
void PrintAcc(adcval as int16_t, pos as int8_t)
// adcval is 0-1023 adc reading, pos is position to print on the lcd.
{
char numstr[4]; // string variable
numstr[0]=0;
numstr[1]=0;
numstr[2]=0;
numstr[3]=0;
adcval = (adcval/25)-19;
itoa(adcval,numstr,10); // convert integer to string
//This is the formatting that needs to occur:
//value itoa() display
//-10 "-10" "-1.0"
//-1 "-1" "-0.1"
// 0 "0" " 0.0"
// 1 "1" " 0.1"
// 10 "10" " 1.0"
if (adcval>=0 && adcval<10) // 0 to 9 -> " 0.0" to " 0.9"
{
lcd_gotoyxy(0+pos,1);
lcd_putc( ' ' ) ;
lcd_gotoyxy(1+pos,1);
lcd_putc( '0' ) ;
lcd_gotoyxy(2+pos,1);
lcd_putc( '.' ) ;
lcd_gotoyxy(3+pos,1);
lcd_putc( numstr[0] ) ;
}
if (adcval>=10) // 10 to 99 -> " 1.0" to " 9.9"
{
lcd_gotoyxy(0+pos,1);
lcd_putc( ' ' ) ;
lcd_gotoyxy(1+pos,1);
lcd_putc( numstr[0] ) ;
lcd_gotoyxy(2+pos,1);
lcd_putc( '.' ) ;
lcd_gotoyxy(3+pos,1);
lcd_putc( numstr[1] ) ;
}
if (adcval>=-10 && adcval<0) // -9 to 0 -> "-0.9" to "-0.1"
{
lcd_gotoyxy(0+pos,1);
lcd_putc( '-' ) ; // could use numstr[0] here...
lcd_gotoyxy(1+pos,1);
lcd_putc( '0' ) ;
lcd_gotoyxy(2+pos,1);
lcd_putc( '.' ) ;
lcd_gotoyxy(3+pos,1);
lcd_putc( numstr[1] ) ;
}
if (adcval<-10) // -10 to -99 -> "-1.0" to "-9.9"
{
lcd_gotoyxy(0+pos,1);
lcd_putc( '-' ) ; // could use numstr[0] here...
lcd_gotoyxy(1+pos,1);
lcd_putc( numstr[1] ) ;
lcd_gotoyxy(2+pos,1);
lcd_putc( '.' ) ;
lcd_gotoyxy(3+pos,1);
lcd_putc( numstr[2] ) ;
}
}
void convert()
{
delay_ms(1);
// start the conversion
ADCSRA |= 0x40;
while((ADCSRA&0x40) == 0x40)
{
continue;
}
}
void main()
{
while(1)
{
lcd_clrscr();
lcd_puts("Xacc Yacc Zacc";
//select ADC1 and Use 3.3 Vcc as reference with cap at AREF pin
//Also set right adjusted in the result
// ADC1
ADMUX =0x41; // ADC1
convert(); // Start the conversion and wait for completion...
PrintAcc(ADC,0);// Convert, format, and print the result.
// ADC2
ADMUX =0x42; // ADC2
convert();
PrintAcc(ADC,5);
// ADC3
ADMUX =0x43; // ADC3
convert();
PrintAcc(ADC,10);
}
delay_ms(250);
}
I've basically chucked a few of the parts into subroutines and tidied up a few bits. It may or may not help?
Ed.
[Edited on 7/1/10 by Madinventions]
Mojo build diary: http://www.madinventions.co.uk
Solo music project: Syrrenfor http://www.reverbnation.com/syrrenfor
View my band website:
http://www.shadowlight.org.uk
http://www.eastangliankitcars.co.uk/
|
|
|
AdrianH
|
| posted on 7/1/10 at 01:05 AM |
|
|
That looks very good indeed.
Just using the Atmega 168 here with free software from Atmel the Studio 4 package that also uses GCC. I play and fiddle until stuff works, as you can
probably tell.
But! and this is a big but for me. I need a reason to learn code, to just try and follow a book does not get it in my head. I need a reason to
continue with something or else I can give it up.
All done on the cheep side here, as mentioned my board came from tuxgraphics together with the programming lead. The board is the surface mount one
with a web type interface. Have used it before as a type of link between two boards to measure latency through the Internet and monitor TTL and
battery voltage. A sort of remote monitoring tool if you will.
But now want something for the car.
I will go through your code later today, try and understand what it is doing and go on from there. I now understand the null pointer section and now
realise I need to reformat it to show 0.x value or - 0.x value.
The maths will work if I use (ADC/2.5)-192 to give 0 to 100 display. So still to figure why (ADC-480)/25 will not work out.
But too late for now.
Cheers and thanks again.
Adrian
p.s
sure the last posts and this one disappeared from the forum, then came back again. Must be me!
[Edited on 7-1-10 by AdrianH]
Why do I have to make the tools to finish the job? More time then money.
|
|
|
Madinventions
|
| posted on 7/1/10 at 01:28 AM |
|
|
Ok, one last quick thought before I go and find somewhere warm (I'm in the workshop and my calor gas heater has just run out... brr!!)
You'll probably find that the ADC variable is declared somewhere as a uint16. Therefore if you have an ADC value of say 230 and the routine has
the function (ADC-480)/25 then the compiler will first try to calculate 230-480 (ignore the /25 for now). Using signed math this will be = -250.
Correct. However, if ADC is a uint, the compiler will assume that the '480' is also a uint and will do the calculation using unsigned
integers (0-65535). Negative values are not allowed in the result so it will 'wrap-around' and give you a value of 65536-250 = 65286.
When this is divided by 25 you get the 2612 you see on the display.
So, you either need to copy the ADC value into a int16 variable before using it in this formula, or you need to typecast the ADC variable to force the
compiler to use signed math and be aware that it may have to handle negative values.
int16_t adcval;
adcval = adc;
xacc = (adcval-480)/25;
or the typecast version:
xacc = ((int16)ADC-480)/25;
The actual syntax may be slightly different from this but this is one of the standard pitfalls of integers and C coding!
Hope this helps, let us know how you get on.
Best regards,
Ed.
[Edited on 7/1/10 by Madinventions]
Mojo build diary: http://www.madinventions.co.uk
Solo music project: Syrrenfor http://www.reverbnation.com/syrrenfor
View my band website:
http://www.shadowlight.org.uk
http://www.eastangliankitcars.co.uk/
|
|
|
splitrivet
|
| posted on 7/1/10 at 09:58 AM |
|
|
Wish I never started reading this thread my brain really hurts now.
Cheers,
Bob  
I used to be a Werewolf but I'm alright nowwoooooooooooooo
|
|
|
skinned knuckles
|
| posted on 7/1/10 at 10:09 AM |
|
|
all of a sudden i feel really stupid!
A man isn't complete until he's married, then he's finished
|
|
|
Madinventions
|
| posted on 7/1/10 at 10:53 AM |
|
|
Yep - that's how I feel when I try to weld 2 bits of metal together!
Microcontroller programming: no problem.
Welding: Fire, pain, pigeon poo, disaster.
  
Ed.
Mojo build diary: http://www.madinventions.co.uk
Solo music project: Syrrenfor http://www.reverbnation.com/syrrenfor
View my band website:
http://www.shadowlight.org.uk
http://www.eastangliankitcars.co.uk/
|
|
|
02GF74
|
| posted on 7/1/10 at 11:42 AM |
|
|
quote: Originally posted by AdrianH
The maths will work if I use (ADC/2.5)-192 to give 0 to 100 display. So still to figure why (ADC-480)/25 will not work out.
the result will be different according to variable types: signed or unsigned integers.
but also you have 2.5 in the equation - that is not gonna give you exepcted result using integer math.
|
|
|
MikeR
|
| posted on 7/1/10 at 12:00 PM |
|
|
not sure if i'm talking down & apologise if i am. Just in case you're not aware ...
Integer - whole number only eg 3, 12, 21. Can't do 2.4. Has a range of 0-???? if 8bit 256, if 16 bit 64,000ish (ok 65,500ish)
Signed integer - same as integer but the first half of the number is classed as negative. Eg 16 bit signed integer is -32000 to +32000 instead of 0 to
64000. If you started with the very first value and added 1 to it it would be classed as -31999, if you add 32000 to it, the computer thinks its
actually 0.
If you want to have a value with a decimal point it it, ie a real number you need to use floating point. the problem with floating point point is that
its a) slow and b) (scarily) imprecise. For reasons i won't go into the computer doesn't hold the actual number like 2.5 is holds an
approximation that would be something 2.500000000001. This can then mess you up when you start doing something like 2.5 - 2.5 and expecting 0. 
If you try to do integer / floating point the computer will (depending on the complier) try to do something - but you can't guarantee what it
will do without experimentation and its likely to not do what you want unless you're being REALLY clever. We used to do tricks of writing 100
character strings into a 1 character strings knowing it would overwrite the next 99 characters. This was deliberate as it was faster than 20 or 30
separate writes which is what it really needed.
|
|
|
02GF74
|
| posted on 7/1/10 at 12:16 PM |
|
|
quote: Originally posted by MikeR
not sure if i'm talking down & apologise if i am. Just in case you're not aware ...
Signed integer - same as integer but the first half of the number is classed as negative. Eg 16 bit signed integer is -32000 to +32000 instead of 0 to
64000. If you started with the very first value and added 1 to it it would be classed as -31999, if you add 32000 to it, the computer thinks its
actually 0.
not sure if i'm talking down & apologise if i am. Just in case you're not aware ...
not strictly correct.
most micros use 2's (twos) complement to represent negative numbers.
I won't go into details - google it as I am sure itwold be described better - but addition of positve and negative numbers will product the
correct result.
mircos cannot perform subtraction - this is done by the addition of a negative number. (I've not come across hardware for a subtrator but adders
are easy to do)
another representation of negatvie numbers is to use the most significant bit as the sign bit; if set then number is negative. this is fine but the
addition and subtraction will not give correct result is some cases (without some conversion?) hence reason why 2's complement is used.
[Edited on 7/1/10 by 02GF74]
|
|
|
MikeR
|
| posted on 7/1/10 at 01:01 PM |
|
|
eeek - its been a while. having to read up again now to relearn what i've obviously forgotten from my PC coding days. Sorry for the
miss-information.
(i do vaguely remember at uni make up a adders circuit using logic gates - which i seem to recall needed two half adders which was a combination of
AND gates plus something else).
|
|
|
MikeRJ
|
| posted on 7/1/10 at 01:14 PM |
|
|
quote: Originally posted by MikeR
If you want to have a value with a decimal point it it, ie a real number you need to use floating point.
You only need floating point maths when you are dealing with numbers that have a very large range, i.e. they can be very small or very large, and the
floating point allows you to trade off resolution against range.
In the vast majority of embedded applications you can get away without using floating point maths, by using fixed point maths instead. Normally you
would not scale intermediate values by factors of ten, but rather by factors of two since this gives you the most efficient/fastest calculations
(though obvioulsy you need to scale the final result by a power of ten to display decimal places).
In the last 14 years I've not worked on an embedded project that actually required floating point operations, though it can certainly make
things simpler sometimes if you can spare the memory and speed overhead.
BTW Adrian, you are going to have problems interfacing to a USB stick. If you really want to do this you should be looking at a different micro, one
with a USB "On The Go" peripheral that can work as a (limited) USB master. Your best bet for portable flash storage would be to save to
an SD card. These can be accessed by an SPI interface which makes things much easier, though the code required for handling the FAT16/32 file system
is pretty large.
BTW, if you are using a standard character based LCD then you don't need to position the cursor prior to writing each character providing the
LCD has been initialised properly.
code:
while( ( numstr[ i ] !=0 ) && ( i<4 ) )
{
lcd_gotoxy(i+10,1);
lcd_putc(numstr[ i ]);
i++;
}
lcd_gotoxy(10,1);
while( ( numstr[ i ] !=0 ) && ( i<4 ) )
{
lcd_putc(numstr[ i ]);
i++;
}
It would make more sense to add an string writing function to your LCD driver as well, this would save you having to implement a loop every time you
want to write a string, which saves memory.
code:
/**
* Write a null terminated string to the LCD.
* Assumes cursor is at correct location prior to calling.
* @param str Pointer to null terminated string.
*/
void lcd_puts( char *str )
{
while( *str )
{
lcd_putc( *str++ );
}
}
/**
* Write a null terminated string to the LCD up to specified number of characters.
* Assumes cursor is at correct location prior to calling.
* @param str Pointer to null terminated string.
* @param len Number of characters to write.
*/
void lcd_putsn( char *str, unsigned int len )
{
while( *str && len )
{
lcd_putc( *str++ );
len--;
}
}
Arrggghh...I'd forgotten how uselessly broken the CODE tags are on this forum! The CODE tags should instruct the parser to ignore any control
characters within the section, and it plainly does not! Also we don't need double spacing enabled, and it should not remove multiple spaces.
|
|
|
iank
|
| posted on 7/1/10 at 01:16 PM |
|
|
quote: Originally posted by MikeR
eeek - its been a while. having to read up again now to relearn what i've obviously forgotten from my PC coding days. Sorry for the
miss-information.
(i do vaguely remember at uni make up a adders circuit using logic gates - which i seem to recall needed two half adders which was a combination of
AND gates plus something else).
AND gate for the carry, XOR for the sum.
Doing a 2's complement subtractor in hardware isn't difficult at all, it's an adder with one input inverted and a 1 stuck in the
carry LSB carry in.
--
Never argue with an idiot. They drag you down to their level, then beat you with experience.
Anonymous
|
|
|
MikeR
|
| posted on 7/1/10 at 01:25 PM |
|
|
quote: Originally posted by MikeRJ
quote: Originally posted by MikeR
If you want to have a value with a decimal point it it, ie a real number you need to use floating point.
You only need floating point maths when you are dealing with numbers that have a very large range, i.e. they can be very small or very large, and the
floating point allows you to trade off resolution against range.
In the vast majority of embedded applications you can get away without using floating point maths, by using fixed point maths instead. Normally you
would not scale intermediate values by factors of ten, but rather by factors of two since this gives you the most efficient/fastest calculations
(though obvioulsy you need to scale the final result by a power of ten to display decimal places).
I was trying to keep it simple for the guy - we used to store all prices in our system as integers to 2, 3 and 4 assumed decimal places depending on
where you where in the system (never quite sure why we didn't standardise - hoped it was some cleverly thought out rounding trick to make us
more money instead of the more likely 3 developers 3 approaches scenario).
|
|
|
AdrianH
|
| posted on 7/1/10 at 07:33 PM |
|
|
More and more input, will have to catch up after a club meet.
On number types types I will work out how the compiler is working but putting in fixed values and seeing what the result is working out at.
I believe some compilers could work out the maths in floating point if a floating point number was used, but if the end result was an integer, you
would loose the decimal at the end. Could well be wrong, as I am really only a beginner, it is a pass time not a careerer with me and just helps me
think logically sometimes!
The LCD routines are all pre written, using 4 bits of the I/O port, there is clear screen which sets cursor to top right, has functions for characters
and strings and cursor position and probably a few I do not know yet.
On the AVR forum there are others the atmega devices to USB, sticks, but memory cards would be fine also.
Things have moved on a lot since I originally did a weather satellite decoding system with 8 bit resolution (grey ) on the old Z80 processor.
Anyone remember Nascom?
Adrian
Why do I have to make the tools to finish the job? More time then money.
|
|
|
iank
|
| posted on 7/1/10 at 08:05 PM |
|
|
quote: Originally posted by AdrianH
...
Anyone remember Nascom?
Adrian
Yes (showing my age).
I've even programmed Z80's professionally in C and assembler.
--
Never argue with an idiot. They drag you down to their level, then beat you with experience.
Anonymous
|
|
|