\mode* % Reset \mode<all> from slides.tex

\section{\en{Overview of Sugar and GTK+}\es{Visión general de Sugar y GTK+}}

\note{Before starting, ask how everyone got on with the exercises from part 2.}

\en{The Sugar platform is what runs on the XO. Sugar itself is written in
Python, but uses a system called GTK+ as its underlying UI toolkit. GTK+ is a
popular UI toolkit, used by many projects on Linux (not just on the XO).}
\es{La plataforma de Sugar es lo que se ejecuta en la XO. Sugar sí está escrito
en Python, pero utiliza un sistema llamado GTK+ como su kit de herramientas de
interfaz de usuario (IU) subyacente. GTK+ es un popular juego de herramientas de
interfaz de usuario, que se utiliza por muchos proyectos en Linux (y no sólo en
la XO).}

\en{Sugar's distinctive appearance is due to a theme it applies to the default
GTK+ widgets. Without this theme, activities on the XO would look very similar
to normal Linux programs (such as gedit).}
\es{El aspecto distintivo de Sugar es debido a un tema que se aplica a los
widgets GTK+ predeterminados. Sin este tema, las actividades en la XO se vería
muy similar a los programas normales de Linux (como gedit).}

\en{As with Python, there are two major versions of GTK+ available at the
moment: GTK+~2 and GTK+~3. GTK+~3 is the recommended version, and is available
on the XO. All software should be written using GTK+~3 using GIR (GObject
Introspection) and \emph{not} PyGTK (which is out of date).}
\es{Al igual que con Python, hay dos versiones principales de GTK+ disponibles
en este momento: GTK+~2 y GTK+~3. GTK+~3 es la versión recomendada, y está
disponible en la XO. Todo el software debe ser escrito usando GTK+~3 y GIR
(introspección GObject) y \emph{no} PyGTK (que es obsoleta).}

\en{Similarly, there are two versions of Sugar code available: \texttt{sugar}
and \texttt{sugar3}. \texttt{sugar} uses GTK+~2, whereas \texttt{sugar3} uses
GTK+~3. All new software should be written using \texttt{sugar3}.}
\es{Del mismo modo, hay dos versiones de código de Sugar disponibles:
\texttt{sugar} y \texttt{sugar3}. \texttt{sugar} usa GTK+~2, mientras que
\texttt{sugar3} usa GTK+~3. Todas las novedades software debe ser escrito con
\texttt{sugar3}.}

\begin{frame}{\en{Sugar and GTK+}\es{Sugar y GTK+}}
\begin{itemize}
    \item{\en{All XO activities use Sugar}
          \es{Todas las actividades XO utilizan Sugar}}
    \item{\en{Sugar is built on GTK+~3}\es{El Sugar se basa en GTK+~3}}
    \item{\en{Use \texttt{sugar3} and GTK+~3}
          \es{Debe utilizar \texttt{sugar3} y GTK+~3}}
\end{itemize}
\end{frame}


\section{\en{Introduction to GTK+}\es{Introducción a GTK+}}

\en{GTK+ is based on the concept of a hierarchy of \emph{widgets}. A widget is
a single graphical control, such as a button, some text, a toolbar, or a
window. These widgets are built into a hierarchy, with child widgets inside
parent widgets. For example, when a button is shown next to an image, a menu bar
and a label in a window, this widget hierarchy is used:}
\es{GTK+ se basa en el concepto de una jerarquía de \emph{widgets}. Un widget es
un control gráfico único, tal como un botón, un texto, una barra de
herramientas, o una ventana. Estos widgets están integradas en una jerarquía,
con widgets hijos dentro de los widgets de los padres. Por ejemplo, cuando se
muestra un botón al lado de la imagen, una barra de menús y una etiqueta en una
ventana, se utiliza esta jerarquía de controles:}

\begin{frame}{\en{GTK+ widget hierarchy}\es{Jerarquía de widgets de GTK+}}
\begin{itemize}
    \item{\texttt{Gtk.Window}\begin{itemize}
        \item{\texttt{Gtk.Box}\begin{itemize}
            \item{\texttt{Gtk.MenuBar}}
            \item{\texttt{Gtk.Label}}
            \item{\texttt{Gtk.Image}}
            \item{\texttt{Gtk.Button}}
        \end{itemize}}
    \end{itemize}}
\end{itemize}
\end{frame}

\begin{frame}{\en{GTK+ widget hierarchy}\es{Jerarquía de widgets de GTK+}}
\begin{figure}[h!]
    \centering
    \includegraphics[width=0.4\textwidth]{example-ui.png}
    \caption{\en{The example UI.}
             \es{Un ejemplo de un IU.}}
    \label{fig:example-ui}
\end{figure}
\end{frame}

\en{Widgets are roughly divided between normal controls and layout containers
(such as \texttt{Gtk.Box} in the example hierarchy). Other code in GTK+ supports
key bindings, drag-and-drop and the clipboard.}
\es{Widgets están divididos más o menos entre los controles normales y
contenedores de diseño (como \texttt{Gtk.Box} en la jerarquía de ejemplo). Otro
código en GTK+ soporta atajos de teclado, arrastrar y soltar y el portapapeles.}

\note{Give an interactive demo of Glade and \texttt{example-ui.ui} now.}

\en{\emph{Glade} is a popular tool for building UIs with GTK+. It isn't
normally used when creating Sugar activities, but is useful for exploring the
widget hierarchy.}
\es{\emph{Glade} es una herramienta popular para la creación de IUs con GTK+. No
se suele utilizar cuando se crean actividades para Sugar, pero es útil para
explorar la jerarquía de widgets.}


\section{\en{Building an interactive UI}\es{Construcción de una IU interactiva}}

\en{To build a UI in GTK+, construct a Python object for each widget, and then
call methods on the container widgets to add child widgets to parents and thus
construct a hierarchy.}
\es{Para construir una IU en GTK+, construir un objeto de Python para cada
widget, y luego llamar a métodos en los widgets de contenedores para añadir
hijos a los padres y así la construcción de una jerarquía.}

\begin{frame}[fragile]
\frametitle{\en{Constructing a GTK+ widget hierarchy}
            \es{Construcción de una jerarquía de widgets de GTK+}}
\begin{lstlisting}[language=Python,basicstyle={\ttfamily\footnotesize}]
from gi.repository import Gtk

window = Gtk.Window(title='Hola Mundo')

# Crear widget contenedor.
box = Gtk.Box()
box.set_orientation(Gtk.Orientation.VERTICAL)
window.add(box)
# Crear una etiqueta, una imagen y un boton.
label = Gtk.Label('Logo OLPC:')
box.add(label)
image = Gtk.Image()
image.set_from_file('olpc-square_logo.jpg')
box.add(image)
button = Gtk.Button()
button.set_label('Boton')
box.add(button)

# Mostrar la IU.
window.show_all()
Gtk.main()
\end{lstlisting}
\end{frame}


\en{In this example, the last two lines of code require explanation. Every GTK+
widget can be hidden, and all are hidden by default. Before they can be used by
the user they need to be shown --- either by calling the \texttt{show()} method
on each widget, or by calling the \texttt{show\_all()} method on one of the
container widgets which contains them (such as the top-level window, for
example).}
\es{En este ejemplo, las dos últimas líneas de código requieren de una
explicación. Cada widget de GTK+ se puede ocultar, y todos se oculta de manera
predeterminada. Antes de que puedan ser utilizados por el usuario, es necesario
que se muestra --- o bien llamando al método \texttt{show()} de cada widget, o
llamando al método \texttt{show\_all()} en uno de los widgets de contenedor que
los contiene (como la ventana de nivel superior, por ejemplo).}

\en{The last line of code starts the GTK+ \emph{main loop}. This is what
handles user input and drawing of widgets in a UI. The main loop is an infinite
loop which:}
\es{La última línea de código se inicia el \emph{bucle principal} de GTK+. Esto
es lo que se encarga de la entrada del usuario y el dibujo de widgets en una IU.
El bucle principal es un bucle infinito que:}

\begin{frame}{\en{GTK+ main loop}\es{Bucle principal de GTK+}}
\begin{enumerate}
    \item{\en{Receives input events from the user (such as mouse movements or
              keyboard button presses)}
          \es{Recibe los eventos de entrada del usuario (por ejemplo, los
              movimientos del ratón o pulsaciones de botones del teclado)}}
    \item{\en{Calls \emph{event handlers} for those events}
          \es{Llamadas \emph{controladores de eventos} para los eventos}}
    \item{\en{Waits for the next input event, then loops}
          \es{Espera a que el próximo evento de entrada, entonces se realiza un
              bucle}}
\end{enumerate}
\end{frame}
% TODO: Diagram of the main loop?

\en{This is a standard event-based programming model. It means that after
calling the \texttt{Gtk.main()} function, all code in your program is executed
inside callbacks from this main loop. A callback is where the main loop calls
a function provided by your code: the main loop \emph{calls back} to your
code.}
\es{Este es un modelo de programación estándar basado en eventos. Esto significa
que después de llamar a la función \texttt{Gtk.main()}, todo el código de su
programa se ejecuta dentro de callbacks de este bucle principal. Un callback es
donde el bucle principal llama a una función proporcionada por su código: el
bucle principal \emph{vuelve a llamar} a su código.}


\section{\en{Signal handling}\es{Manejo de señales}}

\en{Almost all callbacks in GTK+ are for \emph{signals} from widgets. These
correspond to events on the widgets. For example, the \texttt{Button} widget
emits a \texttt{clicked} signal when the user clicks it. Zero or more callbacks
can be \emph{connected} for this signal, all of which will be called from the
main loop when the button is clicked.}
\es{Casi todas las callbacks en GTK+ son para señales de widgets. Estos
corresponden a eventos en los widgets. Por ejemplo, el widget \texttt{Button}
emite una señal de \texttt{clicked} cuando el usuario hace clic en él. Cero o
más callbacks se pueden conectar a esta señal, todos los cuales serán llamados
desde el bucle principal cuando se hace clic en el botón.}

\en{A signal handler can be connected by calling the \texttt{connect()} method,
passing the name of the signal, and the name of the function to use as a
callback. This function must accept the parameters specified in the
documentation for the signal. It is common practice (though not required) to
suffix callback function names with \texttt{\_cb} (which stands for
`callback').}
\es{Un manejador de la señal se puede conectar mediante una llamada al método
\texttt{connect()}, pasando el nombre de la señal, y el nombre de la función
para utilizarla como un callback. Esta función debe aceptar los parámetros
especificados en la documentación de la señal. Es una práctica común (aunque no
es obligatorio) a los nombres de funciones callback con sufijo \texttt{\_cb}
(que significa `callback').}

\en{In this example, we subclass \texttt{Gtk.Window} so that the signal callback
can be included as a private method of the window. This is a tidy way to do
things, as it prevents callbacks from different windows getting mixed up.}
\es{En este ejemplo, subclase \texttt{Gtk.Window} de modo que el callback de la
señal puede ser incluido como un método privado de la ventana. Esta es una
manera ordenada de hacer las cosas, ya que evita que callbacks de diferentes
ventanas se mezclen.}

\begin{frame}[fragile]
\frametitle{\en{GTK+ signal handlers}\es{Manejadores de señales de GTK+}}
\begin{lstlisting}[language=Python,basicstyle={\ttfamily\footnotesize}]
# Subclase Window para crear una ventana.
class MyWindow(Gtk.Window):
    def __init__(self):
        super(MyWindow, self).__init__()

        # Crear y anadir un boton.
        button = Gtk.Button('Hola Mundo')
        button.show()
        self.add(button)

        # Conecte un manejador de senales.
        button.connect('clicked',
            self.__button_clicked_cb)

    def __button_clicked_cb(self, button):
        print('Boton se hizo clic!')

window = MyWindow()
window.show()
Gtk.main()
\end{lstlisting}
\end{frame}

\en{Signal handling is one of the key features of GTK+, and is worth
understanding.}
\es{Manipulación de las señales es una de las características principales de
GTK+, y vale la pena comprensión.}

\begin{frame}{\en{Signal handling tutorials}\es{Tutoriales sobre el manejo de señales}}
\begin{itemize}
    \item{\url{\en{https://developer.gnome.org/gnome-devel-demos/stable/signals-callbacks.py.html.en}
               \es{https://developer.gnome.org/gnome-devel-demos/stable/signals-callbacks.py.html.es}}}
    \item{\url{http://python-gtk-3-tutorial.readthedocs.org/en/latest/basics.html\#main-loop-and-signals}}
\end{itemize}
\end{frame}


\section{\en{GTK+ documentation}\es{Documentación de GTK+}}

\en{GTK+ is a huge library, and covering it in detail here would take too long.
There are several good tutorials for using GTK+ in Python, available in several
languages. It is recommended that you read them and practice the exercises they
give. The \href{https://developer.gnome.org/gtk3/stable/ch03.html}{GTK+ widget
gallery} contains screenshots of every GTK+ widget, and links to their API
documentation.}
\es{GTK+ es una gran librería, y cubriendo en detalle aquí tomaría demasiado
tiempo. Hay varios buenos tutoriales para el uso de GTK+ en Python, disponible
en varios idiomas. Se recomienda que los lea y aplique los ejercicios que dan.
La \href{https://developer.gnome.org/gtk3/stable/ch03.html}{galería de widgets
de GTK+} contiene imágenes de todos los widgets de GTK+, y enlaces a la
documentación de la API.}

\begin{frame}{\en{GTK+ tutorials}\es{Tutoriales de GTK+}}
\begin{itemize}
    \item{\en{\url{https://developer.gnome.org/gnome-devel-demos/stable/tutorial.py.html.en}}
          \es{\url{https://developer.gnome.org/gnome-devel-demos/stable/tutorial.py.html.es}}}
    \item{\en{\url{https://developer.gnome.org/gnome-devel-demos/stable/beginner.py.html.en}}
          \es{\url{https://developer.gnome.org/gnome-devel-demos/stable/beginner.py.html.es}}}
    \item{\url{http://python-gtk-3-tutorial.readthedocs.org/en/latest/index.html}}
    \item{\url{https://developer.gnome.org/gtk3/stable/ch03.html}}
\end{itemize}
\end{frame}

\en{The GTK+ API documentation is currently only available for the C
programming language. However, converting function names between C and Python
is fairly simple, so you can use the C API documentation for Python.}
\es{La documentación del API de GTK+ sólo está disponible para el lenguaje de
programación C. Sin embargo, la conversión de nombres de funciones entre C y
Python es bastante simple, por lo que puede utilizar la documentación de la API
C con Python.}

\en{To convert a C function name to a Python method name, remove underscores,
change it to camelcase, and separate `gtk', the class name, and the method
name. Python constructors become \texttt{*\_new()} functions in C. Constant
values are entirely capitalised in C, and only partially capitalised in
Python.}
\es{Para convertir un nombre de función C para un nombre de método Python,
retire subrayado, cambiar a CamelCase, y separado `gtk' del nombre de la clase y
del nombre del método. Constructores Python vuelven funciones \texttt{*\_new()}
en C. Valores constantes están completamente activados en C, y sólo parcialmente
capitalizado en Python.}

\begin{frame}{\en{GTK+ API documentation}\es{Documentación de la API de GTK+}}
\begin{block}{}
\url{https://developer.gnome.org/gtk3/stable/gtkobjects.html}
\end{block}
\begin{block}{\en{Conversion}\es{Conversión}}
{\small\begin{align*}
    \mathbf{Python} &\leftrightarrow \mathbf{C} \\
    \mathtt{Gtk.Window.set\_title()} &\leftrightarrow
        \mathtt{gtk\_window\_set\_title()} \\
    \mathtt{Gtk.Button()} &\leftrightarrow \mathtt{gtk\_button\_new()} \\
    \mathtt{Gtk.ToggleButton.get\_active()} &\leftrightarrow
        \mathtt{gtk\_toggle\_button\_get\_active()} \\
    \mathtt{Gtk.Orientation.VERTICAL} &\leftrightarrow
        \mathtt{GTK\_ORIENTATION\_VERTICAL}
\end{align*}}
\end{block}
\end{frame}


\section{\en{Writing an activity}\es{Escribir una actividad}}

\en{Fundamentally, a Sugar activity is a GTK+ application which provides a
single GTK+ \texttt{Window} widget for the activity to use. This window forms
the root of the activity's widget hierarchy, just as in a normal GTK+
application. Events and callbacks are handled similarly.}
\es{Fundamentalmente, una actividad de Sugar es una aplicación de GTK+ que
proporciona un solo widget \texttt{Window} de GTK+ para la actividad de usar.
Esta ventana se forma la raíz de la jerarquía de widgets de la actividad, al
igual que en una aplicación normal de GTK+. Eventos y callbacks se manejan de
manera similar.}

\en{To create an activity, subclass the
\texttt{sugar3.activity.activity.Activity} class
in Python. This \texttt{Activity} class provides a method to parent your
activity's widget tree: \texttt{set\_canvas()}. By creating a widget hierarchy
and passing it to this function, the interface for an activity can be created.}
\es{Para crear una actividad, debe subclase de la clase
\texttt{sugar3.activity.activity.Activity} en Python. Esta clase
\texttt{Activity} proporciona un método para adjuntar la jerarquía de widgets de
su actividad: \texttt{set\_canvas()}. Mediante la creación de una jerarquía de
widgets y pasarlo a esta función, se puede crear la interfaz para una
actividad.}

\begin{frame}[fragile]
\frametitle{\en{Creating an activity UI}\es{Creación de una IU de la actividad}}
\begin{lstlisting}[language=Python,basicstyle={\ttfamily\small}]
from sugar3.activity import activity

class HolaMundoActivity(activity.Activity):
    def __init__(self, handle):
        super(HolaMundoActivity, self).__init__(handle)

        box = Gtk.Box()
        label = Gtk.Label('Hola Mundo!')
        button = Gtk.Button('Boton')

        label.show()
        box.add(label)

        button.show()
        box.add(button)

        box.show()
        self.set_canvas(box)
\end{lstlisting}
\end{frame}

\en{When subclassing \texttt{sugar3.activity.activity.Activity}, three methods
must be implemented. \texttt{\_\_init()\_\_} is the normal object constructor,
and is called when your activity is started by the user. The \texttt{handle}
parameter provides the activity ID and access to sharing services (which aren't
covered here).}
\es{Al crear subclases de \texttt{sugar3.activity.activity.Activity}, tres
métodos se deben implementar. \texttt{\_\_init\_\_()} es el constructor de
objeto normal, y se llama cuando su actividad se inicia por el usuario. El
parámetro \texttt{handle} proporciona el ID de la actividad y el acceso a
servicios para compartir (que no se cubre en este manual).}

\en{\texttt{read\_file} is called after \texttt{\_\_init\_\_} when resuming an
activity from the Journal. The \texttt{file\_path} parameter is the path of a
file containing the saved Journal data. Similarly, \texttt{write\_file} is
called when the user wants to save the activity to the Journal (either
explicitly, when closing the activity, or when switching to another activity),
and the \texttt{file\_path} is the path of a file which the Journal entry
should be saved to.}
\es{\texttt{read\_file} es llamada después \texttt{\_\_init\_\_} cuando se
reanuda la actividad en el Diario. El parámetro \texttt{file\_path} es la ruta
de un archivo que contiene los datos de diario guardados. Del mismo modo,
\texttt{write\_file} se llama cuando el usuario desea guardar la actividad con
el Diario (ya sea de manera explícita, al cerrar la actividad, o cuando se
cambia a otra actividad), y el \texttt{file\_path} es la ruta de un archivo que
la entrada de Diario debe ser guardado en.}

\begin{frame}{\en{Required activity methods}
              \es{Métodos necesarios para actividades}}
\begin{itemize}
    \item{\texttt{\_\_init\_\_(self, handle)}}
    \item{\texttt{read\_file(self, file\_path)}}
    \item{\texttt{write\_file(self, file\_path)}}
\end{itemize}
\end{frame}

\en{The \texttt{Activity} class provides several other methods (apart from
\texttt{set\_canvas()}) which can be called from within the activity code to
perform various tasks such as forcing the activity to be saved to the Journal,
closing the activity, and starting to share the activity on the network. Look
at the
\href{https://github.com/sugarlabs/sugar-toolkit-gtk3/blob/master/src/sugar3/activity/activity.py}{source code} for \texttt{sugar3.activity.activity.Activity} for
details.}
\es{La clase \texttt{Activity} ofrece varios métodos (además de
\texttt{set\_canvas()}), que se puede llamar desde dentro del código de
actividad para realizar diversas tareas, tales como obligar a la actividad que
se guardan en el Diario, el cierre de la actividad, y empezar a compartir la
actividad en la red. Mira
\href{https://github.com/sugarlabs/sugar-toolkit-gtk3/blob/master/src/sugar3/activity/activity.py}{el código} de
\texttt{sugar3.activity.activity.Activity} para más detalles.}

\en{The most important thing to do in the \texttt{\_\_init\_\_} method is to
add a toolbar to the activity. Amongst other things, this adds a close button
to the activity.}
\es{La cosa más importante que hacer en el método \texttt{\_\_init\_\_} es
agregar una barra de herramientas a la actividad. Entre otras cosas, esto se
agrega un botón de cierre de la actividad.}

\begin{frame}[fragile]
\frametitle{\en{Adding a toolbar}\es{Adición de una barra de herramientas}}
\begin{lstlisting}[language=Python]
def __init__(self, handle):
    # Cree la caja de herramientas de
    # actividad estandar.
    toolbar_box = ToolbarBox()
    self.set_toolbar_box(toolbar_box)
    toolbar_box.show()

    main_toolbar = toolbar_box.toolbar

    activity_button = widgets.ActivityToolbarButton(self)
    main_toolbar.insert(activity_button, 0)
    activity_button.show()
\end{lstlisting}
\end{frame}


\section{\en{Packaging an activity}\es{Empaquetar una actividad}}

\en{All the files for an activity are bundled together in a special format to
form a single \texttt{.xo} file which can be executed by the XO. An \texttt{.xo}
file is just a renamed Zip archive, but it must contain three key files:
\texttt{setup.py}, \texttt{activity/activity.info} and
\texttt{activity/activity.svg}.}
\es{Todos los archivos de una actividad se agrupan en un formato especial para
formar un único archivo \texttt{.xo} que puede ser ejecutado por el XO. Un
archivo \texttt{.xo} es sólo un archivo Zip cambiado de nombre, pero debe
contener tres archivos principales: \texttt{setup.py},
\texttt{activity/activity.info} y \texttt{activity/activity.svg}.}

\es{Los nombres de archivo en Inglés no se deben traducir al Español, como el
código de Sugar espera encontrar los nombres de los archivos exactos.}

\begin{frame}{\en{XO bundle format}\es{Formato de los paquetes de XO}}
\begin{itemize}\item{\texttt{\en{ActivityName.activity}\es{NombreDeActividad.activity}}\begin{itemize}
    \item{\texttt{\en{activityname.py}\es{nombredeactividad.py}}}
    \item{\texttt{setup.py}}
    \item{\texttt{activity/}\begin{itemize}
        \item{\texttt{activity.info}}
        \item{\texttt{activity.svg}}
    \end{itemize}}
    \item{\texttt{icons/}\begin{itemize}
        \item{\en{any-custom-icons.svg}\es{los-iconos-personalizados.svg}}
        \item{$\cdots$}
    \end{itemize}}
    \item{\texttt{po/}\begin{itemize}
        \item{\texttt{de.po}}
        \item{\texttt{es.po}}
        \item{\texttt{it.po}}
        \item{$\cdots$}
        \item{\texttt{\en{ActivityName.pot}\es{NombreDeActividad.pot}}}
    \end{itemize}}
\end{itemize}}\end{itemize}
\end{frame}

\en{\texttt{activity.info} contains metadata about the activity, such as its
name, description, ID, version and software licence. \texttt{activity.svg} is
the icon for the activity. \texttt{setup.py} is used during development to build
and test the activity, and is the same for all activities.
\texttt{activityname.py} contains the code for the activity, and can have any
name --- the actual filename is referenced in \texttt{activity.info}.}
\es{\texttt{activity.info} contiene metadatos acerca de la actividad, tales como
su nombre, descripción, ID, la versión y licencia de software.
\texttt{activity.svg} es el icono de la actividad. \texttt{setup.py} se utiliza
durante el desarrollo para construir y probar la actividad, y es el mismo para
todas las actividades. \texttt{nombredeactividad.py} contiene el código para la
actividad, y puede tener cualquier nombre --- el nombre de archivo real se hace
referencia en la \texttt{activity.info}.}

% TODO: Add a lstdefinelanguage for this if I get time.
\begin{frame}[fragile]
\frametitle{\texttt{activity.info}}
\begin{lstlisting}
[Activity]
name = Pascal Triangle
summary = Addition game using Pascal's triangle.
activity_version = 1
host_version = 1
bundle_id = hn.educatrachos.pascaltriangle
icon = activity
exec = sugar-activity pascaltriangle.PascalTriangleActivity
license = GPLv2+
\end{lstlisting}
\end{frame}

\begin{frame}[fragile]
\frametitle{\texttt{setup.py}}
\begin{lstlisting}[language=Python]
#!/usr/bin/env python
from sugar.activity import bundlebuilder
if __name__ == "__main__":
    bundlebuilder.start()
\end{lstlisting}
\end{frame}

\en{The \texttt{icons} directory is optional, and contains any custom icons
which your activity uses (for example, in toolbars). The XO ships a few standard
icons, but not many, so activities have to provide their own in many cases.}
\es{La carpeta \texttt{icons} es opcional, y contiene los iconos
personalizados que utiliza su actividad (por ejemplo, en las barras de
herramientas). La XO proporciona unos iconos estándar, pero no muchos, por lo
que las actividades tienen que proporcionar su propia en muchos casos.}

\en{The \texttt{po} directory is also optional (though highly recommended) and
contains translations of all the UI strings in the activity, so it can be run
in other languages. By convention, all UI strings in Python are written in
English --- so when writing an activity, you need to provide a Spanish
translation as \texttt{es.po}. \texttt{ActivityName.pot} is a template for the
\texttt{.po} files. Internationalisation will be covered in more detail later.}
\es{La carpeta \texttt{po} también es opcional (aunque muy recomendable) y
contiene las traducciones de todas las cadenas de la IU en la actividad, por lo
que se puede ejecutar en otros idiomas. Por convención, todas las cadenas de la
IU en Python están escritos en Inglés --- así cuando se escribe una actividad,
es necesario proporcionar una traducción al Español como \texttt{es.po}.
\texttt{NombreDeActividad.pot} es una plantilla para los archivos \texttt{.po}.
Internacionalización se explica con más detalle más adelante.}


\section{\en{Version control}\es{Control de versiones}}

\en{Creating a new activity starts with creating the directory structure for it,
then by setting up version control. Version control is a way of cataloguing the
history of development of some code by storing multiple \emph{revisions} of each
file. This allows examination of the changes between each revision (as the
software is developed), and also allows the code to be reverted to a previous
revision if problems are found in later code. Importantly, version control
systems make it easy to distribute code across the Internet, by \emph{pushing}
it to remote repositories.}
\es{Crear una nueva actividad se inicia con la creación de la estructura de
carpetas para que, a continuación, mediante el establecimiento de control de
versiones. El control de versiones es una manera de catalogar la historia del
desarrollo de un código mediante el almacenamiento de múltiples
\emph{revisiones} de cada archivo. Esto permite que el examen de los cambios
entre cada revisión (como se desarrolla el software), y también permite que el
código para revertir a una revisión anterior si los problemas se encuentran en
el código más adelante. Es importante destacar que los sistemas de control de
versiones facilitan la distribución del código a través de Internet,
\emph{empujándolo} a los repositorios remotos.}

\en{The recommended version control system for use with Sugar activities is
`git', a popular system used by many open source projects. There isn't
time to give a full introduction to git here, so only a few commands
will be demonstrated.}
\es{El sistema de control de versiones se recomienda su uso en las actividades
de Sugar es `git', un sistema popular y utilizado por muchos proyectos de
software libre. No hay tiempo para dar una introducción completa a git aquí, así
que sólo unos pocos comandos se demostrarán.}

\en{Executed from a terminal, in the activity's directory, \texttt{git~init}
creates a new git repository. (This only needs to be perfomed once.)
\texttt{git~add} adds files to git's list of staged files, which can be seen by
running \texttt{git~status}. \texttt{git~commit} creates a new revision in the
repository, with the changes which were staged using \texttt{git~add}. The whole
repository can then be pushed to a server. \texttt{git~log} shows the existing
revisions in the repository.}
\es{Ejecutado desde un terminal, en la carpeta de la actividad,
\texttt{git~init} crea un nuevo repositorio de git. (Necesario sólo una vez.)
\texttt{git~add} agrega archivos a la lista de archivos de git organizaron, que
se puede ver mediante la ejecución de \texttt{git~status}. \texttt{git~commit}
crea una nueva revisión en el repositorio, con los cambios que se organizaron
con \texttt{git~add}. Todo el repositorio puede entonces ser empujada a un
servidor. \texttt{git~log} muestra las revisiones existentes en el repositorio.}

\begin{frame}{\en{Introduction to git}\es{Introducción a git}}
\begin{itemize}
    \item{\texttt{git~init}}
    \item{\texttt{git~add \en{file1.py file2.py}\es{archivo1.py archivo2.py} \dots}}
    \item{\texttt{git~status}}
    \item{\texttt{git~commit}}
    \item{\texttt{git~log}}
\end{itemize}
\end{frame}

\begin{frame}{\en{git resources}\es{Recursos para git}}
\begin{block}{\en{Introductions}\es{Introducciones}}
\begin{itemize}
    \item{\url{http://try.github.io/}}
    \item{\url{http://gitimmersion.com/}}
\end{itemize}
\end{block}
\begin{block}{\en{References}\es{Referencias}}
\begin{itemize}
    \item{\url{http://git-scm.com/book\es{/es}}}
    \item{\url{http://gitref.org/}}
\end{itemize}
\end{block}
\end{frame}


\en{Building the XO bundle is achieved using \texttt{setup.py}. When developing
locally, run \texttt{./setup.py~dev} from a terminal in the activity's directory
to set up the activity to run on your computer with \texttt{sugar-emulator}
(discussed later). To build the \texttt{.xo} file for distribution, run
\texttt{./setup.py~dist\_xo}. When building the \texttt{.xo} file, the script
will ignore files which aren't committed to git, so ensure all relevant files
(but not files which have been automatically generated) have been added to git
using \texttt{git~add}.}
\es{Construyendo el paquete XO se consigue utilizando \texttt{setup.py}. En el
desarrollo a nivel local, ejecute \texttt{./setup.py~dev} desde un terminal en
la carpeta de la actividad para establecer la actividad se ejecute en su
equipo con \texttt{sugar-emulator} (explicado más adelante). Para generar el
archivo \texttt{.xo} para la distribución, ejecute \texttt{./setup.py~dist\_xo}.
Cuando se construye el archivo \texttt{.xo}, el script pasará por alto los
archivos que no se han añadido a git, para asegurar que todos los archivos
relevantes (pero no los archivos que se han generado de forma automática), se
han añadido git utilizando \texttt{git~add}.}

\begin{frame}{\texttt{setup.py}}
\begin{itemize}
    \item{\texttt{./setup.py~dev}}
    \item{\texttt{./setup.py~dist\_xo}}
\end{itemize}
\end{frame}


\section{\en{Emulating Sugar for testing}\es{Emulando Sugar para probar}}

\en{A recommended way to develop activities is to use \texttt{sugar-emulator},
a program which can be installed on most desktop Linux distributions. It allows
the Sugar environment to be emulated on a desktop, meaning a new activity can
be tested without being copied over to a physical XO.}
\es{Una forma recomendada para el desarrollo de actividades es utilizar
\texttt{sugar-emulator}, un programa que se puede instalar en la mayoría de las
distribuciones de Linux. Permite el entorno Sugar a emular en un escritorio, lo
que significa una nueva actividad puede ser probado sin copiarse a un XO
físico.}

\en{To run \texttt{sugar-emulator}, simply type its name into the terminal. For
extra debugging output, also set the \texttt{SUGAR\_LOG\_LEVEL} environment
variable. To run the emulator in a different language, set the \texttt{LANG}
environment variable.}
\es{Para ejecutar \texttt{sugar-emulator}, simplemente escriba su nombre en el
terminal. Para la salida de depuración extra, también establezca la variable de
entorno \texttt{SUGAR\_LOG\_LEVEL}. Para ejecutar el emulador en un idioma
diferente, establezca la variable de entorno \texttt{LANG}.}

\begin{frame}{\texttt{sugar-emulator}}
\begin{itemize}
    \item{\texttt{sugar-emulator}}
    \item{\texttt{SUGAR\_LOG\_LEVEL=debug LANG=es sugar-emulator}}
\end{itemize}
\end{frame}

\note{Give an interactive demo of \texttt{sugar-emulator} at this point.}


\en{Debugging an activity is similar to debugging any other Python program: the
simplest way is to use the \texttt{print()} function to print out values from
the program, and manually check whether they're what's expected --- or whether
those points in the program are reached at all.}
\es{Depuración de la actividad es similar a depurar cualquier otro programa de
Python: la forma más sencilla es utilizar la función \texttt{print()} para
imprimir los valores del programa, y comprobar manualmente si son lo que se
espera --- o si esos puntos en el programa se alcanzan en absoluto.}

\en{When using \texttt{sugar-emulator}, text outputted using \texttt{print()}
won't appear in the normal terminal. Instead, it is saved to a log file in
\texttt{\textasciitilde/.sugar/default/logs} which is specific to the activity.
A new log file is created every time the activity is run in a single
\texttt{sugar-emulator} session, so the number $N$ changes.}
\es{Al usar \texttt{sugar-emulator}, texto emite utilizando \texttt{print()} no
aparecerá en el terminal normal. En su lugar, se guarda en un archivo de
registro en \texttt{\textasciitilde/.sugar/default/logs}, que es específica de
la actividad. Un nuevo archivo de registro se crea cada vez que la actividad se
ejecuta en una sola sesión de \texttt{sugar-emulator}, por lo que los cambios en
el número $N$.}

\en{For a more flexible logging solution which doesn't have to be removed before
publishing the activity, use the
\href{http://docs.python.org/2/library/logging.html}{Python \texttt{logging}
module}. Create a \texttt{logger} object and call methods on it to print
messages with different severities.}
\es{Para una solución de registro más flexible que no tiene que ser removido
antes de la publicación de la actividad, el uso del
\href{http://docs.python.org/2/library/logging.html}{módulo \texttt{logging} de
Python}. Crear un objeto \texttt{logger} y llamar a métodos en él para imprimir
mensajes con diferentes niveles de gravedad.}

\begin{frame}[fragile]
\frametitle{\en{Sugar logging}\es{Registro en Sugar}}
\begin{block}{\en{Log files}\es{Archivos de registro}}
{\large{\texttt{\textasciitilde/.sugar/default/logs/\en{activity.id}\es{actividad.id}-$N$.log}}}
\end{block}
\begin{block}{\en{Logging code}\es{Código de registro}}
\begin{lstlisting}[language=Python]
import logging

self._logger = logging.getLogger('nombre-de-mi-actividad')

self._logger.error('Este es un error')
self._logger.warning('...una advertencia')
self._logger.debug('...un mensaje de depuracion')
\end{lstlisting}
\end{block}
\end{frame}


\section{\en{Internationalisation}\es{Internationalisation}}

\en{Internationalisation is an important part of writing an activity, as it
allows your activity to be used in other languages. Internationalisation is
mostly about translation, but other things must be considered (such as
currencies, date formats, and whether text is written left-to-right or
right-to-left). Adding translation support to an activity is easier; the others
are more complex and are not covered here.}
\es{La internacionalización es una parte importante de la escritura una
actividad, ya que permite que la actividad que se utilizará en otros idiomas. La
internacionalización es sobre todo acerca de la traducción, pero otras cosas se
debe considerar (como monedas, formatos de fecha y si el texto se escribe de
izquierda a derecha o de derecha a izquierda). Adición de apoyo a la traducción
de una actividad es más fácil; los otros son más complejos y no están cubiertos
aquí.}

\en{To add translation support, a library called \texttt{gettext} is used. For
each UI string to be translated, the English string is passed through the
\texttt{\_} (underscore) function provided by \texttt{gettext}, which returns
either a translated version, or the original string if no translation is
available.}
\es{Para añadir soporte de traducción, se utiliza una librería llamada
\texttt{gettext}. Para cada cadena de IU sea traducida, la cadena de Inglés se
pasa a través de la función \texttt{\_} (guión bajo) proporcionado por
\texttt{gettext}, que devuelve una versión traducida, o la cadena original si no
hay traducción disponible.}

\begin{frame}[fragile]
\frametitle{\en{Translation support}\es{Apoyo a la traducción}}
\begin{lstlisting}[language=Python]
from gettext import gettext as _

# Previoso: Gtk.Button('Hello world!')
button = Gtk.Button(_('Hello world!'))
\end{lstlisting}
\end{frame}

\en{In addition to these code changes, a set of \texttt{.po} translation files
have to be created. These give the translations of the English strings into
other languages, one file per language. Each file is written manually by a human
translator, working from a \texttt{.pot} template file. This \texttt{.pot} file
must be periodically updated to reflect changes in the strings marked for
translation in the program code.}
\es{Además de estos cambios en el código, un conjunto de archivos de traducción
\texttt{.po} tienen que ser creados. Estos dan las traducciones de las cadenas
en Inglés a otros idiomas, un archivo por cada idioma. Cada archivo se escribe
manualmente por un traductor humano, trabajando desde un archivo de plantilla
\texttt{.pot}. Este archivo \texttt{.pot} debe actualizarse periódicamente para
reflejar los cambios en las cuerdas marcadas para la traducción en el código del
programa.}

\en{To generate the \texttt{.pot} file, run \texttt{./setup.py~genpot}. You can
then copy the \texttt{.pot} file to (for example) \texttt{es.po} and write the
Spanish translation. Don't forget to commit both files to git.}
\es{Para generar el archivo \texttt{.pot}, ejecutar \texttt{./setup.py~genpot}.
A continuación, puede copiar el archivo \texttt{.pot} a (por ejemplo)
\texttt{es.po} y escribir la traducción en Español. No te olvides de añadir los
dos archivos a git.}

\begin{frame}{\en{Generating a POT}\es{Generación de un POT}}
\begin{itemize}
    \item{\texttt{./setup.py genpot}}
    \item{\texttt{cd po}}
    \item{\texttt{cp \en{ActivityName}\es{NombreDeActividad}.pot es.po}}
    \item{\en{Edit \texttt{es.po} to create the Spanish translation.}
          \es{Editar \texttt{es.po} para crear la traducción en Español}}
\end{itemize}
\end{frame}

\note{Give an interactive example of generating a POT file and changing it to a
PO file now.}

\en{Activities whose source code is hosted on \url{http://git.sugarlabs.org} can
use a web-based service called Pootle to get translations from teams all over
the world. This is a valuable service, and more information about setting it up
is available online.}
\es{Actividades cuyo código está alojado en \url{http://git.sugarlabs.org}
pueden utilizar un servicio basado en web llamado Pootle para obtener
traducciones de los equipos de todo el mundo. Este es un servicio valioso, y más
información sobre su puesta en marcha está disponible en línea.}

\begin{frame}{\en{Adding Pootle support}\es{Añadir soporte de Pootle}}
\begin{block}{\en{Reference}\es{Referencía}}
\en{\url{http://en.flossmanuals.net/make-your-own-sugar-activities/going-international-with-pootle/}}
\es{\url{http://en.flossmanuals.net/como-hacer-una-actividad-sugar/internacionalizarse-con-pootle-god-100/}}
\end{block}
\begin{block}{\en{Overview}\es{Visión de conjunto}}
\begin{enumerate}
    \item{\en{Push activity code to git.sugarlabs.org, as described below.}
          \es{Empuje código de actividad a git.sugarlabs.org, tal como se
              describe a continuación.}}
    \item{\en{Allow the `pootle' user to commit to git.}
          \es{Permitir que el usuario `pootle' para crear commites en git.}}
    \item{\en{File a bug report requesting Pootle support for your project.}
          \es{Presentar un informe de error solicitando apoyo Pootle para su
              proyecto.}}
\end{enumerate}
\end{block}
\end{frame}


\section{\en{Publishing an activity}\es{Publicar una actividad}}

\en{After finishing the activity, testing it on relevant versions of the XO (in
emulation and on physical machines), and generating a \texttt{.xo} bundle, the
activity needs to be published to \url{http://activities.sugarlabs.org} for
users to download.}
\es{Después de terminar la escritura de la actividad, la probación en las
versiones pertinentes de la XO (en la emulación y en máquinas físicas), y la
generación de un paquete de \texttt{.xo}, la actividad tiene que ser publicada a
\url{http://activities.sugarlabs.org/es-ES/} para que los usuarios descargar.}

\en{Before publishing the activity, its source code must be made available on
\url{http://git.sugarlabs.org} so that others can view it and improve on it.
Educatrachos has \href{https://git.sugarlabs.org/+educatrachos}{a team page} on
that website, and anyone from Educatrachos who is writing an activity should
become a member of the team. An administrator (like me) can do that.}
\es{Antes de la publicación de la actividad, su código debe estar disponible en
\url{http://git.sugarlabs.org} para que otros puedan verlo y mejorar en él.
Educatrachos tiene
\href{https://git.sugarlabs.org/+educatrachos}{una página del equipo} en ese
sitio web, y cualquier persona de Educatrachos que está escribiendo una
actividad debe convertirse en un miembro del equipo. Un administrador (como yo)
puede hacer eso.}

\en{To add an activity to \url{http://git.sugarlabs.org}, add a new project for
it, then create a repository in that project. Name both after the activity. Once
the repository's been created, add it as a \texttt{remote} called
\texttt{origin} in your local git repository, then push the \texttt{master}
branch to it. Whenever you commit to the local repository from that point
onwards, you must subsequently push the commit to the remote so that it is
visible online.}
\es{Para añadir una actividad a \url{http://git.sugarlabs.org}, agregue un nuevo
proyecto para que, a continuación, crear un repositorio en ese proyecto. Nombra
dos después de la actividad. Después ha creado el repositorio, añadirlo como el
\texttt{remote} se llama \texttt{origin} en su repositorio git local, empujar la
rama \texttt{master} a ella. Cada vez que se crea un commit en el repositorio
local de ese punto en adelante, debe posteriormente empujar el commit con el
mando a distancia para que sea visible en Internet.}

\begin{frame}{\en{Publishing activity source code}
              \es{Publicación del código de una actividad}}
\begin{enumerate}
    \item{\en{Register on \href{http://git.sugarlabs.org}{git.sugarlabs.org}:}
          \es{Registrarse en
              \href{http://git.sugarlabs.org}{git.sugarlabs.org}:}
          \url{https://git.sugarlabs.org/users/new}}
    \item{\en{Have your account added to the Educatrachos team:}
          \es{Haga que su cuenta agregada al equipo Educatrachos:}
          \url{https://git.sugarlabs.org/+educatrachos/memberships/new}}
    \item{\en{Create a new project owned by the Educatrachos team:}
          \es{Crear un nuevo proyecto de propiedad del equipo Educatrachos:}
          \url{https://git.sugarlabs.org/projects/new}}
    \item{\en{Add a new repository to the project. Enable merge requests so
              others can suggest changes to the code.}
          \es{Añadir un nuevo repositorio para el proyecto. Permitir solicitudes
              de fusiones para que otros pueden sugerir cambios en el código.}}
    \item{\en{Copy the `SSH' URI from ``Clone \& push URLs'' on the repository
              page. e.g.\ \url{gitorious@git.sugarlabs.org:pascal-triangle/pascal-triangle.git}}
          \es{Copie el URI `SSH' desde ``Clone \& push URLs'' en la página del
              repositorio. Por ejemplo,
              \url{gitorious@git.sugarlabs.org:pascal-triangle/pascal-triangle.git}}}
    \item{\en{In a terminal:}\es{En un terminal:}
          \texttt{cd \en{path/to/my-activity}\es{camino/a/mi-actividad}}}
    \item{\texttt{git~remote add origin \emph{SSH URI}}}
    \item{\texttt{git~push -u origin master}}
\end{enumerate}
\end{frame}

\en{With the source code published online, the activity can be added to
\url{http://activities.sugarlabs.org}. You must register an account on that
website, then join the
\href{http://activities.sugarlabs.org/en-US/developers}{Developer Hub} and follow
the process to submit a new activity.}
\es{Con el código fuente publicada en línea, la actividad se puede añadir a
\url{http://activities.sugarlabs.org/es-ES/}. Debe registrar una cuenta en ese
sitio web, y luego unirse el Centro de Desarrollo y seguir el proceso para
enviar una nueva actividad.}

\en{Newly submitted activities are initially marked as private. Once enough
details have been filled out for an activity, it is moved to the sandbox, when
users can start downloading it. Once enough users have downloaded and rated the
activity, it can be peer-reviewed and promoted to public status.}
\es{Actividades recién enviados inicialmente se marcan como privados. Una vez
que suficientes detalles se han llenado de una actividad, se trasladó a la caja
de arena, cuando los usuarios pueden empezar a descargarlo. Una vez que
suficientes usuarios han descargado y evaluado la actividad, puede ser revisada
por pares y promovido a la condición pública.}

\begin{frame}{\en{Publishing an activity bundle}
              \es{Publicación de un paquete de una actividad}}
\begin{enumerate}
    \item{\en{Register on
              \href{http://activities.sugarlabs.org}{activities.sugarlabs.org}:
              \url{http://activities.sugarlabs.org/en-US/sugar/users/register}}
          \es{Registrarse en:
              \href{http://activities.sugarlabs.org/es-ES/}
                  {activities.sugarlabs.org}:
              \url{http://activities.sugarlabs.org/es-ES/sugar/users/register}}}
    \item{\en{Join the `Developer Hub':
              \url{http://activities.sugarlabs.org/en-US/developers}}
          \es{Únete a la `Centro de desarrolladores':
              \url{http://activities.sugarlabs.org/es-ES/developers}}}
    \item{\en{Follow the process to submit a new activity:
              \url{http://activities.sugarlabs.org/en-US/developers/addon/submit}}
          \es{Siga el proceso para enviar una nueva actividad:
              \url{http://activities.sugarlabs.org/es-ES/developers/addon/submit}}}
\end{enumerate}
\end{frame}


\section{\en{Conclusion}\es{Conclusión}}

\en{In summary: one of the key aims of writing your own activities should be to
work in partnership with the worldwide Sugar and OLPC community. This is
sometimes called ``working upstream''. They are happy to answer questions and
help solve problems, and in return they would be happy to receive new activities
and contributions which can be re-used by other OLPC deployments. As with any
community, the tighter people integrate, the better the results for everyone.}
\es{En resumen: uno de los objetivos principales de escribir sus propias
actividades debería ser trabajar en colaboración con la comunidad mundial de
Sugar y OLPC. Esto a veces se llama ``trabajando río arriba''. Ellos están
dispuestos a responder preguntas y ayudar a resolver problemas, y en cambio
estarían felices de recibir las nuevas actividades y las contribuciones que
pueden ser reutilizados por otros despliegues de OLPC. Al igual que con
cualquier comunidad, el pueblo más estrictas integran, mejores serán los
resultados para todos.}

\en{This is the end of the training, but not the end of the learning. I
encourage you to practice everything you've learned by writing activities. The
best way to learn programming is through practice. I am happy to answer
absolutely any questions either in person or by e-mail, even after I've left
Honduras. I would be thrilled to help get activities published by Educatrachos
once I return to the UK.}
\es{Este es el final de la capacitación, pero no el final del aprendizaje. Les
animo a practicar todo lo que has aprendido al escribir algunas actividades. La
mejor manera de aprender es a través de la práctica de programación. Estoy
encantado de responder a cualquier pregunta en absoluto, ya sea en persona o por
e-mail, incluso después de que me he dejado Honduras. Yo estaría encantado de
ayudar a que las actividades publicadas por Educatrachos cuando regreso al
Reino~Unido.}

\note{After a break, it would be a good idea to give an interactive demo of
creating an entire activity from scratch.}


\section{\en{Miscellany}\es{Miscelánea}}

\en{Again, not all the features of Sugar can be covered
in the available time. Here are the topics which haven't been covered, along
with links to relevant documentation. Writing activities in HTML5 wasn't covered
because the version of Sugar deployed in Honduras is too old to support them.}
\es{Una vez más, no todas las características de Sugar se pueden cubrir en el
tiempo disponible. Estos son los temas que no han sido cubiertos, así como
enlaces a la documentación pertinente. Las actividades de escritura en HTML5 no
estaba cubierto por la versión de Sugar desplegado en Honduras es demasiado
viejo para apoyarlos.}

\begin{frame}{\en{What's missing}\es{Temas no abarcados}}
\begin{itemize}
    \item{\en{Drawing custom widgets with Cairo:}
          \es{Dibujo widgets personalizados con Cairo:}
          % FIXME: This should actually be the following, but it doesn't exist yet:
          % https://developer.gnome.org/gnome-devel-demos/unstable/widget_drawing.py.html.en
          \href{http://tecnocode.co.uk/misc/platform-demos/widget_drawing.py.xhtml}{(1)},
          \href{http://www.tortall.net/mu/wiki/CairoTutorial}{(2)},
          \href{https://sites.google.com/site/randomcodecollections/home/python-gtk-3-pango-cairo-example}{(3)},
          \href{http://ptomato.name/advanced-gtk-techniques/html/custom-container.html}{(4)},
          \href{http://lotsofexpression.blogspot.com/2012/04/python-gtk-3-example-implementing-cairo.html}{(5)}}
    \item{\en{Shared activities:}\es{Actividades compartidas:}
          \en{\href{http://en.flossmanuals.net/make-your-own-sugar-activities/making-shared-activities/}{(1)}}
          \es{\href{http://en.flossmanuals.net/como-hacer-una-actividad-sugar/making-shared-activities-vc/}{(1)}}}
    \item{\en{Text-to-speech:}\es{Texto a voz:}
          \en{\href{http://en.flossmanuals.net/make-your-own-sugar-activities/adding-text-to-speech/}{(1)}}
          \es{\href{http://en.flossmanuals.net/como-hacer-una-actividad-sugar/adding-text-to-speach/}{(1)}}}
    \item{\en{Games with PyGame:}\es{Juegos con PyGame:}
          \en{\href{http://en.flossmanuals.net/make-your-own-sugar-activities/making-activities-using-pygame/}{(1)}}
          \es{\href{http://en.flossmanuals.net/como-hacer-una-actividad-sugar/construir-actividades-usando-pygame/}{(1)}}}
    \item{HTML5:
          \href{http://developer.sugarlabs.org/web-architecture.md.html}{(1)}}
\end{itemize}
\end{frame}


\begin{frame}{\en{Links}\es{Enlaces}}
\begin{block}{\en{Important links}\es{Enlaces importantes}}
\begin{itemize}
    \item{\en{\url{http://en.flossmanuals.net/make-your-own-sugar-activities/}}
          \es{\url{http://en.flossmanuals.net/como-hacer-una-actividad-sugar/heredar-activity-de-sugaractivity-jm-50/}}}
    \item{\url{http://python-gtk-3-tutorial.readthedocs.org/en/}}
    \item{\url{http://doc.sugarlabs.org/epydocs/}}
\end{itemize}
\end{block}
\begin{block}{\en{Other links}\es{Enlaces otros}}
\begin{itemize}
    \item{\url{http://wiki.sugarlabs.org/go/Features/GTK3/Porting}}
    \item{\url{http://wiki.sugarlabs.org/go/Human_Interface_Guidelines/The_Sugar_Interface}}
    \item{\url{http://wiki.sugarlabs.org/go/Development_Team/Almanac}}
    \item{\url{http://wiki.sugarlabs.org/go/Activity_Team}}
\end{itemize}
\end{block}
\end{frame}


\begin{frame}<presentation>{\en{Questions?}\es{¿Preguntas?}}
\en{Any questions so far?}
\es{¿Hay preguntas hasta ahora?}
\end{frame}
