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.

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:
- A distance matrix as explained above.
- 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.
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.
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=