This lab journal shows the data preparation for analyses ‘starting to publish’ and ‘stopping to publish’


Custom functions

  • package.check: Check if packages are installed (and install if not) in R (source).
fpackage.check <- function(packages) {
    lapply(packages, FUN = function(x) {
        if (!require(x, character.only = TRUE)) {
            install.packages(x, dependencies = TRUE)
            library(x, character.only = TRUE)
        }
    })
}

Packages

  • tidyverse: for tidy data manipulations
  • dplyr: for data manipulations
  • zoo: to calculate running averages and minimums for the ‘stopping to publish’ analyses
packages = c("tidyverse", "dplyr", "zoo")

fpackage.check(packages)

Input

We use one processed dataset:

  • phdfield: processed example dataset of PhDs with gender, ethnicity and field variables
    • name of dataset: phd_field / phd_df

Further, we use one raw dataset: * pubs_metadf: publications dataset
- name of dataset: pubs_metadf

load(file = "./data/processed/phdfield.rda")
phd_df <- phdfield

load(file = "./data/pubs_metadf.rda")

Creating a person-period file

We start by cleaning up the publications data, and then summarize the publications per PhD per year (i.e. a person-period data format).

pubs_metadf$type <- as.factor(pubs_metadf$type)

# selecting only articles, books and book chapters
pubs_metadf <- pubs_metadf[(pubs_metadf$type == "Artikel") | (pubs_metadf$type == "Boek" | (pubs_metadf$type ==
    "Boekdeel")), ]

# derive publication year from variable Data.issued
pubs_metadf <- pubs_metadf[!is.na(pubs_metadf$date.issued), ]


pubs_metadf %>%
    mutate(pub_year = as.character(date.issued)) %>%
    mutate(pub_year = substr(pub_year, 1, 4)) %>%
    mutate(pub_year = as.numeric(pub_year)) -> pubs_metadf

# last complete year of publications data is 2022, so remove publications from the following years
pubs_metadf <- pubs_metadf[pubs_metadf$pub_year < 2023, ]


# now, we create a person-period file: one row per PhD per year
pubs_metadf %>%
    group_by(id, pub_year) %>%
    dplyr::summarize(npubs = n(), id = first(id)) -> df_ppf

That looks something like this:

knitr::kable(df_ppf, format = "markdown")
id pub_year npubs
f 2009 2
f 2011 1
f 2012 2
f 2013 4
f 2014 1
f 2019 2
g 2016 1
g 2017 1
g 2018 3
g 2020 3
g 2021 4
g 2022 10
h 1998 1
h 1999 1
h 2000 1
h 2001 1
h 2005 3
h 2006 2
h 2009 3
h 2010 2
h 2012 2
h 2015 1

Starting to publish

We create a variable for whether a person has started publishing within 3 years after their PhD, by looking at the year of first publication and the PhD year.

# We add PhD year to the person-period file to select only publications from after the PhD year
year <- subset(phd_df, select = c(id, phd_year))
starting <- df_ppf %>%
    left_join(year, by = "id")

starting <- starting[starting$phd_year < starting$pub_year, ]  # only pubs after PhD


# We add the year in which a person first published after obtaining their PhD
starting %>%
    group_by(id) %>%
    dplyr::summarize(pub_min = min(pub_year)) %>%
    ungroup() -> minpub

starting %>%
    left_join(minpub, by = "id") -> starting

starting <- na.omit(starting)  # remove missings 

starting <- subset(starting, select = -c(phd_year))  # remove phd year variable again, because it will be added to the data when merging with phd_df


# Now we combine combine the PhD data with the publications data
starting %>%
    inner_join(phd_df, by = "id") -> starting


# Creating a variable for whether a person has published within three years after the PhD in other
# words, the first publication should occur less than four years after the year in which their
# dissertation was published
starting$start_pub <- ifelse(starting$pub_min < (starting$phd_year + 4), 1, 0)

Next, we add the “start_pub” variable to the PhD data.

# select only the starting variable and ID to match
starting %>%
    select(id, start_pub) -> starting

# keep a single row per individual
starting <- starting[!duplicated(starting$id), ]


# merge onto the PhD dataset
phd_df <- left_join(phd_df, starting, by = "id")

phd_df$start_pub <- ifelse(is.na(phd_df$start_pub), 0, phd_df$start_pub)  # all those who do not have a profile automatically score a 0


# because we look at in the 3 years following the PhD for start_pub, we exclude PhDs from cohorts
# after 2019 for cohorts 2020 and later, we have fewer than 3 years of publication data
phd_df <- phd_df[phd_df$phd_year < 2020, ]


# adding a cohort variable : phd_year centered on the minimum
phd_df$phd_cohort <- as.numeric(phd_df$phd_year) - 1990

And save the data for use in the analyses for “starting to publish”

id start_pub uni phd_year phd_cohort field field2 ethnicity ethnicity2 gender
f 1 LU 2012 22 Physical and Mathematical Sciences Physical and Mathematical Sciences moroccan minority women
g 1 UU 2019 29 Biological and Health Sciences Biological and Health Sciences other other men
h 1 WUR 2000 10 Social and Behavioral Sciences Social and Behavioral Sciences other other women

Stopping to publish

For the analyses under ‘stopping to publish’, we continue with the sample of PhDs who have ‘started publishing’ according to analysis #1.

df_stopping <- phd_df[phd_df$start_pub == 1, ]

df_stopping %>%
    select(-c(start_pub)) -> df_stopping

We again need the person-period file in order to analyse publications for PhDs over multiple years, but this time, we want to include rows with 0 publications. This means we have to start with an empty person-period file.

pub_year <- c(1988:2022)  # this is the time-window in which we scraped data. 

npubs_zero <- rep(0, length(pub_year))  # default to 0 publications

id <- unique(df_ppf$id)  #identify the unique PHD ids

nid <- length(id)

# based on this info make the empty dataset
pub_year <- rep(pub_year, nid)
npubs_zero <- rep(npubs_zero, nid)
id <- rep(id, each = length(c(1988:2022)))
empty_ppf <- data.frame(id, pub_year, npubs_zero)

Adding info to the empty person-period file

# adding time-invariant variables to the person-period file
df_ppf %>%
    inner_join(df_stopping, by = "id") -> df_ppf


# filling up the empty person-period file with the actual publications data
empty_ppf %>%
    full_join(df_ppf, by = c("id", "pub_year")) %>%
    arrange(id, pub_year) %>%
    select(id, pub_year, npubs, gender, ethnicity, ethnicity2, field, field2, uni, phd_year, phd_cohort) ->
    df_ppf


# all time-constant vars are empty in rows with 0 pubs. Let's fix this.
df_ppf %>%
    group_by(id) %>%
    fill(gender, .direction = "downup") %>%
    fill(ethnicity, .direction = "downup") %>%
    fill(ethnicity2, .direction = "downup") %>%
    fill(field, .direction = "downup") %>%
    fill(field2, .direction = "downup") %>%
    fill(uni, .direction = "downup") %>%
    fill(phd_cohort, .direction = "downup") %>%
    fill(phd_year, .direction = "downup") %>%
    ungroup() -> df_ppf

# replacing NA values in npubs with 0
df_ppf %>%
    mutate(npubs = replace_na(npubs, 0)) -> df_ppf


# next, we include a variable with the average number of publications in the previous years rolling
# average here computes the average number of publications in the year t, t-1 and t-2 then we take
# the value of the rolling average for the preceding year in npubs_prev (when it is present) for
# the first year (1988), we take the value of the year itself
df_ppf %>%
    group_by(id) %>%
    mutate(npubs_rollavg = rollapply(npubs, 3, mean, align = "right", fill = 0), npubs_prev = lag(npubs_rollavg,
        n = 1, order_by = pub_year), npubs_prev = ifelse(is.na(npubs_prev), lead(npubs_prev, n = 1, order_by = pub_year),
        npubs_prev)) %>%
    ungroup() -> df_ppf


# we log-transform the number of publications to account for outliers
df_ppf$npubs_prev_s <- log10(df_ppf$npubs_prev + 1)  # +1 to avoid negative infinity

Creating the variable ‘stopping to publish’.

# creating a time variable (= how many years since obtaining doctorate); removing years before
# doctorate
df_ppf %>%
    mutate(time = as.numeric(pub_year - phd_year)) -> df_ppf

# We look at cohorts 1990-2018 because we selected publishing scholars from the analyses for
# 'starting to publish', PhDs from cohort 2019 cannot become inactive by design
df_ppf3 <- df_ppf[df_ppf$phd_year < 2019, ]


# we compute rolling maximum across 3 time periods align = left ensures that it looks forward in
# time: no publication at t, but 1+ pub at t+1 or t+2 ensures non-zero pubs at t.
df_ppf3 %>%
    group_by(id) %>%
    mutate(npubs3 = rollapply(npubs, 3, sum, align = "left", fill = "extend")) %>%
    ungroup() -> df_ppf3

# if a person did not have any publications in the three year period (i.e. the max is 0), we assume
# career exit
df_ppf3 %>%
    mutate(inactive = ifelse((npubs3 > 0), 0, 1)) -> df_ppf3


# we only look at publications after the PhD
df_ppf3 <- df_ppf3[(df_ppf3$pub_year > df_ppf3$phd_year), ]



# currently, a person can become inactive, and then active again. We only look at the first
# transition to inactivity.
df_ppf3 %>%
    group_by(id) %>%
    dplyr::arrange(time, .by_group = TRUE) %>%
    mutate(inactive_cs = cumsum(inactive)) %>%
    filter(inactive_cs < 2) -> df_ppf3

Alternative time window: 5 years

# Alternative publication window: 5 year
df_ppf5 <- df_ppf[df_ppf$phd_year < 2017, ]
df_ppf5 <- df_ppf5 %>%
    mutate(npubs = replace_na(npubs, 0))

# Rolling maximum across 5 years
df_ppf5 %>%
    group_by(id) %>%
    mutate(npubs5 = rollapply(npubs, 5, sum, align = "left", fill = "extend")) %>%
    ungroup() -> df_ppf5

df_ppf5 %>%
    mutate(inactive = ifelse((npubs5 > 0), 0, 1)) -> df_ppf5


df_ppf5 <- df_ppf5[(df_ppf5$pub_year > df_ppf5$phd_year), ]


# Max. 1 time inactive
df_ppf5 %>%
    group_by(id) %>%
    arrange(time, .by_group = TRUE) %>%
    mutate(inactive_cs = cumsum(inactive)) %>%
    filter(inactive_cs < 2) -> df_ppf5


df_ppf5 <- na.omit(df_ppf5)
LS0tDQp0aXRsZTogIkRhdGEgcHJlcGFyYXRpb24gJ3N0YXJ0aW5nIHRvIHB1Ymxpc2gnIg0KZGF0ZTogIkxhc3QgY29tcGlsZWQgb24gYHIgZm9ybWF0KFN5cy50aW1lKCksICclQiwgJVknKWAiDQpvdXRwdXQ6IA0KICBodG1sX2RvY3VtZW50Og0KICAgIGNzczogdHdlYWtzLmNzcw0KICAgIHRvYzogIHRydWUNCiAgICB0b2NfZmxvYXQ6IHRydWUNCiAgICBudW1iZXJfc2VjdGlvbnM6IGZhbHNlDQogICAgY29kZV9mb2xkaW5nOiBzaG93DQogICAgY29kZV9kb3dubG9hZDogeWVzDQoNCi0tLQ0KDQoNCg0KDQpgYGB7ciwgZ2xvYmFsc2V0dGluZ3MsIGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHJlc3VsdHM9ImhpZGUifQ0KDQpsaWJyYXJ5KGtuaXRyKQ0KI2xpYnJhcnkocmdsKQ0Kb3B0c19jaHVuayRzZXQodGlkeS5vcHRzPWxpc3Qod2lkdGguY3V0b2ZmPTEwMCksdGlkeT1UUlVFLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSxjb21tZW50ID0gIiM+IiwgY2FjaGU9VFJVRSwgY2xhc3Muc291cmNlPWMoInRlc3QiKSwgY2xhc3Mub3V0cHV0PWMoInRlc3QyIiksIGNhY2hlLmxhenkgPSBGQUxTRSkNCm9wdGlvbnMod2lkdGggPSAxMDApDQpyZ2w6OnNldHVwS25pdHIoKQ0KDQpjb2xvcml6ZSA8LSBmdW5jdGlvbih4LCBjb2xvcikge3NwcmludGYoIjxzcGFuIHN0eWxlPSdjb2xvcjogJXM7Jz4lczwvc3Bhbj4iLCBjb2xvciwgeCkgfQ0KDQpgYGANCg0KYGBge3Iga2xpcHB5LCBlY2hvPUZBTFNFLCBpbmNsdWRlPVRSVUUsIGV2YWw9VFJVRX0NCmtsaXBweTo6a2xpcHB5KHBvc2l0aW9uID0gYygndG9wJywgJ3JpZ2h0JykpDQoja2xpcHB5OjprbGlwcHkoY29sb3IgPSAnZGFya3JlZCcpDQoja2xpcHB5OjprbGlwcHkodG9vbHRpcF9tZXNzYWdlID0gJ0NsaWNrIHRvIGNvcHknLCB0b29sdGlwX3N1Y2Nlc3MgPSAnRG9uZScpDQpgYGANCg0KLS0tLQ0KDQpUaGlzIGxhYiBqb3VybmFsIHNob3dzIHRoZSBkYXRhIHByZXBhcmF0aW9uIGZvciBhbmFseXNlcyAnc3RhcnRpbmcgdG8gcHVibGlzaCcgYW5kICdzdG9wcGluZyB0byBwdWJsaXNoJw0KICANCg0KLS0tLQ0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCg0Kcm0obGlzdCA9IGxzKCkpDQoNCmBgYA0KDQoNCg0KIyBDdXN0b20gZnVuY3Rpb25zDQoNCi0gYHBhY2thZ2UuY2hlY2tgOiBDaGVjayBpZiBwYWNrYWdlcyBhcmUgaW5zdGFsbGVkIChhbmQgaW5zdGFsbCBpZiBub3QpIGluIFIgKFtzb3VyY2VdKGh0dHBzOi8vdmJhbGlnYS5naXRodWIuaW8vdmVyaWZ5LXRoYXQtci1wYWNrYWdlcy1hcmUtaW5zdGFsbGVkLWFuZC1sb2FkZWQvKSkuICANCg0KDQpgYGB7ciwgcmVzdWx0cz0naGlkZSd9DQoNCmZwYWNrYWdlLmNoZWNrIDwtIGZ1bmN0aW9uKHBhY2thZ2VzKSB7DQogIGxhcHBseShwYWNrYWdlcywgRlVOID0gZnVuY3Rpb24oeCkgew0KICAgIGlmICghcmVxdWlyZSh4LCBjaGFyYWN0ZXIub25seSA9IFRSVUUpKSB7DQogICAgICBpbnN0YWxsLnBhY2thZ2VzKHgsIGRlcGVuZGVuY2llcyA9IFRSVUUpDQogICAgICBsaWJyYXJ5KHgsIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkNCiAgICB9DQogIH0pDQp9DQoNCmBgYA0KDQoNCi0tLSAgDQoNCiMgUGFja2FnZXMNCg0KLSBgdGlkeXZlcnNlYDogZm9yIHRpZHkgZGF0YSBtYW5pcHVsYXRpb25zDQotIGBkcGx5cmA6IGZvciBkYXRhIG1hbmlwdWxhdGlvbnMNCi0gYHpvb2A6IHRvIGNhbGN1bGF0ZSBydW5uaW5nIGF2ZXJhZ2VzIGFuZCBtaW5pbXVtcyBmb3IgdGhlICdzdG9wcGluZyB0byBwdWJsaXNoJyBhbmFseXNlcw0KDQoNCmBgYHtyLCByZXN1bHRzPSdoaWRlJ30NCg0KcGFja2FnZXMgPSBjKCJ0aWR5dmVyc2UiLCAiZHBseXIiLCAiem9vIikNCg0KZnBhY2thZ2UuY2hlY2socGFja2FnZXMpDQoNCmBgYA0KDQoNCi0tLSANCg0KIyBJbnB1dA0KDQoNCg0KV2UgdXNlIG9uZSBwcm9jZXNzZWQgZGF0YXNldDoNCg0KKiBbcGhkZmllbGRdKCJodHRwczovL2dpdGh1Yi5jb20vYW1tdWxkZXJzL2FtYXR0ZXJvZnRpbWUvZGF0YS9wcm9jZXNzZWQvcGhkZmllbGQucmRhIik6IHByb2Nlc3NlZCBleGFtcGxlIGRhdGFzZXQgb2YgUGhEcyB3aXRoIGdlbmRlciwgZXRobmljaXR5IGFuZCBmaWVsZCB2YXJpYWJsZXMNCiAgICAtIG5hbWUgb2YgZGF0YXNldDogYHBoZF9maWVsZGAgLyBgcGhkX2RmYCANCiAgICANCkZ1cnRoZXIsIHdlIHVzZSBvbmUgcmF3IGRhdGFzZXQ6DQoqIFtwdWJzX21ldGFkZl0oImh0dHBzOi8vZ2l0aHViLmNvbS9hbW11bGRlcnMvYW1hdHRlcm9mdGltZS9kYXRhL3B1YnNfbWV0YWRmLnJkYSIpOiBwdWJsaWNhdGlvbnMgZGF0YXNldCAgIA0KICAgIC0gbmFtZSBvZiBkYXRhc2V0OiBgcHVic19tZXRhZGZgIA0KDQoNCmBgYHtyIGRhdGF9DQoNCmxvYWQoZmlsZSA9ICIuL2RhdGEvcHJvY2Vzc2VkL3BoZGZpZWxkLnJkYSIpDQpwaGRfZGYgPC0gcGhkZmllbGQNCg0KbG9hZChmaWxlID0gIi4vZGF0YS9wdWJzX21ldGFkZi5yZGEiKQ0KDQpgYGANCg0KDQoNCg0KIyBDcmVhdGluZyBhIHBlcnNvbi1wZXJpb2QgZmlsZQ0KDQpXZSBzdGFydCBieSBjbGVhbmluZyB1cCB0aGUgcHVibGljYXRpb25zIGRhdGEsIGFuZCB0aGVuIHN1bW1hcml6ZSB0aGUgcHVibGljYXRpb25zIHBlciBQaEQgcGVyIHllYXIgKGkuZS4gYSBwZXJzb24tcGVyaW9kIGRhdGEgZm9ybWF0KS4gDQoNCg0KYGBge3J9DQoNCnB1YnNfbWV0YWRmJHR5cGUgPC0gYXMuZmFjdG9yKHB1YnNfbWV0YWRmJHR5cGUpDQoNCiMgc2VsZWN0aW5nIG9ubHkgYXJ0aWNsZXMsIGJvb2tzIGFuZCBib29rIGNoYXB0ZXJzDQpwdWJzX21ldGFkZiA8LSBwdWJzX21ldGFkZlsocHVic19tZXRhZGYkdHlwZT09IkFydGlrZWwiKSB8IChwdWJzX21ldGFkZiR0eXBlPT0iQm9layIgfCAocHVic19tZXRhZGYkdHlwZT09IkJvZWtkZWVsIikpLCBdICANCg0KIyBkZXJpdmUgcHVibGljYXRpb24geWVhciBmcm9tIHZhcmlhYmxlIERhdGEuaXNzdWVkDQpwdWJzX21ldGFkZiA8LSBwdWJzX21ldGFkZlshaXMubmEocHVic19tZXRhZGYkZGF0ZS5pc3N1ZWQpLF0NCg0KDQpwdWJzX21ldGFkZiAlPiUgDQogIG11dGF0ZShwdWJfeWVhciA9IGFzLmNoYXJhY3RlcihkYXRlLmlzc3VlZCkpICU+JQ0KICBtdXRhdGUocHViX3llYXIgPSBzdWJzdHIocHViX3llYXIsIDEsNCkpICU+JQ0KICBtdXRhdGUocHViX3llYXIgPSBhcy5udW1lcmljKHB1Yl95ZWFyKSkgLT4gcHVic19tZXRhZGYNCg0KIyBsYXN0IGNvbXBsZXRlIHllYXIgb2YgcHVibGljYXRpb25zIGRhdGEgaXMgMjAyMiwgc28gcmVtb3ZlIHB1YmxpY2F0aW9ucyBmcm9tIHRoZSBmb2xsb3dpbmcgeWVhcnMNCnB1YnNfbWV0YWRmIDwtIHB1YnNfbWV0YWRmW3B1YnNfbWV0YWRmJHB1Yl95ZWFyPDIwMjMsXQ0KDQoNCiMgbm93LCB3ZSBjcmVhdGUgYSBwZXJzb24tcGVyaW9kIGZpbGU6IG9uZSByb3cgcGVyIFBoRCBwZXIgeWVhcg0KcHVic19tZXRhZGYgJT4lIA0KICBncm91cF9ieShpZCwgcHViX3llYXIpICU+JQ0KICBkcGx5cjo6c3VtbWFyaXplKG5wdWJzID0gbigpLA0KICAgICAgICAgICAgaWQgPSBmaXJzdChpZCkpIC0+IGRmX3BwZg0KDQoNCmBgYA0KDQpUaGF0IGxvb2tzIHNvbWV0aGluZyBsaWtlIHRoaXM6IA0KDQpgYGB7cn0NCg0Ka25pdHI6OmthYmxlKGRmX3BwZiwgZm9ybWF0PSJtYXJrZG93biIpDQoNCmBgYA0KDQoNCg0KDQojIFN0YXJ0aW5nIHRvIHB1Ymxpc2gNCg0KV2UgY3JlYXRlIGEgdmFyaWFibGUgZm9yIHdoZXRoZXIgYSBwZXJzb24gaGFzIHN0YXJ0ZWQgcHVibGlzaGluZyB3aXRoaW4gMyB5ZWFycyBhZnRlciB0aGVpciBQaEQsIGJ5IGxvb2tpbmcgYXQgdGhlIHllYXIgb2YgZmlyc3QgcHVibGljYXRpb24gYW5kIHRoZSBQaEQgeWVhci4gIA0KDQpgYGB7cn0NCg0KIyBXZSBhZGQgUGhEIHllYXIgdG8gdGhlIHBlcnNvbi1wZXJpb2QgZmlsZSB0byBzZWxlY3Qgb25seSBwdWJsaWNhdGlvbnMgZnJvbSBhZnRlciB0aGUgUGhEIHllYXINCnllYXIgPC0gc3Vic2V0KHBoZF9kZiwgc2VsZWN0PWMoaWQsIHBoZF95ZWFyKSkNCnN0YXJ0aW5nIDwtIGRmX3BwZiAlPiUgbGVmdF9qb2luKHllYXIsIGJ5ID0gImlkIikgDQoNCnN0YXJ0aW5nIDwtIHN0YXJ0aW5nW3N0YXJ0aW5nJHBoZF95ZWFyPHN0YXJ0aW5nJHB1Yl95ZWFyLF0gIyBvbmx5IHB1YnMgYWZ0ZXIgUGhEDQoNCg0KIyBXZSBhZGQgdGhlIHllYXIgaW4gd2hpY2ggYSBwZXJzb24gZmlyc3QgcHVibGlzaGVkIGFmdGVyIG9idGFpbmluZyB0aGVpciBQaEQNCnN0YXJ0aW5nICU+JQ0KICBncm91cF9ieShpZCkgJT4lDQogIGRwbHlyOjpzdW1tYXJpemUocHViX21pbiA9IG1pbihwdWJfeWVhcikpICU+JQ0KICB1bmdyb3VwKCkgLT4gbWlucHViDQoNCnN0YXJ0aW5nICU+JQ0KICBsZWZ0X2pvaW4obWlucHViLCBieSA9ICJpZCIpIC0+IHN0YXJ0aW5nDQoNCnN0YXJ0aW5nIDwtIG5hLm9taXQoc3RhcnRpbmcpICMgcmVtb3ZlIG1pc3NpbmdzIA0KDQpzdGFydGluZyA8LSBzdWJzZXQoc3RhcnRpbmcsIHNlbGVjdD0tYyhwaGRfeWVhcikpICMgcmVtb3ZlIHBoZCB5ZWFyIHZhcmlhYmxlIGFnYWluLCBiZWNhdXNlIGl0IHdpbGwgYmUgYWRkZWQgdG8gdGhlIGRhdGEgd2hlbiBtZXJnaW5nIHdpdGggcGhkX2RmDQoNCg0KIyBOb3cgd2UgY29tYmluZSBjb21iaW5lIHRoZSBQaEQgZGF0YSB3aXRoIHRoZSBwdWJsaWNhdGlvbnMgZGF0YQ0Kc3RhcnRpbmcgJT4lIGlubmVyX2pvaW4ocGhkX2RmLCBieT0iaWQiKSAtPiBzdGFydGluZw0KDQoNCiMgQ3JlYXRpbmcgYSB2YXJpYWJsZSBmb3Igd2hldGhlciBhIHBlcnNvbiBoYXMgcHVibGlzaGVkIHdpdGhpbiB0aHJlZSB5ZWFycyBhZnRlciB0aGUgUGhEDQojIGluIG90aGVyIHdvcmRzLCB0aGUgZmlyc3QgcHVibGljYXRpb24gc2hvdWxkIG9jY3VyIGxlc3MgdGhhbiBmb3VyIHllYXJzIGFmdGVyIHRoZSB5ZWFyIGluIHdoaWNoIHRoZWlyIGRpc3NlcnRhdGlvbiB3YXMgcHVibGlzaGVkDQpzdGFydGluZyRzdGFydF9wdWIgPC0gaWZlbHNlKHN0YXJ0aW5nJHB1Yl9taW4gPCAoc3RhcnRpbmckcGhkX3llYXIgKyA0KSwgMSwgMCkNCg0KYGBgDQoNCg0KTmV4dCwgd2UgYWRkIHRoZSAic3RhcnRfcHViIiB2YXJpYWJsZSB0byB0aGUgUGhEIGRhdGEuIA0KDQpgYGAge3J9DQoNCiMgc2VsZWN0IG9ubHkgdGhlIHN0YXJ0aW5nIHZhcmlhYmxlIGFuZCBJRCB0byBtYXRjaA0Kc3RhcnRpbmcgJT4lDQogIHNlbGVjdChpZCwgc3RhcnRfcHViKSAtPiBzdGFydGluZw0KDQojIGtlZXAgYSBzaW5nbGUgcm93IHBlciBpbmRpdmlkdWFsDQpzdGFydGluZyA8LSBzdGFydGluZ1shZHVwbGljYXRlZChzdGFydGluZyRpZCksXQ0KDQoNCiMgbWVyZ2Ugb250byB0aGUgUGhEIGRhdGFzZXQNCnBoZF9kZiA8LSBsZWZ0X2pvaW4ocGhkX2RmLCBzdGFydGluZywgYnkgPSAiaWQiKSAgICAgDQoNCnBoZF9kZiRzdGFydF9wdWIgPC0gaWZlbHNlKGlzLm5hKHBoZF9kZiRzdGFydF9wdWIpLCAwLCBwaGRfZGYkc3RhcnRfcHViKSAjIGFsbCB0aG9zZSB3aG8gZG8gbm90IGhhdmUgYSBwcm9maWxlIGF1dG9tYXRpY2FsbHkgc2NvcmUgYSAwDQoNCg0KIyBiZWNhdXNlIHdlIGxvb2sgYXQgaW4gdGhlIDMgeWVhcnMgZm9sbG93aW5nIHRoZSBQaEQgZm9yIHN0YXJ0X3B1Yiwgd2UgZXhjbHVkZSBQaERzIGZyb20gY29ob3J0cyBhZnRlciAyMDE5DQojIGZvciBjb2hvcnRzIDIwMjAgYW5kIGxhdGVyLCB3ZSBoYXZlIGZld2VyIHRoYW4gMyB5ZWFycyBvZiBwdWJsaWNhdGlvbiBkYXRhDQpwaGRfZGYgPC0gcGhkX2RmW3BoZF9kZiRwaGRfeWVhcjwyMDIwLF0NCg0KDQojIGFkZGluZyBhIGNvaG9ydCB2YXJpYWJsZSA6IHBoZF95ZWFyIGNlbnRlcmVkIG9uIHRoZSBtaW5pbXVtDQpwaGRfZGYkcGhkX2NvaG9ydCA8LSBhcy5udW1lcmljKHBoZF9kZiRwaGRfeWVhcikgLSAxOTkwDQoNCg0KYGBgDQoNCg0KDQpBbmQgc2F2ZSB0aGUgZGF0YSBmb3IgdXNlIGluIHRoZSBhbmFseXNlcyBmb3IgInN0YXJ0aW5nIHRvIHB1Ymxpc2giDQpgYGB7ciwgZWNobz1GQUxTRX0NCg0KZGZfc3RhcnRpbmcgPC0gc3Vic2V0KHBoZF9kZiwgc2VsZWN0ID0gYyhpZCwgc3RhcnRfcHViLCB1bmksIHBoZF95ZWFyLCBwaGRfY29ob3J0LCBmaWVsZCwgZmllbGQyLCBldGhuaWNpdHksIGV0aG5pY2l0eTIsIGdlbmRlcikpDQoNCmtuaXRyOjprYWJsZShkZl9zdGFydGluZywgZm9ybWF0PSJtYXJrZG93biIpDQoNCg0KYGBgDQoNCg0KDQojIFN0b3BwaW5nIHRvIHB1Ymxpc2ggDQoNCkZvciB0aGUgYW5hbHlzZXMgdW5kZXIgJ3N0b3BwaW5nIHRvIHB1Ymxpc2gnLCB3ZSBjb250aW51ZSB3aXRoIHRoZSBzYW1wbGUgb2YgUGhEcyB3aG8gaGF2ZSAnc3RhcnRlZCBwdWJsaXNoaW5nJyBhY2NvcmRpbmcgdG8gYW5hbHlzaXMgIzEuIA0KDQoNCmBgYHtyfQ0KDQpkZl9zdG9wcGluZyA8LSBwaGRfZGZbcGhkX2RmJHN0YXJ0X3B1Yj09MSwgXQ0KDQpkZl9zdG9wcGluZyAlPiUNCiAgc2VsZWN0KC1jKHN0YXJ0X3B1YikpIC0+IGRmX3N0b3BwaW5nDQoNCmBgYA0KDQoNCldlIGFnYWluIG5lZWQgdGhlIHBlcnNvbi1wZXJpb2QgZmlsZSBpbiBvcmRlciB0byBhbmFseXNlIHB1YmxpY2F0aW9ucyBmb3IgUGhEcyBvdmVyIG11bHRpcGxlIHllYXJzLCBidXQgdGhpcyB0aW1lLCB3ZSB3YW50IHRvIGluY2x1ZGUgcm93cyB3aXRoIDAgcHVibGljYXRpb25zLiBUaGlzIG1lYW5zIHdlIGhhdmUgdG8gc3RhcnQgd2l0aCBhbiBlbXB0eSBwZXJzb24tcGVyaW9kIGZpbGUuIA0KDQpgYGB7cn0NCg0KcHViX3llYXIgPC0gYygxOTg4OjIwMjIpICMgdGhpcyBpcyB0aGUgdGltZS13aW5kb3cgaW4gd2hpY2ggd2Ugc2NyYXBlZCBkYXRhLiANCg0KbnB1YnNfemVybyA8LSByZXAoMCwgbGVuZ3RoKHB1Yl95ZWFyKSkgIyBkZWZhdWx0IHRvIDAgcHVibGljYXRpb25zDQoNCmlkIDwtIHVuaXF1ZShkZl9wcGYkaWQpICNpZGVudGlmeSB0aGUgdW5pcXVlIFBIRCBpZHMNCg0KbmlkIDwtIGxlbmd0aChpZCkNCg0KI2Jhc2VkIG9uIHRoaXMgaW5mbyBtYWtlIHRoZSBlbXB0eSBkYXRhc2V0DQpwdWJfeWVhciA8LSByZXAocHViX3llYXIsIG5pZCkNCm5wdWJzX3plcm8gPC0gcmVwKG5wdWJzX3plcm8sIG5pZCkNCmlkIDwtIHJlcChpZCwgZWFjaD1sZW5ndGgoYygxOTg4OjIwMjIpKSkgIA0KZW1wdHlfcHBmIDwtIGRhdGEuZnJhbWUoaWQsIHB1Yl95ZWFyLCBucHVic196ZXJvKQ0KDQpgYGAgDQoNCg0KQWRkaW5nIGluZm8gdG8gdGhlIGVtcHR5IHBlcnNvbi1wZXJpb2QgZmlsZSANCg0KYGBge3J9DQoNCiMgYWRkaW5nIHRpbWUtaW52YXJpYW50IHZhcmlhYmxlcyB0byB0aGUgcGVyc29uLXBlcmlvZCBmaWxlDQpkZl9wcGYgJT4lIGlubmVyX2pvaW4oZGZfc3RvcHBpbmcsIGJ5PSJpZCIpIC0+IGRmX3BwZg0KDQoNCiMgZmlsbGluZyB1cCB0aGUgZW1wdHkgcGVyc29uLXBlcmlvZCBmaWxlIHdpdGggdGhlIGFjdHVhbCBwdWJsaWNhdGlvbnMgZGF0YQ0KZW1wdHlfcHBmICU+JSANCiAgZnVsbF9qb2luKGRmX3BwZiwgYnk9YygiaWQiLCAicHViX3llYXIiKSkgJT4lDQogIGFycmFuZ2UoaWQsIHB1Yl95ZWFyKSAlPiUNCiAgc2VsZWN0KGlkLCBwdWJfeWVhciwgbnB1YnMsIGdlbmRlciwgZXRobmljaXR5LCBldGhuaWNpdHkyLCBmaWVsZCwgZmllbGQyLCB1bmksIHBoZF95ZWFyLCBwaGRfY29ob3J0KSAtPiBkZl9wcGYNCg0KDQojIGFsbCB0aW1lLWNvbnN0YW50IHZhcnMgYXJlIGVtcHR5IGluIHJvd3Mgd2l0aCAwIHB1YnMuIExldCdzIGZpeCB0aGlzLiANCmRmX3BwZiAlPiUNCiAgZ3JvdXBfYnkoaWQpICU+JQ0KICBmaWxsKGdlbmRlciwgLmRpcmVjdGlvbiA9ICJkb3dudXAiKSAlPiUNCiAgZmlsbChldGhuaWNpdHksIC5kaXJlY3Rpb24gPSAiZG93bnVwIikgJT4lDQogIGZpbGwoZXRobmljaXR5MiwgLmRpcmVjdGlvbiA9ICJkb3dudXAiKSAlPiUNCiAgZmlsbChmaWVsZCwgLmRpcmVjdGlvbiA9ICJkb3dudXAiKSAlPiUNCiAgZmlsbChmaWVsZDIsIC5kaXJlY3Rpb24gPSAiZG93bnVwIikgJT4lDQogIGZpbGwodW5pLCAuZGlyZWN0aW9uID0gImRvd251cCIpICU+JQ0KICBmaWxsKHBoZF9jb2hvcnQsIC5kaXJlY3Rpb24gPSAiZG93bnVwIikgJT4lDQogIGZpbGwocGhkX3llYXIsIC5kaXJlY3Rpb24gPSAiZG93bnVwIikgJT4lDQogIHVuZ3JvdXAgKCkgLT4gZGZfcHBmDQoNCiMgcmVwbGFjaW5nIE5BIHZhbHVlcyBpbiBucHVicyB3aXRoIDANCmRmX3BwZiAlPiUgbXV0YXRlKG5wdWJzID0gcmVwbGFjZV9uYShucHVicywgMCkpIC0+IGRmX3BwZg0KDQoNCiMgbmV4dCwgd2UgaW5jbHVkZSBhIHZhcmlhYmxlIHdpdGggdGhlIGF2ZXJhZ2UgbnVtYmVyIG9mIHB1YmxpY2F0aW9ucyBpbiB0aGUgcHJldmlvdXMgeWVhcnMNCiMgcm9sbGluZyBhdmVyYWdlIGhlcmUgY29tcHV0ZXMgdGhlIGF2ZXJhZ2UgbnVtYmVyIG9mIHB1YmxpY2F0aW9ucyBpbiB0aGUgeWVhciB0LCB0LTEgYW5kIHQtMg0KIyB0aGVuIHdlIHRha2UgdGhlIHZhbHVlIG9mIHRoZSByb2xsaW5nIGF2ZXJhZ2UgZm9yIHRoZSBwcmVjZWRpbmcgeWVhciBpbiBucHVic19wcmV2ICh3aGVuIGl0IGlzIHByZXNlbnQpDQojIGZvciB0aGUgZmlyc3QgeWVhciAoMTk4OCksIHdlIHRha2UgdGhlIHZhbHVlIG9mIHRoZSB5ZWFyIGl0c2VsZg0KZGZfcHBmICU+JQ0KICBncm91cF9ieShpZCkgJT4lDQogIG11dGF0ZShucHVic19yb2xsYXZnID0gcm9sbGFwcGx5KG5wdWJzLCAzLCBtZWFuLCBhbGlnbiA9ICJyaWdodCIsIGZpbGwgPSAwKSwgDQogICAgICAgICBucHVic19wcmV2ID0gbGFnKG5wdWJzX3JvbGxhdmcsIG49MSwgb3JkZXJfYnkgPSBwdWJfeWVhciksDQogICAgICAgICBucHVic19wcmV2ID0gaWZlbHNlKGlzLm5hKG5wdWJzX3ByZXYpLCBsZWFkKG5wdWJzX3ByZXYsIG49MSwgb3JkZXJfYnkgPSBwdWJfeWVhciksIG5wdWJzX3ByZXYpKSAlPiUNCiAgdW5ncm91cCgpIC0+IGRmX3BwZg0KDQoNCiMgd2UgbG9nLXRyYW5zZm9ybSB0aGUgbnVtYmVyIG9mIHB1YmxpY2F0aW9ucyB0byBhY2NvdW50IGZvciBvdXRsaWVycyANCmRmX3BwZiRucHVic19wcmV2X3MgPC0gbG9nMTAoZGZfcHBmJG5wdWJzX3ByZXYgKyAxKSAjICsxIHRvIGF2b2lkIG5lZ2F0aXZlIGluZmluaXR5DQoNCg0KYGBgDQoNCg0KDQpDcmVhdGluZyB0aGUgdmFyaWFibGUgJ3N0b3BwaW5nIHRvIHB1Ymxpc2gnLiANCg0KYGBge3J9DQoNCiMgY3JlYXRpbmcgYSB0aW1lIHZhcmlhYmxlICg9IGhvdyBtYW55IHllYXJzIHNpbmNlIG9idGFpbmluZyBkb2N0b3JhdGUpOyByZW1vdmluZyB5ZWFycyBiZWZvcmUgZG9jdG9yYXRlIA0KZGZfcHBmICU+JQ0KICBtdXRhdGUodGltZSA9IGFzLm51bWVyaWMocHViX3llYXIgLSBwaGRfeWVhcikpIC0+IGRmX3BwZg0KDQojIFdlIGxvb2sgYXQgY29ob3J0cyAxOTkwLTIwMTgNCiMgYmVjYXVzZSB3ZSBzZWxlY3RlZCBwdWJsaXNoaW5nIHNjaG9sYXJzIGZyb20gdGhlIGFuYWx5c2VzIGZvciAic3RhcnRpbmcgdG8gcHVibGlzaCIsIFBoRHMgZnJvbSBjb2hvcnQgMjAxOSBjYW5ub3QgYmVjb21lIGluYWN0aXZlIGJ5IGRlc2lnbg0KZGZfcHBmMyA8LSBkZl9wcGZbZGZfcHBmJHBoZF95ZWFyPDIwMTksIF0NCg0KDQojIHdlIGNvbXB1dGUgcm9sbGluZyBtYXhpbXVtIGFjcm9zcyAzIHRpbWUgcGVyaW9kcw0KIyBhbGlnbiA9IGxlZnQgZW5zdXJlcyB0aGF0IGl0IGxvb2tzIGZvcndhcmQgaW4gdGltZTogbm8gcHVibGljYXRpb24gYXQgdCwgYnV0IDErIHB1YiBhdCB0KzEgb3IgdCsyIGVuc3VyZXMgbm9uLXplcm8gcHVicyBhdCB0LiANCmRmX3BwZjMgJT4lDQogIGdyb3VwX2J5KGlkKSAlPiUNCiAgbXV0YXRlKG5wdWJzMyA9IHJvbGxhcHBseShucHVicywgMywgc3VtLCBhbGlnbiA9ICJsZWZ0IiwgZmlsbCA9ICJleHRlbmQiKSkgJT4lDQogIHVuZ3JvdXAoKSAtPiBkZl9wcGYzDQoNCiMgaWYgYSBwZXJzb24gZGlkIG5vdCBoYXZlIGFueSBwdWJsaWNhdGlvbnMgaW4gdGhlIHRocmVlIHllYXIgcGVyaW9kIChpLmUuIHRoZSBtYXggaXMgMCksIHdlIGFzc3VtZSBjYXJlZXIgZXhpdA0KZGZfcHBmMyAlPiUNCiAgbXV0YXRlKGluYWN0aXZlID0gaWZlbHNlKChucHViczM+MCksIDAsIDEpKSAtPiBkZl9wcGYzDQoNCg0KIyB3ZSBvbmx5IGxvb2sgYXQgcHVibGljYXRpb25zIGFmdGVyIHRoZSBQaEQNCmRmX3BwZjMgPC0gZGZfcHBmM1soZGZfcHBmMyRwdWJfeWVhciA+IGRmX3BwZjMkcGhkX3llYXIpLCBdDQoNCg0KDQojIGN1cnJlbnRseSwgYSBwZXJzb24gY2FuIGJlY29tZSBpbmFjdGl2ZSwgYW5kIHRoZW4gYWN0aXZlIGFnYWluLiBXZSBvbmx5IGxvb2sgYXQgdGhlIGZpcnN0IHRyYW5zaXRpb24gdG8gaW5hY3Rpdml0eS4gDQpkZl9wcGYzICU+JSANCglncm91cF9ieShpZCkgJT4lIA0KICBkcGx5cjo6YXJyYW5nZSh0aW1lLCAuYnlfZ3JvdXA9VFJVRSkgJT4lDQoJbXV0YXRlKGluYWN0aXZlX2NzID0gY3Vtc3VtKGluYWN0aXZlKSkgJT4lDQogIGZpbHRlcihpbmFjdGl2ZV9jcyA8IDIpIC0+IGRmX3BwZjMNCg0KDQpgYGANCg0KDQoNCkFsdGVybmF0aXZlIHRpbWUgd2luZG93OiA1IHllYXJzDQoNCmBgYHtyfQ0KDQojIEFsdGVybmF0aXZlIHB1YmxpY2F0aW9uIHdpbmRvdzogNSB5ZWFyDQpkZl9wcGY1IDwtIGRmX3BwZltkZl9wcGYkcGhkX3llYXI8MjAxNywgXQ0KZGZfcHBmNSA8LSBkZl9wcGY1ICU+JSBtdXRhdGUobnB1YnMgPSByZXBsYWNlX25hKG5wdWJzLCAwKSkNCg0KIyBSb2xsaW5nIG1heGltdW0gYWNyb3NzIDUgeWVhcnMNCmRmX3BwZjUgJT4lDQogIGdyb3VwX2J5KGlkKSAlPiUNCiAgbXV0YXRlKG5wdWJzNSA9IHJvbGxhcHBseShucHVicywgNSwgc3VtLCBhbGlnbiA9ICJsZWZ0IiwgZmlsbCA9ICJleHRlbmQiKSkgJT4lDQogIHVuZ3JvdXAoKSAtPiBkZl9wcGY1DQoNCmRmX3BwZjUgJT4lDQogIG11dGF0ZShpbmFjdGl2ZSA9IGlmZWxzZSgobnB1YnM1PjApLCAwLCAxKSkgLT4gZGZfcHBmNQ0KDQoNCmRmX3BwZjUgPC0gZGZfcHBmNVsoZGZfcHBmNSRwdWJfeWVhciA+IGRmX3BwZjUkcGhkX3llYXIpLCBdDQoNCg0KIyBNYXguIDEgdGltZSBpbmFjdGl2ZQ0KZGZfcHBmNSAlPiUgDQoJZ3JvdXBfYnkoaWQpICU+JSANCiAgYXJyYW5nZSh0aW1lLCAuYnlfZ3JvdXA9VFJVRSkgJT4lDQoJbXV0YXRlKGluYWN0aXZlX2NzID0gY3Vtc3VtKGluYWN0aXZlKSkgJT4lDQogIGZpbHRlcihpbmFjdGl2ZV9jcyA8IDIpIC0+IGRmX3BwZjUNCg0KDQpkZl9wcGY1IDwtIG5hLm9taXQoZGZfcHBmNSkNCg0KYGBgDQoNCg0KDQoNCg==


Copyright © 2023