1 Adobe Best Practices

  • Name variables all lowercase with no spaces; use underscores if separating words
  • Use radio buttons whenever possible
  • Use the align feature and match size to when creating variables
  • When creating forms in Word, give space for the Adobe buttons that will eventually be created
  • Make sure you are using same naming conventions
    • tcid
    • wave
    • coder_name
    • date_coded
    • coder (for 1, 2, 3 variable)
    • given_opp_to_play
    • play_task
    • pc_present
    • task_start_time
    • task_stop_time
    • task_length
  • Keep it clean
  • Keep consistent naming conventions within (and across) forms
  • For fonts in the fields, in general, use auto. However, this can be changed if problematic.
  • To reset forms, copy and paste the variables, then delete what you pasted, and it will be cleared.
  • Calculated fields should NOT be calculated off of already calculated fields. Fields should only be calculated off of fields that are manually inputted. For more information on this, see creating time calculations

2 Converting Word Documents to PDFs

Before converting forms to pdfs, all required edits to the document should be made in Microsoft Word. Edits of content or formatting should be completed and finalized in Word before converting the document to a pdf. To convert a Word document to a pdf, complete the following steps:

  1. Open the document in Microsoft Word
  2. Click the “File” tab in the top left corner within the Word interface
  3. Select “Save as ADOBE PDF”
  4. Name the new pdf accordingly

3 Editing pdfs in Adobe

  1. Open pdf in Adobe Acrobat Pro 2020

    • Note: Editing of pdfs must be done in Adobe Acrobat Pro 2020, not Adobe Acrobat
  2. Under the “Tools” tab in the top left corner of the Adobe interface, find the heading “Forms & Signatures” and select “Prepare Form”

  3. Select “Start” to begin scanning and preparation of the pdf

  4. The “Prepare Form” tool bar should now be visible, allowing for the addition of text fields, radio buttons, check boxes, and more

3.1 Adding Text Fields, Radio Buttons, and Check Boxes

  1. Text fields should be implemented when:
    1. Textual or numeric information must be manually entered
    2. A calculated field is required
  2. Radio buttons should be implemented whenever possible
    • Radio buttons allow for only one selection out of a group of options
      • Radio buttons thus should be used for imitation, comprehension, practice, and test trial fields within pdfs
    • In order to prevent human error, radio buttons should be applied to as many variables as possible
    • Calculated fields can be derived from radio buttons
  3. Check boxes should only be used when necessary
    • Check boxes allow for multiple selections within a group
    • Check boxes should not be used for trials fields within pdfs unless multiple answers can be selected for a given trial
    • Calculated fields can be derived from check boxes
  4. Action buttons should be implemented when a specific action is needed to be carried out. These actions typically include:
    • Reseting a field(s)/form
    • Hiding/Revealing a field(s)

3.2 Naming Convention for Variables in Adobe

  1. Variable names should be in all lowercase with no spaces and underscores separating words
  2. Keep variable names as consistent as possible across forms with similar variables
  3. The following are common names for variables which should be used when applicable:
    • Identifying information:
      • TCID: tcid
      • Wave: wave
      • Coder Name: coder_name
      • Date Coded: date_coded
      • Coder: coder (for 1, 2, 3 variable)
      • Was TC given the opportunity to play the task: given_opp_to_play
      • Did TC play the task: play_task
      • PC Present: pc_present
      • Did TC pass the imitation trials: pass_imitation
      • Did TC pass the comprehension check: pass_comprehension
      • Did TC pass the practice trials: pass_practiceX
      • Start time: task_start_time
      • Stop time: task_stop_time
      • Length of administration: task_length
      • Coder 1/2/3: initials_date_coderX
    • Task Trials
      • Imitation Trials: imitation_trials_x
      • Imitation Trials Second Administration: imitation_trials_readmin_x
      • Comprehension Check: comp_checkX_x
      • Practice Trials: practice_trialsX_x
      • Test Trials: test_trialsX_x
      • Note: “X” signifies the round/block of the trials while “x” signifies the trial number within that round/block (ex: practice_trials2_7). An “X” within the variable name is only necessary if there are multiple rounds/blocks for the trial. Thus, if there is only one round of imitation trials, those trials should be simply named test_trials rather than test_trials1.
    • Trial Totals
      • Total Incorrect: total_incorrect_task_trials
      • Total Initially incorrect, but changed to correct: total_initially_task_trials
      • Total Correct: total_correct_task_trials
      • Total No Response: total_noresponse_task_trials
      • Total Uncodeable: total_uncodeable_task_trials
      • Total # of Scoreable Trials Played: total_scored_task_trials
      • Note: “task_trials” should be replaced with whether the round/block of trials is imitation_trials, comp_check, practice_trials, or test_trials.

3.2.1 Naming Convention for Radio Buttons

  1. In order to create calculated fields for trial totals, radio button “Choice Values” must be manually set. To facilitate the process, this should be done after aligning each group of radio buttons for each trial under each TC response for the trial. For example, there should be a column of radio buttons under the “Correct” label within the trial’s grid with each radio button in this column representing the “Correct” choice for a different group of radio buttons. A column of buttons should be present for “Incorrect,” “No Response,” and so forth. Thus, each group of radio buttons should be aligned horizontally, with each button reflecting a different TC response. These groups should then be stacked into a column with each column representing the response across trials. The Choice Values can then be set through the following steps:

    1. Select the entire column under a certain TC response (ex. select the entire column of radio buttons under “Correct”)
    2. Right-click on the selected column of radio buttons and select “Properties”
    3. Under the “Options” tab, set the “Radio Button Choice” according to the following values:
      • “Correct” column = 2
      • “Incorrect” column = 0
      • “Initially incorrect but changed response to correct” column = 1
      • “No response” column = -9
      • “Uncodeable” column = 9
    4. Set all columns with their appropriate radio button choice value
    • Note: While calculated fields can be derived from different radio button choice values, it is imperative to assign the button choices according to these values. This allows for consistency across pdfs and the ability to smoothly borrow code for calculated fields.

3.2.2 Naming Convention for Check Boxes

Check boxes can be named in such a way that they act similar to radio buttons, allowing only one selection out of a group of check boxes.= A group of check boxes can be formatted as radio buttons through the following steps:

  1. Input the same variable name for each check box within the group to be formatted
  2. Right click on each check box and select “Properties”
  3. Under the “Options” tab, set the “Export Value” for each check box according to the following values:
    • “Correct” column = 2
    • “Incorrect” column = 0
    • “Initially incorrect but changed response to correct” column = 1
    • “No response” column = -9
    • “Uncodeable” column = 9
  4. With each check box named the same but also each with a different export value, the group of check boxes should now operate similar to a group of radio buttons
    • Within the group, only one check box should be able to be selected
    • Additionally, the selection should be able to be unselected
  5. While both groups of radio buttons and this form of groups of check boxes operate the same way and permit only one selection within the group, groups of check boxes provide an advantage by allowing for deselection of the value. Within groups of radio buttons, as soon as a button is selected, the group of buttons cannot be reset or deselected. This usage of groups of check buttons may be useful going forward and should be considered when creating new coding forms.
    • Note: Creating calculated fields from groups of check boxes will follow the same procedure as creating calcuated fields from radio buttons. Thus, it is important to ensure the export values for each check box follow the values listed in Step 3.

3.3 Hiding and Revealing Fields in Adobe

Fields can be hidden and revealed within Adobe documents. To do such, complete the following steps:

  1. Right click on the field to be hidden
  2. Select “Properties”
  3. Under the “General” tab, navigate to the “Common Properties” box at the bottom of the tab
  4. For “Form Field:” select Hidden from the drop-down menu
  5. Now, when previewing the document, the selected field should be hidden from user view
  6. In order to make the field visible to users again, complete steps 1-4, but instead of selecting Hidden for “Form Field:”, select Visible
  7. The field should now be visible to users

3.4 Creating Actions in Adobe

Radio buttons, check boxes, text fields, and action buttons can all be assigned specific actions upon clicking them. The most common actions used are: * Clearing or reseting a field(s) or an entire form * Hiding/revealing a field(s)

To assign a radio button, check box, text field, or action button an action, complete the following steps:

  1. Right click on the object (the radio button/check box/text field/action button in question) to which an action is to be assigned
  2. Select the “Actions” tab
  3. Within the “Add an Action” interface, for “Select Trigger:” ensure the response of Mouse Up is selected
    • This configures the action to be executed when the object is clicked upon with the user’s mouse
  4. Within the “Add an Action” interface, for “Select Action:” choose the desired action to be assigned to the object from the drop-down menu
    • To clear/reset a field:
      • Select Reset a form
    • To hide/reveal a field:
      • Select Show/hide a field
  5. Within the “Add an Action” interface, select “Add…” to implement the chosen action to the object
    • Upon clicking add, a separate window will appear asking you to specify which fields the action should be applied to
    • If clearing/reseting a field:
      • Mark all the check boxes of all the fields to be rest
      • Select “OK”
    • If hiding/revealing a field:
      • Select the name of the field to be hidden/revealed
      • On the right, select the radio button selection for whether the action should Show or Hide the field
      • Select “OK”
  6. Upon selection of “OK,” the action should now appear within the “Action” box at the bottom of the tab
  7. In order to edit the action, select the action to be edited and then select “Edit” at the bottom of the interface
  8. Multiple actions can be assigned to the same object. Thus, repeat steps 1-6 as many times as needed to assign the necessary actions to a given object

4 Creating Calculated Fields

Adobe Acrobat both includes its own functions for creating calculated fields and allows for the implementation of custom calculation scripts within forms. While the calculation features are built-in to Adobe, the custom calculation scripts must be written using the programming language JavaScript. The following sections detail how to create different types of calculated fields.

4.1 Creating Calculated Fields from Radio Buttons

  1. First, ensure the radio buttons and their choice values are appropriately set according to the naming convention for radio buttons
  2. Select the text field which must be turned into a calculated field
  3. Right-click on the field and select “Properties”
  4. Select the “Calculate” tab within the Properties menu
  5. Select the “Custom calculation script:” radio button
  6. Select “Edit…” and input the desired calculation script
    • The following script should be applied in order to calculate radio buttons:
    var v1 = getField("variable_group_name").value
    var v2 = getField("variable_group_name2").value
    var v3 = getField("variable_group_name3").value
    var v4 = getField("variable_group_name4").value
    
    if (v1 == X) { 
    total = 1;
    } else {
    total = 0;
    }
    
    if (v2 == X) {
    total2 = 1;
    } else {
    total2 = 0;
    }
    
    if (v3 == X) {
    total3 = 1;
    } else {
    total3 = 0;
    }
    
    if (v4 == X) {
    total4 = 1;
    } else {
    total4 = 0;
    }
    
    event.value = total + total2 + total3 + total4
    • This script should be fit according to how many trials/variables must be calculated from
    • Proceed to Breaking Down the Calculation Script to gain a greater understanding of the script

4.2 Creating Calculated Fields from Radio Buttons: Video

Watch the following video in order to observe an example of creating calculated fields from radio buttons:

4.3 Creating Calculated Fields from Check Boxes

  1. Prepare the check boxes for calculation:

    1. Provide the check boxes from which the field will be calculated with appropriate variable names, closely following standard naming convention for variables when possible

    2. For each check box, an export value must be assigned. The export value will determine what numeric value the check box will carry throughout calculation. To set the export value, complete the following steps:

      1. Select and right-click on the check box and select “Properties”
      2. In the Properties menu, select the “Options” tab
      3. In the “Export Value:” field, enter the numeric value the check box should reflect
  2. Select the text field which must be turned into a calculated field

  3. Right-click on the field and select “Properties”

  4. Select the “Calculate” tab within the Properties menu

  5. Select the “Value is the mathematical operators of the following fields” radio button

    • Note: The appropriate mathematical operator should be selected according to the desired final calculation from the drop down list of “sum (+),” “product (x),” “average,” “minimum,” or “maximum”
  6. Select “Pick…” and then check the variable names of the check boxes to be calculated

4.4 Breaking Down the Calculation Script

var v1 = getField("variable_group_name").value
var v2 = getField("variable_group_name2").value
var v3 = getField("variable_group_name3").value
var v4 = getField("variable_group_name4").value

if (v1 == X) { 
total = 1;
} else {
total = 0;
}

if (v2 == X) {
total2 = 1;
} else {
total2 = 0;
}

if (v3 == X) {
total3 = 1;
} else {
total3 = 0;
}

if (v4 == X) {
total4 = 1;
} else {
total4 = 0;
}

event.value = total + total2 + total3 + total4

The calculation script for radio buttons can be broken down into three parts:

  1. Defining the Variables

    var v1 = getField("variable_group_name").value
    var v2 = getField("variable_group_name2").value
    var v3 = getField("variable_group_name3").value
    var v4 = getField("variable_group_name4").value
    • This portion of the script defines the variables from which information is being pulled from. In nearly all cases the variables being pulled from will be the groups of radio buttons for each trial.
    • The line var v1 = getField("variable_group_name").value defines the selected radio button in “variable_group_name” as var v1 (variable 1) within this script and pulls the choice value from each group
      • Thus, within each getField(), the name of each group of radio buttons should be added in quotations
      • Note: The number being pulled through this function directly corresponds to the choice value defined for each radio button in the group of radio of radio buttons. This is why it is crucial to define choice values according to the same naming convention for radio buttons
    • Each var vX should reflect a trial on the form. Thus, if there are 15 test trials, there should be 15 lines of code from var v1 to var v15 with the name for each group of radio buttons inputed in getField("") for each variable
  2. Defining the Selected Values

    if (v1 == X) { 
    total = 1;
    } else {
    total = 0;
    }
    
    if (v2 == X) {
    total2 = 1;
    } else {
    total2 = 0;
    }
    
    if (v3 == X) {
    total3 = 1;
    } else {
    total3 = 0;
    }
    
    if (v4 == X) {
    total4 = 1;
    } else {
    total4 = 0;
    }
    • This portion of code utilizes if/else statements in order to create the total value for each field
    • In v1 == X and each subsequent v == X, the X should be replaced with the choice value of the radio button from the group of radio buttons that corresponds to the desired field you are calculating
      • For example, if a total correct field is being calculated, the code should read:

        if (v1 == 2) { 
        total = 1;
        } else {
        total = 0;
        }
        
        if (v2 == 2) {
        total2 = 1;
        } else {
        total2 = 0;
        }
      • Because a total correct field is being calculated, the choice value of 2 should be inputed as this is the choice value which corresponds to “Correct” (see naming convention for radio buttons)

      • The value of 2 would be inputed for each if/else statement for each variable. Thus, if there were 15 variables, there should be 15 if/else statements v1 == 2 to v15 == 2

    • The if/else statement for each variable defines that if the value pulled by the getField() function matches the inputted choice value for the variable then the total for that variable becomes equal to 1. If it does not match, the the total becomes equal to 0.
  3. Defining the Total

event.value = total + total2 + total3 + total4
  • This portion of code defines the calculation to take place in the field
    • The event.value determines what appears in the text box
  • This line of code adds together the totals defined in the if/else statements. This produces the final calculated value for the field.
  • The number of totals added together should correspond to the number of variables. Thus, if there are 15 trials, then the final line of code should read: event.value = total + total2 + total3 + total4 + total5 + total6 + total7 + total8 + total9 + total10 + total11 + total12 + total13 + total14 + total15

The following is an example script for a calculated “total_correct_test_trials” field, calculated from 15 trials:

var v1 = getField("test_trials_1").value
var v2 = getField("test_trials_2").value
var v3 = getField("test_trials_3").value
var v4 = getField("test_trials_4").value
var v5 = getField("test_trials_5").value
var v6 = getField("test_trials_6").value
var v7 = getField("test_trials_7").value
var v8 = getField("test_trials_8").value
var v9 = getField("test_trials_9").value
var v10 = getField("test_trials_10").value
var v11 = getField("test_trials_11").value
var v12 = getField("test_trials_12").value
var v13 = getField("test_trials_13").value
var v14 = getField("test_trials_14").value
var v15 = getField("test_trials_15").value


if (v1 == 2) {
  total = 1;
} else {
  total = 0;
}

if (v2 == 2) {
  total2 = 1;
} else {
  total2 = 0;
}

if (v3 == 2) {
  total3 = 1;
} else {
  total3 = 0;
}

if (v4 == 2) {
  total4 = 1;
} else {
  total4 = 0;
}

if (v5 == 2) {
  total5 = 1;
} else {
  total5 = 0;
}

if (v6 == 2) {
  total6 = 1;
} else {
  total6 = 0;
}

if (v7 == 2) {
  total7 = 1;
} else {
  total7 = 0;
}

if (v8 == 2) {
  total8 = 1;
} else {
  total8 = 0;
}

if (v9 == 2) {
  total9 = 1;
} else {
  total9 = 0;
}

if (v10 == 2) {
  total10 = 1;
} else {
  total10 = 0;
}

if (v11 == 2) {
  total11 = 1;
} else {
  total11 = 0;
}

if (v12 == 2) {
  total12 = 1;
} else {
  total12 = 0;
}

if (v13 == 2) {
  total13 = 1;
} else {
  total13 = 0;
}

if (v14 == 2) {
  total14 = 1;
} else {
  total14 = 0;
}

if (v15 == 2) {
  total15 = 1;
} else {
  total15 = 0;
}

event.value = total + total2 + total3 + total4 + total5 + total6 + total7 + total8 + total9 + total10 + total11 + total12 + total13 + total14 + total15

4.5 Creating Calculated Fields with Conditional Formatting

For cases where a calculated total can change from a manually-input variable, an altered script must be used.

For example, a calculated field can be created for the total number of correct responses a participant gives to a stimulus. If what qualifies as a “correct” response depends on a variable that can be manually changed, the original calculation script will result in an inaccurate total.

Thus, the altered scripted must show that the value of the calculated total is conditional on another variable. The value of Variable X is dependent on the value of Variable Y. This can be accomplished through the usage of if/else commands in JavaScript.

Provided below is an example of a calculation script with conditional formatting:

var v1= getField("variable_X_group_name").value
var v2= getField("variable_X_group_name2").value
var v3= getField("variable_X_group_name3").value
var v4= getField("variable_X_group_name4").value
var v5= getField("variable_X_group_name5").value
var v6= getField("variable_X_group_name6").value
var v7= getField("variable_X_group_name7").value
var v8= getField("variable_X_group_name8").value
var v9= getField("variable_X_group_name9").value
var v10= getField("variable_X_group_name10").value
var v11= getField("variable_X_group_name11").value
var v12= getField("variable_X_group_name12").value
var v13= getField("variable_X_group_name13").value
var v14= getField("variable_X_group_name14").value
var v15= getField("variable_X_group_name15").value
var v16= getField("variable_X_group_name16").value


var v17= getField("variable_Y_group_name").value
var v18= getField("variable_Y_group_name2").value
var v19= getField("variable_Y_group_name3").value
var v20= getField("variable_Y_group_name4").value
var v21= getField("variable_Y_group_name5").value
var v22= getField("variable_Y_group_name6").value
var v23= getField("variable_Y_group_name7").value
var v24= getField("variable_Y_group_name8").value
var v25= getField("variable_Y_group_name9").value
var v26= getField("variable_Y_group_name10").value
var v27= getField("variable_Y_group_name11").value
var v28= getField("variable_Y_group_name12").value
var v29= getField("variable_Y_group_name13").value
var v30= getField("variable_Y_group_name14").value
var v31= getField("variable_Y_group_name15").value
var v32= getField("variable_Y_group_name16").value

if(v17 == Y1){
    if (v1 == X2){
            total=1
    }else{
            total=0
    }
}else{
    if (v1 == X1){
            total=1
    }else{
            total=0
    }
}

if(v18 == Y2){
    if (v2 == X1){
            total2=1
    }else{
            total2=0
    }
}else{
    if (v2 == X2){
            total2=1
    }else{
            total2=0
    }
}

if(v19 == Y2){
    if (v3 == X1){
            total3=1
    }else{
            total3=0
    }
}else{
    if (v3 == X2){
            total3=1
    }else{
            total3=0
    }
}

if(v20 == Y1){
    if (v4 == X2){
            total4=1
    }else{
            total4=0
    }
}else{
    if (v4 == X1){
            total4=1
    }else{
            total4=0
    }
}

if(v21 == Y2){
    if (v5 == X1){
            total5=1
    }else{
            total5=0
    }
}else{

    if (v5 == X2){
            total5=1
    }else{
            total5=0
    }
}

if(v22 == Y2){
    if (v6 == X1){
            total6=1
    }else{
            total6=0
    }
}else{
    if (v6 == X2){
            total6=1
    }else{
            total6=0
    }
}

if(v23 == Y1){
    if (v7 == X2){
         total7=1
    }else{
            total7=0
    }
}else{
    if (v7 == X1){
         total7=1
    }else{
            total7=0
    }
}

if(v24 == Y1){
    if (v8 == X2){
            total8=1
    }else{
         total8=0
    }
}else{
    if (v8 == X1){
            total8=1
    }else{
         total8=0
    }
}

if(v25 == Y1){
    if (v9 == X2){
         total9=1
    }else{
            total9=0
    }
}else{
    if (v9 == X1){
         total9=1
    }else{
            total9=0
    }
}

if(v26 == Y2){
    if (v10 == X1){
            total10=1
    }else{
            total10=0
    }
}else{
    if (v10 == X2){
            total10=1
    }else{
            total10=0
    }
}

if(v27 == Y1){
    if (v11 == X2){
            total11=1
    }else{
            total11=0
    }
}else{
    if (v11 == X1){
            total11=1
    }else{
            total11=0
    }
}

if(v28 == Y2){
    if (v12 == X1){
            total12=1
    }else{
         total12=0
    }
}else{
    if (v12 == X2){
            total12=1
    }else{
         total12=0
    }
}

if(v29 == Y2){
    if (v13 == X1){
            total13=1
    }else{
            total13=0
    }
}else{
    if (v13 == X2){
            total13=1
    }else{
            total13=0
    }
}

if(v30 == Y1){
    if (v14 == X2){
            total14=1
    }else{
        total14=0
    }
}else{
    if (v14 == X1){
        total14=1
    }else{
            total14=0
    }
}

if(v31 == Y1){
    if (v15 == X2){
            total15=1
    }else{
            total15=0
    }
}else{
    if (v15 == X1){
            total15=1
    }else{
            total15=0
    }
}

if(v32 == Y2){
    if (v16 == X1){
            total16=1
    }else{
            total16=0
    }
}else{
    if (v16 == X2){
            total16=1
    }else{
            total16=0
    }
}


event.value=total+total2+total3+total4+total5+total6+total7+total8+total9+total10+total11+total12+total13+total14+total15+total16


4.6 Breaking Down the Conditional Formatting Calculation Script

Notice the traditional calculation script is present within this script. However, additional if/else commands are implemented in order to account for the dependence on another variable. Before proceeding with this section, an understanding of the traditional calculation script should be obtained. In the following section, Variable X refers to the variable which is contingent on the value of another variable, Variable Y. Thus, the conditional formatting is described in such a way that the value of a Variable X is dependent on the value of Variable Y.

The conditional formatting calculation script features two major alterations:

  1. Defining the Additional Variable

    var v17= getField("variable_Y_group_name").value
    var v18= getField("variable_Y_group_name2").value
    var v19= getField("variable_Y_group_name3").value
    var v20= getField("variable_Y_group_name4").value
    var v21= getField("variable_Y_group_name5").value
    var v22= getField("variable_Y_group_name6").value
    var v23= getField("variable_Y_group_name7").value
    var v24= getField("variable_Y_group_name8").value
    var v25= getField("variable_Y_group_name9").value
    var v26= getField("variable_Y_group_name10").value
    var v27= getField("variable_Y_group_name11").value
    var v28= getField("variable_Y_group_name12").value
    var v29= getField("variable_Y_group_name13").value
    var v30= getField("variable_Y_group_name14").value
    var v31= getField("variable_Y_group_name15").value
    var v32= getField("variable_Y_group_name16").value
    • This addition to the script is necessary in order to accomodate for the additional Variable Y by which the calculated total is contingent
    • An additional 16 variables must be added, one for each of the 16 groups of Variable X (v1-v16). Each of these new var commands corresponds to one of the original 16 var commands for Variable X and pulls each trial’s value for Variable Y upon which the total is dependent.
    • Thus for a form with 16 test trials, there should be 32 total lines of code: 16 which correspond to the original 16 groups of radio buttons for Variable X which reflect a response for each trial, and an additional 16 which correspond to the manually input response for Variable Y upon which the calculated total is conditional
  2. Creating the Conditional Formatting using If/Else Commands

    if(v17 == Y1){
        if (v1 == X2){
                total=1
        }else{
                total=0
        }
    }else{
        if (v1 == X1){
                total=1
        }else{
                total=0
        }
    }
    
    if(v18 == Y2){
        if (v2 == X1){
                total2=1
        }else{
                total2=0
        }
    }else{
        if (v2 == X2){
                total2=1
        }else{
                total2=0
        }
    }
    ...
    • This alteration to the script utilizes if/else commands to establish contingency on Variable Y

    • As outlined in the Breaking Down the Calculation Script section, the if/else statements operate in the same manner and follow the same procedures. However, notice an additional if/else statement is present for each trial and surrounds the original if/else statement:

      if(v17 == Y1){       <------------ START OF OVERARCHING IF STATEMENT
          if (v1 == X2){     # Original if/else statement
                  total=1
          }else{
                  total=0
          }
      }else{               <------------ START OF OVERARCHING ELSE STATEMENT
          if (v1 == X1){     # Second original if/else statement
                  total=1
          }else{
                  total=0
          }
      }                    <------------ END OF OVERARCHING IF/ELSE STATEMENT
      
    • The overarching if/else statement is centered around the variable which defines the conditional formatting, Variable Y, thus the if(v == Y){ should only reference var v17 to var v32

    • Within the overarching if/else statement, Y1 and Y2 represent the choice value of the field being pulled from for Variable Y

      • For the original if/else statements within the overarching if/else statement, X1 and X2 still reflect the desired choice value of the radio button from the group of radio buttons that correspond to the desired field you are calculating for Variable X
    • The conditional formatting emerges from defining the Y in if(v == Y){ as Y1 or Y2

      • Notice, there are two if/else statements within the overarching if/else statement. Each of these secondary if/else statements define a different outcome - in this instance, the outcomes are “if v1 == X2 then total = 1” and “if v1 == X1 then total = 1” Which outcome is selected is dependent on the definition of Y in if(v == Y){.
      • Thus, for the example script above, if v17 == Y1, then the first outcome of “if v1 == X2 then total = 1” will be the result, but if v17 equals anything else besides Y1, then the second outcome of “if v1 == X1 then total = 1” will be the result
      • The final result is conditional formatting as the calculated total for each trial of Variable X is ultimately dependent on the value of Variable Y

4.7 Conditional Formatting Calculation Script: An Example

Listed below is a specific example where the conditional formatting calculation script is necessary:

4.7.1 The Scenario

A calculated field for the total number of correct responses out of 16 trials is needed.

For each trial, an experimenter taps the table either one time or two times. In response to the experimenter’s administration, the participant is expected to tap the table the opposite number of times.

If the experimenter taps the table once, the participant should tap the table twice; if the experimenter taps the table twice, the participant taps the table once. A response is correct if the particpant successfully taps the table the opposite number of times as the experimenter.

Thus, the correct response is not always one tap or two taps. Instead, whether the response is correct is contingent on the experimenter’s administration and how many times the experimenter taps the table. As a result, conditional formatting is necessary in order to calculate the total number of correct responses across the 16 trials.

4.7.2 The Variables

  • Variable X = participant’s responses (the number of times the participant taps the table)
  • Variable Y = experimenter’s administration (the number of times the experimenter tapped the table)
  • X1 = choice value of radio button reflecting the action of the participant tapping the table once - in this case, 1
  • X2 = choice value of radio button reflecting the action of the participant tapping the table twice - in this case, 2
  • Y1 = choice value of the field reflecting the experimenter tapped the table once - in this case, 1
  • Y2 = choice value of the field reflecting the experimenter tapped the table once - in this case, 2

4.7.3 The Script

The calculation script for the above scenario can be written as such:

var v1= getField("participant_response").value
var v2= getField("participant_response2").value
var v3= getField("participant_response3").value
var v4= getField("participant_response4").value
var v5= getField("participant_response5").value
var v6= getField("participant_response6").value
var v7= getField("participant_response7").value
var v8= getField("participant_response8").value
var v9= getField("participant_response9").value
var v10= getField("participant_response10").value
var v11= getField("participant_response11").value
var v12= getField("participant_response12").value
var v13= getField("participant_response13").value
var v14= getField("participant_response14").value
var v15= getField("participant_response15").value
var v16= getField("participant_response16").value


var v17= getField("experimenter_administration").value
var v18= getField("experimenter_administration2").value
var v19= getField("experimenter_administration3").value
var v20= getField("experimenter_administration4").value
var v21= getField("experimenter_administration5").value
var v22= getField("experimenter_administration6").value
var v23= getField("experimenter_administration7").value
var v24= getField("experimenter_administration8").value
var v25= getField("experimenter_administration9").value
var v26= getField("experimenter_administration10").value
var v27= getField("experimenter_administration11").value
var v28= getField("experimenter_administration12").value
var v29= getField("experimenter_administration13").value
var v30= getField("experimenter_administration14").value
var v31= getField("experimenter_administration15").value
var v32= getField("experimenter_administration16").value

if(v17 == 1){
    if (v1 == 2){
            total=1
    }else{
            total=0
    }
}else{
    if (v1 == 1){
            total=1
    }else{
            total=0
    }
}

if(v18 == 2){
    if (v2 == 1){
            total2=1
    }else{
            total2=0
    }
}else{
    if (v2 == 2){
            total2=1
    }else{
            total2=0
    }
}

if(v19 == 2){
    if (v3 == 1){
            total3=1
    }else{
            total3=0
    }
}else{
    if (v3 == 2){
            total3=1
    }else{
            total3=0
    }
}

if(v20 == 1){
    if (v4 == 2){
            total4=1
    }else{
            total4=0
    }
}else{
    if (v4 == 1){
            total4=1
    }else{
            total4=0
    }
}

if(v21 == 2){
    if (v5 == 1){
            total5=1
    }else{
            total5=0
    }
}else{
    if (v5 == 2){
            total5=1
    }else{
            total5=0
    }
}

if(v22 == 2){
    if (v6 == 1){
            total6=1
    }else{
            total6=0
    }
}else{
    if (v6 == 2){
            total6=1
    }else{
            total6=0
    }
}

if(v23 == 1){
    if (v7 == 2){
         total7=1
    }else{
            total7=0
    }
}else{
    if (v7 == 1){
         total7=1
    }else{
            total7=0
    }
}

if(v24 == 1){
    if (v8 == 2){
            total8=1
    }else{
         total8=0
    }
}else{
    if (v8 == 1){
            total8=1
    }else{
         total8=0
    }
}

if(v25 == 1){
    if (v9 == 2){
         total9=1
    }else{
            total9=0
    }
}else{
    if (v9 == 1){
         total9=1
    }else{
            total9=0
    }
}

if(v26 == 2){
    if (v10 == 1){
            total10=1
    }else{
            total10=0
    }
}else{
    if (v10 == 2){
            total10=1
    }else{
            total10=0
    }
}

if(v27 == 1){
    if (v11 == 2){
            total11=1
    }else{
            total11=0
    }
}else{
    if (v11 == 1){
            total11=1
    }else{
            total11=0
    }
}

if(v28 == 2){
    if (v12 == 1){
            total12=1
    }else{
         total12=0
    }
}else{
    if (v12 == 2){
            total12=1
    }else{
         total12=0
    }
}

if(v29 == 2){
    if (v13 == 1){
            total13=1
    }else{
            total13=0
    }
}else{
    if (v13 == 2){
            total13=1
    }else{
            total13=0
    }
}

if(v30 == 1){
    if (v14 == 2){
            total14=1
    }else{
        total14=0
    }
}else{
    if (v14 == 1){
        total14=1
    }else{
            total14=0
    }
}

if(v31 == 1){
    if (v15 == 2){
            total15=1
    }else{
            total15=0
    }
}else{
    if (v15 == 1){
            total15=1
    }else{
            total15=0
    }
}

if(v32 == 2){
    if (v16 == 1){
            total16=1
    }else{
            total16=0
    }
}else{
    if (v16 == 2){
            total16=1
    }else{
            total16=0
    }
}


event.value=total+total2+total3+total4+total5+total6+total7+total8+total9+total10+total11+total12+total13+total14+total15+total16

4.8 Time Calculations in Adobe

Calculating a time based on two other times can be accomplished within Adobe. To do this, custom calculation scripts using the language JavaScript must be implemented.

4.8.1 Creating Time Calculations in Adobe

  1. First, ensure all fields from which the time calculations are to be made from or applied to have been formatted into the desired time format. To do this:
    1. Right click on the field and select “Properties”
    2. Navigate to the “Format” tab
    3. For “Select format category:” select Time
    4. In the “Time Options” interface that appears, select the desired time format
    5. Repeat this for every field that the time calculations will be made from or applied to
    6. The following calculation script calculates time in the HH:MM:ss format
  2. Select the field in which the time calculation will occur
  3. Right click on the field and select “Properties”
  4. Select the “Calculate” tab
  5. Select the “Custom calculation script:” radio button
  6. Select “Edit…” and input the desired time calculation script

The following script details how to calculate X second intervals based on an inputted starting time. The times within this script follow the HH:MM:ss time format. The following script can easily be modified to calculate different length intervals or to use different time formats.

var timestarted = this.getField("start_time_field").valueAsString;

var timeSplit = timestarted.split(":") ;

var totalSec = ((timeSplit[0]*3600) + (timeSplit[1]*60) + (timeSplit[2]*1));

var newtotalSec = ((timeSplit[0]*3600) + (timeSplit[1]*60) + (timeSplit[2]*1) + "INTERVAL LENGTH X");

hours = Math.floor(newtotalSec/3600);

minutes = Math.floor((newtotalSec % 3600)/60);

seconds = newtotalSec % 60;

timeOutput = hours + ":" + minutes + ":" + seconds;

event.value = timeOutput
  • Proceed to Breaking Down the Time Calculation Script to gain a greater understanding of the script

4.8.2 Breaking Down the Time Calculation Script

var timestarted = this.getField("start_time_field").valueAsString;

var timeSplit = timestarted.split(":") ;

var totalSec = ((timeSplit[0]*3600) + (timeSplit[1]*60) + (timeSplit[2]*1));

var newtotalSec = ((timeSplit[0]*3600) + (timeSplit[1]*60) + (timeSplit[2]*1) + "INTERVAL LENGTH X");

hours = Math.floor(newtotalSec/3600);

minutes = Math.floor((newtotalSec % 3600)/60);

seconds = newtotalSec % 60;

timeOutput = hours + ":" + minutes + ":" + seconds;

event.value = timeOutput

The time calculation script can be broken down into three parts:

  1. Defining the Start Time
var timestarted = this.getField("start_time_field").valueAsString;

var timeSplit = timestarted.split(":") ;

var totalSec = ((timeSplit[0]*3600) + (timeSplit[1]*60) + (timeSplit[2]*1));
  • This portion of the script defines the initial time from which the time calculation is to be done
  • The line var timestarted = this.getField("start_time_field").valueAsString; imports the desired start time from the variable start_time_field. This imported time should be in the HH:MM:ss time format
  • The line var timeSplit = timestarted.split(":") ; then removes the colons from this imported time, leaving the time as HH MM ss. This is stored as a new variable, timesplit
  • Finally, the line var totalSec = ((timeSplit[0]*3600) + (timeSplit[1]*60) + (timeSplit[2]*1)); converts this imported time to be all in seconds. At this point in the script, the imported start time has now been converted to a total time in seconds
    • The following operators are used in this line of code: [0], [1], and [2]
    • [0] retrives the first portion of the variable timesplit
      • Thus, timeSplit[0] returns the value of HH from the variable of timesplit
      • Multiplying this value of hours by 3600 in turn converts the hours to seconds
    • [1] retrieves the second portion of the variable timesplit
      • Thus, timeSplit[1] returns the value of MM from the variable of timesplit
      • Multiplying this value of minutes by 60 in turn converts the minutes to seconds
    • [2] retrieves the second portion of the variable timesplit
      • Thus, timeSplit[2] returns the value of ss from the variable of timesplit
      • Multiplying this value of seconds by 1 leaves the time in seconds
  1. Defining the New Time
var newtotalSec = ((timeSplit[0]*3600) + (timeSplit[1]*60) + (timeSplit[2]*1) + "INTERVAL LENGTH X");

hours = Math.floor(newtotalSec/3600);

minutes = Math.floor((newtotalSec % 3600)/60);

seconds = newtotalSec % 60;
  • This portion of the script defines the new time to be calculated from the start time
  • The line var newtotalSec = ((timeSplit[0]*3600) + (timeSplit[1]*60) + (timeSplit[2]*1) + "INTERVAL LENGTH X"); calculates a new time in seconds by adding X amount of seconds to the initial start time in seconds
    • (timeSplit[0]*3600) + (timeSplit[1]*60) + (timeSplit[2]*1) converts the initial start time to be a total of seconds
    • + "INTERVAL LENGTH X" adds X amount of seconds to this start time total of seconds to result in the new desired calculated time
      • Thus, if the desired calculated time is to be 25 seconds after the start time, the line of code should look like the following:
        • var newtotalSec = ((timeSplit[0]*3600) + (timeSplit[1]*60) + (timeSplit[2]*1) + 25);
  • The lines of code following this line convert this new total of time of seconds into hours, minutes, and seconds
    • hours = Math.floor(newtotalSec/3600); converts the new total start time in seconds into hours
      • The function Math.floor() rounds the number in hours down, leaving only the number of hours with no decimal value
      • Thus, if the new total time of seoonds converts into 2.56 hours, the Math.floor() returns a value of 2 hours
    • minutes = Math.floor((newtotalSec % 3600)/60); converts the new total start time of seconds into minutes
      • The operator % is the remainder operator and returns only the remainder after integer division is completed
      • Thus, newtotalSec % 3600 returns only the remainder of seconds that did not divide wholly into hours. Dividing this value by 60, leaves the remainder in minutes.
    • seconds = newtotalSec % 60; returns the remainder of seconds that did not divide wholly into hours or minutes
      • Thus, this leaves the number of seconds to be left in HH:MM:ss format
    • After these three lines of code, three new variables have been created: the number of hours, minutes, and seconds in the new total start time of seconds
  1. Defining the Time Output
timeOutput = hours + ":" + minutes + ":" + seconds;

event.value = timeOutput
  • This portion of the script defines the final time calculated in HH:MM:ss time format
  • The line timeOutput = hours + ":" + minutes + ":" + seconds; defines a new variable of the new total time in HH:MM:ss time format
    • This line takes the previously defined variables of hours, minutes, and seconds and adds colons between them to give the new total calculated time in HH:MM:ss time format
  • The line event.value = timeOutput then defines the new total time in HH:MM:ss to be the output value of the field

The following is an example script for creating a new calculated time 10 seconds after the start time:

var timestarted = this.getField("task_start_time").valueAsString;

var timeSplit = timestarted.split(":") ;

var totalSec = ((timeSplit[0]*3600) + (timeSplit[1]*60) + (timeSplit[2]*1));

var newtotalSec = ((timeSplit[0]*3600) + (timeSplit[1]*60) + (timeSplit[2]*1) + 10);

hours = Math.floor(newtotalSec/3600);

minutes = Math.floor((newtotalSec % 3600)/60);

seconds = newtotalSec % 60;

timeOutput = hours + ":" + minutes + ":" + seconds;

event.value = timeOutput

Note. When creating multiple time calculated fields, each field should be calculated off of the intitial time. Calculated time fields should NOT be calculated off each other. For example, if five calculated time fields must be created, each 10 seconds apart from each other, one should not calculate each time field 10 seconds based off the previously calculated time. Instead, each field should be calculated based off of the initial start time. Thus, the first calculated field should add 10 seconds to the initial start time. The second calculated field should add 20 seconds based off the initial start time. The third calculated field should add 30 seconds based off the initial start time. And so forth. This ensures that no errors occur from calculating times based off times in fields that are already being calculated.


Note. Time calculated fields cannot be overwritten. One cannot manually overwrite the calculated time in a field with an alternative time. The field will always read the time calculated according to the inputted script. This should be kept in mind when creating multiple field that feature X second consecutive intervals. If at any point the intervals should be interrupted and a new time must be manually entered, it cannot be done. A potential means to work around this issue is found in the Token/Bead Sort example.

4.8.3 The Perfect Example: Token/Bead Sort

The Token/Bead Sort coding form provides a perfect example of time calculations, action buttons, and hidden fields at play. Token/Bead Sort consists of 18 ten second intervals. All of these intervals occur after a specified start time and should always be 10 seconds apart. However, if an interruption should occur during the task, a new start time must be entered into one of the intervals from which the following intervals should calculated from. Due to the time fields being calculated, the time values cannot be manually overwritten. The following solution is implemented to work around this:

  1. Time calculations are made for each of the initial 18 intervals
    • Each of these intervals calculate from the intial start time
      • Thus, the first interval calculates ten seconds from the initial start time, the second interval 20 seconds from the start time, the third interval 30 seconds from the start time, etc.
    • When the initial time is inputted, each of these intervals calculate automatically
  2. A second set of text fields are made for each of these 18 intervals
    • These fields have no calculations applied to them
    • These 18 fields are set to be hidden from user view
    • These 18 fields serve to allow for manually entry of a time in case of an interruption
    • The 18 fields are positioned over the initial 18 fields which do the contain the calculations
  3. A set of 18 buttons are created, one for each interval
    • Each button corresponds to an interval and is configured with actions to hide the calculated time interval it corresponds to and show the second text time field which allows for manual entry that it corresponds to
    • Each of these buttons serves to hide the calculated time field for the interval in which the interruption occurs and all the following intervals
    • Each button also shows the second time text field which allows for manual entry and also reveals the manual entry fields for all the following intervals
    • Each of these buttons is also set to be hidden from user view
  4. At the top of the coding form, the radio buttons for the “Was there an interruption in the task?” question are assigned actions
    • If “Yes” is selected, the 18 buttons are revealed and shown to the user
    • If “No” is selected, the 18 buttons are hidden
    • Thus, when the user selects that an interruption occurred, the 18 buttons appear and allow the user to select the interval in which the interruption occurred. When the button is pressed, the automatically calculated time fields are hidden for that interval and subsequent intervals, and the fields that allow for manual entry are shown for that interval and subsequent intervals. This allows for time calculations to be implemented even when interruptions occur
  5. Refer to the Token/Bead Sort coding form in order to gain further understanding of this setup

4.9 Calculating the Highest Level from a Row of Values

The following script returns the highest level of a behavior. For example, a behavior may be coded for the number of times it occurs at different levels of intensity. If one wants the highest level of intensity the behavior occurred at, regardless of the number of times it occurred, the following script can be utilized:

Note. The following script was created for a unique situation. Essentially, the script utilizes multiple if/else statements. How to employ if/else statements and conditionals are outlines above. Thus the explanation of how this specific script operates is less technical and brief. The building blocks of how to understand this script at a more technical level are provided above.

var v1= getField("intensity_of_behavior_1").value
var v2= getField("intensity_of_behavior_2").value
var v3= getField("intensity_of_behavior_3").value
var v4= getField("intensity_of_behavior_4").value
var v5= getField("intensity_of_behavior_5").value
var v6= getField("intensity_of_behavior_6").value


if (v6 > 0) {
  total6 = 6;
} else {
  total6 = 0;
}


if ((v5 > 0) && (v6 <= 0)) {
  total5 = 5;
} else {
  total5 = 0;
}


if ((v4 > 0) && (v6 <= 0) && (v5 <= 0)) {
  total4 = 4;
} else {
  total4 = 0;
}

if ((v3 > 0) && (v6 <= 0) && (v5 <= 0) && (v4 <= 0)){
  total3 = 3;
} else {
  total3 = 0;
}

if ((v2 > 0) && (v6 <= 0) && (v5 <= 0) && (v4 <= 0) && (v3 <= 0)){
  total2 = 2;
} else {
  total2 = 0;
}

if ((v1 > 0) && (v6 <= 0) && (v5 <= 0) && (v4 <= 0) && (v3 <= 0) && (v2 <= 0)){
  total = 1;
} else {
  total = 0;
}

event.value = total + total2 + total3 + total4 + total5 + total6
  • The above script uses if/else statements to determine the highest level at which the behaviors occurs
    • Double ampersands are used to create conditional statements with multiple conditions
  • Plainly, the above script asks whether the behavior occurs at least once at each level of intensity
    • If the behavior occurs at the highest level of intensity, the total returns a 6 which signifies the highest level of intensity
    • If the behavior does not occur at the highest level, it asks whether there is a value present for the second highest level. If there is, the total returns a 5 which significes the second highest level of intensity
    • If the behavior does not occur at the second highest level, it asks whether there is a value for the third highest. If not at the third highest, it asks at the fourth highest, and so forth.
  • This script may be modified to be employed in a variety of situations
  • The above script can be found in the Parental Sensitivity and Parental Intrusiveness Coding Forms
    • These forms should be studied in order to gain greater understanding of the specific context for which this script was created and how might it be applied to other contexts

5 How To Split PDF Files into Multiple Documents

  1. Open the PDF in Acrobat DC, and then choose Tools > Organize Pages or choose Organize Pages from the right pane.
    • The Organize Pages toolset is displayed in the secondary toolbar.
  2. In the secondary toolbar, click “Split”.
    • A new toolbar appears below the secondary toolbar with the commands specific to the Split operation.
  3. In this secondary toolbar, choose “Split” to see the document splitting options.
  4. In the “Split By” drop-down list, select the criteria for dividing the document:
    • Number Of Pages: Specify the maximum number of pages for each document in the split.
      • This is the most helpful option when trying to separate large scanned PDF packets into individual files. Just specify the number of pages as “1” (if the individual documents are only one page),“2” (if the documents are double sided), etc.
    • File Size: Specify the maximum file size for each document in the split.
    • Top-level Bookmarks: If the document includes bookmarks, creates one document for every top-level bookmark.
  5. To specify a target folder for the split files and filename preferences, click “Output Options”. Specify the folder in the lab drive that the files should be saved to, and then click OK.

Optional: To apply the same split to multiple documents, click “Split Multiple Files”. In the Split Documents dialog box, click either “Add Files”, and choose “Add Files”, “Add Folders”, or “Add Open Files”. Select the files or folder, and then click OK.

LS0tCnRpdGxlOiAiQWRvYmUgQmVzdCBQcmFjdGljZSBHdWlkZSIKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZSA9IEZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoCiAgZWNobyA9IFRSVUUsCiAgZXJyb3IgPSBUUlVFLAogIGNvbW1lbnQgPSAiIiwKICBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IikKYGBgCgojIEFkb2JlIEJlc3QgUHJhY3RpY2VzCgotIE5hbWUgdmFyaWFibGVzIGFsbCBsb3dlcmNhc2Ugd2l0aCBubyBzcGFjZXM7IHVzZSB1bmRlcnNjb3JlcyBpZiBzZXBhcmF0aW5nIHdvcmRzCi0gVXNlIHJhZGlvIGJ1dHRvbnMgd2hlbmV2ZXIgcG9zc2libGUKLSBVc2UgdGhlIGBhbGlnbmAgZmVhdHVyZSBhbmQgYG1hdGNoIHNpemVgIHRvIHdoZW4gY3JlYXRpbmcgdmFyaWFibGVzCi0gV2hlbiBjcmVhdGluZyBmb3JtcyBpbiBXb3JkLCBnaXZlIHNwYWNlIGZvciB0aGUgQWRvYmUgYnV0dG9ucyB0aGF0IHdpbGwgZXZlbnR1YWxseSBiZSBjcmVhdGVkCi0gTWFrZSBzdXJlIHlvdSBhcmUgdXNpbmcgc2FtZSBuYW1pbmcgY29udmVudGlvbnMKICAgIC0gYHRjaWRgCiAgICAtIGB3YXZlYAogICAgLSBgY29kZXJfbmFtZWAKICAgIC0gYGRhdGVfY29kZWRgCiAgICAtIGBjb2RlcmAgKGZvciAxLCAyLCAzIHZhcmlhYmxlKQogICAgLSBgZ2l2ZW5fb3BwX3RvX3BsYXlgCiAgICAtIGBwbGF5X3Rhc2tgCiAgICAtIGBwY19wcmVzZW50YAogICAgLSBgdGFza19zdGFydF90aW1lYAogICAgLSBgdGFza19zdG9wX3RpbWVgCiAgICAtIGB0YXNrX2xlbmd0aGAKLSBLZWVwIGl0IGNsZWFuCi0gS2VlcCBjb25zaXN0ZW50IG5hbWluZyBjb252ZW50aW9ucyB3aXRoaW4gKGFuZCBhY3Jvc3MpIGZvcm1zCi0gRm9yIGZvbnRzIGluIHRoZSBmaWVsZHMsIGluIGdlbmVyYWwsIHVzZSBhdXRvLgpIb3dldmVyLCB0aGlzIGNhbiBiZSBjaGFuZ2VkIGlmIHByb2JsZW1hdGljLiAKLSBUbyByZXNldCBmb3JtcywgY29weSBhbmQgcGFzdGUgdGhlIHZhcmlhYmxlcywgdGhlbiBkZWxldGUgd2hhdCB5b3UgcGFzdGVkLCBhbmQgaXQgd2lsbCBiZSBjbGVhcmVkLgotIENhbGN1bGF0ZWQgZmllbGRzIHNob3VsZCAqKipOT1QqKiogYmUgY2FsY3VsYXRlZCBvZmYgb2YgYWxyZWFkeSBjYWxjdWxhdGVkIGZpZWxkcy4KRmllbGRzIHNob3VsZCBvbmx5IGJlIGNhbGN1bGF0ZWQgb2ZmIG9mIGZpZWxkcyB0aGF0IGFyZSBtYW51YWxseSBpbnB1dHRlZC4KRm9yIG1vcmUgaW5mb3JtYXRpb24gb24gdGhpcywgc2VlIGNyZWF0aW5nIFt0aW1lIGNhbGN1bGF0aW9uc10oYWRvYmUuaHRtbCN0aW1lY2FsY3VsYXRpb25zKQoKIyBDb252ZXJ0aW5nIFdvcmQgRG9jdW1lbnRzIHRvIFBERnMKCkJlZm9yZSBjb252ZXJ0aW5nIGZvcm1zIHRvIHBkZnMsIGFsbCByZXF1aXJlZCBlZGl0cyB0byB0aGUgZG9jdW1lbnQgc2hvdWxkIGJlIG1hZGUgaW4gTWljcm9zb2Z0IFdvcmQuCkVkaXRzIG9mIGNvbnRlbnQgb3IgZm9ybWF0dGluZyBzaG91bGQgYmUgY29tcGxldGVkIGFuZCBmaW5hbGl6ZWQgaW4gV29yZCBiZWZvcmUgY29udmVydGluZyB0aGUgZG9jdW1lbnQgdG8gYSBwZGYuClRvIGNvbnZlcnQgYSBXb3JkIGRvY3VtZW50IHRvIGEgcGRmLCBjb21wbGV0ZSB0aGUgZm9sbG93aW5nIHN0ZXBzOgoKMS4gT3BlbiB0aGUgZG9jdW1lbnQgaW4gTWljcm9zb2Z0IFdvcmQKMS4gQ2xpY2sgdGhlICJGaWxlIiB0YWIgaW4gdGhlIHRvcCBsZWZ0IGNvcm5lciB3aXRoaW4gdGhlIFdvcmQgaW50ZXJmYWNlCjEuIFNlbGVjdCAiU2F2ZSBhcyBBRE9CRSBQREYiCjEuIE5hbWUgdGhlIG5ldyBwZGYgYWNjb3JkaW5nbHkKCiMgRWRpdGluZyBwZGZzIGluIEFkb2JlCgoxLiBPcGVuIHBkZiBpbiBBZG9iZSBBY3JvYmF0IFBybyAyMDIwCgogICAtICpOb3RlOiogRWRpdGluZyBvZiBwZGZzIG11c3QgYmUgZG9uZSBpbiBBZG9iZSBBY3JvYmF0IFBybyAyMDIwLCAqKipub3QqKiogQWRvYmUgQWNyb2JhdAoKMS4gVW5kZXIgdGhlICJUb29scyIgdGFiIGluIHRoZSB0b3AgbGVmdCBjb3JuZXIgb2YgdGhlIEFkb2JlIGludGVyZmFjZSwgZmluZCB0aGUgaGVhZGluZyAiRm9ybXMgJiBTaWduYXR1cmVzIiBhbmQgc2VsZWN0ICJQcmVwYXJlIEZvcm0iCgoxLiBTZWxlY3QgIlN0YXJ0IiB0byBiZWdpbiBzY2FubmluZyBhbmQgcHJlcGFyYXRpb24gb2YgdGhlIHBkZgoKMS4gVGhlICJQcmVwYXJlIEZvcm0iIHRvb2wgYmFyIHNob3VsZCBub3cgYmUgdmlzaWJsZSwgYWxsb3dpbmcgZm9yIHRoZSBhZGRpdGlvbiBvZiB0ZXh0IGZpZWxkcywgcmFkaW8gYnV0dG9ucywgY2hlY2sgYm94ZXMsIGFuZCBtb3JlCgojIyBBZGRpbmcgVGV4dCBGaWVsZHMsIFJhZGlvIEJ1dHRvbnMsIGFuZCBDaGVjayBCb3hlcwoKMS4gVGV4dCBmaWVsZHMgc2hvdWxkIGJlIGltcGxlbWVudGVkIHdoZW46CiAgIDEuIFRleHR1YWwgb3IgbnVtZXJpYyBpbmZvcm1hdGlvbiBtdXN0IGJlIG1hbnVhbGx5IGVudGVyZWQKICAgMS4gQSBjYWxjdWxhdGVkIGZpZWxkIGlzIHJlcXVpcmVkCjEuIFJhZGlvIGJ1dHRvbnMgc2hvdWxkIGJlIGltcGxlbWVudGVkIHdoZW5ldmVyIHBvc3NpYmxlCiAgIC0gUmFkaW8gYnV0dG9ucyBhbGxvdyBmb3Igb25seSBvbmUgc2VsZWN0aW9uIG91dCBvZiBhIGdyb3VwIG9mIG9wdGlvbnMKICAgICAgLSBSYWRpbyBidXR0b25zIHRodXMgc2hvdWxkIGJlIHVzZWQgZm9yIGltaXRhdGlvbiwgY29tcHJlaGVuc2lvbiwgcHJhY3RpY2UsIGFuZCB0ZXN0IHRyaWFsIGZpZWxkcyB3aXRoaW4gcGRmcwogICAtIEluIG9yZGVyIHRvIHByZXZlbnQgaHVtYW4gZXJyb3IsIHJhZGlvIGJ1dHRvbnMgc2hvdWxkIGJlIGFwcGxpZWQgdG8gYXMgbWFueSB2YXJpYWJsZXMgYXMgcG9zc2libGUKICAgLSBDYWxjdWxhdGVkIGZpZWxkcyBjYW4gYmUgZGVyaXZlZCBmcm9tIHJhZGlvIGJ1dHRvbnMKMS4gQ2hlY2sgYm94ZXMgc2hvdWxkIG9ubHkgYmUgdXNlZCB3aGVuIG5lY2Vzc2FyeQogICAtIENoZWNrIGJveGVzIGFsbG93IGZvciBtdWx0aXBsZSBzZWxlY3Rpb25zIHdpdGhpbiBhIGdyb3VwCiAgIC0gQ2hlY2sgYm94ZXMgc2hvdWxkICoqbm90KiogYmUgdXNlZCBmb3IgdHJpYWxzIGZpZWxkcyB3aXRoaW4gcGRmcyB1bmxlc3MgbXVsdGlwbGUgYW5zd2VycyBjYW4gYmUgc2VsZWN0ZWQgZm9yIGEgZ2l2ZW4gdHJpYWwKICAgLSBDYWxjdWxhdGVkIGZpZWxkcyBjYW4gYmUgZGVyaXZlZCBmcm9tIGNoZWNrIGJveGVzCjEuIEFjdGlvbiBidXR0b25zIHNob3VsZCBiZSBpbXBsZW1lbnRlZCB3aGVuIGEgc3BlY2lmaWMgYWN0aW9uIGlzIG5lZWRlZCB0byBiZSBjYXJyaWVkIG91dC4KVGhlc2UgYWN0aW9ucyB0eXBpY2FsbHkgaW5jbHVkZToKICAgKiBSZXNldGluZyBhIGZpZWxkKHMpL2Zvcm0KICAgKiBIaWRpbmcvUmV2ZWFsaW5nIGEgZmllbGQocykKCiMjIE5hbWluZyBDb252ZW50aW9uIGZvciBWYXJpYWJsZXMgaW4gQWRvYmUgeyNuYW1pbmd2YXJpYWJsZXN9CgoxLiBWYXJpYWJsZSBuYW1lcyBzaG91bGQgYmUgaW4gYWxsIGxvd2VyY2FzZSB3aXRoIG5vIHNwYWNlcyBhbmQgdW5kZXJzY29yZXMgc2VwYXJhdGluZyB3b3JkcwoxLiBLZWVwIHZhcmlhYmxlIG5hbWVzIGFzIGNvbnNpc3RlbnQgYXMgcG9zc2libGUgYWNyb3NzIGZvcm1zIHdpdGggc2ltaWxhciB2YXJpYWJsZXMKMS4gVGhlIGZvbGxvd2luZyBhcmUgY29tbW9uIG5hbWVzIGZvciB2YXJpYWJsZXMgd2hpY2ggc2hvdWxkIGJlIHVzZWQgd2hlbiBhcHBsaWNhYmxlOgogICAtIElkZW50aWZ5aW5nIGluZm9ybWF0aW9uOgogICAgICAtIFRDSUQ6IGB0Y2lkYAogICAgICAtIFdhdmU6IGB3YXZlYAogICAgICAtIENvZGVyIE5hbWU6IGBjb2Rlcl9uYW1lYAogICAgICAtIERhdGUgQ29kZWQ6IGBkYXRlX2NvZGVkYAogICAgICAtIENvZGVyOiBgY29kZXJgIChmb3IgMSwgMiwgMyB2YXJpYWJsZSkKICAgICAgLSBXYXMgVEMgZ2l2ZW4gdGhlIG9wcG9ydHVuaXR5IHRvIHBsYXkgdGhlIHRhc2s6IGBnaXZlbl9vcHBfdG9fcGxheWAKICAgICAgLSBEaWQgVEMgcGxheSB0aGUgdGFzazogYHBsYXlfdGFza2AKICAgICAgLSBQQyBQcmVzZW50OiBgcGNfcHJlc2VudGAKICAgICAgLSBEaWQgVEMgcGFzcyB0aGUgaW1pdGF0aW9uIHRyaWFsczogYHBhc3NfaW1pdGF0aW9uYAogICAgICAtIERpZCBUQyBwYXNzIHRoZSBjb21wcmVoZW5zaW9uIGNoZWNrOiBgcGFzc19jb21wcmVoZW5zaW9uYAogICAgICAtIERpZCBUQyBwYXNzIHRoZSBwcmFjdGljZSB0cmlhbHM6IGBwYXNzX3ByYWN0aWNlWGAKICAgICAgLSBTdGFydCB0aW1lOiBgdGFza19zdGFydF90aW1lYAogICAgICAtIFN0b3AgdGltZTogYHRhc2tfc3RvcF90aW1lYAogICAgICAtIExlbmd0aCBvZiBhZG1pbmlzdHJhdGlvbjogYHRhc2tfbGVuZ3RoYAogICAgICAtIENvZGVyIDEvMi8zOiBgaW5pdGlhbHNfZGF0ZV9jb2RlclhgCiAgIC0gVGFzayBUcmlhbHMKICAgICAgLSBJbWl0YXRpb24gVHJpYWxzOiBgaW1pdGF0aW9uX3RyaWFsc194YAogICAgICAtIEltaXRhdGlvbiBUcmlhbHMgU2Vjb25kIEFkbWluaXN0cmF0aW9uOiBgaW1pdGF0aW9uX3RyaWFsc19yZWFkbWluX3hgCiAgICAgIC0gQ29tcHJlaGVuc2lvbiBDaGVjazogYGNvbXBfY2hlY2tYX3hgCiAgICAgIC0gUHJhY3RpY2UgVHJpYWxzOiBgcHJhY3RpY2VfdHJpYWxzWF94YAogICAgICAtIFRlc3QgVHJpYWxzOiBgdGVzdF90cmlhbHNYX3hgCiAgICAgIC0gKk5vdGU6KiAiWCIgc2lnbmlmaWVzIHRoZSByb3VuZC9ibG9jayBvZiB0aGUgdHJpYWxzIHdoaWxlICJ4IiBzaWduaWZpZXMgdGhlIHRyaWFsIG51bWJlciB3aXRoaW4gdGhhdCByb3VuZC9ibG9jayAoZXg6IGBwcmFjdGljZV90cmlhbHMyXzdgKS4KICAgICAgQW4gIlgiIHdpdGhpbiB0aGUgdmFyaWFibGUgbmFtZSBpcyBvbmx5IG5lY2Vzc2FyeSBpZiB0aGVyZSBhcmUgbXVsdGlwbGUgcm91bmRzL2Jsb2NrcyBmb3IgdGhlIHRyaWFsLgogICAgICBUaHVzLCBpZiB0aGVyZSBpcyBvbmx5IG9uZSByb3VuZCBvZiBpbWl0YXRpb24gdHJpYWxzLCB0aG9zZSB0cmlhbHMgc2hvdWxkIGJlIHNpbXBseSBuYW1lZCBgdGVzdF90cmlhbHNgIHJhdGhlciB0aGFuIGB0ZXN0X3RyaWFsczFgLgogICAtIFRyaWFsIFRvdGFscwogICAgICAtIFRvdGFsIEluY29ycmVjdDogYHRvdGFsX2luY29ycmVjdF90YXNrX3RyaWFsc2AKICAgICAgLSBUb3RhbCBJbml0aWFsbHkgaW5jb3JyZWN0LCBidXQgY2hhbmdlZCB0byBjb3JyZWN0OiBgdG90YWxfaW5pdGlhbGx5X3Rhc2tfdHJpYWxzYAogICAgICAtIFRvdGFsIENvcnJlY3Q6IGB0b3RhbF9jb3JyZWN0X3Rhc2tfdHJpYWxzYAogICAgICAtIFRvdGFsIE5vIFJlc3BvbnNlOiBgdG90YWxfbm9yZXNwb25zZV90YXNrX3RyaWFsc2AKICAgICAgLSBUb3RhbCBVbmNvZGVhYmxlOiBgdG90YWxfdW5jb2RlYWJsZV90YXNrX3RyaWFsc2AKICAgICAgLSBUb3RhbCAjIG9mIFNjb3JlYWJsZSBUcmlhbHMgUGxheWVkOiBgdG90YWxfc2NvcmVkX3Rhc2tfdHJpYWxzYAogICAgICAtICpOb3RlOiogInRhc2tfdHJpYWxzIiBzaG91bGQgYmUgcmVwbGFjZWQgd2l0aCB3aGV0aGVyIHRoZSByb3VuZC9ibG9jayBvZiB0cmlhbHMgaXMgYGltaXRhdGlvbl90cmlhbHNgLCBgY29tcF9jaGVja2AsIGBwcmFjdGljZV90cmlhbHNgLCBvciBgdGVzdF90cmlhbHNgLgoKIyMjIE5hbWluZyBDb252ZW50aW9uIGZvciBSYWRpbyBCdXR0b25zIHsjbmFtaW5nY29udmVudGlvbnJhZGlvYnV0dG9uc30KCjEuIEluIG9yZGVyIHRvIGNyZWF0ZSBjYWxjdWxhdGVkIGZpZWxkcyBmb3IgdHJpYWwgdG90YWxzLCByYWRpbyBidXR0b24gIkNob2ljZSBWYWx1ZXMiIG11c3QgYmUgbWFudWFsbHkgc2V0LgpUbyBmYWNpbGl0YXRlIHRoZSBwcm9jZXNzLCB0aGlzIHNob3VsZCBiZSBkb25lIGFmdGVyIGFsaWduaW5nIGVhY2ggZ3JvdXAgb2YgcmFkaW8gYnV0dG9ucyBmb3IgZWFjaCB0cmlhbCB1bmRlciBlYWNoIFRDIHJlc3BvbnNlIGZvciB0aGUgdHJpYWwuCkZvciBleGFtcGxlLCB0aGVyZSBzaG91bGQgYmUgYSBjb2x1bW4gb2YgcmFkaW8gYnV0dG9ucyB1bmRlciB0aGUgIkNvcnJlY3QiIGxhYmVsIHdpdGhpbiB0aGUgdHJpYWwncyBncmlkIHdpdGggZWFjaCByYWRpbyBidXR0b24gaW4gdGhpcyBjb2x1bW4gcmVwcmVzZW50aW5nIHRoZSAiQ29ycmVjdCIgY2hvaWNlIGZvciBhIGRpZmZlcmVudCBncm91cCBvZiByYWRpbyBidXR0b25zLgpBIGNvbHVtbiBvZiBidXR0b25zIHNob3VsZCBiZSBwcmVzZW50IGZvciAiSW5jb3JyZWN0LCIgIk5vIFJlc3BvbnNlLCIgYW5kIHNvIGZvcnRoLgpUaHVzLCBlYWNoIGdyb3VwIG9mIHJhZGlvIGJ1dHRvbnMgc2hvdWxkIGJlIGFsaWduZWQgaG9yaXpvbnRhbGx5LCB3aXRoIGVhY2ggYnV0dG9uIHJlZmxlY3RpbmcgYSBkaWZmZXJlbnQgVEMgcmVzcG9uc2UuClRoZXNlIGdyb3VwcyBzaG91bGQgdGhlbiBiZSBzdGFja2VkIGludG8gYSBjb2x1bW4gd2l0aCBlYWNoIGNvbHVtbiByZXByZXNlbnRpbmcgdGhlIHJlc3BvbnNlIGFjcm9zcyB0cmlhbHMuClRoZSBDaG9pY2UgVmFsdWVzIGNhbiB0aGVuIGJlIHNldCB0aHJvdWdoIHRoZSBmb2xsb3dpbmcgc3RlcHM6CiAgIAogICAxLiBTZWxlY3QgdGhlIGVudGlyZSBjb2x1bW4gdW5kZXIgYSBjZXJ0YWluIFRDIHJlc3BvbnNlIChleC4gc2VsZWN0IHRoZSBlbnRpcmUgY29sdW1uIG9mIHJhZGlvIGJ1dHRvbnMgdW5kZXIgIkNvcnJlY3QiKQogICAxLiBSaWdodC1jbGljayBvbiB0aGUgc2VsZWN0ZWQgY29sdW1uIG9mIHJhZGlvIGJ1dHRvbnMgYW5kIHNlbGVjdCAiUHJvcGVydGllcyIKICAgMS4gVW5kZXIgdGhlICJPcHRpb25zIiB0YWIsIHNldCB0aGUgIlJhZGlvIEJ1dHRvbiBDaG9pY2UiIGFjY29yZGluZyB0byB0aGUgZm9sbG93aW5nIHZhbHVlczoKICAgICAgLSAiQ29ycmVjdCIgY29sdW1uID0gMgogICAgICAtICJJbmNvcnJlY3QiIGNvbHVtbiA9IDAKICAgICAgLSAiSW5pdGlhbGx5IGluY29ycmVjdCBidXQgY2hhbmdlZCByZXNwb25zZSB0byBjb3JyZWN0IiBjb2x1bW4gPSAxCiAgICAgIC0gIk5vIHJlc3BvbnNlIiBjb2x1bW4gPSAtOQogICAgICAtICJVbmNvZGVhYmxlIiBjb2x1bW4gPSA5CiAgIDEuIFNldCBhbGwgY29sdW1ucyB3aXRoIHRoZWlyIGFwcHJvcHJpYXRlIHJhZGlvIGJ1dHRvbiBjaG9pY2UgdmFsdWUKICAgLSAqTm90ZToqIFdoaWxlIGNhbGN1bGF0ZWQgZmllbGRzIGNhbiBiZSBkZXJpdmVkIGZyb20gZGlmZmVyZW50IHJhZGlvIGJ1dHRvbiBjaG9pY2UgdmFsdWVzLCBpdCBpcyBpbXBlcmF0aXZlIHRvIGFzc2lnbiB0aGUgYnV0dG9uIGNob2ljZXMgYWNjb3JkaW5nIHRvIHRoZXNlIHZhbHVlcy4KICAgVGhpcyBhbGxvd3MgZm9yIGNvbnNpc3RlbmN5IGFjcm9zcyBwZGZzIGFuZCB0aGUgYWJpbGl0eSB0byBzbW9vdGhseSBib3Jyb3cgY29kZSBmb3IgY2FsY3VsYXRlZCBmaWVsZHMuCgojIyMgTmFtaW5nIENvbnZlbnRpb24gZm9yIENoZWNrIEJveGVzIHsjbmFtaW5nY29udmVudGlvbmNoZWNrYm94ZXN9CgpDaGVjayBib3hlcyBjYW4gYmUgbmFtZWQgaW4gc3VjaCBhIHdheSB0aGF0IHRoZXkgYWN0IHNpbWlsYXIgdG8gcmFkaW8gYnV0dG9ucywgYWxsb3dpbmcgb25seSBvbmUgc2VsZWN0aW9uIG91dCBvZiBhIGdyb3VwIG9mIGNoZWNrIGJveGVzLj0KQSBncm91cCBvZiBjaGVjayBib3hlcyBjYW4gYmUgZm9ybWF0dGVkIGFzIHJhZGlvIGJ1dHRvbnMgdGhyb3VnaCB0aGUgZm9sbG93aW5nIHN0ZXBzOgoKMS4gSW5wdXQgdGhlICpzYW1lKiB2YXJpYWJsZSBuYW1lIGZvciBlYWNoIGNoZWNrIGJveCB3aXRoaW4gdGhlIGdyb3VwIHRvIGJlIGZvcm1hdHRlZAoxLiBSaWdodCBjbGljayBvbiBlYWNoIGNoZWNrIGJveCBhbmQgc2VsZWN0ICJQcm9wZXJ0aWVzIgoxLiBVbmRlciB0aGUgIk9wdGlvbnMiIHRhYiwgc2V0IHRoZSAiRXhwb3J0IFZhbHVlIiBmb3IgZWFjaCBjaGVjayBib3ggYWNjb3JkaW5nIHRvIHRoZSBmb2xsb3dpbmcgdmFsdWVzOgogICAgICAtICJDb3JyZWN0IiBjb2x1bW4gPSAyCiAgICAgIC0gIkluY29ycmVjdCIgY29sdW1uID0gMAogICAgICAtICJJbml0aWFsbHkgaW5jb3JyZWN0IGJ1dCBjaGFuZ2VkIHJlc3BvbnNlIHRvIGNvcnJlY3QiIGNvbHVtbiA9IDEKICAgICAgLSAiTm8gcmVzcG9uc2UiIGNvbHVtbiA9IC05CiAgICAgIC0gIlVuY29kZWFibGUiIGNvbHVtbiA9IDkKMS4gV2l0aCBlYWNoIGNoZWNrIGJveCBuYW1lZCB0aGUgc2FtZSBidXQgYWxzbyBlYWNoIHdpdGggYSBkaWZmZXJlbnQgZXhwb3J0IHZhbHVlLCB0aGUgZ3JvdXAgb2YgY2hlY2sgYm94ZXMgc2hvdWxkIG5vdyBvcGVyYXRlIHNpbWlsYXIgdG8gYSBncm91cCBvZiByYWRpbyBidXR0b25zCiAgIC0gV2l0aGluIHRoZSBncm91cCwgb25seSBvbmUgY2hlY2sgYm94IHNob3VsZCBiZSBhYmxlIHRvIGJlIHNlbGVjdGVkCiAgIC0gQWRkaXRpb25hbGx5LCB0aGUgc2VsZWN0aW9uIHNob3VsZCBiZSBhYmxlIHRvIGJlIHVuc2VsZWN0ZWQKMS4gV2hpbGUgYm90aCBncm91cHMgb2YgcmFkaW8gYnV0dG9ucyBhbmQgdGhpcyBmb3JtIG9mIGdyb3VwcyBvZiBjaGVjayBib3hlcyBvcGVyYXRlIHRoZSBzYW1lIHdheSBhbmQgcGVybWl0IG9ubHkgb25lIHNlbGVjdGlvbiB3aXRoaW4gdGhlIGdyb3VwLCBncm91cHMgb2YgY2hlY2sgYm94ZXMgcHJvdmlkZSBhbiBhZHZhbnRhZ2UgYnkgYWxsb3dpbmcgZm9yIGRlc2VsZWN0aW9uIG9mIHRoZSB2YWx1ZS4KV2l0aGluIGdyb3VwcyBvZiByYWRpbyBidXR0b25zLCBhcyBzb29uIGFzIGEgYnV0dG9uIGlzIHNlbGVjdGVkLCB0aGUgZ3JvdXAgb2YgYnV0dG9ucyBjYW5ub3QgYmUgcmVzZXQgb3IgZGVzZWxlY3RlZC4KVGhpcyB1c2FnZSBvZiBncm91cHMgb2YgY2hlY2sgYnV0dG9ucyBtYXkgYmUgdXNlZnVsIGdvaW5nIGZvcndhcmQgYW5kIHNob3VsZCBiZSBjb25zaWRlcmVkIHdoZW4gY3JlYXRpbmcgbmV3IGNvZGluZyBmb3Jtcy4KICAgLSAqTm90ZToqIENyZWF0aW5nIGNhbGN1bGF0ZWQgZmllbGRzIGZyb20gZ3JvdXBzIG9mIGNoZWNrIGJveGVzIHdpbGwgZm9sbG93IHRoZSBzYW1lIHByb2NlZHVyZSBhcyBbY3JlYXRpbmcgY2FsY3VhdGVkIGZpZWxkcyBmcm9tIHJhZGlvIGJ1dHRvbnNdKGFkb2JlLmh0bWwjY3JlYXRlY2FsY3VsYXRlZHJhZGlvYnV0dG9ucykuCiAgIFRodXMsIGl0IGlzIGltcG9ydGFudCB0byBlbnN1cmUgdGhlIGV4cG9ydCB2YWx1ZXMgZm9yIGVhY2ggY2hlY2sgYm94IGZvbGxvdyB0aGUgdmFsdWVzIGxpc3RlZCBpbiBTdGVwIDMuCgoKIyMgSGlkaW5nIGFuZCBSZXZlYWxpbmcgRmllbGRzIGluIEFkb2JlIHsjaGlkZGVuZmllbGRzfQoKRmllbGRzIGNhbiBiZSBoaWRkZW4gYW5kIHJldmVhbGVkIHdpdGhpbiBBZG9iZSBkb2N1bWVudHMuClRvIGRvIHN1Y2gsIGNvbXBsZXRlIHRoZSBmb2xsb3dpbmcgc3RlcHM6CgoxLiBSaWdodCBjbGljayBvbiB0aGUgZmllbGQgdG8gYmUgaGlkZGVuCjEuIFNlbGVjdCAiUHJvcGVydGllcyIKMS4gVW5kZXIgdGhlICJHZW5lcmFsIiB0YWIsIG5hdmlnYXRlIHRvIHRoZSAiQ29tbW9uIFByb3BlcnRpZXMiIGJveCBhdCB0aGUgYm90dG9tIG9mIHRoZSB0YWIKMS4gRm9yICJGb3JtIEZpZWxkOiIgc2VsZWN0IGBIaWRkZW5gIGZyb20gdGhlIGRyb3AtZG93biBtZW51CjEuIE5vdywgd2hlbiBwcmV2aWV3aW5nIHRoZSBkb2N1bWVudCwgdGhlIHNlbGVjdGVkIGZpZWxkIHNob3VsZCBiZSBoaWRkZW4gZnJvbSB1c2VyIHZpZXcKMS4gSW4gb3JkZXIgdG8gbWFrZSB0aGUgZmllbGQgdmlzaWJsZSB0byB1c2VycyBhZ2FpbiwgY29tcGxldGUgc3RlcHMgMS00LCBidXQgaW5zdGVhZCBvZiBzZWxlY3RpbmcgYEhpZGRlbmAgZm9yICJGb3JtIEZpZWxkOiIsIHNlbGVjdCBgVmlzaWJsZWAKMS4gVGhlIGZpZWxkIHNob3VsZCBub3cgYmUgdmlzaWJsZSB0byB1c2VycwoKIyMgQ3JlYXRpbmcgQWN0aW9ucyBpbiBBZG9iZQoKUmFkaW8gYnV0dG9ucywgY2hlY2sgYm94ZXMsIHRleHQgZmllbGRzLCBhbmQgYWN0aW9uIGJ1dHRvbnMgY2FuIGFsbCBiZSBhc3NpZ25lZCBzcGVjaWZpYyBhY3Rpb25zIHVwb24gY2xpY2tpbmcgdGhlbS4gVGhlIG1vc3QgY29tbW9uIGFjdGlvbnMgdXNlZCBhcmU6CiAgICogQ2xlYXJpbmcgb3IgcmVzZXRpbmcgYSBmaWVsZChzKSBvciBhbiBlbnRpcmUgZm9ybQogICAqIEhpZGluZy9yZXZlYWxpbmcgYSBmaWVsZChzKQoKVG8gYXNzaWduIGEgcmFkaW8gYnV0dG9uLCBjaGVjayBib3gsIHRleHQgZmllbGQsIG9yIGFjdGlvbiBidXR0b24gYW4gYWN0aW9uLCBjb21wbGV0ZSB0aGUgZm9sbG93aW5nIHN0ZXBzOgoKMS4gUmlnaHQgY2xpY2sgb24gdGhlIG9iamVjdCAodGhlIHJhZGlvIGJ1dHRvbi9jaGVjayBib3gvdGV4dCBmaWVsZC9hY3Rpb24gYnV0dG9uIGluIHF1ZXN0aW9uKSB0byB3aGljaCBhbiBhY3Rpb24gaXMgdG8gYmUgYXNzaWduZWQKMS4gU2VsZWN0IHRoZSAiQWN0aW9ucyIgdGFiCjEuIFdpdGhpbiB0aGUgIkFkZCBhbiBBY3Rpb24iIGludGVyZmFjZSwgZm9yICJTZWxlY3QgVHJpZ2dlcjoiIGVuc3VyZSB0aGUgcmVzcG9uc2Ugb2YgYE1vdXNlIFVwYCBpcyBzZWxlY3RlZAogICAqIFRoaXMgY29uZmlndXJlcyB0aGUgYWN0aW9uIHRvIGJlIGV4ZWN1dGVkIHdoZW4gdGhlIG9iamVjdCBpcyBjbGlja2VkIHVwb24gd2l0aCB0aGUgdXNlcidzIG1vdXNlCjEuIFdpdGhpbiB0aGUgIkFkZCBhbiBBY3Rpb24iIGludGVyZmFjZSwgZm9yICJTZWxlY3QgQWN0aW9uOiIgY2hvb3NlIHRoZSBkZXNpcmVkIGFjdGlvbiB0byBiZSBhc3NpZ25lZCB0byB0aGUgb2JqZWN0IGZyb20gdGhlIGRyb3AtZG93biBtZW51CiAgICogVG8gY2xlYXIvcmVzZXQgYSBmaWVsZDoKICAgICAgKiBTZWxlY3QgYFJlc2V0IGEgZm9ybWAKICAgKiBUbyBoaWRlL3JldmVhbCBhIGZpZWxkOgogICAgICAqIFNlbGVjdCBgU2hvdy9oaWRlIGEgZmllbGRgCjEuIFdpdGhpbiB0aGUgIkFkZCBhbiBBY3Rpb24iIGludGVyZmFjZSwgc2VsZWN0ICJBZGQuLi4iIHRvIGltcGxlbWVudCB0aGUgY2hvc2VuIGFjdGlvbiB0byB0aGUgb2JqZWN0CiAgICogVXBvbiBjbGlja2luZyBhZGQsIGEgc2VwYXJhdGUgd2luZG93IHdpbGwgYXBwZWFyIGFza2luZyB5b3UgdG8gc3BlY2lmeSB3aGljaCBmaWVsZHMgdGhlIGFjdGlvbiBzaG91bGQgYmUgYXBwbGllZCB0bwogICAqIElmIGNsZWFyaW5nL3Jlc2V0aW5nIGEgZmllbGQ6CiAgICAgICogTWFyayBhbGwgdGhlIGNoZWNrIGJveGVzIG9mIGFsbCB0aGUgZmllbGRzIHRvIGJlIHJlc3QKICAgICAgKiBTZWxlY3QgIk9LIgogICAqIElmIGhpZGluZy9yZXZlYWxpbmcgYSBmaWVsZDoKICAgICAgKiBTZWxlY3QgdGhlIG5hbWUgb2YgdGhlIGZpZWxkIHRvIGJlIGhpZGRlbi9yZXZlYWxlZAogICAgICAqIE9uIHRoZSByaWdodCwgc2VsZWN0IHRoZSByYWRpbyBidXR0b24gc2VsZWN0aW9uIGZvciB3aGV0aGVyIHRoZSBhY3Rpb24gc2hvdWxkIGBTaG93YCBvciBgSGlkZWAgdGhlIGZpZWxkCiAgICAgICogU2VsZWN0ICJPSyIKMS4gVXBvbiBzZWxlY3Rpb24gb2YgIk9LLCIgdGhlIGFjdGlvbiBzaG91bGQgbm93IGFwcGVhciB3aXRoaW4gdGhlICJBY3Rpb24iIGJveCBhdCB0aGUgYm90dG9tIG9mIHRoZSB0YWIKMS4gSW4gb3JkZXIgdG8gZWRpdCB0aGUgYWN0aW9uLCBzZWxlY3QgdGhlIGFjdGlvbiB0byBiZSBlZGl0ZWQgYW5kIHRoZW4gc2VsZWN0ICJFZGl0IiBhdCB0aGUgYm90dG9tIG9mIHRoZSBpbnRlcmZhY2UKMS4gTXVsdGlwbGUgYWN0aW9ucyBjYW4gYmUgYXNzaWduZWQgdG8gdGhlIHNhbWUgb2JqZWN0LgpUaHVzLCByZXBlYXQgc3RlcHMgMS02IGFzIG1hbnkgdGltZXMgYXMgbmVlZGVkIHRvIGFzc2lnbiB0aGUgbmVjZXNzYXJ5IGFjdGlvbnMgdG8gYSBnaXZlbiBvYmplY3QKCgojIENyZWF0aW5nIENhbGN1bGF0ZWQgRmllbGRzCgpBZG9iZSBBY3JvYmF0IGJvdGggaW5jbHVkZXMgaXRzIG93biBmdW5jdGlvbnMgZm9yIGNyZWF0aW5nIGNhbGN1bGF0ZWQgZmllbGRzIGFuZCBhbGxvd3MgZm9yIHRoZSBpbXBsZW1lbnRhdGlvbiBvZiBjdXN0b20gY2FsY3VsYXRpb24gc2NyaXB0cyB3aXRoaW4gZm9ybXMuCldoaWxlIHRoZSBjYWxjdWxhdGlvbiBmZWF0dXJlcyBhcmUgYnVpbHQtaW4gdG8gQWRvYmUsIHRoZSBjdXN0b20gY2FsY3VsYXRpb24gc2NyaXB0cyBtdXN0IGJlIHdyaXR0ZW4gdXNpbmcgdGhlIHByb2dyYW1taW5nIGxhbmd1YWdlIEphdmFTY3JpcHQuClRoZSBmb2xsb3dpbmcgc2VjdGlvbnMgZGV0YWlsIGhvdyB0byBjcmVhdGUgZGlmZmVyZW50IHR5cGVzIG9mIGNhbGN1bGF0ZWQgZmllbGRzLgoKIyMgQ3JlYXRpbmcgQ2FsY3VsYXRlZCBGaWVsZHMgZnJvbSBSYWRpbyBCdXR0b25zIHsjY3JlYXRlY2FsY3VsYXRlZHJhZGlvYnV0dG9uc30KCjEuIEZpcnN0LCBlbnN1cmUgdGhlIHJhZGlvIGJ1dHRvbnMgYW5kIHRoZWlyIGNob2ljZSB2YWx1ZXMgYXJlIGFwcHJvcHJpYXRlbHkgc2V0IGFjY29yZGluZyB0byB0aGUgW25hbWluZyBjb252ZW50aW9uIGZvciByYWRpbyBidXR0b25zXShhZG9iZS5odG1sI25hbWluZ2NvbnZlbnRpb25yYWRpb2J1dHRvbnMpCjEuIFNlbGVjdCB0aGUgdGV4dCBmaWVsZCB3aGljaCBtdXN0IGJlIHR1cm5lZCBpbnRvIGEgY2FsY3VsYXRlZCBmaWVsZAoxLiBSaWdodC1jbGljayBvbiB0aGUgZmllbGQgYW5kIHNlbGVjdCAiUHJvcGVydGllcyIKMS4gU2VsZWN0IHRoZSAiQ2FsY3VsYXRlIiB0YWIgd2l0aGluIHRoZSBQcm9wZXJ0aWVzIG1lbnUKMS4gU2VsZWN0IHRoZSAiQ3VzdG9tIGNhbGN1bGF0aW9uIHNjcmlwdDoiIHJhZGlvIGJ1dHRvbgoxLiBTZWxlY3QgIkVkaXQuLi4iIGFuZCBpbnB1dCB0aGUgZGVzaXJlZCBjYWxjdWxhdGlvbiBzY3JpcHQKICAgLSBUaGUgZm9sbG93aW5nIHNjcmlwdCBzaG91bGQgYmUgYXBwbGllZCBpbiBvcmRlciB0byBjYWxjdWxhdGUgcmFkaW8gYnV0dG9uczoKCiAgIGBgYAogICB2YXIgdjEgPSBnZXRGaWVsZCgidmFyaWFibGVfZ3JvdXBfbmFtZSIpLnZhbHVlCiAgIHZhciB2MiA9IGdldEZpZWxkKCJ2YXJpYWJsZV9ncm91cF9uYW1lMiIpLnZhbHVlCiAgIHZhciB2MyA9IGdldEZpZWxkKCJ2YXJpYWJsZV9ncm91cF9uYW1lMyIpLnZhbHVlCiAgIHZhciB2NCA9IGdldEZpZWxkKCJ2YXJpYWJsZV9ncm91cF9uYW1lNCIpLnZhbHVlCgogICBpZiAodjEgPT0gWCkgeyAKICAgdG90YWwgPSAxOwogICB9IGVsc2UgewogICB0b3RhbCA9IDA7CiAgIH0KCiAgIGlmICh2MiA9PSBYKSB7CiAgIHRvdGFsMiA9IDE7CiAgIH0gZWxzZSB7CiAgIHRvdGFsMiA9IDA7CiAgIH0KCiAgIGlmICh2MyA9PSBYKSB7CiAgIHRvdGFsMyA9IDE7CiAgIH0gZWxzZSB7CiAgIHRvdGFsMyA9IDA7CiAgIH0KCiAgIGlmICh2NCA9PSBYKSB7CiAgIHRvdGFsNCA9IDE7CiAgIH0gZWxzZSB7CiAgIHRvdGFsNCA9IDA7CiAgIH0KCiAgIGV2ZW50LnZhbHVlID0gdG90YWwgKyB0b3RhbDIgKyB0b3RhbDMgKyB0b3RhbDQKICAgYGBgCiAgIC0gVGhpcyBzY3JpcHQgc2hvdWxkIGJlIGZpdCBhY2NvcmRpbmcgdG8gaG93IG1hbnkgdHJpYWxzL3ZhcmlhYmxlcyBtdXN0IGJlIGNhbGN1bGF0ZWQgZnJvbQogICAtIFByb2NlZWQgdG8gW0JyZWFraW5nIERvd24gdGhlIENhbGN1bGF0aW9uIFNjcmlwdF0oYWRvYmUuaHRtbCNicmVha2luZ2Rvd25zY3JpcHQpIHRvIGdhaW4gYSBncmVhdGVyIHVuZGVyc3RhbmRpbmcgb2YgdGhlIHNjcmlwdAoKIyMgQ3JlYXRpbmcgQ2FsY3VsYXRlZCBGaWVsZHMgZnJvbSBSYWRpbyBCdXR0b25zOiBWaWRlbwoKV2F0Y2ggdGhlIGZvbGxvd2luZyB2aWRlbyBpbiBvcmRlciB0byBvYnNlcnZlIGFuIGV4YW1wbGUgb2YgY3JlYXRpbmcgY2FsY3VsYXRlZCBmaWVsZHMgZnJvbSByYWRpbyBidXR0b25zOgo8YnI+Cjxicj4KCjx2aWRlbyB3aWR0aD0iMTAwJSIgY29udHJvbHM9IiIgcHJlbG9hZD0ibm9uZSI+Cjxzb3VyY2Ugc3JjPSJpbWFnZXMvY3JlYXRpbmdfY2FsY3VsYXRlZF9maWVsZHNfaW5fYWRvYmUubXA0IiB0eXBlPSJ2aWRlby9tcDQiPgo8L3ZpZGVvPgoKIyMgQ3JlYXRpbmcgQ2FsY3VsYXRlZCBGaWVsZHMgZnJvbSBDaGVjayBCb3hlcwoKMS4gUHJlcGFyZSB0aGUgY2hlY2sgYm94ZXMgZm9yIGNhbGN1bGF0aW9uOgoKICAgMS4gUHJvdmlkZSB0aGUgY2hlY2sgYm94ZXMgZnJvbSB3aGljaCB0aGUgZmllbGQgd2lsbCBiZSBjYWxjdWxhdGVkIHdpdGggYXBwcm9wcmlhdGUgdmFyaWFibGUgbmFtZXMsIGNsb3NlbHkgZm9sbG93aW5nIHN0YW5kYXJkIFtuYW1pbmcgY29udmVudGlvbiBmb3IgdmFyaWFibGVzXShhZG9iZS5odG1sI25hbWluZ3ZhcmlhYmxlcykgd2hlbiBwb3NzaWJsZQogICAKICAgMS4gRm9yIGVhY2ggY2hlY2sgYm94LCBhbiBleHBvcnQgdmFsdWUgbXVzdCBiZSBhc3NpZ25lZC4KICAgVGhlIGV4cG9ydCB2YWx1ZSB3aWxsIGRldGVybWluZSB3aGF0IG51bWVyaWMgdmFsdWUgdGhlIGNoZWNrIGJveCB3aWxsIGNhcnJ5IHRocm91Z2hvdXQgY2FsY3VsYXRpb24uCiAgIFRvIHNldCB0aGUgZXhwb3J0IHZhbHVlLCBjb21wbGV0ZSB0aGUgZm9sbG93aW5nIHN0ZXBzOgoKICAgICAgMS4gU2VsZWN0IGFuZCByaWdodC1jbGljayBvbiB0aGUgY2hlY2sgYm94IGFuZCBzZWxlY3QgIlByb3BlcnRpZXMiCiAgICAgIDEuIEluIHRoZSBQcm9wZXJ0aWVzIG1lbnUsIHNlbGVjdCB0aGUgIk9wdGlvbnMiIHRhYgogICAgICAxLiBJbiB0aGUgIkV4cG9ydCBWYWx1ZToiIGZpZWxkLCBlbnRlciB0aGUgbnVtZXJpYyB2YWx1ZSB0aGUgY2hlY2sgYm94IHNob3VsZCByZWZsZWN0CgoxLiBTZWxlY3QgdGhlIHRleHQgZmllbGQgd2hpY2ggbXVzdCBiZSB0dXJuZWQgaW50byBhIGNhbGN1bGF0ZWQgZmllbGQKMS4gUmlnaHQtY2xpY2sgb24gdGhlIGZpZWxkIGFuZCBzZWxlY3QgIlByb3BlcnRpZXMiCjEuIFNlbGVjdCB0aGUgIkNhbGN1bGF0ZSIgdGFiIHdpdGhpbiB0aGUgUHJvcGVydGllcyBtZW51CjEuIFNlbGVjdCB0aGUgIlZhbHVlIGlzIHRoZSBgbWF0aGVtYXRpY2FsIG9wZXJhdG9yc2Agb2YgdGhlIGZvbGxvd2luZyBmaWVsZHMiIHJhZGlvIGJ1dHRvbgogICAtICpOb3RlOiogVGhlIGFwcHJvcHJpYXRlIGBtYXRoZW1hdGljYWwgb3BlcmF0b3JgIHNob3VsZCBiZSBzZWxlY3RlZCBhY2NvcmRpbmcgdG8gdGhlIGRlc2lyZWQgZmluYWwgY2FsY3VsYXRpb24gZnJvbSB0aGUgZHJvcCBkb3duIGxpc3Qgb2YgInN1bSAoKyksIiAicHJvZHVjdCAoeCksIiAiYXZlcmFnZSwiICJtaW5pbXVtLCIgb3IgIm1heGltdW0iCjEuIFNlbGVjdCAiUGljay4uLiIgYW5kIHRoZW4gY2hlY2sgdGhlIHZhcmlhYmxlIG5hbWVzIG9mIHRoZSBjaGVjayBib3hlcyB0byBiZSBjYWxjdWxhdGVkCgojIyBCcmVha2luZyBEb3duIHRoZSBDYWxjdWxhdGlvbiBTY3JpcHQgeyNicmVha2luZ2Rvd25zY3JpcHR9CgpgYGAKdmFyIHYxID0gZ2V0RmllbGQoInZhcmlhYmxlX2dyb3VwX25hbWUiKS52YWx1ZQp2YXIgdjIgPSBnZXRGaWVsZCgidmFyaWFibGVfZ3JvdXBfbmFtZTIiKS52YWx1ZQp2YXIgdjMgPSBnZXRGaWVsZCgidmFyaWFibGVfZ3JvdXBfbmFtZTMiKS52YWx1ZQp2YXIgdjQgPSBnZXRGaWVsZCgidmFyaWFibGVfZ3JvdXBfbmFtZTQiKS52YWx1ZQoKaWYgKHYxID09IFgpIHsgCnRvdGFsID0gMTsKfSBlbHNlIHsKdG90YWwgPSAwOwp9CgppZiAodjIgPT0gWCkgewp0b3RhbDIgPSAxOwp9IGVsc2Ugewp0b3RhbDIgPSAwOwp9CgppZiAodjMgPT0gWCkgewp0b3RhbDMgPSAxOwp9IGVsc2Ugewp0b3RhbDMgPSAwOwp9CgppZiAodjQgPT0gWCkgewp0b3RhbDQgPSAxOwp9IGVsc2Ugewp0b3RhbDQgPSAwOwp9CgpldmVudC52YWx1ZSA9IHRvdGFsICsgdG90YWwyICsgdG90YWwzICsgdG90YWw0CmBgYApUaGUgY2FsY3VsYXRpb24gc2NyaXB0IGZvciByYWRpbyBidXR0b25zIGNhbiBiZSBicm9rZW4gZG93biBpbnRvIHRocmVlIHBhcnRzOgoKMS4gRGVmaW5pbmcgdGhlIFZhcmlhYmxlcwoKICAgYGBgCiAgIHZhciB2MSA9IGdldEZpZWxkKCJ2YXJpYWJsZV9ncm91cF9uYW1lIikudmFsdWUKICAgdmFyIHYyID0gZ2V0RmllbGQoInZhcmlhYmxlX2dyb3VwX25hbWUyIikudmFsdWUKICAgdmFyIHYzID0gZ2V0RmllbGQoInZhcmlhYmxlX2dyb3VwX25hbWUzIikudmFsdWUKICAgdmFyIHY0ID0gZ2V0RmllbGQoInZhcmlhYmxlX2dyb3VwX25hbWU0IikudmFsdWUKICAgYGBgCgogICAtIFRoaXMgcG9ydGlvbiBvZiB0aGUgc2NyaXB0IGRlZmluZXMgdGhlIHZhcmlhYmxlcyBmcm9tIHdoaWNoIGluZm9ybWF0aW9uIGlzIGJlaW5nIHB1bGxlZCBmcm9tLgogICBJbiBuZWFybHkgYWxsIGNhc2VzIHRoZSB2YXJpYWJsZXMgYmVpbmcgcHVsbGVkIGZyb20gd2lsbCBiZSB0aGUgZ3JvdXBzIG9mIHJhZGlvIGJ1dHRvbnMgZm9yIGVhY2ggdHJpYWwuCiAgIC0gVGhlIGxpbmUgYHZhciB2MSA9IGdldEZpZWxkKCJ2YXJpYWJsZV9ncm91cF9uYW1lIikudmFsdWVgIGRlZmluZXMgdGhlIHNlbGVjdGVkIHJhZGlvIGJ1dHRvbiBpbiAidmFyaWFibGVfZ3JvdXBfbmFtZSIgYXMgYHZhciB2MWAgKHZhcmlhYmxlIDEpIHdpdGhpbiB0aGlzIHNjcmlwdCBhbmQgcHVsbHMgdGhlICoqY2hvaWNlIHZhbHVlKiogZnJvbSBlYWNoIGdyb3VwCiAgICAgIC0gVGh1cywgd2l0aGluIGVhY2ggYGdldEZpZWxkKClgLCB0aGUgbmFtZSBvZiBlYWNoIGdyb3VwIG9mIHJhZGlvIGJ1dHRvbnMgc2hvdWxkIGJlIGFkZGVkIGluIHF1b3RhdGlvbnMKICAgICAgLSAqTm90ZToqIFRoZSBudW1iZXIgYmVpbmcgcHVsbGVkIHRocm91Z2ggdGhpcyBmdW5jdGlvbiBkaXJlY3RseSBjb3JyZXNwb25kcyB0byB0aGUgY2hvaWNlIHZhbHVlIGRlZmluZWQgZm9yIGVhY2ggcmFkaW8gYnV0dG9uIGluIHRoZSBncm91cCBvZiByYWRpbyBvZiByYWRpbyBidXR0b25zLgogICAgICBUaGlzIGlzIHdoeSBpdCBpcyBjcnVjaWFsIHRvIGRlZmluZSBjaG9pY2UgdmFsdWVzIGFjY29yZGluZyB0byB0aGUgc2FtZSBbbmFtaW5nIGNvbnZlbnRpb24gZm9yIHJhZGlvIGJ1dHRvbnNdKGFkb2JlLmh0bWwjbmFtaW5nY29udmVudGlvbnJhZGlvYnV0dG9ucykKICAgLSBFYWNoIGB2YXIgdlhgIHNob3VsZCByZWZsZWN0IGEgdHJpYWwgb24gdGhlIGZvcm0uCiAgIFRodXMsIGlmIHRoZXJlIGFyZSAxNSB0ZXN0IHRyaWFscywgdGhlcmUgc2hvdWxkIGJlIDE1IGxpbmVzIG9mIGNvZGUgZnJvbSBgdmFyIHYxYCB0byBgdmFyIHYxNWAgd2l0aCB0aGUgbmFtZSBmb3IgZWFjaCBncm91cCBvZiByYWRpbyBidXR0b25zIGlucHV0ZWQgaW4gYGdldEZpZWxkKCIiKWAgZm9yIGVhY2ggdmFyaWFibGUKCjIuIERlZmluaW5nIHRoZSBTZWxlY3RlZCBWYWx1ZXMKCiAgIGBgYAogICBpZiAodjEgPT0gWCkgeyAKICAgdG90YWwgPSAxOwogICB9IGVsc2UgewogICB0b3RhbCA9IDA7CiAgIH0KCiAgIGlmICh2MiA9PSBYKSB7CiAgIHRvdGFsMiA9IDE7CiAgIH0gZWxzZSB7CiAgIHRvdGFsMiA9IDA7CiAgIH0KCiAgIGlmICh2MyA9PSBYKSB7CiAgIHRvdGFsMyA9IDE7CiAgIH0gZWxzZSB7CiAgIHRvdGFsMyA9IDA7CiAgIH0KCiAgIGlmICh2NCA9PSBYKSB7CiAgIHRvdGFsNCA9IDE7CiAgIH0gZWxzZSB7CiAgIHRvdGFsNCA9IDA7CiAgIH0KICAgYGBgCiAgIC0gVGhpcyBwb3J0aW9uIG9mIGNvZGUgdXRpbGl6ZXMgaWYvZWxzZSBzdGF0ZW1lbnRzIGluIG9yZGVyIHRvIGNyZWF0ZSB0aGUgdG90YWwgdmFsdWUgZm9yIGVhY2ggZmllbGQKICAgLSBJbiBgdjEgPT0gWGAgYW5kIGVhY2ggc3Vic2VxdWVudCBgdiA9PSBYYCwgdGhlIGBYYCBzaG91bGQgYmUgcmVwbGFjZWQgd2l0aCB0aGUgKipjaG9pY2UgdmFsdWUqKiBvZiB0aGUgcmFkaW8gYnV0dG9uIGZyb20gdGhlIGdyb3VwIG9mIHJhZGlvIGJ1dHRvbnMgdGhhdCBjb3JyZXNwb25kcyB0byB0aGUgZGVzaXJlZCBmaWVsZCB5b3UgYXJlIGNhbGN1bGF0aW5nCiAgICAgIC0gRm9yIGV4YW1wbGUsIGlmIGEgdG90YWwgY29ycmVjdCBmaWVsZCBpcyBiZWluZyBjYWxjdWxhdGVkLCB0aGUgY29kZSBzaG91bGQgcmVhZDoKCiAgICAgICAgIGBgYAogICAgICAgICBpZiAodjEgPT0gMikgeyAKICAgICAgICAgdG90YWwgPSAxOwogICAgICAgICB9IGVsc2UgewogICAgICAgICB0b3RhbCA9IDA7CiAgICAgICAgIH0KCiAgICAgICAgIGlmICh2MiA9PSAyKSB7CiAgICAgICAgIHRvdGFsMiA9IDE7CiAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgIHRvdGFsMiA9IDA7CiAgICAgICAgIH0KICAgICAgICAgYGBgCgogICAgICAtIEJlY2F1c2UgYSB0b3RhbCBjb3JyZWN0IGZpZWxkIGlzIGJlaW5nIGNhbGN1bGF0ZWQsIHRoZSBjaG9pY2UgdmFsdWUgb2YgMiBzaG91bGQgYmUgaW5wdXRlZCBhcyB0aGlzIGlzIHRoZSBjaG9pY2UgdmFsdWUgd2hpY2ggY29ycmVzcG9uZHMgdG8gIkNvcnJlY3QiIChzZWUgW25hbWluZyBjb252ZW50aW9uIGZvciByYWRpbyBidXR0b25zXShhZG9iZS5odG1sI25hbWluZ2NvbnZlbnRpb25yYWRpb2J1dHRvbnMpKQogICAgICAtIFRoZSB2YWx1ZSBvZiAyIHdvdWxkIGJlIGlucHV0ZWQgZm9yIGVhY2ggaWYvZWxzZSBzdGF0ZW1lbnQgZm9yIGVhY2ggdmFyaWFibGUuCiAgICAgIFRodXMsIGlmIHRoZXJlIHdlcmUgMTUgdmFyaWFibGVzLCB0aGVyZSBzaG91bGQgYmUgMTUgaWYvZWxzZSBzdGF0ZW1lbnRzIGB2MSA9PSAyYCB0byBgdjE1ID09IDJgCiAgIC0gVGhlIGlmL2Vsc2Ugc3RhdGVtZW50IGZvciBlYWNoIHZhcmlhYmxlIGRlZmluZXMgdGhhdCBpZiB0aGUgdmFsdWUgcHVsbGVkIGJ5IHRoZSBgZ2V0RmllbGQoKWAgZnVuY3Rpb24gbWF0Y2hlcyB0aGUgaW5wdXR0ZWQgY2hvaWNlIHZhbHVlIGZvciB0aGUgdmFyaWFibGUgdGhlbiB0aGUgdG90YWwgZm9yIHRoYXQgdmFyaWFibGUgYmVjb21lcyBlcXVhbCB0byAxLgogICBJZiBpdCBkb2VzIG5vdCBtYXRjaCwgdGhlIHRoZSB0b3RhbCBiZWNvbWVzIGVxdWFsIHRvIDAuCgozLiBEZWZpbmluZyB0aGUgVG90YWwKCmBgYApldmVudC52YWx1ZSA9IHRvdGFsICsgdG90YWwyICsgdG90YWwzICsgdG90YWw0CmBgYAoKLSBUaGlzIHBvcnRpb24gb2YgY29kZSBkZWZpbmVzIHRoZSBjYWxjdWxhdGlvbiB0byB0YWtlIHBsYWNlIGluIHRoZSBmaWVsZAogICAtIFRoZSBgZXZlbnQudmFsdWVgIGRldGVybWluZXMgd2hhdCBhcHBlYXJzIGluIHRoZSB0ZXh0IGJveAotIFRoaXMgbGluZSBvZiBjb2RlIGFkZHMgdG9nZXRoZXIgdGhlIHRvdGFscyBkZWZpbmVkIGluIHRoZSBpZi9lbHNlIHN0YXRlbWVudHMuClRoaXMgcHJvZHVjZXMgdGhlIGZpbmFsIGNhbGN1bGF0ZWQgdmFsdWUgZm9yIHRoZSBmaWVsZC4KLSBUaGUgbnVtYmVyIG9mIHRvdGFscyBhZGRlZCB0b2dldGhlciBzaG91bGQgY29ycmVzcG9uZCB0byB0aGUgbnVtYmVyIG9mIHZhcmlhYmxlcy4KVGh1cywgaWYgdGhlcmUgYXJlIDE1IHRyaWFscywgdGhlbiB0aGUgZmluYWwgbGluZSBvZiBjb2RlIHNob3VsZCByZWFkOgogICBgYGAKICAgZXZlbnQudmFsdWUgPSB0b3RhbCArIHRvdGFsMiArIHRvdGFsMyArIHRvdGFsNCArIHRvdGFsNSArIHRvdGFsNiArIHRvdGFsNyArIHRvdGFsOCArIHRvdGFsOSArIHRvdGFsMTAgKyB0b3RhbDExICsgdG90YWwxMiArIHRvdGFsMTMgKyB0b3RhbDE0ICsgdG90YWwxNQogICBgYGAKClRoZSBmb2xsb3dpbmcgaXMgYW4gZXhhbXBsZSBzY3JpcHQgZm9yIGEgY2FsY3VsYXRlZCAidG90YWxfY29ycmVjdF90ZXN0X3RyaWFscyIgZmllbGQsIGNhbGN1bGF0ZWQgZnJvbSAxNSB0cmlhbHM6CgpgYGAKdmFyIHYxID0gZ2V0RmllbGQoInRlc3RfdHJpYWxzXzEiKS52YWx1ZQp2YXIgdjIgPSBnZXRGaWVsZCgidGVzdF90cmlhbHNfMiIpLnZhbHVlCnZhciB2MyA9IGdldEZpZWxkKCJ0ZXN0X3RyaWFsc18zIikudmFsdWUKdmFyIHY0ID0gZ2V0RmllbGQoInRlc3RfdHJpYWxzXzQiKS52YWx1ZQp2YXIgdjUgPSBnZXRGaWVsZCgidGVzdF90cmlhbHNfNSIpLnZhbHVlCnZhciB2NiA9IGdldEZpZWxkKCJ0ZXN0X3RyaWFsc182IikudmFsdWUKdmFyIHY3ID0gZ2V0RmllbGQoInRlc3RfdHJpYWxzXzciKS52YWx1ZQp2YXIgdjggPSBnZXRGaWVsZCgidGVzdF90cmlhbHNfOCIpLnZhbHVlCnZhciB2OSA9IGdldEZpZWxkKCJ0ZXN0X3RyaWFsc185IikudmFsdWUKdmFyIHYxMCA9IGdldEZpZWxkKCJ0ZXN0X3RyaWFsc18xMCIpLnZhbHVlCnZhciB2MTEgPSBnZXRGaWVsZCgidGVzdF90cmlhbHNfMTEiKS52YWx1ZQp2YXIgdjEyID0gZ2V0RmllbGQoInRlc3RfdHJpYWxzXzEyIikudmFsdWUKdmFyIHYxMyA9IGdldEZpZWxkKCJ0ZXN0X3RyaWFsc18xMyIpLnZhbHVlCnZhciB2MTQgPSBnZXRGaWVsZCgidGVzdF90cmlhbHNfMTQiKS52YWx1ZQp2YXIgdjE1ID0gZ2V0RmllbGQoInRlc3RfdHJpYWxzXzE1IikudmFsdWUKCgppZiAodjEgPT0gMikgewogIHRvdGFsID0gMTsKfSBlbHNlIHsKICB0b3RhbCA9IDA7Cn0KCmlmICh2MiA9PSAyKSB7CiAgdG90YWwyID0gMTsKfSBlbHNlIHsKICB0b3RhbDIgPSAwOwp9CgppZiAodjMgPT0gMikgewogIHRvdGFsMyA9IDE7Cn0gZWxzZSB7CiAgdG90YWwzID0gMDsKfQoKaWYgKHY0ID09IDIpIHsKICB0b3RhbDQgPSAxOwp9IGVsc2UgewogIHRvdGFsNCA9IDA7Cn0KCmlmICh2NSA9PSAyKSB7CiAgdG90YWw1ID0gMTsKfSBlbHNlIHsKICB0b3RhbDUgPSAwOwp9CgppZiAodjYgPT0gMikgewogIHRvdGFsNiA9IDE7Cn0gZWxzZSB7CiAgdG90YWw2ID0gMDsKfQoKaWYgKHY3ID09IDIpIHsKICB0b3RhbDcgPSAxOwp9IGVsc2UgewogIHRvdGFsNyA9IDA7Cn0KCmlmICh2OCA9PSAyKSB7CiAgdG90YWw4ID0gMTsKfSBlbHNlIHsKICB0b3RhbDggPSAwOwp9CgppZiAodjkgPT0gMikgewogIHRvdGFsOSA9IDE7Cn0gZWxzZSB7CiAgdG90YWw5ID0gMDsKfQoKaWYgKHYxMCA9PSAyKSB7CiAgdG90YWwxMCA9IDE7Cn0gZWxzZSB7CiAgdG90YWwxMCA9IDA7Cn0KCmlmICh2MTEgPT0gMikgewogIHRvdGFsMTEgPSAxOwp9IGVsc2UgewogIHRvdGFsMTEgPSAwOwp9CgppZiAodjEyID09IDIpIHsKICB0b3RhbDEyID0gMTsKfSBlbHNlIHsKICB0b3RhbDEyID0gMDsKfQoKaWYgKHYxMyA9PSAyKSB7CiAgdG90YWwxMyA9IDE7Cn0gZWxzZSB7CiAgdG90YWwxMyA9IDA7Cn0KCmlmICh2MTQgPT0gMikgewogIHRvdGFsMTQgPSAxOwp9IGVsc2UgewogIHRvdGFsMTQgPSAwOwp9CgppZiAodjE1ID09IDIpIHsKICB0b3RhbDE1ID0gMTsKfSBlbHNlIHsKICB0b3RhbDE1ID0gMDsKfQoKZXZlbnQudmFsdWUgPSB0b3RhbCArIHRvdGFsMiArIHRvdGFsMyArIHRvdGFsNCArIHRvdGFsNSArIHRvdGFsNiArIHRvdGFsNyArIHRvdGFsOCArIHRvdGFsOSArIHRvdGFsMTAgKyB0b3RhbDExICsgdG90YWwxMiArIHRvdGFsMTMgKyB0b3RhbDE0ICsgdG90YWwxNQpgYGAKCiMjIENyZWF0aW5nIENhbGN1bGF0ZWQgRmllbGRzIHdpdGggQ29uZGl0aW9uYWwgRm9ybWF0dGluZwoKRm9yIGNhc2VzIHdoZXJlIGEgY2FsY3VsYXRlZCB0b3RhbCBjYW4gY2hhbmdlIGZyb20gYSBtYW51YWxseS1pbnB1dCB2YXJpYWJsZSwgYW4gYWx0ZXJlZCBzY3JpcHQgbXVzdCBiZSB1c2VkLgo8YnI+CgpGb3IgZXhhbXBsZSwgYSBjYWxjdWxhdGVkIGZpZWxkIGNhbiBiZSBjcmVhdGVkIGZvciB0aGUgdG90YWwgbnVtYmVyIG9mIGNvcnJlY3QgcmVzcG9uc2VzIGEgcGFydGljaXBhbnQgZ2l2ZXMgdG8gYSBzdGltdWx1cy4KSWYgd2hhdCBxdWFsaWZpZXMgYXMgYSAiY29ycmVjdCIgcmVzcG9uc2UgZGVwZW5kcyBvbiBhIHZhcmlhYmxlIHRoYXQgY2FuIGJlIG1hbnVhbGx5IGNoYW5nZWQsIHRoZSBvcmlnaW5hbCBjYWxjdWxhdGlvbiBzY3JpcHQgd2lsbCByZXN1bHQgaW4gYW4gaW5hY2N1cmF0ZSB0b3RhbC4KPGJyPgoKVGh1cywgdGhlIGFsdGVyZWQgc2NyaXB0ZWQgbXVzdCBzaG93IHRoYXQgdGhlIHZhbHVlIG9mIHRoZSBjYWxjdWxhdGVkIHRvdGFsIGlzIGNvbmRpdGlvbmFsIG9uIGFub3RoZXIgdmFyaWFibGUuClRoZSB2YWx1ZSBvZiBgVmFyaWFibGUgWGAgaXMgZGVwZW5kZW50IG9uIHRoZSB2YWx1ZSBvZiBgVmFyaWFibGUgWWAuClRoaXMgY2FuIGJlIGFjY29tcGxpc2hlZCB0aHJvdWdoIHRoZSB1c2FnZSBvZiBpZi9lbHNlIGNvbW1hbmRzIGluIEphdmFTY3JpcHQuCjxicj4KClByb3ZpZGVkIGJlbG93IGlzIGFuIGV4YW1wbGUgb2YgYSBjYWxjdWxhdGlvbiBzY3JpcHQgd2l0aCBjb25kaXRpb25hbCBmb3JtYXR0aW5nOgo8YnI+CgpgYGAKdmFyIHYxPSBnZXRGaWVsZCgidmFyaWFibGVfWF9ncm91cF9uYW1lIikudmFsdWUKdmFyIHYyPSBnZXRGaWVsZCgidmFyaWFibGVfWF9ncm91cF9uYW1lMiIpLnZhbHVlCnZhciB2Mz0gZ2V0RmllbGQoInZhcmlhYmxlX1hfZ3JvdXBfbmFtZTMiKS52YWx1ZQp2YXIgdjQ9IGdldEZpZWxkKCJ2YXJpYWJsZV9YX2dyb3VwX25hbWU0IikudmFsdWUKdmFyIHY1PSBnZXRGaWVsZCgidmFyaWFibGVfWF9ncm91cF9uYW1lNSIpLnZhbHVlCnZhciB2Nj0gZ2V0RmllbGQoInZhcmlhYmxlX1hfZ3JvdXBfbmFtZTYiKS52YWx1ZQp2YXIgdjc9IGdldEZpZWxkKCJ2YXJpYWJsZV9YX2dyb3VwX25hbWU3IikudmFsdWUKdmFyIHY4PSBnZXRGaWVsZCgidmFyaWFibGVfWF9ncm91cF9uYW1lOCIpLnZhbHVlCnZhciB2OT0gZ2V0RmllbGQoInZhcmlhYmxlX1hfZ3JvdXBfbmFtZTkiKS52YWx1ZQp2YXIgdjEwPSBnZXRGaWVsZCgidmFyaWFibGVfWF9ncm91cF9uYW1lMTAiKS52YWx1ZQp2YXIgdjExPSBnZXRGaWVsZCgidmFyaWFibGVfWF9ncm91cF9uYW1lMTEiKS52YWx1ZQp2YXIgdjEyPSBnZXRGaWVsZCgidmFyaWFibGVfWF9ncm91cF9uYW1lMTIiKS52YWx1ZQp2YXIgdjEzPSBnZXRGaWVsZCgidmFyaWFibGVfWF9ncm91cF9uYW1lMTMiKS52YWx1ZQp2YXIgdjE0PSBnZXRGaWVsZCgidmFyaWFibGVfWF9ncm91cF9uYW1lMTQiKS52YWx1ZQp2YXIgdjE1PSBnZXRGaWVsZCgidmFyaWFibGVfWF9ncm91cF9uYW1lMTUiKS52YWx1ZQp2YXIgdjE2PSBnZXRGaWVsZCgidmFyaWFibGVfWF9ncm91cF9uYW1lMTYiKS52YWx1ZQoKCnZhciB2MTc9IGdldEZpZWxkKCJ2YXJpYWJsZV9ZX2dyb3VwX25hbWUiKS52YWx1ZQp2YXIgdjE4PSBnZXRGaWVsZCgidmFyaWFibGVfWV9ncm91cF9uYW1lMiIpLnZhbHVlCnZhciB2MTk9IGdldEZpZWxkKCJ2YXJpYWJsZV9ZX2dyb3VwX25hbWUzIikudmFsdWUKdmFyIHYyMD0gZ2V0RmllbGQoInZhcmlhYmxlX1lfZ3JvdXBfbmFtZTQiKS52YWx1ZQp2YXIgdjIxPSBnZXRGaWVsZCgidmFyaWFibGVfWV9ncm91cF9uYW1lNSIpLnZhbHVlCnZhciB2MjI9IGdldEZpZWxkKCJ2YXJpYWJsZV9ZX2dyb3VwX25hbWU2IikudmFsdWUKdmFyIHYyMz0gZ2V0RmllbGQoInZhcmlhYmxlX1lfZ3JvdXBfbmFtZTciKS52YWx1ZQp2YXIgdjI0PSBnZXRGaWVsZCgidmFyaWFibGVfWV9ncm91cF9uYW1lOCIpLnZhbHVlCnZhciB2MjU9IGdldEZpZWxkKCJ2YXJpYWJsZV9ZX2dyb3VwX25hbWU5IikudmFsdWUKdmFyIHYyNj0gZ2V0RmllbGQoInZhcmlhYmxlX1lfZ3JvdXBfbmFtZTEwIikudmFsdWUKdmFyIHYyNz0gZ2V0RmllbGQoInZhcmlhYmxlX1lfZ3JvdXBfbmFtZTExIikudmFsdWUKdmFyIHYyOD0gZ2V0RmllbGQoInZhcmlhYmxlX1lfZ3JvdXBfbmFtZTEyIikudmFsdWUKdmFyIHYyOT0gZ2V0RmllbGQoInZhcmlhYmxlX1lfZ3JvdXBfbmFtZTEzIikudmFsdWUKdmFyIHYzMD0gZ2V0RmllbGQoInZhcmlhYmxlX1lfZ3JvdXBfbmFtZTE0IikudmFsdWUKdmFyIHYzMT0gZ2V0RmllbGQoInZhcmlhYmxlX1lfZ3JvdXBfbmFtZTE1IikudmFsdWUKdmFyIHYzMj0gZ2V0RmllbGQoInZhcmlhYmxlX1lfZ3JvdXBfbmFtZTE2IikudmFsdWUKCmlmKHYxNyA9PSBZMSl7CglpZiAodjEgPT0gWDIpewogICAgCQl0b3RhbD0xCgl9ZWxzZXsKICAgIAkJdG90YWw9MAoJfQp9ZWxzZXsKCWlmICh2MSA9PSBYMSl7CiAgICAJCXRvdGFsPTEKCX1lbHNlewogICAgCQl0b3RhbD0wCgl9Cn0KCmlmKHYxOCA9PSBZMil7CglpZiAodjIgPT0gWDEpewogICAgCQl0b3RhbDI9MQoJfWVsc2V7CiAgICAJCXRvdGFsMj0wCgl9Cn1lbHNlewoJaWYgKHYyID09IFgyKXsKICAgIAkJdG90YWwyPTEKCX1lbHNlewogICAgCQl0b3RhbDI9MAoJfQp9CgppZih2MTkgPT0gWTIpewoJaWYgKHYzID09IFgxKXsKICAgIAkJdG90YWwzPTEKCX1lbHNlewogICAgCQl0b3RhbDM9MAoJfQp9ZWxzZXsKCWlmICh2MyA9PSBYMil7CiAgICAJCXRvdGFsMz0xCgl9ZWxzZXsKICAgIAkJdG90YWwzPTAKCX0KfQoKaWYodjIwID09IFkxKXsKCWlmICh2NCA9PSBYMil7CiAgICAJCXRvdGFsND0xCgl9ZWxzZXsKICAgIAkJdG90YWw0PTAKCX0KfWVsc2V7CglpZiAodjQgPT0gWDEpewogICAgCQl0b3RhbDQ9MQoJfWVsc2V7CiAgICAJCXRvdGFsND0wCgl9Cn0KCmlmKHYyMSA9PSBZMil7CglpZiAodjUgPT0gWDEpewogICAgCQl0b3RhbDU9MQoJfWVsc2V7CiAgICAJCXRvdGFsNT0wCgl9Cn1lbHNlewoKCWlmICh2NSA9PSBYMil7CiAgICAJCXRvdGFsNT0xCgl9ZWxzZXsKICAgIAkJdG90YWw1PTAKCX0KfQoKaWYodjIyID09IFkyKXsKCWlmICh2NiA9PSBYMSl7CiAgICAJCXRvdGFsNj0xCgl9ZWxzZXsKICAgIAkJdG90YWw2PTAKCX0KfWVsc2V7CglpZiAodjYgPT0gWDIpewogICAgCQl0b3RhbDY9MQoJfWVsc2V7CiAgICAJCXRvdGFsNj0wCgl9Cn0KCmlmKHYyMyA9PSBZMSl7CglpZiAodjcgPT0gWDIpewogICAJCSB0b3RhbDc9MQoJfWVsc2V7CiAgICAJCXRvdGFsNz0wCgl9Cn1lbHNlewoJaWYgKHY3ID09IFgxKXsKICAgCQkgdG90YWw3PTEKCX1lbHNlewogICAgCQl0b3RhbDc9MAoJfQp9CgppZih2MjQgPT0gWTEpewoJaWYgKHY4ID09IFgyKXsKICAgIAkJdG90YWw4PTEKCX1lbHNlewogICAJCSB0b3RhbDg9MAoJfQp9ZWxzZXsKCWlmICh2OCA9PSBYMSl7CiAgICAJCXRvdGFsOD0xCgl9ZWxzZXsKICAgCQkgdG90YWw4PTAKCX0KfQoKaWYodjI1ID09IFkxKXsKCWlmICh2OSA9PSBYMil7CiAgIAkJIHRvdGFsOT0xCgl9ZWxzZXsKICAgIAkJdG90YWw5PTAKCX0KfWVsc2V7CglpZiAodjkgPT0gWDEpewogICAJCSB0b3RhbDk9MQoJfWVsc2V7CiAgICAJCXRvdGFsOT0wCgl9Cn0KCmlmKHYyNiA9PSBZMil7CglpZiAodjEwID09IFgxKXsKICAgIAkJdG90YWwxMD0xCgl9ZWxzZXsKICAgIAkJdG90YWwxMD0wCgl9Cn1lbHNlewoJaWYgKHYxMCA9PSBYMil7CiAgICAJCXRvdGFsMTA9MQoJfWVsc2V7CiAgICAJCXRvdGFsMTA9MAoJfQp9CgppZih2MjcgPT0gWTEpewoJaWYgKHYxMSA9PSBYMil7CiAgICAJCXRvdGFsMTE9MQoJfWVsc2V7CiAgICAJCXRvdGFsMTE9MAoJfQp9ZWxzZXsKCWlmICh2MTEgPT0gWDEpewogICAgCQl0b3RhbDExPTEKCX1lbHNlewogICAgCQl0b3RhbDExPTAKCX0KfQoKaWYodjI4ID09IFkyKXsKCWlmICh2MTIgPT0gWDEpewogICAgCQl0b3RhbDEyPTEKCX1lbHNlewogICAJCSB0b3RhbDEyPTAKCX0KfWVsc2V7CglpZiAodjEyID09IFgyKXsKICAgIAkJdG90YWwxMj0xCgl9ZWxzZXsKICAgCQkgdG90YWwxMj0wCgl9Cn0KCmlmKHYyOSA9PSBZMil7CglpZiAodjEzID09IFgxKXsKICAgIAkJdG90YWwxMz0xCgl9ZWxzZXsKICAgIAkJdG90YWwxMz0wCgl9Cn1lbHNlewoJaWYgKHYxMyA9PSBYMil7CiAgICAJCXRvdGFsMTM9MQoJfWVsc2V7CiAgICAJCXRvdGFsMTM9MAoJfQp9CgppZih2MzAgPT0gWTEpewoJaWYgKHYxNCA9PSBYMil7CiAgICAJCXRvdGFsMTQ9MQoJfWVsc2V7CgkJdG90YWwxND0wCgl9Cn1lbHNlewoJaWYgKHYxNCA9PSBYMSl7CgkJdG90YWwxND0xCgl9ZWxzZXsKICAgIAkJdG90YWwxND0wCgl9Cn0KCmlmKHYzMSA9PSBZMSl7CglpZiAodjE1ID09IFgyKXsKICAgIAkJdG90YWwxNT0xCgl9ZWxzZXsKICAgIAkJdG90YWwxNT0wCgl9Cn1lbHNlewoJaWYgKHYxNSA9PSBYMSl7CiAgICAJCXRvdGFsMTU9MQoJfWVsc2V7CiAgICAJCXRvdGFsMTU9MAoJfQp9CgppZih2MzIgPT0gWTIpewoJaWYgKHYxNiA9PSBYMSl7CiAgICAJCXRvdGFsMTY9MQoJfWVsc2V7CiAgICAJCXRvdGFsMTY9MAoJfQp9ZWxzZXsKCWlmICh2MTYgPT0gWDIpewogICAgCQl0b3RhbDE2PTEKCX1lbHNlewogICAgCQl0b3RhbDE2PTAKCX0KfQoKCmV2ZW50LnZhbHVlPXRvdGFsK3RvdGFsMit0b3RhbDMrdG90YWw0K3RvdGFsNSt0b3RhbDYrdG90YWw3K3RvdGFsOCt0b3RhbDkrdG90YWwxMCt0b3RhbDExK3RvdGFsMTIrdG90YWwxMyt0b3RhbDE0K3RvdGFsMTUrdG90YWwxNgpgYGAKPGJyPgoKIyMgQnJlYWtpbmcgRG93biB0aGUgQ29uZGl0aW9uYWwgRm9ybWF0dGluZyBDYWxjdWxhdGlvbiBTY3JpcHQKCk5vdGljZSB0aGUgW3RyYWRpdGlvbmFsIGNhbGN1bGF0aW9uIHNjcmlwdF0oYWRvYmUuaHRtbCNicmVha2luZ2Rvd25zY3JpcHQpIGlzIHByZXNlbnQgd2l0aGluIHRoaXMgc2NyaXB0LgpIb3dldmVyLCBhZGRpdGlvbmFsIGlmL2Vsc2UgY29tbWFuZHMgYXJlIGltcGxlbWVudGVkIGluIG9yZGVyIHRvIGFjY291bnQgZm9yIHRoZSBkZXBlbmRlbmNlIG9uIGFub3RoZXIgdmFyaWFibGUuCkJlZm9yZSBwcm9jZWVkaW5nIHdpdGggdGhpcyBzZWN0aW9uLCBhbiB1bmRlcnN0YW5kaW5nIG9mIHRoZSBbdHJhZGl0aW9uYWwgY2FsY3VsYXRpb24gc2NyaXB0XShhZG9iZS5odG1sI2JyZWFraW5nZG93bnNjcmlwdCkgc2hvdWxkIGJlIG9idGFpbmVkLgpJbiB0aGUgZm9sbG93aW5nIHNlY3Rpb24sIFZhcmlhYmxlIFggcmVmZXJzIHRvIHRoZSB2YXJpYWJsZSB3aGljaCBpcyBjb250aW5nZW50IG9uIHRoZSB2YWx1ZSBvZiBhbm90aGVyIHZhcmlhYmxlLCBWYXJpYWJsZSBZLgpUaHVzLCB0aGUgY29uZGl0aW9uYWwgZm9ybWF0dGluZyBpcyBkZXNjcmliZWQgaW4gc3VjaCBhIHdheSB0aGF0IHRoZSB2YWx1ZSBvZiBhIFZhcmlhYmxlIFggaXMgZGVwZW5kZW50IG9uIHRoZSB2YWx1ZSBvZiBWYXJpYWJsZSBZLgo8YnI+CgpUaGUgY29uZGl0aW9uYWwgZm9ybWF0dGluZyBjYWxjdWxhdGlvbiBzY3JpcHQgZmVhdHVyZXMgdHdvIG1ham9yIGFsdGVyYXRpb25zOgoKMS4gRGVmaW5pbmcgdGhlIEFkZGl0aW9uYWwgVmFyaWFibGUKCiAgIGBgYAogICB2YXIgdjE3PSBnZXRGaWVsZCgidmFyaWFibGVfWV9ncm91cF9uYW1lIikudmFsdWUKICAgdmFyIHYxOD0gZ2V0RmllbGQoInZhcmlhYmxlX1lfZ3JvdXBfbmFtZTIiKS52YWx1ZQogICB2YXIgdjE5PSBnZXRGaWVsZCgidmFyaWFibGVfWV9ncm91cF9uYW1lMyIpLnZhbHVlCiAgIHZhciB2MjA9IGdldEZpZWxkKCJ2YXJpYWJsZV9ZX2dyb3VwX25hbWU0IikudmFsdWUKICAgdmFyIHYyMT0gZ2V0RmllbGQoInZhcmlhYmxlX1lfZ3JvdXBfbmFtZTUiKS52YWx1ZQogICB2YXIgdjIyPSBnZXRGaWVsZCgidmFyaWFibGVfWV9ncm91cF9uYW1lNiIpLnZhbHVlCiAgIHZhciB2MjM9IGdldEZpZWxkKCJ2YXJpYWJsZV9ZX2dyb3VwX25hbWU3IikudmFsdWUKICAgdmFyIHYyND0gZ2V0RmllbGQoInZhcmlhYmxlX1lfZ3JvdXBfbmFtZTgiKS52YWx1ZQogICB2YXIgdjI1PSBnZXRGaWVsZCgidmFyaWFibGVfWV9ncm91cF9uYW1lOSIpLnZhbHVlCiAgIHZhciB2MjY9IGdldEZpZWxkKCJ2YXJpYWJsZV9ZX2dyb3VwX25hbWUxMCIpLnZhbHVlCiAgIHZhciB2Mjc9IGdldEZpZWxkKCJ2YXJpYWJsZV9ZX2dyb3VwX25hbWUxMSIpLnZhbHVlCiAgIHZhciB2Mjg9IGdldEZpZWxkKCJ2YXJpYWJsZV9ZX2dyb3VwX25hbWUxMiIpLnZhbHVlCiAgIHZhciB2Mjk9IGdldEZpZWxkKCJ2YXJpYWJsZV9ZX2dyb3VwX25hbWUxMyIpLnZhbHVlCiAgIHZhciB2MzA9IGdldEZpZWxkKCJ2YXJpYWJsZV9ZX2dyb3VwX25hbWUxNCIpLnZhbHVlCiAgIHZhciB2MzE9IGdldEZpZWxkKCJ2YXJpYWJsZV9ZX2dyb3VwX25hbWUxNSIpLnZhbHVlCiAgIHZhciB2MzI9IGdldEZpZWxkKCJ2YXJpYWJsZV9ZX2dyb3VwX25hbWUxNiIpLnZhbHVlCiAgIGBgYAogICAKICAgLSBUaGlzIGFkZGl0aW9uIHRvIHRoZSBzY3JpcHQgaXMgbmVjZXNzYXJ5IGluIG9yZGVyIHRvIGFjY29tb2RhdGUgZm9yIHRoZSBhZGRpdGlvbmFsIFZhcmlhYmxlIFkgYnkgd2hpY2ggdGhlIGNhbGN1bGF0ZWQgdG90YWwgaXMgY29udGluZ2VudAogICAtIEFuIGFkZGl0aW9uYWwgMTYgdmFyaWFibGVzIG11c3QgYmUgYWRkZWQsIG9uZSBmb3IgZWFjaCBvZiB0aGUgMTYgZ3JvdXBzIG9mIFZhcmlhYmxlIFggKHYxLXYxNikuCiAgIEVhY2ggb2YgdGhlc2UgbmV3IGB2YXJgIGNvbW1hbmRzIGNvcnJlc3BvbmRzIHRvIG9uZSBvZiB0aGUgb3JpZ2luYWwgMTYgYHZhcmAgY29tbWFuZHMgZm9yIFZhcmlhYmxlIFggYW5kIHB1bGxzIGVhY2ggdHJpYWwncyB2YWx1ZSBmb3IgVmFyaWFibGUgWSB1cG9uIHdoaWNoIHRoZSB0b3RhbCBpcyBkZXBlbmRlbnQuCiAgIC0gVGh1cyBmb3IgYSBmb3JtIHdpdGggMTYgdGVzdCB0cmlhbHMsIHRoZXJlIHNob3VsZCBiZSAzMiB0b3RhbCBsaW5lcyBvZiBjb2RlOiAxNiB3aGljaCBjb3JyZXNwb25kIHRvIHRoZSBvcmlnaW5hbCAxNiBncm91cHMgb2YgcmFkaW8gYnV0dG9ucyBmb3IgVmFyaWFibGUgWCB3aGljaCByZWZsZWN0IGEgcmVzcG9uc2UgZm9yIGVhY2ggdHJpYWwsIGFuZCBhbiBhZGRpdGlvbmFsIDE2IHdoaWNoIGNvcnJlc3BvbmQgdG8gdGhlIG1hbnVhbGx5IGlucHV0IHJlc3BvbnNlIGZvciBWYXJpYWJsZSBZIHVwb24gd2hpY2ggdGhlIGNhbGN1bGF0ZWQgdG90YWwgaXMgY29uZGl0aW9uYWwKCjEuIENyZWF0aW5nIHRoZSBDb25kaXRpb25hbCBGb3JtYXR0aW5nIHVzaW5nIElmL0Vsc2UgQ29tbWFuZHMKCiAgIGBgYAogICBpZih2MTcgPT0gWTEpewoJICAgaWYgKHYxID09IFgyKXsKICAgIAkJICAgdG90YWw9MQoJICAgfWVsc2V7CiAgICAJCSAgIHRvdGFsPTAKCSAgIH0KICAgfWVsc2V7CgkgICBpZiAodjEgPT0gWDEpewogICAgCQkgICB0b3RhbD0xCgkgICB9ZWxzZXsKICAgIAkJICAgdG90YWw9MAoJICAgfQogICB9CgogICBpZih2MTggPT0gWTIpewoJICAgaWYgKHYyID09IFgxKXsKICAgIAkJICAgdG90YWwyPTEKCSAgIH1lbHNlewogICAgCQkgICB0b3RhbDI9MAoJICAgfQogICB9ZWxzZXsKCSAgIGlmICh2MiA9PSBYMil7CiAgICAJCSAgIHRvdGFsMj0xCgkgICB9ZWxzZXsKICAgIAkJICAgdG90YWwyPTAKCSAgIH0KICAgfQogICAuLi4KICAgYGBgCgogICAtIFRoaXMgYWx0ZXJhdGlvbiB0byB0aGUgc2NyaXB0IHV0aWxpemVzIGlmL2Vsc2UgY29tbWFuZHMgdG8gZXN0YWJsaXNoIGNvbnRpbmdlbmN5IG9uIFZhcmlhYmxlIFkKICAgLSBBcyBvdXRsaW5lZCBpbiB0aGUgW0JyZWFraW5nIERvd24gdGhlIENhbGN1bGF0aW9uIFNjcmlwdF0oYWRvYmUuaHRtbCNicmVha2luZ2Rvd25zY3JpcHQpIHNlY3Rpb24sIHRoZSBpZi9lbHNlIHN0YXRlbWVudHMgb3BlcmF0ZSBpbiB0aGUgc2FtZSBtYW5uZXIgYW5kIGZvbGxvdyB0aGUgc2FtZSBwcm9jZWR1cmVzLgogICBIb3dldmVyLCBub3RpY2UgYW4gYWRkaXRpb25hbCBpZi9lbHNlIHN0YXRlbWVudCBpcyBwcmVzZW50IGZvciBlYWNoIHRyaWFsIGFuZCBzdXJyb3VuZHMgdGhlIG9yaWdpbmFsIGlmL2Vsc2Ugc3RhdGVtZW50OgogICAKICAgICAgYGBgCiAgICAgIGlmKHYxNyA9PSBZMSl7ICAgICAgIDwtLS0tLS0tLS0tLS0gU1RBUlQgT0YgT1ZFUkFSQ0hJTkcgSUYgU1RBVEVNRU5UCgkgICAgICBpZiAodjEgPT0gWDIpeyAgICAgIyBPcmlnaW5hbCBpZi9lbHNlIHN0YXRlbWVudAogICAgCQkgICAgICB0b3RhbD0xCgkgICAgICB9ZWxzZXsKICAgIAkJICAgICAgdG90YWw9MAoJICAgICAgfQogICAgICB9ZWxzZXsgICAgICAgICAgICAgICA8LS0tLS0tLS0tLS0tIFNUQVJUIE9GIE9WRVJBUkNISU5HIEVMU0UgU1RBVEVNRU5UCgkgICAgICBpZiAodjEgPT0gWDEpeyAgICAgIyBTZWNvbmQgb3JpZ2luYWwgaWYvZWxzZSBzdGF0ZW1lbnQKICAgIAkJICAgICAgdG90YWw9MQoJICAgICAgfWVsc2V7CiAgICAJCSAgICAgIHRvdGFsPTAKCSAgICAgIH0KICAgICAgfSAgICAgICAgICAgICAgICAgICAgPC0tLS0tLS0tLS0tLSBFTkQgT0YgT1ZFUkFSQ0hJTkcgSUYvRUxTRSBTVEFURU1FTlQKICAgICAgCiAgICAgIGBgYAoKICAgLSBUaGUgb3ZlcmFyY2hpbmcgaWYvZWxzZSBzdGF0ZW1lbnQgaXMgY2VudGVyZWQgYXJvdW5kIHRoZSB2YXJpYWJsZSB3aGljaCBkZWZpbmVzIHRoZSBjb25kaXRpb25hbCBmb3JtYXR0aW5nLCBWYXJpYWJsZSBZLCB0aHVzIHRoZSBgaWYodiA9PSBZKXtgIHNob3VsZCBvbmx5IHJlZmVyZW5jZSBgdmFyIHYxN2AgdG8gYHZhciB2MzJgCiAgIC0gV2l0aGluIHRoZSBvdmVyYXJjaGluZyBpZi9lbHNlIHN0YXRlbWVudCwgYFkxYCBhbmQgYFkyYCByZXByZXNlbnQgdGhlICoqY2hvaWNlIHZhbHVlKiogb2YgdGhlIGZpZWxkIGJlaW5nIHB1bGxlZCBmcm9tIGZvciBWYXJpYWJsZSBZCiAgIAogICAgICAtIEZvciB0aGUgb3JpZ2luYWwgaWYvZWxzZSBzdGF0ZW1lbnRzIHdpdGhpbiB0aGUgb3ZlcmFyY2hpbmcgaWYvZWxzZSBzdGF0ZW1lbnQsIGBYMWAgYW5kIGBYMmAgc3RpbGwgcmVmbGVjdCB0aGUgZGVzaXJlZCAqKmNob2ljZSB2YWx1ZSoqIG9mIHRoZSByYWRpbyBidXR0b24gZnJvbSB0aGUgZ3JvdXAgb2YgcmFkaW8gYnV0dG9ucyB0aGF0IGNvcnJlc3BvbmQgdG8gdGhlIGRlc2lyZWQgZmllbGQgeW91IGFyZSBjYWxjdWxhdGluZyBmb3IgVmFyaWFibGUgWAoKICAgLSBUaGUgY29uZGl0aW9uYWwgZm9ybWF0dGluZyBlbWVyZ2VzIGZyb20gZGVmaW5pbmcgdGhlIGBZYCBpbiBgaWYodiA9PSBZKXtgIGFzIGBZMWAgb3IgYFkyYAogICAgICAKICAgICAgLSBOb3RpY2UsIHRoZXJlIGFyZSB0d28gaWYvZWxzZSBzdGF0ZW1lbnRzIHdpdGhpbiB0aGUgb3ZlcmFyY2hpbmcgaWYvZWxzZSBzdGF0ZW1lbnQuCiAgICAgIEVhY2ggb2YgdGhlc2Ugc2Vjb25kYXJ5IGlmL2Vsc2Ugc3RhdGVtZW50cyBkZWZpbmUgYSBkaWZmZXJlbnQgb3V0Y29tZSAtIGluIHRoaXMgaW5zdGFuY2UsIHRoZSBvdXRjb21lcyBhcmUgImlmIGB2MSA9PSBYMmAgdGhlbiBgdG90YWwgPSAxYCIgYW5kICJpZiBgdjEgPT0gWDFgIHRoZW4gYHRvdGFsID0gMWAiCiAgICAgIFdoaWNoIG91dGNvbWUgaXMgc2VsZWN0ZWQgaXMgZGVwZW5kZW50IG9uIHRoZSBkZWZpbml0aW9uIG9mIGBZYCBpbiBgaWYodiA9PSBZKXtgLgogICAgICAtIFRodXMsIGZvciB0aGUgZXhhbXBsZSBzY3JpcHQgYWJvdmUsIGlmIGB2MTcgPT0gWTFgLCB0aGVuIHRoZSBmaXJzdCBvdXRjb21lIG9mICJpZiBgdjEgPT0gWDJgIHRoZW4gYHRvdGFsID0gMWAiIHdpbGwgYmUgdGhlIHJlc3VsdCwgYnV0IGlmIGB2MTdgIGVxdWFscyBhbnl0aGluZyBlbHNlIGJlc2lkZXMgYFkxYCwgdGhlbiB0aGUgc2Vjb25kIG91dGNvbWUgb2YgImlmIGB2MSA9PSBYMWAgdGhlbiBgdG90YWwgPSAxYCIgd2lsbCBiZSB0aGUgcmVzdWx0CiAgICAgIC0gVGhlIGZpbmFsIHJlc3VsdCBpcyBjb25kaXRpb25hbCBmb3JtYXR0aW5nIGFzIHRoZSBjYWxjdWxhdGVkIHRvdGFsIGZvciBlYWNoIHRyaWFsIG9mIFZhcmlhYmxlIFggaXMgdWx0aW1hdGVseSBkZXBlbmRlbnQgb24gdGhlIHZhbHVlIG9mIFZhcmlhYmxlIFkKICAgCgojIyBDb25kaXRpb25hbCBGb3JtYXR0aW5nIENhbGN1bGF0aW9uIFNjcmlwdDogQW4gRXhhbXBsZQoKTGlzdGVkIGJlbG93IGlzIGEgc3BlY2lmaWMgZXhhbXBsZSB3aGVyZSB0aGUgY29uZGl0aW9uYWwgZm9ybWF0dGluZyBjYWxjdWxhdGlvbiBzY3JpcHQgaXMgbmVjZXNzYXJ5Ogo8YnI+CgojIyMgVGhlIFNjZW5hcmlvCgpBIGNhbGN1bGF0ZWQgZmllbGQgZm9yIHRoZSB0b3RhbCBudW1iZXIgb2YgY29ycmVjdCByZXNwb25zZXMgb3V0IG9mIDE2IHRyaWFscyBpcyBuZWVkZWQuCjxicj4KCkZvciBlYWNoIHRyaWFsLCBhbiBleHBlcmltZW50ZXIgdGFwcyB0aGUgdGFibGUgZWl0aGVyIG9uZSB0aW1lIG9yIHR3byB0aW1lcy4KSW4gcmVzcG9uc2UgdG8gdGhlIGV4cGVyaW1lbnRlcidzIGFkbWluaXN0cmF0aW9uLCB0aGUgcGFydGljaXBhbnQgaXMgZXhwZWN0ZWQgdG8gdGFwIHRoZSB0YWJsZSB0aGUgb3Bwb3NpdGUgbnVtYmVyIG9mIHRpbWVzLgo8YnI+CgpJZiB0aGUgZXhwZXJpbWVudGVyIHRhcHMgdGhlIHRhYmxlIG9uY2UsIHRoZSBwYXJ0aWNpcGFudCBzaG91bGQgdGFwIHRoZSB0YWJsZSB0d2ljZTsgaWYgdGhlIGV4cGVyaW1lbnRlciB0YXBzIHRoZSB0YWJsZSB0d2ljZSwgdGhlIHBhcnRpY2lwYW50IHRhcHMgdGhlIHRhYmxlIG9uY2UuCkEgcmVzcG9uc2UgaXMgY29ycmVjdCBpZiB0aGUgcGFydGljcGFudCBzdWNjZXNzZnVsbHkgdGFwcyB0aGUgdGFibGUgdGhlIG9wcG9zaXRlIG51bWJlciBvZiB0aW1lcyBhcyB0aGUgZXhwZXJpbWVudGVyLgo8YnI+CgpUaHVzLCB0aGUgY29ycmVjdCByZXNwb25zZSBpcyBub3QgYWx3YXlzIG9uZSB0YXAgb3IgdHdvIHRhcHMuCkluc3RlYWQsIHdoZXRoZXIgdGhlIHJlc3BvbnNlIGlzIGNvcnJlY3QgaXMgY29udGluZ2VudCBvbiB0aGUgZXhwZXJpbWVudGVyJ3MgYWRtaW5pc3RyYXRpb24gYW5kIGhvdyBtYW55IHRpbWVzIHRoZSBleHBlcmltZW50ZXIgdGFwcyB0aGUgdGFibGUuCkFzIGEgcmVzdWx0LCBjb25kaXRpb25hbCBmb3JtYXR0aW5nIGlzIG5lY2Vzc2FyeSBpbiBvcmRlciB0byBjYWxjdWxhdGUgdGhlIHRvdGFsIG51bWJlciBvZiBjb3JyZWN0IHJlc3BvbnNlcyBhY3Jvc3MgdGhlIDE2IHRyaWFscy4KCiMjIyBUaGUgVmFyaWFibGVzCgotIGBWYXJpYWJsZSBYYCA9IHBhcnRpY2lwYW50J3MgcmVzcG9uc2VzICh0aGUgbnVtYmVyIG9mIHRpbWVzIHRoZSBwYXJ0aWNpcGFudCB0YXBzIHRoZSB0YWJsZSkKLSBgVmFyaWFibGUgWWAgPSBleHBlcmltZW50ZXIncyBhZG1pbmlzdHJhdGlvbiAodGhlIG51bWJlciBvZiB0aW1lcyB0aGUgZXhwZXJpbWVudGVyIHRhcHBlZCB0aGUgdGFibGUpCi0gYFgxYCA9IGNob2ljZSB2YWx1ZSBvZiByYWRpbyBidXR0b24gcmVmbGVjdGluZyB0aGUgYWN0aW9uIG9mIHRoZSBwYXJ0aWNpcGFudCB0YXBwaW5nIHRoZSB0YWJsZSBvbmNlIC0gaW4gdGhpcyBjYXNlLCAqKjEqKgotIGBYMmAgPSBjaG9pY2UgdmFsdWUgb2YgcmFkaW8gYnV0dG9uIHJlZmxlY3RpbmcgdGhlIGFjdGlvbiBvZiB0aGUgcGFydGljaXBhbnQgdGFwcGluZyB0aGUgdGFibGUgdHdpY2UgLSBpbiB0aGlzIGNhc2UsICoqMioqCi0gYFkxYCA9IGNob2ljZSB2YWx1ZSBvZiB0aGUgZmllbGQgcmVmbGVjdGluZyB0aGUgZXhwZXJpbWVudGVyIHRhcHBlZCB0aGUgdGFibGUgb25jZSAtIGluIHRoaXMgY2FzZSwgKioxKioKLSBgWTJgID0gY2hvaWNlIHZhbHVlIG9mIHRoZSBmaWVsZCByZWZsZWN0aW5nIHRoZSBleHBlcmltZW50ZXIgdGFwcGVkIHRoZSB0YWJsZSBvbmNlIC0gaW4gdGhpcyBjYXNlLCAqKjIqKgogCiMjIyBUaGUgU2NyaXB0CgpUaGUgY2FsY3VsYXRpb24gc2NyaXB0IGZvciB0aGUgYWJvdmUgc2NlbmFyaW8gY2FuIGJlIHdyaXR0ZW4gYXMgc3VjaDoKPGJyPgoKYGBgCnZhciB2MT0gZ2V0RmllbGQoInBhcnRpY2lwYW50X3Jlc3BvbnNlIikudmFsdWUKdmFyIHYyPSBnZXRGaWVsZCgicGFydGljaXBhbnRfcmVzcG9uc2UyIikudmFsdWUKdmFyIHYzPSBnZXRGaWVsZCgicGFydGljaXBhbnRfcmVzcG9uc2UzIikudmFsdWUKdmFyIHY0PSBnZXRGaWVsZCgicGFydGljaXBhbnRfcmVzcG9uc2U0IikudmFsdWUKdmFyIHY1PSBnZXRGaWVsZCgicGFydGljaXBhbnRfcmVzcG9uc2U1IikudmFsdWUKdmFyIHY2PSBnZXRGaWVsZCgicGFydGljaXBhbnRfcmVzcG9uc2U2IikudmFsdWUKdmFyIHY3PSBnZXRGaWVsZCgicGFydGljaXBhbnRfcmVzcG9uc2U3IikudmFsdWUKdmFyIHY4PSBnZXRGaWVsZCgicGFydGljaXBhbnRfcmVzcG9uc2U4IikudmFsdWUKdmFyIHY5PSBnZXRGaWVsZCgicGFydGljaXBhbnRfcmVzcG9uc2U5IikudmFsdWUKdmFyIHYxMD0gZ2V0RmllbGQoInBhcnRpY2lwYW50X3Jlc3BvbnNlMTAiKS52YWx1ZQp2YXIgdjExPSBnZXRGaWVsZCgicGFydGljaXBhbnRfcmVzcG9uc2UxMSIpLnZhbHVlCnZhciB2MTI9IGdldEZpZWxkKCJwYXJ0aWNpcGFudF9yZXNwb25zZTEyIikudmFsdWUKdmFyIHYxMz0gZ2V0RmllbGQoInBhcnRpY2lwYW50X3Jlc3BvbnNlMTMiKS52YWx1ZQp2YXIgdjE0PSBnZXRGaWVsZCgicGFydGljaXBhbnRfcmVzcG9uc2UxNCIpLnZhbHVlCnZhciB2MTU9IGdldEZpZWxkKCJwYXJ0aWNpcGFudF9yZXNwb25zZTE1IikudmFsdWUKdmFyIHYxNj0gZ2V0RmllbGQoInBhcnRpY2lwYW50X3Jlc3BvbnNlMTYiKS52YWx1ZQoKCnZhciB2MTc9IGdldEZpZWxkKCJleHBlcmltZW50ZXJfYWRtaW5pc3RyYXRpb24iKS52YWx1ZQp2YXIgdjE4PSBnZXRGaWVsZCgiZXhwZXJpbWVudGVyX2FkbWluaXN0cmF0aW9uMiIpLnZhbHVlCnZhciB2MTk9IGdldEZpZWxkKCJleHBlcmltZW50ZXJfYWRtaW5pc3RyYXRpb24zIikudmFsdWUKdmFyIHYyMD0gZ2V0RmllbGQoImV4cGVyaW1lbnRlcl9hZG1pbmlzdHJhdGlvbjQiKS52YWx1ZQp2YXIgdjIxPSBnZXRGaWVsZCgiZXhwZXJpbWVudGVyX2FkbWluaXN0cmF0aW9uNSIpLnZhbHVlCnZhciB2MjI9IGdldEZpZWxkKCJleHBlcmltZW50ZXJfYWRtaW5pc3RyYXRpb242IikudmFsdWUKdmFyIHYyMz0gZ2V0RmllbGQoImV4cGVyaW1lbnRlcl9hZG1pbmlzdHJhdGlvbjciKS52YWx1ZQp2YXIgdjI0PSBnZXRGaWVsZCgiZXhwZXJpbWVudGVyX2FkbWluaXN0cmF0aW9uOCIpLnZhbHVlCnZhciB2MjU9IGdldEZpZWxkKCJleHBlcmltZW50ZXJfYWRtaW5pc3RyYXRpb245IikudmFsdWUKdmFyIHYyNj0gZ2V0RmllbGQoImV4cGVyaW1lbnRlcl9hZG1pbmlzdHJhdGlvbjEwIikudmFsdWUKdmFyIHYyNz0gZ2V0RmllbGQoImV4cGVyaW1lbnRlcl9hZG1pbmlzdHJhdGlvbjExIikudmFsdWUKdmFyIHYyOD0gZ2V0RmllbGQoImV4cGVyaW1lbnRlcl9hZG1pbmlzdHJhdGlvbjEyIikudmFsdWUKdmFyIHYyOT0gZ2V0RmllbGQoImV4cGVyaW1lbnRlcl9hZG1pbmlzdHJhdGlvbjEzIikudmFsdWUKdmFyIHYzMD0gZ2V0RmllbGQoImV4cGVyaW1lbnRlcl9hZG1pbmlzdHJhdGlvbjE0IikudmFsdWUKdmFyIHYzMT0gZ2V0RmllbGQoImV4cGVyaW1lbnRlcl9hZG1pbmlzdHJhdGlvbjE1IikudmFsdWUKdmFyIHYzMj0gZ2V0RmllbGQoImV4cGVyaW1lbnRlcl9hZG1pbmlzdHJhdGlvbjE2IikudmFsdWUKCmlmKHYxNyA9PSAxKXsKCWlmICh2MSA9PSAyKXsKICAgIAkJdG90YWw9MQoJfWVsc2V7CiAgICAJCXRvdGFsPTAKCX0KfWVsc2V7CglpZiAodjEgPT0gMSl7CiAgICAJCXRvdGFsPTEKCX1lbHNlewogICAgCQl0b3RhbD0wCgl9Cn0KCmlmKHYxOCA9PSAyKXsKCWlmICh2MiA9PSAxKXsKICAgIAkJdG90YWwyPTEKCX1lbHNlewogICAgCQl0b3RhbDI9MAoJfQp9ZWxzZXsKCWlmICh2MiA9PSAyKXsKICAgIAkJdG90YWwyPTEKCX1lbHNlewogICAgCQl0b3RhbDI9MAoJfQp9CgppZih2MTkgPT0gMil7CglpZiAodjMgPT0gMSl7CiAgICAJCXRvdGFsMz0xCgl9ZWxzZXsKICAgIAkJdG90YWwzPTAKCX0KfWVsc2V7CglpZiAodjMgPT0gMil7CiAgICAJCXRvdGFsMz0xCgl9ZWxzZXsKICAgIAkJdG90YWwzPTAKCX0KfQoKaWYodjIwID09IDEpewoJaWYgKHY0ID09IDIpewogICAgCQl0b3RhbDQ9MQoJfWVsc2V7CiAgICAJCXRvdGFsND0wCgl9Cn1lbHNlewoJaWYgKHY0ID09IDEpewogICAgCQl0b3RhbDQ9MQoJfWVsc2V7CiAgICAJCXRvdGFsND0wCgl9Cn0KCmlmKHYyMSA9PSAyKXsKCWlmICh2NSA9PSAxKXsKICAgIAkJdG90YWw1PTEKCX1lbHNlewogICAgCQl0b3RhbDU9MAoJfQp9ZWxzZXsKCWlmICh2NSA9PSAyKXsKICAgIAkJdG90YWw1PTEKCX1lbHNlewogICAgCQl0b3RhbDU9MAoJfQp9CgppZih2MjIgPT0gMil7CglpZiAodjYgPT0gMSl7CiAgICAJCXRvdGFsNj0xCgl9ZWxzZXsKICAgIAkJdG90YWw2PTAKCX0KfWVsc2V7CglpZiAodjYgPT0gMil7CiAgICAJCXRvdGFsNj0xCgl9ZWxzZXsKICAgIAkJdG90YWw2PTAKCX0KfQoKaWYodjIzID09IDEpewoJaWYgKHY3ID09IDIpewogICAJCSB0b3RhbDc9MQoJfWVsc2V7CiAgICAJCXRvdGFsNz0wCgl9Cn1lbHNlewoJaWYgKHY3ID09IDEpewogICAJCSB0b3RhbDc9MQoJfWVsc2V7CiAgICAJCXRvdGFsNz0wCgl9Cn0KCmlmKHYyNCA9PSAxKXsKCWlmICh2OCA9PSAyKXsKICAgIAkJdG90YWw4PTEKCX1lbHNlewogICAJCSB0b3RhbDg9MAoJfQp9ZWxzZXsKCWlmICh2OCA9PSAxKXsKICAgIAkJdG90YWw4PTEKCX1lbHNlewogICAJCSB0b3RhbDg9MAoJfQp9CgppZih2MjUgPT0gMSl7CglpZiAodjkgPT0gMil7CiAgIAkJIHRvdGFsOT0xCgl9ZWxzZXsKICAgIAkJdG90YWw5PTAKCX0KfWVsc2V7CglpZiAodjkgPT0gMSl7CiAgIAkJIHRvdGFsOT0xCgl9ZWxzZXsKICAgIAkJdG90YWw5PTAKCX0KfQoKaWYodjI2ID09IDIpewoJaWYgKHYxMCA9PSAxKXsKICAgIAkJdG90YWwxMD0xCgl9ZWxzZXsKICAgIAkJdG90YWwxMD0wCgl9Cn1lbHNlewoJaWYgKHYxMCA9PSAyKXsKICAgIAkJdG90YWwxMD0xCgl9ZWxzZXsKICAgIAkJdG90YWwxMD0wCgl9Cn0KCmlmKHYyNyA9PSAxKXsKCWlmICh2MTEgPT0gMil7CiAgICAJCXRvdGFsMTE9MQoJfWVsc2V7CiAgICAJCXRvdGFsMTE9MAoJfQp9ZWxzZXsKCWlmICh2MTEgPT0gMSl7CiAgICAJCXRvdGFsMTE9MQoJfWVsc2V7CiAgICAJCXRvdGFsMTE9MAoJfQp9CgppZih2MjggPT0gMil7CglpZiAodjEyID09IDEpewogICAgCQl0b3RhbDEyPTEKCX1lbHNlewogICAJCSB0b3RhbDEyPTAKCX0KfWVsc2V7CglpZiAodjEyID09IDIpewogICAgCQl0b3RhbDEyPTEKCX1lbHNlewogICAJCSB0b3RhbDEyPTAKCX0KfQoKaWYodjI5ID09IDIpewoJaWYgKHYxMyA9PSAxKXsKICAgIAkJdG90YWwxMz0xCgl9ZWxzZXsKICAgIAkJdG90YWwxMz0wCgl9Cn1lbHNlewoJaWYgKHYxMyA9PSAyKXsKICAgIAkJdG90YWwxMz0xCgl9ZWxzZXsKICAgIAkJdG90YWwxMz0wCgl9Cn0KCmlmKHYzMCA9PSAxKXsKCWlmICh2MTQgPT0gMil7CiAgICAJCXRvdGFsMTQ9MQoJfWVsc2V7CgkJdG90YWwxND0wCgl9Cn1lbHNlewoJaWYgKHYxNCA9PSAxKXsKCQl0b3RhbDE0PTEKCX1lbHNlewogICAgCQl0b3RhbDE0PTAKCX0KfQoKaWYodjMxID09IDEpewoJaWYgKHYxNSA9PSAyKXsKICAgIAkJdG90YWwxNT0xCgl9ZWxzZXsKICAgIAkJdG90YWwxNT0wCgl9Cn1lbHNlewoJaWYgKHYxNSA9PSAxKXsKICAgIAkJdG90YWwxNT0xCgl9ZWxzZXsKICAgIAkJdG90YWwxNT0wCgl9Cn0KCmlmKHYzMiA9PSAyKXsKCWlmICh2MTYgPT0gMSl7CiAgICAJCXRvdGFsMTY9MQoJfWVsc2V7CiAgICAJCXRvdGFsMTY9MAoJfQp9ZWxzZXsKCWlmICh2MTYgPT0gMil7CiAgICAJCXRvdGFsMTY9MQoJfWVsc2V7CiAgICAJCXRvdGFsMTY9MAoJfQp9CgoKZXZlbnQudmFsdWU9dG90YWwrdG90YWwyK3RvdGFsMyt0b3RhbDQrdG90YWw1K3RvdGFsNit0b3RhbDcrdG90YWw4K3RvdGFsOSt0b3RhbDEwK3RvdGFsMTErdG90YWwxMit0b3RhbDEzK3RvdGFsMTQrdG90YWwxNSt0b3RhbDE2CmBgYAoKIyMgVGltZSBDYWxjdWxhdGlvbnMgaW4gQWRvYmUgeyN0aW1lY2FsY3VsYXRpb25zfQoKQ2FsY3VsYXRpbmcgYSB0aW1lIGJhc2VkIG9uIHR3byBvdGhlciB0aW1lcyBjYW4gYmUgYWNjb21wbGlzaGVkIHdpdGhpbiBBZG9iZS4KVG8gZG8gdGhpcywgY3VzdG9tIGNhbGN1bGF0aW9uIHNjcmlwdHMgdXNpbmcgdGhlIGxhbmd1YWdlIEphdmFTY3JpcHQgbXVzdCBiZSBpbXBsZW1lbnRlZC4KCiMjIyBDcmVhdGluZyBUaW1lIENhbGN1bGF0aW9ucyBpbiBBZG9iZQoKMS4gRmlyc3QsIGVuc3VyZSBhbGwgZmllbGRzIGZyb20gd2hpY2ggdGhlIHRpbWUgY2FsY3VsYXRpb25zIGFyZSB0byBiZSBtYWRlIGZyb20gb3IgYXBwbGllZCB0byBoYXZlIGJlZW4gZm9ybWF0dGVkIGludG8gdGhlIGRlc2lyZWQgdGltZSBmb3JtYXQuClRvIGRvIHRoaXM6CiAgIDEuIFJpZ2h0IGNsaWNrIG9uIHRoZSBmaWVsZCBhbmQgc2VsZWN0ICJQcm9wZXJ0aWVzIgogICAxLiBOYXZpZ2F0ZSB0byB0aGUgIkZvcm1hdCIgdGFiCiAgIDEuIEZvciAiU2VsZWN0IGZvcm1hdCBjYXRlZ29yeToiIHNlbGVjdCBgVGltZWAKICAgMS4gSW4gdGhlICJUaW1lIE9wdGlvbnMiIGludGVyZmFjZSB0aGF0IGFwcGVhcnMsIHNlbGVjdCB0aGUgZGVzaXJlZCB0aW1lIGZvcm1hdAogICAxLiBSZXBlYXQgdGhpcyBmb3IgZXZlcnkgZmllbGQgdGhhdCB0aGUgdGltZSBjYWxjdWxhdGlvbnMgd2lsbCBiZSBtYWRlIGZyb20gb3IgYXBwbGllZCB0bwogICAxLiBUaGUgZm9sbG93aW5nIGNhbGN1bGF0aW9uIHNjcmlwdCBjYWxjdWxhdGVzIHRpbWUgaW4gdGhlIGBISDpNTTpzc2AgZm9ybWF0CjEuIFNlbGVjdCB0aGUgZmllbGQgaW4gd2hpY2ggdGhlIHRpbWUgY2FsY3VsYXRpb24gd2lsbCBvY2N1cgoxLiBSaWdodCBjbGljayBvbiB0aGUgZmllbGQgYW5kIHNlbGVjdCAiUHJvcGVydGllcyIKMS4gU2VsZWN0IHRoZSAiQ2FsY3VsYXRlIiB0YWIKMS4gU2VsZWN0IHRoZSAiQ3VzdG9tIGNhbGN1bGF0aW9uIHNjcmlwdDoiIHJhZGlvIGJ1dHRvbgoxLiBTZWxlY3QgIkVkaXQuLi4iIGFuZCBpbnB1dCB0aGUgZGVzaXJlZCB0aW1lIGNhbGN1bGF0aW9uIHNjcmlwdAoKVGhlIGZvbGxvd2luZyBzY3JpcHQgZGV0YWlscyBob3cgdG8gY2FsY3VsYXRlIFggc2Vjb25kIGludGVydmFscyBiYXNlZCBvbiBhbiBpbnB1dHRlZCBzdGFydGluZyB0aW1lLgpUaGUgdGltZXMgd2l0aGluIHRoaXMgc2NyaXB0IGZvbGxvdyB0aGUgYEhIOk1NOnNzYCB0aW1lIGZvcm1hdC4KVGhlIGZvbGxvd2luZyBzY3JpcHQgY2FuIGVhc2lseSBiZSBtb2RpZmllZCB0byBjYWxjdWxhdGUgZGlmZmVyZW50IGxlbmd0aCBpbnRlcnZhbHMgb3IgdG8gdXNlIGRpZmZlcmVudCB0aW1lIGZvcm1hdHMuCgpgYGAKdmFyIHRpbWVzdGFydGVkID0gdGhpcy5nZXRGaWVsZCgic3RhcnRfdGltZV9maWVsZCIpLnZhbHVlQXNTdHJpbmc7Cgp2YXIgdGltZVNwbGl0ID0gdGltZXN0YXJ0ZWQuc3BsaXQoIjoiKSA7Cgp2YXIgdG90YWxTZWMgPSAoKHRpbWVTcGxpdFswXSozNjAwKSArICh0aW1lU3BsaXRbMV0qNjApICsgKHRpbWVTcGxpdFsyXSoxKSk7Cgp2YXIgbmV3dG90YWxTZWMgPSAoKHRpbWVTcGxpdFswXSozNjAwKSArICh0aW1lU3BsaXRbMV0qNjApICsgKHRpbWVTcGxpdFsyXSoxKSArICJJTlRFUlZBTCBMRU5HVEggWCIpOwoKaG91cnMgPSBNYXRoLmZsb29yKG5ld3RvdGFsU2VjLzM2MDApOwoKbWludXRlcyA9IE1hdGguZmxvb3IoKG5ld3RvdGFsU2VjICUgMzYwMCkvNjApOwoKc2Vjb25kcyA9IG5ld3RvdGFsU2VjICUgNjA7Cgp0aW1lT3V0cHV0ID0gaG91cnMgKyAiOiIgKyBtaW51dGVzICsgIjoiICsgc2Vjb25kczsKCmV2ZW50LnZhbHVlID0gdGltZU91dHB1dApgYGAKCiAgICogUHJvY2VlZCB0byBCcmVha2luZyBEb3duIHRoZSBUaW1lIENhbGN1bGF0aW9uIFNjcmlwdCB0byBnYWluIGEgZ3JlYXRlciB1bmRlcnN0YW5kaW5nIG9mIHRoZSBzY3JpcHQKCiMjIyBCcmVha2luZyBEb3duIHRoZSBUaW1lIENhbGN1bGF0aW9uIFNjcmlwdAoKYGBgCnZhciB0aW1lc3RhcnRlZCA9IHRoaXMuZ2V0RmllbGQoInN0YXJ0X3RpbWVfZmllbGQiKS52YWx1ZUFzU3RyaW5nOwoKdmFyIHRpbWVTcGxpdCA9IHRpbWVzdGFydGVkLnNwbGl0KCI6IikgOwoKdmFyIHRvdGFsU2VjID0gKCh0aW1lU3BsaXRbMF0qMzYwMCkgKyAodGltZVNwbGl0WzFdKjYwKSArICh0aW1lU3BsaXRbMl0qMSkpOwoKdmFyIG5ld3RvdGFsU2VjID0gKCh0aW1lU3BsaXRbMF0qMzYwMCkgKyAodGltZVNwbGl0WzFdKjYwKSArICh0aW1lU3BsaXRbMl0qMSkgKyAiSU5URVJWQUwgTEVOR1RIIFgiKTsKCmhvdXJzID0gTWF0aC5mbG9vcihuZXd0b3RhbFNlYy8zNjAwKTsKCm1pbnV0ZXMgPSBNYXRoLmZsb29yKChuZXd0b3RhbFNlYyAlIDM2MDApLzYwKTsKCnNlY29uZHMgPSBuZXd0b3RhbFNlYyAlIDYwOwoKdGltZU91dHB1dCA9IGhvdXJzICsgIjoiICsgbWludXRlcyArICI6IiArIHNlY29uZHM7CgpldmVudC52YWx1ZSA9IHRpbWVPdXRwdXQKYGBgCgpUaGUgdGltZSBjYWxjdWxhdGlvbiBzY3JpcHQgY2FuIGJlIGJyb2tlbiBkb3duIGludG8gdGhyZWUgcGFydHM6CgoxLiBEZWZpbmluZyB0aGUgU3RhcnQgVGltZQoKYGBgCnZhciB0aW1lc3RhcnRlZCA9IHRoaXMuZ2V0RmllbGQoInN0YXJ0X3RpbWVfZmllbGQiKS52YWx1ZUFzU3RyaW5nOwoKdmFyIHRpbWVTcGxpdCA9IHRpbWVzdGFydGVkLnNwbGl0KCI6IikgOwoKdmFyIHRvdGFsU2VjID0gKCh0aW1lU3BsaXRbMF0qMzYwMCkgKyAodGltZVNwbGl0WzFdKjYwKSArICh0aW1lU3BsaXRbMl0qMSkpOwpgYGAKCiAgICogVGhpcyBwb3J0aW9uIG9mIHRoZSBzY3JpcHQgZGVmaW5lcyB0aGUgaW5pdGlhbCB0aW1lIGZyb20gd2hpY2ggdGhlIHRpbWUgY2FsY3VsYXRpb24gaXMgdG8gYmUgZG9uZQogICAqIFRoZSBsaW5lIGB2YXIgdGltZXN0YXJ0ZWQgPSB0aGlzLmdldEZpZWxkKCJzdGFydF90aW1lX2ZpZWxkIikudmFsdWVBc1N0cmluZztgIGltcG9ydHMgdGhlIGRlc2lyZWQgc3RhcnQgdGltZSBmcm9tIHRoZSB2YXJpYWJsZSBgc3RhcnRfdGltZV9maWVsZGAuCiAgIFRoaXMgaW1wb3J0ZWQgdGltZSBzaG91bGQgYmUgaW4gdGhlIGBISDpNTTpzc2AgdGltZSBmb3JtYXQKICAgKiBUaGUgbGluZSBgdmFyIHRpbWVTcGxpdCA9IHRpbWVzdGFydGVkLnNwbGl0KCI6IikgO2AgdGhlbiByZW1vdmVzIHRoZSBjb2xvbnMgZnJvbSB0aGlzIGltcG9ydGVkIHRpbWUsIGxlYXZpbmcgdGhlIHRpbWUgYXMgYEhIIE1NIHNzYC4KICAgVGhpcyBpcyBzdG9yZWQgYXMgYSBuZXcgdmFyaWFibGUsIGB0aW1lc3BsaXRgCiAgICogRmluYWxseSwgdGhlIGxpbmUgYHZhciB0b3RhbFNlYyA9ICgodGltZVNwbGl0WzBdKjM2MDApICsgKHRpbWVTcGxpdFsxXSo2MCkgKyAodGltZVNwbGl0WzJdKjEpKTtgIGNvbnZlcnRzIHRoaXMgaW1wb3J0ZWQgdGltZSB0byBiZSBhbGwgaW4gKnNlY29uZHMqLgogICBBdCB0aGlzIHBvaW50IGluIHRoZSBzY3JpcHQsIHRoZSBpbXBvcnRlZCBzdGFydCB0aW1lIGhhcyBub3cgYmVlbiBjb252ZXJ0ZWQgdG8gYSB0b3RhbCB0aW1lIGluIHNlY29uZHMKICAgICAgKiBUaGUgZm9sbG93aW5nIG9wZXJhdG9ycyBhcmUgdXNlZCBpbiB0aGlzIGxpbmUgb2YgY29kZTogYFswXWAsIGBbMV1gLCBhbmQgYFsyXWAKICAgICAgKiBgWzBdYCByZXRyaXZlcyB0aGUgZmlyc3QgcG9ydGlvbiBvZiB0aGUgdmFyaWFibGUgYHRpbWVzcGxpdGAKICAgICAgICAgKiBUaHVzLCBgdGltZVNwbGl0WzBdYCByZXR1cm5zIHRoZSB2YWx1ZSBvZiBgSEhgIGZyb20gdGhlIHZhcmlhYmxlIG9mIGB0aW1lc3BsaXRgCiAgICAgICAgICogTXVsdGlwbHlpbmcgdGhpcyB2YWx1ZSBvZiBob3VycyBieSAzNjAwIGluIHR1cm4gY29udmVydHMgdGhlIGhvdXJzIHRvIHNlY29uZHMKICAgICAgKiBgWzFdYCByZXRyaWV2ZXMgdGhlIHNlY29uZCBwb3J0aW9uIG9mIHRoZSB2YXJpYWJsZSBgdGltZXNwbGl0YAogICAgICAgICAqIFRodXMsIGB0aW1lU3BsaXRbMV1gIHJldHVybnMgdGhlIHZhbHVlIG9mIGBNTWAgZnJvbSB0aGUgdmFyaWFibGUgb2YgYHRpbWVzcGxpdGAKICAgICAgICAgKiBNdWx0aXBseWluZyB0aGlzIHZhbHVlIG9mIG1pbnV0ZXMgYnkgNjAgaW4gdHVybiBjb252ZXJ0cyB0aGUgbWludXRlcyB0byBzZWNvbmRzCiAgICAgICogYFsyXWAgcmV0cmlldmVzIHRoZSBzZWNvbmQgcG9ydGlvbiBvZiB0aGUgdmFyaWFibGUgYHRpbWVzcGxpdGAKICAgICAgICAgKiBUaHVzLCBgdGltZVNwbGl0WzJdYCByZXR1cm5zIHRoZSB2YWx1ZSBvZiBgc3NgIGZyb20gdGhlIHZhcmlhYmxlIG9mIGB0aW1lc3BsaXRgCiAgICAgICAgICogTXVsdGlwbHlpbmcgdGhpcyB2YWx1ZSBvZiBzZWNvbmRzIGJ5IDEgbGVhdmVzIHRoZSB0aW1lIGluIHNlY29uZHMKCjEuIERlZmluaW5nIHRoZSBOZXcgVGltZQoKYGBgCnZhciBuZXd0b3RhbFNlYyA9ICgodGltZVNwbGl0WzBdKjM2MDApICsgKHRpbWVTcGxpdFsxXSo2MCkgKyAodGltZVNwbGl0WzJdKjEpICsgIklOVEVSVkFMIExFTkdUSCBYIik7Cgpob3VycyA9IE1hdGguZmxvb3IobmV3dG90YWxTZWMvMzYwMCk7CgptaW51dGVzID0gTWF0aC5mbG9vcigobmV3dG90YWxTZWMgJSAzNjAwKS82MCk7CgpzZWNvbmRzID0gbmV3dG90YWxTZWMgJSA2MDsKYGBgCgogICAqIFRoaXMgcG9ydGlvbiBvZiB0aGUgc2NyaXB0IGRlZmluZXMgdGhlIG5ldyB0aW1lIHRvIGJlIGNhbGN1bGF0ZWQgZnJvbSB0aGUgc3RhcnQgdGltZQogICAqIFRoZSBsaW5lIGB2YXIgbmV3dG90YWxTZWMgPSAoKHRpbWVTcGxpdFswXSozNjAwKSArICh0aW1lU3BsaXRbMV0qNjApICsgKHRpbWVTcGxpdFsyXSoxKSArICJJTlRFUlZBTCBMRU5HVEggWCIpO2AgY2FsY3VsYXRlcyBhIG5ldyB0aW1lIGluIHNlY29uZHMgYnkgYWRkaW5nIFggYW1vdW50IG9mIHNlY29uZHMgdG8gdGhlIGluaXRpYWwgc3RhcnQgdGltZSBpbiBzZWNvbmRzCiAgICAgICogYCh0aW1lU3BsaXRbMF0qMzYwMCkgKyAodGltZVNwbGl0WzFdKjYwKSArICh0aW1lU3BsaXRbMl0qMSlgIGNvbnZlcnRzIHRoZSBpbml0aWFsIHN0YXJ0IHRpbWUgdG8gYmUgYSB0b3RhbCBvZiBzZWNvbmRzCiAgICAgICogYCsgIklOVEVSVkFMIExFTkdUSCBYImAgYWRkcyBYIGFtb3VudCBvZiBzZWNvbmRzIHRvIHRoaXMgc3RhcnQgdGltZSB0b3RhbCBvZiBzZWNvbmRzIHRvIHJlc3VsdCBpbiB0aGUgbmV3IGRlc2lyZWQgY2FsY3VsYXRlZCB0aW1lCiAgICAgICAgICogVGh1cywgaWYgdGhlIGRlc2lyZWQgY2FsY3VsYXRlZCB0aW1lIGlzIHRvIGJlIDI1IHNlY29uZHMgYWZ0ZXIgdGhlIHN0YXJ0IHRpbWUsIHRoZSBsaW5lIG9mIGNvZGUgc2hvdWxkIGxvb2sgbGlrZSB0aGUgZm9sbG93aW5nOgogICAgICAgICAgICAqIGB2YXIgbmV3dG90YWxTZWMgPSAoKHRpbWVTcGxpdFswXSozNjAwKSArICh0aW1lU3BsaXRbMV0qNjApICsgKHRpbWVTcGxpdFsyXSoxKSArIDI1KTtgCiAgICogVGhlIGxpbmVzIG9mIGNvZGUgZm9sbG93aW5nIHRoaXMgbGluZSBjb252ZXJ0IHRoaXMgbmV3IHRvdGFsIG9mIHRpbWUgb2Ygc2Vjb25kcyBpbnRvIGhvdXJzLCBtaW51dGVzLCBhbmQgc2Vjb25kcwogICAgICAqIGBob3VycyA9IE1hdGguZmxvb3IobmV3dG90YWxTZWMvMzYwMCk7YCBjb252ZXJ0cyB0aGUgbmV3IHRvdGFsIHN0YXJ0IHRpbWUgaW4gc2Vjb25kcyBpbnRvIGhvdXJzCiAgICAgICAgICogVGhlIGZ1bmN0aW9uIGBNYXRoLmZsb29yKClgIHJvdW5kcyB0aGUgbnVtYmVyIGluIGhvdXJzIGRvd24sIGxlYXZpbmcgb25seSB0aGUgbnVtYmVyIG9mIGhvdXJzIHdpdGggbm8gZGVjaW1hbCB2YWx1ZQogICAgICAgICAqIFRodXMsIGlmIHRoZSBuZXcgdG90YWwgdGltZSBvZiBzZW9vbmRzIGNvbnZlcnRzIGludG8gMi41NiBob3VycywgdGhlIGBNYXRoLmZsb29yKClgIHJldHVybnMgYSB2YWx1ZSBvZiAyIGhvdXJzCiAgICAgICogYG1pbnV0ZXMgPSBNYXRoLmZsb29yKChuZXd0b3RhbFNlYyAlIDM2MDApLzYwKTtgIGNvbnZlcnRzIHRoZSBuZXcgdG90YWwgc3RhcnQgdGltZSBvZiBzZWNvbmRzIGludG8gbWludXRlcwogICAgICAgICAqIFRoZSBvcGVyYXRvciBgJWAgaXMgdGhlIHJlbWFpbmRlciBvcGVyYXRvciBhbmQgcmV0dXJucyBvbmx5IHRoZSByZW1haW5kZXIgYWZ0ZXIgaW50ZWdlciBkaXZpc2lvbiBpcyBjb21wbGV0ZWQKICAgICAgICAgKiBUaHVzLCBgbmV3dG90YWxTZWMgJSAzNjAwYCByZXR1cm5zIG9ubHkgdGhlIHJlbWFpbmRlciBvZiBzZWNvbmRzIHRoYXQgZGlkIG5vdCBkaXZpZGUgd2hvbGx5IGludG8gaG91cnMuIERpdmlkaW5nIHRoaXMgdmFsdWUgYnkgNjAsIGxlYXZlcyB0aGUgcmVtYWluZGVyIGluIG1pbnV0ZXMuCiAgICAgICogYHNlY29uZHMgPSBuZXd0b3RhbFNlYyAlIDYwO2AgcmV0dXJucyB0aGUgcmVtYWluZGVyIG9mIHNlY29uZHMgdGhhdCBkaWQgbm90IGRpdmlkZSB3aG9sbHkgaW50byBob3VycyBvciBtaW51dGVzCiAgICAgICAgICogVGh1cywgdGhpcyBsZWF2ZXMgdGhlIG51bWJlciBvZiBzZWNvbmRzIHRvIGJlIGxlZnQgaW4gYEhIOk1NOnNzYCBmb3JtYXQKICAgICAgKiBBZnRlciB0aGVzZSB0aHJlZSBsaW5lcyBvZiBjb2RlLCB0aHJlZSBuZXcgdmFyaWFibGVzIGhhdmUgYmVlbiBjcmVhdGVkOiB0aGUgbnVtYmVyIG9mIGhvdXJzLCBtaW51dGVzLCBhbmQgc2Vjb25kcyBpbiB0aGUgbmV3IHRvdGFsIHN0YXJ0IHRpbWUgb2Ygc2Vjb25kcwoKMS4gRGVmaW5pbmcgdGhlIFRpbWUgT3V0cHV0CgpgYGAKdGltZU91dHB1dCA9IGhvdXJzICsgIjoiICsgbWludXRlcyArICI6IiArIHNlY29uZHM7CgpldmVudC52YWx1ZSA9IHRpbWVPdXRwdXQKYGBgCgogICAqIFRoaXMgcG9ydGlvbiBvZiB0aGUgc2NyaXB0IGRlZmluZXMgdGhlIGZpbmFsIHRpbWUgY2FsY3VsYXRlZCBpbiBgSEg6TU06c3NgIHRpbWUgZm9ybWF0CiAgICogVGhlIGxpbmUgYHRpbWVPdXRwdXQgPSBob3VycyArICI6IiArIG1pbnV0ZXMgKyAiOiIgKyBzZWNvbmRzO2AgZGVmaW5lcyBhIG5ldyB2YXJpYWJsZSBvZiB0aGUgbmV3IHRvdGFsIHRpbWUgaW4gYEhIOk1NOnNzYCB0aW1lIGZvcm1hdAogICAgICAqIFRoaXMgbGluZSB0YWtlcyB0aGUgcHJldmlvdXNseSBkZWZpbmVkIHZhcmlhYmxlcyBvZiBgaG91cnNgLCBgbWludXRlc2AsIGFuZCBgc2Vjb25kc2AgYW5kIGFkZHMgY29sb25zIGJldHdlZW4gdGhlbSB0byBnaXZlIHRoZSBuZXcgdG90YWwgY2FsY3VsYXRlZCB0aW1lIGluIGBISDpNTTpzc2AgdGltZSBmb3JtYXQKICAgKiBUaGUgbGluZSBgZXZlbnQudmFsdWUgPSB0aW1lT3V0cHV0YCB0aGVuIGRlZmluZXMgdGhlIG5ldyB0b3RhbCB0aW1lIGluIGBISDpNTTpzc2AgdG8gYmUgdGhlIG91dHB1dCB2YWx1ZSBvZiB0aGUgZmllbGQKClRoZSBmb2xsb3dpbmcgaXMgYW4gZXhhbXBsZSBzY3JpcHQgZm9yIGNyZWF0aW5nIGEgbmV3IGNhbGN1bGF0ZWQgdGltZSAxMCBzZWNvbmRzIGFmdGVyIHRoZSBzdGFydCB0aW1lOgoKYGBgCnZhciB0aW1lc3RhcnRlZCA9IHRoaXMuZ2V0RmllbGQoInRhc2tfc3RhcnRfdGltZSIpLnZhbHVlQXNTdHJpbmc7Cgp2YXIgdGltZVNwbGl0ID0gdGltZXN0YXJ0ZWQuc3BsaXQoIjoiKSA7Cgp2YXIgdG90YWxTZWMgPSAoKHRpbWVTcGxpdFswXSozNjAwKSArICh0aW1lU3BsaXRbMV0qNjApICsgKHRpbWVTcGxpdFsyXSoxKSk7Cgp2YXIgbmV3dG90YWxTZWMgPSAoKHRpbWVTcGxpdFswXSozNjAwKSArICh0aW1lU3BsaXRbMV0qNjApICsgKHRpbWVTcGxpdFsyXSoxKSArIDEwKTsKCmhvdXJzID0gTWF0aC5mbG9vcihuZXd0b3RhbFNlYy8zNjAwKTsKCm1pbnV0ZXMgPSBNYXRoLmZsb29yKChuZXd0b3RhbFNlYyAlIDM2MDApLzYwKTsKCnNlY29uZHMgPSBuZXd0b3RhbFNlYyAlIDYwOwoKdGltZU91dHB1dCA9IGhvdXJzICsgIjoiICsgbWludXRlcyArICI6IiArIHNlY29uZHM7CgpldmVudC52YWx1ZSA9IHRpbWVPdXRwdXQKYGBgCgoqTm90ZS4qIFdoZW4gY3JlYXRpbmcgbXVsdGlwbGUgdGltZSBjYWxjdWxhdGVkIGZpZWxkcywgZWFjaCBmaWVsZCBzaG91bGQgYmUgY2FsY3VsYXRlZCBvZmYgb2YgdGhlIGludGl0aWFsIHRpbWUuCkNhbGN1bGF0ZWQgdGltZSBmaWVsZHMgc2hvdWxkICoqKk5PVCoqKiBiZSBjYWxjdWxhdGVkIG9mZiBlYWNoIG90aGVyLgpGb3IgZXhhbXBsZSwgaWYgZml2ZSBjYWxjdWxhdGVkIHRpbWUgZmllbGRzIG11c3QgYmUgY3JlYXRlZCwgZWFjaCAxMCBzZWNvbmRzIGFwYXJ0IGZyb20gZWFjaCBvdGhlciwgb25lIHNob3VsZCAqKm5vdCoqIGNhbGN1bGF0ZSBlYWNoIHRpbWUgZmllbGQgMTAgc2Vjb25kcyBiYXNlZCBvZmYgdGhlIHByZXZpb3VzbHkgY2FsY3VsYXRlZCB0aW1lLgpJbnN0ZWFkLCBlYWNoIGZpZWxkIHNob3VsZCBiZSBjYWxjdWxhdGVkIGJhc2VkIG9mZiBvZiB0aGUgaW5pdGlhbCBzdGFydCB0aW1lLgpUaHVzLCB0aGUgZmlyc3QgY2FsY3VsYXRlZCBmaWVsZCBzaG91bGQgYWRkIDEwIHNlY29uZHMgdG8gdGhlIGluaXRpYWwgc3RhcnQgdGltZS4KVGhlIHNlY29uZCBjYWxjdWxhdGVkIGZpZWxkIHNob3VsZCBhZGQgMjAgc2Vjb25kcyAqYmFzZWQgb2ZmIHRoZSBpbml0aWFsIHN0YXJ0IHRpbWUqLgpUaGUgdGhpcmQgY2FsY3VsYXRlZCBmaWVsZCBzaG91bGQgYWRkIDMwIHNlY29uZHMgYmFzZWQgb2ZmIHRoZSBpbml0aWFsIHN0YXJ0IHRpbWUuCkFuZCBzbyBmb3J0aC4KVGhpcyBlbnN1cmVzIHRoYXQgbm8gZXJyb3JzIG9jY3VyIGZyb20gY2FsY3VsYXRpbmcgdGltZXMgYmFzZWQgb2ZmIHRpbWVzIGluIGZpZWxkcyB0aGF0IGFyZSBhbHJlYWR5IGJlaW5nIGNhbGN1bGF0ZWQuCgo8YnI+CgoqTm90ZS4qIFRpbWUgY2FsY3VsYXRlZCBmaWVsZHMgY2Fubm90IGJlIG92ZXJ3cml0dGVuLgpPbmUgY2Fubm90IG1hbnVhbGx5IG92ZXJ3cml0ZSB0aGUgY2FsY3VsYXRlZCB0aW1lIGluIGEgZmllbGQgd2l0aCBhbiBhbHRlcm5hdGl2ZSB0aW1lLgpUaGUgZmllbGQgd2lsbCBhbHdheXMgcmVhZCB0aGUgdGltZSBjYWxjdWxhdGVkIGFjY29yZGluZyB0byB0aGUgaW5wdXR0ZWQgc2NyaXB0LgpUaGlzIHNob3VsZCBiZSBrZXB0IGluIG1pbmQgd2hlbiBjcmVhdGluZyBtdWx0aXBsZSBmaWVsZCB0aGF0IGZlYXR1cmUgWCBzZWNvbmQgY29uc2VjdXRpdmUgaW50ZXJ2YWxzLgpJZiBhdCBhbnkgcG9pbnQgdGhlIGludGVydmFscyBzaG91bGQgYmUgaW50ZXJydXB0ZWQgYW5kIGEgbmV3IHRpbWUgbXVzdCBiZSBtYW51YWxseSBlbnRlcmVkLCBpdCBjYW5ub3QgYmUgZG9uZS4KQSBwb3RlbnRpYWwgbWVhbnMgdG8gd29yayBhcm91bmQgdGhpcyBpc3N1ZSBpcyBmb3VuZCBpbiB0aGUgVG9rZW4vQmVhZCBTb3J0IGV4YW1wbGUuCgojIyMgVGhlIFBlcmZlY3QgRXhhbXBsZTogVG9rZW4vQmVhZCBTb3J0CgpUaGUgVG9rZW4vQmVhZCBTb3J0IGNvZGluZyBmb3JtIHByb3ZpZGVzIGEgcGVyZmVjdCBleGFtcGxlIG9mIHRpbWUgY2FsY3VsYXRpb25zLCBhY3Rpb24gYnV0dG9ucywgYW5kIGhpZGRlbiBmaWVsZHMgYXQgcGxheS4KVG9rZW4vQmVhZCBTb3J0IGNvbnNpc3RzIG9mIDE4IHRlbiBzZWNvbmQgaW50ZXJ2YWxzLgpBbGwgb2YgdGhlc2UgaW50ZXJ2YWxzIG9jY3VyIGFmdGVyIGEgc3BlY2lmaWVkIHN0YXJ0IHRpbWUgYW5kIHNob3VsZCBhbHdheXMgYmUgMTAgc2Vjb25kcyBhcGFydC4KSG93ZXZlciwgaWYgYW4gaW50ZXJydXB0aW9uIHNob3VsZCBvY2N1ciBkdXJpbmcgdGhlIHRhc2ssIGEgbmV3IHN0YXJ0IHRpbWUgbXVzdCBiZSBlbnRlcmVkIGludG8gb25lIG9mIHRoZSBpbnRlcnZhbHMgZnJvbSB3aGljaCB0aGUgZm9sbG93aW5nIGludGVydmFscyBzaG91bGQgY2FsY3VsYXRlZCBmcm9tLgpEdWUgdG8gdGhlIHRpbWUgZmllbGRzIGJlaW5nIGNhbGN1bGF0ZWQsIHRoZSB0aW1lIHZhbHVlcyBjYW5ub3QgYmUgbWFudWFsbHkgb3ZlcndyaXR0ZW4uClRoZSBmb2xsb3dpbmcgc29sdXRpb24gaXMgaW1wbGVtZW50ZWQgdG8gd29yayBhcm91bmQgdGhpczoKCjEuIFRpbWUgY2FsY3VsYXRpb25zIGFyZSBtYWRlIGZvciBlYWNoIG9mIHRoZSBpbml0aWFsIDE4IGludGVydmFscwogICAqIEVhY2ggb2YgdGhlc2UgaW50ZXJ2YWxzIGNhbGN1bGF0ZSBmcm9tIHRoZSBpbnRpYWwgc3RhcnQgdGltZQogICAgICAqIFRodXMsIHRoZSBmaXJzdCBpbnRlcnZhbCBjYWxjdWxhdGVzIHRlbiBzZWNvbmRzIGZyb20gdGhlIGluaXRpYWwgc3RhcnQgdGltZSwgdGhlIHNlY29uZCBpbnRlcnZhbCAyMCBzZWNvbmRzIGZyb20gdGhlIHN0YXJ0IHRpbWUsIHRoZSB0aGlyZCBpbnRlcnZhbCAzMCBzZWNvbmRzIGZyb20gdGhlIHN0YXJ0IHRpbWUsIGV0Yy4KICAgKiBXaGVuIHRoZSBpbml0aWFsIHRpbWUgaXMgaW5wdXR0ZWQsIGVhY2ggb2YgdGhlc2UgaW50ZXJ2YWxzIGNhbGN1bGF0ZSBhdXRvbWF0aWNhbGx5CjEuIEEgc2Vjb25kIHNldCBvZiB0ZXh0IGZpZWxkcyBhcmUgbWFkZSBmb3IgZWFjaCBvZiB0aGVzZSAxOCBpbnRlcnZhbHMKICAgKiBUaGVzZSBmaWVsZHMgaGF2ZSBubyBjYWxjdWxhdGlvbnMgYXBwbGllZCB0byB0aGVtCiAgICogVGhlc2UgMTggZmllbGRzIGFyZSBzZXQgdG8gYmUgW2hpZGRlbl0oYWRvYmUuaHRtbCNoaWRkZW5maWVsZHMpIGZyb20gdXNlciB2aWV3CiAgICogVGhlc2UgMTggZmllbGRzIHNlcnZlIHRvIGFsbG93IGZvciBtYW51YWxseSBlbnRyeSBvZiBhIHRpbWUgaW4gY2FzZSBvZiBhbiBpbnRlcnJ1cHRpb24KICAgKiBUaGUgMTggZmllbGRzIGFyZSBwb3NpdGlvbmVkIG92ZXIgdGhlIGluaXRpYWwgMTggZmllbGRzIHdoaWNoIGRvIHRoZSBjb250YWluIHRoZSBjYWxjdWxhdGlvbnMKMS4gQSBzZXQgb2YgMTggYnV0dG9ucyBhcmUgY3JlYXRlZCwgb25lIGZvciBlYWNoIGludGVydmFsCiAgICogRWFjaCBidXR0b24gY29ycmVzcG9uZHMgdG8gYW4gaW50ZXJ2YWwgYW5kIGlzIGNvbmZpZ3VyZWQgd2l0aCBhY3Rpb25zIHRvIGhpZGUgdGhlIGNhbGN1bGF0ZWQgdGltZSBpbnRlcnZhbCBpdCBjb3JyZXNwb25kcyB0byBhbmQgc2hvdyB0aGUgc2Vjb25kIHRleHQgdGltZSBmaWVsZCB3aGljaCBhbGxvd3MgZm9yIG1hbnVhbCBlbnRyeSB0aGF0IGl0IGNvcnJlc3BvbmRzIHRvCiAgICogRWFjaCBvZiB0aGVzZSBidXR0b25zIHNlcnZlcyB0byBoaWRlIHRoZSBjYWxjdWxhdGVkIHRpbWUgZmllbGQgZm9yIHRoZSBpbnRlcnZhbCBpbiB3aGljaCB0aGUgaW50ZXJydXB0aW9uIG9jY3VycyBhbmQgYWxsIHRoZSBmb2xsb3dpbmcgaW50ZXJ2YWxzCiAgICogRWFjaCBidXR0b24gYWxzbyBzaG93cyB0aGUgc2Vjb25kIHRpbWUgdGV4dCBmaWVsZCB3aGljaCBhbGxvd3MgZm9yIG1hbnVhbCBlbnRyeSBhbmQgYWxzbyByZXZlYWxzIHRoZSBtYW51YWwgZW50cnkgZmllbGRzIGZvciBhbGwgdGhlIGZvbGxvd2luZyBpbnRlcnZhbHMKICAgKiBFYWNoIG9mIHRoZXNlIGJ1dHRvbnMgaXMgYWxzbyBzZXQgdG8gYmUgaGlkZGVuIGZyb20gdXNlciB2aWV3CjEuIEF0IHRoZSB0b3Agb2YgdGhlIGNvZGluZyBmb3JtLCB0aGUgcmFkaW8gYnV0dG9ucyBmb3IgdGhlICJXYXMgdGhlcmUgYW4gaW50ZXJydXB0aW9uIGluIHRoZSB0YXNrPyIgcXVlc3Rpb24gYXJlIGFzc2lnbmVkIGFjdGlvbnMKICAgKiBJZiAiWWVzIiBpcyBzZWxlY3RlZCwgdGhlIDE4IGJ1dHRvbnMgYXJlIHJldmVhbGVkIGFuZCBzaG93biB0byB0aGUgdXNlcgogICAqIElmICJObyIgaXMgc2VsZWN0ZWQsIHRoZSAxOCBidXR0b25zIGFyZSBoaWRkZW4KICAgKiBUaHVzLCB3aGVuIHRoZSB1c2VyIHNlbGVjdHMgdGhhdCBhbiBpbnRlcnJ1cHRpb24gb2NjdXJyZWQsIHRoZSAxOCBidXR0b25zIGFwcGVhciBhbmQgYWxsb3cgdGhlIHVzZXIgdG8gc2VsZWN0IHRoZSBpbnRlcnZhbCBpbiB3aGljaCB0aGUgaW50ZXJydXB0aW9uIG9jY3VycmVkLgogICBXaGVuIHRoZSBidXR0b24gaXMgcHJlc3NlZCwgdGhlIGF1dG9tYXRpY2FsbHkgY2FsY3VsYXRlZCB0aW1lIGZpZWxkcyBhcmUgaGlkZGVuIGZvciB0aGF0IGludGVydmFsIGFuZCBzdWJzZXF1ZW50IGludGVydmFscywgYW5kIHRoZSBmaWVsZHMgdGhhdCBhbGxvdyBmb3IgbWFudWFsIGVudHJ5IGFyZSBzaG93biBmb3IgdGhhdCBpbnRlcnZhbCBhbmQgc3Vic2VxdWVudCBpbnRlcnZhbHMuCiAgIFRoaXMgYWxsb3dzIGZvciB0aW1lIGNhbGN1bGF0aW9ucyB0byBiZSBpbXBsZW1lbnRlZCBldmVuIHdoZW4gaW50ZXJydXB0aW9ucyBvY2N1cgoxLiBSZWZlciB0byB0aGUgVG9rZW4vQmVhZCBTb3J0IGNvZGluZyBmb3JtIGluIG9yZGVyIHRvIGdhaW4gZnVydGhlciB1bmRlcnN0YW5kaW5nIG9mIHRoaXMgc2V0dXAKCiMjIENhbGN1bGF0aW5nIHRoZSBIaWdoZXN0IExldmVsIGZyb20gYSBSb3cgb2YgVmFsdWVzCgpUaGUgZm9sbG93aW5nIHNjcmlwdCByZXR1cm5zIHRoZSBoaWdoZXN0IGxldmVsIG9mIGEgYmVoYXZpb3IuCkZvciBleGFtcGxlLCBhIGJlaGF2aW9yIG1heSBiZSBjb2RlZCBmb3IgdGhlIG51bWJlciBvZiB0aW1lcyBpdCBvY2N1cnMgYXQgZGlmZmVyZW50IGxldmVscyBvZiBpbnRlbnNpdHkuCklmIG9uZSB3YW50cyB0aGUgaGlnaGVzdCBsZXZlbCBvZiBpbnRlbnNpdHkgdGhlIGJlaGF2aW9yIG9jY3VycmVkIGF0LCByZWdhcmRsZXNzIG9mIHRoZSBudW1iZXIgb2YgdGltZXMgaXQgb2NjdXJyZWQsIHRoZSBmb2xsb3dpbmcgc2NyaXB0IGNhbiBiZSB1dGlsaXplZDoKCipOb3RlLiogVGhlIGZvbGxvd2luZyBzY3JpcHQgd2FzIGNyZWF0ZWQgZm9yIGEgdW5pcXVlIHNpdHVhdGlvbi4KRXNzZW50aWFsbHksIHRoZSBzY3JpcHQgdXRpbGl6ZXMgbXVsdGlwbGUgaWYvZWxzZSBzdGF0ZW1lbnRzLgpIb3cgdG8gZW1wbG95IGlmL2Vsc2Ugc3RhdGVtZW50cyBhbmQgY29uZGl0aW9uYWxzIGFyZSBvdXRsaW5lcyBhYm92ZS4KVGh1cyB0aGUgZXhwbGFuYXRpb24gb2YgaG93IHRoaXMgc3BlY2lmaWMgc2NyaXB0IG9wZXJhdGVzIGlzIGxlc3MgdGVjaG5pY2FsIGFuZCBicmllZi4KVGhlIGJ1aWxkaW5nIGJsb2NrcyBvZiBob3cgdG8gdW5kZXJzdGFuZCB0aGlzIHNjcmlwdCBhdCBhIG1vcmUgdGVjaG5pY2FsIGxldmVsIGFyZSBwcm92aWRlZCBhYm92ZS4KCgpgYGAKdmFyIHYxPSBnZXRGaWVsZCgiaW50ZW5zaXR5X29mX2JlaGF2aW9yXzEiKS52YWx1ZQp2YXIgdjI9IGdldEZpZWxkKCJpbnRlbnNpdHlfb2ZfYmVoYXZpb3JfMiIpLnZhbHVlCnZhciB2Mz0gZ2V0RmllbGQoImludGVuc2l0eV9vZl9iZWhhdmlvcl8zIikudmFsdWUKdmFyIHY0PSBnZXRGaWVsZCgiaW50ZW5zaXR5X29mX2JlaGF2aW9yXzQiKS52YWx1ZQp2YXIgdjU9IGdldEZpZWxkKCJpbnRlbnNpdHlfb2ZfYmVoYXZpb3JfNSIpLnZhbHVlCnZhciB2Nj0gZ2V0RmllbGQoImludGVuc2l0eV9vZl9iZWhhdmlvcl82IikudmFsdWUKCgppZiAodjYgPiAwKSB7CiAgdG90YWw2ID0gNjsKfSBlbHNlIHsKICB0b3RhbDYgPSAwOwp9CgoKaWYgKCh2NSA+IDApICYmICh2NiA8PSAwKSkgewogIHRvdGFsNSA9IDU7Cn0gZWxzZSB7CiAgdG90YWw1ID0gMDsKfQoKCmlmICgodjQgPiAwKSAmJiAodjYgPD0gMCkgJiYgKHY1IDw9IDApKSB7CiAgdG90YWw0ID0gNDsKfSBlbHNlIHsKICB0b3RhbDQgPSAwOwp9CgppZiAoKHYzID4gMCkgJiYgKHY2IDw9IDApICYmICh2NSA8PSAwKSAmJiAodjQgPD0gMCkpewogIHRvdGFsMyA9IDM7Cn0gZWxzZSB7CiAgdG90YWwzID0gMDsKfQoKaWYgKCh2MiA+IDApICYmICh2NiA8PSAwKSAmJiAodjUgPD0gMCkgJiYgKHY0IDw9IDApICYmICh2MyA8PSAwKSl7CiAgdG90YWwyID0gMjsKfSBlbHNlIHsKICB0b3RhbDIgPSAwOwp9CgppZiAoKHYxID4gMCkgJiYgKHY2IDw9IDApICYmICh2NSA8PSAwKSAmJiAodjQgPD0gMCkgJiYgKHYzIDw9IDApICYmICh2MiA8PSAwKSl7CiAgdG90YWwgPSAxOwp9IGVsc2UgewogIHRvdGFsID0gMDsKfQoKZXZlbnQudmFsdWUgPSB0b3RhbCArIHRvdGFsMiArIHRvdGFsMyArIHRvdGFsNCArIHRvdGFsNSArIHRvdGFsNgpgYGAKCiAgICogVGhlIGFib3ZlIHNjcmlwdCB1c2VzIGlmL2Vsc2Ugc3RhdGVtZW50cyB0byBkZXRlcm1pbmUgdGhlIGhpZ2hlc3QgbGV2ZWwgYXQgd2hpY2ggdGhlIGJlaGF2aW9ycyBvY2N1cnMKICAgICAgKiBEb3VibGUgYW1wZXJzYW5kcyBhcmUgdXNlZCB0byBjcmVhdGUgY29uZGl0aW9uYWwgc3RhdGVtZW50cyB3aXRoIG11bHRpcGxlIGNvbmRpdGlvbnMKICAgKiBQbGFpbmx5LCB0aGUgYWJvdmUgc2NyaXB0IGFza3Mgd2hldGhlciB0aGUgYmVoYXZpb3Igb2NjdXJzIGF0IGxlYXN0IG9uY2UgYXQgZWFjaCBsZXZlbCBvZiBpbnRlbnNpdHkKICAgICAgKiBJZiB0aGUgYmVoYXZpb3Igb2NjdXJzIGF0IHRoZSBoaWdoZXN0IGxldmVsIG9mIGludGVuc2l0eSwgdGhlIHRvdGFsIHJldHVybnMgYSA2IHdoaWNoIHNpZ25pZmllcyB0aGUgaGlnaGVzdCBsZXZlbCBvZiBpbnRlbnNpdHkKICAgICAgKiBJZiB0aGUgYmVoYXZpb3IgZG9lcyBub3Qgb2NjdXIgYXQgdGhlIGhpZ2hlc3QgbGV2ZWwsIGl0IGFza3Mgd2hldGhlciB0aGVyZSBpcyBhIHZhbHVlIHByZXNlbnQgZm9yIHRoZSBzZWNvbmQgaGlnaGVzdCBsZXZlbC4KICAgICAgSWYgdGhlcmUgaXMsIHRoZSB0b3RhbCByZXR1cm5zIGEgNSB3aGljaCBzaWduaWZpY2VzIHRoZSBzZWNvbmQgaGlnaGVzdCBsZXZlbCBvZiBpbnRlbnNpdHkKICAgICAgKiBJZiB0aGUgYmVoYXZpb3IgZG9lcyBub3Qgb2NjdXIgYXQgdGhlIHNlY29uZCBoaWdoZXN0IGxldmVsLCBpdCBhc2tzIHdoZXRoZXIgdGhlcmUgaXMgYSB2YWx1ZSBmb3IgdGhlIHRoaXJkIGhpZ2hlc3QuCiAgICAgIElmIG5vdCBhdCB0aGUgdGhpcmQgaGlnaGVzdCwgaXQgYXNrcyBhdCB0aGUgZm91cnRoIGhpZ2hlc3QsIGFuZCBzbyBmb3J0aC4KICAgKiBUaGlzIHNjcmlwdCBtYXkgYmUgbW9kaWZpZWQgdG8gYmUgZW1wbG95ZWQgaW4gYSB2YXJpZXR5IG9mIHNpdHVhdGlvbnMKICAgKiBUaGUgYWJvdmUgc2NyaXB0IGNhbiBiZSBmb3VuZCBpbiB0aGUgUGFyZW50YWwgU2Vuc2l0aXZpdHkgYW5kIFBhcmVudGFsIEludHJ1c2l2ZW5lc3MgQ29kaW5nIEZvcm1zCiAgICAgICogVGhlc2UgZm9ybXMgc2hvdWxkIGJlIHN0dWRpZWQgaW4gb3JkZXIgdG8gZ2FpbiBncmVhdGVyIHVuZGVyc3RhbmRpbmcgb2YgdGhlIHNwZWNpZmljIGNvbnRleHQgZm9yIHdoaWNoIHRoaXMgc2NyaXB0IHdhcyBjcmVhdGVkIGFuZCBob3cgbWlnaHQgaXQgYmUgYXBwbGllZCB0byBvdGhlciBjb250ZXh0cwoKCiMgSG93IFRvIFNwbGl0IFBERiBGaWxlcyBpbnRvIE11bHRpcGxlIERvY3VtZW50cwoKMS4gT3BlbiB0aGUgUERGIGluIEFjcm9iYXQgREMsIGFuZCB0aGVuIGNob29zZSBUb29scyA+IE9yZ2FuaXplIFBhZ2VzIG9yIGNob29zZSBPcmdhbml6ZSBQYWdlcyBmcm9tIHRoZSByaWdodCBwYW5lLgogICAtIFRoZSBPcmdhbml6ZSBQYWdlcyB0b29sc2V0IGlzIGRpc3BsYXllZCBpbiB0aGUgc2Vjb25kYXJ5IHRvb2xiYXIuCjEuIEluIHRoZSBzZWNvbmRhcnkgdG9vbGJhciwgY2xpY2sg4oCcU3BsaXTigJ0uCiAgIC0gQSBuZXcgdG9vbGJhciBhcHBlYXJzIGJlbG93IHRoZSBzZWNvbmRhcnkgdG9vbGJhciB3aXRoIHRoZSBjb21tYW5kcyBzcGVjaWZpYyB0byB0aGUgU3BsaXQgb3BlcmF0aW9uLgoxLiBJbiB0aGlzIHNlY29uZGFyeSB0b29sYmFyLCBjaG9vc2Ug4oCcU3BsaXTigJ0gdG8gc2VlIHRoZSBkb2N1bWVudCBzcGxpdHRpbmcgb3B0aW9ucy4KMS4gSW4gdGhlIOKAnFNwbGl0IEJ54oCdIGRyb3AtZG93biBsaXN0LCBzZWxlY3QgdGhlIGNyaXRlcmlhIGZvciBkaXZpZGluZyB0aGUgZG9jdW1lbnQ6CiAgIC0gTnVtYmVyIE9mIFBhZ2VzOiBTcGVjaWZ5IHRoZSBtYXhpbXVtIG51bWJlciBvZiBwYWdlcyBmb3IgZWFjaCBkb2N1bWVudCBpbiB0aGUgc3BsaXQuCiAgICAgIC0gVGhpcyBpcyB0aGUgbW9zdCBoZWxwZnVsIG9wdGlvbiB3aGVuIHRyeWluZyB0byBzZXBhcmF0ZSBsYXJnZSBzY2FubmVkIFBERiBwYWNrZXRzIGludG8gaW5kaXZpZHVhbCBmaWxlcy4KICAgICAgSnVzdCBzcGVjaWZ5IHRoZSBudW1iZXIgb2YgcGFnZXMgYXMg4oCcMeKAnSAoaWYgdGhlIGluZGl2aWR1YWwgZG9jdW1lbnRzIGFyZSBvbmx5IG9uZSBwYWdlKSzigJwy4oCdIChpZiB0aGUgZG9jdW1lbnRzIGFyZSBkb3VibGUgc2lkZWQpLCBldGMuCiAgIC0gRmlsZSBTaXplOiBTcGVjaWZ5IHRoZSBtYXhpbXVtIGZpbGUgc2l6ZSBmb3IgZWFjaCBkb2N1bWVudCBpbiB0aGUgc3BsaXQuCiAgIC0gVG9wLWxldmVsIEJvb2ttYXJrczogSWYgdGhlIGRvY3VtZW50IGluY2x1ZGVzIGJvb2ttYXJrcywgY3JlYXRlcyBvbmUgZG9jdW1lbnQgZm9yIGV2ZXJ5IHRvcC1sZXZlbCBib29rbWFyay4KMS4gVG8gc3BlY2lmeSBhIHRhcmdldCBmb2xkZXIgZm9yIHRoZSBzcGxpdCBmaWxlcyBhbmQgZmlsZW5hbWUgcHJlZmVyZW5jZXMsIGNsaWNrIOKAnE91dHB1dCBPcHRpb25z4oCdLgpTcGVjaWZ5IHRoZSBmb2xkZXIgaW4gdGhlIGxhYiBkcml2ZSB0aGF0IHRoZSBmaWxlcyBzaG91bGQgYmUgc2F2ZWQgdG8sIGFuZCB0aGVuIGNsaWNrIE9LLgoKKk9wdGlvbmFsOiogVG8gYXBwbHkgdGhlIHNhbWUgc3BsaXQgdG8gbXVsdGlwbGUgZG9jdW1lbnRzLCBjbGljayDigJxTcGxpdCBNdWx0aXBsZSBGaWxlc+KAnS4KSW4gdGhlIFNwbGl0IERvY3VtZW50cyBkaWFsb2cgYm94LCBjbGljayBlaXRoZXIg4oCcQWRkIEZpbGVz4oCdLCBhbmQgY2hvb3NlIOKAnEFkZCBGaWxlc+KAnSwg4oCcQWRkIEZvbGRlcnPigJ0sIG9yIOKAnEFkZCBPcGVuIEZpbGVz4oCdLgpTZWxlY3QgdGhlIGZpbGVzIG9yIGZvbGRlciwgYW5kIHRoZW4gY2xpY2sgT0suCg==



Developmental Psychopathology Lab