\documentclass[a4paper,12pt]{extarticle}

% ęóąśłżźćń ĘÓĄŚŁŻŹĆŃ wpisane, żeby gvim rozpoznał kodowanie w~latin2

\usepackage[T1]{fontenc}
%\usepackage{times}
\usepackage[latin2]{inputenc}
\usepackage[polish]{babel}

\usepackage{lineno}
\usepackage{graphicx}
\usepackage{polski}
\usepackage{hyperref}
\usepackage{setspace}

\usepackage[left=35mm,right=25mm,top=25mm,bottom=25mm,nohead]{geometry}

%% odstęp między wierszami
\onehalfspacing

%% dokument główny
\begin{document}

\begin{titlepage}
    \begin{center}
	\singlespacing
	\begin{Large}
	    Uniwersytet im. Adama Mickiewicza\\
	    w~Poznaniu 
	    
	    \vspace*{30pt}

	    Wydział Fizyki
	\end{Large}

	\vspace*{130pt}

	\begin{huge}
            \textbf{Praca magisterska}
	\end{huge}

    	\vspace*{40pt}
	
	\begin{LARGE}
	    ,,Tworzenie aplikacji internetowych przy użyciu środowiska Zope''

	    \vspace*{90pt}

            \textbf{Wojciech Lichota} 
	\end{LARGE}

	\vspace*{90pt}

	\begin{Large}
            Kierownik pracy:\\
	    \textbf{prof. dr hab. Ryszard Tanaś}\\
	    Zakład Optyki Nieliniowej, Wydział Fizyki UAM

	    \vspace*{60pt}

	    Poznań 2007
        \end{Large}
	\onehalfspacing
    \end{center}
\end{titlepage}

\newpage

\vspace*{100pt}

\begin{center}
    \begin{Large}
	OŚWIADCZENIE
    \end{Large}
\end{center}

\vspace*{100pt}

Ja niżej podpisany {\em Wojciech Lichota} student {\em Wydziału Fizyki} Uniwersytetu im. Adama Mickiewicza w~Poznaniu oświadczam, że przedkładaną pracę magisterską pt. {\em Tworzenie aplikacji internetowych przy użyciu środowiska Zope} napisałem samodzielnie. Oznacza to, że przy pisaniu pracy, poza niezbędnymi konsultacjami, nie korzystałem z~pomocy innych osób, a~w~szczególności nie zlecałem opracowania rozprawy lub jej istotnych części innym osobom, ani nie odpisywałem tej rozprawy lub jej istotnych części od innych osób.

Równocześnie wyrażam zgodę na to, że gdyby powyższe oświadczenie okazało się nieprawdziwe, decyzja o~wydaniu mi dyplomu zostanie cofnięta.

\newpage
\addcontentsline{toc}{section}{Spis treści}
\tableofcontents

\newpage
\section{Wstęp}

    \subsection{Streszczenie}
    Tworzenie rozbudowanych stron internetowych w~początkowym stadium rozwoju internetu było zajęciem pracochłonnym. Jeszcze większy nakład pracy był potrzebny na aktualizację danych znajdujących się na stronie. Rozbudowa serwisu była na tyle uciążliwa, że twórcy często wybierali tworzenie wszystkiego od nowa. Aby zlikwidować te niedogodności powstały narzędzia, które na celu mają uproszczenie i~przyspieszenie procesu budowania i~rozwijania serwisów internetowych.

    Jednym z~pomysłów na ułatwienie pracy budowniczym stron internetowych są serwery aplikacji. Serwer aplikacji posiada zestaw narzędzi i~mechanizmów, dzięki którym osoba tworząca serwis może skupić się jedynie na najważniejszych czynnościach, jakie ma wykonywać aplikacja internetowa. Całą resztę wykona za niego wyspecjalizowane do tego oprogramowanie.

    Jedną z~implementacji idei serwerów aplikacji jest Zope. Dzięki temu, że pisany jest przez wielu programistów, zarówno entuzjastów, jak i~profesjonalistów specjalnie do tego zatrudnionych, Zope jest serwerem oferującym bardzo wiele udogodnień. Zope zdobywa dużą popularność także ze względu na to, że dostępny jest za darmo na zasadach wolnego oprogramowania.

    Tworzeniem stron internetowych zajmuję się praktycznie od momentu, kiedy stałem się użytkownikiem internetu. W miarę nabywania doświadczenia w ich tworzeniu zacząłem odczuwać wszystkie te utrudnienia opisywane powyżej. Dlatego też zainteresowałem się narzędziami ułatwiającymi tworzenie rozbudowanych stron internetowych. Z podobnych przyczyn zdecydowałem się nauczyć języka programowania Python. Wcześniej używane przez mnie języki (takie jak C/C++ czy Java) nie dają programiście tylu udogodnień co Python. Serwer aplikacji Zope zwrócił moją uwagę tym, że zapewnia bardzo wygodne w użytkowaniu środowisko do budowy stron internetowych a jednocześnie wykorzystuje możliwości poznanego przeze mnie wcześniej języka Python.

    Celem niniejszej pracy magisterskiej jest zapoznanie czytelnika z wiedzą, jaką należy posiąść, aby móc budować aplikacje internetowe w oparciu o serwer aplikacji Zope. W tym celu opisane zostaną zagadnienia teoretyczne pomagające zrozumieć zasadę działania serwera aplikacji. Przedstawione zostaną specyfikacje języków programowania wykorzystywanych do tworzenia elementów, które składają się na aplikację internetową w środowisku Zope. Opisane zagadnienia teoretyczne rozszerzane będą o stworzone przeze mnie przykłady ich wykorzystania. Jako przykład kompletnej aplikacji internetowej zostanie opisany także, stworzony przeze mnie w środowisku Zope, serwis poświęcony kinematografii.

    \subsection{Abstract}
    Every year web pages are becomming increasingly complicated. Many tools, programming languages and techniques have appeared to facilitate creating, administrating as well as extending bigger and bigger web pages.
    
    Application servers can facilitate webpage extension. Owing to a built-in set of tools and mechanisms in an application server, the person creating web pages can focus solely on the most important activities of the web application. All other activities can be carried out by  specialised software.
    
    One of the examples of the application server implementation is Zope. Zope offers many conveniences thanks to the fact that it is written by numerous programmers, both professionals as well as amateours. One more reason why Zope is becoming more and more popular is the fact that it is free. 
    
    The aim of this thesis is to provide the reader with the appropriate knowledge which is necessary to build web applications based on Zope application server. There will be described some theoretical issues to understand application servers usage. There will be presented a specifications of programming languages used to create the elements of which web applications in Zope environment consist. The theoretical issues will be illustrated by the examples created by the author of the thesis. There will be presented also a website devoted to cinematography which is a complete web application created by the author of this thesis in Zope environment.
    
    \subsection{Budowa pracy}
    Tworzenie serwisów internetowych w~środowisku Zope nie jest możliwe bez przyswojenia ogólnej wiedzy teoretycznej z~tego zakresu. Konieczne jest zrozumienie czym jest aplikacja internetowa, {\em framework} czy serwer aplikacji. Należy także nauczyć się prawidłowo dzielić elementy serwisu na trzy podstawowe warstwy: prezentacji, logiki i~danych. Bardzo przydatne dla pełnego zrozumienia zasad wpływających na pracę serwera aplikacji jest poznanie czynności jakie wykonuje serwer od otrzymania żądania HTTP z~przeglądarki WWW użytkownika aplikacji, aż do wysłania do niego gotowego dokumentu z~informacjami które go interesują. Powyższe zagadnienia przedstawiłem w~pierwszym rozdziale o~tytule ,,Charakterystyka Zope jako serwera aplikacji''.

    Drugi rozdział niniejszej pracy magisterskiej o~tytule ,,Elementy środowiska Zope'' opisuje elementy z~których budowana jest aplikacja internetowa w~Zope. Na początku przedstawiłem opis interfejsu dzięki któremu możliwe jest zarządzanie (dodawanie, edycja, przenoszenie, usuwanie itp.) obiektami znajdującymi się w~Zope. Przy okazji opisałem niektóre mechanizmy jakie udostępnia Zope (np. polityka bezpieczeństwa, zarządzanie sesjami, obsługa błędów i~sytuacji wyjątkowych). W~dalszej części opisałem szczegółowo obiekty z~każdej z~warstw. 

    Szablon ZPT ({\em Zope Page Template}) należy do warstwy prezentacji. Szablon taki budowany jest na bazie kodu w~języku HTML lub XML, powiększonego o~specjalne instrukcje. Zestaw tych rozszerzeń opisuje specyfikacja TAL ({\em Template Attribute Language}). Możliwości TAL zostały powiększone o dodatkowe funkcje przy użyciu METAL ({\em Macro Expansion Template Attribute Language}). Dzięki tym makrom możliwe jest dzielenie kodu między wiele szablonów. Wyrażenia jakie można przypisać do atrybutów TAL opisuje TALES ({\em Template Attribute Language Expression Syntax}).

    Obiektami warstwy logiki opisanymi w~pracy są skrypty w~języku Python (ang. {\em Python-based Scripts}) oraz metody zewnętrzne (ang. {\em External Methods}). Podczas ich opisywania nie wchodziłem w~szczegóły samego języka Python, przy użyciu którego pisze się te skrypty, lecz na strukturach i~funkcjach charakterystycznych dla Zope, czyli na Zope API.

    Na zakończenie drugiego rozdziału opisałem w~jaki sposób zorganizowana jest warstwa danych w~Zope. Został tam zawarty opis procedury łączenia się Zope z~zewnętrznymi relacyjnymi bazami danych. Przedstawiłem także specyfikację metod ZSQL (ang. {\em Z~SQL Methods}) czyli mechanizmu budowania przez Zope zapytań w~standardzie SQL służących do komunikacji z~bazami danych.

    W~trzecim rozdziale o~tytule ,,Biblioteki wykorzystywane przez FilmoBazę'' opisuję coraz częściej wykorzystywaną technikę budowy przyjaznych użytkownikowi interfejsów graficznych, a mianowicie AJAX. W dalszej części opisuję trzy biblioteki języka Python, które wykorzystałem podczas pisania projektu. {\em PyGoogle} jest nakładką na {\em Google SOAP Search API} i ułatwia dostęp do wyszukiwarki Google. {\em IMDbPy} w podobny sposób ułatwia komunikację z serwisem IMDb. Natomiast w opise modułu {\em re} przedstawiam w jaki sposób możliwe jest wykorzystanie wyrażeń regularnych w języku Python. Zagadnienia te mimo, że nie są bezpośrednio związane z serwerem aplikacji Zope, to w dużej mierze pomagają w zrozumieniu działania stworzonej przeze mnie aplikacji internetowej opisanej w następnym rozdziale.

    Najlepszym sposobem na utrwalenie i~rozwinięcie wiedzy teoretycznej o~Zope jest wykorzystanie jej w~praktyce. W~tym celu stworzyłem aplikację internetową, dzięki której możliwe jest przeglądanie informacji o~filmach. Informacje te nie zostały umieszczone ,,ręcznie'' przez internautów, tak jak to ma miejsce w~większości serwisów, lecz zostały one znalezione w~internecie. Zasadę działania zbudowanego przeze mnie serwisu o~filmach (który nazwałem FilmoBaza) zarówno od strony użytkownika, jak i~od strony programisty opisałem w~rozdziale czwartym o~tytule ,,Aplikacja internetowa wykonanego w~Zope - FilmoBaza''.

\section{Charakterystyka Zope jako serwera aplikacji}
   
Zope ({\em Z~Object Publishing Environment}) jest serwerem aplikacji napisanym w~języku Python. Za twórcę Zope uważany jest Jim Fulton, który to w~1996 roku napisał szkielet Zope, a~następnie przez wiele lat go rozbudowywał. W~1998 roku Zope został wydany na licencji ZPL ({\em Zope Public License}). Licencja ta jest zgodna z~definicją OSD ({\em Open Source Definition}) jako ,,wolna licencja'', a~więc Zope jest programem o~otwartym kodzie źródłowym. ZPL w~odróżnieniu od licencji GPL (wersja 2) stworzonej  przez {\em Free Software Fundation} nie nakazuje odsyłania modyfikacji do pierwotnych twórców. W~chwili obecnej Zope jest rozwijany przez społeczność programistów-wolontariuszy. Do tej społeczności należy także {\em Zope Corporation} (kierowana przez Jim-a Fulton-a). {\em Zope Corporation} prowadzi rolę koordynatora prac, a~także zapewnia możliwości techniczne do dystrybucji kolejnych wersji Zope.

    \subsection{Aplikacja internetowa}

    Jeszcze parę lat temu większość stron internetowych była statyczna. Statyczne strony to takie, których autor (lub autorzy) tworzy pliki HTML ({\em Hiper Text Markup Language}) przy użyciu edytora teksu lub innego narzędzia, a~następnie umieszcza te pliki na serwerze pod wybranym adresem internetowym. Tak stworzona strona pokazuje dokładnie te informacje, jakie zawarł autor. W~celu naniesienia aktualizacji twórca strony musi ponownie wyedytować pliki HTML i~umieścić je na serwerze. W~przypadku, kiedy świeżo dopisane dane powinny znaleźć się na większej ilości podstron, konieczne jest żmudne poprawianie wielu plików HTML. Im częściej konieczna jest zmiana treści strony, tym większy staje się nakład pracy potrzebny do wykonania tego.

    Niewystarczająca elastyczność takiego podejścia do budowy stron internetowych spowodowała konieczność stworzenia lepszych metod. Krokiem w~tym kierunku było zastosowanie różnych metod dynamicznego tworzenia stron WWW. Jednym z~pierwszych sposobów tworzenia takich dynamicznych stron, który stał się popularny, był standard CGI ({\em Common Gateway Interface}). Autor strony tworzy program w~dowolnym języku programowania możliwym do uruchomienia na maszynie serwera. Program ten generuje kod HTML, który jest następnie przesyłany do czytelnika strony. Program taki można nazwać aplikacją internetową (ang. {\em web application}).

    \begin{description}
        \item[Aplikacja internetowa] (inaczej nazywana aplikacją webową) to ,,ogólna nazwa programu, który pracuje na maszynie podłączonej do sieci internet (serwerze) i~komunikuje się z~użytkownikiem za pomocą przeglądarki internetowej. Aplikacja webowa jest czymś więcej niż zwykłe, statyczne strony WWW. Zakłada ona interakcję z~użytkownikiem. 
	    
	    W~pracy aplikacji webowych pośredniczy serwer WWW, np. Apache. Do przygotowania samej aplikacji używa się różnych mechanizmów (np. CGI, ASP) i~języków (np. PHP, JSP), jak również serwerów aplikacji. Mechanizm prezentacji danych w~przeglądarce określa się czasem mianem cienkiego klienta.,,\cite{wiki-webapp}
    \end{description}

    Innym, bardzo popularnym sposobem na tworzenie stron dynamicznie budowanych, jest wykorzystanie skryptów - np. PHP ({\em PHP Hypertext Preprocessor}). Autor tworzy plik(i), który jest splotem kodu HTML oraz kodu języka skryptowego. Serwer WWW uruchamia interpreter skryptów dla tych części pliku które nie są kodem HTML, a~następnie łączy wszystko w~całość i~wysyła do przeglądarki WWW użytkownika.

    \subsection{Serwer aplikacji}

    Aby ułatwić budowanie aplikacji internetowych stworzono tzw. {\em framework-i}. {\em Framework} jest zestawem narzędzi i~funkcji, pozwalającą na przyspieszenie procesu tworzenia aplikacji internetowych. Programista może się skupić na programowaniu czynności jakie ma wykonywać aplikacja, ponieważ nie musi programować typowych działań, które wykonuje aplikacja internetowa (np. obsługa szablonów, zarządzanie sesjami użytkowników itd.).
        
    Często wzbogaca się {\em framework-i} o~możliwość udostępniania usług sieciowych - np. serwowanie stron poprzez protokół HTTP. Połączenie to nazywane jest serwerem aplikacji internetowych lub w~skrócie serwerem aplikacji.

    \begin{description}
        \item[Serwer aplikacji] według Wikipedii to:
	    \begin{enumerate}
		\item ,,Serwer w~sieci komputerowej, przeznaczony do zdalnego uruchamiania i~użytkowania aplikacji.
		\item Zestaw oprogramowania (platforma) wspierająca programistę/developera przy tworzeniu aplikacji. Umożliwia oddzielenie logiki biznesowej od usług dostarczanych przez producenta platformy (bezpieczeństwo, zarządzanie transakcjami, skalowalność, czy też dostęp do baz danych).
		\item Program działający na zdalnej maszynie obsługujący żądania kierowane do aplikacji, do której dostęp zapewnia. Użytkownik łączy się za pośrednictwem przeglądarki internetowej, kieruje żadanie do wybranej aplikacji, a~całość operacji odbywa się po stronie komputera należącego do organizacji, która udostępnia daną aplikację.''\cite{wiki-appserv}
	    \end{enumerate}
    \end{description}

    Podstawową funkcją serwera aplikacji jest możliwość zdalnego uruchamiania programu. Serwer musi także pośredniczyć między tym uruchomionym programem a~przeglądarką WWW użytkownika. Odbywa się to poprzez odsyłanie osobie uruchamiającej wyników działania aplikacji w~postaci strony HTML. Inne funkcje nie są konieczne, lecz bardzo ułatwiają tworzenie i~zarządzanie stroną. Pozwalają utrzymać nieprzerwane działanie, a~także zabezpieczyć przed ingerencją niepowołanych osób. Przydatne jest także zapewnienie skalowalności - możliwości rozłożenia obciążenia na wiele systemów komputerowych.

    Zastosowanie serwera aplikacji powoduje zmniejszenie nakładu pracy potrzebnego do stworzenia aplikacji internetowej. Skraca także czas potrzebny na znalezienie ewentualnych błędów oraz na dalszy rozwój. Wykorzystanie serwera aplikacji pozwala na stworzenie bardziej użytecznych i~ergonomicznych stron, bardziej lubianych przez użytkowników, a~także prezentujących informacje w~bardziej przystępny sposób. Użycie serwera aplikacji jest bezpieczniejsze niż używanie starszych metod budowania dynamicznych stron internetowych.

    \subsection{Zope jako serwer aplikacji}

    Zope udostępnia funkcje, jakie powinien spełniać serwer aplikacji, a~także posiada wiele innych przydatnych narzędzi. ,,Zope oparty jest na obiektowej bazie danych przechowującej nie tylko dane, ale również szablony i~skrypty. Dzięki temu mamy możliwość tworzenia i~konfiguracji aplikacji za pośrednictwem przeglądarki internetowej, co daje możliwość pracy nad projektem niemal z~każdego komputera podłączonego do Internetu.''\cite{soft20e}
    
    Aplikacja internetowa w~Zope jest podzielona na trzy warstwy:
    \begin{description}
        \item[prezentacji] - opisuje wygląd stron jakie będą wysyłane do przeglądarki użytkownika, do tego celu wykorzystuje jeden z~mechanizmów szablonów - ZPT ({\em Zope Page Template}) lub DTML ({\em Document Template Markup Language}),
        \item[logiki] - obiekty wykonywalne generujące pewne dane, które można wstawić do szablonów, mogą interpretować i~zapamiętywać dane przesyłane przez użytkownika, mogą także wykonywać inne zadania. W~Zope są trzy podstawowe obiekty logiki - skrypty w~języku Python (ang. {\em Script (Python) Objects}), metody zewnętrzne (ang. {\em External Methods}) oraz metody ZSQL (ang. {\em Z~SQL Methods}),
        \item[danych] - czyli informacje składowane najczęściej w~bazie danych lub w~obiektach wewnątrz Zope oraz plikach zewnętrznych. Dane te są przetwarzane przez warstwę logiki i~udostępniane użytkownikom przy użyciu warstwy prezentacji.
    \end{description}

        Dzięki zastosowanemu w~Zope mechanizmowi zabezpieczeń, możliwe jest jednoczesne zmienianie różnych części aplikacji internetowej przez różnych twórców. Częścią interfejsu mogą zająć się osoby znające się na tej dziedzinie, nie muszą one poznawać zasad działania logiki, wystarczy im tylko wiedza na temat struktur danych otrzymywanych przez wykonanie tychże skryptów. Podobnie programiści logiki nie muszą wiedzieć w~jaki sposób wyświetlone zostaną uzyskane przez ich skrypty dane.

    \subsection{Budowa Zope}

    Na rysunku \ref{zope-arch} przedstawiono architekturę Zope, a~także sposób, w~jaki odbywa się komunikacja między poszczególnymi elementami składowymi a~zewnętrznymi obiektami, takimi jak bazy danych czy inne serwery.

    \begin{figure}
	\includegraphics[width=15cm]{rys/budowa}
	\caption[Architektura Zope]{Architektura Zope \newline \em{Źródło: opracowanie własne na podstawie The Zope Book, Figure 2-1 \cite{tzb26}}}
        \label{zope-arch}
    \end{figure}

    Podstawowymi elementami wchodzącymi w~skład Zope są:
    \begin{description}
        \item[Rdzeń Zope] (ang. {\em Zope Core}) jest główną częścią odpowiedzialną za zarządzanie obiektową bazą danych (ZODB), uruchamianie i~wykonywanie skryptów, przetwarzanie szablonów.
	\item[Produkty] (ang. {\em Zope Products}) są to wtyczki (ang. {\em plug-ins}) rozszerzające możliwości Zope. Oferują one pełną gamę udogodnień - począwszy od bardzo małych zmian, aż po takie które przemieniają całkowicie niektóre zachowania serwera. 
	    
	    Na stronie internetowej projektu Zope umieszczona jest ogólnodostępna baza produktów. Umieszczone tam wtyczki zostały pogrupowane na następujące kategorie:
	    \begin{description}
		\item[dotyczące handlu] - (ang. {\em Commerce}) ,,produkty odpowiedzialne za operacje kupna-sprzedaży,''\cite{zope-prod}
		\item[obiekty prezentacji] - (ang. {\em Content Object}) ,,produkty pozwalające tworzyć nowe dokumenty prezentujące zawartość,''\cite{zope-prod} 
		\item[przykłady] - ,,produkty zawierające przykłady pomagające osobom odpowiedzialnym za tworzenie aplikacji,''\cite{zope-prod}
		\item[dostęp do zewnętrznych zasobów] - (ang. {\em External Access}) ,,produkty pozwalające na dostęp do świata poza Zope (np. sterowniki baz danych), a~także pomagające innym produktom na dostęp do Zope,''\cite{zope-prod}
		\item[mechanizm opinii] - (ang. {\em Feedback}) ,,produkty umożliwiające przekazywanie opinii lub reakcji użytkowników,''\cite{zope-prod}
		\item[udogodnienia] - (ang. {\em Helpers}) ,,produkty ułatwiające budowanie aplikacji,''\cite{zope-prod}
		\item[umiędzynarodowienie] - (ang. {\em Internationalization}) - ,,produkty pozwalające na prezentowanie treści w~różnych wersjach językowych,''\cite{zope-prod}
		\item[pomagające w~nawigacji] - (ang. {\em Navigational}) ,,produkty pomagające budować ułatwienia w~poruszaniu się po aplikacji internetowej,''\cite{zope-prod}
		\item[poprawki] - (ang. {\em Patches}) ,,produkty zwierające ulepszenia i~poprawki do kodu źródłowego Zope,''\cite{zope-prod}
		\item[serwery] - (ang. {\em Servers}) ,,produkty związane z~prowadzeniem komunikacji w~protokole HTTP (i/lub innych), a~także pomagające w~współdziałaniu z~innymi serwerami,''\cite{zope-prod}
		\item[zarządzanie użytkownikami] - (ang. {\em User Management}) ,,produkty ułatwiające zarządzanie kontami użytkowników,''\cite{zope-prod}
		\item[wizualizacyjne] - (ang. {\em Visual}) ,,produkty prezentujące dane w~postaci wizualnej (np. jako grafy lub zdjęcia).,,\cite{zope-prod}
	    \end{description}
        \item[{\em ZClasses}] są to wtyczki stworzone przez twórcę aplikacji - można je traktować jako produkty stworzone przez samego siebie (w odróżnieniu od produktów tworzonych przez innych).
        \item[ZSerwer] (ang. {\em ZServer}) jest wbudowanym serwerem obsługującym podstawowe protokoły komunikacyjne internetu (HTTP, FTP, XML-PRC i~inne), pośredniczy on podczas komunikacji między użytkownikiem posługującym się przeglądarką WWW a~aplikacją internetową uruchomioną w~środowisku Zope.
        \item[ZODB] - obiektowa baza danych ({\em Zope's Object Database}) jest bazą przechowującą obiekty, którymi posługuje się Zope (np. szablony, skrypty itd.).
    \end{description}

    Należy także wymienić elementy które nie wchodzą w~skład Zope, lecz są konieczne lub bardzo przydatne w trakcie działania serwera aplikacji.
    \begin{description}
        \item[Przeglądarka WWW] - klient protokołu HTTP uruchomiony po stronie użytkownika. Możliwe jest bezpośrednie łączenie użytkownika z~ZSerwerem, częściej jednak komunikacja odbywa się za pośrednictwem innego serwera WWW.
        \item[Serwer WWW] - serwer pośredniczący między ZSerwerem a~przeglądarką WWW. Dzięki wstawieniu między ZSerwer a~użytkownika dodatkowego serwera WWW (np. {\em Apache, Lighttp} lub {\em Microsoft IIS}) możliwe jest przyspieszenie działania komunikacji (np. dzięki buforowaniu podstron), utworzenie wirtualnych hostów (rozpoznawanie którą z~wielu dostępnych na serwerze aplikacji uruchomić, może odbywać się po nazwach domen, a~nie po ścieżce dostępu przekazywanej w~URL) oraz zwiększenie bezpieczeństwa (np. poprzez ograniczenie dostępu do interfejsu administracyjnemu tylko wybranym adresom IP). Komunikacja ZSerwera z~serwerem WWW odbywa się poprzez interface FastCGI lub HTTP.
        \item[Baza danych] - zastosowanie zewnętrznej relacyjnej bazy danych (np. {\em MySQL, PostgreSQL} lub {\em Oracle}), procentuje skróceniem czasu zapisu i~wyszukiwania danych. Wbudowany w~Zope ZODB nie jest efektywnym sposobem przechowywania danych tekstowych, za to potrafi przechowywać obiekty (czego nie potrafią relacyjne bazy danych). Komunikacja z~zewnętrznymi bazami odbywa się przy użyciu zapytań SQL lub wywołań ODBC.
        \item[System plików] - ze względów bezpieczeństwa możliwości skryptów dostępnych w~Zope są mocno ograniczone, pełną swobodę mają metody zewnętrzne. Metody te przechowywane są właśnie w zewnętrznym systemie plików.
    \end{description}

    \subsection{Procedura generowania przez Zope stron internetowych}

    Mając wiedzę o~podstawowych elementach budowy Zope oraz o~relacjach między nimi możliwe jest prześledzenie działań, jakie zachodzą podczas połączenia między użytkownikiem a~aplikacją internetową.
        
    Użytkownik poprzez swoją przeglądarkę WWW wybiera adres strony internetowej, którą chce obejrzeć (np. {\em http://filmobaza.pl/film?id=1002}). Przeglądarka łączy się za pośrednictwem protokołu HTTP z~serwerem WWW działającym na maszynie pod adresem wskazywanym przez domenę (tu {\em filmobaza.pl}). Serwer WWW rozpoznaje i wyszukuje w~swojej konfiguracji odpowiedni wirtualny host i~tłumaczy otrzymany adres (w tym przypadku {\em /film?id=1002}) na odpowiednie wywołanie serwera aplikacji. Mając tak przygotowane dane łączy się z~Zope (działającym przeważnie na tym samym systemie komputerowym) oczekując zwrócenia treści strony, którą następnie będzie mógł odesłać do użytkownika. ZSerwer po otrzymaniu zapotrzebowania na daną podstronę przekazuje działanie do rdzenia Zope. Tam następuje rozpoznanie na podstawie otrzymanego URI jaki obiekt należy uruchomić (tu {\em film}). Obiekt ten zostaje odczytany z~ZODB a~następnie uruchomiony. Reszta adresu zostaje rozpoznana jako parametry (w omawianym przypadku jest jeden parametr o~nazwie {\em id} i~wartości 1002). W~zdecydowanej większości przypadków odwołania odnoszą się do obiektów szablonów (napisanych w~języku ZPT lub DTML). Pobrany wcześniej szablon interpretowany jest przez moduł za to odpowiedzialny. Często wewnątrz szablonu istnieją odwołania do skryptów. W~takim przypadku ponownie następuje pobranie odpowiedniego skryptu z~ZODB i~jego uruchomienie. Jeżeli wywoływana jest metoda zewnętrzna konieczne jest otwarcie i~uruchomienie pliku znajdującego się w~systemie plików. Gdy skrypt jest metodą ZSQL, wykonanie jego zostaje przekazanie do odpowiedniego produktu rozszerzającego działanie Zope o~komunikację z~używaną relacyjną bazą danych (np. jeżeli używana jest baza {\em MySQL}, konieczna jest instalacja wtyczki {\em ZMySQLDA}). Generowanie zapytanie SQL może przybrać dwie formy - modyfikujące bazę (wtedy nie następuje zwrócenie danych) lub przeszukujące dane (zwracane są dane, lecz nie następuje żadna zmiana w~bazie). Wszystkie trzy typy skryptów (tj. skrypty, metody zewnętrzne i metody ZSQL) zwracają wynik swojego działania do interpretera szablonów (w przypadku braku danych zwracają obiekt pusty (typu None)). Dane o~odpowiedniej strukturze mogą być umieszczone wewnątrz generowanego przez szablon kodu (np. kodu HTML). Po zakończeniu przetwarzania skryptu następuje zwrócenie gotowej strony do ZSerwer, a~następnie do serwera WWW. Jeżeli z~jakiegoś powodu niemożliwe było prawidłowe zadziałanie któregoś ze skryptów lub szablonów albo wystąpił inny błąd, Zope zamiast gotowej strony odsyła informacje o~wyjątku, a~także zapisuje do wewnętrznego dziennika błędów informacje przydatne do identyfikacji problemu.
        
    Wszystkie te działania są oczywiście niewidoczne dla użytkownika. Otrzymuje on jedynie gotową stronę tak jakby była ona stroną statyczną.

\section{Elementy środowiska Zope}
    
    \subsection{Interfejs zarządzania Zope}

    Proces tworzenia aplikacji internetowej w~Zope odbywa się poprzez specjalnie do tego stworzony interfejs. {\em Zope Managment Interface} w~skrócie ZMI dostępny jest pod adresem {\em http://nazwa-domeny/manage}. Dostęp oczywiście chroniony jest hasłem. Po zalogowaniu ukazuje się strona zbudowana z~trzech części: nagłówka, ramki nawigacji ({\em Nawigator Frame}) i~ramki {\em workspace} ({\em Workspace Frame}) (por. rys.~\ref{zmi}).

    \begin{figure}
	\includegraphics[width=15cm]{rys/zmi}
	\caption[Interfejs zarządzania Zope]{Interfejs zarządzania Zope \newline \em{Źródło: opracowanie własne\hspace*{10cm}}}
        \label{zmi}
    \end{figure}

    Ramka {\em workspace} pozwala przeglądać i~edytować obiekty znajdujące się w~ZODB. W~górnej części tej ramki dostępne są zakładki dające dostęp do różnych funkcjonalności. Najważniejsze z~nich to:
    \begin{description}
        \item[{\em View}] - pokazuje w~jaki sposób wybrany obiekt pokazywany będzie w~przeglądarce użytkownika,
        \item[{\em Properties}] - w~tym miejscu możliwy jest podgląd, edycja i~dodawanie zmiennych przypisanych do wybranego obiektu,
        \item[{\em Security}] - panel ten daje możliwość zezwalania lub blokowania wielu różnych czynności wybranym użytkownikom. Okno menadżera zabezpieczeń składa się z~listy dostępnych akcji (czyli zdarzeń jakie mogą wystąpić) oraz z~listy {\em checkbox-ów} przypisanych do jednej z~czterech grup użytkowników. Te grupy to: 
            \begin{description}
                \item[{\em Anonumous}] - użytkownicy niezalogowani i~goście,
                \item[{\em Authenticated}] - zalogowani użytkownicy nie mający pełnych praw,
                \item[{\em Manager}] - administratorzy mający większe prawa dostępu,
                \item[{\em Owner}] - użytkownik który jest właścicielem danego obiektu. 
            \end{description}
            Edycja uprawnień polega na zaznaczaniu lub odznaczaniu {\em checkbox-u} przy danej akcji dla wybranej grupy użytkowników. Jeżeli pole jest zaznaczone oznacza to, że użytkownik z~danej grupy posiada uprawnienia do wykonania akcji. Akcje dzielą się na następujące typy: 
            \begin{description}
                \item[akcje dostępu] - (ang. {\em access}) zezwolenie na dostęp do zmiennych i~danych przechowywanych w~różnych częściach Zope,
                \item[akcje dodawania] - (ang. {\em add}) możliwe jest ograniczenie możliwości tworzenia nowych obiektów,
                \item[akcje zmiany] - (ang. {\em change}) zabezpieczenie przed zmianą zawartości wybranych obiektów,
                \item[akcje zarządzania] - (ang. {\em manage}) zarządzanie obiektami i~innymi elementami składowymi Zope powinno być udostępnione tylko uprzywilejowanym użytkownikom,
                \item[akcje przeglądania] - (ang. {\em view}) określa kto może oglądać wyniki uruchomienia danego obiektu,
                \item[inne akcje] - do nich należą między innymi: usuwanie, kopiowanie, przesuwanie obiektów; definiowanie praw; importowanie i~eksportowanie obiektów; instalowanie i~usuwanie produktów; łączenie i~rozłączanie połączeń z~zewnętrznymi bazami danych i~inne.
            \end{description}
        \item[{\em Undo}] - każda zmiana obiektu zostaje zapamiętana jako transakcja (ang. {\em Transaction}) z~obiektową bazą danych (ZODB). Możliwe jest cofnięcie stanu ZODB do stanu sprzed pewnej ilości transakcji. Odbywa się to właśnie w~tej zakładce,
        \item[{\em Ownership}] - do każdego z~obiektów znajdujących się w~ZODB możliwe jest przypisanie właściciela. Na tej zakładce pokazane jest, jaki użytkownik jest właścicielem obiektu.
    \end{description}

    Natomiast w~dolnej części ramki {\em Workspace} znajdują się przyciski umożliwiające operowanie obiektami. Podobnie jak pliki na dysku twardym obiekty w~Zope można kopiować, usuwać, zmieniać ich nazwy, wycinać i~wklejać. Odbywa się to poprzez zaznaczenie {\em checkbox-u} znajdującego się przy obiekcie oraz na kliknięcie przycisku skojarzonego z~jednym z~działań. 
    
    W~ten sam sposób możliwe jest eksportowanie i~importowanie obiektów. Eksport obiektu możliwy jest na dwa sposoby - do pliku na serwerze lub do pliku wysyłanego przy użyciu protokołu HTTP do przeglądarki WWW użytkownika. Utworzony plik z~rozszerzeniem {\em .zexp} zawiera wybrany obiekt lub grupę obiektów (jeżeli zostanie wybrany obiekt kontenerowy - np. folder). Import ze względów bezpieczeństwa możliwy jest tylko z~pliku umieszczonego w~wyznaczonym do tego celu katalogu w~systemie plików komputera na którym uruchomiony jest serwer aplikacji. Mechanizm importu i~eksportu daje możliwość łatwego przenoszenia kodu między serwerami Zope a~także szybkie tworzenie kopii zapasowych.

    \subsection{Podstawowe obiekty Zope}

    Serwer aplikacji Zope od razu po zainstalowaniu posiada zestaw obiektów, które mogą być użyte podczas budowy. Tak, jak aplikację internetową można podzielić na trzy warstwy, podobnie obiekty można podzielić na cztery grupy - trzy grupy zawierające obiekty skojarzone z tymi opisywanymi wcześniej warstwami, a~także grupę innych obiektów nie uczestniczących w~budowie samej aplikacji, ale pomagających w~jej zarządzaniu. Podział na cztery grupy to:
    \begin{description}
        \item[obiekty prezentacji] - szablony budujące interfejs graficzny, a więc generujące dokumenty w formacie HTML wysyłane do przeglądarki WWW użytkownika. W~tej grupie można wyróżnić następujące obiekty:
            \begin{description}
                \item[dokument DTML] - (ang. {\em DTML Document}) ,,jest narzędziem do szablonowania który wspomaga tworzenie dynamicznych stron HTML i~tekstu. (\ldots) DTML jest opartym o~{\em tagi} językiem skryptowym. Oznacza to, że {\em tagi} (np. {\em <dtml-var name>}) osadzone w~kodzie HTML powodują zastąpienie pewnej części strony przez ,,wyliczoną'' zawartość. DTML jest językiem skryptowym działającym po stronie serwera (ang. {\em server-side}). Oznacza to, że komendy DTML są wykonywane przez Zope na maszynie serwera i~wyniki wykonania są wysyłane do przeglądarki WWW użytkownika. Inaczej jest w~przypadku języków skryptowych działających po stronie klienta (np. {\em JavaScript}), skrypty te nie są przetwarzane przez serwer lecz są wysyłane do przeglądarki WWW i~tam uruchamiane.,,\cite{tzb26} DTML był głównie wykorzystywany w~starszych wersjach Zope (wersje 1.x). Obecnie zalecane jest używanie ZPT do tworzenia szablonów,
                \item[szablon ZPT] - ({\em Zope Page Template}) są narzędziem do dynamicznego generowania dokumentów HTML. Dokładny opis ZPT został umieszczony w~rozdziale \ref{zpt},
                \item[{\em ReStructuredText Document}] jest plikiem tekstowym, w~którym pewne często występujące elementy (np.: akapity, rozdziały, wypunktowania, listy, tabele, itd.) zapisane są według z~góry określonych zasad. Dzięki takiemu podejściu łatwe jest przetworzenie zwykłego pliku tekstowego na dokumenty w~formatach, w~których dopuszczalne jest np. zmienianie krojów i~wielkości czcionek. W~Zope {\em ReStructuredText Document} przetwarzany jest na plik HTML. Więcej informacji na temat tworzenia takich dokumentów można znaleźć na stronie internetowej projektu: \\ {\em http://docutils.sourceforge.net/rst.html}.
            \end{description}
        \item[obiekty logiki] - skrypty wykonujące różnorakie zadania. Do tej grupy należą:
            \begin{description}
                \item[skrypty w~języku Python] - (ang. {\em Python-based Scripts}) stosowane są głównie do wykonywania prostych zadań. Z~powodów bezpieczeństwa w~skryptach możliwe jest jedynie używanie mocno zredukowanych możliwości języka Python. Bardziej rozbudowany opis znajduje się w~rozdziale \ref{zapi},
                \item[metody zewnętrzne] - (ang. {\em External Method}) aby móc wykorzystać cały potencjał języka Python zastosowano w~Zope metody zewnętrzne. Tworzenie takich metod możliwe jest tylko przez użytkowników mających dostęp do systemu plików komputer,a na którym uruchomiony jest serwer aplikacji. Poprzez interfejs administracyjny ZMI możliwe jest tylko podłączenie metod zewnętrznych znajdujących się w plikach wgranych uprzednio do odpowiedniego katalogu na dysku twardym serwera. Podejście takie wymuszone jest względami bezpieczeństwa. Gdyby skrypty w~języku Python przechowywane wewnątrz ZODB miały np. dostęp do systemu plików czy do wywołań systemowych, to mogłyby zaburzyć prawidłową pracę serwera aplikacji (np. poprzez zmianę konfiguracji lub wysłania sygnału przerwania do systemu operacyjnego),
                \item[metody DTML] - (ang. {\em DTML Method}) podobnie jak w~dokumentach DTML wykorzystywany jest ten sam zestaw {\em tagów}, a~także uruchamiany jest ten sam interpreter. W~odróżnieniu jednak od szablonów napisanych w~DTML wynikiem wykonania metod nie jest kod HTML lecz inne wartości (np. liczbowe, tekstowe czy struktury danych). Wartości te zostaną wykorzystane podczas przetwarzania szablonów. Ponieważ język DTML nie był przygotowywany z~myślą o~tworzeniu wyrafinowanych skryptów, zalecane jest tworzenie logiki aplikacji internetowych przy użyciu innych narzędzi - np. skryptów w~języku Python,
                \item[metody ZSQL] - (ang. {\em Z~SQL Method}) w~celu usprawnienia komunikacji z~relacyjnymi zewnętrznymi bazami danych wprowadzono możliwość dynamicznego tworzenia zapytań SQL. Odbywa się to przy użyciu pewnych elementów języka DTML. Pełniejszy opis można znaleźć w~rozdziale \ref{zsql}.
            \end{description}
        \item[obiekty danych] - obiekty, w~których mogą być przechowywane dane lub obiekty dające możliwość połączenia z~danymi znajdującymi się poza serwerem aplikacji. Najważniejsze z nich to:
            \begin{description}
                \item[plik] - (ang. {\em File}) możliwe jest wstawienie do ZODB dowolnego pliku. Gdy nastąpi żądanie wysłania do przeglądarki WWW takiego pliku, nie nastąpi żadne jego przetworzenie, zostanie on po prostu odczytany i~wysłany. Z~obiektem plikowym skojarzony jest jego typ (ang. {\em MIME Type}). Wartość tego parametru zostanie przekazana w~odpowiedzi protokołu HTTP, informując użytkownika o~formacie wysyłanego pliku. Gdyby Zope nieprawidłowo rozpoznał jego typ, podczas wstawiania istnieje możliwość ustawienia ręcznego wartości tego parametru - patrz rysunek \ref{mime}, 
                \item[obraz] - (ang. {\em Image}) podobnie do obiektu plikowego w~tym obiekcie przechowywane są dane binarne, skojarzone są one jednak z~formatami plików graficznych obsługiwanych przez większość nowoczesnych przeglądarek WWW - tzn. GIF, JPEG i~PNG. Interfejs edycji obiektu obrazka podobny jest do interfejsu obiektu pliku (przedstawionego na rysunku \ref{mime}), z~tym wyjątkiem, że dodano możliwość podglądu obrazu,
                \item[połączenie z~zewnętrzną bazą danych] - (ang. {\em Database Connection}) jak już wcześniej opisywałem komunikacja z~zewnętrznymi relacyjnymi bazami danych odbywa się poprzez zapytania SQL generowane przez metody ZSQL. Jednak aby móc rozpocząć komunikację konieczne jest skonfigurowanie połączenia. Odbywa się to właśnie poprzez obiekty sterowników baz danych (ang. {\em database adapters}). Domyślnie zainstalowanym sterownikiem jest {\em Z~Gadfly Database Connection} pozwalający na połączenia z~bazą {\em Gadfly}. Więcej o~bazie {\em Gadfly} a~także możliwościach połączenia z~innymi relacyjnymi bazami danych zostało opisanych w~rozdziale \ref{zsql}.
            \end{description}
        \item[inne] - tutaj trzeba zaliczyć wszystkie te obiekty, które nie wchodzą w~skład budowanych aplikacji internetowych lecz są konieczne lub bardzo przydatne w~działaniu serwera aplikacji lub zarządzaniu aplikacją internetową. Jednym z~takich obiektów jest folder (ang. {\em Folder}), czyli obiekt mogący przechowywać inne obiekty - obiekt kontenerowy. Inne obiekty zapewniają możliwości włączania różnych funkcjonalności serwera aplikacji i~edycji ich ustawień. Opis niektórych mechanizmów został przedstawiony w~rozdziale \ref{installed}.
    \end{description}

    \begin{figure}
	\includegraphics[width=15cm]{rys/file-mime}
	\caption[Edycja obiektu plikowego w~Zope]{Edycja obiektu plikowego w~Zope \newline \em{Źródło: opracowanie własne\hspace*{10cm}}}
        \label{mime}
    \end{figure}

    \subsection{Obiekty pustej aplikacji internetowej w środowisku Zope}
    \label{installed}

    Świeżo zainstalowany i~uruchomiony serwer Zope posiada następujące obiekty:
    \begin{description}
        \item[{\em Control\_Panel}] - w~tym miejscu możliwe jest przeglądanie i~edycja różnych ustawień środowiska Zope. Instalowanie i~zarządzanie produktami odbywa się poprzez moduł {\em Product Managment}. Tu także możliwe jest edytowanie ustawień poszczególnych produktów oraz przeglądanie dołączonych plików pomocy,
        \item[{\em acl\_users}] jest obiektem typu {\em User Folder} czyli zbiorczym katalogiem kont uprzywilejowanych użytkowników serwera. Tutaj ma się możliwość dodawania nowych kont, a~także edycji praw i~haseł już istniejących,
        \item[{\em browser\_id\_manager}] - obiekt typu {\em Browser Id Manager} zapewnia obsługę mechanizmu rozpoznawania użytkowników poprzez znakowanie ich unikalnym kluczem. Najczęściej ta niepowtarzalna sygnatura jest umieszczana w~tzw. ciasteczkach (ang. {\em Cookie}) przechowywanych przez przeglądarkę WWW na maszynie użytkownika i~wysyłanych podczas każdorazowego łączenia się z~serwerem aplikacji. {\em Browser Id Manager} pozwala na ustawienie zachowań tego mechanizmu oraz zasad zabezpieczeń,
        \item[{\em error\_log}] - w~tym miejscu możliwe jest przeglądanie informacji dotyczących wyjątków i~błędów, które nastąpiły podczas działania aplikacji. Rysunek \ref{errlog} przedstawia początek przykładowego wydruku wyjątku. Pełna informacja o~błędzie składa się z: podstawowych informacji o~błędzie (np. rodzaj błędu, czas jego wystąpienia itd.), ścieżki wywołania modułu w~którym wystąpił błąd, listy zmiennych, jakie są dostępne wraz z~ich wartościami (zmienne te głównie dotyczą żądania jakie przesłała przeglądarka WWW użytkownika),
        \item[{\em index\_html}] - obiekt typu {\em DTML Method} zawierający szablon głównej strony aplikacji internetowej. Domyślna wartość to {\tt <dtml-var zope\_quick\_start>} - komenda ta generuje stronę na której znajduje się podstawowa pomoc przydatna przy rozpoczynaniu pracy z~Zope,
        \item[{\em session\_data\_manager}] czyli obiekt typu {\em Session Data Manager} zapewnia mechanizm wymiany danych w~trakcie sesji. Kolejne żądania wysyłane przez tego samego użytkownika dzięki identyfikacji jego przeglądarki można połączyć w~ciąg pracy aplikacji internetowej. Sesją zatem nazywamy interakcję użytkownika z~serwerem aplikacji odbywającą się przez pewien okres czasu w~kilku (-nastu, -dziesięciu) żądaniach protokołu HTTP. {\em Session Data Manager} pozwala przechować pewne dane między tymi kolejnymi wywołaniami,  
        \item[{\em standard\_error\_message, standard\_html\_footer, standard\_html\_header}] - określają wygląd informacji o~błędzie jaka zostanie przesłana do przeglądarki WWW użytkownika, który natrafił na wyjątek,
        \item[{\em standard\_template.pt}] - zawiera podstawowy szablon stron generowanych przez Zope,
        \item[{\em temp\_folder}] - w~tym folderze możliwe jest przechowywanie tymczasowych obiektów, tutaj także znajdują się dane przechowywane przez {\em Session Data Manager},
        \item[{\em virtual\_hosting}] - obiekt typu {\em Virtual Host Monster} zapewniający mechanizm rozróżniania aplikacji internetowych na podstawie adresu.
    \end{description}

    \begin{figure}
	\includegraphics[width=15cm]{rys/error-log}
	\caption[Wydruk przykładowego wyjątku w~Zope]{Wydruk przykładowego wyjątku w~Zope \newline \em{Źródło: opracowanie własne\hspace*{10cm}}}
        \label{errlog}
    \end{figure}

    \subsection{Szablony ZPT ({\em Zope Page Template})}
    \label{zpt}

    ,,Szablony ZPT ({\em Zope Page Template}) pozwalają na tworzenie dynamicznych stron internetowych. Statyczny kod HTML w~szablonie jest zmieniany na dynamiczny dzięki dodaniu przestrzeni nazw zgodnej ze specyfikacją XML, które to atrybuty definiują dynamiczne zachowania tych stron.''\cite{tzb26}

    Dzięki umieszczeniu elementów decydujących o~dynamicznych właściwościach szablonów wewnątrz atrybutów, a~nie jako osobne {\em tagi}, tak jak to jest w~dokumentach DTML, kod szablonu zgodny jest ze specyfikacją języka HTML (lub XML czy XHTML). Daje to możliwość edytowania szablonów przy użyciu narzędzi do budowy statycznych stron internetowych. Podejście takie pozwala na dopuszczenie do prac nad aplikacją internetową osób nie znających języka szablonów ZPT lecz potrafiących tworzyć ładne strony (np. grafików, designerów). Szablony ZPT można edytować przy użyciu edytorów WYSIWYG ({\em What You See Is What You Get}) czyli graficznych edytorów. Zwalnia to nawet twórców layout-u ze znajomości języka HTML!

    Zastosowanie atrybutów do realizacji zachowań dynamicznych ma też swoje minusy. ZPT nie potrafi generować plików w~innym standardzie niż HTML czy XML. Niemożliwe przez to jest tworzenie plików tekstowych (np. treści listów) czy arkuszy stylów CSS. Z~tego powodu zachowano nadal w~Zope interpreter DTML dzięki któremu takie działania można przeprowadzić.

    \subsubsection{TAL ({\em Template Attribute Language})}
    ,,Szablony ZPT używają {\em Template Attribute Language} (TAL). Wyrażenia TAL składają się ze specjalnych atrybutów umieszczonych wewnątrz {\em tagów} poprzedzonych przedrostkiem {\tt tal:} będącym przestrzenią nazw zgodną ze standardem XML. Do wszystkich tych wyrażeń TAL przypisane są wartości zapisywane w~cudzysłowie.''\cite{tzb26} 
    
    Język TAL składa się z~następujących atrybutów:
    \begin{description}
        \item[{\tt tal:attributes}] - wstawia do wewnątrz {\em taga} atrybut o~zadanej wartości. Przykładem może być dynamiczne tworzenie linków. Kod szablonu: 
            \begin{verbatim}<a tal:attributes="href python: '/film?id=%s'
% request.id">nazwa filmu</a> \end{verbatim}
            spowoduje wykonanie jednolinijkowego skryptu w~języku Python (w tym przypadku operującego na tekscie). Wynik działania tego skryptu zostanie przypisany do atrybutu podanego na początku zadanej wartości wyrażenia TAL ({\tt href}). Efektem przetworzenia tej linii szablonu będzie utworzenie kodu HTML: 
            \begin{verbatim}<a href="/film?id=1002">nazwa filmu</a>\end{verbatim}

        \item[{\tt tal:define}] - definiuje zmienną. Zasięg zmiennej rozciąga się w~całym zakresie objętym przez {\em tag}. Patrząc na kod szablonu:
            \begin{verbatim}<span tal:define="wynik here/my_script">
    <h1 tal:content="wynik">tekst</h1>
</span>\end{verbatim}
            można zauważyć, że zostaje zdefiniowana zmienna {\tt wynik} do której zostaje przypisana wartość zwrócona przez skrypt {\tt my\_script} znajdujący się w~tym samym folderze co szablon. Zmienna ta może być wykorzystywana w~całym zakresie obejmowanym przez parę tagów {\tt <span> </span>}. W~opisanym przypadku została wykorzystana do wstawienia na stronie nagłówka pierwszego stopnia. Ostatecznie wygenerowany zostanie następujący kod HTML:
            \begin{verbatim}<span>
    <h1>wartość wykonania skryptu my_script</h1>
</span>\end{verbatim}
        Powyższy kod został specjalnie spreparowany na użytek przykładu. Mógłby zostać zastąpiony prostszym sformułowaniem, tj.:
        \begin{verbatim}<h1 tal:content="here/my_script">tekst</h1>\end{verbatim}
        Wyrażenie {\tt tal:define} stosuje się, gdy pewna wyliczona wartość będzie kilkakrotnie wykorzystywana - nie potrzebne będzie ponowne wykonanie skryptu,

	\item[{\tt tal:condition}] - spowoduje umieszczenie {\em tagu} (wraz z~zawartością, jeżeli jest to para {\em tagów}), jeżeli wyrażenie podane w~wartości atrybutu jest prawdziwe. Jeżeli skrypt {\em my\_script} zwróci wartość prawdziwą (tzn. inną niż: zero, pusty ciąg znaków, pustą listę, pusty słownik lub wartość {\em None}) to kod skryptu:
            \begin{verbatim}<span tal:condition="here/my_script">
    <p>my_script zwrócił true</p>            
</span>\end{verbatim}
        zostanie przetworzony na:
            \begin{verbatim}<span>
    <p>my_script zwrócił true</p>
</span>\end{verbatim}
        w~innym przypadku kod zostanie pominięty.

        Do języka TAL nie został wbudowany mechanizm tworzenia rozbudowanych warunków (np. {\em if .. else if .. else}). W~takim przypadku należy samemu zbudować strukturę przy użyciu {\tt tal:define} i~{\tt tal:condition}:
            \begin{verbatim}<span tal:define="wynik here/my_script">
    <p tal:condition="wynik">
        my_script zwrócił true
    </p>
    <p tal:condition="not: wynik">
        my_script zwrócił false
    </p>
</span>\end{verbatim}

        \item[{\tt tal:content}] - zastępuje zawartość znajdującą się między parą {\em tagów} wartością przypisaną do wyrażenia TAL. Na przykład:
            \begin{verbatim}<h1 tal:content="here/my_script">tekst</h1>\end{verbatim}
            po interpretacji da wynik:
            \begin{verbatim}<h1>wartość wykonania skryptu my_script</h1>\end{verbatim}

        \item[{\tt tal:omit-tag}] - {\em tag}, w~którym zostanie wstawiony ten atrybut nie zostanie przepisany do kodu wynikowego, zostanie natomiast wstawiona jego zawartość - kod będący wewnątrz pary {\em tagów} lub wstawiany poprzez {\tt tal:content}. W~więc:
            \begin{verbatim}<h1 tal:content="here/my_script" tal:omit-tag="">
    tekst
</h1>\end{verbatim}
            zostanie zamienione na:
            \begin{verbatim}wartość wykonania skryptu my_script\end{verbatim}

        \item[{\tt tal:on-error}] - w~przypadku gdy podczas wykonania wyrażenia TAL wystąpi błąd to nastąpi zamiana zawartości {\em tagu} wartością atrybutu {\tt tal:on-error}. Jest odpowiednikiem {\tt tal:content} wykonywanym tylko gdy wystąpi wyjątek. Szablon zawierający:
            \begin{verbatim}<p tal:content="python: '%.3f' % (1 / id)"
   tal:on-error="string: wystąpił błąd">
    tekst
</p>\end{verbatim}
            powinien zostać zamieniony na:
            \begin{verbatim}<p>0.123</p>\end{verbatim}
            Natomiast w~przypadku gdy zmienna {\tt id} nie została zdefiniowana lub nie jest liczbą albo jest równa zero to wystąpi wyjątek i~wynikiem będzie kod:
            \begin{verbatim}<p>wystąpił błąd</p>\end{verbatim}

	\item[{\tt tal:repeat}] - powtarza w~pętli {\em tag}, w~którym wstawiono ten atrybut. Często stosowany jest do budowy tabel, gdzie powtarzane jest wstawianie {\em tagu} języka HTML odpowiadającego za linie ({\tt <tr>}) lub kolumnę ({\tt <td>}). Podczas wykonania pętli zdefiniowany jest iterator, a~także zmienna {\em repeat} przechowująca opis stanu wykonania pętli. Zmienna repeat posiada szereg przydatnych atrybutów, najważniejsze z~nich to: {\em index} - licznik wykonania pętli (liczony od zera), {\em number} - licznik (liczony od jedynki), {\em length} - podaje ilość elementów, po których następuje iteracja, {\em first, start} - zwraca {\em true} gdy pętla wykonywana jest po raz pierwszy, {\em last, end} - {\em true} gdy jest to ostatnie wykonanie pętli. 
            
            Przypatrzmy się przykładowi:
            \begin{verbatim}<table>
    <tr tal:repeat="item here/get_items">
        <td tal:content="repeat/item/number"></td>
        <td tal:content="item/name"></td>
        <td tal:content="item/size"></td>
    </tr>
</table>\end{verbatim}
            Założeniem jest to, że skrypt {\tt get\_items} zwraca listę obiektów mających co najmniej dwa atrybuty: {\tt name} i~{\tt size}. Dla każdego z~obiektów zawartych w~zwróconej liście nastąpi powtórzenie wstawiania pary {\em tagów} {\tt <tr> </tr>} wraz z~całą zawartością obejmowaną przez nie. 
            Efektem wykonania tego szablonu może być następujący kod HTML:
            \begin{verbatim}<table>
    <tr>
        <td>1</td>
        <td>samochód</td>
        <td>4 metry</td>
    </tr>
    <tr>
        <td>2</td>
        <td>samolot</td>
        <td>15 metrów</td>
    </tr>
    <tr>
        <td>3</td>
        <td>statek</td>
        <td>50 metrów</td>
    </tr>
</table>\end{verbatim}

        \item[{\tt tal:replace}] - to wyrażenie TAL podobnie jak {\tt tal:content} zastępuje zawartość {\em tagu} zadaną wartością oraz jednocześnie nie wstawia tego {\em tagu}. Kod szablonu:
            \begin{verbatim}<h1 tal:replace="here/my_script">tekst</h1>\end{verbatim}
            jest równoznaczny z~kodem:
            \begin{verbatim}<h1 tal:content="here/my_script" tal:omit-tag="">
    tekst
</h1>\end{verbatim}
            i~daje w~wyniku:
            \begin{verbatim}wartość wykonania skryptu my_script\end{verbatim}
    \end{description}

    Jeżeli wewnątrz {\em taga} znajduje się więcej niż jedno wyrażenia TAL, to wykonywane są one według następującej kolejności: {\tt define}, {\tt condition}, {\tt repeat}, {\tt content} lub {\tt replace}, {\tt attributes}, {\tt omite-tag}.

    \subsubsection{METAL ({\em Macro Expansion Template Attribute Language})}
    
    {\em Macro Expansion Template Attribute Language} (METAL) jest rozszerzeniem jeżyka TAL o~zestaw makr ułatwiających powielanie tego samego kodu w~wielu szablonach. ,,Makra w~Zope umożliwiają stworzenie szablonu, który jest wykorzystywany przez inne szablony w~ten sposób, że wszystkie zmiany dokonane na szablonie źródłowym pojawiają się również w~szablonach z~niego korzystających. Rozwinięciem makr są sloty, które umożliwiają osadzanie fragmentu szablonu w~już zdefiniowanym makrze.''\cite{soft20e}
    
    Zasadę działania METAL najłatwiej pokazać na przykładzie. Stworzone zostały trzy szablony ZPT. Jeden jest szablonem bazowym, w~którym następuje definicja makra (poprzez wyrażenie {\tt metal:define-macro}). W~nim także zostanie zdefiniowany slot ({\tt metal:define-slot}). W~drugim szablonie konieczne jest użycie wyrażenia języka METAL informującego o~położeniu szablonu bazowego ({\tt metal:use-macro}) oraz kodu zawierającego {\em tag} z~atrybutem {\tt matel:fill-slot}. Cała zawartość obejmowana przez ten {\em tag} podczas interpretacji zostanie przetworzona i~wstawiona do szablonu bazowego, który również podlega interpretacji. Trzeci szablon zawiera definicję stopki, która zostaje dołączona w trakcie interpretacji szablonu bazowego.

    Przykładowy szablon bazowy (zapisany w~obiekcie o~nazwie ,,bazowy''):
    \begin{verbatim}<metal:page define-macro="base">
<!DOCTYPE html PUBLIC 
 "-//W3C//DTD XHTML 1.0 Strict//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:tal="http://xml.zope.org/namespaces/tal"
  xmlns:metal="http://xml.zope.org/namespaces/metal"
  lang="pl" xml:lang="pl">
<head>
    <title tal:content="template/title">title</title>
    <meta http-equiv="Content-Type"
     content="text/html; charset=utf-8" />
</head>

<body>
    <div metal:define-slot="main">
    </div>

    <div metal:use-macro="here/stopka/macros/footer">
    </div>
</body>
</html>
</metal:page>\end{verbatim}

    Makro opisujące budowę stopki zamieszczono w~osobnym szablonie o~nazwie ,,stopka'':
    \begin{verbatim}<div tal:omit-tag=""
 metal:define-macro="footer"
 style="font-size: 10px; text-align: center">
        Copyright &copy; 2007<br />
        Wojciech Lichota
        <a href="mailto:sargo@amu.edu.pl">
</div>\end{verbatim}

    Przykładowy szablon wykorzystujący makro zdefiniowane w~szablonie bazowym umieszczono w~obiekcie o~nazwie ,,przyklad'' (obiekt przechowujący ten szablon ustawioną ma wartość atrybutu {\em title} na ,,przykład''):
    \begin{verbatim}<html metal:use-macro="here/bazowy/macros/base">
    <body>
        <metal:main fill-slot="main">
            <p>
                zawartość jaka zostanie
                wstawiona do szablonu bazowego
            </p>
        </metal:main>
    </body>
</html>\end{verbatim}

    Rezultatem interpretacji szablonu ,,przyklad'' jest następujący kod XHTML:
    \begin{verbatim}<!DOCTYPE html PUBLIC 
 "-//W3C//DTD XHTML 1.0 Strict//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:tal="http://xml.zope.org/namespaces/tal"
  xmlns:metal="http://xml.zope.org/namespaces/metal"
  lang="pl" xml:lang="pl">
<head>
    <title>przykład</title>
    <meta http-equiv="Content-Type"
     content="text/html; charset=utf-8" />
</head>

<body>
    <div>
            <p>
                zawartość jaka zostanie
                wstawiona do szablonu bazowego
            </p>
    </div>

    <div style="font-size: 10px; text-align: center">
        Copyright &copy; 2007<br />
        Wojciech Lichota
        <a href="mailto:sargo@amu.edu.pl">
    </div>
</body>
</html>\end{verbatim}

    Jak można zauważyć powyższy przykład pokazuje, w~jaki sposób można tworzyć taki sam układ wszystkich podstron budowanej aplikacji internetowej. Dzięki wykorzystaniu makr METAL możliwy jest też podział dużych szablonów na mniejsze części ułatwiając przez to zarządzanie i~rozwijanie aplikacji. Możliwe jest także łatwe rozdzielenie pracy na większą ilość osób.

    \subsubsection{TALES ({\em Template Attribute Language Expression Syntax})}
    \label{tales}

    Składnia wyrażeń, jakie można przypisać do wartości atrybutów TAL, została nazwana {\em Template Attribute Language Expression Syntax} (TALES). Wyrażenia TALES są integralną częścią TAL i~nie można ich stosować poza wartościami atrybutów. Wewnątrz budowanych wyrażeń dostępne są zmienne zawierające różne dane. Oprócz wbudowanych zmiennych możliwe jest użycie zdefiniowanych (przy użyciu komendy {\tt tal:define}) wcześniej zmiennych. Poniżej przedstawiam opis wbudowanych zmiennych wraz z~przykładami ich wykorzystania:
    \begin{description}
	\item[{\em nothing}] - ,,wartość {\em false}, podobna do pustego stringu. Może być użyta z~{\tt tal:replace} lub {\tt tal:content} w~celu wymazania zawartości.''\cite{tzb26} Przykładowo użycie
	    \begin{verbatim}<p tal:content="nothing">tekst</p>\end{verbatim}
	    spowoduje wygenerowanie kodu
	    \begin{verbatim}<p></p>\end{verbatim}
	\item[{\em default}] - ,,specjalna wartość która nie wpływa na zmianę zawartości. Może być używana dla {\tt tal:replace}, {\tt tal:content} lub {\tt tal:attributes}.''\cite{tzb26} Na przykład:
	    \begin{verbatim}<a tal:attributes="href here/my_script | default"
    href="/link">opis linku</a>\end{verbatim}
	    spowoduje pozostawienie wartości {\em ,,/link''} dla atrybutu {\em href} w~przypadku gdy skrypt {\tt my\_script} zwróci wartość {\em false},
	\item[{\em options}] - używane tylko w~przypadku gdy przetwarzany jest szablon poprzez wywołanie z~poziomu skryptu w~języku Python wraz z~podanymi argumentami. Przykładowo, jeżeli wyrażeniem uruchamiającym interpretację szablonu ZPT było {\tt szablon(id=1)} to zmienna {\tt options/id} przyjmuje wartość 1,
	\item[{\em attrs}] jest słownikiem zawierającym atrybuty przypisane do {\em taga}, w~którym nastąpiło odczytanie tej zmiennej,
	\item[{\em root}] - wskazuje na obiekt głównego folderu serwera Zope. Dzięki tej zmiennej możliwe jest budowanie ścieżek bezwzględnych,
	\item[{\em here}] jest obiektem folderu w~którym znajduje się obiekt właśnie przetwarzanego szablonu. Służy do budowania ścieżej względnych,
	\item[{\em container}] - w~większości przypadków jest tym samym obiektem co {\em here}, przyjmuje natomiast inną wartość w~przypadku osadzenia szablonu wewnątrz innego obiektu nie będącego folderem (np. wewnątrz metody ZSQL),
	\item[{\em modules}] - określa zestaw możliwych do wykorzystania modułów języka Python,
	\item[{\em request}] - zawiera informacje przekazane w~żądaniu HTTP wysłanym przez przeglądarkę WWW użytkownika. Atrybutami obiekty {\em request} są nazwy parametrów jakie zostały podane w~URL (w przypadku gdy jest to żądanie typu GET) lub w~części dołączonej (w przypadku POST). Na przykład gdy szablon zostanie uruchomiony w~rezultacie otrzymania żądania zawierającego adres URL {\em http://filmobaza.pl/film?id=12\&user=wl} to obiekt {\em request} posiada dwa atrybuty: {\em id} o~wartości 12 i~atrybut {\em user} o~wartości {\tt wl}.
    \end{description}

    Wyrażenia możliwe do zbudowania przy użyciu TALES można podzielić na następujące grupy:
    \begin{description}
	\item[wyrażenia tekstowe] - (ang. {\em String Expressions}) służą do przygotowywania tekstu, który zostanie przekazany jako wartość dla atrybutów języka TAL. Wyrażenia tekstowe poprzedzane są przedrostkiem {\tt string:}. Dzięki zastosowaniu notacji ze znakiem \$ (dolara) możliwe jest proste wstawianie wartości zmiennych lub też wyników wykonania obiektów logiki. Na przykład:
	    \begin{verbatim}<p tal:content="string: wartość to $id">tekst</p>\end{verbatim}
	    po interpretacji zwróci kod:
	    \begin{verbatim}<p>wartość id to 12</p>\end{verbatim}
	    Jeżeli nazwa zmiennej jest bardziej rozbudowana lub też konieczne jest oddzielenie nazwy zmiennej od tekstu występującego od razu za nią, można pisać zmienną wewnątrz nawiasów klamrowych:
	    \begin{verbatim}<p tal:content="string: wynikiem jest
                ${here/my_script}"></p>\end{verbatim}
	    Podczas generowania kodu wynikowego uruchomiony będzie skrypt {\tt my\_script}, a~jego wynik połączony z~tekstem wpisanym do wyrażenia tekstowego. Zakładając, że wartość zwrócona przez skrypt równa się {\tt tekst}, to szablon zostanie przekształcony w: 
	    \begin{verbatim}<p>wynikiem jest tekst</p>\end{verbatim}

	\item[wyrażenia określające ścieżkę] - (ang. {\em Path Expressions}) ,,odnoszą się obiektów za pomocą ścieżek podobnych do ścieżek URL. Ścieżka opisuje sposób przemierzenia od obiektu do obiektu. Wszystkie ścieżki zaczynają się od znanego obiektu (takiego jak wbudowana zmienna, obiekt {\tt repeat} lub zmienna zadeklarowana przez użytkownika) i~wskazują drogę od tego miejsca do żądanego obiektu.''\cite{tzb26} Ścieżki mogą także wskazywać na podobiekty znajdujące się wewnątrz obiektów, np. na właściwości, makra lub metody.

	    Wyrażenie określające ścieżkę jest domyślnym wyrażeniem TALES dlatego też nie jest konieczne poprzedzanie go przedrostkiem {\tt path:}. 

	    Aby zapobiec występowaniu błędów podczas działania interpretera TAL w~przypadku gdy obiekt wskazywany przez ścieżkę nie istnieje można podać po znaku ,,|'' alternatywne wyrażenie, np.:
	    \begin{verbatim}<p tal:content="here/my_script | 
	                string: brak skryptu!"></p>\end{verbatim}
	    w~tym przypadku, jeżeli {\tt my\_script} nie zostanie odnaleziony powyższy kod zostanie przetworzony w~wyniku interpretacji na:
	    \begin{verbatim}<p>brak skryptu!</p>\end{verbatim}

	\item[zaprzeczenia] - (ang. {\em Not Expressions}) używane wraz z~{\tt tal:condition} służą do zaprzeczania wyrażenia znajdującego się po przedrostku {\tt not:}. W Zope zero, pusty ciąg znaków, pusta lista, {\tt nothing} oraz {\tt None} są uważane jako wartości fałszywe ({\rm false}), wszystkie pozostałe jako wartości prawdziwe ({\em true}). Wyrażenie {\tt not} zamienia {\em true} na {\em false} i~odwrotnie,

	\item[wyrażenia {\tt nocall}] - (ang. {\em Nocall Expressions}) używane jest podczas definiowania (przy użyciu {\tt tal:define}) zmiennych, których wartością ma być ścieżka, a~nie wynik wykonania obiektu wskazywanego przez tą ścieżkę. Konstruując wyrażenie należy je poprzedzić przedrostkiem {\tt nocall:}. Wykorzystywany jest głównie do skracania często używanych ścieżek, zapewnia to zwiększenie czytelności kodu. Patrząc na przykład:
	    \begin{verbatim}<span tal:define="funkcje nocall: 
  here/business_logic/scipts/aditional/functions">
    <p tal:content="funkcje/my_script"></p>            
</span>\end{verbatim}
	    można zauważyć, że interpreter ZPT uruchomi skrypt {\tt my\_script} dopiero podczas przetwarzania {\em tagu} {\tt <p>},

	\item[wyrażenia sprawdzające istnienie] - (ang. {\em Exists Expressions}) zwracają wartość prawdziwą ({\em true}) w~przypadku, gdy obiekt opisany podaną ścieżką istnieje, w~przeciwnym przypadku zwracają wartość fałszywą ({\em false}). Podaną ścieżkę należy poprzedzić przedrostkiem {\tt exists:}. Wykorzystywane jest głównie w~połączeniu z~{\tt tal:condition}. W~przypadku:
	    \begin{verbatim}<a tal:condition="exists: request/id"
   tal:attributes="href string: 
   /link?id=${request/id}">film</a>
<p tal:condition="not:exists: request/id">
    brak parametru
</p>\end{verbatim}
	    zostanie utworzony {\em tag} zawierający link tylko pod warunkiem, że został przekazany parametr {\tt id} w~żądaniu HTTP wysłanym przez przeglądarkę WWW użytkownika. W~przeciwnym przypadku zostanie wstawiony paragraf pokazujący komunikat o~braku parametru.

	\item[wyrażenia w~języku Python] - (ang. {\em Python Expressions}) rozpoczynają się od przedrostka {\tt python:}. Mogą zawierać większość wyrażeń języka Python, lecz ze względów bezpieczeństwa nie wszystkie. Głównym ograniczeniem jest zakaz zmieniania atrybutów obiektów Zope - możliwy jest tylko ich odczyt.
	    
	    Możliwości zastosowania jest bardzo dużo (np. wykonywanie prostych obliczeń, bardziej złożone przetwarzanie ciągów znaków, obsługa konwersji czasu). Używane są jednak najczęściej w~dwóch przypadkach: gdy potrzebne jest uruchomienie skryptu lub metody wraz z~podaniem argumentów oraz w~połączeniu z~{\tt tal:condition}, aby móc tworzyć bardziej rozbudowane warunki. 
	    
	    Język Python zawiera podstawowe metody porównań tj.:
	    \begin{verbatim}>, <, == , !=, and, or, not\end{verbatim}
	    W~tych ,,jednolinijkowcach'' możliwe jest wykorzystanie podstawowych funkcji wbudowanych w~język Python: {\tt abs}, {\tt apply}, {\tt callable}, {\tt chr}, {\tt cmp}, {\tt complex}, \linebreak {\tt delattr}, {\tt divmod}, {\tt filter}, {\tt float}, {\tt getattr}, {\tt hash}, {\tt hex}, {\tt int}, {\tt isinstance},\linebreak  {\tt issibclass}, {\tt list}, {\tt len}, {\tt long}, {\tt map}, {\tt max}, {\tt min}, {\tt oct}, {\tt ord}, {\tt repr}, {\tt round}, {\tt setattr}, {\tt str}, {\tt tuple}. Z~pewnymi ograniczeniami dostępne są także {\tt range} i~{\tt pow}. Dodatkowo możliwe jest użycie funkcji {\tt DataTime}, {\tt test} oraz {\tt same\_type}, które prawdzie nie są wbudowane w~język Python, ale są w~nim dostępne. Oprócz tego występują jeszcze funkcje dostępne tylko w~środowisku Zope tzn.: {\tt path}, {\tt string}, {\tt exists}, {\tt nocall} będące odpowiednikami innych wyrażeń TALES (patrz poprzednie punkty). Dokładny opis działania wymienionych powyżej funkcji dostępny jest w~dokumentacji języka Python (pod adresem {\tt http://python.org}).
	    
	    Oprócz wyrażeń logicznych i~funkcji, dostępne są także niektóre standardowe moduły: {\tt string}, {\tt random}, {\tt math}, {\tt sequence}. Można także wykorzystać moduły specyficzne dla środowiska Zope:
	    \begin{description}
		\item[{\em Products.PythonScripts.standard}] - ,,różnorodne funkcje formatujące HTML dostępne w~języku DTML,''\cite{tzb26}
		\item[{\em ZTUtils}] - mechanizmy przetwarzania wsadowego podobne do tych oferowanych przez {\tt dtml-in},
		\item[{\em AccessControl}] - mechanizmy pozwalające zarządzać zasadami dostępu do obiektów i~akcji.
	    \end{description}
    \end{description}

    \subsection{Skrypty w~języku Python}
    \label{zapi}
    
    Podczas budowy aplikacji internetowej w~Zope konieczne jest wprowadzenie podziału na obiekty prezentacji i~logiki. To właśnie obiekty logiki pozwalają na wykonywanie różnorodnych działań takich jak: zmiany innych obiektów, obliczenia na danych, sprawdzanie warunków itd. Obiekty prezentacji natomiast przedstawiają wyniki otrzymane z~wykonania obiektów logiki. Mimo, że w~ZPT możliwe jest wykonywanie prostych operacji dzięki wykorzystaniu składni TALES jest to niezalecane. W~języku TALES nie jest zresztą możliwe przeprowadzenie bardziej skomplikowanych działań. Dopiero skrypty będące osobnymi obiektami dają takie możliwości. 

    W~Zope wyróżnia się trzy podstawowe obiekty logiki: skrypty w~języku Python, metody zewnętrzne oraz metody ZSQL. Dwa ostatnie typy zostaną dokładnie opisane w~następnych podrozdziałach.

    Wyróżnia się parę sposobów na uruchomienie skryptu. Możliwe jest uruchomienie skryptu w~efekcie otrzymania przez Zope wywołania HTTP zawierającego adres skryptu. W~takim przypadku do przeglądarki WWW użytkownika, który wpisał taki link, zostanie wysłany wynik wykonania tego skryptu w~formie tekstu. Możliwe, lecz niezalecane, jest zwracanie przez obiekt logiki kodu HTML. Zope API a~więc zbiór funkcji i~obiektów dostępnych w~trakcie budowy skryptów nie został wyposażony w~usprawnienia ułatwiające generowanie kodu HTML. Zostało to zrobione specjalnie po to, aby zachęcić twórców aplikacji do prawidłowego rozdzielania prezentacji od logiki. 
    
    Zdecydowanie częściej występującym sposobem uruchomienia skryptu są wywołania z~szablonów ZPT lub z~innych skryptów. W~ZPT odwołanie do skryptu odbywa się poprzez stworzenie odpowiedniego wyrażenia w~języku TALES. Jeżeli konieczne jest tylko wywołanie skryptu (bez przekazywania do niego argumentów), to korzysta się z~wyrażeń określających ścieżkę (ang. {\em Path Expression}). W~przypadku kiedy konieczne jest przekazanie dodatkowych parametrów wywołanie odbywa się poprzez wyrażenie w~języku Python (ang. {\em Python Expression}). Dokładniejszy opis można znaleźć w~podrozdziale \ref{tales}. Uruchomienie obiektu logiki z~innego skryptu odbywa się poprzez podanie ścieżki dostępu do obiektu (ścieżka zaczyna się od {\tt context} podobnie jak od {\tt here} w~ZPT) oraz parametrów wykonania, np.:
    \begin{verbatim}context.get_comments(movie_id=movie_id)\end{verbatim}

    Python (czyt. {\em pajton}) jest ,,językiem bardzo wysokiego poziomu, posiada wbudowane typy danych wysokiego poziomu, jak rozszerzalne tablice i~słowniki. (\ldots) Język dostarczany jest z~obszernym zbiorem standardowych modułów, które mogą być podstawowymi składnikami twoich programów, lub służyć jako przykłady przy rozpoczęciu nauki programowania w~Pythonie. Istnieją również moduły wbudowane w~interpreter, mające na celu obsługę I/O, wywołań systemowych, gniazdek lub nawet moduły interfejsu użytkownika (GUI), jak np. Tk.'' \cite{pydoc}. Charakterystyczną cechą języka Python jest przejrzysta składnia. Bloki instrukcji grupuje się poprzez intendencje (wcinanie wierszy), a~nie poprzez klamry (znane choćby z~C/C++ czy Java) lub instrukcje {\tt begin} i~{\tt end} (tak jak w~Pascal-u lub Ruby). Język Python posiada jeszcze bardzo wiele udogodnień, pozwalających programistom skupić się na budowanie najważniejszych części programów a~nie na tworzeniu kodu pomocniczego.
	
    Prawidłowo zbudowany skrypt powinien zwracać (poprzez instrukcję {\tt return}) obiekt zawierający przetworzone dane. Przeważnie będzie to ciąg znaków (tzw. {\em string}). Zalecane jest także aby skrypt obsługiwał sytuacje wyjątkowe, jakie mogą wystąpić podczas uruchomienia. 
    
    Tworzenie nowego obiektu typu skrypt polega na wybraniu z~rozwijanej listy (która znajduje się w~widoku folderu, w~którym chcemy aby ten skrypt się znajdował) opcji {\em Script (Python)}. Następnie należy wybrać nazwę ({\em id}) nowo tworzonego skryptu. Po wykonaniu tych czynności pokazuje się okno edycji skryptu (patrz rys.~\ref{script}). Tu możliwe jest zdefiniowanie argumentów jakie może przyjmować tworzony skrypt. Argumenty wraz z~opcjonalnymi wartościami domyślnymi podaje się oddzielone przecinkami w~linii oznaczonej jako {\em Parameter List}.
	
	\begin{figure}
	    \includegraphics[width=15cm]{rys/script}
	    \caption[Okno edycji skryptu w~języku Python]{Okno edycji skryptu w~języku Python \newline \em{Źródło: opracowanie własne\hspace*{10cm}}}
	    \label{script}
	\end{figure}

	Pojedynczy obiekt skryptu w~języku Python jest równoznaczny z~definicją funkcji w~języku Python. Przykładowo skrypt o~nazwie {\tt get\_nick} posiadający argument {\tt uid} oraz kod:
	\begin{verbatim}user = context.get_user(user_id=uid).dictionaries()
if len(user) != 1:
  return ''
else:
  return user[0]['NICK']\end{verbatim} 
	jest jednoznaczny z~funkcją języka Python:
	\begin{verbatim}def get_nick(uid):
  user = context.get_user(user_id=uid).dictionaries()
  if len(user) != 1:
    return ''
  else:
    return user[0]['NICK']\end{verbatim}


	\subsubsection{Zope API}
	
	Podczas budowania skryptów w~języku Python nie jest możliwe pełne wykorzystanie możliwości tego języka. Ze względów bezpieczeństwa możliwe jest tylko wykorzystanie części funkcji, obiektów i~modułów. Zakres tych możliwości opisuje Zope API. Skrypty mogą zawierać podstawowe elementy języka Python, tj. pętle, instrukcje warunkowe, podstawowe struktury danych (np. listy, słowniki, krotki, literały itd.), operacje matematyczne i~logiczne oraz niektóre funkcje ({\tt abs}, {\tt apply}, {\tt callable}, {\tt chr}, {\tt cmp}, {\tt complex}, {\tt delattr}, {\tt divmod}, {\tt filter}, {\tt float}, {\tt getattr}, {\tt hash}, {\tt hex}, {\tt int}, {\tt isinstance}, {\tt issubclass}, {\tt list}, {\tt len}, {\tt long}, {\tt map}, {\tt max}, {\tt min}, {\tt oct}, {\tt ord}, {\tt repr}, {\tt round}, {\tt setattr}, {\tt str}, {\tt tuple}).
	
	Uruchomiony skrypt ma dostęp do podstawowych zmiennych. Dzięki tym zmiennym możliwe jest otrzymanie informacji o~stanie aktualnego wywołania skryptu, dostęp do innych obiektów lub do żądania HTTP. Te zmienne to:
	\begin{description}
	    \item[{\tt context}] - zmienna ta odnosi się do obiektu, który wywołuje dany skrypt. Przeważnie jest to szablon ZPT lub inny skrypt, z~którego nastąpiło wywołanie. Zmienna to posiada cechę {\tt REQUEST} dającą dostęp do żądania, jakie otrzymał serwer Zope od przeglądarki WWW klienta. Dokładniejszy opis został zawarty w~dalszej części rozdziału,
	    \item[{\tt container}] - zmienna wskazuje na obiekt przechowujący skrypt. Przeważnie jest to obiekt folderu zawierającego uruchomiony skrypt. Zmienna ta może być wykorzystana do budowania ścieżek względnych do innych obiektów,
	    \item[{\tt script}] - zmienna odnosi się do obiektu skryptu czyli do siebie samego. Może być użyty do kontroli właściwości przypisanych do skryptu,
	    \item[{\tt traverse\_subpath}] - zmienna zawiera część URL, jaki został podany po nazwie skryptu. Przykładowo jeżeli wywołano skrypt {\tt test} bezpośrednio z~przeglądarki WWW użytkownika używając adresu {\em http://filmobaza.pl/test/jakies/id}, to zmienna {\tt traverse\_subpath} jest listą zawierającą dwa elementy: {\tt jakies} oraz {\tt id}.
	\end{description}
	
	W~skład Zope API wchodzą moduły, dzięki którym możliwe jest kontrolowanie działania serwera aplikacji a~także wykonywanie bardziej złożonych operacji przez skrypty. Moduły te można podzielić na: dające dostęp do mechanizmów serwera Zope, odnoszące się do różnych typów obiektów, a~także moduły wywodzące się z~samego języka Python. W~modułach przeważnie znajdują się klasy a~także funkcje. Część wymienionych powyżej zmiennych dostępnych podczas przebiegu skryptu jest właśnie obiektami klas pochodzących z~tychże modułów.
	
	Moduły Zope API dostępne w~skryptach w~języku Python oraz w~wyrażeniach TALES szablonów ZPT to:
	\begin{description}
	    \item[{\tt AccessControll}] - zawiera funkcje i~klasy dotyczące zasad bezpieczeństwa. Najważniejszy element, czyli klasa {\tt SecurityManager}, dostarcza mechanizmy pozwalające na sprawdzanie i~zarządzanie prawami dostępu do różnych elementów środowiska,
	    \item[{\tt AuthenticatedUser}] - zawiera klasę o~takiej samej nazwie. Obiekty tej klasy używane są podczas wprowadzania zasad zabezpieczeń z~podziałem na różne klasy użytkowników,
	    \item[{\tt DTMLDocument}] - klasa o~nazwie {\tt DTMLDocument} znajdująca się w~tym module reprezentuje obiekty Zope zawierające dokumenty w~języku DTML. Zawiera metody: {\tt document\_src}, która zwraca zawartość dokumentu, {\tt manage\_edit} pozwalającą zmienić źródło dokumentu. Obiekt ten jest wykonywalny (uruchomienie tego obiektu powoduje interpretacje treści dokumentu). Utworzenie nowego obiektu tej klasy dokonuje się przy użyciu funkcji {\tt manage\_addDocument},
	    \item[{\tt DTMLMethod}] - moduł ten jest prawie identyczny do powyższego. Metoda DTML może posiadać dokładnie ten sam kod co dokument DTML. Rozróżniane jest jedynie zastosowanie tych dwóch obiektów. Dokument DTML należy do warstwy prezentacji i~powinien zawierać szablon dokumentów, a~więc wynikiem jego wykonania powinna być strona wysyłana do przeglądarki WWW użytkownika. Metoda DTML należy natomiast do warstwy logiki i~powinna generować obiekty, które będą wykorzystywane przez inne szablony. Implementuje metody {\tt manage\_edit} oraz {\tt document\_src}. Jest wykonywalny. Funkcja {\tt manage\_addDTMLMethod} tworzy nowy obiekt tej klasy,
	    \item[{\tt DataTime}] - zawiera klasę o~tej samej nazwie. Obiekty klasy {\tt DataTime} dostarczają mechanizmy pozwalające na pracę z~danymi opisującymi daty i~godziny w~różnych formatach. Zapewniają również współpracę z~kalendarzem a~także arytmetykę czasu. Przykładowy kod z~szablonu ZPT:
		\begin{verbatim}<h4>W Londynie jest w tej chwili:</h4>
<p tal:content="python: DateTime('GMT').rfc822()"></p>
<br>
<h4>W Warszawie jest  w tej chwili:</h4>
<p tal:content="python: DateTime('CEST').rfc822()"></p>\end{verbatim}
		spowoduje wyświetlenie strony zawierającej aktualny czas według uniwersalnej i~polskiej strefy czasowej,
	    \item[{\tt ExternalMethod}] - moduł zawiera klasę reprezentującą obiekty metod zewnętrznych. Dzięki metodzie {\tt manage\_edit} możliwe jest programowe zmienianie połączenia metody z~funkcją w~zewnętrznym pliku. Obiekty tej klasy tworzy {\tt manage\_addExternalMethod},
	    \item[{\tt File}] - obiekty klasa {\tt File} tworzone są przy użyciu {\tt manage\_addFile} i~odnoszą się do obiektów plikowych możliwych do składowania z~ZODB. Metoda {\tt update\_data} pozwala na zmianę zawartości obiektu,
	    \item[{\tt Folder}] - obiekty tej klasy tworzone są przez {\tt manage\_addFolder}. Są używane jako {\em kontenery}, czyli obiekty mogące zawierać inne obiekty,
	    \item[{\tt Image}] - podobny do {\tt File}. Zawiera metodę {\tt tag} zwracającą {\em tag} HTML powodujący wstawienie na stronie internetowej obrazka zawartego w~tym obiekcie,
	    \item[{\tt MailHost}] - moduł jest nakładką na protokół SMTP ({\em Simple Mail Transfer Protocol}) ułatwiającą wysyłanie listów elektronicznych,
	    \item[{\tt ObjectManager}] - moduł zawiera klasę bazową dla wszystkich obiektów mogących zawierać inne obiekty (tzw. obiekty {\em kontenerowe}). Zawiera {\tt manage\_addProduct} metodę konieczną do tworzenia nowych obiektów. Na przykład:
		\begin{verbatim}context.manage_addProduct['OFSP']. \
manage_addExternalMethod(id, title, module, function)\end{verbatim}
		powoduje dodanie do obecnego folderu nowej metody zewnętrznej,
	    \item[{\tt ObjectManagerItem}] - moduł ten zawiera klasę o~tej samej nazwie będącej klasą bazową dla wszystkich obiektów, które mogą być składowane w~obiektach {\em kontenerowych},
	    \item[{\tt PropertyManager}] - klasa {\tt PropertyManager} pośredniczy w~dostępie do właściwości obiektów (ang. {\em property}). Dostarcza między innymi funkcje {\tt propertyItem}, {\tt propertyValues}, {\tt propertyMap}, {\tt propertyIds} oraz najważniejsze {\tt getProperty} i~{\tt hasProperty},
	    \item[{\tt PropertySheet}] - klasa zawarta w~tym module daje dostęp do właściwości zorganizowanych w~większą całość. Przy użyciu {\tt getProperty}, {\tt manage\_delProperties}, {\tt manage\_changeProperties} oraz {\tt manage\_addProperty} odbywa się zarządzanie tymi atrybutami,
	    \item[{\tt PropertySheets}] - jest zbiorem obiektów typu {\tt PropertySheet} (patrz opis poprzedniego modułu),
	    \item[{\tt PythonScript}] - klasa o~tej samej nazwie wywodząca się z~tego modułu reprezentuje obiekty skryptów w~języku Python. Zawiera metody {\tt document\_src} oraz {\tt ZPythonScript\_edit} służące do pobierania i~zmieniania kodu skryptu. Ten wykonywalny obiekt jest tworzony przez funkcję {\tt manage\_addPythonScript},
	    \item[{\tt Request}] - moduł ten zawiera klasę {\tt Request}. ,,Obiekty tej klasy zawierają wszystkie informacje odnoszące się do aktualnego żądania w~Zope.'' \cite{tzb26} Zmienne zawarte w~tym obiekcie podzielone są na grupy: zmienne środowiskowe, dane formularzy, dane {\em cookie} oraz inne dane (np. dotyczące bieżącej sesji). Wszystkie te zmienne powinny być używane tylko do odczytu, ponieważ Zope nie ma wpływu na to jakie żądanie otrzymuje,
	    \item[{\tt Response}] - operacje na obiekcie (utworzonym z~klasy znajdującej się w~tym module) zmieniają nagłówek HTTP, który zostanie odesłany do przeglądarki WWW użytkownika w~wyniku przetwarzania żądania, jakie ten użytkownik przesłał. To tutaj możliwe jest dodawanie i/lub zmienianie danych, które zostaną zapisane na komputerze użytkownika w~plikach {\em cookie}. Najważniejsze metody tej klasy to: {\tt setHeader} oraz {\tt addHeader} zmieniają lub dodają do nagłówka parę {\em klucz-wartość}, {\tt setStatus} zmienia numeryczną wartość statusu HTTP wysyłanego żądania (wartości statusu określa specyfikacja protokołu HTTP, np. 404 elementu nie odnaleziono, 200 zakończono powodzeniem), {\tt setCookie} oraz {\tt appendCookie} tworzy nową parę {\em klucz-wartość}, która zostanie zachowana w~{\em cookie}, {\tt expireCookie} powoduje wysłanie wraz z~żądaniem, informacji kiedy program zarządzający plikami {\em cookie} ma usunąć dane pochodzące z~tego serwera, {\tt write} powoduje dołączenie do żądania strumienia danych, {\tt redirect} pozwala na wysłanie komendy nakazującej przeglądarce WWW pobranie strony z~innego adresu,
	    \item[{\tt Script}] - klasa z~tego modułu służy do budowy wszystkich wykonywalnych obiektów Zope,
	    \item[{\tt SessionInterfaces}] - moduł zawiera definicje klas, dzięki którym możliwe jest wymienianie danych między kolejnymi żądaniami HTTP od jednego użytkownika (ciąg takich wywołań nazywany jest sesją),
	    \item[{\tt TransienceInterfaces}] - zawiera klasy, które służą do budowy klas z~tymczasowymi danymi, np. z~danymi dotyczącymi sesji,
	    \item[{\tt UserFolder}] - klasa {\tt UserFolder} z~tego modułu implementuje mechanizmy pozwalające zarządzać obiektami skojarzonymi z~kontami użytkowników. Najważniejsze metody tej klasy to: {\tt userFolderEditUser} zmienia dane przypisane do istniejącego użytkownika, {\tt userFolderDelUser} usuwa użytkownika, a także {\tt userFolderAddUser} dodaje nowe konto, {\tt getUsers} zwraca listę wszystkich użytkowników, {\tt getUser} zwraca obiekt użytkownika,
	    \item[{\tt Vocabulary}] - moduł zawiera klasę służącą do przechowywania słów i~reguł językowych używanych przez różne moduły,
	    \item[{\tt ZCatalog}] - klasa o~tej samej nazwie co moduł. Umożliwia indeksowanie i~wyszukiwanie danych znajdujących się w~obiektach zgromadzonych w~ZODB,
	    \item[{\tt ZSQLMethod}] - klasa {\tt ZSQLMethod} z~tego modułu reprezentuje obiekty metod ZSQL. Przy użyciu funkcji {\tt manage\_edit} możliwa jest zmiana zachowania danej metody. Nowe obiekt są tworzone przy użyciu funkcji {\tt manage\_addZSQLMethod},
	    \item[{\tt ZTUtils}] - zawiera użyteczne klasy dodatkowe dostępne w~szablonach ZPT,
	    \item[{\tt math}] - moduł w~całości zapożyczony z~interpretera języka Python. Znajdują się tu funkcje matematyczne (np. trygonometryczne),
	    \item[{\tt random}] - ten moduł także w~całości został zapożyczony z~języka Python. Zapewnia pseudolosową generację liczb,
	    \item[{\tt sequence}] - w~tym module znajduje się funkcja {\tt sort} dzięki której możliwe jest sortowanie sekwencji,
	    \item[{\tt standard}] - moduł zawiera różnego rodzaju przydatne funkcje. Najważniejsze z~nich to: {\tt html\_quote}, {\tt url\_quote\_plus}, {\tt url\_quote}, {\tt sql\_quote}. Powodują one zamianę podanego tekstu na dane, które mogą zostać użyte podczas przesyłania w~różnym standardzie,
	    \item[{\tt string}] - moduł w~całości zapożyczony z~interpretera języka Python. Daje funkcje ułatwiające operacje na ciągach znaków,
	\end{description}

    \subsection{Metody zewnętrzne}
    \label{extmeth}
    
    Kiedy konieczne jest wykonanie operacji niedostępnych w~Zope API, należy wykorzystać do tego celu metody zewnętrzne (ang. {\em External Methods}). Tworzenie metod zewnętrznych polega na pisaniu funkcji języka Python. Funkcje te następnie należy umieścić w~pliku znajdującym się w~katalogu {\em Extensions} znajdującym się w~miejscu instalacji danej instancji serwera Zope (np. {\tt /var/lib/zope/fb/Extensions}). Gdy już plik fizycznie znajduje się w~odpowiednim miejscu systemu plików, należy utworzyć w~ZODB odpowiedni obiekt typu {\em External Method}. Podczas tworzenia tego obiektu należy podać nazwę funkcji, jaka ma być połączona z~tworzoną metodą zewnętrzną oraz nazwę pliku (bez rozszerzenia ''.py'') w~którym znajduje się ta funkcja (patrz rys.~\ref{extmethod}).
    
    \begin{figure}
	\includegraphics[width=15cm]{rys/extmethod}
	\caption[Tworzenie nowego obiektu typu metoda zewnętrzna]{Tworzenie nowego obiektu typu metoda zewnętrzna \newline \em{Źródło: opracowanie własne\hspace*{10cm}}}
	\label{extmethod}
    \end{figure}

    Metody zewnętrzne mają pełne możliwości języka Python, czyli przykładowo mogą otwierać i~zapisywać pliki. Na serwerze metoda zewnętrzna uruchomiona jest z~tymi samymi prawami co serwer aplikacji Zope. Co za tym idzie metoda zewnętrzna ma prawo do odczytu, a~także, co gorsze, do zapisu plików, w~których znajduje się ZODB. Wykorzystanie mechanizmu fizycznego umieszczania plików na dysku wprowadzono ze względów bezpieczeństwa. Dostęp do systemu plików odbywa się poprzez zewnętrzne protokołu (np. SSH lub FTP) nie związane z~Zope. Uprawnienia powierza się tylko najbardziej zaufanym administratorom. Tylko oni mogą tworzyć pliki zawierające metody zewnętrzne. W~przypadku, gdy ktoś nie mający takich uprawnień chciałby utworzyć moduł, który byłby źródłem metod zewnętrznych, musi zgłosić się do administracji serwera. Oni natomiast przed umieszczeniem takiego pliku dokonują audytu kodu, sprawdzając czy nie jest on potencjalnie niebezpieczny.
    
    Z~poziomu metod zewnętrznych możliwy jest także dostęp do obiektów znajdujących się w~bazie obiektów Zope. Odbywa się to poprzez argument {\tt self} który może być przekazywany jako pierwszy parametr wywołania funkcji. Zmienna {\tt self}, podobna jest do zmiennej {\tt context} dostępnej podczas uruchomienia skryptu w~języku Python. Następujący przykład pokazuje metodę zewnętrzną która pobiera z~ZODB treść szablonu ZPT i~zwraca jego zawartość bez {\em tagów} HTML:
    \begin{verbatim}def del_tags(self):
    import re
    data = self.index_html.document_src()
    return re.sub('<.+?>', '', data)\end{verbatim}
    Operacji tej nie można przeprowadzić w~skrypcie w~języku Python, ponieważ nie możliwe jest zaimportowanie modułu {\tt re} zawierającego operacje na wyrażeniach regularnych.
    
    Istnieją oczywiście także ograniczenia związane z~metodami zewnętrznymi. Najbardziej problematyczne jest przypisywanie obiektów własnoręcznie napisanych klas do właściwości obiektów znajdujących się w~ZODB. Inną niedogodnością może być używanie wątków w~metodach zewnętrznych. Należy także pamiętać o~czasie wykonania funkcji. Jeżeli jest on zbyt długi, przeglądarka WWW użytkownika może uznać, że straciła ona połączenie z~serwerem, co może zakłócić dalszą komunikację, a~jednocześnie powoduje u~użytkownika wrażenie dyskomfortu w~pracy z~aplikacją.

    \subsection{Współpraca z~relacyjnymi bazami danych}
    \label{zsql}
    
    Praktycznie każda z~obecnie budowanych aplikacji internetowych operuje na różnego rodzaju danych. W~przypadku gdy jest ich dość mało, możliwe jest przechowywanie wewnątrz ZODB (np. jako właściwości obiektów). Lecz kiedy ich objętość jest duża, konieczne jest wykorzystanie zewnętrznej bazy danych. Inną zaletą przeniesienia danych poza Zope jest zwolnienie obiektowej bazy danych Zope z~operacji, do których nie była optymalizowana. Nowoczesne relacyjne bazy danych oprócz zwykłego składowania danych oferują znacznie bardziej rozwinięte i~zoptymalizowane algorytmy wyszukiwania, sortowania i~przekształcania danych. 
    
    Komunikacja z~zewnętrzną bazą danych odbywa się poprzez sterownik (ang. {\em Database Adapter}). Domyślnie wraz z~Zope zainstalowany jest sterownik bazy Gadfly. Jest to prymitywna baza oferująca tylko podstawowe możliwości. Aby Zope mógł nawiązać połączenie z~innymi bazami potrzebne jest doinstalowanie odpowiedniej wtyczki. Wtyczki te można znaleźć na podstronie {\em products} strony domowej projektu Zope.
    
    Okno widoku obiektu będącego połączeniem z~bazą danych (typu {\em Database Connection}) posiada dwie bardzo przydatne zakładki. Zakładka {\em Test} pozwala na wydawanie pojedynczych zapytań SQL - przydatne na przykład podczas tworzenia tabel lub testowania poprawności zapytań przerabianych później na metody ZSQL. Inna zakładka {\em Browse} pozwala na przeglądanie struktury tabel podłączonej bazy danych. Jest to bardzo przydatne, gdy nad aplikacją internetową pracuje wielu użytkowników, a~osoba tworząca metody ZSQL nie tworzyła bazy danych.
    
    \begin{figure}
	\includegraphics[width=15cm]{rys/dbbrowse}
	\caption[Przeglądanie struktury tabel podłączonej bazy danych]{Przeglądanie struktury tabel podłączonej bazy danych \newline \em{Źródło: opracowanie własne\hspace*{10cm}}}
	\label{dbbrowse}
    \end{figure}
    
	\subsubsection{Baza danych {\em Gadfly}}
	
	Baza {\em Gadfly} została dołączona do Zope tylko dla celów demonstracyjnych i~dydaktycznych (można poćwiczyć pisanie metod ZSQL). Jest to baza posiadająca tylko podstawowe funkcje, całość działań przeprowadza w~pamięci, a~dane przechowuje w~ZODB, przez co jest mało funkcjonalna i~powolna. Przydatna jest jedynie w~początkowej fazie budowy aplikacji internetowej, kiedy wydajność nie jest ważna, a~liczy się mały nakład pracy potrzebny na stworzenie bazy.
	
	Baza danych Gadfly używa kodu {\em kjParsing} napisanego przez Aaron-a Waters-a. Jest to kod rozpowszechniany na zasadach wolnego oprogramowania.
	
	Utworzenie nowej bazy jest proste i~szybkie. Należy jedynie utworzyć nowy obiekt typu {\em Z~Gadfly Database Connection}. W~kolejnym kroku konieczne jest podanie nazwy tworzonego obiektu. Tak niewiele wystarczy do utworzenia pustej bazy danych. Dodanie tabel odbywa się poprzez wykonanie odpowiednich zapytań zgodnych ze składnią SQL. 

	\subsubsection{Baza danych {\em MySQL}}
	
	Kiedy budowa aplikacji internetowej zmierza ku końcowi, konieczna jest migracja na bardziej wydajny silnik bazodanowy. Czasami jest to konieczne już wcześniej, kiedy to okazuje się, że przydatne są niektóre właściwości, których baza Gadfly nie posiada. Jedną z~najpopularniejszych darmowych relacyjnych baz danych jest {\em MySQL}. Zyskała ona popularność dzięki wysokiej wydajności, a~także obszernej i~zrozumiałej dokumentacji. 
	
	Baza {\em MySQL} jest osobnym serwerem oferującym przechowywanie danych. Komunikacja z~bazą może odbywać się poprzez lokalny port Unix, jeżeli zarówno serwer Zope jak i~serwer {\em MySQL} uruchomione są na tym samym komputerze, działającym pod kontrolą systemu operacyjnego z~rodziny Unix lub Linux. Możliwe jest także komunikowanie się przy wykorzystaniu protokół TCP poprzez port 3306. Dzięki temu możliwe jest umieszczenie bazy danych na osobnym serwerze - co niesie zarówno korzyści jak i~zagrożenia. Korzyścią jest na pewno rozłożenie obciążenia na większą ilość komputerów, a~także oddelegowanie administracji do zewnętrznych dostawców (to oni dbają, aby serwer działał szybko i~bezpiecznie). Jednakże używanie zdalnej bazy danych może wiązać się z~wydłużeniem przesyłania danych lub też z~niebezpieczeństwem podsłuchu.
	
	Aby Zope mógł komunikować się z~bazą danych {\em MySQL}, konieczne jest zainstalowanie sterownika. Produktem oferującym ten sterownik jest {\em Zope MySQL Database Adapter} w~skrócie {\em ZMySQLDA}. Produkt ten można za darmo ściągnąć ze strony domowej projektu Zope ({\em http://zope.org}). Po zainstalowaniu tej wtyczki i~zresetowaniu serwera, na liście rozwijanej pokazującej spis możliwych do dodania obiektów, pojawi się {\em Z~MySQL Database Connection}. Podczas dodawania obiektu tego typu konieczne jest podanie tzw. {\em Database Connection String} czyli ciągu komend opisujących położenie bazy i~serwera SQL. {\em String} ten buduje się według schematu: {\tt [+/-]database[@host[:port]] [user [password [unix\_socket]]]}. Konieczne podanie jest tylko nazwy bazy danych. Opcjonalnie można podać nazwę zdalnego hosta i~port, a~także nazwę użytkownika i~hasło dające dostęp do serwera.

	\subsubsection{Metody ZSQL}

	Jeżeli w~budowanej aplikacji internetowej stworzone jest już połączenie z~zewnętrzną bazą danych, to dalsza komunikacja odbywa się poprzez metody ZSQL (ang. {\em Zope SQL Methods}). Metody te są połączeniem zapytań SQL z~wyrażeniami języka DTML. Metoda ZSQL może zawierać więcej niż tylko jedno zapytanie. 
	
	Działanie metod ZSQL przebiega w~trzech etapach. Na początku następuje interpretacja {\em tagów} języka DTML i~tworzone jest finalne zapytanie. Zapytanie to jest wysłane do serwera bazy danych. Ostatnią czynnością jest zamiana otrzymanych danych na obiekt, dzięki któremu operowanie tymi danymi jest łatwiejsze.
	
	Zapytania SQL dzielą się na dwie grupy - pytania (czyli takie, które nie wprowadzają zmian do bazy, tylko pobierają dane z~bazy) oraz zmiany (czyli takie, które nie pobierają żadnych danych, ale zmieniają dane znajdujące się w~bazie). Jeżeli zapytanie nie zwróciło żadnych danych to interpreter metod ZSQL stworzy obiekt nie zawierający danych (a~nie jak można by się spodziewać, nie zwróci nic).
	
	Podczas tworzenia nowego obiektu typu {\em Z~SQL Method} należy podać oprócz nazwy, listę argumentów oraz treść zapytania. Konieczne jest także wybranie z~listy jednego z~utworzonych wcześniej połączeń do zewnętrznej bazy danych (jak widać możliwa jest współpraca z~wieloma bazami danych naraz). Argumenty podaje się oddzielone spacjami. 
	
	\begin{figure}
	    \includegraphics[width=15cm]{rys/addzsql}
	    \caption[Tworzenie nowej metody ZSQL]{Tworzenie nowej metody ZSQL \newline \em{Źródło: opracowanie własne\hspace*{10cm}}}
	    \label{addzsql}
	\end{figure}

	W~kodzie pisanej metody ZSQL można użyć jednego z~trzech {\em tagów} języka DTML:
	\begin{description}
	    \item[{\tt dtml-sqlgroup}] jest {\em tagiem} który pozwala na tworzenie bloków instrukcji połączonych spójnikami {\tt and} lub {\tt or}. Wykorzystywany w~połączeniu z~{\tt dtml-sqltest} pozwala tworzyć rozbudowane instrukcje warunkowe. Na przykład gdy zmienne {\tt from} i~{\tt to} wynoszą odpowiednio 8 i~9 to metoda ZSQL:
		\begin{verbatim}SELECT * FROM movie
<dtml-sqlgroup WHERE>
  <dtml-sqltest form column="IMDB_RATING"
                op="gt" type="float">
<dtml-and>
  <dtml-sqltest to column="IMDB_RATING" 
                op="lt" type="float">
</dtml-sqlgroup>\end{verbatim}
		po interpretacji da zapytanie:
		\begin{verbatim}SELECT * FROM movie
WHERE
  (
    IMDB_RATING > 8.0
    and
    IMDB_RATING < 9.0
  )\end{verbatim}

	    \item[{\tt dtml-sqltest}] - służy do wstawiania do zapytań SQL instrukcji warunkowych. Możliwe jest opcjonalne dopisanie jednego z~parametrów: {\tt type} określający typ zmiennej, {\tt column} ustawia nazwę kolumny, wobec której będzie wykonywany test (domyślnie ustawiony jest na nazwę przekazywanej zmiennej), {\tt multiple} powiadamia, że przekazywana zmienna jest listą wartości, {\tt optional} nakazuje pominięcie wykonania {\em tagu} w~przypadku gdy zmienna nie istnieje bądź jest fałszywa (przyjmuje wartość {\em false}). Najważniejszym parametrem jest {\tt op} określający, jaka ma zostać wykonana operacja. Może on przyjmować jedną z~wartości określających typ działania: {\tt eq} (równy), {\tt gt} (większy niż), {\tt lt} (mniejszy niż), {\tt ne} (różny/nie równy), {\tt ge} (większy lub równy), {\tt le} (mniejszy lub równy) oraz {\tt like} powodujący wstawienie wyrażenia {\tt like} języka SQL. Przykład zastosowania {\tt dtml-sqltest} został podany podczas omawiania {\tt dtml-sqlgroup},
	    \item[{\tt dtml-sqlvar}] - powoduje wstawienie do zapytania wartości zmiennej podanej jako parametr. Opcjonalnie można podać typ na jaki ma być zamieniona zmienna (podstawowe typy to {\tt int}, {\tt float}, {\tt string} oraz {\tt nb} oznaczający string zawierający co najmniej jeden znak). Możliwe jest również wstawienie flagi {\tt optional} (w~takim przypadku zmienna zostanie wstawiona tylko wtedy, gdy istnieje i~jest prawdziwa (ma wartość {\em true})). Przykładowo metoda ZSQL:
		\begin{verbatim}SELECT * FROM movie
WHERE imdb_id=<dtml-sqlvar movie_id type=string>\end{verbatim}
		podczas interpretacji zostanie zamieniona na zapytanie SQL:
		\begin{verbatim}SELECT * FROM movie
WHERE imdb_id="0242653"\end{verbatim}
	\end{description}
    
	\subsubsection{Przetwarzanie danych pobranych z~bazy danych}
	
	Po wysłaniu zapytania SQL serwer zwraca wynik tego zapytania jako sekwencję linii danej tabeli pasujących do zadanego filtra. Interpreter metod ZSQL zamienia otrzymaną sekwencję na jeden obiekt - {\em Result object}. Obiekt ten może być przetwarzany zarówno w~skryptach języka Python, jak i~w~szablonach ZPT dzięki wyrażeniom języka Python oferowanym w~TALES.
	
	W~przykładach podanych poniżej, użyto metodę ZSQL {\tt get\_nicks\_by\_letter} (posiadającej argument {\tt nick}) o~następującej treści:
	\begin{verbatim}SELECT user_id, nick, join_time
FROM users
WHERE nick <dtml-sqltest nick op="like" type="string">\end{verbatim}
	Wykonanie tej metody (przy użyciu zakładki {\em Test}) wraz z~ustawieniem wartości argumentu {\tt nick} na {\tt s\%} daje stronę pokazaną na rys.~\ref{gnbl}.
	
	\begin{figure}
	    \includegraphics[width=8cm]{rys/gnbl}
	    \caption[Wynik wykonania przykładowej metody ZSQL]{Wynik wykonania przykładowej metody ZSQL \newline \em{Źródło: opracowanie własne\hspace*{10cm}}}
	    \label{gnbl}
	\end{figure}
	
	Stworzony został także prosty skrypt w~języku Python zawierający instrukcję:
	\begin{verbatim}result = context.get_nicks_by_letter(nick="s%")\end{verbatim}
	Tworzy on obiekt typu {\em Result object} o~nazwie {\tt result}.

	Dane zawarte w~zmiennej {\tt result} mogą być pobrane przy użyciu operacji wyboru elementu (funkcja {\tt \_\_getitem\_\_} z~języka Python). Rozpatrując przykład, instrukcja {\tt result[0][1]} zwróci wartość z~drugiej kolumny pierwszego wiersza (numeracja zaczyna się od zera) czyli {\tt sargo}. Funkcja {\tt len(result)} zwraca ilość linii wykonanego zapytania (w~tym przypadku będzie to liczba 6). Wynik zapytania może być także przekształcony na łatwiejsze w~obróbce struktury danych. Służą do tego następujące funkcje:
	\begin{description}
	    \item[{\tt tuples}] - zwraca listę krotek (ang. {\em tuple}). Każda z~krotek zawiera sekwencję wartości dla danej linii rezultatu wykonania zapytania. W~omawianym przykładzie dopisanie do skryptu linii:
		\begin{verbatim}return result.tuples()\end{verbatim}
		spowoduje zwrócenie następującej struktury:
		\begin{verbatim}[(1L, 'sargo', '1152300000'),
 (10L, 'siwy43', '1153560411'),
 (23L, 'stalkerama', '1155511008'),
 (60L, 'Slygado', '1169976168'),
 (65L, 'sipciak', '1171966862'),
 (80L, 'sendi', '1173027126')]\end{verbatim}

	    \item[{\tt dictionaries}] - zwraca listę słowników. Każdy linia rezultatu jest zamieniana na słownik, w~którym kluczami są nazwy kolumn wraz z~przyporządkowanymi im wartościami danej kolumny. Dopisanie funkcji:
		\begin{verbatim}return result.dictionaries()\end{verbatim}
		do rozpatrywanego przykładu spowoduje zwrócenie następującej struktury:
		\begin{verbatim}[{'nick': 'sargo', 'user_id': 1L,
  'join_time': '1152300000'},
 {'nick': 'siwy43', 'user_id': 10L, 
  'join_time': '1153560411'},
 {'nick': 'stalkerama', 'user_id': 23L,
  'join_time': '1155511008'},
 {'nick': 'Slygado', 'user_id': 60L,
  'join_time': '1169976168'},
 {'nick': 'sipciak', 'user_id': 65L,
  'join_time': '1171966862'},
 {'nick': 'sendi', 'user_id': 80L,
  'join_time': '1173027126'}]\end{verbatim}

	    \item[{\tt asRDB}] - pokazuje dane w~sposób bardzo podobny do tego, jak serwer bazy danych wysyła rezultat do Zope. W~kolejnych liniach znajdują się wartości oddzielone tabulatorem. W~omawianym przypadku będzie to:
		\begin{verbatim}user_id	nick	join_time
2l	10t	10t
1	sargo	1152300000
10	siwy43	1153560411
23	stalkerama	1155511008
60	Slygado	1169976168
65	sipciak	1171966862
80	sendi	1173027126\end{verbatim}

	\end{description}
	
	Obiekt {\tt result} posiada jeszcze dwie bardzo przydatne funkcje. Wykonanie funkcji {\tt names} da w~wyniku listę zawierającą nazwy kolumn. Natomiast {\tt data\_dictionary} zwraca słownik, w~którym skojarzone zostały nazwy kolumn ze słownikami zawierającymi opis ich właściwości (np. rozmiar, typ). Rozpatrywany przykład da następujący słownik:
		\begin{verbatim}{'nick': {'width': 10, 'null': 1, 'type': 't', 
          'name': 'nick'},
 'user_id': {'width': 2, 'null': 0, 'type': 'l', 
             'name': 'user_id'},
 'join_time': {'width': 10, 'null': 1, 'type': 't', 
               'name': 'join_time'}}\end{verbatim}


\section{Biblioteki wykorzystywane przez FilmoBazę}

Podczas budowy aplikacji internetowej, dzięki której utrwalałem nabytą wiedzę o Zope, wykorzystywałem różnego rodzaju biblioteki oraz techniki wspomagające tworzenie. Aby móc w~pełni zrozumieć, w~jaki sposób działa stworzony przeze mnie projekt - FilmoBaza (dokładny opis znajduje się w~rozdziale \ref{fb}), konieczne jest zapoznanie się z~tymi zagadnieniami.

    \subsection{Wykorzystanie AJAX do tworzenia interfejsu użytkownika}

    Asynchroniczny JavaScript i XML (ang. {\em Asynchronous JavaScript and XML}), czyli w skrócie AJAX jest zbiorem technik (np. XHTML, XMLHttpRequest). Jednoczesne ich wykorzystanie służy do budowy aplikacji internetowych, o interfejsie aktualizowanym przyrostowo. Tradycyjne podejście do budowy graficznego interfejsu użytkownika poprzez WWW charakteryzuje się tym, że każda interakcja użytkownika powoduje wygenerowanie przez serwer aplikacji dokumentu HTML (lub XHTML), który to zostaje odesłany do użytkownika, a następnie jest wyświetlony przez jego przeglądarkę WWW. W przypadku gdy wykorzystywany jest AJAX, nie jest konieczne generowanie całego dokumentu lecz tylko tych fragmentów strony, które są różny względem poprzedniego widoku.

	\subsubsection{Zalety i wady płynące z wykorzystania AJAX}

	Wykorzystanie AJAX przynosi wiele korzyści. Najważniejszą z nich jest zwiększenie komfortu używania aplikacji internetowej przez użytkowników. Dzieje się tak dlatego, że interfejs zachowuje się bardzo podobnie do interfejsu zwykłego programu komputerowego, a nie jak strona internetowa. Ponieważ po każdej interakcji użytkownika nie następuje odświeżenie całej strony lecz tylko jej części, operacja ta wykonywana jest szybciej, co dodatkowo punktuje na korzyść AJAX. Przesyłanie przez sieć tylko przyrostów przyczynia się do obniżenia wykorzystania przepustowości łącz serwera i użytkowników, a co za tym idzie na zmniejszenie kosztów utrzymania serwera. Serwer aplikacji przystosowany do generowania tylko fragmentów ulegających zmianie, zwolniony jest także z dodatkowych obliczeń. Nie jest więc konieczne inwestowanie w najnowszy sprzęt komputerowy. 

	Należy jednak także zauważyć pewne niedogodności płynące z używania AJAX. Obecne przeglądarki internetowe nie potrafią odwrócić pojedynczej zmiany w interfejsie. Kliknięcia przez użytkownika przycisku ,,Wstecz'' powoduje cofnięcie wszystkich przyrostów utworzonych przez AJAX. To zachowanie może prowadzić do irytacji nieobeznanych z tą techniką użytkowników. Podobną wadą wynikającą z nieprzystosowania przeglądarek jest to, że wyświetlany przez nie adres odnosi się tylko do pierwotnej strony (bez naniesionych przyrostów). Tak więc zapisanie linku (np. w ulubionych) lub przesłanie go do innej osoby spowoduje, że wskazywać on będzie na nie tą stronę, której użytkownik oczekiwał. Strony zbudowane w oparciu o technikę AJAX są trudne lub wręcz niemożliwe do pełnego zindeksowania (przejrzenia) przez roboty wyszukiwarek internetowych, a co za tym idzie wypozycjonowanie strony jest utrudnione lub niemożliwe. Wyjściem z tej sytuacji jest równoległe tworzenie klasycznego interfejsu pokazywanego robotom, lecz jest to dodatkowy nakład pracy.
    
	Wykorzystanie AJAX może także przyczynić się do zmiany jakości statystyk. Kiedy aplikacja internetowa oparta o technikę AJAX wykorzystuje gotowe narzędzia do zliczania osób odwiedzających stronę i ich zachowania, to uzyskiwane są niepełne wyniki, ponieważ zbierane są tylko dane o stronach generowanych klasycznie. Jest to niewątpliwie wadą. Dzięki dość niewielkiemu nakładowi pracy można jednak obrócić tą sytuację na swoją korzyść. Jeżeli aplikacja internetowa jak i serwer aplikacji zostanie przystosowany do zbierania informacji o wszystkich interakcjach wykonywanych przez użytkownika, możliwe jest zbieranie o wiele większej ilości danych niż robią to gotowe narzędzia statystyczne. Możliwe jest wierniejsze prześledzenie, w jaki sposób użytkownicy wykorzystują dostępne opcje, a co za tym idzie możliwe jest takie przystosowanie aplikacji aby lepiej odpowiadała ich oczekiwaniom.

	\subsubsection{Zasada tworzenia interfejsu przy wykorzystaniu AJAX}

	Aby móc budować strony w oparciu o technikę AJAX konieczne jest, aby użytkownik tworzonej aplikacji internetowej używał nowoczesnej przeglądarki WWW. W przeglądarce takiej dodatkowo musi być włączona obsługa skryptów w języku JavaScript. Jest to konieczne, ponieważ jednym z najważniejszych technologii wykorzystywanych w AJAX jest {\em XMLHttpRequest}. {\em XMLHttpRequest} jest biblioteką pozwalającą skryptom JavaScript na ściąganie z internetu danych.

	Budowanie aplikacji internetowej z interfejsem opartym o technikę AJAX w większości przypadków rozpoczyna się od tworzenia jej w sposób klasyczny. Do zbudowanych w~ten sposób dokumentów HTML lub szablonów je generujących wstawia się instrukcje, które mają dwa zadania. Po pierwsze konieczne jest oznaczenie miejsc w dokumencie, do których będą wstawiane przyrosty. Po drugie należy zapewnić obsługę interakcji użytkownika.

	Miejsca stron, w których mają pojawiać się przyrostowe zmiany dosyłane w trakcie używania interfejsu opartego o AJAX, należy oznaczyć poprzez nadanie im identyfikatorów. Operacja ta polega na dopisaniu atrybutu {\tt id} do tagów języka HTML (lub XHTML). W zdecydowanej większości przypadków wykorzystywane są tagi rozciągające się na większą część dokumentu (np. {\tt <span>}, {\tt <div>}, {\tt <p>}).

	Do obsługi zdarzeń, jakie może wywoływać użytkownik budowanej aplikacji, wykorzystywany jest JavaScript. Najczęstszą interakcją jest kliknięcie myszą. Aby dodać obsługę tego zdarzenia należy dopisać do {\em tagu} opisującego element aktywny strony (np. link, przycisk) instrukcję:
	\begin{verbatim}onClick="nazwa_funkcji()"\end{verbatim}
	Najważniejszą częścią umożliwiającą działanie całości jest właśnie ta wywoływana funkcja. 

	Znając te najważniejsze elementy można prześledzić działanie wszystkich elementów obsługujących aplikację internetową działającą na zasadach AJAX.
	\begin{enumerate}
	    \item Gdy nastąpi zdarzenie wywołane interakcją użytkownika, serwer aplikacji przygotowuje stronę bazową zawierającą {\em tagi} oznaczone przez identyfikatory oraz instrukcje powodujące wywołanie funkcji JavaScript.
	    \item Przeglądarka WWW wyświetla otrzymany dokument jak zwykłą stronę.
	    \item Użytkownik wykonuje interakcję, na przykład klika element aktywny.
	    \item Przeglądarka uruchamia funkcję, która przy użyciu {\em XMLHttpRequest} łączy się z serwerem aplikacji i przesyła do niego: albo żądanie konkretnego fragmentu strony albo wysyła opis zdarzenia, jakie wykonał użytkownik. Jeżeli wysyłany jest opis zdarzenia, serwer aplikacji ma możliwość zapamiętywania działań użytkownika i tworzenie dokładnych statystyk. Gdy wysyłane są sprecyzowane żądania to zwiększa się ilość operacji po stronie klienta, a zmniejsza po stronie serwera.
	    \item Na podstawie tych danych serwer aplikacji przygotowuje fragment kodu HTML, o jaki różni się strona pierwotna od strony, jaka ma się ukazać. Serwer aplikacji do budowy przyrostów może wykorzystywać oddzielne szablony lub też generować nową stronę klasycznie. Może też wyłapywać różnice na podstawie porównania z widokiem pierwotnym, zachowanym wcześniej przy użyciu metody rozpoznawania sesji. Pierwsze podejście przyczynia się do zwiększenia nakładu pracy, jaką muszą wykonać twórcy aplikacji, drugie natomiast powoduje zwiększenie wykorzystywanej pamięci i ilości operacji jakie musi wykonać serwer aplikacji.
	    \item Funkcja odbiera od serwera ten przyrostowy kod i wstawia go w miejsce oznaczone odpowiednim identyfikatorem.
	    \item Przeglądarka WWW odświeża widok tej części strony, która uległa zmianie.
	\end{enumerate}

	Aby ułatwić twórcom aplikacji internetowych tworzenie funkcji w języku JavaScript przydatnych przy budowaniu interfejsu AJAX zostały stworzone specjalne biblioteki. Podczas tworzenia aplikacji internetowej opisywanej w dalszej części tej pracy magisterskiej wykorzystałem bibliotekę {\em Prototype} w wersji 1.4.0. {\em Framework} ten jest skryptem o otwartym kodzie źródłowym dostępnym na zasadach licencji MIT. Strona internetowa tego projektu znajduje się pod adresem \\ {\em http://www.prototypejs.org/}.


    \subsection{{\em Google SOAP Search API} i~{\em PyGoogle}}
    
    Wyszukiwarka {\em Google} jest największą wyszukiwarką internetową. {\em Google} zindeksował do tej pory ponad 8 miliardów stron internetowych (stan na luty 2005 roku). Dzięki prostocie i~szybkości działania oraz, co chyba najważniejsze, celności wyszukiwania jest także najczęściej używaną wyszukiwarką.
    
    {\em Google Inc.}, właściciel opisywanej wyszukiwarki udostępnił interfejs o~nazwie {\em Google SOAP Search API}, dzięki któremu możliwe jest wykorzystanie potencjału wyszukiwarki {\em Google} w~budowanych przez siebie programach. Zasada działania polega na tym, że poprzez protokół SOAP ({\em Simple Object Access Protocol}) wysyłane jest zapytanie, natomiast w~odpowiedzi otrzymywany jest dokument w~formacie XML zawierający wszystkie te wyniki, które zawierała by strona HTML, gdyby przesłano to samo zapytanie przy użyciu protokołu HTTP. Rozwiązanie takie jest korzystniejsze, ponieważ przetwarzanie dokumentów XML jest o~wiele prostsze i~efektywniejsze. Inną zaletą jest ograniczenie przesyłanych danych, ponieważ nie przysyłany jest opis wyglądu strony lecz ,,czysta'' informacja.
    
    Aby móc skorzystać z~{\em Google SOAP Search API} konieczne jest zarejestrowanie konta na stronie internetowej {\em http://code.google.com/apis/soapsearch/}, w~wyniku czego dostanie się unikalny ciąg znaków (klucz). Dopiero wtedy możliwy jest dostęp do tego interfejsu. 
    
    Aby ułatwić używanie {\em Google SOAP Search API} podczas pisania programów w~języku Python została stworzona biblioteka o~nazwie {\em PyGoogle} (więcej informacji na stronie {\em http://pygoogle.sourceforge.net/}). Dzięki temu modułowi wyszukiwanie przy użyciu narzędzia udostępnionego przez {\em Google} redukuje się do niewielkiej ilości instrukcji, np.:
    \begin{verbatim}import google
google.setLicense('32 znakowy klucz')
data = google.doGoogleSearch('the godfather')\end{verbatim}
    Po wykonaniu tego programu zmienna {\tt data} jest strukturą składającą się z~dwóch części: {\tt meta} zawierającej informacje na temat procesu wyszukiwania (np. czas wyszukiwania, proponowana zmiana frazy, przybliżona ilość możliwych wyników) oraz z~{\tt result} będącej listą otrzymanych wyników na zapytanie (w~tym przypadku {\em the godfather}). Każdy z~otrzymanych elementów listy zawiera pola charakteryzujące znalezioną stronę. Najważniejsze z~tych pól to: {\tt URL} - zawierający adres do znalezionej strony, {\tt title} - tytuł znalezionej strony, {\tt snippet} - cytat ze strony z~wynikiem zawierający całą bądź część frazy.Tak więc w~rozpatrywanym przypadku uruchomienie następujących funkcji:
    \begin{verbatim}print data.results[0].URL
print data.results[0].title
print data.results[0].snippet\end{verbatim}
    spowoduje wyświetlenie informacji o~stronie najlepiej pasującej do frazy {\em the godfather}, czyli:
    \begin{verbatim}http://www.imdb.com/title/tt0068646/
<b>The Godfather</b> (1972)
<b>The Godfather</b> on IMDb: Movies, TV, Celebs, and more...\end{verbatim}

    \subsection{{\em IMDbPy}}
    
    Podobny zestaw ułatwień co {\em PyGoogle} oferuje inna biblioteka języka Python, a~mianowicie {\em IMDbPy}. Dzięki temu modułowi uproszczony jest sposób na pobieranie informacji, jakie zawiera IMDb, czyli jeden z~największych internetowych serwisów o~filmach. Zestaw instrukcji, jakie znajdują się w~tej bibliotece działa na zasadzie parsera HTML. Po wydaniu komendy znalezienia informacji o~zadanym filmie bądź osobie (aktorze, reżyserze lub postaci filmowej) następuje pobranie z~internetu odpowiedniej podstrony (czasami więcej niż jednej) serwisu IMDb zawierającej te informacje. Tak uzyskany kod HTML jest parsowany przy użyciu wbudowanego w~język Python parsera. Wszystkie uzyskane dane w~wyniku tych operacji umieszczane są w~strukturze, którą osoba tworząca oprogramowanie z~użyciem biblioteki {\em IMDbPy} może wykorzystać do własnych zadań. Cały ten dość skomplikowany proces zawarty jest w~paru instrukcjach:
    \begin{verbatim}import imdb
data = imdb.IMDb().get_movie('0068646')\end{verbatim}
    Po wykonaniu tych dwóch linii kodu w~zmiennej {\tt data} znajduje się struktura zawierająca dane pobrane z~serwisu IMDb dotyczące filmu ,,Ojciec chrzestny''. Argumentem funkcji {\tt get\_movie} jest identyfikator filmu. Numer ten może być także znaleziony przy użyciu opisywanej biblioteki przy użyciu funkcji {\tt search\_movie} lub {\tt title2imdbID}. Otrzymana w~wyniku powyższego przykładu struktura zawiera zestaw funkcji, dzięki którym ułatwiony jest dostęp i~przetwarzanie danych. Jedną z~takich funkcji jest {\tt summary}, która powoduje zwrócenie tekstowego podsumowania filmu zawierającego najważniejsze dane. W~omawianym przypadku wykonanie instrukcji:
    \begin{verbatim}print data.summary()\end{verbatim}
    spowoduje następujący wydruk:
    \begin{verbatim}Movie
=====
Title: The Godfather (1972)
Genres: Crime, Drama.Director: Francis Ford Coppola.
Writer: Mario Puzo, Mario Puzo, Francis Ford Coppola.
Cast: Marlon Brando (Don Vito Corleone), Al Pacino (Michael
Corleone), James Caan (Santino 'Sonny' Corleone), Richard
S. Castellano (Pete Clemenza), Robert Duvall (Tom Hagen).
Runtime: 175.
Country: USA.
Language: English, Italian, Latin.
Rating: 9.1(212263 votes).
Plot: The story begins as "Don" Vito Corleone, the head of a
(...)
especially from Michael, all for the sake of the family.\end{verbatim}
    Dzięki funkcjom {\tt \_\_getitem\_\_}, {\tt has\_key}, {\tt keys}, {\tt values} możliwe jest używanie tej struktury jak słownika (jednej z~podstawowych struktur języka Python). Słownik (w innych języka programowania nazywany tablicą z~hashem (ang. {\em hash table})) zawiera następujące pary {\em klucz-wartość}:
    \begin{description}
	\item[{\tt akas}] - inne tytuły filmu,
	\item[{\tt cast}] - obsada filmu,
	\item[{\tt cinematographer}] - operatorzy kamer,
	\item[{\tt color info}] - informacja o~rodzaju taśmy filmowej,
	\item[{\tt composer}] - twórcy muzyki,
	\item[{\tt costume designer}] - twórcy kostiumów,
	\item[{\tt countries}] - nazwy krajów, w~których był kręcony film lub które są współproducentami filmu,
	\item[{\tt cover url}] - adres internetowy pod którym znajduje się okładka lub poster danego filmu,
	\item[{\tt director}] - reżyserowie filmu,
	\item[{\tt distributors}] - nazwy firm, które zajęły się dystrybucją filmu,
	\item[{\tt genres}] - lista nazw gatunków, które pasują do opisywanego filmu,
	\item[{\tt languages}] - języki, w~jakich wypowiadane są kwestie aktorów,
	\item[{\tt make up}] - osoby robiące charakteryzację,
	\item[{\tt miscellaneous crew}] - inne osoby współtworzące film,
	\item[{\tt plot}] - streszczenie lub opis wprowadzający,
	\item[{\tt plot outline}] - hasło reklamowe opisujące film,
	\item[{\tt producer}] - producenci filmu,
	\item[{\tt rating}] - średnia ocena filmu wydana przez użytkowników serwisu IMDb,
	\item[{\tt runtimes}] - długość filmu w~minutach,
	\item[{\tt set decorator}] - twórcy dekoracji,
	\item[{\tt sound crew}] - osoby odpowiedzialne za dźwięk,
	\item[{\tt special effects}] - twórcy efektów specjalnych,
	\item[{\tt stunt performer}] - osoby nadzorujące kaskaderów,
	\item[{\tt title}] - tytuł filmu,
	\item[{\tt votes}] - ilość użytkowników IMDb oceniających film,
	\item[{\tt writer}] - twórcy scenariusza,
	\item[{\tt year}] - rok, w~którym film miał swoją premierę.
    \end{description}
    Większość z~danych osiągalnych poprzez wymienione powyżej klucze jest listami. Jeżeli film robiony był przez jednego reżysera to lista będzie zawierała jeden element, lecz dalej będzie to lista. Jak można łatwo zauważyć spora część informacji odnosi się do osób uczestniczących w~filmie bądź w~jego tworzeniu. W~tego typu wartościach opisywanego słownika znajdują się struktury zawierające opis danej osoby. Opis tej struktury najłatwiej można pokazać na przykładzie pierwszego aktora wymienionego w~obsadzie przykładowego filmu:
    \begin{verbatim}actor = data['cast'][0]
print actor['name']
print actor.getID()
print actor.currentRole\end{verbatim}
    Otrzymana struktura przypisana do zmiennej {\tt actor} zawiera oczywiście imię i~nazwisko tej osoby, a~także numer identyfikacyjny w~serwisie IMDb oraz nazwę postaci, jaką gra w~danym filmie. Wykonanie powyższego kodu spowoduje następujący wydruk:
    \begin{verbatim}Marlon Brando
0000008
Don Vito Corleone\end{verbatim}

    \subsection{Używanie wyrażeń regularnych w~języku Python}

    Podczas tworzenia aplikacji internetowej opisywanej w~dalszej części tej pracy magisterskiej często wykorzystywane były wyrażenia regularne (ang. {\em regular expressions}, w~skrócie {\em RE} lub {\em regex}). Wyrażeniem regularnym nazywa się ciąg symboli, które opisują uogólnienie ciągów znaków. Podstawowym wykorzystaniem RE jest stwierdzanie, czy podany ciąg znaków pasuje do zadanego wyrażenia. Bardziej rozbudowanym zadaniem jest znalezienie wszystkich podciagów zadanego ciągu znaków (np. tekstu) pasujących do podanego wzorca. W~niniejszym podrozdziale nie będę opisywał składni wyrażeń, lecz w~jaki sposób używa się ich podczas tworzenia programów w~języku Python. Robię tak dlatego, że zagadnienie wyrażeń regularnych jest bardzo obszerne, a~jednocześnie mało związane z~tematyką tego opracowania.

    Obsługa wyrażeń regularnych w~języku Python została zaimplementowana w~bibliotece standardowej, czyli zestawie modułów instalowanych wraz z~interpreterem języka Python. Moduł odpowiedzialny za tego typu operacje nazwany został {\tt re}. Tak więc każdy kod, w~którym mają być wykorzystywane wyrażenia regularne musi być poprzedzony instrukcją importującą ten moduł ({\tt import re}). Najczęściej wykorzystywane funkcje modułu {\tt re} to:
    \begin{description}
	\item[{\tt compile}] - powoduje zwrócenie obiektu zawierającego skompilowane RE. Kompilacja konieczna jest przed każdą z~operacji na wyrażeniu. Jeżeli zadane wyrażenie regularne wykorzystane będzie tylko raz podczas działania programu, nie jest konieczne samodzielne jego kompilowanie, ponieważ moduł sam je przetworzy, gdy będzie tego potrzebował. Jeżeli jednak używane będzie wielokrotnie, zalecane jest jego wcześniejsze przekompilowanie i~zachowanie po to, aby moduł nie musiał robić tego co każdą operację na wyrażeniu. Dzięki temu omijane jest wykonywanie tej samej operacji wielokrotnie,
	\item[{\tt match}] - powoduje sprawdzenie, czy pierwsze znaki z~podanego ciąg pasują do zadanego wzorca. Funkcja ta daje takie same wyniki jak {\tt search}, gdy wzorzec przekazywany do tej drugiej poprzedzony jest instrukcją \verb*#^#. Zalecane jest jednak używanie funkcji {\tt match}, kiedy konieczne jest sprawdzanie początku zadanego ciągu znaków, ponieważ jest to rozwiązanie szybsze. Funkcja zwraca obiekt typu {\em MatchObject},
	\item[{\tt search}] - wynikiem wykonania tej funkcji jest także obiekt typu {\em MatchObject}, jeżeli w~podanym ciągu znaków znajduje się podciąg pasujący do zadanego wyrażenia regularnego. W~przeciwnym przypadku zwracany jest obiekt pusty ({\tt None}). Przeszukiwanie kończy się od razu po znalezieniu pierwszego pasującego podciągu,
	\item[{\tt findall}] - zwraca listę grup dla wszystkich znalezionych ciągów pasujących do zadanego wzorca,
	\item[{\tt sub}] - powoduje zamienienie tekstu pasującego do wzorca na podany tekst. Przykładowo instrukcja:
	\begin{verbatim}content = re.sub('<.+>', ' ', html_code)\end{verbatim} 
	powoduje usunięcie wszystkich {\em tagów} języka HTML z~podanego tekstu, a~więc zmienna {\tt content} zawierać będzie samą zawartość dokumentu bez instrukcji formatujących.
    \end{description}

    Obiekt typu {\em MatchObject} jest strukturą zawierającą między innymi następujące funkcje:
    \begin{description}
	\item[{\tt start}] - podaje numer znaku podanego ciągu, w~którym zaczyna się podciąg pasujący do zadanego wzorca,
	\item[{\tt end}] - podaje numer znaku następującego po znalezionym podciągu,
	\item[{\tt group}] - zwraca znaleziony ciąg znaków należący do zadanej grupy. Domyślna grupa 0 (zero) zawiera cały znaleziony ciąg, kolejne grupy wyznaczane są poprzez podane nawiasy okrągłe w~wyrażeniu regularnym. W~omawianym poniżej przykładzie zostały znalezione trzy grupy,
	\item[{\tt groups}] - zwraca krotkę (czyli listę ,,tylko do odczytu'') znalezionych grup, oprócz grupy 0 (zero) czyli całego znalezionego dopasowania.
    \end{description}

    Wykorzystanie opisanych powyżej funkcji przedstawia następujący przykład:     
     \begin{verbatim}urls = """http://imdb.com/nowplaying/
ftp://ftp.amu.edu.pl/pub/
http://film.onet.pl/filmoteka.html
http://filmobaza.pl/"""

pattern = 'http:\/\/(.+)\.pl/(.*)'

m1 = re.match(pattern, urls)
print m1

m2 = re.search(pattern, urls)
print m2.group()
print m2.group(1)
print m2.group(2)
print m2.groups()

m3 = re.findall(pattern, urls)
print m3
\end{verbatim}
	    
	Wydruk tworzony przez powyższy kod wygląda następująco:
	\begin{verbatim}None
http://film.onet.pl/filmoteka.html
film.onet
filmoteka.html
('film.onet', 'filmoteka.html')
[('film.onet', 'filmoteka.html'), ('filmobaza', '')]\end{verbatim}
	Jak widać pierwszy link nie odnosi się do domeny kończącej się znakami {\tt .pl}, a~więc funkcja {\tt match} zwraca obiekt pusty. Funkcja {\tt search} znajduje tylko pierwszy link pasujący do wzorca {\tt pattern}. Natomiast funkcja {\tt findall} podaje listę grup wskazanych za pomocą nawiasów we wzorcu, lecz nie daje pełnych linków. W~powyższym przykładzie wyrażenie regularne kompilowane jest trzykrotnie. Aby przyspieszyć działanie tego programu należało by zrezygnować z~automatycznego kompilowania wzorca przed każdą z~funkcji i~wykorzystać jawne wywołanie funkcji {\tt compile}:
	\begin{verbatim}regex = re.compile(pattern)
m1 = regex.match(urls)
m2 = regex.search(urls)
m3 = regex.findall(urls)\end{verbatim}


\section{Aplikacja internetowa wykonana w~Zope - FilmoBaza}
\label{fb}

Pełne zrozumienie mechanizmów działania serwera aplikacji Zope nie jest możliwe tylko po przestudiowaniu literatury opisującej to zagadnienie. Konieczne jest zastosowanie tej teorii w~praktyce. Dlatego też w~toku prac nad niniejszą pracą magisterską podjąłem się stworzenia aplikacji internetowej. Projekt ten, nazwany przeze mnie Filmobaza, pomógł mi nabyć praktyczne umiejętności prawidłowej budowy aplikacji. Podstawowym zadaniem podczas tworzenia aplikacji jest prawidłowy podział jej na trzy części - warstwę prezentacji, warstwę logiki oraz na dane.

Moja aplikacja działa wykorzystując różne oprogramowanie. Najważniejszym elementem tego zestawu jest serwer aplikacji Zope w~wersji 2.9.4. Serwerem pośredniczącym w~wymianie żądań HTTP jest serwer {\em Apache} w~wersji 2.0.58. Dane natomiast obsługiwane są przez relacyjną bazę danych MySQL w~wersji 5.14. Całość uruchomiona jest pod kontrolą systemu operacyjnego {\em Windows XP}.

    \subsection{Czym jest FilmoBaza}
    
    FilmoBaza jest serwisem poświęconym filmom polskim i~zagranicznym. Jest aplikacją intenretowa wydaną na zasadach wolnego oprogramowania w~oparciu o~licencję GPL ({\em GNU General Public License}) w~wersji 2.

    Informacje o~wybranym filmie zostały znalezione w~internecie przy użyciu specjalnie do tego zbudowanego skryptu. Z~najpopularniejszych i~najbardziej wiarygodnych polskich i~zagranicznych serwisów wybierane są najważniejsze informacje o~filmie. Podane są także odnośniki do stron z~których zostały zaczerpnięte informacje (główne źródła). Jest to w~rozumieniu polskiego prawa - przytaczanie urywków utworów (patrz. Ustawa z~dnia 4 lutego 1994 r. o~prawie autorskim i~prawach pokrewnych Art. 29\cite{ustawa}). Skrypt działa podobnie do wyszukiwarek internetowych z~tą tylko różnicą, że dane są indeksowane dopiero, kiedy nastąpi żądanie o~nie, a~nie wcześniej jak to robią roboty wyszukiwarek. Podejście takie odciąża serwer od ciągłego przeglądania internetu. Powoduje to niestety, że w~przypadku, kiedy oczekiwane dane nie były wcześniej przez nikogo wyszukiwane, konieczne jest odczekanie chwili aż aplikacja odnajdzie w~internecie odpowiednie dane. 
    
    FilmoBaza została stworzona, aby ułatwić poszukiwanie w~internecie informacji o~filmach. Jedno wyszukiwanie w~FilmoBazie powoduje wyświetlenie podstawowych informacji o~filmie takich jak: tytuł polski i~zagraniczny, rok i~kraj produkcji, nazwisko reżysera i~scenarzysty, krótki opis oraz skrócona obsada filmu. Oprócz tych danych podawane są odnośniki do innych serwisów zawierających informacje o~filmach, a~także do stron zawierających inne zasoby z~nimi związane (np. napisy dla niedosłyszących, sklepy z~płytami DVD itp.).
    
    Prace nad algorytmem wyszukiwania filmów w~internecie rozpocząłem w~lutym 2005 roku. Początkowo serwis nazywał się ALoHa (nazwa pochodziła od pierwszych liter pełnej nazwy programu - {\em Automated Links' Hunter}). Ta aplikacja internetowa była w~rzeczywistości dużym skryptem CGI. Wyszukane dane przechowywane były w~plikach przechowywanych na dysku serwera. Brak ułatwień, jakie oferuje serwer aplikacji spowodowały, że kod skryptu był skomplikowany a~co za tym idzie trudny w~dalszej rozbudowie, ulepszaniu i~poprawianiu. W~lipcu tego samego roku postanowiłem przekształcić skrypt ALoHa na aplikację internetową napisaną w~środowisku Zope. To właśnie wtedy nabyłem podstawowych umiejętności w~posługiwaniu się tym serwerem aplikacji. Dalsze poznawanie zalet i~wad, jakie niesie ze sobą korzystanie z~Zope skłoniło mnie do decyzji o~całkowitym przepisaniu od nowa algorytmu serwisu.
    
    Tworzenie tej nowej aplikacji zacząłem oczywiście od prawidłowego podziału na trzy warstwy (prezentacji, logiki i~danych). Elementy te wcześniej były wymieszane, co powodowało wspomniane utrudnienia w~dalszym rozwijaniu projektu. Zmieniłem także nazwę serwisu na FilmoBaza, ponieważ lepiej oddaje jego charakter. Dodana została możliwość pisania komentarzy do filmów, a~także zgłaszania administratorom nieścisłości znalezionych informacji. Od chwili uruchomienia tej aplikacji internetowej pod adresem {\em http://filmobaza.pl} stronę odwiedziło prawie 23 tysiące osób i~wyświetlonych zostało ponad 81 tysięcy podstron (dane zebrano w~okresie od 20 sierpnia 2006 roku do 10 maja 2007 roku przy użyciu darmowych statystyk {\em Google Analytics}). Baza danych zawiera opisy prawie 3,5 tysiąca filmów. 
    
    \subsection{Obsługa FilmoBazy przez użytkownika}
    \label{usingfb}
    
    Na stronie główne serwisu FilmoBaza (tj. {\em http://filmobaza.pl}) znajduje się wyszukiwarka filmów (rys.~\ref{fbsearch}). W~tym miejscu użytkownik wpisuje tytuł poszukiwanego przez niego filmu. Tytuł ten powinien być w~języku, w~którym został nakręcony ten film. Możliwe jest także wpisanie tytułu angielskiego lub polskiego lecz trafność wyszukiwania w~takim przypadku jest gorsza. Wyszukiwanie można kontynuować na dwa sposoby: klikając przycisk {\tt Szukaj} lub przycisk {\tt Strzał}. W~pierwszym przypadku nastąpi przejście do listy tytułów filmów najlepiej pasujących do zadanej frazy wyszukiwania, w~drugim natomiast bezpośrednio do filmu, który znajduje się na czele tej listy.
    
    \begin{figure}
	\includegraphics[width=15cm]{rys/fbsearch}
	\caption[Wygląd strony głównej serwisu FilmoBaza]{Wygląd strony głównej serwisu FilmoBaza \newline \em{Źródło: opracowanie własne\hspace*{10cm}}}
	\label{fbsearch}
    \end{figure}

    Lista znalezionych filmów składa się z~dwóch części. Spisu filmów pasujących do frazy, które zostały wcześniej skatalogowane, a~także spisu filmów, które jeszcze nie znajdują się w~serwisie. Kliknięcie na link do skatalogowanego filmu spowoduje natychmiastowe przeniesienie do strony zawierającej opis tego filmu. Gdy wybrany zostanie film spoza serwisu strona z~jego opisem otworzy się po dłuższej chwili. Widok listy ze znalezionymi tytułami przedstawia rysunek \ref{fbfinded}.
    
    \begin{figure}
	\includegraphics[width=15cm]{rys/fbfinded}
	\caption[Wygląd strony zawierającej listę tytułów filmów pasujących do zadanej frazy]{Wygląd strony zawierającej listę tytułów filmów pasujących do zadanej frazy \newline \em{Źródło: opracowanie własne\hspace*{10cm}}}
	\label{fbfinded}
    \end{figure}
	
    Film można także znaleźć używając katalogu filmów, czyli spisu wszystkich filmów, jakie znajdują się w~serwisie. Filmy te podzielone są według alfabetu. 
    
    Strona zawierająca opis filmu jest podzielona na cztery części:
    \begin{enumerate}
	\item Główna część strony zajmująca największą powierzchnię zawiera podstawowe informacje o~filmie. Jeżeli skrypt wyszukujący będzie miał stuprocentową skuteczność dla danego filmu, to zostaną skatalogowane i~uwidocznione następujące informacje: tytuł w~języku, w~którym powstał film, tytuł polski (jeżeli jest inny niż tytuł oryginalny), rok produkcji, imię i~nazwisko reżysera (reżyserów, jeżeli jest ich więcej) oraz scenarzysty i~operatora kamery, kraj produkcji, gatunek. Następnie wypisane są średnie oceny filmów wraz z~liczbą oddanych głosów. Noty te pochodzą z~trzech, według mnie, najbardziej wiarygodnych serwisów filmowych. Są to IMDb ({\em http://imdb.com}), OnetFilm ({\em http://film.onet.pl}) oraz FilmWeb ({\em http://filmweb.pl}). Z~tych trzech źródeł pobierane są także krótkie streszczenia filmów. Na końcu podawana jest obsada filmu, czyli spis aktorów wraz z~przyporządkowanymi postaciami jakie odgrywają.
	    
	    Ostatnią informacją, jaka znajduje się w~tej części strony, jest linijka zawierająca datę i~godzinę, w~której nastąpiło wyszukanie i~skatalogowanie danych.
	    
	\item Z~prawej strony znajduje się kolumna zawierająca linki do stron związanych z~wyszukanym filmem. Odnośniki zostały podzielone na kilka grup:
	    
	\begin{figure}
	    \includegraphics[width=15cm]{rys/movie}
	    \caption[Wygląd strony zawierającej opis przykładowego filmu]{Wygląd strony zawierającej opis przykładowego filmu \newline \em{Źródło: opracowanie własne\hspace*{10cm}}}
	    \label{movie}
	\end{figure}

	    \begin{description}
		\item[Główne źródła] - zawiera łącza do stron opisujących znaleziony film z~trzech podstawowych serwisów: IMDb, OnetFilm i~FilmWeb. Z~wskazywanych przez te linki stron skrypt indeksujący pobiera informacje,
		\item[Inne źródła] - wypisane są odnośniki do innych serwisów filmowych, polskich i~zagranicznych. Linki te nie wskazują bezpośrednio na strony zawierające informacje o~filmie lecz odnoszą się do ich wewnętrznych wyszukiwarek. Po otwarciu tych linków zostanie otwarta strona z~listą tytułów filmów najlepiej pasujących do tytułu, jaki został skatalogowany w~FilmoBazie,
		\item[Napisy] - w~tej grupie umieszczono odnośniki do serwisów zawierających polskie napisy dla niedosłyszących i~głuchych,
		\item[Okładki] - linki z~tej grupy odnoszą się do polskich i~zagranicznych stron zawierających zeskanowane lub zrobione od podstaw okładki do płyt DVD,
		\item[Scena] - tu znajduje się jedno łącze do bazy danych zawierającej informacje o~filmach, jakie zostały nielegalnie udostępnione przez grupy piratów. Ja takich działań oczywiście nie popieram, lecz nie należy ignorować tych użytkowników FilmoBazy którzy życzą sobie, aby i~taki link się tu pojawiał,
		\item[Wikipedia] - niektóre, lepiej znane, kultowe bądź będące arcydziełami filmy zostały także umieszczone w~Wikipedii Wolnej Encyklopedii, dlatego też w~tej grupie znajdują się linki do angielskiej i~polskiej wersji tej encyklopedii,
		\item[Wyszukiwarki] - dopełnieniem zbioru linków jest właśnie ta grupa, która to pozwala na przejście do trzech najpopularniejszych wyszukiwarek internetowych i~kontynuowanie poszukiwania informacji o~filmach,
		\item[Dodatki] - ostatnim łączem jest {\em BB tags}. Otwarcie tej podstrony FilmoBazy spowoduje pokazanie tych samych informacji o~filmie lecz sformatowanych zgodnie ze standardem BB. Standard {\em BB tags} wykorzystywany jest w~wielu forach internetowych do formatowania tekstu, jaki można wstawić do forum.
	    \end{description}
	    
	\item Skrypt wyszukujący informacje o~filmach nie jest nieomylny. Czasami zdarza się, że z~filmem zostaną skojarzone dane odpowiadające innemu filmowi o~podobnym tytule. Poniżej kolumny z~linkami znajduje się miejsce w~którym możliwe jest zgłaszanie błędów. Opcje te dostępne są dopiero po wcześniejszym zalogowaniu. Podczas zgłaszania nieprawidłowości można zaznaczyć jedną z~dwóch opcji wskazujących na błędy łączenia z~serwisami OnetFilm i~FilmWeb.
	    
	\item Ostatnia część zawiera komentarze użytkowników do filmu. Domyślnie część ta jest ukryta i~dopiero po kliknięciu przycisku ,,pokaż komentarze'' zostaje rozwinięta. Jeżeli nikt jeszcze nie komentował oglądanego filmu to pokazywany jest przycisk ,,dodaj komentarz'' lub informacja o~tym, że możliwość komentowania posiadają tylko zalogowani użytkownicy.
	    
	    Wszystkie operacje na komentarzach, a~więc wyświetlanie, tworzenie, edytowanie i~zgłaszanie nieodpowiednich treści komentarzy zostały zaimplementowane na zasadach technologii AJAX. Dzięki takiemu podejściu poprawia się elastyczność pracy z~aplikacją, a~także łącza zostają odciążone, ponieważ mniejsze porcje danych są przesyłane między serwerem a~przeglądarką WWW użytkownika.
    \end{enumerate}

    Wszystkie dotychczas opisane w~tym podrozdziale podstrony dostępne są dla wszystkich odwiedzających FilmoBazę. Użytkownicy, którzy stworzyli sobie konto w~serwisie dodatkowo mają dostęp do strony, dzięki której mogą edytować dane skojarzone z~ich kontem. Najważniejsze dane to link do {\em avatara} czyli małego obrazka - ikonki. Obrazek ten wyświetlany jest po lewej stronie pisanych przez nich komentarzy. Ułatwia to szybkie kojarzenie i~rozpoznawanie autorów bez konieczności zapamiętywania ich ników.
    
    Dodatkowo stworzony został interfejs administracyjny dostępny tylko dla wybranych użytkowników. W~panelu tym dostępne są trzy najważniejsze opcje:
    \begin{description}
	\item[Spis użytkowników] - w~tym miejscu możliwe jest przeglądanie kont użytkowników. Dla wygody podzieleni zostali oni alfabetycznie. Administrator ma możliwość zmienić rangę użytkownika, a~co za tym idzie zwiększyć bądź zmniejszyć uprawnienia mu przysługujące. Może także zablokować konto, uniemożliwiając w~ten sposób logowanie używając hasła skojarzonego z~tym kontem. Przykładowy widok tej części panelu przedstawiono na rysunku \ref{adminusers},
	    
	    \begin{figure}
		\includegraphics[width=15cm]{rys/adminusers}
		\caption[Spis użytkowników w~panelu administracyjnym FilmoBazy]{Spis użytkowników w~panelu administracyjnym FilmoBazy \newline \em{Źródło: opracowanie własne\hspace*{10cm}}}
		\label{adminusers}
	    \end{figure}

	\item[Zgłoszone filmy z~błędami] - ta część panelu administracyjnego pozwala na przeglądanie listy filmów, jakie zostały zgłoszone jako zawierające nieprawidłowe dane. Administrator do dyspozycji ma możliwość edycji linków do podstron serwisów OnetFilm i~FilmWeb. Po podaniu prawidłowych odnośników następuje podobne wydobywanie informacji do tego, jakie odbywa się w~trakcie katalogowania filmu z~tą różnicą, że nie są wyszukiwane linki lecz używane te podane przez administratorów. W~przypadku, gdy zgłoszenie było nieuzasadnione jest także możliwość usunięcia zgłoszenia bez poprawiania filmu,
	    
	    \begin{figure}
		\includegraphics[width=15cm]{rys/adminmovies}
		\caption[Spis zaraportowanych filmów w~panelu administracyjnym FilmoBazy]{Spis zaraportowanych filmów w~panelu administracyjnym FilmoBazy \newline \em{Źródło: opracowanie własne\hspace*{10cm}}}
		\label{adminmovies}
	    \end{figure}

	\item[Zgłoszone nieodpowiednie komentarze] - tu wyświetlana jest lista komentarzy, jakie zostały uznane przez innych użytkowników jako nieodpowiednie (np. wulgarne, nie mające związku z~dyskusją itd.). Administrator oprócz możliwości usunięcia komentarza lub zgłoszenia, w~łatwy sposób może przejść do profilu autora komentarz lub zgłoszenia i~zablokować ich konta.
    \end{description}
    
    \subsection{Procedura generowania stron z opisem filmu}
    
    Poprzedni podrozdział opisuje zachowanie stworzonej przeze mnie aplikacji internetowej widziane od strony użytkownika jej używającej. Osoba ta nie musi wiedzieć, w~jaki sposób dane, które ogląda zostają wyszukane, dla niej liczy się tylko efekt końcowy - pełna i~prawidłowa informacja o~poszukiwanym filmie. W~niniejszym podrozdziale znajduje się opis działania skrypt FilmoBazy, który zaczynając od wpisanej frazy ostatecznie wyświetla pełną informację o~filmie.
    
    Aby ułatwić zrozumienie omawianego zagadnienia konieczne jest poznanie struktury bazy danych, w~której to znajdują się skatalogowane filmy. Najważniejszą tabelą w~bazie danych jest tabela {\em movie}. Opis jej kolumn zawarłem w~tabeli \ref{movietable}.
    
    \begin{table}
	\caption{Struktura tablicy {\em movie} w~bazie danych używanej przez FilmoBazę}
	\label{movietable}
	\begin{small}
	\begin{tabular}{|p{3cm}|p{2.5cm}|p{8.5cm}|}
	    \hline
	    {\em Nazwa}	    &	{\em Typ}	&   {\em Opis}    \\
	    \hline
	    IMDB\_ID	    &  	char(7)		&   numer {\em id} filmu, posiadając ten numer możliwe jest utworzenie odnośnika do strony w~serwisie IMDb\\
	    \hline
	    TITLE	    &	varchar(100) 	&   tytuł filmu w~języku w~jakim został nakręcony, w~większości przypadków jest to język angielski\\
	    \hline
	    YEAR	    &	smallint(5) 	&   rok w~którym nastąpiła premiera filmu\\
	    \hline
	    COUNTRY	    &	varchar(100) 	&   nazwa kraju produkcji filmu\\
	    \hline
	    DIRECTOR	    &	varchar(100) 	&   imiona i~nazwiska reżyserów oddzielona przecinkami\\
	    \hline
	    WRITER	    &	varchar(100) 	&   imiona i~nazwiska scenarzystów rozdzielone przecinkami\\
	    \hline
	    CIN		    &   varchar(100) 	&   imiona i~nazwiska operatorów kamer rozdzielone przecinkami\\
	    \hline
	    IMDB\_PLOT	    &	text		&   streszczenie filmu pochodzące z~serwisu IMDb\\
	    \hline
	    IMDB\_RATING    & 	float		&   średnia ocena filmu w~serwisie IMDb\\
	    \hline
	    IMDB\_VOTES	    & 	mediumint(8) 	&   ilość osób które oceniały film w~serwisie IMDb\\
	    \hline
	    GENRE	    &	varchar(100) 	&   gatunki filmu rozdzielone przecinkami\\
	    \hline
	    CAST	    &	text		&   tekstowa reprezentacja sekwencji par nazwisko aktora i~nazwisko odgrywanej postaci, podczas importowania danych z~bazy następuje przekształcenie tej reprezentację na listę\\
	    \hline
	    FW\_ID	    &	varchar(10) 	&   numer {\em id} filmu w~serwisie FilmWeb, znając ten numer możliwe jest odtworzenie linku do podstrony w~serwisie FilmWeb opisującej dany film\\
	    \hline
	    TITLE\_PL	    &	varchar(100) 	&   polski tytuł filmu, pole to jest puste w~przypadku gdy tytuł oryginalny jest taki sam jak polski lub gdy nie znaleziono danego filmu w~polskich serwisach filmowych\\
	    \hline
	    FW\_RATING	    &	float		&   średnia ocena filmu w~serwisie FilmWeb\\
	    \hline
	    FW\_VOTES	    &	mediumint(8) 	&   ilość osób które oceniały film w~serwisie FilmWeb\\
	    \hline
	    COVER	    &	varchar(100) 	&   część linku do miniaturki okładki lub miniaturki plakatu reklamowego, mając te dane możliwe jest utworzenie linku do obrazka w~formacie jpg znajdującego się w~serwisie FilmWeb, podczas katalogowania filmu okładka ta nie jest kopiowana lecz zapamiętywany jest jedynie link do niej\\
	    \hline
	    FW\_PLOT	    &	text		&   streszczenie filmu pochodzące z~serwisu FilmWeb\\
	    \hline
	    OF\_ID	    &	varchar(100) 	&   numer {\em id} filmu w~serwisie OnetFilm, wykorzystywany do odtworzenia linku z~którego zostały pobrane informacje\\
	    \hline
	    OF\_RATING	    &	float		&   średnia ocena filmu w~serwisie OnetFilm\\
	    \hline
	    OF\_VOTES	    &	mediumint(8) 	&   ilość osób które oceniały film w~serwisie OnetFilm\\
	    \hline
	    OF\_PLOT	    &	text		&   streszczenie filmu pochodzące z~serwisu OnetFilm\\
	    \hline
	    EDIT\_TIME	    &	varchar(10) 	&   data ostatniego katalogowania danego filmu, zapisana jako ilość sekund od 1 stycznia 1970 roku\\
	    \hline
	\end{tabular}
    \end{small}
    \end{table}
    
    Zasadę działania zbudowanej przeze mnie aplikacji internetowej, jaką jest FilmoBaza najlepiej pokazać na przykładzie. Prześledźmy co dzieje się wewnątrz serwera, kiedy użytkownik chce znaleźć opis filmu ,,Godfather'', czyli po polsku ,,Ojciec chrzestny''.

    \begin{enumerate}
	\item Użytkownik po wpisaniu interesującego go tytułu filmu klika przycisk {\tt szukaj}. Jego przeglądarka WWW przekształca to zapytanie na adres URL \\ (np. {\em http://filobaza.pl/szukaj?q=godfather}). 
	\item Serwer aplikacji Zope uruchamia szablon ZPT o~nazwie {\tt szukaj}. W~jednej z~pierwszych linii tego szablonu następuje wywołanie dwóch obiektów warstwy logiki.
	\item Pierwszym z~nich jest metoda ZSQL o~nazwie {\tt find\_movies}. Jako argument przekazywana jest wartość podanej przez użytkownika frazy (tytułu filmu). W~omawianym przykładzie zapytanie SQL będzie miało postać:
	    \begin{verbatim}SELECT IMDB_ID, TITLE, TITLE_PL,
MATCH (title, title_pl) AGAINST ('godfather') AS score
FROM movie
WHERE MATCH (title, title_pl) AGAINST ('godfather')
ORDER BY MATCH (title, title_pl) 
AGAINST ('godfather') DESC\end{verbatim}
	    Zapytanie to ma na celu pobranie z~bazy danych tytułów i~numeru {\em id} filmów najlepiej pasujących do zadanej frazy. Jak widać trafność i~sortowanie wyników odbywa się po stronie serwera {\em MySQL}, dzięki czemu jest o~wiele szybsze niż gdyby miałoby to być robione przez Zope.
	\item Drugim wywoływanym obiektem jest metoda zewnętrzna {\tt find\_imdb\_urls}. Metoda ta skojarzona jest z~funkcją o~tej samej nazwie w~pliku {\tt filmobaza.py}. Zadaniem tej funkcji jest znalezienie przy użyciu wyszukiwarki Google linków do podstron w~serwisie IMDb opisujących film o~tytule pasującym do zadanej frazy. W~tym celu przy użyciu {\em PyGoogle} wraz z~{\em Google SOAP Search API} wysyłane jest zapytanie o~treści:
	    \begin{verbatim}godfather site:imdb.com\end{verbatim}
	    otrzymane w~wyniku odnośniki są filtrowane na takie pasujące do jednego z~wyrażeń regularnych:
	    \begin{verbatim}http:\/\/.*imdb\.com\/title\/tt(\d+)\/$
http:\/\/.*imdb\.com\/Title\?(\d+)$\end{verbatim}
	    W~wyniku wywołania tych wyrażeń pobierane są jednocześnie numery {\em id} filmów. Zwracane są jedynie te numery, które nie znalazły się na liście otrzymanej z~metody ZSQL {\tt find\_movies}.
	\item Mając listy numerów {\em id} filmów pasujących do zapytania (z~podziałem na te, które są już skatalogowane i~te, których jeszcze nie ma w~bazie), formatowany jest szablon ZPT, a~odpowiedz jest wysyłana do przeglądarki WWW użytkownika. Przytoczony przykład zostanie wyświetlony po stronie wyszukującego, tak jak to widać na rysunku \ref{fbfinded}.
	\item W~tym momencie serwer aplikacji oczekuje na interakcję. Użytkownik musi wybrać, który ze znalezionych filmów jego interesuje. Przykładowo niech będzie to film o~tytule {\em The Godfather / Ojciec chrzestny}. Przeglądarka WWW po kliknięciu na ten wskazany tytuł wysyła do Zope żądanie HTTP zawierające adres URL {\em http://filmobaza.pl/film?id=0068646}.
	\item Serwer Zope działający pod adresem {\em filmobaza.pl} uruchamia interpretacje szablonu ZPT o~nazwie {\tt film}. Na początku przetwarzania tego szablonu wywoływany jest skrypt w~języku Python o~nazwie {\tt get\_info}. 
	\item Skrypt {\tt get\_info} najpierw wykonuje metodę ZSQL o~nazwie {\tt get\_movie} z~podanym parametrem będącym numerem {\em id} filmu, który ma zostać wyświetlony. Zostaje wysłane do serwera bazy danych zapytanie SQL:
	    \begin{verbatim}SELECT * FROM movie
WHERE imdb_id='0068646'\end{verbatim}
	\item Jeżeli zapytanie zwróciło dokładnie jeden wiersz z~tabeli {\tt movie} oznacza to, że film jest już skatalogowany i~dane mogą być przekazane do szablonu {\tt film}.
	\item W~przeciwnym przypadku skrypt uruchamia serie komend, które mają na celu znalezienie w~internecie informacji o~filmie. Dokładniej ta część algorytmu została opisana w~podrozdziale \ref{moviesearch}.
	\item Jeżeli dane zostały prawidłowo znalezione zostają one dodane do bazy danych przy użyciu metody ZSQL o~nazwie {\tt add\_movie}, a~następnie zwrócone do szablonu {\tt film}.
	\item Interpreter ZPT po otrzymaniu opisu filmu od skryptu {\tt get\_info} formatuje odpowiednio dane, przygotowuje zestaw linków, wyszukuje także komentarze skojarzone z~tym filmem. Ostatecznie zostaje odesłana do przeglądarki internetowej użytkownika strona przedstawiona na rysunku \ref{movie}.
    \end{enumerate}
    
    W~taki właśnie sposób zachowuje się serwer Zope obsługujący to samo zadanie opisane w~podrozdziale \ref{usingfb}.
    
    \subsection{Algorytm wyszukiwania w~internecie informacji o~filmie}
    \label{moviesearch}
    
    Kod algorytmu, którego celem jest znalezienie informacji o~zadanym filmie, musiał zostać w~dużej części umieszczony w~metodach zewnętrznych. Dwoma głównymi tego powodami była konieczność zezwolenie skryptowi na bezpośredni dostęp do stron internetowych w~internecie oraz częste wykorzystanie wyrażeń regularnych, które nie zostały włączone do Zope.
    
    Koordynująca zachowań tego algorytmu wykonywana jest przez skrypt w~języku Python o~nazwie {\tt get\_info}. Kod odpowiedzialny za to zadanie przedstawia się następująco:
    \begin{verbatim}info = {'IMDB_ID': movie_id}
imdb_info = context.open_imdb(movie_id)
info.update(imdb_info)
if not info.has_key('TITLE'):
    return {}

info['OF_ID'] = context.find_of_url(
                        info['TITLE'] + ' ' + info['YEAR'])
of_info = context.open_of(
        'http://film.onet.pl/%s,film.html' % info['OF_ID'])
info.update(of_info)

fw_link = context.find_fw_url(
                  info['TITLE'] + ' ' + info['YEAR'])
fw_info = context.open_fw(fw_link)
info.update(fw_info)
\end{verbatim}
    Argumentem jego wykonania jest zmienna {\tt movie\_id}. W~omawianym przykładzie będzie ona wynosiła {\tt 0068646}. Efektem przebiegu tego skryptu będzie słownik {\tt info}, którego klucze będą takie same jak nazwy kolumn z~tabeli {\tt movie} znajdującej się w~bazie danych (patrz tabela 1). Kolejne instrukcje powodują wyszukanie danych z~trzech źródeł z~IMDb, z~OnetFilmu i~z~FilmWebu. Te wyszukane dane powiększają wynikowy słownik (wykonuje to funkcja {\tt info.update}).
    
    Bardziej szczegółowo omawiany algorytm przedstawia się następująco:
    \begin{enumerate}
	\item W~drugiej linii przedstawionego fragmentu skryptu {\tt get\_info} uruchamiana jest metoda zewnętrzna {\tt open\_imdb}. Funkcja skojarzona z~tą metodą przy użyciu biblioteki {\em IMDbPy} łączy się z~serwisem IMDb i~z~kilku podstron tego portalu pobiera komplet informacji o~filmie. Niektóre informacje zostają przeformatowane i~dodane do wynikowego słownika. W~funkcji tej wypełniane są następujące pola: {\tt TITLE}, {\tt YEAR}, {\tt COUNTRY}, {\tt DIRECTOR}, {\tt WRITER}, {\tt CIN}, {\tt IMDB\_PLOT}, {\tt IMDB\_RATING}, {\tt IMDB\_VOTES}, {\tt GENRE} oraz {\tt CAST}.
	\item W~dalszej kolejności wykonywana jest metoda zewnętrzna {\tt find\_of\_url}. Parametrem jej wykonania w~rozpatrywanym przypadku będzie ciąg znaków {\tt The Godfather 1972}. 
	\item Funkcja połączona z~powyższą metodą zewnętrzną przy użyciu biblioteki PyGoogle wysyła zapytanie:
	    \begin{verbatim}The Godfather 1972 site:film.onet.pl inurl:film\end{verbatim}
	    Wyszukane odnośniki filtrowane są zgodnie z~wyrażeniem regularnym:
	    \begin{verbatim}http:\/\/film\.onet\.pl\/(.+),film.html$\end{verbatim}
	    Funkcja zwraca tę niepowtarzalną część linku do podstrony w~serwisie OnetFilm dalej zwaną {\tt OF\_ID}. Tu będzie to {\tt 7412,,Ojciec\_chrzestny}.
	\item Kiedy znaleziono {\em id} OnetFilmu możliwe jest otwarcie strony:
	    \begin{verbatim}http://film.onet.pl/7412,,Ojciec_chrzestny,film.html\end{verbatim}
	    Dzieje się to w~metodzie zewnętrznej {\tt open\_of}. Tam też przy użyciu wyrażeń regularnych ze ściągniętej strony w~formacie HTML ,,wyłuskane'' zostają dane, a~następnie wstawione do wynikowego słownika jako pola: {\tt OF\_RATING}, {\tt OF\_VOTES} oraz {\tt OF\_PLOT}.
	\item Kolejną wykonywaną metodą zewnętrzną jest {\tt find\_fw\_url}. Podobnie jak poprzednio wysyłana jest do wyszukiwarki {\em Google} fraza:
	    \begin{verbatim}The Godfather 1972 site:filmweb.pl intitle:filmie\end{verbatim}
	    Wynikowe odnośniki brane są pod uwagę tylko, jeżeli pasują do jednego ze wzorców:
	    \begin{verbatim}http:\/\/.*filmweb\.pl\/Film,id=(\d+)$
http:\/\/(.+)\.filmweb\.pl\/$
http:\/\/.*filmweb\.pl\/.+\?id=(\d+)$\end{verbatim}
	    W~przypadku FilmWebu linki, na których są informacje o~filmach, są dość różnorodne, dlatego też na tym etapie nie jest jeszcze możliwe uzyskanie {\em id}.
	\item Pełne łącze wskazujące na stronę w~serwisie FilmWeb zostaje przekazane do metody zewnętrznej {\tt open\_fw}. Funkcja ta ściąga stronę spod adresu
	    \begin{verbatim}http://ojciec.chrzestny.filmweb.pl\end{verbatim}
	    Tutaj także przy użyciu wyrażeń regularnych ,,wyłuskiwane'' są dane, które następnie będą wstawiane do bazy danych w~następujących polach: {\tt FW\_ID}, {\tt TITLE\_PL}, {\tt FW\_RATING}, {\tt FW\_VOTES}, {\tt COVER} oraz {\tt FW\_PLOT}.
    \end{enumerate}
    
    Wyszukiwanie filmu w~FilmoBazie obciążone jest dwukrotnym przeszukaniem bazy danych oraz jednokrotnym łączeniem z~wyszukiwarką {\em Google}. Przy czym pierwsze z~tych filtrowań jest bardziej czasochłonne (ponieważ wykorzystywana jest komenda dopasowująca - {\tt AGAINST}). 
    
    W~przypadku, gdy film nie został jeszcze skatalogowany, konieczne jest ściągnięcie około trzech podstron serwisu IMDb, dwóch podstron FilmWebu oraz jednej strony z~OnetFilmu. Wysyłane są także do wyszukiwarki {\em Google} dwa zapytania. Wykonanie tych czynności trwa dość długo z~powodu sporego obciążenia wspomnianych serwisów filmowych.

    \subsection{Zawartość dołączonej płyty CD}
    
    Na dołączonej, do niniejszej pracy magisterskiej, płycie CD znajdują się pliki dzięki którym w~łatwy sposób możliwe jest uruchomienie FilmoBazy. Te pliki to:
    \begin{description}
	\item[bbparser.py] - moduł autorstwa Armin-a Ronacher-a zawierający parser {\em BBCode} (udostępniony na licencji wolnej GPLv2). Plik ten należy skopiować do katalogu {\tt Extensions} w~katalogu instalacyjnym instancji Zope,
	\item[filmobaza.py] - moduł zawierający kod wyszukujący informacje o~filmach. Podobnie jak powyższy plik, należy go wgrać do katalogu {\tt Extensions}. Funkcje z~tego modułu są włączane do FilmoBazy jako metody zewnętrzne,
	\item[filmobaza.sql] jest plikiem eksportu z~bazy danych {\em MySQL}. Zawiera opis struktury tabel a~także ich zawartość na dzień 3 lipca 2007. Plik ten może być użyty do stworzenia bazy danych współpracującej z~FilmoBazą,
	\item[filmobaza.xml] jest plikiem eksportu z~ZODB. Zawiera wszystkie obiekty które wchodzą w~skład FilmoBazy. Dzięki strukturze XML możliwe jest łatwe przekształcanie i~przeglądanie danych,
	\item[filmobaza.zexp] jest także plikiem eksportu z~Zope. Zawiera dokładnie te same dane co powyższy plik, ale w~formie trudnej do zrozumienia przez inne programy niż Zope. Zaimportowanie tego pliku do pustej instancji Zope powoduje wgranie wszystkich obiektów koniecznych do uruchomienia FilmoBazy.
    \end{description}
    
    Na płycie znalazła się także treść niniejszej pracy magisterskiej w~formie elektronicznej (w~formacie PDF i~LaTeX).

\section{Zakończenie}

Serwer aplikacji Zope jest potężnym narzędziem bardzo ułatwiającym tworzenie, administrację i~rozwijanie aplikacji internetowych. Ponieważ większość mechanizmów, jakie wykorzystuje, nie zostało zapożyczonych z~innych środowisk ułatwiających budowę aplikacji, konieczne jest zapoznanie się z~dość dużą ilością zagadnień. Niestety ilość wiedzy jaką trzeba posiąść aby móc zacząć budować proste aplikacje internetowe w~Zope jest dość spora. Jednakże po przebrnięciu tego początkowego okresu zyski płynące z~ilości udogodnień przeważają, dzięki czemu nakład pracy zwraca się z~nawiązką.

    \subsection{Zakres materiału objęty w~pracy}

    Zakres wiedzy zawarty w~niniejszej pracy magisterskiej pozwala na budowanie w~pełni działających aplikacji internetowych w~środowisku serwera aplikacji Zope. Nie zostały tu jednak opisane wszystkie mechanizmy, jakie dostępne są w~Zope. Celowo ominąłem opis języka DTML, ponieważ sami twórcy Zope zalecają używanie nowocześniejszych rozwiązań, jakimi niewątpliwie są szablony ZPT (zamiennik dla dokumentów DTML), a~także skrypty w~języku Python (odpowiednik metod DTML). W~pracy zamieściłem tylko skrócony opis zarządzania zasadami bezpieczeństwa i~dostępu. Krótko pisałem także o~mechanizmie wirtualnych hostów oraz przechowywaniu danych między sesjami. Nie opisywałem także niektórych bardziej zaawansowanych zagadnień takich jak: przeszukiwanie i~kategoryzowanie zawartości, obsługa wielojęzyczności, nabywanie cech (ang. {\em Acquisition}), obsługa skalowalności, metody tworzenia produktów oraz tworzenia {\em ZClasses}. Dopiero dokładne opisanie tych wszystkich spraw dało by pełny widok na możliwości, jakie niesie ze sobą Zope.

    \subsection{Zaawansowanie serwisu FilmoBaza}

    Stworzona przeze mnie aplikacja internetowa, czyli FilmoBaza, jest w~pełni funkcjonalnym serwisem prezentującym duży zakres wiedzy o~kinematografii. Jednakże wymaga jeszcze trochę nakładu pracy, aby móc nazwać ją perfekcyjną. Najważniejszym elementem wymagającym poprawy jest celność znajdowania stron z~informacjami o~filmie z~serwisów OnetFilm i~FilmWeb. Przydatnym elementem było by także zautomatyzowanie wykrywania tego, że skrypt nieprawidłowo wyszukał dane w~polskich serwisach filmowych. W~chwili obecnej odbywa się to dzięki uprzejmości użytkowników, którzy zgłaszają te uchybienia poprzez formularz. Wprowadzenie ułatwień dla robotów indeksujących oraz odpowiednie wypozycjonowanie strony spopularyzowało by FilmoBazę. Jeżeli serwis stałby się dość popularny możliwe byłoby zarabianie na reklamie internetowych sklepów oferujących bilety do kina, filmy na płytachDVD oraz inne gadżety związane z~kinematografią.

    \subsection{Podsumowanie}
    
    Celem niniejszej pracy magisterskiej było zapoznanie czytelnika z wiedzą potrzebną do budowania aplikacji internetowych przy użyciu serwera aplikacji Zope. Liczne stworzone przeze mnie przykłady podane wraz z zagadnieniami teoretycznymi ułatwiają czytelnikowi przyswojenie tego materiału. Dlatego też, uważam, że cel został osiągnięty. Literatura polskojęzyczna na omawiany temat jest bardzo uboga, co niewątpliwie utrudniło zbieranie informacji i nabywanie doświadczenia.


\newpage
\addcontentsline{toc}{section}{Spis rysunków}
\listoffigures

\newpage
\addcontentsline{toc}{section}{Spis tablic}

\listoftables

\newpage
\addcontentsline{toc}{section}{Literatura}
\begin{thebibliography}{99}

    \bibitem{pydoc}
	Beazley D., {\em Python}, Warszawa: Wydawawnictwo RM, 2002.

    \bibitem{soft20e}
        Dziergwa M., Mleczko A., {\em Zope - darmowy serwer aplikacji}, ,,Software 2.0 Extra!'', 09/2004.

    \bibitem{tzb26}
        Lateier A., Pelletier M, McDonough C., Sabaini P, {\em The Zope Book}, New Rider 2001.

    \bibitem{wiki-webapp}
	Wikipedia - Wolna encyklopedia, hasło {\em Serwer aplikacji}, dostępność w internecie maj 2007 r. \\ http://pl.wikipedia.org/wiki/Serwer\_aplikacji

    \bibitem{wiki-appserv}
	Wikipedia Wolna encyklopedia, hasło {\em Aplikacja webowa}, dostępność w internecie maj 2007 r. \\ http://pl.wikipedia.org/wiki/Aplikacja\_webowa

    \bibitem{zope-prod}
	Strona internetowa Zope Corporation, dostępność w internecie maj 2007 r. \\ http://www.zope.org/Products

    \bibitem{ustawa}
	Dziennik Ustaw, 1994, Nr~24 poz. 83, wraz z~późniejszymi zmianami

\end{thebibliography}
    
\end{document}

