From 6200bc8389548831e6fc345ceb9867b0d0c1b1ab Mon Sep 17 00:00:00 2001 From: Manuel Traut Date: Tue, 18 Feb 2014 23:29:58 +0100 Subject: update middleware presentation - give an introduction to the topic, what is a middleware, why do we need it - mention some xml based middlewares - update the dbus section, no we don't have HAL anymore :)) - mention the idl workflow in the corba section Signed-off-by: Manuel Traut --- frameworks/middleware/pres_middleware.tex | 571 ++++++++++++++++++++++++++++-- 1 file changed, 546 insertions(+), 25 deletions(-) (limited to 'frameworks/middleware/pres_middleware.tex') diff --git a/frameworks/middleware/pres_middleware.tex b/frameworks/middleware/pres_middleware.tex index 2f4c462..d147ceb 100644 --- a/frameworks/middleware/pres_middleware.tex +++ b/frameworks/middleware/pres_middleware.tex @@ -3,23 +3,473 @@ \title{\lq Middleware\rq} \maketitle -\subsection{DBUS} \begin{frame} -\frametitle{DBUS Communication Framework} +\frametitle{Agenda} +\begin{itemize} +\item Overview +\item XML based Middleware +\item Celery +\item DDS +\item D-Bus +\item CORBA +\end{itemize} +GOAL: get an idea about: + +the amount of available middleware solutions + +and for what they can be used. +\end{frame} + +\subsection{Overview} + +\begin{frame} +\frametitle{Use-case} +\begin{center} +\includegraphics[width=0.8\textheight]{images/714px-Middleware_Schema.png} +\end{center} +\tiny Source: http://commons.wikimedia.org/wiki/File:Middleware\_Schema.svg +\end{frame} + +\begin{frame} +\frametitle{Why should we use a middleware?} +\begin{itemize} +\item IPC +\item scalability +\item os abstraction +\item reusability of sw components +\end{itemize} +\end{frame} + +\begin{frame} +\frametitle{Kinds of Middleware} +\begin{itemize} +\item Message Oriented Middleware (MOM) +\item Remote Procedure Calls (RPC) +\item Webapplications? +\end{itemize} +\end{frame} + +\begin{frame} +\frametitle{Requirements} +\begin{block}{Abstraction Layers} +\begin{itemize} +\item operating system +\item programing language +\item localization +\item transport +\item concurrent access +\end{itemize} +\end{block} +\end{frame} + +\begin{frame} +\frametitle{Requirements} +\begin{block}{Technical, product specific} +\begin{itemize} +\item os / language support +\item performance +\item requirement coverage +\item commerical, open-source, (long-time) support +\end{itemize} +\end{block} +\end{frame} + +\begin{frame} +\frametitle{Standards, Protocols} +\begin{itemize} +\item XML based Middleware +\item Celery - Job Queue Protocol +\item DDS - Data Distribution Service +\item D-Bus - MOM +\item CORBA - Common Object Request Broker +\end{itemize} +\end{frame} + +\subsection{XML based Middleware} +\begin{frame} +\frametitle{popular protocols} +\begin{description} +\item[XML-RPC] Extensible Markup Language Remote Procedure Call +\item[SOAP/WSDL] many webservices are based on SOAP +\item[XMPP] Extensible Messaging and Presence Protocol +\end{description} +\end{frame} + +\begin{frame} +\frametitle{XML-RPC} +\begin{itemize} +\item native supported by Python (see example) +\item C/C++ Implementation: http://xmlrpc-c.sourceforge.net/ +\item Client- / Serverarchitecture +\item uses http as transport +\end{itemize} +\end{frame} + +\begin{frame}[fragile] +\frametitle{XML-RPC example in Python} +server.py\#p1 +\begin{lstlisting}[language=python] +from datetime import datetime +from SimpleXMLRPCServer import SimpleXMLRPCServer +import xmlrpclib + +def today (): + today = datetime.today () + return xmlrpclib.DateTime (today) + +def load (): + fd = open ("/proc/loadavg", "r") + loadavg = fd.read () + sysload = loadavg.split () + return xmlrpclib.FloatType (sysload[0]) +\end{lstlisting} +\end{frame} + +\begin{frame}[fragile] +\frametitle{XML-RPC example in Python} +server.py\#p2 +\begin{lstlisting}[language=python] +server = SimpleXMLRPCServer (("localhost", + 8000)) + +server.register_function (today, "today") +server.register_function (load, "load") + +print "Listening on port 8000..." +server.serve_forever () +\end{lstlisting} +\end{frame} + + +\begin{frame}[fragile] +\frametitle{XML-RPC example in Python} +client.py\#p1 +\begin{lstlisting}[language=python] +import xmlrpclib +from datetime import datetime + +proxy = xmlrpclib.ServerProxy ( + "http://localhost:8000/") +\end{lstlisting} +\end{frame} + +\begin{frame}[fragile] +\frametitle{XML-RPC example in Python} +client.py\#p2 +\begin{lstlisting}[language=python] +today = proxy.today () +# today = 20140218T14:23:45 + +conv = datetime.strptime (today.value, + "%Y%m%dT%H:%M:%S") + +print "Today:", conv.strftime ( + "%d.%m.%Y, %H:%M") + +load = proxy.load () +print "system load:", load +\end{lstlisting} +\end{frame} + +\begin{frame}[fragile] +\frametitle{XML-RPC example in Python} +output: +\begin{lstlisting}[language=bash] + % python client.py +Today: 18.02.2014, 14:26 +system load: 0.45 +\end{lstlisting} +\end{frame} + +\begin{frame}[fragile] +\frametitle{XML-RPC example in Python} +http payload of today rpc call seen in wireshark: +\begin{lstlisting}[language=XML] + + + today + + +\end{lstlisting} +\end{frame} + +\begin{frame}[fragile] +\frametitle{XML-RPC example in Python} +http payload of today rpc response seen in wireshark: +\begin{lstlisting}[language=XML] + + + + + + + 20140218T14:26:25 + + + + + +\end{lstlisting} +\end{frame} + +\begin{frame} +\frametitle{SOAP/WSDL} +\begin{block}{Overview} +\begin{itemize} +\item WSDL (Web Services Description Language) + +describes the interface and spcecial datatypes +\item the SOAP protocol is used for communication +\item SOAP can be used with various transports: + +FTP, SMTP, HTTP(S), JMS +\item hopping is supported, with different transports +\item Client- / Serverarchitecture +\end{itemize} +\end{block} +\end{frame} + +\begin{frame} +\frametitle{SOAP/WSDL} +\begin{block}{Implementations} +\begin{itemize} +\item ZSI: Python +\item KDSOAP: Qt4/5 native Library (commercial) +\item gSOAP: C/C++ +\item Apache Axis2: C++, JAVA +\item Apache CXF: JAVA (+ other middleware protocols) +\item SOAP::WSDL: Perl +\item SOAP4R: Ruby +\item wsdl2objc: Objective C +\item .NET, mono +\end{itemize} +\end{block} +\end{frame} + +\begin{frame}[fragile] +\frametitle{SOAP example in Python/ZSI} +server.py +\begin{lstlisting}[language=python] +from datetime import datetime +from ZSI import dispatch + +def today (arg): + print "today arg:", arg + today = datetime.today () + return str (today) +def load (arg): + print "load arg:", arg + fd = open ("/proc/loadavg", "r") + loadavg = fd.read () + sysload = loadavg.split () + return sysload[0] + +dispatch.AsServer (port=8000, rpc=True) +\end{lstlisting} +\end{frame} + +\begin{frame}[fragile] +\frametitle{SOAP example in Python/ZSI} +client.py +\begin{lstlisting}[language=python] +from datetime import datetime +from ZSI.client import Binding + +b = Binding (url='http://localhost:8000/') +t = b.today (5) +# t = 2014-02-18 15:59:50.571927 +c = datetime.strptime (t, + "%Y-%m-%d %H:%M:%S.%f") +print "Today:", c.strftime ("%d.%m.%Y, %H:%M") +print b.load ("string") +\end{lstlisting} +\end{frame} + + +\begin{frame} +\frametitle{XMPP - Extensible Messaging and Presence Protocol} +\begin{block}{Overview} +\begin{itemize} +\item protocol for MOM based on XML +\item originally named Jabber +\item used for +\begin{itemize} + \item real-time Instant Messaging + \item publishing Presence Informations + \item Contactlist maintenance +\end{itemize} +\end{itemize} +\end{block} +\end{frame} + + +\begin{frame} +\frametitle{Extensible Messaging and Presence Protocol} +\begin{block}{IM for Industry??} +\begin{itemize} +\item free and open standard (IETF RFC 6120, 6121) +\item XMPP servers can be isolated, security is implemented (SASL, TLS) +\item TCP and HTTP(S) transports are supported +\item Priority support: multiple logins from same account, + +login with highest pority gets message +\item not just used for IM: +\begin{itemize} + \item smart grid + \item publish-subscribe systems + \item games + \item signalling for VoIP +\end{itemize} +\end{itemize} +\end{block} +\end{frame} + +\begin{frame} +\frametitle{Extensible Messaging and Presence Protocol} +\begin{block}{Extensible\dots} +\begin{itemize} +\item network management +\item collaboration tools +\item file sharing, gaming +\item remote systems control and monitoring +\item geolocation +\end{itemize} +\end{block} +\end{frame} + +\begin{frame} +\frametitle{Extensible Messaging and Presence Protocol} +\begin{block}{Implemmentations} +\dots too many to mention, have a look at + +http://xmpp.org/xmpp-software/ + +for libraries, clients and servers +\end{block} +\end{frame} + + +\begin{frame}[fragile] +\frametitle{XMPP Client Example} +xmpp\_client.cpp +\begin{lstlisting}[language=C++] +#include +#include "myclient.h" + +int main(int argc, char *argv[]) +{ + QCoreApplication app(argc, argv); + + MyClient client; + client.connectToServer("qtapp@localhost", + "test"); + + return app.exec(); +} +\end{lstlisting} +\end{frame} + +\begin{frame}[fragile] +\frametitle{XMPP Client Example} +myclient.h +\begin{lstlisting}[language=C++] +#include + +class MyClient : public QXmppClient +{ + Q_OBJECT + + public: + MyClient(); + ~MyClient(); + + public slots: + void message_rx(const QXmppMessage&); +}; +\end{lstlisting} +\end{frame} + +\begin{frame}[fragile] +\frametitle{XMPP Client Example} +myclient.cpp\#p1 +\begin{lstlisting}[language=C++] +#include +#include + +#include "myclient.h" + +MyClient::MyClient() : QXmppClient() +{ + bool check = connect(this, + SIGNAL(messageReceived(QXmppMessage)), + SLOT(message_rx(QXmppMessage))); + + Q_ASSERT(check); + Q_UNUSED(check); +} +\end{lstlisting} +\end{frame} + +\begin{frame}[fragile] +\frametitle{XMPP Client Example} +myclient.cpp\#p2 +\begin{lstlisting}[language=C++] +MyClient::~MyClient() { ; } + +void +MyClient::message_rx(const QXmppMessage& msg) +{ + QString from = msg.from(); + QString body = msg.body(); + + std::cout< org.enlightenment.FileManager \ + /org/enlightenment/FileManager \ + org.enlightenment.FileManager.OpenDirectory \ + /home/local +\end{verbatim} \end{frame} -\begin{frame} -\frametitle{Desktop Integration} -\begin{center} -\includegraphics[height=0.8\textheight]{images/dbus-hal.png} -\end{center} -Source: http://www.redhat.com +\begin{frame}[fragile] +\frametitle{System Integration} +e.g. hotplug events +\begin{verbatim} +% mdbus2 -s -l +[SIGNAL] +org.freedesktop.UDisks.DeviceAdded +/org/freedesktop/UDisks :1.25 +('/org/freedesktop/UDisks/devices/sdb',) +\end{verbatim} +\end{frame} + +\begin{frame}[fragile] +\begin{verbatim} +[SIGNAL] +org.freedesktop.DBus.ObjectManager.InterfacesAdded +/org/freedesktop/UDisks2 :1.40 +('/org/freedesktop/UDisks2/drives/WD_My_Passport_0748_57584D314335325839363238', +{'org.freedesktop.UDisks2.Drive': + {'Vendor': <'WD'>, 'Model': <'My Passport0748'>, + 'Revision': <'1015'>, 'Serial': <'57584D314335325839363238'>, + 'WWN': <''>, 'Id': <'WD-My-Passport-0748-57584D314335325839363238'>, + 'Configuration': <@a{sv} {}>, 'Media': <''>, + 'MediaCompatibility': <@as []>, 'MediaRemovable':, + 'MediaAvailable': , 'MediaChangeDetected': , + 'Size':, + 'TimeDetected': , + 'TimeMediaDetected': , + 'Optical': , OpticalBlank': , + 'OpticalNumTracks': , + 'OpticalNumAudioTracks': , + 'OpticalNumDataTracks': , + 'OpticalNumSessions': , + 'RotationRate': <-1>, 'ConnectionBus':<'usb'>, + 'Seat': <'seat0'>, 'Removable': , 'Ejectable': , + 'SortKey': <'01hotplug/1392720111627238'>, + 'CanPowerOff': , + 'SiblingId':<'/sys/devices/pci0000:00/0000:00:14.0/usb2/2-1/2-1:1.0'>}}) +\end{verbatim} +\end{frame} + +\begin{frame}[fragile] +\frametitle{Example: Session Bus Signals} +\begin{itemize} +\item have a look at the code +\item start pingserver and pingclient +\item monitor signals with 'mdbus2 -l' +\end{itemize} \end{frame} \subsection{CORBA} @@ -73,13 +567,40 @@ Source: http://www.redhat.com \end{block} \end{frame} +\begin{frame} +\frametitle{well-known implementations} +\begin{itemize} +\item omniORB: C++ / Python +\item ACE/TAO: C++ including RTCORBA support +\item MICO: C++ focus on security +\item JacORB: JAVA +\item IIOP.NET: .NET Remoting integration +\item ORBit2: C with C++ and Python bindings +\end{itemize} +\end{frame} + + \begin{frame} \frametitle{Functional Principle} \begin{center} -\includegraphics[height=0.8\textheight]{images/orb.jpg} +\includegraphics[width=1.0\textwidth]{images/orb.jpg} \end{center} \end{frame} + +\begin{frame} +\frametitle{Functional Principle} +\begin{block}{IDL Interface Description Language} +\begin{itemize} +\item write Interface Description +\item use IDL compiler to produce stubs and skeleton code +\item implement interfaces and use interfaces in native language +\item compile applications +\end{itemize} +\end{block} +\end{frame} + + \begin{frame} \frametitle{Functional Principle} \begin{block}{CORBA Services} -- cgit v1.2.3 From 276f95e75e21e16fb132ea682e6dbf8dec520738 Mon Sep 17 00:00:00 2001 From: Manuel Traut Date: Wed, 19 Feb 2014 08:10:15 +0100 Subject: middleware: update CORBA section - mention policies - added more details about abstractions (os, language, transports) Signed-off-by: Manuel Traut --- frameworks/middleware/pres_middleware.tex | 55 ++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 5 deletions(-) (limited to 'frameworks/middleware/pres_middleware.tex') diff --git a/frameworks/middleware/pres_middleware.tex b/frameworks/middleware/pres_middleware.tex index d147ceb..c2933ba 100644 --- a/frameworks/middleware/pres_middleware.tex +++ b/frameworks/middleware/pres_middleware.tex @@ -556,17 +556,17 @@ org.freedesktop.DBus.ObjectManager.InterfacesAdded \end{frame} \subsection{CORBA} + \begin{frame} \frametitle{Common Object Request Broker Architecture} -\begin{block}{abstracts} \begin{itemize} -\item operating systems -\item programming language -\item transport protocol +\item hosting of objects / RPC +\item typically a Client- / Serverarchitecture +\item one application can be Client and Server at the same time \end{itemize} -\end{block} \end{frame} + \begin{frame} \frametitle{well-known implementations} \begin{itemize} @@ -580,6 +580,35 @@ org.freedesktop.DBus.ObjectManager.InterfacesAdded \end{frame} +\begin{frame} +\frametitle{communication between different operating systems} +\begin{itemize} +\item hosting of objects is abstracted, e.g. ThreadPool +\item use of OS services, e.g. sockets is abstracted +\end{itemize} +\end{frame} + + +\begin{frame} +\frametitle{communication between programming languages} +\begin{itemize} +\item CORBA uses its own datatypes +\item datatype mapping needs to be implement for each language +\end{itemize} +\end{frame} + + +\begin{frame} +\frametitle{common transports} +\begin{itemize} +\item IIOP +\item socket +\item shared-memory +\item implementing own transports is possible +\end{itemize} +\end{frame} + + \begin{frame} \frametitle{Functional Principle} \begin{center} @@ -600,6 +629,22 @@ org.freedesktop.DBus.ObjectManager.InterfacesAdded \end{block} \end{frame} +\begin{frame} +\frametitle{Functional Principle} +\begin{block}{Policies} +\begin{itemize} +\item Server- or Clientsiede Policies +\item Run-time and compile-time Policies +\item e.g. for +\begin{itemize} +\item Lifetime of objects +\item Activation of objects +\item Thread Policies +\item Connection Polies +\end{itemize} +\end{itemize} +\end{block} +\end{frame} \begin{frame} \frametitle{Functional Principle} -- cgit v1.2.3 From 5ec6915a8f955c8ef72165e7392718a0b1f75bfa Mon Sep 17 00:00:00 2001 From: Manuel Traut Date: Wed, 19 Feb 2014 09:36:54 +0100 Subject: middleware: add celery section and example celery is a python framework for job execution Signed-off-by: Manuel Traut --- frameworks/middleware/examples/celery/README | 3 + frameworks/middleware/examples/celery/exec_task.py | 15 +++++ frameworks/middleware/examples/celery/test.py | 36 ++++++++++ frameworks/middleware/examples/celery/worker.sh | 2 + frameworks/middleware/pres_middleware.tex | 77 ++++++++++++++++++++++ 5 files changed, 133 insertions(+) create mode 100644 frameworks/middleware/examples/celery/README create mode 100644 frameworks/middleware/examples/celery/exec_task.py create mode 100755 frameworks/middleware/examples/celery/test.py create mode 100755 frameworks/middleware/examples/celery/worker.sh (limited to 'frameworks/middleware/pres_middleware.tex') diff --git a/frameworks/middleware/examples/celery/README b/frameworks/middleware/examples/celery/README new file mode 100644 index 0000000..9045901 --- /dev/null +++ b/frameworks/middleware/examples/celery/README @@ -0,0 +1,3 @@ +apt-get install python-celery +./worker.sh +./test.py diff --git a/frameworks/middleware/examples/celery/exec_task.py b/frameworks/middleware/examples/celery/exec_task.py new file mode 100644 index 0000000..9169250 --- /dev/null +++ b/frameworks/middleware/examples/celery/exec_task.py @@ -0,0 +1,15 @@ +import os + +from celery import Celery + +app = Celery ('tasks', broker='sqla+sqlite:///celerydb.sqlite', + backend='db+sqlite:///results.sqlite') + +@app.task +def execute (command): + return os.system (command) + +@app.task +def execute2 (command): + if os.system (command): + raise Exception ("command not found") diff --git a/frameworks/middleware/examples/celery/test.py b/frameworks/middleware/examples/celery/test.py new file mode 100755 index 0000000..7d79c8e --- /dev/null +++ b/frameworks/middleware/examples/celery/test.py @@ -0,0 +1,36 @@ +#!/usr/bin/python + +import sys +import traceback + +from exec_task import execute, execute2 + +execute.delay ("echo hello world") + +print "\n\n" + +result = execute.delay ("sleep 2") +print "result ready?", result.ready () +print "wait for result..." +ret = result.get (timeout=10) +print "task done", ret + +print "\n\n" + +result = execute.delay ("/bin/false") +print "/bin/false:", result.get (timeout=10) + +print "\n\n" + +result = execute2.delay ("/bin/treu") +try: + print "/bin/treu:", result.get (timeout=10) +except: + print "exception occured; backtrace:" + print result.traceback + +print "\n\n" + +result = execute2.delay ("/bin/true") +print "/bin/true:", result.get (timeout=10) + diff --git a/frameworks/middleware/examples/celery/worker.sh b/frameworks/middleware/examples/celery/worker.sh new file mode 100755 index 0000000..1705198 --- /dev/null +++ b/frameworks/middleware/examples/celery/worker.sh @@ -0,0 +1,2 @@ +#!/bin/sh +celery -A exec_task worker --loglevel=info diff --git a/frameworks/middleware/pres_middleware.tex b/frameworks/middleware/pres_middleware.tex index c2933ba..c2eacc7 100644 --- a/frameworks/middleware/pres_middleware.tex +++ b/frameworks/middleware/pres_middleware.tex @@ -445,6 +445,83 @@ MyClient::message_rx(const QXmppMessage& msg) \subsection{Celery} +\begin{frame} +\frametitle{Overview} +\begin{itemize} +\item Distributed Task Queue +\item based on message passing +\item real-time operation and scheduling +\item Tasks can be hosted on a single or on mulitple workers +\item synchronous and asynchronous execution +\item rate limit support +\end{itemize} +\end{frame} + +\begin{frame} +\frametitle{implementations} +\begin{itemize} +\item celery-project: Python +\item celery-php: PHP +\end{itemize} +\end{frame} + +\begin{frame} +\frametitle{celeryproject} +\begin{block}{supports multiple message broker} +\begin{itemize} +\item database: Django, or any supported by SQLAlchemy +\item RabbitMQ +\item Redis +\item Amazon SQS (experimental) +\end{itemize} +\end{block} +\end{frame} + +\begin{frame} +\frametitle{celeryproject} +\begin{block}{supports multiple result storage} +\begin{itemize} +\item database: any supported by SQLAlchemy +\item memcached +\item Redis +\item AMQP +\item Cassandra +\item IronCache +\end{itemize} +\end{block} +\end{frame} + +\begin{frame}[fragile] +\frametitle{celeryproject, example} +exec\_task.py +\begin{lstlisting}{language=python} +import os +from celery import Celery + +app = Celery ('tasks', broker='sqla+sqlite:///celerydb.sqlite) + +@app.task +def execute (command): + os.system (command) +\end{lstlisting} +\end{frame} + +\begin{frame}[fragile] +\frametitle{celeryproject, example} +test.py +\begin{lstlisting}{language=python} +from exec_task import execute + +execute.delay ("echo hello world") +\end{lstlisting} + +start the example: +\begin{lstlisting}{language=bash} +term1% celery -A exec_task worker +term2% ./test.py +\end{lstlisting} +\dots an example using return values and exceptions is in the example dir +\end{frame} \subsection{DDS} -- cgit v1.2.3 From 445b026710cd33745e13e952f25288b4fd87cd1e Mon Sep 17 00:00:00 2001 From: Manuel Traut Date: Wed, 19 Feb 2014 09:52:10 +0100 Subject: middleware: don't mention DDS there is only one open-source implementation and the topic is quiet to complex for a short overview! Signed-off-by: Manuel Traut --- frameworks/middleware/pres_middleware.tex | 6 ------ 1 file changed, 6 deletions(-) (limited to 'frameworks/middleware/pres_middleware.tex') diff --git a/frameworks/middleware/pres_middleware.tex b/frameworks/middleware/pres_middleware.tex index c2eacc7..b8ccce1 100644 --- a/frameworks/middleware/pres_middleware.tex +++ b/frameworks/middleware/pres_middleware.tex @@ -9,7 +9,6 @@ \item Overview \item XML based Middleware \item Celery -\item DDS \item D-Bus \item CORBA \end{itemize} @@ -79,7 +78,6 @@ and for what they can be used. \begin{itemize} \item XML based Middleware \item Celery - Job Queue Protocol -\item DDS - Data Distribution Service \item D-Bus - MOM \item CORBA - Common Object Request Broker \end{itemize} @@ -524,10 +522,6 @@ term2% ./test.py \end{frame} -\subsection{DDS} - - - \subsection{D-Bus} \begin{frame} -- cgit v1.2.3 From 2f46ad6a6f7393dc7898672a7ea3337395bafae9 Mon Sep 17 00:00:00 2001 From: Manuel Traut Date: Wed, 19 Feb 2014 10:00:49 +0100 Subject: middleware: add conclusion Signed-off-by: Manuel Traut --- frameworks/middleware/pres_middleware.tex | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'frameworks/middleware/pres_middleware.tex') diff --git a/frameworks/middleware/pres_middleware.tex b/frameworks/middleware/pres_middleware.tex index b8ccce1..a658f83 100644 --- a/frameworks/middleware/pres_middleware.tex +++ b/frameworks/middleware/pres_middleware.tex @@ -771,4 +771,16 @@ org.freedesktop.DBus.ObjectManager.InterfacesAdded \end{block} \end{frame} +\subsection{Conclusion} +\begin{frame} +\frametitle{Conclusion} +\begin{itemize} +\item many frameworks available +\item different kind of abstraction +\item special frameworks for special problems +\item which framework is best for my problem? +\item is it helpful to use multiple frameworks? +\end{itemize} +\end{frame} + \input{tailpres} -- cgit v1.2.3