Chris Bail
Duke University
www.chrisbail.net

Introduction

This is part of a series of tutorials I’ve written on collecting digital trace data from sites such as Twitter, Facebook, or other internet sources. These earlier tutorials demonstrated some of the potential of digital trace data, but also highlighted many limitations of these new wellsprings of data as well. For example, digital trace data are often incomplete, inaccessible, non-representative, unstructured–and thus difficult to work with– and sensitive in nature. Because of these limitations, there is growing consensus that hybrid approaches are needed that combine digital trace data with more conventional methods such as surveys.

Note: this tutorial is a work in progress. It will be updated soon to include more annotated code

Building Apps for Social Science Research

The term “app” has come to refer to an impressive array of software– from mobile tools we use to find our way around to desktop-based tools for editing photos. In this article, I make the case that apps can also be extremely useful for social scientists. More specifically, I argue that apps can provide a vehicle for social scientists to collect digital trace data alongside survey data. There are numerous advantages of such a hybrid strategy– for example, surveys can be used to collect demographic information about those who produce social media texts in order to evaluate issues of coverage and representativeness. Or, surveys can be used to collect information about other confounding factors. What is more, authentication dialogues within apps provide a natural opportunity to obtain informed consent from social media users– though this was not done in a comprehensive manner in past studies such as those that became central to the Cambridge Analytica scandal.

To demonstrate the potential of apps for social science research it will be useful to provide a more detailed example. Some years ago, I was interested in how social media posts go viral. I was specifically interested in public posts on Facebook fan pages by advocacy organizations and other civil society groups. Using the procedures described in my previous tutorials, I could easily collect the text of all messages and counts of the number of times they were shared or commented upon via Facebook’s Graph API. Yet I was not able to answer important questions about who had viewed such posts, and precisely how they interacted with them. I was also not able to measure critical features of the non-profit groups that I was studying such as their financial resources, number of staff, and their use of offline tactics to call attention to their cause.

To solve this problem, I created a web-based app called “Find Your People.” Find Your People allowed non-profit organizations to get high-quality analysis of their social media outreach via comparisons to their peers who had also installed the app. In return, organizations agreed to share non-public aggregate data about their audiences with me known as Facebook “insights data”– these include metrics such as the number of people age 18-24 who viewed a post on a given day, but not the names of those people or other information that could be used to easily identify them. In addition, Find Your People asked non-profit organizations to complete a brief web-based survey that allowed me to collect additional information about the organization. I recruited non-profit groups working in the fields of Autism Spectrum Disorders and Human Organ Donation, respectively, to install the apps. Response rates to these requests were relatively high, and I identified minimal evidence of response bias. I used this tool to develop a new theory of how social media posts go viral. Readers who are interested in this theory– or those would would like to see more detail about how the apps were employed– can view this paper, this paper, this paper, or this paper.

How to Build Apps

When I created the Find Your People app, app-building required somewhat involved knowledge of programming in multiple languages, web design, and cloud computing. Yet the R program Shiny has become a gamechanger. Shiny is an interactive app building tool that you can use directly from rStudio. In addition to an easy to use, integrated app building tool, RStudio also provides a variety of tools to host and deploy apps on the web with the click of a button. Finally, there is a vibrant community of Shiny app developers— many of whom share the code they used to create their apps on sites such as this one.

There are a number of excellent tutorials online about how to use Shiny, including this excellent video series. Many of these are simple tools for interactive data visualization, yet Shiny enables development of apps for just about anything. Indeed, API calls can be embedded within Shiny apps to produce analyses of a user’s twitter data. Consider, for example, this nice example. Shiny allows you to create text boxes, multiple choice buttons, and many other of the standard fare of online surveys. Together, these tools could be used to create the functionality that I developed in the stone age with much less time and energy.

Building Bots for Social Science Research

Another recent trend in studies that employ digital trace data is the creation of bots, or automated social media accounts. In a very creative study, political science PhD Student Kevin Munger build an app designed to examine racial harrassment on Twitter. He created two automated accounts– one of which had a profile picture with a white person and the other with an African-American person. The bots were then designed to a) search Twitter for tweets by white men that contain racist language; and then b) reply to these tweets with condemnations of the racist language. Notwithstanding some limitations of the research design, this study suggests that people are more likely to stop using racist language if they are chastized by the bot with the White person pictured in its Twitter profile than the African-American person pictured in its Twitter profile.



In a recent study, my coauthors and I created bots designed to disrupt social media echo chambers in order to examine how they shape the formation of political views. We surveyed a large sample of Democrats and Republicans who visit Twitter at least three times each week about a range of social policy issues. One week later, we randomly assigned respondents to a treatment condition in which they were offered financial incentives to follow a Twitter bot for one month that exposed them to messages produced by elected officials, organizations, and other opinion leaders with opposing political ideologies. Respondents were re-surveyed at the end of the month to measure the effect of this treatment, and at regular intervals throughout the study period to monitor treatment compliance. We find that Republicans who followed a liberal Twitter bot became substantially more conservative post-treatment, and Democrats who followed a conservative Twitter bot became slightly more liberal post-treatment.



This study was somewhat more involved than the Munger study (and also much more expensive) since it combined not only observation of publicly-available Twitter data, but also linked these data to surveys of a large group of people. The bots were also somewhat more sophisticated in that they were created using a variety of sophisticated tools from social network analysis and the field of natural language processing. Still, these bots were not terribly difficult to create, and I describe the steps needed to create a bot such as ours in the following section.

How to Create a Bot

One way to create a bot is to write a .R script that is hosted on a single computer and runs throughout the study period. Yet such a strategy presents numerous obstacles. First, it ties up the R session on a machine and it therefore cannot be used for other routine work. Users have to either have another computer or a lot of time on their hands. Second, bots that are hosted on a single laptop or desktop can typically only be accessed or controlled from that machine. Third, all machines are prone to failure, and if the machine that hosts the app fails, valuable time can go buy during a field experiment before the researcher becomes aware of the failure.

For these reasons, I host the bots I’ve built in my work on a cloud machine running Rstudio via an Amazon EC2 server. This may sound complicated, but it is actually rather straightforward. The first step is to create an “Amazon Web Services” account. If you are a student, you may be eligible for 750 hours of free computing time. If you are not a student, you may be pleased to see that cloud computing time can be purchased quite inexpensively—particularly if you do not require significant computing power. The second step is to find a “Machine image” that will provide Amazon with instructions about how to create a cloud machine that can run RStudio. There are now many of these available, but one of the more popular ones is Louis Aslet’s. Click on the “region” closest to you to minimize latency (the time with which it takes for instructions to move from your location to the location of the Amazon server farm). You will also need to follow additional instructions on the aforementioned website in order to configure a “security group” and open up incoming HTTP traffic via port 80. You then cut and paste the “Public IP or DNS” address from your Amazon EC2 page into your web browser and you will be redirected to an Rstudio log-in page. By default, your user name and password are set to “Rstudio,” but you can change these immediately after loggin in (which is good practice to create additional security and prevent others from using your cloud machine). Keep in mind that as long as your machine is on or running, you will be charged by the hour, so make sure to shut down your cloud machines once you are done using them.

Regardless of where you host your bot, you will need to write some code to make it perform the functions necessary for your study. Below, I present code for a very primitive example of a bot that retweets a message about computational social science each hour for 24 days.

Note that this code assumes that you have already authenticated with Twitter in some manner. Be certain that your bot falls within Twitter’s terms of service, and make sure to avoid rate limiting (to learn about how to identify your rate limits, see my previous tutorial on Application Programming Interfaces.)

for (i in 1:24){
  #Search for 50 recent tweets about computational social science
  css_tweets<-search_tweets("Computational Social Science", n=50, include_rts = FALSE)
  #Randomly pick one of them, which appears in the `text` variable with the `css_tweets` dataframe
  lucky_tweet<-sample(css_tweets$text, 1)
  post_tweet(lucky_tweet)
  Sys.sleep(3600)
  #3600 seconds is 60 minutes
}

Needless to say, bots can be much more sophisticated– writing code to make bots interact with people—or sample candidates for interaction in real time—requires more code, though with a few “if/else” loops and a bit of elbow grease, this can often be accomplished in suprisingly few lines of code.

Most studies will also require data collection of those whom the bot interacts with. Such data can be collected within the bot code, or in a separate script that monitors accounts that are selected for interaction by a bot. Once again, make sure your bot does not conflict with Twitter’s terms of service, and does not abuse rate limits.

Ethical Issues in App and Bot-Based Research

Ethical issues in app and bot-based research are manifold and IRB guidelines for such research are in their infancy. For these reasons, it is vital— in my view—that computational social scientists hold themselves to a standard that is higher than IRB because there will no doubt be ethical issues on the horizons that we do not yet know exist. The Cambridge Analytica scandal may only be the tip of the ice-berg in terms of the potential for data collected by apps to be repurposed or merged with other datasets for other purposes. Such issues, combined with the perrenial issue of data security and the challenge of maintaining confidentiality with increasingly detailed data– or meta data–should inspire researchers to carefully review their plans not only with the IRB, but also with other members of the computational social science community who can help them ensure that their research is ethical and safe.

LS0tCnRpdGxlOiAiQnVpbGRpbmcgQXBwcyAmIEJvdHMgZm9yIFNvY2lhbCBTY2llbmNlIFJlc2VhcmNoIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIGRmX3ByaW50OiBwYWdlZAogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogJzUnCiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDUKZWRpdG9yX29wdGlvbnM6CiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQotLS0KCjxicj4KKipDaHJpcyBCYWlsKiogIAoqKkR1a2UgVW5pdmVyc2l0eSoqICAKKipbd3d3LmNocmlzYmFpbC5uZXRdKGh0dHA6Ly93d3cuY2hyaXNiYWlsLm5ldCkqKiAgCgojIEludHJvZHVjdGlvbgoKVGhpcyBpcyBwYXJ0IG9mIGEgc2VyaWVzIG9mIHR1dG9yaWFscyBJJ3ZlIHdyaXR0ZW4gb24gY29sbGVjdGluZyBkaWdpdGFsIHRyYWNlIGRhdGEgZnJvbSBzaXRlcyBzdWNoIGFzIFR3aXR0ZXIsIEZhY2Vib29rLCBvciBvdGhlciBpbnRlcm5ldCBzb3VyY2VzLiBUaGVzZSBlYXJsaWVyIHR1dG9yaWFscyBkZW1vbnN0cmF0ZWQgc29tZSBvZiB0aGUgcG90ZW50aWFsIG9mIGRpZ2l0YWwgdHJhY2UgZGF0YSwgYnV0IGFsc28gaGlnaGxpZ2h0ZWQgbWFueSBsaW1pdGF0aW9ucyBvZiB0aGVzZSBuZXcgd2VsbHNwcmluZ3Mgb2YgZGF0YSBhcyB3ZWxsLiBGb3IgZXhhbXBsZSwgZGlnaXRhbCB0cmFjZSBkYXRhIGFyZSBvZnRlbiBpbmNvbXBsZXRlLCBpbmFjY2Vzc2libGUsIG5vbi1yZXByZXNlbnRhdGl2ZSwgdW5zdHJ1Y3R1cmVkLS1hbmQgdGh1cyBkaWZmaWN1bHQgdG8gd29yayB3aXRoLS0gYW5kIHNlbnNpdGl2ZSBpbiBuYXR1cmUuIEJlY2F1c2Ugb2YgdGhlc2UgbGltaXRhdGlvbnMsIHRoZXJlIGlzIGdyb3dpbmcgY29uc2Vuc3VzIHRoYXQgaHlicmlkIGFwcHJvYWNoZXMgYXJlIG5lZWRlZCB0aGF0IGNvbWJpbmUgZGlnaXRhbCB0cmFjZSBkYXRhIHdpdGggbW9yZSBjb252ZW50aW9uYWwgbWV0aG9kcyBzdWNoIGFzIHN1cnZleXMuCgoqKk5vdGU6IHRoaXMgdHV0b3JpYWwgaXMgYSB3b3JrIGluIHByb2dyZXNzLiBJdCB3aWxsIGJlIHVwZGF0ZWQgc29vbiB0byBpbmNsdWRlIG1vcmUgYW5ub3RhdGVkIGNvZGUqKgoKIyBCdWlsZGluZyBBcHBzIGZvciBTb2NpYWwgU2NpZW5jZSBSZXNlYXJjaAoKVGhlIHRlcm0gImFwcCIgaGFzIGNvbWUgdG8gcmVmZXIgdG8gYW4gaW1wcmVzc2l2ZSBhcnJheSBvZiBzb2Z0d2FyZS0tIGZyb20gbW9iaWxlIHRvb2xzIHdlIHVzZSB0byBmaW5kIG91ciB3YXkgYXJvdW5kIHRvIGRlc2t0b3AtYmFzZWQgdG9vbHMgZm9yIGVkaXRpbmcgcGhvdG9zLiBJbiBbdGhpcyBhcnRpY2xlXShodHRwczovL2RyaXZlLmdvb2dsZS5jb20vZmlsZS9kLzBCeXZrMEE4SWMyMVlNQzFTTkhJeldVNWpTWGMvdmlldyksIEkgbWFrZSB0aGUgY2FzZSB0aGF0IGFwcHMgY2FuIGFsc28gYmUgZXh0cmVtZWx5IHVzZWZ1bCBmb3Igc29jaWFsIHNjaWVudGlzdHMuIE1vcmUgc3BlY2lmaWNhbGx5LCBJIGFyZ3VlIHRoYXQgYXBwcyBjYW4gcHJvdmlkZSBhIHZlaGljbGUgZm9yIHNvY2lhbCBzY2llbnRpc3RzIHRvIGNvbGxlY3QgZGlnaXRhbCB0cmFjZSBkYXRhIGFsb25nc2lkZSBzdXJ2ZXkgZGF0YS4gVGhlcmUgYXJlIG51bWVyb3VzIGFkdmFudGFnZXMgb2Ygc3VjaCBhIGh5YnJpZCBzdHJhdGVneS0tIGZvciBleGFtcGxlLCBzdXJ2ZXlzIGNhbiBiZSB1c2VkIHRvIGNvbGxlY3QgZGVtb2dyYXBoaWMgaW5mb3JtYXRpb24gYWJvdXQgdGhvc2Ugd2hvIHByb2R1Y2Ugc29jaWFsIG1lZGlhIHRleHRzIGluIG9yZGVyIHRvIGV2YWx1YXRlIGlzc3VlcyBvZiBjb3ZlcmFnZSBhbmQgcmVwcmVzZW50YXRpdmVuZXNzLiBPciwgc3VydmV5cyBjYW4gYmUgdXNlZCB0byBjb2xsZWN0IGluZm9ybWF0aW9uIGFib3V0IG90aGVyIGNvbmZvdW5kaW5nIGZhY3RvcnMuIFdoYXQgaXMgbW9yZSwgYXV0aGVudGljYXRpb24gZGlhbG9ndWVzIHdpdGhpbiBhcHBzIHByb3ZpZGUgYSBuYXR1cmFsIG9wcG9ydHVuaXR5IHRvIG9idGFpbiBpbmZvcm1lZCBjb25zZW50IGZyb20gc29jaWFsIG1lZGlhIHVzZXJzLS0gdGhvdWdoIHRoaXMgd2FzIG5vdCBkb25lIGluIGEgY29tcHJlaGVuc2l2ZSBtYW5uZXIgaW4gcGFzdCBzdHVkaWVzIHN1Y2ggYXMgdGhvc2UgdGhhdCBiZWNhbWUgY2VudHJhbCB0byB0aGUgQ2FtYnJpZGdlIEFuYWx5dGljYSBzY2FuZGFsLgoKVG8gZGVtb25zdHJhdGUgdGhlIHBvdGVudGlhbCBvZiBhcHBzIGZvciBzb2NpYWwgc2NpZW5jZSByZXNlYXJjaCBpdCB3aWxsIGJlIHVzZWZ1bCB0byBwcm92aWRlIGEgbW9yZSBkZXRhaWxlZCBleGFtcGxlLiBTb21lIHllYXJzIGFnbywgSSB3YXMgaW50ZXJlc3RlZCBpbiBob3cgc29jaWFsIG1lZGlhIHBvc3RzIGdvIHZpcmFsLiBJIHdhcyBzcGVjaWZpY2FsbHkgaW50ZXJlc3RlZCBpbiBwdWJsaWMgcG9zdHMgb24gRmFjZWJvb2sgZmFuIHBhZ2VzIGJ5IGFkdm9jYWN5IG9yZ2FuaXphdGlvbnMgYW5kIG90aGVyIGNpdmlsIHNvY2lldHkgZ3JvdXBzLiBVc2luZyB0aGUgcHJvY2VkdXJlcyBkZXNjcmliZWQgaW4gbXkgcHJldmlvdXMgdHV0b3JpYWxzLCBJIGNvdWxkIGVhc2lseSBjb2xsZWN0IHRoZSB0ZXh0IG9mIGFsbCBtZXNzYWdlcyBhbmQgY291bnRzIG9mIHRoZSBudW1iZXIgb2YgdGltZXMgdGhleSB3ZXJlIHNoYXJlZCBvciBjb21tZW50ZWQgdXBvbiB2aWEgRmFjZWJvb2sncyBHcmFwaCBBUEkuIFlldCBJIHdhcyBub3QgYWJsZSB0byBhbnN3ZXIgaW1wb3J0YW50IHF1ZXN0aW9ucyBhYm91dCB3aG8gaGFkIHZpZXdlZCBzdWNoIHBvc3RzLCBhbmQgcHJlY2lzZWx5IGhvdyB0aGV5IGludGVyYWN0ZWQgd2l0aCB0aGVtLiBJIHdhcyBhbHNvIG5vdCBhYmxlIHRvIG1lYXN1cmUgY3JpdGljYWwgZmVhdHVyZXMgb2YgdGhlIG5vbi1wcm9maXQgZ3JvdXBzIHRoYXQgSSB3YXMgc3R1ZHlpbmcgc3VjaCBhcyB0aGVpciBmaW5hbmNpYWwgcmVzb3VyY2VzLCBudW1iZXIgb2Ygc3RhZmYsIGFuZCB0aGVpciB1c2Ugb2Ygb2ZmbGluZSB0YWN0aWNzIHRvIGNhbGwgYXR0ZW50aW9uIHRvIHRoZWlyIGNhdXNlLgoKVG8gc29sdmUgdGhpcyBwcm9ibGVtLCBJIGNyZWF0ZWQgYSB3ZWItYmFzZWQgYXBwIGNhbGxlZCAiRmluZCBZb3VyIFBlb3BsZS4iIEZpbmQgWW91ciBQZW9wbGUgYWxsb3dlZCBub24tcHJvZml0IG9yZ2FuaXphdGlvbnMgdG8gZ2V0IGhpZ2gtcXVhbGl0eSBhbmFseXNpcyBvZiB0aGVpciBzb2NpYWwgbWVkaWEgb3V0cmVhY2ggdmlhIGNvbXBhcmlzb25zIHRvIHRoZWlyIHBlZXJzIHdobyBoYWQgYWxzbyBpbnN0YWxsZWQgdGhlIGFwcC4gSW4gcmV0dXJuLCBvcmdhbml6YXRpb25zIGFncmVlZCB0byBzaGFyZSBub24tcHVibGljIGFnZ3JlZ2F0ZSBkYXRhIGFib3V0IHRoZWlyIGF1ZGllbmNlcyB3aXRoIG1lIGtub3duIGFzIEZhY2Vib29rICJpbnNpZ2h0cyBkYXRhIi0tIHRoZXNlIGluY2x1ZGUgbWV0cmljcyBzdWNoIGFzIHRoZSBudW1iZXIgb2YgcGVvcGxlIGFnZSAxOC0yNCB3aG8gdmlld2VkIGEgcG9zdCBvbiBhIGdpdmVuIGRheSwgYnV0IG5vdCB0aGUgbmFtZXMgb2YgdGhvc2UgcGVvcGxlIG9yIG90aGVyIGluZm9ybWF0aW9uIHRoYXQgY291bGQgYmUgdXNlZCB0byBlYXNpbHkgaWRlbnRpZnkgdGhlbS4gSW4gYWRkaXRpb24sIEZpbmQgWW91ciBQZW9wbGUgYXNrZWQgbm9uLXByb2ZpdCBvcmdhbml6YXRpb25zIHRvIGNvbXBsZXRlIGEgYnJpZWYgd2ViLWJhc2VkIHN1cnZleSB0aGF0IGFsbG93ZWQgbWUgdG8gY29sbGVjdCBhZGRpdGlvbmFsIGluZm9ybWF0aW9uIGFib3V0IHRoZSBvcmdhbml6YXRpb24uIEkgcmVjcnVpdGVkIG5vbi1wcm9maXQgZ3JvdXBzIHdvcmtpbmcgaW4gdGhlIGZpZWxkcyBvZiBBdXRpc20gU3BlY3RydW0gRGlzb3JkZXJzIGFuZCBIdW1hbiBPcmdhbiBEb25hdGlvbiwgcmVzcGVjdGl2ZWx5LCB0byBpbnN0YWxsIHRoZSBhcHBzLiBSZXNwb25zZSByYXRlcyB0byB0aGVzZSByZXF1ZXN0cyB3ZXJlIHJlbGF0aXZlbHkgaGlnaCwgYW5kIEkgaWRlbnRpZmllZCBtaW5pbWFsIGV2aWRlbmNlIG9mIHJlc3BvbnNlIGJpYXMuIEkgdXNlZCB0aGlzIHRvb2wgdG8gZGV2ZWxvcCBhIG5ldyB0aGVvcnkgb2YgaG93IHNvY2lhbCBtZWRpYSBwb3N0cyBnbyB2aXJhbC4gUmVhZGVycyB3aG8gYXJlIGludGVyZXN0ZWQgaW4gdGhpcyB0aGVvcnktLSBvciB0aG9zZSB3b3VsZCB3b3VsZCBsaWtlIHRvIHNlZSBtb3JlIGRldGFpbCBhYm91dCBob3cgdGhlIGFwcHMgd2VyZSBlbXBsb3llZC0tIGNhbiB2aWV3IFt0aGlzIHBhcGVyXShodHRwOi8vd3d3LnBuYXMub3JnL2NvbnRlbnQvcG5hcy8xMTMvNDIvMTE4MjMuZnVsbC5wZGY/d2l0aC1kcz15ZXMpLCBbdGhpcyBwYXBlcl0oaHR0cHM6Ly9hanBoLmFwaGFwdWJsaWNhdGlvbnMub3JnL2RvaS9wZGYvMTAuMjEwNS9BSlBILjIwMTYuMzAzMTgxKSwgW3RoaXMgcGFwZXJdKGh0dHBzOi8vZHJpdmUuZ29vZ2xlLmNvbS9maWxlL2QvMTc5U3BKb0x1eU95T2dPRkVlbmx6aU9QbWZrVkxqbkZIL3ZpZXcpLCBvciBbdGhpcyBwYXBlcl0oaHR0cHM6Ly9kcml2ZS5nb29nbGUuY29tL2ZpbGUvZC8wQnl2azBBOEljMjFZUm1SNGNXeHRlRGQwVFhNL3ZpZXcpLgoKIyBIb3cgdG8gQnVpbGQgQXBwcwoKV2hlbiBJIGNyZWF0ZWQgdGhlIEZpbmQgWW91ciBQZW9wbGUgYXBwLCBhcHAtYnVpbGRpbmcgcmVxdWlyZWQgc29tZXdoYXQgaW52b2x2ZWQga25vd2xlZGdlIG9mIHByb2dyYW1taW5nIGluIG11bHRpcGxlIGxhbmd1YWdlcywgd2ViIGRlc2lnbiwgYW5kIGNsb3VkIGNvbXB1dGluZy4gWWV0IHRoZSBSIHByb2dyYW0gW1NoaW55XShodHRwczovL3NoaW55LnJzdHVkaW8uY29tLykgaGFzIGJlY29tZSBhIGdhbWVjaGFuZ2VyLiBTaGlueSBpcyBhbiBpbnRlcmFjdGl2ZSBhcHAgYnVpbGRpbmcgdG9vbCB0aGF0IHlvdSBjYW4gdXNlIGRpcmVjdGx5IGZyb20gclN0dWRpby4gSW4gYWRkaXRpb24gdG8gYW4gZWFzeSB0byB1c2UsIGludGVncmF0ZWQgYXBwIGJ1aWxkaW5nIHRvb2wsIFJTdHVkaW8gYWxzbyBwcm92aWRlcyBhIHZhcmlldHkgb2YgdG9vbHMgdG8gaG9zdCBhbmQgZGVwbG95IGFwcHMgb24gdGhlIHdlYiB3aXRoIHRoZSBjbGljayBvZiBhIGJ1dHRvbi4gRmluYWxseSwgdGhlcmUgaXMgYSB2aWJyYW50IGNvbW11bml0eSBvZiBTaGlueSBhcHAgZGV2ZWxvcGVycy0tLSBtYW55IG9mIHdob20gc2hhcmUgdGhlIGNvZGUgdGhleSB1c2VkIHRvIGNyZWF0ZSB0aGVpciBhcHBzIG9uIHNpdGVzIHN1Y2ggYXMgW3RoaXMgb25lXShodHRwczovL3d3dy5zaG93bWVzaGlueS5jb20vKS4gCgpUaGVyZSBhcmUgYSBudW1iZXIgb2YgZXhjZWxsZW50IHR1dG9yaWFscyBvbmxpbmUgYWJvdXQgaG93IHRvIHVzZSBTaGlueSwgaW5jbHVkaW5nIHRoaXMgW2V4Y2VsbGVudCB2aWRlbyBzZXJpZXNdKGh0dHBzOi8vc2hpbnkucnN0dWRpby5jb20vdHV0b3JpYWwvKS4gTWFueSBvZiB0aGVzZSBhcmUgc2ltcGxlIHRvb2xzIGZvciBpbnRlcmFjdGl2ZSBkYXRhIHZpc3VhbGl6YXRpb24sIHlldCBTaGlueSBlbmFibGVzIGRldmVsb3BtZW50IG9mIGFwcHMgZm9yIGp1c3QgYWJvdXQgYW55dGhpbmcuIEluZGVlZCwgQVBJIGNhbGxzIGNhbiBiZSBlbWJlZGRlZCB3aXRoaW4gU2hpbnkgYXBwcyB0byBwcm9kdWNlIGFuYWx5c2VzIG9mIGEgdXNlcidzIHR3aXR0ZXIgZGF0YS4gQ29uc2lkZXIsIGZvciBleGFtcGxlLCB0aGlzIFtuaWNlIGV4YW1wbGVdKGh0dHBzOi8vYWoxNy5zaGlueWFwcHMuaW8vdHdpdHRlcmFuYWx5dGljcy8pLiBTaGlueSBhbGxvd3MgeW91IHRvIGNyZWF0ZSB0ZXh0IGJveGVzLCBtdWx0aXBsZSBjaG9pY2UgYnV0dG9ucywgYW5kIG1hbnkgb3RoZXIgb2YgdGhlIHN0YW5kYXJkIGZhcmUgb2Ygb25saW5lIHN1cnZleXMuIFRvZ2V0aGVyLCB0aGVzZSB0b29scyBjb3VsZCBiZSB1c2VkIHRvIGNyZWF0ZSB0aGUgZnVuY3Rpb25hbGl0eSB0aGF0IEkgZGV2ZWxvcGVkIGluIHRoZSBzdG9uZSBhZ2Ugd2l0aCBtdWNoIGxlc3MgdGltZSBhbmQgZW5lcmd5LgoKCiMgQnVpbGRpbmcgQm90cyBmb3IgU29jaWFsIFNjaWVuY2UgUmVzZWFyY2gKCkFub3RoZXIgcmVjZW50IHRyZW5kIGluIHN0dWRpZXMgdGhhdCBlbXBsb3kgZGlnaXRhbCB0cmFjZSBkYXRhIGlzIHRoZSBjcmVhdGlvbiBvZiBib3RzLCBvciBhdXRvbWF0ZWQgc29jaWFsIG1lZGlhIGFjY291bnRzLiBJbiBhIHZlcnkgW2NyZWF0aXZlIHN0dWR5XShodHRwczovL2ludGVybmV0LnBzeWNoLndpc2MuZWR1L3dwLWNvbnRlbnQvdXBsb2Fkcy81MzItTWFzdGVyLzUzMi1Vbml0UGFnZXMvVW5pdC0wNi9NdW5nZXJfUEJfMjAxNy5wZGYpLCBwb2xpdGljYWwgc2NpZW5jZSBQaEQgU3R1ZGVudCBLZXZpbiBNdW5nZXIgYnVpbGQgYW4gYXBwIGRlc2lnbmVkIHRvIGV4YW1pbmUgcmFjaWFsIGhhcnJhc3NtZW50IG9uIFR3aXR0ZXIuIEhlIGNyZWF0ZWQgdHdvIGF1dG9tYXRlZCBhY2NvdW50cy0tIG9uZSBvZiB3aGljaCBoYWQgYSBwcm9maWxlIHBpY3R1cmUgd2l0aCBhIHdoaXRlIHBlcnNvbiBhbmQgdGhlIG90aGVyIHdpdGggYW4gQWZyaWNhbi1BbWVyaWNhbiBwZXJzb24uIFRoZSBib3RzIHdlcmUgdGhlbiBkZXNpZ25lZCB0byBhKSBzZWFyY2ggVHdpdHRlciBmb3IgdHdlZXRzIGJ5IHdoaXRlIG1lbiB0aGF0IGNvbnRhaW4gcmFjaXN0IGxhbmd1YWdlOyBhbmQgdGhlbiBiKSByZXBseSB0byB0aGVzZSB0d2VldHMgd2l0aCBjb25kZW1uYXRpb25zIG9mIHRoZSByYWNpc3QgbGFuZ3VhZ2UuIE5vdHdpdGhzdGFuZGluZyBzb21lIGxpbWl0YXRpb25zIG9mIHRoZSByZXNlYXJjaCBkZXNpZ24sIHRoaXMgc3R1ZHkgc3VnZ2VzdHMgdGhhdCBwZW9wbGUgYXJlIG1vcmUgbGlrZWx5IHRvIHN0b3AgdXNpbmcgcmFjaXN0IGxhbmd1YWdlIGlmIHRoZXkgYXJlIGNoYXN0aXplZCBieSB0aGUgYm90IHdpdGggdGhlIFdoaXRlIHBlcnNvbiBwaWN0dXJlZCBpbiBpdHMgVHdpdHRlciBwcm9maWxlIHRoYW4gdGhlIEFmcmljYW4tQW1lcmljYW4gcGVyc29uIHBpY3R1cmVkIGluIGl0cyBUd2l0dGVyIHByb2ZpbGUuCgoKPGJyPgo8ZGl2IHN0eWxlPSJ3aWR0aDo2MDBweDsiPgohW10oTXVuZ2VyLnBuZykKPC9kaXY+Cjxicj4KCkluIGEgW3JlY2VudCBzdHVkeV0oaHR0cHM6Ly9vc2YuaW8vcHJlcHJpbnRzL3NvY2FyeGl2LzR5Z3V4KSwgbXkgY29hdXRob3JzIGFuZCBJIGNyZWF0ZWQgYm90cyBkZXNpZ25lZCB0byBkaXNydXB0IHNvY2lhbCBtZWRpYSBlY2hvIGNoYW1iZXJzIGluIG9yZGVyIHRvIGV4YW1pbmUgaG93IHRoZXkgc2hhcGUgdGhlIGZvcm1hdGlvbiBvZiBwb2xpdGljYWwgdmlld3MuIFdlIHN1cnZleWVkIGEgbGFyZ2Ugc2FtcGxlIG9mIERlbW9jcmF0cyBhbmQgUmVwdWJsaWNhbnMgd2hvIHZpc2l0IFR3aXR0ZXIgYXQgbGVhc3QgdGhyZWUgdGltZXMgZWFjaCB3ZWVrIGFib3V0IGEgcmFuZ2Ugb2Ygc29jaWFsIHBvbGljeSBpc3N1ZXMuIE9uZSB3ZWVrIGxhdGVyLCB3ZSByYW5kb21seSBhc3NpZ25lZCByZXNwb25kZW50cyB0byBhIHRyZWF0bWVudCBjb25kaXRpb24gaW4gd2hpY2ggdGhleSB3ZXJlIG9mZmVyZWQgZmluYW5jaWFsIGluY2VudGl2ZXMgdG8gZm9sbG93IGEgVHdpdHRlciBib3QgZm9yIG9uZSBtb250aCB0aGF0IGV4cG9zZWQgdGhlbSB0byBtZXNzYWdlcyBwcm9kdWNlZCBieSBlbGVjdGVkIG9mZmljaWFscywgb3JnYW5pemF0aW9ucywgYW5kIG90aGVyIG9waW5pb24gbGVhZGVycyB3aXRoIG9wcG9zaW5nIHBvbGl0aWNhbCBpZGVvbG9naWVzLiBSZXNwb25kZW50cyB3ZXJlIHJlLXN1cnZleWVkIGF0IHRoZSBlbmQgb2YgdGhlIG1vbnRoIHRvIG1lYXN1cmUgdGhlIGVmZmVjdCBvZiB0aGlzIHRyZWF0bWVudCwgYW5kIGF0IHJlZ3VsYXIgaW50ZXJ2YWxzIHRocm91Z2hvdXQgdGhlIHN0dWR5IHBlcmlvZCB0byBtb25pdG9yIHRyZWF0bWVudCBjb21wbGlhbmNlLiBXZSBmaW5kIHRoYXQgUmVwdWJsaWNhbnMgd2hvIGZvbGxvd2VkIGEgbGliZXJhbCBUd2l0dGVyIGJvdCBiZWNhbWUgc3Vic3RhbnRpYWxseSBtb3JlIGNvbnNlcnZhdGl2ZSBwb3N0LXRyZWF0bWVudCwgYW5kIERlbW9jcmF0cyB3aG8gZm9sbG93ZWQgYSBjb25zZXJ2YXRpdmUgVHdpdHRlciBib3QgYmVjYW1lIHNsaWdodGx5IG1vcmUgbGliZXJhbCBwb3N0LXRyZWF0bWVudC4gCgo8YnI+CiFbXShCYWlsX3Jlc2VhcmNoX2Rlc2lnbi5wbmcpCjxicj4KClRoaXMgc3R1ZHkgd2FzIHNvbWV3aGF0IG1vcmUgaW52b2x2ZWQgdGhhbiB0aGUgTXVuZ2VyIHN0dWR5IChhbmQgYWxzbyBtdWNoIG1vcmUgZXhwZW5zaXZlKSBzaW5jZSBpdCBjb21iaW5lZCBub3Qgb25seSBvYnNlcnZhdGlvbiBvZiBwdWJsaWNseS1hdmFpbGFibGUgVHdpdHRlciBkYXRhLCBidXQgYWxzbyBsaW5rZWQgdGhlc2UgZGF0YSB0byBzdXJ2ZXlzIG9mIGEgbGFyZ2UgZ3JvdXAgb2YgcGVvcGxlLiBUaGUgYm90cyB3ZXJlIGFsc28gc29tZXdoYXQgbW9yZSBzb3BoaXN0aWNhdGVkIGluIHRoYXQgdGhleSB3ZXJlIGNyZWF0ZWQgdXNpbmcgYSB2YXJpZXR5IG9mIHNvcGhpc3RpY2F0ZWQgdG9vbHMgZnJvbSBzb2NpYWwgbmV0d29yayBhbmFseXNpcyBhbmQgdGhlIGZpZWxkIG9mIG5hdHVyYWwgbGFuZ3VhZ2UgcHJvY2Vzc2luZy4gU3RpbGwsIHRoZXNlIGJvdHMgd2VyZSBub3QgdGVycmlibHkgZGlmZmljdWx0IHRvIGNyZWF0ZSwgYW5kIEkgZGVzY3JpYmUgdGhlIHN0ZXBzIG5lZWRlZCB0byBjcmVhdGUgYSBib3Qgc3VjaCBhcyBvdXJzIGluIHRoZSBmb2xsb3dpbmcgc2VjdGlvbi4KCiNIb3cgdG8gQ3JlYXRlIGEgQm90CgpPbmUgd2F5IHRvIGNyZWF0ZSBhIGJvdCBpcyB0byB3cml0ZSBhIC5SIHNjcmlwdCB0aGF0IGlzIGhvc3RlZCBvbiBhIHNpbmdsZSBjb21wdXRlciBhbmQgcnVucyB0aHJvdWdob3V0IHRoZSBzdHVkeSBwZXJpb2QuIFlldCBzdWNoIGEgc3RyYXRlZ3kgcHJlc2VudHMgbnVtZXJvdXMgb2JzdGFjbGVzLiBGaXJzdCwgaXQgdGllcyB1cCB0aGUgUiBzZXNzaW9uIG9uIGEgbWFjaGluZSBhbmQgaXQgdGhlcmVmb3JlIGNhbm5vdCBiZSB1c2VkIGZvciBvdGhlciByb3V0aW5lIHdvcmsuIFVzZXJzIGhhdmUgdG8gZWl0aGVyIGhhdmUgYW5vdGhlciBjb21wdXRlciBvciBhIGxvdCBvZiB0aW1lIG9uIHRoZWlyIGhhbmRzLiBTZWNvbmQsIGJvdHMgdGhhdCBhcmUgaG9zdGVkIG9uIGEgc2luZ2xlIGxhcHRvcCBvciBkZXNrdG9wIGNhbiB0eXBpY2FsbHkgb25seSBiZSBhY2Nlc3NlZCBvciBjb250cm9sbGVkIGZyb20gdGhhdCBtYWNoaW5lLiBUaGlyZCwgYWxsIG1hY2hpbmVzIGFyZSBwcm9uZSB0byBmYWlsdXJlLCBhbmQgaWYgdGhlIG1hY2hpbmUgdGhhdCBob3N0cyB0aGUgYXBwIGZhaWxzLCB2YWx1YWJsZSB0aW1lIGNhbiBnbyBidXkgZHVyaW5nIGEgZmllbGQgZXhwZXJpbWVudCBiZWZvcmUgdGhlIHJlc2VhcmNoZXIgYmVjb21lcyBhd2FyZSBvZiB0aGUgZmFpbHVyZS4KCkZvciB0aGVzZSByZWFzb25zLCBJIGhvc3QgdGhlIGJvdHMgSSd2ZSBidWlsdCBpbiBteSB3b3JrIG9uIGEgY2xvdWQgbWFjaGluZSBydW5uaW5nIFJzdHVkaW8gdmlhIGFuIEFtYXpvbiBFQzIgc2VydmVyLiBUaGlzIG1heSBzb3VuZCBjb21wbGljYXRlZCwgYnV0IGl0IGlzIGFjdHVhbGx5IHJhdGhlciBzdHJhaWdodGZvcndhcmQuIFRoZSBmaXJzdCBzdGVwIGlzIHRvIGNyZWF0ZSBhbiAiQW1hem9uIFdlYiBTZXJ2aWNlcyIgYWNjb3VudC4gSWYgeW91IGFyZSBhIHN0dWRlbnQsIHlvdSBtYXkgYmUgZWxpZ2libGUgZm9yIDc1MCBob3VycyBvZiBmcmVlIGNvbXB1dGluZyB0aW1lLiBJZiB5b3UgYXJlIG5vdCBhIHN0dWRlbnQsIHlvdSBtYXkgYmUgcGxlYXNlZCB0byBzZWUgdGhhdCBjbG91ZCBjb21wdXRpbmcgdGltZSBjYW4gYmUgcHVyY2hhc2VkIHF1aXRlIGluZXhwZW5zaXZlbHktLS1wYXJ0aWN1bGFybHkgaWYgeW91IGRvIG5vdCByZXF1aXJlIHNpZ25pZmljYW50IGNvbXB1dGluZyBwb3dlci4gVGhlIHNlY29uZCBzdGVwIGlzIHRvIGZpbmQgYSAiTWFjaGluZSBpbWFnZSIgdGhhdCB3aWxsIHByb3ZpZGUgQW1hem9uIHdpdGggaW5zdHJ1Y3Rpb25zIGFib3V0IGhvdyB0byBjcmVhdGUgYSBjbG91ZCBtYWNoaW5lIHRoYXQgY2FuIHJ1biBSU3R1ZGlvLiBUaGVyZSBhcmUgbm93IG1hbnkgb2YgdGhlc2UgYXZhaWxhYmxlLCBidXQgb25lIG9mIHRoZSBtb3JlIHBvcHVsYXIgb25lcyBpcyBbTG91aXMgQXNsZXQnc10oaHR0cDovL3d3dy5sb3Vpc2FzbGV0dC5jb20vUlN0dWRpb19BTUkvKS4gQ2xpY2sgb24gdGhlICJyZWdpb24iIGNsb3Nlc3QgdG8geW91IHRvIG1pbmltaXplIGxhdGVuY3kgKHRoZSB0aW1lIHdpdGggd2hpY2ggaXQgdGFrZXMgZm9yIGluc3RydWN0aW9ucyB0byBtb3ZlIGZyb20geW91ciBsb2NhdGlvbiB0byB0aGUgbG9jYXRpb24gb2YgdGhlIEFtYXpvbiBzZXJ2ZXIgZmFybSkuIFlvdSB3aWxsIGFsc28gbmVlZCB0byBmb2xsb3cgYWRkaXRpb25hbCBpbnN0cnVjdGlvbnMgb24gdGhlIGFmb3JlbWVudGlvbmVkIHdlYnNpdGUgaW4gb3JkZXIgdG8gY29uZmlndXJlIGEgInNlY3VyaXR5IGdyb3VwIiBhbmQgb3BlbiB1cCBpbmNvbWluZyBIVFRQIHRyYWZmaWMgdmlhIHBvcnQgODAuIFlvdSB0aGVuIGN1dCBhbmQgcGFzdGUgdGhlICJQdWJsaWMgSVAgb3IgRE5TIiBhZGRyZXNzIGZyb20geW91ciBBbWF6b24gRUMyIHBhZ2UgaW50byB5b3VyIHdlYiBicm93c2VyIGFuZCB5b3Ugd2lsbCBiZSByZWRpcmVjdGVkIHRvIGFuIFJzdHVkaW8gbG9nLWluIHBhZ2UuIEJ5IGRlZmF1bHQsIHlvdXIgdXNlciBuYW1lIGFuZCBwYXNzd29yZCBhcmUgc2V0IHRvICJSc3R1ZGlvLCIgYnV0IHlvdSBjYW4gY2hhbmdlIHRoZXNlIGltbWVkaWF0ZWx5IGFmdGVyIGxvZ2dpbiBpbiAod2hpY2ggaXMgZ29vZCBwcmFjdGljZSB0byBjcmVhdGUgYWRkaXRpb25hbCBzZWN1cml0eSBhbmQgcHJldmVudCBvdGhlcnMgZnJvbSB1c2luZyB5b3VyIGNsb3VkIG1hY2hpbmUpLiAqKktlZXAgaW4gbWluZCB0aGF0IGFzIGxvbmcgYXMgeW91ciBtYWNoaW5lIGlzIG9uIG9yIHJ1bm5pbmcsIHlvdSB3aWxsIGJlIGNoYXJnZWQgYnkgdGhlIGhvdXIsIHNvIG1ha2Ugc3VyZSB0byBzaHV0IGRvd24geW91ciBjbG91ZCBtYWNoaW5lcyBvbmNlIHlvdSBhcmUgZG9uZSB1c2luZyB0aGVtLioqCgpSZWdhcmRsZXNzIG9mIHdoZXJlIHlvdSBob3N0IHlvdXIgYm90LCB5b3Ugd2lsbCBuZWVkIHRvIHdyaXRlIHNvbWUgY29kZSB0byBtYWtlIGl0IHBlcmZvcm0gdGhlIGZ1bmN0aW9ucyBuZWNlc3NhcnkgZm9yIHlvdXIgc3R1ZHkuIEJlbG93LCBJIHByZXNlbnQgY29kZSBmb3IgYSB2ZXJ5IHByaW1pdGl2ZSBleGFtcGxlIG9mIGEgYm90IHRoYXQgcmV0d2VldHMgYSBtZXNzYWdlIGFib3V0IGNvbXB1dGF0aW9uYWwgc29jaWFsIHNjaWVuY2UgZWFjaCBob3VyIGZvciAyNCBkYXlzLiAKCk5vdGUgdGhhdCB0aGlzIGNvZGUgYXNzdW1lcyB0aGF0IHlvdSBoYXZlIGFscmVhZHkgYXV0aGVudGljYXRlZCB3aXRoIFR3aXR0ZXIgaW4gc29tZSBtYW5uZXIuICoqQmUgY2VydGFpbiB0aGF0IHlvdXIgYm90IGZhbGxzIHdpdGhpbiBUd2l0dGVyJ3MgdGVybXMgb2Ygc2VydmljZSwgYW5kIG1ha2Ugc3VyZSB0byBhdm9pZCByYXRlIGxpbWl0aW5nICh0byBsZWFybiBhYm91dCBob3cgdG8gaWRlbnRpZnkgeW91ciByYXRlIGxpbWl0cywgc2VlIG15IHByZXZpb3VzIHR1dG9yaWFsIG9uIEFwcGxpY2F0aW9uIFByb2dyYW1taW5nIEludGVyZmFjZXMuKiopCgpgYGB7ciwgZXZhbD1GQUxTRX0KCmZvciAoaSBpbiAxOjI0KXsKICAjU2VhcmNoIGZvciA1MCByZWNlbnQgdHdlZXRzIGFib3V0IGNvbXB1dGF0aW9uYWwgc29jaWFsIHNjaWVuY2UKICBjc3NfdHdlZXRzPC1zZWFyY2hfdHdlZXRzKCJDb21wdXRhdGlvbmFsIFNvY2lhbCBTY2llbmNlIiwgbj01MCwgaW5jbHVkZV9ydHMgPSBGQUxTRSkKICAjUmFuZG9tbHkgcGljayBvbmUgb2YgdGhlbSwgd2hpY2ggYXBwZWFycyBpbiB0aGUgYHRleHRgIHZhcmlhYmxlIHdpdGggdGhlIGBjc3NfdHdlZXRzYCBkYXRhZnJhbWUKICBsdWNreV90d2VldDwtc2FtcGxlKGNzc190d2VldHMkdGV4dCwgMSkKICBwb3N0X3R3ZWV0KGx1Y2t5X3R3ZWV0KQogIFN5cy5zbGVlcCgzNjAwKQogICMzNjAwIHNlY29uZHMgaXMgNjAgbWludXRlcwp9CgpgYGAKCgpOZWVkbGVzcyB0byBzYXksIGJvdHMgY2FuIGJlIG11Y2ggbW9yZSBzb3BoaXN0aWNhdGVkLS0gd3JpdGluZyBjb2RlIHRvIG1ha2UgYm90cyBpbnRlcmFjdCB3aXRoIHBlb3BsZS0tLW9yIHNhbXBsZSBjYW5kaWRhdGVzIGZvciBpbnRlcmFjdGlvbiBpbiByZWFsIHRpbWUtLS1yZXF1aXJlcyBtb3JlIGNvZGUsIHRob3VnaCB3aXRoIGEgZmV3ICJpZi9lbHNlIiBsb29wcyBhbmQgYSBiaXQgb2YgZWxib3cgZ3JlYXNlLCB0aGlzIGNhbiBvZnRlbiBiZSBhY2NvbXBsaXNoZWQgaW4gc3VwcmlzaW5nbHkgZmV3IGxpbmVzIG9mIGNvZGUuCgpNb3N0IHN0dWRpZXMgd2lsbCBhbHNvIHJlcXVpcmUgZGF0YSBjb2xsZWN0aW9uIG9mIHRob3NlIHdob20gdGhlIGJvdCBpbnRlcmFjdHMgd2l0aC4gU3VjaCBkYXRhIGNhbiBiZSBjb2xsZWN0ZWQgd2l0aGluIHRoZSBib3QgY29kZSwgb3IgaW4gYSBzZXBhcmF0ZSBzY3JpcHQgdGhhdCBtb25pdG9ycyBhY2NvdW50cyB0aGF0IGFyZSBzZWxlY3RlZCBmb3IgaW50ZXJhY3Rpb24gYnkgYSBib3QuIE9uY2UgYWdhaW4sIG1ha2Ugc3VyZSB5b3VyIGJvdCBkb2VzIG5vdCBjb25mbGljdCB3aXRoIFR3aXR0ZXIncyB0ZXJtcyBvZiBzZXJ2aWNlLCBhbmQgZG9lcyBub3QgYWJ1c2UgcmF0ZSBsaW1pdHMuCgoKI0V0aGljYWwgSXNzdWVzIGluIEFwcCBhbmQgQm90LUJhc2VkIFJlc2VhcmNoCgpFdGhpY2FsIGlzc3VlcyBpbiBhcHAgYW5kIGJvdC1iYXNlZCByZXNlYXJjaCBhcmUgbWFuaWZvbGQgYW5kIElSQiBndWlkZWxpbmVzIGZvciBzdWNoIHJlc2VhcmNoIGFyZSBpbiB0aGVpciBpbmZhbmN5LiBGb3IgdGhlc2UgcmVhc29ucywgaXQgaXMgdml0YWwtLS0gaW4gbXkgdmlldy0tLXRoYXQgY29tcHV0YXRpb25hbCBzb2NpYWwgc2NpZW50aXN0cyBob2xkIHRoZW1zZWx2ZXMgdG8gYSBzdGFuZGFyZCB0aGF0IGlzIGhpZ2hlciB0aGFuIElSQiBiZWNhdXNlIHRoZXJlIHdpbGwgbm8gZG91YnQgYmUgZXRoaWNhbCBpc3N1ZXMgb24gdGhlIGhvcml6b25zIHRoYXQgd2UgZG8gbm90IHlldCBrbm93IGV4aXN0LiBUaGUgQ2FtYnJpZGdlIEFuYWx5dGljYSBzY2FuZGFsIG1heSBvbmx5IGJlIHRoZSB0aXAgb2YgdGhlIGljZS1iZXJnIGluIHRlcm1zIG9mIHRoZSBwb3RlbnRpYWwgZm9yIGRhdGEgY29sbGVjdGVkIGJ5IGFwcHMgdG8gYmUgcmVwdXJwb3NlZCBvciBtZXJnZWQgd2l0aCBvdGhlciBkYXRhc2V0cyBmb3Igb3RoZXIgcHVycG9zZXMuIFN1Y2ggaXNzdWVzLCBjb21iaW5lZCB3aXRoIHRoZSBwZXJyZW5pYWwgaXNzdWUgb2YgZGF0YSBzZWN1cml0eSBhbmQgdGhlIGNoYWxsZW5nZSBvZiBtYWludGFpbmluZyBjb25maWRlbnRpYWxpdHkgd2l0aCBpbmNyZWFzaW5nbHkgZGV0YWlsZWQgZGF0YS0tIG9yIG1ldGEgZGF0YS0tc2hvdWxkIGluc3BpcmUgcmVzZWFyY2hlcnMgdG8gY2FyZWZ1bGx5IHJldmlldyB0aGVpciBwbGFucyBub3Qgb25seSB3aXRoIHRoZSBJUkIsIGJ1dCBhbHNvIHdpdGggb3RoZXIgbWVtYmVycyBvZiB0aGUgY29tcHV0YXRpb25hbCBzb2NpYWwgc2NpZW5jZSBjb21tdW5pdHkgd2hvIGNhbiBoZWxwIHRoZW0gZW5zdXJlIHRoYXQgdGhlaXIgcmVzZWFyY2ggaXMgZXRoaWNhbCBhbmQgc2FmZS4KCgoKCgoKCgoKCgoKCgoKCgoK