1 Data Description

Please load the MSR package and the data camera from the package. The baseline levels for the attributes are already set for you. To see a detailed description of the data, run ?camera or help(camera) in your command line prompt.

# load the package MSR
library(MSR)

# load the data `camera`
data(camera)

# get a sneak peak of the data 
head(camera)
##   id      memory_format                 lens    price  ratings
## 1  1            SD Card Plastic Lens 8x Zoom 300 euro 51.05633
## 2  1 Compact Flash Card   Glass Lens 8x Zoom 100 euro 89.76444
## 3  1            SD Card Plastic Lens 4x Zoom 100 euro 20.50488
## 4  1 Compact Flash Card Plastic Lens 8x Zoom 200 euro 61.27721
## 5  1       Memory Stick Plastic Lens 8x Zoom 100 euro 62.21202
## 6  1            SD Card   Glass Lens 8x Zoom 200 euro 33.26009

The data has 3 product attributes for a camera and 3 levels for each attribute. The levels of these attributes are as below. Note that the baseline levels are already set for all the attributes (Memory Stick, Glass Lens 8x Zoom, 300 euro).

## $memory_format
## [1] "Memory Stick"       "SD Card"            "Compact Flash Card"
## 
## $lens
## [1] "Glass Lens 8x Zoom"   "Plastic Lens 8x Zoom" "Plastic Lens 4x Zoom"
## 
## $price
## [1] "300 euro" "100 euro" "200 euro"

2 Estimating the Coefficients

We first estimate a linear regression of ratings on the three attributes (memory_format, lens, price) to obtain the coefficients of levels. The baseline levels are already set for you. In your own practices, you may use relevel() function to choose your own baselines. In theory, you can use any level as the baseline for an attribute.

# running the linear regression 
mdl <- lm(ratings ~ memory_format + lens + price, camera)

# get a summary of the model results
summary(mdl)
## 
## Call:
## lm(formula = ratings ~ memory_format + lens + price, data = camera)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -45.959  -9.616   0.387   9.410  54.870 
## 
## Coefficients:
##                                 Estimate Std. Error t value Pr(>|t|)    
## (Intercept)                      46.6175     1.5757  29.585  < 2e-16 ***
## memory_formatSD Card             -0.1962     1.4588  -0.134  0.89307    
## memory_formatCompact Flash Card   0.5834     1.4588   0.400  0.68938    
## lensPlastic Lens 8x Zoom         -3.7992     1.4588  -2.604  0.00943 ** 
## lensPlastic Lens 4x Zoom         -9.9566     1.4588  -6.825 2.14e-11 ***
## price100 euro                    16.5377     1.4588  11.336  < 2e-16 ***
## price200 euro                     6.2857     1.4588   4.309 1.92e-05 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 14.73 on 605 degrees of freedom
## Multiple R-squared:  0.2281, Adjusted R-squared:  0.2204 
## F-statistic: 29.79 on 6 and 605 DF,  p-value: < 2.2e-16

From the estimation results, we see that the overall model is significant with F-stat 29.79 and p-value < 0.05. Therefore, we reject the null hypothesis that all coefficients are zero. Note that it is unnecessary to check the R-squared as we are not doing prediction here.

Moreover, a closer look at the coefficients show that the two levels of memory_format are insignificant, with p-values of 0.89 and 0.69 respectively. Therefore, we cannot reject the null hypothesis that the coefficients are zeros. We will use this observation in the next step.

3 Obtaining the Partworths

In class, we have discussed three rules to transform the coefficients to partworths:

  1. Baseline levels partworths = 0
  2. Insignificant levels partworths = 0
  3. Significant levels partworths = coefficients

Here, we presenting two options. For those of you who are not familiar with R, we will create a table in word/excel/ppt to record the results. For those of you R lovers, pleas see the final section for the R code.

First, we create a coefficients table to record the coefficients and p-values of all levels. In your own practice, please follow a similar procedure. I will show you the table here, but you can create your table in word or excel. Note that in the table, the coefficients of baselines are zeros, and p-values of the baselines are empty. This is because we must set the coefficients of baselines to zeros.

Attributes Levels Coefficients P-values
Memory Format SD card -0.196 0.893
Compact flash card 0.583 0.689
Memory stick 0.000
Lens Plastic 8x Zoom -3.799 0.009
Plastic 4x Zoom -9.957 2.14E-11
Glass 8x Zoom 0.000
Price 100 euro 16.538 2.00E-16
200 euro 6.286 1.92E-05
300 euro 0.000


Based on the coefficients table, we then follow the three rules to obtain the partworths of all levels. The partworths of all baselines (Memory Stick, Glass 8x Zoom and 300 euro) are zeros. The partworths for insignificant levels are also zeros, including SD Card and Compact Flash Card. For all the other levels, the partworths are the coefficients.

Attributes Levels Coefficients P-values Partworths
Memory Format SD card -0.196 0.893 0.000
Compact flash card 0.583 0.689 0.000
Memory stick 0.000 0.000
Lens Plastic 8x Zoom -3.799 0.009 -3.799
Plastic 4x Zoom -9.957 2.14E-11 -9.957
Glass 8x Zoom 0.000 0.000
Price 100 euro 16.538 2.00E-16 16.538
200 euro 6.286 1.92E-05 6.286
300 euro 0.000 0.000

4 Making Use of the Results

Given the partworths, we can use them to generate some insights into consumers. Here, we focus on three applications:

  • Calculating the importance of attributes;
  • Checking the most preferred products;
  • Comparing product ideas;

4.1 Calculating the importance of attributes

To calculate the importance of an attribute, we first look at the partworths of all the levels of the attribute. Then, we find the highest and lowest levels and difference them. \[ importance = max(partworth) - min(partworth) \] Following the equation, we have:

  • Importance of Memory Format = 0 - 0 = 0
  • Importance of Lens = 0 - (-9.957) = 9.957
  • Importance of Price = 16.538 - 0 = 16.538

We can also normalize the importance for reporting purposes. With the relative importance, our clients can read results much more easily. To do the normalization, we divide each importance by the sum of all importance.

\[ Memory\,\,Format=\frac{0}{\left( 0+9.957+16.538 \right)}=0 \\ Lens=\frac{9.957}{\left( 0+9.957+16.538 \right)}=0.376 \\ Price=\frac{16.538}{\left( 0+9.957+16.538 \right)}=0.624 \]

4.2 Obtaining the most preferred product profile

To see which product profile consumers like the most, we just combine all the highest levels. For Lens, it’s Glass 8x Zoom. For Price, it’s 100 euro. For Memory Format, all the levels have the same partworth (all zeros). This means consumers do not care about which memory format to include, and the company can decide whichever memory format without influencing consumers’ preferences.

4.3 Comparing product ideas

In real research projects, you are often asked by your clients to compare some product profiles. These profiles are probably “good candidates” from within the company. For example, suppose your client asks you to compare the following two product ideas:

  • Camera A: SD card, Plastic 4x Zoom and priced at 100 euro.
  • Camera B: Memory Stick, Plastic 8x Zoom and priced at 200 euro.

To compare the two products, you just need to add up the partworths of the levels of the products.

  • For Camera A, we have \(0 − 9.957 +16.538 = 6.581\).
  • For Camera B, we have \(0 − 3.799 + 6.286 = 2.487\).

From the calculation, Camera A is more preferred by consumers.

5 For R Lovers: R Codes to Obtain Partworths and Make Use of Results (ignore this if you are not familiar with R)

First, we create three vectors for three attributes with names.

Memory_Format <- setNames(rep(0,3),
                          levels(camera$memory_format))
Lens <- setNames(rep(0,3),
                          levels(camera$lens))
Price <- setNames(rep(0,3),
                          levels(camera$price))

We next obtain the coefficients from the estimation results and transform insignificant coefficients to zeros by checking if p-values are larger than 0.05.

# getting the coefficients table
results <- summary(mdl)$coefficients
coefficients <- results[-1,1]*(results[-1,4]<0.05)

# reshape into a matrix
coefficients <- matrix(coefficients, nrow = 2, ncol = 3)

We next pack the coefficients into the three partworth vectors and create a list called partworths to store all partworths values.

Memory_Format[2:3] <- coefficients[,1]
Lens[2:3] <- coefficients[,2]
Price[2:3] <- coefficients[,3]

partworths <- list(Memory_Format = Memory_Format,
                   Lens = Lens,
                   Price = Price)
partworths
## $Memory_Format
##       Memory Stick            SD Card Compact Flash Card 
##                  0                  0                  0 
## 
## $Lens
##   Glass Lens 8x Zoom Plastic Lens 8x Zoom Plastic Lens 4x Zoom 
##             0.000000            -3.799195            -9.956553 
## 
## $Price
##  300 euro  100 euro  200 euro 
##  0.000000 16.537702  6.285731

Given the partworths table, we then calculate the importance of different attributes and the relative importance.

importance <- unlist(lapply(partworths,
                            function(x){max(x)-min(x)}))
importance
## Memory_Format          Lens         Price 
##      0.000000      9.956553     16.537702
relative_importance <- importance/sum(importance)
relative_importance
## Memory_Format          Lens         Price 
##     0.0000000     0.3758005     0.6241995

The most preferred products are the combination of all highest levels.

most_preferred <- lapply(partworths,
                         function(x){which(x==max(x),arr.ind = T)})
most_preferred
## $Memory_Format
##       Memory Stick            SD Card Compact Flash Card 
##                  1                  2                  3 
## 
## $Lens
## Glass Lens 8x Zoom 
##                  1 
## 
## $Price
## 100 euro 
##        2

Lastly, we compare the two hypothetical product profiles: A vs. B.

  • Camera A: SD card, Plastic 4x Zoom and priced at 100 euro.
  • Camera B: Memory Stick, Plastic 8x Zoom and priced at 200 euro.
Utility_A <- partworths$Memory_Format[2] +
  partworths$Lens[3] + 
  partworths$Price[2]
setNames(Utility_A,"Utility_A")
## Utility_A 
##  6.581148
Utility_B <- partworths$Memory_Format[1] +
  partworths$Lens[2] + 
  partworths$Price[3]
setNames(Utility_B,"Utility_B")
## Utility_B 
##  2.486536
LS0tDQp0aXRsZTogJ1IgVHV0b3JpYWw6IENvbmpvaW50IEFuYWx5c2lzJw0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIGRmX3ByaW50OiBkZWZhdWx0DQogICAgY29kZV9kb3dubG9hZDogeWVzDQogICAgdGhlbWU6IHJlYWRhYmxlDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZmxvYXQ6IA0KICAgICAgY29sbGFwc2VkOiBubw0KICAgICAgc21vb3RoX3Njcm9sbDogbm8NCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICBwZGZfZG9jdW1lbnQ6DQogICAgdG9jOiB5ZXMNCi0tLQ0KDQojIERhdGEgRGVzY3JpcHRpb24gDQoNClBsZWFzZSBsb2FkIHRoZSBgTVNSYCBwYWNrYWdlIGFuZCB0aGUgZGF0YSBgY2FtZXJhYCBmcm9tIHRoZSBwYWNrYWdlLiBUaGUgYmFzZWxpbmUgbGV2ZWxzIGZvciB0aGUgYXR0cmlidXRlcyBhcmUgYWxyZWFkeSBzZXQgZm9yIHlvdS4gVG8gc2VlIGEgZGV0YWlsZWQgZGVzY3JpcHRpb24gb2YgdGhlIGRhdGEsIHJ1biBgP2NhbWVyYWAgb3IgYGhlbHAoY2FtZXJhKWAgaW4geW91ciBjb21tYW5kIGxpbmUgcHJvbXB0LiANCg0KYGBge3J9DQojIGxvYWQgdGhlIHBhY2thZ2UgTVNSDQpsaWJyYXJ5KE1TUikNCg0KIyBsb2FkIHRoZSBkYXRhIGBjYW1lcmFgDQpkYXRhKGNhbWVyYSkNCg0KIyBnZXQgYSBzbmVhayBwZWFrIG9mIHRoZSBkYXRhIA0KaGVhZChjYW1lcmEpDQpgYGANCg0KVGhlIGRhdGEgaGFzIDMgcHJvZHVjdCBhdHRyaWJ1dGVzIGZvciBhIGNhbWVyYSBhbmQgMyBsZXZlbHMgZm9yIGVhY2ggYXR0cmlidXRlLiBUaGUgbGV2ZWxzIG9mIHRoZXNlIGF0dHJpYnV0ZXMgYXJlIGFzIGJlbG93LiBOb3RlIHRoYXQgdGhlIGJhc2VsaW5lIGxldmVscyBhcmUgYWxyZWFkeSBzZXQgZm9yIGFsbCB0aGUgYXR0cmlidXRlcyAoYE1lbW9yeSBTdGlja2AsIGBHbGFzcyBMZW5zIDh4IFpvb21gLCBgMzAwIGV1cm9gKS4NCg0KYGBge3IsIGVjaG89RkFMU0V9DQojIGNoZWNrIHRoZSBsZXZlbHMgb2YgYWxsIGF0dHJpYnV0ZXMNCmxhcHBseShjYW1lcmFbLDI6NF0sbGV2ZWxzKQ0KYGBgDQoNCiMgRXN0aW1hdGluZyB0aGUgQ29lZmZpY2llbnRzDQoNCldlIGZpcnN0IGVzdGltYXRlIGEgbGluZWFyIHJlZ3Jlc3Npb24gb2YgcmF0aW5ncyBvbiB0aGUgdGhyZWUgYXR0cmlidXRlcyAoYG1lbW9yeV9mb3JtYXRgLCBgbGVuc2AsIGBwcmljZWApIHRvIG9idGFpbiB0aGUgY29lZmZpY2llbnRzIG9mIGxldmVscy4gVGhlIGJhc2VsaW5lIGxldmVscyBhcmUgYWxyZWFkeSBzZXQgZm9yIHlvdS4gSW4geW91ciBvd24gcHJhY3RpY2VzLCB5b3UgbWF5IHVzZSBgcmVsZXZlbCgpYCBmdW5jdGlvbiB0byBjaG9vc2UgeW91ciBvd24gYmFzZWxpbmVzLiBJbiB0aGVvcnksIHlvdSBjYW4gdXNlIGFueSBsZXZlbCBhcyB0aGUgYmFzZWxpbmUgZm9yIGFuIGF0dHJpYnV0ZS4gDQoNCmBgYHtyfQ0KIyBydW5uaW5nIHRoZSBsaW5lYXIgcmVncmVzc2lvbiANCm1kbCA8LSBsbShyYXRpbmdzIH4gbWVtb3J5X2Zvcm1hdCArIGxlbnMgKyBwcmljZSwgY2FtZXJhKQ0KDQojIGdldCBhIHN1bW1hcnkgb2YgdGhlIG1vZGVsIHJlc3VsdHMNCnN1bW1hcnkobWRsKQ0KDQpgYGANCg0KRnJvbSB0aGUgZXN0aW1hdGlvbiByZXN1bHRzLCB3ZSBzZWUgdGhhdCB0aGUgb3ZlcmFsbCBtb2RlbCBpcyBzaWduaWZpY2FudCB3aXRoIGBGLXN0YXRgIDI5Ljc5IGFuZCBgcC12YWx1ZSA8IDAuMDVgLiBUaGVyZWZvcmUsIHdlIHJlamVjdCB0aGUgbnVsbCBoeXBvdGhlc2lzIHRoYXQgYWxsIGNvZWZmaWNpZW50cyBhcmUgemVyby4gTm90ZSB0aGF0IGl0IGlzIHVubmVjZXNzYXJ5IHRvIGNoZWNrIHRoZSBSLXNxdWFyZWQgYXMgd2UgYXJlIG5vdCBkb2luZyBwcmVkaWN0aW9uIGhlcmUuIA0KDQpNb3Jlb3ZlciwgYSBjbG9zZXIgbG9vayBhdCB0aGUgY29lZmZpY2llbnRzIHNob3cgdGhhdCB0aGUgdHdvIGxldmVscyBvZiBgbWVtb3J5X2Zvcm1hdGAgYXJlIGluc2lnbmlmaWNhbnQsIHdpdGggYHAtdmFsdWVzYCBvZiAwLjg5IGFuZCAwLjY5IHJlc3BlY3RpdmVseS4gVGhlcmVmb3JlLCB3ZSBjYW5ub3QgcmVqZWN0IHRoZSBudWxsIGh5cG90aGVzaXMgdGhhdCB0aGUgY29lZmZpY2llbnRzIGFyZSB6ZXJvcy4gV2Ugd2lsbCB1c2UgdGhpcyBvYnNlcnZhdGlvbiBpbiB0aGUgbmV4dCBzdGVwLiANCg0KIyBPYnRhaW5pbmcgdGhlIFBhcnR3b3J0aHMNCg0KSW4gY2xhc3MsIHdlIGhhdmUgZGlzY3Vzc2VkIHRocmVlIHJ1bGVzIHRvIHRyYW5zZm9ybSB0aGUgY29lZmZpY2llbnRzIHRvIHBhcnR3b3J0aHM6DQoNCiAgMS4gQmFzZWxpbmUgbGV2ZWxzIHBhcnR3b3J0aHMgPSAwDQogIDIuIEluc2lnbmlmaWNhbnQgbGV2ZWxzIHBhcnR3b3J0aHMgPSAwDQogIDMuIFNpZ25pZmljYW50IGxldmVscyBwYXJ0d29ydGhzID0gY29lZmZpY2llbnRzICANCg0KSGVyZSwgd2UgcHJlc2VudGluZyB0d28gb3B0aW9ucy4gRm9yIHRob3NlIG9mIHlvdSB3aG8gYXJlIG5vdCBmYW1pbGlhciB3aXRoIFIsIHdlIHdpbGwgY3JlYXRlIGEgdGFibGUgaW4gd29yZC9leGNlbC9wcHQgdG8gcmVjb3JkIHRoZSByZXN1bHRzLiBGb3IgdGhvc2Ugb2YgeW91IFIgbG92ZXJzLCBwbGVhcyBzZWUgdGhlIGZpbmFsIHNlY3Rpb24gZm9yIHRoZSBSIGNvZGUuIA0KDQpGaXJzdCwgd2UgY3JlYXRlIGEgY29lZmZpY2llbnRzIHRhYmxlIHRvIHJlY29yZCB0aGUgY29lZmZpY2llbnRzIGFuZCBwLXZhbHVlcyBvZiBhbGwgbGV2ZWxzLiBJbiB5b3VyIG93biBwcmFjdGljZSwgcGxlYXNlIGZvbGxvdyBhIHNpbWlsYXIgcHJvY2VkdXJlLiBJIHdpbGwgc2hvdyB5b3UgdGhlIHRhYmxlIGhlcmUsIGJ1dCB5b3UgY2FuIGNyZWF0ZSB5b3VyIHRhYmxlIGluIHdvcmQgb3IgZXhjZWwuIE5vdGUgdGhhdCBpbiB0aGUgdGFibGUsIHRoZSBjb2VmZmljaWVudHMgb2YgYmFzZWxpbmVzIGFyZSB6ZXJvcywgYW5kIHAtdmFsdWVzIG9mIHRoZSBiYXNlbGluZXMgYXJlIGVtcHR5LiBUaGlzIGlzIGJlY2F1c2Ugd2UgbXVzdCBzZXQgdGhlIGNvZWZmaWNpZW50cyBvZiBiYXNlbGluZXMgdG8gemVyb3MuICAgDQoNCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+DQoudGcgIHtib3JkZXItY29sbGFwc2U6Y29sbGFwc2U7Ym9yZGVyLXNwYWNpbmc6MDt9DQoudGcgdGR7Ym9yZGVyLWNvbG9yOmJsYWNrO2JvcmRlci1zdHlsZTpzb2xpZDtib3JkZXItd2lkdGg6MXB4O2ZvbnQtZmFtaWx5OkFyaWFsLCBzYW5zLXNlcmlmO2ZvbnQtc2l6ZToxNHB4Ow0KICBvdmVyZmxvdzpoaWRkZW47cGFkZGluZzoxMHB4IDVweDt3b3JkLWJyZWFrOm5vcm1hbDt9DQoudGcgdGh7Ym9yZGVyLWNvbG9yOmJsYWNrO2JvcmRlci1zdHlsZTpzb2xpZDtib3JkZXItd2lkdGg6MXB4O2ZvbnQtZmFtaWx5OkFyaWFsLCBzYW5zLXNlcmlmO2ZvbnQtc2l6ZToxNHB4Ow0KICBmb250LXdlaWdodDpub3JtYWw7b3ZlcmZsb3c6aGlkZGVuO3BhZGRpbmc6MTBweCA1cHg7d29yZC1icmVhazpub3JtYWw7fQ0KLnRnIC50Zy1meW1ye2JvcmRlci1jb2xvcjppbmhlcml0O2ZvbnQtd2VpZ2h0OmJvbGQ7dGV4dC1hbGlnbjpsZWZ0O3ZlcnRpY2FsLWFsaWduOnRvcH0NCi50ZyAudGctMHBreXtib3JkZXItY29sb3I6aW5oZXJpdDt0ZXh0LWFsaWduOmxlZnQ7dmVydGljYWwtYWxpZ246dG9wfQ0KPC9zdHlsZT4NCjx0YWJsZSBjbGFzcz0idGciPg0KPHRoZWFkPg0KICA8dHI+DQogICAgPHRoIGNsYXNzPSJ0Zy1meW1yIj5BdHRyaWJ1dGVzPC90aD4NCiAgICA8dGggY2xhc3M9InRnLWZ5bXIiPkxldmVsczwvdGg+DQogICAgPHRoIGNsYXNzPSJ0Zy1meW1yIj5Db2VmZmljaWVudHM8L3RoPg0KICAgIDx0aCBjbGFzcz0idGctZnltciI+UC12YWx1ZXM8L3RoPg0KICA8L3RyPg0KPC90aGVhZD4NCjx0Ym9keT4NCiAgPHRyPg0KICAgIDx0ZCBjbGFzcz0idGctMHBreSI+TWVtb3J5IEZvcm1hdDwvdGQ+DQogICAgPHRkIGNsYXNzPSJ0Zy0wcGt5Ij5TRCBjYXJkPC90ZD4NCiAgICA8dGQgY2xhc3M9InRnLTBwa3kiPi0wLjE5NjwvdGQ+DQogICAgPHRkIGNsYXNzPSJ0Zy0wcGt5Ij4wLjg5MzwvdGQ+DQogIDwvdHI+DQogIDx0cj4NCiAgICA8dGQgY2xhc3M9InRnLTBwa3kiPjwvdGQ+DQogICAgPHRkIGNsYXNzPSJ0Zy0wcGt5Ij5Db21wYWN0IGZsYXNoIGNhcmQ8L3RkPg0KICAgIDx0ZCBjbGFzcz0idGctMHBreSI+MC41ODM8L3RkPg0KICAgIDx0ZCBjbGFzcz0idGctMHBreSI+MC42ODk8L3RkPg0KICA8L3RyPg0KICA8dHI+DQogICAgPHRkIGNsYXNzPSJ0Zy0wcGt5Ij48L3RkPg0KICAgIDx0ZCBjbGFzcz0idGctMHBreSI+TWVtb3J5IHN0aWNrPC90ZD4NCiAgICA8dGQgY2xhc3M9InRnLTBwa3kiPjAuMDAwPC90ZD4NCiAgICA8dGQgY2xhc3M9InRnLTBwa3kiPjwvdGQ+DQogIDwvdHI+DQogIDx0cj4NCiAgICA8dGQgY2xhc3M9InRnLTBwa3kiPkxlbnM8L3RkPg0KICAgIDx0ZCBjbGFzcz0idGctMHBreSI+UGxhc3RpYyA4eCBab29tPC90ZD4NCiAgICA8dGQgY2xhc3M9InRnLTBwa3kiPi0zLjc5OTwvdGQ+DQogICAgPHRkIGNsYXNzPSJ0Zy0wcGt5Ij4wLjAwOTwvdGQ+DQogIDwvdHI+DQogIDx0cj4NCiAgICA8dGQgY2xhc3M9InRnLTBwa3kiPjwvdGQ+DQogICAgPHRkIGNsYXNzPSJ0Zy0wcGt5Ij5QbGFzdGljIDR4IFpvb208L3RkPg0KICAgIDx0ZCBjbGFzcz0idGctMHBreSI+LTkuOTU3PC90ZD4NCiAgICA8dGQgY2xhc3M9InRnLTBwa3kiPjIuMTRFLTExPC90ZD4NCiAgPC90cj4NCiAgPHRyPg0KICAgIDx0ZCBjbGFzcz0idGctMHBreSI+PC90ZD4NCiAgICA8dGQgY2xhc3M9InRnLTBwa3kiPkdsYXNzIDh4IFpvb208L3RkPg0KICAgIDx0ZCBjbGFzcz0idGctMHBreSI+MC4wMDA8L3RkPg0KICAgIDx0ZCBjbGFzcz0idGctMHBreSI+PC90ZD4NCiAgPC90cj4NCiAgPHRyPg0KICAgIDx0ZCBjbGFzcz0idGctMHBreSI+UHJpY2U8L3RkPg0KICAgIDx0ZCBjbGFzcz0idGctMHBreSI+MTAwIGV1cm88L3RkPg0KICAgIDx0ZCBjbGFzcz0idGctMHBreSI+MTYuNTM4PC90ZD4NCiAgICA8dGQgY2xhc3M9InRnLTBwa3kiPjIuMDBFLTE2PC90ZD4NCiAgPC90cj4NCiAgPHRyPg0KICAgIDx0ZCBjbGFzcz0idGctMHBreSI+PC90ZD4NCiAgICA8dGQgY2xhc3M9InRnLTBwa3kiPjIwMCBldXJvPC90ZD4NCiAgICA8dGQgY2xhc3M9InRnLTBwa3kiPjYuMjg2PC90ZD4NCiAgICA8dGQgY2xhc3M9InRnLTBwa3kiPjEuOTJFLTA1PC90ZD4NCiAgPC90cj4NCiAgPHRyPg0KICAgIDx0ZCBjbGFzcz0idGctMHBreSI+PC90ZD4NCiAgICA8dGQgY2xhc3M9InRnLTBwa3kiPjMwMCBldXJvPC90ZD4NCiAgICA8dGQgY2xhc3M9InRnLTBwa3kiPjAuMDAwPC90ZD4NCiAgICA8dGQgY2xhc3M9InRnLTBwa3kiPjwvdGQ+DQogIDwvdHI+DQo8L3Rib2R5Pg0KPC90YWJsZT48YnI+DQoNCkJhc2VkIG9uIHRoZSBjb2VmZmljaWVudHMgdGFibGUsIHdlIHRoZW4gZm9sbG93IHRoZSB0aHJlZSBydWxlcyB0byBvYnRhaW4gdGhlIHBhcnR3b3J0aHMgb2YgYWxsIGxldmVscy4gVGhlIHBhcnR3b3J0aHMgb2YgYWxsIGJhc2VsaW5lcyAoYE1lbW9yeSBTdGlja2AsIGBHbGFzcyA4eCBab29tYCBhbmQgYDMwMCBldXJvYCkgYXJlIHplcm9zLiBUaGUgcGFydHdvcnRocyBmb3IgaW5zaWduaWZpY2FudCBsZXZlbHMgYXJlIGFsc28gemVyb3MsIGluY2x1ZGluZyBgU0QgQ2FyZGAgYW5kIGBDb21wYWN0IEZsYXNoIENhcmRgLiBGb3IgYWxsIHRoZSBvdGhlciBsZXZlbHMsIHRoZSBwYXJ0d29ydGhzIGFyZSB0aGUgY29lZmZpY2llbnRzLiANCg0KPHN0eWxlIHR5cGU9InRleHQvY3NzIj4NCi50ZyAge2JvcmRlci1jb2xsYXBzZTpjb2xsYXBzZTtib3JkZXItc3BhY2luZzowO30NCi50ZyB0ZHtib3JkZXItY29sb3I6YmxhY2s7Ym9yZGVyLXN0eWxlOnNvbGlkO2JvcmRlci13aWR0aDoxcHg7Zm9udC1mYW1pbHk6QXJpYWwsIHNhbnMtc2VyaWY7Zm9udC1zaXplOjE0cHg7DQogIG92ZXJmbG93OmhpZGRlbjtwYWRkaW5nOjEwcHggNXB4O3dvcmQtYnJlYWs6bm9ybWFsO30NCi50ZyB0aHtib3JkZXItY29sb3I6YmxhY2s7Ym9yZGVyLXN0eWxlOnNvbGlkO2JvcmRlci13aWR0aDoxcHg7Zm9udC1mYW1pbHk6QXJpYWwsIHNhbnMtc2VyaWY7Zm9udC1zaXplOjE0cHg7DQogIGZvbnQtd2VpZ2h0Om5vcm1hbDtvdmVyZmxvdzpoaWRkZW47cGFkZGluZzoxMHB4IDVweDt3b3JkLWJyZWFrOm5vcm1hbDt9DQoudGcgLnRnLWZ5bXJ7Ym9yZGVyLWNvbG9yOmluaGVyaXQ7Zm9udC13ZWlnaHQ6Ym9sZDt0ZXh0LWFsaWduOmxlZnQ7dmVydGljYWwtYWxpZ246dG9wfQ0KLnRnIC50Zy0wcGt5e2JvcmRlci1jb2xvcjppbmhlcml0O3RleHQtYWxpZ246bGVmdDt2ZXJ0aWNhbC1hbGlnbjp0b3B9DQo8L3N0eWxlPg0KPHRhYmxlIGNsYXNzPSJ0ZyI+DQo8dGhlYWQ+DQogIDx0cj4NCiAgICA8dGggY2xhc3M9InRnLWZ5bXIiPkF0dHJpYnV0ZXM8L3RoPg0KICAgIDx0aCBjbGFzcz0idGctZnltciI+TGV2ZWxzPC90aD4NCiAgICA8dGggY2xhc3M9InRnLWZ5bXIiPkNvZWZmaWNpZW50czwvdGg+DQogICAgPHRoIGNsYXNzPSJ0Zy1meW1yIj5QLXZhbHVlczwvdGg+DQogICAgPHRoIGNsYXNzPSJ0Zy0wcGt5Ij48c3BhbiBzdHlsZT0iZm9udC13ZWlnaHQ6Ym9sZCI+UGFydHdvcnRoczwvc3Bhbj48L3RoPg0KICA8L3RyPg0KPC90aGVhZD4NCjx0Ym9keT4NCiAgPHRyPg0KICAgIDx0ZCBjbGFzcz0idGctMHBreSI+TWVtb3J5IEZvcm1hdDwvdGQ+DQogICAgPHRkIGNsYXNzPSJ0Zy0wcGt5Ij5TRCBjYXJkPC90ZD4NCiAgICA8dGQgY2xhc3M9InRnLTBwa3kiPi0wLjE5NjwvdGQ+DQogICAgPHRkIGNsYXNzPSJ0Zy0wcGt5Ij4wLjg5MzwvdGQ+DQogICAgPHRkIGNsYXNzPSJ0Zy0wcGt5Ij4wLjAwMDwvdGQ+DQogIDwvdHI+DQogIDx0cj4NCiAgICA8dGQgY2xhc3M9InRnLTBwa3kiPjwvdGQ+DQogICAgPHRkIGNsYXNzPSJ0Zy0wcGt5Ij5Db21wYWN0IGZsYXNoIGNhcmQ8L3RkPg0KICAgIDx0ZCBjbGFzcz0idGctMHBreSI+MC41ODM8L3RkPg0KICAgIDx0ZCBjbGFzcz0idGctMHBreSI+MC42ODk8L3RkPg0KICAgIDx0ZCBjbGFzcz0idGctMHBreSI+MC4wMDA8L3RkPg0KICA8L3RyPg0KICA8dHI+DQogICAgPHRkIGNsYXNzPSJ0Zy0wcGt5Ij48L3RkPg0KICAgIDx0ZCBjbGFzcz0idGctMHBreSI+TWVtb3J5IHN0aWNrPC90ZD4NCiAgICA8dGQgY2xhc3M9InRnLTBwa3kiPjAuMDAwPC90ZD4NCiAgICA8dGQgY2xhc3M9InRnLTBwa3kiPjwvdGQ+DQogICAgPHRkIGNsYXNzPSJ0Zy0wcGt5Ij4wLjAwMDwvdGQ+DQogIDwvdHI+DQogIDx0cj4NCiAgICA8dGQgY2xhc3M9InRnLTBwa3kiPkxlbnM8L3RkPg0KICAgIDx0ZCBjbGFzcz0idGctMHBreSI+UGxhc3RpYyA4eCBab29tPC90ZD4NCiAgICA8dGQgY2xhc3M9InRnLTBwa3kiPi0zLjc5OTwvdGQ+DQogICAgPHRkIGNsYXNzPSJ0Zy0wcGt5Ij4wLjAwOTwvdGQ+DQogICAgPHRkIGNsYXNzPSJ0Zy0wcGt5Ij4tMy43OTk8L3RkPg0KICA8L3RyPg0KICA8dHI+DQogICAgPHRkIGNsYXNzPSJ0Zy0wcGt5Ij48L3RkPg0KICAgIDx0ZCBjbGFzcz0idGctMHBreSI+UGxhc3RpYyA0eCBab29tPC90ZD4NCiAgICA8dGQgY2xhc3M9InRnLTBwa3kiPi05Ljk1NzwvdGQ+DQogICAgPHRkIGNsYXNzPSJ0Zy0wcGt5Ij4yLjE0RS0xMTwvdGQ+DQogICAgPHRkIGNsYXNzPSJ0Zy0wcGt5Ij4tOS45NTc8L3RkPg0KICA8L3RyPg0KICA8dHI+DQogICAgPHRkIGNsYXNzPSJ0Zy0wcGt5Ij48L3RkPg0KICAgIDx0ZCBjbGFzcz0idGctMHBreSI+R2xhc3MgOHggWm9vbTwvdGQ+DQogICAgPHRkIGNsYXNzPSJ0Zy0wcGt5Ij4wLjAwMDwvdGQ+DQogICAgPHRkIGNsYXNzPSJ0Zy0wcGt5Ij48L3RkPg0KICAgIDx0ZCBjbGFzcz0idGctMHBreSI+MC4wMDA8L3RkPg0KICA8L3RyPg0KICA8dHI+DQogICAgPHRkIGNsYXNzPSJ0Zy0wcGt5Ij5QcmljZTwvdGQ+DQogICAgPHRkIGNsYXNzPSJ0Zy0wcGt5Ij4xMDAgZXVybzwvdGQ+DQogICAgPHRkIGNsYXNzPSJ0Zy0wcGt5Ij4xNi41Mzg8L3RkPg0KICAgIDx0ZCBjbGFzcz0idGctMHBreSI+Mi4wMEUtMTY8L3RkPg0KICAgIDx0ZCBjbGFzcz0idGctMHBreSI+MTYuNTM4PC90ZD4NCiAgPC90cj4NCiAgPHRyPg0KICAgIDx0ZCBjbGFzcz0idGctMHBreSI+PC90ZD4NCiAgICA8dGQgY2xhc3M9InRnLTBwa3kiPjIwMCBldXJvPC90ZD4NCiAgICA8dGQgY2xhc3M9InRnLTBwa3kiPjYuMjg2PC90ZD4NCiAgICA8dGQgY2xhc3M9InRnLTBwa3kiPjEuOTJFLTA1PC90ZD4NCiAgICA8dGQgY2xhc3M9InRnLTBwa3kiPjYuMjg2PC90ZD4NCiAgPC90cj4NCiAgPHRyPg0KICAgIDx0ZCBjbGFzcz0idGctMHBreSI+PC90ZD4NCiAgICA8dGQgY2xhc3M9InRnLTBwa3kiPjMwMCBldXJvPC90ZD4NCiAgICA8dGQgY2xhc3M9InRnLTBwa3kiPjAuMDAwPC90ZD4NCiAgICA8dGQgY2xhc3M9InRnLTBwa3kiPjwvdGQ+DQogICAgPHRkIGNsYXNzPSJ0Zy0wcGt5Ij4wLjAwMDwvdGQ+DQogIDwvdHI+DQo8L3Rib2R5Pg0KPC90YWJsZT4NCg0KIyBNYWtpbmcgVXNlIG9mIHRoZSBSZXN1bHRzDQoNCkdpdmVuIHRoZSBwYXJ0d29ydGhzLCB3ZSBjYW4gdXNlIHRoZW0gdG8gZ2VuZXJhdGUgc29tZSBpbnNpZ2h0cyBpbnRvIGNvbnN1bWVycy4gSGVyZSwgd2UgZm9jdXMgb24gdGhyZWUgYXBwbGljYXRpb25zOiANCg0KKiBDYWxjdWxhdGluZyB0aGUgaW1wb3J0YW5jZSBvZiBhdHRyaWJ1dGVzOyANCiogQ2hlY2tpbmcgdGhlIG1vc3QgcHJlZmVycmVkIHByb2R1Y3RzOyANCiogQ29tcGFyaW5nIHByb2R1Y3QgaWRlYXM7IA0KDQojIyBDYWxjdWxhdGluZyB0aGUgaW1wb3J0YW5jZSBvZiBhdHRyaWJ1dGVzDQoNClRvIGNhbGN1bGF0ZSB0aGUgaW1wb3J0YW5jZSBvZiBhbiBhdHRyaWJ1dGUsIHdlIGZpcnN0IGxvb2sgYXQgdGhlIHBhcnR3b3J0aHMgb2YgYWxsIHRoZSBsZXZlbHMgb2YgdGhlIGF0dHJpYnV0ZS4gVGhlbiwgd2UgZmluZCB0aGUgaGlnaGVzdCBhbmQgbG93ZXN0IGxldmVscyBhbmQgZGlmZmVyZW5jZSB0aGVtLiANCiQkIGltcG9ydGFuY2UgPSBtYXgocGFydHdvcnRoKSAtIG1pbihwYXJ0d29ydGgpICQkDQpGb2xsb3dpbmcgdGhlIGVxdWF0aW9uLCB3ZSBoYXZlOiANCg0KKiBJbXBvcnRhbmNlIG9mIE1lbW9yeSBGb3JtYXQgPSAwIC0gMCA9IDANCiogSW1wb3J0YW5jZSBvZiBMZW5zID0gMCAtICgtOS45NTcpID0gOS45NTcNCiogSW1wb3J0YW5jZSBvZiBQcmljZSA9IDE2LjUzOCAtIDAgPSAxNi41MzgNCg0KV2UgY2FuIGFsc28gbm9ybWFsaXplIHRoZSBpbXBvcnRhbmNlIGZvciByZXBvcnRpbmcgcHVycG9zZXMuIFdpdGggdGhlIHJlbGF0aXZlIGltcG9ydGFuY2UsIG91ciBjbGllbnRzIGNhbiByZWFkIHJlc3VsdHMgbXVjaCBtb3JlIGVhc2lseS4gVG8gZG8gdGhlIG5vcm1hbGl6YXRpb24sIHdlIGRpdmlkZSBlYWNoIGltcG9ydGFuY2UgYnkgdGhlIHN1bSBvZiBhbGwgaW1wb3J0YW5jZS4gDQoNCiQkDQpNZW1vcnlcLFwsRm9ybWF0PVxmcmFjezB9e1xsZWZ0KCAwKzkuOTU3KzE2LjUzOCBccmlnaHQpfT0wDQpcXA0KTGVucz1cZnJhY3s5Ljk1N317XGxlZnQoIDArOS45NTcrMTYuNTM4IFxyaWdodCl9PTAuMzc2DQpcXA0KUHJpY2U9XGZyYWN7MTYuNTM4fXtcbGVmdCggMCs5Ljk1NysxNi41MzggXHJpZ2h0KX09MC42MjQNCiQkDQoNCiMjIE9idGFpbmluZyB0aGUgbW9zdCBwcmVmZXJyZWQgcHJvZHVjdCBwcm9maWxlDQoNClRvIHNlZSB3aGljaCBwcm9kdWN0IHByb2ZpbGUgY29uc3VtZXJzIGxpa2UgdGhlIG1vc3QsIHdlIGp1c3QgY29tYmluZSBhbGwgdGhlIGhpZ2hlc3QgbGV2ZWxzLiBGb3IgYExlbnNgLCBpdCdzIGBHbGFzcyA4eCBab29tYC4gRm9yIGBQcmljZWAsIGl0J3MgYDEwMCBldXJvYC4gRm9yIGBNZW1vcnkgRm9ybWF0YCwgYWxsIHRoZSBsZXZlbHMgaGF2ZSB0aGUgc2FtZSBwYXJ0d29ydGggKGFsbCB6ZXJvcykuIFRoaXMgbWVhbnMgY29uc3VtZXJzIGRvIG5vdCBjYXJlIGFib3V0IHdoaWNoIG1lbW9yeSBmb3JtYXQgdG8gaW5jbHVkZSwgYW5kIHRoZSBjb21wYW55IGNhbiBkZWNpZGUgd2hpY2hldmVyIG1lbW9yeSBmb3JtYXQgd2l0aG91dCBpbmZsdWVuY2luZyBjb25zdW1lcnMnIHByZWZlcmVuY2VzLiANCg0KIyMgQ29tcGFyaW5nIHByb2R1Y3QgaWRlYXMNCg0KSW4gcmVhbCByZXNlYXJjaCBwcm9qZWN0cywgeW91IGFyZSBvZnRlbiBhc2tlZCBieSB5b3VyIGNsaWVudHMgdG8gY29tcGFyZSBzb21lIHByb2R1Y3QgcHJvZmlsZXMuIFRoZXNlIHByb2ZpbGVzIGFyZSBwcm9iYWJseSAiZ29vZCBjYW5kaWRhdGVzIiBmcm9tIHdpdGhpbiB0aGUgY29tcGFueS4gRm9yIGV4YW1wbGUsIHN1cHBvc2UgeW91ciBjbGllbnQgYXNrcyB5b3UgdG8gY29tcGFyZSB0aGUgZm9sbG93aW5nIHR3byBwcm9kdWN0IGlkZWFzOiANCg0KKiBDYW1lcmEgQTogU0QgY2FyZCwgUGxhc3RpYyA0eCBab29tIGFuZCBwcmljZWQgYXQgMTAwIGV1cm8uIA0KKiBDYW1lcmEgQjogTWVtb3J5IFN0aWNrLCBQbGFzdGljIDh4IFpvb20gYW5kIHByaWNlZCBhdCAyMDAgZXVyby4gDQoNClRvIGNvbXBhcmUgdGhlIHR3byBwcm9kdWN0cywgeW91IGp1c3QgbmVlZCB0byBhZGQgdXAgdGhlIHBhcnR3b3J0aHMgb2YgdGhlIGxldmVscyBvZiB0aGUgcHJvZHVjdHMuIA0KDQoqIEZvciBDYW1lcmEgQSwgd2UgaGF2ZSAkMCDiiJIgOS45NTcgKzE2LjUzOCA9IDYuNTgxJC4NCiogRm9yIENhbWVyYSBCLCB3ZSBoYXZlICQwIOKIkiAzLjc5OSArIDYuMjg2ID0gMi40ODckLiANCg0KRnJvbSB0aGUgY2FsY3VsYXRpb24sIENhbWVyYSBBIGlzIG1vcmUgcHJlZmVycmVkIGJ5IGNvbnN1bWVycy4gDQoNCiMgRm9yIFIgTG92ZXJzOiBSIENvZGVzIHRvIE9idGFpbiBQYXJ0d29ydGhzIGFuZCBNYWtlIFVzZSBvZiBSZXN1bHRzIChpZ25vcmUgdGhpcyBpZiB5b3UgYXJlIG5vdCBmYW1pbGlhciB3aXRoIFIpDQoNCkZpcnN0LCB3ZSBjcmVhdGUgdGhyZWUgdmVjdG9ycyBmb3IgdGhyZWUgYXR0cmlidXRlcyB3aXRoIG5hbWVzLiANCg0KYGBge3J9DQpNZW1vcnlfRm9ybWF0IDwtIHNldE5hbWVzKHJlcCgwLDMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMoY2FtZXJhJG1lbW9yeV9mb3JtYXQpKQ0KTGVucyA8LSBzZXROYW1lcyhyZXAoMCwzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzKGNhbWVyYSRsZW5zKSkNClByaWNlIDwtIHNldE5hbWVzKHJlcCgwLDMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMoY2FtZXJhJHByaWNlKSkNCmBgYA0KDQpXZSBuZXh0IG9idGFpbiB0aGUgY29lZmZpY2llbnRzIGZyb20gdGhlIGVzdGltYXRpb24gcmVzdWx0cyBhbmQgdHJhbnNmb3JtIGluc2lnbmlmaWNhbnQgY29lZmZpY2llbnRzIHRvIHplcm9zIGJ5IGNoZWNraW5nIGlmIHAtdmFsdWVzIGFyZSBsYXJnZXIgdGhhbiAwLjA1LiANCg0KYGBge3J9DQojIGdldHRpbmcgdGhlIGNvZWZmaWNpZW50cyB0YWJsZQ0KcmVzdWx0cyA8LSBzdW1tYXJ5KG1kbCkkY29lZmZpY2llbnRzDQpjb2VmZmljaWVudHMgPC0gcmVzdWx0c1stMSwxXSoocmVzdWx0c1stMSw0XTwwLjA1KQ0KDQojIHJlc2hhcGUgaW50byBhIG1hdHJpeA0KY29lZmZpY2llbnRzIDwtIG1hdHJpeChjb2VmZmljaWVudHMsIG5yb3cgPSAyLCBuY29sID0gMykNCmBgYA0KDQpXZSBuZXh0IHBhY2sgdGhlIGNvZWZmaWNpZW50cyBpbnRvIHRoZSB0aHJlZSBwYXJ0d29ydGggdmVjdG9ycyBhbmQgY3JlYXRlIGEgbGlzdCBjYWxsZWQgcGFydHdvcnRocyB0byBzdG9yZSBhbGwgcGFydHdvcnRocyB2YWx1ZXMuICANCg0KYGBge3J9DQpNZW1vcnlfRm9ybWF0WzI6M10gPC0gY29lZmZpY2llbnRzWywxXQ0KTGVuc1syOjNdIDwtIGNvZWZmaWNpZW50c1ssMl0NClByaWNlWzI6M10gPC0gY29lZmZpY2llbnRzWywzXQ0KDQpwYXJ0d29ydGhzIDwtIGxpc3QoTWVtb3J5X0Zvcm1hdCA9IE1lbW9yeV9Gb3JtYXQsDQogICAgICAgICAgICAgICAgICAgTGVucyA9IExlbnMsDQogICAgICAgICAgICAgICAgICAgUHJpY2UgPSBQcmljZSkNCnBhcnR3b3J0aHMNCmBgYA0KDQpHaXZlbiB0aGUgcGFydHdvcnRocyB0YWJsZSwgd2UgdGhlbiBjYWxjdWxhdGUgdGhlIGltcG9ydGFuY2Ugb2YgZGlmZmVyZW50IGF0dHJpYnV0ZXMgYW5kIHRoZSByZWxhdGl2ZSBpbXBvcnRhbmNlLiANCg0KYGBge3J9DQppbXBvcnRhbmNlIDwtIHVubGlzdChsYXBwbHkocGFydHdvcnRocywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbih4KXttYXgoeCktbWluKHgpfSkpDQppbXBvcnRhbmNlDQoNCnJlbGF0aXZlX2ltcG9ydGFuY2UgPC0gaW1wb3J0YW5jZS9zdW0oaW1wb3J0YW5jZSkNCnJlbGF0aXZlX2ltcG9ydGFuY2UNCmBgYA0KDQpUaGUgbW9zdCBwcmVmZXJyZWQgcHJvZHVjdHMgYXJlIHRoZSBjb21iaW5hdGlvbiBvZiBhbGwgaGlnaGVzdCBsZXZlbHMuIA0KDQpgYGB7cn0NCm1vc3RfcHJlZmVycmVkIDwtIGxhcHBseShwYXJ0d29ydGhzLA0KICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKHgpe3doaWNoKHg9PW1heCh4KSxhcnIuaW5kID0gVCl9KQ0KbW9zdF9wcmVmZXJyZWQNCmBgYA0KDQpMYXN0bHksIHdlIGNvbXBhcmUgdGhlIHR3byBoeXBvdGhldGljYWwgcHJvZHVjdCBwcm9maWxlczogQSB2cy4gQi4gDQoNCiogQ2FtZXJhIEE6IFNEIGNhcmQsIFBsYXN0aWMgNHggWm9vbSBhbmQgcHJpY2VkIGF0IDEwMCBldXJvLiANCiogQ2FtZXJhIEI6IE1lbW9yeSBTdGljaywgUGxhc3RpYyA4eCBab29tIGFuZCBwcmljZWQgYXQgMjAwIGV1cm8uIA0KDQpgYGB7cn0NClV0aWxpdHlfQSA8LSBwYXJ0d29ydGhzJE1lbW9yeV9Gb3JtYXRbMl0gKw0KICBwYXJ0d29ydGhzJExlbnNbM10gKyANCiAgcGFydHdvcnRocyRQcmljZVsyXQ0Kc2V0TmFtZXMoVXRpbGl0eV9BLCJVdGlsaXR5X0EiKQ0KDQpVdGlsaXR5X0IgPC0gcGFydHdvcnRocyRNZW1vcnlfRm9ybWF0WzFdICsNCiAgcGFydHdvcnRocyRMZW5zWzJdICsgDQogIHBhcnR3b3J0aHMkUHJpY2VbM10NCnNldE5hbWVzKFV0aWxpdHlfQiwiVXRpbGl0eV9CIikNCmBgYA0KDQoNCg0KDQoNCg==