This is an R Markdown Notebook. When you execute code within the notebook, the results appear beneath the code.

Try executing this chunk by clicking the Run button within the chunk or by placing your cursor inside it and pressing Cmd+Shift+Enter.

Loading my libraries

library(dplyr)

Attaching package: ‘dplyr’

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union
library(tidyverse)
Warning: package ‘ggplot2’ was built under R version 4.3.3── Attaching core tidyverse packages ───────────────────────────────────────────────────────────────── tidyverse 2.0.0 ──
✔ forcats   1.0.0     ✔ readr     2.1.4
✔ ggplot2   3.5.2     ✔ stringr   1.5.1
✔ lubridate 1.9.3     ✔ tibble    3.2.1
✔ purrr     1.0.2     ✔ tidyr     1.3.0── Conflicts ─────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the ]8;;http://conflicted.r-lib.org/conflicted package]8;; to force all conflicts to become errors
library(readxl)
library(readr)
library(stringr)
library(janitor)
Warning: package ‘janitor’ was built under R version 4.3.3
Attaching package: ‘janitor’

The following objects are masked from ‘package:stats’:

    chisq.test, fisher.test

Here I’m importing the data, and I’m skipping 6 because the first 6 rows of the excel file have summary information, but the data itself doesn’t actually start. Then I’m using Summary to check what my time range is, looking specifically at the Apprehension column.

AdminArrest <- read_excel("/Users/eleanorprickettmorgan/Desktop/DeportationData/AdminArrest.xlsx", skip = 6)
View(AdminArrest)
summary(AdminArrest)
 Apprehension Date                Apprehension State Apprehension County Apprehension AOR   Final Program     
 Min.   :2023-09-01 00:00:00.00   Length:291722      Mode:logical        Length:291722      Length:291722     
 1st Qu.:2024-04-19 06:28:15.00   Class :character   NA's:291722         Class :character   Class :character  
 Median :2024-12-18 17:00:00.00   Mode  :character                       Mode  :character   Mode  :character  
 Mean   :2024-10-23 16:33:28.67                                                                               
 3rd Qu.:2025-05-07 10:15:40.50                                                                               
 Max.   :2025-07-29 01:14:44.00                                                                               
                                                                                                              
 Final Program Group Apprehension Method Apprehension Criminality Case Status        Case Category     
 Length:291722       Length:291722       Length:291722            Length:291722      Length:291722     
 Class :character    Class :character    Class :character         Class :character   Class :character  
 Mode  :character    Mode  :character    Mode  :character         Mode  :character   Mode  :character  
                                                                                                       
                                                                                                       
                                                                                                       
                                                                                                       
 Departed Date                    Departure Country  Final Order Yes No Final Order Date                
 Min.   :1923-09-14 00:00:00.00   Length:291722      Length:291722      Min.   :1967-01-06 00:00:00.00  
 1st Qu.:2024-07-05 00:00:00.00   Class :character   Class :character   1st Qu.:2019-06-05 00:00:00.00  
 Median :2025-02-10 00:00:00.00   Mode  :character   Mode  :character   Median :2024-04-16 00:00:00.00  
 Mean   :2024-12-05 05:22:06.14                                         Mean   :2021-03-03 06:16:09.34  
 3rd Qu.:2025-05-23 00:00:00.00                                         3rd Qu.:2025-02-27 00:00:00.00  
 Max.   :2025-07-28 00:00:00.00                                         Max.   :2025-07-29 00:00:00.00  
 NA's   :123300                                                         NA's   :113703                  
  Birth Date          Birth Year   Citizenship Country    Gender          Apprehension Site Landmark Alien File Number 
 Length:291722      Min.   :1934   Length:291722       Length:291722      Length:291722              Length:291722     
 Class :character   1st Qu.:1983   Class :character    Class :character   Class :character           Class :character  
 Mode  :character   Median :1991   Mode  :character    Mode  :character   Mode  :character           Mode  :character  
                    Mean   :1990                                                                                       
                    3rd Qu.:1998                                                                                       
                    Max.   :2025                                                                                       
                                                                                                                       
 EID Case ID        EID Subject ID     Unique Identifier 
 Length:291722      Length:291722      Length:291722     
 Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character  
                                                         
                                                         
                                                         
                                                         

To check for duplicates I’m going to look at the unique identifier column.

AdminArrest %>%
  group_by(`Unique Identifier`) %>%
  filter(n()==2)
NA

I get back 27,214 rows where the Unique identifier repeated itself. But I can tell that there are certain instances where the same identifier appears twice with a different apprehension date. So I’m going to try again looking at Apprehension Date in addition to the Unique Identifier column.

AdminArrest %>%
  group_by(`Unique Identifier`, `Apprehension Date`) %>%
  filter(n()==2)

When I filter by both of these things I get 3,304 rows. That suggests that maybe certain individuals were apprehended twice, or have been in the system multiple times over the course of many years, this is closer to the true number of duplicates. So now I’m going to remove those potential duplicates using the distinct function.

cleaned_AdminArrest <- AdminArrest %>%
  distinct(`Unique Identifier`,`Apprehension Date`, .keep_all = TRUE)
View(cleaned_AdminArrest)

When I run this I now have 289,927 entries instead of the original 291722. I would probably still ask an expert who works with this data if there are other ways I might not be catching duplicates but this makes the most sense to me.

To check for consistency issues, I’m going to look at the column names dealing primarily with characters. So for example for states I know that I want 50 ideally, and I would check by doing the following:

cleaned_AdminArrest %>%
  group_by(`Apprehension State`) %>%
  tally()

Here there are a couple consistency issues, some of the things included in States are three locations labeled “ARMED FORCES - EUROPE, ARMED FORCES - THE AMERICAS, ARMED SERVICES - THE PACIFIC.” I have no idea what differentiates armed forces vs. services, nor am I clear if these are arrests that took place on military bases or as a part of Military operations. Worth noting that we have 62 rows, instead of 50, which is partially because of territories under US control (i.e. Puerto Rico, Federated States of Micronesia, Guam, etc.) District of Columbia is also it’s own entry, and it’s not a state. There are also two lone entries in areas outside of US control, one just labeled “MEXICO,” the other labeled “TAMAULIPAS,” which is a territory in Mexico. Those seem like individual data entry issues or miscategorizatons. Aside from that, the states themselves are spelled in consistent ways.

Now I’m going to perform a similar test on the AOR column for consistency. From the ICE.gov website I’m expecting 25 AOR’s

cleaned_AdminArrest %>%
  group_by(`Apprehension AOR`) %>%
  tally()
NA

Here I got 27 rows back, one corresponded to N/A, with 5223 entries not assigned to a specific geography. There’s also a mysterious HQ Area of Responsibility, which is not listed online with only 50 entries. I would again have to ask someone who works with this data regularly what this means.

Now I’ll do the same with the final program column:

cleaned_AdminArrest %>%
  group_by(`Final Program`) %>%
  tally()

Here the most obvious issue which populates first is what’s the difference between “287G Program” and “287g Task Force.” Because my project is in California which is (allegedly) not participating in 287g, I’m not worried about that. I would want to double check with an expert that some of these things do not refer to the same practical categories. I am concerned about the 487 Juveniles listed here.

Because this is ICE data, I would assume everything in the final program group column is ICE, but I’m just double checking.

cleaned_AdminArrest %>%
  group_by(`Final Program Group`) %>%
  tally()

That produced just one row, so that’s consistent.

Now I’m checking for apprehension method:

cleaned_AdminArrest %>%
  group_by(`Apprehension Method`) %>%
  tally()

In terms of how things are literally spelled yes there is consistency. In terms of what the data is saying here, I do have a lot of questions. For example only one person is listed as arrested in the “Presented During Inspection” category, which feels like a contradiction with the courthouse and field office check-ins having so many individuals grabbed by ICE. However, those might be a different category of enforcement that’s included in another data set (i.e. detentions). This is probably my flawed understanding of the legal system here, but still something I want to note.

Now I’m going to check for apprehension criminality:

cleaned_AdminArrest %>%
  group_by(`Apprehension Criminality`) %>%
  tally()

Here I get back only three rows, which is consistent with my understanding of folks are categorized in these situations.

Now I’ll check for case status:

cleaned_AdminArrest %>%
  group_by(`Case Status`) %>%
  tally()

Here I get back 14 rows with categories listed. The first chunk are numbered starting at 0, but notably missing 1 and 2. I don’t know what those categories could be. There are 4462 who are not in a category at all, which is confusing because one category is literally just for active cases. There are also some acronyms I don’t understand, “9-VR Witnessed” I assume is voluntary removal witnessed, how is that different than voluntary departure? I’m concerned also about the 41 deaths listed. I’d also like to understand the difference between “L-Legalization - Permanent Residence Granted” and “Z-SAW - Permanent Residence Granted.”

Now I’ll look at Case Category:

cleaned_AdminArrest %>%
  group_by(`Case Category`) %>%
  tally()

Here there are no glaring consistency issues except the 4412 uncategorized cases.

Now I’ll check for Departure Country:

cleaned_AdminArrest %>%
  group_by(`Departure Country`) %>%
  tally()

I got back 193 rows which is in line with the number of countries in the world (depending on who you ask, but at least in line with the number of countries the US recognizes). Clicking through I didn’t see any super weird duplicates. One row is N/A but from looking at the other columns in conjunction, I think a departure country is only entered when the departure happens. So the active cases don’t have a departure country listed.

Now I’ll check final order Yes or No (hopefully 2 rows)

cleaned_AdminArrest %>%
  group_by(`Final Order Yes No`) %>%
  tally()

Here we get back Yes, No, or Blank (4412 rows).

Now I’ll look at citizenship country

cleaned_AdminArrest %>%
  group_by(`Citizenship Country`) %>%
  tally()

My citizenship countries outnumber my departure countries by 3, I would want to compare those and see where I have additional citizenship but not departure. Notably no one here is uncategorized.

Now I’m checking for gender which I’m expecting 2 rows for:

cleaned_AdminArrest %>%
  group_by(Gender) %>%
  tally()

We get back three rows: Female, Male, and Unknown. Important to note that unknown is written in, and isn’t just a blank.

Now I’m checking for Apprehension Site Landmark. This is where I’m expecting the most inconsistencies.

cleaned_AdminArrest %>%
  group_by(`Apprehension Site Landmark`) %>%
  tally()

Here I get back 500 rows, and there are major differences in capitalization and usage of Dashes. Some include the state they were in, others do not. Some also includde the program they were in (297(g), CAP, etc.). For the purposes of my project I’d probably take the California subset and clean that, but this would likely be the most onerous part of working with this data.

Now to check for missing data, I’m going to use/refer to the original unclean data “AdminArrest”:

MissingData <-colSums(is.na(AdminArrest))
print(MissingData)
         Apprehension Date         Apprehension State        Apprehension County           Apprehension AOR 
                         0                      56709                     291722                       5976 
             Final Program        Final Program Group        Apprehension Method   Apprehension Criminality 
                         0                          0                          0                          0 
               Case Status              Case Category              Departed Date          Departure Country 
                      4450                       4450                     123300                     123341 
        Final Order Yes No           Final Order Date                 Birth Date                 Birth Year 
                      4450                     113703                          0                          0 
       Citizenship Country                     Gender Apprehension Site Landmark          Alien File Number 
                         0                          0                       6264                       2471 
               EID Case ID             EID Subject ID          Unique Identifier 
                      4450                          0                       2473 

I want to mutate the apprehension date column so that I can filter later by year and month, and even potentially the time of day an administrative arrest took place.

new_AdminArrest <-cleaned_AdminArrest%>% 
  mutate(ApprehensionYear = year(`Apprehension Date`) )%>% 
   mutate(ApprehensionMonth = month(`Apprehension Date`))%>% 
  mutate(ApprehensionDay = day(`Apprehension Date`))%>% 
  mutate(ApprehensionHour = hour(`Apprehension Date`))

View(new_AdminArrest)

Now I want to look at just administrative arrests in California, so I’m going to filter by the apprehension state column.

CA_AdminArrest <- new_AdminArrest %>%
  filter(`Apprehension State` == "CALIFORNIA")
View(CA_AdminArrest)

I want to filter that further to just the Administrative arrests in the SF Area of Responsibility, because even though that’s actually a lot larger than the geographic scope my project is looking at, it at least includes my area the Bay Area.

SFAOR_AdminArrest <- CA_AdminArrest %>% 
  filter(`Apprehension AOR` == "San Francisco Area of Responsibility")
View(SFAOR_AdminArrest)

ANALYSIS SECTION:

A really basic comparison I might make to start is comparing the number of Administrative Arrests by year.

SFAOR_AdminArrest %>% 
  group_by(ApprehensionYear) %>% 
  tally()

But the table I get here actually isn’t that informative given that I only have data from three years. But maybe I just want to see the change in time by month of just this new administration (2025), So I’d likely do the following:

SFAOR_AdminArrestbyMonth <-SFAOR_AdminArrest %>% 
  filter(ApprehensionYear == "2025") %>% 
  group_by(ApprehensionMonth) %>% 
  tally()
View(SFAOR_AdminArrestbyMonth)

Just looking at the table I see there’s an increase in June which held in July, but it might be helpful to visualize it, so I’m going to look at plot it out:

ggplot(data=SFAOR_AdminArrestbyMonth) +
  geom_line(aes(x=ApprehensionMonth, y=n)) +
  xlim(1,8) +
  ylim(0,600) +
  labs( x = "Month", y = "Number of Arrests")

  ggtitle("Administrative Arrests by Month") 
$title
[1] "Administrative Arrests by Month"

attr(,"class")
[1] "labels"
  

Anecdotally, I’ve also heard this thing from a number of advocates that ICE actions (arrests) tend to happen in the early morning. I want to check if that’s true, so I’m going to look at the ApprehensionHour column that I mutated out of the original Apprehension Date column. It’s on a 24 hour clock (no am/pm). I’m going to use the CA_AdminArrest data because according to advocates this represents ICE policy so it should be true across the state.

CA_AdminArrest_byHour <- CA_AdminArrest %>%
  group_by(ApprehensionHour) %>%
  tally()

View(CA_AdminArrest_byHour)

To see that visually I’m going to chart it.

ggplot(data=CA_AdminArrest_byHour, aes(x = ApprehensionHour, y = n)) +
  geom_bar(stat="identity", width=0.5, fill= "steelblue") +
  labs( x = "Hour of the Day", y = "Number of Arrests") +
  ggtitle("Administrative Arrests by Hour of the Day from Sept 2023 through July 2025") +
  scale_x_continuous(n.breaks=23)

This shows that the number of arrests peaks betwen 9 and 10 am, and if the actual arrests are taking place at that hour we can infer that ICE/DHS had to be active before then. The majority of the activity seems to happen between 7am and 1pm.

Another thing I’m interested in is under the current administration, what are the top countries of origin for folks being arrested. I’m interested both statewide and for just the San Francisco AOR, but I’l start with just California

CaliforniaCitizenshipCountry2025 <- CA_AdminArrest %>%
  filter(ApprehensionYear == "2025") %>%
  group_by(`Citizenship Country`) %>%
  tally() 

View(CaliforniaCitizenshipCountry2025)

When I do this and sort by values my top 10 citizenship countries are Mexico, Guatemala, El Salvador, Colombia, Honduras, India, Venezuela, China, Nicaragua and Peru. To compare this to the SFAOR I’m doing a similar analysis

SFAORCitizenshipCountry2025 <- SFAOR_AdminArrest %>%
  filter(ApprehensionYear == "2025") %>%
  group_by(`Citizenship Country`) %>%
  tally() 

View(SFAORCitizenshipCountry2025)

When I sort this table by the count, I get slightly different results, but there is a lot of overlap. In the San Francisco Area of Responsibility the top 10 citizenship countries for arrested folks are Mexico, India, Guatemala, El Salvador, Colombia, Honduras, Peru, Nicaragua, Venezuela, and China. Mexico notably outpaces the rest of these places in number of arrests.

Something else I’m interested in is the “criminality” of those arrested in the San Francisco Area of responsibility. Again I want to look just in the context of the current administration. Those who are arrested are assigned to one of three categories of criminality, but I’m interested in the proportion that those categories show up in arrests.

SFAORArrestCriminality2025 <- SFAOR_AdminArrest %>%
  filter(ApprehensionYear == "2025") %>%
  group_by(`Apprehension Criminality`) %>%
  tally() 

View(SFAORArrestCriminality2025)

For those arrested the majority are convicted criminals, according to the data, but it’s notable that a sizable chunk are categorized under “other immigration violation.” Arrests are supposed to represent individuals have a real case against them, so the convicted criminal category should represented the majority. And these arrests are not the totality of deportations, if you look at the deportation data set in addition to this arrests data, you would find the majority of folks coming in to contact with ICE/DHS do not have any criminal convictions. It’s also worth noting that the convicted criminal category doesn’t break down further into what crimes folks were convicted of. Other reporting has confirmed that there are many folks who end up arrested where the basis of their conviction is a traffic violation. I talked to one lawyer in the Bay Area who confirmed they had a client where a prior conviction came in the form of a citation for failing to pay for BART. Are those crimes the same as murder? No, but under this categorization they’re flattened into one category together.

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKVGhpcyBpcyBhbiBbUiBNYXJrZG93bl0oaHR0cDovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbSkgTm90ZWJvb2suIFdoZW4geW91IGV4ZWN1dGUgY29kZSB3aXRoaW4gdGhlIG5vdGVib29rLCB0aGUgcmVzdWx0cyBhcHBlYXIgYmVuZWF0aCB0aGUgY29kZS4gCgpUcnkgZXhlY3V0aW5nIHRoaXMgY2h1bmsgYnkgY2xpY2tpbmcgdGhlICpSdW4qIGJ1dHRvbiB3aXRoaW4gdGhlIGNodW5rIG9yIGJ5IHBsYWNpbmcgeW91ciBjdXJzb3IgaW5zaWRlIGl0IGFuZCBwcmVzc2luZyAqQ21kK1NoaWZ0K0VudGVyKi4gCgpMb2FkaW5nIG15IGxpYnJhcmllcwoKYGBge3J9CmxpYnJhcnkoZHBseXIpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHJlYWR4bCkKbGlicmFyeShyZWFkcikKbGlicmFyeShzdHJpbmdyKQpsaWJyYXJ5KGphbml0b3IpCmBgYApIZXJlIEknbSBpbXBvcnRpbmcgdGhlIGRhdGEsIGFuZCBJJ20gc2tpcHBpbmcgNiBiZWNhdXNlIHRoZSBmaXJzdCA2IHJvd3Mgb2YgdGhlIGV4Y2VsIGZpbGUgaGF2ZSBzdW1tYXJ5IGluZm9ybWF0aW9uLCBidXQgdGhlIGRhdGEgaXRzZWxmIGRvZXNuJ3QgYWN0dWFsbHkgc3RhcnQuIFRoZW4gSSdtIHVzaW5nIFN1bW1hcnkgdG8gY2hlY2sgd2hhdCBteSB0aW1lIHJhbmdlIGlzLCBsb29raW5nIHNwZWNpZmljYWxseSBhdCB0aGUgQXBwcmVoZW5zaW9uIGNvbHVtbi4gCgpgYGB7cn0KQWRtaW5BcnJlc3QgPC0gcmVhZF9leGNlbCgiL1VzZXJzL2VsZWFub3Jwcmlja2V0dG1vcmdhbi9EZXNrdG9wL0RlcG9ydGF0aW9uRGF0YS9BZG1pbkFycmVzdC54bHN4Iiwgc2tpcCA9IDYpClZpZXcoQWRtaW5BcnJlc3QpCnN1bW1hcnkoQWRtaW5BcnJlc3QpCmBgYApUbyBjaGVjayBmb3IgZHVwbGljYXRlcyBJJ20gZ29pbmcgdG8gbG9vayBhdCB0aGUgdW5pcXVlIGlkZW50aWZpZXIgY29sdW1uLiAKCmBgYHtyfQpBZG1pbkFycmVzdCAlPiUKICBncm91cF9ieShgVW5pcXVlIElkZW50aWZpZXJgKSAlPiUKICBmaWx0ZXIobigpPT0yKQoKYGBgCkkgZ2V0IGJhY2sgMjcsMjE0IHJvd3Mgd2hlcmUgdGhlIFVuaXF1ZSBpZGVudGlmaWVyIHJlcGVhdGVkIGl0c2VsZi4gQnV0IEkgY2FuIHRlbGwgdGhhdCB0aGVyZSBhcmUgY2VydGFpbiBpbnN0YW5jZXMgd2hlcmUgdGhlIHNhbWUgaWRlbnRpZmllciBhcHBlYXJzIHR3aWNlIHdpdGggYSBkaWZmZXJlbnQgYXBwcmVoZW5zaW9uIGRhdGUuIFNvIEknbSBnb2luZyB0byB0cnkgYWdhaW4gbG9va2luZyBhdCBBcHByZWhlbnNpb24gRGF0ZSBpbiBhZGRpdGlvbiB0byB0aGUgVW5pcXVlIElkZW50aWZpZXIgY29sdW1uLiAKCmBgYHtyfQpBZG1pbkFycmVzdCAlPiUKICBncm91cF9ieShgVW5pcXVlIElkZW50aWZpZXJgLCBgQXBwcmVoZW5zaW9uIERhdGVgKSAlPiUKICBmaWx0ZXIobigpPT0yKQpgYGAKV2hlbiBJIGZpbHRlciBieSBib3RoIG9mIHRoZXNlIHRoaW5ncyBJIGdldCAzLDMwNCByb3dzLiBUaGF0IHN1Z2dlc3RzIHRoYXQgbWF5YmUgY2VydGFpbiBpbmRpdmlkdWFscyB3ZXJlIGFwcHJlaGVuZGVkIHR3aWNlLCBvciBoYXZlIGJlZW4gaW4gdGhlIHN5c3RlbSBtdWx0aXBsZSB0aW1lcyBvdmVyIHRoZSBjb3Vyc2Ugb2YgbWFueSB5ZWFycywgdGhpcyBpcyBjbG9zZXIgdG8gdGhlIHRydWUgbnVtYmVyIG9mIGR1cGxpY2F0ZXMuIFNvIG5vdyBJJ20gZ29pbmcgdG8gcmVtb3ZlIHRob3NlIHBvdGVudGlhbCBkdXBsaWNhdGVzIHVzaW5nIHRoZSBkaXN0aW5jdCBmdW5jdGlvbi4gCgpgYGB7cn0KY2xlYW5lZF9BZG1pbkFycmVzdCA8LSBBZG1pbkFycmVzdCAlPiUKICBkaXN0aW5jdChgVW5pcXVlIElkZW50aWZpZXJgLGBBcHByZWhlbnNpb24gRGF0ZWAsIC5rZWVwX2FsbCA9IFRSVUUpClZpZXcoY2xlYW5lZF9BZG1pbkFycmVzdCkKYGBgCgpXaGVuIEkgcnVuIHRoaXMgSSBub3cgaGF2ZSAyODksOTI3IGVudHJpZXMgaW5zdGVhZCBvZiB0aGUgb3JpZ2luYWwgMjkxNzIyLiBJIHdvdWxkIHByb2JhYmx5IHN0aWxsIGFzayBhbiBleHBlcnQgd2hvIHdvcmtzIHdpdGggdGhpcyBkYXRhIGlmIHRoZXJlIGFyZSBvdGhlciB3YXlzIEkgbWlnaHQgbm90IGJlIGNhdGNoaW5nIGR1cGxpY2F0ZXMgYnV0IHRoaXMgbWFrZXMgdGhlIG1vc3Qgc2Vuc2UgdG8gbWUuIAoKVG8gY2hlY2sgZm9yIGNvbnNpc3RlbmN5IGlzc3VlcywgSSdtIGdvaW5nIHRvIGxvb2sgYXQgdGhlIGNvbHVtbiBuYW1lcyBkZWFsaW5nIHByaW1hcmlseSB3aXRoIGNoYXJhY3RlcnMuIFNvIGZvciBleGFtcGxlIGZvciBzdGF0ZXMgSSBrbm93IHRoYXQgSSB3YW50IDUwIGlkZWFsbHksIGFuZCBJIHdvdWxkIGNoZWNrIGJ5IGRvaW5nIHRoZSBmb2xsb3dpbmc6CgpgYGB7cn0KY2xlYW5lZF9BZG1pbkFycmVzdCAlPiUKICBncm91cF9ieShgQXBwcmVoZW5zaW9uIFN0YXRlYCkgJT4lCiAgdGFsbHkoKQpgYGAKCkhlcmUgdGhlcmUgYXJlIGEgY291cGxlIGNvbnNpc3RlbmN5IGlzc3Vlcywgc29tZSBvZiB0aGUgdGhpbmdzIGluY2x1ZGVkIGluIFN0YXRlcyBhcmUgdGhyZWUgbG9jYXRpb25zIGxhYmVsZWQgIkFSTUVEIEZPUkNFUyAtIEVVUk9QRSwgQVJNRUQgRk9SQ0VTIC0gVEhFIEFNRVJJQ0FTLCBBUk1FRCBTRVJWSUNFUyAtIFRIRSBQQUNJRklDLiIgSSBoYXZlIG5vIGlkZWEgd2hhdCBkaWZmZXJlbnRpYXRlcyBhcm1lZCBmb3JjZXMgdnMuIHNlcnZpY2VzLCBub3IgYW0gSSBjbGVhciBpZiB0aGVzZSBhcmUgYXJyZXN0cyB0aGF0IHRvb2sgcGxhY2Ugb24gbWlsaXRhcnkgYmFzZXMgb3IgYXMgYSBwYXJ0IG9mIE1pbGl0YXJ5IG9wZXJhdGlvbnMuIFdvcnRoIG5vdGluZyB0aGF0IHdlIGhhdmUgNjIgcm93cywgaW5zdGVhZCBvZiA1MCwgd2hpY2ggaXMgcGFydGlhbGx5IGJlY2F1c2Ugb2YgdGVycml0b3JpZXMgdW5kZXIgVVMgY29udHJvbCAoaS5lLiBQdWVydG8gUmljbywgRmVkZXJhdGVkIFN0YXRlcyBvZiBNaWNyb25lc2lhLCBHdWFtLCBldGMuKSBEaXN0cmljdCBvZiBDb2x1bWJpYSBpcyBhbHNvIGl0J3Mgb3duIGVudHJ5LCBhbmQgaXQncyBub3QgYSBzdGF0ZS4gVGhlcmUgYXJlIGFsc28gdHdvIGxvbmUgZW50cmllcyBpbiBhcmVhcyBvdXRzaWRlIG9mIFVTIGNvbnRyb2wsIG9uZSBqdXN0IGxhYmVsZWQgIk1FWElDTywiIHRoZSBvdGhlciBsYWJlbGVkICJUQU1BVUxJUEFTLCIgd2hpY2ggaXMgYSB0ZXJyaXRvcnkgaW4gTWV4aWNvLiBUaG9zZSBzZWVtIGxpa2UgaW5kaXZpZHVhbCBkYXRhIGVudHJ5IGlzc3VlcyBvciBtaXNjYXRlZ29yaXphdG9ucy4gQXNpZGUgZnJvbSB0aGF0LCB0aGUgc3RhdGVzIHRoZW1zZWx2ZXMgYXJlIHNwZWxsZWQgaW4gY29uc2lzdGVudCB3YXlzLiAKCk5vdyBJJ20gZ29pbmcgdG8gcGVyZm9ybSBhIHNpbWlsYXIgdGVzdCBvbiB0aGUgQU9SIGNvbHVtbiBmb3IgY29uc2lzdGVuY3kuIEZyb20gdGhlIElDRS5nb3Ygd2Vic2l0ZSBJJ20gZXhwZWN0aW5nIDI1IEFPUidzCgpgYGB7cn0KY2xlYW5lZF9BZG1pbkFycmVzdCAlPiUKICBncm91cF9ieShgQXBwcmVoZW5zaW9uIEFPUmApICU+JQogIHRhbGx5KCkKCmBgYApIZXJlIEkgZ290IDI3IHJvd3MgYmFjaywgb25lIGNvcnJlc3BvbmRlZCB0byBOL0EsIHdpdGggNTIyMyBlbnRyaWVzIG5vdCBhc3NpZ25lZCB0byBhIHNwZWNpZmljIGdlb2dyYXBoeS4gVGhlcmUncyBhbHNvIGEgbXlzdGVyaW91cyBIUSBBcmVhIG9mIFJlc3BvbnNpYmlsaXR5LCB3aGljaCBpcyBub3QgbGlzdGVkIG9ubGluZSB3aXRoIG9ubHkgNTAgZW50cmllcy4gSSB3b3VsZCBhZ2FpbiBoYXZlIHRvIGFzayBzb21lb25lIHdobyB3b3JrcyB3aXRoIHRoaXMgZGF0YSByZWd1bGFybHkgd2hhdCB0aGlzIG1lYW5zLiAKCk5vdyBJJ2xsIGRvIHRoZSBzYW1lIHdpdGggdGhlIGZpbmFsIHByb2dyYW0gY29sdW1uOiAKCmBgYHtyfQpjbGVhbmVkX0FkbWluQXJyZXN0ICU+JQogIGdyb3VwX2J5KGBGaW5hbCBQcm9ncmFtYCkgJT4lCiAgdGFsbHkoKQpgYGAKCkhlcmUgdGhlIG1vc3Qgb2J2aW91cyBpc3N1ZSB3aGljaCBwb3B1bGF0ZXMgZmlyc3QgaXMgd2hhdCdzIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gIjI4N0cgUHJvZ3JhbSIgYW5kICIyODdnIFRhc2sgRm9yY2UuIiBCZWNhdXNlIG15IHByb2plY3QgaXMgaW4gQ2FsaWZvcm5pYSB3aGljaCBpcyAoYWxsZWdlZGx5KSBub3QgcGFydGljaXBhdGluZyBpbiAyODdnLCBJJ20gbm90IHdvcnJpZWQgYWJvdXQgdGhhdC4gSSB3b3VsZCB3YW50IHRvIGRvdWJsZSBjaGVjayB3aXRoIGFuIGV4cGVydCB0aGF0IHNvbWUgb2YgdGhlc2UgdGhpbmdzIGRvIG5vdCByZWZlciB0byB0aGUgc2FtZSBwcmFjdGljYWwgY2F0ZWdvcmllcy4gSSBhbSBjb25jZXJuZWQgYWJvdXQgdGhlIDQ4NyBKdXZlbmlsZXMgbGlzdGVkIGhlcmUuCgpCZWNhdXNlIHRoaXMgaXMgSUNFIGRhdGEsIEkgd291bGQgYXNzdW1lIGV2ZXJ5dGhpbmcgaW4gdGhlIGZpbmFsIHByb2dyYW0gZ3JvdXAgY29sdW1uIGlzIElDRSwgYnV0IEknbSBqdXN0IGRvdWJsZSBjaGVja2luZy4gCgpgYGB7cn0KY2xlYW5lZF9BZG1pbkFycmVzdCAlPiUKICBncm91cF9ieShgRmluYWwgUHJvZ3JhbSBHcm91cGApICU+JQogIHRhbGx5KCkKYGBgClRoYXQgcHJvZHVjZWQganVzdCBvbmUgcm93LCBzbyB0aGF0J3MgY29uc2lzdGVudC4gCgpOb3cgSSdtIGNoZWNraW5nIGZvciBhcHByZWhlbnNpb24gbWV0aG9kOgoKYGBge3J9CmNsZWFuZWRfQWRtaW5BcnJlc3QgJT4lCiAgZ3JvdXBfYnkoYEFwcHJlaGVuc2lvbiBNZXRob2RgKSAlPiUKICB0YWxseSgpCmBgYApJbiB0ZXJtcyBvZiBob3cgdGhpbmdzIGFyZSBsaXRlcmFsbHkgc3BlbGxlZCB5ZXMgdGhlcmUgaXMgY29uc2lzdGVuY3kuIEluIHRlcm1zIG9mIHdoYXQgdGhlIGRhdGEgaXMgc2F5aW5nIGhlcmUsIEkgZG8gaGF2ZSBhIGxvdCBvZiBxdWVzdGlvbnMuIEZvciBleGFtcGxlIG9ubHkgb25lIHBlcnNvbiBpcyBsaXN0ZWQgYXMgYXJyZXN0ZWQgaW4gdGhlICJQcmVzZW50ZWQgRHVyaW5nIEluc3BlY3Rpb24iIGNhdGVnb3J5LCB3aGljaCBmZWVscyBsaWtlIGEgY29udHJhZGljdGlvbiB3aXRoIHRoZSBjb3VydGhvdXNlIGFuZCBmaWVsZCBvZmZpY2UgY2hlY2staW5zIGhhdmluZyBzbyBtYW55IGluZGl2aWR1YWxzIGdyYWJiZWQgYnkgSUNFLiBIb3dldmVyLCB0aG9zZSBtaWdodCBiZSBhIGRpZmZlcmVudCBjYXRlZ29yeSBvZiBlbmZvcmNlbWVudCB0aGF0J3MgaW5jbHVkZWQgaW4gYW5vdGhlciBkYXRhIHNldCAoaS5lLiBkZXRlbnRpb25zKS4gVGhpcyBpcyBwcm9iYWJseSBteSBmbGF3ZWQgdW5kZXJzdGFuZGluZyBvZiB0aGUgbGVnYWwgc3lzdGVtIGhlcmUsIGJ1dCBzdGlsbCBzb21ldGhpbmcgSSB3YW50IHRvIG5vdGUuIAoKTm93IEknbSBnb2luZyB0byBjaGVjayBmb3IgYXBwcmVoZW5zaW9uIGNyaW1pbmFsaXR5OiAKCmBgYHtyfQpjbGVhbmVkX0FkbWluQXJyZXN0ICU+JQogIGdyb3VwX2J5KGBBcHByZWhlbnNpb24gQ3JpbWluYWxpdHlgKSAlPiUKICB0YWxseSgpCmBgYAoKSGVyZSBJIGdldCBiYWNrIG9ubHkgdGhyZWUgcm93cywgd2hpY2ggaXMgY29uc2lzdGVudCB3aXRoIG15IHVuZGVyc3RhbmRpbmcgb2YgZm9sa3MgYXJlIGNhdGVnb3JpemVkIGluIHRoZXNlIHNpdHVhdGlvbnMuIAoKTm93IEknbGwgY2hlY2sgZm9yIGNhc2Ugc3RhdHVzOgoKYGBge3J9CmNsZWFuZWRfQWRtaW5BcnJlc3QgJT4lCiAgZ3JvdXBfYnkoYENhc2UgU3RhdHVzYCkgJT4lCiAgdGFsbHkoKQpgYGAKSGVyZSBJIGdldCBiYWNrIDE0IHJvd3Mgd2l0aCBjYXRlZ29yaWVzIGxpc3RlZC4gVGhlIGZpcnN0IGNodW5rIGFyZSBudW1iZXJlZCBzdGFydGluZyBhdCAwLCBidXQgbm90YWJseSBtaXNzaW5nIDEgYW5kIDIuIEkgZG9uJ3Qga25vdyB3aGF0IHRob3NlIGNhdGVnb3JpZXMgY291bGQgYmUuIFRoZXJlIGFyZSA0NDYyIHdobyBhcmUgbm90IGluIGEgY2F0ZWdvcnkgYXQgYWxsLCB3aGljaCBpcyBjb25mdXNpbmcgYmVjYXVzZSBvbmUgY2F0ZWdvcnkgaXMgbGl0ZXJhbGx5IGp1c3QgZm9yIGFjdGl2ZSBjYXNlcy4gVGhlcmUgYXJlIGFsc28gc29tZSBhY3JvbnltcyBJIGRvbid0IHVuZGVyc3RhbmQsICI5LVZSIFdpdG5lc3NlZCIgSSBhc3N1bWUgaXMgdm9sdW50YXJ5IHJlbW92YWwgd2l0bmVzc2VkLCBob3cgaXMgdGhhdCBkaWZmZXJlbnQgdGhhbiB2b2x1bnRhcnkgZGVwYXJ0dXJlPyBJJ20gY29uY2VybmVkIGFsc28gYWJvdXQgdGhlIDQxIGRlYXRocyBsaXN0ZWQuIEknZCBhbHNvIGxpa2UgdG8gdW5kZXJzdGFuZCB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuICJMLUxlZ2FsaXphdGlvbiAtIFBlcm1hbmVudCBSZXNpZGVuY2UgR3JhbnRlZCIgYW5kCSJaLVNBVyAtIFBlcm1hbmVudCBSZXNpZGVuY2UgR3JhbnRlZC4iCgpOb3cgSSdsbCBsb29rIGF0IENhc2UgQ2F0ZWdvcnk6IAoKYGBge3J9CmNsZWFuZWRfQWRtaW5BcnJlc3QgJT4lCiAgZ3JvdXBfYnkoYENhc2UgQ2F0ZWdvcnlgKSAlPiUKICB0YWxseSgpCmBgYApIZXJlIHRoZXJlIGFyZSBubyBnbGFyaW5nIGNvbnNpc3RlbmN5IGlzc3VlcyBleGNlcHQgdGhlIDQ0MTIgdW5jYXRlZ29yaXplZCBjYXNlcy4gCgpOb3cgSSdsbCBjaGVjayBmb3IgRGVwYXJ0dXJlIENvdW50cnk6CgpgYGB7cn0KY2xlYW5lZF9BZG1pbkFycmVzdCAlPiUKICBncm91cF9ieShgRGVwYXJ0dXJlIENvdW50cnlgKSAlPiUKICB0YWxseSgpCmBgYApJIGdvdCBiYWNrIDE5MyByb3dzIHdoaWNoIGlzIGluIGxpbmUgd2l0aCB0aGUgbnVtYmVyIG9mIGNvdW50cmllcyBpbiB0aGUgd29ybGQgKGRlcGVuZGluZyBvbiB3aG8geW91IGFzaywgYnV0IGF0IGxlYXN0IGluIGxpbmUgd2l0aCB0aGUgbnVtYmVyIG9mIGNvdW50cmllcyB0aGUgVVMgcmVjb2duaXplcykuIENsaWNraW5nIHRocm91Z2ggSSBkaWRuJ3Qgc2VlIGFueSBzdXBlciB3ZWlyZCBkdXBsaWNhdGVzLiBPbmUgcm93IGlzIE4vQSBidXQgZnJvbSBsb29raW5nIGF0IHRoZSBvdGhlciBjb2x1bW5zIGluIGNvbmp1bmN0aW9uLCBJIHRoaW5rIGEgZGVwYXJ0dXJlIGNvdW50cnkgaXMgb25seSBlbnRlcmVkIHdoZW4gdGhlIGRlcGFydHVyZSBoYXBwZW5zLiBTbyB0aGUgYWN0aXZlIGNhc2VzIGRvbid0IGhhdmUgYSBkZXBhcnR1cmUgY291bnRyeSBsaXN0ZWQuIAoKTm93IEknbGwgY2hlY2sgZmluYWwgb3JkZXIgWWVzIG9yIE5vIChob3BlZnVsbHkgMiByb3dzKQoKYGBge3J9CmNsZWFuZWRfQWRtaW5BcnJlc3QgJT4lCiAgZ3JvdXBfYnkoYEZpbmFsIE9yZGVyIFllcyBOb2ApICU+JQogIHRhbGx5KCkKYGBgCkhlcmUgd2UgZ2V0IGJhY2sgWWVzLCBObywgb3IgQmxhbmsgKDQ0MTIgcm93cykuCgpOb3cgSSdsbCBsb29rIGF0IGNpdGl6ZW5zaGlwIGNvdW50cnkKCmBgYHtyfQpjbGVhbmVkX0FkbWluQXJyZXN0ICU+JQogIGdyb3VwX2J5KGBDaXRpemVuc2hpcCBDb3VudHJ5YCkgJT4lCiAgdGFsbHkoKQpgYGAKTXkgY2l0aXplbnNoaXAgY291bnRyaWVzIG91dG51bWJlciBteSBkZXBhcnR1cmUgY291bnRyaWVzIGJ5IDMsIEkgd291bGQgd2FudCB0byBjb21wYXJlIHRob3NlIGFuZCBzZWUgd2hlcmUgSSBoYXZlIGFkZGl0aW9uYWwgY2l0aXplbnNoaXAgYnV0IG5vdCBkZXBhcnR1cmUuIE5vdGFibHkgbm8gb25lIGhlcmUgaXMgdW5jYXRlZ29yaXplZC4gCgpOb3cgSSdtIGNoZWNraW5nIGZvciBnZW5kZXIgd2hpY2ggSSdtIGV4cGVjdGluZyAyIHJvd3MgZm9yOgpgYGB7cn0KY2xlYW5lZF9BZG1pbkFycmVzdCAlPiUKICBncm91cF9ieShHZW5kZXIpICU+JQogIHRhbGx5KCkKYGBgCldlIGdldCBiYWNrIHRocmVlIHJvd3M6IEZlbWFsZSwgTWFsZSwgYW5kIFVua25vd24uIEltcG9ydGFudCB0byBub3RlIHRoYXQgdW5rbm93biBpcyB3cml0dGVuIGluLCBhbmQgaXNuJ3QganVzdCBhIGJsYW5rLiAKCk5vdyBJJ20gY2hlY2tpbmcgZm9yIEFwcHJlaGVuc2lvbiBTaXRlIExhbmRtYXJrLiBUaGlzIGlzIHdoZXJlIEknbSBleHBlY3RpbmcgdGhlIG1vc3QgaW5jb25zaXN0ZW5jaWVzLgoKYGBge3J9CmNsZWFuZWRfQWRtaW5BcnJlc3QgJT4lCiAgZ3JvdXBfYnkoYEFwcHJlaGVuc2lvbiBTaXRlIExhbmRtYXJrYCkgJT4lCiAgdGFsbHkoKQpgYGAKSGVyZSBJIGdldCBiYWNrIDUwMCByb3dzLCBhbmQgdGhlcmUgYXJlIG1ham9yIGRpZmZlcmVuY2VzIGluIGNhcGl0YWxpemF0aW9uIGFuZCB1c2FnZSBvZiBEYXNoZXMuIFNvbWUgaW5jbHVkZSB0aGUgc3RhdGUgdGhleSB3ZXJlIGluLCBvdGhlcnMgZG8gbm90LiBTb21lIGFsc28gaW5jbHVkZGUgdGhlIHByb2dyYW0gdGhleSB3ZXJlIGluICgyOTcoZyksIENBUCwgZXRjLikuIEZvciB0aGUgcHVycG9zZXMgb2YgbXkgcHJvamVjdCBJJ2QgcHJvYmFibHkgdGFrZSB0aGUgQ2FsaWZvcm5pYSBzdWJzZXQgYW5kIGNsZWFuIHRoYXQsIGJ1dCB0aGlzIHdvdWxkIGxpa2VseSBiZSB0aGUgbW9zdCBvbmVyb3VzIHBhcnQgb2Ygd29ya2luZyB3aXRoIHRoaXMgZGF0YS4gCgpOb3cgdG8gY2hlY2sgZm9yIG1pc3NpbmcgZGF0YSwgSSdtIGdvaW5nIHRvIHVzZS9yZWZlciB0byB0aGUgb3JpZ2luYWwgdW5jbGVhbiBkYXRhICJBZG1pbkFycmVzdCI6CgpgYGB7cn0KTWlzc2luZ0RhdGEgPC1jb2xTdW1zKGlzLm5hKEFkbWluQXJyZXN0KSkKcHJpbnQoTWlzc2luZ0RhdGEpCmBgYAoKSSB3YW50IHRvIG11dGF0ZSB0aGUgYXBwcmVoZW5zaW9uIGRhdGUgY29sdW1uIHNvIHRoYXQgSSBjYW4gZmlsdGVyIGxhdGVyIGJ5IHllYXIgYW5kIG1vbnRoLCBhbmQgZXZlbiBwb3RlbnRpYWxseSB0aGUgdGltZSBvZiBkYXkgYW4gYWRtaW5pc3RyYXRpdmUgYXJyZXN0IHRvb2sgcGxhY2UuCgpgYGB7cn0KbmV3X0FkbWluQXJyZXN0IDwtY2xlYW5lZF9BZG1pbkFycmVzdCU+JSAKICBtdXRhdGUoQXBwcmVoZW5zaW9uWWVhciA9IHllYXIoYEFwcHJlaGVuc2lvbiBEYXRlYCkgKSU+JSAKICAgbXV0YXRlKEFwcHJlaGVuc2lvbk1vbnRoID0gbW9udGgoYEFwcHJlaGVuc2lvbiBEYXRlYCkpJT4lIAogIG11dGF0ZShBcHByZWhlbnNpb25EYXkgPSBkYXkoYEFwcHJlaGVuc2lvbiBEYXRlYCkpJT4lIAogIG11dGF0ZShBcHByZWhlbnNpb25Ib3VyID0gaG91cihgQXBwcmVoZW5zaW9uIERhdGVgKSkKClZpZXcobmV3X0FkbWluQXJyZXN0KQoKYGBgCgpOb3cgSSB3YW50IHRvIGxvb2sgYXQganVzdCBhZG1pbmlzdHJhdGl2ZSBhcnJlc3RzIGluIENhbGlmb3JuaWEsIHNvIEknbSBnb2luZyB0byBmaWx0ZXIgYnkgdGhlIGFwcHJlaGVuc2lvbiBzdGF0ZSBjb2x1bW4uCgpgYGB7cn0KQ0FfQWRtaW5BcnJlc3QgPC0gbmV3X0FkbWluQXJyZXN0ICU+JQogIGZpbHRlcihgQXBwcmVoZW5zaW9uIFN0YXRlYCA9PSAiQ0FMSUZPUk5JQSIpClZpZXcoQ0FfQWRtaW5BcnJlc3QpCgpgYGAKCkkgd2FudCB0byBmaWx0ZXIgdGhhdCBmdXJ0aGVyIHRvIGp1c3QgdGhlIEFkbWluaXN0cmF0aXZlIGFycmVzdHMgaW4gdGhlIFNGIEFyZWEgb2YgUmVzcG9uc2liaWxpdHksIGJlY2F1c2UgZXZlbiB0aG91Z2ggdGhhdCdzIGFjdHVhbGx5IGEgbG90IGxhcmdlciB0aGFuIHRoZSBnZW9ncmFwaGljIHNjb3BlIG15IHByb2plY3QgaXMgbG9va2luZyBhdCwgaXQgYXQgbGVhc3QgaW5jbHVkZXMgbXkgYXJlYSB0aGUgQmF5IEFyZWEuIAoKYGBge3J9ClNGQU9SX0FkbWluQXJyZXN0IDwtIENBX0FkbWluQXJyZXN0ICU+JSAKICBmaWx0ZXIoYEFwcHJlaGVuc2lvbiBBT1JgID09ICJTYW4gRnJhbmNpc2NvIEFyZWEgb2YgUmVzcG9uc2liaWxpdHkiKQpWaWV3KFNGQU9SX0FkbWluQXJyZXN0KQpgYGAKCkFOQUxZU0lTIFNFQ1RJT046IAoKQSByZWFsbHkgYmFzaWMgY29tcGFyaXNvbiBJIG1pZ2h0IG1ha2UgdG8gc3RhcnQgaXMgY29tcGFyaW5nIHRoZSBudW1iZXIgb2YgQWRtaW5pc3RyYXRpdmUgQXJyZXN0cyBieSB5ZWFyLgoKYGBge3J9ClNGQU9SX0FkbWluQXJyZXN0ICU+JSAKICBncm91cF9ieShBcHByZWhlbnNpb25ZZWFyKSAlPiUgCiAgdGFsbHkoKQpgYGAKCkJ1dCB0aGUgdGFibGUgSSBnZXQgaGVyZSBhY3R1YWxseSBpc24ndCB0aGF0IGluZm9ybWF0aXZlIGdpdmVuIHRoYXQgSSBvbmx5IGhhdmUgZGF0YSBmcm9tIHRocmVlIHllYXJzLiBCdXQgbWF5YmUgSSBqdXN0IHdhbnQgdG8gc2VlIHRoZSBjaGFuZ2UgaW4gdGltZSBieSBtb250aCBvZiBqdXN0IHRoaXMgbmV3IGFkbWluaXN0cmF0aW9uICgyMDI1KSwgU28gSSdkIGxpa2VseSBkbyB0aGUgZm9sbG93aW5nOgoKYGBge3J9ClNGQU9SX0FkbWluQXJyZXN0YnlNb250aCA8LVNGQU9SX0FkbWluQXJyZXN0ICU+JSAKICBmaWx0ZXIoQXBwcmVoZW5zaW9uWWVhciA9PSAiMjAyNSIpICU+JSAKICBncm91cF9ieShBcHByZWhlbnNpb25Nb250aCkgJT4lIAogIHRhbGx5KCkKVmlldyhTRkFPUl9BZG1pbkFycmVzdGJ5TW9udGgpCgpgYGAKCkp1c3QgbG9va2luZyBhdCB0aGUgdGFibGUgSSBzZWUgdGhlcmUncyBhbiBpbmNyZWFzZSBpbiBKdW5lIHdoaWNoIGhlbGQgaW4gSnVseSwgYnV0IGl0IG1pZ2h0IGJlIGhlbHBmdWwgdG8gdmlzdWFsaXplIGl0LCBzbyBJJ20gZ29pbmcgdG8gbG9vayBhdCBwbG90IGl0IG91dDogCgpgYGB7cn0KZ2dwbG90KGRhdGE9U0ZBT1JfQWRtaW5BcnJlc3RieU1vbnRoKSArCiAgZ2VvbV9saW5lKGFlcyh4PUFwcHJlaGVuc2lvbk1vbnRoLCB5PW4pKSArCiAgeGxpbSgxLDgpICsKICB5bGltKDAsNjAwKSArCiAgbGFicyggeCA9ICJNb250aCIsIHkgPSAiTnVtYmVyIG9mIEFycmVzdHMiKQogIGdndGl0bGUoIkFkbWluaXN0cmF0aXZlIEFycmVzdHMgYnkgTW9udGgiKSAKICAKYGBgCkFuZWNkb3RhbGx5LCBJJ3ZlIGFsc28gaGVhcmQgdGhpcyB0aGluZyBmcm9tIGEgbnVtYmVyIG9mIGFkdm9jYXRlcyB0aGF0IElDRSBhY3Rpb25zIChhcnJlc3RzKSB0ZW5kIHRvIGhhcHBlbiBpbiB0aGUgZWFybHkgbW9ybmluZy4gSSB3YW50IHRvIGNoZWNrIGlmIHRoYXQncyB0cnVlLCBzbyBJJ20gZ29pbmcgdG8gbG9vayBhdCB0aGUgQXBwcmVoZW5zaW9uSG91ciBjb2x1bW4gdGhhdCBJIG11dGF0ZWQgb3V0IG9mIHRoZSBvcmlnaW5hbCBBcHByZWhlbnNpb24gRGF0ZSBjb2x1bW4uIEl0J3Mgb24gYSAyNCBob3VyIGNsb2NrIChubyBhbS9wbSkuIEknbSBnb2luZyB0byB1c2UgdGhlIENBX0FkbWluQXJyZXN0IGRhdGEgYmVjYXVzZSBhY2NvcmRpbmcgdG8gYWR2b2NhdGVzIHRoaXMgcmVwcmVzZW50cyBJQ0UgcG9saWN5IHNvIGl0IHNob3VsZCBiZSB0cnVlIGFjcm9zcyB0aGUgc3RhdGUuIAoKYGBge3J9CkNBX0FkbWluQXJyZXN0X2J5SG91ciA8LSBDQV9BZG1pbkFycmVzdCAlPiUKICBncm91cF9ieShBcHByZWhlbnNpb25Ib3VyKSAlPiUKICB0YWxseSgpCgpWaWV3KENBX0FkbWluQXJyZXN0X2J5SG91cikKCmBgYApUbyBzZWUgdGhhdCB2aXN1YWxseSBJJ20gZ29pbmcgdG8gY2hhcnQgaXQuIAoKYGBge3J9CmdncGxvdChkYXRhPUNBX0FkbWluQXJyZXN0X2J5SG91ciwgYWVzKHggPSBBcHByZWhlbnNpb25Ib3VyLCB5ID0gbikpICsKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIHdpZHRoPTAuNSwgZmlsbD0gInN0ZWVsYmx1ZSIpICsKICBsYWJzKCB4ID0gIkhvdXIgb2YgdGhlIERheSIsIHkgPSAiTnVtYmVyIG9mIEFycmVzdHMiKSArCiAgZ2d0aXRsZSgiQWRtaW5pc3RyYXRpdmUgQXJyZXN0cyBieSBIb3VyIG9mIHRoZSBEYXkgZnJvbSBTZXB0IDIwMjMgdGhyb3VnaCBKdWx5IDIwMjUiKSArCiAgc2NhbGVfeF9jb250aW51b3VzKG4uYnJlYWtzPTIzKQpgYGAKVGhpcyBzaG93cyB0aGF0IHRoZSBudW1iZXIgb2YgYXJyZXN0cyBwZWFrcyBiZXR3ZW4gOSBhbmQgMTAgYW0sIGFuZCBpZiB0aGUgYWN0dWFsIGFycmVzdHMgYXJlIHRha2luZyBwbGFjZSBhdCB0aGF0IGhvdXIgd2UgY2FuIGluZmVyIHRoYXQgSUNFL0RIUyBoYWQgdG8gYmUgYWN0aXZlIGJlZm9yZSB0aGVuLiBUaGUgbWFqb3JpdHkgb2YgdGhlIGFjdGl2aXR5IHNlZW1zIHRvIGhhcHBlbiBiZXR3ZWVuIDdhbSBhbmQgMXBtLgoKQW5vdGhlciB0aGluZyBJJ20gaW50ZXJlc3RlZCBpbiBpcyB1bmRlciB0aGUgY3VycmVudCBhZG1pbmlzdHJhdGlvbiwgd2hhdCBhcmUgdGhlIHRvcCBjb3VudHJpZXMgb2Ygb3JpZ2luIGZvciBmb2xrcyBiZWluZyBhcnJlc3RlZC4gSSdtIGludGVyZXN0ZWQgYm90aCBzdGF0ZXdpZGUgYW5kIGZvciBqdXN0IHRoZSBTYW4gRnJhbmNpc2NvIEFPUiwgYnV0IEknbCBzdGFydCB3aXRoIGp1c3QgQ2FsaWZvcm5pYQoKYGBge3J9CkNhbGlmb3JuaWFDaXRpemVuc2hpcENvdW50cnkyMDI1IDwtIENBX0FkbWluQXJyZXN0ICU+JQogIGZpbHRlcihBcHByZWhlbnNpb25ZZWFyID09ICIyMDI1IikgJT4lCiAgZ3JvdXBfYnkoYENpdGl6ZW5zaGlwIENvdW50cnlgKSAlPiUKICB0YWxseSgpIAoKVmlldyhDYWxpZm9ybmlhQ2l0aXplbnNoaXBDb3VudHJ5MjAyNSkKYGBgCgpXaGVuIEkgZG8gdGhpcyBhbmQgc29ydCBieSB2YWx1ZXMgbXkgdG9wIDEwIGNpdGl6ZW5zaGlwIGNvdW50cmllcyBhcmUgTWV4aWNvLCBHdWF0ZW1hbGEsIEVsIFNhbHZhZG9yLCBDb2xvbWJpYSwgSG9uZHVyYXMsIEluZGlhLCBWZW5lenVlbGEsIENoaW5hLCBOaWNhcmFndWEgYW5kIFBlcnUuIFRvIGNvbXBhcmUgdGhpcyB0byB0aGUgU0ZBT1IgSSdtIGRvaW5nIGEgc2ltaWxhciBhbmFseXNpcwoKCmBgYHtyfQpTRkFPUkNpdGl6ZW5zaGlwQ291bnRyeTIwMjUgPC0gU0ZBT1JfQWRtaW5BcnJlc3QgJT4lCiAgZmlsdGVyKEFwcHJlaGVuc2lvblllYXIgPT0gIjIwMjUiKSAlPiUKICBncm91cF9ieShgQ2l0aXplbnNoaXAgQ291bnRyeWApICU+JQogIHRhbGx5KCkgCgpWaWV3KFNGQU9SQ2l0aXplbnNoaXBDb3VudHJ5MjAyNSkKYGBgCgpXaGVuIEkgc29ydCB0aGlzIHRhYmxlIGJ5IHRoZSBjb3VudCwgSSBnZXQgc2xpZ2h0bHkgZGlmZmVyZW50IHJlc3VsdHMsIGJ1dCB0aGVyZSBpcyBhIGxvdCBvZiBvdmVybGFwLiBJbiB0aGUgU2FuIEZyYW5jaXNjbyBBcmVhIG9mIFJlc3BvbnNpYmlsaXR5IHRoZSB0b3AgMTAgY2l0aXplbnNoaXAgY291bnRyaWVzIGZvciBhcnJlc3RlZCBmb2xrcyBhcmUgTWV4aWNvLCBJbmRpYSwgR3VhdGVtYWxhLCBFbCBTYWx2YWRvciwgQ29sb21iaWEsIEhvbmR1cmFzLCBQZXJ1LCBOaWNhcmFndWEsIFZlbmV6dWVsYSwgYW5kIENoaW5hLiBNZXhpY28gbm90YWJseSBvdXRwYWNlcyB0aGUgcmVzdCBvZiB0aGVzZSBwbGFjZXMgaW4gbnVtYmVyIG9mIGFycmVzdHMuIAoKU29tZXRoaW5nIGVsc2UgSSdtIGludGVyZXN0ZWQgaW4gaXMgdGhlICJjcmltaW5hbGl0eSIgb2YgdGhvc2UgYXJyZXN0ZWQgaW4gdGhlIFNhbiBGcmFuY2lzY28gQXJlYSBvZiByZXNwb25zaWJpbGl0eS4gQWdhaW4gSSB3YW50IHRvIGxvb2sganVzdCBpbiB0aGUgY29udGV4dCBvZiB0aGUgY3VycmVudCBhZG1pbmlzdHJhdGlvbi4gVGhvc2Ugd2hvIGFyZSBhcnJlc3RlZCBhcmUgYXNzaWduZWQgdG8gb25lIG9mIHRocmVlIGNhdGVnb3JpZXMgb2YgY3JpbWluYWxpdHksIGJ1dCBJJ20gaW50ZXJlc3RlZCBpbiB0aGUgcHJvcG9ydGlvbiB0aGF0IHRob3NlIGNhdGVnb3JpZXMgc2hvdyB1cCBpbiBhcnJlc3RzLiAKCmBgYHtyfQpTRkFPUkFycmVzdENyaW1pbmFsaXR5MjAyNSA8LSBTRkFPUl9BZG1pbkFycmVzdCAlPiUKICBmaWx0ZXIoQXBwcmVoZW5zaW9uWWVhciA9PSAiMjAyNSIpICU+JQogIGdyb3VwX2J5KGBBcHByZWhlbnNpb24gQ3JpbWluYWxpdHlgKSAlPiUKICB0YWxseSgpIAoKVmlldyhTRkFPUkFycmVzdENyaW1pbmFsaXR5MjAyNSkKYGBgCkZvciB0aG9zZSBhcnJlc3RlZCB0aGUgbWFqb3JpdHkgYXJlIGNvbnZpY3RlZCBjcmltaW5hbHMsIGFjY29yZGluZyB0byB0aGUgZGF0YSwgYnV0IGl0J3Mgbm90YWJsZSB0aGF0IGEgc2l6YWJsZSBjaHVuayBhcmUgY2F0ZWdvcml6ZWQgdW5kZXIgIm90aGVyIGltbWlncmF0aW9uIHZpb2xhdGlvbi4iIEFycmVzdHMgYXJlIHN1cHBvc2VkIHRvIHJlcHJlc2VudCBpbmRpdmlkdWFscyBoYXZlIGEgcmVhbCBjYXNlIGFnYWluc3QgdGhlbSwgc28gdGhlIGNvbnZpY3RlZCBjcmltaW5hbCBjYXRlZ29yeSBzaG91bGQgcmVwcmVzZW50ZWQgdGhlIG1ham9yaXR5LiBBbmQgdGhlc2UgYXJyZXN0cyBhcmUgbm90IHRoZSB0b3RhbGl0eSBvZiBkZXBvcnRhdGlvbnMsIGlmIHlvdSBsb29rIGF0IHRoZSBkZXBvcnRhdGlvbiBkYXRhIHNldCBpbiBhZGRpdGlvbiB0byB0aGlzIGFycmVzdHMgZGF0YSwgeW91IHdvdWxkIGZpbmQgdGhlIG1ham9yaXR5IG9mIGZvbGtzIGNvbWluZyBpbiB0byBjb250YWN0IHdpdGggSUNFL0RIUyBkbyBub3QgaGF2ZSBhbnkgY3JpbWluYWwgY29udmljdGlvbnMuIEl0J3MgYWxzbyB3b3J0aCBub3RpbmcgdGhhdCB0aGUgY29udmljdGVkIGNyaW1pbmFsIGNhdGVnb3J5IGRvZXNuJ3QgYnJlYWsgZG93biBmdXJ0aGVyIGludG8gd2hhdCBjcmltZXMgZm9sa3Mgd2VyZSBjb252aWN0ZWQgb2YuIE90aGVyIHJlcG9ydGluZyBoYXMgY29uZmlybWVkIHRoYXQgdGhlcmUgYXJlIG1hbnkgZm9sa3Mgd2hvIGVuZCB1cCBhcnJlc3RlZCB3aGVyZSB0aGUgYmFzaXMgb2YgdGhlaXIgY29udmljdGlvbiBpcyBhIHRyYWZmaWMgdmlvbGF0aW9uLiBJIHRhbGtlZCB0byBvbmUgbGF3eWVyIGluIHRoZSBCYXkgQXJlYSB3aG8gY29uZmlybWVkIHRoZXkgaGFkIGEgY2xpZW50IHdoZXJlIGEgcHJpb3IgY29udmljdGlvbiBjYW1lIGluIHRoZSBmb3JtIG9mIGEgY2l0YXRpb24gZm9yIGZhaWxpbmcgdG8gcGF5IGZvciBCQVJULiBBcmUgdGhvc2UgY3JpbWVzIHRoZSBzYW1lIGFzIG11cmRlcj8gTm8sIGJ1dCB1bmRlciB0aGlzIGNhdGVnb3JpemF0aW9uIHRoZXkncmUgZmxhdHRlbmVkIGludG8gb25lIGNhdGVnb3J5IHRvZ2V0aGVyLiAK