Este documento tem como objetivo apresentar conceitos de programação linear e como implementar tais problemas de otimização no R.

INTRODUÇÃO

Um problema geral de Programação Linear é utilizado para otimizar (maximizar ou minimizar) uma função linear de variáveis, chamada de função objetivo, sujeita a uma série de equações (ou inequações) lineares, chamadas restrições. Assim, temos que Programação linear é um caso de programação matemática onde a função objetivo e as restrições são todas lineares.

Abaixo, um exemplo de problema de programação linear:

\[ \begin{aligned} & \text{MAX} & & z = c_{1}x_{1}+c_{2}x_{2}+...+c_{n}x_{n} \\ & \text{s.a.} & & a_{11}x_{1}+a_{12}x_{2}+...+a_{1n}x_{n}\leq b_{1} \\ &&& a_{21}x_{1}+a_{22}x_{2}+...+a_{2n}x_{n}\leq b_{2} \\ &&& \ldots \ldots \ldots \ldots \ldots \ldots \ldots \ldots \ldots \\ &&& a_{m1}x_{1}+a_{m2}x_{2}+...+a_{mn}x_{n}\leq b_{m} \\ &&& x_{j} \geq 0 \end{aligned} \] O modelo tem os seguintes elementos:

As restrições de um problema de programação linear definem a região viável, que é o conjunto de valores que satisfazem todas as restrições. Tais restrições também podem ter sinal de \(\geq\) ou \(=\).

Outra maneira usual de expressar o problema de programação linear é no formato matricial, como segue:

\[ \begin{aligned} & \text{MAX} & & z = c^{\prime}x \\ & \text{s.a.} & & \boldsymbol{A}x \leq \boldsymbol{b} \\ &&& x \geq 0 \end{aligned} \]

\[ \begin{aligned} & \text{MIN} & & z = c^{\prime}x \\ & \text{s.a.} & & \boldsymbol{A}x \geq \boldsymbol{b} \\ &&& x \geq 0 \end{aligned} \] onde letras maiúsculas em negrito são matrizes e letras minúsculas em negrito são vetores.

TERMINOLOGIA PARA SOLUÇÕES DE MODELOS

Você deve estar acostumado a ver o termo solução com o significado de resposta final para um problema, porém, a convenção em programação linear (e suas extensões) é bem diferente. Aqui, qualquer especificação de valores para as variáveis de decisão (\(x_{1},x_{2},...,x_{n}\)) é chamda solução, idependentemente de ela ser desejável ou até mesmo ser uma opão admissível. Diferentes tipos de soluções são então identificados usando-se um adjetivo apropriado.

Uma solução viável é aquela para a qual todas as restrições são satisfeitas. Já uma solução inviável é aquela para a qual pelo menos uma das restrições é violada. Dado que existem soluções viáveis, o objetivo da programação linear é encontrar a melhor solução viável conforme medida pelo valor da função objetivo no modelo.

O valor mais favorável é o maior valor se a função objetivo tiver de ser maximizada, ao passo que será o menor valor caso ela deva ser minimizada. A maior parte dos problemas terá apenas uma solução ótima. Entretanto, é possível ter mais de uma. Outra possibilidade é que um problema não tenha nenhuma solução ótima. Isso acontece apenas se:

EXEMPLO DE PROBLEMA DE PROGRAMAÇÃO LINEAR

Uma pequena empresa vende dois produtos, Produto 1 e Produto 2. Cada tonelada do Produto 1 consome 30 horas de trabalho e cada tonelada do Produto 2 consome 20 horas de trabalho. A empresa tem no máximo 2700 horas de trabalho para o período considerado.

Além disso, cada tonelada dos Produtos 1 e 2 consome 5 e 10 horas de máquina para processar a matéria prima, respectivamente. Sabe-se que a empresa tem 850 horas disponíveis para processamento da matéria prima.

Cada tonelada vendida do Produto 1 gera 20 mil reais de lucro enquanto para o Produto 2 o valor é de 60 mil reais. Por razões técnicas a empresa deve produzir no mínimo um total de 95 toneladas. Nosso objetivo é saber quantas toneladas dos dois produtos devem ser produzidas para maximar o lucro total da empresa.

O problema exposto pode ser escrito da seguinte forma:

\[ \begin{aligned} & \text{MAX} & & z = 20P_{1}+60P_{2} \\ & \text{s.a.} & & 30P_{1}+20P_{2}\leq 2700 \\ &&& 5P_{1}+10P_{2}\leq 850 \\ &&& P_{1}+P_{2}\geq 95 \\ &&& P_{1} \geq 0 \\ &&& P_{2} \geq 0 \end{aligned} \]

RESOLVENDO PROBLEMAS DE PROGRAMAÇÃO LINEAR

O procedimento mais utilizado para resolver um problema de programação linear é usar o algoritmo simplex desenvolvido por Dantzig (1951). Outra alternativa para problemas com até duas variáveis é o método gráfico.

Problemas de programação linear com até duas variáveis de decisão podem ser representados e resolvidos graficamente. Embora limitada, a representação gráfica permite evidenciar propriedades e as diversas situações que podem ser encontradas ao se resolver problemas com um número maior de variáveis. Para efeito de exposição, considere o seguinte problema de programação linear:

\[ \begin{aligned} & \text{MAX} & & z = x_{1}+2x_{2} \\ & \text{s.a.} & & x_{1}+x_{2}\leq 8 \\ &&& -x_{1}+2x_{2}\leq 4 \\ &&& 2x_{1}-x_{2}\leq 12 \\ &&& x_{1} \geq 0 \\ &&& x_{2} \geq 0 \end{aligned} \] Considere o plano \(x_1 \times x_2\), com os eixos das abcissas e das ordenadas representando possíveis valores para as variáveis de decisão \(x_{1}\) e \(x_{2}\). Cada uma das restrições descreve uma região do plano. Para obter a região associada à restrição \(x_{1}+x_{2}\leq 8\), descreve-se inicialmente a reta \(x_{1}+x_{2}= 8\), que passa pelos pontos \((0,8)\) e \((8,0)\). A reta \(x_{1}+x_{2}= 8\) divide o plano em semiplanos, \(x_{1}+x_{2}\leq 8\) e \(x_{1}+x_{2}\ge 8\).

Repete-se o procedimento para todas as restrições presentes no modelo. A interseção das regiões descritas pelos semiplanos representa a região viável do problema ilustrada na figura abaixo.

A região viável possui infinitos pontos e, em princípio, qualquer um deles pode ser uma solução ótima do problema. Para determinar qual deles produz o maior valor para \(z\), usa-se o fato de que \(x_{1}+2x_{2}=z\) descreve uma família de retas paralelas de inclinação \(-0.5\) parametrizada pelo valor de \(z\). Diferentes valores de \(z\) levam a diferentes pontos de cruzamento com os eixos \(x_1\) e \(x_2\). Retas correspondentes a valores selecionados de \(z\) encontram-se representadas na figura acima. Para determinar o sentido de crescimento de \(z\), utiliza-se o conceito de gradiente de uma função num ponto. O vetor gradiente de qualquer função diferenciável \(z=f(x)\) de \(n\) variáveis num ponto \(x=(x_1,x_2,...,x_n)\), denotado por \(\nabla f(x)\), é o vetor formado pelas primeiras derivadas parciais da função no ponto considerado:

\[ \nabla f(x) = \left( \frac { \partial f\left( x \right) }{ \partial { x }_{ 1 } } ,\frac { \partial f\left( x \right) }{ \partial { x }_{ 2 } } ,...,\frac { \partial f\left( x \right) }{ \partial { x }_{ n } } \right) \] O vetor gradiente indica o sentido de maior crescimento da função no entorno do ponto considerado. Observa-se que o vetor gradiente de uma função linear,

\[ z=c_1x_1+c_2x_2+...+c_nx_n \] é constante e dado por

\[ c=(c_1,c_2,...,c_n) \] No caso do exemplo ilustrativo, \(c=(1,2)\). O sentido do gradiente está indicado na figura anterior. O vetor gradiente é ortogonal a qualquer reta que descreva um valor para a função objetivo.

Resumindo, a maximização do valor da função-objetivo no problema descrito pode ser conduzida da seguinte forma:

Se o objetivo do problema fosse, ao invés de maximizar, minimizar o valor de \(z\), adotar-se-ia a direção contrária à do gradiente, ou seja, a de maior decrescimento da função. O valor mínimo da função-objetivo seria \(z^{\ast}=0\), obtido no ponto \(x^{\ast}=(0,0)\).

O algoritmo simplex se aproveita do fato que o ótimo de um problema de programação linear pode ser encontrado explorando suas soluções básicas. As soluções básicas correspondem aos vértices da região viável do problema. A estratégia do algoritmo simplex será:

Softwares que resolvem problemas de programação linear quase sempre fazem uso do algoritmo simplex ou sua versão revisada que é uma variante que está implementada para ser mais eficiente. Existem outros algoritmos para problemas particulares de programação linear tal como: transporte de uma origem para um destino ou problema de fluxo máximo.

RESOLVENDO PROBLEMAS DE PROGRAMAÇÃO LINEAR NO R

Existem vários solvers disponíveis para resolver problemas de programação linear. Uma lista deles pode ser encontrada neste link. Alguns deles também são implementados no R, como segue:

Alguns destes pacotes têm funções que permitem a leitura de arquivos contendo problemas de programação linear, programação linear inteira e programação linear inteira mista escritos no formato CPLEX, por exemplo.

  1. Considere o exemplo apresentado anteriormente, abaixo temos a solução do problema de programação linear no R.
##########################
####     PACOTES     #####
##########################
# Instalar pacotes necessários para o restante do documento
#install.packages(c("lpSolve","lpSolveAPI", "ggplot2","plotly"))
# Carregar pacotes necessários para o restante do documento
suppressMessages(require(lpSolve))
suppressMessages(require(lpSolveAPI))
suppressMessages(require(ggplot2))
suppressMessages(require(plotly))
##########################
####     PROBMELA    #####
##########################
# coeficientes de P1 e P2 na função objetivo 
func.objetivo <- c(20 , 60)
# coeficientes de P1 e P2 nas restrições. Sempre em matriz como mostrado no texto acima
coeficientes.restricoes <- matrix (c(30, 20, 5, 10, 1, 1), ncol = 2 , byrow = TRUE)
# sinal das restrições. Deve obedecer a ordem da matriz de coeficientes
direcao.restricoes <- c("<=","<=",">=")
# limite das restrições. Deve obedecer a ordem da matriz de coeficientes
limites.restricoes <- c(2700, 850, 95)
##########################
####     SOLUÇÃO     #####
##########################
# Basicamente, usamos a função lp do pacote lpSolve com os seguintes parâmetros:
# direction: que recebe max ou min dependendo se o problema é de maximização ou minização, respectivamente
# objective.in: que recebe o nome do vetor com parâmetros da função objetivo
# const.mat: que recebe o nome da matriz com coeficientes das restrições
# const.rhs: que recebe o nome do vetor com os limites das restrições
# mais opções da função podem ser obtidas por meio do help(lp)
solucao.problema <- lpSolve::lp(direction = "max",             
                               objective.in = func.objetivo,  
                               const.mat = coeficientes.restricoes,
                               const.dir = direcao.restricoes,
                               const.rhs = limites.restricoes)
##########################
####    RESULTADO    #####
##########################
# valor da função objetivo na solução
solucao.problema$objval
[1] 4900
# Valores para as variáveis de escolha que geram máximo ou mínimo dependendo do problema
solucao.problema$solution
[1] 20 75
  1. Considere o seguinte problema de minimização:

\[ \begin{aligned} & \text{MIN} & & z = -3x_{1}-4x_{2}-3x_{3} \\ & \text{s.a.} & & 6x_{1}+2x_{2}+4x_{3}\leq 150 \\ &&& x_{1}+x_{2}+6x_{3}\geq 0 \\ &&& 4x_{1}+5x_{2}+4x_{3}= 40 \\ &&& x_{1} \geq 0 \\ &&& x_{2} \geq 0 \\ &&& x_{3} \geq 0 \\ \end{aligned} \]

##########################
####     PROBMELA    #####
##########################
# coeficientes de X1, X2 e X3 na função objetivo 
func.objetivo.prob2 <- c(-3 , -4, -3)
# coeficientes de X1, X2 e X3 nas restrições. 
coeficientes.restricoes.prob2 <- matrix (c(6, 2, 4, 1, 1, 6, 4, 5, 4), ncol = 3 , byrow = TRUE)
# sinal das restrições. Deve obedecer a ordem da matriz de coeficientes
direcao.restricoes.prob2 <- c("<=",">=","=")
# limite das restrições. Deve obedecer a ordem da matriz de coeficientes
limites.restricoes.prob2 <- c(150, 0, 40)
##########################
####     SOLUÇÃO     #####
##########################
solucao.problema2 <- lpSolve::lp(direction = "min",             
                               objective.in = func.objetivo.prob2,  
                               const.mat = coeficientes.restricoes.prob2,
                               const.dir = direcao.restricoes.prob2,
                               const.rhs = limites.restricoes.prob2)
##########################
####    RESULTADO    #####
##########################
# valor da função objetivo na solução
solucao.problema2$objval
[1] -32
# Valores para as variáveis de escolha que geram máximo ou mínimo dependendo do problema
solucao.problema2$solution
[1] 0 8 0
  1. Uma Companhia aérea está acrescentando mais vôos de/para seu aeroporto central e, para tanto, precisa contratar mais agentes para o atendimento ao público. Entretanto, não está claro quantas pessoas eles devem contratar. A gerência reconhece a necessidade de controle de custos, embora mantendo, ao mesmo tempo, um nível de serviços satisfatório a seus clientes.

Para isso, uma equipe está estudando como programar as escalas desses agentes para fornecer bons serviços aos clientes com o menor custo possível em termos de pessoal.

Tomando como base a nova escala de vôos, foi realizada uma análise do número mínimo de agentes de atendimento ao cliente que precisavam estar de serviço em diferentes horas do dia para fornecer um nível de serviço satisfatório. A coluna mais à direita da tabela abaixo mostra o número de agentes necessários para os períodos dados na primeira coluna. Os demais campos dessa tabela refletem uma das cláusulas no contrato atual da empresa com o sindicato que representa os agentes de atendimento ao cliente. Essa cláusula diz que cada agente trabalha cinco dias por semana em turnos de oito horas e os turnos autorizados são:

Período do Dia Turno Número mínimo de agentes necessários
1 2 3 4 5
6h-8h x 48
8h-10h x x 79
10h-12h x x 65
12h-14h x x x 87
14h-16h x x 64
16h-18h x x 73
18h-20h x x 82
20h-22h x 43
22h-00h x x 52
00h-06h x 15
Custo diário por agente 170 160 175 180 195

As marcas de verificação (x) no corpo da tabela indicam os horários cobertos pelos respectivos turnos. Pelo fato de alguns turnos serem menos desejados do que outros, os salários especificados no contrato diferem conforme o turno. Para cad turno, o pagamento diário (incluindo benefícios) para cada agente é mostrado na ultima linha da tabela. O problema é determinar quantos agentes devem ser alocados para os respectivos turnos diários a fim de minimizar o custo total com pessoal (agentes) tomando como base a última linha da tabela e, ao mesmo tempo, atendendo (ou ultrapassando) as exigências de nível de serviço dadas na coluna mais à direita.

Pelo fato de a função objetivo minimizar o custo total dos aentes atribuídos aos cinco turnos, os coeficientes na funç]ao objetivo são dados pela última linha da tabela. Portanto, o problema de programação linear completo é:

\[ \begin{aligned} & \text{MIN} & & z = 170x_{1}+160x_{2}+175x_{3}+180x_{4}+195x_{5} \\ & \text{s.a.} & & x_{1}\geq 48 && \text{(6h-8h)} \\ &&& x_{1}+x_{2}\geq 79 && \text{(8h-10h)} \\ &&& x_{1}+x_{2}\geq 65 && \text{(10h-12h)} \\ &&& x_{1}+x_{2}+x_{3} \geq 87 && \text{(12h-14h)} \\ &&& x_{2}+x_{3} \geq 64 && \text{(14h-16h)} \\ &&& x_{3}+x_{4} \geq 73 && \text{(16h-18h)} \\ &&& x_{3}+x_{4} \geq 82 && \text{(18h-20h)} \\ &&& x_{4} \geq 43 && \text{(20h-22h)} \\ &&& x_{4}+x_{5} \geq 52 && \text{(22h-00h)} \\ &&& x_{5} \geq 15 && \text{(00h-6h)} \\ &&& x_{j} \geq 0 && \text{para j=1,2,3,4,5} \\ \end{aligned} \] Com um olhar aguçado, você provavelmente deve ter percebido que a terceira restrição, \(x_{1}+x_{2}\geq 65\), na verdade não é necessária, pois a segunda restrição \(x_{1}+x_{2}\geq 79\), garante que \(x_{1}+x_{2}\) será maior que 65. Portanto, \(x_{1}+x_{2}\geq 65\) é uma restrição redundante que pode ser eliminada.

Da mesma forma, a sexta restrição \(x_{3}+x_{4} \geq 7\), também é redundante porque a sétima restrição é \(x_{3}+x_{4} \geq 82\). Na realidade, três das restrições de não-negatividade também são redundantes em razão da primeira, oitava e décima restrições funcionais: \(x_{1}\geq 48\), \(x_{4} \geq 43\) e \(x_{5} \geq 15\). Entretanto, não se ganha nenhuma vantagem em termos computacionais eliminando-se essas três restrições de não-negatividade.

##########################
####     PROBMELA    #####
##########################
# coeficientes de X1, X2 e X3 na função objetivo 
func.objetivo.prob3 <- c(170, 160, 175, 180, 195)
# coeficientes de X1, X2 e X3 nas restrições. 
coeficientes.restricoes.prob3 <- matrix (c(1, 0, 0, 0, 0, 
                                          1, 1, 0, 0, 0,
                                          1, 1, 1, 0, 0,
                                          0, 1, 1, 0, 0,
                                          0, 0, 1, 1, 0,
                                          0, 0, 0, 1, 0,
                                          0, 0, 0, 1, 1,
                                          0, 0, 0, 0, 1), 
                                        ncol = 5 , byrow = TRUE)
# sinal das restrições. Deve obedecer a ordem da matriz de coeficientes
direcao.restricoes.prob3 <- c(">=",">=",">=",">=",">=",">=",">=",">=")
# limite das restrições. Deve obedecer a ordem da matriz de coeficientes
limites.restricoes.prob3 <- c(48, 79, 87, 64, 82, 43, 52, 15)
##########################
####     SOLUÇÃO     #####
##########################
solucao.problema3 <- lpSolve::lp(direction = "min",             
                               objective.in = func.objetivo.prob3,  
                               const.mat = coeficientes.restricoes.prob3,
                               const.dir = direcao.restricoes.prob3,
                               const.rhs = limites.restricoes.prob3)
##########################
####    RESULTADO    #####
##########################
# valor da função objetivo na solução
solucao.problema3$objval
[1] 30610
# Valores para as variáveis de escolha que geram máximo ou mínimo dependendo do problema
solucao.problema3$solution
[1] 48 31 39 43 15

A solução ótima para esse modelo é \((x_{1},x_{2},x_{3},x_{4},x_{5})=(48,31,39,43,15)\). Isso faz com que \(Z=30.610\), isto é, um custo diário total com pessoal de U$30.610.

O número de agentes alocados para cada turno precisa ser um inteiro. Rigorosamente falando, o modelo deveria ter uma restrição adicional para cada variável de decisão especificando que a variável deve ter um valor inteiro. Acrescentar essas restrições transformaria o modelo de programação linear em um modelo de programação inteira.

Considere que temos o seguinte problema de programação linear:

\[ \begin{aligned} & \text{MIN} & & z = x_{1}+3x_{2}+6.24x_{3}+0.1x_{4} \\ & \text{s.a.} & & 78.26x_{2}+2.9x_{4}\geq 92.3 \\ &&& 0.24x_{1}+11.31x_{3}\leq 14.8 \\ &&& 12.68x_{1}+0.08x_{3}+0.9x_{4} \geq 4 \end{aligned} \] onde \(x_1\) é uma variável com valor mínimo de \(28.6\), \(x_2\) é uma variável não-negativa e inteira, \(x_3\) é uma variável binária e \(x_4\) é uma variável limitada ao intervalo \([18,48.98]\). Assim, por meio do pacote lpsolveAPI, temos a seguinte solução:

##########################
####     PROBMELA    #####
##########################
# Primeiro, criamos o problema com 3 restrições e 4 variáveis. Observe
# que abaixo sempre usaremos "lprec" para dizer que estamos adicionando
# definições ao problema
lprec <- lpSolveAPI::make.lp(3,4)
# Depois, definimos os valores da primeira coluna da matriz de restrições:
# - 1: indica a primeira coluna
# - c(0, 0.24, 12.68): os coeficientes de x1 nas restrições
lpSolveAPI::set.column(lprec, 1, c(0, 0.24, 12.68))
# Fazemos o mesmo para as demais variáveis (colunas). Aqui, usamos
# a opção indices que vai dizer em qual posição da coluna há valor, 
# pois em alguns casos podemos não ter nas restrições valores para
# outras variáveis
lpSolveAPI::set.column(lprec, 2, 78.26, indices = 1)
lpSolveAPI::set.column(lprec, 3, c(11.31, 0.08), indices = 2:3)
lpSolveAPI::set.column(lprec, 4, c(2.9, 0.9), indices = c(1,3))
# Agora, definimos a função objetivo
lpSolveAPI::set.objfn(lprec, c(1,3, 6.24, 0.1))
# Tipos de restrições
lpSolveAPI::set.constr.type(lprec, c(">=", "<=", ">="))
# Limite das restrições
lpSolveAPI::set.rhs(lprec, c(92.3, 14.8, 4))
# Por default, todas as variáveis são criadas como um valor real no 
# intervalo [0, infinito]. Assim, devemos mudar isso caso o problema
# demande. No nosso exemplo, temos:
# - x2: inteiro
# - x3: binário
lpSolveAPI::set.type(lprec, 2, "integer")
lpSolveAPI::set.type(lprec, 3, "binary")
# Definir o intervalo para as variáveis x1 e x4
# - x1: valor mínimo de 28.6 (primeira coluna)
# - x4: valor mínimo de 18 e máximo de 48.98 (quarta coluna)
lpSolveAPI::set.bounds(lprec, lower = c(28.6, 18), columns = c(1, 4))
lpSolveAPI::set.bounds(lprec, upper = 48.98, columns = 4)
# Finalmente, podemos renomear as variáveis do problema
RowNames <- c("ROWONE","ROWTWO", "ROWTHREE")
ColNames <- c("COLONE","COLTWO", "COLTHREE", "COLTFOUR")
dimnames(lprec) <- list(RowNames, ColNames)
# Definir se é um problema de maximização ou minimização
# Se maximização sense = c("max"). Use help(lp.control.options)
# para visualizar todas as opções que podem ser alteradas em
# um problema de otimização usando este pacote.
minimizar <- lpSolveAPI::lp.control(lprec, sense = c("min"))
# Visualizar o problema definido em um formato que seja fácil
# conferir se está tudo em conformidade com o problema a ser 
# resolvido
lprec
Model name: 
            COLONE    COLTWO  COLTHREE  COLTFOUR          
Minimize         1         3      6.24       0.1          
ROWONE           0     78.26         0       2.9  >=  92.3
ROWTWO        0.24         0     11.31         0  <=  14.8
ROWTHREE     12.68         0      0.08       0.9  >=     4
Kind           Std       Std       Std       Std          
Type          Real       Int       Int      Real          
Upper          Inf       Inf         1     48.98          
Lower         28.6         0         0        18          

Agora, podemos solucionar o problema como segue:

##########################
####     SOLUÇÃO     #####
##########################
# Solucionar o problema definido anteriormente usando a função
# solve.lpExtPtr do pacote lpSolveAPI. Aqui, o solver apenas
# informa o status da solução, como segue:
# 0:     "optimal solution found"
# 1:     "the model is sub-optimal"
# 2:     "the model is infeasible"
# 3:     "the model is unbounded"
# 4:     "the model is degenerate"
# 5:     "numerical failure encountered"
# 6:     "process aborted"
# 7:     "timeout"
# 9:     "the model was solved by presolve"
# 10:    "the branch and bound routine failed"
# 11:    "the branch and bound was stopped because of a break-at-first or break-at-value"
# 12:    "a feasible branch and bound solution was found"
# 13:    "no feasible branch and bound solution was found"
solucao.problema4 <- lpSolveAPI::solve.lpExtPtr(lprec)
##########################
####    RESULTADO    #####
##########################
# valor da função objetivo na solução
lpSolveAPI::get.objective(lprec)
[1] 31.78276
# Valores para as variáveis de escolha que geram máximo ou mínimo dependendo do problema
lpSolveAPI::get.variables(lprec)
[1] 28.60000  0.00000  0.00000 31.82759

REFERÊNCIAS

Chiang, Alpha C., and Kevin Wainwright. 2006. Matemática Para Economistas. Elsevier.

Dantzig, George B. 1951. “Maximization of a Linear Function of Variables Subject to Linear Inequalities.” New York.

Hillier, Frederick S, and Gerald J Lieberman. 2013. Introdução à Pesquisa Pesquisa Operacional. McGraw Hill Brasil.

Soetaert, Karline, and Peter MJ Herman. 2008. A Practical Guide to Ecological Modelling Using R as a Simulation Platform. Springer Science & Business Media.

LS0tCnRpdGxlOiA8Y2VudGVyPiA8aDI+IDxiPiBQcm9ncmFtYcOnw6NvIExpbmVhciA8L2I+IDwvaDI+IDwvY2VudGVyPiAKYXV0aG9yOiA8Y2VudGVyPiBIdWRzb24gQ2hhdmVzIENvc3RhIDwvY2VudGVyPgpncmFwaGljczogeWVzCmxpbmtjb2xvcjogYmx1ZQpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICB0aGVtZTogY2VydWxlYW4KICAgIGZpZ19jYXB0aW9uOiB5ZXMKcmVmZXJlbmNlczoKLSBpZDogc29ldGFlcnQyMDA4cHJhY3RpY2FsCiAgdGl0bGU6IEEgcHJhY3RpY2FsIGd1aWRlIHRvIGVjb2xvZ2ljYWwgbW9kZWxsaW5nIHVzaW5nIFIgYXMgYSBzaW11bGF0aW9uIHBsYXRmb3JtCiAgYXV0aG9yOgogIC0gZmFtaWx5OiBTb2V0YWVydAogICAgZ2l2ZW46IEthcmxpbmUKICAtIGZhbWlseTogSGVybWFuCiAgICBnaXZlbjogUGV0ZXIgTUoKICBwdWJsaXNoZXI6IFNwcmluZ2VyIFNjaWVuY2UgXCYgQnVzaW5lc3MgTWVkaWEKICB0eXBlOiBib29rCiAgaXNzdWVkOgogICAgeWVhcjogMjAwOAotIGlkOiBhbHBoYTIwMDRtYXRlbWF0aWNhCiAgdGl0bGU6IE1hdGVtw6F0aWNhIHBhcmEgZWNvbm9taXN0YXMKICBhdXRob3I6IAogIC0gZmFtaWx5OiBDaGlhbmcKICAgIGdpdmVuOiBBbHBoYSBDLgogIC0gZmFtaWx5OiBXYWlud3JpZ2h0CiAgICBnaXZlbjogS2V2aW4KICBwdWJsaXNoZXI6IEVsc2V2aWVyCiAgdHlwZTogYm9vawogIGlzc3VlZDoKICAgIHllYXI6IDIwMDYKLSBpZDogZGFudHppZzE5NTFtYXhpbWl6YXRpb24KICB0aXRsZTogTWF4aW1pemF0aW9uIG9mIGEgbGluZWFyIGZ1bmN0aW9uIG9mIHZhcmlhYmxlcyBzdWJqZWN0IHRvIGxpbmVhciBpbmVxdWFsaXRpZXMKICBhdXRob3I6IAogIC0gZmFtaWx5OiBEYW50emlnCiAgICBnaXZlbjogR2VvcmdlIEIKICBwdWJsaXNoZXI6IE5ldyBZb3JrCiAgdHlwZTogYXJ0aWNsZS1qb3VybmFsIAogIGlzc3VlZDoKICAgIHllYXI6IDE5NTEKLSBpZDogaGlsbGllcjIwMTNpbnRyb2R1Y2NhbwogIHRpdGxlOiBJbnRyb2R1w6fDo28gw6AgcGVzcXVpc2EgcGVzcXVpc2Egb3BlcmFjaW9uYWwKICBhdXRob3I6CiAgLSBmYW1pbHk6IEhpbGxpZXIKICAgIGdpdmVuOiBGcmVkZXJpY2sgUwogIC0gZmFtaWx5OiBMaWViZXJtYW4KICAgIGdpdmVuOiBHZXJhbGQgSgogIHB1Ymxpc2hlcjogTWNHcmF3IEhpbGwgQnJhc2lsCiAgdHlwZTogYm9vawogIGlzc3VlZDoKICAgIHllYXI6IDIwMTMKbm9jaXRlOiB8IAogIEBzb2V0YWVydDIwMDhwcmFjdGljYWwsIEBhbHBoYTIwMDRtYXRlbWF0aWNhLCBAZGFudHppZzE5NTFtYXhpbWl6YXRpb24sIEBoaWxsaWVyMjAxM2ludHJvZHVjY2FvCi0tLQoKRXN0ZSBkb2N1bWVudG8gdGVtIGNvbW8gb2JqZXRpdm8gYXByZXNlbnRhciBjb25jZWl0b3MgZGUgcHJvZ3JhbWHDp8OjbyBsaW5lYXIgZSBjb21vIGltcGxlbWVudGFyIHRhaXMgcHJvYmxlbWFzIGRlIG90aW1pemHDp8OjbyBubyBbUl0oaHR0cHM6Ly93d3cuci1wcm9qZWN0Lm9yZy8pLiAKCiMjIyMjICoqSU5UUk9EVcOHw4NPKioKClVtIHByb2JsZW1hIGdlcmFsIGRlIFByb2dyYW1hw6fDo28gTGluZWFyIMOpIHV0aWxpemFkbyBwYXJhIG90aW1pemFyIChtYXhpbWl6YXIgb3UgbWluaW1pemFyKSB1bWEgZnVuw6fDo28gbGluZWFyIGRlIHZhcmnDoXZlaXMsIGNoYW1hZGEgZGUgZnVuw6fDo28gb2JqZXRpdm8sIHN1amVpdGEgYSB1bWEgc8OpcmllIGRlIGVxdWHDp8O1ZXMgKG91IGluZXF1YcOnw7VlcykgbGluZWFyZXMsIGNoYW1hZGFzIHJlc3RyacOnw7Vlcy4gQXNzaW0sIHRlbW9zIHF1ZSBQcm9ncmFtYcOnw6NvIGxpbmVhciDDqSB1bSBjYXNvIGRlIHByb2dyYW1hw6fDo28gbWF0ZW3DoXRpY2Egb25kZSBhIGZ1bsOnw6NvIG9iamV0aXZvIGUgYXMgcmVzdHJpw6fDtWVzIHPDo28gdG9kYXMgbGluZWFyZXMuIAoKQWJhaXhvLCB1bSBleGVtcGxvIGRlIHByb2JsZW1hIGRlIHByb2dyYW1hw6fDo28gbGluZWFyOgoKJCQKXGJlZ2lue2FsaWduZWR9CiYgXHRleHR7TUFYfQomICYgeiA9IGNfezF9eF97MX0rY197Mn14X3syfSsuLi4rY197bn14X3tufSBcXAomIFx0ZXh0e3MuYS59CiYgJiBhX3sxMX14X3sxfSthX3sxMn14X3syfSsuLi4rYV97MW59eF97bn1cbGVxIGJfezF9IFxcCiYmJiBhX3syMX14X3sxfSthX3syMn14X3syfSsuLi4rYV97Mm59eF97bn1cbGVxIGJfezJ9IFxcCiYmJiBcbGRvdHMgXGxkb3RzIFxsZG90cyBcbGRvdHMgXGxkb3RzIFxsZG90cyBcbGRvdHMgXGxkb3RzIFxsZG90cyBcXAomJiYgYV97bTF9eF97MX0rYV97bTJ9eF97Mn0rLi4uK2Ffe21ufXhfe259XGxlcSBiX3ttfSBcXAomJiYgeF97an0gXGdlcSAwClxlbmR7YWxpZ25lZH0KJCQKTyBtb2RlbG8gdGVtIG9zIHNlZ3VpbnRlcyBlbGVtZW50b3M6CgogICogVW1hIGZ1bsOnw6NvIG9iamV0aXZvIGNvbSAkbiQgdmFyacOhdmVpcyBkZSBlc2NvbGhhIHF1ZSBzw6NvIGFmZXRhZGFzIHBvciBzZXVzIGNvZWZpY2llbnRlcywgJGNfe2p9JCwgcGFyYSAkaj0xLC4uLixuJC4KICAqIFVtIGNvbmp1bnRvIGRlICRtJCByZXN0cmnDp8O1ZXMgZW0gcXVlIHVtYSBjb21iaW5hw6fDo28gbGluZWFyIGRhcyB2YXJpw6F2ZWlzIGRlIGVzY29saGEgYWZldGFkYXMgcGVsb3MgY29lZmljaWVudGVzICRhX3tpan0kIGRldmVtIHNlciBtZW5vciBvdSBpZ3VhbCBhb3MgdmFsb3JlcyBkbyBsYWRvIGRpcmVpdG8gZGFzIGVxdWHDp8O1ZXMsICRiX3tpfSQgcGFyYSAkaT0xLC4uLm0kCiAgKiBMaW1pdGVzIGRhcyB2YXJpw6F2ZWlzIGRlIGVzY29saGEuIE5lc3RlIGNhc28sIHRvZGFzIHByZWNpc2FtIGFzc3VtaXIgdmFsb3JlcyBuw6NvIG5lZ2F0aXZvcyAoJHhfe2p9IFxnZXEgMCQpCgpBcyByZXN0cmnDp8O1ZXMgZGUgdW0gcHJvYmxlbWEgZGUgcHJvZ3JhbWHDp8OjbyBsaW5lYXIgZGVmaW5lbSBhIHJlZ2nDo28gdmnDoXZlbCwgcXVlIMOpIG8gY29uanVudG8gZGUgdmFsb3JlcyBxdWUgc2F0aXNmYXplbSB0b2RhcyBhcyByZXN0cmnDp8O1ZXMuIFRhaXMgcmVzdHJpw6fDtWVzIHRhbWLDqW0gcG9kZW0gdGVyIHNpbmFsIGRlICRcZ2VxJCBvdSAkPSQuIAoKT3V0cmEgbWFuZWlyYSB1c3VhbCBkZSBleHByZXNzYXIgbyBwcm9ibGVtYSBkZSBwcm9ncmFtYcOnw6NvIGxpbmVhciDDqSBubyBmb3JtYXRvIG1hdHJpY2lhbCwgY29tbyBzZWd1ZToKCiQkClxiZWdpbnthbGlnbmVkfQomIFx0ZXh0e01BWH0KJiAmIHogPSBjXntccHJpbWV9eCBcXAomIFx0ZXh0e3MuYS59CiYgJiBcYm9sZHN5bWJvbHtBfXggXGxlcSBcYm9sZHN5bWJvbHtifSBcXAomJiYgeCBcZ2VxIDAKXGVuZHthbGlnbmVkfQokJAoKJCQKXGJlZ2lue2FsaWduZWR9CiYgXHRleHR7TUlOfQomICYgeiA9IGNee1xwcmltZX14IFxcCiYgXHRleHR7cy5hLn0KJiAmIFxib2xkc3ltYm9se0F9eCBcZ2VxIFxib2xkc3ltYm9se2J9IFxcCiYmJiB4IFxnZXEgMApcZW5ke2FsaWduZWR9CiQkCm9uZGUgbGV0cmFzIG1hacO6c2N1bGFzIGVtIG5lZ3JpdG8gc8OjbyBtYXRyaXplcyBlIGxldHJhcyBtaW7DunNjdWxhcyBlbSBuZWdyaXRvIHPDo28gdmV0b3Jlcy4gCgojIyMjIyAqKlRFUk1JTk9MT0dJQSBQQVJBIFNPTFXDh8OVRVMgREUgTU9ERUxPUyoqCgpWb2PDqiBkZXZlIGVzdGFyIGFjb3N0dW1hZG8gYSB2ZXIgbyB0ZXJtbyAqKnNvbHXDp8OjbyoqIGNvbSBvIHNpZ25pZmljYWRvIGRlIHJlc3Bvc3RhIGZpbmFsIHBhcmEgdW0gcHJvYmxlbWEsIHBvcsOpbSwgYSBjb252ZW7Dp8OjbyBlbSBwcm9ncmFtYcOnw6NvIGxpbmVhciAoZSBzdWFzIGV4dGVuc8O1ZXMpIMOpIGJlbSBkaWZlcmVudGUuIEFxdWksIHF1YWxxdWVyIGVzcGVjaWZpY2HDp8OjbyBkZSB2YWxvcmVzIHBhcmEgYXMgdmFyacOhdmVpcyBkZSBkZWNpc8OjbyAoJHhfezF9LHhfezJ9LC4uLix4X3tufSQpIMOpIGNoYW1kYSAqKnNvbHXDp8OjbyoqLCBpZGVwZW5kZW50ZW1lbnRlIGRlIGVsYSBzZXIgZGVzZWrDoXZlbCBvdSBhdMOpIG1lc21vIHNlciB1bWEgb3DDo28gYWRtaXNzw612ZWwuIERpZmVyZW50ZXMgdGlwb3MgZGUgc29sdcOnw7VlcyBzw6NvIGVudMOjbyBpZGVudGlmaWNhZG9zIHVzYW5kby1zZSB1bSBhZGpldGl2byBhcHJvcHJpYWRvLgoKVW1hICoqc29sdcOnw6NvIHZpw6F2ZWwqKiDDqSBhcXVlbGEgcGFyYSBhIHF1YWwgKip0b2RhcyoqIGFzIHJlc3RyacOnw7VlcyBzw6NvIHNhdGlzZmVpdGFzLiBKw6EgdW1hICoqc29sdcOnw6NvIGludmnDoXZlbCoqIMOpIGFxdWVsYSBwYXJhIGEgcXVhbCAqKnBlbG8gbWVub3MgdW1hKiogZGFzIHJlc3RyacOnw7VlcyDDqSB2aW9sYWRhLiBEYWRvIHF1ZSBleGlzdGVtIHNvbHXDp8O1ZXMgdmnDoXZlaXMsIG8gb2JqZXRpdm8gZGEgcHJvZ3JhbWHDp8OjbyBsaW5lYXIgw6kgZW5jb250cmFyIGEgbWVsaG9yIHNvbHXDp8OjbyB2acOhdmVsIGNvbmZvcm1lIG1lZGlkYSBwZWxvIHZhbG9yIGRhIGZ1bsOnw6NvIG9iamV0aXZvIG5vIG1vZGVsby4KCk8gKip2YWxvciBtYWlzIGZhdm9yw6F2ZWwqKiDDqSBvIG1haW9yIHZhbG9yIHNlIGEgZnVuw6fDo28gb2JqZXRpdm8gdGl2ZXIgZGUgc2VyIG1heGltaXphZGEsIGFvIHBhc3NvIHF1ZSBzZXLDoSBvIG1lbm9yIHZhbG9yIGNhc28gZWxhIGRldmEgc2VyIG1pbmltaXphZGEuIEEgbWFpb3IgcGFydGUgZG9zIHByb2JsZW1hcyB0ZXLDoSBhcGVuYXMgdW1hIHNvbHXDp8OjbyDDs3RpbWEuIEVudHJldGFudG8sIMOpIHBvc3PDrXZlbCB0ZXIgbWFpcyBkZSB1bWEuIE91dHJhIHBvc3NpYmlsaWRhZGUgw6kgcXVlIHVtIHByb2JsZW1hIG7Do28gdGVuaGEgKipuZW5odW1hIHNvbHXDp8OjbyDDs3RpbWEqKi4gSXNzbyBhY29udGVjZSBhcGVuYXMgc2U6CgogICAqIHNlIG7Do28gZXhpc3RpciBuZW5odW1hIHNvbHXDp8OjbyB2acOhdmVsOwogICAqIGFzIHJlc3RyacOnw7VlcyBuw6NvIGltcGVkaXJlbSBxdWUgc2UgYXVtZW50ZSBpbmRlZmluaWRhbWVudGUgbyB2YWxvciBkYSBmdW7Dp8OjbyBvYmpldGl2byBuYSBkaXJlw6fDo28gZmF2b3LDoXZlbCAocG9zaXRpdmEgb3UgbmVnYXRpdmEpLiBFc3RlIGNhc28gw6kgY29uaGVjaWRvIGNvbW8gKipmdW7Dp8OjbyBvYmpldGl2byBpbGltaXRhZGEqLioKCiMjIyMjICoqRVhFTVBMTyBERSBQUk9CTEVNQSBERSBQUk9HUkFNQcOHw4NPIExJTkVBUioqCgpVbWEgcGVxdWVuYSBlbXByZXNhIHZlbmRlIGRvaXMgcHJvZHV0b3MsIFByb2R1dG8gMSBlIFByb2R1dG8gMi4gQ2FkYSB0b25lbGFkYSBkbyBQcm9kdXRvIDEgY29uc29tZSAzMCBob3JhcyBkZSB0cmFiYWxobyBlIGNhZGEgdG9uZWxhZGEgZG8gUHJvZHV0byAyIGNvbnNvbWUgMjAgaG9yYXMgZGUgdHJhYmFsaG8uIEEgZW1wcmVzYSB0ZW0gbm8gbcOheGltbyAyNzAwIGhvcmFzIGRlIHRyYWJhbGhvIHBhcmEgbyBwZXLDrW9kbyBjb25zaWRlcmFkby4KCkFsw6ltIGRpc3NvLCBjYWRhIHRvbmVsYWRhIGRvcyBQcm9kdXRvcyAxIGUgMiBjb25zb21lIDUgZSAxMCBob3JhcyBkZSBtw6FxdWluYSBwYXJhIHByb2Nlc3NhciBhIG1hdMOpcmlhIHByaW1hLCByZXNwZWN0aXZhbWVudGUuIFNhYmUtc2UgcXVlIGEgZW1wcmVzYSB0ZW0gODUwIGhvcmFzIGRpc3BvbsOtdmVpcyBwYXJhIHByb2Nlc3NhbWVudG8gZGEgbWF0w6lyaWEgcHJpbWEuCgpDYWRhIHRvbmVsYWRhIHZlbmRpZGEgZG8gUHJvZHV0byAxIGdlcmEgMjAgbWlsIHJlYWlzIGRlIGx1Y3JvIGVucXVhbnRvIHBhcmEgbyBQcm9kdXRvIDIgbyB2YWxvciDDqSBkZSA2MCBtaWwgcmVhaXMuIFBvciByYXrDtWVzIHTDqWNuaWNhcyBhIGVtcHJlc2EgZGV2ZSBwcm9kdXppciBubyBtw61uaW1vIHVtIHRvdGFsIGRlIDk1IHRvbmVsYWRhcy4gKipOb3NzbyBvYmpldGl2byDDqSBzYWJlciBxdWFudGFzIHRvbmVsYWRhcyBkb3MgZG9pcyBwcm9kdXRvcyBkZXZlbSBzZXIgcHJvZHV6aWRhcyBwYXJhIG1heGltYXIgbyBsdWNybyB0b3RhbCBkYSBlbXByZXNhLioqCgpPIHByb2JsZW1hIGV4cG9zdG8gcG9kZSBzZXIgZXNjcml0byBkYSBzZWd1aW50ZSBmb3JtYToKCiQkClxiZWdpbnthbGlnbmVkfQomIFx0ZXh0e01BWH0KJiAmIHogPSAyMFBfezF9KzYwUF97Mn0gXFwKJiBcdGV4dHtzLmEufQomICYgMzBQX3sxfSsyMFBfezJ9XGxlcSAyNzAwIFxcCiYmJiA1UF97MX0rMTBQX3syfVxsZXEgODUwIFxcCiYmJiBQX3sxfStQX3syfVxnZXEgOTUgXFwKJiYmIFBfezF9IFxnZXEgMCBcXAomJiYgUF97Mn0gXGdlcSAwClxlbmR7YWxpZ25lZH0KJCQKCiMjIyMjICoqUkVTT0xWRU5ETyBQUk9CTEVNQVMgREUgUFJPR1JBTUHDh8ODTyBMSU5FQVIqKgoKTyBwcm9jZWRpbWVudG8gbWFpcyB1dGlsaXphZG8gcGFyYSByZXNvbHZlciB1bSBwcm9ibGVtYSBkZSBwcm9ncmFtYcOnw6NvIGxpbmVhciDDqSB1c2FyIG8gYWxnb3JpdG1vICoqc2ltcGxleCoqIGRlc2Vudm9sdmlkbyBwb3IgQGRhbnR6aWcxOTUxbWF4aW1pemF0aW9uLiBPdXRyYSBhbHRlcm5hdGl2YSBwYXJhIHByb2JsZW1hcyBjb20gYXTDqSBkdWFzIHZhcmnDoXZlaXMgw6kgbyAqKm3DqXRvZG8gZ3LDoWZpY28qKi4gCgoqICoqTcOJVE9ETyBHUsOBRklDTyoqCgpQcm9ibGVtYXMgZGUgcHJvZ3JhbWHDp8OjbyBsaW5lYXIgY29tIGF0w6kgZHVhcyB2YXJpw6F2ZWlzIGRlIGRlY2lzw6NvIHBvZGVtIHNlciByZXByZXNlbnRhZG9zIGUgcmVzb2x2aWRvcyBncmFmaWNhbWVudGUuIEVtYm9yYSBsaW1pdGFkYSwgYSByZXByZXNlbnRhw6fDo28gZ3LDoWZpY2EgcGVybWl0ZSBldmlkZW5jaWFyIHByb3ByaWVkYWRlcyBlIGFzIGRpdmVyc2FzIHNpdHVhw6fDtWVzIHF1ZSBwb2RlbSBzZXIgZW5jb250cmFkYXMgYW8gc2UgcmVzb2x2ZXIgcHJvYmxlbWFzIGNvbSB1bSBuw7ptZXJvIG1haW9yIGRlIHZhcmnDoXZlaXMuIFBhcmEgZWZlaXRvIGRlIGV4cG9zacOnw6NvLCBjb25zaWRlcmUgbyBzZWd1aW50ZSBwcm9ibGVtYSBkZSBwcm9ncmFtYcOnw6NvIGxpbmVhcjoKCiQkClxiZWdpbnthbGlnbmVkfQomIFx0ZXh0e01BWH0KJiAmIHogPSB4X3sxfSsyeF97Mn0gXFwKJiBcdGV4dHtzLmEufQomICYgeF97MX0reF97Mn1cbGVxIDggXFwKJiYmIC14X3sxfSsyeF97Mn1cbGVxIDQgXFwKJiYmIDJ4X3sxfS14X3syfVxsZXEgMTIgXFwKJiYmIHhfezF9IFxnZXEgMCBcXAomJiYgeF97Mn0gXGdlcSAwClxlbmR7YWxpZ25lZH0KJCQKQ29uc2lkZXJlIG8gKipwbGFubyoqICR4XzEgXHRpbWVzIHhfMiQsIGNvbSBvcyBlaXhvcyBkYXMgYWJjaXNzYXMgZSBkYXMgb3JkZW5hZGFzIHJlcHJlc2VudGFuZG8gcG9zc8OtdmVpcyB2YWxvcmVzIHBhcmEgYXMgdmFyacOhdmVpcyBkZSBkZWNpc8OjbyAkeF97MX0kIGUgJHhfezJ9JC4gQ2FkYSB1bWEgZGFzIHJlc3RyacOnw7VlcyBkZXNjcmV2ZSB1bWEgcmVnacOjbyBkbyAqKnBsYW5vKiouIFBhcmEgb2J0ZXIgYSByZWdpw6NvIGFzc29jaWFkYSDDoCByZXN0cmnDp8OjbyAkeF97MX0reF97Mn1cbGVxIDgkLCBkZXNjcmV2ZS1zZSBpbmljaWFsbWVudGUgYSAqKnJldGEqKiAkeF97MX0reF97Mn09IDgkLCBxdWUgcGFzc2EgcGVsb3MgcG9udG9zICQoMCw4KSQgZSAkKDgsMCkkLiBBIHJldGEgJHhfezF9K3hfezJ9PSA4JCBkaXZpZGUgbyBwbGFubyBlbSAqKnNlbWlwbGFub3MqKiwgICR4X3sxfSt4X3syfVxsZXEgOCQgZSAkeF97MX0reF97Mn1cZ2UgOCQuIAoKUmVwZXRlLXNlIG8gcHJvY2VkaW1lbnRvIHBhcmEgdG9kYXMgYXMgcmVzdHJpw6fDtWVzIHByZXNlbnRlcyBubyBtb2RlbG8uIEEgaW50ZXJzZcOnw6NvIGRhcyByZWdpw7VlcyBkZXNjcml0YXMgcGVsb3Mgc2VtaXBsYW5vcyByZXByZXNlbnRhIGEgKipyZWdpw6NvIHZpw6F2ZWwqKiBkbyBwcm9ibGVtYSBpbHVzdHJhZGEgbmEgZmlndXJhIGFiYWl4by4KCmBgYHtyICBlY2hvPUZBTFNFLCBvdXQud2lkdGggPSAiMzAlIiwgZmlnLmFsaWduPSdyaWdodCd9CmxpYnJhcnkoa25pdHIpCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCdmb3RvLmpwZycpCmBgYApBIHJlZ2nDo28gdmnDoXZlbCBwb3NzdWkgaW5maW5pdG9zIHBvbnRvcyBlLCBlbSBwcmluY8OtcGlvLCBxdWFscXVlciB1bSBkZWxlcyBwb2RlIHNlciB1bWEgc29sdcOnw6NvIMOzdGltYSBkbyBwcm9ibGVtYS4gUGFyYSBkZXRlcm1pbmFyIHF1YWwgZGVsZXMgcHJvZHV6IG8gbWFpb3IgdmFsb3IgcGFyYSAkeiQsIHVzYS1zZSBvIGZhdG8gZGUgcXVlICR4X3sxfSsyeF97Mn09eiQgZGVzY3JldmUgdW1hIGZhbcOtbGlhIGRlIHJldGFzIHBhcmFsZWxhcyBkZSBpbmNsaW5hw6fDo28gJC0wLjUkIHBhcmFtZXRyaXphZGEgcGVsbyB2YWxvciBkZSAkeiQuIERpZmVyZW50ZXMgdmFsb3JlcyBkZSAkeiQgbGV2YW0gYSBkaWZlcmVudGVzIHBvbnRvcyBkZSBjcnV6YW1lbnRvIGNvbSBvcyBlaXhvcyAkeF8xJCBlICR4XzIkLiBSZXRhcyBjb3JyZXNwb25kZW50ZXMgYSB2YWxvcmVzIHNlbGVjaW9uYWRvcyBkZSAkeiQgZW5jb250cmFtLXNlIHJlcHJlc2VudGFkYXMgbmEgZmlndXJhIGFjaW1hLiBQYXJhIGRldGVybWluYXIgbyBzZW50aWRvIGRlIGNyZXNjaW1lbnRvIGRlICR6JCwgdXRpbGl6YS1zZSBvIGNvbmNlaXRvIGRlICoqZ3JhZGllbnRlKiogZGUgdW1hIGZ1bsOnw6NvIG51bSBwb250by4gTyB2ZXRvciBncmFkaWVudGUgZGUgcXVhbHF1ZXIgZnVuw6fDo28gZGlmZXJlbmNpw6F2ZWwgJHo9Zih4KSQgZGUgJG4kIHZhcmnDoXZlaXMgbnVtIHBvbnRvICR4PSh4XzEseF8yLC4uLix4X24pJCwgZGVub3RhZG8gcG9yICRcbmFibGEgZih4KSQsIMOpIG8gdmV0b3IgZm9ybWFkbyBwZWxhcyBwcmltZWlyYXMgZGVyaXZhZGFzIHBhcmNpYWlzIGRhIGZ1bsOnw6NvIG5vIHBvbnRvIGNvbnNpZGVyYWRvOgoKJCQKXG5hYmxhIGYoeCkgPSBcbGVmdCggXGZyYWMgeyBccGFydGlhbCBmXGxlZnQoIHggXHJpZ2h0KSAgfXsgXHBhcnRpYWwgeyB4IH1feyAxIH0gfSAsXGZyYWMgeyBccGFydGlhbCBmXGxlZnQoIHggXHJpZ2h0KSAgfXsgXHBhcnRpYWwgeyB4IH1feyAyIH0gfSAsLi4uLFxmcmFjIHsgXHBhcnRpYWwgZlxsZWZ0KCB4IFxyaWdodCkgIH17IFxwYXJ0aWFsIHsgeCB9X3sgbiB9IH0gIFxyaWdodCkgCiQkCk8gdmV0b3IgZ3JhZGllbnRlIGluZGljYSBvIHNlbnRpZG8gZGUgbWFpb3IgY3Jlc2NpbWVudG8gZGEgZnVuw6fDo28gbm8gZW50b3JubyBkbyBwb250byBjb25zaWRlcmFkby4gT2JzZXJ2YS1zZSBxdWUgbyB2ZXRvciBncmFkaWVudGUgZGUgdW1hIGZ1bsOnw6NvIGxpbmVhciwgCgokJAp6PWNfMXhfMStjXzJ4XzIrLi4uK2NfbnhfbgokJArDqSBjb25zdGFudGUgZSBkYWRvIHBvciAKCiQkCmM9KGNfMSxjXzIsLi4uLGNfbikKJCQKTm8gY2FzbyBkbyBleGVtcGxvIGlsdXN0cmF0aXZvLCAkYz0oMSwyKSQuIE8gc2VudGlkbyBkbyBncmFkaWVudGUgZXN0w6EgaW5kaWNhZG8gbmEgZmlndXJhIGFudGVyaW9yLiBPIHZldG9yIGdyYWRpZW50ZSDDqSAqKm9ydG9nb25hbCoqIGEgcXVhbHF1ZXIgcmV0YSBxdWUgZGVzY3JldmEgdW0gdmFsb3IgcGFyYSBhIGZ1bsOnw6NvIG9iamV0aXZvLiAKClJlc3VtaW5kbywgYSBtYXhpbWl6YcOnw6NvIGRvIHZhbG9yIGRhIGZ1bsOnw6NvLW9iamV0aXZvIG5vIHByb2JsZW1hIGRlc2NyaXRvIHBvZGUgc2VyIGNvbmR1emlkYSBkYSBzZWd1aW50ZSBmb3JtYToKCiogcGVyY29ycmVyIGEgcmVnacOjbyB2acOhdmVsIGRvIHByb2JsZW1hIG5vIHNlbnRpZG8gZG8gZ3JhZGllbnRlIChhdW1lbnRhbmRvIGNvbnRpbnVhbWVudGUgbyB2YWxvciBkYSBmdW7Dp8OjbyBvYmpldGl2bykgYXTDqSBxdWUgYSBmcm9udGVpcmEgZGEgcmVnacOjbyBzZWphIGV2ZW50dWFsbWVudGUgYXRpbmdpZGE7CiogbyB2YWxvciBtw6F4aW1vIGRhIGZ1bsOnw6NvLW9iamV0aXZvIG5hIHJlZ2nDo28gdmnDoXZlbCDDqSBkYWRvIHBlbG8gdmFsb3IgZGEgcmV0YSBxdWUgdG9jYSBhIGZyb250ZWlyYSwgbm8gY2FzbyAkel57XGFzdH09MTIkLiBRdWFscXVlciBwb250byBxdWUgcGVydGVuY2Egw6AgcmV0YSBkZSB2YWxvciAkel57XGFzdH09MTIkIHF1ZSB0YW1iw6ltIHBlcmNlbnRlIMOgIGZyb250ZWlyYSDDqSB1bWEgc29sdcOnw6NvIMOzdGltYSBkbyBwcm9ibGVtYS4gTm8gY2FzbyBkbyBleGVtcGxvLCBleGlzdGUgYXBlbmFzIHVtYSBzb2x1w6fDo28gw7N0aW1hLCAkeF57XGFzdH09KDQsNCkkLgoKU2UgbyBvYmpldGl2byBkbyBwcm9ibGVtYSBmb3NzZSwgYW8gaW52w6lzIGRlIG1heGltaXphciwgbWluaW1pemFyIG8gdmFsb3IgZGUgJHokLCBhZG90YXItc2UtaWEgYSBkaXJlw6fDo28gY29udHLDoXJpYSDDoCBkbyBncmFkaWVudGUsIG91IHNlamEsIGEgZGUgbWFpb3IgKipkZWNyZXNjaW1lbnRvKiogZGEgZnVuw6fDo28uIE8gdmFsb3IgbcOtbmltbyBkYSBmdW7Dp8Ojby1vYmpldGl2byBzZXJpYSAkel57XGFzdH09MCQsIG9idGlkbyBubyBwb250byAkeF57XGFzdH09KDAsMCkkLiAKCiogKipNw4lUT0RPIFNJTVBMRVgqKgoKTyBhbGdvcml0bW8gKipzaW1wbGV4Kiogc2UgYXByb3ZlaXRhIGRvIGZhdG8gcXVlIG8gw7N0aW1vIGRlIHVtIHByb2JsZW1hIGRlIHByb2dyYW1hw6fDo28gbGluZWFyIHBvZGUgc2VyIGVuY29udHJhZG8gZXhwbG9yYW5kbyBzdWFzIHNvbHXDp8O1ZXMgYsOhc2ljYXMuIEFzIHNvbHXDp8O1ZXMgYsOhc2ljYXMgY29ycmVzcG9uZGVtIGFvcyB2w6lydGljZXMgZGEgcmVnacOjbyB2acOhdmVsIGRvIHByb2JsZW1hLiBBIGVzdHJhdMOpZ2lhIGRvIGFsZ29yaXRtbyAqKnNpbXBsZXgqKiBzZXLDoToKCiogRW5jb250cmFyIGEgc29sdcOnw6NvIGLDoXNpY2EgaW5pY2lhbAoqIEV4cGxvcmFyIGFzIHNvbHXDp8O1ZXMgYsOhc2ljYXMgbW92ZW5kbyBuYSBkaXJlw6fDo28gcXVlIG1heGltaXphIG91IG1pbmltaXphIGEgZnVuw6fDo28gb2JqZXRpdm8KKiBQYXJhciBxdWFuZG8gdW1hIHNvbHXDp8OjbyDDs3RpbWEgw6kgZW5jb250cmFkYQoKU29mdHdhcmVzIHF1ZSByZXNvbHZlbSBwcm9ibGVtYXMgZGUgcHJvZ3JhbWHDp8OjbyBsaW5lYXIgcXVhc2Ugc2VtcHJlIGZhemVtIHVzbyBkbyBhbGdvcml0bW8gc2ltcGxleCBvdSBzdWEgdmVyc8OjbyByZXZpc2FkYSBxdWUgw6kgdW1hIHZhcmlhbnRlIHF1ZSBlc3TDoSBpbXBsZW1lbnRhZGEgcGFyYSBzZXIgbWFpcyBlZmljaWVudGUuIEV4aXN0ZW0gb3V0cm9zIGFsZ29yaXRtb3MgcGFyYSBwcm9ibGVtYXMgcGFydGljdWxhcmVzIGRlIHByb2dyYW1hw6fDo28gbGluZWFyIHRhbCBjb21vOiBbdHJhbnNwb3J0ZSBkZSB1bWEgb3JpZ2VtIHBhcmEgdW0gZGVzdGlub10oaHR0cDovL3dpa2kuaWNtYy51c3AuYnIvaW1hZ2VzLzEvMTMvQXVsYTJQTV9tYXJpLnBkZikgb3UgW3Byb2JsZW1hIGRlIGZsdXhvIG3DoXhpbW9dKGh0dHA6Ly93d3cudWZqZi5ici9lcGQwMTUvZmlsZXMvMjAxMC8wNi9mbHV4b19tYXhpbW8yLnBkZikuCgojIyMjIyAqKlJFU09MVkVORE8gUFJPQkxFTUFTIERFIFBST0dSQU1Bw4fDg08gTElORUFSIE5PIFIqKgoKRXhpc3RlbSB2w6FyaW9zIHNvbHZlcnMgZGlzcG9uw612ZWlzIHBhcmEgcmVzb2x2ZXIgcHJvYmxlbWFzIGRlIHByb2dyYW1hw6fDo28gbGluZWFyLiBVbWEgbGlzdGEgZGVsZXMgcG9kZSBzZXIgZW5jb250cmFkYSBuZXN0ZSBbbGlua10oaHR0cDovL3d3dy5ndXJvYmkuY29tL3Jlc291cmNlcy9zd2l0Y2hpbmctdG8tZ3Vyb2JpL29wZW4tc291cmNlLXNvbHZlcnMpLiBBbGd1bnMgZGVsZXMgdGFtYsOpbSBzw6NvIGltcGxlbWVudGFkb3Mgbm8gUiwgY29tbyBzZWd1ZToKCiogW2xwX3NvbHZlXShodHRwOi8vbHBzb2x2ZS5zb3VyY2Vmb3JnZS5uZXQvNS41LykgcXVlIMOpIGRpc3BvbmliaWxpemFkbyBubyBSIHBvciBtZWlvIGRvcyBwYWNvdGVzIFtscFNvbHZlXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvbHBTb2x2ZS9scFNvbHZlLnBkZikgZSBbbHBTb2x2ZUFQSV0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL2xwU29sdmVBUEkvbHBTb2x2ZUFQSS5wZGYpOwoqIFtHTFBLXShodHRwczovL3d3dy5nbnUub3JnL3NvZnR3YXJlL2dscGsvKSBxdWUgbm8gUiBwb2RlIHNlciB1c2FkbyB2aWEgcGFjb3RlIFtSZ2xwa10oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL1JnbHBrL1JnbHBrLnBkZik7CiogW1NZTVBIT05ZXShodHRwczovL3Byb2plY3RzLmNvaW4tb3Iub3JnL1NZTVBIT05ZKSBxdWUgZXN0w6EgZGlzcG9uw612ZWwgbm8gUiB2aWEgcGFjb3RlIFtSc3ltcGhvbnldKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9Sc3ltcGhvbnkvUnN5bXBob255LnBkZikKCkFsZ3VucyBkZXN0ZXMgcGFjb3RlcyB0w6ptIGZ1bsOnw7VlcyBxdWUgcGVybWl0ZW0gYSBsZWl0dXJhIGRlIGFycXVpdm9zIGNvbnRlbmRvIHByb2JsZW1hcyBkZSBwcm9ncmFtYcOnw6NvIGxpbmVhciwgcHJvZ3JhbWHDp8OjbyBsaW5lYXIgaW50ZWlyYSBlIHByb2dyYW1hw6fDo28gbGluZWFyIGludGVpcmEgbWlzdGEgZXNjcml0b3Mgbm8gZm9ybWF0byBDUExFWCwgcG9yIGV4ZW1wbG8uCgoqICoqUmVzb2x2ZW5kbyBwcm9ibGVtYXMgZGUgcHJvZ3JhbWHDp2HDtSBsaW5lYXIgdXNhbmRvIG8gcGFjb3RlIGBscFNvbHZlYDoqKgoKMS4gQ29uc2lkZXJlIG8gZXhlbXBsbyBhcHJlc2VudGFkbyBhbnRlcmlvcm1lbnRlLCBhYmFpeG8gdGVtb3MgYSBzb2x1w6fDo28gZG8gcHJvYmxlbWEgZGUgcHJvZ3JhbWHDp8OjbyBsaW5lYXIgbm8gUi4KCmBgYHtyfQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIyMjICAgICBQQUNPVEVTICAgICAjIyMjIwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKIyBJbnN0YWxhciBwYWNvdGVzIG5lY2Vzc8OhcmlvcyBwYXJhIG8gcmVzdGFudGUgZG8gZG9jdW1lbnRvCiNpbnN0YWxsLnBhY2thZ2VzKGMoImxwU29sdmUiLCJscFNvbHZlQVBJIiwgImdncGxvdDIiLCJwbG90bHkiKSkKCiMgQ2FycmVnYXIgcGFjb3RlcyBuZWNlc3PDoXJpb3MgcGFyYSBvIHJlc3RhbnRlIGRvIGRvY3VtZW50bwpzdXBwcmVzc01lc3NhZ2VzKHJlcXVpcmUobHBTb2x2ZSkpCnN1cHByZXNzTWVzc2FnZXMocmVxdWlyZShscFNvbHZlQVBJKSkKc3VwcHJlc3NNZXNzYWdlcyhyZXF1aXJlKGdncGxvdDIpKQpzdXBwcmVzc01lc3NhZ2VzKHJlcXVpcmUocGxvdGx5KSkKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMjIyMgICAgIFBST0JNRUxBICAgICMjIyMjCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgojIGNvZWZpY2llbnRlcyBkZSBQMSBlIFAyIG5hIGZ1bsOnw6NvIG9iamV0aXZvIApmdW5jLm9iamV0aXZvIDwtIGMoMjAgLCA2MCkKCiMgY29lZmljaWVudGVzIGRlIFAxIGUgUDIgbmFzIHJlc3RyacOnw7Vlcy4gU2VtcHJlIGVtIG1hdHJpeiBjb21vIG1vc3RyYWRvIG5vIHRleHRvIGFjaW1hCmNvZWZpY2llbnRlcy5yZXN0cmljb2VzIDwtIG1hdHJpeCAoYygzMCwgMjAsIDUsIDEwLCAxLCAxKSwgbmNvbCA9IDIgLCBieXJvdyA9IFRSVUUpCgojIHNpbmFsIGRhcyByZXN0cmnDp8O1ZXMuIERldmUgb2JlZGVjZXIgYSBvcmRlbSBkYSBtYXRyaXogZGUgY29lZmljaWVudGVzCmRpcmVjYW8ucmVzdHJpY29lcyA8LSBjKCI8PSIsIjw9IiwiPj0iKQoKIyBsaW1pdGUgZGFzIHJlc3RyacOnw7Vlcy4gRGV2ZSBvYmVkZWNlciBhIG9yZGVtIGRhIG1hdHJpeiBkZSBjb2VmaWNpZW50ZXMKbGltaXRlcy5yZXN0cmljb2VzIDwtIGMoMjcwMCwgODUwLCA5NSkKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMjIyMgICAgIFNPTFXDh8ODTyAgICAgIyMjIyMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCiMgQmFzaWNhbWVudGUsIHVzYW1vcyBhIGZ1bsOnw6NvIGxwIGRvIHBhY290ZSBscFNvbHZlIGNvbSBvcyBzZWd1aW50ZXMgcGFyw6JtZXRyb3M6CiMgZGlyZWN0aW9uOiBxdWUgcmVjZWJlIG1heCBvdSBtaW4gZGVwZW5kZW5kbyBzZSBvIHByb2JsZW1hIMOpIGRlIG1heGltaXphw6fDo28gb3UgbWluaXphw6fDo28sIHJlc3BlY3RpdmFtZW50ZQojIG9iamVjdGl2ZS5pbjogcXVlIHJlY2ViZSBvIG5vbWUgZG8gdmV0b3IgY29tIHBhcsOibWV0cm9zIGRhIGZ1bsOnw6NvIG9iamV0aXZvCiMgY29uc3QubWF0OiBxdWUgcmVjZWJlIG8gbm9tZSBkYSBtYXRyaXogY29tIGNvZWZpY2llbnRlcyBkYXMgcmVzdHJpw6fDtWVzCiMgY29uc3QucmhzOiBxdWUgcmVjZWJlIG8gbm9tZSBkbyB2ZXRvciBjb20gb3MgbGltaXRlcyBkYXMgcmVzdHJpw6fDtWVzCiMgbWFpcyBvcMOnw7VlcyBkYSBmdW7Dp8OjbyBwb2RlbSBzZXIgb2J0aWRhcyBwb3IgbWVpbyBkbyBoZWxwKGxwKQoKc29sdWNhby5wcm9ibGVtYSA8LSBscFNvbHZlOjpscChkaXJlY3Rpb24gPSAibWF4IiwgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvYmplY3RpdmUuaW4gPSBmdW5jLm9iamV0aXZvLCAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdC5tYXQgPSBjb2VmaWNpZW50ZXMucmVzdHJpY29lcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0LmRpciA9IGRpcmVjYW8ucmVzdHJpY29lcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0LnJocyA9IGxpbWl0ZXMucmVzdHJpY29lcykKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMjIyMgICAgUkVTVUxUQURPICAgICMjIyMjCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgojIHZhbG9yIGRhIGZ1bsOnw6NvIG9iamV0aXZvIG5hIHNvbHXDp8Ojbwpzb2x1Y2FvLnByb2JsZW1hJG9ianZhbAoKIyBWYWxvcmVzIHBhcmEgYXMgdmFyacOhdmVpcyBkZSBlc2NvbGhhIHF1ZSBnZXJhbSBtw6F4aW1vIG91IG3DrW5pbW8gZGVwZW5kZW5kbyBkbyBwcm9ibGVtYQpzb2x1Y2FvLnByb2JsZW1hJHNvbHV0aW9uCmBgYAoKMi4gQ29uc2lkZXJlIG8gc2VndWludGUgcHJvYmxlbWEgZGUgbWluaW1pemHDp8OjbzoKCiQkClxiZWdpbnthbGlnbmVkfQomIFx0ZXh0e01JTn0KJiAmIHogPSAtM3hfezF9LTR4X3syfS0zeF97M30gXFwKJiBcdGV4dHtzLmEufQomICYgNnhfezF9KzJ4X3syfSs0eF97M31cbGVxIDE1MCBcXAomJiYgeF97MX0reF97Mn0rNnhfezN9XGdlcSAwIFxcCiYmJiA0eF97MX0rNXhfezJ9KzR4X3szfT0gNDAgXFwKJiYmIHhfezF9IFxnZXEgMCBcXAomJiYgeF97Mn0gXGdlcSAwIFxcCiYmJiB4X3szfSBcZ2VxIDAgXFwKXGVuZHthbGlnbmVkfQokJAoKCmBgYHtyfQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIyMjICAgICBQUk9CTUVMQSAgICAjIyMjIwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKIyBjb2VmaWNpZW50ZXMgZGUgWDEsIFgyIGUgWDMgbmEgZnVuw6fDo28gb2JqZXRpdm8gCmZ1bmMub2JqZXRpdm8ucHJvYjIgPC0gYygtMyAsIC00LCAtMykKCiMgY29lZmljaWVudGVzIGRlIFgxLCBYMiBlIFgzIG5hcyByZXN0cmnDp8O1ZXMuIApjb2VmaWNpZW50ZXMucmVzdHJpY29lcy5wcm9iMiA8LSBtYXRyaXggKGMoNiwgMiwgNCwgMSwgMSwgNiwgNCwgNSwgNCksIG5jb2wgPSAzICwgYnlyb3cgPSBUUlVFKQoKIyBzaW5hbCBkYXMgcmVzdHJpw6fDtWVzLiBEZXZlIG9iZWRlY2VyIGEgb3JkZW0gZGEgbWF0cml6IGRlIGNvZWZpY2llbnRlcwpkaXJlY2FvLnJlc3RyaWNvZXMucHJvYjIgPC0gYygiPD0iLCI+PSIsIj0iKQoKIyBsaW1pdGUgZGFzIHJlc3RyacOnw7Vlcy4gRGV2ZSBvYmVkZWNlciBhIG9yZGVtIGRhIG1hdHJpeiBkZSBjb2VmaWNpZW50ZXMKbGltaXRlcy5yZXN0cmljb2VzLnByb2IyIDwtIGMoMTUwLCAwLCA0MCkKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMjIyMgICAgIFNPTFXDh8ODTyAgICAgIyMjIyMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCnNvbHVjYW8ucHJvYmxlbWEyIDwtIGxwU29sdmU6OmxwKGRpcmVjdGlvbiA9ICJtaW4iLCAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9iamVjdGl2ZS5pbiA9IGZ1bmMub2JqZXRpdm8ucHJvYjIsICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0Lm1hdCA9IGNvZWZpY2llbnRlcy5yZXN0cmljb2VzLnByb2IyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QuZGlyID0gZGlyZWNhby5yZXN0cmljb2VzLnByb2IyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QucmhzID0gbGltaXRlcy5yZXN0cmljb2VzLnByb2IyKQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyMjIyAgICBSRVNVTFRBRE8gICAgIyMjIyMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCiMgdmFsb3IgZGEgZnVuw6fDo28gb2JqZXRpdm8gbmEgc29sdcOnw6NvCnNvbHVjYW8ucHJvYmxlbWEyJG9ianZhbAoKIyBWYWxvcmVzIHBhcmEgYXMgdmFyacOhdmVpcyBkZSBlc2NvbGhhIHF1ZSBnZXJhbSBtw6F4aW1vIG91IG3DrW5pbW8gZGVwZW5kZW5kbyBkbyBwcm9ibGVtYQpzb2x1Y2FvLnByb2JsZW1hMiRzb2x1dGlvbgpgYGAKCjMuIFVtYSBDb21wYW5oaWEgYcOpcmVhIGVzdMOhIGFjcmVzY2VudGFuZG8gbWFpcyB2w7RvcyBkZS9wYXJhIHNldSBhZXJvcG9ydG8gY2VudHJhbCBlLCBwYXJhIHRhbnRvLCBwcmVjaXNhIGNvbnRyYXRhciBtYWlzIGFnZW50ZXMgcGFyYSBvIGF0ZW5kaW1lbnRvIGFvIHDDumJsaWNvLiBFbnRyZXRhbnRvLCBuw6NvIGVzdMOhIGNsYXJvIHF1YW50YXMgcGVzc29hcyBlbGVzIGRldmVtIGNvbnRyYXRhci4gQSBnZXLDqm5jaWEgcmVjb25oZWNlIGEgbmVjZXNzaWRhZGUgZGUgY29udHJvbGUgZGUgY3VzdG9zLCBlbWJvcmEgbWFudGVuZG8sIGFvIG1lc21vIHRlbXBvLCB1bSBuw612ZWwgZGUgc2VydmnDp29zIHNhdGlzZmF0w7NyaW8gYSBzZXVzIGNsaWVudGVzLiAKClBhcmEgaXNzbywgdW1hIGVxdWlwZSBlc3TDoSBlc3R1ZGFuZG8gY29tbyBwcm9ncmFtYXIgYXMgZXNjYWxhcyBkZXNzZXMgYWdlbnRlcyBwYXJhIGZvcm5lY2VyIGJvbnMgc2VydmnDp29zIGFvcyBjbGllbnRlcyBjb20gbyBtZW5vciBjdXN0byBwb3Nzw612ZWwgZW0gdGVybW9zIGRlIHBlc3NvYWwuCgpUb21hbmRvIGNvbW8gYmFzZSBhIG5vdmEgZXNjYWxhIGRlIHbDtG9zLCBmb2kgcmVhbGl6YWRhIHVtYSBhbsOhbGlzZSBkbyBuw7ptZXJvIG3DrW5pbW8gZGUgYWdlbnRlcyBkZSBhdGVuZGltZW50byBhbyBjbGllbnRlIHF1ZSBwcmVjaXNhdmFtIGVzdGFyIGRlIHNlcnZpw6dvIGVtIGRpZmVyZW50ZXMgaG9yYXMgZG8gZGlhIHBhcmEgZm9ybmVjZXIgdW0gbsOtdmVsIGRlIHNlcnZpw6dvIHNhdGlzZmF0w7NyaW8uIEEgY29sdW5hIG1haXMgw6AgZGlyZWl0YSBkYSB0YWJlbGEgYWJhaXhvIG1vc3RyYSBvIG7Dum1lcm8gZGUgYWdlbnRlcyBuZWNlc3PDoXJpb3MgcGFyYSBvcyBwZXLDrW9kb3MgZGFkb3MgbmEgcHJpbWVpcmEgY29sdW5hLiBPcyBkZW1haXMgY2FtcG9zIGRlc3NhIHRhYmVsYSByZWZsZXRlbSB1bWEgZGFzIGNsw6F1c3VsYXMgbm8gY29udHJhdG8gYXR1YWwgZGEgZW1wcmVzYSBjb20gbyBzaW5kaWNhdG8gcXVlIHJlcHJlc2VudGEgb3MgYWdlbnRlcyBkZSBhdGVuZGltZW50byBhbyBjbGllbnRlLiBFc3NhIGNsw6F1c3VsYSBkaXogcXVlIGNhZGEgYWdlbnRlIHRyYWJhbGhhIGNpbmNvIGRpYXMgcG9yIHNlbWFuYSBlbSB0dXJub3MgZGUgb2l0byBob3JhcyBlIG9zIHR1cm5vcyBhdXRvcml6YWRvcyBzw6NvOgoKICAgKiBUdXJubyAxOiA2aC0xNGgKICAgKiBUdXJubyAyOiA4aC0xNmgKICAgKiBUdXJubyAzOiAxMmgtMjBoCiAgICogVHVybm8gNDogMTZoLTAwaAogICAqIFR1cm5vIDU6IDIyaC02aAoKYGBge3IsIGZpZy5hbGlnbj0nY2VudGVyJywgZWNobz1GQUxTRX0Kc3VwcHJlc3NNZXNzYWdlcyhyZXF1aXJlKGh0bWx0b29scykpCmh0bWx0b29sczo6aW5jbHVkZUhUTUwoInRhYmxlLmh0bWwiKQpgYGAKCkFzIG1hcmNhcyBkZSB2ZXJpZmljYcOnw6NvICh4KSBubyBjb3JwbyBkYSB0YWJlbGEgaW5kaWNhbSBvcyBob3LDoXJpb3MgY29iZXJ0b3MgcGVsb3MgcmVzcGVjdGl2b3MgdHVybm9zLiBQZWxvIGZhdG8gZGUgYWxndW5zIHR1cm5vcyBzZXJlbSBtZW5vcyBkZXNlamFkb3MgZG8gcXVlIG91dHJvcywgb3Mgc2Fsw6FyaW9zIGVzcGVjaWZpY2Fkb3Mgbm8gY29udHJhdG8gZGlmZXJlbSBjb25mb3JtZSBvIHR1cm5vLiBQYXJhIGNhZCB0dXJubywgbyBwYWdhbWVudG8gZGnDoXJpbyAoaW5jbHVpbmRvIGJlbmVmw61jaW9zKSBwYXJhIGNhZGEgYWdlbnRlIMOpIG1vc3RyYWRvIG5hIHVsdGltYSBsaW5oYSBkYSB0YWJlbGEuIE8gcHJvYmxlbWEgw6kgZGV0ZXJtaW5hciBxdWFudG9zIGFnZW50ZXMgZGV2ZW0gc2VyIGFsb2NhZG9zIHBhcmEgb3MgcmVzcGVjdGl2b3MgdHVybm9zIGRpw6FyaW9zIGEgZmltIGRlIG1pbmltaXphciBvIGN1c3RvIHRvdGFsIGNvbSBwZXNzb2FsIChhZ2VudGVzKSB0b21hbmRvIGNvbW8gYmFzZSBhIMO6bHRpbWEgbGluaGEgZGEgdGFiZWxhIGUsIGFvIG1lc21vIHRlbXBvLCBhdGVuZGVuZG8gKG91IHVsdHJhcGFzc2FuZG8pIGFzIGV4aWfDqm5jaWFzIGRlIG7DrXZlbCBkZSBzZXJ2acOnbyBkYWRhcyBuYSBjb2x1bmEgbWFpcyDDoCBkaXJlaXRhLgoKUGVsbyBmYXRvIGRlIGEgZnVuw6fDo28gb2JqZXRpdm8gbWluaW1pemFyIG8gY3VzdG8gdG90YWwgZG9zIGFlbnRlcyBhdHJpYnXDrWRvcyBhb3MgY2luY28gdHVybm9zLCBvcyBjb2VmaWNpZW50ZXMgbmEgZnVuw6ddYW8gb2JqZXRpdm8gc8OjbyBkYWRvcyBwZWxhIMO6bHRpbWEgbGluaGEgZGEgdGFiZWxhLiBQb3J0YW50bywgbyBwcm9ibGVtYSBkZSBwcm9ncmFtYcOnw6NvIGxpbmVhciBjb21wbGV0byDDqToKCiQkClxiZWdpbnthbGlnbmVkfQomIFx0ZXh0e01JTn0KJiAmIHogPSAxNzB4X3sxfSsxNjB4X3syfSsxNzV4X3szfSsxODB4X3s0fSsxOTV4X3s1fSBcXAomIFx0ZXh0e3MuYS59CiYgJiB4X3sxfVxnZXEgNDggICYmIFx0ZXh0eyg2aC04aCl9IFxcCiYmJiB4X3sxfSt4X3syfVxnZXEgNzkgJiYgXHRleHR7KDhoLTEwaCl9IFxcCiYmJiB4X3sxfSt4X3syfVxnZXEgNjUgJiYgXHRleHR7KDEwaC0xMmgpfSBcXAomJiYgeF97MX0reF97Mn0reF97M30gXGdlcSA4NyAmJiBcdGV4dHsoMTJoLTE0aCl9IFxcCiYmJiB4X3syfSt4X3szfSBcZ2VxIDY0ICYmIFx0ZXh0eygxNGgtMTZoKX0gXFwKJiYmIHhfezN9K3hfezR9IFxnZXEgNzMgJiYgXHRleHR7KDE2aC0xOGgpfSBcXAomJiYgeF97M30reF97NH0gXGdlcSA4MiAmJiBcdGV4dHsoMThoLTIwaCl9IFxcCiYmJiB4X3s0fSBcZ2VxIDQzICYmIFx0ZXh0eygyMGgtMjJoKX0gXFwKJiYmIHhfezR9K3hfezV9IFxnZXEgNTIgJiYgXHRleHR7KDIyaC0wMGgpfSBcXAomJiYgeF97NX0gXGdlcSAxNSAmJiBcdGV4dHsoMDBoLTZoKX0gXFwKJiYmIHhfe2p9IFxnZXEgMCAmJiBcdGV4dHtwYXJhIGo9MSwyLDMsNCw1fSBcXApcZW5ke2FsaWduZWR9CiQkCkNvbSB1bSBvbGhhciBhZ3XDp2Fkbywgdm9jw6ogcHJvdmF2ZWxtZW50ZSBkZXZlIHRlciBwZXJjZWJpZG8gcXVlIGEgdGVyY2VpcmEgcmVzdHJpw6fDo28sICR4X3sxfSt4X3syfVxnZXEgNjUkLCBuYSB2ZXJkYWRlIG7Do28gw6kgbmVjZXNzw6FyaWEsIHBvaXMgYSBzZWd1bmRhIHJlc3RyacOnw6NvICR4X3sxfSt4X3syfVxnZXEgNzkkLCBnYXJhbnRlIHF1ZSAkeF97MX0reF97Mn0kIHNlcsOhIG1haW9yIHF1ZSA2NS4gUG9ydGFudG8sICR4X3sxfSt4X3syfVxnZXEgNjUkIMOpIHVtYSAqKnJlc3RyacOnw6NvIHJlZHVuZGFudGUqKiBxdWUgcG9kZSBzZXIgZWxpbWluYWRhLgoKRGEgbWVzbWEgZm9ybWEsIGEgc2V4dGEgcmVzdHJpw6fDo28gJHhfezN9K3hfezR9IFxnZXEgNyQsIHRhbWLDqW0gw6kgcmVkdW5kYW50ZSBwb3JxdWUgYSBzw6l0aW1hIHJlc3RyacOnw6NvIMOpICR4X3szfSt4X3s0fSBcZ2VxIDgyJC4gTmEgcmVhbGlkYWRlLCB0csOqcyBkYXMgcmVzdHJpw6fDtWVzIGRlIG7Do28tbmVnYXRpdmlkYWRlIHRhbWLDqW0gc8OjbyByZWR1bmRhbnRlcyBlbSByYXrDo28gZGEgcHJpbWVpcmEsIG9pdGF2YSBlIGTDqWNpbWEgcmVzdHJpw6fDtWVzIGZ1bmNpb25haXM6ICR4X3sxfVxnZXEgNDgkLCAkeF97NH0gXGdlcSA0MyQgZSAkeF97NX0gXGdlcSAxNSQuIEVudHJldGFudG8sIG7Do28gc2UgZ2FuaGEgbmVuaHVtYSB2YW50YWdlbSBlbSB0ZXJtb3MgY29tcHV0YWNpb25haXMgZWxpbWluYW5kby1zZSBlc3NhcyB0csOqcyByZXN0cmnDp8O1ZXMgZGUgbsOjby1uZWdhdGl2aWRhZGUuCgpgYGB7cn0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyMjIyAgICAgUFJPQk1FTEEgICAgIyMjIyMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCiMgY29lZmljaWVudGVzIGRlIFgxLCBYMiBlIFgzIG5hIGZ1bsOnw6NvIG9iamV0aXZvIApmdW5jLm9iamV0aXZvLnByb2IzIDwtIGMoMTcwLCAxNjAsIDE3NSwgMTgwLCAxOTUpCgojIGNvZWZpY2llbnRlcyBkZSBYMSwgWDIgZSBYMyBuYXMgcmVzdHJpw6fDtWVzLiAKY29lZmljaWVudGVzLnJlc3RyaWNvZXMucHJvYjMgPC0gbWF0cml4IChjKDEsIDAsIDAsIDAsIDAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAxLCAxLCAwLCAwLCAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAxLCAxLCAxLCAwLCAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAwLCAxLCAxLCAwLCAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAwLCAwLCAxLCAxLCAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAwLCAwLCAwLCAxLCAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAwLCAwLCAwLCAxLCAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAwLCAwLCAwLCAwLCAxKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuY29sID0gNSAsIGJ5cm93ID0gVFJVRSkKCiMgc2luYWwgZGFzIHJlc3RyacOnw7Vlcy4gRGV2ZSBvYmVkZWNlciBhIG9yZGVtIGRhIG1hdHJpeiBkZSBjb2VmaWNpZW50ZXMKZGlyZWNhby5yZXN0cmljb2VzLnByb2IzIDwtIGMoIj49IiwiPj0iLCI+PSIsIj49IiwiPj0iLCI+PSIsIj49IiwiPj0iKQoKIyBsaW1pdGUgZGFzIHJlc3RyacOnw7Vlcy4gRGV2ZSBvYmVkZWNlciBhIG9yZGVtIGRhIG1hdHJpeiBkZSBjb2VmaWNpZW50ZXMKbGltaXRlcy5yZXN0cmljb2VzLnByb2IzIDwtIGMoNDgsIDc5LCA4NywgNjQsIDgyLCA0MywgNTIsIDE1KQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyMjIyAgICAgU09MVcOHw4NPICAgICAjIyMjIwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKc29sdWNhby5wcm9ibGVtYTMgPC0gbHBTb2x2ZTo6bHAoZGlyZWN0aW9uID0gIm1pbiIsICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2JqZWN0aXZlLmluID0gZnVuYy5vYmpldGl2by5wcm9iMywgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QubWF0ID0gY29lZmljaWVudGVzLnJlc3RyaWNvZXMucHJvYjMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdC5kaXIgPSBkaXJlY2FvLnJlc3RyaWNvZXMucHJvYjMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdC5yaHMgPSBsaW1pdGVzLnJlc3RyaWNvZXMucHJvYjMpCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIyMjICAgIFJFU1VMVEFETyAgICAjIyMjIwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKIyB2YWxvciBkYSBmdW7Dp8OjbyBvYmpldGl2byBuYSBzb2x1w6fDo28Kc29sdWNhby5wcm9ibGVtYTMkb2JqdmFsCgojIFZhbG9yZXMgcGFyYSBhcyB2YXJpw6F2ZWlzIGRlIGVzY29saGEgcXVlIGdlcmFtIG3DoXhpbW8gb3UgbcOtbmltbyBkZXBlbmRlbmRvIGRvIHByb2JsZW1hCnNvbHVjYW8ucHJvYmxlbWEzJHNvbHV0aW9uCmBgYAoKQSBzb2x1w6fDo28gw7N0aW1hIHBhcmEgZXNzZSBtb2RlbG8gw6kgJCh4X3sxfSx4X3syfSx4X3szfSx4X3s0fSx4X3s1fSk9KDQ4LDMxLDM5LDQzLDE1KSQuIElzc28gZmF6IGNvbSBxdWUgJFo9MzAuNjEwJCwgaXN0byDDqSwgdW0gY3VzdG8gZGnDoXJpbyB0b3RhbCBjb20gcGVzc29hbCBkZSBVJDMwLjYxMC4KCk8gbsO6bWVybyBkZSBhZ2VudGVzIGFsb2NhZG9zIHBhcmEgY2FkYSB0dXJubyBwcmVjaXNhIHNlciB1bSBpbnRlaXJvLiBSaWdvcm9zYW1lbnRlIGZhbGFuZG8sIG8gbW9kZWxvIGRldmVyaWEgdGVyIHVtYSByZXN0cmnDp8OjbyBhZGljaW9uYWwgcGFyYSBjYWRhIHZhcmnDoXZlbCBkZSBkZWNpc8OjbyBlc3BlY2lmaWNhbmRvIHF1ZSBhIHZhcmnDoXZlbCBkZXZlIHRlciB1bSB2YWxvciBpbnRlaXJvLiBBY3Jlc2NlbnRhciBlc3NhcyByZXN0cmnDp8O1ZXMgdHJhbnNmb3JtYXJpYSBvIG1vZGVsbyBkZSBwcm9ncmFtYcOnw6NvIGxpbmVhciBlbSB1bSBtb2RlbG8gZGUgcHJvZ3JhbWHDp8OjbyBpbnRlaXJhLiAKCiogKipSZXNvbHZlbmRvIHByb2JsZW1hcyBkZSBwcm9ncmFtYcOnw6NvIGxpbmVhciB1c2FuZG8gbyBwYWNvdGUgYGxwU29sdmVBUElgOioqCgpDb25zaWRlcmUgcXVlIHRlbW9zIG8gc2VndWludGUgcHJvYmxlbWEgZGUgcHJvZ3JhbWHDp8OjbyBsaW5lYXI6CgokJApcYmVnaW57YWxpZ25lZH0KJiBcdGV4dHtNSU59CiYgJiB6ID0geF97MX0rM3hfezJ9KzYuMjR4X3szfSswLjF4X3s0fSBcXAomIFx0ZXh0e3MuYS59CiYgJiA3OC4yNnhfezJ9KzIuOXhfezR9XGdlcSA5Mi4zIFxcCiYmJiAwLjI0eF97MX0rMTEuMzF4X3szfVxsZXEgMTQuOCBcXAomJiYgMTIuNjh4X3sxfSswLjA4eF97M30rMC45eF97NH0gXGdlcSA0ClxlbmR7YWxpZ25lZH0KJCQKb25kZSAkeF8xJCDDqSB1bWEgdmFyacOhdmVsIGNvbSB2YWxvciBtw61uaW1vIGRlICQyOC42JCwgJHhfMiQgw6kgdW1hIHZhcmnDoXZlbCBuw6NvLW5lZ2F0aXZhIGUgaW50ZWlyYSwgJHhfMyQgw6kgdW1hIHZhcmnDoXZlbCBiaW7DoXJpYSBlICR4XzQkIMOpIHVtYSB2YXJpw6F2ZWwgbGltaXRhZGEgYW8gaW50ZXJ2YWxvICRbMTgsNDguOThdJC4gQXNzaW0sIHBvciBtZWlvIGRvIHBhY290ZSBgbHBzb2x2ZUFQSWAsIHRlbW9zIGEgc2VndWludGUgc29sdcOnw6NvOgpgYGB7ciwgZWNobz1UUlVFLCB3YXJuaW5nPUZBTFNFfQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIyMjICAgICBQUk9CTUVMQSAgICAjIyMjIwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKIyBQcmltZWlybywgY3JpYW1vcyBvIHByb2JsZW1hIGNvbSAzIHJlc3RyacOnw7VlcyBlIDQgdmFyacOhdmVpcy4gT2JzZXJ2ZQojIHF1ZSBhYmFpeG8gc2VtcHJlIHVzYXJlbW9zICJscHJlYyIgcGFyYSBkaXplciBxdWUgZXN0YW1vcyBhZGljaW9uYW5kbwojIGRlZmluacOnw7VlcyBhbyBwcm9ibGVtYQpscHJlYyA8LSBscFNvbHZlQVBJOjptYWtlLmxwKDMsNCkKCiMgRGVwb2lzLCBkZWZpbmltb3Mgb3MgdmFsb3JlcyBkYSBwcmltZWlyYSBjb2x1bmEgZGEgbWF0cml6IGRlIHJlc3RyacOnw7VlczoKIyAtIDE6IGluZGljYSBhIHByaW1laXJhIGNvbHVuYQojIC0gYygwLCAwLjI0LCAxMi42OCk6IG9zIGNvZWZpY2llbnRlcyBkZSB4MSBuYXMgcmVzdHJpw6fDtWVzCmxwU29sdmVBUEk6OnNldC5jb2x1bW4obHByZWMsIDEsIGMoMCwgMC4yNCwgMTIuNjgpKQoKIyBGYXplbW9zIG8gbWVzbW8gcGFyYSBhcyBkZW1haXMgdmFyacOhdmVpcyAoY29sdW5hcykuIEFxdWksIHVzYW1vcwojIGEgb3DDp8OjbyBpbmRpY2VzIHF1ZSB2YWkgZGl6ZXIgZW0gcXVhbCBwb3Npw6fDo28gZGEgY29sdW5hIGjDoSB2YWxvciwgCiMgcG9pcyBlbSBhbGd1bnMgY2Fzb3MgcG9kZW1vcyBuw6NvIHRlciBuYXMgcmVzdHJpw6fDtWVzIHZhbG9yZXMgcGFyYQojIG91dHJhcyB2YXJpw6F2ZWlzCmxwU29sdmVBUEk6OnNldC5jb2x1bW4obHByZWMsIDIsIDc4LjI2LCBpbmRpY2VzID0gMSkKbHBTb2x2ZUFQSTo6c2V0LmNvbHVtbihscHJlYywgMywgYygxMS4zMSwgMC4wOCksIGluZGljZXMgPSAyOjMpCmxwU29sdmVBUEk6OnNldC5jb2x1bW4obHByZWMsIDQsIGMoMi45LCAwLjkpLCBpbmRpY2VzID0gYygxLDMpKQoKIyBBZ29yYSwgZGVmaW5pbW9zIGEgZnVuw6fDo28gb2JqZXRpdm8KbHBTb2x2ZUFQSTo6c2V0Lm9iamZuKGxwcmVjLCBjKDEsMywgNi4yNCwgMC4xKSkKCiMgVGlwb3MgZGUgcmVzdHJpw6fDtWVzCmxwU29sdmVBUEk6OnNldC5jb25zdHIudHlwZShscHJlYywgYygiPj0iLCAiPD0iLCAiPj0iKSkKCiMgTGltaXRlIGRhcyByZXN0cmnDp8O1ZXMKbHBTb2x2ZUFQSTo6c2V0LnJocyhscHJlYywgYyg5Mi4zLCAxNC44LCA0KSkKCiMgUG9yIGRlZmF1bHQsIHRvZGFzIGFzIHZhcmnDoXZlaXMgc8OjbyBjcmlhZGFzIGNvbW8gdW0gdmFsb3IgcmVhbCBubyAKIyBpbnRlcnZhbG8gWzAsIGluZmluaXRvXS4gQXNzaW0sIGRldmVtb3MgbXVkYXIgaXNzbyBjYXNvIG8gcHJvYmxlbWEKIyBkZW1hbmRlLiBObyBub3NzbyBleGVtcGxvLCB0ZW1vczoKIyAtIHgyOiBpbnRlaXJvCiMgLSB4MzogYmluw6FyaW8KbHBTb2x2ZUFQSTo6c2V0LnR5cGUobHByZWMsIDIsICJpbnRlZ2VyIikKbHBTb2x2ZUFQSTo6c2V0LnR5cGUobHByZWMsIDMsICJiaW5hcnkiKQoKIyBEZWZpbmlyIG8gaW50ZXJ2YWxvIHBhcmEgYXMgdmFyacOhdmVpcyB4MSBlIHg0CiMgLSB4MTogdmFsb3IgbcOtbmltbyBkZSAyOC42IChwcmltZWlyYSBjb2x1bmEpCiMgLSB4NDogdmFsb3IgbcOtbmltbyBkZSAxOCBlIG3DoXhpbW8gZGUgNDguOTggKHF1YXJ0YSBjb2x1bmEpCmxwU29sdmVBUEk6OnNldC5ib3VuZHMobHByZWMsIGxvd2VyID0gYygyOC42LCAxOCksIGNvbHVtbnMgPSBjKDEsIDQpKQpscFNvbHZlQVBJOjpzZXQuYm91bmRzKGxwcmVjLCB1cHBlciA9IDQ4Ljk4LCBjb2x1bW5zID0gNCkKCiMgRmluYWxtZW50ZSwgcG9kZW1vcyByZW5vbWVhciBhcyB2YXJpw6F2ZWlzIGRvIHByb2JsZW1hClJvd05hbWVzIDwtIGMoIlJPV09ORSIsIlJPV1RXTyIsICJST1dUSFJFRSIpCkNvbE5hbWVzIDwtIGMoIkNPTE9ORSIsIkNPTFRXTyIsICJDT0xUSFJFRSIsICJDT0xURk9VUiIpCmRpbW5hbWVzKGxwcmVjKSA8LSBsaXN0KFJvd05hbWVzLCBDb2xOYW1lcykKCiMgRGVmaW5pciBzZSDDqSB1bSBwcm9ibGVtYSBkZSBtYXhpbWl6YcOnw6NvIG91IG1pbmltaXphw6fDo28KIyBTZSBtYXhpbWl6YcOnw6NvIHNlbnNlID0gYygibWF4IikuIFVzZSBoZWxwKGxwLmNvbnRyb2wub3B0aW9ucykKIyBwYXJhIHZpc3VhbGl6YXIgdG9kYXMgYXMgb3DDp8O1ZXMgcXVlIHBvZGVtIHNlciBhbHRlcmFkYXMgZW0KIyB1bSBwcm9ibGVtYSBkZSBvdGltaXphw6fDo28gdXNhbmRvIGVzdGUgcGFjb3RlLgptaW5pbWl6YXIgPC0gbHBTb2x2ZUFQSTo6bHAuY29udHJvbChscHJlYywgc2Vuc2UgPSBjKCJtaW4iKSkKCiMgVmlzdWFsaXphciBvIHByb2JsZW1hIGRlZmluaWRvIGVtIHVtIGZvcm1hdG8gcXVlIHNlamEgZsOhY2lsCiMgY29uZmVyaXIgc2UgZXN0w6EgdHVkbyBlbSBjb25mb3JtaWRhZGUgY29tIG8gcHJvYmxlbWEgYSBzZXIgCiMgcmVzb2x2aWRvCmxwcmVjCgpgYGAKCkFnb3JhLCBwb2RlbW9zIHNvbHVjaW9uYXIgbyBwcm9ibGVtYSBjb21vIHNlZ3VlOgoKYGBge3J9CiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMjIyMgICAgIFNPTFXDh8ODTyAgICAgIyMjIyMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCiMgU29sdWNpb25hciBvIHByb2JsZW1hIGRlZmluaWRvIGFudGVyaW9ybWVudGUgdXNhbmRvIGEgZnVuw6fDo28KIyBzb2x2ZS5scEV4dFB0ciBkbyBwYWNvdGUgbHBTb2x2ZUFQSS4gQXF1aSwgbyBzb2x2ZXIgYXBlbmFzCiMgaW5mb3JtYSBvIHN0YXR1cyBkYSBzb2x1w6fDo28sIGNvbW8gc2VndWU6CiMgMDoJICJvcHRpbWFsIHNvbHV0aW9uIGZvdW5kIgojIDE6CSAidGhlIG1vZGVsIGlzIHN1Yi1vcHRpbWFsIgojIDI6CSAidGhlIG1vZGVsIGlzIGluZmVhc2libGUiCiMgMzoJICJ0aGUgbW9kZWwgaXMgdW5ib3VuZGVkIgojIDQ6CSAidGhlIG1vZGVsIGlzIGRlZ2VuZXJhdGUiCiMgNToJICJudW1lcmljYWwgZmFpbHVyZSBlbmNvdW50ZXJlZCIKIyA2OgkgInByb2Nlc3MgYWJvcnRlZCIKIyA3OgkgInRpbWVvdXQiCiMgOToJICJ0aGUgbW9kZWwgd2FzIHNvbHZlZCBieSBwcmVzb2x2ZSIKIyAxMDoJICJ0aGUgYnJhbmNoIGFuZCBib3VuZCByb3V0aW5lIGZhaWxlZCIKIyAxMToJICJ0aGUgYnJhbmNoIGFuZCBib3VuZCB3YXMgc3RvcHBlZCBiZWNhdXNlIG9mIGEgYnJlYWstYXQtZmlyc3Qgb3IgYnJlYWstYXQtdmFsdWUiCiMgMTI6CSAiYSBmZWFzaWJsZSBicmFuY2ggYW5kIGJvdW5kIHNvbHV0aW9uIHdhcyBmb3VuZCIKIyAxMzoJICJubyBmZWFzaWJsZSBicmFuY2ggYW5kIGJvdW5kIHNvbHV0aW9uIHdhcyBmb3VuZCIKc29sdWNhby5wcm9ibGVtYTQgPC0gbHBTb2x2ZUFQSTo6c29sdmUubHBFeHRQdHIobHByZWMpCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIyMjICAgIFJFU1VMVEFETyAgICAjIyMjIwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKIyB2YWxvciBkYSBmdW7Dp8OjbyBvYmpldGl2byBuYSBzb2x1w6fDo28KbHBTb2x2ZUFQSTo6Z2V0Lm9iamVjdGl2ZShscHJlYykKCiMgVmFsb3JlcyBwYXJhIGFzIHZhcmnDoXZlaXMgZGUgZXNjb2xoYSBxdWUgZ2VyYW0gbcOheGltbyBvdSBtw61uaW1vIGRlcGVuZGVuZG8gZG8gcHJvYmxlbWEKbHBTb2x2ZUFQSTo6Z2V0LnZhcmlhYmxlcyhscHJlYykKYGBgCgojIyMjICoqUkVGRVLDik5DSUFTKioK