Subversion Repositories Code-Repo

Compare Revisions

No changes between revisions

Ignore whitespace Rev 140 → Rev 141

/Classwork/CS3214 - Computer Systems/Project 2 - Extensible Shell/.swp
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/Classwork/CS3214 - Computer Systems/Project 2 - Extensible Shell/.swp
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/Classwork/CS3214 - Computer Systems/Project 2 - Extensible Shell/Makefile
0,0 → 1,49
#
# A simple Makefile to build 'esh'
#
LDFLAGS=
LDLIBS=-ll -ldl -lreadline -lcurses
# The use of -Wall, -Werror, and -Wmissing-prototypes is mandatory
# for this assignment
CFLAGS=-Wall -Werror -Wmissing-prototypes -g -fPIC
#YFLAGS=-v
 
LIB_OBJECTS=list.o esh-utils.o esh-sys-utils.o
OBJECTS=esh.o
HEADERS=list.h esh.h esh-sys-utils.h
PLUGINDIR=plugins
PLUGIN_C=$(wildcard $(PLUGINDIR)/*.c)
PLUGIN_SO=$(patsubst %.c,%.so,$(PLUGIN_C))
 
default: esh $(PLUGIN_SO)
 
# rules to build plugins
plugins/deadline.so: plugins/deadline.c
gcc -g -Wall -shared -fPIC -o $@ -IcJSONFiles \
$< libesh.a $(shell curl-config --libs) cJSONFiles/cJSON.c -lm
 
# The rules assume each plugin is in its own file
$(PLUGIN_SO): %.so : %.c
gcc -Wall -shared -fPIC -o $@ $< libesh.a
 
$(LIB_OBJECTS) : $(HEADERS)
 
# build scanner and parser
esh-grammar.o: esh-grammar.y esh-grammar.l
$(LEX) $(LFLAGS) $*.l
$(YACC) $(YFLAGS) $<
$(CC) -Dlint -c -o $@ $(CFLAGS) y.tab.c
rm -f y.tab.c lex.yy.c
 
# build the shell
esh: libesh.a $(OBJECTS) $(HEADERS) esh-grammar.o
$(CC) $(CFLAGS) -o $@ $(LDFLAGS) esh-grammar.o $(OBJECTS) libesh.a $(LDLIBS)
 
# build the supporting library
libesh.a: $(LIB_OBJECTS)
ar cr $@ $(LIB_OBJECTS)
ranlib $@
 
clean:
rm -f $(OBJECTS) $(LIB_OBJECTS) esh esh-grammar.o \
$(PLUGIN_SO) core.* libesh.a tests/*.pyc
/Classwork/CS3214 - Computer Systems/Project 2 - Extensible Shell/README.txt
0,0 → 1,46
Student Information
-------------------
Kevin Lee - klee482 - group244
 
 
How to execute the shell
------------------------
The shell can be started by running ./esh
Basic functionality can be tested by running ./stdriver.py -b
Advanced functionality can be tested by running ./stdriver.py -a
 
 
Important Notes
---------------
A more comprehensive test for exclusive access can be done by
running/suspending vim from inside the shell.
 
 
Description of Base Functionality
---------------------------------
The shell implements the following built in commands: jobs, fg, bg, kill, stop.
The shell also implements \^C and \^Z to stop and suspend foreground
processes. For each specified pipeline (seperated by ;), the first command
is checked to see if it is a built in command. If it is, the built in command is
executed and all following commands in the pipeline are ignored. The command
jobs outputs a list of all background jobs and the state of each job along with
a job ID. The job ID can then be used by commands fg, bg, kill, and stop. \^C
kills the current foreground job (including the esh shell) and \^Z suspends the
current foreground job.
 
 
Description of Extended Functionality
-------------------------------------
The shell also implements I/O redirection, pipes, and exclusive access.
Multilpe commands can be chained together using '|' so that the output of
the first process goes to the input of the second process. I/O redirection
is also implemented so that a file can be used as the imput to the first
command using '<' . The output of the last process can be directed to a file
as well using '>'. Appending the output to the specified file works as well
with '>>'. Exclusive access is also implemented using process groups and
terminal access to allow programs such as vim to work.
 
 
List of Plugins Implemented
---------------------------
N/A
/Classwork/CS3214 - Computer Systems/Project 2 - Extensible Shell/esh-grammar.l
0,0 → 1,22
/*
* Tokens for esh.
*
* Developed by Godmar Back for CS 3214 Fall 2009
* Virginia Tech.
*/
%{
#include <string.h>
 
/* lex.yy.c uses 'ECHO;' which is in termbits.h defined as 0x10
* undefine this to avoid 'useless statement' warning.
*/
#ifdef ECHO
#undef ECHO
#endif /* ECHO */
%}
%%
[ \t]* ;
">>" return GREATER_GREATER;
[|&;<>\n] return *yytext;
[^|&;<>\n\t ]+ { yylval.word = strdup(yytext); return WORD; }
%%
/Classwork/CS3214 - Computer Systems/Project 2 - Extensible Shell/esh-grammar.y
0,0 → 1,247
/*
* esh - the 'pluggable' shell.
*
* Developed by Godmar Back for CS 3214 Fall 2009
* Virginia Tech.
*
* This is based on an assignment I did in 1993 as an undergraduate
* student at Technische Universitaet Berlin.
*
* Known bugs: leaks memory when parse errors occur.
*/
%{
#include <stdio.h>
#include <stdlib.h>
#define YYDEBUG 1
int yydebug;
void yyerror(const char *msg);
int yylex(void);
 
/*
* Error messages, csh-style
*/
#define MISRED "Missing name for redirect."
#define INVNUL "Invalid null command."
#define AMBINP "Ambiguous input redirect."
#define AMBOUT "Ambiguous output redirect."
 
#include "esh.h"
 
#define obstack_chunk_alloc malloc
#define obstack_chunk_free free
 
struct cmd_helper {
struct obstack words; /* an obstack of char * to collect argv */
char *iored_input;
char *iored_output;
bool append_to_output;
};
 
/* Initialize cmd_helper and, optionally, set first argv */
static void
init_cmd(struct cmd_helper *cmd, char *firstcmd,
char *iored_input, char *iored_output, bool append_to_output)
{
obstack_init(&cmd->words);
if (firstcmd)
obstack_ptr_grow(&cmd->words, firstcmd);
 
cmd->iored_output = iored_output;
cmd->iored_input = iored_input;
cmd->append_to_output = append_to_output;
}
 
/* print error message */
static void p_error(char *msg);
 
/* Convert cmd_helper to esh_command.
* Ensures NULL-terminated argv[] array
*/
static struct esh_command *
make_esh_command(struct cmd_helper *cmd)
{
obstack_ptr_grow(&cmd->words, NULL);
 
int sz = obstack_object_size(&cmd->words);
char **argv = malloc(sz);
memcpy(argv, obstack_finish(&cmd->words), sz);
obstack_free(&cmd->words, NULL);
 
if (*argv == NULL) {
free(argv);
return NULL;
}
 
return esh_command_create(argv,
cmd->iored_input,
cmd->iored_output,
cmd->append_to_output);
}
 
/* Called by parser when command line is complete */
static void cmdline_complete(struct esh_command_line *);
 
/* work-around for bug in flex 2.31 and later */
static void yyunput (int c,char *buf_ptr ) __attribute__((unused));
 
%}
 
/* LALR stack types */
%union {
struct cmd_helper command;
struct esh_pipeline * pipe;
struct esh_command_line * cmdline;
char *word;
}
 
/* Nonterminals */
%type <command> input output
%type <command> command
%type <pipe> pipeline
%type <cmdline> cmd_list
 
/* Terminals */
%token <word> WORD
%token GREATER_GREATER
 
%%
cmd_line: cmd_list { cmdline_complete($1); }
 
cmd_list: /* Null Command */ { $$ = esh_command_line_create_empty(); }
| pipeline {
esh_pipeline_finish($1);
$$ = esh_command_line_create($1);
}
| cmd_list ';'
| cmd_list '&' {
$$ = $1;
struct esh_pipeline * last;
last = list_entry(list_back(&$1->pipes),
struct esh_pipeline, elem);
last->bg_job = true;
}
| cmd_list ';' pipeline {
esh_pipeline_finish($3);
$$ = $1;
list_push_back(&$$->pipes, &$3->elem);
}
| cmd_list '&' pipeline {
esh_pipeline_finish($3);
$$ = $1;
 
struct esh_pipeline * last;
last = list_entry(list_back(&$1->pipes),
struct esh_pipeline, elem);
last->bg_job = true;
 
list_push_back(&$$->pipes, &$3->elem);
}
 
pipeline: command {
struct esh_command * pcmd = make_esh_command(&$1);
if (pcmd == NULL) { p_error(INVNUL); YYABORT; }
$$ = esh_pipeline_create(pcmd);
}
| pipeline '|' command {
/* Error: 'ls >x | wc' */
struct esh_command * last;
last = list_entry(list_back(&$1->commands),
struct esh_command, elem);
if (last->iored_output) { p_error(AMBOUT); YYABORT; }
 
/* Error: 'ls | <x wc' */
if ($3.iored_input) { p_error(AMBINP); YYABORT; }
 
struct esh_command * pcmd = make_esh_command(&$3);
if (pcmd == NULL) { p_error(INVNUL); YYABORT; }
 
list_push_back(&$1->commands, &pcmd->elem);
pcmd->pipeline = $1;
$$ = $1;
}
| '|' error { p_error(INVNUL); YYABORT; }
| pipeline '|' error { p_error(INVNUL); YYABORT; }
 
command: WORD {
init_cmd(&$$, $1, NULL, NULL, false);
}
| input
| output
| command WORD {
$$ = $1;
obstack_ptr_grow(&$$.words, $2);
}
| command input {
obstack_free(&$2.words, NULL);
/* Error: ambiguous redirect 'a <b <c' */
if($1.iored_input) { p_error(AMBINP); YYABORT; }
$$ = $1;
$$.iored_input = $2.iored_input;
}
| command output {
obstack_free(&$2.words, NULL);
/* Error: ambiguous redirect 'a >b >c' */
if ($1.iored_output) { p_error(AMBOUT); YYABORT; }
$$ = $1;
$$.iored_output = $2.iored_output;
$$.append_to_output = $2.append_to_output;
}
 
input: '<' WORD {
init_cmd(&$$, NULL, $2, NULL, false);
}
| '<' error { p_error(MISRED); YYABORT; }
 
output: '>' WORD {
init_cmd(&$$, NULL, NULL, $2, false);
}
| GREATER_GREATER WORD {
init_cmd(&$$, NULL, NULL, $2, true);
}
/* Error: missing redirect */
| '>' error { p_error(MISRED); YYABORT; }
| GREATER_GREATER error { p_error(MISRED); YYABORT; }
 
%%
static char * inputline; /* currently processed input line */
#define YY_INPUT(buf,result,max_size) \
{ \
result = *inputline ? (buf[0] = *inputline++, 1) : YY_NULL; \
}
 
#define YY_NO_UNPUT
#define YY_NO_INPUT
#include "lex.yy.c"
 
static void
p_error(char *msg)
{
/* print error */
fprintf(stderr, "%s\n", msg);
}
 
extern int yyparse (void);
 
/* do not use default error handling since errors are handled above. */
void
yyerror(const char *msg) { }
 
static struct esh_command_line * commandline;
static void cmdline_complete(struct esh_command_line *cline)
{
commandline = cline;
}
 
/*
* parse a commandline.
*/
struct esh_command_line *
esh_parse_command_line(char * line)
{
inputline = line;
commandline = NULL;
 
int error = yyparse();
 
return error ? NULL : commandline;
}
/Classwork/CS3214 - Computer Systems/Project 2 - Extensible Shell/esh-handout.pdf
0,0 → 1,1784
%PDF-1.4
5 0 obj
<< /S /GoTo /D (section.1) >>
endobj
8 0 obj
(Introduction)
endobj
9 0 obj
<< /S /GoTo /D (section.2) >>
endobj
12 0 obj
(Base Functionality)
endobj
13 0 obj
<< /S /GoTo /D (section.3) >>
endobj
16 0 obj
(Strategy)
endobj
17 0 obj
<< /S /GoTo /D (subsection.3.1) >>
endobj
20 0 obj
(Signal Handling)
endobj
21 0 obj
<< /S /GoTo /D (subsection.3.2) >>
endobj
24 0 obj
(Process Groups)
endobj
25 0 obj
<< /S /GoTo /D (subsection.3.3) >>
endobj
28 0 obj
(Managing Access To The Terminal)
endobj
29 0 obj
<< /S /GoTo /D (subsection.3.4) >>
endobj
32 0 obj
(Pipes and I/O Redirection)
endobj
33 0 obj
<< /S /GoTo /D (section.4) >>
endobj
36 0 obj
(Use of SVN)
endobj
37 0 obj
<< /S /GoTo /D (subsection.4.1) >>
endobj
40 0 obj
(Code Base)
endobj
41 0 obj
<< /S /GoTo /D (section.5) >>
endobj
44 0 obj
(Testing)
endobj
45 0 obj
<< /S /GoTo /D (section.6) >>
endobj
48 0 obj
(Plug-Ins)
endobj
49 0 obj
<< /S /GoTo /D (section.7) >>
endobj
52 0 obj
(Honor Code)
endobj
53 0 obj
<< /S /GoTo /D (section.8) >>
endobj
56 0 obj
(Grading)
endobj
57 0 obj
<< /S /GoTo /D [58 0 R /Fit ] >>
endobj
60 0 obj <<
/Length 2422
/Filter /FlateDecode
>>
stream
+L soÀ°‚d&
+·}$ ešr´ÂÁ
+GJ¢%xÂëÁ s©ð/D‚ϘžoÌX'ظ1Ò ’Åp[ð°¶hPàádiJ'Og »¾h¸ƒ ¾[á—#Uh—Y臎ì$<ր
+PÉٍèò¤#x9°»±šœ-ËÙÙp[)Pezé
+Ÿºà¹ d"…`é¢åÎÿޏ Ç«ó¿º4¼0YD®ë$[ 4J¡±cI«N¢œ»09L€&G­ˆ³ÇÏ
+¢–¸xŠ.<1 .Ë´@Ó×8Ø>¶Î
+iºìóAÊ|yV†a1ÆÊûžž%p
+]ñ‚ L~sQO¦xþLÉ̀I<á €×ŽÍ֜ªqœÙLÏ£˜¾ì !˜ž9øNr*¼û OÁ9–_‘Á$åüH‚qã~V)»7¸8:± t!ÙÜ+Q•Ññxìzië#Þ
+’hKö&± G¶œÿ/Wê«4T'ÛR²¥Û/~bᢶÚ9‘¼›‰¥ÚÓ,Ÿ›Ø‹{ñóÌ-óÏëuµê—òùri_Qèa–Ì7mÌ»ºŠš3H×éᔃaßYù6—„ðò±†‡ÍSy~ÎÂJ®iÕÎIA÷ðÀJ‰R?Py27aԉñw¾˜ïCÝàyüÓ±?r%o%0ÅÐKú0§2e+ý­Ïß·NÖ; Nÿ*ÿÁú¦Ý«ô¥nu¨`—J‹r…&¼KœHû½ØË¿Á<ó€7àaÙÊPD`^ëÉCªÎ΄ð'p7þ½=^\)õ³S­ñzAJr·×|ªrN ±¯¢4†;s´†¼ßô³›³?AäŒ?ä·endstream
+endobj
+58 0 obj <<
+/Type /Page
+/Contents 60 0 R
+/Resources 59 0 R
+/MediaBox [0 0 612 792]
+/Parent 81 0 R
+>> endobj
+61 0 obj <<
+/D [58 0 R /XYZ 72 744.9066 null]
+>> endobj
+65 0 obj <<
+/D [58 0 R /XYZ 72 720 null]
+>> endobj
+6 0 obj <<
+/D [58 0 R /XYZ 72 627.2661 null]
+>> endobj
+10 0 obj <<
+/D [58 0 R /XYZ 72 478.9303 null]
+>> endobj
+59 0 obj <<
+/Font << /F31 64 0 R /F32 68 0 R /F35 71 0 R /F36 74 0 R /F29 77 0 R /F28 80 0 R >>
+/ProcSet [ /PDF /Text ]
+>> endobj
+84 0 obj <<
+/Length 2509
+/Filter /FlateDecode
+>>
+stream
+4‚Ý'âÊø]=ôÛ°µ—8Zùe2áýÜt“5üY7¶vɅÄ}!Ä°kÓl§fwM"¯7I%¢7ú48ƒ¹“
+Ø×€×Âæ {¶Dجž[ù­‹…/æjew• 0sÅc¡Ý ÷bÓ
+G'E'ڛ+⥔ŠÙÀ
+7I¸ÃÃ%–$à<8ú&°s“R–> };6çt,âJ`¦t\Æ©*éQømhçðqäCLã›Ú$ü!ø>láóÇX·Ó×Þ=áú )ýóª¢5ªZeqU9=ÀªX¸ß_¨Þƒí"ýˆo<>&Ò=(‰Š•þôWÌxY$¯p*â²(ŠyÝKJ@(¯¼¬Õ|ã:/Èb™)/¸Õ°÷ÖÝYÀ*²|ü¤ÅmÕÿƒ‰Nendstream
+endobj
+83 0 obj <<
+/Type /Page
+/Contents 84 0 R
+/Resources 82 0 R
+/MediaBox [0 0 612 792]
+/Parent 81 0 R
+/Annots [ 86 0 R ]
+>> endobj
+86 0 obj <<
+/Type /Annot
+/Border[0 0 1]/H/I/C[1 0 0]
+/Rect [390.8831 668.808 398.8532 682.8811]
+/Subtype /Link
+/A << /S /GoTo /D (section.6) >>
+>> endobj
+85 0 obj <<
+/D [83 0 R /XYZ 72 738.929 null]
+>> endobj
+14 0 obj <<
+/D [83 0 R /XYZ 72 638.9143 null]
+>> endobj
+18 0 obj <<
+/D [83 0 R /XYZ 72 553.8065 null]
+>> endobj
+22 0 obj <<
+/D [83 0 R /XYZ 72 220.3244 null]
+>> endobj
+82 0 obj <<
+/Font << /F31 64 0 R /F32 68 0 R /F36 74 0 R /F35 71 0 R /F29 77 0 R /F28 80 0 R >>
+/ProcSet [ /PDF /Text ]
+>> endobj
+89 0 obj <<
+/Length 2677
+/Filter /FlateDecode
+>>
+stream
+}E]lJ³X*›­•
+Ý£{‹ÁwU¹£‘©mÚv×ôûõ˜w骇À‡æQUûî`–yÝU‡YÑ«}qÚ?ù›òû&QÛà9ÆJ†m·§âÀÊ-i íƒdh\ØóPÑwIÝMßÁÖÔ΀ÄRrt=Ø]ÕÔ[Pó±xâY»¢£®uãx—ºá.¼æqªÁ"lr˜º^3{Û¬—Pë±êvD50ãԊÌÐ2ÚêdŒzή—Ḁ̃΄” d«k«½“dy×…d·«Z¢ø¼Žè»FG¿×Õ7«êŽF×}é]دdeS—mˆøE3ÏòhӐúƒêõd3vbè@
+ð-ÎTô¾€Kž±˜ÑÁIÄ* þ[j’e …ÛK;áªmÝlFè­½Íþ¿qà7Àk¤2¿–yx3ÑÁµ˜9„ͦ›¥ú,<5Ùµy LGGwöžRÓ·Þ£Ï%z$ÇE’Dú»¯ÎöGî[¹ûÖ»3öÖ¿¤5³©Ú9ëo]ûËÇO[má¦^#$ÑÝÍÇÕ
+rg ~ñ° 6ñ´Ùü DidiB#ÎR`SöR£(é‘Æ Ư‡ø¶}‹áÖ¡MûþÀat“ž9Gë,aoÃ9eÑ:TÙ&£uŒþavYðÎ{Wœê9ŠûÆk¨³À¨¶+ºžérWÔ[Gôý÷~ÑéB㱨ºcµþ"S ÿ
+äMáÌÿsóáŽ.ëööý¿p˜â^WaÖçÙ2{@H'¸áq5H5³@}Ø+1ùLüY=Éúu2Æô §«êޟ£–`ß[0ò$lú¶#Êˎ=Åڅm™ø‘ÓÚçNë|²•æüP‡0 ÊLS†KÈÇ1 Ö<Tw—­ëŽÛÓ1Ü*š:y‹#®õ„¿}.+ Ô½›» öZ¥½×ªýñÝçO+ê#ƛ²9»ö‚10é„U]éݼ;ôû£†ž\¦xðI§Â4Ãk€ëv<aªŒ gÏ î¾2J(Hеµß÷ÒFHU\Tœ>+Z‹°‹V"ËrÚåÎ@Hv HM¢:áíâðD&>ºoh@ëÄB qªÌÑ+±CÒ Wqƒ7áמ†>8ÁÕÝêöZÁ}‡4{,ÈÛL$–à3sø1ÍF^ð¾³Q;•—!JŽãëÏäò çò·Õѵ×vóê3¿¹uur„»?NÛôH!>@¾| {†æwA—1!L¤œ°‡Qô+͘a­}j;LàpAÁ[%ћó¢Ø¨ºçðSbáýž.·;cûœ-c鋉½ÌŒÐmÃuЄ‚>å®ò¡<ã̺`ÞW4cˆYôT`„5ùyeüFªª!ªz§ÈBν_¤Ô{¦©v;‚GµaV1«ÆÙ
+¡ì;¢¼Ù‡
+•¿R|?g W´WbO­Ñt9lÈ4LkøVdÊ>"›È‰­`²ÚŒ‚Œ"œ± ŸCÔáÍ$;¾6"ÓÆÂ
+F® ä¿ô¹ŸCŠØŠ öâ+UÈÓTziRH]ÙwxY3û«$™M2æ7»¥’Ââ»M©‚édŽæRžƒÕÂ#+ îËÎÊ¢xì³¢Ó=ü´r`Ti*¬4ÉEyìsT}ÏF–‹,Wù ߌ
+ƒüª
+”‚dzÇH%8G\l§E!$ôçóè.­
+Õ8ÆÐÒwb2Öcޏߏ‚¾o‹ò+ÿâ°½‡æ?ËV<t­{3‘SÇJH¥4ÇΘæh»Ÿ0&£dD éè¢/Àœ"÷€U" …òDƒ×Q ÷™A¬…V2„güí!MƒMv2"7Æ óžsF™y‚2žó„T¨Ä„ wîIî}¨UþrôÛ!cÎÿ»¸yzendstream
+endobj
+88 0 obj <<
+/Type /Page
+/Contents 89 0 R
+/Resources 87 0 R
+/MediaBox [0 0 612 792]
+/Parent 81 0 R
+/Annots [ 91 0 R 92 0 R ]
+>> endobj
+91 0 obj <<
+/Type /Annot
+/Border[0 0 1]/H/I/C[1 0 0]
+/Rect [260.7425 697.6997 267.2182 712.965]
+/Subtype /Link
+/A << /S /GoTo /D (Hfootnote.1) >>
+>> endobj
+92 0 obj <<
+/Type /Annot
+/Border[0 0 1]/H/I/C[1 0 0]
+/Rect [279.2962 569.6392 285.7719 581.6049]
+/Subtype /Link
+/A << /S /GoTo /D (Hfootnote.2) >>
+>> endobj
+90 0 obj <<
+/D [88 0 R /XYZ 72 738.929 null]
+>> endobj
+26 0 obj <<
+/D [88 0 R /XYZ 72 667.558 null]
+>> endobj
+30 0 obj <<
+/D [88 0 R /XYZ 72 361.4372 null]
+>> endobj
+93 0 obj <<
+/D [88 0 R /XYZ 89.9328 118.3421 null]
+>> endobj
+94 0 obj <<
+/D [88 0 R /XYZ 89.9328 94.4219 null]
+>> endobj
+87 0 obj <<
+/Font << /F31 64 0 R /F32 68 0 R /F36 74 0 R /F35 71 0 R /F29 77 0 R /F28 80 0 R >>
+/ProcSet [ /PDF /Text ]
+>> endobj
+97 0 obj <<
+/Length 2650
+/Filter /FlateDecode
+>>
+stream
+pªï០ꁿ¥ÜÊ``²z‰¬Ï¶”‡º©˜ÜL7È'Ξkä'í  ò¶†Q91Ð FT9c
+vlÑÌ<¢™¾Ü֖¿{Ӛ¾h@\¢®½·`’¶Ç¡h˜µ`,\¡-ø3]_pi–n‰4Q‘_¥WöƒøϦoMÃs“-Åy
+0Œÿ‹†Wó
+Æ
+âÀŽ(Ñ·òåIÔ±léÝr6)Æזñd…•¬E÷Y‚ÂNC±SšÂ ͬ„çCÇÀ¡ »2Œ']|¥ë4¼µf:«»9ÓIðä<×äiæ}èãöÃó’Ì5çñæK=ˆjv¬»v³<Ѥ¸íZô43+›±’+M™2xz½o‹†–(2b¾²WÜI
+‡¢ZrîD×qZ‚
+"¼½ð—uۗïÈiå'D‰Ü_«ªÆÐOÆ¥@-|,$¢, ‡ï®1~óbþ²Wðã‡_xߦÞöEáÁ±hGօμⱨ‰0ÇÙ2™gË(Ô¾
+»9 Çæ6óCðuœD«8†LŸ%ߒþC?Βä™
+`"¸žQä2àJ0(ü,
+§s‘ù¶«Ì¦†ÈðÅw¼ÞV*Hý8Oœ>(ŽeÞϦÀ®ÑvÐ4¢ÎP—c&’FMrz!兑ò£0¿Qž5TX6™NŒì#0ä߰g¢ùµbnï»-oº–SǶìë•J}­âÙӋ2?M"¶d(ðTÞ/V̔Ê<ó_–¤s´Ëúú÷}¹~Ä̕zÇ#B£5 ؃cÌßïâÉá%Ò&˜¦ÕnIÁŸs]IáD¤+†l7…RÎ*áî‚a¥’Bô¤Å*êbs”àp>ÔSošî,Ñà86C}z
+¦àb…K,ö0ƒYð®±-¬‘”ò¤¶(u™Ö²Ú")r#·p$B! ©×t%ÄÆ
+®à֊-•mÐÔ¤=¶<(;n¿&kã=µ,(øsëšÔ¸”-è‘%Z¥>(ò~Úqß5ž*|–Wt²r;îy[‘/n–›-åܦ%haó2u0`øQx¤ò3¥@vá¢( °uûÛ‡’¢!2Ò># ú!·öÐèQh§¢ç„6@[Y}ËcIøŽV–ü¡L¢ãøº”Ðta4ÔX-¯¬wü½LGC˜‘£/ÓToMóh¬¿”R\i3¯ ËՔÍñ=ߟi䚂³x(PÅ£¯
+*þt䵎¿ªÍ¨Øiea±˜w¢Ós­¸g­ kœì:íâã Ôg÷«™k”3èóܻⴋ+Ø$ef&ϖ™«Éaê©rô¼rfêEY7õ0%”Þ¤dΤû6vI¤UƒñÙY©§>Gz,‘ú#HC!¥²º1v€Ìgo2=S•†!D‘,CÔ2DÞ Ì?ëcWÕ;øðËÐÞ¼à5€¦—žXºçøI ؊Õ>¢üqt]ðÇ!…ãï}Ò@îm;ªia‚âՂð½¬<ù@£·ã^ê䭏²%"èNætÒ@„œèqѽޘš»ÌëО ük‡F³.&⮘üÉí\¶¼–ÍÃ$Y:ŒlGô¡h÷x;P›k
+åA¿L{”èP9õ*EêŋyÉ=Äwyˆ× ìù ¥ÏEÈ–#
+Ïü,×\W¼™Ú´›×§}þ¾.\цJßoaø—)“].±¡ò¥´”±¯Ñù*öó4¥zLEÚèÇZò3”µº±áñðÁÄWt´B ›µ¯ÕTK¿Bë=µpRêgišN뾦„’Üñš‹<ñlAì«(dÁGsfe²Ê^Î~ߒªÿ&A¹endstream
+endobj
+96 0 obj <<
+/Type /Page
+/Contents 97 0 R
+/Resources 95 0 R
+/MediaBox [0 0 612 792]
+/Parent 81 0 R
+/Annots [ 99 0 R 100 0 R 101 0 R 102 0 R 103 0 R ]
+>> endobj
+99 0 obj <<
+/Type /Annot
+/Border[0 0 1]/H/I/C[0 1 1]
+/Rect [503.1383 560.4643 540.9963 574.5374]
+/Subtype/Link/A<</Type/Action/S/URI/URI(http://www.gnu.org/s/libc/manual/html_node/index.html)>>
+>> endobj
+100 0 obj <<
+/Type /Annot
+/Border[0 0 1]/H/I/C[0 1 1]
+/Rect [71.0037 546.0185 414.4357 560.0915]
+/Subtype/Link/A<</Type/Action/S/URI/URI(http://www.gnu.org/s/libc/manual/html_node/index.html)>>
+>> endobj
+101 0 obj <<
+/Type /Annot
+/Border[0 0 1]/H/I/C[0 1 1]
+/Rect [132.5004 531.5727 221.0474 545.6457]
+/Subtype/Link/A<</Type/Action/S/URI/URI(http://www.gnu.org/s/libc/manual/html_node/Signal-Handling.html#Signal-Handling)>>
+>> endobj
+102 0 obj <<
+/Type /Annot
+/Border[0 0 1]/H/I/C[0 1 1]
+/Rect [245.2725 531.5727 310.7343 545.6457]
+/Subtype/Link/A<</Type/Action/S/URI/URI(http://www.gnu.org/s/libc/manual/html_node/Job-Control.html#Job-Control)>>
+>> endobj
+103 0 obj <<
+/Type /Annot
+/Border[0 0 1]/H/I/C[0 1 1]
+/Rect [267.9195 448.2431 294.7547 462.3162]
+/Subtype/Link/A<</Type/Action/S/URI/URI(http://svnbook.red-bean.com/)>>
+>> endobj
+98 0 obj <<
+/D [96 0 R /XYZ 72 738.929 null]
+>> endobj
+34 0 obj <<
+/D [96 0 R /XYZ 72 512.9448 null]
+>> endobj
+95 0 obj <<
+/Font << /F31 64 0 R /F36 74 0 R /F32 68 0 R /F15 106 0 R /F29 77 0 R /F28 80 0 R /F35 71 0 R >>
+/ProcSet [ /PDF /Text ]
+>> endobj
+109 0 obj <<
+/Length 1792
+/Filter /FlateDecode
+>>
+stream
+R±Xp5Úk´ÁBÅ¢Ø(àÜ»€±/ö¹@¼"Ɛ)ˋ.¦Xùö»/Àßÿ©Ñws;ýÁjtv ÈğtÆ3¾³¾B±.>Þ>/u¢‘ÐW¿¿üÙmÑ3’G³‹jßµ¸°îڇɃÈOxuŒýœä x¤†?˜3ŽJä66ÿâNj•ûŒxNö<9ߣ3îùœ9OÎáç)Á¶+ÅB©0}þV×·+_ÅÒ³×Zů±%ì1oÞYž!%o¶,Åárâ7]•¶E]!½­ñÛäÄe[ß_Z)ª»ú–I–è3L¤=¶‚¼z¿np!A €?œfZ¨>e«HôÙ
+F…ÍG`µ-R(
+ÜT%bïY’nç|a 5Æ¡zà.è€IøÍ<Ñ3üœ#´6pe¢ðK=!ɖ!øk
+ØH¸YÓ`Û×UfÃHÅFʸ0‚é»zmÇ!͵HÙ%G@[Ö`Á‚Ìm«]j³„ÁkTgE•¥»¤D8Ýé^66l0ÚԇŽö&³¹ÔêÎ՗ÒæÕðúÆæ.Á—tT)òzÁœ0‰Åˆx>O
+ç²*lõ$w¹—®—n¨³“¡`\C´>˜Êšá ¥`!<{êҊŒC´IºÒ=Å#R Î*¼Réƒ5*}@£ÊGˆ—mØ;W:q±èE`¬.ëv{\#©!âiyÜMžÅßéùI
+ý õJpDy/öXw8èܑG1E* §¶ÂÊ!µCJ*eE߂aW)4ë
+4
+ë)æQ¢5ÝÆjj“OZ€xځ§évÿ©ýC|q¸¦¶Ôôa ‰™íéðð  _ñû ëÿJoéŸ,ð›5LJvײ<ë€$æ‚Ú$Æí«Sì;ŒŒ—‹£Èý7#´„ôö½ì˕¯½üœiN(Ü ¶ƒŠ˜x ÉSû¯Zž˜‘bEîcNÀ(Œ{]ã!͝:Ò¸Ê÷mNi¼"̣тÔgü ŸŒendstream
+endobj
+108 0 obj <<
+/Type /Page
+/Contents 109 0 R
+/Resources 107 0 R
+/MediaBox [0 0 612 792]
+/Parent 81 0 R
+>> endobj
+110 0 obj <<
+/D [108 0 R /XYZ 72 738.929 null]
+>> endobj
+38 0 obj <<
+/D [108 0 R /XYZ 72 714.0224 null]
+>> endobj
+42 0 obj <<
+/D [108 0 R /XYZ 72 177.4529 null]
+>> endobj
+107 0 obj <<
+/Font << /F31 64 0 R /F32 68 0 R /F36 74 0 R /F35 71 0 R /F29 77 0 R /F28 80 0 R >>
+/ProcSet [ /PDF /Text ]
+>> endobj
+113 0 obj <<
+/Length 2114
+/Filter /FlateDecode
+>>
+stream
+ÿ’µáNúùôû$Dü½VÛVïã^¶-t$›ß~Z½{XEë¾È®A‡éºîVŸW¿ý®›U¸þiqY¤ëgh„AT–bÝ­’¬pvõqõó,ÇAþRÒ·Ó((ÓtÞi(‚0wªú‡¥÷y’Ú¨¡6~‚Ûke¥%vÞnhÛᙆ™½$b7:¢†ÝU׶ҪfÕD>ï%/¥º±ÝDžìdoTÿx5»jŽU_ˍ»òÁKI’VY+îYóy¯ê=‘uÕ±eK•| –® J3dK3€`xÒ
+þ$â°ÖèóûqÚ¶ªþçÞtíý\N¿ÖÓú^ê½UâÞnòžE‹u”"JAž%JDL†`ÑéÑÿÐkž]i'Aš%™òÁ )OYÓ¥`aC¶KÐvƒæ˜Â.3¿SÖj¬Œ¤6›3õv“™l¨rǤ%K­ú†X½”ͼ‹£Ÿ>i#;î:p×8‚}*Š• Ñ~—Qç±WÙÕë½2`@VEsWÓpÛ2PkÅ]#/Òc{â9‹5ТmÂÌv¨š™kwBÐäª×n,…ÂuPñRGÕpô€Z
+·Wñ±ßM}MmeNÄBcà_ö{ VŽ¾IµÆWý­YQy³¹–‘÷w{,D\xÚTc£Ï
+NˆÙSÃî‰;$¢Q lûŽšŸÂ0®ñ`$¡w1zç¤àAkyΩ¯:ð\۞ˆ6ã¥÷ä%·z«¶0ïPº
+üèV¢í|žÔ\aPVæ–uu^m†‘{vœö/B•çŒ3KT/ â¥+¿ì"ˆ¶°:4àTëj ç±?v$ñNæA'ÉUFù- ²€SÁ@óJ–G^·ž¤PÏfºÎÜx•Oԍ³ûµ"¾Κ/Ðä=$V®£¾ŒÎ9 çcóAýµË¿Ä¥1 ‡!UÃHL½^òeT\t³•ŽPUP›êom‘‡M
+þ¿öê R©7îU;èaܟ¨Ç'¶â²—‡ªÅU³rž–Ù÷ûx¢iüõý†ØТ^0÷éf}ÒQݞ —åáçU&&" XIèĺKŽ×<FOõÕËóåå7fÜbQs҃.~Ì@þÐÛ«hŽ7ÝAKbrʦ½´ÝÐ|ËUƒµh…¦À[òž$h®G¸ŽTŠq!*·âú¤¦z$÷>ð<wÿçRk|¨Â N;o͖HKq7t½{Rm‹·ñ"[˜Î Eº4tP¡™ßžx¨ž–+7žT^6£v=T–ñpgYpv
+Ž:ºõmœ~¸UXõÒ>ýå.Jj´‡&–] ëøCñòd뻤ˆÎÕ1M? ÐšKb 1Îísƒ}™°½¦b
+¡¤ó±™1 Ê°ŒÜ[Z Ç1"¨xË%³qï[†Ö÷ýÏ ý¸…æŸkM ›é ¼—@#â(£(f¤ÉhŒ(×iPæp{E,JDÚ§Z;ä° ØCÊÃêöYb@‚±O ±æ'Ä+¨ ¢ëÀ3ϋyÜÊ1Üii@É»IÒ Jòx.ŠF#8¹®ˆŠW‹·o¾hÿZIàendstream
+endobj
+112 0 obj <<
+/Type /Page
+/Contents 113 0 R
+/Resources 111 0 R
+/MediaBox [0 0 612 792]
+/Parent 81 0 R
+>> endobj
+114 0 obj <<
+/D [112 0 R /XYZ 72 738.929 null]
+>> endobj
+46 0 obj <<
+/D [112 0 R /XYZ 72 644.4516 null]
+>> endobj
+111 0 obj <<
+/Font << /F31 64 0 R /F36 74 0 R /F32 68 0 R /F43 117 0 R /F29 77 0 R /F28 80 0 R /F35 71 0 R >>
+/ProcSet [ /PDF /Text ]
+>> endobj
+120 0 obj <<
+/Length 2538
+/Filter /FlateDecode
+>>
+stream
+´íýÔµ{ѧ®Rk§•2òã$J–¶
+¯Dòy©ñŠLCé2ÔF¡Šœlý›–ã*`jìxFþ¦¹.—c]Üx ŠnÈÔ+‹–ûƲTZïÇÆúô4uW Èn3olñ¦Aæ+:X–„]ȳwM­y×ë]³ D‹³ZsÚ
+ÎÝt½C¸®u–Àv€úN«xõ€8šJ‚o‡î™Ú øÕµ¡ÓªŒº)XQ©Ýx Å´b,,#‚jj­4o·_¬™® Óuá¼.ì옐8ŽýÚÕUb¡0d=õψ¿¸°9´mLJƒÆ´ÅwÌÌ^þõц?u´º[ôŽ=$ž{Hùy&Röw²ã,bÿÍb-#Øb‚Dl-O(Ñõlז>ªÜ%Ûº,è$0Ñú*ŒÛs\@Ók¦1ВÅaŽ{ZÊ‚„±ÆnÙñXAMwQ©¤~.eº¼à
+€íäåÖԞ”ŠÑ5†¼éÉúOnšîB$û%óÀë"ÚðTvI œ›È$ñ.Š»i£s]qGAŸIÕ[nA“y¿֗:ú–]ÿ:y׉ӄO¨]&Q0ìNQ²xÑ¥6̐NasÁ¿ý¦XM&¹ßÈö%”¢Ô˜šÞ[è(ÿs4§æ~ŠÄÜô¾lBªïµ+H¶¨,„”µ˜”I?‹^?ã•K‘‰, ‹!v¦{w 0ôJȏ§D C
+Ú%c7ë×WHŽZæª4¯ ô“îØ2âîV£§”
+¤Ý©©ò@ø8[x›R$sMÈP¸’Ü‹K˜B9:ûDµ¦€´¼¢fݺ5<>K„KĔ‰ÅE¬q¡zÍñ͞×Ýõ¹nÔÁ†Ö0¢› ÝÍ1j´‚êE•£!c™Oâ
+;dßÐ×” ¥µÏ0‡¹5o¡•oI²À?G¶~íØZϊbj‰†=ž6×}WÏ2™ŸÍdØÎ\y„+E…¸÷亱Žÿñ¨7\šߴZ2yhÁœNSö{¯Ú¨“¶µ>qאָî .§~ªZ58³?AèƒÃE *Gcúïïï/—‹6¾ªÆûb׍澘¤… Q®ÉÇ(±DæçQ 'œ ‹íû¦V°Ã<¡r̈³ñôZą"£L
+:m‘Ìq¼ Ìãt'.GuMµ8V^ó?Šß9–^sÁe­®»f
+¸l7Èg©]ËY® ‚šßd%m¾¥ʸúq(,N+Þ­‚þ9Ôþ;¡%’aÈZ~b¹sg–ü†”vZ‚[ìƖ» ¬ 7ˆ¯ÄÛ>XÈ܋o9ÑûpÔº>X@Y°ì±ŸN¸Ù:Aß¼ºp`ؑJÂQ»{,½@@Ph¸
+àÒK
+ðE 74‹¿P_ÇË®:Çaw[i˜zØIÃ@ú2³¥¦˜g,Ì/R. rØAeœ9¶æ¯ƒµÅièü"bñð ­wU¿Kc8)Àj½î•fZ½@*¢í[ÝÖÀ& 6Í+—»sUó'?éòÑã·Fï/k˜à^¯P-îuk§ð*ÝÛTDU¾p]íxÚü §ÑýK9³¨m ÞE.Ž6:5jõÅAµz¼†·XÌÞ7 lm_Žú
+¿œD¶Ãû7Ãäðü¢kӕýb‚ìô*ú]"°þ8˜TÌ¢ Lj"7gÇÀiS2I—Û¬ÁŽXy¡ãñ_¿c.ôº ¾Þoαà¡l¸E ‚—2çÜÆvØêlWîÝuñ¨æ’MñìBÏÞ=…UʙOY»Ûr ’¶ëã²yu¯ýt  à|^^ÁѲ–¬|2 °yà¢Kê Á¯ô×bÓåž,ô>}?N› ïÙÚ䯍(3°~´92ðE¸À”Òœ0‡B'OÓĂ>ÂÚ?(ÊAJá©3jÝ«øA%°äó¸„T¹2!ÄXá*¡ï1fÄ^°²SêgišNó¾æŒ’ÜɚOH{ûA”ºôè’ uÚ¹Œ#Èîfÿáð;òÿŒ.ç:endstream
+endobj
+119 0 obj <<
+/Type /Page
+/Contents 120 0 R
+/Resources 118 0 R
+/MediaBox [0 0 612 792]
+/Parent 124 0 R
+/Annots [ 122 0 R ]
+>> endobj
+122 0 obj <<
+/Type /Annot
+/Border[0 0 1]/H/I/C[0 1 1]
+/Rect [83.3581 296.5619 394.292 310.635]
+/Subtype/Link/A<</Type/Action/S/URI/URI(http://www.vt.edu/about/acceptable-use.html)>>
+>> endobj
+121 0 obj <<
+/D [119 0 R /XYZ 72 738.929 null]
+>> endobj
+50 0 obj <<
+/D [119 0 R /XYZ 72 614.0656 null]
+>> endobj
+54 0 obj <<
+/D [119 0 R /XYZ 72 263.4882 null]
+>> endobj
+123 0 obj <<
+/D [119 0 R /XYZ 72 220.2438 null]
+>> endobj
+118 0 obj <<
+/Font << /F31 64 0 R /F36 74 0 R /F32 68 0 R /F35 71 0 R /F29 77 0 R /F28 80 0 R >>
+/ProcSet [ /PDF /Text ]
+>> endobj
+127 0 obj <<
+/Length 1302
+/Filter /FlateDecode
+>>
+stream
+ ]Ó²DÛj%Ñ¥¼üûݑ”_·[°a1É»ãsÏñHêl>z}á3‡Ä"î̗N̝8€.MRg^|rÏg>gÁØã!u/²ª2§Œ=Æ£$voÚ1K\ùE䝝4gš[ÎýÉC'U.*aÆfkQU0Œ?Ïߍ&ós(ü˜^ÝOHèÓÐÉëѷѧÏÔ)FÔy7¢ÄO“й‡%,M¹S‚(:Õh6ú}ëÇGÞ¾§3)w#in#¥œÐ©,Êf5ö»ÇjÌ\A ¡hg˜$„`DµÙÇqÊ]Ù·Æ0'`8øQàGXq-{ôY˜nuùڈÝUhº¯-—fÈÌÁÀÆ°|W¢0S°àóâ$0 XÇàyÕ R¯†fw)«JÞ£n7¢5s¹%ÁÈ͝hºR6Ê(ßchÝÚt´¡PvTï¤i ™÷5Øehù
+Æbà#«Á­îP7k
+(‘aŽ3EI²O2ìž4rë^uFÊ×"ÿjDM
+W×·éßeU/”‘‘UlÍ>A=ªNÔÖŒZ=DBìVå¢ÍÚG3ºì›\³qP¤¹8X\IHà‘ØÄC.6h j‰É.¶5,)ó[Rþ1‚‰e.ömQ}¾³Â„éÞ$ÅF-1Í¿V³¤€¸”­ºµTÖ6SFýJð'DÂl©ÌäÐfGT֛ª¼¥”ç™Ek„tðn÷*žãº`Ï·óe“W}!loàDÕcM ”Ù‘¯%À7~ô”NVÔvr(Ճ‡ü”$)3%>ëu©`?^ؔP‡…àÙ®~PF/‘3Ó@0媱²Ýÿ¸Kxä~˜œ¾½œîaÀд©Õ?O§;SÏV±Årtkbï•.Sû2u½‡ÄÀ!cu¤igޖ kð¨-ȬØí‰%'rR’F<²L²”°8a†Éˆ`"JÝicÖÂ=1웁UÐõžÿª—o|²g®>æûЈ߈û$eÔ×F¿á释H ¶âAä}'ìàÚ
+
+o©ÐATûk½ÙQŽ>×?\zÙÊú ˆ\ÖµÞñØ©ÊFl#òC’Da¨W™ÖÙvÙÀÕ젺þùQÀ§Í£ñR:m´S-f ÙÛQ³‡4]ú,=
+ï­æÀ€¨‹ ¶g™²q^ØÃ5«Êîñ%¤¿„ýØéåÍûÉåäj~:Ÿ^_‚Úr¿WP{©P'Çà}‘ ¼´ÙÊ
+‹AÀS̊ª“+Þ2?¸åŒž?éÿiº/cR?±ôÛà¿aóat¹ó(­Ó×ז›r#†'p¨òÎz=Ís¡ÔX{_ªîÑMÕ¯ÊÆÚL‡ÓO/äJ«1I8O3¼—þh˲b7ƒ­ª[Ææ"«õµvĉ=Ý6¦­¿¬ÇÏÀb·)Œ‚·õ¶ŸºïBº†ü´êßA±gøª•ý扒¹f)IiÊð*ñҐDƒ»-ˆHÌcznnY'ìõŽè°ý•˜ö,ÓÏü¤€@V èþ’+r×Qôø§W:÷ܣ̷wzbtxê„$c}³±>ô—„Vù0WÜÁ…¹øޅ=´ Qh¬ƒdÏÏ gÖúìÂÐeGÖVã8Ùê=÷n¢tø¬Hm4ážBHX¡ÌàA)ꅰ78K^í}šÙϪ¿«9endstream
+endobj
+126 0 obj <<
+/Type /Page
+/Contents 127 0 R
+/Resources 125 0 R
+/MediaBox [0 0 612 792]
+/Parent 124 0 R
+>> endobj
+128 0 obj <<
+/D [126 0 R /XYZ 72 738.929 null]
+>> endobj
+129 0 obj <<
+/D [126 0 R /XYZ 72 714.0224 null]
+>> endobj
+130 0 obj <<
+/D [126 0 R /XYZ 72 601.0215 null]
+>> endobj
+125 0 obj <<
+/Font << /F31 64 0 R /F32 68 0 R /F36 74 0 R /F29 77 0 R /F28 80 0 R /F35 71 0 R >>
+/ProcSet [ /PDF /Text ]
+>> endobj
+133 0 obj <<
+/Length 1906
+/Filter /FlateDecode
+>>
+stream
+÷_áNV;sIê;Oíuî2É4mÒÛ>tr™-qmuõ}¬wû× Éö©—ÍtÇ!Á@Àïî7w|µUðƒHoﶱÞÆLe’nï󟼿|ôµ
+nw:”ÞS–Di©ôíNé(‰½º[•xÍl6ðGv4|ÒÚÿ<غ/ö¥%ÞÇ£-KøÜþ|ÿÝæýýFm%ü”ÛÝODèËp›U›_6?ý,·ùFn¿ÛHá§I¸=ÁD
+I%x Žµƒk
+‚0qÖGTªÕlœBàBq»ó¥òޛìHlÞ¨Ìô¼¸?6c‰ûhíå¶jê~`sqÁÑ Ŭbò‘3‹7vkV’‹T蝚ï¡éˆ÷.̉{ËÌ¢nÇAàÉïÛâÁUÐÒÌÔu3³»M¼±&šì>#°:ð îÊûÃñJöÂq+¶“°‘g꜈Öô=QŒ ššÆ´;8õ+œ&l6œ
+Š›È#ëØ[ZböÓCC£‹&›Ùâ‰?dÄÉ ^JþÃÇɺ ø®äê2(”Ô*¥<1‰h%"ˆc'rä=W)?Ã|8ãEk–Êm_j¦›läX‚YÿhK;ºh
+1p®òK˜å^‰73uÁÀo˜:càÂTL𢅐Žý@^^¾c_¾Zç÷υN¸Trÿ'Þ8!q"Tç}C0œ©ü"&¹×‚á­L=×M]ÀpnªÅÊvÀRÒ]½¯£ë'ÁN½ É}Ž
+MGe-ÖÞÉrTØ!kj¬ÊMáÊO`Zû½y´K«”hï‡Òbc´ReØ/ùÊçbNM'mIü>ëŠv ڕ r²{b´æÀ«œƒ<;ilùðãMë߀%¡”ÞßÝ;e5/=¸dD™‚8•­ö¶#±Ê¼¬ÙÍV‚Rxç[zÙ«-)ì;|-ç~
+y7ø†È œRߐHßé:ºô¿Ú[쫶&aÖÄOð`/µM·‡’]¬á{g‰Ö fR«uJípMÙ7Äɱǰ·$æèŸÐ|dBžÛ®§„uà.í·¦²±Ô;k:;}`:3À§œM}iHk»¡¨±åYi½xL«}×?ƺ¦bnßЀÙvçºhã@šŽŽ[C¤N]1 ¶æ‰Ë(|(&r>Šu6öd(Ô:ì,ûÀ™ƒHQ6jø î©ÈYYý+Ú86õ«zÎ!0B†m‰ã½äúdAÒì×d6Ã5ÏI Ñsãî¾ð#uâv‡¦ŠWâ¡X7å: ¨yÓqº<°l>ö+§pM©«%â£@±y`]Îs1sðÄü •y.ª±¢ ¦/µdÎPptû˜m0+õ¼ðÑZÖYðÞÐýå“v×rò>+ð²U{4½kÁ85…«D›úÁv /=Ýjf{–ÇI¼’$&Ðý³.ž‰³›4¹´Œ%‘ÏnB>½«`ð„Y6ÅLL*°VÜž6Ü[À®ÚÁY=U`±öÄ^EÓ7MÃÙ_Çìñˋ%E*S5­ðS'’ÿ朓¯Üóãù ñÉ§!”‡=Lÿ”õâi6ϞþËÚÄWB*¥¹ÔKIFCó"Ò8Ž¨ÒÒBºÿ1)¾<ûΊ<|{ÁÊØÙz5+HÎøZh%¯ÿV†¡§VvŠEÇñ,÷¹&P¥W¶‚ŸP¨ Xà£m~Ð+*ùêì¯a.O$¨9endstream
+endobj
+132 0 obj <<
+/Type /Page
+/Contents 133 0 R
+/Resources 131 0 R
+/MediaBox [0 0 612 792]
+/Parent 124 0 R
+>> endobj
+134 0 obj <<
+/D [132 0 R /XYZ 72 738.929 null]
+>> endobj
+131 0 obj <<
+/Font << /F31 64 0 R /F36 74 0 R /F43 117 0 R /F35 71 0 R /F29 77 0 R /F28 80 0 R >>
+/ProcSet [ /PDF /Text ]
+>> endobj
+116 0 obj <<
+/Length1 750
+/Length2 576
+/Length3 532
+/Length 1110
+/Filter /FlateDecode
+>>
+stream
+Ž44P0Ô3àRUu.JM,ÉÌÏsI,IµR0´´4Tp,MW04U00·22°25çRUpÎ/¨,ÊLÏ(QÐpÖ)2WpÌM-ÊLNÌSðM,ÉHÍš‘œ˜£œŸœ™ZR©§à˜“£ÒQ¬”ZœZT–š¢Çeh¨’™\¢”šž™Ç¥r‘g^Z¾‚9D8¥´&U–ZT t”‚Бš
+@'¦äçåT*¤¤¦qéûåíJº„ŽB7Ü­4'Ç/1d<8”0äs3s*¡*òs JKR‹|óSR‹òЕ†§B盚’Yš‹.ëY’˜“™ì˜—ž“ª kh¢g`l
+æ"øÀP*ʬPˆ6Ð300*B+Í2×¼äü”̼t#S3…Ä¢¢ÄJ.`
+644S077­EQ˜\ZT”šWN+Àà€ñÓ2A˜šZ‘šÌuóZ~²uKÖômm+ë\_XŪÏùóÄڗ7ÙD쨛™Rl:/P1½dÉ«…¶öϾ(á•l=U¸h‹d¯_OܗEÂk¶v-X1¡Át¿Þ`ñÊæ®i¼ÿ´Õ_y. ›1§õ‘´Õþ¢Ç³:•un~Q®?Á3/å…SÔâ}ßï]ãÒ
+îûd}dN<6Îø-uBÛošHºÁ=c¦MÏvHžÎzºq½aûÿìRKë~,K̞³}Š¬Ë›ªÂå»m¿‡Š÷Öêyo›ù~ÉîÃÜ×v‹
+{fýß_áþZ#MzîáUü.G?=¨=ãûp®Yõ'åǶ‡/¨Tñå}[}âWè:‡)ïÓ»ÚÕÎÖ0Ê3íÿ±:oÝ;K©æBÊû.l½ñcc«yEá2ÿ
+óî-ƌž×¦ÈWµýþdö䓎¡_Õ~Ò+ ”áš”iïsûs‹`ª¨C¸¾îuÞI^>öÉ\mü|¢Ðr¢úÿXöÑñßϾØad­j|ïǝéÖR/ü,2 p0, HÎIM,*ÉÏM,Êæ\r’endstream
+endobj
+117 0 obj <<
+/Type /Font
+/Subtype /Type1
+/Encoding 135 0 R
+/FirstChar 15
+/LastChar 15
+/Widths 136 0 R
+/BaseFont /KWVJOO+CMSY10
+/FontDescriptor 115 0 R
+>> endobj
+115 0 obj <<
+/Ascent 750
+/CapHeight 683
+/Descent -194
+/FontName /KWVJOO+CMSY10
+/ItalicAngle -14.035
+/StemV 85
+/XHeight 431
+/FontBBox [-29 -960 1116 775]
+/Flags 4
+/CharSet (/bullet)
+/FontFile 116 0 R
+>> endobj
+136 0 obj
+[500 ]
+endobj
+135 0 obj <<
+/Type /Encoding
+/Differences [ 0 /.notdef 15/bullet 16/.notdef]
+>> endobj
+105 0 obj <<
+/Length1 740
+/Length2 1048
+/Length3 532
+/Length 1590
+/Filter /FlateDecode
+>>
+stream
+xÚí’kPW†‹èT´ÂTE@M²„ ­
+ÈUƒ©xáRÁ5Ù$+›]ØlBÂ%­#T $Z.ÞÀêPª©\:j•bEDE¼Õ¢EPKc¡ ….XÛ)ýÙþêt÷Ï~ß÷ž÷<ûžã²X¹Ü_DlC‚ œZ1!?È_yˆÉf¸¸’L¡¾¦?ùúBÀ_!žlyûq|üØ\† $Õ$*‘RÀ-Ð}\Äþ2„D…0ø0%Ed´‡Æ@$!DJÍþ֏¯ƒõˆ!•ˆˆÉ€ B…؆HPœÁ
+ÃÅà½j‹‰¯GJ„”ÓPÀ†t4¢ˆÀ15!b+‚ ÷Bh’j²y°Ã"`Ù¸ýxHÃ2Sÿ. d‰
+
+!Ÿ!$>YºyÅÆGD¨B6yFÁ*ôÇ%دZ¨<U!"J ¥@ crd¢à¢Étn¬°€¡K_çÄL£8µAø‡ë¸x¢†þ¬étHTbÙL6¢…ôûúkˤ½‚p!!BqúBp½L’°šAß ºâ‚T ¸QDE³˜8AÑKI:$cü8!OoÀ¢PL„Œ÷ÿ€B•ºœã–{r!àëãx\vú_tBI"85qEè0^×b”ŽATˆÑÙNßÙ½ýSf…&¨üZå4‹É—ù_œkýjú®Ž-°#—×$yÜ­Ž>^<gfÏ´žEÉ#Nò=õiï7?ߑ”¯oíQní)N©qŠ(æ«¿O|{p×ÓYu¦›æ>®Åºw›*
+éNkïé¡ôxضÓ:O6›pî¾Ï¬NîÞ?íƒ{ãIã~‡=šG–‰û÷==uÅÆ£Ò*÷Á¶RNL«çí
+¾„ö‹uœƒS~ŠS22ÿš²=Ø~I-ÜkYïžÇ˜“ÓŠÙ<JåïF‰é‘âðpk+]´c½e”Ä¢;k;Rˆ…jB<n«>j$æ6mÊtárÝ^xdÔ.¡‹žË€§b¶Ý&¦1¹åœiôI¡ÊÑÂâx'ÇÏÜ£|×½ñ]2ÏuVg·ÎÎê¼VÒy™\ïgÌ=?¿@ü]?—ˆ¯´:ôʏ¤‡{¬$–L­ÿú!Ëæ@£­½-1£WsØ)7zË' M~)è¬JÙµa´O+èxw7ÇbŒԫÓ çyk:R½4aìø0þ7øO1&)B“ Œß„üa˜endstream
+endobj
+106 0 obj <<
+/Type /Font
+/Subtype /Type1
+/Encoding 137 0 R
+/FirstChar 126
+/LastChar 126
+/Widths 138 0 R
+/BaseFont /GIBUCH+CMR12
+/FontDescriptor 104 0 R
+>> endobj
+104 0 obj <<
+/Ascent 694
+/CapHeight 683
+/Descent -194
+/FontName /GIBUCH+CMR12
+/ItalicAngle 0
+/StemV 65
+/XHeight 431
+/FontBBox [-34 -251 988 750]
+/Flags 4
+/CharSet (/tilde)
+/FontFile 105 0 R
+>> endobj
+138 0 obj
+[490 ]
+endobj
+137 0 obj <<
+/Type /Encoding
+/Differences [ 0 /.notdef 126/tilde 127/.notdef]
+>> endobj
+79 0 obj <<
+/Length1 770
+/Length2 1341
+/Length3 532
+/Length 1906
+/Filter /FlateDecode
+>>
+stream
+xÚíRy<•ù˜8n“˜bB½²ä,œãX“µd;¶J–Ûq΋Ã9ïËYìNMŒ,7ۑ=c©ä
+ùÀñ#Lå~JƒL"
+u…Ï%rŠR––_´\œ„ýŠF½ú²­ñTÃÊAšz1hí2¡°u)x“úÓ÷1Í+eŸ6¦(™L;ï\âg¤×ìˉ´_bí]×-{ïø^®kíO®¢ÙwãJ22Ō/(ïw¹}†Î~\x~#ÐàiJ̗ü’Œ’÷ѵŸ½^L¿ýáQJ‰¸4£Ö¾ÃG·,6£Oƒ†®Ãûól¼f;¢Ë)6jåi‰6/“÷»65Çýð«¥ð|ÙÝþœ0åÞ9œ(©;+™PUr<ý‹§ã'óËï]6÷tKlÉñj›òêEYñµ~>ç H=TÅß<Í8\¾_õ² áËA=_ˆ·ìVÉRY”y°f/¦¹È™@áڅä²ê2z\r<,•“ø‚Ñ€¬>JššÖÒÐÑÂa~â+1}‘[C~w {Ýørã«Z‡Ê5—È´˜gÑC£†Ù3=XEè ò’­~¬Ä͝Ÿ q–HƝl:>e¸˜ÛJj9’Ðh˜7~-—[.‘nm˜qw®uï¼×óҊKG­
+»64ŽCákÕú)8®Nó¡GExB·ô˜¸Î‚²ž|ÎEÉâ•iU òœí3™¦ÙÎs¯b–Ù2™k3¨½¯Š5Q[öhʲԳ„ªèó^1 »ÔsºÉFƒ=rk³×ßT÷5cIäÕŽÞ°Õ›Èu{w›/„óW0â5
+ œ•RV¡Ç‰Ô
+YQw÷â–#ûœWžŽê˜8~î-¤ÀNO!Tú¬¦YÛ¼U×T…‰7ŸÙ>ªŽ)wm¾žŸT´D¹RxSO?ԛtÚpÏHÿ[õÄß½MÚ*²ã˜Ê?ßÿ
+3ÈÌÔß±endstream
+endobj
+80 0 obj <<
+/Type /Font
+/Subtype /Type1
+/Encoding 139 0 R
+/FirstChar 49
+/LastChar 58
+/Widths 140 0 R
+/BaseFont /MZCPTT+CMR6
+/FontDescriptor 78 0 R
+>> endobj
+78 0 obj <<
+/Ascent 694
+/CapHeight 683
+/Descent -194
+/FontName /MZCPTT+CMR6
+/ItalicAngle 0
+/StemV 83
+/XHeight 431
+/FontBBox [-20 -250 1193 750]
+/Flags 4
+/CharSet (/one/nine/colon)
+/FontFile 79 0 R
+>> endobj
+140 0 obj
+[611 0 0 0 0 0 0 0 611 352 ]
+endobj
+139 0 obj <<
+/Type /Encoding
+/Differences [ 0 /.notdef 49/one 50/.notdef 57/nine/colon 59/.notdef]
+>> endobj
+76 0 obj <<
+/Length1 853
+/Length2 2413
+/Length3 532
+/Length 3019
+/Filter /FlateDecode
+>>
+stream
+xÚíRy<”í¶†‘5…(¯J‘e&{²†Œìb̼4šE3Cöe,m({H‘ø²”,Ùה­’,‘µHjÈNҙt¾óuúþ<ç¯ó;ïóÏsÝ÷õ\÷õ»îWFÚÂZQKrHDª"\ ®è£P&GæƒÈÈè“A4G" © WW?˜zã„2SÕ@*k @ŸäåGÆyœ¥²úr?Hª€.$ã0h"€BSς¦¬IHõStñxÀêÇ
+Ìý¢ƒ…8 Ëïs?‹]µugÐ8¯êzL™¦ÝÞ/`Æ©XKºê“oY4ŸHJÆxóÕÓ̈9>ŽË=uÙ·vl´¾Ýꤊr:_¡…XŽ^ì”;T¹ŒÿÚÇ+0[½ž)dòª¥§ ìe✗´›A¶Î¦k$<íŒ;Õ¯+*GُØ,^3'öWûç^¾#Þ8蕦c«K©¦mßáÅ»¹Uh,䉒 NzÿùC]+ڎ:uô¸?
+|kâÕ$ÉÌä†&}ä”y™yë"IN–öñ5:蛵2ô#Gƒß|nßõw ½ÔǵÅõ髛/ãåûÏ)|뇆$=©\yÓ6„ïk/YëƱ¿+Ž3{ž–㔸c»¿é÷X¶Ï'¦yœ_ʌ•ì”IÖ÷èñÍz›«|_“`™©ÂξßÏö|†$T`ýÅ )±dw³Þêވšé¢èÁ½…‹Í¡ àIÂöE‰Kï²6…ÊñbÝÂãÂ*€ «©ÚNÍÚXº¡ÝrP›–ìÕRù½ÕñÝÜ{jÆý q-¢‡Ç&è´ýC"—ìÛª¢¹; 1|ôOE´)F¯ó±ê0TQúLF*-£ØºçÕÞőcŒ¢Xu–{‹Yòö½)~Eù‹/[ØÚ¢\+ªW4êè!ÇÁ,üËÛ­‘X-Y ÂLlº¥°ÁuäN>ˆ°wQXuUçÝq# hó|ªqÎaŽföá`FŸìž'ƄÔgÉ4쀲Á'Hñ×½+ÍbãwlÒ§·>»ýßFs йÛHªò°ðPmß8 _þæým|ੂЇ
+X)»>*|{×µ©Ü÷êä†ýZáæE®¢(‰2”ýmñ*Píl
+­ –wDµ"0ô¼Ô2;Öt}s¨ÚÍbDf;•Äùìœ è®=}•30¡?B-‘|1oûJŸ1¿´Ôõ“IÛ;ÇÏÚö=²u&Õ魐P˜4<r‹Çv¹ñû9SŒ†ÓñÁ+ÖW+:±Kµ%ö1§|
+y”5¹ªèŽy´×·˜ËUtLÌϏ‡翞¸(y9«â¨i©¶4D²yÎr4O#ÆÈ~¢³‰µ[˜©m®\¸éÖåšÎPÇ9§dhü %
+×;
+Õös „ë3ê_”kÐæá1ˤÐق÷=FnvÜŒ4¾ÍÕã5†p][û0Ǩûêȇ¯‘8¤Å[Lž52h|öœµMÊ-ÞM¢§ÃºZÒ6н~Tÿô‘{†‘|¶4-…ßÜøíªžÐ;Ãâ1?ÁÏÍÉÇûÑC¬–G‘±Ó˹ûöºgÁ6¸5kSn¥E²r§U·¥Þçˏ¹ºdƒ÷‰rè P{¿nÁ¨œ¨zˆ~®£?™ o0j¹)3®­N¦*îáÉ´kE¬¼ œsXœ|/dݾÊ8݉ö“ ãŒíÚí± ­%·ÿ¦ßˆóiÝP¾×
+ á[M,¢ÍMö±‚¤ÍUI~³}p’M
+ž¯#„rfO2½;6eYÏã7¬åüÁÆ}H5À\Ýês‹Ð曣BiÝ"¹†³."ě8Bü®çGõÀ?¬Âċ9Òõ¶“‰¯¾+˜-Õ´]Uø8N¹}ÓîºÌ²RÇVÎpÏïRH Â^×›ª}ßඐÛÑ»¾<w~='ÉîêSÛAs~‹äãU•¿‡‡ûÞ©ï¬5¾–4P11.Þû?Èÿþ'0xM¦’hò9È?n2Ÿendstream
+endobj
+77 0 obj <<
+/Type /Font
+/Subtype /Type1
+/Encoding 141 0 R
+/FirstChar 58
+/LastChar 118
+/Widths 142 0 R
+/BaseFont /JMMKJT+CMMI6
+/FontDescriptor 75 0 R
+>> endobj
+75 0 obj <<
+/Ascent 694
+/CapHeight 683
+/Descent -194
+/FontName /JMMKJT+CMMI6
+/ItalicAngle -14.04
+/StemV 85
+/XHeight 431
+/FontBBox [11 -250 1241 750]
+/Flags 4
+/CharSet (/period/R/e/i/n/o/s/v)
+/FontFile 76 0 R
+>> endobj
+142 0 obj
+[380 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 922 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 589 0 0 0 446 0 0 0 0 770 612 0 0 0 584 0 0 625 ]
+endobj
+141 0 obj <<
+/Type /Encoding
+/Differences [ 0 /.notdef 58/period 59/.notdef 82/R 83/.notdef 101/e 102/.notdef 105/i 106/.notdef 110/n/o 112/.notdef 115/s 116/.notdef 118/v 119/.notdef]
+>> endobj
+143 0 obj <<
+/Type /Encoding
+/Differences [ 0 /.notdef 1/dotaccent/fi/fl/fraction/hungarumlaut/Lslash/lslash/ogonek/ring 10/.notdef 11/breve/minus 13/.notdef 14/Zcaron/zcaron/caron/dotlessi/dotlessj/ff/ffi/ffl/notequal/infinity/lessequal/greaterequal/partialdiff/summation/product/pi/grave/quotesingle/space/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright/parenleft/parenright/asterisk/plus/comma/hyphen/period/slash/zero/one/two/three/four/five/six/seven/eight/nine/colon/semicolon/less/equal/greater/question/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash/bracketright/asciicircum/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/asciitilde 127/.notdef 128/Euro/integral/quotesinglbase/florin/quotedblbase/ellipsis/dagger/daggerdbl/circumflex/perthousand/Scaron/guilsinglleft/OE/Omega/radical/approxequal 144/.notdef 147/quotedblleft/quotedblright/bullet/endash/emdash/tilde/trademark/scaron/guilsinglright/oe/Delta/lozenge/Ydieresis 160/.notdef 161/exclamdown/cent/sterling/currency/yen/brokenbar/section/dieresis/copyright/ordfeminine/guillemotleft/logicalnot/hyphen/registered/macron/degree/plusminus/twosuperior/threesuperior/acute/mu/paragraph/periodcentered/cedilla/onesuperior/ordmasculine/guillemotright/onequarter/onehalf/threequarters/questiondown/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn/germandbls/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla/egrave/eacute/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis/eth/ntilde/ograve/oacute/ocircumflex/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex/udieresis/yacute/thorn/ydieresis]
+>> endobj
+73 0 obj <<
+/Length1 1612
+/Length2 15692
+/Length3 532
+/Length 16549
+/Filter /FlateDecode
+>>
+stream
+G±³÷p´03wP©*©SÓÒÒý§åŸ€‘Çxþît²0³Pü}pZÛÙÛmÿBü¿Þ¨ œÍS k @DAQSJ^@%!¯
+­Š.FÖÆY c ­`jç°þ÷`lgkbñOiN ±„œ†'{ ±Åßm@wc ý?.:€=ÐÑÆÂÉéï3À `æhhëü·Îv [ck“üµ›Úý‹½£Ýß›¿¾¿`ŠvNÎNƎö΀¿YEÅÿÍÓÙÜÐùŸÜNÝ;Ó¿‘&vÆ.ÿ”ô/ß_˜¿^gC ['€3ÐÝùŸ\F@€‰…“½µ¡ÇßÜÁì-þEÃÅÉÂÖì?Ёf†Ž&Ö@'§¿0±ÿéÎÖ ø_ª7´··öø×n»EýOÎN@kS8f–¿9ÿæ6³°…cügP¤lMíÌLÿ¶›¸Øÿ‡Ïèø¯Qý33ÔIšØÙZ{L€¦pŒòvÎS¨þß©Ìðß'òƒÄÿ-ÿ·Èû&îÕè9Äÿ§çù¿B‹»X[ËÚü€_0€¿7Œ@ðÏcmèø 7´±°öøßlø¯êÀ“üÀ‘r6üÛ ![³¿‚010ýÛhá$ná4Q´p66˜ZÿíԿ쪶&@Gk [à_EÿÕL=3Óñ©˜[[ÙþÓzö»€¶&ÿ•ü_‘þEQAMA\]„ö¿Þ©ÿŠRü«½³Š‡ý_bÿ£9;“ÿ¹øCXØÎàEÿ÷Ò³°r8þ&äbföùßdû ó®å -ÜÚKfbþWáÿãûŸ+Ýÿ#fklgòϬ(;ښü¯ÿiøÇmìâèøW՝ø¿ÿÇú_ƒºá6VíŒyƒ-Ó³2œë±òF§Eµû™ÁGCì˚TŠ ýkíúüÒÃ÷¸« ÞëBšgy>;<VÎì?Ž¤iŽÇû1­)ûRWø>¤Ô…(;]œ´ÇŒzeˆçêÑ^×˲»ZLjÇûÓ?”ôJß¡f»Xa®Ÿ¨ýI] ýÑÉí¿ù§5Æat#7ƒ ÖS$ý~z¤ž黅8£͍ƒ%çu…@¤ˆòwÈÅÔR­òŠ †ÊhAÀ»í¼þ$RïõÒË''Ã%‹´‘}U4+Ø´í”}O†ÌèäK’s”l?ªÖÀ¼YœâJšå^ÈûÚr!sÂâkÁŸ ¼›·" šË‚n$ývC5èîUoSKó:ð-oilîGwY£[Ô9ýX„Kõ7‘v{'rO5asà{yN¸m\Êð㲺Wÿ‚Uݹ¬Iž®c}¶"ÃYkØ)Æi G‘aó­èЌìhPˍ–ü”$iÉù.ß«(×A<²„
+møšôÆæ2Õî6Ù%•§äñޒ¤s¼•à12_î$„p²xÒo˜FKٓaÚ_gC'™î?mQÓ«N<OC]†1Ià旊€þWŒ4X•dÖB6Å#Œ]•÷­O¬u±<©Ä1u%oc“ßf³Ãùøã0£õB»^‘àtšlÙé&óŸ—HüG ­Þ´'­^F¿{~5ƒ‹áëÎĹ÷˜Œi‚w úíbAŒ;† ~µXgTäG5߃º
+=2¿óL„ŠinUÐo2ž§RPS³±÷IG¼ }`ØÓݓ§ãåG±øùª'Wü¢Ø#SÍRñÝ4l+ê`÷s3ë¬˖÷r{ú֏Ûß®iB®ï$¾}9¶´â{1³Ä©f˜ù's*«¨ê¬tT ÛÆ\•-9Åي­c—™)a$Wûå$ Ãz-ž_xãtÀÄ9ÓCý#eÏù]Zü­á t=,ËO•v;«5-Ç©vÀ#S~ނšJTWtô3–Š¬¨£žu‡§¼ðÁ™amN)f2ÖB'.ñª¿úÝ)—ved‡¶í‡–ì,1³ªq„¦cïï¨ngÐÞ\À&¼Õ8ᲅ)fÖ¶Idåï
+hêp?_l˜žø¬ZáUžÎd¢ ,—šqä¦
+Yfì ÈæAQ^ÕLû‡SýìkÑïCWPöŸ–ô%çE7ÍÄñåM]†¸¶ëfð9±ƒ43Áéæ„N ¹‚‡Z j¢uÆ>Ûr ð„¡†<tÒþÍ'ї£ð¨ô^ÞE6fýŒÜa&Rd)tæ^‰³»µ >3ñÈúü
+íÑاµ¨÷>ÿ}”gJ¿P^hî•H_ÿdföD¹ø^á žÎŠž—3ß ¿'¤OŠ9pY˜cB0)ï]ɸµL³¢¦g^ùk0œ´ûò!帹çÕÞaš Ö?#;+èoÀiS—êe¨r€Š»qTpÊÙìý?`WmYÛ9qÿ,¥Ã':­»¼Ð÷ŠCbù€XIq¯ú¸ n(]ßoÅVߧŒÊ®Š4wØä<âWj†:¶7i‘oÄxáӕŽ„økÏ­·Íµ$=œ¼Ä.x2Ðæiëaƒ"²ZY̦¾§áç¤I}¦†Mu÷¶U]_Ñ@ì°"¿` }·d$lõ^4b܉$Nì~h’
+—k“êñݓT%ô&Õð¾†× 
+.£æÇá]xP^%ÅqæEJæî?9nÕ©§÷C™ r3Ô7Z8Ù-Òhq^A*-§“=¾wjfù´±ù†¸ ¨K³‚¿¶š‚ä÷ã sxvCÿáÁ{T.ç1çé$=PP‘Ž­It:¼^ªØк~¦
+rxâ [ezkµZúÆš€ÛG+fÆ©i²Nœw~>Tí<|p‘¥ž
+¶<ÃP¢WŸNN”€Ó=ÿbÀgk¬bÒ`ºÀd„^™žÝIÂ
+\¾Žñ&âä®ÚîÈH²JµV4u°•ÊHj4Å-X>Þ×Ù·WÎÄ·©®=)ù8e¾ÕÅ=±¹ràºGo¾)VG)} Ö2pÌtÉHõíÈqz#' Ë_Ðæ†pU•ÀO™«iYJÕ|j2)Q¢#-jïݼ:QŠ$·´_ötí2f½Œ‡¶ßaRN¾Ãú΀{T&òt}º³êùÃéQà#Á…Ç~˜f=O«ÓŠ½ÁM{íÒ [
+ߖ´8Y‚/g˜a (±/Œ8®ÛæEu++3…ø¯µ§35܎§sp&Ü£‰eñ÷äôçêSÌ¿;#ɣʂÆà ­öÕ ÷m{G÷pÔÇCZe«tQ°;¿.ÚñÓJt‰aÝÔ,%‰ª¤ÀðmC5v ¥;Úk¶§.<B²}Ā0~e‚‡7ðS cbX<5å¡ä:7ßvþႚî˜Cõ=ƒ<{eíÚäC±®‰zæÙ£>j±¼%ÚTÿ9×Ûm oµ*¨å0ÅXZ«j„à#ñ™tÐ"„ÈC ¢ÏÛ5c ¤iP·°9°qyþ½!`®Ðt¬\Ñÿ\ ¨éûV"*ôgÿ…h s¸£~o5¡+ü*âM|T„æjª &>"ú³>ÀVôk)û'ð‡e_7kºú—“È"ïsÿi‹ç#òZ<Ó¥ná|Xò©Ì“dèhô0}’²3×4_åUUo,¡“Xé½³•ºh2Š$ší¡•Š­u6¶åU9T •k-~äi²ª9ÄF.“~‘Ûüdø«ãør©ú!gèAÙr<›¯ šÉQE>¿^G‚…픉¤³¥dxä«|Í]Ê^Xàº5,)+W&cº\&W²dxÙÄ{U°#ëÔv$_º1˜£&Þ_kÚjɈWÝÁl4ÁVM ˆ”Dƒ©›l¼’Üќ6óI©ŽµÍ«OvlþüMüâˆfjÿµ=Å3¡ó˜5'þÜïÖGodC ²â.½ŸîF·6VL*´~»f OܲRX ȜðŒ¿\§‡B@“Sð½‰À?¥#Øañ4éµz(
+Ê£® ¿ÀoI„ÎI„ÃëoÑy¿h͜Y»f)DVHŒìªy £–b5 _$¾\n\T|À–—Ê
+ô…†»ÈŶKaç,¯½Ç+Kk¥yvT[£ò̾gÔÓWe): òxÖúüqµ¶ÍÙrø^èÄz6„mçCðÎÔX)!Çlä±6ôDžôÕ©ƒÂÍLÊD¢.ƒ \ŒR¬?§ÂV”Z§"\@Ö'(cƒB¹0´ñêÜãþdØ9;’jF^™qRÄY\•µ*–†XÀ¦|´Žµ†¶=ÂÇȖº¬d»G»Ì¤±9ù ›·Ñá¾ë}÷î:j
+Ýiœ;[1Éèä?ÑuóEʐ $»Eù_s3¯¨Ææ<פÇú8xÒ0Êûà‰C_UlJ
+û˜/铫@ X¬ß" Oó„£Ù„€þ†ÍÁ'KýçÛ»“Ðm]ÅÂÑ
+£nï~o3¾J?†§s‰UÔù(<Ɣ+\À,
+VšCÔÝûØT—¿;TyµRéâÒ(Ä¡?wu9%+ˆà0
+ď—#Ú¨çÐÜb)M[¦úݓµ'-ŽXr$ Òåéædè…™GÐúFbzÊ'>àú’¼yç†u‰/Oک戤W뱏ñß0{iUéò(^,ÅNFïæ)ÅPKU« ñ ›×úa¼;õˆ†Ò,ܟ¶u¯Ã†ÿ ±Q;7YÊ.%÷IЄRÕÆ ÖäâҒgç>r@÷à+º‘—°Ÿ"s;ËB™¡î˦…ÁIo+??ïæ&܀~¸õ™:#ô‘—cùX;¸K
+g߁hëWi4Á9TÒúöUÀÞ »Œ;SãQ³”º¸5ù§ õ2ÌÒª¼rt#tт¦WaKß3æsrÍjöحƼß
+J%QæžC:ÄÖÐd’*Ϗv¤'Ù´Ùl¥ÿ`´á¿©À,üúÕGqj?-d«
+¹NŸ‹{·T±·<ëÊQk|H/'ó;՝«üHESmuJY ¿¯ëÇBР6ÓüfÛ$f­Ï–(f0Ÿæ7^ñ6Ú³˜g¤¡8ƒÝ„%=lòóMçϟøõóðÅq֎hç2¿xóe¶Ø7X.Ƶ4êA(GzòSF†8ò¨2‰lté!_‘d®•—æ»#ðësÞµòwuƃ؍ü•³Åy´Z¦À[® —¾hxmLçDØ12Þ´û?Ù»@èO֡めι—¢Œ*AH+…Þ&ô[ç©æa’
+Þ'‘/
+‰œ¡6?×¥I¹ëÈÅcf±Ý"šÍöST2oB<júÍ÷~Eú[c¶Ÿ~6cYåî¤<÷U½Â°^ÝȞšI-
+dkDng$¡ö¢ o(Bò´§†²ŽÚˆOupÈT‡õÎ4<-¸›
+Nñ6!J]46™—}Õ`8{êx=´ ª-´ÿ^5,âÉú=¼G{!áå¤aIð‘ý ˆW¼.J¼{nZP­NqY³#);.<ÜzÞьòŠ<Z²õªZªÇ_'Ž!B–÷pvã@¹MóÚC¥À¨?MwªÐ¨p5¹Ç +•ü=Ip#ø(¦'Û#{µJ;~?42{%À¬ü^ÅH¹¿%‚}¿Ï0låÆYz˜ÚM\ïÿ¡ùNðv~ÖOÔsØß¹èø-ԕâm)º_%}P„ËgæÙõg8‰QX]‰7 ÐI*ø¢PòBÞ_ë¤ðó±ˆÏà¹31[Óï­æ¦eY¤åþ@´f+xSývG¨™èëu]N<ƒð^±à·Ýõ9‡Y2ۀ˜`æ1aµ×·ð±ö[}*½Ç¶‹&øÓ¾Bs9¾Ç
+ïSJ¼#
+ªÎÎìˆ=´ì€‰efPüÝ4H1&áè>Ö$«t=~ãiõ$£%Å!ŠŽ|SöK¼HØ&¾¸µ§±*ÎìDŸ ”i¨Ê·‹Æ8Ž™Ïmä{¥­ô,ì"RK(#®¦ü¨`k[Ífh²<øt—MQ“*$ÿ¾‚N+ú—$R» Hf!»Áy}s™U%0Ö¦·è† ®§ÍYpä&–ÄՈ¯/.*!§ø˜›©«Êxž£qvç'ÄeÍ´=:p—yê><aòuan%B¶Rz­«þºªÖ}¿'•Õ>ªª `Ÿ+„bñÑtß ‰á´ƒYA¸¨š|vÔŒÑ3*4³Ä¨¡Âùö=‹ẦƒÚ¼Åð{>—±h2ЦØ(í.Ö ÙÎ(Øãaóû–Ò–ßMZ裐Nž©X¥©‘\Ý­2ƒ#÷ǎ´5Ô´HÂÞ§Ó¼† ØÒrŠâ¹=W°…¨Û«öÎmïl¸õøšÅ)Œ›ª6a&”¿Ñ†’ók–è&؟ÅÅ.Ãp˜
+Mdj®;P¿—˜i±i¾®˜O ?äÐ&.náklLÎòøÞ§™µã]‹ñà€L›ÆC+WÃÄ«‡1›ŒÅs¡ÆðHQ&3_¢AÅ3ç-žáÚaQL͗>¹¸hfkϔññuŪ‘V™#&“eî}¢“°xÞÅý’¨ð‰’[†‚d|dEJÝLæ¶_[èXm éæ²ü#Vàw_}s&Í0²ÿVìrž!—íPU_ŸÓo݂ëÜ6‰<œk¥—ã&Yß_Qϐóܓ–c?§ŠRN:!†ak*}Œ!r
+p²[¦®’¿ÆÇã0bÑCv2ŒŽS W3–&û†.Yi‚¥ÀÃ"d—*>ÇʦRÆ0dê=çÒʸúsÁB'I/ÈRߧ­H#Á8!å1Ž+kö»ˆŽ"ƒ¬‡(Å[E:°l
+ïmËq&÷kC¦XOß
+MÁáSey<÷” oóú‹nØTuŸ~" ó<rHáp¨gË-Çꟈ$¿°ÛˆWB¤Ô’õjò¤I-&ý½,НUå|4ûôK¯AE'†dz]=žVáZw˜Žï-_µÿØÛ؎9é½5ª ¼ìÃ×N,ÝzžÎò¤ Œº·V cÿ<
+ÒIcJY+ïKþf{H#ì! ÿV|ôÒNZýGÂZ§‡O³3ÀÔåšIð膈(øg"½e:ÓÅž¾2Îè{+ß5˜lTab
+êDß\ÊU³Ú éÔDµtSPFõR‚cýž/íæS; Ó?,ÛÕ½…=&§ÙŽÁ:~tR£-z3ïU´aóˆÁ­óË+ZÝn&ãPVcP0¬îcáêÞ¸l¤/ áîEZäốîå† º‚†>õé}f¢ ú½ÉoZø[ÁZ̵°­²¼zÁd?ŸDñ䎿Kûl‹•ÒEY¯Î»>¾ž
+u[}Âjâã8\W‘"$F‚ñìd¾–œìðö~6¦,DỽIKáS6s2°‹ÌLÃ\m¢«û ºì4^àe)OËñïÚÃæÇwlL˜/¢a QðùÄ$*š’J-£Á5.Ò=oií::/ò’cÞ1Z-d|Œc@¦„ðkóGÒTÒÛR„‹ì”äDW†Õ‚à)¼ýèèY½Ý8·l.Ü©óyý)Ôi'àë·&g¹z_cVÉp>k¯ä%ü¶œðãE§ˆ½üK—õÏIZáVµ› YX,°Â1ñº™íE;+UšT¡è¡ 7©0ÛÞQˆ‘X|Ž“^%“5;$-òALèMK$\õž¶çïý¡'Ã¥c¨GøΙÃèô¬éˆ›9.\ŸyGo\öÀ9ÿj{£ŽßŸ´ã9f(½¤ªñ2[w²­”¿Ž9¦á‡¶È XZïë-Ò¯pÅU-ªv« ï8¶<Cª± w;6!`£Ln)Ë|WŠÃê7õázF{“¹vßßÔàk¿nKvùûÛ C—Z¿&‚FÛ3ñà2ìY˪ÓO­û6—Þ Õ½È/YSû8ÿ>V[ª$6®Gö°ÙÁ2L‡G³¦.ZÌæV(k F ÂטÍüðøôsªQâéyG5'‘ñ–zy­ˆ…”BçO¼
+"Ù*4% ÊØRÓ£›>vfÊ>ú½ˆÜ-Ôî¾ÖÞ*ÕR»E#R´0Oóҋ̚¡òÌG±û‘G7è]ê$n2V¯‘“±H'¥§­{⡪„đ“mãþ̲IŠÜ<zf¾í?£Òô¾vuGL.î)ÂÆåÔÔN:0¯:¯ðSñ̔>Šþe|Êåª_SùµŸ®›×~íIJõò=i&m8þükÖNŸôkŒk “Ï9·™{w9|°{-G·<©<_ƒ6n'2~û^8–ÆŏÆ £‰Æ~p§*LxWSƒÞYÓL;<•mÞ[î½­4lPI…Ž¢·î²•7öOå`u=‹T”ÐÔc}ÙÜFÚÑ[Z>7{ŒW.¿ïây–u&ƒvIÇU͖9ÀtX¹–>°¤Ãçoؘ9ÏKȇj) ɬ~ -(w·7›;ñSÎßv¬ÑžEïŽJ w ãÞ£»àýûÔ½{¨FÄs€uÙdʜk3a™ï6^JÄ(ßdbŠÏqË;§Gø‘)‹nˏþrۗ’ã+¯ºßÛ7  ¤Àá]N]Kg¿«þÐþûâàßOʇV:þJ,xùómŒË3•Gß{¹<_\ò7²«g½Ì÷2ùõ&;?Œ¢½¾§]ÿÕ$ -¡†¬ÔÔBmþâH˜;/n­Ù_ «\¯çp–f¶fVÝžÂçEeèÙ-ϕ{¼Ø $UÔÅWÿ±78÷œªüÑzrCm2ˆ ÊØ>-md•*”’+ Õùƒã&¼Š#aôn7²fê÷;’£óãÕ>,Ýø«'Ói?Xa5N†ö"¹´U“úÛ{ýˆ½¼æPB{Ÿ¤Fm„Ž{Õ5-¤Ñ¢ÞY,—ý
+f¬tÚ-n÷‰#‰Þ{'œ«%&G¾L҉EŸ\ ¶ß)IßoA°‹z-ªáO¤ĵõ]"
+¡ÀÕ¬{žM$͘§]‰˜ñÇ8’Šõ‘7æq´I¤ÍŠ¾ËÕ©ŸÉIé£ø|鏆iz2р•Å³G.Áaå>5ÐrźØ{pÅ4M!…ß"«DÕ‡|ýë8=õ¦.±|%â:¼!¶¬gïļ:–½zÚ+RÇ6d ºýës¿ŸÈá`à
+:Ý/Ù)Ջ<-bö§œŠlô™|Æ¿tÏT3 lN+cV,´Û|–T4Z9PC#·t¹C‹W\z3dJbF?Y.9lųK,0Œ¹*Í"ì~Š÷kSx—&‹„ûʑús2ÅBøÈ65E_ù °‰¾\†*&™I‘’Xù{uÎÔ ‡g·…`f€½Ã_º¯_ß ~¡Õ^©`>¸'¿È¿Š³»JòŸTè&‰3\]oh͐ó¶B"0ÜùuvA0-Ll!‰1÷㜠ø„ýLà)%PªÂ¹Ä‘™:¤Ç—`êßxx4â²H)0‚Z %d¹æˆ2 Q,aÊ<Ð&l=–õ¹üsiÓ&0/õIJiæÚÏúèíy ®Ö^/ŠÊ<;!g–DÜ뿜¢òŒxðbÝ‚¢ë…\×`-~º)ïØ
+oñ=ó)9»šã•ó˜y·¼ŒäãSBW+(Ü ©Î‰¯jjhbÆvÑq5žûnÚÄJeµ–šÀk1-ÆÃÛÕ×7_ 8;Àh:âƒ{ÎLbiíÕ©}ڌ¹@·¿=k(+Ü`ù Ú±T2MøÞ¤»¬õ õA4Ü+$o¢¦ŠØOd+Z}ÐR2© Ç7óo»´H¦ÜÏfWžoÃA(®Í ø=dd«z8Qªې^9–Lx=Æͺn°VçϕWB¿†ëdBiÀíÝ% .•»Îõ<䉚ˆ*èU’Ñ×Ù’ÑsáfÉñž7/ K+3æm˜¥[¼Ÿ£Cã‘ò¡´`põÊæm«æègȯÐ}Ûd/éS¶b*òÀ^oJAêžä<‘qó&ý®1ËÎ1—.Õ9ÜÉSpÅg±ºåH7gEɏ@¹mºo¸&KË`h„RfMzƑsÆÇ=/¹HñŒ€Èmn ¸2S8á©Ï$1!£è¿_tY–9Ý÷GzèÚ5K@‡¬>¶Sh†B»â)’ŽoûE4¸B9ÁОˇ›>F÷¦ëÈß³”:Ð*µ²z\úŠß2ÞñøÞdˆT%­õÑ
+‡] dpÖ÷q% ¾£¡pdñ2/#¯ô¬íi9
+¶¤©«‚ŒíZOMhÈ*§& Î×H¶(•EÜ¢Áå2=¾Æ֞/Š›Sm
+ •Õֈåšwô0*ÙÕfy@3êªÇp™e†ÕB{𪷈&‹6¶™éX°Å ^”B¢Ïps:9j*ÒyÓ·ÓûÌU÷¤GÅ”œ¾FÂ?ÑQÐ_õÀRÖ ¹8…§š!§ÜÎn4se§Ì¼hÖí­JSWxæ¬
+®|™!: rS;lŸ€sox=QIˆ¼HçæPÐ=¡ËH‡õ¶{PŠKt|W_³AþivÊ"}8ªu:‚AN\jS´&±b¯/úKpv|áúNR$i)9pžÔÜ=JU°˜mfDz¼1ümîÛlSº½(<€4°©¡P폮Û/ò”vØrÈêÀt°Óg
+5ìjg¢wُNVif=_…·ôy^ó
+‚hîdœLª²ñ^â7^ÃB¯ûK
+֞–æåÒ¦Äûá`ýªv\󽩡¾Ê?>ÔfǁænŽ8Šë-â£ÿ|WègwÃ{œÂ˜b%ìDAÕ/'H2­d±Ö?zâúéžP`QìZ,w1$Ðqƒ™$B‹AJsÁ¢ýغÂà×oBE"5¦•rKÙÛüßq^²§5ÂÚ%^˜¶Rˆ‡?í¦Á)ÁéâÒö+IÕ¤RPÂÑ2·jœQ¦Á»#Ä ݱæQbº9KyŸÞœN®´” t TÐ¥¥4¤ð»…nLYq –8W|·„Ùë—6);Š˜±æ^%%܋9p>¸•ŸòÆm/ œíaNè~8±œo$Uúj„kéUVðvI6’š~öo²,ÊÑa«tËnv'y1âB)ôUa@D¨}w—‘ÊN•(ry_迈Î:D À(‚HØPU‹ ^qÕ$…Zïf
+®+&qAÙÜC"ƹVç?l ÁÓ…Õ\öÎ8>Ä,:.ÕFGæ´ú%t¯ËàÊP %ÀC„áûr”J“ÍÌO²ÑÔ~ ž…9ŠÐÒíJmoçpN¸U?ÄíËÛ^@£BUn3Óõžu´óÞÈX««-4eZ{HrUåÀJRbM·º§y¡$Æç‚ùÏþ˜+ü4»V±®U '×ãðëGmëRé\<Âø Ë/’>p,Ûȕ8³‘NþhýþíÛkzǕ…“OÞÉÝÓ<D²M^»]cz’€:H4òÏ͉îŒ`1=_}›…vQL+t³t¸?‘~£€ÒON
+¶GQǑw›šü•ì ­ 4%iž&ªys
+ÿæ*2á>ç¾ÒgŽ4gù:?°
+4tt¶³1t´‚û¿;
+endstream
+endobj
+74 0 obj <<
+/Type /Font
+/Subtype /Type1
+/Encoding 143 0 R
+/FirstChar 34
+/LastChar 152
+/Widths 144 0 R
+/BaseFont /OVOFWC+NimbusMonL-Regu
+/FontDescriptor 72 0 R
+>> endobj
+72 0 obj <<
+/Ascent 625
+/CapHeight 557
+/Descent -147
+/FontName /OVOFWC+NimbusMonL-Regu
+/ItalicAngle 0
+/StemV 41
+/XHeight 426
+/FontBBox [-12 -237 650 811]
+/Flags 4
+/CharSet (/quotedbl/ampersand/quoteright/parenleft/parenright/asterisk/comma/hyphen/period/slash/zero/one/two/three/four/eight/nine/colon/semicolon/less/greater/A/B/C/D/E/F/H/I/L/M/N/O/P/R/S/T/W/Y/Z/backslash/underscore/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/r/s/t/u/v/w/x/y/bar/circumflex/tilde)
+/FontFile 73 0 R
+>> endobj
+144 0 obj
+[600 0 0 0 600 600 600 600 600 0 600 600 600 600 600 600 600 600 600 0 0 0 600 600 600 600 600 0 600 0 0 600 600 600 600 600 600 0 600 600 0 0 600 600 600 600 600 0 600 600 600 0 0 600 0 600 600 0 600 0 0 600 0 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 0 600 600 600 600 600 600 600 600 0 0 600 0 0 0 0 0 0 0 0 0 0 0 600 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 600 ]
+endobj
+70 0 obj <<
+/Length1 1620
+/Length2 12927
+/Length3 532
+/Length 13789
+/Filter /FlateDecode
+>>
+stream
+xÚíteT\ݶ%× …[pwww—‚* °Â5¸»»»;!@p·`!¸‚»{çûnßw{Ü~¿Þ{¿zôãœqöškÍ%sïME¦¢Î(
+*0Ê:m̜ÈTTâŽ` 3j'tó´Á €Ø ÀÆ`åååE¦ˆCí=!–ÎÚ?t ŸþeùË`êñOäO¤ÄÂ@ýçÇlµ·Û9ÿ¡ø/ªƒÁgK0Àbˆ+«èÊ*Ih¥•4Ò`;°ãŸ&T\Lm fˆØÎ L0‡:lþ±˜Aí@¿ZsbúÃ%êœìÁf?a`w3°ý_Ð'€=ØÑâäôçqX8íœÿÌÀ
+€Ø™Ù¸€þ*àÝúwAöŽÐ?¶°?d*P'g'3Gˆ½3àOV ©Ôél tþ+·ä €šÿñAÍ\þjéoìÍÔ±s8ƒÝÿÊe
+€ Nö6@?¹ÿÙ;Bþ.ÃÅ bgñ¯
+g'°92+۟œfÎr[@쐙ÿÚ*²væP+Ë?ì ûb®`Ç¿Dûמ¡ûSµ³ñ€ÀæÈÌJPç?)´ÿ5•™þçDþøDàÿyÿ{âþ»FÿÇ!þïžç§–r±±QڂÿüóŽ(þºd fÿ—;ÐbãñŸü»§6øUª-\l€Žÿÿƒ^ÔÎâ"Œ¼Lœÿ°Bœ¤ î`
+MÿÈÐà@×9BÏ/B†œX$*~WxêH?‡Ba=Í
+èoo¾PBe땔ÞA§Qa “ón¼smq»ÇÓ0¬Á &ð_gUw¸x³wËZ6œßЪ)Oú;é·;¶ºÞk>
+/eÖV7RK‡Ó¡u?—bz§/£l˜P¯öQDZhW꼉Ÿ_‘šŒ´ ó€{gWÉß+ʕqðݽ bòÇ|4?Í_i÷6_¨)¢¼¬êqIbïÒ;R3‚´_4>ý`—ö ôÐއ¯úL¿hÚ%vƒå1K{^E)p› kí$aJûâ"x¶‡q¦æºþméœñDѯ´²·Â«¿.—®ÿ`γ6µ³—7uÉBŽU~‚½Z4…±Øâz¶Bq?'aqŽ¾ÿ‹\„ OííóXŒbq+ö†„ºbq™VSÙÛǨç!ï<~ù9²÷‘bYL°Ç«1νúÛt֋78O¬kcÜÖX —`TY¦Q‹Ÿ¼×À*mx稷Tõky?1ò,”0ú> ¦ÈÃÏì×ÚWûŠ\l&)¹6SÚ$]ø7'ϘëËeä¼%C°Ô¡
+MøM¡…2v2Õ&ü£ lƒ„!ÞIÓk*w~øý]lAéù³ß½è<ÆóÌk
+ì=úæÍ!Ë žÉI~u·÷ç2È+çkY§l‘…ÈIÈ-™ÝåN‡Êr8Íó`D s­ÞªøD/.Ûòd,ÏÕ¹¦<ëIO}8êY×Ô¿Š›ðæøñôeà^-*DŸ­àÒp¬¶ْ6E\²F*¤+òYö‚\"Hb"ø¢¯‚Er¶tο˷¸„êă
+1í^ñâAp‘˜Á ÒíwQˆý³ˆ|)§&¶lK¶Ó܇¾úO0[÷q•;@÷®(‰¬ÉDù‘Ûد¨åXÌ^Žó ,*ãù‰aܽt½Â÷|¿Ö?ïÉ/ÖTÁ“Ÿ•—°Ñ^%éd1pñ×_{#ˆOÇe ¾ÿț@2–-ØU&ß/e©Œ–OrWÓ>¼u>¼Rw—jzԌ̎ I° ƒå\¥sJqmĺè|dz0ìœdMZˆK[ßs‹$—/zÑgÏѼq©œ<òF4EŽR¿ÀæÍ«i º_֓Ÿ‡óýñ,,‚)_¬“½G•ùJ1bñ1z}ï.¨¤eÕxg"£Ãµ<„'ÇSJpޅė<ŸmMÊó1¶»TrK¸Þ$(Û»Ê/e(Aê§H!.FЊ¬àjýiÿr,›˜íækn‚üñ:ÍÅå3w¿ªn*·Ù§hÝuƟa„;µüx\/¼in滸Í095èn
+Øækù:i¹{¬ºI»öÊT`֝áO5£ÁÕκˆ ܸæ4í¯Õ {ÄHäiOK˜œxéä3•
+¢¶ñÈõOf‚ç†ÐZ}©)õ&ýÐæ’®]&Ãk®h°‡í^P³K”4Ÿ¿Ø~“I Ž­ÏPái¥•*Äø¹/ÁÓÓ郜n¼y!4]ó1h>æ‚7'„žº¦= µÖ^pÑ';‹§I3©ÚòDò¨UT­ „Ž!nîŜ³Çå±x4êYÁØf;ZR‘¬Ú¥vù…]´çó7½T´_ÒÍw8µ_Ic+Pîˆ7öУûE€º·d½ìœá·hÎ)&ènDͽàf·¤&¾ÏßÕò°Äé§á7wŠ8ŽßD0³Œ´ú}٘²Æ¤éDš‰Àù)ÈtkÙáfw‚·`jw¿«2äâÉ÷­^ÛWE?Õùk…R-C:
+7­“¸þ{ۘ®§¶€ÓXé'¾Ë뛲ߡ+§gÔ´ovߏ}2kOÕå¸5—×D—ø¦û˲oåÆOò1å^}´È/@éÓ®fÃl™xÊäGuZG ÁµÓÿÞ'ôúÌKG¹ã3¦GA‡®Ú«ƒ`‚b{e·®cê˜MˆŠÓ‰ð6.JØBiz':̜a ýv/ßép· ŠicÆN¼ÊñÝÑS;Œv&®3-v©f2j
+\äUjÌ*´u`[½-ÐUB«ZÙòˆ[leþ4¾2²vÕ:HÉwSô8xö@Ÿˆž«FI
+c7:yKOí‹Á‘  ~4÷’ËmؘT[F¾?@x|yÌ2ÉÍUJzœ³ûL¢U¡ÚK÷ g¯7ò‰ò}M/òlÅw¬¸ëS·¤Þ£Ì+çÒE²¶RçÜÛàsÔ’YÜ~ð3«ÜÐò«90¿Î™˜+šÑüº‚¼€°"í¤¯ã¤Ãê½^)q§¬'£Lõ–®·‹Îã
+ŠøÎG{ëÒK±ê2¢v©Õ²ã°è%ðqúÉA?K‚dœÛ±Ì¼ñäöµí
+Í|7ÐÞ³œ«°Nè@ZßQiïƒ&±€u STmuNG˅^X™Èao6¶n´¾fÏü®74˜9ë¢*"%°ƒ
+®šü~¤kÒßF¤`N¸“ŸÒ¹Üªö
+r4 ¾àC[&؂ٺlu}¼S·Í¹ìBãp"#Ø!»*Óà`(˜¶(îúö&í +A:.à
+P¯³¡ß-÷qv î2TûõÕô
+ü1ÀhÁhgí­šDß°wr³íÏÌØóŒŽ
+ÇÏ;“>‚ß‘X<F)
+ö ü{–3~”Õ±ö菋¶œþŠ
+Qv$:ö:‹±4)VMž}é
+1և0²wÜ:ÐúbÄ;æqÒ»°òú_(¬CÂúJTœ<Sô$µ_X–3¬x—Á;–«|«H(ôó -oŽ=“vî`¡å»ÖFÓ¢2òxß@æï,‹‘0›¢ÈŹcͩǍ‰¹8ϒç
+'ÄMAW>]´V£]ðc[©4](+šxØÎäé?œ¨â¾ìZŒ'– ^V³çͪ}¯$¡Mj%]ÃpãqÖöÁ3’ˆ^Êp{šÐ3rÓsàW‘Jen7¿Åªc¨e]äW]cú8"Ô#Õq³ÀÇÚÔv~âkòlc#KjŽÀD—w2“яöt™& Ì¥LÎ%68Àá—È+¾ÀHÆj€Š¹2¶Íx.1?­ü\”=•‹fŽÄÿÎG€Sáò
+/BÞUV›ë ›Êªpnt‡Nš/–ŸÜì(»ÄËg¦²m4¾ºß€ÃªÍ­Z͆n{fR—zŽÓ`ՎäŽ|¿ó:m¯† ¾²ßæ!ðØ×Ý0/U8W¶ uÆxzé¯A5‰G´µwîÐpÁ_\¦È’0ÏvðaÞ`Lj
+}&~=/qïðZޔ/Y|ÄÔ³¸fÛ+Ïøy–_nz¯Rƒ(Gΐ}üÄùdüho%·4½x^¤–¡Ô¯±:¡i¯ƒS¼)Ùµ}Kr‰q0•Ì’Õ¬µŽÜ++”VCXO—Ë-¡ÆW$o|EVLšOŠãÕûçû©Ï" 2tŒº‰õ}Ãj
+ \FÜ,~åMà1Ó’›@¦¸\ê‘ ž?½§×Z¢ã{÷œ—ÍãYvðœë†D[Ýèٖ–ÿ`áðB bãïí‚f¾÷|ØFÊUL|øöyð¾Kk>âŸäÅ¡;Êî[)5‹Þ=ãúaêTd_.Pd‰‰:«\ÿÃÀíØöõϯ÷¿0Óõ•šbvRÌ{¤÷ò`ód˜ñÉ?öFªÑ·Ýáy*U¥ßƒˆ1eô\­A9°_n<ÂA›M‰ögQyš®©c7oöØå<t“fQÕ½2ͨóŒ±Áñ ¦
+v'#ÛÅxžaÓ e*È܆™Fšô¤œo‚³±ë?cnG ¢‹“‹‚­OqœV9.[~ä굸\ Žºú:lô2ُ£ïo>嚊—<y¥Üªé7QÇȶ%•—ž„ +(82iUcE`%ؚpæÈY¿Ýc.7iN™Ó~µA^¼z'ž£t€±zï;,g¥U²Þ‘"ݪšc*{Kes˜{QÇû†ªøÔÿá’ÎD¤‘Kñ4plì¢ãÐja©ÃuELàm¿à~ä¨Éa1Æ8ûÞ:YMt]­ÏÖºÐBZ<¨1 ¶§àÈ çñÀÎæÓÊ/M%„¦¢1l¹óg?wä¬Ìýoš,ΧÍɈ­à·äªwb…?‹lXŸÐšîû•™}Ì®)è¿ÅLÖuÜ\n®&mç“6La{]5K7 ò…V­Ë¤ù$ºËÁÍ'Ðí!t¼ê×}ò'%YXlbI¶íZÖ~1u™zw¹¦r0öJgóþø©—!ëÍPÓ
+˜p8ªáÄ/µ=å;A"Ó¨*•ß"`7WºFµÕ±”ð“æ +é#7/ÅÏNÒU:f¿}§-§Ì™Zچ´Hô èMA¼ä?|6©E‰–qK'2`ƒ6Gß}ö{±Q%ÒØ»¸/ý¹®sÅRXè‰<‚¢R)ÅA]Y&ñ¦òŠúÜÚºS³Ì>¢Ò1`͆Šsª”Žn<ՕÌy–(N»dÝpIû@+¨vWoLê€ÑEÛ¹âPÒ@ќҒ"/—yL­wƒf˜œcW¨Øt`§t8𒶧á°ь@FyÈs'‹Ò.±â[Ì"º qyÁáLŸö½òÖäHq$ÒÒ
+ÛI-¼¤öa-Ê`Ɵ'=š ×ø½«=¤…-PÙö_8¥e€ÞPH$Ì_-o÷·Þ¯¤cØ`Rž¨¢£ø˜æNgˆöôgÖ¯»Ü­âé¢Æ¬—õº}»ßùaœlfכm™-§…­Í!Äuáô­Ö¶Tô„c
+¨‹nëe,Þv¨½z{ßü²Än
+Elü܈˜î‘s‡€JóvÒÊþ¹Nô©ÃîC ™*…É×·Ü]èb8ú›h(Ý=A…ƒùZÂew7yè"™«Ÿ­©F|é­ö}¾^2ä;Šá:X’YÍâ¿yÓ¥òYÁ°u›W­„ŠÍ»´{•U.Á«®´k°<ԙùBƒ®_él´fœŸ'_x‰¨“Ö‚|¶&
+’G†º´F7;“8ÛÈ¥¿”Bk‚aÇXù¾Ï’TÏ<
+6ì>™4J.$Å<úº²Î1ʛ±êã/ó¹_æš]‹Xó<A+à󴢕•Æi*‘™ƒ:¢Ó÷ºY¡jkgÛä ¾×¹sÊ5L†î¾û*r#ïo|:Ao¸Úâ~ª/Ø\¬Y O¹“ž†wí²å2ˆÁǏž{(àrUøIq)fÅDøÀÓ:lû,·µw¼¾=‹û3â…e°Y§Ìk­eä>«+Ì̳µô»ò›¨Y„蜏úÅq‡ú–(e½'òr?o 6Ý·<7óú²l¡«e¿@WÄÕ¯wÞÿ”Gã]ð]TfÜ?Yúsó’5ä³ø»Gì1°‰ô‹v³0iځÁ0áW± CäJڙ̒O ÌC#O# ½záÞ0
+Æ¥E˜Õ 2t½]Ÿ(¯@‹žæý‹¹pÆÍ©²\÷„˜ùQ#\Z«Ãp˜%-Ÿå«ˆ¾•vü06{¡ùÈÿýÔ2$VõÇ°èܬ9mgµëb¥)Ø}xh)£6Ï™cG˜¶[®¦€¼œñ;fÔPMk[þÊøAÀIhBŸ˜¥[c¢H"öôúÉ4YHÓÖi&úŽÆNÉFµJ`ŒßF8*Ò儼:íÛÞ>8ÏgõzÕc›ùÂþm
+£ªYÀ §è)^ ÞüÄÚþ"òDðŒ°(<ã'lÐWáé<¸Ü=™8¸;YՕú¢ïÍxý@ ¢>È:¶ŸD˂]›Ð{«On:“cÜ ™”@‚wNMcB'
+õÍ <>£¯¢IÌ÷©Dñ3®…¤¾¨½sð§"XðäQ&å鯓‹g·û1ÈeûñÏqva˜©è%âVŽÕê§8:—à6sNž~ÓN ¼52֚ºÓsç“ݱ6*?ÛEìJaÛk_0d~›VySdº³'/4*U¢eŽ¢¯£_€mWq)«ì_¬í5Û )¥˜dÇ7)¼Zs¬èø‘Á ‹f&©ý%xn6lã;€J°_3üüVJ獢fé‘è·ü ÞGõɛbnü_Ý¿ Š÷ÉBȨ#«=B:è‰<ò?
+;sPŠù klaXr‘:À0:ÉìƒÃ9Á»rWm9g1NÎô8úîØßõ’ž‰Q ³˜gR½f`Û·ìgòöSîqÏç.%Ž=ÆH¾`Ýéà^;4rƒï‰°,ìaNÅìÃI}«ZôÈdp%rŸüW¹Ü®Ž±Éɾ‡ºþ//=B®±KDUá,‰—灅±¸ð5ƒÞÕæzöX“T@fÏ˅q!u$×1ì’Þ‘Ñ`Fsq±ËõüÕíŸ:–?¯‹žÖò~¾½sÇ`ÛÞ»ûFlióûUA_Qã³1òŽ‰ž‘6{5DƒÝô¼Õgç[³˜rh\î:®´É*=ޑŒžHJ¤bä½7AW9úÆËöÝ}zRm.1à0-Z¼EOÖøtƒ"I’Ùd:tL"7²KŽáÖãoÈU`¯.þç{ &®ZXùؘû?£A(æ5œ’ «‰5Cæ5ë\¢†±6Ž?¹S­ÆvÏì3BpL5¤p›o‰gP™<¿.÷ª`W¤ý˜â
+R\YU£èô‚ÃëÜ{ø„nÓè­Â­›å¯‘óI^ñ˳>2 atŸ)\da¾~]~á¾RˆVl¥wa<ƒ|ÄocM®t³^ã¢÷B%¨ $c=oÄ[NãÂÜîJ- †H±>2F+—ŽÉúúÕê7ÀùÖ¥{q9:τŸ‚-•F’å–ÂEQ½¸v·#ba2
+M¿ÀÎîç^ ó× ~ˆ6d’…õùl…7ۙ¯ïôÏÛ¶ÎöøfQªôz;ö>¼#—Œv¤!¤ÃøЄëù»…ÁÖuú\p<Ê3%ºO®Î°_qÒéªg"qí½ör7/ýXi,>Ã>öéØꙪÈÞwÒ¯×aìƒØ{قÖo׺£–|Bîý6‡2Ê
+øò}FgøÛ~‰oãG]b­”^²¢HUHü²ÝjtPXkKƒÙ‡ùðU\TÞUn£·—ßw_{Fô/cfC—¤‰2`àµÙGwgý±mÞ M&Æcc¨³Æ× `‰„
+õLõ4ÐY
+=Ĝá1KeÌån~
+ÄBøZÀ-2L©ùðÓ~´‘Ñãµ>ÜÖµ0¬Ø¹™Š/›Åє…çû\Ãü¢z‚o¯žï—]DŸöÃúøØÕ{Ÿ…Ö^uùIò$î5§âÆHV“'ÒÆ|*oT糈àä,x©•{¯ß |æø< 6¦>o[³œfEÎgéš™U‡iºmoajpðéDKxëó ›ì „ŸJ™…Èf˜<"¤
+z}°{,*äªx?+E§1t
+Ú(G6^·ÊT‚é)õ29¯ýª›%æ§ÓnÖ-P6:ž¥Ã½~HR"5ù'Ø2H>Ãw ‹ŽÏÞ³ :«Æ‹à`ú• ÚÈ1 V–¨°
+æTGü2eä"u¦›‹ä6iò0ârüî,çיnÌÑI"ou‚$˜N¤Ôm!Æ/$GR®©='ëµ%‚¶@م 4¹ï'’ á\nMWˆ4<H|•²2—ù%¡9‚@[)Ĭpº§à‘# 5Èû<h›, á•tù•*ꌽøëø¶ÞiÆ= À!þ‚àé°ÄèNb2Žf3‰ÉJnP ýSPÙR¯*
+gµ„á¨WÈ>_‰˜<xxhÀ[uÛk1i'h¾g‹Fv ÐÕ¨nÅf³„q5Fd¨llÚ´lõ%\?Lí*ê_4ðéæ«ÄÍ::9³ôӎÎVÌÛ@ø¦Ÿ®­dg³Z
+-œo­-/Ìlm@Š\åÝ+7
+bn†
+CtYi¨äõTS<Þ3§ø¾ª]$ßZOwrj†D¯“„ÔŸ|•"åu_h|íIó€Ù¹±Kàd|jܚˆò×ä#ÅwڜpDw= »hž¿ë9i
+®
+K*-WÚ¬—߇R}Bk±2îD–±§·œü9Ǖµöƒ›MIxÿÕL·‡@!|¤RŽÜŽÖ°¦æë›v§¸¼¼ª ɔÊk¬FÔÚk8ý0ïfF}cÆ¿>²EUœóót
+/À/ôÇÀs²ÙÃöƒ”ˆÇ]–‹á¬í9.õÑ7°…3.ù§w~·n0!í*±0•da};^åN@'tpÂ%H#dc¸E…º¼m]: ‡
+£c´¶N¹Â¬ï¾Vp´$†8U”¯-]OŒaŽko$án6¼Ï(c±ÍRUñ˜ ö”4òOe¦­M‘Gy\¨‚вw9¤M_t-ê#ÑÊy\°!/¶5Š^ƒ^Ãçª[´³õÞ¥ÞIÂÛçvH
+7tV*ÖT…êÔñy+œª
+IÒßÁ>@£Éë8öÀϦò–'ñ%Ä
+ ø).9čïØ°1Æ'kçáÅ
+·¨þ7û˜œçèÕÉ¥«ÍWMt/:°p[¥šõK¡Ô¼+…7êtjÔ=n#¢‚Ö®–(^éˆ4ŒDH¹Òl¶˜†‡!õ HrSVYëv@I°îOã0̨ràrí@è܁ÖÄn—BceBŒqZ7¸tÉÁ“_÷ôîÌåãó]ÁX_Ñ®·Y!ÒV„ô=9@èĉºŒ©Zʐÿê.ß&ü%sÊ ¾ Ǘ˜®ˆ‚q™S;ÉÈ%€lQlƒÈ:úb aB¬XŠb[µ¸ËFÛ4)-d:¤•§ôn#šUít©¦9–¥ÕÔÍdxñÂufJéI¢F'šæ|f`m)¬4ð1֕v‚ò=ãdïLŒÑ¬‡‰%ýnAžj%ÐèW¨Õa—où¬Ùn¨L™ ž‰‘òìáð÷ðôŠKêægŠ`Š*ä"ßöNK¯:-ÜRB|r´cƒrÐáäKñžOÚmnfk‹ÃÐxhӆ3ǖýšfrD°¨oáN"ºçÆd…Ü©”˜?>Í
+vìþte‘ɍq·Pó/BœÛÙ­šv¦göÂë-±tŒ¼fKãoíÙ±ë‹}š»ŸÞnÞ·"ñ}¤?˜+—À¯Ôɂ ab¾dµA›?âp£Yþ›òÿ'ø‚ÀÌ tt†Ú­‘ÿˆÛ°0endstream
+endobj
+71 0 obj <<
+/Type /Font
+/Subtype /Type1
+/Encoding 143 0 R
+/FirstChar 33
+/LastChar 121
+/Widths 145 0 R
+/BaseFont /IAPXJO+URWPalladioL-Ital
+/FontDescriptor 69 0 R
+>> endobj
+69 0 obj <<
+/Ascent 722
+/CapHeight 693
+/Descent -261
+/FontName /IAPXJO+URWPalladioL-Ital
+/ItalicAngle -9.5
+/StemV 78
+/XHeight 482
+/FontBBox [-170 -305 1010 941]
+/Flags 4
+/CharSet (/exclam/comma/hyphen/period/zero/one/two/eight/A/G/L/S/T/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/r/s/t/u/w/x/y)
+/FontFile 70 0 R
+>> endobj
+145 0 obj
+[333 0 0 0 0 0 0 0 0 0 0 250 333 250 0 500 500 500 0 0 0 0 0 500 0 0 0 0 0 0 0 0 722 0 0 0 0 0 722 0 0 0 0 556 0 0 0 0 0 0 556 611 0 0 0 0 0 0 0 0 0 0 0 0 444 463 407 500 389 278 500 500 278 278 444 278 778 556 444 500 0 389 389 333 556 0 722 500 500 ]
+endobj
+67 0 obj <<
+/Length1 1614
+/Length2 17799
+/Length3 532
+/Length 18700
+/Filter /FlateDecode
+>>
+stream
+xÚ¬·stå]°&ÛvNǶmulul''¶mÛ¶mÛN'étlu¬¯ß÷Ν;ëÎü5ßüqÖúíªÚO=UOí½Î&ÿ¦¨B/lbod*aoçLÏÌÀÄPSÖP4´±14±´—¥±·1ü5³Ã‘“‹:™:[Úۉ:›ò4LMb¦Æ37779@ÔÞÁÃÉÒÜÂ@õƒš––î¿,ÿ„Œ<þÓów'ÐÒÜ@ñ÷ÃÕÔÆÞÁÖÔÎù/ÄÿõFSS€³…)ÀÌÒÆ ª ¨%-/  ’”WHšÚ™:Ú]Œl,²–Ʀv@Sj€™½Àæ?c{;ËJ2üÅ @ScË¿ÛLݍMþqÑLl-À¿ßK ÀÜÉÐÎùoœí–vÆ6.&ÿøk7³ÿ—ƒ“ýßÛ¿¾¿`Šö@g ±“¥ƒ3àoVE1‰ÿàélaèüOn å_7ÀÞìo¤‰½±Ë?%ýëû ó×ëlhi8›º;ÿ“ËÈ`b t°1ôø›û/˜ƒ“å¿4\€–væÿŀàdjnèdbc
+þ…ù‹ýOwþ«NÀÿR½¡ƒƒÇ¿»íÿúŸ,¦6f pÌ,s;ÿÍmniÇøϨHۙÙ˜™þÃnââðŸ>WS§DõÏÌPÿ%ahbogã015ƒc”·wþ›@õ§2Ãÿ;‘ÿHüÿDàÿ'òþÿ÷¿kô¿âÿ¿çù¿CK¸ØØÈښþ» ðŸw @ðÏ%ó¿ÚZÚxüŸÂÿ{¤†épü?¡H;þm„°ù_1˜˜þÃh ”°t75Q´t6¶˜ÚüíÒ¿v5;S'K;Ó¿jþÛH=3Óó©ZX[ÛýÓvöÿp™Ú™üwêú—8£¦–š²´*íÿ~£þ§øWygU‡¿ÔþG%rö&ÿsñŠˆˆ½;À‹ž™@ÏÊÄü÷ÀýåÃÍÊîóÈø/ó­å ,Ý:Ëþ»óŸâÿÇï¿V?þŒ¸±½É?³¢âlhgòw¼þ§á·±‹“Ó_Uÿ=ñ‹þÏõ¿ƒnjênj ·±joÌl•ž•á\7:-¦3ØÏ >âPÖ¤Z\è_kßç—þ‹»Êà½.„¡y–ç³ÃcåÌáã@†æp¼ˆ²/Õôª€À‡”z u›¢‹“ö0Q¯ 1ã\#ÚëzYvB›ƒIýpoZIY¯ôŠp¶‹Õ æú‰ÚŸÔµÐƒìÑÉ×8­1³¥­¾èìœ"éäé‘rxblt¤ïràŸ67–œ×‘"Êß1_P[­R¼º™òª#/ʄoÿO«XîJ«–‚ÃôŒ×´€1BR ˜¤Íy‰3þÕaRܬ€[†úy­r£áù„‡@†öìåÁóå¥E
+NHGð3 ySWl
+Éq0®Wä-¿Cã ª  èLëy&ÕLŽz |&Ešð²†››¹¦?68?&- ™ÒޏEÇN æ·•þfHôx‚ÃÌéz{Èß­ã•cWiË#ÖqÊÝ5?ƒVƆõuí vó’—i íůÓÏpÓzŸV,â2OÒë
+¹»/`
+ÁÄu¼ø¶—êèmfÕm™37'µÂý²Â™Ü”­TÔ[âÆØÓ"teï|M=birُhÖ>P‘£ï0S±Dñæ}ÂýúЕLj٠Öç ÿÜB¢ÂO¬Ó0u÷æ´²
+3E¬]]p†7Oba8بêôc圳U¿çàbaÎÌõ-ur¨–Ùðü9Cì9·dfºÐ¤Øûr§¢>r@ßµ7ܖ3m7ÇBÈÆ£¸o×ÄÍê´»ÒV Ýè8y—.ÓVèQnó»ƒ}•S”½}­˜šÆßó”6×VÉC$/ìJ_ãJžp»¯|žî8×ü‰ބnýtËæ «,Ý{ ß ;ݤÝû‘@§j¦‰²DNl#Ù:ìýš,øRñp²r;t4ýªÛ­dâý}G¢;’3¶…ßyLh=EçˆùA‡ÇÈJ u I=¹Cò¸Ë¶ƒDv Øù©j¾ÌÖ¯FgۈN°B>Fh;½Š}ãÇh¦Þ×#]¬$B0Ø'›«õ´ºF¥2\ªˆjoÓ¿VÁ('ˆëo 5ÕK›#s?
+™Œð‘`ٜ™Bú$ÙGKwʏԞ:†:2ô\BðâùYePó `Ó[çFV¬yÒí±vMùCKÔä»
+R¬‹šTzg&$BÚÄBʗ`8!É<óÄ
+û ¢T@›È*˜Â¶Æ7l,ÊOðg$܃Q‚AÛR?RÿO3¬“¶]Ø/²¼CD›¶Ç.5É­B²ó¿ÔÎ ¿I©“ah#c’L­
+éŠ3m
+•FbB[śÃBþt+ ²Lp»Ñ`-ČZüŒˆ,aÅ´¦öÍVjLà/eœ”[ҔPàZ&j»¡cz.D~ȏ‰XÙp;K;kAÓ#pÏN®ß»!zG ÷h31¢Ê­ìÙ
+¨ «.‚
+ókƒdö²xÔ Þ½–{ê¦<˜ ›Þ ΀R»>Œ\V ?ÃcË5ã°×wZ^‹N¬™À‘ÚTyX"LâãVo:½º£2\K‚Rf*×sºµß¥jkƒx•Ÿ! ³3Ë ®?ssŔ…åüJ6êåÊñé ?^ÃìÕU>áÇOµŽÈhH2÷Ç/É5CiløªD¸}ɔ¢“ ³ÞÑZ$xá¨ò¬ÁÕa𼋿Ç×o½(*@g äª~Ŋï܎íÁÎñè~¹ g=U'CÅ}1šqŽYõáÚ¨¼™N}?¶JÌÙPƝºymØÙáÈР¥[ä÷ÂcË/–ùñ 5käƒÑs£Žõže4ÉÏæCUñð–;³Z€:ãÌjŸ§(óô‹}O ݄ó^ÇÃ}ÑÉÕìQÚ
+ˆŸg¥õý\(Ù8ánœËpõ”S´ïÝ;ђìދVÞ o„ªÛ_q±Q‹oàÈù4ë 5‹l5়v½œOlÜÚ8ÚúÞÁ¶Fïò1£"´—m¹Yœ
+Wä 4þK\y$* ŒÙrÕ-‚Tn؁†¤²jî¥ð_Ø
+£ó}Р3Å|Ÿ£H©-o4ÆáöX™–͜֊‰<Bµä­Ð†ÍÔzÇ\z{Q£Äµµ)nëـ!!o}Ô)ÏQ46ÃRohçÚáRG:×öÈü+ntPQ[Ä]嗁›ÃSF f HíMwŠâŒí):$¯ç1¾H,³ç'ƒóëYÏޘ†uiÕ¤Íó…/?ˆp­FžW
+tkA ­5tS‘Û}²[hF$Qkç.»EVȕ¤¯0ÌÔq}D'KkF(iC±¸VÃÒs²s–S/4çªKÒÊÂä©Ü š
+ÖÄŒ VQâÖeAÌ%\Q#‹<Øë\dÀåÑZ›®î6iːp¯E`ÛÝ,ÆÏ|èÝpÁÈ{)’=å“g¥7©Ø<¾Ã[9DCÚU9q 3³‰Zm믿Šµö¡È
+fùpFͱo‰Epáòæ«ÀT”@ÿ`Œ^{­o²x±!ÁQÊA¡J•Lëæ)ðþ óH«ýš7€R÷€¬@v“6-˜zçÆLm¶ìý)ã)lëžrZý½í-Þà˜…çÏÄÞÒ(¿á¼-Óª
+øõ£¶M¾ISÔá¼ã3ìHRgvE*•øÇG®_Z>}OîȼL‰ÔíÕ3E¯I÷J ÀExIF
+ ÀžÑßO\Û¡ïd_˜HOè‹L+1ÿ‚…F¿à„:ß«|‚Úë¹¾ërò>Ëñ+×o°ÔU WrÈC)Ù'(ÎòÕÚ§§Ñ΃ùüa<ÃtŸzEœ~µÒN^»ÏUey/a’W߈G¬'è÷…È. 2tà/ªÈ˜5‡}H]PO¾œ
+¢ë štÂd4|òDÝLzÈJPBÕöñÒC7KZÞMØ)Š¼EJÂm …‹a¯vŠó
+;f…d‚iö½6"f‡ŒþŸ@dD
+©%È
+óØ°è{¸M›æñ
+­Ò‚û<w©Ù㸟d†hUX¾)å1ÍPyèaӕâõ×r¤›S?3ŠéY÷~kä‹ 0‰7Ç<€Në¾F¦÷dò¤À|û•dŠ[‘
+Ò~HG“v]¿n»ÑÇÈÓ$÷[«TóƒäkG§›ç¹[ñæÊ궃EÑ2²TÏ—û‰Œßáé
+;«‡·@Wó]’íãL¼ðÒÆ͕™²ÞI d;ñ³
+›„‹Ä"ô·_ÿ7T™ÀÆD¦ôµOjö#zÁrvÿ}Ìoº²D2ëíЭ$[ÉÜ)†ÚnúªmÑßً‰';’“¶.‰ˆ0W’äî"R¾Cg-¦ƒ;lƒMÞb’+Ï~©;¸™Ö~µV©ðènÐ)fƒZJ{lÎj§ðnœâ¬˜H+kKW§íìÈñº?ßãi'Ö\<ß;X}‡YÑ¿Çl¤–æeÄåq;M— ·’¹];UÑÊ%—HRŠ• .ªÑ ‚¦†ª9.à*ˆ&¹²DzgÒ,⠛ÊbKT ›%d¾UqE~š|‚h"> ×€UÁpVÈè½,¤‘E¢þÒßCPkËp„2jþä¯?¯§Æeå”
+dŠç¹7ò€JM¥öÿîsd°p¸9ÁBW¼^Ò@__\WcÖº´ü®q,x8IëS(¨;ß7h!ä^Ñ%Z$ü;L~£“éŸ^ƒåogÃ堞v^;Ö{¹“f?”c3Hõ+,ŒV%'Ì9ݎF±ãóނsN•ŽzŠQ°.V]ýˆ™ Ò¬ë‘;Ù5³ªw*?GÝãQÛcoœ“;
+n×”ã!ƺ„#ݗ:L Sm'¸4â»®‹8æ…³¨*F„Ø©¶vvŒÏÆb7óät×þšÑ­ªz³ÅhB"ìâöŠ œ—7Ύd‹FOíÑ |Êç<8_%M¬Ï˜<H¼Ž¬Ìå'ᮤHãH½M¬•¨ëÝtb˜CꆠEçO }ߊ0T$í
+m@Ž9ò£,ãË÷3æ³E~ؚ¾©¼ðÃTšÆ}MþLrëYí+€]›·îþ«n—_T'1µû`í`º*9Íqi¿­ÉN;³…϶/F ~6é
+¡0ÁI”}(ԃ–Ý&†ˆ[ ƘÖ*žSw¨Ìî lÆ;&†H {ïçHEfþAd Q×€j£4TšG/Týñ]Ûf&‰^æzknŠÍ§Š¥,ÿ–¬S¢M%ÉpóQI±âeN[o’àºt1 Š r?ۈ­r~y
+úÁÙ8 ªºâ,i~MQ öƒ5=¼îi‹ïÆå›Sv×WuùLá`ŽêñÏÁçìèÑ»`ìH>´1’%²9ýÕJRVü…3¼µDÔ±‘
+1ÆW0Ö>Rm¨0÷
+/‹ºˆ¢|r¹8½Êå¡ÏÁìuþ_Þm±ßëa––ÄÙÇ5ù«UAâ/ä)¢Ì•ÿ9çD²—ᆚù3a:‘§?dÞ¾B’‰‰ä&õ=UW¼4Ûëaßî9\§F
+CÄbB«€d%Ø;ï†ò4šuq’”l/Âêé;t/‡wڗ•_Šöî¢L-Q¡Â;‰85Žéèuˆhg¤u ¸Š–ß5êÚµ¾c`MP¬b-/5]Šþᨇ„—¨@Wu‡!VŸÇä_l n£
+Ÿ(%=UÉ#dƒÖÅtdðž`ÿu†Y¨Ï/Š’DîŠÃõÂrXo¶Y²›ÿ .3ÏTèuÀžÞÜÝþ[&‘Áòá,¨/ ï%>É {±u)ú<w˜!™yYÿ7˛ZønŽÿÅsäwÙ ôÐá2®‹j’9q¢M×_7v._Ì8OÅÆ{‘º§í‘h<›+܀ª%Æ~TèêT‚;-k|ø8β@Ké’‚]¿[竑JՅ"‹øåþŬêÊÛ-è­Uù¯J#6²!™‰Àß )½†WÅÕäaXNF˜Ø-Ù ²'À*ìCN1ezmf|­ðiÔ(g9ÝyA©¹륱¢@ ¾@“è×Ä °UñLT&™û—þö³
+¯q›dlËÍf‹Â×C#Æ¢‡&!ãC„'‘ò|ùÚâu¿‘0ýIÀ~âÏqzÜWÝR¥Ä‚™žó#„a‹ ÔWÅù‹„Áç˜BM>j8lÜäõÑÞY> F¦Ý¦:ݕƒHz9p>QÀÕö0aX;zx¬¾t«UuÐ có‹ÒQ
+&Q—8^F#êUyúê(II;¡ôKK¶Õ½· ©³ð.—ò'vvÐQRæhZż¡§LPÊ¡˜
+¦ÿ$ÑÚÚ1Š<T•JÓ¤©{ 1Si†!ÓÓ°†©¤ì[p»ÏÄɆ›a€cÜßb^ŒÙ¸^ºÚșiaßFXë'ÙßÍ/¢48’«VýìÝËv½Ãø ‚À>uȾ3Y¼²ÙË+³£ð«Œ<àD£x"3J"ëwÊuH=e`Ò>‹3~²ø«ö…E‘`ï>ÝRî@cœàŽ.ö€ÑÀ¼ÏKזÿ‘±n.R hu,›,óEªyh``ûÍg5ߤ1šPžr5o+ùX¯­ç9eÖMÕ?´^ˋQ“PDøÌ(±ÄG-˪î{?üK¡ÙNÙgÂç´à×µ–&zØ¥xž
+,‚,TÃAÅh(~R«ep¾´Ž¶/Ÿxi5à2п>£÷B®ãØSÏVqY¿\hÉÜ£{ôCV<Äs[Œªk65¥ H§/“i”T#(±Çpd<([ËLI òl‹&¢,ƒî®-.ʓ¦þžµ¯ ˜•,³ˆºOuiB¹ò_ 2ÕHŽ6ýžTªX+HYCiãÛ³:㔞èO’óY<§†ÄÖF" Z%”ZM=Âc{õ\uüþàÉuD„Aƒ•0ÂÓ°0yì|
+f13æ.ƒªo 5 ¸`QžF:~ U0’¬~z7$œ.î·*–íÂæ =±ºõWo(¡TåXñùýZ Y&X„™|)îûRñ·“[G®Ã
+Ue.&J¶i·Œ/ç+úQÃâÝà=![’¬ƒooa"- ۄ4I¾ÕÇO7ÛÀEÒ$kÌf°ñ£fxqøRžÃ„ç2²ZÍÍÀã<±—9ú²Â>/%Ms};%¬(͑MncMºµ<©V~ÙáᰎÉC.Jßq½Û^ùïr¨¦Tnºh|§ÝYTºn
+Rq/W Ì,=Ó‡†oQUlŽ/Ë`Ø7c•˜Ó®àO`ű"­7áâà‘÷h¼ºCé%” »âX?ŒÑmT[÷]èéÔ³_D¨ªgÔÝÈ>JíYÄØ$¨»·ðø:¢ÀEY™af?´… ÛNo¯Á8s [®exã±ôMÇHáë7]”'âÎð¶àj—7a¢z¹¦j 9R²6™ `ZêþóèM ûÖIîg:ïÛ¥ì«ì0ú«7OڗÛû*ÖOŠ„ü*Üs;Ò¢ý;¤z|ª5A >N)‘…ƒxÑ.(|²^­[U“ñù$ñy§Ë¶Êppnë1M—­Q¡è\¦-2ÍX‹fƒiòóx™ÍÃÉ!Õ癀jE4˜7E–+Õ÷êõҊ—,½ìÏၛ‹pÊU\ûP×¹¦¤y¿ê{Ôp>8
+îDš
+îMœ<3Û|ño=ȏt=,´•ž±’`².aG£A÷ù«Ì„–,¿¯hà3q àçEò Ç*^ew²«ñ CÀ%°ÿ¨ZžDkr>ß-P.)@šOú€UÃOtŸÊW ¹7xÉðB¨_V1ܕŦD¶á´›Ñ–ƒØÉí̙¼EÐÌÎDrå+&©:šN¼­mÖ²|±×bWƒ¯ãކ„k 6Ö`+ñ‰)"y}P`(vFVÀr S
+Ô\ëŽ-¾Eüi$Z {ø% Y)ƒêzÊÝC¾±´ W•oT\â¤s¶kàP ª–B€Úu½’«™ûX8\î%Î\¬J]SN1ž…i>òa¬€è³ÛÕÞÐÚÚÖ§˜…ÖpĞÄ1¦ª“ ê¡îü10Š*Ñà»6j›G&i¸eœîàh¡U qEfm©Ú‡3Ï 7Þ×2ýÅÅàlýÎÏ+¢Û
+AOéû¶•NBe%ˆJ?·ºé™À¹A®§éq¯ì­F#ýpžä×ñf[ÏÊ Sbk(‰Es¾³è3(;?ãm8‡]Ñu_•œ,ªï4܏ëÙJž>ï^3VõuH§
+è»Ò/Zú.xU—´•L)„xœ}µÆäYx˜Æxx\£K˜3»”Àåì_ÈÀ†fÁ<w(¦…‘¿jn6‚¶¹’§TaΌÉ1CËyÆDûgŽi¾âëï–3f„Kɝ¬0FR„Ò¶D²zù ^ð™;a—Ì%ÅCäw8.;Öæê!§úßN‚æãžZÖÌÂ]?äˆíZ$õ­˜F‘x›dü”·Ý
+ÂA%Á겁Ú#Bê«k {ÂD¿XO¿>tÛ±Û˧/ï$í×EĬ>Tâ Ê-$‚+•–d½ö—<YR/—Ú4Õ@}Q
+Ã^$Ù×AÁ¤Ý¨ã~´_VìT¡DL]¸š7—p8,lï#M¿MLnS×1g®Ê·^ƒnÆ^ž‰09ÿ۞&3.é)þ[ߐ8M
+³[ƒßšþD9úº]<Gª¦¨J>I1Xs™¤Ý l§N̲¤òºã9ëú6©þävå{Y˜dÐáŸTàœoȂrrT®ÑU-­…8¼1-l£@®¡rê²6Ý··wVæ^zÐþïh¿ãŠ‚‹šž«K­&åܹÝA û¨…‰àâc³ê[YÇ`(`fFî'˜ÎôD¡T¾ScGyV×rV£î<ÇÝ2Ÿ·?T:µ¨õgh›•®w •N‡¡ ™ùŽf,@§D´Ö*9Mâ¾á¨‚y’x: 6ÃýpÆAŸù>òµŒàª|ÿŒ“ôl’Œ…s<ÂOžÕó‘–ñë.üœÍ=HYñc¤ß9Þ»,!ÉÎ-{YýêSš„Wø>Ãø&ÉÉä 'R‡½Ð¿2ÉÈxÞD¡1á:g’¢>þò«@™Õh"jÝk»u©Zgt8%CV×¥ø|Ñá¹^O^½êªZÆ¢î„Þî}’*lÂ2ŜXÂnÓÚ(j[Íø.¯¢]'‰+}?.m
+o±*‘5¬¯laêÿkÎÿ™pŽ¡É\͵¶PfB…,#¹cŽ,†JnÃbfî;¹©D䖛\“kú–åΊ4*ɌõÝ\sîáyþ‡ç·çõ|þ€÷/`¯± ”-\ý?ªVtà;Sö–ë_/¦š+}*7—ùíXwL$ô¹U'VÏRdXâ³c¥—ºM¿ß²Jæ;¡±Y{ ëéåÕCB90D,¿å° ¯ç7nkú;%­õ}8üÂéZ Ê·¦½ë(ÄńVp§ Niõ‡eÿPxžË”Y†½D$ˆå©]¶âœáG#阄£êhéc7\³•-§ã÷}®”ÿd© Kx”†fåŸx£ ÞlJDvó͍|n–ü¢"‡Ú«ìÏIÐ½{0¯êP×ʱ’e‡ƒVÓácÛ%´­[Å*ö˔ïü§ÁfNë–^ü{X+¾¡E[Çݟ¶+÷1ÙR›óª¤f¬e;S¢GG:ôÇ灪‚Kê•X7üéï‘:»çIöáSvk&>ÀØÖ?vªBúDÝì
+qg‡]=7é]Žøµ’xªÅ%0<?EXŸ4(üÙWŠ?œ‚¸—Z‰ê¾ª3o‰©ÇD:#HyBeÜ|èB¼o–€œÛ…Ôf;#kŸ “H[éÑTqyÜ˜]5óÕ(67 ÷‚ ånê-ZYyؾõ™bWãX„‹BO_LPۋ¥ëä:¡«N¶–£›)rqÖ5;ÔUSÕŦÿÜ!y&¯ÂOÿ|¸b¢{¢nÍ×"R  †µfk$ÆÎ
+c"üÁÃêC[»ÖÃÒd
+A&òÝ£èÝêãýS½´Qôp‰vÑQ•i-¿¥6«9¼ËºC¬´™µ¤æ·Âօ[GÛ¶Æ5,h—ŒŽßePû+ýKÞ_ƾ©IxF®%Ÿ™¬< ë:ïWЅû2‡ÚÜç,±!Ðý†ì$ôˆØ©U”œqÏÏvêÖct m°JQvA}¼><×돝–Þb²§È_×0œ”¯Hã‘ON‰æüþË!›9JXß÷&™N½Â"B—øÃoî,žÍ*ªk]ClŸô®¤îǺ¢çÖ¦Ý
+P7GÃÿáïk…,u¯Û-Q<@”’ôëWÀßãÇ5H;›¯ý¶
+ÜÊ¿ƒÓÈ5|Ÿ@6ƒ\-˜îÌ9çâcäΌ(æ2"6‹ìÒ"ç1tý0åe‹”t WAê=ß=æ—s™ÓÕ9N™à¿6,ÇY{¥b`_üÕµžŒB.å
+@é£êïn\^Žx¨â\¹O !´ $˜ƒy•9Uo»yš,šþe:üS9sÕãÑ\Ï)Ç Ø_ôÍ0!vø½[®ŠgÚ
+AmgڝWVøÚGg©é3W|G–Ì/þ—þüO^XàPÞ#Øðo8ã¡endstream
+endobj
+68 0 obj <<
+/Type /Font
+/Subtype /Type1
+/Encoding 143 0 R
+/FirstChar 45
+/LastChar 121
+/Widths 146 0 R
+/BaseFont /XYURIT+URWPalladioL-Bold
+/FontDescriptor 66 0 R
+>> endobj
+66 0 obj <<
+/Ascent 708
+/CapHeight 672
+/Descent -266
+/FontName /XYURIT+URWPalladioL-Bold
+/ItalicAngle 0
+/StemV 123
+/XHeight 471
+/FontBBox [-152 -301 1000 935]
+/Flags 4
+/CharSet (/hyphen/period/slash/one/two/three/four/five/six/seven/eight/colon/A/B/C/D/F/G/H/I/M/N/O/P/R/S/T/U/V/a/b/c/d/e/f/g/h/i/l/m/n/o/p/r/s/t/u/y)
+/FontFile 67 0 R
+>> endobj
+146 0 obj
+[333 250 296 0 500 500 500 500 500 500 500 500 0 250 0 0 0 0 0 0 778 667 722 833 0 556 833 833 389 0 0 0 1000 833 833 611 0 722 611 667 778 778 0 0 0 0 0 0 0 0 0 0 500 611 444 611 500 389 556 611 333 0 0 333 889 611 556 611 0 389 444 333 611 0 0 0 556 ]
+endobj
+63 0 obj <<
+/Length1 1616
+/Length2 23802
+/Length3 532
+/Length 24696
+/Filter /FlateDecode
+>>
+stream
+íYþ {þ§çïNgKs;ùß7 ½ƒ-ÐÎå/ÄÿõF àb˜YÚ"
+WgK;óÿb@ pš9™ÚÿÂüÅþ§;ÿU'à©ÞÈÁÁÆóßÝöÿFýO–.Î@3zX&æ¿9M\þæ6·´ƒeøgT¤ìÌìLŒÿa7uuøOŸÐéßQþ33TI™ÚÛÙxLf° òö.S(ÿïT¦ÿ'òÿ‰ÿŸüÿDÞÿâþwþ—Cüÿ÷<ÿwhqWy#[࿛ÿyÇdÿ\2vÿ[´‘­¥çÿ)þ¿GjÿƒäÿFÊÅèo+„ìÌÿÊÁHÏøFKgqK ©¢¥‹‰ÀÌÈæoŸþµ«Ù™l,í€õü·•:&FÆÿæSµ°4±¶û§ñlÿáڙþwî%ú—9ƒ²¬†¸†Íÿ~§þ§øW{UO‡¿ÔþG)rö¦ÿsñŠ°°½À›Ž‰@ÇÌÉò÷È13¸XY|ÿÿbú¯µœ‘‹“¥@çoٌLÿÿ?~ÿµÒûo0bv&ö¦ÿL‹Š‹‘éßûŸ†Ü&®NNuý÷Ìÿ-ú?×ÿŽ:è4]]²7á ¶JÏÊp©ÅÌšÕéëa
+q(mPýYPmß퟾ÃUiø^Bß8ÅýÙæ¹xæðq M}8҃aCѝ
+¼*Àó%¡ê-DÙ$oç 9 bÐ/EÈ8׈ö¾^Ý×fgT?ܝPRÖ/y‡ÄŸjgq‚¾~¢
+ q+ @#}t@ô3I«Cï@nA­-:;'O:yz¤쾅è=À¥Éƒ!ãqG 
+ÌCšªÎҘqïr®ÙkTô¯O¾¥$›*;¡Q}ŽÔuœÛi´²š6-Ù×£·²"DǘóÂâ'.5o±è2‡6ê—u$‡|[,]ô‹…Y&?ÔAÚ©S™?>À{ù¤VSl­ú’%=~?J \xQfüJïŒ ÷,)’$×dΐå©
+{
+$Èí(ŸÆ"u
+b&£q´¢TßòôšªÕä5 ðê".pJTá‰G×ώŒ)uÉ¢) Á_ó¢?}©j/è½R?,͖–šœ>¦NËç‡e–­oÿú›¸¤è‹ÚÎ|ž€¥AIXcOG_ÅîCœ/à o§y8©Jµrý´8¹!ŠÜºFȆ7´–úã[ä}ì[ƒ+Œxy©ð´¢sÅSvƒn¸_”ô±\D/³† 4৚Hé)°ÖñEP‹8V3¢ùŽEÛÖ`0À*á³UÔjÙÉ鍇wÞsV—î66™h»Õ.¶wœ£¿y[¨'-0ï åã^³w/¦á
+ñKYμ¦¢çŠ—È'Ìå~õûסxŠ«´vL.â]ðIãVwe…M”P8&ë7©·Hé²_}›æ¨Œ*AT2+7T¢
+.kê!Í V֖G²ù§&ZW9$ÃG¾ÄÜÊ%êužQë|ÞÆ*¾RèdáDzQÂ,‡²Ñ jcîùl†Qõ¡èa£¹‚ÄG®¡6#îƒÎD¤b6xÉ2|®q´$¯ï‰¶ê†§ÖiB-z±ôÅôB?îµ;oôHòÁ°¤²ø\Ïð}"’;J’{ Ý:€A°¼áYk·Ù˂tÜí+®1
+åë|2n®5¢ØäÙs½Y;«5Êìæ’+í¸<uƒ¸e)ÝnÏTÝE “îzÜ*µÚ˜P¬›Ï–¤"D¸"àñ}•íò+&îYêÇ,zÉ¿âdR[ž9"ö_˪œtßG¤‹Úƒ`òDNU[›Çð´_Æ#MŒ'ý9'DúUß$Ï\ð„ò;õ\ ̈́>ª Efh%œ•d—¾úš?pÌ•§—"” "ý!>‡’éé³^ >1ÇÞKš®¶Ì£‰+»(!ü®‰ÍëNjØ!…“"§û*çëÓ;Çú-— Tnʍ^‡ë¯@uàÆùTrûß'àÎfÊQ]ŠÞÜ×딵´Ay^\ֵׅûRÝ¡òa#-Nb÷ä¨jÎʾXÀ•¢ÙÕ@UíŒ-¸‹ÔÙMkpê
+êŠ:ƒk¿$–@4yv"iÍø𘠓¸)"ö®Í‚€'ǞÚz?ÃO¦9yU&¿- I)ø›ÌÚcÙ¦ýdj6ÜÊ3¯&­Nºô*ëϗ×JBVGy`íU¶ÚKtÛñ¾nÂà=|G$h8üü
+v|›–Ô×@@¯ÖåùUÃCÀÁ
+ýËká”ȏaAÆY›6£HX«ñ¤-*Ii·²Å$ ýÊÎðd_¯S±`ç$CQs
+Á®¡¸)6­oÉùlÜ%Më%l0Içôº…Ýìb§aFøaMO2®Ø¤]ÁæùQ¹CeB='ß
+¥„0òî1oªLy'Ì×N¸#
+W/
+]dãõ}*ÕÆBĸF%³»Â¢ƒ@òfzØ¡ø]“F)_÷ÁD%b]Yv˜1ލ€¢ë(‹yÓõ˜qŸwcÙ2ãs¸‘ûÕÄ#¸;”üV¥¹å[þuYª«–;Kùø¥NŽkßù Ñ€üeõ„ ùs™Ü°©ß!¸®¢K,Køê&É×P¶Uö·•òÀ[CÎÞÜρXø-€½qâ¯îì)©ö~¯ÇuO=Ä"l+¢†~¥ñÝíïòÜ]Ð\­)J2¼M
+½•°º>#qýF°® ôRèyÞªOg^ä~ÿˆ^í:S¶y._ µ«‘w½Û2¢ˆŒÑž'šJzß²àºÄÂo"k‹ºÒ€!Q̸ëú/z ìɾwÓm"i^XúáünUoáD|8·?!|}_Æ[Š•tÑ7ž­ÒAý|Îçò÷hSk('è¼â“†T
+ü\
+¢: {^}…ŸÜhƒcëª:EG0_W:þm÷ÒLœöPKV‚M³F¶>Át‡Á¼ÉÊ]’/‡#Š½ß~Ì M>¥&Ó£]–¢gd§¥@ÅSú4B+apCì]|p¸Vïv¿1ë̍œ»VåúG#ûå¥=£0 &´ÏøºãòL×.}ˆwJo!þÙ7t¦µNWtéH¨ÂK<!†ò@vSh2°5:Úhš|phLºuÂ?Œ ¤©Ê¹Sf’’€Ô<ì¬öb1߸Ï:òðp–˜“îHj.ô
+-ÜíîEø»ötŸRèL,(ͱ9œ)w l™³æ5fbÚ4R2d X»Àýḑ×Ã[:™ÕHUÒ2úÃO+Ø°§¼ú<Q½Éxî7&ehÛ
+;„;ü͛’Ô̅XÒèuñÍZ µ¬wýŒAŒG÷1AO˜‡b
+ÉÜ}÷NuÁ,ÅûX«[†î#D…À.ÛtUÎ|vߥ¼@û]&Üg¼Æ!åÐiƒ½O „4>Wý[£« ‘1A ¶mr¼÷¯˜äs<§ä%9»›¿mŒóp©ÉZòIå w–9E^åŠH(TïÝ
+­rhևâ!Nˆ³Ÿ‰!?ud*jµF·iŒ9äzïóß³vòBÞ®2æp•(<w‰ ­E}¥”ìå~·!$ó ÌࡑãæºZ0 Q£„ilN¯X²ß*iCmc‰¨¨ïüêOjøàN÷èœÅ‹±†›[$,ÔCïE1N¡œªº"ΉÓòɈràÈ5¼ýo飀£
+;Þ<
+<j¦SÒ#XÂôe~ôã¿wω f³«î«§ö÷
+£…¿'tÈí_”¾knôÝÀ‚í™O¤KŠ¥Žºv%
+jHŒå†«P96{ ¼V:#òW}ºA mgßð2exV­HŽ2@ü(²ê’ê"ƒ½‹¬TW×ÀM¸qªá³¢Pònp;«­XoæÚuT¢Øöͨ’¥¡q¿‘F@~®šêÊ&@LTږÚT
+ôçœîøºAEÊ2|c]RCÑõ¼1¼D:ö"ט‡·”I%VÛÉöX'Ò&Û%¦Ñè¸!üPiåÓ\K…œúlç÷nÞ·Ã1±¤äÅ9ˆ]ߤîžýÏöðBµywûÐgJNTuðv¸‰nìŸá/¥_‡ˆzr00"ÀÿÌ~þy¨Þë¹QŠ°oÄÙÓøõÊý>ƒ™ÕüŸ
+mtPÆl¿‰=%¼¦Õê'ø…ì)®\2„«|IéÝâ"ÉcÿáÚ[çW¬m³å›û0í¶Ë6>9WdTïۜÉ^¨Iü­gì_’¶‹ÜA
+¿™Àµ
+Ê3ØàŒ¦’ÕH–’ÊÑÓq`×GÒ Å7JÀá¬<)“@!xão:£…2;@ðBFyÞ´»bU¨hp!Ìßx
+‚x•ñÛÝpvãXÕ¤ôË YŸG˜Q-S#®}fÔÛ«-ÃÓâq‘ì %GÿçתÅúÔÛù×_f£ŽXuríP`]Ÿë쁅Í0, ¨©t—W$†‹Ü6ôµ\ÜD}éò) ‘õ¤¦ªÕx²W¨drK[GÔ>Šlœ/ç6Ù0Õ/úŽª?ù4=Á)úw{³V#5±…ŽµJÇ|ÚYâ¾v¥Åq0+Qú –ÁèI„Í3r‹TcÞ¾Dë®ùÛ(7m*8V¯,²¿ö—¨9 ¬ˆnÝËòfI,|ôéó±0ÈT]¶ä¯ÅÒ¦©=õÿ¾G$°Á6¨ºîÁͤ±>2ƒ[2AՇ}Qú6ßÜ`;ð^ªüœÉµöåÇZÛn¤^á厵> eQ5Ô_3 P&qó÷Q
+ÚýÁN»9E†ä4‡ñ¼Ž¿:'ٓÅloz}NÇæö»š¨be±}n²í²n£oŤdj¾¤–|1$ŸÈ1ÚDZà'šF“Ø@}d(ÐäÏEoÅ:ÑKânÂE£ð÷Óäw­-‡{QÉ;)òR’w#Îé‡éÅÎkòÞa&_«™'J§«­ÎWÜøzԑԎð8 ï_a,ˆYü.ó´ö¯Ïp6³árMzƒTúC«cúrшK-„†•<·yPۑƒÃ5< …wÃùtØqi%ŽØ‹I¬-8Y^üÒ<ÊÍJ¥M܆ç
+/ò?¬°æržC#‰¡AO$:£Á pÚ$ëÜê~Sßè¿d”n6Ù45žViÓã:vðp@tiª¯ÕÏSáÕ¡ Â?ÃǔL(@VŸ'Ê$å?yï$³˜éqᗼ·¢ÓúOÂàÿ0žJ:_"oPÌø&?®4bòUAÏð?¾±|˒¹…·øõƒ§F†X˜³ÏaF"> ¯©=È+Ñâ;O ¨$ÈàÍӟðI©H¶µ!žÂq_‡“]<éYeH# qŒå”·üìnq:q”á£ìTà7§Ê†$G<©ºɹÅð#ÝTAP¼º„3&(I¶çx%’ÓáH
+÷.Ã0r|ìy‹áiJHz­ªfñˆ”j46't¹á+ŠˆbóD¨a›Œ 0ôcÕϔ>1¿úU“CÂÅ®¦o*Äö̙{“¶‚ç2{¹5èS<ä¡^礋Da֝áó҇‰àX^Áž¬Çz¤vrý߬»Þ ‰*•40ţˣ`kB¡Vr}?8٘Ÿœ¿ußÇöÚc»A¨{ÿ<QV‘J#‘ilÄ6ßbú
+<Í_Õ*ꊯ•ñÀc햫˸¼ožÉ9Øîwò—üm%ËÀ ­´b‚ù¬˜|çìÀ˜aVB÷Á²ò'@œ[^2¯tlÞ;Îm=¼Ö˜”Û~?ì‹yØ?¾ö\mb’A~tܖë`¡_<OmêÙìåÆÛT6ÀŒûvR{©N!j…ÖåD¬>pü ܖõÝFw×îð¢^MwÃ&£vüY,výzkf±v6Tø©1ÌkžÛ†E‡ï±w ô½žeV tª(ý%«C3ü¼MçGÇ×ÙÈu՛¨ŠåëÅàR9Äø±š®€<”4Ø ?)#vtW5=›ßŠè…{T–‘õ·nZmkÌcøӋæ‘
+åQ§žYÄ_ÑÃ÷Nù°;p+Œ–ŽGôŒ1È¥Ÿ»
+NÛ;éì°kÌrQ¹ª–ߟ_0wâÖQ*º³'Ð@“Å8?¬#å`3lRñ…HŠŸ3Ë RøNhP~ßþpÙ:1U¨îº'6S?CF=Ûófx—úhmìÆa0t^.¤'Hk ­sÔÇýÖöUd\Årêï½?ëh4­tBÛ/¬=û˜ ìÖ*uÜJÿ£!ªB9„ÛŸÛžþÕ^.i°ƋËýWÆïr…
+C¡‚K¸nuiƒ ïÕUÛdè<©Î ë6´ £°ùA6yµLb»°J%ËëѳBuØ'·yGi€°¶&éGz;ñ‡¨‘t¹_Ù+¥¥cK:þ©Ž^º||eRÝip¡C»ày~ßíõc]ÝZ9¤nFü±Ò631‰(Ì¿wÊéðA¥VžØŒ20b8
+Ü:!À’±€è2ÒǨ3£~úÀÂ>j.%ýñp¿C´ƒX^h©=\ÞÃBèxWÊÝዛ[æā9h}ÏÀz‡ÙÊ}’¹¤m霪
+R $t^Ô|G‘`6Â$SÔQCMCØFðͶåj2 œ•øÿxûN\SŠ÷‹ńEçb³F°–~1òÛª7€z;ÑÝÆv,€•]@Ö@‹Î¥J
+x—XۓWåUR`…2GȞ©þ¹õÛì Taü(û³Ñ0ƒ§}ü&Tˆ
+ÓF:hȓOÍ¥ºú™žiÒàxÀK‚Ì„[‡”s¨c>£‡£ÃÍ àúYºÿ!UTèT£Û|ltû¸ݺßÈ1]ß®u—6òPqûð—N8&wŸö¸7 ÁÐtH!>:;¹O³b¥è%aöÞ Cw©@‘G=M‹îWy…´ðšs„é/ôóÏc³ÏäªrRÒRÒッéÌìÑûŽ|)”o ¢Ý*âLZ1«”<^ÊÃÏ£;)((ƕÁ—€Z”æ^
+-†(h«ÉVúV¹¶Î*ìÈøûÞúÆamGQhOjŬæë@Pžd¥Q9Ú¥:“¬1Ä€¢og|µ!pŸ•ó!rY‚Ûê0ÀZÉę©¡1•r5 uæ¥Y)neu±E"23,“"p«[NîŠ1²/»
+½ ×ǔTwÛ¿þ2Õ7V5äݔÍiXèù!DkB<‡ ݍENZnÜ©bõ±€&·ô¸ê½!ZèA]ù•¾¥ ´!F¥xNÚóTyߘv‡=ò»ëkøzF1ÍÄ+ÁTY,·ˆšyÞùt8‹ãŠè);o¤[ÁŒÞ„BP3ÈßIŒÍö“óÆíQå6¼NqŽ,ÙõÚ%n¶áóœ­éjšŽn<Ì«™N¥K¦¥u:gÉ^öL>魂®úr)¯·ªÔ÷»–·‰1ÇùD+Íð…+±­ßgí©]:ªÔ1…JlŠºÄ³eòe§ Ëd¾JN#ÃK›&ÄüïꋯA½AÔ&0 3$g$µƒ$jèÀX3‡z}²”e'®«šùy»-@â)¦™&y>A|–¨:€¦
+ñÛóktªMæIL“§æ㕠$Ün‡z0Ââ9^¼¥–^,|Š–KØë~kM>c„wA¦ jß^u¡S¢Wn§zª®ËÈ܈5,‰E6yÊL h®€ƒúö¬]þFÆì¼ý;Q;Éâ㌠㏹ؾ ÜæݬÓ:KÑC(¤ðkÒxq‘/nzr̓K‡¾­Q5q†düèà¤7¼òÆ< [yÙZÉón+Ãe$e®²ƒ75ˆaâZpðmq³ˆŽ?¥9H/•·
+o#YÆé©«3.V#b
+=L(ZŸ&õz‹k.Äu{óŽ,=Òèσlªèœ¨S,Øw7à7ÛüUóWdjuUº9˜£xŠ\tJ¡ÛŠÊê„0VÕÈŠ~¾»×fÆáU5–`¿!~0EõÉö¶‡õ`ŽpHÏø²yœŽA™-~“iA=Ÿ(ï'ꊚÊûOŸq
+íbdmnâ >iÆåì'ïú I9· ÙüjT½Gø/ˆa1™ —„É2kE›fïÄí9,iŨb1"%*Œ‰JOâ*N>äûÓ©æ„
+‹ùà“)Í
+ß;Rç‘Üu¼{^´?h~=¡"†…~…ŒÆP2
+ÑiUèÊFùú­DǝσFŸöþQí*îÚCk{s™éHñvêc´ݚ‚VÇ}ˆWèMt¼b‚væY»
+Š%ËØܦDïGHÔv8bÆL֘Ô£‰©œqF’%iüŽßá ÂÕߔ±7„ÛÅêäH+µƒš›AiVÖî„,¬EW§zÇèKâ"çwÛÏwè 6ǘ2«%ÝuúAAEMiµµÖMŽv€Õð²÷ƒ×Öø§!•ª¦̝D€[[x]¥>…c7ƒ
+n`ü„,?)«I£ÅYÛÐáÚV¬ öéΩÙëxkÔ"¬$ÔBâ˄ÊiéIF•ùœU×äi2^ßhõæËýjÄ=ø iÂXcê‘%‹°¤¯N›döL%ÆÝK#!¬(ښ¾”Óçz–Š+2Þ"é=¡Ã@ÂB:JWâäÌ?ë[19X° †$["¨]#Ás—2“R}
+ê]&‘ˆÁyJ̗äÎBS=¤¨j’
+vu|ŠrŽ‚RÕf§niS¥X:0‰Ž¡};*Þý
+H}¶p‡$$vGóšÛ"ƒŒ£àJÔÆÄ&×£Æ_D3™…ÕŒ¹&ÈãÄ
+@v}PLñS&ý*£¥2Ö”GÞÝ-j¸õ¢‘&`¶Üïʬƒ²m‹þ%)¨£
+Ú•8Ot0-5ºb™Ù./b7nœté13Úx.+&¤‰ÇEÇ£¢
+¡ÖUNŒìä`¢ßÏÌ*F«øÚ a±|!â*x’˜T¾ïï˩ƀwzR¬ì ~Ó© 9÷e`yZLyÉfo˜ÛZ4o#
+×6£¹ßäq„ý[U{†h*=Œ*aû˶)TDY>Æ!y$ž_>ÒÀ"›bf’º!h6m@8ðÎôè|'«Ox¢wí9*çˆÉã%ÃFÓG*£uÁ–_dä9¹_—ƒ¤Ëà`ï¢5á‚SbQúa¸_™1òÔÆD~þÛ4qÈÿ³Xݏ.;!ò+ ³füÂ]Vo ©# …5Ó?Ðõ.Û^˜G´ÕO`oÈ^§lçã5¼ý1à¸ñ‹§FêÉÓHFq^Aÿm¼‘DÂå̑8híæÑ®/ºuµ
+ڞväùÔ ësZ,G‡EÚtÛtêQûD\Õ'KŠö#ªìwr™¶¡¤ÏüFòCZÝ4óà`¡æÓæ
+\ä‡õüóœw`±Þþ}Â[SƈëHWPée¡aB‚(–»gÝ7³q~W!c;Ȝ7SL1ùÈ+5)°ùŽ¢EîJWèýؙ4ñ•P|×£noXS‹@ƒÙ;¹§~ XaP“" ђ<‰†”Eԗߪ¥÷+ÔªšœìrªˆMÇŌ­s<3éOð²¼ڄn—¸/%Í\R*M$ñ+‡ÉmÇ]³³ü*r®Š‘êAكÀRÔ&;bs±’!éƔ`ì¹ÙàKV(óMÅNʽMÜÃÀœeìø>›üؐ´Th ó,gzíÇ¿ZÙû—7vÒt?÷\¶È 3”RW –ŠŸIΔ‚Ði˺}=ÌFƟ¾‹4£Ýò:N³¤µòóM2«Å äݶ™”´¤ ꝏsåvþÔ;J±ò$õûÜþxBqJ{©¾âÀuØoÐóúnЏ Ž ŠåÐ7¸Ú[ Yâ“Ö-]ºµÑ©%A*'-­Ê4¸Ó†¼jgŽüHD100îX“Îæû¹¼o«D7c•]‡-áöðõÎÎʲ|äKš¨ŠN]ž@¾›¤—t°—˜cˆë䙹™ÔÖ)¢~ǾïÍ5ùÇ\ZB<ܗÑ=SXW±12×ì׎GÄLŽ€j.Gþ Ê&|*‡§‘ÑÄôߢ±rŸ•zE\ÁgnÔ[ˆñHé=^SßêÐ:‘.g¹ÎݘI
+GYc×pµæ\¶”,~:ÖUó‰Ž?´@FT4w‘££|kq¦h4ÕJ ê
+þx7)Å̀úœKpIî¾ÃQ·laR!iÓÞ?AÕ(UõV
+à›uìJ!D¡øÄ]<æ䣐:Úý¼ˆã•Ïõûe®h_é®!^´±s5nb)q±ËÍiEï¦|¾1µä²Óµ 8â€tœËdÅÑ 6 TôËÐE¡ü¦ÖPÈ1Ŝ«J:Ѭ‚s‘˶a-ò3ßYÅ"Í]Ø
+–:•Åâðc¥Fœ¹•*vøCõF(:«ìåœË^§ÀÓºªÑ–£ÉˆÀ Æ?à7­¬VŒÈÏ¿¯
+ÆLGÞh¨µøbTÙ@V‘|üX ƒW­lâ ü2E¹Á°UFaA@KeðÁ+êBK”©Ciš™™+iÆÙ9>KdÐ5žHuèÒZºü,ï²ÀÙß&³~%çM‹l_+뤜Ž.ŒŽ™”÷Qä¸aïû™“%ëEž-1Ð\Pºd“ônÆ:CŸ]òž~
+)UI#âW¾,Vhí£…ÙÚÀ‚4]㥤5¢®ÊÔ­~¼ L`ÓÚó¦æi±nÔIe1@–BY'XÌwJ¢/*ÏD_*XŠ„´¬Q—‚ Œ=ÕìýšÃô÷|_¸c¨ œ¡Êe»ô‚©¥NXæôðd“¨oÃÜÜÀpÊ
+A©q¢³Z·]–Ó,x=Z¥…a%3#žg¤»%h{èæ-Á/<e [¨#ihâÒ³E@œ´t?›àJÍKdx)€Ç0‰ôõ­Å6:†:Oî°LiIšìèT³Ý‚–¿°:† 1[®Ó|ÌI§aÅXǂ¡ÿ!±>À‹²É8¶] “6ôÕzáBýÿÚ+§µJ@f[ÓζmÛíÚM¶íš0Ù6'M¶íšlÛ¶ó¿Ã¹;ßY°îÖ·Ž§@t7ýrQávmõÆÙ0¢Mg³GRÁþá~Œ"ºWíÖxòx*žË[ßn©¤œrI֎FôlʏWYÚ$Þꋩœ”¶Ø~ ðýÃÀWÁp•Ç=ªRޅßEÂz“^fUÃ)(ç*ÿeóF/çe‡áDó&`×QM§f [ÍÜ@ƒL[÷*ÆÁqY<G‚°1t5X}âF7=¿d$FÿùZPÎÏ®«LÓû©4^R4+Õ<s\ž\ØÜ$´¬¨£¡/Eøi.·¸•‹¸…Os±¢©yÈåH†NŠÿï)j²€šÉ˜nxj?3ÃyR¾vՋƒ¥¨ÛÙ ¬=_Dz¸Z¹Ž€É_°c:Ð7¬÷1·)THßþÕ¸¬k7°îo
+þ扃GՅÒ¥¬çW]÷nˆ,€½}©gÞy
+ç¿ærp’v–€A®)Iç·O0ÒNgœÀ7ß(ªÀ¼ñ¤VZÆl•b½½‰Ÿ²S±…父ŠÚ–z[%$ȯd³Û×/®)%FzúÅ+i¡è˜Á)2Kã Ác­aÀnÍ*ü@f‡ïÄ:ð-dPÊ9ߘ*”CŽmÙ³ã‚ý¡:[»ÝÈd2êØþ\¶âÌ9`¶Ø"”ý¡Á›/hp}rÈøé„q®oZÚ%†ÉzrÁžÒÑdGÉSb€ŒÈmxR06^Cd‹=è5›®Xži´5·»e̤/«r ]Ðe¢ŽAR_r®ç
+êFnè$ʲ#ö‚ò¹G;“À[Eþ܂uÝá7óEå®R™/°)»¶W{ÓÝ«É|Ùüb¬ÛìPYÓÂtY_印m¨+ûÎPʙͿ¢?Óº&\†è–À£wÄ5Y*ª·÷ðU?xû\u¡S\bD³…$›UL
+­XÏoŠS!‚;b\hjqS{èv’ï`#1[Þò/åèöû«ìIÂ^Ï
+w@yÊèíÍ'¤»™º0ÍíÌ-ò "á~(T 93¬QuÀqUÎr»lšU÷òÉýI˜BLDÍVvtH¹ÝÝß$ͨX¹2sº-Ÿè¬ÌÂ1íòœTÓ½,ø.Ü»"æó ªýþ‡<¶˜D„@™ 
+6…‹›T¿“v¹ì¼Hn}6ɹu¢ëCzoGÃ{ã¶M/I–f`R0‘wŠ¸kôwk+.Aº††(†ì›=V£J¦ QUŸù$Uï¤å{)šÞ°Gæë×9?ì¡*DdtÑ8?²Dd…òN¨uèn×äËÆI†´ºfLRMÊýô5„ C"u1µ!%šÝuåª;ߍ†±Ý‡ãå4s'Nç,¿TT­G(Z]a¾/±q¸³iÙ»ïÐۂK¢g–®O>M5^3øXË!`Ÿµa;p‘nÆgÚøÖEMË<X³ ë!ÚXH»¦ª\{•…{ýOhæ.GGw1³b/Ⱥ÷NP`{¾˜¹Œ±–i¤ÛEÝÜ~c!ˆ¶™,5 cªDMì—J¹cٜßcõ-”?fÈ Ão‡óº/>k* ¾ ¼lNægÁ
+QTòÚ?ôùQ,£³ï¥¶"0ZšFt™¤½J
+MplXOòd飌M‘Í 3÷e©¾j³,oœ´¬s9Ñ&µJy½%ç á!|Ņ]hZhó ZzØÄö}ñ|C28Æδˆz:sKVø…FѼ2AԜÄ=ÛÇ?þBU»=Õ{üDӑù¦„Âöo¤aJ<ÊSÉz¬E'»à‹j›7(\>þ T¶¿J‘¨ä–ØTŽÅ®
+üqÍœ·Ô‡®ßó?¯JMûᖚ
+Fñ<H5ÓËE¨Î¾RÊ©c]S@óÒ:lÌ©cêÝüØpëâ—ý6¸ï×"¯|+ÈÝ̯±7¹Êî^ö,÷
+Šæú­§Øٟvås¢JaIé–ßúlJ†ã6@zd&Që³Á˜ò\Ÿ?eŸ¼|Ç*+Ù¤O©*¿½&(„jg¡CìɊ¾%~'˜(]ΙZ-ÆJ;Ø؟Ê­e]QË` Åæ….b¢ bD/¸òÚnéÇIW:"†Œ)üº-á»ïíÿ´¹µ×4ÍàÉ-„ƒ²³}2ýÔ!iògÞ©oeÍDE @•aþ½ÜÿØ<nøës¨`~™‹6GqsÙ7ç¬öÏ8‚õÇ`8ÔL6+éq#94Ð.±Ëgú½CáXoq«E<
+ÀRÚªu1þà‡Q”¡ÁB¯Ej`
+’ŕ$Y(‰Ué‡'Féד„ä+Z¢šóÕþtY1y}ÖqA´xFØhEa^a“?­§æc¼ËšMÏÛaSåàއ(¨Íd"¹–}ý”ʇX)U}ì™<˜éÕÿªÿ>3ÁaÀ–ÈôËetH,m_€tœÿ`;›i5b>lÖ@ñ¤ô«·²ç±“Vð]ëic†z˜~ˆÓ®$ˆ-4D¯)ˆó©ÇuÈ<¸û’Þ‚¢uåf}Ýa÷/ðwAT oC§ÎæÖ§»™n<šP™86F%[”å#“«LUJ‡¸Z=ÓÒÁ?“ØÒʽn‰;ø¢÷m.ŠǤ7Pcám¿dºˆZWû—‡„õ³koÌÒ ~ùKæQ |7DÍË°·§Kö«rÈ2Íç‡Æ]<¢G%JpT>B~þZ>4~˜ŠD®sçmn?ae¥2¿uaÁ=Yf…2ß¶"¦ÔnUtÊì°;8Ǩ÷ӛC\hu
+OºN7f1Î<úómöBÎí¯FåarGō–‚à-–uMòu(sjœë9w­^~Žcq6ñ ĘÈû6*k¾—êގæU«~ö0²tÆsmÆg ÒxĖÌñ¤”™ó¤ò²A†Ü‰ÉèT¿¿”Âc?²Ö …›xÊ縕åÁ”“• E\¤~äMŒñ6$—{î!×Á
+¾,1‹mK<ˆækLñ”›è–’Gš3Yéêݲ֋2r›9dð‘hY§qº¿º—{ùß0=ÖÌ9iâebÔîô¼><Ê-éÅbšÒJÚó°¡Ð߈ zâG†n6µnÆu$ü[‰~(ìÒ÷Üp¿3Þ=ÞäCm”vÛñ}ƽ㙈e‘ÊϘÂÿ‡Pét…óÓjÖ.W¿^ ¹5)ð׫išË\‚?ôZbc¯Ù­<º#çր;”wÚZÑQQRÜ^ÕÆ74ú«ü0ŽtAq±‘ˆ–BRþ¹FfÊÜ›+Q¥WN26³é_ü¤ª#Ù¦—hÅÎyãX‚òýV=]µÃ±¨«øÚxäÕ®2Åå¯ì梼7nypÔÇ"8ÿÕʳž#uÉÖìv¸auF1eü³lp‰ØÖmQʶ
+þ,C[{§Ø´°ÙR¥Wû8ç¤^滸« ‘m(xuøó¯®;õð°l2ŽAðï›Ü¤9žÈü%v ±SŠgs,½ýKã¥÷ 
+·Buꗱ}(Æ,½yr')AH1\œÃôbeÐ{7ËwƼÃ#6k½–K]ޑ8W…»·g›$aòk€í7T .ѕ¡7J<ñ:¾ùÚS&ÚäÌyÝ6–í­t ‰•t1·Àdæ @ðŒGϑîæiSǟC‘9qªˆŸ^vÃnTÿ€| •·ÕÖ¬¿0æ
+Qžçuú¶˜æ0Æøl 9Ãõ|k¨¯>Sѽ-`NmMš…¢ÈjL#Èm"=ÏOBõyùߏòu·×Œ}Ú­i"¾}vXÔRÿ‚´?²”5ޙŠëßN›§ž*B-Yb'ÑD&dá1KÃC+Fí¼0w˜N8.± tÆL«Éͬó4ÄÀj•]0†ìΘ@z@.{
+°þ¦ª-_”þ4Ê"_Þv·|«üÝ0jkæÏ-›ƒ‚ÊR­ ßØ؏0õÏôØȽz?œÎ;xvZD¨‚ܱ¨ÜBÎò5¯ŽJp+UE:q¢cÌNoܝæáލ,0NR•h¿j/ZÜBÕyQ‡À„úöи9¡IûkX’|~;¿Óˆþˆ™Ÿ;ÐÞØk·Ó¡nd#‹žq+QR4"ȁ×
+CÑiú5…ÏÙÍ¿pAÎðÁÐv0ƒåÀEqâEn.´¢MK]
+£ƒJÿN.´`ºÄ35ËNx)0g×åI¦»Œ—¥«ã•íð‚‰qa¥ûÀv¢²(û$À:ÚÊ×9;ÓÁG”ÀË9Þ.¤ÑHۥ䂆úú(¦°vÝÚ~‘÷<†–ªZà¢ïŠ͍ðrRÏ «1„ný–q¨—8OkW¤WðTõ¿ù½¥ß´­m‹=eyî\¨ÝºYV"Š[g^dPi‚¯#†½çýÕø ÌoPðæn´b°®q§6Uìׁtï·à𙿔‹^gíí¼lZÊÏ ÃýÑ©­µìùñ[EŸµV‰ØÂФ´—¹¦c$µÁ:Ì!wš7G4ý>RÁœZƺÔî֚[½ß ;l-{˜OiM&_\À9™MÉ_ªX9çp
+—)¶„Ú}ÿàDZÁ ¾®DÔÄ@2°–_ԙnŠq†ãď»ðn°ÈHBµg~s) ÏdqÈza–‡ þb™lµâynµì‘°ñ·±Ù_Ê¡0u9Ý6‡žÎ<QRl~r‘¹=/£7EèŠ7X†ðᏉ­ÎÚûÍá…”8μ0»
+HË>/&ohHœÛÁ:=…gn@KÝwÛ)4¹W&3冘>i?…ɶ¦¶ hÀ•!õr ÝõÅ=E0õdT3ÝÏñíÈ)fÛ‡õBQŽQó@æ¯<¡Ì…Yc¦ø]§`MÔ~Ï“d"Ãu”¿f¢;•(4«‚l¾Z´Å¨E‰¼Ð¯§„š…êÅi™Î/í'…tR¶]-Ö¢(¾ WOùñûö53žàYt¦„×b¯cñÅþëEwn2ì[±‹"CìëðF‘ÚS˓"5`8Ñ2¿Ê¯e̅Ás,k²ý®îËáÑHÅ¢i3¨6<§Éúc¢3LsBª«@S E‡ðÔ¬5%­è“jj¢²æ¿(ëóžó"%RŠÐ÷ÂÑ·„:äÔ °ßóç}C_J¯£Jz—öÅw1âGè°f‰œÿñ&Ã%ãƒõþ~MJ¡ÏÐ#æÎ4WÏQ[$^§Ê çƒ3J=fC=Z€Þ™<϶ð÷Æl}*°-7šHw7‹ÄwØ2³^ÿN\ïu5Ú/B^,¦ƒWC?+¡w˜1¸’D#‡ýqèÏeÀêdø½-ßmDJØ××v3<Óú"&s“µª¹Mùðc‚ ë8í®v ìC 6?uô«ïY³eiñ4s}+×sÔ|ûý:®™ ƒsŸ8`¦«_Cž/ÎèñiÑ]f"+}ó/+¬L]d°Ø{$]Všyí^óµ¢ÆÜ[<Òe  _ö&M@äÚRXR)S-Š
+Ü{rÐî
+V`àâ’×ÂæSŽ\öæ)á†àí)ÿ‡˜ÖINIÍØ·ˆJi'|öíìò¢ù&¿«q¸¢ëûÀ±
+0Ü ZFïWn ôð¸š}·Å϶zj™rC`á›EølNbeilº$ö)!ÖøÔ¿F@‰5©
+6V‹žÖ ¸à(äɅy+bJ¤‚ôÚ;:™p¸—ÔYô…Dl„*žÍæ¥Z‹7NEÝB½‡ªÁÁÞ«Óg¸„]2?›õuùҙ¥£Äݖè9-œ{(G%ÖTÊàµF.f¼ú"Ô*—ÿ¤!Î/nzîrÀ™¹ +Cäö…S5ó²
+~ˆƒsJ”U‰RävZ€´Jyñ‘G5iÂ?rîÈäÌ
+óψí!Ƈ;Eù°Â k"œ@Ü£çÓA»¤¥óÚTÞ¿g»¸9·©n…vÂRÃþ(Éc3¥ŒA>òá"'ÐÎU0K@YL–™õØPùc¢^ÔÒðõ«Ù¬ÄhœxOÏSi€Kz‹ÒFqRSåøߕâC=›p
+‰ö]ëH÷0ü)àD,ø{Û­ÚdâCläôÖ*Êðã¦ÞP‰CX–°¯}뵓k៿$+b¾µ—‚Ç)¯Yá{.Åç·ö(Š×G‰Ì{õ⦺—€3zïß·H{Bž=Ɲ»·#UAŽGĶ*fçù泔Òå
+QÐ{e%ËR'ö¹]¨Ä!Z3ÈäŠåiPrFmÎì]_×¥z‹G«Ñ%"T]œ \#¾£ÜË÷ýJèÐ)™ ª.ÁŠ
+žÁ¡ڋI/âÁéèV›q"«§ gÏçè‰3 "ø %Û|œqFižtÔ1þB®6wÃÈ´Ö)Si—“Õµ `RQ“ƒKÝnHu5"6Ÿ ¨9\ÉlQ¡›æA&{ëÁc)rõ2ŸËêv_SžJrׅ±)yi~Ë×ÜòY.Me+ig#ÒÙSð»Ü–µùClgSD»ë
+,"MHÄߺ¹¤Ò·x¡P"¢:nm3Úy¬0‘ÿ,L$vŸWé'+¾²žPäõôç'‘Œ+¢O1ÙUÍ£´Þ¯Ço…AŒžêo˜g&QËm06í9­"2äÏÑ©«3á1¬aã÷ G’“ì$mhžm„¿ËÐ ­XÔ÷ýTP–•ÌmDáWš«]û4JƒBG‚0ˆÄL¶Éý÷ûøl#cH©6±
+×ØäGéº %% ê¸)ì
+m‚ç“Ó^ù!^»‡+7sù÷Ö
+Šê­ÉEí¾Qh˜€~bÝ8d6ðŒ™¼Í™»#Ðt. ÕˊÀü “,¤;ôìµÛ‹Kúg"D2µ@Ÿð5ý1#VÀ¼Ï®üG½Ù/«dÝc hÇ#”ª8ƒ¸‰qPµ¿ÎÇ&hàÕ O²Ï§G)TƒæÇÔ¿‘É
+»&côá`bH}܉­~9õí…ͬM 7H”xžñ~©¥¼÷›X“ïNkÑQ÷ß C©BOTöùÑ7&zOôÂTËC$vÜ¢^3hþçÚv
+šM•~˜!§]_>§­{³å6n2£ÎŠäÐþL$ƒ‡å Âÿ þOLl͌œ]쌜mþP£Óendstream
+endobj
+64 0 obj <<
+/Type /Font
+/Subtype /Type1
+/Encoding 143 0 R
+/FirstChar 2
+/LastChar 148
+/Widths 147 0 R
+/BaseFont /RLWFWM+URWPalladioL-Roma
+/FontDescriptor 62 0 R
+>> endobj
+62 0 obj <<
+/Ascent 715
+/CapHeight 680
+/Descent -282
+/FontName /RLWFWM+URWPalladioL-Roma
+/ItalicAngle 0
+/StemV 84
+/XHeight 469
+/FontBBox [-166 -283 1021 943]
+/Flags 4
+/CharSet (/fi/fl/exclam/numbersign/percent/ampersand/quoteright/parenleft/parenright/asterisk/comma/hyphen/period/slash/zero/one/two/three/four/five/six/seven/eight/nine/colon/semicolon/question/at/A/B/C/D/E/F/G/H/I/J/L/M/N/O/P/R/S/T/U/V/W/Y/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/quotedblleft/quotedblright)
+/FontFile 63 0 R
+>> endobj
+147 0 obj
+[605 608 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 278 0 500 0 840 778 278 333 333 389 0 250 333 250 606 500 500 500 500 500 500 500 500 500 500 250 250 0 0 0 444 747 778 611 709 774 611 556 763 832 337 333 0 611 946 831 786 604 0 668 525 613 778 722 1000 0 667 0 0 0 0 0 0 278 500 553 444 611 479 333 556 582 291 234 556 291 883 582 546 601 560 395 424 326 603 565 834 516 556 500 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 500 500 ]
+endobj
+81 0 obj <<
+/Type /Pages
+/Count 6
+/Parent 148 0 R
+/Kids [58 0 R 83 0 R 88 0 R 96 0 R 108 0 R 112 0 R]
+>> endobj
+124 0 obj <<
+/Type /Pages
+/Count 3
+/Parent 148 0 R
+/Kids [119 0 R 126 0 R 132 0 R]
+>> endobj
+148 0 obj <<
+/Type /Pages
+/Count 9
+/Kids [81 0 R 124 0 R]
+>> endobj
+149 0 obj <<
+/Type /Outlines
+/First 7 0 R
+/Last 55 0 R
+/Count 8
+>> endobj
+55 0 obj <<
+/Title 56 0 R
+/A 53 0 R
+/Parent 149 0 R
+/Prev 51 0 R
+>> endobj
+51 0 obj <<
+/Title 52 0 R
+/A 49 0 R
+/Parent 149 0 R
+/Prev 47 0 R
+/Next 55 0 R
+>> endobj
+47 0 obj <<
+/Title 48 0 R
+/A 45 0 R
+/Parent 149 0 R
+/Prev 43 0 R
+/Next 51 0 R
+>> endobj
+43 0 obj <<
+/Title 44 0 R
+/A 41 0 R
+/Parent 149 0 R
+/Prev 35 0 R
+/Next 47 0 R
+>> endobj
+39 0 obj <<
+/Title 40 0 R
+/A 37 0 R
+/Parent 35 0 R
+>> endobj
+35 0 obj <<
+/Title 36 0 R
+/A 33 0 R
+/Parent 149 0 R
+/Prev 15 0 R
+/Next 43 0 R
+/First 39 0 R
+/Last 39 0 R
+/Count -1
+>> endobj
+31 0 obj <<
+/Title 32 0 R
+/A 29 0 R
+/Parent 15 0 R
+/Prev 27 0 R
+>> endobj
+27 0 obj <<
+/Title 28 0 R
+/A 25 0 R
+/Parent 15 0 R
+/Prev 23 0 R
+/Next 31 0 R
+>> endobj
+23 0 obj <<
+/Title 24 0 R
+/A 21 0 R
+/Parent 15 0 R
+/Prev 19 0 R
+/Next 27 0 R
+>> endobj
+19 0 obj <<
+/Title 20 0 R
+/A 17 0 R
+/Parent 15 0 R
+/Next 23 0 R
+>> endobj
+15 0 obj <<
+/Title 16 0 R
+/A 13 0 R
+/Parent 149 0 R
+/Prev 11 0 R
+/Next 35 0 R
+/First 19 0 R
+/Last 31 0 R
+/Count -4
+>> endobj
+11 0 obj <<
+/Title 12 0 R
+/A 9 0 R
+/Parent 149 0 R
+/Prev 7 0 R
+/Next 15 0 R
+>> endobj
+7 0 obj <<
+/Title 8 0 R
+/A 5 0 R
+/Parent 149 0 R
+/Next 11 0 R
+>> endobj
+150 0 obj <<
+/Names [(Doc-Start) 65 0 R (Hfootnote.1) 93 0 R (Hfootnote.2) 94 0 R (page.1) 61 0 R (page.2) 85 0 R (page.3) 90 0 R (page.4) 98 0 R (page.5) 110 0 R (page.6) 114 0 R (page.7) 121 0 R (page.8) 128 0 R (page.9) 134 0 R (section*.1) 123 0 R (section*.2) 129 0 R (section*.3) 130 0 R (section.1) 6 0 R (section.2) 10 0 R (section.3) 14 0 R (section.4) 34 0 R (section.5) 42 0 R (section.6) 46 0 R (section.7) 50 0 R (section.8) 54 0 R (subsection.3.1) 18 0 R (subsection.3.2) 22 0 R (subsection.3.3) 26 0 R (subsection.3.4) 30 0 R (subsection.4.1) 38 0 R]
+/Limits [(Doc-Start) (subsection.4.1)]
+>> endobj
+151 0 obj <<
+/Kids [150 0 R]
+>> endobj
+152 0 obj <<
+/Dests 151 0 R
+>> endobj
+153 0 obj <<
+/Type /Catalog
+/Pages 148 0 R
+/Outlines 149 0 R
+/Names 152 0 R
+/PageMode /UseOutlines
+/OpenAction 57 0 R
+>> endobj
+154 0 obj <<
+/Author()/Title()/Subject()/Creator(LaTeX with hyperref package)/Producer(pdfeTeX-1.21a)/Keywords()
+/CreationDate (D:20120918213605-04'00')
+/PTEX.Fullbanner (This is pdfeTeX, Version 3.141592-1.21a-2.2 (Web2C 7.5.4) kpathsea version 3.5.4)
+>> endobj
+xref
+0 155
+0000000001 65535 f
+0000000002 00000 f
+0000000003 00000 f
+0000000004 00000 f
+0000000000 00000 f
+0000000009 00000 n
+0000003816 00000 n
+0000118888 00000 n
+0000000054 00000 n
+0000000084 00000 n
+0000003871 00000 n
+0000118802 00000 n
+0000000129 00000 n
+0000000166 00000 n
+0000006981 00000 n
+0000118677 00000 n
+0000000212 00000 n
+0000000239 00000 n
+0000007037 00000 n
+0000118603 00000 n
+0000000290 00000 n
+0000000324 00000 n
+0000007093 00000 n
+0000118516 00000 n
+0000000375 00000 n
+0000000408 00000 n
+0000010537 00000 n
+0000118429 00000 n
+0000000459 00000 n
+0000000509 00000 n
+0000010592 00000 n
+0000118355 00000 n
+0000000560 00000 n
+0000000604 00000 n
+0000014884 00000 n
+0000118230 00000 n
+0000000650 00000 n
+0000000679 00000 n
+0000017123 00000 n
+0000118169 00000 n
+0000000730 00000 n
+0000000758 00000 n
+0000017180 00000 n
+0000118081 00000 n
+0000000804 00000 n
+0000000830 00000 n
+0000019730 00000 n
+0000117993 00000 n
+0000000876 00000 n
+0000000903 00000 n
+0000022930 00000 n
+0000117905 00000 n
+0000000949 00000 n
+0000000978 00000 n
+0000022987 00000 n
+0000117830 00000 n
+0000001024 00000 n
+0000001050 00000 n
+0000003601 00000 n
+0000003927 00000 n
+0000001100 00000 n
+0000003709 00000 n
+0000116484 00000 n
+0000091497 00000 n
+0000116314 00000 n
+0000003765 00000 n
+0000090881 00000 n
+0000071889 00000 n
+0000090710 00000 n
+0000071308 00000 n
+0000057227 00000 n
+0000071137 00000 n
+0000056351 00000 n
+0000039512 00000 n
+0000056182 00000 n
+0000037053 00000 n
+0000033756 00000 n
+0000036894 00000 n
+0000033394 00000 n
+0000031212 00000 n
+0000033237 00000 n
+0000117483 00000 n
+0000007149 00000 n
+0000006645 00000 n
+0000004057 00000 n
+0000006926 00000 n
+0000006772 00000 n
+0000010769 00000 n
+0000010035 00000 n
+0000007279 00000 n
+0000010482 00000 n
+0000010169 00000 n
+0000010325 00000 n
+0000010648 00000 n
+0000010709 00000 n
+0000014940 00000 n
+0000013628 00000 n
+0000010899 00000 n
+0000014829 00000 n
+0000013787 00000 n
+0000013991 00000 n
+0000014195 00000 n
+0000014426 00000 n
+0000014649 00000 n
+0000030900 00000 n
+0000029028 00000 n
+0000030738 00000 n
+0000017237 00000 n
+0000016955 00000 n
+0000015083 00000 n
+0000017066 00000 n
+0000019787 00000 n
+0000019562 00000 n
+0000017368 00000 n
+0000019673 00000 n
+0000028708 00000 n
+0000027318 00000 n
+0000028547 00000 n
+0000023102 00000 n
+0000022549 00000 n
+0000019931 00000 n
+0000022873 00000 n
+0000022681 00000 n
+0000023044 00000 n
+0000117595 00000 n
+0000024900 00000 n
+0000024615 00000 n
+0000023233 00000 n
+0000024727 00000 n
+0000024784 00000 n
+0000024842 00000 n
+0000027186 00000 n
+0000027017 00000 n
+0000025031 00000 n
+0000027129 00000 n
+0000028941 00000 n
+0000028917 00000 n
+0000031124 00000 n
+0000031100 00000 n
+0000033647 00000 n
+0000033601 00000 n
+0000037429 00000 n
+0000037271 00000 n
+0000037624 00000 n
+0000056831 00000 n
+0000071619 00000 n
+0000091226 00000 n
+0000117010 00000 n
+0000117688 00000 n
+0000117756 00000 n
+0000118960 00000 n
+0000119575 00000 n
+0000119614 00000 n
+0000119652 00000 n
+0000119781 00000 n
+trailer
+<<
+/Size 155
+/Root 153 0 R
+/Info 154 0 R
+/ID [<E41AD0AB16D0E85E62780543FFA3B5F8> <E41AD0AB16D0E85E62780543FFA3B5F8>]
+>>
+startxref
+120044
+%%EOF
/Classwork/CS3214 - Computer Systems/Project 2 - Extensible Shell/esh-sys-utils.c
0,0 → 1,159
/*
* esh - the 'extensible' shell.
*
* Utility functions for system calls.
*
* Developed by Godmar Back for CS 3214 Fall 2009
* Virginia Tech.
*/
 
#include <termios.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <signal.h>
#include <assert.h>
 
#include "esh-sys-utils.h"
 
static const char rcsid [] = "$Id: esh-sys-utils.c,v 1.4 2011/01/21 20:13:06 cs3214 Exp $";
 
/* Utility function for esh_sys_fatal_error and esh_sys_error */
static void
vesh_sys_error(char *fmt, va_list ap)
{
char errmsg[1024];
 
strerror_r(errno, errmsg, sizeof errmsg);
vfprintf(stderr, fmt, ap);
fprintf(stderr, "%s\n", errmsg);
}
 
/* Print information about the last syscall error */
void
esh_sys_error(char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vesh_sys_error(fmt, ap);
va_end(ap);
}
 
/* Print information about the last syscall error and then exit */
void
esh_sys_fatal_error(char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vesh_sys_error(fmt, ap);
va_end(ap);
exit(EXIT_FAILURE);
}
 
static int terminal_fd = -1; /* the controlling terminal */
static struct termios saved_tty_state; /* the state of the terminal when shell
was started. */
 
/* Initialize tty support. Return pointer to saved initial terminal state */
struct termios *
esh_sys_tty_init(void)
{
char *tty;
assert(terminal_fd == -1 || !!!"esh_sys_tty_init already called");
 
terminal_fd = open(tty = ctermid(NULL), O_RDWR);
if (terminal_fd == -1)
esh_sys_fatal_error("opening controlling terminal %s failed: ", tty);
 
esh_sys_tty_save(&saved_tty_state);
return &saved_tty_state;
}
 
/* Save current terminal settings.
* This function is used when a job is suspended.*/
void
esh_sys_tty_save(struct termios *saved_tty_state)
{
int rc = tcgetattr(terminal_fd, saved_tty_state);
if (rc == -1)
esh_sys_fatal_error("tcgetattr failed: ");
}
 
/* Restore terminal to saved settings.
* This function is used when resuming a suspended job. */
void
esh_sys_tty_restore(struct termios *saved_tty_state)
{
int rc = tcsetattr(terminal_fd, TCSADRAIN, saved_tty_state);
if (rc == -1)
esh_sys_fatal_error("could not restore tty attributes tcsetattr: ");
}
 
/* Get a file descriptor that refers to controlling terminal */
int
esh_sys_tty_getfd(void)
{
assert(terminal_fd != -1 || !!!"esh_sys_tty_init() must be called");
return terminal_fd;
}
 
/* Return true if this signal is blocked */
bool
esh_signal_is_blocked(int sig)
{
sigset_t mask;
if (sigprocmask(0, NULL, &mask) == -1)
esh_sys_error("sigprocmask failed while retrieving current mask");
 
return sigismember(&mask, sig);
}
 
/* Helper for esh_signal_block and esh_signal_unblock */
static bool
__mask_signal(int sig, int how)
{
sigset_t mask, omask;
sigemptyset(&mask);
sigaddset(&mask, sig);
if (sigprocmask(how, &mask, &omask) != 0)
esh_sys_error("sigprocmask failed for %d/%d", sig, how);
return sigismember(&omask, sig);
}
 
/* Block a signal. Returns true it was blocked before */
bool
esh_signal_block(int sig)
{
return __mask_signal(sig, SIG_BLOCK);
}
 
/* Unblock a signal. Returns true it was blocked before */
bool
esh_signal_unblock(int sig)
{
return __mask_signal(sig, SIG_UNBLOCK);
}
 
/* Install signal handler for signal 'sig' */
void
esh_signal_sethandler(int sig, sa_sigaction_t handler)
{
sigset_t emptymask;
 
sigemptyset(&emptymask);
struct sigaction sa = {
.sa_sigaction = handler,
/* do not block any additional signals (besides 'sig') when
* signal handler is entered. */
.sa_mask = emptymask,
/* restart system calls when possible */
.sa_flags = SA_RESTART | SA_SIGINFO
};
 
if (sigaction(sig, &sa, NULL) != 0)
esh_sys_fatal_error("sigaction failed for signal %d", sig);
}
/Classwork/CS3214 - Computer Systems/Project 2 - Extensible Shell/esh-sys-utils.h
0,0 → 1,49
/*
* esh - the 'extensible' shell.
*
* Utility functions for system calls.
*
* Developed by Godmar Back for CS 3214 Fall 2009
* Virginia Tech.
*/
 
#include <stdbool.h>
#include <signal.h>
 
/* Print message to stderr, followed by information about current error.
* Use like 'printf' */
void esh_sys_error(char *fmt, ...);
void esh_sys_fatal_error(char *fmt, ...);
 
/* Get a file descriptor that refers to controlling terminal */
int esh_sys_tty_getfd(void);
 
/* Initialize tty support.
* Return pointer to static structure that saves initial state.
* Restore this state via esh_sys_tty_restore() whenever the shell
* takes back control of the terminal.
*/
struct termios * esh_sys_tty_init(void);
 
/* Save current terminal settings.
* This function is used when a job is suspended.*/
void esh_sys_tty_save(struct termios *saved_tty_state);
 
/* Restore terminal to saved settings.
* This function is used when resuming a suspended job. */
void esh_sys_tty_restore(struct termios *saved_tty_state);
 
/* Return true if this signal is blocked */
bool esh_signal_is_blocked(int sig);
 
/* Block a signal. Returns true it was blocked before */
bool esh_signal_block(int sig);
 
/* Unblock a signal. Returns true it was blocked before */
bool esh_signal_unblock(int sig);
 
/* Signal handler prototype */
typedef void (*sa_sigaction_t)(int, siginfo_t *, void *);
 
/* Install signal handler for signal 'sig' */
void esh_signal_sethandler(int sig, sa_sigaction_t handler);
/Classwork/CS3214 - Computer Systems/Project 2 - Extensible Shell/esh-utils.c
0,0 → 1,262
/*
* esh-utils.c
* A set of utility routines to manage esh objects.
*
* Developed by Godmar Back for CS 3214 Fall 2009
* Virginia Tech.
*/
#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
#include <dlfcn.h>
#include <limits.h>
 
#include "esh.h"
 
static const char rcsid [] = "$Id: esh-utils.c,v 1.5 2011/03/29 15:46:28 cs3214 Exp $";
 
/* List of loaded plugins */
struct list esh_plugin_list;
 
/* Create new command structure and initialize first command word,
* and/or input or output redirect file. */
struct esh_command *
esh_command_create(char ** argv,
char *iored_input,
char *iored_output,
bool append_to_output)
{
struct esh_command *cmd = malloc(sizeof *cmd);
 
cmd->iored_input = iored_input;
cmd->iored_output = iored_output;
cmd->argv = argv;
cmd->append_to_output = append_to_output;
 
return cmd;
}
 
/* Create a new pipeline containing only one command */
struct esh_pipeline *
esh_pipeline_create(struct esh_command *cmd)
{
struct esh_pipeline *pipe = malloc(sizeof *pipe);
 
pipe->bg_job = false;
cmd->pipeline = pipe;
list_init(&pipe->commands);
list_push_back(&pipe->commands, &cmd->elem);
return pipe;
}
 
/* Complete a pipe's setup by copying I/O redirection information */
void
esh_pipeline_finish(struct esh_pipeline *pipe)
{
if (list_size(&pipe->commands) == 0)
return;
 
struct esh_command *first;
first = list_entry(list_front(&pipe->commands), struct esh_command, elem);
pipe->iored_input = first->iored_input;
 
struct esh_command *last;
last = list_entry(list_back(&pipe->commands), struct esh_command, elem);
pipe->iored_output = last->iored_output;
pipe->append_to_output = last->append_to_output;
}
 
/* Create an empty command line */
struct esh_command_line *
esh_command_line_create_empty(void)
{
struct esh_command_line *cmdline = malloc(sizeof *cmdline);
 
list_init(&cmdline->pipes);
return cmdline;
}
 
/* Create a command line with a single pipeline */
struct esh_command_line *
esh_command_line_create(struct esh_pipeline *pipe)
{
struct esh_command_line *cmdline = esh_command_line_create_empty();
 
list_push_back(&cmdline->pipes, &pipe->elem);
return cmdline;
}
 
/* Print esh_command structure to stdout */
void
esh_command_print(struct esh_command *cmd)
{
char **p = cmd->argv;
 
printf(" Command:");
while (*p)
printf(" %s", *p++);
 
printf("\n");
 
if (cmd->iored_output)
printf(" stdout %ss to %s\n",
cmd->append_to_output ? "append" : "write",
cmd->iored_output);
 
if (cmd->iored_input)
printf(" stdin reads from %s\n", cmd->iored_input);
}
/* Print esh_pipeline structure to stdout */
void
esh_pipeline_print(struct esh_pipeline *pipe)
{
int i = 1;
struct list_elem * e = list_begin (&pipe->commands);
 
printf(" Pipeline\n");
for (; e != list_end (&pipe->commands); e = list_next (e)) {
struct esh_command *cmd = list_entry(e, struct esh_command, elem);
 
printf(" %d. ", i++);
esh_command_print(cmd);
}
 
if (pipe->bg_job)
printf(" - is a background job\n");
}
 
/* Print esh_command_line structure to stdout */
void
esh_command_line_print(struct esh_command_line *cmdline)
{
struct list_elem * e = list_begin (&cmdline->pipes);
 
printf("Command line\n");
for (; e != list_end (&cmdline->pipes); e = list_next (e)) {
struct esh_pipeline *pipe = list_entry(e, struct esh_pipeline, elem);
 
printf(" ------------- \n");
esh_pipeline_print(pipe);
}
printf("==========================================\n");
}
 
/* Deallocation functions. */
void
esh_command_line_free(struct esh_command_line *cmdline)
{
struct list_elem * e = list_begin (&cmdline->pipes);
 
for (; e != list_end (&cmdline->pipes); ) {
struct esh_pipeline *pipe = list_entry(e, struct esh_pipeline, elem);
e = list_remove(e);
esh_pipeline_free(pipe);
}
free(cmdline);
}
 
void
esh_pipeline_free(struct esh_pipeline *pipe)
{
struct list_elem * e = list_begin (&pipe->commands);
 
for (; e != list_end (&pipe->commands); ) {
struct esh_command *cmd = list_entry(e, struct esh_command, elem);
e = list_remove(e);
esh_command_free(cmd);
}
free(pipe);
}
 
void
esh_command_free(struct esh_command * cmd)
{
char ** p = cmd->argv;
while (*p) {
free(*p++);
}
if (cmd->iored_input)
free(cmd->iored_input);
if (cmd->iored_output)
free(cmd->iored_output);
free(cmd->argv);
free(cmd);
}
 
#define PSH_MODULE_NAME "esh_module"
 
/* Load a plugin referred to by modname */
static struct esh_plugin *
load_plugin(char *modname)
{
printf("Loading %s ...", modname);
fflush(stdout);
 
void *handle = dlopen(modname, RTLD_LAZY);
if (handle == NULL) {
fprintf(stderr, "Could not open %s: %s\n", modname, dlerror());
return NULL;
}
 
struct esh_plugin * p = dlsym(handle, PSH_MODULE_NAME);
if (p == NULL) {
fprintf(stderr, "%s does not define %s\n", modname, PSH_MODULE_NAME);
dlclose(handle);
return NULL;
}
 
printf("done.\n");
return p;
}
 
static bool sort_by_rank (const struct list_elem *a,
const struct list_elem *b,
void *aux __attribute__((unused)))
{
struct esh_plugin * pa = list_entry(a, struct esh_plugin, elem);
struct esh_plugin * pb = list_entry(b, struct esh_plugin, elem);
return pa->rank < pb->rank;
}
 
/* Load plugins from directory dirname */
void
esh_plugin_load_from_directory(char *dirname)
{
DIR * dir = opendir(dirname);
if (dir == NULL) {
perror("opendir");
return;
}
 
struct dirent * dentry;
while ((dentry = readdir(dir)) != NULL) {
if (!strstr(dentry->d_name, ".so"))
continue;
 
char modname[PATH_MAX + 1];
snprintf(modname, sizeof modname, "%s/%s", dirname, dentry->d_name);
 
struct esh_plugin * plugin = load_plugin(modname);
if (plugin)
list_push_back(&esh_plugin_list, &plugin->elem);
}
closedir(dir);
}
 
/* Initialize loaded plugins */
void
esh_plugin_initialize(struct esh_shell *shell)
{
/* Sort plugins and call init() method. */
list_sort(&esh_plugin_list, sort_by_rank, NULL);
 
struct list_elem * e = list_begin(&esh_plugin_list);
for (; e != list_end(&esh_plugin_list); e = list_next(e)) {
struct esh_plugin *plugin = list_entry(e, struct esh_plugin, elem);
if (plugin->init)
plugin->init(shell);
}
}
 
/* TBD: implement unloading. */
/Classwork/CS3214 - Computer Systems/Project 2 - Extensible Shell/esh.c
0,0 → 1,507
/*
* esh - the 'pluggable' shell.
*
* Developed by Godmar Back for CS 3214 Fall 2009
* Virginia Tech.
*/
#include <stdio.h>
#include <readline/readline.h>
#include <unistd.h>
#include <sys/wait.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
 
#include "esh.h"
#include "esh-sys-utils.h"
 
// Function declarations
static void usage(char *progname);
static char * build_prompt_from_plugins(void);
 
static struct list *get_job_list(void);
static struct esh_pipeline *job_from_jid(int jid);
static struct esh_pipeline *job_from_pgrp(pid_t pgrp);
static struct esh_command *cmd_from_pid(pid_t pid);
 
static void print_jobs(void);
static void purge_jobs(void);
static void wait_for_job(struct esh_pipeline *pipeline,bool exists_in_job_list);
static void send_signal_to_job(int jid, int sig);
static void bring_to_foreground(int jid);
static void give_terminal_to(pid_t pgrp, struct termios *pg_tty_state);
 
static void sigchld_handler(int sig, siginfo_t *info, void *_ctxt);
 
static int job_next_id = 1;
static struct termios *sys_tty;
static pid_t shell_pgrp;
 
// List of all jobs running in the current shell
static struct esh_command_line *job_list;
 
/* The shell object plugins use.
* Some methods are set to defaults. */
struct esh_shell shell = {
.get_jobs = get_job_list,
.get_job_from_jid = job_from_jid,
.get_job_from_pgrp = job_from_pgrp,
.get_cmd_from_pid = cmd_from_pid,
.build_prompt = build_prompt_from_plugins,
.readline = readline, /* GNU readline(3) */
.parse_command_line = esh_parse_command_line /* Default parser */
};
 
int main(int ac, char *av[]) {
int opt;
list_init(&esh_plugin_list);
int i = 0;
 
// Create an empty list of pipelines (jobs)
job_list = esh_command_line_create_empty();
// Obtain an empty (sane) terminal
sys_tty = esh_sys_tty_init();
// Store the process group of the shell
shell_pgrp = getpgrp();
 
/* Process command-line arguments. See getopt(3) */
while ((opt = getopt(ac, av, "hp:")) > 0) {
switch (opt) {
case 'h':
usage(av[0]);
break;
 
case 'p':
esh_plugin_load_from_directory(optarg);
break;
}
}
 
esh_plugin_initialize(&shell);
 
/* Read/eval loop. */
for (;;) {
// Ensure that the shell has access to input/output before prompting
give_terminal_to(shell_pgrp, sys_tty);
 
/* Do not output a prompt unless shell's stdin is a terminal */
char * prompt = isatty(0) ? shell.build_prompt() : NULL;
char * cmdline = shell.readline(prompt);
free (prompt);
 
if (cmdline == NULL) /* User typed EOF */
break;
 
struct esh_command_line * cline = shell.parse_command_line(cmdline);
free (cmdline);
if (cline == NULL) /* Error in command line */
continue;
 
if (list_empty(&cline->pipes)) { /* User hit enter */
esh_command_line_free(cline);
continue;
}
 
esh_signal_sethandler(SIGCHLD, sigchld_handler);
esh_signal_block(SIGCHLD);
 
// Pop each pipeline, parse it, then execute the commands
while (!list_empty(&cline->pipes)) {
struct list_elem *l = list_pop_front(&cline->pipes);
struct esh_pipeline *pipeline = list_entry(l, struct esh_pipeline, elem);
 
// Initialize some variables in the pipeline
pipeline->jid = 0;
pipeline->pgrp = 0;
memset(pipeline->cmd_string, 0, 256);
 
// Initialize array of pipes
int p_pipe_ind = 0;
int p_pipe_max = list_size(&pipeline->commands) - 1;
int **pipes = (int**) malloc(p_pipe_max*sizeof(int*));
if (pipes == NULL) esh_sys_fatal_error("malloc: ");
for (i = 0; i < p_pipe_max; i++) {
pipes[i] = (int *) malloc(2);
if (pipes[i] == NULL) esh_sys_fatal_error("malloc: ");
if (pipe(pipes[i]) == -1) esh_sys_fatal_error("pipe: ");
}
 
// Concat the command string containing the parsed commands
struct list_elem *c = list_begin(&pipeline->commands);
for (; c != list_end(&pipeline->commands); c = list_next(c)) {
struct esh_command *cmd = list_entry(c, struct esh_command, elem);
char **p = cmd->argv;
while (*p) {
strcat(pipeline->cmd_string, *p++);
if (*p)
strcat(pipeline->cmd_string, " ");
}
if (list_next(c) != list_tail(&pipeline->commands))
strcat(pipeline->cmd_string, " | ");
}
// printf("Command string: %s\n", pipeline->cmd_string);
// Get the first command
c = list_begin(&pipeline->commands);
struct esh_command *cmd = list_entry(c, struct esh_command, elem);
char **p = cmd->argv;
 
// Check if the first command is a built in command
if (strcmp(*p, "jobs") == 0) {
print_jobs();
purge_jobs();
continue;
} else if (strcmp(*p, "fg") == 0) {
bring_to_foreground(atoi(cmd->argv[1]));
continue;
} else if (strcmp(*p, "bg") == 0) {
send_signal_to_job(atoi(cmd->argv[1]), SIGCONT);
continue;
} else if (strcmp(*p, "kill") == 0) {
send_signal_to_job(atoi(cmd->argv[1]), SIGKILL);
continue;
} else if (strcmp(*p, "stop") == 0) {
send_signal_to_job(atoi(cmd->argv[1]), SIGSTOP);
continue;
} else if (strcmp(*p, "exit") == 0) {
exit(0);
}
 
// Otherwise parse and execute each command
for (; c != list_end(&pipeline->commands); c = list_next(c)) {
cmd = list_entry(c, struct esh_command, elem);
p = cmd->argv;
 
// If it is not a built in command, fork the process and let it run
if ((cmd->pid = fork()) == 0) {
// Set the group process ID to the same value for each pipeline
setpgid(0,pipeline->pgrp);
esh_signal_unblock(SIGCHLD);
if (p_pipe_max) {
// Set up the pipelines if there are more than one command
if (p_pipe_ind == 0) {
// First command
if (dup2(pipes[p_pipe_ind][1], 1) < 0)
esh_sys_fatal_error("dup2: ");
// Set stdin of the first process to the input file if it is specified
if (pipeline->iored_input) {
if (dup2(open(pipeline->iored_input, O_RDONLY), 0) < 0)
esh_sys_fatal_error("dup2: ");
}
} else if (p_pipe_ind == p_pipe_max) {
// Last command
if (dup2(pipes[p_pipe_ind-1][0], 0) < 0)
esh_sys_fatal_error("dup2: ");
// Set stdout of the final process to the output file if it is specified
if (pipeline->iored_output) {
// Check if we are creating a new file or appending to an existing file
if (pipeline->append_to_output) {
if (dup2(open(pipeline->iored_output, O_WRONLY|O_APPEND), 1) < 0)
esh_sys_fatal_error("dup2: ");
} else {
if (dup2(creat(pipeline->iored_output, 0600), 1) < 0)
esh_sys_fatal_error("dup2: ");
}
}
} else {
// All other commands in between
if (dup2(pipes[p_pipe_ind-1][0], 0) < 0)
esh_sys_fatal_error("dup2: ");
if (dup2(pipes[p_pipe_ind][1], 1) < 0)
esh_sys_fatal_error("dup2: ");
}
// Close all pipes
for (i = 0; i < p_pipe_max; i++) {
if (close(pipes[i][0]) == -1)
esh_sys_fatal_error("close: ");
if (close(pipes[i][1]) == -1)
esh_sys_fatal_error("close: ");
}
} else {
// If there is only one command, set stdin to input file if it is specified
if (pipeline->iored_input) {
if (dup2(open(pipeline->iored_input, O_RDONLY), 0) < 0)
esh_sys_fatal_error("dup2: ");
}
// Set stdout of the process to the output file if it is specified
if (pipeline->iored_output) {
// Check if we are creating a new file or appending to an existing file
if (pipeline->append_to_output) {
if (dup2(open(pipeline->iored_output, O_WRONLY|O_APPEND), 1) < 0)
esh_sys_fatal_error("dup2: ");
} else {
if (dup2(creat(pipeline->iored_output, 0600), 1) < 0)
esh_sys_fatal_error("dup2: ");
}
}
}
if (execvp(cmd->argv[0],&(cmd->argv[0])) < 0)
printf("%s: Command not found.\n",cmd->argv[0]);
return 1;
}
if (cmd->pid == -1)
esh_sys_fatal_error("fork: ");
 
// Make sure the terminal is in its own process group
if (setpgid(0,0) == -1)
esh_sys_error("setpgid: ");
 
// Store the process group ID
if (pipeline->pgrp == 0)
pipeline->pgrp = cmd->pid;
 
// Increment the pipe counter
if (p_pipe_max) {
p_pipe_ind++;
}
}
 
// Close all pipes
for (i = 0; i < p_pipe_max; i++) {
if (close(pipes[i][0]) == -1)
esh_sys_fatal_error("close: ");
if (close(pipes[i][1]) == -1)
esh_sys_fatal_error("close: ");
}
 
if (!pipeline->bg_job) {
// If the process is going to be executed in the background, give it the terminal
pipeline->status = FOREGROUND;
esh_sys_tty_save(sys_tty);
give_terminal_to(pipeline->pgrp, NULL);
wait_for_job(pipeline, false);
} else {
// Otherwise save the job in the job list and move on
pipeline->status = BACKGROUND;
// Assign the pipeline a job ID
pipeline->jid = job_next_id;
job_next_id++;
list_push_back(shell.get_jobs(),l);
printf("[%d] %d\n", pipeline->jid, pipeline->pgrp);
}
}
 
esh_signal_unblock(SIGCHLD);
esh_command_line_free(cline);
}
return 0;
}
 
static void usage(char *progname) {
printf("Usage: %s -h\n"
" -h print this help\n"
" -p plugindir directory from which to load plug-ins\n",
progname);
 
exit(EXIT_SUCCESS);
}
 
/* Build a prompt by assembling fragments from loaded plugins that
* implement 'make_prompt.'
*
* This function demonstrates how to iterate over all loaded plugins.
*/
static char * build_prompt_from_plugins(void) {
char *prompt = NULL;
struct list_elem * e = list_begin(&esh_plugin_list);
 
for (; e != list_end(&esh_plugin_list); e = list_next(e)) {
struct esh_plugin *plugin = list_entry(e, struct esh_plugin, elem);
 
if (plugin->make_prompt == NULL)
continue;
 
/* append prompt fragment created by plug-in */
char * p = plugin->make_prompt();
if (prompt == NULL) {
prompt = p;
} else {
prompt = realloc(prompt, strlen(prompt) + strlen(p) + 1);
strcat(prompt, p);
free(p);
}
}
 
/* default prompt */
if (prompt == NULL)
prompt = strdup("esh> ");
 
return prompt;
}
 
/* Shell function to return the list of jobs running in the shell */
static struct list *get_job_list(void) {
return &job_list->pipes;
}
 
/* Shell function to return a job given a job ID */
static struct esh_pipeline *job_from_jid(int jid) {
struct list_elem * p = list_begin (get_job_list());
for (; p != list_end (get_job_list()); p = list_next (p)) {
struct esh_pipeline *pipe = list_entry(p, struct esh_pipeline, elem);
if (pipe->jid == jid)
return pipe;
}
return NULL;
}
 
/* Shell function to return a job given a process group */
static struct esh_pipeline *job_from_pgrp(pid_t pgrp) {
struct list_elem * p = list_begin (get_job_list());
for (; p != list_end (get_job_list()); p = list_next (p)) {
struct esh_pipeline *pipe = list_entry(p, struct esh_pipeline, elem);
if (pipe->pgrp == pgrp)
return pipe;
}
return NULL;
}
 
/* Shell function to return a command given a PID */
static struct esh_command *cmd_from_pid(pid_t pid) {
struct list_elem * p = list_begin (get_job_list());
for (; p != list_end (get_job_list()); p = list_next (p)) {
struct esh_pipeline *pipe = list_entry(p, struct esh_pipeline, elem);
struct list_elem *c = list_begin(&pipe->commands);
for (; c != list_end(&pipe->commands); c = list_next(c)) {
struct esh_command *cmd = list_entry(c, struct esh_command, elem);
if (cmd->pid == pid)
return cmd;
}
}
return NULL;
}
 
/* Prints out the current list of jobs in the shell and their statuses */
static void print_jobs(void) {
struct list_elem * p = list_begin (shell.get_jobs());
for (; p != list_end (shell.get_jobs()); p = list_next (p)) {
struct esh_pipeline *pipe = list_entry(p, struct esh_pipeline, elem);
 
// For each job, print out [JobID] Status (Command String)
printf("[%d] ", pipe->jid);
if (pipe->status == FOREGROUND || pipe->status == BACKGROUND)
printf("Running ");
else if (pipe->status == COMPLETED)
printf("Done ");
else if (pipe->status == TERMINATED)
printf("Terminated ");
else if (pipe->status == STOPPED)
printf("Stopped ");
else
printf("Unknown State ");
 
printf("(%s)\n", pipe->cmd_string);
}
}
 
/* Removes completed or terminated jobs from the job list */
static void purge_jobs(void) {
struct list_elem * p = list_begin (shell.get_jobs());
for (; p != list_end (shell.get_jobs()); p = list_next (p)) {
struct esh_pipeline *pipe = list_entry(p, struct esh_pipeline, elem);
if (pipe->status == COMPLETED || pipe->status == TERMINATED) {
list_remove(p);
}
}
// Also reset the job ID if the job list is empty
if (list_empty(shell.get_jobs())) {
job_next_id = 1;
}
}
 
/* Waits for the specified job to finish */
static void wait_for_job(struct esh_pipeline *pipeline, bool exists_in_job_list) {
assert(esh_signal_is_blocked(SIGCHLD));
 
// Loop till all commands in the pipeline is done executing
while (pipeline->status == FOREGROUND && !list_empty(&pipeline->commands)) {
int status;
 
// Wait till a child process exits
pid_t child = waitpid(-1, &status, WUNTRACED);
if (child != -1) {
// If child has exited or terminated, remove the child from the pipeline
if (WIFEXITED(status) || WIFSIGNALED(status)) {
struct list_elem * e = list_begin (&pipeline->commands);
for (; e != list_end (&pipeline->commands); e = list_next (e)) {
struct esh_command *cmd = list_entry(e, struct esh_command, elem);
if (child == cmd->pid)
list_remove(e);
}
}
// If child was stopped (INTPSTP), put it in the job list and print out status
if (WIFSTOPPED(status)) {
pipeline->status = STOPPED;
if (pipeline->jid == 0) {
pipeline->jid = job_next_id;
job_next_id++;
}
if (!exists_in_job_list)
list_push_back(shell.get_jobs(), &pipeline->elem);
printf("\n[%d] Stopped (%s)\n", pipeline->jid, pipeline->cmd_string);
return;
}
}
}
pipeline->status = COMPLETED;
}
 
/* Sends the specified signal to the specified job ID */
static void send_signal_to_job(int jid, int sig) {
struct esh_pipeline *pipe = job_from_jid(jid);
if (killpg(pipe->pgrp, sig) == -1)
esh_sys_fatal_error("killpg: ");
}
 
/* Brings a job to the foreground */
static void bring_to_foreground(int jid) {
struct esh_pipeline *pipe = job_from_jid(jid);
printf("%s\r\n", pipe->cmd_string);
pipe->status = FOREGROUND;
 
// Give the foreground process the terminal
give_terminal_to(pipe->pgrp, NULL);
// Resume the process
send_signal_to_job(jid, SIGCONT);
// Wait for process to finish
wait_for_job(pipe, true);
}
 
/* Gives the terminal to the specified process group */
static void give_terminal_to(pid_t pgrp, struct termios *pg_tty_state) {
esh_signal_block(SIGTTOU);
// printf("Terminal to process group %d\n", pgrp);
int rc = tcsetpgrp(esh_sys_tty_getfd(), pgrp);
if (rc == -1)
esh_sys_fatal_error("tcsetpgrp: ");
 
if (pg_tty_state)
esh_sys_tty_restore(pg_tty_state);
esh_signal_unblock(SIGTTOU);
}
 
/* Handler for SIGCHLD */
static void sigchld_handler(int sig, siginfo_t *info, void *_ctxt) {
pid_t child;
int status;
 
assert(sig == SIGCHLD);
 
while ((child = waitpid(-1, &status, WUNTRACED|WNOHANG|WCONTINUED)) > 0) {
// printf("Received signal %d from process %d\n",sig, child);
struct esh_command *cmd = shell.get_cmd_from_pid(child);
// Check the status of the child and update status accordingly
if (WIFEXITED(status)) {
cmd->pipeline->status = COMPLETED;
} else if (WIFSIGNALED(status)) {
cmd->pipeline->status = TERMINATED;
} else if (WIFCONTINUED(status)) {
cmd->pipeline->status = BACKGROUND;
} else if (WIFSTOPPED(status)) {
cmd->pipeline->status = STOPPED;
}
}
}
/Classwork/CS3214 - Computer Systems/Project 2 - Extensible Shell/esh.h
0,0 → 1,207
/*
* esh - the 'extensible' shell.
*
* Developed by Godmar Back for CS 3214 Fall 2009
* Virginia Tech.
*
* $Id: esh.h,v 1.4 2011/03/29 15:46:28 cs3214 Exp $
*/
 
#include <stdbool.h>
#include <obstack.h>
#include <stdlib.h>
#include <termios.h>
#include "list.h"
 
/* Forward declarations. */
struct esh_command;
struct esh_pipeline;
struct esh_command_line;
 
/*
* A esh_shell object allows plugins to access services and information.
* The shell object should support the following operations.
*/
struct esh_shell {
 
/* Return the list of current jobs */
struct list/* <esh_pipeline> */ * (* get_jobs) (void);
 
/* Return job corresponding to jid */
struct esh_pipeline * (* get_job_from_jid)(int jid);
 
/* Return job corresponding to pgrp */
struct esh_pipeline * (* get_job_from_pgrp)(pid_t pgrp);
 
/* Return process corresponding to pid */
struct esh_command * (* get_cmd_from_pid)(pid_t pid);
 
/* Build a prompt. Memory must be malloc'd */
char * (* build_prompt) (void);
 
/* Read an input line */
char * (* readline) (const char *prompt);
 
/* Parse command line */
struct esh_command_line * (* parse_command_line) (char *);
};
 
/*
* Modules must define a esh_plugin instance named 'esh_module.'
* Each of the following members is optional.
* esh will call its 'init' functions upon successful load.
*
* For binary compatibility, do not change the order of these fields.
*/
struct esh_plugin {
struct list_elem elem; /* Link element */
 
/* an integer number denoting the relative rank of the plugin
* Plugins are notified of events in increasing rank. */
int rank;
 
/* Initialize plugin and pass shell object */
bool (* init)(struct esh_shell *);
 
/* The return value of the following three functions indicates
* whether the plugin wants processing to stop.
* true - indicates processing should stop.
* false - indicates processing should continue.
*/
/* The command line the user entered.
* A plugin may change it. */
bool (* process_raw_cmdline)(char **);
 
/* A given pipeline of commands
* A plugin may change it. */
bool (* process_pipeline)(struct esh_pipeline *);
 
/* If the command is a built-in provided by a plugin, execute the
* command and return true. */
bool (* process_builtin)(struct esh_command *);
 
/* Manufacture part of a prompt. Memory must be allocated via malloc().
* If no plugin implements this, the shell will provide a default prompt. */
char * (* make_prompt)(void);
 
/* The process or processes that are part of a new pipeline
* have been forked.
* The jid and pgid fields of the pipeline and the pid fields
* of all commands in the pipeline are set.
* SIGCHLD is blocked.
*/
void (* pipeline_forked)(struct esh_pipeline *);
 
/* Notify the plugin about a child's status change.
* 'waitstatus' is the value returned by waitpid(2)
*
* May be called from SIGCHLD handler.
* The status of the associated pipeline has not yet been
* updated.
* */
bool (* command_status_change)(struct esh_command *, int waitstatus);
 
/* Add additional fields here if needed. */
};
 
/* A command line may contain multiple pipelines. */
struct esh_command_line {
struct list/* <esh_pipeline> */ pipes; /* List of pipelines */
 
/* Add additional fields here if needed. */
};
 
enum job_status {
FOREGROUND, /* job is running in foreground. Only one job can be
in the foreground state. */
BACKGROUND, /* job is running in background */
STOPPED, /* job is stopped via SIGSTOP */
NEEDSTERMINAL, /* job is stopped because it was a background job
and requires exclusive terminal access */
COMPLETED,
TERMINATED,
};
 
/* A pipeline is a list of one or more commands.
* For the purposes of job control, a pipeline forms one job.
*/
struct esh_pipeline {
struct list/* <esh_command> */ commands; /* List of commands */
char *iored_input; /* If non-NULL, first command should read from
file 'iored_input' */
char *iored_output; /* If non-NULL, last command should write to
file 'iored_output' */
bool append_to_output; /* True if user typed >> to append */
bool bg_job; /* True if user entered & */
struct list_elem elem; /* Link element. */
 
int jid; /* Job id. */
pid_t pgrp; /* Process group. */
enum job_status status; /* Job status. */
struct termios saved_tty_state; /* The state of the terminal when this job was
stopped after having been in foreground */
 
/* Add additional fields here if needed. */
char cmd_string[256]; /* Command string */
};
 
/* A command is part of a pipeline. */
struct esh_command {
char **argv; /* NULL terminated array of pointers to words
making up this command. */
char *iored_input; /* If non-NULL, command should read from
file 'iored_input' */
char *iored_output; /* If non-NULL, command should write to
file 'iored_output' */
bool append_to_output; /* True if user typed >> to append */
struct list_elem elem; /* Link element to link commands in pipeline. */
 
pid_t pid; /* Process id. */
struct esh_pipeline * pipeline;
/* The pipeline of which this job is a part. */
 
/* Add additional fields here if needed. */
};
 
/** ----------------------------------------------------------- */
 
/* Create new command structure and initialize it */
struct esh_command * esh_command_create(char ** argv,
char *iored_input,
char *iored_output,
bool append_to_output);
 
/* Create a new pipeline containing only one command */
struct esh_pipeline * esh_pipeline_create(struct esh_command *cmd);
 
/* Complete a pipe's setup by copying I/O redirection information
* from first and last command */
void esh_pipeline_finish(struct esh_pipeline *pipe);
 
/* Create an empty command line */
struct esh_command_line * esh_command_line_create_empty(void);
 
/* Create a command line with a single pipeline */
struct esh_command_line * esh_command_line_create(struct esh_pipeline *pipe);
 
/* Deallocation functions */
void esh_command_line_free(struct esh_command_line *);
void esh_pipeline_free(struct esh_pipeline *);
void esh_command_free(struct esh_command *);
 
/* Print functions */
void esh_command_print(struct esh_command *cmd);
void esh_pipeline_print(struct esh_pipeline *pipe);
void esh_command_line_print(struct esh_command_line *line);
 
/* Parse a command line. Implemented in esh-grammar.y */
struct esh_command_line * esh_parse_command_line(char * line);
 
/* Load plugins from directory dir */
void esh_plugin_load_from_directory(char *dirname);
 
/* Initialize loaded plugins */
void esh_plugin_initialize(struct esh_shell *shell);
 
/* List of loaded plugins */
extern struct list esh_plugin_list;
/Classwork/CS3214 - Computer Systems/Project 2 - Extensible Shell/eshoutput.py
0,0 → 1,48
#!/usr/bin/python
 
#
# This file contains definitions that describe the output of your esh.
#
# You may adapt all settings in this file to match the output of your
# shell. (Alternatively, you may write your shell to match these templates.)
#
 
# the shell executable.
shell = "./esh"
 
# the prompt printed by your shell
prompt = "esh>"
 
#
# a regexp matching the message printed when a job is sent into the background
# must capture (jobid, processid)
#
bgjob_regex = "\[(\d+)\] (\d+)"
 
#
# a regexp matching a job status when printed using the 'jobs' command
# must capture (jobid, jobstatus, commandline)
#
job_status_regex = "\[(\d+)\].?\s+(\S+)\s+\((.+?)\)\r\n"
 
#
# job status messages
#
jobs_status_msg = {
'stopped' : "Stopped",
'running' : "Running"
}
 
#
# builtin commands
#
# Use printf-style formats. stop, kill, fg, and bg expect job ids.
# If your shell requires a % before the jobid, use %%%s.
#
builtin_commands = {
'jobs' : 'jobs',
'stop' : 'stop %s',
'kill' : 'kill %s',
'fg' : 'fg %s',
'bg' : 'bg %s'
}
/Classwork/CS3214 - Computer Systems/Project 2 - Extensible Shell/eshtests/advanced/exclusive_access_test.py
0,0 → 1,58
#!/usr/bin/python
#
# Block header comment
#
#
import sys, imp, atexit
sys.path.append("/home/courses/cs3214/software/pexpect-dpty/");
import pexpect, shellio, signal, time, os, re, proc_check
 
#Ensure the shell process is terminated
def force_shell_termination(shell_process):
c.close(force=True)
 
#pulling in the regular expression and other definitions
definitions_scriptname = sys.argv[1]
def_module = imp.load_source('', definitions_scriptname)
logfile = None
if hasattr(def_module, 'logfile'):
logfile = def_module.logfile
 
#spawn an instance of the shell
c = pexpect.spawn(def_module.shell, drainpty=True, logfile=logfile)
atexit.register(force_shell_termination, shell_process=c)
 
 
# set timeout for all following 'expect*' calls to 2 seconds
c.timeout = 2
 
# ensure that shell prints expected prompt
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
# run a command
c.sendline("vim")
 
# The following call is necessary to ensure that the SIGTSTP
# we are sending below via 'sendcontrol' reaches the 'sleep' child.
proc_check.wait_until_child_is_in_foreground(c)
 
# send SIGTSTP to 'sleep'
c.sendcontrol('z')
 
# shell should pick up that 'sleep' was stopped and respond with job status
# it should output a line such [6]+ Stopped sleep 60
(jobid, statusmsg, cmdline) = \
shellio.parse_regular_expression(c, def_module.job_status_regex)
assert statusmsg == def_module.jobs_status_msg['stopped'], "Shell did not report stopped job"
 
# move job into foreground
c.sendline(def_module.builtin_commands['fg'] % jobid)
 
# when moving a job in the foreground, bash outputs its command line
assert c.expect_exact(cmdline) == 0, "Shell did not report the job moved into the foreground"
 
# end the program
c.sendintr()
 
 
shellio.success()
/Classwork/CS3214 - Computer Systems/Project 2 - Extensible Shell/eshtests/advanced/io_append_test.py
0,0 → 1,58
#!/usr/bin/python
#
# Block header comment
#
#
import sys, imp, atexit
sys.path.append("/home/courses/cs3214/software/pexpect-dpty/");
import pexpect, shellio, signal, time, os, re, proc_check
 
#Ensure the shell process is terminated
def force_shell_termination(shell_process):
c.close(force=True)
 
#pulling in the regular expression and other definitions
definitions_scriptname = sys.argv[1]
def_module = imp.load_source('', definitions_scriptname)
logfile = None
if hasattr(def_module, 'logfile'):
logfile = def_module.logfile
 
#spawn an instance of the shell
c = pexpect.spawn(def_module.shell, drainpty=True, logfile=logfile)
atexit.register(force_shell_termination, shell_process=c)
 
 
# set timeout for all following 'expect*' calls to 2 seconds
c.timeout = 2
 
# ensure that shell prints expected prompt
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
# save a string to a file
c.sendline("echo This is a test message > testfile")
 
# ensure that the shell prints the expected prompt
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
# append a string to the file
c.sendline("echo This is another message >> testfile")
 
# ensure that the shell prints the expected prompt
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
# print out contents of said file
c.sendline("cat testfile")
 
# check if correct string was written
assert c.expect("This is a test message\r\nThis is another message") == 0, \
"Shell did not print expected output"
 
# remove tmp file
c.sendline("rm testfile")
 
c.sendline("exit");
assert c.expect_exact("exit\r\n") == 0, "Shell output extraneous characters"
 
 
shellio.success()
/Classwork/CS3214 - Computer Systems/Project 2 - Extensible Shell/eshtests/advanced/io_in_test.py
0,0 → 1,51
#!/usr/bin/python
#
# Block header comment
#
#
import sys, imp, atexit
sys.path.append("/home/courses/cs3214/software/pexpect-dpty/");
import pexpect, shellio, signal, time, os, re, proc_check
 
#Ensure the shell process is terminated
def force_shell_termination(shell_process):
c.close(force=True)
 
#pulling in the regular expression and other definitions
definitions_scriptname = sys.argv[1]
def_module = imp.load_source('', definitions_scriptname)
logfile = None
if hasattr(def_module, 'logfile'):
logfile = def_module.logfile
 
#spawn an instance of the shell
c = pexpect.spawn(def_module.shell, drainpty=True, logfile=logfile)
atexit.register(force_shell_termination, shell_process=c)
 
 
# set timeout for all following 'expect*' calls to 2 seconds
c.timeout = 2
 
# ensure that shell prints expected prompt
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
# save a string to a file
c.sendline("echo This is a test message > testfile")
 
# ensure that the shell prints the expected prompt
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
# print out contents of said file
c.sendline("wc < testfile")
 
# check if correct string was written
assert c.expect(" 1 5 23") == 0, "Shell did not print expected output"
 
# remove tmp file
c.sendline("rm testfile")
 
c.sendline("exit");
assert c.expect_exact("exit\r\n") == 0, "Shell output extraneous characters"
 
 
shellio.success()
/Classwork/CS3214 - Computer Systems/Project 2 - Extensible Shell/eshtests/advanced/io_out_test.py
0,0 → 1,51
#!/usr/bin/python
#
# Block header comment
#
#
import sys, imp, atexit
sys.path.append("/home/courses/cs3214/software/pexpect-dpty/");
import pexpect, shellio, signal, time, os, re, proc_check
 
#Ensure the shell process is terminated
def force_shell_termination(shell_process):
c.close(force=True)
 
#pulling in the regular expression and other definitions
definitions_scriptname = sys.argv[1]
def_module = imp.load_source('', definitions_scriptname)
logfile = None
if hasattr(def_module, 'logfile'):
logfile = def_module.logfile
 
#spawn an instance of the shell
c = pexpect.spawn(def_module.shell, drainpty=True, logfile=logfile)
atexit.register(force_shell_termination, shell_process=c)
 
 
# set timeout for all following 'expect*' calls to 2 seconds
c.timeout = 2
 
# ensure that shell prints expected prompt
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
# save a string to a file
c.sendline("echo This is a test message > testfile")
 
# ensure that the shell prints the expected prompt
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
# print out contents of said file
c.sendline("cat testfile")
 
# check if correct string was written
assert c.expect("This is a test message") == 0, "Shell did not print expected output"
 
# remove tmp file
c.sendline("rm testfile")
 
c.sendline("exit");
assert c.expect_exact("exit\r\n") == 0, "Shell output extraneous characters"
 
 
shellio.success()
/Classwork/CS3214 - Computer Systems/Project 2 - Extensible Shell/eshtests/advanced/multi_pipe_test.py
0,0 → 1,42
#!/usr/bin/python
#
# Block header comment
#
#
import sys, imp, atexit
sys.path.append("/home/courses/cs3214/software/pexpect-dpty/");
import pexpect, shellio, signal, time, os, re, proc_check
 
#Ensure the shell process is terminated
def force_shell_termination(shell_process):
c.close(force=True)
 
#pulling in the regular expression and other definitions
definitions_scriptname = sys.argv[1]
def_module = imp.load_source('', definitions_scriptname)
logfile = None
if hasattr(def_module, 'logfile'):
logfile = def_module.logfile
 
#spawn an instance of the shell
c = pexpect.spawn(def_module.shell, drainpty=True, logfile=logfile)
atexit.register(force_shell_termination, shell_process=c)
 
 
# set timeout for all following 'expect*' calls to 2 seconds
c.timeout = 2
 
# ensure that shell prints expected prompt
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
# send >1 pipe of commands
c.sendline("echo This is a test message | wc | wc")
 
# check the output
assert c.expect(" 1 3 24") == 0, "Shell did not print expected output"
 
c.sendline("exit");
assert c.expect_exact("exit\r\n") == 0, "Shell output extraneous characters"
 
 
shellio.success()
/Classwork/CS3214 - Computer Systems/Project 2 - Extensible Shell/eshtests/advanced/single_pipe_test.py
0,0 → 1,42
#!/usr/bin/python
#
# Block header comment
#
#
import sys, imp, atexit
sys.path.append("/home/courses/cs3214/software/pexpect-dpty/");
import pexpect, shellio, signal, time, os, re, proc_check
 
#Ensure the shell process is terminated
def force_shell_termination(shell_process):
c.close(force=True)
 
#pulling in the regular expression and other definitions
definitions_scriptname = sys.argv[1]
def_module = imp.load_source('', definitions_scriptname)
logfile = None
if hasattr(def_module, 'logfile'):
logfile = def_module.logfile
 
#spawn an instance of the shell
c = pexpect.spawn(def_module.shell, drainpty=True, logfile=logfile)
atexit.register(force_shell_termination, shell_process=c)
 
 
# set timeout for all following 'expect*' calls to 2 seconds
c.timeout = 2
 
# ensure that shell prints expected prompt
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
# send a single pipe of commands
c.sendline("echo This is a test message | wc")
 
# check the output
assert c.expect(" 1 5 23") == 0, "Shell did not print expected output"
 
c.sendline("exit");
assert c.expect_exact("exit\r\n") == 0, "Shell output extraneous characters"
 
 
shellio.success()
/Classwork/CS3214 - Computer Systems/Project 2 - Extensible Shell/eshtests/advanced.tst
0,0 → 1,7
= Advanced Tests
11 advanced/single_pipe_test.py
7 advanced/multi_pipe_test.py
7 advanced/io_in_test.py
7 advanced/io_out_test.py
7 advanced/io_append_test.py
11 advanced/exclusive_access_test.py
/Classwork/CS3214 - Computer Systems/Project 2 - Extensible Shell/eshtests/basic/bg_test.py
0,0 → 1,96
#!/usr/bin/python
#
# bg_test: tests the bg command
#
# Test the stop command for stopping a process by its pid.
# Requires the following commands to be implemented
# or otherwise usable:
#
# bg, sleep, stop
#
 
import sys, imp, atexit
sys.path.append("/home/courses/cs3214/software/pexpect-dpty/");
import pexpect, shellio, signal, time, os, re, proc_check
 
#Ensure the shell process is terminated
def force_shell_termination(shell_process):
c.close(force=True)
 
#pulling in the regular expression and other definitions
definitions_scriptname = sys.argv[1]
 
def_module = imp.load_source('', definitions_scriptname)
logfile = None
if hasattr(def_module, 'logfile'):
logfile = def_module.logfile
 
#spawn an instance of the shell
c = pexpect.spawn(def_module.shell, drainpty=True, logfile=logfile)
atexit.register(force_shell_termination, shell_process=c)
 
# set timeout for all following 'expect*' calls to 2 seconds
c.timeout = 2
 
# ensure that shell prints expected prompt
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
 
 
# run program sleep
c.sendline("sleep 30 &")
 
#Used to get the jobid and pid of the sleep process
(jobid, pid) = shellio.parse_regular_expression(c, def_module.bgjob_regex)
 
# ensure that shell prints expected prompt
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
 
 
# send the stop command to the process
c.sendline(def_module.builtin_commands['stop'] % jobid)
 
#Ensure that sleep has enough time to stop before we read its
#/proc/ /stat file.
proc_check.count_children_timeout(c, 1, 1)
 
 
 
#Ensure that sleep is now stopped in the background, and is not
#the foreground process.
assert not proc_check.check_pid_fgpgrp(pid), \
'Error: process is in the foreground'
assert proc_check.check_pid_status(pid, 'T'), 'Error: process not stopped'
 
#check the prompt prints
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
 
 
#resume the sleep program
c.sendline(def_module.builtin_commands['bg'] % jobid)
 
#check the prompt prints
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
#Ensure that sleep has enough time to start before we read its
#/proc/ /stat file.
proc_check.count_children_timeout(c, 1, 1)
 
 
 
#Ensure that sleep is running now in the background, and is not
#the foreground process.
assert not proc_check.check_pid_fgpgrp(pid), \
'Error: process is in the foreground'
assert proc_check.check_pid_status(pid, 'S'), 'Error: process not running'
 
 
 
#exit
c.sendline("exit");
assert c.expect("exit\r\n") == 0, "Shell output extraneous characters"
 
 
shellio.success()
/Classwork/CS3214 - Computer Systems/Project 2 - Extensible Shell/eshtests/basic/ctrl-c_test.py
0,0 → 1,63
#!/usr/bin/python
#
# Ctrl-C Test: Start a shell, send SIGINT, run a program,
# send SIGINT, then exit
#
# Requires the following commands to be implemented
# or otherwise usable:
#
# sleep, ctrl-c control
#
 
import sys, imp, atexit
sys.path.append("/home/courses/cs3214/software/pexpect-dpty/");
import pexpect, proc_check, shellio, signal, time, threading
 
#Ensure the shell process is terminated
def force_shell_termination(shell_process):
c.close(force=True)
 
#pulling in the regular expression and other definitions
definitions_scriptname = sys.argv[1]
def_module = imp.load_source('', definitions_scriptname)
logfile = None
if hasattr(def_module, 'logfile'):
logfile = def_module.logfile
 
# spawn an instance of the shell
c = pexpect.spawn(def_module.shell, drainpty=True, logfile=logfile)
atexit.register(force_shell_termination, shell_process=c)
 
# set timeout for all following 'expect*' calls to 2 seconds
c.timeout = 2
 
# ensure that shell prints expected prompt
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
# run a command
c.sendline("sleep 60")
 
# The following call is necessary to ensure that the SIGINT
# we are sending below reaches the 'sleep' child.
proc_check.wait_until_child_is_in_foreground(c)
 
#checks that our process is running
proc_check.count_active_children(c, 1)
 
# send SIGINT
c.sendintr()
 
#prompt check
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
#checks that the process was ended
proc_check.count_active_children(c, 0)
 
 
 
c.sendline("exit")
 
assert c.expect_exact("exit\r\n") == 0, "Shell output extraneous characters"
 
 
shellio.success()
/Classwork/CS3214 - Computer Systems/Project 2 - Extensible Shell/eshtests/basic/ctrl-z_test.py
0,0 → 1,88
#!/usr/bin/python
#
# Ctrl-Z Test: Start a shell, run a program,
# send SIGTSTP, wait for status msg, move in
# foreground, then send SIGINT, then exit
#
# Requires use of the following commands:
#
# ctrl-z control, fg, sleep
#
 
import sys, imp, atexit
sys.path.append("/home/courses/cs3214/software/pexpect-dpty/");
import pexpect, proc_check, shellio, signal, time, threading
 
#Ensure the shell process is terminated
def force_shell_termination(shell_process):
c.close(force=True)
 
# pulling in the regular expression and other definitions
definitions_scriptname = sys.argv[1]
def_module = imp.load_source('', definitions_scriptname)
logfile = None
if hasattr(def_module, 'logfile'):
logfile = def_module.logfile
 
# spawn an instance of the shell
c = pexpect.spawn(def_module.shell, drainpty=True, logfile=logfile)
atexit.register(force_shell_termination, shell_process=c)
 
# set timeout for all following 'expect*' calls to 2 seconds
c.timeout = 2
 
# ensure that shell prints expected prompt
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
 
 
# run a command
c.sendline("sleep 60")
 
# The following call is necessary to ensure that the SIGTSTP
# we are sending below via 'sendcontrol' reaches the 'sleep' child.
proc_check.wait_until_child_is_in_foreground(c)
 
#checks the number of active child processes
#using a timeout based process count
proc_check.count_children_timeout(c, 1, 1)
 
#checks the number of active child processes
#at this moment in time
proc_check.count_active_children(c, 1)
 
 
 
# send SIGTSTP to 'sleep'
c.sendcontrol('z')
 
# shell should pick up that 'sleep' was stopped and respond with job status
# it should output a line such as [6]+ Stopped (sleep 60)
# (note that the provided regexp assumes the job name appears in parentheses,
# adjust your eshoutput.py if needed)
(jobid, statusmsg, cmdline) = \
shellio.parse_regular_expression(c, def_module.job_status_regex)
assert statusmsg == def_module.jobs_status_msg['stopped'], "Shell did not report stopped job"
 
# move job into foreground
c.sendline(def_module.builtin_commands['fg'] % jobid)
 
# when moving a job in the foreground, bash outputs its command line
assert c.expect_exact(cmdline) == 0, "Shell did not report the job moved into the foreground"
 
 
 
# send SIGINT
c.sendintr()
 
#check that the prompt prints
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
 
 
#exit
c.sendline("exit")
assert c.expect_exact("exit\r\n") == 0, "Shell output extraneous characters"
 
 
shellio.success()
/Classwork/CS3214 - Computer Systems/Project 2 - Extensible Shell/eshtests/basic/fg_test.py
0,0 → 1,152
#!/usr/bin/python
#
# fg_test: tests the fg command
#
# Test the fg command for bringing a command back to the foreground.
# Requires the following commands to be implemented
# or otherwise usable:
#
# fg, sleep, ctrl-c control, ctrl-z control
#
 
import sys, imp, atexit
sys.path.append("/home/courses/cs3214/software/pexpect-dpty/");
import pexpect, shellio, signal, time, os, re, proc_check
 
#Ensure the shell process is terminated
def force_shell_termination(shell_process):
c.close(force=True)
 
#pulling in the regular expression and other definitions
definitions_scriptname = sys.argv[1]
def_module = imp.load_source('', definitions_scriptname)
logfile = None
if hasattr(def_module, 'logfile'):
logfile = def_module.logfile
 
# spawn an instance of the shell
c = pexpect.spawn(def_module.shell, drainpty=True, logfile=logfile)
atexit.register(force_shell_termination, shell_process=c)
 
# set timeout for all following 'expect*' calls to 2 seconds
c.timeout = 2
 
# ensure that shell prints expected prompt
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt (1)"
 
 
# run a command
c.sendline("sleep 60")
 
# The following call is necessary to ensure that the SIGTSTP
# we are sending below via 'sendcontrol' reaches the 'sleep' child.
proc_check.wait_until_child_is_in_foreground(c)
 
# send SIGTSTP to 'sleep'
c.sendcontrol('z')
 
# shell should pick up that 'sleep' was stopped and respond with job status
# it should output a line such [6]+ Stopped sleep 60
(jobid, statusmsg, cmdline) = \
shellio.parse_regular_expression(c, def_module.job_status_regex)
assert statusmsg == def_module.jobs_status_msg['stopped'], "Shell did not report stopped job"
 
# move job into foreground
c.sendline(def_module.builtin_commands['fg'] % jobid)
 
# when moving a job in the foreground, bash outputs its command line
assert c.expect_exact(cmdline) == 0, "Shell did not report the job moved into the foreground"
 
# end the program
c.sendintr()
 
 
 
# run a command
c.sendline("sleep 30 &")
 
#snag the jobid and pid of the sleep command
(jobid, pid) = shellio.parse_regular_expression(c, def_module.bgjob_regex)
 
#check the prompt prints
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt (2)"
 
 
 
#resume the sleep command
c.sendline(def_module.builtin_commands['fg'] % jobid)
 
#wait until it takes over the foreground process group
proc_check.wait_until_child_is_in_foreground(c)
 
#send the command back to the background
c.sendcontrol('z')
 
#check the prompt prints
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt (3)"
 
 
 
#run a command to the background
c.sendline("sleep 300 &")
 
#snag the jobid and pid of the second sleep command
(jobid2, pid2) = shellio.parse_regular_expression(c, def_module.bgjob_regex)
 
#check the prompt prints
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt (4)"
 
#resume the command by its jobid
c.sendline(def_module.builtin_commands['fg'] % jobid)
 
#wait until it takes over the foreground process group
proc_check.wait_until_child_is_in_foreground(c)
 
#Ensure that the sleep is in the foreground process group via /proc/
assert proc_check.check_pid_fgpgrp(pid), "Error, the pid's process group is \
not the foreground process group"
 
#send the command back to the background
c.sendcontrol('z')
 
#check the prompt prints
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt (5)"
 
 
 
#resume the command by its jobid
c.sendline(def_module.builtin_commands['fg'] % jobid2)
 
#wait until it takes over the foreground process group
proc_check.wait_until_child_is_in_foreground(c)
 
#Ensure that the sleep is in the foreground process group via /proc/
assert proc_check.check_pid_fgpgrp(pid2), "Error, the pid's process group is \
not the foreground process group"
 
#end the process
c.sendintr()
 
#check that the prompt prints
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt (6)"
 
 
 
#resume the first sleep command
c.sendline(def_module.builtin_commands['fg'] % jobid)
 
#wait until the process takes over the foreground process group
proc_check.wait_until_child_is_in_foreground(c)
 
#Ensure that the sleep is in the foreground process group via /proc/
assert proc_check.check_pid_fgpgrp(pid), "Error, the pid's process group is \
not the foreground process group"
 
 
 
#exit
c.sendline("exit");
assert c.expect_exact("exit\r\n") == 0, "Shell output extraneous characters"
 
 
shellio.success()
/Classwork/CS3214 - Computer Systems/Project 2 - Extensible Shell/eshtests/basic/jobs_test.py
0,0 → 1,164
#!/usr/bin/python
#
# jobs_test: tests the jobs command
#
# Test the jobs command for status messages and proper output
# of the command and jobid. Requires the following commands to be implemented
# or otherwise usable:
#
# jobs, ctrl-z control, ctrl-c control, sleep, fg, clear
#
 
import sys, imp, atexit
sys.path.append("/home/courses/cs3214/software/pexpect-dpty/");
import pexpect, shellio, signal, time, os, re, proc_check
 
#Ensure the shell process is terminated
def force_shell_termination(shell_process):
c.close(force=True)
 
#pulling in the regular expression and other definitions
definitions_scriptname = sys.argv[1]
def_module = imp.load_source('', definitions_scriptname)
logfile = None
if hasattr(def_module, 'logfile'):
logfile = def_module.logfile
 
# spawn an instance of bash. PS1 is the env variable from which bash
# draws its prompt
c = pexpect.spawn(def_module.shell, drainpty=True, logfile=logfile)
atexit.register(force_shell_termination, shell_process=c)
 
# set timeout for all following 'expect*' calls to 2 seconds
c.timeout = 2
 
# ensure that shell prints expected prompt
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
 
 
#check that the jobs list outputs nothing
c.sendline(def_module.builtin_commands['jobs'])
 
# ensure that shell prints expected prompt
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
 
 
# run a command
c.sendline("sleep 30")
 
#Wait until the sleep command takes over the foreground
proc_check.wait_until_child_is_in_foreground(c)
 
#send the job to the background
c.sendcontrol('z')
 
# ensure that the shell prints the expected prompt
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
 
 
#Request the jobs list
c.sendline(def_module.builtin_commands['jobs'])
 
#Check the jobs list
(jobid, status_message, command_line) = shellio.parse_regular_expression(c, def_module.job_status_regex)
assert status_message == def_module.jobs_status_msg['stopped'] and \
'sleep 30' in command_line, "Job status not properly displayed"
 
# ensure that the shell prints the expected prompt
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
 
 
#Add another job
c.sendline("sleep 300 &")
 
# pick up the background job output
(jobid, pid) = shellio.parse_regular_expression(c, def_module.bgjob_regex)
 
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
#Both jobs need to be active and running before the jobs command is
#sent. if this isn't so, the test is failed.
proc_check.count_active_children(c, 2)
 
 
 
#Recheck the jobs list
c.sendline(def_module.builtin_commands['jobs'])
 
#Check the jobs list
(jobid, status_message, command_line) = \
shellio.parse_regular_expression(c, def_module.job_status_regex)
(jobid2, status_message2, command_line2) = \
shellio.parse_regular_expression(c, def_module.job_status_regex)
 
# Check that the jobs list contains both jobs in some order
 
#check the first possible order of job statuses, and then
#the second possible order.
assert (status_message == def_module.jobs_status_msg['stopped'] and \
'sleep 30' in command_line and \
\
status_message2 == def_module.jobs_status_msg['running'] and \
'sleep 300' in command_line2) \
\
or \
\
(status_message2 == def_module.jobs_status_msg['stopped'] and \
'sleep 30' in command_line2 and \
\
status_message == def_module.jobs_status_msg['running'] and \
'sleep 300' in command_line), "Job status not properly displayed"
 
# Check that there are no duplicate job id's.
assert jobid != jobid2, "Duplicate job id's."
 
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
 
 
#bring the second sleep command back to foreground
#so that we can end it with ctrl-c
c.sendline(def_module.builtin_commands['fg'] % jobid2)
 
#Wait until the sleep command takes over the foreground
proc_check.wait_until_child_is_in_foreground(c)
 
#ctrl-c to close the process
c.sendintr()
 
 
 
#clear any printout of the old job that was just killed by ctrl-c
c.sendline(def_module.builtin_commands['jobs'])
 
#check the prompt and move past this text
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
 
#check the prompt and move past this text
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
 
#check the jobs list
c.sendline(def_module.builtin_commands['jobs'])
 
#check that the first job is still on the jobs list
assert (jobid, status_message, command_line) == \
shellio.parse_regular_expression(c, def_module.job_status_regex), \
"The original job was not displayed properly after ending a previous job."
 
# ensure the prompt is printed
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
 
 
# exit
c.sendline("exit");
assert c.expect_exact("exit\r\n") == 0, "Shell output extraneous characters"
 
 
shellio.success()
/Classwork/CS3214 - Computer Systems/Project 2 - Extensible Shell/eshtests/basic/kill_test.py
0,0 → 1,81
#!/usr/bin/python
#
# kill_test: tests the kill command with the default
# semantics of:
#
# kill <jid>
#
# This test may require updating such that we test other signals
#
# Requires the following commands to be implemented
# or otherwise usable:
#
# kill, sleep
#
 
import sys, imp, atexit
sys.path.append("/home/courses/cs3214/software/pexpect-dpty/");
import pexpect, shellio, signal, time, os, re, proc_check
 
 
#Ensure the shell process is terminated
def force_shell_termination(shell_process):
c.close(force=True)
 
# pulling in the regular expression and other definitions
definitions_scriptname = sys.argv[1]
def_module = imp.load_source('', definitions_scriptname)
logfile = None
if hasattr(def_module, 'logfile'):
logfile = def_module.logfile
 
# spawn an instance of the shell
c = pexpect.spawn(def_module.shell, drainpty=True, logfile=logfile)
atexit.register(force_shell_termination, shell_process=c)
 
# set timeout for all following 'expect*' calls to 2 seconds
c.timeout = 2
 
# ensure that the shell prints the expected prompt
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
 
 
# run a command
c.sendline("sleep 30 &")
 
# parse the jobid and pid output
(jobid, pid) = shellio.parse_regular_expression(c, def_module.bgjob_regex)
 
# ensure that the shell prints the expected prompt
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
# The job needs to be running when we call kill
proc_check.count_children_timeout(c, 1, 1)
 
# Run the kill command and kill the sleep process in the background
c.sendline(def_module.builtin_commands['kill'] % jobid)
 
# ensure that the shell prints the expected prompt
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
# ensure there is enough time for the process to be killed
time.sleep(.5)
 
 
 
# check the proc file that the process has actually been stopped
# the proc file should not exist
assert not os.path.exists("/proc/" + pid + "/stat"), 'the process was not \
killed'
 
 
# end the shell program by sending it an end-of-file character
c.sendline("exit");
 
# ensure that no extra characters are output after exiting
assert c.expect_exact("exit\r\n") == 0, "Shell output extraneous characters"
 
 
# the test was successful
shellio.success()
/Classwork/CS3214 - Computer Systems/Project 2 - Extensible Shell/eshtests/basic/stop_test.py
0,0 → 1,77
#!/usr/bin/python
#
# stop_test: tests the stop command
#
# Test the stop command for stopping a process by its pid.
# Requires the following commands to be implemented
# or otherwise usable:
#
# stop, sleep
#
 
import sys, imp, atexit
sys.path.append("/home/courses/cs3214/software/pexpect-dpty/");
import pexpect, shellio, signal, time, os, re, proc_check
 
#Ensure the shell process is terminated
def force_shell_termination(shell_process):
c.close(force=True)
 
#pulling in the regular expression and other definitions
definitions_scriptname = sys.argv[1]
def_module = imp.load_source('', definitions_scriptname)
logfile = None
if hasattr(def_module, 'logfile'):
logfile = def_module.logfile
 
# spawn an instance of the shell
c = pexpect.spawn(def_module.shell, drainpty=True, logfile=logfile)
atexit.register(force_shell_termination, shell_process=c)
 
# set timeout for all following 'expect*' calls to 2 seconds
c.timeout = 2
 
# ensure that shell prints expected prompt
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
 
 
# run a command
c.sendline("sleep 30 &")
 
# pull the jobid and pid from the background process printout
(jobid, pid) = shellio.parse_regular_expression(c, def_module.bgjob_regex)
 
# ensure that the shell prints the expected prompt
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
 
 
#The job needs to be running when we call stop
proc_check.count_children_timeout(c, 1, 1)
 
# send the stop command to the process
c.sendline(def_module.builtin_commands['stop'] % jobid)
 
#Ensure that sleep has enough time to stop before we read its
#/proc/ pid /stat file.
time.sleep(.5)
 
 
 
#Ensure that sleep is now stopped in the background, and is not
#the foreground process.
assert not proc_check.check_pid_fgpgrp(pid), \
'Error: process is in the foreground'
assert proc_check.check_pid_status(pid, 'T'), 'Error: process not stopped'
 
#check the prompt prints
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
 
 
c.sendline("exit");
assert c.expect_exact("exit\r\n") == 0, "Shell output extraneous characters"
 
 
shellio.success()
/Classwork/CS3214 - Computer Systems/Project 2 - Extensible Shell/eshtests/basic.tst
0,0 → 1,8
= Basic Tests
6 basic/ctrl-z_test.py
6 basic/ctrl-c_test.py
8 basic/fg_test.py
8 basic/jobs_test.py
7 basic/stop_test.py
8 basic/bg_test.py
7 basic/kill_test.py
/Classwork/CS3214 - Computer Systems/Project 2 - Extensible Shell/eshtests/milestone/foreground.py
0,0 → 1,43
#!/usr/bin/python
#
# Tests that esh can run commands in the foreground
#
 
import sys, imp, atexit
sys.path.append("/home/courses/cs3214/software/pexpect-dpty/");
import pexpect, shellio, signal, time, os, re, proc_check
 
 
#Ensure the shell process is terminated
def force_shell_termination(shell_process):
c.close(force=True)
 
#pulling in the regular expression and other definitions
definitions_scriptname = sys.argv[1]
def_module = imp.load_source('', definitions_scriptname)
 
# start shell
c = pexpect.spawn(def_module.shell, drainpty=True, logfile=None)
atexit.register(force_shell_termination, shell_process=c)
 
# set timeout for all following 'expect*' calls to 4 seconds
c.timeout = 4
 
# ensure that shell prints expected prompt
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
# run a command
c.sendline("/usr/bin/gcc")
 
assert c.expect("gcc: no input files") == 0, "Shell did not start gcc"
 
# make sure shell returns to prompt
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
# send EOF
c.sendeof()
 
# send SIGINT in case the EOF doesn't quit their shell
c.sendintr()
 
shellio.success()
/Classwork/CS3214 - Computer Systems/Project 2 - Extensible Shell/eshtests/milestone.tst
0,0 → 1,3
= Milestone
30 milestone/foreground.py
 
/Classwork/CS3214 - Computer Systems/Project 2 - Extensible Shell/eshtests/plugin_skeleton.py
0,0 → 1,30
#!/usr/bin/python
#
# Block header comment
#
#
import sys, imp, atexit
sys.path.append("/home/courses/cs3214/software/pexpect-dpty/");
import pexpect, shellio, signal, time, os, re, proc_check
 
#Ensure the shell process is terminated
def force_shell_termination(shell_process):
c.close(force=True)
 
#pulling in the regular expression and other definitions
definitions_scriptname = sys.argv[1]
plugin_dir = sys.argv[2]
def_module = imp.load_source('', definitions_scriptname)
logfile = None
if hasattr(def_module, 'logfile'):
logfile = def_module.logfile
 
#spawn an instance of the shell
c = pexpect.spawn(def_module.shell + plugin_dir, drainpty=True, logfile=logfile)
 
atexit.register(force_shell_termination, shell_process=c)
 
assert 1 == 0, "Unimplemented functionality"
 
 
shellio.success()
/Classwork/CS3214 - Computer Systems/Project 2 - Extensible Shell/eshtests/reduced/bg_test.py
0,0 → 1,95
#!/usr/bin/python
#
# bg_test: tests the bg command
#
# Test the stop command for stopping a process by its pid.
# Requires the following commands to be implemented
# or otherwise usable:
#
# bg, sleep, stop
#
 
 
import sys, imp, atexit
sys.path.append("/home/courses/cs3214/software/pexpect-dpty/");
import pexpect, shellio, signal, time, os, re, proc_check
 
#Ensure the shell process is terminated
def force_shell_termination(shell_process):
c.close(force=True)
 
#pulling in the regular expression and other definitions
definitions_scriptname = sys.argv[1]
def_module = imp.load_source('', definitions_scriptname)
logfile = None
if hasattr(def_module, 'logfile'):
logfile = def_module.logfile
 
#spawn an instance of the shell
c = pexpect.spawn(def_module.shell, drainpty=True, logfile=logfile)
atexit.register(force_shell_termination, shell_process=c)
 
# set timeout for all following 'expect*' calls to 2 seconds
c.timeout = 2
 
# ensure that shell prints expected prompt
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
 
 
# run program sleep
c.sendline("sleep 30 &")
 
#Used to get the jobid and pid of the sleep process
(jobid, pid) = shellio.parse_regular_expression(c, def_module.bgjob_regex)
 
# ensure that shell prints expected prompt
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
 
 
# send the stop command to the process
c.sendline(def_module.builtin_commands['stop'] % jobid)
 
#Ensure that sleep has enough time to stop before we read its
#/proc/ /stat file.
time.sleep(.5)
 
 
 
#Ensure that sleep is now stopped in the background, and is not
#the foreground process.
assert not proc_check.check_pid_fgpgrp(pid), \
'Error: process is in the foreground'
assert proc_check.check_pid_status(pid, 'T'), 'Error: process not stopped'
 
#check the prompt prints
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
 
 
#resume the sleep program
c.sendline(def_module.builtin_commands['bg'] % jobid)
 
#check the prompt prints
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
#Ensure that sleep has enough time to start before we read its
#/proc/ /stat file.
time.sleep(.5)
 
 
 
#Ensure that sleep is running now in the background, and is not
#the foreground process.
assert not proc_check.check_pid_fgpgrp(pid), \
'Error: process is in the foreground'
assert proc_check.check_pid_status(pid, 'S'), 'Error: process not running'
 
 
 
#exit
c.sendline("exit");
assert c.expect("exit\r\n") == 0, "Shell output extraneous characters"
 
shellio.success()
/Classwork/CS3214 - Computer Systems/Project 2 - Extensible Shell/eshtests/reduced/ctrl-c_test.py
0,0 → 1,65
#!/usr/bin/python
#
# Ctrl-C Test: Start a shell, send SIGINT, run a program,
# send SIGINT, then exit
#
# Requires the following commands to be implemented
# or otherwise usable:
#
# sleep, ctrl-c control
#
 
import sys, imp, atexit
sys.path.append("/home/courses/cs3214/software/pexpect-dpty/");
import pexpect, proc_check, shellio, signal, time, threading
 
#Ensure the shell process is terminated
def force_shell_termination(shell_process):
c.close(force=True)
 
#pulling in the regular expression and other definitions
definitions_scriptname = sys.argv[1]
def_module = imp.load_source('', definitions_scriptname)
logfile = None
if hasattr(def_module, 'logfile'):
logfile = def_module.logfile
 
# spawn an instance of the shell
c = pexpect.spawn(def_module.shell, drainpty=True, logfile=logfile)
atexit.register(force_shell_termination, shell_process=c)
 
# set timeout for all following 'expect*' calls to 2 seconds
c.timeout = 2
 
# ensure that shell prints expected prompt
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
# run a command
c.sendline("sleep 60")
 
 
# The following call is necessary to ensure that the SIGINT
# we are sending below reaches the 'sleep' child.
# This is NOT a bullet-proof fix, you may fail on occasion!
time.sleep(1)
 
#checks that our process is running
proc_check.count_active_children(c, 1)
 
# send SIGINT
c.sendintr()
 
#prompt check
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
#checks that the process was ended
proc_check.count_active_children(c, 0)
 
 
 
c.sendline("exit")
 
assert c.expect_exact("exit\r\n") == 0, "Shell output extraneous characters"
 
 
shellio.success()
/Classwork/CS3214 - Computer Systems/Project 2 - Extensible Shell/eshtests/reduced/ctrl-z_test.py
0,0 → 1,88
#!/usr/bin/python
#
# Ctrl-Z Test: Start a shell, run a program,
# send SIGTSTP, wait for status msg, move in
# foreground, then send SIGINT, then exit
#
# Requires use of the following commands:
#
# ctrl-z control, fg, sleep
#
 
import sys, imp, atexit
sys.path.append("/home/courses/cs3214/software/pexpect-dpty/");
import pexpect, proc_check, shellio, signal, time, threading
 
 
#Ensure the shell process is terminated
def force_shell_termination(shell_process):
c.close(force=True)
 
# pulling in the regular expression and other definitions
definitions_scriptname = sys.argv[1]
def_module = imp.load_source('', definitions_scriptname)
logfile = None
if hasattr(def_module, 'logfile'):
logfile = def_module.logfile
 
# spawn an instance of the shell
c = pexpect.spawn(def_module.shell, drainpty=True, logfile=logfile)
atexit.register(force_shell_termination, shell_process=c)
 
# set timeout for all following 'expect*' calls to 2 seconds
c.timeout = 2
 
# ensure that shell prints expected prompt
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
 
 
# run a command
c.sendline("sleep 60")
 
# The following call is necessary to ensure that the SIGTSTP
# we are sending below via 'sendcontrol' reaches the 'sleep' child.
# This is NOT a bullet-proof fix, you may fail on occasion!
time.sleep(1)
 
 
#checks the number of active child processes
#using a timeout based process count
proc_check.count_children_timeout(c, 1, 1)
 
#checks the number of active child processes
#at this moment in time
proc_check.count_active_children(c, 1)
 
 
 
# send SIGTSTP to 'sleep'
c.sendcontrol('z')
 
# shell should pick up that 'sleep' was stopped and respond with job status
# it should output a line such [6]+ Stopped sleep 60
(jobid, statusmsg, cmdline) = \
shellio.parse_regular_expression(c, def_module.job_status_regex)
assert statusmsg == def_module.jobs_status_msg['stopped'], "Shell did not report stopped job"
 
# move job into foreground
c.sendline(def_module.builtin_commands['fg'] % jobid)
 
# when moving a job in the foreground, bash outputs its command line
assert c.expect_exact(cmdline) == 0, "Shell did not move job in foreground"
 
 
 
# send SIGINT
c.sendintr()
 
#check that the prompt prints
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
 
 
#exit
c.sendline("exit")
assert c.expect_exact("exit\r\n") == 0, "Shell output extraneous characters"
 
shellio.success()
/Classwork/CS3214 - Computer Systems/Project 2 - Extensible Shell/eshtests/reduced/fg_test.py
0,0 → 1,131
#!/usr/bin/python
#
# fg_test: tests the fg command
#
# Test the fg command for bringing a command back to the foreground.
# Requires the following commands to be implemented
# or otherwise usable:
#
# fg, sleep, ctrl-c control, ctrl-z control
#
 
import sys, imp, atexit
sys.path.append("/home/courses/cs3214/software/pexpect-dpty/");
import pexpect, shellio, signal, time, os, re, proc_check
 
#Ensure the shell process is terminated
def force_shell_termination(shell_process):
c.close(force=True)
 
#pulling in the regular expression and other definitions
definitions_scriptname = sys.argv[1]
def_module = imp.load_source('', definitions_scriptname)
logfile = None
if hasattr(def_module, 'logfile'):
logfile = def_module.logfile
 
# spawn an instance of the shell
c = pexpect.spawn(def_module.shell, drainpty=True, logfile=logfile)
atexit.register(force_shell_termination, shell_process=c)
 
# set timeout for all following 'expect*' calls to 2 seconds
c.timeout = 2
 
# ensure that shell prints expected prompt
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt (1)"
 
 
 
# run a command
c.sendline("sleep 30 &")
 
#snag the jobid and pid of the sleep command
(jobid, pid) = shellio.parse_regular_expression(c, def_module.bgjob_regex)
 
#check the prompt prints
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt (2)"
 
 
 
#resume the sleep command
c.sendline(def_module.builtin_commands['fg'] % jobid)
 
#wait until it takes over the foreground process group
# This is NOT a bullet-proof fix, you may fail on occasion!
time.sleep(1)
 
#send the command back to the background
c.sendcontrol('z')
 
#check the prompt prints
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt (3)"
 
 
 
#run a command to the background
c.sendline("sleep 300 &")
 
#snag the jobid and pid of the second sleep command
(jobid2, pid2) = shellio.parse_regular_expression(c, def_module.bgjob_regex)
 
#check the prompt prints
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt (4)"
 
#resume the command by its jobid
c.sendline(def_module.builtin_commands['fg'] % jobid)
 
#wait until it takes over the foreground process group
# This is NOT a bullet-proof fix, you may fail on occasion!
time.sleep(1)
 
#Ensure that the sleep is in the foreground process group via /proc/
#assert proc_check.check_pid_fgpgrp(pid), "Error, the pid's process group is \
# not the foreground process group"
 
#send the command back to the background
c.sendcontrol('z')
 
#check the prompt prints
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt (5)"
 
 
 
#resume the command by its jobid
c.sendline(def_module.builtin_commands['fg'] % jobid2)
 
#wait until it takes over the foreground process group
# This is NOT a bullet-proof fix, you may fail on occasion!
time.sleep(1)
 
#Ensure that the sleep is in the foreground process group via /proc/
#assert proc_check.check_pid_fgpgrp(pid2), "Error, the pid's process group is \
# not the foreground process group"
 
#end the process
c.sendintr()
 
#check that the prompt prints
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt (6)"
 
 
 
#resume the first sleep command
c.sendline(def_module.builtin_commands['fg'] % jobid)
 
#wait until the process takes over the foreground process group
# This is NOT a bullet-proof fix, you may fail on occasion!
time.sleep(1)
 
 
#Ensure that the sleep is in the foreground process group via /proc/
#assert proc_check.check_pid_fgpgrp(pid), "Error, the pid's process group is \
# not the foreground process group"
 
 
 
#exit
c.sendline("exit");
assert c.expect_exact("exit\r\n") == 0, "Shell output extraneous characters"
 
 
shellio.success()
/Classwork/CS3214 - Computer Systems/Project 2 - Extensible Shell/eshtests/reduced/jobs_test.py
0,0 → 1,167
#!/usr/bin/python
#
# jobs_test: tests the jobs command
#
# Test the jobs command for status messages and proper output
# of the command and jobid. Requires the following commands to be implemented
# or otherwise usable:
#
# jobs, ctrl-z control, ctrl-c control, sleep, fg, clear
#
 
import sys, imp, atexit
sys.path.append("/home/courses/cs3214/software/pexpect-dpty/");
import pexpect, shellio, signal, time, os, re, proc_check
 
#Ensure the shell process is terminated
def force_shell_termination(shell_process):
c.close(force=True)
 
#pulling in the regular expression and other definitions
definitions_scriptname = sys.argv[1]
def_module = imp.load_source('', definitions_scriptname)
logfile = None
if hasattr(def_module, 'logfile'):
logfile = def_module.logfile
 
# spawn an instance of bash. PS1 is the env variable from which bash
# draws its prompt
c = pexpect.spawn(def_module.shell, drainpty=True, logfile=logfile)
atexit.register(force_shell_termination, shell_process=c)
 
# set timeout for all following 'expect*' calls to 2 seconds
c.timeout = 2
 
# ensure that shell prints expected prompt
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
 
 
#check that the jobs list outputs nothing
c.sendline(def_module.builtin_commands['jobs'])
 
# ensure that shell prints expected prompt
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
 
 
# run a command
c.sendline("sleep 30")
 
#Wait until the sleep command takes over the foreground
# This is NOT a bullet-proof fix, you may fail on occasion!
time.sleep(1)
 
 
#send the job to the background
c.sendcontrol('z')
 
# ensure that the shell prints the expected prompt
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
 
 
#Request the jobs list
c.sendline(def_module.builtin_commands['jobs'])
 
#Check the jobs list
(jobid, status_message, command_line) = shellio.parse_regular_expression(c, def_module.job_status_regex)
assert status_message == def_module.jobs_status_msg['stopped'] and \
'sleep 30' in command_line, "Job status not properly displayed"
 
# ensure that the shell prints the expected prompt
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
 
 
#Add another job
c.sendline("sleep 300 &")
 
# pick up the background job output
(jobid, pid) = shellio.parse_regular_expression(c, def_module.bgjob_regex)
 
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
#Both jobs need to be active and running before the jobs command is
#sent. if this isn't so, the test is failed.
proc_check.count_active_children(c, 2)
 
 
 
#Recheck the jobs list
c.sendline(def_module.builtin_commands['jobs'])
 
#Check the jobs list
(jobid, status_message, command_line) = \
shellio.parse_regular_expression(c, def_module.job_status_regex)
(jobid2, status_message2, command_line2) = \
shellio.parse_regular_expression(c, def_module.job_status_regex)
 
# Check that the jobs list contains both jobs in some order
 
#check the first possible order of job statuses, and then
#the second possible order.
assert (status_message == def_module.jobs_status_msg['stopped'] and \
'sleep 30' in command_line and \
\
status_message2 == def_module.jobs_status_msg['running'] and \
'sleep 300' in command_line2) \
\
or \
\
(status_message2 == def_module.jobs_status_msg['stopped'] and \
'sleep 30' in command_line2 and \
\
status_message == def_module.jobs_status_msg['running'] and \
'sleep 300' in command_line), "Job status not properly displayed"
 
# Check that there are no duplicate job id's.
assert jobid != jobid2, "Duplicate job id's."
 
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
 
 
#bring the second sleep command back to foreground
#so that we can end it with ctrl-c
c.sendline(def_module.builtin_commands['fg'] % jobid2)
 
 
#Wait until the sleep command takes over the foreground
# This is NOT a bullet-proof fix, you may fail on occasion!
time.sleep(1)
 
#ctrl-c to close the process
c.sendintr()
 
 
 
#clear any printout of the old job that was just killed by ctrl-c
c.sendline(def_module.builtin_commands['jobs'])
 
#check the prompt and move past this text
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
 
#check the prompt and move past this text
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
 
#check the jobs list
c.sendline(def_module.builtin_commands['jobs'])
 
#check that the first job is still on the jobs list
assert (jobid, status_message, command_line) == \
shellio.parse_regular_expression(c, def_module.job_status_regex), \
"The original job was not displayed properly after ending a previous job."
 
# ensure the prompt is printed
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
 
 
# exit
c.sendline("exit");
assert c.expect_exact("exit\r\n") == 0, "Shell output extraneous characters"
 
shellio.success()
/Classwork/CS3214 - Computer Systems/Project 2 - Extensible Shell/eshtests/reduced/kill_test.py
0,0 → 1,80
#!/usr/bin/python
#
# kill_test: tests the kill command with the default
# semantics of:
#
# kill <pid>
#
# This test may require updating such that we test other signals
#
# Requires the following commands to be implemented
# or otherwise usable:
#
# kill, sleep
#
 
 
import sys, imp, atexit
sys.path.append("/home/courses/cs3214/software/pexpect-dpty/");
import pexpect, shellio, signal, time, os, re, proc_check
 
#Ensure the shell process is terminated
def force_shell_termination(shell_process):
c.close(force=True)
 
# pulling in the regular expression and other definitions
definitions_scriptname = sys.argv[1]
def_module = imp.load_source('', definitions_scriptname)
logfile = None
if hasattr(def_module, 'logfile'):
logfile = def_module.logfile
 
# spawn an instance of the shell
c = pexpect.spawn(def_module.shell, drainpty=True, logfile=logfile)
atexit.register(force_shell_termination, shell_process=c)
 
# set timeout for all following 'expect*' calls to 2 seconds
c.timeout = 2
 
# ensure that the shell prints the expected prompt
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
 
 
# run a command
c.sendline("sleep 30 &")
 
# parse the jobid and pid output
(jobid, pid) = shellio.parse_regular_expression(c, def_module.bgjob_regex)
 
# ensure that the shell prints the expected prompt
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
# The job needs to be running when we call kill
proc_check.count_children_timeout(c, 1, 1)
 
# Run the kill command and kill the sleep process in the background
c.sendline(def_module.builtin_commands['kill'] % jobid)
 
# ensure that the shell prints the expected prompt
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
# ensure there is enough time for the process to be killed
time.sleep(.5)
 
 
 
# check the proc file that the process has actually been stopped
# the proc file should not exist
assert not os.path.exists("/proc/" + pid + "/stat"), 'the process was not \
killed'
 
 
# end the shell program by sending it an end-of-file character
c.sendline("exit");
 
# ensure that no extra characters are output after exiting
assert c.expect_exact("exit\r\n") == 0, "Shell output extraneous characters"
 
# the test was successful
shellio.success()
/Classwork/CS3214 - Computer Systems/Project 2 - Extensible Shell/eshtests/reduced/stop_test.py
0,0 → 1,77
#!/usr/bin/python
#
# stop_test: tests the stop command
#
# Test the stop command for stopping a process by its pid.
# Requires the following commands to be implemented
# or otherwise usable:
#
# stop, sleep
#
 
 
import sys, imp, atexit
sys.path.append("/home/courses/cs3214/software/pexpect-dpty/");
import pexpect, shellio, signal, time, os, re, proc_check
 
#Ensure the shell process is terminated
def force_shell_termination(shell_process):
c.close(force=True)
 
#pulling in the regular expression and other definitions
definitions_scriptname = sys.argv[1]
def_module = imp.load_source('', definitions_scriptname)
logfile = None
if hasattr(def_module, 'logfile'):
logfile = def_module.logfile
 
# spawn an instance of the shell
c = pexpect.spawn(def_module.shell, drainpty=True, logfile=logfile)
atexit.register(force_shell_termination, shell_process=c)
 
# set timeout for all following 'expect*' calls to 2 seconds
c.timeout = 2
 
# ensure that shell prints expected prompt
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
 
 
# run a command
c.sendline("sleep 30 &")
 
# pull the jobid and pid from the background process printout
(jobid, pid) = shellio.parse_regular_expression(c, def_module.bgjob_regex)
 
# ensure that the shell prints the expected prompt
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
 
 
#The job needs to be running when we call stop
proc_check.count_children_timeout(c, 1, 1)
 
# send the stop command to the process
c.sendline(def_module.builtin_commands['stop'] % jobid)
 
#Ensure that sleep has enough time to stop before we read its
#/proc/ pid /stat file.
time.sleep(.5)
 
 
 
#Ensure that sleep is now stopped in the background, and is not
#the foreground process.
assert not proc_check.check_pid_fgpgrp(pid), \
'Error: process is in the foreground'
assert proc_check.check_pid_status(pid, 'T'), 'Error: process not stopped'
 
#check the prompt prints
assert c.expect(def_module.prompt) == 0, "Shell did not print expected prompt"
 
 
 
c.sendline("exit");
assert c.expect_exact("exit\r\n") == 0, "Shell output extraneous characters"
 
shellio.success()
/Classwork/CS3214 - Computer Systems/Project 2 - Extensible Shell/eshtests/reduced.tst
0,0 → 1,9
= Reduced Tests
6 reduced/ctrl-z_test.py
6 reduced/ctrl-c_test.py
6 reduced/fg_test.py
6 reduced/jobs_test.py
6 reduced/stop_test.py
5 reduced/bg_test.py
5 reduced/kill_test.py
 
/Classwork/CS3214 - Computer Systems/Project 2 - Extensible Shell/list.c
0,0 → 1,532
#include "list.h"
#include <assert.h>
 
/* Our doubly linked lists have two header elements: the "head"
just before the first element and the "tail" just after the
last element. The `prev' link of the front header is null, as
is the `next' link of the back header. Their other two links
point toward each other via the interior elements of the list.
 
An empty list looks like this:
 
+------+ +------+
<---| head |<--->| tail |--->
+------+ +------+
 
A list with two elements in it looks like this:
 
+------+ +-------+ +-------+ +------+
<---| head |<--->| 1 |<--->| 2 |<--->| tail |<--->
+------+ +-------+ +-------+ +------+
 
The symmetry of this arrangement eliminates lots of special
cases in list processing. For example, take a look at
list_remove(): it takes only two pointer assignments and no
conditionals. That's a lot simpler than the code would be
without header elements.
 
(Because only one of the pointers in each header element is used,
we could in fact combine them into a single header element
without sacrificing this simplicity. But using two separate
elements allows us to do a little bit of checking on some
operations, which can be valuable.) */
 
static bool is_sorted (struct list_elem *a, struct list_elem *b,
list_less_func *less, void *aux);
 
/* Returns true if ELEM is a head, false otherwise. */
static inline bool
is_head (struct list_elem *elem)
{
return elem != NULL && elem->prev == NULL && elem->next != NULL;
}
 
/* Returns true if ELEM is an interior element,
false otherwise. */
static inline bool
is_interior (struct list_elem *elem)
{
return elem != NULL && elem->prev != NULL && elem->next != NULL;
}
 
/* Returns true if ELEM is a tail, false otherwise. */
static inline bool
is_tail (struct list_elem *elem)
{
return elem != NULL && elem->prev != NULL && elem->next == NULL;
}
 
/* Initializes LIST as an empty list. */
void
list_init (struct list *list)
{
assert (list != NULL);
list->head.prev = NULL;
list->head.next = &list->tail;
list->tail.prev = &list->head;
list->tail.next = NULL;
}
 
/* Returns the beginning of LIST. */
struct list_elem *
list_begin (struct list *list)
{
assert (list != NULL);
return list->head.next;
}
 
/* Returns the element after ELEM in its list. If ELEM is the
last element in its list, returns the list tail. Results are
undefined if ELEM is itself a list tail. */
struct list_elem *
list_next (struct list_elem *elem)
{
assert (is_head (elem) || is_interior (elem));
return elem->next;
}
 
/* Returns LIST's tail.
 
list_end() is often used in iterating through a list from
front to back. See the big comment at the top of list.h for
an example. */
struct list_elem *
list_end (struct list *list)
{
assert (list != NULL);
return &list->tail;
}
 
/* Returns the LIST's reverse beginning, for iterating through
LIST in reverse order, from back to front. */
struct list_elem *
list_rbegin (struct list *list)
{
assert (list != NULL);
return list->tail.prev;
}
 
/* Returns the element before ELEM in its list. If ELEM is the
first element in its list, returns the list head. Results are
undefined if ELEM is itself a list head. */
struct list_elem *
list_prev (struct list_elem *elem)
{
assert (is_interior (elem) || is_tail (elem));
return elem->prev;
}
 
/* Returns LIST's head.
 
list_rend() is often used in iterating through a list in
reverse order, from back to front. Here's typical usage,
following the example from the top of list.h:
 
for (e = list_rbegin (&foo_list); e != list_rend (&foo_list);
e = list_prev (e))
{
struct foo *f = list_entry (e, struct foo, elem);
...do something with f...
}
*/
struct list_elem *
list_rend (struct list *list)
{
assert (list != NULL);
return &list->head;
}
 
/* Return's LIST's head.
 
list_head() can be used for an alternate style of iterating
through a list, e.g.:
 
e = list_head (&list);
while ((e = list_next (e)) != list_end (&list))
{
...
}
*/
struct list_elem *
list_head (struct list *list)
{
assert (list != NULL);
return &list->head;
}
 
/* Return's LIST's tail. */
struct list_elem *
list_tail (struct list *list)
{
assert (list != NULL);
return &list->tail;
}
 
/* Inserts ELEM just before BEFORE, which may be either an
interior element or a tail. The latter case is equivalent to
list_push_back(). */
void
list_insert (struct list_elem *before, struct list_elem *elem)
{
assert (is_interior (before) || is_tail (before));
assert (elem != NULL);
 
elem->prev = before->prev;
elem->next = before;
before->prev->next = elem;
before->prev = elem;
}
 
/* Removes elements FIRST though LAST (exclusive) from their
current list, then inserts them just before BEFORE, which may
be either an interior element or a tail. */
void
list_splice (struct list_elem *before,
struct list_elem *first, struct list_elem *last)
{
assert (is_interior (before) || is_tail (before));
if (first == last)
return;
last = list_prev (last);
 
assert (is_interior (first));
assert (is_interior (last));
 
/* Cleanly remove FIRST...LAST from its current list. */
first->prev->next = last->next;
last->next->prev = first->prev;
 
/* Splice FIRST...LAST into new list. */
first->prev = before->prev;
last->next = before;
before->prev->next = first;
before->prev = last;
}
 
/* Inserts ELEM at the beginning of LIST, so that it becomes the
front in LIST. */
void
list_push_front (struct list *list, struct list_elem *elem)
{
list_insert (list_begin (list), elem);
}
 
/* Inserts ELEM at the end of LIST, so that it becomes the
back in LIST. */
void
list_push_back (struct list *list, struct list_elem *elem)
{
list_insert (list_end (list), elem);
}
 
/* Removes ELEM from its list and returns the element that
followed it. Undefined behavior if ELEM is not in a list.
 
It's not safe to treat ELEM as an element in a list after
removing it. In particular, using list_next() or list_prev()
on ELEM after removal yields undefined behavior. This means
that a naive loop to remove the elements in a list will fail:
 
** DON'T DO THIS **
for (e = list_begin (&list); e != list_end (&list); e = list_next (e))
{
...do something with e...
list_remove (e);
}
** DON'T DO THIS **
 
Here is one correct way to iterate and remove elements from a
list:
 
for (e = list_begin (&list); e != list_end (&list); e = list_remove (e))
{
...do something with e...
}
 
If you need to free() elements of the list then you need to be
more conservative. Here's an alternate strategy that works
even in that case:
 
while (!list_empty (&list))
{
struct list_elem *e = list_pop_front (&list);
...do something with e...
}
*/
struct list_elem *
list_remove (struct list_elem *elem)
{
assert (is_interior (elem));
elem->prev->next = elem->next;
elem->next->prev = elem->prev;
return elem->next;
}
 
/* Removes the front element from LIST and returns it.
Undefined behavior if LIST is empty before removal. */
struct list_elem *
list_pop_front (struct list *list)
{
struct list_elem *front = list_front (list);
list_remove (front);
return front;
}
 
/* Removes the back element from LIST and returns it.
Undefined behavior if LIST is empty before removal. */
struct list_elem *
list_pop_back (struct list *list)
{
struct list_elem *back = list_back (list);
list_remove (back);
return back;
}
 
/* Returns the front element in LIST.
Undefined behavior if LIST is empty. */
struct list_elem *
list_front (struct list *list)
{
assert (!list_empty (list));
return list->head.next;
}
 
/* Returns the back element in LIST.
Undefined behavior if LIST is empty. */
struct list_elem *
list_back (struct list *list)
{
assert (!list_empty (list));
return list->tail.prev;
}
 
/* Returns the number of elements in LIST.
Runs in O(n) in the number of elements. */
size_t
list_size (struct list *list)
{
struct list_elem *e;
size_t cnt = 0;
 
for (e = list_begin (list); e != list_end (list); e = list_next (e))
cnt++;
return cnt;
}
 
/* Returns true if LIST is empty, false otherwise. */
bool
list_empty (struct list *list)
{
return list_begin (list) == list_end (list);
}
 
/* Swaps the `struct list_elem *'s that A and B point to. */
static void
swap (struct list_elem **a, struct list_elem **b)
{
struct list_elem *t = *a;
*a = *b;
*b = t;
}
 
/* Reverses the order of LIST. */
void
list_reverse (struct list *list)
{
if (!list_empty (list))
{
struct list_elem *e;
 
for (e = list_begin (list); e != list_end (list); e = e->prev)
swap (&e->prev, &e->next);
swap (&list->head.next, &list->tail.prev);
swap (&list->head.next->prev, &list->tail.prev->next);
}
}
 
/* Returns true only if the list elements A through B (exclusive)
are in order according to LESS given auxiliary data AUX. */
static bool
is_sorted (struct list_elem *a, struct list_elem *b,
list_less_func *less, void *aux)
{
if (a != b)
while ((a = list_next (a)) != b)
if (less (a, list_prev (a), aux))
return false;
return true;
}
 
/* Finds a run, starting at A and ending not after B, of list
elements that are in nondecreasing order according to LESS
given auxiliary data AUX. Returns the (exclusive) end of the
run.
A through B (exclusive) must form a non-empty range. */
static struct list_elem *
find_end_of_run (struct list_elem *a, struct list_elem *b,
list_less_func *less, void *aux)
{
assert (a != NULL);
assert (b != NULL);
assert (less != NULL);
assert (a != b);
do
{
a = list_next (a);
}
while (a != b && !less (a, list_prev (a), aux));
return a;
}
 
/* Merges A0 through A1B0 (exclusive) with A1B0 through B1
(exclusive) to form a combined range also ending at B1
(exclusive). Both input ranges must be nonempty and sorted in
nondecreasing order according to LESS given auxiliary data
AUX. The output range will be sorted the same way. */
static void
inplace_merge (struct list_elem *a0, struct list_elem *a1b0,
struct list_elem *b1,
list_less_func *less, void *aux)
{
assert (a0 != NULL);
assert (a1b0 != NULL);
assert (b1 != NULL);
assert (less != NULL);
assert (is_sorted (a0, a1b0, less, aux));
assert (is_sorted (a1b0, b1, less, aux));
 
while (a0 != a1b0 && a1b0 != b1)
if (!less (a1b0, a0, aux))
a0 = list_next (a0);
else
{
a1b0 = list_next (a1b0);
list_splice (a0, list_prev (a1b0), a1b0);
}
}
 
/* Sorts LIST according to LESS given auxiliary data AUX, using a
natural iterative merge sort that runs in O(n lg n) time and
O(1) space in the number of elements in LIST. */
void
list_sort (struct list *list, list_less_func *less, void *aux)
{
size_t output_run_cnt; /* Number of runs output in current pass. */
 
assert (list != NULL);
assert (less != NULL);
 
/* Pass over the list repeatedly, merging adjacent runs of
nondecreasing elements, until only one run is left. */
do
{
struct list_elem *a0; /* Start of first run. */
struct list_elem *a1b0; /* End of first run, start of second. */
struct list_elem *b1; /* End of second run. */
 
output_run_cnt = 0;
for (a0 = list_begin (list); a0 != list_end (list); a0 = b1)
{
/* Each iteration produces one output run. */
output_run_cnt++;
 
/* Locate two adjacent runs of nondecreasing elements
A0...A1B0 and A1B0...B1. */
a1b0 = find_end_of_run (a0, list_end (list), less, aux);
if (a1b0 == list_end (list))
break;
b1 = find_end_of_run (a1b0, list_end (list), less, aux);
 
/* Merge the runs. */
inplace_merge (a0, a1b0, b1, less, aux);
}
}
while (output_run_cnt > 1);
 
assert (is_sorted (list_begin (list), list_end (list), less, aux));
}
 
/* Inserts ELEM in the proper position in LIST, which must be
sorted according to LESS given auxiliary data AUX.
Runs in O(n) average case in the number of elements in LIST. */
void
list_insert_ordered (struct list *list, struct list_elem *elem,
list_less_func *less, void *aux)
{
struct list_elem *e;
 
assert (list != NULL);
assert (elem != NULL);
assert (less != NULL);
 
for (e = list_begin (list); e != list_end (list); e = list_next (e))
if (less (elem, e, aux))
break;
return list_insert (e, elem);
}
 
/* Iterates through LIST and removes all but the first in each
set of adjacent elements that are equal according to LESS
given auxiliary data AUX. If DUPLICATES is non-null, then the
elements from LIST are appended to DUPLICATES. */
void
list_unique (struct list *list, struct list *duplicates,
list_less_func *less, void *aux)
{
struct list_elem *elem, *next;
 
assert (list != NULL);
assert (less != NULL);
if (list_empty (list))
return;
 
elem = list_begin (list);
while ((next = list_next (elem)) != list_end (list))
if (!less (elem, next, aux) && !less (next, elem, aux))
{
list_remove (next);
if (duplicates != NULL)
list_push_back (duplicates, next);
}
else
elem = next;
}
 
/* Returns the element in LIST with the largest value according
to LESS given auxiliary data AUX. If there is more than one
maximum, returns the one that appears earlier in the list. If
the list is empty, returns its tail. */
struct list_elem *
list_max (struct list *list, list_less_func *less, void *aux)
{
struct list_elem *max = list_begin (list);
if (max != list_end (list))
{
struct list_elem *e;
for (e = list_next (max); e != list_end (list); e = list_next (e))
if (less (max, e, aux))
max = e;
}
return max;
}
 
/* Returns the element in LIST with the smallest value according
to LESS given auxiliary data AUX. If there is more than one
minimum, returns the one that appears earlier in the list. If
the list is empty, returns its tail. */
struct list_elem *
list_min (struct list *list, list_less_func *less, void *aux)
{
struct list_elem *min = list_begin (list);
if (min != list_end (list))
{
struct list_elem *e;
for (e = list_next (min); e != list_end (list); e = list_next (e))
if (less (e, min, aux))
min = e;
}
return min;
}
/Classwork/CS3214 - Computer Systems/Project 2 - Extensible Shell/list.h
0,0 → 1,170
#ifndef __LIST_H
#define __LIST_H
/* This code is taken from the Pintos education OS.
* For copyright information, see www.pintos-os.org */
 
/* Doubly linked list.
 
This implementation of a doubly linked list does not require
use of dynamically allocated memory. Instead, each structure
that is a potential list element must embed a struct list_elem
member. All of the list functions operate on these `struct
list_elem's. The list_entry macro allows conversion from a
struct list_elem back to a structure object that contains it.
 
For example, suppose there is a needed for a list of `struct
foo'. `struct foo' should contain a `struct list_elem'
member, like so:
 
struct foo
{
struct list_elem elem;
int bar;
...other members...
};
 
Then a list of `struct foo' can be be declared and initialized
like so:
 
struct list foo_list;
 
list_init (&foo_list);
 
Iteration is a typical situation where it is necessary to
convert from a struct list_elem back to its enclosing
structure. Here's an example using foo_list:
 
struct list_elem *e;
 
for (e = list_begin (&foo_list); e != list_end (&foo_list);
e = list_next (e))
{
struct foo *f = list_entry (e, struct foo, elem);
...do something with f...
}
 
You can find real examples of list usage throughout the
source; for example, malloc.c, palloc.c, and thread.c in the
threads directory all use lists.
 
The interface for this list is inspired by the list<> template
in the C++ STL. If you're familiar with list<>, you should
find this easy to use. However, it should be emphasized that
these lists do *no* type checking and can't do much other
correctness checking. If you screw up, it will bite you.
 
Glossary of list terms:
 
- "front": The first element in a list. Undefined in an
empty list. Returned by list_front().
 
- "back": The last element in a list. Undefined in an empty
list. Returned by list_back().
 
- "tail": The element figuratively just after the last
element of a list. Well defined even in an empty list.
Returned by list_end(). Used as the end sentinel for an
iteration from front to back.
 
- "beginning": In a non-empty list, the front. In an empty
list, the tail. Returned by list_begin(). Used as the
starting point for an iteration from front to back.
 
- "head": The element figuratively just before the first
element of a list. Well defined even in an empty list.
Returned by list_rend(). Used as the end sentinel for an
iteration from back to front.
 
- "reverse beginning": In a non-empty list, the back. In an
empty list, the head. Returned by list_rbegin(). Used as
the starting point for an iteration from back to front.
 
- "interior element": An element that is not the head or
tail, that is, a real list element. An empty list does
not have any interior elements.
*/
 
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
 
/* List element. */
struct list_elem
{
struct list_elem *prev; /* Previous list element. */
struct list_elem *next; /* Next list element. */
};
 
/* List. */
struct list
{
struct list_elem head; /* List head. */
struct list_elem tail; /* List tail. */
};
 
/* Converts pointer to list element LIST_ELEM into a pointer to
the structure that LIST_ELEM is embedded inside. Supply the
name of the outer structure STRUCT and the member name MEMBER
of the list element. See the big comment at the top of the
file for an example. */
#define list_entry(LIST_ELEM, STRUCT, MEMBER) \
((STRUCT *) ((uint8_t *) &(LIST_ELEM)->next \
- offsetof (STRUCT, MEMBER.next)))
 
void list_init (struct list *);
 
/* List traversal. */
struct list_elem *list_begin (struct list *);
struct list_elem *list_next (struct list_elem *);
struct list_elem *list_end (struct list *);
 
struct list_elem *list_rbegin (struct list *);
struct list_elem *list_prev (struct list_elem *);
struct list_elem *list_rend (struct list *);
 
struct list_elem *list_head (struct list *);
struct list_elem *list_tail (struct list *);
 
/* List insertion. */
void list_insert (struct list_elem *, struct list_elem *);
void list_splice (struct list_elem *before,
struct list_elem *first, struct list_elem *last);
void list_push_front (struct list *, struct list_elem *);
void list_push_back (struct list *, struct list_elem *);
 
/* List removal. */
struct list_elem *list_remove (struct list_elem *);
struct list_elem *list_pop_front (struct list *);
struct list_elem *list_pop_back (struct list *);
 
/* List elements. */
struct list_elem *list_front (struct list *);
struct list_elem *list_back (struct list *);
 
/* List properties. */
size_t list_size (struct list *);
bool list_empty (struct list *);
 
/* Miscellaneous. */
void list_reverse (struct list *);
/* Compares the value of two list elements A and B, given
auxiliary data AUX. Returns true if A is less than B, or
false if A is greater than or equal to B. */
typedef bool list_less_func (const struct list_elem *a,
const struct list_elem *b,
void *aux);
 
/* Operations on lists with ordered elements. */
void list_sort (struct list *,
list_less_func *, void *aux);
void list_insert_ordered (struct list *, struct list_elem *,
list_less_func *, void *aux);
void list_unique (struct list *, struct list *duplicates,
list_less_func *, void *aux);
 
/* Max and min. */
struct list_elem *list_max (struct list *, list_less_func *, void *aux);
struct list_elem *list_min (struct list *, list_less_func *, void *aux);
 
#endif /* list.h */
/Classwork/CS3214 - Computer Systems/Project 2 - Extensible Shell/plugins/README
0,0 → 1,5
 
This directory contains two skeleton examples of plug-ins.
 
The Makefile in ../Makefile builds the corresponding .so files.
/Classwork/CS3214 - Computer Systems/Project 2 - Extensible Shell/plugins/cd.c
0,0 → 1,50
/*
* An example plug-in, which implements the 'cd' command.
*/
#include <stdbool.h>
#include <stdio.h>
#include <pwd.h>
#include <unistd.h>
#include <sys/types.h>
#include "../esh.h"
#include <signal.h>
#include "../esh-sys-utils.h"
 
static bool
init_plugin(struct esh_shell *shell)
{
printf("Plugin 'cd' initialized...\n");
return true;
}
 
/* Implement chdir built-in.
* Returns true if handled, false otherwise. */
static bool
chdir_builtin(struct esh_command *cmd)
{
if (strcmp(cmd->argv[0], "cd"))
return false;
 
char *dir = cmd->argv[1];
// if no argument is given, default to home directory
if (dir == NULL) {
struct passwd *pw = getpwuid(getuid());
if (pw == NULL) {
esh_sys_error("Could not obtain home directory.\n"
"getpwuid(%d) failed: ", getuid());
} else {
dir = pw->pw_dir;
}
}
 
if (chdir(dir) != 0)
esh_sys_error("chdir: ");
 
return true;
}
 
struct esh_plugin esh_module = {
.rank = 1,
.init = init_plugin,
.process_builtin = chdir_builtin
};
/Classwork/CS3214 - Computer Systems/Project 2 - Extensible Shell/plugins/prompt.c
0,0 → 1,23
#include <stdbool.h>
#include <stdio.h>
#include "../esh.h"
 
static bool
init_plugin(struct esh_shell *shell)
{
printf("Plugin 'prompt' initialized...\n");
return true;
}
 
static char *
prompt(void)
{
// the prompt must be dynamically allocated
return strdup("custom prompt> ");
}
 
struct esh_plugin esh_module = {
.rank = 10,
.init = init_plugin,
.make_prompt = prompt
};
/Classwork/CS3214 - Computer Systems/Project 2 - Extensible Shell/stdriver.py
0,0 → 1,213
#!/usr/bin/python
#
#Script: stdriver.py
#Author: Patrick Boyd
#
#Purpose: Run point-valued python test scripts and generate a grade sheet
#
#Description:
#Runs a set of python tests as determined by the contents of the input file.
#The contents of the .txt file should appear as follows:
# = test group 1
# 5 test_worth_5.py
# 10 test_worth 10.py
# 15 test_worth_15.py
# = test group 2
# 20 test_worth 20.py
# 25 test_worth 25.py
# ...
#
#These tests will then be spawned into their own subprocesses and ran,
#and their results will be recorded. If the verbose option is enabled,
#error information will be displayed.
#
#
#
 
import getopt, os, sys, subprocess, re
 
# add directory in which script is located to python path
script_dir = "/".join(__file__.split("/")[:-1])
if script_dir == "":
script_dir = "."
if script_dir not in sys.path:
sys.path.append(script_dir)
 
verbose = False
output_spec_file = "./eshoutput.py"
plugin_directory = ""
test_base = "./eshtests/"
milestone_test_file = "milestone.tst"
basic_test_file = "basic.tst"
reduced_test_file = "reduced.tst"
advanced_test_file = "advanced.tst"
testfilter = None
 
def usage():
print """
Usage: python stdriver.py [options] [tests1.tst tests2.tst] ...
-m Run milestone tests
-p plugin_dir Run plugins from the supplied directory
-b Run basic tests
-v Verbose
-h Show help
-o outputspec Run using this output spec file
-t testname Run only tests whose names contains 'testname'
-l List available tests (not implemented)
-a Run advanced tests
"""
 
try:
opts, args = getopt.getopt(sys.argv[1:], "ahvmrbo:p:t:", \
["help", "outputspec=", "test="])
except getopt.GetoptError, err:
# print help information and exit:
print str(err) # will print something like "option -a not recognized"
usage()
sys.exit(2)
 
for o, a in opts:
if o == "-v":
verbose = True
elif o in ("-h", "--help"):
usage()
sys.exit()
elif o in ("-t", "--test"):
testfilter = a
elif o in ("-m"):
args = [test_base + milestone_test_file]
elif o in ("-b"):
args = [test_base + basic_test_file]
elif o in ("-a"):
args = [test_base + advanced_test_file]
elif o in ("-r"):
#args = [test_base + reduced_test_file]
print "-r is no longer allowed"
usage()
sys.exit()
elif o in ("-p"):
plugin_directory = a
elif o in ("-o"):
output_spec_file = a
else:
assert False, "unhandled option"
 
if plugin_directory != "" and not os.access(plugin_directory, os.R_OK):
print "Directory ", plugin_directory, " is not readable"
print "You must create this plugin directory if you wish to test plugins"
sys.exit(1)
else:
plugin_directory = " -p " + plugin_directory
 
if not os.access(output_spec_file, os.R_OK):
print "File ", output_spec_file, " is not readable"
print "You must create this file and adapt it to match the output of your shell"
sys.exit(1)
 
full_testlist = []
if len(args) == 0:
usage()
sys.exit(1)
 
for testlist_filename in args:
try:
testlist_file = open(testlist_filename, 'r')
test_dir = os.path.dirname(testlist_filename)
if test_dir == "":
test_dir = './'
else:
test_dir = test_dir + '/'
except:
print 'Error: Tests list file: ''%s'' could not be opened.'% testlist_filename
sys.exit(-1)
 
#File input, read in the test filenames
#test information is placed into tuples that are placed onto a 2d list
for line in testlist_file:
 
grps = re.match("^= (.+)", line)
if grps:
testset = { 'name' : grps.group(1),
'tests' : [ ],
'dir' : test_dir }
full_testlist.append(testset)
else:
grps = re.match("(\d+) (.+)", line)
if grps:
points, testname = int(grps.group(1)), grps.group(2)
if not testfilter or testname.find(testfilter) != -1:
testset['tests'].append((points, testname))
 
testlist_file.close()
 
# print full_testlist
 
process_list = []
 
#Run through each test set in the list
for testset in full_testlist:
print testset['name']
print '-------------------------'
#Run through each test in the set
testresults = [ ]
for (points, testname) in testset['tests']:
print str(points) + '\t' + testname + ':',
sys.stdout.flush()
# run test
child_process = subprocess.Popen(["python", testset['dir'] + testname, \
output_spec_file, plugin_directory],\
stderr=subprocess.PIPE, stdout=subprocess.PIPE)
test_passed = child_process.wait() == 0
 
# build result list
testresults.append((points, testname, child_process, test_passed))
#if: test passed
if test_passed:
print ' PASS'
else:
print ' FAIL'
print ""
testset['tests'] = testresults
 
 
#Grade sheet printing. It prints each individual test and the points awarded
#from that test, the points awarded from each set of tests, and the total
#points awarded over the entire test.
 
#Run through each set of tests in the list
testset_points = 0
testset_points_earned = 0
#Run through each test in the set
for (points, testname, child_process, test_passed) in testset['tests']:
testset_points += points
points_earned = points
if not test_passed:
points_earned = 0
 
print '\t%s\t%d/%d' % (testname, points_earned, points)
testset_points_earned += points_earned
print '-------------------------'
print testset['name'] + '\t' + str(testset_points_earned) + '/' + \
str(testset_points)
 
 
 
#Verbose printing. If the verbose option was enabled, print the error
#information from the tests that failed.
if verbose:
print '\nError Output'
print '-------------------------'
for testset in full_testlist:
for (points, testname, child_process, test_passed) in testset['tests']:
if not test_passed:
print testname + ':'
(stdout, stderr) = child_process.communicate()
print stdout, stderr