This is an R Markdown Notebook. When you execute code within the notebook, the results appear beneath the code.

Try executing this chunk by clicking the Run button within the chunk or by placing your cursor inside it and pressing Ctrl+Shift+Enter.

Add a new chunk by clicking the Insert Chunk button on the toolbar or by pressing Ctrl+Alt+I.

When you save the notebook, an HTML file containing the code and output will be saved alongside it (click the Preview button or press Ctrl+Shift+K to preview the HTML file).

List of R colours at: http://www.stat.columbia.edu/~tzheng/files/Rcolor.pdf

Required Libraries

The library we need for this work book is ggplot2 which is required for plotting clustered and stacked bar-plots. This library must be first installed as follows:

  1. Go to the Tools tab and select Install Packages
  2. In the Packages box type ggplot2 and press install
  3. Once installed, call the ggplot2 library as follows
library(ggplot2)

Clustered Bar Charts

In the case of clustered bar-charts it is often helpful to create a separate data file for our table. In the example from lectures we drew a clustered bar chart to represent the results of a customer survey carried out by a mobile phone company regarding five areas of customer experience:

Experience Satisfied Dissatisfied
Support 551 449
Pricing 684 316
Contracts 329 671
Coverage 848 152
Rewards 215 785

We create this table in a standard database system and save the file with a .csv (comma separated values) extension. The file for this particular example, CustomerSurvey.csv, is available on Moodle in the section Data Files. Download this file into the same directory as this R workbook.

We now import the data in the .csv file, which we call Survey, as follows: Run the chunk below as usual, and when the pop-up menu appears select the file CustomerSurvey.csv and press Open

Survey <- read.csv(file.choose())

We display this data frame by running the following chunk

Survey

We now plot this data frame using the functions ggplot(), geom_bar() and scale_fill_manual():

ggplot(data=Survey, aes(x=Experience, y=Frequency)) +   
  geom_bar(aes(fill = Satisfaction), position = "dodge", stat = "identity")+
  scale_fill_manual(values=c("blue", "red"))

Ordering the data

  • We saw during lectures that rearranging the order of the clusters may improve the overall appearance of the bar chart, and in particular it may make the content of data more apparent.

  • We will organise our clusters so they are arranged from highest to lowest levels of customer satisfaction. This means the clusters should be arranged as

    1. Coverage
    2. Pricing
    3. Support
    4. Contracts
    5. Rewards

This is done in R in the cell below:

Survey$Experience <- factor(Survey$Experience, levels = c('Coverage', 'Pricing', 'Support', 'Contracts', 'Rewards'))
Survey
ggplot(data=Survey, aes(x=Experience,y=Frequency)) +   
  geom_bar(aes(fill = Satisfaction), position = "dodge", stat = "identity")+
  scale_fill_manual(values=c("blue", "red"))

  • It is clear, at least in this particular example, that re-ordering the clusters has improved the presentation of the data, and in particular it should be more apparent that levels of customer satisfaction are slightly higher than levels of customer dissatisfaction.

Colouring

  • So far, the bars representing satisfaction/dissatisfaction are coloured in a similar way. This can make it difficult to discern which bar represents which sub-category.

  • A list of colours in R can be found at http://www.stat.columbia.edu/~tzheng/files/Rcolor.pdf

  • To highlight the difference between satisfaction/dissatisfaction we could choose different colours that bear no resemblance to one another.

  • In addition, colours that are occur in nature are found to be more appealing to the viewer. With this in mind, we make the same plot with alternative colors

ggplot(data=Survey, aes(x=Experience,y=Frequency)) +   
  geom_bar(aes(fill = Satisfaction), position = "dodge", stat = "identity")+
  scale_fill_manual(values=c("cadetblue4", "goldenrod"))

Exercise 1

A computer retailer collected data on laptop sales and organise it according to make and chip type, with the following data obtained

Make Intel i3 Intel i5 Intel i7
Apple 5 25 31
Dell 15 21 16
HP 21 28 26
Lenovo 18 32 31

Given this data answer the following

  1. Identify the data type given.

  2. Create a .csv file to tabulate this data.

  3. Create two clustered bar plot from this data file, using different colours in each plot.

  4. Reorder these plots in order of decreasing Intel i3 sales.

  5. Which of these plots conveys the data in the clearest way?

Exercise 2

A company survey asked a sample of 500 employees a series of satisfied/dissatisfied questions in relation to their work in the following areas

  1. Work/Life Balance 2. Remuneration 3. Career Opportunities 4. Job Satisfaction 5. Vacation Time 6. Up-skilling Opportunities

with the following data obtained

Work Feature Satisfied Dissatisfied
Work/Life Balance 398 102
Remuneration 302 198
Career Opportunities 274 226
Job Satisfaction 405 95
Vacation Time 277 233
Up-skilling Opportunities 321 179

Using this data answer the following

  1. Create a .csv file for this data an import it into this work book

  2. Create a clustered bar-plot for this data

  3. Identify the datatype given

  4. Is there any trend obvious from the chart?

Stacked Bar Charts

A stacked bar-chart is another type of bar-chart where we compare data within a given class, and in particular it illustrates how the overall frequency in a given class is decomposed into further sub-categories.

Example 2

A Toyota dealership is taking an inventory of all models present on the lot, and organises its data according to make and age. The ages of the cars are categorised according to pre-2008 and post-2008, with the data given as follows

Model Pre-2008 Post-2008
Auris 8 15
Avensis 11 21
Camry 4 2
Corolla 23 18
Prius 1 4
Yaris 4 12
  1. Import the data from CarInventory.csv available in Workbook Files on Moodle and display the data.
Cars <- read.csv(file.choose())

We display the data frame Cars to ensure all is correct

Cars
  1. Plot the data with high-contrast colours using ggplot.
ggplot(Cars, aes(x=Model,y=Inventory, fill=Year))+
  geom_bar(stat="identity")+
  scale_fill_manual(values=c("dodgerblue","goldenrod1"))

  1. Reorder the plots in order of decreaing Pre-2008 inventory.
Cars$Model <- factor(Cars$Model, levels = c('Corolla', 'Avensis', 'Auris', 'Camry', 'Yaris', 'Prius'))
Cars
  1. Plot the reordered data using the same colouring.
ggplot(Cars, aes(x=Model,y=Inventory, fill=Year))+
  geom_bar(stat="identity")+
  scale_fill_manual(values=c("dodgerblue","goldenrod1"))

  1. Re-plot the ordered bar-chart using different colours. Which of the bar-charts is easier to interpret?
ggplot(Cars, aes(x=Model,y=Inventory, fill=Year))+
  geom_bar(stat="identity")+
  scale_fill_manual(values=c("slategrey","skyblue"))

Exercise 3

A computer retailer sumarises its quarterly sales by computer make and sales point, with the following data collected

Make Online Sales Store Sales Corporate Sales
Apple 210 155 53
Asus 335 278 55
Fujitsu 188 205 75
HP 336 451 125
Lenovo 225 321 144

Using this data answer the following:

  1. Identify the data type given
  2. Construct a .csv file to store this data
  3. Generate a stacked bar chart to represent this data
  4. Re-plot the data in order of decreasing Online Sales
  5. Use a different set of colours to re-plot the ordered bar-chart

Exercise 4

Using the data given in Exercise 1, generate ordered and unordered stacked bar charts to represent this data set.

Exercise 5

Using the data given in Exercise 2, generate ordered and unordered clustered bar chart to represent this data.

Exercise 6

A food producer collects data on its global revenue from one year of sales. It categorises the regions of sales activity as

  1. North America 2. Central & South America 3. Europe, Middle East and Africa (EMEA) 4. Asia 5. Australasia

It categorises its food products according to

  1. Wheat and Dairy 2. Beverages 3. Confectionery 4. Weight Reduction

with the following sales data in millions of euro

Region Wheat and Dairy Beverages Confectionary Weight Reduction
North America 51 152 95 125
South & Central America 71 32 122 75
EMEA 241 111 84 119
Asia 188 94 88 92
Australasia 44 29 74 57

Using this data set answer the following:

  1. Identify the data types given

  2. Generate a .csv file to store this data

  3. Generate a clustered barplot to represent this data

  4. Generate a stacked barplot to represent this data

  5. Which of the bar charts represents this data better?

  6. Re-plot these charts with a different ordering and with different colouring, of your own choice?

LS0tCnRpdGxlOiAiRGF0YSBWaXN1YWxpc2F0aW9uIDIwMTkgLSBBc3NpZ25tZW50IDIiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KClRoaXMgaXMgYW4gW1IgTWFya2Rvd25dKGh0dHA6Ly9ybWFya2Rvd24ucnN0dWRpby5jb20pIE5vdGVib29rLiBXaGVuIHlvdSBleGVjdXRlIGNvZGUgd2l0aGluIHRoZSBub3RlYm9vaywgdGhlIHJlc3VsdHMgYXBwZWFyIGJlbmVhdGggdGhlIGNvZGUuIAoKVHJ5IGV4ZWN1dGluZyB0aGlzIGNodW5rIGJ5IGNsaWNraW5nIHRoZSAqUnVuKiBidXR0b24gd2l0aGluIHRoZSBjaHVuayBvciBieSBwbGFjaW5nIHlvdXIgY3Vyc29yIGluc2lkZSBpdCBhbmQgcHJlc3NpbmcgKkN0cmwrU2hpZnQrRW50ZXIqLiAKCkFkZCBhIG5ldyBjaHVuayBieSBjbGlja2luZyB0aGUgKkluc2VydCBDaHVuayogYnV0dG9uIG9uIHRoZSB0b29sYmFyIG9yIGJ5IHByZXNzaW5nICpDdHJsK0FsdCtJKi4KCldoZW4geW91IHNhdmUgdGhlIG5vdGVib29rLCBhbiBIVE1MIGZpbGUgY29udGFpbmluZyB0aGUgY29kZSBhbmQgb3V0cHV0IHdpbGwgYmUgc2F2ZWQgYWxvbmdzaWRlIGl0IChjbGljayB0aGUgKlByZXZpZXcqIGJ1dHRvbiBvciBwcmVzcyAqQ3RybCtTaGlmdCtLKiB0byBwcmV2aWV3IHRoZSBIVE1MIGZpbGUpLgoKTGlzdCBvZiBfX1JfXyBjb2xvdXJzIGF0OgogaHR0cDovL3d3dy5zdGF0LmNvbHVtYmlhLmVkdS9+dHpoZW5nL2ZpbGVzL1Jjb2xvci5wZGYKIAojIyBSZXF1aXJlZCBMaWJyYXJpZXMKVGhlIGxpYnJhcnkgd2UgbmVlZCBmb3IgdGhpcyB3b3JrIGJvb2sgaXMgX19nZ3Bsb3QyX18gd2hpY2ggaXMgcmVxdWlyZWQgZm9yIHBsb3R0aW5nIGNsdXN0ZXJlZCBhbmQgc3RhY2tlZCBiYXItcGxvdHMuIFRoaXMgbGlicmFyeSBtdXN0IGJlIGZpcnN0IGluc3RhbGxlZCBhcyBmb2xsb3dzOgoKMS4gR28gdG8gdGhlIF9fVG9vbHNfXyB0YWIgYW5kIHNlbGVjdCBfSW5zdGFsbCBQYWNrYWdlc18KMi4gSW4gdGhlIF9QYWNrYWdlc18gYm94IHR5cGUgX19nZ3Bsb3QyX18gYW5kIHByZXNzIGluc3RhbGwKMy4gT25jZSBpbnN0YWxsZWQsIGNhbGwgdGhlIF9fZ2dwbG90Ml9fIGxpYnJhcnkgYXMgZm9sbG93cwogCmBgYHtyfQpsaWJyYXJ5KGdncGxvdDIpCmBgYAoKIyBDbHVzdGVyZWQgQmFyIENoYXJ0cwpJbiB0aGUgY2FzZSBvZiBjbHVzdGVyZWQgYmFyLWNoYXJ0cyBpdCBpcyBvZnRlbiBoZWxwZnVsIHRvIGNyZWF0ZSBhIHNlcGFyYXRlIGRhdGEgZmlsZSBmb3Igb3VyIHRhYmxlLiBJbiB0aGUgZXhhbXBsZSBmcm9tIGxlY3R1cmVzIHdlIGRyZXcgYSBjbHVzdGVyZWQgYmFyIGNoYXJ0IHRvIHJlcHJlc2VudCB0aGUgcmVzdWx0cyBvZiBhIGN1c3RvbWVyIHN1cnZleSBjYXJyaWVkIG91dCBieSBhIG1vYmlsZSBwaG9uZSBjb21wYW55IHJlZ2FyZGluZyBmaXZlIGFyZWFzIG9mIGN1c3RvbWVyIGV4cGVyaWVuY2U6CgogIHwgX19FeHBlcmllbmNlX18gfCBfX1NhdGlzZmllZF9fIHwgX19EaXNzYXRpc2ZpZWRfXyB8CiAgfC0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLXwKICB8ICAgICBTdXBwb3J0ICAgIHwgICAgNTUxICAgICAgICB8ICAgICAgNDQ5ICAgICAgICAgfAogIHwgICAgIFByaWNpbmcgICAgfCAgICA2ODQgICAgICAgIHwgICAgICAzMTYgICAgICAgICB8CiAgfCAgICAgQ29udHJhY3RzICB8ICAgIDMyOSAgICAgICAgfCAgICAgIDY3MSAgICAgICAgIHwKICB8ICAgICBDb3ZlcmFnZSAgIHwgICAgODQ4ICAgICAgICB8ICAgICAgMTUyICAgICAgICAgfAogIHwgICAgIFJld2FyZHMgICAgfCAgICAyMTUgICAgICAgIHwgICAgICA3ODUgICAgICAgICB8CiAgCldlIGNyZWF0ZSB0aGlzIHRhYmxlIGluIGEgc3RhbmRhcmQgZGF0YWJhc2Ugc3lzdGVtIGFuZCBzYXZlIHRoZSBmaWxlIHdpdGggYSBfXy5jc3ZfXyAoY29tbWEgc2VwYXJhdGVkIHZhbHVlcykgZXh0ZW5zaW9uLiBUaGUgZmlsZSBmb3IgdGhpcyBwYXJ0aWN1bGFyIGV4YW1wbGUsIF9fQ3VzdG9tZXJTdXJ2ZXkuY3N2X18sIGlzIGF2YWlsYWJsZSBvbiBNb29kbGUgaW4gdGhlIHNlY3Rpb24gX0RhdGEgRmlsZXNfLiBEb3dubG9hZCB0aGlzIGZpbGUgaW50byB0aGUgc2FtZSBkaXJlY3RvcnkgYXMgdGhpcyBfX1JfXyB3b3JrYm9vay4gIAogIAoKV2Ugbm93IGltcG9ydCB0aGUgZGF0YSBpbiB0aGUgX18uY3N2X18gZmlsZSwgd2hpY2ggd2UgY2FsbCBfX1N1cnZleV9fLCBhcyBmb2xsb3dzOiBSdW4gdGhlIGNodW5rIGJlbG93IGFzIHVzdWFsLCBhbmQgd2hlbiB0aGUgcG9wLXVwIG1lbnUgYXBwZWFycyBzZWxlY3QgdGhlIGZpbGUgX19DdXN0b21lclN1cnZleS5jc3ZfXyBhbmQgcHJlc3MgX19PcGVuX18KYGBge3J9ClN1cnZleSA8LSByZWFkLmNzdihmaWxlLmNob29zZSgpKQpgYGAKV2UgZGlzcGxheSB0aGlzIGRhdGEgZnJhbWUgYnkgcnVubmluZyB0aGUgZm9sbG93aW5nIGNodW5rCmBgYHtyfQpTdXJ2ZXkKYGBgCldlIG5vdyBwbG90IHRoaXMgZGF0YSBmcmFtZSB1c2luZyB0aGUgZnVuY3Rpb25zIF9fZ2dwbG90KClfXywgX19nZW9tX2JhcigpX18gYW5kIF9fc2NhbGVfZmlsbF9tYW51YWwoKV9fOgoKCgoqIFdlIHVzZSBfX2dncGxvdCgpX18gdG8gcGxvdCB0aGUgZGF0YSBzdHJ1Y3R1cmUgX19DdXN0RGF0YV9fLiBUaGUgYXJndW1lbnQgX19hZXMoKV9fIChmb3IgYWVzdGhldGljcykgaW5mb3JtcyBfX2dncGxvdF9fIHRvIHVzZSB0aGUgX19FeHBlcmllbmNlX18gY29sdW1uIGFzIHRoZSB4LWF4aXMgZGF0YSBvZiB0aGUgcGxvdCBhbmQgdG8gdXNlIHRoZSBfX0ZyZXF1ZW5jeV9fIGNvbHVtbiBhcyB0aGUgeS1heGlzIGRhdGEgb2YgdGhlIHBsb3QuCgoKKiBXZSB1c2UgX19nZW9tX2JhcigpX18gdG8gaW5kaWNhdGUgd2Ugd2FudCB0aGUgZ2VvbWV0cnkgb2YgdGhlIHBsb3QgdG8gYmUgYmFycy4gVGhlIGFyZ3VtZW50IF9fYWVzKGZpbGw9U2F0aXNmYWNpb24pX18gaW5kaWNhdGVzIHRoYXQgdGhlIGJhcnMgc2hvdWxkIGJlIGZpbGxlZCBhY2NvcmRpbmcgdG8gdGhlIF9fU2F0aXNmYWN0aW9uX18gdmFsdWVzIGZyb20gdGhlIGRhdGEgZnJhbWUuIFRoZSBhcmd1bWVudCBfX3Bvc2l0aW9uID0gImRvZGdlIl9fIGVuc3VyZXMgdGhlIGNsdXN0ZXJlZCBiYXJzIGRvIG5vdCBvdmVybGFwLiBUaGUgYXJndW1lbnQgX19zdGF0PSJpZGVudGl0eSJfXyBlbnN1cmVzIHRoZSB5LWRhdGEgaXMgdGFrZW4gZnJvbSB0aGUgZGF0YSBzZXQuCgoqIFRoZSBfX3NjYWxlX2ZpbGxfbWFudWFsKClfXyBmdW5jdGlvbiBhbGxvd3MgdXMgdG8gY2hvb3NlIHRoZSBjb2xvdXJzIG9mIHRoZSBiYXJzCgpgYGB7cn0KZ2dwbG90KGRhdGE9U3VydmV5LCBhZXMoeD1FeHBlcmllbmNlLCB5PUZyZXF1ZW5jeSkpICsgICAKICBnZW9tX2JhcihhZXMoZmlsbCA9IFNhdGlzZmFjdGlvbiksIHBvc2l0aW9uID0gImRvZGdlIiwgc3RhdCA9ICJpZGVudGl0eSIpKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCJibHVlIiwgInJlZCIpKQpgYGAKCiMjIE9yZGVyaW5nIHRoZSBkYXRhCgoqIFdlIHNhdyBkdXJpbmcgbGVjdHVyZXMgdGhhdCByZWFycmFuZ2luZyB0aGUgb3JkZXIgb2YgdGhlIGNsdXN0ZXJzIG1heSBpbXByb3ZlIHRoZSBvdmVyYWxsIGFwcGVhcmFuY2Ugb2YgdGhlIGJhciBjaGFydCwgYW5kIGluIHBhcnRpY3VsYXIgaXQgbWF5IG1ha2UgdGhlIGNvbnRlbnQgb2YgZGF0YSBtb3JlIGFwcGFyZW50LgoKKiBXZSB3aWxsIG9yZ2FuaXNlIG91ciBjbHVzdGVycyBzbyB0aGV5IGFyZSBhcnJhbmdlZCBmcm9tIGhpZ2hlc3QgdG8gbG93ZXN0IGxldmVscyBvZiBjdXN0b21lciBzYXRpc2ZhY3Rpb24uIFRoaXMgbWVhbnMgdGhlIGNsdXN0ZXJzIHNob3VsZCBiZSBhcnJhbmdlZCBhcwoKICAgIDEuIENvdmVyYWdlCiAgICAyLiBQcmljaW5nCiAgICAzLiBTdXBwb3J0CiAgICA0LiBDb250cmFjdHMKICAgIDUuIFJld2FyZHMKClRoaXMgaXMgZG9uZSBpbiBfX1JfXyBpbiB0aGUgY2VsbCBiZWxvdzoKYGBge3J9ClN1cnZleSRFeHBlcmllbmNlIDwtIGZhY3RvcihTdXJ2ZXkkRXhwZXJpZW5jZSwgbGV2ZWxzID0gYygnQ292ZXJhZ2UnLCAnUHJpY2luZycsICdTdXBwb3J0JywgJ0NvbnRyYWN0cycsICdSZXdhcmRzJykpClN1cnZleQpgYGAKCmBgYHtyfQpnZ3Bsb3QoZGF0YT1TdXJ2ZXksIGFlcyh4PUV4cGVyaWVuY2UseT1GcmVxdWVuY3kpKSArICAgCiAgZ2VvbV9iYXIoYWVzKGZpbGwgPSBTYXRpc2ZhY3Rpb24pLCBwb3NpdGlvbiA9ICJkb2RnZSIsIHN0YXQgPSAiaWRlbnRpdHkiKSsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiYmx1ZSIsICJyZWQiKSkKYGBgCiogSXQgaXMgY2xlYXIsIGF0IGxlYXN0IGluIHRoaXMgcGFydGljdWxhciBleGFtcGxlLCB0aGF0IHJlLW9yZGVyaW5nIHRoZSBjbHVzdGVycyBoYXMgaW1wcm92ZWQgdGhlIHByZXNlbnRhdGlvbiBvZiB0aGUgZGF0YSwgYW5kIGluIHBhcnRpY3VsYXIgaXQgc2hvdWxkIGJlIG1vcmUgYXBwYXJlbnQgdGhhdCBsZXZlbHMgb2YgY3VzdG9tZXIgc2F0aXNmYWN0aW9uIGFyZSBzbGlnaHRseSBoaWdoZXIgdGhhbiBsZXZlbHMgb2YgY3VzdG9tZXIgZGlzc2F0aXNmYWN0aW9uLgoKCgojIyMgQ29sb3VyaW5nCgoqIFNvIGZhciwgdGhlIGJhcnMgcmVwcmVzZW50aW5nIF9fc2F0aXNmYWN0aW9uL2Rpc3NhdGlzZmFjdGlvbl9fIGFyZSBjb2xvdXJlZCBpbiBhIHNpbWlsYXIgd2F5LiBUaGlzIGNhbiBtYWtlIGl0IGRpZmZpY3VsdCB0byBkaXNjZXJuIHdoaWNoIGJhciByZXByZXNlbnRzIHdoaWNoIHN1Yi1jYXRlZ29yeS4KCiogQSBsaXN0IG9mIGNvbG91cnMgaW4gX19SX18gY2FuIGJlIGZvdW5kIGF0ICBodHRwOi8vd3d3LnN0YXQuY29sdW1iaWEuZWR1L350emhlbmcvZmlsZXMvUmNvbG9yLnBkZgoKKiBUbyBoaWdobGlnaHQgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiBfX3NhdGlzZmFjdGlvbi9kaXNzYXRpc2ZhY3Rpb25fXyB3ZSBjb3VsZCBjaG9vc2UgZGlmZmVyZW50IGNvbG91cnMgdGhhdCBiZWFyIG5vIHJlc2VtYmxhbmNlIHRvIG9uZSBhbm90aGVyLgoKKiBJbiBhZGRpdGlvbiwgY29sb3VycyAgdGhhdCBhcmUgb2NjdXIgaW4gbmF0dXJlIGFyZSBmb3VuZCB0byBiZSBtb3JlIGFwcGVhbGluZyB0byB0aGUgdmlld2VyLiBXaXRoIHRoaXMgaW4gbWluZCwgd2UgbWFrZSB0aGUgc2FtZSBwbG90IHdpdGggYWx0ZXJuYXRpdmUgY29sb3JzCgpgYGB7cn0KZ2dwbG90KGRhdGE9U3VydmV5LCBhZXMoeD1FeHBlcmllbmNlLHk9RnJlcXVlbmN5KSkgKyAgIAogIGdlb21fYmFyKGFlcyhmaWxsID0gU2F0aXNmYWN0aW9uKSwgcG9zaXRpb24gPSAiZG9kZ2UiLCBzdGF0ID0gImlkZW50aXR5IikrCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoImNhZGV0Ymx1ZTQiLCAiZ29sZGVucm9kIikpCmBgYAoKIyMgRXhlcmNpc2UgMSAKCkEgY29tcHV0ZXIgcmV0YWlsZXIgY29sbGVjdGVkIGRhdGEgb24gbGFwdG9wIHNhbGVzIGFuZCBvcmdhbmlzZSBpdCBhY2NvcmRpbmcgdG8gbWFrZSBhbmQgY2hpcCB0eXBlLCB3aXRoIHRoZSBmb2xsb3dpbmcgZGF0YSBvYnRhaW5lZAoKfCBfX01ha2VfXyB8IF9fSW50ZWwgaTNfXyB8IF9fSW50ZWwgaTVfXyB8IF9fSW50ZWwgaTdfXyB8CnwtLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tfAp8ICBBcHBsZSAgIHwgICAgICA1ICAgICAgIHwgICAgICAyNSAgICAgIHwgICAgICAgMzEgICAgIHwKfCAgRGVsbCAgICB8ICAgICAgMTUgICAgICB8ICAgICAgMjEgICAgICB8ICAgICAgIDE2ICAgICB8CnwgIEhQICAgICAgfCAgICAgIDIxICAgICAgfCAgICAgIDI4ICAgICAgfCAgICAgICAyNiAgICAgfAp8ICBMZW5vdm8gIHwgICAgICAxOCAgICAgIHwgICAgICAzMiAgICAgIHwgICAgICAgMzEgICAgIHwKCkdpdmVuIHRoaXMgZGF0YSBhbnN3ZXIgdGhlIGZvbGxvd2luZwoKMS4gSWRlbnRpZnkgdGhlIGRhdGEgdHlwZSBnaXZlbi4KCjIuIENyZWF0ZSBhIF9fLmNzdl9fIGZpbGUgdG8gdGFidWxhdGUgdGhpcyBkYXRhLgoKMy4gQ3JlYXRlIF9fdHdvX18gY2x1c3RlcmVkIGJhciBwbG90IGZyb20gdGhpcyBkYXRhIGZpbGUsIHVzaW5nIGRpZmZlcmVudCBjb2xvdXJzIGluIGVhY2ggcGxvdC4KCjQuIFJlb3JkZXIgdGhlc2UgcGxvdHMgaW4gb3JkZXIgb2YgX19kZWNyZWFzaW5nIEludGVsIGkzX18gc2FsZXMuCgo0LiBXaGljaCBvZiB0aGVzZSBwbG90cyBjb252ZXlzIHRoZSBkYXRhIGluIHRoZSBjbGVhcmVzdCB3YXk/CgojIyBFeGVyY2lzZSAyCgpBIGNvbXBhbnkgc3VydmV5IGFza2VkIGEgc2FtcGxlIG9mIDUwMCBlbXBsb3llZXMgYSBzZXJpZXMgb2Ygc2F0aXNmaWVkL2Rpc3NhdGlzZmllZCBxdWVzdGlvbnMgaW4gcmVsYXRpb24gdG8gdGhlaXIgd29yayBpbiB0aGUgZm9sbG93aW5nIGFyZWFzCgoxLiBXb3JrL0xpZmUgQmFsYW5jZSAgMi4gUmVtdW5lcmF0aW9uICAzLiBDYXJlZXIgT3Bwb3J0dW5pdGllcyAgIDQuIEpvYiBTYXRpc2ZhY3Rpb24gICA1LiBWYWNhdGlvbiBUaW1lICA2LiBVcC1za2lsbGluZyBPcHBvcnR1bml0aWVzCgp3aXRoIHRoZSBmb2xsb3dpbmcgZGF0YSBvYnRhaW5lZAoKfCBfX1dvcmsgRmVhdHVyZV9fICAgICAgICB8IFNhdGlzZmllZCB8IERpc3NhdGlzZmllZCB8CnwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tfAp8V29yay9MaWZlIEJhbGFuY2UgICAgICAgIHwgICAgMzk4ICAgIHwgICAgIDEwMiAgICAgIHwKfCAgUmVtdW5lcmF0aW9uICAgICAgICAgICB8ICAgIDMwMiAgICB8ICAgICAxOTggICAgICB8CnxDYXJlZXIgT3Bwb3J0dW5pdGllcyAgICAgfCAgICAyNzQgICAgfCAgICAgMjI2ICAgICAgfAp8IEpvYiBTYXRpc2ZhY3Rpb24gICAgICAgIHwgICAgNDA1ICAgIHwgICAgICA5NSAgICAgIHwKfCBWYWNhdGlvbiBUaW1lICAgICAgICAgICB8ICAgIDI3NyAgICB8ICAgICAyMzMgICAgICB8CnwgVXAtc2tpbGxpbmcgT3Bwb3J0dW5pdGllc3wgICAgMzIxICAgIHwgICAgIDE3OSAgICAgIHwKClVzaW5nIHRoaXMgZGF0YSBhbnN3ZXIgdGhlIGZvbGxvd2luZwoKMS4gQ3JlYXRlIGEgX18uY3N2X18gZmlsZSBmb3IgdGhpcyBkYXRhIGFuIGltcG9ydCBpdCBpbnRvIHRoaXMgd29yayBib29rCgoyLiBDcmVhdGUgYSBjbHVzdGVyZWQgYmFyLXBsb3QgZm9yIHRoaXMgZGF0YQoKMy4gSWRlbnRpZnkgdGhlIGRhdGF0eXBlIGdpdmVuIAoKNC4gSXMgdGhlcmUgYW55IHRyZW5kIG9idmlvdXMgZnJvbSB0aGUgY2hhcnQ/CgojIFN0YWNrZWQgQmFyIENoYXJ0cwoKQSBzdGFja2VkIGJhci1jaGFydCBpcyBhbm90aGVyIHR5cGUgb2YgYmFyLWNoYXJ0IHdoZXJlIHdlIGNvbXBhcmUgZGF0YSB3aXRoaW4gYSBnaXZlbiBjbGFzcywgYW5kIGluIHBhcnRpY3VsYXIgaXQgaWxsdXN0cmF0ZXMgaG93IHRoZSBvdmVyYWxsIGZyZXF1ZW5jeSBpbiBhIGdpdmVuIGNsYXNzIGlzIGRlY29tcG9zZWQgaW50byBmdXJ0aGVyIHN1Yi1jYXRlZ29yaWVzLgoKIyMgRXhhbXBsZSAyCgpBIFRveW90YSBkZWFsZXJzaGlwIGlzIHRha2luZyBhbiBpbnZlbnRvcnkgb2YgYWxsIG1vZGVscyBwcmVzZW50IG9uIHRoZSBsb3QsIGFuZCBvcmdhbmlzZXMgaXRzIGRhdGEgYWNjb3JkaW5nIHRvIG1ha2UgYW5kIGFnZS4gVGhlIGFnZXMgb2YgdGhlIGNhcnMgYXJlIGNhdGVnb3Jpc2VkIGFjY29yZGluZyB0byBwcmUtMjAwOCBhbmQgcG9zdC0yMDA4LCB3aXRoIHRoZSBkYXRhIGdpdmVuIGFzIGZvbGxvd3MKCgp8IF9fTW9kZWxfXyB8IFByZS0yMDA4IHwgUG9zdC0yMDA4ICB8CnwtLS0tLS0tLS0tLXwtLS0tLS0tLS0tfC0tLS0tLS0tLS0tLXwKfCAgIEF1cmlzICAgfCAgICA4ICAgICB8ICAgICAxNSAgICAgfAp8ICAgQXZlbnNpcyB8ICAgIDExICAgIHwgICAgIDIxICAgICB8CnwgICBDYW1yeSAgIHwgICAgNCAgICAgfCAgICAgIDIgICAgIHwKfCAgIENvcm9sbGEgfCAgICAyMyAgICB8ICAgICAxOCAgICAgfAp8ICAgUHJpdXMgICB8ICAgIDEgICAgIHwgICAgICA0ICAgICB8CnwgICBZYXJpcyAgIHwgICAgNCAgICAgfCAgICAgMTIgICAgIHwKCgoxLiBJbXBvcnQgdGhlIGRhdGEgZnJvbSAgX19DYXJJbnZlbnRvcnkuY3N2X18gYXZhaWxhYmxlIGluIF9Xb3JrYm9vayBGaWxlc18gb24gTW9vZGxlIGFuZCBkaXNwbGF5IHRoZSBkYXRhLgpgYGB7cn0KQ2FycyA8LSByZWFkLmNzdihmaWxlLmNob29zZSgpKQpgYGAKV2UgZGlzcGxheSB0aGUgZGF0YSBmcmFtZSBfX0NhcnNfXyB0byBlbnN1cmUgYWxsIGlzIGNvcnJlY3QKYGBge3J9CkNhcnMKYGBgCgoyLiBQbG90IHRoZSBkYXRhIHdpdGggaGlnaC1jb250cmFzdCBjb2xvdXJzIHVzaW5nIF9fZ2dwbG90X18uCgpgYGB7cn0KZ2dwbG90KENhcnMsIGFlcyh4PU1vZGVsLHk9SW52ZW50b3J5LCBmaWxsPVllYXIpKSsKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCJkb2RnZXJibHVlIiwiZ29sZGVucm9kMSIpKQpgYGAgCjMuIFJlb3JkZXIgdGhlIHBsb3RzIGluIG9yZGVyIG9mIF9fZGVjcmVhaW5nIFByZS0yMDA4X18gaW52ZW50b3J5LgpgYGB7cn0KQ2FycyRNb2RlbCA8LSBmYWN0b3IoQ2FycyRNb2RlbCwgbGV2ZWxzID0gYygnQ29yb2xsYScsICdBdmVuc2lzJywgJ0F1cmlzJywgJ0NhbXJ5JywgJ1lhcmlzJywgJ1ByaXVzJykpCkNhcnMKYGBgCjQuIFBsb3QgdGhlIHJlb3JkZXJlZCBkYXRhIHVzaW5nIHRoZSBzYW1lIGNvbG91cmluZy4KYGBge3J9CmdncGxvdChDYXJzLCBhZXMoeD1Nb2RlbCx5PUludmVudG9yeSwgZmlsbD1ZZWFyKSkrCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiKSsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiZG9kZ2VyYmx1ZSIsImdvbGRlbnJvZDEiKSkKYGBgIAo1LiBSZS1wbG90IHRoZSBvcmRlcmVkIGJhci1jaGFydCB1c2luZyBkaWZmZXJlbnQgY29sb3Vycy4gV2hpY2ggb2YgdGhlIGJhci1jaGFydHMgaXMgZWFzaWVyIHRvIGludGVycHJldD8KYGBge3J9CmdncGxvdChDYXJzLCBhZXMoeD1Nb2RlbCx5PUludmVudG9yeSwgZmlsbD1ZZWFyKSkrCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiKSsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9Yygic2xhdGVncmV5Iiwic2t5Ymx1ZSIpKQpgYGAgCgoKIyMgRXhlcmNpc2UgMyAKQSBjb21wdXRlciByZXRhaWxlciBzdW1hcmlzZXMgaXRzIHF1YXJ0ZXJseSBzYWxlcyBieSBjb21wdXRlciBtYWtlIGFuZCBzYWxlcyBwb2ludCwgd2l0aCB0aGUgZm9sbG93aW5nIGRhdGEgY29sbGVjdGVkCgp8IF9fTWFrZV9fIHwgX19PbmxpbmUgU2FsZXNfXyB8IF9fU3RvcmUgU2FsZXNfXyB8IF9fQ29ycG9yYXRlIFNhbGVzX18gfAp8LS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS0tfAp8IEFwcGxlICAgIHwgICAgICAgICAyMTAgICAgICB8ICAgICAgICAxNTUgICAgICB8ICAgICAgICAgIDUzICAgICAgICAgfAp8IEFzdXMgICAgIHwgICAgICAgICAzMzUgICAgICB8ICAgICAgICAyNzggICAgICB8ICAgICAgICAgIDU1ICAgICAgICAgfAp8IEZ1aml0c3UgIHwgICAgICAgICAxODggICAgICB8ICAgICAgICAyMDUgICAgICB8ICAgICAgICAgIDc1ICAgICAgICAgfAp8IEhQICAgICAgIHwgICAgICAgICAzMzYgICAgICB8ICAgICAgICA0NTEgICAgICB8ICAgICAgICAgMTI1ICAgICAgICAgfAp8IExlbm92byAgIHwgICAgICAgICAyMjUgICAgICB8ICAgICAgICAzMjEgICAgICB8ICAgICAgICAgMTQ0ICAgICAgICAgfAoKVXNpbmcgdGhpcyBkYXRhIGFuc3dlciB0aGUgZm9sbG93aW5nOgoKMS4gSWRlbnRpZnkgdGhlIGRhdGEgdHlwZSBnaXZlbgoyLiBDb25zdHJ1Y3QgYSBfXy5jc3ZfXyBmaWxlIHRvIHN0b3JlIHRoaXMgZGF0YQozLiBHZW5lcmF0ZSBhIHN0YWNrZWQgYmFyIGNoYXJ0IHRvIHJlcHJlc2VudCB0aGlzIGRhdGEKNC4gUmUtcGxvdCB0aGUgZGF0YSBpbiBvcmRlciBvZiBfX2RlY3JlYXNpbmcgT25saW5lIFNhbGVzX18KNS4gVXNlIGEgZGlmZmVyZW50IHNldCBvZiBjb2xvdXJzIHRvIHJlLXBsb3QgdGhlIG9yZGVyZWQgYmFyLWNoYXJ0CgoKIyMgRXhlcmNpc2UgNAoKVXNpbmcgdGhlIGRhdGEgZ2l2ZW4gaW4gX19FeGVyY2lzZSAxX18sIGdlbmVyYXRlIG9yZGVyZWQgYW5kIHVub3JkZXJlZCBfKipzdGFja2VkIGJhciBjaGFydHMqKl8gdG8gcmVwcmVzZW50IHRoaXMgZGF0YSBzZXQuCgoKIyMgRXhlcmNpc2UgNQoKVXNpbmcgdGhlIGRhdGEgZ2l2ZW4gaW4gX19FeGVyY2lzZSAyX18sIGdlbmVyYXRlIG9yZGVyZWQgYW5kIHVub3JkZXJlZCBfKipjbHVzdGVyZWQgYmFyIGNoYXJ0KipfIHRvIHJlcHJlc2VudCB0aGlzIGRhdGEuCgoKCiMjIEV4ZXJjaXNlIDYKCkEgZm9vZCBwcm9kdWNlciBjb2xsZWN0cyBkYXRhIG9uIGl0cyBnbG9iYWwgcmV2ZW51ZSBmcm9tIG9uZSB5ZWFyIG9mIHNhbGVzLiBJdCBjYXRlZ29yaXNlcyB0aGUgcmVnaW9ucyBvZiBzYWxlcyBhY3Rpdml0eSBhcwoKMS4gTm9ydGggQW1lcmljYSAgMi4gQ2VudHJhbCAmIFNvdXRoIEFtZXJpY2EgIDMuIEV1cm9wZSwgTWlkZGxlIEVhc3QgYW5kIEFmcmljYSAoRU1FQSkgICA0LiBBc2lhICA1LiBBdXN0cmFsYXNpYQoKSXQgY2F0ZWdvcmlzZXMgaXRzIGZvb2QgcHJvZHVjdHMgYWNjb3JkaW5nIHRvCgoxLiBXaGVhdCBhbmQgRGFpcnkgIDIuIEJldmVyYWdlcyAgMy4gQ29uZmVjdGlvbmVyeSAgNC4gV2VpZ2h0IFJlZHVjdGlvbgoKd2l0aCB0aGUgZm9sbG93aW5nIHNhbGVzIGRhdGEgaW4gbWlsbGlvbnMgb2YgZXVybyAKCnwgX19SZWdpb25fXyAgICAgICAgICAgICB8IF9fV2hlYXQgYW5kIERhaXJ5X18gfCBfX0JldmVyYWdlc19fIHwgX19Db25mZWN0aW9uYXJ5X18gfCBfX1dlaWdodCBSZWR1Y3Rpb25fXyB8CnwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS18CnwgTm9ydGggQW1lcmljYSAgICAgICAgICB8ICAgICAgIDUxICAgICAgICAgICAgfCAgICAgICAxNTIgICAgIHwgICAgICAgOTUgICAgICAgICAgfCAgICAgICAgMTI1ICAgICAgICAgICB8CnwgU291dGggJiBDZW50cmFsIEFtZXJpY2F8ICAgICAgIDcxICAgICAgICAgICAgfCAgICAgICAgMzIgICAgIHwgICAgICAgMTIyICAgICAgICAgfCAgICAgICAgIDc1ICAgICAgICAgICB8CnwgRU1FQSAgICAgICAgICAgICAgICAgICB8ICAgICAgIDI0MSAgICAgICAgICAgfCAgICAgICAxMTEgICAgIHwgICAgICAgODQgICAgICAgICAgfCAgICAgICAgMTE5ICAgICAgICAgICB8CnwgQXNpYSAgICAgICAgICAgICAgICAgICB8ICAgICAgIDE4OCAgICAgICAgICAgfCAgICAgICAgOTQgICAgIHwgICAgICAgODggICAgICAgICAgfCAgICAgICAgIDkyICAgICAgICAgICB8CnwgQXVzdHJhbGFzaWEgICAgICAgICAgICB8ICAgICAgIDQ0ICAgICAgICAgICAgfCAgICAgICAgMjkgICAgIHwgICAgICAgNzQgICAgICAgICAgfCAgICAgICAgIDU3ICAgICAgICAgICB8CgoKVXNpbmcgdGhpcyBkYXRhIHNldCBhbnN3ZXIgdGhlIGZvbGxvd2luZzoKCjEuIElkZW50aWZ5IHRoZSBkYXRhIHR5cGVzIGdpdmVuCgoyLiBHZW5lcmF0ZSBhIF9fLmNzdl9fIGZpbGUgdG8gc3RvcmUgdGhpcyBkYXRhCgozLiBHZW5lcmF0ZSBhIF9fY2x1c3RlcmVkIGJhcnBsb3RfXyB0byByZXByZXNlbnQgdGhpcyBkYXRhCgo0LiBHZW5lcmF0ZSBhIF9fc3RhY2tlZCBiYXJwbG90X18gdG8gcmVwcmVzZW50IHRoaXMgZGF0YQoKNS4gV2hpY2ggb2YgdGhlIGJhciBjaGFydHMgcmVwcmVzZW50cyB0aGlzIGRhdGEgYmV0dGVyPwoKNi4gUmUtcGxvdCB0aGVzZSBjaGFydHMgd2l0aCBhIGRpZmZlcmVudCBvcmRlcmluZyBhbmQgd2l0aCBkaWZmZXJlbnQgY29sb3VyaW5nLCBvZiB5b3VyIG93biBjaG9pY2U/CgoKCgoKCgoKCgoKCgoK