Este documento tem como objetivo apresentar conceitos de programação linear e como implementar tais problemas de otimização no R.
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:
- percorrer a região viável do problema no sentido do gradiente (aumentando continuamente o valor da função objetivo) até que a fronteira da região seja eventualmente atingida;
- o valor máximo da função-objetivo na região viável é dado pelo valor da reta que toca a fronteira, no caso \(z^{\ast}=12\). Qualquer ponto que pertenca à reta de valor \(z^{\ast}=12\) que também percente à fronteira é uma solução ótima do problema. No caso do exemplo, existe apenas uma solução ótima, \(x^{\ast}=(4,4)\).
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á:
- Encontrar a solução básica inicial
- Explorar as soluções básicas movendo na direção que maximiza ou minimiza a função objetivo
- Parar quando uma solução ótima é encontrada
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.
- Resolvendo problemas de programaçaõ linear usando o pacote
lpSolve:
- 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
- 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
- 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:
- Turno 1: 6h-14h
- Turno 2: 8h-16h
- Turno 3: 12h-20h
- Turno 4: 16h-00h
- Turno 5: 22h-6h
| 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.
- Resolvendo problemas de programação linear usando o pacote
lpSolveAPI:
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
LS0tCnRpdGxlOiA8Y2VudGVyPiA8aDI+IDxiPiBQcm9ncmFtYcOnw6NvIExpbmVhciA8L2I+IDwvaDI+IDwvY2VudGVyPiAKYXV0aG9yOiA8Y2VudGVyPiBIdWRzb24gQ2hhdmVzIENvc3RhIDwvY2VudGVyPgpncmFwaGljczogeWVzCmxpbmtjb2xvcjogYmx1ZQpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICB0aGVtZTogY2VydWxlYW4KICAgIGZpZ19jYXB0aW9uOiB5ZXMKcmVmZXJlbmNlczoKLSBpZDogc29ldGFlcnQyMDA4cHJhY3RpY2FsCiAgdGl0bGU6IEEgcHJhY3RpY2FsIGd1aWRlIHRvIGVjb2xvZ2ljYWwgbW9kZWxsaW5nIHVzaW5nIFIgYXMgYSBzaW11bGF0aW9uIHBsYXRmb3JtCiAgYXV0aG9yOgogIC0gZmFtaWx5OiBTb2V0YWVydAogICAgZ2l2ZW46IEthcmxpbmUKICAtIGZhbWlseTogSGVybWFuCiAgICBnaXZlbjogUGV0ZXIgTUoKICBwdWJsaXNoZXI6IFNwcmluZ2VyIFNjaWVuY2UgXCYgQnVzaW5lc3MgTWVkaWEKICB0eXBlOiBib29rCiAgaXNzdWVkOgogICAgeWVhcjogMjAwOAotIGlkOiBhbHBoYTIwMDRtYXRlbWF0aWNhCiAgdGl0bGU6IE1hdGVtw6F0aWNhIHBhcmEgZWNvbm9taXN0YXMKICBhdXRob3I6IAogIC0gZmFtaWx5OiBDaGlhbmcKICAgIGdpdmVuOiBBbHBoYSBDLgogIC0gZmFtaWx5OiBXYWlud3JpZ2h0CiAgICBnaXZlbjogS2V2aW4KICBwdWJsaXNoZXI6IEVsc2V2aWVyCiAgdHlwZTogYm9vawogIGlzc3VlZDoKICAgIHllYXI6IDIwMDYKLSBpZDogZGFudHppZzE5NTFtYXhpbWl6YXRpb24KICB0aXRsZTogTWF4aW1pemF0aW9uIG9mIGEgbGluZWFyIGZ1bmN0aW9uIG9mIHZhcmlhYmxlcyBzdWJqZWN0IHRvIGxpbmVhciBpbmVxdWFsaXRpZXMKICBhdXRob3I6IAogIC0gZmFtaWx5OiBEYW50emlnCiAgICBnaXZlbjogR2VvcmdlIEIKICBwdWJsaXNoZXI6IE5ldyBZb3JrCiAgdHlwZTogYXJ0aWNsZS1qb3VybmFsIAogIGlzc3VlZDoKICAgIHllYXI6IDE5NTEKLSBpZDogaGlsbGllcjIwMTNpbnRyb2R1Y2NhbwogIHRpdGxlOiBJbnRyb2R1w6fDo28gw6AgcGVzcXVpc2EgcGVzcXVpc2Egb3BlcmFjaW9uYWwKICBhdXRob3I6CiAgLSBmYW1pbHk6IEhpbGxpZXIKICAgIGdpdmVuOiBGcmVkZXJpY2sgUwogIC0gZmFtaWx5OiBMaWViZXJtYW4KICAgIGdpdmVuOiBHZXJhbGQgSgogIHB1Ymxpc2hlcjogTWNHcmF3IEhpbGwgQnJhc2lsCiAgdHlwZTogYm9vawogIGlzc3VlZDoKICAgIHllYXI6IDIwMTMKbm9jaXRlOiB8IAogIEBzb2V0YWVydDIwMDhwcmFjdGljYWwsIEBhbHBoYTIwMDRtYXRlbWF0aWNhLCBAZGFudHppZzE5NTFtYXhpbWl6YXRpb24sIEBoaWxsaWVyMjAxM2ludHJvZHVjY2FvCi0tLQoKRXN0ZSBkb2N1bWVudG8gdGVtIGNvbW8gb2JqZXRpdm8gYXByZXNlbnRhciBjb25jZWl0b3MgZGUgcHJvZ3JhbWHDp8OjbyBsaW5lYXIgZSBjb21vIGltcGxlbWVudGFyIHRhaXMgcHJvYmxlbWFzIGRlIG90aW1pemHDp8OjbyBubyBbUl0oaHR0cHM6Ly93d3cuci1wcm9qZWN0Lm9yZy8pLiAKCiMjIyMjICoqSU5UUk9EVcOHw4NPKioKClVtIHByb2JsZW1hIGdlcmFsIGRlIFByb2dyYW1hw6fDo28gTGluZWFyIMOpIHV0aWxpemFkbyBwYXJhIG90aW1pemFyIChtYXhpbWl6YXIgb3UgbWluaW1pemFyKSB1bWEgZnVuw6fDo28gbGluZWFyIGRlIHZhcmnDoXZlaXMsIGNoYW1hZGEgZGUgZnVuw6fDo28gb2JqZXRpdm8sIHN1amVpdGEgYSB1bWEgc8OpcmllIGRlIGVxdWHDp8O1ZXMgKG91IGluZXF1YcOnw7VlcykgbGluZWFyZXMsIGNoYW1hZGFzIHJlc3RyacOnw7Vlcy4gQXNzaW0sIHRlbW9zIHF1ZSBQcm9ncmFtYcOnw6NvIGxpbmVhciDDqSB1bSBjYXNvIGRlIHByb2dyYW1hw6fDo28gbWF0ZW3DoXRpY2Egb25kZSBhIGZ1bsOnw6NvIG9iamV0aXZvIGUgYXMgcmVzdHJpw6fDtWVzIHPDo28gdG9kYXMgbGluZWFyZXMuIAoKQWJhaXhvLCB1bSBleGVtcGxvIGRlIHByb2JsZW1hIGRlIHByb2dyYW1hw6fDo28gbGluZWFyOgoKJCQKXGJlZ2lue2FsaWduZWR9CiYgXHRleHR7TUFYfQomICYgeiA9IGNfezF9eF97MX0rY197Mn14X3syfSsuLi4rY197bn14X3tufSBcXAomIFx0ZXh0e3MuYS59CiYgJiBhX3sxMX14X3sxfSthX3sxMn14X3syfSsuLi4rYV97MW59eF97bn1cbGVxIGJfezF9IFxcCiYmJiBhX3syMX14X3sxfSthX3syMn14X3syfSsuLi4rYV97Mm59eF97bn1cbGVxIGJfezJ9IFxcCiYmJiBcbGRvdHMgXGxkb3RzIFxsZG90cyBcbGRvdHMgXGxkb3RzIFxsZG90cyBcbGRvdHMgXGxkb3RzIFxsZG90cyBcXAomJiYgYV97bTF9eF97MX0rYV97bTJ9eF97Mn0rLi4uK2Ffe21ufXhfe259XGxlcSBiX3ttfSBcXAomJiYgeF97an0gXGdlcSAwClxlbmR7YWxpZ25lZH0KJCQKTyBtb2RlbG8gdGVtIG9zIHNlZ3VpbnRlcyBlbGVtZW50b3M6CgogICogVW1hIGZ1bsOnw6NvIG9iamV0aXZvIGNvbSAkbiQgdmFyacOhdmVpcyBkZSBlc2NvbGhhIHF1ZSBzw6NvIGFmZXRhZGFzIHBvciBzZXVzIGNvZWZpY2llbnRlcywgJGNfe2p9JCwgcGFyYSAkaj0xLC4uLixuJC4KICAqIFVtIGNvbmp1bnRvIGRlICRtJCByZXN0cmnDp8O1ZXMgZW0gcXVlIHVtYSBjb21iaW5hw6fDo28gbGluZWFyIGRhcyB2YXJpw6F2ZWlzIGRlIGVzY29saGEgYWZldGFkYXMgcGVsb3MgY29lZmljaWVudGVzICRhX3tpan0kIGRldmVtIHNlciBtZW5vciBvdSBpZ3VhbCBhb3MgdmFsb3JlcyBkbyBsYWRvIGRpcmVpdG8gZGFzIGVxdWHDp8O1ZXMsICRiX3tpfSQgcGFyYSAkaT0xLC4uLm0kCiAgKiBMaW1pdGVzIGRhcyB2YXJpw6F2ZWlzIGRlIGVzY29saGEuIE5lc3RlIGNhc28sIHRvZGFzIHByZWNpc2FtIGFzc3VtaXIgdmFsb3JlcyBuw6NvIG5lZ2F0aXZvcyAoJHhfe2p9IFxnZXEgMCQpCgpBcyByZXN0cmnDp8O1ZXMgZGUgdW0gcHJvYmxlbWEgZGUgcHJvZ3JhbWHDp8OjbyBsaW5lYXIgZGVmaW5lbSBhIHJlZ2nDo28gdmnDoXZlbCwgcXVlIMOpIG8gY29uanVudG8gZGUgdmFsb3JlcyBxdWUgc2F0aXNmYXplbSB0b2RhcyBhcyByZXN0cmnDp8O1ZXMuIFRhaXMgcmVzdHJpw6fDtWVzIHRhbWLDqW0gcG9kZW0gdGVyIHNpbmFsIGRlICRcZ2VxJCBvdSAkPSQuIAoKT3V0cmEgbWFuZWlyYSB1c3VhbCBkZSBleHByZXNzYXIgbyBwcm9ibGVtYSBkZSBwcm9ncmFtYcOnw6NvIGxpbmVhciDDqSBubyBmb3JtYXRvIG1hdHJpY2lhbCwgY29tbyBzZWd1ZToKCiQkClxiZWdpbnthbGlnbmVkfQomIFx0ZXh0e01BWH0KJiAmIHogPSBjXntccHJpbWV9eCBcXAomIFx0ZXh0e3MuYS59CiYgJiBcYm9sZHN5bWJvbHtBfXggXGxlcSBcYm9sZHN5bWJvbHtifSBcXAomJiYgeCBcZ2VxIDAKXGVuZHthbGlnbmVkfQokJAoKJCQKXGJlZ2lue2FsaWduZWR9CiYgXHRleHR7TUlOfQomICYgeiA9IGNee1xwcmltZX14IFxcCiYgXHRleHR7cy5hLn0KJiAmIFxib2xkc3ltYm9se0F9eCBcZ2VxIFxib2xkc3ltYm9se2J9IFxcCiYmJiB4IFxnZXEgMApcZW5ke2FsaWduZWR9CiQkCm9uZGUgbGV0cmFzIG1hacO6c2N1bGFzIGVtIG5lZ3JpdG8gc8OjbyBtYXRyaXplcyBlIGxldHJhcyBtaW7DunNjdWxhcyBlbSBuZWdyaXRvIHPDo28gdmV0b3Jlcy4gCgojIyMjIyAqKlRFUk1JTk9MT0dJQSBQQVJBIFNPTFXDh8OVRVMgREUgTU9ERUxPUyoqCgpWb2PDqiBkZXZlIGVzdGFyIGFjb3N0dW1hZG8gYSB2ZXIgbyB0ZXJtbyAqKnNvbHXDp8OjbyoqIGNvbSBvIHNpZ25pZmljYWRvIGRlIHJlc3Bvc3RhIGZpbmFsIHBhcmEgdW0gcHJvYmxlbWEsIHBvcsOpbSwgYSBjb252ZW7Dp8OjbyBlbSBwcm9ncmFtYcOnw6NvIGxpbmVhciAoZSBzdWFzIGV4dGVuc8O1ZXMpIMOpIGJlbSBkaWZlcmVudGUuIEFxdWksIHF1YWxxdWVyIGVzcGVjaWZpY2HDp8OjbyBkZSB2YWxvcmVzIHBhcmEgYXMgdmFyacOhdmVpcyBkZSBkZWNpc8OjbyAoJHhfezF9LHhfezJ9LC4uLix4X3tufSQpIMOpIGNoYW1kYSAqKnNvbHXDp8OjbyoqLCBpZGVwZW5kZW50ZW1lbnRlIGRlIGVsYSBzZXIgZGVzZWrDoXZlbCBvdSBhdMOpIG1lc21vIHNlciB1bWEgb3DDo28gYWRtaXNzw612ZWwuIERpZmVyZW50ZXMgdGlwb3MgZGUgc29sdcOnw7VlcyBzw6NvIGVudMOjbyBpZGVudGlmaWNhZG9zIHVzYW5kby1zZSB1bSBhZGpldGl2byBhcHJvcHJpYWRvLgoKVW1hICoqc29sdcOnw6NvIHZpw6F2ZWwqKiDDqSBhcXVlbGEgcGFyYSBhIHF1YWwgKip0b2RhcyoqIGFzIHJlc3RyacOnw7VlcyBzw6NvIHNhdGlzZmVpdGFzLiBKw6EgdW1hICoqc29sdcOnw6NvIGludmnDoXZlbCoqIMOpIGFxdWVsYSBwYXJhIGEgcXVhbCAqKnBlbG8gbWVub3MgdW1hKiogZGFzIHJlc3RyacOnw7VlcyDDqSB2aW9sYWRhLiBEYWRvIHF1ZSBleGlzdGVtIHNvbHXDp8O1ZXMgdmnDoXZlaXMsIG8gb2JqZXRpdm8gZGEgcHJvZ3JhbWHDp8OjbyBsaW5lYXIgw6kgZW5jb250cmFyIGEgbWVsaG9yIHNvbHXDp8OjbyB2acOhdmVsIGNvbmZvcm1lIG1lZGlkYSBwZWxvIHZhbG9yIGRhIGZ1bsOnw6NvIG9iamV0aXZvIG5vIG1vZGVsby4KCk8gKip2YWxvciBtYWlzIGZhdm9yw6F2ZWwqKiDDqSBvIG1haW9yIHZhbG9yIHNlIGEgZnVuw6fDo28gb2JqZXRpdm8gdGl2ZXIgZGUgc2VyIG1heGltaXphZGEsIGFvIHBhc3NvIHF1ZSBzZXLDoSBvIG1lbm9yIHZhbG9yIGNhc28gZWxhIGRldmEgc2VyIG1pbmltaXphZGEuIEEgbWFpb3IgcGFydGUgZG9zIHByb2JsZW1hcyB0ZXLDoSBhcGVuYXMgdW1hIHNvbHXDp8OjbyDDs3RpbWEuIEVudHJldGFudG8sIMOpIHBvc3PDrXZlbCB0ZXIgbWFpcyBkZSB1bWEuIE91dHJhIHBvc3NpYmlsaWRhZGUgw6kgcXVlIHVtIHByb2JsZW1hIG7Do28gdGVuaGEgKipuZW5odW1hIHNvbHXDp8OjbyDDs3RpbWEqKi4gSXNzbyBhY29udGVjZSBhcGVuYXMgc2U6CgogICAqIHNlIG7Do28gZXhpc3RpciBuZW5odW1hIHNvbHXDp8OjbyB2acOhdmVsOwogICAqIGFzIHJlc3RyacOnw7VlcyBuw6NvIGltcGVkaXJlbSBxdWUgc2UgYXVtZW50ZSBpbmRlZmluaWRhbWVudGUgbyB2YWxvciBkYSBmdW7Dp8OjbyBvYmpldGl2byBuYSBkaXJlw6fDo28gZmF2b3LDoXZlbCAocG9zaXRpdmEgb3UgbmVnYXRpdmEpLiBFc3RlIGNhc28gw6kgY29uaGVjaWRvIGNvbW8gKipmdW7Dp8OjbyBvYmpldGl2byBpbGltaXRhZGEqLioKCiMjIyMjICoqRVhFTVBMTyBERSBQUk9CTEVNQSBERSBQUk9HUkFNQcOHw4NPIExJTkVBUioqCgpVbWEgcGVxdWVuYSBlbXByZXNhIHZlbmRlIGRvaXMgcHJvZHV0b3MsIFByb2R1dG8gMSBlIFByb2R1dG8gMi4gQ2FkYSB0b25lbGFkYSBkbyBQcm9kdXRvIDEgY29uc29tZSAzMCBob3JhcyBkZSB0cmFiYWxobyBlIGNhZGEgdG9uZWxhZGEgZG8gUHJvZHV0byAyIGNvbnNvbWUgMjAgaG9yYXMgZGUgdHJhYmFsaG8uIEEgZW1wcmVzYSB0ZW0gbm8gbcOheGltbyAyNzAwIGhvcmFzIGRlIHRyYWJhbGhvIHBhcmEgbyBwZXLDrW9kbyBjb25zaWRlcmFkby4KCkFsw6ltIGRpc3NvLCBjYWRhIHRvbmVsYWRhIGRvcyBQcm9kdXRvcyAxIGUgMiBjb25zb21lIDUgZSAxMCBob3JhcyBkZSBtw6FxdWluYSBwYXJhIHByb2Nlc3NhciBhIG1hdMOpcmlhIHByaW1hLCByZXNwZWN0aXZhbWVudGUuIFNhYmUtc2UgcXVlIGEgZW1wcmVzYSB0ZW0gODUwIGhvcmFzIGRpc3BvbsOtdmVpcyBwYXJhIHByb2Nlc3NhbWVudG8gZGEgbWF0w6lyaWEgcHJpbWEuCgpDYWRhIHRvbmVsYWRhIHZlbmRpZGEgZG8gUHJvZHV0byAxIGdlcmEgMjAgbWlsIHJlYWlzIGRlIGx1Y3JvIGVucXVhbnRvIHBhcmEgbyBQcm9kdXRvIDIgbyB2YWxvciDDqSBkZSA2MCBtaWwgcmVhaXMuIFBvciByYXrDtWVzIHTDqWNuaWNhcyBhIGVtcHJlc2EgZGV2ZSBwcm9kdXppciBubyBtw61uaW1vIHVtIHRvdGFsIGRlIDk1IHRvbmVsYWRhcy4gKipOb3NzbyBvYmpldGl2byDDqSBzYWJlciBxdWFudGFzIHRvbmVsYWRhcyBkb3MgZG9pcyBwcm9kdXRvcyBkZXZlbSBzZXIgcHJvZHV6aWRhcyBwYXJhIG1heGltYXIgbyBsdWNybyB0b3RhbCBkYSBlbXByZXNhLioqCgpPIHByb2JsZW1hIGV4cG9zdG8gcG9kZSBzZXIgZXNjcml0byBkYSBzZWd1aW50ZSBmb3JtYToKCiQkClxiZWdpbnthbGlnbmVkfQomIFx0ZXh0e01BWH0KJiAmIHogPSAyMFBfezF9KzYwUF97Mn0gXFwKJiBcdGV4dHtzLmEufQomICYgMzBQX3sxfSsyMFBfezJ9XGxlcSAyNzAwIFxcCiYmJiA1UF97MX0rMTBQX3syfVxsZXEgODUwIFxcCiYmJiBQX3sxfStQX3syfVxnZXEgOTUgXFwKJiYmIFBfezF9IFxnZXEgMCBcXAomJiYgUF97Mn0gXGdlcSAwClxlbmR7YWxpZ25lZH0KJCQKCiMjIyMjICoqUkVTT0xWRU5ETyBQUk9CTEVNQVMgREUgUFJPR1JBTUHDh8ODTyBMSU5FQVIqKgoKTyBwcm9jZWRpbWVudG8gbWFpcyB1dGlsaXphZG8gcGFyYSByZXNvbHZlciB1bSBwcm9ibGVtYSBkZSBwcm9ncmFtYcOnw6NvIGxpbmVhciDDqSB1c2FyIG8gYWxnb3JpdG1vICoqc2ltcGxleCoqIGRlc2Vudm9sdmlkbyBwb3IgQGRhbnR6aWcxOTUxbWF4aW1pemF0aW9uLiBPdXRyYSBhbHRlcm5hdGl2YSBwYXJhIHByb2JsZW1hcyBjb20gYXTDqSBkdWFzIHZhcmnDoXZlaXMgw6kgbyAqKm3DqXRvZG8gZ3LDoWZpY28qKi4gCgoqICoqTcOJVE9ETyBHUsOBRklDTyoqCgpQcm9ibGVtYXMgZGUgcHJvZ3JhbWHDp8OjbyBsaW5lYXIgY29tIGF0w6kgZHVhcyB2YXJpw6F2ZWlzIGRlIGRlY2lzw6NvIHBvZGVtIHNlciByZXByZXNlbnRhZG9zIGUgcmVzb2x2aWRvcyBncmFmaWNhbWVudGUuIEVtYm9yYSBsaW1pdGFkYSwgYSByZXByZXNlbnRhw6fDo28gZ3LDoWZpY2EgcGVybWl0ZSBldmlkZW5jaWFyIHByb3ByaWVkYWRlcyBlIGFzIGRpdmVyc2FzIHNpdHVhw6fDtWVzIHF1ZSBwb2RlbSBzZXIgZW5jb250cmFkYXMgYW8gc2UgcmVzb2x2ZXIgcHJvYmxlbWFzIGNvbSB1bSBuw7ptZXJvIG1haW9yIGRlIHZhcmnDoXZlaXMuIFBhcmEgZWZlaXRvIGRlIGV4cG9zacOnw6NvLCBjb25zaWRlcmUgbyBzZWd1aW50ZSBwcm9ibGVtYSBkZSBwcm9ncmFtYcOnw6NvIGxpbmVhcjoKCiQkClxiZWdpbnthbGlnbmVkfQomIFx0ZXh0e01BWH0KJiAmIHogPSB4X3sxfSsyeF97Mn0gXFwKJiBcdGV4dHtzLmEufQomICYgeF97MX0reF97Mn1cbGVxIDggXFwKJiYmIC14X3sxfSsyeF97Mn1cbGVxIDQgXFwKJiYmIDJ4X3sxfS14X3syfVxsZXEgMTIgXFwKJiYmIHhfezF9IFxnZXEgMCBcXAomJiYgeF97Mn0gXGdlcSAwClxlbmR7YWxpZ25lZH0KJCQKQ29uc2lkZXJlIG8gKipwbGFubyoqICR4XzEgXHRpbWVzIHhfMiQsIGNvbSBvcyBlaXhvcyBkYXMgYWJjaXNzYXMgZSBkYXMgb3JkZW5hZGFzIHJlcHJlc2VudGFuZG8gcG9zc8OtdmVpcyB2YWxvcmVzIHBhcmEgYXMgdmFyacOhdmVpcyBkZSBkZWNpc8OjbyAkeF97MX0kIGUgJHhfezJ9JC4gQ2FkYSB1bWEgZGFzIHJlc3RyacOnw7VlcyBkZXNjcmV2ZSB1bWEgcmVnacOjbyBkbyAqKnBsYW5vKiouIFBhcmEgb2J0ZXIgYSByZWdpw6NvIGFzc29jaWFkYSDDoCByZXN0cmnDp8OjbyAkeF97MX0reF97Mn1cbGVxIDgkLCBkZXNjcmV2ZS1zZSBpbmljaWFsbWVudGUgYSAqKnJldGEqKiAkeF97MX0reF97Mn09IDgkLCBxdWUgcGFzc2EgcGVsb3MgcG9udG9zICQoMCw4KSQgZSAkKDgsMCkkLiBBIHJldGEgJHhfezF9K3hfezJ9PSA4JCBkaXZpZGUgbyBwbGFubyBlbSAqKnNlbWlwbGFub3MqKiwgICR4X3sxfSt4X3syfVxsZXEgOCQgZSAkeF97MX0reF97Mn1cZ2UgOCQuIAoKUmVwZXRlLXNlIG8gcHJvY2VkaW1lbnRvIHBhcmEgdG9kYXMgYXMgcmVzdHJpw6fDtWVzIHByZXNlbnRlcyBubyBtb2RlbG8uIEEgaW50ZXJzZcOnw6NvIGRhcyByZWdpw7VlcyBkZXNjcml0YXMgcGVsb3Mgc2VtaXBsYW5vcyByZXByZXNlbnRhIGEgKipyZWdpw6NvIHZpw6F2ZWwqKiBkbyBwcm9ibGVtYSBpbHVzdHJhZGEgbmEgZmlndXJhIGFiYWl4by4KCmBgYHtyICBlY2hvPUZBTFNFLCBvdXQud2lkdGggPSAiMzAlIiwgZmlnLmFsaWduPSdyaWdodCd9CmxpYnJhcnkoa25pdHIpCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCdmb3RvLmpwZycpCmBgYApBIHJlZ2nDo28gdmnDoXZlbCBwb3NzdWkgaW5maW5pdG9zIHBvbnRvcyBlLCBlbSBwcmluY8OtcGlvLCBxdWFscXVlciB1bSBkZWxlcyBwb2RlIHNlciB1bWEgc29sdcOnw6NvIMOzdGltYSBkbyBwcm9ibGVtYS4gUGFyYSBkZXRlcm1pbmFyIHF1YWwgZGVsZXMgcHJvZHV6IG8gbWFpb3IgdmFsb3IgcGFyYSAkeiQsIHVzYS1zZSBvIGZhdG8gZGUgcXVlICR4X3sxfSsyeF97Mn09eiQgZGVzY3JldmUgdW1hIGZhbcOtbGlhIGRlIHJldGFzIHBhcmFsZWxhcyBkZSBpbmNsaW5hw6fDo28gJC0wLjUkIHBhcmFtZXRyaXphZGEgcGVsbyB2YWxvciBkZSAkeiQuIERpZmVyZW50ZXMgdmFsb3JlcyBkZSAkeiQgbGV2YW0gYSBkaWZlcmVudGVzIHBvbnRvcyBkZSBjcnV6YW1lbnRvIGNvbSBvcyBlaXhvcyAkeF8xJCBlICR4XzIkLiBSZXRhcyBjb3JyZXNwb25kZW50ZXMgYSB2YWxvcmVzIHNlbGVjaW9uYWRvcyBkZSAkeiQgZW5jb250cmFtLXNlIHJlcHJlc2VudGFkYXMgbmEgZmlndXJhIGFjaW1hLiBQYXJhIGRldGVybWluYXIgbyBzZW50aWRvIGRlIGNyZXNjaW1lbnRvIGRlICR6JCwgdXRpbGl6YS1zZSBvIGNvbmNlaXRvIGRlICoqZ3JhZGllbnRlKiogZGUgdW1hIGZ1bsOnw6NvIG51bSBwb250by4gTyB2ZXRvciBncmFkaWVudGUgZGUgcXVhbHF1ZXIgZnVuw6fDo28gZGlmZXJlbmNpw6F2ZWwgJHo9Zih4KSQgZGUgJG4kIHZhcmnDoXZlaXMgbnVtIHBvbnRvICR4PSh4XzEseF8yLC4uLix4X24pJCwgZGVub3RhZG8gcG9yICRcbmFibGEgZih4KSQsIMOpIG8gdmV0b3IgZm9ybWFkbyBwZWxhcyBwcmltZWlyYXMgZGVyaXZhZGFzIHBhcmNpYWlzIGRhIGZ1bsOnw6NvIG5vIHBvbnRvIGNvbnNpZGVyYWRvOgoKJCQKXG5hYmxhIGYoeCkgPSBcbGVmdCggXGZyYWMgeyBccGFydGlhbCBmXGxlZnQoIHggXHJpZ2h0KSAgfXsgXHBhcnRpYWwgeyB4IH1feyAxIH0gfSAsXGZyYWMgeyBccGFydGlhbCBmXGxlZnQoIHggXHJpZ2h0KSAgfXsgXHBhcnRpYWwgeyB4IH1feyAyIH0gfSAsLi4uLFxmcmFjIHsgXHBhcnRpYWwgZlxsZWZ0KCB4IFxyaWdodCkgIH17IFxwYXJ0aWFsIHsgeCB9X3sgbiB9IH0gIFxyaWdodCkgCiQkCk8gdmV0b3IgZ3JhZGllbnRlIGluZGljYSBvIHNlbnRpZG8gZGUgbWFpb3IgY3Jlc2NpbWVudG8gZGEgZnVuw6fDo28gbm8gZW50b3JubyBkbyBwb250byBjb25zaWRlcmFkby4gT2JzZXJ2YS1zZSBxdWUgbyB2ZXRvciBncmFkaWVudGUgZGUgdW1hIGZ1bsOnw6NvIGxpbmVhciwgCgokJAp6PWNfMXhfMStjXzJ4XzIrLi4uK2NfbnhfbgokJArDqSBjb25zdGFudGUgZSBkYWRvIHBvciAKCiQkCmM9KGNfMSxjXzIsLi4uLGNfbikKJCQKTm8gY2FzbyBkbyBleGVtcGxvIGlsdXN0cmF0aXZvLCAkYz0oMSwyKSQuIE8gc2VudGlkbyBkbyBncmFkaWVudGUgZXN0w6EgaW5kaWNhZG8gbmEgZmlndXJhIGFudGVyaW9yLiBPIHZldG9yIGdyYWRpZW50ZSDDqSAqKm9ydG9nb25hbCoqIGEgcXVhbHF1ZXIgcmV0YSBxdWUgZGVzY3JldmEgdW0gdmFsb3IgcGFyYSBhIGZ1bsOnw6NvIG9iamV0aXZvLiAKClJlc3VtaW5kbywgYSBtYXhpbWl6YcOnw6NvIGRvIHZhbG9yIGRhIGZ1bsOnw6NvLW9iamV0aXZvIG5vIHByb2JsZW1hIGRlc2NyaXRvIHBvZGUgc2VyIGNvbmR1emlkYSBkYSBzZWd1aW50ZSBmb3JtYToKCiogcGVyY29ycmVyIGEgcmVnacOjbyB2acOhdmVsIGRvIHByb2JsZW1hIG5vIHNlbnRpZG8gZG8gZ3JhZGllbnRlIChhdW1lbnRhbmRvIGNvbnRpbnVhbWVudGUgbyB2YWxvciBkYSBmdW7Dp8OjbyBvYmpldGl2bykgYXTDqSBxdWUgYSBmcm9udGVpcmEgZGEgcmVnacOjbyBzZWphIGV2ZW50dWFsbWVudGUgYXRpbmdpZGE7CiogbyB2YWxvciBtw6F4aW1vIGRhIGZ1bsOnw6NvLW9iamV0aXZvIG5hIHJlZ2nDo28gdmnDoXZlbCDDqSBkYWRvIHBlbG8gdmFsb3IgZGEgcmV0YSBxdWUgdG9jYSBhIGZyb250ZWlyYSwgbm8gY2FzbyAkel57XGFzdH09MTIkLiBRdWFscXVlciBwb250byBxdWUgcGVydGVuY2Egw6AgcmV0YSBkZSB2YWxvciAkel57XGFzdH09MTIkIHF1ZSB0YW1iw6ltIHBlcmNlbnRlIMOgIGZyb250ZWlyYSDDqSB1bWEgc29sdcOnw6NvIMOzdGltYSBkbyBwcm9ibGVtYS4gTm8gY2FzbyBkbyBleGVtcGxvLCBleGlzdGUgYXBlbmFzIHVtYSBzb2x1w6fDo28gw7N0aW1hLCAkeF57XGFzdH09KDQsNCkkLgoKU2UgbyBvYmpldGl2byBkbyBwcm9ibGVtYSBmb3NzZSwgYW8gaW52w6lzIGRlIG1heGltaXphciwgbWluaW1pemFyIG8gdmFsb3IgZGUgJHokLCBhZG90YXItc2UtaWEgYSBkaXJlw6fDo28gY29udHLDoXJpYSDDoCBkbyBncmFkaWVudGUsIG91IHNlamEsIGEgZGUgbWFpb3IgKipkZWNyZXNjaW1lbnRvKiogZGEgZnVuw6fDo28uIE8gdmFsb3IgbcOtbmltbyBkYSBmdW7Dp8Ojby1vYmpldGl2byBzZXJpYSAkel57XGFzdH09MCQsIG9idGlkbyBubyBwb250byAkeF57XGFzdH09KDAsMCkkLiAKCiogKipNw4lUT0RPIFNJTVBMRVgqKgoKTyBhbGdvcml0bW8gKipzaW1wbGV4Kiogc2UgYXByb3ZlaXRhIGRvIGZhdG8gcXVlIG8gw7N0aW1vIGRlIHVtIHByb2JsZW1hIGRlIHByb2dyYW1hw6fDo28gbGluZWFyIHBvZGUgc2VyIGVuY29udHJhZG8gZXhwbG9yYW5kbyBzdWFzIHNvbHXDp8O1ZXMgYsOhc2ljYXMuIEFzIHNvbHXDp8O1ZXMgYsOhc2ljYXMgY29ycmVzcG9uZGVtIGFvcyB2w6lydGljZXMgZGEgcmVnacOjbyB2acOhdmVsIGRvIHByb2JsZW1hLiBBIGVzdHJhdMOpZ2lhIGRvIGFsZ29yaXRtbyAqKnNpbXBsZXgqKiBzZXLDoToKCiogRW5jb250cmFyIGEgc29sdcOnw6NvIGLDoXNpY2EgaW5pY2lhbAoqIEV4cGxvcmFyIGFzIHNvbHXDp8O1ZXMgYsOhc2ljYXMgbW92ZW5kbyBuYSBkaXJlw6fDo28gcXVlIG1heGltaXphIG91IG1pbmltaXphIGEgZnVuw6fDo28gb2JqZXRpdm8KKiBQYXJhciBxdWFuZG8gdW1hIHNvbHXDp8OjbyDDs3RpbWEgw6kgZW5jb250cmFkYQoKU29mdHdhcmVzIHF1ZSByZXNvbHZlbSBwcm9ibGVtYXMgZGUgcHJvZ3JhbWHDp8OjbyBsaW5lYXIgcXVhc2Ugc2VtcHJlIGZhemVtIHVzbyBkbyBhbGdvcml0bW8gc2ltcGxleCBvdSBzdWEgdmVyc8OjbyByZXZpc2FkYSBxdWUgw6kgdW1hIHZhcmlhbnRlIHF1ZSBlc3TDoSBpbXBsZW1lbnRhZGEgcGFyYSBzZXIgbWFpcyBlZmljaWVudGUuIEV4aXN0ZW0gb3V0cm9zIGFsZ29yaXRtb3MgcGFyYSBwcm9ibGVtYXMgcGFydGljdWxhcmVzIGRlIHByb2dyYW1hw6fDo28gbGluZWFyIHRhbCBjb21vOiBbdHJhbnNwb3J0ZSBkZSB1bWEgb3JpZ2VtIHBhcmEgdW0gZGVzdGlub10oaHR0cDovL3dpa2kuaWNtYy51c3AuYnIvaW1hZ2VzLzEvMTMvQXVsYTJQTV9tYXJpLnBkZikgb3UgW3Byb2JsZW1hIGRlIGZsdXhvIG3DoXhpbW9dKGh0dHA6Ly93d3cudWZqZi5ici9lcGQwMTUvZmlsZXMvMjAxMC8wNi9mbHV4b19tYXhpbW8yLnBkZikuCgojIyMjIyAqKlJFU09MVkVORE8gUFJPQkxFTUFTIERFIFBST0dSQU1Bw4fDg08gTElORUFSIE5PIFIqKgoKRXhpc3RlbSB2w6FyaW9zIHNvbHZlcnMgZGlzcG9uw612ZWlzIHBhcmEgcmVzb2x2ZXIgcHJvYmxlbWFzIGRlIHByb2dyYW1hw6fDo28gbGluZWFyLiBVbWEgbGlzdGEgZGVsZXMgcG9kZSBzZXIgZW5jb250cmFkYSBuZXN0ZSBbbGlua10oaHR0cDovL3d3dy5ndXJvYmkuY29tL3Jlc291cmNlcy9zd2l0Y2hpbmctdG8tZ3Vyb2JpL29wZW4tc291cmNlLXNvbHZlcnMpLiBBbGd1bnMgZGVsZXMgdGFtYsOpbSBzw6NvIGltcGxlbWVudGFkb3Mgbm8gUiwgY29tbyBzZWd1ZToKCiogW2xwX3NvbHZlXShodHRwOi8vbHBzb2x2ZS5zb3VyY2Vmb3JnZS5uZXQvNS41LykgcXVlIMOpIGRpc3BvbmliaWxpemFkbyBubyBSIHBvciBtZWlvIGRvcyBwYWNvdGVzIFtscFNvbHZlXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvbHBTb2x2ZS9scFNvbHZlLnBkZikgZSBbbHBTb2x2ZUFQSV0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL2xwU29sdmVBUEkvbHBTb2x2ZUFQSS5wZGYpOwoqIFtHTFBLXShodHRwczovL3d3dy5nbnUub3JnL3NvZnR3YXJlL2dscGsvKSBxdWUgbm8gUiBwb2RlIHNlciB1c2FkbyB2aWEgcGFjb3RlIFtSZ2xwa10oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL1JnbHBrL1JnbHBrLnBkZik7CiogW1NZTVBIT05ZXShodHRwczovL3Byb2plY3RzLmNvaW4tb3Iub3JnL1NZTVBIT05ZKSBxdWUgZXN0w6EgZGlzcG9uw612ZWwgbm8gUiB2aWEgcGFjb3RlIFtSc3ltcGhvbnldKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9Sc3ltcGhvbnkvUnN5bXBob255LnBkZikKCkFsZ3VucyBkZXN0ZXMgcGFjb3RlcyB0w6ptIGZ1bsOnw7VlcyBxdWUgcGVybWl0ZW0gYSBsZWl0dXJhIGRlIGFycXVpdm9zIGNvbnRlbmRvIHByb2JsZW1hcyBkZSBwcm9ncmFtYcOnw6NvIGxpbmVhciwgcHJvZ3JhbWHDp8OjbyBsaW5lYXIgaW50ZWlyYSBlIHByb2dyYW1hw6fDo28gbGluZWFyIGludGVpcmEgbWlzdGEgZXNjcml0b3Mgbm8gZm9ybWF0byBDUExFWCwgcG9yIGV4ZW1wbG8uCgoqICoqUmVzb2x2ZW5kbyBwcm9ibGVtYXMgZGUgcHJvZ3JhbWHDp2HDtSBsaW5lYXIgdXNhbmRvIG8gcGFjb3RlIGBscFNvbHZlYDoqKgoKMS4gQ29uc2lkZXJlIG8gZXhlbXBsbyBhcHJlc2VudGFkbyBhbnRlcmlvcm1lbnRlLCBhYmFpeG8gdGVtb3MgYSBzb2x1w6fDo28gZG8gcHJvYmxlbWEgZGUgcHJvZ3JhbWHDp8OjbyBsaW5lYXIgbm8gUi4KCmBgYHtyfQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIyMjICAgICBQQUNPVEVTICAgICAjIyMjIwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKIyBJbnN0YWxhciBwYWNvdGVzIG5lY2Vzc8OhcmlvcyBwYXJhIG8gcmVzdGFudGUgZG8gZG9jdW1lbnRvCiNpbnN0YWxsLnBhY2thZ2VzKGMoImxwU29sdmUiLCJscFNvbHZlQVBJIiwgImdncGxvdDIiLCJwbG90bHkiKSkKCiMgQ2FycmVnYXIgcGFjb3RlcyBuZWNlc3PDoXJpb3MgcGFyYSBvIHJlc3RhbnRlIGRvIGRvY3VtZW50bwpzdXBwcmVzc01lc3NhZ2VzKHJlcXVpcmUobHBTb2x2ZSkpCnN1cHByZXNzTWVzc2FnZXMocmVxdWlyZShscFNvbHZlQVBJKSkKc3VwcHJlc3NNZXNzYWdlcyhyZXF1aXJlKGdncGxvdDIpKQpzdXBwcmVzc01lc3NhZ2VzKHJlcXVpcmUocGxvdGx5KSkKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMjIyMgICAgIFBST0JNRUxBICAgICMjIyMjCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgojIGNvZWZpY2llbnRlcyBkZSBQMSBlIFAyIG5hIGZ1bsOnw6NvIG9iamV0aXZvIApmdW5jLm9iamV0aXZvIDwtIGMoMjAgLCA2MCkKCiMgY29lZmljaWVudGVzIGRlIFAxIGUgUDIgbmFzIHJlc3RyacOnw7Vlcy4gU2VtcHJlIGVtIG1hdHJpeiBjb21vIG1vc3RyYWRvIG5vIHRleHRvIGFjaW1hCmNvZWZpY2llbnRlcy5yZXN0cmljb2VzIDwtIG1hdHJpeCAoYygzMCwgMjAsIDUsIDEwLCAxLCAxKSwgbmNvbCA9IDIgLCBieXJvdyA9IFRSVUUpCgojIHNpbmFsIGRhcyByZXN0cmnDp8O1ZXMuIERldmUgb2JlZGVjZXIgYSBvcmRlbSBkYSBtYXRyaXogZGUgY29lZmljaWVudGVzCmRpcmVjYW8ucmVzdHJpY29lcyA8LSBjKCI8PSIsIjw9IiwiPj0iKQoKIyBsaW1pdGUgZGFzIHJlc3RyacOnw7Vlcy4gRGV2ZSBvYmVkZWNlciBhIG9yZGVtIGRhIG1hdHJpeiBkZSBjb2VmaWNpZW50ZXMKbGltaXRlcy5yZXN0cmljb2VzIDwtIGMoMjcwMCwgODUwLCA5NSkKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMjIyMgICAgIFNPTFXDh8ODTyAgICAgIyMjIyMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCiMgQmFzaWNhbWVudGUsIHVzYW1vcyBhIGZ1bsOnw6NvIGxwIGRvIHBhY290ZSBscFNvbHZlIGNvbSBvcyBzZWd1aW50ZXMgcGFyw6JtZXRyb3M6CiMgZGlyZWN0aW9uOiBxdWUgcmVjZWJlIG1heCBvdSBtaW4gZGVwZW5kZW5kbyBzZSBvIHByb2JsZW1hIMOpIGRlIG1heGltaXphw6fDo28gb3UgbWluaXphw6fDo28sIHJlc3BlY3RpdmFtZW50ZQojIG9iamVjdGl2ZS5pbjogcXVlIHJlY2ViZSBvIG5vbWUgZG8gdmV0b3IgY29tIHBhcsOibWV0cm9zIGRhIGZ1bsOnw6NvIG9iamV0aXZvCiMgY29uc3QubWF0OiBxdWUgcmVjZWJlIG8gbm9tZSBkYSBtYXRyaXogY29tIGNvZWZpY2llbnRlcyBkYXMgcmVzdHJpw6fDtWVzCiMgY29uc3QucmhzOiBxdWUgcmVjZWJlIG8gbm9tZSBkbyB2ZXRvciBjb20gb3MgbGltaXRlcyBkYXMgcmVzdHJpw6fDtWVzCiMgbWFpcyBvcMOnw7VlcyBkYSBmdW7Dp8OjbyBwb2RlbSBzZXIgb2J0aWRhcyBwb3IgbWVpbyBkbyBoZWxwKGxwKQoKc29sdWNhby5wcm9ibGVtYSA8LSBscFNvbHZlOjpscChkaXJlY3Rpb24gPSAibWF4IiwgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvYmplY3RpdmUuaW4gPSBmdW5jLm9iamV0aXZvLCAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdC5tYXQgPSBjb2VmaWNpZW50ZXMucmVzdHJpY29lcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0LmRpciA9IGRpcmVjYW8ucmVzdHJpY29lcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0LnJocyA9IGxpbWl0ZXMucmVzdHJpY29lcykKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMjIyMgICAgUkVTVUxUQURPICAgICMjIyMjCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgojIHZhbG9yIGRhIGZ1bsOnw6NvIG9iamV0aXZvIG5hIHNvbHXDp8Ojbwpzb2x1Y2FvLnByb2JsZW1hJG9ianZhbAoKIyBWYWxvcmVzIHBhcmEgYXMgdmFyacOhdmVpcyBkZSBlc2NvbGhhIHF1ZSBnZXJhbSBtw6F4aW1vIG91IG3DrW5pbW8gZGVwZW5kZW5kbyBkbyBwcm9ibGVtYQpzb2x1Y2FvLnByb2JsZW1hJHNvbHV0aW9uCmBgYAoKMi4gQ29uc2lkZXJlIG8gc2VndWludGUgcHJvYmxlbWEgZGUgbWluaW1pemHDp8OjbzoKCiQkClxiZWdpbnthbGlnbmVkfQomIFx0ZXh0e01JTn0KJiAmIHogPSAtM3hfezF9LTR4X3syfS0zeF97M30gXFwKJiBcdGV4dHtzLmEufQomICYgNnhfezF9KzJ4X3syfSs0eF97M31cbGVxIDE1MCBcXAomJiYgeF97MX0reF97Mn0rNnhfezN9XGdlcSAwIFxcCiYmJiA0eF97MX0rNXhfezJ9KzR4X3szfT0gNDAgXFwKJiYmIHhfezF9IFxnZXEgMCBcXAomJiYgeF97Mn0gXGdlcSAwIFxcCiYmJiB4X3szfSBcZ2VxIDAgXFwKXGVuZHthbGlnbmVkfQokJAoKCmBgYHtyfQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIyMjICAgICBQUk9CTUVMQSAgICAjIyMjIwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKIyBjb2VmaWNpZW50ZXMgZGUgWDEsIFgyIGUgWDMgbmEgZnVuw6fDo28gb2JqZXRpdm8gCmZ1bmMub2JqZXRpdm8ucHJvYjIgPC0gYygtMyAsIC00LCAtMykKCiMgY29lZmljaWVudGVzIGRlIFgxLCBYMiBlIFgzIG5hcyByZXN0cmnDp8O1ZXMuIApjb2VmaWNpZW50ZXMucmVzdHJpY29lcy5wcm9iMiA8LSBtYXRyaXggKGMoNiwgMiwgNCwgMSwgMSwgNiwgNCwgNSwgNCksIG5jb2wgPSAzICwgYnlyb3cgPSBUUlVFKQoKIyBzaW5hbCBkYXMgcmVzdHJpw6fDtWVzLiBEZXZlIG9iZWRlY2VyIGEgb3JkZW0gZGEgbWF0cml6IGRlIGNvZWZpY2llbnRlcwpkaXJlY2FvLnJlc3RyaWNvZXMucHJvYjIgPC0gYygiPD0iLCI+PSIsIj0iKQoKIyBsaW1pdGUgZGFzIHJlc3RyacOnw7Vlcy4gRGV2ZSBvYmVkZWNlciBhIG9yZGVtIGRhIG1hdHJpeiBkZSBjb2VmaWNpZW50ZXMKbGltaXRlcy5yZXN0cmljb2VzLnByb2IyIDwtIGMoMTUwLCAwLCA0MCkKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMjIyMgICAgIFNPTFXDh8ODTyAgICAgIyMjIyMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCnNvbHVjYW8ucHJvYmxlbWEyIDwtIGxwU29sdmU6OmxwKGRpcmVjdGlvbiA9ICJtaW4iLCAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9iamVjdGl2ZS5pbiA9IGZ1bmMub2JqZXRpdm8ucHJvYjIsICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0Lm1hdCA9IGNvZWZpY2llbnRlcy5yZXN0cmljb2VzLnByb2IyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QuZGlyID0gZGlyZWNhby5yZXN0cmljb2VzLnByb2IyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QucmhzID0gbGltaXRlcy5yZXN0cmljb2VzLnByb2IyKQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyMjIyAgICBSRVNVTFRBRE8gICAgIyMjIyMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCiMgdmFsb3IgZGEgZnVuw6fDo28gb2JqZXRpdm8gbmEgc29sdcOnw6NvCnNvbHVjYW8ucHJvYmxlbWEyJG9ianZhbAoKIyBWYWxvcmVzIHBhcmEgYXMgdmFyacOhdmVpcyBkZSBlc2NvbGhhIHF1ZSBnZXJhbSBtw6F4aW1vIG91IG3DrW5pbW8gZGVwZW5kZW5kbyBkbyBwcm9ibGVtYQpzb2x1Y2FvLnByb2JsZW1hMiRzb2x1dGlvbgpgYGAKCjMuIFVtYSBDb21wYW5oaWEgYcOpcmVhIGVzdMOhIGFjcmVzY2VudGFuZG8gbWFpcyB2w7RvcyBkZS9wYXJhIHNldSBhZXJvcG9ydG8gY2VudHJhbCBlLCBwYXJhIHRhbnRvLCBwcmVjaXNhIGNvbnRyYXRhciBtYWlzIGFnZW50ZXMgcGFyYSBvIGF0ZW5kaW1lbnRvIGFvIHDDumJsaWNvLiBFbnRyZXRhbnRvLCBuw6NvIGVzdMOhIGNsYXJvIHF1YW50YXMgcGVzc29hcyBlbGVzIGRldmVtIGNvbnRyYXRhci4gQSBnZXLDqm5jaWEgcmVjb25oZWNlIGEgbmVjZXNzaWRhZGUgZGUgY29udHJvbGUgZGUgY3VzdG9zLCBlbWJvcmEgbWFudGVuZG8sIGFvIG1lc21vIHRlbXBvLCB1bSBuw612ZWwgZGUgc2VydmnDp29zIHNhdGlzZmF0w7NyaW8gYSBzZXVzIGNsaWVudGVzLiAKClBhcmEgaXNzbywgdW1hIGVxdWlwZSBlc3TDoSBlc3R1ZGFuZG8gY29tbyBwcm9ncmFtYXIgYXMgZXNjYWxhcyBkZXNzZXMgYWdlbnRlcyBwYXJhIGZvcm5lY2VyIGJvbnMgc2VydmnDp29zIGFvcyBjbGllbnRlcyBjb20gbyBtZW5vciBjdXN0byBwb3Nzw612ZWwgZW0gdGVybW9zIGRlIHBlc3NvYWwuCgpUb21hbmRvIGNvbW8gYmFzZSBhIG5vdmEgZXNjYWxhIGRlIHbDtG9zLCBmb2kgcmVhbGl6YWRhIHVtYSBhbsOhbGlzZSBkbyBuw7ptZXJvIG3DrW5pbW8gZGUgYWdlbnRlcyBkZSBhdGVuZGltZW50byBhbyBjbGllbnRlIHF1ZSBwcmVjaXNhdmFtIGVzdGFyIGRlIHNlcnZpw6dvIGVtIGRpZmVyZW50ZXMgaG9yYXMgZG8gZGlhIHBhcmEgZm9ybmVjZXIgdW0gbsOtdmVsIGRlIHNlcnZpw6dvIHNhdGlzZmF0w7NyaW8uIEEgY29sdW5hIG1haXMgw6AgZGlyZWl0YSBkYSB0YWJlbGEgYWJhaXhvIG1vc3RyYSBvIG7Dum1lcm8gZGUgYWdlbnRlcyBuZWNlc3PDoXJpb3MgcGFyYSBvcyBwZXLDrW9kb3MgZGFkb3MgbmEgcHJpbWVpcmEgY29sdW5hLiBPcyBkZW1haXMgY2FtcG9zIGRlc3NhIHRhYmVsYSByZWZsZXRlbSB1bWEgZGFzIGNsw6F1c3VsYXMgbm8gY29udHJhdG8gYXR1YWwgZGEgZW1wcmVzYSBjb20gbyBzaW5kaWNhdG8gcXVlIHJlcHJlc2VudGEgb3MgYWdlbnRlcyBkZSBhdGVuZGltZW50byBhbyBjbGllbnRlLiBFc3NhIGNsw6F1c3VsYSBkaXogcXVlIGNhZGEgYWdlbnRlIHRyYWJhbGhhIGNpbmNvIGRpYXMgcG9yIHNlbWFuYSBlbSB0dXJub3MgZGUgb2l0byBob3JhcyBlIG9zIHR1cm5vcyBhdXRvcml6YWRvcyBzw6NvOgoKICAgKiBUdXJubyAxOiA2aC0xNGgKICAgKiBUdXJubyAyOiA4aC0xNmgKICAgKiBUdXJubyAzOiAxMmgtMjBoCiAgICogVHVybm8gNDogMTZoLTAwaAogICAqIFR1cm5vIDU6IDIyaC02aAoKYGBge3IsIGZpZy5hbGlnbj0nY2VudGVyJywgZWNobz1GQUxTRX0Kc3VwcHJlc3NNZXNzYWdlcyhyZXF1aXJlKGh0bWx0b29scykpCmh0bWx0b29sczo6aW5jbHVkZUhUTUwoInRhYmxlLmh0bWwiKQpgYGAKCkFzIG1hcmNhcyBkZSB2ZXJpZmljYcOnw6NvICh4KSBubyBjb3JwbyBkYSB0YWJlbGEgaW5kaWNhbSBvcyBob3LDoXJpb3MgY29iZXJ0b3MgcGVsb3MgcmVzcGVjdGl2b3MgdHVybm9zLiBQZWxvIGZhdG8gZGUgYWxndW5zIHR1cm5vcyBzZXJlbSBtZW5vcyBkZXNlamFkb3MgZG8gcXVlIG91dHJvcywgb3Mgc2Fsw6FyaW9zIGVzcGVjaWZpY2Fkb3Mgbm8gY29udHJhdG8gZGlmZXJlbSBjb25mb3JtZSBvIHR1cm5vLiBQYXJhIGNhZCB0dXJubywgbyBwYWdhbWVudG8gZGnDoXJpbyAoaW5jbHVpbmRvIGJlbmVmw61jaW9zKSBwYXJhIGNhZGEgYWdlbnRlIMOpIG1vc3RyYWRvIG5hIHVsdGltYSBsaW5oYSBkYSB0YWJlbGEuIE8gcHJvYmxlbWEgw6kgZGV0ZXJtaW5hciBxdWFudG9zIGFnZW50ZXMgZGV2ZW0gc2VyIGFsb2NhZG9zIHBhcmEgb3MgcmVzcGVjdGl2b3MgdHVybm9zIGRpw6FyaW9zIGEgZmltIGRlIG1pbmltaXphciBvIGN1c3RvIHRvdGFsIGNvbSBwZXNzb2FsIChhZ2VudGVzKSB0b21hbmRvIGNvbW8gYmFzZSBhIMO6bHRpbWEgbGluaGEgZGEgdGFiZWxhIGUsIGFvIG1lc21vIHRlbXBvLCBhdGVuZGVuZG8gKG91IHVsdHJhcGFzc2FuZG8pIGFzIGV4aWfDqm5jaWFzIGRlIG7DrXZlbCBkZSBzZXJ2acOnbyBkYWRhcyBuYSBjb2x1bmEgbWFpcyDDoCBkaXJlaXRhLgoKUGVsbyBmYXRvIGRlIGEgZnVuw6fDo28gb2JqZXRpdm8gbWluaW1pemFyIG8gY3VzdG8gdG90YWwgZG9zIGFlbnRlcyBhdHJpYnXDrWRvcyBhb3MgY2luY28gdHVybm9zLCBvcyBjb2VmaWNpZW50ZXMgbmEgZnVuw6ddYW8gb2JqZXRpdm8gc8OjbyBkYWRvcyBwZWxhIMO6bHRpbWEgbGluaGEgZGEgdGFiZWxhLiBQb3J0YW50bywgbyBwcm9ibGVtYSBkZSBwcm9ncmFtYcOnw6NvIGxpbmVhciBjb21wbGV0byDDqToKCiQkClxiZWdpbnthbGlnbmVkfQomIFx0ZXh0e01JTn0KJiAmIHogPSAxNzB4X3sxfSsxNjB4X3syfSsxNzV4X3szfSsxODB4X3s0fSsxOTV4X3s1fSBcXAomIFx0ZXh0e3MuYS59CiYgJiB4X3sxfVxnZXEgNDggICYmIFx0ZXh0eyg2aC04aCl9IFxcCiYmJiB4X3sxfSt4X3syfVxnZXEgNzkgJiYgXHRleHR7KDhoLTEwaCl9IFxcCiYmJiB4X3sxfSt4X3syfVxnZXEgNjUgJiYgXHRleHR7KDEwaC0xMmgpfSBcXAomJiYgeF97MX0reF97Mn0reF97M30gXGdlcSA4NyAmJiBcdGV4dHsoMTJoLTE0aCl9IFxcCiYmJiB4X3syfSt4X3szfSBcZ2VxIDY0ICYmIFx0ZXh0eygxNGgtMTZoKX0gXFwKJiYmIHhfezN9K3hfezR9IFxnZXEgNzMgJiYgXHRleHR7KDE2aC0xOGgpfSBcXAomJiYgeF97M30reF97NH0gXGdlcSA4MiAmJiBcdGV4dHsoMThoLTIwaCl9IFxcCiYmJiB4X3s0fSBcZ2VxIDQzICYmIFx0ZXh0eygyMGgtMjJoKX0gXFwKJiYmIHhfezR9K3hfezV9IFxnZXEgNTIgJiYgXHRleHR7KDIyaC0wMGgpfSBcXAomJiYgeF97NX0gXGdlcSAxNSAmJiBcdGV4dHsoMDBoLTZoKX0gXFwKJiYmIHhfe2p9IFxnZXEgMCAmJiBcdGV4dHtwYXJhIGo9MSwyLDMsNCw1fSBcXApcZW5ke2FsaWduZWR9CiQkCkNvbSB1bSBvbGhhciBhZ3XDp2Fkbywgdm9jw6ogcHJvdmF2ZWxtZW50ZSBkZXZlIHRlciBwZXJjZWJpZG8gcXVlIGEgdGVyY2VpcmEgcmVzdHJpw6fDo28sICR4X3sxfSt4X3syfVxnZXEgNjUkLCBuYSB2ZXJkYWRlIG7Do28gw6kgbmVjZXNzw6FyaWEsIHBvaXMgYSBzZWd1bmRhIHJlc3RyacOnw6NvICR4X3sxfSt4X3syfVxnZXEgNzkkLCBnYXJhbnRlIHF1ZSAkeF97MX0reF97Mn0kIHNlcsOhIG1haW9yIHF1ZSA2NS4gUG9ydGFudG8sICR4X3sxfSt4X3syfVxnZXEgNjUkIMOpIHVtYSAqKnJlc3RyacOnw6NvIHJlZHVuZGFudGUqKiBxdWUgcG9kZSBzZXIgZWxpbWluYWRhLgoKRGEgbWVzbWEgZm9ybWEsIGEgc2V4dGEgcmVzdHJpw6fDo28gJHhfezN9K3hfezR9IFxnZXEgNyQsIHRhbWLDqW0gw6kgcmVkdW5kYW50ZSBwb3JxdWUgYSBzw6l0aW1hIHJlc3RyacOnw6NvIMOpICR4X3szfSt4X3s0fSBcZ2VxIDgyJC4gTmEgcmVhbGlkYWRlLCB0csOqcyBkYXMgcmVzdHJpw6fDtWVzIGRlIG7Do28tbmVnYXRpdmlkYWRlIHRhbWLDqW0gc8OjbyByZWR1bmRhbnRlcyBlbSByYXrDo28gZGEgcHJpbWVpcmEsIG9pdGF2YSBlIGTDqWNpbWEgcmVzdHJpw6fDtWVzIGZ1bmNpb25haXM6ICR4X3sxfVxnZXEgNDgkLCAkeF97NH0gXGdlcSA0MyQgZSAkeF97NX0gXGdlcSAxNSQuIEVudHJldGFudG8sIG7Do28gc2UgZ2FuaGEgbmVuaHVtYSB2YW50YWdlbSBlbSB0ZXJtb3MgY29tcHV0YWNpb25haXMgZWxpbWluYW5kby1zZSBlc3NhcyB0csOqcyByZXN0cmnDp8O1ZXMgZGUgbsOjby1uZWdhdGl2aWRhZGUuCgpgYGB7cn0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyMjIyAgICAgUFJPQk1FTEEgICAgIyMjIyMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCiMgY29lZmljaWVudGVzIGRlIFgxLCBYMiBlIFgzIG5hIGZ1bsOnw6NvIG9iamV0aXZvIApmdW5jLm9iamV0aXZvLnByb2IzIDwtIGMoMTcwLCAxNjAsIDE3NSwgMTgwLCAxOTUpCgojIGNvZWZpY2llbnRlcyBkZSBYMSwgWDIgZSBYMyBuYXMgcmVzdHJpw6fDtWVzLiAKY29lZmljaWVudGVzLnJlc3RyaWNvZXMucHJvYjMgPC0gbWF0cml4IChjKDEsIDAsIDAsIDAsIDAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAxLCAxLCAwLCAwLCAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAxLCAxLCAxLCAwLCAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAwLCAxLCAxLCAwLCAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAwLCAwLCAxLCAxLCAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAwLCAwLCAwLCAxLCAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAwLCAwLCAwLCAxLCAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAwLCAwLCAwLCAwLCAxKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuY29sID0gNSAsIGJ5cm93ID0gVFJVRSkKCiMgc2luYWwgZGFzIHJlc3RyacOnw7Vlcy4gRGV2ZSBvYmVkZWNlciBhIG9yZGVtIGRhIG1hdHJpeiBkZSBjb2VmaWNpZW50ZXMKZGlyZWNhby5yZXN0cmljb2VzLnByb2IzIDwtIGMoIj49IiwiPj0iLCI+PSIsIj49IiwiPj0iLCI+PSIsIj49IiwiPj0iKQoKIyBsaW1pdGUgZGFzIHJlc3RyacOnw7Vlcy4gRGV2ZSBvYmVkZWNlciBhIG9yZGVtIGRhIG1hdHJpeiBkZSBjb2VmaWNpZW50ZXMKbGltaXRlcy5yZXN0cmljb2VzLnByb2IzIDwtIGMoNDgsIDc5LCA4NywgNjQsIDgyLCA0MywgNTIsIDE1KQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyMjIyAgICAgU09MVcOHw4NPICAgICAjIyMjIwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKc29sdWNhby5wcm9ibGVtYTMgPC0gbHBTb2x2ZTo6bHAoZGlyZWN0aW9uID0gIm1pbiIsICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2JqZWN0aXZlLmluID0gZnVuYy5vYmpldGl2by5wcm9iMywgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QubWF0ID0gY29lZmljaWVudGVzLnJlc3RyaWNvZXMucHJvYjMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdC5kaXIgPSBkaXJlY2FvLnJlc3RyaWNvZXMucHJvYjMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdC5yaHMgPSBsaW1pdGVzLnJlc3RyaWNvZXMucHJvYjMpCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIyMjICAgIFJFU1VMVEFETyAgICAjIyMjIwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKIyB2YWxvciBkYSBmdW7Dp8OjbyBvYmpldGl2byBuYSBzb2x1w6fDo28Kc29sdWNhby5wcm9ibGVtYTMkb2JqdmFsCgojIFZhbG9yZXMgcGFyYSBhcyB2YXJpw6F2ZWlzIGRlIGVzY29saGEgcXVlIGdlcmFtIG3DoXhpbW8gb3UgbcOtbmltbyBkZXBlbmRlbmRvIGRvIHByb2JsZW1hCnNvbHVjYW8ucHJvYmxlbWEzJHNvbHV0aW9uCmBgYAoKQSBzb2x1w6fDo28gw7N0aW1hIHBhcmEgZXNzZSBtb2RlbG8gw6kgJCh4X3sxfSx4X3syfSx4X3szfSx4X3s0fSx4X3s1fSk9KDQ4LDMxLDM5LDQzLDE1KSQuIElzc28gZmF6IGNvbSBxdWUgJFo9MzAuNjEwJCwgaXN0byDDqSwgdW0gY3VzdG8gZGnDoXJpbyB0b3RhbCBjb20gcGVzc29hbCBkZSBVJDMwLjYxMC4KCk8gbsO6bWVybyBkZSBhZ2VudGVzIGFsb2NhZG9zIHBhcmEgY2FkYSB0dXJubyBwcmVjaXNhIHNlciB1bSBpbnRlaXJvLiBSaWdvcm9zYW1lbnRlIGZhbGFuZG8sIG8gbW9kZWxvIGRldmVyaWEgdGVyIHVtYSByZXN0cmnDp8OjbyBhZGljaW9uYWwgcGFyYSBjYWRhIHZhcmnDoXZlbCBkZSBkZWNpc8OjbyBlc3BlY2lmaWNhbmRvIHF1ZSBhIHZhcmnDoXZlbCBkZXZlIHRlciB1bSB2YWxvciBpbnRlaXJvLiBBY3Jlc2NlbnRhciBlc3NhcyByZXN0cmnDp8O1ZXMgdHJhbnNmb3JtYXJpYSBvIG1vZGVsbyBkZSBwcm9ncmFtYcOnw6NvIGxpbmVhciBlbSB1bSBtb2RlbG8gZGUgcHJvZ3JhbWHDp8OjbyBpbnRlaXJhLiAKCiogKipSZXNvbHZlbmRvIHByb2JsZW1hcyBkZSBwcm9ncmFtYcOnw6NvIGxpbmVhciB1c2FuZG8gbyBwYWNvdGUgYGxwU29sdmVBUElgOioqCgpDb25zaWRlcmUgcXVlIHRlbW9zIG8gc2VndWludGUgcHJvYmxlbWEgZGUgcHJvZ3JhbWHDp8OjbyBsaW5lYXI6CgokJApcYmVnaW57YWxpZ25lZH0KJiBcdGV4dHtNSU59CiYgJiB6ID0geF97MX0rM3hfezJ9KzYuMjR4X3szfSswLjF4X3s0fSBcXAomIFx0ZXh0e3MuYS59CiYgJiA3OC4yNnhfezJ9KzIuOXhfezR9XGdlcSA5Mi4zIFxcCiYmJiAwLjI0eF97MX0rMTEuMzF4X3szfVxsZXEgMTQuOCBcXAomJiYgMTIuNjh4X3sxfSswLjA4eF97M30rMC45eF97NH0gXGdlcSA0ClxlbmR7YWxpZ25lZH0KJCQKb25kZSAkeF8xJCDDqSB1bWEgdmFyacOhdmVsIGNvbSB2YWxvciBtw61uaW1vIGRlICQyOC42JCwgJHhfMiQgw6kgdW1hIHZhcmnDoXZlbCBuw6NvLW5lZ2F0aXZhIGUgaW50ZWlyYSwgJHhfMyQgw6kgdW1hIHZhcmnDoXZlbCBiaW7DoXJpYSBlICR4XzQkIMOpIHVtYSB2YXJpw6F2ZWwgbGltaXRhZGEgYW8gaW50ZXJ2YWxvICRbMTgsNDguOThdJC4gQXNzaW0sIHBvciBtZWlvIGRvIHBhY290ZSBgbHBzb2x2ZUFQSWAsIHRlbW9zIGEgc2VndWludGUgc29sdcOnw6NvOgpgYGB7ciwgZWNobz1UUlVFLCB3YXJuaW5nPUZBTFNFfQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIyMjICAgICBQUk9CTUVMQSAgICAjIyMjIwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKIyBQcmltZWlybywgY3JpYW1vcyBvIHByb2JsZW1hIGNvbSAzIHJlc3RyacOnw7VlcyBlIDQgdmFyacOhdmVpcy4gT2JzZXJ2ZQojIHF1ZSBhYmFpeG8gc2VtcHJlIHVzYXJlbW9zICJscHJlYyIgcGFyYSBkaXplciBxdWUgZXN0YW1vcyBhZGljaW9uYW5kbwojIGRlZmluacOnw7VlcyBhbyBwcm9ibGVtYQpscHJlYyA8LSBscFNvbHZlQVBJOjptYWtlLmxwKDMsNCkKCiMgRGVwb2lzLCBkZWZpbmltb3Mgb3MgdmFsb3JlcyBkYSBwcmltZWlyYSBjb2x1bmEgZGEgbWF0cml6IGRlIHJlc3RyacOnw7VlczoKIyAtIDE6IGluZGljYSBhIHByaW1laXJhIGNvbHVuYQojIC0gYygwLCAwLjI0LCAxMi42OCk6IG9zIGNvZWZpY2llbnRlcyBkZSB4MSBuYXMgcmVzdHJpw6fDtWVzCmxwU29sdmVBUEk6OnNldC5jb2x1bW4obHByZWMsIDEsIGMoMCwgMC4yNCwgMTIuNjgpKQoKIyBGYXplbW9zIG8gbWVzbW8gcGFyYSBhcyBkZW1haXMgdmFyacOhdmVpcyAoY29sdW5hcykuIEFxdWksIHVzYW1vcwojIGEgb3DDp8OjbyBpbmRpY2VzIHF1ZSB2YWkgZGl6ZXIgZW0gcXVhbCBwb3Npw6fDo28gZGEgY29sdW5hIGjDoSB2YWxvciwgCiMgcG9pcyBlbSBhbGd1bnMgY2Fzb3MgcG9kZW1vcyBuw6NvIHRlciBuYXMgcmVzdHJpw6fDtWVzIHZhbG9yZXMgcGFyYQojIG91dHJhcyB2YXJpw6F2ZWlzCmxwU29sdmVBUEk6OnNldC5jb2x1bW4obHByZWMsIDIsIDc4LjI2LCBpbmRpY2VzID0gMSkKbHBTb2x2ZUFQSTo6c2V0LmNvbHVtbihscHJlYywgMywgYygxMS4zMSwgMC4wOCksIGluZGljZXMgPSAyOjMpCmxwU29sdmVBUEk6OnNldC5jb2x1bW4obHByZWMsIDQsIGMoMi45LCAwLjkpLCBpbmRpY2VzID0gYygxLDMpKQoKIyBBZ29yYSwgZGVmaW5pbW9zIGEgZnVuw6fDo28gb2JqZXRpdm8KbHBTb2x2ZUFQSTo6c2V0Lm9iamZuKGxwcmVjLCBjKDEsMywgNi4yNCwgMC4xKSkKCiMgVGlwb3MgZGUgcmVzdHJpw6fDtWVzCmxwU29sdmVBUEk6OnNldC5jb25zdHIudHlwZShscHJlYywgYygiPj0iLCAiPD0iLCAiPj0iKSkKCiMgTGltaXRlIGRhcyByZXN0cmnDp8O1ZXMKbHBTb2x2ZUFQSTo6c2V0LnJocyhscHJlYywgYyg5Mi4zLCAxNC44LCA0KSkKCiMgUG9yIGRlZmF1bHQsIHRvZGFzIGFzIHZhcmnDoXZlaXMgc8OjbyBjcmlhZGFzIGNvbW8gdW0gdmFsb3IgcmVhbCBubyAKIyBpbnRlcnZhbG8gWzAsIGluZmluaXRvXS4gQXNzaW0sIGRldmVtb3MgbXVkYXIgaXNzbyBjYXNvIG8gcHJvYmxlbWEKIyBkZW1hbmRlLiBObyBub3NzbyBleGVtcGxvLCB0ZW1vczoKIyAtIHgyOiBpbnRlaXJvCiMgLSB4MzogYmluw6FyaW8KbHBTb2x2ZUFQSTo6c2V0LnR5cGUobHByZWMsIDIsICJpbnRlZ2VyIikKbHBTb2x2ZUFQSTo6c2V0LnR5cGUobHByZWMsIDMsICJiaW5hcnkiKQoKIyBEZWZpbmlyIG8gaW50ZXJ2YWxvIHBhcmEgYXMgdmFyacOhdmVpcyB4MSBlIHg0CiMgLSB4MTogdmFsb3IgbcOtbmltbyBkZSAyOC42IChwcmltZWlyYSBjb2x1bmEpCiMgLSB4NDogdmFsb3IgbcOtbmltbyBkZSAxOCBlIG3DoXhpbW8gZGUgNDguOTggKHF1YXJ0YSBjb2x1bmEpCmxwU29sdmVBUEk6OnNldC5ib3VuZHMobHByZWMsIGxvd2VyID0gYygyOC42LCAxOCksIGNvbHVtbnMgPSBjKDEsIDQpKQpscFNvbHZlQVBJOjpzZXQuYm91bmRzKGxwcmVjLCB1cHBlciA9IDQ4Ljk4LCBjb2x1bW5zID0gNCkKCiMgRmluYWxtZW50ZSwgcG9kZW1vcyByZW5vbWVhciBhcyB2YXJpw6F2ZWlzIGRvIHByb2JsZW1hClJvd05hbWVzIDwtIGMoIlJPV09ORSIsIlJPV1RXTyIsICJST1dUSFJFRSIpCkNvbE5hbWVzIDwtIGMoIkNPTE9ORSIsIkNPTFRXTyIsICJDT0xUSFJFRSIsICJDT0xURk9VUiIpCmRpbW5hbWVzKGxwcmVjKSA8LSBsaXN0KFJvd05hbWVzLCBDb2xOYW1lcykKCiMgRGVmaW5pciBzZSDDqSB1bSBwcm9ibGVtYSBkZSBtYXhpbWl6YcOnw6NvIG91IG1pbmltaXphw6fDo28KIyBTZSBtYXhpbWl6YcOnw6NvIHNlbnNlID0gYygibWF4IikuIFVzZSBoZWxwKGxwLmNvbnRyb2wub3B0aW9ucykKIyBwYXJhIHZpc3VhbGl6YXIgdG9kYXMgYXMgb3DDp8O1ZXMgcXVlIHBvZGVtIHNlciBhbHRlcmFkYXMgZW0KIyB1bSBwcm9ibGVtYSBkZSBvdGltaXphw6fDo28gdXNhbmRvIGVzdGUgcGFjb3RlLgptaW5pbWl6YXIgPC0gbHBTb2x2ZUFQSTo6bHAuY29udHJvbChscHJlYywgc2Vuc2UgPSBjKCJtaW4iKSkKCiMgVmlzdWFsaXphciBvIHByb2JsZW1hIGRlZmluaWRvIGVtIHVtIGZvcm1hdG8gcXVlIHNlamEgZsOhY2lsCiMgY29uZmVyaXIgc2UgZXN0w6EgdHVkbyBlbSBjb25mb3JtaWRhZGUgY29tIG8gcHJvYmxlbWEgYSBzZXIgCiMgcmVzb2x2aWRvCmxwcmVjCgpgYGAKCkFnb3JhLCBwb2RlbW9zIHNvbHVjaW9uYXIgbyBwcm9ibGVtYSBjb21vIHNlZ3VlOgoKYGBge3J9CiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMjIyMgICAgIFNPTFXDh8ODTyAgICAgIyMjIyMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCiMgU29sdWNpb25hciBvIHByb2JsZW1hIGRlZmluaWRvIGFudGVyaW9ybWVudGUgdXNhbmRvIGEgZnVuw6fDo28KIyBzb2x2ZS5scEV4dFB0ciBkbyBwYWNvdGUgbHBTb2x2ZUFQSS4gQXF1aSwgbyBzb2x2ZXIgYXBlbmFzCiMgaW5mb3JtYSBvIHN0YXR1cyBkYSBzb2x1w6fDo28sIGNvbW8gc2VndWU6CiMgMDoJICJvcHRpbWFsIHNvbHV0aW9uIGZvdW5kIgojIDE6CSAidGhlIG1vZGVsIGlzIHN1Yi1vcHRpbWFsIgojIDI6CSAidGhlIG1vZGVsIGlzIGluZmVhc2libGUiCiMgMzoJICJ0aGUgbW9kZWwgaXMgdW5ib3VuZGVkIgojIDQ6CSAidGhlIG1vZGVsIGlzIGRlZ2VuZXJhdGUiCiMgNToJICJudW1lcmljYWwgZmFpbHVyZSBlbmNvdW50ZXJlZCIKIyA2OgkgInByb2Nlc3MgYWJvcnRlZCIKIyA3OgkgInRpbWVvdXQiCiMgOToJICJ0aGUgbW9kZWwgd2FzIHNvbHZlZCBieSBwcmVzb2x2ZSIKIyAxMDoJICJ0aGUgYnJhbmNoIGFuZCBib3VuZCByb3V0aW5lIGZhaWxlZCIKIyAxMToJICJ0aGUgYnJhbmNoIGFuZCBib3VuZCB3YXMgc3RvcHBlZCBiZWNhdXNlIG9mIGEgYnJlYWstYXQtZmlyc3Qgb3IgYnJlYWstYXQtdmFsdWUiCiMgMTI6CSAiYSBmZWFzaWJsZSBicmFuY2ggYW5kIGJvdW5kIHNvbHV0aW9uIHdhcyBmb3VuZCIKIyAxMzoJICJubyBmZWFzaWJsZSBicmFuY2ggYW5kIGJvdW5kIHNvbHV0aW9uIHdhcyBmb3VuZCIKc29sdWNhby5wcm9ibGVtYTQgPC0gbHBTb2x2ZUFQSTo6c29sdmUubHBFeHRQdHIobHByZWMpCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIyMjICAgIFJFU1VMVEFETyAgICAjIyMjIwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKIyB2YWxvciBkYSBmdW7Dp8OjbyBvYmpldGl2byBuYSBzb2x1w6fDo28KbHBTb2x2ZUFQSTo6Z2V0Lm9iamVjdGl2ZShscHJlYykKCiMgVmFsb3JlcyBwYXJhIGFzIHZhcmnDoXZlaXMgZGUgZXNjb2xoYSBxdWUgZ2VyYW0gbcOheGltbyBvdSBtw61uaW1vIGRlcGVuZGVuZG8gZG8gcHJvYmxlbWEKbHBTb2x2ZUFQSTo6Z2V0LnZhcmlhYmxlcyhscHJlYykKYGBgCgojIyMjICoqUkVGRVLDik5DSUFTKioK