‘Reconstructing Dunkleosteus terrelli (Placodermi: Arthrodira): A New Look for an Iconic Devonian Predator’

Appendix 3 (Supplementary Analyses)

Russell Engelman

2023-11-27

Date Created: 27 November, 2023

Last Modified: 20 August, 2024

This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see http://rmarkdown.rstudio.com.

To obtain the original R code for this analysis, select the “Code” button at the top of the document and click “Download Rmd”. This will download the original code in .rmd format. This format can be opened in programs like RStudio as well as general text editors. To replicate this document, place this code and associated data files (“1343_Appendix 4.xlsx”) in a single folder, open this file in RStudio, and then click the “Knit” button.

1 Loading in Data

Saving Ramanujan’s Approximation of the Perimeter of an Ellipse

ramanujan.approx<-function(x,y) {
  majoraxis=x/2;
  minoraxis=y/2;
  pi*((majoraxis+minoraxis)-
        ((3*(majoraxis-minoraxis)^2)/
           (10*(x+minoraxis)+sqrt(x^2+14*majoraxis*minoraxis+minoraxis^2))))
}

Saving Custom Formula for Regression Statistics

regression.stats<-function(fit){
  formula<-fit$call;
  log_trans<-dplyr::case_when(substr(colnames(fit$model[1]),1,5)=="log10"~"log10",
                       substr(colnames(fit$model[1]),1,4)=="log("~"ln",
                       TRUE~"none");
  y<-switch(log_trans,"log10"=10^fit$model[,1],"ln"=exp(fit$model[,1]),"none"=fit$model[,1]);
  fitted<-switch(log_trans,"log10"=10^fitted(fit),"ln"=exp(fitted(fit)),"none"=fitted(fit));
  abserror<-abs(fitted-y)/fitted;
  QMLE<-ifelse(log_trans=="none",
               NA,
               ifelse(log_trans=="log10",
                      10^((sigma(fit)^2)/2),
                      exp((sigma(fit)^2)/2)));
  smear<-ifelse(log_trans=="none",
                NA,
                ifelse(log_trans=="log10",
                       sum(10^fit$residuals)/nrow(fit$model),
                       sum(exp(fit$residuals))/nrow(fit$model)));
  RE<-ifelse(log_trans=="none",
             NA,
             mean(y)/mean(fitted));
  CF<-ifelse(log_trans=="none",
             NA,
             (RE+smear+QMLE)/3);
  adjPE<-ifelse(log_trans=="none",
                NA,
                mean(abs((fitted*CF)-y)/(fitted*CF)));
  SEE<-ifelse(log_trans=="log10",
              10^(2+sigma(fit))-100,
              exp(sigma(fit)+4.6052)-100);
  summary<-summary(fit);
  statistics<-data.frame("N"=nrow(fit$model),
                         "df"=fit$df.residual,
                         "r2"=round(summary(fit)$r.squared,4),
                         "adjr2"=round(summary(fit)$adj.r.squared,4),
                         "AIC"=round(AIC(fit),0),"BIC"=round(BIC(fit),0),
                         "logLik"=round(logLik(fit),0),
                         "PE"=round(mean(abserror)*100,2),QMLE=round(QMLE,3),
                         smear=round(smear,3),RE=round(RE,3),CF=round(CF,3),
                         "adjPE"=round(mean(adjPE)*100,2),
                         "SEE"=round(SEE,2),
                         row.names=deparse(substitute(fit)));
  return(statistics)
}

Loading in Data

data_recon<-read_xlsx("1343_Appendix_4.xlsx") %>%
  rename(clade=Clade,order=Order,higher_group="Higher Order Clade",family="Family",
         shape=Shape,habitat=Habitus,extinct=Extinct,genus=Genus,species=Species,
         specimen=Specimen,
         body_mass="Weight (g)",
         total_length="Total Length (cm)",
         fork_length="Fork Length (cm)",
         precaudal_length="Precaudal Length (cm)",
         head_length="Head Length (cm)",
         body_depth="Body Depth (cm)",
         prepectoral_length="Prepectoral Length (cm)",
         prepelvic_length="Prepelvic Length",
         pec_base="Pectoral Fin Base (cm)",
         SVL="Snout-Vent Length (cm)",
         preanal_length="Preanal Length (cm)",
         peduncle_height="Caudal Peduncle Depth (cm)")%>%
  mutate(taxon=paste0(genus,"_",species))

Creating Rhizoprionodon silhouette

rhizo<-data.frame(x=c(0.4007578,0.3946954,0.3887508,0.382929,0.3773131,0.3721988,0.3675113,0.3629002,0.3583384,0.3538188,0.3493424,0.344916,0.3404293,0.3357709,0.3308291,0.3253511,0.3189982,0.3122617,0.3053785,0.2984326,0.2914573,0.2844737,0.2774993,0.2705516,0.2636601,0.2567807,0.2498727,0.2429436,0.2360215,0.2291405,0.2222616,0.2153569,0.2084741,0.2016375,0.1948848,0.1880772,0.1812338,0.1744288,0.1676627,0.1608254,0.1540911,0.1473995,0.1406738,0.1340172,0.1274724,0.1209183,0.1142861,0.1075532,0.10072,0.09381659,0.08693189,0.08011189,0.07337916,0.066796,0.0603155,0.0535914,0.04681221,0.04012917,0.03342231,0.02663037,0.01989815,0.01327379,0.006823727,0.0008294744,0,0.005352874,0.0116654,0.01834354,0.02497352,0.03148309,0.03802411,0.04464998,0.05136349,0.05813275,0.06480448,0.07180219,0.07882237,0.08046313,0.0860565,0.09298445,0.09993063,0.1068777,0.1138192,0.120756,0.1276884,0.1346166,0.1415398,0.1484563,0.1553617,0.162258,0.1692408,0.1762649,0.183284,0.1901262,0.1970588,0.2040668,0.2110424,0.2178543,0.224394,0.2306892,0.2358916,0.2387133,0.2413728,0.2441582,0.2470131,0.2499318,0.2529363,0.2560034,0.2588352,0.2621672,0.2656913,0.2691895,0.2726331,0.2760466,0.2798983,0.2851486,0.2909202,0.2966793,0.2974377,0.2977752,0.2980597,0.2983595,0.2987163,0.2991733,0.2998496,0.3013401,0.3031798,0.304369,0.3049683,0.3083117,0.3142919,0.3213169,0.3283423,0.3353666,0.3423856,0.3493983,0.3564045,0.3634039,0.3703963,0.3773814,0.3843587,0.3913275,0.3982862,0.405233,0.4121648,0.4190758,0.4259554,0.432777,0.439605,0.44649,0.4534098,0.4602782,0.467119,0.4741326,0.4809811,0.4874313,0.493718,0.499973,0.5062312,0.5124573,0.5177527,0.5223012,0.5265004,0.5306674,0.5349406,0.5403294,0.5473082,0.5543216,0.561337,0.5683531,0.5753715,0.5823932,0.5894184,0.5964402,0.6034181,0.6103072,0.616967,0.6232154,0.6291671,0.6352319,0.6417947,0.6487681,0.6552499,0.6588087,0.6618288,0.6668433,0.6723809,0.6784414,0.6844551,0.6909902,0.697909,0.7048814,0.7118569,0.7188161,0.7257901,0.7327971,0.7398162,0.7467872,0.7523764,0.7573401,0.7619737,0.766102,0.7707246,0.7750986,0.779709,0.7845408,0.7896139,0.7951749,0.8012544,0.8075934,0.8141272,0.8208852,0.8266883,0.8284469,0.8287026,0.8273061,0.8255916,0.824009,0.8227464,0.8233034,0.8280211,0.8337875,0.8398104,0.8459381,0.8521208,0.8583221,0.8645029,0.8706353,0.8766755,0.8826232,0.8885799,0.8946842,0.9009177,0.9072566,0.9136827,0.9201044,0.9262665,0.9321909,0.9382273,0.9435401,0.9493351,0.9555131,0.9620498,0.9678954,0.9716326,0.9759521,0.9808132,0.9857814,0.9903338,0.9937468,0.9975843,1,0.9945907,0.9876402,0.9806249,0.9736297,0.9666723,0.9597628,0.9528873,0.946031,0.9391853,0.9323455,0.925508,0.9186626,0.9118087,0.9049476,0.898077,0.8911929,0.8843274,0.8774926,0.8706879,0.8638077,0.8569091,0.8501716,0.8434315,0.8366172,0.8298535,0.8231429,0.8164895,0.8098143,0.8031271,0.7964602,0.7898276,0.7832661,0.7767062,0.7701209,0.7635237,0.7569343,0.7503637,0.7436362,0.7366103,0.7295843,0.7225584,0.7155323,0.7086713,0.7031059,0.6966117,0.6911706,0.6861978,0.6816191,0.6767815,0.6701159,0.6638064,0.6574758,0.650753,0.6437554,0.6367315,0.6297064,0.6226806,0.6156547,0.6086304,0.6016101,0.5945989,0.5876041,0.5806394,0.5737211,0.5668213,0.5599164,0.5530069,0.5460954,0.539195,0.5323047,0.5254344,0.5185569,0.5116648,0.5047543,0.497865,0.4910337,0.4841394,0.4771916,0.4702347,0.4633041,0.4564551,0.4495968,0.4434005,0.4389519,0.4340479,0.4294488,0.4252657,0.42242,0.4212366,0.4202908,0.4193971,0.4184924,0.4175307,0.4164942,0.4153371,0.4137883,0.4112077,0.4073199),
                  y=c(0.3278792,0.3243291,0.3205844,0.3166521,0.3124316,0.3076504,0.3024168,0.2971157,0.2917721,0.2863928,0.2809775,0.2755212,0.2701146,0.2648557,0.2598637,0.2554783,0.2525117,0.2505284,0.2491256,0.2480705,0.2472294,0.2464598,0.2456105,0.2445679,0.2432036,0.2417769,0.2404955,0.239333,0.2381297,0.2367203,0.235292,0.2339926,0.2325824,0.2309641,0.2290265,0.2272897,0.2256988,0.2239516,0.2220627,0.220459,0.2184564,0.2163149,0.2142838,0.2120662,0.2095113,0.2069803,0.2046627,0.2026577,0.2010268,0.1997225,0.1983231,0.1966367,0.1946309,0.1921823,0.1894819,0.1874507,0.1856063,0.1834446,0.1813549,0.1795576,0.1775492,0.1752104,0.17243,0.1687951,0.1627831,0.1582755,0.1552146,0.1530378,0.1507147,0.1480721,0.145508,0.143172,0.1411018,0.1392206,0.1370943,0.1364945,0.1362103,0.1304006,0.1272447,0.1260762,0.1250204,0.1239706,0.1228843,0.1217682,0.1206261,0.1194578,0.1182601,0.1170249,0.1157293,0.1143879,0.1136473,0.1135211,0.1132539,0.1117557,0.1106748,0.1101752,0.1093583,0.1076638,0.1051033,0.1019925,0.09735957,0.09094869,0.08444597,0.07799575,0.07157596,0.06518496,0.05883386,0.05251301,0.04608548,0.03990091,0.03382267,0.02772949,0.02160533,0.01546515,0.009593715,0.004949856,0.0009464814,0,0.006975124,0.01399291,0.02101316,0.0280327,0.03504963,0.04206063,0.04905319,0.05590182,0.06267992,0.0696009,0.07659,0.08264781,0.08577069,0.08565095,0.0855796,0.08572504,0.08603347,0.08646302,0.08698991,0.08760067,0.08828592,0.08904189,0.08986712,0.09076166,0.09173123,0.09278255,0.09392846,0.09519326,0.09661949,0.09829827,0.09995211,0.1013509,0.1025665,0.1040412,0.1055818,0.1053321,0.103851,0.1010741,0.09793739,0.0947374,0.09154378,0.09166042,0.09624836,0.1016003,0.1072325,0.1128893,0.1184659,0.1226128,0.1233818,0.1238001,0.1241855,0.1245583,0.1248829,0.1251254,0.125216,0.1250079,0.1242168,0.1228476,0.120633,0.1174306,0.1136984,0.1101597,0.1076929,0.1071488,0.109421,0.1154495,0.1216422,0.1265557,0.1308744,0.1344168,0.1380435,0.1405314,0.1417416,0.142606,0.1434455,0.1444102,0.1452456,0.1457588,0.1460627,0.1455665,0.1413847,0.1364138,0.1311345,0.1254529,0.1201673,0.1146694,0.1093687,0.1042683,0.09940931,0.09512769,0.09161121,0.08858448,0.08600548,0.08410858,0.08641954,0.09319907,0.1001984,0.1070805,0.1138941,0.1207391,0.1276489,0.1345353,0.1396749,0.1436834,0.1473005,0.150737,0.1540745,0.1573772,0.1607178,0.1641469,0.1677351,0.1714754,0.1752003,0.1786779,0.1819187,0.1849483,0.1877886,0.1906357,0.1940025,0.1977758,0.201364,0.2059392,0.205114,0.2017685,0.1992707,0.2023425,0.2082863,0.2138143,0.2188862,0.2238539,0.2291945,0.2353298,0.2412048,0.2471672,0.2514645,0.2522377,0.2518744,0.251222,0.250248,0.2489764,0.2475309,0.245996,0.2444142,0.2428078,0.2411917,0.2396098,0.2380638,0.2365506,0.235081,0.2336772,0.2321849,0.2305573,0.2288116,0.2273907,0.2260648,0.2241088,0.2221322,0.2204212,0.2185203,0.2164401,0.2141827,0.2119906,0.2098351,0.2076182,0.2053003,0.2027901,0.2002741,0.1978254,0.195408,0.1929703,0.1904822,0.1889234,0.1888989,0.1888744,0.1888681,0.1888681,0.1892572,0.1934248,0.1960751,0.2005018,0.2054635,0.210788,0.2152836,0.2132566,0.2101671,0.2071225,0.2051481,0.2045656,0.2043968,0.2042932,0.2042496,0.20429,0.2044366,0.2047167,0.2051657,0.2058259,0.2067465,0.2079698,0.2092949,0.210594,0.2118677,0.2131297,0.2144533,0.2158272,0.2172971,0.218733,0.2200978,0.2213665,0.2227444,0.2243822,0.2257254,0.2267697,0.2277532,0.2289027,0.2304566,0.2319635,0.2344573,0.2398777,0.244908,0.2502181,0.25586,0.2622212,0.269145,0.276107,0.2830759,0.2900432,0.2970033,0.3039523,0.310882,0.3177296,0.3242609,0.3298849))

2 Methods

Comparative data in these analyses were drawn from a large sample of extant fishes coming from a wide variety of sources, including fluid-preserved specimens directly measured from the collections of the Cleveland Museum of Natural History (CMNH), Florida Fish and Wildlife Research Institute (FSBC), and the Ohio State University Museum of Biodiversity (OSUM). Other data were collected from the previously published literature, either as reported values or measured from photographs published in those studies. Similarly, for extinct arthrodires a combination of directly observed specimens and the previously published literature was used.

Specific attention is brought to the work of Randall (1997), who made his photographic collection of nearly 10,000 fishes with associated length (http://www.fishbase.org/search.php). Not all 10,000+ fishes in Randall (1997) were able to be measured due to time constraints, but an attempt was made to include…

  1. A representative collection of fish diversity
  2. As many large-bodied fish species as possible (as measurements for these taxa tend to be rare)
  3. As many basal fish lineages as possible within this sample (e.g., chondrichthyans, megalopids, clupeids, etc.), because those taxa are likely to better compare with arthrodires than specialized acanthopterygians
data_recon %>%
  filter(length_as=="total length") %>%
  mutate(reference_2 = factor(case_when(Reference == "Present Study" ~ "First-hand observation",
                               Reference %in% c("Randall 1997","Randall 1997, Mihalitsis and Bellwood 2019") ~ "Randall 1997",
                               .default = "Other prior literature sources (reported or measured from figures)"),
                              ordered=T,levels=c("First-hand observation","Randall 1997","Other prior literature sources (reported or measured from figures)"))) %>%
  group_by(reference_2) %>%
  summarise(N=n()) %>%
  kable(caption="Sources of data used in this analysis",col.names = c("Source","N")) %>% 
  kable_styling()
Table 2.1: Sources of data used in this analysis
Source N
First-hand observation 307
Randall 1997 519
Other prior literature sources (reported or measured from figures) 1873

This results in a total of nearly 2500 distinct observations representing 888 fish taxa. The term “observations” is preferred over specimens here as some studies report measurements of their material as mean proportion values (% total length or standard length) of the entire sample, as is often the case in studies of modern fishes. However, because these values are reported as proportions of total length, rather than measurements, they can still be converted to a form where they can be compared with other fishes.

data_recon %>%
  group_by(taxon) %>%
  summarise(n=n()) %>%
  ungroup() %>%
  summarise(taxon=sum(!is.na(taxon)),n=sum(n)) %>%
  kable(caption="Total count of observations examined",
        col.names=c("Taxa","Observations"),align="c") %>%
  kable_styling()
Table 2.2: Total count of observations examined
Taxa Observations
913 2722

Most of this data was collected alongside a previous study by the author (Engelman 2023), and the reader is encouraged to check the methods of that paper for more details. For more details on how the measurements were collected, see Engelman (2023). Figure 4 of that study in particular provides a graphic showing how several measurements were collected Methods of measuring of SVL require additional clarification and are discussed in the section “Measuring SVL”.

All measurements taken by the author (including those measured from the figures in Randall 1997) were measured relative to the anteroposterior axis of the animal (see Engelman 2023: fig. 4), rather than point to point or over body curvature. However, it is possible some reported measurements in the literature may be distorted if they were taken point to point or measured over curves. Reporting how measurements are taken is typically not done in ichthyological studies. This possible bias is worth noting but cannot be controlled for in the current dataset, though its effects seem to be minor.

Several figures in these supplementary analyses use a silhouette of Rhizoprionodon terraenovae created by Nathan Hermann through PhyloPic (https://www.phylopic.org/images/afa6bf86-bfd1-40a3-a78b-a43e396d77aa/rhizoprionodon-terraenovae). R. terraenovae was chosen as a representative fish because Rhizoprionodon was closest to the mean relative prepectoral length, prepelvic length, and snout-vent length of the entire non-acanthopterygian sample.

Measurement Variable Name Definition
Total length total_length Anteroposterior length from anterior tip of rostrum to posterior tip of caudal fin in natural position (when possible)
Fork length fork_length Length from anterior tip of rostrum to notch in caudal fork between upper and lower caudal fin lobes. Recorded as NA for taxa without a caudal notch.
Standard length precaudal_length Length from anterior tip of rostrum to posterior tip of caudal peduncle
For sharks and arthrodires: to caudal peduncle
For osteichthyans to end of hypurals (which sometimes extend beyond caudal peduncle)
Head length head_length Length from anterior tip of rostrum to posterior margin of branchial cavity. Head length and internal anatomy are homologous among the groups examined due to the conserved position of the neurocranium and branchial arches (see manuscript) but the definition of external landmarks can vary slightly if a cheek plate or operculum covers the gill arches externally.
For sharks: from snout to opening of terminal gill arch
For osteichthyans: from snout to posterior end of operculum
For arthrodires: from snout to cranio-thoracic joint
Orbit-opercular Length ool Length of the head minus preorbital length
Body depth body_depth Maximum height of trunk
Fineness ratio (f) fineness Standard length divided by body depth
Prepectoral length prepectoral_length Distance from the tip of the snout to the origin of the pelvic fins parallel to the the anteroposterior axis
Pectoral fin base length pec_base Anteroposterior length of pectoral fin base
For sharks: length of fleshy pectoral fin base on living animal
For arthrodires: Length of pectoral fenestra on anterior ventral lateral plate or external face of scapulocoracoid (if preserved)
For osteichthyans: not considered due to differences in fin position (usually obliquely oriented to anteroposterior axis), structure (much narrower base), and function (oscillation rather than fixed fins in most taxa)
Prepelvic length prepelvic_length Distance from the tip of the snout to the origin of the pelvic fins parallel to the the anteroposterior axis
Snout-vent length (SVL) SVL Distance from the tip of the snout to the level of the vent parallel to the anteroposterior axis
Preanal (fin) length preanal_length Distance from the tip of the snout to the anal fin origin parallel to the anteroposterior axis. Notably not length to the vent.
Caudal peduncle height peduncle_height Minimum height of caudal peduncle

In addition to the various extant fishes considered in this study, representatives of 8 species of the extinct fish order Ichthyodectiformes were included in this analysis. Ichthyodectiforms were considered because they have hyper-elongated bodies with small heads relative to their trunks, representing some of the most extreme head-body proportions seen among any living or extinct non-anguilliform fish. Other extinct elongate-bodied fish groups (e.g., saurichthyids) do not show these kinds of proportions (e.g., Kogan et al. 2015). Ichthyodectiforms were also singled out because following the conclusion of Engelman (2023) some have tried to maintain larger body size estimates for Dunkleosteus terrelli by proposing it may have had Xiphactinus-like head-body proportions (pers. comms. to R. Engelman). Thus, Ichthyodectiforms represent a useful test to see how consistent the proportions under examination are across fishes.

2.1 Measuring SVL

Data in this supplementary information was collected from the literature and preserved specimens when measuring data for prior studies (Engelman 2023). Anatomical observations regarding vent position were made from direct observation of these specimens.

SVL was measured as the distance from the tip of the snout to the level of the vent along the anteroposterior axis of the body. In many photographs (e.g., those of Randall 1997), the vent can be readily identified in lateral view by a distinct notch or puckering on the ventral margin of the animal. In cases where the vent could not be not clearly identified SVL was not recorded.

SVL could only be measured opportunistically in fishes. In specimens measured directly, the original goal was to collect measurements of the mouth and head, and SVL only began to be collected late in the analysis, resulting in many fishes lacking SVL data. Photos were taken in lateral view, but in many cases the vent cannot be located on these photos.

SVL is rarely reported for fishes in the literature. Pre-anal length is often reported, with the implication that anal fin position reflects cloaca position. This does appear to be the case for most actinopterygians, where the vent is immediately anterior to the anal fin origin, but the position of the pelvic and anal fins relative to the vent can vary. In some taxa (e.g., Carangidae, Gobiidae) there is a distinct gap between the vent and the anal fin origin, and in others (Siluriformes, Amia) the vent is halfway between the pelvic and anal fins. To make comparisons more rigorous, only measurable SVL was used rather than treating pre-anal fin length in actinopterygians as SVL.

All SVL data are reported as species averages to allow for a more even representation of taxa relative to sample size. The same is true for prepectoral length and prepelvic length unless noted.

2.2 Vent position in arthrodires

The location of the cloaca in arthrodires can be determined based on preserved visceral organs in several Gogo taxa (Trinajstic et al. 2022). Additionally, the position of the cloaca can be further constrained based on other features like the position of the claspers (which have to be near the vent to function as intromittant organs, as in chondrichthyans), posterior extent of the ventral shield, and the enlargement of the haemal arches denoting the posterior boundary of the visceral cavity (as in other fishes) (Dean 1896, Miles and Westoll 1968, Ahlberg et al. 2009, Trinajstic et al. 2015, Trinajstic et al. 2022, Engelman 2023).

Vent position could be confidently determined in two near-complete arthrodire taxa: Coccosteus cuspidatus and Incisoscutum ritchei. In Coccosteus cuspidatus (ROM VP 52664), the vent is estimated to be located at 48.3% total length based on the position of the claspers. For ROM VP 52664, there are a pair of elements at the posterior end of the ventral shield that look like iliac processes but other colleagues have suggested in conversation they may actually be claspers (S. van Mesdag, pers. comm. October 2023). The author is not completely sure if these elements truly are claspers (as clasper elements versus isolated iliac processes can be very hard to identify in arthrodires; S. van Mesdag, pers. comm. October 2023), but it was decided to use the proportion in ROM VP 52664 as an approximate estimated SVL because other specimens of coccosteid arthrodires show definite claspers located at approximately this position (Trinajstic et al. 2015). Thus, even if these are pelvic remains, the length to these elements approximates SVL.

For Incisoscutum ritchei, vent position was based on the reconstruction in Trinajstic et al. (2013), as determined by the presence of claspers and location of the preserved cloaca in some specimens (Trinajstic et al. 2022). Total length was estimated from precaudal/total length in Coccosteus as described below. This results in an SVL 46.2-50.5% total length, with most specimens of C. cuspidatus suggesting higher values (SVL = 49.6% total length). If a greater caudal fin length length similar to Miles and Westoll (1968)’s reconstruction is used resulting total length is 27.2 cm and the SVL is 46.2% of total body length, suggesting interpretations of caudal fin size have little effect on the resulting proportion.

Vent position in two other specimens, one of Dickosteus threiplandi (NHMUK PV P 49663) and one of Amazichthys trinajsticae (AA.MEM.DS.8) were also considered. However, the former is a highly distorted specimen where the armor is “exploded” and some of the tail may be missing, and in the latter vent position was merely inferred assuming it was located just posterior to the pelvis as in Coccosteus and Incisoscutum. Vent position in these taxa are considered much less rigorous, though are discussed just to examine possible variation within eubrachythoracid arthrodires.

2.3 Data for arthrodires

2.4 Total lengths and body masses for arthrodires in pectoral fin analysis

In addition to taxa for which length could be measured directly (Amazichthys, Coccosteus), several arthrodires had proportions calculated relative to estimated total length. As mentioned above the length of Incisoscutum was calculated from Trinajstic et al. (2013), with caudal fin length approximated based on Coccosteus. Lengths for Dunkleosteus and other arthrodires for which complete body outlines are unknown were taken from the best-fitting model in Engelman 2023 (the one using individual specimens, allowing allometric slopes to vary between chondrichthyans and non-chondrichthyans, and considering body shape and membership in the outlier clades Serranidae or Holocentridae as additional variables, see that study for more details). For arthrodires, this equation takes the form…

\[ \mbox{total length} = 1.015*exp(0.993271*ln(\mbox{orbit-opercular length})+1.881925) \]

Body masses for arthrodires were calculated using the ellipsoid method of Ault and Luo (2013) as modified by and detailed in Engelman (2023). Body masses for Dunkleosteus terrelli taken directly from that study. Juvenile specimens of Dunkleosteus for which body depth and body width were not available had their mass calculated using the axis available and assuming a sub-circular cross-section, given CMNH 7424 and CMNH 6194 show sub-circular cross-sections and CMNH 8982 and CMC VP 8294 have crushed trunk armors suggesting sub-circular proportions. For CMNH 5768, body mass was recalculated given the narrower body depth for this specimen determined in this study (100 cm versus 114 cm). This specimen is probably too wide as mounted, and it is possible the mass for this specimen would be even lower, around 760-795 kg, if a cross-sectional shape similar to CMNH 6090 and CMNH 7054 is assumed (in which the cross-sectional shape of the armor is better preserved and body width is ~80% body depth). However, because these values are within the range of error calculated here (538-1714 kg), this suggests the use of these mass estimates are reasonable for now and do not invalidate the conclusions presented here.

Error bars for length use +/- percent error unless otherwise noted, due to log-transformation resulting in leptokurtically distributed detransformed residuals and thus exaggerated and unrealistically wide confidence intervals relative to the distribution of the data (see Engelman 2023 for more details).

For Coccosteus cuspidatus and Incisoscutum ritchei body masses were recalculated given the reconstruction in Miles and Westoll (1968) was slightly too long in its abdomen and caudal fin and had an unnaturally compressed trunk armor compared to complete fossils.

The weight of Incisoscutum ritchei was estimated using the proportions in Trinajstic et al. 2013, as in Engelman 2023, but a shorter total length was used following the reasoning in “Vent position in arthrodires”.

For Coccosteus cuspidatus (see manuscript), body mass was estimated using the reconstruction of Coccosteus cuspidatus in this study (Figure 7 in main text). This reconstruction was was adjusted from Miles and Westoll (1968) following the proportions of ROM VP 52664. For girth, body height was measured and it was assumed the proportions of the trunk armor followed the proportions in Miles and Westoll (1968: fig. 44). This might produce a slight overestimate of weight, because shearing the armor might make it slightly deeper than in Miles and Westoll (1968), and thus overestimate trunk width. However, the resulting weight differs only slightly from the body mass of 550 g estimated in Engelman (2023) using the reconstruction in Miles and Westoll (1968), and might be expected because of the slightly stockier body in this reconstruction.

2.5 Adjustments

For extinct taxa known from fragmentary remains, occasionally adjustments had to be made in order to use data from crushed or fragmentary specimens. This is particularly the case with obtaining enough information to produce a reliable estimate of body mass, which requires a value for body girth. These decisions are stated here for transparency and replicability.

  • Incisoscutum ritchei - The caudal fin is unknown for Incisoscutum, despite the precaudal anatomy being well known. Caudal fin size was previously estimated in Engelman (2023) based the proportion of precaudal to total length in Miles and Westoll (1968)’s Coccosteus reconstruction. However, examination of more complete specimens of Coccosteus suggests this estimate is overly generous due to the unusually large fin in that reconstruction. Caudal fin size here was estimated based on five near-complete specimens of C. cuspidatus (total length ~ 1.23 x precaudal length, see Appendix 8, this paper), which produce total lengths of 25 to 27 cm for Incisoscutum.
  • WAM 70.4.864 (Eastmanosteus calliaspis) - Any measurements taken from the reconstruction in Dennis-Bryant (1987: fig. 5) were scaled to match the reported dimensions of the specimen using head shield length (13.37 cm). The reconstruction in Dennis-Bryant (1987) is slightly larger than the reported measurements of the holotype, despite being mostly based on this specimen. The original material could not be examined directly for measurement.
  • CMNH 6194 (Dunkleosteus terrelli) - Body mass was calculated assuming a subcircular cross-section with body width approximate equal to body depth (~36.5 cm) Direct observation of this mount shows it had a subcircular cross-section, but exact dimensions could not be measured due to inaccessibility of the specimen during the 2022-2024 renovations of the Cleveland Museum of Natural History.
  • CMNH 8982 (Dunkleosteus terrelli) - Body mass was estimated assuming a subcircular cross-section with body width approximately equal to estimated body depth (~33 cm), given other D. terrelli specimens of similar size (CMNH 6194, CMNH 7424) have subcircular cross-sections
  • CMC VP8294 (Dunkleosteus terrelli) - Body mass was estimated assuming a subcircular cross-section with body width approximately equal to estimated body depth (~33 cm), given other D. terrelli specimens of similar size (CMNH 6194, CMNH 7424) have subcircular cross-sections
  • Amazichthys trinajsticae - Pectoral fin base length in the holotype (AA.MEM.DS.8) was restored after PIMUZ A/I 4773. AA.MEM.DS.8 only preserves a fragment of the scapulocoracoid, but PIMUZ A/I 4773 preserves the entire element, and the two specimens are similar in size (Jobbins et al. 2022). Body mass in this taxon was estimated assuming a cross-sectional length/depth ratio of 1.2, similar to other pelagic pachyosteomorphs (see Engelman 2023).

3 Data distribution

For this section “mean value” means the mean value as a proportion of total length, for easier comparison between taxa/specimens of different sizes.

3.1 By higher-level clade

obs_by_clade<-data_recon %>%
  mutate(pec_base2=pec_base/total_length,
         ppl=prepectoral_length/total_length,
         SVL2=SVL/total_length,
         pvl=prepelvic_length/total_length,
         clade=ifelse(higher_group=="Acanthopterygii","Acanthopterygii",clade),
         clade=ifelse(clade=="Actinopterygii","Non-Acanthopterygian Actinopterygii",clade),
         clade=factor(clade,ordered=T,levels=c("Acanthopterygii","Non-Acanthopterygian Actinopterygii","Sarcopterygii","Chondrichthyes","Placodermi"))) %>%
  group_by(taxon) %>%
  summarise(pec_base=mean(pec_base2,na.rm=T),
            n_pec=sum(!is.na(pec_base2)),
            n_ppl=sum(!is.na(ppl)),
            n_svl=sum(!is.na(SVL2)),
            n_pvl=sum(!is.na(pvl)),
            ppl=mean(ppl,na.rm=T),
            SVL=mean(SVL2,na.rm=T),
            pvl=mean(pvl,na.rm=T),
            order=unique(order),clade=unique(clade)) %>%
  group_by(clade) %>%
  summarise(clade=unique(clade),
            nspec_pec=sum(!is.na(pec_base)),
            n_pec=sum(n_pec),
            nspec_ppl=sum(!is.na(ppl)),
            n_ppl=sum(n_ppl),
            nspec_SVL=sum(!is.na(SVL)),
            n_SVL=sum(n_svl),
            nspec_pvl=sum(!is.na(pvl)),
            n_pvl=sum(n_pvl),
            ppl=mean(ppl,na.rm=T),
            SVL=mean(SVL,na.rm=T),
            pvl=mean(pvl,na.rm=T)) %>%
  select(clade,nspec_pec,n_pec,n_ppl,nspec_ppl,ppl,n_SVL,nspec_SVL,SVL,n_pvl,nspec_pvl,pvl)
  
obs_by_clade %>%
  add_row(clade="All Species",
          n_pec = sum(obs_by_clade$n_pec),
          nspec_pec = sum(obs_by_clade$nspec_pec),
          nspec_ppl = sum(obs_by_clade$nspec_ppl),
          n_ppl = sum(obs_by_clade$n_ppl),
          n_SVL = sum(obs_by_clade$n_SVL),
          nspec_SVL = sum(obs_by_clade$nspec_SVL),
          n_pvl = sum(obs_by_clade$n_pvl),
          nspec_pvl = sum(obs_by_clade$nspec_pvl),
          ppl = data_recon %>% group_by(taxon) %>% drop_na(prepectoral_length,total_length) %>% summarise(ppl=mean(prepectoral_length/total_length)) %>% pull() %>% mean(),
          SVL = data_recon %>% group_by(taxon) %>% drop_na(SVL,total_length) %>% summarise(ppl=mean(SVL/total_length)) %>% pull() %>% mean(),
          pvl = data_recon %>% group_by(taxon) %>% drop_na(prepelvic_length,total_length) %>% summarise(ppl=mean(prepelvic_length/total_length)) %>% pull() %>% mean()) %>%
  mutate(across(where(is.numeric), ~na_if(., 0))) %>%
  kable(digits=3,col.names=c("Clade",
                             "N spp.","N observations",
                             "N spp.","N observations","Mean Value",
                             "N spp.","N observations","Mean Value",
                             "N spp.","N observations","Mean Value"),
        align=c("l","c","c","c","c","c","c","c","c","c","c","c"),
        caption="Distribution of data in this study by higher level clade") %>%
  add_header_above(c("Taxonomy"=1,"Pectoral Fin Base Length"=2,"Prepectoral Length"=3,
                     "Snout-Vent Length"=3,"Prepelvic Length"=3)) %>%
  column_spec (c(1,3,6,9,12),border_right = T) %>%
  row_spec (6,bold=T) %>%
  kable_styling()
Table 3.1: Distribution of data in this study by higher level clade
Taxonomy
Pectoral Fin Base Length
Prepectoral Length
Snout-Vent Length
Prepelvic Length
Clade N spp. N observations N spp. N observations Mean Value N spp. N observations Mean Value N spp. N observations Mean Value
Acanthopterygii 1137 428 0.238 651 251 0.489 933 363 0.276
Non-Acanthopterygian Actinopterygii 527 247 0.189 283 131 0.521 519 226 0.412
Sarcopterygii 4 3 0.221 1 1 0.488 4 3 0.491
Chondrichthyes 108 372 699 178 0.207 280 124 0.509 676 182 0.487
Placodermi 17 29 31 22 0.193 4 4 0.521 13 8 0.470
All Species 125 401 2398 878 0.216 1219 511 0.502 2145 782 0.367

3.2 Prepectoral length, SVL, and prepelvic length by order

data_recon %>%
  group_by(taxon) %>%
  mutate(ppl=prepectoral_length/total_length,
         SVL2=SVL/total_length,
         pvl=prepelvic_length/total_length) %>%
  summarise(n_ppl=sum(!is.na(ppl)),
            n_svl=sum(!is.na(SVL2)),
            n_pvl=sum(!is.na(pvl)),
            ppl=mean(ppl,na.rm=T),
            SVL=mean(SVL2,na.rm=T),
            pvl=mean(pvl,na.rm=T),
            order=unique(order),clade=unique(clade)) %>%
  group_by(order) %>%
  summarise(order=unique(order),clade=unique(clade),
            nspec_ppl=sum(!is.na(ppl)),
            n_ppl=sum(n_ppl),
            nspec_SVL=sum(!is.na(SVL)),
            n_SVL=sum(n_svl),
            nspec_pvl=sum(!is.na(pvl)),
            n_pvl=sum(n_pvl),
            ppl=mean(ppl,na.rm=T),
            SVL=mean(SVL,na.rm=T),
            pvl=mean(pvl,na.rm=T)) %>%
  select(order,clade,nspec_ppl,n_ppl,ppl,nspec_SVL,n_SVL,SVL,nspec_pvl,n_pvl,pvl) %>%
  mutate(across(where(is.numeric), ~na_if(., 0))) %>%
  kable(digits=3,col.names=c("Order","Clade",
                             "N spp.","N observations","Mean Value",
                             "N spp.","N observations","Mean Value",
                             "N spp.","N observations","Mean Value"),
        align=c("l","c","c","c","c","c","c","c","c","c","c"),
        caption="Distribution of data for prepectoral length, snout-vent length (SVL), and prepelvic length by order") %>%
  add_header_above(c("Taxonomy"=2,"Prepectoral Length"=3,
                   "Snout-Vent Length"=3,"Prepelvic Length"=3)) %>%
  column_spec (c(2,5,8,11),border_right = T) %>%
  kable_styling()
Table 3.2: Distribution of data for prepectoral length, snout-vent length (SVL), and prepelvic length by order
Taxonomy
Prepectoral Length
Snout-Vent Length
Prepelvic Length
Order Clade N spp. N observations Mean Value N spp. N observations Mean Value N spp. N observations Mean Value
Acanthuriformes Actinopterygii 6 15 0.214 6 12 0.365 6 13 0.237
Acipenseriformes Actinopterygii 5 6 0.241 2 3 0.628 7 12 0.521
Actinistia Sarcopterygii 2 3 0.250 1 1 0.488 2 3 0.441
Albuliformes Actinopterygii 3 9 0.194 2 4 0.604 3 9 0.472
Alepocephaliformes Actinopterygii 2 2 0.211 1 1 0.595 2 5 0.480
Amiiformes Actinopterygii 1 6 0.219 1 6 0.535 1 6 0.462
Anabantiformes Actinopterygii 4 8 0.308 1 1 0.554 1 1 0.381
Anguilliformes Actinopterygii 6 7 0.147 6 34 0.445
Arthrodira Placodermi 22 31 0.193 4 4 0.521 8 13 0.470
Atheriniformes Actinopterygii 7 16 0.193 2 3 0.427 7 13 0.338
Aulopiformes Actinopterygii 9 20 0.193 3 4 0.607 9 19 0.321
Beloniformes Actinopterygii 14 28 0.218 5 7 0.585 13 24 0.488
Beryciformes Actinopterygii 3 5 0.245 2 3 0.427 3 4 0.295
Blenniiformes Actinopterygii 2 12 0.181 2 7 0.403 2 7 0.129
Callionymiformes Actinopterygii 1 1 0.243 1 1 0.158
Carangaria incertae sedis Actinopterygii 18 51 0.249 4 7 0.555 14 33 0.315
Carangiformes Actinopterygii 60 128 0.212 34 66 0.433 60 121 0.230
Carcharhiniformes Chondrichthyes 87 372 0.204 56 147 0.479 86 354 0.461
Centrarchiformes Actinopterygii 11 23 0.233 9 18 0.463 11 23 0.293
Characiformes Actinopterygii 57 120 0.189 31 49 0.509 54 112 0.384
Chimaeriformes Chondrichthyes 6 14 0.190 6 8 0.442 6 14 0.467
Cichliformes Actinopterygii 3 3 0.283 3 3 0.315
Clupeiformes Actinopterygii 19 59 0.182 11 36 0.547 19 56 0.403
Cypriniformes Actinopterygii 23 65 0.196 14 24 0.568 19 63 0.402
Cyprinodontiformes Actinopterygii 1 7 0.206 1 7 0.482 1 7 0.364
Dipnoi Sarcopterygii 1 1 0.162 1 1 0.591
Echinorhiniformes Chondrichthyes 2 40 0.270 2 39 0.570
Elopiformes Actinopterygii 4 11 0.183 1 1 0.675 4 19 0.420
Esociformes Actinopterygii 5 14 0.205 2 5 0.653 5 15 0.454
Eupercaria incertae sedis Actinopterygii 28 54 0.236 14 30 0.493 20 44 0.270
Gadiformes Actinopterygii 6 7 0.190 2 2 0.461 4 5 0.175
Galaxiiformes Actinopterygii 1 1 0.166 1 1 0.667 1 1 0.465
Gobiiformes Actinopterygii 5 21 0.228 4 19 0.444 5 11 0.240
Gonorynchiformes Actinopterygii 2 6 0.181 2 6 0.513
Gymnotiformes Actinopterygii 3 4 0.114 2 2 0.070
Heterodontiformes Chondrichthyes 1 1 0.207 1 1 0.430
Hexanchiformes Chondrichthyes 6 38 0.186 6 12 0.483 6 36 0.434
Hiodontiformes Actinopterygii
Holocentriformes Actinopterygii 14 44 0.269 14 31 0.564 14 44 0.301
Ichthyodectiformes Actinopterygii 7 7 0.137 8 13 0.454
Istiophoriformes Actinopterygii 10 147 0.211 5 102 0.468 7 100 0.233
Kurtiformes Actinopterygii 5 9 0.278 3 4 0.471 4 7 0.286
Labriformes Actinopterygii 12 37 0.245 12 35 0.471 12 38 0.270
Lamniformes Chondrichthyes 14 79 0.227 8 16 0.526 14 69 0.506
Lampriformes Actinopterygii 7 8 0.196 4 4 0.642 4 4 0.410
Lepisosteiformes Actinopterygii 1 1 0.264 1 1 0.516
Lutjaniformes Actinopterygii 31 63 0.246 24 49 0.502 29 63 0.280
Mugiliformes Actinopterygii 3 6 0.195 3 4 0.514 3 4 0.284
Ophidiiformes Actinopterygii 2 2 0.251 1 1 0.128
Orectolobiformes Chondrichthyes 10 20 0.176 10 16 0.436 10 20 0.400
Osteoglossiformes Actinopterygii 10 13 0.191 7 8 0.591 8 11 0.464
Ovalentaria incertae sedis Actinopterygii 5 9 0.222 4 9 0.444 5 10 0.247
Pempheriformes Actinopterygii 5 9 0.253 1 1 0.454 4 6 0.279
Perciformes Actinopterygii 74 177 0.255 54 138 0.497 60 153 0.276
Percopsiformes Actinopterygii 1 5 0.226 1 4 0.486 1 6 0.348
Pleuronectiformes Actinopterygii 1 4 0.223 1 4 0.210
Pleuronectifromes Actinopterygii 1 1 0.214 1 1 0.162
Polypteriformes Actinopterygii 4 10 0.146 4 7 0.613
Priacanthiformes Actinopterygii 3 6 0.234 1 2 0.188
Rhinopristiformes Chondrichthyes 1 2 0.235 3 6 0.474 5 8 0.413
Salmoniformes Actinopterygii 12 35 0.188 6 18 0.648 12 35 0.472
Scombriformes Actinopterygii 52 159 0.222 22 53 0.548 42 122 0.249
Scorpaeniformes Actinopterygii 10 21 0.248 6 7 0.501 8 19 0.267
Siluriformes Actinopterygii 56 108 0.193 32 75 0.458 57 113 0.407
Spariformes Actinopterygii 19 48 0.255 16 32 0.482 19 47 0.292
Squaliformes Chondrichthyes 48 128 0.217 34 73 0.597 48 130 0.569
Squatiniformes Chondrichthyes 3 5 0.150 1 2 0.452 4 5 0.364
Stomiiformes Actinopterygii 1 1 0.200 1 1 0.528 1 1 0.456
Syngnathiformes Actinopterygii 4 5 0.269 1 4 0.504 3 4 0.465
Tetraodontiformes Actinopterygii 13 16 0.258 2 2 0.480 1 1 0.434
Trachichthyiformes Actinopterygii 1 2 0.254 1 2 0.285
Zeiformes Actinopterygii 2 2 0.240 1 1 0.450

3.3 Pectoral fin base data by chondrichthyan family

data_recon %>%
  drop_na(pec_base) %>%
  filter(clade=="Chondrichthyes") %>%
  summarise(.by=taxon,count=n(),order=unique(order),family=unique(family),
            pec_base=mean(pec_base/total_length)) %>%
  summarise(.by=family,order=unique(order),N=n(),count=sum(count),
            pec_mean=mean(pec_base),
            pec_range=ifelse(N==1,NA,
                             paste0("(",round(min(pec_base),3),"–",
                             round(max(pec_base),3),")"))) %>% 
  mutate(across(where(is.numeric), ~na_if(., 0))) %>%
  arrange(order,family) %>%
  kable(col.names=c("Family","Order","N spp.","N specimens",
                    "Mean Proportional Pectoral Base Length (as fraction of total length)","Range of Species Averages"),
        digits=c(1,1,1,1,3,3),align=c("l","c","c","c","c","c"),
        caption="Distribution of shark taxa with pectoral fin base measurements by family") %>% 
  kable_styling()
Table 3.3: Distribution of shark taxa with pectoral fin base measurements by family
Family Order N spp. N specimens Mean Proportional Pectoral Base Length (as fraction of total length) Range of Species Averages
Carcharhinidae Carcharhiniformes 35 170 0.063 (0.051–0.078)
Hemigaleidae Carcharhiniformes 4 19 0.046 (0.041–0.052)
Pentachidae Carcharhiniformes 1 3 0.063
Pseudotriakidae Carcharhiniformes 2 5 0.048 (0.046–0.049)
Scyliorhinidae Carcharhiniformes 5 6 0.064 (0.047–0.08)
Sphyrnidae Carcharhiniformes 1 2 0.052
Triakidae Carcharhiniformes 8 24 0.052 (0.04–0.074)
Heterodontidae Heterodontiformes 1 1 0.110
Chlamydoselachidae Hexanchiformes 1 4 0.040
Hexanchidae Hexanchiformes 5 23 0.066 (0.06–0.082)
Alopiidae Lamniformes 2 3 0.069 (0.065–0.073)
Cetorhinidae Lamniformes 1 2 0.066
Lamnidae Lamniformes 4 15 0.070 (0.062–0.075)
Megachasmatidae Lamniformes 1 6 0.067
Mitsukurinidae Lamniformes 1 6 0.049
Odontaspidae Lamniformes 3 6 0.067 (0.061–0.075)
Pseudocarchariidae Lamniformes 1 3 0.054
Ginglymostomatidae Orectolobiformes 1 2 0.060
Rhincodontidae Orectolobiformes 1 1 0.078
Centrophoridae Squaliformes 3 5 0.069 (0.05–0.101)
Etmopteridae Squaliformes 1 1 0.040
Somniosidae Squaliformes 13 37 0.065 (0.052–0.079)
Squalidae Squaliformes 13 28 0.057 (0.049–0.071)
data_recon %>%
  filter(clade=="Placodermi") %>%
  drop_na(pec_base,total_length) %>%
  mutate(length_as=ifelse(length_as=="total length","No","Yes"),
         specimen=ifelse(specimen %in% c("Composite tuberculatus","Composite pulchellus",
                                         "Recon (Trinajstic et al. 2013"),
                                         "Reconstruction in Study",specimen),
         taxon=str_replace(taxon,"_"," "),
         body_mass=body_mass/1000,
         specimen=ifelse(specimen=="AA.MEM.DS.8","AA.MEM.DS.8 (with pectoral base from PIMUZ A/I 4773)",specimen)) %>%
  select(taxon,specimen,pec_base,total_length,body_mass,length_as,Reference) %>%
  arrange(taxon) %>%
  kable(digits=c(1,1,1,1,2,1,1),
        col.names = c("Taxon","Specimen","Pectoral Fin Base","Total Length","Body Mass","Length Estimated?","Reference"),
        caption = "Pectoral fin base size in arthrodires, along with either measured or estimated total length and body mass estimated using the ellipsoid model in Engelman (2023). Linear measurements in cm and body mass in kg.",
        align=c("l","c","c","c","c","c","c")) %>%
  column_spec (1,italic=T) %>%
  kable_styling()
Table 3.4: Pectoral fin base size in arthrodires, along with either measured or estimated total length and body mass estimated using the ellipsoid model in Engelman (2023). Linear measurements in cm and body mass in kg.
Taxon Specimen Pectoral Fin Base Total Length Body Mass Length Estimated? Reference
Amazichthys trinajsticae AA.MEM.DS.8 (with pectoral base from PIMUZ A/I 4773) 9.8 89.7 6.29 No Jobbins et al. 2022
Brachyosteus dietrichi W.f. 200 2.5 29.2 Yes Stensiö 1963: plate 38
Camuropiscis concinnus WAM 70.4.255 1.4 30.0 0.17 Yes Dennis and Miles 1979
Coccosteus cuspidatus Recon. (M & W 1968) 2.6 39.4 0.55 No Miles and Westoll 1968
Coccosteus cuspidatus NMS 1893.107.27 2.5 29.6 No Present Study
Coccosteus cuspidatus FMNH PF 1673 2.8 37.1 No Present Study
Coccosteus cuspidatus ROM VP 52664 2.7 37.5 0.65 No Present Study
Dunkleosteus terrelli CMNH 5768 36.2 340.7 960.40 Yes Present Study
Dunkleosteus terrelli CMNH 7424 14.6 188.9 106.73 Yes Present Study
Dunkleosteus terrelli CMNH 6090 28.7 283.3 391.65 Yes Present Study
Dunkleosteus terrelli CMNH 7054 32.0 295.5 381.41 Yes Present Study
Dunkleosteus terrelli CMNH 8982 12.8 154.8 25.47 Yes Present Study; Carr et al. 2010
Dunkleosteus terrelli CMNH 6194 16.2 166.3 54.65 Yes Present Study
Dunkleosteus terrelli CMC VP8294 14.5 157.3 38.83 Yes Present Study
Eastmanosteus calliaspis WAM 70.4.864 6.8 79.3 4.95 Yes Dennis-Bryan 1987
Enseosteus jaekeli W.f. 128 5.5 45.8 Yes Stensiö 1959: plate 1
Harrytoombsia elegans WAM P50914 2.2 37.0 0.46 Yes Miles and Dennis 1979
Heintzichthys gouldii Recon. (Carr 1991) 15.2 140.8 Yes Carr 1991
Incisoscutum ritchei Recon. (Trinajstic et al. 2013) 2.1 25.4 0.17 No Trinajstic et al. 2013
Incisoscutum ritchei WAM 86.9.667 3.5 49.9 Yes Long 1994
Latocamurus coulthardi WAM 86.9.699 1.0 24.0 0.08 Yes Long 1988
Mcnamaraspis kaprios WAM 86.9.676 3.0 32.6 0.31 Yes Long 1995
Millerosteus minor Composite of LDUCZ-V998 and NHMUK PV P16795 0.7 14.9 No Desmond 1974, Newman pers. comm.
Millerosteus minor FMNH PF 1089 0.8 13.7 No Present Study
Millerosteus minor NHMUK PV P16795 0.8 17.1 No M. J. Newman pers. comm.
Rolfosteus canningensis WAM P50977 1.8 29.7 0.13 Yes Dennis and Miles 1979
Torosteus pulchellus Reconstruction in Study 1.8 36.0 0.33 Yes Gardiner and Miles 1990
Torosteus tuberculatus Reconstruction in Study 2.6 40.2 0.59 Yes Gardiner and Miles 1990
Tubonasus lennardensis WAM 70.4.257 1.5 36.5 0.19 Yes Dennis and Miles 1979

3.4 Fineness ratio by order

data_recon %>%
  group_by(taxon) %>%
  mutate(fineness=precaudal_length/body_depth) %>%
  summarise(n_fineness=sum(!is.na(fineness)),
            fineness=mean(fineness,na.rm=T),
            order=unique(order),clade=unique(clade)) %>%
  group_by(order) %>%
  summarise(order=unique(order),clade=unique(clade),
            nspec_fineness=sum(!is.na(fineness)),
            n_fineness=sum(n_fineness),
            fineness=mean(fineness,na.rm=T)) %>%
  select(order,clade,nspec_fineness,n_fineness,fineness) %>%
  mutate(across(where(is.numeric), ~na_if(., 0))) %>%
  kable(digits=3,col.names=c("Order","Clade",
                             "N spp.","N observations","Mean Value"),
        align=c("l","c","c","c","c"),
        caption="Distribution of data for fineness ratio by order") %>%
  kable_styling()
Table 3.5: Distribution of data for fineness ratio by order
Order Clade N spp. N observations Mean Value
Acanthuriformes Actinopterygii 6 15 2.031
Acipenseriformes Actinopterygii 7 10 7.412
Actinistia Sarcopterygii 2 3 2.932
Albuliformes Actinopterygii 3 9 4.315
Alepocephaliformes Actinopterygii 2 5 5.312
Amiiformes Actinopterygii 1 11 4.793
Anabantiformes Actinopterygii 2 3 3.693
Anguilliformes Actinopterygii 3 3 11.312
Arthrodira Placodermi 18 26 4.441
Atheriniformes Actinopterygii 7 17 5.836
Aulopiformes Actinopterygii 10 23 6.714
Beloniformes Actinopterygii 14 27 8.391
Beryciformes Actinopterygii 3 6 2.243
Blenniiformes Actinopterygii 2 12 3.256
Callionymiformes Actinopterygii 1 1 4.848
Carangaria incertae sedis Actinopterygii 18 55 6.103
Carangiformes Actinopterygii 61 133 3.313
Carcharhiniformes Chondrichthyes 79 248 6.881
Centrarchiformes Actinopterygii 11 52 2.634
Characiformes Actinopterygii 54 114 2.894
Chimaeriformes Chondrichthyes 5 11 4.620
Cichliformes Actinopterygii 3 3 2.815
Clupeiformes Actinopterygii 19 61 4.212
Cypriniformes Actinopterygii 23 67 3.663
Cyprinodontiformes Actinopterygii 1 7 4.957
Dipnoi Sarcopterygii 1 1 5.411
Echinorhiniformes Chondrichthyes 2 6 6.869
Elopiformes Actinopterygii 4 19 4.456
Esociformes Actinopterygii 5 24 5.945
Eupercaria incertae sedis Actinopterygii 28 53 3.412
Gadiformes Actinopterygii 5 6 5.762
Galaxiiformes Actinopterygii 1 1 5.465
Gobiiformes Actinopterygii 6 23 4.877
Gonorynchiformes Actinopterygii 2 6 6.705
Gymnotiformes Actinopterygii
Heterodontiformes Chondrichthyes 1 1 5.089
Hexanchiformes Chondrichthyes 6 29 6.266
Hiodontiformes Actinopterygii 1 5 3.283
Holocentriformes Actinopterygii 14 44 2.696
Ichthyodectiformes Actinopterygii 8 11 5.474
Istiophoriformes Actinopterygii 10 119 5.720
Kurtiformes Actinopterygii 5 9 2.948
Labriformes Actinopterygii 12 39 3.388
Lamniformes Chondrichthyes 13 45 5.039
Lampriformes Actinopterygii 6 9 4.517
Lepisosteiformes Actinopterygii 3 6 8.868
Lutjaniformes Actinopterygii 31 66 2.705
Mugiliformes Actinopterygii 3 6 3.798
Ophidiiformes Actinopterygii
Orectolobiformes Chondrichthyes 8 13 7.666
Osteoglossiformes Actinopterygii 8 11 4.312
Ovalentaria incertae sedis Actinopterygii 6 11 2.624
Pempheriformes Actinopterygii 6 10 3.192
Perciformes Actinopterygii 76 205 3.189
Percopsiformes Actinopterygii 1 8 4.773
Pleuronectiformes Actinopterygii 1 4 2.250
Pleuronectifromes Actinopterygii
Polypteriformes Actinopterygii 4 10 8.216
Priacanthiformes Actinopterygii 3 6 2.416
Rhinopristiformes Chondrichthyes 1 3 5.658
Salmoniformes Actinopterygii 12 35 4.470
Scombriformes Actinopterygii 54 209 4.437
Scorpaeniformes Actinopterygii 10 19 2.749
Siluriformes Actinopterygii 56 112 5.006
Spariformes Actinopterygii 19 49 2.571
Squaliformes Chondrichthyes 47 116 6.403
Squatiniformes Chondrichthyes
Stomiiformes Actinopterygii 1 1 5.811
Syngnathiformes Actinopterygii 4 5 9.218
Tetraodontiformes Actinopterygii 11 13 3.145
Trachichthyiformes Actinopterygii 1 2 2.487
Zeiformes Actinopterygii 2 2 2.224

3.5 Caudal peduncle height by order

data_recon %>%
  group_by(taxon) %>%
  mutate(caudal_peduncle=peduncle_height/total_length) %>%
  summarise(n_cpl=sum(!is.na(caudal_peduncle)),
            cpl=mean(caudal_peduncle,na.rm=T),
            order=unique(order),clade=unique(clade)) %>%
  group_by(order) %>%
  summarise(order=unique(order),clade=unique(clade),
            nspec_cpl=sum(!is.na(cpl)),
            n_cpl=sum(n_cpl),
            cpl=mean(cpl,na.rm=T)) %>%
  select(order,clade,nspec_cpl,n_cpl,cpl) %>%
  mutate(across(where(is.numeric), ~na_if(., 0))) %>%
  kable(digits=3,col.names=c("Order","Clade",
                             "N spp.","N observations","Mean Value"),
        align=c("l","c","c","c","c"),
        caption="Distribution of data for caudal peduncle height by order") %>%
  kable_styling()
Table 3.6: Distribution of data for caudal peduncle height by order
Order Clade N spp. N observations Mean Value
Acanthuriformes Actinopterygii 6 14 0.067
Acipenseriformes Actinopterygii 7 12 0.027
Actinistia Sarcopterygii 2 3 0.088
Albuliformes Actinopterygii 3 9 0.061
Alepocephaliformes Actinopterygii 2 5 0.074
Amiiformes Actinopterygii 1 11 0.108
Anabantiformes Actinopterygii 1 1 0.115
Anguilliformes Actinopterygii 2 2 0.042
Arthrodira Placodermi 4 4 0.072
Atheriniformes Actinopterygii 7 17 0.065
Aulopiformes Actinopterygii 9 22 0.056
Beloniformes Actinopterygii 14 25 0.043
Beryciformes Actinopterygii 3 6 0.090
Blenniiformes Actinopterygii 2 12 0.084
Callionymiformes Actinopterygii 1 1 0.066
Carangaria incertae sedis Actinopterygii 17 48 0.066
Carangiformes Actinopterygii 58 129 0.039
Carcharhiniformes Chondrichthyes 72 171 0.036
Centrarchiformes Actinopterygii 11 52 0.095
Characiformes Actinopterygii 56 116 0.087
Chimaeriformes Chondrichthyes 3 4 0.018
Cichliformes Actinopterygii 3 3 0.099
Clupeiformes Actinopterygii 19 60 0.072
Cypriniformes Actinopterygii 20 64 0.097
Cyprinodontiformes Actinopterygii 1 7 0.094
Dipnoi Sarcopterygii 1 1 0.145
Echinorhiniformes Chondrichthyes 2 4 0.066
Elopiformes Actinopterygii 4 18 0.075
Esociformes Actinopterygii 5 24 0.066
Eupercaria incertae sedis Actinopterygii 26 52 0.083
Gadiformes Actinopterygii 4 5 0.040
Galaxiiformes Actinopterygii
Gobiiformes Actinopterygii 6 23 0.098
Gonorynchiformes Actinopterygii 2 6 0.057
Gymnotiformes Actinopterygii
Heterodontiformes Chondrichthyes 1 1 0.039
Hexanchiformes Chondrichthyes 6 17 0.041
Hiodontiformes Actinopterygii 1 5 0.085
Holocentriformes Actinopterygii 14 44 0.072
Ichthyodectiformes Actinopterygii 7 7 0.055
Istiophoriformes Actinopterygii 10 168 0.033
Kurtiformes Actinopterygii 5 9 0.119
Labriformes Actinopterygii 12 39 0.118
Lamniformes Chondrichthyes 12 38 0.043
Lampriformes Actinopterygii 4 6 0.060
Lepisosteiformes Actinopterygii 3 6 0.052
Lutjaniformes Actinopterygii 31 65 0.094
Mugiliformes Actinopterygii 3 6 0.094
Ophidiiformes Actinopterygii
Orectolobiformes Chondrichthyes 7 11 0.034
Osteoglossiformes Actinopterygii 8 11 0.062
Ovalentaria incertae sedis Actinopterygii 6 11 0.113
Pempheriformes Actinopterygii 6 10 0.084
Perciformes Actinopterygii 75 203 0.094
Percopsiformes Actinopterygii 1 8 0.061
Pleuronectiformes Actinopterygii 1 4 0.091
Pleuronectifromes Actinopterygii 1 1 0.106
Polypteriformes Actinopterygii 4 7 0.053
Priacanthiformes Actinopterygii 3 6 0.071
Rhinopristiformes Chondrichthyes 2 4 0.017
Salmoniformes Actinopterygii 11 28 0.081
Scombriformes Actinopterygii 49 165 0.039
Scorpaeniformes Actinopterygii 7 15 0.092
Siluriformes Actinopterygii 51 100 0.076
Spariformes Actinopterygii 19 48 0.090
Squaliformes Chondrichthyes 38 84 0.031
Squatiniformes Chondrichthyes 3 3 0.023
Stomiiformes Actinopterygii 1 1 0.056
Syngnathiformes Actinopterygii 3 7 0.059
Tetraodontiformes Actinopterygii 9 10 0.060
Trachichthyiformes Actinopterygii 1 2 0.101
Zeiformes Actinopterygii 2 2 0.047

4 Analyses

4.1 Fineness Ratio

fineness<-data_recon %>%
  drop_na(precaudal_length,body_depth) %>%
  mutate(fineness=precaudal_length/body_depth,
         order2=ifelse(clade=="Placodermi","Other Arthrodira",order))%>%
  mutate(order2=ifelse(genus=="Dunkleosteus","*Dunkleosteus*",order2),
         order2=ifelse(genus=="Coccosteus","*Coccosteus*",order2),
         order2=ifelse(genus=="Incisoscutum","*Incisoscutum*",order2),
         order2=ifelse(genus=="Amazichthys","*Amazichthys*",order2),
         order2=ifelse(family=="Camuropiscidae","Camuropiscidae",order2),
         order2=ifelse(order %in% c("Scombriformes","Lampriformes",
                                   "Lamniformes","Centrarchiformes",
                                   "Carangiformes",
                                   "Carangaria incertae sedis","Perciformes",
                                   "Eupercaria incertae sedis",
                                   "Istiophoriformes","Characiformes"),family,order2)) %>%
  mutate(order2=ifelse(family=="Centrarchidae" & genus!="Micropterus","Other Centrarchidae",order2),
         order2=ifelse(genus %in% c("Thunnus",
                      "Allothunnus",
                      "Auxis",
                      "Euthynnus",
                      "Katsuwonus",
                      "Sarda","Orcynopsis","Cybiosarda","Gymnosarda"),
                      "Thunnini + Sardini",order2),
         order2=ifelse(genus=="Gasterochisma","*Gasterochisma*",order2)) %>%
  mutate(order2=ifelse(genus=="Micropterus","*Micropterus*",order2),
         order2=ifelse(order2=="Scombridae","Other Scombridae",order2)) %>%
  mutate(higher_group=factor(higher_group,levels=c("Petromyzontiformes","Arthrodira","Chondrichthyes","Sarcopterygii","Basal Actinopterygii","Basal Teleostei","Otocephala","Stem Euteleostei","Acanthopterygii")))%>%
  arrange(higher_group,order,family,taxon)%>%
  select(taxon,fineness,order2,everything())

level_info <- fineness %>%
  add_row(higher_group="Arthrodira",order="Arthrodira",
          family="Dunkleosteidae",genus="Dunkleosteus",
          order2="*Dunkleosteus* (upper PE)") %>%
  mutate(higher_group=factor(higher_group,levels=c("Petromyzontiformes","Arthrodira","Chondrichthyes","Sarcopterygii","Basal Actinopterygii","Basal Teleostei","Otocephala","Stem Euteleostei","Acanthopterygii")))%>%
  arrange(higher_group,order,family,genus) %>%
  pull(order2) %>% 
  unique()

fineness_2<-bind_rows(fineness %>%
            filter(clade == "Placodermi") %>%
            drop_na(fineness),
            fineness %>%
            filter(genus == "Dunkleosteus") %>%
              mutate(precaudal_length=precaudal_length*1.1240,
                     order2="*Dunkleosteus* (upper PE)") %>%
              mutate(fineness=precaudal_length/body_depth) %>%
            drop_na(fineness),
          fineness %>%
            filter(genus!="Placodermi"|is.na(order2)) %>%
            group_by(taxon) %>%
            drop_na(fineness) %>%
            summarize(across(where(is.numeric),mean),
                      higher_group=unique(higher_group),order2=unique(order2),
                      order=unique(order),
                      taxon=unique(taxon),genus=unique(genus),species=unique(species),
                      clade=unique(clade,na.rm=F),shape=unique(shape))) %>%
  mutate(order2=factor(order2,ordered=T,levels=rev(level_info)))

fineness_2 %>%
  ggplot(aes(y=order2,x=fineness))+
  annotate("rect", xmin=3, xmax=7, ymin=-Inf, ymax=Inf, alpha=0.15) +
  geom_vline(xintercept=c(3,7),linetype="dashed")+
  geom_vline(xintercept=4.6)+
  geom_point(aes(y=order2,x=fineness),color=NA) +
  geom_vline(data=. %>% filter(clade!="Placodermi"),aes(xintercept=mean(fineness)),color="red") +
  geom_violin(data=. %>% filter(clade!="Placodermi"),scale="width",aes(fill=clade),show.legend = F)+
  geom_boxplot(data=. %>% filter(clade!="Placodermi"),width=0.3)+
  geom_star(data= . %>% filter(order2=="*Dunkleosteus* (upper PE)"|
                                 Reference=="Miles and Westoll 1968"),
            alpha=0.5,fill="white",size=1.5) +
  geom_star(data= . %>% filter(clade=="Placodermi", 
                               Reference!="Miles and Westoll 1968",
                               order2!="*Dunkleosteus* (upper PE)"),
            fill="white",size=1.5) +
  labs(y=element_blank(),x="Fineness Ratio (*f*)")+
  theme(axis.text.y = element_markdown(),
        axis.title.x = element_markdown())
Fineness ratios in eugnathostomes, showing the distinctly below-average fineness ratios for arthrodires compared to other clades. “Other Arthrodires” mostly represent taxa with estimated lengths via OOL, whereas Coccosteus, Incisoscutum, and Amazichthys are based on relatively complete material. Data are reported as individual observations for arthrodires and species averages for all other taxa to display individual variation within Arthrodira. Shaded area represent “typical” fineness ratios for fishes according to Alexander (1967), representing an f of 3.5 to 7, with the black line representing hypothetical ideal hydrodynamic f of 4.6. Red line represents the mean fineness ratio among all species. Faded stars represent the outdated reconstruction of Miles and Westoll (1968) or showing the hypothetical position of a longer Dunkleosteus at the upper end of the confidence intervals of Engelman (2023).

Figure 4.1: Fineness ratios in eugnathostomes, showing the distinctly below-average fineness ratios for arthrodires compared to other clades. “Other Arthrodires” mostly represent taxa with estimated lengths via OOL, whereas Coccosteus, Incisoscutum, and Amazichthys are based on relatively complete material. Data are reported as individual observations for arthrodires and species averages for all other taxa to display individual variation within Arthrodira. Shaded area represent “typical” fineness ratios for fishes according to Alexander (1967), representing an f of 3.5 to 7, with the black line representing hypothetical ideal hydrodynamic f of 4.6. Red line represents the mean fineness ratio among all species. Faded stars represent the outdated reconstruction of Miles and Westoll (1968) or showing the hypothetical position of a longer Dunkleosteus at the upper end of the confidence intervals of Engelman (2023).

Eubrachythoracid arthrodires generally have relatively low fineness ratios within the range of variation seen in fishes, especially if not counting discoid taxa. The only eubrachythoracid arthrodires to reliably have above average fineness ratios are the camuropiscids, which are highly tubular species with pointed rostra (Dennis and Miles 1979) that have been considered tachynektonic swimmers (Trinajstic et al. 2022).

One of the few other arthrodires that shows a fineness ratio close to the average for fishes is Torosteus pulchellus. However the holotype of T. pulchellus is very small in size and may represent a juvenile of T. tuberculatus, similar to what has happened with Gogopiscis and Compagopiscis (Trinajstic and Hazelton 2007), in which case it might be expected to have a shallower trunk (see Trinajstic and Hazelton 2007 and main manuscript).

For Coccosteus the specimen ROM VP 52667, which is considered the most reliably measured specimen here, has a fineness ratio of 3.62. However even the famous Miles and Westoll (1968) reconstruction only has an f around 4, despite having a torso that is much too long relative to the head and body armor (see main manuscript), indicating the low fineness ratio here is unlikely to be the result of incorrect reconstruction.

For Incisoscutum the reconstruction in Trinajstic (2013) has a fineness ratio of ~3.9. , The proportions of this reconstruction agree very well with actual specimens of Incisoscutum like NHMUK PV P 50934, suggesting this value is reasonable. However, the figure in Trinajstic (2013) has its head raised and thus extending anteroposteriorly slightly. Rotating the head back into a neutral position would produce a fineness ratio of about 3.8. The holotype of Incisoscutum (“Gogosteus”) sarahae (the other data point for Incisoscutum) has an unusually high fineness ratio of 4.94. The author has been unable to determine why this is, but suspects this is due to measurement error.

Dunkleosteus has a very low fineness ratio among fishes, even lower than other arthrodires due to its deep trunk. Larger individuals have fineness ratios close to 3.5, whereas juveniles have narrower trunks and slightly higher fineness ratios. Even if taking the extreme upper bounds of the range of possible body lengths (based on %PE) reported by Engelman (2023), the fineness ratio is still below average. The three specimens approaching the ideal value of 4.6 in the above graph are all juvenile specimens with narrower trunks. The values calculated for Dunkleosteus are not out of the question for fusiform fishes, being comparable to serranids and Latimeria, slightly lower than bramids (e.g., Taractes), and somewhat similar to (if a bit lower than) thunnins. Some of this may be because the arthrodire body plan is short and stocky in general and thus Dunkleosteus represents a more extreme version of this, this can be seen in how taxa like lamnids and thunnins show a similar pattern of having low fineness ratios relative to their non-thunniform relatives, despite the precise f values in both groups being different. Another possibility may be this is affected by the shorter snouts of arthrodires relative to other eugnathostomes (Engelman 2023). Preorbital length does affect fineness ratio, and the short, blunt snouts of arthrodires would be expected to negatively influence fineness ratio towards lower values.

rbind(fineness_2 %>%
  drop_na(body_depth,precaudal_length) %>%
  filter(clade=="Chondrichthyes",
         !(order %in% c("Chimaeriformes","Rhinopristiformes"))) %>%
  mutate(f=precaudal_length/body_depth) %>%
  summarise(f=mean(f),clade=unique(clade),.by=taxon) %>%
  summarise(mean=mean(f),median=median(f),min=min(f),max=max(f),n=n()),
  
  fineness_2 %>%
    filter(order=="Lamniformes") %>%
  drop_na(body_depth,precaudal_length) %>%
  mutate(f=precaudal_length/body_depth) %>%
  summarise(f=mean(f),clade=unique(clade),.by=taxon) %>%
  summarise(mean=mean(f),median=median(f),min=min(f),max=max(f),n=n()),
  
  fineness_2 %>%
    filter(order=="Carcharhiniformes") %>%
  drop_na(body_depth,precaudal_length) %>%
  mutate(f=precaudal_length/body_depth) %>%
  summarise(f=mean(f),clade=unique(clade),.by=taxon) %>%
  summarise(mean=mean(f),median=median(f),min=min(f),max=max(f),n=n()),
  
  fineness_2 %>%
  drop_na(body_depth,precaudal_length) %>%
  mutate(f=precaudal_length/body_depth) %>%
  summarise(f=mean(f),clade=unique(clade),.by=taxon) %>%
  summarise(mean=mean(f),median=median(f),min=min(f),max=max(f),n=n()),
  fineness_2 %>%
    filter(shape=="fusiform") %>%
  drop_na(body_depth,precaudal_length) %>%
  mutate(f=precaudal_length/body_depth) %>%
  summarise(f=mean(f),clade=unique(clade),.by=taxon) %>%
  summarise(mean=mean(f),median=median(f),min=min(f),max=max(f),n=n()),
  
  fineness_2 %>%
    filter(order2=="Other Scombridae") %>%
  drop_na(body_depth,precaudal_length) %>%
  mutate(f=precaudal_length/body_depth) %>%
  summarise(f=mean(f),clade=unique(clade),.by=taxon) %>%
  summarise(mean=mean(f),median=median(f),min=min(f),max=max(f),n=n()),
  
  fineness_2 %>%
    filter(order2 %in% c("Thunnini + Sardini","Gasterochisma")) %>%
  drop_na(body_depth,precaudal_length) %>%
  mutate(f=precaudal_length/body_depth) %>%
  summarise(f=mean(f),clade=unique(clade),.by=taxon) %>%
  summarise(mean=mean(f),median=median(f),min=min(f),max=max(f),n=n()),
  
fineness_2 %>%
  drop_na(body_depth,precaudal_length) %>%
    
  filter(clade=="Placodermi",family!="Camuropiscidae") %>%
  mutate(f=precaudal_length/body_depth) %>%
  summarise(f=mean(f),clade=unique(clade),.by=taxon) %>%
  summarise(mean=mean(f),median=median(f),min=min(f),max=max(f),n=n()),

fineness_2 %>%
  drop_na(body_depth,precaudal_length) %>%
    
  filter(family=="Camuropiscidae") %>%
  mutate(f=precaudal_length/body_depth) %>%
  summarise(f=mean(f),clade=unique(clade),.by=taxon) %>%
  summarise(mean=mean(f),median=median(f),min=min(f),max=max(f),n=n())

) %>%
  add_column(name=c("Elasmobranchs","Lamnidae","Carcharhiniformes","All Fishes","All Fusiform Fishes","Other Scombridae","Thunnini, Sardini, and Gasterochisma","Non-Camuropiscid Arthrodires","Camuropiscidae")) %>%
  column_to_rownames("name") %>%
  kable(digits=2,align="c",caption="Summary statistics for fineness ratio (<i>f</i>) for various groups of interest, as species averages",
        col.names = c("Mean","Median","Min","Max","N")) %>%
  kable_styling()
Table 4.1: Summary statistics for fineness ratio (f) for various groups of interest, as species averages
Mean Median Min Max N
Elasmobranchs 6.49 6.19 3.46 14.76 156
Lamnidae 4.93 4.93 3.84 6.50 13
Carcharhiniformes 6.78 6.37 4.31 12.42 79
All Fishes 4.49 3.95 1.33 18.07 853
All Fusiform Fishes 4.18 3.85 1.74 9.73 615
Other Scombridae 4.89 4.67 3.42 6.65 13
Thunnini, Sardini, and Gasterochisma 3.73 3.86 2.92 4.45 19
Non-Camuropiscid Arthrodires 3.79 3.83 3.13 4.54 14
Camuropiscidae 6.78 6.77 5.54 8.05 4

4.2 Head-body proportions in Ichthyodectiformes

rbind(
data_recon %>%
  drop_na(total_length,head_length) %>%
  filter(order=="Ichthyodectiformes") %>%
  group_by(taxon) %>%
  summarise(head_length=mean(head_length/total_length)) %>%
  ungroup() %>%
  summarise_at(vars(head_length),
               list(min=min, Q1=~quantile(., probs = 0.025),
                    mean=mean,median=median, Q3=~quantile(., probs = 0.975),
                    max=max,n=length,sd=sd)),
data_recon %>%
  drop_na(total_length,head_length) %>%
  filter(shape!="anguilliform",
         length_as=="total length",
         clade!="Placodermi",
         order!="Ichthyodectiformes") %>%
  group_by(taxon) %>%
  summarise(head_length=mean(head_length/total_length)) %>%
  ungroup() %>%
  summarise_at(vars(head_length),
               list(min=min, Q1=~quantile(., probs = 0.025),
                    mean=mean,median=median, Q3=~quantile(., probs = 0.975),
                    max=max,n=length,sd=sd)),
data_recon %>%
  drop_na(total_length,head_length) %>%
  filter(shape=="anguilliform",
         length_as=="total length") %>%
  group_by(taxon) %>%
  summarise(head_length=mean(head_length/total_length)) %>%
  ungroup() %>%
  summarise_at(vars(head_length),
               list(min=min, Q1=~quantile(., probs = 0.025),
                    mean=mean,median=median, Q3=~quantile(., probs = 0.975),
                    max=max,n=length,sd=sd)),
data_recon %>%
  drop_na(total_length,head_length) %>%
  filter(clade=="Placodermi",
         length_as=="total length") %>%
  group_by(taxon) %>%
  summarise(head_length=mean(head_length/total_length)) %>%
  ungroup() %>%
  summarise_at(vars(head_length),
               list(min=min, Q1=~quantile(., probs = 0.025),
                    mean=mean,median=median, Q3=~quantile(., probs = 0.975),
                    max=max,n=length,sd=sd)),
data_recon %>%
  drop_na(total_length,head_length) %>%
  filter(clade=="Placodermi") %>%
  group_by(taxon) %>%
  summarise(head_length=mean(head_length/total_length)) %>%
  ungroup() %>%
  summarise_at(vars(head_length),
               list(min=min, Q1=~quantile(., probs = 0.025),
                    mean=mean,median=median, Q3=~quantile(., probs = 0.975),
                    max=max,n=length,sd=sd))
) %>%
  add_column(Sample=c("Ichthyodectiformes","Extant non-anguilliform fishes","Anguilliform fishes","Arthrodira","Arthrodira (including estimated lengths)")) %>%
  mutate(n=as.numeric(n),percentile=paste0("(",round(Q1,3),"–",round(Q3,3),")"),
         confint=paste0("(",round(mean-1.96*(sd/sqrt(n)),3),"–",round(mean+1.96*(sd/sqrt(n)),3),")")) %>%
  select(Sample,n,min,mean,median,max,sd,percentile,confint) %>%
  kable(digits=c(1,1,3,3,3,3,4,1,1),align=c("l","c","c","c","c","c","c","c","c"),
        col.names = c("Sample","N","Minimum","Mean","Median","Maximum","Standard Dev.","95% Quantile","95% Confidence Interval"),
        caption="Comparison of head-total length proportions in Ichthyodectiformes compared to other fishes") %>%
  kable_styling()
Table 4.2: Comparison of head-total length proportions in Ichthyodectiformes compared to other fishes
Sample N Minimum Mean Median Maximum Standard Dev. 95% Quantile 95% Confidence Interval
Ichthyodectiformes 8 0.138 0.147 0.145 0.167 0.0089 (0.138–0.164) (0.141–0.153)
Extant non-anguilliform fishes 853 0.123 0.230 0.226 0.383 0.0398 (0.158–0.312) (0.227–0.232)
Anguilliform fishes 25 0.044 0.143 0.139 0.274 0.0485 (0.053–0.227) (0.124–0.162)
Arthrodira 9 0.151 0.198 0.199 0.242 0.0319 (0.153–0.24) (0.177–0.219)
Arthrodira (including estimated lengths) 24 0.151 0.189 0.181 0.247 0.0265 (0.156–0.244) (0.178–0.2)

Unsurprisingly, ichthyodectiforms have a relatively small head among fishes. What is perhaps more surprising is how extreme their proportions are, being outside the 95% quantile of all examined living fishes and their heads proportionally smaller than even most taxa with elongate trunks (e.g., Amazichthys, Scomberomorus, Coryphaena) with the exception of Cheirocentrus, Alepisaurus, Icosteus, and Scomberoides lysan.

However, Ichthyodectiformes are also consistent in their extreme head-trunk proportions. There is little variation in head-trunk proportions within the group and little evidence of allometry. This suggests Ichthyodectiformes have circumvented the otherwise fairly restrictive constraints on head-trunk proportions in fishes but their proportions subsequently stabilized around a new local optimum. The hyper-elongate bodies of Ichthyodectiformes should be regarded an apomorphy that characterizes the clade (or a node within the clade, like Ichthyodectoidei), similar to what has been proposed for Lampriformes (Engelman 2023). Such extreme proportions should be considered unique to Ichthyodectiformes and are unlikely to be present in other fishes unless strong evidence for a hyper-elongate trunk in those taxa is present.

Arthrodires generally do not show the extreme trunk elongation seen in ichthyodectiforms (which are significantly more elongate-bodied than even Amazichthys), suggesting such proportions are unlikely to be present in Dunkleosteus. A Xiphactinus-like body plan for Dunkleosteus would also require violating relationships that are otherwise consistent within Arthrodira. These include pelvic girdle position, the correlation of the end of the ventral shield with the location of the pelvic girdle and vent/end of the visceral cavity, and the scaling of ventral shield size relative to total length (see manuscript). There is no evidence that Dunkleosteus was an exception in these regards, and indeed CMC VP8294 suggests an arrangement similar to other arthrodires. Ichthyodectiformes notably do not differ from other fishes in the position of their pelvic fin and vent relative to total length (see below), suggesting even though they have a hyper-elongate trunk their body plan still follows some of the general proportional patterns in fishes.

This is to be expected. Even highly constrained morphological or allometric relationships occasionally show outliers, which are expected to be phylogenetically clustered around nodes where novel mutations have allowed circumvention of pre-existing morphological or developmental constraints (Werdelin 1987, Schwenk 1995, Wagner and Schwenk 2000). Other proportions in ichthyodectiformes (such as prepelvic length, see below) are consistent with other fishes. The consistency in anteroposterior head dimensions, pectoral/pelvic fin positions, and ventral shield length in arthrodires (including Dunkleosteus) suggest that Dunkleosteus did not exhibit a hyper-elongate body plan.

Thus, the hyper-elongate bodies of ichthyodectiforms do not invalidate conclusions of a shorter, stockier body plan for Dunkleosteus (as some have proposed in the wake of Engelman 2023), and treating the clearly autapomorphic proportions of one fish group as a suitable analogue for reconstructing the proportions other fishes in the absence of additional morphological evidence suggesting they are reasonable analogues is not tenable.

4.3 Snout-Vent Length (SVL)

4.3.1 Histogram of SVL Proportions

p1_svl <- ggplot(rhizo, aes(x, y)) +
    geom_polygon(fill = "darkgrey",color="black", alpha = 0.5) +
    geom_line(data=data.frame(x=c(1,1),y=c(0.2471672000,-0.03)))+
    geom_line(data=data.frame(x=c(0,0),y=c(0.1627831000,-0.03)))+
    geom_line(data=data.frame(x=c(0,0.502,0.502),
                              y=c(0.055,0.055,0.12)),
              linewidth=1.5,color="steelblue")+
    coord_cartesian(ylim=c(0,0.33))+
    annotate("text",label="snout-vent length",x=0.502,y=0.035,hjust=0.5)+
    theme(axis.title.x=element_blank(),
          axis.text.x=element_blank(),
          axis.ticks.x=element_blank(),
          axis.title.y=element_blank(),
          axis.text.y=element_blank(),
          axis.ticks.y=element_blank(),
          axis.line.y = element_blank(),
          axis.line.x = element_blank())+
    theme_void()

p2_svl <- data_recon %>%
  drop_na(SVL,total_length) %>%
  summarise(.by=taxon,genus=unique(genus),SVL=mean(SVL),total_length=mean(total_length),
            shape=unique(shape),clade=unique(clade)) %>%
  ggplot(.,aes(SVL/total_length)) +
  geom_text(data=. %>% filter(genus %in% c("Electrophorus","Lophotis")) %>%
              group_by(genus) %>% summarise(genus=unique(genus),SVL=mean(SVL),
                                            total_length=mean(total_length)),
            aes(label=genus,x=SVL/total_length),y=c(3,2),fontface=3,angle=90,hjust="left")+
  geom_vline(xintercept = 0) +
  geom_vline(xintercept = 1) +
  geom_histogram(aes(fill=clade),binwidth=0.01)+
  geom_vline(aes(xintercept = mean(SVL/total_length)),linetype="dashed") +
  coord_cartesian(xlim=c(0,1))+
  labs(x="Snout-Vent Length/Total Length",y="# of Species",fill="Clade")+
  theme(legend.position=c(0.8,0.75))

p1_svl / p2_svl + plot_layout(heights = 1:2) & theme(plot.margin = margin(0, 20, 0, 0))
Histogram of SVL as a percentage of total length across gnathostome taxa

Figure 4.2: Histogram of SVL as a percentage of total length across gnathostome taxa

Based on this, snout-vent length is approximately 50-60% of total length in most fishes. The two arthrodires considered, Coccosteus and Incisoscutum, have proportional SVLs close to the mean for all examined fishes.

A third specimen with preserved claspers, referred to Dickosteus threiplandi (NHMUK PV P 49663) has an estimated SVL of 55% preserved length. However, this specimen is highly distorted as preserved and may be missing some of the tail. Thus, this proportion may be an overestimate, especially given Dickosteus is considered a close relative of Coccosteus (both in Coccosteidae).

Assuming the vent of Amazichthys trinajsticae (AA.MEM.DS.8) was located near the posterior level of the pelvic girdle, this would mean its SVL represents ~55% of total length. This resembles what is seen in some other pelagic fishes (Scombridae, Lamnidae), where the abdomen is shortened and the vent ends up at a slightly more posterior position.

Arthrodires seem to show similar vent positions and patterns of variation in this feature to eugnathostomes. The inferred more posterior vent of Amazichthys does not invalidate , because it would actually imply smaller lengths. Assuming SVL/total length proportions similar to Amazichthys would result in lengths of only ~3 m for CMNH 5768 and 3.6 m for the largest individuals of Dunkleosteus, which are clearly unreasonable given the extreme tapering it would require of the caudal peduncle relative to trunk height (see Engelman 2023 for more discussion on why shorter lengths are unlikely). SVL in Dunkleosteus would have to be significantly smaller relative to total length for larger size estimates than presented here to be justified.

summary(lm(log(SVL)~log(total_length),
           data_recon %>%
             drop_na(SVL,total_length) %>%
             group_by(taxon) %>%
             summarise(across(where(is.numeric),mean))))
## 
## Call:
## lm(formula = log(SVL) ~ log(total_length), data = data_recon %>% 
##     drop_na(SVL, total_length) %>% group_by(taxon) %>% summarise(across(where(is.numeric), 
##     mean)))
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -2.01602 -0.08774  0.00941  0.10568  0.59587 
## 
## Coefficients:
##                    Estimate Std. Error t value Pr(>|t|)    
## (Intercept)       -0.765596   0.035626  -21.49   <2e-16 ***
## log(total_length)  1.017057   0.009579  106.18   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.1983 on 509 degrees of freedom
## Multiple R-squared:  0.9568, Adjusted R-squared:  0.9567 
## F-statistic: 1.127e+04 on 1 and 509 DF,  p-value: < 2.2e-16

The allometry regression shows SVL is nearly isometric relative to total length.

4.3.2 Comparing chondrichthyans and osteichthyans

Given this data spans a very broad selection of fishes, it is necessary to demonstrate this proportion is consistent across fishes and does not show differences associated with clade-specific body plans.

4.3.2.1 Box-and-Whisker Plot

data_recon %>%
  drop_na(SVL) %>%
  summarise(SVL=mean(SVL),total_length=mean(total_length),shape=unique(shape),
            clade=unique(clade),habitat=unique(habitat),.by=taxon) %>%
  ggplot(.,aes(x=SVL/total_length,y=clade)) +
  geom_vline(data=. %>% group_by(clade) %>%
               summarise(proportion=mean(SVL/total_length),habitat=unique(shape)),
               aes(xintercept=proportion,color=clade),show.legend=F)+
  geom_point(data=. %>% filter(clade=="Sarcopterygii"),shape=21,aes(fill=clade),
             size=3,show.legend=F)+
  geom_point(data=. %>% filter(clade=="Placodermi"),shape=21,aes(fill=clade),
             size=3,show.legend=F)+
  geom_violin(data=. %>% filter(!clade %in% c("Sarcopterygii","Placodermi")),
              aes(fill=clade),scale="width",show.legend=F)+
  geom_boxplot(data=. %>% filter(!clade %in% c("Sarcopterygii","Placodermi")),
               width=0.25)+
  coord_cartesian(xlim=c(0,1))+
  labs(x="Snout-Vent Length/Total Length",y="Body Shape",fill="Body Shape")
## `summarise()` has grouped output by 'clade'. You can override using the
## `.groups` argument.
Box-and-Whisker plot of SVL/total length in gnathostomes by higher level clade

Figure 4.3: Box-and-Whisker plot of SVL/total length in gnathostomes by higher level clade

4.3.2.2 Mann-Whitney U Test between Chondrichthyans and Osteichthyans

Note: a two-sample Wilcoxon Rank Sum test is the same thing as a Mann-Whitney U test.

wilcox.test(
  data_recon %>% filter(clade=="Chondrichthyes") %>%
    drop_na(SVL) %>%
    mutate(proportion=SVL/total_length) %>%
    group_by(taxon) %>%
    summarise(proportion=mean(proportion)) %>%
    pull(proportion),
  data_recon %>% filter(clade %in% c("Sarcopterygii","Actinopterygii")) %>%
    drop_na(SVL) %>%
    mutate(proportion=SVL/total_length) %>%
    group_by(taxon) %>%
    summarise(proportion=mean(proportion)) %>%
    pull(proportion))
## 
##  Wilcoxon rank sum test with continuity correction
## 
## data:  data_recon %>% filter(clade == "Chondrichthyes") %>% drop_na(SVL) %>% mutate(proportion = SVL/total_length) %>% group_by(taxon) %>% summarise(proportion = mean(proportion)) %>% pull(proportion) and data_recon %>% filter(clade %in% c("Sarcopterygii", "Actinopterygii")) %>% drop_na(SVL) %>% mutate(proportion = SVL/total_length) %>% group_by(taxon) %>% summarise(proportion = mean(proportion)) %>% pull(proportion)
## W = 24522, p-value = 0.5538
## alternative hypothesis: true location shift is not equal to 0

Based on the Mann-Whitney U test, there is no significant difference in vent position relative to total length in chondrichthyans and osteichthyans. Sample sizes are too small to directly compare arthrodires to these other groups, but based on the available data they resemble both of these groups in vent position. Vent position in general seems to be consistent across gnathostomes.

Some sarcopterygians have a more posterior position of the pelvic fins suggesting the vent may more posteriorly positioned in these forms (e.g., Osteolepiformes). However, this appears to be a derived condition given the vent in coelacanths is in a similar position to chondrichthyans and actinopterygians (Lund and Lund 1984, Millot et al. 1978, Saruwatari et al. 2019).

4.3.2.3 Position of Vent Relative to Pelvic and Anal Fins

level_info <- data_recon %>%
  mutate(higher_group=factor(higher_group,ordered=T,levels=c("Arthrodira","Chondrichthyes",
                             "Sarcopterygii","Basal Actinopterygii","Basal Teleostei",
                             "Otocephala","Stem Euteleostei","Acanthopterygii"))) %>%
  drop_na(higher_group,order) %>%
  arrange(higher_group, order) %>% 
  pull(order) %>% 
  unique()

data_recon %>%
  drop_na(prepelvic_length,SVL,preanal_length) %>%
  group_by(taxon) %>%
  summarise(across(where(is.numeric),mean),
            order=unique(order),
            higher_group=unique(higher_group)) %>%
  mutate(venter=preanal_length-prepelvic_length,
         order2=factor(order,levels=rev(level_info))) %>%
  ggplot(.,aes(x=((SVL-prepelvic_length)/venter),y=order2)) +
  labs(x="Position of Vent as a Percent of Prepelvic-Preanal Space",
       y="Order") +
  geom_vline(aes(xintercept=0)) +
  scale_x_continuous(labels = scales::percent)+
  geom_vline(aes(xintercept=1)) +
  geom_violin(aes(fill=higher_group),scale="width",show.legend=F) +
  geom_boxplot(width=0.3)
Position of the vent relative to the pelvic and anal fin origins. Data are reported as length from pelvic origin to vent as a proportion of prepelvic-preanal space.

Figure 4.4: Position of the vent relative to the pelvic and anal fin origins. Data are reported as length from pelvic origin to vent as a proportion of prepelvic-preanal space.

The vent is clearly much closer to the pelvic fin base in arthrodires and chondrichthyans and much closer to the anal fin in teleosts. Some groups like Siluriformes actually show an intermediate vent position, whereas in many acanthopterygians because the pelvic fins are so anterior there can still be a substantial space between the vent and anal fins, despite this value as a percent of prepelvic-preanal length being similar to other teleosts. Because vent position is so consistent among gnathostomes, this suggests actually represents a shift of the fin bases relative to a conserved vent, rather than an actual change in vent position.

The data points with vent position greater than 100% prepelvic-preanal length are cases where snout-vent length was not reported directly and had to be calculated as the sum of reported prepelvic length + pelvic origin-to-vent length. Prepelvic length may have been measured point-to-point (oblique to the anteroposterior axis) and thus summing these values is a slight overapproximation of SVL.

4.3.3 Testing for differences based on body shape

Note, Electrophorus and Lophotis spp. are not included in this analysis because they represent significant outliers.

data_recon %>%
  drop_na(SVL) %>%
  filter(!genus %in% c("Electrophorus","Lophotis")) %>%
  group_by(taxon) %>%
  summarise(SVL=mean(SVL),total_length=mean(total_length),shape=unique(shape),clade=unique(clade),habitat=unique(habitat)) %>%
  ggplot(.,aes(x=SVL/total_length,y=shape)) +
  geom_vline(data=. %>% group_by(shape) %>%
               summarise(proportion=mean(SVL/total_length),habitat=unique(shape)),
               aes(xintercept=proportion,color=shape),show.legend=F)+
  geom_violin(aes(fill=shape),scale="width",show.legend=F)+
  geom_boxplot(width=0.25)+
  coord_cartesian(xlim=c(0,1))+
  labs(x="Snout-Vent Length/Total Length",y="Body Shape",fill="Body Shape")+
  theme(legend.position=c(0.15,0.75))
Box-and-whisker plot of SVL as a proportion of total length in extant fishes

Figure 4.5: Box-and-whisker plot of SVL as a proportion of total length in extant fishes

Based on this, there appears to be relatively little variation in vent position based on body shape. Even anguilliform taxa generally have anuses located close to the midpoint of the body. Macruriform taxa are an exception, primarily because the extremely elongate caudal fin in these species results in a greater total length relative to SVL. The caudal fin of macruriform taxa does not appear to be constrained by the same factors that restrict proportional relationships in other fishes (see Engelman 2023).

4.3.4 Box and Whisker Plot by Habitus

data_recon %>%
  drop_na(SVL,total_length,habitat) %>%
  summarise(.by=taxon,
            SVL=mean(SVL),total_length=mean(total_length),shape=unique(shape),
            clade=unique(clade),habitat=unique(habitat)) %>%
  ggplot(.,aes(x=SVL/total_length,y=habitat)) +
  geom_vline(data=. %>%
               summarise(.by=habitat,
                         proportion=mean(SVL/total_length)),
               aes(xintercept=proportion,color=habitat),show.legend=F)+
  geom_violin(aes(fill=habitat),scale="width",show.legend=F)+
  geom_boxplot(width=0.25)+
  coord_cartesian(xlim=c(0,1))+
  labs(x="Snout-Vent Length/Total Length",y="Habitus",fill="Habitus")
Box-and-whisker plot of SVL as a proportion of total length in extant fishes, grouped by life habits

Figure 4.6: Box-and-whisker plot of SVL as a proportion of total length in extant fishes, grouped by life habits

Based on these results benthic taxa seem to have a more anterior vent relative to total length, whereas pelagic forms have a more posterior vent relative to total length. The more anterior position in benthic taxa seems to be driven by the elongate caudal fins in many forms (e.g., Stegostoma tigrinum). By contrast, the longer SVL relative to body length in pelagic forms may be related to them more attenuated abdomen of these taxa.

data_recon %>%
  group_by(taxon) %>%
  drop_na(precaudal_length,SVL) %>%
  summarise(SVL=mean(SVL),precaudal_length=mean(precaudal_length),shape=unique(shape),
            clade=unique(clade),habitat=unique(habitat)) %>%
  ggplot(.,aes(x=SVL/precaudal_length,y=habitat)) +
  geom_vline(data=. %>% group_by(habitat) %>%
               summarise(proportion=mean(SVL/precaudal_length),habitat=unique(habitat)),
               aes(xintercept=proportion,color=habitat),show.legend=F)+
  geom_violin(aes(fill=habitat))+
  geom_boxplot(width=0.25)+
  coord_cartesian(xlim=c(0,1))+
  labs(x="Snout-Vent Length/Precaudal Length",y="Habitus",fill="Habitus")+
  theme(legend.position=c(0.15,0.75))
Box-and-whisker plot of SVL as a proportion of precaudal length in extant fishes,grouped by life habits

Figure 4.7: Box-and-whisker plot of SVL as a proportion of precaudal length in extant fishes,grouped by life habits

However, even when considering SVL as a proportion of precaudal length pelagic taxa still have more posteriorly placed vents and benthic taxa have more anteriorly placed ones. I.e., benthic taxa seem to have slightly longer abdomens, and pelagic taxa have slightly shorter ones.

More data are needed, but the present dataset implies Dunkleosteus could potentially have a more posteriorly positioned vent relative to total length than Coccosteus and Incisoscutum, given the shorter abdomens seen in many pelagic fishes.

4.3.5 Approximate vent position in Ichthyodectiformes

data_recon %>%
  filter(order=="Ichthyodectiformes") %>%
  mutate(ratio1=preanal_length/total_length,
         ratio2=(((prepelvic_length+preanal_length)/2)/total_length)) %>%
  group_by(taxon) %>%
  summarise(ratio1=mean(ratio1),ratio2=mean(ratio2)) %>%
  ungroup() %>%
  summarise(ratio1=mean(ratio1),ratio2=mean(ratio2),N=n()) %>%
  kable(caption="Approximate location of the vent in Ichthyodectiformes as a percentage of total length",
        digits=3,align="c",col.names = c("Assuming vent is located at anal fin base", "Assuming vent is intermediate between pelvic and anal fin origins","N Species")) %>%
  kable_styling()
Table 4.3: Approximate location of the vent in Ichthyodectiformes as a percentage of total length
Assuming vent is located at anal fin base Assuming vent is intermediate between pelvic and anal fin origins N Species
0.595 0.524 8

Assuming the vent is between the pelvic and anal fins, as is the case in most fishes, or close to the base of the anal fin, as in most actinopterygians, proportional SVL in Ichthyodectiformes is similar to other fishes, and is particularly similar to the anus position in other pelagic species.

4.4 Pre-Pectoral Length

# separating y-axis into clades of interest

prepec1<-data_recon %>%
  drop_na(prepectoral_length,total_length,clade,higher_group) %>%
  mutate(clade=as.character(clade),
         higher_group=ifelse(genus=="Dunkleosteus","Dunkleosteus",higher_group),
         higher_group=ifelse(genus=="Eastmanosteus","Eastmanosteus",higher_group),
         higher_group=ifelse(higher_group=="Arthrodira" & 
                               length_as == "estimated t.l." & genus !="Dunkleosteus",
                             "Arthrodira (est. lengths)",higher_group),
         higher_group=ifelse(higher_group=="Arthrodira",
                             "Arthrodira (known lengths)",higher_group),
         higher_group=ifelse(genus=="Alopias","Alopias",higher_group),
         higher_group=ifelse(order=="Chimaeriformes","Holocephali",higher_group),
         higher_group=ifelse(higher_group=="Chondrichthyes",
                             "Other Elasmobranchii",higher_group),
         higher_group=ifelse(order=="Ichthyodectiformes",
                             "Ichthyodectiformes",higher_group),
         higher_group=ifelse(shape=="anguilliform","Anguilliform Taxa",higher_group),
         clade=ifelse(shape=="anguilliform",NA,clade),
         higher_group=factor(higher_group,ordered=T,
                             levels=c("Dunkleosteus","Eastmanosteus",
                                      "Arthrodira (known lengths)",
                                      "Arthrodira (est. lengths)",
                                      "Other Elasmobranchii", "Holocephali",
                                      "Alopias","Sarcopterygii","Basal Actinopterygii",
                                      "Ichthyodectiformes", "Basal Teleostei",
                                      "Otocephala", "Stem Euteleostei", 
                                      "Acanthopterygii","Anguilliform Taxa")))

# summarising values for non-placoderms

prepec_2<-bind_rows(prepec1 %>%
            filter(clade == "Placodermi"),
          prepec1 %>%
            filter(clade!="Placodermi"|is.na(clade)) %>%
            group_by(taxon) %>%
            summarize(across(where(is.numeric),mean),
                      higher_group=unique(higher_group),
                      taxon=unique(taxon),genus=unique(genus),species=unique(species),
                      clade=unique(clade,na.rm=F),shape=unique(shape)))

# plotting graph

p1_pec <- ggplot(rhizo, aes(x, y)) +
    geom_polygon(fill = "darkgrey",color="black", alpha = 0.5) +
    geom_line(data=data.frame(x=c(1,1),y=c(0.2471672000,-0.03)))+
    geom_line(data=data.frame(x=c(0,0),y=c(0.1627831000,-0.03)))+
    geom_line(data=data.frame(x=c(0,0.225,0.225),
                              y=c(0.055,0.055,0.105)),
              linewidth=1.5,color="steelblue")+
    coord_cartesian(ylim=c(0,0.33))+
    annotate("text",label="pre-pectoral length",x=0.225,y=0.035,hjust=1)+
    theme(axis.title.x=element_blank(),
          axis.text.x=element_blank(),
          axis.ticks.x=element_blank(),
          axis.title.y=element_blank(),
          axis.text.y=element_blank(),
          axis.ticks.y=element_blank(),
          axis.line.y = element_blank(),
          axis.line.x = element_blank())+
    theme_void()

p2_pec <- prepec_2 %>%
  ggplot(aes(x=prepectoral_length/total_length,y=higher_group)) +
  coord_cartesian(xlim=c(0,1))+
  scale_y_discrete(limits=rev)+
  scale_x_continuous(labels = scales::percent)+
  labs(x="Pre-Pectoral Length (as percent of total length)",y="Clade")+
  geom_vline(data=. %>% filter(genus=="Dunkleosteus"),
             aes(xintercept=mean(prepectoral_length/total_length)),
             color="#00B0F6",linetype="dashed")+
  geom_vline(aes(xintercept=mean(prepectoral_length/total_length)),
             linetype="dashed")+
  geom_vline(xintercept = 0) +
  geom_vline(xintercept = 1) +
  geom_violin(aes(fill=clade),show.legend = F,scale="width")+
  geom_violin(data=.%>%filter(genus=="Dunkleosteus"),fill="#00B0F6",
              show.legend = F,scale="width")+
  geom_boxplot(width=0.3)+
  geom_star(data=. %>% filter(genus=="Eastmanosteus"),
            fill="white",color="black",size=2.5)+
  theme(axis.text.y = element_text(face=c(rep("plain",8),"italic",
                                          rep("plain",4),"italic","italic")))


p1_pec / p2_pec + plot_layout(heights = 1:2) & theme(plot.margin = margin(0, 20, 0, 0))
Box-and-whisker plot of prepectoral length as a percentage of total length in gnathostomes, showing how Dunkleosteus has a relatively anterior pectoral fin girdle relative to the total lengths predicted in Engelman (2023). Data for non-placoderms reported as species averages where placoderms are reported in terms of individual specimens to better show the consistency in these proportions between specimens.

Figure 4.8: Box-and-whisker plot of prepectoral length as a percentage of total length in gnathostomes, showing how Dunkleosteus has a relatively anterior pectoral fin girdle relative to the total lengths predicted in Engelman (2023). Data for non-placoderms reported as species averages where placoderms are reported in terms of individual specimens to better show the consistency in these proportions between specimens.

Dunkleosteus has one of the most anteriorly positioned pectoral fins in any examined fish, living or extinct. The more anterior pectoral fin position in Dunkleosteus relative to other arthrodires is evident based on trunk armor morphology (see manuscript), but this condition extends to fishes in general. This cannot be due to the length estimates calculated by Engelman (2023), as longer body lengths for D. terrelli make this proportion more extreme, potentially to the point of being biomechanically unreasonable.

Other arthrodires resemble broader patterns among eugnathostomes in relative pectoral fin position. These proportions are consistent regardless of whether total lengths are directly measured or estimated via OOL. One exception is the dunkleosteoid Eastmanosteus calliaspis, which shows values similar to D. terrelli, and also shows a more anterior pectoral fenestra than any other eubrachythoracid examined except D. terrelli (see manuscript). This indicates a relatively anterior position of the pectoral fin may be an apomorphy of dunkleosteoids. Some aspinothoracidans may show a similar condition (Brachyosteus, Enseosteus), though this is not universal among members of this group (it is absent in Amazichthys or Heintzichthys), and the condition is not quite as extreme as in Dunkleosteus.

data_recon %>%
  mutate(group=case_when(order == "Carangiformes" ~ "Carangiformes",
                         genus == "Dunkleosteus" ~ "*Dunkleosteus*",
                         genus == "Incisoscutum" ~ "*Incisoscutum*",
                         family == "Coccosteidae" ~ "Coccosteidae",
                         order == "Clupeiformes" & family!="Cheirocentridae" ~ "Other Clupeiformes",
                         family == "Megalopidae" ~ "Megalopidae",
                         genus == "Amazichthys" ~ "*Amazichthys*",
                         family == "Salmonidae" ~ "Salmonidae",
                         family == "Cheirocentridae" ~ "Cheirocentridae",
                         family == "Lamnidae" ~ "Lamnidae",
                         family == "Carcharhinidae" ~ "Carcharhinidae",
                         family == "Squalidae" ~ "Squalidae",
                         family == "Lampridae" ~ "Lampridae",
                         order == "Istiophoriformes" ~ "Istiophoriformes",
                         order == "Ichthyodectiformes" ~ "Ichthyodectiformes",
                         family == "Sphyraenidae" ~ "Sphyraenidae",
                         family == "Scombridae" ~ "Scombridae",
                         genus == "Eastmanosteus" ~ "*Eastmanosteus*")) %>%
  drop_na(group,prepectoral_length,total_length) %>%
  mutate(ppl = 100*(prepectoral_length/total_length)) %>%
  group_by(taxon) %>%
  summarise(higher_group=unique(higher_group),mean1=mean(ppl),max=max(ppl),min=min(ppl),n=n(),group=unique(group),clade=unique(clade)) %>%
  group_by(group) %>%
  summarise(higher_group=unique(higher_group),clade=unique(clade),
            mean2=mean(mean1),min1=min(mean1),max1=max(mean1),
            sd=sd(mean1),min2=min(min),max2=max(max),Nspec=sum(n),n=n())%>%
  mutate(higher_group=factor(higher_group,ordered=T,levels=c("Arthrodira",
                                                             "Basal Actinopterygii",
                                                             "Basal Teleostei",
                                                             "Otocephala",
                                                             "Stem Euteleostei",
                                                             "Acanthopterygii",
                                                             "Chondrichthyes")),
         min1=ifelse(n==1,NA,min1),
         max1=ifelse(n==1,NA,max1)) %>%
  arrange(higher_group,group) %>%
  select(-higher_group) %>%
  kable(col.names=c("Taxon","Clade","Mean","Minimum","Maximum","St. Dev",
                    "Min. Obs.","Max. Obs.",
                    "Observations","Species"),
        digits=1, align=c("l","c","c","c","c","c","c","c","c","c"),
        caption="Pre-pectoral length in <i>Dunkleosteus</i> as a percent of total length in select nektonic (mostly pelagic) fish clades. Note how <i>Dunkleosteus</i> shows a pre-pectoral length comparable to or shorter than the highly elongate Cheirocentridae and Ichthyodectiformes even when using the lengths estimated by Engelman (2023). Data are presented as averages of species averages to avoid bias from any one taxon. Data are described as 'observations' rather than specimens as some data points are species averages reported in literature. 'Min Obs.' and 'Max Obs' represent the minimum and maximum pre-averaged observation for each group.") %>%
  add_header_above(c(" "=2,"Percent Pre-Pectoral Length"=4,"Data Extrema"=2,"Sample Size"=2))%>%
  row_spec(2,bold=T)%>%
  kable_styling()
Table 4.4: Pre-pectoral length in Dunkleosteus as a percent of total length in select nektonic (mostly pelagic) fish clades. Note how Dunkleosteus shows a pre-pectoral length comparable to or shorter than the highly elongate Cheirocentridae and Ichthyodectiformes even when using the lengths estimated by Engelman (2023). Data are presented as averages of species averages to avoid bias from any one taxon. Data are described as ‘observations’ rather than specimens as some data points are species averages reported in literature. ‘Min Obs.’ and ‘Max Obs’ represent the minimum and maximum pre-averaged observation for each group.
Percent Pre-Pectoral Length
Data Extrema
Sample Size
Taxon Clade Mean Minimum Maximum St. Dev Min. Obs. Max. Obs. Observations Species
Amazichthys Placodermi 23.1 23.1 23.1 1 1
Dunkleosteus Placodermi 13.1 11.2 14.6 5 1
Eastmanosteus Placodermi 13.3 13.3 13.3 1 1
Incisoscutum Placodermi 21.1 19.3 22.8 2 1
Coccosteidae Placodermi 20.8 18.6 23.7 2.7 15.4 23.7 7 3
Ichthyodectiformes Actinopterygii 13.7 12.1 15.8 1.4 12.1 15.8 7 7
Megalopidae Actinopterygii 18.5 17.6 19.4 1.3 15.5 22.7 6 2
Cheirocentridae Actinopterygii 14.5 14.3 14.8 0.3 12.3 17.7 8 2
Other Clupeiformes Actinopterygii 18.6 15.8 21.8 1.9 14.8 24.1 51 17
Lampridae Actinopterygii 28.3 27.3 28.8 0.7 27.3 28.8 4 4
Salmonidae Actinopterygii 18.8 15.3 22.3 2.3 13.6 25.7 35 12
Carangiformes Actinopterygii 21.2 14.6 27.6 3.1 14.1 28.5 128 60
Istiophoriformes Actinopterygii 21.1 18.7 22.7 1.4 12.8 24.5 147 10
Scombridae Actinopterygii 23.0 15.1 29.4 3.8 15.1 32.5 106 33
Sphyraenidae Actinopterygii 25.4 23.3 28.2 1.6 21.9 28.2 40 13
Carcharhinidae Chondrichthyes 22.1 18.1 24.6 1.4 16.8 28.2 234 41
Lamnidae Chondrichthyes 26.2 24.8 27.8 1.3 20.1 30.2 31 4
Squalidae Chondrichthyes 21.8 18.0 24.8 1.7 15.0 24.8 37 15

The pectoral fin origin of Ichthyodectiformes is more anterior than most extant fishes, but this is due to hyper-elongation of the trunk relative to a conserved pectoral girdle morphology rather than an unusual morphology of the pectoral girdle and trunk armor allowing a more anteroventral position of the pectoral fin as in Dunkleosteus.

p1_pec_xip <- ggplot(rhizo, aes(x, y)) +
    geom_polygon(fill = "darkgrey",color="black", alpha = 0.5) +
    geom_line(data=data.frame(x=c(1,1),y=c(0.2471672000,-0.03)))+
    geom_line(data=data.frame(x=c(0,0),y=c(0.1627831000,-0.03)))+
    geom_line(data=data.frame(x=c(0,0.225,0.225),
                              y=c(0.055,0.055,0.105)),
              linewidth=1.5,color="steelblue")+
    coord_cartesian(ylim=c(0,0.33),xlim=c(0,.35))+
    annotate("text",label="pre-pectoral length",x=0.225,y=0.045,hjust=1)+
    theme(axis.title.x=element_blank(),
          axis.text.x=element_blank(),
          axis.ticks.x=element_blank(),
          axis.title.y=element_blank(),
          axis.text.y=element_blank(),
          axis.ticks.y=element_blank(),
          axis.line.y = element_blank(),
          axis.line.x = element_blank())+
    theme_void()

p2_pec_xip <- prepec_2 %>%
  mutate(total_length=ifelse(genus=="Dunkleosteus",
                head_length * (data_recon %>% filter(order=="Ichthyodectiformes") %>%
                                 group_by(taxon) %>%
                                 summarise(head_length=mean(head_length),
                                 total_length=mean(total_length)) %>%
                                 mutate(head_trunk_ratio=total_length/head_length) %>%
                                 pull(head_trunk_ratio) %>% mean()),
                total_length)) %>%
  ggplot(aes(x=prepectoral_length/total_length,y=higher_group)) +
  scale_y_discrete(limits=rev)+
  scale_x_continuous(labels = scales::percent)+
  coord_cartesian(xlim=c(0,.35))+
  geom_vline(xintercept=0)+
  labs(x="Percent Pre-Pectoral Length",y="Clade")+
  geom_vline(data=. %>% filter(genus=="Dunkleosteus"),
             aes(xintercept=mean(prepectoral_length/total_length)),
             linetype="dashed")+
  geom_violin(aes(fill=clade),show.legend = F,scale="width")+
  geom_boxplot(width=0.3)+
  geom_star(data=. %>% filter(genus=="Eastmanosteus"),fill="white",color="black",size=2.5)+
  theme(axis.text.y = element_text(face=c(rep("plain",8),"italic",
                                          rep("plain",4),"italic","italic")))

p1_pec_xip / p2_pec_xip + plot_layout(heights = 1.15:2) & theme(plot.margin = margin(0, 20, 0, 0))
Pre-pectoral length in Dunkleosteus assuming head-trunk proportions similar to Ichthyodectiformes, showing how this results in a more anterior position of the pectoral fin than almost any other non-anguilliform fish. Data for non-placoderms reported as species averages where placoderms are reported in terms of individual specimens to better show the consistency in these proportions between specimens.

Figure 4.9: Pre-pectoral length in Dunkleosteus assuming head-trunk proportions similar to Ichthyodectiformes, showing how this results in a more anterior position of the pectoral fin than almost any other non-anguilliform fish. Data for non-placoderms reported as species averages where placoderms are reported in terms of individual specimens to better show the consistency in these proportions between specimens.

If artificially manipulating Dunkleosteus to have head-trunk proportions similar to Ichthyodectiformes (which have a head around 1/7 total length), this results in Dunkleosteus having a pectoral fin significantly more anterior than almost any other fish (only 11% total length), to the point of being an unusual outlier. This seems unlikely, because if the pectoral fin is positioned too far anteriorly it might be expected to have negative biomechanical consequences like destabilizing the animal during swimming (see manuscript).

data_recon %>%
  filter(genus=="Dunkleosteus") %>%
  add_row(specimen="CMNH 5936",head_length=72.4,total_length=409) %>%
  mutate(total_length2=
                head_length * (data_recon %>% filter(order=="Ichthyodectiformes") %>%
                                 group_by(taxon) %>%
                                 summarise(head_length=mean(head_length),
                                 total_length=mean(total_length)) %>%
                                 mutate(head_trunk_ratio=total_length/head_length) %>%
                                 pull(head_trunk_ratio) %>% mean())) %>%
  select(specimen, head_length, total_length, total_length2) %>%
  mutate(head_length=ifelse(head_length==72.4,"~72.4",
                            sprintf("%.1f", round(head_length,1)))) %>%
  arrange(total_length) %>%
  kable(digits=1,align=c("l","c","c","c"),
        col.names = c("Specimen","Head Length","Total Length (using OOL)", "Total Length (assuming ichthyodectiform-like proportions)"),
        caption="Total lengths for specimens of <i>Dunkleosteus terrelli</i> assuming similar head-trunk proportions to Ichthyodectiformes (e.g., <i>Xiphactinus</i>). Head size in CMNH 5936 based on scaling from the oral region of the infragnathal and allometric patterns within <i>D. terrelli</i> (see Engelman 2023)") %>%
  kable_styling
Table 4.5: Total lengths for specimens of Dunkleosteus terrelli assuming similar head-trunk proportions to Ichthyodectiformes (e.g., Xiphactinus). Head size in CMNH 5936 based on scaling from the oral region of the infragnathal and allometric patterns within D. terrelli (see Engelman 2023)
Specimen Head Length Total Length (using OOL) Total Length (assuming ichthyodectiform-like proportions)
CMNH 8982 28.8 154.8 196.7
CMC VP8294 23.6 157.3 161.1
CMNH 6194 29.0 166.3 198.0
CMNH 7424 34.0 188.9 232.1
CMNH 6090 51.0 283.3 348.2
CMNH 7054 53.6 295.5 366.0
CMNH 5768 61.3 340.7 418.5
CMNH 5936 ~72.4 409.0 494.2

Additionally, even assuming ichthyodectiform-like proportions in Dunkleosteus terrelli it is not possible to produce lengths greater than 5 m for the largest known individuals.

4.4.1 Predicting in Dunkleosteus terrelli

4.4.1.1 Setting up Regressions

Without Log-Transformation

fit.pectoral<-lm(total_length~prepectoral_length,
                 data=data_recon %>%
                   filter(length_as!="estimated t.l."))

summary(fit.pectoral)
## 
## Call:
## lm(formula = total_length ~ prepectoral_length, data = data_recon %>% 
##     filter(length_as != "estimated t.l."))
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -143.39   -6.48   -2.16    3.82  368.34 
## 
## Coefficients:
##                    Estimate Std. Error t value Pr(>|t|)    
## (Intercept)         3.75489    0.59261   6.336 2.81e-10 ***
## prepectoral_length  4.35435    0.02299 189.368  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 21.79 on 2376 degrees of freedom
##   (321 observations deleted due to missingness)
## Multiple R-squared:  0.9379, Adjusted R-squared:  0.9378 
## F-statistic: 3.586e+04 on 1 and 2376 DF,  p-value: < 2.2e-16
regression.stats(fit.pectoral)

With Log-Transformation

fit.pectoral_2<-lm(log(total_length)~log(prepectoral_length),
                 data=data_recon %>%
                   filter(length_as!="estimated t.l."))

summary(fit.pectoral_2)
## 
## Call:
## lm(formula = log(total_length) ~ log(prepectoral_length), data = data_recon %>% 
##     filter(length_as != "estimated t.l."))
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -0.48477 -0.13078 -0.00965  0.11106  1.64119 
## 
## Coefficients:
##                         Estimate Std. Error t value Pr(>|t|)    
## (Intercept)             1.613595   0.009533   169.3   <2e-16 ***
## log(prepectoral_length) 0.966160   0.003753   257.4   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.1897 on 2376 degrees of freedom
##   (321 observations deleted due to missingness)
## Multiple R-squared:  0.9654, Adjusted R-squared:  0.9654 
## F-statistic: 6.627e+04 on 1 and 2376 DF,  p-value: < 2.2e-16
regression.stats(fit.pectoral_2)

4.4.1.2 Estimating

data_recon %>% filter(genus=="Dunkleosteus") %>%
  drop_na(prepectoral_length) %>%
  arrange(prepectoral_length) %>%
  rename(OOL_length=total_length) %>%
  augment(fit.pectoral,newdata=.,interval="prediction") %>%
  rename_at(vars(starts_with('.')), funs(paste0("pectoral1",.)))%>%
  augment(fit.pectoral_2,newdata=.,interval="prediction") %>%
  mutate(across(.fitted:.upper,~exp(.)*regression.stats(fit.pectoral_2)$CF))%>%
  rename_at(vars(starts_with('.')), funs(paste0("pectoral2",.)))%>%
  mutate(OOL.pe=paste0("(",round(minlength,1),"–",round(maxlength,1),")"),
         pectoral1.range=paste0("(",round(pectoral1.lower,1),"–",round(pectoral1.upper,1),")"),
         pectoral2.range=paste0("(",round(pectoral2.lower,1),"–",round(pectoral2.upper,1),")"))%>%
  select(specimen,prepectoral_length,OOL_length,OOL.pe,
         pectoral1.fitted,pectoral1.range,
         pectoral2.fitted,pectoral2.range) %>%
  kable(digits=1,col.names=c("Specimen","Prepectoral Length",
                             "Est.","+/- %PE","Est.","95% P.I.",
                             "Est.","95% P.I."),
        align=c("l","c","c","c","c","c","c","c")) %>%
  add_header_above(c(" "=2,"Orbit-Opercular Length"=2,"Prepectoral Length, non-log-transformed"=2,
                   "Prepectoral Length, log-transformed"=2)) %>%
  kable_styling()
Orbit-Opercular Length
Prepectoral Length, non-log-transformed
Prepectoral Length, log-transformed
Specimen Prepectoral Length Est. +/- %PE Est. 95% P.I. Est. 95% P.I.
CMC VP8294 19.9 157.3 (137.8–176.9) 90.4 (47.6–133.1) 92.0 (63.4–133.4)
CMNH 7424 21.1 188.9 (165.5–212.4) 95.8 (53–138.5) 97.5 (67.2–141.5)
CMNH 6090 37.7 283.3 (248.2–318.4) 167.8 (125.1–210.6) 170.5 (117.5–247.4)
CMNH 7054 43.1 295.5 (258.9–332.2) 191.5 (148.8–234.3) 194.2 (133.9–281.8)
CMNH 5768 46.5 340.7 (298.4–382.9) 206.4 (163.6–249.2) 209.1 (144.1–303.4)

Prepectoral length produces lengths that are somewhat in the range of OOL, but much shorter. This is to be expected given the extreme anterior position of the scapulocoracoid in Dunkleosteus. However, it is important to note that even the 95% prediction intervals for prepectoral length, which are expected to be much wider than the intervals based on +/- PE, still do not allow for greater lengths and longer trunks for D. terrelli.

fit.pectoral_3<-lm(log(total_length)~log(prepectoral_length),
                   data_recon %>%
                     filter(length_as=="total length",higher_group!="Acanthopterygii" &
                              !(order %in% c("Gadiformes","Aulopiformes"))))
data_recon %>% filter(genus=="Dunkleosteus") %>%
  drop_na(prepectoral_length) %>%
  arrange(prepectoral_length) %>%
  rename(OOL_length=total_length) %>%
  augment(fit.pectoral_3,newdata=.,interval="prediction") %>%
  mutate(across(.fitted:.upper,~exp(.)*regression.stats(fit.pectoral_3)$CF))%>%
  rename_at(vars(starts_with('.')), funs(paste0("pectoral2",.)))%>%
  mutate(OOL.pe=paste0("(",round(minlength,1),"–",round(maxlength,1),")"),
         pectoral2.range=paste0("(",round(pectoral2.lower,1),"–",round(pectoral2.upper,1),")"))%>%
  select(specimen,prepectoral_length,OOL_length,OOL.pe,
         pectoral2.fitted,pectoral2.range) %>%
  kable(digits=1,col.names=c("Specimen","Prepectoral Length",
                             "Est.","+/- %PE",
                             "Est.","95% P.I."),
        align=c("l","c","c","c","c","c","c","c")) %>%
  add_header_above(c(" "=2,"Orbit-Opercular Length"=2,
                   "Prepectoral Length, log-transformed"=2)) %>%
  kable_styling()
Orbit-Opercular Length
Prepectoral Length, log-transformed
Specimen Prepectoral Length Est. +/- %PE Est. 95% P.I.
CMC VP8294 19.9 157.3 (137.8–176.9) 97.6 (68.7–138.7)
CMNH 7424 21.1 188.9 (165.5–212.4) 103.4 (72.7–146.9)
CMNH 6090 37.7 283.3 (248.2–318.4) 178.3 (125.5–253.4)
CMNH 7054 43.1 295.5 (258.9–332.2) 202.5 (142.5–287.8)
CMNH 5768 46.5 340.7 (298.4–382.9) 217.6 (153.1–309.3)

Similar results occur even if restricting comparisons to taxa without anteriorly positioned pelves (non-acanthopterygians).

4.5 Pre-Pelvic Length

p1_pelv <- ggplot(rhizo, aes(x, y)) +
    geom_polygon(fill = "darkgrey",color="black", alpha = 0.5) +
    geom_line(data=data.frame(x=c(1,1),y=c(0.2471672000,-0.03)))+
    geom_line(data=data.frame(x=c(0,0),y=c(0.1627831000,-0.03)))+
    geom_line(data=data.frame(x=c(0,0.454,0.454),
                              y=c(0.055,0.055,0.105)),
              linewidth=1.5,color="steelblue")+
    coord_cartesian(ylim=c(0,0.33))+
    annotate("text",label="pre-pelvic length",x=0.454,y=0.035,hjust=0.5)+
    theme(axis.title.x=element_blank(),
          axis.text.x=element_blank(),
          axis.ticks.x=element_blank(),
          axis.title.y=element_blank(),
          axis.text.y=element_blank(),
          axis.ticks.y=element_blank(),
          axis.line.y = element_blank(),
          axis.line.x = element_blank())+
    theme_void()

p2_pelv <- data_recon %>%
  mutate(clade=ifelse(higher_group == "Acanthopterygii","Acanthopterygii",clade),
         clade=ifelse(order %in% c("Gadiformes","Aulopiformes"),"Gadiformes, Aulopiformes",clade),
         clade=ifelse(clade=="Actinopterygii","Other Actinopterygii",clade),
         clade=factor(clade,ordered=T,levels=c("Acanthopterygii","Gadiformes, Aulopiformes","Other Actinopterygii","Chondrichthyes","Placodermi","Sarcopterygii"))) %>%
  drop_na(prepelvic_length,total_length) %>%
  group_by(taxon) %>%
  summarise(genus=unique(genus),prepelvic_length=mean(prepelvic_length),
            total_length=mean(total_length),
            shape=unique(shape),clade=unique(clade)) %>%
  ggplot(.,aes(prepelvic_length/total_length)) +
  geom_vline(xintercept = 0) +
  geom_vline(xintercept = 1) +
  geom_histogram(aes(fill=clade),binwidth=0.01)+
  scale_fill_manual(values=c("darkgrey",hue_pal()(5)))+
  geom_vline(data = . %>% 
               filter (!clade %in% c("Acanthopterygii","Gadiformes","Aulopiformes")),
             aes(xintercept = mean(prepelvic_length/total_length)),linetype="dashed") +
  coord_cartesian(xlim=c(0,1))+
  labs(x="Pre-Pelvic Length/Total Length",y="# of Species",fill="Clade")+
  theme(legend.position=c(0.775,0.75))

p1_pelv / p2_pelv + plot_layout(heights = 1:2) & theme(plot.margin = margin(0, 20, 0, 0))
Histogram of pre-pelvic length in fishes, using species averages. Dashed line represents mean value for all non-acanthopterygian taxa (excluding Gadiformes and Aulopiformes). All data are in species averages except for Dunkleosteus, to show that individual variation does not change interpretations of pelvic fin location.

Figure 4.10: Histogram of pre-pelvic length in fishes, using species averages. Dashed line represents mean value for all non-acanthopterygian taxa (excluding Gadiformes and Aulopiformes). All data are in species averages except for Dunkleosteus, to show that individual variation does not change interpretations of pelvic fin location.

Overall, pre-pelvic length as a proportion of total length is relatively consistent across non-acanthopterygian fishes. On average, pre-pelvic length is around 45% of total length in non-acanthopterygian fishes, with almost all taxa falling between 35% and 55% total length.

Outliers do exist within this relationship, but for the most part these are restricted to certain phylogenetic nodes within the sample. A more posterior pelvic fin position (~60% TL) is seen in Polypteriformes and deep-sea Squaliformes (Centrophoridae, Dalatiidae, Etmopteridae, Oxynotidae, Somniosidae), the latter of which form a monophyletic clade (Straube et al. 2015) characterized by an extreme posterior position of the pelvic fins. Large Carcharhiniformes and Lamniformes also have slightly more posteriorly positioned pelvic fins than other sharks (~50% TL), which may be due to the larger livers of these taxa (Gleiss et al. 2017) and the shorter abdomens of pelagic Lamniformes (Sternes and Shimada 2020). Pre-pelvic length is a smaller proportion of body length in A more anterior position of the pelvic fins is present in benthic sharks with elongate abdomens (e.g., Hemiscyllidae; Sternes and Shimada 2020) and some characids.

# separating y-axis into clades of interest

pelvprecaudal_1<-
  data_recon %>%
  mutate(prepelvic_length=ifelse(specimen %in% "CMC VP8294", 70.77,prepelvic_length),
         prepelvic_length=ifelse(specimen %in% "CMNH 7424", 70.15,prepelvic_length),
         prepelvic_length=ifelse(specimen %in% "CMNH 6090", 121.77,prepelvic_length),
         prepelvic_length=ifelse(specimen %in% "CMNH 7054", 126.06,prepelvic_length),
         prepelvic_length=ifelse(specimen %in% "CMNH 5768", 137.71,prepelvic_length)) %>%
  filter(length_as=="total length"|genus=="Dunkleosteus") %>%
  mutate(pvl1 = prepelvic_length/total_length,
         pvl2 = prepelvic_length/precaudal_length,
         higher_group=ifelse(order %in% c("Aulopiformes","Gadiformes"),"Aulopiformes, Gadiformes",higher_group),
         higher_group=ifelse(family %in% c("Dalatiidae","Etmopteridae","Oxynotidae","Somniosidae","Centrophoridae"),"Deep Sea Squaliformes",higher_group),
         higher_group=ifelse(order == "Chimaeriformes","Holocephali",higher_group),
         higher_group=ifelse(order == "Beloniformes","Beloniformes",higher_group),
         higher_group=ifelse(genus == "Alopias","*Alopias*",higher_group),
         higher_group=ifelse(order == "Ichthyodectiformes","Ichthyodectiformes",higher_group),
         higher_group=ifelse(higher_group=="Chondrichthyes","Other Elasmobranchii",higher_group),
         higher_group=ifelse(genus=="Dunkleosteus","*Dunkleosteus* (est.)",higher_group))

# summarising values for non-Dunkleosteus taxa (total length)
         
pelvprecaudal_2<-bind_rows(pelvprecaudal_1 %>%
            filter(genus == "Dunkleosteus") %>%
            drop_na(pvl1),
          pelvprecaudal_1 %>%
            filter(genus!="Dunkleosteus"|is.na(higher_group)) %>%
            group_by(taxon) %>%
            drop_na(pvl1) %>%
            summarize(across(where(is.numeric),mean),
                      higher_group=unique(higher_group),
                      taxon=unique(taxon),genus=unique(genus),species=unique(species),
                      clade=unique(clade,na.rm=F),shape=unique(shape))) %>%
  mutate(higher_group=factor(higher_group,ordered = T, levels = c("*Dunkleosteus* (est.)",
                             "Arthrodira","Other Elasmobranchii","*Alopias*",
                             "Deep Sea Squaliformes","Holocephali","Sarcopterygii",
                             "Basal Actinopterygii","Ichthyodectiformes",
                             "Basal Teleostei","Otocephala","Stem Euteleostei",
                             "Aulopiformes, Gadiformes",
                             "Beloniformes","Acanthopterygii")))

pelvprecaudal_3<-bind_rows(pelvprecaudal_1 %>%
            filter(genus == "Dunkleosteus") %>%
            drop_na(pvl2),
          pelvprecaudal_1 %>%
            filter(genus!="Dunkleosteus"|is.na(higher_group)) %>%
            group_by(taxon) %>%
            drop_na(pvl2) %>%
            summarize(across(where(is.numeric),mean),
                      higher_group=unique(higher_group),
                      taxon=unique(taxon),genus=unique(genus),species=unique(species),
                      clade=unique(clade,na.rm=F),shape=unique(shape))) %>%
  mutate(higher_group=factor(higher_group,ordered = T, levels = c("*Dunkleosteus* (est.)",
                             "Arthrodira","Other Elasmobranchii","*Alopias*",
                             "Deep Sea Squaliformes","Holocephali","Sarcopterygii",
                             "Basal Actinopterygii","Ichthyodectiformes",
                             "Basal Teleostei","Otocephala","Stem Euteleostei",
                             "Aulopiformes, Gadiformes",
                             "Beloniformes","Acanthopterygii")))

grid.arrange(nrow=1,
pelvprecaudal_2 %>%
  ggplot(aes(x=pvl1,y=higher_group,fill=clade)) +
  labs(x="Pre-Pelvic Length",y="Clade")+
  ggtitle("As a Proportion of Total Length")+
  geom_vline(xintercept = 0) +
  geom_vline(xintercept = 1) +
  geom_vline(data=.%>%filter(!(order %in% c("Aulopiformes","Gadiformes","Beloniformes")|
                                 genus %in% "Dunkleosteus"|
                                 higher_group=="Acanthopterygii")),
             aes(xintercept=mean(pvl1)),linetype="dashed")+
  scale_y_discrete(limits=rev)+
  geom_violin(scale="width",show.legend=F)+
  geom_boxplot(width=0.3,fill="white")+
  theme(axis.text.y = element_markdown())+
  coord_cartesian(xlim=c(0,1))
,
pelvprecaudal_3 %>%
  ggplot(aes(x=pvl2,y=higher_group,fill=clade)) +
  geom_vline(xintercept = 0) +
  geom_vline(xintercept = 1) +
  labs(x="Pre-Pelvic Length",y="Clade")+
  ggtitle("As a Proportion of Precaudal Length")+
  scale_y_discrete(limits=rev)+
  geom_vline(data=.%>%filter(!(order %in% c("Aulopiformes","Gadiformes","Beloniformes")|
                                 genus %in% "Dunkleosteus"|
                                 higher_group=="Acanthopterygii")),
             aes(xintercept=mean(pvl2)),linetype="dashed")+
  geom_violin(scale="width",show.legend=F)+
  geom_boxplot(width=0.3,fill="white")+
  theme(axis.text.y = element_markdown())+
  coord_cartesian(xlim=c(0,1))
)
Pre-pelvic length in fishes as a proportion of total length (left) and precaudal length (right). Dashed line represents the mean proportion for all non-acanthopterygian, gadiform, aulopiform fishes in which this value could be measured.

Figure 4.11: Pre-pelvic length in fishes as a proportion of total length (left) and precaudal length (right). Dashed line represents the mean proportion for all non-acanthopterygian, gadiform, aulopiform fishes in which this value could be measured.

There is a slight tendency for the pelvic girdle to be increasingly anterior in position as one gets closer to Acanthopterygii, but extreme anterior positions of the pelvis (< 30% total length) are restricted to certain neoteleost groups (Acanthopterygii, Gadiformes, and some Aulopiformes among the taxa examined here). Most acanthopterygians show much more anteriorly positioned pelvic girdles than any non-acanthopterygian, except for Beloniformes which show a secondary reversion to a non-acanthopterygian-like condition. Stem teleost lineages generally show a slightly more anterior pelvis position relative to precaudal length, but this may be confounded by the fact that precaudal length (= standard length) in actinopterygians is typically measured to the end of the hypurals (Hubbs and Lagler 2004), which typically means some of the base of the caudal fin is counted as part of precaudal length.

The hyper-elongated Ichthyodectiformes show a similar position of the pelvic fins relative to total length and precaudal length as other closely related fishes (stem-teleosts; see discussion in Cavin et al. 2013). This suggests that pelvic fin position is a relatively consistent proportion of body length in non-acanthopterygian fishes regardless of the degree of body elongation.

Pre-pelvic lengths in arthrodires known from complete remains are close to the average for all non-acanthopterygian fishes, and are particularly similar to the proportions seen in typical extant elasmobranchs. This suggests arthrodires show a similar relationship between pelvic girdle position and total length as these fishes. Because the pelvic girdle of arthrodires is either immediately posterior to or otherwise close to the end of the ventral armor (see manuscript), including in Dunkleosteus, this suggests the lengths for Dunkleosteus terrelli predicted by Engelman (2023) are accurate.

4.5.1 Examples of pre-pelvic Length in extreme body shapes

data_recon %>%
  filter(family %in% c("Cheirocentridae","Lampridae","Serrasalmidae")|
         order %in% c("Ichthyodectiformes")) %>%
  mutate(group = case_when(order == "Ichthyodectiformes" ~ "Ichthyodectiformes",
                           family == "Lampridae" ~ "Lampridae",
                           family == "Cheirocentridae" ~ "Cheirocentridae",
                           family == "Serrasalmidae" ~ "Serrasalmidae")) %>%
  drop_na(prepelvic_length,total_length) %>%
  summarise(.by=taxon,order=unique(order),group=unique(group),n=n(),
            pvl=mean(prepelvic_length/total_length)) %>%
  summarise(.by=group,n1=sum(n),n2=n(),mean_pvl=mean(pvl),
            range=paste0("(",round(min(pvl),3),"–",round(max(pvl),3),")")) %>%
  arrange(group) %>%
  kable(digits=c(1,1,1,3,1),align=c("l","c","c","c","c"),
        col.names = c("Group","N. Obs.","N. Species","Mean","Range"),
        caption = "Mean prepelvic length (as a proportion of total length) for the four clades mentioned in the manuscript") %>%
  add_header_above(c(" "=3,"Prepelvic Length"=2)) %>%
  kable_styling()
Table 4.6: Mean prepelvic length (as a proportion of total length) for the four clades mentioned in the manuscript
Prepelvic Length
Group N. Obs. N. Species Mean Range
Cheirocentridae 5 2 0.421 (0.417–0.425)
Ichthyodectiformes 13 8 0.454 (0.379–0.552)
Lampridae 4 4 0.410 (0.399–0.424)
Serrasalmidae 32 15 0.391 (0.316–0.428)

4.5.2 Predicting in Dunkleosteus terrelli

4.5.2.1 Setting up Regressions

Without log-transformation

fit.pelvic<-lm(total_length~prepelvic_length * I(higher_group == "Acanthopterygii"|order %in% c("Gadiformes","Aulopiformes")),
                 data=data_recon %>%
                   filter(length_as!="estimated t.l."))

summary(fit.pelvic)
## 
## Call:
## lm(formula = total_length ~ prepelvic_length * I(higher_group == 
##     "Acanthopterygii" | order %in% c("Gadiformes", "Aulopiformes")), 
##     data = data_recon %>% filter(length_as != "estimated t.l."))
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -126.548   -4.368   -0.667    3.800  120.090 
## 
## Coefficients:
##                                                                                                         Estimate
## (Intercept)                                                                                             6.780137
## prepelvic_length                                                                                        1.887185
## I(higher_group == "Acanthopterygii" | order %in% c("Gadiformes", "Aulopiformes"))TRUE                  -9.539332
## prepelvic_length:I(higher_group == "Acanthopterygii" | order %in% c("Gadiformes", "Aulopiformes"))TRUE  2.222744
##                                                                                                        Std. Error
## (Intercept)                                                                                              0.592050
## prepelvic_length                                                                                         0.009392
## I(higher_group == "Acanthopterygii" | order %in% c("Gadiformes", "Aulopiformes"))TRUE                    0.932003
## prepelvic_length:I(higher_group == "Acanthopterygii" | order %in% c("Gadiformes", "Aulopiformes"))TRUE   0.038090
##                                                                                                        t value
## (Intercept)                                                                                              11.45
## prepelvic_length                                                                                        200.93
## I(higher_group == "Acanthopterygii" | order %in% c("Gadiformes", "Aulopiformes"))TRUE                   -10.23
## prepelvic_length:I(higher_group == "Acanthopterygii" | order %in% c("Gadiformes", "Aulopiformes"))TRUE   58.36
##                                                                                                        Pr(>|t|)
## (Intercept)                                                                                              <2e-16
## prepelvic_length                                                                                         <2e-16
## I(higher_group == "Acanthopterygii" | order %in% c("Gadiformes", "Aulopiformes"))TRUE                    <2e-16
## prepelvic_length:I(higher_group == "Acanthopterygii" | order %in% c("Gadiformes", "Aulopiformes"))TRUE   <2e-16
##                                                                                                           
## (Intercept)                                                                                            ***
## prepelvic_length                                                                                       ***
## I(higher_group == "Acanthopterygii" | order %in% c("Gadiformes", "Aulopiformes"))TRUE                  ***
## prepelvic_length:I(higher_group == "Acanthopterygii" | order %in% c("Gadiformes", "Aulopiformes"))TRUE ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 15.39 on 2140 degrees of freedom
##   (555 observations deleted due to missingness)
## Multiple R-squared:  0.9624, Adjusted R-squared:  0.9623 
## F-statistic: 1.825e+04 on 3 and 2140 DF,  p-value: < 2.2e-16
regression.stats(fit.pelvic)

With log-transformation

fit.pelvic_2<-lm(log(total_length)~log(prepelvic_length) * I(higher_group == "Acanthopterygii"|order %in% c("Gadiformes","Aulopiformes")),
                   data=data_recon %>%
                     filter(length_as!="estimated t.l."))

summary(fit.pelvic_2)
## 
## Call:
## lm(formula = log(total_length) ~ log(prepelvic_length) * I(higher_group == 
##     "Acanthopterygii" | order %in% c("Gadiformes", "Aulopiformes")), 
##     data = data_recon %>% filter(length_as != "estimated t.l."))
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -0.78669 -0.09250 -0.00226  0.09262  1.01086 
## 
## Coefficients:
##                                                                                                             Estimate
## (Intercept)                                                                                                 1.083699
## log(prepelvic_length)                                                                                       0.907811
## I(higher_group == "Acanthopterygii" | order %in% c("Gadiformes", "Aulopiformes"))TRUE                       0.247450
## log(prepelvic_length):I(higher_group == "Acanthopterygii" | order %in% c("Gadiformes", "Aulopiformes"))TRUE 0.091373
##                                                                                                             Std. Error
## (Intercept)                                                                                                   0.014970
## log(prepelvic_length)                                                                                         0.004442
## I(higher_group == "Acanthopterygii" | order %in% c("Gadiformes", "Aulopiformes"))TRUE                         0.021593
## log(prepelvic_length):I(higher_group == "Acanthopterygii" | order %in% c("Gadiformes", "Aulopiformes"))TRUE   0.007795
##                                                                                                             t value
## (Intercept)                                                                                                   72.39
## log(prepelvic_length)                                                                                        204.39
## I(higher_group == "Acanthopterygii" | order %in% c("Gadiformes", "Aulopiformes"))TRUE                         11.46
## log(prepelvic_length):I(higher_group == "Acanthopterygii" | order %in% c("Gadiformes", "Aulopiformes"))TRUE   11.72
##                                                                                                             Pr(>|t|)
## (Intercept)                                                                                                   <2e-16
## log(prepelvic_length)                                                                                         <2e-16
## I(higher_group == "Acanthopterygii" | order %in% c("Gadiformes", "Aulopiformes"))TRUE                         <2e-16
## log(prepelvic_length):I(higher_group == "Acanthopterygii" | order %in% c("Gadiformes", "Aulopiformes"))TRUE   <2e-16
##                                                                                                                
## (Intercept)                                                                                                 ***
## log(prepelvic_length)                                                                                       ***
## I(higher_group == "Acanthopterygii" | order %in% c("Gadiformes", "Aulopiformes"))TRUE                       ***
## log(prepelvic_length):I(higher_group == "Acanthopterygii" | order %in% c("Gadiformes", "Aulopiformes"))TRUE ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.1722 on 2140 degrees of freedom
##   (555 observations deleted due to missingness)
## Multiple R-squared:  0.9697, Adjusted R-squared:  0.9697 
## F-statistic: 2.285e+04 on 3 and 2140 DF,  p-value: < 2.2e-16
regression.stats(fit.pelvic_2)

Membership in the clades Acanthopterygii, Gadiformes, or Aulopiformes was treated as additional variable because these taxa show a significantly more anterior position of the pelvis than other fishes, which if not controlled for as an additional variable might bias the regression.

rbind(
  "Log-transformed, with factor" = regression.stats(fit.pelvic_2),
  "Log-transformed, without factor" = regression.stats(lm(log(total_length)~log(prepelvic_length),data_recon)))

As can be seen by the above data, including this factor massively decreases prediction error, and not including it is likely to bias body lengths in favor of shorter estimates due to the condition in Acanthopterygii and similar fishes.

4.5.2.2 Estimating

data_recon %>% filter(genus=="Dunkleosteus") %>%
  mutate(prepelvic_length=case_when(specimen == "CMC VP8294" ~ 70.77,
                                    specimen == "CMNH 7424" ~ 70.15,
                                    specimen == "CMNH 6090" ~ 121.77,
                                    specimen == "CMNH 7054" ~ 126.06,
                                    specimen == "CMNH 5768" ~ 137.71,)) %>%
  drop_na(prepelvic_length) %>%
  arrange(prepelvic_length) %>%
  rename(OOL_length=total_length) %>%
  augment(fit.pelvic,newdata=.,interval="prediction") %>%
  rename_at(vars(starts_with('.')), funs(paste0("pelvic1",.)))%>%
  augment(fit.pelvic_2,newdata=.,interval="prediction") %>%
  mutate(across(.fitted:.upper,~exp(.)*regression.stats(fit.pelvic_2)$CF))%>%
  rename_at(vars(starts_with('.')), funs(paste0("pelvic2",.)))%>%
  mutate(OOL.pe=paste0("(",round(minlength,1),"–",round(maxlength,1),")"),
         pelvic1.range=paste0("(",round(pelvic1.lower,1),"–",round(pelvic1.upper,1),")"),
         pelvic2.range=paste0("(",round(pelvic2.lower,1),"–",round(pelvic2.upper,1),")"))%>%
  select(specimen,prepelvic_length,OOL_length,OOL.pe,
         pelvic1.fitted,pelvic1.range,
         pelvic2.fitted,pelvic2.range) %>%
  kable(digits=1,col.names=c("Specimen","Prepelvic Length (snout to end of armor)",
                             "Est.","+/- %PE","Est.","95% P.I.",
                             "Est.","95% P.I."),
        caption="Rough estimates of total length in <i>Dunkleosteus terrelli</i> using prepelvic length, approximated as the length from the tip of the snout to the end of the armor in an anteroposterior line.",
        align=c("l","c","c","c","c","c","c","c")) %>%
  add_header_above(c(" "=2,"Orbit-Opercular Length"=2,"Prepelvic Length, non-log-transformed"=2,
                     "Prepelvic Length, log-transformed"=2)) %>%
  kable_styling()
Table 4.7: Rough estimates of total length in Dunkleosteus terrelli using prepelvic length, approximated as the length from the tip of the snout to the end of the armor in an anteroposterior line.
Orbit-Opercular Length
Prepelvic Length, non-log-transformed
Prepelvic Length, log-transformed
Specimen Prepelvic Length (snout to end of armor) Est. +/- %PE Est. 95% P.I. Est. 95% P.I.
CMNH 7424 70.2 188.9 (165.5–212.4) 139.2 (109–169.4) 142.6 (101.7–200)
CMC VP8294 70.8 157.3 (137.8–176.9) 140.3 (110.1–170.5) 143.8 (102.6–201.6)
CMNH 6090 121.8 283.3 (248.2–318.4) 236.6 (206.4–266.8) 235.3 (167.8–330)
CMNH 7054 126.1 295.5 (258.9–332.2) 244.7 (214.4–274.9) 242.8 (173.2–340.5)
CMNH 5768 137.7 340.7 (298.4–382.9) 266.7 (236.4–296.9) 263.1 (187.6–369)

As with prepectoral length, though lengths based on OOL are on the very high end of the prediction interval. Again, even though the 95% prediction intervals are wider than intervals based on +/- PE, approximate pelvic girdle position favors shorter lengths for Dunkleosteus terrelli

Nevertheless, because pelvic girdle position shows phylogenetic signal throughout Actinopterygii and prepelvic length can only be approximated in D. terrelli, these lengths are considered less reliable than the ones based on OOL (not least because they would result in an animal with a tail too short to function).

4.6 Pectoral Fin Base

4.6.1 Allometric scaling relationship in sharks

Against total length

data_recon %>%
  filter(clade=="Chondrichthyes") %$%
  lm(log10(pec_base) ~ log10(total_length)) %>%
  summary()
## 
## Call:
## lm(formula = log10(pec_base) ~ log10(total_length))
## 
## Residuals:
##       Min        1Q    Median        3Q       Max 
## -0.220971 -0.042388 -0.001782  0.048422  0.292911 
## 
## Coefficients:
##                     Estimate Std. Error t value Pr(>|t|)    
## (Intercept)         -1.45285    0.02674  -54.33   <2e-16 ***
## log10(total_length)  1.11138    0.01346   82.54   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.07608 on 370 degrees of freedom
##   (368 observations deleted due to missingness)
## Multiple R-squared:  0.9485, Adjusted R-squared:  0.9484 
## F-statistic:  6813 on 1 and 370 DF,  p-value: < 2.2e-16

The slope for the log-transformed relationship in nektonic sharks is close to 1, suggesting pectoral fin base size scales isometrically with total length in sharks.

Against body mass

data_recon %>%
  filter(clade=="Chondrichthyes") %$%
  lm(log10(pec_base) ~ log10(body_mass)) %>%
  summary()
## 
## Call:
## lm(formula = log10(pec_base) ~ log10(body_mass))
## 
## Residuals:
##       Min        1Q    Median        3Q       Max 
## -0.176465 -0.050785 -0.003237  0.042143  0.238536 
## 
## Coefficients:
##                   Estimate Std. Error t value Pr(>|t|)    
## (Intercept)      -0.490619   0.015023  -32.66   <2e-16 ***
## log10(body_mass)  0.340303   0.004069   83.63   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.07363 on 357 degrees of freedom
##   (381 observations deleted due to missingness)
## Multiple R-squared:  0.9514, Adjusted R-squared:  0.9513 
## F-statistic:  6994 on 1 and 357 DF,  p-value: < 2.2e-16

The slope when regressing log10 pectoral fin base length against log10 body mass is close to 0.33, indicating pectoral fin base size scales with geometric similarity to body mass in sharks. This is generally because sharks show relatively little allometric change in body shape.

4.6.2 Comparing arthrodires and sharks

pec_base_1<-data_recon%>%
  drop_na(pec_base,clade,total_length) %>%
  ggplot(aes(total_length,pec_base))+
  geom_star(data=. %>% filter(!(clade=="Placodermi"&genus!="Dunkleosteus")),
                              aes(fill=order,starshape=clade),show.legend=F)+
  geom_smooth(data=. %>% filter(!(clade=="Placodermi"&genus!="Dunkleosteus")),
              formula=y~x,
              aes(color=clade),method="lm",alpha=0.2,show.legend=F)+
  geom_errorbarh(data=.%>% filter(clade=="Placodermi") %>% drop_na(minlength),
                 aes(xmin=minlength,xmax=maxlength),
                 height=0.75)+
  geom_star(data=. %>% filter(genus=="Dunkleosteus"),
            aes(fill=order,starshape=clade),show.legend=F,size=2)+
  geom_star(data=.%>%filter(clade=="Placodermi" & genus!="Dunkleosteus" &
                              length_as == "total length"),
             color="white",fill="black",aes(starshape=clade),size=2.5,
            starstroke=0.33,show.legend = F)+
  geom_star(data=.%>%filter(clade=="Placodermi" & genus!="Dunkleosteus" & 
                              length_as=="estimated t.l."),
            color="black",fill="gray45",aes(starshape=clade),size=2.5,
            starstroke=0.33,show.legend = F)+
  ggtitle("A")+
  scale_fill_manual(values=c("white",hue_pal()(6)))+
  scale_starshape_manual(values=c(15,1))+
  scale_color_manual(values=c("black","dark grey","red"))+
  theme_classic()+
  labs(x="Total Length (cm)",y="Pectoral Base Length (cm)")
pec_base_2 <- data_recon %>%
  drop_na(pec_base,clade,body_mass) %>%
  ggplot(aes(body_mass,pec_base))+
  geom_star(aes(fill=order,starshape=order))+
  geom_smooth(data=. %>% filter(!(clade=="Placodermi"&genus!="Dunkleosteus")),
              formula=y~x,
              aes(color=clade),method="lm",alpha=0.2,show.legend=F)+
  geom_smooth(data=. %>% filter(!(clade=="Placodermi"&genus!="Dunkleosteus")),
              formula=y~x,
              color=NA,method="lm",se=F)+
  geom_errorbarh(data=.%>% filter(clade=="Placodermi") %>% drop_na(minmass),
                 aes(xmin=minmass,xmax=maxmass),
                 height=.02)+
  geom_star(data=.%>%filter(clade=="Placodermi"),
            color="white",fill="white",aes(starshape=order),size=2.5,
            starstroke=0.4,show.legend = F)+
  geom_star(data=.%>%filter(genus=="Dunkleosteus"),
            color="black",fill="white",aes(starshape=order),size=2,show.legend = F)+
  geom_star(data=.%>%filter(clade=="Placodermi" & genus!="Dunkleosteus" &
                              length_as=="total length"),
            color="black",fill="black",aes(starshape=order),size=2,
            starstroke=0.33,show.legend = F)+
  geom_star(data=.%>%filter(clade=="Placodermi" & genus!="Dunkleosteus" & 
                              length_as=="estimated t.l."),
            color="black",fill="gray45",aes(starshape=order),size=2.5,
            starstroke=0.33,show.legend = F)+
  geom_star(data=.%>%filter(clade=="Placodermi"&genus!="Dunkleosteus"),
            color="black",fill=NA,aes(starshape=order),size=2,
            starstroke=0.33,show.legend = F)+
  ggtitle("B")+
  scale_x_continuous(trans="log10",
                     breaks = scales::trans_breaks("log10", function(x) 10^x,n=5),
                     labels = scales::trans_format("log10", scales::math_format(10^.x)))+
  scale_y_continuous(trans="log10")+
  scale_color_manual(values=c("black","dark grey"))+
  scale_fill_manual(values=c("black",hue_pal()(6)))+
  scale_starshape_manual(values=c(1,15,15,15,15,15,15))+
  labs(x=bquote("Log"[10]~"Body Mass (g)"),y=bquote("Log"[10]~"Pectoral Base Length (cm)"),
       fill="Order",color="Order",starshape="Order")+
  theme_classic()+
  theme(legend.position=c(0.85,0.3))

grid.arrange(nrow=1,pec_base_1,pec_base_2)
Pectoral fin base length scaled against total length (A) and body mass (B) in arthrodires and elasmobranchs. For arthrodires, white stars represent Dunkleosteus, black stars represent arthrodires known from complete body fossils, and gray stars represent arthrodires for which body length was estimated from the OOL equation in Engelman (2023). The black line represents the allometric relationship for elasmobranchs whereas the gray represents the scaling relationship for sharks. Colors in the legend for elasmobranch clades in this figure are followed in the figures below.

Figure 4.12: Pectoral fin base length scaled against total length (A) and body mass (B) in arthrodires and elasmobranchs. For arthrodires, white stars represent Dunkleosteus, black stars represent arthrodires known from complete body fossils, and gray stars represent arthrodires for which body length was estimated from the OOL equation in Engelman (2023). The black line represents the allometric relationship for elasmobranchs whereas the gray represents the scaling relationship for sharks. Colors in the legend for elasmobranch clades in this figure are followed in the figures below.

pec_base_figure1<-data_recon %>%
  drop_na(pec_base,clade,total_length) %>%
  filter(!(clade=="Placodermi"&genus!="Dunkleosteus"))%>%
  ggplot(aes(total_length,pec_base))+
  geom_star(data=. %>% filter(!(clade=="Placodermi"&genus!="Dunkleosteus")),
            aes(fill=order,starshape=clade),show.legend=F)+
  geom_smooth(formula=y~x,
              aes(color=clade),method="lm",alpha=0.2,show.legend=F)+
  geom_errorbarh(data=.%>% filter(clade=="Placodermi") %>% drop_na(minlength),
                 aes(xmin=minlength,xmax=maxlength),
                 height=0.75)+
  ggtitle("A")+
  geom_star(data=. %>% filter(genus=="Dunkleosteus"),
            aes(fill=order,starshape=clade),show.legend=F,size=2.5)+
  geom_star(data=.%>%filter(clade=="Placodermi"&genus!="Dunkleosteus"),
            color="white",fill="white",aes(starshape=clade),size=3,
            starstroke=0.33,show.legend = F)+
  geom_star(data=.%>%filter(clade=="Placodermi" & genus!="Dunkleosteus" &
                              length_as=="total length"),
            color="black",fill="black",aes(starshape=clade),size=2.5,
            starstroke=0.33,show.legend = F)+
  geom_star(data=.%>%filter(clade=="Placodermi" & genus!="Dunkleosteus" & 
                              length_as=="estimated t.l."),
            color="black",fill="gray45",aes(starshape=clade),size=2.5,
            starstroke=0.33,show.legend = F)+
  geom_star(data=.%>%filter(clade=="Placodermi"&genus!="Dunkleosteus"),
            color="black",fill=NA,aes(starshape=clade),size=2.5,
            starstroke=0.33,show.legend = F)+
  scale_fill_manual(values=c("white",hue_pal()(6)))+
  scale_starshape_manual(values=c(15,1))+
  scale_color_manual(values=c("black","dark grey","red"))+
  labs(x="Total Length (cm)",
       y="Pectoral Base Length (cm)") +
  coord_cartesian(xlim=c(-1,700),ylim=c(-1,50)) +
  theme_classic()

pec_base_figure2 <- data_recon %>%
  drop_na(pec_base,clade,body_mass) %>%
  filter(!(clade=="Placodermi"&genus!="Dunkleosteus"))%>%
  ggplot(aes(body_mass,pec_base))+
  geom_smooth(formula=y~x,aes(color=clade),method="lm",se=F,show.legend=T)+
  geom_star(aes(starshape=clade),fill="white")+
  geom_star(aes(fill=order,starshape=clade),show.legend = F)+
  geom_smooth(formula=y~x,
              aes(color=clade),method="lm",alpha=0.2,show.legend=F)+
  geom_errorbarh(data=.%>% filter(clade=="Placodermi") %>% drop_na(minmass),
                 aes(xmin=minmass,xmax=maxmass),
                 height=.02)+
  geom_star(data=.%>%filter(clade=="Placodermi"),
            color="white",fill="white",aes(starshape=clade),size=3,
            starstroke=0.4,show.legend = F)+
  geom_star(data=.%>%filter(genus=="Dunkleosteus"),
            color="black",fill="white",aes(starshape=clade),size=2.5,show.legend = F)+
  geom_star(data=.%>%filter(clade=="Placodermi" & genus!="Dunkleosteus" &
                              length_as=="total length"),
            color="black",fill="black",aes(starshape=clade),size=2.5,
            starstroke=0.33,show.legend = F)+
  geom_star(data=.%>%filter(clade=="Placodermi" & genus!="Dunkleosteus" & 
                              length_as=="estimated t.l."),
            color="black",fill="black",aes(starshape=clade),size=2.5,
            starstroke=0.33,show.legend = F,alpha=0.7)+
  geom_star(data=.%>%filter(clade=="Placodermi"&genus!="Dunkleosteus"),
            color="black",fill=NA,aes(starshape=clade),size=2.5,
            starstroke=0.33,show.legend = F)+
  ggtitle("B")+
  scale_x_continuous(trans="log10",
                     breaks = scales::trans_breaks("log10", function(x) 10^x,n=5),
                     labels = scales::trans_format("log10", scales::math_format(10^.x)))+
  scale_y_continuous(trans="log10")+
  scale_color_manual(values=c("black","dark grey"),
                     labels=c("Elasmobranchii","*Dunkleosteus*"))+
  scale_fill_manual(guide="none",values=c("white",hue_pal()(6)))+
  scale_starshape_manual(values=c(15,1),
                         labels=c("Elasmobranchii","*Dunkleosteus*"))+
  labs(x=bquote("Log"[10]~"Body Mass (g)"),y=bquote("Log"[10]~"Pectoral Base Length (cm)"),
       fill="Clade",color="Clade",starshape="Clade")+
  coord_cartesian(xlim=c(36,2270000),ylim=c(1,50))+
  theme_classic()+
  theme(legend.position=c(0.75,0.2),
        legend.text = element_markdown())+
  guides(shape=(guide_legend(override.aes=list(fill = c("white")))))

pectoral_base_2<-grid.arrange(nrow=1,pec_base_figure1,pec_base_figure2)
Pectoral fin base length scaled against total length (A) and body mass (B) showing scaling patterns in Dunkleosteus (white stars, gray line) versus elasmobranchs (circles, black line). The outlier point Rhincodon is not shown to make it easier to interpret points in the rest of the graph. This figure is identical to Figure 20 of the main manuscript.

Figure 4.13: Pectoral fin base length scaled against total length (A) and body mass (B) showing scaling patterns in Dunkleosteus (white stars, gray line) versus elasmobranchs (circles, black line). The outlier point Rhincodon is not shown to make it easier to interpret points in the rest of the graph. This figure is identical to Figure 20 of the main manuscript.

# These x,y coordinates are supposed to be the coordinates ggplot would normally plot if excluding the outlier Rhincodon

ggsave(filename="Reconstruction of Dunkleosteus Figure 20 (Pectoral Base).tiff",
       pectoral_base_2,
       device="tiff",width=175,height=100,
       dpi=600,units="mm",compression="lzw")

When comparing pectoral fin base size in arthrodires and nektonic sharks, Dunkleosteus has a much larger pectoral fin base than extant sharks and shows clear positive allometry. However, when comparing against body mass, pectoral fin base size scales along roughly the same line as sharks (possibly a little larger, but not much) and scales with geometric similarity. This is probably because Dunkleosteus shows positive allometry in fineness ratio, and thus positive allometry in body mass at larger body lengths.

When adding additional arthrodires to the analysis, these taxa show similar pectoral fin bases to extant sharks when graphed against untransformed total length or log10-transformed body mass. The only exceptions are the pachyosteomorphs Amazichthys and Eastmanosteus, which have larger pectoral fins base closer in size to juvenile Dunkleosteus. However, arthrodires showing similar pectoral fin base sizes to modern sharks may be an artifact of the relationship between pectoral fin base length and total length not being log-transformed. When the same data are log-transformed (i.e., changed to an allometric scale), they show a relatively consistent, positively allometric relationship between pectoral fin base length and total length (see figure 4.15, below).

grid.arrange(nrow=1,
data_recon %>%
  drop_na(pec_base,body_mass,clade,order) %>%
  ggplot(aes(body_mass,pec_base))+
  geom_errorbarh(data=.%>% filter(clade=="Placodermi") %>% drop_na(minmass),
                 aes(xmin=minmass,xmax=maxmass),
                 height=0.75)+
  geom_star(aes(fill=order,starshape=clade),show.legend=F)+
  ggtitle(label="A")+
  geom_star(data=.%>%filter(genus=="Dunkleosteus"),
            color="black",fill="white",aes(starshape=clade),size=2.5,show.legend = F)+
  geom_star(data=.%>%filter(clade=="Placodermi"&genus!="Dunkleosteus"),
            color="white",fill="white",aes(starshape=clade),size=3,
            starstroke=0.33,show.legend = F)+
  geom_star(data=.%>%filter(clade=="Placodermi" & genus!="Dunkleosteus" &
                              length_as=="total length"),
            color="black",fill="black",aes(starshape=clade),size=2.5,
            starstroke=0.33,show.legend = F)+
  geom_star(data=.%>%filter(clade=="Placodermi" & genus!="Dunkleosteus" & 
                              length_as=="estimated t.l."),
            color="black",fill="gray45",aes(starshape=clade),size=2.5,
            starstroke=0.33,show.legend = F)+
  geom_star(data=.%>%filter(clade=="Placodermi"&genus!="Dunkleosteus"),
            color="black",fill=NA,aes(starshape=clade),size=2.5,
            starstroke=0.33,show.legend = F)+
  scale_x_continuous(trans="log10",
                     breaks = scales::trans_breaks("log10", function(x) 10^x,n=5),
                     labels = scales::trans_format("log10", scales::math_format(10^.x)))+
  scale_color_manual(values=c("black","dark grey"))+
  scale_fill_manual(guide="none",values=c("white",hue_pal()(6)))+
  scale_starshape_manual(values=c(15,1))+
  labs(x="Body Mass (g)",y="Pectoral Base Length (cm)",
       fill="Clade",color="Clade",starshape="Clade")+
  theme_classic()+
  theme(legend.position=c(0.75,0.2))+
  guides(shape=(guide_legend(override.aes=list(fill = c("white"))))),
data_recon %>%
  drop_na(pec_base,body_mass,clade,order) %>%
  ggplot(aes(body_mass^(1/3),pec_base))+
  geom_smooth(formula=y~x,aes(color=clade),method="lm",alpha=0.2,show.legend=F)+
  geom_smooth(formula=y~x,color=NA,method="lm",se=F)+
  geom_errorbarh(data=.%>% filter(clade=="Placodermi") %>% drop_na(minmass),
                 aes(xmin=minmass^(1/3),xmax=maxmass^(1/3)),
                 height=0.75)+
  geom_star(aes(fill=order,starshape=clade))+
  geom_star(data=.%>%filter(genus=="Dunkleosteus"),
            color="black",fill="white",aes(starshape=clade),size=2.5,show.legend = F)+
  geom_star(data=.%>%filter(clade=="Placodermi"&genus!="Dunkleosteus"),
            color="white",fill="white",aes(starshape=clade),size=3,
            starstroke=0.33,show.legend = F)+
  geom_star(data=.%>%filter(clade=="Placodermi" & genus!="Dunkleosteus" &
                              length_as=="total length"),
            color="black",fill="black",aes(starshape=clade),size=2.5,
            starstroke=0.33,show.legend = F)+
  geom_star(data=.%>%filter(clade=="Placodermi" & genus!="Dunkleosteus" & 
                              length_as=="estimated t.l."),
            color="black",fill="gray45",aes(starshape=clade),size=2.5,
            starstroke=0.33,show.legend = F)+
  geom_star(data=.%>%filter(clade=="Placodermi"&genus!="Dunkleosteus"),
            color="black",fill=NA,aes(starshape=clade),size=2.5,
            starstroke=0.33,show.legend = F)+
  ggtitle(label="B")+
  scale_color_manual(values=c("black","dark grey"))+
  scale_fill_manual(guide="none",values=c("white",hue_pal()(6)))+
  scale_starshape_manual(values=c(15,1))+
  labs(x=bquote("Body Mass (g)"^"1/3"),y="Pectoral Base Length (cm)",
       fill="Clade",color="Clade",starshape="Clade")+
  theme_classic()+
  theme(legend.position=c(0.75,0.2))+
  guides(shape=(guide_legend(override.aes=list(fill = c("white")))))
)
Pectoral fin base length scaled against untransformed body mass (A) and body mass raised to the 1/3 power (B). A shows how the two measurements do not scale linearly, because the graph regresses a linear measurement (pectoral fin base length) against a volumetric one (body mass). The scale-location graph of the residuals of an untransformed linear regression model showed significant heteroskedasticity, suggesting log-transformation was necessary. By taking the cubic root of body mass, B converts body mass into a form that can be more directly compared to a linear measurement.

Figure 4.14: Pectoral fin base length scaled against untransformed body mass (A) and body mass raised to the 1/3 power (B). A shows how the two measurements do not scale linearly, because the graph regresses a linear measurement (pectoral fin base length) against a volumetric one (body mass). The scale-location graph of the residuals of an untransformed linear regression model showed significant heteroskedasticity, suggesting log-transformation was necessary. By taking the cubic root of body mass, B converts body mass into a form that can be more directly compared to a linear measurement.

Pectoral fin base length and body mass in Figure 4.12b had to be log transformed, because it involves regressing a linear measurement against a volumetric one (Figure 4.13a). However, if plotting pectoral fin base length against the cubic root of body mass (Figure 4.13b), which essentially transforms the volumetric body mass into a form that can be directly compared against a linear measurement, a similar relationship is found to Figure 4.12b.

data_recon %>%
  drop_na(pec_base,clade,total_length) %>%
  ggplot(aes(total_length,pec_base))+
  geom_star(data=. %>% filter(!(clade=="Placodermi"&genus!="Dunkleosteus")),
            aes(fill=order,starshape=clade),show.legend=F)+
  geom_smooth(formula=y~x,
              aes(color=clade),method="lm",alpha=0.2,show.legend=F)+
  geom_errorbarh(data=.%>% filter(clade=="Placodermi") %>% drop_na(minlength),
                 aes(xmin=minlength,xmax=maxlength),
                 height=0.02)+
  geom_star(data=. %>% filter(genus=="Dunkleosteus"),
            aes(fill=order,starshape=clade),show.legend=F,size=2.5)+
  geom_star(data=.%>%filter(clade=="Placodermi"&genus!="Dunkleosteus"),
            color="white",fill="white",aes(starshape=clade),size=3,
            starstroke=0.33,show.legend = F)+
  geom_star(data=.%>%filter(clade=="Placodermi" & genus!="Dunkleosteus" &
                              length_as=="total length"),
            color="black",fill="black",aes(starshape=clade),size=2.5,
            starstroke=0.33,show.legend = F)+
  geom_star(data=.%>%filter(clade=="Placodermi" & genus!="Dunkleosteus" & 
                              length_as=="estimated t.l."),
            color="black",fill="gray45",aes(starshape=clade),size=2.5,
            starstroke=0.33,show.legend = F)+
  geom_star(data=.%>%filter(clade=="Placodermi"&genus!="Dunkleosteus"),
            color="black",fill=NA,aes(starshape=clade),size=2.5,
            starstroke=0.33,show.legend = F)+
  scale_x_continuous(trans="log10")+
  scale_y_continuous(trans="log10")+
  scale_fill_manual(values=c("white",hue_pal()(6)))+
  scale_starshape_manual(values=c(15,1))+
  scale_color_manual(values=c("black","dark grey","red"))+
  theme_classic()+
  labs(x=bquote("Log"[10]~"Total Length (cm)"),
       y=bquote("Log"[10]~"Pectoral Base Length (cm)"))
Plot of log10-transformed pectoral fin base length plotted against log10 total length. Black line represents allometric relationship for extant Chondrichthyes and gray line for Eubrachythoraci. White stars represent Dunkleosteus, black stars represent arthrodires known from complete remains, and gray stars represent taxa with total length estimated via OOL.

Figure 4.15: Plot of log10-transformed pectoral fin base length plotted against log10 total length. Black line represents allometric relationship for extant Chondrichthyes and gray line for Eubrachythoraci. White stars represent Dunkleosteus, black stars represent arthrodires known from complete remains, and gray stars represent taxa with total length estimated via OOL.

When scaling log10 pectoral fin base length against log10 total length, arthrodires generally have proportionally larger pectoral fin bases than extant nektonic chondrichthyans. This relationship is generally obscured in the prior figure because the data was not log-transformed, making proportional relationships more difficult to discern at smaller sizes. This is rather surprising given coccosteomorphs are generally considered to be less nektonic than carcharhinids, hexanchiids, etc., and non-pachyosteomorph arthrodires are often considered to have small fin bases.

Within Arthrodira there is some variation in pectoral fin base size. Smaller pectoral fin bases are seen in Millerosteus and camuropiscids, whereas larger ones are seen in pachyosteomorphs. It is possible the large fin base of Dunkleosteus is related to the general enlargement of the pectoral fenestra in pachyosteomorph arthrodires (Stensiö 1959, Miles 1969, Carr 1995), as the aspinothoracidans Amazichthys, Brachyosteus, Enseosteus, and Heintzichthys and the geologically older dunkleosteoid Eastmanosteus calliaspis also have relatively large pectoral fin bases for their size. However, it is also possible this is a broader pattern due to allometry. Including data from additional pachyosteomorphs might provide a better understanding of pectoral fin scaling in arthrodires, but a more extensive examination of pectoral fin base evolution across eubrachythoracid arthrodires is beyond the scope of this study.

data_recon %>%
  drop_na(pec_base) %>%
  filter(!(clade=="Placodermi"&genus!="Dunkleosteus")) %>%
  mutate(clade=ifelse(genus=="Dunkleosteus","Dunkleosteus",clade)) %$%
  lm(log10(pec_base)~log10(body_mass)*clade,.) %>%
  summary()
## 
## Call:
## lm(formula = log10(pec_base) ~ log10(body_mass) * clade, data = .)
## 
## Residuals:
##       Min        1Q    Median        3Q       Max 
## -0.176465 -0.050255 -0.002545  0.041159  0.238536 
## 
## Coefficients:
##                                     Estimate Std. Error t value Pr(>|t|)    
## (Intercept)                        -0.490619   0.014986 -32.738   <2e-16 ***
## log10(body_mass)                    0.340303   0.004059  83.834   <2e-16 ***
## cladeDunkleosteus                   0.230618   0.260401   0.886    0.376    
## log10(body_mass):cladeDunkleosteus -0.034505   0.050539  -0.683    0.495    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.07345 on 362 degrees of freedom
##   (13 observations deleted due to missingness)
## Multiple R-squared:  0.954,  Adjusted R-squared:  0.9536 
## F-statistic:  2501 on 3 and 362 DF,  p-value: < 2.2e-16

When comparing allometric regression equations between pectoral fin base size and body mass in Dunkleosteus and elasmobranchs (not considering other arthrodires), the two show non-significant differences in slope and intercept.

4.7 Setting up Pectoral and Pelvic Origin Figure

p1_pec_a <- ggplot(rhizo, aes(x, y)) +
    geom_polygon(fill = "darkgrey",color="black", alpha = 0.5) +
    geom_line(data=data.frame(x=c(1,1),y=c(0.2471672000,-0.03)))+
    geom_line(data=data.frame(x=c(0,0),y=c(0.1627831000,-0.03)))+
    geom_line(data=data.frame(x=c(0,0.225,0.225),
                              y=c(0.055,0.055,0.105)),
              linewidth=1.25,color="steelblue")+
    coord_cartesian(ylim=c(0,0.33))+
    annotate("text",label="pre-pectoral length",x=0.257,y=0.03,hjust=1,size=3.163138)+
    annotate(geom="text",label="N Species",x=.99,y=0.01,hjust=1,size=3.25)+
    theme(axis.title.x=element_blank(),
          axis.text.x=element_blank(),
          axis.ticks.x=element_blank(),
          axis.title.y=element_blank(),
          axis.text.y=element_blank(),
          axis.ticks.y=element_blank(),
          axis.line.y = element_blank(),
          axis.line.x = element_blank())+
    theme_void()

p1_pelv_a <- ggplot(rhizo, aes(x, y)) +
    geom_polygon(fill = "darkgrey",color="black", alpha = 0.5) +
    geom_line(data=data.frame(x=c(1,1),y=c(0.2471672000,-0.03)))+
    geom_line(data=data.frame(x=c(0,0),y=c(0.1627831000,-0.03)))+
    geom_line(data=data.frame(x=c(0,0.454,0.454),
                              y=c(0.055,0.055,0.105)),
              linewidth=1.25,color="steelblue")+
    coord_cartesian(ylim=c(0,0.33))+
    annotate("text",label="pre-pelvic length",x=0.454,y=0.03,hjust=0.5,size=3.163138)+
    annotate(geom="text",label="N Species",x=.99,y=0.01,hjust=1,size=3.25)+
    theme(axis.title.x=element_blank(),
          axis.text.x=element_blank(),
          axis.ticks.x=element_blank(),
          axis.title.y=element_blank(),
          axis.text.y=element_blank(),
          axis.ticks.y=element_blank(),
          axis.line.y = element_blank(),
          axis.line.x = element_blank())+
    theme_void()

p2_pec_a <- prepec_2 %>%
  mutate(higher_group=ifelse(higher_group=="Dunkleosteus","Dunkleosteus*",as.character(higher_group)),
         higher_group=ifelse(higher_group=="Arthrodira (known lengths)","Arthrodira (known)*",higher_group),
         higher_group=ifelse(higher_group=="Arthrodira (est. lengths)","Arthrodira (est.)*",higher_group)) %>%
  mutate(higher_group=factor(higher_group,ordered=T,
                      levels=c("Dunkleosteus*","Eastmanosteus",
                               "Arthrodira (known)*",
                               "Arthrodira (est.)*",
                               "Other Elasmobranchii", "Holocephali",
                               "Alopias","Sarcopterygii","Basal Actinopterygii",
                               "Ichthyodectiformes", "Basal Teleostei",
                               "Otocephala", "Stem Euteleostei", 
                               "Acanthopterygii","Anguilliform Taxa"))) %>%
  ggplot(aes(x=prepectoral_length/total_length,y=higher_group)) +
  coord_cartesian(xlim=c(0,1))+
  scale_x_continuous(labels = scales::percent)+
  scale_y_discrete(limits=rev)+
  labs(x="Pre-Pectoral Length (as percent of total length)",y="Clade")+
  geom_vline(data=. %>% filter(genus=="Dunkleosteus"),
             aes(xintercept=mean(prepectoral_length/total_length)),
             color="#00B0F6",linetype="dashed")+
  geom_vline(aes(xintercept=mean(prepectoral_length/total_length)),
             linetype="dashed")+
  geom_vline(xintercept = 0) +
  geom_vline(xintercept = 1) +
  geom_violin(aes(fill=clade),show.legend = F,scale="width")+
  geom_violin(data=.%>%filter(genus=="Dunkleosteus"),fill="#00B0F6",
              show.legend = F,scale="width")+
  geom_boxplot(width=0.3)+
  geom_star(data=. %>% filter(genus=="Eastmanosteus"),
            fill="white",color="black",size=2.5)+
  theme(axis.text.y = element_text(face=c(rep("plain",8),"italic",
                                          rep("plain",4),"italic","italic")))

p2_pelv_a_1<-
  data_recon %>%
  mutate(prepelvic_length=ifelse(specimen %in% "CMC VP8294", 70.77,prepelvic_length),
         prepelvic_length=ifelse(specimen %in% "CMNH 7424", 70.15,prepelvic_length),
         prepelvic_length=ifelse(specimen %in% "CMNH 6090", 121.77,prepelvic_length),
         prepelvic_length=ifelse(specimen %in% "CMNH 7054", 126.06,prepelvic_length),
         prepelvic_length=ifelse(specimen %in% "CMNH 5768", 137.71,prepelvic_length)) %>%
  filter(length_as=="total length"|genus=="Dunkleosteus") %>%
  mutate(higher_group=ifelse(order %in% c("Aulopiformes","Gadiformes"),"Aulopiformes, Gadiformes",higher_group),
         higher_group=ifelse(family %in% c("Dalatiidae","Etmopteridae","Oxynotidae","Somniosidae","Centrophoridae"),"Deep Sea Squaliformes",higher_group),
         higher_group=ifelse(order == "Chimaeriformes","Holocephali",higher_group),
         higher_group=ifelse(higher_group == "Acanthopterygii","Other Acanthopterygii",
                             higher_group),
         higher_group=ifelse(order == "Beloniformes","Beloniformes",higher_group),
         higher_group=ifelse(genus == "Alopias","*Alopias*",higher_group),
         higher_group=ifelse(order == "Ichthyodectiformes","Ichthyodectiformes",higher_group),
         higher_group=ifelse(higher_group=="Chondrichthyes","Other Elasmobranchii",higher_group),
         higher_group=ifelse(genus=="Dunkleosteus","*Dunkleosteus* (est.)*",higher_group))

# summarising values for non-Dunkleosteus taxa (total length)

p2_pelv_a_2<-bind_rows(p2_pelv_a_1 %>%
                             filter(genus == "Dunkleosteus") %>%
                             drop_na(prepelvic_length,total_length),
                       p2_pelv_a_1 %>%
                             filter(genus!="Dunkleosteus"|is.na(higher_group)) %>%
                             group_by(taxon) %>%
                             drop_na(prepelvic_length,total_length) %>%
                             summarize(across(where(is.numeric),mean),
                                       higher_group=unique(higher_group),
                                       taxon=unique(taxon),genus=unique(genus),
                                       species=unique(species),
                                       clade=unique(clade,na.rm=F),
                                       shape=unique(shape))) %>%
mutate(higher_group=factor(higher_group,ordered = T, 
                           levels = c("*Dunkleosteus* (est.)*","Arthrodira",
                                      "Other Elasmobranchii","*Alopias*",
                                      "Deep Sea Squaliformes","Holocephali",
                                      "Sarcopterygii", "Basal Actinopterygii", "Ichthyodectiformes", "Basal Teleostei", "Otocephala", "Stem Euteleostei", "Aulopiformes, Gadiformes", "Beloniformes", "Other Acanthopterygii")))

p2_pelv_a<-p2_pelv_a_2%>%
  ggplot(aes(x=prepelvic_length/total_length,y=higher_group,fill=clade)) +
  labs(x="Pre-Pelvic Length (as percent of total length)",y="Clade")+
  geom_vline(xintercept = 0) +
  geom_vline(xintercept = 1) +
  geom_vline(data=.%>%filter(!(order %in% c("Aulopiformes","Gadiformes","Beloniformes")|
                                 genus %in% c("Dunkleosteus")|
                                 higher_group=="Other Acanthopterygii")),
             aes(xintercept=mean(prepelvic_length/total_length)),linetype="dashed")+
  scale_x_continuous(labels = scales::percent)+
  scale_y_discrete(limits=rev)+
  geom_violin(scale="width",show.legend=F)+
  geom_violin(data=. %>% filter(genus=="Dunkleosteus"),
              scale="width",fill="#00B0F6",show.legend=F)+
  geom_boxplot(width=0.3,fill="white")+
  geom_text(data=. %>%
              summarise(.by=taxon,prepelvic_length=mean(prepelvic_length),higher_group=unique(higher_group),
                        clade=unique(clade))%>%
              summarise(.by=higher_group,N=n(),clade=unique(clade)),
            aes(y=higher_group,label=N),x=.99,hjust=1,size=3.25)+
  theme(axis.title.y=element_blank(),
        axis.text.y = element_markdown())

pec_pelv_figure<-wrap_plots(p1_pec_a / p2_pec_a +
             theme(axis.title.y=element_blank())+
             geom_text(data=. %>%
                         summarise(.by=taxon,ppl=mean(prepectoral_length),higher_group=unique(higher_group),
                                   clade=unique(clade))%>%
                         summarise(.by=higher_group,N=n(),clade=unique(clade)),
                       aes(y=higher_group,label=N),x=.99,hjust=1,size=3.25)+
             plot_layout(heights = 1:2) & theme(plot.margin = margin(0, 20, 0, 0)),
           (p1_pelv_a / p2_pelv_a + 
              plot_layout(heights = 1:2) & theme(plot.margin = margin(0, 20, 0, 0))),ncol=1)

ggsave(filename="Reconstruction of Dunkleosteus Figure 11 (Pectoral-Pelvic Proportions).tiff",
       plot=pec_pelv_figure,device="tiff",
       width=175,height=220,units="mm",dpi=600,compression="lzw")

4.8 Caudal Peduncle

4.8.1 Peduncle height in Amazichthys

grid.arrange(nrow=1,
  data_recon%>%
  filter(family %in% c("Scombridae","Lamnidae","Megalopidae","Sphyraenidae")|order %in% c("Carangiformes","Istiophoriformes")|genus=="Amazichthys") %>%
  filter(!genus %in% c("Mitsukurina","Carcharhias","Odontaspis")) %>%
  drop_na(peduncle_height,body_depth) %>%
  mutate(order=case_when(genus=="Amazichthys" ~ "Amazichthys",
                         order == "Lamniformes" ~ "Lamnidae",
                         order == "Scombriformes" ~ "Scombridae",
                         family == "Megalopidae" ~ "Megalopidae",
                         order == "Carangaria incertae sedis" ~ "Sphyraenidae",
                         order == "Istiophoriformes" ~ "Istiophoriformes",
                         family %in% c("Carangidae","Coryphaenidae") ~ "Carangidae + Coryphaenidae",
                         family %in% c("Rachycentridae","Echeneidae") ~ "Echeneidae + Rachycentridae")) %>%
  ggplot(aes(x=peduncle_height/body_depth,y=order))+
    ggtitle("As percentage of body depth")+
  scale_y_discrete(limits=rev) +
  scale_x_continuous(labels = scales::percent) +
  geom_vline(data=. %>% filter(genus=="Amazichthys"),
             aes(xintercept=peduncle_height/body_depth),
             color="darkgrey") +
  labs(y=element_blank(),x="Peduncle Height as % of Body Depth") +
  geom_violin(data =. %>% filter(genus!="Amazichthys"), aes(fill=order),scale="width")+
  geom_boxplot(data = . %>% filter(genus!="Amazichthys"), width=0.3)+
  geom_star(data = . %>% filter(genus=="Amazichthys"),fill="black",size=3) +
  theme(legend.position="NA",
        axis.text.y = element_text(face=c(rep("plain",7),"italic"))),
data_recon%>%
  filter(family %in% c("Scombridae","Lamnidae","Megalopidae","Sphyraenidae")|order %in% c("Carangiformes","Istiophoriformes")|genus=="Amazichthys") %>%
  filter(!genus %in% c("Mitsukurina","Carcharhias","Odontaspis")) %>%
  drop_na(peduncle_height,precaudal_length) %>%
  mutate(order=case_when(genus=="Amazichthys" ~ "Amazichthys",
                         order == "Lamniformes" ~ "Lamnidae",
                         order == "Scombriformes" ~ "Scombridae",
                         order == "Elopiformes" ~ "Megalopidae",
                         order == "Carangaria incertae sedis" ~ "Sphyraenidae",
                         order == "Istiophoriformes" ~ "Istiophoriformes",
                         family %in% c("Carangidae","Coryphaenidae") ~ "Carangidae + Coryphaenidae",
                         family %in% c("Rachycentridae","Echeneidae") ~ "Echeneidae + Rachycentridae")) %>%
  ggplot(aes(x=peduncle_height/precaudal_length,y=order))+
  ggtitle("As percentage of precaudal length")+
  scale_y_discrete(limits=rev) +
  scale_x_continuous(labels = scales::percent) +
  geom_vline(data=. %>% filter(genus=="Amazichthys"),
             aes(xintercept=peduncle_height/precaudal_length),
             color="darkgrey") +
  labs(y=element_blank(),x="Peduncle Height as % of Precaudal Length") +
  geom_violin(data =. %>% filter(genus!="Amazichthys"), aes(fill=order),scale="width")+
  geom_boxplot(data = . %>% filter(genus!="Amazichthys"), width=0.3)+
  geom_star(data = . %>% filter(genus=="Amazichthys"),fill="black",size=3) +
  theme(legend.position="NA",
        axis.text.y = element_text(face=c(rep("plain",7),"italic")))
)
Caudal peduncle height in Amazichthys trinajsticae compared to select tachynektonic fish groups, measured as a proportion of body depth (left) and precaudal length (right). Caudal peduncle height in Amazichthys measured from photographs of specimen AA.MEM.DS.8 in Jobbins et al. 2022.

Figure 4.16: Caudal peduncle height in Amazichthys trinajsticae compared to select tachynektonic fish groups, measured as a proportion of body depth (left) and precaudal length (right). Caudal peduncle height in Amazichthys measured from photographs of specimen AA.MEM.DS.8 in Jobbins et al. 2022.

It is possible the peduncle as preserved in Amazichthys is too deep and has been altered by taphonomic deformation. The reconstruction in Engelman (2023) provides an alternative measurement of peduncle height in this taxon, because the peduncle was reconstructed to be slightly narrower than preserved assuming some taphonomic deformation. This reconstruction was made directly from the proportions of the holotype with oversight from the lead author of the paper describing Amazichthys (M. Jobbins pers. comm., September 2022), so its proportions are relatively reliable.

grid.arrange(nrow=1,
  data_recon%>%
  filter(family %in% c("Scombridae","Lamnidae","Megalopidae","Sphyraenidae")|order %in% c("Carangiformes","Istiophoriformes")|genus=="Amazichthys") %>%
    mutate(peduncle_height=ifelse(genus=="Amazichthys",6.679,peduncle_height)) %>%
  filter(!genus %in% c("Mitsukurina","Carcharhias","Odontaspis")) %>%
  drop_na(peduncle_height,body_depth) %>%
  mutate(order=case_when(genus=="Amazichthys" ~ "Amazichthys",
                         order == "Lamniformes" ~ "Lamnidae",
                         order == "Scombriformes" ~ "Scombridae",
                         family == "Megalopidae" ~ "Megalopidae",
                         order == "Carangaria incertae sedis" ~ "Sphyraenidae",
                         order == "Istiophoriformes" ~ "Istiophoriformes",
                         family %in% c("Carangidae","Coryphaenidae") ~ "Carangidae + Coryphaenidae",
                         family %in% c("Rachycentridae","Echeneidae") ~ "Echeneidae + Rachycentridae")) %>%
  ggplot(aes(x=peduncle_height/body_depth,y=order))+
    ggtitle("As percentage of body depth")+
  scale_y_discrete(limits=rev) +
  scale_x_continuous(labels = scales::percent) +
  geom_vline(data=. %>% filter(genus=="Amazichthys"),
             aes(xintercept=peduncle_height/body_depth),
             color="darkgrey") +
  labs(y=element_blank(),x="Peduncle Height as % of Body Depth") +
  geom_violin(data =. %>% filter(genus!="Amazichthys"), aes(fill=order),scale="width")+
  geom_boxplot(data = . %>% filter(genus!="Amazichthys"), width=0.3)+
  geom_star(data = . %>% filter(genus=="Amazichthys"),fill="black",size=3) +
  theme(legend.position="NA",
        axis.text.y = element_text(face=c(rep("plain",7),"italic"))),
data_recon%>%
  filter(family %in% c("Scombridae","Lamnidae","Megalopidae","Sphyraenidae")|order %in% c("Carangiformes","Istiophoriformes")|genus=="Amazichthys") %>%
  mutate(peduncle_height=ifelse(genus=="Amazichthys",6.679,peduncle_height)) %>%
  filter(!genus %in% c("Mitsukurina","Carcharhias","Odontaspis")) %>%
  drop_na(peduncle_height,precaudal_length) %>%
  mutate(order=case_when(genus=="Amazichthys" ~ "Amazichthys",
                         order == "Lamniformes" ~ "Lamnidae",
                         order == "Scombriformes" ~ "Scombridae",
                         order == "Elopiformes" ~ "Megalopidae",
                         order == "Carangaria incertae sedis" ~ "Sphyraenidae",
                         order == "Istiophoriformes" ~ "Istiophoriformes",
                         family %in% c("Carangidae","Coryphaenidae") ~ "Carangidae + Coryphaenidae",
                         family %in% c("Rachycentridae","Echeneidae") ~ "Echeneidae + Rachycentridae")) %>%
  ggplot(aes(x=peduncle_height/precaudal_length,y=order))+
  ggtitle("As percentage of precaudal length")+
  scale_y_discrete(limits=rev) +
  scale_x_continuous(labels = scales::percent) +
  geom_vline(data=. %>% filter(genus=="Amazichthys"),
             aes(xintercept=peduncle_height/precaudal_length),
             color="darkgrey") +
  labs(y=element_blank(),x="Peduncle Height as % of Precaudal Length") +
  geom_violin(data =. %>% filter(genus!="Amazichthys"), aes(fill=order),scale="width")+
  geom_boxplot(data = . %>% filter(genus!="Amazichthys"), width=0.3)+
  geom_star(data = . %>% filter(genus=="Amazichthys"),fill="black",size=3) +
  theme(legend.position="NA",
        axis.text.y = element_text(face=c(rep("plain",7),"italic")))
)
Caudal peduncle height in Amazichthys trinajsticae using the peduncle height in the reconstruction of Engelman (2023).

Figure 4.17: Caudal peduncle height in Amazichthys trinajsticae using the peduncle height in the reconstruction of Engelman (2023).

However, this has little effect on how unusually deep the peduncle of Amazichthys trinajsticae is relative to either precaudal length or body depth. It is almost impossible for Amazichthys to have a narrow lamnid/scombrid/istiophoriform-like peduncle, because this would require the peduncle to nearly double in height (go from ~8 cm to ~3.5 cm) due to decay, crushing, and taphonomic distortion, something that would be very difficult to achieve if the peduncle were originally narrow. This is even more so given both AA.MEM.DS.8 and PIMUZ A/I 4773 seem to show relatively deep peduncles (Jobbins et al. 2022: fig. 2).

4.8.2 Estimating peduncle height in Dunkleosteus

4.8.2.1 Estimating peduncle height using pelagic fishes

peduncle_height_1 <- data_recon %>%
  filter(family %in% c("Scombridae","Lamnidae","Cetorhinidae","Megachasmidae","Megalopidae","Sphyraenidae")|
           order %in% c("Carangiformes","Istiophoriformes")|
           genus=="Amazichthys") %$%
  lm(log(peduncle_height)~log(body_depth)*log(precaudal_length),.)

summary(peduncle_height_1)
## 
## Call:
## lm(formula = log(peduncle_height) ~ log(body_depth) * log(precaudal_length), 
##     data = .)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -0.94597 -0.23568  0.00498  0.19010  1.00082 
## 
## Coefficients:
##                                        Estimate Std. Error t value Pr(>|t|)    
## (Intercept)                           -2.750252   0.324060  -8.487 4.51e-16 ***
## log(body_depth)                       -0.081094   0.135864  -0.597    0.551    
## log(precaudal_length)                  0.952152   0.082407  11.554  < 2e-16 ***
## log(body_depth):log(precaudal_length)  0.001895   0.027264   0.069    0.945    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.3222 on 389 degrees of freedom
##   (136 observations deleted due to missingness)
## Multiple R-squared:  0.8579, Adjusted R-squared:  0.8568 
## F-statistic: 782.6 on 3 and 389 DF,  p-value: < 2.2e-16
data_recon %>%
  filter(genus %in% c("Dunkleosteus","Coccosteus","Incisoscutum","Amazichthys")) %>%
  filter(!is.na(peduncle_height)|genus=="Dunkleosteus") %>%
  arrange(genus)%>%
  drop_na(precaudal_length,body_depth) %>%
  augment(peduncle_height_1,
          newdata=.,
          interval="predict") %>%
  mutate(across(.fitted:.upper,~exp(.)*regression.stats(peduncle_height_1)$CF),
         taxon=str_replace(taxon,"_"," ")) %>%
  select(taxon,specimen,body_depth,precaudal_length,peduncle_height,.fitted,.lower,.upper)%>%
  kable(digits=c(1,1,1,1,2,2,2,2),
        align=c("l","c","c","c","c","c","c","c"),
        col.names=c("Taxon","Specimen","Body Depth","Precaudal Length",
                    "Actual Peduncle Depth",
                    "Fitted","Lower","Upper"),
        caption="Predicting the height of the caudal peduncle in <i>Dunkleosteus</i> using a model containing only large-bodied, pelagic fishes. All measurements in  cm.") %>%
  column_spec(1,italic=T) %>%
  kable_styling()
Table 4.8: Predicting the height of the caudal peduncle in Dunkleosteus using a model containing only large-bodied, pelagic fishes. All measurements in cm.
Taxon Specimen Body Depth Precaudal Length Actual Peduncle Depth Fitted Lower Upper
Amazichthys trinajsticae AA.MEM.DS.8 18.0 69.6 8.00 3.10 1.64 5.85
Coccosteus cuspidatus Recon. (M & W 1968) 6.8 26.9 2.82 1.34 0.71 2.53
Dunkleosteus terrelli CMNH 5768 100.0 265.9 9.90 5.20 18.84
Dunkleosteus terrelli CMNH 7424 38.2 147.2 6.01 3.19 11.34
Dunkleosteus terrelli CMNH 6090 75.6 221.0 8.45 4.46 16.02
Dunkleosteus terrelli CMNH 7054 72.5 230.6 8.83 4.66 16.73
Dunkleosteus terrelli CMNH 6194 36.5 129.5 5.33 2.83 10.07
Dunkleosteus terrelli CMC VP8294 33.0 122.6 5.09 2.70 9.62
Incisoscutum ritchei Recon. (Trinajstic et al. 2013) 5.3 20.7 1.94 1.06 0.56 2.01

Estimating the peduncle height using only large-bodied pelagic fishes produces a relatively narrow peduncle. However, this estimate potentially uses circular logic to estimate the peduncle height of Dunkleosteus by assuming this taxon is pelagic, as well as insensitive to clade-specific differences in peduncle height between arthrodires and other fishes (as seen in it underestimating peduncle height in all arthrodires where peduncle height can be approximated). Therefore, a broader approach using data from a wider variety of fishes was used.

4.8.2.2 Estimating peduncle height using all fishes

This model seeks to estimate the caudal peduncle depth of Dunkleosteus terrelli using all fishes, not just pelagic ones.

peduncle_height_2 <- data_recon %>%
  drop_na(peduncle_height,body_depth,precaudal_length) %$%
  lm(log(peduncle_height)~log(body_depth)*log(precaudal_length),.)

summary(peduncle_height_2)
## 
## Call:
## lm(formula = log(peduncle_height) ~ log(body_depth) * log(precaudal_length), 
##     data = .)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1.42466 -0.17506  0.04972  0.23949  1.47377 
## 
## Coefficients:
##                                        Estimate Std. Error t value Pr(>|t|)    
## (Intercept)                           -1.225664   0.049001 -25.013  < 2e-16 ***
## log(body_depth)                        0.603490   0.025882  23.317  < 2e-16 ***
## log(precaudal_length)                  0.283442   0.023038  12.303  < 2e-16 ***
## log(body_depth):log(precaudal_length) -0.021561   0.005683  -3.794 0.000153 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.3613 on 1965 degrees of freedom
## Multiple R-squared:  0.8141, Adjusted R-squared:  0.8138 
## F-statistic:  2869 on 3 and 1965 DF,  p-value: < 2.2e-16

Based on this, caudal peduncle height in fishes has a significant correlation with trunk height (body_depth), precaudal length, as well as fineness ratio (the interaction between body_depth and precaudal_length).

data_recon %>%
  filter(genus %in% c("Amazichthys","Dunkleosteus","Coccosteus","Incisoscutum")) %>%
  filter(!is.na(peduncle_height)|genus=="Dunkleosteus") %>%
  arrange(genus)%>%
  drop_na(precaudal_length,body_depth) %>%
  augment(peduncle_height_2,
          newdata=.,
          interval="predict") %>%
  mutate(across(.fitted:.upper,~exp(.)*regression.stats(peduncle_height_2)$CF),
         taxon=str_replace(taxon,"_"," ")) %>%
  select(taxon,specimen,body_depth,precaudal_length,peduncle_height,.fitted,.lower,.upper)%>%
  kable(digits=c(1,1,1,1,2,2,2,2),
        align=c("l","c","c","c","c","c","c","c"),
        col.names=c("Taxon","Specimen","Body Depth","Precaudal Length",
                    "Actual Peduncle Depth",
                    "Fitted","Lower","Upper"),
        caption="Predicting the height of the caudal peduncle in <i>Dunkleosteus</i> using a model containing all fishes and no life habits data. All measurements in cm.") %>%
  column_spec(1,italic=T) %>%
  kable_styling()
Table 4.9: Predicting the height of the caudal peduncle in Dunkleosteus using a model containing all fishes and no life habits data. All measurements in cm.
Taxon Specimen Body Depth Precaudal Length Actual Peduncle Depth Fitted Lower Upper
Amazichthys trinajsticae AA.MEM.DS.8 18.0 69.6 8.00 4.58 2.26 9.31
Coccosteus cuspidatus Recon. (M & W 1968) 6.8 26.9 2.82 2.21 1.09 4.49
Dunkleosteus terrelli CMNH 5768 100.0 265.9 14.12 6.92 28.78
Dunkleosteus terrelli CMNH 7424 38.2 147.2 7.86 3.87 15.98
Dunkleosteus terrelli CMNH 6090 75.6 221.0 11.91 5.85 24.25
Dunkleosteus terrelli CMNH 7054 72.5 230.6 11.76 5.78 23.95
Dunkleosteus terrelli CMNH 6194 36.5 129.5 7.48 3.68 15.21
Dunkleosteus terrelli CMC VP8294 33.0 122.6 7.03 3.46 14.30
Incisoscutum ritchei Recon. (Trinajstic et al. 2013) 5.3 20.7 1.94 1.81 0.89 3.68
peduncle_height_3 <- data_recon %>%
  drop_na(peduncle_height,body_depth,precaudal_length) %$%
  lm(log(peduncle_height)~log(body_depth)*log(precaudal_length)+habitat,.)

summary(peduncle_height_3)
## 
## Call:
## lm(formula = log(peduncle_height) ~ log(body_depth) * log(precaudal_length) + 
##     habitat, data = .)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1.50435 -0.16265  0.05342  0.21090  1.53215 
## 
## Coefficients:
##                                        Estimate Std. Error t value Pr(>|t|)    
## (Intercept)                           -1.284086   0.051110 -25.124  < 2e-16 ***
## log(body_depth)                        0.520267   0.026557  19.591  < 2e-16 ***
## log(precaudal_length)                  0.318867   0.021929  14.541  < 2e-16 ***
## habitatdemersal                        0.075302   0.030487   2.470   0.0136 *  
## habitatneritic                        -0.132858   0.033209  -4.001 6.55e-05 ***
## habitatpelagic                        -0.258872   0.035271  -7.339 3.13e-13 ***
## log(body_depth):log(precaudal_length) -0.002201   0.005724  -0.384   0.7007    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.3414 on 1957 degrees of freedom
##   (5 observations deleted due to missingness)
## Multiple R-squared:  0.8345, Adjusted R-squared:  0.834 
## F-statistic:  1645 on 6 and 1957 DF,  p-value: < 2.2e-16

Adding in life habits as an additional explanatory variable seems to have a significant correlative effect.

data_recon %>%
  filter(genus %in% c("Dunkleosteus","Coccosteus","Incisoscutum","Amazichthys")) %>%
  filter(!is.na(peduncle_height)|genus=="Dunkleosteus") %>%
  arrange(genus)%>%
  drop_na(precaudal_length,body_depth) %>%
  augment(peduncle_height_3,
          newdata=.,
          interval="predict") %>%
  mutate(across(.fitted:.upper,~exp(.)*regression.stats(peduncle_height_3)$CF),
         taxon=str_replace(taxon,"_"," ")) %>%
  select(taxon,specimen,body_depth,precaudal_length,peduncle_height,.fitted,.lower,.upper)%>%
  kable(digits=c(1,1,1,1,2,2,2,2),
        align=c("l","c","c","c","c","c","c","c"),
        col.names=c("Taxon","Specimen","Body Depth","Precaudal Length",
                    "Actual Peduncle Depth",
                    "Fitted","Lower","Upper"),
        caption="Predicting the height of the caudal peduncle in <i>Dunkleosteus</i> using a model containing all fishes and allowing covariance with life habits. All measurements in  cm.") %>%
  column_spec(1,italic=T) %>%
  kable_styling()
Table 4.10: Predicting the height of the caudal peduncle in Dunkleosteus using a model containing all fishes and allowing covariance with life habits. All measurements in cm.
Taxon Specimen Body Depth Precaudal Length Actual Peduncle Depth Fitted Lower Upper
Amazichthys trinajsticae AA.MEM.DS.8 18.0 69.6 8.00 3.84 1.97 7.51
Coccosteus cuspidatus Recon. (M & W 1968) 6.8 26.9 2.82 2.42 1.24 4.72
Dunkleosteus terrelli CMNH 5768 100.0 265.9 13.96 7.12 27.35
Dunkleosteus terrelli CMNH 7424 38.2 147.2 7.12 3.64 13.93
Dunkleosteus terrelli CMNH 6090 75.6 221.0 11.43 5.84 22.39
Dunkleosteus terrelli CMNH 7054 72.5 230.6 11.34 5.79 22.20
Dunkleosteus terrelli CMNH 6194 36.5 129.5 6.69 3.42 13.08
Dunkleosteus terrelli CMC VP8294 33.0 122.6 6.24 3.19 12.21
Incisoscutum ritchei Recon. (Trinajstic et al. 2013) 5.3 20.7 1.94 1.96 1.00 3.82

However, using this equation to estimate peduncle height in Dunkleosteus has little effect on caudal peduncle height predictions.

rbind(
  "Large-bodied pelagic fishes only"=regression.stats(peduncle_height_1),
  "All fishes, no habitat"=regression.stats(peduncle_height_2),
  "All fishes, with habitat"=regression.stats(peduncle_height_3)
)

Error rates in these models are okay, but not particularly great.

The predicted caudal peduncle height of Coccosteus and Incisoscutum is relatively close to the actual values. However the caudal peduncle of Amazichthys is significantly deeper than expected based on these models. Some of this is because while peduncle height is correlated with precaudal length, body depth, and life habits in fishes, there are other, clade-specific differences that influence caudal peduncle height as well. For example, all carangids have very narrow peduncles, regardless of whether they are pelagic taxa or occupy coastal or more reefal environments. Similarly, despite being closely related and having similar habits, rachycentrids have much deeper peduncles than carangids. Unfortunately, there are too few arthrodires for which the caudal peduncle height can be approximated to include taxonomic group as a variable in these models to expect this to improve model prediction. There is also a concern that these models might be biased towards tachynektonic pelagic fishes (and thus narrower peduncles) at larger sizes, simply because most large-bodied extant fishes are tachynektonic. These uncertainties are why the methods used here were not applied to the reconstruction of Dunkleosteus terrelli.

The peduncle height used for the present reconstruction of Dunkleosteus terrelli (~ 22 cm in CMNH 5768) is within the range of variation allowed by these models. It was calculated assuming shape change due to pelagic habits result in a similar disparity in relative peduncle depth between this taxon and demersal arthrodires (Coccosteus, Incisoscutum) as exists between analogous pelagic and demersal sharks. This is a coarse approximation, and is acknowledged as such. In spite of this, the model presented in this section suggests this estimate may be overly conservative and the peduncle may actually be too deep, predicting a peduncle height of ~15 cm. If the present model is accurate, its prediction would suggest the potential thunniform shape suggested elsewhere in this paper may be correct. However, this is said with the caveat that the model is insensitive to the possibility that arthrodires have proportionally deeper peduncles than other fishes, and accounting for this may result in a slightly deeper peduncle.

5 Other Data

5.1 Vertebral Count and Size in Dunkleosteus

Another feature supporting a smaller size for Dunkleosteus is the relative size of the vertebral column. Neural arches from the anterior axial skeleton are known in D. terrelli (CMNH 50322), but these elements are small relative to the size of the skull and thoracic shield (Johanson et al. 2019: fig. 1.2). This would result in an unusually small vertebral column with a slender notochord if assuming a shark-like body plan as in traditional reconstructions, which seems unlikely for an actively swimming nektonic organism. However, the size of the vertebrae make considerably more sense for a grouper or tuna-like body plan with a wider and deeper head and trunk relative to total length.

Extrapolating the size of the neural arches in CMNH 50322 to total length, and considering that vertebral elements in arthrodires tend to be narrower in the posterior (caudal and post-anal) regions of the axial skeleton (Miles and Westoll 1968), results in an estimated post-thoracic neural arch count of 104 elements (Figure 14 in main text)1. This is comparable to post-thoracic vertebral counts in Coccosteus cuspidatus (75–107, Miles and Westoll 1968: tab. I)

Anterior to the posterior margin of the thoracic shield, the neural arches are partially incorporated into the synarcual by fusion (Johanson et al. 2019). 16 partially fused neural arches are preserved in CMNH 50322, though more may have been present anteriorly and not preserved. This is not counting the “true” synarcual, which is composed of ~14 fully fused, undifferentiated vertebral elements based on the number of visible spinal nerve foramina (Johanson et al. 2013). This would result in a total count of ~124 vertebrae in Dunkleosteus terrelli.

This vertebral count is within the range of variation for sharks, though slightly below average (Springer and Garrick, 1964). It is comparable to taxa like Squalus (96-118), Cetorhinus (110), Mitsukurina (122) and Squatina (121-141), though lower than typical vertebral counts for Carcharias (156-170), Lamnidae (150-197) and Carcharhinidae (110-252) (ibid). This may be because sharks have a significant number of vertebrae anterior to the pectoral girdle above the branchial chamber, whereas in arthrodires these vertebrae are absent due to the posterior extension of the neurocranium and skull (Carr et al. 2009). For example Lamna nasus, a fairly short-bodied shark, there are 18 vertebrae in this region (ZMA.PISC.116165; Kamminga et al. 2017)

These vertebral accounts are approximate, but show the number of vertebrae required for the shorter, stockier Dunkleosteus depicted here better agree with vertebral counts in other arthrodires and sharks.

1 - Neural arch count is used given the haemal arches at the base of the caudal fin in arthrodires may be fusions of two vertebral elements (Miles and Westoll 1968: p. 449).

5.2 Scaling Pelvic Girdle Size in Eastmanosteus calliaspis

Dennis-Bryant (1987) reported a partial pelvic girdle for the specimen NHMUK PV P50877 (see also Trinajstic et al., 2015). This girdle measures 6.04 cm in greatest height (measured parallel to the iliac process, see Dennis-Bryant, 1987: fig. 30a-b). Specimens of Dunkleosteus terrelli were measured the same way, making these measurements comparable between specimens. NHMUK PV P50877 has an OOL of 8.66 cm (Dennis-Bryant 1987: fig. 11), though the angle the specimen was photographed at introduces some uncertainty. Using the OOL equation of Engelman 2023 (the one using individual specimens, body shape, and controlling for the effects of Serranidae, Holocentridae, and Chondrichthyes, see section 10.7.3. in that study’s supplementary information), this produces a total length of 56.88 cm. This results in a pelvic girdle with a height 10.6% estimated total length.

Alternatively, the nuchal plate of NHMUK PV P50877 is 82.1% the length of this plate in the holotype (WAM 70.4.864; Dennis-Bryant 1987: tab. 1). Nuchal length scales isometrically in other arthrodires (Trinajstic and McNamara 1999). Scaling the estimated total length of the holotype reported in Engelman (2023: 79.3 cm) to the size of NHMUK PV P50877 produces an estimated length of 65.1 cm and a relative pelvis height of 9.3% total length.

Regardless of how the size of the pelvis in NHMUK PV P50877 is estimated, it is at least twice the relative size of this element in Dunkleosteus terrelli, and probably around 2.5 times the size of the pelvis in this taxon.

Even if the estimated size of the pelvis in Eastmanosteus is slight overestimated, the height of the pelvis of Incisoscutum in the reconstruction of Trinajstic (2013) is 8.5% the total length of the animal. In Coccosteus the pelvis is 7.5% total length using the reconstruction in Miles and Westoll (1968); this reconstruction was used as total pelvis height was not measurable in any of the preserved specimens available. This would suggest the pelvis in Dunkleosteus is proportionally smaller than these other arthrodires, roughly 15–40% smaller in linear dimensions. In Amazichthys trinajsticae the pelvis is only about 5% total length (Jobbins et al. 2022: fig. 2a-b), closer to but slightly smaller than the relative size seen in Dunkleosteus.

6 References

6.1 Literature References

Ahlberg, P., Trinajstic, K., Johanson, Z., Long, J. 2009. Pelvic claspers confirm chondrichthyan-like internal fertilization in arthrodires. Nature, 460:888-889. https://doi.org/10.1038/nature08176

Ault, J.S., and Luo, J. 2013. A reliable game fish weight estimation model for Atlantic tarpon (Megalops atlanticus). Fisheries Research, 139:110–117. https://doi.org/https://doi.org/10.1016/j.fishres.2012.10.004

Carr, R.K. 1995. Placoderm diversity and evolution. Bulletin du Muséum National d’Histoire Naturelle, 4:85–125.

Carr, R.K., Johanson, Z., and Ritchie, A. 2009. The phyllolepid placoderm Cowralepis mclachlani: Insights into the evolution of feeding mechanisms in jawed vertebrates. Journal of Morphology, 270:775–804. https://doi.org/10.1002/jmor.10719

Cavin, L., Forey, P.L., and Giersch, S. 2013. Osteology of Eubiodectes libanicus (Pictet & Humbert, 1866) and some other ichthyodectiformes (Teleostei): phylogenetic implications. Journal of Systematic Palaeontology, 11:115–177. https://doi.org/10.1080/14772019.2012.691559

Dean, B. 1896. On the vertebral column, fins, and ventral armoring of Dinichthys. Proceedings of the New York Academy of Sciences, 15:157-188.

Dennis-Bryan, K. 1987. A new species of eastmanosteid arthrodire (Pisces: Placodermi) from Gogo, Western Australia. Zoological Journal of the Linnean Society, 90:1–64. https://doi.org/10.1111/j.1096-3642.1987.tb01347.x

Dennis, K., and Miles, R.S. 1979. Eubrachythoracid arthrodires with tubular rostral plates from Gogo, Western Australia. Zoological Journal of the Linnean Society, 67:297–328. https://doi.org/10.1111/j.1096-3642.1979.tb01118.x

Engelman, R.K. 2023. A Devonian fish tale: A new method of body length estimation suggests much smaller sizes for Dunkleosteus terrelli (Placodermi: Arthrodira). Diversity, 15:318. https://doi.org/10.3390/d15030318

Gleiss, A.C., Potvin, J., and Goldbogen, J.A. 2017. Physical trade-offs shape the evolution of buoyancy control in sharks. Proceedings of the Royal Society B: Biological Sciences, 284:20171345. https://doi.org/10.1098/rspb.2017.1345

Hubbs, C., Lagler, K., and Smith, G. 2004. Fishes of the Great Lakes Region, Revised Edition, Revised edition. University of Michigan Press, Ann Arbor.https://doi.org/10.3998/mpub.17658

Jobbins, M., Rücklin, M., Ferrón, H.G., and Klug, C. 2022. A new selenosteid placoderm from the Late Devonian of the eastern Anti-Atlas (Morocco) with preserved body outline and its ecomorphology. Frontiers in Ecology and Evolution, 10:969158. https://doi.org/10.3389/fevo.2022.969158

Johanson, Z., Trinajstic, K., Carr, R., and Ritchie, A. 2013. Evolution and development of the synarcual in early vertebrates. Zoomorphology, 132:95–110. https://doi.org/10.1007/s00435-012-0169-9

Johanson, Z., Trinajstic, K., Cumbaa, S., and Ryan, M.J. 2019. Fusion in the vertebral column of the pachyosteomorph arthrodire Dunkleosteus terrelli (‘Placodermi’). Palaeontologia Electronica, 22.2.20A:1–13. https://doi.org/10.26879/872

Kamminga, P., De Bruin, P.W., Geleijns, J., and Brazeau, M.D. 2017. X-ray computed tomography library of shark anatomy and lower jaw surface models. Scientific Data, 4:170047. https://doi.org/10.1038/sdata.2017.47

Kogan, I., S. Pacholak, M. Licht, J. W. Schneider, C. Brucker, and S. Brandt. 2015. The invisible fish: hydrodynamic constraints for predator-prey interaction in fossil fish Saurichthys compared to recent actinopterygians. Biology Open 4:1715-1726. https://doi.org/10.1242/bio.014720

Lund, R., and Lund, W. 1984. New genera and species of coelacanths from the Bear Gulch limestone (lower Carboniferous) of Montana, U.S.A. Geobios 17:237-244. https://doi.org/10.1016/S0016-6995(84)80145-X

Miles, R.S. 1969. Features of Placoderm Diversification and the Evolution of the Arthrodire Feeding Mechanism. Transactions of the Royal Society of Edinburgh, 68:123–170. https://doi.org/10.1017/S0080456800014629

Miles, R.S., Westoll, T.S. 1968. The Placoderm Fish Coccosteus cuspidatus Miller ex Agassiz from the Middle Old Red Sandstone of Scotland. Part I. Descriptive Morphology. Transactions of the Royal Society of Edinburgh, 67:373-476. https://doi.org/10.1017/S0080456800024078

Millot, J., Anthony, J., and Robineau ,D. 1978. Anatomie de Latimeria Chalumnae, Tome III: Appareil Digestif, Appareil Respiratoire, Appareil Urogenital Glandes Endocrines, Appareil Circulatoire Téguments, Ecailles, Conclusions Générale. CNRS, Paris.

Randall, J.E. 1997. Randall’s tank photos. Collection of 10,000 large-format photos (slides) of dead fishes. Accessed June 29, 2022. www.fishbase.org (see species pages for more details)

Saruwatari, T., Iwata, M., Yabumoto, Y., Hukom, F.D., Peristiwady, T., and Abe, Y. 2019. A detailed morphological measurement of the seventh specimen of the Indonesian coelacanth, Latimeria menadoensis, with a compilation of current morphological data of the species. Bulletin of the Kitakyushu Museum of Natural History and Human History, Series A (Natural History): 17:67-80. https://doi.org/10.34522/kmnh.17.0_67

Schwenk, K. 1995. A utilitarian approach to evolutionary constraint. Zoology, 98:251–262.

Springer, V.G., and Garrick, J.A.F. 1964. A survey of vertebral numbers in sharks. Proceedings of the United States National Museum, 116:73–96. https://10.5479/si.00963801.116-3496.73

Straube, N., Li, C., Claes, J.M., Corrigan, S., and Naylor, G.J.P. 2015. Molecular phylogeny of Squaliformes and first occurrence of bioluminescence in sharks. BMC Evolutionary Biology, 15:162. https://doi.org/10.1186/s12862-015-0446-6

Stensiö, E.A. 1959. On the pectoral fin and shoulder girdle of the arthrodires. Kungligar Svenska Vetenskapakadamiens Handlingar, 8:1–229.

Sternes, P.C., and Shimada, K. 2020. Body forms in sharks (Chondrichthyes: Elasmobranchii) and their functional, ecological, and evolutionary implications. Zoology, 140:125799. https://doi.org/10.1016/j.zool.2020.125799

Trinajstic, K., and McNamara, K.J. 1999. Heterochrony in the Late Devonian arthrodiran fishes Compagopiscis and Incisoscutum. Records of the Western Australian Museum, 57:77–91.

Trinajstic, K., and Hazelton, M. 2007. Ontogeny, phenotypic variation and phylogenetic implications of arthrodires from the Gogo Formation, Western Australia. Journal of Vertebrate Paleontology, 27:571–583. https://doi.org/10.1671/0272-4634(2007)27[571:OPVAPI]2.0.CO;2

Trinajstic, K., Boisvert, C., Long, J., Maksimenko, A., and Johanson, Z. 2015. Pelvic and reproductive structures in placoderms (stem gnathostomes). Biological Reviews, 90:467-501. https://doi.org/10.1111/brv.12118

Trinajstic, K., Long, J.A., Sanchez, S., Boisvert, C.A., Snitting, D., Tafforeau, P., Dupret, V., Clement, A.M., Currie, P.D., Roelofs, B., Bevitt, J.J., Lee, M.S.Y., and Ahlberg, P.E. 2022. Exceptional preservation of organs in Devonian placoderms from the Gogo lagerstätte. Science, 377:1311-1314, https://doi.org/10.1126/science.abf3289

Trinajstic, K., Sanchez, S., Dupret, V., Tafforeau, P., Long, J., Young, G., Senden, T., Boisvert, C., Power, N., and Ahlberg, P.E. 2013. Fossil musculature of the most primitive jawed vertebrates. Science, 341:160-4. https://doi.org/10.1126/science.1237275

Wagner, G.P., and Schwenk, K. 2000. Evolutionarily Stable Configurations: Functional Integration and the Evolution of Phenotypic Stability. In Hecht, M.K., Macintyre, R.J., Clegg, M.T. (eds.) Evolutionary Biology. Springer, Boston. https://doi.org/10.1007/978-1-4615-4185-1_4

Werdelin, L. 1987. Jaw geometry and molar morphology in marsupial carnivores; analysis of a constraint and its macroevolutionary consequences. Paleobiology, 13:342–350. https://doi.org/10.1017/S0094837300008915

6.2 R Packages

Auguie B (2017). gridExtra: Miscellaneous Functions for “Grid” Graphics. R package version 2.3, https://CRAN.R-project.org/package=gridExtra.

Bache S, Wickham H (2022). magrittr: A Forward-Pipe Operator for R. R package version 2.0.3, https://CRAN.R-project.org/package=magrittr.

Pedersen T (2024). patchwork: The Composer of Plots. R package version 1.2.0, https://CRAN.R-project.org/package=patchwork.

R Core Team (2023). R: A Language and Environment for Statistical Computing. R Foundation for Statistical Computing, Vienna, Austria. https://www.R-project.org/.

Robinson D, Hayes A, Couch S (2023). broom: Convert Statistical Objects into Tidy Tibbles. R package version 1.0.5, https://CRAN.R-project.org/package=broom.

Wickham H, Bryan J (2023). readxl: Read Excel Files. R package version 1.4.3, https://CRAN.R-project.org/package=readxl.

Wickham H, Seidel D (2022). scales: Scale Functions for Visualization. R package version 1.2.1, https://CRAN.R-project.org/package=scales.

Wickham H, Averick M, Bryan J, Chang W, McGowan LD, François R, Grolemund G, Hayes A, Henry L, Hester J, Kuhn M, Pedersen TL, Miller E, Bache SM, Müller K, Ooms J, Robinson D, Seidel DP, Spinu V, Takahashi K, Vaughan D, Wilke C, Woo K, Yutani H (2019). “Welcome to the tidyverse.” Journal of Open Source Software, 4(43), 1686. https://doi.org/10.21105/joss.01686.

Wilke C, Wiernik B (2022). ggtext: Improved Text Rendering Support for ‘ggplot2’. R package version 0.1.2, https://CRAN.R-project.org/package=ggtext.

Xu S (2022). ggstar: Multiple Geometric Shape Point Layer for ‘ggplot2’. R package version 1.0.4, https://CRAN.R-project.org/package=ggstar.

Zhu H (2021). kableExtra: Construct Complex Table with ‘kable’ and Pipe Syntax. R package version 1.3.4, https://CRAN.R-project.org/package=kableExtra.

7 Session Information

xfun::session_info()
## R version 4.3.1 (2023-06-16 ucrt)
## Platform: x86_64-w64-mingw32/x64 (64-bit)
## Running under: Windows 10 x64 (build 19045)
## 
## 
## Locale:
##   LC_COLLATE=English_United States.utf8 
##   LC_CTYPE=English_United States.utf8   
##   LC_MONETARY=English_United States.utf8
##   LC_NUMERIC=C                          
##   LC_TIME=English_United States.utf8    
## 
## time zone: America/New_York
## tzcode source: internal
## 
## Package version:
##   askpass_1.2.0       backports_1.4.1     base64enc_0.1.3    
##   bit_4.0.5           bit64_4.0.5         blob_1.2.4         
##   bookdown_0.36       broom_1.0.5         bslib_0.5.1        
##   cachem_1.0.8        callr_3.7.3         cellranger_1.1.0   
##   cli_3.6.1           clipr_0.8.0         colorspace_2.1-0   
##   commonmark_1.9.0    compiler_4.3.1      conflicted_1.2.0   
##   cpp11_0.4.6         crayon_1.5.2        curl_5.1.0         
##   data.table_1.14.8   DBI_1.1.3           dbplyr_2.4.0       
##   digest_0.6.33       dplyr_1.1.3         dtplyr_1.3.1       
##   ellipsis_0.3.2      evaluate_0.23       fansi_1.0.5        
##   farver_2.1.1        fastmap_1.1.1       fontawesome_0.5.2  
##   forcats_1.0.0       fs_1.6.3            gargle_1.5.2       
##   generics_0.1.3      ggplot2_3.4.4       ggstar_1.0.4       
##   ggtext_0.1.2        glue_1.6.2          googledrive_2.1.1  
##   googlesheets4_1.1.1 graphics_4.3.1      grDevices_4.3.1    
##   grid_4.3.1          gridExtra_2.3       gridtext_0.1.5     
##   gtable_0.3.4        haven_2.5.3         highr_0.10         
##   hms_1.1.3           htmltools_0.5.6.1   httr_1.4.7         
##   ids_1.0.1           isoband_0.2.7       jpeg_0.1.10        
##   jquerylib_0.1.4     jsonlite_1.8.7      kableExtra_1.3.4   
##   knitr_1.44          labeling_0.4.3      lattice_0.21-8     
##   lifecycle_1.0.3     lubridate_1.9.3     magrittr_2.0.3     
##   markdown_1.11       MASS_7.3.60         Matrix_1.5-4.1     
##   memoise_2.0.1       methods_4.3.1       mgcv_1.8-42        
##   mime_0.12           modelr_0.1.11       munsell_0.5.0      
##   nlme_3.1-162        openssl_2.1.1       patchwork_1.2.0    
##   pillar_1.9.0        pkgconfig_2.0.3     png_0.1.8          
##   prettyunits_1.2.0   processx_3.8.2      progress_1.2.2     
##   ps_1.7.5            purrr_1.0.2         R6_2.5.1           
##   ragg_1.2.6          rappdirs_0.3.3      RColorBrewer_1.1.3 
##   Rcpp_1.0.11         readr_2.1.4         readxl_1.4.3       
##   rematch_2.0.0       rematch2_2.1.2      reprex_2.0.2       
##   rlang_1.1.1         rmarkdown_2.25      rmdformats_1.0.4   
##   rstudioapi_0.15.0   rvest_1.0.3         sass_0.4.7         
##   scales_1.2.1        selectr_0.4.2       splines_4.3.1      
##   stats_4.3.1         stringi_1.7.12      stringr_1.5.0      
##   svglite_2.1.2       sys_3.4.2           systemfonts_1.0.5  
##   textshaping_0.3.7   tibble_3.2.1        tidyr_1.3.0        
##   tidyselect_1.2.0    tidyverse_2.0.0     timechange_0.2.0   
##   tinytex_0.48        tools_4.3.1         tzdb_0.4.0         
##   utf8_1.2.4          utils_4.3.1         uuid_1.1.1         
##   vctrs_0.6.4         viridisLite_0.4.2   vroom_1.6.4        
##   webshot_0.5.5       withr_2.5.2         xfun_0.40          
##   xml2_1.3.5          yaml_2.3.7
LS0tDQp0aXRsZTogIidSZWNvbnN0cnVjdGluZyA8aT5EdW5rbGVvc3RldXMgdGVycmVsbGk8L2k+IChQbGFjb2Rlcm1pOiBBcnRocm9kaXJhKTogQSBOZXcgTG9vayBmb3IgYW4gSWNvbmljIERldm9uaWFuIFByZWRhdG9yJyINCnN1YnRpdGxlOiAiQXBwZW5kaXggMyAoU3VwcGxlbWVudGFyeSBBbmFseXNlcykiDQphdXRob3I6ICJSdXNzZWxsIEVuZ2VsbWFuIg0KZGF0ZTogIjIwMjMtMTEtMjciDQpwYXJhbXM6DQogIG9yaWdfZGF0ZTogIjI3IE5vdmVtYmVyLCAyMDIzIg0KICB1cGRhdGVfZGF0ZTogIXIgcGFzdGUoZm9ybWF0KFN5cy50aW1lKCksICclZCAlQiwgJVknKSkNCm91dHB1dDoNCiAgcm1kZm9ybWF0czo6aHRtbF9jbGVhbjoNCiAgICBoaWdobGlnaHQ6IGhhZGRvY2sNCiAgICB0b2M6IFRSVUUNCiAgICB0b2NfZGVwdGg6IDMNCiAgICB0b2NfZmxvYXQ6IFRSVUUNCiAgICBudW1iZXJfc2VjdGlvbnM6IFRSVUUNCiAgICB0aHVtYm5haWxzOiBGQUxTRQ0KICAgIGNvZGVfZm9sZGluZzogc2hvdw0KICAgIGRmX3ByaW50OiBwYWdlZA0KICAgIERUOiBkYXRhdGFibGUNCiAgICB1c2VfYm9va2Rvd246IFRSVUUNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQotLS0NCjxzdHlsZT4NCmJvZHkgLm1haW4tY29udGFpbmVyIHsNCiAgICAgICAgbWF4LXdpZHRoOiAxMDAwcHg7DQogICAgfQ0KI3RvYyB7DQogIHdpZHRoOiAxNSU7DQp9DQo8L3N0eWxlPg0KDQoqKkRhdGUgQ3JlYXRlZDoqKiBgciBwYXJhbXMkb3JpZ19kYXRlYA0KDQoqKkxhc3QgTW9kaWZpZWQ6KiogYHIgcGFyYW1zJHVwZGF0ZV9kYXRlYA0KDQpUaGlzIGlzIGFuIFIgTWFya2Rvd24gZG9jdW1lbnQuIE1hcmtkb3duIGlzIGEgc2ltcGxlIGZvcm1hdHRpbmcgc3ludGF4IGZvciBhdXRob3JpbmcgSFRNTCwgUERGLCBhbmQgTVMgV29yZCBkb2N1bWVudHMuIEZvciBtb3JlIGRldGFpbHMgb24gdXNpbmcgUiBNYXJrZG93biBzZWUgPGh0dHA6Ly9ybWFya2Rvd24ucnN0dWRpby5jb20+Lg0KDQpUbyBvYnRhaW4gdGhlIG9yaWdpbmFsIFIgY29kZSBmb3IgdGhpcyBhbmFseXNpcywgc2VsZWN0IHRoZSAiQ29kZSIgYnV0dG9uIGF0IHRoZSB0b3Agb2YgdGhlIGRvY3VtZW50IGFuZCBjbGljayAiRG93bmxvYWQgUm1kIi4gVGhpcyB3aWxsIGRvd25sb2FkIHRoZSBvcmlnaW5hbCBjb2RlIGluIC5ybWQgZm9ybWF0LiBUaGlzIGZvcm1hdCBjYW4gYmUgb3BlbmVkIGluIHByb2dyYW1zIGxpa2UgUlN0dWRpbyBhcyB3ZWxsIGFzIGdlbmVyYWwgdGV4dCBlZGl0b3JzLiBUbyByZXBsaWNhdGUgdGhpcyBkb2N1bWVudCwgcGxhY2UgdGhpcyBjb2RlIGFuZCBhc3NvY2lhdGVkIGRhdGEgZmlsZXMgKCIxMzQzX0FwcGVuZGl4IDQueGxzeCIpIGluIGEgc2luZ2xlIGZvbGRlciwgb3BlbiB0aGlzIGZpbGUgaW4gUlN0dWRpbywgYW5kIHRoZW4gY2xpY2sgdGhlICJLbml0IiBidXR0b24uDQoNCiMgTG9hZGluZyBpbiBEYXRhDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZ9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsZmlnLndpZHRoPTcsZmlnLmhlaWdodD00LjUsY2xhc3Muc291cmNlID0gJ2ZvbGQtaGlkZScpDQpsaWJyYXJ5KGthYmxlRXh0cmEpO2xpYnJhcnkocmVhZHhsKTtsaWJyYXJ5KGdyaWRFeHRyYSk7bGlicmFyeShtYWdyaXR0cik7bGlicmFyeShicm9vbSk7bGlicmFyeShzY2FsZXMpO2xpYnJhcnkoZ2dzdGFyKTtsaWJyYXJ5KHBhdGNod29yayk7bGlicmFyeShnZ3RleHQpO2xpYnJhcnkodGlkeXZlcnNlKQ0Kb3B0aW9ucyhrbml0ci5rYWJsZS5OQSA9ICItLSIpDQpgYGANCg0KKipTYXZpbmcgUmFtYW51amFuJ3MgQXBwcm94aW1hdGlvbiBvZiB0aGUgUGVyaW1ldGVyIG9mIGFuIEVsbGlwc2UqKg0KDQpgYGB7cn0NCnJhbWFudWphbi5hcHByb3g8LWZ1bmN0aW9uKHgseSkgew0KICBtYWpvcmF4aXM9eC8yOw0KICBtaW5vcmF4aXM9eS8yOw0KICBwaSooKG1ham9yYXhpcyttaW5vcmF4aXMpLQ0KICAgICAgICAoKDMqKG1ham9yYXhpcy1taW5vcmF4aXMpXjIpLw0KICAgICAgICAgICAoMTAqKHgrbWlub3JheGlzKStzcXJ0KHheMisxNCptYWpvcmF4aXMqbWlub3JheGlzK21pbm9yYXhpc14yKSkpKQ0KfQ0KYGBgDQoNCioqU2F2aW5nIEN1c3RvbSBGb3JtdWxhIGZvciBSZWdyZXNzaW9uIFN0YXRpc3RpY3MqKg0KDQpgYGB7cn0NCnJlZ3Jlc3Npb24uc3RhdHM8LWZ1bmN0aW9uKGZpdCl7DQogIGZvcm11bGE8LWZpdCRjYWxsOw0KICBsb2dfdHJhbnM8LWRwbHlyOjpjYXNlX3doZW4oc3Vic3RyKGNvbG5hbWVzKGZpdCRtb2RlbFsxXSksMSw1KT09ImxvZzEwIn4ibG9nMTAiLA0KICAgICAgICAgICAgICAgICAgICAgICBzdWJzdHIoY29sbmFtZXMoZml0JG1vZGVsWzFdKSwxLDQpPT0ibG9nKCJ+ImxuIiwNCiAgICAgICAgICAgICAgICAgICAgICAgVFJVRX4ibm9uZSIpOw0KICB5PC1zd2l0Y2gobG9nX3RyYW5zLCJsb2cxMCI9MTBeZml0JG1vZGVsWywxXSwibG4iPWV4cChmaXQkbW9kZWxbLDFdKSwibm9uZSI9Zml0JG1vZGVsWywxXSk7DQogIGZpdHRlZDwtc3dpdGNoKGxvZ190cmFucywibG9nMTAiPTEwXmZpdHRlZChmaXQpLCJsbiI9ZXhwKGZpdHRlZChmaXQpKSwibm9uZSI9Zml0dGVkKGZpdCkpOw0KICBhYnNlcnJvcjwtYWJzKGZpdHRlZC15KS9maXR0ZWQ7DQogIFFNTEU8LWlmZWxzZShsb2dfdHJhbnM9PSJub25lIiwNCiAgICAgICAgICAgICAgIE5BLA0KICAgICAgICAgICAgICAgaWZlbHNlKGxvZ190cmFucz09ImxvZzEwIiwNCiAgICAgICAgICAgICAgICAgICAgICAxMF4oKHNpZ21hKGZpdCleMikvMiksDQogICAgICAgICAgICAgICAgICAgICAgZXhwKChzaWdtYShmaXQpXjIpLzIpKSk7DQogIHNtZWFyPC1pZmVsc2UobG9nX3RyYW5zPT0ibm9uZSIsDQogICAgICAgICAgICAgICAgTkEsDQogICAgICAgICAgICAgICAgaWZlbHNlKGxvZ190cmFucz09ImxvZzEwIiwNCiAgICAgICAgICAgICAgICAgICAgICAgc3VtKDEwXmZpdCRyZXNpZHVhbHMpL25yb3coZml0JG1vZGVsKSwNCiAgICAgICAgICAgICAgICAgICAgICAgc3VtKGV4cChmaXQkcmVzaWR1YWxzKSkvbnJvdyhmaXQkbW9kZWwpKSk7DQogIFJFPC1pZmVsc2UobG9nX3RyYW5zPT0ibm9uZSIsDQogICAgICAgICAgICAgTkEsDQogICAgICAgICAgICAgbWVhbih5KS9tZWFuKGZpdHRlZCkpOw0KICBDRjwtaWZlbHNlKGxvZ190cmFucz09Im5vbmUiLA0KICAgICAgICAgICAgIE5BLA0KICAgICAgICAgICAgIChSRStzbWVhcitRTUxFKS8zKTsNCiAgYWRqUEU8LWlmZWxzZShsb2dfdHJhbnM9PSJub25lIiwNCiAgICAgICAgICAgICAgICBOQSwNCiAgICAgICAgICAgICAgICBtZWFuKGFicygoZml0dGVkKkNGKS15KS8oZml0dGVkKkNGKSkpOw0KICBTRUU8LWlmZWxzZShsb2dfdHJhbnM9PSJsb2cxMCIsDQogICAgICAgICAgICAgIDEwXigyK3NpZ21hKGZpdCkpLTEwMCwNCiAgICAgICAgICAgICAgZXhwKHNpZ21hKGZpdCkrNC42MDUyKS0xMDApOw0KICBzdW1tYXJ5PC1zdW1tYXJ5KGZpdCk7DQogIHN0YXRpc3RpY3M8LWRhdGEuZnJhbWUoIk4iPW5yb3coZml0JG1vZGVsKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAiZGYiPWZpdCRkZi5yZXNpZHVhbCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAicjIiPXJvdW5kKHN1bW1hcnkoZml0KSRyLnNxdWFyZWQsNCksDQogICAgICAgICAgICAgICAgICAgICAgICAgImFkanIyIj1yb3VuZChzdW1tYXJ5KGZpdCkkYWRqLnIuc3F1YXJlZCw0KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAiQUlDIj1yb3VuZChBSUMoZml0KSwwKSwiQklDIj1yb3VuZChCSUMoZml0KSwwKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAibG9nTGlrIj1yb3VuZChsb2dMaWsoZml0KSwwKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAiUEUiPXJvdW5kKG1lYW4oYWJzZXJyb3IpKjEwMCwyKSxRTUxFPXJvdW5kKFFNTEUsMyksDQogICAgICAgICAgICAgICAgICAgICAgICAgc21lYXI9cm91bmQoc21lYXIsMyksUkU9cm91bmQoUkUsMyksQ0Y9cm91bmQoQ0YsMyksDQogICAgICAgICAgICAgICAgICAgICAgICAgImFkalBFIj1yb3VuZChtZWFuKGFkalBFKSoxMDAsMiksDQogICAgICAgICAgICAgICAgICAgICAgICAgIlNFRSI9cm91bmQoU0VFLDIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgIHJvdy5uYW1lcz1kZXBhcnNlKHN1YnN0aXR1dGUoZml0KSkpOw0KICByZXR1cm4oc3RhdGlzdGljcykNCn0NCmBgYA0KDQoqKkxvYWRpbmcgaW4gRGF0YSoqDQoNCmBgYHtyfQ0KZGF0YV9yZWNvbjwtcmVhZF94bHN4KCIxMzQzX0FwcGVuZGl4XzQueGxzeCIpICU+JQ0KICByZW5hbWUoY2xhZGU9Q2xhZGUsb3JkZXI9T3JkZXIsaGlnaGVyX2dyb3VwPSJIaWdoZXIgT3JkZXIgQ2xhZGUiLGZhbWlseT0iRmFtaWx5IiwNCiAgICAgICAgIHNoYXBlPVNoYXBlLGhhYml0YXQ9SGFiaXR1cyxleHRpbmN0PUV4dGluY3QsZ2VudXM9R2VudXMsc3BlY2llcz1TcGVjaWVzLA0KICAgICAgICAgc3BlY2ltZW49U3BlY2ltZW4sDQogICAgICAgICBib2R5X21hc3M9IldlaWdodCAoZykiLA0KICAgICAgICAgdG90YWxfbGVuZ3RoPSJUb3RhbCBMZW5ndGggKGNtKSIsDQogICAgICAgICBmb3JrX2xlbmd0aD0iRm9yayBMZW5ndGggKGNtKSIsDQogICAgICAgICBwcmVjYXVkYWxfbGVuZ3RoPSJQcmVjYXVkYWwgTGVuZ3RoIChjbSkiLA0KICAgICAgICAgaGVhZF9sZW5ndGg9IkhlYWQgTGVuZ3RoIChjbSkiLA0KICAgICAgICAgYm9keV9kZXB0aD0iQm9keSBEZXB0aCAoY20pIiwNCiAgICAgICAgIHByZXBlY3RvcmFsX2xlbmd0aD0iUHJlcGVjdG9yYWwgTGVuZ3RoIChjbSkiLA0KICAgICAgICAgcHJlcGVsdmljX2xlbmd0aD0iUHJlcGVsdmljIExlbmd0aCIsDQogICAgICAgICBwZWNfYmFzZT0iUGVjdG9yYWwgRmluIEJhc2UgKGNtKSIsDQogICAgICAgICBTVkw9IlNub3V0LVZlbnQgTGVuZ3RoIChjbSkiLA0KICAgICAgICAgcHJlYW5hbF9sZW5ndGg9IlByZWFuYWwgTGVuZ3RoIChjbSkiLA0KICAgICAgICAgcGVkdW5jbGVfaGVpZ2h0PSJDYXVkYWwgUGVkdW5jbGUgRGVwdGggKGNtKSIpJT4lDQogIG11dGF0ZSh0YXhvbj1wYXN0ZTAoZ2VudXMsIl8iLHNwZWNpZXMpKQ0KYGBgDQoNCioqQ3JlYXRpbmcgKlJoaXpvcHJpb25vZG9uKiBzaWxob3VldHRlKioNCg0KYGBge3J9DQpyaGl6bzwtZGF0YS5mcmFtZSh4PWMoMC40MDA3NTc4LDAuMzk0Njk1NCwwLjM4ODc1MDgsMC4zODI5MjksMC4zNzczMTMxLDAuMzcyMTk4OCwwLjM2NzUxMTMsMC4zNjI5MDAyLDAuMzU4MzM4NCwwLjM1MzgxODgsMC4zNDkzNDI0LDAuMzQ0OTE2LDAuMzQwNDI5MywwLjMzNTc3MDksMC4zMzA4MjkxLDAuMzI1MzUxMSwwLjMxODk5ODIsMC4zMTIyNjE3LDAuMzA1Mzc4NSwwLjI5ODQzMjYsMC4yOTE0NTczLDAuMjg0NDczNywwLjI3NzQ5OTMsMC4yNzA1NTE2LDAuMjYzNjYwMSwwLjI1Njc4MDcsMC4yNDk4NzI3LDAuMjQyOTQzNiwwLjIzNjAyMTUsMC4yMjkxNDA1LDAuMjIyMjYxNiwwLjIxNTM1NjksMC4yMDg0NzQxLDAuMjAxNjM3NSwwLjE5NDg4NDgsMC4xODgwNzcyLDAuMTgxMjMzOCwwLjE3NDQyODgsMC4xNjc2NjI3LDAuMTYwODI1NCwwLjE1NDA5MTEsMC4xNDczOTk1LDAuMTQwNjczOCwwLjEzNDAxNzIsMC4xMjc0NzI0LDAuMTIwOTE4MywwLjExNDI4NjEsMC4xMDc1NTMyLDAuMTAwNzIsMC4wOTM4MTY1OSwwLjA4NjkzMTg5LDAuMDgwMTExODksMC4wNzMzNzkxNiwwLjA2Njc5NiwwLjA2MDMxNTUsMC4wNTM1OTE0LDAuMDQ2ODEyMjEsMC4wNDAxMjkxNywwLjAzMzQyMjMxLDAuMDI2NjMwMzcsMC4wMTk4OTgxNSwwLjAxMzI3Mzc5LDAuMDA2ODIzNzI3LDAuMDAwODI5NDc0NCwwLDAuMDA1MzUyODc0LDAuMDExNjY1NCwwLjAxODM0MzU0LDAuMDI0OTczNTIsMC4wMzE0ODMwOSwwLjAzODAyNDExLDAuMDQ0NjQ5OTgsMC4wNTEzNjM0OSwwLjA1ODEzMjc1LDAuMDY0ODA0NDgsMC4wNzE4MDIxOSwwLjA3ODgyMjM3LDAuMDgwNDYzMTMsMC4wODYwNTY1LDAuMDkyOTg0NDUsMC4wOTk5MzA2MywwLjEwNjg3NzcsMC4xMTM4MTkyLDAuMTIwNzU2LDAuMTI3Njg4NCwwLjEzNDYxNjYsMC4xNDE1Mzk4LDAuMTQ4NDU2MywwLjE1NTM2MTcsMC4xNjIyNTgsMC4xNjkyNDA4LDAuMTc2MjY0OSwwLjE4MzI4NCwwLjE5MDEyNjIsMC4xOTcwNTg4LDAuMjA0MDY2OCwwLjIxMTA0MjQsMC4yMTc4NTQzLDAuMjI0Mzk0LDAuMjMwNjg5MiwwLjIzNTg5MTYsMC4yMzg3MTMzLDAuMjQxMzcyOCwwLjI0NDE1ODIsMC4yNDcwMTMxLDAuMjQ5OTMxOCwwLjI1MjkzNjMsMC4yNTYwMDM0LDAuMjU4ODM1MiwwLjI2MjE2NzIsMC4yNjU2OTEzLDAuMjY5MTg5NSwwLjI3MjYzMzEsMC4yNzYwNDY2LDAuMjc5ODk4MywwLjI4NTE0ODYsMC4yOTA5MjAyLDAuMjk2Njc5MywwLjI5NzQzNzcsMC4yOTc3NzUyLDAuMjk4MDU5NywwLjI5ODM1OTUsMC4yOTg3MTYzLDAuMjk5MTczMywwLjI5OTg0OTYsMC4zMDEzNDAxLDAuMzAzMTc5OCwwLjMwNDM2OSwwLjMwNDk2ODMsMC4zMDgzMTE3LDAuMzE0MjkxOSwwLjMyMTMxNjksMC4zMjgzNDIzLDAuMzM1MzY2NiwwLjM0MjM4NTYsMC4zNDkzOTgzLDAuMzU2NDA0NSwwLjM2MzQwMzksMC4zNzAzOTYzLDAuMzc3MzgxNCwwLjM4NDM1ODcsMC4zOTEzMjc1LDAuMzk4Mjg2MiwwLjQwNTIzMywwLjQxMjE2NDgsMC40MTkwNzU4LDAuNDI1OTU1NCwwLjQzMjc3NywwLjQzOTYwNSwwLjQ0NjQ5LDAuNDUzNDA5OCwwLjQ2MDI3ODIsMC40NjcxMTksMC40NzQxMzI2LDAuNDgwOTgxMSwwLjQ4NzQzMTMsMC40OTM3MTgsMC40OTk5NzMsMC41MDYyMzEyLDAuNTEyNDU3MywwLjUxNzc1MjcsMC41MjIzMDEyLDAuNTI2NTAwNCwwLjUzMDY2NzQsMC41MzQ5NDA2LDAuNTQwMzI5NCwwLjU0NzMwODIsMC41NTQzMjE2LDAuNTYxMzM3LDAuNTY4MzUzMSwwLjU3NTM3MTUsMC41ODIzOTMyLDAuNTg5NDE4NCwwLjU5NjQ0MDIsMC42MDM0MTgxLDAuNjEwMzA3MiwwLjYxNjk2NywwLjYyMzIxNTQsMC42MjkxNjcxLDAuNjM1MjMxOSwwLjY0MTc5NDcsMC42NDg3NjgxLDAuNjU1MjQ5OSwwLjY1ODgwODcsMC42NjE4Mjg4LDAuNjY2ODQzMywwLjY3MjM4MDksMC42Nzg0NDE0LDAuNjg0NDU1MSwwLjY5MDk5MDIsMC42OTc5MDksMC43MDQ4ODE0LDAuNzExODU2OSwwLjcxODgxNjEsMC43MjU3OTAxLDAuNzMyNzk3MSwwLjczOTgxNjIsMC43NDY3ODcyLDAuNzUyMzc2NCwwLjc1NzM0MDEsMC43NjE5NzM3LDAuNzY2MTAyLDAuNzcwNzI0NiwwLjc3NTA5ODYsMC43Nzk3MDksMC43ODQ1NDA4LDAuNzg5NjEzOSwwLjc5NTE3NDksMC44MDEyNTQ0LDAuODA3NTkzNCwwLjgxNDEyNzIsMC44MjA4ODUyLDAuODI2Njg4MywwLjgyODQ0NjksMC44Mjg3MDI2LDAuODI3MzA2MSwwLjgyNTU5MTYsMC44MjQwMDksMC44MjI3NDY0LDAuODIzMzAzNCwwLjgyODAyMTEsMC44MzM3ODc1LDAuODM5ODEwNCwwLjg0NTkzODEsMC44NTIxMjA4LDAuODU4MzIyMSwwLjg2NDUwMjksMC44NzA2MzUzLDAuODc2Njc1NSwwLjg4MjYyMzIsMC44ODg1Nzk5LDAuODk0Njg0MiwwLjkwMDkxNzcsMC45MDcyNTY2LDAuOTEzNjgyNywwLjkyMDEwNDQsMC45MjYyNjY1LDAuOTMyMTkwOSwwLjkzODIyNzMsMC45NDM1NDAxLDAuOTQ5MzM1MSwwLjk1NTUxMzEsMC45NjIwNDk4LDAuOTY3ODk1NCwwLjk3MTYzMjYsMC45NzU5NTIxLDAuOTgwODEzMiwwLjk4NTc4MTQsMC45OTAzMzM4LDAuOTkzNzQ2OCwwLjk5NzU4NDMsMSwwLjk5NDU5MDcsMC45ODc2NDAyLDAuOTgwNjI0OSwwLjk3MzYyOTcsMC45NjY2NzIzLDAuOTU5NzYyOCwwLjk1Mjg4NzMsMC45NDYwMzEsMC45MzkxODUzLDAuOTMyMzQ1NSwwLjkyNTUwOCwwLjkxODY2MjYsMC45MTE4MDg3LDAuOTA0OTQ3NiwwLjg5ODA3NywwLjg5MTE5MjksMC44ODQzMjc0LDAuODc3NDkyNiwwLjg3MDY4NzksMC44NjM4MDc3LDAuODU2OTA5MSwwLjg1MDE3MTYsMC44NDM0MzE1LDAuODM2NjE3MiwwLjgyOTg1MzUsMC44MjMxNDI5LDAuODE2NDg5NSwwLjgwOTgxNDMsMC44MDMxMjcxLDAuNzk2NDYwMiwwLjc4OTgyNzYsMC43ODMyNjYxLDAuNzc2NzA2MiwwLjc3MDEyMDksMC43NjM1MjM3LDAuNzU2OTM0MywwLjc1MDM2MzcsMC43NDM2MzYyLDAuNzM2NjEwMywwLjcyOTU4NDMsMC43MjI1NTg0LDAuNzE1NTMyMywwLjcwODY3MTMsMC43MDMxMDU5LDAuNjk2NjExNywwLjY5MTE3MDYsMC42ODYxOTc4LDAuNjgxNjE5MSwwLjY3Njc4MTUsMC42NzAxMTU5LDAuNjYzODA2NCwwLjY1NzQ3NTgsMC42NTA3NTMsMC42NDM3NTU0LDAuNjM2NzMxNSwwLjYyOTcwNjQsMC42MjI2ODA2LDAuNjE1NjU0NywwLjYwODYzMDQsMC42MDE2MTAxLDAuNTk0NTk4OSwwLjU4NzYwNDEsMC41ODA2Mzk0LDAuNTczNzIxMSwwLjU2NjgyMTMsMC41NTk5MTY0LDAuNTUzMDA2OSwwLjU0NjA5NTQsMC41MzkxOTUsMC41MzIzMDQ3LDAuNTI1NDM0NCwwLjUxODU1NjksMC41MTE2NjQ4LDAuNTA0NzU0MywwLjQ5Nzg2NSwwLjQ5MTAzMzcsMC40ODQxMzk0LDAuNDc3MTkxNiwwLjQ3MDIzNDcsMC40NjMzMDQxLDAuNDU2NDU1MSwwLjQ0OTU5NjgsMC40NDM0MDA1LDAuNDM4OTUxOSwwLjQzNDA0NzksMC40Mjk0NDg4LDAuNDI1MjY1NywwLjQyMjQyLDAuNDIxMjM2NiwwLjQyMDI5MDgsMC40MTkzOTcxLDAuNDE4NDkyNCwwLjQxNzUzMDcsMC40MTY0OTQyLDAuNDE1MzM3MSwwLjQxMzc4ODMsMC40MTEyMDc3LDAuNDA3MzE5OSksDQogICAgICAgICAgICAgICAgICB5PWMoMC4zMjc4NzkyLDAuMzI0MzI5MSwwLjMyMDU4NDQsMC4zMTY2NTIxLDAuMzEyNDMxNiwwLjMwNzY1MDQsMC4zMDI0MTY4LDAuMjk3MTE1NywwLjI5MTc3MjEsMC4yODYzOTI4LDAuMjgwOTc3NSwwLjI3NTUyMTIsMC4yNzAxMTQ2LDAuMjY0ODU1NywwLjI1OTg2MzcsMC4yNTU0NzgzLDAuMjUyNTExNywwLjI1MDUyODQsMC4yNDkxMjU2LDAuMjQ4MDcwNSwwLjI0NzIyOTQsMC4yNDY0NTk4LDAuMjQ1NjEwNSwwLjI0NDU2NzksMC4yNDMyMDM2LDAuMjQxNzc2OSwwLjI0MDQ5NTUsMC4yMzkzMzMsMC4yMzgxMjk3LDAuMjM2NzIwMywwLjIzNTI5MiwwLjIzMzk5MjYsMC4yMzI1ODI0LDAuMjMwOTY0MSwwLjIyOTAyNjUsMC4yMjcyODk3LDAuMjI1Njk4OCwwLjIyMzk1MTYsMC4yMjIwNjI3LDAuMjIwNDU5LDAuMjE4NDU2NCwwLjIxNjMxNDksMC4yMTQyODM4LDAuMjEyMDY2MiwwLjIwOTUxMTMsMC4yMDY5ODAzLDAuMjA0NjYyNywwLjIwMjY1NzcsMC4yMDEwMjY4LDAuMTk5NzIyNSwwLjE5ODMyMzEsMC4xOTY2MzY3LDAuMTk0NjMwOSwwLjE5MjE4MjMsMC4xODk0ODE5LDAuMTg3NDUwNywwLjE4NTYwNjMsMC4xODM0NDQ2LDAuMTgxMzU0OSwwLjE3OTU1NzYsMC4xNzc1NDkyLDAuMTc1MjEwNCwwLjE3MjQzLDAuMTY4Nzk1MSwwLjE2Mjc4MzEsMC4xNTgyNzU1LDAuMTU1MjE0NiwwLjE1MzAzNzgsMC4xNTA3MTQ3LDAuMTQ4MDcyMSwwLjE0NTUwOCwwLjE0MzE3MiwwLjE0MTEwMTgsMC4xMzkyMjA2LDAuMTM3MDk0MywwLjEzNjQ5NDUsMC4xMzYyMTAzLDAuMTMwNDAwNiwwLjEyNzI0NDcsMC4xMjYwNzYyLDAuMTI1MDIwNCwwLjEyMzk3MDYsMC4xMjI4ODQzLDAuMTIxNzY4MiwwLjEyMDYyNjEsMC4xMTk0NTc4LDAuMTE4MjYwMSwwLjExNzAyNDksMC4xMTU3MjkzLDAuMTE0Mzg3OSwwLjExMzY0NzMsMC4xMTM1MjExLDAuMTEzMjUzOSwwLjExMTc1NTcsMC4xMTA2NzQ4LDAuMTEwMTc1MiwwLjEwOTM1ODMsMC4xMDc2NjM4LDAuMTA1MTAzMywwLjEwMTk5MjUsMC4wOTczNTk1NywwLjA5MDk0ODY5LDAuMDg0NDQ1OTcsMC4wNzc5OTU3NSwwLjA3MTU3NTk2LDAuMDY1MTg0OTYsMC4wNTg4MzM4NiwwLjA1MjUxMzAxLDAuMDQ2MDg1NDgsMC4wMzk5MDA5MSwwLjAzMzgyMjY3LDAuMDI3NzI5NDksMC4wMjE2MDUzMywwLjAxNTQ2NTE1LDAuMDA5NTkzNzE1LDAuMDA0OTQ5ODU2LDAuMDAwOTQ2NDgxNCwwLDAuMDA2OTc1MTI0LDAuMDEzOTkyOTEsMC4wMjEwMTMxNiwwLjAyODAzMjcsMC4wMzUwNDk2MywwLjA0MjA2MDYzLDAuMDQ5MDUzMTksMC4wNTU5MDE4MiwwLjA2MjY3OTkyLDAuMDY5NjAwOSwwLjA3NjU5LDAuMDgyNjQ3ODEsMC4wODU3NzA2OSwwLjA4NTY1MDk1LDAuMDg1NTc5NiwwLjA4NTcyNTA0LDAuMDg2MDMzNDcsMC4wODY0NjMwMiwwLjA4Njk4OTkxLDAuMDg3NjAwNjcsMC4wODgyODU5MiwwLjA4OTA0MTg5LDAuMDg5ODY3MTIsMC4wOTA3NjE2NiwwLjA5MTczMTIzLDAuMDkyNzgyNTUsMC4wOTM5Mjg0NiwwLjA5NTE5MzI2LDAuMDk2NjE5NDksMC4wOTgyOTgyNywwLjA5OTk1MjExLDAuMTAxMzUwOSwwLjEwMjU2NjUsMC4xMDQwNDEyLDAuMTA1NTgxOCwwLjEwNTMzMjEsMC4xMDM4NTEsMC4xMDEwNzQxLDAuMDk3OTM3MzksMC4wOTQ3Mzc0LDAuMDkxNTQzNzgsMC4wOTE2NjA0MiwwLjA5NjI0ODM2LDAuMTAxNjAwMywwLjEwNzIzMjUsMC4xMTI4ODkzLDAuMTE4NDY1OSwwLjEyMjYxMjgsMC4xMjMzODE4LDAuMTIzODAwMSwwLjEyNDE4NTUsMC4xMjQ1NTgzLDAuMTI0ODgyOSwwLjEyNTEyNTQsMC4xMjUyMTYsMC4xMjUwMDc5LDAuMTI0MjE2OCwwLjEyMjg0NzYsMC4xMjA2MzMsMC4xMTc0MzA2LDAuMTEzNjk4NCwwLjExMDE1OTcsMC4xMDc2OTI5LDAuMTA3MTQ4OCwwLjEwOTQyMSwwLjExNTQ0OTUsMC4xMjE2NDIyLDAuMTI2NTU1NywwLjEzMDg3NDQsMC4xMzQ0MTY4LDAuMTM4MDQzNSwwLjE0MDUzMTQsMC4xNDE3NDE2LDAuMTQyNjA2LDAuMTQzNDQ1NSwwLjE0NDQxMDIsMC4xNDUyNDU2LDAuMTQ1NzU4OCwwLjE0NjA2MjcsMC4xNDU1NjY1LDAuMTQxMzg0NywwLjEzNjQxMzgsMC4xMzExMzQ1LDAuMTI1NDUyOSwwLjEyMDE2NzMsMC4xMTQ2Njk0LDAuMTA5MzY4NywwLjEwNDI2ODMsMC4wOTk0MDkzMSwwLjA5NTEyNzY5LDAuMDkxNjExMjEsMC4wODg1ODQ0OCwwLjA4NjAwNTQ4LDAuMDg0MTA4NTgsMC4wODY0MTk1NCwwLjA5MzE5OTA3LDAuMTAwMTk4NCwwLjEwNzA4MDUsMC4xMTM4OTQxLDAuMTIwNzM5MSwwLjEyNzY0ODksMC4xMzQ1MzUzLDAuMTM5Njc0OSwwLjE0MzY4MzQsMC4xNDczMDA1LDAuMTUwNzM3LDAuMTU0MDc0NSwwLjE1NzM3NzIsMC4xNjA3MTc4LDAuMTY0MTQ2OSwwLjE2NzczNTEsMC4xNzE0NzU0LDAuMTc1MjAwMywwLjE3ODY3NzksMC4xODE5MTg3LDAuMTg0OTQ4MywwLjE4Nzc4ODYsMC4xOTA2MzU3LDAuMTk0MDAyNSwwLjE5Nzc3NTgsMC4yMDEzNjQsMC4yMDU5MzkyLDAuMjA1MTE0LDAuMjAxNzY4NSwwLjE5OTI3MDcsMC4yMDIzNDI1LDAuMjA4Mjg2MywwLjIxMzgxNDMsMC4yMTg4ODYyLDAuMjIzODUzOSwwLjIyOTE5NDUsMC4yMzUzMjk4LDAuMjQxMjA0OCwwLjI0NzE2NzIsMC4yNTE0NjQ1LDAuMjUyMjM3NywwLjI1MTg3NDQsMC4yNTEyMjIsMC4yNTAyNDgsMC4yNDg5NzY0LDAuMjQ3NTMwOSwwLjI0NTk5NiwwLjI0NDQxNDIsMC4yNDI4MDc4LDAuMjQxMTkxNywwLjIzOTYwOTgsMC4yMzgwNjM4LDAuMjM2NTUwNiwwLjIzNTA4MSwwLjIzMzY3NzIsMC4yMzIxODQ5LDAuMjMwNTU3MywwLjIyODgxMTYsMC4yMjczOTA3LDAuMjI2MDY0OCwwLjIyNDEwODgsMC4yMjIxMzIyLDAuMjIwNDIxMiwwLjIxODUyMDMsMC4yMTY0NDAxLDAuMjE0MTgyNywwLjIxMTk5MDYsMC4yMDk4MzUxLDAuMjA3NjE4MiwwLjIwNTMwMDMsMC4yMDI3OTAxLDAuMjAwMjc0MSwwLjE5NzgyNTQsMC4xOTU0MDgsMC4xOTI5NzAzLDAuMTkwNDgyMiwwLjE4ODkyMzQsMC4xODg4OTg5LDAuMTg4ODc0NCwwLjE4ODg2ODEsMC4xODg4NjgxLDAuMTg5MjU3MiwwLjE5MzQyNDgsMC4xOTYwNzUxLDAuMjAwNTAxOCwwLjIwNTQ2MzUsMC4yMTA3ODgsMC4yMTUyODM2LDAuMjEzMjU2NiwwLjIxMDE2NzEsMC4yMDcxMjI1LDAuMjA1MTQ4MSwwLjIwNDU2NTYsMC4yMDQzOTY4LDAuMjA0MjkzMiwwLjIwNDI0OTYsMC4yMDQyOSwwLjIwNDQzNjYsMC4yMDQ3MTY3LDAuMjA1MTY1NywwLjIwNTgyNTksMC4yMDY3NDY1LDAuMjA3OTY5OCwwLjIwOTI5NDksMC4yMTA1OTQsMC4yMTE4Njc3LDAuMjEzMTI5NywwLjIxNDQ1MzMsMC4yMTU4MjcyLDAuMjE3Mjk3MSwwLjIxODczMywwLjIyMDA5NzgsMC4yMjEzNjY1LDAuMjIyNzQ0NCwwLjIyNDM4MjIsMC4yMjU3MjU0LDAuMjI2NzY5NywwLjIyNzc1MzIsMC4yMjg5MDI3LDAuMjMwNDU2NiwwLjIzMTk2MzUsMC4yMzQ0NTczLDAuMjM5ODc3NywwLjI0NDkwOCwwLjI1MDIxODEsMC4yNTU4NiwwLjI2MjIyMTIsMC4yNjkxNDUsMC4yNzYxMDcsMC4yODMwNzU5LDAuMjkwMDQzMiwwLjI5NzAwMzMsMC4zMDM5NTIzLDAuMzEwODgyLDAuMzE3NzI5NiwwLjMyNDI2MDksMC4zMjk4ODQ5KSkNCmBgYA0KDQojIE1ldGhvZHMNCg0KQ29tcGFyYXRpdmUgZGF0YSBpbiB0aGVzZSBhbmFseXNlcyB3ZXJlIGRyYXduIGZyb20gYSBsYXJnZSBzYW1wbGUgb2YgZXh0YW50IGZpc2hlcyBjb21pbmcgZnJvbSBhIHdpZGUgdmFyaWV0eSBvZiBzb3VyY2VzLCBpbmNsdWRpbmcgZmx1aWQtcHJlc2VydmVkIHNwZWNpbWVucyBkaXJlY3RseSBtZWFzdXJlZCBmcm9tIHRoZSBjb2xsZWN0aW9ucyBvZiB0aGUgQ2xldmVsYW5kIE11c2V1bSBvZiBOYXR1cmFsIEhpc3RvcnkgKCoqQ01OSCoqKSwgRmxvcmlkYSBGaXNoIGFuZCBXaWxkbGlmZSBSZXNlYXJjaCBJbnN0aXR1dGUgKCoqRlNCQyoqKSwgYW5kIHRoZSBPaGlvIFN0YXRlIFVuaXZlcnNpdHkgTXVzZXVtIG9mIEJpb2RpdmVyc2l0eSAoKipPU1VNKiopLiBPdGhlciBkYXRhIHdlcmUgY29sbGVjdGVkIGZyb20gdGhlIHByZXZpb3VzbHkgcHVibGlzaGVkIGxpdGVyYXR1cmUsIGVpdGhlciBhcyByZXBvcnRlZCB2YWx1ZXMgb3IgbWVhc3VyZWQgZnJvbSBwaG90b2dyYXBocyBwdWJsaXNoZWQgaW4gdGhvc2Ugc3R1ZGllcy4gU2ltaWxhcmx5LCBmb3IgZXh0aW5jdCBhcnRocm9kaXJlcyBhIGNvbWJpbmF0aW9uIG9mIGRpcmVjdGx5IG9ic2VydmVkIHNwZWNpbWVucyBhbmQgdGhlIHByZXZpb3VzbHkgcHVibGlzaGVkIGxpdGVyYXR1cmUgd2FzIHVzZWQuDQoNClNwZWNpZmljIGF0dGVudGlvbiBpcyBicm91Z2h0IHRvIHRoZSB3b3JrIG9mIFJhbmRhbGwgKDE5OTcpLCB3aG8gbWFkZSBoaXMgcGhvdG9ncmFwaGljIGNvbGxlY3Rpb24gb2YgbmVhcmx5IDEwLDAwMCBmaXNoZXMgd2l0aCBhc3NvY2lhdGVkIGxlbmd0aCAoaHR0cDovL3d3dy5maXNoYmFzZS5vcmcvc2VhcmNoLnBocCkuIE5vdCBhbGwgMTAsMDAwKyBmaXNoZXMgaW4gUmFuZGFsbCAoMTk5Nykgd2VyZSBhYmxlIHRvIGJlIG1lYXN1cmVkIGR1ZSB0byB0aW1lIGNvbnN0cmFpbnRzLCBidXQgYW4gYXR0ZW1wdCB3YXMgbWFkZSB0byBpbmNsdWRlLi4uDQoNCjEuIEEgcmVwcmVzZW50YXRpdmUgY29sbGVjdGlvbiBvZiBmaXNoIGRpdmVyc2l0eQ0KMi4gQXMgbWFueSBsYXJnZS1ib2RpZWQgZmlzaCBzcGVjaWVzIGFzIHBvc3NpYmxlIChhcyBtZWFzdXJlbWVudHMgZm9yIHRoZXNlIHRheGEgdGVuZCB0byBiZSByYXJlKQ0KMy4gQXMgbWFueSBiYXNhbCBmaXNoIGxpbmVhZ2VzIGFzIHBvc3NpYmxlIHdpdGhpbiB0aGlzIHNhbXBsZSAoZS5nLiwgY2hvbmRyaWNodGh5YW5zLCBtZWdhbG9waWRzLCBjbHVwZWlkcywgZXRjLiksIGJlY2F1c2UgdGhvc2UgdGF4YSBhcmUgbGlrZWx5IHRvIGJldHRlciBjb21wYXJlIHdpdGggYXJ0aHJvZGlyZXMgdGhhbiBzcGVjaWFsaXplZCBhY2FudGhvcHRlcnlnaWFucw0KDQpgYGB7cn0NCmRhdGFfcmVjb24gJT4lDQogIGZpbHRlcihsZW5ndGhfYXM9PSJ0b3RhbCBsZW5ndGgiKSAlPiUNCiAgbXV0YXRlKHJlZmVyZW5jZV8yID0gZmFjdG9yKGNhc2Vfd2hlbihSZWZlcmVuY2UgPT0gIlByZXNlbnQgU3R1ZHkiIH4gIkZpcnN0LWhhbmQgb2JzZXJ2YXRpb24iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFJlZmVyZW5jZSAlaW4lIGMoIlJhbmRhbGwgMTk5NyIsIlJhbmRhbGwgMTk5NywgTWloYWxpdHNpcyBhbmQgQmVsbHdvb2QgMjAxOSIpIH4gIlJhbmRhbGwgMTk5NyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLmRlZmF1bHQgPSAiT3RoZXIgcHJpb3IgbGl0ZXJhdHVyZSBzb3VyY2VzIChyZXBvcnRlZCBvciBtZWFzdXJlZCBmcm9tIGZpZ3VyZXMpIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcmRlcmVkPVQsbGV2ZWxzPWMoIkZpcnN0LWhhbmQgb2JzZXJ2YXRpb24iLCJSYW5kYWxsIDE5OTciLCJPdGhlciBwcmlvciBsaXRlcmF0dXJlIHNvdXJjZXMgKHJlcG9ydGVkIG9yIG1lYXN1cmVkIGZyb20gZmlndXJlcykiKSkpICU+JQ0KICBncm91cF9ieShyZWZlcmVuY2VfMikgJT4lDQogIHN1bW1hcmlzZShOPW4oKSkgJT4lDQogIGthYmxlKGNhcHRpb249IlNvdXJjZXMgb2YgZGF0YSB1c2VkIGluIHRoaXMgYW5hbHlzaXMiLGNvbC5uYW1lcyA9IGMoIlNvdXJjZSIsIk4iKSkgJT4lIA0KICBrYWJsZV9zdHlsaW5nKCkNCmBgYA0KDQpUaGlzIHJlc3VsdHMgaW4gYSB0b3RhbCBvZiBuZWFybHkgMjUwMCBkaXN0aW5jdCBvYnNlcnZhdGlvbnMgcmVwcmVzZW50aW5nIDg4OCBmaXNoIHRheGEuIFRoZSB0ZXJtICJvYnNlcnZhdGlvbnMiIGlzIHByZWZlcnJlZCBvdmVyIHNwZWNpbWVucyBoZXJlIGFzIHNvbWUgc3R1ZGllcyByZXBvcnQgbWVhc3VyZW1lbnRzIG9mIHRoZWlyIG1hdGVyaWFsIGFzIG1lYW4gcHJvcG9ydGlvbiB2YWx1ZXMgKCUgdG90YWwgbGVuZ3RoIG9yIHN0YW5kYXJkIGxlbmd0aCkgb2YgdGhlIGVudGlyZSBzYW1wbGUsIGFzIGlzIG9mdGVuIHRoZSBjYXNlIGluIHN0dWRpZXMgb2YgbW9kZXJuIGZpc2hlcy4gSG93ZXZlciwgYmVjYXVzZSB0aGVzZSB2YWx1ZXMgYXJlIHJlcG9ydGVkIGFzIHByb3BvcnRpb25zIG9mIHRvdGFsIGxlbmd0aCwgcmF0aGVyIHRoYW4gbWVhc3VyZW1lbnRzLCB0aGV5IGNhbiBzdGlsbCBiZSBjb252ZXJ0ZWQgdG8gYSBmb3JtIHdoZXJlIHRoZXkgY2FuIGJlIGNvbXBhcmVkIHdpdGggb3RoZXIgZmlzaGVzLg0KDQpgYGB7cn0NCmRhdGFfcmVjb24gJT4lDQogIGdyb3VwX2J5KHRheG9uKSAlPiUNCiAgc3VtbWFyaXNlKG49bigpKSAlPiUNCiAgdW5ncm91cCgpICU+JQ0KICBzdW1tYXJpc2UodGF4b249c3VtKCFpcy5uYSh0YXhvbikpLG49c3VtKG4pKSAlPiUNCiAga2FibGUoY2FwdGlvbj0iVG90YWwgY291bnQgb2Ygb2JzZXJ2YXRpb25zIGV4YW1pbmVkIiwNCiAgICAgICAgY29sLm5hbWVzPWMoIlRheGEiLCJPYnNlcnZhdGlvbnMiKSxhbGlnbj0iYyIpICU+JQ0KICBrYWJsZV9zdHlsaW5nKCkNCmBgYA0KDQpNb3N0IG9mIHRoaXMgZGF0YSB3YXMgY29sbGVjdGVkIGFsb25nc2lkZSBhIHByZXZpb3VzIHN0dWR5IGJ5IHRoZSBhdXRob3IgKEVuZ2VsbWFuIDIwMjMpLCBhbmQgdGhlIHJlYWRlciBpcyBlbmNvdXJhZ2VkIHRvIGNoZWNrIHRoZSBtZXRob2RzIG9mIHRoYXQgcGFwZXIgZm9yIG1vcmUgZGV0YWlscy4gRm9yIG1vcmUgZGV0YWlscyBvbiBob3cgdGhlIG1lYXN1cmVtZW50cyB3ZXJlIGNvbGxlY3RlZCwgc2VlIEVuZ2VsbWFuICgyMDIzKS4gRmlndXJlIDQgb2YgdGhhdCBzdHVkeSBpbiBwYXJ0aWN1bGFyIHByb3ZpZGVzIGEgZ3JhcGhpYyBzaG93aW5nIGhvdyBzZXZlcmFsIG1lYXN1cmVtZW50cyB3ZXJlIGNvbGxlY3RlZCBbTWV0aG9kcyBvZiBtZWFzdXJpbmcgb2YgU1ZMIHJlcXVpcmUgYWRkaXRpb25hbCBjbGFyaWZpY2F0aW9uIGFuZCBhcmUgZGlzY3Vzc2VkIGluIHRoZSBzZWN0aW9uICJNZWFzdXJpbmcgU1ZMIl0oI21lYXN1cmluZ1NWTCkuDQoNCkFsbCBtZWFzdXJlbWVudHMgdGFrZW4gYnkgdGhlIGF1dGhvciAoaW5jbHVkaW5nIHRob3NlIG1lYXN1cmVkIGZyb20gdGhlIGZpZ3VyZXMgaW4gUmFuZGFsbCAxOTk3KSB3ZXJlIG1lYXN1cmVkIHJlbGF0aXZlIHRvIHRoZSBhbnRlcm9wb3N0ZXJpb3IgYXhpcyBvZiB0aGUgYW5pbWFsIChzZWUgRW5nZWxtYW4gMjAyMzogZmlnLiA0KSwgcmF0aGVyIHRoYW4gcG9pbnQgdG8gcG9pbnQgb3Igb3ZlciBib2R5IGN1cnZhdHVyZS4gSG93ZXZlciwgaXQgaXMgcG9zc2libGUgc29tZSByZXBvcnRlZCBtZWFzdXJlbWVudHMgaW4gdGhlIGxpdGVyYXR1cmUgbWF5IGJlIGRpc3RvcnRlZCBpZiB0aGV5IHdlcmUgdGFrZW4gcG9pbnQgdG8gcG9pbnQgb3IgbWVhc3VyZWQgb3ZlciBjdXJ2ZXMuIFJlcG9ydGluZyBob3cgbWVhc3VyZW1lbnRzIGFyZSB0YWtlbiBpcyB0eXBpY2FsbHkgbm90IGRvbmUgaW4gaWNodGh5b2xvZ2ljYWwgc3R1ZGllcy4gVGhpcyBwb3NzaWJsZSBiaWFzIGlzIHdvcnRoIG5vdGluZyBidXQgY2Fubm90IGJlIGNvbnRyb2xsZWQgZm9yIGluIHRoZSBjdXJyZW50IGRhdGFzZXQsIHRob3VnaCBpdHMgZWZmZWN0cyBzZWVtIHRvIGJlIG1pbm9yLg0KDQpTZXZlcmFsIGZpZ3VyZXMgaW4gdGhlc2Ugc3VwcGxlbWVudGFyeSBhbmFseXNlcyB1c2UgYSBzaWxob3VldHRlIG9mICpSaGl6b3ByaW9ub2RvbiB0ZXJyYWVub3ZhZSogY3JlYXRlZCBieSBOYXRoYW4gSGVybWFubiB0aHJvdWdoIFBoeWxvUGljIChodHRwczovL3d3dy5waHlsb3BpYy5vcmcvaW1hZ2VzL2FmYTZiZjg2LWJmZDEtNDBhMy1hNzhiLWE0M2UzOTZkNzdhYS9yaGl6b3ByaW9ub2Rvbi10ZXJyYWVub3ZhZSkuICpSLiB0ZXJyYWVub3ZhZSogd2FzIGNob3NlbiBhcyBhIHJlcHJlc2VudGF0aXZlIGZpc2ggYmVjYXVzZSAqUmhpem9wcmlvbm9kb24qIHdhcyBjbG9zZXN0IHRvIHRoZSBtZWFuIHJlbGF0aXZlIHByZXBlY3RvcmFsIGxlbmd0aCwgcHJlcGVsdmljIGxlbmd0aCwgYW5kIHNub3V0LXZlbnQgbGVuZ3RoIG9mIHRoZSBlbnRpcmUgbm9uLWFjYW50aG9wdGVyeWdpYW4gc2FtcGxlLg0KDQpNZWFzdXJlbWVudCB8IFZhcmlhYmxlIE5hbWUgfCBEZWZpbml0aW9uDQotLS0tLS0tLS0tLSB8IC0tLS0tLS0tLS0tLS0gfCAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQpUb3RhbCBsZW5ndGggfCB0b3RhbF9sZW5ndGggfCBBbnRlcm9wb3N0ZXJpb3IgbGVuZ3RoIGZyb20gYW50ZXJpb3IgdGlwIG9mIHJvc3RydW0gdG8gcG9zdGVyaW9yIHRpcCBvZiBjYXVkYWwgZmluIGluIG5hdHVyYWwgcG9zaXRpb24gKHdoZW4gcG9zc2libGUpDQpGb3JrIGxlbmd0aCB8IGZvcmtfbGVuZ3RoIHwgTGVuZ3RoIGZyb20gYW50ZXJpb3IgdGlwIG9mIHJvc3RydW0gdG8gbm90Y2ggaW4gY2F1ZGFsIGZvcmsgYmV0d2VlbiB1cHBlciBhbmQgbG93ZXIgY2F1ZGFsIGZpbiBsb2Jlcy4gUmVjb3JkZWQgYXMgYE5BYCBmb3IgdGF4YSB3aXRob3V0IGEgY2F1ZGFsIG5vdGNoLg0KU3RhbmRhcmQgbGVuZ3RoIHwgcHJlY2F1ZGFsX2xlbmd0aCB8IExlbmd0aCBmcm9tIGFudGVyaW9yIHRpcCBvZiByb3N0cnVtIHRvIHBvc3RlcmlvciB0aXAgb2YgY2F1ZGFsIHBlZHVuY2xlIDxicj4gKipGb3Igc2hhcmtzIGFuZCBhcnRocm9kaXJlczoqKiB0byBjYXVkYWwgcGVkdW5jbGUgPGJyPiAqKkZvciBvc3RlaWNodGh5YW5zKiogdG8gZW5kIG9mIGh5cHVyYWxzICh3aGljaCBzb21ldGltZXMgZXh0ZW5kIGJleW9uZCBjYXVkYWwgcGVkdW5jbGUpDQpIZWFkIGxlbmd0aCB8IGhlYWRfbGVuZ3RoIHwgTGVuZ3RoIGZyb20gYW50ZXJpb3IgdGlwIG9mIHJvc3RydW0gdG8gcG9zdGVyaW9yIG1hcmdpbiBvZiBicmFuY2hpYWwgY2F2aXR5LiBIZWFkIGxlbmd0aCBhbmQgaW50ZXJuYWwgYW5hdG9teSBhcmUgaG9tb2xvZ291cyBhbW9uZyB0aGUgZ3JvdXBzIGV4YW1pbmVkIGR1ZSB0byB0aGUgY29uc2VydmVkIHBvc2l0aW9uIG9mIHRoZSBuZXVyb2NyYW5pdW0gYW5kIGJyYW5jaGlhbCBhcmNoZXMgKHNlZSBtYW51c2NyaXB0KSBidXQgdGhlIGRlZmluaXRpb24gb2YgZXh0ZXJuYWwgbGFuZG1hcmtzIGNhbiB2YXJ5IHNsaWdodGx5IGlmIGEgY2hlZWsgcGxhdGUgb3Igb3BlcmN1bHVtIGNvdmVycyB0aGUgZ2lsbCBhcmNoZXMgZXh0ZXJuYWxseS4gPGJyPiAqKkZvciBzaGFya3M6KiogZnJvbSBzbm91dCB0byBvcGVuaW5nIG9mIHRlcm1pbmFsIGdpbGwgYXJjaCA8YnI+ICoqRm9yIG9zdGVpY2h0aHlhbnM6KiogZnJvbSBzbm91dCB0byBwb3N0ZXJpb3IgZW5kIG9mIG9wZXJjdWx1bSA8YnI+ICoqRm9yIGFydGhyb2RpcmVzOioqIGZyb20gc25vdXQgdG8gY3JhbmlvLXRob3JhY2ljIGpvaW50IDxicj4NCk9yYml0LW9wZXJjdWxhciBMZW5ndGggfCBvb2wgfCBMZW5ndGggb2YgdGhlIGhlYWQgbWludXMgcHJlb3JiaXRhbCBsZW5ndGgNCkJvZHkgZGVwdGggfCBib2R5X2RlcHRoIHwgTWF4aW11bSBoZWlnaHQgb2YgdHJ1bmsNCkZpbmVuZXNzIHJhdGlvICgqZiopfCBmaW5lbmVzcyB8IFN0YW5kYXJkIGxlbmd0aCBkaXZpZGVkIGJ5IGJvZHkgZGVwdGgNClByZXBlY3RvcmFsIGxlbmd0aCB8cHJlcGVjdG9yYWxfbGVuZ3RofCBEaXN0YW5jZSBmcm9tIHRoZSB0aXAgb2YgdGhlIHNub3V0IHRvIHRoZSBvcmlnaW4gb2YgdGhlIHBlbHZpYyBmaW5zIHBhcmFsbGVsIHRvIHRoZSB0aGUgYW50ZXJvcG9zdGVyaW9yIGF4aXMNClBlY3RvcmFsIGZpbiBiYXNlIGxlbmd0aCB8cGVjX2Jhc2V8IEFudGVyb3Bvc3RlcmlvciBsZW5ndGggb2YgcGVjdG9yYWwgZmluIGJhc2UgPGJyPiAqKkZvciBzaGFya3M6KiogbGVuZ3RoIG9mIGZsZXNoeSBwZWN0b3JhbCBmaW4gYmFzZSBvbiBsaXZpbmcgYW5pbWFsIDxicj4gICoqRm9yIGFydGhyb2RpcmVzOioqIExlbmd0aCBvZiBwZWN0b3JhbCBmZW5lc3RyYSBvbiBhbnRlcmlvciB2ZW50cmFsIGxhdGVyYWwgcGxhdGUgb3IgZXh0ZXJuYWwgZmFjZSBvZiBzY2FwdWxvY29yYWNvaWQgKGlmIHByZXNlcnZlZCk8YnI+ICAqKkZvciBvc3RlaWNodGh5YW5zOioqIG5vdCBjb25zaWRlcmVkIGR1ZSB0byBkaWZmZXJlbmNlcyBpbiBmaW4gcG9zaXRpb24gKHVzdWFsbHkgb2JsaXF1ZWx5IG9yaWVudGVkIHRvIGFudGVyb3Bvc3RlcmlvciBheGlzKSwgc3RydWN0dXJlIChtdWNoIG5hcnJvd2VyIGJhc2UpLCBhbmQgZnVuY3Rpb24gKG9zY2lsbGF0aW9uIHJhdGhlciB0aGFuIGZpeGVkIGZpbnMgaW4gbW9zdCB0YXhhKQ0KUHJlcGVsdmljIGxlbmd0aHxwcmVwZWx2aWNfbGVuZ3RofCBEaXN0YW5jZSBmcm9tIHRoZSB0aXAgb2YgdGhlIHNub3V0IHRvIHRoZSBvcmlnaW4gb2YgdGhlIHBlbHZpYyBmaW5zIHBhcmFsbGVsIHRvIHRoZSB0aGUgYW50ZXJvcG9zdGVyaW9yIGF4aXMNClNub3V0LXZlbnQgbGVuZ3RoIChTVkwpfFNWTHwgRGlzdGFuY2UgZnJvbSB0aGUgdGlwIG9mIHRoZSBzbm91dCB0byB0aGUgbGV2ZWwgb2YgdGhlIHZlbnQgcGFyYWxsZWwgdG8gdGhlIGFudGVyb3Bvc3RlcmlvciBheGlzDQpQcmVhbmFsIChmaW4pIGxlbmd0aHxwcmVhbmFsX2xlbmd0aHwgRGlzdGFuY2UgZnJvbSB0aGUgdGlwIG9mIHRoZSBzbm91dCB0byB0aGUgYW5hbCBmaW4gb3JpZ2luIHBhcmFsbGVsIHRvIHRoZSBhbnRlcm9wb3N0ZXJpb3IgYXhpcy4gTm90YWJseSAqKipub3QqKiogbGVuZ3RoIHRvIHRoZSB2ZW50Lg0KQ2F1ZGFsIHBlZHVuY2xlIGhlaWdodHxwZWR1bmNsZV9oZWlnaHR8TWluaW11bSBoZWlnaHQgb2YgY2F1ZGFsIHBlZHVuY2xlDQoNCkluIGFkZGl0aW9uIHRvIHRoZSB2YXJpb3VzIGV4dGFudCBmaXNoZXMgY29uc2lkZXJlZCBpbiB0aGlzIHN0dWR5LCByZXByZXNlbnRhdGl2ZXMgb2YgOCBzcGVjaWVzIG9mIHRoZSBleHRpbmN0IGZpc2ggb3JkZXIgSWNodGh5b2RlY3RpZm9ybWVzIHdlcmUgaW5jbHVkZWQgaW4gdGhpcyBhbmFseXNpcy4gSWNodGh5b2RlY3RpZm9ybXMgd2VyZSBjb25zaWRlcmVkIGJlY2F1c2UgdGhleSBoYXZlIGh5cGVyLWVsb25nYXRlZCBib2RpZXMgd2l0aCBzbWFsbCBoZWFkcyByZWxhdGl2ZSB0byB0aGVpciB0cnVua3MsIHJlcHJlc2VudGluZyBzb21lIG9mIHRoZSBtb3N0IGV4dHJlbWUgaGVhZC1ib2R5IHByb3BvcnRpb25zIHNlZW4gYW1vbmcgYW55IGxpdmluZyBvciBleHRpbmN0IG5vbi1hbmd1aWxsaWZvcm0gZmlzaC4gT3RoZXIgZXh0aW5jdCBlbG9uZ2F0ZS1ib2RpZWQgZmlzaCBncm91cHMgKGUuZy4sIHNhdXJpY2h0aHlpZHMpIGRvIG5vdCBzaG93IHRoZXNlIGtpbmRzIG9mIHByb3BvcnRpb25zIChlLmcuLCBLb2dhbiBldCBhbC4gMjAxNSkuIEljaHRoeW9kZWN0aWZvcm1zIHdlcmUgYWxzbyBzaW5nbGVkIG91dCBiZWNhdXNlIGZvbGxvd2luZyB0aGUgY29uY2x1c2lvbiBvZiBFbmdlbG1hbiAoMjAyMykgc29tZSBoYXZlIHRyaWVkIHRvIG1haW50YWluIGxhcmdlciBib2R5IHNpemUgZXN0aW1hdGVzIGZvciAqRHVua2xlb3N0ZXVzIHRlcnJlbGxpKiBieSBwcm9wb3NpbmcgaXQgbWF5IGhhdmUgaGFkICpYaXBoYWN0aW51cyotbGlrZSBoZWFkLWJvZHkgcHJvcG9ydGlvbnMgKHBlcnMuIGNvbW1zLiB0byBSLiBFbmdlbG1hbikuIFRodXMsIEljaHRoeW9kZWN0aWZvcm1zIHJlcHJlc2VudCBhIHVzZWZ1bCB0ZXN0IHRvIHNlZSBob3cgY29uc2lzdGVudCB0aGUgcHJvcG9ydGlvbnMgdW5kZXIgZXhhbWluYXRpb24gYXJlIGFjcm9zcyBmaXNoZXMuDQoNCiMjIE1lYXN1cmluZyBTVkwgeyNtZWFzdXJpbmdTVkx9DQoNCkRhdGEgaW4gdGhpcyBzdXBwbGVtZW50YXJ5IGluZm9ybWF0aW9uIHdhcyBjb2xsZWN0ZWQgZnJvbSB0aGUgbGl0ZXJhdHVyZSBhbmQgcHJlc2VydmVkIHNwZWNpbWVucyB3aGVuIG1lYXN1cmluZyBkYXRhIGZvciBwcmlvciBzdHVkaWVzIChFbmdlbG1hbiAyMDIzKS4gQW5hdG9taWNhbCBvYnNlcnZhdGlvbnMgcmVnYXJkaW5nIHZlbnQgcG9zaXRpb24gd2VyZSBtYWRlIGZyb20gZGlyZWN0IG9ic2VydmF0aW9uIG9mIHRoZXNlIHNwZWNpbWVucy4NCg0KU1ZMIHdhcyBtZWFzdXJlZCBhcyB0aGUgZGlzdGFuY2UgZnJvbSB0aGUgdGlwIG9mIHRoZSBzbm91dCB0byB0aGUgbGV2ZWwgb2YgdGhlIHZlbnQgYWxvbmcgdGhlIGFudGVyb3Bvc3RlcmlvciBheGlzIG9mIHRoZSBib2R5LiBJbiBtYW55IHBob3RvZ3JhcGhzIChlLmcuLCB0aG9zZSBvZiBSYW5kYWxsIDE5OTcpLCB0aGUgdmVudCBjYW4gYmUgcmVhZGlseSBpZGVudGlmaWVkIGluIGxhdGVyYWwgdmlldyBieSBhIGRpc3RpbmN0IG5vdGNoIG9yIHB1Y2tlcmluZyBvbiB0aGUgdmVudHJhbCBtYXJnaW4gb2YgdGhlIGFuaW1hbC4gSW4gY2FzZXMgd2hlcmUgdGhlIHZlbnQgY291bGQgbm90IGJlIG5vdCBjbGVhcmx5IGlkZW50aWZpZWQgU1ZMIHdhcyBub3QgcmVjb3JkZWQuDQoNClNWTCBjb3VsZCBvbmx5IGJlIG1lYXN1cmVkIG9wcG9ydHVuaXN0aWNhbGx5IGluIGZpc2hlcy4gSW4gc3BlY2ltZW5zIG1lYXN1cmVkIGRpcmVjdGx5LCB0aGUgb3JpZ2luYWwgZ29hbCB3YXMgdG8gY29sbGVjdCBtZWFzdXJlbWVudHMgb2YgdGhlIG1vdXRoIGFuZCBoZWFkLCBhbmQgU1ZMIG9ubHkgYmVnYW4gdG8gYmUgY29sbGVjdGVkIGxhdGUgaW4gdGhlIGFuYWx5c2lzLCByZXN1bHRpbmcgaW4gbWFueSBmaXNoZXMgbGFja2luZyBTVkwgZGF0YS4gUGhvdG9zIHdlcmUgdGFrZW4gaW4gbGF0ZXJhbCB2aWV3LCBidXQgaW4gbWFueSBjYXNlcyB0aGUgdmVudCBjYW5ub3QgYmUgbG9jYXRlZCBvbiB0aGVzZSBwaG90b3MuDQoNClNWTCBpcyByYXJlbHkgcmVwb3J0ZWQgZm9yIGZpc2hlcyBpbiB0aGUgbGl0ZXJhdHVyZS4gUHJlLWFuYWwgbGVuZ3RoIGlzIG9mdGVuIHJlcG9ydGVkLCB3aXRoIHRoZSBpbXBsaWNhdGlvbiB0aGF0IGFuYWwgZmluIHBvc2l0aW9uIHJlZmxlY3RzIGNsb2FjYSBwb3NpdGlvbi4gVGhpcyBkb2VzIGFwcGVhciB0byBiZSB0aGUgY2FzZSBmb3IgbW9zdCBhY3Rpbm9wdGVyeWdpYW5zLCB3aGVyZSB0aGUgdmVudCBpcyBpbW1lZGlhdGVseSBhbnRlcmlvciB0byB0aGUgYW5hbCBmaW4gb3JpZ2luLCBidXQgdGhlIHBvc2l0aW9uIG9mIHRoZSBwZWx2aWMgYW5kIGFuYWwgZmlucyByZWxhdGl2ZSB0byB0aGUgdmVudCBjYW4gdmFyeS4gSW4gc29tZSB0YXhhIChlLmcuLCBDYXJhbmdpZGFlLCBHb2JpaWRhZSkgdGhlcmUgaXMgYSBkaXN0aW5jdCBnYXAgYmV0d2VlbiB0aGUgdmVudCBhbmQgdGhlIGFuYWwgZmluIG9yaWdpbiwgYW5kIGluIG90aGVycyAoU2lsdXJpZm9ybWVzLCAqQW1pYSopIHRoZSB2ZW50IGlzIGhhbGZ3YXkgYmV0d2VlbiB0aGUgcGVsdmljIGFuZCBhbmFsIGZpbnMuIFRvIG1ha2UgY29tcGFyaXNvbnMgbW9yZSByaWdvcm91cywgb25seSBtZWFzdXJhYmxlIFNWTCB3YXMgdXNlZCByYXRoZXIgdGhhbiB0cmVhdGluZyBwcmUtYW5hbCBmaW4gbGVuZ3RoIGluIGFjdGlub3B0ZXJ5Z2lhbnMgYXMgU1ZMLg0KDQpBbGwgU1ZMIGRhdGEgYXJlIHJlcG9ydGVkIGFzIHNwZWNpZXMgYXZlcmFnZXMgdG8gYWxsb3cgZm9yIGEgbW9yZSBldmVuIHJlcHJlc2VudGF0aW9uIG9mIHRheGEgcmVsYXRpdmUgdG8gc2FtcGxlIHNpemUuIFRoZSBzYW1lIGlzIHRydWUgZm9yIHByZXBlY3RvcmFsIGxlbmd0aCBhbmQgcHJlcGVsdmljIGxlbmd0aCB1bmxlc3Mgbm90ZWQuDQoNCiMjIFZlbnQgcG9zaXRpb24gaW4gYXJ0aHJvZGlyZXMgeyNWZW50cG9zaXRpb259DQoNClRoZSBsb2NhdGlvbiBvZiB0aGUgY2xvYWNhIGluIGFydGhyb2RpcmVzIGNhbiBiZSBkZXRlcm1pbmVkIGJhc2VkIG9uIHByZXNlcnZlZCB2aXNjZXJhbCBvcmdhbnMgaW4gc2V2ZXJhbCBHb2dvIHRheGEgKFRyaW5hanN0aWMgZXQgYWwuIDIwMjIpLiBBZGRpdGlvbmFsbHksIHRoZSBwb3NpdGlvbiBvZiB0aGUgY2xvYWNhIGNhbiBiZSBmdXJ0aGVyIGNvbnN0cmFpbmVkIGJhc2VkIG9uIG90aGVyIGZlYXR1cmVzIGxpa2UgdGhlIHBvc2l0aW9uIG9mIHRoZSBjbGFzcGVycyAod2hpY2ggaGF2ZSB0byBiZSBuZWFyIHRoZSB2ZW50IHRvIGZ1bmN0aW9uIGFzIGludHJvbWl0dGFudCBvcmdhbnMsIGFzIGluIGNob25kcmljaHRoeWFucyksIHBvc3RlcmlvciBleHRlbnQgb2YgdGhlIHZlbnRyYWwgc2hpZWxkLCBhbmQgdGhlIGVubGFyZ2VtZW50IG9mIHRoZSBoYWVtYWwgYXJjaGVzIGRlbm90aW5nIHRoZSBwb3N0ZXJpb3IgYm91bmRhcnkgb2YgdGhlIHZpc2NlcmFsIGNhdml0eSAoYXMgaW4gb3RoZXIgZmlzaGVzKSAoRGVhbiAxODk2LCBNaWxlcyBhbmQgV2VzdG9sbCAxOTY4LCBBaGxiZXJnIGV0IGFsLiAyMDA5LCBUcmluYWpzdGljIGV0IGFsLiAyMDE1LCBUcmluYWpzdGljIGV0IGFsLiAyMDIyLCBFbmdlbG1hbiAyMDIzKS4NCg0KVmVudCBwb3NpdGlvbiBjb3VsZCBiZSBjb25maWRlbnRseSBkZXRlcm1pbmVkIGluIHR3byBuZWFyLWNvbXBsZXRlIGFydGhyb2RpcmUgdGF4YTogKkNvY2Nvc3RldXMgY3VzcGlkYXR1cyogYW5kICpJbmNpc29zY3V0dW0gcml0Y2hlaSouIEluICpDb2Njb3N0ZXVzIGN1c3BpZGF0dXMqIChST00gVlAgNTI2NjQpLCB0aGUgdmVudCBpcyBlc3RpbWF0ZWQgdG8gYmUgbG9jYXRlZCBhdCA0OC4zJSB0b3RhbCBsZW5ndGggYmFzZWQgb24gdGhlIHBvc2l0aW9uIG9mIHRoZSBjbGFzcGVycy4gRm9yIFJPTSBWUCA1MjY2NCwgdGhlcmUgYXJlIGEgcGFpciBvZiBlbGVtZW50cyBhdCB0aGUgcG9zdGVyaW9yIGVuZCBvZiB0aGUgdmVudHJhbCBzaGllbGQgdGhhdCBsb29rIGxpa2UgaWxpYWMgcHJvY2Vzc2VzIGJ1dCBvdGhlciBjb2xsZWFndWVzIGhhdmUgc3VnZ2VzdGVkIGluIGNvbnZlcnNhdGlvbiB0aGV5IG1heSBhY3R1YWxseSBiZSBjbGFzcGVycyAoUy4gdmFuIE1lc2RhZywgcGVycy4gY29tbS4gT2N0b2JlciAyMDIzKS4gVGhlIGF1dGhvciBpcyBub3QgY29tcGxldGVseSBzdXJlIGlmIHRoZXNlIGVsZW1lbnRzIHRydWx5IGFyZSBjbGFzcGVycyAoYXMgY2xhc3BlciBlbGVtZW50cyB2ZXJzdXMgaXNvbGF0ZWQgaWxpYWMgcHJvY2Vzc2VzIGNhbiBiZSB2ZXJ5IGhhcmQgdG8gaWRlbnRpZnkgaW4gYXJ0aHJvZGlyZXM7IFMuIHZhbiBNZXNkYWcsIHBlcnMuIGNvbW0uIE9jdG9iZXIgMjAyMyksIGJ1dCBpdCB3YXMgZGVjaWRlZCB0byB1c2UgdGhlIHByb3BvcnRpb24gaW4gUk9NIFZQIDUyNjY0IGFzIGFuIGFwcHJveGltYXRlIGVzdGltYXRlZCBTVkwgYmVjYXVzZSBvdGhlciBzcGVjaW1lbnMgb2YgY29jY29zdGVpZCBhcnRocm9kaXJlcyBzaG93IGRlZmluaXRlIGNsYXNwZXJzIGxvY2F0ZWQgYXQgYXBwcm94aW1hdGVseSB0aGlzIHBvc2l0aW9uIChUcmluYWpzdGljIGV0IGFsLiAyMDE1KS4gVGh1cywgZXZlbiBpZiB0aGVzZSBhcmUgcGVsdmljIHJlbWFpbnMsIHRoZSBsZW5ndGggdG8gdGhlc2UgZWxlbWVudHMgYXBwcm94aW1hdGVzIFNWTC4NCg0KRm9yICpJbmNpc29zY3V0dW0gcml0Y2hlaSosIHZlbnQgcG9zaXRpb24gd2FzIGJhc2VkIG9uIHRoZSByZWNvbnN0cnVjdGlvbiBpbiBUcmluYWpzdGljIGV0IGFsLiAoMjAxMyksIGFzIGRldGVybWluZWQgYnkgdGhlIHByZXNlbmNlIG9mIGNsYXNwZXJzIGFuZCBsb2NhdGlvbiBvZiB0aGUgcHJlc2VydmVkIGNsb2FjYSBpbiBzb21lIHNwZWNpbWVucyAoVHJpbmFqc3RpYyBldCBhbC4gMjAyMikuIFRvdGFsIGxlbmd0aCB3YXMgZXN0aW1hdGVkIGZyb20gcHJlY2F1ZGFsL3RvdGFsIGxlbmd0aCBpbiAqQ29jY29zdGV1cyogYXMgZGVzY3JpYmVkIGJlbG93LiBUaGlzIHJlc3VsdHMgaW4gYW4gU1ZMIDQ2LjItNTAuNSUgdG90YWwgbGVuZ3RoLCB3aXRoIG1vc3Qgc3BlY2ltZW5zIG9mICpDLiBjdXNwaWRhdHVzKiBzdWdnZXN0aW5nIGhpZ2hlciB2YWx1ZXMgKFNWTCA9IDQ5LjYlIHRvdGFsIGxlbmd0aCkuIElmIGEgZ3JlYXRlciBjYXVkYWwgZmluIGxlbmd0aCBsZW5ndGggc2ltaWxhciB0byBNaWxlcyBhbmQgV2VzdG9sbCAoMTk2OCkncyByZWNvbnN0cnVjdGlvbiBpcyB1c2VkIHJlc3VsdGluZyB0b3RhbCBsZW5ndGggaXMgMjcuMiBjbSBhbmQgdGhlIFNWTCBpcyA0Ni4yJSBvZiB0b3RhbCBib2R5IGxlbmd0aCwgc3VnZ2VzdGluZyBpbnRlcnByZXRhdGlvbnMgb2YgY2F1ZGFsIGZpbiBzaXplIGhhdmUgbGl0dGxlIGVmZmVjdCBvbiB0aGUgcmVzdWx0aW5nIHByb3BvcnRpb24uDQoNClZlbnQgcG9zaXRpb24gaW4gdHdvIG90aGVyIHNwZWNpbWVucywgb25lIG9mICpEaWNrb3N0ZXVzIHRocmVpcGxhbmRpKiAoTkhNVUsgUFYgUCA0OTY2MykgYW5kIG9uZSBvZiAqQW1hemljaHRoeXMgdHJpbmFqc3RpY2FlKiAoQUEuTUVNLkRTLjgpIHdlcmUgYWxzbyBjb25zaWRlcmVkLiBIb3dldmVyLCB0aGUgZm9ybWVyIGlzIGEgaGlnaGx5IGRpc3RvcnRlZCBzcGVjaW1lbiB3aGVyZSB0aGUgYXJtb3IgaXMgImV4cGxvZGVkIiBhbmQgc29tZSBvZiB0aGUgdGFpbCBtYXkgYmUgbWlzc2luZywgYW5kIGluIHRoZSBsYXR0ZXIgdmVudCBwb3NpdGlvbiB3YXMgbWVyZWx5IGluZmVycmVkIGFzc3VtaW5nIGl0IHdhcyBsb2NhdGVkIGp1c3QgcG9zdGVyaW9yIHRvIHRoZSBwZWx2aXMgYXMgaW4gKkNvY2Nvc3RldXMqIGFuZCAqSW5jaXNvc2N1dHVtKi4gVmVudCBwb3NpdGlvbiBpbiB0aGVzZSB0YXhhIGFyZSBjb25zaWRlcmVkIG11Y2ggbGVzcyByaWdvcm91cywgdGhvdWdoIGFyZSBkaXNjdXNzZWQganVzdCB0byBleGFtaW5lIHBvc3NpYmxlIHZhcmlhdGlvbiB3aXRoaW4gZXVicmFjaHl0aG9yYWNpZCBhcnRocm9kaXJlcy4NCg0KIyMgRGF0YSBmb3IgYXJ0aHJvZGlyZXMNCg0KIyMgVG90YWwgbGVuZ3RocyBhbmQgYm9keSBtYXNzZXMgZm9yIGFydGhyb2RpcmVzIGluIHBlY3RvcmFsIGZpbiBhbmFseXNpcw0KDQpJbiBhZGRpdGlvbiB0byB0YXhhIGZvciB3aGljaCBsZW5ndGggY291bGQgYmUgbWVhc3VyZWQgZGlyZWN0bHkgKCpBbWF6aWNodGh5cyosICpDb2Njb3N0ZXVzKiksIHNldmVyYWwgYXJ0aHJvZGlyZXMgaGFkIHByb3BvcnRpb25zIGNhbGN1bGF0ZWQgcmVsYXRpdmUgdG8gZXN0aW1hdGVkIHRvdGFsIGxlbmd0aC4gQXMgbWVudGlvbmVkIGFib3ZlIHRoZSBsZW5ndGggb2YgKkluY2lzb3NjdXR1bSogd2FzIGNhbGN1bGF0ZWQgZnJvbSBUcmluYWpzdGljIGV0IGFsLiAoMjAxMyksIHdpdGggY2F1ZGFsIGZpbiBsZW5ndGggYXBwcm94aW1hdGVkIGJhc2VkIG9uICpDb2Njb3N0ZXVzKi4gTGVuZ3RocyBmb3IgKkR1bmtsZW9zdGV1cyogYW5kIG90aGVyIGFydGhyb2RpcmVzIGZvciB3aGljaCBjb21wbGV0ZSBib2R5IG91dGxpbmVzIGFyZSB1bmtub3duIHdlcmUgdGFrZW4gZnJvbSB0aGUgYmVzdC1maXR0aW5nIG1vZGVsIGluIEVuZ2VsbWFuIDIwMjMgKHRoZSBvbmUgdXNpbmcgaW5kaXZpZHVhbCBzcGVjaW1lbnMsIGFsbG93aW5nIGFsbG9tZXRyaWMgc2xvcGVzIHRvIHZhcnkgYmV0d2VlbiBjaG9uZHJpY2h0aHlhbnMgYW5kIG5vbi1jaG9uZHJpY2h0aHlhbnMsIGFuZCBjb25zaWRlcmluZyBib2R5IHNoYXBlIGFuZCBtZW1iZXJzaGlwIGluIHRoZSBvdXRsaWVyIGNsYWRlcyBTZXJyYW5pZGFlIG9yIEhvbG9jZW50cmlkYWUgYXMgYWRkaXRpb25hbCB2YXJpYWJsZXMsIHNlZSB0aGF0IHN0dWR5IGZvciBtb3JlIGRldGFpbHMpLiBGb3IgYXJ0aHJvZGlyZXMsIHRoaXMgZXF1YXRpb24gdGFrZXMgdGhlIGZvcm0uLi4NCg0KJCQNClxtYm94e3RvdGFsIGxlbmd0aH0gPSAxLjAxNSpleHAoMC45OTMyNzEqbG4oXG1ib3h7b3JiaXQtb3BlcmN1bGFyIGxlbmd0aH0pKzEuODgxOTI1KQ0KJCQNCg0KQm9keSBtYXNzZXMgZm9yIGFydGhyb2RpcmVzIHdlcmUgY2FsY3VsYXRlZCB1c2luZyB0aGUgZWxsaXBzb2lkIG1ldGhvZCBvZiBBdWx0IGFuZCBMdW8gKDIwMTMpIGFzIG1vZGlmaWVkIGJ5IGFuZCBkZXRhaWxlZCBpbiBFbmdlbG1hbiAoMjAyMykuIEJvZHkgbWFzc2VzIGZvciAqRHVua2xlb3N0ZXVzIHRlcnJlbGxpKiB0YWtlbiBkaXJlY3RseSBmcm9tIHRoYXQgc3R1ZHkuIEp1dmVuaWxlIHNwZWNpbWVucyBvZiAqRHVua2xlb3N0ZXVzKiBmb3Igd2hpY2ggYm9keSBkZXB0aCBhbmQgYm9keSB3aWR0aCB3ZXJlIG5vdCBhdmFpbGFibGUgaGFkIHRoZWlyIG1hc3MgY2FsY3VsYXRlZCB1c2luZyB0aGUgYXhpcyBhdmFpbGFibGUgYW5kIGFzc3VtaW5nIGEgc3ViLWNpcmN1bGFyIGNyb3NzLXNlY3Rpb24sIGdpdmVuIENNTkggNzQyNCBhbmQgQ01OSCA2MTk0IHNob3cgc3ViLWNpcmN1bGFyIGNyb3NzLXNlY3Rpb25zIGFuZCBDTU5IIDg5ODIgYW5kIENNQyBWUCA4Mjk0IGhhdmUgY3J1c2hlZCB0cnVuayBhcm1vcnMgc3VnZ2VzdGluZyBzdWItY2lyY3VsYXIgcHJvcG9ydGlvbnMuIEZvciBDTU5IIDU3NjgsIGJvZHkgbWFzcyB3YXMgcmVjYWxjdWxhdGVkIGdpdmVuIHRoZSBuYXJyb3dlciBib2R5IGRlcHRoIGZvciB0aGlzIHNwZWNpbWVuIGRldGVybWluZWQgaW4gdGhpcyBzdHVkeSAoMTAwIGNtIHZlcnN1cyAxMTQgY20pLiBUaGlzIHNwZWNpbWVuIGlzIHByb2JhYmx5IHRvbyB3aWRlIGFzIG1vdW50ZWQsIGFuZCBpdCBpcyBwb3NzaWJsZSB0aGUgbWFzcyBmb3IgdGhpcyBzcGVjaW1lbiB3b3VsZCBiZSBldmVuIGxvd2VyLCBhcm91bmQgNzYwLTc5NSBrZywgaWYgYSBjcm9zcy1zZWN0aW9uYWwgc2hhcGUgc2ltaWxhciB0byBDTU5IIDYwOTAgYW5kIENNTkggNzA1NCBpcyBhc3N1bWVkIChpbiB3aGljaCB0aGUgY3Jvc3Mtc2VjdGlvbmFsIHNoYXBlIG9mIHRoZSBhcm1vciBpcyBiZXR0ZXIgcHJlc2VydmVkIGFuZCBib2R5IHdpZHRoIGlzIH44MCUgYm9keSBkZXB0aCkuIEhvd2V2ZXIsIGJlY2F1c2UgdGhlc2UgdmFsdWVzIGFyZSB3aXRoaW4gdGhlIHJhbmdlIG9mIGVycm9yIGNhbGN1bGF0ZWQgaGVyZSAoNTM4LTE3MTQga2cpLCB0aGlzIHN1Z2dlc3RzIHRoZSB1c2Ugb2YgdGhlc2UgbWFzcyBlc3RpbWF0ZXMgYXJlIHJlYXNvbmFibGUgZm9yIG5vdyBhbmQgZG8gbm90IGludmFsaWRhdGUgdGhlIGNvbmNsdXNpb25zIHByZXNlbnRlZCBoZXJlLg0KDQpFcnJvciBiYXJzIGZvciBsZW5ndGggdXNlICsvLSBwZXJjZW50IGVycm9yIHVubGVzcyBvdGhlcndpc2Ugbm90ZWQsIGR1ZSB0byBsb2ctdHJhbnNmb3JtYXRpb24gcmVzdWx0aW5nIGluIGxlcHRva3VydGljYWxseSBkaXN0cmlidXRlZCBkZXRyYW5zZm9ybWVkIHJlc2lkdWFscyBhbmQgdGh1cyBleGFnZ2VyYXRlZCBhbmQgdW5yZWFsaXN0aWNhbGx5IHdpZGUgY29uZmlkZW5jZSBpbnRlcnZhbHMgcmVsYXRpdmUgdG8gdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgZGF0YSAoc2VlIEVuZ2VsbWFuIDIwMjMgZm9yIG1vcmUgZGV0YWlscykuDQoNCkZvciAqQ29jY29zdGV1cyBjdXNwaWRhdHVzKiBhbmQgKkluY2lzb3NjdXR1bSByaXRjaGVpKiBib2R5IG1hc3NlcyB3ZXJlIHJlY2FsY3VsYXRlZCBnaXZlbiB0aGUgcmVjb25zdHJ1Y3Rpb24gaW4gTWlsZXMgYW5kIFdlc3RvbGwgKDE5NjgpIHdhcyBzbGlnaHRseSB0b28gbG9uZyBpbiBpdHMgYWJkb21lbiBhbmQgY2F1ZGFsIGZpbiBhbmQgaGFkIGFuIHVubmF0dXJhbGx5IGNvbXByZXNzZWQgdHJ1bmsgYXJtb3IgY29tcGFyZWQgdG8gY29tcGxldGUgZm9zc2lscy4NCg0KVGhlIHdlaWdodCBvZiAqSW5jaXNvc2N1dHVtIHJpdGNoZWkqIHdhcyBlc3RpbWF0ZWQgdXNpbmcgdGhlIHByb3BvcnRpb25zIGluIFRyaW5hanN0aWMgZXQgYWwuIDIwMTMsIGFzIGluIEVuZ2VsbWFuIDIwMjMsIGJ1dCBhIHNob3J0ZXIgdG90YWwgbGVuZ3RoIHdhcyB1c2VkIGZvbGxvd2luZyB0aGUgcmVhc29uaW5nIGluIFsiVmVudCBwb3NpdGlvbiBpbiBhcnRocm9kaXJlcyJdKCNWZW50cG9zaXRpb24pLg0KDQpGb3IgKkNvY2Nvc3RldXMgY3VzcGlkYXR1cyogKHNlZSBtYW51c2NyaXB0KSwgYm9keSBtYXNzIHdhcyBlc3RpbWF0ZWQgdXNpbmcgdGhlIHJlY29uc3RydWN0aW9uIG9mICpDb2Njb3N0ZXVzIGN1c3BpZGF0dXMqIGluIHRoaXMgc3R1ZHkgKEZpZ3VyZSA3IGluIG1haW4gdGV4dCkuIFRoaXMgcmVjb25zdHJ1Y3Rpb24gd2FzIHdhcyBhZGp1c3RlZCBmcm9tIE1pbGVzIGFuZCBXZXN0b2xsICgxOTY4KSBmb2xsb3dpbmcgdGhlIHByb3BvcnRpb25zIG9mIFJPTSBWUCA1MjY2NC4gRm9yIGdpcnRoLCBib2R5IGhlaWdodCB3YXMgbWVhc3VyZWQgYW5kIGl0IHdhcyBhc3N1bWVkIHRoZSBwcm9wb3J0aW9ucyBvZiB0aGUgdHJ1bmsgYXJtb3IgZm9sbG93ZWQgdGhlIHByb3BvcnRpb25zIGluIE1pbGVzIGFuZCBXZXN0b2xsICgxOTY4OiBmaWcuIDQ0KS4gVGhpcyBtaWdodCBwcm9kdWNlIGEgc2xpZ2h0IG92ZXJlc3RpbWF0ZSBvZiB3ZWlnaHQsIGJlY2F1c2Ugc2hlYXJpbmcgdGhlIGFybW9yIG1pZ2h0IG1ha2UgaXQgc2xpZ2h0bHkgZGVlcGVyIHRoYW4gaW4gTWlsZXMgYW5kIFdlc3RvbGwgKDE5NjgpLCBhbmQgdGh1cyBvdmVyZXN0aW1hdGUgdHJ1bmsgd2lkdGguIEhvd2V2ZXIsIHRoZSByZXN1bHRpbmcgd2VpZ2h0IGRpZmZlcnMgb25seSBzbGlnaHRseSBmcm9tIHRoZSBib2R5IG1hc3Mgb2YgNTUwIGcgZXN0aW1hdGVkIGluIEVuZ2VsbWFuICgyMDIzKSB1c2luZyB0aGUgcmVjb25zdHJ1Y3Rpb24gaW4gTWlsZXMgYW5kIFdlc3RvbGwgKDE5NjgpLCBhbmQgbWlnaHQgYmUgZXhwZWN0ZWQgYmVjYXVzZSBvZiB0aGUgc2xpZ2h0bHkgc3RvY2tpZXIgYm9keSBpbiB0aGlzIHJlY29uc3RydWN0aW9uLg0KDQojIyBBZGp1c3RtZW50cw0KDQpGb3IgZXh0aW5jdCB0YXhhIGtub3duIGZyb20gZnJhZ21lbnRhcnkgcmVtYWlucywgb2NjYXNpb25hbGx5IGFkanVzdG1lbnRzIGhhZCB0byBiZSBtYWRlIGluIG9yZGVyIHRvIHVzZSBkYXRhIGZyb20gY3J1c2hlZCBvciBmcmFnbWVudGFyeSBzcGVjaW1lbnMuIFRoaXMgaXMgcGFydGljdWxhcmx5IHRoZSBjYXNlIHdpdGggb2J0YWluaW5nIGVub3VnaCBpbmZvcm1hdGlvbiB0byBwcm9kdWNlIGEgcmVsaWFibGUgZXN0aW1hdGUgb2YgYm9keSBtYXNzLCB3aGljaCByZXF1aXJlcyBhIHZhbHVlIGZvciBib2R5IGdpcnRoLiBUaGVzZSBkZWNpc2lvbnMgYXJlIHN0YXRlZCBoZXJlIGZvciB0cmFuc3BhcmVuY3kgYW5kIHJlcGxpY2FiaWxpdHkuDQoNCiogKioqSW5jaXNvc2N1dHVtIHJpdGNoZWkqKiogLSBUaGUgY2F1ZGFsIGZpbiBpcyB1bmtub3duIGZvciAqSW5jaXNvc2N1dHVtKiwgZGVzcGl0ZSB0aGUgcHJlY2F1ZGFsIGFuYXRvbXkgYmVpbmcgd2VsbCBrbm93bi4gQ2F1ZGFsIGZpbiBzaXplIHdhcyBwcmV2aW91c2x5IGVzdGltYXRlZCBpbiBFbmdlbG1hbiAoMjAyMykgYmFzZWQgdGhlIHByb3BvcnRpb24gb2YgcHJlY2F1ZGFsIHRvIHRvdGFsIGxlbmd0aCBpbiBNaWxlcyBhbmQgV2VzdG9sbCAoMTk2OCkncyAqQ29jY29zdGV1cyogcmVjb25zdHJ1Y3Rpb24uIEhvd2V2ZXIsIGV4YW1pbmF0aW9uIG9mIG1vcmUgY29tcGxldGUgc3BlY2ltZW5zIG9mICpDb2Njb3N0ZXVzKiBzdWdnZXN0cyB0aGlzIGVzdGltYXRlIGlzIG92ZXJseSBnZW5lcm91cyBkdWUgdG8gdGhlIHVudXN1YWxseSBsYXJnZSBmaW4gaW4gdGhhdCByZWNvbnN0cnVjdGlvbi4gQ2F1ZGFsIGZpbiBzaXplIGhlcmUgd2FzIGVzdGltYXRlZCBiYXNlZCBvbiBmaXZlIG5lYXItY29tcGxldGUgc3BlY2ltZW5zIG9mICpDLiBjdXNwaWRhdHVzKiAodG90YWwgbGVuZ3RoIH4gMS4yMyB4IHByZWNhdWRhbCBsZW5ndGgsIHNlZSBBcHBlbmRpeCA4LCB0aGlzIHBhcGVyKSwgd2hpY2ggcHJvZHVjZSB0b3RhbCBsZW5ndGhzIG9mIDI1IHRvIDI3IGNtIGZvciAqSW5jaXNvc2N1dHVtKi4NCiogKipXQU0gNzAuNC44NjQqKiAoKkVhc3RtYW5vc3RldXMgY2FsbGlhc3BpcyopIC0gQW55IG1lYXN1cmVtZW50cyB0YWtlbiBmcm9tIHRoZSByZWNvbnN0cnVjdGlvbiBpbiBEZW5uaXMtQnJ5YW50ICgxOTg3OiBmaWcuIDUpIHdlcmUgc2NhbGVkIHRvIG1hdGNoIHRoZSByZXBvcnRlZCBkaW1lbnNpb25zIG9mIHRoZSBzcGVjaW1lbiB1c2luZyBoZWFkIHNoaWVsZCBsZW5ndGggKDEzLjM3IGNtKS4gVGhlIHJlY29uc3RydWN0aW9uIGluIERlbm5pcy1CcnlhbnQgKDE5ODcpIGlzIHNsaWdodGx5IGxhcmdlciB0aGFuIHRoZSByZXBvcnRlZCBtZWFzdXJlbWVudHMgb2YgdGhlIGhvbG90eXBlLCBkZXNwaXRlIGJlaW5nIG1vc3RseSBiYXNlZCBvbiB0aGlzIHNwZWNpbWVuLiBUaGUgb3JpZ2luYWwgbWF0ZXJpYWwgY291bGQgbm90IGJlIGV4YW1pbmVkIGRpcmVjdGx5IGZvciBtZWFzdXJlbWVudC4NCiogKipDTU5IIDYxOTQqKiAoKkR1bmtsZW9zdGV1cyB0ZXJyZWxsaSopIC0gQm9keSBtYXNzIHdhcyBjYWxjdWxhdGVkIGFzc3VtaW5nIGEgc3ViY2lyY3VsYXIgY3Jvc3Mtc2VjdGlvbiB3aXRoIGJvZHkgd2lkdGggYXBwcm94aW1hdGUgZXF1YWwgdG8gYm9keSBkZXB0aCAofjM2LjUgY20pIERpcmVjdCBvYnNlcnZhdGlvbiBvZiB0aGlzIG1vdW50IHNob3dzIGl0IGhhZCBhIHN1YmNpcmN1bGFyIGNyb3NzLXNlY3Rpb24sIGJ1dCBleGFjdCBkaW1lbnNpb25zIGNvdWxkIG5vdCBiZSBtZWFzdXJlZCBkdWUgdG8gaW5hY2Nlc3NpYmlsaXR5IG9mIHRoZSBzcGVjaW1lbiBkdXJpbmcgdGhlIDIwMjItMjAyNCByZW5vdmF0aW9ucyBvZiB0aGUgQ2xldmVsYW5kIE11c2V1bSBvZiBOYXR1cmFsIEhpc3RvcnkuDQoqICoqQ01OSCA4OTgyKiogKCpEdW5rbGVvc3RldXMgdGVycmVsbGkqKSAtIEJvZHkgbWFzcyB3YXMgZXN0aW1hdGVkIGFzc3VtaW5nIGEgc3ViY2lyY3VsYXIgY3Jvc3Mtc2VjdGlvbiB3aXRoIGJvZHkgd2lkdGggYXBwcm94aW1hdGVseSBlcXVhbCB0byBlc3RpbWF0ZWQgYm9keSBkZXB0aCAofjMzIGNtKSwgZ2l2ZW4gb3RoZXIgKkQuIHRlcnJlbGxpKiBzcGVjaW1lbnMgb2Ygc2ltaWxhciBzaXplIChDTU5IIDYxOTQsIENNTkggNzQyNCkgaGF2ZSBzdWJjaXJjdWxhciBjcm9zcy1zZWN0aW9ucw0KKiAqKkNNQyBWUDgyOTQqKiAoKkR1bmtsZW9zdGV1cyB0ZXJyZWxsaSopIC0gQm9keSBtYXNzIHdhcyBlc3RpbWF0ZWQgYXNzdW1pbmcgYSBzdWJjaXJjdWxhciBjcm9zcy1zZWN0aW9uIHdpdGggYm9keSB3aWR0aCBhcHByb3hpbWF0ZWx5IGVxdWFsIHRvIGVzdGltYXRlZCBib2R5IGRlcHRoICh+MzMgY20pLCBnaXZlbiBvdGhlciAqRC4gdGVycmVsbGkqIHNwZWNpbWVucyBvZiBzaW1pbGFyIHNpemUgKENNTkggNjE5NCwgQ01OSCA3NDI0KSBoYXZlIHN1YmNpcmN1bGFyIGNyb3NzLXNlY3Rpb25zDQoqICoqKkFtYXppY2h0aHlzIHRyaW5hanN0aWNhZSoqKiAtIFBlY3RvcmFsIGZpbiBiYXNlIGxlbmd0aCBpbiB0aGUgaG9sb3R5cGUgKEFBLk1FTS5EUy44KSB3YXMgcmVzdG9yZWQgYWZ0ZXIgUElNVVogQS9JIDQ3NzMuIEFBLk1FTS5EUy44IG9ubHkgcHJlc2VydmVzIGEgZnJhZ21lbnQgb2YgdGhlIHNjYXB1bG9jb3JhY29pZCwgYnV0IFBJTVVaIEEvSSA0NzczIHByZXNlcnZlcyB0aGUgZW50aXJlIGVsZW1lbnQsIGFuZCB0aGUgdHdvIHNwZWNpbWVucyBhcmUgc2ltaWxhciBpbiBzaXplIChKb2JiaW5zIGV0IGFsLiAyMDIyKS4gQm9keSBtYXNzIGluIHRoaXMgdGF4b24gd2FzIGVzdGltYXRlZCBhc3N1bWluZyBhIGNyb3NzLXNlY3Rpb25hbCBsZW5ndGgvZGVwdGggcmF0aW8gb2YgMS4yLCBzaW1pbGFyIHRvIG90aGVyIHBlbGFnaWMgcGFjaHlvc3Rlb21vcnBocyAoc2VlIEVuZ2VsbWFuIDIwMjMpLg0KDQojIERhdGEgZGlzdHJpYnV0aW9uDQoNCkZvciB0aGlzIHNlY3Rpb24gIm1lYW4gdmFsdWUiIG1lYW5zIHRoZSBtZWFuIHZhbHVlIGFzIGEgcHJvcG9ydGlvbiBvZiB0b3RhbCBsZW5ndGgsIGZvciBlYXNpZXIgY29tcGFyaXNvbiBiZXR3ZWVuIHRheGEvc3BlY2ltZW5zIG9mIGRpZmZlcmVudCBzaXplcy4NCg0KIyMgQnkgaGlnaGVyLWxldmVsIGNsYWRlDQoNCmBgYHtyfQ0Kb2JzX2J5X2NsYWRlPC1kYXRhX3JlY29uICU+JQ0KICBtdXRhdGUocGVjX2Jhc2UyPXBlY19iYXNlL3RvdGFsX2xlbmd0aCwNCiAgICAgICAgIHBwbD1wcmVwZWN0b3JhbF9sZW5ndGgvdG90YWxfbGVuZ3RoLA0KICAgICAgICAgU1ZMMj1TVkwvdG90YWxfbGVuZ3RoLA0KICAgICAgICAgcHZsPXByZXBlbHZpY19sZW5ndGgvdG90YWxfbGVuZ3RoLA0KICAgICAgICAgY2xhZGU9aWZlbHNlKGhpZ2hlcl9ncm91cD09IkFjYW50aG9wdGVyeWdpaSIsIkFjYW50aG9wdGVyeWdpaSIsY2xhZGUpLA0KICAgICAgICAgY2xhZGU9aWZlbHNlKGNsYWRlPT0iQWN0aW5vcHRlcnlnaWkiLCJOb24tQWNhbnRob3B0ZXJ5Z2lhbiBBY3Rpbm9wdGVyeWdpaSIsY2xhZGUpLA0KICAgICAgICAgY2xhZGU9ZmFjdG9yKGNsYWRlLG9yZGVyZWQ9VCxsZXZlbHM9YygiQWNhbnRob3B0ZXJ5Z2lpIiwiTm9uLUFjYW50aG9wdGVyeWdpYW4gQWN0aW5vcHRlcnlnaWkiLCJTYXJjb3B0ZXJ5Z2lpIiwiQ2hvbmRyaWNodGh5ZXMiLCJQbGFjb2Rlcm1pIikpKSAlPiUNCiAgZ3JvdXBfYnkodGF4b24pICU+JQ0KICBzdW1tYXJpc2UocGVjX2Jhc2U9bWVhbihwZWNfYmFzZTIsbmEucm09VCksDQogICAgICAgICAgICBuX3BlYz1zdW0oIWlzLm5hKHBlY19iYXNlMikpLA0KICAgICAgICAgICAgbl9wcGw9c3VtKCFpcy5uYShwcGwpKSwNCiAgICAgICAgICAgIG5fc3ZsPXN1bSghaXMubmEoU1ZMMikpLA0KICAgICAgICAgICAgbl9wdmw9c3VtKCFpcy5uYShwdmwpKSwNCiAgICAgICAgICAgIHBwbD1tZWFuKHBwbCxuYS5ybT1UKSwNCiAgICAgICAgICAgIFNWTD1tZWFuKFNWTDIsbmEucm09VCksDQogICAgICAgICAgICBwdmw9bWVhbihwdmwsbmEucm09VCksDQogICAgICAgICAgICBvcmRlcj11bmlxdWUob3JkZXIpLGNsYWRlPXVuaXF1ZShjbGFkZSkpICU+JQ0KICBncm91cF9ieShjbGFkZSkgJT4lDQogIHN1bW1hcmlzZShjbGFkZT11bmlxdWUoY2xhZGUpLA0KICAgICAgICAgICAgbnNwZWNfcGVjPXN1bSghaXMubmEocGVjX2Jhc2UpKSwNCiAgICAgICAgICAgIG5fcGVjPXN1bShuX3BlYyksDQogICAgICAgICAgICBuc3BlY19wcGw9c3VtKCFpcy5uYShwcGwpKSwNCiAgICAgICAgICAgIG5fcHBsPXN1bShuX3BwbCksDQogICAgICAgICAgICBuc3BlY19TVkw9c3VtKCFpcy5uYShTVkwpKSwNCiAgICAgICAgICAgIG5fU1ZMPXN1bShuX3N2bCksDQogICAgICAgICAgICBuc3BlY19wdmw9c3VtKCFpcy5uYShwdmwpKSwNCiAgICAgICAgICAgIG5fcHZsPXN1bShuX3B2bCksDQogICAgICAgICAgICBwcGw9bWVhbihwcGwsbmEucm09VCksDQogICAgICAgICAgICBTVkw9bWVhbihTVkwsbmEucm09VCksDQogICAgICAgICAgICBwdmw9bWVhbihwdmwsbmEucm09VCkpICU+JQ0KICBzZWxlY3QoY2xhZGUsbnNwZWNfcGVjLG5fcGVjLG5fcHBsLG5zcGVjX3BwbCxwcGwsbl9TVkwsbnNwZWNfU1ZMLFNWTCxuX3B2bCxuc3BlY19wdmwscHZsKQ0KICANCm9ic19ieV9jbGFkZSAlPiUNCiAgYWRkX3JvdyhjbGFkZT0iQWxsIFNwZWNpZXMiLA0KICAgICAgICAgIG5fcGVjID0gc3VtKG9ic19ieV9jbGFkZSRuX3BlYyksDQogICAgICAgICAgbnNwZWNfcGVjID0gc3VtKG9ic19ieV9jbGFkZSRuc3BlY19wZWMpLA0KICAgICAgICAgIG5zcGVjX3BwbCA9IHN1bShvYnNfYnlfY2xhZGUkbnNwZWNfcHBsKSwNCiAgICAgICAgICBuX3BwbCA9IHN1bShvYnNfYnlfY2xhZGUkbl9wcGwpLA0KICAgICAgICAgIG5fU1ZMID0gc3VtKG9ic19ieV9jbGFkZSRuX1NWTCksDQogICAgICAgICAgbnNwZWNfU1ZMID0gc3VtKG9ic19ieV9jbGFkZSRuc3BlY19TVkwpLA0KICAgICAgICAgIG5fcHZsID0gc3VtKG9ic19ieV9jbGFkZSRuX3B2bCksDQogICAgICAgICAgbnNwZWNfcHZsID0gc3VtKG9ic19ieV9jbGFkZSRuc3BlY19wdmwpLA0KICAgICAgICAgIHBwbCA9IGRhdGFfcmVjb24gJT4lIGdyb3VwX2J5KHRheG9uKSAlPiUgZHJvcF9uYShwcmVwZWN0b3JhbF9sZW5ndGgsdG90YWxfbGVuZ3RoKSAlPiUgc3VtbWFyaXNlKHBwbD1tZWFuKHByZXBlY3RvcmFsX2xlbmd0aC90b3RhbF9sZW5ndGgpKSAlPiUgcHVsbCgpICU+JSBtZWFuKCksDQogICAgICAgICAgU1ZMID0gZGF0YV9yZWNvbiAlPiUgZ3JvdXBfYnkodGF4b24pICU+JSBkcm9wX25hKFNWTCx0b3RhbF9sZW5ndGgpICU+JSBzdW1tYXJpc2UocHBsPW1lYW4oU1ZML3RvdGFsX2xlbmd0aCkpICU+JSBwdWxsKCkgJT4lIG1lYW4oKSwNCiAgICAgICAgICBwdmwgPSBkYXRhX3JlY29uICU+JSBncm91cF9ieSh0YXhvbikgJT4lIGRyb3BfbmEocHJlcGVsdmljX2xlbmd0aCx0b3RhbF9sZW5ndGgpICU+JSBzdW1tYXJpc2UocHBsPW1lYW4ocHJlcGVsdmljX2xlbmd0aC90b3RhbF9sZW5ndGgpKSAlPiUgcHVsbCgpICU+JSBtZWFuKCkpICU+JQ0KICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpLCB+bmFfaWYoLiwgMCkpKSAlPiUNCiAga2FibGUoZGlnaXRzPTMsY29sLm5hbWVzPWMoIkNsYWRlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk4gc3BwLiIsIk4gb2JzZXJ2YXRpb25zIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk4gc3BwLiIsIk4gb2JzZXJ2YXRpb25zIiwiTWVhbiBWYWx1ZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOIHNwcC4iLCJOIG9ic2VydmF0aW9ucyIsIk1lYW4gVmFsdWUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTiBzcHAuIiwiTiBvYnNlcnZhdGlvbnMiLCJNZWFuIFZhbHVlIiksDQogICAgICAgIGFsaWduPWMoImwiLCJjIiwiYyIsImMiLCJjIiwiYyIsImMiLCJjIiwiYyIsImMiLCJjIiwiYyIpLA0KICAgICAgICBjYXB0aW9uPSJEaXN0cmlidXRpb24gb2YgZGF0YSBpbiB0aGlzIHN0dWR5IGJ5IGhpZ2hlciBsZXZlbCBjbGFkZSIpICU+JQ0KICBhZGRfaGVhZGVyX2Fib3ZlKGMoIlRheG9ub215Ij0xLCJQZWN0b3JhbCBGaW4gQmFzZSBMZW5ndGgiPTIsIlByZXBlY3RvcmFsIExlbmd0aCI9MywNCiAgICAgICAgICAgICAgICAgICAgICJTbm91dC1WZW50IExlbmd0aCI9MywiUHJlcGVsdmljIExlbmd0aCI9MykpICU+JQ0KICBjb2x1bW5fc3BlYyAoYygxLDMsNiw5LDEyKSxib3JkZXJfcmlnaHQgPSBUKSAlPiUNCiAgcm93X3NwZWMgKDYsYm9sZD1UKSAlPiUNCiAga2FibGVfc3R5bGluZygpDQpgYGANCg0KIyMgUHJlcGVjdG9yYWwgbGVuZ3RoLCBTVkwsIGFuZCBwcmVwZWx2aWMgbGVuZ3RoIGJ5IG9yZGVyDQoNCmBgYHtyfQ0KZGF0YV9yZWNvbiAlPiUNCiAgZ3JvdXBfYnkodGF4b24pICU+JQ0KICBtdXRhdGUocHBsPXByZXBlY3RvcmFsX2xlbmd0aC90b3RhbF9sZW5ndGgsDQogICAgICAgICBTVkwyPVNWTC90b3RhbF9sZW5ndGgsDQogICAgICAgICBwdmw9cHJlcGVsdmljX2xlbmd0aC90b3RhbF9sZW5ndGgpICU+JQ0KICBzdW1tYXJpc2Uobl9wcGw9c3VtKCFpcy5uYShwcGwpKSwNCiAgICAgICAgICAgIG5fc3ZsPXN1bSghaXMubmEoU1ZMMikpLA0KICAgICAgICAgICAgbl9wdmw9c3VtKCFpcy5uYShwdmwpKSwNCiAgICAgICAgICAgIHBwbD1tZWFuKHBwbCxuYS5ybT1UKSwNCiAgICAgICAgICAgIFNWTD1tZWFuKFNWTDIsbmEucm09VCksDQogICAgICAgICAgICBwdmw9bWVhbihwdmwsbmEucm09VCksDQogICAgICAgICAgICBvcmRlcj11bmlxdWUob3JkZXIpLGNsYWRlPXVuaXF1ZShjbGFkZSkpICU+JQ0KICBncm91cF9ieShvcmRlcikgJT4lDQogIHN1bW1hcmlzZShvcmRlcj11bmlxdWUob3JkZXIpLGNsYWRlPXVuaXF1ZShjbGFkZSksDQogICAgICAgICAgICBuc3BlY19wcGw9c3VtKCFpcy5uYShwcGwpKSwNCiAgICAgICAgICAgIG5fcHBsPXN1bShuX3BwbCksDQogICAgICAgICAgICBuc3BlY19TVkw9c3VtKCFpcy5uYShTVkwpKSwNCiAgICAgICAgICAgIG5fU1ZMPXN1bShuX3N2bCksDQogICAgICAgICAgICBuc3BlY19wdmw9c3VtKCFpcy5uYShwdmwpKSwNCiAgICAgICAgICAgIG5fcHZsPXN1bShuX3B2bCksDQogICAgICAgICAgICBwcGw9bWVhbihwcGwsbmEucm09VCksDQogICAgICAgICAgICBTVkw9bWVhbihTVkwsbmEucm09VCksDQogICAgICAgICAgICBwdmw9bWVhbihwdmwsbmEucm09VCkpICU+JQ0KICBzZWxlY3Qob3JkZXIsY2xhZGUsbnNwZWNfcHBsLG5fcHBsLHBwbCxuc3BlY19TVkwsbl9TVkwsU1ZMLG5zcGVjX3B2bCxuX3B2bCxwdmwpICU+JQ0KICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpLCB+bmFfaWYoLiwgMCkpKSAlPiUNCiAga2FibGUoZGlnaXRzPTMsY29sLm5hbWVzPWMoIk9yZGVyIiwiQ2xhZGUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTiBzcHAuIiwiTiBvYnNlcnZhdGlvbnMiLCJNZWFuIFZhbHVlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk4gc3BwLiIsIk4gb2JzZXJ2YXRpb25zIiwiTWVhbiBWYWx1ZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOIHNwcC4iLCJOIG9ic2VydmF0aW9ucyIsIk1lYW4gVmFsdWUiKSwNCiAgICAgICAgYWxpZ249YygibCIsImMiLCJjIiwiYyIsImMiLCJjIiwiYyIsImMiLCJjIiwiYyIsImMiKSwNCiAgICAgICAgY2FwdGlvbj0iRGlzdHJpYnV0aW9uIG9mIGRhdGEgZm9yIHByZXBlY3RvcmFsIGxlbmd0aCwgc25vdXQtdmVudCBsZW5ndGggKFNWTCksIGFuZCBwcmVwZWx2aWMgbGVuZ3RoIGJ5IG9yZGVyIikgJT4lDQogIGFkZF9oZWFkZXJfYWJvdmUoYygiVGF4b25vbXkiPTIsIlByZXBlY3RvcmFsIExlbmd0aCI9MywNCiAgICAgICAgICAgICAgICAgICAiU25vdXQtVmVudCBMZW5ndGgiPTMsIlByZXBlbHZpYyBMZW5ndGgiPTMpKSAlPiUNCiAgY29sdW1uX3NwZWMgKGMoMiw1LDgsMTEpLGJvcmRlcl9yaWdodCA9IFQpICU+JQ0KICBrYWJsZV9zdHlsaW5nKCkNCmBgYA0KDQojIyBQZWN0b3JhbCBmaW4gYmFzZSBkYXRhIGJ5IGNob25kcmljaHRoeWFuIGZhbWlseQ0KDQpgYGB7cn0NCmRhdGFfcmVjb24gJT4lDQogIGRyb3BfbmEocGVjX2Jhc2UpICU+JQ0KICBmaWx0ZXIoY2xhZGU9PSJDaG9uZHJpY2h0aHllcyIpICU+JQ0KICBzdW1tYXJpc2UoLmJ5PXRheG9uLGNvdW50PW4oKSxvcmRlcj11bmlxdWUob3JkZXIpLGZhbWlseT11bmlxdWUoZmFtaWx5KSwNCiAgICAgICAgICAgIHBlY19iYXNlPW1lYW4ocGVjX2Jhc2UvdG90YWxfbGVuZ3RoKSkgJT4lDQogIHN1bW1hcmlzZSguYnk9ZmFtaWx5LG9yZGVyPXVuaXF1ZShvcmRlciksTj1uKCksY291bnQ9c3VtKGNvdW50KSwNCiAgICAgICAgICAgIHBlY19tZWFuPW1lYW4ocGVjX2Jhc2UpLA0KICAgICAgICAgICAgcGVjX3JhbmdlPWlmZWxzZShOPT0xLE5BLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZTAoIigiLHJvdW5kKG1pbihwZWNfYmFzZSksMyksIuKAkyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvdW5kKG1heChwZWNfYmFzZSksMyksIikiKSkpICU+JSANCiAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSwgfm5hX2lmKC4sIDApKSkgJT4lDQogIGFycmFuZ2Uob3JkZXIsZmFtaWx5KSAlPiUNCiAga2FibGUoY29sLm5hbWVzPWMoIkZhbWlseSIsIk9yZGVyIiwiTiBzcHAuIiwiTiBzcGVjaW1lbnMiLA0KICAgICAgICAgICAgICAgICAgICAiTWVhbiBQcm9wb3J0aW9uYWwgUGVjdG9yYWwgQmFzZSBMZW5ndGggKGFzIGZyYWN0aW9uIG9mIHRvdGFsIGxlbmd0aCkiLCJSYW5nZSBvZiBTcGVjaWVzIEF2ZXJhZ2VzIiksDQogICAgICAgIGRpZ2l0cz1jKDEsMSwxLDEsMywzKSxhbGlnbj1jKCJsIiwiYyIsImMiLCJjIiwiYyIsImMiKSwNCiAgICAgICAgY2FwdGlvbj0iRGlzdHJpYnV0aW9uIG9mIHNoYXJrIHRheGEgd2l0aCBwZWN0b3JhbCBmaW4gYmFzZSBtZWFzdXJlbWVudHMgYnkgZmFtaWx5IikgJT4lIA0KICBrYWJsZV9zdHlsaW5nKCkNCmBgYA0KDQpgYGB7cn0NCmRhdGFfcmVjb24gJT4lDQogIGZpbHRlcihjbGFkZT09IlBsYWNvZGVybWkiKSAlPiUNCiAgZHJvcF9uYShwZWNfYmFzZSx0b3RhbF9sZW5ndGgpICU+JQ0KICBtdXRhdGUobGVuZ3RoX2FzPWlmZWxzZShsZW5ndGhfYXM9PSJ0b3RhbCBsZW5ndGgiLCJObyIsIlllcyIpLA0KICAgICAgICAgc3BlY2ltZW49aWZlbHNlKHNwZWNpbWVuICVpbiUgYygiQ29tcG9zaXRlIHR1YmVyY3VsYXR1cyIsIkNvbXBvc2l0ZSBwdWxjaGVsbHVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlJlY29uIChUcmluYWpzdGljIGV0IGFsLiAyMDEzIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJSZWNvbnN0cnVjdGlvbiBpbiBTdHVkeSIsc3BlY2ltZW4pLA0KICAgICAgICAgdGF4b249c3RyX3JlcGxhY2UodGF4b24sIl8iLCIgIiksDQogICAgICAgICBib2R5X21hc3M9Ym9keV9tYXNzLzEwMDAsDQogICAgICAgICBzcGVjaW1lbj1pZmVsc2Uoc3BlY2ltZW49PSJBQS5NRU0uRFMuOCIsIkFBLk1FTS5EUy44ICh3aXRoIHBlY3RvcmFsIGJhc2UgZnJvbSBQSU1VWiBBL0kgNDc3MykiLHNwZWNpbWVuKSkgJT4lDQogIHNlbGVjdCh0YXhvbixzcGVjaW1lbixwZWNfYmFzZSx0b3RhbF9sZW5ndGgsYm9keV9tYXNzLGxlbmd0aF9hcyxSZWZlcmVuY2UpICU+JQ0KICBhcnJhbmdlKHRheG9uKSAlPiUNCiAga2FibGUoZGlnaXRzPWMoMSwxLDEsMSwyLDEsMSksDQogICAgICAgIGNvbC5uYW1lcyA9IGMoIlRheG9uIiwiU3BlY2ltZW4iLCJQZWN0b3JhbCBGaW4gQmFzZSIsIlRvdGFsIExlbmd0aCIsIkJvZHkgTWFzcyIsIkxlbmd0aCBFc3RpbWF0ZWQ/IiwiUmVmZXJlbmNlIiksDQogICAgICAgIGNhcHRpb24gPSAiUGVjdG9yYWwgZmluIGJhc2Ugc2l6ZSBpbiBhcnRocm9kaXJlcywgYWxvbmcgd2l0aCBlaXRoZXIgbWVhc3VyZWQgb3IgZXN0aW1hdGVkIHRvdGFsIGxlbmd0aCBhbmQgYm9keSBtYXNzIGVzdGltYXRlZCB1c2luZyB0aGUgZWxsaXBzb2lkIG1vZGVsIGluIEVuZ2VsbWFuICgyMDIzKS4gTGluZWFyIG1lYXN1cmVtZW50cyBpbiBjbSBhbmQgYm9keSBtYXNzIGluIGtnLiIsDQogICAgICAgIGFsaWduPWMoImwiLCJjIiwiYyIsImMiLCJjIiwiYyIsImMiKSkgJT4lDQogIGNvbHVtbl9zcGVjICgxLGl0YWxpYz1UKSAlPiUNCiAga2FibGVfc3R5bGluZygpDQpgYGANCg0KIyMgRmluZW5lc3MgcmF0aW8gYnkgb3JkZXINCg0KYGBge3J9DQpkYXRhX3JlY29uICU+JQ0KICBncm91cF9ieSh0YXhvbikgJT4lDQogIG11dGF0ZShmaW5lbmVzcz1wcmVjYXVkYWxfbGVuZ3RoL2JvZHlfZGVwdGgpICU+JQ0KICBzdW1tYXJpc2Uobl9maW5lbmVzcz1zdW0oIWlzLm5hKGZpbmVuZXNzKSksDQogICAgICAgICAgICBmaW5lbmVzcz1tZWFuKGZpbmVuZXNzLG5hLnJtPVQpLA0KICAgICAgICAgICAgb3JkZXI9dW5pcXVlKG9yZGVyKSxjbGFkZT11bmlxdWUoY2xhZGUpKSAlPiUNCiAgZ3JvdXBfYnkob3JkZXIpICU+JQ0KICBzdW1tYXJpc2Uob3JkZXI9dW5pcXVlKG9yZGVyKSxjbGFkZT11bmlxdWUoY2xhZGUpLA0KICAgICAgICAgICAgbnNwZWNfZmluZW5lc3M9c3VtKCFpcy5uYShmaW5lbmVzcykpLA0KICAgICAgICAgICAgbl9maW5lbmVzcz1zdW0obl9maW5lbmVzcyksDQogICAgICAgICAgICBmaW5lbmVzcz1tZWFuKGZpbmVuZXNzLG5hLnJtPVQpKSAlPiUNCiAgc2VsZWN0KG9yZGVyLGNsYWRlLG5zcGVjX2ZpbmVuZXNzLG5fZmluZW5lc3MsZmluZW5lc3MpICU+JQ0KICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpLCB+bmFfaWYoLiwgMCkpKSAlPiUNCiAga2FibGUoZGlnaXRzPTMsY29sLm5hbWVzPWMoIk9yZGVyIiwiQ2xhZGUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTiBzcHAuIiwiTiBvYnNlcnZhdGlvbnMiLCJNZWFuIFZhbHVlIiksDQogICAgICAgIGFsaWduPWMoImwiLCJjIiwiYyIsImMiLCJjIiksDQogICAgICAgIGNhcHRpb249IkRpc3RyaWJ1dGlvbiBvZiBkYXRhIGZvciBmaW5lbmVzcyByYXRpbyBieSBvcmRlciIpICU+JQ0KICBrYWJsZV9zdHlsaW5nKCkNCmBgYA0KDQoNCiMjIENhdWRhbCBwZWR1bmNsZSBoZWlnaHQgYnkgb3JkZXINCg0KYGBge3J9DQpkYXRhX3JlY29uICU+JQ0KICBncm91cF9ieSh0YXhvbikgJT4lDQogIG11dGF0ZShjYXVkYWxfcGVkdW5jbGU9cGVkdW5jbGVfaGVpZ2h0L3RvdGFsX2xlbmd0aCkgJT4lDQogIHN1bW1hcmlzZShuX2NwbD1zdW0oIWlzLm5hKGNhdWRhbF9wZWR1bmNsZSkpLA0KICAgICAgICAgICAgY3BsPW1lYW4oY2F1ZGFsX3BlZHVuY2xlLG5hLnJtPVQpLA0KICAgICAgICAgICAgb3JkZXI9dW5pcXVlKG9yZGVyKSxjbGFkZT11bmlxdWUoY2xhZGUpKSAlPiUNCiAgZ3JvdXBfYnkob3JkZXIpICU+JQ0KICBzdW1tYXJpc2Uob3JkZXI9dW5pcXVlKG9yZGVyKSxjbGFkZT11bmlxdWUoY2xhZGUpLA0KICAgICAgICAgICAgbnNwZWNfY3BsPXN1bSghaXMubmEoY3BsKSksDQogICAgICAgICAgICBuX2NwbD1zdW0obl9jcGwpLA0KICAgICAgICAgICAgY3BsPW1lYW4oY3BsLG5hLnJtPVQpKSAlPiUNCiAgc2VsZWN0KG9yZGVyLGNsYWRlLG5zcGVjX2NwbCxuX2NwbCxjcGwpICU+JQ0KICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpLCB+bmFfaWYoLiwgMCkpKSAlPiUNCiAga2FibGUoZGlnaXRzPTMsY29sLm5hbWVzPWMoIk9yZGVyIiwiQ2xhZGUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTiBzcHAuIiwiTiBvYnNlcnZhdGlvbnMiLCJNZWFuIFZhbHVlIiksDQogICAgICAgIGFsaWduPWMoImwiLCJjIiwiYyIsImMiLCJjIiksDQogICAgICAgIGNhcHRpb249IkRpc3RyaWJ1dGlvbiBvZiBkYXRhIGZvciBjYXVkYWwgcGVkdW5jbGUgaGVpZ2h0IGJ5IG9yZGVyIikgJT4lDQogIGthYmxlX3N0eWxpbmcoKQ0KYGBgDQoNCiMgQW5hbHlzZXMNCg0KIyMgRmluZW5lc3MgUmF0aW8NCg0KKHJlZjpmaW5lbmVzc3JhdGlvKSBGaW5lbmVzcyByYXRpb3MgaW4gZXVnbmF0aG9zdG9tZXMsIHNob3dpbmcgdGhlIGRpc3RpbmN0bHkgYmVsb3ctYXZlcmFnZSBmaW5lbmVzcyByYXRpb3MgZm9yIGFydGhyb2RpcmVzIGNvbXBhcmVkIHRvIG90aGVyIGNsYWRlcy4gIk90aGVyIEFydGhyb2RpcmVzIiBtb3N0bHkgcmVwcmVzZW50IHRheGEgd2l0aCBlc3RpbWF0ZWQgbGVuZ3RocyB2aWEgT09MLCB3aGVyZWFzIENvY2Nvc3RldXMsIEluY2lzb3NjdXR1bSwgYW5kIEFtYXppY2h0aHlzIGFyZSBiYXNlZCBvbiByZWxhdGl2ZWx5IGNvbXBsZXRlIG1hdGVyaWFsLiBEYXRhIGFyZSByZXBvcnRlZCBhcyBpbmRpdmlkdWFsIG9ic2VydmF0aW9ucyBmb3IgYXJ0aHJvZGlyZXMgYW5kIHNwZWNpZXMgYXZlcmFnZXMgZm9yIGFsbCBvdGhlciB0YXhhIHRvIGRpc3BsYXkgaW5kaXZpZHVhbCB2YXJpYXRpb24gd2l0aGluIEFydGhyb2RpcmEuIFNoYWRlZCBhcmVhIHJlcHJlc2VudCAidHlwaWNhbCIgZmluZW5lc3MgcmF0aW9zIGZvciBmaXNoZXMgYWNjb3JkaW5nIHRvIEFsZXhhbmRlciAoMTk2NyksIHJlcHJlc2VudGluZyBhbiBmIG9mIDMuNSB0byA3LCB3aXRoIHRoZSBibGFjayBsaW5lIHJlcHJlc2VudGluZyBoeXBvdGhldGljYWwgaWRlYWwgaHlkcm9keW5hbWljIGYgb2YgNC42LiBSZWQgbGluZSByZXByZXNlbnRzIHRoZSBtZWFuIGZpbmVuZXNzIHJhdGlvIGFtb25nIGFsbCBzcGVjaWVzLiBGYWRlZCBzdGFycyByZXByZXNlbnQgdGhlIG91dGRhdGVkIHJlY29uc3RydWN0aW9uIG9mIE1pbGVzIGFuZCBXZXN0b2xsICgxOTY4KSBvciBzaG93aW5nIHRoZSBoeXBvdGhldGljYWwgcG9zaXRpb24gb2YgYSBsb25nZXIgKkR1bmtsZW9zdGV1cyogYXQgdGhlIHVwcGVyIGVuZCBvZiB0aGUgY29uZmlkZW5jZSBpbnRlcnZhbHMgb2YgRW5nZWxtYW4gKDIwMjMpLg0KDQpgYGB7cixmaWcuaGVpZ2h0PTEzLHdhcm5pbmc9RixmaWcuY2FwPSIocmVmOmZpbmVuZXNzcmF0aW8pIn0NCmZpbmVuZXNzPC1kYXRhX3JlY29uICU+JQ0KICBkcm9wX25hKHByZWNhdWRhbF9sZW5ndGgsYm9keV9kZXB0aCkgJT4lDQogIG11dGF0ZShmaW5lbmVzcz1wcmVjYXVkYWxfbGVuZ3RoL2JvZHlfZGVwdGgsDQogICAgICAgICBvcmRlcjI9aWZlbHNlKGNsYWRlPT0iUGxhY29kZXJtaSIsIk90aGVyIEFydGhyb2RpcmEiLG9yZGVyKSklPiUNCiAgbXV0YXRlKG9yZGVyMj1pZmVsc2UoZ2VudXM9PSJEdW5rbGVvc3RldXMiLCIqRHVua2xlb3N0ZXVzKiIsb3JkZXIyKSwNCiAgICAgICAgIG9yZGVyMj1pZmVsc2UoZ2VudXM9PSJDb2Njb3N0ZXVzIiwiKkNvY2Nvc3RldXMqIixvcmRlcjIpLA0KICAgICAgICAgb3JkZXIyPWlmZWxzZShnZW51cz09IkluY2lzb3NjdXR1bSIsIipJbmNpc29zY3V0dW0qIixvcmRlcjIpLA0KICAgICAgICAgb3JkZXIyPWlmZWxzZShnZW51cz09IkFtYXppY2h0aHlzIiwiKkFtYXppY2h0aHlzKiIsb3JkZXIyKSwNCiAgICAgICAgIG9yZGVyMj1pZmVsc2UoZmFtaWx5PT0iQ2FtdXJvcGlzY2lkYWUiLCJDYW11cm9waXNjaWRhZSIsb3JkZXIyKSwNCiAgICAgICAgIG9yZGVyMj1pZmVsc2Uob3JkZXIgJWluJSBjKCJTY29tYnJpZm9ybWVzIiwiTGFtcHJpZm9ybWVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkxhbW5pZm9ybWVzIiwiQ2VudHJhcmNoaWZvcm1lcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDYXJhbmdpZm9ybWVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNhcmFuZ2FyaWEgaW5jZXJ0YWUgc2VkaXMiLCJQZXJjaWZvcm1lcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJFdXBlcmNhcmlhIGluY2VydGFlIHNlZGlzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIklzdGlvcGhvcmlmb3JtZXMiLCJDaGFyYWNpZm9ybWVzIiksZmFtaWx5LG9yZGVyMikpICU+JQ0KICBtdXRhdGUob3JkZXIyPWlmZWxzZShmYW1pbHk9PSJDZW50cmFyY2hpZGFlIiAmIGdlbnVzIT0iTWljcm9wdGVydXMiLCJPdGhlciBDZW50cmFyY2hpZGFlIixvcmRlcjIpLA0KICAgICAgICAgb3JkZXIyPWlmZWxzZShnZW51cyAlaW4lIGMoIlRodW5udXMiLA0KICAgICAgICAgICAgICAgICAgICAgICJBbGxvdGh1bm51cyIsDQogICAgICAgICAgICAgICAgICAgICAgIkF1eGlzIiwNCiAgICAgICAgICAgICAgICAgICAgICAiRXV0aHlubnVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAiS2F0c3V3b251cyIsDQogICAgICAgICAgICAgICAgICAgICAgIlNhcmRhIiwiT3JjeW5vcHNpcyIsIkN5Ymlvc2FyZGEiLCJHeW1ub3NhcmRhIiksDQogICAgICAgICAgICAgICAgICAgICAgIlRodW5uaW5pICsgU2FyZGluaSIsb3JkZXIyKSwNCiAgICAgICAgIG9yZGVyMj1pZmVsc2UoZ2VudXM9PSJHYXN0ZXJvY2hpc21hIiwiKkdhc3Rlcm9jaGlzbWEqIixvcmRlcjIpKSAlPiUNCiAgbXV0YXRlKG9yZGVyMj1pZmVsc2UoZ2VudXM9PSJNaWNyb3B0ZXJ1cyIsIipNaWNyb3B0ZXJ1cyoiLG9yZGVyMiksDQogICAgICAgICBvcmRlcjI9aWZlbHNlKG9yZGVyMj09IlNjb21icmlkYWUiLCJPdGhlciBTY29tYnJpZGFlIixvcmRlcjIpKSAlPiUNCiAgbXV0YXRlKGhpZ2hlcl9ncm91cD1mYWN0b3IoaGlnaGVyX2dyb3VwLGxldmVscz1jKCJQZXRyb215em9udGlmb3JtZXMiLCJBcnRocm9kaXJhIiwiQ2hvbmRyaWNodGh5ZXMiLCJTYXJjb3B0ZXJ5Z2lpIiwiQmFzYWwgQWN0aW5vcHRlcnlnaWkiLCJCYXNhbCBUZWxlb3N0ZWkiLCJPdG9jZXBoYWxhIiwiU3RlbSBFdXRlbGVvc3RlaSIsIkFjYW50aG9wdGVyeWdpaSIpKSklPiUNCiAgYXJyYW5nZShoaWdoZXJfZ3JvdXAsb3JkZXIsZmFtaWx5LHRheG9uKSU+JQ0KICBzZWxlY3QodGF4b24sZmluZW5lc3Msb3JkZXIyLGV2ZXJ5dGhpbmcoKSkNCg0KbGV2ZWxfaW5mbyA8LSBmaW5lbmVzcyAlPiUNCiAgYWRkX3JvdyhoaWdoZXJfZ3JvdXA9IkFydGhyb2RpcmEiLG9yZGVyPSJBcnRocm9kaXJhIiwNCiAgICAgICAgICBmYW1pbHk9IkR1bmtsZW9zdGVpZGFlIixnZW51cz0iRHVua2xlb3N0ZXVzIiwNCiAgICAgICAgICBvcmRlcjI9IipEdW5rbGVvc3RldXMqICh1cHBlciBQRSkiKSAlPiUNCiAgbXV0YXRlKGhpZ2hlcl9ncm91cD1mYWN0b3IoaGlnaGVyX2dyb3VwLGxldmVscz1jKCJQZXRyb215em9udGlmb3JtZXMiLCJBcnRocm9kaXJhIiwiQ2hvbmRyaWNodGh5ZXMiLCJTYXJjb3B0ZXJ5Z2lpIiwiQmFzYWwgQWN0aW5vcHRlcnlnaWkiLCJCYXNhbCBUZWxlb3N0ZWkiLCJPdG9jZXBoYWxhIiwiU3RlbSBFdXRlbGVvc3RlaSIsIkFjYW50aG9wdGVyeWdpaSIpKSklPiUNCiAgYXJyYW5nZShoaWdoZXJfZ3JvdXAsb3JkZXIsZmFtaWx5LGdlbnVzKSAlPiUNCiAgcHVsbChvcmRlcjIpICU+JSANCiAgdW5pcXVlKCkNCg0KZmluZW5lc3NfMjwtYmluZF9yb3dzKGZpbmVuZXNzICU+JQ0KICAgICAgICAgICAgZmlsdGVyKGNsYWRlID09ICJQbGFjb2Rlcm1pIikgJT4lDQogICAgICAgICAgICBkcm9wX25hKGZpbmVuZXNzKSwNCiAgICAgICAgICAgIGZpbmVuZXNzICU+JQ0KICAgICAgICAgICAgZmlsdGVyKGdlbnVzID09ICJEdW5rbGVvc3RldXMiKSAlPiUNCiAgICAgICAgICAgICAgbXV0YXRlKHByZWNhdWRhbF9sZW5ndGg9cHJlY2F1ZGFsX2xlbmd0aCoxLjEyNDAsDQogICAgICAgICAgICAgICAgICAgICBvcmRlcjI9IipEdW5rbGVvc3RldXMqICh1cHBlciBQRSkiKSAlPiUNCiAgICAgICAgICAgICAgbXV0YXRlKGZpbmVuZXNzPXByZWNhdWRhbF9sZW5ndGgvYm9keV9kZXB0aCkgJT4lDQogICAgICAgICAgICBkcm9wX25hKGZpbmVuZXNzKSwNCiAgICAgICAgICBmaW5lbmVzcyAlPiUNCiAgICAgICAgICAgIGZpbHRlcihnZW51cyE9IlBsYWNvZGVybWkifGlzLm5hKG9yZGVyMikpICU+JQ0KICAgICAgICAgICAgZ3JvdXBfYnkodGF4b24pICU+JQ0KICAgICAgICAgICAgZHJvcF9uYShmaW5lbmVzcykgJT4lDQogICAgICAgICAgICBzdW1tYXJpemUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpLG1lYW4pLA0KICAgICAgICAgICAgICAgICAgICAgIGhpZ2hlcl9ncm91cD11bmlxdWUoaGlnaGVyX2dyb3VwKSxvcmRlcjI9dW5pcXVlKG9yZGVyMiksDQogICAgICAgICAgICAgICAgICAgICAgb3JkZXI9dW5pcXVlKG9yZGVyKSwNCiAgICAgICAgICAgICAgICAgICAgICB0YXhvbj11bmlxdWUodGF4b24pLGdlbnVzPXVuaXF1ZShnZW51cyksc3BlY2llcz11bmlxdWUoc3BlY2llcyksDQogICAgICAgICAgICAgICAgICAgICAgY2xhZGU9dW5pcXVlKGNsYWRlLG5hLnJtPUYpLHNoYXBlPXVuaXF1ZShzaGFwZSkpKSAlPiUNCiAgbXV0YXRlKG9yZGVyMj1mYWN0b3Iob3JkZXIyLG9yZGVyZWQ9VCxsZXZlbHM9cmV2KGxldmVsX2luZm8pKSkNCg0KZmluZW5lc3NfMiAlPiUNCiAgZ2dwbG90KGFlcyh5PW9yZGVyMix4PWZpbmVuZXNzKSkrDQogIGFubm90YXRlKCJyZWN0IiwgeG1pbj0zLCB4bWF4PTcsIHltaW49LUluZiwgeW1heD1JbmYsIGFscGhhPTAuMTUpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0PWMoMyw3KSxsaW5ldHlwZT0iZGFzaGVkIikrDQogIGdlb21fdmxpbmUoeGludGVyY2VwdD00LjYpKw0KICBnZW9tX3BvaW50KGFlcyh5PW9yZGVyMix4PWZpbmVuZXNzKSxjb2xvcj1OQSkgKw0KICBnZW9tX3ZsaW5lKGRhdGE9LiAlPiUgZmlsdGVyKGNsYWRlIT0iUGxhY29kZXJtaSIpLGFlcyh4aW50ZXJjZXB0PW1lYW4oZmluZW5lc3MpKSxjb2xvcj0icmVkIikgKw0KICBnZW9tX3Zpb2xpbihkYXRhPS4gJT4lIGZpbHRlcihjbGFkZSE9IlBsYWNvZGVybWkiKSxzY2FsZT0id2lkdGgiLGFlcyhmaWxsPWNsYWRlKSxzaG93LmxlZ2VuZCA9IEYpKw0KICBnZW9tX2JveHBsb3QoZGF0YT0uICU+JSBmaWx0ZXIoY2xhZGUhPSJQbGFjb2Rlcm1pIiksd2lkdGg9MC4zKSsNCiAgZ2VvbV9zdGFyKGRhdGE9IC4gJT4lIGZpbHRlcihvcmRlcjI9PSIqRHVua2xlb3N0ZXVzKiAodXBwZXIgUEUpInwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFJlZmVyZW5jZT09Ik1pbGVzIGFuZCBXZXN0b2xsIDE5NjgiKSwNCiAgICAgICAgICAgIGFscGhhPTAuNSxmaWxsPSJ3aGl0ZSIsc2l6ZT0xLjUpICsNCiAgZ2VvbV9zdGFyKGRhdGE9IC4gJT4lIGZpbHRlcihjbGFkZT09IlBsYWNvZGVybWkiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBSZWZlcmVuY2UhPSJNaWxlcyBhbmQgV2VzdG9sbCAxOTY4IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcmRlcjIhPSIqRHVua2xlb3N0ZXVzKiAodXBwZXIgUEUpIiksDQogICAgICAgICAgICBmaWxsPSJ3aGl0ZSIsc2l6ZT0xLjUpICsNCiAgbGFicyh5PWVsZW1lbnRfYmxhbmsoKSx4PSJGaW5lbmVzcyBSYXRpbyAoKmYqKSIpKw0KICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfbWFya2Rvd24oKSwNCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9tYXJrZG93bigpKQ0KYGBgDQoNCkV1YnJhY2h5dGhvcmFjaWQgYXJ0aHJvZGlyZXMgZ2VuZXJhbGx5IGhhdmUgcmVsYXRpdmVseSBsb3cgZmluZW5lc3MgcmF0aW9zIHdpdGhpbiB0aGUgcmFuZ2Ugb2YgdmFyaWF0aW9uIHNlZW4gaW4gZmlzaGVzLCBlc3BlY2lhbGx5IGlmIG5vdCBjb3VudGluZyBkaXNjb2lkIHRheGEuIFRoZSBvbmx5IGV1YnJhY2h5dGhvcmFjaWQgYXJ0aHJvZGlyZXMgdG8gcmVsaWFibHkgaGF2ZSBhYm92ZSBhdmVyYWdlIGZpbmVuZXNzIHJhdGlvcyBhcmUgdGhlIGNhbXVyb3Bpc2NpZHMsIHdoaWNoIGFyZSBoaWdobHkgdHVidWxhciBzcGVjaWVzIHdpdGggcG9pbnRlZCByb3N0cmEgKERlbm5pcyBhbmQgTWlsZXMgMTk3OSkgdGhhdCBoYXZlIGJlZW4gY29uc2lkZXJlZCB0YWNoeW5la3RvbmljIHN3aW1tZXJzIChUcmluYWpzdGljIGV0IGFsLiAyMDIyKS4NCg0KT25lIG9mIHRoZSBmZXcgb3RoZXIgYXJ0aHJvZGlyZXMgdGhhdCBzaG93cyBhIGZpbmVuZXNzIHJhdGlvIGNsb3NlIHRvIHRoZSBhdmVyYWdlIGZvciBmaXNoZXMgaXMgKlRvcm9zdGV1cyBwdWxjaGVsbHVzKi4gSG93ZXZlciB0aGUgaG9sb3R5cGUgb2YgKlQuIHB1bGNoZWxsdXMqIGlzIHZlcnkgc21hbGwgaW4gc2l6ZSBhbmQgbWF5IHJlcHJlc2VudCBhIGp1dmVuaWxlIG9mICpULiB0dWJlcmN1bGF0dXMqLCBzaW1pbGFyIHRvIHdoYXQgaGFzIGhhcHBlbmVkIHdpdGggKkdvZ29waXNjaXMqIGFuZCAqQ29tcGFnb3Bpc2NpcyogKFRyaW5hanN0aWMgYW5kIEhhemVsdG9uIDIwMDcpLCBpbiB3aGljaCBjYXNlIGl0IG1pZ2h0IGJlIGV4cGVjdGVkIHRvIGhhdmUgYSBzaGFsbG93ZXIgdHJ1bmsgKHNlZSBUcmluYWpzdGljIGFuZCBIYXplbHRvbiAyMDA3IGFuZCBtYWluIG1hbnVzY3JpcHQpLg0KDQpGb3IgKkNvY2Nvc3RldXMqIHRoZSBzcGVjaW1lbiBST00gVlAgNTI2NjcsIHdoaWNoIGlzIGNvbnNpZGVyZWQgdGhlIG1vc3QgcmVsaWFibHkgbWVhc3VyZWQgc3BlY2ltZW4gaGVyZSwgaGFzIGEgZmluZW5lc3MgcmF0aW8gb2YgMy42Mi4gSG93ZXZlciBldmVuIHRoZSBmYW1vdXMgTWlsZXMgYW5kIFdlc3RvbGwgKDE5NjgpIHJlY29uc3RydWN0aW9uIG9ubHkgaGFzIGFuICpmKiBhcm91bmQgNCwgZGVzcGl0ZSBoYXZpbmcgYSB0b3JzbyB0aGF0IGlzIG11Y2ggdG9vIGxvbmcgcmVsYXRpdmUgdG8gdGhlIGhlYWQgYW5kIGJvZHkgYXJtb3IgKHNlZSBtYWluIG1hbnVzY3JpcHQpLCBpbmRpY2F0aW5nIHRoZSBsb3cgZmluZW5lc3MgcmF0aW8gaGVyZSBpcyB1bmxpa2VseSB0byBiZSB0aGUgcmVzdWx0IG9mIGluY29ycmVjdCByZWNvbnN0cnVjdGlvbi4NCg0KRm9yICpJbmNpc29zY3V0dW0qIHRoZSByZWNvbnN0cnVjdGlvbiBpbiBUcmluYWpzdGljICgyMDEzKSBoYXMgYSBmaW5lbmVzcyByYXRpbyBvZiB+My45LiAsIFRoZSBwcm9wb3J0aW9ucyBvZiB0aGlzIHJlY29uc3RydWN0aW9uIGFncmVlIHZlcnkgd2VsbCB3aXRoIGFjdHVhbCBzcGVjaW1lbnMgb2YgKkluY2lzb3NjdXR1bSogbGlrZSBOSE1VSyBQViBQIDUwOTM0LCBzdWdnZXN0aW5nIHRoaXMgdmFsdWUgaXMgcmVhc29uYWJsZS4gSG93ZXZlciwgdGhlIGZpZ3VyZSBpbiBUcmluYWpzdGljICgyMDEzKSBoYXMgaXRzIGhlYWQgcmFpc2VkIGFuZCB0aHVzIGV4dGVuZGluZyBhbnRlcm9wb3N0ZXJpb3JseSBzbGlnaHRseS4gUm90YXRpbmcgdGhlIGhlYWQgYmFjayBpbnRvIGEgbmV1dHJhbCBwb3NpdGlvbiB3b3VsZCBwcm9kdWNlIGEgZmluZW5lc3MgcmF0aW8gb2YgYWJvdXQgMy44LiBUaGUgaG9sb3R5cGUgb2YgKkluY2lzb3NjdXR1bSogKCIqR29nb3N0ZXVzKiIpICpzYXJhaGFlKiAodGhlIG90aGVyIGRhdGEgcG9pbnQgZm9yICpJbmNpc29zY3V0dW0qKSBoYXMgYW4gdW51c3VhbGx5IGhpZ2ggZmluZW5lc3MgcmF0aW8gb2YgNC45NC4gVGhlIGF1dGhvciBoYXMgYmVlbiB1bmFibGUgdG8gZGV0ZXJtaW5lIHdoeSB0aGlzIGlzLCBidXQgc3VzcGVjdHMgdGhpcyBpcyBkdWUgdG8gbWVhc3VyZW1lbnQgZXJyb3IuDQoNCipEdW5rbGVvc3RldXMqIGhhcyBhIHZlcnkgbG93IGZpbmVuZXNzIHJhdGlvIGFtb25nIGZpc2hlcywgZXZlbiBsb3dlciB0aGFuIG90aGVyIGFydGhyb2RpcmVzIGR1ZSB0byBpdHMgZGVlcCB0cnVuay4gTGFyZ2VyIGluZGl2aWR1YWxzIGhhdmUgZmluZW5lc3MgcmF0aW9zIGNsb3NlIHRvIDMuNSwgd2hlcmVhcyBqdXZlbmlsZXMgaGF2ZSBuYXJyb3dlciB0cnVua3MgYW5kIHNsaWdodGx5IGhpZ2hlciBmaW5lbmVzcyByYXRpb3MuIEV2ZW4gaWYgdGFraW5nIHRoZSBleHRyZW1lIHVwcGVyIGJvdW5kcyBvZiB0aGUgcmFuZ2Ugb2YgcG9zc2libGUgYm9keSBsZW5ndGhzIChiYXNlZCBvbiAlUEUpIHJlcG9ydGVkIGJ5IEVuZ2VsbWFuICgyMDIzKSwgdGhlIGZpbmVuZXNzIHJhdGlvIGlzIHN0aWxsIGJlbG93IGF2ZXJhZ2UuIFRoZSB0aHJlZSBzcGVjaW1lbnMgYXBwcm9hY2hpbmcgdGhlIGlkZWFsIHZhbHVlIG9mIDQuNiBpbiB0aGUgYWJvdmUgZ3JhcGggYXJlIGFsbCBqdXZlbmlsZSBzcGVjaW1lbnMgd2l0aCBuYXJyb3dlciB0cnVua3MuIFRoZSB2YWx1ZXMgY2FsY3VsYXRlZCBmb3IgKkR1bmtsZW9zdGV1cyogYXJlIG5vdCBvdXQgb2YgdGhlIHF1ZXN0aW9uIGZvciBmdXNpZm9ybSBmaXNoZXMsIGJlaW5nIGNvbXBhcmFibGUgdG8gc2VycmFuaWRzIGFuZCAqTGF0aW1lcmlhKiwgc2xpZ2h0bHkgbG93ZXIgdGhhbiBicmFtaWRzIChlLmcuLCAqVGFyYWN0ZXMqKSwgYW5kIHNvbWV3aGF0IHNpbWlsYXIgdG8gKGlmIGEgYml0IGxvd2VyIHRoYW4pIHRodW5uaW5zLiBTb21lIG9mIHRoaXMgbWF5IGJlIGJlY2F1c2UgdGhlIGFydGhyb2RpcmUgYm9keSBwbGFuIGlzIHNob3J0IGFuZCBzdG9ja3kgaW4gZ2VuZXJhbCBhbmQgdGh1cyAqRHVua2xlb3N0ZXVzKiByZXByZXNlbnRzIGEgbW9yZSBleHRyZW1lIHZlcnNpb24gb2YgdGhpcywgdGhpcyBjYW4gYmUgc2VlbiBpbiBob3cgdGF4YSBsaWtlIGxhbW5pZHMgYW5kIHRodW5uaW5zIHNob3cgYSBzaW1pbGFyIHBhdHRlcm4gb2YgaGF2aW5nIGxvdyBmaW5lbmVzcyByYXRpb3MgcmVsYXRpdmUgdG8gdGhlaXIgbm9uLXRodW5uaWZvcm0gcmVsYXRpdmVzLCBkZXNwaXRlIHRoZSBwcmVjaXNlICpmKiB2YWx1ZXMgaW4gYm90aCBncm91cHMgYmVpbmcgZGlmZmVyZW50LiBBbm90aGVyIHBvc3NpYmlsaXR5IG1heSBiZSB0aGlzIGlzIGFmZmVjdGVkIGJ5IHRoZSBzaG9ydGVyIHNub3V0cyBvZiBhcnRocm9kaXJlcyByZWxhdGl2ZSB0byBvdGhlciBldWduYXRob3N0b21lcyAoRW5nZWxtYW4gMjAyMykuIFByZW9yYml0YWwgbGVuZ3RoIGRvZXMgYWZmZWN0IGZpbmVuZXNzIHJhdGlvLCBhbmQgdGhlIHNob3J0LCBibHVudCBzbm91dHMgb2YgYXJ0aHJvZGlyZXMgd291bGQgYmUgZXhwZWN0ZWQgdG8gbmVnYXRpdmVseSBpbmZsdWVuY2UgZmluZW5lc3MgcmF0aW8gdG93YXJkcyBsb3dlciB2YWx1ZXMuDQoNCmBgYHtyLHdhcm5pbmc9Rn0NCnJiaW5kKGZpbmVuZXNzXzIgJT4lDQogIGRyb3BfbmEoYm9keV9kZXB0aCxwcmVjYXVkYWxfbGVuZ3RoKSAlPiUNCiAgZmlsdGVyKGNsYWRlPT0iQ2hvbmRyaWNodGh5ZXMiLA0KICAgICAgICAgIShvcmRlciAlaW4lIGMoIkNoaW1hZXJpZm9ybWVzIiwiUmhpbm9wcmlzdGlmb3JtZXMiKSkpICU+JQ0KICBtdXRhdGUoZj1wcmVjYXVkYWxfbGVuZ3RoL2JvZHlfZGVwdGgpICU+JQ0KICBzdW1tYXJpc2UoZj1tZWFuKGYpLGNsYWRlPXVuaXF1ZShjbGFkZSksLmJ5PXRheG9uKSAlPiUNCiAgc3VtbWFyaXNlKG1lYW49bWVhbihmKSxtZWRpYW49bWVkaWFuKGYpLG1pbj1taW4oZiksbWF4PW1heChmKSxuPW4oKSksDQogIA0KICBmaW5lbmVzc18yICU+JQ0KICAgIGZpbHRlcihvcmRlcj09IkxhbW5pZm9ybWVzIikgJT4lDQogIGRyb3BfbmEoYm9keV9kZXB0aCxwcmVjYXVkYWxfbGVuZ3RoKSAlPiUNCiAgbXV0YXRlKGY9cHJlY2F1ZGFsX2xlbmd0aC9ib2R5X2RlcHRoKSAlPiUNCiAgc3VtbWFyaXNlKGY9bWVhbihmKSxjbGFkZT11bmlxdWUoY2xhZGUpLC5ieT10YXhvbikgJT4lDQogIHN1bW1hcmlzZShtZWFuPW1lYW4oZiksbWVkaWFuPW1lZGlhbihmKSxtaW49bWluKGYpLG1heD1tYXgoZiksbj1uKCkpLA0KICANCiAgZmluZW5lc3NfMiAlPiUNCiAgICBmaWx0ZXIob3JkZXI9PSJDYXJjaGFyaGluaWZvcm1lcyIpICU+JQ0KICBkcm9wX25hKGJvZHlfZGVwdGgscHJlY2F1ZGFsX2xlbmd0aCkgJT4lDQogIG11dGF0ZShmPXByZWNhdWRhbF9sZW5ndGgvYm9keV9kZXB0aCkgJT4lDQogIHN1bW1hcmlzZShmPW1lYW4oZiksY2xhZGU9dW5pcXVlKGNsYWRlKSwuYnk9dGF4b24pICU+JQ0KICBzdW1tYXJpc2UobWVhbj1tZWFuKGYpLG1lZGlhbj1tZWRpYW4oZiksbWluPW1pbihmKSxtYXg9bWF4KGYpLG49bigpKSwNCiAgDQogIGZpbmVuZXNzXzIgJT4lDQogIGRyb3BfbmEoYm9keV9kZXB0aCxwcmVjYXVkYWxfbGVuZ3RoKSAlPiUNCiAgbXV0YXRlKGY9cHJlY2F1ZGFsX2xlbmd0aC9ib2R5X2RlcHRoKSAlPiUNCiAgc3VtbWFyaXNlKGY9bWVhbihmKSxjbGFkZT11bmlxdWUoY2xhZGUpLC5ieT10YXhvbikgJT4lDQogIHN1bW1hcmlzZShtZWFuPW1lYW4oZiksbWVkaWFuPW1lZGlhbihmKSxtaW49bWluKGYpLG1heD1tYXgoZiksbj1uKCkpLA0KICBmaW5lbmVzc18yICU+JQ0KICAgIGZpbHRlcihzaGFwZT09ImZ1c2lmb3JtIikgJT4lDQogIGRyb3BfbmEoYm9keV9kZXB0aCxwcmVjYXVkYWxfbGVuZ3RoKSAlPiUNCiAgbXV0YXRlKGY9cHJlY2F1ZGFsX2xlbmd0aC9ib2R5X2RlcHRoKSAlPiUNCiAgc3VtbWFyaXNlKGY9bWVhbihmKSxjbGFkZT11bmlxdWUoY2xhZGUpLC5ieT10YXhvbikgJT4lDQogIHN1bW1hcmlzZShtZWFuPW1lYW4oZiksbWVkaWFuPW1lZGlhbihmKSxtaW49bWluKGYpLG1heD1tYXgoZiksbj1uKCkpLA0KICANCiAgZmluZW5lc3NfMiAlPiUNCiAgICBmaWx0ZXIob3JkZXIyPT0iT3RoZXIgU2NvbWJyaWRhZSIpICU+JQ0KICBkcm9wX25hKGJvZHlfZGVwdGgscHJlY2F1ZGFsX2xlbmd0aCkgJT4lDQogIG11dGF0ZShmPXByZWNhdWRhbF9sZW5ndGgvYm9keV9kZXB0aCkgJT4lDQogIHN1bW1hcmlzZShmPW1lYW4oZiksY2xhZGU9dW5pcXVlKGNsYWRlKSwuYnk9dGF4b24pICU+JQ0KICBzdW1tYXJpc2UobWVhbj1tZWFuKGYpLG1lZGlhbj1tZWRpYW4oZiksbWluPW1pbihmKSxtYXg9bWF4KGYpLG49bigpKSwNCiAgDQogIGZpbmVuZXNzXzIgJT4lDQogICAgZmlsdGVyKG9yZGVyMiAlaW4lIGMoIlRodW5uaW5pICsgU2FyZGluaSIsIkdhc3Rlcm9jaGlzbWEiKSkgJT4lDQogIGRyb3BfbmEoYm9keV9kZXB0aCxwcmVjYXVkYWxfbGVuZ3RoKSAlPiUNCiAgbXV0YXRlKGY9cHJlY2F1ZGFsX2xlbmd0aC9ib2R5X2RlcHRoKSAlPiUNCiAgc3VtbWFyaXNlKGY9bWVhbihmKSxjbGFkZT11bmlxdWUoY2xhZGUpLC5ieT10YXhvbikgJT4lDQogIHN1bW1hcmlzZShtZWFuPW1lYW4oZiksbWVkaWFuPW1lZGlhbihmKSxtaW49bWluKGYpLG1heD1tYXgoZiksbj1uKCkpLA0KICANCmZpbmVuZXNzXzIgJT4lDQogIGRyb3BfbmEoYm9keV9kZXB0aCxwcmVjYXVkYWxfbGVuZ3RoKSAlPiUNCiAgICANCiAgZmlsdGVyKGNsYWRlPT0iUGxhY29kZXJtaSIsZmFtaWx5IT0iQ2FtdXJvcGlzY2lkYWUiKSAlPiUNCiAgbXV0YXRlKGY9cHJlY2F1ZGFsX2xlbmd0aC9ib2R5X2RlcHRoKSAlPiUNCiAgc3VtbWFyaXNlKGY9bWVhbihmKSxjbGFkZT11bmlxdWUoY2xhZGUpLC5ieT10YXhvbikgJT4lDQogIHN1bW1hcmlzZShtZWFuPW1lYW4oZiksbWVkaWFuPW1lZGlhbihmKSxtaW49bWluKGYpLG1heD1tYXgoZiksbj1uKCkpLA0KDQpmaW5lbmVzc18yICU+JQ0KICBkcm9wX25hKGJvZHlfZGVwdGgscHJlY2F1ZGFsX2xlbmd0aCkgJT4lDQogICAgDQogIGZpbHRlcihmYW1pbHk9PSJDYW11cm9waXNjaWRhZSIpICU+JQ0KICBtdXRhdGUoZj1wcmVjYXVkYWxfbGVuZ3RoL2JvZHlfZGVwdGgpICU+JQ0KICBzdW1tYXJpc2UoZj1tZWFuKGYpLGNsYWRlPXVuaXF1ZShjbGFkZSksLmJ5PXRheG9uKSAlPiUNCiAgc3VtbWFyaXNlKG1lYW49bWVhbihmKSxtZWRpYW49bWVkaWFuKGYpLG1pbj1taW4oZiksbWF4PW1heChmKSxuPW4oKSkNCg0KKSAlPiUNCiAgYWRkX2NvbHVtbihuYW1lPWMoIkVsYXNtb2JyYW5jaHMiLCJMYW1uaWRhZSIsIkNhcmNoYXJoaW5pZm9ybWVzIiwiQWxsIEZpc2hlcyIsIkFsbCBGdXNpZm9ybSBGaXNoZXMiLCJPdGhlciBTY29tYnJpZGFlIiwiVGh1bm5pbmksIFNhcmRpbmksIGFuZCBHYXN0ZXJvY2hpc21hIiwiTm9uLUNhbXVyb3Bpc2NpZCBBcnRocm9kaXJlcyIsIkNhbXVyb3Bpc2NpZGFlIikpICU+JQ0KICBjb2x1bW5fdG9fcm93bmFtZXMoIm5hbWUiKSAlPiUNCiAga2FibGUoZGlnaXRzPTIsYWxpZ249ImMiLGNhcHRpb249IlN1bW1hcnkgc3RhdGlzdGljcyBmb3IgZmluZW5lc3MgcmF0aW8gKDxpPmY8L2k+KSBmb3IgdmFyaW91cyBncm91cHMgb2YgaW50ZXJlc3QsIGFzIHNwZWNpZXMgYXZlcmFnZXMiLA0KICAgICAgICBjb2wubmFtZXMgPSBjKCJNZWFuIiwiTWVkaWFuIiwiTWluIiwiTWF4IiwiTiIpKSAlPiUNCiAga2FibGVfc3R5bGluZygpDQpgYGANCg0KIyMgSGVhZC1ib2R5IHByb3BvcnRpb25zIGluIEljaHRoeW9kZWN0aWZvcm1lcw0KDQpgYGB7cn0NCnJiaW5kKA0KZGF0YV9yZWNvbiAlPiUNCiAgZHJvcF9uYSh0b3RhbF9sZW5ndGgsaGVhZF9sZW5ndGgpICU+JQ0KICBmaWx0ZXIob3JkZXI9PSJJY2h0aHlvZGVjdGlmb3JtZXMiKSAlPiUNCiAgZ3JvdXBfYnkodGF4b24pICU+JQ0KICBzdW1tYXJpc2UoaGVhZF9sZW5ndGg9bWVhbihoZWFkX2xlbmd0aC90b3RhbF9sZW5ndGgpKSAlPiUNCiAgdW5ncm91cCgpICU+JQ0KICBzdW1tYXJpc2VfYXQodmFycyhoZWFkX2xlbmd0aCksDQogICAgICAgICAgICAgICBsaXN0KG1pbj1taW4sIFExPX5xdWFudGlsZSguLCBwcm9icyA9IDAuMDI1KSwNCiAgICAgICAgICAgICAgICAgICAgbWVhbj1tZWFuLG1lZGlhbj1tZWRpYW4sIFEzPX5xdWFudGlsZSguLCBwcm9icyA9IDAuOTc1KSwNCiAgICAgICAgICAgICAgICAgICAgbWF4PW1heCxuPWxlbmd0aCxzZD1zZCkpLA0KZGF0YV9yZWNvbiAlPiUNCiAgZHJvcF9uYSh0b3RhbF9sZW5ndGgsaGVhZF9sZW5ndGgpICU+JQ0KICBmaWx0ZXIoc2hhcGUhPSJhbmd1aWxsaWZvcm0iLA0KICAgICAgICAgbGVuZ3RoX2FzPT0idG90YWwgbGVuZ3RoIiwNCiAgICAgICAgIGNsYWRlIT0iUGxhY29kZXJtaSIsDQogICAgICAgICBvcmRlciE9IkljaHRoeW9kZWN0aWZvcm1lcyIpICU+JQ0KICBncm91cF9ieSh0YXhvbikgJT4lDQogIHN1bW1hcmlzZShoZWFkX2xlbmd0aD1tZWFuKGhlYWRfbGVuZ3RoL3RvdGFsX2xlbmd0aCkpICU+JQ0KICB1bmdyb3VwKCkgJT4lDQogIHN1bW1hcmlzZV9hdCh2YXJzKGhlYWRfbGVuZ3RoKSwNCiAgICAgICAgICAgICAgIGxpc3QobWluPW1pbiwgUTE9fnF1YW50aWxlKC4sIHByb2JzID0gMC4wMjUpLA0KICAgICAgICAgICAgICAgICAgICBtZWFuPW1lYW4sbWVkaWFuPW1lZGlhbiwgUTM9fnF1YW50aWxlKC4sIHByb2JzID0gMC45NzUpLA0KICAgICAgICAgICAgICAgICAgICBtYXg9bWF4LG49bGVuZ3RoLHNkPXNkKSksDQpkYXRhX3JlY29uICU+JQ0KICBkcm9wX25hKHRvdGFsX2xlbmd0aCxoZWFkX2xlbmd0aCkgJT4lDQogIGZpbHRlcihzaGFwZT09ImFuZ3VpbGxpZm9ybSIsDQogICAgICAgICBsZW5ndGhfYXM9PSJ0b3RhbCBsZW5ndGgiKSAlPiUNCiAgZ3JvdXBfYnkodGF4b24pICU+JQ0KICBzdW1tYXJpc2UoaGVhZF9sZW5ndGg9bWVhbihoZWFkX2xlbmd0aC90b3RhbF9sZW5ndGgpKSAlPiUNCiAgdW5ncm91cCgpICU+JQ0KICBzdW1tYXJpc2VfYXQodmFycyhoZWFkX2xlbmd0aCksDQogICAgICAgICAgICAgICBsaXN0KG1pbj1taW4sIFExPX5xdWFudGlsZSguLCBwcm9icyA9IDAuMDI1KSwNCiAgICAgICAgICAgICAgICAgICAgbWVhbj1tZWFuLG1lZGlhbj1tZWRpYW4sIFEzPX5xdWFudGlsZSguLCBwcm9icyA9IDAuOTc1KSwNCiAgICAgICAgICAgICAgICAgICAgbWF4PW1heCxuPWxlbmd0aCxzZD1zZCkpLA0KZGF0YV9yZWNvbiAlPiUNCiAgZHJvcF9uYSh0b3RhbF9sZW5ndGgsaGVhZF9sZW5ndGgpICU+JQ0KICBmaWx0ZXIoY2xhZGU9PSJQbGFjb2Rlcm1pIiwNCiAgICAgICAgIGxlbmd0aF9hcz09InRvdGFsIGxlbmd0aCIpICU+JQ0KICBncm91cF9ieSh0YXhvbikgJT4lDQogIHN1bW1hcmlzZShoZWFkX2xlbmd0aD1tZWFuKGhlYWRfbGVuZ3RoL3RvdGFsX2xlbmd0aCkpICU+JQ0KICB1bmdyb3VwKCkgJT4lDQogIHN1bW1hcmlzZV9hdCh2YXJzKGhlYWRfbGVuZ3RoKSwNCiAgICAgICAgICAgICAgIGxpc3QobWluPW1pbiwgUTE9fnF1YW50aWxlKC4sIHByb2JzID0gMC4wMjUpLA0KICAgICAgICAgICAgICAgICAgICBtZWFuPW1lYW4sbWVkaWFuPW1lZGlhbiwgUTM9fnF1YW50aWxlKC4sIHByb2JzID0gMC45NzUpLA0KICAgICAgICAgICAgICAgICAgICBtYXg9bWF4LG49bGVuZ3RoLHNkPXNkKSksDQpkYXRhX3JlY29uICU+JQ0KICBkcm9wX25hKHRvdGFsX2xlbmd0aCxoZWFkX2xlbmd0aCkgJT4lDQogIGZpbHRlcihjbGFkZT09IlBsYWNvZGVybWkiKSAlPiUNCiAgZ3JvdXBfYnkodGF4b24pICU+JQ0KICBzdW1tYXJpc2UoaGVhZF9sZW5ndGg9bWVhbihoZWFkX2xlbmd0aC90b3RhbF9sZW5ndGgpKSAlPiUNCiAgdW5ncm91cCgpICU+JQ0KICBzdW1tYXJpc2VfYXQodmFycyhoZWFkX2xlbmd0aCksDQogICAgICAgICAgICAgICBsaXN0KG1pbj1taW4sIFExPX5xdWFudGlsZSguLCBwcm9icyA9IDAuMDI1KSwNCiAgICAgICAgICAgICAgICAgICAgbWVhbj1tZWFuLG1lZGlhbj1tZWRpYW4sIFEzPX5xdWFudGlsZSguLCBwcm9icyA9IDAuOTc1KSwNCiAgICAgICAgICAgICAgICAgICAgbWF4PW1heCxuPWxlbmd0aCxzZD1zZCkpDQopICU+JQ0KICBhZGRfY29sdW1uKFNhbXBsZT1jKCJJY2h0aHlvZGVjdGlmb3JtZXMiLCJFeHRhbnQgbm9uLWFuZ3VpbGxpZm9ybSBmaXNoZXMiLCJBbmd1aWxsaWZvcm0gZmlzaGVzIiwiQXJ0aHJvZGlyYSIsIkFydGhyb2RpcmEgKGluY2x1ZGluZyBlc3RpbWF0ZWQgbGVuZ3RocykiKSkgJT4lDQogIG11dGF0ZShuPWFzLm51bWVyaWMobikscGVyY2VudGlsZT1wYXN0ZTAoIigiLHJvdW5kKFExLDMpLCLigJMiLHJvdW5kKFEzLDMpLCIpIiksDQogICAgICAgICBjb25maW50PXBhc3RlMCgiKCIscm91bmQobWVhbi0xLjk2KihzZC9zcXJ0KG4pKSwzKSwi4oCTIixyb3VuZChtZWFuKzEuOTYqKHNkL3NxcnQobikpLDMpLCIpIikpICU+JQ0KICBzZWxlY3QoU2FtcGxlLG4sbWluLG1lYW4sbWVkaWFuLG1heCxzZCxwZXJjZW50aWxlLGNvbmZpbnQpICU+JQ0KICBrYWJsZShkaWdpdHM9YygxLDEsMywzLDMsMyw0LDEsMSksYWxpZ249YygibCIsImMiLCJjIiwiYyIsImMiLCJjIiwiYyIsImMiLCJjIiksDQogICAgICAgIGNvbC5uYW1lcyA9IGMoIlNhbXBsZSIsIk4iLCJNaW5pbXVtIiwiTWVhbiIsIk1lZGlhbiIsIk1heGltdW0iLCJTdGFuZGFyZCBEZXYuIiwiOTUlIFF1YW50aWxlIiwiOTUlIENvbmZpZGVuY2UgSW50ZXJ2YWwiKSwNCiAgICAgICAgY2FwdGlvbj0iQ29tcGFyaXNvbiBvZiBoZWFkLXRvdGFsIGxlbmd0aCBwcm9wb3J0aW9ucyBpbiBJY2h0aHlvZGVjdGlmb3JtZXMgY29tcGFyZWQgdG8gb3RoZXIgZmlzaGVzIikgJT4lDQogIGthYmxlX3N0eWxpbmcoKQ0KYGBgDQoNClVuc3VycHJpc2luZ2x5LCBpY2h0aHlvZGVjdGlmb3JtcyBoYXZlIGEgcmVsYXRpdmVseSBzbWFsbCBoZWFkIGFtb25nIGZpc2hlcy4gV2hhdCBpcyBwZXJoYXBzIG1vcmUgc3VycHJpc2luZyBpcyBob3cgZXh0cmVtZSB0aGVpciBwcm9wb3J0aW9ucyBhcmUsIGJlaW5nIG91dHNpZGUgdGhlIDk1JSBxdWFudGlsZSBvZiBhbGwgZXhhbWluZWQgbGl2aW5nIGZpc2hlcyBhbmQgdGhlaXIgaGVhZHMgcHJvcG9ydGlvbmFsbHkgc21hbGxlciB0aGFuIGV2ZW4gbW9zdCB0YXhhIHdpdGggZWxvbmdhdGUgdHJ1bmtzIChlLmcuLCAqQW1hemljaHRoeXMqLCAqU2NvbWJlcm9tb3J1cyosICpDb3J5cGhhZW5hKikgd2l0aCB0aGUgZXhjZXB0aW9uIG9mICpDaGVpcm9jZW50cnVzKiwgKkFsZXBpc2F1cnVzKiwgKkljb3N0ZXVzKiwgYW5kICpTY29tYmVyb2lkZXMgbHlzYW4qLg0KDQpIb3dldmVyLCBJY2h0aHlvZGVjdGlmb3JtZXMgYXJlIGFsc28gKmNvbnNpc3RlbnQqIGluIHRoZWlyIGV4dHJlbWUgaGVhZC10cnVuayBwcm9wb3J0aW9ucy4gVGhlcmUgaXMgbGl0dGxlIHZhcmlhdGlvbiBpbiBoZWFkLXRydW5rIHByb3BvcnRpb25zIHdpdGhpbiB0aGUgZ3JvdXAgYW5kIGxpdHRsZSBldmlkZW5jZSBvZiBhbGxvbWV0cnkuIFRoaXMgc3VnZ2VzdHMgSWNodGh5b2RlY3RpZm9ybWVzIGhhdmUgY2lyY3VtdmVudGVkIHRoZSBvdGhlcndpc2UgZmFpcmx5IHJlc3RyaWN0aXZlIGNvbnN0cmFpbnRzIG9uIGhlYWQtdHJ1bmsgcHJvcG9ydGlvbnMgaW4gZmlzaGVzIGJ1dCB0aGVpciBwcm9wb3J0aW9ucyBzdWJzZXF1ZW50bHkgc3RhYmlsaXplZCBhcm91bmQgYSBuZXcgbG9jYWwgb3B0aW11bS4gVGhlIGh5cGVyLWVsb25nYXRlIGJvZGllcyBvZiBJY2h0aHlvZGVjdGlmb3JtZXMgc2hvdWxkIGJlIHJlZ2FyZGVkIGFuIGFwb21vcnBoeSB0aGF0IGNoYXJhY3Rlcml6ZXMgdGhlIGNsYWRlIChvciBhIG5vZGUgd2l0aGluIHRoZSBjbGFkZSwgbGlrZSBJY2h0aHlvZGVjdG9pZGVpKSwgc2ltaWxhciB0byB3aGF0IGhhcyBiZWVuIHByb3Bvc2VkIGZvciBMYW1wcmlmb3JtZXMgKEVuZ2VsbWFuIDIwMjMpLiBTdWNoIGV4dHJlbWUgcHJvcG9ydGlvbnMgc2hvdWxkIGJlIGNvbnNpZGVyZWQgdW5pcXVlIHRvIEljaHRoeW9kZWN0aWZvcm1lcyBhbmQgYXJlIHVubGlrZWx5IHRvIGJlIHByZXNlbnQgaW4gb3RoZXIgZmlzaGVzIHVubGVzcyBzdHJvbmcgZXZpZGVuY2UgZm9yIGEgaHlwZXItZWxvbmdhdGUgdHJ1bmsgaW4gdGhvc2UgdGF4YSBpcyBwcmVzZW50Lg0KDQpBcnRocm9kaXJlcyBnZW5lcmFsbHkgZG8gbm90IHNob3cgdGhlIGV4dHJlbWUgdHJ1bmsgZWxvbmdhdGlvbiBzZWVuIGluIGljaHRoeW9kZWN0aWZvcm1zICh3aGljaCBhcmUgc2lnbmlmaWNhbnRseSBtb3JlIGVsb25nYXRlLWJvZGllZCB0aGFuIGV2ZW4gKkFtYXppY2h0aHlzKiksIHN1Z2dlc3Rpbmcgc3VjaCBwcm9wb3J0aW9ucyBhcmUgdW5saWtlbHkgdG8gYmUgcHJlc2VudCBpbiAqRHVua2xlb3N0ZXVzLiogQSAqWGlwaGFjdGludXMqLWxpa2UgYm9keSBwbGFuIGZvciAqRHVua2xlb3N0ZXVzKiB3b3VsZCBhbHNvIHJlcXVpcmUgdmlvbGF0aW5nIHJlbGF0aW9uc2hpcHMgdGhhdCBhcmUgb3RoZXJ3aXNlIGNvbnNpc3RlbnQgd2l0aGluIEFydGhyb2RpcmEuIFRoZXNlIGluY2x1ZGUgcGVsdmljIGdpcmRsZSBwb3NpdGlvbiwgdGhlIGNvcnJlbGF0aW9uIG9mIHRoZSBlbmQgb2YgdGhlIHZlbnRyYWwgc2hpZWxkIHdpdGggdGhlIGxvY2F0aW9uIG9mIHRoZSBwZWx2aWMgZ2lyZGxlIGFuZCB2ZW50L2VuZCBvZiB0aGUgdmlzY2VyYWwgY2F2aXR5LCBhbmQgdGhlIHNjYWxpbmcgb2YgdmVudHJhbCBzaGllbGQgc2l6ZSByZWxhdGl2ZSB0byB0b3RhbCBsZW5ndGggKHNlZSBtYW51c2NyaXB0KS4gVGhlcmUgaXMgbm8gZXZpZGVuY2UgdGhhdCAqRHVua2xlb3N0ZXVzKiB3YXMgYW4gZXhjZXB0aW9uIGluIHRoZXNlIHJlZ2FyZHMsIGFuZCBpbmRlZWQgQ01DIFZQODI5NCBzdWdnZXN0cyBhbiBhcnJhbmdlbWVudCBzaW1pbGFyIHRvIG90aGVyIGFydGhyb2RpcmVzLiBJY2h0aHlvZGVjdGlmb3JtZXMgbm90YWJseSBkbyBub3QgZGlmZmVyIGZyb20gb3RoZXIgZmlzaGVzIGluIHRoZSBwb3NpdGlvbiBvZiB0aGVpciBwZWx2aWMgZmluIGFuZCB2ZW50IHJlbGF0aXZlIHRvIHRvdGFsIGxlbmd0aCAoc2VlIGJlbG93KSwgc3VnZ2VzdGluZyBldmVuIHRob3VnaCB0aGV5IGhhdmUgYSBoeXBlci1lbG9uZ2F0ZSB0cnVuayB0aGVpciBib2R5IHBsYW4gc3RpbGwgZm9sbG93cyBzb21lIG9mIHRoZSBnZW5lcmFsIHByb3BvcnRpb25hbCBwYXR0ZXJucyBpbiBmaXNoZXMuDQoNClRoaXMgaXMgdG8gYmUgZXhwZWN0ZWQuIEV2ZW4gaGlnaGx5IGNvbnN0cmFpbmVkIG1vcnBob2xvZ2ljYWwgb3IgYWxsb21ldHJpYyByZWxhdGlvbnNoaXBzIG9jY2FzaW9uYWxseSBzaG93IG91dGxpZXJzLCB3aGljaCBhcmUgZXhwZWN0ZWQgdG8gYmUgcGh5bG9nZW5ldGljYWxseSBjbHVzdGVyZWQgYXJvdW5kIG5vZGVzIHdoZXJlIG5vdmVsIG11dGF0aW9ucyBoYXZlIGFsbG93ZWQgY2lyY3VtdmVudGlvbiBvZiBwcmUtZXhpc3RpbmcgbW9ycGhvbG9naWNhbCBvciBkZXZlbG9wbWVudGFsIGNvbnN0cmFpbnRzIChXZXJkZWxpbiAxOTg3LCBTY2h3ZW5rIDE5OTUsIFdhZ25lciBhbmQgU2Nod2VuayAyMDAwKS4gT3RoZXIgcHJvcG9ydGlvbnMgaW4gaWNodGh5b2RlY3RpZm9ybWVzIChzdWNoIGFzIHByZXBlbHZpYyBsZW5ndGgsIHNlZSBiZWxvdykgYXJlIGNvbnNpc3RlbnQgd2l0aCBvdGhlciBmaXNoZXMuIFRoZSBjb25zaXN0ZW5jeSBpbiBhbnRlcm9wb3N0ZXJpb3IgaGVhZCBkaW1lbnNpb25zLCBwZWN0b3JhbC9wZWx2aWMgZmluIHBvc2l0aW9ucywgYW5kIHZlbnRyYWwgc2hpZWxkIGxlbmd0aCBpbiBhcnRocm9kaXJlcyAoaW5jbHVkaW5nICpEdW5rbGVvc3RldXMqKSBzdWdnZXN0IHRoYXQgKkR1bmtsZW9zdGV1cyogZGlkIG5vdCBleGhpYml0IGEgaHlwZXItZWxvbmdhdGUgYm9keSBwbGFuLg0KDQpUaHVzLCB0aGUgaHlwZXItZWxvbmdhdGUgYm9kaWVzIG9mIGljaHRoeW9kZWN0aWZvcm1zIGRvIG5vdCBpbnZhbGlkYXRlIGNvbmNsdXNpb25zIG9mIGEgc2hvcnRlciwgc3RvY2tpZXIgYm9keSBwbGFuIGZvciAqRHVua2xlb3N0ZXVzKiAoYXMgc29tZSBoYXZlIHByb3Bvc2VkIGluIHRoZSB3YWtlIG9mIEVuZ2VsbWFuIDIwMjMpLCBhbmQgdHJlYXRpbmcgdGhlIGNsZWFybHkgYXV0YXBvbW9ycGhpYyBwcm9wb3J0aW9ucyBvZiBvbmUgZmlzaCBncm91cCBhcyBhIHN1aXRhYmxlIGFuYWxvZ3VlIGZvciByZWNvbnN0cnVjdGluZyB0aGUgcHJvcG9ydGlvbnMgb3RoZXIgZmlzaGVzIGluIHRoZSBhYnNlbmNlIG9mIGFkZGl0aW9uYWwgbW9ycGhvbG9naWNhbCBldmlkZW5jZSBzdWdnZXN0aW5nIHRoZXkgYXJlIHJlYXNvbmFibGUgYW5hbG9ndWVzIGlzIG5vdCB0ZW5hYmxlLg0KDQojIyBTbm91dC1WZW50IExlbmd0aCAoU1ZMKQ0KDQojIyMgSGlzdG9ncmFtIG9mIFNWTCBQcm9wb3J0aW9ucw0KDQpgYGB7cixmaWcuaGVpZ2h0PTYuNSxmaWcuY2FwPSJIaXN0b2dyYW0gb2YgU1ZMIGFzIGEgcGVyY2VudGFnZSBvZiB0b3RhbCBsZW5ndGggYWNyb3NzIGduYXRob3N0b21lIHRheGEifQ0KcDFfc3ZsIDwtIGdncGxvdChyaGl6bywgYWVzKHgsIHkpKSArDQogICAgZ2VvbV9wb2x5Z29uKGZpbGwgPSAiZGFya2dyZXkiLGNvbG9yPSJibGFjayIsIGFscGhhID0gMC41KSArDQogICAgZ2VvbV9saW5lKGRhdGE9ZGF0YS5mcmFtZSh4PWMoMSwxKSx5PWMoMC4yNDcxNjcyMDAwLC0wLjAzKSkpKw0KICAgIGdlb21fbGluZShkYXRhPWRhdGEuZnJhbWUoeD1jKDAsMCkseT1jKDAuMTYyNzgzMTAwMCwtMC4wMykpKSsNCiAgICBnZW9tX2xpbmUoZGF0YT1kYXRhLmZyYW1lKHg9YygwLDAuNTAyLDAuNTAyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9YygwLjA1NSwwLjA1NSwwLjEyKSksDQogICAgICAgICAgICAgIGxpbmV3aWR0aD0xLjUsY29sb3I9InN0ZWVsYmx1ZSIpKw0KICAgIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoMCwwLjMzKSkrDQogICAgYW5ub3RhdGUoInRleHQiLGxhYmVsPSJzbm91dC12ZW50IGxlbmd0aCIseD0wLjUwMix5PTAuMDM1LGhqdXN0PTAuNSkrDQogICAgdGhlbWUoYXhpcy50aXRsZS54PWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICBheGlzLnRleHQueD1lbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgYXhpcy50aWNrcy54PWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICBheGlzLnRpdGxlLnk9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgIGF4aXMudGV4dC55PWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICBheGlzLnRpY2tzLnk9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgIGF4aXMubGluZS55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgIGF4aXMubGluZS54ID0gZWxlbWVudF9ibGFuaygpKSsNCiAgICB0aGVtZV92b2lkKCkNCg0KcDJfc3ZsIDwtIGRhdGFfcmVjb24gJT4lDQogIGRyb3BfbmEoU1ZMLHRvdGFsX2xlbmd0aCkgJT4lDQogIHN1bW1hcmlzZSguYnk9dGF4b24sZ2VudXM9dW5pcXVlKGdlbnVzKSxTVkw9bWVhbihTVkwpLHRvdGFsX2xlbmd0aD1tZWFuKHRvdGFsX2xlbmd0aCksDQogICAgICAgICAgICBzaGFwZT11bmlxdWUoc2hhcGUpLGNsYWRlPXVuaXF1ZShjbGFkZSkpICU+JQ0KICBnZ3Bsb3QoLixhZXMoU1ZML3RvdGFsX2xlbmd0aCkpICsNCiAgZ2VvbV90ZXh0KGRhdGE9LiAlPiUgZmlsdGVyKGdlbnVzICVpbiUgYygiRWxlY3Ryb3Bob3J1cyIsIkxvcGhvdGlzIikpICU+JQ0KICAgICAgICAgICAgICBncm91cF9ieShnZW51cykgJT4lIHN1bW1hcmlzZShnZW51cz11bmlxdWUoZ2VudXMpLFNWTD1tZWFuKFNWTCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvdGFsX2xlbmd0aD1tZWFuKHRvdGFsX2xlbmd0aCkpLA0KICAgICAgICAgICAgYWVzKGxhYmVsPWdlbnVzLHg9U1ZML3RvdGFsX2xlbmd0aCkseT1jKDMsMiksZm9udGZhY2U9MyxhbmdsZT05MCxoanVzdD0ibGVmdCIpKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwKSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDEpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKGZpbGw9Y2xhZGUpLGJpbndpZHRoPTAuMDEpKw0KICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0ID0gbWVhbihTVkwvdG90YWxfbGVuZ3RoKSksbGluZXR5cGU9ImRhc2hlZCIpICsNCiAgY29vcmRfY2FydGVzaWFuKHhsaW09YygwLDEpKSsNCiAgbGFicyh4PSJTbm91dC1WZW50IExlbmd0aC9Ub3RhbCBMZW5ndGgiLHk9IiMgb2YgU3BlY2llcyIsZmlsbD0iQ2xhZGUiKSsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPWMoMC44LDAuNzUpKQ0KDQpwMV9zdmwgLyBwMl9zdmwgKyBwbG90X2xheW91dChoZWlnaHRzID0gMToyKSAmIHRoZW1lKHBsb3QubWFyZ2luID0gbWFyZ2luKDAsIDIwLCAwLCAwKSkNCmBgYA0KDQpCYXNlZCBvbiB0aGlzLCBzbm91dC12ZW50IGxlbmd0aCBpcyBhcHByb3hpbWF0ZWx5IDUwLTYwJSBvZiB0b3RhbCBsZW5ndGggaW4gbW9zdCBmaXNoZXMuIFRoZSB0d28gYXJ0aHJvZGlyZXMgY29uc2lkZXJlZCwgKkNvY2Nvc3RldXMqIGFuZCAqSW5jaXNvc2N1dHVtKiwgaGF2ZSBwcm9wb3J0aW9uYWwgU1ZMcyBjbG9zZSB0byB0aGUgbWVhbiBmb3IgYWxsIGV4YW1pbmVkIGZpc2hlcy4NCg0KQSB0aGlyZCBzcGVjaW1lbiB3aXRoIHByZXNlcnZlZCBjbGFzcGVycywgcmVmZXJyZWQgdG8gKkRpY2tvc3RldXMgdGhyZWlwbGFuZGkqIChOSE1VSyBQViBQIDQ5NjYzKSBoYXMgYW4gZXN0aW1hdGVkIFNWTCBvZiA1NSUgcHJlc2VydmVkIGxlbmd0aC4gSG93ZXZlciwgdGhpcyBzcGVjaW1lbiBpcyBoaWdobHkgZGlzdG9ydGVkIGFzIHByZXNlcnZlZCBhbmQgbWF5IGJlIG1pc3Npbmcgc29tZSBvZiB0aGUgdGFpbC4gVGh1cywgdGhpcyBwcm9wb3J0aW9uIG1heSBiZSBhbiBvdmVyZXN0aW1hdGUsIGVzcGVjaWFsbHkgZ2l2ZW4gKkRpY2tvc3RldXMqIGlzIGNvbnNpZGVyZWQgYSBjbG9zZSByZWxhdGl2ZSBvZiAqQ29jY29zdGV1cyogKGJvdGggaW4gQ29jY29zdGVpZGFlKS4NCg0KQXNzdW1pbmcgdGhlIHZlbnQgb2YgKkFtYXppY2h0aHlzIHRyaW5hanN0aWNhZSogKEFBLk1FTS5EUy44KSB3YXMgbG9jYXRlZCBuZWFyIHRoZSBwb3N0ZXJpb3IgbGV2ZWwgb2YgdGhlIHBlbHZpYyBnaXJkbGUsIHRoaXMgd291bGQgbWVhbiBpdHMgU1ZMIHJlcHJlc2VudHMgfjU1JSBvZiB0b3RhbCBsZW5ndGguIFRoaXMgcmVzZW1ibGVzIHdoYXQgaXMgc2VlbiBpbiBzb21lIG90aGVyIHBlbGFnaWMgZmlzaGVzIChTY29tYnJpZGFlLCBMYW1uaWRhZSksIHdoZXJlIHRoZSBhYmRvbWVuIGlzIHNob3J0ZW5lZCBhbmQgdGhlIHZlbnQgZW5kcyB1cCBhdCBhIHNsaWdodGx5IG1vcmUgcG9zdGVyaW9yIHBvc2l0aW9uLg0KDQpBcnRocm9kaXJlcyBzZWVtIHRvIHNob3cgc2ltaWxhciB2ZW50IHBvc2l0aW9ucyBhbmQgcGF0dGVybnMgb2YgdmFyaWF0aW9uIGluIHRoaXMgZmVhdHVyZSB0byBldWduYXRob3N0b21lcy4gVGhlIGluZmVycmVkIG1vcmUgcG9zdGVyaW9yIHZlbnQgb2YgKkFtYXppY2h0aHlzKiBkb2VzIG5vdCBpbnZhbGlkYXRlICwgYmVjYXVzZSBpdCB3b3VsZCBhY3R1YWxseSBpbXBseSAqc21hbGxlciogbGVuZ3Rocy4gQXNzdW1pbmcgU1ZML3RvdGFsIGxlbmd0aCBwcm9wb3J0aW9ucyBzaW1pbGFyIHRvICpBbWF6aWNodGh5cyogd291bGQgcmVzdWx0IGluIGxlbmd0aHMgb2Ygb25seSB+MyBtIGZvciBDTU5IIDU3NjggYW5kIDMuNiBtIGZvciB0aGUgbGFyZ2VzdCBpbmRpdmlkdWFscyBvZiAqRHVua2xlb3N0ZXVzKiwgd2hpY2ggYXJlIGNsZWFybHkgdW5yZWFzb25hYmxlIGdpdmVuIHRoZSBleHRyZW1lIHRhcGVyaW5nIGl0IHdvdWxkIHJlcXVpcmUgb2YgdGhlIGNhdWRhbCBwZWR1bmNsZSByZWxhdGl2ZSB0byB0cnVuayBoZWlnaHQgKHNlZSBFbmdlbG1hbiAyMDIzIGZvciBtb3JlIGRpc2N1c3Npb24gb24gd2h5IHNob3J0ZXIgbGVuZ3RocyBhcmUgdW5saWtlbHkpLiBTVkwgaW4gKkR1bmtsZW9zdGV1cyogd291bGQgaGF2ZSB0byBiZSBzaWduaWZpY2FudGx5IHNtYWxsZXIgcmVsYXRpdmUgdG8gdG90YWwgbGVuZ3RoIGZvciBsYXJnZXIgc2l6ZSBlc3RpbWF0ZXMgdGhhbiBwcmVzZW50ZWQgaGVyZSB0byBiZSBqdXN0aWZpZWQuDQoNCmBgYHtyfQ0Kc3VtbWFyeShsbShsb2coU1ZMKX5sb2codG90YWxfbGVuZ3RoKSwNCiAgICAgICAgICAgZGF0YV9yZWNvbiAlPiUNCiAgICAgICAgICAgICBkcm9wX25hKFNWTCx0b3RhbF9sZW5ndGgpICU+JQ0KICAgICAgICAgICAgIGdyb3VwX2J5KHRheG9uKSAlPiUNCiAgICAgICAgICAgICBzdW1tYXJpc2UoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpLG1lYW4pKSkpDQpgYGANCg0KVGhlIGFsbG9tZXRyeSByZWdyZXNzaW9uIHNob3dzIFNWTCBpcyBuZWFybHkgaXNvbWV0cmljIHJlbGF0aXZlIHRvIHRvdGFsIGxlbmd0aC4NCg0KIyMjIENvbXBhcmluZyBjaG9uZHJpY2h0aHlhbnMgYW5kIG9zdGVpY2h0aHlhbnMNCg0KR2l2ZW4gdGhpcyBkYXRhIHNwYW5zIGEgdmVyeSBicm9hZCBzZWxlY3Rpb24gb2YgZmlzaGVzLCBpdCBpcyBuZWNlc3NhcnkgdG8gZGVtb25zdHJhdGUgdGhpcyBwcm9wb3J0aW9uIGlzIGNvbnNpc3RlbnQgYWNyb3NzIGZpc2hlcyBhbmQgZG9lcyBub3Qgc2hvdyBkaWZmZXJlbmNlcyBhc3NvY2lhdGVkIHdpdGggY2xhZGUtc3BlY2lmaWMgYm9keSBwbGFucy4NCg0KIyMjIyBCb3gtYW5kLVdoaXNrZXIgUGxvdA0KDQpgYGB7cix3YXJuaW5nPUYsZmlnLmNhcD0iQm94LWFuZC1XaGlza2VyIHBsb3Qgb2YgU1ZML3RvdGFsIGxlbmd0aCBpbiBnbmF0aG9zdG9tZXMgYnkgaGlnaGVyIGxldmVsIGNsYWRlIn0NCmRhdGFfcmVjb24gJT4lDQogIGRyb3BfbmEoU1ZMKSAlPiUNCiAgc3VtbWFyaXNlKFNWTD1tZWFuKFNWTCksdG90YWxfbGVuZ3RoPW1lYW4odG90YWxfbGVuZ3RoKSxzaGFwZT11bmlxdWUoc2hhcGUpLA0KICAgICAgICAgICAgY2xhZGU9dW5pcXVlKGNsYWRlKSxoYWJpdGF0PXVuaXF1ZShoYWJpdGF0KSwuYnk9dGF4b24pICU+JQ0KICBnZ3Bsb3QoLixhZXMoeD1TVkwvdG90YWxfbGVuZ3RoLHk9Y2xhZGUpKSArDQogIGdlb21fdmxpbmUoZGF0YT0uICU+JSBncm91cF9ieShjbGFkZSkgJT4lDQogICAgICAgICAgICAgICBzdW1tYXJpc2UocHJvcG9ydGlvbj1tZWFuKFNWTC90b3RhbF9sZW5ndGgpLGhhYml0YXQ9dW5pcXVlKHNoYXBlKSksDQogICAgICAgICAgICAgICBhZXMoeGludGVyY2VwdD1wcm9wb3J0aW9uLGNvbG9yPWNsYWRlKSxzaG93LmxlZ2VuZD1GKSsNCiAgZ2VvbV9wb2ludChkYXRhPS4gJT4lIGZpbHRlcihjbGFkZT09IlNhcmNvcHRlcnlnaWkiKSxzaGFwZT0yMSxhZXMoZmlsbD1jbGFkZSksDQogICAgICAgICAgICAgc2l6ZT0zLHNob3cubGVnZW5kPUYpKw0KICBnZW9tX3BvaW50KGRhdGE9LiAlPiUgZmlsdGVyKGNsYWRlPT0iUGxhY29kZXJtaSIpLHNoYXBlPTIxLGFlcyhmaWxsPWNsYWRlKSwNCiAgICAgICAgICAgICBzaXplPTMsc2hvdy5sZWdlbmQ9RikrDQogIGdlb21fdmlvbGluKGRhdGE9LiAlPiUgZmlsdGVyKCFjbGFkZSAlaW4lIGMoIlNhcmNvcHRlcnlnaWkiLCJQbGFjb2Rlcm1pIikpLA0KICAgICAgICAgICAgICBhZXMoZmlsbD1jbGFkZSksc2NhbGU9IndpZHRoIixzaG93LmxlZ2VuZD1GKSsNCiAgZ2VvbV9ib3hwbG90KGRhdGE9LiAlPiUgZmlsdGVyKCFjbGFkZSAlaW4lIGMoIlNhcmNvcHRlcnlnaWkiLCJQbGFjb2Rlcm1pIikpLA0KICAgICAgICAgICAgICAgd2lkdGg9MC4yNSkrDQogIGNvb3JkX2NhcnRlc2lhbih4bGltPWMoMCwxKSkrDQogIGxhYnMoeD0iU25vdXQtVmVudCBMZW5ndGgvVG90YWwgTGVuZ3RoIix5PSJCb2R5IFNoYXBlIixmaWxsPSJCb2R5IFNoYXBlIikNCmBgYA0KDQojIyMjIE1hbm4tV2hpdG5leSBVIFRlc3QgYmV0d2VlbiBDaG9uZHJpY2h0aHlhbnMgYW5kIE9zdGVpY2h0aHlhbnMNCg0KTm90ZTogYSB0d28tc2FtcGxlIFdpbGNveG9uIFJhbmsgU3VtIHRlc3QgaXMgdGhlIHNhbWUgdGhpbmcgYXMgYSBNYW5uLVdoaXRuZXkgVSB0ZXN0Lg0KDQpgYGB7cn0NCndpbGNveC50ZXN0KA0KICBkYXRhX3JlY29uICU+JSBmaWx0ZXIoY2xhZGU9PSJDaG9uZHJpY2h0aHllcyIpICU+JQ0KICAgIGRyb3BfbmEoU1ZMKSAlPiUNCiAgICBtdXRhdGUocHJvcG9ydGlvbj1TVkwvdG90YWxfbGVuZ3RoKSAlPiUNCiAgICBncm91cF9ieSh0YXhvbikgJT4lDQogICAgc3VtbWFyaXNlKHByb3BvcnRpb249bWVhbihwcm9wb3J0aW9uKSkgJT4lDQogICAgcHVsbChwcm9wb3J0aW9uKSwNCiAgZGF0YV9yZWNvbiAlPiUgZmlsdGVyKGNsYWRlICVpbiUgYygiU2FyY29wdGVyeWdpaSIsIkFjdGlub3B0ZXJ5Z2lpIikpICU+JQ0KICAgIGRyb3BfbmEoU1ZMKSAlPiUNCiAgICBtdXRhdGUocHJvcG9ydGlvbj1TVkwvdG90YWxfbGVuZ3RoKSAlPiUNCiAgICBncm91cF9ieSh0YXhvbikgJT4lDQogICAgc3VtbWFyaXNlKHByb3BvcnRpb249bWVhbihwcm9wb3J0aW9uKSkgJT4lDQogICAgcHVsbChwcm9wb3J0aW9uKSkNCmBgYA0KDQpCYXNlZCBvbiB0aGUgTWFubi1XaGl0bmV5IFUgdGVzdCwgdGhlcmUgaXMgbm8gc2lnbmlmaWNhbnQgZGlmZmVyZW5jZSBpbiB2ZW50IHBvc2l0aW9uIHJlbGF0aXZlIHRvIHRvdGFsIGxlbmd0aCBpbiBjaG9uZHJpY2h0aHlhbnMgYW5kIG9zdGVpY2h0aHlhbnMuIFNhbXBsZSBzaXplcyBhcmUgdG9vIHNtYWxsIHRvIGRpcmVjdGx5IGNvbXBhcmUgYXJ0aHJvZGlyZXMgdG8gdGhlc2Ugb3RoZXIgZ3JvdXBzLCBidXQgYmFzZWQgb24gdGhlIGF2YWlsYWJsZSBkYXRhIHRoZXkgcmVzZW1ibGUgYm90aCBvZiB0aGVzZSBncm91cHMgaW4gdmVudCBwb3NpdGlvbi4gVmVudCBwb3NpdGlvbiBpbiBnZW5lcmFsIHNlZW1zIHRvIGJlIGNvbnNpc3RlbnQgYWNyb3NzIGduYXRob3N0b21lcy4NCg0KU29tZSBzYXJjb3B0ZXJ5Z2lhbnMgaGF2ZSBhIG1vcmUgcG9zdGVyaW9yIHBvc2l0aW9uIG9mIHRoZSBwZWx2aWMgZmlucyBzdWdnZXN0aW5nIHRoZSB2ZW50IG1heSBtb3JlIHBvc3Rlcmlvcmx5IHBvc2l0aW9uZWQgaW4gdGhlc2UgZm9ybXMgKGUuZy4sIE9zdGVvbGVwaWZvcm1lcykuIEhvd2V2ZXIsIHRoaXMgYXBwZWFycyB0byBiZSBhIGRlcml2ZWQgY29uZGl0aW9uIGdpdmVuIHRoZSB2ZW50IGluIGNvZWxhY2FudGhzIGlzIGluIGEgc2ltaWxhciBwb3NpdGlvbiB0byBjaG9uZHJpY2h0aHlhbnMgYW5kIGFjdGlub3B0ZXJ5Z2lhbnMgKEx1bmQgYW5kIEx1bmQgMTk4NCwgTWlsbG90IGV0IGFsLiAxOTc4LCBTYXJ1d2F0YXJpIGV0IGFsLiAyMDE5KS4NCg0KIyMjIyBQb3NpdGlvbiBvZiBWZW50IFJlbGF0aXZlIHRvIFBlbHZpYyBhbmQgQW5hbCBGaW5zDQoNCihyZWY6dmVudHBvc2l0aW9uKSBQb3NpdGlvbiBvZiB0aGUgdmVudCByZWxhdGl2ZSB0byB0aGUgcGVsdmljIGFuZCBhbmFsIGZpbiBvcmlnaW5zLiBEYXRhIGFyZSByZXBvcnRlZCBhcyBsZW5ndGggZnJvbSBwZWx2aWMgb3JpZ2luIHRvIHZlbnQgYXMgYSBwcm9wb3J0aW9uIG9mIHByZXBlbHZpYy1wcmVhbmFsIHNwYWNlLg0KDQpgYGB7cixmaWcuaGVpZ2h0PTYuNSxmaWcuY2FwPSIocmVmOnZlbnRwb3NpdGlvbikiLHdhcm5pbmc9Rn0NCmxldmVsX2luZm8gPC0gZGF0YV9yZWNvbiAlPiUNCiAgbXV0YXRlKGhpZ2hlcl9ncm91cD1mYWN0b3IoaGlnaGVyX2dyb3VwLG9yZGVyZWQ9VCxsZXZlbHM9YygiQXJ0aHJvZGlyYSIsIkNob25kcmljaHRoeWVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNhcmNvcHRlcnlnaWkiLCJCYXNhbCBBY3Rpbm9wdGVyeWdpaSIsIkJhc2FsIFRlbGVvc3RlaSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJPdG9jZXBoYWxhIiwiU3RlbSBFdXRlbGVvc3RlaSIsIkFjYW50aG9wdGVyeWdpaSIpKSkgJT4lDQogIGRyb3BfbmEoaGlnaGVyX2dyb3VwLG9yZGVyKSAlPiUNCiAgYXJyYW5nZShoaWdoZXJfZ3JvdXAsIG9yZGVyKSAlPiUgDQogIHB1bGwob3JkZXIpICU+JSANCiAgdW5pcXVlKCkNCg0KZGF0YV9yZWNvbiAlPiUNCiAgZHJvcF9uYShwcmVwZWx2aWNfbGVuZ3RoLFNWTCxwcmVhbmFsX2xlbmd0aCkgJT4lDQogIGdyb3VwX2J5KHRheG9uKSAlPiUNCiAgc3VtbWFyaXNlKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSxtZWFuKSwNCiAgICAgICAgICAgIG9yZGVyPXVuaXF1ZShvcmRlciksDQogICAgICAgICAgICBoaWdoZXJfZ3JvdXA9dW5pcXVlKGhpZ2hlcl9ncm91cCkpICU+JQ0KICBtdXRhdGUodmVudGVyPXByZWFuYWxfbGVuZ3RoLXByZXBlbHZpY19sZW5ndGgsDQogICAgICAgICBvcmRlcjI9ZmFjdG9yKG9yZGVyLGxldmVscz1yZXYobGV2ZWxfaW5mbykpKSAlPiUNCiAgZ2dwbG90KC4sYWVzKHg9KChTVkwtcHJlcGVsdmljX2xlbmd0aCkvdmVudGVyKSx5PW9yZGVyMikpICsNCiAgbGFicyh4PSJQb3NpdGlvbiBvZiBWZW50IGFzIGEgUGVyY2VudCBvZiBQcmVwZWx2aWMtUHJlYW5hbCBTcGFjZSIsDQogICAgICAgeT0iT3JkZXIiKSArDQogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9MCkpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudCkrDQogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9MSkpICsNCiAgZ2VvbV92aW9saW4oYWVzKGZpbGw9aGlnaGVyX2dyb3VwKSxzY2FsZT0id2lkdGgiLHNob3cubGVnZW5kPUYpICsNCiAgZ2VvbV9ib3hwbG90KHdpZHRoPTAuMykNCmBgYA0KDQpUaGUgdmVudCBpcyBjbGVhcmx5IG11Y2ggY2xvc2VyIHRvIHRoZSBwZWx2aWMgZmluIGJhc2UgaW4gYXJ0aHJvZGlyZXMgYW5kIGNob25kcmljaHRoeWFucyBhbmQgbXVjaCBjbG9zZXIgdG8gdGhlIGFuYWwgZmluIGluIHRlbGVvc3RzLiBTb21lIGdyb3VwcyBsaWtlIFNpbHVyaWZvcm1lcyBhY3R1YWxseSBzaG93IGFuIGludGVybWVkaWF0ZSB2ZW50IHBvc2l0aW9uLCB3aGVyZWFzIGluIG1hbnkgYWNhbnRob3B0ZXJ5Z2lhbnMgYmVjYXVzZSB0aGUgcGVsdmljIGZpbnMgYXJlIHNvIGFudGVyaW9yIHRoZXJlIGNhbiBzdGlsbCBiZSBhIHN1YnN0YW50aWFsIHNwYWNlIGJldHdlZW4gdGhlIHZlbnQgYW5kIGFuYWwgZmlucywgZGVzcGl0ZSB0aGlzIHZhbHVlIGFzIGEgcGVyY2VudCBvZiBwcmVwZWx2aWMtcHJlYW5hbCBsZW5ndGggYmVpbmcgc2ltaWxhciB0byBvdGhlciB0ZWxlb3N0cy4gQmVjYXVzZSB2ZW50IHBvc2l0aW9uIGlzIHNvIGNvbnNpc3RlbnQgYW1vbmcgZ25hdGhvc3RvbWVzLCB0aGlzIHN1Z2dlc3RzIGFjdHVhbGx5IHJlcHJlc2VudHMgYSBzaGlmdCBvZiB0aGUgZmluIGJhc2VzIHJlbGF0aXZlIHRvIGEgY29uc2VydmVkIHZlbnQsIHJhdGhlciB0aGFuIGFuIGFjdHVhbCBjaGFuZ2UgaW4gdmVudCBwb3NpdGlvbi4NCg0KVGhlIGRhdGEgcG9pbnRzIHdpdGggdmVudCBwb3NpdGlvbiBncmVhdGVyIHRoYW4gMTAwJSBwcmVwZWx2aWMtcHJlYW5hbCBsZW5ndGggYXJlIGNhc2VzIHdoZXJlIHNub3V0LXZlbnQgbGVuZ3RoIHdhcyBub3QgcmVwb3J0ZWQgZGlyZWN0bHkgYW5kIGhhZCB0byBiZSBjYWxjdWxhdGVkIGFzIHRoZSBzdW0gb2YgcmVwb3J0ZWQgcHJlcGVsdmljIGxlbmd0aCArIHBlbHZpYyBvcmlnaW4tdG8tdmVudCBsZW5ndGguIFByZXBlbHZpYyBsZW5ndGggbWF5IGhhdmUgYmVlbiBtZWFzdXJlZCBwb2ludC10by1wb2ludCAob2JsaXF1ZSB0byB0aGUgYW50ZXJvcG9zdGVyaW9yIGF4aXMpIGFuZCB0aHVzIHN1bW1pbmcgdGhlc2UgdmFsdWVzIGlzIGEgc2xpZ2h0IG92ZXJhcHByb3hpbWF0aW9uIG9mIFNWTC4NCg0KIyMjIFRlc3RpbmcgZm9yIGRpZmZlcmVuY2VzIGJhc2VkIG9uIGJvZHkgc2hhcGUNCg0KTm90ZSwgKkVsZWN0cm9waG9ydXMqIGFuZCAqTG9waG90aXMqIHNwcC4gYXJlIG5vdCBpbmNsdWRlZCBpbiB0aGlzIGFuYWx5c2lzIGJlY2F1c2UgdGhleSByZXByZXNlbnQgc2lnbmlmaWNhbnQgb3V0bGllcnMuDQoNCmBgYHtyLGZpZy5jYXA9IkJveC1hbmQtd2hpc2tlciBwbG90IG9mIFNWTCBhcyBhIHByb3BvcnRpb24gb2YgdG90YWwgbGVuZ3RoIGluIGV4dGFudCBmaXNoZXMiLHdhcm5pbmc9Rn0NCmRhdGFfcmVjb24gJT4lDQogIGRyb3BfbmEoU1ZMKSAlPiUNCiAgZmlsdGVyKCFnZW51cyAlaW4lIGMoIkVsZWN0cm9waG9ydXMiLCJMb3Bob3RpcyIpKSAlPiUNCiAgZ3JvdXBfYnkodGF4b24pICU+JQ0KICBzdW1tYXJpc2UoU1ZMPW1lYW4oU1ZMKSx0b3RhbF9sZW5ndGg9bWVhbih0b3RhbF9sZW5ndGgpLHNoYXBlPXVuaXF1ZShzaGFwZSksY2xhZGU9dW5pcXVlKGNsYWRlKSxoYWJpdGF0PXVuaXF1ZShoYWJpdGF0KSkgJT4lDQogIGdncGxvdCguLGFlcyh4PVNWTC90b3RhbF9sZW5ndGgseT1zaGFwZSkpICsNCiAgZ2VvbV92bGluZShkYXRhPS4gJT4lIGdyb3VwX2J5KHNoYXBlKSAlPiUNCiAgICAgICAgICAgICAgIHN1bW1hcmlzZShwcm9wb3J0aW9uPW1lYW4oU1ZML3RvdGFsX2xlbmd0aCksaGFiaXRhdD11bmlxdWUoc2hhcGUpKSwNCiAgICAgICAgICAgICAgIGFlcyh4aW50ZXJjZXB0PXByb3BvcnRpb24sY29sb3I9c2hhcGUpLHNob3cubGVnZW5kPUYpKw0KICBnZW9tX3Zpb2xpbihhZXMoZmlsbD1zaGFwZSksc2NhbGU9IndpZHRoIixzaG93LmxlZ2VuZD1GKSsNCiAgZ2VvbV9ib3hwbG90KHdpZHRoPTAuMjUpKw0KICBjb29yZF9jYXJ0ZXNpYW4oeGxpbT1jKDAsMSkpKw0KICBsYWJzKHg9IlNub3V0LVZlbnQgTGVuZ3RoL1RvdGFsIExlbmd0aCIseT0iQm9keSBTaGFwZSIsZmlsbD0iQm9keSBTaGFwZSIpKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb249YygwLjE1LDAuNzUpKQ0KYGBgDQoNCkJhc2VkIG9uIHRoaXMsIHRoZXJlIGFwcGVhcnMgdG8gYmUgcmVsYXRpdmVseSBsaXR0bGUgdmFyaWF0aW9uIGluIHZlbnQgcG9zaXRpb24gYmFzZWQgb24gYm9keSBzaGFwZS4gRXZlbiBhbmd1aWxsaWZvcm0gdGF4YSBnZW5lcmFsbHkgaGF2ZSBhbnVzZXMgbG9jYXRlZCBjbG9zZSB0byB0aGUgbWlkcG9pbnQgb2YgdGhlIGJvZHkuIE1hY3J1cmlmb3JtIHRheGEgYXJlIGFuIGV4Y2VwdGlvbiwgcHJpbWFyaWx5IGJlY2F1c2UgdGhlIGV4dHJlbWVseSBlbG9uZ2F0ZSBjYXVkYWwgZmluIGluIHRoZXNlIHNwZWNpZXMgcmVzdWx0cyBpbiBhIGdyZWF0ZXIgdG90YWwgbGVuZ3RoIHJlbGF0aXZlIHRvIFNWTC4gVGhlIGNhdWRhbCBmaW4gb2YgbWFjcnVyaWZvcm0gdGF4YSBkb2VzIG5vdCBhcHBlYXIgdG8gYmUgY29uc3RyYWluZWQgYnkgdGhlIHNhbWUgZmFjdG9ycyB0aGF0IHJlc3RyaWN0IHByb3BvcnRpb25hbCByZWxhdGlvbnNoaXBzIGluIG90aGVyIGZpc2hlcyAoc2VlIEVuZ2VsbWFuIDIwMjMpLg0KDQojIyMgQm94IGFuZCBXaGlza2VyIFBsb3QgYnkgSGFiaXR1cw0KDQpgYGB7cixmaWcuY2FwPSJCb3gtYW5kLXdoaXNrZXIgcGxvdCBvZiBTVkwgYXMgYSBwcm9wb3J0aW9uIG9mIHRvdGFsIGxlbmd0aCBpbiBleHRhbnQgZmlzaGVzLCBncm91cGVkIGJ5IGxpZmUgaGFiaXRzIix3YXJuaW5nPUZ9DQpkYXRhX3JlY29uICU+JQ0KICBkcm9wX25hKFNWTCx0b3RhbF9sZW5ndGgsaGFiaXRhdCkgJT4lDQogIHN1bW1hcmlzZSguYnk9dGF4b24sDQogICAgICAgICAgICBTVkw9bWVhbihTVkwpLHRvdGFsX2xlbmd0aD1tZWFuKHRvdGFsX2xlbmd0aCksc2hhcGU9dW5pcXVlKHNoYXBlKSwNCiAgICAgICAgICAgIGNsYWRlPXVuaXF1ZShjbGFkZSksaGFiaXRhdD11bmlxdWUoaGFiaXRhdCkpICU+JQ0KICBnZ3Bsb3QoLixhZXMoeD1TVkwvdG90YWxfbGVuZ3RoLHk9aGFiaXRhdCkpICsNCiAgZ2VvbV92bGluZShkYXRhPS4gJT4lDQogICAgICAgICAgICAgICBzdW1tYXJpc2UoLmJ5PWhhYml0YXQsDQogICAgICAgICAgICAgICAgICAgICAgICAgcHJvcG9ydGlvbj1tZWFuKFNWTC90b3RhbF9sZW5ndGgpKSwNCiAgICAgICAgICAgICAgIGFlcyh4aW50ZXJjZXB0PXByb3BvcnRpb24sY29sb3I9aGFiaXRhdCksc2hvdy5sZWdlbmQ9RikrDQogIGdlb21fdmlvbGluKGFlcyhmaWxsPWhhYml0YXQpLHNjYWxlPSJ3aWR0aCIsc2hvdy5sZWdlbmQ9RikrDQogIGdlb21fYm94cGxvdCh3aWR0aD0wLjI1KSsNCiAgY29vcmRfY2FydGVzaWFuKHhsaW09YygwLDEpKSsNCiAgbGFicyh4PSJTbm91dC1WZW50IExlbmd0aC9Ub3RhbCBMZW5ndGgiLHk9IkhhYml0dXMiLGZpbGw9IkhhYml0dXMiKQ0KYGBgDQoNCkJhc2VkIG9uIHRoZXNlIHJlc3VsdHMgYmVudGhpYyB0YXhhIHNlZW0gdG8gaGF2ZSBhIG1vcmUgYW50ZXJpb3IgdmVudCByZWxhdGl2ZSB0byB0b3RhbCBsZW5ndGgsIHdoZXJlYXMgcGVsYWdpYyBmb3JtcyBoYXZlIGEgbW9yZSBwb3N0ZXJpb3IgdmVudCByZWxhdGl2ZSB0byB0b3RhbCBsZW5ndGguIFRoZSBtb3JlIGFudGVyaW9yIHBvc2l0aW9uIGluIGJlbnRoaWMgdGF4YSBzZWVtcyB0byBiZSBkcml2ZW4gYnkgdGhlIGVsb25nYXRlIGNhdWRhbCBmaW5zIGluIG1hbnkgZm9ybXMgKGUuZy4sICpTdGVnb3N0b21hIHRpZ3JpbnVtKikuIEJ5IGNvbnRyYXN0LCB0aGUgbG9uZ2VyIFNWTCByZWxhdGl2ZSB0byBib2R5IGxlbmd0aCBpbiBwZWxhZ2ljIGZvcm1zIG1heSBiZSByZWxhdGVkIHRvIHRoZW0gbW9yZSBhdHRlbnVhdGVkIGFiZG9tZW4gb2YgdGhlc2UgdGF4YS4NCg0KYGBge3IsZmlnLmNhcD0iQm94LWFuZC13aGlza2VyIHBsb3Qgb2YgU1ZMIGFzIGEgcHJvcG9ydGlvbiBvZiBwcmVjYXVkYWwgbGVuZ3RoIGluIGV4dGFudCBmaXNoZXMsZ3JvdXBlZCBieSBsaWZlIGhhYml0cyIsd2FybmluZz1GfQ0KZGF0YV9yZWNvbiAlPiUNCiAgZ3JvdXBfYnkodGF4b24pICU+JQ0KICBkcm9wX25hKHByZWNhdWRhbF9sZW5ndGgsU1ZMKSAlPiUNCiAgc3VtbWFyaXNlKFNWTD1tZWFuKFNWTCkscHJlY2F1ZGFsX2xlbmd0aD1tZWFuKHByZWNhdWRhbF9sZW5ndGgpLHNoYXBlPXVuaXF1ZShzaGFwZSksDQogICAgICAgICAgICBjbGFkZT11bmlxdWUoY2xhZGUpLGhhYml0YXQ9dW5pcXVlKGhhYml0YXQpKSAlPiUNCiAgZ2dwbG90KC4sYWVzKHg9U1ZML3ByZWNhdWRhbF9sZW5ndGgseT1oYWJpdGF0KSkgKw0KICBnZW9tX3ZsaW5lKGRhdGE9LiAlPiUgZ3JvdXBfYnkoaGFiaXRhdCkgJT4lDQogICAgICAgICAgICAgICBzdW1tYXJpc2UocHJvcG9ydGlvbj1tZWFuKFNWTC9wcmVjYXVkYWxfbGVuZ3RoKSxoYWJpdGF0PXVuaXF1ZShoYWJpdGF0KSksDQogICAgICAgICAgICAgICBhZXMoeGludGVyY2VwdD1wcm9wb3J0aW9uLGNvbG9yPWhhYml0YXQpLHNob3cubGVnZW5kPUYpKw0KICBnZW9tX3Zpb2xpbihhZXMoZmlsbD1oYWJpdGF0KSkrDQogIGdlb21fYm94cGxvdCh3aWR0aD0wLjI1KSsNCiAgY29vcmRfY2FydGVzaWFuKHhsaW09YygwLDEpKSsNCiAgbGFicyh4PSJTbm91dC1WZW50IExlbmd0aC9QcmVjYXVkYWwgTGVuZ3RoIix5PSJIYWJpdHVzIixmaWxsPSJIYWJpdHVzIikrDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj1jKDAuMTUsMC43NSkpDQpgYGANCg0KSG93ZXZlciwgZXZlbiB3aGVuIGNvbnNpZGVyaW5nIFNWTCBhcyBhIHByb3BvcnRpb24gb2YgcHJlY2F1ZGFsIGxlbmd0aCBwZWxhZ2ljIHRheGEgc3RpbGwgaGF2ZSBtb3JlIHBvc3Rlcmlvcmx5IHBsYWNlZCB2ZW50cyBhbmQgYmVudGhpYyB0YXhhIGhhdmUgbW9yZSBhbnRlcmlvcmx5IHBsYWNlZCBvbmVzLiBJLmUuLCBiZW50aGljIHRheGEgc2VlbSB0byBoYXZlIHNsaWdodGx5IGxvbmdlciBhYmRvbWVucywgYW5kIHBlbGFnaWMgdGF4YSBoYXZlIHNsaWdodGx5IHNob3J0ZXIgb25lcy4NCg0KTW9yZSBkYXRhIGFyZSBuZWVkZWQsIGJ1dCB0aGUgcHJlc2VudCBkYXRhc2V0IGltcGxpZXMgKkR1bmtsZW9zdGV1cyogY291bGQgcG90ZW50aWFsbHkgaGF2ZSBhIG1vcmUgcG9zdGVyaW9ybHkgcG9zaXRpb25lZCB2ZW50IHJlbGF0aXZlIHRvIHRvdGFsIGxlbmd0aCB0aGFuICpDb2Njb3N0ZXVzKiBhbmQgKkluY2lzb3NjdXR1bSosIGdpdmVuIHRoZSBzaG9ydGVyIGFiZG9tZW5zIHNlZW4gaW4gbWFueSBwZWxhZ2ljIGZpc2hlcy4NCg0KIyMjIEFwcHJveGltYXRlIHZlbnQgcG9zaXRpb24gaW4gSWNodGh5b2RlY3RpZm9ybWVzDQoNCmBgYHtyfQ0KZGF0YV9yZWNvbiAlPiUNCiAgZmlsdGVyKG9yZGVyPT0iSWNodGh5b2RlY3RpZm9ybWVzIikgJT4lDQogIG11dGF0ZShyYXRpbzE9cHJlYW5hbF9sZW5ndGgvdG90YWxfbGVuZ3RoLA0KICAgICAgICAgcmF0aW8yPSgoKHByZXBlbHZpY19sZW5ndGgrcHJlYW5hbF9sZW5ndGgpLzIpL3RvdGFsX2xlbmd0aCkpICU+JQ0KICBncm91cF9ieSh0YXhvbikgJT4lDQogIHN1bW1hcmlzZShyYXRpbzE9bWVhbihyYXRpbzEpLHJhdGlvMj1tZWFuKHJhdGlvMikpICU+JQ0KICB1bmdyb3VwKCkgJT4lDQogIHN1bW1hcmlzZShyYXRpbzE9bWVhbihyYXRpbzEpLHJhdGlvMj1tZWFuKHJhdGlvMiksTj1uKCkpICU+JQ0KICBrYWJsZShjYXB0aW9uPSJBcHByb3hpbWF0ZSBsb2NhdGlvbiBvZiB0aGUgdmVudCBpbiBJY2h0aHlvZGVjdGlmb3JtZXMgYXMgYSBwZXJjZW50YWdlIG9mIHRvdGFsIGxlbmd0aCIsDQogICAgICAgIGRpZ2l0cz0zLGFsaWduPSJjIixjb2wubmFtZXMgPSBjKCJBc3N1bWluZyB2ZW50IGlzIGxvY2F0ZWQgYXQgYW5hbCBmaW4gYmFzZSIsICJBc3N1bWluZyB2ZW50IGlzIGludGVybWVkaWF0ZSBiZXR3ZWVuIHBlbHZpYyBhbmQgYW5hbCBmaW4gb3JpZ2lucyIsIk4gU3BlY2llcyIpKSAlPiUNCiAga2FibGVfc3R5bGluZygpDQpgYGANCg0KQXNzdW1pbmcgdGhlIHZlbnQgaXMgYmV0d2VlbiB0aGUgcGVsdmljIGFuZCBhbmFsIGZpbnMsIGFzIGlzIHRoZSBjYXNlIGluIG1vc3QgZmlzaGVzLCBvciBjbG9zZSB0byB0aGUgYmFzZSBvZiB0aGUgYW5hbCBmaW4sIGFzIGluIG1vc3QgYWN0aW5vcHRlcnlnaWFucywgcHJvcG9ydGlvbmFsIFNWTCBpbiBJY2h0aHlvZGVjdGlmb3JtZXMgaXMgc2ltaWxhciB0byBvdGhlciBmaXNoZXMsIGFuZCBpcyBwYXJ0aWN1bGFybHkgc2ltaWxhciB0byB0aGUgYW51cyBwb3NpdGlvbiBpbiBvdGhlciBwZWxhZ2ljIHNwZWNpZXMuDQoNCiMjIFByZS1QZWN0b3JhbCBMZW5ndGgNCg0KKHJlZjpwcmVwZWN0b3JhbGxlbmd0aCkgQm94LWFuZC13aGlza2VyIHBsb3Qgb2YgcHJlcGVjdG9yYWwgbGVuZ3RoIGFzIGEgcGVyY2VudGFnZSBvZiB0b3RhbCBsZW5ndGggaW4gZ25hdGhvc3RvbWVzLCBzaG93aW5nIGhvdyAqRHVua2xlb3N0ZXVzKiBoYXMgYSByZWxhdGl2ZWx5IGFudGVyaW9yIHBlY3RvcmFsIGZpbiBnaXJkbGUgcmVsYXRpdmUgdG8gdGhlIHRvdGFsIGxlbmd0aHMgcHJlZGljdGVkIGluIEVuZ2VsbWFuICgyMDIzKS4gRGF0YSBmb3Igbm9uLXBsYWNvZGVybXMgcmVwb3J0ZWQgYXMgc3BlY2llcyBhdmVyYWdlcyB3aGVyZSBwbGFjb2Rlcm1zIGFyZSByZXBvcnRlZCBpbiB0ZXJtcyBvZiBpbmRpdmlkdWFsIHNwZWNpbWVucyB0byBiZXR0ZXIgc2hvdyB0aGUgY29uc2lzdGVuY3kgaW4gdGhlc2UgcHJvcG9ydGlvbnMgYmV0d2VlbiBzcGVjaW1lbnMuDQoNCmBgYHtyLGZpZy5oZWlnaHQ9Ni41LGZpZy5jYXA9IihyZWY6cHJlcGVjdG9yYWxsZW5ndGgpIixmaWcud2lkdGg9OSx3YXJuaW5nPUZ9DQojIHNlcGFyYXRpbmcgeS1heGlzIGludG8gY2xhZGVzIG9mIGludGVyZXN0DQoNCnByZXBlYzE8LWRhdGFfcmVjb24gJT4lDQogIGRyb3BfbmEocHJlcGVjdG9yYWxfbGVuZ3RoLHRvdGFsX2xlbmd0aCxjbGFkZSxoaWdoZXJfZ3JvdXApICU+JQ0KICBtdXRhdGUoY2xhZGU9YXMuY2hhcmFjdGVyKGNsYWRlKSwNCiAgICAgICAgIGhpZ2hlcl9ncm91cD1pZmVsc2UoZ2VudXM9PSJEdW5rbGVvc3RldXMiLCJEdW5rbGVvc3RldXMiLGhpZ2hlcl9ncm91cCksDQogICAgICAgICBoaWdoZXJfZ3JvdXA9aWZlbHNlKGdlbnVzPT0iRWFzdG1hbm9zdGV1cyIsIkVhc3RtYW5vc3RldXMiLGhpZ2hlcl9ncm91cCksDQogICAgICAgICBoaWdoZXJfZ3JvdXA9aWZlbHNlKGhpZ2hlcl9ncm91cD09IkFydGhyb2RpcmEiICYgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVuZ3RoX2FzID09ICJlc3RpbWF0ZWQgdC5sLiIgJiBnZW51cyAhPSJEdW5rbGVvc3RldXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQXJ0aHJvZGlyYSAoZXN0LiBsZW5ndGhzKSIsaGlnaGVyX2dyb3VwKSwNCiAgICAgICAgIGhpZ2hlcl9ncm91cD1pZmVsc2UoaGlnaGVyX2dyb3VwPT0iQXJ0aHJvZGlyYSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBcnRocm9kaXJhIChrbm93biBsZW5ndGhzKSIsaGlnaGVyX2dyb3VwKSwNCiAgICAgICAgIGhpZ2hlcl9ncm91cD1pZmVsc2UoZ2VudXM9PSJBbG9waWFzIiwiQWxvcGlhcyIsaGlnaGVyX2dyb3VwKSwNCiAgICAgICAgIGhpZ2hlcl9ncm91cD1pZmVsc2Uob3JkZXI9PSJDaGltYWVyaWZvcm1lcyIsIkhvbG9jZXBoYWxpIixoaWdoZXJfZ3JvdXApLA0KICAgICAgICAgaGlnaGVyX2dyb3VwPWlmZWxzZShoaWdoZXJfZ3JvdXA9PSJDaG9uZHJpY2h0aHllcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJPdGhlciBFbGFzbW9icmFuY2hpaSIsaGlnaGVyX2dyb3VwKSwNCiAgICAgICAgIGhpZ2hlcl9ncm91cD1pZmVsc2Uob3JkZXI9PSJJY2h0aHlvZGVjdGlmb3JtZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSWNodGh5b2RlY3RpZm9ybWVzIixoaWdoZXJfZ3JvdXApLA0KICAgICAgICAgaGlnaGVyX2dyb3VwPWlmZWxzZShzaGFwZT09ImFuZ3VpbGxpZm9ybSIsIkFuZ3VpbGxpZm9ybSBUYXhhIixoaWdoZXJfZ3JvdXApLA0KICAgICAgICAgY2xhZGU9aWZlbHNlKHNoYXBlPT0iYW5ndWlsbGlmb3JtIixOQSxjbGFkZSksDQogICAgICAgICBoaWdoZXJfZ3JvdXA9ZmFjdG9yKGhpZ2hlcl9ncm91cCxvcmRlcmVkPVQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscz1jKCJEdW5rbGVvc3RldXMiLCJFYXN0bWFub3N0ZXVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFydGhyb2RpcmEgKGtub3duIGxlbmd0aHMpIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFydGhyb2RpcmEgKGVzdC4gbGVuZ3RocykiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiT3RoZXIgRWxhc21vYnJhbmNoaWkiLCAiSG9sb2NlcGhhbGkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQWxvcGlhcyIsIlNhcmNvcHRlcnlnaWkiLCJCYXNhbCBBY3Rpbm9wdGVyeWdpaSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJJY2h0aHlvZGVjdGlmb3JtZXMiLCAiQmFzYWwgVGVsZW9zdGVpIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk90b2NlcGhhbGEiLCAiU3RlbSBFdXRlbGVvc3RlaSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQWNhbnRob3B0ZXJ5Z2lpIiwiQW5ndWlsbGlmb3JtIFRheGEiKSkpDQoNCiMgc3VtbWFyaXNpbmcgdmFsdWVzIGZvciBub24tcGxhY29kZXJtcw0KDQpwcmVwZWNfMjwtYmluZF9yb3dzKHByZXBlYzEgJT4lDQogICAgICAgICAgICBmaWx0ZXIoY2xhZGUgPT0gIlBsYWNvZGVybWkiKSwNCiAgICAgICAgICBwcmVwZWMxICU+JQ0KICAgICAgICAgICAgZmlsdGVyKGNsYWRlIT0iUGxhY29kZXJtaSJ8aXMubmEoY2xhZGUpKSAlPiUNCiAgICAgICAgICAgIGdyb3VwX2J5KHRheG9uKSAlPiUNCiAgICAgICAgICAgIHN1bW1hcml6ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYyksbWVhbiksDQogICAgICAgICAgICAgICAgICAgICAgaGlnaGVyX2dyb3VwPXVuaXF1ZShoaWdoZXJfZ3JvdXApLA0KICAgICAgICAgICAgICAgICAgICAgIHRheG9uPXVuaXF1ZSh0YXhvbiksZ2VudXM9dW5pcXVlKGdlbnVzKSxzcGVjaWVzPXVuaXF1ZShzcGVjaWVzKSwNCiAgICAgICAgICAgICAgICAgICAgICBjbGFkZT11bmlxdWUoY2xhZGUsbmEucm09Riksc2hhcGU9dW5pcXVlKHNoYXBlKSkpDQoNCiMgcGxvdHRpbmcgZ3JhcGgNCg0KcDFfcGVjIDwtIGdncGxvdChyaGl6bywgYWVzKHgsIHkpKSArDQogICAgZ2VvbV9wb2x5Z29uKGZpbGwgPSAiZGFya2dyZXkiLGNvbG9yPSJibGFjayIsIGFscGhhID0gMC41KSArDQogICAgZ2VvbV9saW5lKGRhdGE9ZGF0YS5mcmFtZSh4PWMoMSwxKSx5PWMoMC4yNDcxNjcyMDAwLC0wLjAzKSkpKw0KICAgIGdlb21fbGluZShkYXRhPWRhdGEuZnJhbWUoeD1jKDAsMCkseT1jKDAuMTYyNzgzMTAwMCwtMC4wMykpKSsNCiAgICBnZW9tX2xpbmUoZGF0YT1kYXRhLmZyYW1lKHg9YygwLDAuMjI1LDAuMjI1KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9YygwLjA1NSwwLjA1NSwwLjEwNSkpLA0KICAgICAgICAgICAgICBsaW5ld2lkdGg9MS41LGNvbG9yPSJzdGVlbGJsdWUiKSsNCiAgICBjb29yZF9jYXJ0ZXNpYW4oeWxpbT1jKDAsMC4zMykpKw0KICAgIGFubm90YXRlKCJ0ZXh0IixsYWJlbD0icHJlLXBlY3RvcmFsIGxlbmd0aCIseD0wLjIyNSx5PTAuMDM1LGhqdXN0PTEpKw0KICAgIHRoZW1lKGF4aXMudGl0bGUueD1lbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgIGF4aXMudGlja3MueD1lbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgYXhpcy50aXRsZS55PWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgYXhpcy50aWNrcy55PWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICBheGlzLmxpbmUueSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICBheGlzLmxpbmUueCA9IGVsZW1lbnRfYmxhbmsoKSkrDQogICAgdGhlbWVfdm9pZCgpDQoNCnAyX3BlYyA8LSBwcmVwZWNfMiAlPiUNCiAgZ2dwbG90KGFlcyh4PXByZXBlY3RvcmFsX2xlbmd0aC90b3RhbF9sZW5ndGgseT1oaWdoZXJfZ3JvdXApKSArDQogIGNvb3JkX2NhcnRlc2lhbih4bGltPWMoMCwxKSkrDQogIHNjYWxlX3lfZGlzY3JldGUobGltaXRzPXJldikrDQogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQpKw0KICBsYWJzKHg9IlByZS1QZWN0b3JhbCBMZW5ndGggKGFzIHBlcmNlbnQgb2YgdG90YWwgbGVuZ3RoKSIseT0iQ2xhZGUiKSsNCiAgZ2VvbV92bGluZShkYXRhPS4gJT4lIGZpbHRlcihnZW51cz09IkR1bmtsZW9zdGV1cyIpLA0KICAgICAgICAgICAgIGFlcyh4aW50ZXJjZXB0PW1lYW4ocHJlcGVjdG9yYWxfbGVuZ3RoL3RvdGFsX2xlbmd0aCkpLA0KICAgICAgICAgICAgIGNvbG9yPSIjMDBCMEY2IixsaW5ldHlwZT0iZGFzaGVkIikrDQogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9bWVhbihwcmVwZWN0b3JhbF9sZW5ndGgvdG90YWxfbGVuZ3RoKSksDQogICAgICAgICAgICAgbGluZXR5cGU9ImRhc2hlZCIpKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwKSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDEpICsNCiAgZ2VvbV92aW9saW4oYWVzKGZpbGw9Y2xhZGUpLHNob3cubGVnZW5kID0gRixzY2FsZT0id2lkdGgiKSsNCiAgZ2VvbV92aW9saW4oZGF0YT0uJT4lZmlsdGVyKGdlbnVzPT0iRHVua2xlb3N0ZXVzIiksZmlsbD0iIzAwQjBGNiIsDQogICAgICAgICAgICAgIHNob3cubGVnZW5kID0gRixzY2FsZT0id2lkdGgiKSsNCiAgZ2VvbV9ib3hwbG90KHdpZHRoPTAuMykrDQogIGdlb21fc3RhcihkYXRhPS4gJT4lIGZpbHRlcihnZW51cz09IkVhc3RtYW5vc3RldXMiKSwNCiAgICAgICAgICAgIGZpbGw9IndoaXRlIixjb2xvcj0iYmxhY2siLHNpemU9Mi41KSsNCiAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoZmFjZT1jKHJlcCgicGxhaW4iLDgpLCJpdGFsaWMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwKCJwbGFpbiIsNCksIml0YWxpYyIsIml0YWxpYyIpKSkNCg0KDQpwMV9wZWMgLyBwMl9wZWMgKyBwbG90X2xheW91dChoZWlnaHRzID0gMToyKSAmIHRoZW1lKHBsb3QubWFyZ2luID0gbWFyZ2luKDAsIDIwLCAwLCAwKSkNCmBgYA0KDQoqRHVua2xlb3N0ZXVzKiBoYXMgb25lIG9mIHRoZSBtb3N0IGFudGVyaW9ybHkgcG9zaXRpb25lZCBwZWN0b3JhbCBmaW5zIGluIGFueSBleGFtaW5lZCBmaXNoLCBsaXZpbmcgb3IgZXh0aW5jdC4gVGhlIG1vcmUgYW50ZXJpb3IgcGVjdG9yYWwgZmluIHBvc2l0aW9uIGluICpEdW5rbGVvc3RldXMqIHJlbGF0aXZlIHRvIG90aGVyIGFydGhyb2RpcmVzIGlzIGV2aWRlbnQgYmFzZWQgb24gdHJ1bmsgYXJtb3IgbW9ycGhvbG9neSAoc2VlIG1hbnVzY3JpcHQpLCBidXQgdGhpcyBjb25kaXRpb24gZXh0ZW5kcyB0byBmaXNoZXMgaW4gZ2VuZXJhbC4gVGhpcyBjYW5ub3QgYmUgZHVlIHRvIHRoZSBsZW5ndGggZXN0aW1hdGVzIGNhbGN1bGF0ZWQgYnkgRW5nZWxtYW4gKDIwMjMpLCBhcyBsb25nZXIgYm9keSBsZW5ndGhzIGZvciAqRC4gdGVycmVsbGkqIG1ha2UgdGhpcyBwcm9wb3J0aW9uIG1vcmUgZXh0cmVtZSwgcG90ZW50aWFsbHkgdG8gdGhlIHBvaW50IG9mIGJlaW5nIGJpb21lY2hhbmljYWxseSB1bnJlYXNvbmFibGUuDQoNCk90aGVyIGFydGhyb2RpcmVzIHJlc2VtYmxlIGJyb2FkZXIgcGF0dGVybnMgYW1vbmcgZXVnbmF0aG9zdG9tZXMgaW4gcmVsYXRpdmUgcGVjdG9yYWwgZmluIHBvc2l0aW9uLiBUaGVzZSBwcm9wb3J0aW9ucyBhcmUgY29uc2lzdGVudCByZWdhcmRsZXNzIG9mIHdoZXRoZXIgdG90YWwgbGVuZ3RocyBhcmUgZGlyZWN0bHkgbWVhc3VyZWQgb3IgZXN0aW1hdGVkIHZpYSBPT0wuIE9uZSBleGNlcHRpb24gaXMgdGhlIGR1bmtsZW9zdGVvaWQgKkVhc3RtYW5vc3RldXMgY2FsbGlhc3BpcyosIHdoaWNoIHNob3dzIHZhbHVlcyBzaW1pbGFyIHRvICpELiB0ZXJyZWxsaSosIGFuZCBhbHNvIHNob3dzIGEgbW9yZSBhbnRlcmlvciBwZWN0b3JhbCBmZW5lc3RyYSB0aGFuIGFueSBvdGhlciBldWJyYWNoeXRob3JhY2lkIGV4YW1pbmVkIGV4Y2VwdCAqRC4gdGVycmVsbGkqIChzZWUgbWFudXNjcmlwdCkuIFRoaXMgaW5kaWNhdGVzIGEgcmVsYXRpdmVseSBhbnRlcmlvciBwb3NpdGlvbiBvZiB0aGUgcGVjdG9yYWwgZmluIG1heSBiZSBhbiBhcG9tb3JwaHkgb2YgZHVua2xlb3N0ZW9pZHMuIFNvbWUgYXNwaW5vdGhvcmFjaWRhbnMgbWF5IHNob3cgYSBzaW1pbGFyIGNvbmRpdGlvbiAoKkJyYWNoeW9zdGV1cyosICpFbnNlb3N0ZXVzKiksIHRob3VnaCB0aGlzIGlzIG5vdCB1bml2ZXJzYWwgYW1vbmcgbWVtYmVycyBvZiB0aGlzIGdyb3VwIChpdCBpcyBhYnNlbnQgaW4gKkFtYXppY2h0aHlzKiBvciAqSGVpbnR6aWNodGh5cyopLCBhbmQgdGhlIGNvbmRpdGlvbiBpcyBub3QgcXVpdGUgYXMgZXh0cmVtZSBhcyBpbiAqRHVua2xlb3N0ZXVzKi4NCg0KYGBge3J9DQpkYXRhX3JlY29uICU+JQ0KICBtdXRhdGUoZ3JvdXA9Y2FzZV93aGVuKG9yZGVyID09ICJDYXJhbmdpZm9ybWVzIiB+ICJDYXJhbmdpZm9ybWVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICBnZW51cyA9PSAiRHVua2xlb3N0ZXVzIiB+ICIqRHVua2xlb3N0ZXVzKiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgZ2VudXMgPT0gIkluY2lzb3NjdXR1bSIgfiAiKkluY2lzb3NjdXR1bSoiLA0KICAgICAgICAgICAgICAgICAgICAgICAgIGZhbWlseSA9PSAiQ29jY29zdGVpZGFlIiB+ICJDb2Njb3N0ZWlkYWUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgIG9yZGVyID09ICJDbHVwZWlmb3JtZXMiICYgZmFtaWx5IT0iQ2hlaXJvY2VudHJpZGFlIiB+ICJPdGhlciBDbHVwZWlmb3JtZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgIGZhbWlseSA9PSAiTWVnYWxvcGlkYWUiIH4gIk1lZ2Fsb3BpZGFlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICBnZW51cyA9PSAiQW1hemljaHRoeXMiIH4gIipBbWF6aWNodGh5cyoiLA0KICAgICAgICAgICAgICAgICAgICAgICAgIGZhbWlseSA9PSAiU2FsbW9uaWRhZSIgfiAiU2FsbW9uaWRhZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgZmFtaWx5ID09ICJDaGVpcm9jZW50cmlkYWUiIH4gIkNoZWlyb2NlbnRyaWRhZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgZmFtaWx5ID09ICJMYW1uaWRhZSIgfiAiTGFtbmlkYWUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgIGZhbWlseSA9PSAiQ2FyY2hhcmhpbmlkYWUiIH4gIkNhcmNoYXJoaW5pZGFlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICBmYW1pbHkgPT0gIlNxdWFsaWRhZSIgfiAiU3F1YWxpZGFlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICBmYW1pbHkgPT0gIkxhbXByaWRhZSIgfiAiTGFtcHJpZGFlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICBvcmRlciA9PSAiSXN0aW9waG9yaWZvcm1lcyIgfiAiSXN0aW9waG9yaWZvcm1lcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgb3JkZXIgPT0gIkljaHRoeW9kZWN0aWZvcm1lcyIgfiAiSWNodGh5b2RlY3RpZm9ybWVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICBmYW1pbHkgPT0gIlNwaHlyYWVuaWRhZSIgfiAiU3BoeXJhZW5pZGFlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICBmYW1pbHkgPT0gIlNjb21icmlkYWUiIH4gIlNjb21icmlkYWUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgIGdlbnVzID09ICJFYXN0bWFub3N0ZXVzIiB+ICIqRWFzdG1hbm9zdGV1cyoiKSkgJT4lDQogIGRyb3BfbmEoZ3JvdXAscHJlcGVjdG9yYWxfbGVuZ3RoLHRvdGFsX2xlbmd0aCkgJT4lDQogIG11dGF0ZShwcGwgPSAxMDAqKHByZXBlY3RvcmFsX2xlbmd0aC90b3RhbF9sZW5ndGgpKSAlPiUNCiAgZ3JvdXBfYnkodGF4b24pICU+JQ0KICBzdW1tYXJpc2UoaGlnaGVyX2dyb3VwPXVuaXF1ZShoaWdoZXJfZ3JvdXApLG1lYW4xPW1lYW4ocHBsKSxtYXg9bWF4KHBwbCksbWluPW1pbihwcGwpLG49bigpLGdyb3VwPXVuaXF1ZShncm91cCksY2xhZGU9dW5pcXVlKGNsYWRlKSkgJT4lDQogIGdyb3VwX2J5KGdyb3VwKSAlPiUNCiAgc3VtbWFyaXNlKGhpZ2hlcl9ncm91cD11bmlxdWUoaGlnaGVyX2dyb3VwKSxjbGFkZT11bmlxdWUoY2xhZGUpLA0KICAgICAgICAgICAgbWVhbjI9bWVhbihtZWFuMSksbWluMT1taW4obWVhbjEpLG1heDE9bWF4KG1lYW4xKSwNCiAgICAgICAgICAgIHNkPXNkKG1lYW4xKSxtaW4yPW1pbihtaW4pLG1heDI9bWF4KG1heCksTnNwZWM9c3VtKG4pLG49bigpKSU+JQ0KICBtdXRhdGUoaGlnaGVyX2dyb3VwPWZhY3RvcihoaWdoZXJfZ3JvdXAsb3JkZXJlZD1ULGxldmVscz1jKCJBcnRocm9kaXJhIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQmFzYWwgQWN0aW5vcHRlcnlnaWkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCYXNhbCBUZWxlb3N0ZWkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJPdG9jZXBoYWxhIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU3RlbSBFdXRlbGVvc3RlaSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFjYW50aG9wdGVyeWdpaSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNob25kcmljaHRoeWVzIikpLA0KICAgICAgICAgbWluMT1pZmVsc2Uobj09MSxOQSxtaW4xKSwNCiAgICAgICAgIG1heDE9aWZlbHNlKG49PTEsTkEsbWF4MSkpICU+JQ0KICBhcnJhbmdlKGhpZ2hlcl9ncm91cCxncm91cCkgJT4lDQogIHNlbGVjdCgtaGlnaGVyX2dyb3VwKSAlPiUNCiAga2FibGUoY29sLm5hbWVzPWMoIlRheG9uIiwiQ2xhZGUiLCJNZWFuIiwiTWluaW11bSIsIk1heGltdW0iLCJTdC4gRGV2IiwNCiAgICAgICAgICAgICAgICAgICAgIk1pbi4gT2JzLiIsIk1heC4gT2JzLiIsDQogICAgICAgICAgICAgICAgICAgICJPYnNlcnZhdGlvbnMiLCJTcGVjaWVzIiksDQogICAgICAgIGRpZ2l0cz0xLCBhbGlnbj1jKCJsIiwiYyIsImMiLCJjIiwiYyIsImMiLCJjIiwiYyIsImMiLCJjIiksDQogICAgICAgIGNhcHRpb249IlByZS1wZWN0b3JhbCBsZW5ndGggaW4gPGk+RHVua2xlb3N0ZXVzPC9pPiBhcyBhIHBlcmNlbnQgb2YgdG90YWwgbGVuZ3RoIGluIHNlbGVjdCBuZWt0b25pYyAobW9zdGx5IHBlbGFnaWMpIGZpc2ggY2xhZGVzLiBOb3RlIGhvdyA8aT5EdW5rbGVvc3RldXM8L2k+IHNob3dzIGEgcHJlLXBlY3RvcmFsIGxlbmd0aCBjb21wYXJhYmxlIHRvIG9yIHNob3J0ZXIgdGhhbiB0aGUgaGlnaGx5IGVsb25nYXRlIENoZWlyb2NlbnRyaWRhZSBhbmQgSWNodGh5b2RlY3RpZm9ybWVzIGV2ZW4gd2hlbiB1c2luZyB0aGUgbGVuZ3RocyBlc3RpbWF0ZWQgYnkgRW5nZWxtYW4gKDIwMjMpLiBEYXRhIGFyZSBwcmVzZW50ZWQgYXMgYXZlcmFnZXMgb2Ygc3BlY2llcyBhdmVyYWdlcyB0byBhdm9pZCBiaWFzIGZyb20gYW55IG9uZSB0YXhvbi4gRGF0YSBhcmUgZGVzY3JpYmVkIGFzICdvYnNlcnZhdGlvbnMnIHJhdGhlciB0aGFuIHNwZWNpbWVucyBhcyBzb21lIGRhdGEgcG9pbnRzIGFyZSBzcGVjaWVzIGF2ZXJhZ2VzIHJlcG9ydGVkIGluIGxpdGVyYXR1cmUuICdNaW4gT2JzLicgYW5kICdNYXggT2JzJyByZXByZXNlbnQgdGhlIG1pbmltdW0gYW5kIG1heGltdW0gcHJlLWF2ZXJhZ2VkIG9ic2VydmF0aW9uIGZvciBlYWNoIGdyb3VwLiIpICU+JQ0KICBhZGRfaGVhZGVyX2Fib3ZlKGMoIiAiPTIsIlBlcmNlbnQgUHJlLVBlY3RvcmFsIExlbmd0aCI9NCwiRGF0YSBFeHRyZW1hIj0yLCJTYW1wbGUgU2l6ZSI9MikpJT4lDQogIHJvd19zcGVjKDIsYm9sZD1UKSU+JQ0KICBrYWJsZV9zdHlsaW5nKCkNCmBgYA0KICANClRoZSBwZWN0b3JhbCBmaW4gb3JpZ2luIG9mIEljaHRoeW9kZWN0aWZvcm1lcyBpcyBtb3JlIGFudGVyaW9yIHRoYW4gbW9zdCBleHRhbnQgZmlzaGVzLCBidXQgdGhpcyBpcyBkdWUgdG8gaHlwZXItZWxvbmdhdGlvbiBvZiB0aGUgdHJ1bmsgcmVsYXRpdmUgdG8gYSBjb25zZXJ2ZWQgcGVjdG9yYWwgZ2lyZGxlIG1vcnBob2xvZ3kgcmF0aGVyIHRoYW4gYW4gdW51c3VhbCBtb3JwaG9sb2d5IG9mIHRoZSBwZWN0b3JhbCBnaXJkbGUgYW5kIHRydW5rIGFybW9yIGFsbG93aW5nIGEgbW9yZSBhbnRlcm92ZW50cmFsIHBvc2l0aW9uIG9mIHRoZSBwZWN0b3JhbCBmaW4gYXMgaW4gKkR1bmtsZW9zdGV1cyouDQoNCihyZWY6WGlwaGFjdGludXMpIFByZS1wZWN0b3JhbCBsZW5ndGggaW4gKkR1bmtsZW9zdGV1cyogYXNzdW1pbmcgaGVhZC10cnVuayBwcm9wb3J0aW9ucyBzaW1pbGFyIHRvIEljaHRoeW9kZWN0aWZvcm1lcywgc2hvd2luZyBob3cgdGhpcyByZXN1bHRzIGluIGEgbW9yZSBhbnRlcmlvciBwb3NpdGlvbiBvZiB0aGUgcGVjdG9yYWwgZmluIHRoYW4gYWxtb3N0IGFueSBvdGhlciBub24tYW5ndWlsbGlmb3JtIGZpc2guIERhdGEgZm9yIG5vbi1wbGFjb2Rlcm1zIHJlcG9ydGVkIGFzIHNwZWNpZXMgYXZlcmFnZXMgd2hlcmUgcGxhY29kZXJtcyBhcmUgcmVwb3J0ZWQgaW4gdGVybXMgb2YgaW5kaXZpZHVhbCBzcGVjaW1lbnMgdG8gYmV0dGVyIHNob3cgdGhlIGNvbnNpc3RlbmN5IGluIHRoZXNlIHByb3BvcnRpb25zIGJldHdlZW4gc3BlY2ltZW5zLg0KDQpgYGB7cixmaWcuaGVpZ2h0PTguNSxmaWcuY2FwPSIocmVmOlhpcGhhY3RpbnVzKSIsd2FybmluZz1GfQ0KcDFfcGVjX3hpcCA8LSBnZ3Bsb3Qocmhpem8sIGFlcyh4LCB5KSkgKw0KICAgIGdlb21fcG9seWdvbihmaWxsID0gImRhcmtncmV5Iixjb2xvcj0iYmxhY2siLCBhbHBoYSA9IDAuNSkgKw0KICAgIGdlb21fbGluZShkYXRhPWRhdGEuZnJhbWUoeD1jKDEsMSkseT1jKDAuMjQ3MTY3MjAwMCwtMC4wMykpKSsNCiAgICBnZW9tX2xpbmUoZGF0YT1kYXRhLmZyYW1lKHg9YygwLDApLHk9YygwLjE2Mjc4MzEwMDAsLTAuMDMpKSkrDQogICAgZ2VvbV9saW5lKGRhdGE9ZGF0YS5mcmFtZSh4PWMoMCwwLjIyNSwwLjIyNSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PWMoMC4wNTUsMC4wNTUsMC4xMDUpKSwNCiAgICAgICAgICAgICAgbGluZXdpZHRoPTEuNSxjb2xvcj0ic3RlZWxibHVlIikrDQogICAgY29vcmRfY2FydGVzaWFuKHlsaW09YygwLDAuMzMpLHhsaW09YygwLC4zNSkpKw0KICAgIGFubm90YXRlKCJ0ZXh0IixsYWJlbD0icHJlLXBlY3RvcmFsIGxlbmd0aCIseD0wLjIyNSx5PTAuMDQ1LGhqdXN0PTEpKw0KICAgIHRoZW1lKGF4aXMudGl0bGUueD1lbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgIGF4aXMudGlja3MueD1lbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgYXhpcy50aXRsZS55PWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgYXhpcy50aWNrcy55PWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICBheGlzLmxpbmUueSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICBheGlzLmxpbmUueCA9IGVsZW1lbnRfYmxhbmsoKSkrDQogICAgdGhlbWVfdm9pZCgpDQoNCnAyX3BlY194aXAgPC0gcHJlcGVjXzIgJT4lDQogIG11dGF0ZSh0b3RhbF9sZW5ndGg9aWZlbHNlKGdlbnVzPT0iRHVua2xlb3N0ZXVzIiwNCiAgICAgICAgICAgICAgICBoZWFkX2xlbmd0aCAqIChkYXRhX3JlY29uICU+JSBmaWx0ZXIob3JkZXI9PSJJY2h0aHlvZGVjdGlmb3JtZXMiKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwX2J5KHRheG9uKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1bW1hcmlzZShoZWFkX2xlbmd0aD1tZWFuKGhlYWRfbGVuZ3RoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvdGFsX2xlbmd0aD1tZWFuKHRvdGFsX2xlbmd0aCkpICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKGhlYWRfdHJ1bmtfcmF0aW89dG90YWxfbGVuZ3RoL2hlYWRfbGVuZ3RoKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHB1bGwoaGVhZF90cnVua19yYXRpbykgJT4lIG1lYW4oKSksDQogICAgICAgICAgICAgICAgdG90YWxfbGVuZ3RoKSkgJT4lDQogIGdncGxvdChhZXMoeD1wcmVwZWN0b3JhbF9sZW5ndGgvdG90YWxfbGVuZ3RoLHk9aGlnaGVyX2dyb3VwKSkgKw0KICBzY2FsZV95X2Rpc2NyZXRlKGxpbWl0cz1yZXYpKw0KICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50KSsNCiAgY29vcmRfY2FydGVzaWFuKHhsaW09YygwLC4zNSkpKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9MCkrDQogIGxhYnMoeD0iUGVyY2VudCBQcmUtUGVjdG9yYWwgTGVuZ3RoIix5PSJDbGFkZSIpKw0KICBnZW9tX3ZsaW5lKGRhdGE9LiAlPiUgZmlsdGVyKGdlbnVzPT0iRHVua2xlb3N0ZXVzIiksDQogICAgICAgICAgICAgYWVzKHhpbnRlcmNlcHQ9bWVhbihwcmVwZWN0b3JhbF9sZW5ndGgvdG90YWxfbGVuZ3RoKSksDQogICAgICAgICAgICAgbGluZXR5cGU9ImRhc2hlZCIpKw0KICBnZW9tX3Zpb2xpbihhZXMoZmlsbD1jbGFkZSksc2hvdy5sZWdlbmQgPSBGLHNjYWxlPSJ3aWR0aCIpKw0KICBnZW9tX2JveHBsb3Qod2lkdGg9MC4zKSsNCiAgZ2VvbV9zdGFyKGRhdGE9LiAlPiUgZmlsdGVyKGdlbnVzPT0iRWFzdG1hbm9zdGV1cyIpLGZpbGw9IndoaXRlIixjb2xvcj0iYmxhY2siLHNpemU9Mi41KSsNCiAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoZmFjZT1jKHJlcCgicGxhaW4iLDgpLCJpdGFsaWMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwKCJwbGFpbiIsNCksIml0YWxpYyIsIml0YWxpYyIpKSkNCg0KcDFfcGVjX3hpcCAvIHAyX3BlY194aXAgKyBwbG90X2xheW91dChoZWlnaHRzID0gMS4xNToyKSAmIHRoZW1lKHBsb3QubWFyZ2luID0gbWFyZ2luKDAsIDIwLCAwLCAwKSkNCmBgYA0KDQpJZiBhcnRpZmljaWFsbHkgbWFuaXB1bGF0aW5nICpEdW5rbGVvc3RldXMqIHRvIGhhdmUgaGVhZC10cnVuayBwcm9wb3J0aW9ucyBzaW1pbGFyIHRvIEljaHRoeW9kZWN0aWZvcm1lcyAod2hpY2ggaGF2ZSBhIGhlYWQgYXJvdW5kIDEvNyB0b3RhbCBsZW5ndGgpLCB0aGlzIHJlc3VsdHMgaW4gKkR1bmtsZW9zdGV1cyogaGF2aW5nIGEgcGVjdG9yYWwgZmluIHNpZ25pZmljYW50bHkgbW9yZSBhbnRlcmlvciB0aGFuIGFsbW9zdCBhbnkgb3RoZXIgZmlzaCAob25seSAxMSUgdG90YWwgbGVuZ3RoKSwgdG8gdGhlIHBvaW50IG9mIGJlaW5nIGFuIHVudXN1YWwgb3V0bGllci4gVGhpcyBzZWVtcyB1bmxpa2VseSwgYmVjYXVzZSBpZiB0aGUgcGVjdG9yYWwgZmluIGlzIHBvc2l0aW9uZWQgdG9vIGZhciBhbnRlcmlvcmx5IGl0IG1pZ2h0IGJlIGV4cGVjdGVkIHRvIGhhdmUgbmVnYXRpdmUgYmlvbWVjaGFuaWNhbCBjb25zZXF1ZW5jZXMgbGlrZSBkZXN0YWJpbGl6aW5nIHRoZSBhbmltYWwgZHVyaW5nIHN3aW1taW5nIChzZWUgbWFudXNjcmlwdCkuDQoNCmBgYHtyfQ0KZGF0YV9yZWNvbiAlPiUNCiAgZmlsdGVyKGdlbnVzPT0iRHVua2xlb3N0ZXVzIikgJT4lDQogIGFkZF9yb3coc3BlY2ltZW49IkNNTkggNTkzNiIsaGVhZF9sZW5ndGg9NzIuNCx0b3RhbF9sZW5ndGg9NDA5KSAlPiUNCiAgbXV0YXRlKHRvdGFsX2xlbmd0aDI9DQogICAgICAgICAgICAgICAgaGVhZF9sZW5ndGggKiAoZGF0YV9yZWNvbiAlPiUgZmlsdGVyKG9yZGVyPT0iSWNodGh5b2RlY3RpZm9ybWVzIikgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cF9ieSh0YXhvbikgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdW1tYXJpc2UoaGVhZF9sZW5ndGg9bWVhbihoZWFkX2xlbmd0aCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b3RhbF9sZW5ndGg9bWVhbih0b3RhbF9sZW5ndGgpKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShoZWFkX3RydW5rX3JhdGlvPXRvdGFsX2xlbmd0aC9oZWFkX2xlbmd0aCkgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwdWxsKGhlYWRfdHJ1bmtfcmF0aW8pICU+JSBtZWFuKCkpKSAlPiUNCiAgc2VsZWN0KHNwZWNpbWVuLCBoZWFkX2xlbmd0aCwgdG90YWxfbGVuZ3RoLCB0b3RhbF9sZW5ndGgyKSAlPiUNCiAgbXV0YXRlKGhlYWRfbGVuZ3RoPWlmZWxzZShoZWFkX2xlbmd0aD09NzIuNCwifjcyLjQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNwcmludGYoIiUuMWYiLCByb3VuZChoZWFkX2xlbmd0aCwxKSkpKSAlPiUNCiAgYXJyYW5nZSh0b3RhbF9sZW5ndGgpICU+JQ0KICBrYWJsZShkaWdpdHM9MSxhbGlnbj1jKCJsIiwiYyIsImMiLCJjIiksDQogICAgICAgIGNvbC5uYW1lcyA9IGMoIlNwZWNpbWVuIiwiSGVhZCBMZW5ndGgiLCJUb3RhbCBMZW5ndGggKHVzaW5nIE9PTCkiLCAiVG90YWwgTGVuZ3RoIChhc3N1bWluZyBpY2h0aHlvZGVjdGlmb3JtLWxpa2UgcHJvcG9ydGlvbnMpIiksDQogICAgICAgIGNhcHRpb249IlRvdGFsIGxlbmd0aHMgZm9yIHNwZWNpbWVucyBvZiA8aT5EdW5rbGVvc3RldXMgdGVycmVsbGk8L2k+IGFzc3VtaW5nIHNpbWlsYXIgaGVhZC10cnVuayBwcm9wb3J0aW9ucyB0byBJY2h0aHlvZGVjdGlmb3JtZXMgKGUuZy4sIDxpPlhpcGhhY3RpbnVzPC9pPikuIEhlYWQgc2l6ZSBpbiBDTU5IIDU5MzYgYmFzZWQgb24gc2NhbGluZyBmcm9tIHRoZSBvcmFsIHJlZ2lvbiBvZiB0aGUgaW5mcmFnbmF0aGFsIGFuZCBhbGxvbWV0cmljIHBhdHRlcm5zIHdpdGhpbiA8aT5ELiB0ZXJyZWxsaTwvaT4gKHNlZSBFbmdlbG1hbiAyMDIzKSIpICU+JQ0KICBrYWJsZV9zdHlsaW5nDQpgYGANCg0KQWRkaXRpb25hbGx5LCBldmVuIGFzc3VtaW5nIGljaHRoeW9kZWN0aWZvcm0tbGlrZSBwcm9wb3J0aW9ucyBpbiAqRHVua2xlb3N0ZXVzIHRlcnJlbGxpKiBpdCBpcyBub3QgcG9zc2libGUgdG8gcHJvZHVjZSBsZW5ndGhzIGdyZWF0ZXIgdGhhbiA1IG0gZm9yIHRoZSBsYXJnZXN0IGtub3duIGluZGl2aWR1YWxzLg0KDQojIyMgUHJlZGljdGluZyBpbiAqRHVua2xlb3N0ZXVzIHRlcnJlbGxpKg0KDQojIyMjIFNldHRpbmcgdXAgUmVncmVzc2lvbnMNCg0KKipXaXRob3V0IExvZy1UcmFuc2Zvcm1hdGlvbioqDQoNCmBgYHtyfQ0KZml0LnBlY3RvcmFsPC1sbSh0b3RhbF9sZW5ndGh+cHJlcGVjdG9yYWxfbGVuZ3RoLA0KICAgICAgICAgICAgICAgICBkYXRhPWRhdGFfcmVjb24gJT4lDQogICAgICAgICAgICAgICAgICAgZmlsdGVyKGxlbmd0aF9hcyE9ImVzdGltYXRlZCB0LmwuIikpDQoNCnN1bW1hcnkoZml0LnBlY3RvcmFsKQ0KcmVncmVzc2lvbi5zdGF0cyhmaXQucGVjdG9yYWwpDQpgYGANCg0KKipXaXRoIExvZy1UcmFuc2Zvcm1hdGlvbioqDQoNCmBgYHtyfQ0KZml0LnBlY3RvcmFsXzI8LWxtKGxvZyh0b3RhbF9sZW5ndGgpfmxvZyhwcmVwZWN0b3JhbF9sZW5ndGgpLA0KICAgICAgICAgICAgICAgICBkYXRhPWRhdGFfcmVjb24gJT4lDQogICAgICAgICAgICAgICAgICAgZmlsdGVyKGxlbmd0aF9hcyE9ImVzdGltYXRlZCB0LmwuIikpDQoNCnN1bW1hcnkoZml0LnBlY3RvcmFsXzIpDQpyZWdyZXNzaW9uLnN0YXRzKGZpdC5wZWN0b3JhbF8yKQ0KYGBgDQoNCiMjIyMgRXN0aW1hdGluZw0KDQpgYGB7cix3YXJuaW5nPUZ9DQpkYXRhX3JlY29uICU+JSBmaWx0ZXIoZ2VudXM9PSJEdW5rbGVvc3RldXMiKSAlPiUNCiAgZHJvcF9uYShwcmVwZWN0b3JhbF9sZW5ndGgpICU+JQ0KICBhcnJhbmdlKHByZXBlY3RvcmFsX2xlbmd0aCkgJT4lDQogIHJlbmFtZShPT0xfbGVuZ3RoPXRvdGFsX2xlbmd0aCkgJT4lDQogIGF1Z21lbnQoZml0LnBlY3RvcmFsLG5ld2RhdGE9LixpbnRlcnZhbD0icHJlZGljdGlvbiIpICU+JQ0KICByZW5hbWVfYXQodmFycyhzdGFydHNfd2l0aCgnLicpKSwgZnVucyhwYXN0ZTAoInBlY3RvcmFsMSIsLikpKSU+JQ0KICBhdWdtZW50KGZpdC5wZWN0b3JhbF8yLG5ld2RhdGE9LixpbnRlcnZhbD0icHJlZGljdGlvbiIpICU+JQ0KICBtdXRhdGUoYWNyb3NzKC5maXR0ZWQ6LnVwcGVyLH5leHAoLikqcmVncmVzc2lvbi5zdGF0cyhmaXQucGVjdG9yYWxfMikkQ0YpKSU+JQ0KICByZW5hbWVfYXQodmFycyhzdGFydHNfd2l0aCgnLicpKSwgZnVucyhwYXN0ZTAoInBlY3RvcmFsMiIsLikpKSU+JQ0KICBtdXRhdGUoT09MLnBlPXBhc3RlMCgiKCIscm91bmQobWlubGVuZ3RoLDEpLCLigJMiLHJvdW5kKG1heGxlbmd0aCwxKSwiKSIpLA0KICAgICAgICAgcGVjdG9yYWwxLnJhbmdlPXBhc3RlMCgiKCIscm91bmQocGVjdG9yYWwxLmxvd2VyLDEpLCLigJMiLHJvdW5kKHBlY3RvcmFsMS51cHBlciwxKSwiKSIpLA0KICAgICAgICAgcGVjdG9yYWwyLnJhbmdlPXBhc3RlMCgiKCIscm91bmQocGVjdG9yYWwyLmxvd2VyLDEpLCLigJMiLHJvdW5kKHBlY3RvcmFsMi51cHBlciwxKSwiKSIpKSU+JQ0KICBzZWxlY3Qoc3BlY2ltZW4scHJlcGVjdG9yYWxfbGVuZ3RoLE9PTF9sZW5ndGgsT09MLnBlLA0KICAgICAgICAgcGVjdG9yYWwxLmZpdHRlZCxwZWN0b3JhbDEucmFuZ2UsDQogICAgICAgICBwZWN0b3JhbDIuZml0dGVkLHBlY3RvcmFsMi5yYW5nZSkgJT4lDQogIGthYmxlKGRpZ2l0cz0xLGNvbC5uYW1lcz1jKCJTcGVjaW1lbiIsIlByZXBlY3RvcmFsIExlbmd0aCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJFc3QuIiwiKy8tICVQRSIsIkVzdC4iLCI5NSUgUC5JLiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJFc3QuIiwiOTUlIFAuSS4iKSwNCiAgICAgICAgYWxpZ249YygibCIsImMiLCJjIiwiYyIsImMiLCJjIiwiYyIsImMiKSkgJT4lDQogIGFkZF9oZWFkZXJfYWJvdmUoYygiICI9MiwiT3JiaXQtT3BlcmN1bGFyIExlbmd0aCI9MiwiUHJlcGVjdG9yYWwgTGVuZ3RoLCBub24tbG9nLXRyYW5zZm9ybWVkIj0yLA0KICAgICAgICAgICAgICAgICAgICJQcmVwZWN0b3JhbCBMZW5ndGgsIGxvZy10cmFuc2Zvcm1lZCI9MikpICU+JQ0KICBrYWJsZV9zdHlsaW5nKCkNCmBgYA0KDQpQcmVwZWN0b3JhbCBsZW5ndGggcHJvZHVjZXMgbGVuZ3RocyB0aGF0IGFyZSBzb21ld2hhdCBpbiB0aGUgcmFuZ2Ugb2YgT09MLCBidXQgbXVjaCBzaG9ydGVyLiBUaGlzIGlzIHRvIGJlIGV4cGVjdGVkIGdpdmVuIHRoZSBleHRyZW1lIGFudGVyaW9yIHBvc2l0aW9uIG9mIHRoZSBzY2FwdWxvY29yYWNvaWQgaW4gKkR1bmtsZW9zdGV1cyouIEhvd2V2ZXIsIGl0IGlzIGltcG9ydGFudCB0byBub3RlIHRoYXQgZXZlbiB0aGUgOTUlIHByZWRpY3Rpb24gaW50ZXJ2YWxzIGZvciBwcmVwZWN0b3JhbCBsZW5ndGgsIHdoaWNoIGFyZSBleHBlY3RlZCB0byBiZSBtdWNoIHdpZGVyIHRoYW4gdGhlIGludGVydmFscyBiYXNlZCBvbiArLy0gUEUsIHN0aWxsIGRvIG5vdCBhbGxvdyBmb3IgZ3JlYXRlciBsZW5ndGhzIGFuZCBsb25nZXIgdHJ1bmtzIGZvciAqRC4gdGVycmVsbGkqLg0KDQpgYGB7cix3YXJuaW5nPUZ9DQpmaXQucGVjdG9yYWxfMzwtbG0obG9nKHRvdGFsX2xlbmd0aCl+bG9nKHByZXBlY3RvcmFsX2xlbmd0aCksDQogICAgICAgICAgICAgICAgICAgZGF0YV9yZWNvbiAlPiUNCiAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihsZW5ndGhfYXM9PSJ0b3RhbCBsZW5ndGgiLGhpZ2hlcl9ncm91cCE9IkFjYW50aG9wdGVyeWdpaSIgJg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIShvcmRlciAlaW4lIGMoIkdhZGlmb3JtZXMiLCJBdWxvcGlmb3JtZXMiKSkpKQ0KZGF0YV9yZWNvbiAlPiUgZmlsdGVyKGdlbnVzPT0iRHVua2xlb3N0ZXVzIikgJT4lDQogIGRyb3BfbmEocHJlcGVjdG9yYWxfbGVuZ3RoKSAlPiUNCiAgYXJyYW5nZShwcmVwZWN0b3JhbF9sZW5ndGgpICU+JQ0KICByZW5hbWUoT09MX2xlbmd0aD10b3RhbF9sZW5ndGgpICU+JQ0KICBhdWdtZW50KGZpdC5wZWN0b3JhbF8zLG5ld2RhdGE9LixpbnRlcnZhbD0icHJlZGljdGlvbiIpICU+JQ0KICBtdXRhdGUoYWNyb3NzKC5maXR0ZWQ6LnVwcGVyLH5leHAoLikqcmVncmVzc2lvbi5zdGF0cyhmaXQucGVjdG9yYWxfMykkQ0YpKSU+JQ0KICByZW5hbWVfYXQodmFycyhzdGFydHNfd2l0aCgnLicpKSwgZnVucyhwYXN0ZTAoInBlY3RvcmFsMiIsLikpKSU+JQ0KICBtdXRhdGUoT09MLnBlPXBhc3RlMCgiKCIscm91bmQobWlubGVuZ3RoLDEpLCLigJMiLHJvdW5kKG1heGxlbmd0aCwxKSwiKSIpLA0KICAgICAgICAgcGVjdG9yYWwyLnJhbmdlPXBhc3RlMCgiKCIscm91bmQocGVjdG9yYWwyLmxvd2VyLDEpLCLigJMiLHJvdW5kKHBlY3RvcmFsMi51cHBlciwxKSwiKSIpKSU+JQ0KICBzZWxlY3Qoc3BlY2ltZW4scHJlcGVjdG9yYWxfbGVuZ3RoLE9PTF9sZW5ndGgsT09MLnBlLA0KICAgICAgICAgcGVjdG9yYWwyLmZpdHRlZCxwZWN0b3JhbDIucmFuZ2UpICU+JQ0KICBrYWJsZShkaWdpdHM9MSxjb2wubmFtZXM9YygiU3BlY2ltZW4iLCJQcmVwZWN0b3JhbCBMZW5ndGgiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRXN0LiIsIisvLSAlUEUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRXN0LiIsIjk1JSBQLkkuIiksDQogICAgICAgIGFsaWduPWMoImwiLCJjIiwiYyIsImMiLCJjIiwiYyIsImMiLCJjIikpICU+JQ0KICBhZGRfaGVhZGVyX2Fib3ZlKGMoIiAiPTIsIk9yYml0LU9wZXJjdWxhciBMZW5ndGgiPTIsDQogICAgICAgICAgICAgICAgICAgIlByZXBlY3RvcmFsIExlbmd0aCwgbG9nLXRyYW5zZm9ybWVkIj0yKSkgJT4lDQogIGthYmxlX3N0eWxpbmcoKQ0KYGBgDQoNClNpbWlsYXIgcmVzdWx0cyBvY2N1ciBldmVuIGlmIHJlc3RyaWN0aW5nIGNvbXBhcmlzb25zIHRvIHRheGEgd2l0aG91dCBhbnRlcmlvcmx5IHBvc2l0aW9uZWQgcGVsdmVzIChub24tYWNhbnRob3B0ZXJ5Z2lhbnMpLg0KDQojIyBQcmUtUGVsdmljIExlbmd0aA0KDQoocmVmOnBlbHZpY2hpc3RvZ3JhbSkgSGlzdG9ncmFtIG9mIHByZS1wZWx2aWMgbGVuZ3RoIGluIGZpc2hlcywgdXNpbmcgc3BlY2llcyBhdmVyYWdlcy4gRGFzaGVkIGxpbmUgcmVwcmVzZW50cyBtZWFuIHZhbHVlIGZvciBhbGwgbm9uLWFjYW50aG9wdGVyeWdpYW4gdGF4YSAoZXhjbHVkaW5nIEdhZGlmb3JtZXMgYW5kIEF1bG9waWZvcm1lcykuIEFsbCBkYXRhIGFyZSBpbiBzcGVjaWVzIGF2ZXJhZ2VzIGV4Y2VwdCBmb3IgKkR1bmtsZW9zdGV1cyosIHRvIHNob3cgdGhhdCBpbmRpdmlkdWFsIHZhcmlhdGlvbiBkb2VzIG5vdCBjaGFuZ2UgaW50ZXJwcmV0YXRpb25zIG9mIHBlbHZpYyBmaW4gbG9jYXRpb24uDQoNCmBgYHtyLGZpZy5oZWlnaHQ9NixmaWcuY2FwPSIocmVmOnBlbHZpY2hpc3RvZ3JhbSkifQ0KcDFfcGVsdiA8LSBnZ3Bsb3Qocmhpem8sIGFlcyh4LCB5KSkgKw0KICAgIGdlb21fcG9seWdvbihmaWxsID0gImRhcmtncmV5Iixjb2xvcj0iYmxhY2siLCBhbHBoYSA9IDAuNSkgKw0KICAgIGdlb21fbGluZShkYXRhPWRhdGEuZnJhbWUoeD1jKDEsMSkseT1jKDAuMjQ3MTY3MjAwMCwtMC4wMykpKSsNCiAgICBnZW9tX2xpbmUoZGF0YT1kYXRhLmZyYW1lKHg9YygwLDApLHk9YygwLjE2Mjc4MzEwMDAsLTAuMDMpKSkrDQogICAgZ2VvbV9saW5lKGRhdGE9ZGF0YS5mcmFtZSh4PWMoMCwwLjQ1NCwwLjQ1NCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PWMoMC4wNTUsMC4wNTUsMC4xMDUpKSwNCiAgICAgICAgICAgICAgbGluZXdpZHRoPTEuNSxjb2xvcj0ic3RlZWxibHVlIikrDQogICAgY29vcmRfY2FydGVzaWFuKHlsaW09YygwLDAuMzMpKSsNCiAgICBhbm5vdGF0ZSgidGV4dCIsbGFiZWw9InByZS1wZWx2aWMgbGVuZ3RoIix4PTAuNDU0LHk9MC4wMzUsaGp1c3Q9MC41KSsNCiAgICB0aGVtZShheGlzLnRpdGxlLng9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgIGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICBheGlzLnRpY2tzLng9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgIGF4aXMudGl0bGUueT1lbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgYXhpcy50ZXh0Lnk9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgIGF4aXMudGlja3MueT1lbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgYXhpcy5saW5lLnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgYXhpcy5saW5lLnggPSBlbGVtZW50X2JsYW5rKCkpKw0KICAgIHRoZW1lX3ZvaWQoKQ0KDQpwMl9wZWx2IDwtIGRhdGFfcmVjb24gJT4lDQogIG11dGF0ZShjbGFkZT1pZmVsc2UoaGlnaGVyX2dyb3VwID09ICJBY2FudGhvcHRlcnlnaWkiLCJBY2FudGhvcHRlcnlnaWkiLGNsYWRlKSwNCiAgICAgICAgIGNsYWRlPWlmZWxzZShvcmRlciAlaW4lIGMoIkdhZGlmb3JtZXMiLCJBdWxvcGlmb3JtZXMiKSwiR2FkaWZvcm1lcywgQXVsb3BpZm9ybWVzIixjbGFkZSksDQogICAgICAgICBjbGFkZT1pZmVsc2UoY2xhZGU9PSJBY3Rpbm9wdGVyeWdpaSIsIk90aGVyIEFjdGlub3B0ZXJ5Z2lpIixjbGFkZSksDQogICAgICAgICBjbGFkZT1mYWN0b3IoY2xhZGUsb3JkZXJlZD1ULGxldmVscz1jKCJBY2FudGhvcHRlcnlnaWkiLCJHYWRpZm9ybWVzLCBBdWxvcGlmb3JtZXMiLCJPdGhlciBBY3Rpbm9wdGVyeWdpaSIsIkNob25kcmljaHRoeWVzIiwiUGxhY29kZXJtaSIsIlNhcmNvcHRlcnlnaWkiKSkpICU+JQ0KICBkcm9wX25hKHByZXBlbHZpY19sZW5ndGgsdG90YWxfbGVuZ3RoKSAlPiUNCiAgZ3JvdXBfYnkodGF4b24pICU+JQ0KICBzdW1tYXJpc2UoZ2VudXM9dW5pcXVlKGdlbnVzKSxwcmVwZWx2aWNfbGVuZ3RoPW1lYW4ocHJlcGVsdmljX2xlbmd0aCksDQogICAgICAgICAgICB0b3RhbF9sZW5ndGg9bWVhbih0b3RhbF9sZW5ndGgpLA0KICAgICAgICAgICAgc2hhcGU9dW5pcXVlKHNoYXBlKSxjbGFkZT11bmlxdWUoY2xhZGUpKSAlPiUNCiAgZ2dwbG90KC4sYWVzKHByZXBlbHZpY19sZW5ndGgvdG90YWxfbGVuZ3RoKSkgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwKSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDEpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKGZpbGw9Y2xhZGUpLGJpbndpZHRoPTAuMDEpKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiZGFya2dyZXkiLGh1ZV9wYWwoKSg1KSkpKw0KICBnZW9tX3ZsaW5lKGRhdGEgPSAuICU+JSANCiAgICAgICAgICAgICAgIGZpbHRlciAoIWNsYWRlICVpbiUgYygiQWNhbnRob3B0ZXJ5Z2lpIiwiR2FkaWZvcm1lcyIsIkF1bG9waWZvcm1lcyIpKSwNCiAgICAgICAgICAgICBhZXMoeGludGVyY2VwdCA9IG1lYW4ocHJlcGVsdmljX2xlbmd0aC90b3RhbF9sZW5ndGgpKSxsaW5ldHlwZT0iZGFzaGVkIikgKw0KICBjb29yZF9jYXJ0ZXNpYW4oeGxpbT1jKDAsMSkpKw0KICBsYWJzKHg9IlByZS1QZWx2aWMgTGVuZ3RoL1RvdGFsIExlbmd0aCIseT0iIyBvZiBTcGVjaWVzIixmaWxsPSJDbGFkZSIpKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb249YygwLjc3NSwwLjc1KSkNCg0KcDFfcGVsdiAvIHAyX3BlbHYgKyBwbG90X2xheW91dChoZWlnaHRzID0gMToyKSAmIHRoZW1lKHBsb3QubWFyZ2luID0gbWFyZ2luKDAsIDIwLCAwLCAwKSkNCmBgYA0KDQpPdmVyYWxsLCBwcmUtcGVsdmljIGxlbmd0aCBhcyBhIHByb3BvcnRpb24gb2YgdG90YWwgbGVuZ3RoIGlzIHJlbGF0aXZlbHkgY29uc2lzdGVudCBhY3Jvc3Mgbm9uLWFjYW50aG9wdGVyeWdpYW4gZmlzaGVzLiBPbiBhdmVyYWdlLCBwcmUtcGVsdmljIGxlbmd0aCBpcyBhcm91bmQgNDUlIG9mIHRvdGFsIGxlbmd0aCBpbiBub24tYWNhbnRob3B0ZXJ5Z2lhbiBmaXNoZXMsIHdpdGggYWxtb3N0IGFsbCB0YXhhIGZhbGxpbmcgYmV0d2VlbiAzNSUgYW5kIDU1JSB0b3RhbCBsZW5ndGguDQoNCk91dGxpZXJzIGRvIGV4aXN0IHdpdGhpbiB0aGlzIHJlbGF0aW9uc2hpcCwgYnV0IGZvciB0aGUgbW9zdCBwYXJ0IHRoZXNlIGFyZSByZXN0cmljdGVkIHRvIGNlcnRhaW4gcGh5bG9nZW5ldGljIG5vZGVzIHdpdGhpbiB0aGUgc2FtcGxlLiBBIG1vcmUgcG9zdGVyaW9yIHBlbHZpYyBmaW4gcG9zaXRpb24gKH42MCUgVEwpIGlzIHNlZW4gaW4gUG9seXB0ZXJpZm9ybWVzIGFuZCBkZWVwLXNlYSBTcXVhbGlmb3JtZXMgKENlbnRyb3Bob3JpZGFlLCBEYWxhdGlpZGFlLCBFdG1vcHRlcmlkYWUsIE94eW5vdGlkYWUsIFNvbW5pb3NpZGFlKSwgdGhlIGxhdHRlciBvZiB3aGljaCBmb3JtIGEgbW9ub3BoeWxldGljIGNsYWRlIChTdHJhdWJlIGV0IGFsLiAyMDE1KSBjaGFyYWN0ZXJpemVkIGJ5IGFuIGV4dHJlbWUgcG9zdGVyaW9yIHBvc2l0aW9uIG9mIHRoZSBwZWx2aWMgZmlucy4gTGFyZ2UgQ2FyY2hhcmhpbmlmb3JtZXMgYW5kIExhbW5pZm9ybWVzIGFsc28gaGF2ZSBzbGlnaHRseSBtb3JlIHBvc3Rlcmlvcmx5IHBvc2l0aW9uZWQgcGVsdmljIGZpbnMgdGhhbiBvdGhlciBzaGFya3MgKH41MCUgVEwpLCB3aGljaCBtYXkgYmUgZHVlIHRvIHRoZSBsYXJnZXIgbGl2ZXJzIG9mIHRoZXNlIHRheGEgKEdsZWlzcyBldCBhbC4gMjAxNykgYW5kIHRoZSBzaG9ydGVyIGFiZG9tZW5zIG9mIHBlbGFnaWMgTGFtbmlmb3JtZXMgKFN0ZXJuZXMgYW5kIFNoaW1hZGEgMjAyMCkuIFByZS1wZWx2aWMgbGVuZ3RoIGlzIGEgc21hbGxlciBwcm9wb3J0aW9uIG9mIGJvZHkgbGVuZ3RoIGluIEEgbW9yZSBhbnRlcmlvciBwb3NpdGlvbiBvZiB0aGUgcGVsdmljIGZpbnMgaXMgcHJlc2VudCBpbiBiZW50aGljIHNoYXJrcyB3aXRoIGVsb25nYXRlIGFiZG9tZW5zIChlLmcuLCBIZW1pc2N5bGxpZGFlOyBTdGVybmVzIGFuZCBTaGltYWRhIDIwMjApIGFuZCBzb21lIGNoYXJhY2lkcy4NCg0KKHJlZjpwZWx2cHJlY2F1ZGFsKSBQcmUtcGVsdmljIGxlbmd0aCBpbiBmaXNoZXMgYXMgYSBwcm9wb3J0aW9uIG9mIHRvdGFsIGxlbmd0aCAobGVmdCkgYW5kIHByZWNhdWRhbCBsZW5ndGggKHJpZ2h0KS4gRGFzaGVkIGxpbmUgcmVwcmVzZW50cyB0aGUgbWVhbiBwcm9wb3J0aW9uIGZvciBhbGwgbm9uLWFjYW50aG9wdGVyeWdpYW4sIGdhZGlmb3JtLCBhdWxvcGlmb3JtIGZpc2hlcyBpbiB3aGljaCB0aGlzIHZhbHVlIGNvdWxkIGJlIG1lYXN1cmVkLg0KDQpgYGB7cixmaWcuY2FwPSIocmVmOnBlbHZwcmVjYXVkYWwpIixmaWcud2lkdGg9MTF9DQojIHNlcGFyYXRpbmcgeS1heGlzIGludG8gY2xhZGVzIG9mIGludGVyZXN0DQoNCnBlbHZwcmVjYXVkYWxfMTwtDQogIGRhdGFfcmVjb24gJT4lDQogIG11dGF0ZShwcmVwZWx2aWNfbGVuZ3RoPWlmZWxzZShzcGVjaW1lbiAlaW4lICJDTUMgVlA4Mjk0IiwgNzAuNzcscHJlcGVsdmljX2xlbmd0aCksDQogICAgICAgICBwcmVwZWx2aWNfbGVuZ3RoPWlmZWxzZShzcGVjaW1lbiAlaW4lICJDTU5IIDc0MjQiLCA3MC4xNSxwcmVwZWx2aWNfbGVuZ3RoKSwNCiAgICAgICAgIHByZXBlbHZpY19sZW5ndGg9aWZlbHNlKHNwZWNpbWVuICVpbiUgIkNNTkggNjA5MCIsIDEyMS43NyxwcmVwZWx2aWNfbGVuZ3RoKSwNCiAgICAgICAgIHByZXBlbHZpY19sZW5ndGg9aWZlbHNlKHNwZWNpbWVuICVpbiUgIkNNTkggNzA1NCIsIDEyNi4wNixwcmVwZWx2aWNfbGVuZ3RoKSwNCiAgICAgICAgIHByZXBlbHZpY19sZW5ndGg9aWZlbHNlKHNwZWNpbWVuICVpbiUgIkNNTkggNTc2OCIsIDEzNy43MSxwcmVwZWx2aWNfbGVuZ3RoKSkgJT4lDQogIGZpbHRlcihsZW5ndGhfYXM9PSJ0b3RhbCBsZW5ndGgifGdlbnVzPT0iRHVua2xlb3N0ZXVzIikgJT4lDQogIG11dGF0ZShwdmwxID0gcHJlcGVsdmljX2xlbmd0aC90b3RhbF9sZW5ndGgsDQogICAgICAgICBwdmwyID0gcHJlcGVsdmljX2xlbmd0aC9wcmVjYXVkYWxfbGVuZ3RoLA0KICAgICAgICAgaGlnaGVyX2dyb3VwPWlmZWxzZShvcmRlciAlaW4lIGMoIkF1bG9waWZvcm1lcyIsIkdhZGlmb3JtZXMiKSwiQXVsb3BpZm9ybWVzLCBHYWRpZm9ybWVzIixoaWdoZXJfZ3JvdXApLA0KICAgICAgICAgaGlnaGVyX2dyb3VwPWlmZWxzZShmYW1pbHkgJWluJSBjKCJEYWxhdGlpZGFlIiwiRXRtb3B0ZXJpZGFlIiwiT3h5bm90aWRhZSIsIlNvbW5pb3NpZGFlIiwiQ2VudHJvcGhvcmlkYWUiKSwiRGVlcCBTZWEgU3F1YWxpZm9ybWVzIixoaWdoZXJfZ3JvdXApLA0KICAgICAgICAgaGlnaGVyX2dyb3VwPWlmZWxzZShvcmRlciA9PSAiQ2hpbWFlcmlmb3JtZXMiLCJIb2xvY2VwaGFsaSIsaGlnaGVyX2dyb3VwKSwNCiAgICAgICAgIGhpZ2hlcl9ncm91cD1pZmVsc2Uob3JkZXIgPT0gIkJlbG9uaWZvcm1lcyIsIkJlbG9uaWZvcm1lcyIsaGlnaGVyX2dyb3VwKSwNCiAgICAgICAgIGhpZ2hlcl9ncm91cD1pZmVsc2UoZ2VudXMgPT0gIkFsb3BpYXMiLCIqQWxvcGlhcyoiLGhpZ2hlcl9ncm91cCksDQogICAgICAgICBoaWdoZXJfZ3JvdXA9aWZlbHNlKG9yZGVyID09ICJJY2h0aHlvZGVjdGlmb3JtZXMiLCJJY2h0aHlvZGVjdGlmb3JtZXMiLGhpZ2hlcl9ncm91cCksDQogICAgICAgICBoaWdoZXJfZ3JvdXA9aWZlbHNlKGhpZ2hlcl9ncm91cD09IkNob25kcmljaHRoeWVzIiwiT3RoZXIgRWxhc21vYnJhbmNoaWkiLGhpZ2hlcl9ncm91cCksDQogICAgICAgICBoaWdoZXJfZ3JvdXA9aWZlbHNlKGdlbnVzPT0iRHVua2xlb3N0ZXVzIiwiKkR1bmtsZW9zdGV1cyogKGVzdC4pIixoaWdoZXJfZ3JvdXApKQ0KDQojIHN1bW1hcmlzaW5nIHZhbHVlcyBmb3Igbm9uLUR1bmtsZW9zdGV1cyB0YXhhICh0b3RhbCBsZW5ndGgpDQogICAgICAgICANCnBlbHZwcmVjYXVkYWxfMjwtYmluZF9yb3dzKHBlbHZwcmVjYXVkYWxfMSAlPiUNCiAgICAgICAgICAgIGZpbHRlcihnZW51cyA9PSAiRHVua2xlb3N0ZXVzIikgJT4lDQogICAgICAgICAgICBkcm9wX25hKHB2bDEpLA0KICAgICAgICAgIHBlbHZwcmVjYXVkYWxfMSAlPiUNCiAgICAgICAgICAgIGZpbHRlcihnZW51cyE9IkR1bmtsZW9zdGV1cyJ8aXMubmEoaGlnaGVyX2dyb3VwKSkgJT4lDQogICAgICAgICAgICBncm91cF9ieSh0YXhvbikgJT4lDQogICAgICAgICAgICBkcm9wX25hKHB2bDEpICU+JQ0KICAgICAgICAgICAgc3VtbWFyaXplKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSxtZWFuKSwNCiAgICAgICAgICAgICAgICAgICAgICBoaWdoZXJfZ3JvdXA9dW5pcXVlKGhpZ2hlcl9ncm91cCksDQogICAgICAgICAgICAgICAgICAgICAgdGF4b249dW5pcXVlKHRheG9uKSxnZW51cz11bmlxdWUoZ2VudXMpLHNwZWNpZXM9dW5pcXVlKHNwZWNpZXMpLA0KICAgICAgICAgICAgICAgICAgICAgIGNsYWRlPXVuaXF1ZShjbGFkZSxuYS5ybT1GKSxzaGFwZT11bmlxdWUoc2hhcGUpKSkgJT4lDQogIG11dGF0ZShoaWdoZXJfZ3JvdXA9ZmFjdG9yKGhpZ2hlcl9ncm91cCxvcmRlcmVkID0gVCwgbGV2ZWxzID0gYygiKkR1bmtsZW9zdGV1cyogKGVzdC4pIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFydGhyb2RpcmEiLCJPdGhlciBFbGFzbW9icmFuY2hpaSIsIipBbG9waWFzKiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJEZWVwIFNlYSBTcXVhbGlmb3JtZXMiLCJIb2xvY2VwaGFsaSIsIlNhcmNvcHRlcnlnaWkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQmFzYWwgQWN0aW5vcHRlcnlnaWkiLCJJY2h0aHlvZGVjdGlmb3JtZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQmFzYWwgVGVsZW9zdGVpIiwiT3RvY2VwaGFsYSIsIlN0ZW0gRXV0ZWxlb3N0ZWkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQXVsb3BpZm9ybWVzLCBHYWRpZm9ybWVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkJlbG9uaWZvcm1lcyIsIkFjYW50aG9wdGVyeWdpaSIpKSkNCg0KcGVsdnByZWNhdWRhbF8zPC1iaW5kX3Jvd3MocGVsdnByZWNhdWRhbF8xICU+JQ0KICAgICAgICAgICAgZmlsdGVyKGdlbnVzID09ICJEdW5rbGVvc3RldXMiKSAlPiUNCiAgICAgICAgICAgIGRyb3BfbmEocHZsMiksDQogICAgICAgICAgcGVsdnByZWNhdWRhbF8xICU+JQ0KICAgICAgICAgICAgZmlsdGVyKGdlbnVzIT0iRHVua2xlb3N0ZXVzInxpcy5uYShoaWdoZXJfZ3JvdXApKSAlPiUNCiAgICAgICAgICAgIGdyb3VwX2J5KHRheG9uKSAlPiUNCiAgICAgICAgICAgIGRyb3BfbmEocHZsMikgJT4lDQogICAgICAgICAgICBzdW1tYXJpemUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpLG1lYW4pLA0KICAgICAgICAgICAgICAgICAgICAgIGhpZ2hlcl9ncm91cD11bmlxdWUoaGlnaGVyX2dyb3VwKSwNCiAgICAgICAgICAgICAgICAgICAgICB0YXhvbj11bmlxdWUodGF4b24pLGdlbnVzPXVuaXF1ZShnZW51cyksc3BlY2llcz11bmlxdWUoc3BlY2llcyksDQogICAgICAgICAgICAgICAgICAgICAgY2xhZGU9dW5pcXVlKGNsYWRlLG5hLnJtPUYpLHNoYXBlPXVuaXF1ZShzaGFwZSkpKSAlPiUNCiAgbXV0YXRlKGhpZ2hlcl9ncm91cD1mYWN0b3IoaGlnaGVyX2dyb3VwLG9yZGVyZWQgPSBULCBsZXZlbHMgPSBjKCIqRHVua2xlb3N0ZXVzKiAoZXN0LikiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQXJ0aHJvZGlyYSIsIk90aGVyIEVsYXNtb2JyYW5jaGlpIiwiKkFsb3BpYXMqIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkRlZXAgU2VhIFNxdWFsaWZvcm1lcyIsIkhvbG9jZXBoYWxpIiwiU2FyY29wdGVyeWdpaSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCYXNhbCBBY3Rpbm9wdGVyeWdpaSIsIkljaHRoeW9kZWN0aWZvcm1lcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCYXNhbCBUZWxlb3N0ZWkiLCJPdG9jZXBoYWxhIiwiU3RlbSBFdXRlbGVvc3RlaSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBdWxvcGlmb3JtZXMsIEdhZGlmb3JtZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQmVsb25pZm9ybWVzIiwiQWNhbnRob3B0ZXJ5Z2lpIikpKQ0KDQpncmlkLmFycmFuZ2UobnJvdz0xLA0KcGVsdnByZWNhdWRhbF8yICU+JQ0KICBnZ3Bsb3QoYWVzKHg9cHZsMSx5PWhpZ2hlcl9ncm91cCxmaWxsPWNsYWRlKSkgKw0KICBsYWJzKHg9IlByZS1QZWx2aWMgTGVuZ3RoIix5PSJDbGFkZSIpKw0KICBnZ3RpdGxlKCJBcyBhIFByb3BvcnRpb24gb2YgVG90YWwgTGVuZ3RoIikrDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDApICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMSkgKw0KICBnZW9tX3ZsaW5lKGRhdGE9LiU+JWZpbHRlcighKG9yZGVyICVpbiUgYygiQXVsb3BpZm9ybWVzIiwiR2FkaWZvcm1lcyIsIkJlbG9uaWZvcm1lcyIpfA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VudXMgJWluJSAiRHVua2xlb3N0ZXVzInwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhpZ2hlcl9ncm91cD09IkFjYW50aG9wdGVyeWdpaSIpKSwNCiAgICAgICAgICAgICBhZXMoeGludGVyY2VwdD1tZWFuKHB2bDEpKSxsaW5ldHlwZT0iZGFzaGVkIikrDQogIHNjYWxlX3lfZGlzY3JldGUobGltaXRzPXJldikrDQogIGdlb21fdmlvbGluKHNjYWxlPSJ3aWR0aCIsc2hvdy5sZWdlbmQ9RikrDQogIGdlb21fYm94cGxvdCh3aWR0aD0wLjMsZmlsbD0id2hpdGUiKSsNCiAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X21hcmtkb3duKCkpKw0KICBjb29yZF9jYXJ0ZXNpYW4oeGxpbT1jKDAsMSkpDQosDQpwZWx2cHJlY2F1ZGFsXzMgJT4lDQogIGdncGxvdChhZXMoeD1wdmwyLHk9aGlnaGVyX2dyb3VwLGZpbGw9Y2xhZGUpKSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDApICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMSkgKw0KICBsYWJzKHg9IlByZS1QZWx2aWMgTGVuZ3RoIix5PSJDbGFkZSIpKw0KICBnZ3RpdGxlKCJBcyBhIFByb3BvcnRpb24gb2YgUHJlY2F1ZGFsIExlbmd0aCIpKw0KICBzY2FsZV95X2Rpc2NyZXRlKGxpbWl0cz1yZXYpKw0KICBnZW9tX3ZsaW5lKGRhdGE9LiU+JWZpbHRlcighKG9yZGVyICVpbiUgYygiQXVsb3BpZm9ybWVzIiwiR2FkaWZvcm1lcyIsIkJlbG9uaWZvcm1lcyIpfA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VudXMgJWluJSAiRHVua2xlb3N0ZXVzInwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhpZ2hlcl9ncm91cD09IkFjYW50aG9wdGVyeWdpaSIpKSwNCiAgICAgICAgICAgICBhZXMoeGludGVyY2VwdD1tZWFuKHB2bDIpKSxsaW5ldHlwZT0iZGFzaGVkIikrDQogIGdlb21fdmlvbGluKHNjYWxlPSJ3aWR0aCIsc2hvdy5sZWdlbmQ9RikrDQogIGdlb21fYm94cGxvdCh3aWR0aD0wLjMsZmlsbD0id2hpdGUiKSsNCiAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X21hcmtkb3duKCkpKw0KICBjb29yZF9jYXJ0ZXNpYW4oeGxpbT1jKDAsMSkpDQopDQpgYGANCg0KVGhlcmUgaXMgYSBzbGlnaHQgdGVuZGVuY3kgZm9yIHRoZSBwZWx2aWMgZ2lyZGxlIHRvIGJlIGluY3JlYXNpbmdseSBhbnRlcmlvciBpbiBwb3NpdGlvbiBhcyBvbmUgZ2V0cyBjbG9zZXIgdG8gQWNhbnRob3B0ZXJ5Z2lpLCBidXQgZXh0cmVtZSBhbnRlcmlvciBwb3NpdGlvbnMgb2YgdGhlIHBlbHZpcyAoPCAzMCUgdG90YWwgbGVuZ3RoKSBhcmUgcmVzdHJpY3RlZCB0byBjZXJ0YWluIG5lb3RlbGVvc3QgZ3JvdXBzIChBY2FudGhvcHRlcnlnaWksIEdhZGlmb3JtZXMsIGFuZCBzb21lIEF1bG9waWZvcm1lcyBhbW9uZyB0aGUgdGF4YSBleGFtaW5lZCBoZXJlKS4gTW9zdCBhY2FudGhvcHRlcnlnaWFucyBzaG93IG11Y2ggbW9yZSBhbnRlcmlvcmx5IHBvc2l0aW9uZWQgcGVsdmljIGdpcmRsZXMgdGhhbiBhbnkgbm9uLWFjYW50aG9wdGVyeWdpYW4sIGV4Y2VwdCBmb3IgQmVsb25pZm9ybWVzIHdoaWNoIHNob3cgYSBzZWNvbmRhcnkgcmV2ZXJzaW9uIHRvIGEgbm9uLWFjYW50aG9wdGVyeWdpYW4tbGlrZSBjb25kaXRpb24uIFN0ZW0gdGVsZW9zdCBsaW5lYWdlcyBnZW5lcmFsbHkgc2hvdyBhIHNsaWdodGx5IG1vcmUgYW50ZXJpb3IgcGVsdmlzIHBvc2l0aW9uIHJlbGF0aXZlIHRvIHByZWNhdWRhbCBsZW5ndGgsIGJ1dCB0aGlzIG1heSBiZSBjb25mb3VuZGVkIGJ5IHRoZSBmYWN0IHRoYXQgcHJlY2F1ZGFsIGxlbmd0aCAoPSBzdGFuZGFyZCBsZW5ndGgpIGluIGFjdGlub3B0ZXJ5Z2lhbnMgaXMgdHlwaWNhbGx5IG1lYXN1cmVkIHRvIHRoZSBlbmQgb2YgdGhlIGh5cHVyYWxzIChIdWJicyBhbmQgTGFnbGVyIDIwMDQpLCB3aGljaCB0eXBpY2FsbHkgbWVhbnMgc29tZSBvZiB0aGUgYmFzZSBvZiB0aGUgY2F1ZGFsIGZpbiBpcyBjb3VudGVkIGFzIHBhcnQgb2YgcHJlY2F1ZGFsIGxlbmd0aC4NCg0KVGhlIGh5cGVyLWVsb25nYXRlZCBJY2h0aHlvZGVjdGlmb3JtZXMgc2hvdyBhIHNpbWlsYXIgcG9zaXRpb24gb2YgdGhlIHBlbHZpYyBmaW5zIHJlbGF0aXZlIHRvIHRvdGFsIGxlbmd0aCBhbmQgcHJlY2F1ZGFsIGxlbmd0aCBhcyBvdGhlciBjbG9zZWx5IHJlbGF0ZWQgZmlzaGVzIChzdGVtLXRlbGVvc3RzOyBzZWUgZGlzY3Vzc2lvbiBpbiBDYXZpbiBldCBhbC4gMjAxMykuIFRoaXMgc3VnZ2VzdHMgdGhhdCBwZWx2aWMgZmluIHBvc2l0aW9uIGlzIGEgcmVsYXRpdmVseSBjb25zaXN0ZW50IHByb3BvcnRpb24gb2YgYm9keSBsZW5ndGggaW4gbm9uLWFjYW50aG9wdGVyeWdpYW4gZmlzaGVzIHJlZ2FyZGxlc3Mgb2YgdGhlIGRlZ3JlZSBvZiBib2R5IGVsb25nYXRpb24uDQoNClByZS1wZWx2aWMgbGVuZ3RocyBpbiBhcnRocm9kaXJlcyBrbm93biBmcm9tIGNvbXBsZXRlIHJlbWFpbnMgYXJlIGNsb3NlIHRvIHRoZSBhdmVyYWdlIGZvciBhbGwgbm9uLWFjYW50aG9wdGVyeWdpYW4gZmlzaGVzLCBhbmQgYXJlIHBhcnRpY3VsYXJseSBzaW1pbGFyIHRvIHRoZSBwcm9wb3J0aW9ucyBzZWVuIGluIHR5cGljYWwgZXh0YW50IGVsYXNtb2JyYW5jaHMuIFRoaXMgc3VnZ2VzdHMgYXJ0aHJvZGlyZXMgc2hvdyBhIHNpbWlsYXIgcmVsYXRpb25zaGlwIGJldHdlZW4gcGVsdmljIGdpcmRsZSBwb3NpdGlvbiBhbmQgdG90YWwgbGVuZ3RoIGFzIHRoZXNlIGZpc2hlcy4gQmVjYXVzZSB0aGUgcGVsdmljIGdpcmRsZSBvZiBhcnRocm9kaXJlcyBpcyBlaXRoZXIgaW1tZWRpYXRlbHkgcG9zdGVyaW9yIHRvIG9yIG90aGVyd2lzZSBjbG9zZSB0byB0aGUgZW5kIG9mIHRoZSB2ZW50cmFsIGFybW9yIChzZWUgbWFudXNjcmlwdCksIGluY2x1ZGluZyBpbiAqRHVua2xlb3N0ZXVzKiwgdGhpcyBzdWdnZXN0cyB0aGUgbGVuZ3RocyBmb3IgKkR1bmtsZW9zdGV1cyB0ZXJyZWxsaSogcHJlZGljdGVkIGJ5IEVuZ2VsbWFuICgyMDIzKSBhcmUgYWNjdXJhdGUuDQoNCiMjIyBFeGFtcGxlcyBvZiBwcmUtcGVsdmljIExlbmd0aCBpbiBleHRyZW1lIGJvZHkgc2hhcGVzDQoNCmBgYHtyfQ0KZGF0YV9yZWNvbiAlPiUNCiAgZmlsdGVyKGZhbWlseSAlaW4lIGMoIkNoZWlyb2NlbnRyaWRhZSIsIkxhbXByaWRhZSIsIlNlcnJhc2FsbWlkYWUiKXwNCiAgICAgICAgIG9yZGVyICVpbiUgYygiSWNodGh5b2RlY3RpZm9ybWVzIikpICU+JQ0KICBtdXRhdGUoZ3JvdXAgPSBjYXNlX3doZW4ob3JkZXIgPT0gIkljaHRoeW9kZWN0aWZvcm1lcyIgfiAiSWNodGh5b2RlY3RpZm9ybWVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhbWlseSA9PSAiTGFtcHJpZGFlIiB+ICJMYW1wcmlkYWUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFtaWx5ID09ICJDaGVpcm9jZW50cmlkYWUiIH4gIkNoZWlyb2NlbnRyaWRhZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBmYW1pbHkgPT0gIlNlcnJhc2FsbWlkYWUiIH4gIlNlcnJhc2FsbWlkYWUiKSkgJT4lDQogIGRyb3BfbmEocHJlcGVsdmljX2xlbmd0aCx0b3RhbF9sZW5ndGgpICU+JQ0KICBzdW1tYXJpc2UoLmJ5PXRheG9uLG9yZGVyPXVuaXF1ZShvcmRlciksZ3JvdXA9dW5pcXVlKGdyb3VwKSxuPW4oKSwNCiAgICAgICAgICAgIHB2bD1tZWFuKHByZXBlbHZpY19sZW5ndGgvdG90YWxfbGVuZ3RoKSkgJT4lDQogIHN1bW1hcmlzZSguYnk9Z3JvdXAsbjE9c3VtKG4pLG4yPW4oKSxtZWFuX3B2bD1tZWFuKHB2bCksDQogICAgICAgICAgICByYW5nZT1wYXN0ZTAoIigiLHJvdW5kKG1pbihwdmwpLDMpLCLigJMiLHJvdW5kKG1heChwdmwpLDMpLCIpIikpICU+JQ0KICBhcnJhbmdlKGdyb3VwKSAlPiUNCiAga2FibGUoZGlnaXRzPWMoMSwxLDEsMywxKSxhbGlnbj1jKCJsIiwiYyIsImMiLCJjIiwiYyIpLA0KICAgICAgICBjb2wubmFtZXMgPSBjKCJHcm91cCIsIk4uIE9icy4iLCJOLiBTcGVjaWVzIiwiTWVhbiIsIlJhbmdlIiksDQogICAgICAgIGNhcHRpb24gPSAiTWVhbiBwcmVwZWx2aWMgbGVuZ3RoIChhcyBhIHByb3BvcnRpb24gb2YgdG90YWwgbGVuZ3RoKSBmb3IgdGhlIGZvdXIgY2xhZGVzIG1lbnRpb25lZCBpbiB0aGUgbWFudXNjcmlwdCIpICU+JQ0KICBhZGRfaGVhZGVyX2Fib3ZlKGMoIiAiPTMsIlByZXBlbHZpYyBMZW5ndGgiPTIpKSAlPiUNCiAga2FibGVfc3R5bGluZygpDQpgYGANCg0KIyMjIFByZWRpY3RpbmcgaW4gKkR1bmtsZW9zdGV1cyB0ZXJyZWxsaSoNCg0KIyMjIyBTZXR0aW5nIHVwIFJlZ3Jlc3Npb25zDQoNCioqV2l0aG91dCBsb2ctdHJhbnNmb3JtYXRpb24qKg0KDQpgYGB7cn0NCmZpdC5wZWx2aWM8LWxtKHRvdGFsX2xlbmd0aH5wcmVwZWx2aWNfbGVuZ3RoICogSShoaWdoZXJfZ3JvdXAgPT0gIkFjYW50aG9wdGVyeWdpaSJ8b3JkZXIgJWluJSBjKCJHYWRpZm9ybWVzIiwiQXVsb3BpZm9ybWVzIikpLA0KICAgICAgICAgICAgICAgICBkYXRhPWRhdGFfcmVjb24gJT4lDQogICAgICAgICAgICAgICAgICAgZmlsdGVyKGxlbmd0aF9hcyE9ImVzdGltYXRlZCB0LmwuIikpDQoNCnN1bW1hcnkoZml0LnBlbHZpYykNCnJlZ3Jlc3Npb24uc3RhdHMoZml0LnBlbHZpYykNCmBgYA0KDQoqKldpdGggbG9nLXRyYW5zZm9ybWF0aW9uKioNCg0KYGBge3J9DQpmaXQucGVsdmljXzI8LWxtKGxvZyh0b3RhbF9sZW5ndGgpfmxvZyhwcmVwZWx2aWNfbGVuZ3RoKSAqIEkoaGlnaGVyX2dyb3VwID09ICJBY2FudGhvcHRlcnlnaWkifG9yZGVyICVpbiUgYygiR2FkaWZvcm1lcyIsIkF1bG9waWZvcm1lcyIpKSwNCiAgICAgICAgICAgICAgICAgICBkYXRhPWRhdGFfcmVjb24gJT4lDQogICAgICAgICAgICAgICAgICAgICBmaWx0ZXIobGVuZ3RoX2FzIT0iZXN0aW1hdGVkIHQubC4iKSkNCg0Kc3VtbWFyeShmaXQucGVsdmljXzIpDQpyZWdyZXNzaW9uLnN0YXRzKGZpdC5wZWx2aWNfMikNCmBgYA0KDQpNZW1iZXJzaGlwIGluIHRoZSBjbGFkZXMgQWNhbnRob3B0ZXJ5Z2lpLCBHYWRpZm9ybWVzLCBvciBBdWxvcGlmb3JtZXMgd2FzIHRyZWF0ZWQgYXMgYWRkaXRpb25hbCB2YXJpYWJsZSBiZWNhdXNlIHRoZXNlIHRheGEgc2hvdyBhIHNpZ25pZmljYW50bHkgbW9yZSBhbnRlcmlvciBwb3NpdGlvbiBvZiB0aGUgcGVsdmlzIHRoYW4gb3RoZXIgZmlzaGVzLCB3aGljaCBpZiBub3QgY29udHJvbGxlZCBmb3IgYXMgYW4gYWRkaXRpb25hbCB2YXJpYWJsZSBtaWdodCBiaWFzIHRoZSByZWdyZXNzaW9uLg0KDQpgYGB7cn0NCnJiaW5kKA0KICAiTG9nLXRyYW5zZm9ybWVkLCB3aXRoIGZhY3RvciIgPSByZWdyZXNzaW9uLnN0YXRzKGZpdC5wZWx2aWNfMiksDQogICJMb2ctdHJhbnNmb3JtZWQsIHdpdGhvdXQgZmFjdG9yIiA9IHJlZ3Jlc3Npb24uc3RhdHMobG0obG9nKHRvdGFsX2xlbmd0aCl+bG9nKHByZXBlbHZpY19sZW5ndGgpLGRhdGFfcmVjb24pKSkNCmBgYA0KDQpBcyBjYW4gYmUgc2VlbiBieSB0aGUgYWJvdmUgZGF0YSwgaW5jbHVkaW5nIHRoaXMgZmFjdG9yIG1hc3NpdmVseSBkZWNyZWFzZXMgcHJlZGljdGlvbiBlcnJvciwgYW5kIG5vdCBpbmNsdWRpbmcgaXQgaXMgbGlrZWx5IHRvIGJpYXMgYm9keSBsZW5ndGhzIGluIGZhdm9yIG9mIHNob3J0ZXIgZXN0aW1hdGVzIGR1ZSB0byB0aGUgY29uZGl0aW9uIGluIEFjYW50aG9wdGVyeWdpaSBhbmQgc2ltaWxhciBmaXNoZXMuDQoNCiMjIyMgRXN0aW1hdGluZw0KDQpgYGB7cix3YXJuaW5nPUZ9DQpkYXRhX3JlY29uICU+JSBmaWx0ZXIoZ2VudXM9PSJEdW5rbGVvc3RldXMiKSAlPiUNCiAgbXV0YXRlKHByZXBlbHZpY19sZW5ndGg9Y2FzZV93aGVuKHNwZWNpbWVuID09ICJDTUMgVlA4Mjk0IiB+IDcwLjc3LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3BlY2ltZW4gPT0gIkNNTkggNzQyNCIgfiA3MC4xNSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNwZWNpbWVuID09ICJDTU5IIDYwOTAiIH4gMTIxLjc3LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3BlY2ltZW4gPT0gIkNNTkggNzA1NCIgfiAxMjYuMDYsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzcGVjaW1lbiA9PSAiQ01OSCA1NzY4IiB+IDEzNy43MSwpKSAlPiUNCiAgZHJvcF9uYShwcmVwZWx2aWNfbGVuZ3RoKSAlPiUNCiAgYXJyYW5nZShwcmVwZWx2aWNfbGVuZ3RoKSAlPiUNCiAgcmVuYW1lKE9PTF9sZW5ndGg9dG90YWxfbGVuZ3RoKSAlPiUNCiAgYXVnbWVudChmaXQucGVsdmljLG5ld2RhdGE9LixpbnRlcnZhbD0icHJlZGljdGlvbiIpICU+JQ0KICByZW5hbWVfYXQodmFycyhzdGFydHNfd2l0aCgnLicpKSwgZnVucyhwYXN0ZTAoInBlbHZpYzEiLC4pKSklPiUNCiAgYXVnbWVudChmaXQucGVsdmljXzIsbmV3ZGF0YT0uLGludGVydmFsPSJwcmVkaWN0aW9uIikgJT4lDQogIG11dGF0ZShhY3Jvc3MoLmZpdHRlZDoudXBwZXIsfmV4cCguKSpyZWdyZXNzaW9uLnN0YXRzKGZpdC5wZWx2aWNfMikkQ0YpKSU+JQ0KICByZW5hbWVfYXQodmFycyhzdGFydHNfd2l0aCgnLicpKSwgZnVucyhwYXN0ZTAoInBlbHZpYzIiLC4pKSklPiUNCiAgbXV0YXRlKE9PTC5wZT1wYXN0ZTAoIigiLHJvdW5kKG1pbmxlbmd0aCwxKSwi4oCTIixyb3VuZChtYXhsZW5ndGgsMSksIikiKSwNCiAgICAgICAgIHBlbHZpYzEucmFuZ2U9cGFzdGUwKCIoIixyb3VuZChwZWx2aWMxLmxvd2VyLDEpLCLigJMiLHJvdW5kKHBlbHZpYzEudXBwZXIsMSksIikiKSwNCiAgICAgICAgIHBlbHZpYzIucmFuZ2U9cGFzdGUwKCIoIixyb3VuZChwZWx2aWMyLmxvd2VyLDEpLCLigJMiLHJvdW5kKHBlbHZpYzIudXBwZXIsMSksIikiKSklPiUNCiAgc2VsZWN0KHNwZWNpbWVuLHByZXBlbHZpY19sZW5ndGgsT09MX2xlbmd0aCxPT0wucGUsDQogICAgICAgICBwZWx2aWMxLmZpdHRlZCxwZWx2aWMxLnJhbmdlLA0KICAgICAgICAgcGVsdmljMi5maXR0ZWQscGVsdmljMi5yYW5nZSkgJT4lDQogIGthYmxlKGRpZ2l0cz0xLGNvbC5uYW1lcz1jKCJTcGVjaW1lbiIsIlByZXBlbHZpYyBMZW5ndGggKHNub3V0IHRvIGVuZCBvZiBhcm1vcikiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRXN0LiIsIisvLSAlUEUiLCJFc3QuIiwiOTUlIFAuSS4iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRXN0LiIsIjk1JSBQLkkuIiksDQogICAgICAgIGNhcHRpb249IlJvdWdoIGVzdGltYXRlcyBvZiB0b3RhbCBsZW5ndGggaW4gPGk+RHVua2xlb3N0ZXVzIHRlcnJlbGxpPC9pPiB1c2luZyBwcmVwZWx2aWMgbGVuZ3RoLCBhcHByb3hpbWF0ZWQgYXMgdGhlIGxlbmd0aCBmcm9tIHRoZSB0aXAgb2YgdGhlIHNub3V0IHRvIHRoZSBlbmQgb2YgdGhlIGFybW9yIGluIGFuIGFudGVyb3Bvc3RlcmlvciBsaW5lLiIsDQogICAgICAgIGFsaWduPWMoImwiLCJjIiwiYyIsImMiLCJjIiwiYyIsImMiLCJjIikpICU+JQ0KICBhZGRfaGVhZGVyX2Fib3ZlKGMoIiAiPTIsIk9yYml0LU9wZXJjdWxhciBMZW5ndGgiPTIsIlByZXBlbHZpYyBMZW5ndGgsIG5vbi1sb2ctdHJhbnNmb3JtZWQiPTIsDQogICAgICAgICAgICAgICAgICAgICAiUHJlcGVsdmljIExlbmd0aCwgbG9nLXRyYW5zZm9ybWVkIj0yKSkgJT4lDQogIGthYmxlX3N0eWxpbmcoKQ0KYGBgDQoNCkFzIHdpdGggcHJlcGVjdG9yYWwgbGVuZ3RoLCB0aG91Z2ggbGVuZ3RocyBiYXNlZCBvbiBPT0wgYXJlIG9uIHRoZSB2ZXJ5IGhpZ2ggZW5kIG9mIHRoZSBwcmVkaWN0aW9uIGludGVydmFsLiBBZ2FpbiwgZXZlbiB0aG91Z2ggdGhlIDk1JSBwcmVkaWN0aW9uIGludGVydmFscyBhcmUgd2lkZXIgdGhhbiBpbnRlcnZhbHMgYmFzZWQgb24gKy8tIFBFLCBhcHByb3hpbWF0ZSBwZWx2aWMgZ2lyZGxlIHBvc2l0aW9uIGZhdm9ycyBzaG9ydGVyIGxlbmd0aHMgZm9yICpEdW5rbGVvc3RldXMgdGVycmVsbGkqDQoNCk5ldmVydGhlbGVzcywgYmVjYXVzZSBwZWx2aWMgZ2lyZGxlIHBvc2l0aW9uIHNob3dzIHBoeWxvZ2VuZXRpYyBzaWduYWwgdGhyb3VnaG91dCBBY3Rpbm9wdGVyeWdpaSBhbmQgcHJlcGVsdmljIGxlbmd0aCBjYW4gb25seSBiZSBhcHByb3hpbWF0ZWQgaW4gKkQuIHRlcnJlbGxpKiwgdGhlc2UgbGVuZ3RocyBhcmUgY29uc2lkZXJlZCBsZXNzIHJlbGlhYmxlIHRoYW4gdGhlIG9uZXMgYmFzZWQgb24gT09MIChub3QgbGVhc3QgYmVjYXVzZSB0aGV5IHdvdWxkIHJlc3VsdCBpbiBhbiBhbmltYWwgd2l0aCBhIHRhaWwgdG9vIHNob3J0IHRvIGZ1bmN0aW9uKS4NCg0KIyMgUGVjdG9yYWwgRmluIEJhc2UNCg0KIyMjIEFsbG9tZXRyaWMgc2NhbGluZyByZWxhdGlvbnNoaXAgaW4gc2hhcmtzDQoNCioqQWdhaW5zdCB0b3RhbCBsZW5ndGgqKg0KDQpgYGB7cn0NCmRhdGFfcmVjb24gJT4lDQogIGZpbHRlcihjbGFkZT09IkNob25kcmljaHRoeWVzIikgJSQlDQogIGxtKGxvZzEwKHBlY19iYXNlKSB+IGxvZzEwKHRvdGFsX2xlbmd0aCkpICU+JQ0KICBzdW1tYXJ5KCkNCmBgYA0KDQpUaGUgc2xvcGUgZm9yIHRoZSBsb2ctdHJhbnNmb3JtZWQgcmVsYXRpb25zaGlwIGluIG5la3RvbmljIHNoYXJrcyBpcyBjbG9zZSB0byAxLCBzdWdnZXN0aW5nIHBlY3RvcmFsIGZpbiBiYXNlIHNpemUgc2NhbGVzIGlzb21ldHJpY2FsbHkgd2l0aCB0b3RhbCBsZW5ndGggaW4gc2hhcmtzLg0KDQoqKkFnYWluc3QgYm9keSBtYXNzKioNCg0KYGBge3J9DQpkYXRhX3JlY29uICU+JQ0KICBmaWx0ZXIoY2xhZGU9PSJDaG9uZHJpY2h0aHllcyIpICUkJQ0KICBsbShsb2cxMChwZWNfYmFzZSkgfiBsb2cxMChib2R5X21hc3MpKSAlPiUNCiAgc3VtbWFyeSgpDQpgYGANCg0KVGhlIHNsb3BlIHdoZW4gcmVncmVzc2luZyBsb2d+MTB+IHBlY3RvcmFsIGZpbiBiYXNlIGxlbmd0aCBhZ2FpbnN0IGxvZ34xMH4gYm9keSBtYXNzIGlzIGNsb3NlIHRvIDAuMzMsIGluZGljYXRpbmcgcGVjdG9yYWwgZmluIGJhc2Ugc2l6ZSBzY2FsZXMgd2l0aCBnZW9tZXRyaWMgc2ltaWxhcml0eSB0byBib2R5IG1hc3MgaW4gc2hhcmtzLiBUaGlzIGlzIGdlbmVyYWxseSBiZWNhdXNlIHNoYXJrcyBzaG93IHJlbGF0aXZlbHkgbGl0dGxlIGFsbG9tZXRyaWMgY2hhbmdlIGluIGJvZHkgc2hhcGUuDQoNCiMjIyBDb21wYXJpbmcgYXJ0aHJvZGlyZXMgYW5kIHNoYXJrcw0KDQoocmVmOnBlY2ZpbikgUGVjdG9yYWwgZmluIGJhc2UgbGVuZ3RoIHNjYWxlZCBhZ2FpbnN0IHRvdGFsIGxlbmd0aCAoKipBKiopIGFuZCBib2R5IG1hc3MgKCoqQioqKSBpbiBhcnRocm9kaXJlcyBhbmQgZWxhc21vYnJhbmNocy4gRm9yIGFydGhyb2RpcmVzLCB3aGl0ZSBzdGFycyByZXByZXNlbnQgKkR1bmtsZW9zdGV1cyosIGJsYWNrIHN0YXJzIHJlcHJlc2VudCBhcnRocm9kaXJlcyBrbm93biBmcm9tIGNvbXBsZXRlIGJvZHkgZm9zc2lscywgYW5kIGdyYXkgc3RhcnMgcmVwcmVzZW50IGFydGhyb2RpcmVzIGZvciB3aGljaCBib2R5IGxlbmd0aCB3YXMgZXN0aW1hdGVkIGZyb20gdGhlIE9PTCBlcXVhdGlvbiBpbiBFbmdlbG1hbiAoMjAyMykuIFRoZSBibGFjayBsaW5lIHJlcHJlc2VudHMgdGhlIGFsbG9tZXRyaWMgcmVsYXRpb25zaGlwIGZvciBlbGFzbW9icmFuY2hzIHdoZXJlYXMgdGhlIGdyYXkgcmVwcmVzZW50cyB0aGUgc2NhbGluZyByZWxhdGlvbnNoaXAgZm9yIHNoYXJrcy4gQ29sb3JzIGluIHRoZSBsZWdlbmQgZm9yIGVsYXNtb2JyYW5jaCBjbGFkZXMgaW4gdGhpcyBmaWd1cmUgYXJlIGZvbGxvd2VkIGluIHRoZSBmaWd1cmVzIGJlbG93Lg0KDQpgYGB7cixmaWcud2lkdGg9OSxmaWcuY2FwPSIocmVmOnBlY2ZpbikifQ0KcGVjX2Jhc2VfMTwtZGF0YV9yZWNvbiU+JQ0KICBkcm9wX25hKHBlY19iYXNlLGNsYWRlLHRvdGFsX2xlbmd0aCkgJT4lDQogIGdncGxvdChhZXModG90YWxfbGVuZ3RoLHBlY19iYXNlKSkrDQogIGdlb21fc3RhcihkYXRhPS4gJT4lIGZpbHRlcighKGNsYWRlPT0iUGxhY29kZXJtaSImZ2VudXMhPSJEdW5rbGVvc3RldXMiKSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZXMoZmlsbD1vcmRlcixzdGFyc2hhcGU9Y2xhZGUpLHNob3cubGVnZW5kPUYpKw0KICBnZW9tX3Ntb290aChkYXRhPS4gJT4lIGZpbHRlcighKGNsYWRlPT0iUGxhY29kZXJtaSImZ2VudXMhPSJEdW5rbGVvc3RldXMiKSksDQogICAgICAgICAgICAgIGZvcm11bGE9eX54LA0KICAgICAgICAgICAgICBhZXMoY29sb3I9Y2xhZGUpLG1ldGhvZD0ibG0iLGFscGhhPTAuMixzaG93LmxlZ2VuZD1GKSsNCiAgZ2VvbV9lcnJvcmJhcmgoZGF0YT0uJT4lIGZpbHRlcihjbGFkZT09IlBsYWNvZGVybWkiKSAlPiUgZHJvcF9uYShtaW5sZW5ndGgpLA0KICAgICAgICAgICAgICAgICBhZXMoeG1pbj1taW5sZW5ndGgseG1heD1tYXhsZW5ndGgpLA0KICAgICAgICAgICAgICAgICBoZWlnaHQ9MC43NSkrDQogIGdlb21fc3RhcihkYXRhPS4gJT4lIGZpbHRlcihnZW51cz09IkR1bmtsZW9zdGV1cyIpLA0KICAgICAgICAgICAgYWVzKGZpbGw9b3JkZXIsc3RhcnNoYXBlPWNsYWRlKSxzaG93LmxlZ2VuZD1GLHNpemU9MikrDQogIGdlb21fc3RhcihkYXRhPS4lPiVmaWx0ZXIoY2xhZGU9PSJQbGFjb2Rlcm1pIiAmIGdlbnVzIT0iRHVua2xlb3N0ZXVzIiAmDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZW5ndGhfYXMgPT0gInRvdGFsIGxlbmd0aCIpLA0KICAgICAgICAgICAgIGNvbG9yPSJ3aGl0ZSIsZmlsbD0iYmxhY2siLGFlcyhzdGFyc2hhcGU9Y2xhZGUpLHNpemU9Mi41LA0KICAgICAgICAgICAgc3RhcnN0cm9rZT0wLjMzLHNob3cubGVnZW5kID0gRikrDQogIGdlb21fc3RhcihkYXRhPS4lPiVmaWx0ZXIoY2xhZGU9PSJQbGFjb2Rlcm1pIiAmIGdlbnVzIT0iRHVua2xlb3N0ZXVzIiAmIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVuZ3RoX2FzPT0iZXN0aW1hdGVkIHQubC4iKSwNCiAgICAgICAgICAgIGNvbG9yPSJibGFjayIsZmlsbD0iZ3JheTQ1IixhZXMoc3RhcnNoYXBlPWNsYWRlKSxzaXplPTIuNSwNCiAgICAgICAgICAgIHN0YXJzdHJva2U9MC4zMyxzaG93LmxlZ2VuZCA9IEYpKw0KICBnZ3RpdGxlKCJBIikrDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCJ3aGl0ZSIsaHVlX3BhbCgpKDYpKSkrDQogIHNjYWxlX3N0YXJzaGFwZV9tYW51YWwodmFsdWVzPWMoMTUsMSkpKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoImJsYWNrIiwiZGFyayBncmV5IiwicmVkIikpKw0KICB0aGVtZV9jbGFzc2ljKCkrDQogIGxhYnMoeD0iVG90YWwgTGVuZ3RoIChjbSkiLHk9IlBlY3RvcmFsIEJhc2UgTGVuZ3RoIChjbSkiKQ0KcGVjX2Jhc2VfMiA8LSBkYXRhX3JlY29uICU+JQ0KICBkcm9wX25hKHBlY19iYXNlLGNsYWRlLGJvZHlfbWFzcykgJT4lDQogIGdncGxvdChhZXMoYm9keV9tYXNzLHBlY19iYXNlKSkrDQogIGdlb21fc3RhcihhZXMoZmlsbD1vcmRlcixzdGFyc2hhcGU9b3JkZXIpKSsNCiAgZ2VvbV9zbW9vdGgoZGF0YT0uICU+JSBmaWx0ZXIoIShjbGFkZT09IlBsYWNvZGVybWkiJmdlbnVzIT0iRHVua2xlb3N0ZXVzIikpLA0KICAgICAgICAgICAgICBmb3JtdWxhPXl+eCwNCiAgICAgICAgICAgICAgYWVzKGNvbG9yPWNsYWRlKSxtZXRob2Q9ImxtIixhbHBoYT0wLjIsc2hvdy5sZWdlbmQ9RikrDQogIGdlb21fc21vb3RoKGRhdGE9LiAlPiUgZmlsdGVyKCEoY2xhZGU9PSJQbGFjb2Rlcm1pIiZnZW51cyE9IkR1bmtsZW9zdGV1cyIpKSwNCiAgICAgICAgICAgICAgZm9ybXVsYT15fngsDQogICAgICAgICAgICAgIGNvbG9yPU5BLG1ldGhvZD0ibG0iLHNlPUYpKw0KICBnZW9tX2Vycm9yYmFyaChkYXRhPS4lPiUgZmlsdGVyKGNsYWRlPT0iUGxhY29kZXJtaSIpICU+JSBkcm9wX25hKG1pbm1hc3MpLA0KICAgICAgICAgICAgICAgICBhZXMoeG1pbj1taW5tYXNzLHhtYXg9bWF4bWFzcyksDQogICAgICAgICAgICAgICAgIGhlaWdodD0uMDIpKw0KICBnZW9tX3N0YXIoZGF0YT0uJT4lZmlsdGVyKGNsYWRlPT0iUGxhY29kZXJtaSIpLA0KICAgICAgICAgICAgY29sb3I9IndoaXRlIixmaWxsPSJ3aGl0ZSIsYWVzKHN0YXJzaGFwZT1vcmRlciksc2l6ZT0yLjUsDQogICAgICAgICAgICBzdGFyc3Ryb2tlPTAuNCxzaG93LmxlZ2VuZCA9IEYpKw0KICBnZW9tX3N0YXIoZGF0YT0uJT4lZmlsdGVyKGdlbnVzPT0iRHVua2xlb3N0ZXVzIiksDQogICAgICAgICAgICBjb2xvcj0iYmxhY2siLGZpbGw9IndoaXRlIixhZXMoc3RhcnNoYXBlPW9yZGVyKSxzaXplPTIsc2hvdy5sZWdlbmQgPSBGKSsNCiAgZ2VvbV9zdGFyKGRhdGE9LiU+JWZpbHRlcihjbGFkZT09IlBsYWNvZGVybWkiICYgZ2VudXMhPSJEdW5rbGVvc3RldXMiICYNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlbmd0aF9hcz09InRvdGFsIGxlbmd0aCIpLA0KICAgICAgICAgICAgY29sb3I9ImJsYWNrIixmaWxsPSJibGFjayIsYWVzKHN0YXJzaGFwZT1vcmRlciksc2l6ZT0yLA0KICAgICAgICAgICAgc3RhcnN0cm9rZT0wLjMzLHNob3cubGVnZW5kID0gRikrDQogIGdlb21fc3RhcihkYXRhPS4lPiVmaWx0ZXIoY2xhZGU9PSJQbGFjb2Rlcm1pIiAmIGdlbnVzIT0iRHVua2xlb3N0ZXVzIiAmIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVuZ3RoX2FzPT0iZXN0aW1hdGVkIHQubC4iKSwNCiAgICAgICAgICAgIGNvbG9yPSJibGFjayIsZmlsbD0iZ3JheTQ1IixhZXMoc3RhcnNoYXBlPW9yZGVyKSxzaXplPTIuNSwNCiAgICAgICAgICAgIHN0YXJzdHJva2U9MC4zMyxzaG93LmxlZ2VuZCA9IEYpKw0KICBnZW9tX3N0YXIoZGF0YT0uJT4lZmlsdGVyKGNsYWRlPT0iUGxhY29kZXJtaSImZ2VudXMhPSJEdW5rbGVvc3RldXMiKSwNCiAgICAgICAgICAgIGNvbG9yPSJibGFjayIsZmlsbD1OQSxhZXMoc3RhcnNoYXBlPW9yZGVyKSxzaXplPTIsDQogICAgICAgICAgICBzdGFyc3Ryb2tlPTAuMzMsc2hvdy5sZWdlbmQgPSBGKSsNCiAgZ2d0aXRsZSgiQiIpKw0KICBzY2FsZV94X2NvbnRpbnVvdXModHJhbnM9ImxvZzEwIiwNCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHNjYWxlczo6dHJhbnNfYnJlYWtzKCJsb2cxMCIsIGZ1bmN0aW9uKHgpIDEwXngsbj01KSwNCiAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IHNjYWxlczo6dHJhbnNfZm9ybWF0KCJsb2cxMCIsIHNjYWxlczo6bWF0aF9mb3JtYXQoMTBeLngpKSkrDQogIHNjYWxlX3lfY29udGludW91cyh0cmFucz0ibG9nMTAiKSsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCJibGFjayIsImRhcmsgZ3JleSIpKSsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoImJsYWNrIixodWVfcGFsKCkoNikpKSsNCiAgc2NhbGVfc3RhcnNoYXBlX21hbnVhbCh2YWx1ZXM9YygxLDE1LDE1LDE1LDE1LDE1LDE1KSkrDQogIGxhYnMoeD1icXVvdGUoIkxvZyJbMTBdfiJCb2R5IE1hc3MgKGcpIikseT1icXVvdGUoIkxvZyJbMTBdfiJQZWN0b3JhbCBCYXNlIExlbmd0aCAoY20pIiksDQogICAgICAgZmlsbD0iT3JkZXIiLGNvbG9yPSJPcmRlciIsc3RhcnNoYXBlPSJPcmRlciIpKw0KICB0aGVtZV9jbGFzc2ljKCkrDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj1jKDAuODUsMC4zKSkNCg0KZ3JpZC5hcnJhbmdlKG5yb3c9MSxwZWNfYmFzZV8xLHBlY19iYXNlXzIpDQpgYGANCg0KKHJlZjpwZWNmaW5maWd1cmUpIFBlY3RvcmFsIGZpbiBiYXNlIGxlbmd0aCBzY2FsZWQgYWdhaW5zdCB0b3RhbCBsZW5ndGggKCoqQSoqKSBhbmQgYm9keSBtYXNzICgqKkIqKikgc2hvd2luZyBzY2FsaW5nIHBhdHRlcm5zIGluICpEdW5rbGVvc3RldXMqICh3aGl0ZSBzdGFycywgZ3JheSBsaW5lKSB2ZXJzdXMgZWxhc21vYnJhbmNocyAoY2lyY2xlcywgYmxhY2sgbGluZSkuIFRoZSBvdXRsaWVyIHBvaW50ICpSaGluY29kb24qIGlzIG5vdCBzaG93biB0byBtYWtlIGl0IGVhc2llciB0byBpbnRlcnByZXQgcG9pbnRzIGluIHRoZSByZXN0IG9mIHRoZSBncmFwaC4gVGhpcyBmaWd1cmUgaXMgaWRlbnRpY2FsIHRvIEZpZ3VyZSAyMCBvZiB0aGUgbWFpbiBtYW51c2NyaXB0Lg0KDQpgYGB7cixjbGFzcy5zb3VyY2UgPSAnZm9sZC1oaWRlJyxmaWcuY2FwPSIocmVmOnBlY2ZpbmZpZ3VyZSkifQ0KcGVjX2Jhc2VfZmlndXJlMTwtZGF0YV9yZWNvbiAlPiUNCiAgZHJvcF9uYShwZWNfYmFzZSxjbGFkZSx0b3RhbF9sZW5ndGgpICU+JQ0KICBmaWx0ZXIoIShjbGFkZT09IlBsYWNvZGVybWkiJmdlbnVzIT0iRHVua2xlb3N0ZXVzIikpJT4lDQogIGdncGxvdChhZXModG90YWxfbGVuZ3RoLHBlY19iYXNlKSkrDQogIGdlb21fc3RhcihkYXRhPS4gJT4lIGZpbHRlcighKGNsYWRlPT0iUGxhY29kZXJtaSImZ2VudXMhPSJEdW5rbGVvc3RldXMiKSksDQogICAgICAgICAgICBhZXMoZmlsbD1vcmRlcixzdGFyc2hhcGU9Y2xhZGUpLHNob3cubGVnZW5kPUYpKw0KICBnZW9tX3Ntb290aChmb3JtdWxhPXl+eCwNCiAgICAgICAgICAgICAgYWVzKGNvbG9yPWNsYWRlKSxtZXRob2Q9ImxtIixhbHBoYT0wLjIsc2hvdy5sZWdlbmQ9RikrDQogIGdlb21fZXJyb3JiYXJoKGRhdGE9LiU+JSBmaWx0ZXIoY2xhZGU9PSJQbGFjb2Rlcm1pIikgJT4lIGRyb3BfbmEobWlubGVuZ3RoKSwNCiAgICAgICAgICAgICAgICAgYWVzKHhtaW49bWlubGVuZ3RoLHhtYXg9bWF4bGVuZ3RoKSwNCiAgICAgICAgICAgICAgICAgaGVpZ2h0PTAuNzUpKw0KICBnZ3RpdGxlKCJBIikrDQogIGdlb21fc3RhcihkYXRhPS4gJT4lIGZpbHRlcihnZW51cz09IkR1bmtsZW9zdGV1cyIpLA0KICAgICAgICAgICAgYWVzKGZpbGw9b3JkZXIsc3RhcnNoYXBlPWNsYWRlKSxzaG93LmxlZ2VuZD1GLHNpemU9Mi41KSsNCiAgZ2VvbV9zdGFyKGRhdGE9LiU+JWZpbHRlcihjbGFkZT09IlBsYWNvZGVybWkiJmdlbnVzIT0iRHVua2xlb3N0ZXVzIiksDQogICAgICAgICAgICBjb2xvcj0id2hpdGUiLGZpbGw9IndoaXRlIixhZXMoc3RhcnNoYXBlPWNsYWRlKSxzaXplPTMsDQogICAgICAgICAgICBzdGFyc3Ryb2tlPTAuMzMsc2hvdy5sZWdlbmQgPSBGKSsNCiAgZ2VvbV9zdGFyKGRhdGE9LiU+JWZpbHRlcihjbGFkZT09IlBsYWNvZGVybWkiICYgZ2VudXMhPSJEdW5rbGVvc3RldXMiICYNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlbmd0aF9hcz09InRvdGFsIGxlbmd0aCIpLA0KICAgICAgICAgICAgY29sb3I9ImJsYWNrIixmaWxsPSJibGFjayIsYWVzKHN0YXJzaGFwZT1jbGFkZSksc2l6ZT0yLjUsDQogICAgICAgICAgICBzdGFyc3Ryb2tlPTAuMzMsc2hvdy5sZWdlbmQgPSBGKSsNCiAgZ2VvbV9zdGFyKGRhdGE9LiU+JWZpbHRlcihjbGFkZT09IlBsYWNvZGVybWkiICYgZ2VudXMhPSJEdW5rbGVvc3RldXMiICYgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZW5ndGhfYXM9PSJlc3RpbWF0ZWQgdC5sLiIpLA0KICAgICAgICAgICAgY29sb3I9ImJsYWNrIixmaWxsPSJncmF5NDUiLGFlcyhzdGFyc2hhcGU9Y2xhZGUpLHNpemU9Mi41LA0KICAgICAgICAgICAgc3RhcnN0cm9rZT0wLjMzLHNob3cubGVnZW5kID0gRikrDQogIGdlb21fc3RhcihkYXRhPS4lPiVmaWx0ZXIoY2xhZGU9PSJQbGFjb2Rlcm1pIiZnZW51cyE9IkR1bmtsZW9zdGV1cyIpLA0KICAgICAgICAgICAgY29sb3I9ImJsYWNrIixmaWxsPU5BLGFlcyhzdGFyc2hhcGU9Y2xhZGUpLHNpemU9Mi41LA0KICAgICAgICAgICAgc3RhcnN0cm9rZT0wLjMzLHNob3cubGVnZW5kID0gRikrDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCJ3aGl0ZSIsaHVlX3BhbCgpKDYpKSkrDQogIHNjYWxlX3N0YXJzaGFwZV9tYW51YWwodmFsdWVzPWMoMTUsMSkpKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoImJsYWNrIiwiZGFyayBncmV5IiwicmVkIikpKw0KICBsYWJzKHg9IlRvdGFsIExlbmd0aCAoY20pIiwNCiAgICAgICB5PSJQZWN0b3JhbCBCYXNlIExlbmd0aCAoY20pIikgKw0KICBjb29yZF9jYXJ0ZXNpYW4oeGxpbT1jKC0xLDcwMCkseWxpbT1jKC0xLDUwKSkgKw0KICB0aGVtZV9jbGFzc2ljKCkNCg0KcGVjX2Jhc2VfZmlndXJlMiA8LSBkYXRhX3JlY29uICU+JQ0KICBkcm9wX25hKHBlY19iYXNlLGNsYWRlLGJvZHlfbWFzcykgJT4lDQogIGZpbHRlcighKGNsYWRlPT0iUGxhY29kZXJtaSImZ2VudXMhPSJEdW5rbGVvc3RldXMiKSklPiUNCiAgZ2dwbG90KGFlcyhib2R5X21hc3MscGVjX2Jhc2UpKSsNCiAgZ2VvbV9zbW9vdGgoZm9ybXVsYT15fngsYWVzKGNvbG9yPWNsYWRlKSxtZXRob2Q9ImxtIixzZT1GLHNob3cubGVnZW5kPVQpKw0KICBnZW9tX3N0YXIoYWVzKHN0YXJzaGFwZT1jbGFkZSksZmlsbD0id2hpdGUiKSsNCiAgZ2VvbV9zdGFyKGFlcyhmaWxsPW9yZGVyLHN0YXJzaGFwZT1jbGFkZSksc2hvdy5sZWdlbmQgPSBGKSsNCiAgZ2VvbV9zbW9vdGgoZm9ybXVsYT15fngsDQogICAgICAgICAgICAgIGFlcyhjb2xvcj1jbGFkZSksbWV0aG9kPSJsbSIsYWxwaGE9MC4yLHNob3cubGVnZW5kPUYpKw0KICBnZW9tX2Vycm9yYmFyaChkYXRhPS4lPiUgZmlsdGVyKGNsYWRlPT0iUGxhY29kZXJtaSIpICU+JSBkcm9wX25hKG1pbm1hc3MpLA0KICAgICAgICAgICAgICAgICBhZXMoeG1pbj1taW5tYXNzLHhtYXg9bWF4bWFzcyksDQogICAgICAgICAgICAgICAgIGhlaWdodD0uMDIpKw0KICBnZW9tX3N0YXIoZGF0YT0uJT4lZmlsdGVyKGNsYWRlPT0iUGxhY29kZXJtaSIpLA0KICAgICAgICAgICAgY29sb3I9IndoaXRlIixmaWxsPSJ3aGl0ZSIsYWVzKHN0YXJzaGFwZT1jbGFkZSksc2l6ZT0zLA0KICAgICAgICAgICAgc3RhcnN0cm9rZT0wLjQsc2hvdy5sZWdlbmQgPSBGKSsNCiAgZ2VvbV9zdGFyKGRhdGE9LiU+JWZpbHRlcihnZW51cz09IkR1bmtsZW9zdGV1cyIpLA0KICAgICAgICAgICAgY29sb3I9ImJsYWNrIixmaWxsPSJ3aGl0ZSIsYWVzKHN0YXJzaGFwZT1jbGFkZSksc2l6ZT0yLjUsc2hvdy5sZWdlbmQgPSBGKSsNCiAgZ2VvbV9zdGFyKGRhdGE9LiU+JWZpbHRlcihjbGFkZT09IlBsYWNvZGVybWkiICYgZ2VudXMhPSJEdW5rbGVvc3RldXMiICYNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlbmd0aF9hcz09InRvdGFsIGxlbmd0aCIpLA0KICAgICAgICAgICAgY29sb3I9ImJsYWNrIixmaWxsPSJibGFjayIsYWVzKHN0YXJzaGFwZT1jbGFkZSksc2l6ZT0yLjUsDQogICAgICAgICAgICBzdGFyc3Ryb2tlPTAuMzMsc2hvdy5sZWdlbmQgPSBGKSsNCiAgZ2VvbV9zdGFyKGRhdGE9LiU+JWZpbHRlcihjbGFkZT09IlBsYWNvZGVybWkiICYgZ2VudXMhPSJEdW5rbGVvc3RldXMiICYgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZW5ndGhfYXM9PSJlc3RpbWF0ZWQgdC5sLiIpLA0KICAgICAgICAgICAgY29sb3I9ImJsYWNrIixmaWxsPSJibGFjayIsYWVzKHN0YXJzaGFwZT1jbGFkZSksc2l6ZT0yLjUsDQogICAgICAgICAgICBzdGFyc3Ryb2tlPTAuMzMsc2hvdy5sZWdlbmQgPSBGLGFscGhhPTAuNykrDQogIGdlb21fc3RhcihkYXRhPS4lPiVmaWx0ZXIoY2xhZGU9PSJQbGFjb2Rlcm1pIiZnZW51cyE9IkR1bmtsZW9zdGV1cyIpLA0KICAgICAgICAgICAgY29sb3I9ImJsYWNrIixmaWxsPU5BLGFlcyhzdGFyc2hhcGU9Y2xhZGUpLHNpemU9Mi41LA0KICAgICAgICAgICAgc3RhcnN0cm9rZT0wLjMzLHNob3cubGVnZW5kID0gRikrDQogIGdndGl0bGUoIkIiKSsNCiAgc2NhbGVfeF9jb250aW51b3VzKHRyYW5zPSJsb2cxMCIsDQogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBzY2FsZXM6OnRyYW5zX2JyZWFrcygibG9nMTAiLCBmdW5jdGlvbih4KSAxMF54LG49NSksDQogICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBzY2FsZXM6OnRyYW5zX2Zvcm1hdCgibG9nMTAiLCBzY2FsZXM6Om1hdGhfZm9ybWF0KDEwXi54KSkpKw0KICBzY2FsZV95X2NvbnRpbnVvdXModHJhbnM9ImxvZzEwIikrDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiYmxhY2siLCJkYXJrIGdyZXkiKSwNCiAgICAgICAgICAgICAgICAgICAgIGxhYmVscz1jKCJFbGFzbW9icmFuY2hpaSIsIipEdW5rbGVvc3RldXMqIikpKw0KICBzY2FsZV9maWxsX21hbnVhbChndWlkZT0ibm9uZSIsdmFsdWVzPWMoIndoaXRlIixodWVfcGFsKCkoNikpKSsNCiAgc2NhbGVfc3RhcnNoYXBlX21hbnVhbCh2YWx1ZXM9YygxNSwxKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHM9YygiRWxhc21vYnJhbmNoaWkiLCIqRHVua2xlb3N0ZXVzKiIpKSsNCiAgbGFicyh4PWJxdW90ZSgiTG9nIlsxMF1+IkJvZHkgTWFzcyAoZykiKSx5PWJxdW90ZSgiTG9nIlsxMF1+IlBlY3RvcmFsIEJhc2UgTGVuZ3RoIChjbSkiKSwNCiAgICAgICBmaWxsPSJDbGFkZSIsY29sb3I9IkNsYWRlIixzdGFyc2hhcGU9IkNsYWRlIikrDQogIGNvb3JkX2NhcnRlc2lhbih4bGltPWMoMzYsMjI3MDAwMCkseWxpbT1jKDEsNTApKSsNCiAgdGhlbWVfY2xhc3NpYygpKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb249YygwLjc1LDAuMiksDQogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF9tYXJrZG93bigpKSsNCiAgZ3VpZGVzKHNoYXBlPShndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzPWxpc3QoZmlsbCA9IGMoIndoaXRlIikpKSkpDQoNCnBlY3RvcmFsX2Jhc2VfMjwtZ3JpZC5hcnJhbmdlKG5yb3c9MSxwZWNfYmFzZV9maWd1cmUxLHBlY19iYXNlX2ZpZ3VyZTIpDQoNCiMgVGhlc2UgeCx5IGNvb3JkaW5hdGVzIGFyZSBzdXBwb3NlZCB0byBiZSB0aGUgY29vcmRpbmF0ZXMgZ2dwbG90IHdvdWxkIG5vcm1hbGx5IHBsb3QgaWYgZXhjbHVkaW5nIHRoZSBvdXRsaWVyIFJoaW5jb2Rvbg0KDQpnZ3NhdmUoZmlsZW5hbWU9IlJlY29uc3RydWN0aW9uIG9mIER1bmtsZW9zdGV1cyBGaWd1cmUgMjAgKFBlY3RvcmFsIEJhc2UpLnRpZmYiLA0KICAgICAgIHBlY3RvcmFsX2Jhc2VfMiwNCiAgICAgICBkZXZpY2U9InRpZmYiLHdpZHRoPTE3NSxoZWlnaHQ9MTAwLA0KICAgICAgIGRwaT02MDAsdW5pdHM9Im1tIixjb21wcmVzc2lvbj0ibHp3IikNCmBgYA0KDQpXaGVuIGNvbXBhcmluZyBwZWN0b3JhbCBmaW4gYmFzZSBzaXplIGluIGFydGhyb2RpcmVzIGFuZCBuZWt0b25pYyBzaGFya3MsICpEdW5rbGVvc3RldXMqIGhhcyBhIG11Y2ggbGFyZ2VyIHBlY3RvcmFsIGZpbiBiYXNlIHRoYW4gZXh0YW50IHNoYXJrcyBhbmQgc2hvd3MgY2xlYXIgcG9zaXRpdmUgYWxsb21ldHJ5LiBIb3dldmVyLCB3aGVuIGNvbXBhcmluZyBhZ2FpbnN0IGJvZHkgbWFzcywgcGVjdG9yYWwgZmluIGJhc2Ugc2l6ZSBzY2FsZXMgYWxvbmcgcm91Z2hseSB0aGUgc2FtZSBsaW5lIGFzIHNoYXJrcyAocG9zc2libHkgYSBsaXR0bGUgbGFyZ2VyLCBidXQgbm90IG11Y2gpIGFuZCBzY2FsZXMgd2l0aCBnZW9tZXRyaWMgc2ltaWxhcml0eS4gVGhpcyBpcyBwcm9iYWJseSBiZWNhdXNlICpEdW5rbGVvc3RldXMqIHNob3dzIHBvc2l0aXZlIGFsbG9tZXRyeSBpbiBmaW5lbmVzcyByYXRpbywgYW5kIHRodXMgcG9zaXRpdmUgYWxsb21ldHJ5IGluIGJvZHkgbWFzcyBhdCBsYXJnZXIgYm9keSBsZW5ndGhzLg0KDQpXaGVuIGFkZGluZyBhZGRpdGlvbmFsIGFydGhyb2RpcmVzIHRvIHRoZSBhbmFseXNpcywgdGhlc2UgdGF4YSBzaG93IHNpbWlsYXIgcGVjdG9yYWwgZmluIGJhc2VzIHRvIGV4dGFudCBzaGFya3Mgd2hlbiBncmFwaGVkIGFnYWluc3QgdW50cmFuc2Zvcm1lZCB0b3RhbCBsZW5ndGggb3IgbG9nfjEwfi10cmFuc2Zvcm1lZCBib2R5IG1hc3MuIFRoZSBvbmx5IGV4Y2VwdGlvbnMgYXJlIHRoZSBwYWNoeW9zdGVvbW9ycGhzICpBbWF6aWNodGh5cyogYW5kICpFYXN0bWFub3N0ZXVzKiwgd2hpY2ggaGF2ZSBsYXJnZXIgcGVjdG9yYWwgZmlucyBiYXNlIGNsb3NlciBpbiBzaXplIHRvIGp1dmVuaWxlICpEdW5rbGVvc3RldXMqLiBIb3dldmVyLCBhcnRocm9kaXJlcyBzaG93aW5nIHNpbWlsYXIgcGVjdG9yYWwgZmluIGJhc2Ugc2l6ZXMgdG8gbW9kZXJuIHNoYXJrcyBtYXkgYmUgYW4gYXJ0aWZhY3Qgb2YgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHBlY3RvcmFsIGZpbiBiYXNlIGxlbmd0aCBhbmQgdG90YWwgbGVuZ3RoIG5vdCBiZWluZyBsb2ctdHJhbnNmb3JtZWQuIFdoZW4gdGhlIHNhbWUgZGF0YSBhcmUgbG9nLXRyYW5zZm9ybWVkIChpLmUuLCBjaGFuZ2VkIHRvIGFuIGFsbG9tZXRyaWMgc2NhbGUpLCB0aGV5IHNob3cgYSByZWxhdGl2ZWx5IGNvbnNpc3RlbnQsIHBvc2l0aXZlbHkgYWxsb21ldHJpYyByZWxhdGlvbnNoaXAgYmV0d2VlbiBwZWN0b3JhbCBmaW4gYmFzZSBsZW5ndGggYW5kIHRvdGFsIGxlbmd0aCAoc2VlIGZpZ3VyZSA0LjE1LCBiZWxvdykuDQoNCihyZWY6cGVjZmludGVzdCkgUGVjdG9yYWwgZmluIGJhc2UgbGVuZ3RoIHNjYWxlZCBhZ2FpbnN0IHVudHJhbnNmb3JtZWQgYm9keSBtYXNzICgqKkEqKikgYW5kIGJvZHkgbWFzcyByYWlzZWQgdG8gdGhlIDEvMyBwb3dlciAoKipCKiopLiAqKkEqKiBzaG93cyBob3cgdGhlIHR3byBtZWFzdXJlbWVudHMgZG8gbm90IHNjYWxlIGxpbmVhcmx5LCBiZWNhdXNlIHRoZSBncmFwaCByZWdyZXNzZXMgYSBsaW5lYXIgbWVhc3VyZW1lbnQgKHBlY3RvcmFsIGZpbiBiYXNlIGxlbmd0aCkgYWdhaW5zdCBhIHZvbHVtZXRyaWMgb25lIChib2R5IG1hc3MpLiBUaGUgc2NhbGUtbG9jYXRpb24gZ3JhcGggb2YgdGhlIHJlc2lkdWFscyBvZiBhbiB1bnRyYW5zZm9ybWVkIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsIHNob3dlZCBzaWduaWZpY2FudCBoZXRlcm9za2VkYXN0aWNpdHksIHN1Z2dlc3RpbmcgbG9nLXRyYW5zZm9ybWF0aW9uIHdhcyBuZWNlc3NhcnkuIEJ5IHRha2luZyB0aGUgY3ViaWMgcm9vdCBvZiBib2R5IG1hc3MsICoqQioqIGNvbnZlcnRzIGJvZHkgbWFzcyBpbnRvIGEgZm9ybSB0aGF0IGNhbiBiZSBtb3JlIGRpcmVjdGx5IGNvbXBhcmVkIHRvIGEgbGluZWFyIG1lYXN1cmVtZW50Lg0KDQpgYGB7cixmaWcud2lkdGg9OSxmaWcuY2FwPSIocmVmOnBlY2ZpbnRlc3QpIn0NCmdyaWQuYXJyYW5nZShucm93PTEsDQpkYXRhX3JlY29uICU+JQ0KICBkcm9wX25hKHBlY19iYXNlLGJvZHlfbWFzcyxjbGFkZSxvcmRlcikgJT4lDQogIGdncGxvdChhZXMoYm9keV9tYXNzLHBlY19iYXNlKSkrDQogIGdlb21fZXJyb3JiYXJoKGRhdGE9LiU+JSBmaWx0ZXIoY2xhZGU9PSJQbGFjb2Rlcm1pIikgJT4lIGRyb3BfbmEobWlubWFzcyksDQogICAgICAgICAgICAgICAgIGFlcyh4bWluPW1pbm1hc3MseG1heD1tYXhtYXNzKSwNCiAgICAgICAgICAgICAgICAgaGVpZ2h0PTAuNzUpKw0KICBnZW9tX3N0YXIoYWVzKGZpbGw9b3JkZXIsc3RhcnNoYXBlPWNsYWRlKSxzaG93LmxlZ2VuZD1GKSsNCiAgZ2d0aXRsZShsYWJlbD0iQSIpKw0KICBnZW9tX3N0YXIoZGF0YT0uJT4lZmlsdGVyKGdlbnVzPT0iRHVua2xlb3N0ZXVzIiksDQogICAgICAgICAgICBjb2xvcj0iYmxhY2siLGZpbGw9IndoaXRlIixhZXMoc3RhcnNoYXBlPWNsYWRlKSxzaXplPTIuNSxzaG93LmxlZ2VuZCA9IEYpKw0KICBnZW9tX3N0YXIoZGF0YT0uJT4lZmlsdGVyKGNsYWRlPT0iUGxhY29kZXJtaSImZ2VudXMhPSJEdW5rbGVvc3RldXMiKSwNCiAgICAgICAgICAgIGNvbG9yPSJ3aGl0ZSIsZmlsbD0id2hpdGUiLGFlcyhzdGFyc2hhcGU9Y2xhZGUpLHNpemU9MywNCiAgICAgICAgICAgIHN0YXJzdHJva2U9MC4zMyxzaG93LmxlZ2VuZCA9IEYpKw0KICBnZW9tX3N0YXIoZGF0YT0uJT4lZmlsdGVyKGNsYWRlPT0iUGxhY29kZXJtaSIgJiBnZW51cyE9IkR1bmtsZW9zdGV1cyIgJg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVuZ3RoX2FzPT0idG90YWwgbGVuZ3RoIiksDQogICAgICAgICAgICBjb2xvcj0iYmxhY2siLGZpbGw9ImJsYWNrIixhZXMoc3RhcnNoYXBlPWNsYWRlKSxzaXplPTIuNSwNCiAgICAgICAgICAgIHN0YXJzdHJva2U9MC4zMyxzaG93LmxlZ2VuZCA9IEYpKw0KICBnZW9tX3N0YXIoZGF0YT0uJT4lZmlsdGVyKGNsYWRlPT0iUGxhY29kZXJtaSIgJiBnZW51cyE9IkR1bmtsZW9zdGV1cyIgJiANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlbmd0aF9hcz09ImVzdGltYXRlZCB0LmwuIiksDQogICAgICAgICAgICBjb2xvcj0iYmxhY2siLGZpbGw9ImdyYXk0NSIsYWVzKHN0YXJzaGFwZT1jbGFkZSksc2l6ZT0yLjUsDQogICAgICAgICAgICBzdGFyc3Ryb2tlPTAuMzMsc2hvdy5sZWdlbmQgPSBGKSsNCiAgZ2VvbV9zdGFyKGRhdGE9LiU+JWZpbHRlcihjbGFkZT09IlBsYWNvZGVybWkiJmdlbnVzIT0iRHVua2xlb3N0ZXVzIiksDQogICAgICAgICAgICBjb2xvcj0iYmxhY2siLGZpbGw9TkEsYWVzKHN0YXJzaGFwZT1jbGFkZSksc2l6ZT0yLjUsDQogICAgICAgICAgICBzdGFyc3Ryb2tlPTAuMzMsc2hvdy5sZWdlbmQgPSBGKSsNCiAgc2NhbGVfeF9jb250aW51b3VzKHRyYW5zPSJsb2cxMCIsDQogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBzY2FsZXM6OnRyYW5zX2JyZWFrcygibG9nMTAiLCBmdW5jdGlvbih4KSAxMF54LG49NSksDQogICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBzY2FsZXM6OnRyYW5zX2Zvcm1hdCgibG9nMTAiLCBzY2FsZXM6Om1hdGhfZm9ybWF0KDEwXi54KSkpKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoImJsYWNrIiwiZGFyayBncmV5IikpKw0KICBzY2FsZV9maWxsX21hbnVhbChndWlkZT0ibm9uZSIsdmFsdWVzPWMoIndoaXRlIixodWVfcGFsKCkoNikpKSsNCiAgc2NhbGVfc3RhcnNoYXBlX21hbnVhbCh2YWx1ZXM9YygxNSwxKSkrDQogIGxhYnMoeD0iQm9keSBNYXNzIChnKSIseT0iUGVjdG9yYWwgQmFzZSBMZW5ndGggKGNtKSIsDQogICAgICAgZmlsbD0iQ2xhZGUiLGNvbG9yPSJDbGFkZSIsc3RhcnNoYXBlPSJDbGFkZSIpKw0KICB0aGVtZV9jbGFzc2ljKCkrDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj1jKDAuNzUsMC4yKSkrDQogIGd1aWRlcyhzaGFwZT0oZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcz1saXN0KGZpbGwgPSBjKCJ3aGl0ZSIpKSkpKSwNCmRhdGFfcmVjb24gJT4lDQogIGRyb3BfbmEocGVjX2Jhc2UsYm9keV9tYXNzLGNsYWRlLG9yZGVyKSAlPiUNCiAgZ2dwbG90KGFlcyhib2R5X21hc3NeKDEvMykscGVjX2Jhc2UpKSsNCiAgZ2VvbV9zbW9vdGgoZm9ybXVsYT15fngsYWVzKGNvbG9yPWNsYWRlKSxtZXRob2Q9ImxtIixhbHBoYT0wLjIsc2hvdy5sZWdlbmQ9RikrDQogIGdlb21fc21vb3RoKGZvcm11bGE9eX54LGNvbG9yPU5BLG1ldGhvZD0ibG0iLHNlPUYpKw0KICBnZW9tX2Vycm9yYmFyaChkYXRhPS4lPiUgZmlsdGVyKGNsYWRlPT0iUGxhY29kZXJtaSIpICU+JSBkcm9wX25hKG1pbm1hc3MpLA0KICAgICAgICAgICAgICAgICBhZXMoeG1pbj1taW5tYXNzXigxLzMpLHhtYXg9bWF4bWFzc14oMS8zKSksDQogICAgICAgICAgICAgICAgIGhlaWdodD0wLjc1KSsNCiAgZ2VvbV9zdGFyKGFlcyhmaWxsPW9yZGVyLHN0YXJzaGFwZT1jbGFkZSkpKw0KICBnZW9tX3N0YXIoZGF0YT0uJT4lZmlsdGVyKGdlbnVzPT0iRHVua2xlb3N0ZXVzIiksDQogICAgICAgICAgICBjb2xvcj0iYmxhY2siLGZpbGw9IndoaXRlIixhZXMoc3RhcnNoYXBlPWNsYWRlKSxzaXplPTIuNSxzaG93LmxlZ2VuZCA9IEYpKw0KICBnZW9tX3N0YXIoZGF0YT0uJT4lZmlsdGVyKGNsYWRlPT0iUGxhY29kZXJtaSImZ2VudXMhPSJEdW5rbGVvc3RldXMiKSwNCiAgICAgICAgICAgIGNvbG9yPSJ3aGl0ZSIsZmlsbD0id2hpdGUiLGFlcyhzdGFyc2hhcGU9Y2xhZGUpLHNpemU9MywNCiAgICAgICAgICAgIHN0YXJzdHJva2U9MC4zMyxzaG93LmxlZ2VuZCA9IEYpKw0KICBnZW9tX3N0YXIoZGF0YT0uJT4lZmlsdGVyKGNsYWRlPT0iUGxhY29kZXJtaSIgJiBnZW51cyE9IkR1bmtsZW9zdGV1cyIgJg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVuZ3RoX2FzPT0idG90YWwgbGVuZ3RoIiksDQogICAgICAgICAgICBjb2xvcj0iYmxhY2siLGZpbGw9ImJsYWNrIixhZXMoc3RhcnNoYXBlPWNsYWRlKSxzaXplPTIuNSwNCiAgICAgICAgICAgIHN0YXJzdHJva2U9MC4zMyxzaG93LmxlZ2VuZCA9IEYpKw0KICBnZW9tX3N0YXIoZGF0YT0uJT4lZmlsdGVyKGNsYWRlPT0iUGxhY29kZXJtaSIgJiBnZW51cyE9IkR1bmtsZW9zdGV1cyIgJiANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlbmd0aF9hcz09ImVzdGltYXRlZCB0LmwuIiksDQogICAgICAgICAgICBjb2xvcj0iYmxhY2siLGZpbGw9ImdyYXk0NSIsYWVzKHN0YXJzaGFwZT1jbGFkZSksc2l6ZT0yLjUsDQogICAgICAgICAgICBzdGFyc3Ryb2tlPTAuMzMsc2hvdy5sZWdlbmQgPSBGKSsNCiAgZ2VvbV9zdGFyKGRhdGE9LiU+JWZpbHRlcihjbGFkZT09IlBsYWNvZGVybWkiJmdlbnVzIT0iRHVua2xlb3N0ZXVzIiksDQogICAgICAgICAgICBjb2xvcj0iYmxhY2siLGZpbGw9TkEsYWVzKHN0YXJzaGFwZT1jbGFkZSksc2l6ZT0yLjUsDQogICAgICAgICAgICBzdGFyc3Ryb2tlPTAuMzMsc2hvdy5sZWdlbmQgPSBGKSsNCiAgZ2d0aXRsZShsYWJlbD0iQiIpKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoImJsYWNrIiwiZGFyayBncmV5IikpKw0KICBzY2FsZV9maWxsX21hbnVhbChndWlkZT0ibm9uZSIsdmFsdWVzPWMoIndoaXRlIixodWVfcGFsKCkoNikpKSsNCiAgc2NhbGVfc3RhcnNoYXBlX21hbnVhbCh2YWx1ZXM9YygxNSwxKSkrDQogIGxhYnMoeD1icXVvdGUoIkJvZHkgTWFzcyAoZykiXiIxLzMiKSx5PSJQZWN0b3JhbCBCYXNlIExlbmd0aCAoY20pIiwNCiAgICAgICBmaWxsPSJDbGFkZSIsY29sb3I9IkNsYWRlIixzdGFyc2hhcGU9IkNsYWRlIikrDQogIHRoZW1lX2NsYXNzaWMoKSsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPWMoMC43NSwwLjIpKSsNCiAgZ3VpZGVzKHNoYXBlPShndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzPWxpc3QoZmlsbCA9IGMoIndoaXRlIikpKSkpDQopDQpgYGANCg0KUGVjdG9yYWwgZmluIGJhc2UgbGVuZ3RoIGFuZCBib2R5IG1hc3MgaW4gRmlndXJlIDQuMTJiIGhhZCB0byBiZSBsb2cgdHJhbnNmb3JtZWQsIGJlY2F1c2UgaXQgaW52b2x2ZXMgcmVncmVzc2luZyBhIGxpbmVhciBtZWFzdXJlbWVudCBhZ2FpbnN0IGEgdm9sdW1ldHJpYyBvbmUgKEZpZ3VyZSA0LjEzYSkuIEhvd2V2ZXIsIGlmIHBsb3R0aW5nIHBlY3RvcmFsIGZpbiBiYXNlIGxlbmd0aCBhZ2FpbnN0IHRoZSBjdWJpYyByb290IG9mIGJvZHkgbWFzcyAoRmlndXJlIDQuMTNiKSwgd2hpY2ggZXNzZW50aWFsbHkgdHJhbnNmb3JtcyB0aGUgdm9sdW1ldHJpYyBib2R5IG1hc3MgaW50byBhIGZvcm0gdGhhdCBjYW4gYmUgZGlyZWN0bHkgY29tcGFyZWQgYWdhaW5zdCBhIGxpbmVhciBtZWFzdXJlbWVudCwgYSBzaW1pbGFyIHJlbGF0aW9uc2hpcCBpcyBmb3VuZCB0byBGaWd1cmUgNC4xMmIuDQoNCihyZWY6bG9ncGVjZmlubGVuZ3RoKSBQbG90IG9mIGxvZ34xMH4tdHJhbnNmb3JtZWQgcGVjdG9yYWwgZmluIGJhc2UgbGVuZ3RoIHBsb3R0ZWQgYWdhaW5zdCBsb2d+MTB+IHRvdGFsIGxlbmd0aC4gQmxhY2sgbGluZSByZXByZXNlbnRzIGFsbG9tZXRyaWMgcmVsYXRpb25zaGlwIGZvciBleHRhbnQgQ2hvbmRyaWNodGh5ZXMgYW5kIGdyYXkgbGluZSBmb3IgRXVicmFjaHl0aG9yYWNpLiBXaGl0ZSBzdGFycyByZXByZXNlbnQgKkR1bmtsZW9zdGV1cyosIGJsYWNrIHN0YXJzIHJlcHJlc2VudCBhcnRocm9kaXJlcyBrbm93biBmcm9tIGNvbXBsZXRlIHJlbWFpbnMsIGFuZCBncmF5IHN0YXJzIHJlcHJlc2VudCB0YXhhIHdpdGggdG90YWwgbGVuZ3RoIGVzdGltYXRlZCB2aWEgT09MLg0KDQpgYGB7cixmaWcuY2FwPSIocmVmOmxvZ3BlY2Zpbmxlbmd0aCkiLGZpZy53aWR0aD02fQ0KZGF0YV9yZWNvbiAlPiUNCiAgZHJvcF9uYShwZWNfYmFzZSxjbGFkZSx0b3RhbF9sZW5ndGgpICU+JQ0KICBnZ3Bsb3QoYWVzKHRvdGFsX2xlbmd0aCxwZWNfYmFzZSkpKw0KICBnZW9tX3N0YXIoZGF0YT0uICU+JSBmaWx0ZXIoIShjbGFkZT09IlBsYWNvZGVybWkiJmdlbnVzIT0iRHVua2xlb3N0ZXVzIikpLA0KICAgICAgICAgICAgYWVzKGZpbGw9b3JkZXIsc3RhcnNoYXBlPWNsYWRlKSxzaG93LmxlZ2VuZD1GKSsNCiAgZ2VvbV9zbW9vdGgoZm9ybXVsYT15fngsDQogICAgICAgICAgICAgIGFlcyhjb2xvcj1jbGFkZSksbWV0aG9kPSJsbSIsYWxwaGE9MC4yLHNob3cubGVnZW5kPUYpKw0KICBnZW9tX2Vycm9yYmFyaChkYXRhPS4lPiUgZmlsdGVyKGNsYWRlPT0iUGxhY29kZXJtaSIpICU+JSBkcm9wX25hKG1pbmxlbmd0aCksDQogICAgICAgICAgICAgICAgIGFlcyh4bWluPW1pbmxlbmd0aCx4bWF4PW1heGxlbmd0aCksDQogICAgICAgICAgICAgICAgIGhlaWdodD0wLjAyKSsNCiAgZ2VvbV9zdGFyKGRhdGE9LiAlPiUgZmlsdGVyKGdlbnVzPT0iRHVua2xlb3N0ZXVzIiksDQogICAgICAgICAgICBhZXMoZmlsbD1vcmRlcixzdGFyc2hhcGU9Y2xhZGUpLHNob3cubGVnZW5kPUYsc2l6ZT0yLjUpKw0KICBnZW9tX3N0YXIoZGF0YT0uJT4lZmlsdGVyKGNsYWRlPT0iUGxhY29kZXJtaSImZ2VudXMhPSJEdW5rbGVvc3RldXMiKSwNCiAgICAgICAgICAgIGNvbG9yPSJ3aGl0ZSIsZmlsbD0id2hpdGUiLGFlcyhzdGFyc2hhcGU9Y2xhZGUpLHNpemU9MywNCiAgICAgICAgICAgIHN0YXJzdHJva2U9MC4zMyxzaG93LmxlZ2VuZCA9IEYpKw0KICBnZW9tX3N0YXIoZGF0YT0uJT4lZmlsdGVyKGNsYWRlPT0iUGxhY29kZXJtaSIgJiBnZW51cyE9IkR1bmtsZW9zdGV1cyIgJg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVuZ3RoX2FzPT0idG90YWwgbGVuZ3RoIiksDQogICAgICAgICAgICBjb2xvcj0iYmxhY2siLGZpbGw9ImJsYWNrIixhZXMoc3RhcnNoYXBlPWNsYWRlKSxzaXplPTIuNSwNCiAgICAgICAgICAgIHN0YXJzdHJva2U9MC4zMyxzaG93LmxlZ2VuZCA9IEYpKw0KICBnZW9tX3N0YXIoZGF0YT0uJT4lZmlsdGVyKGNsYWRlPT0iUGxhY29kZXJtaSIgJiBnZW51cyE9IkR1bmtsZW9zdGV1cyIgJiANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlbmd0aF9hcz09ImVzdGltYXRlZCB0LmwuIiksDQogICAgICAgICAgICBjb2xvcj0iYmxhY2siLGZpbGw9ImdyYXk0NSIsYWVzKHN0YXJzaGFwZT1jbGFkZSksc2l6ZT0yLjUsDQogICAgICAgICAgICBzdGFyc3Ryb2tlPTAuMzMsc2hvdy5sZWdlbmQgPSBGKSsNCiAgZ2VvbV9zdGFyKGRhdGE9LiU+JWZpbHRlcihjbGFkZT09IlBsYWNvZGVybWkiJmdlbnVzIT0iRHVua2xlb3N0ZXVzIiksDQogICAgICAgICAgICBjb2xvcj0iYmxhY2siLGZpbGw9TkEsYWVzKHN0YXJzaGFwZT1jbGFkZSksc2l6ZT0yLjUsDQogICAgICAgICAgICBzdGFyc3Ryb2tlPTAuMzMsc2hvdy5sZWdlbmQgPSBGKSsNCiAgc2NhbGVfeF9jb250aW51b3VzKHRyYW5zPSJsb2cxMCIpKw0KICBzY2FsZV95X2NvbnRpbnVvdXModHJhbnM9ImxvZzEwIikrDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCJ3aGl0ZSIsaHVlX3BhbCgpKDYpKSkrDQogIHNjYWxlX3N0YXJzaGFwZV9tYW51YWwodmFsdWVzPWMoMTUsMSkpKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoImJsYWNrIiwiZGFyayBncmV5IiwicmVkIikpKw0KICB0aGVtZV9jbGFzc2ljKCkrDQogIGxhYnMoeD1icXVvdGUoIkxvZyJbMTBdfiJUb3RhbCBMZW5ndGggKGNtKSIpLA0KICAgICAgIHk9YnF1b3RlKCJMb2ciWzEwXX4iUGVjdG9yYWwgQmFzZSBMZW5ndGggKGNtKSIpKQ0KYGBgDQoNCldoZW4gc2NhbGluZyBsb2d+MTB+IHBlY3RvcmFsIGZpbiBiYXNlIGxlbmd0aCBhZ2FpbnN0IGxvZ34xMH4gdG90YWwgbGVuZ3RoLCBhcnRocm9kaXJlcyBnZW5lcmFsbHkgaGF2ZSBwcm9wb3J0aW9uYWxseSBsYXJnZXIgcGVjdG9yYWwgZmluIGJhc2VzIHRoYW4gZXh0YW50IG5la3RvbmljIGNob25kcmljaHRoeWFucy4gVGhpcyByZWxhdGlvbnNoaXAgaXMgZ2VuZXJhbGx5IG9ic2N1cmVkIGluIHRoZSBwcmlvciBmaWd1cmUgYmVjYXVzZSB0aGUgZGF0YSB3YXMgbm90IGxvZy10cmFuc2Zvcm1lZCwgbWFraW5nIHByb3BvcnRpb25hbCByZWxhdGlvbnNoaXBzIG1vcmUgZGlmZmljdWx0IHRvIGRpc2Nlcm4gYXQgc21hbGxlciBzaXplcy4gVGhpcyBpcyByYXRoZXIgc3VycHJpc2luZyBnaXZlbiBjb2Njb3N0ZW9tb3JwaHMgYXJlIGdlbmVyYWxseSBjb25zaWRlcmVkIHRvIGJlIGxlc3MgbmVrdG9uaWMgdGhhbiBjYXJjaGFyaGluaWRzLCBoZXhhbmNoaWlkcywgZXRjLiwgYW5kIG5vbi1wYWNoeW9zdGVvbW9ycGggYXJ0aHJvZGlyZXMgYXJlIG9mdGVuIGNvbnNpZGVyZWQgdG8gaGF2ZSBzbWFsbCBmaW4gYmFzZXMuDQoNCldpdGhpbiBBcnRocm9kaXJhIHRoZXJlIGlzIHNvbWUgdmFyaWF0aW9uIGluIHBlY3RvcmFsIGZpbiBiYXNlIHNpemUuIFNtYWxsZXIgcGVjdG9yYWwgZmluIGJhc2VzIGFyZSBzZWVuIGluICpNaWxsZXJvc3RldXMqIGFuZCBjYW11cm9waXNjaWRzLCB3aGVyZWFzIGxhcmdlciBvbmVzIGFyZSBzZWVuIGluIHBhY2h5b3N0ZW9tb3JwaHMuIEl0IGlzIHBvc3NpYmxlIHRoZSBsYXJnZSBmaW4gYmFzZSBvZiAqRHVua2xlb3N0ZXVzKiBpcyByZWxhdGVkIHRvIHRoZSBnZW5lcmFsIGVubGFyZ2VtZW50IG9mIHRoZSBwZWN0b3JhbCBmZW5lc3RyYSBpbiBwYWNoeW9zdGVvbW9ycGggYXJ0aHJvZGlyZXMgKFN0ZW5zacO2IDE5NTksIE1pbGVzIDE5NjksIENhcnIgMTk5NSksIGFzIHRoZSBhc3Bpbm90aG9yYWNpZGFucyAqQW1hemljaHRoeXMqLCAqQnJhY2h5b3N0ZXVzKiwgKkVuc2Vvc3RldXMqLCBhbmQgKkhlaW50emljaHRoeXMqIGFuZCB0aGUgZ2VvbG9naWNhbGx5IG9sZGVyIGR1bmtsZW9zdGVvaWQgKkVhc3RtYW5vc3RldXMgY2FsbGlhc3BpcyogYWxzbyBoYXZlIHJlbGF0aXZlbHkgbGFyZ2UgcGVjdG9yYWwgZmluIGJhc2VzIGZvciB0aGVpciBzaXplLiBIb3dldmVyLCBpdCBpcyBhbHNvIHBvc3NpYmxlIHRoaXMgaXMgYSBicm9hZGVyIHBhdHRlcm4gZHVlIHRvIGFsbG9tZXRyeS4gSW5jbHVkaW5nIGRhdGEgZnJvbSBhZGRpdGlvbmFsIHBhY2h5b3N0ZW9tb3JwaHMgbWlnaHQgcHJvdmlkZSBhIGJldHRlciB1bmRlcnN0YW5kaW5nIG9mIHBlY3RvcmFsIGZpbiBzY2FsaW5nIGluIGFydGhyb2RpcmVzLCBidXQgYSBtb3JlIGV4dGVuc2l2ZSBleGFtaW5hdGlvbiBvZiBwZWN0b3JhbCBmaW4gYmFzZSBldm9sdXRpb24gYWNyb3NzIGV1YnJhY2h5dGhvcmFjaWQgYXJ0aHJvZGlyZXMgaXMgYmV5b25kIHRoZSBzY29wZSBvZiB0aGlzIHN0dWR5Lg0KDQpgYGB7cn0NCmRhdGFfcmVjb24gJT4lDQogIGRyb3BfbmEocGVjX2Jhc2UpICU+JQ0KICBmaWx0ZXIoIShjbGFkZT09IlBsYWNvZGVybWkiJmdlbnVzIT0iRHVua2xlb3N0ZXVzIikpICU+JQ0KICBtdXRhdGUoY2xhZGU9aWZlbHNlKGdlbnVzPT0iRHVua2xlb3N0ZXVzIiwiRHVua2xlb3N0ZXVzIixjbGFkZSkpICUkJQ0KICBsbShsb2cxMChwZWNfYmFzZSl+bG9nMTAoYm9keV9tYXNzKSpjbGFkZSwuKSAlPiUNCiAgc3VtbWFyeSgpDQpgYGANCg0KV2hlbiBjb21wYXJpbmcgYWxsb21ldHJpYyByZWdyZXNzaW9uIGVxdWF0aW9ucyBiZXR3ZWVuIHBlY3RvcmFsIGZpbiBiYXNlIHNpemUgYW5kIGJvZHkgbWFzcyBpbiAqRHVua2xlb3N0ZXVzKiBhbmQgZWxhc21vYnJhbmNocyAobm90IGNvbnNpZGVyaW5nIG90aGVyIGFydGhyb2RpcmVzKSwgdGhlIHR3byBzaG93IG5vbi1zaWduaWZpY2FudCBkaWZmZXJlbmNlcyBpbiBzbG9wZSBhbmQgaW50ZXJjZXB0Lg0KDQojIyBTZXR0aW5nIHVwIFBlY3RvcmFsIGFuZCBQZWx2aWMgT3JpZ2luIEZpZ3VyZQ0KDQpgYGB7cix3YXJuaW5nPUZ9DQpwMV9wZWNfYSA8LSBnZ3Bsb3Qocmhpem8sIGFlcyh4LCB5KSkgKw0KICAgIGdlb21fcG9seWdvbihmaWxsID0gImRhcmtncmV5Iixjb2xvcj0iYmxhY2siLCBhbHBoYSA9IDAuNSkgKw0KICAgIGdlb21fbGluZShkYXRhPWRhdGEuZnJhbWUoeD1jKDEsMSkseT1jKDAuMjQ3MTY3MjAwMCwtMC4wMykpKSsNCiAgICBnZW9tX2xpbmUoZGF0YT1kYXRhLmZyYW1lKHg9YygwLDApLHk9YygwLjE2Mjc4MzEwMDAsLTAuMDMpKSkrDQogICAgZ2VvbV9saW5lKGRhdGE9ZGF0YS5mcmFtZSh4PWMoMCwwLjIyNSwwLjIyNSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PWMoMC4wNTUsMC4wNTUsMC4xMDUpKSwNCiAgICAgICAgICAgICAgbGluZXdpZHRoPTEuMjUsY29sb3I9InN0ZWVsYmx1ZSIpKw0KICAgIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoMCwwLjMzKSkrDQogICAgYW5ub3RhdGUoInRleHQiLGxhYmVsPSJwcmUtcGVjdG9yYWwgbGVuZ3RoIix4PTAuMjU3LHk9MC4wMyxoanVzdD0xLHNpemU9My4xNjMxMzgpKw0KICAgIGFubm90YXRlKGdlb209InRleHQiLGxhYmVsPSJOIFNwZWNpZXMiLHg9Ljk5LHk9MC4wMSxoanVzdD0xLHNpemU9My4yNSkrDQogICAgdGhlbWUoYXhpcy50aXRsZS54PWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICBheGlzLnRleHQueD1lbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgYXhpcy50aWNrcy54PWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICBheGlzLnRpdGxlLnk9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgIGF4aXMudGV4dC55PWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICBheGlzLnRpY2tzLnk9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgIGF4aXMubGluZS55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgIGF4aXMubGluZS54ID0gZWxlbWVudF9ibGFuaygpKSsNCiAgICB0aGVtZV92b2lkKCkNCg0KcDFfcGVsdl9hIDwtIGdncGxvdChyaGl6bywgYWVzKHgsIHkpKSArDQogICAgZ2VvbV9wb2x5Z29uKGZpbGwgPSAiZGFya2dyZXkiLGNvbG9yPSJibGFjayIsIGFscGhhID0gMC41KSArDQogICAgZ2VvbV9saW5lKGRhdGE9ZGF0YS5mcmFtZSh4PWMoMSwxKSx5PWMoMC4yNDcxNjcyMDAwLC0wLjAzKSkpKw0KICAgIGdlb21fbGluZShkYXRhPWRhdGEuZnJhbWUoeD1jKDAsMCkseT1jKDAuMTYyNzgzMTAwMCwtMC4wMykpKSsNCiAgICBnZW9tX2xpbmUoZGF0YT1kYXRhLmZyYW1lKHg9YygwLDAuNDU0LDAuNDU0KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9YygwLjA1NSwwLjA1NSwwLjEwNSkpLA0KICAgICAgICAgICAgICBsaW5ld2lkdGg9MS4yNSxjb2xvcj0ic3RlZWxibHVlIikrDQogICAgY29vcmRfY2FydGVzaWFuKHlsaW09YygwLDAuMzMpKSsNCiAgICBhbm5vdGF0ZSgidGV4dCIsbGFiZWw9InByZS1wZWx2aWMgbGVuZ3RoIix4PTAuNDU0LHk9MC4wMyxoanVzdD0wLjUsc2l6ZT0zLjE2MzEzOCkrDQogICAgYW5ub3RhdGUoZ2VvbT0idGV4dCIsbGFiZWw9Ik4gU3BlY2llcyIseD0uOTkseT0wLjAxLGhqdXN0PTEsc2l6ZT0zLjI1KSsNCiAgICB0aGVtZShheGlzLnRpdGxlLng9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgIGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICBheGlzLnRpY2tzLng9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgIGF4aXMudGl0bGUueT1lbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgYXhpcy50ZXh0Lnk9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgIGF4aXMudGlja3MueT1lbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgYXhpcy5saW5lLnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgYXhpcy5saW5lLnggPSBlbGVtZW50X2JsYW5rKCkpKw0KICAgIHRoZW1lX3ZvaWQoKQ0KDQpwMl9wZWNfYSA8LSBwcmVwZWNfMiAlPiUNCiAgbXV0YXRlKGhpZ2hlcl9ncm91cD1pZmVsc2UoaGlnaGVyX2dyb3VwPT0iRHVua2xlb3N0ZXVzIiwiRHVua2xlb3N0ZXVzKiIsYXMuY2hhcmFjdGVyKGhpZ2hlcl9ncm91cCkpLA0KICAgICAgICAgaGlnaGVyX2dyb3VwPWlmZWxzZShoaWdoZXJfZ3JvdXA9PSJBcnRocm9kaXJhIChrbm93biBsZW5ndGhzKSIsIkFydGhyb2RpcmEgKGtub3duKSoiLGhpZ2hlcl9ncm91cCksDQogICAgICAgICBoaWdoZXJfZ3JvdXA9aWZlbHNlKGhpZ2hlcl9ncm91cD09IkFydGhyb2RpcmEgKGVzdC4gbGVuZ3RocykiLCJBcnRocm9kaXJhIChlc3QuKSoiLGhpZ2hlcl9ncm91cCkpICU+JQ0KICBtdXRhdGUoaGlnaGVyX2dyb3VwPWZhY3RvcihoaWdoZXJfZ3JvdXAsb3JkZXJlZD1ULA0KICAgICAgICAgICAgICAgICAgICAgIGxldmVscz1jKCJEdW5rbGVvc3RldXMqIiwiRWFzdG1hbm9zdGV1cyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFydGhyb2RpcmEgKGtub3duKSoiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBcnRocm9kaXJhIChlc3QuKSoiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJPdGhlciBFbGFzbW9icmFuY2hpaSIsICJIb2xvY2VwaGFsaSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFsb3BpYXMiLCJTYXJjb3B0ZXJ5Z2lpIiwiQmFzYWwgQWN0aW5vcHRlcnlnaWkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJJY2h0aHlvZGVjdGlmb3JtZXMiLCAiQmFzYWwgVGVsZW9zdGVpIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiT3RvY2VwaGFsYSIsICJTdGVtIEV1dGVsZW9zdGVpIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFjYW50aG9wdGVyeWdpaSIsIkFuZ3VpbGxpZm9ybSBUYXhhIikpKSAlPiUNCiAgZ2dwbG90KGFlcyh4PXByZXBlY3RvcmFsX2xlbmd0aC90b3RhbF9sZW5ndGgseT1oaWdoZXJfZ3JvdXApKSArDQogIGNvb3JkX2NhcnRlc2lhbih4bGltPWMoMCwxKSkrDQogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQpKw0KICBzY2FsZV95X2Rpc2NyZXRlKGxpbWl0cz1yZXYpKw0KICBsYWJzKHg9IlByZS1QZWN0b3JhbCBMZW5ndGggKGFzIHBlcmNlbnQgb2YgdG90YWwgbGVuZ3RoKSIseT0iQ2xhZGUiKSsNCiAgZ2VvbV92bGluZShkYXRhPS4gJT4lIGZpbHRlcihnZW51cz09IkR1bmtsZW9zdGV1cyIpLA0KICAgICAgICAgICAgIGFlcyh4aW50ZXJjZXB0PW1lYW4ocHJlcGVjdG9yYWxfbGVuZ3RoL3RvdGFsX2xlbmd0aCkpLA0KICAgICAgICAgICAgIGNvbG9yPSIjMDBCMEY2IixsaW5ldHlwZT0iZGFzaGVkIikrDQogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9bWVhbihwcmVwZWN0b3JhbF9sZW5ndGgvdG90YWxfbGVuZ3RoKSksDQogICAgICAgICAgICAgbGluZXR5cGU9ImRhc2hlZCIpKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwKSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDEpICsNCiAgZ2VvbV92aW9saW4oYWVzKGZpbGw9Y2xhZGUpLHNob3cubGVnZW5kID0gRixzY2FsZT0id2lkdGgiKSsNCiAgZ2VvbV92aW9saW4oZGF0YT0uJT4lZmlsdGVyKGdlbnVzPT0iRHVua2xlb3N0ZXVzIiksZmlsbD0iIzAwQjBGNiIsDQogICAgICAgICAgICAgIHNob3cubGVnZW5kID0gRixzY2FsZT0id2lkdGgiKSsNCiAgZ2VvbV9ib3hwbG90KHdpZHRoPTAuMykrDQogIGdlb21fc3RhcihkYXRhPS4gJT4lIGZpbHRlcihnZW51cz09IkVhc3RtYW5vc3RldXMiKSwNCiAgICAgICAgICAgIGZpbGw9IndoaXRlIixjb2xvcj0iYmxhY2siLHNpemU9Mi41KSsNCiAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoZmFjZT1jKHJlcCgicGxhaW4iLDgpLCJpdGFsaWMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwKCJwbGFpbiIsNCksIml0YWxpYyIsIml0YWxpYyIpKSkNCg0KcDJfcGVsdl9hXzE8LQ0KICBkYXRhX3JlY29uICU+JQ0KICBtdXRhdGUocHJlcGVsdmljX2xlbmd0aD1pZmVsc2Uoc3BlY2ltZW4gJWluJSAiQ01DIFZQODI5NCIsIDcwLjc3LHByZXBlbHZpY19sZW5ndGgpLA0KICAgICAgICAgcHJlcGVsdmljX2xlbmd0aD1pZmVsc2Uoc3BlY2ltZW4gJWluJSAiQ01OSCA3NDI0IiwgNzAuMTUscHJlcGVsdmljX2xlbmd0aCksDQogICAgICAgICBwcmVwZWx2aWNfbGVuZ3RoPWlmZWxzZShzcGVjaW1lbiAlaW4lICJDTU5IIDYwOTAiLCAxMjEuNzcscHJlcGVsdmljX2xlbmd0aCksDQogICAgICAgICBwcmVwZWx2aWNfbGVuZ3RoPWlmZWxzZShzcGVjaW1lbiAlaW4lICJDTU5IIDcwNTQiLCAxMjYuMDYscHJlcGVsdmljX2xlbmd0aCksDQogICAgICAgICBwcmVwZWx2aWNfbGVuZ3RoPWlmZWxzZShzcGVjaW1lbiAlaW4lICJDTU5IIDU3NjgiLCAxMzcuNzEscHJlcGVsdmljX2xlbmd0aCkpICU+JQ0KICBmaWx0ZXIobGVuZ3RoX2FzPT0idG90YWwgbGVuZ3RoInxnZW51cz09IkR1bmtsZW9zdGV1cyIpICU+JQ0KICBtdXRhdGUoaGlnaGVyX2dyb3VwPWlmZWxzZShvcmRlciAlaW4lIGMoIkF1bG9waWZvcm1lcyIsIkdhZGlmb3JtZXMiKSwiQXVsb3BpZm9ybWVzLCBHYWRpZm9ybWVzIixoaWdoZXJfZ3JvdXApLA0KICAgICAgICAgaGlnaGVyX2dyb3VwPWlmZWxzZShmYW1pbHkgJWluJSBjKCJEYWxhdGlpZGFlIiwiRXRtb3B0ZXJpZGFlIiwiT3h5bm90aWRhZSIsIlNvbW5pb3NpZGFlIiwiQ2VudHJvcGhvcmlkYWUiKSwiRGVlcCBTZWEgU3F1YWxpZm9ybWVzIixoaWdoZXJfZ3JvdXApLA0KICAgICAgICAgaGlnaGVyX2dyb3VwPWlmZWxzZShvcmRlciA9PSAiQ2hpbWFlcmlmb3JtZXMiLCJIb2xvY2VwaGFsaSIsaGlnaGVyX2dyb3VwKSwNCiAgICAgICAgIGhpZ2hlcl9ncm91cD1pZmVsc2UoaGlnaGVyX2dyb3VwID09ICJBY2FudGhvcHRlcnlnaWkiLCJPdGhlciBBY2FudGhvcHRlcnlnaWkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoaWdoZXJfZ3JvdXApLA0KICAgICAgICAgaGlnaGVyX2dyb3VwPWlmZWxzZShvcmRlciA9PSAiQmVsb25pZm9ybWVzIiwiQmVsb25pZm9ybWVzIixoaWdoZXJfZ3JvdXApLA0KICAgICAgICAgaGlnaGVyX2dyb3VwPWlmZWxzZShnZW51cyA9PSAiQWxvcGlhcyIsIipBbG9waWFzKiIsaGlnaGVyX2dyb3VwKSwNCiAgICAgICAgIGhpZ2hlcl9ncm91cD1pZmVsc2Uob3JkZXIgPT0gIkljaHRoeW9kZWN0aWZvcm1lcyIsIkljaHRoeW9kZWN0aWZvcm1lcyIsaGlnaGVyX2dyb3VwKSwNCiAgICAgICAgIGhpZ2hlcl9ncm91cD1pZmVsc2UoaGlnaGVyX2dyb3VwPT0iQ2hvbmRyaWNodGh5ZXMiLCJPdGhlciBFbGFzbW9icmFuY2hpaSIsaGlnaGVyX2dyb3VwKSwNCiAgICAgICAgIGhpZ2hlcl9ncm91cD1pZmVsc2UoZ2VudXM9PSJEdW5rbGVvc3RldXMiLCIqRHVua2xlb3N0ZXVzKiAoZXN0LikqIixoaWdoZXJfZ3JvdXApKQ0KDQojIHN1bW1hcmlzaW5nIHZhbHVlcyBmb3Igbm9uLUR1bmtsZW9zdGV1cyB0YXhhICh0b3RhbCBsZW5ndGgpDQoNCnAyX3BlbHZfYV8yPC1iaW5kX3Jvd3MocDJfcGVsdl9hXzEgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihnZW51cyA9PSAiRHVua2xlb3N0ZXVzIikgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRyb3BfbmEocHJlcGVsdmljX2xlbmd0aCx0b3RhbF9sZW5ndGgpLA0KICAgICAgICAgICAgICAgICAgICAgICBwMl9wZWx2X2FfMSAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKGdlbnVzIT0iRHVua2xlb3N0ZXVzInxpcy5uYShoaWdoZXJfZ3JvdXApKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBfYnkodGF4b24pICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkcm9wX25hKHByZXBlbHZpY19sZW5ndGgsdG90YWxfbGVuZ3RoKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3VtbWFyaXplKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSxtZWFuKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhpZ2hlcl9ncm91cD11bmlxdWUoaGlnaGVyX2dyb3VwKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRheG9uPXVuaXF1ZSh0YXhvbiksZ2VudXM9dW5pcXVlKGdlbnVzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNwZWNpZXM9dW5pcXVlKHNwZWNpZXMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2xhZGU9dW5pcXVlKGNsYWRlLG5hLnJtPUYpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hhcGU9dW5pcXVlKHNoYXBlKSkpICU+JQ0KbXV0YXRlKGhpZ2hlcl9ncm91cD1mYWN0b3IoaGlnaGVyX2dyb3VwLG9yZGVyZWQgPSBULCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIipEdW5rbGVvc3RldXMqIChlc3QuKSoiLCJBcnRocm9kaXJhIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk90aGVyIEVsYXNtb2JyYW5jaGlpIiwiKkFsb3BpYXMqIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkRlZXAgU2VhIFNxdWFsaWZvcm1lcyIsIkhvbG9jZXBoYWxpIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNhcmNvcHRlcnlnaWkiLCAiQmFzYWwgQWN0aW5vcHRlcnlnaWkiLCAiSWNodGh5b2RlY3RpZm9ybWVzIiwgIkJhc2FsIFRlbGVvc3RlaSIsICJPdG9jZXBoYWxhIiwgIlN0ZW0gRXV0ZWxlb3N0ZWkiLCAiQXVsb3BpZm9ybWVzLCBHYWRpZm9ybWVzIiwgIkJlbG9uaWZvcm1lcyIsICJPdGhlciBBY2FudGhvcHRlcnlnaWkiKSkpDQoNCnAyX3BlbHZfYTwtcDJfcGVsdl9hXzIlPiUNCiAgZ2dwbG90KGFlcyh4PXByZXBlbHZpY19sZW5ndGgvdG90YWxfbGVuZ3RoLHk9aGlnaGVyX2dyb3VwLGZpbGw9Y2xhZGUpKSArDQogIGxhYnMoeD0iUHJlLVBlbHZpYyBMZW5ndGggKGFzIHBlcmNlbnQgb2YgdG90YWwgbGVuZ3RoKSIseT0iQ2xhZGUiKSsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCkgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAxKSArDQogIGdlb21fdmxpbmUoZGF0YT0uJT4lZmlsdGVyKCEob3JkZXIgJWluJSBjKCJBdWxvcGlmb3JtZXMiLCJHYWRpZm9ybWVzIiwiQmVsb25pZm9ybWVzIil8DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW51cyAlaW4lIGMoIkR1bmtsZW9zdGV1cyIpfA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGlnaGVyX2dyb3VwPT0iT3RoZXIgQWNhbnRob3B0ZXJ5Z2lpIikpLA0KICAgICAgICAgICAgIGFlcyh4aW50ZXJjZXB0PW1lYW4ocHJlcGVsdmljX2xlbmd0aC90b3RhbF9sZW5ndGgpKSxsaW5ldHlwZT0iZGFzaGVkIikrDQogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQpKw0KICBzY2FsZV95X2Rpc2NyZXRlKGxpbWl0cz1yZXYpKw0KICBnZW9tX3Zpb2xpbihzY2FsZT0id2lkdGgiLHNob3cubGVnZW5kPUYpKw0KICBnZW9tX3Zpb2xpbihkYXRhPS4gJT4lIGZpbHRlcihnZW51cz09IkR1bmtsZW9zdGV1cyIpLA0KICAgICAgICAgICAgICBzY2FsZT0id2lkdGgiLGZpbGw9IiMwMEIwRjYiLHNob3cubGVnZW5kPUYpKw0KICBnZW9tX2JveHBsb3Qod2lkdGg9MC4zLGZpbGw9IndoaXRlIikrDQogIGdlb21fdGV4dChkYXRhPS4gJT4lDQogICAgICAgICAgICAgIHN1bW1hcmlzZSguYnk9dGF4b24scHJlcGVsdmljX2xlbmd0aD1tZWFuKHByZXBlbHZpY19sZW5ndGgpLGhpZ2hlcl9ncm91cD11bmlxdWUoaGlnaGVyX2dyb3VwKSwNCiAgICAgICAgICAgICAgICAgICAgICAgIGNsYWRlPXVuaXF1ZShjbGFkZSkpJT4lDQogICAgICAgICAgICAgIHN1bW1hcmlzZSguYnk9aGlnaGVyX2dyb3VwLE49bigpLGNsYWRlPXVuaXF1ZShjbGFkZSkpLA0KICAgICAgICAgICAgYWVzKHk9aGlnaGVyX2dyb3VwLGxhYmVsPU4pLHg9Ljk5LGhqdXN0PTEsc2l6ZT0zLjI1KSsNCiAgdGhlbWUoYXhpcy50aXRsZS55PWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X21hcmtkb3duKCkpDQoNCnBlY19wZWx2X2ZpZ3VyZTwtd3JhcF9wbG90cyhwMV9wZWNfYSAvIHAyX3BlY19hICsNCiAgICAgICAgICAgICB0aGVtZShheGlzLnRpdGxlLnk9ZWxlbWVudF9ibGFuaygpKSsNCiAgICAgICAgICAgICBnZW9tX3RleHQoZGF0YT0uICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgIHN1bW1hcmlzZSguYnk9dGF4b24scHBsPW1lYW4ocHJlcGVjdG9yYWxfbGVuZ3RoKSxoaWdoZXJfZ3JvdXA9dW5pcXVlKGhpZ2hlcl9ncm91cCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNsYWRlPXVuaXF1ZShjbGFkZSkpJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgc3VtbWFyaXNlKC5ieT1oaWdoZXJfZ3JvdXAsTj1uKCksY2xhZGU9dW5pcXVlKGNsYWRlKSksDQogICAgICAgICAgICAgICAgICAgICAgIGFlcyh5PWhpZ2hlcl9ncm91cCxsYWJlbD1OKSx4PS45OSxoanVzdD0xLHNpemU9My4yNSkrDQogICAgICAgICAgICAgcGxvdF9sYXlvdXQoaGVpZ2h0cyA9IDE6MikgJiB0aGVtZShwbG90Lm1hcmdpbiA9IG1hcmdpbigwLCAyMCwgMCwgMCkpLA0KICAgICAgICAgICAocDFfcGVsdl9hIC8gcDJfcGVsdl9hICsgDQogICAgICAgICAgICAgIHBsb3RfbGF5b3V0KGhlaWdodHMgPSAxOjIpICYgdGhlbWUocGxvdC5tYXJnaW4gPSBtYXJnaW4oMCwgMjAsIDAsIDApKSksbmNvbD0xKQ0KDQpnZ3NhdmUoZmlsZW5hbWU9IlJlY29uc3RydWN0aW9uIG9mIER1bmtsZW9zdGV1cyBGaWd1cmUgMTEgKFBlY3RvcmFsLVBlbHZpYyBQcm9wb3J0aW9ucykudGlmZiIsDQogICAgICAgcGxvdD1wZWNfcGVsdl9maWd1cmUsZGV2aWNlPSJ0aWZmIiwNCiAgICAgICB3aWR0aD0xNzUsaGVpZ2h0PTIyMCx1bml0cz0ibW0iLGRwaT02MDAsY29tcHJlc3Npb249Imx6dyIpDQpgYGANCg0KIyMgQ2F1ZGFsIFBlZHVuY2xlDQoNCiMjIyBQZWR1bmNsZSBoZWlnaHQgaW4gKkFtYXppY2h0aHlzKg0KDQoocmVmOmFtYXppY2h0aHlzcGVkdW5jbGUpIENhdWRhbCBwZWR1bmNsZSBoZWlnaHQgaW4gQW1hemljaHRoeXMgdHJpbmFqc3RpY2FlIGNvbXBhcmVkIHRvIHNlbGVjdCB0YWNoeW5la3RvbmljIGZpc2ggZ3JvdXBzLCBtZWFzdXJlZCBhcyBhIHByb3BvcnRpb24gb2YgYm9keSBkZXB0aCAobGVmdCkgYW5kIHByZWNhdWRhbCBsZW5ndGggKHJpZ2h0KS4gQ2F1ZGFsIHBlZHVuY2xlIGhlaWdodCBpbiBBbWF6aWNodGh5cyBtZWFzdXJlZCBmcm9tIHBob3RvZ3JhcGhzIG9mIHNwZWNpbWVuIEFBLk1FTS5EUy44IGluIEpvYmJpbnMgZXQgYWwuIDIwMjIuDQoNCmBgYHtyLGZpZy5jYXA9IihyZWY6YW1hemljaHRoeXNwZWR1bmNsZSkiLGZpZy53aWR0aD0xMSx3YXJuaW5nPUZ9DQpncmlkLmFycmFuZ2UobnJvdz0xLA0KICBkYXRhX3JlY29uJT4lDQogIGZpbHRlcihmYW1pbHkgJWluJSBjKCJTY29tYnJpZGFlIiwiTGFtbmlkYWUiLCJNZWdhbG9waWRhZSIsIlNwaHlyYWVuaWRhZSIpfG9yZGVyICVpbiUgYygiQ2FyYW5naWZvcm1lcyIsIklzdGlvcGhvcmlmb3JtZXMiKXxnZW51cz09IkFtYXppY2h0aHlzIikgJT4lDQogIGZpbHRlcighZ2VudXMgJWluJSBjKCJNaXRzdWt1cmluYSIsIkNhcmNoYXJoaWFzIiwiT2RvbnRhc3BpcyIpKSAlPiUNCiAgZHJvcF9uYShwZWR1bmNsZV9oZWlnaHQsYm9keV9kZXB0aCkgJT4lDQogIG11dGF0ZShvcmRlcj1jYXNlX3doZW4oZ2VudXM9PSJBbWF6aWNodGh5cyIgfiAiQW1hemljaHRoeXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgIG9yZGVyID09ICJMYW1uaWZvcm1lcyIgfiAiTGFtbmlkYWUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgIG9yZGVyID09ICJTY29tYnJpZm9ybWVzIiB+ICJTY29tYnJpZGFlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICBmYW1pbHkgPT0gIk1lZ2Fsb3BpZGFlIiB+ICJNZWdhbG9waWRhZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgb3JkZXIgPT0gIkNhcmFuZ2FyaWEgaW5jZXJ0YWUgc2VkaXMiIH4gIlNwaHlyYWVuaWRhZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgb3JkZXIgPT0gIklzdGlvcGhvcmlmb3JtZXMiIH4gIklzdGlvcGhvcmlmb3JtZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgIGZhbWlseSAlaW4lIGMoIkNhcmFuZ2lkYWUiLCJDb3J5cGhhZW5pZGFlIikgfiAiQ2FyYW5naWRhZSArIENvcnlwaGFlbmlkYWUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgIGZhbWlseSAlaW4lIGMoIlJhY2h5Y2VudHJpZGFlIiwiRWNoZW5laWRhZSIpIH4gIkVjaGVuZWlkYWUgKyBSYWNoeWNlbnRyaWRhZSIpKSAlPiUNCiAgZ2dwbG90KGFlcyh4PXBlZHVuY2xlX2hlaWdodC9ib2R5X2RlcHRoLHk9b3JkZXIpKSsNCiAgICBnZ3RpdGxlKCJBcyBwZXJjZW50YWdlIG9mIGJvZHkgZGVwdGgiKSsNCiAgc2NhbGVfeV9kaXNjcmV0ZShsaW1pdHM9cmV2KSArDQogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQpICsNCiAgZ2VvbV92bGluZShkYXRhPS4gJT4lIGZpbHRlcihnZW51cz09IkFtYXppY2h0aHlzIiksDQogICAgICAgICAgICAgYWVzKHhpbnRlcmNlcHQ9cGVkdW5jbGVfaGVpZ2h0L2JvZHlfZGVwdGgpLA0KICAgICAgICAgICAgIGNvbG9yPSJkYXJrZ3JleSIpICsNCiAgbGFicyh5PWVsZW1lbnRfYmxhbmsoKSx4PSJQZWR1bmNsZSBIZWlnaHQgYXMgJSBvZiBCb2R5IERlcHRoIikgKw0KICBnZW9tX3Zpb2xpbihkYXRhID0uICU+JSBmaWx0ZXIoZ2VudXMhPSJBbWF6aWNodGh5cyIpLCBhZXMoZmlsbD1vcmRlciksc2NhbGU9IndpZHRoIikrDQogIGdlb21fYm94cGxvdChkYXRhID0gLiAlPiUgZmlsdGVyKGdlbnVzIT0iQW1hemljaHRoeXMiKSwgd2lkdGg9MC4zKSsNCiAgZ2VvbV9zdGFyKGRhdGEgPSAuICU+JSBmaWx0ZXIoZ2VudXM9PSJBbWF6aWNodGh5cyIpLGZpbGw9ImJsYWNrIixzaXplPTMpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJOQSIsDQogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KGZhY2U9YyhyZXAoInBsYWluIiw3KSwiaXRhbGljIikpKSwNCmRhdGFfcmVjb24lPiUNCiAgZmlsdGVyKGZhbWlseSAlaW4lIGMoIlNjb21icmlkYWUiLCJMYW1uaWRhZSIsIk1lZ2Fsb3BpZGFlIiwiU3BoeXJhZW5pZGFlIil8b3JkZXIgJWluJSBjKCJDYXJhbmdpZm9ybWVzIiwiSXN0aW9waG9yaWZvcm1lcyIpfGdlbnVzPT0iQW1hemljaHRoeXMiKSAlPiUNCiAgZmlsdGVyKCFnZW51cyAlaW4lIGMoIk1pdHN1a3VyaW5hIiwiQ2FyY2hhcmhpYXMiLCJPZG9udGFzcGlzIikpICU+JQ0KICBkcm9wX25hKHBlZHVuY2xlX2hlaWdodCxwcmVjYXVkYWxfbGVuZ3RoKSAlPiUNCiAgbXV0YXRlKG9yZGVyPWNhc2Vfd2hlbihnZW51cz09IkFtYXppY2h0aHlzIiB+ICJBbWF6aWNodGh5cyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgb3JkZXIgPT0gIkxhbW5pZm9ybWVzIiB+ICJMYW1uaWRhZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgb3JkZXIgPT0gIlNjb21icmlmb3JtZXMiIH4gIlNjb21icmlkYWUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgIG9yZGVyID09ICJFbG9waWZvcm1lcyIgfiAiTWVnYWxvcGlkYWUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgIG9yZGVyID09ICJDYXJhbmdhcmlhIGluY2VydGFlIHNlZGlzIiB+ICJTcGh5cmFlbmlkYWUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgIG9yZGVyID09ICJJc3Rpb3Bob3JpZm9ybWVzIiB+ICJJc3Rpb3Bob3JpZm9ybWVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICBmYW1pbHkgJWluJSBjKCJDYXJhbmdpZGFlIiwiQ29yeXBoYWVuaWRhZSIpIH4gIkNhcmFuZ2lkYWUgKyBDb3J5cGhhZW5pZGFlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICBmYW1pbHkgJWluJSBjKCJSYWNoeWNlbnRyaWRhZSIsIkVjaGVuZWlkYWUiKSB+ICJFY2hlbmVpZGFlICsgUmFjaHljZW50cmlkYWUiKSkgJT4lDQogIGdncGxvdChhZXMoeD1wZWR1bmNsZV9oZWlnaHQvcHJlY2F1ZGFsX2xlbmd0aCx5PW9yZGVyKSkrDQogIGdndGl0bGUoIkFzIHBlcmNlbnRhZ2Ugb2YgcHJlY2F1ZGFsIGxlbmd0aCIpKw0KICBzY2FsZV95X2Rpc2NyZXRlKGxpbWl0cz1yZXYpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudCkgKw0KICBnZW9tX3ZsaW5lKGRhdGE9LiAlPiUgZmlsdGVyKGdlbnVzPT0iQW1hemljaHRoeXMiKSwNCiAgICAgICAgICAgICBhZXMoeGludGVyY2VwdD1wZWR1bmNsZV9oZWlnaHQvcHJlY2F1ZGFsX2xlbmd0aCksDQogICAgICAgICAgICAgY29sb3I9ImRhcmtncmV5IikgKw0KICBsYWJzKHk9ZWxlbWVudF9ibGFuaygpLHg9IlBlZHVuY2xlIEhlaWdodCBhcyAlIG9mIFByZWNhdWRhbCBMZW5ndGgiKSArDQogIGdlb21fdmlvbGluKGRhdGEgPS4gJT4lIGZpbHRlcihnZW51cyE9IkFtYXppY2h0aHlzIiksIGFlcyhmaWxsPW9yZGVyKSxzY2FsZT0id2lkdGgiKSsNCiAgZ2VvbV9ib3hwbG90KGRhdGEgPSAuICU+JSBmaWx0ZXIoZ2VudXMhPSJBbWF6aWNodGh5cyIpLCB3aWR0aD0wLjMpKw0KICBnZW9tX3N0YXIoZGF0YSA9IC4gJT4lIGZpbHRlcihnZW51cz09IkFtYXppY2h0aHlzIiksZmlsbD0iYmxhY2siLHNpemU9MykgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb249Ik5BIiwNCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoZmFjZT1jKHJlcCgicGxhaW4iLDcpLCJpdGFsaWMiKSkpDQopDQpgYGANCg0KSXQgaXMgcG9zc2libGUgdGhlIHBlZHVuY2xlIGFzIHByZXNlcnZlZCBpbiAqQW1hemljaHRoeXMqIGlzIHRvbyBkZWVwIGFuZCBoYXMgYmVlbiBhbHRlcmVkIGJ5IHRhcGhvbm9taWMgZGVmb3JtYXRpb24uIFRoZSByZWNvbnN0cnVjdGlvbiBpbiBFbmdlbG1hbiAoMjAyMykgcHJvdmlkZXMgYW4gYWx0ZXJuYXRpdmUgbWVhc3VyZW1lbnQgb2YgcGVkdW5jbGUgaGVpZ2h0IGluIHRoaXMgdGF4b24sIGJlY2F1c2UgdGhlIHBlZHVuY2xlIHdhcyByZWNvbnN0cnVjdGVkIHRvIGJlIHNsaWdodGx5IG5hcnJvd2VyIHRoYW4gcHJlc2VydmVkIGFzc3VtaW5nIHNvbWUgdGFwaG9ub21pYyBkZWZvcm1hdGlvbi4gVGhpcyByZWNvbnN0cnVjdGlvbiB3YXMgbWFkZSBkaXJlY3RseSBmcm9tIHRoZSBwcm9wb3J0aW9ucyBvZiB0aGUgaG9sb3R5cGUgd2l0aCBvdmVyc2lnaHQgZnJvbSB0aGUgbGVhZCBhdXRob3Igb2YgdGhlIHBhcGVyIGRlc2NyaWJpbmcgKkFtYXppY2h0aHlzKiAoTS4gSm9iYmlucyBwZXJzLiBjb21tLiwgU2VwdGVtYmVyIDIwMjIpLCBzbyBpdHMgcHJvcG9ydGlvbnMgYXJlIHJlbGF0aXZlbHkgcmVsaWFibGUuDQoNCihyZWY6YW1hemljaHRoeXNwZWR1bmNsZTIpIENhdWRhbCBwZWR1bmNsZSBoZWlnaHQgaW4gQW1hemljaHRoeXMgdHJpbmFqc3RpY2FlIHVzaW5nIHRoZSBwZWR1bmNsZSBoZWlnaHQgaW4gdGhlIHJlY29uc3RydWN0aW9uIG9mIEVuZ2VsbWFuICgyMDIzKS4NCg0KYGBge3IsZmlnLmNhcD0iKHJlZjphbWF6aWNodGh5c3BlZHVuY2xlMikiLGZpZy53aWR0aD0xMSx3YXJuaW5nPUZ9DQpncmlkLmFycmFuZ2UobnJvdz0xLA0KICBkYXRhX3JlY29uJT4lDQogIGZpbHRlcihmYW1pbHkgJWluJSBjKCJTY29tYnJpZGFlIiwiTGFtbmlkYWUiLCJNZWdhbG9waWRhZSIsIlNwaHlyYWVuaWRhZSIpfG9yZGVyICVpbiUgYygiQ2FyYW5naWZvcm1lcyIsIklzdGlvcGhvcmlmb3JtZXMiKXxnZW51cz09IkFtYXppY2h0aHlzIikgJT4lDQogICAgbXV0YXRlKHBlZHVuY2xlX2hlaWdodD1pZmVsc2UoZ2VudXM9PSJBbWF6aWNodGh5cyIsNi42NzkscGVkdW5jbGVfaGVpZ2h0KSkgJT4lDQogIGZpbHRlcighZ2VudXMgJWluJSBjKCJNaXRzdWt1cmluYSIsIkNhcmNoYXJoaWFzIiwiT2RvbnRhc3BpcyIpKSAlPiUNCiAgZHJvcF9uYShwZWR1bmNsZV9oZWlnaHQsYm9keV9kZXB0aCkgJT4lDQogIG11dGF0ZShvcmRlcj1jYXNlX3doZW4oZ2VudXM9PSJBbWF6aWNodGh5cyIgfiAiQW1hemljaHRoeXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgIG9yZGVyID09ICJMYW1uaWZvcm1lcyIgfiAiTGFtbmlkYWUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgIG9yZGVyID09ICJTY29tYnJpZm9ybWVzIiB+ICJTY29tYnJpZGFlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICBmYW1pbHkgPT0gIk1lZ2Fsb3BpZGFlIiB+ICJNZWdhbG9waWRhZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgb3JkZXIgPT0gIkNhcmFuZ2FyaWEgaW5jZXJ0YWUgc2VkaXMiIH4gIlNwaHlyYWVuaWRhZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgb3JkZXIgPT0gIklzdGlvcGhvcmlmb3JtZXMiIH4gIklzdGlvcGhvcmlmb3JtZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgIGZhbWlseSAlaW4lIGMoIkNhcmFuZ2lkYWUiLCJDb3J5cGhhZW5pZGFlIikgfiAiQ2FyYW5naWRhZSArIENvcnlwaGFlbmlkYWUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgIGZhbWlseSAlaW4lIGMoIlJhY2h5Y2VudHJpZGFlIiwiRWNoZW5laWRhZSIpIH4gIkVjaGVuZWlkYWUgKyBSYWNoeWNlbnRyaWRhZSIpKSAlPiUNCiAgZ2dwbG90KGFlcyh4PXBlZHVuY2xlX2hlaWdodC9ib2R5X2RlcHRoLHk9b3JkZXIpKSsNCiAgICBnZ3RpdGxlKCJBcyBwZXJjZW50YWdlIG9mIGJvZHkgZGVwdGgiKSsNCiAgc2NhbGVfeV9kaXNjcmV0ZShsaW1pdHM9cmV2KSArDQogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQpICsNCiAgZ2VvbV92bGluZShkYXRhPS4gJT4lIGZpbHRlcihnZW51cz09IkFtYXppY2h0aHlzIiksDQogICAgICAgICAgICAgYWVzKHhpbnRlcmNlcHQ9cGVkdW5jbGVfaGVpZ2h0L2JvZHlfZGVwdGgpLA0KICAgICAgICAgICAgIGNvbG9yPSJkYXJrZ3JleSIpICsNCiAgbGFicyh5PWVsZW1lbnRfYmxhbmsoKSx4PSJQZWR1bmNsZSBIZWlnaHQgYXMgJSBvZiBCb2R5IERlcHRoIikgKw0KICBnZW9tX3Zpb2xpbihkYXRhID0uICU+JSBmaWx0ZXIoZ2VudXMhPSJBbWF6aWNodGh5cyIpLCBhZXMoZmlsbD1vcmRlciksc2NhbGU9IndpZHRoIikrDQogIGdlb21fYm94cGxvdChkYXRhID0gLiAlPiUgZmlsdGVyKGdlbnVzIT0iQW1hemljaHRoeXMiKSwgd2lkdGg9MC4zKSsNCiAgZ2VvbV9zdGFyKGRhdGEgPSAuICU+JSBmaWx0ZXIoZ2VudXM9PSJBbWF6aWNodGh5cyIpLGZpbGw9ImJsYWNrIixzaXplPTMpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJOQSIsDQogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KGZhY2U9YyhyZXAoInBsYWluIiw3KSwiaXRhbGljIikpKSwNCmRhdGFfcmVjb24lPiUNCiAgZmlsdGVyKGZhbWlseSAlaW4lIGMoIlNjb21icmlkYWUiLCJMYW1uaWRhZSIsIk1lZ2Fsb3BpZGFlIiwiU3BoeXJhZW5pZGFlIil8b3JkZXIgJWluJSBjKCJDYXJhbmdpZm9ybWVzIiwiSXN0aW9waG9yaWZvcm1lcyIpfGdlbnVzPT0iQW1hemljaHRoeXMiKSAlPiUNCiAgbXV0YXRlKHBlZHVuY2xlX2hlaWdodD1pZmVsc2UoZ2VudXM9PSJBbWF6aWNodGh5cyIsNi42NzkscGVkdW5jbGVfaGVpZ2h0KSkgJT4lDQogIGZpbHRlcighZ2VudXMgJWluJSBjKCJNaXRzdWt1cmluYSIsIkNhcmNoYXJoaWFzIiwiT2RvbnRhc3BpcyIpKSAlPiUNCiAgZHJvcF9uYShwZWR1bmNsZV9oZWlnaHQscHJlY2F1ZGFsX2xlbmd0aCkgJT4lDQogIG11dGF0ZShvcmRlcj1jYXNlX3doZW4oZ2VudXM9PSJBbWF6aWNodGh5cyIgfiAiQW1hemljaHRoeXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgIG9yZGVyID09ICJMYW1uaWZvcm1lcyIgfiAiTGFtbmlkYWUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgIG9yZGVyID09ICJTY29tYnJpZm9ybWVzIiB+ICJTY29tYnJpZGFlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICBvcmRlciA9PSAiRWxvcGlmb3JtZXMiIH4gIk1lZ2Fsb3BpZGFlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICBvcmRlciA9PSAiQ2FyYW5nYXJpYSBpbmNlcnRhZSBzZWRpcyIgfiAiU3BoeXJhZW5pZGFlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICBvcmRlciA9PSAiSXN0aW9waG9yaWZvcm1lcyIgfiAiSXN0aW9waG9yaWZvcm1lcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgZmFtaWx5ICVpbiUgYygiQ2FyYW5naWRhZSIsIkNvcnlwaGFlbmlkYWUiKSB+ICJDYXJhbmdpZGFlICsgQ29yeXBoYWVuaWRhZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgZmFtaWx5ICVpbiUgYygiUmFjaHljZW50cmlkYWUiLCJFY2hlbmVpZGFlIikgfiAiRWNoZW5laWRhZSArIFJhY2h5Y2VudHJpZGFlIikpICU+JQ0KICBnZ3Bsb3QoYWVzKHg9cGVkdW5jbGVfaGVpZ2h0L3ByZWNhdWRhbF9sZW5ndGgseT1vcmRlcikpKw0KICBnZ3RpdGxlKCJBcyBwZXJjZW50YWdlIG9mIHByZWNhdWRhbCBsZW5ndGgiKSsNCiAgc2NhbGVfeV9kaXNjcmV0ZShsaW1pdHM9cmV2KSArDQogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQpICsNCiAgZ2VvbV92bGluZShkYXRhPS4gJT4lIGZpbHRlcihnZW51cz09IkFtYXppY2h0aHlzIiksDQogICAgICAgICAgICAgYWVzKHhpbnRlcmNlcHQ9cGVkdW5jbGVfaGVpZ2h0L3ByZWNhdWRhbF9sZW5ndGgpLA0KICAgICAgICAgICAgIGNvbG9yPSJkYXJrZ3JleSIpICsNCiAgbGFicyh5PWVsZW1lbnRfYmxhbmsoKSx4PSJQZWR1bmNsZSBIZWlnaHQgYXMgJSBvZiBQcmVjYXVkYWwgTGVuZ3RoIikgKw0KICBnZW9tX3Zpb2xpbihkYXRhID0uICU+JSBmaWx0ZXIoZ2VudXMhPSJBbWF6aWNodGh5cyIpLCBhZXMoZmlsbD1vcmRlciksc2NhbGU9IndpZHRoIikrDQogIGdlb21fYm94cGxvdChkYXRhID0gLiAlPiUgZmlsdGVyKGdlbnVzIT0iQW1hemljaHRoeXMiKSwgd2lkdGg9MC4zKSsNCiAgZ2VvbV9zdGFyKGRhdGEgPSAuICU+JSBmaWx0ZXIoZ2VudXM9PSJBbWF6aWNodGh5cyIpLGZpbGw9ImJsYWNrIixzaXplPTMpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJOQSIsDQogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KGZhY2U9YyhyZXAoInBsYWluIiw3KSwiaXRhbGljIikpKQ0KKQ0KYGBgDQoNCkhvd2V2ZXIsIHRoaXMgaGFzIGxpdHRsZSBlZmZlY3Qgb24gaG93IHVudXN1YWxseSBkZWVwIHRoZSBwZWR1bmNsZSBvZiAqQW1hemljaHRoeXMgdHJpbmFqc3RpY2FlKiBpcyByZWxhdGl2ZSB0byBlaXRoZXIgcHJlY2F1ZGFsIGxlbmd0aCBvciBib2R5IGRlcHRoLiBJdCBpcyBhbG1vc3QgaW1wb3NzaWJsZSBmb3IgKkFtYXppY2h0aHlzKiB0byBoYXZlIGEgbmFycm93IGxhbW5pZC9zY29tYnJpZC9pc3Rpb3Bob3JpZm9ybS1saWtlIHBlZHVuY2xlLCBiZWNhdXNlIHRoaXMgd291bGQgcmVxdWlyZSB0aGUgcGVkdW5jbGUgdG8gbmVhcmx5IGRvdWJsZSBpbiBoZWlnaHQgKGdvIGZyb20gfjggY20gdG8gfjMuNSBjbSkgZHVlIHRvIGRlY2F5LCBjcnVzaGluZywgYW5kIHRhcGhvbm9taWMgZGlzdG9ydGlvbiwgc29tZXRoaW5nIHRoYXQgd291bGQgYmUgdmVyeSBkaWZmaWN1bHQgdG8gYWNoaWV2ZSBpZiB0aGUgcGVkdW5jbGUgd2VyZSBvcmlnaW5hbGx5IG5hcnJvdy4gVGhpcyBpcyBldmVuIG1vcmUgc28gZ2l2ZW4gYm90aCBBQS5NRU0uRFMuOCBhbmQgUElNVVogQS9JIDQ3NzMgc2VlbSB0byBzaG93IHJlbGF0aXZlbHkgZGVlcCBwZWR1bmNsZXMgKEpvYmJpbnMgZXQgYWwuIDIwMjI6IGZpZy4gMikuDQoNCiMjIyBFc3RpbWF0aW5nIHBlZHVuY2xlIGhlaWdodCBpbiAqRHVua2xlb3N0ZXVzKg0KDQojIyMjIEVzdGltYXRpbmcgcGVkdW5jbGUgaGVpZ2h0IHVzaW5nIHBlbGFnaWMgZmlzaGVzDQoNCmBgYHtyfQ0KcGVkdW5jbGVfaGVpZ2h0XzEgPC0gZGF0YV9yZWNvbiAlPiUNCiAgZmlsdGVyKGZhbWlseSAlaW4lIGMoIlNjb21icmlkYWUiLCJMYW1uaWRhZSIsIkNldG9yaGluaWRhZSIsIk1lZ2FjaGFzbWlkYWUiLCJNZWdhbG9waWRhZSIsIlNwaHlyYWVuaWRhZSIpfA0KICAgICAgICAgICBvcmRlciAlaW4lIGMoIkNhcmFuZ2lmb3JtZXMiLCJJc3Rpb3Bob3JpZm9ybWVzIil8DQogICAgICAgICAgIGdlbnVzPT0iQW1hemljaHRoeXMiKSAlJCUNCiAgbG0obG9nKHBlZHVuY2xlX2hlaWdodCl+bG9nKGJvZHlfZGVwdGgpKmxvZyhwcmVjYXVkYWxfbGVuZ3RoKSwuKQ0KDQpzdW1tYXJ5KHBlZHVuY2xlX2hlaWdodF8xKQ0KYGBgDQoNCmBgYHtyfQ0KZGF0YV9yZWNvbiAlPiUNCiAgZmlsdGVyKGdlbnVzICVpbiUgYygiRHVua2xlb3N0ZXVzIiwiQ29jY29zdGV1cyIsIkluY2lzb3NjdXR1bSIsIkFtYXppY2h0aHlzIikpICU+JQ0KICBmaWx0ZXIoIWlzLm5hKHBlZHVuY2xlX2hlaWdodCl8Z2VudXM9PSJEdW5rbGVvc3RldXMiKSAlPiUNCiAgYXJyYW5nZShnZW51cyklPiUNCiAgZHJvcF9uYShwcmVjYXVkYWxfbGVuZ3RoLGJvZHlfZGVwdGgpICU+JQ0KICBhdWdtZW50KHBlZHVuY2xlX2hlaWdodF8xLA0KICAgICAgICAgIG5ld2RhdGE9LiwNCiAgICAgICAgICBpbnRlcnZhbD0icHJlZGljdCIpICU+JQ0KICBtdXRhdGUoYWNyb3NzKC5maXR0ZWQ6LnVwcGVyLH5leHAoLikqcmVncmVzc2lvbi5zdGF0cyhwZWR1bmNsZV9oZWlnaHRfMSkkQ0YpLA0KICAgICAgICAgdGF4b249c3RyX3JlcGxhY2UodGF4b24sIl8iLCIgIikpICU+JQ0KICBzZWxlY3QodGF4b24sc3BlY2ltZW4sYm9keV9kZXB0aCxwcmVjYXVkYWxfbGVuZ3RoLHBlZHVuY2xlX2hlaWdodCwuZml0dGVkLC5sb3dlciwudXBwZXIpJT4lDQogIGthYmxlKGRpZ2l0cz1jKDEsMSwxLDEsMiwyLDIsMiksDQogICAgICAgIGFsaWduPWMoImwiLCJjIiwiYyIsImMiLCJjIiwiYyIsImMiLCJjIiksDQogICAgICAgIGNvbC5uYW1lcz1jKCJUYXhvbiIsIlNwZWNpbWVuIiwiQm9keSBEZXB0aCIsIlByZWNhdWRhbCBMZW5ndGgiLA0KICAgICAgICAgICAgICAgICAgICAiQWN0dWFsIFBlZHVuY2xlIERlcHRoIiwNCiAgICAgICAgICAgICAgICAgICAgIkZpdHRlZCIsIkxvd2VyIiwiVXBwZXIiKSwNCiAgICAgICAgY2FwdGlvbj0iUHJlZGljdGluZyB0aGUgaGVpZ2h0IG9mIHRoZSBjYXVkYWwgcGVkdW5jbGUgaW4gPGk+RHVua2xlb3N0ZXVzPC9pPiB1c2luZyBhIG1vZGVsIGNvbnRhaW5pbmcgb25seSBsYXJnZS1ib2RpZWQsIHBlbGFnaWMgZmlzaGVzLiBBbGwgbWVhc3VyZW1lbnRzIGluICBjbS4iKSAlPiUNCiAgY29sdW1uX3NwZWMoMSxpdGFsaWM9VCkgJT4lDQogIGthYmxlX3N0eWxpbmcoKQ0KYGBgDQoNCkVzdGltYXRpbmcgdGhlIHBlZHVuY2xlIGhlaWdodCB1c2luZyBvbmx5IGxhcmdlLWJvZGllZCBwZWxhZ2ljIGZpc2hlcyBwcm9kdWNlcyBhIHJlbGF0aXZlbHkgbmFycm93IHBlZHVuY2xlLiBIb3dldmVyLCB0aGlzIGVzdGltYXRlIHBvdGVudGlhbGx5IHVzZXMgY2lyY3VsYXIgbG9naWMgdG8gZXN0aW1hdGUgdGhlIHBlZHVuY2xlIGhlaWdodCBvZiAqRHVua2xlb3N0ZXVzKiBieSBhc3N1bWluZyB0aGlzIHRheG9uIGlzIHBlbGFnaWMsIGFzIHdlbGwgYXMgaW5zZW5zaXRpdmUgdG8gY2xhZGUtc3BlY2lmaWMgZGlmZmVyZW5jZXMgaW4gcGVkdW5jbGUgaGVpZ2h0IGJldHdlZW4gYXJ0aHJvZGlyZXMgYW5kIG90aGVyIGZpc2hlcyAoYXMgc2VlbiBpbiBpdCB1bmRlcmVzdGltYXRpbmcgcGVkdW5jbGUgaGVpZ2h0IGluIGFsbCBhcnRocm9kaXJlcyB3aGVyZSBwZWR1bmNsZSBoZWlnaHQgY2FuIGJlIGFwcHJveGltYXRlZCkuIFRoZXJlZm9yZSwgYSBicm9hZGVyIGFwcHJvYWNoIHVzaW5nIGRhdGEgZnJvbSBhIHdpZGVyIHZhcmlldHkgb2YgZmlzaGVzIHdhcyB1c2VkLg0KDQojIyMjIEVzdGltYXRpbmcgcGVkdW5jbGUgaGVpZ2h0IHVzaW5nIGFsbCBmaXNoZXMNCg0KVGhpcyBtb2RlbCBzZWVrcyB0byBlc3RpbWF0ZSB0aGUgY2F1ZGFsIHBlZHVuY2xlIGRlcHRoIG9mICpEdW5rbGVvc3RldXMgdGVycmVsbGkqIHVzaW5nIGFsbCBmaXNoZXMsIG5vdCBqdXN0IHBlbGFnaWMgb25lcy4NCg0KYGBge3J9DQpwZWR1bmNsZV9oZWlnaHRfMiA8LSBkYXRhX3JlY29uICU+JQ0KICBkcm9wX25hKHBlZHVuY2xlX2hlaWdodCxib2R5X2RlcHRoLHByZWNhdWRhbF9sZW5ndGgpICUkJQ0KICBsbShsb2cocGVkdW5jbGVfaGVpZ2h0KX5sb2coYm9keV9kZXB0aCkqbG9nKHByZWNhdWRhbF9sZW5ndGgpLC4pDQoNCnN1bW1hcnkocGVkdW5jbGVfaGVpZ2h0XzIpDQpgYGANCg0KQmFzZWQgb24gdGhpcywgY2F1ZGFsIHBlZHVuY2xlIGhlaWdodCBpbiBmaXNoZXMgaGFzIGEgc2lnbmlmaWNhbnQgY29ycmVsYXRpb24gd2l0aCB0cnVuayBoZWlnaHQgKGBib2R5X2RlcHRoYCksIHByZWNhdWRhbCBsZW5ndGgsIGFzIHdlbGwgYXMgZmluZW5lc3MgcmF0aW8gKHRoZSBpbnRlcmFjdGlvbiBiZXR3ZWVuIGBib2R5X2RlcHRoYCBhbmQgYHByZWNhdWRhbF9sZW5ndGhgKS4NCg0KYGBge3J9DQpkYXRhX3JlY29uICU+JQ0KICBmaWx0ZXIoZ2VudXMgJWluJSBjKCJBbWF6aWNodGh5cyIsIkR1bmtsZW9zdGV1cyIsIkNvY2Nvc3RldXMiLCJJbmNpc29zY3V0dW0iKSkgJT4lDQogIGZpbHRlcighaXMubmEocGVkdW5jbGVfaGVpZ2h0KXxnZW51cz09IkR1bmtsZW9zdGV1cyIpICU+JQ0KICBhcnJhbmdlKGdlbnVzKSU+JQ0KICBkcm9wX25hKHByZWNhdWRhbF9sZW5ndGgsYm9keV9kZXB0aCkgJT4lDQogIGF1Z21lbnQocGVkdW5jbGVfaGVpZ2h0XzIsDQogICAgICAgICAgbmV3ZGF0YT0uLA0KICAgICAgICAgIGludGVydmFsPSJwcmVkaWN0IikgJT4lDQogIG11dGF0ZShhY3Jvc3MoLmZpdHRlZDoudXBwZXIsfmV4cCguKSpyZWdyZXNzaW9uLnN0YXRzKHBlZHVuY2xlX2hlaWdodF8yKSRDRiksDQogICAgICAgICB0YXhvbj1zdHJfcmVwbGFjZSh0YXhvbiwiXyIsIiAiKSkgJT4lDQogIHNlbGVjdCh0YXhvbixzcGVjaW1lbixib2R5X2RlcHRoLHByZWNhdWRhbF9sZW5ndGgscGVkdW5jbGVfaGVpZ2h0LC5maXR0ZWQsLmxvd2VyLC51cHBlciklPiUNCiAga2FibGUoZGlnaXRzPWMoMSwxLDEsMSwyLDIsMiwyKSwNCiAgICAgICAgYWxpZ249YygibCIsImMiLCJjIiwiYyIsImMiLCJjIiwiYyIsImMiKSwNCiAgICAgICAgY29sLm5hbWVzPWMoIlRheG9uIiwiU3BlY2ltZW4iLCJCb2R5IERlcHRoIiwiUHJlY2F1ZGFsIExlbmd0aCIsDQogICAgICAgICAgICAgICAgICAgICJBY3R1YWwgUGVkdW5jbGUgRGVwdGgiLA0KICAgICAgICAgICAgICAgICAgICAiRml0dGVkIiwiTG93ZXIiLCJVcHBlciIpLA0KICAgICAgICBjYXB0aW9uPSJQcmVkaWN0aW5nIHRoZSBoZWlnaHQgb2YgdGhlIGNhdWRhbCBwZWR1bmNsZSBpbiA8aT5EdW5rbGVvc3RldXM8L2k+IHVzaW5nIGEgbW9kZWwgY29udGFpbmluZyBhbGwgZmlzaGVzIGFuZCBubyBsaWZlIGhhYml0cyBkYXRhLiBBbGwgbWVhc3VyZW1lbnRzIGluIGNtLiIpICU+JQ0KICBjb2x1bW5fc3BlYygxLGl0YWxpYz1UKSAlPiUNCiAga2FibGVfc3R5bGluZygpDQpgYGANCg0KYGBge3J9DQpwZWR1bmNsZV9oZWlnaHRfMyA8LSBkYXRhX3JlY29uICU+JQ0KICBkcm9wX25hKHBlZHVuY2xlX2hlaWdodCxib2R5X2RlcHRoLHByZWNhdWRhbF9sZW5ndGgpICUkJQ0KICBsbShsb2cocGVkdW5jbGVfaGVpZ2h0KX5sb2coYm9keV9kZXB0aCkqbG9nKHByZWNhdWRhbF9sZW5ndGgpK2hhYml0YXQsLikNCg0Kc3VtbWFyeShwZWR1bmNsZV9oZWlnaHRfMykNCmBgYA0KDQpBZGRpbmcgaW4gbGlmZSBoYWJpdHMgYXMgYW4gYWRkaXRpb25hbCBleHBsYW5hdG9yeSB2YXJpYWJsZSBzZWVtcyB0byBoYXZlIGEgc2lnbmlmaWNhbnQgY29ycmVsYXRpdmUgZWZmZWN0Lg0KDQpgYGB7cn0NCmRhdGFfcmVjb24gJT4lDQogIGZpbHRlcihnZW51cyAlaW4lIGMoIkR1bmtsZW9zdGV1cyIsIkNvY2Nvc3RldXMiLCJJbmNpc29zY3V0dW0iLCJBbWF6aWNodGh5cyIpKSAlPiUNCiAgZmlsdGVyKCFpcy5uYShwZWR1bmNsZV9oZWlnaHQpfGdlbnVzPT0iRHVua2xlb3N0ZXVzIikgJT4lDQogIGFycmFuZ2UoZ2VudXMpJT4lDQogIGRyb3BfbmEocHJlY2F1ZGFsX2xlbmd0aCxib2R5X2RlcHRoKSAlPiUNCiAgYXVnbWVudChwZWR1bmNsZV9oZWlnaHRfMywNCiAgICAgICAgICBuZXdkYXRhPS4sDQogICAgICAgICAgaW50ZXJ2YWw9InByZWRpY3QiKSAlPiUNCiAgbXV0YXRlKGFjcm9zcyguZml0dGVkOi51cHBlcix+ZXhwKC4pKnJlZ3Jlc3Npb24uc3RhdHMocGVkdW5jbGVfaGVpZ2h0XzMpJENGKSwNCiAgICAgICAgIHRheG9uPXN0cl9yZXBsYWNlKHRheG9uLCJfIiwiICIpKSAlPiUNCiAgc2VsZWN0KHRheG9uLHNwZWNpbWVuLGJvZHlfZGVwdGgscHJlY2F1ZGFsX2xlbmd0aCxwZWR1bmNsZV9oZWlnaHQsLmZpdHRlZCwubG93ZXIsLnVwcGVyKSU+JQ0KICBrYWJsZShkaWdpdHM9YygxLDEsMSwxLDIsMiwyLDIpLA0KICAgICAgICBhbGlnbj1jKCJsIiwiYyIsImMiLCJjIiwiYyIsImMiLCJjIiwiYyIpLA0KICAgICAgICBjb2wubmFtZXM9YygiVGF4b24iLCJTcGVjaW1lbiIsIkJvZHkgRGVwdGgiLCJQcmVjYXVkYWwgTGVuZ3RoIiwNCiAgICAgICAgICAgICAgICAgICAgIkFjdHVhbCBQZWR1bmNsZSBEZXB0aCIsDQogICAgICAgICAgICAgICAgICAgICJGaXR0ZWQiLCJMb3dlciIsIlVwcGVyIiksDQogICAgICAgIGNhcHRpb249IlByZWRpY3RpbmcgdGhlIGhlaWdodCBvZiB0aGUgY2F1ZGFsIHBlZHVuY2xlIGluIDxpPkR1bmtsZW9zdGV1czwvaT4gdXNpbmcgYSBtb2RlbCBjb250YWluaW5nIGFsbCBmaXNoZXMgYW5kIGFsbG93aW5nIGNvdmFyaWFuY2Ugd2l0aCBsaWZlIGhhYml0cy4gQWxsIG1lYXN1cmVtZW50cyBpbiAgY20uIikgJT4lDQogIGNvbHVtbl9zcGVjKDEsaXRhbGljPVQpICU+JQ0KICBrYWJsZV9zdHlsaW5nKCkNCmBgYA0KDQpIb3dldmVyLCB1c2luZyB0aGlzIGVxdWF0aW9uIHRvIGVzdGltYXRlIHBlZHVuY2xlIGhlaWdodCBpbiAqRHVua2xlb3N0ZXVzKiBoYXMgbGl0dGxlIGVmZmVjdCBvbiBjYXVkYWwgcGVkdW5jbGUgaGVpZ2h0IHByZWRpY3Rpb25zLg0KDQpgYGB7cn0NCnJiaW5kKA0KICAiTGFyZ2UtYm9kaWVkIHBlbGFnaWMgZmlzaGVzIG9ubHkiPXJlZ3Jlc3Npb24uc3RhdHMocGVkdW5jbGVfaGVpZ2h0XzEpLA0KICAiQWxsIGZpc2hlcywgbm8gaGFiaXRhdCI9cmVncmVzc2lvbi5zdGF0cyhwZWR1bmNsZV9oZWlnaHRfMiksDQogICJBbGwgZmlzaGVzLCB3aXRoIGhhYml0YXQiPXJlZ3Jlc3Npb24uc3RhdHMocGVkdW5jbGVfaGVpZ2h0XzMpDQopDQpgYGANCg0KRXJyb3IgcmF0ZXMgaW4gdGhlc2UgbW9kZWxzIGFyZSBva2F5LCBidXQgbm90IHBhcnRpY3VsYXJseSBncmVhdC4NCg0KVGhlIHByZWRpY3RlZCBjYXVkYWwgcGVkdW5jbGUgaGVpZ2h0IG9mICpDb2Njb3N0ZXVzKiBhbmQgKkluY2lzb3NjdXR1bSogaXMgcmVsYXRpdmVseSBjbG9zZSB0byB0aGUgYWN0dWFsIHZhbHVlcy4gSG93ZXZlciB0aGUgY2F1ZGFsIHBlZHVuY2xlIG9mICpBbWF6aWNodGh5cyogaXMgc2lnbmlmaWNhbnRseSBkZWVwZXIgdGhhbiBleHBlY3RlZCBiYXNlZCBvbiB0aGVzZSBtb2RlbHMuIFNvbWUgb2YgdGhpcyBpcyBiZWNhdXNlIHdoaWxlIHBlZHVuY2xlIGhlaWdodCBpcyBjb3JyZWxhdGVkIHdpdGggcHJlY2F1ZGFsIGxlbmd0aCwgYm9keSBkZXB0aCwgYW5kIGxpZmUgaGFiaXRzIGluIGZpc2hlcywgdGhlcmUgYXJlIG90aGVyLCBjbGFkZS1zcGVjaWZpYyBkaWZmZXJlbmNlcyB0aGF0IGluZmx1ZW5jZSBjYXVkYWwgcGVkdW5jbGUgaGVpZ2h0IGFzIHdlbGwuIEZvciBleGFtcGxlLCBhbGwgY2FyYW5naWRzIGhhdmUgdmVyeSBuYXJyb3cgcGVkdW5jbGVzLCByZWdhcmRsZXNzIG9mIHdoZXRoZXIgdGhleSBhcmUgcGVsYWdpYyB0YXhhIG9yIG9jY3VweSBjb2FzdGFsIG9yIG1vcmUgcmVlZmFsIGVudmlyb25tZW50cy4gU2ltaWxhcmx5LCBkZXNwaXRlIGJlaW5nIGNsb3NlbHkgcmVsYXRlZCBhbmQgaGF2aW5nIHNpbWlsYXIgaGFiaXRzLCByYWNoeWNlbnRyaWRzIGhhdmUgbXVjaCBkZWVwZXIgcGVkdW5jbGVzIHRoYW4gY2FyYW5naWRzLiBVbmZvcnR1bmF0ZWx5LCB0aGVyZSBhcmUgdG9vIGZldyBhcnRocm9kaXJlcyBmb3Igd2hpY2ggdGhlIGNhdWRhbCBwZWR1bmNsZSBoZWlnaHQgY2FuIGJlIGFwcHJveGltYXRlZCB0byBpbmNsdWRlIHRheG9ub21pYyBncm91cCBhcyBhIHZhcmlhYmxlIGluIHRoZXNlIG1vZGVscyB0byBleHBlY3QgdGhpcyB0byBpbXByb3ZlIG1vZGVsIHByZWRpY3Rpb24uIFRoZXJlIGlzIGFsc28gYSBjb25jZXJuIHRoYXQgdGhlc2UgbW9kZWxzIG1pZ2h0IGJlIGJpYXNlZCB0b3dhcmRzIHRhY2h5bmVrdG9uaWMgcGVsYWdpYyBmaXNoZXMgKGFuZCB0aHVzIG5hcnJvd2VyIHBlZHVuY2xlcykgYXQgbGFyZ2VyIHNpemVzLCBzaW1wbHkgYmVjYXVzZSBtb3N0IGxhcmdlLWJvZGllZCBleHRhbnQgZmlzaGVzIGFyZSB0YWNoeW5la3RvbmljLiBUaGVzZSB1bmNlcnRhaW50aWVzIGFyZSB3aHkgdGhlIG1ldGhvZHMgdXNlZCBoZXJlIHdlcmUgbm90IGFwcGxpZWQgdG8gdGhlIHJlY29uc3RydWN0aW9uIG9mICpEdW5rbGVvc3RldXMgdGVycmVsbGkqLg0KDQpUaGUgcGVkdW5jbGUgaGVpZ2h0IHVzZWQgZm9yIHRoZSBwcmVzZW50IHJlY29uc3RydWN0aW9uIG9mICpEdW5rbGVvc3RldXMgdGVycmVsbGkqICh+IDIyIGNtIGluIENNTkggNTc2OCkgaXMgd2l0aGluIHRoZSByYW5nZSBvZiB2YXJpYXRpb24gYWxsb3dlZCBieSB0aGVzZSBtb2RlbHMuIEl0IHdhcyBjYWxjdWxhdGVkIGFzc3VtaW5nIHNoYXBlIGNoYW5nZSBkdWUgdG8gcGVsYWdpYyBoYWJpdHMgcmVzdWx0IGluIGEgc2ltaWxhciBkaXNwYXJpdHkgaW4gcmVsYXRpdmUgcGVkdW5jbGUgZGVwdGggYmV0d2VlbiB0aGlzIHRheG9uIGFuZCBkZW1lcnNhbCBhcnRocm9kaXJlcyAoKkNvY2Nvc3RldXMqLCAqSW5jaXNvc2N1dHVtKikgYXMgZXhpc3RzIGJldHdlZW4gYW5hbG9nb3VzIHBlbGFnaWMgYW5kIGRlbWVyc2FsIHNoYXJrcy4gVGhpcyBpcyBhIGNvYXJzZSBhcHByb3hpbWF0aW9uLCBhbmQgaXMgYWNrbm93bGVkZ2VkIGFzIHN1Y2guIEluIHNwaXRlIG9mIHRoaXMsIHRoZSBtb2RlbCBwcmVzZW50ZWQgaW4gdGhpcyBzZWN0aW9uIHN1Z2dlc3RzIHRoaXMgZXN0aW1hdGUgbWF5IGJlIG92ZXJseSBjb25zZXJ2YXRpdmUgYW5kIHRoZSBwZWR1bmNsZSBtYXkgYWN0dWFsbHkgYmUgKnRvbyBkZWVwKiwgcHJlZGljdGluZyBhIHBlZHVuY2xlIGhlaWdodCBvZiB+MTUgY20uICpJZiogdGhlIHByZXNlbnQgbW9kZWwgaXMgYWNjdXJhdGUsIGl0cyBwcmVkaWN0aW9uIHdvdWxkIHN1Z2dlc3QgdGhlIHBvdGVudGlhbCB0aHVubmlmb3JtIHNoYXBlIHN1Z2dlc3RlZCBlbHNld2hlcmUgaW4gdGhpcyBwYXBlciBtYXkgYmUgY29ycmVjdC4gSG93ZXZlciwgdGhpcyBpcyBzYWlkIHdpdGggdGhlIGNhdmVhdCB0aGF0IHRoZSBtb2RlbCBpcyBpbnNlbnNpdGl2ZSB0byB0aGUgcG9zc2liaWxpdHkgdGhhdCBhcnRocm9kaXJlcyBoYXZlIHByb3BvcnRpb25hbGx5IGRlZXBlciBwZWR1bmNsZXMgdGhhbiBvdGhlciBmaXNoZXMsIGFuZCBhY2NvdW50aW5nIGZvciB0aGlzIG1heSByZXN1bHQgaW4gYSBzbGlnaHRseSBkZWVwZXIgcGVkdW5jbGUuDQoNCiMgT3RoZXIgRGF0YQ0KDQojIyBWZXJ0ZWJyYWwgQ291bnQgYW5kIFNpemUgaW4gKkR1bmtsZW9zdGV1cyoNCg0KQW5vdGhlciBmZWF0dXJlIHN1cHBvcnRpbmcgYSBzbWFsbGVyIHNpemUgZm9yICpEdW5rbGVvc3RldXMqIGlzIHRoZSByZWxhdGl2ZSBzaXplIG9mIHRoZSB2ZXJ0ZWJyYWwgY29sdW1uLiBOZXVyYWwgYXJjaGVzIGZyb20gdGhlIGFudGVyaW9yIGF4aWFsIHNrZWxldG9uIGFyZSBrbm93biBpbiAqRC4gdGVycmVsbGkqIChDTU5IIDUwMzIyKSwgYnV0IHRoZXNlIGVsZW1lbnRzIGFyZSBzbWFsbCByZWxhdGl2ZSB0byB0aGUgc2l6ZSBvZiB0aGUgc2t1bGwgYW5kIHRob3JhY2ljIHNoaWVsZCAoSm9oYW5zb24gZXQgYWwuIDIwMTk6IGZpZy4gMS4yKS4gVGhpcyB3b3VsZCByZXN1bHQgaW4gYW4gdW51c3VhbGx5IHNtYWxsIHZlcnRlYnJhbCBjb2x1bW4gd2l0aCBhIHNsZW5kZXIgbm90b2Nob3JkIGlmIGFzc3VtaW5nIGEgc2hhcmstbGlrZSBib2R5IHBsYW4gYXMgaW4gdHJhZGl0aW9uYWwgcmVjb25zdHJ1Y3Rpb25zLCB3aGljaCBzZWVtcyB1bmxpa2VseSBmb3IgYW4gYWN0aXZlbHkgc3dpbW1pbmcgbmVrdG9uaWMgb3JnYW5pc20uIEhvd2V2ZXIsIHRoZSBzaXplIG9mIHRoZSB2ZXJ0ZWJyYWUgbWFrZSBjb25zaWRlcmFibHkgbW9yZSBzZW5zZSBmb3IgYSBncm91cGVyIG9yIHR1bmEtbGlrZSBib2R5IHBsYW4gd2l0aCBhIHdpZGVyIGFuZCBkZWVwZXIgaGVhZCBhbmQgdHJ1bmsgcmVsYXRpdmUgdG8gdG90YWwgbGVuZ3RoLg0KDQpFeHRyYXBvbGF0aW5nIHRoZSBzaXplIG9mIHRoZSBuZXVyYWwgYXJjaGVzIGluIENNTkggNTAzMjIgdG8gdG90YWwgbGVuZ3RoLCBhbmQgY29uc2lkZXJpbmcgdGhhdCB2ZXJ0ZWJyYWwgZWxlbWVudHMgaW4gYXJ0aHJvZGlyZXMgdGVuZCB0byBiZSBuYXJyb3dlciBpbiB0aGUgcG9zdGVyaW9yIChjYXVkYWwgYW5kIHBvc3QtYW5hbCkgcmVnaW9ucyBvZiB0aGUgYXhpYWwgc2tlbGV0b24gKE1pbGVzIGFuZCBXZXN0b2xsIDE5NjgpLCByZXN1bHRzIGluIGFuIGVzdGltYXRlZCBwb3N0LXRob3JhY2ljIG5ldXJhbCBhcmNoIGNvdW50IG9mIDEwNCBlbGVtZW50cyAoRmlndXJlIDE0IGluIG1haW4gdGV4dCleMV4uIFRoaXMgaXMgY29tcGFyYWJsZSB0byBwb3N0LXRob3JhY2ljIHZlcnRlYnJhbCBjb3VudHMgaW4gKkNvY2Nvc3RldXMgY3VzcGlkYXR1cyogKDc14oCTMTA3LCBNaWxlcyBhbmQgV2VzdG9sbCAxOTY4OiB0YWIuIEkpDQoNCkFudGVyaW9yIHRvIHRoZSBwb3N0ZXJpb3IgbWFyZ2luIG9mIHRoZSB0aG9yYWNpYyBzaGllbGQsIHRoZSBuZXVyYWwgYXJjaGVzIGFyZSBwYXJ0aWFsbHkgaW5jb3Jwb3JhdGVkIGludG8gdGhlIHN5bmFyY3VhbCBieSBmdXNpb24gKEpvaGFuc29uIGV0IGFsLiAyMDE5KS4gMTYgcGFydGlhbGx5IGZ1c2VkIG5ldXJhbCBhcmNoZXMgYXJlIHByZXNlcnZlZCBpbiBDTU5IIDUwMzIyLCB0aG91Z2ggbW9yZSBtYXkgaGF2ZSBiZWVuIHByZXNlbnQgYW50ZXJpb3JseSBhbmQgbm90IHByZXNlcnZlZC4gVGhpcyBpcyBub3QgY291bnRpbmcgdGhlICJ0cnVlIiBzeW5hcmN1YWwsIHdoaWNoIGlzIGNvbXBvc2VkIG9mIH4xNCBmdWxseSBmdXNlZCwgdW5kaWZmZXJlbnRpYXRlZCB2ZXJ0ZWJyYWwgZWxlbWVudHMgYmFzZWQgb24gdGhlIG51bWJlciBvZiB2aXNpYmxlIHNwaW5hbCBuZXJ2ZSBmb3JhbWluYSAoSm9oYW5zb24gZXQgYWwuIDIwMTMpLiBUaGlzIHdvdWxkIHJlc3VsdCBpbiBhIHRvdGFsIGNvdW50IG9mIH4xMjQgdmVydGVicmFlIGluICpEdW5rbGVvc3RldXMgdGVycmVsbGkqLg0KDQpUaGlzIHZlcnRlYnJhbCBjb3VudCBpcyB3aXRoaW4gdGhlIHJhbmdlIG9mIHZhcmlhdGlvbiBmb3Igc2hhcmtzLCB0aG91Z2ggc2xpZ2h0bHkgYmVsb3cgYXZlcmFnZSAoU3ByaW5nZXIgYW5kIEdhcnJpY2ssIDE5NjQpLiBJdCBpcyBjb21wYXJhYmxlIHRvIHRheGEgbGlrZSAqU3F1YWx1cyogKDk2LTExOCksICpDZXRvcmhpbnVzKiAoMTEwKSwgKk1pdHN1a3VyaW5hKiAoMTIyKSBhbmQgKlNxdWF0aW5hKiAoMTIxLTE0MSksIHRob3VnaCBsb3dlciB0aGFuIHR5cGljYWwgdmVydGVicmFsIGNvdW50cyBmb3IgICpDYXJjaGFyaWFzKiAoMTU2LTE3MCksIExhbW5pZGFlICgxNTAtMTk3KSBhbmQgQ2FyY2hhcmhpbmlkYWUgKDExMC0yNTIpIChpYmlkKS4gVGhpcyBtYXkgYmUgYmVjYXVzZSBzaGFya3MgaGF2ZSBhIHNpZ25pZmljYW50IG51bWJlciBvZiB2ZXJ0ZWJyYWUgYW50ZXJpb3IgdG8gdGhlIHBlY3RvcmFsIGdpcmRsZSBhYm92ZSB0aGUgYnJhbmNoaWFsIGNoYW1iZXIsIHdoZXJlYXMgaW4gYXJ0aHJvZGlyZXMgdGhlc2UgdmVydGVicmFlIGFyZSBhYnNlbnQgZHVlIHRvIHRoZSBwb3N0ZXJpb3IgZXh0ZW5zaW9uIG9mIHRoZSBuZXVyb2NyYW5pdW0gYW5kIHNrdWxsIChDYXJyIGV0IGFsLiAyMDA5KS4gRm9yIGV4YW1wbGUgKkxhbW5hIG5hc3VzKiwgYSBmYWlybHkgc2hvcnQtYm9kaWVkIHNoYXJrLCB0aGVyZSBhcmUgMTggdmVydGVicmFlIGluIHRoaXMgcmVnaW9uIChaTUEuUElTQy4xMTYxNjU7IEthbW1pbmdhIGV0IGFsLiAyMDE3KQ0KDQpUaGVzZSB2ZXJ0ZWJyYWwgYWNjb3VudHMgYXJlIGFwcHJveGltYXRlLCBidXQgc2hvdyB0aGUgbnVtYmVyIG9mIHZlcnRlYnJhZSByZXF1aXJlZCBmb3IgdGhlIHNob3J0ZXIsIHN0b2NraWVyICpEdW5rbGVvc3RldXMqIGRlcGljdGVkIGhlcmUgYmV0dGVyIGFncmVlIHdpdGggdmVydGVicmFsIGNvdW50cyBpbiBvdGhlciBhcnRocm9kaXJlcyBhbmQgc2hhcmtzLg0KDQpeMV4gLSBOZXVyYWwgYXJjaCBjb3VudCBpcyB1c2VkIGdpdmVuIHRoZSBoYWVtYWwgYXJjaGVzIGF0IHRoZSBiYXNlIG9mIHRoZSBjYXVkYWwgZmluIGluIGFydGhyb2RpcmVzIG1heSBiZSBmdXNpb25zIG9mIHR3byB2ZXJ0ZWJyYWwgZWxlbWVudHMgKE1pbGVzIGFuZCBXZXN0b2xsIDE5Njg6IHAuIDQ0OSkuDQoNCiMjIFNjYWxpbmcgUGVsdmljIEdpcmRsZSBTaXplIGluICpFYXN0bWFub3N0ZXVzIGNhbGxpYXNwaXMqDQoNCkRlbm5pcy1CcnlhbnQgKDE5ODcpIHJlcG9ydGVkIGEgcGFydGlhbCBwZWx2aWMgZ2lyZGxlIGZvciB0aGUgc3BlY2ltZW4gTkhNVUsgUFYgUDUwODc3IChzZWUgYWxzbyBUcmluYWpzdGljIGV0IGFsLiwgMjAxNSkuIFRoaXMgZ2lyZGxlIG1lYXN1cmVzIDYuMDQgY20gaW4gZ3JlYXRlc3QgaGVpZ2h0IChtZWFzdXJlZCBwYXJhbGxlbCB0byB0aGUgaWxpYWMgcHJvY2Vzcywgc2VlIERlbm5pcy1CcnlhbnQsIDE5ODc6IGZpZy4gMzBhLWIpLiBTcGVjaW1lbnMgb2YgKkR1bmtsZW9zdGV1cyB0ZXJyZWxsaSogd2VyZSBtZWFzdXJlZCB0aGUgc2FtZSB3YXksIG1ha2luZyB0aGVzZSBtZWFzdXJlbWVudHMgY29tcGFyYWJsZSBiZXR3ZWVuIHNwZWNpbWVucy4gTkhNVUsgUFYgUDUwODc3IGhhcyBhbiBPT0wgb2YgOC42NiBjbSAoRGVubmlzLUJyeWFudCAxOTg3OiBmaWcuIDExKSwgdGhvdWdoIHRoZSBhbmdsZSB0aGUgc3BlY2ltZW4gd2FzIHBob3RvZ3JhcGhlZCBhdCBpbnRyb2R1Y2VzIHNvbWUgdW5jZXJ0YWludHkuIFVzaW5nIHRoZSBPT0wgZXF1YXRpb24gb2YgRW5nZWxtYW4gMjAyMyAodGhlIG9uZSB1c2luZyBpbmRpdmlkdWFsIHNwZWNpbWVucywgYm9keSBzaGFwZSwgYW5kIGNvbnRyb2xsaW5nIGZvciB0aGUgZWZmZWN0cyBvZiBTZXJyYW5pZGFlLCBIb2xvY2VudHJpZGFlLCBhbmQgQ2hvbmRyaWNodGh5ZXMsIHNlZSBzZWN0aW9uIDEwLjcuMy4gaW4gdGhhdCBzdHVkeSdzIHN1cHBsZW1lbnRhcnkgaW5mb3JtYXRpb24pLCB0aGlzIHByb2R1Y2VzIGEgdG90YWwgbGVuZ3RoIG9mIDU2Ljg4IGNtLiBUaGlzIHJlc3VsdHMgaW4gYSBwZWx2aWMgZ2lyZGxlIHdpdGggYSBoZWlnaHQgMTAuNiUgZXN0aW1hdGVkIHRvdGFsIGxlbmd0aC4NCg0KQWx0ZXJuYXRpdmVseSwgdGhlIG51Y2hhbCBwbGF0ZSBvZiBOSE1VSyBQViBQNTA4NzcgaXMgODIuMSUgdGhlIGxlbmd0aCBvZiB0aGlzIHBsYXRlIGluIHRoZSBob2xvdHlwZSAoV0FNIDcwLjQuODY0OyBEZW5uaXMtQnJ5YW50IDE5ODc6IHRhYi4gMSkuIE51Y2hhbCBsZW5ndGggc2NhbGVzIGlzb21ldHJpY2FsbHkgaW4gb3RoZXIgYXJ0aHJvZGlyZXMgKFRyaW5hanN0aWMgYW5kIE1jTmFtYXJhIDE5OTkpLiBTY2FsaW5nIHRoZSBlc3RpbWF0ZWQgdG90YWwgbGVuZ3RoIG9mIHRoZSBob2xvdHlwZSByZXBvcnRlZCBpbiBFbmdlbG1hbiAoMjAyMzogNzkuMyBjbSkgdG8gdGhlIHNpemUgb2YgTkhNVUsgUFYgUDUwODc3IHByb2R1Y2VzIGFuIGVzdGltYXRlZCBsZW5ndGggb2YgNjUuMSBjbSBhbmQgYSByZWxhdGl2ZSBwZWx2aXMgaGVpZ2h0IG9mIDkuMyUgdG90YWwgbGVuZ3RoLg0KDQpSZWdhcmRsZXNzIG9mIGhvdyB0aGUgc2l6ZSBvZiB0aGUgcGVsdmlzIGluIE5ITVVLIFBWIFA1MDg3NyBpcyBlc3RpbWF0ZWQsIGl0IGlzIGF0IGxlYXN0IHR3aWNlIHRoZSByZWxhdGl2ZSBzaXplIG9mIHRoaXMgZWxlbWVudCBpbiAqRHVua2xlb3N0ZXVzIHRlcnJlbGxpKiwgYW5kIHByb2JhYmx5IGFyb3VuZCAyLjUgdGltZXMgdGhlIHNpemUgb2YgdGhlIHBlbHZpcyBpbiB0aGlzIHRheG9uLg0KDQpFdmVuIGlmIHRoZSBlc3RpbWF0ZWQgc2l6ZSBvZiB0aGUgcGVsdmlzIGluICpFYXN0bWFub3N0ZXVzKiBpcyBzbGlnaHQgb3ZlcmVzdGltYXRlZCwgdGhlIGhlaWdodCBvZiB0aGUgcGVsdmlzIG9mICpJbmNpc29zY3V0dW0qIGluIHRoZSByZWNvbnN0cnVjdGlvbiBvZiBUcmluYWpzdGljICgyMDEzKSBpcyA4LjUlIHRoZSB0b3RhbCBsZW5ndGggb2YgdGhlIGFuaW1hbC4gSW4gKkNvY2Nvc3RldXMqIHRoZSBwZWx2aXMgaXMgNy41JSB0b3RhbCBsZW5ndGggdXNpbmcgdGhlIHJlY29uc3RydWN0aW9uIGluIE1pbGVzIGFuZCBXZXN0b2xsICgxOTY4KTsgdGhpcyByZWNvbnN0cnVjdGlvbiB3YXMgdXNlZCBhcyB0b3RhbCBwZWx2aXMgaGVpZ2h0IHdhcyBub3QgbWVhc3VyYWJsZSBpbiBhbnkgb2YgdGhlIHByZXNlcnZlZCBzcGVjaW1lbnMgYXZhaWxhYmxlLiBUaGlzIHdvdWxkIHN1Z2dlc3QgdGhlIHBlbHZpcyBpbiBEdW5rbGVvc3RldXMgaXMgcHJvcG9ydGlvbmFsbHkgc21hbGxlciB0aGFuIHRoZXNlIG90aGVyIGFydGhyb2RpcmVzLCByb3VnaGx5IDE14oCTNDAlIHNtYWxsZXIgaW4gbGluZWFyIGRpbWVuc2lvbnMuIEluICpBbWF6aWNodGh5cyB0cmluYWpzdGljYWUqIHRoZSBwZWx2aXMgaXMgb25seSBhYm91dCA1JSB0b3RhbCBsZW5ndGggKEpvYmJpbnMgZXQgYWwuIDIwMjI6IGZpZy4gMmEtYiksIGNsb3NlciB0byBidXQgc2xpZ2h0bHkgc21hbGxlciB0aGFuIHRoZSByZWxhdGl2ZSBzaXplIHNlZW4gaW4gKkR1bmtsZW9zdGV1cyouDQoNCiMgUmVmZXJlbmNlcyB7I3JlZmVyZW5jZXN9DQoNCiMjIExpdGVyYXR1cmUgUmVmZXJlbmNlcw0KDQo8ZGl2IHN0eWxlPSJ0ZXh0LWluZGVudDogLTQwcHg7IHBhZGRpbmctbGVmdDogNDBweDsgbWFyZ2luLWJvdHRvbT0wOyBtYXJnaW4tdG9wPTAiPg0KDQpBaGxiZXJnLCBQLiwgVHJpbmFqc3RpYywgSy4sIEpvaGFuc29uLCBaLiwgTG9uZywgSi4gMjAwOS4gUGVsdmljIGNsYXNwZXJzIGNvbmZpcm0gY2hvbmRyaWNodGh5YW4tbGlrZSBpbnRlcm5hbCBmZXJ0aWxpemF0aW9uIGluIGFydGhyb2RpcmVzLiAqTmF0dXJlKiwgNDYwOjg4OC04ODkuIGh0dHBzOi8vZG9pLm9yZy8xMC4xMDM4L25hdHVyZTA4MTc2DQoNCkF1bHQsIEouUy4sIGFuZCBMdW8sIEouIDIwMTMuIEEgcmVsaWFibGUgZ2FtZSBmaXNoIHdlaWdodCBlc3RpbWF0aW9uIG1vZGVsIGZvciBBdGxhbnRpYyB0YXJwb24gKCpNZWdhbG9wcyBhdGxhbnRpY3VzKikuICpGaXNoZXJpZXMgUmVzZWFyY2gqLCAxMzk6MTEw4oCTMTE3LiBodHRwczovL2RvaS5vcmcvaHR0cHM6Ly9kb2kub3JnLzEwLjEwMTYvai5maXNocmVzLjIwMTIuMTAuMDA0DQoNCkNhcnIsIFIuSy4gMTk5NS4gUGxhY29kZXJtIGRpdmVyc2l0eSBhbmQgZXZvbHV0aW9uLiAqQnVsbGV0aW4gZHUgTXVzw6l1bSBOYXRpb25hbCBkJ0hpc3RvaXJlIE5hdHVyZWxsZSosIDQ6ODXigJMxMjUuIA0KDQpDYXJyLCBSLksuLCBKb2hhbnNvbiwgWi4sIGFuZCBSaXRjaGllLCBBLiAyMDA5LiBUaGUgcGh5bGxvbGVwaWQgcGxhY29kZXJtICpDb3dyYWxlcGlzIG1jbGFjaGxhbmkqOiBJbnNpZ2h0cyBpbnRvIHRoZSBldm9sdXRpb24gb2YgZmVlZGluZyBtZWNoYW5pc21zIGluIGphd2VkIHZlcnRlYnJhdGVzLiAqSm91cm5hbCBvZiBNb3JwaG9sb2d5KiwgMjcwOjc3NeKAkzgwNC4gaHR0cHM6Ly9kb2kub3JnLzEwLjEwMDIvam1vci4xMDcxOQ0KDQpDYXZpbiwgTC4sIEZvcmV5LCBQLkwuLCBhbmQgR2llcnNjaCwgUy4gMjAxMy4gT3N0ZW9sb2d5IG9mICpFdWJpb2RlY3RlcyBsaWJhbmljdXMqIChQaWN0ZXQgJiBIdW1iZXJ0LCAxODY2KSBhbmQgc29tZSBvdGhlciBpY2h0aHlvZGVjdGlmb3JtZXMgKFRlbGVvc3RlaSk6IHBoeWxvZ2VuZXRpYyBpbXBsaWNhdGlvbnMuICpKb3VybmFsIG9mIFN5c3RlbWF0aWMgUGFsYWVvbnRvbG9neSosIDExOjExNeKAkzE3Ny4NCmh0dHBzOi8vZG9pLm9yZy8xMC4xMDgwLzE0NzcyMDE5LjIwMTIuNjkxNTU5DQoNCkRlYW4sIEIuIDE4OTYuIE9uIHRoZSB2ZXJ0ZWJyYWwgY29sdW1uLCBmaW5zLCBhbmQgdmVudHJhbCBhcm1vcmluZyBvZiAqRGluaWNodGh5cyouICpQcm9jZWVkaW5ncyBvZiB0aGUgTmV3IFlvcmsgQWNhZGVteSBvZiBTY2llbmNlcyosIDE1OjE1Ny0xODguDQoNCkRlbm5pcy1CcnlhbiwgSy4gMTk4Ny4gQSBuZXcgc3BlY2llcyBvZiBlYXN0bWFub3N0ZWlkIGFydGhyb2RpcmUgKFBpc2NlczogUGxhY29kZXJtaSkgZnJvbSBHb2dvLCBXZXN0ZXJuIEF1c3RyYWxpYS4gKlpvb2xvZ2ljYWwgSm91cm5hbCBvZiB0aGUgTGlubmVhbiBTb2NpZXR5KiwgOTA6MeKAkzY0LiBodHRwczovL2RvaS5vcmcvMTAuMTExMS9qLjEwOTYtMzY0Mi4xOTg3LnRiMDEzNDcueA0KDQpEZW5uaXMsIEsuLCBhbmQgTWlsZXMsIFIuUy4gMTk3OS4gRXVicmFjaHl0aG9yYWNpZCBhcnRocm9kaXJlcyB3aXRoIHR1YnVsYXIgcm9zdHJhbCBwbGF0ZXMgZnJvbSBHb2dvLCBXZXN0ZXJuIEF1c3RyYWxpYS4gKlpvb2xvZ2ljYWwgSm91cm5hbCBvZiB0aGUgTGlubmVhbiBTb2NpZXR5KiwgNjc6Mjk34oCTMzI4LiBodHRwczovL2RvaS5vcmcvMTAuMTExMS9qLjEwOTYtMzY0Mi4xOTc5LnRiMDExMTgueA0KDQpFbmdlbG1hbiwgUi5LLiAyMDIzLiBBIERldm9uaWFuIGZpc2ggdGFsZTogQSBuZXcgbWV0aG9kIG9mIGJvZHkgbGVuZ3RoIGVzdGltYXRpb24gc3VnZ2VzdHMgbXVjaCBzbWFsbGVyIHNpemVzIGZvciAqRHVua2xlb3N0ZXVzIHRlcnJlbGxpKiAoUGxhY29kZXJtaTogQXJ0aHJvZGlyYSkuICpEaXZlcnNpdHkqLCAxNTozMTguIGh0dHBzOi8vZG9pLm9yZy8xMC4zMzkwL2QxNTAzMDMxOA0KDQpHbGVpc3MsIEEuQy4sIFBvdHZpbiwgSi4sIGFuZCBHb2xkYm9nZW4sIEouQS4gMjAxNy4gUGh5c2ljYWwgdHJhZGUtb2ZmcyBzaGFwZSB0aGUgZXZvbHV0aW9uIG9mIGJ1b3lhbmN5IGNvbnRyb2wgaW4gc2hhcmtzLiAqUHJvY2VlZGluZ3Mgb2YgdGhlIFJveWFsIFNvY2lldHkgQjogQmlvbG9naWNhbCBTY2llbmNlcyosIDI4NDoyMDE3MTM0NS4gaHR0cHM6Ly9kb2kub3JnLzEwLjEwOTgvcnNwYi4yMDE3LjEzNDUNCg0KSHViYnMsIEMuLCBMYWdsZXIsIEsuLCBhbmQgU21pdGgsIEcuIDIwMDQuIEZpc2hlcyBvZiB0aGUgR3JlYXQgTGFrZXMgUmVnaW9uLCBSZXZpc2VkIEVkaXRpb24sIFJldmlzZWQgZWRpdGlvbi4gVW5pdmVyc2l0eSBvZiBNaWNoaWdhbiBQcmVzcywgQW5uIEFyYm9yLmh0dHBzOi8vZG9pLm9yZy8xMC4zOTk4L21wdWIuMTc2NTgNCg0KSm9iYmlucywgTS4sIFLDvGNrbGluLCBNLiwgRmVycsOzbiwgSC5HLiwgYW5kIEtsdWcsIEMuIDIwMjIuIEEgbmV3IHNlbGVub3N0ZWlkIHBsYWNvZGVybSBmcm9tIHRoZSBMYXRlIERldm9uaWFuIG9mIHRoZSBlYXN0ZXJuIEFudGktQXRsYXMgKE1vcm9jY28pIHdpdGggcHJlc2VydmVkIGJvZHkgb3V0bGluZSBhbmQgaXRzIGVjb21vcnBob2xvZ3kuICpGcm9udGllcnMgaW4gRWNvbG9neSBhbmQgRXZvbHV0aW9uKiwgMTA6OTY5MTU4LiBodHRwczovL2RvaS5vcmcvMTAuMzM4OS9mZXZvLjIwMjIuOTY5MTU4DQoNCkpvaGFuc29uLCBaLiwgVHJpbmFqc3RpYywgSy4sIENhcnIsIFIuLCBhbmQgUml0Y2hpZSwgQS4gMjAxMy4gRXZvbHV0aW9uIGFuZCBkZXZlbG9wbWVudCBvZiB0aGUgc3luYXJjdWFsIGluIGVhcmx5IHZlcnRlYnJhdGVzLiAqWm9vbW9ycGhvbG9neSosIDEzMjo5NeKAkzExMC4gaHR0cHM6Ly9kb2kub3JnLzEwLjEwMDcvczAwNDM1LTAxMi0wMTY5LTkNCg0KSm9oYW5zb24sIFouLCBUcmluYWpzdGljLCBLLiwgQ3VtYmFhLCBTLiwgYW5kIFJ5YW4sIE0uSi4gMjAxOS4gRnVzaW9uIGluIHRoZSB2ZXJ0ZWJyYWwgY29sdW1uIG9mIHRoZSBwYWNoeW9zdGVvbW9ycGggYXJ0aHJvZGlyZSAqRHVua2xlb3N0ZXVzIHRlcnJlbGxpKiAo4oCYUGxhY29kZXJtaeKAmSkuICpQYWxhZW9udG9sb2dpYSBFbGVjdHJvbmljYSosIDIyLjIuMjBBOjHigJMxMy4gaHR0cHM6Ly9kb2kub3JnLzEwLjI2ODc5Lzg3Mg0KDQpLYW1taW5nYSwgUC4sIERlIEJydWluLCBQLlcuLCBHZWxlaWpucywgSi4sIGFuZCBCcmF6ZWF1LCBNLkQuIDIwMTcuIFgtcmF5IGNvbXB1dGVkIHRvbW9ncmFwaHkgbGlicmFyeSBvZiBzaGFyayBhbmF0b215IGFuZCBsb3dlciBqYXcgc3VyZmFjZSBtb2RlbHMuICpTY2llbnRpZmljIERhdGEqLCA0OjE3MDA0Ny4gaHR0cHM6Ly9kb2kub3JnLzEwLjEwMzgvc2RhdGEuMjAxNy40Nw0KDQpLb2dhbiwgSS4sIFMuIFBhY2hvbGFrLCBNLiBMaWNodCwgSi4gVy4gU2NobmVpZGVyLCBDLiBCcnVja2VyLCBhbmQgUy4gQnJhbmR0LiAyMDE1LiBUaGUgaW52aXNpYmxlIGZpc2g6IGh5ZHJvZHluYW1pYyBjb25zdHJhaW50cyBmb3IgcHJlZGF0b3ItcHJleSBpbnRlcmFjdGlvbiBpbiBmb3NzaWwgZmlzaCAqU2F1cmljaHRoeXMqIGNvbXBhcmVkIHRvIHJlY2VudCBhY3Rpbm9wdGVyeWdpYW5zLiAqQmlvbG9neSBPcGVuKiA0OjE3MTUtMTcyNi4gaHR0cHM6Ly9kb2kub3JnLzEwLjEyNDIvYmlvLjAxNDcyMA0KDQpMdW5kLCBSLiwgYW5kIEx1bmQsIFcuIDE5ODQuIE5ldyBnZW5lcmEgYW5kIHNwZWNpZXMgb2YgY29lbGFjYW50aHMgZnJvbSB0aGUgQmVhciBHdWxjaCBsaW1lc3RvbmUgKGxvd2VyIENhcmJvbmlmZXJvdXMpIG9mIE1vbnRhbmEsIFUuUy5BLiAqR2VvYmlvcyogMTc6MjM3LTI0NC4gaHR0cHM6Ly9kb2kub3JnLzEwLjEwMTYvUzAwMTYtNjk5NSg4NCk4MDE0NS1YDQoNCk1pbGVzLCBSLlMuIDE5NjkuIEZlYXR1cmVzIG9mIFBsYWNvZGVybSBEaXZlcnNpZmljYXRpb24gYW5kIHRoZSBFdm9sdXRpb24gb2YgdGhlIEFydGhyb2RpcmUgRmVlZGluZyBNZWNoYW5pc20uIFRyYW5zYWN0aW9ucyBvZiB0aGUgUm95YWwgU29jaWV0eSBvZiBFZGluYnVyZ2gsIDY4OjEyM+KAkzE3MC4gaHR0cHM6Ly9kb2kub3JnLzEwLjEwMTcvUzAwODA0NTY4MDAwMTQ2MjkNCg0KTWlsZXMsIFIuUy4sIFdlc3RvbGwsIFQuUy4gMTk2OC4gVGhlIFBsYWNvZGVybSBGaXNoICpDb2Njb3N0ZXVzIGN1c3BpZGF0dXMqIE1pbGxlciBleCBBZ2Fzc2l6IGZyb20gdGhlIE1pZGRsZSBPbGQgUmVkIFNhbmRzdG9uZSBvZiBTY290bGFuZC4gUGFydCBJLiBEZXNjcmlwdGl2ZSBNb3JwaG9sb2d5LiAqVHJhbnNhY3Rpb25zIG9mIHRoZSBSb3lhbCBTb2NpZXR5IG9mIEVkaW5idXJnaCosIDY3OjM3My00NzYuIGh0dHBzOi8vZG9pLm9yZy8xMC4xMDE3L1MwMDgwNDU2ODAwMDI0MDc4DQoNCk1pbGxvdCwgSi4sIEFudGhvbnksIEouLCBhbmQgUm9iaW5lYXUgLEQuIDE5NzguIEFuYXRvbWllIGRlICpMYXRpbWVyaWEgQ2hhbHVtbmFlKiwgVG9tZSBJSUk6IEFwcGFyZWlsIERpZ2VzdGlmLCBBcHBhcmVpbCBSZXNwaXJhdG9pcmUsIEFwcGFyZWlsIFVyb2dlbml0YWwgR2xhbmRlcyBFbmRvY3JpbmVzLCBBcHBhcmVpbCBDaXJjdWxhdG9pcmUgVMOpZ3VtZW50cywgRWNhaWxsZXMsIENvbmNsdXNpb25zIEfDqW7DqXJhbGUuIENOUlMsIFBhcmlzLg0KDQpSYW5kYWxsLCBKLkUuIDE5OTcuIFJhbmRhbGwncyB0YW5rIHBob3Rvcy4gQ29sbGVjdGlvbiBvZiAxMCwwMDAgbGFyZ2UtZm9ybWF0IHBob3RvcyAoc2xpZGVzKSBvZiBkZWFkIGZpc2hlcy4gQWNjZXNzZWQgSnVuZSAyOSwgMjAyMi4gd3d3LmZpc2hiYXNlLm9yZyAoc2VlIHNwZWNpZXMgcGFnZXMgZm9yIG1vcmUgZGV0YWlscykNCg0KU2FydXdhdGFyaSwgVC4sIEl3YXRhLCBNLiwgWWFidW1vdG8sIFkuLCBIdWtvbSwgRi5ELiwgUGVyaXN0aXdhZHksIFQuLCBhbmQgQWJlLCBZLiAyMDE5LiBBIGRldGFpbGVkIG1vcnBob2xvZ2ljYWwgbWVhc3VyZW1lbnQgb2YgdGhlIHNldmVudGggc3BlY2ltZW4gb2YgdGhlIEluZG9uZXNpYW4gY29lbGFjYW50aCwgKkxhdGltZXJpYSBtZW5hZG9lbnNpcyosIHdpdGggYSBjb21waWxhdGlvbiBvZiBjdXJyZW50IG1vcnBob2xvZ2ljYWwgZGF0YSBvZiB0aGUgc3BlY2llcy4gKkJ1bGxldGluIG9mIHRoZSBLaXRha3l1c2h1IE11c2V1bSBvZiBOYXR1cmFsIEhpc3RvcnkgYW5kIEh1bWFuIEhpc3RvcnksIFNlcmllcyBBIChOYXR1cmFsIEhpc3RvcnkpKjogMTc6NjctODAuIGh0dHBzOi8vZG9pLm9yZy8xMC4zNDUyMi9rbW5oLjE3LjBfNjcNCg0KU2Nod2VuaywgSy4gMTk5NS4gQSB1dGlsaXRhcmlhbiBhcHByb2FjaCB0byBldm9sdXRpb25hcnkgY29uc3RyYWludC4gKlpvb2xvZ3kqLCA5ODoyNTHigJMyNjIuDQoNClNwcmluZ2VyLCBWLkcuLCBhbmQgR2FycmljaywgSi5BLkYuIDE5NjQuIEEgc3VydmV5IG9mIHZlcnRlYnJhbCBudW1iZXJzIGluIHNoYXJrcy4gKlByb2NlZWRpbmdzIG9mIHRoZSBVbml0ZWQgU3RhdGVzIE5hdGlvbmFsIE11c2V1bSosIDExNjo3M+KAkzk2LiBodHRwczovLzEwLjU0Nzkvc2kuMDA5NjM4MDEuMTE2LTM0OTYuNzMgDQoNClN0cmF1YmUsIE4uLCBMaSwgQy4sIENsYWVzLCBKLk0uLCBDb3JyaWdhbiwgUy4sIGFuZCBOYXlsb3IsIEcuSi5QLiAyMDE1LiBNb2xlY3VsYXIgcGh5bG9nZW55IG9mIFNxdWFsaWZvcm1lcyBhbmQgZmlyc3Qgb2NjdXJyZW5jZSBvZiBiaW9sdW1pbmVzY2VuY2UgaW4gc2hhcmtzLiBCTUMgRXZvbHV0aW9uYXJ5IEJpb2xvZ3ksIDE1OjE2Mi4gaHR0cHM6Ly9kb2kub3JnLzEwLjExODYvczEyODYyLTAxNS0wNDQ2LTYNCg0KU3RlbnNpw7YsIEUuQS4gMTk1OS4gT24gdGhlIHBlY3RvcmFsIGZpbiBhbmQgc2hvdWxkZXIgZ2lyZGxlIG9mIHRoZSBhcnRocm9kaXJlcy4gS3VuZ2xpZ2FyICpTdmVuc2thIFZldGVuc2thcGFrYWRhbWllbnMgSGFuZGxpbmdhciosIDg6MeKAkzIyOS4NCg0KU3Rlcm5lcywgUC5DLiwgYW5kIFNoaW1hZGEsIEsuIDIwMjAuIEJvZHkgZm9ybXMgaW4gc2hhcmtzIChDaG9uZHJpY2h0aHllczogRWxhc21vYnJhbmNoaWkpIGFuZCB0aGVpciBmdW5jdGlvbmFsLCBlY29sb2dpY2FsLCBhbmQgZXZvbHV0aW9uYXJ5IGltcGxpY2F0aW9ucy4gKlpvb2xvZ3kqLCAxNDA6MTI1Nzk5LiBodHRwczovL2RvaS5vcmcvMTAuMTAxNi9qLnpvb2wuMjAyMC4xMjU3OTkNCg0KVHJpbmFqc3RpYywgSy4sIGFuZCBNY05hbWFyYSwgSy5KLiAxOTk5LiBIZXRlcm9jaHJvbnkgaW4gdGhlIExhdGUgRGV2b25pYW4gYXJ0aHJvZGlyYW4gZmlzaGVzIENvbXBhZ29waXNjaXMgYW5kIEluY2lzb3NjdXR1bS4gKlJlY29yZHMgb2YgdGhlIFdlc3Rlcm4gQXVzdHJhbGlhbiBNdXNldW0qLCA1Nzo3N+KAkzkxLiANCg0KVHJpbmFqc3RpYywgSy4sIGFuZCBIYXplbHRvbiwgTS4gMjAwNy4gT250b2dlbnksIHBoZW5vdHlwaWMgdmFyaWF0aW9uIGFuZCBwaHlsb2dlbmV0aWMgaW1wbGljYXRpb25zIG9mIGFydGhyb2RpcmVzIGZyb20gdGhlIEdvZ28gRm9ybWF0aW9uLCBXZXN0ZXJuIEF1c3RyYWxpYS4gKkpvdXJuYWwgb2YgVmVydGVicmF0ZSBQYWxlb250b2xvZ3kqLCAyNzo1NzHigJM1ODMuIGh0dHBzOi8vZG9pLm9yZy8xMC4xNjcxLzAyNzItNDYzNCgyMDA3KTI3WzU3MTpPUFZBUEldMi4wLkNPOzINCg0KVHJpbmFqc3RpYywgSy4sIEJvaXN2ZXJ0LCBDLiwgTG9uZywgSi4sIE1ha3NpbWVua28sIEEuLCBhbmQgSm9oYW5zb24sIFouIDIwMTUuIFBlbHZpYyBhbmQgcmVwcm9kdWN0aXZlIHN0cnVjdHVyZXMgaW4gcGxhY29kZXJtcyAoc3RlbSBnbmF0aG9zdG9tZXMpLiAqQmlvbG9naWNhbCBSZXZpZXdzKiwgOTA6NDY3LTUwMS4gaHR0cHM6Ly9kb2kub3JnLzEwLjExMTEvYnJ2LjEyMTE4DQoNClRyaW5hanN0aWMsIEsuLCBMb25nLCBKLkEuLCBTYW5jaGV6LCBTLiwgQm9pc3ZlcnQsIEMuQS4sIFNuaXR0aW5nLCBELiwgVGFmZm9yZWF1LCBQLiwgRHVwcmV0LCBWLiwgQ2xlbWVudCwgQS5NLiwgQ3VycmllLCBQLkQuLCBSb2Vsb2ZzLCBCLiwgQmV2aXR0LCBKLkouLCBMZWUsIE0uUy5ZLiwgYW5kIEFobGJlcmcsIFAuRS4gMjAyMi4gRXhjZXB0aW9uYWwgcHJlc2VydmF0aW9uIG9mIG9yZ2FucyBpbiBEZXZvbmlhbiBwbGFjb2Rlcm1zIGZyb20gdGhlIEdvZ28gbGFnZXJzdMOkdHRlLiAqU2NpZW5jZSosIDM3NzoxMzExLTEzMTQsIGh0dHBzOi8vZG9pLm9yZy8xMC4xMTI2L3NjaWVuY2UuYWJmMzI4OQ0KDQpUcmluYWpzdGljLCBLLiwgU2FuY2hleiwgUy4sIER1cHJldCwgVi4sIFRhZmZvcmVhdSwgUC4sIExvbmcsIEouLCBZb3VuZywgRy4sIFNlbmRlbiwgVC4sIEJvaXN2ZXJ0LCBDLiwgUG93ZXIsIE4uLCBhbmQgQWhsYmVyZywgUC5FLiAyMDEzLiBGb3NzaWwgbXVzY3VsYXR1cmUgb2YgdGhlIG1vc3QgcHJpbWl0aXZlIGphd2VkIHZlcnRlYnJhdGVzLiAqU2NpZW5jZSosIDM0MToxNjAtNC4gaHR0cHM6Ly9kb2kub3JnLzEwLjExMjYvc2NpZW5jZS4xMjM3Mjc1DQoNCldhZ25lciwgRy5QLiwgYW5kIFNjaHdlbmssIEsuIDIwMDAuIEV2b2x1dGlvbmFyaWx5IFN0YWJsZSBDb25maWd1cmF0aW9uczogRnVuY3Rpb25hbCBJbnRlZ3JhdGlvbiBhbmQgdGhlIEV2b2x1dGlvbiBvZiBQaGVub3R5cGljIFN0YWJpbGl0eS4gSW4gSGVjaHQsIE0uSy4sIE1hY2ludHlyZSwgUi5KLiwgQ2xlZ2csIE0uVC4gKGVkcy4pIEV2b2x1dGlvbmFyeSBCaW9sb2d5LiBTcHJpbmdlciwgQm9zdG9uLiBodHRwczovL2RvaS5vcmcvMTAuMTAwNy85NzgtMS00NjE1LTQxODUtMV80DQoNCldlcmRlbGluLCBMLiAxOTg3LiBKYXcgZ2VvbWV0cnkgYW5kIG1vbGFyIG1vcnBob2xvZ3kgaW4gbWFyc3VwaWFsIGNhcm5pdm9yZXM7IGFuYWx5c2lzIG9mIGEgY29uc3RyYWludCBhbmQgaXRzIG1hY3JvZXZvbHV0aW9uYXJ5IGNvbnNlcXVlbmNlcy4gKlBhbGVvYmlvbG9neSosIDEzOjM0MuKAkzM1MC4gaHR0cHM6Ly9kb2kub3JnLzEwLjEwMTcvUzAwOTQ4MzczMDAwMDg5MTUNCg0KPC9kaXY+DQoNCiMjIFIgUGFja2FnZXMNCg0KPGRpdiBzdHlsZT0idGV4dC1pbmRlbnQ6IC00MHB4OyBwYWRkaW5nLWxlZnQ6IDQwcHg7IG1hcmdpbi1ib3R0b209MDsgbWFyZ2luLXRvcD0wIj4NCg0KQXVndWllIEIgKDIwMTcpLiBfZ3JpZEV4dHJhOiBNaXNjZWxsYW5lb3VzIEZ1bmN0aW9ucyBmb3IgIkdyaWQiIEdyYXBoaWNzXy4gUiBwYWNrYWdlIHZlcnNpb24gMi4zLCA8aHR0cHM6Ly9DUkFOLlItcHJvamVjdC5vcmcvcGFja2FnZT1ncmlkRXh0cmE+Lg0KDQpCYWNoZSBTLCBXaWNraGFtIEggKDIwMjIpLiBfbWFncml0dHI6IEEgRm9yd2FyZC1QaXBlIE9wZXJhdG9yIGZvciBSXy4gUiBwYWNrYWdlIHZlcnNpb24gMi4wLjMsIDxodHRwczovL0NSQU4uUi1wcm9qZWN0Lm9yZy9wYWNrYWdlPW1hZ3JpdHRyPi4NCg0KUGVkZXJzZW4gVCAoMjAyNCkuIF9wYXRjaHdvcms6IFRoZSBDb21wb3NlciBvZiBQbG90c18uIFIgcGFja2FnZSB2ZXJzaW9uIDEuMi4wLCA8aHR0cHM6Ly9DUkFOLlItcHJvamVjdC5vcmcvcGFja2FnZT1wYXRjaHdvcms+Lg0KDQpSIENvcmUgVGVhbSAoMjAyMykuIF9SOiBBIExhbmd1YWdlIGFuZCBFbnZpcm9ubWVudCBmb3IgU3RhdGlzdGljYWwgQ29tcHV0aW5nXy4gUg0KRm91bmRhdGlvbiBmb3IgU3RhdGlzdGljYWwgQ29tcHV0aW5nLCBWaWVubmEsIEF1c3RyaWEuIDxodHRwczovL3d3dy5SLXByb2plY3Qub3JnLz4uDQoNClJvYmluc29uIEQsIEhheWVzIEEsIENvdWNoIFMgKDIwMjMpLiBfYnJvb206IENvbnZlcnQgU3RhdGlzdGljYWwgT2JqZWN0cyBpbnRvIFRpZHkgVGliYmxlc18uIFIgcGFja2FnZSB2ZXJzaW9uIDEuMC41LCA8aHR0cHM6Ly9DUkFOLlItcHJvamVjdC5vcmcvcGFja2FnZT1icm9vbT4uDQoNCldpY2toYW0gSCwgQnJ5YW4gSiAoMjAyMykuIF9yZWFkeGw6IFJlYWQgRXhjZWwgRmlsZXNfLiBSIHBhY2thZ2UgdmVyc2lvbiAxLjQuMywgPGh0dHBzOi8vQ1JBTi5SLXByb2plY3Qub3JnL3BhY2thZ2U9cmVhZHhsPi4NCg0KV2lja2hhbSBILCBTZWlkZWwgRCAoMjAyMikuIF9zY2FsZXM6IFNjYWxlIEZ1bmN0aW9ucyBmb3IgVmlzdWFsaXphdGlvbl8uIFIgcGFja2FnZSB2ZXJzaW9uIDEuMi4xLCA8aHR0cHM6Ly9DUkFOLlItcHJvamVjdC5vcmcvcGFja2FnZT1zY2FsZXM+Lg0KDQpXaWNraGFtIEgsIEF2ZXJpY2sgTSwgQnJ5YW4gSiwgQ2hhbmcgVywgTWNHb3dhbiBMRCwgRnJhbsOnb2lzIFIsIEdyb2xlbXVuZCBHLCBIYXllcyBBLCBIZW5yeSBMLCBIZXN0ZXIgSiwgS3VobiBNLCBQZWRlcnNlbiBUTCwgTWlsbGVyIEUsIEJhY2hlIFNNLCBNw7xsbGVyIEssIE9vbXMgSiwgUm9iaW5zb24gRCwgU2VpZGVsIERQLCBTcGludSBWLCBUYWthaGFzaGkgSywgVmF1Z2hhbiBELCBXaWxrZSBDLCBXb28gSywgWXV0YW5pIEggKDIwMTkpLiDigJxXZWxjb21lIHRvIHRoZSB0aWR5dmVyc2Uu4oCdIF9Kb3VybmFsIG9mIE9wZW4gU291cmNlIFNvZnR3YXJlXywgKjQqKDQzKSwgMTY4Ni4gPGh0dHBzOi8vZG9pLm9yZy8xMC4yMTEwNS9qb3NzLjAxNjg2Pi4NCg0KV2lsa2UgQywgV2llcm5payBCICgyMDIyKS4gX2dndGV4dDogSW1wcm92ZWQgVGV4dCBSZW5kZXJpbmcgU3VwcG9ydCBmb3IgJ2dncGxvdDInXy4gUiBwYWNrYWdlIHZlcnNpb24gMC4xLjIsIDxodHRwczovL0NSQU4uUi1wcm9qZWN0Lm9yZy9wYWNrYWdlPWdndGV4dD4uDQoNClh1IFMgKDIwMjIpLiBfZ2dzdGFyOiBNdWx0aXBsZSBHZW9tZXRyaWMgU2hhcGUgUG9pbnQgTGF5ZXIgZm9yICdnZ3Bsb3QyJ18uIFIgcGFja2FnZSB2ZXJzaW9uIDEuMC40LCA8aHR0cHM6Ly9DUkFOLlItcHJvamVjdC5vcmcvcGFja2FnZT1nZ3N0YXI+Lg0KDQpaaHUgSCAoMjAyMSkuIF9rYWJsZUV4dHJhOiBDb25zdHJ1Y3QgQ29tcGxleCBUYWJsZSB3aXRoICdrYWJsZScgYW5kIFBpcGUgU3ludGF4Xy4NClIgcGFja2FnZSB2ZXJzaW9uIDEuMy40LCA8aHR0cHM6Ly9DUkFOLlItcHJvamVjdC5vcmcvcGFja2FnZT1rYWJsZUV4dHJhPi4NCg0KPC9kaXY+DQoNCiMgU2Vzc2lvbiBJbmZvcm1hdGlvbg0KDQpgYGB7cn0NCnhmdW46OnNlc3Npb25faW5mbygpDQpgYGA=