Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPablo Moleri <pmoleri@PABLOMOLERI-PC.(none)>2009-08-24 04:57:26 (GMT)
committer Pablo Moleri <pmoleri@PABLOMOLERI-PC.(none)>2009-08-24 04:57:26 (GMT)
commit86915957fe8ec6b001b45c667ec0fe44274520be (patch)
tree5c6734212b73a3982138e5a527c40f05aa25d365
parenteec72a9c75f0fb4b942de7811343a2efbff06613 (diff)
- Sugarizado.
- Juego colaborativo (red) más o menos funcionando, la respuesta de "agua" o "tocado" no está funcionando correctamente.
-rw-r--r--BatallaNaval.Activity/BatallaNaval.py246
-rw-r--r--BatallaNaval.activity/BatallaNavalActivity.py38
-rw-r--r--BatallaNaval.activity/Collaboration.py231
-rw-r--r--BatallaNaval.activity/MANIFEST6
-rw-r--r--BatallaNaval.activity/activity/activity.info9
-rw-r--r--BatallaNaval.activity/activity/batalla-naval-icon.svg68
6 files changed, 352 insertions, 246 deletions
diff --git a/BatallaNaval.Activity/BatallaNaval.py b/BatallaNaval.Activity/BatallaNaval.py
deleted file mode 100644
index 104c10b..0000000
--- a/BatallaNaval.Activity/BatallaNaval.py
+++ /dev/null
@@ -1,246 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: cp1252 -*-
-
-import pygtk
-pygtk.require('2.0')
-import gtk
-
-import random
-
-try:
- from sugar.activity.activity import Activity, ActivityToolbox
-except:
- pass
-
-class PanelPrincipal(gtk.HBox):
-
- def __init__(self):
- gtk.HBox.__init__(self, True)
-
- self.tablero1 = Tablero(None) # tablero propio
- self.tablero2 = Tablero(self.jugada_hecha) # tablero enemigo
-
- self.barcos_propios = crear_barcos()
- for barco in self.barcos_propios:
- self.tablero1.agregar_barco(barco, True)
-
- print "Barcos Enemigos"
- self.barcos_enemigos = crear_barcos()
- for barco in self.barcos_enemigos:
- self.tablero2.agregar_barco(barco, False)
- print "%s: %s" % (barco.nombre, barco.pos)
-
- self.add(self.tablero1)
- self.add(self.tablero2)
-
- self.show_all()
-
- self.jugadas_enemigas= [] # Lleva un registro de las jugadas hechas por la computadora
-
- def jugada_hecha(self):
- # Cuando se hace una jugada, la computadora hace una jugada al azar sobre el tablero propio
- if len(self.jugadas_enemigas) == 100:
- return
-
- ok = False
- while not ok:
- x, y = random.randint(1, 10), random.randint(1, 10)
- if not (x, y) in self.jugadas_enemigas:
- ok = True
-
- self.tablero1.filas[x-1][y-1].clicked()
-
-def crear_barcos():
-
- barcos = [
- Barco("Portaaviones", 5, None),
- Barco("Acorazado", 4, None),
- Barco("Crucero", 3, None),
- Barco("Submarino", 3, None),
- Barco("Destructor", 2, None)]
-
- celdas_ocupadas = []
-
- for barco in barcos:
- ok = False
- while not ok:
- # Calculo coordenadas random, asumo orientacion horizontal
- posx = random.randint(1, 10)
- posy = random.randint(1, 10-barco.largo+1)
-
- barco.pos = (posx, posy)
- ok = True
- for celda in barco.get_celdas():
- if celda in celdas_ocupadas:
- ok = False
- if ok:
- celdas_ocupadas.extend(barco.get_celdas())
- return barcos
-
-class Celda(gtk.Button):
-
- def __init__(self, pos, clicked_cb):
- gtk.Button.__init__(self)
- self.pos = pos
-
- self.connect("clicked", clicked_cb)
-
- def ocultar(self):
- self.set_no_show_all(True)
- self.hide()
-
- def tocado(self):
- color = gtk.gdk.Color(65535,65535/2,0)
- self.modify_bg(gtk.STATE_NORMAL, color)
- self.modify_bg(gtk.STATE_PRELIGHT, color)
- self.show() # Por si está oculta atrás de un barco
-
- def agua(self):
- color = gtk.gdk.Color(0,0,65535/2)
- self.modify_bg(gtk.STATE_NORMAL, color)
- self.modify_bg(gtk.STATE_PRELIGHT, color)
- self.show() # Por si está oculta atrás de un barco
-
-class Tablero(gtk.Frame):
-
- def __init__(self, llamada_jugada_hecha):
- gtk.Frame.__init__(self)
-
- # Números
- tabla_numeros = gtk.Table(1, 10, True)
- for i in range(1, 11):
- label = gtk.Label(str(i))
- tabla_numeros.attach(label, i-1, i, 0, 1)
-
- # Letras
- tabla_letras = gtk.Table(10, 1, True)
- for i in range(1, 11):
- char = chr( ord('A') + i - 1 )
- label = gtk.Label(char)
- tabla_letras.attach(label, 0, 1, i-1, i)
-
- # Se hace una tabla para ubicar las letras, los números y el tablero
- self.tabla = gtk.Table(2, 2, False)
- self.add(self.tabla)
-
- opciones = gtk.SHRINK|gtk.FILL
-
- label = gtk.Label(" ")
- self.tabla.attach(label, 0, 1, 0, 1, xoptions=opciones, yoptions=opciones)
-
- self.tabla.attach(tabla_numeros, 1, 2, 0, 1, xoptions=opciones, yoptions=opciones)
- self.tabla.attach(tabla_letras, 0, 1, 1, 2, xoptions=opciones, yoptions=opciones)
-
- self.filas = []
-
- # El tablero es otra tabla
- self.tabla_celdas = gtk.Table(10, 10, True)
- self.tabla.attach(self.tabla_celdas, 1, 2, 1, 2, xoptions=gtk.FILL|gtk.EXPAND, yoptions=gtk.FILL|gtk.EXPAND)
-
- for i in range(1, 11):
- row = []
- for j in range(1, 11):
- left = j - 1
- top = i - 1
- celda = Celda((i, j), self.celda_clickeada)
- row.append(celda)
- self.tabla_celdas.attach(celda, left, j, top, i)
- #print label.get_text()
- self.filas.append(row)
-
- self.barcos = [] # Los barcos que hay en el tablero
-
- self.llamada_jugada_hecha = llamada_jugada_hecha
-
- def agregar_barco(self, barco, show):
- self.barcos.append(barco)
- if show:
- for i in barco.get_filas():
- for j in barco.get_cols():
- self.ocultar_celda(i, j)
- izq = barco.get_inicio()[1]-1
- der = barco.get_fin()[1]
- arr = barco.get_inicio()[0]-1
- aba = barco.get_fin()[0]
- self.tabla_celdas.attach(barco, izq, der, arr, aba)
-
- def ocultar_celda(self, i, j):
- self.filas[i-1][j-1].ocultar()
-
- def celda_clickeada(self, celda):
- tocado = False
- for barco in self.barcos:
- if celda.pos in barco.get_celdas():
- tocado = True
- celda.tocado()
- if not tocado:
- celda.agua()
-
- if self.llamada_jugada_hecha:
- self.llamada_jugada_hecha()
-
-class Barco(gtk.Frame):
-
- horizontal = 'H'
- vertical = 'V'
-
- def __init__(self, nombre, largo, pos, orientacion = horizontal):
- #gtk.Label.__init__(self, nombre)
- gtk.Frame.__init__(self)
- self.nombre = nombre
- self.largo = largo
- self.orientacion = orientacion
- self.pos = pos
-
- self.add(gtk.Label(nombre))
-
- self.show()
-
- def get_inicio(self):
- return self.pos
-
- def get_fin(self):
- if self.orientacion == Barco.horizontal:
- return self.pos[0], self.pos[1] + self.largo - 1
- else:
- return self.pos[0] + self.largo - 1, self.pos[1]
-
- def get_filas(self):
- return range(self.get_inicio()[0], self.get_fin()[0]+1)
-
- def get_cols(self):
- return range(self.get_inicio()[1], self.get_fin()[1]+1)
-
- def get_celdas(self):
- return [(f, c) for f in self.get_filas() for c in self.get_cols()]
-
-# Esta función es el punto de entrada común para sugar y modo standalone
-# standalone es un boolean que indica si es Standalone o se ejecuta desde Sugar
-def init(standalone, ventana_principal):
-
- panel_principal = PanelPrincipal()
-
- if not standalone:
- toolbox = ActivityToolbox(toplevel_window)
- ventana_principal.set_toolbox(toolbox)
- toolbox.show()
- ventana_principal.set_canvas(panel_principal)
- else:
- ventana_principal.add(panel_principal)
-
- ventana_principal.set_title("Batalla Naval - ceibalJAM")
- ventana_principal.connect("destroy", lambda wid: gtk.main_quit())
- ventana_principal.connect("delete_event", lambda a1, a2: gtk.main_quit())
-
- ventana_principal.show()
-
-# Este es el procedimiento principal en modo standalone
-def main():
- ventana_principal = gtk.Window(gtk.WINDOW_TOPLEVEL)
- init(True, ventana_principal)
- gtk.main()
- return 0
-
-# Este código se ejecuta sólo cuando se ejecuta directo ese módulo (no cuando se importa desde sugar)
-if __name__ == "__main__":
- main()
diff --git a/BatallaNaval.activity/BatallaNavalActivity.py b/BatallaNaval.activity/BatallaNavalActivity.py
new file mode 100644
index 0000000..1c77416
--- /dev/null
+++ b/BatallaNaval.activity/BatallaNavalActivity.py
@@ -0,0 +1,38 @@
+from sugar.activity.activity import Activity, ActivityToolbox
+import BatallaNaval
+from Collaboration import CollaborationWrapper
+
+class BatallaNavalActivity(Activity):
+ def __init__(self, handle):
+ Activity.__init__(self, handle)
+ self.connect('destroy', self._cleanup_cb)
+
+ self.gamename = 'BatallaNaval'
+ self.set_title("Batalla Naval")
+
+ # connect to the in/out events
+ self.connect('focus_in_event', self._focus_in)
+ self.connect('focus_out_event', self._focus_out)
+
+ self.colaboracion = CollaborationWrapper(self, None, None, None)
+ self.connect('shared', self.colaboracion._shared_cb)
+ if self._shared_activity:
+ # We are joining the activity
+ self.connect('joined', self.colaboracion._joined_cb)
+ if self.get_shared():
+ # We've already joined
+ self.colaboracion._joined_cb()
+
+ # The activity is a subclass of Window, so it passses itself to the init function
+ BatallaNaval.init(False, self)
+ # It never returns, gtk.main()
+
+ def _cleanup_cb(self, data=None):
+ return
+
+ # We could use these methods to conserve power by having the activity stop processing when it is in the background.
+ def _focus_in(self, event, data=None):
+ return
+
+ def _focus_out(self, event, data=None):
+ return
diff --git a/BatallaNaval.activity/Collaboration.py b/BatallaNaval.activity/Collaboration.py
new file mode 100644
index 0000000..2e7d4e9
--- /dev/null
+++ b/BatallaNaval.activity/Collaboration.py
@@ -0,0 +1,231 @@
+# -*- coding: UTF-8 -*-
+# Copyright 2007-2008 One Laptop Per Child
+# Copyright 2007 Gerard J. Cerchio <www.circlesoft.com>
+# Copyright 2008 Andrés Ambrois <andresambrois@gmail.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import logging
+import sugar.logger
+
+from sugar.presence import presenceservice
+import telepathy
+from dbus.service import method, signal
+# In build 656 Sugar lacks sugartubeconn
+try:
+ from sugar.presence.sugartubeconn import SugarTubeConnection
+except:
+ from sugar.presence.tubeconn import TubeConnection as SugarTubeConnection
+from dbus.gobject_service import ExportedGObject
+
+
+# Todas las actividades colaborativas de sugar deben tener implentadas las señales "Hello" y "World"
+# Cuando alguien entra a la colaboración sugar automáticamente emite la señal Hello
+# Este wrapper automáticamente responde con la señal World, que sirve para informarle al nuevo
+# participante el estado actual.
+
+SERVICE = "org.ceibaljam.BatallaNaval"
+IFACE = SERVICE
+PATH = "/org/ceibaljam/BatallaNaval"
+
+logger = logging.getLogger('BatallaNaval')
+
+class CollaborationWrapper(ExportedGObject):
+ ''' A wrapper for the collaboration bureaucracy
+ Recibe la actividad y los callbacks necesarios '''
+
+ def __init__(self, activity, buddy_joined_cb, buddy_left_cb, play_cb):
+ self.activity = activity
+ self.buddy_joined = buddy_joined_cb
+ self.buddy_left = buddy_left_cb
+ self.Play_cb = play_cb
+ self.world = False
+ self.entered = False
+ self.presence_service = presenceservice.get_instance()
+ self.owner = self.presence_service.get_owner()
+
+ def _shared_cb(self, activity):
+ #self.activity.gameToolbar.grey_out_size_change()
+ #self.activity.gameToolbar.grey_out_restart()
+ #self.activity.gameToolbar.grey_out_ai()
+ self._sharing_setup()
+ self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].OfferDBusTube(
+ SERVICE, {})
+ self.is_initiator = True
+ #self.activity.undo_button.hide()
+
+ def _joined_cb(self, activity):
+ #self.activity.gameToolbar.grey_out_size_change()
+ #self.activity.gameToolbar.grey_out_restart()
+ #self.activity.gameToolbar.grey_out_ai()
+ self._sharing_setup()
+ self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].ListTubes(
+ reply_handler=self._list_tubes_reply_cb,
+ error_handler=self._list_tubes_error_cb)
+ self.is_initiator = False
+ #self.activity.undo_button.hide()
+
+ def _sharing_setup(self):
+ if self.activity._shared_activity is None:
+ logger.error('Failed to share or join activity')
+ return
+
+ self.conn = self.activity._shared_activity.telepathy_conn
+ self.tubes_chan = self.activity._shared_activity.telepathy_tubes_chan
+ self.text_chan = self.activity._shared_activity.telepathy_text_chan
+
+ self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].connect_to_signal(
+ 'NewTube', self._new_tube_cb)
+
+ self.activity._shared_activity.connect('buddy-joined', self._buddy_joined_cb)
+ self.activity._shared_activity.connect('buddy-left', self._buddy_left_cb)
+
+ # Optional - included for example:
+ # Find out who's already in the shared activity:
+ for buddy in self.activity._shared_activity.get_joined_buddies():
+ logger.debug('Buddy %s is already in the activity',
+ buddy.props.nick)
+
+ def participant_change_cb(self, added, removed):
+ logger.debug('Tube: Added participants: %r', added)
+ logger.debug('Tube: Removed participants: %r', removed)
+ for handle, bus_name in added:
+ buddy = self._get_buddy(handle)
+ if buddy is not None:
+ logger.debug('Tube: Handle %u (Buddy %s) was added',
+ handle, buddy.props.nick)
+ for handle in removed:
+ buddy = self._get_buddy(handle)
+ if buddy is not None:
+ logger.debug('Buddy %s was removed' % buddy.props.nick)
+ if not self.entered:
+ if self.is_initiator:
+ logger.debug("I'm initiating the tube, will "
+ "watch for hellos.")
+ self.add_hello_handler()
+ else:
+ logger.debug('Hello, everyone! What did I miss?')
+ self.Hello()
+ self.entered = True
+
+
+ # This is sent to all participants whenever we join an activity
+ @signal(dbus_interface=IFACE, signature='')
+ def Hello(self):
+ """Say Hello to whoever else is in the tube."""
+ logger.debug('I said Hello.')
+
+ # This is called by whoever receives our Hello signal
+ # This method receives the current game state and puts us in sync
+ # with the rest of the participants.
+ # The current game state is represented by the game object
+ @method(dbus_interface=IFACE, in_signature='', out_signature='')
+ def World(self):
+ """To be called on the incoming XO after they Hello."""
+ if not self.world:
+ logger.debug('Somebody called World on me')
+ #self.activity.board_size_change(None, size)
+ self.world = True # En vez de cargar el mundo, lo voy recibiendo jugada a jugada.
+ #self.activity.set_player_color(self.activity.invert_color(taken_color))
+ #self.players = players
+ # now I can World others
+ self.add_hello_handler()
+ else:
+ self.world = True
+ logger.debug("I've already been welcomed, doing nothing")
+
+ @signal(dbus_interface=IFACE, signature='ii')
+ def Play(self, x, y):
+ """Say Hello to whoever else is in the tube."""
+ logger.debug('Signaling players of stone placement at:%s x %s.', x, y)
+
+ def add_hello_handler(self):
+ logger.debug('Adding hello handler.')
+ self.tube.add_signal_receiver(self.hello_signal_cb, 'Hello', IFACE,
+ path=PATH, sender_keyword='sender')
+ self.tube.add_signal_receiver(self.play_signal_cb, 'Play', IFACE,
+ path=PATH, sender_keyword='sender')
+
+ def hello_signal_cb(self, sender=None):
+ """Somebody Helloed me. World them."""
+ if sender == self.tube.get_unique_name():
+ # sender is my bus name, so ignore my own signal
+ return
+ logger.debug('Newcomer %s has joined', sender)
+ logger.debug('Welcoming newcomer and sending them the game state')
+
+ # No le mandamos nada, la solo interesa mandar jugadas y reflejar el resultado {tocado, agua, hundido}
+ self.tube.get_object(sender, PATH).World(dbus_interface=IFACE)
+
+ def play_signal_cb(self, x, y, sender=None):
+ """Somebody placed a stone. """
+ if sender == self.tube.get_unique_name():
+ return # sender is my bus name, so ignore my own signal
+ logger.debug('Buddy %s placed a stone at %s x %s', sender, x, y)
+ # Call our Play callback
+ #self.Play_cb(x, y, sender)
+ self.Play_cb(x, y) # En principio no importa quien lo mandó
+
+ def _list_tubes_error_cb(self, e):
+ logger.error('ListTubes() failed: %s', e)
+
+ def _list_tubes_reply_cb(self, tubes):
+ for tube_info in tubes:
+ self._new_tube_cb(*tube_info)
+
+ def _new_tube_cb(self, id, initiator, type, service, params, state):
+ logger.debug('New tube: ID=%d initator=%d type=%d service=%s '
+ 'params=%r state=%d', id, initiator, type, service,
+ params, state)
+ if (type == telepathy.TUBE_TYPE_DBUS and
+ service == SERVICE):
+ if state == telepathy.TUBE_STATE_LOCAL_PENDING:
+ self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].AcceptDBusTube(id)
+ self.tube = SugarTubeConnection(self.conn,
+ self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES],
+ id, group_iface=self.text_chan[telepathy.CHANNEL_INTERFACE_GROUP])
+ super(CollaborationWrapper, self).__init__(self.tube, PATH)
+ self.tube.watch_participants(self.participant_change_cb)
+
+ def _buddy_joined_cb (self, activity, buddy):
+ """Called when a buddy joins the shared activity. """
+ logger.debug('Buddy %s joined', buddy.props.nick)
+ if self.buddy_joined:
+ self.buddy_joined(buddy)
+
+ def _buddy_left_cb (self, activity, buddy):
+ """Called when a buddy leaves the shared activity. """
+ if self.buddy_left:
+ self.buddy_left(buddy)
+
+ def _get_buddy(self, cs_handle):
+ """Get a Buddy from a channel specific handle."""
+ logger.debug('Trying to find owner of handle %u...', cs_handle)
+ group = self.text_chan[telepathy.CHANNEL_INTERFACE_GROUP]
+ my_csh = group.GetSelfHandle()
+ logger.debug('My handle in that group is %u', my_csh)
+ if my_csh == cs_handle:
+ handle = self.conn.GetSelfHandle()
+ logger.debug('CS handle %u belongs to me, %u', cs_handle, handle)
+ elif group.GetGroupFlags() & telepathy.CHANNEL_GROUP_FLAG_CHANNEL_SPECIFIC_HANDLES:
+ handle = group.GetHandleOwners([cs_handle])[0]
+ logger.debug('CS handle %u belongs to %u', cs_handle, handle)
+ else:
+ handle = cs_handle
+ logger.debug('non-CS handle %u belongs to itself', handle)
+ # XXX: deal with failure to get the handle owner
+ assert handle != 0
+ return self.presence_service.get_buddy_by_telepathy_handle(
+ self.conn.service_name, self.conn.object_path, handle)
diff --git a/BatallaNaval.activity/MANIFEST b/BatallaNaval.activity/MANIFEST
new file mode 100644
index 0000000..3da8118
--- /dev/null
+++ b/BatallaNaval.activity/MANIFEST
@@ -0,0 +1,6 @@
+Collaboration.py
+setup.py
+BatallaNavalActivity.py
+BatallaNaval.py
+activity/activity.info
+activity/batalla-naval-icon.svg
diff --git a/BatallaNaval.activity/activity/activity.info b/BatallaNaval.activity/activity/activity.info
new file mode 100644
index 0000000..7cb17e8
--- /dev/null
+++ b/BatallaNaval.activity/activity/activity.info
@@ -0,0 +1,9 @@
+[Activity]
+name = BatallaNaval
+bundle_id = org.ceibaljam.BatallaNaval
+class = BatallaNavalActivity.BatallaNavalActivity
+icon = batalla-naval-icon
+activity_version = 2
+host_version = 1
+show_launcher = no
+license = GPLv2+
diff --git a/BatallaNaval.activity/activity/batalla-naval-icon.svg b/BatallaNaval.activity/activity/batalla-naval-icon.svg
new file mode 100644
index 0000000..432bd56
--- /dev/null
+++ b/BatallaNaval.activity/activity/batalla-naval-icon.svg
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
+ <!ENTITY stroke_color "#666666">
+ <!ENTITY fill_color "#FFFFFF">
+]>
+<svg
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ version="1.0"
+ width="55"
+ height="55"
+ id="svg4502"
+ style="display:inline">
+ <defs
+ id="defs4504" />
+
+ <g
+ transform="translate(-0.2226721,0.2016908)"
+ id="fondo"
+ style="opacity:0.5">
+ <g
+ transform="translate(0,-1.8115502)"
+ id="barras_horizontales">
+ <rect
+ width="51.214573"
+ height="3.7854252"
+ x="2.4493928"
+ y="22.482435"
+ id="rect2398"
+ style="opacity:1;fill:&stroke_color;fill-opacity:1;" />
+ <rect
+ width="51.214573"
+ height="3.7854252"
+ x="2.4493928"
+ y="39.06778"
+ id="rect2404"
+ style="opacity:1;fill:&stroke_color;fill-opacity:1;" />
+ </g>
+ <use
+ transform="matrix(0,0.9057751,-1.1040268,0,62.122828,5.4432283)"
+ id="use2426"
+ x="0"
+ y="0"
+ width="55"
+ height="55"
+ xlink:href="#barras_horizontales" />
+ </g>
+ <g id="terron">
+ <path
+ d="M 38.822128,44.108722 C 38.822128,44.108722 38.445765,44.108722 38.092819,44.108722 C 38.092819,42.747378 38.097001,38.459638 38.097001,37.325183 C 38.097001,37.325183 38.097001,37.325183 38.097001,37.323527 L 38.097001,24.562988 L 38.089474,16.811436 C 38.086128,15.932855 37.361837,15.224857 36.48031,15.228997 C 36.052928,15.228997 35.648965,15.396267 35.347873,15.696856 C 35.045946,15.999101 34.882019,16.399058 34.883691,16.823857 C 34.883691,16.863604 34.885364,19.358576 34.887873,21.45773 L 22.071438,21.45773 C 20.330965,21.45773 18.920019,22.854682 18.920019,24.575409 L 18.920019,26.300276 L 13.265364,26.303588 C 12.377982,26.309384 11.663728,27.024008 11.667074,27.896793 C 11.668746,28.321592 11.837691,28.719892 12.141291,29.017998 C 12.446565,29.316931 12.850528,29.479232 13.277073,29.477576 C 13.326419,29.477576 16.696965,29.47592 18.919182,29.474263 L 18.919182,37.014658 C 18.919182,37.02625 18.915837,37.036187 18.915837,37.046952 C 18.915837,37.104917 18.919182,42.545329 18.919182,44.107894 C 18.567073,44.107894 18.189873,44.107894 18.189873,44.107894 C 17.285765,44.125284 16.584055,44.849844 16.59911,45.724285 C 16.61751,46.601209 17.351837,47.296787 18.234201,47.279397 L 20.537546,47.277741 C 21.439146,47.26118 22.145037,46.535792 22.126637,45.661352 L 22.123292,40.442034 L 34.887873,40.442034 L 34.882019,45.661352 C 34.865292,46.53662 35.571182,47.262009 36.472783,47.277741 L 38.774455,47.279397 C 39.661,47.296787 40.393656,46.601209 40.411219,45.724285 C 40.428782,44.849844 39.723728,44.126112 38.822128,44.108722 z M 30.604855,25.673428 C 31.197837,25.590621 31.748164,25.999687 31.832637,26.587615 C 31.917946,27.174716 31.50311,27.720413 30.910128,27.804876 C 30.3138,27.887683 29.76431,27.476962 29.680673,26.890689 C 29.595365,26.301932 30.010201,25.756235 30.604855,25.673428 z M 24.950201,26.467545 C 25.542346,26.384739 26.09351,26.793805 26.177147,27.381734 C 26.262455,27.97049 25.847619,28.513703 25.255473,28.598995 C 24.659146,28.683458 24.109656,28.272735 24.026019,27.684807 C 23.941546,27.096049 24.353874,26.552009 24.950201,26.467545 z M 26.384565,35.548148 C 25.364201,34.827728 23.744165,32.814693 24.326273,31.447552 C 24.532019,30.966443 24.984492,31.265376 25.47711,31.509657 C 26.653037,32.10421 28.05311,32.180392 29.308492,31.805277 C 29.946637,31.614821 30.491946,31.305951 31.012165,30.893574 C 31.328309,30.641012 32.191437,29.636565 32.666491,30.090346 C 33.037837,30.445588 33.101401,30.886121 33.101401,30.890261 C 33.634164,34.258844 29.418891,37.688706 26.384565,35.548148 z"
+ id="cuerpo"
+ style="fill:&stroke_color;fill-opacity:1;overflow:visible" />
+ <path
+ d="M 17.233073,11.642631 C 18.971874,8.6971904 24.424965,8.6756607 25.411873,12.233044 C 25.743073,13.428775 25.717147,16.000757 24.39151,16.697991 C 23.925655,16.943099 23.764237,16.42804 23.540092,15.929543 C 23.003146,14.736296 21.969401,13.79975 20.755837,13.307049 C 20.139437,13.055317 19.519691,12.950152 18.853946,12.946839 C 18.446637,12.943527 17.137728,13.184495 17.060783,12.532805 C 17.000564,12.027683 17.233073,11.644287 17.233073,11.642631 z"
+ id="pelo_oscuro"
+ style="fill:&stroke_color;fill-opacity:1;overflow:visible" />
+ <g
+ transform="matrix(0.8363636,0,0,0.8280687,4.3773279,7.643887)"
+ id="pelo_claro"
+ style="fill:&stroke_color;fill-opacity:1;overflow:visible">
+ <path
+ d="M 30.514,13.666 C 25.959,9.955 27.36,0.759 33.675,0.043 C 35.799,-0.198 40.171,0.537 41.006,2.954 C 41.299,3.802 40.382,3.936 39.473,4.18 C 37.299,4.765 35.434,6.261 34.273,8.172 C 33.681,9.144 33.342,10.161 33.16,11.281 C 33.047,11.964 33.108,14.236 31.982,14.194 C 31.107,14.162 30.516,13.668 30.514,13.666 z"
+ id="path2674"
+ style="fill:&stroke_color;fill-opacity:1" />
+ </g>
+ </g>
+</svg>