#packages
library(readODS)
library(ggplot2)
library(dplyr)
library(tidyr)
library(kableExtra)
library(forcats)
library(purrr)
library(tseries)
library(ggfortify)
library(binom)
library(broom)
library(stringr)
library(ggpmisc)
library(corrplot)
library(DT)
library(shades)
#data
FAB <- read_ods("~\\FABtory\\FABtory.ods", sheet =2)
FAB2 <- FAB  |>  pivot_longer(
  cols = Biretta:WhiteOre,
  names_to = "Item",
  values_to = "AttemptsNeeded"
  )
Snitt <- FAB2  |> 
  group_by(Toon, Who) |>
  summarise(MeanAttemptsNeeded = mean(AttemptsNeeded))
Robe <- read_ods("~\\FABtory\\FABtory.ods", sheet =3)
Design <- read_ods("~\\FABtory\\FABtory.ods", sheet =4)
RobeSummaryTable <- read_ods("~\\FABtory\\FABtory.ods", sheet =6)

1 Summary

New data presented here show that the Holy Roman Emperor (HRE) policy effect on alchemy experiments is huge, much larger than the effect of the Adept title. Utilising a plethora of tricks it was possible over a few days to complete the Memorial Album for alchemy experiments (with FAB as reward) for a large number of low level characters at base rank 1 alchemy, at 20%–25% success rate (depending on item) across 3100 alchemy experiments. Also having the court alchemist advisor role on top of the HRE effect gave 10% additional success, as revealed by a further 1962 separate experiments focusing solely on Adept’s robe. With only adept title the success was around 1%. The proportion of minor success was unaffected by these factors. There was no measurable effect of alchemy rank, Oxford skills, paymaster aide or EX equipment on robe success, but an effect of alchemy rank on the minor successes.

2 Introduction

In Uncharted Waters Online (UWO), the Alchemy Experiment Result (No.1) Memorial Album (MA) give Forbidden Alchemy Book (FAB, Figure 1) as a reward for completing. It is notoriously hard to complete because the success rate of obtaining the entries in it is very low, thought to be 0.1% base or less for some items. Due to this difficulty, and because one character can only obtain one FAB, it is a valuable and sought after item that sells for around 10 captain’s tickets. It gives rank 15 increased Nanban rates, the highest in the game. (It is also possible to obtain FAB from spending real money, but the ticket it comes from also gives the choice of Vagrant’s Wear which is even more valuable so few would choose to get a FAB that way).

The FAB

FIGURE 1: The FAB

Having base rank 13 in Alchemy helps, because the Adept title obtained at r13 increases the success rate of alchemy experiments. But even with the title active the success rate is low: Around 1% to get Adept’s Biretta and Adept’s Robe, 5% to get Gold Short Sword and 10% for the rest (unpublished gut feelings based on getting adept title and FAB for about 25 characters in the past). With adept title, the number of attempts needed to get one item can still easily reach the hundreds (585 have been observed, and more rumoured). So this is hard to do, considering the relative difficulty of obtaining the base materials in quantity and in particular the need for base r13.

Increased availability of gear boosting alchemy in recent years have made it possible to grind alchemy very efficiently from base r1+11 (making gold at John Dee in London, and using gaseous drugs at Paracelsus in Venice), making it easier to obtain the adept title. It is nevertheless still a major effort because of the huge amount of materials needed for the skill grind and the low success of the experiments. Although it takes less than 30 minutes to get from r1 to r13 base alchemy using best practices, this obviously does not include the considerable time needed to prepare the necessary mats.

However, increased alchemy experiment success rate is a possible policy of some Holy Roman Emperor (HRE) candidates. With enough support done to unlock this effect it may be possible to easily obtain FAB, even without Adept title, without grinding alchemy at all (provided one could reach the required ranks for the experiments: r10–12 needed, + secondary skills). This HRE policy is rare, but we have had it least once early on Maris server when I made 125 Adept Robe and transmuted them into Alchemist Robe and then Alchemist Robe EX that sold for 1 billion ducats each.

During March 2023 such an opportunity came again in the form of Rudolf II as Emperor. Players that had supported this candidate with at least 49 support permits (i.e. 4.9m ducats effective support needed) got the effect activated for 31 days, along with +2 alchemy (Figure 2).

Policy of Support Alchemy and Court Alchemist advisor position for Rudolf II

FIGURE 2: Policy of Support Alchemy and Court Alchemist advisor position for Rudolf II

Less than a week later PapayaPlay launched an event that gave another +1 alchemy for 2 weeks. In addition, Stinker got the Alchemist advisor court position so could give friends one more +1 alchemy (Figure 2), as well as being Alchemist Meister (base rank 15+ alchemy) and thus able to give yet another +1 to apprentices. If all this was not enough, Atlantis made its appearance in the midst of it. Although unrelated to the experiment success for the MA, Atlantis is very relevant for alchemy since it gives +20% to transmutation success (such as when making Alchemist robe from the Adept’s robe made for the FAB). There was also 100% skill proficiency event going on so it was unavoidable to rank up several times before finishing the MA.

Thus, there was a lot of alchemy skill boost happening at the same time as the experiment success boost. The time was ripe for creating a FABtory.

This report present analyses of some data that was gathered when making MA entries for FAB during these unprecedented circumstances, and some additional experiments performed to better understand exactly how the HRE and other factors influence the outcome of alchemy experiments, and how this relates to crafting success in general.

2.1 Crafting success

Alchemy experiments differ from ordinary alchemy/casting/storage/handicrafts/sewing in that there is a “huge success” category (see Figure 3), as well as several tiers of minor success that all give different items, and failures that produce no item. Ordinary crafting do not have the huge success category but some recipes have a failure category, normal success and several tiers of “great success”. The latter may simply produce more quantity of the same, but for some recipes it results in a different item than normal success, and the goal is often to craft the highest tier such great success item in as few attempts as possible (to preserve valuable materials). My understanding of crafting success can be summarized as follows.

The outcome of ordinary crafting depends on two hidden parameters that can be manipulated independently. The first is the chance of great success. This can be increased by:

  • Paymaster aide
  • Oxford increased production skills 1-4
  • Meister title with apprentice nearby (only when crafting on land)
  • Workshop/galley ship skill (only when crafting at sea)

These factors have no effect at all if using Master’s Secrets, because the great success chance is then instantly made 100%. This is an uncommon consumable item (but obtainable in-game) that cannot be used for alchemy experiments.

The second parameter is the degree of great success, such as tier of cannon penetration or attack/defense stats of clothes. This can be increased by:

  • Skill rank
  • Oxford Item improvement Tech skill
  • Gear with the special goods production rate up EX effect
  • Sailor equipment with the special goods production effect (only at sea with workshop)

One theory is that the probability of producing a huge success in alchemy experiments is affected entirely by other factors than crafting a high tier great success in normal crafting. Alternatively, another school of thought argues that huge success is nothing but a high tier great success, so should be influenced at least partly by the same factors.

Seeing this for the first time in 2011 was something

FIGURE 3: Seeing this for the first time in 2011 was something

3 Methods

3.1 Experimental protocol for FAB

In total I had access to 74 characters that made enough support for Rudolf II as emperor, and had not obtained Adept title or any FAB MA entries previously. Nearly all of these had not yet obtained the alchemy skill at all, and most were low level and low court rank. The following steps were done to obtain a FAB for each of these characters:

  • In the election period, get support permits and invest enough in Rudolf II to unlock the alchemy support benefit.
  • Invest 10m ducats in London to get court rank 4 which is needed for quarters rank 2 necessary to place furniture which is needed to perform alchemy experiments.
  • Sell trade goods to get 20k fame, needed to equip +1 Nigredo gloves. In hindsight, this turned out to be a total overkill but I didn’t know I would get court alchemist or that papaya would have +1 production skills event. Also, I didn’t remember that the HRE gave +2 alchemy. I had assumed +1. So without using +3 paper, aide, job, Boston skill or ship I felt I needed this. Which I didn’t need in any case due to ranking up. But what the heck.
  • Buy quarters and upgrade to rank 2.
  • Make and place kiln (mostly +3 version) and bench (mostly +1 version) in the quarters.
  • Obtain alchemy skill. This was done in one of 4 ways:
    • Do the quest chain for alchemist job and get the skill from the job (the only way to learn it in the past). N = 4
    • Get adventure level 7 and casting rank 2, and then learn alchemy from John Dee in London. N = 27
    • Learn the skill at the scholar from another character at same account bestowing it. N = 24
    • Learn skill at the scholar from another character at same account bestowing it after itself having learned it this way (doubly bestowed). N = 19
  • Get alchemy boosters. I used:
    • +1 from being apprentice
    • +2 accessory
    • +1 hat (there is also +2 hats but I didn’t have any of those)
    • +2 clothes
    • +1 weapon
    • +1 gloves
    • +2 from HRE
    • +1 from being on court alchemist friend-list. In total they would therefore start out at r12 (r1+11). For the last 1/3 of the sample there was also:
    • +1 from Papaya event, so r1+12. During the experiments they would also get enough skills points for a few base ranks.
  • Craft all base mats and ingredients in huge quantities in advance and store on storage alts, aide bazaars, company vaults, quarters. This was done utilising the job-specific Boston skills for alchemy, sewing, handicraft and casting to save on mats when crafting, and using r20 buying skills, Robe EX and merchant mentor Boston skill to buy as much as possible per purchase order. This could have been tweaked even further with r9 EX and 4th fleet member.
  • Each character then made (during the HRE influence period) the 10 items needed for the MA (resulting in 740 items obtained). The experiments terminated when the item was obtained, moved on to the next item, and then to the next character. The items (see Appendix for the recipes) were always made in the following order:
    • Adept’s Biretta (r10)
    • Adept’s Robe (r11)
    • Gold-plated Armour (r12)
    • Knife losing it’s gold (r12)
    • Metal Works (r12)
    • Processed Lumber (r11)
    • Green Ore (r11)
    • Blue Ore (r11)
    • Red Ore (r11)
    • White Ore (r11)

(Yes, I know I’m inconsistent in naming some after the end product and some after the base material, but give me some slack). The characters were handed 3 base mats and plenty consumables of the right kind (other materials were handed back after each MA entry was obtained to avoid using wrong mats, or at wrong furniture, by mistake). They would have to trade me again if more than 3 base mats were needed and thus close and enter the experiment dialogue anew. For the coloured ores they received 250-300, apart from a few that I couldn’t bother to get a new ship for. Some made FAB in a starter barca.

I counted the number of times each experiment was performed until they got the item. That is, I counted in effect the number of consumables used, and not the number of base items. The main base item is not consumed on failures, only on success and “huge success” (i.e. MA item). If different experiments have different tables of possible results (for example if one have many possible success products, and another fewer, or they differ in the rate of failure) this could have affected the number of base items consumed (in addition to possible different probabilities of the MA item), which may in some sense be considered more important than the number of experiments performed. However, I did not collect good data on this.

The raw data for FAB experiments can be found in the Appendix.

3.2 Experimental protocol for Robes

In a separate set of experiments performed shortly after the FAB study I focused on the Adept’s Robe recipe. Unlike in the experiments for FAB I kept track of each outcome. The experimental set-up was designed to yield pairwise comparisons where a treatment group and a control group could be compared while all other factors were held constant. I did 1962 experiments in total, with 1–3 batches for each of 14 combinations of factors tested (Table 1), with approx 80 experiments in each batch until I ran out of resources (fine dye) to produce base materials. The conditions tested were:

  • With or without HRE policy (server wide effect for HRE supporters)
  • With or without Advisor position (personal effect for the sole court alchemist title holder)
  • With or without Adept title (obtained at alchemy base rank 13)
  • With or without Oxfords (increased production success 1–4, and item improvement tech)
  • With or without EX (Golden Ark rank 6 Special Goods Production Rate Up)
  • With r20 or r11 alchemy
kbl(Design[,-2], caption = 'Experimental design for Robe experiments. Group 15 is the Robe part of the FAB setup for comparison.', align ="c") |> 
  kable_paper(c("hover", "condensed"), full_width = F)
TABLE 1: Experimental design for Robe experiments. Group 15 is the Robe part of the FAB setup for comparison.
Condition HRE Advisor Adept EXr6 Oxfords AlchRank Batch Sequence Experiments Who Totals
1 Yes Yes Yes No No 20 1–3 1–204 60+61+83 Stinker 204
2 Yes Yes No No No 20 4–6 205–417 70+79+64 Stinker 222
3 Yes Yes Yes Yes No 20 7–9 418–613 62+68+66 Stinker 196
4 Yes Yes No Yes No 20 10–12 614–825 71+66+75 Stinker 212
5 Yes Yes Yes Yes Yes 20 13–15 826–1028 75+62+66 Stinker 203
6 Yes Yes No No No 11 16–17 1029–1186 79+79 Stinker 158
7 Yes No No No No 11 18 1197–1269 83 Bodal 83
8 Yes No No No No 20 19 1270–1352 83 Bodal 83
9 Yes No Yes No No 11 20 1353–1442 90 Bodal 90
10 Yes No Yes No No 20 21 1443–1522 80 Bodal 80
11 No No No No No 11 22 1523–1630 108 Bib2 108
12 No No Yes No No 11 23 1631–1731 101 Bib2 101
13 No No No No No 20 24 1732–1840 109 Bib2 109
14 No No Yes No No 20 25–26 1841–1962 93+29 Bib2 122
15 Yes No No No No 12–14 NA NA 364 74 FAB 364

One batch is here defined as an uninterrupted sequence of experiments done without closing the dialogue screen. The length of a batch was limited by inventory space and the number of failures (more failure = longer batch), but was not limited by vigour food. No disconnects from the server occurred during the experiments. Batch number 26 was merged with batch 25 (identical conditions) in some analyses because the sample size was deemed too small to be treated separately.

It was not possible to keep the sample sizes strictly equal between batches because even though the number of base clothes were the same (+/- a few), the number of experiments differed due to the fact that failure do not consume the base material and would lead to more experiments possible before the base mats were used up for the batch.

A full factorial experimental design of 6 factors with 2 levels each would require \(2^6\) = 64 combinations. It was not practically possible to test every combination of the factors. I chose to ignore any interaction effects as there is reason to believe all the effects are purely additive, removing the need for a full design. However, certain combinations of factors were physically impossible. For example, the advisor effect could not be obtained without having also the HRE effect. Another difficulty was that without wearing any gear I was already r20 alchemy. However, adjusting alchemy rank down to r11 could be achieved with a combination of mentoring and + gear (Figure 4). Thus it was possible to disentangle skill rank, Adept title and HRE effects which would otherwise be confounded.

Mentoring was used in order to lower skill rank and retain adept title

FIGURE 4: Mentoring was used in order to lower skill rank and retain adept title

Oxfords were compared with all on or all off. Even though it would have been ideal to have experiments with and without Oxford improvement techniques while having Oxford production success on or off, it is still possible to separate the effects. Oxford tech skill is only (possibly) relevant for experiments that did not fail, whereas the production success Oxfords should (possibly) only affect fail rate. Therefore one can compare fail rate with and without Oxfords to test the production success Oxfords, and compare outcome among experiments that did not fail with and without Oxfords to test the item improvement tech Oxford.

All experiments in the Robe setup were done with aide in Paymaster 100s job. Since the FAB trials were not, it was to some extent also possible to test the effect of paymaster aide by comparing certain groups from the Robe setup with the FAB results. Unfortunately there was no data to separate failures from minor success in the FAB experiments, so only the effect of aide on huge success can be considered.

Results were mostly analysed by comparing confidence intervals of proportions. Since some of the observed proportions were 0 or close to 0, I did not use the standard asymptotic (Wald) approximation to calculate binomial confidence intervals, but instead the Wilson method implemented in R package binom.

The raw data for Robe experiments can be found in the Appendix.

This report was written using R Markdown in RStudio. R code used to generate the results and some output can be seen by clicking on the “code” buttons, as well as found in the Appendix (without output) together with software versions used.

4 Results

4.1 FAB experiments


ggplot(FAB2, aes(AttemptsNeeded)) +
  geom_histogram(fill = "#377eb8", colour = "black", binwidth = 1)

ggplot(FAB2, aes(AttemptsNeeded)) +
  stat_density(aes(colour = AlchemySkill),  linewidth = 2,
               bounds = c(1, Inf), geom="line", position="identity") +
  #scale_colour_manual(values = c("#7a0403","#FABA39","#18bc9c", "#2c3e50"))+
  scale_colour_brewer(palette = "RdBu", direction = -1) +
  #scale_colour_manual(values = c("#7a0403","#FABA39","#18bc9c", "#2c3e50"))+
  theme(legend.position = c(0.95,0.95),
        legend.justification = c(1,1))
Needed attempts to get an MA entry overall (histogram), and by how the alchemy skill was obtained (kernel density estimates)Needed attempts to get an MA entry overall (histogram), and by how the alchemy skill was obtained (kernel density estimates)

FIGURE 5: Needed attempts to get an MA entry overall (histogram), and by how the alchemy skill was obtained (kernel density estimates)

Over all 740 MA items obtained, the mean number of experiments needed to obtain one item was 4.19 attempts, with a median of 3. In total 3100 experiments were performed to get all the MA items for all 74 participants. The distribution of needed attempts is shown in Figure 5. The highest number observed was 25 attempts for one item. It did not seem to matter if the skill was obtained from the job, learned by fulfilling requirements, bestowed or bestowed again (Figure 5). If we compare the results from the different items (Figure 6) there does not seem to be any obvious differences – there is a lot of variation within compared to between groups.

FAB3 <- FAB2 |>
  mutate(Item = reorder(Item, AttemptsNeeded, FUN = mean, na.rm = TRUE))
ItemLabels <- FAB3 |>
  group_by(Item) |>
  summarise(snitt = mean(AttemptsNeeded), median =median(AttemptsNeeded))
ItemLabels$snitt2 <- sprintf("bar(x) == %.2f", ItemLabels$snitt)
ItemLabels
## # A tibble: 10 × 4
##    Item       snitt median snitt2        
##    <fct>      <dbl>  <dbl> <chr>         
##  1 ProcLumber  3.45    2.5 bar(x) == 3.45
##  2 Knife       3.80    3   bar(x) == 3.80
##  3 GoldPlated  3.82    3   bar(x) == 3.82
##  4 RedOre      3.99    3   bar(x) == 3.99
##  5 GreenOre    4.12    3   bar(x) == 4.12
##  6 WhiteOre    4.28    3   bar(x) == 4.28
##  7 MetalWorks  4.30    3   bar(x) == 4.30
##  8 Biretta     4.54    3.5 bar(x) == 4.54
##  9 BlueOre     4.68    4   bar(x) == 4.68
## 10 Robe        4.92    3.5 bar(x) == 4.92

ggplot(FAB3, aes(AttemptsNeeded)) +
  geom_histogram(binwidth = 1, colour = "black", 
                 aes(fill=(Item))) + 
  facet_wrap(vars(Item), ncol = 2) +
  #scale_fill_viridis_d(option = "turbo", direction = 1, guide = "none") +
  scale_fill_brewer(palette = "RdBu", guide = "none", direction = -1)+
  geom_label(x = 12.5, y = 17.5, aes(label = snitt2), data = ItemLabels, parse = TRUE, 
             hjust = "center", size = 3, label.size = NA)
Needed attempts for the different items

FIGURE 6: Needed attempts for the different items

This is easier to compare using box plots, shown in Figure 7. We can think of a box plot as dividing the data in 4 parts with equal number of observations. The median (shown as a vertical line) cut the data in half with as many smaller as larger observations, and the box show the lower (25%) and upper (75%) quartiles. That is, the central 50% of the observations lie within the boxes, and 50% below and 50% above the median. Mean values (shown as white dots) are higher than medians because of the shape of the distributions. Again there is no large difference discernible in the difficulty of obtaining any of the items, but we can see that robes have the highest mean followed by biretta and blue ore.

ggplot(FAB3, aes(x=AttemptsNeeded, y=Item, fill=Item)) +
  geom_boxplot() +
  stat_summary(fun=mean, geom="point", shape=20, size=3, color="white", fill="white") +
  ylab(NULL) +
  scale_x_continuous(breaks = seq(0,24, by =2))+
  #scale_fill_viridis_d(option = "turbo", direction = 1, guide="none")
  scale_fill_brewer(palette = "RdBu", guide = "none", direction =-1)
Box plots of number of attempts needed to get each MA entry

FIGURE 7: Box plots of number of attempts needed to get each MA entry

FAB4 <- FAB3 |>
  mutate(ItemGroup = ifelse(Item == "Biretta" | Item == "Robe" , "Robe/Biretta", "Others"))
FAB4$ItemGroup <- as_factor(FAB4$ItemGroup)
ItemLabels2 <- FAB4 |>
  group_by(ItemGroup) |>
  summarise(snitt = mean(AttemptsNeeded), 
            median =median(AttemptsNeeded), 
            n = (length(AttemptsNeeded)))
ItemLabels2$snitt2 <- sprintf("bar(x) == %.2f", ItemLabels2$snitt)
ItemLabels2$n2 <- sprintf("n == %.0f", ItemLabels2$n)
ItemLabels2$snittAndN <- sprintf(
  "bar(x) == %.2f * ',' ~~ n == %.0f",
  ItemLabels2$snitt,
  ItemLabels2$n
)
ggplot(FAB4, aes(AttemptsNeeded)) +
  geom_histogram(binwidth = 1, colour = "black", 
                 aes(fill=(ItemGroup))) + 
  facet_wrap(vars(ItemGroup), ncol = 2) +
  scale_fill_manual(values = c("#B51F2E", "#377eb8"), guide = "none") +
  #scale_fill_manual(values = c("#7a0403", "#95a5a6"), guide = "none") +
  #scale_fill_brewer(palette = "Set1", guide = "none")+
  geom_label(x = 12.5, y = 140, aes(label = snittAndN), data = ItemLabels2, parse = TRUE, 
             hjust = "center", vjust = "center", size = 3, label.size = NA)

ggplot(FAB4, aes(AttemptsNeeded)) +
  geom_histogram(binwidth = 1, colour = "black", 
                 aes(fill=(ItemGroup), y = stat(density))) + 
  facet_wrap(vars(ItemGroup), ncol = 2) +
  scale_fill_manual(values = c("#B51F2E", "#377eb8"), guide = "none") +
  #scale_fill_manual(values = c("#7a0403", "#95a5a6"), guide = "none") +
  #scale_fill_brewer(palette = "Set1", guide = "none")+
  geom_label(x = 12.5, y = 0.235, aes(label = snittAndN), data = ItemLabels2, parse = TRUE, 
             hjust = "center", vjust = "center", size = 3, label.size = NA)

ggplot(FAB4, aes(AttemptsNeeded)) +
  stat_density(aes(colour = ItemGroup),  linewidth = 2,
               bounds = c(1, Inf), geom="line", position="identity") +
  scale_colour_manual(values = c("#B51F2E", "#377eb8"), guide = "none") +
  #scale_colour_viridis_d(option = "turbo", direction = -1) +
  #scale_colour_manual(values = c("#7a0403","#95a5a6")) +
  #scale_colour_brewer(palette = "Set1", guide = "none")+
  theme(legend.position = c(0.95,0.95),
        legend.justification = c(1,1)) +
  guides(colour = guide_legend(title = NULL))

ggplot(FAB4, aes(x=AttemptsNeeded, y=ItemGroup, fill=ItemGroup)) +
  geom_boxplot() +
  stat_summary(fun=mean, geom="point", shape=20, size=3, color="white", fill="white") +
  ylab(NULL) +
  scale_x_continuous(breaks = seq(0,24, by =2))+
  scale_fill_manual(values = c("#B51F2E", "#377eb8"), guide = "none") 
  #scale_fill_manual(values = c("#7a0403","#95a5a6"), guide="none")
  #scale_fill_brewer(palette = "Set1", guide = "none")
Number of attempts needed for two groups of items. Histogram of counts, standardised histogram, kernel density estimates and box plotsNumber of attempts needed for two groups of items. Histogram of counts, standardised histogram, kernel density estimates and box plotsNumber of attempts needed for two groups of items. Histogram of counts, standardised histogram, kernel density estimates and box plotsNumber of attempts needed for two groups of items. Histogram of counts, standardised histogram, kernel density estimates and box plots

FIGURE 8: Number of attempts needed for two groups of items. Histogram of counts, standardised histogram, kernel density estimates and box plots

table(FAB4$ItemGroup)
## 
## Robe/Biretta       Others 
##          148          592
(WT <- wilcox.test(FAB4$AttemptsNeeded ~ FAB4$ItemGroup, 
            paired = F, 
            alternative = "greater"))
## 
##  Wilcoxon rank sum test with continuity correction
## 
## data:  FAB4$AttemptsNeeded by FAB4$ItemGroup
## W = 47772, p-value = 0.04238
## alternative hypothesis: true location shift is greater than 0

In order to learn if there is more than random variability in the data we can perform some statistical analyses. From a priori information we can expect Robe and Biretta to be harder to make than the other 8 items, so to increase sample size and reduce uncertainty I lumped the data into two groups: Robe+Biretta (n = 148, \(\bar{x}\) = 4.73 attempts) vs the other items (n = 592, \(\bar{x}\) = 4.05 attempts). The distributions of needed attempts for these two groups is shown in in Figure 8. The number of attempts was significantly larger for the Robe/Biretta group (Mann-Whitney U-test, one-sided p = 0.04).

#restructure data
FABprop <- FAB4 |>
  group_by(ItemGroup) |>
  summarise(success = sum(n()), total = sum(AttemptsNeeded))
#binomial confidence intervals
binom::binom.confint(FABprop$success, FABprop$total) 
##           method   x    n      mean     lower     upper
## 1  agresti-coull 148  700 0.2114286 0.1827560 0.2432511
## 2  agresti-coull 592 2400 0.2466667 0.2298297 0.2643133
## 3     asymptotic 148  700 0.2114286 0.1811802 0.2416769
## 4     asymptotic 592 2400 0.2466667 0.2294206 0.2639128
## 5          bayes 148  700 0.2118402 0.1818799 0.2422619
## 6          bayes 592 2400 0.2467722 0.2295945 0.2640682
## 7        cloglog 148  700 0.2114286 0.1820038 0.2423941
## 8        cloglog 592 2400 0.2466667 0.2296016 0.2640760
## 9          exact 148  700 0.2114286 0.1817347 0.2435774
## 10         exact 592 2400 0.2466667 0.2295297 0.2644240
## 11         logit 148  700 0.2114286 0.1827598 0.2432559
## 12         logit 592 2400 0.2466667 0.2298285 0.2643151
## 13        probit 148  700 0.2114286 0.1824644 0.2429217
## 14        probit 592 2400 0.2466667 0.2297478 0.2642309
## 15       profile 148  700 0.2114286 0.1822669 0.2426986
## 16       profile 592 2400 0.2466667 0.2296966 0.2641772
## 17           lrt 148  700 0.2114286 0.1822720 0.2426960
## 18           lrt 592 2400 0.2466667 0.2296995 0.2641903
## 19     prop.test 148  700 0.2114286 0.1821235 0.2439577
## 20     prop.test 592 2400 0.2466667 0.2296313 0.2645215
## 21        wilson 148  700 0.2114286 0.1827968 0.2432103
## 22        wilson 592 2400 0.2466667 0.2298344 0.2643086
(binomRes <- binom::binom.wilson(FABprop$success, FABprop$total))
##   method   x    n      mean     lower     upper
## 1 wilson 148  700 0.2114286 0.1827968 0.2432103
## 2 wilson 592 2400 0.2466667 0.2298344 0.2643086
binomRes$Group <- as_factor(c("Robe/Biretta", "Others"))
#test if equal proportions
(propRes <- prop.test(x = binomRes$x, binomRes$n, alternative = "less"))
## 
##  2-sample test for equality of proportions with continuity correction
## 
## data:  binomRes$x out of binomRes$n
## X-squared = 3.5116, df = 1, p-value = 0.03047
## alternative hypothesis: less
## 95 percent confidence interval:
##  -1.000000000 -0.005094121
## sample estimates:
##    prop 1    prop 2 
## 0.2114286 0.2466667
kbl(FABprop, label = "FABpropTable", 
    caption = 'Number of successes and attempts when making MA entries for FAB', 
    align ="c",
    col.names = c('Group', 'Successes', 'Total Experiments')) |>
  kable_paper(c("hover", "condensed"), full_width = F) #|>
TABLE 2: Number of successes and attempts when making MA entries for FAB
Group Successes Total Experiments
Robe/Biretta 148 700
Others 592 2400
  #column_spec(1, color = "white", bold = F, 
  #            background = c("#ca0020", "#0571b0"))
binomRes |> 
ggplot(aes(x = Group, y = mean, colour= Group)) +
  ylab("Proportion Success") +
  xlab(NULL) +
  geom_pointrange(aes(ymin = lower, ymax = upper), size =0.75, linewidth = 1)+
  scale_colour_manual(values = c("#B51F2E", "#377eb8"), guide = "none") +
  geom_text(aes(label = round(mean, 3), vjust = -2), size = 3) +
  coord_flip() +
  theme(axis.ticks.y = element_blank(),
        panel.grid.major.y = element_blank())
Proportion success for the two groups of items, with 95% confidence intervals

FIGURE 9: Proportion success for the two groups of items, with 95% confidence intervals

We may also arguably treat each experiment as independent and look at if the proportion of success is lower for the Robe/Biretta group than for the other group (Table 2). The binomial confidence intervals of the two proportions had some overlap (Figure 9), but as expected the proportion of success was significantly less for the Robe/Biretta group (\(\chi^{2}\) = 3.51 , df = 1, one-sided p = 0.03).

Overall we can say that with the HRE effect active the “difficult” items (Robe and Biretta) on average needed about 5 attempts and the other, “easy”, items about 4 attempts, which translates to 20 % and 25 % chance, respectively.


ggplot(Snitt, aes(MeanAttemptsNeeded)) +
  geom_histogram(aes(fill= Who), binwidth = 0.5, colour="black") +
  #scale_fill_brewer(palette = "RdBu", direction = 1) +
  scale_fill_manual(values = c("#B51F2E","#F4A582","#A7CFE4", "#377eb8"))+
  #scale_fill_viridis_d(option = "turbo", direction = -1) +
  ylab("Count") +
  xlab("Average attempts needed") +
  annotate("text", x = 2.5, y = 9.5, label = "Alta-lucky-vista", colour = "#B51F2E") +
  geom_curve(
    aes(x = 2.5, y = 8.8, xend = 2.0, yend = 2.5),
    arrow = arrow(
    length = unit(0.03, "npc"), 
    type="closed" 
    ),
    colour = "#B51F2E",
    linewidth = 1.2,
    angle = 0 
  ) +
  scale_y_continuous(breaks = seq(0,20, by =2))+
  theme(
    legend.position = c(0.95,0.95),
    legend.justification = c(1,1),
    legend.background = element_rect(fill = "white"),
    legend.key = element_rect(fill = "white", color = NA)
  )
Mean number of attempts needed to get each of the 10 MA entries for FAB

FIGURE 10: Mean number of attempts needed to get each of the 10 MA entries for FAB

The mean number of attempts a player had to do to get each of the 10 items for the MA varied from 2.1 to 6.6 with a mean of 4.19. Some people are luckier than others (Figure 10).

As an anecdote, only one character managed to complete the FAB without getting any other MA entries (like gemstones and plates from minor success by-products, Figure 11). And he did not have any other MA records either. What a guy.

Another unique individual

FIGURE 11: Another unique individual

4.2 Robe experiments

A summary of the results is presented in Table 3 below. This is visualized as stacked bars ordered by proportion Robes in Figure 12 (per condition) and Figure 13 (further divided into the separate batches). Figure 14 show the he actual sequence of outcomes for each batch (batches in same order as in Figure 13, but omitting labelling the conditions to leave more space).

It is difficult to compare stacked bar charts that have more than two categories because the location of the middle categories is shifted relative to each other across groups – they don’t have a common baseline. When analysing the effect of the various treatments in the sub-chapters below, the details are therefore presented as proportion (with 95% confidence intervals) of the relevant category.

kbl(RobeSummaryTable, caption = 'Outcome of Robe Experiments for each batch. The percentage Adept Robe is highlighted.', align ="c") |>
  kable_paper(c("hover", "condensed"), full_width = F) |>
  column_spec(9, background = "#92c5de") |> #, color = "white"
  pack_rows("HRE, Advisor, Adept, r20", 1, 3) |>
  pack_rows("HRE, Advisor, r20", 4, 6) |>
  pack_rows("HRE, Advisor, Adept, r20, Ex", 7, 9) |>
  pack_rows("HRE, Advisor, r20, Ex", 10, 12) |>
  pack_rows("HRE, Advisor, Adept, r20, Ex, Oxf", 13, 15) |>
  pack_rows("HRE, Advisor, r11", 16, 17) |>
  pack_rows("HRE, r11", 18, 18) |>
  pack_rows("HRE, r20", 19, 19) |>
  pack_rows("HRE, Adept, r11", 20, 20) |>
  pack_rows("HRE, Adept, r20", 21, 21) |>
  pack_rows("r11", 22, 22) |>
  pack_rows("Adept, r11", 23, 23) |>
  pack_rows("r20", 24, 24) |>
  pack_rows("Adept, r20", 25, 26)
TABLE 3: Outcome of Robe Experiments for each batch. The percentage Adept Robe is highlighted.
Condition Batch Failure FineVelvet Justaucorps Robe Waistcoat Total %Robe %Failure %minor %Justau %Justau/minor
HRE, Advisor, Adept, r20
1 1 20 7 5 20 8 60 33.3 33.3 33.3 8.3 25.0
1 2 17 6 7 24 7 61 39.3 27.9 32.8 11.5 35.0
1 3 36 8 10 17 12 83 20.5 43.4 36.1 12.0 33.3
HRE, Advisor, r20
2 4 24 12 3 23 8 70 32.9 34.3 32.9 4.3 13.0
2 5 34 7 9 20 9 79 25.3 43.0 31.6 11.4 36.0
2 6 21 4 11 22 6 64 34.4 32.8 32.8 17.2 52.4
HRE, Advisor, Adept, r20, Ex
3 7 16 6 4 26 10 62 41.9 25.8 32.3 6.5 20.0
3 8 22 9 7 23 7 68 33.8 32.4 33.8 10.3 30.4
3 9 19 10 7 24 6 66 36.4 28.8 34.8 10.6 30.4
HRE, Advisor, r20, Ex
4 10 24 4 6 27 10 71 38.0 33.8 28.2 8.5 30.0
4 11 19 12 11 16 8 66 24.2 28.8 47.0 16.7 35.5
4 12 29 11 9 19 7 75 25.3 38.7 36.0 12.0 33.3
HRE, Advisor, Adept, r20, Ex, Oxf
5 13 28 8 12 19 8 75 25.3 37.3 37.3 16.0 42.9
5 14 15 11 11 21 4 62 33.9 24.2 41.9 17.7 42.3
5 15 19 4 12 15 16 66 22.7 28.8 48.5 18.2 37.5
HRE, Advisor, r11
6 16 30 15 1 20 13 79 25.3 38.0 36.7 1.3 3.4
6 17 31 9 1 26 12 79 32.9 39.2 27.8 1.3 4.5
HRE, r11
7 18 37 13 3 15 15 83 18.1 44.6 37.3 3.6 9.7
HRE, r20
8 19 37 10 10 15 11 83 18.1 44.6 37.3 12.0 32.3
HRE, Adept, r11
9 20 43 15 2 18 12 90 20.0 47.8 32.2 2.2 6.9
HRE, Adept, r20
10 21 33 10 13 16 8 80 20.0 41.3 38.8 16.3 41.9
r11
11 22 68 24 3 0 13 108 0.0 63.0 37.0 2.8 7.5
Adept, r11
12 23 62 18 5 1 15 101 1.0 61.4 37.6 5.0 13.2
r20
13 24 69 16 11 0 13 109 0.0 63.3 36.7 10.1 27.5
Adept, r20
14 25 53 9 16 0 15 93 0.0 57.0 43.0 17.2 40.0
14 26 19 2 4 1 3 29 3.4 65.5 31.0 13.8 44.4
Total Result NA 825 260 193 428 256 1962 21.8 42.0 36.1 9.8 27.2

# get condition descriptions from table, and combine with sample size for figure labels
# and reorder factor levels by % robes. and the items from "hardest to easiest"
# keep them reordered in the file so don't have to do within ggplot
Robe2 <- Robe |> left_join(Design |> select(Condition, Condition2, Totals), by="Condition")
Robe2 <- Robe2 |>
  mutate(Condition3 = paste0(Condition2, " (n = ", Totals, ")")) |>
  mutate(Condition3 = fct_reorder(.f = Condition3, 
                                         .x = Result,
                                         .fun = function(.x) mean(.x == "Robe"),
                                         .desc = TRUE)) |>
  mutate(Result = fct_relevel(Result, "Robe", "Justaucorps", "Waistcoat", "FineVelvet", "Failure"))
  
ggplot(Robe2, aes(Condition3, fill = fct_rev(Result))) + 
  geom_bar(position = "fill", width = 0.9,) + #
  #shades::brightness(scale_fill_brewer(palette = "RdBu", direction = -1),   shades::delta(-0.05)) +
  scale_fill_brewer(palette = "RdYlBu", direction = -1) +
  #scale_fill_viridis_d(option = "turbo", direction = 1) +
  scale_y_continuous(labels = scales::percent, breaks = seq(0, 1, by = 0.2), expand = expansion(mult = c(0, 0.02))) +
  scale_x_discrete(expand = expansion(mult = c(0, 0)))+
  ylab("Percentage") +
  xlab(NULL) +
  theme(legend.background = element_rect(fill = "#EBEBEB"),
        legend.key = element_rect(fill = NA),
        legend.position = "top",
        axis.text.y = element_text(size = rel(1)),
        axis.ticks.y = element_blank(),
        panel.grid.major.y = element_blank(),
        legend.justification = c(1, 0),
        panel.background = element_rect(fill = "white")) +
  guides(fill = guide_legend(reverse = TRUE, title = NULL))+
  coord_flip()
Percentage of outcomes for Robe experiments under different conditions

FIGURE 12: Percentage of outcomes for Robe experiments under different conditions


# include batch, within condition
Robe2$GroupBatch <- ave(Robe2$Batch, Robe2$Condition, 
                        FUN = function(x) as.numeric(factor(x)))
ggplot(Robe2, aes(GroupBatch, fill = fct_rev(Result))) + 
  geom_bar(position = "fill",  width = 1) + #colour = "black",
  scale_fill_brewer(palette = "RdYlBu", direction = -1) +
  #scale_fill_viridis_d(option = "turbo", direction = 1) +
  scale_y_continuous(labels = scales::percent, breaks = seq(0, 1, by = 0.2), expand = expansion(mult = c(0, 0.02))) +
  scale_x_continuous(breaks = NULL, expand = expansion(mult = c(0, 0))) +
  ylab("Percentage") +
  xlab(NULL) +
  theme(legend.background = element_rect(fill = "#EBEBEB"),
        legend.key = element_rect(fill = NA),
        legend.position = "top",
        axis.text.y = element_text(size = rel(1.2)),
        legend.justification = c(1, 0)) +
  guides(fill = guide_legend(reverse = TRUE, title = NULL))+
  coord_flip()+
  facet_wrap(~fct_rev(Condition3), strip.position = "left", ncol = 1, scales = "free_y") +
  theme(strip.text.y.left = element_text(angle = 0, hjust = 1), 
        panel.spacing = unit(0.1,"cm"), 
        strip.background = element_rect(fill = NA))
Percentage of outcomes split in batches

FIGURE 13: Percentage of outcomes split in batches

# time series visualization
ggplot(Robe2, aes(x=BatSeq, fill = fct_rev(Result))) +
  geom_bar(position = "fill", width = 1) + #, colour = "black"
  facet_wrap(vars(fct_rev(Condition3), GroupBatch), strip.position = "left", ncol = 1) +
  scale_fill_brewer(palette = "RdYlBu", direction = -1) +
  #scale_fill_viridis_d(option = "turbo", direction = 1)+
  scale_x_continuous(breaks = seq(0, 120, by = 20), expand = expansion(mult = c(0, 0))) +
  scale_y_continuous(breaks = NULL, expand = expansion(mult = c(0, 0))) +
  theme(legend.background = element_rect(fill = "#EBEBEB"),
        legend.key = element_rect(fill = NA),
        legend.position = "top",
        axis.text.y = element_text(size = rel(1.2)),
        legend.justification = c(0.5, 0)) +
  guides(fill = guide_legend(reverse = TRUE, title = NULL)) +
  theme(strip.text.y.left = element_blank(), 
        strip.text.x = element_blank(),
        panel.spacing = unit(0.1,"cm")) +
  xlab("Sequence") +
  ylab(NULL)
Sequence of outcomes for Robe experiments under different conditions, for each batch

FIGURE 14: Sequence of outcomes for Robe experiments under different conditions, for each batch

4.2.1 HRE effect

HRE <- Robe2 |> 
  mutate(robeSeries = fct_other(Result, keep = "Robe")) |> 
  group_by(HRE, Condition2, robeSeries) |>
  summarise(number = n(), Condition = mean(Condition)) |> 
  ungroup() |> 
  pivot_wider(
  names_from  = "robeSeries",
  values_from = "number",
  values_fill = 0) |> 
  mutate(Total = Robe+Other,
         PropRobe = Robe/Total)
HRE <- cbind(HRE, 
      binom.confint(HRE$Robe, n = HRE$Total, methods = "wilson"))

HRE <- HRE |> 
  filter(Condition %in% c(7:10) | HRE == "NO") |> #manual subsetting
  mutate(Condition3 = (str_replace(Condition2, c("HRE, "), "")))
  
HRE |> 
ggplot(aes(y = Condition3, x = PropRobe, colour = HRE)) +
  ylab(NULL) +
  xlab("Proportion Robe") +
  geom_pointrange(aes(xmin = lower, xmax = upper), 
                  size =0.75, linewidth = 1,
                  position = position_dodge(width=1)) +
  scale_colour_manual(values = c("#95a5a6", "#2c3e50")) +
  theme(legend.position = "top") +
  facet_wrap(vars(Condition3), strip.position = "left", ncol = 1, scales = "free_y")+
  theme(strip.text.y.left = element_blank(), 
        strip.text.x = element_blank(),
        panel.spacing = unit(0.5,"cm"),
        axis.ticks.y = element_blank(),
        panel.grid.major.y = element_blank()) +
  geom_text(aes(label = paste("n =", Total)), vjust = 0, hjust = -0.5, size = 3)
Effect of Holy Roman Emperor support alchemy policy (HRE). Proportion of experiments that yielded Robe under otherwise similar conditions, with 95% confidence intervals

FIGURE 15: Effect of Holy Roman Emperor support alchemy policy (HRE). Proportion of experiments that yielded Robe under otherwise similar conditions, with 95% confidence intervals

There was a large and consistent effect of the Holy Roman Empire policy (Figure 15). Having the HRE effect added around 20% to the Robe proportion, both when at r11 and r20 alchemy and with or without adept title.

4.2.2 Advisor effect

ADV <- Robe2 |> 
  mutate(robeSeries = fct_other(Result, keep = "Robe")) |> 
  group_by(Advisor, Condition2, robeSeries) |>
  summarise(number = n(), Condition = mean(Condition)) |> 
  ungroup() |> 
  pivot_wider(
  names_from  = "robeSeries",
  values_from = "number",
  values_fill = 0) |> 
  mutate(Total = Robe+Other,
         PropRobe = Robe/Total)
ADV <- cbind(ADV, 
      binom.confint(ADV$Robe, n = ADV$Total, methods = "wilson"))

ADV <- ADV |> 
  filter(Condition %in% c(1,2,6,7,8,10)) |> #dont like manual subsetting of these rows...
  mutate(Condition3 = (str_replace(Condition2, c("Advisor, "), "")))
  
ADV |> 
ggplot(aes(y = Condition3, x = PropRobe, colour = Advisor)) +
  ylab(NULL) +
  xlab("Proportion Robe") +
  geom_pointrange(aes(xmin = lower, xmax = upper), 
                  size =0.75, linewidth = 1,
                  position = position_dodge(width=1)) +
  scale_colour_manual(values = c("#95a5a6", "#2c3e50")) +
  theme(legend.position = "top") +
  facet_wrap(vars(Condition3), strip.position = "left", ncol = 1, scales = "free_y")+
  theme(strip.text.y.left = element_blank(), 
        strip.text.x = element_blank(),
        panel.spacing = unit(0.5,"cm"),
        axis.ticks.y = element_blank(),
        panel.grid.major.y = element_blank()) +
  geom_text(aes(label = paste("n =", Total)), vjust = 0, hjust = -0.5, size = 3)
Effect of Court Alchemist Advisor position. Proportion of experiments that yielded Robe under otherwise similar conditions, with 95% confidence intervals

FIGURE 16: Effect of Court Alchemist Advisor position. Proportion of experiments that yielded Robe under otherwise similar conditions, with 95% confidence intervals

ADVwide <- ADV |> 
  group_by(Advisor) |> 
  summarise(SumRobes = sum(Robe), SumTots = sum(Total)) |> 
  mutate(SumProp = SumRobes/SumTots)
(ADVpropTestTotal <- prop.test(x = ADVwide$SumRobes, ADVwide$SumTots, alternative = "less"))
## 
##  2-sample test for equality of proportions with continuity correction
## 
## data:  ADVwide$SumRobes out of ADVwide$SumTots
## X-squared = 10.542, df = 1, p-value = 0.0005836
## alternative hypothesis: less
## 95 percent confidence interval:
##  -1.00000000 -0.05767609
## sample estimates:
##    prop 1    prop 2 
## 0.1869919 0.2991304
(ADVpropTests <- 
  split(ADV, as.factor(ADV$Condition3)) |>  
  map(function (df) prop.test(x = df$Robe, n = df$Total, alternative = "less")))
## $`HRE, Adept, r20`
## 
##  2-sample test for equality of proportions with continuity correction
## 
## data:  df$Robe out of df$Total
## X-squared = 2.3721, df = 1, p-value = 0.06176
## alternative hypothesis: less
## 95 percent confidence interval:
##  -1.0000000000  0.0001854689
## sample estimates:
##    prop 1    prop 2 
## 0.2000000 0.2990196 
## 
## 
## $`HRE, r11`
## 
##  2-sample test for equality of proportions with continuity correction
## 
## data:  df$Robe out of df$Total
## X-squared = 2.9495, df = 1, p-value = 0.04295
## alternative hypothesis: less
## 95 percent confidence interval:
##  -1.00000000 -0.00979298
## sample estimates:
##    prop 1    prop 2 
## 0.1807229 0.2911392 
## 
## 
## $`HRE, r20`
## 
##  2-sample test for equality of proportions with continuity correction
## 
## data:  df$Robe out of df$Total
## X-squared = 4.0799, df = 1, p-value = 0.0217
## alternative hypothesis: less
## 95 percent confidence interval:
##  -1.00000000 -0.02935368
## sample estimates:
##    prop 1    prop 2 
## 0.1807229 0.3051643

The advisor effect was clearly smaller in magnitude than the HRE effect, adding consistently around 10% to the Robe proportion in the three contrasts that could be made (Figure 16). The confidence intervals overlapped but the effect was significant in the HRE-r11 and HRE-r20 groups, and highly significant when pooling the three groups (46/246 vs 172/574, \(\chi^{2}\) = 10.54 , df = 1, one-sided p < 0.001).

4.2.3 Adept effect and base success rate

ADEPT <- Robe2 |> 
  mutate(robeSeries = fct_other(Result, keep = "Robe")) |> 
  group_by(Adept, Condition2, robeSeries) |>
  summarise(number = n(), Condition = mean(Condition)) |> 
  ungroup() |> 
  pivot_wider(
  names_from  = "robeSeries",
  values_from = "number",
  values_fill = 0) |> 
  mutate(Total = Robe+Other,
         PropRobe = Robe/Total)
ADEPT <- cbind(ADEPT, 
      binom.confint(ADEPT$Robe, n = ADEPT$Total, methods = "wilson"))

ADEPT <- ADEPT |> 
  filter(!(Condition %in% c(5,6))) |> #dont like manual subsetting of these rows...
  mutate(Condition3 = (str_replace(Condition2, c("Adept, "), "")))
  
ADEPT |> 
ggplot(aes(y = Condition3, x = PropRobe, colour = Adept)) +
  ylab(NULL) +
  xlab("Proportion Robe") +
  geom_pointrange(aes(xmin = lower, xmax = upper), 
                  size =0.75, linewidth = 1,
                  position = position_dodge(width=1)) +
  scale_colour_manual(values = c("#95a5a6", "#2c3e50")) +
  theme(legend.position = "top") +
  facet_wrap(vars(Condition3), strip.position = "left", ncol = 1, scales = "free_y")+
  theme(strip.text.y.left = element_blank(), 
        strip.text.x = element_blank(),
        panel.spacing = unit(0.5,"cm"),
        axis.ticks.y = element_blank(),
        panel.grid.major.y = element_blank()) +
  ggrepel::geom_text_repel(aes(label = paste("n =", Total)), 
                           size = 3, 
                           direction = "x", 
                           min.segment.length = 5, 
                           seed =666)
Effect of Adept title. Proportion of experiments that yielded Robe under otherwise similar conditions, with 95% confidence intervals

FIGURE 17: Effect of Adept title. Proportion of experiments that yielded Robe under otherwise similar conditions, with 95% confidence intervals

ADEPTwide <- ADEPT |> 
  pivot_wider(
  names_from  = c(Adept),
  values_from = "PropRobe") |>
  group_by(Condition3) |> 
  summarise(NO = max(NO, na.rm = T), YES = max(YES, na.rm = T)) |> 
  mutate(difference = YES-NO)
adeptdiff <-  round(mean(ADEPTwide$difference), digits = 4)

(adeptEst <- binom.confint(x= 2, n = 223, methods = "wilson"))
##   method x   n       mean       lower      upper
## 1 wilson 2 223 0.00896861 0.002462972 0.03210504
(baseEst <- binom.confint(x= 0, n = 217, methods = "wilson"))
##   method x   n mean        lower      upper
## 1 wilson 0 217    0 1.704549e-18 0.01739465

The adept effect was too small to be precisely measured with these data (Figure 17), but it is clearly smaller than the HRE and advisor effects. On average (for the 6 contrasts) the effect was to increase the proportion by 0.022 (i.e. to add 2.2% to the success rate), but the estimates varied from -0.006 to 0.08. Although we do not know the exact base rate, it is most reliable to simply estimate the adept effect from the two samples of adept without HRE or advisor effect, because the control group estimates otherwise suffers from uncertainty as well. If we pool the two samples (that only differed in alchemy rank) we get 2 robes out of 223 trials (0.009), with a 95% confidence interval of 0.0025–0.032. We are therefore 95% certain that the true effect of the adept title is less than 3.2%, with a point estimate of 0.9% (minus the base rate).

The base rate is very low, and below the detection limit of the study. No robes resulted from the 217 trials in the two r11/r20 groups without adept title or other effects (from the two lower panels in Figure 17). If we pool these we get a 95% confidence interval of 0–0.017. We are thus 95% certain that the true base rate is below 1.7%, with a point estimate of 0.0%. It should be noted that the base rate is known not to be zero – it is possible to produce the robe without adept title or any other effects active.

4.2.4 Alchemy skill rank, EX, Oxford and aide

There was no effect of alchemy rank on the probability of getting a Robe (Figure 18): in all five comparisons the treatment (r20) and the control group (r11) was very similar to each other, relative to the uncertainty and the readily evident effects of HRE and Advisor.

ALCH <- Robe2 |> 
  mutate(robeSeries = fct_other(Result, keep = "Robe")) |> 
  group_by(Alchemy, Condition2, robeSeries) |>
  summarise(number = n(), Condition = mean(Condition)) |> 
  ungroup() |> 
  pivot_wider(
  names_from  = "robeSeries",
  values_from = "number",
  values_fill = 0) |> 
  mutate(Total = Robe+Other,
         PropRobe = Robe/Total)
ALCH <- cbind(ALCH, 
      binom.confint(ALCH$Robe, n = ALCH$Total, methods = "wilson"))

ALCH <- ALCH |> 
  filter(Condition %in% c(2,6:14)) |> #dont like manual subsetting of these rows...
  mutate(Condition3 = (str_replace(Condition2, c(", r11"), ""))) |> 
  mutate(Condition3 = (str_replace(Condition3, c(", r20"), ""))) |> 
  mutate(Condition3 = (str_replace(Condition3, c("r11"), "Nothing"))) |> 
  mutate(Condition3 = (str_replace(Condition3, c("r20"), "Nothing")))
  
ALCH |> 
ggplot(aes(y = Condition3, x = PropRobe, colour = as.factor((Alchemy)))) +
  ylab(NULL) +
  xlab("Proportion Robe") +
  labs(colour = "Alchemy rank")+
  geom_pointrange(aes(xmin = lower, xmax = upper), 
                  size =0.75, linewidth = 1,
                  position = position_dodge(width=1)) +
  scale_colour_manual(values = c("#95a5a6", "#2c3e50")) +
  theme(legend.position = "top") +
  facet_wrap(vars(Condition3), strip.position = "left", ncol = 1, scales = "free_y")+
  theme(strip.text.y.left = element_blank(), 
        strip.text.x = element_blank(),
        panel.spacing = unit(0.5,"cm"),
        axis.ticks.y = element_blank(),
        panel.grid.major.y = element_blank()) +
  ggrepel::geom_text_repel(aes(label = paste("n =", Total)), 
                           size = 3, 
                           direction = "x", 
                           min.segment.length = 5, 
                           seed =666)
Effect of Alchemy rank (r11 or r20). Proportion of experiments that yielded Robe under otherwise similar conditions, with 95% confidence intervals

FIGURE 18: Effect of Alchemy rank (r11 or r20). Proportion of experiments that yielded Robe under otherwise similar conditions, with 95% confidence intervals

EX equipment had no effect either. Two comparisons were available: In one comparison the treatment group estimate was higher than the control group (Figure 19, top) and in another comparison lower (Figure 19, bottom). In both cases with considerable overlap of confidence intervals. To illuminate the issue further I included the group with Oxford effects on in addition to EX (Figure 19, middle). If anything this group should be higher or at least similar to the group without Oxford. In fact it was lower, and lower than the control group in the top panel. Taken together this shows no measurable effect of EX equipment on Robe success.

EX <- Robe2 |> 
  mutate(robeSeries = fct_other(Result, keep = "Robe")) |> 
  group_by(EX, Condition2, robeSeries) |>
  summarise(number = n(), Condition = mean(Condition)) |> 
  ungroup() |> 
  pivot_wider(
  names_from  = "robeSeries",
  values_from = "number",
  values_fill = 0) |> 
  mutate(Total = Robe+Other,
         PropRobe = Robe/Total)
EX <- cbind(EX, 
      binom.confint(EX$Robe, n = EX$Total, methods = "wilson"))

EX <- EX |> 
  filter(Condition %in% c(1:5)) |> #dont like manual subsetting of these rows...
  mutate(Condition3 = (str_replace(Condition2, c(", Ex"), "")))

EXwide <- EX |> 
  pivot_wider(
  names_from  = c(EX),
  values_from = "PropRobe") |>
  group_by(Condition3) |> 
  summarise(NO = mean(NO, na.rm = T), YES = mean(YES, na.rm = T)) |> 
  mutate(difference = YES-NO)
EXdiff <-  round(mean(EXwide$difference), digits = 4)  

EX |> 
ggplot(aes(y = Condition3, x = PropRobe, colour = EX)) +
  ylab(NULL) +
  xlab("Proportion Robe") +
  geom_pointrange(aes(xmin = lower, xmax = upper), 
                  size =0.75, linewidth = 1,
                  position = position_dodge(width=1)) +
  scale_colour_manual(values = c("#95a5a6", "#2c3e50")) +
  theme(legend.position = "top") +
  facet_wrap(vars(Condition3), strip.position = "left", ncol = 1, scales = "free_y")+
  theme(strip.text.y.left = element_blank(), 
        strip.text.x = element_blank(),
        panel.spacing = unit(0.5,"cm"),
        axis.ticks.y = element_blank(),
        panel.grid.major.y = element_blank()) +
  ggrepel::geom_text_repel(aes(label = paste("n =", Total)),
  size = 3,
  min.segment.length = 5,
  seed =555)
Effect of EX equipment. Proportion of experiments that yielded Robe under otherwise similar conditions, with 95% confidence intervals. Also includes a group with Oxfords on, but otherwise similar to the top panel.

FIGURE 19: Effect of EX equipment. Proportion of experiments that yielded Robe under otherwise similar conditions, with 95% confidence intervals. Also includes a group with Oxfords on, but otherwise similar to the top panel.

The same comparison also reveal no increased Robe success from Oxford skills (for clarity shown separately in Figure 20). Unfortunately only this one contrast of treatment vs. control was available, but if anything success was reduced with Oxfords on which indicates random noise.

OXF <- Robe2 |> 
  mutate(robeSeries = fct_other(Result, keep = "Robe")) |> 
  group_by(Oxfords, Condition2, robeSeries) |>
  summarise(number = n(), Condition = mean(Condition)) |> 
  ungroup() |> 
  pivot_wider(
  names_from  = "robeSeries",
  values_from = "number",
  values_fill = 0) |> 
  mutate(Total = Robe+Other,
         PropRobe = Robe/Total)
OXF <- cbind(OXF, 
      binom.confint(OXF$Robe, n = OXF$Total, methods = "wilson"))

OXF <- OXF |> 
  filter(Condition %in% c(3,5)) |> #dont like manual subsetting of these rows...
  mutate(Condition3 = (str_replace(Condition2, c(", Oxf"), "")))

OXFwide <- OXF |> 
  pivot_wider(
  names_from  = c(Oxfords),
  values_from = "PropRobe") |>
  group_by(Condition3) |> 
  summarise(NO = mean(NO, na.rm = T), YES = mean(YES, na.rm = T)) |> 
  mutate(difference = YES-NO)
OXFdiff <-  round(mean(EXwide$difference), digits = 4) 

OXF |> 
ggplot(aes(y = Condition3, x = PropRobe, colour = Oxfords)) +
  ylab(NULL) +
  xlab("Proportion Robe") +
  geom_pointrange(aes(xmin = lower, xmax = upper), 
                  size =0.75, linewidth = 1,
                  position = position_dodge(width=1)) +
  scale_colour_manual(values = c("#95a5a6", "#2c3e50")) +
  theme(legend.position = "top") +
  facet_wrap(vars(Condition3), strip.position = "left", ncol = 1, scales = "free_y")+
  theme(strip.text.y.left = element_blank(), 
        strip.text.x = element_blank(),
        panel.spacing = unit(0.5,"cm"),
        axis.ticks.y = element_blank(),
        panel.grid.major.y = element_blank()) +
  ggrepel::geom_text_repel(aes(label = paste("n =", Total)),
  size = 3,
  min.segment.length = 5,
  seed =555)
Effect of Oxford skills active. Proportion of experiments that yielded Robe under otherwise similar conditions, with 95% confidence intervals

FIGURE 20: Effect of Oxford skills active. Proportion of experiments that yielded Robe under otherwise similar conditions, with 95% confidence intervals

All trials in the Robe set-up were done with aide in paymaster 100s. However, a comparison with the FAB experiments allows an estimate of a paymaster aide effect to be made since only very few had an aide at all in the FAB trials. The relevant condition is HRE, with rank 11 or 20 alchemy. These were pooled to increase sample size (rank had no effect). The FAB experiments were done with HRE, at r12–14 (included in Table 1 for convenience). Figure 21 shows that having aide in paymaster did not improve the chance of producing a Robe. If anything, the probability was lower with paymaster but the difference is well within the uncertainty.

Paymaster <- read_ods("~\\FABtory\\paymaster.ods", sheet =1)
Paymaster$Condition3 <- (as.factor(Paymaster$Condition3))
Paymaster$Condition3 <-fct_relevel(Paymaster$Condition3, "HRE (r11+r20)", "HRE (r12-r14)")

Paymaster |> 
ggplot(aes(y = Condition3, x = PropRobe, colour = Paymaster)) +
  ylab(NULL) +
  xlab("Proportion Robe") +
  geom_pointrange(aes(xmin = lower, xmax = upper), 
                  size =0.75, linewidth = 1,
                  position = position_dodge(width=1)) +
  scale_colour_manual(values = c("#95a5a6", "#2c3e50")) +
  theme(legend.position = "top") +
  facet_wrap(vars(Condition3), strip.position = "left", ncol = 1, scales = "free_y")+
  theme(strip.text.y.left = element_blank(), #element_text(angle = 0, hjust = 0),
        strip.text.x = element_blank(),
        panel.spacing = unit(0,"cm"),
        axis.ticks.y = element_blank(),
        panel.grid.major.y = element_blank()) +
  geom_text(aes(label = paste("n =", Total)), vjust = -1, hjust = -0.5, size = 3)
Effect of aide in Paymaster. Proportion of experiments that yielded Robe under otherwise similar conditions, with 95% confidence intervals. Note that the control group is from the FAB trials.

FIGURE 21: Effect of aide in Paymaster. Proportion of experiments that yielded Robe under otherwise similar conditions, with 95% confidence intervals. Note that the control group is from the FAB trials.

Note that the scale varies in Figure 1821.

4.2.5 Effects on failure and minor success

#proportion minorsuccess
RST <- RobeSummaryTable
#remove row for totals
RST <- RST |> 
  filter(Batch < 27) |> 
  mutate(Condition = as.numeric(Condition))
RST <- RST |> 
  mutate(Minor = (FineVelvet+Justaucorps+Waistcoat)) 
RST <- RST |> 
  mutate(propMinor = (FineVelvet+Justaucorps+Waistcoat)/Total) 
RST <- RST |> left_join(Design |> 
                          select(Condition, Condition2), by="Condition")
RST <- cbind(RST, 
      MinorProp=binom.confint(RST$Minor, n = RST$Total, methods = "wilson"))

#combine batches
RST2 <- RST |> 
  group_by(Condition2) |> 
  summarise(
    Condition = mean(Condition),
    Failure = sum(Failure),
    FineVelvet = sum(FineVelvet),
    Justaucorps = sum(Justaucorps),
    Robe = sum(Robe),
    Waistcoat = sum(Waistcoat),
    Total = sum(Total),
    Minor = sum(Minor)
  ) |> 
  mutate(propMinor = (FineVelvet+Justaucorps+Waistcoat)/Total,
         propRobe = Robe/Total,
         propFailure = Failure/Total,
         propJustau = Justaucorps/Total,
         propVelvet = FineVelvet/Total,
         propWaist = Waistcoat/Total,
         propJustau_minor = Justaucorps/Minor,
         propVelvet_minor = FineVelvet/Minor,
         propWaist_minor = Waistcoat/Minor
         ) 
RST2  <- RST2 |> 
  mutate(Condition2 = as.factor(Condition2)) |> 
  mutate(Condition2 = fct_reorder(Condition2, propRobe, .fun = mean)) |> 
  mutate(Condition2 = fct_rev(Condition2))
RST2 <- cbind(RST2, 
              propMinor = binom.confint(RST2$Minor, n = RST2$Total, methods = "wilson"))
#overall proportion minor success:
propMinorOverall <- sum(RST2$Minor)/sum(RST2$Total)
propMinorOverall2 <- mean(RST2$propMinor)

RST2 |> 
  ggplot(aes(y = Condition2, x = propMinor)) +
  ylab(NULL) +
  xlab("Proportion minor success") +
  geom_vline(xintercept = propMinorOverall, linetype = "dashed", colour = "#95a5a6")+
  geom_pointrange(aes(xmin = propMinor.lower, xmax = propMinor.upper), 
                  size =0.5, linewidth = 0.75,
                  position = position_dodge(width=1)) +
  scale_x_continuous(breaks = seq(0, 1, by = 0.2), limits = c(0,1))
Proportion of minor success (Fine Velvet, Justaucorps or Waistcoat) under different experimental conditions

FIGURE 22: Proportion of minor success (Fine Velvet, Justaucorps or Waistcoat) under different experimental conditions

So far we have only considered Robes. We will now look more closely at the other outcomes: failure and minor successes.

The proportion of minor success (justaucorps, waistcoat and fine velvet together) was remarkably constant under all conditions (overall mean = 0.361), and thus seems fixed at a ratio of around 2:3 (i.e. 40% minor success, 60% failures and huge success, or maybe 35:65), unaffected by the factors that influence huge success (Figure 22).

The surprising consequence is therefore that all that can be attained by changing the conditions is to shift the share of outcomes within these two categories.

RST2 <- cbind(RST2, 
              propFailure = binom.confint(RST2$Failure, n = RST2$Total, methods = "wilson"))
RST2 <- cbind(RST2, 
              propRobe = binom.confint(RST2$Robe, n = RST2$Total, methods = "wilson"))
RST2 <- cbind(RST2, 
              propJustau = binom.confint(RST2$Justaucorps, n = RST2$Total, methods = "wilson"))
RST2 <- cbind(RST2, 
              propVelvet = binom.confint(RST2$FineVelvet, n = RST2$Total, methods = "wilson"))
RST2 <- cbind(RST2, 
              propWaist = binom.confint(RST2$Waistcoat, n = RST2$Total, methods = "wilson"))
RST2 <- cbind(RST2, 
              propJustau_minor = binom.confint(RST2$Justaucorps, n = RST2$Minor, methods = "wilson"))
RST2 <- cbind(RST2, 
              propVelvet_minor = binom.confint(RST2$FineVelvet, n = RST2$Minor, methods = "wilson"))
RST2 <- cbind(RST2, 
              propWaist_minor = binom.confint(RST2$Waistcoat, n = RST2$Minor, methods = "wilson"))
rank11 <- c(6,7,9,11,12)
RST2 <- RST2 |> 
  mutate(AlchemyRank = ifelse(Condition %in% rank11, 11, 20))

propFailureOverall <- sum(RST2$Failure)/sum(RST2$Total)
RST2 |> 
  ggplot(aes(y = Condition2, x = propFailure.mean)) +
  ylab(NULL) +
  xlab("Proportion Failure") +
  geom_vline(xintercept = propFailureOverall, linetype = "dashed", colour = "#95a5a6")+
  geom_pointrange(aes(xmin = propFailure.lower, xmax = propFailure.upper), 
                  size =0.5, linewidth = 0.75)+
  scale_x_continuous(breaks = seq(0, 1, by = 0.2), limits = c(0,1))

propRobeOverall <- sum(RST2$Robe)/sum(RST2$Total)
RST2 |> 
  ggplot(aes(y = Condition2, x = propRobe.mean)) +
  ylab(NULL) +
  xlab("Proportion Adept's Robe") +
  geom_vline(xintercept = propRobeOverall, linetype = "dashed", colour = "#95a5a6")+
  geom_pointrange(aes(xmin = propRobe.lower, xmax = propRobe.upper), 
                  size =0.5, linewidth = 0.75)+
  scale_x_continuous(breaks = seq(0, 1, by = 0.2), limits = c(0,1))

propJustauOverall <- sum(RST2$Justaucorps)/sum(RST2$Total)

propJustauR11 <- RST2 |>  
  filter(AlchemyRank == 11) |> 
  summarise(out = sum(Justaucorps)/sum(Total)) |> 
  pull(out)
propJustauR20 <- RST2 |>  
  filter(AlchemyRank == 20) |> 
  summarise(out = sum(Justaucorps)/sum(Total)) |> 
  pull(out)

JustauPropAlchemy <- RST2 |>
  group_by(AlchemyRank) |>
  summarise(Justaucorps = sum(Justaucorps), Total = sum(Total))

(JustauAlchRes <- 
    binom.wilson(JustauPropAlchemy$Justaucorps, JustauPropAlchemy$Total))
##   method   x    n       mean     lower     upper
## 1 wilson  15  540 0.02777778 0.0169047 0.0453220
## 2 wilson 178 1422 0.12517581 0.1089796 0.1433917
JustauAlchRes$Group <- as_factor(c("r11", "r20"))
#test if equal proportions
(JustauAlchResTest <- 
    prop.test(x = JustauAlchRes$x, JustauAlchRes$n, alternative = "two.sided"))
## 
##  2-sample test for equality of proportions with continuity correction
## 
## data:  JustauAlchRes$x out of JustauAlchRes$n
## X-squared = 40.77, df = 1, p-value = 0.0000000001713
## alternative hypothesis: two.sided
## 95 percent confidence interval:
##  -0.12076502 -0.07403104
## sample estimates:
##     prop 1     prop 2 
## 0.02777778 0.12517581

RST2 |> 
  ggplot(aes(y = Condition2, x = propJustau.mean, 
             colour = as.factor(AlchemyRank))) +
  ylab(NULL) +
  xlab("Proportion Admiral Justaucorps") +
  geom_vline(xintercept = propJustauOverall, linetype = "dashed", 
             colour = "#95a5a6")+
  geom_vline(xintercept = propJustauR11, linetype = "dashed", 
             colour = "#377eb8")+
  geom_vline(xintercept = propJustauR20, linetype = "dashed", 
             colour = "#B51F2E")+
  geom_pointrange(aes(xmin = propJustau.lower, xmax = propJustau.upper), 
                  size =0.5, linewidth = 0.75)+
  scale_x_continuous(breaks = seq(0, 1, by = 0.2), limits = c(0,1))+
  scale_colour_manual(values = c("#377eb8", "#B51F2E"))+
  theme( 
    legend.position = c(0.95,0.95),
    legend.justification = c(1,1),
  )+
  labs(colour = "Alchemy rank")
 

propVelvetOverall <- sum(RST2$FineVelvet)/sum(RST2$Total)
RST2 |> 
  ggplot(aes(y = Condition2, x = propVelvet.mean)) +
  ylab(NULL) +
  xlab("Proportion Fine Velvet") +
  geom_vline(xintercept = propVelvetOverall, linetype = "dashed", 
             colour = "#95a5a6")+
  geom_pointrange(aes(xmin = propVelvet.lower, xmax = propVelvet.upper), 
                  size =0.5, linewidth = 0.75)+
  scale_x_continuous(breaks = seq(0, 1, by = 0.2), limits = c(0,1))

propWaistOverall <- sum(RST2$Waistcoat)/sum(RST2$Total)
RST2 |> 
  ggplot(aes(y = Condition2, x = propWaist.mean)) +
  ylab(NULL) +
  xlab("Proportion Waistcoat") +
  geom_vline(xintercept = propWaistOverall, linetype = "dashed", 
             colour = "#95a5a6")+
  geom_pointrange(aes(xmin = propWaist.lower, xmax = propWaist.upper), 
                  size =0.5, linewidth = 0.75)+
  scale_x_continuous(breaks = seq(0, 1, by = 0.2), limits = c(0,1))
Proportion of all possible outcomes: Failure; Robe; Justaucorps; Fine Velvet; Waistcoat. Dashed lines show the mean for each item.Proportion of all possible outcomes: Failure; Robe; Justaucorps; Fine Velvet; Waistcoat. Dashed lines show the mean for each item.Proportion of all possible outcomes: Failure; Robe; Justaucorps; Fine Velvet; Waistcoat. Dashed lines show the mean for each item.Proportion of all possible outcomes: Failure; Robe; Justaucorps; Fine Velvet; Waistcoat. Dashed lines show the mean for each item.Proportion of all possible outcomes: Failure; Robe; Justaucorps; Fine Velvet; Waistcoat. Dashed lines show the mean for each item.

FIGURE 23: Proportion of all possible outcomes: Failure; Robe; Justaucorps; Fine Velvet; Waistcoat. Dashed lines show the mean for each item.

Figure 23 shows the proportion of all possible outcomes, including Robes again for ease of comparison.

Since proportion of minor success was constant, the proportion of failure (Figure 23, upper panel) was in consequence largely an inverse mirror of the proportion of Robes: Conditions that increased the proportion of Robes lowered the proportion of failures and vice versa. As with Robes, we can readily see three clusters: Advisor has the lowest amount of failures, HRE a bit more, and considerably lower without HRE, with adept less clear (Figure 23).

The proportion of the various minor successes appeared to be unaffected by changing the conditions, except an effect of alchemy rank on Justaucorps, discussed below.

#proportions innen minor
#prop.test
propJustauOverall_Minor <- sum(RST2$Justaucorps)/(sum(RST2$Justaucorps)+sum(RST2$Waistcoat)+sum(RST$FineVelvet))
propJustauR11_Minor <- RST2 |>  
  filter(AlchemyRank == 11) |> 
  summarise(out = sum(Justaucorps)/sum(Minor)) |> 
  pull(out)
propJustauR20_Minor <- RST2 |>  filter(AlchemyRank == 20) |> 
  summarise(out = sum(Justaucorps)/sum(Minor)) |> 
  pull(out)
RST2 |> 
  ggplot(aes(y = Condition2, x = propJustau_minor.mean, 
             colour = as.factor(AlchemyRank))) +
  ylab(NULL) +
  xlab("Proportion Justaucorps among minor successes") +
  geom_vline(xintercept = propJustauOverall_Minor, linetype = "dashed", 
             colour = "#95a5a6")+
  geom_vline(xintercept = propJustauR11_Minor, linetype = "dashed", 
             colour = "#377eb8")+
  geom_vline(xintercept = propJustauR20_Minor, linetype = "dashed", 
             colour = "#B51F2E")+
  geom_pointrange(aes(xmin = propJustau_minor.lower, xmax = propJustau_minor.upper), 
                  size =0.5, linewidth = 0.75)+
  scale_x_continuous(breaks = seq(0, 1, by = 0.2), limits = c(0,1))+
  scale_colour_manual(values = c("#377eb8", "#B51F2E"))+
  theme( 
    legend.position = c(0.95,0.95),
    legend.justification = c(1,1),
  )+
  labs(colour = "Alchemy rank")


propVelvetOverall_Minor <- sum(RST2$FineVelvet)/(sum(RST2$Justaucorps)+sum(RST2$Waistcoat)+sum(RST$FineVelvet))
propVelvetR11_Minor <- RST2 |>  
  filter(AlchemyRank == 11) |> 
  summarise(out = sum(FineVelvet)/sum(Minor)) |> 
  pull(out)
propVelvetR20_Minor <- RST2 |>  
  filter(AlchemyRank == 20) |> 
  summarise(out = sum(FineVelvet)/sum(Minor)) |> 
  pull(out)

RST2 |> 
  ggplot(aes(y = Condition2, x = propVelvet_minor.mean, 
             colour = as.factor(AlchemyRank))) +
  ylab(NULL) +
  xlab("Proportion Fine Velvet among minor successes") +
  geom_vline(xintercept = propVelvetOverall_Minor, linetype = "dashed", 
             colour = "#95a5a6")+
  geom_vline(xintercept = propVelvetR11_Minor, linetype = "dashed", 
             colour = "#377eb8")+
  geom_vline(xintercept = propVelvetR20_Minor, linetype = "dashed", 
             colour = "#B51F2E")+
  geom_pointrange(aes(xmin = propVelvet_minor.lower, xmax = propVelvet_minor.upper), 
                  size =0.5, linewidth = 0.75)+
  scale_x_continuous(breaks = seq(0, 1, by = 0.2), limits = c(0,1))+
  scale_colour_manual(values = c("#377eb8", "#B51F2E"))+
  theme( 
    legend.position = c(0.95,0.95),
    legend.justification = c(1,1),
  )+
  labs(colour = "Alchemy rank")

propWaistOverall_Minor <- 
  sum(RST2$Waistcoat)/(sum(RST2$Justaucorps)+sum(RST2$Waistcoat)+sum(RST$FineVelvet))
propWaistR11_Minor <- RST2 |>  
  filter(AlchemyRank == 11) |> 
  summarise(out = sum(Waistcoat)/sum(Minor)) |> 
  pull(out)
propWaistR20_Minor <- 
  RST2 |>  filter(AlchemyRank == 20) |> 
  summarise(out = sum(Waistcoat)/sum(Minor)) |> 
  pull(out)
RST2 |> 
  ggplot(aes(y = Condition2, x = propWaist_minor.mean, 
             colour = as.factor(AlchemyRank))) +
  ylab(NULL) +
  xlab("Proportion Waistcoat among minor successes") +
  geom_vline(xintercept = propWaistOverall_Minor, linetype = "dashed", 
             colour = "#95a5a6")+
  geom_vline(xintercept = propWaistR11_Minor, linetype = "dashed", 
             colour = "#377eb8")+
  geom_vline(xintercept = propWaistR20_Minor, linetype = "dashed", 
             colour = "#B51F2E")+
  geom_pointrange(aes(xmin = propWaist_minor.lower, xmax = propWaist_minor.upper), 
                  size =0.5, linewidth = 0.75)+
  scale_x_continuous(breaks = seq(0, 1, by = 0.2), limits = c(0,1))+
  scale_colour_manual(values = c("#377eb8", "#B51F2E"))+
  theme( 
    legend.position = c(0.95,0.95),
    legend.justification = c(1,1),
  )+
  labs(colour = "Alchemy rank")
Proportion of the three possible outcomes of minor success under different conditions. Dashed lines shows the meanProportion of the three possible outcomes of minor success under different conditions. Dashed lines shows the meanProportion of the three possible outcomes of minor success under different conditions. Dashed lines shows the mean

FIGURE 24: Proportion of the three possible outcomes of minor success under different conditions. Dashed lines shows the mean

Figure 24 shows the proportion of outcomes under different conditions when the result was a minor success (expressed as share of the sum of minor success, not total trials).

There are 3 different minor success outcomes possible. Among these, Admiral Justaucorps can be considered a higher tier outcome than Fine Velvet or Waistcoats. If we look at the outcome within the minor success group there are no effects of the experimental conditions that did affect huge success: Justaucorps is not any more likely with adept or HRE policy or advisor active. However, there is now a noticeable effect of alchemy rank (which had no effect on Robes or failure). Significantly more Justaucorps was produced at r20 than at r11 alchemy, under all conditions measured where alchemy rank could be contrasted (Figure 24, upper panel). Overall, the proportion of Justaucorps at r11 alchemy was clearly lower than at r20 (15/540 vs 178/1422, \(\chi^{2}\) = 40.77 , df = 1, two-sided p < 0.0001.

In other words, if you for some reason want to make Admiral Justaucorps it doesn’t help to have adept title, or HRE or advisor position. Only higher rank alchemy skill will help. It is a rare outcome at rank 11 – the base probability can be estimated at 2.8%. At r20 it increased to 12.5%, i.e. gain about 1% per rank. At r20 the three minor success possibilities are equally likely. For the other two items there did not seem to be any effects apart from both simply decreasing a little in frequency at r20 in consequence of increased Justaucorps (Figure 24, two lower panels).


#per batch:
RST |> 
  ggplot(aes(y = Failure/Total, x = Robe/Total)) +
  geom_segment(aes(x = 0, y = 0.65, xend = 0.65, yend = 0),
               colour = "#95a5a6", 
               linetype ="dashed", 
               linewidth = 1)+
  annotate("text", x = 0.57, y = 0.21, 
           label ="Fixed 65% \ny = 0.65 − x",
           colour = "#95a5a6") +
  ylim(0,0.7) +
  xlim(0,0.7) +
  ggpmisc::stat_ma_line(se = FALSE, colour = "#B51F2E") +
  ggpmisc::stat_ma_eq(mapping = use_label(c("eq", "R2")), 
                      colour = "#B51F2E", label.x = 0.15, label.y = 0.9) +
  geom_point(size= 3, shape = 21, fill = "black", colour = "white")
#per condition (more precise, but fewer data points):
RST2 |> 
  ggplot(aes(y = Failure/Total, x = Robe/Total)) +
  geom_segment(aes(x = 0, y = 0.65, xend = 0.65, yend = 0),
               colour = "#95a5a6", 
               linetype ="dashed", 
               linewidth = 1)+
  annotate("text", x = 0.57, y = 0.21, 
           label ="Fixed 65% \ny = 0.65 − x",
           colour = "#95a5a6") +
  ylim(0,0.7) +
  xlim(0,0.7) +
  ggpmisc::stat_ma_line(se = FALSE, colour = "#B51F2E") +
  ggpmisc::stat_ma_eq(mapping = use_label(c("eq", "R2")), 
                      colour = "#B51F2E", label.x = 0.15, label.y = 0.9) +
  geom_point(size= 3, shape = 21, fill = "black", colour = "white")

cor.test(RST$Failure/RST$Total, RST$Robe/RST$Total)
## 
##  Pearson's product-moment correlation
## 
## data:  RST$Failure/RST$Total and RST$Robe/RST$Total
## t = -11.85, df = 24, p-value = 0.00000000001622
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  -0.9657742 -0.8360694
## sample estimates:
##        cor 
## -0.9241368
cor.test(RST2$Failure/RST2$Total, RST2$Robe/RST2$Total)
## 
##  Pearson's product-moment correlation
## 
## data:  RST2$Failure/RST2$Total and RST2$Robe/RST2$Total
## t = -14.783, df = 12, p-value = 0.000000004592
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  -0.9918362 -0.9164908
## sample estimates:
##        cor 
## -0.9736247
ppcor::pcor.test(RST$Robe, RST$Failure, RST$Total)
##     estimate           p.value statistic  n gp  Method
## 1 -0.8950273 0.000000001567685 -9.623968 26  1 pearson
ppcor::pcor.test(RST2$Robe, RST2$Failure, RST2$Total)
##     estimate       p.value statistic  n gp  Method
## 1 -0.9100018 0.00001583437 -7.279556 14  1 pearson
Scatterplot of proportion robe vs. proportion failures per experimental batch (upper) and condition (lower). Dotted line shows a situation where the sum of robes and failures have a fixed share of 65% of the total (y = 0.65-x). The red line is the actual regressionScatterplot of proportion robe vs. proportion failures per experimental batch (upper) and condition (lower). Dotted line shows a situation where the sum of robes and failures have a fixed share of 65% of the total (y = 0.65-x). The red line is the actual regression

FIGURE 25: Scatterplot of proportion robe vs. proportion failures per experimental batch (upper) and condition (lower). Dotted line shows a situation where the sum of robes and failures have a fixed share of 65% of the total (y = 0.65-x). The red line is the actual regression

Failure and robes were very strongly negatively related, in a way consistent with a common share fixed at 60-65% of the outcomes (Figure 25). In the figure I used a model II major axis regression instead of ordinary least squares, because we do not want to predict y from x but rather describe the slope of the relationship, and both variables are subject to random variation.1

In fact it is inevitable to be such a strong negative relationship if the sum of outcomes that is minor success (Figure 22) is fixed, leaving robe a constant percentage to share with failure, irrespective of experimental conditions. Changing the conditions will merely slide the outcome proportions up and down along the line in Figure 25.

Moreover, inspection of a correlation matrix between all the five outcomes (Figure 26) show that it is only the proportion of robes that is strongly related to failure. Proportion justaucorps is negatively related to fine velvet and waistcoat but less so, as can be expected because there are three outcomes that covary and not only two like for robe and failure.2

RST2matrix <- RST2 |> 
  select(propRobe, propFailure, propMinor, propJustau, propVelvet, propWaist, propJustau_minor, propVelvet_minor, propWaist_minor) |> 
  cor()

corrplot.mixed(RST2matrix,
 upper = "ellipse",
 lower = "number",
 order = 'AOE', 
 tl.col = 'black',
 tl.pos = "lt",
 diag = "n",
 tl.srt = 30,
 bg = "#EBEBEB",
 #mar = c(0,1,1,1)
 )
Correlogram for proportion of different outcomes. Lower triangular shows the correlation matrix, upper triangular shows the ellipsis matrix, where the eccentricity of the ellipse is scaled to the correlation value

FIGURE 26: Correlogram for proportion of different outcomes. Lower triangular shows the correlation matrix, upper triangular shows the ellipsis matrix, where the eccentricity of the ellipse is scaled to the correlation value

4.2.6 Non-randomness and biases in the underlying RNG algorithm

# sequence plots robe vs non-robe
#whole sequence:
ggplot(Robe2, aes(x=Sequence, fill = fct_rev(Result))) +
  geom_bar(position = "fill", width = 1) +
  scale_fill_brewer(palette = "RdBu", direction = -1) +
  #scale_fill_viridis_d(option = "turbo", direction = 1)+
  #scale_x_continuous(breaks = seq(0, 2000, by = 100)) +
  scale_x_continuous(expand = expansion(mult = .025)) +
  scale_y_continuous(breaks = NULL) +
  theme(legend.background = element_rect(fill = "#EBEBEB"),
        legend.key = element_rect(fill = NA),
        legend.position = "top",
        axis.text.y = element_text(size = rel(1.2)),
        legend.justification = c(0.5, 0)) +
  guides(fill = guide_legend(reverse = TRUE, title = NULL)) +
  xlab("Sequence") +
  ylab(NULL)
Sequence of outcome for all robe experiments

FIGURE 27: Sequence of outcome for all robe experiments

A fundamental assumption in the analyses presented above is that each trial is statistically independent and that the probability of success is the same for all trials for which a confidence interval is calculated. This need not be the case and should be confirmed.

To test for the presence of biases in the pseudo-random number generator algorithm used, we can look at the sequence of outcomes (Figure 27). Non-randomness would result in more clusters of the same result, or more evenly spread out results than expected by chance. One way of measuring this is by counting the number of “runs” – segments of the sequence with the same value. For example if there are certain “lucky times” (where one should continue producing), and certain bad ones (where one should immediately cancel), there would be more runs in the data than expected by chance.

We only consider a binary outcome of Robe vs. non-Robe, shown in Figure 28 below.3 There was a highly significant deviation from randomness in the complete sequence (Wald-Wolfowitz runs-test, p = 0.003).

ggplot(Robe2, aes(x=Sequence, fill = fct_rev(robeSeries))) +
  geom_bar(position = "fill", width = 1) +
  scale_fill_manual(values = c("#95a5a6","#B51F2E")) +
  #scale_x_continuous(breaks = seq(0, 2000, by = 100)) +
  scale_x_continuous(expand = expansion(mult = .025)) +
  scale_y_continuous(breaks = NULL) +
  theme(legend.background = element_rect(fill = "#EBEBEB"),
        legend.key = element_rect(fill = NA, color = NA),
        legend.position = "top",
        axis.text.y = element_text(size = rel(1.2)),
        legend.justification = c(0.5, 0)) +
  guides(fill = guide_legend(reverse = TRUE, title = NULL)) +
  xlab("Sequence") +
  ylab(NULL)
Sequence of outcome for all robe experiments, dichotomized

FIGURE 28: Sequence of outcome for all robe experiments, dichotomized

However, this is entirely as expected because we introduced a potential source of non-randomness, namely changing the conditions. If the conditions indeed affect the outcome of the experiments we thus cannot use the complete sequence to distinguish between the effect of the conditions and the presence of any other non-randomness.

Instead we must look at the batch sequences separately (Figure 29), or the combined sequence of several batches done under the same experimental conditions (Figure 30). These two can differ, for example if closing and starting the production dialogue window somehow matters: Then we should find a deviation when looking at combined sequences from several batches, but not when looking at single batches.4

# per batch:
ggplot(Robe2, aes(x=BatSeq, fill = fct_rev(robeSeries))) +
  geom_bar(position = "fill", width = 1) +
  facet_wrap(vars(fct_rev(Condition3), GroupBatch), strip.position = "left", ncol = 1) +
  #scale_fill_viridis_d(option = "turbo", direction = 1)+
  scale_fill_manual(values = c("#95a5a6","#B51F2E")) +
  scale_x_continuous(breaks = seq(0, 120, by = 20)) +
  scale_y_continuous(breaks = NULL) +
  theme(legend.background = element_rect(fill = "#EBEBEB"),
        legend.key = element_rect(fill = NA, color = NA),
        legend.position = "top",
        axis.text.y = element_text(size = rel(1.2)),
        legend.justification = c(0.5, 0)) +
  guides(fill = guide_legend(reverse = TRUE, title = NULL)) +
  theme(strip.text.y.left = element_blank(), #element_text(angle = 0, hjust = 0),
        strip.text.x = element_blank(),
        panel.spacing = unit(0.05,"cm")) +
  xlab("Sequence") +
  ylab(NULL)
Sequence of outcome for robe experiments, per batch

FIGURE 29: Sequence of outcome for robe experiments, per batch

# per condition:
# first make a sequence within condition.

Robe2 <- Robe2 |> 
  group_by(Condition) |> 
  mutate(StartSeq = min(Sequence),
         CondSeq = Sequence-StartSeq+1)
Robe2 <- ungroup(Robe2)
         
ggplot(Robe2, aes(x=CondSeq, fill = fct_rev(robeSeries))) +
  geom_bar(position = "fill", width = 1) +
  facet_wrap(vars(fct_rev(Condition3)), strip.position = "left", ncol = 1) +
  #scale_fill_viridis_d(option = "turbo", direction = 1)+
  scale_fill_manual(values = c("#95a5a6","#B51F2E")) +
  scale_x_continuous(breaks = seq(0, 220, by = 20)) +
  scale_y_continuous(breaks = NULL) +
  theme(legend.background = element_rect(fill = "#EBEBEB"),
        legend.key = element_rect(fill = NA, color = NA),
        legend.position = "top",
        axis.text.y = element_text(size = rel(1.2)),
        legend.justification = c(0.5, 0)) +
  guides(fill = guide_legend(reverse = TRUE, title = NULL)) +
  theme(strip.text.y.left = element_blank(), #element_text(angle = 0, hjust = 0),
        strip.text.x = element_blank(),
        panel.spacing = unit(0.05,"cm")) +
  xlab("Sequence") +
  ylab(NULL)
Sequence of outcome for robe experiments, per condition

FIGURE 30: Sequence of outcome for robe experiments, per condition

There were very few significant deviations from non-randomness of runs in the separate batches and none in the combined batches under same conditions (runs-tests results in Appendix), and considering the number of tests performed is as expected under randomness. Hence, the pseudo-random number generator algorithm generating the results appears to be unbiased and in accordance with a random process. This result — presence of non-randomness in the complete sequence but not in the batches — therefore give additional statistical confirmation that the experimental conditions affected the outcome.

Another approach to detecting non-randomness is to consider the sequence of outcomes as a time-series and look for auto-correlation. Auto-correlation is that a time series is correlated with a lagged version of itself. This could for example be caused by cycles or trends, or in general if the outcome of one experiment is related to the outcome of the previous experiment (or a certain number of steps away).

Auto-correlation function plots (ACF) and partial auto-correlation function plots (i.e., controlled for auto-correlation at shorter lags) are presented in the Appendix. Again, any (weak) auto correlation could only be seen in the complete sequence of experiments and not in the separate batches, as expected if the only source of non-randomness in the outcome of the experiments was varying the factors studied. In other words, the time-series under constant conditions looked like white noise which is what we can expect from a random process.

5 Discussion

“I guess we’ll be traveling in uncharted waters.”
“That’ll be fun”, Phil said.5

Lemony Snicket (A Series of Unfortunate Events)

In the English version of UWO the descriptions in game of adept title, HRE position and advisor all refer to increased “chance of success” of alchemy experiments. This is somewhat vague, as it does not explicitly state if it refers to “huge success” or simply any success (as opposed to failure) or both. The results presented here show that these effects specifically target the chance of “huge success” and have no effect on the other outcomes.

Compared to the normal rate (with adept title) of approx. 1 robe or biretta from 100 experiments, it is clear that the HRE effect is enormous: with HRE I got approximately 1 robe per 5 experiments, or 20% success. With also advisor title the success increased 10% more, to 30%.

It was surprising that the general HRE effect is larger than the court advisor effect. It would arguably have made more sense if it was the other way around. One of the wider ramifications of this finding is that the other HRE effects perhaps are of the same magnitude, which fits with observations of e.g. the ganador drop rate HRE effect.

Making the FAB album during a HRE boost is obviously saving a lot of materials and suffering, and as shown here is easily done for any character. Even low level ones in a starter barca, provided they have access to rank 2 quarters (and some help).

However, deciding to do further experiments on Robes did not save a lot of materials and suffering.

By comparing experiments where certain conditions were manipulated and all other factors were held constant, it was possible to measure the effect of various factors thought to possibly influence the success of alchemy experiments. There was no discernible effect of having or not having Oxford production skills active (including item improvement technique). If anything, the success was better with Oxfords off. Also, the EX gear for better tier great success did not seem to influence alchemy experiments. Alchemy rank and paymaster aide rank had no effect either. All this is as expected from the “alchemy experiments are different” camp, and supports the view that huge success in alchemy experiments is not analogous to high tier great success of normal crafting.

However, alchemy rank did have an effect on minor success, with higher rank increasing the probability of admiral justaucorps. The magnitude of the effect was estimated at +1% per skill rank above minimum requirement. This suggests that the minor success outcome may be influenced by the same factors as normal crafting. But, why then did only alchemy rank effect the outcome of minor success? I suspect that Oxford and EX actually did have an effect, but only on the stats of the items. This was not tested, and the data is now lost since it was not kept track of where each Adept’s Robe originated from. Just like Darwin (that did not label what particular island his Finches collected in the Galapagos had been obtained from), I can say in hindsight that this should have been done. It must be left to future studies to investigate if alchemy rank, Oxford and EX affects the stats of minor and huge success alchemy experiments.

An unexpected result was that the rate of minor success was constant under all treatments. Increasing the rate of justaucorps by having higher alchemy rank did not change the rate of failures or robes, but only shuffled the proportions of the other minor success options within their fixed common share of all outcomes.

My interpretation is this: that the factors influencing chance of great success in normal crafting play no role in alchemy experiments because unlike normal crafting, rate of failure is not a separate parameter in alchemy experiments. It is simply the inverse of the rate of huge success (Figure 25) because the minor success rate is fixed.

For some alchemy experiments more than one kind also of great success is possible (such as plates from processed lumber and metal works). I do not have any data to say what, if anything, might affect the rates of different great success. I also have no data on the different normal successes for the recipes other than robe. A reasonable conjecture is that these are also affected by alchemy rank, and that their common share of the outcomes is constant like for the robe recipe.

Perhaps surprisingly, there was no measurable effect of having the Adept title, but it was with a high degree of confidence measured to be less than 3%. It may be 1%. However, larger sample sizes than obtained here would be needed to precisely estimate such small effects. This is illustrated by the replication done for some conditions, that showed considerable inter-batch variation (sometimes of the same magnitude as among conditions). Differences between batches subject to the exact same conditions could be mistaken for some kind of bias in the RNG6, but in reality is what is expected from small samples from a random process, shown by tests done here that failed to detect any non-randomness.

The effect of adept is clearly very small compared to the HRE effects, and in practice does not matter under HRE conditions. However, outside of HRE it does matter. In fact, if the adept effect is indeed + 1% I guess the base rate without adept title is 0.1%. In terms of expected materials consumed an increase from 0.1% to even 1% success is substantial, whereas an increase from 30 to 31% is negligible.

Since the adept effect is so small I did not try to test another uncertainty: if one could leech the adept effect by being apprentice to an adept. It is feasible that this is the case (like for some other titles), and could be worth exploiting for obtaining FAB under normal situations when the HRE effect is absent. However, one could not then simultaneously get the +1 alchemy from being apprentice to an alchemy meister. In the FAB experiments all characters were apprentice to a meister for the +1. There is no reason to think this could have affected the outcome because the effect on success is the other way around – for the meister, not the apprentice, and such effects would not have affected the chance of huge success anyway (according to the present report).

The data from FAB experiments on robe success were collected in a slightly different way from the Robe experiments. The gathering of data from one player was terminated when a robe was obtained during the FAB study, whereas in the Robe experiments it was terminated when no more base clothes were left in the inventory. Thus one could argue that the FAB setup would bias the results in favour of success compared to the Robe setup. However, if the observations are independent this would in fact not create a bias because the dataseries could be considered as continuing in the next player, in the same way as for the Robe experiments.7

It would have been interesting to see what the individual effect of court alchemist is compared to the global effect for all supporters of the HRE policy. If the effects found in this study are additive it should be +10%. This was not possible to fully test here since the only individual with the advisor effect also by necessity had the global effect active, so no player had only the HRE advisor position. This must be tested during elections where there is no global alchemy success policy but court alchemist position is still available. But such elections seem to be rare – court alchemist is often not present as an option. (Note that there are skill rank and job requirements for certain advisor roles).

This is not a pressing concern though since the only item worth making is the adept’s robe, as base material for Alchemist robe EX (see Appendix for how to make Robe EX). After this event it is fair to say we have an over-abundance of adept’s robe and the market for Alchemy Robe EX is not endless (although I made and sold 125 of them after last time we had this HRE effect years ago). The robe EX also has a new competitor now in form of Tianzhu Treasure Sword from grande ganador which have the same EX rank and sells for more than robe EX.

Indeed, also the market for FAB is limited and it will be a challenge selling off the ones made during this study. But this was done for Science, not money of course.

The main bottleneck for obtaining mats for FAB turned out, unsurprisingly, to be the knife loosing its gold needed for gold short-sword. To secure maximum number of knives, I let a character without the HRE effect make the knives so that it would be fewer gold swords produced and thus more knives. Or so I thought in my ignorance. As it turns out, HRE should have no effect on a minor success such as this knife (but alchemy rank would), if the results from the robe experiments hold in general. Unfortunately I did not keep records of the outcomes, but I can state that way too many unwanted huge success came out of this.

In the FAB experiments any small differences between the “easy” recipes was likely due to random variation. An outlier was blue ore that was almost as hard as robe to succeed with on average, but there is no reason to believe the blue ore recipe to differ form the other coloured ores. My best estimate is that they all had 25% chance for success, which should give 5% base chance if the HRE effect is the same for all items. An earlier hunch that knife was harder than the others appears to be wrong. It probably only gave the impression to be more difficult because the base material is much harder to obtain than for the others.

There is no reason to believe that the HRE effect (or any other effect) acts differently for different items. Instead, the lower success of Robe/Biretta compared to other items is likely to be due to different base probabilities, to which is added a common fixed increase in the probability of huge success from Adept, HRE and advisor. In other words, I make the assumption that the effects are additive to each other and to the base rate and are the same for all the MA items. An outline of a theory for alchemy experiments, summarising what I have discussed, is presented in Figure 31.

Proposed theory of the outcome of alchemy experiments

FIGURE 31: Proposed theory of the outcome of alchemy experiments

The theory yields some predictions that can be tested. In particular that the independent effect of advisor position is +10%, and that the proportion of failures would be around 55% with only advisor effect on. The court alchemist advisor position is rare, and I am not certain if it actually can be obtained from an emperor that does not have the support alchemy policy. But if it can, it would be interesting to do more Robe experiments with only the Advisor effect on. Easier to test is that processed lumber and the other non-Robe/Biretta should yield 5% MA items in experiments conducted outside HRE/advisor without Adept, and 6% with Adept title on. It would also be interesting to look at the “minor huge successes” from these experiments, such as non-FAB armour plates and how those fit into the picture. The Robe and Biretta recipes do not have multiple huge success categories, so I have no data on this. Another unexplored issue is if the ratio of minor success to failure/huge success is fixed at 2:3 also for other recipes than Robe.

6 Conclusions

Despite some shortcomings, the results presented here show several clear patterns. My conclusion (summarised in Figure 31) is that the chance of minor success is fixed at 35% or 40% and cannot be altered by any known factor, and that increasing the probability of huge success therefore is the same as lowering the probability of failure. The chance of huge success can be modified as follows:

  • Adept: +1%
  • HRE advisor effect: +10%
  • HRE general effect: +20%
  • Oxford: not applicable to alchemy experiments
  • EX: not applicable to alchemy experiments
  • Paymaster aide: not applicable to alchemy experiments
  • Skill rank: no effect on huge success or failure, but moderate effect within minor success

7 Acknowledgments

I want to thank those that lent me their characters for the advancement of science. Big thank you to Marsali that gave me some much needed fine dye and canned silk thread, and to Altavista, Guilder, Marsali and TardyMcGormless for discussions about this and that.

8 Appendices

8.1 How to make items for FAB

Recipes and best practices for making FAB items

FIGURE 32: Recipes and best practices for making FAB items

8.2 How to make Robe EX from Adept’s Robe

How to make Robe EX

FIGURE 33: How to make Robe EX

8.3 FAB raw data

DT::datatable(FAB[,-1], options = list(pageLength = 10), caption = 'FAB experiments raw data. Values are number of attempts needed')

8.4 Robe raw data

DT::datatable(Robe, options = list(pageLength = 10), caption = 'Robe experiments raw data')

8.5 Runs-tests

runsTableBatch
runsTableCond

8.6 Auto-correlation

ACFwhole
PACFwhole
Auto-correlation (upper panel) and partial auto-correlation (lower panel) function plot for the whole Robe sequenceAuto-correlation (upper panel) and partial auto-correlation (lower panel) function plot for the whole Robe sequence

FIGURE 34: Auto-correlation (upper panel) and partial auto-correlation (lower panel) function plot for the whole Robe sequence

BatchACF
Auto-correlation function plots for Robe batches

FIGURE 35: Auto-correlation function plots for Robe batches

ConditionACF
Auto-correlation function plots for Robe conditions

FIGURE 36: Auto-correlation function plots for Robe conditions

BatchPACF
Partial auto-correlation function plots for Robe batches

FIGURE 37: Partial auto-correlation function plots for Robe batches

ConditionPACF
Partial auto-correlation function plots for Robe conditions

FIGURE 38: Partial auto-correlation function plots for Robe conditions

8.7 R code for this report

p.caption {
  color: #777;
}
caption {
  color: #777;
}
knitr::opts_chunk$set(fig.width = 5, fig.align = 'center', 
                      collapse = TRUE, warning = FALSE, message = FALSE)
#packages
library(readODS)
library(ggplot2)
library(dplyr)
library(tidyr)
library(kableExtra)
library(forcats)
library(purrr)
library(tseries)
library(ggfortify)
library(binom)
library(broom)
library(stringr)
library(ggpmisc)
library(corrplot)
library(DT)
library(shades)
#data
FAB <- read_ods("~\\FABtory\\FABtory.ods", sheet =2)
FAB2 <- FAB  |>  pivot_longer(
  cols = Biretta:WhiteOre,
  names_to = "Item",
  values_to = "AttemptsNeeded"
  )
Snitt <- FAB2  |> 
  group_by(Toon, Who) |>
  summarise(MeanAttemptsNeeded = mean(AttemptsNeeded))
Robe <- read_ods("~\\FABtory\\FABtory.ods", sheet =3)
Design <- read_ods("~\\FABtory\\FABtory.ods", sheet =4)
RobeSummaryTable <- read_ods("~\\FABtory\\FABtory.ods", sheet =6)
knitr::include_graphics('FABpic.png')
knitr::include_graphics('HRE.png')
knitr::include_graphics('robeSuccess.png')
kbl(Design[,-2], caption = 'Experimental design for Robe experiments. Group 15 is the Robe part of the FAB setup for comparison.', align ="c") |> 
  kable_paper(c("hover", "condensed"), full_width = F)
knitr::include_graphics('mentored.png')

ggplot(FAB2, aes(AttemptsNeeded)) +
  geom_histogram(fill = "#377eb8", colour = "black", binwidth = 1)

ggplot(FAB2, aes(AttemptsNeeded)) +
  stat_density(aes(colour = AlchemySkill),  linewidth = 2,
               bounds = c(1, Inf), geom="line", position="identity") +
  #scale_colour_manual(values = c("#7a0403","#FABA39","#18bc9c", "#2c3e50"))+
  scale_colour_brewer(palette = "RdBu", direction = -1) +
  #scale_colour_manual(values = c("#7a0403","#FABA39","#18bc9c", "#2c3e50"))+
  theme(legend.position = c(0.95,0.95),
        legend.justification = c(1,1))
FAB3 <- FAB2 |>
  mutate(Item = reorder(Item, AttemptsNeeded, FUN = mean, na.rm = TRUE))
ItemLabels <- FAB3 |>
  group_by(Item) |>
  summarise(snitt = mean(AttemptsNeeded), median =median(AttemptsNeeded))
ItemLabels$snitt2 <- sprintf("bar(x) == %.2f", ItemLabels$snitt)
ItemLabels

ggplot(FAB3, aes(AttemptsNeeded)) +
  geom_histogram(binwidth = 1, colour = "black", 
                 aes(fill=(Item))) + 
  facet_wrap(vars(Item), ncol = 2) +
  #scale_fill_viridis_d(option = "turbo", direction = 1, guide = "none") +
  scale_fill_brewer(palette = "RdBu", guide = "none", direction = -1)+
  geom_label(x = 12.5, y = 17.5, aes(label = snitt2), data = ItemLabels, parse = TRUE, 
             hjust = "center", size = 3, label.size = NA)
ggplot(FAB3, aes(x=AttemptsNeeded, y=Item, fill=Item)) +
  geom_boxplot() +
  stat_summary(fun=mean, geom="point", shape=20, size=3, color="white", fill="white") +
  ylab(NULL) +
  scale_x_continuous(breaks = seq(0,24, by =2))+
  #scale_fill_viridis_d(option = "turbo", direction = 1, guide="none")
  scale_fill_brewer(palette = "RdBu", guide = "none", direction =-1)

FAB4 <- FAB3 |>
  mutate(ItemGroup = ifelse(Item == "Biretta" | Item == "Robe" , "Robe/Biretta", "Others"))
FAB4$ItemGroup <- as_factor(FAB4$ItemGroup)
ItemLabels2 <- FAB4 |>
  group_by(ItemGroup) |>
  summarise(snitt = mean(AttemptsNeeded), 
            median =median(AttemptsNeeded), 
            n = (length(AttemptsNeeded)))
ItemLabels2$snitt2 <- sprintf("bar(x) == %.2f", ItemLabels2$snitt)
ItemLabels2$n2 <- sprintf("n == %.0f", ItemLabels2$n)
ItemLabels2$snittAndN <- sprintf(
  "bar(x) == %.2f * ',' ~~ n == %.0f",
  ItemLabels2$snitt,
  ItemLabels2$n
)
ggplot(FAB4, aes(AttemptsNeeded)) +
  geom_histogram(binwidth = 1, colour = "black", 
                 aes(fill=(ItemGroup))) + 
  facet_wrap(vars(ItemGroup), ncol = 2) +
  scale_fill_manual(values = c("#B51F2E", "#377eb8"), guide = "none") +
  #scale_fill_manual(values = c("#7a0403", "#95a5a6"), guide = "none") +
  #scale_fill_brewer(palette = "Set1", guide = "none")+
  geom_label(x = 12.5, y = 140, aes(label = snittAndN), data = ItemLabels2, parse = TRUE, 
             hjust = "center", vjust = "center", size = 3, label.size = NA)

ggplot(FAB4, aes(AttemptsNeeded)) +
  geom_histogram(binwidth = 1, colour = "black", 
                 aes(fill=(ItemGroup), y = stat(density))) + 
  facet_wrap(vars(ItemGroup), ncol = 2) +
  scale_fill_manual(values = c("#B51F2E", "#377eb8"), guide = "none") +
  #scale_fill_manual(values = c("#7a0403", "#95a5a6"), guide = "none") +
  #scale_fill_brewer(palette = "Set1", guide = "none")+
  geom_label(x = 12.5, y = 0.235, aes(label = snittAndN), data = ItemLabels2, parse = TRUE, 
             hjust = "center", vjust = "center", size = 3, label.size = NA)

ggplot(FAB4, aes(AttemptsNeeded)) +
  stat_density(aes(colour = ItemGroup),  linewidth = 2,
               bounds = c(1, Inf), geom="line", position="identity") +
  scale_colour_manual(values = c("#B51F2E", "#377eb8"), guide = "none") +
  #scale_colour_viridis_d(option = "turbo", direction = -1) +
  #scale_colour_manual(values = c("#7a0403","#95a5a6")) +
  #scale_colour_brewer(palette = "Set1", guide = "none")+
  theme(legend.position = c(0.95,0.95),
        legend.justification = c(1,1)) +
  guides(colour = guide_legend(title = NULL))

ggplot(FAB4, aes(x=AttemptsNeeded, y=ItemGroup, fill=ItemGroup)) +
  geom_boxplot() +
  stat_summary(fun=mean, geom="point", shape=20, size=3, color="white", fill="white") +
  ylab(NULL) +
  scale_x_continuous(breaks = seq(0,24, by =2))+
  scale_fill_manual(values = c("#B51F2E", "#377eb8"), guide = "none") 
  #scale_fill_manual(values = c("#7a0403","#95a5a6"), guide="none")
  #scale_fill_brewer(palette = "Set1", guide = "none")
table(FAB4$ItemGroup)
(WT <- wilcox.test(FAB4$AttemptsNeeded ~ FAB4$ItemGroup, 
            paired = F, 
            alternative = "greater"))
#restructure data
FABprop <- FAB4 |>
  group_by(ItemGroup) |>
  summarise(success = sum(n()), total = sum(AttemptsNeeded))
#binomial confidence intervals
binom::binom.confint(FABprop$success, FABprop$total) 
(binomRes <- binom::binom.wilson(FABprop$success, FABprop$total))
binomRes$Group <- as_factor(c("Robe/Biretta", "Others"))
#test if equal proportions
(propRes <- prop.test(x = binomRes$x, binomRes$n, alternative = "less"))
kbl(FABprop, label = "FABpropTable", 
    caption = 'Number of successes and attempts when making MA entries for FAB', 
    align ="c",
    col.names = c('Group', 'Successes', 'Total Experiments')) |>
  kable_paper(c("hover", "condensed"), full_width = F) #|>
  #column_spec(1, color = "white", bold = F, 
  #            background = c("#ca0020", "#0571b0"))
binomRes |> 
ggplot(aes(x = Group, y = mean, colour= Group)) +
  ylab("Proportion Success") +
  xlab(NULL) +
  geom_pointrange(aes(ymin = lower, ymax = upper), size =0.75, linewidth = 1)+
  scale_colour_manual(values = c("#B51F2E", "#377eb8"), guide = "none") +
  geom_text(aes(label = round(mean, 3), vjust = -2), size = 3) +
  coord_flip() +
  theme(axis.ticks.y = element_blank(),
        panel.grid.major.y = element_blank())

ggplot(Snitt, aes(MeanAttemptsNeeded)) +
  geom_histogram(aes(fill= Who), binwidth = 0.5, colour="black") +
  #scale_fill_brewer(palette = "RdBu", direction = 1) +
  scale_fill_manual(values = c("#B51F2E","#F4A582","#A7CFE4", "#377eb8"))+
  #scale_fill_viridis_d(option = "turbo", direction = -1) +
  ylab("Count") +
  xlab("Average attempts needed") +
  annotate("text", x = 2.5, y = 9.5, label = "Alta-lucky-vista", colour = "#B51F2E") +
  geom_curve(
    aes(x = 2.5, y = 8.8, xend = 2.0, yend = 2.5),
    arrow = arrow(
    length = unit(0.03, "npc"), 
    type="closed" 
    ),
    colour = "#B51F2E",
    linewidth = 1.2,
    angle = 0 
  ) +
  scale_y_continuous(breaks = seq(0,20, by =2))+
  theme(
    legend.position = c(0.95,0.95),
    legend.justification = c(1,1),
    legend.background = element_rect(fill = "white"),
    legend.key = element_rect(fill = "white", color = NA)
  )

knitr::include_graphics('Ikea.png')
kbl(RobeSummaryTable, caption = 'Outcome of Robe Experiments for each batch. The percentage Adept Robe is highlighted.', align ="c") |>
  kable_paper(c("hover", "condensed"), full_width = F) |>
  column_spec(9, background = "#92c5de") |> #, color = "white"
  pack_rows("HRE, Advisor, Adept, r20", 1, 3) |>
  pack_rows("HRE, Advisor, r20", 4, 6) |>
  pack_rows("HRE, Advisor, Adept, r20, Ex", 7, 9) |>
  pack_rows("HRE, Advisor, r20, Ex", 10, 12) |>
  pack_rows("HRE, Advisor, Adept, r20, Ex, Oxf", 13, 15) |>
  pack_rows("HRE, Advisor, r11", 16, 17) |>
  pack_rows("HRE, r11", 18, 18) |>
  pack_rows("HRE, r20", 19, 19) |>
  pack_rows("HRE, Adept, r11", 20, 20) |>
  pack_rows("HRE, Adept, r20", 21, 21) |>
  pack_rows("r11", 22, 22) |>
  pack_rows("Adept, r11", 23, 23) |>
  pack_rows("r20", 24, 24) |>
  pack_rows("Adept, r20", 25, 26)

# get condition descriptions from table, and combine with sample size for figure labels
# and reorder factor levels by % robes. and the items from "hardest to easiest"
# keep them reordered in the file so don't have to do within ggplot
Robe2 <- Robe |> left_join(Design |> select(Condition, Condition2, Totals), by="Condition")
Robe2 <- Robe2 |>
  mutate(Condition3 = paste0(Condition2, " (n = ", Totals, ")")) |>
  mutate(Condition3 = fct_reorder(.f = Condition3, 
                                         .x = Result,
                                         .fun = function(.x) mean(.x == "Robe"),
                                         .desc = TRUE)) |>
  mutate(Result = fct_relevel(Result, "Robe", "Justaucorps", "Waistcoat", "FineVelvet", "Failure"))
  
ggplot(Robe2, aes(Condition3, fill = fct_rev(Result))) + 
  geom_bar(position = "fill", width = 0.9,) + #
  #shades::brightness(scale_fill_brewer(palette = "RdBu", direction = -1),   shades::delta(-0.05)) +
  scale_fill_brewer(palette = "RdYlBu", direction = -1) +
  #scale_fill_viridis_d(option = "turbo", direction = 1) +
  scale_y_continuous(labels = scales::percent, breaks = seq(0, 1, by = 0.2), expand = expansion(mult = c(0, 0.02))) +
  scale_x_discrete(expand = expansion(mult = c(0, 0)))+
  ylab("Percentage") +
  xlab(NULL) +
  theme(legend.background = element_rect(fill = "#EBEBEB"),
        legend.key = element_rect(fill = NA),
        legend.position = "top",
        axis.text.y = element_text(size = rel(1)),
        axis.ticks.y = element_blank(),
        panel.grid.major.y = element_blank(),
        legend.justification = c(1, 0),
        panel.background = element_rect(fill = "white")) +
  guides(fill = guide_legend(reverse = TRUE, title = NULL))+
  coord_flip()

# include batch, within condition
Robe2$GroupBatch <- ave(Robe2$Batch, Robe2$Condition, 
                        FUN = function(x) as.numeric(factor(x)))
ggplot(Robe2, aes(GroupBatch, fill = fct_rev(Result))) + 
  geom_bar(position = "fill",  width = 1) + #colour = "black",
  scale_fill_brewer(palette = "RdYlBu", direction = -1) +
  #scale_fill_viridis_d(option = "turbo", direction = 1) +
  scale_y_continuous(labels = scales::percent, breaks = seq(0, 1, by = 0.2), expand = expansion(mult = c(0, 0.02))) +
  scale_x_continuous(breaks = NULL, expand = expansion(mult = c(0, 0))) +
  ylab("Percentage") +
  xlab(NULL) +
  theme(legend.background = element_rect(fill = "#EBEBEB"),
        legend.key = element_rect(fill = NA),
        legend.position = "top",
        axis.text.y = element_text(size = rel(1.2)),
        legend.justification = c(1, 0)) +
  guides(fill = guide_legend(reverse = TRUE, title = NULL))+
  coord_flip()+
  facet_wrap(~fct_rev(Condition3), strip.position = "left", ncol = 1, scales = "free_y") +
  theme(strip.text.y.left = element_text(angle = 0, hjust = 1), 
        panel.spacing = unit(0.1,"cm"), 
        strip.background = element_rect(fill = NA))
# time series visualization
ggplot(Robe2, aes(x=BatSeq, fill = fct_rev(Result))) +
  geom_bar(position = "fill", width = 1) + #, colour = "black"
  facet_wrap(vars(fct_rev(Condition3), GroupBatch), strip.position = "left", ncol = 1) +
  scale_fill_brewer(palette = "RdYlBu", direction = -1) +
  #scale_fill_viridis_d(option = "turbo", direction = 1)+
  scale_x_continuous(breaks = seq(0, 120, by = 20), expand = expansion(mult = c(0, 0))) +
  scale_y_continuous(breaks = NULL, expand = expansion(mult = c(0, 0))) +
  theme(legend.background = element_rect(fill = "#EBEBEB"),
        legend.key = element_rect(fill = NA),
        legend.position = "top",
        axis.text.y = element_text(size = rel(1.2)),
        legend.justification = c(0.5, 0)) +
  guides(fill = guide_legend(reverse = TRUE, title = NULL)) +
  theme(strip.text.y.left = element_blank(), 
        strip.text.x = element_blank(),
        panel.spacing = unit(0.1,"cm")) +
  xlab("Sequence") +
  ylab(NULL)

HRE <- Robe2 |> 
  mutate(robeSeries = fct_other(Result, keep = "Robe")) |> 
  group_by(HRE, Condition2, robeSeries) |>
  summarise(number = n(), Condition = mean(Condition)) |> 
  ungroup() |> 
  pivot_wider(
  names_from  = "robeSeries",
  values_from = "number",
  values_fill = 0) |> 
  mutate(Total = Robe+Other,
         PropRobe = Robe/Total)
HRE <- cbind(HRE, 
      binom.confint(HRE$Robe, n = HRE$Total, methods = "wilson"))

HRE <- HRE |> 
  filter(Condition %in% c(7:10) | HRE == "NO") |> #manual subsetting
  mutate(Condition3 = (str_replace(Condition2, c("HRE, "), "")))
  
HRE |> 
ggplot(aes(y = Condition3, x = PropRobe, colour = HRE)) +
  ylab(NULL) +
  xlab("Proportion Robe") +
  geom_pointrange(aes(xmin = lower, xmax = upper), 
                  size =0.75, linewidth = 1,
                  position = position_dodge(width=1)) +
  scale_colour_manual(values = c("#95a5a6", "#2c3e50")) +
  theme(legend.position = "top") +
  facet_wrap(vars(Condition3), strip.position = "left", ncol = 1, scales = "free_y")+
  theme(strip.text.y.left = element_blank(), 
        strip.text.x = element_blank(),
        panel.spacing = unit(0.5,"cm"),
        axis.ticks.y = element_blank(),
        panel.grid.major.y = element_blank()) +
  geom_text(aes(label = paste("n =", Total)), vjust = 0, hjust = -0.5, size = 3)

ADV <- Robe2 |> 
  mutate(robeSeries = fct_other(Result, keep = "Robe")) |> 
  group_by(Advisor, Condition2, robeSeries) |>
  summarise(number = n(), Condition = mean(Condition)) |> 
  ungroup() |> 
  pivot_wider(
  names_from  = "robeSeries",
  values_from = "number",
  values_fill = 0) |> 
  mutate(Total = Robe+Other,
         PropRobe = Robe/Total)
ADV <- cbind(ADV, 
      binom.confint(ADV$Robe, n = ADV$Total, methods = "wilson"))

ADV <- ADV |> 
  filter(Condition %in% c(1,2,6,7,8,10)) |> #dont like manual subsetting of these rows...
  mutate(Condition3 = (str_replace(Condition2, c("Advisor, "), "")))
  
ADV |> 
ggplot(aes(y = Condition3, x = PropRobe, colour = Advisor)) +
  ylab(NULL) +
  xlab("Proportion Robe") +
  geom_pointrange(aes(xmin = lower, xmax = upper), 
                  size =0.75, linewidth = 1,
                  position = position_dodge(width=1)) +
  scale_colour_manual(values = c("#95a5a6", "#2c3e50")) +
  theme(legend.position = "top") +
  facet_wrap(vars(Condition3), strip.position = "left", ncol = 1, scales = "free_y")+
  theme(strip.text.y.left = element_blank(), 
        strip.text.x = element_blank(),
        panel.spacing = unit(0.5,"cm"),
        axis.ticks.y = element_blank(),
        panel.grid.major.y = element_blank()) +
  geom_text(aes(label = paste("n =", Total)), vjust = 0, hjust = -0.5, size = 3)
ADVwide <- ADV |> 
  group_by(Advisor) |> 
  summarise(SumRobes = sum(Robe), SumTots = sum(Total)) |> 
  mutate(SumProp = SumRobes/SumTots)
(ADVpropTestTotal <- prop.test(x = ADVwide$SumRobes, ADVwide$SumTots, alternative = "less"))
(ADVpropTests <- 
  split(ADV, as.factor(ADV$Condition3)) |>  
  map(function (df) prop.test(x = df$Robe, n = df$Total, alternative = "less")))
ADEPT <- Robe2 |> 
  mutate(robeSeries = fct_other(Result, keep = "Robe")) |> 
  group_by(Adept, Condition2, robeSeries) |>
  summarise(number = n(), Condition = mean(Condition)) |> 
  ungroup() |> 
  pivot_wider(
  names_from  = "robeSeries",
  values_from = "number",
  values_fill = 0) |> 
  mutate(Total = Robe+Other,
         PropRobe = Robe/Total)
ADEPT <- cbind(ADEPT, 
      binom.confint(ADEPT$Robe, n = ADEPT$Total, methods = "wilson"))

ADEPT <- ADEPT |> 
  filter(!(Condition %in% c(5,6))) |> #dont like manual subsetting of these rows...
  mutate(Condition3 = (str_replace(Condition2, c("Adept, "), "")))
  
ADEPT |> 
ggplot(aes(y = Condition3, x = PropRobe, colour = Adept)) +
  ylab(NULL) +
  xlab("Proportion Robe") +
  geom_pointrange(aes(xmin = lower, xmax = upper), 
                  size =0.75, linewidth = 1,
                  position = position_dodge(width=1)) +
  scale_colour_manual(values = c("#95a5a6", "#2c3e50")) +
  theme(legend.position = "top") +
  facet_wrap(vars(Condition3), strip.position = "left", ncol = 1, scales = "free_y")+
  theme(strip.text.y.left = element_blank(), 
        strip.text.x = element_blank(),
        panel.spacing = unit(0.5,"cm"),
        axis.ticks.y = element_blank(),
        panel.grid.major.y = element_blank()) +
  ggrepel::geom_text_repel(aes(label = paste("n =", Total)), 
                           size = 3, 
                           direction = "x", 
                           min.segment.length = 5, 
                           seed =666)
ADEPTwide <- ADEPT |> 
  pivot_wider(
  names_from  = c(Adept),
  values_from = "PropRobe") |>
  group_by(Condition3) |> 
  summarise(NO = max(NO, na.rm = T), YES = max(YES, na.rm = T)) |> 
  mutate(difference = YES-NO)
adeptdiff <-  round(mean(ADEPTwide$difference), digits = 4)

(adeptEst <- binom.confint(x= 2, n = 223, methods = "wilson"))
(baseEst <- binom.confint(x= 0, n = 217, methods = "wilson"))

ALCH <- Robe2 |> 
  mutate(robeSeries = fct_other(Result, keep = "Robe")) |> 
  group_by(Alchemy, Condition2, robeSeries) |>
  summarise(number = n(), Condition = mean(Condition)) |> 
  ungroup() |> 
  pivot_wider(
  names_from  = "robeSeries",
  values_from = "number",
  values_fill = 0) |> 
  mutate(Total = Robe+Other,
         PropRobe = Robe/Total)
ALCH <- cbind(ALCH, 
      binom.confint(ALCH$Robe, n = ALCH$Total, methods = "wilson"))

ALCH <- ALCH |> 
  filter(Condition %in% c(2,6:14)) |> #dont like manual subsetting of these rows...
  mutate(Condition3 = (str_replace(Condition2, c(", r11"), ""))) |> 
  mutate(Condition3 = (str_replace(Condition3, c(", r20"), ""))) |> 
  mutate(Condition3 = (str_replace(Condition3, c("r11"), "Nothing"))) |> 
  mutate(Condition3 = (str_replace(Condition3, c("r20"), "Nothing")))
  
ALCH |> 
ggplot(aes(y = Condition3, x = PropRobe, colour = as.factor((Alchemy)))) +
  ylab(NULL) +
  xlab("Proportion Robe") +
  labs(colour = "Alchemy rank")+
  geom_pointrange(aes(xmin = lower, xmax = upper), 
                  size =0.75, linewidth = 1,
                  position = position_dodge(width=1)) +
  scale_colour_manual(values = c("#95a5a6", "#2c3e50")) +
  theme(legend.position = "top") +
  facet_wrap(vars(Condition3), strip.position = "left", ncol = 1, scales = "free_y")+
  theme(strip.text.y.left = element_blank(), 
        strip.text.x = element_blank(),
        panel.spacing = unit(0.5,"cm"),
        axis.ticks.y = element_blank(),
        panel.grid.major.y = element_blank()) +
  ggrepel::geom_text_repel(aes(label = paste("n =", Total)), 
                           size = 3, 
                           direction = "x", 
                           min.segment.length = 5, 
                           seed =666)
EX <- Robe2 |> 
  mutate(robeSeries = fct_other(Result, keep = "Robe")) |> 
  group_by(EX, Condition2, robeSeries) |>
  summarise(number = n(), Condition = mean(Condition)) |> 
  ungroup() |> 
  pivot_wider(
  names_from  = "robeSeries",
  values_from = "number",
  values_fill = 0) |> 
  mutate(Total = Robe+Other,
         PropRobe = Robe/Total)
EX <- cbind(EX, 
      binom.confint(EX$Robe, n = EX$Total, methods = "wilson"))

EX <- EX |> 
  filter(Condition %in% c(1:5)) |> #dont like manual subsetting of these rows...
  mutate(Condition3 = (str_replace(Condition2, c(", Ex"), "")))

EXwide <- EX |> 
  pivot_wider(
  names_from  = c(EX),
  values_from = "PropRobe") |>
  group_by(Condition3) |> 
  summarise(NO = mean(NO, na.rm = T), YES = mean(YES, na.rm = T)) |> 
  mutate(difference = YES-NO)
EXdiff <-  round(mean(EXwide$difference), digits = 4)  

EX |> 
ggplot(aes(y = Condition3, x = PropRobe, colour = EX)) +
  ylab(NULL) +
  xlab("Proportion Robe") +
  geom_pointrange(aes(xmin = lower, xmax = upper), 
                  size =0.75, linewidth = 1,
                  position = position_dodge(width=1)) +
  scale_colour_manual(values = c("#95a5a6", "#2c3e50")) +
  theme(legend.position = "top") +
  facet_wrap(vars(Condition3), strip.position = "left", ncol = 1, scales = "free_y")+
  theme(strip.text.y.left = element_blank(), 
        strip.text.x = element_blank(),
        panel.spacing = unit(0.5,"cm"),
        axis.ticks.y = element_blank(),
        panel.grid.major.y = element_blank()) +
  ggrepel::geom_text_repel(aes(label = paste("n =", Total)),
  size = 3,
  min.segment.length = 5,
  seed =555)
OXF <- Robe2 |> 
  mutate(robeSeries = fct_other(Result, keep = "Robe")) |> 
  group_by(Oxfords, Condition2, robeSeries) |>
  summarise(number = n(), Condition = mean(Condition)) |> 
  ungroup() |> 
  pivot_wider(
  names_from  = "robeSeries",
  values_from = "number",
  values_fill = 0) |> 
  mutate(Total = Robe+Other,
         PropRobe = Robe/Total)
OXF <- cbind(OXF, 
      binom.confint(OXF$Robe, n = OXF$Total, methods = "wilson"))

OXF <- OXF |> 
  filter(Condition %in% c(3,5)) |> #dont like manual subsetting of these rows...
  mutate(Condition3 = (str_replace(Condition2, c(", Oxf"), "")))

OXFwide <- OXF |> 
  pivot_wider(
  names_from  = c(Oxfords),
  values_from = "PropRobe") |>
  group_by(Condition3) |> 
  summarise(NO = mean(NO, na.rm = T), YES = mean(YES, na.rm = T)) |> 
  mutate(difference = YES-NO)
OXFdiff <-  round(mean(EXwide$difference), digits = 4) 

OXF |> 
ggplot(aes(y = Condition3, x = PropRobe, colour = Oxfords)) +
  ylab(NULL) +
  xlab("Proportion Robe") +
  geom_pointrange(aes(xmin = lower, xmax = upper), 
                  size =0.75, linewidth = 1,
                  position = position_dodge(width=1)) +
  scale_colour_manual(values = c("#95a5a6", "#2c3e50")) +
  theme(legend.position = "top") +
  facet_wrap(vars(Condition3), strip.position = "left", ncol = 1, scales = "free_y")+
  theme(strip.text.y.left = element_blank(), 
        strip.text.x = element_blank(),
        panel.spacing = unit(0.5,"cm"),
        axis.ticks.y = element_blank(),
        panel.grid.major.y = element_blank()) +
  ggrepel::geom_text_repel(aes(label = paste("n =", Total)),
  size = 3,
  min.segment.length = 5,
  seed =555)
Paymaster <- read_ods("~\\FABtory\\paymaster.ods", sheet =1)
Paymaster$Condition3 <- (as.factor(Paymaster$Condition3))
Paymaster$Condition3 <-fct_relevel(Paymaster$Condition3, "HRE (r11+r20)", "HRE (r12-r14)")

Paymaster |> 
ggplot(aes(y = Condition3, x = PropRobe, colour = Paymaster)) +
  ylab(NULL) +
  xlab("Proportion Robe") +
  geom_pointrange(aes(xmin = lower, xmax = upper), 
                  size =0.75, linewidth = 1,
                  position = position_dodge(width=1)) +
  scale_colour_manual(values = c("#95a5a6", "#2c3e50")) +
  theme(legend.position = "top") +
  facet_wrap(vars(Condition3), strip.position = "left", ncol = 1, scales = "free_y")+
  theme(strip.text.y.left = element_blank(), #element_text(angle = 0, hjust = 0),
        strip.text.x = element_blank(),
        panel.spacing = unit(0,"cm"),
        axis.ticks.y = element_blank(),
        panel.grid.major.y = element_blank()) +
  geom_text(aes(label = paste("n =", Total)), vjust = -1, hjust = -0.5, size = 3)
#proportion minorsuccess
RST <- RobeSummaryTable
#remove row for totals
RST <- RST |> 
  filter(Batch < 27) |> 
  mutate(Condition = as.numeric(Condition))
RST <- RST |> 
  mutate(Minor = (FineVelvet+Justaucorps+Waistcoat)) 
RST <- RST |> 
  mutate(propMinor = (FineVelvet+Justaucorps+Waistcoat)/Total) 
RST <- RST |> left_join(Design |> 
                          select(Condition, Condition2), by="Condition")
RST <- cbind(RST, 
      MinorProp=binom.confint(RST$Minor, n = RST$Total, methods = "wilson"))

#combine batches
RST2 <- RST |> 
  group_by(Condition2) |> 
  summarise(
    Condition = mean(Condition),
    Failure = sum(Failure),
    FineVelvet = sum(FineVelvet),
    Justaucorps = sum(Justaucorps),
    Robe = sum(Robe),
    Waistcoat = sum(Waistcoat),
    Total = sum(Total),
    Minor = sum(Minor)
  ) |> 
  mutate(propMinor = (FineVelvet+Justaucorps+Waistcoat)/Total,
         propRobe = Robe/Total,
         propFailure = Failure/Total,
         propJustau = Justaucorps/Total,
         propVelvet = FineVelvet/Total,
         propWaist = Waistcoat/Total,
         propJustau_minor = Justaucorps/Minor,
         propVelvet_minor = FineVelvet/Minor,
         propWaist_minor = Waistcoat/Minor
         ) 
RST2  <- RST2 |> 
  mutate(Condition2 = as.factor(Condition2)) |> 
  mutate(Condition2 = fct_reorder(Condition2, propRobe, .fun = mean)) |> 
  mutate(Condition2 = fct_rev(Condition2))
RST2 <- cbind(RST2, 
              propMinor = binom.confint(RST2$Minor, n = RST2$Total, methods = "wilson"))
#overall proportion minor success:
propMinorOverall <- sum(RST2$Minor)/sum(RST2$Total)
propMinorOverall2 <- mean(RST2$propMinor)

RST2 |> 
  ggplot(aes(y = Condition2, x = propMinor)) +
  ylab(NULL) +
  xlab("Proportion minor success") +
  geom_vline(xintercept = propMinorOverall, linetype = "dashed", colour = "#95a5a6")+
  geom_pointrange(aes(xmin = propMinor.lower, xmax = propMinor.upper), 
                  size =0.5, linewidth = 0.75,
                  position = position_dodge(width=1)) +
  scale_x_continuous(breaks = seq(0, 1, by = 0.2), limits = c(0,1))

RST2 <- cbind(RST2, 
              propFailure = binom.confint(RST2$Failure, n = RST2$Total, methods = "wilson"))
RST2 <- cbind(RST2, 
              propRobe = binom.confint(RST2$Robe, n = RST2$Total, methods = "wilson"))
RST2 <- cbind(RST2, 
              propJustau = binom.confint(RST2$Justaucorps, n = RST2$Total, methods = "wilson"))
RST2 <- cbind(RST2, 
              propVelvet = binom.confint(RST2$FineVelvet, n = RST2$Total, methods = "wilson"))
RST2 <- cbind(RST2, 
              propWaist = binom.confint(RST2$Waistcoat, n = RST2$Total, methods = "wilson"))
RST2 <- cbind(RST2, 
              propJustau_minor = binom.confint(RST2$Justaucorps, n = RST2$Minor, methods = "wilson"))
RST2 <- cbind(RST2, 
              propVelvet_minor = binom.confint(RST2$FineVelvet, n = RST2$Minor, methods = "wilson"))
RST2 <- cbind(RST2, 
              propWaist_minor = binom.confint(RST2$Waistcoat, n = RST2$Minor, methods = "wilson"))
rank11 <- c(6,7,9,11,12)
RST2 <- RST2 |> 
  mutate(AlchemyRank = ifelse(Condition %in% rank11, 11, 20))

propFailureOverall <- sum(RST2$Failure)/sum(RST2$Total)
RST2 |> 
  ggplot(aes(y = Condition2, x = propFailure.mean)) +
  ylab(NULL) +
  xlab("Proportion Failure") +
  geom_vline(xintercept = propFailureOverall, linetype = "dashed", colour = "#95a5a6")+
  geom_pointrange(aes(xmin = propFailure.lower, xmax = propFailure.upper), 
                  size =0.5, linewidth = 0.75)+
  scale_x_continuous(breaks = seq(0, 1, by = 0.2), limits = c(0,1))

propRobeOverall <- sum(RST2$Robe)/sum(RST2$Total)
RST2 |> 
  ggplot(aes(y = Condition2, x = propRobe.mean)) +
  ylab(NULL) +
  xlab("Proportion Adept's Robe") +
  geom_vline(xintercept = propRobeOverall, linetype = "dashed", colour = "#95a5a6")+
  geom_pointrange(aes(xmin = propRobe.lower, xmax = propRobe.upper), 
                  size =0.5, linewidth = 0.75)+
  scale_x_continuous(breaks = seq(0, 1, by = 0.2), limits = c(0,1))

propJustauOverall <- sum(RST2$Justaucorps)/sum(RST2$Total)

propJustauR11 <- RST2 |>  
  filter(AlchemyRank == 11) |> 
  summarise(out = sum(Justaucorps)/sum(Total)) |> 
  pull(out)
propJustauR20 <- RST2 |>  
  filter(AlchemyRank == 20) |> 
  summarise(out = sum(Justaucorps)/sum(Total)) |> 
  pull(out)

JustauPropAlchemy <- RST2 |>
  group_by(AlchemyRank) |>
  summarise(Justaucorps = sum(Justaucorps), Total = sum(Total))

(JustauAlchRes <- 
    binom.wilson(JustauPropAlchemy$Justaucorps, JustauPropAlchemy$Total))
JustauAlchRes$Group <- as_factor(c("r11", "r20"))
#test if equal proportions
(JustauAlchResTest <- 
    prop.test(x = JustauAlchRes$x, JustauAlchRes$n, alternative = "two.sided"))

RST2 |> 
  ggplot(aes(y = Condition2, x = propJustau.mean, 
             colour = as.factor(AlchemyRank))) +
  ylab(NULL) +
  xlab("Proportion Admiral Justaucorps") +
  geom_vline(xintercept = propJustauOverall, linetype = "dashed", 
             colour = "#95a5a6")+
  geom_vline(xintercept = propJustauR11, linetype = "dashed", 
             colour = "#377eb8")+
  geom_vline(xintercept = propJustauR20, linetype = "dashed", 
             colour = "#B51F2E")+
  geom_pointrange(aes(xmin = propJustau.lower, xmax = propJustau.upper), 
                  size =0.5, linewidth = 0.75)+
  scale_x_continuous(breaks = seq(0, 1, by = 0.2), limits = c(0,1))+
  scale_colour_manual(values = c("#377eb8", "#B51F2E"))+
  theme( 
    legend.position = c(0.95,0.95),
    legend.justification = c(1,1),
  )+
  labs(colour = "Alchemy rank")
 

propVelvetOverall <- sum(RST2$FineVelvet)/sum(RST2$Total)
RST2 |> 
  ggplot(aes(y = Condition2, x = propVelvet.mean)) +
  ylab(NULL) +
  xlab("Proportion Fine Velvet") +
  geom_vline(xintercept = propVelvetOverall, linetype = "dashed", 
             colour = "#95a5a6")+
  geom_pointrange(aes(xmin = propVelvet.lower, xmax = propVelvet.upper), 
                  size =0.5, linewidth = 0.75)+
  scale_x_continuous(breaks = seq(0, 1, by = 0.2), limits = c(0,1))

propWaistOverall <- sum(RST2$Waistcoat)/sum(RST2$Total)
RST2 |> 
  ggplot(aes(y = Condition2, x = propWaist.mean)) +
  ylab(NULL) +
  xlab("Proportion Waistcoat") +
  geom_vline(xintercept = propWaistOverall, linetype = "dashed", 
             colour = "#95a5a6")+
  geom_pointrange(aes(xmin = propWaist.lower, xmax = propWaist.upper), 
                  size =0.5, linewidth = 0.75)+
  scale_x_continuous(breaks = seq(0, 1, by = 0.2), limits = c(0,1))

#proportions innen minor
#prop.test
propJustauOverall_Minor <- sum(RST2$Justaucorps)/(sum(RST2$Justaucorps)+sum(RST2$Waistcoat)+sum(RST$FineVelvet))
propJustauR11_Minor <- RST2 |>  
  filter(AlchemyRank == 11) |> 
  summarise(out = sum(Justaucorps)/sum(Minor)) |> 
  pull(out)
propJustauR20_Minor <- RST2 |>  filter(AlchemyRank == 20) |> 
  summarise(out = sum(Justaucorps)/sum(Minor)) |> 
  pull(out)
RST2 |> 
  ggplot(aes(y = Condition2, x = propJustau_minor.mean, 
             colour = as.factor(AlchemyRank))) +
  ylab(NULL) +
  xlab("Proportion Justaucorps among minor successes") +
  geom_vline(xintercept = propJustauOverall_Minor, linetype = "dashed", 
             colour = "#95a5a6")+
  geom_vline(xintercept = propJustauR11_Minor, linetype = "dashed", 
             colour = "#377eb8")+
  geom_vline(xintercept = propJustauR20_Minor, linetype = "dashed", 
             colour = "#B51F2E")+
  geom_pointrange(aes(xmin = propJustau_minor.lower, xmax = propJustau_minor.upper), 
                  size =0.5, linewidth = 0.75)+
  scale_x_continuous(breaks = seq(0, 1, by = 0.2), limits = c(0,1))+
  scale_colour_manual(values = c("#377eb8", "#B51F2E"))+
  theme( 
    legend.position = c(0.95,0.95),
    legend.justification = c(1,1),
  )+
  labs(colour = "Alchemy rank")


propVelvetOverall_Minor <- sum(RST2$FineVelvet)/(sum(RST2$Justaucorps)+sum(RST2$Waistcoat)+sum(RST$FineVelvet))
propVelvetR11_Minor <- RST2 |>  
  filter(AlchemyRank == 11) |> 
  summarise(out = sum(FineVelvet)/sum(Minor)) |> 
  pull(out)
propVelvetR20_Minor <- RST2 |>  
  filter(AlchemyRank == 20) |> 
  summarise(out = sum(FineVelvet)/sum(Minor)) |> 
  pull(out)

RST2 |> 
  ggplot(aes(y = Condition2, x = propVelvet_minor.mean, 
             colour = as.factor(AlchemyRank))) +
  ylab(NULL) +
  xlab("Proportion Fine Velvet among minor successes") +
  geom_vline(xintercept = propVelvetOverall_Minor, linetype = "dashed", 
             colour = "#95a5a6")+
  geom_vline(xintercept = propVelvetR11_Minor, linetype = "dashed", 
             colour = "#377eb8")+
  geom_vline(xintercept = propVelvetR20_Minor, linetype = "dashed", 
             colour = "#B51F2E")+
  geom_pointrange(aes(xmin = propVelvet_minor.lower, xmax = propVelvet_minor.upper), 
                  size =0.5, linewidth = 0.75)+
  scale_x_continuous(breaks = seq(0, 1, by = 0.2), limits = c(0,1))+
  scale_colour_manual(values = c("#377eb8", "#B51F2E"))+
  theme( 
    legend.position = c(0.95,0.95),
    legend.justification = c(1,1),
  )+
  labs(colour = "Alchemy rank")

propWaistOverall_Minor <- 
  sum(RST2$Waistcoat)/(sum(RST2$Justaucorps)+sum(RST2$Waistcoat)+sum(RST$FineVelvet))
propWaistR11_Minor <- RST2 |>  
  filter(AlchemyRank == 11) |> 
  summarise(out = sum(Waistcoat)/sum(Minor)) |> 
  pull(out)
propWaistR20_Minor <- 
  RST2 |>  filter(AlchemyRank == 20) |> 
  summarise(out = sum(Waistcoat)/sum(Minor)) |> 
  pull(out)
RST2 |> 
  ggplot(aes(y = Condition2, x = propWaist_minor.mean, 
             colour = as.factor(AlchemyRank))) +
  ylab(NULL) +
  xlab("Proportion Waistcoat among minor successes") +
  geom_vline(xintercept = propWaistOverall_Minor, linetype = "dashed", 
             colour = "#95a5a6")+
  geom_vline(xintercept = propWaistR11_Minor, linetype = "dashed", 
             colour = "#377eb8")+
  geom_vline(xintercept = propWaistR20_Minor, linetype = "dashed", 
             colour = "#B51F2E")+
  geom_pointrange(aes(xmin = propWaist_minor.lower, xmax = propWaist_minor.upper), 
                  size =0.5, linewidth = 0.75)+
  scale_x_continuous(breaks = seq(0, 1, by = 0.2), limits = c(0,1))+
  scale_colour_manual(values = c("#377eb8", "#B51F2E"))+
  theme( 
    legend.position = c(0.95,0.95),
    legend.justification = c(1,1),
  )+
  labs(colour = "Alchemy rank")


#per batch:
RST |> 
  ggplot(aes(y = Failure/Total, x = Robe/Total)) +
  geom_segment(aes(x = 0, y = 0.65, xend = 0.65, yend = 0),
               colour = "#95a5a6", 
               linetype ="dashed", 
               linewidth = 1)+
  annotate("text", x = 0.57, y = 0.21, 
           label ="Fixed 65% \ny = 0.65 − x",
           colour = "#95a5a6") +
  ylim(0,0.7) +
  xlim(0,0.7) +
  ggpmisc::stat_ma_line(se = FALSE, colour = "#B51F2E") +
  ggpmisc::stat_ma_eq(mapping = use_label(c("eq", "R2")), 
                      colour = "#B51F2E", label.x = 0.15, label.y = 0.9) +
  geom_point(size= 3, shape = 21, fill = "black", colour = "white")
#per condition (more precise, but fewer data points):
RST2 |> 
  ggplot(aes(y = Failure/Total, x = Robe/Total)) +
  geom_segment(aes(x = 0, y = 0.65, xend = 0.65, yend = 0),
               colour = "#95a5a6", 
               linetype ="dashed", 
               linewidth = 1)+
  annotate("text", x = 0.57, y = 0.21, 
           label ="Fixed 65% \ny = 0.65 − x",
           colour = "#95a5a6") +
  ylim(0,0.7) +
  xlim(0,0.7) +
  ggpmisc::stat_ma_line(se = FALSE, colour = "#B51F2E") +
  ggpmisc::stat_ma_eq(mapping = use_label(c("eq", "R2")), 
                      colour = "#B51F2E", label.x = 0.15, label.y = 0.9) +
  geom_point(size= 3, shape = 21, fill = "black", colour = "white")

cor.test(RST$Failure/RST$Total, RST$Robe/RST$Total)
cor.test(RST2$Failure/RST2$Total, RST2$Robe/RST2$Total)
ppcor::pcor.test(RST$Robe, RST$Failure, RST$Total)
ppcor::pcor.test(RST2$Robe, RST2$Failure, RST2$Total)
RST2matrix <- RST2 |> 
  select(propRobe, propFailure, propMinor, propJustau, propVelvet, propWaist, propJustau_minor, propVelvet_minor, propWaist_minor) |> 
  cor()

corrplot.mixed(RST2matrix,
 upper = "ellipse",
 lower = "number",
 order = 'AOE', 
 tl.col = 'black',
 tl.pos = "lt",
 diag = "n",
 tl.srt = 30,
 bg = "#EBEBEB",
 #mar = c(0,1,1,1)
 )
# runs-test for whole data, should be some non-randomness because batches are from different distributions
Robe2$robeSeries <- fct_other(Robe2$Result, keep = "Robe")
tseries::runs.test(Robe2$robeSeries)
snpar::runs.test(as.numeric(Robe2$robeSeries))
sjekk <- randtests::runs.test(as.numeric(Robe2$robeSeries), threshold = 1.5) 
DescTools::RunsTest(as.numeric(Robe2$robeSeries)) 

# runs-tests for each BATCH, should not be any non-randomness
Robe2$Batch2 <-
  paste("Batch ", Robe2$Batch, ", ", Robe2$Condition2, sep = "")
runsOutputBatch <- split(Robe2, Robe2$Batch2) |>
  map(function (df)
    broom::tidy(randtests::runs.test(as.numeric(df$robeSeries), threshold = 1.5)))
runsOutputBatch <- bind_rows(runsOutputBatch, .id = "ID")
runsTableBatch <- datatable(runsOutputBatch,
          options = list(pageLength = 5),
          caption = 'Runs tests for each batch') |>
  formatRound(columns = c('statistic', 'p.value'),
              digits = 3)

# runs-tests for each CONDITION, should not be any non-randomness
Robe2$Condition4 <-
  paste("Condition ", Robe2$Condition, ", ", Robe2$Condition2, sep = "")
runsOutputCond <- split(Robe2, Robe2$Condition4) |>
  map(function (df)
    broom::tidy(randtests::runs.test(as.numeric(df$robeSeries), threshold = 1.5)))
runsOutputCond <- bind_rows(runsOutputCond, .id = "ID")
runsTableCond <- datatable(runsOutputCond,
          options = list(pageLength = 5),
          caption = 'Runs tests for combination of batches under same conditions') |>
  formatRound(columns = c('statistic', 'p.value'),
              digits = 3)

# autocorrelation, just white noise
acf(as.numeric((Robe2$robeSeries)))
acf(Robe2$robeSeries)
pacf(Robe2$robeSeries)
# nye variabler:
Robe2<- Robe2 |>
  group_by(Batch) |> 
    mutate(robeSeries2 = case_when(
    robeSeries=="Robe" ~ 1, 
    robeSeries=="Other" ~0)) |> 
 summarise(robeInBatch = max(robeSeries2)) |> 
right_join(Robe2)
 
Robe2<- Robe2 |>
  group_by(Condition) |> 
    mutate(robeSeries2 = case_when(
    robeSeries=="Robe" ~ 1, 
    robeSeries=="Other" ~0)) |> 
 summarise(robeInCondition = max(robeSeries2)) |> 
right_join(Robe2) 
Robe2 <- ungroup(Robe2)
# filter on these to avoid empty batches that throws error for acf

ACFwhole <- autoplot(acf(Robe2$robeSeries, plot = FALSE), 
                     main = "Whole time series",
                     conf.int.colour = "#B51F2E")
PACFwhole <- autoplot(pacf(Robe2$robeSeries, plot = FALSE), 
                      main = "Whole time series", 
                      ylab = "Partial ACF",
                      conf.int.colour = "#B51F2E")

RobesInBatchSeries <- Robe2 |> 
  filter(robeInBatch == 1)
autoplot(acf(RobesInBatchSeries$robeSeries, plot = FALSE))
BatchACF <- split(RobesInBatchSeries, RobesInBatchSeries$Batch2) |> 
  map(function (df) acf(df$robeSeries, plot = FALSE))
BatchACF <- autoplot(BatchACF, 
                     ncol = 3, 
                     conf.int.colour = "#B51F2E")
#PACF
BatchPACF <- split(RobesInBatchSeries, RobesInBatchSeries$Batch2) |> 
  map(function (df) pacf(df$robeSeries, plot = FALSE))
BatchPACF <- autoplot(BatchPACF, 
                      ncol = 3, 
                      ylab = "Partial ACF", 
                      conf.int.colour = "#B51F2E")

RobesInConditionSeries <- Robe2 |> 
  filter(robeInCondition == 1)
autoplot(acf(RobesInConditionSeries$robeSeries, plot = FALSE))
ConditionACF <- split(RobesInConditionSeries, 
                      fct_drop(RobesInConditionSeries$Condition2)) |> 
  map(function (df) acf(df$robeSeries, plot = FALSE))
ConditionACF <- autoplot(ConditionACF, 
                         ncol = 3, 
                         conf.int.colour = "#B51F2E")
#PACF
ConditionPACF <- split(RobesInConditionSeries, RobesInConditionSeries$Condition2) |> 
  map(function (df) pacf(df$robeSeries, plot = FALSE))
ConditionPACF <- autoplot(ConditionPACF, 
                          ncol = 3, 
                          ylab = "Partial ACF", 
                          conf.int.colour = "#B51F2E")

#plot text Batch/condition number?
# sequence plots robe vs non-robe
#whole sequence:
ggplot(Robe2, aes(x=Sequence, fill = fct_rev(Result))) +
  geom_bar(position = "fill", width = 1) +
  scale_fill_brewer(palette = "RdBu", direction = -1) +
  #scale_fill_viridis_d(option = "turbo", direction = 1)+
  #scale_x_continuous(breaks = seq(0, 2000, by = 100)) +
  scale_x_continuous(expand = expansion(mult = .025)) +
  scale_y_continuous(breaks = NULL) +
  theme(legend.background = element_rect(fill = "#EBEBEB"),
        legend.key = element_rect(fill = NA),
        legend.position = "top",
        axis.text.y = element_text(size = rel(1.2)),
        legend.justification = c(0.5, 0)) +
  guides(fill = guide_legend(reverse = TRUE, title = NULL)) +
  xlab("Sequence") +
  ylab(NULL)
ggplot(Robe2, aes(x=Sequence, fill = fct_rev(robeSeries))) +
  geom_bar(position = "fill", width = 1) +
  scale_fill_manual(values = c("#95a5a6","#B51F2E")) +
  #scale_x_continuous(breaks = seq(0, 2000, by = 100)) +
  scale_x_continuous(expand = expansion(mult = .025)) +
  scale_y_continuous(breaks = NULL) +
  theme(legend.background = element_rect(fill = "#EBEBEB"),
        legend.key = element_rect(fill = NA, color = NA),
        legend.position = "top",
        axis.text.y = element_text(size = rel(1.2)),
        legend.justification = c(0.5, 0)) +
  guides(fill = guide_legend(reverse = TRUE, title = NULL)) +
  xlab("Sequence") +
  ylab(NULL)
# per batch:
ggplot(Robe2, aes(x=BatSeq, fill = fct_rev(robeSeries))) +
  geom_bar(position = "fill", width = 1) +
  facet_wrap(vars(fct_rev(Condition3), GroupBatch), strip.position = "left", ncol = 1) +
  #scale_fill_viridis_d(option = "turbo", direction = 1)+
  scale_fill_manual(values = c("#95a5a6","#B51F2E")) +
  scale_x_continuous(breaks = seq(0, 120, by = 20)) +
  scale_y_continuous(breaks = NULL) +
  theme(legend.background = element_rect(fill = "#EBEBEB"),
        legend.key = element_rect(fill = NA, color = NA),
        legend.position = "top",
        axis.text.y = element_text(size = rel(1.2)),
        legend.justification = c(0.5, 0)) +
  guides(fill = guide_legend(reverse = TRUE, title = NULL)) +
  theme(strip.text.y.left = element_blank(), #element_text(angle = 0, hjust = 0),
        strip.text.x = element_blank(),
        panel.spacing = unit(0.05,"cm")) +
  xlab("Sequence") +
  ylab(NULL)
# per condition:
# first make a sequence within condition.

Robe2 <- Robe2 |> 
  group_by(Condition) |> 
  mutate(StartSeq = min(Sequence),
         CondSeq = Sequence-StartSeq+1)
Robe2 <- ungroup(Robe2)
         
ggplot(Robe2, aes(x=CondSeq, fill = fct_rev(robeSeries))) +
  geom_bar(position = "fill", width = 1) +
  facet_wrap(vars(fct_rev(Condition3)), strip.position = "left", ncol = 1) +
  #scale_fill_viridis_d(option = "turbo", direction = 1)+
  scale_fill_manual(values = c("#95a5a6","#B51F2E")) +
  scale_x_continuous(breaks = seq(0, 220, by = 20)) +
  scale_y_continuous(breaks = NULL) +
  theme(legend.background = element_rect(fill = "#EBEBEB"),
        legend.key = element_rect(fill = NA, color = NA),
        legend.position = "top",
        axis.text.y = element_text(size = rel(1.2)),
        legend.justification = c(0.5, 0)) +
  guides(fill = guide_legend(reverse = TRUE, title = NULL)) +
  theme(strip.text.y.left = element_blank(), #element_text(angle = 0, hjust = 0),
        strip.text.x = element_blank(),
        panel.spacing = unit(0.05,"cm")) +
  xlab("Sequence") +
  ylab(NULL)
knitr::include_graphics('theorydrawing.png')
knitr::include_graphics('FABingredients.jpg')
knitr::include_graphics('RobeEX.jpg')
DT::datatable(FAB[,-1], options = list(pageLength = 10), caption = 'FAB experiments raw data. Values are number of attempts needed')
DT::datatable(Robe, options = list(pageLength = 10), caption = 'Robe experiments raw data')
runsTableBatch
runsTableCond
ACFwhole
PACFwhole
BatchACF
ConditionACF
BatchPACF
ConditionPACF
sessioninfo::session_info()

8.8 Session information

sessioninfo::session_info()
## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value
##  version  R version 4.2.3 (2023-03-15 ucrt)
##  os       Windows 10 x64 (build 19045)
##  system   x86_64, mingw32
##  ui       RTerm
##  language (EN)
##  collate  Norwegian Bokmål_Norway.utf8
##  ctype    Norwegian Bokmål_Norway.utf8
##  tz       Europe/Berlin
##  date     2023-04-13
##  pandoc   2.19.2 @ C:/Program Files/RStudio/resources/app/bin/quarto/bin/tools/ (via rmarkdown)
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package      * version  date (UTC) lib source
##  backports      1.4.1    2021-12-13 [1] CRAN (R 4.2.0)
##  binom        * 1.1-1.1  2022-05-02 [1] CRAN (R 4.2.0)
##  bookdown       0.33     2023-03-06 [1] CRAN (R 4.2.2)
##  boot           1.3-28.1 2022-11-22 [2] CRAN (R 4.2.3)
##  broom        * 1.0.4    2023-03-11 [1] CRAN (R 4.2.2)
##  bslib          0.4.2    2022-12-16 [1] CRAN (R 4.2.2)
##  cachem         1.0.7    2023-02-24 [1] CRAN (R 4.2.2)
##  cellranger     1.1.0    2016-07-27 [1] CRAN (R 4.2.0)
##  class          7.3-21   2023-01-23 [1] CRAN (R 4.2.2)
##  cli            3.6.1    2023-03-23 [1] CRAN (R 4.2.3)
##  colorspace     2.1-0    2023-01-23 [1] CRAN (R 4.2.2)
##  corrplot     * 0.92     2021-11-18 [1] CRAN (R 4.2.0)
##  crayon         1.5.2    2022-09-29 [1] CRAN (R 4.2.0)
##  crosstalk      1.2.0    2021-11-04 [1] CRAN (R 4.2.0)
##  curl           5.0.0    2023-01-12 [1] CRAN (R 4.2.2)
##  data.table     1.14.8   2023-02-17 [1] CRAN (R 4.2.2)
##  DescTools      0.99.48  2023-02-19 [1] CRAN (R 4.2.2)
##  digest         0.6.31   2022-12-11 [1] CRAN (R 4.2.2)
##  dplyr        * 1.1.1    2023-03-22 [1] CRAN (R 4.2.3)
##  DT           * 0.27     2023-01-17 [1] CRAN (R 4.2.2)
##  e1071          1.7-13   2023-02-01 [1] CRAN (R 4.2.2)
##  ellipsis       0.3.2    2021-04-29 [1] CRAN (R 4.2.0)
##  evaluate       0.20     2023-01-17 [1] CRAN (R 4.2.2)
##  Exact          3.2      2022-09-25 [1] CRAN (R 4.2.0)
##  expm           0.999-7  2023-01-09 [1] CRAN (R 4.2.2)
##  fansi          1.0.4    2023-01-22 [1] CRAN (R 4.2.2)
##  farver         2.1.1    2022-07-06 [1] CRAN (R 4.2.1)
##  fastmap        1.1.1    2023-02-24 [1] CRAN (R 4.2.2)
##  forcats      * 1.0.0    2023-01-29 [1] CRAN (R 4.2.2)
##  generics       0.1.3    2022-07-05 [1] CRAN (R 4.2.1)
##  ggfortify    * 0.4.16   2023-03-20 [1] CRAN (R 4.2.3)
##  ggplot2      * 3.4.2    2023-04-03 [1] CRAN (R 4.2.3)
##  ggpmisc      * 0.5.2    2022-12-17 [1] CRAN (R 4.2.3)
##  ggpp         * 0.5.2    2023-04-01 [1] CRAN (R 4.2.3)
##  ggrepel        0.9.3    2023-02-03 [1] CRAN (R 4.2.2)
##  gld            2.6.6    2022-10-23 [1] CRAN (R 4.2.2)
##  glue           1.6.2    2022-02-24 [1] CRAN (R 4.2.0)
##  gridExtra      2.3      2017-09-09 [1] CRAN (R 4.2.0)
##  gtable         0.3.3    2023-03-21 [1] CRAN (R 4.2.3)
##  highr          0.10     2022-12-22 [1] CRAN (R 4.2.2)
##  hms            1.1.3    2023-03-21 [1] CRAN (R 4.2.3)
##  htmltools      0.5.5    2023-03-23 [1] CRAN (R 4.2.3)
##  htmlwidgets    1.6.2    2023-03-17 [1] CRAN (R 4.2.2)
##  httr           1.4.5    2023-02-24 [1] CRAN (R 4.2.2)
##  jquerylib      0.1.4    2021-04-26 [1] CRAN (R 4.2.0)
##  jsonlite       1.8.4    2022-12-06 [1] CRAN (R 4.2.2)
##  kableExtra   * 1.3.4    2021-02-20 [1] CRAN (R 4.2.0)
##  knitr          1.42     2023-01-25 [1] CRAN (R 4.2.2)
##  labeling       0.4.2    2020-10-20 [1] CRAN (R 4.2.0)
##  lattice        0.21-8   2023-04-05 [1] CRAN (R 4.2.3)
##  lifecycle      1.0.3    2022-10-07 [1] CRAN (R 4.2.2)
##  lmodel2        1.7-3    2018-02-05 [1] CRAN (R 4.2.0)
##  lmom           2.9      2022-05-29 [1] CRAN (R 4.2.0)
##  magrittr       2.0.3    2022-03-30 [1] CRAN (R 4.2.0)
##  MASS           7.3-58.3 2023-03-07 [1] CRAN (R 4.2.2)
##  Matrix         1.5-4    2023-04-04 [1] CRAN (R 4.2.3)
##  MatrixModels   0.5-1    2022-09-11 [1] CRAN (R 4.2.0)
##  munsell        0.5.0    2018-06-12 [1] CRAN (R 4.2.0)
##  mvtnorm        1.1-3    2021-10-08 [1] CRAN (R 4.2.0)
##  pillar         1.9.0    2023-03-22 [1] CRAN (R 4.2.3)
##  pkgconfig      2.0.3    2019-09-22 [1] CRAN (R 4.2.0)
##  polynom        1.4-1    2022-04-11 [1] CRAN (R 4.2.0)
##  ppcor          1.1      2015-12-03 [1] CRAN (R 4.2.3)
##  proxy          0.4-27   2022-06-09 [1] CRAN (R 4.2.0)
##  purrr        * 1.0.1    2023-01-10 [1] CRAN (R 4.2.2)
##  quadprog       1.5-8    2019-11-20 [1] CRAN (R 4.2.0)
##  quantmod       0.4.22   2023-04-07 [1] CRAN (R 4.2.3)
##  quantreg       5.95     2023-04-08 [1] CRAN (R 4.2.3)
##  R6             2.5.1    2021-08-19 [1] CRAN (R 4.2.0)
##  randtests      1.0.1    2022-06-20 [1] CRAN (R 4.2.0)
##  RColorBrewer   1.1-3    2022-04-03 [1] CRAN (R 4.2.0)
##  Rcpp           1.0.10   2023-01-22 [1] CRAN (R 4.2.2)
##  readODS      * 1.8.0    2023-01-23 [1] CRAN (R 4.2.2)
##  readr          2.1.4    2023-02-10 [1] CRAN (R 4.2.2)
##  readxl         1.4.2    2023-02-09 [1] CRAN (R 4.2.2)
##  rlang          1.1.0    2023-03-14 [1] CRAN (R 4.2.2)
##  rmarkdown      2.21     2023-03-26 [1] CRAN (R 4.2.3)
##  rootSolve      1.8.2.3  2021-09-29 [1] CRAN (R 4.2.0)
##  rstudioapi     0.14     2022-08-22 [1] CRAN (R 4.2.1)
##  rvest          1.0.3    2022-08-19 [1] CRAN (R 4.2.0)
##  sass           0.4.5    2023-01-24 [1] CRAN (R 4.2.2)
##  scales         1.2.1    2022-08-20 [1] CRAN (R 4.2.0)
##  sessioninfo    1.2.2    2021-12-06 [1] CRAN (R 4.2.0)
##  shades       * 1.4.0    2019-08-02 [1] CRAN (R 4.2.0)
##  snpar          1.0      2014-08-16 [1] Github (debinqiu/snpar@578b79c)
##  SparseM        1.81     2021-02-18 [1] CRAN (R 4.2.0)
##  stringi        1.7.12   2023-01-11 [1] CRAN (R 4.2.2)
##  stringr      * 1.5.0    2022-12-02 [1] CRAN (R 4.2.2)
##  survival       3.5-5    2023-03-12 [1] CRAN (R 4.2.3)
##  svglite        2.1.1    2023-01-10 [1] CRAN (R 4.2.2)
##  systemfonts    1.0.4    2022-02-11 [1] CRAN (R 4.2.0)
##  tibble         3.2.1    2023-03-20 [1] CRAN (R 4.2.3)
##  tidyr        * 1.3.0    2023-01-24 [1] CRAN (R 4.2.2)
##  tidyselect     1.2.0    2022-10-10 [1] CRAN (R 4.2.2)
##  tseries      * 0.10-53  2023-01-31 [1] CRAN (R 4.2.2)
##  TTR            0.24.3   2021-12-12 [1] CRAN (R 4.2.0)
##  tufte          0.12     2022-01-27 [1] CRAN (R 4.2.3)
##  tzdb           0.3.0    2022-03-28 [1] CRAN (R 4.2.0)
##  utf8           1.2.3    2023-01-31 [1] CRAN (R 4.2.2)
##  vctrs          0.6.1    2023-03-22 [1] CRAN (R 4.2.3)
##  viridisLite    0.4.1    2022-08-22 [1] CRAN (R 4.2.1)
##  webshot        0.5.4    2022-09-26 [1] CRAN (R 4.2.0)
##  withr          2.5.0    2022-03-03 [1] CRAN (R 4.2.0)
##  xfun           0.38     2023-03-24 [1] CRAN (R 4.2.3)
##  xml2           1.3.3    2021-11-30 [1] CRAN (R 4.2.0)
##  xts            0.13.0   2023-02-20 [1] CRAN (R 4.2.2)
##  yaml           2.3.7    2023-01-23 [1] CRAN (R 4.2.2)
##  zoo            1.8-11   2022-09-17 [1] CRAN (R 4.2.1)
## 
##  [1] C:/R/RLibs
##  [2] C:/Program Files/R/R-4.2.3/library
## 
## ──────────────────────────────────────────────────────────────────────────────

9 Footnotes


  1. Of course, the high negative correlation seen in Figure 25 is meaningless in itself because it is partly due to the same total number of trials being used to calculate both proportions, and the variables are not free to vary independently – correlation between parts of a whole is inherently spurious. However, this does not account for the whole relationship since the other correlations between the proportions were much weaker(Figure 26), and the correlation between failures and robes while controlling for totals is still strong: \(r_{partial}\) = -0.91, n = 14, p < 0.0001.↩︎

  2. Figure 26 also includes variables for proportions within the minor success category, denoted _minor. The caveats explained in footnote 1 applies even more.↩︎

  3. Multinomial runs-tests and auto-correlation is computationally complex and beyond the scope of this report, but see Weiss (2017).↩︎

  4. I acknowledge, but ignore, the problem that single batches have inherently less statistical power because of lower sample sizes.↩︎

  5. He could have said FABulous↩︎

  6. Rumours of the flawed (and exploitable) RNG algorithms used in UWO have floated around since the launch of Gama server. For example, one idea is that there are good and bad sessions. So that if you fail, you should close the dialogue screen and start over until you hit a better session. (Or maybe wait a bit until the bad times are over. Who knows.)↩︎

  7. Only for the last individual would a slight bias occur, which is negligible.↩︎

LS0tDQp0aXRsZTogIlJlcG9ydCBmcm9tIGEgRkFCdG9yeSINCmF1dGhvcjogIlN0aW5rZXIsIEFuaW1hIChMb25kb24pLCBEZXB0LiBvZiBFeHBlcmltZW50YWwgQWxjaGVteSINCmRhdGU6ICJMYXN0IGNvbXBpbGVkOiBgciBTeXMuc2V0bG9jYWxlKCdMQ19USU1FJywgJ0VuZ2xpc2gnKTsgZm9ybWF0KFN5cy50aW1lKCksICclZSAlQiwgJVknKWAiDQpvdXRwdXQ6DQogIGJvb2tkb3duOjpodG1sX2RvY3VtZW50MjoNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgdG9jOiB5ZXMNCiAgICBmaWdfY2FwdGlvbjogeWVzDQogICAgZ2xvYmFsX251bWJlcmluZzogeWVzDQogICAgdG9jX2Zsb2F0Og0KICAgICAgY29sbGFwc2VkOiB5ZXMNCiAgICB0aGVtZTogZmxhdGx5DQogICAgaGlnaGxpZ2h0OiBoYWRkb2NrDQplZGl0b3Jfb3B0aW9uczogDQogIGNodW5rX291dHB1dF90eXBlOiBjb25zb2xlDQotLS0NCg0KYGBge2NzcywgZWNobz1GQUxTRX0NCnAuY2FwdGlvbiB7DQogIGNvbG9yOiAjNzc3Ow0KfQ0KY2FwdGlvbiB7DQogIGNvbG9yOiAjNzc3Ow0KfQ0KYGBgDQoNCmBgYHtyLCBzZXR1cCwgcmVzdWx0cz0naGlkZScsIGVjaG8gPSBGQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChmaWcud2lkdGggPSA1LCBmaWcuYWxpZ24gPSAnY2VudGVyJywgDQogICAgICAgICAgICAgICAgICAgICAgY29sbGFwc2UgPSBUUlVFLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSkNCmBgYA0KDQpgYGB7ciwgZWNobyA9IFRSVUUsIHJlc3VsdHM9J2hpZGUnfQ0KI3BhY2thZ2VzDQpsaWJyYXJ5KHJlYWRPRFMpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeSh0aWR5cikNCmxpYnJhcnkoa2FibGVFeHRyYSkNCmxpYnJhcnkoZm9yY2F0cykNCmxpYnJhcnkocHVycnIpDQpsaWJyYXJ5KHRzZXJpZXMpDQpsaWJyYXJ5KGdnZm9ydGlmeSkNCmxpYnJhcnkoYmlub20pDQpsaWJyYXJ5KGJyb29tKQ0KbGlicmFyeShzdHJpbmdyKQ0KbGlicmFyeShnZ3BtaXNjKQ0KbGlicmFyeShjb3JycGxvdCkNCmxpYnJhcnkoRFQpDQpsaWJyYXJ5KHNoYWRlcykNCiNkYXRhDQpGQUIgPC0gcmVhZF9vZHMoIn5cXEZBQnRvcnlcXEZBQnRvcnkub2RzIiwgc2hlZXQgPTIpDQpGQUIyIDwtIEZBQiAgfD4gIHBpdm90X2xvbmdlcigNCiAgY29scyA9IEJpcmV0dGE6V2hpdGVPcmUsDQogIG5hbWVzX3RvID0gIkl0ZW0iLA0KICB2YWx1ZXNfdG8gPSAiQXR0ZW1wdHNOZWVkZWQiDQogICkNClNuaXR0IDwtIEZBQjIgIHw+IA0KICBncm91cF9ieShUb29uLCBXaG8pIHw+DQogIHN1bW1hcmlzZShNZWFuQXR0ZW1wdHNOZWVkZWQgPSBtZWFuKEF0dGVtcHRzTmVlZGVkKSkNClJvYmUgPC0gcmVhZF9vZHMoIn5cXEZBQnRvcnlcXEZBQnRvcnkub2RzIiwgc2hlZXQgPTMpDQpEZXNpZ24gPC0gcmVhZF9vZHMoIn5cXEZBQnRvcnlcXEZBQnRvcnkub2RzIiwgc2hlZXQgPTQpDQpSb2JlU3VtbWFyeVRhYmxlIDwtIHJlYWRfb2RzKCJ+XFxGQUJ0b3J5XFxGQUJ0b3J5Lm9kcyIsIHNoZWV0ID02KQ0KYGBgDQoNCiMgU3VtbWFyeQ0KDQpOZXcgZGF0YSBwcmVzZW50ZWQgaGVyZSBzaG93IHRoYXQgdGhlIEhvbHkgUm9tYW4gRW1wZXJvciAoSFJFKSBwb2xpY3kgZWZmZWN0IG9uIGFsY2hlbXkgZXhwZXJpbWVudHMgaXMgaHVnZSwgbXVjaCBsYXJnZXIgdGhhbiB0aGUgZWZmZWN0IG9mIHRoZSBBZGVwdCB0aXRsZS4gVXRpbGlzaW5nIGEgcGxldGhvcmEgb2YgdHJpY2tzIGl0IHdhcyBwb3NzaWJsZSBvdmVyIGEgZmV3IGRheXMgdG8gY29tcGxldGUgdGhlIE1lbW9yaWFsIEFsYnVtIGZvciBhbGNoZW15IGV4cGVyaW1lbnRzICh3aXRoIEZBQiBhcyByZXdhcmQpIGZvciBhIGxhcmdlIG51bWJlciBvZiBsb3cgbGV2ZWwgY2hhcmFjdGVycyBhdCBiYXNlIHJhbmsgMSBhbGNoZW15LCBhdCAyMCUtLTI1JSBzdWNjZXNzIHJhdGUgKGRlcGVuZGluZyBvbiBpdGVtKSBhY3Jvc3MgMzEwMCBhbGNoZW15IGV4cGVyaW1lbnRzLiBBbHNvIGhhdmluZyB0aGUgY291cnQgYWxjaGVtaXN0IGFkdmlzb3Igcm9sZSBvbiB0b3Agb2YgdGhlIEhSRSBlZmZlY3QgZ2F2ZSAxMCUgYWRkaXRpb25hbCBzdWNjZXNzLCBhcyByZXZlYWxlZCBieSBhIGZ1cnRoZXIgMTk2MiBzZXBhcmF0ZSBleHBlcmltZW50cyBmb2N1c2luZyBzb2xlbHkgb24gQWRlcHQncyByb2JlLiBXaXRoIG9ubHkgYWRlcHQgdGl0bGUgdGhlIHN1Y2Nlc3Mgd2FzIGFyb3VuZCAxJS4gVGhlIHByb3BvcnRpb24gb2YgbWlub3Igc3VjY2VzcyB3YXMgdW5hZmZlY3RlZCBieSB0aGVzZSBmYWN0b3JzLiBUaGVyZSB3YXMgbm8gbWVhc3VyYWJsZSBlZmZlY3Qgb2YgYWxjaGVteSByYW5rLCBPeGZvcmQgc2tpbGxzLCBwYXltYXN0ZXIgYWlkZSBvciBFWCBlcXVpcG1lbnQgb24gcm9iZSBzdWNjZXNzLCBidXQgYW4gZWZmZWN0IG9mIGFsY2hlbXkgcmFuayBvbiB0aGUgbWlub3Igc3VjY2Vzc2VzLg0KDQojIEludHJvZHVjdGlvbg0KDQpJbiBVbmNoYXJ0ZWQgV2F0ZXJzIE9ubGluZSBbKFVXTyldKGh0dHBzOi8vdXdvLnBhcGF5YXBsYXkuY29tL3V3by5kbyl7dGFyZ2V0PSJfYmxhbmsifSwgdGhlIEFsY2hlbXkgRXhwZXJpbWVudCBSZXN1bHQgWyhOby4xKV0oaHR0cDovL3V3b2RibWlycm9yLml2eXJvLm5ldC9lZy9tYWluLnBocD9pZD04ODg4MjEyNCl7dGFyZ2V0PSJfYmxhbmsifSBNZW1vcmlhbCBBbGJ1bSAoTUEpIGdpdmUgRm9yYmlkZGVuIEFsY2hlbXkgQm9vayAoRkFCLCBGaWd1cmUgXEByZWYoZmlnOkZBQnBpYykpIGFzIGEgcmV3YXJkIGZvciBjb21wbGV0aW5nLiBJdCBpcyBub3RvcmlvdXNseSBoYXJkIHRvIGNvbXBsZXRlIGJlY2F1c2UgdGhlIHN1Y2Nlc3MgcmF0ZSBvZiBvYnRhaW5pbmcgdGhlIGVudHJpZXMgaW4gaXQgaXMgdmVyeSBsb3csIHRob3VnaHQgdG8gYmUgMC4xJSBiYXNlIG9yIGxlc3MgZm9yIHNvbWUgaXRlbXMuIER1ZSB0byB0aGlzIGRpZmZpY3VsdHksIGFuZCBiZWNhdXNlIG9uZSBjaGFyYWN0ZXIgY2FuIG9ubHkgb2J0YWluIG9uZSBGQUIsIGl0IGlzIGEgdmFsdWFibGUgYW5kIHNvdWdodCBhZnRlciBpdGVtIHRoYXQgc2VsbHMgZm9yIGFyb3VuZCAxMCBjYXB0YWluJ3MgdGlja2V0cy4gSXQgZ2l2ZXMgcmFuayAxNSBpbmNyZWFzZWQgTmFuYmFuIHJhdGVzLCB0aGUgaGlnaGVzdCBpbiB0aGUgZ2FtZS4gKEl0IGlzIGFsc28gcG9zc2libGUgdG8gb2J0YWluIEZBQiBmcm9tIHNwZW5kaW5nIHJlYWwgbW9uZXksIGJ1dCB0aGUgW3RpY2tldF0oaHR0cDovL3V3b2RibWlycm9yLml2eXJvLm5ldC9lZy9tYWluLnBocD9pZD0wMTU2MTAwNyl7dGFyZ2V0PSJfYmxhbmsifSBpdCBjb21lcyBmcm9tIGFsc28gZ2l2ZXMgdGhlIGNob2ljZSBvZiBWYWdyYW50J3MgV2VhciB3aGljaCBpcyBldmVuIG1vcmUgdmFsdWFibGUgc28gZmV3IHdvdWxkIGNob29zZSB0byBnZXQgYSBGQUIgdGhhdCB3YXkpLg0KDQpgYGB7ciBGQUJwaWMsIG91dC53aWR0aD0nNTAlJywgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcuY2FwPSJUaGUgRkFCIiwgZWNobyA9IEZBTFNFfQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoJ0ZBQnBpYy5wbmcnKQ0KYGBgDQoNCkhhdmluZyBiYXNlIHJhbmsgMTMgaW4gQWxjaGVteSBoZWxwcywgYmVjYXVzZSB0aGUgW0FkZXB0IHRpdGxlXShodHRwOi8vdXdvZGJtaXJyb3IuaXZ5cm8ubmV0L2VnL21haW4ucGhwP2lkPTg4ODgwNTE4KXt0YXJnZXQ9Il9ibGFuayJ9IG9idGFpbmVkIGF0IHIxMyBpbmNyZWFzZXMgdGhlIHN1Y2Nlc3MgcmF0ZSBvZiBhbGNoZW15IGV4cGVyaW1lbnRzLiBCdXQgZXZlbiB3aXRoIHRoZSB0aXRsZSBhY3RpdmUgdGhlIHN1Y2Nlc3MgcmF0ZSBpcyBsb3c6IEFyb3VuZCAxJSB0byBnZXQgQWRlcHQncyBCaXJldHRhIGFuZCBBZGVwdCdzIFJvYmUsIDUlIHRvIGdldCBHb2xkIFNob3J0IFN3b3JkIGFuZCAxMCUgZm9yIHRoZSByZXN0ICh1bnB1Ymxpc2hlZCBndXQgZmVlbGluZ3MgYmFzZWQgb24gZ2V0dGluZyBhZGVwdCB0aXRsZSBhbmQgRkFCIGZvciBhYm91dCAyNSBjaGFyYWN0ZXJzIGluIHRoZSBwYXN0KS4gV2l0aCBhZGVwdCB0aXRsZSwgdGhlIG51bWJlciBvZiBhdHRlbXB0cyBuZWVkZWQgdG8gZ2V0IG9uZSBpdGVtIGNhbiBzdGlsbCBlYXNpbHkgcmVhY2ggdGhlIGh1bmRyZWRzICg1ODUgaGF2ZSBiZWVuIG9ic2VydmVkLCBhbmQgbW9yZSBydW1vdXJlZCkuIFNvIHRoaXMgaXMgaGFyZCB0byBkbywgY29uc2lkZXJpbmcgdGhlIHJlbGF0aXZlIGRpZmZpY3VsdHkgb2Ygb2J0YWluaW5nIHRoZSBiYXNlIG1hdGVyaWFscyBpbiBxdWFudGl0eSBhbmQgaW4gcGFydGljdWxhciB0aGUgbmVlZCBmb3IgYmFzZSByMTMuDQoNCkluY3JlYXNlZCBhdmFpbGFiaWxpdHkgb2YgZ2VhciBib29zdGluZyBhbGNoZW15IGluIHJlY2VudCB5ZWFycyBoYXZlIG1hZGUgaXQgcG9zc2libGUgdG8gZ3JpbmQgYWxjaGVteSB2ZXJ5IGVmZmljaWVudGx5IGZyb20gYmFzZSByMSsxMSAoW21ha2luZyBnb2xkXShodHRwOi8vdXdvZGJtaXJyb3IuaXZ5cm8ubmV0L2VnL21haW4ucGhwP2lkPTAxODAwMjQyKXt0YXJnZXQ9Il9ibGFuayJ9IGF0IEpvaG4gRGVlIGluIExvbmRvbiwgYW5kIFt1c2luZyBnYXNlb3VzIGRydWdzXShodHRwOi8vdXdvZGJtaXJyb3IuaXZ5cm8ubmV0L2VnL21haW4ucGhwP2lkPTAxNTAwNDg4KXt0YXJnZXQ9Il9ibGFuayJ9IGF0IFBhcmFjZWxzdXMgaW4gVmVuaWNlKSwgbWFraW5nIGl0IGVhc2llciB0byBvYnRhaW4gdGhlIGFkZXB0IHRpdGxlLiBJdCBpcyBuZXZlcnRoZWxlc3Mgc3RpbGwgYSBtYWpvciBlZmZvcnQgYmVjYXVzZSBvZiB0aGUgaHVnZSBhbW91bnQgb2YgbWF0ZXJpYWxzIG5lZWRlZCBmb3IgdGhlIHNraWxsIGdyaW5kIGFuZCB0aGUgbG93IHN1Y2Nlc3Mgb2YgdGhlIGV4cGVyaW1lbnRzLiBBbHRob3VnaCBpdCB0YWtlcyBsZXNzIHRoYW4gMzAgbWludXRlcyB0byBnZXQgZnJvbSByMSB0byByMTMgYmFzZSBhbGNoZW15IHVzaW5nIGJlc3QgcHJhY3RpY2VzLCB0aGlzIG9idmlvdXNseSBkb2VzIG5vdCBpbmNsdWRlIHRoZSBjb25zaWRlcmFibGUgdGltZSBuZWVkZWQgdG8gcHJlcGFyZSB0aGUgbmVjZXNzYXJ5IG1hdHMuDQoNCkhvd2V2ZXIsIGluY3JlYXNlZCBhbGNoZW15IGV4cGVyaW1lbnQgc3VjY2VzcyByYXRlIGlzIGEgW3Bvc3NpYmxlIHBvbGljeV0oaHR0cDovL2d2by5nYW1lZGIuaW5mby93aWtpLz9FbGVjdGlvbiNuYWE4NWM1Yyl7dGFyZ2V0PSJfYmxhbmsifSBvZiBzb21lIEhvbHkgUm9tYW4gRW1wZXJvciAoSFJFKSBjYW5kaWRhdGVzLiBXaXRoIGVub3VnaCBzdXBwb3J0IGRvbmUgdG8gdW5sb2NrIHRoaXMgZWZmZWN0IGl0IG1heSBiZSBwb3NzaWJsZSB0byBlYXNpbHkgb2J0YWluIEZBQiwgZXZlbiB3aXRob3V0IEFkZXB0IHRpdGxlLCB3aXRob3V0IGdyaW5kaW5nIGFsY2hlbXkgYXQgYWxsIChwcm92aWRlZCBvbmUgY291bGQgcmVhY2ggdGhlIHJlcXVpcmVkIHJhbmtzIGZvciB0aGUgZXhwZXJpbWVudHM6IHIxMC0tMTIgbmVlZGVkLCArIHNlY29uZGFyeSBza2lsbHMpLiBUaGlzIEhSRSBwb2xpY3kgaXMgcmFyZSwgYnV0IHdlIGhhdmUgaGFkIGl0IGxlYXN0IG9uY2UgZWFybHkgb24gTWFyaXMgc2VydmVyIHdoZW4gSSBtYWRlIDEyNSBBZGVwdCBSb2JlIGFuZCB0cmFuc211dGVkIHRoZW0gaW50byBBbGNoZW1pc3QgUm9iZSBhbmQgdGhlbiBbQWxjaGVtaXN0IFJvYmUgRVhdKGh0dHA6Ly91d29kYm1pcnJvci5pdnlyby5uZXQvZWcvbWFpbi5waHA/aWQ9MDAwNTUzMDEpe3RhcmdldD0iX2JsYW5rIn0gdGhhdCBzb2xkIGZvciAxIGJpbGxpb24gZHVjYXRzIGVhY2guDQoNCkR1cmluZyBNYXJjaCAyMDIzIHN1Y2ggYW4gb3Bwb3J0dW5pdHkgY2FtZSBhZ2FpbiBpbiB0aGUgZm9ybSBvZiBSdWRvbGYgSUkgYXMgRW1wZXJvci4gUGxheWVycyB0aGF0IGhhZCBzdXBwb3J0ZWQgdGhpcyBjYW5kaWRhdGUgd2l0aCBhdCBsZWFzdCA0OSBzdXBwb3J0IHBlcm1pdHMgKGkuZS4gNC45bSBkdWNhdHMgZWZmZWN0aXZlIHN1cHBvcnQgbmVlZGVkKSBnb3QgdGhlIGVmZmVjdCBhY3RpdmF0ZWQgZm9yIDMxIGRheXMsIGFsb25nIHdpdGggKzIgYWxjaGVteSAoRmlndXJlIFxAcmVmKGZpZzpydWRvbGZQaWN0dXJlKSkuDQoNCmBgYHtyIHJ1ZG9sZlBpY3R1cmUsIG91dC53aWR0aD0nNTAlJywgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcuY2FwPSJQb2xpY3kgb2YgU3VwcG9ydCBBbGNoZW15IGFuZCBDb3VydCBBbGNoZW1pc3QgYWR2aXNvciBwb3NpdGlvbiBmb3IgUnVkb2xmIElJIiwgZWNobyA9IEZBTFNFfQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoJ0hSRS5wbmcnKQ0KYGBgDQoNCkxlc3MgdGhhbiBhIHdlZWsgbGF0ZXIgUGFwYXlhUGxheSBsYXVuY2hlZCBhbiBbZXZlbnRdKGh0dHBzOi8vdXdvLnBhcGF5YXBsYXkuY29tL3V3by5kbz90cD1uZXdzLnZpZXcmcG9zdGlkPTQzODgpe3RhcmdldD0iX2JsYW5rIn0gdGhhdCBnYXZlIGFub3RoZXIgKzEgYWxjaGVteSBmb3IgMiB3ZWVrcy4gSW4gYWRkaXRpb24sIFN0aW5rZXIgZ290IHRoZSBBbGNoZW1pc3QgYWR2aXNvciBjb3VydCBwb3NpdGlvbiBzbyBjb3VsZCBnaXZlIGZyaWVuZHMgb25lIG1vcmUgKzEgYWxjaGVteSAoRmlndXJlIFxAcmVmKGZpZzpydWRvbGZQaWN0dXJlKSksIGFzIHdlbGwgYXMgYmVpbmcgQWxjaGVtaXN0IE1laXN0ZXIgKGJhc2UgcmFuayAxNSsgYWxjaGVteSkgYW5kIHRodXMgYWJsZSB0byBnaXZlIHlldCBhbm90aGVyICsxIHRvIGFwcHJlbnRpY2VzLiBJZiBhbGwgdGhpcyB3YXMgbm90IGVub3VnaCwgQXRsYW50aXMgbWFkZSBpdHMgYXBwZWFyYW5jZSBpbiB0aGUgbWlkc3Qgb2YgaXQuIEFsdGhvdWdoIHVucmVsYXRlZCB0byB0aGUgZXhwZXJpbWVudCBzdWNjZXNzIGZvciB0aGUgTUEsIEF0bGFudGlzIGlzIHZlcnkgcmVsZXZhbnQgZm9yIGFsY2hlbXkgc2luY2UgaXQgZ2l2ZXMgKzIwJSB0byB0cmFuc211dGF0aW9uIHN1Y2Nlc3MgKHN1Y2ggYXMgd2hlbiBtYWtpbmcgQWxjaGVtaXN0IHJvYmUgZnJvbSB0aGUgQWRlcHQncyByb2JlIG1hZGUgZm9yIHRoZSBGQUIpLiBUaGVyZSB3YXMgYWxzbyAxMDAlIHNraWxsIHByb2ZpY2llbmN5IGV2ZW50IGdvaW5nIG9uIHNvIGl0IHdhcyB1bmF2b2lkYWJsZSB0byByYW5rIHVwIHNldmVyYWwgdGltZXMgYmVmb3JlIGZpbmlzaGluZyB0aGUgTUEuDQoNClRodXMsIHRoZXJlIHdhcyBhIGxvdCBvZiBhbGNoZW15IHNraWxsIGJvb3N0IGhhcHBlbmluZyBhdCB0aGUgc2FtZSB0aW1lIGFzIHRoZSBleHBlcmltZW50IHN1Y2Nlc3MgYm9vc3QuIFRoZSB0aW1lIHdhcyByaXBlIGZvciBjcmVhdGluZyBhICoqRkFCdG9yeSoqLg0KDQpUaGlzIHJlcG9ydCBwcmVzZW50IGFuYWx5c2VzIG9mIHNvbWUgZGF0YSB0aGF0IHdhcyBnYXRoZXJlZCB3aGVuIG1ha2luZyBNQSBlbnRyaWVzIGZvciBGQUIgZHVyaW5nIHRoZXNlIHVucHJlY2VkZW50ZWQgY2lyY3Vtc3RhbmNlcywgYW5kIHNvbWUgYWRkaXRpb25hbCBleHBlcmltZW50cyBwZXJmb3JtZWQgdG8gYmV0dGVyIHVuZGVyc3RhbmQgZXhhY3RseSBob3cgdGhlIEhSRSBhbmQgb3RoZXIgZmFjdG9ycyBpbmZsdWVuY2UgdGhlIG91dGNvbWUgb2YgYWxjaGVteSBleHBlcmltZW50cywgYW5kIGhvdyB0aGlzIHJlbGF0ZXMgdG8gY3JhZnRpbmcgc3VjY2VzcyBpbiBnZW5lcmFsLg0KDQojIyBDcmFmdGluZyBzdWNjZXNzDQoNCkFsY2hlbXkgZXhwZXJpbWVudHMgZGlmZmVyIGZyb20gb3JkaW5hcnkgYWxjaGVteS9jYXN0aW5nL3N0b3JhZ2UvaGFuZGljcmFmdHMvc2V3aW5nIGluIHRoYXQgdGhlcmUgaXMgYSAiaHVnZSBzdWNjZXNzIiBjYXRlZ29yeSAoc2VlIEZpZ3VyZSBcQHJlZihmaWc6cm9iZVBpY3R1cmUpKSwgYXMgd2VsbCBhcyBzZXZlcmFsIHRpZXJzIG9mIG1pbm9yIHN1Y2Nlc3MgdGhhdCBhbGwgZ2l2ZSBkaWZmZXJlbnQgaXRlbXMsIGFuZCBmYWlsdXJlcyB0aGF0IHByb2R1Y2Ugbm8gaXRlbS4gT3JkaW5hcnkgY3JhZnRpbmcgZG8gbm90IGhhdmUgdGhlIGh1Z2Ugc3VjY2VzcyBjYXRlZ29yeSBidXQgc29tZSByZWNpcGVzIGhhdmUgYSBmYWlsdXJlIGNhdGVnb3J5LCBub3JtYWwgc3VjY2VzcyBhbmQgc2V2ZXJhbCB0aWVycyBvZiAiZ3JlYXQgc3VjY2VzcyIuIFRoZSBsYXR0ZXIgbWF5IHNpbXBseSBwcm9kdWNlIG1vcmUgcXVhbnRpdHkgb2YgdGhlIHNhbWUsIGJ1dCBmb3Igc29tZSByZWNpcGVzIGl0IHJlc3VsdHMgaW4gYSBkaWZmZXJlbnQgaXRlbSB0aGFuIG5vcm1hbCBzdWNjZXNzLCBhbmQgdGhlIGdvYWwgaXMgb2Z0ZW4gdG8gY3JhZnQgdGhlIGhpZ2hlc3QgdGllciBzdWNoIGdyZWF0IHN1Y2Nlc3MgaXRlbSBpbiBhcyBmZXcgYXR0ZW1wdHMgYXMgcG9zc2libGUgKHRvIHByZXNlcnZlIHZhbHVhYmxlIG1hdGVyaWFscykuIE15IHVuZGVyc3RhbmRpbmcgb2YgY3JhZnRpbmcgc3VjY2VzcyBjYW4gYmUgc3VtbWFyaXplZCBhcyBmb2xsb3dzLg0KDQpUaGUgb3V0Y29tZSBvZiBvcmRpbmFyeSBjcmFmdGluZyBkZXBlbmRzIG9uIHR3byBoaWRkZW4gcGFyYW1ldGVycyB0aGF0IGNhbiBiZSBtYW5pcHVsYXRlZCBpbmRlcGVuZGVudGx5LiBUaGUgZmlyc3QgaXMgdGhlIGNoYW5jZSBvZiBncmVhdCBzdWNjZXNzLiBUaGlzIGNhbiBiZSBpbmNyZWFzZWQgYnk6DQoNCi0gICBQYXltYXN0ZXIgYWlkZQ0KLSAgIE94Zm9yZCBpbmNyZWFzZWQgcHJvZHVjdGlvbiBza2lsbHMgMS00DQotICAgTWVpc3RlciB0aXRsZSB3aXRoIGFwcHJlbnRpY2UgbmVhcmJ5IChvbmx5IHdoZW4gY3JhZnRpbmcgb24gbGFuZCkNCi0gICBXb3Jrc2hvcC9nYWxsZXkgc2hpcCBza2lsbCAob25seSB3aGVuIGNyYWZ0aW5nIGF0IHNlYSkNCg0KVGhlc2UgZmFjdG9ycyBoYXZlIG5vIGVmZmVjdCBhdCBhbGwgaWYgdXNpbmcgTWFzdGVyJ3MgU2VjcmV0cywgYmVjYXVzZSB0aGUgZ3JlYXQgc3VjY2VzcyBjaGFuY2UgaXMgdGhlbiBpbnN0YW50bHkgbWFkZSAxMDAlLiBUaGlzIGlzIGFuIHVuY29tbW9uIGNvbnN1bWFibGUgaXRlbSAoYnV0IG9idGFpbmFibGUgaW4tZ2FtZSkgdGhhdCBjYW5ub3QgYmUgdXNlZCBmb3IgYWxjaGVteSBleHBlcmltZW50cy4NCg0KVGhlIHNlY29uZCBwYXJhbWV0ZXIgaXMgdGhlICpkZWdyZWUqIG9mIGdyZWF0IHN1Y2Nlc3MsIHN1Y2ggYXMgdGllciBvZiBjYW5ub24gcGVuZXRyYXRpb24gb3IgYXR0YWNrL2RlZmVuc2Ugc3RhdHMgb2YgY2xvdGhlcy4gVGhpcyBjYW4gYmUgaW5jcmVhc2VkIGJ5Og0KDQotICAgU2tpbGwgcmFuaw0KLSAgIE94Zm9yZCBJdGVtIGltcHJvdmVtZW50IFRlY2ggc2tpbGwNCi0gICBHZWFyIHdpdGggdGhlIHNwZWNpYWwgZ29vZHMgcHJvZHVjdGlvbiByYXRlIHVwIEVYIGVmZmVjdA0KLSAgIFNhaWxvciBlcXVpcG1lbnQgd2l0aCB0aGUgc3BlY2lhbCBnb29kcyBwcm9kdWN0aW9uIGVmZmVjdCAob25seSBhdCBzZWEgd2l0aCB3b3Jrc2hvcCkNCg0KT25lIHRoZW9yeSBpcyB0aGF0IHRoZSBwcm9iYWJpbGl0eSBvZiBwcm9kdWNpbmcgYSBodWdlIHN1Y2Nlc3MgaW4gYWxjaGVteSBleHBlcmltZW50cyBpcyBhZmZlY3RlZCBlbnRpcmVseSBieSBvdGhlciBmYWN0b3JzIHRoYW4gY3JhZnRpbmcgYSBoaWdoIHRpZXIgZ3JlYXQgc3VjY2VzcyBpbiBub3JtYWwgY3JhZnRpbmcuIEFsdGVybmF0aXZlbHksIGFub3RoZXIgc2Nob29sIG9mIHRob3VnaHQgYXJndWVzIHRoYXQgaHVnZSBzdWNjZXNzIGlzIG5vdGhpbmcgYnV0IGEgaGlnaCB0aWVyIGdyZWF0IHN1Y2Nlc3MsIHNvIHNob3VsZCBiZSBpbmZsdWVuY2VkIGF0IGxlYXN0IHBhcnRseSBieSB0aGUgc2FtZSBmYWN0b3JzLg0KDQpgYGB7ciByb2JlUGljdHVyZSwgb3V0LndpZHRoPSc1MCUnLCBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy5jYXA9IlNlZWluZyB0aGlzIGZvciB0aGUgZmlyc3QgdGltZSBpbiAyMDExIHdhcyBzb21ldGhpbmciLCBlY2hvID0gRkFMU0V9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygncm9iZVN1Y2Nlc3MucG5nJykNCmBgYA0KDQojIE1ldGhvZHMNCg0KIyMgRXhwZXJpbWVudGFsIHByb3RvY29sIGZvciBGQUINCg0KSW4gdG90YWwgSSBoYWQgYWNjZXNzIHRvIDc0IGNoYXJhY3RlcnMgdGhhdCBtYWRlIGVub3VnaCBzdXBwb3J0IGZvciBSdWRvbGYgSUkgYXMgZW1wZXJvciwgYW5kIGhhZCBub3Qgb2J0YWluZWQgQWRlcHQgdGl0bGUgb3IgYW55IEZBQiBNQSBlbnRyaWVzIHByZXZpb3VzbHkuIE5lYXJseSBhbGwgb2YgdGhlc2UgaGFkIG5vdCB5ZXQgb2J0YWluZWQgdGhlIGFsY2hlbXkgc2tpbGwgYXQgYWxsLCBhbmQgbW9zdCB3ZXJlIGxvdyBsZXZlbCBhbmQgbG93IGNvdXJ0IHJhbmsuIFRoZSBmb2xsb3dpbmcgc3RlcHMgd2VyZSBkb25lIHRvIG9idGFpbiBhIEZBQiBmb3IgZWFjaCBvZiB0aGVzZSBjaGFyYWN0ZXJzOg0KDQotICAgSW4gdGhlIGVsZWN0aW9uIHBlcmlvZCwgZ2V0IHN1cHBvcnQgcGVybWl0cyBhbmQgaW52ZXN0IGVub3VnaCBpbiBSdWRvbGYgSUkgdG8gdW5sb2NrIHRoZSBhbGNoZW15IHN1cHBvcnQgYmVuZWZpdC4NCi0gICBJbnZlc3QgMTBtIGR1Y2F0cyBpbiBMb25kb24gdG8gZ2V0IGNvdXJ0IHJhbmsgNCB3aGljaCBpcyBuZWVkZWQgZm9yIHF1YXJ0ZXJzIHJhbmsgMiBuZWNlc3NhcnkgdG8gcGxhY2UgZnVybml0dXJlIHdoaWNoIGlzIG5lZWRlZCB0byBwZXJmb3JtIGFsY2hlbXkgZXhwZXJpbWVudHMuDQotICAgU2VsbCB0cmFkZSBnb29kcyB0byBnZXQgMjBrIGZhbWUsIG5lZWRlZCB0byBlcXVpcCArMSBOaWdyZWRvIGdsb3Zlcy4gSW4gaGluZHNpZ2h0LCB0aGlzIHR1cm5lZCBvdXQgdG8gYmUgYSB0b3RhbCBvdmVya2lsbCBidXQgSSBkaWRuJ3Qga25vdyBJIHdvdWxkIGdldCBjb3VydCBhbGNoZW1pc3Qgb3IgdGhhdCBwYXBheWEgd291bGQgaGF2ZSArMSBwcm9kdWN0aW9uIHNraWxscyBldmVudC4gQWxzbywgSSBkaWRuJ3QgcmVtZW1iZXIgdGhhdCB0aGUgSFJFIGdhdmUgKzIgYWxjaGVteS4gSSBoYWQgYXNzdW1lZCArMS4gU28gd2l0aG91dCB1c2luZyArMyBwYXBlciwgYWlkZSwgam9iLCBCb3N0b24gc2tpbGwgb3Igc2hpcCBJIGZlbHQgSSBuZWVkZWQgdGhpcy4gV2hpY2ggSSBkaWRuJ3QgbmVlZCBpbiAqYW55KiBjYXNlIGR1ZSB0byByYW5raW5nIHVwLiBCdXQgd2hhdCB0aGUgaGVjay4NCi0gICBCdXkgcXVhcnRlcnMgYW5kIHVwZ3JhZGUgdG8gcmFuayAyLg0KLSAgIE1ha2UgYW5kIHBsYWNlIGtpbG4gKG1vc3RseSArMyB2ZXJzaW9uKSBhbmQgYmVuY2ggKG1vc3RseSArMSB2ZXJzaW9uKSBpbiB0aGUgcXVhcnRlcnMuDQotICAgT2J0YWluIGFsY2hlbXkgc2tpbGwuIFRoaXMgd2FzIGRvbmUgaW4gb25lIG9mIDQgd2F5czoNCiAgICAtICAgRG8gdGhlIHF1ZXN0IGNoYWluIGZvciBhbGNoZW1pc3Qgam9iIGFuZCBnZXQgdGhlIHNraWxsIGZyb20gdGhlIGpvYiAodGhlIG9ubHkgd2F5IHRvIGxlYXJuIGl0IGluIHRoZSBwYXN0KS4gTiA9IGByIG5yb3coZmlsdGVyKEZBQiwgQWxjaGVteVNraWxsID09ICJKb2IiKSlgDQogICAgLSAgIEdldCBhZHZlbnR1cmUgbGV2ZWwgNyBhbmQgY2FzdGluZyByYW5rIDIsIGFuZCB0aGVuIGxlYXJuIGFsY2hlbXkgZnJvbSBKb2huIERlZSBpbiBMb25kb24uIE4gPSBgciBucm93KGZpbHRlcihGQUIsIEFsY2hlbXlTa2lsbCA9PSAiTGVhcm5lZCIpKWANCiAgICAtICAgTGVhcm4gdGhlIHNraWxsIGF0IHRoZSBzY2hvbGFyIGZyb20gYW5vdGhlciBjaGFyYWN0ZXIgYXQgc2FtZSBhY2NvdW50IGJlc3Rvd2luZyBpdC4gTiA9IGByIG5yb3coZmlsdGVyKEZBQiwgQWxjaGVteVNraWxsID09ICJCZXN0b3dlZCIpKWANCiAgICAtICAgTGVhcm4gc2tpbGwgYXQgdGhlIHNjaG9sYXIgZnJvbSBhbm90aGVyIGNoYXJhY3RlciBhdCBzYW1lIGFjY291bnQgYmVzdG93aW5nIGl0IGFmdGVyIGl0c2VsZiBoYXZpbmcgbGVhcm5lZCBpdCB0aGlzIHdheSAoZG91Ymx5IGJlc3Rvd2VkKS4gTiA9IGByIG5yb3coZmlsdGVyKEZBQiwgQWxjaGVteVNraWxsID09ICJEb3VibGVCZXN0b3dlZCIpKWANCi0gICBHZXQgYWxjaGVteSBib29zdGVycy4gSSB1c2VkOg0KICAgIC0gICArMSBmcm9tIGJlaW5nIGFwcHJlbnRpY2UNCiAgICAtICAgKzIgW2FjY2Vzc29yeV0oaHR0cDovL3V3b2RibWlycm9yLml2eXJvLm5ldC9lZy9tYWluLnBocD9pZD0wMDUxNTEwMSl7dGFyZ2V0PSJfYmxhbmsifQ0KICAgIC0gICArMSBbaGF0XShodHRwOi8vdXdvZGJtaXJyb3IuaXZ5cm8ubmV0L2VnL21haW4ucGhwP2lkPTAwMTQzNDA0KXt0YXJnZXQ9Il9ibGFuayJ9ICh0aGVyZSBpcyBhbHNvICsyIGhhdHMgYnV0IEkgZGlkbid0IGhhdmUgYW55IG9mIHRob3NlKQ0KICAgIC0gICArMiBbY2xvdGhlc10oaHR0cDovL3V3b2RibWlycm9yLml2eXJvLm5ldC9lZy9tYWluLnBocD9pZD0wMDA2MTMwMCl7dGFyZ2V0PSJfYmxhbmsifQ0KICAgIC0gICArMSBbd2VhcG9uXShodHRwOi8vdXdvZGJtaXJyb3IuaXZ5cm8ubmV0L2VnL21haW4ucGhwP2lkPTAwNDMwNTAwKXt0YXJnZXQ9Il9ibGFuayJ9DQogICAgLSAgICsxIFtnbG92ZXNdKGh0dHA6Ly91d29kYm1pcnJvci5pdnlyby5uZXQvZWcvbWFpbi5waHA/aWQ9MDAzMDAyMTIpe3RhcmdldD0iX2JsYW5rIn0NCiAgICAtICAgKzIgZnJvbSBIUkUNCiAgICAtICAgKzEgZnJvbSBiZWluZyBvbiBjb3VydCBhbGNoZW1pc3QgZnJpZW5kLWxpc3QuIEluIHRvdGFsIHRoZXkgd291bGQgdGhlcmVmb3JlIHN0YXJ0IG91dCBhdCByMTIgKHIxKzExKS4gRm9yIHRoZSBsYXN0IDEvMyBvZiB0aGUgc2FtcGxlIHRoZXJlIHdhcyBhbHNvOg0KICAgIC0gICArMSBmcm9tIFBhcGF5YSBldmVudCwgc28gcjErMTIuIER1cmluZyB0aGUgZXhwZXJpbWVudHMgdGhleSB3b3VsZCBhbHNvIGdldCBlbm91Z2ggc2tpbGxzIHBvaW50cyBmb3IgYSBmZXcgYmFzZSByYW5rcy4NCi0gICBDcmFmdCBhbGwgYmFzZSBtYXRzIGFuZCBpbmdyZWRpZW50cyBpbiBodWdlIHF1YW50aXRpZXMgaW4gYWR2YW5jZSBhbmQgc3RvcmUgb24gc3RvcmFnZSBhbHRzLCBhaWRlIGJhemFhcnMsIGNvbXBhbnkgdmF1bHRzLCBxdWFydGVycy4gVGhpcyB3YXMgZG9uZSB1dGlsaXNpbmcgdGhlIGpvYi1zcGVjaWZpYyBCb3N0b24gc2tpbGxzIGZvciBhbGNoZW15LCBzZXdpbmcsIGhhbmRpY3JhZnQgYW5kIGNhc3RpbmcgdG8gc2F2ZSBvbiBtYXRzIHdoZW4gY3JhZnRpbmcsIGFuZCB1c2luZyByMjAgYnV5aW5nIHNraWxscywgUm9iZSBFWCBhbmQgbWVyY2hhbnQgbWVudG9yIEJvc3RvbiBza2lsbCB0byBidXkgYXMgbXVjaCBhcyBwb3NzaWJsZSBwZXIgcHVyY2hhc2Ugb3JkZXIuIFRoaXMgY291bGQgaGF2ZSBiZWVuIHR3ZWFrZWQgZXZlbiBmdXJ0aGVyIHdpdGggW3I5IEVYXShodHRwOi8vdXdvZGJtaXJyb3IuaXZ5cm8ubmV0L2VnL21haW4ucGhwP2lkPTAwMDUyNTAxKXt0YXJnZXQ9Il9ibGFuayJ9IGFuZCA0dGggZmxlZXQgbWVtYmVyLg0KLSAgIEVhY2ggY2hhcmFjdGVyIHRoZW4gbWFkZSAoZHVyaW5nIHRoZSBIUkUgaW5mbHVlbmNlIHBlcmlvZCkgdGhlIDEwIGl0ZW1zIG5lZWRlZCBmb3IgdGhlIE1BIChyZXN1bHRpbmcgaW4gNzQwIGl0ZW1zIG9idGFpbmVkKS4gVGhlIGV4cGVyaW1lbnRzIHRlcm1pbmF0ZWQgd2hlbiB0aGUgaXRlbSB3YXMgb2J0YWluZWQsIG1vdmVkIG9uIHRvIHRoZSBuZXh0IGl0ZW0sIGFuZCB0aGVuIHRvIHRoZSBuZXh0IGNoYXJhY3Rlci4gVGhlIGl0ZW1zIChzZWUgW0FwcGVuZGl4XSgjRkFCLWluZ3JlZGllbnRzKSBmb3IgdGhlIHJlY2lwZXMpIHdlcmUgYWx3YXlzIG1hZGUgaW4gdGhlIGZvbGxvd2luZyBvcmRlcjoNCiAgICAtICAgQWRlcHQncyBCaXJldHRhIChyMTApDQogICAgLSAgIEFkZXB0J3MgUm9iZSAocjExKQ0KICAgIC0gICBHb2xkLXBsYXRlZCBBcm1vdXIgKHIxMikNCiAgICAtICAgS25pZmUgbG9zaW5nIGl0J3MgZ29sZCAocjEyKQ0KICAgIC0gICBNZXRhbCBXb3JrcyAocjEyKQ0KICAgIC0gICBQcm9jZXNzZWQgTHVtYmVyIChyMTEpDQogICAgLSAgIEdyZWVuIE9yZSAocjExKQ0KICAgIC0gICBCbHVlIE9yZSAocjExKQ0KICAgIC0gICBSZWQgT3JlIChyMTEpDQogICAgLSAgIFdoaXRlIE9yZSAocjExKQ0KDQooWWVzLCBJIGtub3cgSSdtIGluY29uc2lzdGVudCBpbiBuYW1pbmcgc29tZSBhZnRlciB0aGUgZW5kIHByb2R1Y3QgYW5kIHNvbWUgYWZ0ZXIgdGhlIGJhc2UgbWF0ZXJpYWwsIGJ1dCBnaXZlIG1lIHNvbWUgc2xhY2spLiBUaGUgY2hhcmFjdGVycyB3ZXJlIGhhbmRlZCAzIGJhc2UgbWF0cyBhbmQgcGxlbnR5IGNvbnN1bWFibGVzIG9mIHRoZSByaWdodCBraW5kIChvdGhlciBtYXRlcmlhbHMgd2VyZSBoYW5kZWQgYmFjayBhZnRlciBlYWNoIE1BIGVudHJ5IHdhcyBvYnRhaW5lZCB0byBhdm9pZCB1c2luZyB3cm9uZyBtYXRzLCBvciBhdCB3cm9uZyBmdXJuaXR1cmUsIGJ5IG1pc3Rha2UpLiBUaGV5IHdvdWxkIGhhdmUgdG8gdHJhZGUgbWUgYWdhaW4gaWYgbW9yZSB0aGFuIDMgYmFzZSBtYXRzIHdlcmUgbmVlZGVkIGFuZCB0aHVzIGNsb3NlIGFuZCBlbnRlciB0aGUgZXhwZXJpbWVudCBkaWFsb2d1ZSBhbmV3LiBGb3IgdGhlIGNvbG91cmVkIG9yZXMgdGhleSByZWNlaXZlZCAyNTAtMzAwLCBhcGFydCBmcm9tIGEgZmV3IHRoYXQgSSBjb3VsZG4ndCBib3RoZXIgdG8gZ2V0IGEgbmV3IHNoaXAgZm9yLiBTb21lIG1hZGUgRkFCIGluIGEgc3RhcnRlciBiYXJjYS4NCg0KSSBjb3VudGVkIHRoZSBudW1iZXIgb2YgdGltZXMgZWFjaCBleHBlcmltZW50IHdhcyBwZXJmb3JtZWQgdW50aWwgdGhleSBnb3QgdGhlIGl0ZW0uIFRoYXQgaXMsIEkgY291bnRlZCBpbiBlZmZlY3QgdGhlIG51bWJlciBvZiBjb25zdW1hYmxlcyB1c2VkLCBhbmQgbm90IHRoZSBudW1iZXIgb2YgYmFzZSBpdGVtcy4gVGhlIG1haW4gYmFzZSBpdGVtIGlzIG5vdCBjb25zdW1lZCBvbiBmYWlsdXJlcywgb25seSBvbiBzdWNjZXNzIGFuZCAiaHVnZSBzdWNjZXNzIiAoaS5lLiBNQSBpdGVtKS4gSWYgZGlmZmVyZW50IGV4cGVyaW1lbnRzIGhhdmUgZGlmZmVyZW50IHRhYmxlcyBvZiBwb3NzaWJsZSByZXN1bHRzIChmb3IgZXhhbXBsZSBpZiBvbmUgaGF2ZSBtYW55IHBvc3NpYmxlIHN1Y2Nlc3MgcHJvZHVjdHMsIGFuZCBhbm90aGVyIGZld2VyLCBvciB0aGV5IGRpZmZlciBpbiB0aGUgcmF0ZSBvZiBmYWlsdXJlKSB0aGlzIGNvdWxkIGhhdmUgYWZmZWN0ZWQgdGhlIG51bWJlciBvZiBiYXNlIGl0ZW1zIGNvbnN1bWVkIChpbiBhZGRpdGlvbiB0byBwb3NzaWJsZSBkaWZmZXJlbnQgcHJvYmFiaWxpdGllcyBvZiB0aGUgTUEgaXRlbSksIHdoaWNoIG1heSBpbiBzb21lIHNlbnNlIGJlIGNvbnNpZGVyZWQgbW9yZSBpbXBvcnRhbnQgdGhhbiB0aGUgbnVtYmVyIG9mIGV4cGVyaW1lbnRzIHBlcmZvcm1lZC4gSG93ZXZlciwgSSBkaWQgbm90IGNvbGxlY3QgZ29vZCBkYXRhIG9uIHRoaXMuDQoNClRoZSByYXcgZGF0YSBmb3IgRkFCIGV4cGVyaW1lbnRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgW0FwcGVuZGl4XSgjZmFiLXJhdy1kYXRhKS4NCg0KIyMgRXhwZXJpbWVudGFsIHByb3RvY29sIGZvciBSb2Jlcw0KDQpJbiBhIHNlcGFyYXRlIHNldCBvZiBleHBlcmltZW50cyBwZXJmb3JtZWQgc2hvcnRseSBhZnRlciB0aGUgRkFCIHN0dWR5IEkgZm9jdXNlZCBvbiB0aGUgQWRlcHQncyBSb2JlIHJlY2lwZS4gVW5saWtlIGluIHRoZSBleHBlcmltZW50cyBmb3IgRkFCIEkga2VwdCB0cmFjayBvZiBlYWNoIG91dGNvbWUuIFRoZSBleHBlcmltZW50YWwgc2V0LXVwIHdhcyBkZXNpZ25lZCB0byB5aWVsZCBwYWlyd2lzZSBjb21wYXJpc29ucyB3aGVyZSBhIHRyZWF0bWVudCBncm91cCBhbmQgYSBjb250cm9sIGdyb3VwIGNvdWxkIGJlIGNvbXBhcmVkIHdoaWxlIGFsbCBvdGhlciBmYWN0b3JzIHdlcmUgaGVsZCBjb25zdGFudC4gSSBkaWQgMTk2MiBleHBlcmltZW50cyBpbiB0b3RhbCwgd2l0aCAxLS0zIGJhdGNoZXMgZm9yIGVhY2ggb2YgMTQgY29tYmluYXRpb25zIG9mIGZhY3RvcnMgdGVzdGVkIChUYWJsZSBcQHJlZih0YWI6cm9iZURlc2lnblRhYmxlKSksIHdpdGggYXBwcm94IDgwIGV4cGVyaW1lbnRzIGluIGVhY2ggYmF0Y2ggdW50aWwgSSByYW4gb3V0IG9mIHJlc291cmNlcyAoZmluZSBkeWUpIHRvIHByb2R1Y2UgYmFzZSBtYXRlcmlhbHMuIFRoZSBjb25kaXRpb25zIHRlc3RlZCB3ZXJlOg0KDQotICAgV2l0aCBvciB3aXRob3V0IEhSRSBwb2xpY3kgKHNlcnZlciB3aWRlIGVmZmVjdCBmb3IgSFJFIHN1cHBvcnRlcnMpDQotICAgV2l0aCBvciB3aXRob3V0IEFkdmlzb3IgcG9zaXRpb24gKHBlcnNvbmFsIGVmZmVjdCBmb3IgdGhlIHNvbGUgY291cnQgYWxjaGVtaXN0IHRpdGxlIGhvbGRlcikNCi0gICBXaXRoIG9yIHdpdGhvdXQgQWRlcHQgdGl0bGUgKG9idGFpbmVkIGF0IGFsY2hlbXkgYmFzZSByYW5rIDEzKQ0KLSAgIFdpdGggb3Igd2l0aG91dCBPeGZvcmRzIChpbmNyZWFzZWQgcHJvZHVjdGlvbiBzdWNjZXNzIDEtLTQsIGFuZCBpdGVtIGltcHJvdmVtZW50IHRlY2gpDQotICAgV2l0aCBvciB3aXRob3V0IEVYIChbR29sZGVuIEFya10oaHR0cDovL3V3b2RibWlycm9yLml2eXJvLm5ldC9lZy9tYWluLnBocD9pZD0wMDUzNjkwNSl7dGFyZ2V0PSJfYmxhbmsifSByYW5rIDYgU3BlY2lhbCBHb29kcyBQcm9kdWN0aW9uIFJhdGUgVXApDQotICAgV2l0aCByMjAgb3IgcjExIGFsY2hlbXkNCg0KYGBge3Igcm9iZURlc2lnblRhYmxlfQ0Ka2JsKERlc2lnblssLTJdLCBjYXB0aW9uID0gJ0V4cGVyaW1lbnRhbCBkZXNpZ24gZm9yIFJvYmUgZXhwZXJpbWVudHMuIEdyb3VwIDE1IGlzIHRoZSBSb2JlIHBhcnQgb2YgdGhlIEZBQiBzZXR1cCBmb3IgY29tcGFyaXNvbi4nLCBhbGlnbiA9ImMiKSB8PiANCiAga2FibGVfcGFwZXIoYygiaG92ZXIiLCAiY29uZGVuc2VkIiksIGZ1bGxfd2lkdGggPSBGKQ0KYGBgDQoNCk9uZSBiYXRjaCBpcyBoZXJlIGRlZmluZWQgYXMgYW4gdW5pbnRlcnJ1cHRlZCBzZXF1ZW5jZSBvZiBleHBlcmltZW50cyBkb25lIHdpdGhvdXQgY2xvc2luZyB0aGUgZGlhbG9ndWUgc2NyZWVuLiBUaGUgbGVuZ3RoIG9mIGEgYmF0Y2ggd2FzIGxpbWl0ZWQgYnkgaW52ZW50b3J5IHNwYWNlIGFuZCB0aGUgbnVtYmVyIG9mIGZhaWx1cmVzIChtb3JlIGZhaWx1cmUgPSBsb25nZXIgYmF0Y2gpLCBidXQgd2FzIG5vdCBsaW1pdGVkIGJ5IHZpZ291ciBmb29kLiBObyBkaXNjb25uZWN0cyBmcm9tIHRoZSBzZXJ2ZXIgb2NjdXJyZWQgZHVyaW5nIHRoZSBleHBlcmltZW50cy4gQmF0Y2ggbnVtYmVyIDI2IHdhcyBtZXJnZWQgd2l0aCBiYXRjaCAyNSAoaWRlbnRpY2FsIGNvbmRpdGlvbnMpIGluIHNvbWUgYW5hbHlzZXMgYmVjYXVzZSB0aGUgc2FtcGxlIHNpemUgd2FzIGRlZW1lZCB0b28gc21hbGwgdG8gYmUgdHJlYXRlZCBzZXBhcmF0ZWx5Lg0KDQpJdCB3YXMgbm90IHBvc3NpYmxlIHRvIGtlZXAgdGhlIHNhbXBsZSBzaXplcyBzdHJpY3RseSBlcXVhbCBiZXR3ZWVuIGJhdGNoZXMgYmVjYXVzZSBldmVuIHRob3VnaCB0aGUgbnVtYmVyIG9mIGJhc2UgY2xvdGhlcyB3ZXJlIHRoZSBzYW1lICgrLy0gYSBmZXcpLCB0aGUgbnVtYmVyIG9mIGV4cGVyaW1lbnRzIGRpZmZlcmVkIGR1ZSB0byB0aGUgZmFjdCB0aGF0IGZhaWx1cmUgZG8gbm90IGNvbnN1bWUgdGhlIGJhc2UgbWF0ZXJpYWwgYW5kIHdvdWxkIGxlYWQgdG8gbW9yZSBleHBlcmltZW50cyBwb3NzaWJsZSBiZWZvcmUgdGhlIGJhc2UgbWF0cyB3ZXJlIHVzZWQgdXAgZm9yIHRoZSBiYXRjaC4NCg0KQSBmdWxsIGZhY3RvcmlhbCBleHBlcmltZW50YWwgZGVzaWduIG9mIDYgZmFjdG9ycyB3aXRoIDIgbGV2ZWxzIGVhY2ggd291bGQgcmVxdWlyZSAkMl42JCA9IDY0IGNvbWJpbmF0aW9ucy4gSXQgd2FzIG5vdCBwcmFjdGljYWxseSBwb3NzaWJsZSB0byB0ZXN0IGV2ZXJ5IGNvbWJpbmF0aW9uIG9mIHRoZSBmYWN0b3JzLiBJIGNob3NlIHRvIGlnbm9yZSBhbnkgaW50ZXJhY3Rpb24gZWZmZWN0cyBhcyB0aGVyZSBpcyByZWFzb24gdG8gYmVsaWV2ZSBhbGwgdGhlIGVmZmVjdHMgYXJlIHB1cmVseSBhZGRpdGl2ZSwgcmVtb3ZpbmcgdGhlIG5lZWQgZm9yIGEgZnVsbCBkZXNpZ24uIEhvd2V2ZXIsIGNlcnRhaW4gY29tYmluYXRpb25zIG9mIGZhY3RvcnMgd2VyZSBwaHlzaWNhbGx5IGltcG9zc2libGUuIEZvciBleGFtcGxlLCB0aGUgYWR2aXNvciBlZmZlY3QgY291bGQgbm90IGJlIG9idGFpbmVkIHdpdGhvdXQgaGF2aW5nIGFsc28gdGhlIEhSRSBlZmZlY3QuIEFub3RoZXIgZGlmZmljdWx0eSB3YXMgdGhhdCB3aXRob3V0IHdlYXJpbmcgYW55IGdlYXIgSSB3YXMgYWxyZWFkeSByMjAgYWxjaGVteS4gSG93ZXZlciwgYWRqdXN0aW5nIGFsY2hlbXkgcmFuayBkb3duIHRvIHIxMSBjb3VsZCBiZSBhY2hpZXZlZCB3aXRoIGEgY29tYmluYXRpb24gb2YgbWVudG9yaW5nIGFuZCArIGdlYXIgKEZpZ3VyZSBcQHJlZihmaWc6bWVudG9yaW5nUGljdHVyZSkpLiBUaHVzIGl0IHdhcyBwb3NzaWJsZSB0byBkaXNlbnRhbmdsZSBza2lsbCByYW5rLCBBZGVwdCB0aXRsZSBhbmQgSFJFIGVmZmVjdHMgd2hpY2ggd291bGQgb3RoZXJ3aXNlIGJlIGNvbmZvdW5kZWQuDQoNCmBgYHtyIG1lbnRvcmluZ1BpY3R1cmUsIG91dC53aWR0aD0nNTAlJywgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcuY2FwPSJNZW50b3Jpbmcgd2FzIHVzZWQgaW4gb3JkZXIgdG8gbG93ZXIgc2tpbGwgcmFuayBhbmQgcmV0YWluIGFkZXB0IHRpdGxlIiwgZWNobyA9IEZBTFNFfQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoJ21lbnRvcmVkLnBuZycpDQpgYGANCg0KT3hmb3JkcyB3ZXJlIGNvbXBhcmVkIHdpdGggYWxsIG9uIG9yIGFsbCBvZmYuIEV2ZW4gdGhvdWdoIGl0IHdvdWxkIGhhdmUgYmVlbiBpZGVhbCB0byBoYXZlIGV4cGVyaW1lbnRzIHdpdGggYW5kIHdpdGhvdXQgT3hmb3JkIGltcHJvdmVtZW50IHRlY2huaXF1ZXMgd2hpbGUgaGF2aW5nIE94Zm9yZCBwcm9kdWN0aW9uIHN1Y2Nlc3Mgb24gb3Igb2ZmLCBpdCBpcyBzdGlsbCBwb3NzaWJsZSB0byBzZXBhcmF0ZSB0aGUgZWZmZWN0cy4gT3hmb3JkIHRlY2ggc2tpbGwgaXMgb25seSAocG9zc2libHkpIHJlbGV2YW50IGZvciBleHBlcmltZW50cyB0aGF0IGRpZCBub3QgZmFpbCwgd2hlcmVhcyB0aGUgcHJvZHVjdGlvbiBzdWNjZXNzIE94Zm9yZHMgc2hvdWxkIChwb3NzaWJseSkgb25seSBhZmZlY3QgZmFpbCByYXRlLiBUaGVyZWZvcmUgb25lIGNhbiBjb21wYXJlIGZhaWwgcmF0ZSB3aXRoIGFuZCB3aXRob3V0IE94Zm9yZHMgdG8gdGVzdCB0aGUgcHJvZHVjdGlvbiBzdWNjZXNzIE94Zm9yZHMsIGFuZCBjb21wYXJlIG91dGNvbWUgYW1vbmcgZXhwZXJpbWVudHMgdGhhdCBkaWQgbm90IGZhaWwgd2l0aCBhbmQgd2l0aG91dCBPeGZvcmRzIHRvIHRlc3QgdGhlIGl0ZW0gaW1wcm92ZW1lbnQgdGVjaCBPeGZvcmQuDQoNCkFsbCBleHBlcmltZW50cyBpbiB0aGUgUm9iZSBzZXR1cCB3ZXJlIGRvbmUgd2l0aCBhaWRlIGluIFBheW1hc3RlciAxMDBzIGpvYi4gU2luY2UgdGhlIEZBQiB0cmlhbHMgd2VyZSBub3QsIGl0IHdhcyB0byBzb21lIGV4dGVudCBhbHNvIHBvc3NpYmxlIHRvIHRlc3QgdGhlIGVmZmVjdCBvZiBwYXltYXN0ZXIgYWlkZSBieSBjb21wYXJpbmcgY2VydGFpbiBncm91cHMgZnJvbSB0aGUgUm9iZSBzZXR1cCB3aXRoIHRoZSBGQUIgcmVzdWx0cy4gVW5mb3J0dW5hdGVseSB0aGVyZSB3YXMgbm8gZGF0YSB0byBzZXBhcmF0ZSBmYWlsdXJlcyBmcm9tIG1pbm9yIHN1Y2Nlc3MgaW4gdGhlIEZBQiBleHBlcmltZW50cywgc28gb25seSB0aGUgZWZmZWN0IG9mIGFpZGUgb24gaHVnZSBzdWNjZXNzIGNhbiBiZSBjb25zaWRlcmVkLiANCg0KUmVzdWx0cyB3ZXJlIG1vc3RseSBhbmFseXNlZCBieSBjb21wYXJpbmcgY29uZmlkZW5jZSBpbnRlcnZhbHMgb2YgcHJvcG9ydGlvbnMuIFNpbmNlIHNvbWUgb2YgdGhlIG9ic2VydmVkIHByb3BvcnRpb25zIHdlcmUgMCBvciBjbG9zZSB0byAwLCBJIGRpZCBub3QgdXNlIHRoZSBzdGFuZGFyZCBhc3ltcHRvdGljIChXYWxkKSBhcHByb3hpbWF0aW9uIHRvIGNhbGN1bGF0ZSBiaW5vbWlhbCBjb25maWRlbmNlIGludGVydmFscywgYnV0IGluc3RlYWQgdGhlIFdpbHNvbiBtZXRob2QgaW1wbGVtZW50ZWQgaW4gUiBwYWNrYWdlIFtiaW5vbV0oaHR0cHM6Ly9DUkFOLlItcHJvamVjdC5vcmcvcGFja2FnZT1iaW5vbSl7dGFyZ2V0PSJfYmxhbmsifS4NCg0KVGhlIHJhdyBkYXRhIGZvciBSb2JlIGV4cGVyaW1lbnRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgW0FwcGVuZGl4XSgjcm9iZS1yYXctZGF0YSkuDQoNClRoaXMgcmVwb3J0IHdhcyB3cml0dGVuIHVzaW5nIFtSIE1hcmtkb3duXShodHRwczovL2Jvb2tkb3duLm9yZy95aWh1aS9ybWFya2Rvd24vKXt0YXJnZXQ9Il9ibGFuayJ9IGluIFtSU3R1ZGlvXShodHRwczovL3Bvc2l0LmNvL3Byb2R1Y3RzL29wZW4tc291cmNlL3JzdHVkaW8vKXt0YXJnZXQ9Il9ibGFuayJ9LiBSIGNvZGUgdXNlZCB0byBnZW5lcmF0ZSB0aGUgcmVzdWx0cyBhbmQgc29tZSBvdXRwdXQgY2FuIGJlIHNlZW4gYnkgY2xpY2tpbmcgb24gdGhlICJjb2RlIiBidXR0b25zLCBhcyB3ZWxsIGFzIGZvdW5kIGluIHRoZSBbQXBwZW5kaXhdKCNyLWNvZGUpICh3aXRob3V0IG91dHB1dCkgdG9nZXRoZXIgd2l0aCBzb2Z0d2FyZSB2ZXJzaW9ucyB1c2VkLg0KDQojIFJlc3VsdHMNCg0KIyMgRkFCIGV4cGVyaW1lbnRzDQoNCmBgYHtyIEZBQmRpc3RyaWJ1dGlvbiwgZmlnLmNhcCA9ICJOZWVkZWQgYXR0ZW1wdHMgdG8gZ2V0IGFuIE1BIGVudHJ5IG92ZXJhbGwgKGhpc3RvZ3JhbSksIGFuZCBieSBob3cgdGhlIGFsY2hlbXkgc2tpbGwgd2FzIG9idGFpbmVkIChrZXJuZWwgZGVuc2l0eSBlc3RpbWF0ZXMpIiwgZmlnLnNob3cgPSAiaG9sZCIsIG91dC53aWR0aD0gIjUwJSJ9DQoNCmdncGxvdChGQUIyLCBhZXMoQXR0ZW1wdHNOZWVkZWQpKSArDQogIGdlb21faGlzdG9ncmFtKGZpbGwgPSAiIzM3N2ViOCIsIGNvbG91ciA9ICJibGFjayIsIGJpbndpZHRoID0gMSkNCg0KZ2dwbG90KEZBQjIsIGFlcyhBdHRlbXB0c05lZWRlZCkpICsNCiAgc3RhdF9kZW5zaXR5KGFlcyhjb2xvdXIgPSBBbGNoZW15U2tpbGwpLCAgbGluZXdpZHRoID0gMiwNCiAgICAgICAgICAgICAgIGJvdW5kcyA9IGMoMSwgSW5mKSwgZ2VvbT0ibGluZSIsIHBvc2l0aW9uPSJpZGVudGl0eSIpICsNCiAgI3NjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiIzdhMDQwMyIsIiNGQUJBMzkiLCIjMThiYzljIiwgIiMyYzNlNTAiKSkrDQogIHNjYWxlX2NvbG91cl9icmV3ZXIocGFsZXR0ZSA9ICJSZEJ1IiwgZGlyZWN0aW9uID0gLTEpICsNCiAgI3NjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiIzdhMDQwMyIsIiNGQUJBMzkiLCIjMThiYzljIiwgIiMyYzNlNTAiKSkrDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC45NSwwLjk1KSwNCiAgICAgICAgbGVnZW5kLmp1c3RpZmljYXRpb24gPSBjKDEsMSkpDQpgYGANCg0KT3ZlciBhbGwgYHIgbnJvdyhGQUIyKWAgTUEgaXRlbXMgb2J0YWluZWQsIHRoZSBtZWFuIG51bWJlciBvZiBleHBlcmltZW50cyBuZWVkZWQgdG8gb2J0YWluIG9uZSBpdGVtIHdhcyBgciByb3VuZChtZWFuKEZBQjIkQXR0ZW1wdHNOZWVkZWQpLCAyKWAgYXR0ZW1wdHMsIHdpdGggYSBtZWRpYW4gb2YgYHIgcm91bmQobWVkaWFuKEZBQjIkQXR0ZW1wdHNOZWVkZWQpLDIpYC4gSW4gdG90YWwgYHIgc3VtKEZBQjIkQXR0ZW1wdHNOZWVkZWQpYCBleHBlcmltZW50cyB3ZXJlIHBlcmZvcm1lZCB0byBnZXQgYWxsIHRoZSBNQSBpdGVtcyBmb3IgYWxsIGByIG5yb3coRkFCKWAgcGFydGljaXBhbnRzLiBUaGUgZGlzdHJpYnV0aW9uIG9mIG5lZWRlZCBhdHRlbXB0cyBpcyBzaG93biBpbiBGaWd1cmUgXEByZWYoZmlnOkZBQmRpc3RyaWJ1dGlvbikuIFRoZSBoaWdoZXN0IG51bWJlciBvYnNlcnZlZCB3YXMgMjUgYXR0ZW1wdHMgZm9yIG9uZSBpdGVtLiBJdCBkaWQgbm90IHNlZW0gdG8gbWF0dGVyIGlmIHRoZSBza2lsbCB3YXMgb2J0YWluZWQgZnJvbSB0aGUgam9iLCBsZWFybmVkIGJ5IGZ1bGZpbGxpbmcgcmVxdWlyZW1lbnRzLCBiZXN0b3dlZCBvciBiZXN0b3dlZCBhZ2FpbiAoRmlndXJlIFxAcmVmKGZpZzpGQUJkaXN0cmlidXRpb24pKS4gSWYgd2UgY29tcGFyZSB0aGUgcmVzdWx0cyBmcm9tIHRoZSBkaWZmZXJlbnQgaXRlbXMgKEZpZ3VyZSBcQHJlZihmaWc6RkFCaGlzdG9JdGVtcykpIHRoZXJlIGRvZXMgbm90IHNlZW0gdG8gYmUgYW55IG9idmlvdXMgZGlmZmVyZW5jZXMgLS0gdGhlcmUgaXMgYSBsb3Qgb2YgdmFyaWF0aW9uIHdpdGhpbiBjb21wYXJlZCB0byBiZXR3ZWVuIGdyb3Vwcy4NCg0KYGBge3IgRkFCaGlzdG9JdGVtcywgZmlnLmhlaWdodD0gOCwgZmlnLmNhcCA9ICJOZWVkZWQgYXR0ZW1wdHMgZm9yIHRoZSBkaWZmZXJlbnQgaXRlbXMifQ0KRkFCMyA8LSBGQUIyIHw+DQogIG11dGF0ZShJdGVtID0gcmVvcmRlcihJdGVtLCBBdHRlbXB0c05lZWRlZCwgRlVOID0gbWVhbiwgbmEucm0gPSBUUlVFKSkNCkl0ZW1MYWJlbHMgPC0gRkFCMyB8Pg0KICBncm91cF9ieShJdGVtKSB8Pg0KICBzdW1tYXJpc2Uoc25pdHQgPSBtZWFuKEF0dGVtcHRzTmVlZGVkKSwgbWVkaWFuID1tZWRpYW4oQXR0ZW1wdHNOZWVkZWQpKQ0KSXRlbUxhYmVscyRzbml0dDIgPC0gc3ByaW50ZigiYmFyKHgpID09ICUuMmYiLCBJdGVtTGFiZWxzJHNuaXR0KQ0KSXRlbUxhYmVscw0KDQpnZ3Bsb3QoRkFCMywgYWVzKEF0dGVtcHRzTmVlZGVkKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDEsIGNvbG91ciA9ICJibGFjayIsIA0KICAgICAgICAgICAgICAgICBhZXMoZmlsbD0oSXRlbSkpKSArIA0KICBmYWNldF93cmFwKHZhcnMoSXRlbSksIG5jb2wgPSAyKSArDQogICNzY2FsZV9maWxsX3ZpcmlkaXNfZChvcHRpb24gPSAidHVyYm8iLCBkaXJlY3Rpb24gPSAxLCBndWlkZSA9ICJub25lIikgKw0KICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlJkQnUiLCBndWlkZSA9ICJub25lIiwgZGlyZWN0aW9uID0gLTEpKw0KICBnZW9tX2xhYmVsKHggPSAxMi41LCB5ID0gMTcuNSwgYWVzKGxhYmVsID0gc25pdHQyKSwgZGF0YSA9IEl0ZW1MYWJlbHMsIHBhcnNlID0gVFJVRSwgDQogICAgICAgICAgICAgaGp1c3QgPSAiY2VudGVyIiwgc2l6ZSA9IDMsIGxhYmVsLnNpemUgPSBOQSkNCmBgYA0KDQpUaGlzIGlzIGVhc2llciB0byBjb21wYXJlIHVzaW5nIGJveCBwbG90cywgc2hvd24gaW4gRmlndXJlIFxAcmVmKGZpZzpGQUJib3hJdGVtcykuIFdlIGNhbiB0aGluayBvZiBhIGJveCBwbG90IGFzIGRpdmlkaW5nIHRoZSBkYXRhIGluIDQgcGFydHMgd2l0aCBlcXVhbCBudW1iZXIgb2Ygb2JzZXJ2YXRpb25zLiBUaGUgbWVkaWFuIChzaG93biBhcyBhIHZlcnRpY2FsIGxpbmUpIGN1dCB0aGUgZGF0YSBpbiBoYWxmIHdpdGggYXMgbWFueSBzbWFsbGVyIGFzIGxhcmdlciBvYnNlcnZhdGlvbnMsIGFuZCB0aGUgYm94IHNob3cgdGhlIGxvd2VyICgyNSUpIGFuZCB1cHBlciAoNzUlKSBxdWFydGlsZXMuIFRoYXQgaXMsIHRoZSBjZW50cmFsIDUwJSBvZiB0aGUgb2JzZXJ2YXRpb25zIGxpZSB3aXRoaW4gdGhlIGJveGVzLCBhbmQgNTAlIGJlbG93IGFuZCA1MCUgYWJvdmUgdGhlIG1lZGlhbi4gTWVhbiB2YWx1ZXMgKHNob3duIGFzIHdoaXRlIGRvdHMpIGFyZSBoaWdoZXIgdGhhbiBtZWRpYW5zIGJlY2F1c2Ugb2YgdGhlIHNoYXBlIG9mIHRoZSBkaXN0cmlidXRpb25zLiBBZ2FpbiB0aGVyZSBpcyBubyBsYXJnZSBkaWZmZXJlbmNlIGRpc2Nlcm5pYmxlIGluIHRoZSBkaWZmaWN1bHR5IG9mIG9idGFpbmluZyBhbnkgb2YgdGhlIGl0ZW1zLCBidXQgd2UgY2FuIHNlZSB0aGF0IHJvYmVzIGhhdmUgdGhlIGhpZ2hlc3QgbWVhbiBmb2xsb3dlZCBieSBiaXJldHRhIGFuZCBibHVlIG9yZS4NCg0KYGBge3IgRkFCYm94SXRlbXMsIGZpZy5oZWlnaHQgPSA1LCBmaWcuY2FwID0gIkJveCBwbG90cyBvZiBudW1iZXIgb2YgYXR0ZW1wdHMgbmVlZGVkIHRvIGdldCBlYWNoIE1BIGVudHJ5In0NCmdncGxvdChGQUIzLCBhZXMoeD1BdHRlbXB0c05lZWRlZCwgeT1JdGVtLCBmaWxsPUl0ZW0pKSArDQogIGdlb21fYm94cGxvdCgpICsNCiAgc3RhdF9zdW1tYXJ5KGZ1bj1tZWFuLCBnZW9tPSJwb2ludCIsIHNoYXBlPTIwLCBzaXplPTMsIGNvbG9yPSJ3aGl0ZSIsIGZpbGw9IndoaXRlIikgKw0KICB5bGFiKE5VTEwpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLDI0LCBieSA9MikpKw0KICAjc2NhbGVfZmlsbF92aXJpZGlzX2Qob3B0aW9uID0gInR1cmJvIiwgZGlyZWN0aW9uID0gMSwgZ3VpZGU9Im5vbmUiKQ0KICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlJkQnUiLCBndWlkZSA9ICJub25lIiwgZGlyZWN0aW9uID0tMSkNCg0KYGBgDQoNCmBgYHtyIEZBQmdyb3VwRmlncywgb3V0LndpZHRoPSAiNTAlIiwgZmlnLmhlaWdodD0gMywgZmlnLnNob3cgPSAiaG9sZCIsIGZpZy5jYXA9ICJOdW1iZXIgb2YgYXR0ZW1wdHMgbmVlZGVkIGZvciB0d28gZ3JvdXBzIG9mIGl0ZW1zLiBIaXN0b2dyYW0gb2YgY291bnRzLCBzdGFuZGFyZGlzZWQgaGlzdG9ncmFtLCBrZXJuZWwgZGVuc2l0eSBlc3RpbWF0ZXMgYW5kIGJveCBwbG90cyJ9DQpGQUI0IDwtIEZBQjMgfD4NCiAgbXV0YXRlKEl0ZW1Hcm91cCA9IGlmZWxzZShJdGVtID09ICJCaXJldHRhIiB8IEl0ZW0gPT0gIlJvYmUiICwgIlJvYmUvQmlyZXR0YSIsICJPdGhlcnMiKSkNCkZBQjQkSXRlbUdyb3VwIDwtIGFzX2ZhY3RvcihGQUI0JEl0ZW1Hcm91cCkNCkl0ZW1MYWJlbHMyIDwtIEZBQjQgfD4NCiAgZ3JvdXBfYnkoSXRlbUdyb3VwKSB8Pg0KICBzdW1tYXJpc2Uoc25pdHQgPSBtZWFuKEF0dGVtcHRzTmVlZGVkKSwgDQogICAgICAgICAgICBtZWRpYW4gPW1lZGlhbihBdHRlbXB0c05lZWRlZCksIA0KICAgICAgICAgICAgbiA9IChsZW5ndGgoQXR0ZW1wdHNOZWVkZWQpKSkNCkl0ZW1MYWJlbHMyJHNuaXR0MiA8LSBzcHJpbnRmKCJiYXIoeCkgPT0gJS4yZiIsIEl0ZW1MYWJlbHMyJHNuaXR0KQ0KSXRlbUxhYmVsczIkbjIgPC0gc3ByaW50ZigibiA9PSAlLjBmIiwgSXRlbUxhYmVsczIkbikNCkl0ZW1MYWJlbHMyJHNuaXR0QW5kTiA8LSBzcHJpbnRmKA0KICAiYmFyKHgpID09ICUuMmYgKiAnLCcgfn4gbiA9PSAlLjBmIiwNCiAgSXRlbUxhYmVsczIkc25pdHQsDQogIEl0ZW1MYWJlbHMyJG4NCikNCmdncGxvdChGQUI0LCBhZXMoQXR0ZW1wdHNOZWVkZWQpKSArDQogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMSwgY29sb3VyID0gImJsYWNrIiwgDQogICAgICAgICAgICAgICAgIGFlcyhmaWxsPShJdGVtR3JvdXApKSkgKyANCiAgZmFjZXRfd3JhcCh2YXJzKEl0ZW1Hcm91cCksIG5jb2wgPSAyKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNCNTFGMkUiLCAiIzM3N2ViOCIpLCBndWlkZSA9ICJub25lIikgKw0KICAjc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiIzdhMDQwMyIsICIjOTVhNWE2IiksIGd1aWRlID0gIm5vbmUiKSArDQogICNzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDEiLCBndWlkZSA9ICJub25lIikrDQogIGdlb21fbGFiZWwoeCA9IDEyLjUsIHkgPSAxNDAsIGFlcyhsYWJlbCA9IHNuaXR0QW5kTiksIGRhdGEgPSBJdGVtTGFiZWxzMiwgcGFyc2UgPSBUUlVFLCANCiAgICAgICAgICAgICBoanVzdCA9ICJjZW50ZXIiLCB2anVzdCA9ICJjZW50ZXIiLCBzaXplID0gMywgbGFiZWwuc2l6ZSA9IE5BKQ0KDQpnZ3Bsb3QoRkFCNCwgYWVzKEF0dGVtcHRzTmVlZGVkKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDEsIGNvbG91ciA9ICJibGFjayIsIA0KICAgICAgICAgICAgICAgICBhZXMoZmlsbD0oSXRlbUdyb3VwKSwgeSA9IHN0YXQoZGVuc2l0eSkpKSArIA0KICBmYWNldF93cmFwKHZhcnMoSXRlbUdyb3VwKSwgbmNvbCA9IDIpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiI0I1MUYyRSIsICIjMzc3ZWI4IiksIGd1aWRlID0gIm5vbmUiKSArDQogICNzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjN2EwNDAzIiwgIiM5NWE1YTYiKSwgZ3VpZGUgPSAibm9uZSIpICsNCiAgI3NjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MSIsIGd1aWRlID0gIm5vbmUiKSsNCiAgZ2VvbV9sYWJlbCh4ID0gMTIuNSwgeSA9IDAuMjM1LCBhZXMobGFiZWwgPSBzbml0dEFuZE4pLCBkYXRhID0gSXRlbUxhYmVsczIsIHBhcnNlID0gVFJVRSwgDQogICAgICAgICAgICAgaGp1c3QgPSAiY2VudGVyIiwgdmp1c3QgPSAiY2VudGVyIiwgc2l6ZSA9IDMsIGxhYmVsLnNpemUgPSBOQSkNCg0KZ2dwbG90KEZBQjQsIGFlcyhBdHRlbXB0c05lZWRlZCkpICsNCiAgc3RhdF9kZW5zaXR5KGFlcyhjb2xvdXIgPSBJdGVtR3JvdXApLCAgbGluZXdpZHRoID0gMiwNCiAgICAgICAgICAgICAgIGJvdW5kcyA9IGMoMSwgSW5mKSwgZ2VvbT0ibGluZSIsIHBvc2l0aW9uPSJpZGVudGl0eSIpICsNCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCIjQjUxRjJFIiwgIiMzNzdlYjgiKSwgZ3VpZGUgPSAibm9uZSIpICsNCiAgI3NjYWxlX2NvbG91cl92aXJpZGlzX2Qob3B0aW9uID0gInR1cmJvIiwgZGlyZWN0aW9uID0gLTEpICsNCiAgI3NjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiIzdhMDQwMyIsIiM5NWE1YTYiKSkgKw0KICAjc2NhbGVfY29sb3VyX2JyZXdlcihwYWxldHRlID0gIlNldDEiLCBndWlkZSA9ICJub25lIikrDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC45NSwwLjk1KSwNCiAgICAgICAgbGVnZW5kLmp1c3RpZmljYXRpb24gPSBjKDEsMSkpICsNCiAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZCh0aXRsZSA9IE5VTEwpKQ0KDQpnZ3Bsb3QoRkFCNCwgYWVzKHg9QXR0ZW1wdHNOZWVkZWQsIHk9SXRlbUdyb3VwLCBmaWxsPUl0ZW1Hcm91cCkpICsNCiAgZ2VvbV9ib3hwbG90KCkgKw0KICBzdGF0X3N1bW1hcnkoZnVuPW1lYW4sIGdlb209InBvaW50Iiwgc2hhcGU9MjAsIHNpemU9MywgY29sb3I9IndoaXRlIiwgZmlsbD0id2hpdGUiKSArDQogIHlsYWIoTlVMTCkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsMjQsIGJ5ID0yKSkrDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNCNTFGMkUiLCAiIzM3N2ViOCIpLCBndWlkZSA9ICJub25lIikgDQogICNzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjN2EwNDAzIiwiIzk1YTVhNiIpLCBndWlkZT0ibm9uZSIpDQogICNzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDEiLCBndWlkZSA9ICJub25lIikNCmBgYA0KDQpgYGB7ciBGQUJzdGF0c30NCnRhYmxlKEZBQjQkSXRlbUdyb3VwKQ0KKFdUIDwtIHdpbGNveC50ZXN0KEZBQjQkQXR0ZW1wdHNOZWVkZWQgfiBGQUI0JEl0ZW1Hcm91cCwgDQogICAgICAgICAgICBwYWlyZWQgPSBGLCANCiAgICAgICAgICAgIGFsdGVybmF0aXZlID0gImdyZWF0ZXIiKSkNCmBgYA0KDQpJbiBvcmRlciB0byBsZWFybiBpZiB0aGVyZSBpcyBtb3JlIHRoYW4gcmFuZG9tIHZhcmlhYmlsaXR5IGluIHRoZSBkYXRhIHdlIGNhbiBwZXJmb3JtIHNvbWUgc3RhdGlzdGljYWwgYW5hbHlzZXMuIEZyb20gYSBwcmlvcmkgaW5mb3JtYXRpb24gd2UgY2FuIGV4cGVjdCBSb2JlIGFuZCBCaXJldHRhIHRvIGJlIGhhcmRlciB0byBtYWtlIHRoYW4gdGhlIG90aGVyIDggaXRlbXMsIHNvIHRvIGluY3JlYXNlIHNhbXBsZSBzaXplIGFuZCByZWR1Y2UgdW5jZXJ0YWludHkgSSBsdW1wZWQgdGhlIGRhdGEgaW50byB0d28gZ3JvdXBzOiBSb2JlK0JpcmV0dGEgKG4gPSAxNDgsICRcYmFye3h9JCA9IGByIHJvdW5kKEl0ZW1MYWJlbHMyWzEsMl0sIDIpYCBhdHRlbXB0cykgdnMgdGhlIG90aGVyIGl0ZW1zIChuID0gNTkyLCAkXGJhcnt4fSQgPSBgciByb3VuZChJdGVtTGFiZWxzMlsyLDJdLCAyKWAgYXR0ZW1wdHMpLiBUaGUgZGlzdHJpYnV0aW9ucyBvZiBuZWVkZWQgYXR0ZW1wdHMgZm9yIHRoZXNlIHR3byBncm91cHMgaXMgc2hvd24gaW4gaW4gRmlndXJlIFxAcmVmKGZpZzpGQUJncm91cEZpZ3MpLiBUaGUgbnVtYmVyIG9mIGF0dGVtcHRzIHdhcyBzaWduaWZpY2FudGx5IGxhcmdlciBmb3IgdGhlIFJvYmUvQmlyZXR0YSBncm91cCAoTWFubi1XaGl0bmV5IFUtdGVzdCwgb25lLXNpZGVkIHAgPSBgciByb3VuZCgoV1QkcC52YWx1ZSksIDIpYCkuDQoNCmBgYHtyIEZBQnByb3AsIGZpZy5oZWlnaHQ9IDEuNzUsIGZpZy5jYXA9ICJQcm9wb3J0aW9uIHN1Y2Nlc3MgZm9yIHRoZSB0d28gZ3JvdXBzIG9mIGl0ZW1zLCB3aXRoIDk1JSBjb25maWRlbmNlIGludGVydmFscyJ9DQojcmVzdHJ1Y3R1cmUgZGF0YQ0KRkFCcHJvcCA8LSBGQUI0IHw+DQogIGdyb3VwX2J5KEl0ZW1Hcm91cCkgfD4NCiAgc3VtbWFyaXNlKHN1Y2Nlc3MgPSBzdW0obigpKSwgdG90YWwgPSBzdW0oQXR0ZW1wdHNOZWVkZWQpKQ0KI2Jpbm9taWFsIGNvbmZpZGVuY2UgaW50ZXJ2YWxzDQpiaW5vbTo6Ymlub20uY29uZmludChGQUJwcm9wJHN1Y2Nlc3MsIEZBQnByb3AkdG90YWwpIA0KKGJpbm9tUmVzIDwtIGJpbm9tOjpiaW5vbS53aWxzb24oRkFCcHJvcCRzdWNjZXNzLCBGQUJwcm9wJHRvdGFsKSkNCmJpbm9tUmVzJEdyb3VwIDwtIGFzX2ZhY3RvcihjKCJSb2JlL0JpcmV0dGEiLCAiT3RoZXJzIikpDQojdGVzdCBpZiBlcXVhbCBwcm9wb3J0aW9ucw0KKHByb3BSZXMgPC0gcHJvcC50ZXN0KHggPSBiaW5vbVJlcyR4LCBiaW5vbVJlcyRuLCBhbHRlcm5hdGl2ZSA9ICJsZXNzIikpDQprYmwoRkFCcHJvcCwgbGFiZWwgPSAiRkFCcHJvcFRhYmxlIiwgDQogICAgY2FwdGlvbiA9ICdOdW1iZXIgb2Ygc3VjY2Vzc2VzIGFuZCBhdHRlbXB0cyB3aGVuIG1ha2luZyBNQSBlbnRyaWVzIGZvciBGQUInLCANCiAgICBhbGlnbiA9ImMiLA0KICAgIGNvbC5uYW1lcyA9IGMoJ0dyb3VwJywgJ1N1Y2Nlc3NlcycsICdUb3RhbCBFeHBlcmltZW50cycpKSB8Pg0KICBrYWJsZV9wYXBlcihjKCJob3ZlciIsICJjb25kZW5zZWQiKSwgZnVsbF93aWR0aCA9IEYpICN8Pg0KICAjY29sdW1uX3NwZWMoMSwgY29sb3IgPSAid2hpdGUiLCBib2xkID0gRiwgDQogICMgICAgICAgICAgICBiYWNrZ3JvdW5kID0gYygiI2NhMDAyMCIsICIjMDU3MWIwIikpDQpiaW5vbVJlcyB8PiANCmdncGxvdChhZXMoeCA9IEdyb3VwLCB5ID0gbWVhbiwgY29sb3VyPSBHcm91cCkpICsNCiAgeWxhYigiUHJvcG9ydGlvbiBTdWNjZXNzIikgKw0KICB4bGFiKE5VTEwpICsNCiAgZ2VvbV9wb2ludHJhbmdlKGFlcyh5bWluID0gbG93ZXIsIHltYXggPSB1cHBlciksIHNpemUgPTAuNzUsIGxpbmV3aWR0aCA9IDEpKw0KICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoIiNCNTFGMkUiLCAiIzM3N2ViOCIpLCBndWlkZSA9ICJub25lIikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcm91bmQobWVhbiwgMyksIHZqdXN0ID0gLTIpLCBzaXplID0gMykgKw0KICBjb29yZF9mbGlwKCkgKw0KICB0aGVtZShheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfYmxhbmsoKSkNCmBgYA0KDQpXZSBtYXkgYWxzbyBhcmd1YWJseSB0cmVhdCBlYWNoIGV4cGVyaW1lbnQgYXMgaW5kZXBlbmRlbnQgYW5kIGxvb2sgYXQgaWYgdGhlIHByb3BvcnRpb24gb2Ygc3VjY2VzcyBpcyBsb3dlciBmb3IgdGhlIFJvYmUvQmlyZXR0YSBncm91cCB0aGFuIGZvciB0aGUgb3RoZXIgZ3JvdXAgKFRhYmxlIFxAcmVmKHRhYjpGQUJwcm9wVGFibGUpKS4gVGhlIGJpbm9taWFsIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIG9mIHRoZSB0d28gcHJvcG9ydGlvbnMgaGFkIHNvbWUgb3ZlcmxhcCAoRmlndXJlIFxAcmVmKGZpZzpGQUJwcm9wKSksIGJ1dCBhcyBleHBlY3RlZCB0aGUgcHJvcG9ydGlvbiBvZiBzdWNjZXNzIHdhcyBzaWduaWZpY2FudGx5IGxlc3MgZm9yIHRoZSBSb2JlL0JpcmV0dGEgZ3JvdXAgKCRcY2hpXnsyfSQgPSBgciByb3VuZChwcm9wUmVzJHN0YXRpc3RpYywgMilgICwgZGYgPSAxLCBvbmUtc2lkZWQgcCA9IGByIHJvdW5kKHByb3BSZXMkcC52YWx1ZSwgMylgKS4NCg0KT3ZlcmFsbCB3ZSBjYW4gc2F5IHRoYXQgd2l0aCB0aGUgSFJFIGVmZmVjdCBhY3RpdmUgdGhlICJkaWZmaWN1bHQiIGl0ZW1zIChSb2JlIGFuZCBCaXJldHRhKSBvbiBhdmVyYWdlIG5lZWRlZCBhYm91dCA1IGF0dGVtcHRzIGFuZCB0aGUgb3RoZXIsICJlYXN5IiwgaXRlbXMgYWJvdXQgNCBhdHRlbXB0cywgd2hpY2ggdHJhbnNsYXRlcyB0byAyMCAlIGFuZCAyNSAlIGNoYW5jZSwgcmVzcGVjdGl2ZWx5Lg0KDQpgYGB7ciBGQUJtZWFucywgZmlnLmNhcCA9ICJNZWFuIG51bWJlciBvZiBhdHRlbXB0cyBuZWVkZWQgdG8gZ2V0IGVhY2ggb2YgdGhlIDEwIE1BIGVudHJpZXMgZm9yIEZBQiJ9DQoNCmdncGxvdChTbml0dCwgYWVzKE1lYW5BdHRlbXB0c05lZWRlZCkpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKGZpbGw9IFdobyksIGJpbndpZHRoID0gMC41LCBjb2xvdXI9ImJsYWNrIikgKw0KICAjc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJSZEJ1IiwgZGlyZWN0aW9uID0gMSkgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjQjUxRjJFIiwiI0Y0QTU4MiIsIiNBN0NGRTQiLCAiIzM3N2ViOCIpKSsNCiAgI3NjYWxlX2ZpbGxfdmlyaWRpc19kKG9wdGlvbiA9ICJ0dXJibyIsIGRpcmVjdGlvbiA9IC0xKSArDQogIHlsYWIoIkNvdW50IikgKw0KICB4bGFiKCJBdmVyYWdlIGF0dGVtcHRzIG5lZWRlZCIpICsNCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gMi41LCB5ID0gOS41LCBsYWJlbCA9ICJBbHRhLWx1Y2t5LXZpc3RhIiwgY29sb3VyID0gIiNCNTFGMkUiKSArDQogIGdlb21fY3VydmUoDQogICAgYWVzKHggPSAyLjUsIHkgPSA4LjgsIHhlbmQgPSAyLjAsIHllbmQgPSAyLjUpLA0KICAgIGFycm93ID0gYXJyb3coDQogICAgbGVuZ3RoID0gdW5pdCgwLjAzLCAibnBjIiksIA0KICAgIHR5cGU9ImNsb3NlZCIgDQogICAgKSwNCiAgICBjb2xvdXIgPSAiI0I1MUYyRSIsDQogICAgbGluZXdpZHRoID0gMS4yLA0KICAgIGFuZ2xlID0gMCANCiAgKSArDQogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwyMCwgYnkgPTIpKSsNCiAgdGhlbWUoDQogICAgbGVnZW5kLnBvc2l0aW9uID0gYygwLjk1LDAuOTUpLA0KICAgIGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gYygxLDEpLA0KICAgIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiKSwNCiAgICBsZWdlbmQua2V5ID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiLCBjb2xvciA9IE5BKQ0KICApDQoNCmBgYA0KDQpUaGUgbWVhbiBudW1iZXIgb2YgYXR0ZW1wdHMgYSBwbGF5ZXIgaGFkIHRvIGRvIHRvIGdldCBlYWNoIG9mIHRoZSAxMCBpdGVtcyBmb3IgdGhlIE1BIHZhcmllZCBmcm9tIGByIG1pbihTbml0dCRNZWFuQXR0ZW1wdHNOZWVkZWQpYCB0byBgciBtYXgoU25pdHQkTWVhbkF0dGVtcHRzTmVlZGVkKWAgd2l0aCBhIG1lYW4gb2YgYHIgcm91bmQobWVhbihTbml0dCRNZWFuQXR0ZW1wdHNOZWVkZWQpLCBkaWdpdHMgPSAyKWAuIFNvbWUgcGVvcGxlIGFyZSBsdWNraWVyIHRoYW4gb3RoZXJzIChGaWd1cmUgXEByZWYoZmlnOkZBQm1lYW5zKSkuDQoNCkFzIGFuIGFuZWNkb3RlLCBvbmx5IG9uZSBjaGFyYWN0ZXIgbWFuYWdlZCB0byBjb21wbGV0ZSB0aGUgRkFCIHdpdGhvdXQgZ2V0dGluZyBhbnkgb3RoZXIgTUEgZW50cmllcyAobGlrZSBnZW1zdG9uZXMgYW5kIHBsYXRlcyBmcm9tIG1pbm9yIHN1Y2Nlc3MgYnktcHJvZHVjdHMsIEZpZ3VyZSBcQHJlZihmaWc6RkFCY29tcGxldGUpKS4gQW5kIGhlIGRpZCBub3QgaGF2ZSBhbnkgb3RoZXIgTUEgcmVjb3JkcyBlaXRoZXIuIFdoYXQgYSBndXkuDQoNCmBgYHtyIEZBQmNvbXBsZXRlLCBvdXQud2lkdGg9JzQwJScsIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLmNhcD0iQW5vdGhlciB1bmlxdWUgaW5kaXZpZHVhbCIsIGVjaG8gPSBGQUxTRX0NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCdJa2VhLnBuZycpDQpgYGANCg0KIyMgUm9iZSBleHBlcmltZW50cw0KDQpBIHN1bW1hcnkgb2YgdGhlIHJlc3VsdHMgaXMgcHJlc2VudGVkIGluIFRhYmxlIFxAcmVmKHRhYjpSb2JlU3VtbWFyeVRhYmxlKSBiZWxvdy4gVGhpcyBpcyB2aXN1YWxpemVkIGFzIHN0YWNrZWQgYmFycyBvcmRlcmVkIGJ5IHByb3BvcnRpb24gUm9iZXMgaW4gRmlndXJlIFxAcmVmKGZpZzpyb2JlU3VtbWFyeUZpZ3VyZXMtMSkgKHBlciBjb25kaXRpb24pIGFuZCBGaWd1cmUgXEByZWYoZmlnOnJvYmVTdW1tYXJ5RmlndXJlcy0yKSAoZnVydGhlciBkaXZpZGVkIGludG8gdGhlIHNlcGFyYXRlIGJhdGNoZXMpLiBGaWd1cmUgXEByZWYoZmlnOnJvYmVTdW1tYXJ5RmlndXJlcy0zKSBzaG93IHRoZSBoZSBhY3R1YWwgc2VxdWVuY2Ugb2Ygb3V0Y29tZXMgZm9yIGVhY2ggYmF0Y2ggKGJhdGNoZXMgaW4gc2FtZSBvcmRlciBhcyBpbiBGaWd1cmUgXEByZWYoZmlnOnJvYmVTdW1tYXJ5RmlndXJlcy0yKSwgYnV0IG9taXR0aW5nIGxhYmVsbGluZyB0aGUgY29uZGl0aW9ucyB0byBsZWF2ZSBtb3JlIHNwYWNlKS4NCg0KSXQgaXMgZGlmZmljdWx0IHRvIGNvbXBhcmUgc3RhY2tlZCBiYXIgY2hhcnRzIHRoYXQgaGF2ZSBtb3JlIHRoYW4gdHdvIGNhdGVnb3JpZXMgYmVjYXVzZSB0aGUgbG9jYXRpb24gb2YgdGhlIG1pZGRsZSBjYXRlZ29yaWVzIGlzIHNoaWZ0ZWQgcmVsYXRpdmUgdG8gZWFjaCBvdGhlciBhY3Jvc3MgZ3JvdXBzIC0tIHRoZXkgZG9uJ3QgaGF2ZSBhIGNvbW1vbiBiYXNlbGluZS4gV2hlbiBhbmFseXNpbmcgdGhlIGVmZmVjdCBvZiB0aGUgdmFyaW91cyB0cmVhdG1lbnRzIGluIHRoZSBzdWItY2hhcHRlcnMgYmVsb3csIHRoZSBkZXRhaWxzIGFyZSB0aGVyZWZvcmUgcHJlc2VudGVkIGFzIHByb3BvcnRpb24gKHdpdGggOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzKSBvZiB0aGUgcmVsZXZhbnQgY2F0ZWdvcnkuDQoNCjxidXR0b24gY2xhc3M9ImJ0biBidG4tcHJpbWFyeSIgZGF0YS10b2dnbGU9ImNvbGxhcHNlIiBkYXRhLXRhcmdldD0iI1JvYmVUYWJsZSI+DQoNClNob3cvSGlkZSBUYWJsZSAzDQo8L2J1dHRvbj4NCg0KOjo6IHsjUm9iZVRhYmxlIC5jb2xsYXBzZS5zaG93fQ0KYGBge3IgUm9iZVN1bW1hcnlUYWJsZX0NCmtibChSb2JlU3VtbWFyeVRhYmxlLCBjYXB0aW9uID0gJ091dGNvbWUgb2YgUm9iZSBFeHBlcmltZW50cyBmb3IgZWFjaCBiYXRjaC4gVGhlIHBlcmNlbnRhZ2UgQWRlcHQgUm9iZSBpcyBoaWdobGlnaHRlZC4nLCBhbGlnbiA9ImMiKSB8Pg0KICBrYWJsZV9wYXBlcihjKCJob3ZlciIsICJjb25kZW5zZWQiKSwgZnVsbF93aWR0aCA9IEYpIHw+DQogIGNvbHVtbl9zcGVjKDksIGJhY2tncm91bmQgPSAiIzkyYzVkZSIpIHw+ICMsIGNvbG9yID0gIndoaXRlIg0KICBwYWNrX3Jvd3MoIkhSRSwgQWR2aXNvciwgQWRlcHQsIHIyMCIsIDEsIDMpIHw+DQogIHBhY2tfcm93cygiSFJFLCBBZHZpc29yLCByMjAiLCA0LCA2KSB8Pg0KICBwYWNrX3Jvd3MoIkhSRSwgQWR2aXNvciwgQWRlcHQsIHIyMCwgRXgiLCA3LCA5KSB8Pg0KICBwYWNrX3Jvd3MoIkhSRSwgQWR2aXNvciwgcjIwLCBFeCIsIDEwLCAxMikgfD4NCiAgcGFja19yb3dzKCJIUkUsIEFkdmlzb3IsIEFkZXB0LCByMjAsIEV4LCBPeGYiLCAxMywgMTUpIHw+DQogIHBhY2tfcm93cygiSFJFLCBBZHZpc29yLCByMTEiLCAxNiwgMTcpIHw+DQogIHBhY2tfcm93cygiSFJFLCByMTEiLCAxOCwgMTgpIHw+DQogIHBhY2tfcm93cygiSFJFLCByMjAiLCAxOSwgMTkpIHw+DQogIHBhY2tfcm93cygiSFJFLCBBZGVwdCwgcjExIiwgMjAsIDIwKSB8Pg0KICBwYWNrX3Jvd3MoIkhSRSwgQWRlcHQsIHIyMCIsIDIxLCAyMSkgfD4NCiAgcGFja19yb3dzKCJyMTEiLCAyMiwgMjIpIHw+DQogIHBhY2tfcm93cygiQWRlcHQsIHIxMSIsIDIzLCAyMykgfD4NCiAgcGFja19yb3dzKCJyMjAiLCAyNCwgMjQpIHw+DQogIHBhY2tfcm93cygiQWRlcHQsIHIyMCIsIDI1LCAyNikNCmBgYA0KOjo6DQoNCmBgYHtyIHJvYmVTdW1tYXJ5RmlndXJlcywgZmlnLndpZHRoPTYsIGZpZy5jYXAgPSBjKCJQZXJjZW50YWdlIG9mIG91dGNvbWVzIGZvciBSb2JlIGV4cGVyaW1lbnRzIHVuZGVyIGRpZmZlcmVudCBjb25kaXRpb25zIiwgIlBlcmNlbnRhZ2Ugb2Ygb3V0Y29tZXMgc3BsaXQgaW4gYmF0Y2hlcyIsICJTZXF1ZW5jZSBvZiBvdXRjb21lcyBmb3IgUm9iZSBleHBlcmltZW50cyB1bmRlciBkaWZmZXJlbnQgY29uZGl0aW9ucywgZm9yIGVhY2ggYmF0Y2giKX0NCg0KIyBnZXQgY29uZGl0aW9uIGRlc2NyaXB0aW9ucyBmcm9tIHRhYmxlLCBhbmQgY29tYmluZSB3aXRoIHNhbXBsZSBzaXplIGZvciBmaWd1cmUgbGFiZWxzDQojIGFuZCByZW9yZGVyIGZhY3RvciBsZXZlbHMgYnkgJSByb2Jlcy4gYW5kIHRoZSBpdGVtcyBmcm9tICJoYXJkZXN0IHRvIGVhc2llc3QiDQojIGtlZXAgdGhlbSByZW9yZGVyZWQgaW4gdGhlIGZpbGUgc28gZG9uJ3QgaGF2ZSB0byBkbyB3aXRoaW4gZ2dwbG90DQpSb2JlMiA8LSBSb2JlIHw+IGxlZnRfam9pbihEZXNpZ24gfD4gc2VsZWN0KENvbmRpdGlvbiwgQ29uZGl0aW9uMiwgVG90YWxzKSwgYnk9IkNvbmRpdGlvbiIpDQpSb2JlMiA8LSBSb2JlMiB8Pg0KICBtdXRhdGUoQ29uZGl0aW9uMyA9IHBhc3RlMChDb25kaXRpb24yLCAiIChuID0gIiwgVG90YWxzLCAiKSIpKSB8Pg0KICBtdXRhdGUoQ29uZGl0aW9uMyA9IGZjdF9yZW9yZGVyKC5mID0gQ29uZGl0aW9uMywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC54ID0gUmVzdWx0LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuZnVuID0gZnVuY3Rpb24oLngpIG1lYW4oLnggPT0gIlJvYmUiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLmRlc2MgPSBUUlVFKSkgfD4NCiAgbXV0YXRlKFJlc3VsdCA9IGZjdF9yZWxldmVsKFJlc3VsdCwgIlJvYmUiLCAiSnVzdGF1Y29ycHMiLCAiV2Fpc3Rjb2F0IiwgIkZpbmVWZWx2ZXQiLCAiRmFpbHVyZSIpKQ0KICANCmdncGxvdChSb2JlMiwgYWVzKENvbmRpdGlvbjMsIGZpbGwgPSBmY3RfcmV2KFJlc3VsdCkpKSArIA0KICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJmaWxsIiwgd2lkdGggPSAwLjksKSArICMNCiAgI3NoYWRlczo6YnJpZ2h0bmVzcyhzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlJkQnUiLCBkaXJlY3Rpb24gPSAtMSksICAgc2hhZGVzOjpkZWx0YSgtMC4wNSkpICsNCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJSZFlsQnUiLCBkaXJlY3Rpb24gPSAtMSkgKw0KICAjc2NhbGVfZmlsbF92aXJpZGlzX2Qob3B0aW9uID0gInR1cmJvIiwgZGlyZWN0aW9uID0gMSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50LCBicmVha3MgPSBzZXEoMCwgMSwgYnkgPSAwLjIpLCBleHBhbmQgPSBleHBhbnNpb24obXVsdCA9IGMoMCwgMC4wMikpKSArDQogIHNjYWxlX3hfZGlzY3JldGUoZXhwYW5kID0gZXhwYW5zaW9uKG11bHQgPSBjKDAsIDApKSkrDQogIHlsYWIoIlBlcmNlbnRhZ2UiKSArDQogIHhsYWIoTlVMTCkgKw0KICB0aGVtZShsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIiNFQkVCRUIiKSwNCiAgICAgICAgbGVnZW5kLmtleSA9IGVsZW1lbnRfcmVjdChmaWxsID0gTkEpLA0KICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAidG9wIiwNCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IHJlbCgxKSksDQogICAgICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvci55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBsZWdlbmQuanVzdGlmaWNhdGlvbiA9IGMoMSwgMCksDQogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIpKSArDQogIGd1aWRlcyhmaWxsID0gZ3VpZGVfbGVnZW5kKHJldmVyc2UgPSBUUlVFLCB0aXRsZSA9IE5VTEwpKSsNCiAgY29vcmRfZmxpcCgpDQoNCiMgaW5jbHVkZSBiYXRjaCwgd2l0aGluIGNvbmRpdGlvbg0KUm9iZTIkR3JvdXBCYXRjaCA8LSBhdmUoUm9iZTIkQmF0Y2gsIFJvYmUyJENvbmRpdGlvbiwgDQogICAgICAgICAgICAgICAgICAgICAgICBGVU4gPSBmdW5jdGlvbih4KSBhcy5udW1lcmljKGZhY3Rvcih4KSkpDQpnZ3Bsb3QoUm9iZTIsIGFlcyhHcm91cEJhdGNoLCBmaWxsID0gZmN0X3JldihSZXN1bHQpKSkgKyANCiAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZmlsbCIsICB3aWR0aCA9IDEpICsgI2NvbG91ciA9ICJibGFjayIsDQogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiUmRZbEJ1IiwgZGlyZWN0aW9uID0gLTEpICsNCiAgI3NjYWxlX2ZpbGxfdmlyaWRpc19kKG9wdGlvbiA9ICJ0dXJibyIsIGRpcmVjdGlvbiA9IDEpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudCwgYnJlYWtzID0gc2VxKDAsIDEsIGJ5ID0gMC4yKSwgZXhwYW5kID0gZXhwYW5zaW9uKG11bHQgPSBjKDAsIDAuMDIpKSkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gTlVMTCwgZXhwYW5kID0gZXhwYW5zaW9uKG11bHQgPSBjKDAsIDApKSkgKw0KICB5bGFiKCJQZXJjZW50YWdlIikgKw0KICB4bGFiKE5VTEwpICsNCiAgdGhlbWUobGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICIjRUJFQkVCIiksDQogICAgICAgIGxlZ2VuZC5rZXkgPSBlbGVtZW50X3JlY3QoZmlsbCA9IE5BKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIsDQogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMS4yKSksDQogICAgICAgIGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gYygxLCAwKSkgKw0KICBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZChyZXZlcnNlID0gVFJVRSwgdGl0bGUgPSBOVUxMKSkrDQogIGNvb3JkX2ZsaXAoKSsNCiAgZmFjZXRfd3JhcCh+ZmN0X3JldihDb25kaXRpb24zKSwgc3RyaXAucG9zaXRpb24gPSAibGVmdCIsIG5jb2wgPSAxLCBzY2FsZXMgPSAiZnJlZV95IikgKw0KICB0aGVtZShzdHJpcC50ZXh0LnkubGVmdCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDAsIGhqdXN0ID0gMSksIA0KICAgICAgICBwYW5lbC5zcGFjaW5nID0gdW5pdCgwLjEsImNtIiksIA0KICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSBOQSkpDQojIHRpbWUgc2VyaWVzIHZpc3VhbGl6YXRpb24NCmdncGxvdChSb2JlMiwgYWVzKHg9QmF0U2VxLCBmaWxsID0gZmN0X3JldihSZXN1bHQpKSkgKw0KICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJmaWxsIiwgd2lkdGggPSAxKSArICMsIGNvbG91ciA9ICJibGFjayINCiAgZmFjZXRfd3JhcCh2YXJzKGZjdF9yZXYoQ29uZGl0aW9uMyksIEdyb3VwQmF0Y2gpLCBzdHJpcC5wb3NpdGlvbiA9ICJsZWZ0IiwgbmNvbCA9IDEpICsNCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJSZFlsQnUiLCBkaXJlY3Rpb24gPSAtMSkgKw0KICAjc2NhbGVfZmlsbF92aXJpZGlzX2Qob3B0aW9uID0gInR1cmJvIiwgZGlyZWN0aW9uID0gMSkrDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMCwgMTIwLCBieSA9IDIwKSwgZXhwYW5kID0gZXhwYW5zaW9uKG11bHQgPSBjKDAsIDApKSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gTlVMTCwgZXhwYW5kID0gZXhwYW5zaW9uKG11bHQgPSBjKDAsIDApKSkgKw0KICB0aGVtZShsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIiNFQkVCRUIiKSwNCiAgICAgICAgbGVnZW5kLmtleSA9IGVsZW1lbnRfcmVjdChmaWxsID0gTkEpLA0KICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAidG9wIiwNCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IHJlbCgxLjIpKSwNCiAgICAgICAgbGVnZW5kLmp1c3RpZmljYXRpb24gPSBjKDAuNSwgMCkpICsNCiAgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQocmV2ZXJzZSA9IFRSVUUsIHRpdGxlID0gTlVMTCkpICsNCiAgdGhlbWUoc3RyaXAudGV4dC55LmxlZnQgPSBlbGVtZW50X2JsYW5rKCksIA0KICAgICAgICBzdHJpcC50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBhbmVsLnNwYWNpbmcgPSB1bml0KDAuMSwiY20iKSkgKw0KICB4bGFiKCJTZXF1ZW5jZSIpICsNCiAgeWxhYihOVUxMKQ0KDQpgYGANCg0KIyMjIEhSRSBlZmZlY3QNCg0KYGBge3IgSFJFZWZmZWN0LCAgZmlnLmhlaWdodD00LCBmaWcuY2FwID0gIkVmZmVjdCBvZiBIb2x5IFJvbWFuIEVtcGVyb3Igc3VwcG9ydCBhbGNoZW15IHBvbGljeSAoSFJFKS4gUHJvcG9ydGlvbiBvZiBleHBlcmltZW50cyB0aGF0IHlpZWxkZWQgUm9iZSB1bmRlciBvdGhlcndpc2Ugc2ltaWxhciBjb25kaXRpb25zLCB3aXRoIDk1JSBjb25maWRlbmNlIGludGVydmFscyJ9DQpIUkUgPC0gUm9iZTIgfD4gDQogIG11dGF0ZShyb2JlU2VyaWVzID0gZmN0X290aGVyKFJlc3VsdCwga2VlcCA9ICJSb2JlIikpIHw+IA0KICBncm91cF9ieShIUkUsIENvbmRpdGlvbjIsIHJvYmVTZXJpZXMpIHw+DQogIHN1bW1hcmlzZShudW1iZXIgPSBuKCksIENvbmRpdGlvbiA9IG1lYW4oQ29uZGl0aW9uKSkgfD4gDQogIHVuZ3JvdXAoKSB8PiANCiAgcGl2b3Rfd2lkZXIoDQogIG5hbWVzX2Zyb20gID0gInJvYmVTZXJpZXMiLA0KICB2YWx1ZXNfZnJvbSA9ICJudW1iZXIiLA0KICB2YWx1ZXNfZmlsbCA9IDApIHw+IA0KICBtdXRhdGUoVG90YWwgPSBSb2JlK090aGVyLA0KICAgICAgICAgUHJvcFJvYmUgPSBSb2JlL1RvdGFsKQ0KSFJFIDwtIGNiaW5kKEhSRSwgDQogICAgICBiaW5vbS5jb25maW50KEhSRSRSb2JlLCBuID0gSFJFJFRvdGFsLCBtZXRob2RzID0gIndpbHNvbiIpKQ0KDQpIUkUgPC0gSFJFIHw+IA0KICBmaWx0ZXIoQ29uZGl0aW9uICVpbiUgYyg3OjEwKSB8IEhSRSA9PSAiTk8iKSB8PiAjbWFudWFsIHN1YnNldHRpbmcNCiAgbXV0YXRlKENvbmRpdGlvbjMgPSAoc3RyX3JlcGxhY2UoQ29uZGl0aW9uMiwgYygiSFJFLCAiKSwgIiIpKSkNCiAgDQpIUkUgfD4gDQpnZ3Bsb3QoYWVzKHkgPSBDb25kaXRpb24zLCB4ID0gUHJvcFJvYmUsIGNvbG91ciA9IEhSRSkpICsNCiAgeWxhYihOVUxMKSArDQogIHhsYWIoIlByb3BvcnRpb24gUm9iZSIpICsNCiAgZ2VvbV9wb2ludHJhbmdlKGFlcyh4bWluID0gbG93ZXIsIHhtYXggPSB1cHBlciksIA0KICAgICAgICAgICAgICAgICAgc2l6ZSA9MC43NSwgbGluZXdpZHRoID0gMSwNCiAgICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGg9MSkpICsNCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCIjOTVhNWE2IiwgIiMyYzNlNTAiKSkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikgKw0KICBmYWNldF93cmFwKHZhcnMoQ29uZGl0aW9uMyksIHN0cmlwLnBvc2l0aW9uID0gImxlZnQiLCBuY29sID0gMSwgc2NhbGVzID0gImZyZWVfeSIpKw0KICB0aGVtZShzdHJpcC50ZXh0LnkubGVmdCA9IGVsZW1lbnRfYmxhbmsoKSwgDQogICAgICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuc3BhY2luZyA9IHVuaXQoMC41LCJjbSIpLA0KICAgICAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfYmxhbmsoKSkgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGFzdGUoIm4gPSIsIFRvdGFsKSksIHZqdXN0ID0gMCwgaGp1c3QgPSAtMC41LCBzaXplID0gMykNCg0KYGBgDQoNClRoZXJlIHdhcyBhIGxhcmdlIGFuZCBjb25zaXN0ZW50IGVmZmVjdCBvZiB0aGUgSG9seSBSb21hbiBFbXBpcmUgcG9saWN5IChGaWd1cmUgXEByZWYoZmlnOkhSRWVmZmVjdCkpLiBIYXZpbmcgdGhlIEhSRSBlZmZlY3QgYWRkZWQgYXJvdW5kIDIwJSB0byB0aGUgUm9iZSBwcm9wb3J0aW9uLCBib3RoIHdoZW4gYXQgcjExIGFuZCByMjAgYWxjaGVteSBhbmQgd2l0aCBvciB3aXRob3V0IGFkZXB0IHRpdGxlLg0KDQojIyMgQWR2aXNvciBlZmZlY3QNCg0KYGBge3IgYWR2aXNvckVmZmVjdCwgZmlnLmhlaWdodD0zLjUsIGZpZy5jYXAgPSAiRWZmZWN0IG9mIENvdXJ0IEFsY2hlbWlzdCBBZHZpc29yIHBvc2l0aW9uLiBQcm9wb3J0aW9uIG9mIGV4cGVyaW1lbnRzIHRoYXQgeWllbGRlZCBSb2JlIHVuZGVyIG90aGVyd2lzZSBzaW1pbGFyIGNvbmRpdGlvbnMsIHdpdGggOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIn0NCkFEViA8LSBSb2JlMiB8PiANCiAgbXV0YXRlKHJvYmVTZXJpZXMgPSBmY3Rfb3RoZXIoUmVzdWx0LCBrZWVwID0gIlJvYmUiKSkgfD4gDQogIGdyb3VwX2J5KEFkdmlzb3IsIENvbmRpdGlvbjIsIHJvYmVTZXJpZXMpIHw+DQogIHN1bW1hcmlzZShudW1iZXIgPSBuKCksIENvbmRpdGlvbiA9IG1lYW4oQ29uZGl0aW9uKSkgfD4gDQogIHVuZ3JvdXAoKSB8PiANCiAgcGl2b3Rfd2lkZXIoDQogIG5hbWVzX2Zyb20gID0gInJvYmVTZXJpZXMiLA0KICB2YWx1ZXNfZnJvbSA9ICJudW1iZXIiLA0KICB2YWx1ZXNfZmlsbCA9IDApIHw+IA0KICBtdXRhdGUoVG90YWwgPSBSb2JlK090aGVyLA0KICAgICAgICAgUHJvcFJvYmUgPSBSb2JlL1RvdGFsKQ0KQURWIDwtIGNiaW5kKEFEViwgDQogICAgICBiaW5vbS5jb25maW50KEFEViRSb2JlLCBuID0gQURWJFRvdGFsLCBtZXRob2RzID0gIndpbHNvbiIpKQ0KDQpBRFYgPC0gQURWIHw+IA0KICBmaWx0ZXIoQ29uZGl0aW9uICVpbiUgYygxLDIsNiw3LDgsMTApKSB8PiAjZG9udCBsaWtlIG1hbnVhbCBzdWJzZXR0aW5nIG9mIHRoZXNlIHJvd3MuLi4NCiAgbXV0YXRlKENvbmRpdGlvbjMgPSAoc3RyX3JlcGxhY2UoQ29uZGl0aW9uMiwgYygiQWR2aXNvciwgIiksICIiKSkpDQogIA0KQURWIHw+IA0KZ2dwbG90KGFlcyh5ID0gQ29uZGl0aW9uMywgeCA9IFByb3BSb2JlLCBjb2xvdXIgPSBBZHZpc29yKSkgKw0KICB5bGFiKE5VTEwpICsNCiAgeGxhYigiUHJvcG9ydGlvbiBSb2JlIikgKw0KICBnZW9tX3BvaW50cmFuZ2UoYWVzKHhtaW4gPSBsb3dlciwgeG1heCA9IHVwcGVyKSwgDQogICAgICAgICAgICAgICAgICBzaXplID0wLjc1LCBsaW5ld2lkdGggPSAxLA0KICAgICAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aD0xKSkgKw0KICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoIiM5NWE1YTYiLCAiIzJjM2U1MCIpKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKSArDQogIGZhY2V0X3dyYXAodmFycyhDb25kaXRpb24zKSwgc3RyaXAucG9zaXRpb24gPSAibGVmdCIsIG5jb2wgPSAxLCBzY2FsZXMgPSAiZnJlZV95IikrDQogIHRoZW1lKHN0cmlwLnRleHQueS5sZWZ0ID0gZWxlbWVudF9ibGFuaygpLCANCiAgICAgICAgc3RyaXAudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5zcGFjaW5nID0gdW5pdCgwLjUsImNtIiksDQogICAgICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvci55ID0gZWxlbWVudF9ibGFuaygpKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwYXN0ZSgibiA9IiwgVG90YWwpKSwgdmp1c3QgPSAwLCBoanVzdCA9IC0wLjUsIHNpemUgPSAzKQ0KQURWd2lkZSA8LSBBRFYgfD4gDQogIGdyb3VwX2J5KEFkdmlzb3IpIHw+IA0KICBzdW1tYXJpc2UoU3VtUm9iZXMgPSBzdW0oUm9iZSksIFN1bVRvdHMgPSBzdW0oVG90YWwpKSB8PiANCiAgbXV0YXRlKFN1bVByb3AgPSBTdW1Sb2Jlcy9TdW1Ub3RzKQ0KKEFEVnByb3BUZXN0VG90YWwgPC0gcHJvcC50ZXN0KHggPSBBRFZ3aWRlJFN1bVJvYmVzLCBBRFZ3aWRlJFN1bVRvdHMsIGFsdGVybmF0aXZlID0gImxlc3MiKSkNCihBRFZwcm9wVGVzdHMgPC0gDQogIHNwbGl0KEFEViwgYXMuZmFjdG9yKEFEViRDb25kaXRpb24zKSkgfD4gIA0KICBtYXAoZnVuY3Rpb24gKGRmKSBwcm9wLnRlc3QoeCA9IGRmJFJvYmUsIG4gPSBkZiRUb3RhbCwgYWx0ZXJuYXRpdmUgPSAibGVzcyIpKSkNCmBgYA0KDQpUaGUgYWR2aXNvciBlZmZlY3Qgd2FzIGNsZWFybHkgc21hbGxlciBpbiBtYWduaXR1ZGUgdGhhbiB0aGUgSFJFIGVmZmVjdCwgYWRkaW5nIGNvbnNpc3RlbnRseSBhcm91bmQgMTAlIHRvIHRoZSBSb2JlIHByb3BvcnRpb24gaW4gdGhlIHRocmVlIGNvbnRyYXN0cyB0aGF0IGNvdWxkIGJlIG1hZGUgKEZpZ3VyZSBcQHJlZihmaWc6YWR2aXNvckVmZmVjdCkpLiBUaGUgY29uZmlkZW5jZSBpbnRlcnZhbHMgb3ZlcmxhcHBlZCBidXQgdGhlIGVmZmVjdCB3YXMgc2lnbmlmaWNhbnQgaW4gdGhlIEhSRS1yMTEgYW5kIEhSRS1yMjAgZ3JvdXBzLCBhbmQgaGlnaGx5IHNpZ25pZmljYW50IHdoZW4gcG9vbGluZyB0aGUgdGhyZWUgZ3JvdXBzICg0Ni8yNDYgdnMgMTcyLzU3NCwgJFxjaGleezJ9JCA9IGByIHJvdW5kKEFEVnByb3BUZXN0VG90YWwkc3RhdGlzdGljLCAyKWAgLCBkZiA9IDEsIG9uZS1zaWRlZCBwIFw8IGByIHJvdW5kKEFEVnByb3BUZXN0VG90YWwkcC52YWx1ZSwgMylgKS4NCg0KIyMjIEFkZXB0IGVmZmVjdCBhbmQgYmFzZSBzdWNjZXNzIHJhdGUNCg0KYGBge3IgYWRlcHRFZmZlY3QsIGZpZy5oZWlnaHQ9NS41LCBmaWcuY2FwID0gIkVmZmVjdCBvZiBBZGVwdCB0aXRsZS4gUHJvcG9ydGlvbiBvZiBleHBlcmltZW50cyB0aGF0IHlpZWxkZWQgUm9iZSB1bmRlciBvdGhlcndpc2Ugc2ltaWxhciBjb25kaXRpb25zLCB3aXRoIDk1JSBjb25maWRlbmNlIGludGVydmFscyJ9DQpBREVQVCA8LSBSb2JlMiB8PiANCiAgbXV0YXRlKHJvYmVTZXJpZXMgPSBmY3Rfb3RoZXIoUmVzdWx0LCBrZWVwID0gIlJvYmUiKSkgfD4gDQogIGdyb3VwX2J5KEFkZXB0LCBDb25kaXRpb24yLCByb2JlU2VyaWVzKSB8Pg0KICBzdW1tYXJpc2UobnVtYmVyID0gbigpLCBDb25kaXRpb24gPSBtZWFuKENvbmRpdGlvbikpIHw+IA0KICB1bmdyb3VwKCkgfD4gDQogIHBpdm90X3dpZGVyKA0KICBuYW1lc19mcm9tICA9ICJyb2JlU2VyaWVzIiwNCiAgdmFsdWVzX2Zyb20gPSAibnVtYmVyIiwNCiAgdmFsdWVzX2ZpbGwgPSAwKSB8PiANCiAgbXV0YXRlKFRvdGFsID0gUm9iZStPdGhlciwNCiAgICAgICAgIFByb3BSb2JlID0gUm9iZS9Ub3RhbCkNCkFERVBUIDwtIGNiaW5kKEFERVBULCANCiAgICAgIGJpbm9tLmNvbmZpbnQoQURFUFQkUm9iZSwgbiA9IEFERVBUJFRvdGFsLCBtZXRob2RzID0gIndpbHNvbiIpKQ0KDQpBREVQVCA8LSBBREVQVCB8PiANCiAgZmlsdGVyKCEoQ29uZGl0aW9uICVpbiUgYyg1LDYpKSkgfD4gI2RvbnQgbGlrZSBtYW51YWwgc3Vic2V0dGluZyBvZiB0aGVzZSByb3dzLi4uDQogIG11dGF0ZShDb25kaXRpb24zID0gKHN0cl9yZXBsYWNlKENvbmRpdGlvbjIsIGMoIkFkZXB0LCAiKSwgIiIpKSkNCiAgDQpBREVQVCB8PiANCmdncGxvdChhZXMoeSA9IENvbmRpdGlvbjMsIHggPSBQcm9wUm9iZSwgY29sb3VyID0gQWRlcHQpKSArDQogIHlsYWIoTlVMTCkgKw0KICB4bGFiKCJQcm9wb3J0aW9uIFJvYmUiKSArDQogIGdlb21fcG9pbnRyYW5nZShhZXMoeG1pbiA9IGxvd2VyLCB4bWF4ID0gdXBwZXIpLCANCiAgICAgICAgICAgICAgICAgIHNpemUgPTAuNzUsIGxpbmV3aWR0aCA9IDEsDQogICAgICAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoPTEpKSArDQogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiIzk1YTVhNiIsICIjMmMzZTUwIikpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpICsNCiAgZmFjZXRfd3JhcCh2YXJzKENvbmRpdGlvbjMpLCBzdHJpcC5wb3NpdGlvbiA9ICJsZWZ0IiwgbmNvbCA9IDEsIHNjYWxlcyA9ICJmcmVlX3kiKSsNCiAgdGhlbWUoc3RyaXAudGV4dC55LmxlZnQgPSBlbGVtZW50X2JsYW5rKCksIA0KICAgICAgICBzdHJpcC50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBhbmVsLnNwYWNpbmcgPSB1bml0KDAuNSwiY20iKSwNCiAgICAgICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2JsYW5rKCkpICsNCiAgZ2dyZXBlbDo6Z2VvbV90ZXh0X3JlcGVsKGFlcyhsYWJlbCA9IHBhc3RlKCJuID0iLCBUb3RhbCkpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAzLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9ICJ4IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICBtaW4uc2VnbWVudC5sZW5ndGggPSA1LCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlZWQgPTY2NikNCkFERVBUd2lkZSA8LSBBREVQVCB8PiANCiAgcGl2b3Rfd2lkZXIoDQogIG5hbWVzX2Zyb20gID0gYyhBZGVwdCksDQogIHZhbHVlc19mcm9tID0gIlByb3BSb2JlIikgfD4NCiAgZ3JvdXBfYnkoQ29uZGl0aW9uMykgfD4gDQogIHN1bW1hcmlzZShOTyA9IG1heChOTywgbmEucm0gPSBUKSwgWUVTID0gbWF4KFlFUywgbmEucm0gPSBUKSkgfD4gDQogIG11dGF0ZShkaWZmZXJlbmNlID0gWUVTLU5PKQ0KYWRlcHRkaWZmIDwtICByb3VuZChtZWFuKEFERVBUd2lkZSRkaWZmZXJlbmNlKSwgZGlnaXRzID0gNCkNCg0KKGFkZXB0RXN0IDwtIGJpbm9tLmNvbmZpbnQoeD0gMiwgbiA9IDIyMywgbWV0aG9kcyA9ICJ3aWxzb24iKSkNCihiYXNlRXN0IDwtIGJpbm9tLmNvbmZpbnQoeD0gMCwgbiA9IDIxNywgbWV0aG9kcyA9ICJ3aWxzb24iKSkNCg0KYGBgDQoNClRoZSBhZGVwdCBlZmZlY3Qgd2FzIHRvbyBzbWFsbCB0byBiZSBwcmVjaXNlbHkgbWVhc3VyZWQgd2l0aCB0aGVzZSBkYXRhIChGaWd1cmUgXEByZWYoZmlnOmFkZXB0RWZmZWN0KSksIGJ1dCBpdCBpcyBjbGVhcmx5IHNtYWxsZXIgdGhhbiB0aGUgSFJFIGFuZCBhZHZpc29yIGVmZmVjdHMuIE9uIGF2ZXJhZ2UgKGZvciB0aGUgNiBjb250cmFzdHMpIHRoZSBlZmZlY3Qgd2FzIHRvIGluY3JlYXNlIHRoZSBwcm9wb3J0aW9uIGJ5IDAuMDIyIChpLmUuIHRvIGFkZCAyLjIlIHRvIHRoZSBzdWNjZXNzIHJhdGUpLCBidXQgdGhlIGVzdGltYXRlcyB2YXJpZWQgZnJvbSAtMC4wMDYgdG8gMC4wOC4gQWx0aG91Z2ggd2UgZG8gbm90IGtub3cgdGhlIGV4YWN0IGJhc2UgcmF0ZSwgaXQgaXMgbW9zdCByZWxpYWJsZSB0byBzaW1wbHkgZXN0aW1hdGUgdGhlIGFkZXB0IGVmZmVjdCBmcm9tIHRoZSB0d28gc2FtcGxlcyBvZiBhZGVwdCB3aXRob3V0IEhSRSBvciBhZHZpc29yIGVmZmVjdCwgYmVjYXVzZSB0aGUgY29udHJvbCBncm91cCBlc3RpbWF0ZXMgb3RoZXJ3aXNlIHN1ZmZlcnMgZnJvbSB1bmNlcnRhaW50eSBhcyB3ZWxsLiBJZiB3ZSBwb29sIHRoZSB0d28gc2FtcGxlcyAodGhhdCBvbmx5IGRpZmZlcmVkIGluIGFsY2hlbXkgcmFuaykgd2UgZ2V0IDIgcm9iZXMgb3V0IG9mIDIyMyB0cmlhbHMgKDAuMDA5KSwgd2l0aCBhIDk1JSBjb25maWRlbmNlIGludGVydmFsIG9mIDAuMDAyNS0tMC4wMzIuIFdlIGFyZSB0aGVyZWZvcmUgOTUlIGNlcnRhaW4gdGhhdCB0aGUgdHJ1ZSBlZmZlY3Qgb2YgdGhlIGFkZXB0IHRpdGxlIGlzIGxlc3MgdGhhbiAzLjIlLCB3aXRoIGEgcG9pbnQgZXN0aW1hdGUgb2YgMC45JSAobWludXMgdGhlIGJhc2UgcmF0ZSkuDQoNClRoZSBiYXNlIHJhdGUgaXMgdmVyeSBsb3csIGFuZCBiZWxvdyB0aGUgZGV0ZWN0aW9uIGxpbWl0IG9mIHRoZSBzdHVkeS4gTm8gcm9iZXMgcmVzdWx0ZWQgZnJvbSB0aGUgMjE3IHRyaWFscyBpbiB0aGUgdHdvIHIxMS9yMjAgZ3JvdXBzIHdpdGhvdXQgYWRlcHQgdGl0bGUgb3Igb3RoZXIgZWZmZWN0cyAoZnJvbSB0aGUgdHdvIGxvd2VyIHBhbmVscyBpbiBGaWd1cmUgXEByZWYoZmlnOmFkZXB0RWZmZWN0KSkuIElmIHdlIHBvb2wgdGhlc2Ugd2UgZ2V0IGEgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgb2YgMC0tMC4wMTcuIFdlIGFyZSB0aHVzIDk1JSBjZXJ0YWluIHRoYXQgdGhlIHRydWUgYmFzZSByYXRlIGlzIGJlbG93IDEuNyUsIHdpdGggYSBwb2ludCBlc3RpbWF0ZSBvZiAwLjAlLiBJdCBzaG91bGQgYmUgbm90ZWQgdGhhdCB0aGUgYmFzZSByYXRlIGlzIGtub3duIG5vdCB0byBiZSB6ZXJvIC0tIGl0IGlzIHBvc3NpYmxlIHRvIHByb2R1Y2UgdGhlIHJvYmUgd2l0aG91dCBhZGVwdCB0aXRsZSBvciBhbnkgb3RoZXIgZWZmZWN0cyBhY3RpdmUuDQoNCiMjIyBBbGNoZW15IHNraWxsIHJhbmssIEVYLCBPeGZvcmQgYW5kIGFpZGUNCg0KVGhlcmUgd2FzIG5vIGVmZmVjdCBvZiBhbGNoZW15IHJhbmsgb24gdGhlIHByb2JhYmlsaXR5IG9mIGdldHRpbmcgYSBSb2JlIChGaWd1cmUgXEByZWYoZmlnOkFsY2hlbXlSKSk6IGluIGFsbCBmaXZlIGNvbXBhcmlzb25zIHRoZSB0cmVhdG1lbnQgKHIyMCkgYW5kIHRoZSBjb250cm9sIGdyb3VwIChyMTEpIHdhcyB2ZXJ5IHNpbWlsYXIgdG8gZWFjaCBvdGhlciwgcmVsYXRpdmUgdG8gdGhlIHVuY2VydGFpbnR5IGFuZCB0aGUgcmVhZGlseSBldmlkZW50IGVmZmVjdHMgb2YgSFJFIGFuZCBBZHZpc29yLg0KDQpgYGB7ciBBbGNoZW15UiwgZmlnLmhlaWdodD00LjUsIGZpZy5jYXA9IkVmZmVjdCBvZiBBbGNoZW15IHJhbmsgKHIxMSBvciByMjApLiBQcm9wb3J0aW9uIG9mIGV4cGVyaW1lbnRzIHRoYXQgeWllbGRlZCBSb2JlIHVuZGVyIG90aGVyd2lzZSBzaW1pbGFyIGNvbmRpdGlvbnMsIHdpdGggOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIn0NCkFMQ0ggPC0gUm9iZTIgfD4gDQogIG11dGF0ZShyb2JlU2VyaWVzID0gZmN0X290aGVyKFJlc3VsdCwga2VlcCA9ICJSb2JlIikpIHw+IA0KICBncm91cF9ieShBbGNoZW15LCBDb25kaXRpb24yLCByb2JlU2VyaWVzKSB8Pg0KICBzdW1tYXJpc2UobnVtYmVyID0gbigpLCBDb25kaXRpb24gPSBtZWFuKENvbmRpdGlvbikpIHw+IA0KICB1bmdyb3VwKCkgfD4gDQogIHBpdm90X3dpZGVyKA0KICBuYW1lc19mcm9tICA9ICJyb2JlU2VyaWVzIiwNCiAgdmFsdWVzX2Zyb20gPSAibnVtYmVyIiwNCiAgdmFsdWVzX2ZpbGwgPSAwKSB8PiANCiAgbXV0YXRlKFRvdGFsID0gUm9iZStPdGhlciwNCiAgICAgICAgIFByb3BSb2JlID0gUm9iZS9Ub3RhbCkNCkFMQ0ggPC0gY2JpbmQoQUxDSCwgDQogICAgICBiaW5vbS5jb25maW50KEFMQ0gkUm9iZSwgbiA9IEFMQ0gkVG90YWwsIG1ldGhvZHMgPSAid2lsc29uIikpDQoNCkFMQ0ggPC0gQUxDSCB8PiANCiAgZmlsdGVyKENvbmRpdGlvbiAlaW4lIGMoMiw2OjE0KSkgfD4gI2RvbnQgbGlrZSBtYW51YWwgc3Vic2V0dGluZyBvZiB0aGVzZSByb3dzLi4uDQogIG11dGF0ZShDb25kaXRpb24zID0gKHN0cl9yZXBsYWNlKENvbmRpdGlvbjIsIGMoIiwgcjExIiksICIiKSkpIHw+IA0KICBtdXRhdGUoQ29uZGl0aW9uMyA9IChzdHJfcmVwbGFjZShDb25kaXRpb24zLCBjKCIsIHIyMCIpLCAiIikpKSB8PiANCiAgbXV0YXRlKENvbmRpdGlvbjMgPSAoc3RyX3JlcGxhY2UoQ29uZGl0aW9uMywgYygicjExIiksICJOb3RoaW5nIikpKSB8PiANCiAgbXV0YXRlKENvbmRpdGlvbjMgPSAoc3RyX3JlcGxhY2UoQ29uZGl0aW9uMywgYygicjIwIiksICJOb3RoaW5nIikpKQ0KICANCkFMQ0ggfD4gDQpnZ3Bsb3QoYWVzKHkgPSBDb25kaXRpb24zLCB4ID0gUHJvcFJvYmUsIGNvbG91ciA9IGFzLmZhY3RvcigoQWxjaGVteSkpKSkgKw0KICB5bGFiKE5VTEwpICsNCiAgeGxhYigiUHJvcG9ydGlvbiBSb2JlIikgKw0KICBsYWJzKGNvbG91ciA9ICJBbGNoZW15IHJhbmsiKSsNCiAgZ2VvbV9wb2ludHJhbmdlKGFlcyh4bWluID0gbG93ZXIsIHhtYXggPSB1cHBlciksIA0KICAgICAgICAgICAgICAgICAgc2l6ZSA9MC43NSwgbGluZXdpZHRoID0gMSwNCiAgICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGg9MSkpICsNCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCIjOTVhNWE2IiwgIiMyYzNlNTAiKSkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikgKw0KICBmYWNldF93cmFwKHZhcnMoQ29uZGl0aW9uMyksIHN0cmlwLnBvc2l0aW9uID0gImxlZnQiLCBuY29sID0gMSwgc2NhbGVzID0gImZyZWVfeSIpKw0KICB0aGVtZShzdHJpcC50ZXh0LnkubGVmdCA9IGVsZW1lbnRfYmxhbmsoKSwgDQogICAgICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuc3BhY2luZyA9IHVuaXQoMC41LCJjbSIpLA0KICAgICAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfYmxhbmsoKSkgKw0KICBnZ3JlcGVsOjpnZW9tX3RleHRfcmVwZWwoYWVzKGxhYmVsID0gcGFzdGUoIm4gPSIsIFRvdGFsKSksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gIngiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pbi5zZWdtZW50Lmxlbmd0aCA9IDUsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VlZCA9NjY2KQ0KYGBgDQoNCkVYIGVxdWlwbWVudCBoYWQgbm8gZWZmZWN0IGVpdGhlci4gVHdvIGNvbXBhcmlzb25zIHdlcmUgYXZhaWxhYmxlOiBJbiBvbmUgY29tcGFyaXNvbiB0aGUgdHJlYXRtZW50IGdyb3VwIGVzdGltYXRlIHdhcyBoaWdoZXIgdGhhbiB0aGUgY29udHJvbCBncm91cCAoRmlndXJlIFxAcmVmKGZpZzpFWCksIHRvcCkgYW5kIGluIGFub3RoZXIgY29tcGFyaXNvbiBsb3dlciAoRmlndXJlIFxAcmVmKGZpZzpFWCksIGJvdHRvbSkuIEluIGJvdGggY2FzZXMgd2l0aCBjb25zaWRlcmFibGUgb3ZlcmxhcCBvZiBjb25maWRlbmNlIGludGVydmFscy4gVG8gaWxsdW1pbmF0ZSB0aGUgaXNzdWUgZnVydGhlciBJIGluY2x1ZGVkIHRoZSBncm91cCB3aXRoIE94Zm9yZCBlZmZlY3RzIG9uIGluIGFkZGl0aW9uIHRvIEVYIChGaWd1cmUgXEByZWYoZmlnOkVYKSwgbWlkZGxlKS4gSWYgYW55dGhpbmcgdGhpcyBncm91cCBzaG91bGQgYmUgaGlnaGVyIG9yIGF0IGxlYXN0IHNpbWlsYXIgdG8gdGhlIGdyb3VwIHdpdGhvdXQgT3hmb3JkLiBJbiBmYWN0IGl0IHdhcyBsb3dlciwgYW5kIGxvd2VyIHRoYW4gdGhlIGNvbnRyb2wgZ3JvdXAgaW4gdGhlIHRvcCBwYW5lbC4gVGFrZW4gdG9nZXRoZXIgdGhpcyBzaG93cyBubyBtZWFzdXJhYmxlIGVmZmVjdCBvZiBFWCBlcXVpcG1lbnQgb24gUm9iZSBzdWNjZXNzLg0KDQpgYGB7ciBFWCwgZmlnLmhlaWdodD0zLjUsIGZpZy5jYXA9IkVmZmVjdCBvZiBFWCBlcXVpcG1lbnQuIFByb3BvcnRpb24gb2YgZXhwZXJpbWVudHMgdGhhdCB5aWVsZGVkIFJvYmUgdW5kZXIgb3RoZXJ3aXNlIHNpbWlsYXIgY29uZGl0aW9ucywgd2l0aCA5NSUgY29uZmlkZW5jZSBpbnRlcnZhbHMuIEFsc28gaW5jbHVkZXMgYSBncm91cCB3aXRoIE94Zm9yZHMgb24sIGJ1dCBvdGhlcndpc2Ugc2ltaWxhciB0byB0aGUgdG9wIHBhbmVsLiJ9DQpFWCA8LSBSb2JlMiB8PiANCiAgbXV0YXRlKHJvYmVTZXJpZXMgPSBmY3Rfb3RoZXIoUmVzdWx0LCBrZWVwID0gIlJvYmUiKSkgfD4gDQogIGdyb3VwX2J5KEVYLCBDb25kaXRpb24yLCByb2JlU2VyaWVzKSB8Pg0KICBzdW1tYXJpc2UobnVtYmVyID0gbigpLCBDb25kaXRpb24gPSBtZWFuKENvbmRpdGlvbikpIHw+IA0KICB1bmdyb3VwKCkgfD4gDQogIHBpdm90X3dpZGVyKA0KICBuYW1lc19mcm9tICA9ICJyb2JlU2VyaWVzIiwNCiAgdmFsdWVzX2Zyb20gPSAibnVtYmVyIiwNCiAgdmFsdWVzX2ZpbGwgPSAwKSB8PiANCiAgbXV0YXRlKFRvdGFsID0gUm9iZStPdGhlciwNCiAgICAgICAgIFByb3BSb2JlID0gUm9iZS9Ub3RhbCkNCkVYIDwtIGNiaW5kKEVYLCANCiAgICAgIGJpbm9tLmNvbmZpbnQoRVgkUm9iZSwgbiA9IEVYJFRvdGFsLCBtZXRob2RzID0gIndpbHNvbiIpKQ0KDQpFWCA8LSBFWCB8PiANCiAgZmlsdGVyKENvbmRpdGlvbiAlaW4lIGMoMTo1KSkgfD4gI2RvbnQgbGlrZSBtYW51YWwgc3Vic2V0dGluZyBvZiB0aGVzZSByb3dzLi4uDQogIG11dGF0ZShDb25kaXRpb24zID0gKHN0cl9yZXBsYWNlKENvbmRpdGlvbjIsIGMoIiwgRXgiKSwgIiIpKSkNCg0KRVh3aWRlIDwtIEVYIHw+IA0KICBwaXZvdF93aWRlcigNCiAgbmFtZXNfZnJvbSAgPSBjKEVYKSwNCiAgdmFsdWVzX2Zyb20gPSAiUHJvcFJvYmUiKSB8Pg0KICBncm91cF9ieShDb25kaXRpb24zKSB8PiANCiAgc3VtbWFyaXNlKE5PID0gbWVhbihOTywgbmEucm0gPSBUKSwgWUVTID0gbWVhbihZRVMsIG5hLnJtID0gVCkpIHw+IA0KICBtdXRhdGUoZGlmZmVyZW5jZSA9IFlFUy1OTykNCkVYZGlmZiA8LSAgcm91bmQobWVhbihFWHdpZGUkZGlmZmVyZW5jZSksIGRpZ2l0cyA9IDQpICANCg0KRVggfD4gDQpnZ3Bsb3QoYWVzKHkgPSBDb25kaXRpb24zLCB4ID0gUHJvcFJvYmUsIGNvbG91ciA9IEVYKSkgKw0KICB5bGFiKE5VTEwpICsNCiAgeGxhYigiUHJvcG9ydGlvbiBSb2JlIikgKw0KICBnZW9tX3BvaW50cmFuZ2UoYWVzKHhtaW4gPSBsb3dlciwgeG1heCA9IHVwcGVyKSwgDQogICAgICAgICAgICAgICAgICBzaXplID0wLjc1LCBsaW5ld2lkdGggPSAxLA0KICAgICAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aD0xKSkgKw0KICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoIiM5NWE1YTYiLCAiIzJjM2U1MCIpKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKSArDQogIGZhY2V0X3dyYXAodmFycyhDb25kaXRpb24zKSwgc3RyaXAucG9zaXRpb24gPSAibGVmdCIsIG5jb2wgPSAxLCBzY2FsZXMgPSAiZnJlZV95IikrDQogIHRoZW1lKHN0cmlwLnRleHQueS5sZWZ0ID0gZWxlbWVudF9ibGFuaygpLCANCiAgICAgICAgc3RyaXAudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5zcGFjaW5nID0gdW5pdCgwLjUsImNtIiksDQogICAgICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvci55ID0gZWxlbWVudF9ibGFuaygpKSArDQogIGdncmVwZWw6Omdlb21fdGV4dF9yZXBlbChhZXMobGFiZWwgPSBwYXN0ZSgibiA9IiwgVG90YWwpKSwNCiAgc2l6ZSA9IDMsDQogIG1pbi5zZWdtZW50Lmxlbmd0aCA9IDUsDQogIHNlZWQgPTU1NSkNCmBgYA0KDQpUaGUgc2FtZSBjb21wYXJpc29uIGFsc28gcmV2ZWFsIG5vIGluY3JlYXNlZCBSb2JlIHN1Y2Nlc3MgZnJvbSBPeGZvcmQgc2tpbGxzIChmb3IgY2xhcml0eSBzaG93biBzZXBhcmF0ZWx5IGluIEZpZ3VyZSBcQHJlZihmaWc6T3hmb3JkKSkuIFVuZm9ydHVuYXRlbHkgb25seSB0aGlzIG9uZSBjb250cmFzdCBvZiB0cmVhdG1lbnQgdnMuIGNvbnRyb2wgd2FzIGF2YWlsYWJsZSwgYnV0IGlmIGFueXRoaW5nIHN1Y2Nlc3Mgd2FzIHJlZHVjZWQgd2l0aCBPeGZvcmRzIG9uIHdoaWNoIGluZGljYXRlcyByYW5kb20gbm9pc2UuDQoNCmBgYHtyIE94Zm9yZCwgZmlnLmhlaWdodD0gMiwgZmlnLmNhcD0gIkVmZmVjdCBvZiBPeGZvcmQgc2tpbGxzIGFjdGl2ZS4gUHJvcG9ydGlvbiBvZiBleHBlcmltZW50cyB0aGF0IHlpZWxkZWQgUm9iZSB1bmRlciBvdGhlcndpc2Ugc2ltaWxhciBjb25kaXRpb25zLCB3aXRoIDk1JSBjb25maWRlbmNlIGludGVydmFscyJ9DQpPWEYgPC0gUm9iZTIgfD4gDQogIG11dGF0ZShyb2JlU2VyaWVzID0gZmN0X290aGVyKFJlc3VsdCwga2VlcCA9ICJSb2JlIikpIHw+IA0KICBncm91cF9ieShPeGZvcmRzLCBDb25kaXRpb24yLCByb2JlU2VyaWVzKSB8Pg0KICBzdW1tYXJpc2UobnVtYmVyID0gbigpLCBDb25kaXRpb24gPSBtZWFuKENvbmRpdGlvbikpIHw+IA0KICB1bmdyb3VwKCkgfD4gDQogIHBpdm90X3dpZGVyKA0KICBuYW1lc19mcm9tICA9ICJyb2JlU2VyaWVzIiwNCiAgdmFsdWVzX2Zyb20gPSAibnVtYmVyIiwNCiAgdmFsdWVzX2ZpbGwgPSAwKSB8PiANCiAgbXV0YXRlKFRvdGFsID0gUm9iZStPdGhlciwNCiAgICAgICAgIFByb3BSb2JlID0gUm9iZS9Ub3RhbCkNCk9YRiA8LSBjYmluZChPWEYsIA0KICAgICAgYmlub20uY29uZmludChPWEYkUm9iZSwgbiA9IE9YRiRUb3RhbCwgbWV0aG9kcyA9ICJ3aWxzb24iKSkNCg0KT1hGIDwtIE9YRiB8PiANCiAgZmlsdGVyKENvbmRpdGlvbiAlaW4lIGMoMyw1KSkgfD4gI2RvbnQgbGlrZSBtYW51YWwgc3Vic2V0dGluZyBvZiB0aGVzZSByb3dzLi4uDQogIG11dGF0ZShDb25kaXRpb24zID0gKHN0cl9yZXBsYWNlKENvbmRpdGlvbjIsIGMoIiwgT3hmIiksICIiKSkpDQoNCk9YRndpZGUgPC0gT1hGIHw+IA0KICBwaXZvdF93aWRlcigNCiAgbmFtZXNfZnJvbSAgPSBjKE94Zm9yZHMpLA0KICB2YWx1ZXNfZnJvbSA9ICJQcm9wUm9iZSIpIHw+DQogIGdyb3VwX2J5KENvbmRpdGlvbjMpIHw+IA0KICBzdW1tYXJpc2UoTk8gPSBtZWFuKE5PLCBuYS5ybSA9IFQpLCBZRVMgPSBtZWFuKFlFUywgbmEucm0gPSBUKSkgfD4gDQogIG11dGF0ZShkaWZmZXJlbmNlID0gWUVTLU5PKQ0KT1hGZGlmZiA8LSAgcm91bmQobWVhbihFWHdpZGUkZGlmZmVyZW5jZSksIGRpZ2l0cyA9IDQpIA0KDQpPWEYgfD4gDQpnZ3Bsb3QoYWVzKHkgPSBDb25kaXRpb24zLCB4ID0gUHJvcFJvYmUsIGNvbG91ciA9IE94Zm9yZHMpKSArDQogIHlsYWIoTlVMTCkgKw0KICB4bGFiKCJQcm9wb3J0aW9uIFJvYmUiKSArDQogIGdlb21fcG9pbnRyYW5nZShhZXMoeG1pbiA9IGxvd2VyLCB4bWF4ID0gdXBwZXIpLCANCiAgICAgICAgICAgICAgICAgIHNpemUgPTAuNzUsIGxpbmV3aWR0aCA9IDEsDQogICAgICAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoPTEpKSArDQogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiIzk1YTVhNiIsICIjMmMzZTUwIikpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpICsNCiAgZmFjZXRfd3JhcCh2YXJzKENvbmRpdGlvbjMpLCBzdHJpcC5wb3NpdGlvbiA9ICJsZWZ0IiwgbmNvbCA9IDEsIHNjYWxlcyA9ICJmcmVlX3kiKSsNCiAgdGhlbWUoc3RyaXAudGV4dC55LmxlZnQgPSBlbGVtZW50X2JsYW5rKCksIA0KICAgICAgICBzdHJpcC50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBhbmVsLnNwYWNpbmcgPSB1bml0KDAuNSwiY20iKSwNCiAgICAgICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2JsYW5rKCkpICsNCiAgZ2dyZXBlbDo6Z2VvbV90ZXh0X3JlcGVsKGFlcyhsYWJlbCA9IHBhc3RlKCJuID0iLCBUb3RhbCkpLA0KICBzaXplID0gMywNCiAgbWluLnNlZ21lbnQubGVuZ3RoID0gNSwNCiAgc2VlZCA9NTU1KQ0KYGBgDQoNCkFsbCB0cmlhbHMgaW4gdGhlIFJvYmUgc2V0LXVwIHdlcmUgZG9uZSB3aXRoIGFpZGUgaW4gcGF5bWFzdGVyIDEwMHMuIEhvd2V2ZXIsIGEgY29tcGFyaXNvbiB3aXRoIHRoZSBGQUIgZXhwZXJpbWVudHMgYWxsb3dzIGFuIGVzdGltYXRlIG9mIGEgcGF5bWFzdGVyIGFpZGUgZWZmZWN0IHRvIGJlIG1hZGUgc2luY2Ugb25seSB2ZXJ5IGZldyBoYWQgYW4gYWlkZSBhdCBhbGwgaW4gdGhlIEZBQiB0cmlhbHMuIFRoZSByZWxldmFudCBjb25kaXRpb24gaXMgSFJFLCB3aXRoIHJhbmsgMTEgb3IgMjAgYWxjaGVteS4gVGhlc2Ugd2VyZSBwb29sZWQgdG8gaW5jcmVhc2Ugc2FtcGxlIHNpemUgKHJhbmsgaGFkIG5vIGVmZmVjdCkuIFRoZSBGQUIgZXhwZXJpbWVudHMgd2VyZSBkb25lIHdpdGggSFJFLCBhdCByMTItLTE0IChpbmNsdWRlZCBpbiBUYWJsZSBcQHJlZih0YWI6cm9iZURlc2lnblRhYmxlKSBmb3IgY29udmVuaWVuY2UpLiBGaWd1cmUgXEByZWYoZmlnOnBheW1hc3Rlcikgc2hvd3MgdGhhdCBoYXZpbmcgYWlkZSBpbiBwYXltYXN0ZXIgZGlkIG5vdCBpbXByb3ZlIHRoZSBjaGFuY2Ugb2YgcHJvZHVjaW5nIGEgUm9iZS4gSWYgYW55dGhpbmcsIHRoZSBwcm9iYWJpbGl0eSB3YXMgbG93ZXIgd2l0aCBwYXltYXN0ZXIgYnV0IHRoZSBkaWZmZXJlbmNlIGlzIHdlbGwgd2l0aGluIHRoZSB1bmNlcnRhaW50eS4NCg0KYGBge3IgcGF5bWFzdGVyLCBmaWcuaGVpZ2h0PSAyLCBmaWcuY2FwPSAiRWZmZWN0IG9mIGFpZGUgaW4gUGF5bWFzdGVyLiBQcm9wb3J0aW9uIG9mIGV4cGVyaW1lbnRzIHRoYXQgeWllbGRlZCBSb2JlIHVuZGVyIG90aGVyd2lzZSBzaW1pbGFyIGNvbmRpdGlvbnMsIHdpdGggOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzLiBOb3RlIHRoYXQgdGhlIGNvbnRyb2wgZ3JvdXAgaXMgZnJvbSB0aGUgRkFCIHRyaWFscy4ifQ0KUGF5bWFzdGVyIDwtIHJlYWRfb2RzKCJ+XFxGQUJ0b3J5XFxwYXltYXN0ZXIub2RzIiwgc2hlZXQgPTEpDQpQYXltYXN0ZXIkQ29uZGl0aW9uMyA8LSAoYXMuZmFjdG9yKFBheW1hc3RlciRDb25kaXRpb24zKSkNClBheW1hc3RlciRDb25kaXRpb24zIDwtZmN0X3JlbGV2ZWwoUGF5bWFzdGVyJENvbmRpdGlvbjMsICJIUkUgKHIxMStyMjApIiwgIkhSRSAocjEyLXIxNCkiKQ0KDQpQYXltYXN0ZXIgfD4gDQpnZ3Bsb3QoYWVzKHkgPSBDb25kaXRpb24zLCB4ID0gUHJvcFJvYmUsIGNvbG91ciA9IFBheW1hc3RlcikpICsNCiAgeWxhYihOVUxMKSArDQogIHhsYWIoIlByb3BvcnRpb24gUm9iZSIpICsNCiAgZ2VvbV9wb2ludHJhbmdlKGFlcyh4bWluID0gbG93ZXIsIHhtYXggPSB1cHBlciksIA0KICAgICAgICAgICAgICAgICAgc2l6ZSA9MC43NSwgbGluZXdpZHRoID0gMSwNCiAgICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGg9MSkpICsNCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCIjOTVhNWE2IiwgIiMyYzNlNTAiKSkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikgKw0KICBmYWNldF93cmFwKHZhcnMoQ29uZGl0aW9uMyksIHN0cmlwLnBvc2l0aW9uID0gImxlZnQiLCBuY29sID0gMSwgc2NhbGVzID0gImZyZWVfeSIpKw0KICB0aGVtZShzdHJpcC50ZXh0LnkubGVmdCA9IGVsZW1lbnRfYmxhbmsoKSwgI2VsZW1lbnRfdGV4dChhbmdsZSA9IDAsIGhqdXN0ID0gMCksDQogICAgICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuc3BhY2luZyA9IHVuaXQoMCwiY20iKSwNCiAgICAgICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2JsYW5rKCkpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHBhc3RlKCJuID0iLCBUb3RhbCkpLCB2anVzdCA9IC0xLCBoanVzdCA9IC0wLjUsIHNpemUgPSAzKQ0KYGBgDQoNCk5vdGUgdGhhdCB0aGUgc2NhbGUgdmFyaWVzIGluIEZpZ3VyZSBcQHJlZihmaWc6QWxjaGVteVIpLS1cQHJlZihmaWc6cGF5bWFzdGVyKS4NCg0KIyMjIEVmZmVjdHMgb24gZmFpbHVyZSBhbmQgbWlub3Igc3VjY2Vzcw0KDQpgYGB7ciBwcm9wTWlub3JTdWNzLCBmaWcuaGVpZ2h0ID0gMywgZmlnLndpZHRoID0gNywgZmlnLmNhcD0iUHJvcG9ydGlvbiBvZiBtaW5vciBzdWNjZXNzIChGaW5lIFZlbHZldCwgSnVzdGF1Y29ycHMgb3IgV2Fpc3Rjb2F0KSB1bmRlciBkaWZmZXJlbnQgZXhwZXJpbWVudGFsIGNvbmRpdGlvbnMifQ0KI3Byb3BvcnRpb24gbWlub3JzdWNjZXNzDQpSU1QgPC0gUm9iZVN1bW1hcnlUYWJsZQ0KI3JlbW92ZSByb3cgZm9yIHRvdGFscw0KUlNUIDwtIFJTVCB8PiANCiAgZmlsdGVyKEJhdGNoIDwgMjcpIHw+IA0KICBtdXRhdGUoQ29uZGl0aW9uID0gYXMubnVtZXJpYyhDb25kaXRpb24pKQ0KUlNUIDwtIFJTVCB8PiANCiAgbXV0YXRlKE1pbm9yID0gKEZpbmVWZWx2ZXQrSnVzdGF1Y29ycHMrV2Fpc3Rjb2F0KSkgDQpSU1QgPC0gUlNUIHw+IA0KICBtdXRhdGUocHJvcE1pbm9yID0gKEZpbmVWZWx2ZXQrSnVzdGF1Y29ycHMrV2Fpc3Rjb2F0KS9Ub3RhbCkgDQpSU1QgPC0gUlNUIHw+IGxlZnRfam9pbihEZXNpZ24gfD4gDQogICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdChDb25kaXRpb24sIENvbmRpdGlvbjIpLCBieT0iQ29uZGl0aW9uIikNClJTVCA8LSBjYmluZChSU1QsIA0KICAgICAgTWlub3JQcm9wPWJpbm9tLmNvbmZpbnQoUlNUJE1pbm9yLCBuID0gUlNUJFRvdGFsLCBtZXRob2RzID0gIndpbHNvbiIpKQ0KDQojY29tYmluZSBiYXRjaGVzDQpSU1QyIDwtIFJTVCB8PiANCiAgZ3JvdXBfYnkoQ29uZGl0aW9uMikgfD4gDQogIHN1bW1hcmlzZSgNCiAgICBDb25kaXRpb24gPSBtZWFuKENvbmRpdGlvbiksDQogICAgRmFpbHVyZSA9IHN1bShGYWlsdXJlKSwNCiAgICBGaW5lVmVsdmV0ID0gc3VtKEZpbmVWZWx2ZXQpLA0KICAgIEp1c3RhdWNvcnBzID0gc3VtKEp1c3RhdWNvcnBzKSwNCiAgICBSb2JlID0gc3VtKFJvYmUpLA0KICAgIFdhaXN0Y29hdCA9IHN1bShXYWlzdGNvYXQpLA0KICAgIFRvdGFsID0gc3VtKFRvdGFsKSwNCiAgICBNaW5vciA9IHN1bShNaW5vcikNCiAgKSB8PiANCiAgbXV0YXRlKHByb3BNaW5vciA9IChGaW5lVmVsdmV0K0p1c3RhdWNvcnBzK1dhaXN0Y29hdCkvVG90YWwsDQogICAgICAgICBwcm9wUm9iZSA9IFJvYmUvVG90YWwsDQogICAgICAgICBwcm9wRmFpbHVyZSA9IEZhaWx1cmUvVG90YWwsDQogICAgICAgICBwcm9wSnVzdGF1ID0gSnVzdGF1Y29ycHMvVG90YWwsDQogICAgICAgICBwcm9wVmVsdmV0ID0gRmluZVZlbHZldC9Ub3RhbCwNCiAgICAgICAgIHByb3BXYWlzdCA9IFdhaXN0Y29hdC9Ub3RhbCwNCiAgICAgICAgIHByb3BKdXN0YXVfbWlub3IgPSBKdXN0YXVjb3Jwcy9NaW5vciwNCiAgICAgICAgIHByb3BWZWx2ZXRfbWlub3IgPSBGaW5lVmVsdmV0L01pbm9yLA0KICAgICAgICAgcHJvcFdhaXN0X21pbm9yID0gV2Fpc3Rjb2F0L01pbm9yDQogICAgICAgICApIA0KUlNUMiAgPC0gUlNUMiB8PiANCiAgbXV0YXRlKENvbmRpdGlvbjIgPSBhcy5mYWN0b3IoQ29uZGl0aW9uMikpIHw+IA0KICBtdXRhdGUoQ29uZGl0aW9uMiA9IGZjdF9yZW9yZGVyKENvbmRpdGlvbjIsIHByb3BSb2JlLCAuZnVuID0gbWVhbikpIHw+IA0KICBtdXRhdGUoQ29uZGl0aW9uMiA9IGZjdF9yZXYoQ29uZGl0aW9uMikpDQpSU1QyIDwtIGNiaW5kKFJTVDIsIA0KICAgICAgICAgICAgICBwcm9wTWlub3IgPSBiaW5vbS5jb25maW50KFJTVDIkTWlub3IsIG4gPSBSU1QyJFRvdGFsLCBtZXRob2RzID0gIndpbHNvbiIpKQ0KI292ZXJhbGwgcHJvcG9ydGlvbiBtaW5vciBzdWNjZXNzOg0KcHJvcE1pbm9yT3ZlcmFsbCA8LSBzdW0oUlNUMiRNaW5vcikvc3VtKFJTVDIkVG90YWwpDQpwcm9wTWlub3JPdmVyYWxsMiA8LSBtZWFuKFJTVDIkcHJvcE1pbm9yKQ0KDQpSU1QyIHw+IA0KICBnZ3Bsb3QoYWVzKHkgPSBDb25kaXRpb24yLCB4ID0gcHJvcE1pbm9yKSkgKw0KICB5bGFiKE5VTEwpICsNCiAgeGxhYigiUHJvcG9ydGlvbiBtaW5vciBzdWNjZXNzIikgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBwcm9wTWlub3JPdmVyYWxsLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvdXIgPSAiIzk1YTVhNiIpKw0KICBnZW9tX3BvaW50cmFuZ2UoYWVzKHhtaW4gPSBwcm9wTWlub3IubG93ZXIsIHhtYXggPSBwcm9wTWlub3IudXBwZXIpLCANCiAgICAgICAgICAgICAgICAgIHNpemUgPTAuNSwgbGluZXdpZHRoID0gMC43NSwNCiAgICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGg9MSkpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCAxLCBieSA9IDAuMiksIGxpbWl0cyA9IGMoMCwxKSkNCg0KYGBgDQoNClNvIGZhciB3ZSBoYXZlIG9ubHkgY29uc2lkZXJlZCBSb2Jlcy4gV2Ugd2lsbCBub3cgbG9vayBtb3JlIGNsb3NlbHkgYXQgdGhlIG90aGVyIG91dGNvbWVzOiBmYWlsdXJlIGFuZCBtaW5vciBzdWNjZXNzZXMuDQoNClRoZSBwcm9wb3J0aW9uIG9mIG1pbm9yIHN1Y2Nlc3MgKGp1c3RhdWNvcnBzLCB3YWlzdGNvYXQgYW5kIGZpbmUgdmVsdmV0IHRvZ2V0aGVyKSB3YXMgcmVtYXJrYWJseSBjb25zdGFudCB1bmRlciBhbGwgY29uZGl0aW9ucyAob3ZlcmFsbCBtZWFuID0gMC4zNjEpLCBhbmQgdGh1cyBzZWVtcyBmaXhlZCBhdCBhIHJhdGlvIG9mIGFyb3VuZCAyOjMgKGkuZS4gNDAlIG1pbm9yIHN1Y2Nlc3MsIDYwJSBmYWlsdXJlcyBhbmQgaHVnZSBzdWNjZXNzLCBvciBtYXliZSAzNTo2NSksIHVuYWZmZWN0ZWQgYnkgdGhlIGZhY3RvcnMgdGhhdCBpbmZsdWVuY2UgaHVnZSBzdWNjZXNzIChGaWd1cmUgXEByZWYoZmlnOnByb3BNaW5vclN1Y3MpKS4NCg0KVGhlIHN1cnByaXNpbmcgY29uc2VxdWVuY2UgaXMgdGhlcmVmb3JlIHRoYXQgYWxsIHRoYXQgY2FuIGJlIGF0dGFpbmVkIGJ5IGNoYW5naW5nIHRoZSBjb25kaXRpb25zIGlzIHRvIHNoaWZ0IHRoZSBzaGFyZSBvZiBvdXRjb21lcyAqd2l0aGluKiB0aGVzZSB0d28gY2F0ZWdvcmllcy4NCg0KYGBge3Igb3RoZXJQcm9wLCBmaWcuaGVpZ2h0ID0gMywgZmlnLndpZHRoID0gNywgZmlnLnNob3cgPSAiaG9sZCIsIGZpZy5jYXA9ICJQcm9wb3J0aW9uIG9mIGFsbCBwb3NzaWJsZSBvdXRjb21lczogRmFpbHVyZTsgUm9iZTsgSnVzdGF1Y29ycHM7IEZpbmUgVmVsdmV0OyBXYWlzdGNvYXQuIERhc2hlZCBsaW5lcyBzaG93IHRoZSBtZWFuIGZvciBlYWNoIGl0ZW0uIn0NClJTVDIgPC0gY2JpbmQoUlNUMiwgDQogICAgICAgICAgICAgIHByb3BGYWlsdXJlID0gYmlub20uY29uZmludChSU1QyJEZhaWx1cmUsIG4gPSBSU1QyJFRvdGFsLCBtZXRob2RzID0gIndpbHNvbiIpKQ0KUlNUMiA8LSBjYmluZChSU1QyLCANCiAgICAgICAgICAgICAgcHJvcFJvYmUgPSBiaW5vbS5jb25maW50KFJTVDIkUm9iZSwgbiA9IFJTVDIkVG90YWwsIG1ldGhvZHMgPSAid2lsc29uIikpDQpSU1QyIDwtIGNiaW5kKFJTVDIsIA0KICAgICAgICAgICAgICBwcm9wSnVzdGF1ID0gYmlub20uY29uZmludChSU1QyJEp1c3RhdWNvcnBzLCBuID0gUlNUMiRUb3RhbCwgbWV0aG9kcyA9ICJ3aWxzb24iKSkNClJTVDIgPC0gY2JpbmQoUlNUMiwgDQogICAgICAgICAgICAgIHByb3BWZWx2ZXQgPSBiaW5vbS5jb25maW50KFJTVDIkRmluZVZlbHZldCwgbiA9IFJTVDIkVG90YWwsIG1ldGhvZHMgPSAid2lsc29uIikpDQpSU1QyIDwtIGNiaW5kKFJTVDIsIA0KICAgICAgICAgICAgICBwcm9wV2Fpc3QgPSBiaW5vbS5jb25maW50KFJTVDIkV2Fpc3Rjb2F0LCBuID0gUlNUMiRUb3RhbCwgbWV0aG9kcyA9ICJ3aWxzb24iKSkNClJTVDIgPC0gY2JpbmQoUlNUMiwgDQogICAgICAgICAgICAgIHByb3BKdXN0YXVfbWlub3IgPSBiaW5vbS5jb25maW50KFJTVDIkSnVzdGF1Y29ycHMsIG4gPSBSU1QyJE1pbm9yLCBtZXRob2RzID0gIndpbHNvbiIpKQ0KUlNUMiA8LSBjYmluZChSU1QyLCANCiAgICAgICAgICAgICAgcHJvcFZlbHZldF9taW5vciA9IGJpbm9tLmNvbmZpbnQoUlNUMiRGaW5lVmVsdmV0LCBuID0gUlNUMiRNaW5vciwgbWV0aG9kcyA9ICJ3aWxzb24iKSkNClJTVDIgPC0gY2JpbmQoUlNUMiwgDQogICAgICAgICAgICAgIHByb3BXYWlzdF9taW5vciA9IGJpbm9tLmNvbmZpbnQoUlNUMiRXYWlzdGNvYXQsIG4gPSBSU1QyJE1pbm9yLCBtZXRob2RzID0gIndpbHNvbiIpKQ0KcmFuazExIDwtIGMoNiw3LDksMTEsMTIpDQpSU1QyIDwtIFJTVDIgfD4gDQogIG11dGF0ZShBbGNoZW15UmFuayA9IGlmZWxzZShDb25kaXRpb24gJWluJSByYW5rMTEsIDExLCAyMCkpDQoNCnByb3BGYWlsdXJlT3ZlcmFsbCA8LSBzdW0oUlNUMiRGYWlsdXJlKS9zdW0oUlNUMiRUb3RhbCkNClJTVDIgfD4gDQogIGdncGxvdChhZXMoeSA9IENvbmRpdGlvbjIsIHggPSBwcm9wRmFpbHVyZS5tZWFuKSkgKw0KICB5bGFiKE5VTEwpICsNCiAgeGxhYigiUHJvcG9ydGlvbiBGYWlsdXJlIikgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBwcm9wRmFpbHVyZU92ZXJhbGwsIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG91ciA9ICIjOTVhNWE2IikrDQogIGdlb21fcG9pbnRyYW5nZShhZXMoeG1pbiA9IHByb3BGYWlsdXJlLmxvd2VyLCB4bWF4ID0gcHJvcEZhaWx1cmUudXBwZXIpLCANCiAgICAgICAgICAgICAgICAgIHNpemUgPTAuNSwgbGluZXdpZHRoID0gMC43NSkrDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMCwgMSwgYnkgPSAwLjIpLCBsaW1pdHMgPSBjKDAsMSkpDQoNCnByb3BSb2JlT3ZlcmFsbCA8LSBzdW0oUlNUMiRSb2JlKS9zdW0oUlNUMiRUb3RhbCkNClJTVDIgfD4gDQogIGdncGxvdChhZXMoeSA9IENvbmRpdGlvbjIsIHggPSBwcm9wUm9iZS5tZWFuKSkgKw0KICB5bGFiKE5VTEwpICsNCiAgeGxhYigiUHJvcG9ydGlvbiBBZGVwdCdzIFJvYmUiKSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IHByb3BSb2JlT3ZlcmFsbCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3VyID0gIiM5NWE1YTYiKSsNCiAgZ2VvbV9wb2ludHJhbmdlKGFlcyh4bWluID0gcHJvcFJvYmUubG93ZXIsIHhtYXggPSBwcm9wUm9iZS51cHBlciksIA0KICAgICAgICAgICAgICAgICAgc2l6ZSA9MC41LCBsaW5ld2lkdGggPSAwLjc1KSsNCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCAxLCBieSA9IDAuMiksIGxpbWl0cyA9IGMoMCwxKSkNCg0KcHJvcEp1c3RhdU92ZXJhbGwgPC0gc3VtKFJTVDIkSnVzdGF1Y29ycHMpL3N1bShSU1QyJFRvdGFsKQ0KDQpwcm9wSnVzdGF1UjExIDwtIFJTVDIgfD4gIA0KICBmaWx0ZXIoQWxjaGVteVJhbmsgPT0gMTEpIHw+IA0KICBzdW1tYXJpc2Uob3V0ID0gc3VtKEp1c3RhdWNvcnBzKS9zdW0oVG90YWwpKSB8PiANCiAgcHVsbChvdXQpDQpwcm9wSnVzdGF1UjIwIDwtIFJTVDIgfD4gIA0KICBmaWx0ZXIoQWxjaGVteVJhbmsgPT0gMjApIHw+IA0KICBzdW1tYXJpc2Uob3V0ID0gc3VtKEp1c3RhdWNvcnBzKS9zdW0oVG90YWwpKSB8PiANCiAgcHVsbChvdXQpDQoNCkp1c3RhdVByb3BBbGNoZW15IDwtIFJTVDIgfD4NCiAgZ3JvdXBfYnkoQWxjaGVteVJhbmspIHw+DQogIHN1bW1hcmlzZShKdXN0YXVjb3JwcyA9IHN1bShKdXN0YXVjb3JwcyksIFRvdGFsID0gc3VtKFRvdGFsKSkNCg0KKEp1c3RhdUFsY2hSZXMgPC0gDQogICAgYmlub20ud2lsc29uKEp1c3RhdVByb3BBbGNoZW15JEp1c3RhdWNvcnBzLCBKdXN0YXVQcm9wQWxjaGVteSRUb3RhbCkpDQpKdXN0YXVBbGNoUmVzJEdyb3VwIDwtIGFzX2ZhY3RvcihjKCJyMTEiLCAicjIwIikpDQojdGVzdCBpZiBlcXVhbCBwcm9wb3J0aW9ucw0KKEp1c3RhdUFsY2hSZXNUZXN0IDwtIA0KICAgIHByb3AudGVzdCh4ID0gSnVzdGF1QWxjaFJlcyR4LCBKdXN0YXVBbGNoUmVzJG4sIGFsdGVybmF0aXZlID0gInR3by5zaWRlZCIpKQ0KDQpSU1QyIHw+IA0KICBnZ3Bsb3QoYWVzKHkgPSBDb25kaXRpb24yLCB4ID0gcHJvcEp1c3RhdS5tZWFuLCANCiAgICAgICAgICAgICBjb2xvdXIgPSBhcy5mYWN0b3IoQWxjaGVteVJhbmspKSkgKw0KICB5bGFiKE5VTEwpICsNCiAgeGxhYigiUHJvcG9ydGlvbiBBZG1pcmFsIEp1c3RhdWNvcnBzIikgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBwcm9wSnVzdGF1T3ZlcmFsbCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgDQogICAgICAgICAgICAgY29sb3VyID0gIiM5NWE1YTYiKSsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gcHJvcEp1c3RhdVIxMSwgbGluZXR5cGUgPSAiZGFzaGVkIiwgDQogICAgICAgICAgICAgY29sb3VyID0gIiMzNzdlYjgiKSsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gcHJvcEp1c3RhdVIyMCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgDQogICAgICAgICAgICAgY29sb3VyID0gIiNCNTFGMkUiKSsNCiAgZ2VvbV9wb2ludHJhbmdlKGFlcyh4bWluID0gcHJvcEp1c3RhdS5sb3dlciwgeG1heCA9IHByb3BKdXN0YXUudXBwZXIpLCANCiAgICAgICAgICAgICAgICAgIHNpemUgPTAuNSwgbGluZXdpZHRoID0gMC43NSkrDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMCwgMSwgYnkgPSAwLjIpLCBsaW1pdHMgPSBjKDAsMSkpKw0KICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoIiMzNzdlYjgiLCAiI0I1MUYyRSIpKSsNCiAgdGhlbWUoIA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC45NSwwLjk1KSwNCiAgICBsZWdlbmQuanVzdGlmaWNhdGlvbiA9IGMoMSwxKSwNCiAgKSsNCiAgbGFicyhjb2xvdXIgPSAiQWxjaGVteSByYW5rIikNCiANCg0KcHJvcFZlbHZldE92ZXJhbGwgPC0gc3VtKFJTVDIkRmluZVZlbHZldCkvc3VtKFJTVDIkVG90YWwpDQpSU1QyIHw+IA0KICBnZ3Bsb3QoYWVzKHkgPSBDb25kaXRpb24yLCB4ID0gcHJvcFZlbHZldC5tZWFuKSkgKw0KICB5bGFiKE5VTEwpICsNCiAgeGxhYigiUHJvcG9ydGlvbiBGaW5lIFZlbHZldCIpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gcHJvcFZlbHZldE92ZXJhbGwsIGxpbmV0eXBlID0gImRhc2hlZCIsIA0KICAgICAgICAgICAgIGNvbG91ciA9ICIjOTVhNWE2IikrDQogIGdlb21fcG9pbnRyYW5nZShhZXMoeG1pbiA9IHByb3BWZWx2ZXQubG93ZXIsIHhtYXggPSBwcm9wVmVsdmV0LnVwcGVyKSwgDQogICAgICAgICAgICAgICAgICBzaXplID0wLjUsIGxpbmV3aWR0aCA9IDAuNzUpKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDEsIGJ5ID0gMC4yKSwgbGltaXRzID0gYygwLDEpKQ0KDQpwcm9wV2Fpc3RPdmVyYWxsIDwtIHN1bShSU1QyJFdhaXN0Y29hdCkvc3VtKFJTVDIkVG90YWwpDQpSU1QyIHw+IA0KICBnZ3Bsb3QoYWVzKHkgPSBDb25kaXRpb24yLCB4ID0gcHJvcFdhaXN0Lm1lYW4pKSArDQogIHlsYWIoTlVMTCkgKw0KICB4bGFiKCJQcm9wb3J0aW9uIFdhaXN0Y29hdCIpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gcHJvcFdhaXN0T3ZlcmFsbCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgDQogICAgICAgICAgICAgY29sb3VyID0gIiM5NWE1YTYiKSsNCiAgZ2VvbV9wb2ludHJhbmdlKGFlcyh4bWluID0gcHJvcFdhaXN0Lmxvd2VyLCB4bWF4ID0gcHJvcFdhaXN0LnVwcGVyKSwgDQogICAgICAgICAgICAgICAgICBzaXplID0wLjUsIGxpbmV3aWR0aCA9IDAuNzUpKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDEsIGJ5ID0gMC4yKSwgbGltaXRzID0gYygwLDEpKQ0KDQpgYGANCg0KRmlndXJlIFxAcmVmKGZpZzpvdGhlclByb3ApIHNob3dzIHRoZSBwcm9wb3J0aW9uIG9mIGFsbCBwb3NzaWJsZSBvdXRjb21lcywgaW5jbHVkaW5nIFJvYmVzIGFnYWluIGZvciBlYXNlIG9mIGNvbXBhcmlzb24uDQoNClNpbmNlIHByb3BvcnRpb24gb2YgbWlub3Igc3VjY2VzcyB3YXMgY29uc3RhbnQsIHRoZSBwcm9wb3J0aW9uIG9mIGZhaWx1cmUgKEZpZ3VyZSBcQHJlZihmaWc6b3RoZXJQcm9wKSwgdXBwZXIgcGFuZWwpIHdhcyBpbiBjb25zZXF1ZW5jZSBsYXJnZWx5IGFuIGludmVyc2UgbWlycm9yIG9mIHRoZSBwcm9wb3J0aW9uIG9mIFJvYmVzOiBDb25kaXRpb25zIHRoYXQgaW5jcmVhc2VkIHRoZSBwcm9wb3J0aW9uIG9mIFJvYmVzIGxvd2VyZWQgdGhlIHByb3BvcnRpb24gb2YgZmFpbHVyZXMgYW5kIHZpY2UgdmVyc2EuIEFzIHdpdGggUm9iZXMsIHdlIGNhbiByZWFkaWx5IHNlZSB0aHJlZSBjbHVzdGVyczogQWR2aXNvciBoYXMgdGhlIGxvd2VzdCBhbW91bnQgb2YgZmFpbHVyZXMsIEhSRSBhIGJpdCBtb3JlLCBhbmQgY29uc2lkZXJhYmx5IGxvd2VyIHdpdGhvdXQgSFJFLCB3aXRoIGFkZXB0IGxlc3MgY2xlYXIgKEZpZ3VyZSBcQHJlZihmaWc6b3RoZXJQcm9wKSkuDQoNClRoZSBwcm9wb3J0aW9uIG9mIHRoZSB2YXJpb3VzIG1pbm9yIHN1Y2Nlc3NlcyBhcHBlYXJlZCB0byBiZSB1bmFmZmVjdGVkIGJ5IGNoYW5naW5nIHRoZSBjb25kaXRpb25zLCBleGNlcHQgYW4gZWZmZWN0IG9mIGFsY2hlbXkgcmFuayBvbiBKdXN0YXVjb3JwcywgZGlzY3Vzc2VkIGJlbG93Lg0KDQpgYGB7ciB3aXRoaW5NaW5vciwgZmlnLmhlaWdodCA9IDMsIGZpZy53aWR0aD0gNywgZmlnLnNob3cgPSAiaG9sZCIsIGZpZy5jYXA9IlByb3BvcnRpb24gb2YgdGhlIHRocmVlIHBvc3NpYmxlIG91dGNvbWVzIG9mIG1pbm9yIHN1Y2Nlc3MgdW5kZXIgZGlmZmVyZW50IGNvbmRpdGlvbnMuIERhc2hlZCBsaW5lcyBzaG93cyB0aGUgbWVhbiJ9DQojcHJvcG9ydGlvbnMgaW5uZW4gbWlub3INCiNwcm9wLnRlc3QNCnByb3BKdXN0YXVPdmVyYWxsX01pbm9yIDwtIHN1bShSU1QyJEp1c3RhdWNvcnBzKS8oc3VtKFJTVDIkSnVzdGF1Y29ycHMpK3N1bShSU1QyJFdhaXN0Y29hdCkrc3VtKFJTVCRGaW5lVmVsdmV0KSkNCnByb3BKdXN0YXVSMTFfTWlub3IgPC0gUlNUMiB8PiAgDQogIGZpbHRlcihBbGNoZW15UmFuayA9PSAxMSkgfD4gDQogIHN1bW1hcmlzZShvdXQgPSBzdW0oSnVzdGF1Y29ycHMpL3N1bShNaW5vcikpIHw+IA0KICBwdWxsKG91dCkNCnByb3BKdXN0YXVSMjBfTWlub3IgPC0gUlNUMiB8PiAgZmlsdGVyKEFsY2hlbXlSYW5rID09IDIwKSB8PiANCiAgc3VtbWFyaXNlKG91dCA9IHN1bShKdXN0YXVjb3Jwcykvc3VtKE1pbm9yKSkgfD4gDQogIHB1bGwob3V0KQ0KUlNUMiB8PiANCiAgZ2dwbG90KGFlcyh5ID0gQ29uZGl0aW9uMiwgeCA9IHByb3BKdXN0YXVfbWlub3IubWVhbiwgDQogICAgICAgICAgICAgY29sb3VyID0gYXMuZmFjdG9yKEFsY2hlbXlSYW5rKSkpICsNCiAgeWxhYihOVUxMKSArDQogIHhsYWIoIlByb3BvcnRpb24gSnVzdGF1Y29ycHMgYW1vbmcgbWlub3Igc3VjY2Vzc2VzIikgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBwcm9wSnVzdGF1T3ZlcmFsbF9NaW5vciwgbGluZXR5cGUgPSAiZGFzaGVkIiwgDQogICAgICAgICAgICAgY29sb3VyID0gIiM5NWE1YTYiKSsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gcHJvcEp1c3RhdVIxMV9NaW5vciwgbGluZXR5cGUgPSAiZGFzaGVkIiwgDQogICAgICAgICAgICAgY29sb3VyID0gIiMzNzdlYjgiKSsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gcHJvcEp1c3RhdVIyMF9NaW5vciwgbGluZXR5cGUgPSAiZGFzaGVkIiwgDQogICAgICAgICAgICAgY29sb3VyID0gIiNCNTFGMkUiKSsNCiAgZ2VvbV9wb2ludHJhbmdlKGFlcyh4bWluID0gcHJvcEp1c3RhdV9taW5vci5sb3dlciwgeG1heCA9IHByb3BKdXN0YXVfbWlub3IudXBwZXIpLCANCiAgICAgICAgICAgICAgICAgIHNpemUgPTAuNSwgbGluZXdpZHRoID0gMC43NSkrDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMCwgMSwgYnkgPSAwLjIpLCBsaW1pdHMgPSBjKDAsMSkpKw0KICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoIiMzNzdlYjgiLCAiI0I1MUYyRSIpKSsNCiAgdGhlbWUoIA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC45NSwwLjk1KSwNCiAgICBsZWdlbmQuanVzdGlmaWNhdGlvbiA9IGMoMSwxKSwNCiAgKSsNCiAgbGFicyhjb2xvdXIgPSAiQWxjaGVteSByYW5rIikNCg0KDQpwcm9wVmVsdmV0T3ZlcmFsbF9NaW5vciA8LSBzdW0oUlNUMiRGaW5lVmVsdmV0KS8oc3VtKFJTVDIkSnVzdGF1Y29ycHMpK3N1bShSU1QyJFdhaXN0Y29hdCkrc3VtKFJTVCRGaW5lVmVsdmV0KSkNCnByb3BWZWx2ZXRSMTFfTWlub3IgPC0gUlNUMiB8PiAgDQogIGZpbHRlcihBbGNoZW15UmFuayA9PSAxMSkgfD4gDQogIHN1bW1hcmlzZShvdXQgPSBzdW0oRmluZVZlbHZldCkvc3VtKE1pbm9yKSkgfD4gDQogIHB1bGwob3V0KQ0KcHJvcFZlbHZldFIyMF9NaW5vciA8LSBSU1QyIHw+ICANCiAgZmlsdGVyKEFsY2hlbXlSYW5rID09IDIwKSB8PiANCiAgc3VtbWFyaXNlKG91dCA9IHN1bShGaW5lVmVsdmV0KS9zdW0oTWlub3IpKSB8PiANCiAgcHVsbChvdXQpDQoNClJTVDIgfD4gDQogIGdncGxvdChhZXMoeSA9IENvbmRpdGlvbjIsIHggPSBwcm9wVmVsdmV0X21pbm9yLm1lYW4sIA0KICAgICAgICAgICAgIGNvbG91ciA9IGFzLmZhY3RvcihBbGNoZW15UmFuaykpKSArDQogIHlsYWIoTlVMTCkgKw0KICB4bGFiKCJQcm9wb3J0aW9uIEZpbmUgVmVsdmV0IGFtb25nIG1pbm9yIHN1Y2Nlc3NlcyIpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gcHJvcFZlbHZldE92ZXJhbGxfTWlub3IsIGxpbmV0eXBlID0gImRhc2hlZCIsIA0KICAgICAgICAgICAgIGNvbG91ciA9ICIjOTVhNWE2IikrDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IHByb3BWZWx2ZXRSMTFfTWlub3IsIGxpbmV0eXBlID0gImRhc2hlZCIsIA0KICAgICAgICAgICAgIGNvbG91ciA9ICIjMzc3ZWI4IikrDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IHByb3BWZWx2ZXRSMjBfTWlub3IsIGxpbmV0eXBlID0gImRhc2hlZCIsIA0KICAgICAgICAgICAgIGNvbG91ciA9ICIjQjUxRjJFIikrDQogIGdlb21fcG9pbnRyYW5nZShhZXMoeG1pbiA9IHByb3BWZWx2ZXRfbWlub3IubG93ZXIsIHhtYXggPSBwcm9wVmVsdmV0X21pbm9yLnVwcGVyKSwgDQogICAgICAgICAgICAgICAgICBzaXplID0wLjUsIGxpbmV3aWR0aCA9IDAuNzUpKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDEsIGJ5ID0gMC4yKSwgbGltaXRzID0gYygwLDEpKSsNCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCIjMzc3ZWI4IiwgIiNCNTFGMkUiKSkrDQogIHRoZW1lKCANCiAgICBsZWdlbmQucG9zaXRpb24gPSBjKDAuOTUsMC45NSksDQogICAgbGVnZW5kLmp1c3RpZmljYXRpb24gPSBjKDEsMSksDQogICkrDQogIGxhYnMoY29sb3VyID0gIkFsY2hlbXkgcmFuayIpDQoNCnByb3BXYWlzdE92ZXJhbGxfTWlub3IgPC0gDQogIHN1bShSU1QyJFdhaXN0Y29hdCkvKHN1bShSU1QyJEp1c3RhdWNvcnBzKStzdW0oUlNUMiRXYWlzdGNvYXQpK3N1bShSU1QkRmluZVZlbHZldCkpDQpwcm9wV2Fpc3RSMTFfTWlub3IgPC0gUlNUMiB8PiAgDQogIGZpbHRlcihBbGNoZW15UmFuayA9PSAxMSkgfD4gDQogIHN1bW1hcmlzZShvdXQgPSBzdW0oV2Fpc3Rjb2F0KS9zdW0oTWlub3IpKSB8PiANCiAgcHVsbChvdXQpDQpwcm9wV2Fpc3RSMjBfTWlub3IgPC0gDQogIFJTVDIgfD4gIGZpbHRlcihBbGNoZW15UmFuayA9PSAyMCkgfD4gDQogIHN1bW1hcmlzZShvdXQgPSBzdW0oV2Fpc3Rjb2F0KS9zdW0oTWlub3IpKSB8PiANCiAgcHVsbChvdXQpDQpSU1QyIHw+IA0KICBnZ3Bsb3QoYWVzKHkgPSBDb25kaXRpb24yLCB4ID0gcHJvcFdhaXN0X21pbm9yLm1lYW4sIA0KICAgICAgICAgICAgIGNvbG91ciA9IGFzLmZhY3RvcihBbGNoZW15UmFuaykpKSArDQogIHlsYWIoTlVMTCkgKw0KICB4bGFiKCJQcm9wb3J0aW9uIFdhaXN0Y29hdCBhbW9uZyBtaW5vciBzdWNjZXNzZXMiKSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IHByb3BXYWlzdE92ZXJhbGxfTWlub3IsIGxpbmV0eXBlID0gImRhc2hlZCIsIA0KICAgICAgICAgICAgIGNvbG91ciA9ICIjOTVhNWE2IikrDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IHByb3BXYWlzdFIxMV9NaW5vciwgbGluZXR5cGUgPSAiZGFzaGVkIiwgDQogICAgICAgICAgICAgY29sb3VyID0gIiMzNzdlYjgiKSsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gcHJvcFdhaXN0UjIwX01pbm9yLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCANCiAgICAgICAgICAgICBjb2xvdXIgPSAiI0I1MUYyRSIpKw0KICBnZW9tX3BvaW50cmFuZ2UoYWVzKHhtaW4gPSBwcm9wV2Fpc3RfbWlub3IubG93ZXIsIHhtYXggPSBwcm9wV2Fpc3RfbWlub3IudXBwZXIpLCANCiAgICAgICAgICAgICAgICAgIHNpemUgPTAuNSwgbGluZXdpZHRoID0gMC43NSkrDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMCwgMSwgYnkgPSAwLjIpLCBsaW1pdHMgPSBjKDAsMSkpKw0KICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoIiMzNzdlYjgiLCAiI0I1MUYyRSIpKSsNCiAgdGhlbWUoIA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC45NSwwLjk1KSwNCiAgICBsZWdlbmQuanVzdGlmaWNhdGlvbiA9IGMoMSwxKSwNCiAgKSsNCiAgbGFicyhjb2xvdXIgPSAiQWxjaGVteSByYW5rIikNCg0KYGBgDQoNCkZpZ3VyZSBcQHJlZihmaWc6d2l0aGluTWlub3IpIHNob3dzIHRoZSBwcm9wb3J0aW9uIG9mIG91dGNvbWVzIHVuZGVyIGRpZmZlcmVudCBjb25kaXRpb25zIHdoZW4gdGhlIHJlc3VsdCB3YXMgYSBtaW5vciBzdWNjZXNzIChleHByZXNzZWQgYXMgc2hhcmUgb2YgdGhlIHN1bSBvZiBtaW5vciBzdWNjZXNzLCBub3QgdG90YWwgdHJpYWxzKS4NCg0KVGhlcmUgYXJlIDMgZGlmZmVyZW50IG1pbm9yIHN1Y2Nlc3Mgb3V0Y29tZXMgcG9zc2libGUuIEFtb25nIHRoZXNlLCBBZG1pcmFsIEp1c3RhdWNvcnBzIGNhbiBiZSBjb25zaWRlcmVkIGEgaGlnaGVyIHRpZXIgb3V0Y29tZSB0aGFuIEZpbmUgVmVsdmV0IG9yIFdhaXN0Y29hdHMuIElmIHdlIGxvb2sgYXQgdGhlIG91dGNvbWUgd2l0aGluIHRoZSBtaW5vciBzdWNjZXNzIGdyb3VwIHRoZXJlIGFyZSBubyBlZmZlY3RzIG9mIHRoZSBleHBlcmltZW50YWwgY29uZGl0aW9ucyB0aGF0IGRpZCBhZmZlY3QgaHVnZSBzdWNjZXNzOiBKdXN0YXVjb3JwcyBpcyBub3QgYW55IG1vcmUgbGlrZWx5IHdpdGggYWRlcHQgb3IgSFJFIHBvbGljeSBvciBhZHZpc29yIGFjdGl2ZS4gSG93ZXZlciwgdGhlcmUgaXMgbm93IGEgbm90aWNlYWJsZSBlZmZlY3Qgb2YgYWxjaGVteSByYW5rICh3aGljaCBoYWQgbm8gZWZmZWN0IG9uIFJvYmVzIG9yIGZhaWx1cmUpLiBTaWduaWZpY2FudGx5IG1vcmUgSnVzdGF1Y29ycHMgd2FzIHByb2R1Y2VkIGF0IHIyMCB0aGFuIGF0IHIxMSBhbGNoZW15LCB1bmRlciBhbGwgY29uZGl0aW9ucyBtZWFzdXJlZCB3aGVyZSBhbGNoZW15IHJhbmsgY291bGQgYmUgY29udHJhc3RlZCAoRmlndXJlIFxAcmVmKGZpZzp3aXRoaW5NaW5vciksIHVwcGVyIHBhbmVsKS4gT3ZlcmFsbCwgdGhlIHByb3BvcnRpb24gb2YgSnVzdGF1Y29ycHMgYXQgcjExIGFsY2hlbXkgd2FzIGNsZWFybHkgbG93ZXIgdGhhbiBhdCByMjAgKDE1LzU0MCB2cyAxNzgvMTQyMiwgJFxjaGleezJ9JCA9IGByIHJvdW5kKEp1c3RhdUFsY2hSZXNUZXN0JHN0YXRpc3RpYywgMilgICwgZGYgPSAxLCB0d28tc2lkZWQgcCBcPCAwLjAwMDEuDQoNCkluIG90aGVyIHdvcmRzLCBpZiB5b3UgZm9yIHNvbWUgcmVhc29uIHdhbnQgdG8gbWFrZSBBZG1pcmFsIEp1c3RhdWNvcnBzIGl0IGRvZXNuJ3QgaGVscCB0byBoYXZlIGFkZXB0IHRpdGxlLCBvciBIUkUgb3IgYWR2aXNvciBwb3NpdGlvbi4gT25seSBoaWdoZXIgcmFuayBhbGNoZW15IHNraWxsIHdpbGwgaGVscC4gSXQgaXMgYSByYXJlIG91dGNvbWUgYXQgcmFuayAxMSAtLSB0aGUgYmFzZSBwcm9iYWJpbGl0eSBjYW4gYmUgZXN0aW1hdGVkIGF0IDIuOCUuIEF0IHIyMCBpdCBpbmNyZWFzZWQgdG8gMTIuNSUsIGkuZS4gZ2FpbiBhYm91dCAxJSBwZXIgcmFuay4gQXQgcjIwIHRoZSB0aHJlZSBtaW5vciBzdWNjZXNzIHBvc3NpYmlsaXRpZXMgYXJlIGVxdWFsbHkgbGlrZWx5LiBGb3IgdGhlIG90aGVyIHR3byBpdGVtcyB0aGVyZSBkaWQgbm90IHNlZW0gdG8gYmUgYW55IGVmZmVjdHMgYXBhcnQgZnJvbSBib3RoIHNpbXBseSBkZWNyZWFzaW5nIGEgbGl0dGxlIGluIGZyZXF1ZW5jeSBhdCByMjAgaW4gY29uc2VxdWVuY2Ugb2YgaW5jcmVhc2VkIEp1c3RhdWNvcnBzIChGaWd1cmUgXEByZWYoZmlnOndpdGhpbk1pbm9yKSwgdHdvIGxvd2VyIHBhbmVscykuDQoNCmBgYHtyIGZpeGVkc2NhdHRlciwgIGZpZy5zaG93ID0gImhvbGQiLCBmaWcuY2FwPSAiU2NhdHRlcnBsb3Qgb2YgcHJvcG9ydGlvbiByb2JlIHZzLiBwcm9wb3J0aW9uIGZhaWx1cmVzIHBlciBleHBlcmltZW50YWwgYmF0Y2ggKHVwcGVyKSBhbmQgY29uZGl0aW9uIChsb3dlcikuIERvdHRlZCBsaW5lIHNob3dzIGEgc2l0dWF0aW9uIHdoZXJlIHRoZSBzdW0gb2Ygcm9iZXMgYW5kIGZhaWx1cmVzIGhhdmUgYSBmaXhlZCBzaGFyZSBvZiA2NSUgb2YgdGhlIHRvdGFsICh5ID0gMC42NS14KS4gVGhlIHJlZCBsaW5lIGlzIHRoZSBhY3R1YWwgcmVncmVzc2lvbiJ9DQoNCiNwZXIgYmF0Y2g6DQpSU1QgfD4gDQogIGdncGxvdChhZXMoeSA9IEZhaWx1cmUvVG90YWwsIHggPSBSb2JlL1RvdGFsKSkgKw0KICBnZW9tX3NlZ21lbnQoYWVzKHggPSAwLCB5ID0gMC42NSwgeGVuZCA9IDAuNjUsIHllbmQgPSAwKSwNCiAgICAgICAgICAgICAgIGNvbG91ciA9ICIjOTVhNWE2IiwgDQogICAgICAgICAgICAgICBsaW5ldHlwZSA9ImRhc2hlZCIsIA0KICAgICAgICAgICAgICAgbGluZXdpZHRoID0gMSkrDQogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDAuNTcsIHkgPSAwLjIxLCANCiAgICAgICAgICAgbGFiZWwgPSJGaXhlZCA2NSUgXG55ID0gMC42NSDiiJIgeCIsDQogICAgICAgICAgIGNvbG91ciA9ICIjOTVhNWE2IikgKw0KICB5bGltKDAsMC43KSArDQogIHhsaW0oMCwwLjcpICsNCiAgZ2dwbWlzYzo6c3RhdF9tYV9saW5lKHNlID0gRkFMU0UsIGNvbG91ciA9ICIjQjUxRjJFIikgKw0KICBnZ3BtaXNjOjpzdGF0X21hX2VxKG1hcHBpbmcgPSB1c2VfbGFiZWwoYygiZXEiLCAiUjIiKSksIA0KICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9ICIjQjUxRjJFIiwgbGFiZWwueCA9IDAuMTUsIGxhYmVsLnkgPSAwLjkpICsNCiAgZ2VvbV9wb2ludChzaXplPSAzLCBzaGFwZSA9IDIxLCBmaWxsID0gImJsYWNrIiwgY29sb3VyID0gIndoaXRlIikNCiNwZXIgY29uZGl0aW9uIChtb3JlIHByZWNpc2UsIGJ1dCBmZXdlciBkYXRhIHBvaW50cyk6DQpSU1QyIHw+IA0KICBnZ3Bsb3QoYWVzKHkgPSBGYWlsdXJlL1RvdGFsLCB4ID0gUm9iZS9Ub3RhbCkpICsNCiAgZ2VvbV9zZWdtZW50KGFlcyh4ID0gMCwgeSA9IDAuNjUsIHhlbmQgPSAwLjY1LCB5ZW5kID0gMCksDQogICAgICAgICAgICAgICBjb2xvdXIgPSAiIzk1YTVhNiIsIA0KICAgICAgICAgICAgICAgbGluZXR5cGUgPSJkYXNoZWQiLCANCiAgICAgICAgICAgICAgIGxpbmV3aWR0aCA9IDEpKw0KICBhbm5vdGF0ZSgidGV4dCIsIHggPSAwLjU3LCB5ID0gMC4yMSwgDQogICAgICAgICAgIGxhYmVsID0iRml4ZWQgNjUlIFxueSA9IDAuNjUg4oiSIHgiLA0KICAgICAgICAgICBjb2xvdXIgPSAiIzk1YTVhNiIpICsNCiAgeWxpbSgwLDAuNykgKw0KICB4bGltKDAsMC43KSArDQogIGdncG1pc2M6OnN0YXRfbWFfbGluZShzZSA9IEZBTFNFLCBjb2xvdXIgPSAiI0I1MUYyRSIpICsNCiAgZ2dwbWlzYzo6c3RhdF9tYV9lcShtYXBwaW5nID0gdXNlX2xhYmVsKGMoImVxIiwgIlIyIikpLCANCiAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSAiI0I1MUYyRSIsIGxhYmVsLnggPSAwLjE1LCBsYWJlbC55ID0gMC45KSArDQogIGdlb21fcG9pbnQoc2l6ZT0gMywgc2hhcGUgPSAyMSwgZmlsbCA9ICJibGFjayIsIGNvbG91ciA9ICJ3aGl0ZSIpDQoNCmNvci50ZXN0KFJTVCRGYWlsdXJlL1JTVCRUb3RhbCwgUlNUJFJvYmUvUlNUJFRvdGFsKQ0KY29yLnRlc3QoUlNUMiRGYWlsdXJlL1JTVDIkVG90YWwsIFJTVDIkUm9iZS9SU1QyJFRvdGFsKQ0KcHBjb3I6OnBjb3IudGVzdChSU1QkUm9iZSwgUlNUJEZhaWx1cmUsIFJTVCRUb3RhbCkNCnBwY29yOjpwY29yLnRlc3QoUlNUMiRSb2JlLCBSU1QyJEZhaWx1cmUsIFJTVDIkVG90YWwpDQpgYGANCg0KRmFpbHVyZSBhbmQgcm9iZXMgd2VyZSB2ZXJ5IHN0cm9uZ2x5IG5lZ2F0aXZlbHkgcmVsYXRlZCwgaW4gYSB3YXkgY29uc2lzdGVudCB3aXRoIGEgY29tbW9uIHNoYXJlIGZpeGVkIGF0IDYwLTY1JSBvZiB0aGUgb3V0Y29tZXMgKEZpZ3VyZSBcQHJlZihmaWc6Zml4ZWRzY2F0dGVyKSkuIEluIHRoZSBmaWd1cmUgSSB1c2VkIGEgbW9kZWwgSUkgbWFqb3IgYXhpcyByZWdyZXNzaW9uIGluc3RlYWQgb2Ygb3JkaW5hcnkgbGVhc3Qgc3F1YXJlcywgYmVjYXVzZSB3ZSBkbyBub3Qgd2FudCB0byBwcmVkaWN0IHkgZnJvbSB4IGJ1dCByYXRoZXIgZGVzY3JpYmUgdGhlIHNsb3BlIG9mIHRoZSByZWxhdGlvbnNoaXAsIGFuZCBib3RoIHZhcmlhYmxlcyBhcmUgc3ViamVjdCB0byByYW5kb20gdmFyaWF0aW9uLlteMV0NCg0KW14xXTogT2YgY291cnNlLCB0aGUgaGlnaCBuZWdhdGl2ZSBjb3JyZWxhdGlvbiBzZWVuIGluIEZpZ3VyZSBcQHJlZihmaWc6Zml4ZWRzY2F0dGVyKSBpcyBtZWFuaW5nbGVzcyBpbiBpdHNlbGYgYmVjYXVzZSBpdCBpcyBwYXJ0bHkgZHVlIHRvIHRoZSBzYW1lIHRvdGFsIG51bWJlciBvZiB0cmlhbHMgYmVpbmcgdXNlZCB0byBjYWxjdWxhdGUgYm90aCBwcm9wb3J0aW9ucywgYW5kIHRoZSB2YXJpYWJsZXMgYXJlIG5vdCBmcmVlIHRvIHZhcnkgaW5kZXBlbmRlbnRseSAtLSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHBhcnRzIG9mIGEgd2hvbGUgaXMgaW5oZXJlbnRseSBzcHVyaW91cy4gSG93ZXZlciwgdGhpcyBkb2VzIG5vdCBhY2NvdW50IGZvciB0aGUgd2hvbGUgcmVsYXRpb25zaGlwIHNpbmNlIHRoZSBvdGhlciBjb3JyZWxhdGlvbnMgYmV0d2VlbiB0aGUgcHJvcG9ydGlvbnMgd2VyZSBtdWNoIHdlYWtlcihGaWd1cmUgXEByZWYoZmlnOmNvcnJtYXRyaXgpKSwgYW5kIHRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIGZhaWx1cmVzIGFuZCByb2JlcyB3aGlsZSBjb250cm9sbGluZyBmb3IgdG90YWxzIGlzIHN0aWxsIHN0cm9uZzogJHJfe3BhcnRpYWx9JCA9IC0wLjkxLCBuID0gMTQsIHAgXDwgMC4wMDAxLg0KDQpJbiBmYWN0IGl0IGlzIGluZXZpdGFibGUgdG8gYmUgc3VjaCBhIHN0cm9uZyBuZWdhdGl2ZSByZWxhdGlvbnNoaXAgaWYgdGhlIHN1bSBvZiBvdXRjb21lcyB0aGF0IGlzIG1pbm9yIHN1Y2Nlc3MgKEZpZ3VyZSBcQHJlZihmaWc6cHJvcE1pbm9yU3VjcykpIGlzIGZpeGVkLCBsZWF2aW5nIHJvYmUgYSBjb25zdGFudCBwZXJjZW50YWdlIHRvIHNoYXJlIHdpdGggZmFpbHVyZSwgaXJyZXNwZWN0aXZlIG9mIGV4cGVyaW1lbnRhbCBjb25kaXRpb25zLiBDaGFuZ2luZyB0aGUgY29uZGl0aW9ucyB3aWxsIG1lcmVseSBzbGlkZSB0aGUgb3V0Y29tZSBwcm9wb3J0aW9ucyB1cCBhbmQgZG93biBhbG9uZyB0aGUgbGluZSBpbiBGaWd1cmUgXEByZWYoZmlnOmZpeGVkc2NhdHRlcikuDQoNCk1vcmVvdmVyLCBpbnNwZWN0aW9uIG9mIGEgY29ycmVsYXRpb24gbWF0cml4IGJldHdlZW4gYWxsIHRoZSBmaXZlIG91dGNvbWVzIChGaWd1cmUgXEByZWYoZmlnOmNvcnJtYXRyaXgpKSBzaG93IHRoYXQgaXQgaXMgb25seSB0aGUgcHJvcG9ydGlvbiBvZiByb2JlcyB0aGF0IGlzIHN0cm9uZ2x5IHJlbGF0ZWQgdG8gZmFpbHVyZS4gUHJvcG9ydGlvbiBqdXN0YXVjb3JwcyBpcyBuZWdhdGl2ZWx5IHJlbGF0ZWQgdG8gZmluZSB2ZWx2ZXQgYW5kIHdhaXN0Y29hdCBidXQgbGVzcyBzbywgYXMgY2FuIGJlIGV4cGVjdGVkIGJlY2F1c2UgdGhlcmUgYXJlIHRocmVlIG91dGNvbWVzIHRoYXQgY292YXJ5IGFuZCBub3Qgb25seSB0d28gbGlrZSBmb3Igcm9iZSBhbmQgZmFpbHVyZS5bXjJdDQoNClteMl06IEZpZ3VyZSBcQHJlZihmaWc6Y29ycm1hdHJpeCkgYWxzbyBpbmNsdWRlcyB2YXJpYWJsZXMgZm9yIHByb3BvcnRpb25zIHdpdGhpbiB0aGUgbWlub3Igc3VjY2VzcyBjYXRlZ29yeSwgZGVub3RlZCBcX21pbm9yLiBUaGUgY2F2ZWF0cyBleHBsYWluZWQgaW4gZm9vdG5vdGUgMSBhcHBsaWVzIGV2ZW4gbW9yZS4NCg0KYGBge3IgY29ycm1hdHJpeCwgZmlnLmhlaWdodCA9IDcsIGZpZy53aWR0aCA9IDgsIG91dC53aWR0aD0gIjc1JSIsIGZpZy5jYXA9ICJDb3JyZWxvZ3JhbSBmb3IgcHJvcG9ydGlvbiBvZiBkaWZmZXJlbnQgb3V0Y29tZXMuIExvd2VyIHRyaWFuZ3VsYXIgc2hvd3MgdGhlIGNvcnJlbGF0aW9uIG1hdHJpeCwgdXBwZXIgdHJpYW5ndWxhciBzaG93cyB0aGUgZWxsaXBzaXMgbWF0cml4LCB3aGVyZSB0aGUgZWNjZW50cmljaXR5IG9mIHRoZSBlbGxpcHNlIGlzIHNjYWxlZCB0byB0aGUgY29ycmVsYXRpb24gdmFsdWUifQ0KUlNUMm1hdHJpeCA8LSBSU1QyIHw+IA0KICBzZWxlY3QocHJvcFJvYmUsIHByb3BGYWlsdXJlLCBwcm9wTWlub3IsIHByb3BKdXN0YXUsIHByb3BWZWx2ZXQsIHByb3BXYWlzdCwgcHJvcEp1c3RhdV9taW5vciwgcHJvcFZlbHZldF9taW5vciwgcHJvcFdhaXN0X21pbm9yKSB8PiANCiAgY29yKCkNCg0KY29ycnBsb3QubWl4ZWQoUlNUMm1hdHJpeCwNCiB1cHBlciA9ICJlbGxpcHNlIiwNCiBsb3dlciA9ICJudW1iZXIiLA0KIG9yZGVyID0gJ0FPRScsIA0KIHRsLmNvbCA9ICdibGFjaycsDQogdGwucG9zID0gImx0IiwNCiBkaWFnID0gIm4iLA0KIHRsLnNydCA9IDMwLA0KIGJnID0gIiNFQkVCRUIiLA0KICNtYXIgPSBjKDAsMSwxLDEpDQogKQ0KYGBgDQoNCiMjIyBOb24tcmFuZG9tbmVzcyBhbmQgYmlhc2VzIGluIHRoZSB1bmRlcmx5aW5nIFJORyBhbGdvcml0aG0NCg0KYGBge3IgIGluY2x1ZGU9RkFMU0V9DQojIHJ1bnMtdGVzdCBmb3Igd2hvbGUgZGF0YSwgc2hvdWxkIGJlIHNvbWUgbm9uLXJhbmRvbW5lc3MgYmVjYXVzZSBiYXRjaGVzIGFyZSBmcm9tIGRpZmZlcmVudCBkaXN0cmlidXRpb25zDQpSb2JlMiRyb2JlU2VyaWVzIDwtIGZjdF9vdGhlcihSb2JlMiRSZXN1bHQsIGtlZXAgPSAiUm9iZSIpDQp0c2VyaWVzOjpydW5zLnRlc3QoUm9iZTIkcm9iZVNlcmllcykNCnNucGFyOjpydW5zLnRlc3QoYXMubnVtZXJpYyhSb2JlMiRyb2JlU2VyaWVzKSkNCnNqZWtrIDwtIHJhbmR0ZXN0czo6cnVucy50ZXN0KGFzLm51bWVyaWMoUm9iZTIkcm9iZVNlcmllcyksIHRocmVzaG9sZCA9IDEuNSkgDQpEZXNjVG9vbHM6OlJ1bnNUZXN0KGFzLm51bWVyaWMoUm9iZTIkcm9iZVNlcmllcykpIA0KDQojIHJ1bnMtdGVzdHMgZm9yIGVhY2ggQkFUQ0gsIHNob3VsZCBub3QgYmUgYW55IG5vbi1yYW5kb21uZXNzDQpSb2JlMiRCYXRjaDIgPC0NCiAgcGFzdGUoIkJhdGNoICIsIFJvYmUyJEJhdGNoLCAiLCAiLCBSb2JlMiRDb25kaXRpb24yLCBzZXAgPSAiIikNCnJ1bnNPdXRwdXRCYXRjaCA8LSBzcGxpdChSb2JlMiwgUm9iZTIkQmF0Y2gyKSB8Pg0KICBtYXAoZnVuY3Rpb24gKGRmKQ0KICAgIGJyb29tOjp0aWR5KHJhbmR0ZXN0czo6cnVucy50ZXN0KGFzLm51bWVyaWMoZGYkcm9iZVNlcmllcyksIHRocmVzaG9sZCA9IDEuNSkpKQ0KcnVuc091dHB1dEJhdGNoIDwtIGJpbmRfcm93cyhydW5zT3V0cHV0QmF0Y2gsIC5pZCA9ICJJRCIpDQpydW5zVGFibGVCYXRjaCA8LSBkYXRhdGFibGUocnVuc091dHB1dEJhdGNoLA0KICAgICAgICAgIG9wdGlvbnMgPSBsaXN0KHBhZ2VMZW5ndGggPSA1KSwNCiAgICAgICAgICBjYXB0aW9uID0gJ1J1bnMgdGVzdHMgZm9yIGVhY2ggYmF0Y2gnKSB8Pg0KICBmb3JtYXRSb3VuZChjb2x1bW5zID0gYygnc3RhdGlzdGljJywgJ3AudmFsdWUnKSwNCiAgICAgICAgICAgICAgZGlnaXRzID0gMykNCg0KIyBydW5zLXRlc3RzIGZvciBlYWNoIENPTkRJVElPTiwgc2hvdWxkIG5vdCBiZSBhbnkgbm9uLXJhbmRvbW5lc3MNClJvYmUyJENvbmRpdGlvbjQgPC0NCiAgcGFzdGUoIkNvbmRpdGlvbiAiLCBSb2JlMiRDb25kaXRpb24sICIsICIsIFJvYmUyJENvbmRpdGlvbjIsIHNlcCA9ICIiKQ0KcnVuc091dHB1dENvbmQgPC0gc3BsaXQoUm9iZTIsIFJvYmUyJENvbmRpdGlvbjQpIHw+DQogIG1hcChmdW5jdGlvbiAoZGYpDQogICAgYnJvb206OnRpZHkocmFuZHRlc3RzOjpydW5zLnRlc3QoYXMubnVtZXJpYyhkZiRyb2JlU2VyaWVzKSwgdGhyZXNob2xkID0gMS41KSkpDQpydW5zT3V0cHV0Q29uZCA8LSBiaW5kX3Jvd3MocnVuc091dHB1dENvbmQsIC5pZCA9ICJJRCIpDQpydW5zVGFibGVDb25kIDwtIGRhdGF0YWJsZShydW5zT3V0cHV0Q29uZCwNCiAgICAgICAgICBvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0gNSksDQogICAgICAgICAgY2FwdGlvbiA9ICdSdW5zIHRlc3RzIGZvciBjb21iaW5hdGlvbiBvZiBiYXRjaGVzIHVuZGVyIHNhbWUgY29uZGl0aW9ucycpIHw+DQogIGZvcm1hdFJvdW5kKGNvbHVtbnMgPSBjKCdzdGF0aXN0aWMnLCAncC52YWx1ZScpLA0KICAgICAgICAgICAgICBkaWdpdHMgPSAzKQ0KDQojIGF1dG9jb3JyZWxhdGlvbiwganVzdCB3aGl0ZSBub2lzZQ0KYWNmKGFzLm51bWVyaWMoKFJvYmUyJHJvYmVTZXJpZXMpKSkNCmFjZihSb2JlMiRyb2JlU2VyaWVzKQ0KcGFjZihSb2JlMiRyb2JlU2VyaWVzKQ0KIyBueWUgdmFyaWFibGVyOg0KUm9iZTI8LSBSb2JlMiB8Pg0KICBncm91cF9ieShCYXRjaCkgfD4gDQogICAgbXV0YXRlKHJvYmVTZXJpZXMyID0gY2FzZV93aGVuKA0KICAgIHJvYmVTZXJpZXM9PSJSb2JlIiB+IDEsIA0KICAgIHJvYmVTZXJpZXM9PSJPdGhlciIgfjApKSB8PiANCiBzdW1tYXJpc2Uocm9iZUluQmF0Y2ggPSBtYXgocm9iZVNlcmllczIpKSB8PiANCnJpZ2h0X2pvaW4oUm9iZTIpDQogDQpSb2JlMjwtIFJvYmUyIHw+DQogIGdyb3VwX2J5KENvbmRpdGlvbikgfD4gDQogICAgbXV0YXRlKHJvYmVTZXJpZXMyID0gY2FzZV93aGVuKA0KICAgIHJvYmVTZXJpZXM9PSJSb2JlIiB+IDEsIA0KICAgIHJvYmVTZXJpZXM9PSJPdGhlciIgfjApKSB8PiANCiBzdW1tYXJpc2Uocm9iZUluQ29uZGl0aW9uID0gbWF4KHJvYmVTZXJpZXMyKSkgfD4gDQpyaWdodF9qb2luKFJvYmUyKSANClJvYmUyIDwtIHVuZ3JvdXAoUm9iZTIpDQojIGZpbHRlciBvbiB0aGVzZSB0byBhdm9pZCBlbXB0eSBiYXRjaGVzIHRoYXQgdGhyb3dzIGVycm9yIGZvciBhY2YNCg0KQUNGd2hvbGUgPC0gYXV0b3Bsb3QoYWNmKFJvYmUyJHJvYmVTZXJpZXMsIHBsb3QgPSBGQUxTRSksIA0KICAgICAgICAgICAgICAgICAgICAgbWFpbiA9ICJXaG9sZSB0aW1lIHNlcmllcyIsDQogICAgICAgICAgICAgICAgICAgICBjb25mLmludC5jb2xvdXIgPSAiI0I1MUYyRSIpDQpQQUNGd2hvbGUgPC0gYXV0b3Bsb3QocGFjZihSb2JlMiRyb2JlU2VyaWVzLCBwbG90ID0gRkFMU0UpLCANCiAgICAgICAgICAgICAgICAgICAgICBtYWluID0gIldob2xlIHRpbWUgc2VyaWVzIiwgDQogICAgICAgICAgICAgICAgICAgICAgeWxhYiA9ICJQYXJ0aWFsIEFDRiIsDQogICAgICAgICAgICAgICAgICAgICAgY29uZi5pbnQuY29sb3VyID0gIiNCNTFGMkUiKQ0KDQpSb2Jlc0luQmF0Y2hTZXJpZXMgPC0gUm9iZTIgfD4gDQogIGZpbHRlcihyb2JlSW5CYXRjaCA9PSAxKQ0KYXV0b3Bsb3QoYWNmKFJvYmVzSW5CYXRjaFNlcmllcyRyb2JlU2VyaWVzLCBwbG90ID0gRkFMU0UpKQ0KQmF0Y2hBQ0YgPC0gc3BsaXQoUm9iZXNJbkJhdGNoU2VyaWVzLCBSb2Jlc0luQmF0Y2hTZXJpZXMkQmF0Y2gyKSB8PiANCiAgbWFwKGZ1bmN0aW9uIChkZikgYWNmKGRmJHJvYmVTZXJpZXMsIHBsb3QgPSBGQUxTRSkpDQpCYXRjaEFDRiA8LSBhdXRvcGxvdChCYXRjaEFDRiwgDQogICAgICAgICAgICAgICAgICAgICBuY29sID0gMywgDQogICAgICAgICAgICAgICAgICAgICBjb25mLmludC5jb2xvdXIgPSAiI0I1MUYyRSIpDQojUEFDRg0KQmF0Y2hQQUNGIDwtIHNwbGl0KFJvYmVzSW5CYXRjaFNlcmllcywgUm9iZXNJbkJhdGNoU2VyaWVzJEJhdGNoMikgfD4gDQogIG1hcChmdW5jdGlvbiAoZGYpIHBhY2YoZGYkcm9iZVNlcmllcywgcGxvdCA9IEZBTFNFKSkNCkJhdGNoUEFDRiA8LSBhdXRvcGxvdChCYXRjaFBBQ0YsIA0KICAgICAgICAgICAgICAgICAgICAgIG5jb2wgPSAzLCANCiAgICAgICAgICAgICAgICAgICAgICB5bGFiID0gIlBhcnRpYWwgQUNGIiwgDQogICAgICAgICAgICAgICAgICAgICAgY29uZi5pbnQuY29sb3VyID0gIiNCNTFGMkUiKQ0KDQpSb2Jlc0luQ29uZGl0aW9uU2VyaWVzIDwtIFJvYmUyIHw+IA0KICBmaWx0ZXIocm9iZUluQ29uZGl0aW9uID09IDEpDQphdXRvcGxvdChhY2YoUm9iZXNJbkNvbmRpdGlvblNlcmllcyRyb2JlU2VyaWVzLCBwbG90ID0gRkFMU0UpKQ0KQ29uZGl0aW9uQUNGIDwtIHNwbGl0KFJvYmVzSW5Db25kaXRpb25TZXJpZXMsIA0KICAgICAgICAgICAgICAgICAgICAgIGZjdF9kcm9wKFJvYmVzSW5Db25kaXRpb25TZXJpZXMkQ29uZGl0aW9uMikpIHw+IA0KICBtYXAoZnVuY3Rpb24gKGRmKSBhY2YoZGYkcm9iZVNlcmllcywgcGxvdCA9IEZBTFNFKSkNCkNvbmRpdGlvbkFDRiA8LSBhdXRvcGxvdChDb25kaXRpb25BQ0YsIA0KICAgICAgICAgICAgICAgICAgICAgICAgIG5jb2wgPSAzLCANCiAgICAgICAgICAgICAgICAgICAgICAgICBjb25mLmludC5jb2xvdXIgPSAiI0I1MUYyRSIpDQojUEFDRg0KQ29uZGl0aW9uUEFDRiA8LSBzcGxpdChSb2Jlc0luQ29uZGl0aW9uU2VyaWVzLCBSb2Jlc0luQ29uZGl0aW9uU2VyaWVzJENvbmRpdGlvbjIpIHw+IA0KICBtYXAoZnVuY3Rpb24gKGRmKSBwYWNmKGRmJHJvYmVTZXJpZXMsIHBsb3QgPSBGQUxTRSkpDQpDb25kaXRpb25QQUNGIDwtIGF1dG9wbG90KENvbmRpdGlvblBBQ0YsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICBuY29sID0gMywgDQogICAgICAgICAgICAgICAgICAgICAgICAgIHlsYWIgPSAiUGFydGlhbCBBQ0YiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgY29uZi5pbnQuY29sb3VyID0gIiNCNTFGMkUiKQ0KDQojcGxvdCB0ZXh0IEJhdGNoL2NvbmRpdGlvbiBudW1iZXI/DQpgYGANCg0KYGBge3Igd2hvbGVTZXF1ZW5jZSwgZmlnLmhlaWdodD0xLjUsIGZpZy53aWR0aD0gOSwgZmlnLmNhcCA9ICJTZXF1ZW5jZSBvZiBvdXRjb21lIGZvciBhbGwgcm9iZSBleHBlcmltZW50cyJ9DQojIHNlcXVlbmNlIHBsb3RzIHJvYmUgdnMgbm9uLXJvYmUNCiN3aG9sZSBzZXF1ZW5jZToNCmdncGxvdChSb2JlMiwgYWVzKHg9U2VxdWVuY2UsIGZpbGwgPSBmY3RfcmV2KFJlc3VsdCkpKSArDQogIGdlb21fYmFyKHBvc2l0aW9uID0gImZpbGwiLCB3aWR0aCA9IDEpICsNCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJSZEJ1IiwgZGlyZWN0aW9uID0gLTEpICsNCiAgI3NjYWxlX2ZpbGxfdmlyaWRpc19kKG9wdGlvbiA9ICJ0dXJibyIsIGRpcmVjdGlvbiA9IDEpKw0KICAjc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCAyMDAwLCBieSA9IDEwMCkpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGV4cGFuZCA9IGV4cGFuc2lvbihtdWx0ID0gLjAyNSkpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IE5VTEwpICsNCiAgdGhlbWUobGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICIjRUJFQkVCIiksDQogICAgICAgIGxlZ2VuZC5rZXkgPSBlbGVtZW50X3JlY3QoZmlsbCA9IE5BKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIsDQogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMS4yKSksDQogICAgICAgIGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gYygwLjUsIDApKSArDQogIGd1aWRlcyhmaWxsID0gZ3VpZGVfbGVnZW5kKHJldmVyc2UgPSBUUlVFLCB0aXRsZSA9IE5VTEwpKSArDQogIHhsYWIoIlNlcXVlbmNlIikgKw0KICB5bGFiKE5VTEwpDQpgYGANCg0KQSBmdW5kYW1lbnRhbCBhc3N1bXB0aW9uIGluIHRoZSBhbmFseXNlcyBwcmVzZW50ZWQgYWJvdmUgaXMgdGhhdCBlYWNoIHRyaWFsIGlzIHN0YXRpc3RpY2FsbHkgaW5kZXBlbmRlbnQgYW5kIHRoYXQgdGhlIHByb2JhYmlsaXR5IG9mIHN1Y2Nlc3MgaXMgdGhlIHNhbWUgZm9yIGFsbCB0cmlhbHMgZm9yIHdoaWNoIGEgY29uZmlkZW5jZSBpbnRlcnZhbCBpcyBjYWxjdWxhdGVkLiBUaGlzIG5lZWQgbm90IGJlIHRoZSBjYXNlIGFuZCBzaG91bGQgYmUgY29uZmlybWVkLg0KDQpUbyB0ZXN0IGZvciB0aGUgcHJlc2VuY2Ugb2YgYmlhc2VzIGluIHRoZSBwc2V1ZG8tcmFuZG9tIG51bWJlciBnZW5lcmF0b3IgYWxnb3JpdGhtIHVzZWQsIHdlIGNhbiBsb29rIGF0IHRoZSBzZXF1ZW5jZSBvZiBvdXRjb21lcyAoRmlndXJlIFxAcmVmKGZpZzp3aG9sZVNlcXVlbmNlKSkuIE5vbi1yYW5kb21uZXNzIHdvdWxkIHJlc3VsdCBpbiBtb3JlIGNsdXN0ZXJzIG9mIHRoZSBzYW1lIHJlc3VsdCwgb3IgbW9yZSBldmVubHkgc3ByZWFkIG91dCByZXN1bHRzIHRoYW4gZXhwZWN0ZWQgYnkgY2hhbmNlLiBPbmUgd2F5IG9mIG1lYXN1cmluZyB0aGlzIGlzIGJ5IGNvdW50aW5nIHRoZSBudW1iZXIgb2YgInJ1bnMiIC0tIHNlZ21lbnRzIG9mIHRoZSBzZXF1ZW5jZSB3aXRoIHRoZSBzYW1lIHZhbHVlLiBGb3IgZXhhbXBsZSBpZiB0aGVyZSBhcmUgY2VydGFpbiAibHVja3kgdGltZXMiICh3aGVyZSBvbmUgc2hvdWxkIGNvbnRpbnVlIHByb2R1Y2luZyksIGFuZCBjZXJ0YWluIGJhZCBvbmVzICh3aGVyZSBvbmUgc2hvdWxkIGltbWVkaWF0ZWx5IGNhbmNlbCksIHRoZXJlIHdvdWxkIGJlIG1vcmUgcnVucyBpbiB0aGUgZGF0YSB0aGFuIGV4cGVjdGVkIGJ5IGNoYW5jZS4NCg0KV2Ugb25seSBjb25zaWRlciBhIGJpbmFyeSBvdXRjb21lIG9mIFJvYmUgdnMuIG5vbi1Sb2JlLCBzaG93biBpbiBGaWd1cmUgXEByZWYoZmlnOndob2xlU2VxdWVuY2VEaWNvKSBiZWxvdy5bXjNdIFRoZXJlIHdhcyBhIGhpZ2hseSBzaWduaWZpY2FudCBkZXZpYXRpb24gZnJvbSByYW5kb21uZXNzIGluIHRoZSBjb21wbGV0ZSBzZXF1ZW5jZSAoV2FsZC1Xb2xmb3dpdHogcnVucy10ZXN0LCBwID0gMC4wMDMpLg0KDQpbXjNdOiBNdWx0aW5vbWlhbCBydW5zLXRlc3RzIGFuZCBhdXRvLWNvcnJlbGF0aW9uIGlzIGNvbXB1dGF0aW9uYWxseSBjb21wbGV4IGFuZCBiZXlvbmQgdGhlIHNjb3BlIG9mIHRoaXMgcmVwb3J0LCBidXQgc2VlIFtXZWlzcyAoMjAxNyldKGh0dHBzOi8vd3d3LndpbGV5LmNvbS9lbi1ubC9BbitJbnRyb2R1Y3Rpb24rdG8rRGlzY3JldGUrVmFsdWVkK1RpbWUrU2VyaWVzLXAtOTc4MTExOTA5Njk5Myl7dGFyZ2V0PSJfYmxhbmsifS4NCg0KYGBge3Igd2hvbGVTZXF1ZW5jZURpY28sIGZpZy5oZWlnaHQ9MS41LCBmaWcud2lkdGg9IDksIGZpZy5jYXAgPSAiU2VxdWVuY2Ugb2Ygb3V0Y29tZSBmb3IgYWxsIHJvYmUgZXhwZXJpbWVudHMsIGRpY2hvdG9taXplZCJ9DQpnZ3Bsb3QoUm9iZTIsIGFlcyh4PVNlcXVlbmNlLCBmaWxsID0gZmN0X3Jldihyb2JlU2VyaWVzKSkpICsNCiAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZmlsbCIsIHdpZHRoID0gMSkgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjOTVhNWE2IiwiI0I1MUYyRSIpKSArDQogICNzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDIwMDAsIGJ5ID0gMTAwKSkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoZXhwYW5kID0gZXhwYW5zaW9uKG11bHQgPSAuMDI1KSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gTlVMTCkgKw0KICB0aGVtZShsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIiNFQkVCRUIiKSwNCiAgICAgICAgbGVnZW5kLmtleSA9IGVsZW1lbnRfcmVjdChmaWxsID0gTkEsIGNvbG9yID0gTkEpLA0KICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAidG9wIiwNCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IHJlbCgxLjIpKSwNCiAgICAgICAgbGVnZW5kLmp1c3RpZmljYXRpb24gPSBjKDAuNSwgMCkpICsNCiAgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQocmV2ZXJzZSA9IFRSVUUsIHRpdGxlID0gTlVMTCkpICsNCiAgeGxhYigiU2VxdWVuY2UiKSArDQogIHlsYWIoTlVMTCkNCmBgYA0KDQpIb3dldmVyLCB0aGlzIGlzIGVudGlyZWx5IGFzIGV4cGVjdGVkIGJlY2F1c2Ugd2UgaW50cm9kdWNlZCBhIHBvdGVudGlhbCBzb3VyY2Ugb2Ygbm9uLXJhbmRvbW5lc3MsIG5hbWVseSBjaGFuZ2luZyB0aGUgY29uZGl0aW9ucy4gSWYgdGhlIGNvbmRpdGlvbnMgaW5kZWVkIGFmZmVjdCB0aGUgb3V0Y29tZSBvZiB0aGUgZXhwZXJpbWVudHMgd2UgdGh1cyBjYW5ub3QgdXNlIHRoZSBjb21wbGV0ZSBzZXF1ZW5jZSB0byBkaXN0aW5ndWlzaCBiZXR3ZWVuIHRoZSBlZmZlY3Qgb2YgdGhlIGNvbmRpdGlvbnMgYW5kIHRoZSBwcmVzZW5jZSBvZiBhbnkgb3RoZXIgbm9uLXJhbmRvbW5lc3MuDQoNCkluc3RlYWQgd2UgbXVzdCBsb29rIGF0IHRoZSBiYXRjaCBzZXF1ZW5jZXMgc2VwYXJhdGVseSAoRmlndXJlIFxAcmVmKGZpZzpzZXF1ZW5jZUJhdGNoKSksIG9yIHRoZSBjb21iaW5lZCBzZXF1ZW5jZSBvZiBzZXZlcmFsIGJhdGNoZXMgZG9uZSB1bmRlciB0aGUgc2FtZSBleHBlcmltZW50YWwgY29uZGl0aW9ucyAoRmlndXJlIFxAcmVmKGZpZzpzZXF1ZW5jZUNvbmRpdGlvbikpLiBUaGVzZSB0d28gY2FuIGRpZmZlciwgZm9yIGV4YW1wbGUgaWYgY2xvc2luZyBhbmQgc3RhcnRpbmcgdGhlIHByb2R1Y3Rpb24gZGlhbG9ndWUgd2luZG93IHNvbWVob3cgbWF0dGVyczogVGhlbiB3ZSBzaG91bGQgZmluZCBhIGRldmlhdGlvbiB3aGVuIGxvb2tpbmcgYXQgY29tYmluZWQgc2VxdWVuY2VzIGZyb20gc2V2ZXJhbCBiYXRjaGVzLCBidXQgbm90IHdoZW4gbG9va2luZyBhdCBzaW5nbGUgYmF0Y2hlcy5bXjRdDQoNClteNF06IEkgYWNrbm93bGVkZ2UsIGJ1dCBpZ25vcmUsIHRoZSBwcm9ibGVtIHRoYXQgc2luZ2xlIGJhdGNoZXMgaGF2ZSBpbmhlcmVudGx5IGxlc3Mgc3RhdGlzdGljYWwgcG93ZXIgYmVjYXVzZSBvZiBsb3dlciBzYW1wbGUgc2l6ZXMuDQoNCmBgYHtyIHNlcXVlbmNlQmF0Y2gsIGZpZy5oZWlnaHQ9IDQsIGZpZy5jYXA9IlNlcXVlbmNlIG9mIG91dGNvbWUgZm9yIHJvYmUgZXhwZXJpbWVudHMsIHBlciBiYXRjaCJ9DQojIHBlciBiYXRjaDoNCmdncGxvdChSb2JlMiwgYWVzKHg9QmF0U2VxLCBmaWxsID0gZmN0X3Jldihyb2JlU2VyaWVzKSkpICsNCiAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZmlsbCIsIHdpZHRoID0gMSkgKw0KICBmYWNldF93cmFwKHZhcnMoZmN0X3JldihDb25kaXRpb24zKSwgR3JvdXBCYXRjaCksIHN0cmlwLnBvc2l0aW9uID0gImxlZnQiLCBuY29sID0gMSkgKw0KICAjc2NhbGVfZmlsbF92aXJpZGlzX2Qob3B0aW9uID0gInR1cmJvIiwgZGlyZWN0aW9uID0gMSkrDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiM5NWE1YTYiLCIjQjUxRjJFIikpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCAxMjAsIGJ5ID0gMjApKSArDQogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBOVUxMKSArDQogIHRoZW1lKGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiI0VCRUJFQiIpLA0KICAgICAgICBsZWdlbmQua2V5ID0gZWxlbWVudF9yZWN0KGZpbGwgPSBOQSwgY29sb3IgPSBOQSksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLA0KICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDEuMikpLA0KICAgICAgICBsZWdlbmQuanVzdGlmaWNhdGlvbiA9IGMoMC41LCAwKSkgKw0KICBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZChyZXZlcnNlID0gVFJVRSwgdGl0bGUgPSBOVUxMKSkgKw0KICB0aGVtZShzdHJpcC50ZXh0LnkubGVmdCA9IGVsZW1lbnRfYmxhbmsoKSwgI2VsZW1lbnRfdGV4dChhbmdsZSA9IDAsIGhqdXN0ID0gMCksDQogICAgICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuc3BhY2luZyA9IHVuaXQoMC4wNSwiY20iKSkgKw0KICB4bGFiKCJTZXF1ZW5jZSIpICsNCiAgeWxhYihOVUxMKQ0KYGBgDQoNCmBgYHtyIHNlcXVlbmNlQ29uZGl0aW9uLCBmaWcuaGVpZ2h0PSA0LCBmaWcuY2FwPSJTZXF1ZW5jZSBvZiBvdXRjb21lIGZvciByb2JlIGV4cGVyaW1lbnRzLCBwZXIgY29uZGl0aW9uIn0NCiMgcGVyIGNvbmRpdGlvbjoNCiMgZmlyc3QgbWFrZSBhIHNlcXVlbmNlIHdpdGhpbiBjb25kaXRpb24uDQoNClJvYmUyIDwtIFJvYmUyIHw+IA0KICBncm91cF9ieShDb25kaXRpb24pIHw+IA0KICBtdXRhdGUoU3RhcnRTZXEgPSBtaW4oU2VxdWVuY2UpLA0KICAgICAgICAgQ29uZFNlcSA9IFNlcXVlbmNlLVN0YXJ0U2VxKzEpDQpSb2JlMiA8LSB1bmdyb3VwKFJvYmUyKQ0KICAgICAgICAgDQpnZ3Bsb3QoUm9iZTIsIGFlcyh4PUNvbmRTZXEsIGZpbGwgPSBmY3RfcmV2KHJvYmVTZXJpZXMpKSkgKw0KICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJmaWxsIiwgd2lkdGggPSAxKSArDQogIGZhY2V0X3dyYXAodmFycyhmY3RfcmV2KENvbmRpdGlvbjMpKSwgc3RyaXAucG9zaXRpb24gPSAibGVmdCIsIG5jb2wgPSAxKSArDQogICNzY2FsZV9maWxsX3ZpcmlkaXNfZChvcHRpb24gPSAidHVyYm8iLCBkaXJlY3Rpb24gPSAxKSsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiIzk1YTVhNiIsIiNCNTFGMkUiKSkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDIyMCwgYnkgPSAyMCkpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IE5VTEwpICsNCiAgdGhlbWUobGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICIjRUJFQkVCIiksDQogICAgICAgIGxlZ2VuZC5rZXkgPSBlbGVtZW50X3JlY3QoZmlsbCA9IE5BLCBjb2xvciA9IE5BKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIsDQogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMS4yKSksDQogICAgICAgIGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gYygwLjUsIDApKSArDQogIGd1aWRlcyhmaWxsID0gZ3VpZGVfbGVnZW5kKHJldmVyc2UgPSBUUlVFLCB0aXRsZSA9IE5VTEwpKSArDQogIHRoZW1lKHN0cmlwLnRleHQueS5sZWZ0ID0gZWxlbWVudF9ibGFuaygpLCAjZWxlbWVudF90ZXh0KGFuZ2xlID0gMCwgaGp1c3QgPSAwKSwNCiAgICAgICAgc3RyaXAudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5zcGFjaW5nID0gdW5pdCgwLjA1LCJjbSIpKSArDQogIHhsYWIoIlNlcXVlbmNlIikgKw0KICB5bGFiKE5VTEwpDQpgYGANCg0KVGhlcmUgd2VyZSB2ZXJ5IGZldyBzaWduaWZpY2FudCBkZXZpYXRpb25zIGZyb20gbm9uLXJhbmRvbW5lc3Mgb2YgcnVucyBpbiB0aGUgc2VwYXJhdGUgYmF0Y2hlcyBhbmQgbm9uZSBpbiB0aGUgY29tYmluZWQgYmF0Y2hlcyB1bmRlciBzYW1lIGNvbmRpdGlvbnMgKHJ1bnMtdGVzdHMgcmVzdWx0cyBpbiBbQXBwZW5kaXhdKCNydW5zLXRlc3RzKSksIGFuZCBjb25zaWRlcmluZyB0aGUgbnVtYmVyIG9mIHRlc3RzIHBlcmZvcm1lZCBpcyBhcyBleHBlY3RlZCB1bmRlciByYW5kb21uZXNzLiBIZW5jZSwgdGhlIHBzZXVkby1yYW5kb20gbnVtYmVyIGdlbmVyYXRvciBhbGdvcml0aG0gZ2VuZXJhdGluZyB0aGUgcmVzdWx0cyBhcHBlYXJzIHRvIGJlIHVuYmlhc2VkIGFuZCBpbiBhY2NvcmRhbmNlIHdpdGggYSByYW5kb20gcHJvY2Vzcy4gVGhpcyByZXN1bHQgLS0tIHByZXNlbmNlIG9mIG5vbi1yYW5kb21uZXNzIGluIHRoZSBjb21wbGV0ZSBzZXF1ZW5jZSBidXQgbm90IGluIHRoZSBiYXRjaGVzIC0tLSB0aGVyZWZvcmUgZ2l2ZSBhZGRpdGlvbmFsIHN0YXRpc3RpY2FsIGNvbmZpcm1hdGlvbiB0aGF0IHRoZSBleHBlcmltZW50YWwgY29uZGl0aW9ucyBhZmZlY3RlZCB0aGUgb3V0Y29tZS4NCg0KQW5vdGhlciBhcHByb2FjaCB0byBkZXRlY3Rpbmcgbm9uLXJhbmRvbW5lc3MgaXMgdG8gY29uc2lkZXIgdGhlIHNlcXVlbmNlIG9mIG91dGNvbWVzIGFzIGEgdGltZS1zZXJpZXMgYW5kIGxvb2sgZm9yIGF1dG8tY29ycmVsYXRpb24uIEF1dG8tY29ycmVsYXRpb24gaXMgdGhhdCBhIHRpbWUgc2VyaWVzIGlzIGNvcnJlbGF0ZWQgd2l0aCBhIGxhZ2dlZCB2ZXJzaW9uIG9mIGl0c2VsZi4gVGhpcyBjb3VsZCBmb3IgZXhhbXBsZSBiZSBjYXVzZWQgYnkgY3ljbGVzIG9yIHRyZW5kcywgb3IgaW4gZ2VuZXJhbCBpZiB0aGUgb3V0Y29tZSBvZiBvbmUgZXhwZXJpbWVudCBpcyByZWxhdGVkIHRvIHRoZSBvdXRjb21lIG9mIHRoZSBwcmV2aW91cyBleHBlcmltZW50IChvciBhIGNlcnRhaW4gbnVtYmVyIG9mIHN0ZXBzIGF3YXkpLg0KDQpBdXRvLWNvcnJlbGF0aW9uIGZ1bmN0aW9uIHBsb3RzIChBQ0YpIGFuZCBwYXJ0aWFsIGF1dG8tY29ycmVsYXRpb24gZnVuY3Rpb24gcGxvdHMgKGkuZS4sIGNvbnRyb2xsZWQgZm9yIGF1dG8tY29ycmVsYXRpb24gYXQgc2hvcnRlciBsYWdzKSBhcmUgcHJlc2VudGVkIGluIHRoZSBbQXBwZW5kaXhdKCNhdXRvLWNvcnJlbGF0aW9uKS4gQWdhaW4sIGFueSAod2VhaykgYXV0byBjb3JyZWxhdGlvbiBjb3VsZCBvbmx5IGJlIHNlZW4gaW4gdGhlIGNvbXBsZXRlIHNlcXVlbmNlIG9mIGV4cGVyaW1lbnRzIGFuZCBub3QgaW4gdGhlIHNlcGFyYXRlIGJhdGNoZXMsIGFzIGV4cGVjdGVkIGlmIHRoZSBvbmx5IHNvdXJjZSBvZiBub24tcmFuZG9tbmVzcyBpbiB0aGUgb3V0Y29tZSBvZiB0aGUgZXhwZXJpbWVudHMgd2FzIHZhcnlpbmcgdGhlIGZhY3RvcnMgc3R1ZGllZC4gSW4gb3RoZXIgd29yZHMsIHRoZSB0aW1lLXNlcmllcyB1bmRlciBjb25zdGFudCBjb25kaXRpb25zIGxvb2tlZCBsaWtlIHdoaXRlIG5vaXNlIHdoaWNoIGlzIHdoYXQgd2UgY2FuIGV4cGVjdCBmcm9tIGEgcmFuZG9tIHByb2Nlc3MuDQoNCiMgRGlzY3Vzc2lvbg0KDQo+ICJJIGd1ZXNzIHdlJ2xsIGJlIHRyYXZlbGluZyBpbiB1bmNoYXJ0ZWQgd2F0ZXJzLiJcDQo+ICJUaGF0J2xsIGJlIGZ1biIsIFBoaWwgc2FpZC5bXjVdDQo+DQo+IDo6OiB7c3R5bGU9InRleHQtYWxpZ246IHJpZ2h0OyJ9DQo+IGByIHR1ZnRlOjpxdW90ZV9mb290ZXIoIkxlbW9ueSBTbmlja2V0IChBIFNlcmllcyBvZiBVbmZvcnR1bmF0ZSBFdmVudHMpIilgDQo+IDo6Og0KDQpbXjVdOiBIZSBjb3VsZCBoYXZlIHNhaWQgRkFCdWxvdXMNCg0KSW4gdGhlIEVuZ2xpc2ggdmVyc2lvbiBvZiBVV08gdGhlIGRlc2NyaXB0aW9ucyBpbiBnYW1lIG9mIGFkZXB0IHRpdGxlLCBIUkUgcG9zaXRpb24gYW5kIGFkdmlzb3IgYWxsIHJlZmVyIHRvIGluY3JlYXNlZCAiY2hhbmNlIG9mIHN1Y2Nlc3MiIG9mIGFsY2hlbXkgZXhwZXJpbWVudHMuIFRoaXMgaXMgc29tZXdoYXQgdmFndWUsIGFzIGl0IGRvZXMgbm90IGV4cGxpY2l0bHkgc3RhdGUgaWYgaXQgcmVmZXJzIHRvICJodWdlIHN1Y2Nlc3MiIG9yIHNpbXBseSBhbnkgc3VjY2VzcyAoYXMgb3Bwb3NlZCB0byBmYWlsdXJlKSBvciBib3RoLiBUaGUgcmVzdWx0cyBwcmVzZW50ZWQgaGVyZSBzaG93IHRoYXQgdGhlc2UgZWZmZWN0cyBzcGVjaWZpY2FsbHkgdGFyZ2V0IHRoZSBjaGFuY2Ugb2YgImh1Z2Ugc3VjY2VzcyIgYW5kIGhhdmUgbm8gZWZmZWN0IG9uIHRoZSBvdGhlciBvdXRjb21lcy4NCg0KQ29tcGFyZWQgdG8gdGhlIG5vcm1hbCByYXRlICh3aXRoIGFkZXB0IHRpdGxlKSBvZiBhcHByb3guIDEgcm9iZSBvciBiaXJldHRhIGZyb20gMTAwIGV4cGVyaW1lbnRzLCBpdCBpcyBjbGVhciB0aGF0IHRoZSBIUkUgZWZmZWN0IGlzIGVub3Jtb3VzOiB3aXRoIEhSRSBJIGdvdCBhcHByb3hpbWF0ZWx5IDEgcm9iZSBwZXIgNSBleHBlcmltZW50cywgb3IgMjAlIHN1Y2Nlc3MuIFdpdGggYWxzbyBhZHZpc29yIHRpdGxlIHRoZSBzdWNjZXNzIGluY3JlYXNlZCAxMCUgbW9yZSwgdG8gMzAlLiANCg0KSXQgd2FzIHN1cnByaXNpbmcgdGhhdCB0aGUgZ2VuZXJhbCBIUkUgZWZmZWN0IGlzIGxhcmdlciB0aGFuIHRoZSBjb3VydCBhZHZpc29yIGVmZmVjdC4gSXQgd291bGQgYXJndWFibHkgaGF2ZSBtYWRlIG1vcmUgc2Vuc2UgaWYgaXQgd2FzIHRoZSBvdGhlciB3YXkgYXJvdW5kLiBPbmUgb2YgdGhlIHdpZGVyIHJhbWlmaWNhdGlvbnMgb2YgdGhpcyBmaW5kaW5nIGlzIHRoYXQgdGhlIG90aGVyIEhSRSBlZmZlY3RzIHBlcmhhcHMgYXJlIG9mIHRoZSBzYW1lIG1hZ25pdHVkZSwgd2hpY2ggZml0cyB3aXRoIG9ic2VydmF0aW9ucyBvZiBlLmcuIHRoZSBnYW5hZG9yIGRyb3AgcmF0ZSBIUkUgZWZmZWN0Lg0KDQpNYWtpbmcgdGhlIEZBQiBhbGJ1bSBkdXJpbmcgYSBIUkUgYm9vc3QgaXMgb2J2aW91c2x5IHNhdmluZyBhIGxvdCBvZiBtYXRlcmlhbHMgYW5kIHN1ZmZlcmluZywgYW5kIGFzIHNob3duIGhlcmUgaXMgZWFzaWx5IGRvbmUgZm9yIGFueSBjaGFyYWN0ZXIuIEV2ZW4gbG93IGxldmVsIG9uZXMgaW4gYSBzdGFydGVyIGJhcmNhLCBwcm92aWRlZCB0aGV5IGhhdmUgYWNjZXNzIHRvIHJhbmsgMiBxdWFydGVycyAoYW5kIHNvbWUgaGVscCkuDQoNCkhvd2V2ZXIsIGRlY2lkaW5nIHRvIGRvIGZ1cnRoZXIgZXhwZXJpbWVudHMgb24gUm9iZXMgZGlkIG5vdCBzYXZlIGEgbG90IG9mIG1hdGVyaWFscyBhbmQgc3VmZmVyaW5nLg0KDQpCeSBjb21wYXJpbmcgZXhwZXJpbWVudHMgd2hlcmUgY2VydGFpbiBjb25kaXRpb25zIHdlcmUgbWFuaXB1bGF0ZWQgYW5kIGFsbCBvdGhlciBmYWN0b3JzIHdlcmUgaGVsZCBjb25zdGFudCwgaXQgd2FzIHBvc3NpYmxlIHRvIG1lYXN1cmUgdGhlIGVmZmVjdCBvZiB2YXJpb3VzIGZhY3RvcnMgdGhvdWdodCB0byBwb3NzaWJseSBpbmZsdWVuY2UgdGhlIHN1Y2Nlc3Mgb2YgYWxjaGVteSBleHBlcmltZW50cy4gVGhlcmUgd2FzIG5vIGRpc2Nlcm5pYmxlIGVmZmVjdCBvZiBoYXZpbmcgb3Igbm90IGhhdmluZyBPeGZvcmQgcHJvZHVjdGlvbiBza2lsbHMgYWN0aXZlIChpbmNsdWRpbmcgaXRlbSBpbXByb3ZlbWVudCB0ZWNobmlxdWUpLiBJZiBhbnl0aGluZywgdGhlIHN1Y2Nlc3Mgd2FzIGJldHRlciB3aXRoIE94Zm9yZHMgb2ZmLiBBbHNvLCB0aGUgRVggZ2VhciBmb3IgYmV0dGVyIHRpZXIgZ3JlYXQgc3VjY2VzcyBkaWQgbm90IHNlZW0gdG8gaW5mbHVlbmNlIGFsY2hlbXkgZXhwZXJpbWVudHMuIEFsY2hlbXkgcmFuayBhbmQgcGF5bWFzdGVyIGFpZGUgcmFuayBoYWQgbm8gZWZmZWN0IGVpdGhlci4gQWxsIHRoaXMgaXMgYXMgZXhwZWN0ZWQgZnJvbSB0aGUgImFsY2hlbXkgZXhwZXJpbWVudHMgYXJlIGRpZmZlcmVudCIgY2FtcCwgYW5kIHN1cHBvcnRzIHRoZSB2aWV3IHRoYXQgaHVnZSBzdWNjZXNzIGluIGFsY2hlbXkgZXhwZXJpbWVudHMgaXMgbm90IGFuYWxvZ291cyB0byBoaWdoIHRpZXIgZ3JlYXQgc3VjY2VzcyBvZiBub3JtYWwgY3JhZnRpbmcuIA0KDQpIb3dldmVyLCBhbGNoZW15IHJhbmsgKmRpZCogaGF2ZSBhbiBlZmZlY3Qgb24gbWlub3Igc3VjY2Vzcywgd2l0aCBoaWdoZXIgcmFuayBpbmNyZWFzaW5nIHRoZSBwcm9iYWJpbGl0eSBvZiBhZG1pcmFsIGp1c3RhdWNvcnBzLiBUaGUgbWFnbml0dWRlIG9mIHRoZSBlZmZlY3Qgd2FzIGVzdGltYXRlZCBhdCArMSUgcGVyIHNraWxsIHJhbmsgYWJvdmUgbWluaW11bSByZXF1aXJlbWVudC4gVGhpcyBzdWdnZXN0cyB0aGF0IHRoZSBtaW5vciBzdWNjZXNzIG91dGNvbWUgbWF5IGJlIGluZmx1ZW5jZWQgYnkgdGhlIHNhbWUgZmFjdG9ycyBhcyBub3JtYWwgY3JhZnRpbmcuIEJ1dCwgd2h5IHRoZW4gZGlkIG9ubHkgYWxjaGVteSByYW5rIGVmZmVjdCB0aGUgb3V0Y29tZSBvZiBtaW5vciBzdWNjZXNzPyBJIHN1c3BlY3QgdGhhdCBPeGZvcmQgYW5kIEVYIGFjdHVhbGx5IGRpZCBoYXZlIGFuIGVmZmVjdCwgYnV0IG9ubHkgb24gdGhlICpzdGF0cyogb2YgdGhlIGl0ZW1zLiBUaGlzIHdhcyBub3QgdGVzdGVkLCBhbmQgdGhlIGRhdGEgaXMgbm93IGxvc3Qgc2luY2UgaXQgd2FzIG5vdCBrZXB0IHRyYWNrIG9mIHdoZXJlIGVhY2ggQWRlcHQncyBSb2JlIG9yaWdpbmF0ZWQgZnJvbS4gSnVzdCBsaWtlIERhcndpbiAodGhhdCBkaWQgbm90IGxhYmVsIHdoYXQgcGFydGljdWxhciBpc2xhbmQgaGlzIEZpbmNoZXMgY29sbGVjdGVkIGluIHRoZSBHYWxhcGFnb3MgaGFkIGJlZW4gb2J0YWluZWQgZnJvbSksIEkgY2FuIHNheSBpbiBoaW5kc2lnaHQgdGhhdCB0aGlzIHNob3VsZCBoYXZlIGJlZW4gZG9uZS4gSXQgbXVzdCBiZSBsZWZ0IHRvIGZ1dHVyZSBzdHVkaWVzIHRvIGludmVzdGlnYXRlIGlmIGFsY2hlbXkgcmFuaywgT3hmb3JkIGFuZCBFWCBhZmZlY3RzIHRoZSBzdGF0cyBvZiBtaW5vciBhbmQgaHVnZSBzdWNjZXNzIGFsY2hlbXkgZXhwZXJpbWVudHMuDQoNCkFuIHVuZXhwZWN0ZWQgcmVzdWx0IHdhcyB0aGF0IHRoZSByYXRlIG9mIG1pbm9yIHN1Y2Nlc3Mgd2FzIGNvbnN0YW50IHVuZGVyIGFsbCB0cmVhdG1lbnRzLiBJbmNyZWFzaW5nIHRoZSByYXRlIG9mIGp1c3RhdWNvcnBzIGJ5IGhhdmluZyBoaWdoZXIgYWxjaGVteSByYW5rIGRpZCBub3QgY2hhbmdlIHRoZSByYXRlIG9mIGZhaWx1cmVzIG9yIHJvYmVzLCBidXQgb25seSBzaHVmZmxlZCB0aGUgcHJvcG9ydGlvbnMgb2YgdGhlIG90aGVyIG1pbm9yIHN1Y2Nlc3Mgb3B0aW9ucyB3aXRoaW4gdGhlaXIgZml4ZWQgY29tbW9uIHNoYXJlIG9mIGFsbCBvdXRjb21lcy4NCg0KTXkgaW50ZXJwcmV0YXRpb24gaXMgdGhpczogdGhhdCB0aGUgZmFjdG9ycyBpbmZsdWVuY2luZyBjaGFuY2Ugb2YgZ3JlYXQgc3VjY2VzcyBpbiBub3JtYWwgY3JhZnRpbmcgcGxheSBubyByb2xlIGluIGFsY2hlbXkgZXhwZXJpbWVudHMgYmVjYXVzZSB1bmxpa2Ugbm9ybWFsIGNyYWZ0aW5nLCByYXRlIG9mIGZhaWx1cmUgaXMgbm90IGEgc2VwYXJhdGUgcGFyYW1ldGVyIGluIGFsY2hlbXkgZXhwZXJpbWVudHMuIEl0IGlzIHNpbXBseSB0aGUgaW52ZXJzZSBvZiB0aGUgcmF0ZSBvZiBodWdlIHN1Y2Nlc3MgKEZpZ3VyZSBcQHJlZihmaWc6Zml4ZWRzY2F0dGVyKSkgYmVjYXVzZSB0aGUgbWlub3Igc3VjY2VzcyByYXRlIGlzIGZpeGVkLg0KDQpGb3Igc29tZSBhbGNoZW15IGV4cGVyaW1lbnRzIG1vcmUgdGhhbiBvbmUga2luZCBhbHNvIG9mIGdyZWF0IHN1Y2Nlc3MgaXMgcG9zc2libGUgKHN1Y2ggYXMgcGxhdGVzIGZyb20gcHJvY2Vzc2VkIGx1bWJlciBhbmQgbWV0YWwgd29ya3MpLiBJIGRvIG5vdCBoYXZlIGFueSBkYXRhIHRvIHNheSB3aGF0LCBpZiBhbnl0aGluZywgbWlnaHQgYWZmZWN0IHRoZSByYXRlcyBvZiBkaWZmZXJlbnQgZ3JlYXQgc3VjY2Vzcy4gSSBhbHNvIGhhdmUgbm8gZGF0YSBvbiB0aGUgZGlmZmVyZW50IG5vcm1hbCBzdWNjZXNzZXMgZm9yIHRoZSByZWNpcGVzIG90aGVyIHRoYW4gcm9iZS4gQSByZWFzb25hYmxlIGNvbmplY3R1cmUgaXMgdGhhdCB0aGVzZSBhcmUgYWxzbyBhZmZlY3RlZCBieSBhbGNoZW15IHJhbmssIGFuZCB0aGF0IHRoZWlyIGNvbW1vbiBzaGFyZSBvZiB0aGUgb3V0Y29tZXMgaXMgY29uc3RhbnQgbGlrZSBmb3IgdGhlIHJvYmUgcmVjaXBlLg0KDQpQZXJoYXBzIHN1cnByaXNpbmdseSwgdGhlcmUgd2FzIG5vIG1lYXN1cmFibGUgZWZmZWN0IG9mIGhhdmluZyB0aGUgQWRlcHQgdGl0bGUsIGJ1dCBpdCB3YXMgd2l0aCBhIGhpZ2ggZGVncmVlIG9mIGNvbmZpZGVuY2UgbWVhc3VyZWQgdG8gYmUgbGVzcyB0aGFuIDMlLiBJdCBtYXkgYmUgMSUuIEhvd2V2ZXIsIGxhcmdlciBzYW1wbGUgc2l6ZXMgdGhhbiBvYnRhaW5lZCBoZXJlIHdvdWxkIGJlIG5lZWRlZCB0byBwcmVjaXNlbHkgZXN0aW1hdGUgc3VjaCBzbWFsbCBlZmZlY3RzLiBUaGlzIGlzIGlsbHVzdHJhdGVkIGJ5IHRoZSByZXBsaWNhdGlvbiBkb25lIGZvciBzb21lIGNvbmRpdGlvbnMsIHRoYXQgc2hvd2VkIGNvbnNpZGVyYWJsZSBpbnRlci1iYXRjaCB2YXJpYXRpb24gKHNvbWV0aW1lcyBvZiB0aGUgc2FtZSBtYWduaXR1ZGUgYXMgYW1vbmcgY29uZGl0aW9ucykuIERpZmZlcmVuY2VzIGJldHdlZW4gYmF0Y2hlcyBzdWJqZWN0IHRvIHRoZSBleGFjdCBzYW1lIGNvbmRpdGlvbnMgY291bGQgYmUgbWlzdGFrZW4gZm9yIHNvbWUga2luZCBvZiBiaWFzIGluIHRoZSBSTkdbXjZdLCBidXQgaW4gcmVhbGl0eSBpcyB3aGF0IGlzIGV4cGVjdGVkIGZyb20gc21hbGwgc2FtcGxlcyBmcm9tIGEgcmFuZG9tIHByb2Nlc3MsIHNob3duIGJ5IHRlc3RzIGRvbmUgaGVyZSB0aGF0IGZhaWxlZCB0byBkZXRlY3QgYW55IG5vbi1yYW5kb21uZXNzLg0KDQpbXjZdOiBSdW1vdXJzIG9mIHRoZSBmbGF3ZWQgKGFuZCBleHBsb2l0YWJsZSkgUk5HIGFsZ29yaXRobXMgdXNlZCBpbiBVV08gaGF2ZSBmbG9hdGVkIGFyb3VuZCBzaW5jZSB0aGUgbGF1bmNoIG9mIEdhbWEgc2VydmVyLiBGb3IgZXhhbXBsZSwgb25lIGlkZWEgaXMgdGhhdCB0aGVyZSBhcmUgZ29vZCBhbmQgYmFkIHNlc3Npb25zLiBTbyB0aGF0IGlmIHlvdSBmYWlsLCB5b3Ugc2hvdWxkIGNsb3NlIHRoZSBkaWFsb2d1ZSBzY3JlZW4gYW5kIHN0YXJ0IG92ZXIgdW50aWwgeW91IGhpdCBhIGJldHRlciBzZXNzaW9uLiAoT3IgbWF5YmUgd2FpdCBhIGJpdCB1bnRpbCB0aGUgYmFkIHRpbWVzIGFyZSBvdmVyLiBXaG8ga25vd3MuKQ0KDQpUaGUgZWZmZWN0IG9mIGFkZXB0IGlzIGNsZWFybHkgdmVyeSBzbWFsbCBjb21wYXJlZCB0byB0aGUgSFJFIGVmZmVjdHMsIGFuZCBpbiBwcmFjdGljZSBkb2VzIG5vdCBtYXR0ZXIgdW5kZXIgSFJFIGNvbmRpdGlvbnMuIEhvd2V2ZXIsIG91dHNpZGUgb2YgSFJFIGl0IGRvZXMgbWF0dGVyLiBJbiBmYWN0LCBpZiB0aGUgYWRlcHQgZWZmZWN0IGlzIGluZGVlZCArIDElIEkgZ3Vlc3MgdGhlIGJhc2UgcmF0ZSB3aXRob3V0IGFkZXB0IHRpdGxlIGlzIDAuMSUuIEluIHRlcm1zIG9mIGV4cGVjdGVkIG1hdGVyaWFscyBjb25zdW1lZCBhbiBpbmNyZWFzZSBmcm9tIDAuMSUgdG8gZXZlbiAxJSBzdWNjZXNzIGlzIHN1YnN0YW50aWFsLCB3aGVyZWFzIGFuIGluY3JlYXNlIGZyb20gMzAgdG8gMzElIGlzIG5lZ2xpZ2libGUuIA0KDQpTaW5jZSB0aGUgYWRlcHQgZWZmZWN0IGlzIHNvIHNtYWxsIEkgZGlkIG5vdCB0cnkgdG8gdGVzdCBhbm90aGVyIHVuY2VydGFpbnR5OiBpZiBvbmUgY291bGQgbGVlY2ggdGhlIGFkZXB0IGVmZmVjdCBieSBiZWluZyBhcHByZW50aWNlIHRvIGFuIGFkZXB0LiBJdCBpcyBmZWFzaWJsZSB0aGF0IHRoaXMgaXMgdGhlIGNhc2UgKGxpa2UgZm9yIHNvbWUgb3RoZXIgdGl0bGVzKSwgYW5kIGNvdWxkIGJlIHdvcnRoIGV4cGxvaXRpbmcgZm9yIG9idGFpbmluZyBGQUIgdW5kZXIgbm9ybWFsIHNpdHVhdGlvbnMgd2hlbiB0aGUgSFJFIGVmZmVjdCBpcyBhYnNlbnQuIEhvd2V2ZXIsIG9uZSBjb3VsZCBub3QgdGhlbiBzaW11bHRhbmVvdXNseSBnZXQgdGhlICsxIGFsY2hlbXkgZnJvbSBiZWluZyBhcHByZW50aWNlIHRvIGFuIGFsY2hlbXkgbWVpc3Rlci4gSW4gdGhlIEZBQiBleHBlcmltZW50cyBhbGwgY2hhcmFjdGVycyB3ZXJlIGFwcHJlbnRpY2UgdG8gYSBtZWlzdGVyIGZvciB0aGUgKzEuIFRoZXJlIGlzIG5vIHJlYXNvbiB0byB0aGluayB0aGlzIGNvdWxkIGhhdmUgYWZmZWN0ZWQgdGhlIG91dGNvbWUgYmVjYXVzZSB0aGUgZWZmZWN0IG9uIHN1Y2Nlc3MgaXMgdGhlIG90aGVyIHdheSBhcm91bmQgLS0gZm9yIHRoZSBtZWlzdGVyLCBub3QgdGhlIGFwcHJlbnRpY2UsIGFuZCBzdWNoIGVmZmVjdHMgd291bGQgbm90IGhhdmUgYWZmZWN0ZWQgdGhlIGNoYW5jZSBvZiBodWdlIHN1Y2Nlc3MgYW55d2F5IChhY2NvcmRpbmcgdG8gdGhlIHByZXNlbnQgcmVwb3J0KS4NCg0KVGhlIGRhdGEgZnJvbSBGQUIgZXhwZXJpbWVudHMgb24gcm9iZSBzdWNjZXNzIHdlcmUgY29sbGVjdGVkIGluIGEgc2xpZ2h0bHkgZGlmZmVyZW50IHdheSBmcm9tIHRoZSBSb2JlIGV4cGVyaW1lbnRzLiBUaGUgZ2F0aGVyaW5nIG9mIGRhdGEgZnJvbSBvbmUgcGxheWVyIHdhcyB0ZXJtaW5hdGVkIHdoZW4gYSByb2JlIHdhcyBvYnRhaW5lZCBkdXJpbmcgdGhlIEZBQiBzdHVkeSwgd2hlcmVhcyBpbiB0aGUgUm9iZSBleHBlcmltZW50cyBpdCB3YXMgdGVybWluYXRlZCB3aGVuIG5vIG1vcmUgYmFzZSBjbG90aGVzIHdlcmUgbGVmdCBpbiB0aGUgaW52ZW50b3J5LiBUaHVzIG9uZSBjb3VsZCBhcmd1ZSB0aGF0IHRoZSBGQUIgc2V0dXAgd291bGQgYmlhcyB0aGUgcmVzdWx0cyBpbiBmYXZvdXIgb2Ygc3VjY2VzcyBjb21wYXJlZCB0byB0aGUgUm9iZSBzZXR1cC4gSG93ZXZlciwgaWYgdGhlIG9ic2VydmF0aW9ucyBhcmUgaW5kZXBlbmRlbnQgdGhpcyB3b3VsZCBpbiBmYWN0IG5vdCBjcmVhdGUgYSBiaWFzIGJlY2F1c2UgdGhlIGRhdGFzZXJpZXMgY291bGQgYmUgY29uc2lkZXJlZCBhcyBjb250aW51aW5nIGluIHRoZSBuZXh0IHBsYXllciwgaW4gdGhlIHNhbWUgd2F5IGFzIGZvciB0aGUgUm9iZSBleHBlcmltZW50cy5bXjddDQoNClteN106IE9ubHkgZm9yIHRoZSBsYXN0IGluZGl2aWR1YWwgd291bGQgYSBzbGlnaHQgYmlhcyBvY2N1ciwgd2hpY2ggaXMgbmVnbGlnaWJsZS4NCg0KSXQgd291bGQgaGF2ZSBiZWVuIGludGVyZXN0aW5nIHRvIHNlZSB3aGF0IHRoZSBpbmRpdmlkdWFsIGVmZmVjdCBvZiBjb3VydCBhbGNoZW1pc3QgaXMgY29tcGFyZWQgdG8gdGhlIGdsb2JhbCBlZmZlY3QgZm9yIGFsbCBzdXBwb3J0ZXJzIG9mIHRoZSBIUkUgcG9saWN5LiBJZiB0aGUgZWZmZWN0cyBmb3VuZCBpbiB0aGlzIHN0dWR5IGFyZSBhZGRpdGl2ZSBpdCBzaG91bGQgYmUgKzEwJS4gVGhpcyB3YXMgbm90IHBvc3NpYmxlIHRvIGZ1bGx5IHRlc3QgaGVyZSBzaW5jZSB0aGUgb25seSBpbmRpdmlkdWFsIHdpdGggdGhlIGFkdmlzb3IgZWZmZWN0IGFsc28gYnkgbmVjZXNzaXR5IGhhZCB0aGUgZ2xvYmFsIGVmZmVjdCBhY3RpdmUsIHNvIG5vIHBsYXllciBoYWQgb25seSB0aGUgSFJFIGFkdmlzb3IgcG9zaXRpb24uIFRoaXMgbXVzdCBiZSB0ZXN0ZWQgZHVyaW5nIGVsZWN0aW9ucyB3aGVyZSB0aGVyZSBpcyBubyBnbG9iYWwgYWxjaGVteSBzdWNjZXNzIHBvbGljeSBidXQgY291cnQgYWxjaGVtaXN0IHBvc2l0aW9uIGlzIHN0aWxsIGF2YWlsYWJsZS4gQnV0IHN1Y2ggZWxlY3Rpb25zIHNlZW0gdG8gYmUgcmFyZSAtLSBjb3VydCBhbGNoZW1pc3QgaXMgb2Z0ZW4gbm90IHByZXNlbnQgYXMgYW4gb3B0aW9uLiAoTm90ZSB0aGF0IHRoZXJlIGFyZSBza2lsbCByYW5rIGFuZCBqb2IgcmVxdWlyZW1lbnRzIGZvciBjZXJ0YWluIGFkdmlzb3Igcm9sZXMpLg0KDQpUaGlzIGlzIG5vdCBhIHByZXNzaW5nIGNvbmNlcm4gdGhvdWdoIHNpbmNlIHRoZSBvbmx5IGl0ZW0gd29ydGggbWFraW5nIGlzIHRoZSBhZGVwdCdzIHJvYmUsIGFzIGJhc2UgbWF0ZXJpYWwgZm9yIEFsY2hlbWlzdCByb2JlIEVYIChzZWUgW0FwcGVuZGl4XSgjcm9iZS1FWCkgZm9yIGhvdyB0byBtYWtlIFJvYmUgRVgpLiBBZnRlciB0aGlzIGV2ZW50IGl0IGlzIGZhaXIgdG8gc2F5IHdlIGhhdmUgYW4gb3Zlci1hYnVuZGFuY2Ugb2YgYWRlcHQncyByb2JlIGFuZCB0aGUgbWFya2V0IGZvciBBbGNoZW15IFJvYmUgRVggaXMgbm90IGVuZGxlc3MgKGFsdGhvdWdoIEkgbWFkZSBhbmQgc29sZCAxMjUgb2YgdGhlbSBhZnRlciBsYXN0IHRpbWUgd2UgaGFkIHRoaXMgSFJFIGVmZmVjdCB5ZWFycyBhZ28pLiBUaGUgcm9iZSBFWCBhbHNvIGhhcyBhIG5ldyBjb21wZXRpdG9yIG5vdyBpbiBmb3JtIG9mIFtUaWFuemh1IFRyZWFzdXJlIFN3b3JkXShodHRwOi8vdXdvZGJtaXJyb3IuaXZ5cm8ubmV0L2VnL21haW4ucGhwP2lkPTg4ODgyMTY3KSBmcm9tIGdyYW5kZSBnYW5hZG9yIHdoaWNoIGhhdmUgdGhlIHNhbWUgRVggcmFuayBhbmQgc2VsbHMgZm9yIG1vcmUgdGhhbiByb2JlIEVYLg0KDQpJbmRlZWQsIGFsc28gdGhlIG1hcmtldCBmb3IgRkFCIGlzIGxpbWl0ZWQgYW5kIGl0IHdpbGwgYmUgYSBjaGFsbGVuZ2Ugc2VsbGluZyBvZmYgdGhlIG9uZXMgbWFkZSBkdXJpbmcgdGhpcyBzdHVkeS4gQnV0IHRoaXMgd2FzIGRvbmUgZm9yIFNjaWVuY2UsIG5vdCBtb25leSBvZiBjb3Vyc2UuDQoNClRoZSBtYWluIGJvdHRsZW5lY2sgZm9yIG9idGFpbmluZyBtYXRzIGZvciBGQUIgdHVybmVkIG91dCwgdW5zdXJwcmlzaW5nbHksIHRvIGJlIHRoZSAqa25pZmUgbG9vc2luZyBpdHMgZ29sZCogbmVlZGVkIGZvciBnb2xkIHNob3J0LXN3b3JkLiBUbyBzZWN1cmUgbWF4aW11bSBudW1iZXIgb2Yga25pdmVzLCBJIGxldCBhIGNoYXJhY3RlciAqd2l0aG91dCogdGhlIEhSRSBlZmZlY3QgbWFrZSB0aGUga25pdmVzIHNvIHRoYXQgaXQgd291bGQgYmUgZmV3ZXIgZ29sZCBzd29yZHMgcHJvZHVjZWQgYW5kIHRodXMgbW9yZSBrbml2ZXMuIE9yIHNvIEkgdGhvdWdodCBpbiBteSBpZ25vcmFuY2UuIEFzIGl0IHR1cm5zIG91dCwgSFJFIHNob3VsZCBoYXZlIG5vIGVmZmVjdCBvbiBhIG1pbm9yIHN1Y2Nlc3Mgc3VjaCBhcyB0aGlzIGtuaWZlIChidXQgYWxjaGVteSByYW5rIHdvdWxkKSwgaWYgdGhlIHJlc3VsdHMgZnJvbSB0aGUgcm9iZSBleHBlcmltZW50cyBob2xkIGluIGdlbmVyYWwuIFVuZm9ydHVuYXRlbHkgSSBkaWQgbm90IGtlZXAgcmVjb3JkcyBvZiB0aGUgb3V0Y29tZXMsIGJ1dCBJIGNhbiBzdGF0ZSB0aGF0IHdheSB0b28gbWFueSB1bndhbnRlZCBodWdlIHN1Y2Nlc3MgY2FtZSBvdXQgb2YgdGhpcy4NCg0KSW4gdGhlIEZBQiBleHBlcmltZW50cyBhbnkgc21hbGwgZGlmZmVyZW5jZXMgYmV0d2VlbiB0aGUgImVhc3kiIHJlY2lwZXMgd2FzIGxpa2VseSBkdWUgdG8gcmFuZG9tIHZhcmlhdGlvbi4gQW4gb3V0bGllciB3YXMgYmx1ZSBvcmUgdGhhdCB3YXMgYWxtb3N0IGFzIGhhcmQgYXMgcm9iZSB0byBzdWNjZWVkIHdpdGggb24gYXZlcmFnZSwgYnV0IHRoZXJlIGlzIG5vIHJlYXNvbiB0byBiZWxpZXZlIHRoZSBibHVlIG9yZSByZWNpcGUgdG8gZGlmZmVyIGZvcm0gdGhlIG90aGVyIGNvbG91cmVkIG9yZXMuIE15IGJlc3QgZXN0aW1hdGUgaXMgdGhhdCB0aGV5IGFsbCBoYWQgMjUlIGNoYW5jZSBmb3Igc3VjY2Vzcywgd2hpY2ggc2hvdWxkIGdpdmUgNSUgYmFzZSBjaGFuY2UgaWYgdGhlIEhSRSBlZmZlY3QgaXMgdGhlIHNhbWUgZm9yIGFsbCBpdGVtcy4gQW4gZWFybGllciBodW5jaCB0aGF0IGtuaWZlIHdhcyBoYXJkZXIgdGhhbiB0aGUgb3RoZXJzIGFwcGVhcnMgdG8gYmUgd3JvbmcuIEl0IHByb2JhYmx5IG9ubHkgZ2F2ZSB0aGUgaW1wcmVzc2lvbiB0byBiZSBtb3JlIGRpZmZpY3VsdCBiZWNhdXNlIHRoZSBiYXNlIG1hdGVyaWFsIGlzIG11Y2ggaGFyZGVyIHRvIG9idGFpbiB0aGFuIGZvciB0aGUgb3RoZXJzLg0KDQpUaGVyZSBpcyBubyByZWFzb24gdG8gYmVsaWV2ZSB0aGF0IHRoZSBIUkUgZWZmZWN0IChvciBhbnkgb3RoZXIgZWZmZWN0KSBhY3RzIGRpZmZlcmVudGx5IGZvciBkaWZmZXJlbnQgaXRlbXMuIEluc3RlYWQsIHRoZSBsb3dlciBzdWNjZXNzIG9mIFJvYmUvQmlyZXR0YSBjb21wYXJlZCB0byBvdGhlciBpdGVtcyBpcyBsaWtlbHkgdG8gYmUgZHVlIHRvIGRpZmZlcmVudCBiYXNlIHByb2JhYmlsaXRpZXMsIHRvIHdoaWNoIGlzIGFkZGVkIGEgY29tbW9uIGZpeGVkIGluY3JlYXNlIGluIHRoZSBwcm9iYWJpbGl0eSBvZiBodWdlIHN1Y2Nlc3MgZnJvbSBBZGVwdCwgSFJFIGFuZCBhZHZpc29yLiBJbiBvdGhlciB3b3JkcywgSSBtYWtlIHRoZSBhc3N1bXB0aW9uIHRoYXQgdGhlIGVmZmVjdHMgYXJlIGFkZGl0aXZlIHRvIGVhY2ggb3RoZXIgYW5kIHRvIHRoZSBiYXNlIHJhdGUgYW5kIGFyZSB0aGUgc2FtZSBmb3IgYWxsIHRoZSBNQSBpdGVtcy4gQW4gb3V0bGluZSBvZiBhIHRoZW9yeSBmb3IgYWxjaGVteSBleHBlcmltZW50cywgc3VtbWFyaXNpbmcgd2hhdCBJIGhhdmUgZGlzY3Vzc2VkLCBpcyBwcmVzZW50ZWQgaW4gRmlndXJlIFxAcmVmKGZpZzpzdW1tYXJ5cGljdHVyZSkuDQoNCmBgYHtyIHN1bW1hcnlwaWN0dXJlLCBvdXQud2lkdGg9JzUwJScsIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLmNhcD0iUHJvcG9zZWQgdGhlb3J5IG9mIHRoZSBvdXRjb21lIG9mIGFsY2hlbXkgZXhwZXJpbWVudHMiLCBlY2hvID0gRkFMU0V9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygndGhlb3J5ZHJhd2luZy5wbmcnKQ0KYGBgDQoNClRoZSB0aGVvcnkgeWllbGRzIHNvbWUgcHJlZGljdGlvbnMgdGhhdCBjYW4gYmUgdGVzdGVkLiBJbiBwYXJ0aWN1bGFyIHRoYXQgdGhlIGluZGVwZW5kZW50IGVmZmVjdCBvZiBhZHZpc29yIHBvc2l0aW9uIGlzICsxMCUsIGFuZCB0aGF0IHRoZSBwcm9wb3J0aW9uIG9mIGZhaWx1cmVzIHdvdWxkIGJlIGFyb3VuZCA1NSUgd2l0aCBvbmx5IGFkdmlzb3IgZWZmZWN0IG9uLiBUaGUgY291cnQgYWxjaGVtaXN0IGFkdmlzb3IgcG9zaXRpb24gaXMgcmFyZSwgYW5kIEkgYW0gbm90IGNlcnRhaW4gaWYgaXQgYWN0dWFsbHkgY2FuIGJlIG9idGFpbmVkIGZyb20gYW4gZW1wZXJvciB0aGF0IGRvZXMgbm90IGhhdmUgdGhlIHN1cHBvcnQgYWxjaGVteSBwb2xpY3kuIEJ1dCBpZiBpdCBjYW4sIGl0IHdvdWxkIGJlIGludGVyZXN0aW5nIHRvIGRvIG1vcmUgUm9iZSBleHBlcmltZW50cyB3aXRoIG9ubHkgdGhlIEFkdmlzb3IgZWZmZWN0IG9uLiBFYXNpZXIgdG8gdGVzdCBpcyB0aGF0IHByb2Nlc3NlZCBsdW1iZXIgYW5kIHRoZSBvdGhlciBub24tUm9iZS9CaXJldHRhIHNob3VsZCB5aWVsZCA1JSBNQSBpdGVtcyBpbiBleHBlcmltZW50cyBjb25kdWN0ZWQgb3V0c2lkZSBIUkUvYWR2aXNvciB3aXRob3V0IEFkZXB0LCBhbmQgNiUgd2l0aCBBZGVwdCB0aXRsZSBvbi4gSXQgd291bGQgYWxzbyBiZSBpbnRlcmVzdGluZyB0byBsb29rIGF0IHRoZSAibWlub3IgaHVnZSBzdWNjZXNzZXMiIGZyb20gdGhlc2UgZXhwZXJpbWVudHMsIHN1Y2ggYXMgbm9uLUZBQiBhcm1vdXIgcGxhdGVzIGFuZCBob3cgdGhvc2UgZml0IGludG8gdGhlIHBpY3R1cmUuIFRoZSBSb2JlIGFuZCBCaXJldHRhIHJlY2lwZXMgZG8gbm90IGhhdmUgbXVsdGlwbGUgaHVnZSBzdWNjZXNzIGNhdGVnb3JpZXMsIHNvIEkgaGF2ZSBubyBkYXRhIG9uIHRoaXMuIEFub3RoZXIgdW5leHBsb3JlZCBpc3N1ZSBpcyBpZiB0aGUgcmF0aW8gb2YgbWlub3Igc3VjY2VzcyB0byBmYWlsdXJlL2h1Z2Ugc3VjY2VzcyBpcyBmaXhlZCBhdCAyOjMgYWxzbyBmb3Igb3RoZXIgcmVjaXBlcyB0aGFuIFJvYmUuDQoNCiMgQ29uY2x1c2lvbnMNCg0KRGVzcGl0ZSBzb21lIHNob3J0Y29taW5ncywgdGhlIHJlc3VsdHMgcHJlc2VudGVkIGhlcmUgc2hvdyBzZXZlcmFsIGNsZWFyIHBhdHRlcm5zLiBNeSBjb25jbHVzaW9uIChzdW1tYXJpc2VkIGluIEZpZ3VyZSBcQHJlZihmaWc6c3VtbWFyeXBpY3R1cmUpKSBpcyB0aGF0IHRoZSBjaGFuY2Ugb2YgbWlub3Igc3VjY2VzcyBpcyBmaXhlZCBhdCAzNSUgb3IgNDAlIGFuZCBjYW5ub3QgYmUgYWx0ZXJlZCBieSBhbnkga25vd24gZmFjdG9yLCBhbmQgdGhhdCBpbmNyZWFzaW5nIHRoZSBwcm9iYWJpbGl0eSBvZiAqaHVnZSBzdWNjZXNzKiB0aGVyZWZvcmUgaXMgdGhlIHNhbWUgYXMgbG93ZXJpbmcgdGhlIHByb2JhYmlsaXR5IG9mIGZhaWx1cmUuIFRoZSBjaGFuY2Ugb2YgaHVnZSBzdWNjZXNzIGNhbiBiZSBtb2RpZmllZCBhcyBmb2xsb3dzOg0KDQotICAgQWRlcHQ6ICsxJQ0KLSAgIEhSRSBhZHZpc29yIGVmZmVjdDogKzEwJQ0KLSAgIEhSRSBnZW5lcmFsIGVmZmVjdDogKzIwJQ0KLSAgIE94Zm9yZDogbm90IGFwcGxpY2FibGUgdG8gYWxjaGVteSBleHBlcmltZW50cw0KLSAgIEVYOiBub3QgYXBwbGljYWJsZSB0byBhbGNoZW15IGV4cGVyaW1lbnRzDQotICAgUGF5bWFzdGVyIGFpZGU6IG5vdCBhcHBsaWNhYmxlIHRvIGFsY2hlbXkgZXhwZXJpbWVudHMNCi0gICBTa2lsbCByYW5rOiBubyBlZmZlY3Qgb24gaHVnZSBzdWNjZXNzIG9yIGZhaWx1cmUsIGJ1dCBtb2RlcmF0ZSBlZmZlY3QgKndpdGhpbiogbWlub3Igc3VjY2Vzcw0KDQojIEFja25vd2xlZGdtZW50cw0KDQpJIHdhbnQgdG8gdGhhbmsgdGhvc2UgdGhhdCBsZW50IG1lIHRoZWlyIGNoYXJhY3RlcnMgZm9yIHRoZSBhZHZhbmNlbWVudCBvZiBzY2llbmNlLiBCaWcgdGhhbmsgeW91IHRvIE1hcnNhbGkgdGhhdCBnYXZlIG1lIHNvbWUgbXVjaCBuZWVkZWQgZmluZSBkeWUgYW5kIGNhbm5lZCBzaWxrIHRocmVhZCwgYW5kIHRvIEFsdGF2aXN0YSwgR3VpbGRlciwgTWFyc2FsaSBhbmQgVGFyZHlNY0dvcm1sZXNzIGZvciBkaXNjdXNzaW9ucyBhYm91dCB0aGlzIGFuZCB0aGF0Lg0KDQojIEFwcGVuZGljZXMgeyNhcHBlbmRpY2VzfQ0KDQojIyBIb3cgdG8gbWFrZSBpdGVtcyBmb3IgRkFCIHsjRkFCLWluZ3JlZGllbnRzfQ0KPGJ1dHRvbiBjbGFzcz0iYnRuIGJ0bi1wcmltYXJ5IiBkYXRhLXRvZ2dsZT0iY29sbGFwc2UiIGRhdGEtdGFyZ2V0PSIjQmxvY2tOYW1lIj4NCg0KU2hvdy9IaWRlDQo8L2J1dHRvbj4NCg0KOjo6IHsjQmxvY2tOYW1lIC5jb2xsYXBzZX0NCmBgYHtyLCBvdXQud2lkdGg9Jzc1JScsIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLmNhcD0iUmVjaXBlcyBhbmQgYmVzdCBwcmFjdGljZXMgZm9yIG1ha2luZyBGQUIgaXRlbXMiLCBlY2hvID0gRkFMU0V9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygnRkFCaW5ncmVkaWVudHMuanBnJykNCmBgYA0KOjo6DQoNCg0KIyMgSG93IHRvIG1ha2UgUm9iZSBFWCBmcm9tIEFkZXB0J3MgUm9iZSB7I3JvYmUtRVh9DQo8YnV0dG9uIGNsYXNzPSJidG4gYnRuLXByaW1hcnkiIGRhdGEtdG9nZ2xlPSJjb2xsYXBzZSIgZGF0YS10YXJnZXQ9IiNCbG9ja05hbWUyIj4NCg0KU2hvdy9IaWRlDQo8L2J1dHRvbj4NCg0KOjo6IHsjQmxvY2tOYW1lMiAuY29sbGFwc2V9DQpgYGB7ciwgb3V0LndpZHRoPSc3NSUnLCBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy5jYXA9IkhvdyB0byBtYWtlIFJvYmUgRVgiLCBlY2hvID0gRkFMU0V9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygnUm9iZUVYLmpwZycpDQpgYGANCjo6Og0KDQojIyBGQUIgcmF3IGRhdGEgeyNmYWItcmF3LWRhdGF9DQoNCjxidXR0b24gY2xhc3M9ImJ0biBidG4tcHJpbWFyeSIgZGF0YS10b2dnbGU9ImNvbGxhcHNlIiBkYXRhLXRhcmdldD0iI0Jsb2NrTmFtZTMiPg0KDQpTaG93L0hpZGUNCjwvYnV0dG9uPg0KDQo6OjogeyNCbG9ja05hbWUzIC5jb2xsYXBzZX0NCmBgYHtyfQ0KRFQ6OmRhdGF0YWJsZShGQUJbLC0xXSwgb3B0aW9ucyA9IGxpc3QocGFnZUxlbmd0aCA9IDEwKSwgY2FwdGlvbiA9ICdGQUIgZXhwZXJpbWVudHMgcmF3IGRhdGEuIFZhbHVlcyBhcmUgbnVtYmVyIG9mIGF0dGVtcHRzIG5lZWRlZCcpDQpgYGANCjo6Og0KDQojIyBSb2JlIHJhdyBkYXRhIHsjcm9iZS1yYXctZGF0YX0NCg0KPGJ1dHRvbiBjbGFzcz0iYnRuIGJ0bi1wcmltYXJ5IiBkYXRhLXRvZ2dsZT0iY29sbGFwc2UiIGRhdGEtdGFyZ2V0PSIjQmxvY2tOYW1lNCI+DQoNClNob3cvSGlkZQ0KPC9idXR0b24+DQoNCjo6OiB7I0Jsb2NrTmFtZTQgLmNvbGxhcHNlfQ0KYGBge3IgRkFCYXBwZW5kaXh9DQpEVDo6ZGF0YXRhYmxlKFJvYmUsIG9wdGlvbnMgPSBsaXN0KHBhZ2VMZW5ndGggPSAxMCksIGNhcHRpb24gPSAnUm9iZSBleHBlcmltZW50cyByYXcgZGF0YScpDQpgYGANCjo6Og0KDQojIyBSdW5zLXRlc3RzIHsjcnVucy10ZXN0c30NCg0KPGJ1dHRvbiBjbGFzcz0iYnRuIGJ0bi1wcmltYXJ5IiBkYXRhLXRvZ2dsZT0iY29sbGFwc2UiIGRhdGEtdGFyZ2V0PSIjQmxvY2tOYW1lNSI+DQoNClNob3cvSGlkZQ0KPC9idXR0b24+DQoNCjo6OiB7I0Jsb2NrTmFtZTUgLmNvbGxhcHNlfQ0KYGBge3J9DQpydW5zVGFibGVCYXRjaA0KYGBgDQoNCmBgYHtyfQ0KcnVuc1RhYmxlQ29uZA0KYGBgDQo6OjoNCg0KIyMgQXV0by1jb3JyZWxhdGlvbiB7I2F1dG8tY29ycmVsYXRpb259DQoNCjxidXR0b24gY2xhc3M9ImJ0biBidG4tcHJpbWFyeSIgZGF0YS10b2dnbGU9ImNvbGxhcHNlIiBkYXRhLXRhcmdldD0iI0Jsb2NrTmFtZTYiPg0KDQpTaG93L0hpZGUNCjwvYnV0dG9uPg0KDQo6OjogeyNCbG9ja05hbWU2IC5jb2xsYXBzZX0NCmBgYHtyIEFDRndob2xlLCBmaWcuaGVpZ2h0PSA0LCBmaWcud2lkdGg9IDUsIGZpZy5zaG93PSdob2xkJywgZmlnLmNhcD0gIkF1dG8tY29ycmVsYXRpb24gKHVwcGVyIHBhbmVsKSBhbmQgcGFydGlhbCBhdXRvLWNvcnJlbGF0aW9uIChsb3dlciBwYW5lbCkgZnVuY3Rpb24gcGxvdCBmb3IgdGhlIHdob2xlIFJvYmUgc2VxdWVuY2UifQ0KQUNGd2hvbGUNClBBQ0Z3aG9sZQ0KYGBgDQoNCmBgYHtyIEFDRmJhdGNoLCBmaWcuaGVpZ2h0PSAxNiwgZmlnLndpZHRoPSA4LCBmaWcuY2FwPSAiQXV0by1jb3JyZWxhdGlvbiBmdW5jdGlvbiBwbG90cyBmb3IgUm9iZSBiYXRjaGVzIn0NCkJhdGNoQUNGDQpgYGANCg0KYGBge3IgQUNGY29uZGl0aW9uLCBmaWcuaGVpZ2h0PSA4LCBmaWcud2lkdGg9IDgsIGZpZy5jYXA9ICJBdXRvLWNvcnJlbGF0aW9uIGZ1bmN0aW9uIHBsb3RzIGZvciBSb2JlIGNvbmRpdGlvbnMifQ0KQ29uZGl0aW9uQUNGDQpgYGANCg0KYGBge3IgUEFDRmJhdGNoLCBmaWcuaGVpZ2h0PSAxNiwgZmlnLndpZHRoPSA4LCBmaWcuY2FwPSAiUGFydGlhbCBhdXRvLWNvcnJlbGF0aW9uIGZ1bmN0aW9uIHBsb3RzIGZvciBSb2JlIGJhdGNoZXMifQ0KQmF0Y2hQQUNGDQpgYGANCg0KYGBge3IgUEFDRmNvbmRpdGlvbiwgZmlnLmhlaWdodD0gOCwgZmlnLndpZHRoPSA4LCBmaWcuY2FwPSAiUGFydGlhbCBhdXRvLWNvcnJlbGF0aW9uIGZ1bmN0aW9uIHBsb3RzIGZvciBSb2JlIGNvbmRpdGlvbnMifQ0KQ29uZGl0aW9uUEFDRg0KYGBgDQo6OjoNCg0KIyMgUiBjb2RlIGZvciB0aGlzIHJlcG9ydCB7I3ItY29kZX0NCg0KYGBge3IgcmVmLmxhYmVsPWtuaXRyOjphbGxfbGFiZWxzKCksIGVjaG89VFJVRSwgZXZhbD1GQUxTRX0NCmBgYA0KDQojIyBTZXNzaW9uIGluZm9ybWF0aW9uIHsjc2Vzc2lvbi1pbmZvfQ0KDQpgYGB7cn0NCnNlc3Npb25pbmZvOjpzZXNzaW9uX2luZm8oKQ0KYGBgDQoNCiMgRm9vdG5vdGVzDQo=