diff --git a/teaching/courses/2017_lsa/index.qmd b/teaching/courses/2017_lsa/index.qmd index 2db171f..d506454 100644 --- a/teaching/courses/2017_lsa/index.qmd +++ b/teaching/courses/2017_lsa/index.qmd @@ -2,6 +2,8 @@ title: "LSA 2017 Statistical Modelling with R" listing: contents: lectures + type: table + fields: [image, order, title, reading-time] --- - [Meeting 1: Introduction to R](lectures/Session_1.nb.html) diff --git a/teaching/courses/2017_lsa/lectures/Session_1.nb.qmd b/teaching/courses/2017_lsa/lectures/Session_1.nb.qmd index 9c7d72f..f7f1e62 100755 --- a/teaching/courses/2017_lsa/lectures/Session_1.nb.qmd +++ b/teaching/courses/2017_lsa/lectures/Session_1.nb.qmd @@ -1,8 +1,11 @@ --- title: "Introduction to R" +image: figures/cran_package.png +order: 1 knitr: opts_chunk: error: true + warning: false --- ## Hellos @@ -27,7 +30,7 @@ These are some of the core areas I figure are necessary to getting good at stati These are all skills you can achieve through practice, experience, and occasional guidance from someone more skilled than you. It is exactly like acquiring any other skill or craft. At first it will be confusing, you'll make some mistakes, and it won't look so good. I think -::: {layout="[40,-20,40]"} +::: {layout="[45,-10,45]"} ![The first hat I ever knit](figures/firsthat.jpg) ![The most recent hat I knit](figures/lasthat.jpg) @@ -52,7 +55,7 @@ Most of the content of the course is devoted to core R programming (things you s The course will follow the workflow outlined at the beginning: `begin → summarize → visualize → analyze`. | Week | Monday | Thursday | -|------------------:|:--------------------------:|:------------------------:| +|------------------:|:-------------------------:|:------------------------:| | 1 | -- | Intro - Basics & R Notebooks | | 2 | Data Frames & Factors | Split-Apply-Combine, Reshaping | | 3 | ggplot2 | Fitting Linear Models | @@ -160,9 +163,7 @@ I'm going to recommend (for now at least) that you run all of your code though a My earlier advice would have been to write all of your code in an R script file, but that also separates the code from its results, which can be hard for beginners to keep track of. -
- - +------------------------------------------------------------------------ ## Installing R Packages @@ -170,7 +171,7 @@ R comes with a lot of functionality installed, but one way that R is extensible Here's a basic diagram of how R packages work: -![](figures/cran_package.png) +![](figures/cran_package.png){fig-align="center" width="100%"} ### Installing Packages @@ -200,14 +201,15 @@ library("ggplot2") foo <- ggplot() ``` -::: {.box .break} -[\~2 Minute Activity]{.big-label} +::: callout-note +## \~2 minute activity Let's install all of the packages we're going to use in the course. Double check that you're connected to the internet. Create a notebook for this lecture called `01_lecture.Rmd`. Copy-paste the following into an R code chunk and run it: ```{r} +#| eval: false install.packages( c("tidyverse", "devtools") @@ -281,10 +283,8 @@ In short, you can use these variables `x` and `y` like they *are* the values you - You could have chosen *almost* any name for these variables. - You can just as easily assign *new* values to these variables. -::: {.box .idiom} -[Idiom]{.label} - -#### Naming Things +::: callout-tip +## Naming Things `x` and `y` are lousy names for variables. When it comes to naming variables, there's a famous saying: @@ -298,7 +298,7 @@ For best practices on naming variables, I'll refer you to [the tidyverse style g Also, be guided by The Principle of Least Effort. Use the minimal amount of characters that are still clearly interpretable. -```{r} +``` # Good Names model_1 model_full @@ -457,8 +457,8 @@ Of course, if you now wanted to know what year these speakers turned 17, you cou (interview_year - ages) + 17 ``` -::: {.box .break} -[\~5 Minute Activity]{.big-label} +::: callout-note +## \~5 minute activity A Starbucks Grande filter coffee in the UK currently costs £1.85. The value of £1 before the Brexit vote was about \$1.49. After the vote, it dropped down to about \$1.31, and lately it's been closer to \$1.27. @@ -474,7 +474,7 @@ If you have a bunch of values stored in a vector, and you want to pull out speci Let's start by indexing by position. ::: {style="font-family:monospace;font-size:xx-large;text-align:center;"} -[vector]{style="color:#747474"}\[[]{style="color:red"}[position]{style="color:#747474"}\] +[vector]{style="color:#747474"}[\[]{style="color:red"}[position]{style="color:#747474"}[\]]{style="color:red"} ::: R has some built in vectors for you to use, like one called `letters`. We haven't defined `letters`, and it's not listed as being in your R environment, but it's there. @@ -504,7 +504,7 @@ letters[abba] You can also index by logical values. ::: {style="font-family:monospace;font-size:xx-large;text-align:center;"} -[vector]{style="color:#747474"}\[[]{style="color:red"}[true false vector]{style="color:#747474"}\] +[vector]{style="color:#747474"}[\[]{style="color:red"}[true false vector]{style="color:#747474"}[\]]{style="color:red"} ::: Let's come back to our vector of speaker's ages @@ -529,8 +529,8 @@ ages > 40 ages[ages > 40] ``` -::: {.box .break} -[\~2 Minute Activity]{.big-label} +::: callout-note +## \~2 minute activity Let's assume our speakers had the following names: @@ -545,9 +545,8 @@ Using logical indexing and the ages in `ages` and year of interview in `intervie The following operators will return a vector of `TRUE` and `FALSE` values. -::: {style="width=50%"} | Operator | Meaning | -|:---------|:-------------------------| +|----------|--------------------------| | `==` | exactly equal to | | `!=` | not equal to | | `>` | greater than | @@ -555,7 +554,6 @@ The following operators will return a vector of `TRUE` and `FALSE` values. | `>=` | greater than or equal to | | `<` | less than | | `<=` | less than or equal to | -::: You can use these to compare vectors to single values, as we've seen, but you can also compare vectors to vectors *if they are the same length*. Comparison is done elementwise. @@ -568,13 +566,11 @@ group_a < group_b There are three more operators that have an effect on `TRUE` and `FALSE` vectors. -::: {style="width:50%"} | Operator | Meaning | -|:---------|:-------------------------------------------------| +|----------|--------------------------------------------------| | `!` | not x
changes all `T` to `F` and `F` to `T` | -| `|` | x or y | -| `&` | x and y | -::: +| \| | `x` or `y` | +| `&` | `x` and `y` | ```{r} x <- c(T, T, F, F) @@ -625,6 +621,4 @@ check_names[check_names %in% speaker_names] check_names[!(check_names %in% speaker_names)] ``` -
- - +------------------------------------------------------------------------ diff --git a/teaching/courses/2017_lsa/lectures/Session_2.nb.html b/teaching/courses/2017_lsa/lectures/Session_2.nb.html deleted file mode 100644 index 40e16a7..0000000 --- a/teaching/courses/2017_lsa/lectures/Session_2.nb.html +++ /dev/null @@ -1,1343 +0,0 @@ - - - - - - - - - - - - - -Data and Data Frames - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -
-
-
-
-
- -
- - - - - - - - -
-

The Agenda

-
    -
  • Talk about organizing, structuring & storing your data.
  • -
  • Review some important data input/output options in R.
  • -
  • Review about how data frames work in R.
  • -
-
-

Setup

-
-

~2 minute setup

-

Make sure that your current RStudio project is set to your course project. Create and save your R notebook for today (I would recommend 02_lecture.Rmd). Clear the workspace of anything left over from last time with the menu options Session > Clear Workspace.

-

Load the important packages for today’s work:

- - - -
library(lsa2017)
-library(tidyverse)
- - - -
-
-
-
-
-

Data Collection and Storage

-
-

General Principles of Data Collection

-
-

Over-collect (for some things)

-

When collecting data in the first place, over-collect if at all possible or ethical. The world is a very complex place, so there is no way you could cram it all into a bottle, but give it your best shot! If during the course of your data analysis, you find that it would have been really useful to have data on, say, duration, as well as formant frequencies, it becomes costly to recollect that data, especially if you haven’t laid the proper trail for yourself. On the other hand, automation of acoustic analysis or data processing can cut down on this costliness.

-

This doesn’t go for personal information on human subjects, though. It’s important from an ethics standpoint to ask for everything you’ll need, but not more. You don’t want to collect an enormous demographic profile on your participants if you won’t wind up using it, especially if you know you won’t use it to begin with.

-
-
-

Preserve HiD Info

-

If, for instance, you’re collecting data on the effect of voicing on preceding vowel duration, preserve high dimensional data coding, like Lexical Item, or the transcription of the following segment. These high dimensional codings probably won’t be too useful for your immediate analysis, but they will allow you to procedurally extract additional features from them at a later time. For example, if you have a column called fol_seg, which is just a transcription of the following segment, it is easy create a new column called manner with code that looks like this:

- - - -
table(iy_ah$fol_seg)
- - -

-  AA0   AA1   AE1   AH0   AH1   AO1   AY1     B    CH     D    DH   EH1   ER0     F     G 
-    2     1     1   371     2     1    36  1588  1201  1920   507     2     5   124   140 
-   HH   IH0   IH1   IY1    JH     K     L     M     N    NG   OW0   OW2     P     R     S 
-   10   255     1     4   126  3156  2888  1589  5397    26     1     2  4963     1  1479 
-   SH    SP     T    TH     V     W     Y     Z    ZH 
-  217   107 12690    96  2167    13     4  3693    32 
- - - - - - -
iy_ah <- iy_ah %>%
-            mutate(manner = recode(fol_seg, B = 'stop',
-                                            CH = 'affricate',
-                                            D = 'stop',
-                                            DH = 'fricative',
-                                            `F` = 'fricative',
-                                            G = 'stop',
-                                            HH = 'fricative',
-                                            JH = 'affricate',
-                                            K = 'stop',
-                                            L = 'liquid',
-                                            M = 'nasal',
-                                            N = 'nasal',
-                                            NG = 'nasal',
-                                            P = 'stop',
-                                            R = 'liquid',
-                                            S = 'fricative',
-                                            SH = 'fricative',
-                                            SP = 'pause',
-                                            `T` = 'stop',
-                                            TH = 'fricative',
-                                            V = 'fricative',
-                                            W = 'glide',
-                                            Y = 'glide',
-                                            Z = 'fricative',
-                                            ZH = 'fricative',
-                                            .default = 'vowel'))
-table(iy_ah$manner)
- - -

-affricate fricative     glide    liquid     nasal     pause      stop     vowel 
-     1327      8325        17      2889      7012       107     24457       684 
- - - -
-
-

Leave A Trail of Crumbs

-

Be sure to answer this question: How can I preserve a record of this observation in such a way that I can quickly return to it and gather more data on it if necessary? If you fail to successfully answer this question, then you’ll be lost in the woods if you ever want to restudy, and the only way home is to replicate the study from scratch.

-
-
-

Give Meaningful Names

-

Give meaningful names to both the names of predictor columns, as well as to labels of nominal observations. Keeping a readme describing the data is still a good idea, but at least now the data is approachable at first glance.

-
-
-

Distinguish between 0 and NA

-

I have worked with some spreadsheets where missing data was given a value of 0, which will mess things up. For example, /oy/ is a fairly rarely occurring phoneme in English, and it’s possible that a speaker won’t produce any tokens in a short interview. In a spreadsheet of mean F1 and F2 for all vowels, that speaker should get an NA for /oy/, not 0.

-
-
-
-

Storing Data

-

When we store data, it should be:

-
    -
  1. Raw Raw data is the most useful data. It’s impossible to move down to smaller granularity from a coarser, summarized granularity. Summary tables etc. are nice for publishing in a paper document, but raw data is what we need for asking novel research questions with old data.

  2. -
  3. Open formatted Do not use proprietary database software for long term storage of your data. I have enough heard stories about interesting data sets that are no longer accessible for research either because the software they are stored in is defunct, or current versions are not backwards compatible. At that point, your data is property of Microsoft, or whoever. Store your data as raw text, delimited in some way (I prefer tabs).

  4. -
  5. Consistent I think this is most important when you may have data in many separate files. Each file and its headers should be consistently named and formatted. They should be consistently delimited and commented also. There is nothing worse than inconsistent headers and erratic comments, labels, headers or NA characters in a corpus. (Automation also helps here.)

  6. -
  7. Documented Produce a readme describing the data, how it was collected and processed, and describe every variable and its possible values.

  8. -
-
-
-
-
-

Structuring Data

-
-

Breaking Bad Spreadsheet Habits

-

Let’s start off by looking at a picture of a data organization approach that might look familiar, and is a very bad way to do things:

-
- - -
-

This spreadsheet has a fairly strict organizational structure, but is virtuously hopeless for doing any kind of serious statistical analysis. It’s also verging on irreparable using R. This because the data in this spreadsheet is organized to be easy to look at with your eyeballs 👀.

-

But looking at neatly organized data in a spreadsheet is not a statistical analysis technique. So we need to start organizing our data in a way that isn’t easy to look at, but is easy to graph and analyze.

-
-
-

Better Habits

-

Everyone working with data (in R or otherwise) should read Hadley Wickham’s paper on Tidy Data: https://cran.r-project.org/web/packages/tidyr/vignettes/tidy-data.html If you are coming off of organizing your data like the picture above, there are a few guidelines not discussed in that paper, namely:

-
-

Follow these rules

-
    -
  1. The first row of the data must be the names of the data columns.
  2. -
  3. All other rows must be the data, and nothing else.
  4. -
  5. You cannot use empty rows or empty columns as visual aids to look at the data.
  6. -
  7. The spreadsheet must not contain any summary cells. No final row called “Average” or final column called “Total”. We can create these in R, and they make data processing more complicated if they’re included in the raw data.
  8. -
-
-
-

Semantics of Data Structure

-

In the semantics of data structure Wickham lays out, there are three important primitives:

-
    -
  1. Variables
  2. -
  3. Values
  4. -
  5. Observations
  6. -
-
-

Defining the primitives

-
-
Variables
-

Variables are the collections of values of interest in data analysis. For example, let’s say you were doing a study on unnormalized vowel space size by just looking at /i:/ and /ɑ/. The variables in that study could be:

-
    -
  • speaker
  • -
  • word
  • -
  • phoneme
  • -
  • duration
  • -
  • F1
  • -
  • F2
  • -
  • word_frequency
  • -
-
-
-
Values
-

Values are, as the name implies, the possible values that each variable can have, for example:

-
    -
  • speaker: "Oakley", "Charlie", "Azaria", ...
  • -
  • word: "street", "thirteen", "not", "got", ...
  • -
  • phoneme: "iy", "ah"
  • -
-
-
-
Observations
-

An observation is the minimal unit across which all variables are collected. For example, in the vowel space study, one observation would be one instance of an uttered vowel for which you record who the speaker was, the word, the duration, F1, F2, etc.

-
-
-
-

Organizing data with these primitives

-

Once you’ve thought through what the variables, values and observations are for your study, the principle of how to organize them is simple:

-
    -
  1. Each variable forms a column.
  2. -
  3. Each observation forms a row.
  4. -
-

For the vowel space size study, you might want to wind up with a plot that looks like this:

- - - -

- - - -

It wouldn’t be uncommon to see the data untidily organized like this:

- - - -
- -
- - - -
-

~5 Minute Activity

-

In small groups, figure out the following:

-
    -
  • What are the variables in the data frame above?
  • -
  • What are the values?
  • -
  • What are the observations?
  • -
  • How should the table above be re-organized?
  • -
- - - - -
-
-
-
-
-
-
-

Data Frames

-

So far we have discussed the following types of values in R:

-
    -
  • numerical
  • -
  • character
  • -
  • logical
  • -
-

And we’ve discussed the following data structures.

-
    -
  • vectors
  • -
-

Here, we’ll cover one new data structure:

-
    -
  • data frames
  • -
-

Data Frames are the data structure we’ll be using the most in R. When you begin thinking about data frames, a useful starting place is to think of them as spreadsheets, with columns and rows (but we’ll eventually abandon spreadsheet thinking). Let’s start out by creating a very simple data frame using the data.frame() function.

- - - -
  pitch <- data.frame(speaker_names = c("Charlie", "Skyler", "Sawyer", "Jamie"),
-                      ages = c(18, 35, 41, 62),
-                      F0 = c(114, 189, 189, 199))
-  pitch
- - -
- -
- - - -
-

Finding your way around

-

The pitch data frame has four rows, and three columns. The rows are just numbered 1 through 4, and the three columns are named speaker_names, ages and F0. To find out how many rows and columns a data frame has, you can use the nrow() and ncol() functions.

- - - -
  nrow(pitch)
- - -
[1] 4
- - -
  ncol(pitch)
- - -
[1] 3
- - - -

Most data frames you’re going to work with have a lot more rows than that. For example, iy_ah is a data frame that is bundled in the lsa2017 package.

- - - -
  nrow(iy_ah)
- - -
[1] 44818
- - - -

That’s too many rows to look at just in the console. One option is to use the head() function, that just prints the first 6 rows.

- - - -
  head(iy_ah)
- - -
- -
- - - -

Another option is to use the summary() function.

- - - -
  summary(iy_ah)
- - -
   idstring              age            sex                 year      years_of_schooling
- Length:44818       Min.   :18.00   Length:44818       Min.   :1973   Length:44818      
- Class :character   1st Qu.:30.00   Class :character   1st Qu.:1980   Class :character  
- Mode  :character   Median :45.00   Mode  :character   Median :1985   Mode  :character  
-                    Mean   :46.69                      Mean   :1989                     
-                    3rd Qu.:65.00                      3rd Qu.:2002                     
-                    Max.   :93.00                      Max.   :2010                     
-    vowel               word                 F1               F2              dur        
- Length:44818       Length:44818       Min.   : 186.6   Min.   : 598.6   Min.   :0.0500  
- Class :character   Class :character   1st Qu.: 398.3   1st Qu.:1355.1   1st Qu.:0.0800  
- Mode  :character   Mode  :character   Median : 528.6   Median :1879.5   Median :0.1100  
-                                       Mean   : 570.6   Mean   :1889.1   Mean   :0.1214  
-                                       3rd Qu.: 732.5   3rd Qu.:2386.7   3rd Qu.:0.1500  
-                                       Max.   :1428.9   Max.   :3690.4   Max.   :0.8700  
-  plt_vclass          pre_seg            fol_seg            context         
- Length:44818       Length:44818       Length:44818       Length:44818      
- Class :character   Class :character   Class :character   Class :character  
- Mode  :character   Mode  :character   Mode  :character   Mode  :character  
-                                                                            
-                                                                            
-                                                                            
-  word_trans             F1_n              F2_n            manner         
- Length:44818       Min.   :-3.0055   Min.   :-2.4533   Length:44818      
- Class :character   1st Qu.:-1.4855   1st Qu.:-0.7021   Class :character  
- Mode  :character   Median :-0.7261   Median : 0.8525   Mode  :character  
-                    Mean   :-0.2476   Mean   : 0.5639                     
-                    3rd Qu.: 1.0521   3rd Qu.: 1.7315                     
-                    Max.   : 4.3707   Max.   : 4.8674                     
- - - -

summary() is a function that works on almost every kind of object.

-
-
-

Indexing Data Frames

-

Since data frames are 2 dimensional (rows are one dimension, columns are another), the way you index them is a little bit more complicated than with vectors. It still uses square brackets, though, but these square brackets have two positions:

-
-

df[row number, column number]

-
-

If you specify a specific row number, but leave the column number blank, you’ll get back that row and all columns.

- - - -
  pitch[1,]
- - -
- -
- - - -

Alternatively, if you specify just the column number, but leave the rows blank, you’ll get back all of the values for that column.

- - - -
  pitch[,2]
- - -
[1] 18 35 41 62
- - - -

When you specify both, you get back the value in the specified row and column

- - - -
  pitch[1,2]
- - -
[1] 18
- - - -

However, there is a special indexing operator for data frames that take advantage of their named columns: $.

-
-

df$column_name

-
- - - -
  pitch$speaker_names
- - -
[1] Charlie Skyler  Sawyer  Jamie  
-Levels: Charlie Jamie Sawyer Skyler
- - - -

After accessing the column of a data frame, you can index it just like it’s a vector.

- - - -
  pitch$speaker_names[1]
- - -
[1] Charlie
-Levels: Charlie Jamie Sawyer Skyler
- - - -

If you really want to, you can do logical indexing of data frames like so:

- - - -
  pitch[pitch$speaker_names == "Charlie", ]
- - -
- -
- - - -

But there’s also a function called filter() that you can use to do the same thing. filter() takes a data frame as its first argument, and then a logical statement referring to one or more of the data frame’s columns.

- - - -
  filter(pitch, speaker_names == "Charlie")
- - -
- -
- - -
  filter(pitch, ages > 18, F0 > 190)
- - -
- -
- - - -
-

~5 Minute Activity

-

First, review the documentation of the iy_ah data set with ?iy_ah. Using filter() and nrow(), find out what percent of /i:/ tokens have a duration less than 90ms (0.09s).

-
-
-
-
-
-

Reading Data into R

-

R can easily read comma-separated (.csv) files and tab-delimited files into its memory.1 You can read them in with read.csv() and read.delim(), respectively. If your data is unavoidably in an Excel spreadsheet, there is a package called readxl with a function called read_excel() If you have the readxl package installed, I strongly recommend reading over its documentation on sheet geometry by calling up the vignette like so:

- - - -
vignette("sheet-geometry", package = "readxl")
- - - -

Last Minute Update: There is also package for reading data in from google spreadsheets https://github.com/jennybc/googlesheets. I haven’t used it yet, but it’s gotten good reviews.

-

When loading a data file into R, you are just loading it into the R workspace. Any alterations or modifications you make to the data frame will not be reflected in the file in your system, just in the copy in the R workspace.

-

The tricky thing now is that the way that feels most natural or normal for you to organize and name your files and folders doesn’t necessarily translate into a good way for R (or other programming languages) to look at them. In order to load a file into R, you need to provide read.csv() or read.delim() with the “path” to the file, which is just a text string.

-

For example, here’s a screenshot of a data file I’d like to load into R.

-
- - -
-

I have the option turned on in my system to see the full path at the bottom of the file window, so you can see a full list of all of the folders this data file is embedded in. In order to read this data into R, you need to type out the full path, although a nice thing about

- - - -
  joe_vowels <- read.csv("~/ownCloud/DocSyncUoE/Courses/LSA/data/joe_vowels.csv")
- - - -

If you’re not sure what it looks like on your system, use the file.choose() function.

- - - -
  file.choose()
- - - -

That’ll launch the default visual file browser for your system. After browsing around and clicking on a file, file.choose() will print the character string that represents the path to that file into the console.

-
-

Hygiene

-

Don’t rely heavily on file.choose(). Sometimes, I’ve seen R scripts with the following line of code in it:

- - - -
data <- read.csv(file.choose())
- - - -

Please never do this. I would caution against using it in any code, scripts or notebooks at all. Only ever use it to refresh your memory of where your data is located. By always writing out the the text of the path to the data, you

-
    -
  • produce more transparent code
  • -
  • allow yourself to re-run your analysis without needing to click around
  • -
  • ensure that you’re using the same data file every single time
  • -
-
-

One pretty cool thing is that if a data file is up on a website somewhere, you can just access it by passing the url to read.csv() or read.delim().2 Here is some sample data on the Donner Party.3

- - - -
  donner <- read.csv("http://jofrhwld.github.io/data/donner.csv")
-  head(donner)
- - - -
-

~5 minute activity

-

Download the file joe_vowels.csv from the course Canvas. Save it to the data directory for the course, or wherever you would like to keep it. Read it into R. What’s my mean F1 and F2 across all of my vowels?

-
-
-
-
-

Cleaning up data

-

We’ve discussed how data ought to be tidily organized, and we’ve now gone over how to load data, and minimally explore dataframes in R. Let’s quickly go over how to tidy up messy data a little.

-

First, let’s look at the wide iy_ah_wide dataframe, which is part of the lsa2017 package.

- - - -
iy_ah_wide
- - -
- -
- - - -

The problem with this data is

-
    -
  • There are values spread across the columns.
  • -
  • Individual column names have combined these values with some variables.
  • -
-

Getting to a tidier format of the data will involve a three step process:

-
    -
  1. Converting this wide data format to a long data format.
  2. -
  3. Separating the vowel class values from the formant variable.
  4. -
  5. Spreading the formant variables back out along the column space.’
  6. -
-

We can do this easily with the functions gather(), separate() and spread() from the tidyr package.

-

For a smaller illustrative purpose for people who may feel uneasy about vowels and formants, I’ll be illustrating each of these steps with a simpler data set about how many apples and oranges two people bought, and how many they ate.

- - - -
fruit <- data.frame(person = c("Oakley", "Charlie"),
-                 apples_bought = c(5, 3),
-                 apples_ate = c(1, 2),
-                 oranges_bought = c(5, 4),
-                 oranges_ate = c(3, 3))
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
personapples_boughtapples_ateoranges_boughtoranges_ate
Oakley5153
Charlie3243
- - - - - - -

Note, even though the column labels look different, this is is an equivalent table to formatting involving merged column label cells.

-
-
- - -
-
-
-

Gathering Columns

-

The gather() function makes wide data long. It takes the following arguments:

-
-

gather(data, key, value, cols)

-
-
    -
  • data -
      -
    • Obviously, the data you want to reshape. must be a data frame.
    • -
  • -
  • key and value -
      -
    • These are new column names that you want to create. gather() is going to take the column names and put them in the column you give to key, and the values from all the cells and put them in the column you call value.
    • -
  • -
  • cols -
      -
    • An indication of which columns you want to gather, either a vector of column names, a vector of column numbers, or some specialized methods for gather() that we’ll discuss.
    • -
  • -
-

Here’s how that’ll work for the fruit data. We’ll tell gather() to gather columns 2 through 5.

- - - -
fruit_long <- gather(data = fruit,
-                     key = fruit_behavior,
-                     value = number,
-                     2:5)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
personfruit_behaviornumber
Oakleyapples_bought5
Charlieapples_bought3
Oakleyapples_ate1
Charlieapples_ate2
Oakleyoranges_bought5
Charlieoranges_bought4
Oakleyoranges_ate3
Charlieoranges_ate3
- - - - - - -

gather() has returned a new data frame. It has created a new column called fruit_behavior, because we told it to with the key argument, and it has created a new column called number, because we told it to with the value function. It has taken all of the column names of the columns we told it to gather, and put them into the fruit_behavior column, and the numeric values from the columns we told it to gather, and put them into the number column. It has also repeated the rows of the other columns (person) as logically necessary.

-

Now, we told it to gather column numbers 2 through 5, but this would have also worked:

- - - -
gather(data = fruit, 
-       key = fruit_behavior, 
-       value = number, 
-       c("apples_bought","apples_ate", "oranges_bought", "oranges_ate"))
- - - -

gather() also has a more convenient method of specifying the columns you want to gather by passing it a named range of columns. We want to gather all columns from apples_bought to oranges_ate, so we can tell it to do so with apples_bought:oranges_ate.

- - - -
gather(data = fruit, 
-       key = fruit_behavior, 
-       value = number, 
-       apples_bought:oranges_ate)
- - - -

Ok, let’s do this now to the iy_ah_wide data, gathering all of the columns from ah_F1 to iy_F2.

- - - -
iy_ah_step1 <- gather(data = iy_ah_wide, 
-                      key = vowel_formant, 
-                      value = hz, 
-                      ah_F1:iy_F2)
-iy_ah_step1
- - -
- -
- - - -

For the fruit data, the only un-gathered column was person, but for iy_ah_wide, idstring, age, sex, and year, were all ungathered. Here you can see how all rows of ungathered columns are repeated as logically necessary.

-
-
-

Separating Columns

-

There is still a problem with both the fruit_long and the iy_ah_step1 data frames, which is that two different kinds of data are merged within one column. For iy_ah_step1, the vowel class and formant variable are merged together (e.g. ah_F1) and for fruit_long, the fruit and behavior are merged together (e.g. apple_bought). We need to separate these, with a very aptly named function called separate()

-
-

separate(data, col, into, sep)

-
-
    -
  • data -
      -
    • Again,the data frame you want to do this separation to.
    • -
  • -
  • col -
      -
    • The name of the column you want to separate.
    • -
  • -
  • into -
      -
    • A character vector of the new column names you want to create.
    • -
  • -
  • sep -
      -
    • The character or regex pattern you want to use to split up the values in col.
    • -
  • -
-

Here’s how it works for fruit_long.

- - - -
fruit_separate <- separate(data = fruit_long,
-                           col = fruit_behavior,
-                           into = c("fruit", "behavior"),
-                           sep = "_")
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
personfruitbehaviornumber
Oakleyapplesbought5
Charlieapplesbought3
Oakleyapplesate1
Charlieapplesate2
Oakleyorangesbought5
Charlieorangesbought4
Oakleyorangesate3
Charlieorangesate3
- - - - - - -

It has returned a new data frame with the fruit_behavior column split into two new columns, named after what I passed to the into argument. It split up fruit_behavior based on what I passed to sep, which was the underscore character.

-

Let’s do this for iy_ah_step1 now.

- - - -
iy_ah_step2 <- separate(iy_ah_step1, 
-                        vowel_formant, 
-                        into = c("vowel", "formant"),
-                        sep = "_")
-iy_ah_step2
- - -
- -
- - - -

We now have two separate columns for vowel and formant.

-
-

Hygiene

-

I have been very helpful and used underscores to merge together the values we want to separate. Be helpful to yourself, and be consistent in the semantics of how you used potential delimiters like - and _. Here’s an example of being helpful to yourself:

-
project_subject_firstname-lastname
-
-EDI_1_Stuart-Duddingston
-EDI_2_Connor-Black-Macdowall
-EDI_3_Mhairi
-

This is helpful, because when you separate by underscore, you’ll have something tidy

-
EDI    1    Stuart-Duddingston
-EDI    2    Connor-Black-Macdowall
-EDI    3    Mhairi
-

If you used - for everything, you’ll have chaos when you try to separate them because some speakers have “double barreled” names, and some speakers have only first names:

-
# Input:
-EDI-1-Stuart-Duddingston
-EDI-2-Connor-Black-Macdowall
-EDI-3-Mhairi
-
-# Becomes
-
-EDI    1    Stuart    Duddingston
-EDI    2    Connor    Black        Macdowall
-EDI    3    Mhairi
-

This goes beyond R programming. You should make some decisions and stick with them for all of your data analysis, including file naming, Praat tier naming, etc.

-
-
-
-

Spreading columns

-

We’ve got one last step, which is spreading the values in some rows across the column space. With the fruit data, we might not want a column called behavior, but actually have two columns called bought and ate. For the vowel data, we definitely don’t want one column called formant. We want one called F1 and one called F2. We can do this with the spread() function.

-
-

spread(data, key, value)

-
-
    -
  • data -
      -
    • Again, the data we want to work with.
    • -
  • -
  • key -
      -
    • The column whose values you want to spread across the column space.
    • -
  • -
  • value -
      -
    • The column with values that you want to fill in the cells.
    • -
  • -
-

Here’s how that looks with the fruit_separate data.

- - - -
fruit_spread <- spread(data = fruit_separate,
-                       key = behavior,
-                       value = number)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
personfruitatebought
Charlieapples23
Charlieoranges34
Oakleyapples15
Oakleyoranges35
- - - - - - -

This has created a new data frame. I told spread() to spread the values in behavior across the column space. Because it had only two unique values in it (bought and ate), it has created two new columns called bought and ate. After creating these new columns, it had to fill in the new cells with some values, and I told it to use the values in number for that.

-

Here’s how that works with iy_ah_step2.

- - - -
iy_ah_step3 <- spread(data = iy_ah_step2,
-                      key = formant,
-                      value = hz)
-iy_ah_step3
- - -
- -
- - - -

Now, we’ve finally gotten to a tidy data format. In our next meeting, we’ll discuss how to chain these three functions into one easy to read process.

-
-

Idiom

-

You might have noticed that in the functions above, I’ve put a new line between individual function arguments. I’ve done this because white-space doesn’t matter when it comes to R. I could have written these with just spaces between each argument, but that would be too visually crowded.

- - - -
# compare
-
-# One line
-fruit_separate <- separate(data = fruit_long, col = fruit_behavior, into = c("fruit", "behavior"), sep = "_")
-
-# New Lines
-fruit_separate <- separate(data = fruit_long, 
-                           col = fruit_behavior, 
-                           into = c("fruit", "behavior"), 
-                           sep = "_")
-
- - - -

I encourage you to use new lines similarly to give yourself “some space to breathe”. Don’t be shy about it. But, if you put newlines between some arguments, you should really put new lines between all arguments.

-
- -
-
-
-
-
    -
  1. My personal aesthetic preference is for tab-delimited files.

  2. -
  3. This doesn’t work if the file is behind encryption, i.e. if it begins with https://.

  4. -
  5. “The Donner Party (sometimes called the Donner-Reed Party) was a group of American pioneer migrants who set out for California in a wagon train. Delayed by a series of mishaps, they spent the winter of 1846–47 snowbound in the Sierra Nevadas. Some of the migrants resorted to cannibalism to survive, eating those who had succumbed to starvation and sickness.” https://en.wikipedia.org/wiki/Donner_Party

  6. -
-
- -
LS0tCnRpdGxlOiAiRGF0YSBhbmQgRGF0YSBGcmFtZXMiCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazogCiAgICBjb2RlX2ZvbGRpbmc6IG5vbmUKICAgIGNzczogLi4vY3VzdG9tLmNzcwogICAgdGhlbWU6IGZsYXRseQogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCiAgICB0b2NfZGVwdGg6IDMKLS0tCgoKCiMgVGhlIEFnZW5kYQoKLSBUYWxrIGFib3V0IG9yZ2FuaXppbmcsIHN0cnVjdHVyaW5nICYgc3RvcmluZyB5b3VyIGRhdGEuCi0gUmV2aWV3IHNvbWUgaW1wb3J0YW50IGRhdGEgaW5wdXQvb3V0cHV0IG9wdGlvbnMgaW4gUi4KLSBSZXZpZXcgYWJvdXQgaG93IGRhdGEgZnJhbWVzIHdvcmsgaW4gUi4KCgojIyBTZXR1cAoKPGRpdiBjbGFzcyA9ICJicmVhayBib3giPgo8c3BhbiBjbGFzcyA9ICdiaWctbGFiZWwnPn4yIG1pbnV0ZSBzZXR1cDwvc3Bhbj4KCk1ha2Ugc3VyZSB0aGF0IHlvdXIgY3VycmVudCBSU3R1ZGlvIHByb2plY3QgaXMgc2V0IHRvIHlvdXIgY291cnNlIHByb2plY3QuIENyZWF0ZSBhbmQgc2F2ZSB5b3VyIFIgbm90ZWJvb2sgZm9yIHRvZGF5IChJIHdvdWxkIHJlY29tbWVuZCBgMDJfbGVjdHVyZS5SbWRgKS4gQ2xlYXIgdGhlIHdvcmtzcGFjZSBvZiBhbnl0aGluZyBsZWZ0IG92ZXIgZnJvbSBsYXN0IHRpbWUgd2l0aCB0aGUgbWVudSBvcHRpb25zIGBTZXNzaW9uID4gQ2xlYXIgV29ya3NwYWNlYC4KCkxvYWQgdGhlIGltcG9ydGFudCBwYWNrYWdlcyBmb3IgdG9kYXkncyB3b3JrOgoKYGBge3J9CmxpYnJhcnkobHNhMjAxNykKbGlicmFyeSh0aWR5dmVyc2UpCmBgYAoKPC9kaXY+CgoKCjxoci8+CgojIERhdGEgQ29sbGVjdGlvbiBhbmQgU3RvcmFnZQoKIyMgR2VuZXJhbCBQcmluY2lwbGVzIG9mIERhdGEgQ29sbGVjdGlvbgoKIyMjIE92ZXItY29sbGVjdCAoZm9yIHNvbWUgdGhpbmdzKQpXaGVuIGNvbGxlY3RpbmcgZGF0YSBpbiB0aGUgZmlyc3QgcGxhY2UsIG92ZXItY29sbGVjdCBpZiBhdCBhbGwgcG9zc2libGUgb3IgZXRoaWNhbC4gVGhlIHdvcmxkIGlzIGEgdmVyeSBjb21wbGV4IHBsYWNlLCBzbyB0aGVyZSBpcyBubyB3YXkgeW91IGNvdWxkIGNyYW0gaXQgYWxsIGludG8gYSBib3R0bGUsIGJ1dCBnaXZlIGl0IHlvdXIgYmVzdCBzaG90ISBJZiBkdXJpbmcgdGhlIGNvdXJzZSBvZiB5b3VyIGRhdGEgYW5hbHlzaXMsIHlvdSBmaW5kIHRoYXQgaXQgd291bGQgaGF2ZSBiZWVuIHJlYWxseSB1c2VmdWwgdG8gaGF2ZSBkYXRhIG9uLCBzYXksIGR1cmF0aW9uLCBhcyB3ZWxsIGFzIGZvcm1hbnQgZnJlcXVlbmNpZXMsIGl0IGJlY29tZXMgY29zdGx5IHRvIHJlY29sbGVjdCB0aGF0IGRhdGEsIGVzcGVjaWFsbHkgaWYgeW91IGhhdmVuJ3QgbGFpZCB0aGUgcHJvcGVyIHRyYWlsIGZvciB5b3Vyc2VsZi4gT24gdGhlIG90aGVyIGhhbmQsICphdXRvbWF0aW9uKiBvZiBhY291c3RpYyBhbmFseXNpcyBvciBkYXRhIHByb2Nlc3NpbmcgY2FuIGN1dCBkb3duIG9uIHRoaXMgY29zdGxpbmVzcy4KClRoaXMgZG9lc24ndCBnbyBmb3IgcGVyc29uYWwgaW5mb3JtYXRpb24gb24gaHVtYW4gc3ViamVjdHMsIHRob3VnaC4gSXQncyBpbXBvcnRhbnQgZnJvbSBhbiBldGhpY3Mgc3RhbmRwb2ludCB0byBhc2sgZm9yIGV2ZXJ5dGhpbmcgeW91J2xsIG5lZWQsIGJ1dCBub3QgbW9yZS4gWW91IGRvbid0IHdhbnQgdG8gY29sbGVjdCBhbiBlbm9ybW91cyBkZW1vZ3JhcGhpYyBwcm9maWxlIG9uIHlvdXIgcGFydGljaXBhbnRzIGlmIHlvdSB3b24ndCB3aW5kIHVwIHVzaW5nIGl0LCBlc3BlY2lhbGx5IGlmIHlvdSBrbm93IHlvdSB3b24ndCB1c2UgaXQgdG8gYmVnaW4gd2l0aC4KCgoKCiMjIyBQcmVzZXJ2ZSBIaUQgSW5mbwpJZiwgZm9yIGluc3RhbmNlLCB5b3UncmUgY29sbGVjdGluZyBkYXRhIG9uIHRoZSBlZmZlY3Qgb2Ygdm9pY2luZyBvbiBwcmVjZWRpbmcgdm93ZWwgZHVyYXRpb24sIHByZXNlcnZlIGhpZ2ggZGltZW5zaW9uYWwgZGF0YSBjb2RpbmcsIGxpa2UgTGV4aWNhbCBJdGVtLCBvciB0aGUgdHJhbnNjcmlwdGlvbiBvZiB0aGUgZm9sbG93aW5nIHNlZ21lbnQuIFRoZXNlIGhpZ2ggZGltZW5zaW9uYWwgY29kaW5ncyBwcm9iYWJseSB3b24ndCBiZSB0b28gdXNlZnVsIGZvciB5b3VyIGltbWVkaWF0ZSBhbmFseXNpcywgYnV0IHRoZXkgd2lsbCBhbGxvdyB5b3UgdG8gcHJvY2VkdXJhbGx5IGV4dHJhY3QgYWRkaXRpb25hbCBmZWF0dXJlcyBmcm9tIHRoZW0gYXQgYSBsYXRlciB0aW1lLiBGb3IgZXhhbXBsZSwgaWYgeW91IGhhdmUgYSBjb2x1bW4gY2FsbGVkIGBmb2xfc2VnYCwgd2hpY2ggaXMganVzdCBhIHRyYW5zY3JpcHRpb24gb2YgdGhlIGZvbGxvd2luZyBzZWdtZW50LCBpdCBpcyBlYXN5IGNyZWF0ZSBhIG5ldyBjb2x1bW4gY2FsbGVkIGBtYW5uZXJgIHdpdGggY29kZSB0aGF0IGxvb2tzIGxpa2UgdGhpczoKCmBgYHtyfQp0YWJsZShpeV9haCRmb2xfc2VnKQpgYGAKCmBgYHtyfQppeV9haCA8LSBpeV9haCAlPiUKICAgICAgICAgICAgbXV0YXRlKG1hbm5lciA9IHJlY29kZShmb2xfc2VnLCBCID0gJ3N0b3AnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIENIID0gJ2FmZnJpY2F0ZScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRCA9ICdzdG9wJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBESCA9ICdmcmljYXRpdmUnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBGYCA9ICdmcmljYXRpdmUnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEcgPSAnc3RvcCcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSEggPSAnZnJpY2F0aXZlJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBKSCA9ICdhZmZyaWNhdGUnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEsgPSAnc3RvcCcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTCA9ICdsaXF1aWQnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE0gPSAnbmFzYWwnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE4gPSAnbmFzYWwnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5HID0gJ25hc2FsJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBQID0gJ3N0b3AnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFIgPSAnbGlxdWlkJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBTID0gJ2ZyaWNhdGl2ZScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU0ggPSAnZnJpY2F0aXZlJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBTUCA9ICdwYXVzZScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYFRgID0gJ3N0b3AnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRIID0gJ2ZyaWNhdGl2ZScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgViA9ICdmcmljYXRpdmUnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFcgPSAnZ2xpZGUnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFkgPSAnZ2xpZGUnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFogPSAnZnJpY2F0aXZlJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBaSCA9ICdmcmljYXRpdmUnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5kZWZhdWx0ID0gJ3Zvd2VsJykpCnRhYmxlKGl5X2FoJG1hbm5lcikKYGBgCgoKIyMjIExlYXZlIEEgVHJhaWwgb2YgQ3J1bWJzIApCZSBzdXJlIHRvIGFuc3dlciB0aGlzIHF1ZXN0aW9uOiBIb3cgY2FuIEkgcHJlc2VydmUgYSByZWNvcmQgb2YgdGhpcyBvYnNlcnZhdGlvbiBpbiBzdWNoIGEgd2F5IHRoYXQgSSBjYW4gcXVpY2tseSByZXR1cm4gdG8gaXQgYW5kIGdhdGhlciBtb3JlIGRhdGEgb24gaXQgaWYgbmVjZXNzYXJ5PyBJZiB5b3UgZmFpbCB0byBzdWNjZXNzZnVsbHkgYW5zd2VyIHRoaXMgcXVlc3Rpb24sIHRoZW4geW91J2xsIGJlIGxvc3QgaW4gdGhlIHdvb2RzIGlmIHlvdSBldmVyIHdhbnQgdG8gcmVzdHVkeSwgYW5kIHRoZSBvbmx5IHdheSBob21lIGlzIHRvIHJlcGxpY2F0ZSB0aGUgc3R1ZHkgZnJvbSBzY3JhdGNoLgoKIyMjIEdpdmUgTWVhbmluZ2Z1bCBOYW1lcwpHaXZlIG1lYW5pbmdmdWwgbmFtZXMgdG8gYm90aCB0aGUgbmFtZXMgb2YgcHJlZGljdG9yIGNvbHVtbnMsIGFzIHdlbGwgYXMgdG8gbGFiZWxzIG9mIG5vbWluYWwgb2JzZXJ2YXRpb25zLiBLZWVwaW5nIGEgcmVhZG1lIGRlc2NyaWJpbmcgdGhlIGRhdGEgaXMgc3RpbGwgYSBnb29kIGlkZWEsIGJ1dCBhdCBsZWFzdCBub3cgdGhlIGRhdGEgaXMgYXBwcm9hY2hhYmxlIGF0IGZpcnN0IGdsYW5jZS4KCiMjIyBEaXN0aW5ndWlzaCBiZXR3ZWVuIGAwYCBhbmQgYE5BYApJIGhhdmUgd29ya2VkIHdpdGggc29tZSBzcHJlYWRzaGVldHMgd2hlcmUgbWlzc2luZyBkYXRhIHdhcyBnaXZlbiBhIHZhbHVlIG9mIGAwYCwgd2hpY2ggd2lsbCBtZXNzIHRoaW5ncyB1cC4gRm9yIGV4YW1wbGUsIC9veS8gaXMgYSBmYWlybHkgcmFyZWx5IG9jY3VycmluZyBwaG9uZW1lIGluIEVuZ2xpc2gsIGFuZCBpdCdzIHBvc3NpYmxlIHRoYXQgYSBzcGVha2VyIHdvbid0IHByb2R1Y2UgYW55IHRva2VucyBpbiBhIHNob3J0IGludGVydmlldy4gSW4gYSBzcHJlYWRzaGVldCBvZiBtZWFuIEYxIGFuZCBGMiBmb3IgYWxsIHZvd2VscywgdGhhdCBzcGVha2VyIHNob3VsZCBnZXQgYW4gYE5BYCBmb3IgL295LywgKipub3QqKiBgMGAuCgojIyBTdG9yaW5nIERhdGEKCldoZW4gd2Ugc3RvcmUgZGF0YSwgaXQgc2hvdWxkIGJlOgoKKEByYXcpCioqUmF3KioKUmF3IGRhdGEgaXMgdGhlIG1vc3QgdXNlZnVsIGRhdGEuIEl0J3MgaW1wb3NzaWJsZSB0byBtb3ZlIGRvd24gdG8gc21hbGxlciBncmFudWxhcml0eSBmcm9tIGEgY29hcnNlciwgc3VtbWFyaXplZCBncmFudWxhcml0eS4gU3VtbWFyeSB0YWJsZXMgZXRjLiBhcmUgbmljZSBmb3IgcHVibGlzaGluZyBpbiBhIHBhcGVyIGRvY3VtZW50LCBidXQgcmF3IGRhdGEgaXMgd2hhdCB3ZSBuZWVkIGZvciBhc2tpbmcgbm92ZWwgcmVzZWFyY2ggcXVlc3Rpb25zIHdpdGggb2xkIGRhdGEuCgooQG9wZW4pCioqT3BlbiBmb3JtYXR0ZWQqKgpEbyBub3QgdXNlIHByb3ByaWV0YXJ5IGRhdGFiYXNlIHNvZnR3YXJlIGZvciBsb25nIHRlcm0gc3RvcmFnZSBvZiB5b3VyIGRhdGEuIEkgaGF2ZSBlbm91Z2ggaGVhcmQgc3RvcmllcyBhYm91dCBpbnRlcmVzdGluZyBkYXRhIHNldHMgdGhhdCBhcmUgbm8gbG9uZ2VyIGFjY2Vzc2libGUgZm9yIHJlc2VhcmNoIGVpdGhlciBiZWNhdXNlIHRoZSBzb2Z0d2FyZSB0aGV5IGFyZSBzdG9yZWQgaW4gaXMgZGVmdW5jdCwgb3IgY3VycmVudCB2ZXJzaW9ucyBhcmUgbm90IGJhY2t3YXJkcyBjb21wYXRpYmxlLiBBdCB0aGF0IHBvaW50LCB5b3VyIGRhdGEgaXMgcHJvcGVydHkgb2YgTWljcm9zb2Z0LCBvciB3aG9ldmVyLiBTdG9yZSB5b3VyIGRhdGEgYXMgcmF3IHRleHQsIGRlbGltaXRlZCBpbiBzb21lIHdheSAoSSBwcmVmZXIgdGFicykuCgooQGNvbnNpc3RlbnQpCioqQ29uc2lzdGVudCoqCkkgdGhpbmsgdGhpcyBpcyBtb3N0IGltcG9ydGFudCB3aGVuIHlvdSBtYXkgaGF2ZSBkYXRhIGluIG1hbnkgc2VwYXJhdGUgZmlsZXMuIEVhY2ggZmlsZSBhbmQgaXRzIGhlYWRlcnMgc2hvdWxkIGJlIGNvbnNpc3RlbnRseSBuYW1lZCBhbmQgZm9ybWF0dGVkLiBUaGV5IHNob3VsZCBiZSBjb25zaXN0ZW50bHkgZGVsaW1pdGVkIGFuZCBjb21tZW50ZWQgYWxzby4gVGhlcmUgaXMgbm90aGluZyB3b3JzZSB0aGFuIGluY29uc2lzdGVudCBoZWFkZXJzIGFuZCBlcnJhdGljIGNvbW1lbnRzLCBsYWJlbHMsIGhlYWRlcnMgb3IgTkEgY2hhcmFjdGVycyBpbiBhIGNvcnB1cy4gKEF1dG9tYXRpb24gYWxzbyBoZWxwcyBoZXJlLikKCihAZG9jdW1lbnRlZCkKKipEb2N1bWVudGVkKioKUHJvZHVjZSBhIHJlYWRtZSBkZXNjcmliaW5nIHRoZSBkYXRhLCBob3cgaXQgd2FzIGNvbGxlY3RlZCBhbmQgcHJvY2Vzc2VkLCBhbmQgZGVzY3JpYmUgZXZlcnkgdmFyaWFibGUgYW5kIGl0cyBwb3NzaWJsZSB2YWx1ZXMuCgo8aHIvPgojIFN0cnVjdHVyaW5nIERhdGEKCiMjIEJyZWFraW5nIEJhZCBTcHJlYWRzaGVldCBIYWJpdHMKCkxldCdzIHN0YXJ0IG9mZiBieSBsb29raW5nIGF0IGEgcGljdHVyZSBvZiBhIGRhdGEgb3JnYW5pemF0aW9uIGFwcHJvYWNoIHRoYXQgbWlnaHQgbG9vayBmYW1pbGlhciwgYW5kIGlzIGEgKnZlcnkgYmFkKiB3YXkgdG8gZG8gdGhpbmdzOgoKIVtdKGZpZ3VyZXMvYmFkX3NwcmVhZHNoZWV0LnBuZykKClRoaXMgc3ByZWFkc2hlZXQgaGFzIGEgZmFpcmx5IHN0cmljdCBvcmdhbml6YXRpb25hbCBzdHJ1Y3R1cmUsIGJ1dCBpcyB2aXJ0dW91c2x5IGhvcGVsZXNzIGZvciBkb2luZyBhbnkga2luZCBvZiBzZXJpb3VzIHN0YXRpc3RpY2FsIGFuYWx5c2lzLiBJdCdzIGFsc28gdmVyZ2luZyBvbiBpcnJlcGFyYWJsZSB1c2luZyBSLiBUaGlzIGJlY2F1c2UgdGhlIGRhdGEgaW4gdGhpcyBzcHJlYWRzaGVldCBpcyBvcmdhbml6ZWQgdG8gYmUgZWFzeSB0byBsb29rIGF0IHdpdGggeW91ciBleWViYWxscyDwn5GALiAKCkJ1dCBsb29raW5nIGF0IG5lYXRseSBvcmdhbml6ZWQgZGF0YSBpbiBhIHNwcmVhZHNoZWV0IGlzIG5vdCBhIHN0YXRpc3RpY2FsIGFuYWx5c2lzIHRlY2huaXF1ZS4gU28gd2UgbmVlZCB0byBzdGFydCBvcmdhbml6aW5nIG91ciBkYXRhIGluIGEgd2F5IHRoYXQgaXNuJ3QgZWFzeSB0byBsb29rIGF0LCBidXQgKmlzKiBlYXN5IHRvIGdyYXBoIGFuZCBhbmFseXplLgoKCgojIyBCZXR0ZXIgSGFiaXRzCgpFdmVyeW9uZSB3b3JraW5nIHdpdGggZGF0YSAoaW4gUiBvciBvdGhlcndpc2UpIHNob3VsZCByZWFkIEhhZGxleSBXaWNraGFtJ3MgcGFwZXIgb24gVGlkeSBEYXRhOiBbaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL3RpZHlyL3ZpZ25ldHRlcy90aWR5LWRhdGEuaHRtbF0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL3RpZHlyL3ZpZ25ldHRlcy90aWR5LWRhdGEuaHRtbCkgSWYgeW91IGFyZSBjb21pbmcgb2ZmIG9mIG9yZ2FuaXppbmcgeW91ciBkYXRhIGxpa2UgdGhlIHBpY3R1cmUgYWJvdmUsIHRoZXJlIGFyZSBhIGZldyBndWlkZWxpbmVzIG5vdCBkaXNjdXNzZWQgaW4gdGhhdCBwYXBlciwgbmFtZWx5OgoKIyMjIyBGb2xsb3cgdGhlc2UgcnVsZXMKMS4gVGhlIGZpcnN0IHJvdyBvZiB0aGUgZGF0YSAqbXVzdCogYmUgdGhlIG5hbWVzIG9mIHRoZSBkYXRhIGNvbHVtbnMuCjIuIEFsbCBvdGhlciByb3dzICptdXN0KiBiZSB0aGUgZGF0YSwgYW5kIG5vdGhpbmcgZWxzZS4KMy4gWW91IGNhbm5vdCB1c2UgZW1wdHkgcm93cyBvciBlbXB0eSBjb2x1bW5zIGFzIHZpc3VhbCBhaWRzIHRvIGxvb2sgYXQgdGhlIGRhdGEuCjQuIFRoZSBzcHJlYWRzaGVldCBtdXN0IG5vdCBjb250YWluIGFueSBzdW1tYXJ5IGNlbGxzLiBObyBmaW5hbCByb3cgY2FsbGVkICJBdmVyYWdlIiBvciBmaW5hbCBjb2x1bW4gY2FsbGVkICJUb3RhbCIuIFdlIGNhbiBjcmVhdGUgdGhlc2UgaW4gUiwgYW5kIHRoZXkgbWFrZSBkYXRhIHByb2Nlc3NpbmcgbW9yZSBjb21wbGljYXRlZCBpZiB0aGV5J3JlIGluY2x1ZGVkIGluIHRoZSByYXcgZGF0YS4KCiMjIyBTZW1hbnRpY3Mgb2YgRGF0YSBTdHJ1Y3R1cmUKCkluIHRoZSBzZW1hbnRpY3Mgb2YgZGF0YSBzdHJ1Y3R1cmUgV2lja2hhbSBsYXlzIG91dCwgdGhlcmUgYXJlIHRocmVlIGltcG9ydGFudCBwcmltaXRpdmVzOgoKMS4gVmFyaWFibGVzCjMuIFZhbHVlcwoyLiBPYnNlcnZhdGlvbnMKCiMjIyMgRGVmaW5pbmcgdGhlIHByaW1pdGl2ZXMKCiMjIyMjIFZhcmlhYmxlcwoKVmFyaWFibGVzIGFyZSB0aGUgY29sbGVjdGlvbnMgb2YgdmFsdWVzIG9mIGludGVyZXN0IGluIGRhdGEgYW5hbHlzaXMuIEZvciBleGFtcGxlLCBsZXQncyBzYXkgeW91IHdlcmUgZG9pbmcgYSBzdHVkeSBvbiB1bm5vcm1hbGl6ZWQgdm93ZWwgc3BhY2Ugc2l6ZSBieSBqdXN0IGxvb2tpbmcgYXQgL2k6LyBhbmQgL8mRLy4gVGhlIHZhcmlhYmxlcyBpbiB0aGF0IHN0dWR5IGNvdWxkIGJlOgoKLSBgc3BlYWtlcmAKLSBgd29yZGAKLSBgcGhvbmVtZWAKLSBgZHVyYXRpb25gCi0gYEYxYAotIGBGMmAKLSBgd29yZF9mcmVxdWVuY3lgCgojIyMjIyBWYWx1ZXMKClZhbHVlcyBhcmUsIGFzIHRoZSBuYW1lIGltcGxpZXMsIHRoZSBwb3NzaWJsZSB2YWx1ZXMgdGhhdCBlYWNoIHZhcmlhYmxlIGNhbiBoYXZlLCBmb3IgZXhhbXBsZToKCi0gYHNwZWFrZXJgOiBgIk9ha2xleSJgLCBgIkNoYXJsaWUiYCwgYCJBemFyaWEiYCwgYC4uLmAKLSBgd29yZGA6IGAic3RyZWV0ImAsIGAidGhpcnRlZW4iYCwgYCJub3QiYCwgYCJnb3QiYCwgYC4uLmAKLSBgcGhvbmVtZWA6IGAiaXkiYCwgYCJhaCJgCgoKIyMjIyMgT2JzZXJ2YXRpb25zCgpBbiBvYnNlcnZhdGlvbiBpcyB0aGUgbWluaW1hbCB1bml0IGFjcm9zcyB3aGljaCBhbGwgdmFyaWFibGVzIGFyZSBjb2xsZWN0ZWQuIEZvciBleGFtcGxlLCBpbiB0aGUgdm93ZWwgc3BhY2Ugc3R1ZHksIG9uZSBvYnNlcnZhdGlvbiB3b3VsZCBiZSBvbmUgaW5zdGFuY2Ugb2YgYW4gdXR0ZXJlZCB2b3dlbCBmb3Igd2hpY2ggeW91IHJlY29yZCB3aG8gdGhlIHNwZWFrZXIgd2FzLCB0aGUgd29yZCwgdGhlIGR1cmF0aW9uLCBGMSwgRjIsIGV0Yy4KCiMjIyMgT3JnYW5pemluZyBkYXRhIHdpdGggdGhlc2UgcHJpbWl0aXZlcwoKT25jZSB5b3UndmUgdGhvdWdodCB0aHJvdWdoIHdoYXQgdGhlIHZhcmlhYmxlcywgdmFsdWVzIGFuZCBvYnNlcnZhdGlvbnMgYXJlIGZvciB5b3VyIHN0dWR5LCB0aGUgcHJpbmNpcGxlIG9mIGhvdyB0byBvcmdhbml6ZSB0aGVtIGlzIHNpbXBsZToKCjEuIEVhY2ggdmFyaWFibGUgZm9ybXMgYSBjb2x1bW4uCjIuIEVhY2ggb2JzZXJ2YXRpb24gZm9ybXMgYSByb3cuCgpGb3IgdGhlIHZvd2VsIHNwYWNlIHNpemUgc3R1ZHksIHlvdSBtaWdodCB3YW50IHRvIHdpbmQgdXAgd2l0aCBhIHBsb3QgdGhhdCBsb29rcyBsaWtlIHRoaXM6CgpgYGB7ciBlY2hvID0gRiwgZGV2ID0gJ3N2ZycsIGZpZy53aWR0aD0xMS8yLCBmaWcuaGVpZ2h0PTUvMn0KaXlfYWggJT4lCiAgZ3JvdXBfYnkoaWRzdHJpbmcsIHNleCwgYWdlLCBwbHRfdmNsYXNzKSAlPiUKICBzdW1tYXJpc2UoRjEgPSBtZWFuKEYxKSwKICAgICAgICAgICAgRjIgPSBtZWFuKEYyKSkgJT4lCiAgZ2dwbG90KGFlcyhGMiwgRjEsIHNoYXBlID0gcGx0X3ZjbGFzcywgY29sb3IgPSBzZXgpKSsKICAgIGdlb21fcG9pbnQoKSsKICAgIHNjYWxlX3lfcmV2ZXJzZSgpKwogICAgc2NhbGVfeF9yZXZlcnNlKCkrCiAgICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIpKwogICAgc2NhbGVfc2hhcGVfZGlzY3JldGUoInZvd2VsIikrCiAgICB0aGVtZV9taW5pbWFsKCkrCiAgICBjb29yZF9maXhlZCgpCiAgCmBgYAoKCgpJdCB3b3VsZG4ndCBiZSB1bmNvbW1vbiB0byBzZWUgdGhlIGRhdGEgdW50aWRpbHkgb3JnYW5pemVkIGxpa2UgdGhpczoKCmBgYHtyIGVjaG8gPSBGfQppeV9haCAlPiUKICBncm91cF9ieShpZHN0cmluZywgc2V4LCBhZ2UsIHBsdF92Y2xhc3MpICU+JQogIHN1bW1hcmlzZShGMSA9IG1lYW4oRjEpLAogICAgICAgICAgICBGMiA9IG1lYW4oRjIpKSAlPiUKICBnYXRoZXIoZm9ybWFudCwgdmFsdWUsIEYxOkYyKSU+JQogIG11dGF0ZSh2YXIgPSBwYXN0ZShwbHRfdmNsYXNzLCBmb3JtYW50LCBzZXAgPSAiXyIpKSAlPiUKICBzZWxlY3QoLXBsdF92Y2xhc3MsIC1mb3JtYW50KSU+JQogIHNwcmVhZCh2YXIsIHZhbHVlKQpgYGAKCjxkaXYgY2xhc3MgPSAiYm94IGJyZWFrIj4KPHNwYW4gY2xhc3M9ImJpZy1sYWJlbCI+fjUgTWludXRlIEFjdGl2aXR5PC9zcGFuPgoKSW4gc21hbGwgZ3JvdXBzLCBmaWd1cmUgb3V0IHRoZSBmb2xsb3dpbmc6CgotIFdoYXQgYXJlIHRoZSB2YXJpYWJsZXMgaW4gdGhlIGRhdGEgZnJhbWUgYWJvdmU/Ci0gV2hhdCBhcmUgdGhlIHZhbHVlcz8KLSBXaGF0IGFyZSB0aGUgb2JzZXJ2YXRpb25zPwotIEhvdyBzaG91bGQgdGhlIHRhYmxlIGFib3ZlIGJlIHJlLW9yZ2FuaXplZD8KCmBgYHtyIGVjaG8gPSBGfQppeV9haCAlPiUKICBncm91cF9ieShpZHN0cmluZywgc2V4LCBhZ2UsIHBsdF92Y2xhc3MpICU+JQogIHN1bW1hcmlzZShGMSA9IG1lYW4oRjEpLAogICAgICAgICAgICBGMiA9IG1lYW4oRjIpKQpgYGAKCgo8L2Rpdj4KCgo8aHIvPgojIERhdGEgRnJhbWVzCgpTbyBmYXIgd2UgaGF2ZSBkaXNjdXNzZWQgdGhlIGZvbGxvd2luZyB0eXBlcyBvZiB2YWx1ZXMgaW4gUjoKCi0gbnVtZXJpY2FsCi0gY2hhcmFjdGVyCi0gbG9naWNhbAoKQW5kIHdlJ3ZlIGRpc2N1c3NlZCB0aGUgZm9sbG93aW5nIGRhdGEgc3RydWN0dXJlcy4KCi0gdmVjdG9ycwoKSGVyZSwgd2UnbGwgY292ZXIgb25lIG5ldyBkYXRhIHN0cnVjdHVyZToKCi0gZGF0YSBmcmFtZXMKCkRhdGEgRnJhbWVzIGFyZSB0aGUgZGF0YSBzdHJ1Y3R1cmUgd2UnbGwgYmUgdXNpbmcgdGhlIG1vc3QgaW4gUi4KV2hlbiB5b3UgYmVnaW4gdGhpbmtpbmcgYWJvdXQgZGF0YSBmcmFtZXMsIGEgdXNlZnVsIHN0YXJ0aW5nIHBsYWNlIGlzIHRvIHRoaW5rIG9mIHRoZW0gYXMgc3ByZWFkc2hlZXRzLCB3aXRoIGNvbHVtbnMgYW5kIHJvd3MgKGJ1dCB3ZSdsbCBldmVudHVhbGx5IGFiYW5kb24gc3ByZWFkc2hlZXQgdGhpbmtpbmcpLgpMZXQncyBzdGFydCBvdXQgYnkgY3JlYXRpbmcgYSB2ZXJ5IHNpbXBsZSBkYXRhIGZyYW1lIHVzaW5nIHRoZSBgZGF0YS5mcmFtZSgpYCBmdW5jdGlvbi4KCmBgYHtyfQogIHBpdGNoIDwtIGRhdGEuZnJhbWUoc3BlYWtlcl9uYW1lcyA9IGMoIkNoYXJsaWUiLCAiU2t5bGVyIiwgIlNhd3llciIsICJKYW1pZSIpLAogICAgICAgICAgICAgICAgICAgICAgYWdlcyA9IGMoMTgsIDM1LCA0MSwgNjIpLAogICAgICAgICAgICAgICAgICAgICAgRjAgPSBjKDExNCwgMTg5LCAxODksIDE5OSkpCgogIHBpdGNoCmBgYAoKCiMjIEZpbmRpbmcgeW91ciB3YXkgYXJvdW5kIAoKVGhlIGBwaXRjaGAgZGF0YSBmcmFtZSBoYXMgZm91ciByb3dzLCBhbmQgdGhyZWUgY29sdW1ucy4KVGhlIHJvd3MgYXJlIGp1c3QgbnVtYmVyZWQgMSB0aHJvdWdoIDQsIGFuZCB0aGUgdGhyZWUgY29sdW1ucyBhcmUgbmFtZWQgYHNwZWFrZXJfbmFtZXNgLCBgYWdlc2AgYW5kIGBGMGAuClRvIGZpbmQgb3V0IGhvdyBtYW55IHJvd3MgYW5kIGNvbHVtbnMgYSBkYXRhIGZyYW1lIGhhcywgeW91IGNhbiB1c2UgdGhlIGBucm93KClgIGFuZCBgbmNvbCgpYCBmdW5jdGlvbnMuCgoKCmBgYHtyfQogIG5yb3cocGl0Y2gpCiAgbmNvbChwaXRjaCkKYGBgCgpNb3N0IGRhdGEgZnJhbWVzIHlvdSdyZSBnb2luZyB0byB3b3JrIHdpdGggaGF2ZSBhIGxvdCBtb3JlIHJvd3MgdGhhbiB0aGF0LgpGb3IgZXhhbXBsZSwgYGl5X2FoYCBpcyBhIGRhdGEgZnJhbWUgdGhhdCBpcyBidW5kbGVkIGluIHRoZSBgbHNhMjAxN2AgcGFja2FnZS4KCmBgYHtyfQogIG5yb3coaXlfYWgpCmBgYAoKVGhhdCdzIHRvbyBtYW55IHJvd3MgdG8gbG9vayBhdCBqdXN0IGluIHRoZSBjb25zb2xlLgpPbmUgb3B0aW9uIGlzIHRvIHVzZSB0aGUgYGhlYWQoKWAgZnVuY3Rpb24sIHRoYXQganVzdCBwcmludHMgdGhlIGZpcnN0IDYgcm93cy4KCmBgYHtyfQogIGhlYWQoaXlfYWgpCmBgYAoKQW5vdGhlciBvcHRpb24gaXMgdG8gdXNlIHRoZSBgc3VtbWFyeSgpYCBmdW5jdGlvbi4gCgpgYGB7cn0KICBzdW1tYXJ5KGl5X2FoKQpgYGAKCmBzdW1tYXJ5KClgIGlzIGEgZnVuY3Rpb24gdGhhdCB3b3JrcyBvbiBhbG1vc3QgZXZlcnkga2luZCBvZiBvYmplY3QuCgoKIyMgSW5kZXhpbmcgRGF0YSBGcmFtZXMKClNpbmNlIGRhdGEgZnJhbWVzIGFyZSAyIGRpbWVuc2lvbmFsIChyb3dzIGFyZSBvbmUgZGltZW5zaW9uLCBjb2x1bW5zIGFyZSBhbm90aGVyKSwgdGhlIHdheSB5b3UgaW5kZXggdGhlbSBpcyBhIGxpdHRsZSBiaXQgbW9yZSBjb21wbGljYXRlZCB0aGFuIHdpdGggdmVjdG9ycy4KSXQgc3RpbGwgdXNlcyBzcXVhcmUgYnJhY2tldHMsIHRob3VnaCwgYnV0IHRoZXNlIHNxdWFyZSBicmFja2V0cyBoYXZlIHR3byBwb3NpdGlvbnM6Cgo8ZGl2IHN0eWxlPSJmb250LWZhbWlseTptb25vc3BhY2U7Zm9udC1zaXplOnh4LWxhcmdlO3RleHQtYWxpZ246Y2VudGVyOyI+CjxzcGFuIHN0eWxlPSJjb2xvcjojNzQ3NDc0Ij5kZjwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6cmVkIj5bPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjojNzQ3NDc0Ij5yb3cgbnVtYmVyPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjpyZWQiPiw8L3NwYW4+IDxzcGFuIHN0eWxlPSJjb2xvcjojNzQ3NDc0Ij5jb2x1bW4gbnVtYmVyPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjpyZWQiPl08L3NwYW4+CjwvZGl2PgoKSWYgeW91IHNwZWNpZnkgYSBzcGVjaWZpYyByb3cgbnVtYmVyLCBidXQgbGVhdmUgdGhlIGNvbHVtbiBudW1iZXIgYmxhbmssIHlvdSdsbCBnZXQgYmFjayB0aGF0IHJvdyBhbmQgYWxsIGNvbHVtbnMuCgpgYGB7cn0KICBwaXRjaFsxLF0KYGBgCgpBbHRlcm5hdGl2ZWx5LCBpZiB5b3Ugc3BlY2lmeSBqdXN0IHRoZSBjb2x1bW4gbnVtYmVyLCBidXQgbGVhdmUgdGhlIHJvd3MgYmxhbmssIHlvdSdsbCBnZXQgYmFjayBhbGwgb2YgdGhlIHZhbHVlcyBmb3IgdGhhdCBjb2x1bW4uCmBgYHtyfQogIHBpdGNoWywyXQpgYGAKCldoZW4geW91IHNwZWNpZnkgYm90aCwgeW91IGdldCBiYWNrIHRoZSB2YWx1ZSBpbiB0aGUgc3BlY2lmaWVkIHJvdyBhbmQgY29sdW1uCmBgYHtyfQogIHBpdGNoWzEsMl0KYGBgCgpIb3dldmVyLCB0aGVyZSBpcyBhIHNwZWNpYWwgaW5kZXhpbmcgb3BlcmF0b3IgZm9yIGRhdGEgZnJhbWVzIHRoYXQgdGFrZSBhZHZhbnRhZ2Ugb2YgdGhlaXIgbmFtZWQgY29sdW1uczogYCRgLgoKPGRpdiBzdHlsZT0iZm9udC1mYW1pbHk6bW9ub3NwYWNlO2ZvbnQtc2l6ZTp4eC1sYXJnZTt0ZXh0LWFsaWduOmNlbnRlciI+CjxzcGFuIHN0eWxlPSJjb2xvcjojNzQ3NDc0Ij5kZjwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6cmVkIj4kPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjojNzQ3NDc0Ij5jb2x1bW5fbmFtZTwvc3Bhbj4KPC9kaXY+CgpgYGB7cn0KICBwaXRjaCRzcGVha2VyX25hbWVzCmBgYAoKCkFmdGVyIGFjY2Vzc2luZyB0aGUgY29sdW1uIG9mIGEgZGF0YSBmcmFtZSwgeW91IGNhbiBpbmRleCBpdCBqdXN0IGxpa2UgaXQncyBhIHZlY3Rvci4KCmBgYHtyfQogIHBpdGNoJHNwZWFrZXJfbmFtZXNbMV0KYGBgCgpJZiB5b3UgcmVhbGx5IHdhbnQgdG8sIHlvdSBjYW4gZG8gbG9naWNhbCBpbmRleGluZyBvZiBkYXRhIGZyYW1lcyBsaWtlIHNvOgoKYGBge3J9CiAgcGl0Y2hbcGl0Y2gkc3BlYWtlcl9uYW1lcyA9PSAiQ2hhcmxpZSIsIF0KYGBgCgpCdXQgdGhlcmUncyBhbHNvIGEgZnVuY3Rpb24gY2FsbGVkIGBmaWx0ZXIoKWAgdGhhdCB5b3UgY2FuIHVzZSB0byBkbyB0aGUgc2FtZSB0aGluZy4KYGZpbHRlcigpYCB0YWtlcyBhIGRhdGEgZnJhbWUgYXMgaXRzIGZpcnN0IGFyZ3VtZW50LCBhbmQgdGhlbiBhIGxvZ2ljYWwgc3RhdGVtZW50IHJlZmVycmluZyB0byBvbmUgb3IgbW9yZSBvZiB0aGUgZGF0YSBmcmFtZSdzIGNvbHVtbnMuCgoKYGBge3J9CiAgZmlsdGVyKHBpdGNoLCBzcGVha2VyX25hbWVzID09ICJDaGFybGllIikKICBmaWx0ZXIocGl0Y2gsIGFnZXMgPiAxOCwgRjAgPiAxOTApCmBgYAoKPGRpdiBjbGFzcyA9ICJib3ggYnJlYWsiPgo8c3BhbiBjbGFzcz0iYmlnLWxhYmVsIj5+NSBNaW51dGUgQWN0aXZpdHk8L3NwYW4+CgpGaXJzdCwgcmV2aWV3IHRoZSBkb2N1bWVudGF0aW9uIG9mIHRoZSBgaXlfYWhgIGRhdGEgc2V0IHdpdGggYD9peV9haGAuIFVzaW5nIGBmaWx0ZXIoKWAgYW5kIGBucm93KClgLCBmaW5kIG91dCB3aGF0IHBlcmNlbnQgb2YgL2k6LyB0b2tlbnMgaGF2ZSBhIGR1cmF0aW9uIGxlc3MgdGhhbiA5MG1zICgwLjA5cykuCgo8L2Rpdj4KCjxoci8+CiMgUmVhZGluZyBEYXRhIGludG8gUgoKUiBjYW4gZWFzaWx5IHJlYWQgY29tbWEtc2VwYXJhdGVkICguY3N2KSBmaWxlcyBhbmQgdGFiLWRlbGltaXRlZCBmaWxlcyBpbnRvIGl0cyBtZW1vcnkuXltNeSBwZXJzb25hbCBhZXN0aGV0aWMgcHJlZmVyZW5jZSBpcyBmb3IgdGFiLWRlbGltaXRlZCBmaWxlcy5dCllvdSBjYW4gcmVhZCB0aGVtIGluIHdpdGggYHJlYWQuY3N2KClgIGFuZCBgcmVhZC5kZWxpbSgpYCwgcmVzcGVjdGl2ZWx5LgpJZiB5b3VyIGRhdGEgaXMgdW5hdm9pZGFibHkgaW4gYW4gRXhjZWwgc3ByZWFkc2hlZXQsIHRoZXJlIGlzIGEgcGFja2FnZSBjYWxsZWQgYHJlYWR4bGAgd2l0aCBhIGZ1bmN0aW9uIGNhbGxlZCBgcmVhZF9leGNlbCgpYApJZiB5b3UgaGF2ZSB0aGUgYHJlYWR4bGAgcGFja2FnZSBpbnN0YWxsZWQsIEkgKnN0cm9uZ2x5KiByZWNvbW1lbmQgcmVhZGluZyBvdmVyIGl0cyBkb2N1bWVudGF0aW9uIG9uIHNoZWV0IGdlb21ldHJ5IGJ5IGNhbGxpbmcgdXAgdGhlIHZpZ25ldHRlIGxpa2Ugc286CgpgYGB7cn0KdmlnbmV0dGUoInNoZWV0LWdlb21ldHJ5IiwgcGFja2FnZSA9ICJyZWFkeGwiKQpgYGAKCioqTGFzdCBNaW51dGUgVXBkYXRlKio6IFRoZXJlIGlzIGFsc28gcGFja2FnZSBmb3IgcmVhZGluZyBkYXRhIGluIGZyb20gZ29vZ2xlIHNwcmVhZHNoZWV0cyBbaHR0cHM6Ly9naXRodWIuY29tL2plbm55YmMvZ29vZ2xlc2hlZXRzXShodHRwczovL2dpdGh1Yi5jb20vamVubnliYy9nb29nbGVzaGVldHMpLiBJIGhhdmVuJ3QgdXNlZCBpdCB5ZXQsIGJ1dCBpdCdzIGdvdHRlbiBnb29kIHJldmlld3MuCgoKV2hlbiBsb2FkaW5nIGEgZGF0YSBmaWxlIGludG8gUiwgeW91IGFyZSBqdXN0IGxvYWRpbmcgaXQgaW50byB0aGUgUiB3b3Jrc3BhY2UuIApBbnkgYWx0ZXJhdGlvbnMgb3IgbW9kaWZpY2F0aW9ucyB5b3UgbWFrZSB0byB0aGUgZGF0YSBmcmFtZSB3aWxsIG5vdCBiZSByZWZsZWN0ZWQgaW4gdGhlIGZpbGUgaW4geW91ciBzeXN0ZW0sICpqdXN0KiBpbiB0aGUgY29weSBpbiB0aGUgUiB3b3Jrc3BhY2UuCgpUaGUgdHJpY2t5IHRoaW5nIG5vdyBpcyB0aGF0IHRoZSB3YXkgdGhhdCBmZWVscyBtb3N0IG5hdHVyYWwgb3Igbm9ybWFsIGZvciB5b3UgdG8gb3JnYW5pemUgYW5kIG5hbWUgeW91ciBmaWxlcyBhbmQgZm9sZGVycyBkb2Vzbid0IG5lY2Vzc2FyaWx5IHRyYW5zbGF0ZSBpbnRvIGEgZ29vZCB3YXkgZm9yIFIgKG9yIG90aGVyIHByb2dyYW1taW5nIGxhbmd1YWdlcykgdG8gbG9vayBhdCB0aGVtLgpJbiBvcmRlciB0byBsb2FkIGEgZmlsZSBpbnRvIFIsIHlvdSBuZWVkIHRvIHByb3ZpZGUgYHJlYWQuY3N2KClgIG9yIGByZWFkLmRlbGltKClgIHdpdGggdGhlICJwYXRoIiB0byB0aGUgZmlsZSwgd2hpY2ggaXMganVzdCBhIHRleHQgc3RyaW5nLiAKCkZvciBleGFtcGxlLCBoZXJlJ3MgYSBzY3JlZW5zaG90IG9mIGEgZGF0YSBmaWxlIEknZCBsaWtlIHRvIGxvYWQgaW50byBSLgoKIVtdKGZpZ3VyZXMvZmlsZS5wbmcpCgpJIGhhdmUgdGhlIG9wdGlvbiB0dXJuZWQgb24gaW4gbXkgc3lzdGVtIHRvIHNlZSB0aGUgZnVsbCBwYXRoIGF0IHRoZSBib3R0b20gb2YgdGhlIGZpbGUgd2luZG93LCBzbyB5b3UgY2FuIHNlZSBhIGZ1bGwgbGlzdCBvZiBhbGwgb2YgdGhlIGZvbGRlcnMgdGhpcyBkYXRhIGZpbGUgaXMgZW1iZWRkZWQgaW4uCkluIG9yZGVyIHRvIHJlYWQgdGhpcyBkYXRhIGludG8gUiwgeW91IG5lZWQgdG8gdHlwZSBvdXQgdGhlIGZ1bGwgcGF0aCwgYWx0aG91Z2ggYSBuaWNlIHRoaW5nIGFib3V0IAoKCmBgYHtyIGV2YWwgPSBGfQogIGpvZV92b3dlbHMgPC0gcmVhZC5jc3YoIn4vb3duQ2xvdWQvRG9jU3luY1VvRS9Db3Vyc2VzL0xTQS9kYXRhL2pvZV92b3dlbHMuY3N2IikKYGBgCgpJZiB5b3UncmUgbm90IHN1cmUgd2hhdCBpdCBsb29rcyBsaWtlIG9uIHlvdXIgc3lzdGVtLCB1c2UgdGhlIGBmaWxlLmNob29zZSgpYCBmdW5jdGlvbi4KCmBgYHtyIGV2YWwgPSBGfQogIGZpbGUuY2hvb3NlKCkKYGBgCgpUaGF0J2xsIGxhdW5jaCB0aGUgZGVmYXVsdCB2aXN1YWwgZmlsZSBicm93c2VyIGZvciB5b3VyIHN5c3RlbS4KQWZ0ZXIgYnJvd3NpbmcgYXJvdW5kIGFuZCBjbGlja2luZyBvbiBhIGZpbGUsIGBmaWxlLmNob29zZSgpYCB3aWxsIHByaW50IHRoZSBjaGFyYWN0ZXIgc3RyaW5nIHRoYXQgcmVwcmVzZW50cyB0aGUgcGF0aCB0byB0aGF0IGZpbGUgaW50byB0aGUgY29uc29sZS4KCjxkaXYgY2xhc3MgPSAiYm94IGh5Z2llbmUiPgo8c3BhbiBjbGFzcyA9ICJsYWJlbCI+SHlnaWVuZTwvc3Bhbj4KCkRvbid0IHJlbHkgaGVhdmlseSBvbiBgZmlsZS5jaG9vc2UoKWAuIFNvbWV0aW1lcywgSSd2ZSBzZWVuIFIgc2NyaXB0cyB3aXRoIHRoZSBmb2xsb3dpbmcgbGluZSBvZiBjb2RlIGluIGl0OgoKYGBge3J9CmRhdGEgPC0gcmVhZC5jc3YoZmlsZS5jaG9vc2UoKSkKYGBgCgpQbGVhc2UgbmV2ZXIgZG8gdGhpcy4KSSB3b3VsZCBjYXV0aW9uIGFnYWluc3QgdXNpbmcgaXQgaW4gYW55IGNvZGUsIHNjcmlwdHMgb3Igbm90ZWJvb2tzIGF0IGFsbC4gT25seSBldmVyIHVzZSBpdCB0byByZWZyZXNoIHlvdXIgbWVtb3J5IG9mIHdoZXJlIHlvdXIgZGF0YSBpcyBsb2NhdGVkLiBCeSBhbHdheXMgd3JpdGluZyBvdXQgdGhlIHRoZSB0ZXh0IG9mIHRoZSBwYXRoIHRvIHRoZSBkYXRhLCB5b3UKCi0gcHJvZHVjZSBtb3JlIHRyYW5zcGFyZW50IGNvZGUKLSBhbGxvdyB5b3Vyc2VsZiB0byByZS1ydW4geW91ciBhbmFseXNpcyB3aXRob3V0IG5lZWRpbmcgdG8gY2xpY2sgYXJvdW5kCi0gZW5zdXJlIHRoYXQgeW91J3JlIHVzaW5nIHRoZSBzYW1lIGRhdGEgZmlsZSBldmVyeSBzaW5nbGUgdGltZQoKPC9kaXY+CgpPbmUgcHJldHR5IGNvb2wgdGhpbmcgaXMgdGhhdCBpZiBhIGRhdGEgZmlsZSBpcyB1cCBvbiBhIHdlYnNpdGUgc29tZXdoZXJlLCB5b3UgY2FuIGp1c3QgYWNjZXNzIGl0IGJ5IHBhc3NpbmcgdGhlIHVybCB0byBgcmVhZC5jc3YoKWAgb3IgYHJlYWQuZGVsaW0oKWAuXltUaGlzIGRvZXNuJ3Qgd29yayBpZiB0aGUgZmlsZSBpcyBiZWhpbmQgZW5jcnlwdGlvbiwgaS5lLiBpZiBpdCBiZWdpbnMgd2l0aCBgaHR0cHM6Ly9gLl0KSGVyZSBpcyBzb21lIHNhbXBsZSBkYXRhIG9uIHRoZSBEb25uZXIgUGFydHkuXlsiVGhlIERvbm5lciBQYXJ0eSAoc29tZXRpbWVzIGNhbGxlZCB0aGUgRG9ubmVyLVJlZWQgUGFydHkpIHdhcyBhIGdyb3VwIG9mIEFtZXJpY2FuIHBpb25lZXIgbWlncmFudHMgd2hvIHNldCBvdXQgZm9yIENhbGlmb3JuaWEgaW4gYSB3YWdvbiB0cmFpbi4gRGVsYXllZCBieSBhIHNlcmllcyBvZiBtaXNoYXBzLCB0aGV5IHNwZW50IHRoZSB3aW50ZXIgb2YgMTg0NuKAkzQ3IHNub3dib3VuZCBpbiB0aGUgU2llcnJhIE5ldmFkYXMuIFNvbWUgb2YgdGhlIG1pZ3JhbnRzIHJlc29ydGVkIHRvIGNhbm5pYmFsaXNtIHRvIHN1cnZpdmUsIGVhdGluZyB0aG9zZSB3aG8gaGFkIHN1Y2N1bWJlZCB0byBzdGFydmF0aW9uIGFuZCBzaWNrbmVzcy4iCltodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9Eb25uZXJfUGFydHldKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0Rvbm5lcl9QYXJ0eSkKXQoKYGBge3J9CiAgZG9ubmVyIDwtIHJlYWQuY3N2KCJodHRwOi8vam9mcmh3bGQuZ2l0aHViLmlvL2RhdGEvZG9ubmVyLmNzdiIpCiAgaGVhZChkb25uZXIpCmBgYAoKPGRpdiBjbGFzcyA9ICJib3ggYnJlYWsiPgogIDxzcGFuIGNsYXNzID0gImJpZy1sYWJlbCI+fjUgbWludXRlIGFjdGl2aXR5PC9zcGFuPiAKICAKRG93bmxvYWQgdGhlIGZpbGUgYGpvZV92b3dlbHMuY3N2YCBmcm9tIHRoZSBjb3Vyc2UgQ2FudmFzLiBTYXZlIGl0IHRvIHRoZSBkYXRhIGRpcmVjdG9yeSBmb3IgdGhlIGNvdXJzZSwgb3Igd2hlcmV2ZXIgeW91IHdvdWxkIGxpa2UgdG8ga2VlcCBpdC4gUmVhZCBpdCBpbnRvIFIuIFdoYXQncyBteSBtZWFuIEYxIGFuZCBGMiBhY3Jvc3MgYWxsIG9mIG15IHZvd2Vscz8KCjwvZGl2PgoKCjxoci8+CgojIENsZWFuaW5nIHVwIGRhdGEKCldlJ3ZlIGRpc2N1c3NlZCBob3cgZGF0YSBvdWdodCB0byBiZSB0aWRpbHkgb3JnYW5pemVkLCBhbmQgd2UndmUgbm93IGdvbmUgb3ZlciBob3cgdG8gbG9hZCBkYXRhLCBhbmQgbWluaW1hbGx5IGV4cGxvcmUgZGF0YWZyYW1lcyBpbiBSLiBMZXQncyBxdWlja2x5IGdvIG92ZXIgaG93IHRvIHRpZHkgdXAgbWVzc3kgZGF0YSBhIGxpdHRsZS4KCkZpcnN0LCBsZXQncyBsb29rIGF0IHRoZSB3aWRlIGBpeV9haF93aWRlYCBkYXRhZnJhbWUsIHdoaWNoIGlzIHBhcnQgb2YgdGhlIGBsc2EyMDE3YCBwYWNrYWdlLgoKYGBge3J9Cml5X2FoX3dpZGUKYGBgCgoKVGhlIHByb2JsZW0gd2l0aCB0aGlzIGRhdGEgaXMKCi0gVGhlcmUgYXJlICp2YWx1ZXMqIHNwcmVhZCBhY3Jvc3MgdGhlIGNvbHVtbnMuCi0gSW5kaXZpZHVhbCBjb2x1bW4gbmFtZXMgaGF2ZSBjb21iaW5lZCB0aGVzZSAqdmFsdWVzKiB3aXRoIHNvbWUgKnZhcmlhYmxlcyouCgpHZXR0aW5nIHRvIGEgdGlkaWVyIGZvcm1hdCBvZiB0aGUgZGF0YSB3aWxsIGludm9sdmUgYSB0aHJlZSBzdGVwIHByb2Nlc3M6CgoxLiBDb252ZXJ0aW5nIHRoaXMgd2lkZSBkYXRhIGZvcm1hdCB0byBhIGxvbmcgZGF0YSBmb3JtYXQuCjIuIFNlcGFyYXRpbmcgdGhlIHZvd2VsIGNsYXNzIHZhbHVlcyBmcm9tIHRoZSBmb3JtYW50IHZhcmlhYmxlLgozLiBTcHJlYWRpbmcgdGhlIGZvcm1hbnQgdmFyaWFibGVzIGJhY2sgb3V0IGFsb25nIHRoZSBjb2x1bW4gc3BhY2UuJwoKV2UgY2FuIGRvIHRoaXMgZWFzaWx5IHdpdGggdGhlIGZ1bmN0aW9ucyBgZ2F0aGVyKClgLCBgc2VwYXJhdGUoKWAgYW5kIGBzcHJlYWQoKWAgZnJvbSB0aGUgYHRpZHlyYCBwYWNrYWdlLgoKRm9yIGEgc21hbGxlciBpbGx1c3RyYXRpdmUgcHVycG9zZSBmb3IgcGVvcGxlIHdobyBtYXkgZmVlbCB1bmVhc3kgYWJvdXQgdm93ZWxzIGFuZCBmb3JtYW50cywgSSdsbCBiZSBpbGx1c3RyYXRpbmcgZWFjaCBvZiB0aGVzZSBzdGVwcyB3aXRoIGEgc2ltcGxlciBkYXRhIHNldCBhYm91dCBob3cgbWFueSBhcHBsZXMgYW5kIG9yYW5nZXMgdHdvIHBlb3BsZSBib3VnaHQsIGFuZCBob3cgbWFueSB0aGV5IGF0ZS4KCmBgYHtyfQpmcnVpdCA8LSBkYXRhLmZyYW1lKHBlcnNvbiA9IGMoIk9ha2xleSIsICJDaGFybGllIiksCiAgICAgICAgICAgICAgICAgYXBwbGVzX2JvdWdodCA9IGMoNSwgMyksCiAgICAgICAgICAgICAgICAgYXBwbGVzX2F0ZSA9IGMoMSwgMiksCiAgICAgICAgICAgICAgICAgb3Jhbmdlc19ib3VnaHQgPSBjKDUsIDQpLAogICAgICAgICAgICAgICAgIG9yYW5nZXNfYXRlID0gYygzLCAzKSkKYGBgCgoKYGBge3IgZWNobyA9IEYsIHJlc3VsdHMgPSAnYXNpcyd9CmxpYnJhcnkoa25pdHIpCmthYmxlKGZydWl0KQpgYGAKCgpOb3RlLCBldmVuIHRob3VnaCB0aGUgY29sdW1uIGxhYmVscyBsb29rIGRpZmZlcmVudCwgdGhpcyBpcyBpcyBhbiBlcXVpdmFsZW50IHRhYmxlIHRvIGZvcm1hdHRpbmcgaW52b2x2aW5nIG1lcmdlZCBjb2x1bW4gbGFiZWwgY2VsbHMuCgo8ZGl2IGNsYXNzID0gImhhbGYtaW1nIj4KCiFbXShmaWd1cmVzL21lcmdlX3RhYi5wbmcpCgo8L2Rpdj4KCiMjIEdhdGhlcmluZyBDb2x1bW5zCgpUaGUgYGdhdGhlcigpYCBmdW5jdGlvbiBtYWtlcyAqd2lkZSogZGF0YSAqbG9uZy4qIEl0IHRha2VzIHRoZSBmb2xsb3dpbmcgYXJndW1lbnRzOgoKPGRpdiBjbGFzcyA9ICJpbGx1c3RyYXRlIj4KZ2F0aGVyKDxzcGFuIGNsYXNzPSJwb3AiPmRhdGE8L3NwYW4+LCA8c3BhbiBjbGFzcyA9ICJwb3AiPmtleTwvc3Bhbj4sIDxzcGFuIGNsYXNzID0gInBvcCI+dmFsdWU8L3NwYW4+LCBjb2xzKQo8L2Rpdj4KCi0gYGRhdGFgCiAgICAtIE9idmlvdXNseSwgdGhlIGRhdGEgeW91IHdhbnQgdG8gcmVzaGFwZS4gbXVzdCBiZSBhIGRhdGEgZnJhbWUuCi0gYGtleWAgYW5kIGB2YWx1ZWAKICAgIC0gVGhlc2UgYXJlIG5ldyBjb2x1bW4gbmFtZXMgdGhhdCB5b3Ugd2FudCB0byBjcmVhdGUuIGBnYXRoZXIoKWAgaXMgZ29pbmcgdG8gdGFrZSB0aGUgY29sdW1uIG5hbWVzIGFuZCBwdXQgdGhlbSBpbiB0aGUgY29sdW1uIHlvdSBnaXZlIHRvIGBrZXlgLCBhbmQgdGhlIHZhbHVlcyBmcm9tIGFsbCB0aGUgY2VsbHMgYW5kIHB1dCB0aGVtIGluIHRoZSBjb2x1bW4geW91IGNhbGwgYHZhbHVlYC4KLSBgY29sc2AKICAgIC0gQW4gaW5kaWNhdGlvbiBvZiB3aGljaCBjb2x1bW5zIHlvdSB3YW50IHRvIGdhdGhlciwgZWl0aGVyIGEgdmVjdG9yIG9mIGNvbHVtbiBuYW1lcywgYSB2ZWN0b3Igb2YgY29sdW1uIG51bWJlcnMsIG9yIHNvbWUgc3BlY2lhbGl6ZWQgbWV0aG9kcyBmb3IgYGdhdGhlcigpYCB0aGF0IHdlJ2xsIGRpc2N1c3MuCiAgICAKCkhlcmUncyBob3cgdGhhdCdsbCB3b3JrIGZvciB0aGUgZnJ1aXQgZGF0YS4gV2UnbGwgdGVsbCBgZ2F0aGVyKClgIHRvIGdhdGhlciBjb2x1bW5zIDIgdGhyb3VnaCA1LgoKYGBge3J9CmZydWl0X2xvbmcgPC0gZ2F0aGVyKGRhdGEgPSBmcnVpdCwKICAgICAgICAgICAgICAgICAgICAga2V5ID0gZnJ1aXRfYmVoYXZpb3IsCiAgICAgICAgICAgICAgICAgICAgIHZhbHVlID0gbnVtYmVyLAogICAgICAgICAgICAgICAgICAgICAyOjUpCmBgYApgYGB7ciBlY2hvPUYsIHJlc3VsdHMgPSAnYXNpcyd9CmthYmxlKGZydWl0X2xvbmcpCmBgYApgZ2F0aGVyKClgIGhhcyByZXR1cm5lZCBhIG5ldyBkYXRhIGZyYW1lLiBJdCBoYXMgY3JlYXRlZCBhIG5ldyBjb2x1bW4gY2FsbGVkIGBmcnVpdF9iZWhhdmlvcmAsIGJlY2F1c2Ugd2UgdG9sZCBpdCB0byB3aXRoIHRoZSBga2V5YCBhcmd1bWVudCwgYW5kIGl0IGhhcyBjcmVhdGVkIGEgbmV3IGNvbHVtbiBjYWxsZWQgYG51bWJlcmAsIGJlY2F1c2Ugd2UgdG9sZCBpdCB0byB3aXRoIHRoZSBgdmFsdWVgIGZ1bmN0aW9uLiBJdCBoYXMgdGFrZW4gYWxsIG9mIHRoZSBjb2x1bW4gbmFtZXMgb2YgdGhlIGNvbHVtbnMgd2UgdG9sZCBpdCB0byBnYXRoZXIsIGFuZCBwdXQgdGhlbSBpbnRvIHRoZSBgZnJ1aXRfYmVoYXZpb3JgIGNvbHVtbiwgYW5kIHRoZSBudW1lcmljIHZhbHVlcyBmcm9tIHRoZSBjb2x1bW5zIHdlIHRvbGQgaXQgdG8gZ2F0aGVyLCBhbmQgcHV0IHRoZW0gaW50byB0aGUgYG51bWJlcmAgY29sdW1uLiBJdCBoYXMgYWxzbyByZXBlYXRlZCB0aGUgcm93cyBvZiB0aGUgb3RoZXIgY29sdW1ucyAoYHBlcnNvbmApIGFzIGxvZ2ljYWxseSBuZWNlc3NhcnkuIAoKTm93LCB3ZSB0b2xkIGl0IHRvIGdhdGhlciBjb2x1bW4gbnVtYmVycyAyIHRocm91Z2ggNSwgYnV0IHRoaXMgd291bGQgaGF2ZSBhbHNvIHdvcmtlZDoKCmBgYHtyfQpnYXRoZXIoZGF0YSA9IGZydWl0LCAKICAgICAgIGtleSA9IGZydWl0X2JlaGF2aW9yLCAKICAgICAgIHZhbHVlID0gbnVtYmVyLCAKICAgICAgIGMoImFwcGxlc19ib3VnaHQiLCJhcHBsZXNfYXRlIiwgIm9yYW5nZXNfYm91Z2h0IiwgIm9yYW5nZXNfYXRlIikpCmBgYAoKCmBnYXRoZXIoKWAgYWxzbyBoYXMgYSBtb3JlIGNvbnZlbmllbnQgbWV0aG9kIG9mIHNwZWNpZnlpbmcgdGhlIGNvbHVtbnMgeW91IHdhbnQgdG8gZ2F0aGVyIGJ5IHBhc3NpbmcgaXQgYSBuYW1lZCByYW5nZSBvZiBjb2x1bW5zLiBXZSB3YW50IHRvIGdhdGhlciBhbGwgY29sdW1ucyBmcm9tIGBhcHBsZXNfYm91Z2h0YCB0byBgb3Jhbmdlc19hdGVgLCBzbyB3ZSBjYW4gdGVsbCBpdCB0byBkbyBzbyB3aXRoIGBhcHBsZXNfYm91Z2h0Om9yYW5nZXNfYXRlYC4KCmBgYHtyfQpnYXRoZXIoZGF0YSA9IGZydWl0LCAKICAgICAgIGtleSA9IGZydWl0X2JlaGF2aW9yLCAKICAgICAgIHZhbHVlID0gbnVtYmVyLCAKICAgICAgIGFwcGxlc19ib3VnaHQ6b3Jhbmdlc19hdGUpCmBgYAoKCk9rLCBsZXQncyBkbyB0aGlzIG5vdyB0byB0aGUgYGl5X2FoX3dpZGVgIGRhdGEsIGdhdGhlcmluZyBhbGwgb2YgdGhlIGNvbHVtbnMgZnJvbSBgYWhfRjFgIHRvIGBpeV9GMmAuCgoKYGBge3J9Cml5X2FoX3N0ZXAxIDwtIGdhdGhlcihkYXRhID0gaXlfYWhfd2lkZSwgCiAgICAgICAgICAgICAgICAgICAgICBrZXkgPSB2b3dlbF9mb3JtYW50LCAKICAgICAgICAgICAgICAgICAgICAgIHZhbHVlID0gaHosIAogICAgICAgICAgICAgICAgICAgICAgYWhfRjE6aXlfRjIpCml5X2FoX3N0ZXAxCmBgYAoKRm9yIHRoZSBmcnVpdCBkYXRhLCB0aGUgb25seSB1bi1nYXRoZXJlZCBjb2x1bW4gd2FzIGBwZXJzb25gLCBidXQgZm9yIGBpeV9haF93aWRlYCwgYGlkc3RyaW5nYCwgYGFnZWAsIGBzZXhgLCBhbmQgYHllYXJgLCB3ZXJlIGFsbCB1bmdhdGhlcmVkLiBIZXJlIHlvdSBjYW4gc2VlIGhvdyBhbGwgcm93cyBvZiB1bmdhdGhlcmVkIGNvbHVtbnMgYXJlIHJlcGVhdGVkIGFzIGxvZ2ljYWxseSBuZWNlc3NhcnkuCgojIyBTZXBhcmF0aW5nIENvbHVtbnMKClRoZXJlIGlzIHN0aWxsIGEgcHJvYmxlbSB3aXRoIGJvdGggdGhlIGBmcnVpdF9sb25nYCBhbmQgdGhlIGBpeV9haF9zdGVwMWAgZGF0YSBmcmFtZXMsIHdoaWNoIGlzIHRoYXQgdHdvIGRpZmZlcmVudCBraW5kcyBvZiBkYXRhIGFyZSBtZXJnZWQgd2l0aGluIG9uZSBjb2x1bW4uIEZvciBgaXlfYWhfc3RlcDFgLCB0aGUgdm93ZWwgY2xhc3MgYW5kIGZvcm1hbnQgdmFyaWFibGUgYXJlIG1lcmdlZCB0b2dldGhlciAoZS5nLiBgYWhfRjFgKSBhbmQgZm9yIGBmcnVpdF9sb25nYCwgdGhlIGZydWl0IGFuZCBiZWhhdmlvciBhcmUgbWVyZ2VkIHRvZ2V0aGVyIChlLmcuIGBhcHBsZV9ib3VnaHRgKS4gV2UgbmVlZCB0byBzZXBhcmF0ZSB0aGVzZSwgd2l0aCBhIHZlcnkgYXB0bHkgbmFtZWQgZnVuY3Rpb24gY2FsbGVkIGBzZXBhcmF0ZSgpYAoKPGRpdiBjbGFzcyA9ICJpbGx1c3RyYXRlIj4Kc2VwYXJhdGUoPHNwYW4gY2xhc3MgPSAicG9wIj5kYXRhPC9zcGFuPiwgPHNwYW4gY2xhc3MgPSAicG9wIj5jb2w8L3NwYW4+LCA8c3BhbiBjbGFzcyA9ICJwb3AiPmludG88L3NwYW4+LCA8c3BhbiBjbGFzcyA9ICJwb3AiPnNlcDwvc3Bhbj4pCjwvZGl2PgoKLSBgZGF0YWAKICAgIC0gQWdhaW4sdGhlIGRhdGEgZnJhbWUgeW91IHdhbnQgdG8gZG8gdGhpcyBzZXBhcmF0aW9uIHRvLgotIGBjb2xgCiAgICAtIFRoZSBuYW1lIG9mIHRoZSBjb2x1bW4geW91IHdhbnQgdG8gc2VwYXJhdGUuCi0gYGludG9gCiAgICAtIEEgY2hhcmFjdGVyIHZlY3RvciBvZiB0aGUgbmV3IGNvbHVtbiBuYW1lcyB5b3Ugd2FudCB0byBjcmVhdGUuCi0gYHNlcGAKICAgIC0gVGhlIGNoYXJhY3RlciBvciByZWdleCBwYXR0ZXJuIHlvdSB3YW50IHRvIHVzZSB0byBzcGxpdCB1cCB0aGUgdmFsdWVzIGluIGBjb2xgLgoKSGVyZSdzIGhvdyBpdCB3b3JrcyBmb3IgYGZydWl0X2xvbmdgLiAKCmBgYHtyfQpmcnVpdF9zZXBhcmF0ZSA8LSBzZXBhcmF0ZShkYXRhID0gZnJ1aXRfbG9uZywKICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sID0gZnJ1aXRfYmVoYXZpb3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGludG8gPSBjKCJmcnVpdCIsICJiZWhhdmlvciIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICBzZXAgPSAiXyIpCmBgYApgYGB7ciBlY2hvID0gRiwgcmVzdWx0cz0nYXNpcyd9CmthYmxlKGZydWl0X3NlcGFyYXRlKQpgYGAKCkl0IGhhcyByZXR1cm5lZCBhIG5ldyBkYXRhIGZyYW1lIHdpdGggdGhlIGBmcnVpdF9iZWhhdmlvcmAgY29sdW1uIHNwbGl0IGludG8gdHdvIG5ldyBjb2x1bW5zLCBuYW1lZCBhZnRlciB3aGF0IEkgcGFzc2VkIHRvIHRoZSBgaW50b2AgYXJndW1lbnQuIEl0IHNwbGl0IHVwIGBmcnVpdF9iZWhhdmlvcmAgYmFzZWQgb24gd2hhdCBJIHBhc3NlZCB0byBgc2VwYCwgd2hpY2ggd2FzIHRoZSB1bmRlcnNjb3JlIGNoYXJhY3Rlci4gCgpMZXQncyBkbyB0aGlzIGZvciBgaXlfYWhfc3RlcDFgIG5vdy4KCgpgYGB7cn0KaXlfYWhfc3RlcDIgPC0gc2VwYXJhdGUoaXlfYWhfc3RlcDEsIAogICAgICAgICAgICAgICAgICAgICAgICB2b3dlbF9mb3JtYW50LCAKICAgICAgICAgICAgICAgICAgICAgICAgaW50byA9IGMoInZvd2VsIiwgImZvcm1hbnQiKSwKICAgICAgICAgICAgICAgICAgICAgICAgc2VwID0gIl8iKQppeV9haF9zdGVwMgpgYGAKCldlIG5vdyBoYXZlIHR3byBzZXBhcmF0ZSBjb2x1bW5zIGZvciBgdm93ZWxgIGFuZCBgZm9ybWFudGAuCgo8ZGl2IGNsYXNzID0gImJveCBoeWdpZW5lIj4KPHNwYW4gY2xhc3MgPSAibGFiZWwiPkh5Z2llbmU8L3NwYW4+CgpJIGhhdmUgYmVlbiB2ZXJ5IGhlbHBmdWwgYW5kIHVzZWQgdW5kZXJzY29yZXMgdG8gbWVyZ2UgdG9nZXRoZXIgdGhlIHZhbHVlcyB3ZSB3YW50IHRvIHNlcGFyYXRlLiBCZSBoZWxwZnVsIHRvIHlvdXJzZWxmLCBhbmQgYmUgY29uc2lzdGVudCBpbiB0aGUgc2VtYW50aWNzIG9mIGhvdyB5b3UgdXNlZCBwb3RlbnRpYWwgZGVsaW1pdGVycyBsaWtlIGAtYCBhbmQgYF9gLiBIZXJlJ3MgYW4gZXhhbXBsZSBvZiBiZWluZyBoZWxwZnVsIHRvIHlvdXJzZWxmOgoKYGBgCnByb2plY3Rfc3ViamVjdF9maXJzdG5hbWUtbGFzdG5hbWUKCkVESV8xX1N0dWFydC1EdWRkaW5nc3RvbgpFRElfMl9Db25ub3ItQmxhY2stTWFjZG93YWxsCkVESV8zX01oYWlyaQpgYGAKVGhpcyBpcyBoZWxwZnVsLCBiZWNhdXNlIHdoZW4geW91IHNlcGFyYXRlIGJ5IHVuZGVyc2NvcmUsIHlvdSdsbCBoYXZlIHNvbWV0aGluZyB0aWR5CgpgYGAKRURJICAgIDEgICAgU3R1YXJ0LUR1ZGRpbmdzdG9uCkVESSAgICAyICAgIENvbm5vci1CbGFjay1NYWNkb3dhbGwKRURJICAgIDMgICAgTWhhaXJpCmBgYAoKSWYgeW91IHVzZWQgYC1gIGZvciBldmVyeXRoaW5nLCB5b3UnbGwgaGF2ZSBjaGFvcyB3aGVuIHlvdSB0cnkgdG8gc2VwYXJhdGUgdGhlbSBiZWNhdXNlIHNvbWUgc3BlYWtlcnMgaGF2ZSAiZG91YmxlIGJhcnJlbGVkIiBuYW1lcywgYW5kIHNvbWUgc3BlYWtlcnMgaGF2ZSBvbmx5IGZpcnN0IG5hbWVzOgoKYGBgCiMgSW5wdXQ6CkVESS0xLVN0dWFydC1EdWRkaW5nc3RvbgpFREktMi1Db25ub3ItQmxhY2stTWFjZG93YWxsCkVESS0zLU1oYWlyaQoKIyBCZWNvbWVzCgpFREkgICAgMSAgICBTdHVhcnQgICAgRHVkZGluZ3N0b24KRURJICAgIDIgICAgQ29ubm9yICAgIEJsYWNrICAgICAgICBNYWNkb3dhbGwKRURJICAgIDMgICAgTWhhaXJpCmBgYAoKVGhpcyBnb2VzIGJleW9uZCBSIHByb2dyYW1taW5nLiBZb3Ugc2hvdWxkIG1ha2Ugc29tZSBkZWNpc2lvbnMgYW5kIHN0aWNrIHdpdGggdGhlbSBmb3IgYWxsIG9mIHlvdXIgZGF0YSBhbmFseXNpcywgaW5jbHVkaW5nIGZpbGUgbmFtaW5nLCBQcmFhdCB0aWVyIG5hbWluZywgZXRjLgoKPC9kaXY+CgojIyBTcHJlYWRpbmcgY29sdW1ucwoKV2UndmUgZ290IG9uZSBsYXN0IHN0ZXAsIHdoaWNoIGlzIHNwcmVhZGluZyB0aGUgdmFsdWVzIGluIHNvbWUgcm93cyBhY3Jvc3MgdGhlIGNvbHVtbiBzcGFjZS4gV2l0aCB0aGUgYGZydWl0YCBkYXRhLCB3ZSBtaWdodCBub3Qgd2FudCBhIGNvbHVtbiBjYWxsZWQgYGJlaGF2aW9yYCwgYnV0IGFjdHVhbGx5IGhhdmUgdHdvIGNvbHVtbnMgY2FsbGVkIGBib3VnaHRgIGFuZCBgYXRlYC4gRm9yIHRoZSB2b3dlbCBkYXRhLCB3ZSBkZWZpbml0ZWx5IGRvbid0IHdhbnQgb25lIGNvbHVtbiBjYWxsZWQgYGZvcm1hbnRgLiBXZSB3YW50IG9uZSBjYWxsZWQgYEYxYCBhbmQgb25lIGNhbGxlZCBgRjJgLiBXZSBjYW4gZG8gdGhpcyB3aXRoIHRoZSBgc3ByZWFkKClgIGZ1bmN0aW9uLgoKPGRpdiBjbGFzcyA9ICJpbGx1c3RyYXRlIj4Kc3ByZWFkKDxzcGFuIGNsYXNzID0gInBvcCI+ZGF0YTwvc3Bhbj4sIDxzcGFuIGNsYXNzID0gInBvcCI+a2V5PC9zcGFuPiwgPHNwYW4gY2xhc3MgPSAicG9wIj52YWx1ZTwvc3Bhbj4pCjwvZGl2PgoKLSBgZGF0YWAKICAgIC0gQWdhaW4sIHRoZSBkYXRhIHdlIHdhbnQgdG8gd29yayB3aXRoLgotIGBrZXlgCiAgICAtIFRoZSBjb2x1bW4gd2hvc2UgdmFsdWVzIHlvdSB3YW50IHRvIHNwcmVhZCBhY3Jvc3MgdGhlIGNvbHVtbiBzcGFjZS4KLSBgdmFsdWVgCiAgICAtIFRoZSBjb2x1bW4gd2l0aCB2YWx1ZXMgdGhhdCB5b3Ugd2FudCB0byBmaWxsIGluIHRoZSBjZWxscy4KCkhlcmUncyBob3cgdGhhdCBsb29rcyB3aXRoIHRoZSBgZnJ1aXRfc2VwYXJhdGVgIGRhdGEuCgpgYGB7cn0KZnJ1aXRfc3ByZWFkIDwtIHNwcmVhZChkYXRhID0gZnJ1aXRfc2VwYXJhdGUsCiAgICAgICAgICAgICAgICAgICAgICAga2V5ID0gYmVoYXZpb3IsCiAgICAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSBudW1iZXIpCmBgYApgYGB7ciBlY2hvID0gRiwgcmVzdWx0cyA9ICdhc2lzJ30Ka2FibGUoZnJ1aXRfc3ByZWFkKQpgYGAKClRoaXMgaGFzIGNyZWF0ZWQgYSBuZXcgZGF0YSBmcmFtZS4gSSB0b2xkIGBzcHJlYWQoKWAgdG8gc3ByZWFkIHRoZSB2YWx1ZXMgaW4gYGJlaGF2aW9yYCBhY3Jvc3MgdGhlIGNvbHVtbiBzcGFjZS4gQmVjYXVzZSBpdCBoYWQgb25seSB0d28gdW5pcXVlIHZhbHVlcyBpbiBpdCAoYGJvdWdodGAgYW5kIGBhdGVgKSwgaXQgaGFzIGNyZWF0ZWQgdHdvIG5ldyBjb2x1bW5zIGNhbGxlZCBgYm91Z2h0YCBhbmQgYGF0ZWAuIEFmdGVyIGNyZWF0aW5nIHRoZXNlIG5ldyBjb2x1bW5zLCBpdCBoYWQgdG8gZmlsbCBpbiB0aGUgbmV3IGNlbGxzIHdpdGggc29tZSB2YWx1ZXMsIGFuZCBJIHRvbGQgaXQgdG8gdXNlIHRoZSB2YWx1ZXMgaW4gYG51bWJlcmAgZm9yIHRoYXQuCgpIZXJlJ3MgaG93IHRoYXQgd29ya3Mgd2l0aCBgaXlfYWhfc3RlcDJgLgoKYGBge3J9Cml5X2FoX3N0ZXAzIDwtIHNwcmVhZChkYXRhID0gaXlfYWhfc3RlcDIsCiAgICAgICAgICAgICAgICAgICAgICBrZXkgPSBmb3JtYW50LAogICAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSBoeikKaXlfYWhfc3RlcDMKYGBgCgpOb3csIHdlJ3ZlIGZpbmFsbHkgZ290dGVuIHRvIGEgdGlkeSBkYXRhIGZvcm1hdC4gSW4gb3VyIG5leHQgbWVldGluZywgd2UnbGwgZGlzY3VzcyBob3cgdG8gY2hhaW4gdGhlc2UgdGhyZWUgZnVuY3Rpb25zIGludG8gb25lIGVhc3kgdG8gcmVhZCBwcm9jZXNzLgoKPGRpdiBjbGFzcyA9ICJib3ggaWRpb20iPgo8c3BhbiBjbGFzcyA9ICJsYWJlbCI+SWRpb208L3NwYW4+CgpZb3UgbWlnaHQgaGF2ZSBub3RpY2VkIHRoYXQgaW4gdGhlIGZ1bmN0aW9ucyBhYm92ZSwgSSd2ZSBwdXQgYSBuZXcgbGluZSBiZXR3ZWVuIGluZGl2aWR1YWwgZnVuY3Rpb24gYXJndW1lbnRzLiBJJ3ZlIGRvbmUgdGhpcyBiZWNhdXNlIHdoaXRlLXNwYWNlIGRvZXNuJ3QgbWF0dGVyIHdoZW4gaXQgY29tZXMgdG8gUi4gSSBjb3VsZCBoYXZlIHdyaXR0ZW4gdGhlc2Ugd2l0aCBqdXN0IHNwYWNlcyBiZXR3ZWVuIGVhY2ggYXJndW1lbnQsIGJ1dCB0aGF0IHdvdWxkIGJlIHRvbyB2aXN1YWxseSBjcm93ZGVkLgoKYGBge3J9CiMgY29tcGFyZQoKIyBPbmUgbGluZQpmcnVpdF9zZXBhcmF0ZSA8LSBzZXBhcmF0ZShkYXRhID0gZnJ1aXRfbG9uZywgY29sID0gZnJ1aXRfYmVoYXZpb3IsIGludG8gPSBjKCJmcnVpdCIsICJiZWhhdmlvciIpLCBzZXAgPSAiXyIpCgojIE5ldyBMaW5lcwpmcnVpdF9zZXBhcmF0ZSA8LSBzZXBhcmF0ZShkYXRhID0gZnJ1aXRfbG9uZywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbCA9IGZydWl0X2JlaGF2aW9yLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgaW50byA9IGMoImZydWl0IiwgImJlaGF2aW9yIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICBzZXAgPSAiXyIpCgpgYGAKCkkgZW5jb3VyYWdlIHlvdSB0byB1c2UgbmV3IGxpbmVzIHNpbWlsYXJseSB0byBnaXZlIHlvdXJzZWxmICJzb21lIHNwYWNlIHRvIGJyZWF0aGUiLiBEb24ndCBiZSBzaHkgYWJvdXQgaXQuIEJ1dCwgaWYgeW91IHB1dCBuZXdsaW5lcyBiZXR3ZWVuICpzb21lKiBhcmd1bWVudHMsIHlvdSBzaG91bGQgcmVhbGx5IHB1dCBuZXcgbGluZXMgYmV0d2VlbiAqYWxsKiBhcmd1bWVudHMuCjwvZGl2Pgo=
- - -
-
- -
- - - - - - - - diff --git a/teaching/courses/2017_lsa/lectures/Session_2.nb.qmd b/teaching/courses/2017_lsa/lectures/Session_2.nb.qmd new file mode 100644 index 0000000..eca33f3 --- /dev/null +++ b/teaching/courses/2017_lsa/lectures/Session_2.nb.qmd @@ -0,0 +1,678 @@ +--- +title: "Data and Data Frames" +order: 2 +knitr: + opts_chunk: + error: true + warning: false +--- + +# The Agenda + +- Talk about organizing, structuring & storing your data. +- Review some important data input/output options in R. +- Review about how data frames work in R. + +## Setup + +::: callout-note +## \~2 minute setup + +Make sure that your current RStudio project is set to your course project. Create and save your R notebook for today (I would recommend `02_lecture.Rmd`). Clear the workspace of anything left over from last time with the menu options `Session > Clear Workspace`. + +Load the important packages for today's work: + +```{r} +library(lsa2017) +library(tidyverse) +``` +::: + +------------------------------------------------------------------------ + +# Data Collection and Storage + +## General Principles of Data Collection + +### Over-collect (for some things) + +When collecting data in the first place, over-collect if at all possible or ethical. The world is a very complex place, so there is no way you could cram it all into a bottle, but give it your best shot! If during the course of your data analysis, you find that it would have been really useful to have data on, say, duration, as well as formant frequencies, it becomes costly to recollect that data, especially if you haven't laid the proper trail for yourself. On the other hand, *automation* of acoustic analysis or data processing can cut down on this costliness. + +This doesn't go for personal information on human subjects, though. It's important from an ethics standpoint to ask for everything you'll need, but not more. You don't want to collect an enormous demographic profile on your participants if you won't wind up using it, especially if you know you won't use it to begin with. + +### Preserve HiD Info + +If, for instance, you're collecting data on the effect of voicing on preceding vowel duration, preserve high dimensional data coding, like Lexical Item, or the transcription of the following segment. These high dimensional codings probably won't be too useful for your immediate analysis, but they will allow you to procedurally extract additional features from them at a later time. For example, if you have a column called `fol_seg`, which is just a transcription of the following segment, it is easy create a new column called `manner` with code that looks like this: + +```{r} +table(iy_ah$fol_seg) +``` + +```{r} +iy_ah <- iy_ah %>% + mutate( + manner = recode( + fol_seg, + B = 'stop', + CH = 'affricate', + D = 'stop', + DH = 'fricative', + `F` = 'fricative', + G = 'stop', + HH = 'fricative', + JH = 'affricate', + K = 'stop', + L = 'liquid', + M = 'nasal', + N = 'nasal', + NG = 'nasal', + P = 'stop', + R = 'liquid', + S = 'fricative', + SH = 'fricative', + SP = 'pause', + `T` = 'stop', + TH = 'fricative', + V = 'fricative', + W = 'glide', + Y = 'glide', + Z = 'fricative', + ZH = 'fricative', + .default = 'vowel' + ) + ) +table(iy_ah$manner) +``` + +### Leave A Trail of Crumbs + +Be sure to answer this question: How can I preserve a record of this observation in such a way that I can quickly return to it and gather more data on it if necessary? If you fail to successfully answer this question, then you'll be lost in the woods if you ever want to restudy, and the only way home is to replicate the study from scratch. + +### Give Meaningful Names + +Give meaningful names to both the names of predictor columns, as well as to labels of nominal observations. Keeping a readme describing the data is still a good idea, but at least now the data is approachable at first glance. + +### Distinguish between `0` and `NA` + +I have worked with some spreadsheets where missing data was given a value of `0`, which will mess things up. For example, /oy/ is a fairly rarely occurring phoneme in English, and it's possible that a speaker won't produce any tokens in a short interview. In a spreadsheet of mean F1 and F2 for all vowels, that speaker should get an `NA` for /oy/, **not** `0`. + +## Storing Data + +When we store data, it should be: + +Raw + +: Raw data is the most useful data. It's impossible to move down to smaller granularity from a coarser, summarized granularity. Summary tables etc. are nice for publishing in a paper document, but raw data is what we need for asking novel research questions with old data. + +Open Formatted + +: Do not use proprietary database software for long term storage of your data. I have enough heard stories about interesting data sets that are no longer accessible for research either because the software they are stored in is defunct, or current versions are not backwards compatible. At that point, your data is property of Microsoft, or whoever. Store your data as raw text, delimited in some way (I prefer tabs). + +Consistent + +: I think this is most important when you may have data in many separate files. Each file and its headers should be consistently named and formatted. They should be consistently delimited and commented also. There is nothing worse than inconsistent headers and erratic comments, labels, headers or NA characters in a corpus. (Automation also helps here.) + +Documented + +: Produce a readme describing the data, how it was collected and processed, and describe every variable and its possible values. + +------------------------------------------------------------------------ + +# Structuring Data + +## Breaking Bad Spreadsheet Habits + +Let's start off by looking at a picture of a data organization approach that might look familiar, and is a *very bad* way to do things: + +![](figures/bad_spreadsheet.png){fig-align="center" width="100%"} + +This spreadsheet has a fairly strict organizational structure, but is virtuously hopeless for doing any kind of serious statistical analysis. It's also verging on irreparable using R. This because the data in this spreadsheet is organized to be easy to look at with your eyeballs 👀. + +But looking at neatly organized data in a spreadsheet is not a statistical analysis technique. So we need to start organizing our data in a way that isn't easy to look at, but *is* easy to graph and analyze. + +## Better Habits + +Everyone working with data (in R or otherwise) should read Hadley Wickham's paper on Tidy Data: If you are coming off of organizing your data like the picture above, there are a few guidelines not discussed in that paper, namely: + +#### Follow these rules + +1. The first row of the data *must* be the names of the data columns. +2. All other rows *must* be the data, and nothing else. +3. You cannot use empty rows or empty columns as visual aids to look at the data. +4. The spreadsheet must not contain any summary cells. No final row called "Average" or final column called "Total". We can create these in R, and they make data processing more complicated if they're included in the raw data. + +### Semantics of Data Structure + +In the semantics of data structure Wickham lays out, there are three important primitives: + +1. Variables +2. Values +3. Observations + +#### Defining the primitives + +##### Variables + +Variables are the collections of values of interest in data analysis. For example, let's say you were doing a study on unnormalized vowel space size by just looking at /i:/ and /ɑ/. The variables in that study could be: + +- `speaker` +- `word` +- `phoneme` +- `duration` +- `F1` +- `F2` +- `word_frequency` + +##### Values + +Values are, as the name implies, the possible values that each variable can have, for example: + +- `speaker`: `"Oakley"`, `"Charlie"`, `"Azaria"`, `...` +- `word`: `"street"`, `"thirteen"`, `"not"`, `"got"`, `...` +- `phoneme`: `"iy"`, `"ah"` + +##### Observations + +An observation is the minimal unit across which all variables are collected. For example, in the vowel space study, one observation would be one instance of an uttered vowel for which you record who the speaker was, the word, the duration, F1, F2, etc. + +#### Organizing data with these primitives + +Once you've thought through what the variables, values and observations are for your study, the principle of how to organize them is simple: + +1. Each variable forms a column. +2. Each observation forms a row. + +For the vowel space size study, you might want to wind up with a plot that looks like this: + +```{r} +#| echo: false +#| dev: svg +iy_ah %>% + group_by(idstring, sex, age, plt_vclass) %>% + summarise(F1 = mean(F1), + F2 = mean(F2)) %>% + ggplot(aes(F2, F1, shape = plt_vclass, color = sex))+ + geom_point()+ + scale_y_reverse()+ + scale_x_reverse()+ + scale_color_brewer(palette = "Dark2")+ + scale_shape_discrete("vowel")+ + theme_minimal()+ + coord_fixed() + +``` + +It wouldn't be uncommon to see the data untidily organized like this: + +```{r} +#| echo: false +iy_ah %>% + group_by(idstring, sex, age, plt_vclass) %>% + summarise(F1 = mean(F1), + F2 = mean(F2)) %>% + gather(formant, value, F1:F2)%>% + mutate(var = paste(plt_vclass, formant, sep = "_")) %>% + select(-plt_vclass, -formant)%>% + spread(var, value) +``` + +::: callout-note +## \~5 minute activity + +In small groups, figure out the following: + +- What are the variables in the data frame above? +- What are the values? +- What are the observations? +- How should the table above be re-organized? + +```{r} +#| echo: false +iy_ah %>% + group_by(idstring, sex, age, plt_vclass) %>% + summarise(F1 = mean(F1), + F2 = mean(F2)) +``` +::: + +# Data Frames + +So far we have discussed the following types of values in R: + +- numerical +- character +- logical + +And we've discussed the following data structures. + +- vectors + +Here, we'll cover one new data structure: + +- data frames + +Data Frames are the data structure we'll be using the most in R. When you begin thinking about data frames, a useful starting place is to think of them as spreadsheets, with columns and rows (but we'll eventually abandon spreadsheet thinking). Let's start out by creating a very simple data frame using the `data.frame()` function. + +```{r} +pitch <- data.frame( + speaker_names = c("Charlie", "Skyler", "Sawyer", "Jamie"), + ages = c(18, 35, 41, 62), + F0 = c(114, 189, 189, 199) +) + +pitch +``` + +## Finding your way around + +The `pitch` data frame has four rows, and three columns. The rows are just numbered 1 through 4, and the three columns are named `speaker_names`, `ages` and `F0`. To find out how many rows and columns a data frame has, you can use the `nrow()` and `ncol()` functions. + +```{r} +nrow(pitch) +ncol(pitch) +``` + +Most data frames you're going to work with have a lot more rows than that. For example, `iy_ah` is a data frame that is bundled in the `lsa2017` package. + +```{r} +nrow(iy_ah) +``` + +That's too many rows to look at just in the console. One option is to use the `head()` function, that just prints the first 6 rows. + +```{r} +head(iy_ah) +``` + +Another option is to use the `summary()` function. + +```{r} +summary(iy_ah) +``` + +`summary()` is a function that works on almost every kind of object. + +## Indexing Data Frames + +Since data frames are 2 dimensional (rows are one dimension, columns are another), the way you index them is a little bit more complicated than with vectors. It still uses square brackets, though, but these square brackets have two positions: + +::: {style="font-family:monospace;font-size:xx-large;text-align:center;"} +[df]{style="color:#747474"}[\[]{style="color:red"}[row number]{style="color:#747474"}[,]{style="color:red"} [column number]{style="color:#747474"}[\]]{style="color:red"} +::: + +If you specify a specific row number, but leave the column number blank, you'll get back that row and all columns. + +```{r} +pitch[1,] +``` + +Alternatively, if you specify just the column number, but leave the rows blank, you'll get back all of the values for that column. + +```{r} +pitch[,2] +``` + +When you specify both, you get back the value in the specified row and column + +```{r} +pitch[1,2] +``` + +However, there is a special indexing operator for data frames that take advantage of their named columns: `$`. + +::: {style="font-family:monospace;font-size:xx-large;text-align:center"} +[df]{style="color:#747474"}[\$]{style="color:red"}[column_name]{style="color:#747474"} +::: + +```{r} +pitch$speaker_names +``` + +After accessing the column of a data frame, you can index it just like it's a vector. + +```{r} +pitch$speaker_names[1] +``` + +If you really want to, you can do logical indexing of data frames like so: + +```{r} +pitch[pitch$speaker_names == "Charlie", ] +``` + +But there's also a function called `filter()` that you can use to do the same thing. `filter()` takes a data frame as its first argument, and then a logical statement referring to one or more of the data frame's columns. + +```{r} +filter(pitch, speaker_names == "Charlie") +filter(pitch, ages > 18, F0 > 190) +``` + +::: callout-note +## \~5 minute activity + +First, review the documentation of the `iy_ah` data set with `?iy_ah`. Using `filter()` and `nrow()`, find out what percent of /i:/ tokens have a duration less than 90ms (0.09s). +::: + +------------------------------------------------------------------------ + +# Reading Data into R + +R can easily read comma-separated (.csv) files and tab-delimited files into its memory.[^1] You can read them in with `read.csv()` and `read.delim()`, respectively. If your data is unavoidably in an Excel spreadsheet, there is a package called `readxl` with a function called `read_excel()` If you have the `readxl` package installed, I *strongly* recommend reading over its documentation on sheet geometry by calling up the vignette like so: + +[^1]: My personal aesthetic preference is for tab-delimited files. + +```{r} +#| eval: false +vignette("sheet-geometry", package = "readxl") +``` + +**Last Minute Update**: There is also package for reading data in from google spreadsheets . I haven't used it yet, but it's gotten good reviews. + +When loading a data file into R, you are just loading it into the R workspace. Any alterations or modifications you make to the data frame will not be reflected in the file in your system, *just* in the copy in the R workspace. + +The tricky thing now is that the way that feels most natural or normal for you to organize and name your files and folders doesn't necessarily translate into a good way for R (or other programming languages) to look at them. In order to load a file into R, you need to provide `read.csv()` or `read.delim()` with the "path" to the file, which is just a text string. + +For example, here's a screenshot of a data file I'd like to load into R. + +![](figures/file.png){fig-align="center" width="100%"} + +I have the option turned on in my system to see the full path at the bottom of the file window, so you can see a full list of all of the folders this data file is embedded in. In order to read this data into R, you need to type out the full path, although a nice thing about + +```{r} +#| eval: false +joe_vowels <- read.csv("~/ownCloud/DocSyncUoE/Courses/LSA/data/joe_vowels.csv") +``` + +If you're not sure what it looks like on your system, use the `file.choose()` function. + +```{r eval = F} +#| eval: false +file.choose() +``` + +That'll launch the default visual file browser for your system. After browsing around and clicking on a file, `file.choose()` will print the character string that represents the path to that file into the console. + +::: callout-tip +## Hygiene + +Don't rely heavily on `file.choose()`. Sometimes, I've seen R scripts with the following line of code in it: + +```{r} +#| eval: false +data <- read.csv(file.choose()) +``` + +Please never do this. I would caution against using it in any code, scripts or notebooks at all. Only ever use it to refresh your memory of where your data is located. By always writing out the the text of the path to the data, you + +- produce more transparent code +- allow yourself to re-run your analysis without needing to click around +- ensure that you're using the same data file every single time +::: + +One pretty cool thing is that if a data file is up on a website somewhere, you can just access it by passing the url to `read.csv()` or `read.delim()`.[^2] Here is some sample data on the Donner Party.[^3] + +[^2]: This doesn't work if the file is behind encryption, i.e. if it begins with `https://`. + +[^3]: "The Donner Party (sometimes called the Donner-Reed Party) was a group of American pioneer migrants who set out for California in a wagon train. Delayed by a series of mishaps, they spent the winter of 1846--47 snowbound in the Sierra Nevadas. Some of the migrants resorted to cannibalism to survive, eating those who had succumbed to starvation and sickness." + +```{r} +donner <- read.csv("https://jofrhwld.github.io/data/donner.csv") +head(donner) +``` + +::: {.box .break} +[\~5 minute activity]{.big-label} + +Download the file `joe_vowels.csv` from the course Canvas. Save it to the data directory for the course, or wherever you would like to keep it. Read it into R. What's my mean F1 and F2 across all of my vowels? +::: + +------------------------------------------------------------------------ + +# Cleaning up data + +We've discussed how data ought to be tidily organized, and we've now gone over how to load data, and minimally explore dataframes in R. Let's quickly go over how to tidy up messy data a little. + +First, let's look at the wide `iy_ah_wide` dataframe, which is part of the `lsa2017` package. + +```{r} +iy_ah_wide +``` + +The problem with this data is + +- There are *values* spread across the columns. +- Individual column names have combined these *values* with some *variables*. + +Getting to a tidier format of the data will involve a three step process: + +1. Converting this wide data format to a long data format. +2. Separating the vowel class values from the formant variable. +3. Spreading the formant variables back out along the column space.' + +We can do this easily with the functions `gather()`, `separate()` and `spread()` from the `tidyr` package. + +For a smaller illustrative purpose for people who may feel uneasy about vowels and formants, I'll be illustrating each of these steps with a simpler data set about how many apples and oranges two people bought, and how many they ate. + +```{r} +fruit <- data.frame(person = c("Oakley", "Charlie"), + apples_bought = c(5, 3), + apples_ate = c(1, 2), + oranges_bought = c(5, 4), + oranges_ate = c(3, 3)) +``` + +```{r echo = F, results = 'asis'} +library(knitr) +kable(fruit) +``` + +Note, even though the column labels look different, this is is an equivalent table to formatting involving merged column label cells. + +::: half-img +![](figures/merge_tab.png) +::: + +## Gathering Columns + +The `gather()` function makes *wide* data *long.* It takes the following arguments: + +::: illustrate +gather([data]{.pop}, [key]{.pop}, [value]{.pop}, cols) +::: + +- `data` + - Obviously, the data you want to reshape. must be a data frame. +- `key` and `value` + - These are new column names that you want to create. `gather()` is going to take the column names and put them in the column you give to `key`, and the values from all the cells and put them in the column you call `value`. +- `cols` + - An indication of which columns you want to gather, either a vector of column names, a vector of column numbers, or some specialized methods for `gather()` that we'll discuss. + +Here's how that'll work for the fruit data. We'll tell `gather()` to gather columns 2 through 5. + +```{r} +fruit_long <- gather(data = fruit, + key = fruit_behavior, + value = number, + 2:5) +``` + +```{r echo=F, results = 'asis'} +kable(fruit_long) +``` + +`gather()` has returned a new data frame. It has created a new column called `fruit_behavior`, because we told it to with the `key` argument, and it has created a new column called `number`, because we told it to with the `value` function. It has taken all of the column names of the columns we told it to gather, and put them into the `fruit_behavior` column, and the numeric values from the columns we told it to gather, and put them into the `number` column. It has also repeated the rows of the other columns (`person`) as logically necessary. + +Now, we told it to gather column numbers 2 through 5, but this would have also worked: + +```{r} +gather(data = fruit, + key = fruit_behavior, + value = number, + c("apples_bought","apples_ate", "oranges_bought", "oranges_ate")) +``` + +`gather()` also has a more convenient method of specifying the columns you want to gather by passing it a named range of columns. We want to gather all columns from `apples_bought` to `oranges_ate`, so we can tell it to do so with `apples_bought:oranges_ate`. + +```{r} +gather(data = fruit, + key = fruit_behavior, + value = number, + apples_bought:oranges_ate) +``` + +Ok, let's do this now to the `iy_ah_wide` data, gathering all of the columns from `ah_F1` to `iy_F2`. + +```{r} +iy_ah_step1 <- gather(data = iy_ah_wide, + key = vowel_formant, + value = hz, + ah_F1:iy_F2) +iy_ah_step1 +``` + +For the fruit data, the only un-gathered column was `person`, but for `iy_ah_wide`, `idstring`, `age`, `sex`, and `year`, were all ungathered. Here you can see how all rows of ungathered columns are repeated as logically necessary. + +## Separating Columns + +There is still a problem with both the `fruit_long` and the `iy_ah_step1` data frames, which is that two different kinds of data are merged within one column. For `iy_ah_step1`, the vowel class and formant variable are merged together (e.g. `ah_F1`) and for `fruit_long`, the fruit and behavior are merged together (e.g. `apple_bought`). We need to separate these, with a very aptly named function called `separate()` + +::: illustrate +separate([data]{.pop}, [col]{.pop}, [into]{.pop}, [sep]{.pop}) +::: + +- `data` + - Again,the data frame you want to do this separation to. +- `col` + - The name of the column you want to separate. +- `into` + - A character vector of the new column names you want to create. +- `sep` + - The character or regex pattern you want to use to split up the values in `col`. + +Here's how it works for `fruit_long`. + +```{r} +fruit_separate <- separate(data = fruit_long, + col = fruit_behavior, + into = c("fruit", "behavior"), + sep = "_") +``` + +```{r echo = F, results='asis'} +kable(fruit_separate) +``` + +It has returned a new data frame with the `fruit_behavior` column split into two new columns, named after what I passed to the `into` argument. It split up `fruit_behavior` based on what I passed to `sep`, which was the underscore character. + +Let's do this for `iy_ah_step1` now. + +```{r} +iy_ah_step2 <- separate(iy_ah_step1, + vowel_formant, + into = c("vowel", "formant"), + sep = "_") +iy_ah_step2 +``` + +We now have two separate columns for `vowel` and `formant`. + +::: {.box .hygiene} +[Hygiene]{.label} + +I have been very helpful and used underscores to merge together the values we want to separate. Be helpful to yourself, and be consistent in the semantics of how you used potential delimiters like `-` and `_`. Here's an example of being helpful to yourself: + +``` +project_subject_firstname-lastname + +EDI_1_Stuart-Duddingston +EDI_2_Connor-Black-Macdowall +EDI_3_Mhairi +``` + +This is helpful, because when you separate by underscore, you'll have something tidy + +``` +EDI 1 Stuart-Duddingston +EDI 2 Connor-Black-Macdowall +EDI 3 Mhairi +``` + +If you used `-` for everything, you'll have chaos when you try to separate them because some speakers have "double barreled" names, and some speakers have only first names: + +``` +# Input: +EDI-1-Stuart-Duddingston +EDI-2-Connor-Black-Macdowall +EDI-3-Mhairi + +# Becomes + +EDI 1 Stuart Duddingston +EDI 2 Connor Black Macdowall +EDI 3 Mhairi +``` + +This goes beyond R programming. You should make some decisions and stick with them for all of your data analysis, including file naming, Praat tier naming, etc. +::: + +## Spreading columns + +We've got one last step, which is spreading the values in some rows across the column space. With the `fruit` data, we might not want a column called `behavior`, but actually have two columns called `bought` and `ate`. For the vowel data, we definitely don't want one column called `formant`. We want one called `F1` and one called `F2`. We can do this with the `spread()` function. + +::: illustrate +spread([data]{.pop}, [key]{.pop}, [value]{.pop}) +::: + +- `data` + - Again, the data we want to work with. +- `key` + - The column whose values you want to spread across the column space. +- `value` + - The column with values that you want to fill in the cells. + +Here's how that looks with the `fruit_separate` data. + +```{r} +fruit_spread <- spread(data = fruit_separate, + key = behavior, + value = number) +``` + +```{r echo = F, results = 'asis'} +kable(fruit_spread) +``` + +This has created a new data frame. I told `spread()` to spread the values in `behavior` across the column space. Because it had only two unique values in it (`bought` and `ate`), it has created two new columns called `bought` and `ate`. After creating these new columns, it had to fill in the new cells with some values, and I told it to use the values in `number` for that. + +Here's how that works with `iy_ah_step2`. + +```{r} +iy_ah_step3 <- spread(data = iy_ah_step2, + key = formant, + value = hz) +iy_ah_step3 +``` + +Now, we've finally gotten to a tidy data format. In our next meeting, we'll discuss how to chain these three functions into one easy to read process. + +::: {.box .idiom} +[Idiom]{.label} + +You might have noticed that in the functions above, I've put a new line between individual function arguments. I've done this because white-space doesn't matter when it comes to R. I could have written these with just spaces between each argument, but that would be too visually crowded. + +```{r} +# compare + +# One line +fruit_separate <- separate(data = fruit_long, col = fruit_behavior, into = c("fruit", "behavior"), sep = "_") + +# New Lines +fruit_separate <- separate(data = fruit_long, + col = fruit_behavior, + into = c("fruit", "behavior"), + sep = "_") + +``` + +I encourage you to use new lines similarly to give yourself "some space to breathe". Don't be shy about it. But, if you put newlines between *some* arguments, you should really put new lines between *all* arguments. +::: diff --git a/teaching/courses/2017_lsa/lectures/_metadata.yml b/teaching/courses/2017_lsa/lectures/_metadata.yml new file mode 100644 index 0000000..f687063 --- /dev/null +++ b/teaching/courses/2017_lsa/lectures/_metadata.yml @@ -0,0 +1,10 @@ +author: + - name: + given: Josef + family: Fruehwald +date: 2017-7-5 +date-format: "MMMM YYYY" +date-modified: 2023-12-18 +format: + html: + code-tools: true \ No newline at end of file