Definición de una
función en R
Función
Una función cualquiera en R está compuesta por tres partes:
- Entradas. Los argumentos de la función.
- Proceso. O el cuerpo de la función, son las instrucciones de lo que
la función debe hacer.
- Salida. El resultado, es lo que por diseño debe hacer la función, su
producto final.
Sintaxis Paso a Paso
en R
Para construir cualquier función en R, es recomendable entender la
siguiente estructura:
mi_funcion <- function(argumento1, argumento2) {
# 1. Realizar cálculo
resultado <- argumento1 + argumento2
# 2. Devolver el resultado
return(resultado)
}
# 3. Test de la función con valores de prueba
prueba1 <- mi_funcion(argumento1 = 2, argumento2 = 9)
cat("El resultado de la suma es:", prueba1, "")
#> El resultado de la suma es: 11
Ejemplo práctico 1:
área de un rectángulo
Para calcular el área de un rectángulo, la función planteada debe
definir como arguentos los dos elemento del mismo que describen su área:
su base y su `altura’:
# 1. Definicion de la funcion
calcular_area_rectangulo <- function(base, altura) {
area <- base * altura
return(area)
}
# 2. Usar la función con valores de prueba
area_1 <- calcular_area_rectangulo(base = 554, altura = 399999)
cat("El área del rectángulo es:", area_1,"
")
#> El área del rectángulo es: 221599446
#>
Ejemplo práctico 2:
convertidor de dólares a millones de dólares
Cuando hay cifras muy grandes, se puede crear una función que
transforme, por ejemplo, montos en dólares a millones de dólares:
# 1. Definir funcion
dolares_millones <- function(monto_dolares) { # Un solo argumento
millones <- monto_dolares / 1000000 # El monto dividido entre un millon
}
# Prueba: convertir $15,500,000.00 a 15.5 millones
resultado_millones <- dolares_millones(15500000)
cat("Monto en millones:", resultado_millones, "millones USD
")
#> Monto en millones: 15.5 millones USD
#>
Condicional
if (toma de decisiones)
El condicional if permite ejecutrar un bloque de codigo
solo si una condición es verdadera.
La lógica:
if – Si. Sí se cumple esto, haz
esto.
else_if – Si no, pero si…. Si no se
cumplió lo anterir, pero se cumple esto, haz esto otro.
else – De lo contrario. Si no se
cumplió ninguno de lo anterior, haz esto otro.
Ejemplo práctico de
if
Con la siguiente función podremos evaluar si un gasto en dólares es
considerado “alto presupuesto”, “presupuesto moderado” o “bajo
presupuesto”:
# Definir función
evaluar_presupuesto <- function(monto_dolares) {
millones <- dolares_millones(monto_dolares) # dolares_millones convierte la
# cifra en millones
if (millones >= 10) { # if :: si millones >= 10 millones
print("Alto Presupuesto - mayor o igual a 10 millones de USD")
} else if (millones >= 2) { # else if :: si no, pero si >= 2 millones
print("Presupuesto moderado - entre 2 y 10 millones de USD")
} else { # else :: cualquier cosa distinta a if, else if
print("Bajo presupuesto - menor a 2 millones de USD")
}
}
# Probando la funcion
# 1. Con 15 millones
evaluar_presupuesto(15000000)
#> [1] "Alto Presupuesto - mayor o igual a 10 millones de USD"
Ciclo loop
for
El ciclo for nos sirver para repetir una tarea un numero
determinado de veces – por ejemplo, para cada elemento de una lista o
para cada mes de un año.
Ejemplo práctico:
convertir las ventas de los primeros 6 meses del año.
Teniendo la ventas en dólars para los primeros 6 meses del año
queremos calcular y mostrar la conversion a millones mes por mes:
# Vector con las ventas mensuales - primer semestre (enero - junio)
ventas_mensuales <- c(20000000, 45000000, 35000000, 29000000, 76000000, 90000000)
nombres_meses <- c("Enero","Febrero","Marzo","Abril","Mayo","Junio")
# Bucle for: recorre desde el mes 1 hasta el 6
for (i in 1:6) {
mes <- nombres_meses[i]
monto <- ventas_mensuales[i]
monto_millones <- dolares_millones(monto)
cat("Mes", i, "(", mes,"):", monto_millones, "millones USD
")
}
#> Mes 1 ( Enero ): 20 millones USD
#> Mes 2 ( Febrero ): 45 millones USD
#> Mes 3 ( Marzo ): 35 millones USD
#> Mes 4 ( Abril ): 29 millones USD
#> Mes 5 ( Mayo ): 76 millones USD
#> Mes 6 ( Junio ): 90 millones USD
#>
Ciclo loop
while
El ciclo while repite una accion mientras una condicion
siga siendo verdadera. Se usa cuando no sabemos exactamente cuantas
veces se iterera el proceso.
Ejemplo practico:
ahorro para un fondo de reserva
Se quiere reunir un fondo de reserva de $1000 dolares. Empieza con $0
y se lograr ahorrar $250 por semana. ¿Cuántas semanas tomará alcanzar la
meta?
meta <- 1000
ahorro_actual <- 0
ahorro_semanal <- 250
semana <- 0
# Mientras no se alcance la meta, continuamos ahorrando
while (ahorro_actual < meta) {
semana <- semana + 1
ahorro_actual <- ahorro_actual + ahorro_semanal
cat("Semana", semana, ": Ahorro acumulado:", ahorro_actual, "USD
")
}
#> Semana 1 : Ahorro acumulado: 250 USD
#> Semana 2 : Ahorro acumulado: 500 USD
#> Semana 3 : Ahorro acumulado: 750 USD
#> Semana 4 : Ahorro acumulado: 1000 USD
#>
cat("
¡Meta alcanzada en", semana, "semanas!
")
#>
#> ¡Meta alcanzada en 4 semanas!
#>
Aplicación práctica:
resolución de la ecuación cuadrática
Para resolver una ecuación cuadrática de la forma \(ax^2+bx+c=0\), se puede utilizar la fórmula
general: \[
x = \frac{-b \ \pm \ \sqrt{b^2-4\cdot a\cdot c} }{2 \cdot a}
\]
La parte dentro de la raíz – \(b^2-4\cdot a
\cdot c\) – se llama discriminante:
- Si el discriminante es negativo, la ecuación no tiene soluciones en
los números reales.
- Si es cero o positivo, si tiene raíces reales, se puede calcular
\(x_1\) y \(x_2\).
resolver_cuadratica <- function(a, b, c) {
# 1. Calcular el discriminante
discriminante <- (b^2) - (4 * a * c)
# 2. Tomar decision con un `if` sencillo
if (discriminante < 0) {
cat("La ecuacion no tiene soluciones en el espacio de los numeros reales
")
} else {
x_1 <- (-b + sqrt(discriminante)) / (2 * a)
x_2 <- (-b - sqrt(discriminante)) / (2 * a)
return(c(x_1 = x_1, x_2 = x_2))
}
}
Demostración
# Ejemplo 1: ecuación con solución en el espacio de los números reales
# x^2 - 5x + 6 = 0
sol_1 <- resolver_cuadratica(a=1, b=-5, c=6)
sol_1
#> x_1 x_2
#> 3 2
# Ejemplo 2: ecuacion sin soluciones reales
# x^2 + 2x + 5 = 0
sol_2 <- resolver_cuadratica(a=1, b=2, c=5)
#> La ecuacion no tiene soluciones en el espacio de los numeros reales
#>
#> NULL
LS0tDQp0aXRsZTogIkPDoWxjdWxvIGRlIGluZGljYWRvcmVzIHNpbXBsZXMgeSB0cmFuc2Zvcm1hY2nDs24gZGUgbGEgaW5mb3JtYWNpw7NuIg0Kc3VidGl0bGU6ICJGdW5jaW9uZXMgeSBidWNsZXMgZW4gUiINCmF1dGhvcjogIkhhcm9sZCBTLiBMLiBNb250YW5vIg0KZGF0ZTogIjIwMjYtMDctMjQiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jOiB0cnVlDQogICAgdG9jX2Zsb2F0Og0KICAgICAgY29sbGFwc2VkOiBmYWxzZQ0KICAgICAgc21vb3RoX3Njcm9sbDogdHJ1ZQ0KICAgIHRvY19kZXB0aDogMw0KICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQ0KICAgIHRoZW1lOiBmbGF0bHkNCiAgICBoaWdobGlnaHQ6IHRhbmdvDQogICAgZGZfcHJpbnQ6IHBhZ2VkDQogICAgY29kZV9mb2xkaW5nOiBzaG93DQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KA0KICBlY2hvICAgID0gVFJVRSwNCiAgbWVzc2FnZSA9IEZBTFNFLA0KICB3YXJuaW5nID0gRkFMU0UsDQogIGNvbW1lbnQgPSAiIz4iDQopDQoNCiMgVEFCTEFTIEhUTUwgQ09OU0lTVEVOVEVTIFNJTiBERVBFTkRFTkNJQVMgRVhURVJOQVMNCnRhYmxhIDwtIGZ1bmN0aW9uKHgsIC4uLikgew0KICBrbml0cjo6a2FibGUoeCwgZm9ybWF0ID0gImh0bWwiLCB0YWJsZS5hdHRyID0gJ2NsYXNzPSJ0YWJsYSInLCAuLi4pDQp9DQpgYGANCg0KYGBge2NzcywgZWNobz1GQUxTRX0NCmJvZHkgew0KICBmb250LXNpemU6IDE1cHg7DQogIGxpbmUtaGVpZ2h0OiAxLjY1Ow0KfQ0KDQpoMS50aXRsZSB7IGZvbnQtd2VpZ2h0OiA2MDA7IH0NCg0KaDEgew0KICBib3JkZXItYm90dG9tOiAycHggc29saWQgIzJjM2U1MDsNCiAgcGFkZGluZy1ib3R0b206IC4zZW07DQogIG1hcmdpbi10b3A6IDEuOGVtOw0KfQ0KDQouZW51bmNpYWRvIHsNCiAgYmFja2dyb3VuZC1jb2xvcjogI2Y0ZjdmOTsNCiAgYm9yZGVyLWxlZnQ6IDRweCBzb2xpZCAjMmMzZTUwOw0KICBwYWRkaW5nOiAuOWVtIDEuMWVtOw0KICBtYXJnaW46IDEuMmVtIDA7DQogIGJvcmRlci1yYWRpdXM6IDAgNHB4IDRweCAwOw0KfQ0KDQouZW51bmNpYWRvIHA6bGFzdC1jaGlsZCB7IG1hcmdpbi1ib3R0b206IDA7IH0NCg0KLm5vdGEgew0KICBiYWNrZ3JvdW5kLWNvbG9yOiAjZmRmNmUzOw0KICBib3JkZXItbGVmdDogNHB4IHNvbGlkICNiNTg5MDA7DQogIHBhZGRpbmc6IC44ZW0gMS4xZW07DQogIG1hcmdpbjogMS4yZW0gMDsNCiAgZm9udC1zaXplOiAuOTNlbTsNCiAgYm9yZGVyLXJhZGl1czogMCA0cHggNHB4IDA7DQp9DQoNCnRhYmxlLnRhYmxhIHsNCiAgYm9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZTsNCiAgbWFyZ2luOiAxZW0gMDsNCiAgZm9udC1zaXplOiAuOTNlbTsNCn0NCg0KdGFibGUudGFibGEgdGggew0KICBiYWNrZ3JvdW5kLWNvbG9yOiAjMmMzZTUwOw0KICBjb2xvcjogI2ZmZjsNCiAgcGFkZGluZzogLjVlbSAuOWVtOw0KICB0ZXh0LWFsaWduOiByaWdodDsNCn0NCg0KdGFibGUudGFibGEgdGg6Zmlyc3QtY2hpbGQgeyB0ZXh0LWFsaWduOiBsZWZ0OyB9DQoNCnRhYmxlLnRhYmxhIHRkIHsNCiAgcGFkZGluZzogLjQ1ZW0gLjllbTsNCiAgYm9yZGVyLWJvdHRvbTogMXB4IHNvbGlkICNlMWU1ZWE7DQogIHRleHQtYWxpZ246IHJpZ2h0Ow0KfQ0KDQp0YWJsZS50YWJsYSB0ZDpmaXJzdC1jaGlsZCB7DQogIHRleHQtYWxpZ246IGxlZnQ7DQogIGZvbnQtd2VpZ2h0OiA1MDA7DQp9DQoNCnRhYmxlLnRhYmxhIHRyOmhvdmVyIHRkIHsgYmFja2dyb3VuZC1jb2xvcjogI2Y0ZjdmOTsgfQ0KDQpwcmUgeyBib3JkZXItcmFkaXVzOiA0cHg7IH0NCmBgYA0KDQojIERlZmluaWNpw7NuIGRlIHVuYSBmdW5jacOzbiBlbiBSDQoNCiMjIEZ1bmNpw7NuDQoNClVuYSBmdW5jacOzbiBjdWFscXVpZXJhIGVuIFIgZXN0w6EgY29tcHVlc3RhIHBvciB0cmVzIHBhcnRlczoNCg0KLSBFbnRyYWRhcy4gTG9zIGFyZ3VtZW50b3MgZGUgbGEgZnVuY2nDs24uDQotIFByb2Nlc28uIE8gZWwgY3VlcnBvIGRlIGxhIGZ1bmNpw7NuLCBzb24gbGFzIGluc3RydWNjaW9uZXMgZGUgbG8gcXVlIGxhIGZ1bmNpw7NuIGRlYmUgaGFjZXIuDQotIFNhbGlkYS4gRWwgcmVzdWx0YWRvLCBlcyBsbyBxdWUgcG9yIGRpc2XDsW8gZGViZSBoYWNlciBsYSBmdW5jacOzbiwgc3UgcHJvZHVjdG8gZmluYWwuDQoNCiMjIFNpbnRheGlzIFBhc28gYSBQYXNvIGVuIFINCg0KUGFyYSBjb25zdHJ1aXIgY3VhbHF1aWVyIGZ1bmNpw7NuIGVuIFIsIGVzIHJlY29tZW5kYWJsZSBlbnRlbmRlciBsYSBzaWd1aWVudGUgZXN0cnVjdHVyYToNCg0KYGBge3IsIGVqZW1wbG8tZnVuY2nDs259DQoNCm1pX2Z1bmNpb24gPC0gZnVuY3Rpb24oYXJndW1lbnRvMSwgYXJndW1lbnRvMikgew0KICAjIDEuIFJlYWxpemFyIGPDoWxjdWxvDQogIHJlc3VsdGFkbyA8LSBhcmd1bWVudG8xICsgYXJndW1lbnRvMg0KICANCiAgIyAyLiBEZXZvbHZlciBlbCByZXN1bHRhZG8NCiAgcmV0dXJuKHJlc3VsdGFkbykNCn0NCg0KICAjIDMuIFRlc3QgZGUgbGEgZnVuY2nDs24gY29uIHZhbG9yZXMgZGUgcHJ1ZWJhDQoNCnBydWViYTEgPC0gbWlfZnVuY2lvbihhcmd1bWVudG8xID0gMiwgYXJndW1lbnRvMiA9IDkpDQpjYXQoIkVsIHJlc3VsdGFkbyBkZSBsYSBzdW1hIGVzOiIsIHBydWViYTEsICIiKQ0KYGBgDQoNCiMjIEVqZW1wbG8gcHLDoWN0aWNvIDE6IMOhcmVhIGRlIHVuIHJlY3TDoW5ndWxvDQoNClBhcmEgY2FsY3VsYXIgZWwgw6FyZWEgZGUgdW4gcmVjdMOhbmd1bG8sIGxhIGZ1bmNpw7NuIHBsYW50ZWFkYSBkZWJlIGRlZmluaXINCmNvbW8gYXJndWVudG9zIGxvcyBkb3MgZWxlbWVudG8gZGVsIG1pc21vIHF1ZSBkZXNjcmliZW4gc3Ugw6FyZWE6IHN1IGBiYXNlYCB5IHN1IGBhbHR1cmEnOg0KDQpgYGB7ciBhcmVhLXJlY3Rhbmd1bG99DQojIDEuIERlZmluaWNpb24gZGUgbGEgZnVuY2lvbg0KY2FsY3VsYXJfYXJlYV9yZWN0YW5ndWxvIDwtIGZ1bmN0aW9uKGJhc2UsIGFsdHVyYSkgew0KICANCiAgYXJlYSA8LSBiYXNlICogYWx0dXJhDQogIHJldHVybihhcmVhKQ0KICANCn0NCg0KIyAyLiBVc2FyIGxhIGZ1bmNpw7NuIGNvbiB2YWxvcmVzIGRlIHBydWViYQ0KYXJlYV8xIDwtIGNhbGN1bGFyX2FyZWFfcmVjdGFuZ3VsbyhiYXNlID0gNTU0LCBhbHR1cmEgPSAzOTk5OTkpDQoNCmNhdCgiRWwgw6FyZWEgZGVsIHJlY3TDoW5ndWxvIGVzOiIsIGFyZWFfMSwiDQogICAgIikNCg0KYGBgDQoNCiMjIEVqZW1wbG8gcHLDoWN0aWNvIDI6IGNvbnZlcnRpZG9yIGRlIGTDs2xhcmVzIGEgbWlsbG9uZXMgZGUgZMOzbGFyZXMNCg0KQ3VhbmRvIGhheSBjaWZyYXMgbXV5IGdyYW5kZXMsIHNlIHB1ZWRlIGNyZWFyIHVuYSBmdW5jacOzbiBxdWUNCnRyYW5zZm9ybWUsIHBvciBlamVtcGxvLCBtb250b3MgZW4gZMOzbGFyZXMgYSBtaWxsb25lcyBkZQ0KZMOzbGFyZXM6DQoNCmBgYHtyIGNvbnZlcnRpZG9yLWNpZnJhc30NCiMgMS4gRGVmaW5pciBmdW5jaW9uDQpkb2xhcmVzX21pbGxvbmVzIDwtIGZ1bmN0aW9uKG1vbnRvX2RvbGFyZXMpIHsgIyBVbiBzb2xvIGFyZ3VtZW50bw0KICANCiAgbWlsbG9uZXMgPC0gbW9udG9fZG9sYXJlcyAvIDEwMDAwMDAgIyBFbCBtb250byBkaXZpZGlkbyBlbnRyZSB1biBtaWxsb24NCiAgDQp9DQoNCiMgUHJ1ZWJhOiBjb252ZXJ0aXIgJDE1LDUwMCwwMDAuMDAgYSAxNS41IG1pbGxvbmVzDQoNCnJlc3VsdGFkb19taWxsb25lcyA8LSBkb2xhcmVzX21pbGxvbmVzKDE1NTAwMDAwKQ0KY2F0KCJNb250byBlbiBtaWxsb25lczoiLCByZXN1bHRhZG9fbWlsbG9uZXMsICJtaWxsb25lcyBVU0QNCiAgICAiKQ0KDQpgYGANCg0KIyBDb25kaWNpb25hbCBgaWZgICh0b21hIGRlIGRlY2lzaW9uZXMpDQoNCkVsIGNvbmRpY2lvbmFsIGBpZmAgcGVybWl0ZSBlamVjdXRyYXIgdW4gYmxvcXVlIGRlIGNvZGlnbyBzb2xvDQpzaSB1bmEgY29uZGljacOzbiBlcyB2ZXJkYWRlcmEuDQoNCioqTGEgbMOzZ2ljYSoqOg0KDQotIGBpZmAgLS0gKipTaSoqLiBTw60gc2UgY3VtcGxlIGVzdG8sIGhheiBlc3RvLg0KLSBgZWxzZV9pZmAgLS0gKipTaSBubywgcGVybyBzaS4uLioqLiBTaSBubyBzZSBjdW1wbGnDsyBsbyBhbnRlcmlyLCBwZXJvIHNlDQpjdW1wbGUgZXN0bywgaGF6IGVzdG8gb3Ryby4NCi0gYGVsc2VgIC0tICoqRGUgbG8gY29udHJhcmlvKiouIFNpIG5vIHNlIGN1bXBsacOzIG5pbmd1bm8gZGUgbG8gYW50ZXJpb3IsIA0KaGF6IGVzdG8gb3Ryby4NCg0KIyMgRWplbXBsbyBwcsOhY3RpY28gZGUgYGlmYA0KDQpDb24gbGEgc2lndWllbnRlIGZ1bmNpw7NuIHBvZHJlbW9zIGV2YWx1YXIgc2kgdW4gZ2FzdG8gZW4gZMOzbGFyZXMgZXMNCmNvbnNpZGVyYWRvICJhbHRvIHByZXN1cHVlc3RvIiwgInByZXN1cHVlc3RvIG1vZGVyYWRvIiBvICJiYWpvIHByZXN1cHVlc3RvIjoNCg0KYGBge3IgYnVkZ2V0LWNsYXNzfQ0KDQojIERlZmluaXIgZnVuY2nDs24NCg0KZXZhbHVhcl9wcmVzdXB1ZXN0byA8LSBmdW5jdGlvbihtb250b19kb2xhcmVzKSB7DQogIG1pbGxvbmVzIDwtIGRvbGFyZXNfbWlsbG9uZXMobW9udG9fZG9sYXJlcykgIyBkb2xhcmVzX21pbGxvbmVzIGNvbnZpZXJ0ZSBsYSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGNpZnJhIGVuIG1pbGxvbmVzDQogIA0KICBpZiAobWlsbG9uZXMgPj0gMTApIHsgICAgICAgIyBpZiA6OiBzaSBtaWxsb25lcyA+PSAxMCBtaWxsb25lcw0KICAgIHByaW50KCJBbHRvIFByZXN1cHVlc3RvIC0gbWF5b3IgbyBpZ3VhbCBhIDEwIG1pbGxvbmVzIGRlIFVTRCIpDQogIH0gZWxzZSBpZiAobWlsbG9uZXMgPj0gMikgeyAjIGVsc2UgaWYgOjogc2kgbm8sIHBlcm8gc2kgPj0gMiBtaWxsb25lcw0KICAgIHByaW50KCJQcmVzdXB1ZXN0byBtb2RlcmFkbyAtIGVudHJlIDIgeSAxMCBtaWxsb25lcyBkZSBVU0QiKQ0KICB9IGVsc2UgeyAgICAgICAgICAgICAgICAgICAgIyBlbHNlIDo6IGN1YWxxdWllciBjb3NhIGRpc3RpbnRhIGEgaWYsIGVsc2UgaWYNCiAgICBwcmludCgiQmFqbyBwcmVzdXB1ZXN0byAtIG1lbm9yIGEgMiBtaWxsb25lcyBkZSBVU0QiKQ0KICB9DQogIA0KfQ0KDQojIFByb2JhbmRvIGxhIGZ1bmNpb24NCiMgMS4gQ29uIDE1IG1pbGxvbmVzDQpldmFsdWFyX3ByZXN1cHVlc3RvKDE1MDAwMDAwKQ0KDQoNCmBgYA0KIyBDaWNsbyAqbG9vcCogYGZvcmANCg0KRWwgY2ljbG8gYGZvcmAgbm9zIHNpcnZlciBwYXJhIHJlcGV0aXIgdW5hIHRhcmVhIHVuIG51bWVybyBkZXRlcm1pbmFkbyBkZQ0KdmVjZXMgLS0gcG9yIGVqZW1wbG8sIHBhcmEgY2FkYSBlbGVtZW50byBkZSB1bmEgbGlzdGEgbyBwYXJhIGNhZGEgbWVzIGRlIHVuIGHDsW8uDQoNCiMjIEVqZW1wbG8gcHLDoWN0aWNvOiBjb252ZXJ0aXIgbGFzIHZlbnRhcyBkZSBsb3MgcHJpbWVyb3MgNiBtZXNlcyBkZWwgYcOxby4NCg0KVGVuaWVuZG8gbGEgdmVudGFzIGVuIGTDs2xhcnMgcGFyYSBsb3MgcHJpbWVyb3MgNiBtZXNlcyBkZWwgYcOxbyBxdWVyZW1vcyBjYWxjdWxhcg0KeSBtb3N0cmFyIGxhIGNvbnZlcnNpb24gYSBtaWxsb25lcyBtZXMgcG9yIG1lczoNCg0KYGBge3Igc2FsZXMtdmlld2VyfQ0KDQojIFZlY3RvciBjb24gbGFzIHZlbnRhcyBtZW5zdWFsZXMgLSBwcmltZXIgc2VtZXN0cmUgKGVuZXJvIC0ganVuaW8pDQoNCnZlbnRhc19tZW5zdWFsZXMgPC0gYygyMDAwMDAwMCwgNDUwMDAwMDAsIDM1MDAwMDAwLCAyOTAwMDAwMCwgNzYwMDAwMDAsIDkwMDAwMDAwKQ0Kbm9tYnJlc19tZXNlcyA8LSBjKCJFbmVybyIsIkZlYnJlcm8iLCJNYXJ6byIsIkFicmlsIiwiTWF5byIsIkp1bmlvIikNCg0KIyBCdWNsZSBmb3I6IHJlY29ycmUgZGVzZGUgZWwgbWVzIDEgaGFzdGEgZWwgNg0KDQpmb3IgKGkgaW4gMTo2KSB7DQogIA0KICBtZXMgPC0gbm9tYnJlc19tZXNlc1tpXQ0KICBtb250byA8LSB2ZW50YXNfbWVuc3VhbGVzW2ldDQogIG1vbnRvX21pbGxvbmVzIDwtIGRvbGFyZXNfbWlsbG9uZXMobW9udG8pDQogIA0KICBjYXQoIk1lcyIsIGksICIoIiwgbWVzLCIpOiIsIG1vbnRvX21pbGxvbmVzLCAibWlsbG9uZXMgVVNEDQogICAgICAiKQ0KICANCn0NCg0KYGBgDQoNCiMgQ2ljbG8gKmxvb3AqIGB3aGlsZWANCg0KRWwgY2ljbG8gYHdoaWxlYCByZXBpdGUgdW5hIGFjY2lvbiBtaWVudHJhcyB1bmEgY29uZGljaW9uIHNpZ2Egc2llbmRvIHZlcmRhZGVyYS4NClNlIHVzYSBjdWFuZG8gbm8gc2FiZW1vcyBleGFjdGFtZW50ZSBjdWFudGFzIHZlY2VzIHNlIGl0ZXJlcmEgZWwgcHJvY2Vzby4NCg0KIyMgRWplbXBsbyBwcmFjdGljbzogYWhvcnJvIHBhcmEgdW4gZm9uZG8gZGUgcmVzZXJ2YQ0KDQpTZSBxdWllcmUgcmV1bmlyIHVuIGZvbmRvIGRlIHJlc2VydmEgZGUgJDEwMDAgZG9sYXJlcy4gDQpFbXBpZXphIGNvbiAkMCB5IHNlIGxvZ3JhciBhaG9ycmFyDQokMjUwIHBvciBzZW1hbmEuIMK/Q3XDoW50YXMgc2VtYW5hcyB0b21hcsOhIGFsY2FuemFyIGxhIG1ldGE/DQoNCmBgYHtyfQ0KDQptZXRhIDwtIDEwMDANCmFob3Jyb19hY3R1YWwgPC0gMA0KYWhvcnJvX3NlbWFuYWwgPC0gMjUwDQpzZW1hbmEgPC0gMA0KDQojIE1pZW50cmFzIG5vIHNlIGFsY2FuY2UgbGEgbWV0YSwgY29udGludWFtb3MgYWhvcnJhbmRvDQoNCndoaWxlIChhaG9ycm9fYWN0dWFsIDwgbWV0YSkgew0KICBzZW1hbmEgPC0gc2VtYW5hICsgMQ0KICBhaG9ycm9fYWN0dWFsIDwtIGFob3Jyb19hY3R1YWwgKyBhaG9ycm9fc2VtYW5hbA0KICANCiAgY2F0KCJTZW1hbmEiLCBzZW1hbmEsICI6IEFob3JybyBhY3VtdWxhZG86IiwgYWhvcnJvX2FjdHVhbCwgIlVTRA0KICAgICAgIikNCiAgDQp9DQoNCmNhdCgiDQogICAgwqFNZXRhIGFsY2FuemFkYSBlbiIsIHNlbWFuYSwgInNlbWFuYXMhDQogICAgIikNCg0KYGBgDQoNCiMgQXBsaWNhY2nDs24gcHLDoWN0aWNhOiByZXNvbHVjacOzbiBkZSBsYSBlY3VhY2nDs24gY3VhZHLDoXRpY2ENCg0KUGFyYSByZXNvbHZlciB1bmEgZWN1YWNpw7NuIGN1YWRyw6F0aWNhIGRlIGxhIGZvcm1hICRheF4yK2J4K2M9MCQsIHNlIHB1ZWRlIHV0aWxpemFyDQpsYSBmw7NybXVsYSBnZW5lcmFsOiANCiQkDQp4ID0gXGZyYWN7LWIgXCBccG0gXCBcc3FydHtiXjItNFxjZG90IGFcY2RvdCBjfSB9ezIgXGNkb3QgYX0NCiQkDQoNCkxhIHBhcnRlIGRlbnRybyBkZSBsYSByYcOteiAtLSAkYl4yLTRcY2RvdCBhIFxjZG90IGMkIC0tIHNlIGxsYW1hIGRpc2NyaW1pbmFudGU6DQoNCi0gU2kgZWwgZGlzY3JpbWluYW50ZSBlcyBuZWdhdGl2bywgbGEgZWN1YWNpw7NuIG5vIHRpZW5lIHNvbHVjaW9uZXMgZW4gbG9zIG7Dum1lcm9zDQpyZWFsZXMuDQotIFNpIGVzIGNlcm8gbyBwb3NpdGl2bywgc2kgdGllbmUgcmHDrWNlcyByZWFsZXMsIHNlIHB1ZWRlIGNhbGN1bGFyICR4XzEkIHkgJHhfMiQuDQoNCmBgYHtyfQ0KcmVzb2x2ZXJfY3VhZHJhdGljYSA8LSBmdW5jdGlvbihhLCBiLCBjKSB7DQogIA0KICAjIDEuIENhbGN1bGFyIGVsIGRpc2NyaW1pbmFudGUNCiAgZGlzY3JpbWluYW50ZSA8LSAoYl4yKSAtICg0ICogYSAqIGMpDQogIA0KICAjIDIuIFRvbWFyIGRlY2lzaW9uIGNvbiB1biBgaWZgIHNlbmNpbGxvDQogIA0KICBpZiAoZGlzY3JpbWluYW50ZSA8IDApIHsNCiAgICBjYXQoIkxhIGVjdWFjaW9uIG5vIHRpZW5lIHNvbHVjaW9uZXMgZW4gZWwgZXNwYWNpbyBkZSBsb3MgbnVtZXJvcyByZWFsZXMNCiAgICAgICAgIikNCiAgfSBlbHNlIHsNCiAgICANCiAgICB4XzEgPC0gKC1iICsgc3FydChkaXNjcmltaW5hbnRlKSkgLyAoMiAqIGEpDQogICAgeF8yIDwtICgtYiAtIHNxcnQoZGlzY3JpbWluYW50ZSkpIC8gKDIgKiBhKQ0KICAgIHJldHVybihjKHhfMSA9IHhfMSwgeF8yID0geF8yKSkNCiAgfQ0KfQ0KYGBgDQoNCiMjIERlbW9zdHJhY2nDs24NCg0KYGBge3J9DQoNCiMgRWplbXBsbyAxOiBlY3VhY2nDs24gY29uIHNvbHVjacOzbiBlbiBlbCBlc3BhY2lvIGRlIGxvcyBuw7ptZXJvcyByZWFsZXMNCiMgeF4yIC0gNXggKyA2ID0gMA0KDQpzb2xfMSA8LSByZXNvbHZlcl9jdWFkcmF0aWNhKGE9MSwgYj0tNSwgYz02KQ0Kc29sXzENCg0KYGBgDQpgYGB7cn0NCiMgRWplbXBsbyAyOiBlY3VhY2lvbiBzaW4gc29sdWNpb25lcyByZWFsZXMNCiMgeF4yICsgMnggKyA1ID0gMA0KDQpzb2xfMiA8LSByZXNvbHZlcl9jdWFkcmF0aWNhKGE9MSwgYj0yLCBjPTUpDQpzb2xfMg0KYGBgDQoNCg==