Random variable X is distributed \(X \sim NB(r,p)\) with mean \(\mu =\frac{r}{p}\) and variance \(\sigma^2= \frac{r(1-p)}{p^2}\)

if X is the count of independent Bernoulli trials required to achieve the rth successful trial when the probability of success is constant p.

The probability of X=n trials is \(f(X=n)= {n-1 \choose r-1} p^r (1-p)^{n-r}\)

#Estimation

if X is defined as: \(X = ∑^n_{i = 1} x_i\) then X is an observation from a negative binomial distribution with parameters prob=p and size=K, where \(K = ∑^n_{i = 1} k_i\)

The maximum likelihood and method of moments estimator (mle) of p is given by: \[ \hat{p}_{mle} = \frac{K}{X + K} \]

Generate Data


getmode <- function(v) {
   uniqv <- unique(v)
   uniqv[which.max(tabulate(match(v, uniqv)))]
}

createDataWithContamination_NB_P <- function(sample_size , contamination_prop  ){

  data <- rnbinom(sample_size , size = 2, prob = .2) 
  contaminations <-   rpois(round((sample_size*contamination_prop)), lambda = 32)
  
  data_with_contamination <- c(data, contaminations) 

   list(
     data = data,
     contaminations = contaminations,
     data_with_contamination = data_with_contamination
    )
   
}

Data Generations Factors

  1. sample size (20,50,100,200)
  2. Distribution Parameters (2 , 0.2)
  3. contamination (10% , 20% , 30%)

generateData <- function(sampleSize , contamination ){
  
  
results = NULL
#create 1000 random sample with contamination
for(i in 1:2000){
  #generate data  
  data_with_contamination <-  createDataWithContamination_NB_P(sampleSize,contamination)$data_with_contamination
   
  #Code To Handling outlier 
  

  #Quantile based flooring and capping
  #In this technique, the outlier is capped at a certain value above the upper percentile value or floored   at a factor below the lower percentile value.
  
lower  = quantile(data_with_contamination  , c(.025))[["2.5%"]]
upper = quantile(data_with_contamination  , c(.975))[["97.5%"]]


outliers <- boxplot(data_with_contamination, plot=FALSE)$out
outliersPos <- which(data_with_contamination %in% outliers)
 
  
 
dataAfterHandling_Q_b_F_C <- data_with_contamination
dataAfterHandling_mean <- data_with_contamination
dataAfterHandling_median <- data_with_contamination
dataAfterHandling_mode <- data_with_contamination


dataAfterHandling_Q_b_F_C[dataAfterHandling_Q_b_F_C<lower] <- round(lower)
dataAfterHandling_Q_b_F_C[dataAfterHandling_Q_b_F_C>upper] <- round(upper)
estimated_prop_After_Q_b_F_C <- enbinom(dataAfterHandling_Q_b_F_C, size = 2)$parameters[2][["prob"]]

mean = mean(dataAfterHandling_mean)
dataAfterHandling_mean[outliersPos] <- round(mean)
estimated_prop_After_mean <- enbinom(dataAfterHandling_mean, size = 2)$parameters[2][["prob"]]

 
median = median(dataAfterHandling_median)
dataAfterHandling_median[outliersPos] <- round(median)
estimated_prop_After_median <- enbinom(dataAfterHandling_median, size = 2)$parameters[2][["prob"]]
 

mode = getmode(dataAfterHandling_mode)
dataAfterHandling_mode[outliersPos] <- round(mode) 
estimated_prop_After_mode <- enbinom(dataAfterHandling_mode, size = 2)$parameters[2][["prob"]]
 

 results = rbind(
   results,
   data.frame(
     i,
     estimated_prop_After_Q_b_F_C,
     estimated_prop_After_mean,
     estimated_prop_After_median,
     estimated_prop_After_mode
     ))
}

results
}

# different sample size   and contamination=10%
data_20_2_10 <- generateData(20 ,  .1)
data_50_2_10 <- generateData(50 ,  .1)
data_100_2_10 <- generateData(100 ,  0.1)
data_200_2_10 <- generateData(200 ,  0.1)

# different sample size   and contamination=20%
data_20_2_20 <- generateData(20 , 0.2)
data_50_2_20 <- generateData(50 , 0.2)
data_100_2_20 <- generateData(100,0.2)
data_200_2_20 <- generateData(200,0.2)



# different sample size and contamination=20%
data_20_2_30 <- generateData(20 , 0.3)
data_50_2_30 <- generateData(50 , 0.3)

Results


doCalculations <- function(data , sampleSize , contamination) {
  
   data %>% summarize(
  sampleSize = sampleSize ,
  contamination = contamination,
 
  bias_prop_Q_b_F_C = bias(estimated_prop_After_Q_b_F_C ,  0.2 ),
  bias_prop_Mean = bias(estimated_prop_After_mean ,0.2),
  bias_prop_Median = bias(estimated_prop_After_median , 0.2),
  bias_prop_Mode = bias(estimated_prop_After_mode ,0.2) ,
  
  
  MSE_prop_Q_b_F_C  = MSE(estimated_prop_After_Q_b_F_C, 0.2),
  MSE_prop_Mean  = MSE(estimated_prop_After_mean, 0.2),
  MSE_prop_Median   = MSE(estimated_prop_After_median, 0.2),
  MSE_prop_Mode  = MSE(estimated_prop_After_mode, 0.2),
) 
}

finalResult <- NULL 

finalResult <- rbind(
  finalResult ,
                doCalculations(data_20_2_10 , 20,10),
                doCalculations(data_50_2_10 , 50,10),
                doCalculations(data_100_2_10 , 100,10),
                doCalculations(data_200_2_10 , 200,10),
  
                doCalculations(data_20_2_20 , 20,20),
                doCalculations(data_50_2_20 , 50,20),
                doCalculations(data_100_2_20 , 100,20),
                doCalculations(data_200_2_20 , 200,20),
     
                doCalculations(data_20_2_30 , 20,30),
                doCalculations(data_50_2_30 , 50,30),
                doCalculations(data_100_2_30 , 100,30),
                doCalculations(data_200_2_30 , 200,30)
                     )

finalResult %>% select(sampleSize , contamination , bias_prop_Q_b_F_C , bias_prop_Mean , bias_prop_Median ,bias_prop_Mode)



finalResult %>% select(sampleSize , contamination , MSE_prop_Q_b_F_C  , MSE_prop_Mean, MSE_prop_Median , MSE_prop_Mode)
NA
NA

#Relation Between sample size and Biased_prop for each method

finalResult %>% select( sampleSize , contamination, bias_prop_Q_b_F_C , bias_prop_Mean , bias_prop_Median ,bias_prop_Mode) %>% 
  gather("Method" , "Biased_prop" , bias_prop_Q_b_F_C , bias_prop_Mean , bias_prop_Median ,bias_prop_Mode ) %>% 
  ggplot(aes(x = (sampleSize) , y = Biased_prop)) + 
  geom_point( aes(colour = as.factor(contamination))) + 
    geom_line( aes(colour = as.factor(contamination))) + 

  facet_wrap(.~Method)




finalResult %>% select( sampleSize , contamination,MSE_prop_Q_b_F_C  , MSE_prop_Mean, MSE_prop_Median , MSE_prop_Mode) %>% 
  gather("Method" , "MSE_prop" ,  MSE_prop_Q_b_F_C  , MSE_prop_Mean, MSE_prop_Median , MSE_prop_Mode ) %>% 
  ggplot(aes(x = (sampleSize) , y = MSE_prop)) + 
  geom_point( aes(colour = as.factor(contamination))) + 
  geom_line( aes(colour = as.factor(contamination))) + 
  facet_wrap(.~Method)
Warning in gzfile(file, "wb") :
  cannot open compressed file 'C:/Users/eyada/Desktop/master/University courses/Statistical inference for data science/OutlierHandlingMethods/.Rproj.user/shared/notebooks/D230BA69-OutlierHandling_Negative Binomial Distribution/1/CD6BAB307633CDB7/cojq04yy8pzmj_t/7a1201eaacdc4086a57059cbc89a92ef.snapshot', probable reason 'No such file or directory'
Error in gzfile(file, "wb") : cannot open the connection

 
Warning in gzfile(file, "wb") :
  cannot open compressed file 'C:/Users/eyada/Desktop/master/University courses/Statistical inference for data science/OutlierHandlingMethods/.Rproj.user/shared/notebooks/D230BA69-OutlierHandling_Negative Binomial Distribution/1/CD6BAB307633CDB7/cojq04yy8pzmj_t/30f20766750349038d97ca4057157fb3.snapshot', probable reason 'No such file or directory'
Error in gzfile(file, "wb") : cannot open the connection

References

  1. https://search.r-project.org/CRAN/refmans/EnvStats/html/enbinom.html

  2. https://search.r-project.org/CRAN/refmans/EnvStats/html/00Index.html

LS0tDQp0aXRsZTogIk91dGxpZXIgSGFuZGxpbmcgTWV0aG9kcyAoTmVnYXRpdmUgQmlub21pYWwgRGlzdHJpYnV0aW9uKSINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNClJhbmRvbSB2YXJpYWJsZSBYIGlzIGRpc3RyaWJ1dGVkICRYIFxzaW0gTkIocixwKSQgd2l0aCBtZWFuICRcbXUgPVxmcmFje3J9e3B9JCBhbmQgdmFyaWFuY2UgJFxzaWdtYV4yPSBcZnJhY3tyKDEtcCl9e3BeMn0kDQoNCmlmIFggaXMgdGhlIGNvdW50IG9mIGluZGVwZW5kZW50IEJlcm5vdWxsaSB0cmlhbHMgcmVxdWlyZWQgdG8gYWNoaWV2ZSB0aGUgcnRoIHN1Y2Nlc3NmdWwgdHJpYWwgd2hlbiB0aGUgcHJvYmFiaWxpdHkgb2Ygc3VjY2VzcyBpcyBjb25zdGFudCBwLg0KIA0KVGhlIHByb2JhYmlsaXR5IG9mIFg9biB0cmlhbHMgaXMgJGYoWD1uKT0ge24tMSBcY2hvb3NlIHItMX0gcF5yICgxLXApXntuLXJ9JA0KDQoNCg0KYGBge3IgaW1wb3J0TGlicmFyeSAsIGVjaG89RkFMU0UgLCB3YXJuaW5nPUZBTFNFICwgZXJyb3I9RkFMU0V9DQpsaWJyYXJ5KHJvYnVzdCkNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KE1MbWV0cmljcykNCmxpYnJhcnkoU2ltRGVzaWduKQ0KbGlicmFyeSh0aWR5cikNCmxpYnJhcnkoRW52U3RhdHMpDQoNCmBgYA0KDQojRXN0aW1hdGlvbg0KDQppZiBYIGlzIGRlZmluZWQgYXM6ICRYID0g4oiRXm5fe2kgPSAxfSB4X2kkDQp0aGVuIFggaXMgYW4gb2JzZXJ2YXRpb24gZnJvbSBhIG5lZ2F0aXZlIGJpbm9taWFsIGRpc3RyaWJ1dGlvbiB3aXRoIHBhcmFtZXRlcnMgcHJvYj1wIGFuZCBzaXplPUssIHdoZXJlICRLID0g4oiRXm5fe2kgPSAxfSBrX2kkDQoNCg0KVGhlIG1heGltdW0gbGlrZWxpaG9vZCBhbmQgbWV0aG9kIG9mIG1vbWVudHMgZXN0aW1hdG9yIChtbGUpIG9mIHAgaXMgZ2l2ZW4gYnk6DQokJCBcaGF0e3B9X3ttbGV9ID0gXGZyYWN7S317WCArIEt9ICQkDQoNCg0KIyBHZW5lcmF0ZSBEYXRhIA0KDQpgYGB7ciBGdW5jdGlvblVzZWRUb0dlbmVyYXRlRGF0YVdpdGhfY29udGFtaW5hdGlvbiAsZWNobz1UUlVFICwgd2FybmluZz1GQUxTRX0NCg0KZ2V0bW9kZSA8LSBmdW5jdGlvbih2KSB7DQogICB1bmlxdiA8LSB1bmlxdWUodikNCiAgIHVuaXF2W3doaWNoLm1heCh0YWJ1bGF0ZShtYXRjaCh2LCB1bmlxdikpKV0NCn0NCg0KY3JlYXRlRGF0YVdpdGhDb250YW1pbmF0aW9uX05CX1AgPC0gZnVuY3Rpb24oc2FtcGxlX3NpemUgLCBjb250YW1pbmF0aW9uX3Byb3AgICl7DQoNCiAgZGF0YSA8LSBybmJpbm9tKHNhbXBsZV9zaXplICwgc2l6ZSA9IDIsIHByb2IgPSAuMikgDQogIGNvbnRhbWluYXRpb25zIDwtICAgcnBvaXMocm91bmQoKHNhbXBsZV9zaXplKmNvbnRhbWluYXRpb25fcHJvcCkpLCBsYW1iZGEgPSAzMikNCiAgDQogIGRhdGFfd2l0aF9jb250YW1pbmF0aW9uIDwtIGMoZGF0YSwgY29udGFtaW5hdGlvbnMpIA0KDQogICBsaXN0KA0KICAgICBkYXRhID0gZGF0YSwNCiAgICAgY29udGFtaW5hdGlvbnMgPSBjb250YW1pbmF0aW9ucywNCiAgICAgZGF0YV93aXRoX2NvbnRhbWluYXRpb24gPSBkYXRhX3dpdGhfY29udGFtaW5hdGlvbg0KICAgICkNCiAgIA0KfQ0KDQpgYGANCg0KDQojIyMgRGF0YSBHZW5lcmF0aW9ucyBGYWN0b3JzDQoNCjEuIHNhbXBsZSBzaXplICAoMjAsNTAsMTAwLDIwMCkgDQoyLiBEaXN0cmlidXRpb24gUGFyYW1ldGVycyAgKDIgLCAwLjIpDQozLiBjb250YW1pbmF0aW9uICgxMCUgLCAyMCUgLCAzMCUpDQoNCg0KYGBge3IgZ2VuZXJhdGVEYXRlRnVuY3Rpb24gLHdhcm5pbmc9RkFMU0V9DQoNCmdlbmVyYXRlRGF0YSA8LSBmdW5jdGlvbihzYW1wbGVTaXplICwgY29udGFtaW5hdGlvbiApew0KICANCiAgDQpyZXN1bHRzID0gTlVMTA0KI2NyZWF0ZSAxMDAwIHJhbmRvbSBzYW1wbGUgd2l0aCBjb250YW1pbmF0aW9uDQpmb3IoaSBpbiAxOjIwMDApew0KICAjZ2VuZXJhdGUgZGF0YSAgDQogIGRhdGFfd2l0aF9jb250YW1pbmF0aW9uIDwtICBjcmVhdGVEYXRhV2l0aENvbnRhbWluYXRpb25fTkJfUChzYW1wbGVTaXplLGNvbnRhbWluYXRpb24pJGRhdGFfd2l0aF9jb250YW1pbmF0aW9uDQogICANCiAgI0NvZGUgVG8gSGFuZGxpbmcgb3V0bGllciANCiAgDQoNCiAgI1F1YW50aWxlIGJhc2VkIGZsb29yaW5nIGFuZCBjYXBwaW5nDQogICNJbiB0aGlzIHRlY2huaXF1ZSwgdGhlIG91dGxpZXIgaXMgY2FwcGVkIGF0IGEgY2VydGFpbiB2YWx1ZSBhYm92ZSB0aGUgdXBwZXIgcGVyY2VudGlsZSB2YWx1ZSBvciBmbG9vcmVkICAgYXQgYSBmYWN0b3IgYmVsb3cgdGhlIGxvd2VyIHBlcmNlbnRpbGUgdmFsdWUuDQogIA0KbG93ZXIgID0gcXVhbnRpbGUoZGF0YV93aXRoX2NvbnRhbWluYXRpb24gICwgYyguMDI1KSlbWyIyLjUlIl1dDQp1cHBlciA9IHF1YW50aWxlKGRhdGFfd2l0aF9jb250YW1pbmF0aW9uICAsIGMoLjk3NSkpW1siOTcuNSUiXV0NCg0KDQpvdXRsaWVycyA8LSBib3hwbG90KGRhdGFfd2l0aF9jb250YW1pbmF0aW9uLCBwbG90PUZBTFNFKSRvdXQNCm91dGxpZXJzUG9zIDwtIHdoaWNoKGRhdGFfd2l0aF9jb250YW1pbmF0aW9uICVpbiUgb3V0bGllcnMpDQogDQogIA0KIA0KZGF0YUFmdGVySGFuZGxpbmdfUV9iX0ZfQyA8LSBkYXRhX3dpdGhfY29udGFtaW5hdGlvbg0KZGF0YUFmdGVySGFuZGxpbmdfbWVhbiA8LSBkYXRhX3dpdGhfY29udGFtaW5hdGlvbg0KZGF0YUFmdGVySGFuZGxpbmdfbWVkaWFuIDwtIGRhdGFfd2l0aF9jb250YW1pbmF0aW9uDQpkYXRhQWZ0ZXJIYW5kbGluZ19tb2RlIDwtIGRhdGFfd2l0aF9jb250YW1pbmF0aW9uDQoNCg0KZGF0YUFmdGVySGFuZGxpbmdfUV9iX0ZfQ1tkYXRhQWZ0ZXJIYW5kbGluZ19RX2JfRl9DPGxvd2VyXSA8LSByb3VuZChsb3dlcikNCmRhdGFBZnRlckhhbmRsaW5nX1FfYl9GX0NbZGF0YUFmdGVySGFuZGxpbmdfUV9iX0ZfQz51cHBlcl0gPC0gcm91bmQodXBwZXIpDQplc3RpbWF0ZWRfcHJvcF9BZnRlcl9RX2JfRl9DIDwtIGVuYmlub20oZGF0YUFmdGVySGFuZGxpbmdfUV9iX0ZfQywgc2l6ZSA9IDIpJHBhcmFtZXRlcnNbMl1bWyJwcm9iIl1dDQoNCm1lYW4gPSBtZWFuKGRhdGFBZnRlckhhbmRsaW5nX21lYW4pDQpkYXRhQWZ0ZXJIYW5kbGluZ19tZWFuW291dGxpZXJzUG9zXSA8LSByb3VuZChtZWFuKQ0KZXN0aW1hdGVkX3Byb3BfQWZ0ZXJfbWVhbiA8LSBlbmJpbm9tKGRhdGFBZnRlckhhbmRsaW5nX21lYW4sIHNpemUgPSAyKSRwYXJhbWV0ZXJzWzJdW1sicHJvYiJdXQ0KDQogDQptZWRpYW4gPSBtZWRpYW4oZGF0YUFmdGVySGFuZGxpbmdfbWVkaWFuKQ0KZGF0YUFmdGVySGFuZGxpbmdfbWVkaWFuW291dGxpZXJzUG9zXSA8LSByb3VuZChtZWRpYW4pDQplc3RpbWF0ZWRfcHJvcF9BZnRlcl9tZWRpYW4gPC0gZW5iaW5vbShkYXRhQWZ0ZXJIYW5kbGluZ19tZWRpYW4sIHNpemUgPSAyKSRwYXJhbWV0ZXJzWzJdW1sicHJvYiJdXQ0KIA0KDQptb2RlID0gZ2V0bW9kZShkYXRhQWZ0ZXJIYW5kbGluZ19tb2RlKQ0KZGF0YUFmdGVySGFuZGxpbmdfbW9kZVtvdXRsaWVyc1Bvc10gPC0gcm91bmQobW9kZSkgDQplc3RpbWF0ZWRfcHJvcF9BZnRlcl9tb2RlIDwtIGVuYmlub20oZGF0YUFmdGVySGFuZGxpbmdfbW9kZSwgc2l6ZSA9IDIpJHBhcmFtZXRlcnNbMl1bWyJwcm9iIl1dDQogDQoNCiByZXN1bHRzID0gcmJpbmQoDQogICByZXN1bHRzLA0KICAgZGF0YS5mcmFtZSgNCiAgICAgaSwNCiAgICAgZXN0aW1hdGVkX3Byb3BfQWZ0ZXJfUV9iX0ZfQywNCiAgICAgZXN0aW1hdGVkX3Byb3BfQWZ0ZXJfbWVhbiwNCiAgICAgZXN0aW1hdGVkX3Byb3BfQWZ0ZXJfbWVkaWFuLA0KICAgICBlc3RpbWF0ZWRfcHJvcF9BZnRlcl9tb2RlDQogICAgICkpDQp9DQoNCnJlc3VsdHMNCn0NCmBgYA0KDQoNCg0KDQpgYGB7cn0NCg0KIyBkaWZmZXJlbnQgc2FtcGxlIHNpemUgICBhbmQgY29udGFtaW5hdGlvbj0xMCUNCmRhdGFfMjBfMl8xMCA8LSBnZW5lcmF0ZURhdGEoMjAgLCAgLjEpDQpkYXRhXzUwXzJfMTAgPC0gZ2VuZXJhdGVEYXRhKDUwICwgIC4xKQ0KZGF0YV8xMDBfMl8xMCA8LSBnZW5lcmF0ZURhdGEoMTAwICwgIDAuMSkNCmRhdGFfMjAwXzJfMTAgPC0gZ2VuZXJhdGVEYXRhKDIwMCAsICAwLjEpDQoNCiMgZGlmZmVyZW50IHNhbXBsZSBzaXplICAgYW5kIGNvbnRhbWluYXRpb249MjAlDQpkYXRhXzIwXzJfMjAgPC0gZ2VuZXJhdGVEYXRhKDIwICwgMC4yKQ0KZGF0YV81MF8yXzIwIDwtIGdlbmVyYXRlRGF0YSg1MCAsIDAuMikNCmRhdGFfMTAwXzJfMjAgPC0gZ2VuZXJhdGVEYXRhKDEwMCwwLjIpDQpkYXRhXzIwMF8yXzIwIDwtIGdlbmVyYXRlRGF0YSgyMDAsMC4yKQ0KDQoNCg0KIyBkaWZmZXJlbnQgc2FtcGxlIHNpemUgYW5kIGNvbnRhbWluYXRpb249MjAlDQpkYXRhXzIwXzJfMzAgPC0gZ2VuZXJhdGVEYXRhKDIwICwgMC4zKQ0KZGF0YV81MF8yXzMwIDwtIGdlbmVyYXRlRGF0YSg1MCAsIDAuMykNCmRhdGFfMTAwXzJfMzAgPC0gZ2VuZXJhdGVEYXRhKDEwMCwwLjMpDQpkYXRhXzIwMF8yXzMwIDwtIGdlbmVyYXRlRGF0YSgyMDAsMC4zKQ0KDQoNCmBgYA0KDQojIFJlc3VsdHMgDQoNCmBgYHtyfQ0KDQpkb0NhbGN1bGF0aW9ucyA8LSBmdW5jdGlvbihkYXRhICwgc2FtcGxlU2l6ZSAsIGNvbnRhbWluYXRpb24pIHsNCiAgDQogICBkYXRhICU+JSBzdW1tYXJpemUoDQogIHNhbXBsZVNpemUgPSBzYW1wbGVTaXplICwNCiAgY29udGFtaW5hdGlvbiA9IGNvbnRhbWluYXRpb24sDQogDQogIGJpYXNfcHJvcF9RX2JfRl9DID0gYmlhcyhlc3RpbWF0ZWRfcHJvcF9BZnRlcl9RX2JfRl9DICwgIDAuMiApLA0KICBiaWFzX3Byb3BfTWVhbiA9IGJpYXMoZXN0aW1hdGVkX3Byb3BfQWZ0ZXJfbWVhbiAsMC4yKSwNCiAgYmlhc19wcm9wX01lZGlhbiA9IGJpYXMoZXN0aW1hdGVkX3Byb3BfQWZ0ZXJfbWVkaWFuICwgMC4yKSwNCiAgYmlhc19wcm9wX01vZGUgPSBiaWFzKGVzdGltYXRlZF9wcm9wX0FmdGVyX21vZGUgLDAuMikgLA0KICANCiAgDQogIE1TRV9wcm9wX1FfYl9GX0MgID0gTVNFKGVzdGltYXRlZF9wcm9wX0FmdGVyX1FfYl9GX0MsIDAuMiksDQogIE1TRV9wcm9wX01lYW4gID0gTVNFKGVzdGltYXRlZF9wcm9wX0FmdGVyX21lYW4sIDAuMiksDQogIE1TRV9wcm9wX01lZGlhbiAgID0gTVNFKGVzdGltYXRlZF9wcm9wX0FmdGVyX21lZGlhbiwgMC4yKSwNCiAgTVNFX3Byb3BfTW9kZSAgPSBNU0UoZXN0aW1hdGVkX3Byb3BfQWZ0ZXJfbW9kZSwgMC4yKSwNCikgDQp9DQoNCg0KDQpgYGANCg0KYGBge3IgY2FsbF9DYWxjdWxhdGlvbnNGdW5jdGlvbiAgLHdhcm5pbmc9RkFMU0UgfQ0KDQpmaW5hbFJlc3VsdCA8LSBOVUxMIA0KDQpmaW5hbFJlc3VsdCA8LSByYmluZCgNCiAgZmluYWxSZXN1bHQgLA0KICAgICAgICAgICAgICAgIGRvQ2FsY3VsYXRpb25zKGRhdGFfMjBfMl8xMCAsIDIwLDEwKSwNCiAgICAgICAgICAgICAgICBkb0NhbGN1bGF0aW9ucyhkYXRhXzUwXzJfMTAgLCA1MCwxMCksDQogICAgICAgICAgICAgICAgZG9DYWxjdWxhdGlvbnMoZGF0YV8xMDBfMl8xMCAsIDEwMCwxMCksDQogICAgICAgICAgICAgICAgZG9DYWxjdWxhdGlvbnMoZGF0YV8yMDBfMl8xMCAsIDIwMCwxMCksDQogIA0KICAgICAgICAgICAgICAgIGRvQ2FsY3VsYXRpb25zKGRhdGFfMjBfMl8yMCAsIDIwLDIwKSwNCiAgICAgICAgICAgICAgICBkb0NhbGN1bGF0aW9ucyhkYXRhXzUwXzJfMjAgLCA1MCwyMCksDQogICAgICAgICAgICAgICAgZG9DYWxjdWxhdGlvbnMoZGF0YV8xMDBfMl8yMCAsIDEwMCwyMCksDQogICAgICAgICAgICAgICAgZG9DYWxjdWxhdGlvbnMoZGF0YV8yMDBfMl8yMCAsIDIwMCwyMCksDQogICAgIA0KICAgICAgICAgICAgICAgIGRvQ2FsY3VsYXRpb25zKGRhdGFfMjBfMl8zMCAsIDIwLDMwKSwNCiAgICAgICAgICAgICAgICBkb0NhbGN1bGF0aW9ucyhkYXRhXzUwXzJfMzAgLCA1MCwzMCksDQogICAgICAgICAgICAgICAgZG9DYWxjdWxhdGlvbnMoZGF0YV8xMDBfMl8zMCAsIDEwMCwzMCksDQogICAgICAgICAgICAgICAgZG9DYWxjdWxhdGlvbnMoZGF0YV8yMDBfMl8zMCAsIDIwMCwzMCkNCiAgICAgICAgICAgICAgICAgICAgICkNCg0KDQoNCg0KDQpgYGANCiANCg0KYGBge3IgIHdhcm5pbmc9RkFMU0V9DQoNCmZpbmFsUmVzdWx0ICU+JSBzZWxlY3Qoc2FtcGxlU2l6ZSAsIGNvbnRhbWluYXRpb24gLCBiaWFzX3Byb3BfUV9iX0ZfQyAsIGJpYXNfcHJvcF9NZWFuICwgYmlhc19wcm9wX01lZGlhbiAsYmlhc19wcm9wX01vZGUpDQoNCg0KDQpmaW5hbFJlc3VsdCAlPiUgc2VsZWN0KHNhbXBsZVNpemUgLCBjb250YW1pbmF0aW9uICwgTVNFX3Byb3BfUV9iX0ZfQyAgLCBNU0VfcHJvcF9NZWFuLCBNU0VfcHJvcF9NZWRpYW4gLCBNU0VfcHJvcF9Nb2RlKQ0KIA0KDQpgYGANCiANCg0KDQpgYGB7ciBSZXN1bHRWaXN1YWxpemF0aW9ufQ0KDQojUmVsYXRpb24gQmV0d2VlbiBzYW1wbGUgc2l6ZSBhbmQgQmlhc2VkX3Byb3AgZm9yIGVhY2ggbWV0aG9kDQoNCmZpbmFsUmVzdWx0ICU+JSBzZWxlY3QoIHNhbXBsZVNpemUgLCBjb250YW1pbmF0aW9uLCBiaWFzX3Byb3BfUV9iX0ZfQyAsIGJpYXNfcHJvcF9NZWFuICwgYmlhc19wcm9wX01lZGlhbiAsYmlhc19wcm9wX01vZGUpICU+JSANCiAgZ2F0aGVyKCJNZXRob2QiICwgIkJpYXNlZF9wcm9wIiAsIGJpYXNfcHJvcF9RX2JfRl9DICwgYmlhc19wcm9wX01lYW4gLCBiaWFzX3Byb3BfTWVkaWFuICxiaWFzX3Byb3BfTW9kZSApICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gKHNhbXBsZVNpemUpICwgeSA9IEJpYXNlZF9wcm9wKSkgKyANCiAgZ2VvbV9wb2ludCggYWVzKGNvbG91ciA9IGFzLmZhY3Rvcihjb250YW1pbmF0aW9uKSkpICsgDQogICAgZ2VvbV9saW5lKCBhZXMoY29sb3VyID0gYXMuZmFjdG9yKGNvbnRhbWluYXRpb24pKSkgKyANCg0KICBmYWNldF93cmFwKC5+TWV0aG9kKQ0KDQoNCg0KZmluYWxSZXN1bHQgJT4lIHNlbGVjdCggc2FtcGxlU2l6ZSAsIGNvbnRhbWluYXRpb24sTVNFX3Byb3BfUV9iX0ZfQyAgLCBNU0VfcHJvcF9NZWFuLCBNU0VfcHJvcF9NZWRpYW4gLCBNU0VfcHJvcF9Nb2RlKSAlPiUgDQogIGdhdGhlcigiTWV0aG9kIiAsICJNU0VfcHJvcCIgLCAgTVNFX3Byb3BfUV9iX0ZfQyAgLCBNU0VfcHJvcF9NZWFuLCBNU0VfcHJvcF9NZWRpYW4gLCBNU0VfcHJvcF9Nb2RlICkgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSAoc2FtcGxlU2l6ZSkgLCB5ID0gTVNFX3Byb3ApKSArIA0KICBnZW9tX3BvaW50KCBhZXMoY29sb3VyID0gYXMuZmFjdG9yKGNvbnRhbWluYXRpb24pKSkgKyANCiAgZ2VvbV9saW5lKCBhZXMoY29sb3VyID0gYXMuZmFjdG9yKGNvbnRhbWluYXRpb24pKSkgKyANCiAgZmFjZXRfd3JhcCgufk1ldGhvZCkNCg0KIA0KDQoNCg0KDQpgYGANCg0KDQoNCg0KIyBSZWZlcmVuY2VzDQoNCjEuIGh0dHBzOi8vc2VhcmNoLnItcHJvamVjdC5vcmcvQ1JBTi9yZWZtYW5zL0VudlN0YXRzL2h0bWwvZW5iaW5vbS5odG1sDQoNCjIuIGh0dHBzOi8vc2VhcmNoLnItcHJvamVjdC5vcmcvQ1JBTi9yZWZtYW5zL0VudlN0YXRzL2h0bWwvMDBJbmRleC5odG1sDQoNCjMuIA0KDQo=