Introduction

Loading datasets

Loading dataset for adults

# Loading required libraries
library(tidyverse)
## Warning: package 'dplyr' was built under R version 4.4.3
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.5
## ✔ forcats   1.0.0     ✔ stringr   1.5.1
## ✔ ggplot2   3.5.1     ✔ tibble    3.2.1
## ✔ lubridate 1.9.3     ✔ tidyr     1.3.1
## ✔ purrr     1.0.2     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
# Step 1: Reading the CSV file
nhis_adult <- read_csv("C:/Users/aleja/Downloads/NHIS_Adult_Summary_Health_Statistics_20250511.csv")
## Rows: 20140 Columns: 8
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (6): Outcome (or Indicator), Grouping category, Group, Confidence Interv...
## dbl (2): Percentage, Year
## 
## ℹ 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.
# Step 2: Inspecting structure
glimpse(nhis_adult)
## Rows: 20,140
## Columns: 8
## $ `Outcome (or Indicator)` <chr> "Coronary heart disease", "Coronary heart dis…
## $ `Grouping category`      <chr> "Total", "Sex", "Sex", "Age groups with 65+",…
## $ Group                    <chr> "Total", "Male", "Female", "18-34 years", "35…
## $ Percentage               <dbl> 4.6, 5.9, 3.4, 0.3, 0.9, 5.4, 14.0, 0.5, 4.4,…
## $ `Confidence Interval`    <chr> "4.3,  4.9", "5.5,  6.3", "3.1,  3.7", "0.2, …
## $ Title                    <chr> "Percentage of coronary heart disease for adu…
## $ Description              <chr> "Respondents were asked if they had ever been…
## $ Year                     <dbl> 2019, 2019, 2019, 2019, 2019, 2019, 2019, 201…

Data cleaning

For dataset adults

Renaming columns

nhis_adult <- nhis_adult %>%
  rename(
    outcome_or_indicator = `Outcome (or Indicator)`,
    grouping_category = `Grouping category`,
    confidence_interval = `Confidence Interval`
  )

Checking for missing values

# Counting missing values per column
colSums(is.na(nhis_adult))
## outcome_or_indicator    grouping_category                Group 
##                    0                    0                    0 
##           Percentage  confidence_interval                Title 
##                    0                 1257                    0 
##          Description                 Year 
##                    0                    0

Dataset has 0 missing values or NA.

Exploring Available Outcomes (Look for Mental Health Topics)

# View unique health outcomes to find depression-related rows
unique(nhis_adult$outcome_or_indicator)
##  [1] "Coronary heart disease"                                                       
##  [2] "Any type of cancer"                                                           
##  [3] "Breast cancer"                                                                
##  [4] "Cervical cancer"                                                              
##  [5] "Prostate cancer"                                                              
##  [6] "Arthritis diagnosis"                                                          
##  [7] "Regularly experienced chronic pain"                                           
##  [8] "Diagnosed diabetes"                                                           
##  [9] "Did not get needed mental health care due to cost"                            
## [10] "Delayed getting medical care due to cost"                                     
## [11] "Did not take medication as prescribed to save money"                          
## [12] "Current asthma"                                                               
## [13] "Angina/angina pectoris"                                                       
## [14] "Difficulty hearing"                                                           
## [15] "Difficulty seeing"                                                            
## [16] "Taking prescription medication for feelings of worry, nervousness, or anxiety"
## [17] "Taking prescription medication for feelings of depression"                    
## [18] "Regularly had feelings of worry, nervousness, or anxiety"                     
## [19] "Regularly had feelings of depression"                                         
## [20] "Exchange-based coverage coverage at time of interview"                        
## [21] "Difficulty walking or climbing steps"                                         
## [22] "Difficulty communicating"                                                     
## [23] "Difficulty with self care"                                                    
## [24] "Difficulty remembering or concentrating"                                      
## [25] "Diagnosed hypertension"                                                       
## [26] "Six or more workdays missed due to illness, injury, or disability"            
## [27] "Receipt of influenza vaccination"                                             
## [28] "Ever received a pneumococcal vaccination"                                     
## [29] "Blood pressure check"                                                         
## [30] "Prescription medication use"                                                  
## [31] "Did not get needed medical care due to cost"                                  
## [32] "Fair or poor health status"                                                   
## [33] "Current cigarette smoking"                                                    
## [34] "Current electronic cigarette use"                                             
## [35] "Obesity"                                                                      
## [36] "Heart attack/myocardial infarction"                                           
## [37] "Has a usual place of care"                                                    
## [38] "Doctor visit"                                                                 
## [39] "Wellness visit"                                                               
## [40] "Asthma episode/attack"                                                        
## [41] "Hospital emergency department visit"                                          
## [42] "Counseled by a mental health professional"                                    
## [43] "Urgent care center or retail health clinic visit"                             
## [44] "Dental exam or cleaning"                                                      
## [45] "Uninsured at time of interview"                                               
## [46] "Private health insurance coverage at time of interview"                       
## [47] "Public health plan coverage at time of interview"                             
## [48] "COPD, emphysema, chronic bronchitis"                                          
## [49] "Uninsured for more than one year"                                             
## [50] "Uninsured for at least part of the past year"                                 
## [51] "Disability status (composite)"                                                
## [52] "High cholesterol"                                                             
## [53] "Any skin cancer"

To address the research objective of identifying early signs of mental health crises using social and economic data, this study focuses on a targeted subset of indicators from the National Health Interview Survey (NHIS) Adult dataset. Five indicators were selected based on their direct relevance to mental health distress, healthcare engagement, and access to services:

Regularly had feelings of depression

Taking prescription medication for feelings of depression

Regularly had feelings of worry, nervousness, or anxiety

Taking prescription medication for feelings of worry, nervousness, or anxiety

Did not get needed mental health care due to cost

These indicators were chosen for three key reasons. First, they offer early, self-reported symptoms of psychological distress (indicators 1 and 3), which are essential for detecting the onset of mental health crises prior to formal diagnosis. Second, they reflect engagement with the healthcare system through treatment behaviors (indicators 2 and 4), allowing the analysis to distinguish between treated and untreated populations. Third, they include a measure of unmet need due to financial barriers (indicator 5), a critical factor in understanding disparities in access to mental health services.

By focusing on these indicators, the analysis remains aligned with the study’s core hypotheses—specifically, that economic hardship, access limitations, and real-time sentiment are strong predictors of mental health deterioration. Additionally, this focused approach ensures analytical clarity, avoids redundancy, and enhances the interpretability of the results in predictive modeling contexts.

Filtering dataset:

mh_indicators <- nhis_adult %>%
  filter(outcome_or_indicator %in% c(
    "Regularly had feelings of depression",
    "Taking prescription medication for feelings of depression",
    "Regularly had feelings of worry, nervousness, or anxiety",
    "Taking prescription medication for feelings of worry, nervousness, or anxiety",
    "Did not get needed mental health care due to cost"
  ))
library(ggplot2)
library(stringr)

# Shortening long facet labels by wrapping them
mh_indicators <- mh_indicators %>%
  mutate(outcome_wrapped = str_wrap(outcome_or_indicator, width = 30))

# Plotting with rotated x-axis and wrapped facet labels
mh_indicators %>%
  filter(grouping_category == "Sex") %>%
  ggplot(aes(x = Year, y = Percentage, color = Group)) +
  geom_line(linewidth = 1.2) +
  facet_wrap(~ outcome_wrapped, scales = "free_y") +
  labs(
    title = "Trends in Mental Health Indicators by Sex (NHIS Adults)",
    x = "Year",
    y = "Percentage"
  ) +
  theme_minimal() +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1),  # rotates x labels
    strip.text = element_text(size = 10)                # reduces facet title size
  )

library(ggplot2)
library(stringr)

# Step 1: Wrap facet labels more tightly
mh_indicators <- mh_indicators %>%
  mutate(outcome_wrapped = str_wrap(outcome_or_indicator, width = 20))  # narrower wrap

# Step 2: Plot with smaller facet label size
mh_indicators %>%
  filter(grouping_category == "Sex") %>%
  ggplot(aes(x = Year, y = Percentage, color = Group)) +
  geom_line(linewidth = 1.2) +
  facet_wrap(~ outcome_wrapped, scales = "free_y") +
  labs(
    title = "Trends in Mental Health Indicators by Sex (NHIS Adults)",
    x = "Year",
    y = "Percentage"
  ) +
  theme_minimal() +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1),
    strip.text = element_text(size = 9),           # smaller facet titles
    plot.title = element_text(size = 13, face = "bold")
  )

Women report higher rates of depression, anxiety, and unmet mental health needs.

Comparing Mental Health Indicators by Sex and Income Level:

library(ggplot2)
library(stringr)
library(dplyr)

# Step 1: Filter only the 5 mental health indicators
indicators_of_interest <- c(
  "Symptoms of anxiety",
  "Symptoms of depression",
  "Regularly had feelings of worry, nervousness, or anxiety",
  "Taking prescription medication for feelings of worry, nervousness, or anxiety",
  "Did not get needed mental health care due to cost"
)

# Step 2: Filter and wrap labels
income_data <- mh_indicators %>%
  filter(grouping_category == "Family income",
         outcome_or_indicator %in% indicators_of_interest) %>%
  mutate(outcome_wrapped = str_wrap(outcome_or_indicator, width = 20))

# Step 3: Plot
ggplot(income_data, aes(x = Year, y = Percentage, color = Group)) +
  geom_line(linewidth = 1.2) +
  facet_wrap(~ outcome_wrapped, scales = "free_y") +
  labs(
    title = "Mental Health Indicators by Family Income (NHIS Adults)",
    x = "Year",
    y = "Percentage",
    color = "Income Group"
  ) +
  theme_minimal() +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1),
    strip.text = element_text(size = 9),
    plot.title = element_text(size = 13, face = "bold")
  )

library(ggplot2)
library(stringr)
library(dplyr)

# Step 1: Filtering only the 5 mental health indicators
indicators_of_interest <- c(
  "Symptoms of anxiety",
  "Symptoms of depression",
  "Regularly had feelings of worry, nervousness, or anxiety",
  "Taking prescription medication for feelings of worry, nervousness, or anxiety",
  "Did not get needed mental health care due to cost"
)

# Step 2: Filtering and assign short labels
income_data <- mh_indicators %>%
  filter(grouping_category == "Family income",
         outcome_or_indicator %in% indicators_of_interest) %>%
  mutate(outcome_wrapped = case_when(
    outcome_or_indicator == "Symptoms of anxiety" ~ "Frequent Anxiety",
    outcome_or_indicator == "Symptoms of depression" ~ "Frequent Depression",
    outcome_or_indicator == "Regularly had feelings of worry, nervousness, or anxiety" ~ "Worry/Nervousness",
    outcome_or_indicator == "Taking prescription medication for feelings of worry, nervousness, or anxiety" ~ "Anxiety Meds",
    outcome_or_indicator == "Did not get needed mental health care due to cost" ~ "Unmet MH Care (Cost)"
  ))

# Step 3: Plotting
ggplot(income_data, aes(x = Year, y = Percentage, color = Group)) +
  geom_line(linewidth = 1.2) +
  facet_wrap(~ outcome_wrapped, scales = "free_y") +
  labs(
    title = "Mental Health Indicators by Family Income (NHIS Adults)",
    x = "Year",
    y = "Percentage",
    color = "Income Group"
  ) +
  theme_minimal() +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1),
    strip.text = element_text(size = 6, face = "bold"),
    plot.title = element_text(size = 13, face = "bold")
  )

The analysis of these key mental health indicators stratified by family income level reveals a consistent and concerning pattern: lower-income adults experience significantly higher rates of mental health distress and barriers to care. Adults living below the Federal Poverty Level (FPL) exhibit the highest percentages across all measures, including frequent anxiety, prescription medication use for anxiety, and unmet mental health care needs due to cost. This group consistently surpasses those with moderate (100% to less than 200% FPL) and higher (200% and greater FPL) income levels.

Moreover, while all income groups show slight increases in mental health service use and symptom prevalence over the four-year period, the sharpest increases are observed among those in poverty, particularly in the post-2020 timeframe. This may reflect the compounded mental health impact of the COVID-19 pandemic, economic instability, and widening health disparities.

These findings support the hypothesis that economic stressors are strong predictors of mental health distress (H1). They also underscore the urgent need for targeted policy interventions and resource allocation to mitigate structural barriers in low-income populations, especially as demand for mental health services continues to grow.

Education and Employment Status

library(dplyr)
library(ggplot2)

# Step 1: Defining the 5 mental health-related indicators
indicators_of_interest <- c(
  "Symptoms of anxiety",
  "Symptoms of depression",
  "Regularly had feelings of worry, nervousness, or anxiety",
  "Taking prescription medication for feelings of worry, nervousness, or anxiety",
  "Did not get needed mental health care due to cost"
)

# Step 2: Filtering data for Education and Employment status groups only
composite_score <- mh_indicators %>%
  filter(outcome_or_indicator %in% indicators_of_interest,
         grouping_category %in% c("Education", "Employment status")) %>%
  group_by(Year, grouping_category, Group) %>%
  summarise(
    depression_symptom_score = sum(Percentage, na.rm = TRUE),
    .groups = "drop"
  )

# Step 3: Plotting results
ggplot(composite_score, aes(x = Group, y = depression_symptom_score, fill = grouping_category)) +
  geom_col(position = "dodge") +
  facet_wrap(~ grouping_category, scales = "free_x") +
  labs(
    title = "Combined Mental Health Symptom Score by Education and Employment Status",
    x = NULL,
    y = "Summed Percentage of Symptoms",
    fill = "Grouping"
  ) +
  theme_minimal(base_size = 11) +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1, size = 8),  # smaller labels
    strip.text = element_text(size = 11),
    plot.title = element_text(face = "bold", size = 14)
  )

Key Findings: Employment Status: The clearest disparities were found in employment status. Adults who were not currently employed but had worked previously reported significantly higher combined symptom scores compared to other groups. This supports existing evidence linking job insecurity or unemployment to elevated mental distress.

Education Level: The variation in mental health symptom burden across education levels was minimal. While individuals with less than a high school diploma had slightly higher scores than those with college degrees, the differences were less pronounced compared to those seen in employment status. This suggests that education alone may not be a sufficient predictor of mental health symptoms without considering factors such as employment and income.

These findings reinforce that economic stress and employment stability are stronger correlates of mental health outcomes than education level in this population.

Age:

library(ggplot2)
library(dplyr)
library(stringr)

# Defining the 5 depression-related indicators
depression_indicators <- c(
  "Symptoms of anxiety",
  "Symptoms of depression",
  "Regularly had feelings of worry, nervousness, or anxiety",
  "Taking prescription medication for feelings of worry, nervousness, or anxiety",
  "Did not get needed mental health care due to cost"
)

# Filtering dataset: indicators + only age groups (containing "years")
age_data <- nhis_adult %>%
  filter(outcome_or_indicator %in% depression_indicators,
         str_detect(Group, "years"))

# Grouping and summarizing to get average percentage per year and age group
avg_age_trends <- age_data %>%
  group_by(Year, Group) %>%
  summarise(avg_percentage = mean(Percentage, na.rm = TRUE), .groups = "drop")

# Plotting
ggplot(avg_age_trends, aes(x = Year, y = avg_percentage, color = Group)) +
  geom_line(linewidth = 1.2) +
  geom_point(size = 2) +
  labs(
    title = "Average Depression Symptoms by Age Group (NHIS Adults)",
    x = "Year",
    y = "Average Percentage",
    color = "Age Group"
  ) +
  theme_minimal(base_size = 13)

Young adults (18–34 years) consistently report the highest average levels of depression symptoms.

Older adults (65+ years) report the lowest, with relatively stable trends.

There’s a noticeable upward trend from 2019 to 2023 in all age groups, but it’s steepest among younger cohorts.

This strongly supports the idea that age is a major factor in mental health symptom burden, especially post-2020.

The previous analysis of NHIS Adult Summary Health Statistics revealed a deeply concerning trend: younger adults aged 18–34 consistently report the highest levels of depression symptoms, with steady increases observed from 2019 through 2023. This age group not only leads all others in reported mental health distress, but the upward trajectory suggests that mental health challenges are not isolated to adulthood—they likely begin much earlier in life.

These findings underscore the urgent need to investigate the early development of mental health symptoms, particularly in adolescents. Mental health disorders such as depression and anxiety often emerge during the teenage years, a critical developmental period characterized by emotional, hormonal, academic, and social transitions. Understanding the burden of depression symptoms in teens is not only important for early detection, but essential for designing interventions that can interrupt the trajectory of worsening mental health into adulthood.

As we shift to analyzing data from the NHIS Teen Summary Health Statistics, we aim to:

Quantify the prevalence of depression symptoms in adolescents aged 12–17.

Identify demographic and socioeconomic disparities in mental health burden.

Explore patterns in unmet mental health care needs and the role of social or emotional support.

This next phase of the analysis will build upon the adult findings to help connect early indicators to long-term outcomes, offering a more complete picture of mental health challenges across the lifespan.

Loading dataset 2

Loading dataset for teens

# Loading required libraries
library(tidyverse)

# Reading the NHIS Teen CSV file
nhis_teen <- read_csv("C:/Users/aleja/Downloads/NHIS_Teen_20250510.csv")
## Rows: 3400 Columns: 22
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (15): stat_group, stat_var, Outcome (or Indicator), row_group, row_var, ...
## dbl  (5): Percentage, FIGURE, CR_P_RELIABLE, CR_Q_RELIABLE, ZERO
## lgl  (2): Description, KG_FLAG
## 
## ℹ 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.
# View the column names
colnames(nhis_teen)
##  [1] "stat_group"             "stat_var"               "Outcome (or Indicator)"
##  [4] "row_group"              "row_var"                "row_label"             
##  [7] "rowLevels"              "col_group"              "col_var"               
## [10] "col_label"              "Group"                  "Percentage"            
## [13] "Confidence Interval"    "Title"                  "Description"           
## [16] "new_caption2"           "FIGURE"                 "CR_P_RELIABLE"         
## [19] "CR_Q_RELIABLE"          "ZERO"                   "KG_FLAG"               
## [22] "Date Range"
# A quick peek at the structure of the dataset
glimpse(nhis_teen)
## Rows: 3,400
## Columns: 22
## $ stat_group               <chr> "Bullying", "Bullying", "Bullying", "Bullying…
## $ stat_var                 <chr> "EVER_BULLIED", "EVER_BULLIED", "EVER_BULLIED…
## $ `Outcome (or Indicator)` <chr> "Bullied", "Bullied", "Bullied", "Bullied", "…
## $ row_group                <chr> "Number or Percentage", "Number or Percentage…
## $ row_var                  <chr> "ind", "ind", "ind", "ind", "ind", "ind", "in…
## $ row_label                <chr> "(none)", "(none)", "(none)", "(none)", "(non…
## $ rowLevels                <chr> "Total", "Total", "Total", "Total", "Total", …
## $ col_group                <chr> "Demographic Characteristics", "Demographic C…
## $ col_var                  <chr> "ind", "sex", "sex", "agegrps", "agegrps", "h…
## $ col_label                <chr> "Total", "Sex", "Sex", "Age groups", "Age gro…
## $ Group                    <chr> "Total", "Female", "Male", "12-14 years", "15…
## $ Percentage               <dbl> 33.5, 37.2, 30.0, 37.7, 29.4, 26.9, 35.9, 16.…
## $ `Confidence Interval`    <chr> "30.1, 37.1", "32.3, 42.4", "25.2, 35.1", "32…
## $ Title                    <chr> "Percentage of teens aged 12-17 years who wer…
## $ Description              <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
## $ new_caption2             <chr> "Based on the question, \"During the past 12 …
## $ FIGURE                   <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, …
## $ CR_P_RELIABLE            <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, …
## $ CR_Q_RELIABLE            <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, …
## $ ZERO                     <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, …
## $ KG_FLAG                  <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
## $ `Date Range`             <chr> "July 2021-December 2022", "July 2021-Decembe…
# View unique values in important fields
unique(nhis_teen$`Outcome (or Indicator)`)
##  [1] "Bullied"                                                                
##  [2] "Household member with substance abuse"                                  
##  [3] "Experienced emotional abuse"                                            
##  [4] "Unmet basic needs"                                                      
##  [5] "Experienced discrimination due to race or ethnic group"                 
##  [6] "Experienced discrimination due to sexual orientation or gender identity"
##  [7] "Ever treated with less courtesy"                                        
##  [8] "Ever received poorer service"                                           
##  [9] "Ever perceived as not smart"                                            
## [10] "Social and emotional support"                                           
## [11] "Peer support"                                                           
## [12] "Bullied others"                                                         
## [13] "Parent support"                                                         
## [14] "Community support"                                                      
## [15] "Met privately with healthcare professional"                             
## [16] "Discussed healthcare transition"                                        
## [17] "Discussed managing health and health care"                              
## [18] "Discussed tobacco use"                                                  
## [19] "Discussed mental or emotional health"                                   
## [20] "Discussed puberty and sexual health"                                    
## [21] "Symptoms of depression"                                                 
## [22] "Symptoms of anxiety"                                                    
## [23] "Electronically bullied"                                                 
## [24] "Any prescription medication for mental health"                          
## [25] "Any mental health therapy"                                              
## [26] "Unmet mental health care"                                               
## [27] "Sports team participation"                                              
## [28] "Took physical education class"                                          
## [29] "Physically active for at least 60 minutes"                              
## [30] "Strength training"                                                      
## [31] "Walked for at least 10 minutes"                                         
## [32] "Biked for at least 10 minutes"                                          
## [33] "Wake up well-rested"                                                    
## [34] "Electronically bullied others"                                          
## [35] "Difficulty getting out of bed"                                          
## [36] "Complain about being tired"                                             
## [37] "Take naps or fall asleep during the day"                                
## [38] "Regular bedtime"                                                        
## [39] "Regular wake time"                                                      
## [40] "2 or more hours of screentime"                                          
## [41] "Meditation"                                                             
## [42] "Yoga"                                                                   
## [43] "Chiropractor Visit"                                                     
## [44] "Concerned about weight"                                                 
## [45] "Death of a parent or guardian"                                          
## [46] "Fair or poor health"                                                    
## [47] "Divorced or separated parents"                                          
## [48] "Victim or witness of neighborhood violence"                             
## [49] "Incarcerated parents"                                                   
## [50] "Household member with mental illness"
unique(nhis_teen$Group)
##  [1] "Total"                             "Female"                           
##  [3] "Male"                              "12-14 years"                      
##  [5] "15-17 years"                       "Hispanic"                         
##  [7] "Non-Hispanic"                      "Asian"                            
##  [9] "Black"                             "White"                            
## [11] "All other races"                   "Medicaid or other public"         
## [13] "Private"                           "Less than 200% FPL"               
## [15] "200-399% FPL"                      "400% and greater FPL"             
## [17] "High school diploma, GED, or less" "Some college"                     
## [19] "College degree or higher"          "Single parent"                    
## [21] "Two parents"                       "Large central and fringe metro"   
## [23] "Medium and small metro"            "Nonmetropolitan"                  
## [25] "Midwest"                           "Northeast"                        
## [27] "South"                             "West"                             
## [29] "With disability"                   "Without disability"               
## [31] "Any developmental disability"      "No developmental disability"      
## [33] "Not a sexual or gender minority"   "Sexual or gender minority"
unique(nhis_teen$`Grouping category`)
## Warning: Unknown or uninitialised column: `Grouping category`.
## NULL

Data cleaning

# Count total missing values in the dataset
sum(is.na(nhis_teen))
## [1] 6986
# Count missing values per column
colSums(is.na(nhis_teen))
##             stat_group               stat_var Outcome (or Indicator) 
##                      0                      0                      0 
##              row_group                row_var              row_label 
##                      0                      0                      0 
##              rowLevels              col_group                col_var 
##                      0                      0                      0 
##              col_label                  Group             Percentage 
##                      0                      0                      0 
##    Confidence Interval                  Title            Description 
##                     93                      0                   3400 
##           new_caption2                 FIGURE          CR_P_RELIABLE 
##                      0                      0                      0 
##          CR_Q_RELIABLE                   ZERO                KG_FLAG 
##                      0                     93                   3400 
##             Date Range 
##                      0

Dataset has 0 missing values

# Filtering for "Symptoms of depression"
depression_teen <- nhis_teen %>%
  filter(`Outcome (or Indicator)` == "Symptoms of depression") %>%
  mutate(Group = str_trim(Group))

# Plot 1: Symptoms of depression by Sex
ggplot(
  depression_teen %>% filter(Group %in% c("Male", "Female")),
  aes(x = Group, y = Percentage, fill = Group)
) +
  geom_col(width = 0.6) +
  scale_fill_manual(values = c("Male" = "#1f78b4", "Female" = "#e31a1c")) +
  labs(
    title = "Symptoms of Depression Among Teens by Sex",
    x = NULL,
    y = "Percentage"
  ) +
  theme_minimal(base_size = 13) +
  theme(legend.position = "none")

# Plot 2: Symptoms of depression by Age Group
ggplot(
  depression_teen %>% filter(str_detect(Group, "years")),
  aes(x = Group, y = Percentage, fill = Group)
) +
  geom_col(width = 0.6) +
  scale_fill_brewer(palette = "Set2") +
  labs(
    title = "Symptoms of Depression Among Teens by Age Group",
    x = NULL,
    y = "Percentage"
  ) +
  theme_minimal(base_size = 13) +
  theme(legend.position = "none")

Based on the dataset, female teens and those aged 15–17 report higher percentages of depression symptoms compared to their male and younger counterparts. This aligns with broader trends observed in public health research, where adolescent girls tend to report higher rates of anxiety and depression, particularly in mid to late adolescence.

This insight helps set the stage for deeper analysis into potential contributing factors, such as:

Social media exposure

Academic pressures

Peer dynamics and bullying

Access to mental health support

# Load necessary libraries
library(tidyverse)
library(stringr)

# Step 1: Read the dataset
nhis_teen <- read_csv("C:/Users/aleja/Downloads/NHIS_Teen_20250510.csv")
## Rows: 3400 Columns: 22
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (15): stat_group, stat_var, Outcome (or Indicator), row_group, row_var, ...
## dbl  (5): Percentage, FIGURE, CR_P_RELIABLE, CR_Q_RELIABLE, ZERO
## lgl  (2): Description, KG_FLAG
## 
## ℹ 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.
# Step 2: Filter for 'Symptoms of depression' and group by family structure
depression_family <- nhis_teen %>%
  filter(`Outcome (or Indicator)` == "Symptoms of depression",
         str_detect(Group, "parent")) %>%  # Filters 'Single parent' or 'Two parents'
  mutate(group_clean = str_to_title(Group))

# Step 3: Create bar plot
ggplot(depression_family, aes(x = group_clean, y = Percentage, fill = group_clean)) +
  geom_col(width = 0.6) +
  labs(
    title = "Symptoms of Depression Among Teens by Family Structure",
    x = "Family Structure",
    y = "Percentage",
    fill = "Family Structure"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    plot.title = element_text(face = "bold", size = 14),
    legend.position = "none"
  )

Income:

# Step 1: Read the dataset
nhis_teen <- read_csv("C:/Users/aleja/Downloads/NHIS_Teen_20250510.csv")
## Rows: 3400 Columns: 22
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (15): stat_group, stat_var, Outcome (or Indicator), row_group, row_var, ...
## dbl  (5): Percentage, FIGURE, CR_P_RELIABLE, CR_Q_RELIABLE, ZERO
## lgl  (2): Description, KG_FLAG
## 
## ℹ 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.
# Step 2: Filter for 'Symptoms of depression' for relevant groups
depression_combo <- nhis_teen %>%
  filter(`Outcome (or Indicator)` == "Symptoms of depression",
         Group %in% c("Single parent", "Two parents",
                      "Less than 200% FPL", "200-399% FPL", "400% and greater FPL")) %>%
  mutate(group_type = case_when(
    Group %in% c("Single parent", "Two parents") ~ "Family Structure",
    str_detect(Group, "FPL") ~ "Family Income"
  ),
  group_clean = str_to_title(Group))

# Step 3: Bar plot faceted by group type
ggplot(depression_combo, aes(x = group_clean, y = Percentage, fill = group_clean)) +
  geom_col(width = 0.6) +
  facet_wrap(~ group_type, scales = "free_x") +
  labs(
    title = "Symptoms of Depression Among Teens by Family Structure and Income",
    x = NULL,
    y = "Percentage",
    fill = NULL
  ) +
  theme_minimal(base_size = 13) +
  theme(
    axis.text.x = element_text(angle = 30, hjust = 1),
    strip.text = element_text(face = "bold", size = 12),
    plot.title = element_text(face = "bold", size = 14),
    legend.position = "none"
  )

Findings:

Depression symptoms are most prevalent among teens in families earning less than 200% of the Federal Poverty Level (FPL).

Those in the 200–399% FPL range fare slightly better, while those in the 400% and greater FPL group report the lowest prevalence.

Interpretation:

Economic hardship is a strong risk factor for adolescent depression. Policy strategies addressing financial insecurity could play a preventive role in teen mental health.

Findings:

Teens from single-parent households are more likely to report depression symptoms than those from two-parent households.

The absence of a second parental figure may affect emotional support, stability, or access to care.

Interpretation:

Mental health services could prioritize family-based support strategies, particularly for single-parent households.

Race and Ethnicity:

# Step 2: Filter for symptoms of depression by race
depression_race <- nhis_teen %>%
  filter(`Outcome (or Indicator)` == "Symptoms of depression",
         Group %in% c("Hispanic", "Non-Hispanic", "Asian", "Black", "White", "All other races")) %>%
  mutate(group_clean = str_to_title(Group))

# Step 3: Create bar plot
ggplot(depression_race, aes(x = group_clean, y = Percentage, fill = group_clean)) +
  geom_col(width = 0.6) +
  labs(
    title = "Symptoms of Depression Among Teens by Race and Ethnicity",
    x = NULL,
    y = "Percentage",
    fill = NULL
  ) +
  theme_minimal(base_size = 13) +
  theme(
    axis.text.x = element_text(angle = 30, hjust = 1),
    plot.title = element_text(face = "bold", size = 14),
    legend.position = "none"
  )

Findings:

Asian teens report the highest rate of depression symptoms, followed by White and Black teens.

Hispanic teens and those grouped as “All other races” show relatively lower prevalence, though this may mask intra-group diversity.

Loading dataset

Loading dataset: Indicators of Anxiety or Depression Based on Reported Frequency of Symptoms During Last 7 Days

# Load required libraries
library(tidyverse)
library(lubridate)

# Step 1: Load the dataset
depression_data <- read_csv("C:/Users/aleja/Downloads/Indicators_of_Anxiety_or_Depression_Based_on_Reported_Frequency_of_Symptoms_During_Last_7_Days_20250511.csv")
## Rows: 16794 Columns: 14
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (10): Indicator, Group, State, Subgroup, Phase, Time Period Label, Time ...
## dbl  (4): Time Period, Value, Low CI, High CI
## 
## ℹ 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.
# Step 2: Filter for 'Symptoms of Depressive Disorder' by Age
depression_age <- depression_data %>%
  filter(Indicator == "Symptoms of Depressive Disorder",
         Group == "By Age")

# Step 3: Convert time period to date
depression_age <- depression_age %>%
  mutate(TimePeriod = mdy(`Time Period Start Date`))

# Step 4: Plot the trend
ggplot(depression_age, aes(x = TimePeriod, y = Value, color = Subgroup)) +
  geom_line(size = 1.2) +
  labs(
    title = "Symptoms of Depressive Disorder by Age Group (US, 2020–2023)",
    x = "Date",
    y = "Percentage",
    color = "Age Group"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1),
    plot.title = element_text(face = "bold")
  )
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

library(ggplot2)

ggplot(depression_age, aes(x = TimePeriod, y = Value, fill = Subgroup)) +
  geom_area(position = "identity", alpha = 0.5) +
  labs(
    title = "Symptoms of Depressive Disorder by Age Group (Area Chart)",
    x = "Date", y = "Percentage", fill = "Age Group"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1),
    plot.title = element_text(face = "bold")
  )
## Warning: Removed 70 rows containing non-finite outside the scale range
## (`stat_align()`).

ggplot(depression_age, aes(x = TimePeriod, y = Value)) +
  geom_line(color = "steelblue", size = 1) +
  facet_wrap(~ Subgroup, scales = "free_y") +
  labs(
    title = "Symptoms of Depressive Disorder by Age Group (Faceted View)",
    x = "Date", y = "Percentage"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1),
    strip.text = element_text(face = "bold")
  )

Key Findings Young adults (18–29 years) consistently show the highest prevalence of depressive symptoms, especially during the earlier part of the pandemic (2020–2021), peaking at over 40%.

This group forms the largest “area” at the top, confirming their disproportionate mental health burden.

The 30–39 and 40–49 age groups follow, but with noticeably lower percentages, staying mostly between 20%–30%.

Older adults (60+) report the lowest rates of depressive symptoms throughout the time period, often remaining below 15%.

Particularly 80+, who consistently report the lowest.

There’s a noticeable decline across most age groups in 2024, which might reflect improved mental health services, pandemic recovery, or survey changes.

Interpretation & Implications Young adults face higher mental health vulnerability, possibly due to:

Economic uncertainty, job loss, and housing instability.

Social isolation and disrupted life milestones (e.g., graduation, early career).

Greater likelihood of reporting symptoms or seeking help.

Older adults, despite potential isolation, might have more resilience, coping mechanisms, or underreporting due to stigma.

Public health policies and mental health interventions should prioritize young adult support, especially during public crises.

glimpse(depression_data)
## Rows: 16,794
## Columns: 14
## $ Indicator                <chr> "Symptoms of Depressive Disorder", "Symptoms …
## $ Group                    <chr> "National Estimate", "By Age", "By Age", "By …
## $ State                    <chr> "United States", "United States", "United Sta…
## $ Subgroup                 <chr> "United States", "18 - 29 years", "30 - 39 ye…
## $ Phase                    <chr> "1", "1", "1", "1", "1", "1", "1", "1", "1", …
## $ `Time Period`            <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, …
## $ `Time Period Label`      <chr> "Apr 23 - May 5, 2020", "Apr 23 - May 5, 2020…
## $ `Time Period Start Date` <chr> "04/23/2020", "04/23/2020", "04/23/2020", "04…
## $ `Time Period End Date`   <chr> "05/05/2020", "05/05/2020", "05/05/2020", "05…
## $ Value                    <dbl> 23.5, 32.7, 25.7, 24.8, 23.2, 18.4, 13.6, 14.…
## $ `Low CI`                 <dbl> 22.7, 30.2, 24.1, 23.3, 21.5, 17.0, 11.8, 9.0…
## $ `High CI`                <dbl> 24.3, 35.2, 27.3, 26.2, 25.0, 19.7, 15.5, 21.…
## $ `Confidence Interval`    <chr> "22.7 - 24.3", "30.2 - 35.2", "24.1 - 27.3", …
## $ `Quartile Range`         <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
# Extract year from date
depression_data <- depression_data %>%
  mutate(Year = year(mdy(`Time Period Start Date`))) %>%
  filter(!is.na(Value))
group_year_data <- depression_data %>%
  group_by(Group, Subgroup, Year) %>%
  summarise(avg_value = mean(Value, na.rm = TRUE), .groups = "drop")
depression_wide <- group_year_data %>%
  unite("group_label", Group, Subgroup, sep = " - ") %>%
  pivot_wider(names_from = Year, values_from = avg_value)
library(dplyr)
library(cluster)
library(tidyverse)
library(tidyr)


library(factoextra)
## Warning: package 'factoextra' was built under R version 4.4.3
## Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa
# Step 2: Filter for 'By Age' group and calculate average value
depression_age <- depression_data %>%
  filter(Group == "By Age") %>%
  group_by(Subgroup) %>%
  summarise(avg_value = mean(Value, na.rm = TRUE))

# Step 3: Scale the data
scaled_data <- scale(depression_age$avg_value)

# Step 4: Apply k-means clustering (e.g., 3 clusters)
set.seed(123)
kmeans_result <- kmeans(scaled_data, centers = 3)

# Step 5: Add cluster info back to dataframe
depression_age$cluster <- as.factor(kmeans_result$cluster)

# Step 6: Plot the results
ggplot(depression_age, aes(x = Subgroup, y = avg_value, fill = cluster)) +
  geom_col() +
  coord_flip() +
  labs(
    title = "Clustered Average Depression Symptoms by Age Group",
    x = "Age Group",
    y = "Average Percentage",
    fill = "Cluster"
  ) +
  theme_minimal()

Cluster 2 (Green): The 18–29 years group stands alone — they report the highest levels of depressive symptoms across all age groups. This aligns with previous datasets showing elevated distress among younger adults.

Cluster 3 (Blue): The 30–59 years range forms a middle group, showing moderate levels of depressive symptoms.

Cluster 1 (Red): Adults 60 years and older have the lowest reported levels of depression symptoms, consistent with national mental health trends showing declining distress with age

Loading dataset for Machine learning

DATASET JSON

This dataset is critical to the goals of the research “Identifying Early Signs of Mental Health Crises Using Social and Economic Data” for several reasons:

Longitudinal and Individual-Level Data: Unlike aggregate public health surveys, PSYCHE-D offers individual-level, time-linked records—ideal for modeling subtle trends in mental health over time.

Multimodal Indicators: It includes digital biomarkers such as step counts, sleep efficiency, and daily activity patterns, which can serve as early predictors of mental health changes.

Labelled Depression Scores: The dataset provides both baseline and follow-up PHQ-9 scores, enabling supervised learning to predict depression risk and progression.

Socioeconomic Context: Variables like education, income, and comorbidities enrich the modeling with contextual and structural factors aligned with this study’s hypotheses.

This makes the PSYCHE-D dataset uniquely suited for developing and validating machine learning models that forecast depression severity based on behavioral and socioeconomic signals—one of the key ambitions outlined in this paper.

# Then load the file
library(arrow)
## Warning: package 'arrow' was built under R version 4.4.3
## 
## Attaching package: 'arrow'
## The following object is masked from 'package:lubridate':
## 
##     duration
## The following object is masked from 'package:utils':
## 
##     timestamp
# Read the parquet file
dep_severity <- read_parquet("C:/Users/aleja/Downloads/anon_processed_df_parquet")

# Peek at the data
glimpse(dep_severity)
## Rows: 35,694
## Columns: 155
## $ steps_awake_mean                                <dbl> 10615.286, 9292.000, 1…
## $ sleep_asleep_weekday_mean                       <dbl> 474.3333, 453.0833, 43…
## $ sleep_asleep_weekend_mean                       <dbl> 467.0, 444.0, 494.5, 5…
## $ sleep_in_bed_weekday_mean                       <dbl> 520.1667, 495.0000, 46…
## $ sleep_in_bed_weekend_mean                       <dbl> 518.5, 478.5, 515.0, 5…
## $ sleep_ratio_asleep_in_bed_weekday_mean          <dbl> 0.9126997, 0.9166477, …
## $ sleep_ratio_asleep_in_bed_weekend_mean          <dbl> 0.9037565, 0.9295840, …
## $ sleep_in_bed_iqr                                <dbl> 90.75, 127.00, 60.25, …
## $ sleep_asleep_iqr                                <dbl> 65.00, 107.00, 65.50, …
## $ sleep_ratio_asleep_in_bed_iqr                   <dbl> 0.04826875, 0.02579844…
## $ steps_mvpa_iqr                                  <dbl> 9.75, 11.50, 8.00, 15.…
## $ steps_lpa_iqr                                   <dbl> 11.25, 9.25, 9.25, 16.…
## $ steps_awake_sum_iqr                             <dbl> 560.50, 1818.75, 896.5…
## $ sleep_main_start_hour_adj_median                <dbl> 23.0, 22.0, 23.0, 22.0…
## $ sleep_main_start_hour_adj_iqr                   <dbl> 0.00, 1.00, 0.75, 0.00…
## $ sleep_main_start_hour_adj_range                 <dbl> 1, 4, 2, 2, 2, 3, 3, 3…
## $ sleep__hypersomnia_count_                       <int> 0, 0, 0, 0, 0, 1, 2, 2…
## $ sleep__hyposomnia_count_                        <int> 0, 0, 0, 0, 0, 0, 1, 0…
## $ steps__active_day_count_                        <int> 5, 5, 7, 3, 5, 6, 6, 3…
## $ steps__sedentary_day_count_                     <int> 0, 0, 0, 0, 0, 0, 0, 0…
## $ sleep__main_start_hour_adj__score               <dbl> 0.0295857988, 0.481700…
## $ sleep__main_start_hour_adj__intercept           <dbl> -0.08806621, -0.620382…
## $ sleep__main_start_hour_adj__coeff               <dbl> 0.0042653524, 0.060568…
## $ steps__awake__sum__score                        <dbl> 0.101986626, 0.2931996…
## $ steps__awake__sum__intercept                    <dbl> 0.48885151, -0.0731905…
## $ steps__awake__sum__coeff                        <dbl> -0.016080409, 0.033225…
## $ steps__mvpa__sum__score                         <dbl> 0.0257095845, 0.391518…
## $ steps__mvpa__sum__intercept                     <dbl> 0.07764224, -0.5192336…
## $ steps__mvpa__sum__coeff                         <dbl> -0.012061347, 0.048004…
## $ steps__light_activity__sum__score               <dbl> 3.499623e-01, 5.319359…
## $ steps__light_activity__sum__intercept           <dbl> 0.3762281366, -0.05797…
## $ steps__light_activity__sum__coeff               <dbl> -0.047212539, 0.018332…
## $ steps__rolling_6_sum__max__score                <dbl> 3.518815e-02, 4.274606…
## $ steps__rolling_6_sum__max__intercept            <dbl> 0.9757825, 0.0616496, …
## $ steps__rolling_6_sum__max__coeff                <dbl> 0.0198831437, 0.091569…
## $ steps__streaks__countDistinct__score            <dbl> 0.0364825413, 0.411786…
## $ steps__streaks__countDistinct__intercept        <dbl> 0.491942233, 1.2087361…
## $ steps__streaks__countDistinct__coeff            <dbl> 0.013322448, -0.068845…
## $ steps__not_moving__sum__score                   <dbl> 2.533170e-01, 1.386702…
## $ steps__not_moving__sum__intercept               <dbl> -0.3906514, 1.0543557,…
## $ steps__not_moving__sum__coeff                   <dbl> 0.103281442, -0.078058…
## $ sleep__nap_count__score                         <dbl> 0.0025641026, 0.207692…
## $ sleep__nap_count__intercept                     <dbl> -0.10755232, -0.667993…
## $ sleep__nap_count__coeff                         <dbl> 0.01077772, 0.09699948…
## $ sleep__total_asleep_minutes__score              <dbl> 0.1382807116, 0.320879…
## $ sleep__total_asleep_minutes__intercept          <dbl> 0.75816339, 0.09845777…
## $ sleep__total_asleep_minutes__coeff              <dbl> -0.027487202, 0.054782…
## $ sleep__main_efficiency__score                   <dbl> 0.2918400748, 0.018672…
## $ sleep__main_efficiency__intercept               <dbl> 0.04389271, 0.17614815…
## $ sleep__main_efficiency__coeff                   <dbl> 0.026351022, 0.0068379…
## $ sleep__awake__sum__score                        <dbl> 0.3877438299, 0.010002…
## $ sleep__awake__sum__intercept                    <dbl> 0.13493442, -0.2036400…
## $ sleep__awake__sum__coeff                        <dbl> -0.039547351, 0.005573…
## $ sleep__total_in_bed_minutes__score              <dbl> 0.2773919766, 0.273476…
## $ sleep__total_in_bed_minutes__intercept          <dbl> 0.7979069565, 0.030943…
## $ sleep__total_in_bed_minutes__coeff              <dbl> -0.040972241, 0.054146…
## $ sleep__awake_regions__countDistinct__score      <dbl> 1.305737e-02, 8.238081…
## $ sleep__awake_regions__countDistinct__intercept  <dbl> -0.05252108, 0.3203695…
## $ sleep__awake_regions__countDistinct__coeff      <dbl> -0.016582879, 0.017927…
## $ sleep_ratio_asleep_in_bed__score                <dbl> 0.3253915292, 0.007931…
## $ sleep_ratio_asleep_in_bed__intercept            <dbl> -0.03141082, 0.2112623…
## $ sleep_ratio_asleep_in_bed__coeff                <dbl> 0.033430718, 0.0040771…
## $ sleep__main_start_hour_adj__score_              <dbl> 1.000000000, 0.3809523…
## $ sleep__main_start_hour_adj__intercept_          <dbl> -0.03270159, -0.366304…
## $ sleep__main_start_hour_adj__coeff_              <dbl> 0.000000e+00, 1.112010…
## $ steps__awake__sum__score_                       <dbl> 3.863442e-02, 3.425546…
## $ steps__awake__sum__intercept_                   <dbl> 0.29792773, 0.18323595…
## $ steps__awake__sum__coeff_                       <dbl> 0.0056317207, 0.014720…
## $ steps__mvpa__sum__score_                        <dbl> 4.786446e-01, 2.242467…
## $ steps__mvpa__sum__intercept_                    <dbl> 0.08261331, 0.05255148…
## $ steps__mvpa__sum__coeff_                        <dbl> -0.053588486, -0.02091…
## $ steps__light_activity__sum__score_              <dbl> 0.1295129428, 0.001644…
## $ steps__light_activity__sum__intercept_          <dbl> 0.03910300, 0.06646843…
## $ steps__light_activity__sum__coeff_              <dbl> -0.039527852, 0.004054…
## $ steps__rolling_6_sum__max__score_               <dbl> 0.028233281, 0.1343328…
## $ steps__rolling_6_sum__max__intercept_           <dbl> 1.18246896, 0.69676537…
## $ steps__rolling_6_sum__max__coeff_               <dbl> -0.02293021, 0.0625369…
## $ steps__streaks__countDistinct__score_           <dbl> 0.003174603, 0.0123266…
## $ steps__streaks__countDistinct__intercept_       <dbl> 0.6850409, 0.5650409, …
## $ steps__streaks__countDistinct__coeff_           <dbl> 0.004999998, -0.019999…
## $ steps__not_moving__sum__score_                  <dbl> 0.4810070671, 0.026729…
## $ steps__not_moving__sum__intercept_              <dbl> 0.999443683, 0.0353604…
## $ steps__not_moving__sum__coeff_                  <dbl> -0.03516737, 0.0730581…
## $ sleep__nap_count__score_                        <dbl> 0.041666667, 0.1000000…
## $ sleep__nap_count__intercept_                    <dbl> 0.22483428, -0.2127105…
## $ sleep__nap_count__coeff_                        <dbl> -8.750897e-02, 1.75017…
## $ sleep__total_asleep_minutes__score_             <dbl> 0.5952382298, 0.043583…
## $ sleep__total_asleep_minutes__intercept_         <dbl> 0.751339284, 0.8103005…
## $ sleep__total_asleep_minutes__coeff_             <dbl> -0.095292980, -0.03467…
## $ sleep__main_efficiency__score_                  <dbl> 0.285714286, 0.8561320…
## $ sleep__main_efficiency__intercept_              <dbl> 0.15970032, -0.0765223…
## $ sleep__main_efficiency__coeff_                  <dbl> 0.043443252, 0.0896017…
## $ sleep__awake__sum__score_                       <dbl> 0.4054758401, 0.841841…
## $ sleep__awake__sum__intercept_                   <dbl> -0.05713781, 0.2224253…
## $ sleep__awake__sum__coeff_                       <dbl> -0.062065185, -0.10200…
## $ sleep__total_in_bed_minutes__score_             <dbl> 5.651211e-01, 1.477327…
## $ sleep__total_in_bed_minutes__intercept_         <dbl> 0.72472724, 0.85762993…
## $ sleep__total_in_bed_minutes__coeff_             <dbl> -0.115000720, -0.06849…
## $ sleep__awake_regions__countDistinct__score_     <dbl> 0.0154109589, 0.481525…
## $ sleep__awake_regions__countDistinct__intercept_ <dbl> -0.32596847, 1.4663903…
## $ sleep__awake_regions__countDistinct__coeff_     <dbl> 0.021858034, -0.255010…
## $ sleep_ratio_asleep_in_bed__score_               <dbl> 2.888719e-01, 8.742842…
## $ sleep_ratio_asleep_in_bed__intercept_           <dbl> 0.13468360, -0.0257850…
## $ sleep_ratio_asleep_in_bed__coeff_               <dbl> 0.0486538469, 0.077811…
## $ steps_mvpa_sum_recent                           <dbl> 54, 73, 62, 41, 67, 63…
## $ sleep_asleep_mean_recent                        <dbl> 420.50, 505.25, 444.25…
## $ sleep_in_bed_mean_recent                        <dbl> 448.25, 544.50, 473.50…
## $ sleep_ratio_asleep_in_bed_mean_recent           <dbl> 0.9389737, 0.9293567, …
## $ steps_lpa_sum_recent                            <dbl> 144, 168, 187, 153, 21…
## $ steps_rolling_6_median_recent                   <dbl> 691.0, 713.5, 587.5, 6…
## $ steps_rolling_6_max_recent                      <dbl> 783, 741, 813, 770, 75…
## $ sex                                             <int> 0, 0, 0, 0, 0, 0, 0, 0…
## $ race_white                                      <lgl> TRUE, TRUE, TRUE, TRUE…
## $ race_black                                      <lgl> FALSE, FALSE, FALSE, F…
## $ race_hispanic                                   <lgl> FALSE, FALSE, FALSE, F…
## $ race_asian                                      <lgl> FALSE, FALSE, FALSE, F…
## $ race_other                                      <lgl> FALSE, FALSE, FALSE, F…
## $ birthyear                                       <int> 1987, 1987, 1987, 1987…
## $ educ                                            <dbl> 5, 5, 5, 5, 5, 5, 5, 5…
## $ height                                          <dbl> 65, 65, 65, 65, 65, 65…
## $ weight                                          <dbl> 136, 136, 136, 136, 13…
## $ bmi                                             <dbl> 22.62911, 22.62911, 22…
## $ pregnant                                        <dbl> 0, 0, 0, 0, 0, 0, 0, 0…
## $ birth                                           <dbl> 1, 1, 1, 1, 1, 1, 1, 1…
## $ trauma                                          <dbl> 0, 0, 0, 0, 0, 0, 0, 0…
## $ insurance                                       <dbl> 1, 1, 1, 1, 1, 1, 1, 1…
## $ money                                           <dbl> 0, 0, 0, 0, 0, 0, 0, 0…
## $ money_assistance                                <dbl> 0, 0, 0, 0, 0, 0, 0, 0…
## $ household                                       <dbl> 3, 3, 3, 3, 3, 3, 3, 3…
## $ comorbid_cancer                                 <dbl> 0, 0, 0, 0, 0, 0, 0, 0…
## $ comorbid_diabetes_typ1                          <dbl> 0, 0, 0, 0, 0, 0, 0, 0…
## $ comorbid_diabetes_typ2                          <dbl> 0, 0, 0, 0, 0, 0, 0, 0…
## $ comorbid_gout                                   <dbl> 0, 0, 0, 0, 0, 0, 0, 0…
## $ comorbid_migraines                              <dbl> 1, 1, 1, 1, 1, 1, 1, 1…
## $ comorbid_ms                                     <dbl> 0, 0, 0, 0, 0, 0, 0, 0…
## $ comorbid_osteoporosis                           <dbl> 0, 0, 0, 0, 0, 0, 0, 0…
## $ num_migraine_days                               <dbl> 1, 1, 1, 1, 1, 1, 1, 1…
## $ meds_migraine                                   <dbl> 0, 0, 0, 0, 0, 0, 0, 0…
## $ med_start                                       <int> 0, 0, 1, 0, 0, 0, 0, 0…
## $ med_stop                                        <int> 0, 0, 0, 0, 0, 0, 0, 0…
## $ med_dose                                        <int> 0, 0, 0, 0, 0, 0, 0, 0…
## $ nonmed_start                                    <int> 0, 0, 0, 0, 0, 0, 0, 0…
## $ nonmed_stop                                     <int> 0, 0, 0, 0, 0, 0, 0, 0…
## $ life_meditation                                 <int> 0, 0, 0, 0, 0, 0, 0, 0…
## $ life_stress                                     <int> 0, 0, 0, 0, 0, 0, 0, 0…
## $ med_nonmed_dnu                                  <int> 0, 1, 1, 1, 0, 0, 1, 0…
## $ life_activity_eating                            <int> 0, 0, 0, 0, 0, 0, 0, 0…
## $ life_red_stop_alcoh                             <int> 0, 0, 0, 0, 0, 0, 0, 0…
## $ comorbid_neuropathic                            <dbl> 0, 0, 0, 0, 0, 0, 0, 0…
## $ comorbid_arthritis                              <dbl> 0, 0, 0, 0, 0, 0, 0, 0…
## $ phq9_score_start                                <dbl> NA, NA, NA, 6, NA, NA,…
## $ phq9_score_end                                  <dbl> NA, NA, NA, 8, NA, NA,…
## $ phq9_cat_end                                    <dbl> NA, NA, NA, 1, NA, NA,…
## $ phq9_cat_start                                  <dbl> NA, NA, NA, 1, NA, NA,…
## $ `__index_level_0__`                             <chr> "4938_1", "4938_10", "…

Data cleaning:

# Load necessary libraries
library(dplyr)

# Summary of missing values per column
na_summary <- dep_severity %>%
  summarise(across(everything(), ~ sum(is.na(.)))) %>%
  pivot_longer(cols = everything(), names_to = "Column", values_to = "Missing_Count") %>%
  arrange(desc(Missing_Count)) %>%
  filter(Missing_Count > 0)

# View top missing columns
print(na_summary)
## # A tibble: 115 × 2
##    Column                        Missing_Count
##    <chr>                                 <int>
##  1 steps_mvpa_iqr                        30801
##  2 steps__mvpa__sum__score_              27064
##  3 steps__mvpa__sum__intercept_          27064
##  4 steps__mvpa__sum__coeff_              27064
##  5 phq9_score_start                      24828
##  6 phq9_score_end                        24828
##  7 phq9_cat_end                          24828
##  8 phq9_cat_start                        24828
##  9 sleep_ratio_asleep_in_bed_iqr         20162
## 10 sleep_main_start_hour_adj_iqr         20162
## # ℹ 105 more rows

Many missing values

# Keepping only rows with valid PHQ-9 scores
dep_severity_filtered <- dep_severity %>%
  filter(!is.na(phq9_score_end))

# Checking how many rows remain
nrow(dep_severity_filtered)
## [1] 10866
# Drop features with more than 80% missing values
threshold <- 0.8 * nrow(dep_severity_filtered)

dep_model_data <- dep_severity_filtered %>%
  select(where(~ sum(is.na(.)) < threshold))

# Check remaining columns
glimpse(dep_model_data)
## Rows: 10,866
## Columns: 154
## $ steps_awake_mean                                <dbl> 9762.714, 10057.143, 9…
## $ sleep_asleep_weekday_mean                       <dbl> 404.750000, 389.916667…
## $ sleep_asleep_weekend_mean                       <dbl> 506.0, 555.0, 494.5, 6…
## $ sleep_in_bed_weekday_mean                       <dbl> 434.833333, 428.083333…
## $ sleep_in_bed_weekend_mean                       <dbl> 560.5, 583.0, 547.0, 6…
## $ sleep_ratio_asleep_in_bed_weekday_mean          <dbl> 0.9324798, 0.9102935, …
## $ sleep_ratio_asleep_in_bed_weekend_mean          <dbl> 0.9031174, 0.9508546, …
## $ sleep_in_bed_iqr                                <dbl> 125.00, 120.00, 89.00,…
## $ sleep_asleep_iqr                                <dbl> 113.00, 111.25, 86.25,…
## $ sleep_ratio_asleep_in_bed_iqr                   <dbl> 0.04002601, 0.03438752…
## $ steps_lpa_iqr                                   <dbl> 16.25, 16.75, 12.25, N…
## $ steps_awake_sum_iqr                             <dbl> 1239.25, 190.50, 158.0…
## $ sleep_main_start_hour_adj_median                <dbl> 22.0, 22.0, 22.0, 23.0…
## $ sleep_main_start_hour_adj_iqr                   <dbl> 0.00, 1.00, 1.50, NA, …
## $ sleep_main_start_hour_adj_range                 <dbl> 2, 3, 3, 4, 4, 4, 4, 4…
## $ sleep__hypersomnia_count_                       <int> 0, 2, 0, 1, 4, 1, 0, 0…
## $ sleep__hyposomnia_count_                        <int> 0, 1, 0, 0, 0, 0, 0, 0…
## $ steps__active_day_count_                        <int> 3, 6, 6, 0, 1, 4, 4, 5…
## $ steps__sedentary_day_count_                     <int> 0, 0, 0, 7, 2, 1, 0, 0…
## $ sleep__main_start_hour_adj__score               <dbl> 0.0003752345, 0.538927…
## $ sleep__main_start_hour_adj__intercept           <dbl> -0.39858387, -0.631472…
## $ sleep__main_start_hour_adj__coeff               <dbl> 0.0008530705, 0.058008…
## $ steps__awake__sum__score                        <dbl> 1.641010e-02, 1.702088…
## $ steps__awake__sum__intercept                    <dbl> 0.27917513, 0.38569530…
## $ steps__awake__sum__coeff                        <dbl> -7.765391e-03, -1.5884…
## $ steps__mvpa__sum__score                         <dbl> 4.203520e-01, 7.917720…
## $ steps__mvpa__sum__intercept                     <dbl> 0.15185973, -0.3206234…
## $ steps__mvpa__sum__coeff                         <dbl> -0.0488082505, 0.02267…
## $ steps__light_activity__sum__score               <dbl> 4.521509e-03, 2.682171…
## $ steps__light_activity__sum__intercept           <dbl> 0.0162953112, 0.383573…
## $ steps__light_activity__sum__coeff               <dbl> 0.0065921763, -0.03421…
## $ steps__rolling_6_sum__max__score                <dbl> 2.097915e-01, 1.446643…
## $ steps__rolling_6_sum__max__intercept            <dbl> 1.21786510, 0.75051501…
## $ steps__rolling_6_sum__max__coeff                <dbl> -0.062578453, 0.013811…
## $ steps__streaks__countDistinct__score            <dbl> 2.582064e-02, 5.877843…
## $ steps__streaks__countDistinct__intercept        <dbl> 0.72520058, 1.14466517…
## $ steps__streaks__countDistinct__coeff            <dbl> 0.0128603976, -0.00354…
## $ steps__not_moving__sum__score                   <dbl> 0.0963660706, 0.064741…
## $ steps__not_moving__sum__intercept               <dbl> 0.85581880, 0.90699298…
## $ steps__not_moving__sum__coeff                   <dbl> -0.064827913, -0.05403…
## $ sleep__nap_count__score                         <dbl> 1.0000000000, 0.143195…
## $ sleep__nap_count__intercept                     <dbl> -0.38777303, -0.597938…
## $ sleep__nap_count__coeff                         <dbl> 0.00000000, 0.05927746…
## $ sleep__total_asleep_minutes__score              <dbl> 0.0113239027, 0.156901…
## $ sleep__total_asleep_minutes__intercept          <dbl> 0.19459911, -0.1371632…
## $ sleep__total_asleep_minutes__coeff              <dbl> 0.010869707, 0.0568009…
## $ sleep__main_efficiency__score                   <dbl> 8.547009e-03, 1.425022…
## $ sleep__main_efficiency__intercept               <dbl> 0.334421060, 0.0438927…
## $ sleep__main_efficiency__coeff                   <dbl> -0.0041694655, 0.02301…
## $ sleep__awake__sum__score                        <dbl> 0.0369399931, 0.073887…
## $ sleep__awake__sum__intercept                    <dbl> -0.355890670, -0.15102…
## $ sleep__awake__sum__coeff                        <dbl> 0.010583561, -0.012640…
## $ sleep__total_in_bed_minutes__score              <dbl> 0.0175340137, 0.132648…
## $ sleep__total_in_bed_minutes__intercept          <dbl> 0.06862262, -0.1742645…
## $ sleep__total_in_bed_minutes__coeff              <dbl> 0.0149349268, 0.050146…
## $ sleep__awake_regions__countDistinct__score      <dbl> 1.480349e-02, 3.723335…
## $ sleep__awake_regions__countDistinct__intercept  <dbl> -0.13409092, 0.3961130…
## $ sleep__awake_regions__countDistinct__coeff      <dbl> -0.0197201801, -0.0430…
## $ sleep_ratio_asleep_in_bed__score                <dbl> 0.0328416950, 0.128479…
## $ sleep_ratio_asleep_in_bed__intercept            <dbl> 0.36122891, 0.08578107…
## $ sleep_ratio_asleep_in_bed__coeff                <dbl> -0.0079497379, 0.02066…
## $ sleep__main_start_hour_adj__score_              <dbl> 1.000000000, 0.4705882…
## $ sleep__main_start_hour_adj__intercept_          <dbl> -0.42190523, -0.421905…
## $ sleep__main_start_hour_adj__coeff_              <dbl> 0.00000000, 0.11120104…
## $ steps__awake__sum__score_                       <dbl> 5.860423e-01, 3.475595…
## $ steps__awake__sum__intercept_                   <dbl> 0.56187639, 0.39407064…
## $ steps__awake__sum__coeff_                       <dbl> -0.0965530846, -0.0561…
## $ steps__mvpa__sum__score_                        <dbl> 0.0001733703, 0.020354…
## $ steps__mvpa__sum__intercept_                    <dbl> -0.31995386, -0.189250…
## $ steps__mvpa__sum__coeff_                        <dbl> -0.001307036, 0.024833…
## $ steps__light_activity__sum__score_              <dbl> 4.520699e-01, 6.835938…
## $ steps__light_activity__sum__intercept_          <dbl> 0.62796664, 0.14856474…
## $ steps__light_activity__sum__coeff_              <dbl> -0.147976063, -0.03547…
## $ steps__rolling_6_sum__max__score_               <dbl> 0.127486759, 0.1696940…
## $ steps__rolling_6_sum__max__intercept_           <dbl> 0.26317590, 1.12444858…
## $ steps__rolling_6_sum__max__coeff_               <dbl> 0.09311056, -0.0913734…
## $ steps__streaks__countDistinct__score_           <dbl> 0.018947368, 0.3050271…
## $ steps__streaks__countDistinct__intercept_       <dbl> 0.91004082, 1.79379055…
## $ steps__streaks__countDistinct__coeff_           <dbl> -0.014999995, -0.19124…
## $ steps__not_moving__sum__score_                  <dbl> 0.184942806, 0.2083653…
## $ steps__not_moving__sum__intercept_              <dbl> 0.877838003, 1.1261409…
## $ steps__not_moving__sum__coeff_                  <dbl> -0.174297527, -0.20354…
## $ sleep__nap_count__score_                        <dbl> 1.000000000, 0.1666666…
## $ sleep__nap_count__intercept_                    <dbl> -0.3877285, -0.5627464…
## $ sleep__nap_count__coeff_                        <dbl> 0.00000000, 0.17501794…
## $ sleep__total_asleep_minutes__score_             <dbl> 0.105965080, 0.4990532…
## $ sleep__total_asleep_minutes__intercept_         <dbl> 0.01806084, -0.4814487…
## $ sleep__total_asleep_minutes__coeff_             <dbl> 7.328632e-02, 2.613810…
## $ sleep__main_efficiency__score_                  <dbl> 0.907407407, 0.1097560…
## $ sleep__main_efficiency__intercept_              <dbl> 0.52896796, 0.12711788…
## $ sleep__main_efficiency__coeff_                  <dbl> -0.076025692, 0.032582…
## $ sleep__awake__sum__score_                       <dbl> 0.516695543, 0.1513013…
## $ sleep__awake__sum__intercept_                   <dbl> -0.53800807, -0.341018…
## $ sleep__awake__sum__coeff_                       <dbl> 0.087430956, 0.0253657…
## $ sleep__total_in_bed_minutes__score_             <dbl> 0.159757669, 0.5245976…
## $ sleep__total_in_bed_minutes__intercept_         <dbl> -0.16083669, -0.564409…
## $ sleep__total_in_bed_minutes__coeff_             <dbl> 0.10235259, 0.25841109…
## $ sleep__awake_regions__countDistinct__score_     <dbl> 0.3118081181, 0.336111…
## $ sleep__awake_regions__countDistinct__intercept_ <dbl> -0.9161354, -0.7121271…
## $ sleep__awake_regions__countDistinct__coeff_     <dbl> 0.189436295, 0.1602922…
## $ sleep_ratio_asleep_in_bed__score_               <dbl> 0.7268453089, 0.085262…
## $ sleep_ratio_asleep_in_bed__intercept_           <dbl> 0.53290570, 0.16256918…
## $ sleep_ratio_asleep_in_bed__coeff_               <dbl> -0.0785101105, 0.02695…
## $ steps_mvpa_sum_recent                           <dbl> 41, 78, 58, 0, 23, 220…
## $ sleep_asleep_mean_recent                        <dbl> 443.00, 495.75, 432.75…
## $ sleep_in_bed_mean_recent                        <dbl> 489.00, 535.50, 480.00…
## $ sleep_ratio_asleep_in_bed_mean_recent           <dbl> 0.9085217, 0.9219097, …
## $ steps_lpa_sum_recent                            <dbl> 153, 156, 200, 31, 86,…
## $ steps_rolling_6_median_recent                   <dbl> 647.5, 720.0, 678.0, 3…
## $ steps_rolling_6_max_recent                      <dbl> 770, 748, 723, 389, 64…
## $ sex                                             <int> 0, 0, 0, 0, 0, 0, 0, 0…
## $ race_white                                      <lgl> TRUE, TRUE, TRUE, TRUE…
## $ race_black                                      <lgl> FALSE, FALSE, FALSE, F…
## $ race_hispanic                                   <lgl> FALSE, FALSE, FALSE, F…
## $ race_asian                                      <lgl> FALSE, FALSE, FALSE, F…
## $ race_other                                      <lgl> FALSE, FALSE, FALSE, F…
## $ birthyear                                       <int> 1987, 1987, 1987, 1971…
## $ educ                                            <dbl> 5, 5, 5, 3, 3, 3, 5, 5…
## $ height                                          <dbl> 65.0, 65.0, 65.0, 67.0…
## $ weight                                          <dbl> 136, 136, 136, 230, 23…
## $ bmi                                             <dbl> 22.62911, 22.62911, 22…
## $ pregnant                                        <dbl> 0, 0, 0, 0, 0, 0, 0, 0…
## $ birth                                           <dbl> 1, 1, 1, 0, 0, 0, 0, 0…
## $ trauma                                          <dbl> 0, 0, 0, 0, 0, 0, 0, 0…
## $ insurance                                       <dbl> 1, 1, 1, 1, 1, 1, 1, 1…
## $ money                                           <dbl> 0, 0, 0, 2, 2, 2, 0, 0…
## $ money_assistance                                <dbl> 0, 0, 0, 1, 1, 1, 0, 0…
## $ household                                       <dbl> 3, 3, 3, 0, 0, 0, 1, 1…
## $ comorbid_cancer                                 <dbl> 0, 0, 0, 0, 0, 0, 0, 0…
## $ comorbid_diabetes_typ1                          <dbl> 0, 0, 0, 0, 0, 0, 0, 0…
## $ comorbid_diabetes_typ2                          <dbl> 0, 0, 0, 0, 0, 0, 0, 0…
## $ comorbid_gout                                   <dbl> 0, 0, 0, 0, 0, 0, 0, 0…
## $ comorbid_migraines                              <dbl> 1, 1, 1, 0, 0, 0, 0, 0…
## $ comorbid_ms                                     <dbl> 0, 0, 0, 1, 1, 1, 0, 0…
## $ comorbid_osteoporosis                           <dbl> 0, 0, 0, 0, 0, 0, 0, 0…
## $ num_migraine_days                               <dbl> 1, 1, 1, 0, 0, 0, 0, 0…
## $ meds_migraine                                   <dbl> 0, 0, 0, 0, 0, 0, 0, 0…
## $ med_start                                       <int> 0, 0, 1, 0, 0, 0, 0, 0…
## $ med_stop                                        <int> 0, 0, 0, 0, 0, 0, 0, 0…
## $ med_dose                                        <int> 0, 0, 0, 1, 1, 0, 0, 0…
## $ nonmed_start                                    <int> 0, 0, 0, 0, 0, 0, 0, 0…
## $ nonmed_stop                                     <int> 0, 0, 0, 0, 0, 0, 0, 0…
## $ life_meditation                                 <int> 0, 0, 0, 0, 0, 0, 0, 0…
## $ life_stress                                     <int> 0, 0, 0, 0, 0, 0, 0, 0…
## $ med_nonmed_dnu                                  <int> 1, 1, 0, 1, 0, 1, 1, 0…
## $ life_activity_eating                            <int> 0, 0, 0, 0, 1, 1, 0, 1…
## $ life_red_stop_alcoh                             <int> 0, 0, 0, 0, 0, 0, 0, 0…
## $ comorbid_neuropathic                            <dbl> 0, 0, 0, 1, 1, 1, 0, 0…
## $ comorbid_arthritis                              <dbl> 0, 0, 0, 0, 0, 0, 0, 0…
## $ phq9_score_start                                <dbl> 6, 8, 8, 10, 3, 5, 5, …
## $ phq9_score_end                                  <dbl> 8, 8, 4, 3, 5, 1, 6, 5…
## $ phq9_cat_end                                    <dbl> 1, 1, 0, 0, 1, 0, 1, 1…
## $ phq9_cat_start                                  <dbl> 1, 1, 1, 2, 0, 1, 1, 1…
## $ `__index_level_0__`                             <chr> "4938_3", "4938_6", "4…

Models

# Load required libraries
library(tidyverse)
library(caret)
## Warning: package 'caret' was built under R version 4.4.3
## Loading required package: lattice
## 
## Attaching package: 'caret'
## The following object is masked from 'package:purrr':
## 
##     lift
# Step 1: Remove unnecessary columns
model_data <- dep_severity %>%
  select(-`__index_level_0__`, -phq9_score_start, -phq9_cat_start, -phq9_cat_end) %>%
  drop_na(phq9_score_end)

# Step 2: Remove highly sparse columns (optional, if still too many NAs)
model_data <- model_data %>%
  select(where(~ mean(!is.na(.)) > 0.8))

# Step 3: Drop remaining NAs (or you could impute)
model_data <- drop_na(model_data)

# Step 4: Partition the data (80% train, 20% test)
set.seed(123)
train_index <- createDataPartition(model_data$phq9_score_end, p = 0.8, list = FALSE)
train_data <- model_data[train_index, ]
test_data <- model_data[-train_index, ]

# Step 5: Fit a linear regression model
lm_model <- lm(phq9_score_end ~ ., data = train_data)

# Step 6: Model summary
summary(lm_model)
## 
## Call:
## lm(formula = phq9_score_end ~ ., data = train_data)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -15.4617  -3.5030  -0.8398   2.7416  24.2503 
## 
## Coefficients:
##                                                  Estimate Std. Error t value
## (Intercept)                                    -7.596e+01  3.158e+01  -2.405
## steps_awake_mean                                3.581e-04  4.584e-04   0.781
## sleep_asleep_weekday_mean                       5.564e-02  5.136e-02   1.083
## sleep_asleep_weekend_mean                       1.320e-02  8.597e-03   1.535
## sleep_in_bed_weekday_mean                      -4.233e-02  4.585e-02  -0.923
## sleep_in_bed_weekend_mean                      -1.183e-02  7.633e-03  -1.550
## sleep_ratio_asleep_in_bed_weekday_mean         -4.764e+01  2.598e+01  -1.834
## sleep_ratio_asleep_in_bed_weekend_mean         -6.476e+00  4.620e+00  -1.402
## sleep_main_start_hour_adj_median                2.080e-02  9.277e-02   0.224
## sleep_main_start_hour_adj_range                 2.711e-01  7.171e-02   3.780
## sleep__hypersomnia_count_                       1.729e-01  1.058e-01   1.635
## sleep__hyposomnia_count_                       -8.391e-02  7.681e-02  -1.092
## steps__active_day_count_                       -7.262e-03  5.138e-02  -0.141
## steps__sedentary_day_count_                     1.271e-01  5.039e-02   2.522
## sleep__main_start_hour_adj__score              -5.704e-01  4.695e-01  -1.215
## sleep__main_start_hour_adj__intercept           2.374e-01  2.700e-01   0.879
## sleep__main_start_hour_adj__coeff              -1.429e-02  2.017e+00  -0.007
## steps__awake__sum__score                       -1.772e-03  6.892e-01  -0.003
## steps__awake__sum__intercept                   -1.532e+00  2.519e+00  -0.608
## steps__awake__sum__coeff                       -9.851e+00  1.706e+01  -0.577
## steps__light_activity__sum__score              -6.874e-01  6.421e-01  -1.070
## steps__light_activity__sum__intercept           2.407e-01  3.720e-01   0.647
## steps__light_activity__sum__coeff               4.212e+00  4.460e+00   0.944
## steps__rolling_6_sum__max__score               -8.874e-01  5.380e-01  -1.650
## steps__rolling_6_sum__max__intercept           -5.983e-01  3.069e-01  -1.949
## steps__rolling_6_sum__max__coeff               -3.923e+00  3.482e+00  -1.127
## steps__streaks__countDistinct__score           -7.903e-01  5.311e-01  -1.488
## steps__streaks__countDistinct__intercept       -6.420e-02  1.336e-01  -0.481
## steps__streaks__countDistinct__coeff            8.512e-01  1.601e+00   0.532
## steps__not_moving__sum__score                   2.244e-01  5.826e-01   0.385
## steps__not_moving__sum__intercept              -6.618e-02  1.108e-01  -0.597
## steps__not_moving__sum__coeff                  -7.492e-01  1.445e+00  -0.518
## sleep__nap_count__score                         3.347e-02  1.605e-01   0.208
## sleep__nap_count__intercept                     7.761e-01  1.693e-01   4.585
## sleep__nap_count__coeff                         4.736e+00  1.459e+00   3.247
## sleep__total_asleep_minutes__score              2.211e+00  1.208e+00   1.830
## sleep__total_asleep_minutes__intercept         -6.574e+00  1.027e+01  -0.640
## sleep__total_asleep_minutes__coeff             -1.474e+01  6.982e+01  -0.211
## sleep__main_efficiency__score                  -1.087e+00  8.683e-01  -1.251
## sleep__main_efficiency__intercept              -6.114e-01  1.017e+00  -0.601
## sleep__main_efficiency__coeff                  -9.349e+00  9.560e+00  -0.978
## sleep__awake__sum__score                       -4.155e-01  7.666e-01  -0.542
## sleep__awake__sum__intercept                    1.117e-01  6.252e-01   0.179
## sleep__awake__sum__coeff                        3.815e+00  5.817e+00   0.656
## sleep__total_in_bed_minutes__score             -2.074e+00  1.194e+00  -1.737
## sleep__total_in_bed_minutes__intercept          4.401e+00  9.754e+00   0.451
## sleep__total_in_bed_minutes__coeff              3.252e+00  6.621e+01   0.049
## sleep__awake_regions__countDistinct__score     -2.882e-01  5.575e-01  -0.517
## sleep__awake_regions__countDistinct__intercept -9.228e-02  1.054e-01  -0.876
## sleep__awake_regions__countDistinct__coeff     -3.055e+00  1.419e+00  -2.152
## sleep_ratio_asleep_in_bed__score                7.195e-01  9.224e-01   0.780
## sleep_ratio_asleep_in_bed__intercept            5.714e+00  4.350e+00   1.314
## sleep_ratio_asleep_in_bed__coeff                3.348e+01  3.017e+01   1.110
## steps_mvpa_sum_recent                          -1.300e-03  2.018e-03  -0.644
## sleep_asleep_mean_recent                       -1.526e-02  1.051e-02  -1.451
## sleep_in_bed_mean_recent                        1.315e-02  9.359e-03   1.405
## sleep_ratio_asleep_in_bed_mean_recent           5.853e+00  6.026e+00   0.971
## steps_lpa_sum_recent                           -3.491e-03  1.992e-03  -1.752
## steps_rolling_6_median_recent                   1.389e-03  1.043e-03   1.332
## steps_rolling_6_max_recent                     -1.590e-04  6.114e-04  -0.260
## sex                                            -7.117e-01  1.929e-01  -3.689
## race_whiteTRUE                                  5.818e-01  3.056e-01   1.903
## race_blackTRUE                                 -8.812e-01  3.401e-01  -2.591
## race_hispanicTRUE                               8.804e-01  3.256e-01   2.704
## race_asianTRUE                                 -1.735e-01  3.830e-01  -0.453
## race_otherTRUE                                  2.519e-01  3.928e-01   0.641
## birthyear                                       5.586e-02  6.825e-03   8.185
## educ                                           -1.368e-01  4.410e-02  -3.101
## height                                          1.025e-01  7.257e-02   1.412
## weight                                         -1.867e-02  1.190e-02  -1.568
## bmi                                             1.270e-01  7.359e-02   1.726
## pregnant                                        2.300e-01  6.153e-01   0.374
## birth                                           4.387e-01  4.230e-01   1.037
## trauma                                          9.045e-01  1.802e-01   5.020
## insurance                                      -3.088e-01  2.557e-01  -1.207
## money                                           1.333e+00  7.635e-02  17.457
## money_assistance                                4.715e-01  1.861e-01   2.534
## household                                      -3.003e-02  4.240e-02  -0.708
## comorbid_cancer                                 6.758e-01  3.015e-01   2.241
## comorbid_diabetes_typ1                         -1.376e+00  7.178e-01  -1.918
## comorbid_diabetes_typ2                          9.096e-02  2.551e-01   0.356
## comorbid_gout                                   2.194e+00  3.812e-01   5.755
## comorbid_migraines                              1.351e+00  1.536e-01   8.799
## comorbid_ms                                    -6.138e-01  5.175e-01  -1.186
## comorbid_osteoporosis                           1.585e+00  4.221e-01   3.756
## num_migraine_days                               7.550e-01  8.234e-02   9.170
## meds_migraine                                   3.648e-01  2.476e-01   1.473
## med_start                                       1.248e+00  2.044e-01   6.107
## med_stop                                        8.231e-01  3.455e-01   2.382
## med_dose                                        1.844e+00  3.290e-01   5.605
## nonmed_start                                    2.585e-01  1.954e-01   1.323
## nonmed_stop                                     6.430e-01  3.692e-01   1.742
## life_meditation                                 7.118e-01  3.460e-01   2.057
## life_stress                                     1.392e-02  3.230e-01   0.043
## med_nonmed_dnu                                 -8.069e-01  1.239e-01  -6.513
## life_activity_eating                           -5.397e-01  1.771e-01  -3.047
## life_red_stop_alcoh                             2.519e-01  3.193e-01   0.789
## comorbid_neuropathic                            1.272e+00  1.157e-01  11.002
## comorbid_arthritis                              5.511e-01  1.306e-01   4.219
##                                                Pr(>|t|)    
## (Intercept)                                    0.016181 *  
## steps_awake_mean                               0.434698    
## sleep_asleep_weekday_mean                      0.278652    
## sleep_asleep_weekend_mean                      0.124834    
## sleep_in_bed_weekday_mean                      0.355944    
## sleep_in_bed_weekend_mean                      0.121075    
## sleep_ratio_asleep_in_bed_weekday_mean         0.066686 .  
## sleep_ratio_asleep_in_bed_weekend_mean         0.161101    
## sleep_main_start_hour_adj_median               0.822576    
## sleep_main_start_hour_adj_range                0.000158 ***
## sleep__hypersomnia_count_                      0.102080    
## sleep__hyposomnia_count_                       0.274658    
## steps__active_day_count_                       0.887604    
## steps__sedentary_day_count_                    0.011681 *  
## sleep__main_start_hour_adj__score              0.224510    
## sleep__main_start_hour_adj__intercept          0.379396    
## sleep__main_start_hour_adj__coeff              0.994348    
## steps__awake__sum__score                       0.997949    
## steps__awake__sum__intercept                   0.543226    
## steps__awake__sum__coeff                       0.563739    
## steps__light_activity__sum__score              0.284460    
## steps__light_activity__sum__intercept          0.517574    
## steps__light_activity__sum__coeff              0.345060    
## steps__rolling_6_sum__max__score               0.099072 .  
## steps__rolling_6_sum__max__intercept           0.051299 .  
## steps__rolling_6_sum__max__coeff               0.259944    
## steps__streaks__countDistinct__score           0.136801    
## steps__streaks__countDistinct__intercept       0.630880    
## steps__streaks__countDistinct__coeff           0.595009    
## steps__not_moving__sum__score                  0.700075    
## steps__not_moving__sum__intercept              0.550467    
## steps__not_moving__sum__coeff                  0.604125    
## sleep__nap_count__score                        0.834870    
## sleep__nap_count__intercept                    4.62e-06 ***
## sleep__nap_count__coeff                        0.001173 ** 
## sleep__total_asleep_minutes__score             0.067264 .  
## sleep__total_asleep_minutes__intercept         0.522263    
## sleep__total_asleep_minutes__coeff             0.832784    
## sleep__main_efficiency__score                  0.210852    
## sleep__main_efficiency__intercept              0.547673    
## sleep__main_efficiency__coeff                  0.328136    
## sleep__awake__sum__score                       0.587831    
## sleep__awake__sum__intercept                   0.858238    
## sleep__awake__sum__coeff                       0.511995    
## sleep__total_in_bed_minutes__score             0.082351 .  
## sleep__total_in_bed_minutes__intercept         0.651837    
## sleep__total_in_bed_minutes__coeff             0.960829    
## sleep__awake_regions__countDistinct__score     0.605261    
## sleep__awake_regions__countDistinct__intercept 0.381097    
## sleep__awake_regions__countDistinct__coeff     0.031407 *  
## sleep_ratio_asleep_in_bed__score               0.435343    
## sleep_ratio_asleep_in_bed__intercept           0.189046    
## sleep_ratio_asleep_in_bed__coeff               0.267201    
## steps_mvpa_sum_recent                          0.519461    
## sleep_asleep_mean_recent                       0.146829    
## sleep_in_bed_mean_recent                       0.160021    
## sleep_ratio_asleep_in_bed_mean_recent          0.331500    
## steps_lpa_sum_recent                           0.079758 .  
## steps_rolling_6_median_recent                  0.182942    
## steps_rolling_6_max_recent                     0.794844    
## sex                                            0.000227 ***
## race_whiteTRUE                                 0.057028 .  
## race_blackTRUE                                 0.009586 ** 
## race_hispanicTRUE                              0.006867 ** 
## race_asianTRUE                                 0.650620    
## race_otherTRUE                                 0.521368    
## birthyear                                      3.18e-16 ***
## educ                                           0.001936 ** 
## height                                         0.157981    
## weight                                         0.116931    
## bmi                                            0.084417 .  
## pregnant                                       0.708512    
## birth                                          0.299700    
## trauma                                         5.29e-07 ***
## insurance                                      0.227328    
## money                                           < 2e-16 ***
## money_assistance                               0.011304 *  
## household                                      0.478880    
## comorbid_cancer                                0.025024 *  
## comorbid_diabetes_typ1                         0.055207 .  
## comorbid_diabetes_typ2                         0.721478    
## comorbid_gout                                  9.00e-09 ***
## comorbid_migraines                              < 2e-16 ***
## comorbid_ms                                    0.235625    
## comorbid_osteoporosis                          0.000174 ***
## num_migraine_days                               < 2e-16 ***
## meds_migraine                                  0.140699    
## med_start                                      1.07e-09 ***
## med_stop                                       0.017230 *  
## med_dose                                       2.16e-08 ***
## nonmed_start                                   0.185735    
## nonmed_stop                                    0.081633 .  
## life_meditation                                0.039677 *  
## life_stress                                    0.965613    
## med_nonmed_dnu                                 7.88e-11 ***
## life_activity_eating                           0.002321 ** 
## life_red_stop_alcoh                            0.430273    
## comorbid_neuropathic                            < 2e-16 ***
## comorbid_arthritis                             2.49e-05 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 4.997 on 7298 degrees of freedom
## Multiple R-squared:  0.3235, Adjusted R-squared:  0.3145 
## F-statistic: 35.62 on 98 and 7298 DF,  p-value: < 2.2e-16
# Step 7: Predict on test data
predictions <- predict(lm_model, newdata = test_data)

# Step 8: Evaluate performance
rmse <- sqrt(mean((test_data$phq9_score_end - predictions)^2))
mae <- mean(abs(test_data$phq9_score_end - predictions))

cat("RMSE:", rmse, "\nMAE:", mae)
## RMSE: 5.078846 
## MAE: 3.988081

Model Performance RMSE: 5.08 → On average, predictions deviate by about 5 points from actual PHQ-9 scores.

MAE: 3.99 → The average absolute error is roughly 4 points.

R²: 0.32 → About 32% of the variation in depression severity is explained by the model. Not huge, but solid given the complexity of mental health.

Key Significant Predictors (p < 0.05) These variables had a statistically significant relationship with the depression score:

Demographics sex: Being male was negatively associated with depression severity.

birthyear: Younger participants showed higher scores.

educ: Higher education was associated with lower depression severity.

race_black, race_hispanic: Both were significant compared to the reference group (likely white).

money: Strong positive correlation — perceived financial hardship is a top predictor.

Medical History comorbid_migraines, comorbid_neuropathic, comorbid_arthritis, comorbid_gout: These comorbidities showed strong links to higher depression scores.

trauma: Strong association with higher depression severity.

Treatment med_start, med_dose, med_stop: Medication usage patterns are all predictive.

med_nonmed_dnu: Those not taking either treatment had significantly worse scores.

Lifestyle life_meditation: Associated with slightly lower depression scores.

life_activity_eating: Better eating habits linked with lower scores.

⚠Non-Significant or Noisy Predictors Many sensor-derived activity and sleep metrics (e.g. steps__awake__sum__coeff) showed no clear signal. These may contain noise or require transformation/interactions.

Random Forest

# Load required packages
library(randomForest)
## Warning: package 'randomForest' was built under R version 4.4.3
## randomForest 4.7-1.2
## Type rfNews() to see new features/changes/bug fixes.
## 
## Attaching package: 'randomForest'
## The following object is masked from 'package:dplyr':
## 
##     combine
## The following object is masked from 'package:ggplot2':
## 
##     margin
library(caret)

# Step 1: Select relevant predictors based on significance/domain knowledge
selected_vars <- c(
  "phq9_score_end", "sex", "birthyear", "educ", "money", "money_assistance", 
  "comorbid_migraines", "comorbid_neuropathic", "comorbid_arthritis", "comorbid_gout",
  "trauma", "med_start", "med_stop", "med_dose", "life_meditation", 
  "life_activity_eating", "med_nonmed_dnu", "insurance"
)

# Subset the data
dep_rf <- dep_severity[, selected_vars]

# Remove rows with any NA in selected features
dep_rf <- na.omit(dep_rf)

# Step 2: Split into training and testing sets
set.seed(123)
split_idx <- createDataPartition(dep_rf$phq9_score_end, p = 0.8, list = FALSE)
train_rf <- dep_rf[split_idx, ]
test_rf <- dep_rf[-split_idx, ]

# Step 3: Train Random Forest model
set.seed(123)
rf_model <- randomForest(phq9_score_end ~ ., data = train_rf, ntree = 500, importance = TRUE)

# Step 4: Predict and evaluate
pred_rf <- predict(rf_model, test_rf)

# Evaluate performance
rf_rmse <- RMSE(pred_rf, test_rf$phq9_score_end)
rf_mae <- MAE(pred_rf, test_rf$phq9_score_end)
cat("Random Forest RMSE:", rf_rmse, "\n")
## Random Forest RMSE: 4.504538
cat("Random Forest MAE:", rf_mae, "\n")
## Random Forest MAE: 3.529064
# View variable importance
importance(rf_model)
##                        %IncMSE IncNodePurity
## sex                   64.15858      6970.362
## birthyear            119.50108     43990.661
## educ                  91.42414     18783.128
## money                134.35017     27796.766
## money_assistance      63.02093      7726.829
## comorbid_migraines   120.07532     23944.718
## comorbid_neuropathic 123.58975     23200.646
## comorbid_arthritis    70.98542      9445.796
## comorbid_gout         45.33309      2875.445
## trauma                59.95942      5743.452
## med_start             30.57675      5073.416
## med_stop              12.31824      2661.148
## med_dose              32.23682      3879.842
## life_meditation       12.01087      2408.095
## life_activity_eating  19.49664      5286.878
## med_nonmed_dnu        58.15057      6814.954
## insurance             46.94399      3796.052
varImpPlot(rf_model)

Model 1: Linear Regression Root Mean Squared Error (RMSE): 5.08

Mean Absolute Error (MAE): 3.99

Adjusted R²: 0.3145

Linear regression provided a moderately accurate and interpretable model. Several features—such as money-related variables, comorbidities, and trauma history—were statistically significant. However, the model assumed linear relationships and may not have captured interactions or non-linear patterns effectively.

Model 2: Random Forest Root Mean Squared Error (RMSE): 4.50

Mean Absolute Error (MAE): 3.53

The random forest model outperformed linear regression on both error metrics. This model can capture complex interactions between features and is more robust to outliers and non-linearities. Key predictors included:

money

comorbid_migraines

comorbid_neuropathic

birthyear

education level

trauma

insurance status

Conclusion The Random Forest model demonstrated better predictive performance, as evidenced by lower RMSE and MAE values. While it sacrifices interpretability, it more effectively captures the complex relationships within the data, making it the preferred model for prediction in this case.

Given the wide availability of user-generated text data related to emotional well-being (e.g., forum posts, social media updates, surveys), it is critical to transform these qualitative expressions into structured formats that can support analysis, pattern recognition, and intervention. Sentiment analysis — particularly in the context of mental health — provides a valuable lens through which to interpret subjective content and identify emotional distress in a scalable and interpretable way.

In the current study, applying sentiment analysis is justified for several reasons:

Understanding Emotional Severity Posts vary significantly in tone, ranging from mild frustration to severe psychological distress. Sentiment classification allows us to assign approximate severity levels (e.g., minimum, mild, moderate, severe), enabling more precise analysis and triage.

Scalability for Large-Scale Data Manual review of thousands of text entries is not feasible. Sentiment analysis enables automated and consistent categorization of mental health-related expressions, making it possible to study emotional patterns at scale.

Support for Early Intervention In mental health contexts, identifying posts that reflect severe or worsening emotional states can inform the design of digital alerts, clinical referral systems, or chatbot triage protocols, helping to prioritize support for individuals at higher risk.

Capturing Changes Over Time When applied longitudinally, sentiment trends can reveal how an individual’s mental state evolves in response to life events or interventions. This is especially useful in digital mental health platforms or treatment monitoring systems.

Unlocking Unstructured Text Unlike survey data with predefined categories, this dataset includes natural language input. Sentiment analysis leverages NLP techniques to convert this rich but unstructured data into meaningful, structured insights.

By incorporating sentiment analysis into this project, we expand the analytical toolkit available for understanding early signs of mental health deterioration, particularly when symptoms manifest in language before formal diagnosis or clinical observation.

Sentiment analysis

library(readr)
library(dplyr)
reddit_url <- "https://raw.githubusercontent.com/usmaann/Depression_Severity_Dataset/refs/heads/main/Reddit_depression_dataset.csv"
reddit_data <- read_csv(reddit_url)
## Rows: 3553 Columns: 2
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (2): text, label
## 
## ℹ 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.

Exploring the dataset:

glimpse(reddit_data)
## Rows: 3,553
## Columns: 2
## $ text  <chr> "He said he had not felt that way before, suggeted I go rest and…
## $ label <chr> "mild", "minimum", "minimum", "mild", "moderate", "mild", "minim…
table(reddit_data$label)
## 
##     mild  minimum moderate   severe 
##      290     2587      394      282

Sentiment Severity Analysis Using Reddit Posts To deepen the exploration of mental health indicators, we incorporated a publicly available dataset containing Reddit posts labeled by depression severity (mild, moderate, severe, and minimum). This text-based dataset enables a complementary approach to our earlier physiological and demographic modeling by leveraging natural language content directly expressed by users experiencing varying levels of distress.

The rationale for conducting sentiment severity analysis is twofold:

First, textual self-expression often reflects emotional intensity and psychological state, offering a valuable proxy for mental health classification.

Second, augmenting physiological signals with language analysis can enhance predictive accuracy and may help surface early indicators of mental health crises not yet evident in behavioral data.

By classifying these posts, we aim to understand how specific expressions and themes correlate with clinical labels of depression severity. This could support the development of models that automatically flag at-risk individuals based on written language—a scalable tool for early intervention in digital mental health monitoring systems.

library(tidytext)
library(textclean)
## Warning: package 'textclean' was built under R version 4.4.3
library(tm)
## Warning: package 'tm' was built under R version 4.4.3
## Loading required package: NLP
## 
## Attaching package: 'NLP'
## The following object is masked from 'package:ggplot2':
## 
##     annotate
library(SnowballC)
#install.packages("textstem")
library(textstem)
## Warning: package 'textstem' was built under R version 4.4.3
## Loading required package: koRpus.lang.en
## Warning: package 'koRpus.lang.en' was built under R version 4.4.3
## Loading required package: koRpus
## Warning: package 'koRpus' was built under R version 4.4.3
## Loading required package: sylly
## Warning: package 'sylly' was built under R version 4.4.3
## For information on available language packages for 'koRpus', run
## 
##   available.koRpus.lang()
## 
## and see ?install.koRpus.lang()
## 
## Attaching package: 'koRpus'
## The following object is masked from 'package:tm':
## 
##     readTagged
## The following object is masked from 'package:readr':
## 
##     tokenize
library(dplyr)
# Clean text
reddit_data_clean <- reddit_data %>%
  mutate(text = replace_html(text),
         text = replace_contraction(text),
         text = tolower(text),
         text = removePunctuation(text),
         text = removeNumbers(text),
         text = stripWhitespace(text))
reddit_data_clean$text <- lemmatize_strings(reddit_data_clean$text)
data("stop_words")

reddit_tokens <- reddit_data_clean %>%
  unnest_tokens(word, text) %>%
  anti_join(stop_words, by = "word")
# Count word frequencies per label
word_freq <- reddit_tokens %>%
  count(label, word, sort = TRUE)

# View top words by severity (optional)
word_freq %>% group_by(label) %>% top_n(10, n) %>% ungroup()
## # A tibble: 40 × 3
##    label   word       n
##    <chr>   <chr>  <int>
##  1 minimum time     846
##  2 minimum feel     791
##  3 minimum friend   493
##  4 minimum people   430
##  5 minimum day      427
##  6 minimum start    396
##  7 minimum talk     383
##  8 minimum month    363
##  9 minimum life     356
## 10 minimum live     328
## # ℹ 30 more rows
# Calculate tf-idf
tf_idf_data <- word_freq %>%
  bind_tf_idf(word, label, n) %>%
  arrange(desc(tf_idf))

# View top tf-idf words per severity
tf_idf_data %>%
  group_by(label) %>%
  top_n(10, tf_idf) %>%
  ungroup()
## # A tibble: 67 × 6
##    label    word            n       tf   idf   tf_idf
##    <chr>    <chr>       <int>    <dbl> <dbl>    <dbl>
##  1 minimum  survey        106 0.00172  0.693 0.00119 
##  2 mild     hopeless       11 0.00148  0.693 0.00103 
##  3 minimum  link           74 0.00120  0.693 0.000830
##  4 severe   humiliation     3 0.000456 1.39  0.000632
##  5 severe   incest          3 0.000456 1.39  0.000632
##  6 minimum  share         134 0.00217  0.288 0.000624
##  7 minimum  request        27 0.000437 1.39  0.000606
##  8 minimum  payment        25 0.000405 1.39  0.000561
##  9 mild     wallow          3 0.000403 1.39  0.000559
## 10 moderate cognition       4 0.000391 1.39  0.000543
## # ℹ 57 more rows
library(ggplot2)

tf_idf_data %>%
  group_by(label) %>%
  top_n(10, tf_idf) %>%
  ungroup() %>%
  mutate(word = reorder_within(word, tf_idf, label)) %>%
  ggplot(aes(tf_idf, word, fill = label)) +
  geom_col(show.legend = FALSE) +
  facet_wrap(~label, scales = "free") +
  scale_y_reordered() +
  labs(title = "Top TF-IDF Words by Depression Severity")

Key Observations: Mild Severity: Posts in this category often contain emotionally descriptive terms like hopeless, heartbroken, gas, and wound. These may reflect emotional discomfort without clear clinical features.

Minimum Severity: This class is dominated by words such as survey, link, request, and gofundme, indicating a large proportion of posts related to general information sharing or resource-seeking, rather than personal emotional expression.

Moderate Severity: Terms like insomnia, asleep, tablet, irritable, and hyperventilate highlight somatic and psychological symptoms typical of clinical depression.

Severe Severity: This group features intense and concerning terms like suicidal, dissociation, ideation, and humiliation. These indicate serious mental health crises, including suicidal thoughts and severe emotional distress.

Implications: This analysis supports the idea that language patterns differ meaningfully across depression severity levels. These distinctions can inform the development of machine learning models by highlighting which lexical features are most informative for predicting severity. Furthermore, recognizing severity-specific keywords can assist moderators, clinicians, or support platforms in prioritizing high-risk content for timely intervention.

# Load required packages
library(tm)
library(SnowballC)
library(caret)
library(randomForest)
library(dplyr)



# STEP 2: Sample a subset of the data
set.seed(123)
reddit_sample <- reddit_data %>% sample_n(500)

# STEP 3: Text cleaning
reddit_sample$text <- tolower(reddit_sample$text)
reddit_sample$text <- gsub("[^a-z\\s]", "", reddit_sample$text)
reddit_sample$text <- gsub("\\s+", " ", reddit_sample$text)

# STEP 4: Create a corpus and DTM
corpus <- VCorpus(VectorSource(reddit_sample$text))
corpus <- tm_map(corpus, removeWords, stopwords("en"))
corpus <- tm_map(corpus, stemDocument)
corpus <- tm_map(corpus, stripWhitespace)

dtm <- DocumentTermMatrix(corpus)

# STEP 5: Convert DTM to dataframe and attach labels
data_features <- as.data.frame(as.matrix(dtm))
colnames(data_features) <- make.names(colnames(data_features), unique = TRUE)
data_features$label <- as.factor(reddit_sample$label)

# STEP 6: Train-test split
set.seed(123)
train_index <- createDataPartition(data_features$label, p = 0.8, list = FALSE)
train_data <- data_features[train_index, ]
test_data <- data_features[-train_index, ]

# STEP 7: Train Random Forest model (with fewer trees to avoid slow training)
model_rf <- randomForest(label ~ ., data = train_data, ntree = 20, importance = TRUE)

# STEP 8: Predict and evaluate
predictions <- predict(model_rf, newdata = test_data)
confusionMatrix(predictions, test_data$label)
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction mild minimum moderate severe
##   mild        0       0        0      0
##   minimum     8      72        9     10
##   moderate    0       0        0      0
##   severe      0       0        0      0
## 
## Overall Statistics
##                                          
##                Accuracy : 0.7273         
##                  95% CI : (0.6285, 0.812)
##     No Information Rate : 0.7273         
##     P-Value [Acc > NIR] : 0.5516         
##                                          
##                   Kappa : 0              
##                                          
##  Mcnemar's Test P-Value : NA             
## 
## Statistics by Class:
## 
##                      Class: mild Class: minimum Class: moderate Class: severe
## Sensitivity              0.00000         1.0000         0.00000         0.000
## Specificity              1.00000         0.0000         1.00000         1.000
## Pos Pred Value               NaN         0.7273             NaN           NaN
## Neg Pred Value           0.91919            NaN         0.90909         0.899
## Prevalence               0.08081         0.7273         0.09091         0.101
## Detection Rate           0.00000         0.7273         0.00000         0.000
## Detection Prevalence     0.00000         1.0000         0.00000         0.000
## Balanced Accuracy        0.50000         0.5000         0.50000         0.500
# Load libraries
library(tm)
library(SnowballC)
library(caret)
library(e1071)
## Warning: package 'e1071' was built under R version 4.4.3
library(dplyr)

# STEP 1: Load and prepare dataset
#reddit_data <- read.csv("C:/Users/aleja/Downloads/Reddit_depression_dataset.csv")
reddit_data$label <- as.factor(reddit_data$label)

# STEP 2: Balance the dataset using downsampling
set.seed(123)
min_class_size <- min(table(reddit_data$label))
balanced_data <- reddit_data %>%
  group_by(label) %>%
  slice_sample(n = min_class_size) %>%
  ungroup()

# STEP 3: Text preprocessing
balanced_data$text <- tolower(balanced_data$text)
balanced_data$text <- gsub("[^a-z\\s]", "", balanced_data$text)
balanced_data$text <- gsub("\\s+", " ", balanced_data$text)

# STEP 4: Corpus and DTM
corpus <- VCorpus(VectorSource(balanced_data$text))
corpus <- tm_map(corpus, removeWords, stopwords("en"))
corpus <- tm_map(corpus, stemDocument)
corpus <- tm_map(corpus, stripWhitespace)

dtm <- DocumentTermMatrix(corpus)
data_features <- as.data.frame(as.matrix(dtm))
colnames(data_features) <- make.names(colnames(data_features), unique = TRUE)

# STEP 5: Reattach labels (ensure they're in the right place)
data_features$label <- balanced_data$label
data_features$label <- as.factor(data_features$label)  # ensure factor

# STEP 6: Train/test split
set.seed(123)
train_index <- createDataPartition(data_features$label, p = 0.8, list = FALSE)
train_data <- data_features[train_index, ]
test_data <- data_features[-train_index, ]

# Force conversion to pure data frames
train_data <- as.data.frame(train_data)
test_data <- as.data.frame(test_data)

# STEP 7: Naive Bayes model
library(e1071)
model_nb <- naiveBayes(label ~ ., data = train_data)

# STEP 8: Predict and evaluate
predictions <- predict(model_nb, newdata = test_data)
confusionMatrix(predictions, test_data$label)
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction mild minimum moderate severe
##   mild       56      56       56     56
##   minimum     0       0        0      0
##   moderate    0       0        0      0
##   severe      0       0        0      0
## 
## Overall Statistics
##                                          
##                Accuracy : 0.25           
##                  95% CI : (0.1947, 0.312)
##     No Information Rate : 0.25           
##     P-Value [Acc > NIR] : 0.5256         
##                                          
##                   Kappa : 0              
##                                          
##  Mcnemar's Test P-Value : NA             
## 
## Statistics by Class:
## 
##                      Class: mild Class: minimum Class: moderate Class: severe
## Sensitivity                 1.00           0.00            0.00          0.00
## Specificity                 0.00           1.00            1.00          1.00
## Pos Pred Value              0.25            NaN             NaN           NaN
## Neg Pred Value               NaN           0.75            0.75          0.75
## Prevalence                  0.25           0.25            0.25          0.25
## Detection Rate              0.25           0.00            0.00          0.00
## Detection Prevalence        1.00           0.00            0.00          0.00
## Balanced Accuracy           0.50           0.50            0.50          0.50

LS0tDQp0aXRsZTogIklkZW50aWZ5aW5nIEVhcmx5IFNpZ25zIG9mIE1lbnRhbCBIZWFsdGggQ3Jpc2VzIg0KYXV0aG9yOiAiTGF1cmEgQiINCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCINCm91dHB1dDogb3BlbmludHJvOjpsYWJfcmVwb3J0DQotLS0NCg0KIyBJbnRyb2R1Y3Rpb24NCg0KDQojIExvYWRpbmcgZGF0YXNldHMNCg0KTG9hZGluZyBkYXRhc2V0IGZvciBhZHVsdHMNCg0KYGBge3J9DQojIExvYWRpbmcgcmVxdWlyZWQgbGlicmFyaWVzDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCg0KIyBTdGVwIDE6IFJlYWRpbmcgdGhlIENTViBmaWxlDQpuaGlzX2FkdWx0IDwtIHJlYWRfY3N2KCJDOi9Vc2Vycy9hbGVqYS9Eb3dubG9hZHMvTkhJU19BZHVsdF9TdW1tYXJ5X0hlYWx0aF9TdGF0aXN0aWNzXzIwMjUwNTExLmNzdiIpDQoNCiMgU3RlcCAyOiBJbnNwZWN0aW5nIHN0cnVjdHVyZQ0KZ2xpbXBzZShuaGlzX2FkdWx0KQ0KDQoNCg0KYGBgDQoNCiMjIERhdGEgY2xlYW5pbmcNCkZvciBkYXRhc2V0IGFkdWx0cw0KDQpSZW5hbWluZyBjb2x1bW5zDQpgYGB7cn0NCm5oaXNfYWR1bHQgPC0gbmhpc19hZHVsdCAlPiUNCiAgcmVuYW1lKA0KICAgIG91dGNvbWVfb3JfaW5kaWNhdG9yID0gYE91dGNvbWUgKG9yIEluZGljYXRvcilgLA0KICAgIGdyb3VwaW5nX2NhdGVnb3J5ID0gYEdyb3VwaW5nIGNhdGVnb3J5YCwNCiAgICBjb25maWRlbmNlX2ludGVydmFsID0gYENvbmZpZGVuY2UgSW50ZXJ2YWxgDQogICkNCg0KYGBgDQoNCkNoZWNraW5nIGZvciBtaXNzaW5nIHZhbHVlcw0KDQpgYGB7cn0NCiMgQ291bnRpbmcgbWlzc2luZyB2YWx1ZXMgcGVyIGNvbHVtbg0KY29sU3Vtcyhpcy5uYShuaGlzX2FkdWx0KSkNCg0KYGBgDQpEYXRhc2V0IGhhcyAwIG1pc3NpbmcgdmFsdWVzIG9yIE5BLg0KDQpFeHBsb3JpbmcgQXZhaWxhYmxlIE91dGNvbWVzIChMb29rIGZvciBNZW50YWwgSGVhbHRoIFRvcGljcykNCg0KYGBge3J9DQojIFZpZXcgdW5pcXVlIGhlYWx0aCBvdXRjb21lcyB0byBmaW5kIGRlcHJlc3Npb24tcmVsYXRlZCByb3dzDQp1bmlxdWUobmhpc19hZHVsdCRvdXRjb21lX29yX2luZGljYXRvcikNCg0KYGBgDQoNClRvIGFkZHJlc3MgdGhlIHJlc2VhcmNoIG9iamVjdGl2ZSBvZiBpZGVudGlmeWluZyBlYXJseSBzaWducyBvZiBtZW50YWwgaGVhbHRoIGNyaXNlcyB1c2luZyBzb2NpYWwgYW5kIGVjb25vbWljIGRhdGEsIHRoaXMgc3R1ZHkgZm9jdXNlcyBvbiBhIHRhcmdldGVkIHN1YnNldCBvZiBpbmRpY2F0b3JzIGZyb20gdGhlIE5hdGlvbmFsIEhlYWx0aCBJbnRlcnZpZXcgU3VydmV5IChOSElTKSBBZHVsdCBkYXRhc2V0LiBGaXZlIGluZGljYXRvcnMgd2VyZSBzZWxlY3RlZCBiYXNlZCBvbiB0aGVpciBkaXJlY3QgcmVsZXZhbmNlIHRvIG1lbnRhbCBoZWFsdGggZGlzdHJlc3MsIGhlYWx0aGNhcmUgZW5nYWdlbWVudCwgYW5kIGFjY2VzcyB0byBzZXJ2aWNlczoNCg0KUmVndWxhcmx5IGhhZCBmZWVsaW5ncyBvZiBkZXByZXNzaW9uDQoNClRha2luZyBwcmVzY3JpcHRpb24gbWVkaWNhdGlvbiBmb3IgZmVlbGluZ3Mgb2YgZGVwcmVzc2lvbg0KDQpSZWd1bGFybHkgaGFkIGZlZWxpbmdzIG9mIHdvcnJ5LCBuZXJ2b3VzbmVzcywgb3IgYW54aWV0eQ0KDQpUYWtpbmcgcHJlc2NyaXB0aW9uIG1lZGljYXRpb24gZm9yIGZlZWxpbmdzIG9mIHdvcnJ5LCBuZXJ2b3VzbmVzcywgb3IgYW54aWV0eQ0KDQpEaWQgbm90IGdldCBuZWVkZWQgbWVudGFsIGhlYWx0aCBjYXJlIGR1ZSB0byBjb3N0DQoNClRoZXNlIGluZGljYXRvcnMgd2VyZSBjaG9zZW4gZm9yIHRocmVlIGtleSByZWFzb25zLiBGaXJzdCwgdGhleSBvZmZlciBlYXJseSwgc2VsZi1yZXBvcnRlZCBzeW1wdG9tcyBvZiBwc3ljaG9sb2dpY2FsIGRpc3RyZXNzIChpbmRpY2F0b3JzIDEgYW5kIDMpLCB3aGljaCBhcmUgZXNzZW50aWFsIGZvciBkZXRlY3RpbmcgdGhlIG9uc2V0IG9mIG1lbnRhbCBoZWFsdGggY3Jpc2VzIHByaW9yIHRvIGZvcm1hbCBkaWFnbm9zaXMuIFNlY29uZCwgdGhleSByZWZsZWN0IGVuZ2FnZW1lbnQgd2l0aCB0aGUgaGVhbHRoY2FyZSBzeXN0ZW0gdGhyb3VnaCB0cmVhdG1lbnQgYmVoYXZpb3JzIChpbmRpY2F0b3JzIDIgYW5kIDQpLCBhbGxvd2luZyB0aGUgYW5hbHlzaXMgdG8gZGlzdGluZ3Vpc2ggYmV0d2VlbiB0cmVhdGVkIGFuZCB1bnRyZWF0ZWQgcG9wdWxhdGlvbnMuIFRoaXJkLCB0aGV5IGluY2x1ZGUgYSBtZWFzdXJlIG9mIHVubWV0IG5lZWQgZHVlIHRvIGZpbmFuY2lhbCBiYXJyaWVycyAoaW5kaWNhdG9yIDUpLCBhIGNyaXRpY2FsIGZhY3RvciBpbiB1bmRlcnN0YW5kaW5nIGRpc3Bhcml0aWVzIGluIGFjY2VzcyB0byBtZW50YWwgaGVhbHRoIHNlcnZpY2VzLg0KDQpCeSBmb2N1c2luZyBvbiB0aGVzZSBpbmRpY2F0b3JzLCB0aGUgYW5hbHlzaXMgcmVtYWlucyBhbGlnbmVkIHdpdGggdGhlIHN0dWR54oCZcyBjb3JlIGh5cG90aGVzZXPigJRzcGVjaWZpY2FsbHksIHRoYXQgZWNvbm9taWMgaGFyZHNoaXAsIGFjY2VzcyBsaW1pdGF0aW9ucywgYW5kIHJlYWwtdGltZSBzZW50aW1lbnQgYXJlIHN0cm9uZyBwcmVkaWN0b3JzIG9mIG1lbnRhbCBoZWFsdGggZGV0ZXJpb3JhdGlvbi4gQWRkaXRpb25hbGx5LCB0aGlzIGZvY3VzZWQgYXBwcm9hY2ggZW5zdXJlcyBhbmFseXRpY2FsIGNsYXJpdHksIGF2b2lkcyByZWR1bmRhbmN5LCBhbmQgZW5oYW5jZXMgdGhlIGludGVycHJldGFiaWxpdHkgb2YgdGhlIHJlc3VsdHMgaW4gcHJlZGljdGl2ZSBtb2RlbGluZyBjb250ZXh0cy4NCg0KRmlsdGVyaW5nIGRhdGFzZXQ6DQpgYGB7cn0NCm1oX2luZGljYXRvcnMgPC0gbmhpc19hZHVsdCAlPiUNCiAgZmlsdGVyKG91dGNvbWVfb3JfaW5kaWNhdG9yICVpbiUgYygNCiAgICAiUmVndWxhcmx5IGhhZCBmZWVsaW5ncyBvZiBkZXByZXNzaW9uIiwNCiAgICAiVGFraW5nIHByZXNjcmlwdGlvbiBtZWRpY2F0aW9uIGZvciBmZWVsaW5ncyBvZiBkZXByZXNzaW9uIiwNCiAgICAiUmVndWxhcmx5IGhhZCBmZWVsaW5ncyBvZiB3b3JyeSwgbmVydm91c25lc3MsIG9yIGFueGlldHkiLA0KICAgICJUYWtpbmcgcHJlc2NyaXB0aW9uIG1lZGljYXRpb24gZm9yIGZlZWxpbmdzIG9mIHdvcnJ5LCBuZXJ2b3VzbmVzcywgb3IgYW54aWV0eSIsDQogICAgIkRpZCBub3QgZ2V0IG5lZWRlZCBtZW50YWwgaGVhbHRoIGNhcmUgZHVlIHRvIGNvc3QiDQogICkpDQoNCmBgYA0KDQoNCg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHN0cmluZ3IpDQoNCiMgU2hvcnRlbmluZyBsb25nIGZhY2V0IGxhYmVscyBieSB3cmFwcGluZyB0aGVtDQptaF9pbmRpY2F0b3JzIDwtIG1oX2luZGljYXRvcnMgJT4lDQogIG11dGF0ZShvdXRjb21lX3dyYXBwZWQgPSBzdHJfd3JhcChvdXRjb21lX29yX2luZGljYXRvciwgd2lkdGggPSAzMCkpDQoNCiMgUGxvdHRpbmcgd2l0aCByb3RhdGVkIHgtYXhpcyBhbmQgd3JhcHBlZCBmYWNldCBsYWJlbHMNCm1oX2luZGljYXRvcnMgJT4lDQogIGZpbHRlcihncm91cGluZ19jYXRlZ29yeSA9PSAiU2V4IikgJT4lDQogIGdncGxvdChhZXMoeCA9IFllYXIsIHkgPSBQZXJjZW50YWdlLCBjb2xvciA9IEdyb3VwKSkgKw0KICBnZW9tX2xpbmUobGluZXdpZHRoID0gMS4yKSArDQogIGZhY2V0X3dyYXAofiBvdXRjb21lX3dyYXBwZWQsIHNjYWxlcyA9ICJmcmVlX3kiKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiVHJlbmRzIGluIE1lbnRhbCBIZWFsdGggSW5kaWNhdG9ycyBieSBTZXggKE5ISVMgQWR1bHRzKSIsDQogICAgeCA9ICJZZWFyIiwNCiAgICB5ID0gIlBlcmNlbnRhZ2UiDQogICkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZSgNCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpLCAgIyByb3RhdGVzIHggbGFiZWxzDQogICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApICAgICAgICAgICAgICAgICMgcmVkdWNlcyBmYWNldCB0aXRsZSBzaXplDQogICkNCg0KDQpgYGANCg0KDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoc3RyaW5ncikNCg0KIyBTdGVwIDE6IFdyYXAgZmFjZXQgbGFiZWxzIG1vcmUgdGlnaHRseQ0KbWhfaW5kaWNhdG9ycyA8LSBtaF9pbmRpY2F0b3JzICU+JQ0KICBtdXRhdGUob3V0Y29tZV93cmFwcGVkID0gc3RyX3dyYXAob3V0Y29tZV9vcl9pbmRpY2F0b3IsIHdpZHRoID0gMjApKSAgIyBuYXJyb3dlciB3cmFwDQoNCiMgU3RlcCAyOiBQbG90IHdpdGggc21hbGxlciBmYWNldCBsYWJlbCBzaXplDQptaF9pbmRpY2F0b3JzICU+JQ0KICBmaWx0ZXIoZ3JvdXBpbmdfY2F0ZWdvcnkgPT0gIlNleCIpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBZZWFyLCB5ID0gUGVyY2VudGFnZSwgY29sb3IgPSBHcm91cCkpICsNCiAgZ2VvbV9saW5lKGxpbmV3aWR0aCA9IDEuMikgKw0KICBmYWNldF93cmFwKH4gb3V0Y29tZV93cmFwcGVkLCBzY2FsZXMgPSAiZnJlZV95IikgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIlRyZW5kcyBpbiBNZW50YWwgSGVhbHRoIEluZGljYXRvcnMgYnkgU2V4IChOSElTIEFkdWx0cykiLA0KICAgIHggPSAiWWVhciIsDQogICAgeSA9ICJQZXJjZW50YWdlIg0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoDQogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwNCiAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA5KSwgICAgICAgICAgICMgc21hbGxlciBmYWNldCB0aXRsZXMNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMywgZmFjZSA9ICJib2xkIikNCiAgKQ0KDQoNCmBgYA0KDQpXb21lbiByZXBvcnQgaGlnaGVyIHJhdGVzIG9mIGRlcHJlc3Npb24sIGFueGlldHksIGFuZCB1bm1ldCBtZW50YWwgaGVhbHRoIG5lZWRzLg0KDQpDb21wYXJpbmcgTWVudGFsIEhlYWx0aCBJbmRpY2F0b3JzIGJ5IFNleCBhbmQgSW5jb21lIExldmVsOg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHN0cmluZ3IpDQpsaWJyYXJ5KGRwbHlyKQ0KDQojIFN0ZXAgMTogRmlsdGVyIG9ubHkgdGhlIDUgbWVudGFsIGhlYWx0aCBpbmRpY2F0b3JzDQppbmRpY2F0b3JzX29mX2ludGVyZXN0IDwtIGMoDQogICJTeW1wdG9tcyBvZiBhbnhpZXR5IiwNCiAgIlN5bXB0b21zIG9mIGRlcHJlc3Npb24iLA0KICAiUmVndWxhcmx5IGhhZCBmZWVsaW5ncyBvZiB3b3JyeSwgbmVydm91c25lc3MsIG9yIGFueGlldHkiLA0KICAiVGFraW5nIHByZXNjcmlwdGlvbiBtZWRpY2F0aW9uIGZvciBmZWVsaW5ncyBvZiB3b3JyeSwgbmVydm91c25lc3MsIG9yIGFueGlldHkiLA0KICAiRGlkIG5vdCBnZXQgbmVlZGVkIG1lbnRhbCBoZWFsdGggY2FyZSBkdWUgdG8gY29zdCINCikNCg0KIyBTdGVwIDI6IEZpbHRlciBhbmQgd3JhcCBsYWJlbHMNCmluY29tZV9kYXRhIDwtIG1oX2luZGljYXRvcnMgJT4lDQogIGZpbHRlcihncm91cGluZ19jYXRlZ29yeSA9PSAiRmFtaWx5IGluY29tZSIsDQogICAgICAgICBvdXRjb21lX29yX2luZGljYXRvciAlaW4lIGluZGljYXRvcnNfb2ZfaW50ZXJlc3QpICU+JQ0KICBtdXRhdGUob3V0Y29tZV93cmFwcGVkID0gc3RyX3dyYXAob3V0Y29tZV9vcl9pbmRpY2F0b3IsIHdpZHRoID0gMjApKQ0KDQojIFN0ZXAgMzogUGxvdA0KZ2dwbG90KGluY29tZV9kYXRhLCBhZXMoeCA9IFllYXIsIHkgPSBQZXJjZW50YWdlLCBjb2xvciA9IEdyb3VwKSkgKw0KICBnZW9tX2xpbmUobGluZXdpZHRoID0gMS4yKSArDQogIGZhY2V0X3dyYXAofiBvdXRjb21lX3dyYXBwZWQsIHNjYWxlcyA9ICJmcmVlX3kiKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiTWVudGFsIEhlYWx0aCBJbmRpY2F0b3JzIGJ5IEZhbWlseSBJbmNvbWUgKE5ISVMgQWR1bHRzKSIsDQogICAgeCA9ICJZZWFyIiwNCiAgICB5ID0gIlBlcmNlbnRhZ2UiLA0KICAgIGNvbG9yID0gIkluY29tZSBHcm91cCINCiAgKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKA0KICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksDQogICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gOSksDQogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTMsIGZhY2UgPSAiYm9sZCIpDQogICkNCg0KYGBgDQoNCg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHN0cmluZ3IpDQpsaWJyYXJ5KGRwbHlyKQ0KDQojIFN0ZXAgMTogRmlsdGVyaW5nIG9ubHkgdGhlIDUgbWVudGFsIGhlYWx0aCBpbmRpY2F0b3JzDQppbmRpY2F0b3JzX29mX2ludGVyZXN0IDwtIGMoDQogICJTeW1wdG9tcyBvZiBhbnhpZXR5IiwNCiAgIlN5bXB0b21zIG9mIGRlcHJlc3Npb24iLA0KICAiUmVndWxhcmx5IGhhZCBmZWVsaW5ncyBvZiB3b3JyeSwgbmVydm91c25lc3MsIG9yIGFueGlldHkiLA0KICAiVGFraW5nIHByZXNjcmlwdGlvbiBtZWRpY2F0aW9uIGZvciBmZWVsaW5ncyBvZiB3b3JyeSwgbmVydm91c25lc3MsIG9yIGFueGlldHkiLA0KICAiRGlkIG5vdCBnZXQgbmVlZGVkIG1lbnRhbCBoZWFsdGggY2FyZSBkdWUgdG8gY29zdCINCikNCg0KIyBTdGVwIDI6IEZpbHRlcmluZyBhbmQgYXNzaWduIHNob3J0IGxhYmVscw0KaW5jb21lX2RhdGEgPC0gbWhfaW5kaWNhdG9ycyAlPiUNCiAgZmlsdGVyKGdyb3VwaW5nX2NhdGVnb3J5ID09ICJGYW1pbHkgaW5jb21lIiwNCiAgICAgICAgIG91dGNvbWVfb3JfaW5kaWNhdG9yICVpbiUgaW5kaWNhdG9yc19vZl9pbnRlcmVzdCkgJT4lDQogIG11dGF0ZShvdXRjb21lX3dyYXBwZWQgPSBjYXNlX3doZW4oDQogICAgb3V0Y29tZV9vcl9pbmRpY2F0b3IgPT0gIlN5bXB0b21zIG9mIGFueGlldHkiIH4gIkZyZXF1ZW50IEFueGlldHkiLA0KICAgIG91dGNvbWVfb3JfaW5kaWNhdG9yID09ICJTeW1wdG9tcyBvZiBkZXByZXNzaW9uIiB+ICJGcmVxdWVudCBEZXByZXNzaW9uIiwNCiAgICBvdXRjb21lX29yX2luZGljYXRvciA9PSAiUmVndWxhcmx5IGhhZCBmZWVsaW5ncyBvZiB3b3JyeSwgbmVydm91c25lc3MsIG9yIGFueGlldHkiIH4gIldvcnJ5L05lcnZvdXNuZXNzIiwNCiAgICBvdXRjb21lX29yX2luZGljYXRvciA9PSAiVGFraW5nIHByZXNjcmlwdGlvbiBtZWRpY2F0aW9uIGZvciBmZWVsaW5ncyBvZiB3b3JyeSwgbmVydm91c25lc3MsIG9yIGFueGlldHkiIH4gIkFueGlldHkgTWVkcyIsDQogICAgb3V0Y29tZV9vcl9pbmRpY2F0b3IgPT0gIkRpZCBub3QgZ2V0IG5lZWRlZCBtZW50YWwgaGVhbHRoIGNhcmUgZHVlIHRvIGNvc3QiIH4gIlVubWV0IE1IIENhcmUgKENvc3QpIg0KICApKQ0KDQojIFN0ZXAgMzogUGxvdHRpbmcNCmdncGxvdChpbmNvbWVfZGF0YSwgYWVzKHggPSBZZWFyLCB5ID0gUGVyY2VudGFnZSwgY29sb3IgPSBHcm91cCkpICsNCiAgZ2VvbV9saW5lKGxpbmV3aWR0aCA9IDEuMikgKw0KICBmYWNldF93cmFwKH4gb3V0Y29tZV93cmFwcGVkLCBzY2FsZXMgPSAiZnJlZV95IikgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIk1lbnRhbCBIZWFsdGggSW5kaWNhdG9ycyBieSBGYW1pbHkgSW5jb21lIChOSElTIEFkdWx0cykiLA0KICAgIHggPSAiWWVhciIsDQogICAgeSA9ICJQZXJjZW50YWdlIiwNCiAgICBjb2xvciA9ICJJbmNvbWUgR3JvdXAiDQogICkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZSgNCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpLA0KICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYsIGZhY2UgPSAiYm9sZCIpLA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEzLCBmYWNlID0gImJvbGQiKQ0KICApDQoNCmBgYA0KDQpUaGUgYW5hbHlzaXMgb2YgdGhlc2Uga2V5IG1lbnRhbCBoZWFsdGggaW5kaWNhdG9ycyBzdHJhdGlmaWVkIGJ5IGZhbWlseSBpbmNvbWUgbGV2ZWwgcmV2ZWFscyBhIGNvbnNpc3RlbnQgYW5kIGNvbmNlcm5pbmcgcGF0dGVybjogbG93ZXItaW5jb21lIGFkdWx0cyBleHBlcmllbmNlIHNpZ25pZmljYW50bHkgaGlnaGVyIHJhdGVzIG9mIG1lbnRhbCBoZWFsdGggZGlzdHJlc3MgYW5kIGJhcnJpZXJzIHRvIGNhcmUuIEFkdWx0cyBsaXZpbmcgYmVsb3cgdGhlIEZlZGVyYWwgUG92ZXJ0eSBMZXZlbCAoRlBMKSBleGhpYml0IHRoZSBoaWdoZXN0IHBlcmNlbnRhZ2VzIGFjcm9zcyBhbGwgbWVhc3VyZXMsIGluY2x1ZGluZyBmcmVxdWVudCBhbnhpZXR5LCBwcmVzY3JpcHRpb24gbWVkaWNhdGlvbiB1c2UgZm9yIGFueGlldHksIGFuZCB1bm1ldCBtZW50YWwgaGVhbHRoIGNhcmUgbmVlZHMgZHVlIHRvIGNvc3QuIFRoaXMgZ3JvdXAgY29uc2lzdGVudGx5IHN1cnBhc3NlcyB0aG9zZSB3aXRoIG1vZGVyYXRlICgxMDAlIHRvIGxlc3MgdGhhbiAyMDAlIEZQTCkgYW5kIGhpZ2hlciAoMjAwJSBhbmQgZ3JlYXRlciBGUEwpIGluY29tZSBsZXZlbHMuDQoNCk1vcmVvdmVyLCB3aGlsZSBhbGwgaW5jb21lIGdyb3VwcyBzaG93IHNsaWdodCBpbmNyZWFzZXMgaW4gbWVudGFsIGhlYWx0aCBzZXJ2aWNlIHVzZSBhbmQgc3ltcHRvbSBwcmV2YWxlbmNlIG92ZXIgdGhlIGZvdXIteWVhciBwZXJpb2QsIHRoZSBzaGFycGVzdCBpbmNyZWFzZXMgYXJlIG9ic2VydmVkIGFtb25nIHRob3NlIGluIHBvdmVydHksIHBhcnRpY3VsYXJseSBpbiB0aGUgcG9zdC0yMDIwIHRpbWVmcmFtZS4gVGhpcyBtYXkgcmVmbGVjdCB0aGUgY29tcG91bmRlZCBtZW50YWwgaGVhbHRoIGltcGFjdCBvZiB0aGUgQ09WSUQtMTkgcGFuZGVtaWMsIGVjb25vbWljIGluc3RhYmlsaXR5LCBhbmQgd2lkZW5pbmcgaGVhbHRoIGRpc3Bhcml0aWVzLg0KDQpUaGVzZSBmaW5kaW5ncyBzdXBwb3J0IHRoZSBoeXBvdGhlc2lzIHRoYXQgZWNvbm9taWMgc3RyZXNzb3JzIGFyZSBzdHJvbmcgcHJlZGljdG9ycyBvZiBtZW50YWwgaGVhbHRoIGRpc3RyZXNzIChIMSkuIFRoZXkgYWxzbyB1bmRlcnNjb3JlIHRoZSB1cmdlbnQgbmVlZCBmb3IgdGFyZ2V0ZWQgcG9saWN5IGludGVydmVudGlvbnMgYW5kIHJlc291cmNlIGFsbG9jYXRpb24gdG8gbWl0aWdhdGUgc3RydWN0dXJhbCBiYXJyaWVycyBpbiBsb3ctaW5jb21lIHBvcHVsYXRpb25zLCBlc3BlY2lhbGx5IGFzIGRlbWFuZCBmb3IgbWVudGFsIGhlYWx0aCBzZXJ2aWNlcyBjb250aW51ZXMgdG8gZ3Jvdy4NCg0KDQpFZHVjYXRpb24gYW5kIEVtcGxveW1lbnQgU3RhdHVzDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGdncGxvdDIpDQoNCiMgU3RlcCAxOiBEZWZpbmluZyB0aGUgNSBtZW50YWwgaGVhbHRoLXJlbGF0ZWQgaW5kaWNhdG9ycw0KaW5kaWNhdG9yc19vZl9pbnRlcmVzdCA8LSBjKA0KICAiU3ltcHRvbXMgb2YgYW54aWV0eSIsDQogICJTeW1wdG9tcyBvZiBkZXByZXNzaW9uIiwNCiAgIlJlZ3VsYXJseSBoYWQgZmVlbGluZ3Mgb2Ygd29ycnksIG5lcnZvdXNuZXNzLCBvciBhbnhpZXR5IiwNCiAgIlRha2luZyBwcmVzY3JpcHRpb24gbWVkaWNhdGlvbiBmb3IgZmVlbGluZ3Mgb2Ygd29ycnksIG5lcnZvdXNuZXNzLCBvciBhbnhpZXR5IiwNCiAgIkRpZCBub3QgZ2V0IG5lZWRlZCBtZW50YWwgaGVhbHRoIGNhcmUgZHVlIHRvIGNvc3QiDQopDQoNCiMgU3RlcCAyOiBGaWx0ZXJpbmcgZGF0YSBmb3IgRWR1Y2F0aW9uIGFuZCBFbXBsb3ltZW50IHN0YXR1cyBncm91cHMgb25seQ0KY29tcG9zaXRlX3Njb3JlIDwtIG1oX2luZGljYXRvcnMgJT4lDQogIGZpbHRlcihvdXRjb21lX29yX2luZGljYXRvciAlaW4lIGluZGljYXRvcnNfb2ZfaW50ZXJlc3QsDQogICAgICAgICBncm91cGluZ19jYXRlZ29yeSAlaW4lIGMoIkVkdWNhdGlvbiIsICJFbXBsb3ltZW50IHN0YXR1cyIpKSAlPiUNCiAgZ3JvdXBfYnkoWWVhciwgZ3JvdXBpbmdfY2F0ZWdvcnksIEdyb3VwKSAlPiUNCiAgc3VtbWFyaXNlKA0KICAgIGRlcHJlc3Npb25fc3ltcHRvbV9zY29yZSA9IHN1bShQZXJjZW50YWdlLCBuYS5ybSA9IFRSVUUpLA0KICAgIC5ncm91cHMgPSAiZHJvcCINCiAgKQ0KDQojIFN0ZXAgMzogUGxvdHRpbmcgcmVzdWx0cw0KZ2dwbG90KGNvbXBvc2l0ZV9zY29yZSwgYWVzKHggPSBHcm91cCwgeSA9IGRlcHJlc3Npb25fc3ltcHRvbV9zY29yZSwgZmlsbCA9IGdyb3VwaW5nX2NhdGVnb3J5KSkgKw0KICBnZW9tX2NvbChwb3NpdGlvbiA9ICJkb2RnZSIpICsNCiAgZmFjZXRfd3JhcCh+IGdyb3VwaW5nX2NhdGVnb3J5LCBzY2FsZXMgPSAiZnJlZV94IikgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIkNvbWJpbmVkIE1lbnRhbCBIZWFsdGggU3ltcHRvbSBTY29yZSBieSBFZHVjYXRpb24gYW5kIEVtcGxveW1lbnQgU3RhdHVzIiwNCiAgICB4ID0gTlVMTCwNCiAgICB5ID0gIlN1bW1lZCBQZXJjZW50YWdlIG9mIFN5bXB0b21zIiwNCiAgICBmaWxsID0gIkdyb3VwaW5nIg0KICApICsNCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxMSkgKw0KICB0aGVtZSgNCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIHNpemUgPSA4KSwgICMgc21hbGxlciBsYWJlbHMNCiAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMSksDQogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gMTQpDQogICkNCg0KDQoNCmBgYA0KDQpLZXkgRmluZGluZ3M6DQpFbXBsb3ltZW50IFN0YXR1czoNClRoZSBjbGVhcmVzdCBkaXNwYXJpdGllcyB3ZXJlIGZvdW5kIGluIGVtcGxveW1lbnQgc3RhdHVzLiBBZHVsdHMgd2hvIHdlcmUgbm90IGN1cnJlbnRseSBlbXBsb3llZCBidXQgaGFkIHdvcmtlZCBwcmV2aW91c2x5IHJlcG9ydGVkIHNpZ25pZmljYW50bHkgaGlnaGVyIGNvbWJpbmVkIHN5bXB0b20gc2NvcmVzIGNvbXBhcmVkIHRvIG90aGVyIGdyb3Vwcy4gVGhpcyBzdXBwb3J0cyBleGlzdGluZyBldmlkZW5jZSBsaW5raW5nIGpvYiBpbnNlY3VyaXR5IG9yIHVuZW1wbG95bWVudCB0byBlbGV2YXRlZCBtZW50YWwgZGlzdHJlc3MuDQoNCkVkdWNhdGlvbiBMZXZlbDoNClRoZSB2YXJpYXRpb24gaW4gbWVudGFsIGhlYWx0aCBzeW1wdG9tIGJ1cmRlbiBhY3Jvc3MgZWR1Y2F0aW9uIGxldmVscyB3YXMgbWluaW1hbC4gV2hpbGUgaW5kaXZpZHVhbHMgd2l0aCBsZXNzIHRoYW4gYSBoaWdoIHNjaG9vbCBkaXBsb21hIGhhZCBzbGlnaHRseSBoaWdoZXIgc2NvcmVzIHRoYW4gdGhvc2Ugd2l0aCBjb2xsZWdlIGRlZ3JlZXMsIHRoZSBkaWZmZXJlbmNlcyB3ZXJlIGxlc3MgcHJvbm91bmNlZCBjb21wYXJlZCB0byB0aG9zZSBzZWVuIGluIGVtcGxveW1lbnQgc3RhdHVzLiBUaGlzIHN1Z2dlc3RzIHRoYXQgZWR1Y2F0aW9uIGFsb25lIG1heSBub3QgYmUgYSBzdWZmaWNpZW50IHByZWRpY3RvciBvZiBtZW50YWwgaGVhbHRoIHN5bXB0b21zIHdpdGhvdXQgY29uc2lkZXJpbmcgZmFjdG9ycyBzdWNoIGFzIGVtcGxveW1lbnQgYW5kIGluY29tZS4NCg0KVGhlc2UgZmluZGluZ3MgcmVpbmZvcmNlIHRoYXQgZWNvbm9taWMgc3RyZXNzIGFuZCBlbXBsb3ltZW50IHN0YWJpbGl0eSBhcmUgc3Ryb25nZXIgY29ycmVsYXRlcyBvZiBtZW50YWwgaGVhbHRoIG91dGNvbWVzIHRoYW4gZWR1Y2F0aW9uIGxldmVsIGluIHRoaXMgcG9wdWxhdGlvbi4NCg0KDQpBZ2U6DQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHN0cmluZ3IpDQoNCiMgRGVmaW5pbmcgdGhlIDUgZGVwcmVzc2lvbi1yZWxhdGVkIGluZGljYXRvcnMNCmRlcHJlc3Npb25faW5kaWNhdG9ycyA8LSBjKA0KICAiU3ltcHRvbXMgb2YgYW54aWV0eSIsDQogICJTeW1wdG9tcyBvZiBkZXByZXNzaW9uIiwNCiAgIlJlZ3VsYXJseSBoYWQgZmVlbGluZ3Mgb2Ygd29ycnksIG5lcnZvdXNuZXNzLCBvciBhbnhpZXR5IiwNCiAgIlRha2luZyBwcmVzY3JpcHRpb24gbWVkaWNhdGlvbiBmb3IgZmVlbGluZ3Mgb2Ygd29ycnksIG5lcnZvdXNuZXNzLCBvciBhbnhpZXR5IiwNCiAgIkRpZCBub3QgZ2V0IG5lZWRlZCBtZW50YWwgaGVhbHRoIGNhcmUgZHVlIHRvIGNvc3QiDQopDQoNCiMgRmlsdGVyaW5nIGRhdGFzZXQ6IGluZGljYXRvcnMgKyBvbmx5IGFnZSBncm91cHMgKGNvbnRhaW5pbmcgInllYXJzIikNCmFnZV9kYXRhIDwtIG5oaXNfYWR1bHQgJT4lDQogIGZpbHRlcihvdXRjb21lX29yX2luZGljYXRvciAlaW4lIGRlcHJlc3Npb25faW5kaWNhdG9ycywNCiAgICAgICAgIHN0cl9kZXRlY3QoR3JvdXAsICJ5ZWFycyIpKQ0KDQojIEdyb3VwaW5nIGFuZCBzdW1tYXJpemluZyB0byBnZXQgYXZlcmFnZSBwZXJjZW50YWdlIHBlciB5ZWFyIGFuZCBhZ2UgZ3JvdXANCmF2Z19hZ2VfdHJlbmRzIDwtIGFnZV9kYXRhICU+JQ0KICBncm91cF9ieShZZWFyLCBHcm91cCkgJT4lDQogIHN1bW1hcmlzZShhdmdfcGVyY2VudGFnZSA9IG1lYW4oUGVyY2VudGFnZSwgbmEucm0gPSBUUlVFKSwgLmdyb3VwcyA9ICJkcm9wIikNCg0KIyBQbG90dGluZw0KZ2dwbG90KGF2Z19hZ2VfdHJlbmRzLCBhZXMoeCA9IFllYXIsIHkgPSBhdmdfcGVyY2VudGFnZSwgY29sb3IgPSBHcm91cCkpICsNCiAgZ2VvbV9saW5lKGxpbmV3aWR0aCA9IDEuMikgKw0KICBnZW9tX3BvaW50KHNpemUgPSAyKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiQXZlcmFnZSBEZXByZXNzaW9uIFN5bXB0b21zIGJ5IEFnZSBHcm91cCAoTkhJUyBBZHVsdHMpIiwNCiAgICB4ID0gIlllYXIiLA0KICAgIHkgPSAiQXZlcmFnZSBQZXJjZW50YWdlIiwNCiAgICBjb2xvciA9ICJBZ2UgR3JvdXAiDQogICkgKw0KICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDEzKQ0KDQoNCmBgYA0KDQpZb3VuZyBhZHVsdHMgKDE44oCTMzQgeWVhcnMpIGNvbnNpc3RlbnRseSByZXBvcnQgdGhlIGhpZ2hlc3QgYXZlcmFnZSBsZXZlbHMgb2YgZGVwcmVzc2lvbiBzeW1wdG9tcy4NCg0KT2xkZXIgYWR1bHRzICg2NSsgeWVhcnMpIHJlcG9ydCB0aGUgbG93ZXN0LCB3aXRoIHJlbGF0aXZlbHkgc3RhYmxlIHRyZW5kcy4NCg0KVGhlcmUncyBhIG5vdGljZWFibGUgdXB3YXJkIHRyZW5kIGZyb20gMjAxOSB0byAyMDIzIGluIGFsbCBhZ2UgZ3JvdXBzLCBidXQgaXQncyBzdGVlcGVzdCBhbW9uZyB5b3VuZ2VyIGNvaG9ydHMuDQoNClRoaXMgc3Ryb25nbHkgc3VwcG9ydHMgdGhlIGlkZWEgdGhhdCBhZ2UgaXMgYSBtYWpvciBmYWN0b3IgaW4gbWVudGFsIGhlYWx0aCBzeW1wdG9tIGJ1cmRlbiwgZXNwZWNpYWxseSBwb3N0LTIwMjAuDQoNCg0KVGhlIHByZXZpb3VzIGFuYWx5c2lzIG9mIE5ISVMgQWR1bHQgU3VtbWFyeSBIZWFsdGggU3RhdGlzdGljcyByZXZlYWxlZCBhIGRlZXBseSBjb25jZXJuaW5nIHRyZW5kOiB5b3VuZ2VyIGFkdWx0cyBhZ2VkIDE44oCTMzQgY29uc2lzdGVudGx5IHJlcG9ydCB0aGUgaGlnaGVzdCBsZXZlbHMgb2YgZGVwcmVzc2lvbiBzeW1wdG9tcywgd2l0aCBzdGVhZHkgaW5jcmVhc2VzIG9ic2VydmVkIGZyb20gMjAxOSB0aHJvdWdoIDIwMjMuIFRoaXMgYWdlIGdyb3VwIG5vdCBvbmx5IGxlYWRzIGFsbCBvdGhlcnMgaW4gcmVwb3J0ZWQgbWVudGFsIGhlYWx0aCBkaXN0cmVzcywgYnV0IHRoZSB1cHdhcmQgdHJhamVjdG9yeSBzdWdnZXN0cyB0aGF0IG1lbnRhbCBoZWFsdGggY2hhbGxlbmdlcyBhcmUgbm90IGlzb2xhdGVkIHRvIGFkdWx0aG9vZOKAlHRoZXkgbGlrZWx5IGJlZ2luIG11Y2ggZWFybGllciBpbiBsaWZlLg0KDQpUaGVzZSBmaW5kaW5ncyB1bmRlcnNjb3JlIHRoZSB1cmdlbnQgbmVlZCB0byBpbnZlc3RpZ2F0ZSB0aGUgZWFybHkgZGV2ZWxvcG1lbnQgb2YgbWVudGFsIGhlYWx0aCBzeW1wdG9tcywgcGFydGljdWxhcmx5IGluIGFkb2xlc2NlbnRzLiBNZW50YWwgaGVhbHRoIGRpc29yZGVycyBzdWNoIGFzIGRlcHJlc3Npb24gYW5kIGFueGlldHkgb2Z0ZW4gZW1lcmdlIGR1cmluZyB0aGUgdGVlbmFnZSB5ZWFycywgYSBjcml0aWNhbCBkZXZlbG9wbWVudGFsIHBlcmlvZCBjaGFyYWN0ZXJpemVkIGJ5IGVtb3Rpb25hbCwgaG9ybW9uYWwsIGFjYWRlbWljLCBhbmQgc29jaWFsIHRyYW5zaXRpb25zLiBVbmRlcnN0YW5kaW5nIHRoZSBidXJkZW4gb2YgZGVwcmVzc2lvbiBzeW1wdG9tcyBpbiB0ZWVucyBpcyBub3Qgb25seSBpbXBvcnRhbnQgZm9yIGVhcmx5IGRldGVjdGlvbiwgYnV0IGVzc2VudGlhbCBmb3IgZGVzaWduaW5nIGludGVydmVudGlvbnMgdGhhdCBjYW4gaW50ZXJydXB0IHRoZSB0cmFqZWN0b3J5IG9mIHdvcnNlbmluZyBtZW50YWwgaGVhbHRoIGludG8gYWR1bHRob29kLg0KDQpBcyB3ZSBzaGlmdCB0byBhbmFseXppbmcgZGF0YSBmcm9tIHRoZSBOSElTIFRlZW4gU3VtbWFyeSBIZWFsdGggU3RhdGlzdGljcywgd2UgYWltIHRvOg0KDQpRdWFudGlmeSB0aGUgcHJldmFsZW5jZSBvZiBkZXByZXNzaW9uIHN5bXB0b21zIGluIGFkb2xlc2NlbnRzIGFnZWQgMTLigJMxNy4NCg0KSWRlbnRpZnkgZGVtb2dyYXBoaWMgYW5kIHNvY2lvZWNvbm9taWMgZGlzcGFyaXRpZXMgaW4gbWVudGFsIGhlYWx0aCBidXJkZW4uDQoNCkV4cGxvcmUgcGF0dGVybnMgaW4gdW5tZXQgbWVudGFsIGhlYWx0aCBjYXJlIG5lZWRzIGFuZCB0aGUgcm9sZSBvZiBzb2NpYWwgb3IgZW1vdGlvbmFsIHN1cHBvcnQuDQoNClRoaXMgbmV4dCBwaGFzZSBvZiB0aGUgYW5hbHlzaXMgd2lsbCBidWlsZCB1cG9uIHRoZSBhZHVsdCBmaW5kaW5ncyB0byBoZWxwIGNvbm5lY3QgZWFybHkgaW5kaWNhdG9ycyB0byBsb25nLXRlcm0gb3V0Y29tZXMsIG9mZmVyaW5nIGEgbW9yZSBjb21wbGV0ZSBwaWN0dXJlIG9mIG1lbnRhbCBoZWFsdGggY2hhbGxlbmdlcyBhY3Jvc3MgdGhlIGxpZmVzcGFuLg0KDQoNCiMjIExvYWRpbmcgZGF0YXNldCAyDQoNCkxvYWRpbmcgZGF0YXNldCBmb3IgdGVlbnMNCg0KYGBge3J9DQojIExvYWRpbmcgcmVxdWlyZWQgbGlicmFyaWVzDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCg0KIyBSZWFkaW5nIHRoZSBOSElTIFRlZW4gQ1NWIGZpbGUNCm5oaXNfdGVlbiA8LSByZWFkX2NzdigiQzovVXNlcnMvYWxlamEvRG93bmxvYWRzL05ISVNfVGVlbl8yMDI1MDUxMC5jc3YiKQ0KDQojIFZpZXcgdGhlIGNvbHVtbiBuYW1lcw0KY29sbmFtZXMobmhpc190ZWVuKQ0KDQojIEEgcXVpY2sgcGVlayBhdCB0aGUgc3RydWN0dXJlIG9mIHRoZSBkYXRhc2V0DQpnbGltcHNlKG5oaXNfdGVlbikNCg0KIyBWaWV3IHVuaXF1ZSB2YWx1ZXMgaW4gaW1wb3J0YW50IGZpZWxkcw0KdW5pcXVlKG5oaXNfdGVlbiRgT3V0Y29tZSAob3IgSW5kaWNhdG9yKWApDQp1bmlxdWUobmhpc190ZWVuJEdyb3VwKQ0KdW5pcXVlKG5oaXNfdGVlbiRgR3JvdXBpbmcgY2F0ZWdvcnlgKQ0KDQpgYGANCg0KIyMjIERhdGEgY2xlYW5pbmcNCg0KYGBge3J9DQojIENvdW50IHRvdGFsIG1pc3NpbmcgdmFsdWVzIGluIHRoZSBkYXRhc2V0DQpzdW0oaXMubmEobmhpc190ZWVuKSkNCg0KIyBDb3VudCBtaXNzaW5nIHZhbHVlcyBwZXIgY29sdW1uDQpjb2xTdW1zKGlzLm5hKG5oaXNfdGVlbikpDQoNCg0KDQpgYGANCg0KRGF0YXNldCBoYXMgMCBtaXNzaW5nIHZhbHVlcw0KDQpgYGB7cn0NCg0KIyBGaWx0ZXJpbmcgZm9yICJTeW1wdG9tcyBvZiBkZXByZXNzaW9uIg0KZGVwcmVzc2lvbl90ZWVuIDwtIG5oaXNfdGVlbiAlPiUNCiAgZmlsdGVyKGBPdXRjb21lIChvciBJbmRpY2F0b3IpYCA9PSAiU3ltcHRvbXMgb2YgZGVwcmVzc2lvbiIpICU+JQ0KICBtdXRhdGUoR3JvdXAgPSBzdHJfdHJpbShHcm91cCkpDQoNCiMgUGxvdCAxOiBTeW1wdG9tcyBvZiBkZXByZXNzaW9uIGJ5IFNleA0KZ2dwbG90KA0KICBkZXByZXNzaW9uX3RlZW4gJT4lIGZpbHRlcihHcm91cCAlaW4lIGMoIk1hbGUiLCAiRmVtYWxlIikpLA0KICBhZXMoeCA9IEdyb3VwLCB5ID0gUGVyY2VudGFnZSwgZmlsbCA9IEdyb3VwKQ0KKSArDQogIGdlb21fY29sKHdpZHRoID0gMC42KSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIk1hbGUiID0gIiMxZjc4YjQiLCAiRmVtYWxlIiA9ICIjZTMxYTFjIikpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJTeW1wdG9tcyBvZiBEZXByZXNzaW9uIEFtb25nIFRlZW5zIGJ5IFNleCIsDQogICAgeCA9IE5VTEwsDQogICAgeSA9ICJQZXJjZW50YWdlIg0KICApICsNCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxMykgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpDQoNCiMgUGxvdCAyOiBTeW1wdG9tcyBvZiBkZXByZXNzaW9uIGJ5IEFnZSBHcm91cA0KZ2dwbG90KA0KICBkZXByZXNzaW9uX3RlZW4gJT4lIGZpbHRlcihzdHJfZGV0ZWN0KEdyb3VwLCAieWVhcnMiKSksDQogIGFlcyh4ID0gR3JvdXAsIHkgPSBQZXJjZW50YWdlLCBmaWxsID0gR3JvdXApDQopICsNCiAgZ2VvbV9jb2wod2lkdGggPSAwLjYpICsNCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQyIikgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIlN5bXB0b21zIG9mIERlcHJlc3Npb24gQW1vbmcgVGVlbnMgYnkgQWdlIEdyb3VwIiwNCiAgICB4ID0gTlVMTCwNCiAgICB5ID0gIlBlcmNlbnRhZ2UiDQogICkgKw0KICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDEzKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCg0KYGBgDQoNCkJhc2VkIG9uIHRoZSBkYXRhc2V0LCBmZW1hbGUgdGVlbnMgYW5kIHRob3NlIGFnZWQgMTXigJMxNyByZXBvcnQgaGlnaGVyIHBlcmNlbnRhZ2VzIG9mIGRlcHJlc3Npb24gc3ltcHRvbXMgY29tcGFyZWQgdG8gdGhlaXIgbWFsZSBhbmQgeW91bmdlciBjb3VudGVycGFydHMuIFRoaXMgYWxpZ25zIHdpdGggYnJvYWRlciB0cmVuZHMgb2JzZXJ2ZWQgaW4gcHVibGljIGhlYWx0aCByZXNlYXJjaCwgd2hlcmUgYWRvbGVzY2VudCBnaXJscyB0ZW5kIHRvIHJlcG9ydCBoaWdoZXIgcmF0ZXMgb2YgYW54aWV0eSBhbmQgZGVwcmVzc2lvbiwgcGFydGljdWxhcmx5IGluIG1pZCB0byBsYXRlIGFkb2xlc2NlbmNlLg0KDQpUaGlzIGluc2lnaHQgaGVscHMgc2V0IHRoZSBzdGFnZSBmb3IgZGVlcGVyIGFuYWx5c2lzIGludG8gcG90ZW50aWFsIGNvbnRyaWJ1dGluZyBmYWN0b3JzLCBzdWNoIGFzOg0KDQpTb2NpYWwgbWVkaWEgZXhwb3N1cmUNCg0KQWNhZGVtaWMgcHJlc3N1cmVzDQoNClBlZXIgZHluYW1pY3MgYW5kIGJ1bGx5aW5nDQoNCkFjY2VzcyB0byBtZW50YWwgaGVhbHRoIHN1cHBvcnQNCg0KYGBge3J9DQojIExvYWQgbmVjZXNzYXJ5IGxpYnJhcmllcw0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KHN0cmluZ3IpDQoNCiMgU3RlcCAxOiBSZWFkIHRoZSBkYXRhc2V0DQpuaGlzX3RlZW4gPC0gcmVhZF9jc3YoIkM6L1VzZXJzL2FsZWphL0Rvd25sb2Fkcy9OSElTX1RlZW5fMjAyNTA1MTAuY3N2IikNCg0KIyBTdGVwIDI6IEZpbHRlciBmb3IgJ1N5bXB0b21zIG9mIGRlcHJlc3Npb24nIGFuZCBncm91cCBieSBmYW1pbHkgc3RydWN0dXJlDQpkZXByZXNzaW9uX2ZhbWlseSA8LSBuaGlzX3RlZW4gJT4lDQogIGZpbHRlcihgT3V0Y29tZSAob3IgSW5kaWNhdG9yKWAgPT0gIlN5bXB0b21zIG9mIGRlcHJlc3Npb24iLA0KICAgICAgICAgc3RyX2RldGVjdChHcm91cCwgInBhcmVudCIpKSAlPiUgICMgRmlsdGVycyAnU2luZ2xlIHBhcmVudCcgb3IgJ1R3byBwYXJlbnRzJw0KICBtdXRhdGUoZ3JvdXBfY2xlYW4gPSBzdHJfdG9fdGl0bGUoR3JvdXApKQ0KDQojIFN0ZXAgMzogQ3JlYXRlIGJhciBwbG90DQpnZ3Bsb3QoZGVwcmVzc2lvbl9mYW1pbHksIGFlcyh4ID0gZ3JvdXBfY2xlYW4sIHkgPSBQZXJjZW50YWdlLCBmaWxsID0gZ3JvdXBfY2xlYW4pKSArDQogIGdlb21fY29sKHdpZHRoID0gMC42KSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiU3ltcHRvbXMgb2YgRGVwcmVzc2lvbiBBbW9uZyBUZWVucyBieSBGYW1pbHkgU3RydWN0dXJlIiwNCiAgICB4ID0gIkZhbWlseSBTdHJ1Y3R1cmUiLA0KICAgIHkgPSAiUGVyY2VudGFnZSIsDQogICAgZmlsbCA9ICJGYW1pbHkgU3RydWN0dXJlIg0KICApICsNCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxMykgKw0KICB0aGVtZSgNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxNCksDQogICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiDQogICkNCg0KDQpgYGANCg0KDQpJbmNvbWU6DQoNCmBgYHtyfQ0KDQoNCiMgU3RlcCAxOiBSZWFkIHRoZSBkYXRhc2V0DQpuaGlzX3RlZW4gPC0gcmVhZF9jc3YoIkM6L1VzZXJzL2FsZWphL0Rvd25sb2Fkcy9OSElTX1RlZW5fMjAyNTA1MTAuY3N2IikNCg0KIyBTdGVwIDI6IEZpbHRlciBmb3IgJ1N5bXB0b21zIG9mIGRlcHJlc3Npb24nIGZvciByZWxldmFudCBncm91cHMNCmRlcHJlc3Npb25fY29tYm8gPC0gbmhpc190ZWVuICU+JQ0KICBmaWx0ZXIoYE91dGNvbWUgKG9yIEluZGljYXRvcilgID09ICJTeW1wdG9tcyBvZiBkZXByZXNzaW9uIiwNCiAgICAgICAgIEdyb3VwICVpbiUgYygiU2luZ2xlIHBhcmVudCIsICJUd28gcGFyZW50cyIsDQogICAgICAgICAgICAgICAgICAgICAgIkxlc3MgdGhhbiAyMDAlIEZQTCIsICIyMDAtMzk5JSBGUEwiLCAiNDAwJSBhbmQgZ3JlYXRlciBGUEwiKSkgJT4lDQogIG11dGF0ZShncm91cF90eXBlID0gY2FzZV93aGVuKA0KICAgIEdyb3VwICVpbiUgYygiU2luZ2xlIHBhcmVudCIsICJUd28gcGFyZW50cyIpIH4gIkZhbWlseSBTdHJ1Y3R1cmUiLA0KICAgIHN0cl9kZXRlY3QoR3JvdXAsICJGUEwiKSB+ICJGYW1pbHkgSW5jb21lIg0KICApLA0KICBncm91cF9jbGVhbiA9IHN0cl90b190aXRsZShHcm91cCkpDQoNCiMgU3RlcCAzOiBCYXIgcGxvdCBmYWNldGVkIGJ5IGdyb3VwIHR5cGUNCmdncGxvdChkZXByZXNzaW9uX2NvbWJvLCBhZXMoeCA9IGdyb3VwX2NsZWFuLCB5ID0gUGVyY2VudGFnZSwgZmlsbCA9IGdyb3VwX2NsZWFuKSkgKw0KICBnZW9tX2NvbCh3aWR0aCA9IDAuNikgKw0KICBmYWNldF93cmFwKH4gZ3JvdXBfdHlwZSwgc2NhbGVzID0gImZyZWVfeCIpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJTeW1wdG9tcyBvZiBEZXByZXNzaW9uIEFtb25nIFRlZW5zIGJ5IEZhbWlseSBTdHJ1Y3R1cmUgYW5kIEluY29tZSIsDQogICAgeCA9IE5VTEwsDQogICAgeSA9ICJQZXJjZW50YWdlIiwNCiAgICBmaWxsID0gTlVMTA0KICApICsNCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxMykgKw0KICB0aGVtZSgNCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDMwLCBoanVzdCA9IDEpLA0KICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDEyKSwNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxNCksDQogICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiDQogICkNCg0KYGBgDQoNCkZpbmRpbmdzOg0KDQpEZXByZXNzaW9uIHN5bXB0b21zIGFyZSBtb3N0IHByZXZhbGVudCBhbW9uZyB0ZWVucyBpbiBmYW1pbGllcyBlYXJuaW5nIGxlc3MgdGhhbiAyMDAlIG9mIHRoZSBGZWRlcmFsIFBvdmVydHkgTGV2ZWwgKEZQTCkuDQoNClRob3NlIGluIHRoZSAyMDDigJMzOTklIEZQTCByYW5nZSBmYXJlIHNsaWdodGx5IGJldHRlciwgd2hpbGUgdGhvc2UgaW4gdGhlIDQwMCUgYW5kIGdyZWF0ZXIgRlBMIGdyb3VwIHJlcG9ydCB0aGUgbG93ZXN0IHByZXZhbGVuY2UuDQoNCkludGVycHJldGF0aW9uOg0KDQpFY29ub21pYyBoYXJkc2hpcCBpcyBhIHN0cm9uZyByaXNrIGZhY3RvciBmb3IgYWRvbGVzY2VudCBkZXByZXNzaW9uLiBQb2xpY3kgc3RyYXRlZ2llcyBhZGRyZXNzaW5nIGZpbmFuY2lhbCBpbnNlY3VyaXR5IGNvdWxkIHBsYXkgYSBwcmV2ZW50aXZlIHJvbGUgaW4gdGVlbiBtZW50YWwgaGVhbHRoLg0KDQpGaW5kaW5nczoNCg0KVGVlbnMgZnJvbSBzaW5nbGUtcGFyZW50IGhvdXNlaG9sZHMgYXJlIG1vcmUgbGlrZWx5IHRvIHJlcG9ydCBkZXByZXNzaW9uIHN5bXB0b21zIHRoYW4gdGhvc2UgZnJvbSB0d28tcGFyZW50IGhvdXNlaG9sZHMuDQoNClRoZSBhYnNlbmNlIG9mIGEgc2Vjb25kIHBhcmVudGFsIGZpZ3VyZSBtYXkgYWZmZWN0IGVtb3Rpb25hbCBzdXBwb3J0LCBzdGFiaWxpdHksIG9yIGFjY2VzcyB0byBjYXJlLg0KDQpJbnRlcnByZXRhdGlvbjoNCg0KTWVudGFsIGhlYWx0aCBzZXJ2aWNlcyBjb3VsZCBwcmlvcml0aXplIGZhbWlseS1iYXNlZCBzdXBwb3J0IHN0cmF0ZWdpZXMsIHBhcnRpY3VsYXJseSBmb3Igc2luZ2xlLXBhcmVudCBob3VzZWhvbGRzLg0KDQpSYWNlIGFuZCBFdGhuaWNpdHk6DQoNCmBgYHtyfQ0KIyBTdGVwIDI6IEZpbHRlciBmb3Igc3ltcHRvbXMgb2YgZGVwcmVzc2lvbiBieSByYWNlDQpkZXByZXNzaW9uX3JhY2UgPC0gbmhpc190ZWVuICU+JQ0KICBmaWx0ZXIoYE91dGNvbWUgKG9yIEluZGljYXRvcilgID09ICJTeW1wdG9tcyBvZiBkZXByZXNzaW9uIiwNCiAgICAgICAgIEdyb3VwICVpbiUgYygiSGlzcGFuaWMiLCAiTm9uLUhpc3BhbmljIiwgIkFzaWFuIiwgIkJsYWNrIiwgIldoaXRlIiwgIkFsbCBvdGhlciByYWNlcyIpKSAlPiUNCiAgbXV0YXRlKGdyb3VwX2NsZWFuID0gc3RyX3RvX3RpdGxlKEdyb3VwKSkNCg0KIyBTdGVwIDM6IENyZWF0ZSBiYXIgcGxvdA0KZ2dwbG90KGRlcHJlc3Npb25fcmFjZSwgYWVzKHggPSBncm91cF9jbGVhbiwgeSA9IFBlcmNlbnRhZ2UsIGZpbGwgPSBncm91cF9jbGVhbikpICsNCiAgZ2VvbV9jb2wod2lkdGggPSAwLjYpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJTeW1wdG9tcyBvZiBEZXByZXNzaW9uIEFtb25nIFRlZW5zIGJ5IFJhY2UgYW5kIEV0aG5pY2l0eSIsDQogICAgeCA9IE5VTEwsDQogICAgeSA9ICJQZXJjZW50YWdlIiwNCiAgICBmaWxsID0gTlVMTA0KICApICsNCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxMykgKw0KICB0aGVtZSgNCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDMwLCBoanVzdCA9IDEpLA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE0KSwNCiAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSINCiAgKQ0KYGBgDQoNCkZpbmRpbmdzOg0KDQpBc2lhbiB0ZWVucyByZXBvcnQgdGhlIGhpZ2hlc3QgcmF0ZSBvZiBkZXByZXNzaW9uIHN5bXB0b21zLCBmb2xsb3dlZCBieSBXaGl0ZSBhbmQgQmxhY2sgdGVlbnMuDQoNCkhpc3BhbmljIHRlZW5zIGFuZCB0aG9zZSBncm91cGVkIGFzIOKAnEFsbCBvdGhlciByYWNlc+KAnSBzaG93IHJlbGF0aXZlbHkgbG93ZXIgcHJldmFsZW5jZSwgdGhvdWdoIHRoaXMgbWF5IG1hc2sgaW50cmEtZ3JvdXAgZGl2ZXJzaXR5Lg0KDQojIyBMb2FkaW5nIGRhdGFzZXQgDQoNCkxvYWRpbmcgZGF0YXNldDogSW5kaWNhdG9ycyBvZiBBbnhpZXR5IG9yIERlcHJlc3Npb24gQmFzZWQgb24gUmVwb3J0ZWQgRnJlcXVlbmN5IG9mIFN5bXB0b21zIER1cmluZyBMYXN0IDcgRGF5cw0KDQpgYGB7cn0NCiMgTG9hZCByZXF1aXJlZCBsaWJyYXJpZXMNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShsdWJyaWRhdGUpDQoNCiMgU3RlcCAxOiBMb2FkIHRoZSBkYXRhc2V0DQpkZXByZXNzaW9uX2RhdGEgPC0gcmVhZF9jc3YoIkM6L1VzZXJzL2FsZWphL0Rvd25sb2Fkcy9JbmRpY2F0b3JzX29mX0FueGlldHlfb3JfRGVwcmVzc2lvbl9CYXNlZF9vbl9SZXBvcnRlZF9GcmVxdWVuY3lfb2ZfU3ltcHRvbXNfRHVyaW5nX0xhc3RfN19EYXlzXzIwMjUwNTExLmNzdiIpDQoNCiMgU3RlcCAyOiBGaWx0ZXIgZm9yICdTeW1wdG9tcyBvZiBEZXByZXNzaXZlIERpc29yZGVyJyBieSBBZ2UNCmRlcHJlc3Npb25fYWdlIDwtIGRlcHJlc3Npb25fZGF0YSAlPiUNCiAgZmlsdGVyKEluZGljYXRvciA9PSAiU3ltcHRvbXMgb2YgRGVwcmVzc2l2ZSBEaXNvcmRlciIsDQogICAgICAgICBHcm91cCA9PSAiQnkgQWdlIikNCg0KIyBTdGVwIDM6IENvbnZlcnQgdGltZSBwZXJpb2QgdG8gZGF0ZQ0KZGVwcmVzc2lvbl9hZ2UgPC0gZGVwcmVzc2lvbl9hZ2UgJT4lDQogIG11dGF0ZShUaW1lUGVyaW9kID0gbWR5KGBUaW1lIFBlcmlvZCBTdGFydCBEYXRlYCkpDQoNCiMgU3RlcCA0OiBQbG90IHRoZSB0cmVuZA0KZ2dwbG90KGRlcHJlc3Npb25fYWdlLCBhZXMoeCA9IFRpbWVQZXJpb2QsIHkgPSBWYWx1ZSwgY29sb3IgPSBTdWJncm91cCkpICsNCiAgZ2VvbV9saW5lKHNpemUgPSAxLjIpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJTeW1wdG9tcyBvZiBEZXByZXNzaXZlIERpc29yZGVyIGJ5IEFnZSBHcm91cCAoVVMsIDIwMjDigJMyMDIzKSIsDQogICAgeCA9ICJEYXRlIiwNCiAgICB5ID0gIlBlcmNlbnRhZ2UiLA0KICAgIGNvbG9yID0gIkFnZSBHcm91cCINCiAgKSArDQogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTMpICsNCiAgdGhlbWUoDQogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIpDQogICkNCg0KYGBgDQoNCg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQoNCmdncGxvdChkZXByZXNzaW9uX2FnZSwgYWVzKHggPSBUaW1lUGVyaW9kLCB5ID0gVmFsdWUsIGZpbGwgPSBTdWJncm91cCkpICsNCiAgZ2VvbV9hcmVhKHBvc2l0aW9uID0gImlkZW50aXR5IiwgYWxwaGEgPSAwLjUpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJTeW1wdG9tcyBvZiBEZXByZXNzaXZlIERpc29yZGVyIGJ5IEFnZSBHcm91cCAoQXJlYSBDaGFydCkiLA0KICAgIHggPSAiRGF0ZSIsIHkgPSAiUGVyY2VudGFnZSIsIGZpbGwgPSAiQWdlIEdyb3VwIg0KICApICsNCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxMykgKw0KICB0aGVtZSgNCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpLA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIikNCiAgKQ0KDQpgYGANCg0KDQpgYGB7cn0NCmdncGxvdChkZXByZXNzaW9uX2FnZSwgYWVzKHggPSBUaW1lUGVyaW9kLCB5ID0gVmFsdWUpKSArDQogIGdlb21fbGluZShjb2xvciA9ICJzdGVlbGJsdWUiLCBzaXplID0gMSkgKw0KICBmYWNldF93cmFwKH4gU3ViZ3JvdXAsIHNjYWxlcyA9ICJmcmVlX3kiKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiU3ltcHRvbXMgb2YgRGVwcmVzc2l2ZSBEaXNvcmRlciBieSBBZ2UgR3JvdXAgKEZhY2V0ZWQgVmlldykiLA0KICAgIHggPSAiRGF0ZSIsIHkgPSAiUGVyY2VudGFnZSINCiAgKSArDQogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTMpICsNCiAgdGhlbWUoDQogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwNCiAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIpDQogICkNCg0KYGBgDQoNCktleSBGaW5kaW5ncw0KWW91bmcgYWR1bHRzICgxOOKAkzI5IHllYXJzKSBjb25zaXN0ZW50bHkgc2hvdyB0aGUgaGlnaGVzdCBwcmV2YWxlbmNlIG9mIGRlcHJlc3NpdmUgc3ltcHRvbXMsIGVzcGVjaWFsbHkgZHVyaW5nIHRoZSBlYXJsaWVyIHBhcnQgb2YgdGhlIHBhbmRlbWljICgyMDIw4oCTMjAyMSksIHBlYWtpbmcgYXQgb3ZlciA0MCUuDQoNClRoaXMgZ3JvdXAgZm9ybXMgdGhlIGxhcmdlc3Qg4oCcYXJlYeKAnSBhdCB0aGUgdG9wLCBjb25maXJtaW5nIHRoZWlyIGRpc3Byb3BvcnRpb25hdGUgbWVudGFsIGhlYWx0aCBidXJkZW4uDQoNClRoZSAzMOKAkzM5IGFuZCA0MOKAkzQ5IGFnZSBncm91cHMgZm9sbG93LCBidXQgd2l0aCBub3RpY2VhYmx5IGxvd2VyIHBlcmNlbnRhZ2VzLCBzdGF5aW5nIG1vc3RseSBiZXR3ZWVuIDIwJeKAkzMwJS4NCg0KT2xkZXIgYWR1bHRzICg2MCspIHJlcG9ydCB0aGUgbG93ZXN0IHJhdGVzIG9mIGRlcHJlc3NpdmUgc3ltcHRvbXMgdGhyb3VnaG91dCB0aGUgdGltZSBwZXJpb2QsIG9mdGVuIHJlbWFpbmluZyBiZWxvdyAxNSUuDQoNClBhcnRpY3VsYXJseSA4MCssIHdobyBjb25zaXN0ZW50bHkgcmVwb3J0IHRoZSBsb3dlc3QuDQoNClRoZXJl4oCZcyBhIG5vdGljZWFibGUgZGVjbGluZSBhY3Jvc3MgbW9zdCBhZ2UgZ3JvdXBzIGluIDIwMjQsIHdoaWNoIG1pZ2h0IHJlZmxlY3QgaW1wcm92ZWQgbWVudGFsIGhlYWx0aCBzZXJ2aWNlcywgcGFuZGVtaWMgcmVjb3ZlcnksIG9yIHN1cnZleSBjaGFuZ2VzLg0KDQpJbnRlcnByZXRhdGlvbiAmIEltcGxpY2F0aW9ucw0KWW91bmcgYWR1bHRzIGZhY2UgaGlnaGVyIG1lbnRhbCBoZWFsdGggdnVsbmVyYWJpbGl0eSwgcG9zc2libHkgZHVlIHRvOg0KDQpFY29ub21pYyB1bmNlcnRhaW50eSwgam9iIGxvc3MsIGFuZCBob3VzaW5nIGluc3RhYmlsaXR5Lg0KDQpTb2NpYWwgaXNvbGF0aW9uIGFuZCBkaXNydXB0ZWQgbGlmZSBtaWxlc3RvbmVzIChlLmcuLCBncmFkdWF0aW9uLCBlYXJseSBjYXJlZXIpLg0KDQpHcmVhdGVyIGxpa2VsaWhvb2Qgb2YgcmVwb3J0aW5nIHN5bXB0b21zIG9yIHNlZWtpbmcgaGVscC4NCg0KT2xkZXIgYWR1bHRzLCBkZXNwaXRlIHBvdGVudGlhbCBpc29sYXRpb24sIG1pZ2h0IGhhdmUgbW9yZSByZXNpbGllbmNlLCBjb3BpbmcgbWVjaGFuaXNtcywgb3IgdW5kZXJyZXBvcnRpbmcgZHVlIHRvIHN0aWdtYS4NCg0KUHVibGljIGhlYWx0aCBwb2xpY2llcyBhbmQgbWVudGFsIGhlYWx0aCBpbnRlcnZlbnRpb25zIHNob3VsZCBwcmlvcml0aXplIHlvdW5nIGFkdWx0IHN1cHBvcnQsIGVzcGVjaWFsbHkgZHVyaW5nIHB1YmxpYyBjcmlzZXMuDQoNCg0KYGBge3J9DQpnbGltcHNlKGRlcHJlc3Npb25fZGF0YSkNCg0KYGBgDQoNCmBgYHtyfQ0KIyBFeHRyYWN0IHllYXIgZnJvbSBkYXRlDQpkZXByZXNzaW9uX2RhdGEgPC0gZGVwcmVzc2lvbl9kYXRhICU+JQ0KICBtdXRhdGUoWWVhciA9IHllYXIobWR5KGBUaW1lIFBlcmlvZCBTdGFydCBEYXRlYCkpKSAlPiUNCiAgZmlsdGVyKCFpcy5uYShWYWx1ZSkpDQoNCg0KDQpgYGANCg0KYGBge3J9DQpncm91cF95ZWFyX2RhdGEgPC0gZGVwcmVzc2lvbl9kYXRhICU+JQ0KICBncm91cF9ieShHcm91cCwgU3ViZ3JvdXAsIFllYXIpICU+JQ0KICBzdW1tYXJpc2UoYXZnX3ZhbHVlID0gbWVhbihWYWx1ZSwgbmEucm0gPSBUUlVFKSwgLmdyb3VwcyA9ICJkcm9wIikNCg0KYGBgDQoNCg0KYGBge3J9DQpkZXByZXNzaW9uX3dpZGUgPC0gZ3JvdXBfeWVhcl9kYXRhICU+JQ0KICB1bml0ZSgiZ3JvdXBfbGFiZWwiLCBHcm91cCwgU3ViZ3JvdXAsIHNlcCA9ICIgLSAiKSAlPiUNCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IFllYXIsIHZhbHVlc19mcm9tID0gYXZnX3ZhbHVlKQ0KDQpgYGANCg0KDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGNsdXN0ZXIpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkodGlkeXIpDQoNCg0KbGlicmFyeShmYWN0b2V4dHJhKQ0KDQojIFN0ZXAgMjogRmlsdGVyIGZvciAnQnkgQWdlJyBncm91cCBhbmQgY2FsY3VsYXRlIGF2ZXJhZ2UgdmFsdWUNCmRlcHJlc3Npb25fYWdlIDwtIGRlcHJlc3Npb25fZGF0YSAlPiUNCiAgZmlsdGVyKEdyb3VwID09ICJCeSBBZ2UiKSAlPiUNCiAgZ3JvdXBfYnkoU3ViZ3JvdXApICU+JQ0KICBzdW1tYXJpc2UoYXZnX3ZhbHVlID0gbWVhbihWYWx1ZSwgbmEucm0gPSBUUlVFKSkNCg0KIyBTdGVwIDM6IFNjYWxlIHRoZSBkYXRhDQpzY2FsZWRfZGF0YSA8LSBzY2FsZShkZXByZXNzaW9uX2FnZSRhdmdfdmFsdWUpDQoNCiMgU3RlcCA0OiBBcHBseSBrLW1lYW5zIGNsdXN0ZXJpbmcgKGUuZy4sIDMgY2x1c3RlcnMpDQpzZXQuc2VlZCgxMjMpDQprbWVhbnNfcmVzdWx0IDwtIGttZWFucyhzY2FsZWRfZGF0YSwgY2VudGVycyA9IDMpDQoNCiMgU3RlcCA1OiBBZGQgY2x1c3RlciBpbmZvIGJhY2sgdG8gZGF0YWZyYW1lDQpkZXByZXNzaW9uX2FnZSRjbHVzdGVyIDwtIGFzLmZhY3RvcihrbWVhbnNfcmVzdWx0JGNsdXN0ZXIpDQoNCiMgU3RlcCA2OiBQbG90IHRoZSByZXN1bHRzDQpnZ3Bsb3QoZGVwcmVzc2lvbl9hZ2UsIGFlcyh4ID0gU3ViZ3JvdXAsIHkgPSBhdmdfdmFsdWUsIGZpbGwgPSBjbHVzdGVyKSkgKw0KICBnZW9tX2NvbCgpICsNCiAgY29vcmRfZmxpcCgpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJDbHVzdGVyZWQgQXZlcmFnZSBEZXByZXNzaW9uIFN5bXB0b21zIGJ5IEFnZSBHcm91cCIsDQogICAgeCA9ICJBZ2UgR3JvdXAiLA0KICAgIHkgPSAiQXZlcmFnZSBQZXJjZW50YWdlIiwNCiAgICBmaWxsID0gIkNsdXN0ZXIiDQogICkgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KYGBgDQoNCg0KQ2x1c3RlciAyIChHcmVlbik6DQpUaGUgMTjigJMyOSB5ZWFycyBncm91cCBzdGFuZHMgYWxvbmUg4oCUIHRoZXkgcmVwb3J0IHRoZSBoaWdoZXN0IGxldmVscyBvZiBkZXByZXNzaXZlIHN5bXB0b21zIGFjcm9zcyBhbGwgYWdlIGdyb3Vwcy4gVGhpcyBhbGlnbnMgd2l0aCBwcmV2aW91cyBkYXRhc2V0cyBzaG93aW5nIGVsZXZhdGVkIGRpc3RyZXNzIGFtb25nIHlvdW5nZXIgYWR1bHRzLg0KDQpDbHVzdGVyIDMgKEJsdWUpOg0KVGhlIDMw4oCTNTkgeWVhcnMgcmFuZ2UgZm9ybXMgYSBtaWRkbGUgZ3JvdXAsIHNob3dpbmcgbW9kZXJhdGUgbGV2ZWxzIG9mIGRlcHJlc3NpdmUgc3ltcHRvbXMuDQoNCkNsdXN0ZXIgMSAoUmVkKToNCkFkdWx0cyA2MCB5ZWFycyBhbmQgb2xkZXIgaGF2ZSB0aGUgbG93ZXN0IHJlcG9ydGVkIGxldmVscyBvZiBkZXByZXNzaW9uIHN5bXB0b21zLCBjb25zaXN0ZW50IHdpdGggbmF0aW9uYWwgbWVudGFsIGhlYWx0aCB0cmVuZHMgc2hvd2luZyBkZWNsaW5pbmcgZGlzdHJlc3Mgd2l0aCBhZ2UNCg0KIyMgTG9hZGluZyBkYXRhc2V0IGZvciBNYWNoaW5lIGxlYXJuaW5nDQoNCkRBVEFTRVQgSlNPTg0KDQpUaGlzIGRhdGFzZXQgaXMgY3JpdGljYWwgdG8gdGhlIGdvYWxzIG9mIHRoZSByZXNlYXJjaCAiSWRlbnRpZnlpbmcgRWFybHkgU2lnbnMgb2YgTWVudGFsIEhlYWx0aCBDcmlzZXMgVXNpbmcgU29jaWFsIGFuZCBFY29ub21pYyBEYXRhIiBmb3Igc2V2ZXJhbCByZWFzb25zOg0KDQpMb25naXR1ZGluYWwgYW5kIEluZGl2aWR1YWwtTGV2ZWwgRGF0YTogVW5saWtlIGFnZ3JlZ2F0ZSBwdWJsaWMgaGVhbHRoIHN1cnZleXMsIFBTWUNIRS1EIG9mZmVycyBpbmRpdmlkdWFsLWxldmVsLCB0aW1lLWxpbmtlZCByZWNvcmRz4oCUaWRlYWwgZm9yIG1vZGVsaW5nIHN1YnRsZSB0cmVuZHMgaW4gbWVudGFsIGhlYWx0aCBvdmVyIHRpbWUuDQoNCk11bHRpbW9kYWwgSW5kaWNhdG9yczogSXQgaW5jbHVkZXMgZGlnaXRhbCBiaW9tYXJrZXJzIHN1Y2ggYXMgc3RlcCBjb3VudHMsIHNsZWVwIGVmZmljaWVuY3ksIGFuZCBkYWlseSBhY3Rpdml0eSBwYXR0ZXJucywgd2hpY2ggY2FuIHNlcnZlIGFzIGVhcmx5IHByZWRpY3RvcnMgb2YgbWVudGFsIGhlYWx0aCBjaGFuZ2VzLg0KDQpMYWJlbGxlZCBEZXByZXNzaW9uIFNjb3JlczogVGhlIGRhdGFzZXQgcHJvdmlkZXMgYm90aCBiYXNlbGluZSBhbmQgZm9sbG93LXVwIFBIUS05IHNjb3JlcywgZW5hYmxpbmcgc3VwZXJ2aXNlZCBsZWFybmluZyB0byBwcmVkaWN0IGRlcHJlc3Npb24gcmlzayBhbmQgcHJvZ3Jlc3Npb24uDQoNClNvY2lvZWNvbm9taWMgQ29udGV4dDogVmFyaWFibGVzIGxpa2UgZWR1Y2F0aW9uLCBpbmNvbWUsIGFuZCBjb21vcmJpZGl0aWVzIGVucmljaCB0aGUgbW9kZWxpbmcgd2l0aCBjb250ZXh0dWFsIGFuZCBzdHJ1Y3R1cmFsIGZhY3RvcnMgYWxpZ25lZCB3aXRoIHRoaXMgc3R1ZHnigJlzIGh5cG90aGVzZXMuDQoNClRoaXMgbWFrZXMgdGhlIFBTWUNIRS1EIGRhdGFzZXQgdW5pcXVlbHkgc3VpdGVkIGZvciBkZXZlbG9waW5nIGFuZCB2YWxpZGF0aW5nIG1hY2hpbmUgbGVhcm5pbmcgbW9kZWxzIHRoYXQgZm9yZWNhc3QgZGVwcmVzc2lvbiBzZXZlcml0eSBiYXNlZCBvbiBiZWhhdmlvcmFsIGFuZCBzb2Npb2Vjb25vbWljIHNpZ25hbHPigJRvbmUgb2YgdGhlIGtleSBhbWJpdGlvbnMgb3V0bGluZWQgaW4gdGhpcyBwYXBlci4NCg0KDQpgYGB7cn0NCiMgVGhlbiBsb2FkIHRoZSBmaWxlDQpsaWJyYXJ5KGFycm93KQ0KDQojIFJlYWQgdGhlIHBhcnF1ZXQgZmlsZQ0KZGVwX3NldmVyaXR5IDwtIHJlYWRfcGFycXVldCgiQzovVXNlcnMvYWxlamEvRG93bmxvYWRzL2Fub25fcHJvY2Vzc2VkX2RmX3BhcnF1ZXQiKQ0KDQojIFBlZWsgYXQgdGhlIGRhdGENCmdsaW1wc2UoZGVwX3NldmVyaXR5KQ0KDQoNCmBgYA0KDQojIyMgRGF0YSBjbGVhbmluZzoNCg0KYGBge3J9DQojIExvYWQgbmVjZXNzYXJ5IGxpYnJhcmllcw0KbGlicmFyeShkcGx5cikNCg0KIyBTdW1tYXJ5IG9mIG1pc3NpbmcgdmFsdWVzIHBlciBjb2x1bW4NCm5hX3N1bW1hcnkgPC0gZGVwX3NldmVyaXR5ICU+JQ0KICBzdW1tYXJpc2UoYWNyb3NzKGV2ZXJ5dGhpbmcoKSwgfiBzdW0oaXMubmEoLikpKSkgJT4lDQogIHBpdm90X2xvbmdlcihjb2xzID0gZXZlcnl0aGluZygpLCBuYW1lc190byA9ICJDb2x1bW4iLCB2YWx1ZXNfdG8gPSAiTWlzc2luZ19Db3VudCIpICU+JQ0KICBhcnJhbmdlKGRlc2MoTWlzc2luZ19Db3VudCkpICU+JQ0KICBmaWx0ZXIoTWlzc2luZ19Db3VudCA+IDApDQoNCiMgVmlldyB0b3AgbWlzc2luZyBjb2x1bW5zDQpwcmludChuYV9zdW1tYXJ5KQ0KDQpgYGANCg0KTWFueSBtaXNzaW5nIHZhbHVlcw0KDQoNCg0KYGBge3J9DQojIEtlZXBwaW5nIG9ubHkgcm93cyB3aXRoIHZhbGlkIFBIUS05IHNjb3Jlcw0KZGVwX3NldmVyaXR5X2ZpbHRlcmVkIDwtIGRlcF9zZXZlcml0eSAlPiUNCiAgZmlsdGVyKCFpcy5uYShwaHE5X3Njb3JlX2VuZCkpDQoNCiMgQ2hlY2tpbmcgaG93IG1hbnkgcm93cyByZW1haW4NCm5yb3coZGVwX3NldmVyaXR5X2ZpbHRlcmVkKQ0KDQoNCmBgYA0KDQpgYGB7cn0NCiMgRHJvcCBmZWF0dXJlcyB3aXRoIG1vcmUgdGhhbiA4MCUgbWlzc2luZyB2YWx1ZXMNCnRocmVzaG9sZCA8LSAwLjggKiBucm93KGRlcF9zZXZlcml0eV9maWx0ZXJlZCkNCg0KZGVwX21vZGVsX2RhdGEgPC0gZGVwX3NldmVyaXR5X2ZpbHRlcmVkICU+JQ0KICBzZWxlY3Qod2hlcmUofiBzdW0oaXMubmEoLikpIDwgdGhyZXNob2xkKSkNCg0KIyBDaGVjayByZW1haW5pbmcgY29sdW1ucw0KZ2xpbXBzZShkZXBfbW9kZWxfZGF0YSkNCg0KYGBgDQoNCiMjIyBNb2RlbHMNCmBgYHtyfQ0KIyBMb2FkIHJlcXVpcmVkIGxpYnJhcmllcw0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGNhcmV0KQ0KDQojIFN0ZXAgMTogUmVtb3ZlIHVubmVjZXNzYXJ5IGNvbHVtbnMNCm1vZGVsX2RhdGEgPC0gZGVwX3NldmVyaXR5ICU+JQ0KICBzZWxlY3QoLWBfX2luZGV4X2xldmVsXzBfX2AsIC1waHE5X3Njb3JlX3N0YXJ0LCAtcGhxOV9jYXRfc3RhcnQsIC1waHE5X2NhdF9lbmQpICU+JQ0KICBkcm9wX25hKHBocTlfc2NvcmVfZW5kKQ0KDQojIFN0ZXAgMjogUmVtb3ZlIGhpZ2hseSBzcGFyc2UgY29sdW1ucyAob3B0aW9uYWwsIGlmIHN0aWxsIHRvbyBtYW55IE5BcykNCm1vZGVsX2RhdGEgPC0gbW9kZWxfZGF0YSAlPiUNCiAgc2VsZWN0KHdoZXJlKH4gbWVhbighaXMubmEoLikpID4gMC44KSkNCg0KIyBTdGVwIDM6IERyb3AgcmVtYWluaW5nIE5BcyAob3IgeW91IGNvdWxkIGltcHV0ZSkNCm1vZGVsX2RhdGEgPC0gZHJvcF9uYShtb2RlbF9kYXRhKQ0KDQojIFN0ZXAgNDogUGFydGl0aW9uIHRoZSBkYXRhICg4MCUgdHJhaW4sIDIwJSB0ZXN0KQ0Kc2V0LnNlZWQoMTIzKQ0KdHJhaW5faW5kZXggPC0gY3JlYXRlRGF0YVBhcnRpdGlvbihtb2RlbF9kYXRhJHBocTlfc2NvcmVfZW5kLCBwID0gMC44LCBsaXN0ID0gRkFMU0UpDQp0cmFpbl9kYXRhIDwtIG1vZGVsX2RhdGFbdHJhaW5faW5kZXgsIF0NCnRlc3RfZGF0YSA8LSBtb2RlbF9kYXRhWy10cmFpbl9pbmRleCwgXQ0KDQojIFN0ZXAgNTogRml0IGEgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwNCmxtX21vZGVsIDwtIGxtKHBocTlfc2NvcmVfZW5kIH4gLiwgZGF0YSA9IHRyYWluX2RhdGEpDQoNCiMgU3RlcCA2OiBNb2RlbCBzdW1tYXJ5DQpzdW1tYXJ5KGxtX21vZGVsKQ0KDQojIFN0ZXAgNzogUHJlZGljdCBvbiB0ZXN0IGRhdGENCnByZWRpY3Rpb25zIDwtIHByZWRpY3QobG1fbW9kZWwsIG5ld2RhdGEgPSB0ZXN0X2RhdGEpDQoNCiMgU3RlcCA4OiBFdmFsdWF0ZSBwZXJmb3JtYW5jZQ0Kcm1zZSA8LSBzcXJ0KG1lYW4oKHRlc3RfZGF0YSRwaHE5X3Njb3JlX2VuZCAtIHByZWRpY3Rpb25zKV4yKSkNCm1hZSA8LSBtZWFuKGFicyh0ZXN0X2RhdGEkcGhxOV9zY29yZV9lbmQgLSBwcmVkaWN0aW9ucykpDQoNCmNhdCgiUk1TRToiLCBybXNlLCAiXG5NQUU6IiwgbWFlKQ0KDQpgYGANCg0KTW9kZWwgUGVyZm9ybWFuY2UNClJNU0U6IDUuMDgg4oaSIE9uIGF2ZXJhZ2UsIHByZWRpY3Rpb25zIGRldmlhdGUgYnkgYWJvdXQgNSBwb2ludHMgZnJvbSBhY3R1YWwgUEhRLTkgc2NvcmVzLg0KDQpNQUU6IDMuOTkg4oaSIFRoZSBhdmVyYWdlIGFic29sdXRlIGVycm9yIGlzIHJvdWdobHkgNCBwb2ludHMuDQoNClLCsjogMC4zMiDihpIgQWJvdXQgMzIlIG9mIHRoZSB2YXJpYXRpb24gaW4gZGVwcmVzc2lvbiBzZXZlcml0eSBpcyBleHBsYWluZWQgYnkgdGhlIG1vZGVsLiBOb3QgaHVnZSwgYnV0IHNvbGlkIGdpdmVuIHRoZSBjb21wbGV4aXR5IG9mIG1lbnRhbCBoZWFsdGguDQoNCktleSBTaWduaWZpY2FudCBQcmVkaWN0b3JzIChwIDwgMC4wNSkNClRoZXNlIHZhcmlhYmxlcyBoYWQgYSBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IHJlbGF0aW9uc2hpcCB3aXRoIHRoZSBkZXByZXNzaW9uIHNjb3JlOg0KDQpEZW1vZ3JhcGhpY3MNCnNleDogQmVpbmcgbWFsZSB3YXMgbmVnYXRpdmVseSBhc3NvY2lhdGVkIHdpdGggZGVwcmVzc2lvbiBzZXZlcml0eS4NCg0KYmlydGh5ZWFyOiBZb3VuZ2VyIHBhcnRpY2lwYW50cyBzaG93ZWQgaGlnaGVyIHNjb3Jlcy4NCg0KZWR1YzogSGlnaGVyIGVkdWNhdGlvbiB3YXMgYXNzb2NpYXRlZCB3aXRoIGxvd2VyIGRlcHJlc3Npb24gc2V2ZXJpdHkuDQoNCnJhY2VfYmxhY2ssIHJhY2VfaGlzcGFuaWM6IEJvdGggd2VyZSBzaWduaWZpY2FudCBjb21wYXJlZCB0byB0aGUgcmVmZXJlbmNlIGdyb3VwIChsaWtlbHkgd2hpdGUpLg0KDQptb25leTogU3Ryb25nIHBvc2l0aXZlIGNvcnJlbGF0aW9uIOKAlCBwZXJjZWl2ZWQgZmluYW5jaWFsIGhhcmRzaGlwIGlzIGEgdG9wIHByZWRpY3Rvci4NCg0KTWVkaWNhbCBIaXN0b3J5DQpjb21vcmJpZF9taWdyYWluZXMsIGNvbW9yYmlkX25ldXJvcGF0aGljLCBjb21vcmJpZF9hcnRocml0aXMsIGNvbW9yYmlkX2dvdXQ6IFRoZXNlIGNvbW9yYmlkaXRpZXMgc2hvd2VkIHN0cm9uZyBsaW5rcyB0byBoaWdoZXIgZGVwcmVzc2lvbiBzY29yZXMuDQoNCnRyYXVtYTogU3Ryb25nIGFzc29jaWF0aW9uIHdpdGggaGlnaGVyIGRlcHJlc3Npb24gc2V2ZXJpdHkuDQoNClRyZWF0bWVudA0KbWVkX3N0YXJ0LCBtZWRfZG9zZSwgbWVkX3N0b3A6IE1lZGljYXRpb24gdXNhZ2UgcGF0dGVybnMgYXJlIGFsbCBwcmVkaWN0aXZlLg0KDQptZWRfbm9ubWVkX2RudTogVGhvc2Ugbm90IHRha2luZyBlaXRoZXIgdHJlYXRtZW50IGhhZCBzaWduaWZpY2FudGx5IHdvcnNlIHNjb3Jlcy4NCg0KTGlmZXN0eWxlDQpsaWZlX21lZGl0YXRpb246IEFzc29jaWF0ZWQgd2l0aCBzbGlnaHRseSBsb3dlciBkZXByZXNzaW9uIHNjb3Jlcy4NCg0KbGlmZV9hY3Rpdml0eV9lYXRpbmc6IEJldHRlciBlYXRpbmcgaGFiaXRzIGxpbmtlZCB3aXRoIGxvd2VyIHNjb3Jlcy4NCg0K4pqgTm9uLVNpZ25pZmljYW50IG9yIE5vaXN5IFByZWRpY3RvcnMNCk1hbnkgc2Vuc29yLWRlcml2ZWQgYWN0aXZpdHkgYW5kIHNsZWVwIG1ldHJpY3MgKGUuZy4gc3RlcHNfX2F3YWtlX19zdW1fX2NvZWZmKSBzaG93ZWQgbm8gY2xlYXIgc2lnbmFsLiBUaGVzZSBtYXkgY29udGFpbiBub2lzZSBvciByZXF1aXJlIHRyYW5zZm9ybWF0aW9uL2ludGVyYWN0aW9ucy4NCg0KDQojIyMjIFJhbmRvbSBGb3Jlc3QNCg0KYGBge3J9DQojIExvYWQgcmVxdWlyZWQgcGFja2FnZXMNCmxpYnJhcnkocmFuZG9tRm9yZXN0KQ0KbGlicmFyeShjYXJldCkNCg0KIyBTdGVwIDE6IFNlbGVjdCByZWxldmFudCBwcmVkaWN0b3JzIGJhc2VkIG9uIHNpZ25pZmljYW5jZS9kb21haW4ga25vd2xlZGdlDQpzZWxlY3RlZF92YXJzIDwtIGMoDQogICJwaHE5X3Njb3JlX2VuZCIsICJzZXgiLCAiYmlydGh5ZWFyIiwgImVkdWMiLCAibW9uZXkiLCAibW9uZXlfYXNzaXN0YW5jZSIsIA0KICAiY29tb3JiaWRfbWlncmFpbmVzIiwgImNvbW9yYmlkX25ldXJvcGF0aGljIiwgImNvbW9yYmlkX2FydGhyaXRpcyIsICJjb21vcmJpZF9nb3V0IiwNCiAgInRyYXVtYSIsICJtZWRfc3RhcnQiLCAibWVkX3N0b3AiLCAibWVkX2Rvc2UiLCAibGlmZV9tZWRpdGF0aW9uIiwgDQogICJsaWZlX2FjdGl2aXR5X2VhdGluZyIsICJtZWRfbm9ubWVkX2RudSIsICJpbnN1cmFuY2UiDQopDQoNCiMgU3Vic2V0IHRoZSBkYXRhDQpkZXBfcmYgPC0gZGVwX3NldmVyaXR5Wywgc2VsZWN0ZWRfdmFyc10NCg0KIyBSZW1vdmUgcm93cyB3aXRoIGFueSBOQSBpbiBzZWxlY3RlZCBmZWF0dXJlcw0KZGVwX3JmIDwtIG5hLm9taXQoZGVwX3JmKQ0KDQojIFN0ZXAgMjogU3BsaXQgaW50byB0cmFpbmluZyBhbmQgdGVzdGluZyBzZXRzDQpzZXQuc2VlZCgxMjMpDQpzcGxpdF9pZHggPC0gY3JlYXRlRGF0YVBhcnRpdGlvbihkZXBfcmYkcGhxOV9zY29yZV9lbmQsIHAgPSAwLjgsIGxpc3QgPSBGQUxTRSkNCnRyYWluX3JmIDwtIGRlcF9yZltzcGxpdF9pZHgsIF0NCnRlc3RfcmYgPC0gZGVwX3JmWy1zcGxpdF9pZHgsIF0NCg0KIyBTdGVwIDM6IFRyYWluIFJhbmRvbSBGb3Jlc3QgbW9kZWwNCnNldC5zZWVkKDEyMykNCnJmX21vZGVsIDwtIHJhbmRvbUZvcmVzdChwaHE5X3Njb3JlX2VuZCB+IC4sIGRhdGEgPSB0cmFpbl9yZiwgbnRyZWUgPSA1MDAsIGltcG9ydGFuY2UgPSBUUlVFKQ0KDQojIFN0ZXAgNDogUHJlZGljdCBhbmQgZXZhbHVhdGUNCnByZWRfcmYgPC0gcHJlZGljdChyZl9tb2RlbCwgdGVzdF9yZikNCg0KIyBFdmFsdWF0ZSBwZXJmb3JtYW5jZQ0KcmZfcm1zZSA8LSBSTVNFKHByZWRfcmYsIHRlc3RfcmYkcGhxOV9zY29yZV9lbmQpDQpyZl9tYWUgPC0gTUFFKHByZWRfcmYsIHRlc3RfcmYkcGhxOV9zY29yZV9lbmQpDQpjYXQoIlJhbmRvbSBGb3Jlc3QgUk1TRToiLCByZl9ybXNlLCAiXG4iKQ0KY2F0KCJSYW5kb20gRm9yZXN0IE1BRToiLCByZl9tYWUsICJcbiIpDQoNCiMgVmlldyB2YXJpYWJsZSBpbXBvcnRhbmNlDQppbXBvcnRhbmNlKHJmX21vZGVsKQ0KdmFySW1wUGxvdChyZl9tb2RlbCkNCg0KYGBgDQoNCk1vZGVsIDE6IExpbmVhciBSZWdyZXNzaW9uDQpSb290IE1lYW4gU3F1YXJlZCBFcnJvciAoUk1TRSk6IDUuMDgNCg0KTWVhbiBBYnNvbHV0ZSBFcnJvciAoTUFFKTogMy45OQ0KDQpBZGp1c3RlZCBSwrI6IDAuMzE0NQ0KDQpMaW5lYXIgcmVncmVzc2lvbiBwcm92aWRlZCBhIG1vZGVyYXRlbHkgYWNjdXJhdGUgYW5kIGludGVycHJldGFibGUgbW9kZWwuIFNldmVyYWwgZmVhdHVyZXPigJRzdWNoIGFzIG1vbmV5LXJlbGF0ZWQgdmFyaWFibGVzLCBjb21vcmJpZGl0aWVzLCBhbmQgdHJhdW1hIGhpc3RvcnnigJR3ZXJlIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQuIEhvd2V2ZXIsIHRoZSBtb2RlbCBhc3N1bWVkIGxpbmVhciByZWxhdGlvbnNoaXBzIGFuZCBtYXkgbm90IGhhdmUgY2FwdHVyZWQgaW50ZXJhY3Rpb25zIG9yIG5vbi1saW5lYXIgcGF0dGVybnMgZWZmZWN0aXZlbHkuDQoNCk1vZGVsIDI6IFJhbmRvbSBGb3Jlc3QNClJvb3QgTWVhbiBTcXVhcmVkIEVycm9yIChSTVNFKTogNC41MA0KDQpNZWFuIEFic29sdXRlIEVycm9yIChNQUUpOiAzLjUzDQoNClRoZSByYW5kb20gZm9yZXN0IG1vZGVsIG91dHBlcmZvcm1lZCBsaW5lYXIgcmVncmVzc2lvbiBvbiBib3RoIGVycm9yIG1ldHJpY3MuIFRoaXMgbW9kZWwgY2FuIGNhcHR1cmUgY29tcGxleCBpbnRlcmFjdGlvbnMgYmV0d2VlbiBmZWF0dXJlcyBhbmQgaXMgbW9yZSByb2J1c3QgdG8gb3V0bGllcnMgYW5kIG5vbi1saW5lYXJpdGllcy4gS2V5IHByZWRpY3RvcnMgaW5jbHVkZWQ6DQoNCm1vbmV5DQoNCmNvbW9yYmlkX21pZ3JhaW5lcw0KDQpjb21vcmJpZF9uZXVyb3BhdGhpYw0KDQpiaXJ0aHllYXINCg0KZWR1Y2F0aW9uIGxldmVsDQoNCnRyYXVtYQ0KDQppbnN1cmFuY2Ugc3RhdHVzDQoNCkNvbmNsdXNpb24NClRoZSBSYW5kb20gRm9yZXN0IG1vZGVsIGRlbW9uc3RyYXRlZCBiZXR0ZXIgcHJlZGljdGl2ZSBwZXJmb3JtYW5jZSwgYXMgZXZpZGVuY2VkIGJ5IGxvd2VyIFJNU0UgYW5kIE1BRSB2YWx1ZXMuIFdoaWxlIGl0IHNhY3JpZmljZXMgaW50ZXJwcmV0YWJpbGl0eSwgaXQgbW9yZSBlZmZlY3RpdmVseSBjYXB0dXJlcyB0aGUgY29tcGxleCByZWxhdGlvbnNoaXBzIHdpdGhpbiB0aGUgZGF0YSwgbWFraW5nIGl0IHRoZSBwcmVmZXJyZWQgbW9kZWwgZm9yIHByZWRpY3Rpb24gaW4gdGhpcyBjYXNlLg0KDQpHaXZlbiB0aGUgd2lkZSBhdmFpbGFiaWxpdHkgb2YgdXNlci1nZW5lcmF0ZWQgdGV4dCBkYXRhIHJlbGF0ZWQgdG8gZW1vdGlvbmFsIHdlbGwtYmVpbmcgKGUuZy4sIGZvcnVtIHBvc3RzLCBzb2NpYWwgbWVkaWEgdXBkYXRlcywgc3VydmV5cyksIGl0IGlzIGNyaXRpY2FsIHRvIHRyYW5zZm9ybSB0aGVzZSBxdWFsaXRhdGl2ZSBleHByZXNzaW9ucyBpbnRvIHN0cnVjdHVyZWQgZm9ybWF0cyB0aGF0IGNhbiBzdXBwb3J0IGFuYWx5c2lzLCBwYXR0ZXJuIHJlY29nbml0aW9uLCBhbmQgaW50ZXJ2ZW50aW9uLiBTZW50aW1lbnQgYW5hbHlzaXMg4oCUIHBhcnRpY3VsYXJseSBpbiB0aGUgY29udGV4dCBvZiBtZW50YWwgaGVhbHRoIOKAlCBwcm92aWRlcyBhIHZhbHVhYmxlIGxlbnMgdGhyb3VnaCB3aGljaCB0byBpbnRlcnByZXQgc3ViamVjdGl2ZSBjb250ZW50IGFuZCBpZGVudGlmeSBlbW90aW9uYWwgZGlzdHJlc3MgaW4gYSBzY2FsYWJsZSBhbmQgaW50ZXJwcmV0YWJsZSB3YXkuDQoNCkluIHRoZSBjdXJyZW50IHN0dWR5LCBhcHBseWluZyBzZW50aW1lbnQgYW5hbHlzaXMgaXMganVzdGlmaWVkIGZvciBzZXZlcmFsIHJlYXNvbnM6DQoNClVuZGVyc3RhbmRpbmcgRW1vdGlvbmFsIFNldmVyaXR5DQpQb3N0cyB2YXJ5IHNpZ25pZmljYW50bHkgaW4gdG9uZSwgcmFuZ2luZyBmcm9tIG1pbGQgZnJ1c3RyYXRpb24gdG8gc2V2ZXJlIHBzeWNob2xvZ2ljYWwgZGlzdHJlc3MuIFNlbnRpbWVudCBjbGFzc2lmaWNhdGlvbiBhbGxvd3MgdXMgdG8gYXNzaWduIGFwcHJveGltYXRlIHNldmVyaXR5IGxldmVscyAoZS5nLiwgbWluaW11bSwgbWlsZCwgbW9kZXJhdGUsIHNldmVyZSksIGVuYWJsaW5nIG1vcmUgcHJlY2lzZSBhbmFseXNpcyBhbmQgdHJpYWdlLg0KDQpTY2FsYWJpbGl0eSBmb3IgTGFyZ2UtU2NhbGUgRGF0YQ0KTWFudWFsIHJldmlldyBvZiB0aG91c2FuZHMgb2YgdGV4dCBlbnRyaWVzIGlzIG5vdCBmZWFzaWJsZS4gU2VudGltZW50IGFuYWx5c2lzIGVuYWJsZXMgYXV0b21hdGVkIGFuZCBjb25zaXN0ZW50IGNhdGVnb3JpemF0aW9uIG9mIG1lbnRhbCBoZWFsdGgtcmVsYXRlZCBleHByZXNzaW9ucywgbWFraW5nIGl0IHBvc3NpYmxlIHRvIHN0dWR5IGVtb3Rpb25hbCBwYXR0ZXJucyBhdCBzY2FsZS4NCg0KU3VwcG9ydCBmb3IgRWFybHkgSW50ZXJ2ZW50aW9uDQpJbiBtZW50YWwgaGVhbHRoIGNvbnRleHRzLCBpZGVudGlmeWluZyBwb3N0cyB0aGF0IHJlZmxlY3Qgc2V2ZXJlIG9yIHdvcnNlbmluZyBlbW90aW9uYWwgc3RhdGVzIGNhbiBpbmZvcm0gdGhlIGRlc2lnbiBvZiBkaWdpdGFsIGFsZXJ0cywgY2xpbmljYWwgcmVmZXJyYWwgc3lzdGVtcywgb3IgY2hhdGJvdCB0cmlhZ2UgcHJvdG9jb2xzLCBoZWxwaW5nIHRvIHByaW9yaXRpemUgc3VwcG9ydCBmb3IgaW5kaXZpZHVhbHMgYXQgaGlnaGVyIHJpc2suDQoNCkNhcHR1cmluZyBDaGFuZ2VzIE92ZXIgVGltZQ0KV2hlbiBhcHBsaWVkIGxvbmdpdHVkaW5hbGx5LCBzZW50aW1lbnQgdHJlbmRzIGNhbiByZXZlYWwgaG93IGFuIGluZGl2aWR1YWzigJlzIG1lbnRhbCBzdGF0ZSBldm9sdmVzIGluIHJlc3BvbnNlIHRvIGxpZmUgZXZlbnRzIG9yIGludGVydmVudGlvbnMuIFRoaXMgaXMgZXNwZWNpYWxseSB1c2VmdWwgaW4gZGlnaXRhbCBtZW50YWwgaGVhbHRoIHBsYXRmb3JtcyBvciB0cmVhdG1lbnQgbW9uaXRvcmluZyBzeXN0ZW1zLg0KDQpVbmxvY2tpbmcgVW5zdHJ1Y3R1cmVkIFRleHQNClVubGlrZSBzdXJ2ZXkgZGF0YSB3aXRoIHByZWRlZmluZWQgY2F0ZWdvcmllcywgdGhpcyBkYXRhc2V0IGluY2x1ZGVzIG5hdHVyYWwgbGFuZ3VhZ2UgaW5wdXQuIFNlbnRpbWVudCBhbmFseXNpcyBsZXZlcmFnZXMgTkxQIHRlY2huaXF1ZXMgdG8gY29udmVydCB0aGlzIHJpY2ggYnV0IHVuc3RydWN0dXJlZCBkYXRhIGludG8gbWVhbmluZ2Z1bCwgc3RydWN0dXJlZCBpbnNpZ2h0cy4NCg0KQnkgaW5jb3Jwb3JhdGluZyBzZW50aW1lbnQgYW5hbHlzaXMgaW50byB0aGlzIHByb2plY3QsIHdlIGV4cGFuZCB0aGUgYW5hbHl0aWNhbCB0b29sa2l0IGF2YWlsYWJsZSBmb3IgdW5kZXJzdGFuZGluZyBlYXJseSBzaWducyBvZiBtZW50YWwgaGVhbHRoIGRldGVyaW9yYXRpb24sIHBhcnRpY3VsYXJseSB3aGVuIHN5bXB0b21zIG1hbmlmZXN0IGluIGxhbmd1YWdlIGJlZm9yZSBmb3JtYWwgZGlhZ25vc2lzIG9yIGNsaW5pY2FsIG9ic2VydmF0aW9uLg0KDQoNCiMjIFNlbnRpbWVudCBhbmFseXNpcw0KDQpgYGB7cn0NCmxpYnJhcnkocmVhZHIpDQpsaWJyYXJ5KGRwbHlyKQ0KcmVkZGl0X3VybCA8LSAiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3VzbWFhbm4vRGVwcmVzc2lvbl9TZXZlcml0eV9EYXRhc2V0L3JlZnMvaGVhZHMvbWFpbi9SZWRkaXRfZGVwcmVzc2lvbl9kYXRhc2V0LmNzdiINCnJlZGRpdF9kYXRhIDwtIHJlYWRfY3N2KHJlZGRpdF91cmwpDQoNCg0KYGBgDQpFeHBsb3JpbmcgdGhlIGRhdGFzZXQ6DQpgYGB7cn0NCmdsaW1wc2UocmVkZGl0X2RhdGEpDQp0YWJsZShyZWRkaXRfZGF0YSRsYWJlbCkNCg0KYGBgDQpTZW50aW1lbnQgU2V2ZXJpdHkgQW5hbHlzaXMgVXNpbmcgUmVkZGl0IFBvc3RzDQpUbyBkZWVwZW4gdGhlIGV4cGxvcmF0aW9uIG9mIG1lbnRhbCBoZWFsdGggaW5kaWNhdG9ycywgd2UgaW5jb3Jwb3JhdGVkIGEgcHVibGljbHkgYXZhaWxhYmxlIGRhdGFzZXQgY29udGFpbmluZyBSZWRkaXQgcG9zdHMgbGFiZWxlZCBieSBkZXByZXNzaW9uIHNldmVyaXR5IChtaWxkLCBtb2RlcmF0ZSwgc2V2ZXJlLCBhbmQgbWluaW11bSkuIFRoaXMgdGV4dC1iYXNlZCBkYXRhc2V0IGVuYWJsZXMgYSBjb21wbGVtZW50YXJ5IGFwcHJvYWNoIHRvIG91ciBlYXJsaWVyIHBoeXNpb2xvZ2ljYWwgYW5kIGRlbW9ncmFwaGljIG1vZGVsaW5nIGJ5IGxldmVyYWdpbmcgbmF0dXJhbCBsYW5ndWFnZSBjb250ZW50IGRpcmVjdGx5IGV4cHJlc3NlZCBieSB1c2VycyBleHBlcmllbmNpbmcgdmFyeWluZyBsZXZlbHMgb2YgZGlzdHJlc3MuDQoNClRoZSByYXRpb25hbGUgZm9yIGNvbmR1Y3Rpbmcgc2VudGltZW50IHNldmVyaXR5IGFuYWx5c2lzIGlzIHR3b2ZvbGQ6DQoNCkZpcnN0LCB0ZXh0dWFsIHNlbGYtZXhwcmVzc2lvbiBvZnRlbiByZWZsZWN0cyBlbW90aW9uYWwgaW50ZW5zaXR5IGFuZCBwc3ljaG9sb2dpY2FsIHN0YXRlLCBvZmZlcmluZyBhIHZhbHVhYmxlIHByb3h5IGZvciBtZW50YWwgaGVhbHRoIGNsYXNzaWZpY2F0aW9uLg0KDQpTZWNvbmQsIGF1Z21lbnRpbmcgcGh5c2lvbG9naWNhbCBzaWduYWxzIHdpdGggbGFuZ3VhZ2UgYW5hbHlzaXMgY2FuIGVuaGFuY2UgcHJlZGljdGl2ZSBhY2N1cmFjeSBhbmQgbWF5IGhlbHAgc3VyZmFjZSBlYXJseSBpbmRpY2F0b3JzIG9mIG1lbnRhbCBoZWFsdGggY3Jpc2VzIG5vdCB5ZXQgZXZpZGVudCBpbiBiZWhhdmlvcmFsIGRhdGEuDQoNCkJ5IGNsYXNzaWZ5aW5nIHRoZXNlIHBvc3RzLCB3ZSBhaW0gdG8gdW5kZXJzdGFuZCBob3cgc3BlY2lmaWMgZXhwcmVzc2lvbnMgYW5kIHRoZW1lcyBjb3JyZWxhdGUgd2l0aCBjbGluaWNhbCBsYWJlbHMgb2YgZGVwcmVzc2lvbiBzZXZlcml0eS4gVGhpcyBjb3VsZCBzdXBwb3J0IHRoZSBkZXZlbG9wbWVudCBvZiBtb2RlbHMgdGhhdCBhdXRvbWF0aWNhbGx5IGZsYWcgYXQtcmlzayBpbmRpdmlkdWFscyBiYXNlZCBvbiB3cml0dGVuIGxhbmd1YWdl4oCUYSBzY2FsYWJsZSB0b29sIGZvciBlYXJseSBpbnRlcnZlbnRpb24gaW4gZGlnaXRhbCBtZW50YWwgaGVhbHRoIG1vbml0b3Jpbmcgc3lzdGVtcy4NCg0KDQpgYGB7cn0NCmxpYnJhcnkodGlkeXRleHQpDQpsaWJyYXJ5KHRleHRjbGVhbikNCmxpYnJhcnkodG0pDQpsaWJyYXJ5KFNub3diYWxsQykNCiNpbnN0YWxsLnBhY2thZ2VzKCJ0ZXh0c3RlbSIpDQpsaWJyYXJ5KHRleHRzdGVtKQ0KbGlicmFyeShkcGx5cikNCg0KDQpgYGANCg0KDQpgYGB7cn0NCiMgQ2xlYW4gdGV4dA0KcmVkZGl0X2RhdGFfY2xlYW4gPC0gcmVkZGl0X2RhdGEgJT4lDQogIG11dGF0ZSh0ZXh0ID0gcmVwbGFjZV9odG1sKHRleHQpLA0KICAgICAgICAgdGV4dCA9IHJlcGxhY2VfY29udHJhY3Rpb24odGV4dCksDQogICAgICAgICB0ZXh0ID0gdG9sb3dlcih0ZXh0KSwNCiAgICAgICAgIHRleHQgPSByZW1vdmVQdW5jdHVhdGlvbih0ZXh0KSwNCiAgICAgICAgIHRleHQgPSByZW1vdmVOdW1iZXJzKHRleHQpLA0KICAgICAgICAgdGV4dCA9IHN0cmlwV2hpdGVzcGFjZSh0ZXh0KSkNCg0KYGBgDQoNCg0KYGBge3J9DQpyZWRkaXRfZGF0YV9jbGVhbiR0ZXh0IDwtIGxlbW1hdGl6ZV9zdHJpbmdzKHJlZGRpdF9kYXRhX2NsZWFuJHRleHQpDQoNCmBgYA0KDQoNCmBgYHtyfQ0KZGF0YSgic3RvcF93b3JkcyIpDQoNCnJlZGRpdF90b2tlbnMgPC0gcmVkZGl0X2RhdGFfY2xlYW4gJT4lDQogIHVubmVzdF90b2tlbnMod29yZCwgdGV4dCkgJT4lDQogIGFudGlfam9pbihzdG9wX3dvcmRzLCBieSA9ICJ3b3JkIikNCg0KYGBgDQoNCg0KYGBge3J9DQojIENvdW50IHdvcmQgZnJlcXVlbmNpZXMgcGVyIGxhYmVsDQp3b3JkX2ZyZXEgPC0gcmVkZGl0X3Rva2VucyAlPiUNCiAgY291bnQobGFiZWwsIHdvcmQsIHNvcnQgPSBUUlVFKQ0KDQojIFZpZXcgdG9wIHdvcmRzIGJ5IHNldmVyaXR5IChvcHRpb25hbCkNCndvcmRfZnJlcSAlPiUgZ3JvdXBfYnkobGFiZWwpICU+JSB0b3BfbigxMCwgbikgJT4lIHVuZ3JvdXAoKQ0KDQpgYGANCg0KDQpgYGB7cn0NCiMgQ2FsY3VsYXRlIHRmLWlkZg0KdGZfaWRmX2RhdGEgPC0gd29yZF9mcmVxICU+JQ0KICBiaW5kX3RmX2lkZih3b3JkLCBsYWJlbCwgbikgJT4lDQogIGFycmFuZ2UoZGVzYyh0Zl9pZGYpKQ0KDQojIFZpZXcgdG9wIHRmLWlkZiB3b3JkcyBwZXIgc2V2ZXJpdHkNCnRmX2lkZl9kYXRhICU+JQ0KICBncm91cF9ieShsYWJlbCkgJT4lDQogIHRvcF9uKDEwLCB0Zl9pZGYpICU+JQ0KICB1bmdyb3VwKCkNCg0KYGBgDQoNCg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQoNCnRmX2lkZl9kYXRhICU+JQ0KICBncm91cF9ieShsYWJlbCkgJT4lDQogIHRvcF9uKDEwLCB0Zl9pZGYpICU+JQ0KICB1bmdyb3VwKCkgJT4lDQogIG11dGF0ZSh3b3JkID0gcmVvcmRlcl93aXRoaW4od29yZCwgdGZfaWRmLCBsYWJlbCkpICU+JQ0KICBnZ3Bsb3QoYWVzKHRmX2lkZiwgd29yZCwgZmlsbCA9IGxhYmVsKSkgKw0KICBnZW9tX2NvbChzaG93LmxlZ2VuZCA9IEZBTFNFKSArDQogIGZhY2V0X3dyYXAofmxhYmVsLCBzY2FsZXMgPSAiZnJlZSIpICsNCiAgc2NhbGVfeV9yZW9yZGVyZWQoKSArDQogIGxhYnModGl0bGUgPSAiVG9wIFRGLUlERiBXb3JkcyBieSBEZXByZXNzaW9uIFNldmVyaXR5IikNCg0KYGBgDQoNCktleSBPYnNlcnZhdGlvbnM6DQpNaWxkIFNldmVyaXR5OiBQb3N0cyBpbiB0aGlzIGNhdGVnb3J5IG9mdGVuIGNvbnRhaW4gZW1vdGlvbmFsbHkgZGVzY3JpcHRpdmUgdGVybXMgbGlrZSBob3BlbGVzcywgaGVhcnRicm9rZW4sIGdhcywgYW5kIHdvdW5kLiBUaGVzZSBtYXkgcmVmbGVjdCBlbW90aW9uYWwgZGlzY29tZm9ydCB3aXRob3V0IGNsZWFyIGNsaW5pY2FsIGZlYXR1cmVzLg0KDQpNaW5pbXVtIFNldmVyaXR5OiBUaGlzIGNsYXNzIGlzIGRvbWluYXRlZCBieSB3b3JkcyBzdWNoIGFzIHN1cnZleSwgbGluaywgcmVxdWVzdCwgYW5kIGdvZnVuZG1lLCBpbmRpY2F0aW5nIGEgbGFyZ2UgcHJvcG9ydGlvbiBvZiBwb3N0cyByZWxhdGVkIHRvIGdlbmVyYWwgaW5mb3JtYXRpb24gc2hhcmluZyBvciByZXNvdXJjZS1zZWVraW5nLCByYXRoZXIgdGhhbiBwZXJzb25hbCBlbW90aW9uYWwgZXhwcmVzc2lvbi4NCg0KTW9kZXJhdGUgU2V2ZXJpdHk6IFRlcm1zIGxpa2UgaW5zb21uaWEsIGFzbGVlcCwgdGFibGV0LCBpcnJpdGFibGUsIGFuZCBoeXBlcnZlbnRpbGF0ZSBoaWdobGlnaHQgc29tYXRpYyBhbmQgcHN5Y2hvbG9naWNhbCBzeW1wdG9tcyB0eXBpY2FsIG9mIGNsaW5pY2FsIGRlcHJlc3Npb24uDQoNClNldmVyZSBTZXZlcml0eTogVGhpcyBncm91cCBmZWF0dXJlcyBpbnRlbnNlIGFuZCBjb25jZXJuaW5nIHRlcm1zIGxpa2Ugc3VpY2lkYWwsIGRpc3NvY2lhdGlvbiwgaWRlYXRpb24sIGFuZCBodW1pbGlhdGlvbi4gVGhlc2UgaW5kaWNhdGUgc2VyaW91cyBtZW50YWwgaGVhbHRoIGNyaXNlcywgaW5jbHVkaW5nIHN1aWNpZGFsIHRob3VnaHRzIGFuZCBzZXZlcmUgZW1vdGlvbmFsIGRpc3RyZXNzLg0KDQpJbXBsaWNhdGlvbnM6DQpUaGlzIGFuYWx5c2lzIHN1cHBvcnRzIHRoZSBpZGVhIHRoYXQgbGFuZ3VhZ2UgcGF0dGVybnMgZGlmZmVyIG1lYW5pbmdmdWxseSBhY3Jvc3MgZGVwcmVzc2lvbiBzZXZlcml0eSBsZXZlbHMuIFRoZXNlIGRpc3RpbmN0aW9ucyBjYW4gaW5mb3JtIHRoZSBkZXZlbG9wbWVudCBvZiBtYWNoaW5lIGxlYXJuaW5nIG1vZGVscyBieSBoaWdobGlnaHRpbmcgd2hpY2ggbGV4aWNhbCBmZWF0dXJlcyBhcmUgbW9zdCBpbmZvcm1hdGl2ZSBmb3IgcHJlZGljdGluZyBzZXZlcml0eS4gRnVydGhlcm1vcmUsIHJlY29nbml6aW5nIHNldmVyaXR5LXNwZWNpZmljIGtleXdvcmRzIGNhbiBhc3Npc3QgbW9kZXJhdG9ycywgY2xpbmljaWFucywgb3Igc3VwcG9ydCBwbGF0Zm9ybXMgaW4gcHJpb3JpdGl6aW5nIGhpZ2gtcmlzayBjb250ZW50IGZvciB0aW1lbHkgaW50ZXJ2ZW50aW9uLg0KDQpgYGB7cn0NCiMgTG9hZCByZXF1aXJlZCBwYWNrYWdlcw0KbGlicmFyeSh0bSkNCmxpYnJhcnkoU25vd2JhbGxDKQ0KbGlicmFyeShjYXJldCkNCmxpYnJhcnkocmFuZG9tRm9yZXN0KQ0KbGlicmFyeShkcGx5cikNCg0KDQoNCiMgU1RFUCAyOiBTYW1wbGUgYSBzdWJzZXQgb2YgdGhlIGRhdGENCnNldC5zZWVkKDEyMykNCnJlZGRpdF9zYW1wbGUgPC0gcmVkZGl0X2RhdGEgJT4lIHNhbXBsZV9uKDUwMCkNCg0KIyBTVEVQIDM6IFRleHQgY2xlYW5pbmcNCnJlZGRpdF9zYW1wbGUkdGV4dCA8LSB0b2xvd2VyKHJlZGRpdF9zYW1wbGUkdGV4dCkNCnJlZGRpdF9zYW1wbGUkdGV4dCA8LSBnc3ViKCJbXmEtelxcc10iLCAiIiwgcmVkZGl0X3NhbXBsZSR0ZXh0KQ0KcmVkZGl0X3NhbXBsZSR0ZXh0IDwtIGdzdWIoIlxccysiLCAiICIsIHJlZGRpdF9zYW1wbGUkdGV4dCkNCg0KIyBTVEVQIDQ6IENyZWF0ZSBhIGNvcnB1cyBhbmQgRFRNDQpjb3JwdXMgPC0gVkNvcnB1cyhWZWN0b3JTb3VyY2UocmVkZGl0X3NhbXBsZSR0ZXh0KSkNCmNvcnB1cyA8LSB0bV9tYXAoY29ycHVzLCByZW1vdmVXb3Jkcywgc3RvcHdvcmRzKCJlbiIpKQ0KY29ycHVzIDwtIHRtX21hcChjb3JwdXMsIHN0ZW1Eb2N1bWVudCkNCmNvcnB1cyA8LSB0bV9tYXAoY29ycHVzLCBzdHJpcFdoaXRlc3BhY2UpDQoNCmR0bSA8LSBEb2N1bWVudFRlcm1NYXRyaXgoY29ycHVzKQ0KDQojIFNURVAgNTogQ29udmVydCBEVE0gdG8gZGF0YWZyYW1lIGFuZCBhdHRhY2ggbGFiZWxzDQpkYXRhX2ZlYXR1cmVzIDwtIGFzLmRhdGEuZnJhbWUoYXMubWF0cml4KGR0bSkpDQpjb2xuYW1lcyhkYXRhX2ZlYXR1cmVzKSA8LSBtYWtlLm5hbWVzKGNvbG5hbWVzKGRhdGFfZmVhdHVyZXMpLCB1bmlxdWUgPSBUUlVFKQ0KZGF0YV9mZWF0dXJlcyRsYWJlbCA8LSBhcy5mYWN0b3IocmVkZGl0X3NhbXBsZSRsYWJlbCkNCg0KIyBTVEVQIDY6IFRyYWluLXRlc3Qgc3BsaXQNCnNldC5zZWVkKDEyMykNCnRyYWluX2luZGV4IDwtIGNyZWF0ZURhdGFQYXJ0aXRpb24oZGF0YV9mZWF0dXJlcyRsYWJlbCwgcCA9IDAuOCwgbGlzdCA9IEZBTFNFKQ0KdHJhaW5fZGF0YSA8LSBkYXRhX2ZlYXR1cmVzW3RyYWluX2luZGV4LCBdDQp0ZXN0X2RhdGEgPC0gZGF0YV9mZWF0dXJlc1stdHJhaW5faW5kZXgsIF0NCg0KIyBTVEVQIDc6IFRyYWluIFJhbmRvbSBGb3Jlc3QgbW9kZWwgKHdpdGggZmV3ZXIgdHJlZXMgdG8gYXZvaWQgc2xvdyB0cmFpbmluZykNCm1vZGVsX3JmIDwtIHJhbmRvbUZvcmVzdChsYWJlbCB+IC4sIGRhdGEgPSB0cmFpbl9kYXRhLCBudHJlZSA9IDIwLCBpbXBvcnRhbmNlID0gVFJVRSkNCg0KIyBTVEVQIDg6IFByZWRpY3QgYW5kIGV2YWx1YXRlDQpwcmVkaWN0aW9ucyA8LSBwcmVkaWN0KG1vZGVsX3JmLCBuZXdkYXRhID0gdGVzdF9kYXRhKQ0KY29uZnVzaW9uTWF0cml4KHByZWRpY3Rpb25zLCB0ZXN0X2RhdGEkbGFiZWwpDQoNCmBgYA0KDQoNCg0KYGBge3J9DQoNCiMgTG9hZCBsaWJyYXJpZXMNCmxpYnJhcnkodG0pDQpsaWJyYXJ5KFNub3diYWxsQykNCmxpYnJhcnkoY2FyZXQpDQpsaWJyYXJ5KGUxMDcxKQ0KbGlicmFyeShkcGx5cikNCg0KIyBTVEVQIDE6IExvYWQgYW5kIHByZXBhcmUgZGF0YXNldA0KI3JlZGRpdF9kYXRhIDwtIHJlYWQuY3N2KCJDOi9Vc2Vycy9hbGVqYS9Eb3dubG9hZHMvUmVkZGl0X2RlcHJlc3Npb25fZGF0YXNldC5jc3YiKQ0KcmVkZGl0X2RhdGEkbGFiZWwgPC0gYXMuZmFjdG9yKHJlZGRpdF9kYXRhJGxhYmVsKQ0KDQojIFNURVAgMjogQmFsYW5jZSB0aGUgZGF0YXNldCB1c2luZyBkb3duc2FtcGxpbmcNCnNldC5zZWVkKDEyMykNCm1pbl9jbGFzc19zaXplIDwtIG1pbih0YWJsZShyZWRkaXRfZGF0YSRsYWJlbCkpDQpiYWxhbmNlZF9kYXRhIDwtIHJlZGRpdF9kYXRhICU+JQ0KICBncm91cF9ieShsYWJlbCkgJT4lDQogIHNsaWNlX3NhbXBsZShuID0gbWluX2NsYXNzX3NpemUpICU+JQ0KICB1bmdyb3VwKCkNCg0KIyBTVEVQIDM6IFRleHQgcHJlcHJvY2Vzc2luZw0KYmFsYW5jZWRfZGF0YSR0ZXh0IDwtIHRvbG93ZXIoYmFsYW5jZWRfZGF0YSR0ZXh0KQ0KYmFsYW5jZWRfZGF0YSR0ZXh0IDwtIGdzdWIoIlteYS16XFxzXSIsICIiLCBiYWxhbmNlZF9kYXRhJHRleHQpDQpiYWxhbmNlZF9kYXRhJHRleHQgPC0gZ3N1YigiXFxzKyIsICIgIiwgYmFsYW5jZWRfZGF0YSR0ZXh0KQ0KDQojIFNURVAgNDogQ29ycHVzIGFuZCBEVE0NCmNvcnB1cyA8LSBWQ29ycHVzKFZlY3RvclNvdXJjZShiYWxhbmNlZF9kYXRhJHRleHQpKQ0KY29ycHVzIDwtIHRtX21hcChjb3JwdXMsIHJlbW92ZVdvcmRzLCBzdG9wd29yZHMoImVuIikpDQpjb3JwdXMgPC0gdG1fbWFwKGNvcnB1cywgc3RlbURvY3VtZW50KQ0KY29ycHVzIDwtIHRtX21hcChjb3JwdXMsIHN0cmlwV2hpdGVzcGFjZSkNCg0KZHRtIDwtIERvY3VtZW50VGVybU1hdHJpeChjb3JwdXMpDQpkYXRhX2ZlYXR1cmVzIDwtIGFzLmRhdGEuZnJhbWUoYXMubWF0cml4KGR0bSkpDQpjb2xuYW1lcyhkYXRhX2ZlYXR1cmVzKSA8LSBtYWtlLm5hbWVzKGNvbG5hbWVzKGRhdGFfZmVhdHVyZXMpLCB1bmlxdWUgPSBUUlVFKQ0KDQojIFNURVAgNTogUmVhdHRhY2ggbGFiZWxzIChlbnN1cmUgdGhleSdyZSBpbiB0aGUgcmlnaHQgcGxhY2UpDQpkYXRhX2ZlYXR1cmVzJGxhYmVsIDwtIGJhbGFuY2VkX2RhdGEkbGFiZWwNCmRhdGFfZmVhdHVyZXMkbGFiZWwgPC0gYXMuZmFjdG9yKGRhdGFfZmVhdHVyZXMkbGFiZWwpICAjIGVuc3VyZSBmYWN0b3INCg0KIyBTVEVQIDY6IFRyYWluL3Rlc3Qgc3BsaXQNCnNldC5zZWVkKDEyMykNCnRyYWluX2luZGV4IDwtIGNyZWF0ZURhdGFQYXJ0aXRpb24oZGF0YV9mZWF0dXJlcyRsYWJlbCwgcCA9IDAuOCwgbGlzdCA9IEZBTFNFKQ0KdHJhaW5fZGF0YSA8LSBkYXRhX2ZlYXR1cmVzW3RyYWluX2luZGV4LCBdDQp0ZXN0X2RhdGEgPC0gZGF0YV9mZWF0dXJlc1stdHJhaW5faW5kZXgsIF0NCg0KIyBGb3JjZSBjb252ZXJzaW9uIHRvIHB1cmUgZGF0YSBmcmFtZXMNCnRyYWluX2RhdGEgPC0gYXMuZGF0YS5mcmFtZSh0cmFpbl9kYXRhKQ0KdGVzdF9kYXRhIDwtIGFzLmRhdGEuZnJhbWUodGVzdF9kYXRhKQ0KDQojIFNURVAgNzogTmFpdmUgQmF5ZXMgbW9kZWwNCmxpYnJhcnkoZTEwNzEpDQptb2RlbF9uYiA8LSBuYWl2ZUJheWVzKGxhYmVsIH4gLiwgZGF0YSA9IHRyYWluX2RhdGEpDQoNCiMgU1RFUCA4OiBQcmVkaWN0IGFuZCBldmFsdWF0ZQ0KcHJlZGljdGlvbnMgPC0gcHJlZGljdChtb2RlbF9uYiwgbmV3ZGF0YSA9IHRlc3RfZGF0YSkNCmNvbmZ1c2lvbk1hdHJpeChwcmVkaWN0aW9ucywgdGVzdF9kYXRhJGxhYmVsKQ0KDQpgYGANCg0KYGBge3J9DQoNCg0KYGBgDQoNCmBgYHtyfQ0KDQoNCmBgYA0KDQoNCg0KDQouLi4NCg0K