ࡱ> tvqrsa (jbjbtt ,|   H ooo8p,4pH \4qLq"qqqSvvv<w SUUUUUU,hRE %w_uSv%w%wqqơ%wq qSTr%wS8^ S(q O*oSSܡ0 g``(S H H [d H H d15-395: Lab # 4 Implementing a Job Control Shell Overview 1 Times of Interest 1 Educational Objectives 1 Project Overview Specification 2 Form 2 Look-and-feel 2 Internal Commands vs. External Commands 3 Foreground vs. Background Jobs 3 Command lines 3 Internal Commands 4 Special Keystrokes 4 Parsing User Input 4 Overview, Delimiters and Special Characters 5 Internal Commands 5 Executing A Single Program 5 I/O Redirection 5 Pipes and Cooperating Processes 5 Background Jobs 6 A Grammar The Other Pieces 7 A Suggested Plan of Attack 7 Deliverables 7 The Project Review 8 Matchmaking 8 Environment Some Useful Information (Some of which is a review) 8 System Calls 10 Process Creation 11 Fork Example Code 12 What If I Dont Want a Clone? 12 I/O Redirection 13 I/O Redirection Example 14 Signals 14 Signal Example Code 15 Pipes 16 Pipe Example Code 18 Process Groups, Sessions, and Job Control 20 Tcsetgrp() and setpgrp() example 15-395: Lab # 4 Implementing a Job Control Shell Times of Interest: Class on Tuesday, October 2, 2007 Assignment distributed 11:59PM, Thursday, October 25, 2007 Assignment submission deadline Educational Objectives: For many people this project will be practice and/or a warm-up. For others, it will be a learning exercise. Regardless of your background, by the end of this project, we hope that you will comfortably and confidently be able to do the following: Develop clear, readable, well-documented and well-designed programs in the C Programming Language. Develop software in the Andrew/Unix using tools such as gcc, gdb, and make. Locate and interpreting man pages applicable to application-level system programming. Use the POSIX/Solaris API to system functions to manage process and sessions as well as use signals and pipes for inter-process communication. Understanding how synchronization might become problematic in light of concurrency. Understand how to communicate and cooperate with a project partner. Project Overview In this project you are asked to implement a simple command-interpreter, a.k.a. shell, for Unix. The shell that you will implement, known as xsh, should be similar to popular shells such as bash, csh, tcsh, zsh, &c, but it is not required to implement as many features as these commercial-grade products. Although we dont require all of the bells and whistles that are incorporated into commercial-grade products, xsh should have much of the important functionality: Allow the user to execute one or more programs, from executable files on the file-system, as background or foreground jobs. Provide job-control, including a job list and tools for changing the foreground/background status of currently running jobs and job suspension/continuation/termination. Allow for the piping of several tasks as well as input and output redirection. With respect to the other programming projects, past, present, and future, this may well be a small project, but we want you to approach it as if it is a bigger and more complex project so that you are prepared for the big ones. Specifically, wed like you to do the following: Use the make utility to build your project Use a debugger instead of print-and-hunt debugging whenever practical. Produce clean, well-documented, and well-designed solutions. Specification Form Your solution should be an application program invoked without command-line parameters or configuration files, &c. If you want to be fancy and support for a resource file similar to those used with commercial-grade shells, e.g. .cshrc, youre a welcome to do this. But, like csh, your shell should function correctly in absence of this file. Look-and-Feel The look and feel of xsh should be similar to that of other UNIX shells, such as bash, tcsh, csh, &c. For example, your shells work loop should produce a prompt, e.g., xsh>, accept input from the user, and then produce another prompt. Messages should be written to the screen as necessary, and the prompt should be delayed when user input shouldnt be accepted, as necessary. Needless to say, your shell should take appropriate action in response to the users input. Internal Commands vs. External Programs In most cases, the users input will be a command to execute programs stored within a file system. Well call these external programs. Your shell should allow these programs to execute with stdin and/or stdout reassigned to a file. It should allow programs I/O to be chained together using pipes. For our purposes, a collection of piped processes or a single process executed by itself from the command line is called a job. When executing backgrounds jobs, the shell should not wait for the job to finish before prompting, reading, and processing the next command. When a background job finally terminates a message to that effect must be printed, by the shell, to the terminal. This message should be printed as soon as the job terminates. The syntax for doing this will be described in the section of this document describing the shells parser. Your parser should also support several internal commands these commands, if issued by the user, should direct the shell to take a particular action itself instead of directing it to execute other programs. The details of this are discussed in the section describing internal commands. Foreground vs. Background Jobs Your shell should be capable of executing both foreground and background jobs. Whereas your shell should wait for foreground jobs to complete before continuing, it should immediately continue, prompt the user, &c, after placing a job into the background. Your shell should print a message immediately when a background job terminates. This is a different behavior than most commercial shells. But, it ensure that you handle signals in a certain way, so we are requiring this. Command lines When the user responds to a prompt, what they type composes a command line string. Your shell should store each command-line string, until the job is finished executing. This includes both background and suspended jobs. The shell should assign each command-line string a non-negative integer identifier. The data structure used to store the jobs should allow access to each element using this identifier. Once the actions directed by a command-line string are completed, your shell should remove it from the data structure. Identifiers can be recycled if you choose. Please note that this data structure should keep track of whole command line strings, not just the names of the individual tasks that may compose them. You should not keep track of command line strings that contain internal commands, since, by their nature, they will complete before this information could become useful. Internal Commands The following are the internal commands. If an internal command is submitted by the user, the shell should take the described actions itself. exit: Kill all child processes and exit xsh with a meaningful return code. jobs: Print out the command line strings for jobs that are currently executing in the background and jobs that are currently suspended, as well as the identifier associated with each command line string. You may format the output of this command in way that is convenient to the user. Please remember that jobs itself is an internal command and consequently should not appear in the output. echo $?: Prints the exit status of the most recent foreground child process to have exited. Return 0 if no such child has existed. fg %: Brings the job identified by into the foreground. If this job was previously stopped, it should now be running. Your shell should wait for a foregound child to terminate before returning a command prompt or taking any other action. bg %: Execute the suspended job identified by in the background. Internal commands can take advantage of piped I/O, execute in the background, &c, as appropriate. Special Keystrokes Through an interaction with the terminal driver, certain combinations of keystrokes will generate signals to your shell instead of appearing within stdin. Your shell should respond appropriately to these signals. Control-Z generates a SIGSTOP. This should not cause your shell to be suspended. Instead, it should cause your shell to suspend the processes in the current foreground job. If there is no foreground job, it should have no effect. Control-C generates a SIGINT. This should not kill your shell. Instead it should cause your shell to kill the processes in the current foreground job. If there is no foreground job, it should have no effect. Parsing User Input Overview, Delimiters and Special Characters Your parser should be generated using (f)lex and yacc/bison. It should be capable of accepting input from the user as described in this section. It should also detect improper input from the user. If the user enters something improper, your shell should produce a meaningful error message. Just like commercial-grade shells, your shell should accept input from the user one line at a time. You should begin parsing the users input when he/she hits enter. Empty command lines should be treated as no-ops and yield a new prompt. Blank-space characters should be treated as delimiters, but your shell should be insensitive to repeated blank spaces. It should also be insensitive to blank spaces at the beginning or end of the command line. Certain characters, known as meta-characters, have special meanings within the context of user input. These characters include &, |, <, and >. Your shell can assume that these meta-characters cannot occur inside strings representing programs, arguments, or files. Instead they are reserved for use by the shell. The purpose of meta-characters is discussed later in this section. Parsing User Input Internal Commands If the command line matches the format of an internal command as described earlier in this document, it should be accepted as an internal command. If not, it should be considered to specify the execution of external programs, or an error, as appropriate. Parsing User Input Executing A Single Program The execution of a program is specified by a sequence of delimited strings. The first of these is the name of the executable file that contains the desired program (modulo a search path as explained in the execvp man page, see man -s 2 execvp) and the others are arguments passed to the program. The command is an error if the executable file named by the first string does not exist, or is not an executable. Paring User Input I/O Redirection A program's execution specified as above may be followed by the meta-character < or > which is in turn followed by a file name. In the case of <, the input of the program will be redirected from the specified file name. In the case of >, the output of the program will be redirected to the specified file name. If the output file does not exist, it should be created. If the input file does not exist, this is an error. Parsing User Input  Pipes and Cooperating Programs Several program invocations can be present in a single command line, when separated by the shell meta-character ``|''. In this case, the shell should fork all of them, chaining their outputs and inputs using pipes appropriately. For instance, the command line progA argA1 argA2 < infile | progB argB1 > outfile should fork progA and progB, make the input for progA come from file infile, the output from progA go to the input of progB, and the output of progB go to the file outfile. This should be accomplished using a pipe IPC primative. A command line with one or more ``pipes'' is an error if any of its component program invocations is an error. A command line with ``pipes'' is an error if the input of any but the first command is redirected, or if the output of any but the last command is redirected. A job consisting of piped processes is not considered to have completed until all of its component processes have completed. Parsing User Input Background Jobs The user can specify that a job should be executed in the background by ending the command line with the meta-character &. If this is the case, all program invocations required by the command line are to be carried out in the background. Parsing User Input A Grammar The grammar below provides a more formal description of the syntax governing user input. It is the same one you saw and converted into a yacc-able form for your last assignment. This grammar doesnt include the special keystrokes, because they wont show up in stdin as user input and should be handled separately. A CommandLine is legal input provided by the user, as a direction to the shell, in response to the prompt. The grammar assumes that the existence of a lexical analyzer that considers blank-space to be a delimiter, recognizes the meta-characters as tokens, &c.  A Suggested Plan Of Attack Read the man pages for fork, exec, wait and exit. Write a few small programs to experiment with these commands. Read the man pages for tcsetgrp() and setpgid() Write some code to experiment with process groups, &c. Pay attention to SIGTTIN & SIGTTOU. Take the parser from your last assignment and flesh it out a bit for this one. I particular, think about the data structures that youll need to build and the helper functions youll need to call. Start to stub these out. Using your parser, write a simple shell that can execute single commands. Add support for running programs in the background, but dont worry about printing the message when a background job terminates (asynchronous notification). Add the jobs command while you are doing this it may prove helpful for debugging. Add input and output redirection Add code to print a message when a background job terminates. Add job control features - implement the behavior of Control-Z (and, if applicable, CONTROL-C), fg and bg. Add support for pipes. Finish up all of the details Test, test test. Celebrate Deliverables You should electronically submit the following items into your groups submission directory before the project deadline: A Makefile. Source files that compile, by typing make, into an executable of name xsh. Optionally, a file of name README that contains anything you wish to point out to us. Soon after everyone is part of a group, we will be creating the following directory for you to submit your work: /afs/andrew.cmu.edu/course/15/395/handin/lab4/andrewid1-andrewid2 The Project Review After you submit your project, a member of the staff will review it. He or she will test your code to determine its completeness and correctness. He or she will also examine your source code to understand how you designed and implemented your solution, as well as the reason for any failures during the testing. The grader will then meet with your group to discuss the project. During this meeting the grader will clear up any questions he or she may have about your project, discuss any problems that were found, and check to make sure that both members of your group seem to be knowledgeable. This is also your opportunity to get answers to any questions you might have. If you run out of time, please schedule a follow-up meeting. Youll receive mail from your grader to schedule a review soon after youve submitted your project. Feel free to e-mail ahead with specific questions, things youd like to discuss, or to request more time. Were here to help! It is important to understand that your grade wont be determined until after this meeting. In order to standardize grading, projects are graded at a meeting when the entire staff is present. Matchmaking If you are having difficulties finding a partner, please send me (gkesden+@cs.cmu.edu) mail and I will try to play the part of a matchmaker. Please do try to find a partner before you do this. Environment Whereas you can do this assignment on any UNIX, it must run on the Andrew UNIX machines for your demo. Although you can solve this assignment in your choice of languages, it would probably be more difficult in anything other than C, or perhaps C++. For future projects you'll almost certainly have to use C or C++. Some Useful Information (Some of which is a review) System Calls You have probably already heard the term System Call. Do you know what it means? As its name implies, a system call is a call, that is, a transfer of control from one instruction to a distant instruction. A system call is different from a regular procedure call in that the callee is executed in a privileged state, i.e, that the callee is within the operating system. Because, for security and sanity, calls into the operating system must be carefully controlled, there is a well-defined and limited set of system calls. This restriction is enforced by the hardware through trap vectors: only those OS addresses entered, at boot time, into the trap (interrupt) vector are valid destinations of a system call. Thus, a system call is a call that trespasses a protection boundary in a controlled manner. Since the process abstraction is maintained by the OS, xsh will need to make calls into the OS in order to control its child processes. These calls are system calls. In UNIX, you can distinguish system calls from user-level library (programmer's API) calls because system calls appear in section 2 of the ``manual'', whereas user-level calls appear in section 3 of the ``manual''. The ``manual'' is, in UNIX, what you get when you use the ``man'' command. For example, man fork will get you the ``man page'' in section 2 of the manual that describes the fork() syscall, and man -s 2 exec will get you the ``man page'' that describes the family of ``exec'' syscalls (a syscall, hence -s 2.) The following UNIX syscalls may prove to be especially useful in your solution to this project. There are plenty of others, so you may find man and good reference books useful, especially if you are new to system programming. pid_t fork(void): It creates a process that is an almost-exact copy of the calling process; in particular, after a successful return from fork(), both parent and child processes are executing the same program. The two processes can be distinguished by the return value from fork(). int execvp(const char * file, char * const argv[]): Loads the executable file path, or a file found through a search path, into the memory associated with the calling process, and starts executing the program therein. If successful, it obliterates whatever program is currently running in the calling process. There are several other, similar forms of exec. void exit(int status): Exits the calling program, destroying the calling process. It returns status as the exit value to the parent, should the parent be interested. The parent receives this exit value through the wait syscall, below. Note that the linker introduces an exit() call at the end of every program, for instance, at the end of a C main procedure, even if the C code doesn't explicitly have one. pid_t wait(int *stat_loc): Returns the exit status of an exited child, if any. Returns error if there are no children running. Blocks the calling process until a child exits if there are children but they are all currently running. pid_t waitpid(pid_t pid, int *stat_loc, int options): Similar to wait() but allows you to wait for a specific process of group of processes, and allows the specification of flags such as WNOHANG. wait3(...), wait4(...): Similar to wait() but allow different combinations of parameters and flags. int tcsetpgrp(int fildes, pid_t pgid_id): Sets the foreground process group id to be the foreground group associated with the controlling terminal. The controlling terminal is usually associated with stdin, stdout, and stderr (file descriptors 0, 1, and 2) int setpgid(pid_t pid, pid_t pgid): Sets the process group ID of the process with ID pid to pgid. int dup2 (int filedes, int filedes2): Causes the file descriptor filedes2 to refer to the same file as filedes. int pipe(int filedes[2]): Creates a pipe, placing the file descriptors into the supplied array of two filedescriptors. Process Creation To create a new process we use the fork() system call. The fork system call actually clones the calling process, with very few differences. The clone has a different process id (PID) and parent process id (PPID). There are some other minor differences, see the man page for details. The return value of the fork() is the only way that the process can tell if it is the parent or the child (the child is the new one). The fork returns the PID of the child to the parent and 0 to the child. This subtle difference allows the two separate processes to take two different paths, if necessary. The wait_() family of functions allows a parent process to wait for a child process to complete. You may want to do this when you create a foreground process form your shell. It is important to note that the wait_() family of functions returns any time the child changes status -- not just when it rolls over or exits. Many status changes you may want to ignore. You may also want to take a look at some of the flags in the man page for waitpid(), you may find WNOHANG, and others helpful. (WNOHANG makes the wait non-blocking, if there's no news -- it just lets you collect information, if available) The following example shows a waitpid(). It waits for a specific child. wait() will wait for any child. There are several other flavors. We'll discuss more about what the execve() within the child does shortly.  SHAPE \* MERGEFORMAT  It is important for your shells to wait for the children that they create. This can either be done in a blocking fashion for foreground processes, or in a non-blocking fashion (WNOHANG) when the child signals. Although many of the resources composing a process are freed when it dies, the process control block(PCB), or at least some of its information, is not. The PCB contains status information that the parent can collect via wait_(). A process that is in this state is called defunct. After the wait_(), the PCB is freed. If the parent dies before the child, the child is reparented to the init() process which will perform a wait_() for any such process, allowing the PCB to be freed. Orphan process that are waiting for init to clean them up are called zombies. What If I Don't Want A Clone? The exec_() family of calls allows a process to substitute another program for itself. Typically a program will call fork() to generate a duplicate copy of itself and the child will call an exec_() function to start another process. There are several different flavors of exec_(). They all boil down to the same call within the kernel. One parameterization may be more or less convenient from time-to-time. An exec'd process isn't completely different from the calling process. It does inherit some things, PPID, GID, and signal mask, but not signal handlers. Please see the man page for the details. The exec_() functions do not return (a new process is now in charge). At least it is fair to say tat if they do return, something bad has happened.  HYPERLINK "http://www.cs.cmu.edu/~412/projects/proj1/simple_fork_example.html" The previous example code also illustrates execvp(). I/O Redirection To implement I/O redirection, you'll need to use the dup2() function: int dup2(int fildes, int fildes2); Each process contains a table with one entry for each open file. This table contains some information about the state of the open file, such as the current offset into the file (the location where the next operation will occur). It also contains a pointer to the system-wide open file table. This table contains exactly one entry for each open file in the system. If multiple processes have the same file open, the corresponding entry in each process's file descriptor table will point to the same entry in the system-wide open file table. This table contains some information about the file, including a count of how many processes currently have it open. It also contains a pointer to the file's inode, the data structure that associates a file with its physical storage on disk. We'll talk more about this when we get to file systems. It is also important to realize that many non-files use the same interface, although they operate differently under the hood. For example, in many ways, terminals can be manipulated as if they were files. By default the first three entries in each process's open file table are open and reference the terminal: stdin (0), stdout(1), and stderr(2). To perform I/O redirection, we open a file and then copy this file's file descriptor entry over either standard in or standard out (or standard error). If we need to restore the original entry later, we need to save it in another entry in the table. The following is an example of I/O redirection.  Signals Signals are the simplest primitive for interprocess communication (IPC). We'll talk more about these tools later in the semester. Signals allow one process to communicate the occurance of an event to another process. The number of the signal indicates which event occured. No other information can be communicated via signals. But signals will be very important in this project. They will indicate changes in the state of a child background process -- such as its termination, and other important events....that its time for a process to sleep, for example. When a process receives a signal, it can take an action. Many signals have a default action. For example, certain signals, by default, cause core dumps, or process's to suspend themselves. We can also specify how we want our process to handle a particular signal (Except for KILL, which isn't really a signal, although it looks like one to the programmer). We do this by specifying a signal handler. The following is an example of a signal handler:  Pipes Pipes are a more sophisticated IPC tool. They allow for a one-way flow of data from one process to another. (Okay -- SYSVR4 pipes can be bidirectional, but we'll stick to Posix pipes for this discussion). We'll talk more about pipes later in the semester, but here's the basic idea. A pipe is basically a circular buffer that hides in the file system. We use it in a producer-consumer fashion. One process writes to the pipe, and blocks if the buffer becomes full. Another process reads from the pipe and blcoks if it becomes empty. A read will fail if the producer closes the pipe or dies. And a write will fail if the consumer closes the pipe or dies. Here's how it works. We create a pipe in the parent process using the pipe() system call, by passing it an array of two file descriptors: pfd[0] and pfd[1]. Much like file descriptor 0, we will use pfd[0] for input. And we will use pfd[1] for output. We fork and create a child. Now the child and the parent both share the pipe file descriptors. Each will close one side of the pipe (which side depends on whether they will be reading or writing. Next each process will use dup2 to copy the open pipe file descriptor over stdin or stdout, as appropriate. We then close the pipe file descriptors, since they are no longer needed. (If we will later need to restore stdin, or stdout, they should be saved, as we discussed with redirection). Now the two processes can communicate using the pipe via stdin and stdout. If we do this in between the time we fork and we exec_(), we can tie processes together using pipes -- even though they are ignorantly communicating using stdin and stdout.  INCLUDEPICTURE "http://www.cs.cmu.edu/~412/ln/dave_ln/pipe.jpg" \* MERGEFORMATINET  Heres a simple example establishing a pipe:  Process Groups, Sessions, and Process Groups, Sessions, and Job Control When we log into a system, the operating system allocates a terminal for our session. A session is an environment for processes that is (or at least can be) associated with one controlling terminal. Our shell is placed into the foreground process group within this session. A process group is a collection of one process or of related processes -- they are usually related by one or more pipes. At most, one terminal can be associated with a process group. The foreground process group is the group within a session that currently has access to the controlling terminal. Since there is only one controlling terminal per session, there can only be one foreground process group. Processes in the foreground process group have access to the stdin and stdout associated with the terminal. It also means that certain key combinations, cause the terminal driver to send signals to all processes in the foreground process group. In the case of CONTROL-C, SIGINT is sent to each process. In the case of CONTROL-Z, SIGTSTP is sent to each process. These key combinations do not result in character being placed in stdin. There can also be background process groups. These are process groups that do not currently have access to the sessions controlling terminal. Since they dont have access to the controlling terminal, they can't perform terminal I/O to/from the controlling terminal. If a background process tries to interact with the controlling terminal, it is sent a SIGTTOU or SIGTTIN, as appropriate. By default, these signals act like a SIGTSTP and suspend the process. The parent process (the shell) is notified about this change, much like it would be if the child process received a SIGTSTP, died, &c. It can discover these changes through the status returned by wait(). Your shell will have to handle these changes in its children. Processes are placed into process groups using the setpgid() function. Process groups are named by the PID of the group leader. The group leader is the first process to create a group -- it's PID becomes the GID. The group leader can die and the group can remain. A group becomes the foreground group using the tcsetpgrp() call. This call makes the specified group the foreground group. It can affect itself or any of its children. If a process forms a new session by calling setsid(), it becomes both a session leader and a group leader. For a new session to interact with a terminal, it must allocate a new one -- you won't need to create a new session or allocate a terminal. Instead, exec (exec xsh) your xsh from the login shell (csh, sh, bash, csh, etc). This will replace the original shell with your shell, making your shell the only process in the foreground process group. You will have to create process groups, and manipulate the foreground process group to make sure the right process group is the current foreground process (which could be your shell). By making the right group the foreground process group, you are not only ensuring that it has a connection to the terminal for stdin, stdout, and stderror, but you are also ensuring that every process in the foreground group will receive terminal control signals like SIGTSTP. Please remember that you have a choice in this project you can take the short-cut. But either way, wed like you to understand how this works. If you do take the shortcut, you can leave all of the child processes in the same group as the shell and masked SIGTSTP when they are created, so that only the shell can recieve it. The shell can then propogate the equivalent (but unmaskable) SIGSTOP to the appropriate children. The approach falls apart, for example, if you want to try to run your shell form within your shell but it is good enough for this project.  INCLUDEPICTURE "http://www.cs.cmu.edu/~412/ln/dave_ln/session.jpg" \* MERGEFORMATINET  Heres an example that illustrates tcsetgrp() and setpgrp():  PAGE   PAGE 1 CommandLine := NULL FgCommandLine FgCommandLine & FgCommandLine := SimpleCommand FirstCommand MidCommand LastCommand SimpleCommand := ProgInvocation InputRedirect OutputRedirect FirstCommand := ProgInvocation InputRedirect MidCommand := NULL | ProgInvocation MidCommand LastCommand := | ProgInvocation OutputRedirect ProgInvocation := ExecFile Args InputRedirect := NULL < STRING OutputRedirect := NULL > STRING ExecFile := STRING Args := NULL STRING Args int main(int argc, char *argv[]) { int status; int pid; char *prog_arv[4]; /* Build argument list */ prog_argv[0] = "/usr/local/bin/ls"; prog_argv[1] = "-l"; prog_argv[2] = "/"; prog_argv[3] = NULL; /* * Create a process space for the ls */ if ((pid=fork()) < 0) { perror ("Fork failed"); exit(errno); } if (!pid) { /* This is the child, so execute the ls */ execvp (prog_argv[0], prog_argv); } if (pid) { /* * We're in the parent; let's wait for the child to finish */ waitpid (pid, NULL, 0); } } #include #include #include #include #include int main(int argc, char *argv[]) { int in; int out; size_t got; char buffer[1024]; in = open (argv[1], O_RDONLY); out = open (argv[2], O_TRUNC | O_CREAT | O_WRONLY, 0666); if ((in <= 0) || (out <= 0)) { fprintf (stderr, "Couldn't open a file\n"); exit (errno); } dup2 (in, 0); dup2 (out, 1); close (in); close (out); while (1) { got = fread (buffer, 1, 1024, stdin); if (got <=0) break; fwrite (buffer, got, 1, stdout); } } /* * This example shows a "signal action function" * Send the child various signals and observe operation. * */ void ChildHandler (int sig, siginfo_t *sip, void *notused) { int status; printf ("The process generating the signal is PID: %d\n", sip->si_pid); fflush (stdout); status = 0; /* The WNOHANG flag means that if there's no news, we don't wait*/ if (sip->si_pid == waitpid (sip->si_pid, &status, WNOHANG)) { /* A SIGCHLD doesn't necessarily mean death - a quick check */ if (WIFEXITED(status)|| WTERMSIG(status)) printf ("The child is gone\n"); /* dead */ else printf ("Uninteresting\n"); /* alive */ } else { /* If there's no news, we're probably not interested, either */ printf ("Uninteresting\n"); } } (cont) (from previous page) int main() { struct sigaction action; action.sa_sigaction = ChildHandler; /* Note use of sigaction, not handler */ sigfillset (&action.sa_mask); action.sa_flags = SA_SIGINFO; /* Note flag,otherwise NULL in function*/ sigaction (SIGCHLD, &action, NULL); fork(); while (1) { printf ("PID: %d\n", getpid()); sleep(1); } } int main(int argc, char *argv[]) { int status; int pid[2]; int pipe_fd[2]; char *prog1_argv[4]; char *prog2_argv[2]; /* Build argument list */ prog1_argv[0] = "/usr/local/bin/ls"; prog1_argv[1] = "-l"; prog1_argv[2] = "/"; prog1_argv[3] = NULL; prog2_argv[0] = "/usr/ucb/more"; prog2_argv[1] = NULL; (cont) #include #include #include #include #include #include /* NOTE: This example illustrates tcsetgrp() and setpgrp(), but doesnt function correctly because SIGTTIN and SIGTTOU arent handled.*/ int main() { int status; int cpid; int ppid; char buf[256]; sigset_t blocked; ppid = getpid(); if (!(cpid=fork())) { setpgid(0,0); tcsetpgrp (0, getpid()); execl ("/bin/vi", "vi", NULL); exit (-1); } if (cpid < 0) exit(-1); setpgid(cpid, cpid); tcsetpgrp (0, cpid); waitpid (cpid, NULL, 0); tcsetpgrp (0, ppid); while (1) { memset (buf, 0, 256); fgets (buf, 256, stdin); puts ("ECHO: "); puts (buf); puts ("\n"); } } (from prior page) /* Create the pipe */ if (pipe(pipe_fd) < 0) { perror ("pipe failed"); exit (errno); } /* Create a process space for the ls */ if ((pid[0]=fork()) < 0) { perror ("Fork failed"); exit(errno); } if (!pid[0]) { /* * Set stdout to pipe */ close (pipe_fd[0]); dup2 (pipe_fd[1], 1); close (pipe_fd[1]); /* Execute the ls */ execvp (prog1_argv[0], prog1_argv); } if (pid[0]) { /* We're in the parent */ /* Create a process space for the more */ if ((pid[1]=fork()) < 0) { perror ("Fork failed"); exit(errno); } if (!pid[1]) { /* We're in the child */ /* Set stdin to pipe */ close (pipe_fd[1]); dup2 (pipe_fd[0], 0); close (pipe_fd[0]); /* Execute the more */ execvp (prog2_argv[0], prog2_argv); } /* This is the parent */ close(pipe_fd[0]); close(pipe_fd[1]); waitpid (pid[1], &status, 0); printf (Done waiting for more.\n); } } 0PQ   ) ! l m x .4$BE+U` !_r B!F!!!####$$$@%C%D%.+=+--....0hIg0JCJOJQJ\^JhIg0J5\ hIg6\ hIg6"hIg0JCJOJPJQJ^JaJhIg0JCJOJQJ hIg5 hIg\ hIg0JhIg hIgCJ$=12;Rmm 2( Px 4 #\'*.25@9 2( Px 4 #\'*.25@9 2( Px 4 #\'*.25@9$ 2( Px 4 #\'*.25@9a$$ 2( Px 4 #\'*.25@9a$ '  7M~=Mc 2( Px 4 #\'*.25@9 2( Px 4 #\'*.25@9 2( Px 4 #\'*.25@9 2( Px 4 #\'*.25@9`cr * G S k v    ) $a$"$ 2( Px 4 #\'*.25@9a$gdIg 2( Px 4 #\'*.25@9) * f ! m V 78ZSTj & F & F & FgdIgjk-.34stHI2^ & F2323 !u A!B!!##$$C% & F [$\$^[$\$ [$\$`^C%D%F%Y%Z%0&1&'''*(+(M)N)<*=*++,,,,----// & F^///2233"5$55566:8;8a8b8Q9S9r9s9::;;;;` ^`^0033"5$5Z5\555555555 66$6)6=6B6V6[6k6r6<8a8::;;;;<<<<<<#<'<<<<<<????@@@@AA#A)A)BaCFFGGG hIg5\"hIg0JCJOJPJQJ^JaJjhIgU hIg5hbLhIgmH sH hIg0JOJQJhbLhIg0JmH sH  hIg0JhIghIgOJQJA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;^;;;;;;*<h<<<=>?0?n??? @@(@)@6@7@@@A^A_A & F  & F  & F _AAABBB(B)BaCbC}D E EEEFFFFGGGHIIII] h^`h & F GGHHIINNdNjNxNNNNOO]PcPPPP!Q*B*ph8jjkEl-mmnnnnnnnnnnnnnooooo dd[$\$]dd[$\$]` ]^ ]`oooo o o o oooqBrrrgsttuu vvvv & Fdd[$\$]^ ]^dd[$\$]` dd[$\$]vvvvvvvvvvvv v!v"v#v%v'v(v)v*v+v,v-v.vxv$ 2( Px 4 #\'*.25@9]^xvAwyz}~Yׁ#ąƅDžȅυЅ 2( Px 4 #\'*.25@9  2( Px 4 #\'*.25@9]$ 2( Px 4 #\'*.25@9]^Ѕх҅ӅԅՅօׅ؅مڅۅ܅݅ޅ߅ 2( Px 4 #\'*.25@9 )7G p^p``&`#$ 2( Px 4 #\'*.25@9GHjφІKLƇ"#=IJ ^` p^p``JKpvш҈1LMVщ;emnn}Ԋ(<Ofy~Ƌ؋W 2( Px 4 #\'*.25@9WX{͌Ռ֌+,<Dtȍɍʍ͍7: 2( Px 4 #\'*.25@9:>y{Ɏ QޏERߐ  2( Px 4 #\'*.25@9&'245PQ͑79_`jkw{Ւے1LMmϓ/078K_sCDOQ_kwwƕʕܕ+/2BPQRiŖߖ!2689:LMcʗҗӗ (H]elǘ^ǘ#$Bnvw2IS\q{ߚ@nnxЛқ%&'( 2( Px 4 #\'*.25@9 (hIg* 001h/R / =!"#$%Dd(# !D  3 @@"?Dd]#  c A^ ?http://www.cs.cmu.edu/~412/ln/dave_ln/pipe.jpgR"K$P1$MwFK$P1$MwJFIFPPC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222@" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( *\ILIڊ cceϮ+3@eϮ+3G&Z_"4Q\&Z_"4eϮ+3@eϮ+3G&Z_"4Q\&Z_"4eϮ+3@eϮ+3G&Z_"4Q\&Z_"4eϮ+3@eϮ+3G&Z_"4Q\&Z_"4eϮ+3@eϮ+3G&Z_"4QYNe|U޴(((((|Aki(lbT1"$b.'EjQ\&Z_"4eϮ+3@eϮ+3G&Z_"4Q\&Z_"4eϮ+3@eϮ+3G&Z_"4Q\&Z_"4eϮ+3@eϮ+3G&Z_"4Q\&Z_"4eϮ+3@eϮ+3G&Z_"4Q\&Z_"4eϮ+3@[` $%($I@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@xW_)O C dx*IW!H ]-oN<Gaq給o#Y #SOFR@; ( ( (9sşHkgc+Z((Ok:泠jpZ,[Đ1)pǜb#b;xT]FB=N[$4u(I\8pAxjǂ`[gUxuYEƯ~DrDudG,G˒h> H/Ƴ_^m+J#;"TQT0'9.h>+_ kGioy.A\E$Kcẙ0^]*󓁓ijR۳j!RRhЃÞx׼eKx!ԯ. e5l_YBe$u* 1liV iv/}w|`Mhei\vTN82q@.QEc:7tϲZ(_y2O@Cѿm+CLt}oloydIvg8q? ѶQEQEQE~ Ѽ׍uU4ýmme i`9\ɬ#JC^ҜbB䃀wq>%{/QgYY!IkMc5ޭ;heV(O<c?x8OE+mjI--5Ī"D6Rp8/|=KH$Ҡ^c3\I/ ?ϖ*Įɯ+-cڵ<>mV,X14 z~'QsF ai<˛x"JڨZÞ%RNc4 0rlYhPoqJ)W6o-GZS\=Ě-iV=T>D&)ɍ*=wVf4 G!Yʋ+Y3>eր.x{C,Ek]s?+ZA@Q@Q@Q@Q@sPo_J+*FPw=ޛ]חE=ėNmf1[q؀4G.mC[K;xnX2 (9gY1;Js?]2-6;KշwV%L9N3"yss}zO9 k?nB\w 8 3߳j_h/pmsL<]@'V4oi:ӛ/0i,JedUZ*F^^oyg3uvy&A"64#H(((((((((((((((((((((((((( z_iw "{o%$dC\Ps=ﶒk;h[ ʜ9Һ({T\6_Yx>=ڌ^(=oXaeO¹?idt !w(\ݢecU9jzFJ~<=ihde1%m"GOe'5'aq%Z#3 1v88cַ({T\6_G#ڧzz(S=s=j9렢9GOeN\Z^RI5-reNTA]e=ߛ/Gv~m>ZoHll",rZ(S=s=j9렢893خ%Dz]@$b ) s("5o_DUq;un|I kaZOv^KU w~t `<Ԡ*g%|#Ee$+A;9cS(ni9"] V>Gwɨ[.sW' wPIEs.˯'Ciy'{qm72Du9-{,_KmnORAW8,A`P?ŋk;k-[ğM#E쀃X\;vH{T\6_]=ߛ/GS=s=tP?C~lGOeQ@#ڧzz??s?͗#AErv~m>ZoHll",rZw(ndg68 º(ֶ[Y$qob[`8IC~l (?iv dYޤ "hP [ k;F>@2 =ߛ/G'sH˸gk۵d!*me!KnGpV }c~,u4ܤȧ *p3??s?͗#C~l yᵷX$/$0UE$xs@.=:䖷Q<3'f7#d[dҺGxF {H(H 0;A֥QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQESu[K;|E̒p@&|Y猼A}<߶F, <x.<'g_ hyxgNU?8*Xdg5O|ok:tۑRW7oQ1 a0%s0 Sč vgyڔ-#y#b1@fEyw/`-I&vTv'N66$2Mėwev#'sP0ğGk1q`q@e!PI9_nS֛}c==Żҏx g 5(((((((_r^_ik7<4\X2HX{o>xwEIR6!G"R72r,}ĺyFy,)`2u<TW? džWQL {"373(3FN)v<2Bč" "@TP0R[u> 86Z(a*,nƤ*~SOͧxyMn[y 7Q@[o^|If|I0vM! Q 3KҴ_0E.,m9dGE7 caU,;9, 1"6#*x8 €,Q\"6vח/o.Q O$y'vT%<)AjZf -h~~]2䌊]kwQ2iH@Ob o;## CxT 7zE.Q8E¢ k?_+VRA||{v9$l`tq`>x_:ֹ4rYh307dr?|0.rJEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEWos7tI#n71 Վ@$1+cSMwz:琳p2OV<R*UZ\:-ϱ%= <J6=l.5AÙl6g< aXۓ}kEzC,zKK* 09ے+( ( ( ( ( (zepZZǍO $< @+/R\-= Z%2Fj#g$U?7Y׹iK5dV,/N$B, FTvMCh^GWIef8IP:(/*-gx1r?oaV,|1G~}SLPCmcN[M76f((((((ym"h%BG"WR0A:5˰y*")*~fAEsT[(Fr;OLtoXI T`Q8&b9ڮN3 Q\!z6i0I1]S .H [^/K4+#`B;: +_._iyh8ǟ.1t>p0u4[MmK-/W(Z̲lTq(Q@Q@Q@Q@W4<[Xii;QA,p98Cuo-QRHPF Ab>`6><ȫ, \L0w)!T9$/cqwVr[Tmg%w^k)I,9T` Ϥxt Cqmvi7 ġ~oyUy*Js'=xųi4\ZZ(̈s!8 }OI Gq)Ƨg ,g ?z vx},> OI7911#%s7p gھMl侼&\F2͓• F>Ӣ((((((((((((((((((((((((((;|9 IoKi,cǼ('p.ryo͏6MW֐jzo\ꨒ6O<6\K0DF dOkHmFz)!dY[0۳|\nCP\rxNڿǼ` 9 >PUcA5'|5|?kH'u ^"8e u{8gݚmd 0v韔`rx_2M͆ql|Nq0n}iMlc_bŘ,Icd@Q@Q@Q@V^L 2c<0AA $?VPȷ v1ٰvFfUj:;z~2c%c ,`e+7Rli=ȏ=e2I!'\!*)fڣ&(((((((((((KÚFpWv1@DLWIL:N@at&(Fϝ'w*UglNIhwtHUp&%XbyɆf 91'9LtoXI T`Q8&b9ڮN3 O ռW4x䍃+s~5ķIiw3y 9;' ܢo0[UjinZ<#%68tpN 2EPEPYOI󼟷ZKmݳz݌9EhQ@3V|ZEsnݳzۜ 8Ig}Ŗim=﹒Uf9rX>࿓IlCgwwern$5|"($]QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQYz֥5Ck`˩ݸH#pHUܢIX>HշW'j @&ej*x*G86\ i] #)$nvbYrIW(5; iQ_kitɷ_>R 4*yX SCt?MtW?'T]G SCt?MtW?'T]G SCt?MtW?'T]G SCt?MtW?'T]G SCt?MtW?'T]G SCt?MtW?'T]G SCt?MtW?'T]G SCt?MtW?'T]G SCt?MtW?'T]G SCt?MtW?'T]G SCt?MtW?'T]G SCt?MtW?'T]G SCt?MtW?'T]G SCt?MtW?'T]G SCt?Mti=ZkGĄc*LqJ$Atzx?M4 4?CCv,&Lr&ՁV#\~њ tXDdS"TQvZW B 4?CAEsx?M4 4?CAEsx?M5^^4 hqLٱ8 JWR٫/=<+HۣoϞtF7_ V SCt?MtWOV!֍ i/D"b!r<((((((((((((((((((((((((}oi7yv<>vXrpY%Vc+F a9,rwl1PW'#kS4('(YQ㓡˴dc QEIu w$Ŀ M]QEQEQE&NZQ5=,(`xercyt4֯:ez`)_Ee&.FI((((((((((((((((Z:e",8 x2O!@H$@b2He|bҧGm|_]gqdg#Mﯚ7/]^o,HW 1(qw`hԠ(W'ڈУcĚ%|Iqjڷ!X&*te$?7 ccoYkk dX$YK1$ĒI$MX(*E5tIu (x\Lo.7:6 sz(/1ּ7oĞumNOԈ`@'rn@.(LYbYAʋ?zsր,QEQEQ\~+g7M0g4 ''Aʞ1nxĖ~޹Zސ(.w:$;ů-oE׼5iY!,RKx%r+(((((((((((((((((Jk {h7[[U,y &ܮAjW?Q - ۔XQ@V@:B2JAy[;f%$r((*E5tIu (((+*֣HnREod`䅎Mxݸ?Qv SI.uia`I+˘XUx\ݿ?wsSKh=,260U7E[;KND+%ÖڠJ$D/ إZPEa4\Kg5{v&##`H˝ +XonJ?adn@aEm,_x4~H !R,Ưxx/ <.(2䌝p(#bL KX#pIjQEQEs;y_]覮"cuf'9aϥG?5";x/4ױi6H&=̣ ?s 4ςMo.4>m}"v1)++}`rNmHq^DmSU0\77k#$H 0.# KTzl?>SԿH2)K$q1NђrrϾ7%vjޗViG3t B+6'N2OxtmNA5vx"XSRxZ8?9Fdu9ݷ7};3~EIa{;F[6RN<8bCh?_?_9]PvqՆ3UK?oO}^Oqw9;xigyy}g[kDr,) T㜁qv:}@sǮw 4[d#u'hbrC,~`'.s e4#zmc7v *H=B>)K+_WԵb[X/<9x]FFvܒ0y>v\,Z^%xp4 _4M2 qgkzKvxfkHzqpY ry'c/5%Ғ{: 5=6r_!s$ŌM98􋿇mׇ!o(Fz7K2;dvX1,njdV}mP}i J]#7?hѮdmGnه+nXЏ64>w湒nUP(frQsrOxtmNA5vx"XSRxZO QR=JKPv@%4YLw/&l%ypp +yEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP?i{Yf$?gWpy%Hé GV+B-6g]KMhԣ@`IN2IW$.cMԡHHs H A2r(((((*g%|#Ee$+ZXD<^gr+`Y}Jc?:q#I'VW e^$t- tJ H#;A($MSW׵>ɳ=[݌qiN[X]bR$(8gP_$W.\g> *Ha t+)$ OΩcz+ s<H@ ѧS}],5;w1#u8 +{x$qơU 8IEQEsZxPw@ """v +sO[$+KHIqr[mGg*f,ǎ$$_[r]]I˜,I$UQI(@@+O"z\][j)*A"7rp79ۊ-woڸ݅8aFŒI u07:Ěvgl {ialCP$?'oK&aVC{yʹ&;`?!YNⱸb (8 +{x$qơU 8IEQEQEQEIu w$Ŀ M]QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE?Ryw72.9g3[@vذ4k 8[XSq;Q@ 2y8uQ@Q@Q@xW_)Ow$PI< ˣh7ϿCc RH< I#*Q\%nuC ]#Jsl99-t[[ KϙNѲ9$Vv >[v$u^T[ ? |fx5fu!T 9c#VO|Оw3ӧ5>%nuC ]#Jsl99Þ2 GDoBY#פH| yͮrY$ƓPoSK;ٝo42y3DaIЁԼK okzm;䌀dcRnڶ?﹝w9?Z =ŭ-n,.a?gtpaWrM۷mX}\+[%Y"(14/\ctlpik>d7N<ϲ\$3gi8_CU_o5Hw !.͓WpNAnzޢ&]\^mv8{Ts&4)|Mi~p'I1<'٠+r\`u4!.rP[dFb'"tCF4oFݟkx!mTPS*I>WfïͨMZ}U-mJnb koG94M;G(6Hcr"83/ O~\kލm=ݺJLT&X}xA>ŨTt)fѰ`c4McBO G^K%Km?@1IJWʞ*ƻm>X}>"(^>+*`PlwylASk jf:g}oei[ƅdHsб4, ?*BY3×wzU{6MHc\# =ȩ5/:5ޛc; u"b# 1g[]x+[[xFE%J 7dds[YV]{ҡdyXnIH BŞ *ȉɽ;`#$*K=sMmAt۹LoUX]QA#8<}RX-Wz% aZXb!$Ox'&ihY=,nQQGFe@g, ѵrO}(?1UKI^,ݏiV|K<>uiFu'88#^75A'`iMwgH"Ppүt-Z+)!aF͕CB@@ڠYAnK vI+!I8>⣇ŞT~2^R- 3ּQ5 z v7zdxrM:{˺m(ٔ ī~`,E.o<YH|Ms['dP0DGd<(q7357`n rkc $g'dMX.^zmiIe9BNa.&_8w7ZYHˎDeW/;p8?#}xWԯ K^{( zrje!D 1m[knœ g]gPx}*WѮmodͷ$(zݴ A}gYywx4r@c ~5zY.2]ˮY"Cyk{[+#d,Ȑ]lj4H|GKF ynxĂ6#}VG r(KwGgu[~ó~e/3'8jǃvmw=kC=U䴜9rxd'\~7lumjƿ.- }ڡ8_i~ =*v_Y%JssS 5NoVU-2k cZaZ9#${\OR,bB͚H-!~ldm4i:3 .N3?mݭbvR1<6drp&EZv%.43Hb兒%vH{953V4zT1PNĨ(;X3P@Ygiսis=칎pTH>ߛ8>pq8=} q~6l-ҧЦV4Q FT  d˽E/}Msiq. 1VpMwQEQEQEQEOUa DIHuWBA2ڮQ@z&5ٵ-^^BGߏ$O R=Tw VҘ䌜g.BSYk.kQI4)1M&ң$ N<5tD:k)x$XQ d]QEs;y_]覮93[±FA;FrCFXcFnit t)% A;?;@$$NMjP'h׉YbԙܞbFpJF xKF+X lYp$A3nQ@Q@Q@Q@Q@Q@Q@xW_)O[&|X6ȱYŘ8버tVԵi[k]gO㷸G0Yv \(+(I\0i0O+ɺ&"?sr7"q\7 x[Ii Kuɑ0r$#W;#^^P6WR\Y]kټ0F"+K쨋.UIZ众Ev I/ jCRkm9-@gAA`BU,;9, 1"6#*x8 ¼~{X-"}7/๞!Sk4gM+ms7>qξ&GӼGak_8Q!|p88N494Yi F06:qW m #@dXI\ M;D%qLb'~Hb5[7+{_Z4#7 5++;xY//e+[fH &THV%ƯqeIO׆Ile9Ȅ!\J szW)%ܐ$0`QG1&cl{8#fK1/( ,8zEփg}T^hDlj(I ,-4fV1v0T3.ϕ Hkh:-Iw^X̣׷8\F\Z6tL/p]Z'`|f,x95xQ\Xriw:=WANCKU?>nygn\$wds0 Ks*I(X/^ (^MzƗ~ڕ=݋tk{UJ^v;r$Ajx|ƹ3_x5Jnnbp-ʄ+!9@K^\j#TSPd@jF %" 8u4Q\\|IV.[N$ԤXP#r~MCQ|y<\ji nkGIO.vƅr5z׼ 1G=;ݵ!*X\دMZ]c?qTkɥj~ZȳV1cb#o6]]Kpꚬ>E[LuhU2nŸCxVX׉t뻯Iy]H& +HV[wWp7 ym 닭^& 7KZ$f,j Mw=q@Exݞr<5燵KSd]i7!_6196ͅ%5 zmIn4zŽaVmʲI$31Fڲ\kO٧k8vJ W O7p89LՓSRmM>& e+"y/Ѥt=SF>4/{ˬv#s\>x. Mi6 `-դX9 XũgȮYWQG I.U\Ç ;сRA (((((+QgAIͦKU;I@8Q@"#,ޜ'9Q@ T^ jZ5LE-10$9@i1 CGxW_)_VnWͷ!lm8'$: (SsYEiAEsi >tP? >xj>/5x4:u0R0I^p#9 (51ס* (51? x±3\\FI/nnI%i. nC(VB m+5@ōȞOEX1w?Tx·W[Fy\$q38$1[PEP?xsEwD#Y=rWGA\_t{cl./]WYLJE12t<1)PEPEORմn5MBp%8'ƀ.Q\%isΑ꺬c5+dk*$4e9dWҴ3[(]bXv,O# V=->K)81 )w 5_+{u]OUF(?#r #lXYqZAikvCb4\Np2I?cnUn:L=%Awo^35p1uu<FTP?Od?OsVi/]{>s]PEPEPEPEPEPEPEPEPEP?'%Uj+*E5tQEs"-,Xs ֯q4JQ$jC4kըn.%"BI#TP2I'5Con\5Yj,VȲM8 CO\WIau ?m>ښzK'ޣv#4[qo,sA*H2AG9GEdبE$v;<̆ pdH<ޙkwmtio 􁬞H-4YSj'@4kڴZe 6T/M@u.ϸ( 7zwp]ɝA G\},[N,񼥌L6r+1 h Iʴ[5HpR8gk6s3sɭ((((((((((((((((((((((O4M`cقۃzJ(דi5,vt̪HANIz4rN{w$F%9PAS6csp7((((/ʁ #`A"((+?Um>λ+rs@QQ[ic3eU 1{n%`m3BnǗev1c:QEQEQYvxRe)REȸe67B:VQEQEQY~ft[Gm:\[rT4Suxv  !y$($sχS|C{85>n˷Nswv:QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW~f}}tuE$ rׯ8=be&oO5ƨMf.\G/>fwG͌1G/NYڷ~ydFU2ɍx (R+/WqL;{ Wd7|AzÜ3x Ul&KJo ֢d ˅.c(bpԝܿQ@/M>k:.6>inn-n+1dn?}3 cMӭbQ:G5?Mi%I$FUl, Jvk10/ ZbAi:o JE  2WViڬrcJ̒)N6A?G@ x\LOJDhr*/?{$ qN &Oh"^dN$Tۺ6r`5s %7k'ؾ'ٻݜP_lۛMJZR_Mi,fӣ%X( *~pOͻ)!b[{Akً<*(?m>i6ٷn;Mfs9(OaEGl@6ߛ;:fj6<$s"'Fnrr0EXҵKMkKԬGM;^kpzF=[wW>-.I(5XYt%C!A3D~Y]$uOXˣᘵ9/,?[9r @YऌsknC-1Dđ ߼O]qqYE`<=7$>I! dyU0HMT.Vot96y̞PXFIݵT|Ì=rxni"sP%쒣|9!vޜ* ];H9[w ѵfTۻe)^j3X,(6Sb8vmZI]yin$a@B3\}zWYu7:ŝf5d3$l:p` |>-|A =aj*ȡ,@Χ(! iZdy|q6%̶ӏHɻʹD&EqKeӴ3a$;-S[g|v,p0H8=%zh-suKi=9 L۶UH8VIis|C{qM۴%Tx -ɮŠF!ς<7$."Ѵy#gscYu7:ŝf5d3$l:p`hmfq7)[ڍkJwܫH1҅8ݜ.+(OQChjf|}oBg, "TʨnO:wqj: VF5 9bb{ T`OK-5ywOD0dr e#veXeu} UQ[Ki=Ǒ-X K#mܽ2 v {)4&ksژ2S( pzWQEy~GZ<1vj6${k bv YZB 5~9dԡu([c׊ `-SRwgwK|Dʅ,;U Fpq@í2F1Aq* ^$RX*Bňsk$6iXkqO=-G5[6GP oPqihA{ ˑtF-4X~H󽕂Ò@#=FSE$Ѧ" sӃ"~~ƬPKR<7' < G-ؓby`\5u{XG#݌%خb3G2DxLL`ʆ3|W*u'K '/#h8fQxow$u+)ln푑nHtU.щ@$EaZɥW/B]m[S[!%x$z&`[hڵ`Kn 8PI -.uK67vi̍ &X2P趓cv|;'$cM #pY`wƒQ:w1i%l!:4&mɷgi s^uKESIg^=\kF|m$\r7@WiPx~W946++Yn‰%ISz03yOV JvO5c/8]`Ag%KxPc Y|`dLT/4O٤o24N,b`vʓW(-?IMjk ŽKH|@o>F e\-~PY4RFA WFۂx9}OOckyҩK{xh>jS0sQU细 7i(qQd+4b((((((((((((((((((((((+67c"ZF(6{)! 2̻Z CVLK##_5YH+#sq:nn^ic9vK` aQhZ=yXXɶ8H$ tvV5/g?j++Y$Kٮd*U)*xmgV[^5.t5)-Уhq F2N+BXnClc_&6L}Gc>_gO'nךcYW՟mf nYxI<]_nsmBQ3|uRJQnDHղ @j$փ6. ѭPč*?3rsW>gH>yfǗnͽ6tq:&,|G}o|U]Awc:ya G >(5O V$ ԮlcAo+IƑ$rYrU8eަ h6R M ZKTPaf,>bI^j; ng"%:7_Œ Ez|K.5"QZ oo'˄ 17cX<yqbqxhJ?0T>l *Gqgh}ἲҬmKtG1Sp=(д}B^^V77B&M5;ɸ!>:o-gY]2{,AxI hn!8.x6K]zZGwa 7N nQmD)eIv J׭n/5WzD]0:хb1 뵷.A<]wx2I㷸mluFyM3(ڙP.GLqZwϴV3}gtolfGͷscd>Wo,y~^6n8LP'A=$䚳Ǯ476-Tvx'?ľ źchxS r03#;  h6[l0Ep.;TUI07u.-QQҬn/n${Nd`F:k'5/o!A 16s(O:$}dk0XG}y,ooGۿn1g(5m{Q}G.%>qBNm<2фXHLJ..4jW1E>uiwH .. |GS[o;;+>ooGۿn1g+BL KX#pIhxS4SS4i4fɞ=o&3@2W]גzֿ=:Jv6Ѐ8x4B1n~f ] Ggl{y0ۢI&㹷09 } Gٴ~ÿ]/.{Ϩj +[E)o5؛W~S;Fzu]#CVL3`dxX|e @:kAŨg7ij)f 眚i:nni}uC`s@w ^"u&:ՠG1+ uAcp+*#>8{Y5=?J,uI#|Gqmq`LrNW``Ccɬxk:i2w,(`7.K` 8*>ۧlkeXi~7}:1ke>k%ɂy|QAX. 8pF^w^}^;qi2"KRM7|c熿|[ZUkibI^hu[z׿<jo1'r3+4dn~iy=>Ic[p3dr3uu {[{M6[G5:¸Œ(Ү};;}>/ݛzm4Jk/e__hzy~_Ot9zO h3iprk H7 w>}k}qGP&-&$o e0I˽-wͻѥ\mz|?w&>Ps yyoop8*|'{;8|?Gkua%r 6#=(ouNiTzB&6cl'|`8r3Shό5Kuk %K#^dz.4-iҬfvϵh<̏ol6v7AߴL]9lzP]A- {O%۬ -%Rdׯu _ipx= -o,0;;ȦGATb%P9ato4MIkj1\Tq*MOB+[Js%ٜgp:z EvncG_h$oW,  }xGwIa=Ѧy[F6s2#t{m>нc BN>p*~a4}-'^H=(G ro Xj~i;^lD ͵LJ]dR!5-W3xkBӵddy0OJJ ʠ{<5ͥåˢikT1#sʦ0܁yP4ۘ-esZ+0(=(֧ug 2k3:I \D2ۏ@rS}i4nxrX"/< V+(c)S Y1#`2*ւm-Ή OSl0!@A1@wwj:qiZ%նx 0Ϻds pghZ=yX_AɹH˵$t5@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@a9'|9a}Aeu]!W2B\>9гfY}[uj9D51m,Yr60FORj |-l}?p]m!~h.sr1gO{$=lю yR4sxx[l,+%]rK=#@lua}scXYYS cxbz.1ܟM, P]u%,`>2|r I5ǁQ5]2R{M>E)|ތ6Bs4'__O[y.-Em-9X0E(`Ec8s.^moYK RY5;m ģK)P#9 {vzIoe/X,7$UK FտC''(YXm*jǰ N@3񖣨AC~{Ŏ;O8m*oUڧ X}& 4^~Eqbatx&6Ϋo}e-̩}$d]Lf6RlIMLQsfy۽IF'j=~i2 cϦ/wFhuǗPɴ9&4縸׵-.-L .ZYeO8hܔ\yQQv47|j6geqp]Pϵ "fڬ@'@xF}}ػ9\i8ͫkυƭecm?\Mc9 lwrpv_A} 햺mI%+Y;qG0 8O9 F|GN\^sk(7|'gj uˍF{K::Y4%o*W #InP^ Hĩ4r<|#Idwq YWi4҅_qf˅#~p@4mWRgufU!" NO1m[r;X5,E$1 $,Wp.A?nu-P=^HΤ$y-\32 E;sdl^iG,cy'S xg(c3v[@ ֚ƒ-u>v1dxȉ. bO3_jGTKֿM\̿jYlUǷaUo  k>#Zw]dZ2,䎠sY{߾[HW:*X3 U;o5c]d+{$+7vm`Ԟ"xMBq]ٺgCVVPlWҀ8Ek>XU5TYʫXg,B$ޤү-I4M^ wT򦙠XfuT،b38/IxN _>&} Ɠygxě!cp8>%m"(/W2L= 1ǥcc fGqk\%&D>Q\2nh!7$uM ɢ+y6vy@a6~yϛݷc=CK3hw~37;PkKQm&#gNA|k;8w7%/#ҕ{g2ywr awr - 7G&"y)p%YK IB2@ syu>w?x#AacwއB@ M)'Dpk^"Pn\8V\9x1^=D]WWE86"U=''$/sX+驧ƙXL6-Qc0p?R4'V"񦍶=SP{?ٖgLD5&"U#|9> _/7ן7m{7&ob.7qA9]{+[>[eoZNi"4R_Xg $ Wz=q* y k7yNiho۪MS؊ 1˻"r4 7[Oj\6F#@:OX_ĺ42=BP>B䑜,d <RԗZYbGBolR"7UqmpX@·i AiՍg<1(-".XtbxHm+jZ&uq,]J& prWA,>I1sr/K"Y q(wc;zF}. < @]bCMx\g#-wlHoefnQپysejd7}9S۽lhOAhE[kn^ (%]*x^6 :֣}}%gהEK nVbc%{'OJCs91| F>f9oj~֯4*w xwα%PIuH@մ6juլR¯h!;C`Dz [ R즐*+?idie;r|FY9 w6+h95}sv {#,qjC’v\ZDϪh6-$0mzM$V+m҆*ʠlG=湡î#]Okp66)TU1}H+SRY< [RMz' w-nt*9!7dL!f!,rh*-:Db4g[?jiqVR ]Sքha|G7mѼ_+ 'RNrjMO6zW۵)Dffx&U0w/-;q@xT]FB=N[$4u(I\8pAxjC^-KH5 5 Rb f@P')`S8N3R$Yn/exđ*(Fl5&m^mKRyh$Egghن``R_,:\zOtpP϶;ў4av n}xsBP|>XQd `t4*z֣5.lBn'|TmcP}R+i ˴9r!$8l_A} 햺mI%+Y;qG0 8O9 K{qJ5}JvH'?@C= _Znq=v'GTk&ePv-wz#wZgE v7&,Sw'j}i3iOw,ڮr%B\DETAԝ '$1׶WԖ }Nme1/d3C{öZkk&# #Qf E'}s:]iqN7W[?{yߺF+FO5x-If#%ƅ*>D{I8E~5`MR`&fBvLc^TAE[jq-܌*2ۄ(!|?>FYsm?tkH5ktU)[Y|mw `t//m>7wl5%A@!VA\2n T VԮu[ۋkImS"Iو5vI<]}yuI>Z^nI̋4eah\gj=x~]CB]}qFeILeR+I]SU<+x†}Y{6bImt==-JK}!bF M tE`Q*{xZՓBִ;+vdLK`]ci`t< $_ KTeCMeګDʃB $IaѴk.ݤh,㷍 TP3(Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@G#2U4 MowtH\>7 :O ]k׭Ry GD۽.Siap@9x?go"Kx/s;EE1 x ?)=2OpȒqXkyD7?YeCgp+b>$v.2iY1yn-gol o4o?n_>yXۻwv._G4{=JT.is2o%]RB"]!i 0N+XkzŦi"X4$ ̩ 6[(;hsZp7oGy[b9D!MIFʲMFw7L{GL4p,06eW@״#šZ%ᦷivbdA{Ğ{үvhm3I ݵF œK{xFQOK=W[6uk#m^ %bc"R 䪴eQsrš O<ik>+|ycy0{i!IvݫѬ5x'ia#ʭ f4.th[:歬Z|~&Igi7QGosnB0ܦYQ7,' 7Ie/FwPf6[-m\!&|0hʧ ' ?(&00kSDjM,g˱v*x`Ȯ-zRƾ53%:,hH.0Haw v;m-63qݸր vvv3jwڅ6Şqǖ*䐣kKMfolF?s"N|Ϊ6c=XIjdҿ|?˞ݤ3](I ocڤ綺U~}JAc Kb>"wiZV#\x/c8=A#pErM[^D.崞{y, LY=UGNLӭ,mbHaME(ָ7þ*1ф%U[y@!`%<hKɥϨFu)b 2 ЮܴeC'  d^:Ь([\7Y-λ^Pf7sӚv[}W]I'` Do 궷Vy g!-H"`!M\e:{^w][kn6($('?eIY$T6X#CU p|/ov(u1<"'!zp+>P2jDZ3yGk=4m##"fgJ;T2@&-!Ƥ%ţ"=Op][*,AzWkYԤƝ>Io-a0R|i:lltv{ (i ed@* F5}?W鱦H.C"Ay-!$-6$~-܉,eV@so_*˴6wF*?M;Ac??Ǿc7M^f}Gڼ+wy.~kƷ{<E ՔRFI(EU8[s &;mjݧ9eRdDs&#$2Eq7DRjږ-dL,K4dEA!q1D?x,o>e$L^I6ʹp3~*F3: e".w)o#*T.8;~t}&gPۋ c< DUT&!}uq׍tMF Osu=Ė6s]oČ6zi$ έ *j_$^TpnMW=xrKXKM<5Kq6ӴFk'vW] .nn3X* H~:H%M "9ZOaÇ#mpH  {LæV&p]1bb"#&rGhݰ>5R+GvYchvʦ5G,@}Z܃Z!ķ #cb*44zMܒ^ stb;(WBH) ϟWLJi6[orŊ[e1nHqݍ֣/<=y$7#)"mN덑SsMĐ0@AA5nK76 4`9'W׭_aX-ȪyX_> ԯOMZ~bYY剚(0m!; M3N˧[M=f;.%[ađSvKUVXnzcmq~4v.I`HW‰L2(4KFGVwg>uxv 4o|6΁<midt^GnH_-ܸ^?u[ Pe \3M#@eFI]qo-r9 ׵> 'LQ&!VHZTRXc _iV q[EF8@?nXzƛ/"@kIK&9@*G&u ]fmn"tPҔ(ʱo_!NӌƷ3Qv6tMԑEļBBr^bjOFp#[prlj4FMf$|We:EimP>mr-O *3d,rZESԴ7Y[}SO\:u ʡF@`FpHϹQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@tuIHD&Mݬ*%u|dx'/,;9, 1"6#*x8 ¬Q@6[0D#5 `*J(((((((((((((((((((((((((((獦$HЪRHp## Pji1\q K rO~Aڪ8;sZP\(Ķzm[eN,[(_9H >lQEcxOz䗗ҮGlXZ6zevvZZǝ$ OV([+MbTgKd1 -6Q.p: (A۬]+[ve$s8*K }3N˵!7'ZEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEٝdDdF  c Ad ?http://www.cs.cmu.edu/~412/ln/dave_ln/session.jpgRc',_41wcFoc',_41JFIFPPC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222c" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( |{;%[Y IQcR (9apq]%y>#cV[P52gv&98 df=b{Q5kMGJ,4-UmĈMn1}3'@cSM|Bc2]w0Q‚O$hWíGP_AMmtѶ~o:& d7PLOnxPz|xvM/aUfdgxW^rW뗺v1լodм"Z;#<ϘLWPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPTMRFkב`WDO+w*Ė`0W++l4eϮ+3G&Z_"5Q@&Z_"4eϮ+3]eϮ+3G&Z_"5Q@&Z_"4eϮ+3]eϮ+3G&Z_"5Q@&Z_"4eϮ+3]eϮ+3G&Z_"5Q@&Z_"4eϮ+3]eϮ+3G&Z_"5Q@&Z_"4eϮ+3]eϮ+3G&Z_"5Q@&Z_"4eϮ+3]eϮ+3G&Z_"5Q@&Z_"4eϮ+3]eϮ+3G&Z_"5Q@&Z_"5x#GGYiV3~#;z滊(|'}hmnfӹv#1kNQQ/\ᛴMsnaNH穮Šw6pVxnIvayV._ j0j7|3vG]`$t5Q@}ƫ;}@>xfѳy9jK]sWf (K]sWfL?E{k9L?E{hK]sWf (K]sWfL?E{k9L?E{hK]sWf (K]sWfL?E{k9L?E{hK]sWf (K]sWfL?E{k9L?E{hK]sWf (K]sWfL?E{k9L?E{hK]sWf (K]sWfL?E{k9L?E{hK]sWf (K]sWfL?E{k9L?E{hK]sWf (K]sWfL?E{k9L?E{hK]sWf (K]sWfL?E{k9L?E{hK]sWf (K]sWfL?E{k9L?E{hK]sWf (K]sWfL?E{k9L?E{hK]sWf (K]sWfi'u=DX@/heK>r)PQAu+b(z7mtQEQEQE@v++l4QEQEc(|5?YUoOݫ|ǰ<g6(#:fqXO!. "˹wG"A8 jPEPEPEPEPEPEPEPEPEPEPEPEhd+Z6eeΆb9儴Daxۊ$8`^4?^Я[6O}$K i I$H `b,ʪq?(ԓV^F[߰.@'c?SwcHIEsqxk]7R]> դ$f"d߷n ]^[go($,."U-° @Eq#icy/8cIt^n-n6;HUI' 0Ԣ{$V_ ;Vd$ <7$YC-ΉCwqq{kh BYL`mW?3=ʂEsv>2:nmƇYyVsNu1 Q5s)Fu`mcm1\yEp.UT6셴B8̯& s&N@ 5v\$<Zo ydpO#ڀ5(>w5 P}:(m2,&fU|x CPIqZVwskh۶ ;_A}7N-oaT3ɽ9o0Ix\|*-X ̇i$84QU/=:O2$F` FAjQEQEQECѿm+~J`i@Q@Q@Q@s2t- e ;o [ tQEo9'(1QY$ ǡD^Eӵ?C<6ْ^+>Gۏ1FN>sz֋5KѢ V/c6S9 ءs67Vơ%Ή;M#lHT#<6I cKEԥ* GDql0`TwZ4 Mx60``: [\_ i@_>fg[(ᛸ8q_Q}+CnLig%4b7H]a/Rv[}6-R٢ ($.YȈ63|8?F:ujOiF8q"P#f-㸋Le[˨붺UUO 'jP^jW+O$Tc?g.G鰉<ϼr9yj)3-+.*t Zu=}u>I$w6dNzNڥ,pkR&k;\Nfa!Zx&SG SZiŰ+ U;38'6~Hҭx0Lp 6+CG_\dQEW4<[Xii;QA,p98 W? >iAEsi >tW? >iAEsi >tW? >iA\k3z׈ak]_EDQv$99CZ >i[& k=VlYiYYd7 }٬Cu}$ڿڟdۼ?c.V&Z_"4eϮ+3@턺sxviNdWO2FpB ب Kӡm[[k 4"O,cV= L?E{hK]sWf0{5Z4I{q6#H-Ȩ;\F,3'xZl}=]Oce1b$XeHP62eϮ+3G&Z_"4X<=]rDͫi\sg J-ˬQ(_<IOC5=;MfWwP L1pҏL?E{hK]sWf3 ~jj}k+ݟ/>۳Xŕƅ/_UH!~l1,yn-/}u^?2\ Ѯ4>}vW,"$j ' Y$[eϮ+3G&Z_"4Q\&Z_"4eϮ+3@eϮ+3G&Z_"4Q\&Z_"4eϮ+3@eϮ+3G&Z_"4Q\&Z_"5%tk%]J?j`W`5\F8c@QEQEW7t[x-fT藬dDX sReϮ+3@eϮ+3G&Z_"4Q\&Z_"4eϮ+3@r<96ﳺZ\nvvLqc-/}u^?2\/7&_6=O",+p;1fڽ95M|?h_K, .6S|m8^kC-/}u^?2\ jޖ-qwjuյ]Ea!mp8 NE x&Gk[^T#̛/MC( &Z_"4eϮ+3@ ^}3NTlDfq!rCyDHuω|5lX['iXxgCzmfRIjeϮ+3G&Z_"4V:c"x~oZPI[&VWt33w䞣X>6kY 9k!r+3G"|U'Rr2Ti >SzeœhpECΓ[$BO"7PNHd;PN-džt?ז>%[O>\g<@tb0gY >iãh:]HY[oHAbA8gU2\-/}u^(-/}u^?2\2\xHaDaHQMhh(~J`i]sPo_J(((++l5W?/WMh(~J`i]sPo_J((((+*FWA\=W6Ҁ: ( w$Ŀ M]s;y_]覠((((((((((((((((sH?d+(( $_ K]syZ襮 ( ( ( ( ( ( ( ( ( ( e ;o [ t@v(+*FWA\=W6Ҁ: ( ( ( e ;o [ t@v(+*FWA\=W6Ҁ$mݮeu%3"sl@p˝zQ=ߛ/G_A@#ڧzz??s?͗#AEsj9{T\6_]=ߛ/GS=s=tP?o~ӯY^3PXat_aL-O#vJ`iG9 V^Cѿm((O#o4+w9Y1%V#G$DV>2ki3>dfXmFw۲^7$PAx±Po_J<=!V?"J`i@Q@s;y_]覮&ZgޟkoipR΄,+;*V+bJ`w^w6 G[M[q%GlrW4(P۷g Ey}jz&}7/FMx;U<O3W?OD]COKK}>TRe>D *+cpp> Ko!PS+].J^(1ܫ,_x2צxOi;9gԮVf;۟5x?Mu < $_ K]syZ襮 e ;o [ t@v+ezv ql@rʒ`IUn<⻊Yqz]>gJoZ&**$A A<7V\[J6 dGjJ/kXb'[*Xӿ+va_YVZkJ%IJ,Eao5-,jB =R=fx2kkdnnClbrm K,jr8 ^/u%wͽ "wxD*X8lgc+Z4hO]ZPoy;VVvYTV5S}C>o4h_A\ma]7Ka((z7mtCѿm((((_A\ma]7Ka((z7mtCѿm(+l5W?/WMk(((gc+Z/? Ѷx{C,EkE=W6Ҁ: ( w$Ŀ M]s;y_]覠(~J`w]sPXۺ(((OLvgzaEsx?M4 4?CAEsx?M4 4?CA\=W6ҏA<B`ƭcx&ө'YH_|`('⊎ ặXTeu# 8 sRP\xW_)ym"h%BG"WR0A% 4?C'T]@ 4?C'T]@ 4?C'T]@ 4?C'T]@ 4?C'T]@ 4?C'T]@^ ~=diEa(H.DJV2[(м +AcMP̯䒥h(OJq[ .5'_Nd '>u He"-rҠ: 4?CAEsx?M4 4?CAEsx?M4 4?CAEsx?M4 4?CAEq~$υt? jZ [":pv98u%//h $ֲn ndr 9e~q@ 4?C'T]@ 4?C'T]@ 4?C'T]@s!+']Q'T]V,|'2;VQdYGA FA# ( (9<RA\ SCt?Mx?M4Q\ SCt?Mx?M4Q\ SCt?Mx?M4Q\ SCt?Ms_[/sۍV=6GeF-F+۝AEsx?M4 4?CAEqx_xI;C?i ?/l>vs6x?M4Q\ SCt?Mx?M4Q\ SCt?Mx?M4Q\^ x/󤗶 ,[gq vdg|7-FPFewepјȉ>T˅GMvW?'T]G SCt?MtW?'T]G SCt?Mt@v?  jH<[[-5C!CklkYV? @!l6mCoIo57SIVD]4O:@m/\>l{e:=ݤ smsi Y"AH*̥XC(Unu.,goĆ//y +l H K&7?S>@ݝ"yQkn̎b@;}#JSK$fw UF20UVy_4SOΌPLx'6\ *HqW;ŀ2x@1m62X&QwL;O˃PKƣTZgIx>͵R&Uq 9ղzyoz|t{j fG2LkY\CiwW[~2F˴aw08@(((((((((+,ඓ`<,,﬒LYnOrwIk*84y|v-v~ 6[.,a}>hYIuB (2X/Tl Vo/bM*Kpj"y©(sOQ@76m'L7K[-Y_OLmm4l2(Y> ټ9>#,4I,>/$2HZD[-}ryc{}Yy+7PJ8ѕՑCʜR7Ƒ:m抖v .I޳ڍV13r U,]^ojCx]QmAk_fcXvp1feM$2sUAW(Dg[YWO+{Wo2)@eRw U$Hv1hsï"#k,"- vSBy4/ܭ׆ĭXt푺2\eH*ܻv0 w4ɖZ!!K{+YDHP1$$xYcϕɌ'#}lucy4b(((((z7mtCѿm((((aI#yBgH!i_b]B(,pO2\-/}u^(-/}u^?2\2\-/}u^(-/}u^?2\2\-/}u^(-/}u^?2\2\-/}u^(-/}u^?2\2\-/}u^(-/}u^?2\2\-/}u^(-/}u^?2\2\-/}u^(-/}u^oxg/Tf ܐ+OY Ydm:1Vn wVV,T$Q>KGWԬuĻ巅;6pau˽!w:ƍQYk[k/ۢnxy)06 ,۰:Ӯ--u%LIdӧP-P z(((((((((((((((((+XmJoXK$nZS+ppK7EG*ME%=`@QmTʚN&Fm$AJs0AW+%:fYZXZ&"B "*#188 B8S&eٺI7..g+#2HP0 %QrqccoYkk dX$YK1$ĒI$MX(((((((((((((((((((((((((((((((((((((((((((Z:e",8 x2O!@H$@b+Zi .v !Wr%`#Vy\3c.iB JPHQv;UUGQT#ml-^y..K"e1R@8P~g 3GaڮyƁtiԇkPnE5hpeCaB88 neEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW,伿 ` #3c(%PYRƹe[_@R{ snb$rجصM8x/wi`$ ]~ Gѿ i)u=<'kUezTmΗn<6@֌Upx0:cr ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( j:Es#7-+HDQ˹¨$KRLY$Y%GoI 8HBE}7M.RԚ9u)#$m QY"S>RϢ E> wʬʊrF#IQbºy:d~rrġqӊآ (1-_I{%}&r UpN>UおQh aL( 7wVy@%JA!*@ UtYђOEMl%+Rv`DܻS$(u,o8d!|J C+)VTA QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQX)ܖRyWl"9u&`su'<b]ey2cRAPZ/ cö}U}ΐ[D!\ Ou"hͰΤH @Sլ3.<_b!-1Gȓ#pCo!rqG5eҼU4׺ܐ]=byrUHSr(~$(|:[xEK0QV4i:.m4E%IPeU,+x{vsOP7>pZ1ܩdQ`(=OgCL>Dĭ,$) @hYzDKi-FHWBFPX97Vf1*E$wzԵY[F[hQ2hB F1^~#/;^mER,?Y0!#R۱\KL"Үt)䵒{}V=V~m$ea`&#.K06gy:U3gq߽-Vto6u9ٞ3W?ϟUDC.<*-mltu>:]QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQENGV4sNdUTs ռG4I#C+ q'mą#B#<*XI^O=3χGϦ[ IR]$&}6Kp@> Heading 6$$@&a$5DA@D Default Paragraph FontViV  Table Normal :V 44 la (k(No List 6U@6 Hyperlink >*B*ph't[FV@F FollowedHyperlink >*B* ph't[e@ HTML Preformatted7 2( Px 4 #\'*.25@9CJOJPJQJ^JaJNg@!N HTML TypewriterCJOJPJQJ^JaJB^@2B Normal (Web)dd[$\$4@B4 Header  !4 @R4 Footer  !:0@b: List Bullet  & F4B@r4 Body Text$a$DC@D Body Text Indent ^.)@. Page Number< )+$ < )+$ z z z z z z z z z z z z z z z z z z z z zT '12^:DJOTUA]aecj mGmx|$c12    # $-=12;Rm  7M~=Mcr*GSkv)*f!mV7 8 Z  S T j k    - . 3 4 stHI2323 !uABCDFYZ0 1 !!!*"+"M#N#<$=$%%&&&&''''))))R+S+++,,,,--6/7/]/^/M0O0n0o0112222222222222222222222222222222222222&3d33345 6,6j666 77$7%72737778Z8[888999$9%9]:^:y;<<<<====|>>>??? @ @AA5C6CEEFFGPIJKLLMaNNIO\OyPQ]R TTTTTTTTUUX$XYYZ[[[[\@]d_`aaa{bAc)ddeeeeeeeeeeeeeeeefffffffffffh>iiicjkkll mmmmmmmmmmmmmmmmmmm!m#m$m%m&m'm(m)m*mtm=npqtuUvxxy|||||||||||||||||||||||||||||||||||||||||||||||||}} } } } }%}3}C}D}f}}}}}}}~G~H~|~~~~~~~~9EFGlr-HIR̀7aijyЁ܁ $8Kbuz‚ԂSTwɃу҃'(8@pĄńƄɄ36:uwŅMچ ANۇ "#.01LMɈ35[\fgswщ׉-HIiˊ+,34G[o?@KM[gsŒƌ،'+.>LMNe|}ۍ .2456HI_|ƎΎώ$DYah{Ï >jrs .EOXmwۑ<jt|̒Β!"%000X002020200000000H00707070707070700000000000000000000000000 0ʀ 000000 0 0 0 0 0 000000000 0 0 0000 0 0  0 0000! 0! 0! 0! 0! 0! 0! 0! 0! 0! 80! 80! 000000080! 000080! 80! 000000000x000 0  0  0  0 0 000H00H0H0H 0H 0H0HH00!0!0!0!0!0!0!0!0!80! 0&0&0&0&0&0&0&80! 0)0)0)80! 0U+0U+0U+0U+0U+0U+0U+0U+0U+0U+0U+0U+0U+H0U+0Q00Q00Q00Q00Q00Q00Q00Q00Q00Q00Q00Q00Q00Q00Q00Q00Q00Q00Q00Q00Q00Q00Q00Q00Q00Q00Q00Q00Q00Q00Q00000000002 02 02 02 02 02 02 02 02 02 0 2 0 2 0 2 0 2 0 2000'7 0'7 057'7 057'7 057'70'7 0'70'70'780'70'70000'90'90'90'90'900<0<00=0=0=0=0=80=0x0x0@x0@x0@x0@x0@x0@0@x0@x0@ 0@x 0@x 0@x 0@ 0@x 0@H 0@x 0@x 0@x 0@x0@0@x0@0@0@P0@P0@P0@0@x0@x0@x0@x0@x0@x0@0@0@x0@x0@x0@x0@x0@x0@0@x0@x0@x0@x0@x0@x0@x0@x0@x0@x0@x0@x0@x0@x0@0@x0@x0@0@x0@x0@x0@x0@0@0@x0@x0@x0@x0@x0@x0@x0@0@x0@x0@x0@0@x0@x0@0@x 0@x 0@ 0@ 0@ 0@0x0x0x0x0x0x000x0x0x0x0x0x00000000x0x0x0x0x0x0x0x00x0x0x0x0x0x0x00x0x0x0x0x0x0x0x0x0x0x0x00x000x0x0000000000x0x00x0x0x00x00x00x0000 000 00|00|00|000`@0y@0000H0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x<0000000000000000000000000000000000000000<0E0000000000000000000000000000000000000<0j0000000000000000000000000000000<000000000000000000000000<000000000000000000000<000000000000000000000000000000000000000000000000000<0000000000000000000000000000000000000000000000000000000000000000x12;Rm  7M~=Mcr*GSkv)*f!mV7 8 Z  S T j k    - . 3 4 %\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>006QqQAeEF^>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00\>00 0Gld (R\`cuc) j2C%/;;_AI]jovxvЅGJnW:wǘn(SUVWXYZ[]^_abdefghijklmnopqrst'TTTT[g[k[lll|x|z|$XtCC !!t8 @t  (  z  C @@ S"`? V   #"  H   #   B    \  # #"  \  # #"  H  #  B    H c $ ?2Taeel!m|$ D$0!T(# !r,D%TD% RD%pT&-T`'5T$&,Ttth_sEc1tth_sEc2tth_sEc3ysh tth_sEc3.1plansyscalls  . O02 @%  . O02 @%Y\^a GJFI[`hnjm9BT"W"\"`"((((,,,,,,,,,,-- -%-9->-R-W-g-n---00x1}111{33336666777778"A(ALAOAZA`AmCpCgEnEEEEEEFFFGGGGHHZI]I+J2JJJJJJKKKKKKKKKKKKKKKLLLM M M MMMMM"MMMMMMMMNNN NNNNNNNNTNWN[N_NaNdNkNnNoNvNxN{NNNNNNNNN8OGOcSjS'T.TTTDWNWYY[[[[[\\ \ \\^^``````b+bbbccff hhjjjj;k@kEkKkkkkknlslxl~lXp]pbphpqqttuuvvawdwlwowwwwwwwRyWyYy_yeymy${+{C{L{a{k{||||| } }}%}2}3}@}D}Q}X}e}f}r}s}}}~}}}}}}}}}}}}}}}}}~-~;~<~F~H~S~^~l~m~{~~~~~~~~~~~ #@DKNTWX\dhx{"3<z|ڀ߀02?EGPU^tw".6BIY`ls~Ȃ΂%)ƃNSfk?KMPQTV_lsy|ׅ݅Z`dkrxX^#&39:CObeqˈՈ؈7@{ɉ͉݉ >EQYem}؋@COR]`aeilmqz}ʌь܌48PWX\^bgpuyōˍ͍Ѝߍnu ,2QVsvԏۏ79FL}=BehΑՑ FLƒϒ֒ؒے%f$BFR"W"'(,,..z2266`EeEFFGGGGPITI^JcJJJKKLLLLMNaNdNNNOOPPcSkS'T/TQTUTTTUURU]U4V:VVW[WWWXX[[[[[[``ddFhQhhhgikiiipp\tattt^ubuuuvvvv||| } }}D}U}}}}}}~H~Y~~~~~~~0KNx{37Հـ?Epr~Ȃ̂ڂނZ\ .3HKxz:>y|҅ՅQSIMX^ #&39ňˈՈ7@^bin{݉37otъ֊-1؋@COR]`iluyʌь܌ 02BFPWgpōˍߍ!%7;eg,2LPnp͏ҏ FLy{8<`bǑ̑ FLϒ֒%:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::~cB CGA ZF(ae_a3 6~& @ct$ hh^h`OJQJo( ^`OJQJo(^`OJQJ^Jo(opp^p`.@ @ ^@ `.^`.^`.^`.^`.PP^P`. ^`OJQJo(^`.pp^p`.@ @ ^@ `.^`.^`.^`.^`.PP^P`. ^`)^`.pp^p`.@ @ ^@ `.^`.^`.^`.^`.PP^P`.^`.^`.pp^p`.@ @ ^@ `.^`.^`.^`.^`.PP^P`.88^8`OJPJQJ^Jo(^`OJQJ^Jo(opp^p`.@ @ ^@ `.^`.^`.^`.^`.PP^P`. ^`)^`.pp^p`.@ @ ^@ `.^`.^`.^`.^`.PP^P`.  6 6B GA GA 0\C @ct@ct  cB cB `$ F(F(Ͼ e_a3e_a3p 00                           l$ 4ePa*ԿVlE+l&Jt                 @@E @)*+,$@ @@0@2@4@l@UnknownGTimes New Roman5Symbol3 ArialeArial Unicode MS0000҉0 Pro W3? Courier New"1ohȩ&!ag4Mj6!4d~|c2QH(?r+eNormalProject 1 -- Yalnix ShellGregory Kesdenjacobo carrasquel(        Oh+'0 ,8 T ` l x'Project 1 -- Yalnix Shell.9 Gregory Kesdend9 9 Normaljacobo carrasqueln39 Microsoft Word 11.2@Ik@ι@jHZ@X]g ՜.+,D՜.+,\ hp  'Carnegie Mellon University4~ Project 1 -- Yalnix Shell Title4 8@ _PID_HLINKS'A^Chttp://www.cs.cmu.edu/~412/projects/proj1/simple_fork_example.htmlmVu/http://www.cs.cmu.edu/~412/ln/dave_ln/pipe.jpgK}2http://www.cs.cmu.edu/~412/ln/dave_ln/session.jpg  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvxyz{|}~     !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`bcdefghjklmnopuRoot Entry F<;wData wK+1Table WordDocument,SummaryInformation(aDocumentSummaryInformation8iCompObjD FMicrosoft Word DocumentNB6W