EJEMPLO
library(markovchain)
library(formattable)
#Definir la matriz P
estados = c(1:3)
P = matrix(c(0.5, 0.3, 0.2,
0.3, 0.4, 0.3,
0.2, 0.3, 0.5), nrow = 3, ncol = 3, byrow = T)
dimnames(P) = list(estados,estados)
#Estado actual
estado = 1
#Definir la distribución de probabilidad para el dia siguiente dado el estado actual
P[estado,]
#Obtener la calidad del aire para el dia siguiente
sample(estados, size = 1, prob = P[estado,])
#Simular 10 dias de la calidad del aire
dias = 10
set.seed(0)#Definiendo la semilla
#Definir el estado inicial
estado = 1
#Inicilizar una lista que contiene la calidad del aire en cada dia
lista_estados = c()
for (i in 1:dias) {
#Guardar el estado actual en la lista de estados
lista_estados = c(lista_estados,estado)
#OBtener el estado futuro
estado = sample(estados, size = 1, prob = P[estado,])
}
lista_estados
plot(lista_estados,type = 'l', xlab = 'Dias', ylab = 'Calidad del aire',
main = 'Evolución de la calidad del aire')
# Simulación con 8 escenarios ---------------------------------------------
dias = 10
escenarios = 8
set.seed(0)
matriz_calidad = matrix(0,nrow = dias, ncol = escenarios)
for (j in 1:escenarios) {
#Definir el estado actual
estado = 1
#Simular los 10 dias
for (i in 1:dias) {
#Guardar el estado en la matriz
matriz_calidad[i,j] = estado
estado = sample(estados, size = 1, prob = P[estado,])
}
}
matplot(matriz_calidad, type = 'l', xlab = 'Dias', ylab = 'Calidad del aire',
main = 'Evolución de la calidad del aire')
EJERCICIO
#Tasa de la demanda
lambda<-15
#Modelación del manejo de inventarios de Wattenspharma con cadenas de Markov
#Crear los estados
estados<-c(0:100)
#*****Crear y llenar la matriz P de la política*****
matrizP<-matrix(0,nrow = length(estados), ncol = length(estados))
rownames(matrizP)<-estados
colnames(matrizP)<-estados
#Para la Politica -> si i<=70 solicita 30 cajas
for (i in estados) {
for (j in estados) {
if(i<=70 & j>0){
matrizP[i+1,j+1]= dpois(30+i-j,lambda=lambda)
}else if(i<=70 & j==0){
matrizP[i+1,j+1]=ppois(30+i-1,lambda = lambda, lower.tail = F)
}else if(i>70 & j>0){
matrizP[i+1,j+1]=dpois(i-j,lambda=lambda)
}else if(i>70 & j==0){
matrizP[i+1,j+1]=ppois(i-1,lambda = lambda, lower.tail = F)
}
}
}
# Crear la cadena usando el paquete markovchain
cmtd<-new("markovchain", states=as.character(estados), transitionMatrix=matrizP)
# Literal B ---------------------------------------------------------------
# Vector para guardar el valor esperado del inventario en cada semana
vEsperadoInv <- c()
# Recorrer las semanas
for(n in 1:30){
estado_inicial <- "0" # Definir el estado inicial
P_t <- cmtd^n # Calcular la matriz de probabilidades en el transitorio
probs <- P_t[estado_inicial,] # Calcular probabilidades en el transitorio dado el estado inicial
vEsperadoInv <- c(vEsperadoInv, probs%*%estados) # Calcular valor esperado y agregar al vector
}
plot(vEsperadoInv, type = "l", ylab="Valor esperado del inventario", xlab="Semana", main="Inventario al final de la semana")
# Calcula el valor esperado del costo de ordenar de las siguientes 30 semanas
cOrdenar <- 5000
vEsperadoOrd <- 0
for(n in 1:30){
estado_inicial <- "0" # Definir el estado inicial
P_t <- cmtd^n # Calcular la matriz de probabilidades en el transitorio
probs <- P_t[estado_inicial,] # Calcular probabilidades en el transitorio dado el estado inicial
# Calcular el valor esperado de ordenar y sumarlo al costo hasta el momento
vEsperadoOrd <- vEsperadoOrd + sum(probs[1:71])*cOrdenar
}
vEsperadoOrd
# Literal C. MonteCarlo ---------------------------------------------------
escenarios = 8
semanas = 30
inventario = matrix(0,nrow = semanas, ncol = escenarios)
#Simular la cadena de markov
set.seed(0)
for (j in 1:escenarios) {
#Determinar el estado inicial
estado = 0
#SImular las 30 semanas
for (i in 1:semanas) {
#Guardar el inventario actual
inventario[i,j] = estado
estado = sample(estados, size = 1, prob = matrizP[as.character(estado),])
}
}
matplot(inventario, type = 'l', xlab = 'Semanas', ylab = 'Inventario')
# Literal D ---------------------------------------------------------------
escenarios = 1000
semanas = 30
inventario = matrix(0,nrow = semanas, ncol = escenarios)
#Simular la cadena de markov
set.seed(0)
for (j in 1:escenarios) {
#Determinar el estado inicial
estado = 0
#SImular las 30 semanas
for (i in 1:semanas) {
#Guardar el inventario actual
inventario[i,j] = estado
estado = sample(estados, size = 1, prob = matrizP[as.character(estado),])
}
}
hist(inventario[30,], main = 'Distribución del inventario en la semana 30')
#Calculando el inventario promedio con MonteCarlo
inventario_promedio = mean(inventario[30,])
print(paste('Inventario con simulación de MonteCarlo: ', inventario_promedio))
#Valoresperado con analisis transitorio
print(paste('Valor esperado del inventario (literal b): ', round(vEsperadoInv[30],3)))
# Literal E ---------------------------------------------------------------
escenarios <- 1000
semanas <- 30
# Inicializar vector para guardar los costos de ordenar de cada escenario
vector_costos <- c()
# Simular la cadena de Markov
set.seed(0)
for(j in 1:escenarios){
# Definir el estado inicial (inventario inicial)
estado <- 0
# Inicializar costo de ordenar
costo <- 0
# Simular las transiciones por 30 semanas
for(i in 1:semanas){
# Si el inventario es menor a 70, sumar costo de ordenar
if(estado<=70){
costo = costo + cOrdenar
}
estado <- sample(estados, size=1, prob=matrizP[as.character(estado),])
}
# Guardar el costo de ordenar
vector_costos <- c(vector_costos, costo)
}
costo_promedio = mean(vector_costos)
costo_promedio
print(paste("Costo total de ordenar promedio utilizando simulación de Monte Carlo: ", currency(costo_promedio)))
print(paste("Valor esperado del costo total de ordenar: ", currency(round(vEsperadoOrd,3))))
LS0tDQp0aXRsZTogIlNpbXVsYWNpb24gZGUgTW9udGVjYXJsbyINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCkVKRU1QTE8NCg0KYGBge3J9DQoNCmxpYnJhcnkobWFya292Y2hhaW4pDQoNCmxpYnJhcnkoZm9ybWF0dGFibGUpDQoNCiNEZWZpbmlyIGxhIG1hdHJpeiBQDQplc3RhZG9zID0gYygxOjMpDQpQID0gbWF0cml4KGMoMC41LCAwLjMsIDAuMiwNCiAgICAgICAgICAgICAwLjMsIDAuNCwgMC4zLA0KICAgICAgICAgICAgIDAuMiwgMC4zLCAwLjUpLCBucm93ID0gMywgbmNvbCA9IDMsIGJ5cm93ID0gVCkNCg0KZGltbmFtZXMoUCkgPSBsaXN0KGVzdGFkb3MsZXN0YWRvcykNCg0KI0VzdGFkbyBhY3R1YWwNCmVzdGFkbyA9IDENCg0KI0RlZmluaXIgbGEgZGlzdHJpYnVjacOzbiBkZSBwcm9iYWJpbGlkYWQgcGFyYSBlbCBkaWEgc2lndWllbnRlIGRhZG8gZWwgZXN0YWRvIGFjdHVhbA0KUFtlc3RhZG8sXQ0KDQojT2J0ZW5lciBsYSBjYWxpZGFkIGRlbCBhaXJlIHBhcmEgZWwgZGlhIHNpZ3VpZW50ZQ0Kc2FtcGxlKGVzdGFkb3MsIHNpemUgPSAxLCBwcm9iID0gUFtlc3RhZG8sXSkNCg0KI1NpbXVsYXIgMTAgZGlhcyBkZSBsYSBjYWxpZGFkIGRlbCBhaXJlDQpkaWFzID0gMTANCnNldC5zZWVkKDApI0RlZmluaWVuZG8gbGEgc2VtaWxsYQ0KDQojRGVmaW5pciBlbCBlc3RhZG8gaW5pY2lhbA0KZXN0YWRvID0gMQ0KDQojSW5pY2lsaXphciB1bmEgbGlzdGEgcXVlIGNvbnRpZW5lIGxhIGNhbGlkYWQgZGVsIGFpcmUgZW4gY2FkYSBkaWENCmxpc3RhX2VzdGFkb3MgPSBjKCkNCg0KZm9yIChpIGluIDE6ZGlhcykgew0KICAjR3VhcmRhciBlbCBlc3RhZG8gYWN0dWFsIGVuIGxhIGxpc3RhIGRlIGVzdGFkb3MNCiAgbGlzdGFfZXN0YWRvcyA9IGMobGlzdGFfZXN0YWRvcyxlc3RhZG8pDQogIA0KICAjT0J0ZW5lciBlbCBlc3RhZG8gZnV0dXJvDQogIGVzdGFkbyA9IHNhbXBsZShlc3RhZG9zLCBzaXplID0gMSwgcHJvYiA9IFBbZXN0YWRvLF0pDQp9DQpsaXN0YV9lc3RhZG9zDQoNCg0KcGxvdChsaXN0YV9lc3RhZG9zLHR5cGUgPSAnbCcsIHhsYWIgPSAnRGlhcycsIHlsYWIgPSAnQ2FsaWRhZCBkZWwgYWlyZScsDQogICAgIG1haW4gPSAnRXZvbHVjacOzbiBkZSBsYSBjYWxpZGFkIGRlbCBhaXJlJykNCg0KDQojIFNpbXVsYWNpw7NuIGNvbiA4IGVzY2VuYXJpb3MgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCg0KZGlhcyA9IDEwDQplc2NlbmFyaW9zID0gOA0Kc2V0LnNlZWQoMCkNCg0KbWF0cml6X2NhbGlkYWQgPSBtYXRyaXgoMCxucm93ID0gZGlhcywgbmNvbCA9IGVzY2VuYXJpb3MpDQoNCmZvciAoaiBpbiAxOmVzY2VuYXJpb3MpIHsNCiAgDQogICNEZWZpbmlyIGVsIGVzdGFkbyBhY3R1YWwNCiAgZXN0YWRvID0gMQ0KICANCiAgI1NpbXVsYXIgbG9zIDEwIGRpYXMNCiAgZm9yIChpIGluIDE6ZGlhcykgew0KICAgIA0KICAgICNHdWFyZGFyIGVsIGVzdGFkbyBlbiBsYSBtYXRyaXogDQogICAgbWF0cml6X2NhbGlkYWRbaSxqXSA9IGVzdGFkbw0KICAgIA0KICAgIGVzdGFkbyA9IHNhbXBsZShlc3RhZG9zLCBzaXplID0gMSwgcHJvYiA9IFBbZXN0YWRvLF0pDQogICAgDQogIH0NCn0NCg0KbWF0cGxvdChtYXRyaXpfY2FsaWRhZCwgdHlwZSA9ICdsJywgeGxhYiA9ICdEaWFzJywgeWxhYiA9ICdDYWxpZGFkIGRlbCBhaXJlJywNCiAgICAgICAgbWFpbiA9ICdFdm9sdWNpw7NuIGRlIGxhIGNhbGlkYWQgZGVsIGFpcmUnKQ0KDQpgYGANCg0KDQpFSkVSQ0lDSU8NCmBgYHtyfQ0KDQoNCiNUYXNhIGRlIGxhIGRlbWFuZGENCmxhbWJkYTwtMTUNCg0KI01vZGVsYWNpw7NuIGRlbCBtYW5lam8gZGUgaW52ZW50YXJpb3MgZGUgV2F0dGVuc3BoYXJtYSBjb24gY2FkZW5hcyBkZSBNYXJrb3YNCiNDcmVhciBsb3MgZXN0YWRvcw0KZXN0YWRvczwtYygwOjEwMCkNCg0KIyoqKioqQ3JlYXIgeSBsbGVuYXIgbGEgbWF0cml6IFAgZGUgbGEgcG9sw610aWNhKioqKioNCm1hdHJpelA8LW1hdHJpeCgwLG5yb3cgPSBsZW5ndGgoZXN0YWRvcyksIG5jb2wgPSBsZW5ndGgoZXN0YWRvcykpDQpyb3duYW1lcyhtYXRyaXpQKTwtZXN0YWRvcw0KY29sbmFtZXMobWF0cml6UCk8LWVzdGFkb3MNCg0KI1BhcmEgbGEgUG9saXRpY2EgLT4gc2kgaTw9NzAgc29saWNpdGEgMzAgY2FqYXMNCmZvciAoaSBpbiBlc3RhZG9zKSB7DQogIGZvciAoaiBpbiBlc3RhZG9zKSB7DQogICAgaWYoaTw9NzAgJiBqPjApew0KICAgICAgbWF0cml6UFtpKzEsaisxXT0gZHBvaXMoMzAraS1qLGxhbWJkYT1sYW1iZGEpDQogICAgfWVsc2UgaWYoaTw9NzAgJiBqPT0wKXsNCiAgICAgIG1hdHJpelBbaSsxLGorMV09cHBvaXMoMzAraS0xLGxhbWJkYSA9IGxhbWJkYSwgbG93ZXIudGFpbCA9IEYpDQogICAgfWVsc2UgaWYoaT43MCAmIGo+MCl7DQogICAgICBtYXRyaXpQW2krMSxqKzFdPWRwb2lzKGktaixsYW1iZGE9bGFtYmRhKQ0KICAgIH1lbHNlIGlmKGk+NzAgJiBqPT0wKXsNCiAgICAgIG1hdHJpelBbaSsxLGorMV09cHBvaXMoaS0xLGxhbWJkYSA9IGxhbWJkYSwgbG93ZXIudGFpbCA9IEYpDQogICAgfQ0KICB9DQp9DQoNCiMgQ3JlYXIgbGEgY2FkZW5hIHVzYW5kbyBlbCBwYXF1ZXRlIG1hcmtvdmNoYWluDQpjbXRkPC1uZXcoIm1hcmtvdmNoYWluIiwgc3RhdGVzPWFzLmNoYXJhY3Rlcihlc3RhZG9zKSwgdHJhbnNpdGlvbk1hdHJpeD1tYXRyaXpQKQ0KDQoNCiMgTGl0ZXJhbCBCIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQojIFZlY3RvciBwYXJhIGd1YXJkYXIgZWwgdmFsb3IgZXNwZXJhZG8gZGVsIGludmVudGFyaW8gZW4gY2FkYSBzZW1hbmENCnZFc3BlcmFkb0ludiA8LSBjKCkgICAgDQoNCiMgUmVjb3JyZXIgbGFzIHNlbWFuYXMNCmZvcihuIGluIDE6MzApew0KICBlc3RhZG9faW5pY2lhbCA8LSAiMCIgICAgICAgICAgICAjIERlZmluaXIgZWwgZXN0YWRvIGluaWNpYWwNCiAgUF90IDwtIGNtdGRebiAgICAgICAgICAgICAgICAgICAgIyBDYWxjdWxhciBsYSBtYXRyaXogZGUgcHJvYmFiaWxpZGFkZXMgZW4gZWwgdHJhbnNpdG9yaW8NCiAgcHJvYnMgPC0gUF90W2VzdGFkb19pbmljaWFsLF0gICAgIyBDYWxjdWxhciBwcm9iYWJpbGlkYWRlcyBlbiBlbCB0cmFuc2l0b3JpbyBkYWRvIGVsIGVzdGFkbyBpbmljaWFsDQogIHZFc3BlcmFkb0ludiA8LSBjKHZFc3BlcmFkb0ludiwgcHJvYnMlKiVlc3RhZG9zKSAgIyBDYWxjdWxhciB2YWxvciBlc3BlcmFkbyB5IGFncmVnYXIgYWwgdmVjdG9yDQp9DQoNCnBsb3QodkVzcGVyYWRvSW52LCB0eXBlID0gImwiLCB5bGFiPSJWYWxvciBlc3BlcmFkbyBkZWwgaW52ZW50YXJpbyIsIHhsYWI9IlNlbWFuYSIsIG1haW49IkludmVudGFyaW8gYWwgZmluYWwgZGUgbGEgc2VtYW5hIikNCg0KIyBDYWxjdWxhIGVsIHZhbG9yIGVzcGVyYWRvIGRlbCBjb3N0byBkZSBvcmRlbmFyIGRlIGxhcyBzaWd1aWVudGVzIDMwIHNlbWFuYXMNCmNPcmRlbmFyIDwtIDUwMDANCnZFc3BlcmFkb09yZCA8LSAwDQoNCmZvcihuIGluIDE6MzApew0KICBlc3RhZG9faW5pY2lhbCA8LSAiMCIgICAgICAgICAgICAjIERlZmluaXIgZWwgZXN0YWRvIGluaWNpYWwNCiAgUF90IDwtIGNtdGRebiAgICAgICAgICAgICAgICAgICAgIyBDYWxjdWxhciBsYSBtYXRyaXogZGUgcHJvYmFiaWxpZGFkZXMgZW4gZWwgdHJhbnNpdG9yaW8NCiAgcHJvYnMgPC0gUF90W2VzdGFkb19pbmljaWFsLF0gICAgIyBDYWxjdWxhciBwcm9iYWJpbGlkYWRlcyBlbiBlbCB0cmFuc2l0b3JpbyBkYWRvIGVsIGVzdGFkbyBpbmljaWFsDQogIA0KICAjIENhbGN1bGFyIGVsIHZhbG9yIGVzcGVyYWRvIGRlIG9yZGVuYXIgeSBzdW1hcmxvIGFsIGNvc3RvIGhhc3RhIGVsIG1vbWVudG8NCiAgdkVzcGVyYWRvT3JkIDwtIHZFc3BlcmFkb09yZCArIHN1bShwcm9ic1sxOjcxXSkqY09yZGVuYXINCn0NCnZFc3BlcmFkb09yZA0KDQoNCg0KIyBMaXRlcmFsIEMuIE1vbnRlQ2FybG8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQplc2NlbmFyaW9zID0gOA0Kc2VtYW5hcyA9IDMwDQoNCmludmVudGFyaW8gPSBtYXRyaXgoMCxucm93ID0gc2VtYW5hcywgbmNvbCA9IGVzY2VuYXJpb3MpDQoNCg0KI1NpbXVsYXIgbGEgY2FkZW5hIGRlIG1hcmtvdg0Kc2V0LnNlZWQoMCkNCmZvciAoaiBpbiAxOmVzY2VuYXJpb3MpIHsNCiAgDQogICNEZXRlcm1pbmFyIGVsIGVzdGFkbyBpbmljaWFsDQogIGVzdGFkbyA9IDANCiAgDQogICNTSW11bGFyIGxhcyAzMCBzZW1hbmFzDQogIGZvciAoaSBpbiAxOnNlbWFuYXMpIHsNCiAgICANCiAgICAjR3VhcmRhciBlbCBpbnZlbnRhcmlvIGFjdHVhbA0KICAgIGludmVudGFyaW9baSxqXSA9IGVzdGFkbw0KICAgIA0KICAgIGVzdGFkbyA9IHNhbXBsZShlc3RhZG9zLCBzaXplID0gMSwgcHJvYiA9IG1hdHJpelBbYXMuY2hhcmFjdGVyKGVzdGFkbyksXSkNCiAgICANCiAgfQ0KfQ0KDQptYXRwbG90KGludmVudGFyaW8sIHR5cGUgPSAnbCcsIHhsYWIgPSAnU2VtYW5hcycsIHlsYWIgPSAnSW52ZW50YXJpbycpDQoNCg0KIyBMaXRlcmFsIEQgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCg0KZXNjZW5hcmlvcyA9IDEwMDANCnNlbWFuYXMgPSAzMA0KDQppbnZlbnRhcmlvID0gbWF0cml4KDAsbnJvdyA9IHNlbWFuYXMsIG5jb2wgPSBlc2NlbmFyaW9zKQ0KDQoNCiNTaW11bGFyIGxhIGNhZGVuYSBkZSBtYXJrb3YNCnNldC5zZWVkKDApDQpmb3IgKGogaW4gMTplc2NlbmFyaW9zKSB7DQogIA0KICAjRGV0ZXJtaW5hciBlbCBlc3RhZG8gaW5pY2lhbA0KICBlc3RhZG8gPSAwDQogIA0KICAjU0ltdWxhciBsYXMgMzAgc2VtYW5hcw0KICBmb3IgKGkgaW4gMTpzZW1hbmFzKSB7DQogICAgDQogICAgI0d1YXJkYXIgZWwgaW52ZW50YXJpbyBhY3R1YWwNCiAgICBpbnZlbnRhcmlvW2ksal0gPSBlc3RhZG8NCiAgICANCiAgICBlc3RhZG8gPSBzYW1wbGUoZXN0YWRvcywgc2l6ZSA9IDEsIHByb2IgPSBtYXRyaXpQW2FzLmNoYXJhY3Rlcihlc3RhZG8pLF0pDQogICAgDQogIH0NCn0NCg0KaGlzdChpbnZlbnRhcmlvWzMwLF0sIG1haW4gPSAnRGlzdHJpYnVjacOzbiBkZWwgaW52ZW50YXJpbyBlbiBsYSBzZW1hbmEgMzAnKQ0KDQojQ2FsY3VsYW5kbyBlbCBpbnZlbnRhcmlvIHByb21lZGlvIGNvbiBNb250ZUNhcmxvDQppbnZlbnRhcmlvX3Byb21lZGlvID0gbWVhbihpbnZlbnRhcmlvWzMwLF0pDQoNCnByaW50KHBhc3RlKCdJbnZlbnRhcmlvIGNvbiBzaW11bGFjacOzbiBkZSBNb250ZUNhcmxvOiAnLCBpbnZlbnRhcmlvX3Byb21lZGlvKSkNCg0KI1ZhbG9yZXNwZXJhZG8gY29uIGFuYWxpc2lzIHRyYW5zaXRvcmlvDQpwcmludChwYXN0ZSgnVmFsb3IgZXNwZXJhZG8gZGVsIGludmVudGFyaW8gKGxpdGVyYWwgYik6ICcsIHJvdW5kKHZFc3BlcmFkb0ludlszMF0sMykpKQ0KDQoNCg0KIyBMaXRlcmFsIEUgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCg0KZXNjZW5hcmlvcyA8LSAxMDAwDQpzZW1hbmFzIDwtIDMwDQoNCiMgSW5pY2lhbGl6YXIgdmVjdG9yIHBhcmEgZ3VhcmRhciBsb3MgY29zdG9zIGRlIG9yZGVuYXIgZGUgY2FkYSBlc2NlbmFyaW8NCnZlY3Rvcl9jb3N0b3MgPC0gYygpDQoNCiMgU2ltdWxhciBsYSBjYWRlbmEgZGUgTWFya292DQpzZXQuc2VlZCgwKQ0KZm9yKGogaW4gMTplc2NlbmFyaW9zKXsNCiAgDQogICMgRGVmaW5pciBlbCBlc3RhZG8gaW5pY2lhbCAoaW52ZW50YXJpbyBpbmljaWFsKQ0KICBlc3RhZG8gPC0gMA0KICAjIEluaWNpYWxpemFyIGNvc3RvIGRlIG9yZGVuYXINCiAgY29zdG8gPC0gMA0KICANCiAgIyBTaW11bGFyIGxhcyB0cmFuc2ljaW9uZXMgcG9yIDMwIHNlbWFuYXMNCiAgZm9yKGkgaW4gMTpzZW1hbmFzKXsNCiAgICANCiAgICAjIFNpIGVsIGludmVudGFyaW8gZXMgbWVub3IgYSA3MCwgc3VtYXIgY29zdG8gZGUgb3JkZW5hcg0KICAgIGlmKGVzdGFkbzw9NzApew0KICAgICAgY29zdG8gPSBjb3N0byArIGNPcmRlbmFyDQogICAgfQ0KICAgIGVzdGFkbyA8LSBzYW1wbGUoZXN0YWRvcywgc2l6ZT0xLCBwcm9iPW1hdHJpelBbYXMuY2hhcmFjdGVyKGVzdGFkbyksXSkNCiAgfQ0KICANCiAgIyBHdWFyZGFyIGVsIGNvc3RvIGRlIG9yZGVuYXINCiAgdmVjdG9yX2Nvc3RvcyA8LSBjKHZlY3Rvcl9jb3N0b3MsIGNvc3RvKQ0KfQ0KY29zdG9fcHJvbWVkaW8gPSBtZWFuKHZlY3Rvcl9jb3N0b3MpDQpjb3N0b19wcm9tZWRpbw0KDQpwcmludChwYXN0ZSgiQ29zdG8gdG90YWwgZGUgb3JkZW5hciBwcm9tZWRpbyB1dGlsaXphbmRvIHNpbXVsYWNpw7NuIGRlIE1vbnRlIENhcmxvOiAiLCBjdXJyZW5jeShjb3N0b19wcm9tZWRpbykpKQ0KDQpwcmludChwYXN0ZSgiVmFsb3IgZXNwZXJhZG8gZGVsIGNvc3RvIHRvdGFsIGRlIG9yZGVuYXI6ICIsIGN1cnJlbmN5KHJvdW5kKHZFc3BlcmFkb09yZCwzKSkpKQ0KDQpgYGANCg0K