From fe9b92c6f1dfe9f50d629563ea50e467b59da67f Mon Sep 17 00:00:00 2001 From: uralbash Date: Tue, 15 Feb 2011 18:37:15 +0500 Subject: [PATCH 01/13] first commit --- README | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 README diff --git a/README b/README new file mode 100644 index 0000000..e69de29 From e3c639ff5f74503334f7ed667151d13e30606047 Mon Sep 17 00:00:00 2001 From: uralbash Date: Fri, 18 Feb 2011 01:03:59 +0500 Subject: [PATCH 02/13] add practice 1 --- README | 1 + practice1/README | 9 +++++++++ 2 files changed, 10 insertions(+) create mode 100644 practice1/README diff --git a/README b/README index e69de29..3cba116 100644 --- a/README +++ b/README @@ -0,0 +1 @@ +Репозитарий практик. Здесь выкладываются задания для их самостоятельного выполнения студентами. diff --git a/practice1/README b/practice1/README new file mode 100644 index 0000000..f036157 --- /dev/null +++ b/practice1/README @@ -0,0 +1,9 @@ +Задачи на практику №1: +1 - зарегистрироваться на github.com +2 - установить git на компьютер, создать rsa ключ и активировать его на сайте +3 - скопировать репозитарий практик на локальный компьютер +4 - создать текстовый файл(в этой папке), где имя файла будет фамилия и инициалы студента написанные слитно в транслите + Пример: + Студент: Иванов Сергей Анатольевич + Имя файла: IvanovSA.txt +5 - сохранить изменения в локальном репозитарии и отправить их в репозитарий практик на github.com From 7edf502c023d39b60e0e115ef52a6a902266dcd4 Mon Sep 17 00:00:00 2001 From: uralbash Date: Sat, 19 Feb 2011 22:42:15 +0500 Subject: [PATCH 03/13] add file --- practice1/SvintsovDV | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 practice1/SvintsovDV diff --git a/practice1/SvintsovDV b/practice1/SvintsovDV new file mode 100644 index 0000000..e69de29 From ec529c83794939cd47d742b3732cff8220f14076 Mon Sep 17 00:00:00 2001 From: uralbash Date: Sat, 19 Feb 2011 23:06:34 +0500 Subject: [PATCH 04/13] add file testForWiki --- practice1/testForWiki | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 practice1/testForWiki diff --git a/practice1/testForWiki b/practice1/testForWiki new file mode 100644 index 0000000..e69de29 From d71b584153187a3908a9774103a0780a033771da Mon Sep 17 00:00:00 2001 From: uralbash Date: Sat, 19 Feb 2011 23:45:11 +0500 Subject: [PATCH 05/13] change README --- practice1/README | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/practice1/README b/practice1/README index f036157..a8fe189 100644 --- a/practice1/README +++ b/practice1/README @@ -1,9 +1,11 @@ Задачи на практику №1: 1 - зарегистрироваться на github.com 2 - установить git на компьютер, создать rsa ключ и активировать его на сайте -3 - скопировать репозитарий практик на локальный компьютер +3 - форкнуть репозитарий +4 - скопировать репозитарий практик на локальный компьютер 4 - создать текстовый файл(в этой папке), где имя файла будет фамилия и инициалы студента написанные слитно в транслите Пример: Студент: Иванов Сергей Анатольевич Имя файла: IvanovSA.txt -5 - сохранить изменения в локальном репозитарии и отправить их в репозитарий практик на github.com +5 - сохранить изменения в локальном репозитарии и отправить их в форкнуты репозитарий практик на github.com +6 - отправить запрос на pull From ae1b155af6cc1f67e51ac2d208bf9ca11a3c0698 Mon Sep 17 00:00:00 2001 From: uralbash Date: Sun, 20 Feb 2011 03:07:30 +0500 Subject: [PATCH 06/13] add practice 2 --- practice1/README | 6 +++--- practice2/README | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) create mode 100644 practice2/README diff --git a/practice1/README b/practice1/README index a8fe189..aa2cc41 100644 --- a/practice1/README +++ b/practice1/README @@ -3,9 +3,9 @@ 2 - установить git на компьютер, создать rsa ключ и активировать его на сайте 3 - форкнуть репозитарий 4 - скопировать репозитарий практик на локальный компьютер -4 - создать текстовый файл(в этой папке), где имя файла будет фамилия и инициалы студента написанные слитно в транслите +5 - создать текстовый файл(в этой папке), где имя файла будет фамилия и инициалы студента написанные слитно в транслите Пример: Студент: Иванов Сергей Анатольевич Имя файла: IvanovSA.txt -5 - сохранить изменения в локальном репозитарии и отправить их в форкнуты репозитарий практик на github.com -6 - отправить запрос на pull +6 - сохранить изменения в локальном репозитарии и отправить их в форкнутый репозитарий практик на github.com +7 - отправить запрос на pull diff --git a/practice2/README b/practice2/README new file mode 100644 index 0000000..f2095cb --- /dev/null +++ b/practice2/README @@ -0,0 +1,2 @@ +Написать программу на яп Python. Подробное описание программы находится в файле с ФамилиейИО студента. +ЗАДАНИЕ НА 2ю ПРАКТИКУ БУДЕТ ВЫЛОЖЕННО ПОСЛЕ ВЫПОЛНЕНИЯ ПЕРВОЙ ПРАКТИКИ!!! From 26503c1e8210c7e6f5bf2c96d2dc06bb30bea2fa Mon Sep 17 00:00:00 2001 From: artmax Date: Fri, 4 Mar 2011 12:52:14 +0500 Subject: [PATCH 07/13] Added KrasilnikovaOV --- practice1/KrasilnikovaOV | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 practice1/KrasilnikovaOV diff --git a/practice1/KrasilnikovaOV b/practice1/KrasilnikovaOV new file mode 100644 index 0000000..e69de29 From 7388d9c14c6be4db24573f20091197b5f6788169 Mon Sep 17 00:00:00 2001 From: uralbash Date: Mon, 7 Mar 2011 13:27:48 +0500 Subject: [PATCH 08/13] added a 4 lecture --- README | 10 +- asd/myTextFile | 4 + lec4/backup.log | 30 +++++ lec4/ex1.py | 12 ++ lec4/ex2.py | 12 ++ lec4/ex3.py | 12 ++ lec4/ex4.py | 16 +++ lec4/ex5.py | 11 ++ lec4/ex6.py | 16 +++ lec4/ex7.py | 65 ++++++++++ lec4/ex8.py | 121 ++++++++++++++++++ lec4/ex9.py | 13 ++ lec4/exA0.py | 34 +++++ lec4/exA1.py | 28 ++++ lec4/get_response.png | Bin 0 -> 53147 bytes lec4/myTextFile | 4 + practice1/KrasilnikovaOV => lec4/tmp/logfile1 | 0 ...1\200\321\205\320\270\320\262\320\260.zip" | Bin 0 -> 143 bytes practice1/README | 11 -- practice1/SvintsovDV | 0 practice1/testForWiki | 0 practice2/README | 2 - 22 files changed, 387 insertions(+), 14 deletions(-) create mode 100644 asd/myTextFile create mode 100644 lec4/backup.log create mode 100644 lec4/ex1.py create mode 100644 lec4/ex2.py create mode 100644 lec4/ex3.py create mode 100644 lec4/ex4.py create mode 100644 lec4/ex5.py create mode 100644 lec4/ex6.py create mode 100644 lec4/ex7.py create mode 100644 lec4/ex8.py create mode 100644 lec4/ex9.py create mode 100644 lec4/exA0.py create mode 100644 lec4/exA1.py create mode 100644 lec4/get_response.png create mode 100644 lec4/myTextFile rename practice1/KrasilnikovaOV => lec4/tmp/logfile1 (100%) create mode 100644 "lec4/\321\204\320\260\320\271\320\273 \320\260\321\200\321\205\320\270\320\262\320\260.zip" delete mode 100644 practice1/README delete mode 100644 practice1/SvintsovDV delete mode 100644 practice1/testForWiki delete mode 100644 practice2/README diff --git a/README b/README index 3cba116..491d116 100644 --- a/README +++ b/README @@ -1 +1,9 @@ -Репозитарий практик. Здесь выкладываются задания для их самостоятельного выполнения студентами. +Репозитарий лекций. +После прослушивания лекций студенты должны знать: + * git и github + * Основы python + * Работа с файлами, их обработка + * Сети + * Веб программирование + * Google App Engine (GAE) + diff --git a/asd/myTextFile b/asd/myTextFile new file mode 100644 index 0000000..2452241 --- /dev/null +++ b/asd/myTextFile @@ -0,0 +1,4 @@ +bla bla bla... +123 +sqdasdasd + diff --git a/lec4/backup.log b/lec4/backup.log new file mode 100644 index 0000000..f307191 --- /dev/null +++ b/lec4/backup.log @@ -0,0 +1,30 @@ +2011-03-05 10:11:34.825054 + +successfully +================================================== +2011-03-05 11:21:46.999648 + +successfully +================================================== +2011-03-05 11:22:17.124585 + +successfully +================================================== +2011-03-05 11:22:39.630096 + + +[Errno 2] No such file or directory: 'backups/myTextFile' +================================================== +2011-03-05 11:31:07.920140 + +successfully +================================================== +2011-03-05 12:32:36.462645 + +successfully +================================================== +2011-03-05 12:33:23.959022 + + +[Errno 2] No such file or directory: 'backups/myTextFile' +================================================== diff --git a/lec4/ex1.py b/lec4/ex1.py new file mode 100644 index 0000000..6a90452 --- /dev/null +++ b/lec4/ex1.py @@ -0,0 +1,12 @@ +# coding=utf8 +""" + Лекция 4. Работа со строками и файлами + Пример 1: + Вывод содержимого файла посимвольно +""" +filename = "myTextFile" + +f = open(filename) +for char in f.read(): + print char + diff --git a/lec4/ex2.py b/lec4/ex2.py new file mode 100644 index 0000000..c07626e --- /dev/null +++ b/lec4/ex2.py @@ -0,0 +1,12 @@ +# coding=utf8 +""" + Лекция 4. Работа со строками и файлами + Пример 2: + Чтение из файла, линия за линией +""" +filename = "myTextFile" + +f = open(filename) +for line in f.readlines(): + print line + diff --git a/lec4/ex3.py b/lec4/ex3.py new file mode 100644 index 0000000..6bebbf7 --- /dev/null +++ b/lec4/ex3.py @@ -0,0 +1,12 @@ +# coding=utf8 +""" + Лекция 4. Работа со строками и файлами + Пример 3: Итерация по линиям + +""" +filename = "myTextFile" + +f = open(filename) +for line in f: + print line + diff --git a/lec4/ex4.py b/lec4/ex4.py new file mode 100644 index 0000000..3d9bc9f --- /dev/null +++ b/lec4/ex4.py @@ -0,0 +1,16 @@ +# coding=utf8 +""" + Лекция 4. Работа со строками и файлами + Пример 4: Итерация по линиям без сохранения объекта с дескриптором файл в + переменной + +""" +filename = "myTextFile" + +# Вариант 1 +for line in open(filename): + print line + +# Вариант 2 +for line in file(filename): + print line diff --git a/lec4/ex5.py b/lec4/ex5.py new file mode 100644 index 0000000..d5dc03e --- /dev/null +++ b/lec4/ex5.py @@ -0,0 +1,11 @@ +# coding=utf8 +""" + Лекция 4. Работа со строками и файлами + Пример 5: Чтение из потока stdin + +""" + +import sys +for line in sys.stdin: + print line + diff --git a/lec4/ex6.py b/lec4/ex6.py new file mode 100644 index 0000000..701389a --- /dev/null +++ b/lec4/ex6.py @@ -0,0 +1,16 @@ +# coding=utf8 +""" + Лекция 4. Работа со строками и файлами + Пример 6: Запись в файл + +""" + +filename = "myTextFile" +filename2 = "myTextFile2" + +f1 = open(filename, "r") +f2 = open(filename2, "w") +for line in f1.readlines(): + f2.write(line) +f2.close() +f1.close() diff --git a/lec4/ex7.py b/lec4/ex7.py new file mode 100644 index 0000000..8816839 --- /dev/null +++ b/lec4/ex7.py @@ -0,0 +1,65 @@ +# -*- coding: utf8 -*- +""" + Лекция 4. Работа со строками и файлами + Пример 7: Работа с файлами + +""" + + +filename = "myTextFile" +filename2 = "myTextFile2" +log = "tmp/logfile" + +# открытие и чтение текстового файла построчно +for line in open(filename): + print(line) + +# ведение лога +logfile = open(log, "w") +print>>logfile, "Какой-то текст" +print>>logfile, "Ещё какой-то текст" +logfile.close() +# проверка, открыт ли файл +print logfile.closed + +# обработка ошибки открытия файла +try: + myfile = open("несуществующий файл") +except IOError, err: + print err.strerror + +# создание и использование временного файла +# файл автоматически удаляется, как только он будет закрыт +import tempfile +myfile = tempfile.TemporaryFile(bufsize = 0) +print myfile.name # полный путь +for i in range(10): + print>>myfile, i +myfile.seek(0) +print("Сейчас во временном файле:\n" + myfile.read()) +myfile.close() + +# копирование файлов +import shutil +shutil.copyfile(filename, "123") + +# удаление файла +import os +os.remove(filename2) +os.remove("123") + +# перезапись содержимого файла +myfile = open(log, "w") +print>>myfile, "текст" +myfile.close() +# собственно перезапись +myfile = open(log, "r+") +data = myfile.read() +data += "добавленный текст" +myfile.seek(0, 0) +myfile.write(data) +myfile.truncate(myfile.tell()) +myfile.close() +for line in open(log): + print line +os.remove(log) diff --git a/lec4/ex8.py b/lec4/ex8.py new file mode 100644 index 0000000..5a73dbd --- /dev/null +++ b/lec4/ex8.py @@ -0,0 +1,121 @@ +# -*- coding: cp1251 -*- +""" + Лекция 4. Работа со строками и файлами + Пример 8: Обработка файлов + +""" +import os +import random +import linecache +import stat +import time +import datetime +import shutil + +filename = "myTextFile" +filename2 = "myTextFile2" +log = "tmp/logfile" +log1 = "tmp/logfile1" +binfile = "get_response.png" + +def _print(argStr): + print unicode(argStr, 'cp1251') + +# чтение строк файла в обратном порядке +for line in reversed(open(filename).readlines()): + print line + +# чтение строк файла в случайном порядке +lines = open(filename).readlines() +random.shuffle(lines) +for line in lines: + print line + +# чтение нужной строки файла по номеру +line = linecache.getline(filename, 2) # вторая строка +print line +line = open(filename).readlines()[1] # вторая строка +print line + +# чтение бинарного файла +bmp_file = open(binfile, "rb") +buff = bmp_file.read(10) # первые 10 байт +print buff +print bmp_file.tell() # текущая позиция в файле. +bmp_file.seek(0) # возврат в начало файла +print bmp_file.tell() +buff = bmp_file.read(2) # первые 2 байта +print buff +bmp_file.close() + +# запись бинарного файла +bmp_file = open(binfile, "rb") +buff = bmp_file.read() +bmp_file.close() +bmp_file = open(log, "wb") +bmp_file.write(buff) +bmp_file.close() + +# некоторые атрибуты файлов +fstat = os.stat(filename) +print stat.S_ISDIR(fstat.st_mode) # признак папки +print stat.S_ISREG(fstat.st_mode) # признак обычного файла +print fstat.st_size # размер файла, в байтах +st_atime = fstat.st_atime # время последнего доступа (число секунд с начала эпохи, 1970 г.) +a,b,c,d,e,f,g,h,i = time.localtime(st_atime) +print datetime.datetime(a,b,c,d,e,f,g) +st_mtime = fstat.st_mtime # время последней модификации +a,b,c,d,e,f,g,h,i = time.localtime(st_mtime) +print datetime.datetime(a,b,c,d,e,f,g) +st_ctime = fstat.st_ctime # время создания +a,b,c,d,e,f,g,h,i = time.localtime(st_ctime) +print datetime.datetime(a,b,c,d,e,f,g) + +# установка некоторых атрибутов +open(log, "w").close() +# задание текущего времени последнего доступа и модификации +os.utime(log, None) +# задание указанного времени последнего доступа и модификации +os.utime(log, (1, 1)) +# снятие и установка атрибута "только чтение" +os.chmod(log, stat.S_IREAD) # поставить read-only +os.chmod(log, stat.S_IWRITE) # снять read-only + +# обработка ошибки удаления файла +try: + os.remove("несущестувующий файл") +except OSError, err: + _print("Ошибка удаления файла.") + +# перебор файлов в каталоге +for filename in os.listdir("./"): + print filename + +# поиск файлов по маске +import glob +[_print(filename) for filename in glob.glob("*.png")] + +# рекурсивный перебор каталогов +for root, dirs, files in os.walk(log): + _print("root: " + root) + if len(dirs): + _print("dirs:") + [_print(dir) for dir in dirs] + if len(files): + _print("files:") + [_print(file) for file in files] + +# создание каталога +os.mkdir("tmp/newdir") +os.mkdir("tmp/newdir/1") +# удаление каталога со всем содержимым +shutil.rmtree("tmp/newdir") # осторожно! + +# переименование файла +open(log, "w").close() +os.rename(log, log1) +# разбор пути (папка, имя файла, расширение) +print "basename: ",os.path.basename(filename) +print "dirname: ", os.path.dirname(filename) +print "split: ", os.path.split(filename) +print "splitext: ", os.path.splitext(filename) diff --git a/lec4/ex9.py b/lec4/ex9.py new file mode 100644 index 0000000..67d18b7 --- /dev/null +++ b/lec4/ex9.py @@ -0,0 +1,13 @@ +# -*- coding: cp1251 -*- +""" + Лекция 4. Работа со строками и файлами + Пример 8: определение каталога запущенного скрипта + +""" + +import os +import sys + +print os.path.realpath(os.path.dirname(sys.argv[0])) +print os.path.realpath(os.path.dirname(sys.modules['__main__'].__file__)) + diff --git a/lec4/exA0.py b/lec4/exA0.py new file mode 100644 index 0000000..8b8c696 --- /dev/null +++ b/lec4/exA0.py @@ -0,0 +1,34 @@ +# -*- coding: cp1251 -*- +""" + Лекция 4. Работа со строками и файлами + Пример 10: Пример простейшего скрипта для резервного копирования файлов, с ведением лога + +""" + +import shutil, sys, os, datetime + +# каталог запущенного скрипта +path = os.path.realpath(os.path.dirname(sys.argv[0])) +print path + +# путь к файлу лога (рядом с самим скриптом, в той же папке) +logpath = path + "/backup.log" + +# открытие файла лога на добавление (если файла нет, он будет создан) +logfile = open(logpath, "a") + +# записываем в лог текущие дату и время +print >> logfile, datetime.datetime.now() +print >> logfile, '' + +# копирование файла поверх существующего (бэкап) +try: + #shutil.copyfile("\\\\Comp1Name\\e$:\\Folder\\file.ext", "\\\\Comp2Name\\c$:\\Backups\\file.ext") + shutil.copyfile("myTextFile", "backups/myTextFile") + print >> logfile, "successfully" +except: + print >> logfile, sys.exc_info()[0] # тип ошибки + print >> logfile, sys.exc_info()[1] # текст ошибки +print >> logfile, '==================================================' +logfile.close() + diff --git a/lec4/exA1.py b/lec4/exA1.py new file mode 100644 index 0000000..43de118 --- /dev/null +++ b/lec4/exA1.py @@ -0,0 +1,28 @@ +# -*- coding: utf8 -*- +""" + Лекция 4. Работа со строками и файлами + Пример 11: Архивация файлов + +""" + +import sys +import zipfile + +# путь к файлу архива +arch = u'файл архива.zip' + +# создание и открытие файла архива, для записи со сжатием +# (для добавления файлов в существующий архив используйте 'a' вместо 'w') +f = zipfile.ZipFile(arch, 'w', zipfile.ZIP_DEFLATED) + +# путь к архивируемому файлу +name = u'myTextFile' + +# путь к архивируемому файлу, как он будет выглядеть в архиве +nameA = (u'zippedFile') + +# архивация +f.write(name, nameA) + +# закрытие файла архива +f.close() diff --git a/lec4/get_response.png b/lec4/get_response.png new file mode 100644 index 0000000000000000000000000000000000000000..80ee629117e6e15542a1d9aae77a5d0cdb9022e1 GIT binary patch literal 53147 zcmbSyWl&vFv*ksCdkF6CF2P-b>&4wYcyI^=mk`|D-Q9z`2M_Mw{xExo%}%jy%Rq#%WifQJAAfsnsQi>rV@5VIfBr;d9P!9H7q)k7dF_}i-YCDC3t)G(s;$bbe@WV9Ja3=1P1mWlry@jlae11e=V zTBQ>P+K6EOY>hLuqA_-bdKA*4d0bcOENEkoeOc*akUeA9Fo6?8EUFAV3*{8C;Jst`Q=mp&lCu(G+-mqFZ{5L zsJUF1co=T2)fdKFdY2+iMpc5B(I{yC$!VuTTuC4_3wKgJxnFrOJC%LIzQ10U<$uMw z|9phWGvNv4df%h`P5oKE$WMXOJ9>~KYE~CS)2oB1-F*b7AM^K!U$+@r9q|Y&)hb#s zl@zpZcPJUGM_Um;HbBeweva_c(;NeuXxZ$8?Uwk<#)Xjt2bG3E38pcck-mpx`PlR9 zbgF!JAJX^y-cH!2XyWgrC=jvGVQ>3K=CM-w?1MF0n{tmP^6vQe8a0M>$OovVKcP`M zTO@rT5DDmuxQN=f^pgyCT}&zb!Tl$~4h@m;VmL1Gewe%94(MD-lL&#De#=NnAI`hv zKRO)!zp>;aJKQlP3TVjS$a1AawmsACV*V<=^q!0XO0yTmNd}k}{0RaLjrlyB~n@T-oiw zfB~3zY!ImX&woEuT0#h7Ko3*{u`~xyTnj}%W{7{Y>9~RpS_^}Yu zaB#Q4#!E1_wt&b!115}=0>7pCZ8L8uDh@OGQYU;-U)Vgt?vE2Ez*&eQ?C5>fzJWj9 zIzN@o3qXJ(hNt*ujA96#*)_g=G5NN`eV8yR&Rd28Za3x)Tb?Le`c2fQ0~<1Pc;o5% z2^0yUVOBa%_i=IFy(A2$(8!vzj*`Y_Gchkx?t4NtWz|wiIq6?1f584Syu=(nBKrrD z$$%k0mR63gFWBt#`0x7M3Nt^;+~i6~zv=wt8>kx=5Xv0xxeNlrsLTTygaM7A${~?L zrT)ZOe|oJE{=RfR#_jTx3%DZnrC)0(o$d3T)n-}QSgGnp)zDmU+rJ4k^%^I8l9cKlEfLwpc)zrdju?##LD<~y`68i?T5GQ z{^msbVs(4SFvE_)Q033bMXsMs;v{wdci2ZVn8U%|&a7gT1~kW>-7Xx}@_5s;?05gE zTDCO8n$tyCQ>zKS&lSA#oqfqurU~7r&CT7_EuaUsTMf8!PLstSeb1F|jD7~QIZ)%v zo~p*Vj13IMX)~!z>}K(f70*#bpXX-B2_=a@aiD9D0KDqWtk;n33G{Lj3^B+IN(Oap z1E>tnX613J2Z~|h80M*=Ipt}wRlT(vTL{oC$a@ni*lA~CNoJ{k#1F@)Uv^$J0g^7s zxI8f%{7EBF4f();#8wTS^I20_Q8<>!>+7X{uNX>_N%=M`Xdc)gOsoO;Wp+u3PF+!p zyWyAtJg=o*qRy6=yLFpe7v42;iar2`t^C2lUVmhKG!TNj`{Cb1m$Qc((8i<-N-|^_ z5<$E=b@AYc=Ca%rwvR{UM=PZ^E;yU@?I&XzTHb;iG$Cl9(f~(&VIh8qcWvwTySeJ% zq+S;$OW2R7A5D6je!I>ch11L|I&54(d(+d?_j!Z-TOs1HrzYp~pCMz5t>Hg*9O$yh zS*UAR;zCVT)oI=eow~A;jiMRQ{2abnONRit0(O_3weO(6U`STcI)YA5(L-Zrccmqo zLCK+5%_=4hT!~3H`8QA=pqK|m#qDa&1R5*7L!q6cQj?f6zu`#P!fqP#4Ig7GzARal zHq;~O;gB_G2cx(om)fga1&~sBEVpqWT0-8}K@7kGTZ{P=sFjx!7&KNC=jI!NMiw_@ z(uSfFjj=rG(gNpJo)b9EA82w;hu|Sj=z=ttA(9Oq#vpk-2S&#gr zzo;gWHELAjv?Cv7DdBP!qSBZNdF)IFJNFaMdT^p*@Z5}+I(5q4HMu-tqGa-vi>a|+ zPb}>sScv{KuJmZx?96^LzawUE_K6Wj%`!psm0Nz9Y$<5t6a#gO-irXDpZ>WTY3$p!Um)#=r`wJTjgOlz~ zb_=X8PQxX=5cl~HG3xOAEjD|JZ*hq@n-k+J!CWX#HLk*N_jYSMx8tJ{eN+bWog0^F z$r;!vRpA+dXh$oBvMz1KlfG}}Pnii>ZV_jz{EDuvZ6r3MGan+7ku&7S*-9 zAoM4|%x2uMV{8;XR04uXa6ztY7M|Pu)F2A|DPQ)T5c_R}p59yiXWRMJfICR-v{(w)e>Q=(*XYo2d#9pO9r=*}Iv`24o##fpg69%|2%qm52aZS8~(KoG*nfZIXp z?OE`htpCJ*Up~g*Q*?`Nb|q^>2US*F-JTygigI^_{e^-6LQ%gge$=hLCQhTKsa66m z;hHX-$4rhlPbb1nu{KL+!kepP5sod)<@gXP$Pu^5c=_xT*u{LKQEwqSVxinjA$o}QQg{q{ zls>DSW)F5fP(KvjCG3~UYtycT7%{ju-R;WayCh=|9Nfpf{|bqPywfg>{MF4Vm6*>} zGfA+CXhZ1hyWEeU7`0j1$7Jhgs+<_^*QkGJ;Zg7-!gnLtKpXS#LUAbq@3&i1|F+5g z-RBQvMm#Zfe;03^$hk8G39vaSNRM$P53Ce|+XC4YDTLwdUhcaGE)lOrWeMy~wr1lp zJ14%S+PE*FzFSaZs}mL$dUaegNP9{ zg}{$XSj@_;vem`c4hTVkxP%s=q0%!kS)rT~0h{+A*lQ)wAg_@e# z)BzlMfTp8G9hOi%qfsQ9ao7;l%QEU29|>D-UEw`QiCB07aV|3I{pD)(Hg0|t8oLgu zc@dH{s9Kr~#lD(l(d{$Ddg5PLUO-6t(fyFoTp(|BZLtxzmbPx?Dj{6@zunuM3i0c1@dhel6F$`0DbX6=E-$+O!Rj6|8Q-(}Ih~P_7FkNhd$%_K181 zT3uY-T*z!uKu7RO`rS$#)FemqTDjL=Q3$T=E{2v72$~p9s=?3xnLghGQ)etWDsDm9 zME+iXK!I?maQ!3q{w42NRH6x0rA;v<>tcm}s-KMbO7HPLrj>J*`&y)W=B2tOQ-l-_4+hrNWzU#j)f|=YrUTFWs%nPO zWh_288Yc$L{MzGew#YhIf7MG*kMd=J0G$~@A?-bFKeMBjV~pk}jHa4ExH{9y*)@oW z!Om}E@%G`8pD>sPwQ(LUQPwJ&Dq2uee-mUj!~j+lihm@iw#J5aQ$Ir1A}F*Q{*#oxr9p{jQcsdkI%@cH`-&rlmspH$Mg;VVSMyY$Cn zwXF)Lnyuk*&N;0hG)amIQR{=LfLe7ns$uDQ{GVvX(zJJ&;GcQ!`0smB9rz8FSOh!R z-KK1=xF0}yARu^!$x(W^x-IiN*KJM3doRqD4mahLwqmVKP!c2bt|8p^U3d0SMh->^ zEmbz#F$`0E&-D3>K@`KB9b0n8fbT_*4+uiT0^4t6U?N)K0>97y@!zaOvC{Er_h%mF zPp5NIlN;t8yO;@K%@`EqSWg0+IheO41qIjoq;K^)Z*OsqJG93{bT%>T&|jz9szN=j;)O1f%lD)Abc7oF|J zL8?92S6|>_hfQtpX6Gk{hX>Xd1_t_<3Sx_r0Bw&L7KN+f`Gj~^-tn}R18tMRmZM!x zHmHU>jJzbyVLx5s`t6=+ZBYP$@%J%zbP3x&o=Q6r0!DNx}}F(0jWGF;+aS#DeA@5Oi+3Yg{i|H$6{uPNVH^m*6&`WzET_!ScM2aqDNaQ(dg?@X~9 z=jM3PVYW~{ynkj!1taX{?sTQPn&lTvPft(k4_aEAlirlhpO3Jwk?3rb|r`p!ClGdMVy#p`;IIX|8EcdMV~VdQexo!`fBPeIWzh~P$Qmu(^Kp#8I*;y(1>BPB3h7K z46`uX96h9bADm6MFk6mNm&zIezkcWvna#9t^y`gDbTy)SfwOgNrnsJ@YCtb7ME)GR zFQ4_M5t&0=*kk<1_p2@3XN?Zp2~~rf(`!;J&OVpKVwKk;1{In#g{sg63`v@tCeNs{ z6NOXP#6Pr=)?XhQFw49H|EOq{NlhFPqJPOzLb`;v6!yPLMRZ1~44af*NF|#$kdf83 z_OGQafzIijmkXd85=ey7Xg9g znqZg*cn+N6LN|~wTn_fRet!|QI9^=^gd_$*kJs;QWj5zSM7&23$S6wsb$>nVsgyH|nIWjOXY>o(b75#1 zMX|_v@Prp3F>#7JvC>%v*5*# zT4MtJ!;HG@pL%rX9|Hp-F41YEuaM)}@Dcj&Mkz za3ECtB11Rb>z}{++SIfa;M3y3oIvgUy3|n^1Na42m+Z!Tsn?t1axlJl1JVoTyp3@O zG4vD~#4hK@>NnN3)~O{ttISkCP8{Cij)`3Bl+w0%u;Q<^_JGhjm#bzl)(XjNRX62sSxuWOTZ~!q47QQvnL> zt!_!*vKp}cG5mu5sbnx>wzkJBGGX%)pO1jc)#!cIy)JK|y)dAlq^cBbCB`YDR8_d_ z=OU6cy%u8Tm%4Z4Yx8`D2C6*iTh# z{z{n+asR07=p$(-roQk7&b?hK7(9<1@2Nk3WLjaObv@s9ZQny1TU@;=XEB;sDd z;Bhjy;%=c)v!O5*^~cFC6UTiZUk+r=to^?9 zor^h*>yGq6c*-B zOU{~l8NjXz>uRKJJ42^+dZ|qbRb9Ubnr=^sMKYsOTne8Yry2vb1<4u&x}{B|I1}e$ zpr(2MZbLZ%+A6t}p2*mcU!U^GW7VS7$)w*1<|4YAVBo#JyB;)4N8n4m%mdF#1_HVkss!>I)jFry+ zXz-pMn{;}3u(!YGbFn-excC-J9F;@p8Fh%o_)A7Xs6DzYnlWV3Yj_epG)Nsv5QlWG zUAg;en%zfFpat@6PZgG#YFz@3k&v@O%5ret@B9pH>9W`lNFmmHj*Te6X0hfKorF z0O>)~KYg)XX?&W6N~Zg#q)Zv7jk;WK8BwKu*V!ivi7<-mtj-ZQD#jf8tG0Pn8 zy^WLsM4iqs(PB6sykOoENa9c}(3aWbs45luUrhDGI`b^ZHtX|b(mP?*LJxPuTNg)hIecIiIpw)ekgRE zLcDa<2bb6T*)}U7uINOU%i{0nAhdyReO=G6!4hxYd-s3FuLs?UM{?O&{*^c^Zi(ym zXKL24qk$~B-1~FFJqo$$c=a;(wqMuAL)CH9cIRrB`KiTqn#VJF5cs|0S!HI;ENhI$ zGzrN-Xg{gUugs#84!2y=x~fssDnqg|qO1c#P?BVy6Wc|uq@RxYsQ(FzE(up{IjZQ= zW?;hPn&*BtF4gmq-SVaw>-4!YRaaLz7;V}4@*pP5ukLUzKxA{xuj_H6q39l6bU|+6 zkA2`LbE;bc+!e~@*=g6w{yefUXwr5-RRHCy5{M%H!*peR)#0T7LG<8v$EY$XVI@UB zWru=>+xEaLEKtgW%c);2H`jj~t}+mBI`)0ITPosVMi=#BeitZQ$yVAZjH%1~Vm8xd zpG8Z<%zJ+@@SXG{rWh<>$tne#CP8Rn;s`gE9G%ZfR2lXTX4|JHi8|@bvBUO-R1~Iy zVsHiR3J%jWETq>9dDEKJ6<@X_=WQpYazu#gdH*;`qF}ogF4c6sc-QD&^&e0 zH!39B>YKFS$YaG{+*kXdG!)2!u4E9@W9m0)8GGEaYp_1hRHX>#S9;E?ZOH5z^F~de zUl4c74KsbCPn5>tz{`+H8p#I=E=)TNi-nMkU&@DD|Mc!=o1%)Mug9!nYpNV#M!$(;`X>%VJmn)>47gD%5a}R z|94aeJM;$y8!q|kpYi9OQOp+F$E2uW5SXe9j6|i;O}`Bu8b#F=z|G1mFMcVc$r7e> zjiN;>Unr@gOW15e6qGTn?_p3P#CYy)u&fjM2Fu1%3#k1dTxQ3&(jm9iO5qRa^1=MX9YiV2e)1i8t_O?S5t?L?O>wi^dquFO))S zOsg4#Q;YIeUa`Xlx0#4y+LBe{EiCLR)a17jvNK0bH7h7{F*VB=|K zx-onTZMXzfoSp#TM{>0S!#uuQ{N)^tkZkZff3vZJ+4c2K0cjNE?0VJ$ zA7{-B^{qBzicqh_zjI4?RJ^1z5(}8<&i&kXsB7hNxbH0g+<4sWThZoXwce;$HbK2z zMZ^8Zc79tPV1o62Y4Rba?4tCi-qkC0U9jtkK+XOI5PJ@4m8=wcFD`d!jT~dY*{{z& z4b)$v3VPm)I^7{MQ#S#H-00AQ*|}MV@vt?mM+a?A`$of|-;EGGz-h;b`Ez8iS?E%} zqgh#JO=qMvw8VdNf1W%4&X13+5idAC{1?H)W^kMsK+~2cKVbKvp`Fy{2J5_!D_n0q ziq33!JYHjXEQNN$7qNW%2H2f;+Z*0yCnuL{A%%P9l8tba^o(+&<4;yszghyRpqsgm zh!^bSOkGBfZz9_lmp(Xj5ph|$B>5tS$k}dfdI{``e35vJ{g6g3w(M@da2Lk})t;_< zo-aW9KyZ^^AG|-1Aj<&XzcF0rDlLnu!M#TOdCK2^!-yTxO^?6!dTVp!16c{@f!K_Y zT6w#g-tX+`0u`&>o0U>ytU$`d(0YL15~R_G>t0;1b-Vj*iT^TAr9YaVfO+M`S@ z_KMGtnbCzVNJC1)m{@^YJ^R)xBD*R!FtTb52HNV?)vim zJ1E`%yn9`7ll8t$S11_yB=Z=Nn?5+bm$+Q%^nf>x?z@Y28l*|}>6+)L;CFAtXVFeB zpx#rQtg0U;Rx*nvf?GMfkL(T5Q>h>5#GE8a@_`xX8whzx%C*S9%<7ev6Shb^ z0zat<$OPeB6j}3661ipF-Q-g3dL1Z)mNhn^=iO2OzIpf~Cul?Ui}-19F^tcrb}wXL2+9pdB!|$Ksg)Q)Aovw|4W|2!P+BD}yBq-@h5u`2!Teu5J+Cs2_F*Ot zKTXsk_6h}Wy>Vg^P5dDb8VK`AI(zRR#9$j1mX6$s`CWt==sXeRSX_jQUpR?)9}F|* zTVe9=O@NX7-NYO&*%e~=GlMpqF42yyxCuG_=tu@n->S^$VG3fJ z7a5;(N{ew&W@UiR21h0Q(`b0VA>JIulrU(Q6H%K3!Il{9iRGGhW}UPlh6=~zKsamS z$XZ3QQ!h_Wc|PU|kC#O0Jr$YIlGiYMqEx*$Rz-^~JT5OUBCbvZ844Nt8#tw`S7f#uC&2Tm^&i<43%tr{kmFh6lvx|x_UJwNT}U3=)AN^lhPG!K zNVEM`r%a+7w-)Tvo$Lhj6xJlEyEarz`!kVyA(XfC^XqUqZ0;Or#_2(h5q>j{##PqU zf4c3wjWH-dkjBv4U*(-;7Vs!e^j4-yfWI1H=>@M({N{9N%G*kaj+{n=LsqYvAIe7N z?*3~T_CLJ;po z^s_Yt?xBSA9nKVtMqo1siRL(Y7#jW^O=6bc{WLWNvHSYRux{z{@)Dup6CCtu*}+s! zU|U;T38C#bH8nMtlRvEN?5Y$P!?NY&<#%Umd~PS2v%D}Iy22hpFbIf<4jY|5*L&kS zP4;GHW({^L;GD*{x3|K(Gn4H0_I9xll%=I5r^^Q5)7Y5FX|qsoHLI(qCx1#fbphJ7 z>!zTje7)cBD^kc985ud6D^Ug3G&ME-_U&^5!fgF<=FH3tP#fFd*_k@LxjkN#l8~@l zYrXwbV*RQE95Uf4g02w3C&UO%w3Ci^OFoARv%C#WV!Ub6iMF`t6^+?rc#} zV}LoM33z@f6s0Yb`}@z$%^~A+rSrO4zdT%C?@v0cHrJF0K#pMoDgXXboyBM(qpX6$ zdYik$WTt@pDN1&h`}sO>P}lSI4xgu+$EV|}zP>*BQ*=YOZfE?lRNx*ZB_w|Q_yKGI z$+Riw@9u7c{aR~!db&aeZxjwI86DjbP`@j5LttSB;%|d!A^~2DiS*;es*s?d!aFz?L;$AZ-`}1c04)HHpOceQc=w?gDw>e5(RPUq zC^`bi5EmCuUMB4R4WKbOpf&=YH{V_!9047WKSfls7&5H|u7**swccVf6Ik&6;)10? z%76Hu56derXP~0myV&d_X(PrpW%B@}!K~kYadU%&jJ#HF6(>i<-k|Dl1>|8TIGon; zRaNIPLT{GVQvRM43@NnPPrw`E3FLx^r7uO%L03I2XOcWqI)#c|GGzH8-dffnRn64qz^>QUU7)_WU z>v@0HVK#~tH1&ABpC#lMjW#kg^x5aBo(mD1S)W23F#l8ztE+MD4e5g02Yj0mnsn$f zEUGvUz!uZE9hkIgf6sM-20-!mfq$ADHUKC<6NQI|=W{=sQ?66ale{9POp>OMiY9nG zEXqP57PK{`hHws6D8k0ZCI;*fkPS-%vv3F0h>lmI!v?VVTlF&VDPSDH{Em)}&U<4m z&ifPX9@kh*x(D0avt=4pi&X|?b`oTIEnetX={T4{1fqMiokOaWvMTmwKi0V_b`ZD zOzZ3G3ly+Zg#0>72qBKJzxj5GeEpo>-2A!USW636bf~|-AE;xmt*y<^&jXgayu7@! z@;sd#^ zug~{ceC|wKTz5zFWmZ;JzyxVrcFP@JO#a7+APsJ}UXtdO!ilrJ{ci45R{P-wA{Oq1oBlAE^~+u)OZi zD)OA-sN{E&itKD{r730rSV0qAUthoC#t7RPOJN6Ci07lSDpR%;IjZA@iZt)O+S=NK zgM$!M;@0NoAwP;_(Hv-K=;9>}-PF;cA!%vp2SAwUqM|u0EG$1I^G;V=oY&huBCr_4 z!@?c`t2#b{14#zTQ8}zMGIDXb4gDkqgTaMvu*KMh^*LvNSG(etkdXNB;e)-sJsc@U znCX9!1$GV&LcrO7{`|SKW6Hq8qW%ggplwGy4D015#pLlZ0gbbp?ek>T_9^4Q+azgvTn4KZCHn^dXScDB*AF&7QG z{XlaLD?%0bLzGlBR5WL3gCr7-JA%;i*4-<3e1!5anC3P2MyQ9(gL0Adpj;-8<-yLKgWb8`WF2CQ$$^a?nE z-@|6euV24@{zS`B0*rR>OB~hkF?~8T9vZ+5t+csUm2`lP5OM4tNSj3-({0d-a zegGu{_$A`cU$Xb7^23XHUIL6-xx&EScNi6;BCQ~=iiEipDW22>|LBcsEx=R5Eq zc@PQ_|3g2v0ZWQpWKB{Mw&>8th7cQDt<`KH1Ox;+I=Y942VBnXXc8(O2Mq~{Fd&Jb zAls$d{+^y3z+Dm%5dmWWuLEeLiks8J#ik@bS2yf*hnIVan&%Z5c=lsBLCu=Hufd1J)=2=X*oIK@2)P3!VpDvPmI%s%Trj zZi)iogoqo29TGm*31C=-caX(i!XEO&hqFbns6@8b%%E#Z8X9S`SRf`G0W{GSiKc4! z=ddZ@w1Ft57yzBI)S;mv01#7_5woL#(myWXdiC}7zuqEE$pcqzztL%D&Fs$$6TfJh z&gX9br`iZugvA|zULceqRP}8tSQ8Z$B~BK*p*CP%2i#Rgdb->xo?)T5l$2s7zsK)T z^g=i2Vs;?N;6lV=$ey;`-QCq?N*Xt>TRH&{;isN3EX&;UB@ph~4nz}{d1o5g*dPiC zgANLTvjE%RY`_Lq%R{Eh2B^qzzTnf76Tp!EYH|6a{5GzMi<<@fQ18Sl)0E!%d?*R2ODklhl|aN1k6?mk(=; zI*XCb>#}AoYVk+MjistT6Qc4A3Q23L4P8P(VoyUBwUHuwY8_svwe+W z$Rp9diGrb~7q0-hWEx1G#N}CXTnTr;1%M6>mf=)2#LBN1SQZ z$a!R0biv1q(vXf(fVb3?dk7$_zn@{vRPwJctF*_R*B8knQvSeLWD0Xo4h9}t9O8<7 zArC?q%<`NZoHm)uHo9|j)7JUGQ5~;kM$2=EW0ZeWRO^q{tNDm(GLE3WvPnm0LodND zDQ(q(H2fYKW!dbnd|RkF&oQ%#Nsoor!`EQUS*KZmsGj6F)Eg2OlVy>Qe;LPWKx9z> zCZy{#fhhwQJB}GfC6m7BmLV1UG;0oXsMvK4u;y87GMbmVXG+ELf4e%c(k^urjE{kd z81kT0ftMPZeGse?dCMgi=;1xGlqU_vz}GuH<|wMko@JOGDJ6r4-~H4+$vm{Uo7n%; zKsndLavpK6craN6#=E&826x;W-10rzCpK0|-{{RNGzHHXeS{uph&W@)!OP;^lH);` zFFTyqswkYNL&urcE5H68Ho#l{*m#r>ME9A1DE%C zFw@C`ypk5?2E5`mE0P@9gfbS%^Uqr>`IYr3Zh=PBiRU z7E@CGKpr%;B_^b=b9r1Zut6T=*$|n`{jC>h+GG(W=etXpbB2za81jBMpTE>==?9!E zR#fU3?&pQ+fwz;qG<10#>>62j1O8Tvr|^!Xm@I|n#_Nc4A3gq}Gwrv^`tH=8C(nbO z${r&M@z&&T`-8JxU-B`6F6uj3fk)exdA^v=Y&fLzI=-uPE$G1nNwhBWjD%E93btOh zUSuqHlJvQNJK&U{MxpY!Sg-FpB60-fnW)#=;_i|a3f6URpZkCFnXMw&z}Rg54AV;u zA;mZZC>_Qkza(i&H-_VLp_E9wcWZ>{N=*jQ7>t|v)Jaa&JKr{ICIht1!azfU-VeiDv) znw=21ds*-$B1g$Yt+i(djW(KBcj5}R*nH)~5dBAAzMX5-s6n!tcr%!Zw_DpQ&F3EJ zk`$zfS$~={KUM>Ot!_kgxj$Vjv^h#k!pW-~UsgC2uwKsmsmQ6Mu5u6cpEeF=fh^i=-gF6aM73^v z7sz#Ko}8J>UYL@9R+c(!zP3#^`S6*Zj(J&ysUdta(Ix#`^GJ{>t@)dY);I}HB3CA$ zIFqT64ZYN9zd=JO(*{~Al8uhNgkvuT7ma-=*lhRgFMqk%xe8NTyiNeCHis=jiX3jE z@5E4)0gMMn=8O%6=r?iktluZ~jyl-#>n)Mv+dt9Zjq2}q)El_< zy>L9sf6m{G`=|N#J-y!_QK|2Ixt%=A2F8iZ1ly7_=eV-_n=2yTnjbfI^vQR9qmJgz zzkrvEbg+CoUv;=*#K_{%dN-n9zKa$jy%`NuyVeErzZTvR*=dfE%p+)eFe)K3Q0}W| zt_W8*dKTP?RF`tP(Agd57mT;RR8nlLc%Gq2HXE$i16`#zwzvWRT36rfquL4AAO*Z< z*3Dm?PN78)%zPEpq`gYyf?0kIn_eA!`tlp-!6KUVS#f#2zB`=Gcp?u%7?sTvT|RIA z`ru;~8&R?SF8F$--m_8{;~?l27l79K{8AH`V27C1o#)Ps##hcRFkPE8(eQ@ z%9F9Vc9x=T@&ZPQ=~lGEZsSwqnbX5WN^HgxSr7uy$i~>~uE&4H&uw!!WVNnf&%EBD zeX-I?rhqFdO%|8vOb;enp^cUKRcqj4ztEUcWT5KMHTJ>{_-84&wMl8-_lJe<#Kb1$JefvsP%T^VB!^B z6zCv0%OM1CrVPxQ=Z!?-YaLmz)82}qp8$VES3!lIQ4PT&a2}e%P zTbHiWvj>iMrVpndNql+Se!enRgk8)HS83tt6edA~|6~V9(qkiAr5KK!E=;s&Cj3vq zZhJUDgn3I|1^eBT2lcBA@2@0Mw0j>}?>E!AO$43w(fjl#%jD1~1mEV@YjO&ZuF4J> zgia^S9L3-Ualg8M9coQ6F8RIDfi4*;nmbieFY1PyHfrQdPh?Kv!0QSk_huGwyv!2X zOTcQhUOlO5NyF!98D*?})CJzS;?`18-aFhG$!8sDw(Sqm?=@q$bn#$tgys*b7N@Fc zMTYF}kk-9<-UA>4XpkV(t8R&{<4ce$RJD@WE!bTRce0o8_PlD1dk#|!tRIZj{^NhN zfFi4`Z?~1ZV8r1Hw##9gU{M(I_N3=DlI+5XyvQrJut%AA7ihhl45Z)BS|y8>=0JE9 z-O3=!Ar$jYRicfD7YJUeE#Gxadwi2G8<1y}oZz}UO{@P67h(1*KHViq8sM1(J>IVX zUhWR;hLeXPuRTum`EDabV=;5JZFkIp(I;?+ulLgx)T$4wq$x&=^EDS(uCP&1wV}?M zQ1TW`H-Bxl?L%RXIvrcCU2xsj!mGlvh4Aps*J(3+!CY(_E>87j_zN|u%T>>A9BSq2 zsB~>p)A!w_ZN>nf5rE=Ckwm;nF6JIeco_1syOM_Wf!~6 zS&E{IjJk@xU_am3te1fzYWXA1t+A%IblVeRGeOyjiEeSeoL35E{m2CD&^tU~ZJ19t zgJVHNV$bzQtAf>LXPxTz?7y~VGG92|w-3gz6N#62^9)WdKj>Iu(j|zlc|GC`Bm*5o z;jd0(DLOcvYpKDc;1<5^OT=Y$_^%Hu4}R1YqS_XSzx#8y$tT{=2^^Gap3*% z+?i;(RX4|QTCo37tuIftVWko`#hukU9Vhu4Ajs|mZ?sK8L{kl4KG?;$XoWQH!nCgBE!T{ zBBk7^KqkRi_8v)xTZaODRJH<#0U+zrW`C`+8$WmizzK|hnWP;N!}(MrYxB(w z49l9=Ir^Iq_EN=*LBhjTk8g&}CHqFZPB0Jr^NEW6R^Hr97T~Px)D7-(+z~5$je1r5 z;q;OSZU>RrgezUbTy?dL|1;uN%oyfy9DOODfn5%56y|=JadUfgM4);6Tyr5XS zGV<(4WcuL4@`=WTG41YTzf%^M<}Y>MJ$^@;i!ho<_R)tXYa7#!=&ZRS@xW4OhM=(fsRH?rJ>v$T*xah>(4PLTEgFK z9j8@uw2b!~NhKRb~!4 zLdKfg*(7)WIcqOl!Ql>04&Nkk7yU5m%|!`{cF;M$-%DdN$<&&LzSZInav&6Uu_r3b zn=HPiZCKB_1DC9*oo55hbVux=nmlT#$Y4H6|A}PfnWaCKP+Nk#kt8mqFgdxxvh@ZIV0d{!)^3MMsibA2uJ6!AodVoRX0 z;I-@E89riSXvnMMrK;l5jPjjfNit7KgLuQ|^$?0#YH_1eSC%Y}`lY=&UE^~5w}bWr z$0ppjHfEwn>Nh%3%cTQc0a3n}^FNgU5Fy7L#3iQjZ0-YZ0VY>M72U@eP2(P(>odPz z7p3>|j|-^lEA6OEg{dhK*-as(m3}vIXYyX=^t61|UsT-+aXm=Td3ihcN-~98R2_rn zzA|_lW-!oDtn}}Coa+JJf?DtzD?Sle_>6_d+0dinq~G8y-0+dBUxP10rtKHOVv+p5 z(nfZ@`;sZf7b43TeL=!TH!ylzyht9s{c6_IyDF;Gq66yd4bAmZvi~i?8i@vWIFX}(?V`r3l42Qd}j(r+ZnUqi~e4qr4Q(c`TA<*4Y=ry1g!Em zuY15DJIG#{;k92ZRCi9iV+)Zef#H-O3e3k~MgwhJ=Am(e}j^{wle=kkWQReZkRAO*yaJD|# zdoBIT7$qZCtZzIJ+_TK>e0#pA=&Hr$HqpsxBb0W2yjMVNp18@BO3xAFS=OpKl!k-SogB;kGM%RJ2V=9-j4s>W|7 z`Qc&94GOh&T-YB{QR|VaEDhVva6Nc@mR%%)moV~y7d0g( z&K6a+u#q0q`wfY-svl>Gu^VquJ0DL-2a+SD1I`4q?r{e4Sx+i#J2Lp4B7h`QT;=kz z8L>;3Cjf1Po>3eJ8R0xL_P*61jp<*_9P?oF`1B-G=cTjO?DQ3yoFQ(QZe*lkp_(IJ zp!lcL(-oUt551Q&Dg{+wC@~y}Xs;9~%AQnl^HrYgEtC#1Qg#kboq^EKgYpLjhL#zja7&yg zxDNsI>{gF9pRh5t73aE~G23h;VS)FkJlo(UV;t7fcs!0s)WX{SrxzgqOPoUbXMlH7 zEg}}}6GP`Zf=ZKN6)Tzn2<{3C)Dp~*ln`zT71}@<@^IXIbau1iU{;fUL&p#N9%J#B zbSSz49(U8@tr00#%fFG7=ozFuJ|$tB(qYq7kF-!^$b6K|kEvAwUZYb7w-^=7m1ce= zL&>_Qpm(+1A;A!Zu#bWXauvf-zwiM1U}K^PBGHF8)+~fIxud2kxc)i4ki5~7XN~BM zj;~KWt{7y>LzuXULMr>Sr~7Y5%ejOD&EF>_;3PQge6HShoBAIa@jh@}-l)6DIG$1W zX$CubOa7Z-*h?dNz2#yf@Yob1OosGxow99=@@_B=xj2;s@?n?vZE1CNHNZ-B0Izod zJj?X-G`&V8zsHp+z{R}!DVdAk?oyUt7U8jzm55U$$gQ>TXX(-Xl0M+zRUZ2bFx$U1 zCItxf&Wk9Cy1X_Y))1=@HplwAr2=Td`0q=8 zoRord+y`msszCqPwM1{E`%;f!KpywR|03%xpsHNAxZgzx2ofrdC@Cr3sDyM#cXtaS z-3Ukv2uO)^OLrsP-KEkgAV`SFH`(WYW887?JI3DUY{B)`^UV0q-<<1BjkD$#eZGXi z(SKS+BwP)R0mraTIbLkCz2CvXhWC%7{dh^&FdE}8Rhx`G!rQ{pcdfs=D*G4@LoxBubFcHY zzE~g;XdXZQ7$08^6&Cpvo?@NakF6Ps^v+kWldy_gNU7q&n24$Zu_Y`IBI3!Ds}|pE zZcrF9}SErDvbZ0KzI_4vFX8mmmj5(dTkFS{~r)S}Rj~Vfh zb|l!^OHN;k?uZIND(SxD5$YV7gXi0={ zW)^h^;BIS?QaP#0QLB1nYep;ko{i?4NS3NX6M38_k2;efANw-&ou5okRG{%LChLbn zC^HL7i~I2gRA_*uu(7Z>o3lvk>g?pQp6sQl9sGQXB@vHR_<8m=dsdUORZ^hTmW#{J z0b3||uC2vIM}Obkw5UrU3>S|$R;I^yC6ny3Oqv(3VT^mXri#8*w$oeoQZ<4;+UP>e zBfkEiAu?ZnaqJUEY1SE&XF89SoQX#qrW{Ful%_G+{-pa#Lkm_{ z7`sB|T&q=|jV1J~xmoU5+oo3xzm%)2uFg>|z@SW$Q&(0V&v+5s^mK}h9f1vNtVbOC z$W*{`L_SUwcRR$ZIz+8O_=|^Z`OoKBb9P(;)foas$>TfYT0<;qR;7i{(C-eZiyj}_ z?QKrfP4~==jUBc5qW~qc1cU;x44O8A8*ODF&qZ85qrNRrvmi4av=j?{UrJ2tNo*2P z+=Va6zBJLHQqqJ$S)i(|sY(3cfv%#WVcHnf*GIG?#1C#$M33xv(A z8yPhhl+FHWY85WCR?WW%doHdhBK_CN?#s6Sd-d}7&W!R#IUJ;q8?m%XjNkdLb_ZPE zv7Dk>L-C#Nnwa2x{P>270iG&V(Dfgl%Hz)A?wXit+3xTYWl9YR(Q0rIj|&BARCSEr zv8(7IQ8PZS4@>+^^)a~7le5)N68Aok3O8lsQOhcLYX75wY~I`}3t_T#L`D9(n%8H+ z@>y0!LG4njupy{!Bp(_aV_z-WEEL&X)f*8fQc=g=g?c-t{gk=lHzZ2=6i(s@0ru3i zw1dq}*I#RWNGNENp(3l)_?T%qd8zeI|3vy@`@cOadUPk0`<}x_1ErR&lTEMkGXwY z21SiHNSM(Ey1VDYtkg6$xAym&p`03epRVTB(x2&Ko%AM;a^`h4KX$0u|Jj`)v*lTs znW_EqWiaqLJw;Wy9Fqs18>&&d5;V`wr3Fb^X18QY)Z=Rj~_;&yla-> zNl@i(^1Ap1t&ZKU1x7~f3WG{PVpK_|8%#IALafjVSsQ)?x!@^K2#@@KB|kM+FVXEY zWPADfDZj<=gZm8`DO#20!27@+^WmCk*u5>Av|#wkFk+W=h>J;7R8(16`D6yg>DNkE zcwitZv;ad9KV_askB^T}4r-r3JmtD{Em_S?5+}j4~BiAJxNkv=Ry18oE6`cfV;Z2wO4<#0G&MP;Q)oX2fhcK zj~s+Co@iHD!Y@D7e>U79u}fbagd1y?rqWhiNaoG$`Jd=+?KJS2i~{S5{OEUaJQk9v%X60<@0r>6}IG zY1f0BCq@{5941C3n^>>wJNWq-nc7l+x#PNwN}~xqKq#Mq->7@N%1k$j-J?9t@}?s* zPJcvA)c{ln z@gw)!kTP3;(xAEb6$M4;6I#MCRiH#9X?#M0>)B5|cpEO7GMl`-%#54yQZ&F1@L?;t zgKV8C9u7;@!dh|=+7%}ZmHM$XW_Mr-%;K4B9FGY30{Z~eiQImOJ5;twnPuF`j4RCF zed2pf1%$(-{vk^VuRn6B;vQ7L--5-87qZ}SHvs&8Om!ls_`=0Og= z`Q+Lk$B@ma$*k_?R#*QFQ=I~jS+|ajh9(=f(tj0lL5a+!roX_D!1XH^Ois4sS9)Kb zLa0eV1l_-U4~C;DUx4+CV^9GYrOs(vS-g61aPSrup{cn!qYQ9coR*{MfSLkxmZ8?` z`@(W8Q~dhx@yN;c1mFjrr+W-BQcjw$(%bsNt=JYmxdP1dE6ow0PJmKK`5jHAr9**O zD7Y$IOY{8)#d~QfDPas?Rc@`v#`vG} z)w^)ZEiEm8oxXnart$Tvgu6R`hS}=RS9;@qdiJA<#lIL0Ig$XhBM9#T#t9<>f+nzT zm*?klpZLl%Gm$BQeB}cAKtW*yb_`G<6oKksRBUESwze!;Sxdp*^rhjQgU1#LK$}}w zsI{8dfES680f7sULw2)eloS*cPoL^8lW`YQ1_JLxbnoVQ0I`5`rlDo zTN^ZZui5w7M@$SgNsgz8ov>UJ5`Z*blCh*W<$kq|*IpDh3o zb-iB1;JjfPf1CP|at&h_;M-E3x>qzINA+ZlSpv_;#|I{_qoAMw z)?;K?n2fA!2eCq`z;E!a#3sOG#z?KD45kX!!V`xz0ic!&7d|<;H-N$N1HaC#>VVxL zEvw&X0)z4cd=(BIKy$#68u(n$iqcb4Q*(1qE!-T9;9%~BX6NTy0>cU*U`a^{I7e1` z`e^%QxW|hWz$78TvM@6P?=KfqjEaWVZ`07&I6x;gH$UI+TP!=FEg{hjNbp)Di$RO- z>qs)nDp&&7m9ERLm8k6=q%D~xv~YOg4%184+rS9Nphdv?^U#V{~9#qaQ&$( zDJgl8O7u%gT6zr9u!#v9HFo<~uUKH^2>JYloCr1t5N*DP-$hhZCV+y@7Iksq`L!4< zOfd`KEBwM4Y*#X}-Gc*MN-vo%QS11GKGVYgj-B0I*sDBGo)p*AsO#x1K@gi2lbK0%|Neb>`Jo#wJ}1ZB z%}p+u>-Js6vAivKvK}5Du#EwDe;aAyr>vp^P$)K{O<~oqHn*hYAwGU!RbqU6kk7R| z@XpOmO>3_Ow2`C=kr1PWac6mHJ~FR5Cnny&&va^Rk4{hD!^%)lu(z~42Pdhgr>DjI zF@GKqN;I4Y=a3*Kuo?gfOpqkD4b~i(cNB!Gy1G6f+k3O+y|seBK90bv-CSSS($QIc z66^K%+nxX2AW>vX%X36}L&N;i(iQBY|LDS?;NY{Jsc?y`ND|HsXne@c&BY>OF=Zo` zT7E)9BSwKYIWq%1;mQ8OOlN23>@0B-Sz~%S1wVg1B&dOQKZ@%c8{y}pmRtgE{JDDmr$$FfIYl#%6aYh4&0t;Q9GKt=In+nmu`qs=+}R?;SH+TX0-|0d+(|-0;PK)D5Q!!q&S0_*w3;io}53ZRI!Q`w0MH3knE) z*uV9Wgwvc^r$(+SY_Qhh_l_FI4?s8L;^P}#4_=v@pRV=Y$M^w&tD34R@Ytik`$Bh! z2nM{!y`Mi{!J4wQ-TU!FNly=(61c&_iV8=tcX#gGdHeP)MIek0IT+8u8t(*xE+R7W zc5!@MTwOy0DH$0VDJi^mDh5MT4UHKqQi4?%tS?z108_8?!9fhPLUPWYMB7H z1Ixz=yoZ9E+?r$kH_Q4d(Ez(^tLU0uxaa>2;%}P@@(W~$`vB?Q+uIYH`1FSF)8L>S zbXKelzXrz%SUUJ-ZRl5kb^^SN6DKSztnJme?9&JYo~Y@b_hqO9yQzf*AfMEs z2k_iT$jGSAHt_9IYf^JwHMZ46+qD7r4Ehm`_+5vI1b>qN43(Mjg>= z0;$8RN4?IWnK|cU&;Qy5J>uAizl#>|8m69rg>P(VP%cGHXa}!xb#*1K<%|{}^0NsW zwsGd|cqeCPZ!a%!S5hZ=@-J>qYq2h#DCFy-sW}UQr$p4lB|-zo<7Tk7{7ze=<2kb8 zwAoCo2nqoK((Pmg85u?@vr22nVdi3kG=rS+>1;Afm@d1d2kDYIF=X7R@+~^Fw z4?DcJstP~83T>SrBP(kaOnq8f)R&b_9uHuOL+(-oc>eeAUq(ho1Oo8h&5<-$C#Nc4 z?qSf2@;f@C(Mw=pqe@aeFSFp8(9r-zfd2VjqNbgV)U z^h*fk8zz6i-25~6_1%S9);awuLP%G@NZ1$~S3n>!Kd)V}L zzG%JpAc-g1YhDTN06rOxm6erGsj0kn^U&q(ewIDc1ZM2(H{DUy)&vYJlx1_aPNU|AhJJ%VfoTgN1M556 z+vGw%pGG#RJF0Fjl!=4mUICABXUGizyihYVFo4A%vaz0@pRZYA8fxkI3C87=>eS-c zM|S*RBaW!5;>w-}y(AzYVBMXug`9Cg7$>@)=le~21$ce14a+Uw@PIjd|9PE=&F=?8 zuv7$7RMUhWsVtLLVBUNMQFE4NQSYjgaNuZ1!vW$D5 zzp}pc?7{*x!Q6CJ{rU3;9yFwA{H{MgSyFv|^cgZhPbJ_a#qwS7Cns7Nne_qHiDIHs4DB{O~b4<3{`~ zNCRO_!C!Xd`vj5G)$bVte}8|-69C=rc!&L>wf;N$cL-GB4*{(Q7avHVo$_mEYpcog z?0v@%+r_#u80ggAE=rFtz{dv-PFB{|9`5ejySrdv2#JWoa|s)Lum8bP;pE_ebRkHt zbZ=whT@yYd9o;4*K$Nyp3JSO;@**NXptlap7u+1gt-38!|O*!Gf;ZB0xZLr}cz}tdT6w;h-(fXeyZ$$?^3|@Ip4?03oM~94@{0h<@ z81==hU6r4a@pW!)4w71EHv)s--;XI|EBi`SL*rnf_FzQlS{KqQXlO~4%VqYgc3!8= zhIb$&^yn(uNf7p@V|v_~XI5q=hufjy*b^`49)<7$GTeXvE)Rgjhsbhnc9uc~8+yKA zD%p5@``bhPI^;-Jylts?Y&af=puE8dr9e{|M3T-YiF&PkJ04fg$wDmx93K(-}^|ZB><7-fNf!GzU zjq1MxmY~H@a!`}^Pucyy(K8WSL;d^MU}Sy-M;OfGL8Bef2+XAGQQs2`GKg z=>Yx_Ts!ni?(FR`d+){J`#fC_!qabbc|uPgVk;@-_un(Dtrp1|gMbPS==Wkz0cU*t z>ld{9@I8153*koL;e*eHMlk4un88RJ(SXDrN^4-r#>SwR_W0yv53(lEP_@_WuT~ij zU`@a;r;tw`y$}Uwqu9Uj4jOW8dB~odCP{aP!eZ@>MAPK3*q)uJUr7~UF*Nr2cWQVf379^CR`WpYQi^=(a~6jAh)ru4*EpEQhnIR zx==JCf_sCDtFl^Oci@A@HqcwLO^N=uGHc^IR*$q7WKrfzewkZXK+E$1boZ=uhMHcE zYp2I0Jjh;i=jP(FjNIDU`Ez~_nn!O>5jYEQYlfHv1O!$qi!I)bW()H2^3Be>gg3EL z1GK&wSeQa5OlIvc0s%>9qy$WwyA-g2h}08y9z?LPGFpd4!zU!-YqPUWp&tzlA+%Q+ z^q%Grh``H`igM4&%AyR!YX?0F>`#5O#_#i^RZuR@e?jp}1|RJBlZ98XksvxnARr)V z1%Em~dTnHx)h}qj{M5kU8^r7}`%=3r10J){m#l-=nYRQ|m-lQbdgG`P$;XNih{v&W zdt7}W3iaAp9=%H6PfSjhVW+~!gw!#lJfIf9`ThO<9J$T@)uWZw)p}i)f9a#woJn%f z25Ksm8!?AQPEPLYdksc{qNpe8k>uwZ=m7c&IR_E~GH7ruU@@T0uYYJruiW@n!oU)A zg~Fmkx=Ap5KLrL}J_p$emJ9qR#DEZ|!QWm4X+23_MFwT7#ES+9$To&k zJy*N2U%cpm^F4Jt{0q_u(U0Jns-ZeE6^DkuRjR*u-pxV4Va61mG-CoAdy4uBsZBlCl8WCq4lI z7A7WicgF7TJB0sV7U0vTz1>|Vd`xzULplejj)0qoPq>8q60Cn%fe>6ySQzHo!E>8w zW`=-#uuOmsjE#;`Tphe!2XmhKc zt*#EjgGWBv*T(?)13UXzcQ?FnPCQZgFSx(Dx;l`d$F@(BlSu~+zV`H3xKcx6jD~>X z4`xt1+|FO9?!ZEZjWS4c@Zg4rwfez5`26i*_{rj7)VJj|e z5YxefLYhpIDvX5{4$0-gQX|ouZoHG zz)}(-g1L3LEzptUyORC=ML=Z^bO00Q`}YW4c@s)u(Eqk_d;z%+Xx`9(npT>fO(X4o zbm>^H`|MdWnDgTcFPz}mq@>%FaE;I0f6;V5A`G8`?d}tKetu4|&d<*e4iX$UE(V4l zUT$_aOkRMD4Z{c|BnX9|VVU@jgtj)RvM}2XK(DyhmrBz5e0XTfA_9GJ}fW@9J8(-z<>sbw|cnV%5|lrr0A%q9Do0c zvW9;J5lKh^WNDDMqs+a&G1b$>MWv-0N=gijjBoMORaM!D?^Hqi7)9V{d;1FLXCF#1 zt9~^!G{_X9QSMFTMZp7yAr|n!75=R6@56((BwRIzp6j>xg7AhvjJ00as-*VT|r8f8Y4*OrQ+U;eM!6)#{wS@Ib(vc1&kNy)k86t z9K42nN;ZKd-q-@xI)pl#M{a>&z?t=%G{aKiuCF29Cl+)|fnOWvET#kd;dRdD=tDz} zA1R@ttenhi|F8lpF4@ivs(v8dAP}&a!30AVIosmx2{soT3z#JMIvZ?kSU+H4_aF)b z3yp-hgVxdBj%*@Hfk%OL?wusJ0S@RREMw~_Mu@g=?ts4yCQYo`J3^oW(G&qbzSGf) zI6~OmJh#4{|JRNI0YN-aKvy6TLydZ92)n>QU;pR+esM_&jPeM2&Ju-`isSIZaQ_!Foc(-@9o%nlADIltr*5XM1y; z+i9%+!rymy$sRsr>4JUb3f|~R-}~NV2oj(3zTJQ>R&Z+-UM(=}mZobM^Z<|+#m_I= zXJh^mAA#-yMI!}%tG%KxU*c3md`lSF^mKQ>`17a5>%tLSD})+EX0c}3RaGYt`@yS( zKZDUF3DwokAo+8c2aIfj7U{G*9r?ekwtl9dxL8eDxxw?Sq<0gdX9%Jxjf1~JE}Wi@ zh-n4wWQ=08)a~#9(tI)=Tep)fr34new*diQ3l%K;2M52vt2%-&B{DZN%czBoqRg@$ z719?kE25_64EADt7oU*O8qUqYAYA}Lm$qpYbHLZK+S+RuLBwzQi^wX~8LCJL>Z2=9 z%lvZeH3~iVF-XxgG&E2Ui%Ux|sRjy{uyM)^ze3e_Z+{=G*j+sz@Ve5{w-Iffoiy;> z9guq<93Ttt#PInB!4tqe;BP=wLPtZR`n~NWFkbrBzi0Ke5=FBDlu?dOPC(_kk#eDX z+6*kawRPAXzDB6I+3{!f-Vur7>9GP?JZr!KRDhI|C~{Jv|N1{|*|; zL`hWC2rR*9k!r};zzrFA7v8^jPgfV@zHNxAt}iwpjm_Lcd-LYa{rj=70f-QIV3gc( z`TwE%R0|mdXP454@nHTwVdL+8ZXfXe{V?RrP`88y2dW)2Gc!!k2?%(hs2H7_y8)>? zq_fB7Xs1l4azwfTM)#dgc%c41{VeIY;;NDEJ`id;KN$vr*>-5i`Lcu1(?fDG+w zZoUEcuBWRTT~Y{DjxozB2;WT?gTliHKuLsHO%Ou6>`?HW*yI9}V8$Wfnw>q@=`N3a zB=nq~J|ET<)EJ-u$LDrP!QnzY0wx~Zeestsu#rD~`ZStyNOxFtbs+%8FS_bp7w+4? zDg*dG45#hr<{X1PFLCP++vAa1askx5R%R=NA>;G3>zwzY zkni;l47^AH@ueB$yt+DKE$rL3j}8ylRctfr8BwR2` zT8wH7&fm}=AU)MTFcACU!|3}^il_dL)O>uJe}u`yYHkr6e?a+Lm=|otl?<9q%jn|b z1C@}Unh6!GK0Wqw`7noo=7caKJA1NNhgXhUAocw=u9!YmC<{cRPtK7aDy1c!_|t=5 z`p|8D_p>lG=saTGVa+*5x=B4+Ub^QTLj~TetFd!E0#XM09AQd9*f~&9H}w=5Grq}x zznS zX%F%f6GUAA5dz%|A{5AN`c8u~&2BE4emy5Tb#KoW9-)l8FHOEJ%1!P?DF|74S$R1K z%NYW5KE&|%ALKt}4cdd`W_ETqF(n05kQiG7dTlfiuXsTeAixZgmX-#|4~lvqu!Ct*x1-eyqIU0XHhLw zDgpTsKp5nu+MDrM(?Ubow?eaXbE!CQXdI{1z!QBnguy3E2-w{rPF2;= zNqN_Q{NV)%F6eiNg<&}rr$XlM_1wBUf&|_k#Aw-dVq;WQS&2lV#P==_#dj8>g65tg zl@>hsjT;h=e5CB9|IUpllY2Yo98=y-dKu+j$qKHxC@p-M83Vm0S>o^VefFAKI_>}k zrZuQYGSE1X?%MTA3!yo=ZpemkB)S-3yC<^c4il||T5mMsM5he&s zx?p7BQ3zFVhjJmhzO1&2bn;>Q4Fsd<|LMSmI+*(Op!5 zaM%0xcU71JjrF6RhjVtzavl$8?f3O-$1#@lE{6z zbCK(>_tT$*pSE}&=+N*xkH(coJJ_=h31j8qbTSH4@pfW|*ZBO6yPt5_{WZ4|E#-+F zE@u59D1l(fr3=!bG<)~%SgC=Knb|sM)%E-mNBdP+>qDDfRO3bFIUl8VJI`W7ENDsm z;0}oAeF8J}qga?3m>8HgL24om2@4bOILSW|kdTmoP5#E!b!Kw% z0jGI{*MqEcm-(PyJ}=2b)NfmJU40-Ohc2gvbQ9g^%n**wl6zq(SXQ?M_9@Ko>iMgy z>FKHIJ(+tL^hxUFOPKxvIl<6$RZR^J78WR8rj>I*#>52J<9~bE*n4d3Sa?slDu21G zyD$;|NduGI7c8ul)vh(y3^&P?{CAzNSVOOjMZah@8PWfv_TiI?aT}qsod0tXor6Av z@Av~k2*_tYmOH`)gI4_<&=rvAeKbnxwZmNQ9`l@9ce4&_;)g)P%#4x)HOJIkf}ip$^sJ z*5Dj&n@6wx0nVCP&#RZ`lL)r*B0%A~b7!Vi0Yk;?iia3O@xUH=X!hK+jpa=`a zm5-yOi0_~{;QV*Mj4O)Wr+*Erh}Ok>nr5RMNZsJuGCV|WU^ov9{~7=|emG6&8tM;vO>Qxh_m2ZcUwX_YzbZr$9>D5U z{h%B%MH8amd7H44HEe1-y`-<81Ro=)(^-5MRR#kIK}atDwBfXdhYic~>g1@A7$%RO z%bOCf5YqRW->6on`}d0>xJE_*eQ68;7r>N=Hh7qk5fRolHo)V+z(R1fL{GHWe*Szv z3Bbpn{}>aPCkATZ`_$AW$X_6;hbR^#bU^dmAk>BuK2J(BhnoVEhY!e zFTubE$SYKYA!Ozt#C_(n`mi|C6D858sDHGDE2WP-{@dCs%}7@AWt5CZ^U7X{ICbv% z=|jh}p<^Z`BON-{F=aCgBKRImM;WZ^rVCeR@BL-JDVOe#&WnGLUmi7?v{Fh?BK!lo zBOFK-mHW2y3$luHw_A)D=M|a`w!}??3ep`6HyT>oS(^H!R#Y|mDXQ-|seeJ-v&*1} zgiH{IA(10s8CE;4_k+52GY}DiT+oDidoc<+Hjg1}fod_YSwB96!w`?$D3^1lCME&Q z0JiPTR}ak0%uG+Kzj%Sd0Ib1Zz>b@ny&+qK92&kyc4r5MSt1Zk)sO?v&T6jNq(hM_ z`EH%KB~d>Xn-Rmy;B3a1v6cqz4_i7d{uEaFB2&&jB3&FBJoQ>D{<88GC1W%A%t^=9 zh!tUYRu#Ye5`{$wOUKdrGP%6+n|aRSdv9iIOXKUiOM|xE``WN`7}-jTXTvoQtj#N3 zAf(gl7%vP%aUB-#l;qbEuuW;=qGGWQoB-Ch|A|Iar2HW;Jy^kMqB`Au|?)Z$$pw)KfE5D$@IIW2)eG%$VXtI9-H(NXK@Dl9UgYdo8? zO8onUK2or$$FCQ+G&;5Z>CZ$VLS#hs)NIeDT?;YEPR*;Gk43?}FVAxt-8W~W4zglb zQH18v#WE z+!ZhesMf;FKaflNdvR>$dmR&v!pPc8erYB|JCA67l8B5WM6l8EX0_P^Cz zobTqXq^jc~vz1?moXtI|3_HGb{Yi51oX}1?v~O)vwY@t+O3OLOKbNIKSH%Dw@%{EK zsl%%|#!k1XFT?l9l*3L^&XU@9L};(%|1J3xHj-%kaRF)7K) z-kx<_1w=B4rJ%4&OiD^c3ngDD;sLu>TUMs1qJn~eM4OJ15@~K8@FEx&Dry5!>5a4^ zD+`Z6ORMk4;R4D&^}=Y}bK!OD5XmtfnWVtW|0)O053ixJ4@ zn?oukHA{`j3m8avJnx#N){2BJMz^YD63^kN)-!lt5On)WI`;E+UzLayWhPrJ-n}e zop`D$V@rIW1OG8G;{`=U19{?W1vMbE0@wMe&$K^J2{Z6C z)-HOq8n+XT!mFiKQjG|i{_o%M-rPwMX|<&DNWmW}M)$C>P~SFp^+$Ff>kQ`qdv4HPoCs_QH1+h#yC5Nepn>F}I6t45!&FL3D`{~)2eB^> zpqH2o^*HMq@Y<5=y96fjeIYVG81%xHr4|NiK1l1W!buD4xkGMJ`oBcl5C}Nw;Sv8z;oO zJ)7xJe5Fx_#8dLf8^|jRTwJ>Kt9>ZR0UH7e*Nwgnj0sKTagL?dy!ar~M}fBBs;y5* zaZjB6NMH=!Y~pPSmjTwmElKudaz_f;9mIF9_O+*-5>G;g@M&t8x_NF{Ey9>f$*70m zZYT!)LGVIDM~{M*9VlK7&E(#AjKOeR_uD2iD;1@8tZ1#1Izt+?u3|~=@RE)5wEBNA z_;9{o3qkO%LJXF2|n75g{Xv!orK+YPV~A$d4LVLBBV|!!#ls zCW@k^jIL}enn{3J;RbOjlyD$6Q>dYC8y;o>tG=)x`0UvgR23%uf)6AcdwCFkeXNF! zsUd%s6kUJSO(O9aP?n2Nz7lgsxjk0n_7f?UFgjWw+UGl}pzK~$7KK050l}<6)JSWSzgok&rPAUw>J1U@Hy&FnBY zKc@n5Pl`ZA`ihA@(lanJWImM5IbVJt=n^53Rb5lx zz3ub|GAi5$e4~&>!H8A&_Z+Y2s=_U1QAK|!ENswiTJR8lKQ7LPDv4oe1l|=LHQvlm zA}MYUp~**;?sRN(*0e}jD#iVWBA+L^6~=ednQV^nzagS}CZ?vKW-liv_xGiIr-jcs z>u)=4BOZ-5q6NPLdWyPVMiO2hG7Bp*s!3kmANxFHM^iF${v#l8il(#|^|06s& zJ5@NGW7<3s2M0>x^aspC25cMVX$cezmv zV+Q-zbzaLQDRlPT&)XSNh*ya2*5IfjA*L;I z9S#XF2JfP>-P^_6{Zd7!NS1BB?9gcZzXnRwm+N{op*}ptnVEM>=Sp3@5~1HDK-(?lObcI zSu`cpx_ZkkGG!=YtU=z*Lm`a8R8;u6B?QymftQZA(Z45NQQ_skzeIo9raTX4eqNdB z%M{9^a|vWaoh_M!4EGV&V6%dOGq>|v5Ier3Fv$NJ8fTu_q%grt;y{}MA2TN~Lu~gO z;kZml2`w>g2`#r_cW{+*fX)~ujU}#8h|3JgDxGU}Wy0**S%#h|86H#(bo7=6I^Ogm zqQJ)ed57lM>U^h^RF}`;lNdVQmJ`%>GO1MH`zfhdUt~w)LV6D)oT2yT@?rP=3Kdjj zq+Gl_~-H|TDy;NsO#Qje*Tl$~gK4pV-Be7iZM zl|pR|5Qw&PYJUF5Vbg8UTUd8xdf5MeSpeOit}@)F1e^D_)hd-`vz=Eid($gF+!3Zw zvq18f8Ng%VJywhfh&Gka zxv94+S9U2kQ4tfPvWL?za4G65Dd{U28C%lKnGW3i?OV6;iHJ5gHURFqXskxiZch>A z;2b(EL78)Mjmg8moj5AOjeg`L{&DPEcgDgju}}|B=Q~m(1@A`I zA`oG`O#R%#uY_yhh*O`T=_?c?c`p?J>RBob{}tXiTPPoSu6SFd2ch5wG87m*|Uj`45EY)&(xzIcIxAEJ(LK)@{$)Q z=#fgs3_i?*%U4>`&3jV^z$ex_NG7y2kuBRYJlor9WiB65J+%>lH!#nLGW&Z@Rcg-Rkj=hgyK&=Q^Sq(PlRj^@k64FTddUa;n2hoZr*u z-y?+Iz-GK!0v086!CIWEBcpXuj8|9DN#|=pq6AgPxTLU5)82!B;gtCA=c+AtTCTOW zQ&>(vV^YkzUg}C>rzXE^FiNqQKsdNMh>+9pJo0zX$H;UfG`-af1ege=J#cqfd3kw7 zm(S>WEaNETv?ku7cKuM**oY(4cH+AGZ0`5gl5an=`r!wmdlkyl28-xOis_v1Tn+?x zqHgii1|j^!>1s(Ww~;ZLJx&yu21yo+c@cgRSDCSv>w- zy>Db<`0-O(l8!bppW9x1zC)ZR9zqdPH;h}EpDOODyiR{nO4*9`QS~DV0w>5|o~+J% zvz3lA@F~*uY%>$~(^q1D-_XfkE|e>TyjL6l$|EGP(g={c_kBB z#DSyf$HvaPKU_p-&+)uY)0v@QE!(&M7Q(^0@EqCyU6??s1QA9Mrjr07y`qMc{gaAz zqKY;KLQ!3nrL>?hU!(%n;rE45c)#okmlNZzwVT(&aa}F7`izhI%KDE3{iHRb#HHA?+A<`Q z#9>GiDS?joySDdZ!G;a>Q0-6S`(%My<41bFuMdWI^PGe=(m4^RkI7HGJ+U*8JnVO0 z;p9#$2sI%iFawdD&D5M})e!z>lJ{*;-l&=*LO4*?tEV1eRbKsx^ursqIw|-mBu?9v z;ei*LYbCt@@@Z3+bf&Z{uOd4iBKED8&Wc)6pvu*H0!ntGRYe}UV1Jzqb7$+`$@AiP#r z5IOL>@>(j6wRS?net}g!=LC1t*@nB=Urvng!HXw8F3*TO73BLybiIGVIijjO_m-!8 zHLhv#Fd1!ZTo(Dz5KkK|gKLuCWz;MmxwjspHZ4)+J!%fuIy!sw=G~vGO6xS_)VnFC z|IV0#DN&E#$xoWuls@35-kMG#$U?4~;(B57s3*6zhn#BcYo>-2rq9Ay1b;C$X{5l# z{#_8)ph*bW=#3&DlwfKW^7nP92ns^I?HBDB6dqzk$nt6~^4?FZH@=N<3zSvM6!lXE zB9LF~zh8LFn&e}MZGU z>-%!SW!3F}OZ$y@nisDW=g=@QFJgdzjg94mVb}asw07^s20Ozv_eH;D^FF8X_sIB2 z|D>&;;5(*U{`g31I1``fk4+sfdpcff@@9i~3XbJFVRbfA)3W+gZ`@vH4DT%5uy`GVw3P#ABMio7K zVW)bhnp;AAvYsvmg1%tQ@YS!D9Ht09wvVb}O=!1k`mk<%z*-Mr7f^?X2Ju#36=f=c zl}Z0|dn!+kEoPtE{58IUk2!Riq5UDZbTVzmqawcKCn)RJD=R9pyyJ#!L6fi7< zHGSLl#Wj_*2g7QfE9-Wn_?1Da@?GB)*!Rhm#%H#IX(E3CmLO;gX~TvBt%2CF zw!9`O^C+32iI`K%LJmMyXW}HF3+P%NSL~#Oxf^MTCUu2W|4GP%g*gN`8 z^bOr7q7?k}$85KlJD6K-HpG8%yd5;fuidWdVG_Jvh0Kj7doP6+9vXiP`hLD{?AvXSp;e3-q$kI6pR=5}giL5PP4fJF%ufGt4pC*=Y)rh6GoEP!XUz0FXHHujdfoOjPe#Krhka#9JUj(BmFIl9?L zWm98YEqPjm;au;w{p}hoO6#J1Hd($kR&;JP(H6 zu%yui;vp-lf$kEmH)7+LX25j^fqOLQyhoq|M-<=MHpP;)booy%(z z&SVuB))YXDQdOOVHj(w2Y)xT|GNF9`Tz5FnVfaZ+iIAf3avSbWc=WCKHV(%W_m;7Bq)h?CTRkBkmVja6 z7WbO7gEw~Af zV+FC#0;2~uBNqjtL@f4h>w0so^w*`z>SsUBXDs-nUAI2i;j4GeYxTAK+jU|~W~CCH zpMcmM(WCEa%+R&q4~jd0VIUU+_ZJQHz}i=6zXj;MoTGpD>V%5pOv+HKM$i1-RM9DTPtsl+YCd8a3QM=;qH^vq|k544Sk zdq9Gk_M2iET5@rhC) z3OiZnM*;#(SO=`i-^}sX9WS1Cjj*#;kode$MMB^u?viwQ$q7$`-H%xs`h6#yQ6^^R zchkG%Kl8cI8*3Wf(A>FLN4+|KSfu-a3E}efK6=X&X zY|fLqXtOQ){;q#ka7znI;(Wr&iAGrb-vA2(9{H!jOh;#LJ8^k}3XfmQ)z`|)T-*@? zhV=g){pgD!gZK>@TKC}qI28U35XRAxR+VK8^dOfR1?cLC2RBCAH zF7x|tPThZ)mY3fqD%qXRu0w(PeRx;Om-mq~0k;}${Px4F81tX4kq-?IOzjLYDL#!_ zB$m8$QL&$~DF18gPlwmkCx`6k^4q<0YV)p=^lNQvTZFJ~H@c^ZtQ~h`*-XrU%wG4ArvJo}{ z0WCP;pn1gXBL_VV0T>t1T@+;GHKDh+?y>l=oa?U4*w@9kZ1>%2Rlw2iQ&+lN@-6rO z_!EJi@S*>g-h>AID9O8d4{skQcO zeR}?d9AIDX+B3?q5Tca$KE1N61#4oo&C9%R_QzEODG;?Lj|?_anV9Qb#t1q&G&{!eA+9gg+?_x;mMT8NOy zEFpwc_Kc7%D>IdmjLfoAk*p*nTe7n^m5~)nG!T)M8A@i|&-40S*LB?g+<)BX@jJf9 z_xOE_^E^NA@fy$PG>S;ln47_4JZ`k9Tn>v&faTW zrhCseV1Mv(KSTOKN$0AvYNFHr!(CqMn@c@BdxCcAuuPqvl|-G{^O4 zONQqarL#hFO>8Uzh`|hRfncloQt%{%52<1%54-6OiIY9te*+z4-CA?{nznwqQ5Wd8n_;j?oxmoih*8c28=Ml{hn z1S|p*z|0_qrlDc?-!XSSU&()bvT1jtR%6`RqhpcO-*Nlc56IDE(maW~!f^kS!{6Ik zys4rL@zkz86y>`nCYHTlnn^b^Qa!2t$o<&oyz1aJDgO3DS^6dJKP+~Xgb3!+4}1NI z*AaRuAzbV1r191j?#b>!^GwGwZ z>x^f*QpJ*#=kK|sdndK@SyKN{Q=mY1?)drh$GUv?4Jf;<2p&E8yi9IOUMXPxwG@jW zy-<@hA;R}B?d2V&Bs&`Taz_k?_Wv@tk zWuda<4!s1tK5#3#{GRDYzYHjg%!`x3&FO767!DSEmP~sq=x9R}%Zoi*t)%rVlinB8 z*2F`G@Ag}|-42%)7z+y7lnVL5ucO%5Ls6y9wpsngeEYoL!9M<+V|nq+2WRa)qdHTb zg+k=e?# zx_U@NP&#w40#P&q0cPd3FUx~YFJaJ6l3-wBQhh87uJ}FDPY(RK>b=J7=dLCeUfU@V zRv+=ci|%60>7*9w6B`*^Uv_dPwJZc|r-s$;PNU(xU%+b_|0y?D{>ox`D_OR6(Rouiu}6tfeK;-Qpwe0P zv&%&WiCGdn6<_nWI=+zyz7uyKPxoJ1lVVE|dL~YB7Y$r=x}YE+dd(0Jr!RR!WlBv& z#qL?fcKfyP39%<9?P^9;M@05MFUeJFbTr-!(tMtmlRaZ==TP*eLv8%QlpSM7SoQD6 zG;?(34#!op;1F-XayKS`#o!y}5} zN03^oF462uKPlVmB@gu#BtuX-B}3|RTxLg~;G;^~Yf+)qIdR5iA)FVe2!xkrXS^I+ zhU?)#qw1FWTN##P;5Pt488_lZE5No(4mhsX|>tL#Kop%LF zR)3Rj6&_@0n^@Ue6>$3I(pqz~n@LK%K=|rtdqH^kw`CgL4^?#cT{guSvpA1z^JO#Sx3%tAF7dz;LpMr7`m`%f&*o2}?9&L{n(0p=;2xb$TRF z_jP!vd{%9%M~}i#&y<2#V;0Hr_y}ulW5X4R@3(7jixRZW&OM7scJZ0qLG>!{!JqFQ zLV`KtMezbUo(nVYOX;V7=?wZWeXV}?=9SOKZ!VD|Eq!8r$EAuH6l^b9{_XMiy!2sY zhirZS>5#LkQt_mVC0_n7wBK3`g|Z*?T;YPT>ZiM;YxNLpbzp^UuCIf-K%{6?ReAjf z1p@&FR@BuS32O-hBwvBy^Ee){{=s2GM>`_#_1S0{mPkcx%RaJOoeIX@}jEqFx+f5R) z9uv;o$O=-Ztx0=y3dwGp0)7^9X6RK^3S}+SYHLnE(PC8{Qfag$^J(CenCQB@wBq)~ zgv(6oamruChu1`>-E0bbpWKxoyb9~9G|Xrs365U0h*+HE2^JRoemk%Hk_*p0ewxE} z0YAPp)$U!&qpOQ^eN;lr%8Iv4P2fF_fd#JPK@__Hz-xH-#?uC^ag4EpeIo3^gQsV1 zTyb?3Ir4rT(js&#as7b%0EZDF0K)Hr0!L(fet*}m0*AxH^GwLG3@Tjca|HzpTlU@# zqJp^dy(_%G+S)YXX9r6z?+O+4rJd)Tq#%SSXRS?93CA|yb=WUm5+F5omyI@}ChX&V#JXHr)sRhYi)FAU}T?)R+)tp#6!v>ZJl2!O&MhWfM7lM~i-B zXW25yh8Rd%G0Z)v`N&YX%)h_PhjTj;uJAH4x&v{W%GA|JwB|EYTqere-e zR?Ls@4w`hkFc&R$O;@?GRFQ^-sdIN^>vx#Q1W(Dx{Ke4$TRtHG=oO;K0*eFs*?+Sy zUSa?)6~U;=dGsNVdU{5Nx70A?RU`x`CuAYggu@RA2I5>cw#c}|M52Zo=hgG9EC3JK zwfrZ>$6;fdHg?rMV=wRL#dcnQfOkMa{in$5QMI?lJ+z7 zE^5WMtcJLMQjhtaE97oSH*R8jms9)TMy$Q9Ev(-6FYMX98w6nJ!bT@1PJ(BLv8*Hn zEEG2gR?%z*gU9J>%}I9lRP1o90MK%Dbe13^h3SPraB?DA!e4qVaf*nD2ng&ZXd4;X zT3TxB=oCY-0yl+CZvwn=P+~a_li%$<8@LlVc9fKr zPbQ{pd*E9C{{4GQZ0v8Y@DckYtawWRC|>^i3!fJel?Iz+`|5P3E#oJZ(i}3M6Y>{T zEhE|KmG2*1lM0G5l9EzhrtBZ8xnINQHj`RYSW%J2Ca2wetmW4ot7L1H(7ZPHv`nu9 z`+35cue;8RDx?7&2awqb5s_s$N)Sri{JVALZ!^A?A_&cZAv*UE7A!JC)RQOhX=~!Q zV*{ZpcYvN=IN>cmkK=Hiv7w=7*OQZ+1|`MC@(19&!ESq;oIH$aeVI!C!zN(@Dd-M_ zm(b*SIiNrOA1|Ao80f93sdD4vuy2|3%#EXmQ85hrmZ-$D~F*RL25yEGE{#-~k&#B$-TnBx4Nb}+aC5l@fMppZe zc)Q&E7Y(z`@#Dvl31IPYzIY%i#_d&M1_;0p>x%O7Bp6kR%2zovvu(&ef3K{N5nu*j zi)@`*fg#Ap*Vm%Kry7D5&>B#cap%;7+VlLrdbZ_O?~d?M%3A9&O?EaD1(P{1EM`xL4*yAsV!0^D80vjk`etx*9n9~&T15>Fe(vrk39r6>mFDIq z_qMhNun*!Z_`hyAJ44$$jXe&xWj5E|A4YJGViYWvTMul1kX&0B8Br0a_UvI5v7s6b zFs>^{SPr-e6s?IZ){slM!94~UR*pu-d%#uwG2&FruY}) z+}+%e6##r2ReTYf2TKQbR*c~Uqph=39X^o${&IvL*tBhe@MK_1T7xZ@Ymj${6%I^n zR{SM!IN+Ft*>IngBB)wS4*w5-RtF@vGZ;^N`7%!p|CXc+aC%TV`z>DJ{mIM6CkXBU zGCG{1M+X^=?HHx6p^eH${gR3hb=;j@=k39xEL@Kj$K1$nDk}^=6eX+LZcw<&BQ!Q^ z-!HPm*}6nw4l98m63bGH0oovK8v!59>DZ5Ua0T8h7&B z6>}Uno$&_MfVD#!mLF&G+v7zIvCHd8oc^3sUS& z`5!GnWzU~`l%}(Z$BG{bU!rT?Uoa-2{#5$05y=gkW{F)&CI6~}w71;JTsLp$TfAiZ zL9{BMc-o|LZ4p1Yi-&iycn$rlB%%)w0e$#ALVDnR zVgU6$w_SYJaZ1ACeIXPAB&Pc0;kN0V%|?2{mXS*e^~rN z%HNF*sUpYgnMyDF}&h!&gIki;F^cKFqa`Ytn$` zl-frT=Fby5?Dp@td7kap(w$rW&<1h@&;*$=M)r)9Has`3d>q11<8k%ggB15~GYQ*< znmw#1&mC%5u&5gyUQro+IX7+fvA}cRj&?bH&QG*wE*&$wE#ucY7HS$NVf;mqb=F^c z%0p4_d+#<&8kK~}m!#@g*FWnS896&?Ua8z!|B%t}b69xf&1dV>B>v!lqcj==6%PvK zBaMp|rt+>{y=IY+kdo2bCqrK|F`cqg@nbjjws+^BKnn?zL0Zp*7)=S)i$|Iz0~btZ zxzVWEh8tzEPQpwjovmXR;e?@D@=N6?MGd``o83uTL-+m&&#%^$sm2tB&gN@#kBgte zv1VD)I?d((*H3y%^X9_HreF$`!i3E)XX5(wo6R;)R{mT+^?cPiG0`^Qi0L@TAz4d( zM8tL>WXMgvm?BlwxpS^oo zY_YfhEyJO7Ic^&Hs@3U8X06iX?LR#q(hb@6`m&Q>crzL1lNIjFtgWvzHZjRzaW$0r zsymatuMkQ@yY47pMs_Z%JORl)bmIuS_2xrd`?v??4#_;EUZJAUp#1o*FFqkvnnLXRvwc;n78c?ZMY~P=YR0lo+ zo%s;DKJH1Lw-Qmiy-c}h&mY&*ixHxkt9KJw_dBS?ZYd(HAVKf6aYVE3m*>D-bi>BL z&6^rYsgbfRd4&^0Y!ebihLvnIjR}ga3Cv6}B`n81QsubY{I(xa+D=_JJL5UqQE+tM z?%%&S2>vf`j@e&w%D?KozF5|;H#zdQeg_BB+~+@&F`H-pNi{KjZuO-M>!Gq>yLVbF z?)OY+Y_aj15Ba5)f+_Xx>nY3sewF_=Q8ZDl;iNn9LSOrVwkC*NsICA!o$W!sbQeVp z2YdV6l0%~9*~)Ksr9Ox^l%QHYEYlEoIr4Uz>D1hsu7!$I=N!Y=2XD_-d+YaIP@(W` zf0t^?oM;iTRc-t#k#(g%Hvd=P>UIBXQdAsuk9}`F%4_X=E%S1udi7G{Xv*zV4tCaO z{*7-N8gGRED|uH{P9sdA~(oA=~+jcy1?Z2taG-fDe8e9tCt?zyB2{S**iCpOZvwCZ-r*!6S zP5iopqlSQ zE^tw@G!m?BY?R8mLM{ND2F#l%*nPRII>9DG=ZgRIhDyizMeANX@o=Q^*}=AyJtS@k z16`yt|GLH|ocL_To+LlkWUZ9%h~LdMpmCfsNvE@b(Xgn@{SGHbWp#V+tFo$^i$1~8 z$?}(d!>ba|<&IAFQ`}!^{K}BGd|Xu2@k+$P$<%pI-Ryl45fM1$n&R%MxY2n@nFDG9 zhAXVEXUm0Lb;7QZg`bUi+pCs!i2Le$()Jvh%r7*V_kMR>Y={yn^b%FPK<-ezC+c+A zh3<>iRP2@2#g9!@^0U8-J10J2Cx1HQI<~~{yPqz@idt_+toz9>pN4Ut`yVOkKKSt* zx#+WYxM{u(jdXa^qvt%tg?F1a_?&5QzVTf7_@m0_2@Ec}B#-D=&T%}}<~s9-N0s#~ z-3ey8qi65lCzD%<5u24$vp;vtgm*B4F3B-;)znWo?Jnhc#oJj2Ufi!BQt8WHJ5O;7 z3;%><07YkgNlwP{ww0Q}>bC8m0x?$hO<`uoiQuqY8^hQh3GI)8LlJEh!TI;gq#bFS z%OCYrcw@%^6VjIqn$FE`8KOLtrtQVM z{?^Iv*wY#{TKf7kE>8DcOu0OxM*56#VYP1pg@ZkfZ$`&3}IMf*T`trjnhBO8y zmsg|2AAuBY;C+>v9Jz98*og8uAYp&~${YyW$Gp4A^~Q~JchG)<+Pdj5aS#B!fOlz* z96c%tWBBLK`9{U*#l^G=@i8&qCnhdmx+Dr~Gm$zo3Y?VR#*gO^V}Op~IMEU7Bjb-f zf=V@rJQ}L1pUWK#!K@FCY8nMdUB|-WB}DGXo@g2Y=R+O$-_NFfaDb5Q*!#A-`+DmQ zB`3cQxsE|)(28YT#>o54ecCLUD)4>YIL^((BToe>4{9~=GoniO0X}eORQ><1qo6fK zgajgLCo*=@)9oD`y57D;VIo=9zrlI55$-1is;RdLAd&i`3=8Z1(W8i~!3-+_PSyv* zA0S@=Zw&&$U>cM$3XDsMmK$shc!+>Yg2P}pB^Nh0_o-7v#6BW$`~Q8f4BlI7#m}Dc zfWW~7jUUVLQ;TI;xBLnBc_)I_#v3aa2Str&z|s^nNz3u!8H~^&5w(#2~dEZDMczg zcUa>Gmk#w`zD`E^UJxERelV7C{n@L?I0I|LQSV7CTA{nri})Py6f%N&{Y{?hq5y=U z0z_n4ojUbtVBnw-Jry~u6a)gk(Yjzb*hd=7YHATLOPo0aV$3%!pw93JQ2jbCAnhFgG@)Yhpsp(d^XF*3J zAm=8IsUs{jG;;k%674BcdZuV;LX`mM14j^BE<7Z}sLYl&vNci6t```XmQiQ+U~opD zQ(j$Ot^xNS#MHZ1sKx;DQS}fWG0>$T5k^*T)pVDHfL#(|YUs8&%&KKgWYTGxn-7Di zIWoI5J)SX8I~1z{z6zqP*IuPB2w+#*lriH^AQuoffsf2TC=f<`|9m|);sbvg6U0Tp zIRkHnjQYcmUr_GC6Re^_WGrJvkKVh)G&wWVG2zO3=ul%*6A1yn86v?RHH#KArL$+d z<4|6)F-D7bWP1my|bMj^W?F=>=52&ycss#|{kKk_z;=A}!@JY*C?pAFD959(mx&BB5on!@6V z=gWmeRq=Rgc<3z#{r! zybm5JevcsUT>5VM6%W_kyu2^haF7v4F669IEFF*n*##v&{OP&3iFZ@0_fQ32!^)L} ztChRfENo`R9t8~G9lHf;31Bh?Sr2z>02z)7eJ@V&r%$t2Dbn~z11%eacj8&X&zC;H z$digi7$tx4;t-l^QF9&~UQ)>~Uc9(-rv(MB>{aD6|NU-E)_i0VyEIi*nNB;i_cyTX zE3ngOB#Q58DuN-@GxV1EyTlZcsAUfmka*FKD#HDW2ap}C%8ibqt-bvQ(X`WX_WXao zMB0!FGLENUVcl!0#!ie4JQ$x(5UQ=d~wB^Jx_Hi2*R6b+hY5_cT<_442LB2X`L|NV=8VTxFLduWw<7p@XiF>{|ib4N)E zB%=x@PZyUQ9&Hnofh+zzI3jR9teFQp{yC6#VGb+-cqCE3#)ukRogcH^{y5|E!#iV( z|8~p!{=cI#n6d*5u*fNcH#ynaRjw1%k*!>;swHo1L_iq|Vd0O?e(^%<{P~HMb&;<$ z|9WghaA6j*YdBoL4t_89K(rl5QJ8zc-!`=CP9vy~>Vq7{mqZd^Q}2BjwQ0A50~5Yz zEUqSeBoI)R!V+yJ0|m?-`g;U?qy%!(*GLDJHjlv24tAUhz6SgPOib9q|BbUBjjZdo zw(;QX0^4_D_pY5gkyL-h1cpnOG9n|j?CtrMG;pS>3OUH6$f9F`x_wuI=<}i?VRrU! zIHceY!n(tStNq2W$Yi#|%!q0dy7nw87>3 zT_7K!u!E)lhO4W`!qAVoIg|(;u3aNSQn45ms4%d^Z~M35)&IiH_kKJ5V+Q0#jK1i# zEyMT$9H5>9u_Q9rVA!t!x)Zf|QBl!cUvEZzU30t%s8Diyi4=2?c$e+*%adYaGVUi~ zCd=h3S32^3udZIuR=4TP)SjQziC51#UaMaBYpSWid%HqVieqimL;;|NnjvPa;I4cF7(9YB&CP>_r;{tR?&he9ExU z&|`dj8yI3o`~~7XD>Fp1I+_`{+ICOX<>yp7g?GZC{QDE2QRenWVZ zre-6GzyrWlZx1vfJitg#PeNn}`#&Bgx)q_0A_;GCVh>^lNvWQZQG8UCTuryeksFBR znv+gQQe~53NAQ`HVlam#k>{-}iP|ysTok7a1#qu?MVCM-PG?0Egu(;am_gYk2zh0w zRn2@DJf(gwFF#y;-PH6QHFKIqm`m<}QGW*|TzoxfBm>Iibq<5Zva+s#%8Je{R{c7* zAaZ{LCsFV`%MZm_~v=dO??*=J8%k6mPIQ-B(VGjn67pF*T9%4om_r*XU z#3&dNp)cTBV^$M;FwZ2mm65Nc6VzkORibyu_412iF9>$H*oH|rSL5N)R{BuAXvPPaVb(3 zkqdJUNwH=+z{HgON)xjkun3+cCSGO}^t*5M84)eRXT;1JK0bA%l578%?jB2i2#@J| zJoj|ggpWU8j8o6yu=hv5qSr%J{KRfk%poL|MDG$S`hdk%?~gVOsY}6%h>!5I!A%M^ zK>Zz%$FU4@Qm{L#ag+iWziZ~seCDq4hEP+iHDqB%jhNsjL z(>WID4;HCloVr8@K<;ao0d3mhA7Eu9Cr4zhH18!4uvr0bAOy5nk7g0i4v>56JaA+p zsJs7yjqt5N+~5#`>>v|QPtV>sCT|RMGL?74`vJO3zZjX47DYMQR6IO9xu13F?kCRt zFhrP1QSRlFOTD(ES}M~*{4_X^d;?A@`nniZuz6NlxxBsM{bNzgNua;OB?7WVwItF$#nt8Hu2n=sLINEgM52%P*O_j zX^Zvx=BBBU5tzUelaslHM{oo?J3C`;!=Al+uZSdIF<|z9S3j;bq#DKoAJHHL@Q#Gw zBV)0}P?eTO;va?9G=eL;PQ*o!Y_DC~doQD)AUrH9Xsb#}iSs?W-`J@B|F%7;($?mW z`$p;^s6r?YG6I2sZ-g`AL|ffWY6(_hOX9a1l2WB{WPhbVB#3&%MfCx`+&q#Xw4 zHi~8YX=qYkb>k*QgHyRihUsoslBD5loyA=Sq?ejEQ@;u|z#39ox`OMlg=g*0AMkDw zzhY{DA{FR*EhBRXwINk8gQfH5s3ICKQXF#JproMdWlTq9g#oW1hWUFf~iG=j(*5I~?B?TF=XNr(ywp^{=@KO!SD{NY24(b)Vv>;C;1 zhj`x#P+5lHpU^3#@(f}$gHxTcherh-=7PVrwl>}~JW{yHLcdTZ7^0`{J~}$;2zOf_ zW0}aty(TQ7I00kM`h&l4(gBV+k6?h62;6nqLrPd%Tf-v3KEZy(M2n?UZk+hHOk;8! zJBaELuOVszZ-`0!T0Bl9d~zI+fP_Je2El`ar6ufRlt{wC@udqL8X9UYbwK6LW2P?$ zL$HwFzxn!=l^~1&0F%C?_U$5I6+#!uo!GVd^Cz!>fW9z$4m}1YAh6tbP^=9DibghW z;S-3EJ;l`n5diX3 z{fQ2S+D zlD*76@$4}&_@bpG6@G!$pg7 zlZS;1Q=m2l{R(H_UaC=Wl~96-n&ZqSJtm|uf7*4N>aNv%NgpLCIO;-mj{-~fJVKXn zYI+(ha^?85<%Dl>?KalN<>p`OyR`HE|x8^<2F=FEonFx+lJ(?$Rgn@r<~D1v8UVd5YyLI4pCi+71b8yNtqT;REi5HP0kRae(M z4sM)Q$aipOg71vO1!L|Y0|OdA^udEicJl~7@OQuBuEZsP)c)2?-!V0z-D6Ek^^@Xt zg8Vg`WADSpNRtCzjBykgs>~?Vciy>O(Aq9@F;{oOoJxgHI_p{Bk=vu6yF7|6SxDaC ztCY4t?aJ=U8&KO(P(1`}ia4>_g|0ftq;N3eL_mT7k{RHUh$T@$MY4cf<0t; zHQ$G;Z(POafuR5=`Wj&pl>!uAE}EHvri98H)9yF;#0Lb7qT=F+#Q2BhP_u-C6b~g2 zAs_{1EV%WM5b9rKXukKLW~k{%(9bD{s}WyS=|hwVZBaUh&b`*-E!WPip8H50Tl8!X zH$$6?s>dClq}XRmA_De=@OCm86H#{#bwjPffg#blhZ}}2p0z6df{Q9e!aX-8CdO+x1RN}c(Rqes z7VkjZK66e;fm`<*6a;(I@Gkeu#Xh}vF|GfBTYQ(hgvhQ_w z^4W}IGvBvUb8tdigZy?dAL+>OUqp$G!(Duf0kJ}zr$9&|( z1UVqeh9^;OMZXBa3L z$%X?yliAJ(z6*W8#{KmX?-6Oz;1!;ft*;Na^ccHe@~u6;{ZFFT$i#${fQtozC=p{} zU~tFENKNfN!0_Q`p}Hh~LWE0TnQK1(uyl+DISIsKIXM{i`(g1ycaNTXZnyZhzoXJY^*OZg2ne^9bNm8}12JTKUJm#KS^!VNL zeDQpVfj*K9va957rA3dXZnWw_S*5Q(J~kF)#bmB)VDNk6w*!{NMJ;5&l0Iucfk*_M z9p}taAU+F@74S80-n_s3iQ9pIkP4G*353jvaGH=+h2z%dfvQUMPsM}FsAaS0XY#F; z^-p@l>g9hMvhfj@>s1WR$aBcev$vOsT}EJy7o9qq6nLq2VNhL*I_>E6j~~BbVa@Ti za}YbY$4+ppKK($4`h~Y1=U91n8$PRf23WV2Rhb|e<4(Me_vVS)2g23 zURz%WlIpg-5KTy>ob)5c+~pQ?h9n*q8d;sJ(%#q41O|1r9?j;v?ONwJotCpLJNl!~n`=a3nz@T;-5@kgad zE&OVP02PLlwozx4Gu{b;mlAffxo$pLA}Z#1RH9PU{iElsO7i{RpA-tyZq zb>!a-&=xqA>6_?vq2tyU8F}NE5<=K#D9FL9K)n6|Z|q-Sr*TA|m$A)o&{LC@x1B}x zFhwBxx8%yf2VLC?#?$ginTI=nYVah@2QPO{t>BDAEx;UQ{ic1gXthP#M`C@+OPB0% zvSqz-^Il)zQxb84jScrt`nxt)2(Q$mcRY3cT+mLUYM(0QE_YCO|GB-r=br6tHg8w; zR%JR8vFg4TS5GAf=l>ZIgW{tUKmV?F!7)Xw+To9(Bu+6B+BRA>9OQ(6`1RQ#$0R+r zp)HQlZ(EViH})`d(NL3m_9=Uetw~IyE(Kw! zW7v7}^cz_8yHx42f}YTtc51M;N&QXyaLdo4_Nc@Us(^1lQ>JeHaX#(ARUGm@j;!yyR}Iwv*YvSDSk4&m)XN9b=fjij%;YnUW&$-&hrTvR?N?vDHuJ z%A1w3pv$sOM}GZ!oJ00ZLcL0iG+J0z)*so1@{3)lYgr&tL%|L&N5?K35oD5R8pgC= z!x44u8pd;?aS4e%@&nYw@V3F7LR^g`2LD9W1@RmnKZnidRbl-DJj9e>h~XuNxyON z>By(MA6EztHXfPn-%oh89T&OPVByE^6;p9U@0xY}2u!ohPI1Cw(~^w&|F&WhZV9FA zP7?NPNps|+VlBAVbNS*ArzsG9Eeck;9zD0c+%2sqHhK2Y2&R4bFZaAmd2q1ax`kRx zOAAp}f0I$Psy-4vypWyYpU`yUh5v-1kSQr67F30C1kE_Qpzg%$X;KpEQ^bK% z4i30f_2+g4PS0eAE-Sdwt7boplZX<$UT`Gr#%$9{;LrF=;!@V{1xsVBYKy)ZRkx|-9eqNu2N(~gCllw&`x1+EC4(6;?{ruP~% zRjN!P;-2`bAKbz9%SBSCvwP^x&?~PF%f;Zg4h5yQp|?E<_zIa6OY161veF7`(iXZ) z=N5Zf<*9TJe`OsTmwDU1y~wC__e@RP#|z68K8@N;b`e64BxFO6aPpq)Ryi$d%;m!R zuT`GCkG5QU_=57oKI3z~JY`4t9{%znW4|n4BCxcOl6R!X$<|(=u#o*1A@l+TseHGr zx0u}K{A&Nmb&L9>xXamj`v`3}xBFV&46F9APrU9bYG3J189M5D{7dnnq}Ur*mU~`^ zb~(tg%lPyudIw%R$w_(pxYaT4)^P6r*r?u9vUIJaUgBJrgF6F0{AeF5v1nKu)ol)J zsEF91SYdu&>Sy$zCDp493y)tvez^I4O&$;V+>|!xR_?|gz{%Uee{;Pg^XF=*03(aX z!1r4ZH+V2LTqffz` zgnc^9HHpF|$KYVEf^q+{`(w++0{6#Wq#}DSaA%ZU5!|mftl@&QZt?JM?cv8~^!R4; z>CVUSXjAv=&cr=!;_g&EW^&nA?Nj?{h970*q=D1UcwP*=9NL8$uB7tMI0_mU*Inm$ zdyT7~$?41l(Ddd`?jsHKTFeexR-4peP@9*W$rmYgeNc8|CiS=W<)xyvO1>|Qcz1=_ zcb4s~G_u+2`MKot)Mn%ua`b?>mbF)i??`lVUv-)>|p`no~dga4QRyAYDq<*)`!_c|*MS{R{hS zirne^Trv|IE=Q&g-Q(`5yx(FMRM$h;a_*DZ4UpEzs9U5wd-2%}@91nFXU+S|_D=D% z8lN?Ge3Kn#pymGaHgNoKXp`!!L8tzHJ+jdFTF^aSqqH zJ%e1yc=z5javpp^)2^MD&a2LT%+EM#^J`&VqRltpfS!6`EfsmXw00Q74d*A`bt+mn zv@S~h`%|jYwKe(Y#(>%~rK8C4?ffp*_XNxP)A6c`>gt_MzOTl$j#QnIIFazSVnCUl zhFXUUux_!HC!HOgVQQzJV)nrG+p65@16(s{?`<~(9^VN~Kuf+ll=-fe{;gm+pSA3` z=BsG*~>gr*d&-Lbak){b|XP~7{MP5!+D-lP|o3P-pktC2O2gF=JT$Nc+kecF_nUm^$$}_~HDZ$p(R?k^E xdEKK!Q;sAFJbJ{$5a7+oB*Ki_2%srou%r=0Aq))gW@Q73Fan_kkah%d7yxx69j*WX literal 0 HcmV?d00001 diff --git a/practice1/README b/practice1/README deleted file mode 100644 index aa2cc41..0000000 --- a/practice1/README +++ /dev/null @@ -1,11 +0,0 @@ -Задачи на практику №1: -1 - зарегистрироваться на github.com -2 - установить git на компьютер, создать rsa ключ и активировать его на сайте -3 - форкнуть репозитарий -4 - скопировать репозитарий практик на локальный компьютер -5 - создать текстовый файл(в этой папке), где имя файла будет фамилия и инициалы студента написанные слитно в транслите - Пример: - Студент: Иванов Сергей Анатольевич - Имя файла: IvanovSA.txt -6 - сохранить изменения в локальном репозитарии и отправить их в форкнутый репозитарий практик на github.com -7 - отправить запрос на pull diff --git a/practice1/SvintsovDV b/practice1/SvintsovDV deleted file mode 100644 index e69de29..0000000 diff --git a/practice1/testForWiki b/practice1/testForWiki deleted file mode 100644 index e69de29..0000000 diff --git a/practice2/README b/practice2/README deleted file mode 100644 index f2095cb..0000000 --- a/practice2/README +++ /dev/null @@ -1,2 +0,0 @@ -Написать программу на яп Python. Подробное описание программы находится в файле с ФамилиейИО студента. -ЗАДАНИЕ НА 2ю ПРАКТИКУ БУДЕТ ВЫЛОЖЕННО ПОСЛЕ ВЫПОЛНЕНИЯ ПЕРВОЙ ПРАКТИКИ!!! From bd6a2e0415e46942821ea72050cbc6bfe41c2537 Mon Sep 17 00:00:00 2001 From: uralbash Date: Mon, 7 Mar 2011 13:46:33 +0500 Subject: [PATCH 09/13] del trash --- asd/myTextFile | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 asd/myTextFile diff --git a/asd/myTextFile b/asd/myTextFile deleted file mode 100644 index 2452241..0000000 --- a/asd/myTextFile +++ /dev/null @@ -1,4 +0,0 @@ -bla bla bla... -123 -sqdasdasd - From 6c73a57a6a65a49a6983dde31b3cb9b4b4b6ca45 Mon Sep 17 00:00:00 2001 From: uralbash Date: Sat, 12 Mar 2011 12:05:21 +0500 Subject: [PATCH 10/13] added lecture 5 --- lec5/README | 5 +++++ lec5/client.py | 16 ++++++++++++++++ lec5/cycled_server.py | 26 ++++++++++++++++++++++++++ lec5/dns_example.py | 16 ++++++++++++++++ lec5/myip.py | 11 +++++++++++ lec5/myip2.py | 8 ++++++++ lec5/sendmail.py | 32 ++++++++++++++++++++++++++++++++ lec5/server.py | 38 ++++++++++++++++++++++++++++++++++++++ lec5/url.py | 9 +++++++++ lec5/url2.py | 20 ++++++++++++++++++++ lec5/url3.py | 10 ++++++++++ lec5/url4.py | 30 ++++++++++++++++++++++++++++++ lec5/url_parce.py | 33 +++++++++++++++++++++++++++++++++ 13 files changed, 254 insertions(+) create mode 100644 lec5/README create mode 100644 lec5/client.py create mode 100644 lec5/cycled_server.py create mode 100644 lec5/dns_example.py create mode 100644 lec5/myip.py create mode 100644 lec5/myip2.py create mode 100644 lec5/sendmail.py create mode 100644 lec5/server.py create mode 100644 lec5/url.py create mode 100644 lec5/url2.py create mode 100644 lec5/url3.py create mode 100644 lec5/url4.py create mode 100644 lec5/url_parce.py diff --git a/lec5/README b/lec5/README new file mode 100644 index 0000000..3c67e85 --- /dev/null +++ b/lec5/README @@ -0,0 +1,5 @@ +Написать программу на яп Python. Подробное описание программы находится в папке с ФамилиейИО студента. + +1 - Сделать pull из основного репозитария с практиками в свой форкнутый +2 - Добавить в свою папку программу +3 - Отправить pull request в основной репозитарий diff --git a/lec5/client.py b/lec5/client.py new file mode 100644 index 0000000..df66614 --- /dev/null +++ b/lec5/client.py @@ -0,0 +1,16 @@ +# coding: utf-8 +#Клиент вначале создает точно такой же сокет, что и сервер. Первый клиентский +#метод – connect() – позволяет соединиться с сервером. Второй метод – send() – +#отсылает данные на сервер. Третий метод – recv() – получает данные с сервера. +#Четвертый метод – close() – закрывает сокет. +import socket +import sys +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +host = 'localhost' +port = 8007 +s.connect((host, port)) +s.send('hello') +data = s.recv(1000000) +print 'received', data, len(data), 'bytes' +s.close() + diff --git a/lec5/cycled_server.py b/lec5/cycled_server.py new file mode 100644 index 0000000..f8e97dc --- /dev/null +++ b/lec5/cycled_server.py @@ -0,0 +1,26 @@ +# coding: utf-8 +import socket, string + +def do_something(x): + lst = map(None, x); + lst.reverse(); + return string.join(lst, "") + +HOST = "" # localhost +PORT = 8008 +srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +srv.bind((HOST, PORT)) +while 1: + print "Слушаю порт ", PORT + srv.listen(1) + sock, addr = srv.accept() + while 1: + pal = sock.recv(1024) + if not pal: + break + print "Получено от %s:%s:" % addr, pal + lap = do_something(pal) + print "Отправлено %s:%s:" % addr, lap + sock.send(lap) + sock.close() + diff --git a/lec5/dns_example.py b/lec5/dns_example.py new file mode 100644 index 0000000..303688e --- /dev/null +++ b/lec5/dns_example.py @@ -0,0 +1,16 @@ +# coding: utf-8 +#Модуль socket имеет несколько вспомогательных функций. В частности, функции для +#работы с системой доменных имен (DNS): + +import socket +print "gethostbyname: ", socket.gethostbyname('www.onego.ru') +print "gethostbyaddr: ", socket.gethostbyaddr('93.158.134.3') +print "gethostname: ", socket.gethostname() + +#В новых версиях Python появилась такая функция как socket.getservbyname(). Она +#позволяет преобразовывать наименования Интернет-сервисов в общепринятые номера +#портов: + +for srv in 'http', 'ftp', 'imap', 'pop3', 'smtp': + print socket.getservbyname(srv, 'tcp'), srv + diff --git a/lec5/myip.py b/lec5/myip.py new file mode 100644 index 0000000..53389d5 --- /dev/null +++ b/lec5/myip.py @@ -0,0 +1,11 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +import urllib2 +from BeautifulSoup import BeautifulSoup + +strURL = 'http://www.viewmyipaddress.com/' +f = urllib2.urlopen(urllib2.Request(strURL)) +soup = BeautifulSoup(f.read()) +f.close() +outerIP = soup.find("p", {"id":"copytext"}).contents[0] +print outerIP diff --git a/lec5/myip2.py b/lec5/myip2.py new file mode 100644 index 0000000..58d258d --- /dev/null +++ b/lec5/myip2.py @@ -0,0 +1,8 @@ +import urllib2 + +strURL = 'http://api.wipmania.com/' +f = urllib2.urlopen(urllib2.Request(strURL)) +response = f.read() +outerIP = response.split("
")[0] +f.close() +print outerIP diff --git a/lec5/sendmail.py b/lec5/sendmail.py new file mode 100644 index 0000000..ebfcad3 --- /dev/null +++ b/lec5/sendmail.py @@ -0,0 +1,32 @@ +# -*- coding: cp1251 -*- +import smtplib +from email.MIMEText import MIMEText + +# отправитель +me = 'me@bk.ru' +# получатель +you = 'you@gmail.com' +# текст письма +text = 'Это тестовое письмо!\nС наилучшими пожеланиями!' +text = unicode(text, "cp1251").encode("koi8-r") +# заголовок письма +subj = 'Привет от Python' + +# параметры SMTP-сервера +server = "194.67.23.114" # "smtp.bk.ru" +port = 25 +user_name = "userName" +user_passwd = "userPass" + +# формирование сообщения +msg = MIMEText(text, "", "cp1251") +msg['Subject'] = subj +msg['From'] = me +msg['To'] = you + +# отправка +s = smtplib.SMTP(server, port) +s.starttls() +s.login(user_name, user_passwd) +s.sendmail(me, you, msg.as_string()) +s.quit() diff --git a/lec5/server.py b/lec5/server.py new file mode 100644 index 0000000..61bf021 --- /dev/null +++ b/lec5/server.py @@ -0,0 +1,38 @@ +# coding: utf-8 +#Напишем простое клиент-серверное приложение. Для этого нам нужно импортировать +#класс socket из стандартной библиотеки, в котором есть все методы для +#организации соединения. Клиент посылает строку на сервер, сервер получает ее и +#отсылает клиенту обратно. +import socket +import sys + +#Код простого сервера: вначале мы создаем сокет, представляющий собой указатель +#на объект соединения. Этому сокету мы передаем два аргумента: первый аргумент +#говорит о том, что это интернет-сокет, второй – что мы используем TCP-протокол. +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +host = 'localhost' +port = 8007 + +#Первый метод, который мы используем – bind(), он инициализирует ip-адрес и +#порт. При этом проверяется, не занят ли порт другой программой. +s.bind((host, port)) + +#Второй метод – listen() – устанавливает количество клиентских соединений, +#которые будет обслуживать операционная система. +s.listen(1) + +#Третья функция – accept() – блокирует приложение до тех пор, пока не придет +#сообщение от клиента. Функция возвращает кортеж из двух параметров – объект +#самого соединения и адрес клиента. +conn, addr = s.accept() +#Четвертая функция – recv() – читает данные из сокета. Аргумент устанавливает +#максимальное количество байтов в сообщении. +data = conn.recv(1000000) +print 'client is at', addr , data +#Пятая функция – send() – отсылает данные клиенту. +conn.send(data) +#Функция raw_input() просто блокирует клавиатуру. +z = raw_input() +#Шестая функция – close() – закрывает сокет. +conn.close() + diff --git a/lec5/url.py b/lec5/url.py new file mode 100644 index 0000000..23fed17 --- /dev/null +++ b/lec5/url.py @@ -0,0 +1,9 @@ +# coding: utf-8 +#Функция urllib.urlopen() создает файлоподобный объект, который читает методом +#read(). Другие методы этого объекта: readline(), readlines(), fileno(), close() +#работают как и у обычного файла, а также есть метод info(), который возвращает +#соответствующий полученному с сервера Message-объект. +import urllib +doc = urllib.urlopen("http://python.onego.ru").read() +print doc[:40] + diff --git a/lec5/url2.py b/lec5/url2.py new file mode 100644 index 0000000..8a715cb --- /dev/null +++ b/lec5/url2.py @@ -0,0 +1,20 @@ +# coding: utf-8 +#С помощью функции urllib.urlopen() можно делать и более сложные вещи, например, +#передавать web-серверу данные формы. Как известно, данные заполненной web-формы +#могут быть переданы на web-сервер с использованием метода GET или метода POST. +#Метод GET связан с кодированием всех передаваемых параметров после знака "?" в +#URL, а при методе POST данные передаются в теле HTTP-запроса. Оба варианта +#передачи представлены ниже: + +import urllib +data = {"search": "Python"} +enc_data = urllib.urlencode(data) + +# метод GET +f = urllib.urlopen("http://searchengine.com/search" + "?" + enc_data) +print "Метод GET: ", f.read() + +# метод POST +f = urllib.urlopen("http://searchengine.com/search", enc_data) +print "Метод POST: ", f.read() + diff --git a/lec5/url3.py b/lec5/url3.py new file mode 100644 index 0000000..0fc3848 --- /dev/null +++ b/lec5/url3.py @@ -0,0 +1,10 @@ +# coding: utf-8 +#В некоторых случаях данные имеют повторяющиеся имена. В этом случае в качестве +#параметра urllib.urlencode() можно использовать вместо словаря +#последовательность пар имя-значение: + +import urllib +data = [("n", "1"), ("n", "3"), ("n", "4"), ("button", "Привет"),] +enc_data = urllib.urlencode(data) +print enc_data + diff --git a/lec5/url4.py b/lec5/url4.py new file mode 100644 index 0000000..ce796d8 --- /dev/null +++ b/lec5/url4.py @@ -0,0 +1,30 @@ +# coding: utf-8 +#В следующем примере программа принимает большой файл и, чтобы пользователь +#не скучал, пишет процент от выполненной загрузки и предполагаемое +#оставшееся время: + +FILE = 'boost-1.31.0-9.src.rpm' +URL = 'http://download.fedora.redhat.com/pub/fedora/linux/core/3/SRPMS/' + FILE + +def download(url, file): + import urllib, time + start_t = time.time() + + def progress(bl, blsize, size): + dldsize = min(bl*blsize, size) + if size != -1: + p = float(dldsize) / size + try: + elapsed = time.time() - start_t + est_t = elapsed / p - elapsed + except: + est_t = 0 + print "%6.2f %% %6.0f s %6.0f s %6i / %-6i bytes" % ( + p*100, elapsed, est_t, dldsize, size) + else: + print "%6i / %-6i bytes" % (dldsize, size) + + urllib.urlretrieve(URL, FILE, progress) + +download(URL, FILE) + diff --git a/lec5/url_parce.py b/lec5/url_parce.py new file mode 100644 index 0000000..972f8b0 --- /dev/null +++ b/lec5/url_parce.py @@ -0,0 +1,33 @@ +# coding: utf-8 +#Функции для анализа URL +""" +Согласно документу RFC 2396 URL должен строиться по следующему шаблону: +scheme://netloc/path;parameters?query#fragment +где +scheme - Адресная схема. Например: http, ftp, gopher. +netloc - Местонахождение в сети. +path - Путь к ресурсу. +params - Параметры. +query - Строка запроса. +fragment - Идентификатор фрагмента. +""" +import urllib + +print "urllib.quote: ", urllib.quote("rnd@onego.ru") +print "urllib.quote: ", urllib.quote("a = b + c") +print "urllib.quote: ", urllib.quote("0/1/1") +print "urllib.quote: ", urllib.quote("0/1/1", safe="") +print "" +print "urllib.unquote: ", urllib.unquote('a%20%3D%20b%20%2B%20c') + +from urlparse import urlsplit, urlunsplit +URL = "http://google.com/search?q=Python" +print "urlsplit: ", urlsplit(URL) +print "urlunsplit: ", urlunsplit(('http', 'google.com', '/search', 'q=Python', '')) + +#Еще одна функция того же модуля urlparse позволяет корректно соединить две части URL - базовую и относительную: + +import urlparse +print "urljoin", urlparse.urljoin('http://python.onego.ru', 'itertools.html') + + From 1d2748979dbc0649033e0a1ffc226f30330a7ebf Mon Sep 17 00:00:00 2001 From: uralbash Date: Sat, 19 Mar 2011 23:09:47 +0500 Subject: [PATCH 11/13] added lecture six --- lec5/README | 5 --- lec5/cycled_server.py | 2 +- lec5/dns_example.py | 2 +- lec6/base_http_serve.py | 46 ++++++++++++++++++++++++ lec6/client.py | 17 +++++++++ lec6/databases/sqlite_ex.py | 13 +++++++ lec6/databases/test.db | Bin 0 -> 2048 bytes lec6/email/receive_mail.py | 19 ++++++++++ lec6/email/send_mail.py | 32 +++++++++++++++++ lec6/serialization/objects_from_file.py | 13 +++++++ lec6/serialization/objects_to_file.py | 17 +++++++++ lec6/serialization/persistent_object.py | 8 +++++ lec6/serialization/pickled.dat | 15 ++++++++ lec6/serialization/somefile.db | Bin 0 -> 12288 bytes lec6/serialization/users.dat | 5 +++ lec6/serialization/write_and_read.py | 31 ++++++++++++++++ lec6/simple_http_server.py | 15 ++++++++ lec6/thread_name.py | 17 +++++++++ lec6/threaded_client.py | 25 +++++++++++++ lec6/threaded_server.py | 35 ++++++++++++++++++ lec6/webbrowser_ex.py | 11 ++++++ 21 files changed, 321 insertions(+), 7 deletions(-) delete mode 100644 lec5/README create mode 100644 lec6/base_http_serve.py create mode 100644 lec6/client.py create mode 100644 lec6/databases/sqlite_ex.py create mode 100644 lec6/databases/test.db create mode 100644 lec6/email/receive_mail.py create mode 100644 lec6/email/send_mail.py create mode 100644 lec6/serialization/objects_from_file.py create mode 100644 lec6/serialization/objects_to_file.py create mode 100644 lec6/serialization/persistent_object.py create mode 100644 lec6/serialization/pickled.dat create mode 100644 lec6/serialization/somefile.db create mode 100644 lec6/serialization/users.dat create mode 100644 lec6/serialization/write_and_read.py create mode 100644 lec6/simple_http_server.py create mode 100644 lec6/thread_name.py create mode 100644 lec6/threaded_client.py create mode 100644 lec6/threaded_server.py create mode 100644 lec6/webbrowser_ex.py diff --git a/lec5/README b/lec5/README deleted file mode 100644 index 3c67e85..0000000 --- a/lec5/README +++ /dev/null @@ -1,5 +0,0 @@ -Написать программу на яп Python. Подробное описание программы находится в папке с ФамилиейИО студента. - -1 - Сделать pull из основного репозитария с практиками в свой форкнутый -2 - Добавить в свою папку программу -3 - Отправить pull request в основной репозитарий diff --git a/lec5/cycled_server.py b/lec5/cycled_server.py index f8e97dc..9718f12 100644 --- a/lec5/cycled_server.py +++ b/lec5/cycled_server.py @@ -7,7 +7,7 @@ def do_something(x): return string.join(lst, "") HOST = "" # localhost -PORT = 8008 +PORT = 8028 srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) srv.bind((HOST, PORT)) while 1: diff --git a/lec5/dns_example.py b/lec5/dns_example.py index 303688e..d48ed48 100644 --- a/lec5/dns_example.py +++ b/lec5/dns_example.py @@ -11,6 +11,6 @@ #позволяет преобразовывать наименования Интернет-сервисов в общепринятые номера #портов: -for srv in 'http', 'ftp', 'imap', 'pop3', 'smtp': +for srv in 'http', 'ftp', 'imap', 'pop3', 'smtp', 'https': print socket.getservbyname(srv, 'tcp'), srv diff --git a/lec6/base_http_serve.py b/lec6/base_http_serve.py new file mode 100644 index 0000000..66ed1ea --- /dev/null +++ b/lec6/base_http_serve.py @@ -0,0 +1,46 @@ +import BaseHTTPServer +import cgi, random, sys + +MESSAGES = [ + "That's as maybe, it's still a frog.", + "Albatross! Albatross! Albatross!", + "It's Wolfgang Amadeus Mozart", + "A pink form from Reading.", + "Hello people, and welcome to 'It's a Tree'" + "I simply stare at the brick and it goes to sleep.", +] + +class Handler(BaseHTTPServer.BaseHTTPRequestHandler): + + def do_GET(self): + if self.path != "/": + self.send_error(404, "File not found") + return + self.send_response(200) + self.send_header("Content-type", "text/html") + self.end_headers() + try: + # redirect stdout to client + stdout = sys.stdout + sys.stdout = self.wfile + self.makepage() + finally: + sys.stdout = stdout # restore + + + def makepage(self): + # generate a random message + tagline = random.choice(MESSAGES) + print "" + print "" + print "

Today's quote: " + print "%s" % cgi.escape(tagline) + print "" + print "" + +PORT = 8000 + +httpd = BaseHTTPServer.HTTPServer(("", PORT), Handler) +print "serving at port", PORT +httpd.serve_forever() + diff --git a/lec6/client.py b/lec6/client.py new file mode 100644 index 0000000..4f726d2 --- /dev/null +++ b/lec6/client.py @@ -0,0 +1,17 @@ +import pickle +import socket + +# Connect to the server: +client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +client.connect(('localhost', 2727)) + +# Retrieve and unpickle the list object: +print pickle.loads(client.recv(1024)) + +# Send some messages: +for x in xrange(10): + client.send('Hey. ' + str(x) + '\n') + +# Close the connection +client.close() + diff --git a/lec6/databases/sqlite_ex.py b/lec6/databases/sqlite_ex.py new file mode 100644 index 0000000..8d2316d --- /dev/null +++ b/lec6/databases/sqlite_ex.py @@ -0,0 +1,13 @@ +import sqlite3 +cxn = sqlite3.connect('test.db') +cur = cxn.cursor() +cur.execute('CREATE TABLE users(login VARCHAR(8), uid INTEGER)') +cur.execute('INSERT INTO users VALUES("john", 100)') +cur.execute('INSERT INTO users VALUES("jane", 110)') +cur.execute('SELECT * FROM users') +for eachUser in cur.fetchall(): + print eachUser +cur.execute('DROP TABLE users') +cur.close() +cxn.commit() +cxn.close() diff --git a/lec6/databases/test.db b/lec6/databases/test.db new file mode 100644 index 0000000000000000000000000000000000000000..dec752e1fcffc6d0af0ead9086fed1c63242635f GIT binary patch literal 2048 zcmWFz^vNtqRY=P(%1ta$FlJz3U}R))P*7lCVBiE|CMaeE(riEsqG14;4HHABIT>^x pN%4Y2Sr{0Yx1&ps@<&5pGz7>C0Z;O@jp`Z=fzc2c4FPBf004h92oV4P literal 0 HcmV?d00001 diff --git a/lec6/email/receive_mail.py b/lec6/email/receive_mail.py new file mode 100644 index 0000000..dd00344 --- /dev/null +++ b/lec6/email/receive_mail.py @@ -0,0 +1,19 @@ +import getpass, poplib, sys + +host = "pop.yandex.ru" +user = "fortest@yandex.ru" +passwd = getpass.getpass() + +p = poplib.POP3(host) +try: + p.user(user) + p.pass_(passwd) +except poplib.error_proto, e: + print "Login failed:", e + sys.exit(1) +status = p.stat() +print "Mailbox has %d messages for a total of %d bytes" % (status[0], status[1]) +for item in p.list()[1]: + number, octets = item.split(' ') + print "Message %s: %s bytes" % (number, octets) +p.quit() diff --git a/lec6/email/send_mail.py b/lec6/email/send_mail.py new file mode 100644 index 0000000..877dc92 --- /dev/null +++ b/lec6/email/send_mail.py @@ -0,0 +1,32 @@ +import sys, smtplib, socket +from getpass import getpass + +server = "smtp.yandex.ru" +fromaddr = "fortest@yandex.ru" +toaddrs = "info@test.ru" + +message = """To: %s +From: %s +Subject: Test Message + +Hello, + +This is a test message. +""" % (', '.join(toaddrs), fromaddr) + +username = "iit.lectures" +password = getpass() + +try: + s = smtplib.SMTP(server) + try: + s.login(username, password) + except smtplib.SMTPException, e: + print "Authentication failed:", e + sys.exit(1) + s.sendmail(fromaddr, toaddrs, message) +except (socket.gaierror, socket.error, socket.herror, smtplib.SMTPException), e: + print e + sys.exit(2) +else: + print "sent" diff --git a/lec6/serialization/objects_from_file.py b/lec6/serialization/objects_from_file.py new file mode 100644 index 0000000..ab91943 --- /dev/null +++ b/lec6/serialization/objects_from_file.py @@ -0,0 +1,13 @@ +import cPickle + +f = open("pickled.dat", "r") + +p = cPickle.Unpickler(f) + +data = p.load() +print data + +data = p.load() +print data + +f.close() diff --git a/lec6/serialization/objects_to_file.py b/lec6/serialization/objects_to_file.py new file mode 100644 index 0000000..33028aa --- /dev/null +++ b/lec6/serialization/objects_to_file.py @@ -0,0 +1,17 @@ +import cPickle + +flights = {"1":"A", "2":"B","3":"C"} +times = ["230pm", "320pm", "420pm"] + +f = open("pickled.dat", "w") + +p = cPickle.Pickler(f) + +p.dump(flights) +p.dump(times) +f.close() + +f = open("pickled.dat", "r") +data = f.read() +print data +f.close() diff --git a/lec6/serialization/persistent_object.py b/lec6/serialization/persistent_object.py new file mode 100644 index 0000000..ff53375 --- /dev/null +++ b/lec6/serialization/persistent_object.py @@ -0,0 +1,8 @@ +# coding: utf-8 +import shelve +s = shelve.open("somefile.db") +s['myobject'] = [1, 2, 3, 4, 'Привет Мир!'] +s.close() + +s = shelve.open("somefile.db") +print s['myobject'] diff --git a/lec6/serialization/pickled.dat b/lec6/serialization/pickled.dat new file mode 100644 index 0000000..a284bdb --- /dev/null +++ b/lec6/serialization/pickled.dat @@ -0,0 +1,15 @@ +(dp1 +S'1' +S'A' +sS'3' +S'C' +sS'2' +S'B' +s.(lp2 +S'230pm' +p3 +aS'320pm' +p4 +aS'420pm' +p5 +a. \ No newline at end of file diff --git a/lec6/serialization/somefile.db b/lec6/serialization/somefile.db new file mode 100644 index 0000000000000000000000000000000000000000..3990902ade1f5f5e7b78106d6c79349c0ae42a61 GIT binary patch literal 12288 zcmeI%%}T>S5Ww--97LB&y!2Y^DLoaFDx`1FoV|uZl75INrr;sIfgaj>AFEH(tFtBx z7CcFh|G?}_W;Pr6T~|cJXt<~7U&xg!ZZs}kAriFdWZiE*#prz98+^^ecI3|R=lIQs z?bH0PzMqp3KmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0;Cuq^j{f&O ze;~V1u8*OvCw>1%?*F|6836Fs}dr literal 0 HcmV?d00001 diff --git a/lec6/serialization/users.dat b/lec6/serialization/users.dat new file mode 100644 index 0000000..b2a1beb --- /dev/null +++ b/lec6/serialization/users.dat @@ -0,0 +1,5 @@ +(lp1 +S'A' +aS'B' +aS'C' +a. \ No newline at end of file diff --git a/lec6/serialization/write_and_read.py b/lec6/serialization/write_and_read.py new file mode 100644 index 0000000..5542392 --- /dev/null +++ b/lec6/serialization/write_and_read.py @@ -0,0 +1,31 @@ +import sys, cPickle + +try: + file = open( "users.dat", "w" ) +except IOError, message: + print >> sys.stderr, "File could not be opened:", message + sys.exit( 1 ) + +inputList = [] + +inputList.append( "A" ) +inputList.append( "B" ) +inputList.append( "C" ) + +cPickle.dump( inputList, file ) + +file.close() + +# Reading and printing pickled object in a file. + +try: + file = open( "users.dat", "r" ) +except IOError: + print >> sys.stderr, "File could not be opened" + sys.exit( 1 ) + +records = cPickle.load( file ) +file.close() + +for record in records: + print record[ 0 ].ljust( 15 ), diff --git a/lec6/simple_http_server.py b/lec6/simple_http_server.py new file mode 100644 index 0000000..f47aedb --- /dev/null +++ b/lec6/simple_http_server.py @@ -0,0 +1,15 @@ +import SimpleHTTPServer +import SocketServer + +# minimal web server. serves files relative to the +# current directory. + +PORT = 8000 + +Handler = SimpleHTTPServer.SimpleHTTPRequestHandler + +httpd = SocketServer.TCPServer(("", PORT), Handler) + +print "serving at port", PORT +httpd.serve_forever() + diff --git a/lec6/thread_name.py b/lec6/thread_name.py new file mode 100644 index 0000000..cbdec3d --- /dev/null +++ b/lec6/thread_name.py @@ -0,0 +1,17 @@ +import threading + +class TestThread(threading.Thread): + def run(self): + print 'Hello, my name is', self.getName() + +cazaril = TestThread() +cazaril.setName('Cazaril') +cazaril.start() + +ista = TestThread() +ista.setName('Ista') +ista.start() + +TestThread().start() +TestThread().start() + diff --git a/lec6/threaded_client.py b/lec6/threaded_client.py new file mode 100644 index 0000000..9b21c1b --- /dev/null +++ b/lec6/threaded_client.py @@ -0,0 +1,25 @@ +import pickle +import socket +import threading + +# Here's our thread: +class ConnectionThread(threading.Thread): + def run(self): + # Connect to the server: + client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + client.connect (('localhost', 2727)) + + # Retrieve and unpickle the list object: + print pickle.loads(client.recv(1024)) + + # Send some messages: + for x in xrange(10): + client.send('Hey. ' + str(x) + '\n') + + # Close the connection + client.close() + +# Let's spawn a few threads: +for x in xrange(5): + ConnectionThread().start() + diff --git a/lec6/threaded_server.py b/lec6/threaded_server.py new file mode 100644 index 0000000..0913071 --- /dev/null +++ b/lec6/threaded_server.py @@ -0,0 +1,35 @@ +import pickle +import socket +import threading + +# We'll pickle a list of numbers: +someList = [1, 2, 7, 9, 0] +pickledList = pickle.dumps(someList) + +# Our thread class: +class ClientThread(threading.Thread): + + # Override Thread's __init__ method to accept the parameters needed: + def __init__(self, channel, details): + self.channel = channel + self.details = details + threading.Thread.__init__(self) + + def run(self): + print 'Received connection:', self.details[0] + self.channel.send(pickledList) + for x in xrange(10): + print self.channel.recv(1024) + self.channel.close() + print 'Closed connection:', self.details[0] + +# Set up the server: +server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +server.bind(('', 2727)) +server.listen(5) + +# Have the server serve "forever": +while True: + channel, details = server.accept() + ClientThread(channel, details).start() + diff --git a/lec6/webbrowser_ex.py b/lec6/webbrowser_ex.py new file mode 100644 index 0000000..722ade2 --- /dev/null +++ b/lec6/webbrowser_ex.py @@ -0,0 +1,11 @@ +import webbrowser +import time + +webbrowser.open("http://www.pythonware.com") + +# wait a while, and then go to another page +time.sleep(5) +webbrowser.open( + "http://www.habrahabr.ru" + ) + From 9d0fe787ca656ed29cc6a4c298cfc363d685d76c Mon Sep 17 00:00:00 2001 From: uralbash Date: Sat, 19 Mar 2011 23:22:22 +0500 Subject: [PATCH 12/13] added lvsl lec6 --- lec6/base_http_serve.py | 0 lec6/client.py | 0 lec6/databases/sqlite_ex.py | 0 lec6/databases/test.db | Bin lec6/email/receive_mail.py | 0 lec6/email/send_mail.py | 0 lec6/lvsl_ex/__init__.py | 0 lec6/lvsl_ex/csv_dict_example.csv | 3 ++ lec6/lvsl_ex/csv_example.csv | 3 ++ lec6/lvsl_ex/csv_example.py | 61 ++++++++++++++++++++++++ lec6/lvsl_ex/json_example.py | 60 +++++++++++++++++++++++ lec6/lvsl_ex/pickle_example_read.py | 22 +++++++++ lec6/lvsl_ex/pickle_example_write.py | 30 ++++++++++++ lec6/lvsl_ex/shelve_example.py | 17 +++++++ lec6/lvsl_ex/sqlite3_example.py | 33 +++++++++++++ lec6/serialization/objects_from_file.py | 0 lec6/serialization/objects_to_file.py | 0 lec6/serialization/persistent_object.py | 0 lec6/serialization/pickled.dat | 0 lec6/serialization/somefile.db | Bin lec6/serialization/users.dat | 0 lec6/serialization/write_and_read.py | 0 lec6/simple_http_server.py | 0 lec6/thread_name.py | 0 lec6/threaded_client.py | 0 lec6/threaded_server.py | 0 lec6/webbrowser_ex.py | 0 27 files changed, 229 insertions(+) mode change 100644 => 100755 lec6/base_http_serve.py mode change 100644 => 100755 lec6/client.py mode change 100644 => 100755 lec6/databases/sqlite_ex.py mode change 100644 => 100755 lec6/databases/test.db mode change 100644 => 100755 lec6/email/receive_mail.py mode change 100644 => 100755 lec6/email/send_mail.py create mode 100755 lec6/lvsl_ex/__init__.py create mode 100755 lec6/lvsl_ex/csv_dict_example.csv create mode 100755 lec6/lvsl_ex/csv_example.csv create mode 100755 lec6/lvsl_ex/csv_example.py create mode 100755 lec6/lvsl_ex/json_example.py create mode 100755 lec6/lvsl_ex/pickle_example_read.py create mode 100755 lec6/lvsl_ex/pickle_example_write.py create mode 100755 lec6/lvsl_ex/shelve_example.py create mode 100755 lec6/lvsl_ex/sqlite3_example.py mode change 100644 => 100755 lec6/serialization/objects_from_file.py mode change 100644 => 100755 lec6/serialization/objects_to_file.py mode change 100644 => 100755 lec6/serialization/persistent_object.py mode change 100644 => 100755 lec6/serialization/pickled.dat mode change 100644 => 100755 lec6/serialization/somefile.db mode change 100644 => 100755 lec6/serialization/users.dat mode change 100644 => 100755 lec6/serialization/write_and_read.py mode change 100644 => 100755 lec6/simple_http_server.py mode change 100644 => 100755 lec6/thread_name.py mode change 100644 => 100755 lec6/threaded_client.py mode change 100644 => 100755 lec6/threaded_server.py mode change 100644 => 100755 lec6/webbrowser_ex.py diff --git a/lec6/base_http_serve.py b/lec6/base_http_serve.py old mode 100644 new mode 100755 diff --git a/lec6/client.py b/lec6/client.py old mode 100644 new mode 100755 diff --git a/lec6/databases/sqlite_ex.py b/lec6/databases/sqlite_ex.py old mode 100644 new mode 100755 diff --git a/lec6/databases/test.db b/lec6/databases/test.db old mode 100644 new mode 100755 diff --git a/lec6/email/receive_mail.py b/lec6/email/receive_mail.py old mode 100644 new mode 100755 diff --git a/lec6/email/send_mail.py b/lec6/email/send_mail.py old mode 100644 new mode 100755 diff --git a/lec6/lvsl_ex/__init__.py b/lec6/lvsl_ex/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/lec6/lvsl_ex/csv_dict_example.csv b/lec6/lvsl_ex/csv_dict_example.csv new file mode 100755 index 0000000..9c763c3 --- /dev/null +++ b/lec6/lvsl_ex/csv_dict_example.csv @@ -0,0 +1,3 @@ +Имя,Отчество,Фамилия +Иван,Иванович,Иванов +Василий,Васильевич,Васильев diff --git a/lec6/lvsl_ex/csv_example.csv b/lec6/lvsl_ex/csv_example.csv new file mode 100755 index 0000000..cb6e5ec --- /dev/null +++ b/lec6/lvsl_ex/csv_example.csv @@ -0,0 +1,3 @@ +Имя,Фамилия,Отчество +Иван,Иванов,Иванович +Василий,Васильев,Васильевич diff --git a/lec6/lvsl_ex/csv_example.py b/lec6/lvsl_ex/csv_example.py new file mode 100755 index 0000000..d1f584d --- /dev/null +++ b/lec6/lvsl_ex/csv_example.py @@ -0,0 +1,61 @@ +# coding: utf-8 + +# Пример работы с CSV файлом + +import csv +from StringIO import StringIO + +def main(): + sample_data = StringIO( + 'Имя,Фамилия,Отчество\n' + 'Иван, Иванов, Иванович\n' + 'Василий, Васильев, Васильевич\n' + ) + sample_obj = [ + ("Имя", "Фамилия", "Отчество"), + ("Иван", "Иванов", "Иванович"), + ("Василий", "Васильев", "Васильевич"), + ] + + csv_file = open('csv_example.csv','w') + + csv_reader = csv.reader(sample_data) + csv_writer = csv.writer(csv_file) + + for row in csv_reader: + print '|'.join(row) + + csv_writer.writerows(sample_obj) + + print '=' * 10, 'В виде словаря', '=' * 10 + + sample_data.seek(0) + csv_reader_dict = csv.DictReader(sample_data) + + for d in csv_reader_dict: + for k,v in d.items(): + print "%s: %s" % (k,v) + + sample_dict = [ + {'Имя': 'Иван', + 'Фамилия': 'Иванов', + 'Отчество': 'Иванович'}, + + {'Имя': 'Василий', + 'Фамилия': 'Васильев', + 'Отчество': 'Васильевич'}, + ] + + csv_dict_file = open('csv_dict_example.csv', 'w') + + csv_writer_dict = csv.DictWriter(csv_dict_file, + sorted(sample_dict[0].keys())) + + csv_writer_dict.writeheader() # python 2.7+ + csv_writer_dict.writerows(sample_dict) + + csv_dict_file.close() + csv_file.close() + +if __name__ == "__main__": + main() diff --git a/lec6/lvsl_ex/json_example.py b/lec6/lvsl_ex/json_example.py new file mode 100755 index 0000000..f959a9d --- /dev/null +++ b/lec6/lvsl_ex/json_example.py @@ -0,0 +1,60 @@ +# coding: utf-8 + +# Пример работы с JSON + +import json + +def _gen_data(): + import time + import hashlib + import random + + t = time.time() + + return { + 'timestamp': int(t), + 'payload': hashlib.md5(str(t + random.random())).hexdigest(), + } + +def main(): + data = [] + for i in range(100): + data.append(_gen_data()) + + print json.dumps(data, indent=1) + + x = ''' +{"widget": { + "debug": "on", + "window": { + "title": "Sample Konfabulator Widget", + "name": "main_window", + "width": 500, + "height": 500 + }, + "image": { + "src": "Images/Sun.png", + "name": "sun1", + "hOffset": 250, + "vOffset": 250, + "alignment": "center" + }, + "text": { + "data": "Click Here", + "size": 36, + "style": "bold", + "name": "text1", + "hOffset": 250, + "vOffset": 100, + "alignment": "center", + "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;" + } +}} + ''' + + d = json.loads(x) + + print d['widget']['image']['src'] + +if __name__ == "__main__": + main() diff --git a/lec6/lvsl_ex/pickle_example_read.py b/lec6/lvsl_ex/pickle_example_read.py new file mode 100755 index 0000000..0b3df11 --- /dev/null +++ b/lec6/lvsl_ex/pickle_example_read.py @@ -0,0 +1,22 @@ +# coding: utf-8 + +# Чтение данных из pickle + +import cPickle as pickle + +from pickle_example_write import State + +def main(): + obj = None + pickled_obj = '' + with open('pickle_example.pickle') as f: + pickled_obj = f.read() + + obj = pickle.loads(pickled_obj) + + print type(obj) + print obj.get_initials() + + +if __name__ == "__main__": + main() diff --git a/lec6/lvsl_ex/pickle_example_write.py b/lec6/lvsl_ex/pickle_example_write.py new file mode 100755 index 0000000..25faa0a --- /dev/null +++ b/lec6/lvsl_ex/pickle_example_write.py @@ -0,0 +1,30 @@ +# coding: utf-8 + +# Запись обекта в pickle + +import cPickle as pickle + +class State(object): + def __init__(self, first_name, third_name, second_name=''): + self.first_name = first_name.decode('utf-8') + self.second_name = second_name.decode('utf-8') + self.third_name = third_name.decode('utf-8') + + def get_initials(self): + tn = self.third_name.lower().capitalize() + fn = self.first_name[0].capitalize() + if self.second_name: + sn = self.second_name[0].capitalize() + else: + sn = '' + return "%s%s%s" % (tn, fn, sn) + +def main(): + s = State("Иван", "Иванов", "Иванович") + print s.get_initials() + pickled_data = pickle.dumps(s) + with open('pickle_example.pickle', 'w') as f: + f.write(pickled_data) + +if __name__ == "__main__": + main() diff --git a/lec6/lvsl_ex/shelve_example.py b/lec6/lvsl_ex/shelve_example.py new file mode 100755 index 0000000..05e7cda --- /dev/null +++ b/lec6/lvsl_ex/shelve_example.py @@ -0,0 +1,17 @@ +# coding: utf-8 + +# Использование модуля shelve для хранения данных + +import shelve +import random + +def main(): + db = shelve.open('example_db.shlv') + print db.keys() + print db.values() + + for i in range(5): + db[str(random.random())] = 'test shelve' + +if __name__ == "__main__": + main() diff --git a/lec6/lvsl_ex/sqlite3_example.py b/lec6/lvsl_ex/sqlite3_example.py new file mode 100755 index 0000000..f553e26 --- /dev/null +++ b/lec6/lvsl_ex/sqlite3_example.py @@ -0,0 +1,33 @@ +# coding: utf-8 + +import sqlite3 + +def main(): + con = sqlite3.connect(':memory:') + + c = con.cursor() + + c.execute('''create table stocks ( + date text, + trans text, + symbol text, + qty real, + price real)''') + + for t in [('2006-03-28', 'BUY', 'IBM', 1000, 45.00), + ('2006-04-05', 'BUY', 'MSOFT', 1000, 72.00), + ('2006-04-06', 'SELL', 'IBM', 500, 53.00), + ]: + c.execute('insert into stocks values (?,?,?,?,?)', t) + + c.execute('select * from stocks where symbol=? order by price', ('IBM',)) + for row in c: + print row + + c.execute('select sum(price) as summ from stocks') + for row in c: + print row + + +if __name__ == "__main__": + main() diff --git a/lec6/serialization/objects_from_file.py b/lec6/serialization/objects_from_file.py old mode 100644 new mode 100755 diff --git a/lec6/serialization/objects_to_file.py b/lec6/serialization/objects_to_file.py old mode 100644 new mode 100755 diff --git a/lec6/serialization/persistent_object.py b/lec6/serialization/persistent_object.py old mode 100644 new mode 100755 diff --git a/lec6/serialization/pickled.dat b/lec6/serialization/pickled.dat old mode 100644 new mode 100755 diff --git a/lec6/serialization/somefile.db b/lec6/serialization/somefile.db old mode 100644 new mode 100755 diff --git a/lec6/serialization/users.dat b/lec6/serialization/users.dat old mode 100644 new mode 100755 diff --git a/lec6/serialization/write_and_read.py b/lec6/serialization/write_and_read.py old mode 100644 new mode 100755 diff --git a/lec6/simple_http_server.py b/lec6/simple_http_server.py old mode 100644 new mode 100755 diff --git a/lec6/thread_name.py b/lec6/thread_name.py old mode 100644 new mode 100755 diff --git a/lec6/threaded_client.py b/lec6/threaded_client.py old mode 100644 new mode 100755 diff --git a/lec6/threaded_server.py b/lec6/threaded_server.py old mode 100644 new mode 100755 diff --git a/lec6/webbrowser_ex.py b/lec6/webbrowser_ex.py old mode 100644 new mode 100755 From df1ab45094f00c84cb72ca9b7cf3db9cf5c00cf2 Mon Sep 17 00:00:00 2001 From: uralbash Date: Thu, 14 Apr 2011 22:45:09 +0600 Subject: [PATCH 13/13] add lec7, 8, 9 --- lec6/__init__.py | 0 lec6/csv_dict_example.csv | 3 ++ lec6/csv_example.csv | 3 ++ lec6/csv_example.py | 62 +++++++++++++++++++++ lec6/json_example.py | 60 +++++++++++++++++++++ lec6/pickle_example_read.py | 22 ++++++++ lec6/pickle_example_write.py | 32 +++++++++++ lec6/shelve_example.py | 17 ++++++ lec6/sqlite3_example.py | 33 ++++++++++++ lec7/config_example.py | 13 +++++ lec7/jinja_example1.py | 10 ++++ lec7/jinja_example2.py | 19 +++++++ lec7/jinja_tmpl.html | 9 ++++ lec7/logging_example.py | 20 +++++++ lec7/options_example.py | 29 ++++++++++ lec7/s.py | 66 +++++++++++++++++++++++ lec7/test.conf | 2 + lec8/README | 8 +++ lec8/__init__.py | 0 lec8/cgi_test/app.yaml | 8 +++ lec8/cgi_test/main.py | 27 ++++++++++ lec8/webapp_test/app.yaml | 8 +++ lec8/webapp_test/main.py | 27 ++++++++++ lec9/README | 8 +++ lec9/__init__.py | 0 lec9/gaccount_example/app.yaml | 8 +++ lec9/gaccount_example/gaccount_example.py | 44 +++++++++++++++ 27 files changed, 538 insertions(+) create mode 100644 lec6/__init__.py create mode 100644 lec6/csv_dict_example.csv create mode 100644 lec6/csv_example.csv create mode 100644 lec6/csv_example.py create mode 100644 lec6/json_example.py create mode 100644 lec6/pickle_example_read.py create mode 100644 lec6/pickle_example_write.py create mode 100644 lec6/shelve_example.py create mode 100644 lec6/sqlite3_example.py create mode 100644 lec7/config_example.py create mode 100644 lec7/jinja_example1.py create mode 100644 lec7/jinja_example2.py create mode 100644 lec7/jinja_tmpl.html create mode 100644 lec7/logging_example.py create mode 100644 lec7/options_example.py create mode 100644 lec7/s.py create mode 100644 lec7/test.conf create mode 100644 lec8/README create mode 100644 lec8/__init__.py create mode 100644 lec8/cgi_test/app.yaml create mode 100644 lec8/cgi_test/main.py create mode 100644 lec8/webapp_test/app.yaml create mode 100644 lec8/webapp_test/main.py create mode 100644 lec9/README create mode 100644 lec9/__init__.py create mode 100644 lec9/gaccount_example/app.yaml create mode 100644 lec9/gaccount_example/gaccount_example.py diff --git a/lec6/__init__.py b/lec6/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lec6/csv_dict_example.csv b/lec6/csv_dict_example.csv new file mode 100644 index 0000000..9c763c3 --- /dev/null +++ b/lec6/csv_dict_example.csv @@ -0,0 +1,3 @@ +Имя,Отчество,Фамилия +Иван,Иванович,Иванов +Василий,Васильевич,Васильев diff --git a/lec6/csv_example.csv b/lec6/csv_example.csv new file mode 100644 index 0000000..cb6e5ec --- /dev/null +++ b/lec6/csv_example.csv @@ -0,0 +1,3 @@ +Имя,Фамилия,Отчество +Иван,Иванов,Иванович +Василий,Васильев,Васильевич diff --git a/lec6/csv_example.py b/lec6/csv_example.py new file mode 100644 index 0000000..9192c4f --- /dev/null +++ b/lec6/csv_example.py @@ -0,0 +1,62 @@ +# coding: utf-8 + +# Пример работы с CSV файлом + +import csv +from StringIO import StringIO + +def main(): + sample_data = StringIO( + 'Имя,Фамилия,Отчество\n' + 'Иван, Иванов, Иванович\n' + 'Василий, Васильев, Васильевич\n' + ) + sample_obj = [ + ("Имя", "Фамилия", "Отчество"), + ("Иван", "Иванов", "Иванович"), + ("Василий", "Васильев", "Васильевич"), + ] + + csv_file = open('csv_example.csv','w') + + csv_reader = csv.reader(sample_data) + csv_writer = csv.writer(csv_file) + + for row in csv_reader: + print '|'.join(row) + + csv_writer.writerows(sample_obj) + + print '=' * 10, 'В виде словаря', '=' * 10 + + sample_data.seek(0) + csv_reader_dict = csv.DictReader(sample_data) + + for d in csv_reader_dict: + print d + for k,v in d.items(): + print "%s: %s" % (k,v) + + sample_dict = [ + {'Имя': 'Иван', + 'Фамилия': 'Иванов', + 'Отчество': 'Иванович'}, + + {'Имя': 'Василий', + 'Фамилия': 'Васильев', + 'Отчество': 'Васильевич'}, + ] + + csv_dict_file = open('csv_dict_example.csv', 'w') + + csv_writer_dict = csv.DictWriter(csv_dict_file, + sorted(sample_dict[0].keys())) + + csv_writer_dict.writeheader() # python 2.7+ + csv_writer_dict.writerows(sample_dict) + + csv_dict_file.close() + csv_file.close() + +if __name__ == "__main__": + main() diff --git a/lec6/json_example.py b/lec6/json_example.py new file mode 100644 index 0000000..f959a9d --- /dev/null +++ b/lec6/json_example.py @@ -0,0 +1,60 @@ +# coding: utf-8 + +# Пример работы с JSON + +import json + +def _gen_data(): + import time + import hashlib + import random + + t = time.time() + + return { + 'timestamp': int(t), + 'payload': hashlib.md5(str(t + random.random())).hexdigest(), + } + +def main(): + data = [] + for i in range(100): + data.append(_gen_data()) + + print json.dumps(data, indent=1) + + x = ''' +{"widget": { + "debug": "on", + "window": { + "title": "Sample Konfabulator Widget", + "name": "main_window", + "width": 500, + "height": 500 + }, + "image": { + "src": "Images/Sun.png", + "name": "sun1", + "hOffset": 250, + "vOffset": 250, + "alignment": "center" + }, + "text": { + "data": "Click Here", + "size": 36, + "style": "bold", + "name": "text1", + "hOffset": 250, + "vOffset": 100, + "alignment": "center", + "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;" + } +}} + ''' + + d = json.loads(x) + + print d['widget']['image']['src'] + +if __name__ == "__main__": + main() diff --git a/lec6/pickle_example_read.py b/lec6/pickle_example_read.py new file mode 100644 index 0000000..0b3df11 --- /dev/null +++ b/lec6/pickle_example_read.py @@ -0,0 +1,22 @@ +# coding: utf-8 + +# Чтение данных из pickle + +import cPickle as pickle + +from pickle_example_write import State + +def main(): + obj = None + pickled_obj = '' + with open('pickle_example.pickle') as f: + pickled_obj = f.read() + + obj = pickle.loads(pickled_obj) + + print type(obj) + print obj.get_initials() + + +if __name__ == "__main__": + main() diff --git a/lec6/pickle_example_write.py b/lec6/pickle_example_write.py new file mode 100644 index 0000000..564ee68 --- /dev/null +++ b/lec6/pickle_example_write.py @@ -0,0 +1,32 @@ +# coding: utf-8 + +# Запись обекта в pickle + +import cPickle as pickle + +class State(object): + def __init__(self, first_name, + third_name, + second_name=''): + self.first_name = first_name.decode('utf-8') + self.second_name = second_name.decode('utf-8') + self.third_name = third_name.decode('utf-8') + + def get_initials(self): + tn = self.third_name.lower().capitalize() + fn = self.first_name[0].capitalize() + if self.second_name: + sn = self.second_name[0].capitalize() + else: + sn = '' + return "%s%s%s" % (tn, fn, sn) + +def main(): + s = State("Иван", "Иванов", "Иванович") + print s.get_initials() + pickled_data = pickle.dumps(s) + with open('pickle_example.pickle', 'w') as f: + f.write(pickled_data) + +if __name__ == "__main__": + main() diff --git a/lec6/shelve_example.py b/lec6/shelve_example.py new file mode 100644 index 0000000..05e7cda --- /dev/null +++ b/lec6/shelve_example.py @@ -0,0 +1,17 @@ +# coding: utf-8 + +# Использование модуля shelve для хранения данных + +import shelve +import random + +def main(): + db = shelve.open('example_db.shlv') + print db.keys() + print db.values() + + for i in range(5): + db[str(random.random())] = 'test shelve' + +if __name__ == "__main__": + main() diff --git a/lec6/sqlite3_example.py b/lec6/sqlite3_example.py new file mode 100644 index 0000000..e3bdb32 --- /dev/null +++ b/lec6/sqlite3_example.py @@ -0,0 +1,33 @@ +# coding: utf-8 + +import sqlite3 + +def main(): + con = sqlite3.connect('db.sqlite3') + + c = con.cursor() + + c.execute('''create table stocks ( + date text, + trans text, + symbol text, + qty real, + price real)''') + + for t in [('2006-03-28', 'BUY', 'IBM', 1000, 45.00), + ('2006-04-05', 'BUY', 'MSOFT', 1000, 72.00), + ('2006-04-06', 'SELL', 'IBM', 500, 53.00), + ]: + c.execute('insert into stocks values (?,?,?,?,?)', t) + + c.execute('select * from stocks where symbol=? order by price', ('IBM',)) + for row in c: + print row + + c.execute('select sum(price) as summ from stocks') + for row in c: + print row + + +if __name__ == "__main__": + main() diff --git a/lec7/config_example.py b/lec7/config_example.py new file mode 100644 index 0000000..0903968 --- /dev/null +++ b/lec7/config_example.py @@ -0,0 +1,13 @@ +# coding: utf-8 + +import ConfigParser + +def main(): + conf = ConfigParser.ConfigParser() + conf.read('test.conf') + + if conf.has_section('main'): + print conf.getint('main', 'log_size') + +if __name__ == "__main__": + main() diff --git a/lec7/jinja_example1.py b/lec7/jinja_example1.py new file mode 100644 index 0000000..0518500 --- /dev/null +++ b/lec7/jinja_example1.py @@ -0,0 +1,10 @@ +# coding: utf-8 + +import jinja2 + +def main(): + tmpl = jinja2.Template('Hello {{name}}!') + print tmpl.render(name='Rango') + +if __name__ == "__main__": + main() diff --git a/lec7/jinja_example2.py b/lec7/jinja_example2.py new file mode 100644 index 0000000..7269aa9 --- /dev/null +++ b/lec7/jinja_example2.py @@ -0,0 +1,19 @@ +# coding: utf-8 + +import jinja2 +import os + + +def main(): + curr_dir = os.path.dirname(os.path.abspath(__file__)) + fs_loader = jinja2.FileSystemLoader([curr_dir], encoding='utf-8') + env = jinja2.Environment(loader=fs_loader) + + tmpl = env.get_template('jinja_tmpl.html') + ctx = {'name': 'test'} + + return tmpl.render(ctx) + + +if __name__ == "__main__": + print main() diff --git a/lec7/jinja_tmpl.html b/lec7/jinja_tmpl.html new file mode 100644 index 0000000..8654c24 --- /dev/null +++ b/lec7/jinja_tmpl.html @@ -0,0 +1,9 @@ + + + {{name}} + + + +

{{name}} !!!

+ + diff --git a/lec7/logging_example.py b/lec7/logging_example.py new file mode 100644 index 0000000..57a046c --- /dev/null +++ b/lec7/logging_example.py @@ -0,0 +1,20 @@ +# codinf: utf-8 + +import logging +import logging.handlers + +def main(): + h = logging.handlers.RotatingFileHandler('test.log', maxBytes=1024*1024*200, backupCount=7) + h.setFormatter(logging.Formatter('%(asctime)s %(levelname)s (%(module)s) %(message)s')) + + log = logging.getLogger('test') + log.addHandler(h) + log.setLevel(logging.DEBUG) + + log.debug('lololo') + log.info('test') + log.error('asds') + + +if __name__ == "__main__": + main() diff --git a/lec7/options_example.py b/lec7/options_example.py new file mode 100644 index 0000000..597d9ea --- /dev/null +++ b/lec7/options_example.py @@ -0,0 +1,29 @@ +# coding: utf-8 + +import optparse + +def main(): + parser = optparse.OptionParser() + parser.add_option( + "--config", + default = "server.conf", + dest = "conf", + help = "config file path" + ) + parser.add_option( + "--command", + dest = "command", + help = "Command name" + ) + parser.add_option( + "--convert", + action="store_true", + dest = "convert", + help = "Auto convert database" + ) + + options, args = parser.parse_args() + print options.conf, options.command, options.convert + +if __name__ == "__main__": + main() diff --git a/lec7/s.py b/lec7/s.py new file mode 100644 index 0000000..4f6d86d --- /dev/null +++ b/lec7/s.py @@ -0,0 +1,66 @@ +# coding: utf-8 +import cgi +from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler +from SocketServer import ThreadingMixIn +from cStringIO import StringIO + +from jinja_example2 import main as example_html + + +class S(ThreadingMixIn, HTTPServer): pass + + +class H(BaseHTTPRequestHandler): + def do_GET(self): + self.send_response(200) + self.send_header('Content-type', 'text/html') + self.send_header('Content-Encoding', 'utf-8') + self.end_headers() + + self.wfile.write(example_html()) + self.wfile.write(self.path) + self.wfile.flush() + self.connection.close() + + + def do_POST(self): + content_type, pdict = cgi.parse_header(self.headers['content-type']) + + max_chunk_size = 2048 + size_remaining = int(self.headers["content-length"]) + + raw_data = '' + while size_remaining: + chunk_size = min(size_remaining, max_chunk_size) + data = self.rfile.read(chunk_size) + size_remaining -= len(data) + raw_data = raw_data + data + + request_dict = {} + is_binary = False + if 'application/x-www-form-urlencoded' in content_type: + request_dict = cgi.parse_qs(raw_data) + + elif 'multipart/form-data' in content_type: + request_dict = cgi.parse_multipart(StringIO(raw_data), pdict) + is_binary = True + + self.send_response(200) + self.send_header('Content-type', 'text/html') + self.send_header('Content-Encoding', 'utf-8') + self.end_headers() + + self.wfile.write(raw_data) + self.wfile.write(request_dict) + self.wfile.write(is_binary) + self.wfile.flush() + self.connection.close() + + +def main(): + s = S(('', 8080), H) + s.serve_forever() + + +if __name__ == "__main__": + main() diff --git a/lec7/test.conf b/lec7/test.conf new file mode 100644 index 0000000..7ecde1d --- /dev/null +++ b/lec7/test.conf @@ -0,0 +1,2 @@ +[main] +log_size = 1024 diff --git a/lec8/README b/lec8/README new file mode 100644 index 0000000..4b318a7 --- /dev/null +++ b/lec8/README @@ -0,0 +1,8 @@ +Чтобы работать с примерами из этой лекции нужно +скачать и распоковать(установить) архив[1] с Google App Engine SDK +в ту же директрию, где находиться это файл. + +Также необходимо завести себе аккаунт[2] на Goggle. + +[1] http://code.google.com/intl/ru/appengine/downloads.html +[2] https://www.google.com/accounts/newaccount diff --git a/lec8/__init__.py b/lec8/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lec8/cgi_test/app.yaml b/lec8/cgi_test/app.yaml new file mode 100644 index 0000000..7feb6a6 --- /dev/null +++ b/lec8/cgi_test/app.yaml @@ -0,0 +1,8 @@ +application: "cgi-test" +version: 1 +runtime: python +api_version: 1 + +handlers: +- url: /.* + script: main.py diff --git a/lec8/cgi_test/main.py b/lec8/cgi_test/main.py new file mode 100644 index 0000000..6123f50 --- /dev/null +++ b/lec8/cgi_test/main.py @@ -0,0 +1,27 @@ +# coding: utf-8 + +# +# Простейший пример GAE приложения +# + +import os +import sys + +# CGI сохраняет запрос в переменных окружения +params_dict = os.environ + +# CGI ответ, это данные выданные программой в stdout +print 'Content-Type: text/html' + + +# Если это POST запрос то его содержимое в stdin +print '
'
+print sys.stdin.read()
+print '
' + +print '
    ' +for k,v in params_dict.items(): + print '
  • %s:%s
  • ' % (k,v) +print '
' + +# вот и всё! diff --git a/lec8/webapp_test/app.yaml b/lec8/webapp_test/app.yaml new file mode 100644 index 0000000..60b2de9 --- /dev/null +++ b/lec8/webapp_test/app.yaml @@ -0,0 +1,8 @@ +application: "webapp-test" +version: 1 +runtime: python +api_version: 1 + +handlers: +- url: /.* + script: main.py diff --git a/lec8/webapp_test/main.py b/lec8/webapp_test/main.py new file mode 100644 index 0000000..712a58f --- /dev/null +++ b/lec8/webapp_test/main.py @@ -0,0 +1,27 @@ +# coding: utf-8 + +# +# Пример использования встроенноой в GAE +# билблиотеки для разработки: webapp +# + +from google.appengine.ext import webapp +from google.appengine.ext.webapp.util import run_wsgi_app + +# Класс обработчий запросов +class MainPage(webapp.RequestHandler): + def get(self): + self.response.headers['Content-Type'] = 'text/html' + self.response.out.write('

Hello webapp!

') + +# Какой обработчик на какой урл вызывается +app = webapp.WSGIApplication( + [('/.*', MainPage)], + debug=True, +) + +def main(): + run_wsgi_app(app) + +if __name__ == "__main__": + main() diff --git a/lec9/README b/lec9/README new file mode 100644 index 0000000..4b318a7 --- /dev/null +++ b/lec9/README @@ -0,0 +1,8 @@ +Чтобы работать с примерами из этой лекции нужно +скачать и распоковать(установить) архив[1] с Google App Engine SDK +в ту же директрию, где находиться это файл. + +Также необходимо завести себе аккаунт[2] на Goggle. + +[1] http://code.google.com/intl/ru/appengine/downloads.html +[2] https://www.google.com/accounts/newaccount diff --git a/lec9/__init__.py b/lec9/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lec9/gaccount_example/app.yaml b/lec9/gaccount_example/app.yaml new file mode 100644 index 0000000..46501c1 --- /dev/null +++ b/lec9/gaccount_example/app.yaml @@ -0,0 +1,8 @@ +application: "google-accounts-example" +version: 1 +runtime: python +api_version: 1 + +handlers: +- url: /.* + script: gaccount_example.py diff --git a/lec9/gaccount_example/gaccount_example.py b/lec9/gaccount_example/gaccount_example.py new file mode 100644 index 0000000..032358d --- /dev/null +++ b/lec9/gaccount_example/gaccount_example.py @@ -0,0 +1,44 @@ +# coding: utf-8 + +# Пример использование сервиса Google Accounts + +from google.appengine.api import users +from google.appengine.ext import webapp +from google.appengine.ext.webapp.util import run_wsgi_app + + +class MainPage(webapp.RequestHandler): + def get(self): + # получаем текущего пользователя + user = users.get_current_user() + + html = ['Google Accounts Test'] + if not user: + # получаем ссылку для входа + login_url = users.create_login_url(self.request.path) + html.append('

Я вас не знаю!

' + 'Залогиньтесь плиз!' % login_url) + else: + # получаем ссылку для выхода + logout_url = users.create_logout_url(self.request.path) + html.append('

Здарова %s!

' + 'Разлогинется можно тут!' % ( + user.email(), logout_url)) + + html.append('') + + # отдаем страничку + self.response.headers['Content-Type'] = 'text/html; charset=UTF-8' + + self.response.out.write(''.join(html)) + + +app = webapp.WSGIApplication([('/.*', MainPage)], debug=True) + + +def main(): + run_wsgi_app(app) + + +if __name__ == "__main__": + main()