In this tutorial, we will use the multi-dimensional scaling to learn the underlying attributes of toothpaste brands. The data can be loaded from the MSR package.

# load the MSR package
library(MSR)

# load the data 
data("dist_toothpaste")
dist_toothpaste
##            AquaFresh Crest Colgate Aim Gleem PlusWhite UltraBrite CloseUp
## AquaFresh          0     3       2   6     6         2          6       6
## Crest              3     0       4   5     6         5          6       6
## Colgate            2     1       0   6     7         5          2       4
## Aim                4     2       2   0     1         6          4       3
## Gleem              6     5       4   3     0         6          4       4
## PlusWhite          5     5       4   4     3         0          6       5
## UltraBrite         6     6       6   5     3         3          0       6
## CloseUp            6     6       6   6     2         3          2       0
## Pepsodent          6     6       6   6     2         2          1       2
## Sensodyne          7     6       4   6     4         5          5       4
##            Pepsodent Sensodyne
## AquaFresh          6         3
## Crest              6         2
## Colgate            3         5
## Aim                3         2
## Gleem              2         1
## PlusWhite          2         5
## UltraBrite         4         2
## CloseUp            3         4
## Pepsodent          0         5
## Sensodyne          5         0

The dist_toothpaste data frame is a distance matrix between the 10 toothpaste brands. As discussed in class, the distance matrix has three features.

  • The matrix has the same no. of rows and columns (\(10 \times 10\), each column/row being a brand). Each cell is the distance/difference between a pair of brands.
  • The matrix is symmetric, with the distance from, for example, Aqua Fresh to Crest the same as that from Crest to Aqua Fresh.
  • The own distance is zero. For example, there is no or zero difference from Colgate to itself.

1 Step 1: Selecting a MDS Procedure

Throughout our course, we will use the classic MDS procedure. Within R, you can use a function called cmdscale() to run the classic MDS procedure. The function cmdscale takes two key inputs:

  1. A distance matrix as explained above.
  2. The no. of dimensions that you are planning to use.

With our data, we use dist_toothpaste as the distance matrix and the no. of dimensions is specified by k = within the function. For example, if we decide to have 2 dimensions, we can code it like this: cmdscale(dist_toothpaste, k = 2). For more details of the function, please use ?cmdscale in your R command line.

2 Step 2: Determine the No. of Dimensions

To obtain the MDS outcome, you must specify the no. of dimensions. Like in Cluster Analysis, we will use the Elbow criterion as the statistical basis to determine the no. of dimensions. To apply the Elbow criterion, we must compare the statistical performance of MDS under different no. of dimensions.

As one principle of statistical analyses, we always minimize the information loss. In MDS, the observation is the distance matrix that is obtained by the aggregating the responses of the stated differences from many consumers. The prediction from MDS is the distance matrix that is calculated based on the dimensions/attributes. Given the observed and predicted distance matrix, we use a criterion called STRESS (standardized residual sum of square). The smaller the STRESS, the smaller the residual sum of square, the less information loss, and the better the MDS.

With the STESS calculated for different no. of dimensions, we can create an plot like Elbow plot to determine the no. of dimensions. This plot is called a scree plot in MDS. The X-axis of the plot is different no. of dimensions. As a rule of thumb, we usually set the max no. to a small value less than 10. So, we have the no. of dimensions equal to \(1, 2, 3, \cdots, 9\) etc. The Y-axis of the scree plot represents the STRESS values at different no. of dimensions.

For our practice, you can use the function scree_plot that is provided to you in the MSR package. The function scree_plot takes one input: the distance matrix. It produces a scree plot for you.

scree_plot(dist_toothpaste)

From the scree plot, we can determine the no. of dimensions by applying the Elbow criterion. A closer look at the scree plot shows that at no. of dimensions \(2\), we have the elbow point. This is because, we have a large decrease in STESS \(1 \rightarrow 2\), and a small decrease in STESS \(2 \rightarrow 3\).

Note that, in practice, we also use prior knowledge and understanding of brands to help us determine the no. of dimensions. The Elbow criterion is the statistical basis, but the practical usefulness of your choice always matters the most.

3 Step 3: Interpreting the Dimensions

With the no. of dimensions determined, we first run the MDS again to obtain the dimensions. Within R, we run the cmdscale with the no. of dimensions set to \(2\), the elbow point.

dim_toothpaste <- cmdscale(dist_toothpaste, k = 2)

# coerce dim_toothpaste into a data frame
# we can use as.data.frame function
# for more info., run "?as.data.frame" in your R command line
dim_toothpaste <- as.data.frame(dim_toothpaste)
dim_toothpaste
##                    V1         V2
## AquaFresh  -2.9981784 -1.0494401
## Crest      -3.1134074 -0.8771502
## Colgate    -2.7490241 -0.2234601
## Aim        -0.7030305 -2.3432308
## Gleem       1.7206795 -1.3680642
## PlusWhite   1.1223830 -2.2401590
## UltraBrite  2.4878988 -1.4446344
## CloseUp     2.8602529  0.2058835
## Pepsodent   2.7463213 -0.6949752
## Sensodyne   0.9399701  1.7481112

In the data, the variables V1-V2 represent the dimensions or underlying attributes of the toothpaste brands. Next, we try to interpret the dimensions and find out more what these underlying attributes are. As discussed in class, the interpretation always requires some extra information. For example, knowledge about the features of the brands. In practice, you may also do extra research, qualitative and/or quantitative, to find out more info.

For easy interpretation, we oftentimes produce the perceptual map as “visual aids”. To do this, you are given a function called perceptual_map in the MSR package. The function produces an 2D (X-Y) plot of two dimensions. You must specify two inputs:

  • A data frame of the dimensions of the brands (e.g., dim_toothpaste).
  • A numeric vector of which two dimensions to plot or which columns of the dimensions data frame. For example, if you want to plot Dimension 1 and 2 in dim_toothpaste, you input a vector of two values c(1,2).

Next, we will produce a perceptual map with Dimension 1 and 2, and discuss how to interpret the two dimensions with the perceptual map.

# To plot the perceptual map between Dimension 1 and 2
# we use the data frame of dimensions "dim_toothpaste"
# we also specify Dimension 1 and 2 with a vector "c(1,2)"
perceptual_map(dim_toothpaste, c(1,2))

From the perceptual map, we want to detect some patterns. For example, we can observe that Sensodyne is the brand that is highest in Dimension 2. So, Dimension 2 may be something unique about Sensodyne. The understanding of the uniqueness of Sensodyne comes from you, as brand managers. For example, if, as a brand manager, you already know what makes Sensodyne unique is the emphasis on “for sensitive teeth”. From this understanding, you may conclude that Dimension 2 is “for sensitive teeth”. By the same logic, CloseUp and Pepsodent are the two highest brands in Dimension 1. Then, you look for what makes these two brands distinctive from other brands. If, say, as a brand manager, you know that these two brands emphasize “omni-protection”, you can interpret Dimension 1 as “omni-protection”.

In practice, it may not be sufficient to rely only on your expertise as a brand manager. We either collect addition data during the MDS studies or carry out more research (e.g., focus groups or in-depth interview with expert users).

LS0tDQp0aXRsZTogIkxlY3R1cmUgNiAtIE11bHRpLWRpbWVuc2lvbmFsIFNjYWxpbmciDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgZGZfcHJpbnQ6IGRlZmF1bHQNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgICB0aGVtZTogcmVhZGFibGUNCiAgICB0b2M6IHllcw0KICAgIHRvY19mbG9hdDogDQogICAgICBjb2xsYXBzZWQ6IG5vDQogICAgICBzbW9vdGhfc2Nyb2xsOiBubw0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogIHBkZl9kb2N1bWVudDoNCiAgICB0b2M6IHllcw0KLS0tDQoNCkluIHRoaXMgdHV0b3JpYWwsIHdlIHdpbGwgdXNlIHRoZSBtdWx0aS1kaW1lbnNpb25hbCBzY2FsaW5nIHRvIGxlYXJuIHRoZSB1bmRlcmx5aW5nIGF0dHJpYnV0ZXMgb2YgdG9vdGhwYXN0ZSBicmFuZHMuIFRoZSBkYXRhIGNhbiBiZSBsb2FkZWQgZnJvbSB0aGUgYE1TUmAgcGFja2FnZS4gDQoNCmBgYHtyfQ0KIyBsb2FkIHRoZSBNU1IgcGFja2FnZQ0KbGlicmFyeShNU1IpDQoNCiMgbG9hZCB0aGUgZGF0YSANCmRhdGEoImRpc3RfdG9vdGhwYXN0ZSIpDQpkaXN0X3Rvb3RocGFzdGUNCmBgYA0KDQpUaGUgYGRpc3RfdG9vdGhwYXN0ZWAgZGF0YSBmcmFtZSBpcyBhIGRpc3RhbmNlIG1hdHJpeCBiZXR3ZWVuIHRoZSAxMCB0b290aHBhc3RlIGJyYW5kcy4gQXMgZGlzY3Vzc2VkIGluIGNsYXNzLCB0aGUgZGlzdGFuY2UgbWF0cml4IGhhcyB0aHJlZSBmZWF0dXJlcy4gDQoNCiogVGhlIG1hdHJpeCBoYXMgdGhlIHNhbWUgbm8uIG9mIHJvd3MgYW5kIGNvbHVtbnMgKCQxMCBcdGltZXMgMTAkLCBlYWNoIGNvbHVtbi9yb3cgYmVpbmcgYSBicmFuZCkuIEVhY2ggY2VsbCBpcyB0aGUgZGlzdGFuY2UvZGlmZmVyZW5jZSBiZXR3ZWVuIGEgcGFpciBvZiBicmFuZHMuIA0KKiBUaGUgbWF0cml4IGlzIHN5bW1ldHJpYywgd2l0aCB0aGUgZGlzdGFuY2UgZnJvbSwgZm9yIGV4YW1wbGUsIEFxdWEgRnJlc2ggdG8gQ3Jlc3QgdGhlIHNhbWUgYXMgdGhhdCBmcm9tIENyZXN0IHRvIEFxdWEgRnJlc2guIA0KKiBUaGUgb3duIGRpc3RhbmNlIGlzIHplcm8uIEZvciBleGFtcGxlLCB0aGVyZSBpcyBubyBvciB6ZXJvIGRpZmZlcmVuY2UgZnJvbSBDb2xnYXRlIHRvIGl0c2VsZi4gDQoNCiFbXShkaXN0X21hdHJpeC5qcGcpDQoNCiMgU3RlcCAxOiBTZWxlY3RpbmcgYSBNRFMgUHJvY2VkdXJlDQoNClRocm91Z2hvdXQgb3VyIGNvdXJzZSwgd2Ugd2lsbCB1c2UgdGhlIGNsYXNzaWMgTURTIHByb2NlZHVyZS4gV2l0aGluIFIsIHlvdSBjYW4gdXNlIGEgZnVuY3Rpb24gY2FsbGVkIGBjbWRzY2FsZSgpYCB0byBydW4gdGhlIGNsYXNzaWMgTURTIHByb2NlZHVyZS4gVGhlIGZ1bmN0aW9uIGBjbWRzY2FsZWAgdGFrZXMgdHdvIGtleSBpbnB1dHM6IA0KDQoxLiBBIGRpc3RhbmNlIG1hdHJpeCBhcyBleHBsYWluZWQgYWJvdmUuIA0KMi4gVGhlIG5vLiBvZiBkaW1lbnNpb25zIHRoYXQgeW91IGFyZSBwbGFubmluZyB0byB1c2UuIA0KDQpXaXRoIG91ciBkYXRhLCB3ZSB1c2UgYGRpc3RfdG9vdGhwYXN0ZWAgYXMgdGhlIGRpc3RhbmNlIG1hdHJpeCBhbmQgdGhlIG5vLiBvZiBkaW1lbnNpb25zIGlzIHNwZWNpZmllZCBieSBgayA9IGAgd2l0aGluIHRoZSBmdW5jdGlvbi4gRm9yIGV4YW1wbGUsIGlmIHdlIGRlY2lkZSB0byBoYXZlIDIgZGltZW5zaW9ucywgd2UgY2FuIGNvZGUgaXQgbGlrZSB0aGlzOiBgY21kc2NhbGUoZGlzdF90b290aHBhc3RlLCBrID0gMilgLiBGb3IgbW9yZSBkZXRhaWxzIG9mIHRoZSBmdW5jdGlvbiwgcGxlYXNlIHVzZSBgP2NtZHNjYWxlYCBpbiB5b3VyIFIgY29tbWFuZCBsaW5lLiANCg0KIyBTdGVwIDI6IERldGVybWluZSB0aGUgTm8uIG9mIERpbWVuc2lvbnMNCg0KVG8gb2J0YWluIHRoZSBNRFMgb3V0Y29tZSwgeW91IG11c3Qgc3BlY2lmeSB0aGUgbm8uIG9mIGRpbWVuc2lvbnMuIExpa2UgaW4gQ2x1c3RlciBBbmFseXNpcywgd2Ugd2lsbCB1c2UgdGhlIEVsYm93IGNyaXRlcmlvbiBhcyB0aGUgc3RhdGlzdGljYWwgYmFzaXMgdG8gZGV0ZXJtaW5lIHRoZSBuby4gb2YgZGltZW5zaW9ucy4gVG8gYXBwbHkgdGhlIEVsYm93IGNyaXRlcmlvbiwgd2UgbXVzdCBjb21wYXJlIHRoZSBzdGF0aXN0aWNhbCBwZXJmb3JtYW5jZSBvZiBNRFMgdW5kZXIgZGlmZmVyZW50IG5vLiBvZiBkaW1lbnNpb25zLiANCg0KQXMgb25lIHByaW5jaXBsZSBvZiBzdGF0aXN0aWNhbCBhbmFseXNlcywgd2UgYWx3YXlzICoqbWluaW1pemUgdGhlIGluZm9ybWF0aW9uIGxvc3MqKi4gSW4gTURTLCAqKnRoZSBvYnNlcnZhdGlvbioqIGlzIHRoZSBkaXN0YW5jZSBtYXRyaXggdGhhdCBpcyBvYnRhaW5lZCBieSB0aGUgYWdncmVnYXRpbmcgdGhlIHJlc3BvbnNlcyBvZiB0aGUgc3RhdGVkIGRpZmZlcmVuY2VzIGZyb20gbWFueSBjb25zdW1lcnMuICoqVGhlIHByZWRpY3Rpb24qKiBmcm9tIE1EUyBpcyB0aGUgZGlzdGFuY2UgbWF0cml4IHRoYXQgaXMgY2FsY3VsYXRlZCBiYXNlZCBvbiB0aGUgZGltZW5zaW9ucy9hdHRyaWJ1dGVzLiBHaXZlbiB0aGUgb2JzZXJ2ZWQgYW5kIHByZWRpY3RlZCBkaXN0YW5jZSBtYXRyaXgsIHdlIHVzZSBhIGNyaXRlcmlvbiBjYWxsZWQgU1RSRVNTIChzdGFuZGFyZGl6ZWQgcmVzaWR1YWwgc3VtIG9mIHNxdWFyZSkuIFRoZSBzbWFsbGVyIHRoZSBTVFJFU1MsIHRoZSBzbWFsbGVyIHRoZSByZXNpZHVhbCBzdW0gb2Ygc3F1YXJlLCB0aGUgbGVzcyBpbmZvcm1hdGlvbiBsb3NzLCBhbmQgdGhlIGJldHRlciB0aGUgTURTLg0KDQpXaXRoIHRoZSBTVEVTUyBjYWxjdWxhdGVkIGZvciBkaWZmZXJlbnQgbm8uIG9mIGRpbWVuc2lvbnMsIHdlIGNhbiBjcmVhdGUgYW4gcGxvdCBsaWtlIEVsYm93IHBsb3QgdG8gZGV0ZXJtaW5lIHRoZSBuby4gb2YgZGltZW5zaW9ucy4gVGhpcyBwbG90IGlzIGNhbGxlZCBhIGBzY3JlZSBwbG90YCBpbiBNRFMuIFRoZSBYLWF4aXMgb2YgdGhlIHBsb3QgaXMgZGlmZmVyZW50IG5vLiBvZiBkaW1lbnNpb25zLiBBcyBhIHJ1bGUgb2YgdGh1bWIsIHdlIHVzdWFsbHkgc2V0IHRoZSBtYXggbm8uIHRvIGEgc21hbGwgdmFsdWUgbGVzcyB0aGFuIDEwLiBTbywgd2UgaGF2ZSB0aGUgbm8uIG9mIGRpbWVuc2lvbnMgZXF1YWwgdG8gJDEsIDIsIDMsIFxjZG90cywgOSQgZXRjLiBUaGUgWS1heGlzIG9mIHRoZSBzY3JlZSBwbG90IHJlcHJlc2VudHMgdGhlIFNUUkVTUyB2YWx1ZXMgYXQgZGlmZmVyZW50IG5vLiBvZiBkaW1lbnNpb25zLg0KDQpGb3Igb3VyIHByYWN0aWNlLCB5b3UgY2FuIHVzZSB0aGUgZnVuY3Rpb24gYHNjcmVlX3Bsb3RgIHRoYXQgaXMgcHJvdmlkZWQgdG8geW91IGluIHRoZSBgTVNSYCBwYWNrYWdlLiBUaGUgZnVuY3Rpb24gYHNjcmVlX3Bsb3RgIHRha2VzIG9uZSBpbnB1dDogdGhlIGRpc3RhbmNlIG1hdHJpeC4gSXQgcHJvZHVjZXMgYSBzY3JlZSBwbG90IGZvciB5b3UuDQoNCmBgYHtyfQ0Kc2NyZWVfcGxvdChkaXN0X3Rvb3RocGFzdGUpDQpgYGANCg0KRnJvbSB0aGUgc2NyZWUgcGxvdCwgd2UgY2FuIGRldGVybWluZSB0aGUgbm8uIG9mIGRpbWVuc2lvbnMgYnkgYXBwbHlpbmcgdGhlIEVsYm93IGNyaXRlcmlvbi4gQSBjbG9zZXIgbG9vayBhdCB0aGUgc2NyZWUgcGxvdCBzaG93cyB0aGF0IGF0IG5vLiBvZiBkaW1lbnNpb25zICQyJCwgd2UgaGF2ZSB0aGUgZWxib3cgcG9pbnQuIFRoaXMgaXMgYmVjYXVzZSwgd2UgaGF2ZSBhIGxhcmdlIGRlY3JlYXNlIGluIFNURVNTICQxIFxyaWdodGFycm93IDIkLCBhbmQgYSBzbWFsbCBkZWNyZWFzZSBpbiBTVEVTUyAkMiBccmlnaHRhcnJvdyAzJC4gDQoNCiFbXShzY3JlZV9wbG90LmpwZykNCg0KTm90ZSB0aGF0LCBpbiBwcmFjdGljZSwgd2UgYWxzbyB1c2UgcHJpb3Iga25vd2xlZGdlIGFuZCB1bmRlcnN0YW5kaW5nIG9mIGJyYW5kcyB0byBoZWxwIHVzIGRldGVybWluZSB0aGUgbm8uIG9mIGRpbWVuc2lvbnMuIFRoZSBFbGJvdyBjcml0ZXJpb24gaXMgdGhlIHN0YXRpc3RpY2FsIGJhc2lzLCBidXQgdGhlIHByYWN0aWNhbCB1c2VmdWxuZXNzIG9mIHlvdXIgY2hvaWNlIGFsd2F5cyBtYXR0ZXJzIHRoZSBtb3N0LiANCg0KIyBTdGVwIDM6IEludGVycHJldGluZyB0aGUgRGltZW5zaW9ucw0KDQpXaXRoIHRoZSBuby4gb2YgZGltZW5zaW9ucyBkZXRlcm1pbmVkLCB3ZSBmaXJzdCBydW4gdGhlIE1EUyBhZ2FpbiB0byBvYnRhaW4gdGhlIGRpbWVuc2lvbnMuIFdpdGhpbiBSLCB3ZSBydW4gdGhlIGBjbWRzY2FsZWAgd2l0aCB0aGUgbm8uIG9mIGRpbWVuc2lvbnMgc2V0IHRvICQyJCwgdGhlIGVsYm93IHBvaW50LiANCg0KYGBge3J9DQpkaW1fdG9vdGhwYXN0ZSA8LSBjbWRzY2FsZShkaXN0X3Rvb3RocGFzdGUsIGsgPSAyKQ0KDQojIGNvZXJjZSBkaW1fdG9vdGhwYXN0ZSBpbnRvIGEgZGF0YSBmcmFtZQ0KIyB3ZSBjYW4gdXNlIGFzLmRhdGEuZnJhbWUgZnVuY3Rpb24NCiMgZm9yIG1vcmUgaW5mby4sIHJ1biAiP2FzLmRhdGEuZnJhbWUiIGluIHlvdXIgUiBjb21tYW5kIGxpbmUNCmRpbV90b290aHBhc3RlIDwtIGFzLmRhdGEuZnJhbWUoZGltX3Rvb3RocGFzdGUpDQpkaW1fdG9vdGhwYXN0ZQ0KYGBgDQoNCkluIHRoZSBkYXRhLCB0aGUgdmFyaWFibGVzIGBWMS1WMmAgcmVwcmVzZW50IHRoZSBkaW1lbnNpb25zIG9yIHVuZGVybHlpbmcgYXR0cmlidXRlcyBvZiB0aGUgdG9vdGhwYXN0ZSBicmFuZHMuIE5leHQsIHdlIHRyeSB0byBpbnRlcnByZXQgdGhlIGRpbWVuc2lvbnMgYW5kIGZpbmQgb3V0IG1vcmUgd2hhdCB0aGVzZSB1bmRlcmx5aW5nIGF0dHJpYnV0ZXMgYXJlLiBBcyBkaXNjdXNzZWQgaW4gY2xhc3MsIHRoZSBpbnRlcnByZXRhdGlvbiBhbHdheXMgcmVxdWlyZXMgc29tZSBleHRyYSBpbmZvcm1hdGlvbi4gRm9yIGV4YW1wbGUsIGtub3dsZWRnZSBhYm91dCB0aGUgZmVhdHVyZXMgb2YgdGhlIGJyYW5kcy4gSW4gcHJhY3RpY2UsIHlvdSBtYXkgYWxzbyBkbyBleHRyYSByZXNlYXJjaCwgcXVhbGl0YXRpdmUgYW5kL29yIHF1YW50aXRhdGl2ZSwgdG8gZmluZCBvdXQgbW9yZSBpbmZvLiANCg0KRm9yIGVhc3kgaW50ZXJwcmV0YXRpb24sIHdlIG9mdGVudGltZXMgcHJvZHVjZSB0aGUgcGVyY2VwdHVhbCBtYXAgYXMgInZpc3VhbCBhaWRzIi4gVG8gZG8gdGhpcywgeW91IGFyZSBnaXZlbiBhIGZ1bmN0aW9uIGNhbGxlZCBgcGVyY2VwdHVhbF9tYXBgIGluIHRoZSBgTVNSYCBwYWNrYWdlLiBUaGUgZnVuY3Rpb24gcHJvZHVjZXMgYW4gMkQgKFgtWSkgcGxvdCBvZiB0d28gZGltZW5zaW9ucy4gWW91IG11c3Qgc3BlY2lmeSB0d28gaW5wdXRzOiANCg0KKiBBIGRhdGEgZnJhbWUgb2YgdGhlIGRpbWVuc2lvbnMgb2YgdGhlIGJyYW5kcyAoZS5nLiwgYGRpbV90b290aHBhc3RlYCkuIA0KKiBBIG51bWVyaWMgdmVjdG9yIG9mIHdoaWNoIHR3byBkaW1lbnNpb25zIHRvIHBsb3Qgb3Igd2hpY2ggY29sdW1ucyBvZiB0aGUgZGltZW5zaW9ucyBkYXRhIGZyYW1lLiBGb3IgZXhhbXBsZSwgaWYgeW91IHdhbnQgdG8gcGxvdCBEaW1lbnNpb24gMSBhbmQgMiBpbiBgZGltX3Rvb3RocGFzdGVgLCB5b3UgaW5wdXQgYSB2ZWN0b3Igb2YgdHdvIHZhbHVlcyBgYygxLDIpYC4gIA0KDQpOZXh0LCB3ZSB3aWxsIHByb2R1Y2UgYSBwZXJjZXB0dWFsIG1hcCB3aXRoIERpbWVuc2lvbiAxIGFuZCAyLCBhbmQgZGlzY3VzcyBob3cgdG8gaW50ZXJwcmV0IHRoZSB0d28gZGltZW5zaW9ucyB3aXRoIHRoZSBwZXJjZXB0dWFsIG1hcC4gDQoNCmBgYHtyfQ0KIyBUbyBwbG90IHRoZSBwZXJjZXB0dWFsIG1hcCBiZXR3ZWVuIERpbWVuc2lvbiAxIGFuZCAyDQojIHdlIHVzZSB0aGUgZGF0YSBmcmFtZSBvZiBkaW1lbnNpb25zICJkaW1fdG9vdGhwYXN0ZSINCiMgd2UgYWxzbyBzcGVjaWZ5IERpbWVuc2lvbiAxIGFuZCAyIHdpdGggYSB2ZWN0b3IgImMoMSwyKSINCnBlcmNlcHR1YWxfbWFwKGRpbV90b290aHBhc3RlLCBjKDEsMikpDQoNCmBgYA0KDQpGcm9tIHRoZSBwZXJjZXB0dWFsIG1hcCwgd2Ugd2FudCB0byBkZXRlY3Qgc29tZSBwYXR0ZXJucy4gRm9yIGV4YW1wbGUsIHdlIGNhbiBvYnNlcnZlIHRoYXQgU2Vuc29keW5lIGlzIHRoZSBicmFuZCB0aGF0IGlzIGhpZ2hlc3QgaW4gRGltZW5zaW9uIDIuIFNvLCBEaW1lbnNpb24gMiBtYXkgYmUgc29tZXRoaW5nIHVuaXF1ZSBhYm91dCBTZW5zb2R5bmUuIFRoZSB1bmRlcnN0YW5kaW5nIG9mIHRoZSB1bmlxdWVuZXNzIG9mIFNlbnNvZHluZSBjb21lcyBmcm9tIHlvdSwgYXMgYnJhbmQgbWFuYWdlcnMuIEZvciBleGFtcGxlLCBpZiwgYXMgYSBicmFuZCBtYW5hZ2VyLCB5b3UgYWxyZWFkeSBrbm93IHdoYXQgbWFrZXMgU2Vuc29keW5lIHVuaXF1ZSBpcyB0aGUgZW1waGFzaXMgb24gImZvciBzZW5zaXRpdmUgdGVldGgiLiBGcm9tIHRoaXMgdW5kZXJzdGFuZGluZywgeW91IG1heSBjb25jbHVkZSB0aGF0IERpbWVuc2lvbiAyIGlzICJmb3Igc2Vuc2l0aXZlIHRlZXRoIi4gQnkgdGhlIHNhbWUgbG9naWMsIENsb3NlVXAgYW5kIFBlcHNvZGVudCBhcmUgdGhlIHR3byBoaWdoZXN0IGJyYW5kcyBpbiBEaW1lbnNpb24gMS4gVGhlbiwgeW91IGxvb2sgZm9yIHdoYXQgbWFrZXMgdGhlc2UgdHdvIGJyYW5kcyBkaXN0aW5jdGl2ZSBmcm9tIG90aGVyIGJyYW5kcy4gSWYsIHNheSwgYXMgYSBicmFuZCBtYW5hZ2VyLCB5b3Uga25vdyB0aGF0IHRoZXNlIHR3byBicmFuZHMgZW1waGFzaXplICJvbW5pLXByb3RlY3Rpb24iLCB5b3UgY2FuIGludGVycHJldCBEaW1lbnNpb24gMSBhcyAib21uaS1wcm90ZWN0aW9uIi4gDQoNCkluIHByYWN0aWNlLCBpdCBtYXkgbm90IGJlIHN1ZmZpY2llbnQgdG8gcmVseSBvbmx5IG9uIHlvdXIgZXhwZXJ0aXNlIGFzIGEgYnJhbmQgbWFuYWdlci4gV2UgZWl0aGVyIGNvbGxlY3QgYWRkaXRpb24gZGF0YSBkdXJpbmcgdGhlIE1EUyBzdHVkaWVzIG9yIGNhcnJ5IG91dCBtb3JlIHJlc2VhcmNoIChlLmcuLCBmb2N1cyBncm91cHMgb3IgaW4tZGVwdGggaW50ZXJ2aWV3IHdpdGggZXhwZXJ0IHVzZXJzKS4gDQo=