/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 |
+LsoÀ°d& |
+·}$ er´ÂÁ |
+GJ¢%xÂëÁ s©ð/DÏoÌX'ظ1Ò Åp[ð°¶hPàádiJ'Og»¾h¸¾[á#UhYèì$<Ö |
+PÉÙèò¤#x9°»±-ËÙÙp[)Pezé |
+ºà¹d" `é¢åÎÿÞ Ç«ó¿º4¼0YD®ë$[ 4J¡±cI«N¢»09L&G³ÇÏ |
+¢ ¸x.<1.Ë´@Ó×8Ø>¶Î |
+iºìóAÊ|yVa1ÆÊû%p |
+]ñ L~sQO¦xþL ÉÍI<á ×ÍÖªqÙLÏ£¾ì !9øNr*¼û OÁ9_Á$åüHqã~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ÕÎIA÷ðÀJR?Py27aÔñw¾ïCÝàyüÓ±?r%o%0ÅÐKú0§2e+ýÏß·NÖ;Nÿ*ÿÁú¦Ý«ô¥nu¨`Jr &¼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áýÜt5üY7¶vÉ Ä}!Ä°kÓl§fwM"¯7I%¢7ú48¹ |
+Ø××Âæ {¶Dج[ù /æjew 0sÅc¡Ý ÷bÓ |
+G'E'Ú+â¥ÙÀ |
+7I¸ÃÃ%$à<8ú&°sR> };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ÝUYÑ«}qÚ?ùòû&QÛà9ÆJm·§âÀÊ-i ídh\ØóPÑwIÝMßÁÖÔÎÄRrt=Ø]ÕÔ[Pó±xâY»¢£®uãxºá. ¼æqªÁ"lrº^3{Û¬Pë±êvD50ãÔÌÐ2ÚêdzήÃÌ¥Îd«k«½dy× d·«Z¢ø¼è»FG¿×Õ7«êF×}é]دdeSmøE3ÏòhÓúêõd3vbè@ |
+ð-ÎTô¾K±ÑÁIÄ*þ[je ÛK;áªmÝlFè½Íþ¿qà7Àk¤2¿yx3ÑÁµ9ͦ¥ú,<5ÙµyLGGwöRÓ·Þ£Ï%z$ÇEDú»¯ÎöGî[¹ûÖ»3öÖ¿¤5³©Ú9ëo]ûËÇO[má¦^#$ÑÝÍÇÕ |
+rg ~ñ° 6ñ ´Ùü DidiB#ÎR`S öR£(éÆƯø¶}áÖ¡MûþÀat9Gë,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ë|²æüP0ÊLSKÈÇ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ÒWq7á×>8ÁÕÝêöZÁ}4{,ÈÛL$à3sø1ÍF^ð¾³Q;!JãëÏäò çò·Õѵ×vóê3¿¹uur»?NÛôH!>@¾| {æwA1!L¤°Qô+Ía}j;LàpAÁ[%Ñó¢Ø¨ºçðSbáý.·;cû-cé½ÌÐmÃuÐ>å®ò¡<ã̺`ÞW4cYôT`5ùyeüFªª!ªz§ÈBν_¤Ô{¦©v;GµaV1«ÆÙ |
+¡ì;¢¼Ù |
+¿R|?gW ´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Â{3SÇJH¥4ÇÎæh» 0&£dDéè¢/À"÷U " òD×Q ÷A¬ V2güí!MMv2"7ÆósFy2ó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] _pin4Q_¥WöøϦoMÃs-Åy |
+0ÿWó |
+Æ |
+âÀ(Ñ·òåIÔ±léÝr6)Æ×ñd ¬E÷YÃNC±S ÂͬçCÇÀ¡ »2']|¥ë4¼µf:«»9ÓIðä< |