By: Adam Rivers

July 2019


Research challenge

Frost damage costs American farmers more than any other weather hazard. In annual crops early frost can kill seedlings and late frost can damage fruits and grains before harvest. The best information available on frost-free dates comes from the 30-year climatological average frost-free dates published by the National Oceanographic and Atmospheric admiration and updated every decade. The current NOAA frost-free data represent a historical average centered on the year 1995. Unfortunately, the global temperature has risen 0.59°C since 1995. There is also some evidence of increased variability in frost dates, which is critically important for mitigating risk in planting decisions. Work has been done modeling frost free-dates in the 50-100 year time horizon. There is a critical need for accurate predictions of the timing and probability of frost for the next planting season.

Objective

The Postdoc will develop a predictive model of frost-free dates and probabilities for future growing seasons. The data will be disseminated to the public through an interactive web application.

National program and objective:

NP 301: Plant Genetic Resources, Genomics and Genetics Improvement; Components

Approach

Data for the model will come from the National Oceanographic and Atmospheric Administration (NOAA). Specifically, US Daily Climate Normal Data a will be supplemented with data from the Local Climatological Dataset and homogeneity corrected using software developed by NOAA for the US Historical Climatology Network. The postdoc will develop Bayesian generalized mixed models with geospatial smoothing to create robust estimates of the frost-free dates and variability.


Preliminary analysis

A quick pilot analysis was done for this proposal to estimate the magnitude of change in frost free dates. NOAA Daily Climate Normal data set from 1951-2010 was used to analyze the frost-free dates at 5,134 stations where frost occurred every year. This data differs from the more accurate data set used for calculating the NOAA climate normals. That data set applied homogeneity correction to account for systemic changes (urbanization, station moves etc.).The frost free date climate normals are not simple means but are calculated by a bootstrapping approach that samples across years and before and after the observed frost free date. This is a state-of-the-art method but it is designed to calculate the mean and variance of the frost free dates assuming the data are not trended. Key findings from the preliminary data are:

Preliminary findings

  1. There is a strong regional difference in the timing of frost free dates, with the east showing earlier spring dates and later fall dates (see maps below).
  2. The average station is predicted to have frost free dates 3 days earlier in the spring and and 6 days later the fall of 2020 than it did on average over the period 1981-2020 with local station changes as large as 2-3 weeks.
  3. Increased variability in frost free dates has been was hypothesized, but that was not a common occurrence in most regions.
  4. Aggregated national trends mask these changes because a shortened western growing season offsets a lengthened eastern growing season.

Next steps

  1. A more sophisticated model incorporating bootstrapping and estimator shrinkage should be done to improve the accuracy of the model at the station level
  2. The underling data should be homogeneity corrected.
  3. Data from 2010 to 2019 should be added.
  4. An empirical model testing framework that evaluates model error should be developed.
  5. A web application for understanding accessing and understanding the data needs to be designed.

Source data

The source data set used in the analysis is the Daily Filled Adjusted Tmin data spanning 1951-2010. Data were downloaded from ftp://ftp.ncdc.noaa.gov/pub/data/normals/1981-2010/supplemental/source-datasets/daily-filled-adjusted-tmin.dat.gz. Data were initially parsed in Python to create the spring and fall Tmin data containing just the first and last dates of each year where the temperature fell below 0ºC every year.

# Setup
library(tidyverse)
library(reshape2)
setwd("~/Documents/frost_free/")
dates <- seq(1981,2010)

Import spring data

spring <- read.table("spring.csv", sep=",", header=T)
rownames(spring)<-spring$X
spring<- spring[,-1]
filteredspring <- spring %>% drop_na() 

Import fall data

fall <- read.table("fall.csv", sep=",", header=T)
rownames(fall)<-fall$X
fall<- fall[,-1]

filteredfall <- fall %>% drop_na() 

Looking at trend patterns of individual stations

General trends do not show a lot but it is possible that these trends are larger at specific sites. The next step is to look at trends across individual stations. we fit a GLM for each station time series and look at the distribution of slopes and predicted frost free dates based on the models.

Looking for regional differences

allstations <-read.table("allstations-clean.txt", header=F, sep="\t")
springloc <- merge(spring2020gap, allstations, by.x="row.names", by.y="V1")
library(ggmap)
library(maps)
library(mapdata)
bc_bbox <- make_bbox(lat = V2, lon = V3, data = springloc)
bc_big <- get_map(location = bc_bbox, source = "google", maptype = "terrain-background")
maptype = "terrain-background" is only available with source = "stamen".
resetting to source = "stamen"...
ggmap(bc_big) + 
  geom_point(data = springloc, mapping = aes(x = V3, y = V2, color = -pdate), size=0.9) + scale_colour_gradient2(trans="pseudo_log") +
  ggtitle("Predicted change in spring frost free date in 2020 versus mean from 1981-2010")

allstations <-read.table("allstations-clean.txt", header=F, sep="\t")
fallloc <- merge(fall2020gap, allstations, by.x="row.names", by.y="V1")
library(ggmap)
library(maps)
library(mapdata)
bc_bbox <- make_bbox(lat = V2, lon = V3, data = fallloc)
bc_big <- get_map(location = bc_bbox, source = "google", maptype = "terrain-background",color="bw")
maptype = "terrain-background" is only available with source = "stamen".
resetting to source = "stamen"...
ggmap(bc_big) + 
  geom_point(data = fallloc, mapping = aes(x = V3, y = V2, color = pdate), size=0.9) + scale_colour_gradient2(trans="pseudo_log") +
  ggtitle("Predicted change in fall frost free date in 2020 versus mean from 1981-2010")

Conclusions about regional data

There do seem to be strong regional trends in the Changes in frost free dates, with strong warming in the Southeast.

Changes in variance

The variability of Frost dates is also an important factor to mitigating the risk of frost damage to crops. To analyze that we take the de-trended data (residuals) from the GLM at each site and apply a test for equality of variances for the periods 1981-1995 and 1996-2010.


spring_res <-  apply(x, 2, function(x.col) residuals(glm(x.col ~ dates, na.action=na.omit)))
springvr <- (apply(spring_res, 2, function(spring_res.col) (var.test(spring_res.col[1:15],spring_res.col[16:30], alternative="greater"))$estimate ))
ggplot(data.frame(springvr), aes(x=log(springvr,2))) + geom_histogram(bins=60) + 
geom_vline(aes(xintercept=mean(log(springvr, 2))), color="blue", linetype="dashed", size=1) +
xlab("Variance ratio") + ylab("Count") + ggtitle("Variance log 2 ratio for de-trended data from  1981-1995 and 1996-2010")

springpval <- (apply(spring_res, 2, function(spring_res.col) (var.test(spring_res.col[1:15],spring_res.col[16:30], alternative="two.sided"))$p.value))
spv.df<-data.frame(springpval)
spv.df$stations <- rownames(spv.df)
sig.stations <-spv.df[spv.df$springpval<0.05,]
# Most stations had sigifigantly greater variation in the later period
springvar <- merge(data.frame(springvr), allstations, by.x="row.names", by.y="V1")
springvarandp <- merge(springvar,sig.stations, by.x="Row.names", by.y="stations")
ggmap(bc_big) + 
  geom_point(data = springvarandp, mapping = aes(x = V3, y = V2, color = log(springvr,2)), size=2) + scale_colour_gradient2() +
  ggtitle("Stations with statistically significant changes in log variance ratios between 1981-1995 and 1996-2010")

ggmap(bc_big) + 
  geom_point(data = springvar, mapping = aes(x = V3, y = V2, color = log(springvr,2)), size=0.9) + scale_colour_gradient2()+
  ggtitle("Log variance ratios between 1981-1995 and 1996-2010")

Conclusions on variance

There does not appear to be a strong shift in variance when comparing de-trended data from 1981-1995 and 1996-2010. There are some regional patterns in the minor shift observed. Potential artifacts driving (such as poorer fit for one period) need to be investigated before any stronger conclusion can be made.

General conclusions

There may be regionally important shifts in the timing of frost free dates by up to several weeks. These preliminary methods need to be confirmed using bootstrapping methods, to minimize the stochastic nature of “last event” data like frost free days. Developing models for local stations rather than large scale trends will require methods like bootstrapping and shrinkage to reduce variability. Finally, models developed need to be evaluated for their error in cross-fold test /train validation experiments and the data needs to be made available in a user-freindly web application.

LS0tCnRpdGxlOiAiRXhwbG9yaW5nIHRoZSBuZWVkIGZvciBhIHByZWRpY3RpdmUgZnJvc3QtZnJlZSBkYXRlIG1vZGVsIGFuZCB3ZWIgYXBwbGljYXRpb24gdG8gaW1wcm92ZSBwbGFudGluZyBkZWNpc2lvbnMiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KIyMjIEJ5OiBBZGFtIFJpdmVycwojIyMgSnVseSAyMDE5CgoqKiogCgojIFJlc2VhcmNoIGNoYWxsZW5nZQoKRnJvc3QgZGFtYWdlIGNvc3RzIEFtZXJpY2FuIGZhcm1lcnMgbW9yZSB0aGFuIGFueSBvdGhlciB3ZWF0aGVyIGhhemFyZC4gSW4gYW5udWFsIGNyb3BzIGVhcmx5IGZyb3N0IGNhbiBraWxsIHNlZWRsaW5ncyBhbmQgbGF0ZSBmcm9zdCBjYW4gZGFtYWdlIGZydWl0cyBhbmQgZ3JhaW5zIGJlZm9yZSBoYXJ2ZXN0LiBUaGUgYmVzdCBpbmZvcm1hdGlvbiBhdmFpbGFibGUgb24gZnJvc3QtZnJlZSBkYXRlcyBjb21lcyBmcm9tIHRoZSAzMC15ZWFyIGNsaW1hdG9sb2dpY2FsIGF2ZXJhZ2UgZnJvc3QtZnJlZSBkYXRlcyBwdWJsaXNoZWQgYnkgdGhlIE5hdGlvbmFsIE9jZWFub2dyYXBoaWMgYW5kIEF0bW9zcGhlcmljIGFkbWlyYXRpb24gYW5kIHVwZGF0ZWQgZXZlcnkgZGVjYWRlLiBUaGUgY3VycmVudCBOT0FBIGZyb3N0LWZyZWUgZGF0YSByZXByZXNlbnQgYSBoaXN0b3JpY2FsIGF2ZXJhZ2UgY2VudGVyZWQgb24gdGhlIHllYXIgMTk5NS4gVW5mb3J0dW5hdGVseSwgdGhlIGdsb2JhbCB0ZW1wZXJhdHVyZSBoYXMgcmlzZW4gMC41OcKwQyBzaW5jZSAxOTk1LiBUaGVyZSBpcyBhbHNvIHNvbWUgZXZpZGVuY2Ugb2YgaW5jcmVhc2VkIHZhcmlhYmlsaXR5IGluIGZyb3N0IGRhdGVzLCB3aGljaCBpcyBjcml0aWNhbGx5IGltcG9ydGFudCBmb3IgbWl0aWdhdGluZyByaXNrIGluIHBsYW50aW5nIGRlY2lzaW9ucy4gIFdvcmsgaGFzIGJlZW4gZG9uZSBtb2RlbGluZyBmcm9zdCBmcmVlLWRhdGVzIGluIHRoZSA1MC0xMDAgeWVhciB0aW1lIGhvcml6b24uIFRoZXJlIGlzIGEgY3JpdGljYWwgbmVlZCBmb3IgYWNjdXJhdGUgcHJlZGljdGlvbnMgb2YgdGhlIHRpbWluZyBhbmQgcHJvYmFiaWxpdHkgb2YgZnJvc3QgZm9yIHRoZSBuZXh0IHBsYW50aW5nIHNlYXNvbi4gCgojIE9iamVjdGl2ZQoKVGhlIFBvc3Rkb2Mgd2lsbCBkZXZlbG9wIGEgcHJlZGljdGl2ZSBtb2RlbCBvZiBmcm9zdC1mcmVlIGRhdGVzIGFuZCBwcm9iYWJpbGl0aWVzIGZvciBmdXR1cmUgZ3Jvd2luZyBzZWFzb25zLiBUaGUgZGF0YSB3aWxsIGJlIGRpc3NlbWluYXRlZCB0byB0aGUgcHVibGljIHRocm91Z2ggYW4gaW50ZXJhY3RpdmUgd2ViIGFwcGxpY2F0aW9uLgoKIyBOYXRpb25hbCBwcm9ncmFtIGFuZCBvYmplY3RpdmU6IAoKTlAgMzAxOiBQbGFudCBHZW5ldGljIFJlc291cmNlcywgR2Vub21pY3MgYW5kIEdlbmV0aWNzIEltcHJvdmVtZW50OyBDb21wb25lbnRzCgojIEFwcHJvYWNoCgpEYXRhIGZvciB0aGUgbW9kZWwgd2lsbCBjb21lIGZyb20gdGhlIE5hdGlvbmFsIE9jZWFub2dyYXBoaWMgYW5kIEF0bW9zcGhlcmljIEFkbWluaXN0cmF0aW9uIChOT0FBKS4gU3BlY2lmaWNhbGx5LCBVUyBEYWlseSBDbGltYXRlIE5vcm1hbCBEYXRhIGEgd2lsbCBiZSBzdXBwbGVtZW50ZWQgd2l0aCBkYXRhIGZyb20gdGhlIExvY2FsIENsaW1hdG9sb2dpY2FsIERhdGFzZXQgYW5kIGhvbW9nZW5laXR5IGNvcnJlY3RlZCB1c2luZyBzb2Z0d2FyZSBkZXZlbG9wZWQgYnkgTk9BQSBmb3IgdGhlIFVTIEhpc3RvcmljYWwgQ2xpbWF0b2xvZ3kgTmV0d29yay4gIFRoZSBwb3N0ZG9jIHdpbGwgZGV2ZWxvcCBCYXllc2lhbiBnZW5lcmFsaXplZCBtaXhlZCBtb2RlbHMgd2l0aCBnZW9zcGF0aWFsIHNtb290aGluZyB0byBjcmVhdGUgcm9idXN0IGVzdGltYXRlcyBvZiB0aGUgZnJvc3QtZnJlZSBkYXRlcyBhbmQgdmFyaWFiaWxpdHkuIAoKKioqIAoKIyBQcmVsaW1pbmFyeSBhbmFseXNpcwoKQSBxdWljayBwaWxvdCBhbmFseXNpcyB3YXMgZG9uZSBmb3IgdGhpcyBwcm9wb3NhbCB0byBlc3RpbWF0ZSB0aGUgbWFnbml0dWRlIG9mIGNoYW5nZSBpbiBmcm9zdCBmcmVlIGRhdGVzLiBOT0FBIERhaWx5IENsaW1hdGUgTm9ybWFsIGRhdGEgc2V0IGZyb20gMTk1MS0yMDEwIHdhcyB1c2VkIHRvIGFuYWx5emUgdGhlIGZyb3N0LWZyZWUgZGF0ZXMgYXQgNSwxMzQgc3RhdGlvbnMgd2hlcmUgZnJvc3Qgb2NjdXJyZWQgZXZlcnkgeWVhci4gVGhpcyBkYXRhIGRpZmZlcnMgZnJvbSB0aGUgbW9yZSBhY2N1cmF0ZSBkYXRhIHNldCB1c2VkIGZvciBjYWxjdWxhdGluZyB0aGUgTk9BQSBjbGltYXRlIG5vcm1hbHMuICBUaGF0IGRhdGEgc2V0IGFwcGxpZWQgaG9tb2dlbmVpdHkgY29ycmVjdGlvbiB0byBhY2NvdW50IGZvciBzeXN0ZW1pYyBjaGFuZ2VzICh1cmJhbml6YXRpb24sIHN0YXRpb24gbW92ZXMgZXRjLikuVGhlIGZyb3N0IGZyZWUgZGF0ZSBjbGltYXRlIG5vcm1hbHMgYXJlIG5vdCBzaW1wbGUgbWVhbnMgYnV0IGFyZSBjYWxjdWxhdGVkIGJ5IGEgYm9vdHN0cmFwcGluZyBhcHByb2FjaCB0aGF0IHNhbXBsZXMgYWNyb3NzIHllYXJzIGFuZCBiZWZvcmUgYW5kIGFmdGVyIHRoZSBvYnNlcnZlZCBmcm9zdCBmcmVlIGRhdGUuIFRoaXMgaXMgYSBzdGF0ZS1vZi10aGUtYXJ0IG1ldGhvZCBidXQgaXQgaXMgZGVzaWduZWQgdG8gY2FsY3VsYXRlIHRoZSBtZWFuIGFuZCB2YXJpYW5jZSBvZiB0aGUgZnJvc3QgZnJlZSBkYXRlcyBhc3N1bWluZyB0aGUgZGF0YSBhcmUgbm90IHRyZW5kZWQuIEtleSBmaW5kaW5ncyBmcm9tIHRoZSBwcmVsaW1pbmFyeSBkYXRhIGFyZToKCiMjIFByZWxpbWluYXJ5IGZpbmRpbmdzCjEuICoqVGhlcmUgaXMgYSBzdHJvbmcgcmVnaW9uYWwgZGlmZmVyZW5jZSBpbiB0aGUgdGltaW5nIG9mIGZyb3N0IGZyZWUgZGF0ZXMsIHdpdGggdGhlIGVhc3Qgc2hvd2luZyBlYXJsaWVyIHNwcmluZyBkYXRlcyBhbmQgbGF0ZXIgZmFsbCBkYXRlcyAoc2VlIG1hcHMgYmVsb3cpLioqCjIuIFRoZSBhdmVyYWdlIHN0YXRpb24gaXMgcHJlZGljdGVkIHRvIGhhdmUgZnJvc3QgZnJlZSBkYXRlcyAzIGRheXMgZWFybGllciBpbiB0aGUgc3ByaW5nIGFuZCBhbmQgNiBkYXlzIGxhdGVyIHRoZSBmYWxsIG9mIDIwMjAgdGhhbiBpdCBkaWQgb24gYXZlcmFnZSBvdmVyIHRoZSBwZXJpb2QgMTk4MS0yMDIwIHdpdGggbG9jYWwgc3RhdGlvbiBjaGFuZ2VzIGFzIGxhcmdlIGFzIDItMyB3ZWVrcy4KMy4gSW5jcmVhc2VkIHZhcmlhYmlsaXR5IGluIGZyb3N0IGZyZWUgZGF0ZXMgaGFzIGJlZW4gd2FzIGh5cG90aGVzaXplZCwgYnV0IHRoYXQgd2FzIG5vdCBhIGNvbW1vbiBvY2N1cnJlbmNlIGluIG1vc3QgcmVnaW9ucy4KNC4gQWdncmVnYXRlZCBuYXRpb25hbCB0cmVuZHMgbWFzayB0aGVzZSBjaGFuZ2VzIGJlY2F1c2UgYSBzaG9ydGVuZWQgd2VzdGVybiBncm93aW5nIHNlYXNvbiBvZmZzZXRzIGEgbGVuZ3RoZW5lZCBlYXN0ZXJuIGdyb3dpbmcgc2Vhc29uLgoKIyBOZXh0IHN0ZXBzCjEuIEEgbW9yZSBzb3BoaXN0aWNhdGVkIG1vZGVsIGluY29ycG9yYXRpbmcgYm9vdHN0cmFwcGluZyBhbmQgZXN0aW1hdG9yIHNocmlua2FnZSBzaG91bGQgYmUgZG9uZSB0byBpbXByb3ZlIHRoZSBhY2N1cmFjeSBvZiB0aGUgbW9kZWwgYXQgdGhlIHN0YXRpb24gbGV2ZWwKMi4gVGhlIHVuZGVybGluZyBkYXRhIHNob3VsZCBiZSBob21vZ2VuZWl0eSBjb3JyZWN0ZWQuCjMuIERhdGEgZnJvbSAyMDEwIHRvIDIwMTkgc2hvdWxkIGJlIGFkZGVkLgo0LiBBbiBlbXBpcmljYWwgbW9kZWwgdGVzdGluZyBmcmFtZXdvcmsgdGhhdCBldmFsdWF0ZXMgbW9kZWwgZXJyb3Igc2hvdWxkIGJlIGRldmVsb3BlZC4KNC4gQSB3ZWIgYXBwbGljYXRpb24gZm9yIHVuZGVyc3RhbmRpbmcgYWNjZXNzaW5nIGFuZCB1bmRlcnN0YW5kaW5nIHRoZSBkYXRhIG5lZWRzIHRvIGJlIGRlc2lnbmVkLgoKIyBTb3VyY2UgZGF0YSAKVGhlIHNvdXJjZSBkYXRhIHNldCB1c2VkIGluIHRoZSBhbmFseXNpcyBpcyB0aGUgRGFpbHkgRmlsbGVkIEFkanVzdGVkIFRtaW4gZGF0YSBzcGFubmluZyAxOTUxLTIwMTAuIERhdGEgd2VyZSBkb3dubG9hZGVkIGZyb20gYGZ0cDovL2Z0cC5uY2RjLm5vYWEuZ292L3B1Yi9kYXRhL25vcm1hbHMvMTk4MS0yMDEwL3N1cHBsZW1lbnRhbC9zb3VyY2UtZGF0YXNldHMvZGFpbHktZmlsbGVkLWFkanVzdGVkLXRtaW4uZGF0Lmd6YC4gRGF0YSB3ZXJlIGluaXRpYWxseSBwYXJzZWQgaW4gUHl0aG9uIHRvIGNyZWF0ZSB0aGUgc3ByaW5nIGFuZCBmYWxsIFRtaW4gZGF0YSBjb250YWluaW5nIGp1c3QgdGhlIGZpcnN0IGFuZCBsYXN0IGRhdGVzIG9mIGVhY2ggeWVhciB3aGVyZSB0aGUgdGVtcGVyYXR1cmUgZmVsbCBiZWxvdyAwwrpDIGV2ZXJ5IHllYXIuCgpgYGB7Un0KIyBTZXR1cApsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShyZXNoYXBlMikKc2V0d2QoIn4vRG9jdW1lbnRzL2Zyb3N0X2ZyZWUvIikKZGF0ZXMgPC0gc2VxKDE5ODEsMjAxMCkKYGBgCiMjIEltcG9ydCBzcHJpbmcgZGF0YQpgYGB7Un0Kc3ByaW5nIDwtIHJlYWQudGFibGUoInNwcmluZy5jc3YiLCBzZXA9IiwiLCBoZWFkZXI9VCkKcm93bmFtZXMoc3ByaW5nKTwtc3ByaW5nJFgKc3ByaW5nPC0gc3ByaW5nWywtMV0KZmlsdGVyZWRzcHJpbmcgPC0gc3ByaW5nICU+JSBkcm9wX25hKCkgCmBgYAoKIyMgSW1wb3J0IGZhbGwgZGF0YQpgYGB7Un0KZmFsbCA8LSByZWFkLnRhYmxlKCJmYWxsLmNzdiIsIHNlcD0iLCIsIGhlYWRlcj1UKQpyb3duYW1lcyhmYWxsKTwtZmFsbCRYCmZhbGw8LSBmYWxsWywtMV0KCmZpbHRlcmVkZmFsbCA8LSBmYWxsICU+JSBkcm9wX25hKCkgCmBgYAoKCiMgTG9vayBhdCBuYXRpb25hbCBzcHJpbmcgYW5kIGZhbGwgdHJlbmRzCgpgYGB7Un0KIyBDb252ZXJ0IERGIHRvIG1hdHJpeAp4IDwtIHQoYXMubWF0cml4KGZpbHRlcmVkc3ByaW5nKSkKI0NhbGN1bGF0ZSBwZXIgc3RhdGlvbiBtZWFuIGRhdGUKeG1lYW48LSBhcHBseSh4LCAyLCBtZWFuKQojIFN1YnJ0YWN0IG1lYW4gZnJvbSBkYXRlCnhub3JtIDwtIHggLSB4bWVhbgoKeGxhYmVsZWQgPC0gZGF0YS5mcmFtZSh5ZWFyPXNlcSgxOTUxLDIwMTApLHhub3JtKQp4bG9uZyA8LSBtZWx0KHhsYWJlbGVkLCBpZC52YXJzPSJ5ZWFyIikKIyBQbG90IGNlbnRlcmVkIGRhdGVzCmdncGxvdCh4bG9uZywgYWVzKHg9YXMuZmFjdG9yKHllYXIpLCB5PXZhbHVlKSkgKwogIGdlb21fYm94cGxvdCgpICsKICBzdGF0X3N1bW1hcnkoZnVuLnk9bWVhbiwgZ2VvbT0icG9pbnQiLCBzaGFwZT0yMywgc2l6ZT0yKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCkpICsKICB4bGFiKCJZZWFyIikgKyB5bGFiKCIgRGF5cyBhd2F5IGZyb20gbWVhbiBkYXkiKSArIGdndGl0bGUoIkFubnVhbCBkZXZpYXRpb25zIGZyb20gc3RhdGlvbiBtZWFuIGluIHNwcmluZyBmcm9zdCBmcmVlIGRhdGUgMTk1MS0yMDEwIikKYGBgCgoKYGBge1J9CiMgQ29udmVydCBERiB0byBtYXRyaXgKeCA8LSB0KGFzLm1hdHJpeChmaWx0ZXJlZGZhbGwpKQojQ2FsY3VsYXRlIHBlciBzdGF0aW9uIG1lYW4gZGF0ZQp4bWVhbjwtIGFwcGx5KHgsIDIsIG1lYW4pCiMgU3VicnRhY3QgbWVhbiBmcm9tIGRhdGUKeG5vcm0gPC0geCAtIHhtZWFuCgp4bGFiZWxlZCA8LSBkYXRhLmZyYW1lKHllYXI9c2VxKDE5NTEsMjAxMCkseG5vcm0pCnhsb25nIDwtIG1lbHQoeGxhYmVsZWQsIGlkLnZhcnM9InllYXIiKQojIFBsb3QgY2VudGVyZWQgZGF0ZXMKZ2dwbG90KHhsb25nLCBhZXMoeD1hcy5mYWN0b3IoeWVhciksIHk9dmFsdWUpKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIHN0YXRfc3VtbWFyeShmdW4ueT1tZWFuLCBnZW9tPSJwb2ludCIsIHNoYXBlPTIzLCBzaXplPTIpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSkgKwogIHhsYWIoIlllYXIiKSArIHlsYWIoIkRheXMgYXdheSBmcm9tIG1lYW4iKSArIGdndGl0bGUoIkFubnVhbCBkZXZpYXRpb25zIGZyb20gc3RhdGlvbiBtZWFuIGluIGZhbGwgZnJvc3QgZnJlZSBkYXRlIDE5NTEtMjAxMCIpCmBgYAoKIyMjIENvbmNsdXNpb25zIGFib3V0IG5hdGlvbmFsIHRyZW5kcwpUaGUgYWdncmVnYXRlZCBzdGF0aW9uIGRhdGEgZG8gbm90IHNob3cgdHJlbmRzIHJlbGF0aXZlIHRvIHRoZSBsYXJnZSBpbnRlci1hbm51YWwgZmx1Y3R1YXRpb25zIGluIGZyb3N0IGRhdGUuCgoqKioKCiMgTG9va2luZyBhdCB0cmVuZCBwYXR0ZXJucyBvZiBpbmRpdmlkdWFsIHN0YXRpb25zCgpHZW5lcmFsIHRyZW5kcyBkbyBub3Qgc2hvdyBhIGxvdCBidXQgaXQgaXMgcG9zc2libGUgdGhhdCB0aGVzZSB0cmVuZHMgYXJlIGxhcmdlciBhdCBzcGVjaWZpYyBzaXRlcy4gVGhlIG5leHQgc3RlcCBpcyB0byBsb29rIGF0IHRyZW5kcyBhY3Jvc3MgaW5kaXZpZHVhbCBzdGF0aW9ucy4gd2UgZml0IGEgR0xNICBmb3IgZWFjaCBzdGF0aW9uIHRpbWUgc2VyaWVzIGFuZCBsb29rIGF0IHRoZSBkaXN0cmlidXRpb24gb2Ygc2xvcGVzIGFuZCBwcmVkaWN0ZWQgZnJvc3QgZnJlZSBkYXRlcyBiYXNlZCBvbiB0aGUgbW9kZWxzLgoKIyMgU3ByaW5nIHRyZW5kcyAxOTgxLTIwMTAKYGBge1J9Cm1vZGVsMjAyMGZ1bmN0aW9uIDwtIGZ1bmN0aW9uKHguY29sKSB7CiAgbW9kMSA8LSBnbG0oeC5jb2wgfiBkYXRlcywgbmEuYWN0aW9uPW5hLm9taXQpCiAgZXN0MSA8LSBwcmVkaWN0KG1vZDEsIG5ld2RhdGE9ZGF0YS5mcmFtZShkYXRlcz1jKDIwMjApKSkKICByZXR1cm4obWVhbih4LmNvbCktIGVzdDEpCn0KCmRhdGVzIDwtIHNlcSgxOTgxLDIwMTApCnggPC0gdChhcy5tYXRyaXgoZmlsdGVyZWRzcHJpbmdbLDMxOjYwXSkpCnNwcmluZ2NvZWZzIDwtICB0KGFwcGx5KHgsIDIsIGZ1bmN0aW9uKHguY29sKSBnbG0oeC5jb2wgfiBkYXRlcywgbmEuYWN0aW9uPW5hLm9taXQpJGNvZWYpKQpzZGYgPC1hcy5kYXRhLmZyYW1lKHNwcmluZ2NvZWZzKQpgYGAKCmBgYHtSfQpnZ3Bsb3Qoc2RmLCBhZXMoeD1kYXRlcykpICsgZ2VvbV9oaXN0b2dyYW0oYmlucz02MCkgKyAKZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1tZWFuKGRhdGVzKSksIGNvbG9yPSJibHVlIiwgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MSkgKwp4bGFiKCJTbG9wZSIpICsgeWxhYigiQ291bnQiKSArIGdndGl0bGUoIlNsb3BlcyBvZiBzdGF0aW9uIGZpdHMgdG8gc3ByaW5nIGZyb3N0IGZyZWUgZGF0ZSAxOTgxLTIwMTAiKQpgYGAKCmBgYHtSfQpzcHJpbmcyMDIwZ2FwIDwtICBkYXRhLmZyYW1lKHBkYXRlPSBhcHBseSh4LCAyLCBtb2RlbDIwMjBmdW5jdGlvbikpCm1lYW4oc3ByaW5nMjAyMGdhcCRwZGF0ZSkKYGBgCmBgYHtyfQpnZ3Bsb3Qoc3ByaW5nMjAyMGdhcCwgYWVzKHg9cGRhdGUpKSArIGdlb21faGlzdG9ncmFtKGJpbnM9NjApICsgCmdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9bWVhbihwZGF0ZSkpLCBjb2xvcj0iYmx1ZSIsIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTEpICsKeGxhYigiRGF5cyIpICsgeWxhYigiQ291bnQiKSArIGdndGl0bGUoIlByZWRpY3RlZCBvZmZzZXQgb2YgMjAyMCBzcHJpbmcgZnJvc3QgZnJlZSBkYXRlIGZyb20gZml0IG9mIGZyb3N0IGZyZWUgZGF0ZXMsIDE5ODEtMjAxMCIpCgpgYGAKCiMjIyBGYWxsIHRyZW5kcyAxOTgxLTIwMTAKCmBgYHtSfQpkYXRlcyA8LSBzZXEoMTk4MSwyMDEwKQp4IDwtIHQoYXMubWF0cml4KGZpbHRlcmVkZmFsbFssMzE6NjBdKSkKZmFsbGNvZWZzIDwtICB0KGFwcGx5KHgsIDIsIGZ1bmN0aW9uKHguY29sKSBnbG0oeC5jb2wgfiBkYXRlcywgbmEuYWN0aW9uPW5hLm9taXQpJGNvZWYpKQpmZGYgPC1hcy5kYXRhLmZyYW1lKGZhbGxjb2VmcykKYGBgCgpgYGB7Un0KZ2dwbG90KGZkZiwgYWVzKHg9ZGF0ZXMpKSArIGdlb21faGlzdG9ncmFtKGJpbnM9NjApICsgCmdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9bWVhbihkYXRlcykpLCBjb2xvcj0iYmx1ZSIsIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTEpICsgCiAgeGxhYigiU2xvcGUiKSArIHlsYWIoIkNvdW50IikgKyBnZ3RpdGxlKCJTbG9wZXMgb2Ygc3RhdGlvbiBmaXRzIHRvIFNwcmluZyBmcm9zdCBmcmVlIGRhdGUgMTk4MS0yMDEwIikKYGBgCgpCb3RoIFNwcmluZyBhbmQgRmFsbCBmcm9zdCBmcmVlIGRhdGVzIHNob3cgYSB3YXJtaW5nIHRyZW5kIHdoZXJlIHRoZSBmcm9zdCBmcmVlIGRhdGUgaXMgY29taW5nIHNvb25lciBpbiB0aGUgc3ByaW5nIGFuZCBsYXRlciBpbiB0aGUgZmFsbC4gVGhpcyB0cmVuZCBjYW4gYmUgcHV0IGludG8gdGhlIG51bWJlciBvZiBkYXlzIHNoaWZ0ZWQgYnkgZml0dGluZyB0aGUgbW9kZWwuCgoKYGBge1J9CmZhbGwyMDIwZ2FwIDwtICBkYXRhLmZyYW1lKHBkYXRlPSBhcHBseSh4LCAyLCBtb2RlbDIwMjBmdW5jdGlvbikpCmBgYApgYGB7cn0KZ2dwbG90KGZhbGwyMDIwZ2FwLCBhZXMoeD1wZGF0ZSkpICsgZ2VvbV9oaXN0b2dyYW0oYmlucz02MCkgKyAKZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1tZWFuKHBkYXRlKSksIGNvbG9yPSJibHVlIiwgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MSkgKwp4bGFiKCJEYXlzIikgKyB5bGFiKCJDb3VudCIpICsgZ2d0aXRsZSgiUHJlZGljdGVkIG9mZnNldCBvZiAyMDIwIGZhbGwgZnJvc3QgZnJlZSBkYXRlIGZyb20gZml0IG9mIGZyb3N0IGZyZWUgZGF0ZXMsIDE5ODEtMjAxMCIpCgptZWFuKGZhbGwyMDIwZ2FwJHBkYXRlKQpgYGAKCiMjIyBDb25jbHVzaW9ucyBvZiBwZXIgc3RhdGlvbiB0cmVuZCBkYXRhCgpCb3RoIFNwcmluZyBhbmQgRmFsbCBmcm9zdCBmcmVlIGRhdGVzIHNob3cgYSB3YXJtaW5nIHRyZW5kLiBUaGUgU3ByaW5nIGZyb3N0IGZyZWUgZGF0ZSBpcyBjb21pbmcgMyBkYXlzIHNvb25lciBhbmQgdGhlIGZhbGwgZnJvc3QgZnJlZSBkYXRlIGlzIGNvbWluZyA2IGRheXMgbGF0ZXIuIFRoaXMgdHJlbmQgY2FuIGJlIHB1dCBpbnRvIHRoZSBudW1iZXIgb2YgZGF5cyBzaGlmdGVkIGJ5IGZpdHRpbmcgdGhlIG1vZGVsLgoKVGhlcmUgZG9lcyBhcHBlYXIgdG8gYmUgYW4gb3ZlcmFsbCBzaGlmdCAKCgojIExvb2tpbmcgZm9yIHJlZ2lvbmFsIGRpZmZlcmVuY2VzCgpgYGB7cn0KYWxsc3RhdGlvbnMgPC1yZWFkLnRhYmxlKCJhbGxzdGF0aW9ucy1jbGVhbi50eHQiLCBoZWFkZXI9Riwgc2VwPSJcdCIpCnNwcmluZ2xvYyA8LSBtZXJnZShzcHJpbmcyMDIwZ2FwLCBhbGxzdGF0aW9ucywgYnkueD0icm93Lm5hbWVzIiwgYnkueT0iVjEiKQpgYGAKCmBgYHtyfQpsaWJyYXJ5KGdnbWFwKQpsaWJyYXJ5KG1hcHMpCmxpYnJhcnkobWFwZGF0YSkKYmNfYmJveCA8LSBtYWtlX2Jib3gobGF0ID0gVjIsIGxvbiA9IFYzLCBkYXRhID0gc3ByaW5nbG9jKQpiY19iaWcgPC0gZ2V0X21hcChsb2NhdGlvbiA9IGJjX2Jib3gsIHNvdXJjZSA9ICJnb29nbGUiLCBtYXB0eXBlID0gInRlcnJhaW4tYmFja2dyb3VuZCIpCmdnbWFwKGJjX2JpZykgKyAKICBnZW9tX3BvaW50KGRhdGEgPSBzcHJpbmdsb2MsIG1hcHBpbmcgPSBhZXMoeCA9IFYzLCB5ID0gVjIsIGNvbG9yID0gLXBkYXRlKSwgc2l6ZT0wLjkpICsgc2NhbGVfY29sb3VyX2dyYWRpZW50Mih0cmFucz0icHNldWRvX2xvZyIpICsKICBnZ3RpdGxlKCJQcmVkaWN0ZWQgY2hhbmdlIGluIHNwcmluZyBmcm9zdCBmcmVlIGRhdGUgaW4gMjAyMCB2ZXJzdXMgbWVhbiBmcm9tIDE5ODEtMjAxMCIpCgpgYGAKCgpgYGB7cn0KYWxsc3RhdGlvbnMgPC1yZWFkLnRhYmxlKCJhbGxzdGF0aW9ucy1jbGVhbi50eHQiLCBoZWFkZXI9Riwgc2VwPSJcdCIpCmZhbGxsb2MgPC0gbWVyZ2UoZmFsbDIwMjBnYXAsIGFsbHN0YXRpb25zLCBieS54PSJyb3cubmFtZXMiLCBieS55PSJWMSIpCmBgYAoKYGBge3J9CmxpYnJhcnkoZ2dtYXApCmxpYnJhcnkobWFwcykKbGlicmFyeShtYXBkYXRhKQpiY19iYm94IDwtIG1ha2VfYmJveChsYXQgPSBWMiwgbG9uID0gVjMsIGRhdGEgPSBmYWxsbG9jKQpiY19iaWcgPC0gZ2V0X21hcChsb2NhdGlvbiA9IGJjX2Jib3gsIHNvdXJjZSA9ICJnb29nbGUiLCBtYXB0eXBlID0gInRlcnJhaW4tYmFja2dyb3VuZCIsY29sb3I9ImJ3IikKZ2dtYXAoYmNfYmlnKSArIAogIGdlb21fcG9pbnQoZGF0YSA9IGZhbGxsb2MsIG1hcHBpbmcgPSBhZXMoeCA9IFYzLCB5ID0gVjIsIGNvbG9yID0gcGRhdGUpLCBzaXplPTAuOSkgKyBzY2FsZV9jb2xvdXJfZ3JhZGllbnQyKHRyYW5zPSJwc2V1ZG9fbG9nIikgKwogIGdndGl0bGUoIlByZWRpY3RlZCBjaGFuZ2UgaW4gZmFsbCBmcm9zdCBmcmVlIGRhdGUgaW4gMjAyMCB2ZXJzdXMgbWVhbiBmcm9tIDE5ODEtMjAxMCIpCmBgYAojIyMgQ29uY2x1c2lvbnMgYWJvdXQgcmVnaW9uYWwgZGF0YQpUaGVyZSBkbyBzZWVtIHRvIGJlIHN0cm9uZyByZWdpb25hbCB0cmVuZHMgaW4gdGhlIENoYW5nZXMgaW4gZnJvc3QgZnJlZSBkYXRlcywgd2l0aCBzdHJvbmcgd2FybWluZyBpbiB0aGUgU291dGhlYXN0LgoKIyBDaGFuZ2VzIGluIHZhcmlhbmNlCgpUaGUgdmFyaWFiaWxpdHkgb2YgRnJvc3QgZGF0ZXMgaXMgYWxzbyBhbiBpbXBvcnRhbnQgZmFjdG9yIHRvIG1pdGlnYXRpbmcgdGhlIHJpc2sgb2YgZnJvc3QgZGFtYWdlIHRvIGNyb3BzLiBUbyBhbmFseXplIHRoYXQgd2UgdGFrZSB0aGUgZGUtdHJlbmRlZCBkYXRhIChyZXNpZHVhbHMpIGZyb20gdGhlIEdMTSBhdCBlYWNoIHNpdGUgYW5kIGFwcGx5IGEgdGVzdCBmb3IgZXF1YWxpdHkgb2YgdmFyaWFuY2VzIGZvciB0aGUgcGVyaW9kcyAxOTgxLTE5OTUgYW5kIDE5OTYtMjAxMC4KYGBge3J9CgpzcHJpbmdfcmVzIDwtICBhcHBseSh4LCAyLCBmdW5jdGlvbih4LmNvbCkgcmVzaWR1YWxzKGdsbSh4LmNvbCB+IGRhdGVzLCBuYS5hY3Rpb249bmEub21pdCkpKQpzcHJpbmd2ciA8LSAoYXBwbHkoc3ByaW5nX3JlcywgMiwgZnVuY3Rpb24oc3ByaW5nX3Jlcy5jb2wpICh2YXIudGVzdChzcHJpbmdfcmVzLmNvbFsxOjE1XSxzcHJpbmdfcmVzLmNvbFsxNjozMF0sIGFsdGVybmF0aXZlPSJncmVhdGVyIikpJGVzdGltYXRlICkpCgpgYGAKCmBgYHtyfQpnZ3Bsb3QoZGF0YS5mcmFtZShzcHJpbmd2ciksIGFlcyh4PWxvZyhzcHJpbmd2ciwyKSkpICsgZ2VvbV9oaXN0b2dyYW0oYmlucz02MCkgKyAKZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1tZWFuKGxvZyhzcHJpbmd2ciwgMikpKSwgY29sb3I9ImJsdWUiLCBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0xKSArCnhsYWIoIlZhcmlhbmNlIHJhdGlvIikgKyB5bGFiKCJDb3VudCIpICsgZ2d0aXRsZSgiVmFyaWFuY2UgbG9nIDIgcmF0aW8gZm9yIGRlLXRyZW5kZWQgZGF0YSBmcm9tICAxOTgxLTE5OTUgYW5kIDE5OTYtMjAxMCIpCmBgYAoKYGBge3J9CnNwcmluZ3B2YWwgPC0gKGFwcGx5KHNwcmluZ19yZXMsIDIsIGZ1bmN0aW9uKHNwcmluZ19yZXMuY29sKSAodmFyLnRlc3Qoc3ByaW5nX3Jlcy5jb2xbMToxNV0sc3ByaW5nX3Jlcy5jb2xbMTY6MzBdLCBhbHRlcm5hdGl2ZT0idHdvLnNpZGVkIikpJHAudmFsdWUpKQpzcHYuZGY8LWRhdGEuZnJhbWUoc3ByaW5ncHZhbCkKc3B2LmRmJHN0YXRpb25zIDwtIHJvd25hbWVzKHNwdi5kZikKc2lnLnN0YXRpb25zIDwtc3B2LmRmW3Nwdi5kZiRzcHJpbmdwdmFsPDAuMDUsXQojIE1vc3Qgc3RhdGlvbnMgaGFkIHNpZ2lmaWdhbnRseSBncmVhdGVyIHZhcmlhdGlvbiBpbiB0aGUgbGF0ZXIgcGVyaW9kCmBgYAoKYGBge3J9CnNwcmluZ3ZhciA8LSBtZXJnZShkYXRhLmZyYW1lKHNwcmluZ3ZyKSwgYWxsc3RhdGlvbnMsIGJ5Lng9InJvdy5uYW1lcyIsIGJ5Lnk9IlYxIikKc3ByaW5ndmFyYW5kcCA8LSBtZXJnZShzcHJpbmd2YXIsc2lnLnN0YXRpb25zLCBieS54PSJSb3cubmFtZXMiLCBieS55PSJzdGF0aW9ucyIpCmdnbWFwKGJjX2JpZykgKyAKICBnZW9tX3BvaW50KGRhdGEgPSBzcHJpbmd2YXJhbmRwLCBtYXBwaW5nID0gYWVzKHggPSBWMywgeSA9IFYyLCBjb2xvciA9IGxvZyhzcHJpbmd2ciwyKSksIHNpemU9MikgKyBzY2FsZV9jb2xvdXJfZ3JhZGllbnQyKCkgKwogIGdndGl0bGUoIlN0YXRpb25zIHdpdGggc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCBjaGFuZ2VzIGluIGxvZyB2YXJpYW5jZSByYXRpb3MgYmV0d2VlbiAxOTgxLTE5OTUgYW5kIDE5OTYtMjAxMCIpCmBgYAoKYGBge3J9CmdnbWFwKGJjX2JpZykgKyAKICBnZW9tX3BvaW50KGRhdGEgPSBzcHJpbmd2YXIsIG1hcHBpbmcgPSBhZXMoeCA9IFYzLCB5ID0gVjIsIGNvbG9yID0gbG9nKHNwcmluZ3ZyLDIpKSwgc2l6ZT0wLjkpICsgc2NhbGVfY29sb3VyX2dyYWRpZW50MigpKwogIGdndGl0bGUoIkxvZyB2YXJpYW5jZSByYXRpb3MgYmV0d2VlbiAxOTgxLTE5OTUgYW5kIDE5OTYtMjAxMCIpCmBgYAoKCiMjIENvbmNsdXNpb25zIG9uIHZhcmlhbmNlIAoKVGhlcmUgZG9lcyBub3QgYXBwZWFyIHRvIGJlIGEgc3Ryb25nIHNoaWZ0IGluIHZhcmlhbmNlIHdoZW4gY29tcGFyaW5nIGRlLXRyZW5kZWQgZGF0YSBmcm9tIDE5ODEtMTk5NSBhbmQgMTk5Ni0yMDEwLiBUaGVyZSBhcmUgc29tZSByZWdpb25hbCBwYXR0ZXJucyBpbiB0aGUgbWlub3Igc2hpZnQgb2JzZXJ2ZWQuIFBvdGVudGlhbCBhcnRpZmFjdHMgZHJpdmluZyAoc3VjaCBhcyBwb29yZXIgZml0IGZvciBvbmUgcGVyaW9kKSBuZWVkIHRvIGJlIGludmVzdGlnYXRlZCBiZWZvcmUgYW55IHN0cm9uZ2VyIGNvbmNsdXNpb24gY2FuIGJlIG1hZGUuIAoKIyBHZW5lcmFsIGNvbmNsdXNpb25zCgpUaGVyZSBtYXkgYmUgcmVnaW9uYWxseSBpbXBvcnRhbnQgc2hpZnRzIGluIHRoZSB0aW1pbmcgb2YgZnJvc3QgZnJlZSBkYXRlcyBieSB1cCB0byBzZXZlcmFsIHdlZWtzLiBUaGVzZSBwcmVsaW1pbmFyeSBtZXRob2RzIG5lZWQgdG8gYmUgY29uZmlybWVkIHVzaW5nIGJvb3RzdHJhcHBpbmcgbWV0aG9kcywgdG8gbWluaW1pemUgdGhlIHN0b2NoYXN0aWMgbmF0dXJlIG9mICJsYXN0IGV2ZW50IiBkYXRhIGxpa2UgZnJvc3QgZnJlZSBkYXlzLiBEZXZlbG9waW5nIG1vZGVscyBmb3IgbG9jYWwgc3RhdGlvbnMgcmF0aGVyIHRoYW4gbGFyZ2Ugc2NhbGUgdHJlbmRzIHdpbGwgcmVxdWlyZSBtZXRob2RzIGxpa2UgYm9vdHN0cmFwcGluZyBhbmQgc2hyaW5rYWdlIHRvIHJlZHVjZSB2YXJpYWJpbGl0eS4gRmluYWxseSwgbW9kZWxzIGRldmVsb3BlZCBuZWVkIHRvIGJlIGV2YWx1YXRlZCBmb3IgdGhlaXIgZXJyb3IgaW4gY3Jvc3MtZm9sZCB0ZXN0IC90cmFpbiB2YWxpZGF0aW9uIGV4cGVyaW1lbnRzIGFuZCB0aGUgZGF0YSBuZWVkcyB0byBiZSBtYWRlIGF2YWlsYWJsZSBpbiBhIHVzZXItZnJlaW5kbHkgd2ViIGFwcGxpY2F0aW9uLgo=