Command-line Arguments

Command-line Arguments

Mate de Vita
Kelli

2008 Oct 4 • 2453
159 ₧
A few new programs (I'll just paste them here so they're all in the first post):

Exercise 5-7. Write the program add which evaluates a reverse Polish expression from the command line. For example,
add 2 3 4 + *
evaluates 2 x (3+4).


C code
#define NUMBER '0'

int main (argc, argv)
int argc;
char *argv[];
{
double op, strtofloat(), pop(), push();

while (--argc > 0)
switch (type (*++argv)){ //determines whether the next argument is a number or something else

case NUMBER: //if it's a number, it pushes it onto the stack
push (strtofloat (*argv));
break;
//otherwise it does the appropriate operation, and pushes the result onto the stack
case '+':
push (pop() + pop());
break;

case '*':
push (pop() * pop());
break;

case '-':
if (type (*argv + 1) == NUMBER){ //unary minus
push (strtofloat (*argv));
break;
}
op = pop();
push (pop() - op);
break;

case '/':
op = pop();
if (op != 0.0) push (pop() / op);
else printf ("\nZero divisor popped.\n");
break;

case '%':
printf ("\nThe floating points will be truncated for the modulus operation.\n");
op = pop();
if (op != 0.0) push ((int)pop() % (int)op);
else printf ("\nZero divisor popped.\n");
break;

default:
printf ("Illegal option: %c.\n", type (*argv));
break;
}
printf ("\t%f\n", pop());
return 0;
}

#define MAXVAL 100 //max depth of val stack

int sp = 0; //stack pointer
double val[MAXVAL]; //value stack

double push (f) //push float onto the value stack
double f;
{
if (sp < MAXVAL) return (val[sp++] = f); //if there is room on the stack push float onto the stack

printf ("Error: stack is full.\n"); //if the stack is full clear stack and return 0
clear();
return 0;
}

double pop() //pops the top value from the stack
{
if (sp > 0) return (val[--sp]); //if there are values on the stack, pop the top one
return 0; //if stack is empty return 0
}

clear() //clears stack
{
sp = 0;
}


Exercise 5-8. Modify the programs entab and detab [...] to accept a list of tab stops as arguments. Use the normal tab settings if there are no arguments.
http://users.powernet.co.uk/eton/kandr2/krx1.html
See exercises 20 and 21 for an explanation of what entab and detab do.

Exercise 5-9. Extend entab and detab to accept the shorthand
entab m +n
to mean tabs stops every n columns, starting at column m. Chooose convenient (for the user) default behavior.


detab:
C code
#define TABSTOP 5 //default length between two tab stops
#define MAXLINE 1000 //maximum line length

int main (argc, argv)
int argc;
char *argv[];
{
char *argvstart = argv;
char line[MAXLINE];
char *pline;
int col; //current column number
int nextstop; //column number of the next tab stop

while (lineget (line, MAXLINE) != 0){ //get next line
argv = argvstart; //set argv back to the first argument
nextstop = (strtoint (*++argv) > 0) ? strtoint (*argv++) : TABSTOP; //find the first tab stop
for (pline = line, col = 1; *pline != '\0'; pline++){
while (col >= nextstop) //if a tab stop has been reached, find the next one
nextstop += (strtoint (*argv) > 0) ? strtoint (*argv++) : (*argv[0] == '+') ? strtoint (*argv + 1) : TABSTOP;
if (*pline == '\t') //if the character is a '\t', print enough ' ' characters to reach the next tab stop
while (col < nextstop){
putchar (' ');
col++;
}
else { //otherwise print the character
putchar (*pline);
col++;
}
}
}
return 0;
}

int lineget (ps, lim)
char *ps;
int lim;
{
int c;
char *start = ps;

while ((c = getchar()) != EOF){
if (--lim < 1){ //line is too long, skip rest of the line
*--ps = '\n';
*++ps = '\0';
return -1;
}
*ps++ = c;
if (c == '\n') break;
}
*ps = '\0';
return (ps - start); //line length counting '\n', but not '\0'
}

int strtoint (ps)
char *ps;
{
int n = 0, sign = 1;

while (*ps == ' ' || *ps == '\n' || *ps == '\t') ps++;
if (*ps == '-'){
sign = -1;
ps++;
}

while (*ps >= '0' && *ps <= '9') n = 10 * n + *ps++ - '0';
return (sign * n);
}


entab
C code
#define TABSTOP 5
#define MAXLINE 1000

int main (argc, argv)
int argc;
char *argv[];
{
char *argvstart = argv;
char line[MAXLINE];
char *pline;
int col; //column number
int nextstop; //column number of the next tab stop
int nspaces; //total number of consecutive spaces
int ntabs; //number of consecutive spaces covered by tabs

while (lineget (line, MAXLINE) != 0){
argv = argvstart;
nextstop = (strtoint (*++argv) > 0) ? strtoint (*argv++) : TABSTOP;

for (pline = line, col = 1; *pline != '\0'; col++){
for (ntabs = nspaces = 0; *pline == ' '; nspaces++, pline++){ //count the total number of consecutive spaces
col++;
if (col >= nextstop){
putchar ('\t');
ntabs += (strtoint (*argv) > 0) ? strtoint (*argv) : (*argv[0] == '+') ? strtoint (*argv + 1) : TABSTOP; //count the number of spaces that are covered by '\t' characters
nextstop += (strtoint (*argv) > 0) ? strtoint (*argv++) : (*argv[0] == '+') ? strtoint (*argv + 1) : TABSTOP;
}
}

while ((--nspaces) % ntabs > 0) putchar (' '); //print the remaining blanks
putchar (*pline++); //print the non-blank character

while (col >= nextstop)
nextstop += (strtoint (*argv) > 0) ? strtoint (*argv++) : (*argv[0] == '+') ? strtoint (*argv + 1) : TABSTOP;
}
}
return 0;
}


1) In the linux terminal, how do I run a program with arguments? Running it as
code
./blah.out -flag1 argument
doesn't seem to work.

2) Could someone check the syntax of the lines that increment nextstop and ntabs for me? I'm pretty new to these pointers to arrays of pointers to strings. Also the conditional expressions or whatever they're called (the ?: expressions).
C code

nextstop += (strtoint (*argv) > 0) ? strtoint (*argv++) : (*argv[0] == '+') ? strtoint (*argv + 1) : TABSTOP;

This is supposed to do the following:
- if the argument is a number, it increments nextstop by that number
- if the argument is a number with a + as the first character (see Exercise 5-9), it also increments it by that number
- if there is no argument, it increments nextstop by the default length between tab stops (I used 5 as the default).

3) Did I understand the instructions correctly? For exampe, which would be the proper input if you wanted tab stops at columns 5, 12, and 16:
entab 5 7 4
or
entab 5 12 16
I went with the first one in my programs.
...and that's the bottom line because Mate de Vita said so.
 
 
2011 Apr 4 at 08:40 PDT — Ed. 2011 Apr 4 at 08:41 PDT
Down Rodeo
Cap'n Moth of the Firehouse

Find the Hole II Participation Medal
2007 Oct 19 • 5486
57,583 ₧
Your C looks quite old to me. But what do I know (answer: not much C). Ternary operators are kind of OK so long as you're careful. As for passing the arguments, you might have to do it like -O3 for optimisation level 3 for instance. Some programs do it like that, others don't. It depends but generally speaking --help will get you the syntax.

Unless you mean how do you pass numbers to *your* program, in which case you do it just by writing the numbers in, separated by spaces. The console just passes your program exactly what the end user types. Well, separated into strings, but you get what I mean.
 
 
2011 Apr 4 at 16:33 PDT
SuperJer
Websiteman

2005 Mar 20 • 6253
1) Linux terminal arguments:

That's the way to do it. I'm not sure what's wrong, but here's a simple program to test it:

164030 jwilson@wayout ~$ cat arguments.c #include <stdio.h> int main( int argc, char *argv ) { int i; for( i=0; i<argc; i++ ) printf( "Argument %d: %s\n", i, argv[i] ); } 164036 jwilson@wayout ~$ gcc arguments.c 164051 jwilson@wayout ~$ ./a.out -flag1 argument Argument 0: ./a.out Argument 1: -flag1 Argument 2: argument
 
 
2011 Apr 4 at 16:40 PDT — Ed. 2011 Apr 4 at 16:46 PDT
SuperJer
Websiteman

2005 Mar 20 • 6253
This stupid forum software needs some work.
 
 
2011 Apr 4 at 16:46 PDT
SuperJer
Websiteman

2005 Mar 20 • 6253
2) I find nested usage of the ?: operator too confusing. So I changed it into an equivalent if-else chain:

C code

if (strtoint (*argv) > 0) nextstop += strtoint (*argv++)
else if (*argv[0] == '+') nextstop += strtoint (*argv + 1)
else nextstop += TABSTOP;


Are you intending to ++ argv in the first case only?

You shouldn't really be ++ing argv at all, I don't think. It won't blow up or anything but once you've modified it you can't go back.
 
 
2011 Apr 4 at 17:02 PDT
Mate de Vita
Kelli

2008 Oct 4 • 2453
159 ₧
Down Rodeo said:
Unless you mean how do you pass numbers to *your* program, in which case you do it just by writing the numbers in, separated by spaces. The console just passes your program exactly what the end user types. Well, separated into strings, but you get what I mean.

superjer said:
1) Linux terminal arguments:

That's the way to do it. I'm not sure what's wrong, but here's a simple program to test it: [...]

I tried to run the add program (in my case it's called Reverse Polish.out) with the line
"./Reverse Polish.out" 2 3 +
but it just drew up a new terminal line.

I'll run that test program when I get home.

superjer said:
Are you intending to ++ argv in the first case only?

Yes, because the program accepts the following inputs:
- detab 7 5 5 5
- detab 7 +5
- detab

So if an argument consists of only a number, it should go to the next argument. If not, it should stay at the same one.

superjer said:
You shouldn't really be ++ing argv at all, I don't think. It won't blow up or anything but once you've modified it you can't go back.

Well, I have the pointer *argvstart to save the initial position of argv. Won't that work?
...and that's the bottom line because Mate de Vita said so.
 
 
2011 Apr 5 at 01:15 PDT — Ed. 2011 Apr 5 at 01:16 PDT
Down Rodeo
Cap'n Moth of the Firehouse

Find the Hole II Participation Medal
2007 Oct 19 • 5486
57,583 ₧
Well, in the case of "./rpn 3 5 +" there are four arguments, the zeroth being the program name and then your two numbers then the plus. You can just refer to them as argv[j] then use atoi on them, or something. There's probably a way to reason about how many numbers compared to how many operators you have. Or something similar.

Oh, you can't refer to the i'th element of an array, or your post goes all italic.
 
 
2011 Apr 5 at 05:04 PDT — Ed. 2011 Apr 5 at 05:04 PDT
Mate de Vita
Kelli

2008 Oct 4 • 2453
159 ₧
Down Rodeo said:
Well, in the case of "./rpn 3 5 +" there are four arguments, the zeroth being the program name and then your two numbers then the plus. You can just refer to them as argv[j] then use atoi on them, or something. There's probably a way to reason about how many numbers compared to how many operators you have. Or something similar.

Oh, you can't refer to the i'th element of an array, or your post goes all italic.

Yeah, my Polish Calc program first increments argv so that it points to the first actual argument, not the name of the program. Then it checks to see if it's a number or an operator.

If it's a number, it pushes it to a stack (using strtofloat, which is my version of atof).
If it's an operator, it pops the two top values on the stack (the last two numbers that were pushed there) and pushes back the result of the proper operation between them.

When there are no more arguments (argc equals 0), it prints the top value from the stack (which is the result of the whole expression if it was input properly).

At least that's what it's supposed to do. In reality it takes ~10 seconds to execute, then either prints 0 as the result (meaning the stack is empty), or prints an error.

When I tried the arguments 5 8 *, it printed a lot of 'Illegal option' messages with various characters from A to P (see the default branch of the switch in the first program).
When I tried 42 6 /, it printed 'Zero divisor popped' (see the '/' branch of the switch in the first program).
When I tried addition and subtraction it simply printed 0 as a result.

I'm guessing it doesn't properly read the number arguments for some reason. Now I just have to find out why.

superjer said:
164030 jwilson@wayout ~$ cat arguments.c #include <stdio.h> int main( int argc, char *argv ) { int i; for( i=0; i<argc; i++ ) printf( "Argument %d: %s\n", i, argv[i] ); } 164036 jwilson@wayout ~$ gcc arguments.c 164051 jwilson@wayout ~$ ./a.out -flag1 argument Argument 0: ./a.out Argument 1: -flag1 Argument 2: argument

OK, that worked properly (except that the [] next to argv isn't showing up next to the argv in your post for some reason).
...and that's the bottom line because Mate de Vita said so.
 
 
2011 Apr 5 at 08:28 PDT — Ed. 2011 Apr 5 at 08:37 PDT
Down Rodeo
Cap'n Moth of the Firehouse

Find the Hole II Participation Medal
2007 Oct 19 • 5486
57,583 ₧
Oh, I get you now. Kind of. First of all I would stay away from spaces and other funny characters in program names. It looks like you have it done correctly, but I always get paranoid anyway. The thing I now suggest is print statements everywhere, that way you get to see where the slow bits are and what is actually getting pushed on the stack etc.

It's funny, I was almost tempted to use the Apache Commons stuff for command-line argument processing, but I never had the time. Boost has one for C I think. Not that would be massively useful in this case...
 
 
2011 Apr 5 at 09:53 PDT
SuperJer
Websiteman

2005 Mar 20 • 6253
I'm not able to run your first program because I don't have the type() function, or macro, or whatever that is.

Pastebin it or something.

The forum software is really showing some suckitude right now for pasting code. Hence the missing [].
 
 
2011 Apr 6 at 00:41 PDT
Mate de Vita
Kelli

2008 Oct 4 • 2453
159 ₧
C code
int type (ps)
char *ps;
{
while (*ps == ' ' || *ps == '\t' || *ps == '\n') ps++;

if (*ps < '0' || *ps > '9') return (*ps);
return NUMBER;
}


For this program it can be simplified to
C code
int type (char *ps)
{
return (*ps >= '0' && *ps <= '9') ? NUMBER : *ps;
}


It basically just checks the first element of the string it's given to see if it's a number or something else.
...and that's the bottom line because Mate de Vita said so.
 
 
2011 Apr 6 at 06:32 PDT — Ed. 2011 Apr 6 at 06:33 PDT
buq25

2008 Jul 5 • 572
295 ₧
yes
Today's post brought to you by the letter: "heck".
 
 
2011 Apr 6 at 06:33 PDT
Mate de Vita
Kelli

2008 Oct 4 • 2453
159 ₧
I just made my first program in C from my own idea and it works!
It's a program that I made to calculate the number of blocks I need to build a pyramid in minecraft. And here it is:


C code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main (argc, argv)
int argc;
char *argv[];
{
char *flag;
int hollow = 0, ground = 0, even = 0, level = 0, edge = 0;
int number;

while (--argc > 0 && (*++argv)[0] == '-')
for (flag = argv[0] + 1; *flag != '\0'; flag++)
switch (*flag){
case 'h':
hollow = 1;
break;
case 'g':
ground = 1;
break;
case 'e':
even = 1;
break;
case 'l':
level = 1;
break;
case 'b':
edge = 1;
break;
default:
printf ("Illegal flag: -%c.\n", *flag);
argc = 0;
break;
}

if (argc != 1) printf ("Usage: Pyramid -h -g -e -l/-b number_of_blocks\n");
else if ((number = strtoint (*argv)) <= 0) printf ("Illegal number argument:\t%d.\n", number);

else if (level){
int nextblocks = (even) ? 2 : 1, nextsquare = nextblocks * nextblocks;
int nblocks = 0;

while (number > 0){
nblocks += nextsquare;
number--;
nextblocks += 2;

if (hollow && (!ground || number - nextblocks * nextblocks > 0)) //if pyramid is hollow and it's not a ground floor
nextsquare = 4 * nextblocks - 4; //n² - (n-2)² = 4n - 4
else nextsquare = nextblocks * nextblocks;
}

printf ("Length of the ground level's edge:\t%d blocks.\n", nextblocks - 2);
printf ("Number of blocks needed:\t%d.\n", nblocks);
}

else if (edge){
int nextsquare = number * number;
int nlevels = 0, nblocks = 0;

while (number > 0){
nlevels++;
number -= 2;
nblocks += nextsquare;

if (hollow && (!ground || nlevels > 1))
nextsquare = 4 * number - 4;
else nextsquare = number * number;
}

printf ("Height of the pyramid:\t%d blocks.\n", nlevels);
printf ("Number of blocks used:\t%d.\n", nblocks);
}

else {
int i = number;
int nextblocks = (even) ? 2 : 1, nextsquare = nextblocks * nextblocks;
int nlevels = 0;

while (i >= nextsquare){
nlevels++;
i -= nextsquare;
nextblocks += 2;

if (hollow && (!ground || i - nextblocks * nextblocks > 0)) //if pyramid is hollow and it's not a ground floor
nextsquare = 4 * nextblocks - 4; //n² - (n-2)² = 4n - 4
else nextsquare = nextblocks * nextblocks;
}

if (hollow && ground && (number >= 4 || !even)) //if -hge, nblocks has to be larger than 4
nextsquare -= (nextblocks - 4) * (nextblocks - 4); //set the level above the ground level to hollow

printf ("Height of the pyramid:\t%d blocks.\nLength of the ground level's edge:\t%d blocks.\n", nlevels, nextblocks - 2);
printf ("Number of blocks used:\t%d.\nNumber of blocks remaining:\t%d.\n", number - i, i);
printf ("Number of blocks you need to get for next level:\t%d.\n", nextsquare - i);
}

return 0;
}

int strtoint (ps)
char *ps;
{
int n = 0, sign = 1;

while (*ps == ' ' || *ps == '\n' || *ps == '\t') ps++;
if (*ps == '-' || *ps == '+') sign = (*ps++ == '+') ? 1 : -1;

while (*ps >= '0' && *ps <= '9') n = 10 * n + *ps++ - '0';
return (sign * n);
}


The flags are as follows:
-h : Hollow pyramid.
-g : Has a full ground level (only effective along with -h).
-e : Even number of blocks in an edge (by default the edges are odd numbers) - top level is 4 blocks instead of 1.
-l : The input number determines the number of levels the pyramid is to have.
-b : The input number determines the number of blocks in the edge of the ground level.
Without a flag the input number determines the number of blocks that you have available (the program calculates how large a pyramid you can build and how many blocks you need to be able to build an additional level).

I have yet to test it extensively, but it appears to be working.

Anyway, just thought I'd share this with the rest of the class.
...and that's the bottom line because Mate de Vita said so.
 
 
2011 May 19 at 13:11 PDT — Ed. 2011 May 19 at 13:34 PDT
SuperJer
Websiteman

2005 Mar 20 • 6253
That's pretty cool. Now that you have code power, make sure to use it for good!

And now do the pyramid thing with calculus.
 
 
2011 May 19 at 19:05 PDT — Ed. 2011 May 19 at 19:06 PDT
Down Rodeo
Cap'n Moth of the Firehouse

Find the Hole II Participation Medal
2007 Oct 19 • 5486
57,583 ₧
Given that the pyramid is discrete, is there any point? Or are you talking like a lower bound?
 
 
2011 May 19 at 23:21 PDT
Mate de Vita
Kelli

2008 Oct 4 • 2453
159 ₧
I located (one of) the problem(s) in my Reverse Polish Calculator, it's my power function. For some reason it does some really weird stuff. Here's its code in a test program (with a few added printf tests):

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

int main()
{
double power();

printf ("%f\n", power (10, 1));
}

double power (b, exp) //integer exponents
int exp;
double b;
{
int i, sign = 1;
double p = 1;

printf ("%f, %d\n", b, exp);

if (exp < 0){
sign = -1;
exp = -exp;
}
printf ("%d, %d\n", sign, exp);

for (i = 0; i < exp; i++) p *= b;
printf ("%f\n", p);

return ((sign == 1) ? p : 1/p);
}

This returns the following:
Terminal code
0.000000, 134513883
1, 134513883
0.000000
0.000000

As you can see, the base is read as 0 and the exponent is read as 134513883.
Why doesn't it properly read the base and the exponent?

EDIT: nvm, problem resolved. The base is a double, I input it as an integer -_-



Now only the multiplication part causes problems. It prints out a lot of Illegal option messages with some random letters. Is the * character reserved for something?
If I use another character (x for example), it works properly.
...and that's the bottom line because Mate de Vita said so.
 
 
2011 May 20 at 09:09 PDT — Ed. 2011 May 20 at 09:53 PDT
Down Rodeo
Cap'n Moth of the Firehouse

Find the Hole II Participation Medal
2007 Oct 19 • 5486
57,583 ₧
I have no idea what version of compiler you're using, but this gives correct results on my machine:
C code
#include <stdio.h>
#include <stdlib.h>

int main()
{
double power();

printf ("%f\n", power (3.0, 3));
}

double power (double b, int exp) //integer exponents
{
int i, sign = 1;
double p = 1;

printf ("%f, %d\n", b, exp);

if (exp < 0)
{
sign = -1;
exp *= -1;
}

printf("%d, %d\n", sign, exp);

for (i = 0; i < exp; i++) { p *= b; }
printf ("%f\n", p);

return ((sign == 1) ? p : 1.0/p);
}
 
 
2011 May 21 at 04:02 PDT
Mate de Vita
Kelli

2008 Oct 4 • 2453
159 ₧
Down Rodeo said:
I have no idea what version of compiler you're using, but this gives correct results on my machine:

Yeah, I put 10 as a function argument instead of 10.0 (the base is of type double, I input an int).
...and that's the bottom line because Mate de Vita said so.
 
 
2011 May 22 at 14:34 PDT
Down Rodeo
Cap'n Moth of the Firehouse

Find the Hole II Participation Medal
2007 Oct 19 • 5486
57,583 ₧
 
 
2011 May 23 at 14:19 PDT
Mate de Vita
Kelli

2008 Oct 4 • 2453
159 ₧
Down Rodeo said:
I see. I think. Doesn't C have smarter casting than that?

Guess not :/

So, why doesn't * work as an argument? The program works perfectly if I use 'x' as a sign for multiplication, but if I use '*', and write ./PolishCalc.out 3 5 * in the terminal, it outputs a lot of Illegal option errors, as if the * wasn't one of the possible arguments. Why doesn't it properly read a(n) *?
...and that's the bottom line because Mate de Vita said so.
 
 
2011 May 23 at 14:25 PDT — Ed. 2011 May 23 at 14:26 PDT
Down Rodeo
Cap'n Moth of the Firehouse

Find the Hole II Participation Medal
2007 Oct 19 • 5486
57,583 ₧
 
 
2011 May 23 at 22:41 PDT
SuperJer
Websiteman

2005 Mar 20 • 6253
Mate de Vita said:
Down Rodeo said:
I see. I think. Doesn't C have smarter casting than that?

Guess not :/

So, why doesn't * work as an argument? The program works perfectly if I use 'x' as a sign for multiplication, but if I use '*', and write ./PolishCalc.out 3 5 * in the terminal, it outputs a lot of Illegal option errors, as if the * wasn't one of the possible arguments. Why doesn't it properly read a(n) *?


When you call power() it hasn't been defined yet. So passing it an int doesn't conflict with the definition. You should use function prototypes to prevent this error. Or define your main() last. Or change your local declaration to match the argument types:

c code
int main()
{
double power(double, int);

printf ("%f\n", power (3, 3));
}


^^ That should work.
 
 
2011 May 24 at 19:00 PDT — Ed. 2011 May 24 at 19:00 PDT
SuperJer
Websiteman

2005 Mar 20 • 6253
Your * problem is happening because your shell is interpreting the * as a shell glob. I.e. the * is matching all files in the current directory.

When you call ./PolishCalc.out 3 5 * the program is getting the following in argv:

./PolishCalc.out
3
5
(list of all files in the current dir, or '' or * depending on the shell)
 
 
2011 May 24 at 19:03 PDT — Ed. 2011 May 24 at 19:03 PDT
Down Rodeo
Cap'n Moth of the Firehouse

Find the Hole II Participation Medal
2007 Oct 19 • 5486
57,583 ₧
Which means the fix is to prepend a backslash, so something like \*, I think. Computers are complicated! Also, I thought there was something weird about the way you were defining the function, but I thought it best not to ask. You're reading from an old book. (Of course I also use Java where you can put functions wherever you like with little to no consequence.)
 
 
2011 May 28 at 09:38 PDT
SuperJer
Websiteman

2005 Mar 20 • 6253
Down Rodeo said:
(Of course I also use Java where you can put functions wherever you like with little to no consequence.)


Anywhere? Like in a class definition?

Does Java have anonymous functions now?
 
 
2011 May 28 at 22:30 PDT
Page [1] 2