Pacotes necessários
library(sf)
Warning: package ‘sf’ was built under R version 4.3.3Linking to GEOS 3.11.2, GDAL 3.8.2, PROJ 9.3.1; sf_use_s2() is TRUE
library(dplyr)
Warning: package ‘dplyr’ was built under R version 4.3.3
Attaching package: ‘dplyr’
The following objects are masked from ‘package:stats’:
filter, lag
The following objects are masked from ‘package:base’:
intersect, setdiff, setequal, union
library(readr)
Warning: package ‘readr’ was built under R version 4.3.3
library(spatstat.geom)
Warning: package ‘spatstat.geom’ was built under R version 4.3.3Carregando pacotes exigidos: spatstat.data
Warning: package ‘spatstat.data’ was built under R version 4.3.3Carregando pacotes exigidos: spatstat.univar
Warning: package ‘spatstat.univar’ was built under R version 4.3.3spatstat.univar 3.1-2
spatstat.geom 3.3-6
library(spatstat.explore)
Warning: package ‘spatstat.explore’ was built under R version 4.3.3Carregando pacotes exigidos: spatstat.random
Warning: package ‘spatstat.random’ was built under R version 4.3.3spatstat.random 3.3-2
Carregando pacotes exigidos: nlme
Attaching package: ‘nlme’
The following object is masked from ‘package:dplyr’:
collapse
spatstat.explore 3.4-2
library(spatstat.random)
library(ggplot2)
Use suppressPackageStartupMessages() to eliminate package startup messages
1- Importar dados
grid = st_read("C:/Users/Samsung/OneDrive/Documentos/1 - PósDoc/2 - FAPESP - Silvipastoril/3 - Execução/Dados/Fase 1/Distribuição/grid_20x20_singlepart.geojson")
Reading layer `grid_20x20_singlepart' from data source
`C:\Users\Samsung\OneDrive\Documentos\1 - PósDoc\2 - FAPESP - Silvipastoril\3 - Execução\Dados\Fase 1\Distribuição\grid_20x20_singlepart.geojson'
using driver `GeoJSON'
Simple feature collection with 3550 features and 2 fields
Geometry type: POLYGON
Dimension: XY
Bounding box: xmin: 676072.3 ymin: 8868882 xmax: 678343.2 ymax: 8870838
Projected CRS: WGS 84 / UTM zone 21S
grid
Simple feature collection with 3550 features and 2 fields
Geometry type: POLYGON
Dimension: XY
Bounding box: xmin: 676072.3 ymin: 8868882 xmax: 678343.2 ymax: 8870838
Projected CRS: WGS 84 / UTM zone 21S
First 10 features:
area ID.Grid geometry
1 400 1 POLYGON ((677185.1 8870838,...
2 400 2 POLYGON ((677173.6 8870822,...
3 400 3 POLYGON ((677162.1 8870805,...
4 400 4 POLYGON ((677150.6 8870789,...
5 400 5 POLYGON ((677139.2 8870773,...
6 400 6 POLYGON ((677127.7 8870756,...
7 400 7 POLYGON ((677116.2 8870740,...
8 400 8 POLYGON ((677104.8 8870723,...
9 400 9 POLYGON ((677093.3 8870707,...
10 400 10 POLYGON ((677081.8 8870691,...
pontos = read_csv("C:/Users/Samsung/OneDrive/Documentos/1 - PósDoc/2 - FAPESP - Silvipastoril/3 - Execução/Dados/Fase 1/Especies_QGIS.csv")
Rows: 2457 Columns: 7── Column specification ───────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (1): Espécie
dbl (6): N, Piquete, LAT, LONG, LONG1, LAT1
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
pontos
copas = st_read("C:/Users/Samsung/OneDrive/Documentos/1 - PósDoc/2 - FAPESP - Silvipastoril/3 - Execução/Dados/Fase 1/GRIDs/Grids Sombreados.shp")
Reading layer `Grids Sombreados' from data source
`C:\Users\Samsung\OneDrive\Documentos\1 - PósDoc\2 - FAPESP - Silvipastoril\3 - Execução\Dados\Fase 1\GRIDs\Grids Sombreados.shp'
using driver `ESRI Shapefile'
Simple feature collection with 3550 features and 6 fields
Geometry type: MULTIPOLYGON
Dimension: XY
Bounding box: xmin: 676072.3 ymin: 8868882 xmax: 678343.2 ymax: 8870838
Projected CRS: WGS 84 / UTM zone 21S
copas
Simple feature collection with 3550 features and 6 fields
Geometry type: MULTIPOLYGON
Dimension: XY
Bounding box: xmin: 676072.3 ymin: 8868882 xmax: 678343.2 ymax: 8870838
Projected CRS: WGS 84 / UTM zone 21S
First 10 features:
area ID.Grid Área.sem Área.somb X..N..Sombr X.Sombreada geometry
1 400 1 400.000 0.000 100.000 0.000 MULTIPOLYGON (((677185.1 88...
2 400 2 400.000 0.000 100.000 0.000 MULTIPOLYGON (((677173.6 88...
3 400 3 400.000 0.000 100.000 0.000 MULTIPOLYGON (((677162.1 88...
4 400 4 400.000 0.000 100.000 0.000 MULTIPOLYGON (((677150.6 88...
5 400 5 400.000 0.000 100.000 0.000 MULTIPOLYGON (((677139.2 88...
6 400 6 400.000 0.000 100.000 0.000 MULTIPOLYGON (((677127.7 88...
7 400 7 382.960 17.040 95.740 4.260 MULTIPOLYGON (((677132.6 88...
8 400 8 358.073 41.927 89.518 10.482 MULTIPOLYGON (((677109.2 88...
9 400 9 396.272 3.728 99.068 0.932 MULTIPOLYGON (((677097.9 88...
10 400 10 383.605 16.395 95.901 4.099 MULTIPOLYGON (((677098.2 88...
2- Converter pontos para objeto sf e plotar
pontos_sf <- st_as_sf(pontos, coords = c("LONG1", "LAT1"), crs = 4326)
pontos_sf <- st_transform(pontos_sf, crs = st_crs(grid))
copas <- st_transform(copas, st_crs(grid))
area_sombreada_real = st_difference(grid, st_union(copas))
Warning: attribute variables are assumed to be spatially constant throughout all geometries
plot1=ggplot() +
geom_sf(data = grid, fill = NA, color = "black") +
geom_sf(data = pontos_sf, color = "red", size = 1) +
theme_minimal() +
labs(title = "Pontos de árvores sobre o grid 20x20 m")
plot1

plot2 = ggplot() +
geom_sf(data = grid, fill = NA, color = "black", size=0.2) +
geom_sf(data = area_sombreada_real, fill = "darkgreen", color = NA, alpha = 0.7) +
theme_minimal() +
labs(title = "Áreas reais ocupadas por copa dentro do grid 20x20 m")
plot2

Aparentemente deu tudo certo com os grids e com as coordenadas
3 - Metodos de de determinação de distribuição
3.1 - Clark-Evans
O índice de Clark-Evans é uma medida estatística descritiva usada
para determinar se um padrão espacial de pontos é: Agregado
(clusterizado), Aleatório ou Disperso (uniformemente distribuído).
Formula: R= robs/rexp. Robs: distância média entre cada ponto e seu
vizinho mais próximo (na amostra); Rexp: distância esperada entre
vizinhos mais próximos se os pontos fossem distribuídos aleatoriamente
em um plano com densidade constante. Interpretação dos valores de R: R
< 1 Agregado; R ≈ 1 Aleatório (Poisson); R > 1 Disperso
(uniforme). Limitações: Não funciona bem com poucos pontos.
calcular_padroes <- function(celula, pontos_celula) {
if (nrow(pontos_celula) < 2) {
return(data.frame(padrao = "Insuficiente", R = NA))
}
janela <- as.owin(st_geometry(celula))
coords <- st_coordinates(pontos_celula)
ppp_obj <- ppp(x = coords[,1], y = coords[,2], window = janela)
ce <- clarkevans(ppp_obj)
# Verifica se ce é uma lista com R
R_val <- if ("R" %in% names(ce)) ce$R else ce
padrao <- ifelse(R_val < 1, "Agregado",
ifelse(R_val > 1, "Disperso", "Aleatório"))
return(data.frame(padrao = padrao, R = R_val))
}
# 1. Loop sobre células do grid
resultados <- lapply(1:nrow(grid), function(i) {
celula <- grid[i, ]
pontos_dentro <- pontos_sf[st_within(pontos_sf, celula, sparse = FALSE), ]
dados <- calcular_padroes(celula, pontos_dentro)
# Garante que sempre retorna uma única linha com o ID
dados$ID <- i
return(dados[1, ])
})
Warning: data contain duplicated pointsWarning: data contain duplicated pointsWarning: data contain duplicated pointsWarning: data contain duplicated pointsWarning: data contain duplicated pointsWarning: data contain duplicated pointsWarning: data contain duplicated pointsWarning: data contain duplicated pointsWarning: data contain duplicated pointsWarning: data contain duplicated pointsWarning: data contain duplicated pointsWarning: data contain duplicated pointsWarning: data contain duplicated points
# 2. Juntar resultados ao grid
resultados_df <- do.call(rbind, resultados)
grid_resultado <- cbind(grid, resultados_df)
View(grid_resultado)
# 3. Exportar resultado para o QGIS
st_write(grid_resultado, "grid_resultado_clarkevans.shp", delete_dsn = TRUE)
Warning: GDAL Error 1: grid_resultado_clarkevans.shp does not appear to be a file or directory.
Deleting source `grid_resultado_clarkevans.shp' failed
Writing layer `grid_resultado_clarkevans' to data source
`grid_resultado_clarkevans.shp' using driver `ESRI Shapefile'
Writing 3550 features with 5 fields and geometry type Polygon.
3.2 - Índice de Morisita
O Morisita é ideal para padrões de contagem em subáreas, mesmo com
poucas árvores por célula. Cada celula do grid é dividida em uma
subdivisão virtual em grade (ex: 4x4 quadrados = 16 subáreas) e é
contado quantas árvores que caem em cada uma. A partir disso, é
calculado o índice de Morisita por célula.
names(grid_resultado1)
[1] "area_m2" "id_grid" "padrao_morisita" "id_morisita" "id_celula"
[6] "geometry"
4 - Comparação entre Clark-Evans vs Morisita

3.3 - Índice de Morisita adaptado
Nesta abordagem fiz uma mudança na equação para considerar a area
ocupada pela copa, em vez de apenas a coordenada.
# 4. Exportar para uso no QGIS
st_write(grid_resultado_area, "grid_resultado_morisita_area.gpkg", layer = "morisita_area", delete_layer = TRUE)
Writing layer `morisita_area' to data source `grid_resultado_morisita_area.gpkg' using driver `GPKG'
Writing 3550 features with 5 fields and geometry type Polygon.
5 - Plot Morisita adaptado

LS0tDQp0aXRsZTogIkFuw6FsaXNlIGRhIGRpc3RyaWJ1acOnw6NvIGRhcyDDoXJ2b3JlcyBjb25zaWRlcmFuZG8gw6FyZWEgZGUgY29wYTogYWRhcHRhw6fDo28gZG8gw61uZGljZSBkZSBtb3Jpc2l0YSINCmF1dGhvcjogIlZhZ25lciBPdmFuaSINCmRhdGU6ICIyMy8wNS8yMDI0Ig0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOg0KICAgIHRvYzogVFJVRQ0KICAgIHRvY19kZXB0aDogMg0KICAgIHRoZW1lOiB1bml0ZWQNCi0tLQ0KDQojICpQYWNvdGVzIG5lY2Vzc8OhcmlvcyoNCg0KYGBge3J9DQpsaWJyYXJ5KHNmKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkocmVhZHIpDQpsaWJyYXJ5KHNwYXRzdGF0Lmdlb20pDQpsaWJyYXJ5KHNwYXRzdGF0LmV4cGxvcmUpDQpsaWJyYXJ5KHNwYXRzdGF0LnJhbmRvbSkNCmxpYnJhcnkoZ2dwbG90MikNCmBgYA0KIyAqMS0gSW1wb3J0YXIgZGFkb3MqDQoNCmBgYHtyfQ0KZ3JpZCA9IHN0X3JlYWQoIkM6L1VzZXJzL1NhbXN1bmcvT25lRHJpdmUvRG9jdW1lbnRvcy8xIC0gUMOzc0RvYy8yIC0gRkFQRVNQIC0gU2lsdmlwYXN0b3JpbC8zIC0gRXhlY3XDp8Ojby9EYWRvcy9GYXNlIDEvRGlzdHJpYnVpw6fDo28vZ3JpZF8yMHgyMF9zaW5nbGVwYXJ0Lmdlb2pzb24iKQ0KZ3JpZA0KcG9udG9zID0gcmVhZF9jc3YoIkM6L1VzZXJzL1NhbXN1bmcvT25lRHJpdmUvRG9jdW1lbnRvcy8xIC0gUMOzc0RvYy8yIC0gRkFQRVNQIC0gU2lsdmlwYXN0b3JpbC8zIC0gRXhlY3XDp8Ojby9EYWRvcy9GYXNlIDEvRXNwZWNpZXNfUUdJUy5jc3YiKQ0KcG9udG9zDQoNCmNvcGFzID0gc3RfcmVhZCgiQzovVXNlcnMvU2Ftc3VuZy9PbmVEcml2ZS9Eb2N1bWVudG9zLzEgLSBQw7NzRG9jLzIgLSBGQVBFU1AgLSBTaWx2aXBhc3RvcmlsLzMgLSBFeGVjdcOnw6NvL0RhZG9zL0Zhc2UgMS9HUklEcy9HcmlkcyBTb21icmVhZG9zLnNocCIpDQpjb3BhcyAgICAgICAgICAgICAgICANCmBgYA0KIyAqMi0gQ29udmVydGVyIHBvbnRvcyBwYXJhIG9iamV0byBzZiBlIHBsb3RhcioNCg0KYGBge3J9DQoNCnBvbnRvc19zZiA8LSBzdF9hc19zZihwb250b3MsIGNvb3JkcyA9IGMoIkxPTkcxIiwgIkxBVDEiKSwgY3JzID0gNDMyNikNCnBvbnRvc19zZiA8LSBzdF90cmFuc2Zvcm0ocG9udG9zX3NmLCBjcnMgPSBzdF9jcnMoZ3JpZCkpDQpjb3BhcyA8LSBzdF90cmFuc2Zvcm0oY29wYXMsIHN0X2NycyhncmlkKSkNCmFyZWFfc29tYnJlYWRhX3JlYWwgPSBzdF9kaWZmZXJlbmNlKGdyaWQsIHN0X3VuaW9uKGNvcGFzKSkNCg0KcGxvdDE9Z2dwbG90KCkgKw0KICBnZW9tX3NmKGRhdGEgPSBncmlkLCBmaWxsID0gTkEsIGNvbG9yID0gImJsYWNrIikgKw0KICBnZW9tX3NmKGRhdGEgPSBwb250b3Nfc2YsIGNvbG9yID0gInJlZCIsIHNpemUgPSAxKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIGxhYnModGl0bGUgPSAiUG9udG9zIGRlIMOhcnZvcmVzIHNvYnJlIG8gZ3JpZCAyMHgyMCBtIikNCnBsb3QxDQoNCnBsb3QyID0gZ2dwbG90KCkgKw0KICBnZW9tX3NmKGRhdGEgPSBncmlkLCBmaWxsID0gTkEsIGNvbG9yID0gImJsYWNrIiwgc2l6ZT0wLjIpICsNCiAgZ2VvbV9zZihkYXRhID0gYXJlYV9zb21icmVhZGFfcmVhbCwgZmlsbCA9ICJkYXJrZ3JlZW4iLCBjb2xvciA9IE5BLCBhbHBoYSA9IDAuNykgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICBsYWJzKHRpdGxlID0gIsOBcmVhcyByZWFpcyBvY3VwYWRhcyBwb3IgY29wYSBkZW50cm8gZG8gZ3JpZCAyMHgyMCBtIikNCnBsb3QyDQpgYGANCj5BcGFyZW50ZW1lbnRlIGRldSB0dWRvIGNlcnRvIGNvbSBvcyBncmlkcyBlIGNvbSBhcyBjb29yZGVuYWRhcyANCg0KIyAqMyAtIE1ldG9kb3MgZGUgZGUgZGV0ZXJtaW5hw6fDo28gZGUgZGlzdHJpYnVpw6fDo28qDQoNCiMgKjMuMSAtIENsYXJrLUV2YW5zKg0KDQo+IE8gw61uZGljZSBkZSBDbGFyay1FdmFucyDDqSB1bWEgbWVkaWRhIGVzdGF0w61zdGljYSBkZXNjcml0aXZhIHVzYWRhIHBhcmEgZGV0ZXJtaW5hciBzZSB1bSBwYWRyw6NvIGVzcGFjaWFsIGRlIHBvbnRvcyDDqTogQWdyZWdhZG8gKGNsdXN0ZXJpemFkbyksIEFsZWF0w7NyaW8gb3UgRGlzcGVyc28gKHVuaWZvcm1lbWVudGUgZGlzdHJpYnXDrWRvKS4gRm9ybXVsYTogUj0gcm9icy9yZXhwLiBSb2JzOiBkaXN0w6JuY2lhIG3DqWRpYSBlbnRyZSBjYWRhIHBvbnRvIGUgc2V1IHZpemluaG8gbWFpcyBwcsOzeGltbyAobmEgYW1vc3RyYSk7IFJleHA6IGRpc3TDom5jaWEgZXNwZXJhZGEgZW50cmUgdml6aW5ob3MgbWFpcyBwcsOzeGltb3Mgc2Ugb3MgcG9udG9zIGZvc3NlbSBkaXN0cmlidcOtZG9zIGFsZWF0b3JpYW1lbnRlIGVtIHVtIHBsYW5vIGNvbSBkZW5zaWRhZGUgY29uc3RhbnRlLiBJbnRlcnByZXRhw6fDo28gZG9zIHZhbG9yZXMgZGUgUjogUiA8IDEJQWdyZWdhZG87IFIg4omIIDEJQWxlYXTDs3JpbyAoUG9pc3Nvbik7IFIgPiAxCURpc3BlcnNvICh1bmlmb3JtZSkuIExpbWl0YcOnw7VlczogTsOjbyBmdW5jaW9uYSBiZW0gY29tIHBvdWNvcyBwb250b3MuDQoNCmBgYHtyfQ0KIyAxLiBDcmlhciBmdW7Dp8Ojbw0KDQpjYWxjdWxhcl9wYWRyb2VzIDwtIGZ1bmN0aW9uKGNlbHVsYSwgcG9udG9zX2NlbHVsYSkgew0KICBpZiAobnJvdyhwb250b3NfY2VsdWxhKSA8IDIpIHsNCiAgICByZXR1cm4oZGF0YS5mcmFtZShwYWRyYW8gPSAiSW5zdWZpY2llbnRlIiwgUiA9IE5BKSkNCiAgfQ0KICBqYW5lbGEgPC0gYXMub3dpbihzdF9nZW9tZXRyeShjZWx1bGEpKQ0KICBjb29yZHMgPC0gc3RfY29vcmRpbmF0ZXMocG9udG9zX2NlbHVsYSkNCiAgcHBwX29iaiA8LSBwcHAoeCA9IGNvb3Jkc1ssMV0sIHkgPSBjb29yZHNbLDJdLCB3aW5kb3cgPSBqYW5lbGEpDQogIGNlIDwtIGNsYXJrZXZhbnMocHBwX29iaikNCiAgIyBWZXJpZmljYSBzZSBjZSDDqSB1bWEgbGlzdGEgY29tIFINCiAgUl92YWwgPC0gaWYgKCJSIiAlaW4lIG5hbWVzKGNlKSkgY2UkUiBlbHNlIGNlDQogIHBhZHJhbyA8LSBpZmVsc2UoUl92YWwgPCAxLCAiQWdyZWdhZG8iLA0KICAgICAgICAgICAgICAgICAgIGlmZWxzZShSX3ZhbCA+IDEsICJEaXNwZXJzbyIsICJBbGVhdMOzcmlvIikpDQogIHJldHVybihkYXRhLmZyYW1lKHBhZHJhbyA9IHBhZHJhbywgUiA9IFJfdmFsKSkNCn0NCg0KIyAyLiBMb29wIHNvYnJlIGPDqWx1bGFzIGRvIGdyaWQNCnJlc3VsdGFkb3MgPC0gbGFwcGx5KDE6bnJvdyhncmlkKSwgZnVuY3Rpb24oaSkgew0KICBjZWx1bGEgPC0gZ3JpZFtpLCBdDQogIHBvbnRvc19kZW50cm8gPC0gcG9udG9zX3NmW3N0X3dpdGhpbihwb250b3Nfc2YsIGNlbHVsYSwgc3BhcnNlID0gRkFMU0UpLCBdDQogIGRhZG9zIDwtIGNhbGN1bGFyX3BhZHJvZXMoY2VsdWxhLCBwb250b3NfZGVudHJvKQ0KICAjIEdhcmFudGUgcXVlIHNlbXByZSByZXRvcm5hIHVtYSDDum5pY2EgbGluaGEgY29tIG8gSUQNCiAgZGFkb3MkSUQgPC0gaQ0KICByZXR1cm4oZGFkb3NbMSwgXSkNCn0pDQoNCiMgMy4gSnVudGFyIHJlc3VsdGFkb3MgYW8gZ3JpZA0KcmVzdWx0YWRvc19kZiA8LSBkby5jYWxsKHJiaW5kLCByZXN1bHRhZG9zKQ0KZ3JpZF9yZXN1bHRhZG8gPC0gY2JpbmQoZ3JpZCwgcmVzdWx0YWRvc19kZikNClZpZXcoZ3JpZF9yZXN1bHRhZG8pDQoNCiMgNC4gRXhwb3J0YXIgcmVzdWx0YWRvIHBhcmEgbyBRR0lTDQpzdF93cml0ZShncmlkX3Jlc3VsdGFkbywgImdyaWRfcmVzdWx0YWRvX2NsYXJrZXZhbnMuc2hwIiwgZGVsZXRlX2RzbiA9IFRSVUUpDQpgYGANCg0KIyAqMy4yIC0gw41uZGljZSBkZSBNb3Jpc2l0YSoNCg0KPiBPIE1vcmlzaXRhIMOpIGlkZWFsIHBhcmEgcGFkcsO1ZXMgZGUgY29udGFnZW0gZW0gc3Viw6FyZWFzLCBtZXNtbyBjb20gcG91Y2FzIMOhcnZvcmVzIHBvciBjw6lsdWxhLiBDYWRhIGNlbHVsYSBkbyBncmlkIMOpIGRpdmlkaWRhIGVtIHVtYSBzdWJkaXZpc8OjbyB2aXJ0dWFsIGVtIGdyYWRlIChleDogNHg0IHF1YWRyYWRvcyA9IDE2IHN1YsOhcmVhcykgZSDDqSBjb250YWRvIHF1YW50YXMgw6Fydm9yZXMgcXVlIGNhZW0gZW0gY2FkYSB1bWEuIEEgcGFydGlyIGRpc3NvLCDDqSBjYWxjdWxhZG8gbyDDrW5kaWNlIGRlIE1vcmlzaXRhIHBvciBjw6lsdWxhLg0KDQpgYGB7cn0NCiMgMS4gY3JpYXIgZnVuw6fDo28NCg0KY2FsY3VsYXJfcGFkcm9lc19tb3Jpc2l0YSA9IGZ1bmN0aW9uKGNlbHVsYSwgcG9udG9zX2NlbHVsYSwgbl9zdWIgPSA0KSB7DQogIGlmIChucm93KHBvbnRvc19jZWx1bGEpIDwgMikgew0KICAgIHJldHVybihkYXRhLmZyYW1lKHBhZHJhbyA9ICJJbnN1ZmljaWVudGUiLCBJZCA9IE5BKSkNCiAgfQ0KICAjIENyaWEgamFuZWxhIGUgb2JqZXRvIHBwcA0KICBqYW5lbGEgPC0gYXMub3dpbihzdF9nZW9tZXRyeShjZWx1bGEpKQ0KICBjb29yZHMgPC0gc3RfY29vcmRpbmF0ZXMocG9udG9zX2NlbHVsYSkNCiAgcHBwX29iaiA8LSBwcHAoeCA9IGNvb3Jkc1ssMV0sIHkgPSBjb29yZHNbLDJdLCB3aW5kb3cgPSBqYW5lbGEpDQogICMgU3ViZGl2aWRlIGEgY8OpbHVsYSBlbSB1bWEgZ3JhZGUgKG5fc3ViIHggbl9zdWIpDQogIHN1YmRpdiA8LSBxdWFkcmF0cyhqYW5lbGEsIG54ID0gbl9zdWIsIG55ID0gbl9zdWIpDQogIGNvbnRhZ2VucyA8LSBxdWFkcmF0Y291bnQocHBwX29iaiwgdGVzcyA9IHN1YmRpdikNCiAgeCA8LSBhcy52ZWN0b3IoY29udGFnZW5zKQ0KICBOIDwtIHN1bSh4KQ0KICBuIDwtIGxlbmd0aCh4KQ0KICBpZiAoTiA8PSAxKSB7DQogICAgcmV0dXJuKGRhdGEuZnJhbWUocGFkcmFvID0gIkluc3VmaWNpZW50ZSIsIElkID0gTkEpKQ0KICB9DQogIElkIDwtIChuICogc3VtKHggKiAoeCAtIDEpKSkgLyAoTiAqIChOIC0gMSkpDQogIHBhZHJhbyA8LSBpZmVsc2UoSWQgPiAxLCAiQWdyZWdhZG8iLA0KICAgICAgICAgICAgICAgICAgIGlmZWxzZShJZCA8IDEsICJEaXNwZXJzbyIsICJBbGVhdMOzcmlvIikpDQogIHJldHVybihkYXRhLmZyYW1lKHBhZHJhbyA9IHBhZHJhbywgSWQgPSBJZCkpDQp9DQoNCiMgMi4gTG9vcCBzb2JyZSBjw6lsdWxhcyBkbyBncmlkDQpyZXN1bHRhZG9zMSA8LSBsYXBwbHkoMTpucm93KGdyaWQpLCBmdW5jdGlvbihpKSB7DQogIGNlbHVsYSA8LSBncmlkW2ksIF0NCiAgcG9udG9zX2RlbnRybyA8LSBwb250b3Nfc2Zbc3Rfd2l0aGluKHBvbnRvc19zZiwgY2VsdWxhLCBzcGFyc2UgPSBGQUxTRSksIF0NCiAgZGFkb3MgPC0gY2FsY3VsYXJfcGFkcm9lc19tb3Jpc2l0YShjZWx1bGEsIHBvbnRvc19kZW50cm8pDQogICMgR2FyYW50ZSBxdWUgc2VtcHJlIHJldG9ybmEgdW1hIMO6bmljYSBsaW5oYSBjb20gbyBJRA0KICBkYWRvcyRJRCA8LSBpDQogIHJldHVybihkYWRvc1sxLCBdKQ0KfSkNCg0KIyAzLiBKdW50YXIgcmVzdWx0YWRvcyBhbyBncmlkDQpyZXN1bHRhZG9zX2RmMSA8LSBkby5jYWxsKHJiaW5kLCByZXN1bHRhZG9zMSkNCmdyaWRfcmVzdWx0YWRvMSA8LSBjYmluZChncmlkLCByZXN1bHRhZG9zX2RmMSkNClZpZXcoZ3JpZF9yZXN1bHRhZG8xKQ0KZ3JpZF9yZXN1bHRhZG8xIDwtIGdyaWRfcmVzdWx0YWRvMSAlPiUNCiAgcmVuYW1lKA0KICAgIGFyZWFfbTIgPSBhcmVhLA0KICAgIGlkX2dyaWQgPSBJRC5HcmlkLA0KICAgIHBhZHJhb19tb3Jpc2l0YSA9IHBhZHJhbywNCiAgICBpZF9tb3Jpc2l0YSA9IElkLA0KICAgIGlkX2NlbHVsYSA9IElEDQogICkNCm5hbWVzKGdyaWRfcmVzdWx0YWRvMSkNCg0KIyA0LiBFeHBvcnRhciBwYXJhIHVzbyBubyBRR0lTDQpzdF93cml0ZShncmlkX3Jlc3VsdGFkbzEsICJncmlkX3Jlc3VsdGFkb19tb3Jpc2l0YV92Mi5ncGtnIiwgbGF5ZXIgPSAibW9yaXNpdGEiLCBkZWxldGVfbGF5ZXIgPSBUUlVFKQ0KYGBgDQoNCiMgKjQgLSBDb21wYXJhw6fDo28gZW50cmUgQ2xhcmstRXZhbnMgdnMgTW9yaXNpdGEqDQoNCmBgYHtyfQ0KIyBKdW50YXIgcmVzdWx0YWRvcyBwZWxvIElEDQpjb21wYXJhdGl2byA8LSBncmlkX3Jlc3VsdGFkbyAlPiUNCiAgc2VsZWN0KGlkX2NlbHVsYSA9IElELCBwYWRyYW9fY2xhcmsgPSBwYWRyYW8sIFIpICU+JQ0KICBpbm5lcl9qb2luKA0KICAgIHN0X2Ryb3BfZ2VvbWV0cnkoZ3JpZF9yZXN1bHRhZG8xKSAlPiUNCiAgICAgIHNlbGVjdChpZF9jZWx1bGEsIHBhZHJhb19tb3Jpc2l0YSwgaWRfbW9yaXNpdGEpLA0KICAgIGJ5ID0gImlkX2NlbHVsYSINCiAgKQ0KY29tcGFyYXRpdm8NCiNUYWJlbGEgZGUgY29uY29yZMOibmNpYQ0KdGFibGUoY29tcGFyYXRpdm8kcGFkcmFvX2NsYXJrLCBjb21wYXJhdGl2byRwYWRyYW9fbW9yaXNpdGEpDQojUG9yY2VudGFnZW0gZGUgY29uY29yZMOibmNpYQ0KbWVhbihjb21wYXJhdGl2byRwYWRyYW9fY2xhcmsgPT0gY29tcGFyYXRpdm8kcGFkcmFvX21vcmlzaXRhLCBuYS5ybSA9IFRSVUUpDQojVmlzdWFsaXphciBjw6lsdWxhcyBkaXNjcmVwYW50ZXMNCmNvbXBhcmF0aXZvX2Rpc2NyZXBhbnRlIDwtIGNvbXBhcmF0aXZvICU+JQ0KICBmaWx0ZXIocGFkcmFvX2NsYXJrICE9IHBhZHJhb19tb3Jpc2l0YSkNClZpZXcoY29tcGFyYXRpdm9fZGlzY3JlcGFudGUpDQojTWFwYSBkYSBjb21wYXJhw6fDo28gbm8gZ2dwbG90Mg0KZ2dwbG90KGNvbXBhcmF0aXZvKSArDQogIGdlb21fc2YoYWVzKGZpbGwgPSBpbnRlcmFjdGlvbihwYWRyYW9fY2xhcmssIHBhZHJhb19tb3Jpc2l0YSkpLCBjb2xvciA9ICJncmF5NzAiLCBzaXplID0gMC4xKSArDQogIGxhYnModGl0bGUgPSAiQ29tcGFyYcOnw6NvIGRvcyBwYWRyw7VlczogQ2xhcmstRXZhbnMgdnMgTW9yaXNpdGEiLA0KICAgICAgIGZpbGwgPSAiQ2xhcmsgLyBNb3Jpc2l0YSIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCmBgYA0KDQojICozLjMgLSDDjW5kaWNlIGRlIE1vcmlzaXRhIGFkYXB0YWRvKg0KDQo+IE5lc3RhIGFib3JkYWdlbSBmaXogdW1hIG11ZGFuw6dhIG5hIGVxdWHDp8OjbyBwYXJhIGNvbnNpZGVyYXIgYSBhcmVhIG9jdXBhZGEgcGVsYSBjb3BhLCBlbSB2ZXogZGUgYXBlbmFzIGEgY29vcmRlbmFkYS4NCg0KYGBge3J9DQojMS4gY3JpYXIgZnVuw6fDo28NCg0KY2FsY3VsYXJfcGFkcm9lc19tb3Jpc2l0YV9hcmVhIDwtIGZ1bmN0aW9uKGNlbHVsYSwgc29tYnJhLCBuX3N1YiA9IDQpIHsNCiAgc29tYnJhX2NsaXAgPC0gc3RfaW50ZXJzZWN0aW9uKHNvbWJyYSwgY2VsdWxhKQ0KICBpZiAobnJvdyhzb21icmFfY2xpcCkgPT0gMCkgew0KICAgIHJldHVybihkYXRhLmZyYW1lKHBhZHJhbyA9ICJJbnN1ZmljaWVudGUiLCBJZF9hcmVhID0gTkEpKQ0KICB9DQogICMgRGl2aWRpciBvIGdyaWQgZW0gc3Viw6FyZWFzDQogIHN1YmRpdmlzb2VzIDwtIHN0X21ha2VfZ3JpZChjZWx1bGEsIG4gPSBjKG5fc3ViLCBuX3N1YikpIHw+IHN0X2FzX3NmKCkNCiAgc3ViZGl2aXNvZXMgPC0gc3RfaW50ZXJzZWN0aW9uKHN1YmRpdmlzb2VzLCBjZWx1bGEpDQogICMgSW50ZXJzZcOnw6NvIGVudHJlIHNvbWJyYSBlIHN1YsOhcmVhcw0KICBpbnRlcnNlYyA8LSBzdF9pbnRlcnNlY3Rpb24oc29tYnJhX2NsaXAsIHN1YmRpdmlzb2VzKQ0KICBpZiAobnJvdyhpbnRlcnNlYykgPT0gMCkgew0KICAgIHJldHVybihkYXRhLmZyYW1lKHBhZHJhbyA9ICJJbnN1ZmljaWVudGUiLCBJZF9hcmVhID0gTkEpKQ0KICB9DQogIGludGVyc2VjJGFyZWFfaW50ZXJzZWMgPC0gc3RfYXJlYShpbnRlcnNlYykNCiAgYXJlYV9wb3Jfc3ViIDwtIGludGVyc2VjIHw+DQogICAgZ3JvdXBfYnkoc3ViX2lkID0gcm93X251bWJlcigpKSB8Pg0KICAgIHN1bW1hcmlzZShhcmVhX3RvdGFsID0gc3VtKGFzLm51bWVyaWMoYXJlYV9pbnRlcnNlYykpKSB8Pg0KICAgIHVuZ3JvdXAoKQ0KICBBIDwtIGFyZWFfcG9yX3N1YiRhcmVhX3RvdGFsDQogIG4gPC0gbGVuZ3RoKEEpDQogIEFfdG90YWwgPC0gc3VtKEEpDQogIEFfbWVhbiA8LSBtZWFuKEEpDQogIGlmIChBX3RvdGFsID09IDAgfHwgQV90b3RhbCA9PSBBX21lYW4pIHsNCiAgICByZXR1cm4oZGF0YS5mcmFtZShwYWRyYW8gPSAiSW5zdWZpY2llbnRlIiwgSWRfYXJlYSA9IE5BKSkNCiAgfQ0KICBJZF9zdGFyIDwtIChuICogc3VtKChBIC0gQV9tZWFuKV4yKSkgLyAoQV90b3RhbCAqIChBX3RvdGFsIC0gQV9tZWFuKSkNCiAgcGFkcmFvIDwtIGlmZWxzZShJZF9zdGFyID4gMSwgIkFncmVnYWRvIiwgIkRpc3BlcnNvIikNCiAgcmV0dXJuKGRhdGEuZnJhbWUocGFkcmFvID0gcGFkcmFvLCBJZF9hcmVhID0gSWRfc3RhcikpDQp9DQoNCiMgMi4gTG9vcCBzb2JyZSBjYWRhIGPDqWx1bGEgZG8gZ3JpZA0KcmVzdWx0YWRvcyA9IGxhcHBseSgxOm5yb3coZ3JpZCksIGZ1bmN0aW9uKGkpIHsNCiAgY2VsdWxhIDwtIGdyaWRbaSwgXQ0KICBkYWRvcyA8LSBjYWxjdWxhcl9wYWRyb2VzX21vcmlzaXRhX2FyZWEoY2VsdWxhLCBhcmVhX3NvbWJyZWFkYV9yZWFsKQ0KICBkYWRvcyRJRCA8LSBpDQogIHJldHVybihkYWRvc1sxLCBdKQ0KfSkNCg0KIyAzLiBKdW50YXIgY29tIG8gZ3JpZCBvcmlnaW5hbA0KcmVzdWx0YWRvc19kZiA8LSBkby5jYWxsKHJiaW5kLCByZXN1bHRhZG9zKQ0KZ3JpZF9yZXN1bHRhZG9fYXJlYSA8LSBjYmluZChncmlkLCByZXN1bHRhZG9zX2RmKQ0KVmlldyhncmlkX3Jlc3VsdGFkb19hcmVhKQ0KDQojIDQuIEV4cG9ydGFyIHBhcmEgdXNvIG5vIFFHSVMNCnN0X3dyaXRlKGdyaWRfcmVzdWx0YWRvX2FyZWEsICJncmlkX3Jlc3VsdGFkb19tb3Jpc2l0YV9hcmVhLmdwa2ciLCBsYXllciA9ICJtb3Jpc2l0YV9hcmVhIiwgZGVsZXRlX2xheWVyID0gVFJVRSkNCmBgYA0KDQojICo1IC0gUGxvdCBNb3Jpc2l0YSBhZGFwdGFkbyoNCg0KYGBge3J9DQpwbG90MyA9Z2dwbG90KCkgKw0KICBnZW9tX3NmKGRhdGEgPSBncmlkX3Jlc3VsdGFkb19hcmVhLCBhZXMoZmlsbCA9IHBhZHJhbyksIGNvbG9yID0gImdyYXkzMCIsIHNpemUgPSAwLjEpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwoDQogICAgdmFsdWVzID0gYygNCiAgICAgICJBZ3JlZ2FkbyIgPSAiZGFya2dyZWVuIiwNCiAgICAgICJEaXNwZXJzbyIgPSAiZ29sZGVucm9kMiIsDQogICAgICAiSW5zdWZpY2llbnRlIiA9ICJsaWdodGdyYXkiDQogICAgKSwNCiAgICBuYS52YWx1ZSA9ICJ3aGl0ZSIsDQogICAgbmFtZSA9ICJQYWRyw6NvIGRlIERpc3RyaWJ1acOnw6NvIg0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJQYWRyw6NvIGRlIGRpc3RyaWJ1acOnw6NvIGJhc2VhZG8gbmEgw6FyZWEgc29tYnJlYWRhICjDjW5kaWNlIE1vcmlzaXRhIEFkYXB0YWRvKSIsDQogICAgc3VidGl0bGUgPSAiQ2xhc3NpZmljYcOnw6NvOiBBZ3JlZ2FkbyAvIERpc3BlcnNvIC8gSW5zdWZpY2llbnRlIiwNCiAgICBmaWxsID0gIkRpc3RyaWJ1acOnw6NvIg0KICApICsNCiAgdGhlbWUoDQogICAgbGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxNCksDQogICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTEpDQogICkNCnBsb3QzDQpgYGANCg0KDQo=