Clustering

Contexto

Este documento aborda el estudio químico realizado sobre muestras de vino provenientes de tres viñedos distintos en una idéntica zona de Italia, explorando la composición química a través del análisis de trece componentes distintivos en cada variedad de vino.

Contenido Etanólico: Mide la proporción de etanol, influenciando directamente en la potencia y cuerpo del vino.

Ácido Orgánico Malico: Componente que incide en la acidez y frescura del vino, aportando equilibrio al sabor.

Residuo Mineral (Ceniza): Indicador de los minerales del suelo donde se cultivaron las uvas, reflejado en el residuo post-combustión.

Neutralidad Mineral (Alcalinidad de la Ceniza): Mide la neutralidad de los residuos minerales, afectando la sensación gustativa del vino.

Presencia de Magnesio: Elemental para la estructura y perfil gustativo del vino, derivado del contenido mineral.

Compuestos Fenólicos Totales: Incluyen antioxidantes naturales de las uvas, beneficiosos para la salud y esenciales para la calidad del vino.

Flavonoides: Contribuyen a la estructura, coloración y propiedades antioxidantes del vino.

Fenoles No Flavonoides: Afectan la astringencia y el sabor del vino, diferenciándose de los flavonoides.

Proantocianidinas: Estos compuestos fenólicos mejoran la astringencia y ofrecen antioxidantes, esenciales en la piel y semillas de las uvas.

Intensidad Cromática: Refleja la densidad de color del vino, revelando la concentración de pigmentos.

Matiz Cromático: Describe la tonalidad específica del vino, variando entre rojo, morado y naranja.

Absorbancia OD280: Este índice de absorción óptica está relacionado con la riqueza fenólica del vino.

Prolina: Este aminoácido señala la madurez de la uva y el proceso de fermentación, afectando el perfil final del vino.

Cada elemento analizado aporta a la identificación y diferenciación de los vinos, destacando la rica diversidad y complejidad inherente a su producción.

Conoce más: Tipos de vinos

Paso 1 - Instalar librerías

library(cluster)
#install.packages("ggplot2")

library(ggplot2)
#install.packages("data.table")

library(data.table)
#install.packages("factoextra")

library(factoextra)

Paso 2 - Obtener los datos

datos <- read.csv("/Users/gabrielmedina/Downloads/M2/wine.csv")

summary(datos)
##     Alcohol        Malic_Acid         Ash         Ash_Alcanity  
##  Min.   :11.03   Min.   :0.740   Min.   :1.360   Min.   :10.60  
##  1st Qu.:12.36   1st Qu.:1.603   1st Qu.:2.210   1st Qu.:17.20  
##  Median :13.05   Median :1.865   Median :2.360   Median :19.50  
##  Mean   :13.00   Mean   :2.336   Mean   :2.367   Mean   :19.49  
##  3rd Qu.:13.68   3rd Qu.:3.083   3rd Qu.:2.558   3rd Qu.:21.50  
##  Max.   :14.83   Max.   :5.800   Max.   :3.230   Max.   :30.00  
##    Magnesium      Total_Phenols     Flavanoids    Nonflavanoid_Phenols
##  Min.   : 70.00   Min.   :0.980   Min.   :0.340   Min.   :0.1300      
##  1st Qu.: 88.00   1st Qu.:1.742   1st Qu.:1.205   1st Qu.:0.2700      
##  Median : 98.00   Median :2.355   Median :2.135   Median :0.3400      
##  Mean   : 99.74   Mean   :2.295   Mean   :2.029   Mean   :0.3619      
##  3rd Qu.:107.00   3rd Qu.:2.800   3rd Qu.:2.875   3rd Qu.:0.4375      
##  Max.   :162.00   Max.   :3.880   Max.   :5.080   Max.   :0.6600      
##  Proanthocyanins Color_Intensity       Hue             OD280      
##  Min.   :0.410   Min.   : 1.280   Min.   :0.4800   Min.   :1.270  
##  1st Qu.:1.250   1st Qu.: 3.220   1st Qu.:0.7825   1st Qu.:1.938  
##  Median :1.555   Median : 4.690   Median :0.9650   Median :2.780  
##  Mean   :1.591   Mean   : 5.058   Mean   :0.9574   Mean   :2.612  
##  3rd Qu.:1.950   3rd Qu.: 6.200   3rd Qu.:1.1200   3rd Qu.:3.170  
##  Max.   :3.580   Max.   :13.000   Max.   :1.7100   Max.   :4.000  
##     Proline      
##  Min.   : 278.0  
##  1st Qu.: 500.5  
##  Median : 673.5  
##  Mean   : 746.9  
##  3rd Qu.: 985.0  
##  Max.   :1680.0

Paso 3 - Escalar los datos

df <- scale(datos)

Paso 4 - Optimizar la cantidad de grupos

La cantidad óptima de grupos corresponde al punto más alto…

set.seed(123)

optimizacion <- clusGap(df, FUN=kmeans, nstart=1, K.max = 8)

plot(optimizacion, xlab = "Número de clusters")

Paso 5 - Asignar la cantidad óptima de grupos

El número más óptimo fue 3 grupos.

grupos <- 3

Paso 6 - Generar los segmentos

segmentos <- kmeans(df, grupos)

segmentos
## K-means clustering with 3 clusters of sizes 65, 51, 62
## 
## Cluster means:
##      Alcohol Malic_Acid        Ash Ash_Alcanity   Magnesium Total_Phenols
## 1 -0.9234669 -0.3929331 -0.4931257    0.1701220 -0.49032869   -0.07576891
## 2  0.1644436  0.8690954  0.1863726    0.5228924 -0.07526047   -0.97657548
## 3  0.8328826 -0.3029551  0.3636801   -0.6084749  0.57596208    0.88274724
##    Flavanoids Nonflavanoid_Phenols Proanthocyanins Color_Intensity        Hue
## 1  0.02075402          -0.03343924      0.05810161      -0.8993770  0.4605046
## 2 -1.21182921           0.72402116     -0.77751312       0.9388902 -1.1615122
## 3  0.97506900          -0.56050853      0.57865427       0.1705823  0.4726504
##        OD280    Proline
## 1  0.2700025 -0.7517257
## 2 -1.2887761 -0.4059428
## 3  0.7770551  1.1220202
## 
## Clustering vector:
##   [1] 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
##  [38] 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 1 1 2 1 1 1 1 1 1 1 1 1 1 1 3
##  [75] 1 1 1 1 1 1 1 1 1 2 1 1 1 1 1 1 1 1 1 1 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
## [112] 1 1 1 1 1 1 1 2 1 1 3 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
## [149] 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
## 
## Within cluster sum of squares by cluster:
## [1] 558.6971 326.3537 385.6983
##  (between_SS / total_SS =  44.8 %)
## 
## Available components:
## 
## [1] "cluster"      "centers"      "totss"        "withinss"     "tot.withinss"
## [6] "betweenss"    "size"         "iter"         "ifault"

Paso 7 - Asignar el grupo al que pertenece cada observación

asignacion <- cbind(cluster = segmentos$cluster, datos)

head(asignacion)
##   cluster Alcohol Malic_Acid  Ash Ash_Alcanity Magnesium Total_Phenols
## 1       3   14.23       1.71 2.43         15.6       127          2.80
## 2       3   13.20       1.78 2.14         11.2       100          2.65
## 3       3   13.16       2.36 2.67         18.6       101          2.80
## 4       3   14.37       1.95 2.50         16.8       113          3.85
## 5       3   13.24       2.59 2.87         21.0       118          2.80
## 6       3   14.20       1.76 2.45         15.2       112          3.27
##   Flavanoids Nonflavanoid_Phenols Proanthocyanins Color_Intensity  Hue OD280
## 1       3.06                 0.28            2.29            5.64 1.04  3.92
## 2       2.76                 0.26            1.28            4.38 1.05  3.40
## 3       3.24                 0.30            2.81            5.68 1.03  3.17
## 4       3.49                 0.24            2.18            7.80 0.86  3.45
## 5       2.69                 0.39            1.82            4.32 1.04  2.93
## 6       3.39                 0.34            1.97            6.75 1.05  2.85
##   Proline
## 1    1065
## 2    1050
## 3    1185
## 4    1480
## 5     735
## 6    1450

Paso 8 - Graficar los clusters

fviz_cluster(segmentos, data = datos)

Paso 9 - Comparación de cada cluster

promedio <- aggregate(asignacion, by = list(asignacion$cluster), FUN=mean)
promedio
##   Group.1 cluster  Alcohol Malic_Acid      Ash Ash_Alcanity Magnesium
## 1       1       1 12.25092   1.897385 2.231231     20.06308  92.73846
## 2       2       2 13.13412   3.307255 2.417647     21.24118  98.66667
## 3       3       3 13.67677   1.997903 2.466290     17.46290 107.96774
##   Total_Phenols Flavanoids Nonflavanoid_Phenols Proanthocyanins Color_Intensity
## 1      2.247692  2.0500000            0.3576923        1.624154        2.973077
## 2      1.683922  0.8188235            0.4519608        1.145882        7.234706
## 3      2.847581  3.0032258            0.2920968        1.922097        5.453548
##         Hue    OD280   Proline
## 1 1.0627077 2.803385  510.1692
## 2 0.6919608 1.696667  619.0588
## 3 1.0654839 3.163387 1100.2258

Conclusiones

El análisis de clustering realizado sobre muestras de vino de tres viñedos italianos ha permitido identificar tres grupos distintos basados en su composición química, utilizando herramientas de análisis de datos en R. Este enfoque ha demostrado ser eficaz para clasificar los vinos según sus perfiles químicos únicos, resaltando la importancia de los componentes analizados en la definición de sus características. La segmentación efectiva de las muestras resalta el valor del análisis de datos en la comprensión y diferenciación de los vinos, ofreciendo perspectivas prácticas para su clasificación y apreciación en la industria.

LS0tCnRpdGxlOiAiUHJhY3RpY2EgMiAtIFdpbmUiCmF1dGhvcjogIkdhYnJpZWwgTWVkaW5hIgpkYXRlOiAiMjAyNC0wMi0yMSIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwogICAgY29kZV9kb3dubG9hZDogeWVzCiAgICB0aGVtZTogY29zbW8KICAgIGhpZ2hsaWdodDogdGFuZ28KICBwZGZfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwotLS0KCjxzdHlsZT4KaDEsIGgyLCBoMywgaDQsIGg1LCBoNiB7CiAgY29sb3I6IHJlZDsKfQouYXV0aG9yLCAuZGF0ZSB7CiAgY29sb3I6IHJlZDsKfQo8L3N0eWxlPgoKIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiByZWQ7Ij5DbHVzdGVyaW5nPC9zcGFuPgoKIVtdKC9Vc2Vycy9nYWJyaWVsbWVkaW5hL0Rvd25sb2Fkcy9NMi92aW5vLmdpZikKCiMgQ29udGV4dG8KCkVzdGUgZG9jdW1lbnRvIGFib3JkYSBlbCBlc3R1ZGlvIHF1w61taWNvIHJlYWxpemFkbyBzb2JyZSBtdWVzdHJhcyBkZSB2aW5vIHByb3ZlbmllbnRlcyBkZSB0cmVzIHZpw7FlZG9zIGRpc3RpbnRvcyBlbiB1bmEgaWTDqW50aWNhIHpvbmEgZGUgSXRhbGlhLCBleHBsb3JhbmRvIGxhIGNvbXBvc2ljacOzbiBxdcOtbWljYSBhIHRyYXbDqXMgZGVsIGFuw6FsaXNpcyBkZSB0cmVjZSBjb21wb25lbnRlcyBkaXN0aW50aXZvcyBlbiBjYWRhIHZhcmllZGFkIGRlIHZpbm8uCgpDb250ZW5pZG8gRXRhbsOzbGljbzogTWlkZSBsYSBwcm9wb3JjacOzbiBkZSBldGFub2wsIGluZmx1ZW5jaWFuZG8gZGlyZWN0YW1lbnRlIGVuIGxhIHBvdGVuY2lhIHkgY3VlcnBvIGRlbCB2aW5vLgoKw4FjaWRvIE9yZ8OhbmljbyBNYWxpY286IENvbXBvbmVudGUgcXVlIGluY2lkZSBlbiBsYSBhY2lkZXogeSBmcmVzY3VyYSBkZWwgdmlubywgYXBvcnRhbmRvIGVxdWlsaWJyaW8gYWwgc2Fib3IuCgpSZXNpZHVvIE1pbmVyYWwgKENlbml6YSk6IEluZGljYWRvciBkZSBsb3MgbWluZXJhbGVzIGRlbCBzdWVsbyBkb25kZSBzZSBjdWx0aXZhcm9uIGxhcyB1dmFzLCByZWZsZWphZG8gZW4gZWwgcmVzaWR1byBwb3N0LWNvbWJ1c3Rpw7NuLgoKTmV1dHJhbGlkYWQgTWluZXJhbCAoQWxjYWxpbmlkYWQgZGUgbGEgQ2VuaXphKTogTWlkZSBsYSBuZXV0cmFsaWRhZCBkZSBsb3MgcmVzaWR1b3MgbWluZXJhbGVzLCBhZmVjdGFuZG8gbGEgc2Vuc2FjacOzbiBndXN0YXRpdmEgZGVsIHZpbm8uCgpQcmVzZW5jaWEgZGUgTWFnbmVzaW86IEVsZW1lbnRhbCBwYXJhIGxhIGVzdHJ1Y3R1cmEgeSBwZXJmaWwgZ3VzdGF0aXZvIGRlbCB2aW5vLCBkZXJpdmFkbyBkZWwgY29udGVuaWRvIG1pbmVyYWwuCgpDb21wdWVzdG9zIEZlbsOzbGljb3MgVG90YWxlczogSW5jbHV5ZW4gYW50aW94aWRhbnRlcyBuYXR1cmFsZXMgZGUgbGFzIHV2YXMsIGJlbmVmaWNpb3NvcyBwYXJhIGxhIHNhbHVkIHkgZXNlbmNpYWxlcyBwYXJhIGxhIGNhbGlkYWQgZGVsIHZpbm8uCgpGbGF2b25vaWRlczogQ29udHJpYnV5ZW4gYSBsYSBlc3RydWN0dXJhLCBjb2xvcmFjacOzbiB5IHByb3BpZWRhZGVzIGFudGlveGlkYW50ZXMgZGVsIHZpbm8uCgpGZW5vbGVzIE5vIEZsYXZvbm9pZGVzOiBBZmVjdGFuIGxhIGFzdHJpbmdlbmNpYSB5IGVsIHNhYm9yIGRlbCB2aW5vLCBkaWZlcmVuY2nDoW5kb3NlIGRlIGxvcyBmbGF2b25vaWRlcy4KClByb2FudG9jaWFuaWRpbmFzOiBFc3RvcyBjb21wdWVzdG9zIGZlbsOzbGljb3MgbWVqb3JhbiBsYSBhc3RyaW5nZW5jaWEgeSBvZnJlY2VuIGFudGlveGlkYW50ZXMsIGVzZW5jaWFsZXMgZW4gbGEgcGllbCB5IHNlbWlsbGFzIGRlIGxhcyB1dmFzLgoKSW50ZW5zaWRhZCBDcm9tw6F0aWNhOiBSZWZsZWphIGxhIGRlbnNpZGFkIGRlIGNvbG9yIGRlbCB2aW5vLCByZXZlbGFuZG8gbGEgY29uY2VudHJhY2nDs24gZGUgcGlnbWVudG9zLgoKTWF0aXogQ3JvbcOhdGljbzogRGVzY3JpYmUgbGEgdG9uYWxpZGFkIGVzcGVjw61maWNhIGRlbCB2aW5vLCB2YXJpYW5kbyBlbnRyZSByb2pvLCBtb3JhZG8geSBuYXJhbmphLgoKQWJzb3JiYW5jaWEgT0QyODA6IEVzdGUgw61uZGljZSBkZSBhYnNvcmNpw7NuIMOzcHRpY2EgZXN0w6EgcmVsYWNpb25hZG8gY29uIGxhIHJpcXVlemEgZmVuw7NsaWNhIGRlbCB2aW5vLgoKUHJvbGluYTogRXN0ZSBhbWlub8OhY2lkbyBzZcOxYWxhIGxhIG1hZHVyZXogZGUgbGEgdXZhIHkgZWwgcHJvY2VzbyBkZSBmZXJtZW50YWNpw7NuLCBhZmVjdGFuZG8gZWwgcGVyZmlsIGZpbmFsIGRlbCB2aW5vLgoKQ2FkYSBlbGVtZW50byBhbmFsaXphZG8gYXBvcnRhIGEgbGEgaWRlbnRpZmljYWNpw7NuIHkgZGlmZXJlbmNpYWNpw7NuIGRlIGxvcyB2aW5vcywgZGVzdGFjYW5kbyBsYSByaWNhIGRpdmVyc2lkYWQgeSBjb21wbGVqaWRhZCBpbmhlcmVudGUgYSBzdSBwcm9kdWNjacOzbi4KCgpDb25vY2UgbcOhczogW1RpcG9zIGRlIHZpbm9zXShodHRwczovL3d3dy5zb2xhcmRlc2FtYW5pZWdvLmNvbS9ibG9nL3F1ZS10aXBvcy1kZS12aW5vcy1leGlzdGVuLXktY3VhbGVzLXNvbi1zdXMtY2FyYWN0ZXJpc3RpY2FzKQoKCiMjIDxzcGFuIHN0eWxlPSJjb2xvcjogYmxhY2s7Ij5QYXNvIDEgLSBJbnN0YWxhciBsaWJyZXLDrWFzPC9zcGFuPgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbGlicmFyeShjbHVzdGVyKQojaW5zdGFsbC5wYWNrYWdlcygiZ2dwbG90MiIpCgpsaWJyYXJ5KGdncGxvdDIpCiNpbnN0YWxsLnBhY2thZ2VzKCJkYXRhLnRhYmxlIikKCmxpYnJhcnkoZGF0YS50YWJsZSkKI2luc3RhbGwucGFja2FnZXMoImZhY3RvZXh0cmEiKQoKbGlicmFyeShmYWN0b2V4dHJhKQpgYGAKCgojIyA8c3BhbiBzdHlsZT0iY29sb3I6IGJsYWNrOyI+UGFzbyAyIC0gT2J0ZW5lciBsb3MgZGF0b3M8L3NwYW4+CgoKYGBge3IgfQoKZGF0b3MgPC0gcmVhZC5jc3YoIi9Vc2Vycy9nYWJyaWVsbWVkaW5hL0Rvd25sb2Fkcy9NMi93aW5lLmNzdiIpCgpzdW1tYXJ5KGRhdG9zKQoKYGBgCgojIyA8c3BhbiBzdHlsZT0iY29sb3I6IGJsYWNrOyI+UGFzbyAzIC0gRXNjYWxhciBsb3MgZGF0b3M8L3NwYW4+CgpgYGB7ciB9CgpkZiA8LSBzY2FsZShkYXRvcykKCmBgYAoKIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBibGFjazsiPlBhc28gNCAtIE9wdGltaXphciBsYSBjYW50aWRhZCBkZSBncnVwb3M8L3NwYW4+CgoKTGEgY2FudGlkYWQgw7NwdGltYSBkZSBncnVwb3MgY29ycmVzcG9uZGUgYWwgcHVudG8gbcOhcyBhbHRvLi4uCgoKYGBge3IgfQpzZXQuc2VlZCgxMjMpCgpvcHRpbWl6YWNpb24gPC0gY2x1c0dhcChkZiwgRlVOPWttZWFucywgbnN0YXJ0PTEsIEsubWF4ID0gOCkKCnBsb3Qob3B0aW1pemFjaW9uLCB4bGFiID0gIk7Dum1lcm8gZGUgY2x1c3RlcnMiKQoKYGBgCgojIyA8c3BhbiBzdHlsZT0iY29sb3I6IGJsYWNrOyI+UGFzbyA1IC0gQXNpZ25hciBsYSBjYW50aWRhZCDDs3B0aW1hIGRlIGdydXBvczwvc3Bhbj4KCkVsIG7Dum1lcm8gbcOhcyDDs3B0aW1vIGZ1ZSAzIGdydXBvcy4KCmBgYHtyIH0KCmdydXBvcyA8LSAzCgpgYGAKCgojIyA8c3BhbiBzdHlsZT0iY29sb3I6IGJsYWNrOyI+UGFzbyA2IC0gR2VuZXJhciBsb3Mgc2VnbWVudG9zPC9zcGFuPgoKCmBgYHtyIH0KCnNlZ21lbnRvcyA8LSBrbWVhbnMoZGYsIGdydXBvcykKCnNlZ21lbnRvcwpgYGAKCiMjIDxzcGFuIHN0eWxlPSJjb2xvcjogYmxhY2s7Ij5QYXNvIDcgLSBBc2lnbmFyIGVsIGdydXBvIGFsIHF1ZSBwZXJ0ZW5lY2UgY2FkYSBvYnNlcnZhY2nDs248L3NwYW4+CgpgYGB7ciB9Cgphc2lnbmFjaW9uIDwtIGNiaW5kKGNsdXN0ZXIgPSBzZWdtZW50b3MkY2x1c3RlciwgZGF0b3MpCgpoZWFkKGFzaWduYWNpb24pCgpgYGAKCiMjIDxzcGFuIHN0eWxlPSJjb2xvcjogYmxhY2s7Ij5QYXNvIDggLSBHcmFmaWNhciBsb3MgY2x1c3RlcnM8L3NwYW4+CgpgYGB7ciB9Cgpmdml6X2NsdXN0ZXIoc2VnbWVudG9zLCBkYXRhID0gZGF0b3MpCgpgYGAKCgojIyA8c3BhbiBzdHlsZT0iY29sb3I6IGJsYWNrOyI+UGFzbyA5IC0gQ29tcGFyYWNpw7NuIGRlIGNhZGEgY2x1c3Rlcjwvc3Bhbj4KCmBgYHtyIH0KCnByb21lZGlvIDwtIGFnZ3JlZ2F0ZShhc2lnbmFjaW9uLCBieSA9IGxpc3QoYXNpZ25hY2lvbiRjbHVzdGVyKSwgRlVOPW1lYW4pCnByb21lZGlvCgpgYGAKCgojIENvbmNsdXNpb25lcwoKRWwgYW7DoWxpc2lzIGRlIGNsdXN0ZXJpbmcgcmVhbGl6YWRvIHNvYnJlIG11ZXN0cmFzIGRlIHZpbm8gZGUgdHJlcyB2acOxZWRvcyBpdGFsaWFub3MgaGEgcGVybWl0aWRvIGlkZW50aWZpY2FyIHRyZXMgZ3J1cG9zIGRpc3RpbnRvcyBiYXNhZG9zIGVuIHN1IGNvbXBvc2ljacOzbiBxdcOtbWljYSwgdXRpbGl6YW5kbyBoZXJyYW1pZW50YXMgZGUgYW7DoWxpc2lzIGRlIGRhdG9zIGVuIFIuIEVzdGUgZW5mb3F1ZSBoYSBkZW1vc3RyYWRvIHNlciBlZmljYXogcGFyYSBjbGFzaWZpY2FyIGxvcyB2aW5vcyBzZWfDum4gc3VzIHBlcmZpbGVzIHF1w61taWNvcyDDum5pY29zLCByZXNhbHRhbmRvIGxhIGltcG9ydGFuY2lhIGRlIGxvcyBjb21wb25lbnRlcyBhbmFsaXphZG9zIGVuIGxhIGRlZmluaWNpw7NuIGRlIHN1cyBjYXJhY3RlcsOtc3RpY2FzLiBMYSBzZWdtZW50YWNpw7NuIGVmZWN0aXZhIGRlIGxhcyBtdWVzdHJhcyByZXNhbHRhIGVsIHZhbG9yIGRlbCBhbsOhbGlzaXMgZGUgZGF0b3MgZW4gbGEgY29tcHJlbnNpw7NuIHkgZGlmZXJlbmNpYWNpw7NuIGRlIGxvcyB2aW5vcywgb2ZyZWNpZW5kbyBwZXJzcGVjdGl2YXMgcHLDoWN0aWNhcyBwYXJhIHN1IGNsYXNpZmljYWNpw7NuIHkgYXByZWNpYWNpw7NuIGVuIGxhIGluZHVzdHJpYS4KCgoKCg==