1 Definición de una función en R

1.1 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.

1.2 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

1.3 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 
#> 

1.4 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
#> 

2 Condicional if (toma de decisiones)

El condicional if permite ejecutrar un bloque de codigo solo si una condición es verdadera.

La lógica:

  • ifSi. Sí se cumple esto, haz esto.
  • else_ifSi no, pero si…. Si no se cumplió lo anterir, pero se cumple esto, haz esto otro.
  • elseDe lo contrario. Si no se cumplió ninguno de lo anterior, haz esto otro.

2.1 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"

3 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.

3.1 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
#> 

4 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.

4.1 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!
#> 

5 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))
  }
}

5.1 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
#> 
sol_2
#> NULL
LS0tDQp0aXRsZTogIkPDoWxjdWxvIGRlIGluZGljYWRvcmVzIHNpbXBsZXMgeSB0cmFuc2Zvcm1hY2nDs24gZGUgbGEgaW5mb3JtYWNpw7NuIg0Kc3VidGl0bGU6ICJGdW5jaW9uZXMgeSBidWNsZXMgZW4gUiINCmF1dGhvcjogIkhhcm9sZCBTLiBMLiBNb250YW5vIg0KZGF0ZTogIjIwMjYtMDctMjQiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jOiB0cnVlDQogICAgdG9jX2Zsb2F0Og0KICAgICAgY29sbGFwc2VkOiBmYWxzZQ0KICAgICAgc21vb3RoX3Njcm9sbDogdHJ1ZQ0KICAgIHRvY19kZXB0aDogMw0KICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQ0KICAgIHRoZW1lOiBmbGF0bHkNCiAgICBoaWdobGlnaHQ6IHRhbmdvDQogICAgZGZfcHJpbnQ6IHBhZ2VkDQogICAgY29kZV9mb2xkaW5nOiBzaG93DQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KA0KICBlY2hvICAgID0gVFJVRSwNCiAgbWVzc2FnZSA9IEZBTFNFLA0KICB3YXJuaW5nID0gRkFMU0UsDQogIGNvbW1lbnQgPSAiIz4iDQopDQoNCiMgVEFCTEFTIEhUTUwgQ09OU0lTVEVOVEVTIFNJTiBERVBFTkRFTkNJQVMgRVhURVJOQVMNCnRhYmxhIDwtIGZ1bmN0aW9uKHgsIC4uLikgew0KICBrbml0cjo6a2FibGUoeCwgZm9ybWF0ID0gImh0bWwiLCB0YWJsZS5hdHRyID0gJ2NsYXNzPSJ0YWJsYSInLCAuLi4pDQp9DQpgYGANCg0KYGBge2NzcywgZWNobz1GQUxTRX0NCmJvZHkgew0KICBmb250LXNpemU6IDE1cHg7DQogIGxpbmUtaGVpZ2h0OiAxLjY1Ow0KfQ0KDQpoMS50aXRsZSB7IGZvbnQtd2VpZ2h0OiA2MDA7IH0NCg0KaDEgew0KICBib3JkZXItYm90dG9tOiAycHggc29saWQgIzJjM2U1MDsNCiAgcGFkZGluZy1ib3R0b206IC4zZW07DQogIG1hcmdpbi10b3A6IDEuOGVtOw0KfQ0KDQouZW51bmNpYWRvIHsNCiAgYmFja2dyb3VuZC1jb2xvcjogI2Y0ZjdmOTsNCiAgYm9yZGVyLWxlZnQ6IDRweCBzb2xpZCAjMmMzZTUwOw0KICBwYWRkaW5nOiAuOWVtIDEuMWVtOw0KICBtYXJnaW46IDEuMmVtIDA7DQogIGJvcmRlci1yYWRpdXM6IDAgNHB4IDRweCAwOw0KfQ0KDQouZW51bmNpYWRvIHA6bGFzdC1jaGlsZCB7IG1hcmdpbi1ib3R0b206IDA7IH0NCg0KLm5vdGEgew0KICBiYWNrZ3JvdW5kLWNvbG9yOiAjZmRmNmUzOw0KICBib3JkZXItbGVmdDogNHB4IHNvbGlkICNiNTg5MDA7DQogIHBhZGRpbmc6IC44ZW0gMS4xZW07DQogIG1hcmdpbjogMS4yZW0gMDsNCiAgZm9udC1zaXplOiAuOTNlbTsNCiAgYm9yZGVyLXJhZGl1czogMCA0cHggNHB4IDA7DQp9DQoNCnRhYmxlLnRhYmxhIHsNCiAgYm9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZTsNCiAgbWFyZ2luOiAxZW0gMDsNCiAgZm9udC1zaXplOiAuOTNlbTsNCn0NCg0KdGFibGUudGFibGEgdGggew0KICBiYWNrZ3JvdW5kLWNvbG9yOiAjMmMzZTUwOw0KICBjb2xvcjogI2ZmZjsNCiAgcGFkZGluZzogLjVlbSAuOWVtOw0KICB0ZXh0LWFsaWduOiByaWdodDsNCn0NCg0KdGFibGUudGFibGEgdGg6Zmlyc3QtY2hpbGQgeyB0ZXh0LWFsaWduOiBsZWZ0OyB9DQoNCnRhYmxlLnRhYmxhIHRkIHsNCiAgcGFkZGluZzogLjQ1ZW0gLjllbTsNCiAgYm9yZGVyLWJvdHRvbTogMXB4IHNvbGlkICNlMWU1ZWE7DQogIHRleHQtYWxpZ246IHJpZ2h0Ow0KfQ0KDQp0YWJsZS50YWJsYSB0ZDpmaXJzdC1jaGlsZCB7DQogIHRleHQtYWxpZ246IGxlZnQ7DQogIGZvbnQtd2VpZ2h0OiA1MDA7DQp9DQoNCnRhYmxlLnRhYmxhIHRyOmhvdmVyIHRkIHsgYmFja2dyb3VuZC1jb2xvcjogI2Y0ZjdmOTsgfQ0KDQpwcmUgeyBib3JkZXItcmFkaXVzOiA0cHg7IH0NCmBgYA0KDQojIERlZmluaWNpw7NuIGRlIHVuYSBmdW5jacOzbiBlbiBSDQoNCiMjIEZ1bmNpw7NuDQoNClVuYSBmdW5jacOzbiBjdWFscXVpZXJhIGVuIFIgZXN0w6EgY29tcHVlc3RhIHBvciB0cmVzIHBhcnRlczoNCg0KLSBFbnRyYWRhcy4gTG9zIGFyZ3VtZW50b3MgZGUgbGEgZnVuY2nDs24uDQotIFByb2Nlc28uIE8gZWwgY3VlcnBvIGRlIGxhIGZ1bmNpw7NuLCBzb24gbGFzIGluc3RydWNjaW9uZXMgZGUgbG8gcXVlIGxhIGZ1bmNpw7NuIGRlYmUgaGFjZXIuDQotIFNhbGlkYS4gRWwgcmVzdWx0YWRvLCBlcyBsbyBxdWUgcG9yIGRpc2XDsW8gZGViZSBoYWNlciBsYSBmdW5jacOzbiwgc3UgcHJvZHVjdG8gZmluYWwuDQoNCiMjIFNpbnRheGlzIFBhc28gYSBQYXNvIGVuIFINCg0KUGFyYSBjb25zdHJ1aXIgY3VhbHF1aWVyIGZ1bmNpw7NuIGVuIFIsIGVzIHJlY29tZW5kYWJsZSBlbnRlbmRlciBsYSBzaWd1aWVudGUgZXN0cnVjdHVyYToNCg0KYGBge3IsIGVqZW1wbG8tZnVuY2nDs259DQoNCm1pX2Z1bmNpb24gPC0gZnVuY3Rpb24oYXJndW1lbnRvMSwgYXJndW1lbnRvMikgew0KICAjIDEuIFJlYWxpemFyIGPDoWxjdWxvDQogIHJlc3VsdGFkbyA8LSBhcmd1bWVudG8xICsgYXJndW1lbnRvMg0KICANCiAgIyAyLiBEZXZvbHZlciBlbCByZXN1bHRhZG8NCiAgcmV0dXJuKHJlc3VsdGFkbykNCn0NCg0KICAjIDMuIFRlc3QgZGUgbGEgZnVuY2nDs24gY29uIHZhbG9yZXMgZGUgcHJ1ZWJhDQoNCnBydWViYTEgPC0gbWlfZnVuY2lvbihhcmd1bWVudG8xID0gMiwgYXJndW1lbnRvMiA9IDkpDQpjYXQoIkVsIHJlc3VsdGFkbyBkZSBsYSBzdW1hIGVzOiIsIHBydWViYTEsICIiKQ0KYGBgDQoNCiMjIEVqZW1wbG8gcHLDoWN0aWNvIDE6IMOhcmVhIGRlIHVuIHJlY3TDoW5ndWxvDQoNClBhcmEgY2FsY3VsYXIgZWwgw6FyZWEgZGUgdW4gcmVjdMOhbmd1bG8sIGxhIGZ1bmNpw7NuIHBsYW50ZWFkYSBkZWJlIGRlZmluaXINCmNvbW8gYXJndWVudG9zIGxvcyBkb3MgZWxlbWVudG8gZGVsIG1pc21vIHF1ZSBkZXNjcmliZW4gc3Ugw6FyZWE6IHN1IGBiYXNlYCB5IHN1IGBhbHR1cmEnOg0KDQpgYGB7ciBhcmVhLXJlY3Rhbmd1bG99DQojIDEuIERlZmluaWNpb24gZGUgbGEgZnVuY2lvbg0KY2FsY3VsYXJfYXJlYV9yZWN0YW5ndWxvIDwtIGZ1bmN0aW9uKGJhc2UsIGFsdHVyYSkgew0KICANCiAgYXJlYSA8LSBiYXNlICogYWx0dXJhDQogIHJldHVybihhcmVhKQ0KICANCn0NCg0KIyAyLiBVc2FyIGxhIGZ1bmNpw7NuIGNvbiB2YWxvcmVzIGRlIHBydWViYQ0KYXJlYV8xIDwtIGNhbGN1bGFyX2FyZWFfcmVjdGFuZ3VsbyhiYXNlID0gNTU0LCBhbHR1cmEgPSAzOTk5OTkpDQoNCmNhdCgiRWwgw6FyZWEgZGVsIHJlY3TDoW5ndWxvIGVzOiIsIGFyZWFfMSwiDQogICAgIikNCg0KYGBgDQoNCiMjIEVqZW1wbG8gcHLDoWN0aWNvIDI6IGNvbnZlcnRpZG9yIGRlIGTDs2xhcmVzIGEgbWlsbG9uZXMgZGUgZMOzbGFyZXMNCg0KQ3VhbmRvIGhheSBjaWZyYXMgbXV5IGdyYW5kZXMsIHNlIHB1ZWRlIGNyZWFyIHVuYSBmdW5jacOzbiBxdWUNCnRyYW5zZm9ybWUsIHBvciBlamVtcGxvLCBtb250b3MgZW4gZMOzbGFyZXMgYSBtaWxsb25lcyBkZQ0KZMOzbGFyZXM6DQoNCmBgYHtyIGNvbnZlcnRpZG9yLWNpZnJhc30NCiMgMS4gRGVmaW5pciBmdW5jaW9uDQpkb2xhcmVzX21pbGxvbmVzIDwtIGZ1bmN0aW9uKG1vbnRvX2RvbGFyZXMpIHsgIyBVbiBzb2xvIGFyZ3VtZW50bw0KICANCiAgbWlsbG9uZXMgPC0gbW9udG9fZG9sYXJlcyAvIDEwMDAwMDAgIyBFbCBtb250byBkaXZpZGlkbyBlbnRyZSB1biBtaWxsb24NCiAgDQp9DQoNCiMgUHJ1ZWJhOiBjb252ZXJ0aXIgJDE1LDUwMCwwMDAuMDAgYSAxNS41IG1pbGxvbmVzDQoNCnJlc3VsdGFkb19taWxsb25lcyA8LSBkb2xhcmVzX21pbGxvbmVzKDE1NTAwMDAwKQ0KY2F0KCJNb250byBlbiBtaWxsb25lczoiLCByZXN1bHRhZG9fbWlsbG9uZXMsICJtaWxsb25lcyBVU0QNCiAgICAiKQ0KDQpgYGANCg0KIyBDb25kaWNpb25hbCBgaWZgICh0b21hIGRlIGRlY2lzaW9uZXMpDQoNCkVsIGNvbmRpY2lvbmFsIGBpZmAgcGVybWl0ZSBlamVjdXRyYXIgdW4gYmxvcXVlIGRlIGNvZGlnbyBzb2xvDQpzaSB1bmEgY29uZGljacOzbiBlcyB2ZXJkYWRlcmEuDQoNCioqTGEgbMOzZ2ljYSoqOg0KDQotIGBpZmAgLS0gKipTaSoqLiBTw60gc2UgY3VtcGxlIGVzdG8sIGhheiBlc3RvLg0KLSBgZWxzZV9pZmAgLS0gKipTaSBubywgcGVybyBzaS4uLioqLiBTaSBubyBzZSBjdW1wbGnDsyBsbyBhbnRlcmlyLCBwZXJvIHNlDQpjdW1wbGUgZXN0bywgaGF6IGVzdG8gb3Ryby4NCi0gYGVsc2VgIC0tICoqRGUgbG8gY29udHJhcmlvKiouIFNpIG5vIHNlIGN1bXBsacOzIG5pbmd1bm8gZGUgbG8gYW50ZXJpb3IsIA0KaGF6IGVzdG8gb3Ryby4NCg0KIyMgRWplbXBsbyBwcsOhY3RpY28gZGUgYGlmYA0KDQpDb24gbGEgc2lndWllbnRlIGZ1bmNpw7NuIHBvZHJlbW9zIGV2YWx1YXIgc2kgdW4gZ2FzdG8gZW4gZMOzbGFyZXMgZXMNCmNvbnNpZGVyYWRvICJhbHRvIHByZXN1cHVlc3RvIiwgInByZXN1cHVlc3RvIG1vZGVyYWRvIiBvICJiYWpvIHByZXN1cHVlc3RvIjoNCg0KYGBge3IgYnVkZ2V0LWNsYXNzfQ0KDQojIERlZmluaXIgZnVuY2nDs24NCg0KZXZhbHVhcl9wcmVzdXB1ZXN0byA8LSBmdW5jdGlvbihtb250b19kb2xhcmVzKSB7DQogIG1pbGxvbmVzIDwtIGRvbGFyZXNfbWlsbG9uZXMobW9udG9fZG9sYXJlcykgIyBkb2xhcmVzX21pbGxvbmVzIGNvbnZpZXJ0ZSBsYSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGNpZnJhIGVuIG1pbGxvbmVzDQogIA0KICBpZiAobWlsbG9uZXMgPj0gMTApIHsgICAgICAgIyBpZiA6OiBzaSBtaWxsb25lcyA+PSAxMCBtaWxsb25lcw0KICAgIHByaW50KCJBbHRvIFByZXN1cHVlc3RvIC0gbWF5b3IgbyBpZ3VhbCBhIDEwIG1pbGxvbmVzIGRlIFVTRCIpDQogIH0gZWxzZSBpZiAobWlsbG9uZXMgPj0gMikgeyAjIGVsc2UgaWYgOjogc2kgbm8sIHBlcm8gc2kgPj0gMiBtaWxsb25lcw0KICAgIHByaW50KCJQcmVzdXB1ZXN0byBtb2RlcmFkbyAtIGVudHJlIDIgeSAxMCBtaWxsb25lcyBkZSBVU0QiKQ0KICB9IGVsc2UgeyAgICAgICAgICAgICAgICAgICAgIyBlbHNlIDo6IGN1YWxxdWllciBjb3NhIGRpc3RpbnRhIGEgaWYsIGVsc2UgaWYNCiAgICBwcmludCgiQmFqbyBwcmVzdXB1ZXN0byAtIG1lbm9yIGEgMiBtaWxsb25lcyBkZSBVU0QiKQ0KICB9DQogIA0KfQ0KDQojIFByb2JhbmRvIGxhIGZ1bmNpb24NCiMgMS4gQ29uIDE1IG1pbGxvbmVzDQpldmFsdWFyX3ByZXN1cHVlc3RvKDE1MDAwMDAwKQ0KDQoNCmBgYA0KIyBDaWNsbyAqbG9vcCogYGZvcmANCg0KRWwgY2ljbG8gYGZvcmAgbm9zIHNpcnZlciBwYXJhIHJlcGV0aXIgdW5hIHRhcmVhIHVuIG51bWVybyBkZXRlcm1pbmFkbyBkZQ0KdmVjZXMgLS0gcG9yIGVqZW1wbG8sIHBhcmEgY2FkYSBlbGVtZW50byBkZSB1bmEgbGlzdGEgbyBwYXJhIGNhZGEgbWVzIGRlIHVuIGHDsW8uDQoNCiMjIEVqZW1wbG8gcHLDoWN0aWNvOiBjb252ZXJ0aXIgbGFzIHZlbnRhcyBkZSBsb3MgcHJpbWVyb3MgNiBtZXNlcyBkZWwgYcOxby4NCg0KVGVuaWVuZG8gbGEgdmVudGFzIGVuIGTDs2xhcnMgcGFyYSBsb3MgcHJpbWVyb3MgNiBtZXNlcyBkZWwgYcOxbyBxdWVyZW1vcyBjYWxjdWxhcg0KeSBtb3N0cmFyIGxhIGNvbnZlcnNpb24gYSBtaWxsb25lcyBtZXMgcG9yIG1lczoNCg0KYGBge3Igc2FsZXMtdmlld2VyfQ0KDQojIFZlY3RvciBjb24gbGFzIHZlbnRhcyBtZW5zdWFsZXMgLSBwcmltZXIgc2VtZXN0cmUgKGVuZXJvIC0ganVuaW8pDQoNCnZlbnRhc19tZW5zdWFsZXMgPC0gYygyMDAwMDAwMCwgNDUwMDAwMDAsIDM1MDAwMDAwLCAyOTAwMDAwMCwgNzYwMDAwMDAsIDkwMDAwMDAwKQ0Kbm9tYnJlc19tZXNlcyA8LSBjKCJFbmVybyIsIkZlYnJlcm8iLCJNYXJ6byIsIkFicmlsIiwiTWF5byIsIkp1bmlvIikNCg0KIyBCdWNsZSBmb3I6IHJlY29ycmUgZGVzZGUgZWwgbWVzIDEgaGFzdGEgZWwgNg0KDQpmb3IgKGkgaW4gMTo2KSB7DQogIA0KICBtZXMgPC0gbm9tYnJlc19tZXNlc1tpXQ0KICBtb250byA8LSB2ZW50YXNfbWVuc3VhbGVzW2ldDQogIG1vbnRvX21pbGxvbmVzIDwtIGRvbGFyZXNfbWlsbG9uZXMobW9udG8pDQogIA0KICBjYXQoIk1lcyIsIGksICIoIiwgbWVzLCIpOiIsIG1vbnRvX21pbGxvbmVzLCAibWlsbG9uZXMgVVNEDQogICAgICAiKQ0KICANCn0NCg0KYGBgDQoNCiMgQ2ljbG8gKmxvb3AqIGB3aGlsZWANCg0KRWwgY2ljbG8gYHdoaWxlYCByZXBpdGUgdW5hIGFjY2lvbiBtaWVudHJhcyB1bmEgY29uZGljaW9uIHNpZ2Egc2llbmRvIHZlcmRhZGVyYS4NClNlIHVzYSBjdWFuZG8gbm8gc2FiZW1vcyBleGFjdGFtZW50ZSBjdWFudGFzIHZlY2VzIHNlIGl0ZXJlcmEgZWwgcHJvY2Vzby4NCg0KIyMgRWplbXBsbyBwcmFjdGljbzogYWhvcnJvIHBhcmEgdW4gZm9uZG8gZGUgcmVzZXJ2YQ0KDQpTZSBxdWllcmUgcmV1bmlyIHVuIGZvbmRvIGRlIHJlc2VydmEgZGUgJDEwMDAgZG9sYXJlcy4gDQpFbXBpZXphIGNvbiAkMCB5IHNlIGxvZ3JhciBhaG9ycmFyDQokMjUwIHBvciBzZW1hbmEuIMK/Q3XDoW50YXMgc2VtYW5hcyB0b21hcsOhIGFsY2FuemFyIGxhIG1ldGE/DQoNCmBgYHtyfQ0KDQptZXRhIDwtIDEwMDANCmFob3Jyb19hY3R1YWwgPC0gMA0KYWhvcnJvX3NlbWFuYWwgPC0gMjUwDQpzZW1hbmEgPC0gMA0KDQojIE1pZW50cmFzIG5vIHNlIGFsY2FuY2UgbGEgbWV0YSwgY29udGludWFtb3MgYWhvcnJhbmRvDQoNCndoaWxlIChhaG9ycm9fYWN0dWFsIDwgbWV0YSkgew0KICBzZW1hbmEgPC0gc2VtYW5hICsgMQ0KICBhaG9ycm9fYWN0dWFsIDwtIGFob3Jyb19hY3R1YWwgKyBhaG9ycm9fc2VtYW5hbA0KICANCiAgY2F0KCJTZW1hbmEiLCBzZW1hbmEsICI6IEFob3JybyBhY3VtdWxhZG86IiwgYWhvcnJvX2FjdHVhbCwgIlVTRA0KICAgICAgIikNCiAgDQp9DQoNCmNhdCgiDQogICAgwqFNZXRhIGFsY2FuemFkYSBlbiIsIHNlbWFuYSwgInNlbWFuYXMhDQogICAgIikNCg0KYGBgDQoNCiMgQXBsaWNhY2nDs24gcHLDoWN0aWNhOiByZXNvbHVjacOzbiBkZSBsYSBlY3VhY2nDs24gY3VhZHLDoXRpY2ENCg0KUGFyYSByZXNvbHZlciB1bmEgZWN1YWNpw7NuIGN1YWRyw6F0aWNhIGRlIGxhIGZvcm1hICRheF4yK2J4K2M9MCQsIHNlIHB1ZWRlIHV0aWxpemFyDQpsYSBmw7NybXVsYSBnZW5lcmFsOiANCiQkDQp4ID0gXGZyYWN7LWIgXCBccG0gXCBcc3FydHtiXjItNFxjZG90IGFcY2RvdCBjfSB9ezIgXGNkb3QgYX0NCiQkDQoNCkxhIHBhcnRlIGRlbnRybyBkZSBsYSByYcOteiAtLSAkYl4yLTRcY2RvdCBhIFxjZG90IGMkIC0tIHNlIGxsYW1hIGRpc2NyaW1pbmFudGU6DQoNCi0gU2kgZWwgZGlzY3JpbWluYW50ZSBlcyBuZWdhdGl2bywgbGEgZWN1YWNpw7NuIG5vIHRpZW5lIHNvbHVjaW9uZXMgZW4gbG9zIG7Dum1lcm9zDQpyZWFsZXMuDQotIFNpIGVzIGNlcm8gbyBwb3NpdGl2bywgc2kgdGllbmUgcmHDrWNlcyByZWFsZXMsIHNlIHB1ZWRlIGNhbGN1bGFyICR4XzEkIHkgJHhfMiQuDQoNCmBgYHtyfQ0KcmVzb2x2ZXJfY3VhZHJhdGljYSA8LSBmdW5jdGlvbihhLCBiLCBjKSB7DQogIA0KICAjIDEuIENhbGN1bGFyIGVsIGRpc2NyaW1pbmFudGUNCiAgZGlzY3JpbWluYW50ZSA8LSAoYl4yKSAtICg0ICogYSAqIGMpDQogIA0KICAjIDIuIFRvbWFyIGRlY2lzaW9uIGNvbiB1biBgaWZgIHNlbmNpbGxvDQogIA0KICBpZiAoZGlzY3JpbWluYW50ZSA8IDApIHsNCiAgICBjYXQoIkxhIGVjdWFjaW9uIG5vIHRpZW5lIHNvbHVjaW9uZXMgZW4gZWwgZXNwYWNpbyBkZSBsb3MgbnVtZXJvcyByZWFsZXMNCiAgICAgICAgIikNCiAgfSBlbHNlIHsNCiAgICANCiAgICB4XzEgPC0gKC1iICsgc3FydChkaXNjcmltaW5hbnRlKSkgLyAoMiAqIGEpDQogICAgeF8yIDwtICgtYiAtIHNxcnQoZGlzY3JpbWluYW50ZSkpIC8gKDIgKiBhKQ0KICAgIHJldHVybihjKHhfMSA9IHhfMSwgeF8yID0geF8yKSkNCiAgfQ0KfQ0KYGBgDQoNCiMjIERlbW9zdHJhY2nDs24NCg0KYGBge3J9DQoNCiMgRWplbXBsbyAxOiBlY3VhY2nDs24gY29uIHNvbHVjacOzbiBlbiBlbCBlc3BhY2lvIGRlIGxvcyBuw7ptZXJvcyByZWFsZXMNCiMgeF4yIC0gNXggKyA2ID0gMA0KDQpzb2xfMSA8LSByZXNvbHZlcl9jdWFkcmF0aWNhKGE9MSwgYj0tNSwgYz02KQ0Kc29sXzENCg0KYGBgDQpgYGB7cn0NCiMgRWplbXBsbyAyOiBlY3VhY2lvbiBzaW4gc29sdWNpb25lcyByZWFsZXMNCiMgeF4yICsgMnggKyA1ID0gMA0KDQpzb2xfMiA8LSByZXNvbHZlcl9jdWFkcmF0aWNhKGE9MSwgYj0yLCBjPTUpDQpzb2xfMg0KYGBgDQoNCg==