데이터베이스 분석하기 20180908
필요한 패키지
if("rJava" %in% installed.packages("rJava") == FALSE)install.packages("rJava")
library(rJava)
if("DBI" %in% installed.packages("DBI") == FALSE)install.packages("DBI")
library(DBI)
if("RJDBC" %in% installed.packages("RJDBC") == FALSE)install.packages("RJDBC")
library(RJDBC)
if("dplyr" %in% installed.packages("dplyr") == FALSE)install.packages("dplyr")
library(dplyr)
if("data.table" %in% installed.packages("data.table") == FALSE)install.packages("data.table")
library(data.table)
Oracle 데이터를 Rstudio로 가져오는 방법
myJDBC <- JDBC("oracle.jdbc.driver.OracleDriver",
"C:\\oraclexe\\app\\oracle\\product\\11.2.0\\server\\jdbc\\lib\\ojdbc6.jar")
conn <- dbConnect(myJDBC,
"jdbc:oracle:thin:@localhost:1521:xe",
"hr",
"oracle"
)
tab <- dbGetQuery(conn,"SELECT * FROM TAB")
tab
dplyr
filter, select, arrange, mutate,
summarise, group_by, left_join, bind_rows
tab <- data.frame(tab)
View(tab)
tname <- tab$TNAME
tname <- as.vector(tname)
tname
[1] “COUNTRIES”
[2] “DEPARTMENTS”
[3] “EMPLOYEES” “EMP_DETAILS_VIEW”
[5] “JOBS” “JOB_HISTORY”
[7] “LOCATIONS” “REGIONS”
cnt <- data.frame(dbGetQuery(conn,"SELECT * FROM COUNTRIES"))
head(cnt)
dep <- data.frame(dbGetQuery(conn,"SELECT * FROM DEPARTMENTS"))
emp <- data.frame(dbGetQuery(conn,"SELECT * FROM EMPLOYEES"))
empd <- data.frame(dbGetQuery(conn,"SELECT * FROM EMP_DETAILS_VIEW"))
job <- data.frame(dbGetQuery(conn,"SELECT * FROM JOBS"))
jobh <- data.frame(dbGetQuery(conn,"SELECT * FROM JOB_HISTORY"))
loc <- data.frame(dbGetQuery(conn,"SELECT * FROM LOCATIONS"))
reg <- data.frame(dbGetQuery(conn,"SELECT * FROM REGIONS"))
head(dep)
head(emp)
cnt 의 컬럼명을 한글로 전환하시오.
COUNTRY_ID
COUNTRY_NAME
REGION_ID
cnt <- cnt %>%
dplyr::rename(국가아이디 = COUNTRY_ID,
국가명 = COUNTRY_NAME,
지역아이디 = REGION_ID
)
str(cnt)
dep 의 컬럼명 전환
DEPARTMENT_ID 부서아이디
DEPARTMENT_NAME 부서명
MANAGER_ID 매니저아이디
LOCATION_ID 위치아이디
dep <- dep %>%
dplyr::rename(부서아이디 = DEPARTMENT_ID,
부서명 = DEPARTMENT_NAME,
매니저아이디 = MANAGER_ID,
위치아이디 = LOCATION_ID)
emp 의 컬럼명을 한글로 전환하시오.
그리고 First Name 과 Last Name 을
붙여서 이름 으로 된 컬럼을 추가하시오
단, 이름 간격은 띄울것. ex) James Dean
직원아이디 = EMPLOYEE_ID
이메일 = EMAIL
전화번호 = PHONE_NUMBER
채용일 = HIRE_DATE
업무아이디 = JOB_ID
연봉 = SALARY
커미션비율 = COMMISSION_PCT
매니저아이디 = MANAGER_ID
부서아이디 = DEPARTMENT_ID
emp <- emp %>%
dplyr::rename(직원아이디 = EMPLOYEE_ID,
이메일 = EMAIL,
전화번호 = PHONE_NUMBER,
채용일 = HIRE_DATE,
업무아이디 = JOB_ID,
연봉 = SALARY,
커미션비율 = COMMISSION_PCT,
매니저아이디 = MANAGER_ID,
부서아이디 = DEPARTMENT_ID) %>%
mutate(이름 = paste(FIRST_NAME, LAST_NAME))
View(head(emp))
# 필요없는 변수 삭제하기
emp <- subset(emp, select = -c(FIRST_NAME,LAST_NAME))
View(head(emp))
# 매달 지급하는 월급여(연봉 / 12)를 보여주는
# 월급이라는 컬럼(변수)을 추가시키시오. 0단위 이하는 절삭
emp <- emp %>%
dplyr::mutate(월급 = 연봉%/%12)
emp %>% View
연봉이 10000불이상인 사원(emp)의 목록을 이름, 직원아이디, 연봉만 구하되,
연봉 내림차순으로 보여주시오.
emp <- emp %>% emp 내용에 할당한다는 말이므로 emp 내용 자체가 변경됌 / 단순히 출력을 위해서는 emp %>% 라고만 입력
emp %>%
filter(연봉 >= 10000) %>%
select(이름, 직원아이디, 연봉) %>%
arrange(desc(연봉)) %>%
head
연봉이 3000 미만인 사원에게 보너스로 급여의 1%를 지급하겠다고 합니다. filter
대상자의 목록을 이름, 직원아이디, 연봉, 보너스를 기재하고 select
아이디 오름차순으로 보여주시오 arrange
dplyr:: 를 포함하는 이유는 어떤 패키지를 사용했는지 보여주기위해
단, 보너스는 이번 달만 주는 것이므로 emp DF(data.frame)에
저장하지는 말고 1회용 임시 DF를 따로 생성해서
저장하고, 기한이 지나서는 폐기하라
임시 저장용 data frame을 생성했으며 한글로 생성했으나 되도록 피해야함
보너스지급명세서 <- emp %>%
filter(연봉 < 3000) %>%
dplyr::mutate(보너스 = 월급*0.01) %>%
select(이름, 직원아이디, 연봉, 보너스) %>%
arrange(직원아이디)
View(보너스지급명세서)
# remove의 약자로 보너스지급명세서 삭제
rm(보너스지급명세서)
연봉이 10000이 넘는 직원의 부서명, 이름, 연봉을
출력하시오
emp %>% ## 기준이 되는 dataframe 지정
left_join(dep, by="부서아이디") %>% ## 연산자를 포함한 경우 raw데이터 (raw 데이터는 "", 302(수), )
filter(연봉 >= 10000) %>%
select(부서명, 이름, 연봉)
부서별로 연봉 평균을 구하시오
dep %>%
left_join(emp, by="부서아이디") %>%
group_by(부서명, 부서아이디) %>%
dplyr::summarise(연봉평균=mean(연봉,na.rm=T)) %>%
arrange(desc(연봉평균)) %>%
View
이 회사의 부서의 수를 구하시오
dep %>%
dplyr::distinct(부서명) %>%
count
연봉이 12000 이 넘는 직원의 부서명, 이름, 연봉, 직책
을 기재하시오.
job <- job %>%
rename(업무아이디 = JOB_ID,
직책 = JOB_TITLE,
최소연봉 = MIN_SALARY,
최대연봉 = MAX_SALARY
)
job %>% View
emp %>%
left_join(dep, by="부서아이디") %>%
left_join(job, by="업무아이디") %>%
filter(연봉 >= 12000) %>%
select(부서명, 이름, 연봉, 직책) %>%
View
부서별로 가장 높은 연봉을 받는 부서아이디,
부서명, 최대연봉을 구하시오. 최대연봉 max(연봉)
emp %>%
left_join(dep, by="부서아이디") %>%
left_join(job, by="업무아이디") %>%
group_by(부서명, 부서아이디) %>%
summarise(max(연봉))
부서아이디를 발급받지 않으면 신입입니다.
신입의 이름과 연봉을 구하시오. is.na(부서아이디) 와의 차이는?
emp %>%
filter(is.na(emp %>% select(부서아이디))) %>%
select(이름, 연봉)
LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQojIyMjIyDrjbDsnbTthLDrsqDsnbTsiqQg67aE7ISd7ZWY6riwIDIwMTgwOTA4DQojIyMg7ZWE7JqU7ZWcIO2MqO2CpOyngA0KDQpgYGB7cn0NCmlmKCJySmF2YSIgJWluJSBpbnN0YWxsZWQucGFja2FnZXMoInJKYXZhIikgPT0gRkFMU0UpaW5zdGFsbC5wYWNrYWdlcygickphdmEiKQ0KbGlicmFyeShySmF2YSkNCmlmKCJEQkkiICVpbiUgaW5zdGFsbGVkLnBhY2thZ2VzKCJEQkkiKSA9PSBGQUxTRSlpbnN0YWxsLnBhY2thZ2VzKCJEQkkiKQ0KbGlicmFyeShEQkkpDQppZigiUkpEQkMiICVpbiUgaW5zdGFsbGVkLnBhY2thZ2VzKCJSSkRCQyIpID09IEZBTFNFKWluc3RhbGwucGFja2FnZXMoIlJKREJDIikNCmxpYnJhcnkoUkpEQkMpDQppZigiZHBseXIiICVpbiUgaW5zdGFsbGVkLnBhY2thZ2VzKCJkcGx5ciIpID09IEZBTFNFKWluc3RhbGwucGFja2FnZXMoImRwbHlyIikNCmxpYnJhcnkoZHBseXIpDQppZigiZGF0YS50YWJsZSIgJWluJSBpbnN0YWxsZWQucGFja2FnZXMoImRhdGEudGFibGUiKSA9PSBGQUxTRSlpbnN0YWxsLnBhY2thZ2VzKCJkYXRhLnRhYmxlIikNCmxpYnJhcnkoZGF0YS50YWJsZSkNCg0KYGBgDQoNCiMjIyBPcmFjbGUg642w7J207YSw66W8IFJzdHVkaW/roZwg6rCA7KC47Jik64qUIOuwqeuylQ0KDQpgYGB7cn0NCm15SkRCQyA8LSBKREJDKCJvcmFjbGUuamRiYy5kcml2ZXIuT3JhY2xlRHJpdmVyIiwgDQogICAgICAgICAgICAgICAiQzpcXG9yYWNsZXhlXFxhcHBcXG9yYWNsZVxccHJvZHVjdFxcMTEuMi4wXFxzZXJ2ZXJcXGpkYmNcXGxpYlxcb2pkYmM2LmphciIpDQpjb25uIDwtIGRiQ29ubmVjdChteUpEQkMsDQogICAgICAgICAgICAgICAgICAiamRiYzpvcmFjbGU6dGhpbjpAbG9jYWxob3N0OjE1MjE6eGUiLA0KICAgICAgICAgICAgICAgICAgImhyIiwNCiAgICAgICAgICAgICAgICAgICJvcmFjbGUiDQogICAgICAgICAgICAgICAgICApDQp0YWIgPC0gZGJHZXRRdWVyeShjb25uLCJTRUxFQ1QgKiBGUk9NIFRBQiIpDQp0YWINCmBgYA0KDQojIyBkcGx5cg0KIyMgZmlsdGVyLCBzZWxlY3QsIGFycmFuZ2UsIG11dGF0ZSwNCiMjIHN1bW1hcmlzZSwgZ3JvdXBfYnksIGxlZnRfam9pbiwgYmluZF9yb3dzDQoNCmBgYHtyfQ0KdGFiIDwtIGRhdGEuZnJhbWUodGFiKQ0KVmlldyh0YWIpDQp0bmFtZSA8LSB0YWIkVE5BTUUNCnRuYW1lIDwtIGFzLnZlY3Rvcih0bmFtZSkNCnRuYW1lDQpgYGANCiMgWzFdICJDT1VOVFJJRVMiICAgICAgIA0KIyBbMl0gIkRFUEFSVE1FTlRTIiAgICAgIA0KIyBbM10gIkVNUExPWUVFUyIgICAgICAgICJFTVBfREVUQUlMU19WSUVXIiANCiMgWzVdICJKT0JTIiAgICAgICAgICAgICAiSk9CX0hJU1RPUlkiICAgICAgDQojIFs3XSAiTE9DQVRJT05TIiAgICAgICAgIlJFR0lPTlMiDQpgYGB7cn0NCmNudCA8LSBkYXRhLmZyYW1lKGRiR2V0UXVlcnkoY29ubiwiU0VMRUNUICogRlJPTSBDT1VOVFJJRVMiKSkNCmhlYWQoY250KQ0KZGVwIDwtIGRhdGEuZnJhbWUoZGJHZXRRdWVyeShjb25uLCJTRUxFQ1QgKiBGUk9NIERFUEFSVE1FTlRTIikpDQplbXAgPC0gZGF0YS5mcmFtZShkYkdldFF1ZXJ5KGNvbm4sIlNFTEVDVCAqIEZST00gRU1QTE9ZRUVTIikpDQplbXBkIDwtIGRhdGEuZnJhbWUoZGJHZXRRdWVyeShjb25uLCJTRUxFQ1QgKiBGUk9NIEVNUF9ERVRBSUxTX1ZJRVciKSkNCmpvYiA8LSBkYXRhLmZyYW1lKGRiR2V0UXVlcnkoY29ubiwiU0VMRUNUICogRlJPTSBKT0JTIikpDQpqb2JoIDwtIGRhdGEuZnJhbWUoZGJHZXRRdWVyeShjb25uLCJTRUxFQ1QgKiBGUk9NIEpPQl9ISVNUT1JZIikpDQpsb2MgPC0gZGF0YS5mcmFtZShkYkdldFF1ZXJ5KGNvbm4sIlNFTEVDVCAqIEZST00gTE9DQVRJT05TIikpDQpyZWcgPC0gZGF0YS5mcmFtZShkYkdldFF1ZXJ5KGNvbm4sIlNFTEVDVCAqIEZST00gUkVHSU9OUyIpKQ0KaGVhZChkZXApDQpoZWFkKGVtcCkNCmBgYA0KDQojIGNudCDsnZgg7Lus65+866qF7J2EIO2VnOq4gOuhnCDsoITtmZjtlZjsi5zsmKQuDQojIENPVU5UUllfSUQgDQojIENPVU5UUllfTkFNRQ0KIyBSRUdJT05fSUQNCg0KYGBge3J9DQpjbnQgPC0gY250ICU+JSANCiAgZHBseXI6OnJlbmFtZSjqta3qsIDslYTsnbTrlJQgPSBDT1VOVFJZX0lELA0KICAgICAgICAgICAgICAgICAgICAg6rWt6rCA66qFID0gQ09VTlRSWV9OQU1FLA0KICAgICAgICAgICAgICAgICAgICAg7KeA7Jet7JWE7J2065SUID0gUkVHSU9OX0lEDQogICAgICAgICAgICAgICAgICAgICApDQpzdHIoY250KQ0KYGBgDQojIGRlcCDsnZgg7Lus65+866qFIOyghO2ZmA0KIyBERVBBUlRNRU5UX0lEIOu2gOyEnOyVhOydtOuUlA0KIyBERVBBUlRNRU5UX05BTUUg67aA7ISc66qFDQojIE1BTkFHRVJfSUQg66ek64uI7KCA7JWE7J2065SUDQojIExPQ0FUSU9OX0lEIOychOy5mOyVhOydtOuUlA0KYGBge3J9DQpkZXAgPC0gZGVwICU+JSANCiAgZHBseXI6OnJlbmFtZSjrtoDshJzslYTsnbTrlJQgPSBERVBBUlRNRU5UX0lELA0KICAgICAgICAgICAgICAgICAgICAg67aA7ISc66qFID0gREVQQVJUTUVOVF9OQU1FLA0KICAgICAgICAgICAgICAgICAgICAg66ek64uI7KCA7JWE7J2065SUID0gTUFOQUdFUl9JRCwNCiAgICAgICAgICAgICAgICAgICAgIOychOy5mOyVhOydtOuUlCA9IExPQ0FUSU9OX0lEKQ0KYGBgDQoNCiMjIGVtcCDsnZgg7Lus65+866qF7J2EIO2VnOq4gOuhnCDsoITtmZjtlZjsi5zsmKQuDQojIyDqt7jrpqzqs6AgRmlyc3QgTmFtZSDqs7wgTGFzdCBOYW1lIOydhA0KIyMg67aZ7Jes7IScIOydtOumhCDsnLzroZwg65CcIOy7rOufvOydhCDstpTqsIDtlZjsi5zsmKQNCiMjIOuLqCwg7J2066aEIOqwhOqyqeydgCDrnYTsmrjqsoMuIGV4KSBKYW1lcyBEZWFuDQojIyDsp4Hsm5DslYTsnbTrlJQgPSBFTVBMT1lFRV9JRA0KIyMg7J2066mU7J28ID0gRU1BSUwNCiMjIOyghO2ZlOuyiO2YuCA9IFBIT05FX05VTUJFUg0KIyMg7LGE7Jqp7J28ID0gSElSRV9EQVRFDQojIyDsl4XrrLTslYTsnbTrlJQgPSBKT0JfSUQNCiMjIOyXsOu0iSA9IFNBTEFSWQ0KIyMg7Luk66+47IWY67mE7JyoID0gQ09NTUlTU0lPTl9QQ1QNCiMjIOunpOuLiOyggOyVhOydtOuUlCA9IE1BTkFHRVJfSUQNCiMjIOu2gOyEnOyVhOydtOuUlCA9IERFUEFSVE1FTlRfSUQNCmBgYHtyfQ0KZW1wIDwtIGVtcCAlPiUgDQogIGRwbHlyOjpyZW5hbWUo7KeB7JuQ7JWE7J2065SUID0gRU1QTE9ZRUVfSUQsDQogICAgICAgICAgICAgICAgICAgICDsnbTrqZTsnbwgPSBFTUFJTCwNCiAgICAgICAgICAgICAgICAgICAgIOyghO2ZlOuyiO2YuCA9IFBIT05FX05VTUJFUiwNCiAgICAgICAgICAgICAgICAgICAgIOyxhOyaqeydvCA9IEhJUkVfREFURSwNCiAgICAgICAgICAgICAgICAgICAgIOyXheustOyVhOydtOuUlCA9IEpPQl9JRCwNCiAgICAgICAgICAgICAgICAgICAgIOyXsOu0iSA9IFNBTEFSWSwNCiAgICAgICAgICAgICAgICAgICAgIOy7pOuvuOyFmOu5hOycqCA9IENPTU1JU1NJT05fUENULA0KICAgICAgICAgICAgICAgICAgICAg66ek64uI7KCA7JWE7J2065SUID0gTUFOQUdFUl9JRCwNCiAgICAgICAgICAgICAgICAgICAgIOu2gOyEnOyVhOydtOuUlCA9IERFUEFSVE1FTlRfSUQpICU+JQ0KICBtdXRhdGUo7J2066aEID0gcGFzdGUoRklSU1RfTkFNRSwgTEFTVF9OQU1FKSkNClZpZXcoaGVhZChlbXApKQ0KDQojIO2VhOyalOyXhuuKlCDrs4DsiJgg7IKt7KCc7ZWY6riwDQplbXAgPC0gc3Vic2V0KGVtcCwgc2VsZWN0ID0gLWMoRklSU1RfTkFNRSxMQVNUX05BTUUpKQ0KVmlldyhoZWFkKGVtcCkpDQoNCiMg66ek64usIOyngOq4ie2VmOuKlCDsm5TquInsl6wo7Jew67SJIC8gMTIp66W8IOuztOyXrOyjvOuKlA0KIyDsm5TquInsnbTrnbzripQg7Lus65+8KOuzgOyImCnsnYQg7LaU6rCA7Iuc7YKk7Iuc7JikLiAw64uo7JyEIOydtO2VmOuKlCDsoIjsgq0NCg0KZW1wIDwtIGVtcCAlPiUgDQogIGRwbHlyOjptdXRhdGUo7JuU6riJID0g7Jew67SJJS8lMTIpDQplbXAgJT4lIFZpZXcNCg0KYGBgDQojIOyXsOu0ieydtCAxMDAwMOu2iOydtOyDgeyduCDsgqzsm5AoZW1wKeydmCDrqqnroZ3snYQg7J2066aELCDsp4Hsm5DslYTsnbTrlJQsIOyXsOu0ieunjCDqtaztlZjrkJgsDQojIOyXsOu0iSDrgrTrprzssKjsiJzsnLzroZwg67O07Jes7KO87Iuc7JikLg0KIyBlbXAgPC0gZW1wICU+JSAgZW1wIOuCtOyaqeyXkCDtlaDri7ntlZzri6TripQg66eQ7J2066+A66GcIGVtcCDrgrTsmqkg7J6Q7LK06rCAIOuzgOqyveuQjCAvIOuLqOyInO2eiCDstpzroKXsnYQg7JyE7ZW07ISc64qUIGVtcCAlPiUgIOudvOqzoOunjCDsnoXroKUNCmBgYHtyfQ0KZW1wICU+JSANCiAgZmlsdGVyKOyXsOu0iSA+PSAxMDAwMCkgJT4lIA0KICBzZWxlY3Qo7J2066aELCDsp4Hsm5DslYTsnbTrlJQsIOyXsOu0iSkgJT4lIA0KICBhcnJhbmdlKGRlc2Mo7Jew67SJKSkgJT4lIA0KICBoZWFkDQpgYGANCiMg7Jew67SJ7J20IDMwMDAg66+466eM7J24IOyCrOybkOyXkOqyjCDrs7TrhIjsiqTroZwg6riJ7Jes7J2YIDEl66W8IOyngOq4ie2VmOqyoOuLpOqzoCDtlanri4jri6QuIGZpbHRlciAgDQojIOuMgOyDgeyekOydmCDrqqnroZ3snYQg7J2066aELCDsp4Hsm5DslYTsnbTrlJQsIOyXsOu0iSwg67O064SI7Iqk66W8IOq4sOyerO2VmOqzoCBzZWxlY3QgIA0KIyDslYTsnbTrlJQg7Jik66aE7LCo7Iic7Jy866GcIOuztOyXrOyjvOyLnOyYpCBhcnJhbmdlICANCiMgZHBseXI6OiDrpbwg7Y+s7ZWo7ZWY64qUIOydtOycoOuKlCDslrTrlqQg7Yyo7YKk7KeA66W8IOyCrOyaqe2WiOuKlOyngCDrs7Tsl6zso7zquLDsnITtlbQNCiMg64uoLCDrs7TrhIjsiqTripQg7J2067KIIOuLrOunjCDso7zripQg6rKD7J2066+A66GcIGVtcCBERihkYXRhLmZyYW1lKeyXkCANCiMg7KCA7J6l7ZWY7KeA64qUIOunkOqzoCAx7ZqM7JqpIOyehOyLnCBERuulvCDrlLDroZwg7IOd7ISx7ZW07IScIA0KIyDsoIDsnqXtlZjqs6AsIOq4sO2VnOydtCDsp4DrgpjshJzripQg7Y+Q6riw7ZWY6528DQoNCiMg7J6E7IucIOyggOyepeyaqSBkYXRhIGZyYW1l7J2EIOyDneyEse2WiOycvOupsCDtlZzquIDroZwg7IOd7ISx7ZaI7Jy864KYIOuQmOuPhOuhnSDtlLztlbTslbztlagNCmBgYHtyfQ0K67O064SI7Iqk7KeA6riJ66qF7IS47IScIDwtIGVtcCAlPiUgDQogIGZpbHRlcijsl7DrtIkgPCAzMDAwKSAlPiUgDQogIGRwbHlyOjptdXRhdGUo67O064SI7IqkID0g7JuU6riJKjAuMDEpICU+JSANCiAgc2VsZWN0KOydtOumhCwg7KeB7JuQ7JWE7J2065SULCDsl7DrtIksIOuztOuEiOyKpCkgJT4lIA0KICBhcnJhbmdlKOyngeybkOyVhOydtOuUlCkNCg0KVmlldyjrs7TrhIjsiqTsp4DquInrqoXshLjshJwpDQojIHJlbW92ZeydmCDslb3snpDroZwg67O064SI7Iqk7KeA6riJ66qF7IS47IScIOyCreygnA0Kcm0o67O064SI7Iqk7KeA6riJ66qF7IS47IScKQ0KICAgICAgICAgICAgDQpgYGANCiMg7Jew67SJ7J20IDEwMDAw7J20IOuEmOuKlCDsp4Hsm5DsnZgg67aA7ISc66qFLCDsnbTrpoQsIOyXsOu0ieydhCANCiMg7Lac66Cl7ZWY7Iuc7JikDQpgYGB7cn0NCmVtcCAlPiUgIyMg6riw7KSA7J20IOuQmOuKlCBkYXRhZnJhbWUg7KeA7KCVDQogIGxlZnRfam9pbihkZXAsIGJ5PSLrtoDshJzslYTsnbTrlJQiKSAlPiUgICMjICDsl7DsgrDsnpDrpbwg7Y+s7ZWo7ZWcIOqyveyasCByYXfrjbDsnbTthLAgKHJhdyDrjbDsnbTthLDripQgIiIsIDMwMijsiJgpLCApDQogIGZpbHRlcijsl7DrtIkgPj0gMTAwMDApICU+JSANCiAgc2VsZWN0KOu2gOyEnOuqhSwg7J2066aELCDsl7DrtIkpDQoNCmBgYA0KDQojIOu2gOyEnOuzhOuhnCDsl7DrtIkg7Y+J6reg7J2EIOq1rO2VmOyLnOyYpA0KDQpgYGB7cn0NCmRlcCAlPiUgDQogIGxlZnRfam9pbihlbXAsIGJ5PSLrtoDshJzslYTsnbTrlJQiKSAlPiUNCiAgZ3JvdXBfYnko67aA7ISc66qFLCDrtoDshJzslYTsnbTrlJQpICU+JSANCiAgZHBseXI6OnN1bW1hcmlzZSjsl7DrtIntj4nqt6A9bWVhbijsl7DrtIksbmEucm09VCkpICU+JSANCiAgYXJyYW5nZShkZXNjKOyXsOu0ie2Pieq3oCkpICU+JSANCiAgVmlldw0KYGBgDQoNCiMg7J20IO2ajOyCrOydmCDrtoDshJzsnZgg7IiY66W8IOq1rO2VmOyLnOyYpA0KYGBge3J9DQpkZXAgJT4lDQogIGRwbHlyOjpkaXN0aW5jdCjrtoDshJzrqoUpICU+JQ0KICBjb3VudA0KYGBgDQoNCiMg7Jew67SJ7J20IDEyMDAwIOydtCDrhJjripQg7KeB7JuQ7J2YIOu2gOyEnOuqhSwg7J2066aELCDsl7DrtIksIOyngeyxhQ0KIyDsnYQg6riw7J6s7ZWY7Iuc7JikLg0KDQpgYGB7cn0NCmpvYiA8LSBqb2IgJT4lIA0KICByZW5hbWUo7JeF66y07JWE7J2065SUID0gSk9CX0lELA0KICAgICAgICAgICAgICDsp4HssYUgPSBKT0JfVElUTEUsDQogICAgICAgICAgICAgIOy1nOyGjOyXsOu0iSA9IE1JTl9TQUxBUlksDQogICAgICAgICAgICAgIOy1nOuMgOyXsOu0iSA9IE1BWF9TQUxBUlkNCiAgICAgICAgICAgICAgKQ0Kam9iICU+JSBWaWV3DQoNCmVtcCAlPiUgDQogIGxlZnRfam9pbihkZXAsIGJ5PSLrtoDshJzslYTsnbTrlJQiKSAlPiUgDQogIGxlZnRfam9pbihqb2IsIGJ5PSLsl4XrrLTslYTsnbTrlJQiKSAlPiUgDQogIGZpbHRlcijsl7DrtIkgPj0gMTIwMDApICU+JSANCiAgc2VsZWN0KOu2gOyEnOuqhSwg7J2066aELCDsl7DrtIksIOyngeyxhSkgJT4lIA0KICBWaWV3DQpgYGANCiMg67aA7ISc67OE66GcIOqwgOyepSDrhpLsnYAg7Jew67SJ7J2EIOuwm+uKlCDrtoDshJzslYTsnbTrlJQsIA0KIyDrtoDshJzrqoUsIOy1nOuMgOyXsOu0ieydhCDqtaztlZjsi5zsmKQuIOy1nOuMgOyXsOu0iSBtYXgo7Jew67SJKQ0KYGBge3J9DQplbXAgJT4lIA0KICBsZWZ0X2pvaW4oZGVwLCBieT0i67aA7ISc7JWE7J2065SUIikgJT4lDQogIGxlZnRfam9pbihqb2IsIGJ5PSLsl4XrrLTslYTsnbTrlJQiKSAlPiUNCiAgZ3JvdXBfYnko67aA7ISc66qFLCDrtoDshJzslYTsnbTrlJQpICU+JQ0KICBzdW1tYXJpc2UobWF4KOyXsOu0iSkpIA0KYGBgDQojIOu2gOyEnOyVhOydtOuUlOulvCDrsJzquInrsJvsp4Ag7JWK7Jy866m0IOyLoOyeheyeheuLiOuLpC4NCiMg7Iug7J6F7J2YIOydtOumhOqzvCDsl7DrtInsnYQg6rWs7ZWY7Iuc7JikLiBpcy5uYSjrtoDshJzslYTsnbTrlJQpIOyZgOydmCDssKjsnbTripQ/DQpgYGB7cn0NCmVtcCAlPiUgDQogIGZpbHRlcihpcy5uYShlbXAgJT4lIHNlbGVjdCjrtoDshJzslYTsnbTrlJQpKSkgJT4lIA0KICBzZWxlY3Qo7J2066aELCDsl7DrtIkpDQoNCmBgYA0KDQoNCg0K