Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Learning by Trolling

Anler
November 21, 2015

Learning by Trolling

PyConES 2015

Anler

November 21, 2015
Tweet

More Decks by Anler

Other Decks in Programming

Transcript

  1. Learning by Trolling Aprende Python trolleando a tus compañeros. ___________________________

    /| /| | | ||__|| | Please don't | / O O\__ feed | / \ the trolls | / \ \ | / _ \ \ ---------------------- / |\____\ \ || / | | | |\____/ || / \|_|_|/ | __|| / / \ |____| || / | | /| | --| | | | // | ____ -- | ,* _ | |_|_|_| | \-/ ,*-- _--\ _ \ // | / _ \\ _ // | / / \_ /- | - | | ,* ___ c_c_c_C/ \C_c_c_c____________ @jespinog @anler
  2. Lección 1 Usa __init__.py para pasar desapercibido ___________________________ /| /|

    | | ||__|| | | / O O\__ Lesson number one: | / \ usa __init__.py | / \ \ | / _ \ \ ---------------------- / |\____\ \ || / | | | |\____/ || / \|_|_|/ | __|| / / \ |____| || / | | /| | --| | | | // | ____ -- | ,* _ | |_|_|_| | \-/ ,*-- _--\ _ \ // | / _ \\ _ // | / / \_ /- | - | | ,* ___ c_c_c_C/ \C_c_c_c____________
  3. $ tree app app ├── __init__.py └── utils.py # código

    del fichero __init__.py import warnings warnings.warn( "Error entre el teclado y la silla")
  4. $ python >>> import app.utils /home/anler/tmp/app/__init__.py:3: UserWarning: Error entre el

    teclado y la silla warnings.warn("Error entre el teclado y la silla") >>>
  5. Siempre que se importe cualquier módulo dentro de un paquete,

    el código dentro del fichero __init__.py del paquete es ejecutado. Por lo general a este fichero se añade código de inicialización troleo. Todos los ficheros __init__.py durante un import son ejecutados según su orden de anidación.
  6. Lección 2 Usa monkey-patching siempre que puedas ___________________________ /| /|

    | | ||__|| | | / O O\__ Lesson number two: | / \ monkey patch pliss | / \ \ | / _ \ \ ---------------------- / |\____\ \ || / | | | |\____/ || / \|_|_|/ | __|| / / \ |____| || / | | /| | --| | | | // | ____ -- | ,* _ | |_|_|_| | \-/ ,*-- _--\ _ \ // | / _ \\ _ // | / / \_ /- | - | | ,* ___ c_c_c_C/ \C_c_c_c____________
  7. Monkey Patch Se refiere a las modificaciones en tiempo de

    ejecución a una clase o módulo motivado por la intención de parchear código de terceros como solución a un bug o feature que no se comporta como es deseado.
  8. $ tree app ├── __init__.py └── utils.py # código del

    fichero __init__.py from . import utils utils.current_year = lambda: ‘Problem?’ # código del fichero utils.py from datetime import date def current_year(): return date.today().strftime(‘%Y’)
  9. Trolleando Django lorem-ipsum ░░░░▄▄▄▄▀▀▀▀▀▀▀▀▄▄▄▄▄▄ ░░░░█░░░░▒▒▒▒▒▒▒▒▒▒▒▒░░▀▀▄ ░░░█░░░▒▒▒▒▒▒░░░░░░░░▒▒▒░░█ ░░█░░░░░░▄██▀▄▄░░░░░▄▄▄░░░█ ░▀▒▄▄▄▒░█▀▀▀▀▄▄█░░░██▄▄█░░░█ █▒█▒▄░▀▄▄▄▀░░░░░░░░█░░░▒▒▒▒▒█ █▒█░█▀▄▄░░░░░█▀░░░░▀▄░░▄▀▀▀▄▒█

    ░█▀▄░█▄░█▀▄▄░▀░▀▀░▄▄▀░░░░█░░█ ░░█░░▀▄▀█▄▄░█▀▀▀▄▄▄▄▀▀█▀██░█ ░░░█░░██░░▀█▄▄▄█▄▄█▄████░█ ░░░░█░░░▀▀▄░█░░░█░███████░█ ░░░░░▀▄░░░▀▀▄▄▄█▄█▄█▄█▄▀░░█ ░░░░░░░▀▄▄░▒▒▒▒░░░░░░░░░░█ ░░░░░░░░░░▀▀▄▄░▒▒▒▒▒▒▒▒▒▒░█ ░░░░░░░░░░░░░░▀▄▄▄▄▄░░░░░█
  10. from django.utils import lorem_ipsum lorem_ipsum.COMMON_P = ( 'Bacon ipsum dolor

    sit amet pork venison kielbasa, pork chop ham ' 'hock meatloaf frankfurter chicken shank tri-tip strip steak salami meatball. ' ... ) lorem_ipsum.WORDS = ( 'beef', 'chicken', 'pork', 'bacon', 'chuck', 'short loin', 'sirloin', 'shank', 'flank', 'sausage', 'pork belly', 'shoulder', 'cow', 'pig', … ) lorem_ipsum.COMMON_WORDS = ( 'consectetur', 'adipisicing', 'elit', 'sed', 'do', 'eiusmod', 'tempor', 'incididunt', 'ut', 'labore', 'et', 'dolore', 'magna', … )
  11. {% lorem %} Bacon ipsum dolor amet pig biltong pork

    fatback venison sausage corned beef ham hock kevin spare ribs porchetta pastrami. Sausage swine ribeye, bacon strip steak cow rump flank ball tip andouille short loin frankfurter doner. Short loin t- bone tail turducken flank sausage, ball tip picanha frankfurter kevin beef ribs. Jerky salami pork pig venison shankle filet mignon. Cupim corned beef shoulder boudin tri-tip. Bacon capicola pork belly jerky hamburger porchetta pork chop tail short loin. ...
  12. Troleando el tiempo ░░░░▄▄▄▄▀▀▀▀▀▀▀▀▄▄▄▄▄▄ ░░░░█░░░░▒▒▒▒▒▒▒▒▒▒▒▒░░▀▀▄ ░░░█░░░▒▒▒▒▒▒░░░░░░░░▒▒▒░░█ ░░█░░░░░░▄██▀▄▄░░░░░▄▄▄░░░█ ░▀▒▄▄▄▒░█▀▀▀▀▄▄█░░░██▄▄█░░░█ █▒█▒▄░▀▄▄▄▀░░░░░░░░█░░░▒▒▒▒▒█ █▒█░█▀▄▄░░░░░█▀░░░░▀▄░░▄▀▀▀▄▒█

    ░█▀▄░█▄░█▀▄▄░▀░▀▀░▄▄▀░░░░█░░█ ░░█░░▀▄▀█▄▄░█▀▀▀▄▄▄▄▀▀█▀██░█ ░░░█░░██░░▀█▄▄▄█▄▄█▄████░█ ░░░░█░░░▀▀▄░█░░░█░███████░█ ░░░░░▀▄░░░▀▀▄▄▄█▄█▄█▄█▄▀░░█ ░░░░░░░▀▄▄░▒▒▒▒░░░░░░░░░░█ ░░░░░░░░░░▀▀▄▄░▒▒▒▒▒▒▒▒▒▒░█ ░░░░░░░░░░░░░░▀▄▄▄▄▄░░░░░█
  13. $ tree app ├── __init__.py └── utils.py # código del

    fichero __init__.py from random import random import time real_time = time.time time.time = lambda: real_time() + random() # código del fichero utils.py import time def profile(): pre = time.time() print(“Expensive computation”) time.sleep(1) post = time.time() taken = post - pre print(“{} seconds”.format(taken))
  14. $ python >>> from app.utils import profile >>> profile() expensive

    computation 0.4662015438079834 seconds >>> profile() expensive computation 0.9543671607971191 seconds
  15. Troleando la apertura de ficheros ░░░░▄▄▄▄▀▀▀▀▀▀▀▀▄▄▄▄▄▄ ░░░░█░░░░▒▒▒▒▒▒▒▒▒▒▒▒░░▀▀▄ ░░░█░░░▒▒▒▒▒▒░░░░░░░░▒▒▒░░█ ░░█░░░░░░▄██▀▄▄░░░░░▄▄▄░░░█ ░▀▒▄▄▄▒░█▀▀▀▀▄▄█░░░██▄▄█░░░█

    █▒█▒▄░▀▄▄▄▀░░░░░░░░█░░░▒▒▒▒▒█ █▒█░█▀▄▄░░░░░█▀░░░░▀▄░░▄▀▀▀▄▒█ ░█▀▄░█▄░█▀▄▄░▀░▀▀░▄▄▀░░░░█░░█ ░░█░░▀▄▀█▄▄░█▀▀▀▄▄▄▄▀▀█▀██░█ ░░░█░░██░░▀█▄▄▄█▄▄█▄████░█ ░░░░█░░░▀▀▄░█░░░█░███████░█ ░░░░░▀▄░░░▀▀▄▄▄█▄█▄█▄█▄▀░░█ ░░░░░░░▀▄▄░▒▒▒▒░░░░░░░░░░█ ░░░░░░░░░░▀▀▄▄░▒▒▒▒▒▒▒▒▒▒░█ ░░░░░░░░░░░░░░▀▄▄▄▄▄░░░░░█
  16. $ ls app ├── __init__.py ├── report.txt └── utils.py #

    código del fichero __init__.py import builtins from io import StringIO as StrB builtins.open = lambda *a, **k: StrB(TROLL) TROLL = “””\ ░░░░▄▄▄▄▀▀▀▀▀▀▀▀▄▄▄▄▄▄ ... “”” # código del fichero utils.py def open_report(): return open(“report.txt”)
  17. $ python >>> from app.utils import open_report >>> with open_report()

    as report: … report.read() ░░░░▄▄▄▄▀▀▀▀▀▀▀▀▄▄▄▄▄▄ ░░░░█░░░░▒▒▒▒▒▒▒▒▒▒▒▒░░▀▀▄ ░░░█░░░▒▒▒▒▒▒░░░░░░░░▒▒▒░░█ ░░█░░░░░░▄██▀▄▄░░░░░▄▄▄░░░█ ░▀▒▄▄▄▒░█▀▀▀▀▄▄█░░░██▄▄█░░░█ █▒█▒▄░▀▄▄▄▀░░░░░░░░█░░░▒▒▒▒▒█ █▒█░█▀▄▄░░░░░█▀░░░░▀▄░░▄▀▀▀▄▒█ ░█▀▄░█▄░█▀▄▄░▀░▀▀░▄▄▀░░░░█░░█ ░░█░░▀▄▀█▄▄░█▀▀▀▄▄▄▄▀▀█▀██░█ ░░░█░░██░░▀█▄▄▄█▄▄█▄████░█ ░░░░█░░░▀▀▄░█░░░█░███████░█ ░░░░░▀▄░░░▀▀▄▄▄█▄█▄█▄█▄▀░░█ ░░░░░░░▀▄▄░▒▒▒▒░░░░░░░░░░█ ░░░░░░░░░░▀▀▄▄░▒▒▒▒▒▒▒▒▒▒░█ ░░░░░░░░░░░░░░▀▄▄▄▄▄░░░░░█
  18. En Python puedes hacer monkey-patch prácticamente cualquier cosa gracias a

    la estructura mutable de tabla hash de casi todos los objetos incluídos los módulos y a que los módulos solo se importan una vez y se guardan a modo caché en <sys.modules>. Antes de sobrescribir recuerda siempre guardar una referencia a la implementación original, puede que te haga falta utilizarla en algún otro sitio.
  19. Lección 3 Si monkey-patch se resiste, prueba con ctypes ___________________________

    /| /| | | ||__|| | | / O O\__ Lesson number three: | / \ ctypes es amigo | / \ \ | / _ \ \ ---------------------- / |\____\ \ || / | | | |\____/ || / \|_|_|/ | __|| / / \ |____| || / | | /| | --| | | | // | ____ -- | ,* _ | |_|_|_| | \-/ ,*-- _--\ _ \ // | / _ \\ _ // | / / \_ /- | - | | ,* ___ c_c_c_C/ \C_c_c_c____________
  20. ctypes Nos provee con tipos de datos compatibles con C,

    por lo que nos permite modelar la estructura en C de un objeto y utilizar dicho modelo en nuestro código para leer y modificar sus valores.
  21. Trolleando los enteros ░░░░▄▄▄▄▀▀▀▀▀▀▀▀▄▄▄▄▄▄ ░░░░█░░░░▒▒▒▒▒▒▒▒▒▒▒▒░░▀▀▄ ░░░█░░░▒▒▒▒▒▒░░░░░░░░▒▒▒░░█ ░░█░░░░░░▄██▀▄▄░░░░░▄▄▄░░░█ ░▀▒▄▄▄▒░█▀▀▀▀▄▄█░░░██▄▄█░░░█ █▒█▒▄░▀▄▄▄▀░░░░░░░░█░░░▒▒▒▒▒█ █▒█░█▀▄▄░░░░░█▀░░░░▀▄░░▄▀▀▀▄▒█

    ░█▀▄░█▄░█▀▄▄░▀░▀▀░▄▄▀░░░░█░░█ ░░█░░▀▄▀█▄▄░█▀▀▀▄▄▄▄▀▀█▀██░█ ░░░█░░██░░▀█▄▄▄█▄▄█▄████░█ ░░░░█░░░▀▀▄░█░░░█░███████░█ ░░░░░▀▄░░░▀▀▄▄▄█▄█▄█▄█▄▀░░█ ░░░░░░░▀▄▄░▒▒▒▒░░░░░░░░░░█ ░░░░░░░░░░▀▀▄▄░▒▒▒▒▒▒▒▒▒▒░█ ░░░░░░░░░░░░░░▀▄▄▄▄▄░░░░░█
  22. estructura de un entero en C +----------------+ | ob_refcnt |

    +----------------+ | ob_type | +----------------+ | ob_size | +----------------+ | ob_digit[] | +----------------+ En Python, id(entero) devuelve la dirección de memoria al objeto que representa al entero este campo de la estructura contiene una referencia a la clase del objeto
  23. $ tree app ├── __init__.py └── utils.py # código del

    fichero __init__.py from ctypes import * class EvilInt(int): __repr__ = lambda self: "42" __str__ = __repr__ lsize = sizeof(c_long) for n in range(258): addr = id(n) + lsize type_addr = c_long.from_address(addr) type_addr.value = id(EvilInt) # código del fichero utils.py def body_mass_index(height, weight): return weight / height**2
  24. ctypes nos permite acceder a estructuras y funciones de C

    definidas en DLLs y shared-libraries directamente sin necesidad de escribir lo que se llama un “extension module”.
  25. Lección 4 Si ctypes es muy complicado, prueba con masterkey

    ___________________________ /| /| | | ||__|| | | / O O\__ Lesson number four: | / \ masterkey es muy amigo | / \ \ | / _ \ \ ---------------------- / |\____\ \ || / | | | |\____/ || / \|_|_|/ | __|| / / \ |____| || / | | /| | --| | | | // | ____ -- | ,* _ | |_|_|_| | \-/ ,*-- _--\ _ \ // | / _ \\ _ // | / / \_ /- | - | | ,* ___ c_c_c_C/ \C_c_c_c____________
  26. Trolleando los booleanos ░░░░▄▄▄▄▀▀▀▀▀▀▀▀▄▄▄▄▄▄ ░░░░█░░░░▒▒▒▒▒▒▒▒▒▒▒▒░░▀▀▄ ░░░█░░░▒▒▒▒▒▒░░░░░░░░▒▒▒░░█ ░░█░░░░░░▄██▀▄▄░░░░░▄▄▄░░░█ ░▀▒▄▄▄▒░█▀▀▀▀▄▄█░░░██▄▄█░░░█ █▒█▒▄░▀▄▄▄▀░░░░░░░░█░░░▒▒▒▒▒█ █▒█░█▀▄▄░░░░░█▀░░░░▀▄░░▄▀▀▀▄▒█

    ░█▀▄░█▄░█▀▄▄░▀░▀▀░▄▄▀░░░░█░░█ ░░█░░▀▄▀█▄▄░█▀▀▀▄▄▄▄▀▀█▀██░█ ░░░█░░██░░▀█▄▄▄█▄▄█▄████░█ ░░░░█░░░▀▀▄░█░░░█░███████░█ ░░░░░▀▄░░░▀▀▄▄▄█▄█▄█▄█▄▀░░█ ░░░░░░░▀▄▄░▒▒▒▒░░░░░░░░░░█ ░░░░░░░░░░▀▀▄▄░▒▒▒▒▒▒▒▒▒▒░█ ░░░░░░░░░░░░░░▀▄▄▄▄▄░░░░░█
  27. $ ls app ├── __init__.py └── utils.py # código del

    fichero __init__.py from masterkey import open_class, close_class open_class(bool) bool.__repr__ = lambda x: “False” if x else “True” bool.__str__ = bool.__repr__ close_class(bool) # código del fichero utils.py def as_boolean(x): return bool(x)
  28. El módulo masterkey nos permite modificar la condición de inmutabilidad

    que tienen algunos tipos built-in para que podamos extenderlos con cualquier funcionalidad trolleo que se nos ocurra. Me pregunto si RubyOnRails empezó así, como un trolleo...
  29. Lección 5 Si te aburres, modifica el intérprete ___________________________ /|

    /| | | ||__|| | | / O O\__ Lesson number five: | / \ change all the things! | / \ \ | / _ \ \ ---------------------- / |\____\ \ || / | | | |\____/ || / \|_|_|/ | __|| / / \ |____| || / | | /| | --| | | | // | ____ -- | ,* _ | |_|_|_| | \-/ ,*-- _--\ _ \ // | / _ \\ _ // | / / \_ /- | - | | ,* ___ c_c_c_C/ \C_c_c_c____________
  30. Python-EE Tracebacks ░░░░▄▄▄▄▀▀▀▀▀▀▀▀▄▄▄▄▄▄ ░░░░█░░░░▒▒▒▒▒▒▒▒▒▒▒▒░░▀▀▄ ░░░█░░░▒▒▒▒▒▒░░░░░░░░▒▒▒░░█ ░░█░░░░░░▄██▀▄▄░░░░░▄▄▄░░░█ ░▀▒▄▄▄▒░█▀▀▀▀▄▄█░░░██▄▄█░░░█ █▒█▒▄░▀▄▄▄▀░░░░░░░░█░░░▒▒▒▒▒█ █▒█░█▀▄▄░░░░░█▀░░░░▀▄░░▄▀▀▀▄▒█ ░█▀▄░█▄░█▀▄▄░▀░▀▀░▄▄▀░░░░█░░█

    ░░█░░▀▄▀█▄▄░█▀▀▀▄▄▄▄▀▀█▀██░█ ░░░█░░██░░▀█▄▄▄█▄▄█▄████░█ ░░░░█░░░▀▀▄░█░░░█░███████░█ ░░░░░▀▄░░░▀▀▄▄▄█▄█▄█▄█▄▀░░█ ░░░░░░░▀▄▄░▒▒▒▒░░░░░░░░░░█ ░░░░░░░░░░▀▀▄▄░▒▒▒▒▒▒▒▒▒▒░█ ░░░░░░░░░░░░░░▀▄▄▄▄▄░░░░░█
  31. Exception: EE ValueErrorException at <module>(ee-traceback.py:25) at func8(ee-traceback.py:23) at func7(ee-traceback.py:20) at

    func6(ee-traceback.py:17) at func5(ee-traceback.py:14) at func4(ee-traceback.py:11) at func3(ee-traceback.py:8) at func2(ee-traceback.py:5) at func1(ee-traceback.py:2)
  32. Python-EE Exceptions ░░░░▄▄▄▄▀▀▀▀▀▀▀▀▄▄▄▄▄▄ ░░░░█░░░░▒▒▒▒▒▒▒▒▒▒▒▒░░▀▀▄ ░░░█░░░▒▒▒▒▒▒░░░░░░░░▒▒▒░░█ ░░█░░░░░░▄██▀▄▄░░░░░▄▄▄░░░█ ░▀▒▄▄▄▒░█▀▀▀▀▄▄█░░░██▄▄█░░░█ █▒█▒▄░▀▄▄▄▀░░░░░░░░█░░░▒▒▒▒▒█ █▒█░█▀▄▄░░░░░█▀░░░░▀▄░░▄▀▀▀▄▒█ ░█▀▄░█▄░█▀▄▄░▀░▀▀░▄▄▀░░░░█░░█

    ░░█░░▀▄▀█▄▄░█▀▀▀▄▄▄▄▀▀█▀██░█ ░░░█░░██░░▀█▄▄▄█▄▄█▄████░█ ░░░░█░░░▀▀▄░█░░░█░███████░█ ░░░░░▀▄░░░▀▀▄▄▄█▄█▄█▄█▄▀░░█ ░░░░░░░▀▄▄░▒▒▒▒░░░░░░░░░░█ ░░░░░░░░░░▀▀▄▄░▒▒▒▒▒▒▒▒▒▒░█ ░░░░░░░░░░░░░░▀▄▄▄▄▄░░░░░█
  33. Traceback (most recent call last): File "invalid-import.py", line 1, in

    <module> import not_valid_module AbstractImportErrorBuilderException: No module named 'not_valid_module'
  34. assert no-determinista ░░░░▄▄▄▄▀▀▀▀▀▀▀▀▄▄▄▄▄▄ ░░░░█░░░░▒▒▒▒▒▒▒▒▒▒▒▒░░▀▀▄ ░░░█░░░▒▒▒▒▒▒░░░░░░░░▒▒▒░░█ ░░█░░░░░░▄██▀▄▄░░░░░▄▄▄░░░█ ░▀▒▄▄▄▒░█▀▀▀▀▄▄█░░░██▄▄█░░░█ █▒█▒▄░▀▄▄▄▀░░░░░░░░█░░░▒▒▒▒▒█ █▒█░█▀▄▄░░░░░█▀░░░░▀▄░░▄▀▀▀▄▒█ ░█▀▄░█▄░█▀▄▄░▀░▀▀░▄▄▀░░░░█░░█

    ░░█░░▀▄▀█▄▄░█▀▀▀▄▄▄▄▀▀█▀██░█ ░░░█░░██░░▀█▄▄▄█▄▄█▄████░█ ░░░░█░░░▀▀▄░█░░░█░███████░█ ░░░░░▀▄░░░▀▀▄▄▄█▄█▄█▄█▄▀░░█ ░░░░░░░▀▄▄░▒▒▒▒░░░░░░░░░░█ ░░░░░░░░░░▀▀▄▄░▒▒▒▒▒▒▒▒▒▒░█ ░░░░░░░░░░░░░░▀▄▄▄▄▄░░░░░█
  35. >>> assert True >>> assert True >>> assert True Traceback

    (most recent call last): File "<stdin>", line 1, in <module> AssertionError >>> assert True
  36. ND-Python (non-deterministic) ░░░░▄▄▄▄▀▀▀▀▀▀▀▀▄▄▄▄▄▄ ░░░░█░░░░▒▒▒▒▒▒▒▒▒▒▒▒░░▀▀▄ ░░░█░░░▒▒▒▒▒▒░░░░░░░░▒▒▒░░█ ░░█░░░░░░▄██▀▄▄░░░░░▄▄▄░░░█ ░▀▒▄▄▄▒░█▀▀▀▀▄▄█░░░██▄▄█░░░█ █▒█▒▄░▀▄▄▄▀░░░░░░░░█░░░▒▒▒▒▒█ █▒█░█▀▄▄░░░░░█▀░░░░▀▄░░▄▀▀▀▄▒█ ░█▀▄░█▄░█▀▄▄░▀░▀▀░▄▄▀░░░░█░░█

    ░░█░░▀▄▀█▄▄░█▀▀▀▄▄▄▄▀▀█▀██░█ ░░░█░░██░░▀█▄▄▄█▄▄█▄████░█ ░░░░█░░░▀▀▄░█░░░█░███████░█ ░░░░░▀▄░░░▀▀▄▄▄█▄█▄█▄█▄▀░░█ ░░░░░░░▀▄▄░▒▒▒▒░░░░░░░░░░█ ░░░░░░░░░░▀▀▄▄░▒▒▒▒▒▒▒▒▒▒░█ ░░░░░░░░░░░░░░▀▄▄▄▄▄░░░░░█
  37. >>> counter = 0 >>> while True is True: …

    counter += 1 … >>> print(counter) 1820 >>> counter = 0 >>> while True is True: … counter += 1 … >>> print(counter) 803
  38. >>> raise SystemExit ___________________________ /| /| | | ||__|| |

    The End, | / O O\__ Thank You! | / \ | / \ \ | / _ \ \ ---------------------- / |\____\ \ || / | | | |\____/ || / \|_|_|/ | __|| / / \ |____| || / | | /| | --| | | | // | ____ -- | ,* _ | |_|_|_| | \-/ ,*-- _--\ _ \ // | / _ \\ _ // | / / \_ /- | - | | ,* ___ c_c_c_C/ \C_c_c_c____________