Instrucciones generales

El Objetivo de este proyecto es desarrollar habilidades del uso del CAS de Python SymPy para resolver problemas de cálculo en el curso de Matemática Básica 2.

Entregable

Un breve informe en formato PDF y enlace con un vídeo de 5 minutos máximo explicando los resultados de su proyecto. El PDF debe incluir:

  • Carátula en la primera hoja con tus datos personales
  • Enunciado de cada problema
  • Código de Python con la solución de cada inciso
  • Capturas de pantalla con gráficas si se solicita
  • Comentarios y Ecuaciones.

Entrega tu proyecto utilizando el nombre Proyecto_Taller_Apellido_Nombre_carnet.pdf

Criterios de evaluación

  • Modelos y cálculos correctos : 40 pts
  • Código de Python comentado : 30 pts
  • Interpretación y comunicación (explicaciones, conclusiones): 20 pts
  • Presentación (orden, formato solicitado): 10 pts

Recomendación:

  • Trabaja en Google Colab con Python
  • Utiliza celdas de texto y código en tu cuaderno Colab
  • Para las ecuaciones o expresiones utiliza código LaTeX
  • Imprime tu documento como PDF y agrega la carátula
  • Carga los módulos SymPy y NumPy
  • Declara variables simbólicas y constantes
  • Deja todo el código comentado utilizando “#”

PROBLEMA 1

Una sala de cine tiene una pantalla que está colocada a 3 m del suelo y tiene 10 m de altura. La primera fila de asientos está ubicada a 3 metros de la pantalla, y las filas están separadas 1 metro. El piso de la zona de asientos está inclinado un ángulo de α = 20° arriba de la horizontal, y la distancia inclinada hasta donde usted está sentado es x. La sala tiene 21 filas de asientos, de modo que 0 ≤ x ≤ 20. Suponga que decide que el mejor lugar para sentarse es la fila donde el ángulo θ que subtiende la pantalla a sus ojos es un máximo. Suponga también que sus ojos están 1.2 m arriba del piso, como se muestra en la figura.

Auditorio
Auditorio

1 Verificación de la fórmula

Explica por qué:

\[ \theta = \arccos\left(\frac{a^2+b^2-100}{2ab}\right) \]

donde

\[ a = \sqrt{(3+x\cos \alpha)^2+(11.8-x\sin\alpha)^2}, \quad b = \sqrt{(3+x\cos \alpha)^2+(1.8-x\sin\alpha)^2} \]

Sugerencias:

  • Identifica los puntos de interés: la posición de los ojos, el borde inferior y el borde superior de la pantalla.
  • Calcula las distancias \(a\) y \(b\) desde los ojos hasta cada borde de la pantalla.
  • Aplica la Ley de Cosenos para relacionar \(a\), \(b\), la longitud de la pantalla (10 m) y el ángulo \(\theta\).
  • Despeja \(\theta\) de dicha relación.
from sympy import *

x, alpha = symbols('x alpha')

# 1. Define las coordenadas de los ojos en función de x y alpha
#    (pista: el piso sube con ángulo alpha, los ojos están 1.2 m sobre el piso)
ojo_x = '---'
ojo_y = '---'

# 2. Define las coordenadas del borde inferior y superior de la pantalla
borde_inf = ('---', '---')   # (coordenada x, coordenada y)
borde_sup = ('---', '---')

# 3. Calcula las distancias a y b (Ley de Cosenos)
a = '---'
b = '---'

# 4. Escribe theta usando arccos y la Ley de Cosenos
theta_expr = '---'
print(theta_expr)

2 Gráfica de \(\theta(x)\) y estimación del máximo

Utilice un gráfico de \(\theta\) como función de \(x\) para estimar el valor que maximiza \(\theta\). ¿En qué fila debe sentarse? ¿Cuál es el ángulo de visión en esa fila? (use \(\alpha = 20^\circ\)).

Sugerencias:

  • Sustituye \(\alpha = 20\pi/180\) en la expresión simbólica.
  • Convierte la expresión a función numérica con lambdify.
  • Grafica \(\theta(x)\) en el intervalo \([0, 20]\).
  • Obtén una tabla de valores de \(\theta(x)\) usando listas por comprensión.
# 1. Sustituye alpha por su valor en radianes
alpha_val = '---'
theta_num = theta_expr.subs('---', '---')

# 2. Crea una función numérica con lambdify
theta_fn = lambdify('---', '---', 'numpy')

# 3. Grafica theta(x) en [0, 20]
#    (usa numpy para los valores de x y matplotlib para graficar)
'---'

# 4. Genera una tabla de valores de theta para x = 0, 1, 2, ..., 20
tabla = [('---') for xi in range('---')]
for fila in tabla:
    print(fila)

3 Derivada de \(\theta(x)\) y comparación

Deriva simbólicamente \(\theta(x)\) y encuentra la raíz de \(\theta'(x)=0\). ¿Confirma el resultado del inciso 2?

Sugerencias:

  • Calcula la derivada con diff.
  • Usa nsolve con un valor inicial dentro del intervalo \([0, 20]\).
  • Evalúa la segunda derivada en el punto crítico para confirmar que es un máximo.
# 1. Calcula la derivada simbolica de theta respecto a x
dtheta = diff('---', '---')

# 2. Encuentra la raiz numerica (usa un valor inicial razonable)
x_critico = nsolve('---', x, '---')
print("x crítico:", x_critico)

# 3. Evalúa la segunda derivada para confirmar máximo
d2theta = diff('---', x, 2)
print("Segunda derivada en x crítico:", d2theta.subs(x, x_critico))

4 Valor promedio de \(\theta\)

Use la gráfica de \(\theta\) para estimar el valor promedio en \([0, 20]\). Luego calcúlelo con integración numérica.

Sugerencias:

  • Recuerda que el valor promedio es \(\bar{\theta} = \dfrac{1}{L}\displaystyle\int_0^{L}\theta(x)\,dx\).
  • Si la integral simbólica es difícil, usa integración numérica con quad de mpmath.
import mpmath as mp

L = '---'   # longitud del intervalo

# Define una función lambda para evaluar theta numéricamente
theta_lambda = lambda xi: '---'

# Calcula la integral numérica y el valor promedio
integral_val, _ = mp.quad('---', ['---', '---'])
promedio = '---'
print("Valor promedio de theta:", float(promedio))

PROBLEMA 2

Se obtiene un modelo para la forma de un huevo de un ave mediante el giro, respecto al eje \(x\), de la región bajo la gráfica de

\[ f(x) = (ax^{3} + bx^{2} + cx + d)\sqrt{1 - x^{2}} \]

\[ \text{Utilice: } a=-0.06,\; b=0.0411,\; c=0.5,\; d=0.45 \]

y la fórmula del disco:

\[ V = \pi \int_{l_i}^{l_s} \bigl[f(x)\bigr]^{2}\, dx \]

Realiza lo siguiente.

1. Definir los parámetros y la función

  • Declarar la variable simbólica \(x\).
  • Definir cada parámetro y plantear \(f(x)\).
from sympy import *
x = symbols('x')

# Define los parámetros numéricos
a_p = '---'
b_p = '---'
c_p = '---'
d_p = '---'

# Plantea f(x) simbólicamente
f = '---'
print("f(x) =", f)

2. Visualizar la función

  • Graficar \(f(x)\) en el intervalo \([-1, 1]\).
  • Observar dónde la función es positiva y si la curva se asemeja a un perfil de huevo.
import numpy as np
import matplotlib.pyplot as plt

# Convierte f a función numérica
f_num = lambdify('---', '---', 'numpy')

x_vals = np.linspace('---', '---', 400)
y_vals = '---'

# Grafica
plt.figure(figsize=(7, 3))
plt.plot('---', '---', label='f(x)')
plt.axhline(0, color='gray', linestyle='--', linewidth=0.8)
plt.xlabel('x'); plt.ylabel('f(x)')
plt.title('---')
plt.legend(); plt.tight_layout(); plt.show()

3. Elegir los límites de integración

  • Determina si usarás \([-1, 1]\) o solo la parte donde \(f(x) > 0\).
  • Justifica tu elección.
# Encuentra las raíces del polinomio interior para saber dónde f cambia de signo
polinomio = '---'
raices = solve('---', x)
print("Raíces:", raices)

4. Plantear la integral de volumen

  • Escribe la integral \(V = \pi\displaystyle\int_{l_i}^{l_s} f(x)^2\,dx\).
  • Nota que \([f(x)]^2 = (ax^3+bx^2+cx+d)^2(1-x^2)\): la raíz cuadrada desaparece.
# Escribe el integrando (aprovecha que [sqrt(1-x^2)]^2 = 1-x^2)
integrando = pi * '---'
print("Integrando:", expand(integrando))

5. Calcular el volumen

  • Calcula la integral de forma simbólica con SymPy.
  • Verifica el resultado con integración numérica.
# Método simbólico
V_sim = integrate('---', (x, '---', '---'))
print("Volumen simbólico:", V_sim)
print("Volumen numérico :", float(V_sim))

# Método numérico (verificación con mpmath)
from mpmath import quad as mpquad, pi as mpi
f_mp = lambdify(x, '---', 'mpmath')
V_num = float(mpi) * float(mpquad('---', ['---', '---']))
print("Volumen numérico (mpmath):", round(V_num, 6))

6. Comparar métodos

  • Calcula la diferencia entre ambos resultados.
  • ¿Son consistentes?
print(f"Simbólico : {float(V_sim):.6f}")
print(f"Numérico  : {V_num:.6f}")
print(f"Diferencia: {abs('---' - '---'):.2e}")

7. Interpretar el resultado

  • Reporta el volumen con 3–4 decimales.
  • Explica qué límites usaste y por qué.
  • Adjunta la gráfica de \(f(x)\).

PROBLEMA 3

En este problema vas a calcular volúmenes que se generan al hacer girar la región bajo la curva

\[ y = 5\cos(x), \qquad x \in [0.5,\; \pi] \]

Para ello utilizarás el método de capas cilíndricas completando el siguiente código.

from sympy import *
x  = symbols('x')
A  = '---'          # Amplitud de la función
f  = A*cos(x)       # Función a rotar
b  = '---'          # Eje de rotación x = b
r1 = x              # Radio desde el eje y
r2 = '---'          # Radio de rotación desde x = b

expr1 = 2*pi*f*r1   # Integrando para volumen 1
expr2 = '---'       # Integrando para volumen 2

v1 = integrate('---', (x, '---', '---')).n(5)   # Volumen 1
v2 = integrate('---', (x, '---', '---')).n(5)   # Volumen 2
print(v1, v2)
  • Calcula el volumen al hacer girar la región alrededor del eje \(y\)
  • Encuentra el volumen al hacer girar la región alrededor de \(x = b = 0.4\)

Sugerencias para completar el código:

  • Identifica la amplitud \(A\) y el valor de \(b\).
  • El radio \(r2\) es la distancia horizontal desde \(x\) hasta el eje de rotación \(x=b\).
  • La fórmula de capas cilíndricas es \(V = 2\pi\displaystyle\int_{l_i}^{l_s} r \cdot f(x)\,dx\).
  • Usa Rational(1,2) para representar \(0.5\) y pi para \(\pi\) en SymPy.
  • Observa el signo del resultado e interpreta qué ocurre cuando \(f(x) < 0\) en parte del intervalo.

Preguntas de análisis:

  1. ¿En qué subintervalo es \(5\cos(x)\) positiva y en cuál negativa?
  2. ¿Qué efecto tiene el cambio de signo sobre el volumen calculado?
  3. ¿Cómo obtendrías el volumen físico (geométrico) del sólido?
# Análisis por subintervalos
# Completa los límites de integración para cada región

# Región donde f(x) > 0
v1_positivo = integrate(expr1, (x, '---', '---')).n(5)

# Región donde f(x) < 0
v1_negativo = integrate(expr1, (x, '---', '---')).n(5)

print("Contribución positiva:", v1_positivo)
print("Contribución negativa:", v1_negativo)
print("Volumen neto         :", (v1_positivo + v1_negativo).n(5))
print("Volumen físico total :", '---')   # ¿cómo combinas ambas?

Contenido del informe

  • Código en Python (Colab o Jupyter) con todos los cálculos comentados.
  • Gráficas y resultados numéricos con al menos 4 decimales.
  • Breve explicación de cada paso y conclusiones.
LS0tDQp0aXRsZTogIlByb3llY3RvIFRhbGxlciBNYXRlbcOhdGljYSBCw6FzaWNhIDIiDQphdXRob3I6ICJEZXBhcnRhbWVudG8gZGUgTWF0ZW1hdGljYSBGSVVTQUMiDQpkYXRlOiAiYHIgZm9ybWF0KFN5cy5EYXRlKCksICclZC8lbS8lWScpYCINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0aGVtZTogdW5pdGVkDQogICAgdG9jOiB0cnVlDQogICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgdG9jX2RlcHRoOiAzDQogICAgbnVtYmVyX3NlY3Rpb25zOiBmYWxzZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgcGRmX2RvY3VtZW50Og0KICAgIHRvYzogdHJ1ZQ0KICAgIG51bWJlcl9zZWN0aW9uczogZmFsc2UNCmZvbnRzaXplOiAxM3B0DQpnZW9tZXRyeTogbWFyZ2luPTIuMmNtDQpsYW5nOiBlcw0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KA0KCWVjaG8gPSBUUlVFLA0KCW1lc3NhZ2UgPSBGQUxTRSwNCgl3YXJuaW5nID0gRkFMU0UsDQoJZXZhbCA9IEZBTFNFDQopDQpgYGANCg0KDQoNCiMgKipJbnN0cnVjY2lvbmVzIGdlbmVyYWxlcyoqDQoNCkVsICoqT2JqZXRpdm8qKiBkZSBlc3RlIHByb3llY3RvIGVzIGRlc2Fycm9sbGFyIGhhYmlsaWRhZGVzIGRlbCB1c28gZGVsIENBUyBkZSAqKlB5dGhvbiBTeW1QeSoqIHBhcmEgcmVzb2x2ZXIgcHJvYmxlbWFzIGRlIGPDoWxjdWxvIGVuIGVsIGN1cnNvIGRlIE1hdGVtw6F0aWNhIELDoXNpY2EgMi4NCg0KIyMgKipFbnRyZWdhYmxlKioNCg0KVW4gYnJldmUgKippbmZvcm1lKiogZW4gZm9ybWF0byBQREYgeSBlbmxhY2UgY29uIHVuIHbDrWRlbyBkZSA1IG1pbnV0b3MgbcOheGltbyBleHBsaWNhbmRvIGxvcyByZXN1bHRhZG9zIGRlIHN1IHByb3llY3RvLiBFbCBQREYgZGViZSBpbmNsdWlyOg0KDQoqIENhcsOhdHVsYSBlbiBsYSBwcmltZXJhIGhvamEgY29uIHR1cyBkYXRvcyBwZXJzb25hbGVzDQoqIEVudW5jaWFkbyBkZSBjYWRhIHByb2JsZW1hDQoqIEPDs2RpZ28gZGUgKipQeXRob24qKiBjb24gbGEgc29sdWNpw7NuIGRlIGNhZGEgaW5jaXNvDQoqIENhcHR1cmFzIGRlIHBhbnRhbGxhIGNvbiBncsOhZmljYXMgc2kgc2Ugc29saWNpdGENCiogQ29tZW50YXJpb3MgeSBFY3VhY2lvbmVzLg0KDQpFbnRyZWdhIHR1IHByb3llY3RvIHV0aWxpemFuZG8gZWwgbm9tYnJlIGBQcm95ZWN0b19UYWxsZXJfQXBlbGxpZG9fTm9tYnJlX2Nhcm5ldC5wZGZgDQoNCiMjICoqQ3JpdGVyaW9zIGRlIGV2YWx1YWNpw7NuKioNCg0KLSBNb2RlbG9zIHkgY8OhbGN1bG9zIGNvcnJlY3RvcyA6ICoqNDAgcHRzKioNCi0gQ8OzZGlnbyBkZSBQeXRob24gY29tZW50YWRvIDogICoqMzAgcHRzKioNCi0gSW50ZXJwcmV0YWNpw7NuIHkgY29tdW5pY2FjacOzbiAoZXhwbGljYWNpb25lcywgY29uY2x1c2lvbmVzKTogKioyMCBwdHMqKg0KLSBQcmVzZW50YWNpw7NuIChvcmRlbiwgZm9ybWF0byBzb2xpY2l0YWRvKTogKioxMCBwdHMqKg0KDQojIyAqKlJlY29tZW5kYWNpw7NuOioqDQoNCiogVHJhYmFqYSBlbiAqKkdvb2dsZSBDb2xhYiBjb24gUHl0aG9uKioNCiogVXRpbGl6YSBjZWxkYXMgZGUgdGV4dG8geSBjw7NkaWdvIGVuIHR1IGN1YWRlcm5vIENvbGFiDQoqIFBhcmEgbGFzIGVjdWFjaW9uZXMgbyBleHByZXNpb25lcyB1dGlsaXphIGPDs2RpZ28gTGFUZVgNCiogSW1wcmltZSB0dSBkb2N1bWVudG8gY29tbyBQREYgeSBhZ3JlZ2EgbGEgY2Fyw6F0dWxhDQoqIENhcmdhIGxvcyBtw7NkdWxvcyAqKlN5bVB5IHkgTnVtUHkqKg0KKiBEZWNsYXJhIHZhcmlhYmxlcyBzaW1iw7NsaWNhcyB5IGNvbnN0YW50ZXMNCiogRGVqYSB0b2RvIGVsIGPDs2RpZ28gY29tZW50YWRvIHV0aWxpemFuZG8gKioiIyIqKg0KDQoNCiMgKipQUk9CTEVNQSAxKioNCg0KVW5hIHNhbGEgZGUgY2luZSB0aWVuZSB1bmEgcGFudGFsbGEgcXVlIGVzdMOhIGNvbG9jYWRhIGEgMyBtIGRlbCBzdWVsbyB5IHRpZW5lIDEwIG0gZGUgYWx0dXJhLg0KTGEgcHJpbWVyYSBmaWxhIGRlIGFzaWVudG9zIGVzdMOhIHViaWNhZGEgYSAzIG1ldHJvcyBkZSBsYSBwYW50YWxsYSwgeSBsYXMgZmlsYXMgZXN0w6FuIHNlcGFyYWRhcyAxIG1ldHJvLiBFbCBwaXNvIGRlIGxhIHpvbmEgZGUgYXNpZW50b3MgZXN0w6EgaW5jbGluYWRvIHVuIMOhbmd1bG8gZGUgzrEgPSAyMMKwIGFycmliYSBkZSBsYSBob3Jpem9udGFsLCB5IGxhIGRpc3RhbmNpYSBpbmNsaW5hZGEgaGFzdGEgZG9uZGUgdXN0ZWQgZXN0w6Egc2VudGFkbyBlcyB4LiBMYSBzYWxhIHRpZW5lIDIxIGZpbGFzIGRlIGFzaWVudG9zLCBkZSBtb2RvIHF1ZSAwIOKJpCB4IOKJpCAyMC4gU3Vwb25nYSBxdWUgZGVjaWRlIHF1ZSBlbCBtZWpvciBsdWdhciBwYXJhIHNlbnRhcnNlIGVzIGxhIGZpbGEgZG9uZGUgZWwgw6FuZ3VsbyDOuCBxdWUgc3VidGllbmRlIGxhIHBhbnRhbGxhIGEgc3VzIG9qb3MgZXMgdW4gbcOheGltby4gU3Vwb25nYSB0YW1iacOpbiBxdWUgc3VzIG9qb3MgZXN0w6FuIDEuMiBtIGFycmliYSBkZWwgcGlzbywgY29tbyBzZSBtdWVzdHJhIGVuIGxhIGZpZ3VyYS4NCg0KIVtBdWRpdG9yaW9dKGF1ZGl0b3Jpb19tZWpvcmFkYV9ncmlzXzJ4LnBuZyl7d2lkdGg9NjAlfQ0KDQojIyMgKioxIFZlcmlmaWNhY2nDs24gZGUgbGEgZsOzcm11bGEqKg0KDQpFeHBsaWNhIHBvciBxdcOpOg0KDQokJA0KXHRoZXRhID0gXGFyY2Nvc1xsZWZ0KFxmcmFje2FeMitiXjItMTAwfXsyYWJ9XHJpZ2h0KQ0KJCQNCg0KZG9uZGUNCg0KJCQNCmEgPSBcc3FydHsoMyt4XGNvcyBcYWxwaGEpXjIrKDExLjgteFxzaW5cYWxwaGEpXjJ9LCBccXVhZA0KYiA9IFxzcXJ0eygzK3hcY29zIFxhbHBoYSleMisoMS44LXhcc2luXGFscGhhKV4yfQ0KJCQNCg0KKipTdWdlcmVuY2lhczoqKg0KDQotIElkZW50aWZpY2EgbG9zIHB1bnRvcyBkZSBpbnRlcsOpczogbGEgcG9zaWNpw7NuIGRlIGxvcyBvam9zLCBlbCBib3JkZSBpbmZlcmlvciB5IGVsIGJvcmRlIHN1cGVyaW9yIGRlIGxhIHBhbnRhbGxhLg0KLSBDYWxjdWxhIGxhcyBkaXN0YW5jaWFzICRhJCB5ICRiJCBkZXNkZSBsb3Mgb2pvcyBoYXN0YSBjYWRhIGJvcmRlIGRlIGxhIHBhbnRhbGxhLg0KLSBBcGxpY2EgbGEgKipMZXkgZGUgQ29zZW5vcyoqIHBhcmEgcmVsYWNpb25hciAkYSQsICRiJCwgbGEgbG9uZ2l0dWQgZGUgbGEgcGFudGFsbGEgKDEwIG0pIHkgZWwgw6FuZ3VsbyAkXHRoZXRhJC4NCi0gRGVzcGVqYSAkXHRoZXRhJCBkZSBkaWNoYSByZWxhY2nDs24uDQoNCmBgYHtweXRob24gZXZhbD1GQUxTRSwgaW5jbHVkZT1UUlVFfQ0KZnJvbSBzeW1weSBpbXBvcnQgKg0KDQp4LCBhbHBoYSA9IHN5bWJvbHMoJ3ggYWxwaGEnKQ0KDQojIDEuIERlZmluZSBsYXMgY29vcmRlbmFkYXMgZGUgbG9zIG9qb3MgZW4gZnVuY2nDs24gZGUgeCB5IGFscGhhDQojICAgIChwaXN0YTogZWwgcGlzbyBzdWJlIGNvbiDDoW5ndWxvIGFscGhhLCBsb3Mgb2pvcyBlc3TDoW4gMS4yIG0gc29icmUgZWwgcGlzbykNCm9qb194ID0gJy0tLScNCm9qb195ID0gJy0tLScNCg0KIyAyLiBEZWZpbmUgbGFzIGNvb3JkZW5hZGFzIGRlbCBib3JkZSBpbmZlcmlvciB5IHN1cGVyaW9yIGRlIGxhIHBhbnRhbGxhDQpib3JkZV9pbmYgPSAoJy0tLScsICctLS0nKSAgICMgKGNvb3JkZW5hZGEgeCwgY29vcmRlbmFkYSB5KQ0KYm9yZGVfc3VwID0gKCctLS0nLCAnLS0tJykNCg0KIyAzLiBDYWxjdWxhIGxhcyBkaXN0YW5jaWFzIGEgeSBiIChMZXkgZGUgQ29zZW5vcykNCmEgPSAnLS0tJw0KYiA9ICctLS0nDQoNCiMgNC4gRXNjcmliZSB0aGV0YSB1c2FuZG8gYXJjY29zIHkgbGEgTGV5IGRlIENvc2Vub3MNCnRoZXRhX2V4cHIgPSAnLS0tJw0KcHJpbnQodGhldGFfZXhwcikNCmBgYA0KDQoNCiMjIyAqKjIgR3LDoWZpY2EgZGUgXChcdGhldGEoeClcKSB5IGVzdGltYWNpw7NuIGRlbCBtw6F4aW1vKioNCg0KVXRpbGljZSB1biBncsOhZmljbyBkZSBcKFx0aGV0YVwpIGNvbW8gZnVuY2nDs24gZGUgXCh4XCkgcGFyYSBlc3RpbWFyIGVsIHZhbG9yIHF1ZSBtYXhpbWl6YSBcKFx0aGV0YVwpLg0Kwr9FbiBxdcOpIGZpbGEgZGViZSBzZW50YXJzZT8gwr9DdcOhbCBlcyBlbCDDoW5ndWxvIGRlIHZpc2nDs24gZW4gZXNhIGZpbGE/ICh1c2UgXChcYWxwaGEgPSAyMF5cY2lyY1wpKS4NCg0KKipTdWdlcmVuY2lhczoqKg0KDQotIFN1c3RpdHV5ZSBcKFxhbHBoYSA9IDIwXHBpLzE4MFwpIGVuIGxhIGV4cHJlc2nDs24gc2ltYsOzbGljYS4NCi0gQ29udmllcnRlIGxhIGV4cHJlc2nDs24gYSBmdW5jacOzbiBudW3DqXJpY2EgY29uIGBsYW1iZGlmeWAuDQotIEdyYWZpY2EgXChcdGhldGEoeClcKSBlbiBlbCBpbnRlcnZhbG8gJFswLCAyMF0kLg0KLSBPYnTDqW4gdW5hIHRhYmxhIGRlIHZhbG9yZXMgZGUgXChcdGhldGEoeClcKSB1c2FuZG8gbGlzdGFzIHBvciBjb21wcmVuc2nDs24uDQoNCmBgYHtweXRob24gZXZhbD1GQUxTRSwgaW5jbHVkZT1UUlVFfQ0KIyAxLiBTdXN0aXR1eWUgYWxwaGEgcG9yIHN1IHZhbG9yIGVuIHJhZGlhbmVzDQphbHBoYV92YWwgPSAnLS0tJw0KdGhldGFfbnVtID0gdGhldGFfZXhwci5zdWJzKCctLS0nLCAnLS0tJykNCg0KIyAyLiBDcmVhIHVuYSBmdW5jacOzbiBudW3DqXJpY2EgY29uIGxhbWJkaWZ5DQp0aGV0YV9mbiA9IGxhbWJkaWZ5KCctLS0nLCAnLS0tJywgJ251bXB5JykNCg0KIyAzLiBHcmFmaWNhIHRoZXRhKHgpIGVuIFswLCAyMF0NCiMgICAgKHVzYSBudW1weSBwYXJhIGxvcyB2YWxvcmVzIGRlIHggeSBtYXRwbG90bGliIHBhcmEgZ3JhZmljYXIpDQonLS0tJw0KDQojIDQuIEdlbmVyYSB1bmEgdGFibGEgZGUgdmFsb3JlcyBkZSB0aGV0YSBwYXJhIHggPSAwLCAxLCAyLCAuLi4sIDIwDQp0YWJsYSA9IFsoJy0tLScpIGZvciB4aSBpbiByYW5nZSgnLS0tJyldDQpmb3IgZmlsYSBpbiB0YWJsYToNCiAgICBwcmludChmaWxhKQ0KYGBgDQoNCg0KIyMjICoqMyBEZXJpdmFkYSBkZSBcKFx0aGV0YSh4KVwpIHkgY29tcGFyYWNpw7NuKioNCg0KRGVyaXZhIHNpbWLDs2xpY2FtZW50ZSBcKFx0aGV0YSh4KVwpIHkgZW5jdWVudHJhIGxhIHJhw616IGRlIFwoXHRoZXRhJyh4KT0wXCkuDQrCv0NvbmZpcm1hIGVsIHJlc3VsdGFkbyBkZWwgaW5jaXNvIDI/DQoNCioqU3VnZXJlbmNpYXM6KioNCg0KLSBDYWxjdWxhIGxhIGRlcml2YWRhIGNvbiBgZGlmZmAuDQotIFVzYSBgbnNvbHZlYCBjb24gdW4gdmFsb3IgaW5pY2lhbCBkZW50cm8gZGVsIGludGVydmFsbyAkWzAsIDIwXSQuDQotIEV2YWzDumEgbGEgc2VndW5kYSBkZXJpdmFkYSBlbiBlbCBwdW50byBjcsOtdGljbyBwYXJhIGNvbmZpcm1hciBxdWUgZXMgdW4gbcOheGltby4NCg0KYGBge3B5dGhvbiBldmFsPUZBTFNFLCBpbmNsdWRlPVRSVUV9DQojIDEuIENhbGN1bGEgbGEgZGVyaXZhZGEgc2ltYm9saWNhIGRlIHRoZXRhIHJlc3BlY3RvIGEgeA0KZHRoZXRhID0gZGlmZignLS0tJywgJy0tLScpDQoNCiMgMi4gRW5jdWVudHJhIGxhIHJhaXogbnVtZXJpY2EgKHVzYSB1biB2YWxvciBpbmljaWFsIHJhem9uYWJsZSkNCnhfY3JpdGljbyA9IG5zb2x2ZSgnLS0tJywgeCwgJy0tLScpDQpwcmludCgieCBjcsOtdGljbzoiLCB4X2NyaXRpY28pDQoNCiMgMy4gRXZhbMO6YSBsYSBzZWd1bmRhIGRlcml2YWRhIHBhcmEgY29uZmlybWFyIG3DoXhpbW8NCmQydGhldGEgPSBkaWZmKCctLS0nLCB4LCAyKQ0KcHJpbnQoIlNlZ3VuZGEgZGVyaXZhZGEgZW4geCBjcsOtdGljbzoiLCBkMnRoZXRhLnN1YnMoeCwgeF9jcml0aWNvKSkNCmBgYA0KDQoNCiMjIyAqKjQgVmFsb3IgcHJvbWVkaW8gZGUgXChcdGhldGFcKSoqDQoNClVzZSBsYSBncsOhZmljYSBkZSBcKFx0aGV0YVwpIHBhcmEgZXN0aW1hciBlbCB2YWxvciBwcm9tZWRpbyBlbiAkWzAsIDIwXSQuDQpMdWVnbyBjYWxjw7psZWxvIGNvbiBpbnRlZ3JhY2nDs24gbnVtw6lyaWNhLg0KDQoqKlN1Z2VyZW5jaWFzOioqDQoNCi0gUmVjdWVyZGEgcXVlIGVsIHZhbG9yIHByb21lZGlvIGVzICRcYmFye1x0aGV0YX0gPSBcZGZyYWN7MX17TH1cZGlzcGxheXN0eWxlXGludF8wXntMfVx0aGV0YSh4KVwsZHgkLg0KLSBTaSBsYSBpbnRlZ3JhbCBzaW1iw7NsaWNhIGVzIGRpZsOtY2lsLCB1c2EgaW50ZWdyYWNpw7NuIG51bcOpcmljYSBjb24gYHF1YWRgIGRlIGBtcG1hdGhgLg0KDQpgYGB7cHl0aG9uIGV2YWw9RkFMU0UsIGluY2x1ZGU9VFJVRX0NCmltcG9ydCBtcG1hdGggYXMgbXANCg0KTCA9ICctLS0nICAgIyBsb25naXR1ZCBkZWwgaW50ZXJ2YWxvDQoNCiMgRGVmaW5lIHVuYSBmdW5jacOzbiBsYW1iZGEgcGFyYSBldmFsdWFyIHRoZXRhIG51bcOpcmljYW1lbnRlDQp0aGV0YV9sYW1iZGEgPSBsYW1iZGEgeGk6ICctLS0nDQoNCiMgQ2FsY3VsYSBsYSBpbnRlZ3JhbCBudW3DqXJpY2EgeSBlbCB2YWxvciBwcm9tZWRpbw0KaW50ZWdyYWxfdmFsLCBfID0gbXAucXVhZCgnLS0tJywgWyctLS0nLCAnLS0tJ10pDQpwcm9tZWRpbyA9ICctLS0nDQpwcmludCgiVmFsb3IgcHJvbWVkaW8gZGUgdGhldGE6IiwgZmxvYXQocHJvbWVkaW8pKQ0KYGBgDQoNCg0KIyAqKlBST0JMRU1BIDIqKg0KDQpTZSBvYnRpZW5lIHVuIG1vZGVsbyBwYXJhIGxhIGZvcm1hIGRlIHVuIGh1ZXZvIGRlIHVuIGF2ZSBtZWRpYW50ZSBlbCBnaXJvLCByZXNwZWN0byBhbCBlamUgJHgkLCBkZSBsYSByZWdpw7NuIGJham8gbGEgZ3LDoWZpY2EgZGUNCg0KJCQNCmYoeCkgPSAoYXheezN9ICsgYnheezJ9ICsgY3ggKyBkKVxzcXJ0ezEgLSB4XnsyfX0NCiQkDQoNCiQkDQpcdGV4dHtVdGlsaWNlOiB9IGE9LTAuMDYsXDsgYj0wLjA0MTEsXDsgYz0wLjUsXDsgZD0wLjQ1DQokJA0KDQp5IGxhIGbDs3JtdWxhIGRlbCBkaXNjbzoNCg0KJCQNClYgPSBccGkgXGludF97bF9pfV57bF9zfSBcYmlnbFtmKHgpXGJpZ3JdXnsyfVwsIGR4DQokJA0KDQpSZWFsaXphIGxvIHNpZ3VpZW50ZS4NCg0KDQojIyMgMS4gKipEZWZpbmlyIGxvcyBwYXLDoW1ldHJvcyB5IGxhIGZ1bmNpw7NuKioNCg0KLSBEZWNsYXJhciBsYSB2YXJpYWJsZSBzaW1iw7NsaWNhICR4JC4NCi0gRGVmaW5pciBjYWRhIHBhcsOhbWV0cm8geSBwbGFudGVhciAkZih4KSQuDQoNCmBgYHtweXRob24gZXZhbD1GQUxTRSwgaW5jbHVkZT1UUlVFfQ0KZnJvbSBzeW1weSBpbXBvcnQgKg0KeCA9IHN5bWJvbHMoJ3gnKQ0KDQojIERlZmluZSBsb3MgcGFyw6FtZXRyb3MgbnVtw6lyaWNvcw0KYV9wID0gJy0tLScNCmJfcCA9ICctLS0nDQpjX3AgPSAnLS0tJw0KZF9wID0gJy0tLScNCg0KIyBQbGFudGVhIGYoeCkgc2ltYsOzbGljYW1lbnRlDQpmID0gJy0tLScNCnByaW50KCJmKHgpID0iLCBmKQ0KYGBgDQoNCiMjIyAyLiAqKlZpc3VhbGl6YXIgbGEgZnVuY2nDs24qKg0KDQotIEdyYWZpY2FyICRmKHgpJCBlbiBlbCBpbnRlcnZhbG8gJFstMSwgMV0kLg0KLSBPYnNlcnZhciBkw7NuZGUgbGEgZnVuY2nDs24gZXMgcG9zaXRpdmEgeSBzaSBsYSBjdXJ2YSBzZSBhc2VtZWphIGEgdW4gcGVyZmlsIGRlIGh1ZXZvLg0KDQpgYGB7cHl0aG9uIGV2YWw9RkFMU0UsIGluY2x1ZGU9VFJVRX0NCmltcG9ydCBudW1weSBhcyBucA0KaW1wb3J0IG1hdHBsb3RsaWIucHlwbG90IGFzIHBsdA0KDQojIENvbnZpZXJ0ZSBmIGEgZnVuY2nDs24gbnVtw6lyaWNhDQpmX251bSA9IGxhbWJkaWZ5KCctLS0nLCAnLS0tJywgJ251bXB5JykNCg0KeF92YWxzID0gbnAubGluc3BhY2UoJy0tLScsICctLS0nLCA0MDApDQp5X3ZhbHMgPSAnLS0tJw0KDQojIEdyYWZpY2ENCnBsdC5maWd1cmUoZmlnc2l6ZT0oNywgMykpDQpwbHQucGxvdCgnLS0tJywgJy0tLScsIGxhYmVsPSdmKHgpJykNCnBsdC5heGhsaW5lKDAsIGNvbG9yPSdncmF5JywgbGluZXN0eWxlPSctLScsIGxpbmV3aWR0aD0wLjgpDQpwbHQueGxhYmVsKCd4Jyk7IHBsdC55bGFiZWwoJ2YoeCknKQ0KcGx0LnRpdGxlKCctLS0nKQ0KcGx0LmxlZ2VuZCgpOyBwbHQudGlnaHRfbGF5b3V0KCk7IHBsdC5zaG93KCkNCmBgYA0KDQojIyMgMy4gKipFbGVnaXIgbG9zIGzDrW1pdGVzIGRlIGludGVncmFjacOzbioqDQoNCi0gRGV0ZXJtaW5hIHNpIHVzYXLDoXMgJFstMSwgMV0kIG8gc29sbyBsYSBwYXJ0ZSBkb25kZSAkZih4KSA+IDAkLg0KLSBKdXN0aWZpY2EgdHUgZWxlY2Npw7NuLg0KDQpgYGB7cHl0aG9uIGV2YWw9RkFMU0UsIGluY2x1ZGU9VFJVRX0NCiMgRW5jdWVudHJhIGxhcyByYcOtY2VzIGRlbCBwb2xpbm9taW8gaW50ZXJpb3IgcGFyYSBzYWJlciBkw7NuZGUgZiBjYW1iaWEgZGUgc2lnbm8NCnBvbGlub21pbyA9ICctLS0nDQpyYWljZXMgPSBzb2x2ZSgnLS0tJywgeCkNCnByaW50KCJSYcOtY2VzOiIsIHJhaWNlcykNCmBgYA0KDQojIyMgNC4gKipQbGFudGVhciBsYSBpbnRlZ3JhbCBkZSB2b2x1bWVuKioNCg0KLSBFc2NyaWJlIGxhIGludGVncmFsICRWID0gXHBpXGRpc3BsYXlzdHlsZVxpbnRfe2xfaX1ee2xfc30gZih4KV4yXCxkeCQuDQotIE5vdGEgcXVlICRbZih4KV1eMiA9IChheF4zK2J4XjIrY3grZCleMigxLXheMikkOiBsYSByYcOteiBjdWFkcmFkYSBkZXNhcGFyZWNlLg0KDQpgYGB7cHl0aG9uIGV2YWw9RkFMU0UsIGluY2x1ZGU9VFJVRX0NCiMgRXNjcmliZSBlbCBpbnRlZ3JhbmRvIChhcHJvdmVjaGEgcXVlIFtzcXJ0KDEteF4yKV1eMiA9IDEteF4yKQ0KaW50ZWdyYW5kbyA9IHBpICogJy0tLScNCnByaW50KCJJbnRlZ3JhbmRvOiIsIGV4cGFuZChpbnRlZ3JhbmRvKSkNCmBgYA0KDQojIyMgNS4gKipDYWxjdWxhciBlbCB2b2x1bWVuKioNCg0KLSBDYWxjdWxhIGxhIGludGVncmFsIGRlIGZvcm1hICoqc2ltYsOzbGljYSoqIGNvbiBTeW1QeS4NCi0gVmVyaWZpY2EgZWwgcmVzdWx0YWRvIGNvbiBpbnRlZ3JhY2nDs24gKipudW3DqXJpY2EqKi4NCg0KYGBge3B5dGhvbiBldmFsPUZBTFNFLCBpbmNsdWRlPVRSVUV9DQojIE3DqXRvZG8gc2ltYsOzbGljbw0KVl9zaW0gPSBpbnRlZ3JhdGUoJy0tLScsICh4LCAnLS0tJywgJy0tLScpKQ0KcHJpbnQoIlZvbHVtZW4gc2ltYsOzbGljbzoiLCBWX3NpbSkNCnByaW50KCJWb2x1bWVuIG51bcOpcmljbyA6IiwgZmxvYXQoVl9zaW0pKQ0KDQojIE3DqXRvZG8gbnVtw6lyaWNvICh2ZXJpZmljYWNpw7NuIGNvbiBtcG1hdGgpDQpmcm9tIG1wbWF0aCBpbXBvcnQgcXVhZCBhcyBtcHF1YWQsIHBpIGFzIG1waQ0KZl9tcCA9IGxhbWJkaWZ5KHgsICctLS0nLCAnbXBtYXRoJykNClZfbnVtID0gZmxvYXQobXBpKSAqIGZsb2F0KG1wcXVhZCgnLS0tJywgWyctLS0nLCAnLS0tJ10pKQ0KcHJpbnQoIlZvbHVtZW4gbnVtw6lyaWNvIChtcG1hdGgpOiIsIHJvdW5kKFZfbnVtLCA2KSkNCmBgYA0KDQojIyMgNi4gKipDb21wYXJhciBtw6l0b2RvcyoqDQoNCi0gQ2FsY3VsYSBsYSBkaWZlcmVuY2lhIGVudHJlIGFtYm9zIHJlc3VsdGFkb3MuDQotIMK/U29uIGNvbnNpc3RlbnRlcz8NCg0KYGBge3B5dGhvbiBldmFsPUZBTFNFLCBpbmNsdWRlPVRSVUV9DQpwcmludChmIlNpbWLDs2xpY28gOiB7ZmxvYXQoVl9zaW0pOi42Zn0iKQ0KcHJpbnQoZiJOdW3DqXJpY28gIDoge1ZfbnVtOi42Zn0iKQ0KcHJpbnQoZiJEaWZlcmVuY2lhOiB7YWJzKCctLS0nIC0gJy0tLScpOi4yZX0iKQ0KYGBgDQoNCiMjIyA3LiAqKkludGVycHJldGFyIGVsIHJlc3VsdGFkbyoqDQoNCi0gUmVwb3J0YSBlbCB2b2x1bWVuIGNvbiAz4oCTNCBkZWNpbWFsZXMuDQotIEV4cGxpY2EgcXXDqSBsw61taXRlcyB1c2FzdGUgeSBwb3IgcXXDqS4NCi0gQWRqdW50YSBsYSBncsOhZmljYSBkZSAkZih4KSQuDQoNCg0KIyAqKlBST0JMRU1BIDMqKg0KDQpFbiBlc3RlIHByb2JsZW1hIHZhcyBhIGNhbGN1bGFyIHZvbMO6bWVuZXMgcXVlIHNlIGdlbmVyYW4gYWwgaGFjZXIgZ2lyYXIgbGEgcmVnacOzbiBiYWpvIGxhIGN1cnZhDQoNCiQkDQp5ID0gNVxjb3MoeCksIFxxcXVhZCB4IFxpbiBbMC41LFw7IFxwaV0NCiQkDQoNClBhcmEgZWxsbyB1dGlsaXphcsOhcyBlbCAqKm3DqXRvZG8gZGUgY2FwYXMgY2lsw61uZHJpY2FzKiogY29tcGxldGFuZG8gZWwgc2lndWllbnRlIGPDs2RpZ28uDQoNCmBgYHtweXRob24gZXZhbD1GQUxTRSwgaW5jbHVkZT1UUlVFfQ0KZnJvbSBzeW1weSBpbXBvcnQgKg0KeCAgPSBzeW1ib2xzKCd4JykNCkEgID0gJy0tLScgICAgICAgICAgIyBBbXBsaXR1ZCBkZSBsYSBmdW5jacOzbg0KZiAgPSBBKmNvcyh4KSAgICAgICAjIEZ1bmNpw7NuIGEgcm90YXINCmIgID0gJy0tLScgICAgICAgICAgIyBFamUgZGUgcm90YWNpw7NuIHggPSBiDQpyMSA9IHggICAgICAgICAgICAgICMgUmFkaW8gZGVzZGUgZWwgZWplIHkNCnIyID0gJy0tLScgICAgICAgICAgIyBSYWRpbyBkZSByb3RhY2nDs24gZGVzZGUgeCA9IGINCg0KZXhwcjEgPSAyKnBpKmYqcjEgICAjIEludGVncmFuZG8gcGFyYSB2b2x1bWVuIDENCmV4cHIyID0gJy0tLScgICAgICAgIyBJbnRlZ3JhbmRvIHBhcmEgdm9sdW1lbiAyDQoNCnYxID0gaW50ZWdyYXRlKCctLS0nLCAoeCwgJy0tLScsICctLS0nKSkubig1KSAgICMgVm9sdW1lbiAxDQp2MiA9IGludGVncmF0ZSgnLS0tJywgKHgsICctLS0nLCAnLS0tJykpLm4oNSkgICAjIFZvbHVtZW4gMg0KcHJpbnQodjEsIHYyKQ0KYGBgDQoNCiogQ2FsY3VsYSBlbCB2b2x1bWVuIGFsIGhhY2VyIGdpcmFyIGxhIHJlZ2nDs24gYWxyZWRlZG9yIGRlbCAqKmVqZSAkeSQqKg0KKiBFbmN1ZW50cmEgZWwgdm9sdW1lbiBhbCBoYWNlciBnaXJhciBsYSByZWdpw7NuIGFscmVkZWRvciBkZSAqKiR4ID0gYiA9IDAuNCQqKg0KDQoqKlN1Z2VyZW5jaWFzIHBhcmEgY29tcGxldGFyIGVsIGPDs2RpZ286KioNCg0KLSBJZGVudGlmaWNhIGxhIGFtcGxpdHVkICRBJCB5IGVsIHZhbG9yIGRlICRiJC4NCi0gRWwgcmFkaW8gJHIyJCBlcyBsYSBkaXN0YW5jaWEgaG9yaXpvbnRhbCBkZXNkZSAkeCQgaGFzdGEgZWwgZWplIGRlIHJvdGFjacOzbiAkeD1iJC4NCi0gTGEgZsOzcm11bGEgZGUgY2FwYXMgY2lsw61uZHJpY2FzIGVzICRWID0gMlxwaVxkaXNwbGF5c3R5bGVcaW50X3tsX2l9XntsX3N9IHIgXGNkb3QgZih4KVwsZHgkLg0KLSBVc2EgYFJhdGlvbmFsKDEsMilgIHBhcmEgcmVwcmVzZW50YXIgJDAuNSQgeSBgcGlgIHBhcmEgJFxwaSQgZW4gU3ltUHkuDQotIE9ic2VydmEgZWwgc2lnbm8gZGVsIHJlc3VsdGFkbyBlIGludGVycHJldGEgcXXDqSBvY3VycmUgY3VhbmRvICRmKHgpIDwgMCQgZW4gcGFydGUgZGVsIGludGVydmFsby4NCg0KKipQcmVndW50YXMgZGUgYW7DoWxpc2lzOioqDQoNCjEuIMK/RW4gcXXDqSBzdWJpbnRlcnZhbG8gZXMgJDVcY29zKHgpJCBwb3NpdGl2YSB5IGVuIGN1w6FsIG5lZ2F0aXZhPw0KMi4gwr9RdcOpIGVmZWN0byB0aWVuZSBlbCBjYW1iaW8gZGUgc2lnbm8gc29icmUgZWwgdm9sdW1lbiBjYWxjdWxhZG8/DQozLiDCv0PDs21vIG9idGVuZHLDrWFzIGVsIHZvbHVtZW4gZsOtc2ljbyAoZ2VvbcOpdHJpY28pIGRlbCBzw7NsaWRvPw0KDQpgYGB7cHl0aG9uIGV2YWw9RkFMU0UsIGluY2x1ZGU9VFJVRX0NCiMgQW7DoWxpc2lzIHBvciBzdWJpbnRlcnZhbG9zDQojIENvbXBsZXRhIGxvcyBsw61taXRlcyBkZSBpbnRlZ3JhY2nDs24gcGFyYSBjYWRhIHJlZ2nDs24NCg0KIyBSZWdpw7NuIGRvbmRlIGYoeCkgPiAwDQp2MV9wb3NpdGl2byA9IGludGVncmF0ZShleHByMSwgKHgsICctLS0nLCAnLS0tJykpLm4oNSkNCg0KIyBSZWdpw7NuIGRvbmRlIGYoeCkgPCAwDQp2MV9uZWdhdGl2byA9IGludGVncmF0ZShleHByMSwgKHgsICctLS0nLCAnLS0tJykpLm4oNSkNCg0KcHJpbnQoIkNvbnRyaWJ1Y2nDs24gcG9zaXRpdmE6IiwgdjFfcG9zaXRpdm8pDQpwcmludCgiQ29udHJpYnVjacOzbiBuZWdhdGl2YToiLCB2MV9uZWdhdGl2bykNCnByaW50KCJWb2x1bWVuIG5ldG8gICAgICAgICA6IiwgKHYxX3Bvc2l0aXZvICsgdjFfbmVnYXRpdm8pLm4oNSkpDQpwcmludCgiVm9sdW1lbiBmw61zaWNvIHRvdGFsIDoiLCAnLS0tJykgICAjIMK/Y8OzbW8gY29tYmluYXMgYW1iYXM/DQpgYGANCg0KDQojICoqQ29udGVuaWRvIGRlbCBpbmZvcm1lKioNCg0KLSBDw7NkaWdvIGVuIFB5dGhvbiAoQ29sYWIgbyBKdXB5dGVyKSBjb24gdG9kb3MgbG9zIGPDoWxjdWxvcyBjb21lbnRhZG9zLg0KLSBHcsOhZmljYXMgeSByZXN1bHRhZG9zIG51bcOpcmljb3MgY29uIGFsIG1lbm9zIDQgZGVjaW1hbGVzLg0KLSBCcmV2ZSBleHBsaWNhY2nDs24gZGUgY2FkYSBwYXNvIHkgY29uY2x1c2lvbmVzLg0K