This is a R Markdown Notebook, provided as supporting information for the manuscript “Flight performance and wing morphology in the bat Carollia perspicillata: biophysical models and energetics”.

For proper compilation, all data and function files provided need to be in the same folder.

Data Preparation and biophysical models

Start by loading required libraries

#Load required libraries
require(paran)
require(ggplot2)
require(metR)
require(FactoMineR)
require(factoextra)
require(car)
require(rsm)
require(knitr)
Loading required package: knitr

Next, the calculations of heat loss for separate body surfaces during flight are done, reading data frames and using the function provided in the file HeatLoss.R.

#Heat Loss calculation for each body part
source("HeatLoss.R")
#Read Body surface data
bodyTA<-read.table("BodyTA.txt",header=T,row.names = 1)
QtBody<-HLoss(bodyTA)
HeadTA<-read.table("HeadTA.txt",header=T,row.names = 1)
QtHead<-HLoss(HeadTA)
WingTA<-read.table("WingTA.txt",header=T,row.names = 1)
QtWing<-HLoss(WingTA)
ArmTA<-read.table("ArmTA.txt",header=T,row.names = 1)
QtArm<-HLoss(ArmTA)

Read wing morphology data, create a data frame with morphology variable for PCA, and calculate derived variables (AR, WL) and the total heat loss summing all body surfaces.

The morphological variable names are:

ID - Animal ID (color and necklace number)

Sex - sex factor: M = males, F = females

B - Wing span (m)

S - Wing Area (m^2) (sum of both sides plus bodyarea)

M - Body Mass (Kg)

ForL - Forearm length (mm)

WTip - Wing tip (Mm)

WLength - Wing length (mm)

DgIIIPh1 - Length of the 3rd digit of the 1st phalange (mm)

DgIIIPh2 - Length of the 3rd digit of the 2nd phalange (mm)

DgIIIPh3 - Length of the 3rd digit of the 3rd phalange (mm)

DgVMt - Length of the 5th digit of the metacarpal (mm)

DgVPh1- Length of the 5th digit of the 1st phalange (mm)

DgVPh2 - Length of the 5th digit of the 2nd phalange (mm)

Dactyl - Dactylopatagium width (mm)

Warea - Wing area (only left side) (mm^2)

DactArea - Dactylopatagium area (mm^2)

#read data, animal IDs are row names
qt<-read.table("WingMorph.txt",header=T,row.names = 1)
qt$Sex<-factor(qt$Sex)
#Separate wing morphology variables for PCA
Wing<-qt[,4:16]
#Calculate aspect ratio
qt$AR<-(qt$B^2)/qt$S
#Calculate wing loading
qt$WL<-(qt$M*9.81)/qt$S
#Add heat loss to main data frame, corrected for mechanical efficiency of 8.7%
qt$Qt<-(QtBody$Qt+QtHead$Qt+QtWing$Qt+QtArm$Qt)/(1-0.087)

Calculate minimum power required to fly, using the function in file ‘PowFlight.R’, and add it to the main data frame.

#Calculation of Pmin (minimum power required to fly horizontally)
source("PowFlight.R")
Powm<-PowFly(qt)
qt$Pmin<-Powm$mP
#MaxR = maximum range, not used in models because it is correlated with Pmin
qt$MaxR<-Powm$MaxR
#Vmp = minimum power speed, not used in models because it is correlated with Pmin
qt$Vmp<-Powm$Vmp

Principal components analysis of wing morphology

Calculate number of dimensions to retain using parallel analysis

paran(Wing,graph=T,all=T)

Using eigendecomposition of correlation matrix.
Computing: 10%  20%  30%  40%  50%  60%  70%  80%  90%  100%


Results of Horn's Parallel Analysis for component retention
390 iterations, using the mean estimate

-------------------------------------------------- 
Component   Adjusted    Unadjusted    Estimated 
            Eigenvalue  Eigenvalue    Bias 
-------------------------------------------------- 
1           4.200816    4.796752      0.595936
2           1.314579    1.754888      0.440309
3           1.085290    1.405174      0.319883
4           0.760734    0.980557      0.219823
5           0.672904    0.804407      0.131503
6           0.671573    0.720502      0.048929
7           0.641264    0.612963     -0.02830
8           0.630732    0.526721     -0.10401
9           0.590322    0.413899     -0.17642
10          0.589626    0.342076     -0.24754
11          0.635438    0.314139     -0.32129
12          0.638933    0.242730     -0.39620
13          0.567783    0.085182     -0.48260
-------------------------------------------------- 

Adjusted eigenvalues > 1 indicate dimensions to retain.
(3 components retained)

Parallel analysis identified 3 PCs with larger eigenvalues than expected in a random distribution. Next, generate a PCA object with 3 axes.

PCWing<-PCA(Wing,ncp=3)

Description of PCs, based on correlations with variables.

kables(list(kable("**Correlations**",col.names = NULL),kable(PCWing$var$cor),kable("**Contribution (%)**",col.names = NULL),kable(PCWing$var$contrib)),caption = "**Table S1. Description of PCs (Dim.1-Dim.3), based on correlations of scores with variables, and the percentage contribution of each variable to the given component**")
Table S1. Description of PCs (Dim.1-Dim.3), based on correlations of scores with variables, and the percentage contribution of each variable to the given component
Correlations
Dim.1 Dim.2 Dim.3
M 0.3930441 0.0357618 -0.1001526
ForL 0.7308137 -0.2824303 -0.1149222
WTip 0.6417254 -0.3058741 0.2054238
WLength 0.7401456 -0.4213380 0.1362644
DgIIIPh1 0.7178556 0.0489367 -0.1991975
DgIIIPh2 0.3370307 0.1107531 -0.6783921
DgIIIPh3 -0.0295857 -0.3541331 0.7739853
DgVMt 0.7557868 -0.2266024 -0.0492903
DgVPh1 0.6799445 -0.0313326 -0.1525218
DgVPh2 0.5936091 0.2221052 0.0231415
Dactyl 0.4057258 0.8122598 0.3129717
Warea 0.7934823 -0.0766917 0.1642200
DactArea 0.5819228 0.7038311 0.2665968
Contribution (%)
Dim.1 Dim.2 Dim.3
M 3.2205882 0.0728769 0.7138284
ForL 11.1343815 4.5454098 0.9398906
WTip 8.5852130 5.3313321 3.0031106
WLength 11.4205482 10.1160689 1.3214015
DgIIIPh1 10.7430312 0.1364644 2.8238231
DgIIIPh2 2.3680544 0.6989754 32.7515036
DgIIIPh3 0.0182481 7.1463351 42.6319435
DgVMt 11.9083419 2.9260355 0.1728990
DgVPh1 9.6382804 0.0559427 1.6555164
DgVPh2 7.3460477 2.8110460 0.0381111
Dactyl 3.4317673 37.5958897 6.9707547
Warea 13.1258434 0.3351563 1.9192072
DactArea 7.0596546 28.2284672 5.0580102

Biplot for the space of the first two principal components

#Prepare data frames for biplot
#Save variable coordinates
PCvar<-as.data.frame(PCWing$var$coord[,1:3])
#Invert PC2 variable coordinates for convenience of interpretation
PCvar$Dim.2<--PCvar$Dim.2
#Save individual scores
PCind<-as.data.frame(PCWing$ind$coord[,1:3])
#Invert PC2 individual scores for convenience of interpretation
PCind$Dim.2<--PCind$Dim.2
#PCA Biplot (Figure 3)
#Create sex factor in numeric form to change point shape in plot
Sexpch<-c(16,17)[as.numeric(qt$Sex)]
#Biplot
ggplot(PCind,aes(x=Dim.1,y=Dim.2))+
  geom_point(size=4,shape=Sexpch,)+
  labs(y="PC2 (13.50%)", x="PC1 (36.90%)")+
  geom_text(data=PCvar*4.5,label=variable.names(Wing),colour="darkred",size=5)+
  geom_segment(data=PCvar,
               aes(x = 0, y = 0, xend = Dim.1*4, yend = Dim.2*4),
               arrow = arrow(
                 length = unit(0.015,"npc"), 
                 type="closed" # Describes arrow head (open or closed)
               ),
               colour = "darkred",
               size = 0.8,
  )+theme(text = element_text(size=rel(4.5)),panel.border=element_rect(linetype="solid",fill=NA))

Other graphics

Scatterplot for aspect ratio and wing loading

#Scatterplot for aspect ratio and wing loading
ggplot(qt,aes(x=WL,y=AR))+
  geom_point(size=4,shape=Sexpch,)+
  labs(y="Aspect Ratio", x=expression(paste("Wing Loading "(Nm^-2))))+
  theme(text = element_text(size=rel(4.5)),panel.border=element_rect(linetype="solid",fill=NA))

Fitting response surface models (rsm package)

Independent variables in RSMs are standardized, so the model coefficients show changes in the response for each standard deviation of the predictor.

#Send PC scores to qt data frame, standardizing to sd=1
qt$PC1<-scale(PCind$Dim.1)
qt$PC2<-scale(PCind$Dim.2)
qt$PC3<-scale(PCind$Dim.3)
#Standardize AR and WL.
qt$sAR<-scale(qt$AR)
qt$sWL<-scale(qt$WL)

Response surface models for minimum power required to fly (Pmin) as response

Models fitting Pmin as response, Sex, AR and WL as predictors. We started fitting the model as second order

pwaw.rsm<-rsm(Pmin~Sex+SO(sAR,sWL),data=qt)
kables(list(kable("**Coefficients**",col.names=NULL), kable(summary(pwaw.rsm)$coefficients),kable("**ANOVA**",col.names=NULL), kable(summary(pwaw.rsm)$lof)), caption = "**Table S2. Coefficients and analysis of variance of response surface model with Pmin as response and Sex, AR, and WL as predictors**")
Near-stationary-ridge situation detected -- stationary point altered
 Change 'threshold' if this is not what you intend
Near-stationary-ridge situation detected -- stationary point altered
 Change 'threshold' if this is not what you intend
Table S2. Coefficients and analysis of variance of response surface model with Pmin as response and Sex, AR, and WL as predictors
Coefficients
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.0606634 0.0005608 108.1674487 0.0000000
SexM -0.0000129 0.0006136 -0.0210137 0.9832731
sAR -0.0037887 0.0002961 -12.7975896 0.0000000
sWL 0.0076974 0.0003451 22.3049325 0.0000000
sAR:sWL -0.0009239 0.0003299 -2.8007187 0.0060338
sAR^2 0.0004849 0.0002299 2.1086880 0.0372623
sWL^2 0.0004675 0.0002813 1.6620954 0.0993670
ANOVA
Df Sum Sq Mean Sq F value Pr(>F)
Sex 1 0.0008487 0.0008487 100.365161 0.0000000
FO(sAR, sWL) 2 0.0055490 0.0027745 328.110021 0.0000000
TWI(sAR, sWL) 1 0.0000236 0.0000236 2.795881 0.0973751
PQ(sAR, sWL) 2 0.0000543 0.0000272 3.211301 0.0441461
Residuals 109 0.0009217 0.0000085 NA NA
Lack of fit 109 0.0009217 0.0000085 NaN NaN
Pure error 0 0.0000000 NaN NA NA

Model summary coefficients and analysis of variance indicate a quadratic component, so second order model is retained. Sex is removed from the model. It might be collinear with WL.

pwaw.rsm2<-rsm(Pmin~SO(sAR,sWL),data=qt)
kables(list(kable("**Coefficients**", col.names=NULL), kable(summary(pwaw.rsm2)$coefficients),kable("**ANOVA**",col.names=NULL), kable(summary(pwaw.rsm2)$lof)), caption = "**Table S3. Coefficients and analysis of variance of response surface model with Pmin as response and AR and WL as predictors**")
Near-stationary-ridge situation detected -- stationary point altered
 Change 'threshold' if this is not what you intend
Near-stationary-ridge situation detected -- stationary point altered
 Change 'threshold' if this is not what you intend
Table S3. Coefficients and analysis of variance of response surface model with Pmin as response and AR and WL as predictors
Coefficients
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.0606556 0.0004180 145.099172 0.0000000
sAR -0.0037885 0.0002945 -12.862482 0.0000000
sWL 0.0076943 0.0003113 24.714144 0.0000000
sAR:sWL -0.0009240 0.0003284 -2.813681 0.0058032
sAR^2 0.0004858 0.0002244 2.165373 0.0325193
sWL^2 0.0004680 0.0002788 1.678789 0.0960317
ANOVA
Df Sum Sq Mean Sq F value Pr(>F)
FO(sAR, sWL) 2 0.0063967 0.0031984 381.705934 0.0000000
TWI(sAR, sWL) 1 0.0000221 0.0000221 2.632569 0.1075549
PQ(sAR, sWL) 2 0.0000568 0.0000284 3.390698 0.0372431
Residuals 110 0.0009217 0.0000084 NA NA
Lack of fit 110 0.0009217 0.0000084 NaN NaN
Pure error 0 0.0000000 NaN NA NA

Check model residuals for trends (no trends observed)

plot(predict(pwaw.rsm2),resid(pwaw.rsm2),xlab="Predicted",ylab = "Residuals")

Models fitting Pmin as response, Sex and PC scores as predictors. We started fitting model as second order, including the first three PCs:

pwpc.rsm<-rsm(Pmin~Sex+SO(PC1,PC2,PC3),data=qt)
kables(list(kable("**Coefficients**", col.names=NULL), kable(summary(pwpc.rsm)$coefficients),kable("**ANOVA**",col.names=NULL), kable(summary(pwpc.rsm)$lof)), caption = "**Table S4. Coefficients and analysis of variance of response surface model with Pmin as response and Sex and PC scores as predictors**")
Table S4. Coefficients and analysis of variance of response surface model with Pmin as response and Sex and PC scores as predictors
Coefficients
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.0568601 0.0012349 46.0434340 0.0000000
SexM 0.0045790 0.0012854 3.5622360 0.0005544
PC1 0.0021145 0.0006329 3.3408988 0.0011573
PC2 -0.0019698 0.0006708 -2.9363502 0.0040813
PC3 -0.0012024 0.0006493 -1.8517957 0.0668648
PC1:PC2 -0.0026303 0.0006671 -3.9431467 0.0001454
PC1:PC3 0.0006649 0.0006533 1.0176791 0.3111697
PC2:PC3 0.0002733 0.0006733 0.4059267 0.6856225
PC1^2 -0.0005764 0.0005210 -1.1064029 0.2710806
PC2^2 0.0012071 0.0004385 2.7530370 0.0069587
PC3^2 0.0015462 0.0004895 3.1586718 0.0020701
ANOVA
Df Sum Sq Mean Sq F value Pr(>F)
Sex 1 0.0008487 0.0008487 19.577895 0.0000237
FO(PC1, PC2, PC3) 3 0.0005919 0.0001973 4.551439 0.0048649
TWI(PC1, PC2, PC3) 3 0.0005490 0.0001830 4.221429 0.0073385
PQ(PC1, PC2, PC3) 3 0.0008561 0.0002854 6.582840 0.0004038
Residuals 105 0.0045517 0.0000433 NA NA
Lack of fit 105 0.0045517 0.0000433 NaN NaN
Pure error 0 0.0000000 NaN NA NA

Model summary coefficients and the analysis of variance indicate a quadratic component, so the second order model is retained. PC3 did not contribute to surface (coefficients not statistically significant), so it was excluded.

pwpc.rsm2<-rsm(Pmin~Sex+SO(PC1,PC2),data=qt)
kables(list(kable("**Coefficients**", col.names=NULL), kable(summary(pwpc.rsm2)$coefficients),kable("**ANOVA**",col.names=NULL), kable(summary(pwpc.rsm2)$lof)), caption = "**Table S5. Coefficients and analysis of variance of response surface model with Pmin as response and PC scores as predictors**")
Table S5. Coefficients and analysis of variance of response surface model with Pmin as response and PC scores as predictors
Coefficients
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.0582617 0.0011466 50.8119168 0.0000000
SexM 0.0044604 0.0013225 3.3726618 0.0010313
PC1 0.0020258 0.0006626 3.0573891 0.0028090
PC2 -0.0017650 0.0006889 -2.5622223 0.0117657
PC1:PC2 -0.0020339 0.0006784 -2.9979953 0.0033666
PC1^2 -0.0004974 0.0005390 -0.9229185 0.3580882
PC2^2 0.0013193 0.0004581 2.8797220 0.0047925
ANOVA
Df Sum Sq Mean Sq F value Pr(>F)
Sex 1 0.0008487 0.0008487 17.743813 0.0000522
FO(PC1, PC2) 2 0.0005659 0.0002830 5.916014 0.0036377
TWI(PC1, PC2) 1 0.0003255 0.0003255 6.805133 0.0103648
PQ(PC1, PC2) 2 0.0004438 0.0002219 4.638899 0.0116552
Residuals 109 0.0052135 0.0000478 NA NA
Lack of fit 109 0.0052135 0.0000478 NaN NaN
Pure error 0 0.0000000 NaN NA NA

Check model residuals for trends (no trends observed)

plot(predict(pwpc.rsm2),resid(pwpc.rsm2),xlab="Predicted",ylab = "Residuals")

Response surface models for heat loss (Qt) as response

Models fitting Qt as response, Sex, AR and WL as predictors. We started fitting model as second order

qtaw.rsm<-rsm(Qt~Sex+SO(sWL,sAR),data=qt)
kables(list(kable("**Coefficients**", col.names=NULL), kable(summary(qtaw.rsm)$coefficients),kable("**ANOVA**",col.names=NULL), kable(summary(qtaw.rsm)$lof)), caption = "**Table S6. Coefficients and analysis of variance of response surface model with Qt as response and Sex, AR, and WL as predictors**")
Table S6. Coefficients and analysis of variance of response surface model with Qt as response and Sex, AR, and WL as predictors
Coefficients
Estimate Std. Error t value Pr(>|t|)
(Intercept) 4.3143781 0.1640823 26.2939892 0.0000000
SexM -0.0137608 0.1795265 -0.0766504 0.9390421
sWL 0.0741225 0.1009652 0.7341391 0.4644403
sAR 0.2089513 0.0866157 2.4123937 0.0175175
sWL:sAR -0.0785660 0.0965165 -0.8140157 0.4174107
sWL^2 0.0634960 0.0822901 0.7716117 0.4420140
sAR^2 0.0796838 0.0672747 1.1844546 0.2388095
ANOVA
Df Sum Sq Mean Sq F value Pr(>F)
Sex 1 0.2232533 0.2232533 0.3084403 0.5797769
FO(sWL, sAR) 2 7.1417316 3.5708658 4.9334062 0.0088908
TWI(sWL, sAR) 1 0.0061370 0.0061370 0.0084787 0.9268036
PQ(sWL, sAR) 2 1.2993613 0.6496806 0.8975802 0.4105453
Residuals 109 78.8956666 0.7238135 NA NA
Lack of fit 109 78.8956666 0.7238135 NaN NaN
Pure error 0 0.0000000 NaN NA NA

Model summary coefficients and the analysis of variance do not support sex or a quadratic component, so first order (linear) model is retained

qtaw.rsm2<-rsm(Qt~FO(sWL,sAR),data=qt)
kables(list(kable("**Coefficients**", col.names=NULL), kable(summary(qtaw.rsm2)$coefficients),kable("**ANOVA**",col.names=NULL), kable(summary(qtaw.rsm2)$lof)), caption = "**Table S7. Coefficients and analysis of variance of response surface model with Qt as response, AR and WL as predictors**")
Table S7. Coefficients and analysis of variance of response surface model with Qt as response, AR and WL as predictors
Coefficients
Estimate Std. Error t value Pr(>|t|)
(Intercept) 4.4212469 0.0782646 56.490998 0.0000000
sWL 0.1036763 0.0843771 1.228726 0.2217273
sAR 0.1945450 0.0843771 2.305661 0.0229542
ANOVA
Df Sum Sq Mean Sq F value Pr(>F)
FO(sWL, sAR) 2 7.275038 3.6375191 5.119367 0.0074424
Residuals 113 80.291111 0.7105408 NA NA
Lack of fit 113 80.291111 0.7105408 NaN NaN
Pure error 0 0.000000 NaN NA NA

Checking residuals (no trends observed)

plot(predict(qtaw.rsm2),resid(qtaw.rsm2),xlab = "Predicted", ylab = "Residuals")

Fitting Qt as response, PC scores as predictors. First, fitting model as second order response:

qtpc.rsm<-rsm(Qt~Sex+SO(PC1,PC2,PC3),data=qt)
kables(list(kable("**Coefficients**", col.names=NULL), kable(summary(qtpc.rsm)$coefficients),kable("**ANOVA**",col.names=NULL), kable(summary(qtpc.rsm)$lof)), caption = "**Table S8. Coefficients and analysis of variance of response surface model with Qt as response and Sex and PC scores as predictors**")
Table S8. Coefficients and analysis of variance of response surface model with Qt as response and Sex and PC scores as predictors
Coefficients
Estimate Std. Error t value Pr(>|t|)
(Intercept) 4.4491746 0.1523645 29.2008639 0.0000000
SexM 0.1713583 0.1585949 1.0804779 0.2824049
PC1 0.0424398 0.0780893 0.5434777 0.5879530
PC2 0.2914635 0.0827659 3.5215398 0.0006363
PC3 -0.0376005 0.0801107 -0.4693564 0.6397881
PC1:PC2 -0.1040224 0.0823013 -1.2639228 0.2090565
PC1:PC3 0.0393790 0.0806052 0.4885416 0.6261850
PC2:PC3 -0.1372087 0.0830749 -1.6516262 0.1015985
PC1^2 -0.0676508 0.0642771 -1.0524868 0.2949924
PC2^2 0.0068314 0.0540978 0.1262793 0.8997523
PC3^2 -0.0522853 0.0603947 -0.8657258 0.3886143
ANOVA
Df Sum Sq Mean Sq F value Pr(>F)
Sex 1 0.2232533 0.2232533 0.3383216 0.5620463
FO(PC1, PC2, PC3) 3 11.7852514 3.9284171 5.9531865 0.0008659
TWI(PC1, PC2, PC3) 3 5.0839760 1.6946587 2.5681130 0.0583382
PQ(PC1, PC2, PC3) 3 1.1857680 0.3952560 0.5989773 0.6170768
Residuals 105 69.2879010 0.6598848 NA NA
Lack of fit 105 69.2879010 0.6598848 NaN NaN
Pure error 0 0.0000000 NaN NA NA

Model summary coefficients and the analysis of variance do not support a quadratic component, so first order model is retained. Sex and PC3 did not contribute to surface (coefficients not statistically significant), so they were excluded from the model.

qtpc.rsm2<-rsm(Qt~FO(PC1,PC2),data=qt)
kables(list(kable("**Coefficients**", col.names=NULL), kable(summary(qtpc.rsm2)$coefficients),kable("**ANOVA**",col.names=NULL), kable(summary(qtpc.rsm2)$lof)), caption = "**Table S9. Coefficients and analysis of variance of response surface model with Qt as response and PC scores as predictors**")
Table S9. Coefficients and analysis of variance of response surface model with Qt as response and PC scores as predictors
Coefficients
Estimate Std. Error t value Pr(>|t|)
(Intercept) 4.4212469 0.0768040 57.5652889 0.0000000
PC1 0.0697330 0.0771372 0.9040119 0.3679123
PC2 0.2901974 0.0771372 3.7620919 0.0002688
ANOVA
Df Sum Sq Mean Sq F value Pr(>F)
FO(PC1, PC2) 2 10.24388 5.1219409 7.485286 0.0008855
Residuals 113 77.32227 0.6842679 NA NA
Lack of fit 113 77.32227 0.6842679 NaN NaN
Pure error 0 0.00000 NaN NA NA

Checking residuals (no trends observed)

plot(predict(qtpc.rsm2),resid(qtpc.rsm2),xlab = "Predicted", ylab = "Residuals")

Plotting response surface models

Generate new variables to predict surface

#Create new dataset based on min max AR and WL to predict rsm. Expanded grid with 50 points
newAW<-expand.grid(sAR=seq(-2.30,2.57,length.out = 50),sWL=seq(-1.79,2.54,length.out = 50))
#Calculate predictions
newAW$Pmin<-predict(pwaw.rsm2,newAW)
#Create new numeric vector to plot sex as different shapes
Sexpch2<-c(1,2)[as.numeric(qt$Sex)]
#Create new dataset based on min max PC scores to predict rsm. Expanded grid with 50 points
newPC<-expand.grid(PC1=seq(-2.47,2.30,length.out = 50),PC2=seq(-2.50,2.80,length.out = 50))
#Calculate predictions for males
newPCM<-newPC
newPCM$Sex<-rep("M",2500)
newPCM$Pmin<-predict(pwpc.rsm2,newPCM)
#Calculate predictions for females
newPCF<-newPC
newPCF$Sex<-rep("F",2500)
newPCF$Pmin<-predict(pwpc.rsm2,newPCF)
#Calculate average prediction
newPC$Pmin<-round((newPCF$Pmin+newPCM$Pmin)/2,digits=5)
#Calculate predictions for Qt models
newAW$Qt<-predict(qtaw.rsm2,newAW)
newPC$Qt<-predict(qtpc.rsm2,newPC)

Generate contour plot for surface. Minimum power required to fly is the response, aspect ratio and wing loading are predictors

ggplot(newAW, aes(sWL,sAR, z = Pmin))+
  labs(y="Standardized Aspect Ratio", x="Standardized Wing Loading")+
  coord_cartesian(xlim=c(-1.64,2.39), ylim=c(-2.13,2.40))+
  geom_raster(aes(fill = Pmin))+
  geom_contour(colour = "black")+
  geom_text_contour(aes(z = Pmin), nudge_x = 0,nudge_y = 0, colour="black",size=6,breaks=seq(0.05,0.1,by=0.01))+
  scale_fill_gradientn(colours=c("red","yellow"))+
  geom_point(data=qt,size=4,shape=Sexpch2,mapping=aes(x=sWL,y=sAR))+
  theme(legend.position = "none",text = element_text(size=rel(4.5)),panel.border=element_rect(linetype="solid",fill=NA))

Generate contour plot for surface. Minimum power required to fly is the response, PC scores are predictors

ggplot(newPC, aes(PC1,PC2, z = Pmin))+
  labs(y="Standardized PC2", x="Standardized PC1")+
  coord_cartesian(xlim=c(-2.295,2.13), ylim=c(-2.32,2.62))+
  geom_raster(aes(fill = Pmin))+
  geom_contour(colour = "black")+
  geom_text_contour(aes(z = Pmin), nudge_x = 0,nudge_y = 0, colour="black",size=6,breaks=seq(0.058,0.072,by=0.002))+
  scale_fill_gradientn(colours=c("red","yellow"))+
  geom_point(data=qt,size=4,shape=Sexpch2,mapping=aes(x=PC1,y=PC2))+
  theme(legend.position = "none",text = element_text(size=rel(4.5)),panel.border=element_rect(linetype="solid",fill=NA))

Generate contour plot for surface. Heat loss (Qt) is the response, aspect ratio and wing loading are predictors

ggplot(newAW, aes(sWL,sAR, z = Qt))+
  labs(y="Standardized Aspect Ratio", x="Standardized Wing Loading")+
  coord_cartesian(xlim=c(-1.64,2.39), ylim=c(-2.13,2.40))+
  geom_raster(aes(fill = Qt))+
  geom_contour(colour = "black")+
  geom_text_contour(aes(z = Qt), nudge_x = 0,nudge_y = 0, colour="black",size=6)+
  scale_fill_gradientn(colours=c("red","yellow"))+
  geom_point(data=qt,size=4,shape=Sexpch2,mapping=aes(x=sWL,y=sAR))+
  theme(legend.position = "none",text = element_text(size=rel(4.5)),panel.border=element_rect(linetype="solid",fill=NA))

Generate contour plot for surface. Heat loss (Qt) is the response, PC scores are predictors

ggplot(newPC, aes(PC1,PC2, z = Qt))+
  labs(y="Standardized PC2", x="Standardized PC1")+
  coord_cartesian(xlim=c(-2.29,2.13), ylim=c(-2.32,2.63))+
  geom_raster(aes(fill = Qt))+
  geom_contour(colour = "black")+
  geom_text_contour(aes(z = Qt), nudge_x = 0, nudge_y = 0, colour="black",size=6)+
  scale_fill_gradientn(colours=c("red","yellow"))+
  geom_point(data=qt,size=4,shape=Sexpch2,mapping=aes(x=PC1,y=PC2))+
  theme(legend.position = "none",text = element_text(size=rel(4.5)),panel.border=element_rect(linetype="solid",fill=NA))

LS0tCnRpdGxlOiAiU3VwcG9ydGluZyBJbmZvcm1hdGlvbiIKb3V0cHV0OgogIHdvcmRfZG9jdW1lbnQ6IGRlZmF1bHQKICBodG1sX25vdGVib29rOiBkZWZhdWx0CiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0CiAgaHRtbF9kb2N1bWVudDoKICAgIGRmX3ByaW50OiBwYWdlZAotLS0KClRoaXMgaXMgYSBbUiBNYXJrZG93bl0oaHR0cDovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbSkgTm90ZWJvb2ssIHByb3ZpZGVkIGFzIHN1cHBvcnRpbmcgaW5mb3JtYXRpb24gZm9yIHRoZSBtYW51c2NyaXB0ICJGbGlnaHQgcGVyZm9ybWFuY2UgYW5kIHdpbmcgbW9ycGhvbG9neSBpbiB0aGUgYmF0ICpDYXJvbGxpYSBwZXJzcGljaWxsYXRhKjogYmlvcGh5c2ljYWwgbW9kZWxzIGFuZCBlbmVyZ2V0aWNzIi4KCioqRm9yIHByb3BlciBjb21waWxhdGlvbiwgYWxsIGRhdGEgYW5kIGZ1bmN0aW9uIGZpbGVzIHByb3ZpZGVkIG5lZWQgdG8gYmUgaW4gdGhlIHNhbWUgZm9sZGVyLioqCgojIyMgRGF0YSBQcmVwYXJhdGlvbiBhbmQgYmlvcGh5c2ljYWwgbW9kZWxzCgpTdGFydCBieSBsb2FkaW5nIHJlcXVpcmVkIGxpYnJhcmllcwoKYGBge3J9CiNMb2FkIHJlcXVpcmVkIGxpYnJhcmllcwpyZXF1aXJlKHBhcmFuKQpyZXF1aXJlKGdncGxvdDIpCnJlcXVpcmUobWV0UikKcmVxdWlyZShGYWN0b01pbmVSKQpyZXF1aXJlKGZhY3RvZXh0cmEpCnJlcXVpcmUoY2FyKQpyZXF1aXJlKHJzbSkKcmVxdWlyZShrbml0cikKYGBgCgpOZXh0LCB0aGUgY2FsY3VsYXRpb25zIG9mIGhlYXQgbG9zcyBmb3Igc2VwYXJhdGUgYm9keSBzdXJmYWNlcyBkdXJpbmcgZmxpZ2h0IGFyZSBkb25lLCByZWFkaW5nIGRhdGEgZnJhbWVzIGFuZCB1c2luZyB0aGUgZnVuY3Rpb24gcHJvdmlkZWQgaW4gdGhlIGZpbGUgYEhlYXRMb3NzLlJgLgoKYGBge3J9CiNIZWF0IExvc3MgY2FsY3VsYXRpb24gZm9yIGVhY2ggYm9keSBwYXJ0CnNvdXJjZSgiSGVhdExvc3MuUiIpCiNSZWFkIEJvZHkgc3VyZmFjZSBkYXRhCmJvZHlUQTwtcmVhZC50YWJsZSgiQm9keVRBLnR4dCIsaGVhZGVyPVQscm93Lm5hbWVzID0gMSkKUXRCb2R5PC1ITG9zcyhib2R5VEEpCkhlYWRUQTwtcmVhZC50YWJsZSgiSGVhZFRBLnR4dCIsaGVhZGVyPVQscm93Lm5hbWVzID0gMSkKUXRIZWFkPC1ITG9zcyhIZWFkVEEpCldpbmdUQTwtcmVhZC50YWJsZSgiV2luZ1RBLnR4dCIsaGVhZGVyPVQscm93Lm5hbWVzID0gMSkKUXRXaW5nPC1ITG9zcyhXaW5nVEEpCkFybVRBPC1yZWFkLnRhYmxlKCJBcm1UQS50eHQiLGhlYWRlcj1ULHJvdy5uYW1lcyA9IDEpClF0QXJtPC1ITG9zcyhBcm1UQSkKYGBgCgpSZWFkIHdpbmcgbW9ycGhvbG9neSBkYXRhLCBjcmVhdGUgYSBkYXRhIGZyYW1lIHdpdGggbW9ycGhvbG9neSB2YXJpYWJsZSBmb3IgUENBLCBhbmQgY2FsY3VsYXRlIGRlcml2ZWQgdmFyaWFibGVzIChBUiwgV0wpIGFuZCB0aGUgdG90YWwgaGVhdCBsb3NzIHN1bW1pbmcgYWxsIGJvZHkgc3VyZmFjZXMuCgpUaGUgbW9ycGhvbG9naWNhbCB2YXJpYWJsZSBuYW1lcyBhcmU6CgpJRCAtIEFuaW1hbCBJRCAoY29sb3IgYW5kIG5lY2tsYWNlIG51bWJlcikKClNleCAtIHNleCBmYWN0b3I6IE0gPSBtYWxlcywgRiA9IGZlbWFsZXMKCkIgLSBXaW5nIHNwYW4gKG0pCgpTIC0gV2luZyBBcmVhIChtXF4yKSAoc3VtIG9mIGJvdGggc2lkZXMgcGx1cyBib2R5YXJlYSkKCk0gLSBCb2R5IE1hc3MgKEtnKQoKRm9yTCAtIEZvcmVhcm0gbGVuZ3RoIChtbSkKCldUaXAgLSBXaW5nIHRpcCAoTW0pCgpXTGVuZ3RoIC0gV2luZyBsZW5ndGggKG1tKQoKRGdJSUlQaDEgLSBMZW5ndGggb2YgdGhlIDNyZCBkaWdpdCBvZiB0aGUgMXN0IHBoYWxhbmdlIChtbSkKCkRnSUlJUGgyIC0gTGVuZ3RoIG9mIHRoZSAzcmQgZGlnaXQgb2YgdGhlIDJuZCBwaGFsYW5nZSAobW0pCgpEZ0lJSVBoMyAtIExlbmd0aCBvZiB0aGUgM3JkIGRpZ2l0IG9mIHRoZSAzcmQgcGhhbGFuZ2UgKG1tKQoKRGdWTXQgLSBMZW5ndGggb2YgdGhlIDV0aCBkaWdpdCBvZiB0aGUgbWV0YWNhcnBhbCAobW0pCgpEZ1ZQaDEtIExlbmd0aCBvZiB0aGUgNXRoIGRpZ2l0IG9mIHRoZSAxc3QgcGhhbGFuZ2UgKG1tKQoKRGdWUGgyIC0gTGVuZ3RoIG9mIHRoZSA1dGggZGlnaXQgb2YgdGhlIDJuZCBwaGFsYW5nZSAobW0pCgpEYWN0eWwgLSBEYWN0eWxvcGF0YWdpdW0gd2lkdGggKG1tKQoKV2FyZWEgLSBXaW5nIGFyZWEgKG9ubHkgbGVmdCBzaWRlKSAobW1cXjIpCgpEYWN0QXJlYSAtIERhY3R5bG9wYXRhZ2l1bSBhcmVhIChtbVxeMikKCmBgYHtyfQojcmVhZCBkYXRhLCBhbmltYWwgSURzIGFyZSByb3cgbmFtZXMKcXQ8LXJlYWQudGFibGUoIldpbmdNb3JwaC50eHQiLGhlYWRlcj1ULHJvdy5uYW1lcyA9IDEpCnF0JFNleDwtZmFjdG9yKHF0JFNleCkKI1NlcGFyYXRlIHdpbmcgbW9ycGhvbG9neSB2YXJpYWJsZXMgZm9yIFBDQQpXaW5nPC1xdFssNDoxNl0KI0NhbGN1bGF0ZSBhc3BlY3QgcmF0aW8KcXQkQVI8LShxdCRCXjIpL3F0JFMKI0NhbGN1bGF0ZSB3aW5nIGxvYWRpbmcKcXQkV0w8LShxdCRNKjkuODEpL3F0JFMKI0FkZCBoZWF0IGxvc3MgdG8gbWFpbiBkYXRhIGZyYW1lLCBjb3JyZWN0ZWQgZm9yIG1lY2hhbmljYWwgZWZmaWNpZW5jeSBvZiA4LjclCnF0JFF0PC0oUXRCb2R5JFF0K1F0SGVhZCRRdCtRdFdpbmckUXQrUXRBcm0kUXQpLygxLTAuMDg3KQpgYGAKCkNhbGN1bGF0ZSBtaW5pbXVtIHBvd2VyIHJlcXVpcmVkIHRvIGZseSwgdXNpbmcgdGhlIGZ1bmN0aW9uIGluIGZpbGUgJ1Bvd0ZsaWdodC5SJywgYW5kIGFkZCBpdCB0byB0aGUgbWFpbiBkYXRhIGZyYW1lLgoKYGBge3J9CiNDYWxjdWxhdGlvbiBvZiBQbWluIChtaW5pbXVtIHBvd2VyIHJlcXVpcmVkIHRvIGZseSBob3Jpem9udGFsbHkpCnNvdXJjZSgiUG93RmxpZ2h0LlIiKQpQb3dtPC1Qb3dGbHkocXQpCnF0JFBtaW48LVBvd20kbVAKI01heFIgPSBtYXhpbXVtIHJhbmdlLCBub3QgdXNlZCBpbiBtb2RlbHMgYmVjYXVzZSBpdCBpcyBjb3JyZWxhdGVkIHdpdGggUG1pbgpxdCRNYXhSPC1Qb3dtJE1heFIKI1ZtcCA9IG1pbmltdW0gcG93ZXIgc3BlZWQsIG5vdCB1c2VkIGluIG1vZGVscyBiZWNhdXNlIGl0IGlzIGNvcnJlbGF0ZWQgd2l0aCBQbWluCnF0JFZtcDwtUG93bSRWbXAKYGBgCgojIyMgUHJpbmNpcGFsIGNvbXBvbmVudHMgYW5hbHlzaXMgb2Ygd2luZyBtb3JwaG9sb2d5CgpDYWxjdWxhdGUgbnVtYmVyIG9mIGRpbWVuc2lvbnMgdG8gcmV0YWluIHVzaW5nIHBhcmFsbGVsIGFuYWx5c2lzCgpgYGB7cn0KcGFyYW4oV2luZyxncmFwaD1ULGFsbD1UKQpgYGAKClBhcmFsbGVsIGFuYWx5c2lzIGlkZW50aWZpZWQgMyBQQ3Mgd2l0aCBsYXJnZXIgZWlnZW52YWx1ZXMgdGhhbiBleHBlY3RlZCBpbiBhIHJhbmRvbSBkaXN0cmlidXRpb24uIE5leHQsIGdlbmVyYXRlIGEgUENBIG9iamVjdCB3aXRoIDMgYXhlcy4KCmBgYHtyfQpQQ1dpbmc8LVBDQShXaW5nLG5jcD0zKQpgYGAKCkRlc2NyaXB0aW9uIG9mIFBDcywgYmFzZWQgb24gY29ycmVsYXRpb25zIHdpdGggdmFyaWFibGVzLgoKYGBge3J9CmthYmxlcyhsaXN0KGthYmxlKCIqKkNvcnJlbGF0aW9ucyoqIixjb2wubmFtZXMgPSBOVUxMKSxrYWJsZShQQ1dpbmckdmFyJGNvciksa2FibGUoIioqQ29udHJpYnV0aW9uICglKSoqIixjb2wubmFtZXMgPSBOVUxMKSxrYWJsZShQQ1dpbmckdmFyJGNvbnRyaWIpKSxjYXB0aW9uID0gIioqVGFibGUgUzEuIERlc2NyaXB0aW9uIG9mIFBDcyAoRGltLjEtRGltLjMpLCBiYXNlZCBvbiBjb3JyZWxhdGlvbnMgb2Ygc2NvcmVzIHdpdGggdmFyaWFibGVzLCBhbmQgdGhlIHBlcmNlbnRhZ2UgY29udHJpYnV0aW9uIG9mIGVhY2ggdmFyaWFibGUgdG8gdGhlIGdpdmVuIGNvbXBvbmVudCoqIikKYGBgCgojIyMjIEJpcGxvdCBmb3IgdGhlIHNwYWNlIG9mIHRoZSBmaXJzdCB0d28gcHJpbmNpcGFsIGNvbXBvbmVudHMKCmBgYHtyfQojUHJlcGFyZSBkYXRhIGZyYW1lcyBmb3IgYmlwbG90CiNTYXZlIHZhcmlhYmxlIGNvb3JkaW5hdGVzClBDdmFyPC1hcy5kYXRhLmZyYW1lKFBDV2luZyR2YXIkY29vcmRbLDE6M10pCiNJbnZlcnQgUEMyIHZhcmlhYmxlIGNvb3JkaW5hdGVzIGZvciBjb252ZW5pZW5jZSBvZiBpbnRlcnByZXRhdGlvbgpQQ3ZhciREaW0uMjwtLVBDdmFyJERpbS4yCiNTYXZlIGluZGl2aWR1YWwgc2NvcmVzClBDaW5kPC1hcy5kYXRhLmZyYW1lKFBDV2luZyRpbmQkY29vcmRbLDE6M10pCiNJbnZlcnQgUEMyIGluZGl2aWR1YWwgc2NvcmVzIGZvciBjb252ZW5pZW5jZSBvZiBpbnRlcnByZXRhdGlvbgpQQ2luZCREaW0uMjwtLVBDaW5kJERpbS4yCiNQQ0EgQmlwbG90IChGaWd1cmUgMykKI0NyZWF0ZSBzZXggZmFjdG9yIGluIG51bWVyaWMgZm9ybSB0byBjaGFuZ2UgcG9pbnQgc2hhcGUgaW4gcGxvdApTZXhwY2g8LWMoMTYsMTcpW2FzLm51bWVyaWMocXQkU2V4KV0KI0JpcGxvdApnZ3Bsb3QoUENpbmQsYWVzKHg9RGltLjEseT1EaW0uMikpKwogIGdlb21fcG9pbnQoc2l6ZT00LHNoYXBlPVNleHBjaCwpKwogIGxhYnMoeT0iUEMyICgxMy41MCUpIiwgeD0iUEMxICgzNi45MCUpIikrCiAgZ2VvbV90ZXh0KGRhdGE9UEN2YXIqNC41LGxhYmVsPXZhcmlhYmxlLm5hbWVzKFdpbmcpLGNvbG91cj0iZGFya3JlZCIsc2l6ZT01KSsKICBnZW9tX3NlZ21lbnQoZGF0YT1QQ3ZhciwKICAgICAgICAgICAgICAgYWVzKHggPSAwLCB5ID0gMCwgeGVuZCA9IERpbS4xKjQsIHllbmQgPSBEaW0uMio0KSwKICAgICAgICAgICAgICAgYXJyb3cgPSBhcnJvdygKICAgICAgICAgICAgICAgICBsZW5ndGggPSB1bml0KDAuMDE1LCJucGMiKSwgCiAgICAgICAgICAgICAgICAgdHlwZT0iY2xvc2VkIiAjIERlc2NyaWJlcyBhcnJvdyBoZWFkIChvcGVuIG9yIGNsb3NlZCkKICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAgY29sb3VyID0gImRhcmtyZWQiLAogICAgICAgICAgICAgICBzaXplID0gMC44LAogICkrdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPXJlbCg0LjUpKSxwYW5lbC5ib3JkZXI9ZWxlbWVudF9yZWN0KGxpbmV0eXBlPSJzb2xpZCIsZmlsbD1OQSkpCmBgYAoKIyMjIE90aGVyIGdyYXBoaWNzCgpTY2F0dGVycGxvdCBmb3IgYXNwZWN0IHJhdGlvIGFuZCB3aW5nIGxvYWRpbmcKCmBgYHtyfQojU2NhdHRlcnBsb3QgZm9yIGFzcGVjdCByYXRpbyBhbmQgd2luZyBsb2FkaW5nCmdncGxvdChxdCxhZXMoeD1XTCx5PUFSKSkrCiAgZ2VvbV9wb2ludChzaXplPTQsc2hhcGU9U2V4cGNoLCkrCiAgbGFicyh5PSJBc3BlY3QgUmF0aW8iLCB4PWV4cHJlc3Npb24ocGFzdGUoIldpbmcgTG9hZGluZyAiKE5tXi0yKSkpKSsKICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9cmVsKDQuNSkpLHBhbmVsLmJvcmRlcj1lbGVtZW50X3JlY3QobGluZXR5cGU9InNvbGlkIixmaWxsPU5BKSkKYGBgCgojIyMgRml0dGluZyByZXNwb25zZSBzdXJmYWNlIG1vZGVscyAocnNtIHBhY2thZ2UpCgpJbmRlcGVuZGVudCB2YXJpYWJsZXMgaW4gUlNNcyBhcmUgc3RhbmRhcmRpemVkLCBzbyB0aGUgbW9kZWwgY29lZmZpY2llbnRzIHNob3cgY2hhbmdlcyBpbiB0aGUgcmVzcG9uc2UgZm9yIGVhY2ggc3RhbmRhcmQgZGV2aWF0aW9uIG9mIHRoZSBwcmVkaWN0b3IuCgpgYGB7cn0KI1NlbmQgUEMgc2NvcmVzIHRvIHF0IGRhdGEgZnJhbWUsIHN0YW5kYXJkaXppbmcgdG8gc2Q9MQpxdCRQQzE8LXNjYWxlKFBDaW5kJERpbS4xKQpxdCRQQzI8LXNjYWxlKFBDaW5kJERpbS4yKQpxdCRQQzM8LXNjYWxlKFBDaW5kJERpbS4zKQojU3RhbmRhcmRpemUgQVIgYW5kIFdMLgpxdCRzQVI8LXNjYWxlKHF0JEFSKQpxdCRzV0w8LXNjYWxlKHF0JFdMKQpgYGAKCiMjIyMgUmVzcG9uc2Ugc3VyZmFjZSBtb2RlbHMgZm9yIG1pbmltdW0gcG93ZXIgcmVxdWlyZWQgdG8gZmx5IChQbWluKSBhcyByZXNwb25zZQoKTW9kZWxzIGZpdHRpbmcgUG1pbiBhcyByZXNwb25zZSwgU2V4LCBBUiBhbmQgV0wgYXMgcHJlZGljdG9ycy4gV2Ugc3RhcnRlZCBmaXR0aW5nIHRoZSBtb2RlbCBhcyBzZWNvbmQgb3JkZXIKCmBgYHtyfQpwd2F3LnJzbTwtcnNtKFBtaW5+U2V4K1NPKHNBUixzV0wpLGRhdGE9cXQpCmthYmxlcyhsaXN0KGthYmxlKCIqKkNvZWZmaWNpZW50cyoqIixjb2wubmFtZXM9TlVMTCksIGthYmxlKHN1bW1hcnkocHdhdy5yc20pJGNvZWZmaWNpZW50cyksa2FibGUoIioqQU5PVkEqKiIsY29sLm5hbWVzPU5VTEwpLCBrYWJsZShzdW1tYXJ5KHB3YXcucnNtKSRsb2YpKSwgY2FwdGlvbiA9ICIqKlRhYmxlIFMyLiBDb2VmZmljaWVudHMgYW5kIGFuYWx5c2lzIG9mIHZhcmlhbmNlIG9mIHJlc3BvbnNlIHN1cmZhY2UgbW9kZWwgd2l0aCBQbWluIGFzIHJlc3BvbnNlIGFuZCBTZXgsIEFSLCBhbmQgV0wgYXMgcHJlZGljdG9ycyoqIikKYGBgCgpNb2RlbCBzdW1tYXJ5IGNvZWZmaWNpZW50cyBhbmQgYW5hbHlzaXMgb2YgdmFyaWFuY2UgaW5kaWNhdGUgYSBxdWFkcmF0aWMgY29tcG9uZW50LCBzbyBzZWNvbmQgb3JkZXIgbW9kZWwgaXMgcmV0YWluZWQuIFNleCBpcyByZW1vdmVkIGZyb20gdGhlIG1vZGVsLiBJdCBtaWdodCBiZSBjb2xsaW5lYXIgd2l0aCBXTC4KCmBgYHtyfQpwd2F3LnJzbTI8LXJzbShQbWluflNPKHNBUixzV0wpLGRhdGE9cXQpCmthYmxlcyhsaXN0KGthYmxlKCIqKkNvZWZmaWNpZW50cyoqIiwgY29sLm5hbWVzPU5VTEwpLCBrYWJsZShzdW1tYXJ5KHB3YXcucnNtMikkY29lZmZpY2llbnRzKSxrYWJsZSgiKipBTk9WQSoqIixjb2wubmFtZXM9TlVMTCksIGthYmxlKHN1bW1hcnkocHdhdy5yc20yKSRsb2YpKSwgY2FwdGlvbiA9ICIqKlRhYmxlIFMzLiBDb2VmZmljaWVudHMgYW5kIGFuYWx5c2lzIG9mIHZhcmlhbmNlIG9mIHJlc3BvbnNlIHN1cmZhY2UgbW9kZWwgd2l0aCBQbWluIGFzIHJlc3BvbnNlIGFuZCBBUiBhbmQgV0wgYXMgcHJlZGljdG9ycyoqIikKYGBgCgpDaGVjayBtb2RlbCByZXNpZHVhbHMgZm9yIHRyZW5kcyAobm8gdHJlbmRzIG9ic2VydmVkKQoKYGBge3J9CnBsb3QocHJlZGljdChwd2F3LnJzbTIpLHJlc2lkKHB3YXcucnNtMikseGxhYj0iUHJlZGljdGVkIix5bGFiID0gIlJlc2lkdWFscyIpCmBgYAoKTW9kZWxzIGZpdHRpbmcgUG1pbiBhcyByZXNwb25zZSwgU2V4IGFuZCBQQyBzY29yZXMgYXMgcHJlZGljdG9ycy4gV2Ugc3RhcnRlZCBmaXR0aW5nIG1vZGVsIGFzIHNlY29uZCBvcmRlciwgaW5jbHVkaW5nIHRoZSBmaXJzdCB0aHJlZSBQQ3M6CgpgYGB7cn0KcHdwYy5yc208LXJzbShQbWluflNleCtTTyhQQzEsUEMyLFBDMyksZGF0YT1xdCkKa2FibGVzKGxpc3Qoa2FibGUoIioqQ29lZmZpY2llbnRzKioiLCBjb2wubmFtZXM9TlVMTCksIGthYmxlKHN1bW1hcnkocHdwYy5yc20pJGNvZWZmaWNpZW50cyksa2FibGUoIioqQU5PVkEqKiIsY29sLm5hbWVzPU5VTEwpLCBrYWJsZShzdW1tYXJ5KHB3cGMucnNtKSRsb2YpKSwgY2FwdGlvbiA9ICIqKlRhYmxlIFM0LiBDb2VmZmljaWVudHMgYW5kIGFuYWx5c2lzIG9mIHZhcmlhbmNlIG9mIHJlc3BvbnNlIHN1cmZhY2UgbW9kZWwgd2l0aCBQbWluIGFzIHJlc3BvbnNlIGFuZCBTZXggYW5kIFBDIHNjb3JlcyBhcyBwcmVkaWN0b3JzKioiKQpgYGAKCk1vZGVsIHN1bW1hcnkgY29lZmZpY2llbnRzIGFuZCB0aGUgYW5hbHlzaXMgb2YgdmFyaWFuY2UgaW5kaWNhdGUgYSBxdWFkcmF0aWMgY29tcG9uZW50LCBzbyB0aGUgc2Vjb25kIG9yZGVyIG1vZGVsIGlzIHJldGFpbmVkLiBQQzMgZGlkIG5vdCBjb250cmlidXRlIHRvIHN1cmZhY2UgKGNvZWZmaWNpZW50cyBub3Qgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCksIHNvIGl0IHdhcyBleGNsdWRlZC4KCmBgYHtyfQpwd3BjLnJzbTI8LXJzbShQbWluflNleCtTTyhQQzEsUEMyKSxkYXRhPXF0KQprYWJsZXMobGlzdChrYWJsZSgiKipDb2VmZmljaWVudHMqKiIsIGNvbC5uYW1lcz1OVUxMKSwga2FibGUoc3VtbWFyeShwd3BjLnJzbTIpJGNvZWZmaWNpZW50cyksa2FibGUoIioqQU5PVkEqKiIsY29sLm5hbWVzPU5VTEwpLCBrYWJsZShzdW1tYXJ5KHB3cGMucnNtMikkbG9mKSksIGNhcHRpb24gPSAiKipUYWJsZSBTNS4gQ29lZmZpY2llbnRzIGFuZCBhbmFseXNpcyBvZiB2YXJpYW5jZSBvZiByZXNwb25zZSBzdXJmYWNlIG1vZGVsIHdpdGggUG1pbiBhcyByZXNwb25zZSBhbmQgUEMgc2NvcmVzIGFzIHByZWRpY3RvcnMqKiIpCmBgYAoKQ2hlY2sgbW9kZWwgcmVzaWR1YWxzIGZvciB0cmVuZHMgKG5vIHRyZW5kcyBvYnNlcnZlZCkKCmBgYHtyfQpwbG90KHByZWRpY3QocHdwYy5yc20yKSxyZXNpZChwd3BjLnJzbTIpLHhsYWI9IlByZWRpY3RlZCIseWxhYiA9ICJSZXNpZHVhbHMiKQpgYGAKCiMjIyMgUmVzcG9uc2Ugc3VyZmFjZSBtb2RlbHMgZm9yIGhlYXQgbG9zcyAoUXQpIGFzIHJlc3BvbnNlCgpNb2RlbHMgZml0dGluZyBRdCBhcyByZXNwb25zZSwgU2V4LCBBUiBhbmQgV0wgYXMgcHJlZGljdG9ycy4gV2Ugc3RhcnRlZCBmaXR0aW5nIG1vZGVsIGFzIHNlY29uZCBvcmRlcgoKYGBge3J9CnF0YXcucnNtPC1yc20oUXR+U2V4K1NPKHNXTCxzQVIpLGRhdGE9cXQpCmthYmxlcyhsaXN0KGthYmxlKCIqKkNvZWZmaWNpZW50cyoqIiwgY29sLm5hbWVzPU5VTEwpLCBrYWJsZShzdW1tYXJ5KHF0YXcucnNtKSRjb2VmZmljaWVudHMpLGthYmxlKCIqKkFOT1ZBKioiLGNvbC5uYW1lcz1OVUxMKSwga2FibGUoc3VtbWFyeShxdGF3LnJzbSkkbG9mKSksIGNhcHRpb24gPSAiKipUYWJsZSBTNi4gQ29lZmZpY2llbnRzIGFuZCBhbmFseXNpcyBvZiB2YXJpYW5jZSBvZiByZXNwb25zZSBzdXJmYWNlIG1vZGVsIHdpdGggUXQgYXMgcmVzcG9uc2UgYW5kIFNleCwgQVIsIGFuZCBXTCBhcyBwcmVkaWN0b3JzKioiKQpgYGAKCk1vZGVsIHN1bW1hcnkgY29lZmZpY2llbnRzIGFuZCB0aGUgYW5hbHlzaXMgb2YgdmFyaWFuY2UgZG8gbm90IHN1cHBvcnQgc2V4IG9yIGEgcXVhZHJhdGljIGNvbXBvbmVudCwgc28gZmlyc3Qgb3JkZXIgKGxpbmVhcikgbW9kZWwgaXMgcmV0YWluZWQKCmBgYHtyfQpxdGF3LnJzbTI8LXJzbShRdH5GTyhzV0wsc0FSKSxkYXRhPXF0KQprYWJsZXMobGlzdChrYWJsZSgiKipDb2VmZmljaWVudHMqKiIsIGNvbC5uYW1lcz1OVUxMKSwga2FibGUoc3VtbWFyeShxdGF3LnJzbTIpJGNvZWZmaWNpZW50cyksa2FibGUoIioqQU5PVkEqKiIsY29sLm5hbWVzPU5VTEwpLCBrYWJsZShzdW1tYXJ5KHF0YXcucnNtMikkbG9mKSksIGNhcHRpb24gPSAiKipUYWJsZSBTNy4gQ29lZmZpY2llbnRzIGFuZCBhbmFseXNpcyBvZiB2YXJpYW5jZSBvZiByZXNwb25zZSBzdXJmYWNlIG1vZGVsIHdpdGggUXQgYXMgcmVzcG9uc2UsIEFSIGFuZCBXTCBhcyBwcmVkaWN0b3JzKioiKQpgYGAKCkNoZWNraW5nIHJlc2lkdWFscyAobm8gdHJlbmRzIG9ic2VydmVkKQoKYGBge3J9CnBsb3QocHJlZGljdChxdGF3LnJzbTIpLHJlc2lkKHF0YXcucnNtMikseGxhYiA9ICJQcmVkaWN0ZWQiLCB5bGFiID0gIlJlc2lkdWFscyIpCmBgYAoKRml0dGluZyBRdCBhcyByZXNwb25zZSwgUEMgc2NvcmVzIGFzIHByZWRpY3RvcnMuIEZpcnN0LCBmaXR0aW5nIG1vZGVsIGFzIHNlY29uZCBvcmRlciByZXNwb25zZToKCmBgYHtyfQpxdHBjLnJzbTwtcnNtKFF0flNleCtTTyhQQzEsUEMyLFBDMyksZGF0YT1xdCkKa2FibGVzKGxpc3Qoa2FibGUoIioqQ29lZmZpY2llbnRzKioiLCBjb2wubmFtZXM9TlVMTCksIGthYmxlKHN1bW1hcnkocXRwYy5yc20pJGNvZWZmaWNpZW50cyksa2FibGUoIioqQU5PVkEqKiIsY29sLm5hbWVzPU5VTEwpLCBrYWJsZShzdW1tYXJ5KHF0cGMucnNtKSRsb2YpKSwgY2FwdGlvbiA9ICIqKlRhYmxlIFM4LiBDb2VmZmljaWVudHMgYW5kIGFuYWx5c2lzIG9mIHZhcmlhbmNlIG9mIHJlc3BvbnNlIHN1cmZhY2UgbW9kZWwgd2l0aCBRdCBhcyByZXNwb25zZSBhbmQgU2V4IGFuZCBQQyBzY29yZXMgYXMgcHJlZGljdG9ycyoqIikKYGBgCgpNb2RlbCBzdW1tYXJ5IGNvZWZmaWNpZW50cyBhbmQgdGhlIGFuYWx5c2lzIG9mIHZhcmlhbmNlIGRvIG5vdCBzdXBwb3J0IGEgcXVhZHJhdGljIGNvbXBvbmVudCwgc28gZmlyc3Qgb3JkZXIgbW9kZWwgaXMgcmV0YWluZWQuIFNleCBhbmQgUEMzIGRpZCBub3QgY29udHJpYnV0ZSB0byBzdXJmYWNlIChjb2VmZmljaWVudHMgbm90IHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQpLCBzbyB0aGV5IHdlcmUgZXhjbHVkZWQgZnJvbSB0aGUgbW9kZWwuCgpgYGB7cn0KcXRwYy5yc20yPC1yc20oUXR+Rk8oUEMxLFBDMiksZGF0YT1xdCkKa2FibGVzKGxpc3Qoa2FibGUoIioqQ29lZmZpY2llbnRzKioiLCBjb2wubmFtZXM9TlVMTCksIGthYmxlKHN1bW1hcnkocXRwYy5yc20yKSRjb2VmZmljaWVudHMpLGthYmxlKCIqKkFOT1ZBKioiLGNvbC5uYW1lcz1OVUxMKSwga2FibGUoc3VtbWFyeShxdHBjLnJzbTIpJGxvZikpLCBjYXB0aW9uID0gIioqVGFibGUgUzkuIENvZWZmaWNpZW50cyBhbmQgYW5hbHlzaXMgb2YgdmFyaWFuY2Ugb2YgcmVzcG9uc2Ugc3VyZmFjZSBtb2RlbCB3aXRoIFF0IGFzIHJlc3BvbnNlIGFuZCBQQyBzY29yZXMgYXMgcHJlZGljdG9ycyoqIikKYGBgCgpDaGVja2luZyByZXNpZHVhbHMgKG5vIHRyZW5kcyBvYnNlcnZlZCkKCmBgYHtyfQpwbG90KHByZWRpY3QocXRwYy5yc20yKSxyZXNpZChxdHBjLnJzbTIpLHhsYWIgPSAiUHJlZGljdGVkIiwgeWxhYiA9ICJSZXNpZHVhbHMiKQpgYGAKCiMjIyBQbG90dGluZyByZXNwb25zZSBzdXJmYWNlIG1vZGVscwoKR2VuZXJhdGUgbmV3IHZhcmlhYmxlcyB0byBwcmVkaWN0IHN1cmZhY2UKCmBgYHtyfQojQ3JlYXRlIG5ldyBkYXRhc2V0IGJhc2VkIG9uIG1pbiBtYXggQVIgYW5kIFdMIHRvIHByZWRpY3QgcnNtLiBFeHBhbmRlZCBncmlkIHdpdGggNTAgcG9pbnRzCm5ld0FXPC1leHBhbmQuZ3JpZChzQVI9c2VxKC0yLjMwLDIuNTcsbGVuZ3RoLm91dCA9IDUwKSxzV0w9c2VxKC0xLjc5LDIuNTQsbGVuZ3RoLm91dCA9IDUwKSkKI0NhbGN1bGF0ZSBwcmVkaWN0aW9ucwpuZXdBVyRQbWluPC1wcmVkaWN0KHB3YXcucnNtMixuZXdBVykKI0NyZWF0ZSBuZXcgbnVtZXJpYyB2ZWN0b3IgdG8gcGxvdCBzZXggYXMgZGlmZmVyZW50IHNoYXBlcwpTZXhwY2gyPC1jKDEsMilbYXMubnVtZXJpYyhxdCRTZXgpXQojQ3JlYXRlIG5ldyBkYXRhc2V0IGJhc2VkIG9uIG1pbiBtYXggUEMgc2NvcmVzIHRvIHByZWRpY3QgcnNtLiBFeHBhbmRlZCBncmlkIHdpdGggNTAgcG9pbnRzCm5ld1BDPC1leHBhbmQuZ3JpZChQQzE9c2VxKC0yLjQ3LDIuMzAsbGVuZ3RoLm91dCA9IDUwKSxQQzI9c2VxKC0yLjUwLDIuODAsbGVuZ3RoLm91dCA9IDUwKSkKI0NhbGN1bGF0ZSBwcmVkaWN0aW9ucyBmb3IgbWFsZXMKbmV3UENNPC1uZXdQQwpuZXdQQ00kU2V4PC1yZXAoIk0iLDI1MDApCm5ld1BDTSRQbWluPC1wcmVkaWN0KHB3cGMucnNtMixuZXdQQ00pCiNDYWxjdWxhdGUgcHJlZGljdGlvbnMgZm9yIGZlbWFsZXMKbmV3UENGPC1uZXdQQwpuZXdQQ0YkU2V4PC1yZXAoIkYiLDI1MDApCm5ld1BDRiRQbWluPC1wcmVkaWN0KHB3cGMucnNtMixuZXdQQ0YpCiNDYWxjdWxhdGUgYXZlcmFnZSBwcmVkaWN0aW9uCm5ld1BDJFBtaW48LXJvdW5kKChuZXdQQ0YkUG1pbituZXdQQ00kUG1pbikvMixkaWdpdHM9NSkKI0NhbGN1bGF0ZSBwcmVkaWN0aW9ucyBmb3IgUXQgbW9kZWxzCm5ld0FXJFF0PC1wcmVkaWN0KHF0YXcucnNtMixuZXdBVykKbmV3UEMkUXQ8LXByZWRpY3QocXRwYy5yc20yLG5ld1BDKQpgYGAKCkdlbmVyYXRlIGNvbnRvdXIgcGxvdCBmb3Igc3VyZmFjZS4gTWluaW11bSBwb3dlciByZXF1aXJlZCB0byBmbHkgaXMgdGhlIHJlc3BvbnNlLCBhc3BlY3QgcmF0aW8gYW5kIHdpbmcgbG9hZGluZyBhcmUgcHJlZGljdG9ycwoKYGBge3J9CmdncGxvdChuZXdBVywgYWVzKHNXTCxzQVIsIHogPSBQbWluKSkrCiAgbGFicyh5PSJTdGFuZGFyZGl6ZWQgQXNwZWN0IFJhdGlvIiwgeD0iU3RhbmRhcmRpemVkIFdpbmcgTG9hZGluZyIpKwogIGNvb3JkX2NhcnRlc2lhbih4bGltPWMoLTEuNjQsMi4zOSksIHlsaW09YygtMi4xMywyLjQwKSkrCiAgZ2VvbV9yYXN0ZXIoYWVzKGZpbGwgPSBQbWluKSkrCiAgZ2VvbV9jb250b3VyKGNvbG91ciA9ICJibGFjayIpKwogIGdlb21fdGV4dF9jb250b3VyKGFlcyh6ID0gUG1pbiksIG51ZGdlX3ggPSAwLG51ZGdlX3kgPSAwLCBjb2xvdXI9ImJsYWNrIixzaXplPTYsYnJlYWtzPXNlcSgwLjA1LDAuMSxieT0wLjAxKSkrCiAgc2NhbGVfZmlsbF9ncmFkaWVudG4oY29sb3Vycz1jKCJyZWQiLCJ5ZWxsb3ciKSkrCiAgZ2VvbV9wb2ludChkYXRhPXF0LHNpemU9NCxzaGFwZT1TZXhwY2gyLG1hcHBpbmc9YWVzKHg9c1dMLHk9c0FSKSkrCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT1yZWwoNC41KSkscGFuZWwuYm9yZGVyPWVsZW1lbnRfcmVjdChsaW5ldHlwZT0ic29saWQiLGZpbGw9TkEpKQpgYGAKCkdlbmVyYXRlIGNvbnRvdXIgcGxvdCBmb3Igc3VyZmFjZS4gTWluaW11bSBwb3dlciByZXF1aXJlZCB0byBmbHkgaXMgdGhlIHJlc3BvbnNlLCBQQyBzY29yZXMgYXJlIHByZWRpY3RvcnMKCmBgYHtyfQpnZ3Bsb3QobmV3UEMsIGFlcyhQQzEsUEMyLCB6ID0gUG1pbikpKwogIGxhYnMoeT0iU3RhbmRhcmRpemVkIFBDMiIsIHg9IlN0YW5kYXJkaXplZCBQQzEiKSsKICBjb29yZF9jYXJ0ZXNpYW4oeGxpbT1jKC0yLjI5NSwyLjEzKSwgeWxpbT1jKC0yLjMyLDIuNjIpKSsKICBnZW9tX3Jhc3RlcihhZXMoZmlsbCA9IFBtaW4pKSsKICBnZW9tX2NvbnRvdXIoY29sb3VyID0gImJsYWNrIikrCiAgZ2VvbV90ZXh0X2NvbnRvdXIoYWVzKHogPSBQbWluKSwgbnVkZ2VfeCA9IDAsbnVkZ2VfeSA9IDAsIGNvbG91cj0iYmxhY2siLHNpemU9NixicmVha3M9c2VxKDAuMDU4LDAuMDcyLGJ5PTAuMDAyKSkrCiAgc2NhbGVfZmlsbF9ncmFkaWVudG4oY29sb3Vycz1jKCJyZWQiLCJ5ZWxsb3ciKSkrCiAgZ2VvbV9wb2ludChkYXRhPXF0LHNpemU9NCxzaGFwZT1TZXhwY2gyLG1hcHBpbmc9YWVzKHg9UEMxLHk9UEMyKSkrCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT1yZWwoNC41KSkscGFuZWwuYm9yZGVyPWVsZW1lbnRfcmVjdChsaW5ldHlwZT0ic29saWQiLGZpbGw9TkEpKQpgYGAKCkdlbmVyYXRlIGNvbnRvdXIgcGxvdCBmb3Igc3VyZmFjZS4gSGVhdCBsb3NzIChRdCkgaXMgdGhlIHJlc3BvbnNlLCBhc3BlY3QgcmF0aW8gYW5kIHdpbmcgbG9hZGluZyBhcmUgcHJlZGljdG9ycwoKYGBge3J9CmdncGxvdChuZXdBVywgYWVzKHNXTCxzQVIsIHogPSBRdCkpKwogIGxhYnMoeT0iU3RhbmRhcmRpemVkIEFzcGVjdCBSYXRpbyIsIHg9IlN0YW5kYXJkaXplZCBXaW5nIExvYWRpbmciKSsKICBjb29yZF9jYXJ0ZXNpYW4oeGxpbT1jKC0xLjY0LDIuMzkpLCB5bGltPWMoLTIuMTMsMi40MCkpKwogIGdlb21fcmFzdGVyKGFlcyhmaWxsID0gUXQpKSsKICBnZW9tX2NvbnRvdXIoY29sb3VyID0gImJsYWNrIikrCiAgZ2VvbV90ZXh0X2NvbnRvdXIoYWVzKHogPSBRdCksIG51ZGdlX3ggPSAwLG51ZGdlX3kgPSAwLCBjb2xvdXI9ImJsYWNrIixzaXplPTYpKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKGNvbG91cnM9YygicmVkIiwieWVsbG93IikpKwogIGdlb21fcG9pbnQoZGF0YT1xdCxzaXplPTQsc2hhcGU9U2V4cGNoMixtYXBwaW5nPWFlcyh4PXNXTCx5PXNBUikpKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIix0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9cmVsKDQuNSkpLHBhbmVsLmJvcmRlcj1lbGVtZW50X3JlY3QobGluZXR5cGU9InNvbGlkIixmaWxsPU5BKSkKYGBgCgpHZW5lcmF0ZSBjb250b3VyIHBsb3QgZm9yIHN1cmZhY2UuIEhlYXQgbG9zcyAoUXQpIGlzIHRoZSByZXNwb25zZSwgUEMgc2NvcmVzIGFyZSBwcmVkaWN0b3JzCgpgYGB7cn0KZ2dwbG90KG5ld1BDLCBhZXMoUEMxLFBDMiwgeiA9IFF0KSkrCiAgbGFicyh5PSJTdGFuZGFyZGl6ZWQgUEMyIiwgeD0iU3RhbmRhcmRpemVkIFBDMSIpKwogIGNvb3JkX2NhcnRlc2lhbih4bGltPWMoLTIuMjksMi4xMyksIHlsaW09YygtMi4zMiwyLjYzKSkrCiAgZ2VvbV9yYXN0ZXIoYWVzKGZpbGwgPSBRdCkpKwogIGdlb21fY29udG91cihjb2xvdXIgPSAiYmxhY2siKSsKICBnZW9tX3RleHRfY29udG91cihhZXMoeiA9IFF0KSwgbnVkZ2VfeCA9IDAsIG51ZGdlX3kgPSAwLCBjb2xvdXI9ImJsYWNrIixzaXplPTYpKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKGNvbG91cnM9YygicmVkIiwieWVsbG93IikpKwogIGdlb21fcG9pbnQoZGF0YT1xdCxzaXplPTQsc2hhcGU9U2V4cGNoMixtYXBwaW5nPWFlcyh4PVBDMSx5PVBDMikpKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIix0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9cmVsKDQuNSkpLHBhbmVsLmJvcmRlcj1lbGVtZW50X3JlY3QobGluZXR5cGU9InNvbGlkIixmaWxsPU5BKSkKYGBgCg==