2026년 1월 26일 월요일

빅데이터 분석기사 시험 후기.(11회차)

공무원 경력공채를 준비하면서 이미 있는 정보처리기사 말고 가산점용으로 자격증을 뭐하나 따야겠다 싶어서 빅데이터분석기사를 준비했다.

지금 생각해보면 경력공채 가산점을 위해서는 그냥 사무자동화를 땄어야 했다.

빅데이터분석기사는 신입 채용에서는 가산점에 포함이 되어있는데, 무슨 이유인지 경력공채에는 가산점 대상 자격증에 없었다.

아무튼 빅데이터분석기사는 한국데이터산업진흥원(DataQ)에서 만든 시험인데, 공부를 하면서 느낀점이 이게 빅데이터랑 상관이 아주 없는건 아닌데, 뭐 그냥 데이터라는 공통점만 있지 빅데이터랑 뭔상관인가 싶은 시험이다.

솔직히 실무에서의 쓸모는 사무자동화가 더 클듯.

필기는 통계학이나 데이터분석 관련 학과 나온 분들은 쉽다고 하는데, 난 그냥 개발자라서 그런지 외울게 너무 많았다. 주말에만 6~7시간씩 3달정도 한거 같은데...일수로 따지면 3주정도 일듯. 평일지나면 외운거 리셋되는게 가장 큰 문제였다.

그리고 책에 나와있는 내용이 이미 안쓰이는 것들도 꽤 있었다. 문제는 실제 시험에 이런 안 쓰이는 것들이 나왔다는거. 흠....

아무튼 공무원 준비하는 분들 중 전공자들은 각잡고 2주면 붙을정도인듯. 전공자가 아니면 빡셀거 같고. 필기 시험 난이도는 정보처리기사보다 어렵긴 했다. 근데 살짝 어려운정도.

외울게 너무 많았어.ㅠㅠ 아무튼 필기는 70점으로 합격.

필기는 팁이랄게 없었다. 그냥 외워야지. 기출문제 위주로 공부하지 않고 그냥 다 외우려고 했다. 시험이 기출 기반으로 나오지는 않았다.

실기는 파이썬으로 하는 걸 추천한다. 왜냐면 찾아볼 자료가 많으니까.

실기공부도 주말에만 했는데 6~7시간씩 5주정도 했으니까 10일정도 한 거 같다.

실기 팁은 그냥 책사서 처음부터 끝까지 계속 예제 전부를 쳐보는거다. 뭐 옛날 방식으로 프로그래밍 공부하는거지. 10일정도면 최소 두 번은 쳐볼꺼고, 좀 더 집중하면 세 번은 쳐볼꺼다.

이 정도면 떨어지는 게 더 어려움.

실기 난이도는 정보처리기사보다 빅데이터가 훨씬 쉽다.
난 11회차를 봤는데, 실제 프로그래밍을 하는 것 때문에 서술형보다 훨씬 쉽게 느껴진다.
파이썬에는 dir이라는 함수가 있는데, 모듈에 어떤 것들이 있는지를 나열해준다. 이걸 이용하면 어떤 함수였는지 대충 기억만 하고 있어도 시험 보는데는 문제가 없다.

빅데이터 실기 자체가 데이터를 가공해서 원하는 값을 얻는게 목적인데, 가공하는 방법이 몇 가지로 정해져있다. 이 부분을 책을 보면서 두 세 번 쳐보면 익숙해지게 된다.

암턴 나는 실기책을 두 번 쳐봤고, 인터넷에서 모의고사를 더 받아서 풀어봤다.

실기는 90점으로 합격. 100점이 아닌게 이상했는데, 2과목에서 10점 감점 당했음. 이유는 모르겠다.(무지성 랜덤포레스트를 한 것도 아니고, preprocessing하고 불균형 데이터 보정도 했는데...왜지...)
시간도 널널했다. 시험장에서 시험 시작하고 90분인가? 120분인가 이후에 퇴실 가능한데 이미 그전에 끝내고 시간되면 나가려고 대기중이였음.

실기는 아래 내용만 이해할 수 있으면 어지간해서는 떨어지는게 말이 안되는 정도의 난이도다.
아래 내용을 이해할 수 있으면 아래 내용만 외워가면 된다. 물론 책을 두번정도 쳐봤다는 가정.

===========================================================================

import pandas as pd

import numpy as np

import sklearn.preprocessing as skpp

import sklearn.metrics as metrics

import sklearn.ensemble as ensemble

import sklearn.linear_model as sklm

import sklearn.model_selection as skms

import lightgbm as lgb


#t검정

import scipy as sp

# ols(최소제곱법, 선형회귀), logit(로지스틱)

import statsmodels.formula.api as fapi

# anova(분산분석) .ols결과(Model)을 넣음

import statsmodels.api as api


'''

raw로 구분되어있는 내용을 컬럼으로 올리고 싶을 때 unstack 이용.


평균비교

단일표본검정: 표본의 평균을 특정값과 비교. ttest_1samp

대응표본검정: 표본을 두번 측정해서 비교. ttest_rel

독립표본검정: 표본 두개를 비교. ttest_ind

일원분산분석: 표본 세개 이상을 비교. 표본을 나누는 요인이 하나.

이원분산분석: 표본 세개 이상을 비교. 표본을 나누는 요인이 두개.


카이제곱검정(적합성, 독립성)

적합성: 관찰빈도가 기대빈도를 잘 따르는가.

독립성: 두 변수가 서로 독립적인가. (교차표가 주어져야 하며 raw데이터로 주어질 경우 crosstab을 이용해서 교차표를 만들어야함.)


독립표본검정시 등분산성이 만족되어야함.

등분산성은 정규성을 만족해야함.

정규성은 샤피로윌크. 0.05보다 크면 만족.

등분산성은 레빈검정. 0.05보다 크면 만족.

등분산성을 만족하지 않을 경우 welch 검정.


ols분석 결과 pvalue가 0.05보다 작으면 통계적으로 유의미하다.(0.05보다 작으면 귀무가설 기각.)

ols, logit의 파라미터는 (formula, data).fit()

logit

우도: llf

잔차이탈도: llf * -2


corr 상관분석.


정확도: accuracy_score

오류율: 1 - 정확도


model의 신뢰구간 변경.

model.conf_int(alpha=0.1) # 90퍼센트 신뢰구간


값 예측

model.predict(df)


특정값의 신뢰구간과 예측구간 예측.

result = model.get_prediction(df)

result.summary_frame(alpha=0.1) # 90퍼센트 구간.


오즈비 np.exp(params)

오즈비를 계산할 때 특정값이 몇 증가할 때의 오즈비는 params에 증가분을 곱하면 된다. np.exp(params * 5) 5증가.

'''

===========================================================================


2025년 9월 24일 수요일

windows 라이선스 인증 관련

 기존에 사용하던 윈도우 라이선스가 있었는데, ssd를 변경 후 인증이 되지 않음.

이게 처음이 아니고 전에도 두번쯤 전화인증으로 인증해줬음.


그래서 한국마이크로소프트에 전화

나: 전화인증 부탁드립니다.

상담사: 어떻게 구매하셨나요?

나: 오래전에 박스로 된 제품을 구매했습니다.

상담사: 그럼 박스가 있어야 합니다.


근데 디지털 라이선스로 전환된다는 글을 보고 박스를 버린거 같음. 물론 계정귀속 디지털 라이선스로 전환해놓고.


나: 디지털 라이선스로 전환되면 박스 필요없는거 아님?

상담사: 뭔소리냐. 박스랑 구매기록이 있어야 인증을 도와줄 수 있음.

나: 아니 근데 디지털라이선스로 인증된게 있는데?

상담사: ㄴㄴ 박스부터 내놔.


여기서 좀 빡쳤던게 상담원이 무조건 박스 무새마냥 박스타령만 30분 넘게 하고 있었음. 뭘 어떻게 해봐라 이런게 아니라 박스내놔 이 소리만.

그래서 며칠 지난 후에 미국 ms로 채팅 문의. 인증은 전화로만 가능하다고 하는데 실제로는 채팅으로도 최대한 해주더라.


나: 인증 안되서 연락함.

미국 상담사: 계정에 라이선스 등록되어있니?

나: ㅇㅇ 계정귀속 상태였음.

미국 상담사: 그럼 이렇게 해보고 저렇게 해봐.

나: 안됨.

미국 상담사: 기달. 니 계정 상태 확인해봄. 원격으로 봐줄께. 원격 수락 ㄱㄱ

나: ㅇㅋ

한 30분정도 후...

미국 상담사: 너 인증 안되는데? 이유는 나도 몰?루? 너는 ssd만 변경했다고 하는데 인증서버에서 뭔가 이유로 거부하는거임.

나: 근데 몇년전에 한국 고객센터에서 전화인증 받은 적도 있음. 근데 왜 지금은 안되는거임?

미국 상담사: 너 윈도우 어디서 샀는데?

나: 뭐 어디 마켓에서 샀겠지. 기억은 안나고, 키만 있고 박스는 없음.

미국 상담사: 인증 안되는 이유는 모르겠는데, 구매를 니가 증명하지 않으면 도와줄 수 없음.


검색해보면 강제로 인증시켜줄 수는 있는 것 같은데, 니 구매가 증명되지 않으면 도와줄 수 없음. 이 핵심이였음.

결국 윈도우11을 박스로 구매했으면 박스와 영수증을 가지고 있어야함. 디지털 라이선스로 전환하고 상관이 없음. 제품키를 입력해서 인증하는 방식이라서 제품키의 구매와 소유권을 인증해야함.

근데 ms store에서 구매하면 이 짓을 안해도 됨. 그냥 계정 귀속이고 제품키도 없음.

혹시 이거 보는 분들은 꼭 박스와 구매영수증은 갖고 있기를...


결론은

편하려면 ms store에서 구매해라. 몇만원 더 주고.


추가: 한국 MS 고객센터는 죤나 불친절하다. 검색해보면 앵무새마냥 뻐끔거리기만 한다는 글들이 죤나 많고, 내 예전 기억의 미화 덕분에 나는 괜찮겠지 했는데....뭐 시스템이 바뀐건지 답변이 사이코패스 스러움.

2024년 2월 29일 목요일

code snipper 예제

<pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; 
                color: #000000; background-color: #eee;
                font-size: 12px; border: 1px dashed #999999;
                line-height: 14px; padding: 5px; 
                overflow: auto; width: 100%">
       <code style="color:black;word-wrap:normal;">
            CODE HERE
       </code>
</pre>
<div>code snipper 아래 본문</div>

HTML Input Number type disable scroll

const MyNumberInput = () => {
  const numberInputOnWheelPreventChange = (e) => {
    // Prevent the input value change
    e.target.blur()

    // Prevent the page/container scrolling
    e.stopPropagation()

    // Refocus immediately, on the next tick (after the current     
    function is done)
      setTimeout(() => {
        e.target.focus()
    }, 0)
}

  return <input type="number" onWheel={numberInputOnWheelPreventChange}/>
}       

mysql 프로시저에서 파라미터로 받은 값을 IN 구문에 사용하여 인덱스 이용하기

프로시저에서 파라미터로 받은 값은 FIND_IN_SET으로만 검색이 가능한데, 이럴 경우 INDEX를 타지 않고 Full Search를 진행한다.

IN 구문을 사용하려면 쿼리 전체를 문자열로 만들어서 수행해야한다.

DROP PROCEDURE IF EXISTS ABC.admin_SelectData;
/*
    CALL ABC.admin_SelectData('');
*/
DELIMITER //
CREATE PROCEDURE ABC.admin_SelectData(
    IN _ids NVARCHAR(256),
    IN _types NVARCHAR(128),
    IN _beginDateTime DATETIME(3),
    IN _endDateTime DATETIME(3)
)
BEGIN

    SET @_sql = 'SELECT * FROM ABC.Data WHERE ';
    SET @_sql = CONCAT(@_sql, ' rewardDateTime >= \'', _beginDateTime, '\' AND rewardDateTime < \'', _endDateTime, '\'');
    SET @_sql = CONCAT(@_sql, ' AND ID IN (', _ids, ')');
    IF _types IS NOT NULL THEN
        SET @_sql = CONCAT(@_sql, ' AND type IN (', _types, ')');
    END IF;

    SET @_sql = CONCAT(@_sql, ' GROUP BY userID ORDER BY reward DESC LIMIT 1;');
    PREPARE PSQL FROM @_sql;
    EXECUTE PSQL;
    DEALLOCATE PREPARE PSQL;

END //
DELIMITER ;

위와 같이 CONCAT을 이용해서 쿼리 문자열을 만들고, PREPARE와 EXECUTE를 이용하여 실행시켜주면 된다.


2023년 12월 28일 목요일

mysql varchar size 변경.

mysql 5.6 이상에서 varchar size를 변경할 때 아래 조건일 경우 table lock 없이 변경할 수 있다.


varchar 컬럼의 byte가 0~255 안에서는 lock없이 변경가능.

varchar 컬럼의 byte가 256~65535(max size) 안에서는 lock없이 변경가능.

여기서 단위가 byte라는것이 중요하며, utf8mb4는 4byte이기 때문에 테이블의 케릭터셋을 확인하여 alter로 변경하면 된다.

예를 들어 utf8mb4 테이블의 varchar(32) 컬럼의 길이를 변경하려면 lock 없이 변경할 수 있는 최대 길이는 63이다.(255 / 4)

alter table tbl_name MODIFY col varchar(63);

lock 걸릴지 두렵다면 아래와 같이 algorithm을 inplace로 지정해주자. DDL이 online 상에서 변경되지 못할 경우 에러난다.

alter table tbl_name ALGORITHM=INPLACE MODIFY col varchar(63);

위 내용은 길이 한정 내용이고 NOT NULL을 NULLABLE로 변경할 경우 당연히 lock이 발생함.

2022년 9월 27일 화요일

aws ec2 nodejs port

기본적으로 Beanstalk 환경에서는 환경변수에 PORT 속성을 설정하면 nginx가 80포트로 수신되는 요청을 전달할 nodejs port를 지정할 수 있다.

(가이드 문서에서 역방향 프록시 구성 확인)

그런데 이런 설정이 없다면 기본 적으로 nginx는 nodejs로 요청을 전달할 때8081(Amazon Linux AMI-구버전 Linux 플랫폼-) 또는 8080(Amazon Linux 2)로 전달을 하는데, 이게 어디 세팅되어 있냐면...

Amazon Linux AMI(구버전 Linux 플랫폼)에서는

sudo iptables -L -t nat

명령어를 입력해보면 80포트를 8081로 포워딩 하고 있다.

Amazon Linux 2에서는 nginx conf로 조절하고 있다.

'/etc/nginx/conf.d/elasticbeanstalk/00_application.conf' 파일을 보면 8080으로 포워딩 하고 있다. 당연히 기본 설정은 /etc/nginx/nginx.conf에 있고, 아래 내용이 추가되어 있다.

# Include the Elastic Beanstalk generated locations

include conf.d/elasticbeanstalk/*.conf;

2022년 9월 26일 월요일

About proxy

먼저 프록시에 대해서 설명하자면, 클라이언트와 서버 사이에서 중간에 통신을 대리해서 연결해주는 것을 의미한다.(참고사이트: Proxy)

클라이언트 입장에서는 서버에 연결하는 과정에서 Proxy를 사용하므로 프록시를 서버라고 인식하고, 서버의 입장에서는 Proxy가 서버에 요청을 하므로 클라이언트라고 본다.

프록시는 포워드 프록시가 있고 백워드 프록시가 있다.

포워드 프록시

클라이언트 입장에서 사용하는 프록시를 의미한다. 클라이언트에서 프록시서버를 통해 네트워크 통신을 하게 되면, 클라이언트의 IP가 숨겨질 수 있다. 포워드 프록시 기능 중 주변에서 쉽게 볼 수 있는 것은 집에서 이용하는 PC방 서비스 같은 것이 있다.

그리고 사내망에서 외부 인터넷에 접속을 제한하는 것도 가능하다. 프록시서버에서 destination 을 보고 제한을 하면 되기 때문이다.


리버스 프록시

대표적인 서비스가 nginx인데, 서버 앞에 위치하고 프록시서버는 클라이언트의 요청을 받고 프록시 서버가 서버에게 전달한다.

포워드 프록시처럼 클라이언트는 프록시서버를 보고 있기 때문에, 실제 서버 endpoint는 모르게 된다.

이 경우 프록시서버가 하는 역할은 클라이언트가 호출하는 url(port포함)별로 서버를 다르게 호출할 수 있다.

2022년 9월 25일 일요일

자주쓰는 vi 이동 명령어

ctrl+f - 다음 페이지로

ctrl+b - 이전 페이지로

gg - 파일 첫 문장으로

G - 파일 끝으로

:숫자 – 숫자 번째 문장으로 이동

/[검색어]: 커서 위치에서부터 앞쪽으로 검색

?[검색어]: 커서 위치에서부터 뒤쪽으로 검색

n: 다음 검색

N: 이전 검색

set number: 줄 번호

set nonumber: 줄 번호 숨기기


자주 안쓰니까 자주 까먹음.ㅠ

2022년 6월 1일 수요일

aws beanstalk 환경에서 스크립트 실행 시 application enviroment (환경 변수) 읽어오기.

빈스톡 구성을 보면 환경 변수를 아래와 같이 세팅할 수 있다.


위에 세팅해놓은 MODE 값을 ec2 쉘 스크립트에서 읽어오고 싶으면 아래와 같이 할 수 있다.


.ebextensions에 파일 하나를 만들고 아래와 같이 작성해준다.

commands:

    00_mode_test:

        command: "echo $mode > /mode"

        env:

            mode:

                "Fn::GetOptionSetting":

                    Namespace: "aws:elasticbeanstalk:application:environment"

                    OptionName: MODE

위와 같이 작성하면 환경 변수의 MODE 값을 읽어와서 루트 위치에 파일로 기록을 한다.

그리고 아래와 같이 쉘 스크립트에서 해당 파일을 읽어오면 된다.

mode=$(<mode)


추가로 .ebextensions를 통해서 환경 변수를 세팅해줄 수 있다.

option_settings:

    - namespace:  aws:elasticbeanstalk:application:environment

      option_name:  MODE

      value:  “PROD”

aws beanstalk ebextension을 이용한 스크립트 실행

 서버가 시작되거나 어플리케이션이 시작되는 등의 일부 이벤트 상황에 스크립트를 실행시킬 수 있다.


빈스톡 구플랫폼인 Amazon Linux 1은 

https://docs.aws.amazon.com/ko_kr/elasticbeanstalk/latest/dg/custom-platform-hooks.html


현세대 플랫폼인 Amazon Linux 2는

https://docs.aws.amazon.com/ko_kr/elasticbeanstalk/latest/dg/platforms-linux-extend.html

여기서 확인하면 된다.


아래 내용은 Linux 1에 해당되는 내용이다.

우선 실행할 스크립트를 .ebextensions 폴더에 파일로 만든다.(https://mfcdev.blogspot.com/2021/10/aws-ebextensions-eb.html 참조)


files:

    "/startTime.sh":

        mode: "000700"

        owner: root

        group: root

        content: |

            #!/bin/bash

            now=`date`

            echo [start] $now >> /start_time


위 처럼 파일을 만들었다면, 이 파일을 특정 폴더에 넣어주면 특정 시점에 자동으로 실행시킬 수 있다.

위 내용에 아래의 내용을 추가하자.


container_commands:

    01mkdir_appdeploy_post:

        test: '[ ! -d /opt/elasticbeanstalk/hooks/appdeploy/post ]'

        command: "mkdir /opt/elasticbeanstalk/hooks/appdeploy/post"

    02mkdir_restartappserver_post:

            test: '[ ! -d /opt/elasticbeanstalk/hooks/restartappserver/post ]'

            command: "mkdir /opt/elasticbeanstalk/hooks/restartappserver/post"

    03_copy_appdeploy:

        command: "cp /startTime.sh /opt/elasticbeanstalk/hooks/appdeploy/post/"

    04_copy_restartappserver:

        command: "cp /startTime.sh /opt/elasticbeanstalk/hooks/restartappserver/post/"

/opt/elasticbeanstalk/hooks/restartappserver/post, /opt/elasticbeanstalk/hooks/appdeploy/post 두 개의 폴더를 만들고 있다. 빈스톡 환경으로 서버가 만들어져도 위 폴더가 없기 때문에 만들어서 스크립트 파일을 넣어줘야 한다.

restartappserver는 앱서버가 재시작하면 수행하고, appdeploy는 어플리케이션을 배포할 때 수행한다. 그 뒤에 있는 post는 각각의 단계에서 수행되는 시점인데 pre, enact, post가 있으며 순서는 pre -> enact -> post로 불리며, 각 폴더의 스크립트들은 알파벳 순서대로 호출된다.

위처럼 해놓으면 앱 재시작, 어플리케이션 배포할 때 startTime.sh 스크립트를 실행해준다.


Linux 2에서는 위와 같이 하지 않고, .platform/hooks/ 폴더 하위에 prebuild, predeploy, postdeploy 폴더를 만들고 스크립트 파일을 넣어주면 동작한다. 앱 재시작같은 이벤트는 없다. 자세한 내용은 위의 Linux 2 url을 참고 바란다.

2021년 10월 15일 금요일

nginx upstream keepalive

nginx upstream keepalive는 다음을 설정한다.

keepalive – The number of idle keepalive connections to an upstream server that remain open for each worker process. There is no default value.

Syntax:keepalive connections;
Default:
Context:upstream

This directive appeared in version 1.1.4.

Activates the cache for connections to upstream servers.

The connections parameter sets the maximum number of idle keepalive connections to upstream servers that are preserved in the cache of each worker process. When this number is exceeded, the least recently used connections are closed.

It should be particularly noted that the keepalive directive does not limit the total number of connections to upstream servers that an nginx worker process can open. The connections parameter should be set to a number small enough to let upstream servers process new incoming connections as well.

When using load balancing methods other than the default round-robin method, it is necessary to activate them before the keepalive directive.


업스트림 서버에 연결할 캐시를 활성화한다. 연결 매개변수(connections 값)는 각 작업자 프로세스의 캐시에 보존되는 업스트림 서버에 대한 최대 유휴 유지 접속 수를 설정한다. 이 숫자를 초과하면 가장 최근에 사용한 연결이 닫힌다.

worker process당 설정 값인데, worker process는 cpu 코어 숫자이고 nginx 설정(conf 파일)을 보면 기본적으로 auto로 설정되어 있다.(worker_processes auto;)

auto로 되어있으면 시스템의 코어 숫자를 디텍팅하여 자동 설정된다.

코어 숫자 확인은 grep -c processor /proc/cpuinfo 명령어로 확인 가능하다.

아무튼 keepalive 숫자를 늘리면 서버가 처리할 수 있는 트래픽이 많아지는건 당연한거 같은데...서버 스펙 고려안하고 늘린다고 과연 다 받아줄지도 의문이고, 결국엔 커넥션 숫자를 늘리는게 아니라 서버를 증설하는 방향으로 갈거 같다.

aws ebextensions를 사용하여 eb 환경 설정.

eb의 환경을 변경해야 할 필요가 있을 경우, .ebextensions 폴더를 만들고 config 파일을 넣은 후 소스를 배포하면 eb의 환경을 변경할 수 있다.

https://docs.aws.amazon.com/ko_kr/elasticbeanstalk/latest/dg/ebextensions.html

기본적인 내용은 위의 내용을 참고하면 된다.

샘플들은 https://github.com/awsdocs/elastic-beanstalk-samples/tree/master/configuration-files 여기서 볼 수 있다.

이 문서는 https://github.com/awsdocs/elastic-beanstalk-samples/blob/master/configuration-files/aws-provided/security-configuration/proxy-ratelimit-linux/nodejs/rate-limit-connections-nodejs.config 의 내용이다.

files 섹션에는 기본적으로 아래의 값이 들어간다.

files:
"/저장될 경로/파일명.확장자명":
mode: "권한(ex. 000644)"
owner: root
group: root
content: |
            위 파일에 기록될 내용


files:
"/tmp/#etc#nginx#conf.d#00_elastic_beanstalk_proxy.conf":
owner: root
group: root
mode: "000644"
content: |

즉 위 내용은 /tmp/#etc#nginx#conf.d#00_elastic_beanstalk_proxy.conf 이 파일을 만드는 것이다.(샵 문자는 그냥 파일 이름임.)

그리고 그 아래 부분을 보면 container_commands라는 부분이 있다. container_commands 는 웹서버가 설정되고 애플리케이션 버전 아카이브의 압축이 풀린 후에 실행된다고 한다.(https://mosei.tistory.com/entry/AWS-EBElastic-Beanstalk-ebextensions-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0)

container_commands:
99_move_config:
command: "mv -f /tmp/#etc#nginx#conf.d#00_elastic_beanstalk_proxy.conf /tmp/deployment/config/#etc#nginx#conf.d#00_elastic_beanstalk_proxy.conf"

99_move_config를 수행하고 command는 파일을 이동시키는 것이다.(근데 files에서 생성한 파일을 옮기는건데...왜 이런 예제를 써놨는지는 모르겠음.)

container_commands:
99_move_config:
command: "mv -f /tmp/#etc#nginx#conf.d#00_elastic_beanstalk_proxy.conf /tmp/deployment/config/#etc#nginx#conf.d#00_elastic_beanstalk_proxy.conf"
99_move_config_2:
command: "mv -f /tmp/#etc#nginx#conf.d#00_elastic_beanstalk_proxy.conf /tmp/deployment/config/#etc#nginx#conf.d#00_elastic_beanstalk_proxy.conf"

위와 같이 files도 여러개의 파일을 생성할 수 있고, container_commands도 여러개의 명령을 수행할 수 있다.

추가로 container_commands 말고 commands도 있다.

commands는 웹서버가 설정되고 애플리케이션 버전이 추출되기 전에 실행되고,
container_commands 는 웹서버가 설정되고 애플리케이션 버전 아카이브의 압축이 풀린 후에 실행된다.
만약 chown 처럼 애플리케이션의 파일 소유자 권한 등을 세팅할 때에는 container_commands로 해야 한다.

2021년 3월 23일 화요일

구글 어시스턴트(ok google) 알림음이 안나올 때(beep sound not working)

증상은 ok google 했을 때 알림음이 나오는게 아니라 진동이 울리는 것이다.

영어로 설명되어 있는 곳은 많은데, 영어랑 한글 메뉴랑 해석했을 때 매칭이 안되서 못찾고 있었다.

영어 영상

접근성 -> 설치된 서비스 -> '사용자 휴대폰 도우미' 사용으로 변경


'사용자 휴대폰 도우미'가 영어로 switch access 라는데...왜?????

2021년 2월 14일 일요일

vi 명령어

입력모드 전환

i 현재 커서의 위치부터 입력 I 현재 커서 줄의 맨 앞에서부터 입력 ( shift + i ) 

a 현재 커서의 위치 다음 칸부터 입력  현재 커서 줄의 맨 마지막부터 입력 ( shift + a) 

현재 커서의 다음 줄에 입력  O 현재 커서의 이전 줄에 입력 ( shfit + o ) 

s 현재 커서 위치의 한 글자를 지우고 입력 S 현재 커서의 한 줄을 지우고 입력 ( shift + s ) 


커서 이동 명령
 h 커서를 왼쪽으로 한 칸 이동 ( ← 이랑 같은 의미 ) 
 j  커서를 아래로 한 칸 이동 ( ↓와 같은 의미 ) 
 k 커서를 위로 한 칸 이동 ( ↑와 같은 의미 ) 
 l  커서를 오른쪽으로 이동 ( →와 같은 의미 ) 
 w 다음 단어의 처음으로 이동 ( 왠지 word의 약자 같은 느낌? )  
 ^  줄의 첫 문자로 이동 
 $ 줄의 맨 끝으로 이동 (:$은 줄의 제일 끝으로 이동)
 0 첫 번째 열로 이동  (:0은 줄의 제일 처음으로 이동)
 G 제일 끝 행으로 이동 ( shift + G ) 
 gg 제일 첫 행으로 이동 ( g + g ) 
 nG n 번째 행으로 이동  
 :숫자 +enter 해당 숫자의 행으로 이동 
 H 화면의 첫 줄로 이동 ( Head ) (shift + h)
 M 화면의 중간으로 이동 ( Middle ) (shift + m)
 L 화면의 끝 줄로 이동 ( Last ) (shift + l)
 [Ctrl] + b 이전 화면으로 이동 (Page Up과 같아요) 
 [Ctrl + d] 반 전도 화면 이동 (스크롤 중간 정도 내린거 같은거.)
 [Ctrl] + F 다음 화면으로 이동 (Page Down과 같아요)  
 n% 입력한 n퍼센트에 해당하는 줄로 이동 

삭제 복사 붙여넣기
 x 현재 커서가 위치한 문자를 삭제 ( del와 같은 의미예요) 
dw 단어 삭제
 dd 현재 커서의 행 삭제   
 숫자 dd 현재 커서부터 숫자만큼의 행 삭제 
 yy 현재 커서가 있는 행을 복사  
 숫자 yy 현재 커서부터 숫자만큼의 행을 복사  
 p 복사한 내용을 현재 행 이후에 붙여 넣기 
 P  복사한 내용을 현재 행 이전에 붙여 넣기 ( shift + p ) 

되돌리기 및 검색
 u 직전에 내린 명령을 취소 
 /exp + enter 'exp' 와 같은 문자열을 현재 커서가 위치한 곳부터 아래 방향으로 검색 
?exp + enter 'exp'와 같은 문자열을 뒤에서부터 찾습니다. 즉 위 방향으로 검색!
 n 찾은 문자 중에서 다음 문자로 이동  
N n이 아래로 검색을 계속 내려가는 거라면 N은 위로 검색을 계속하는거 (shift + n)

빨간색 굻은 글씨는 자주 쓰는거.

2021년 2월 13일 토요일

[Typescript] github이나 npm에서 배포될 모듈을 만들 때 여러 개의 구분된 모듈을 하나로 만드는 방법

하나의 모듈에 type을 비교하는 기능과 로그를 쓰는 기능 두 개를 만든다고 가정하자.

프로젝트를 생성 후 src 폴더를 만든 후 rootDir(tsconfig.json)로 설정하고, outDir(tsconfig.json)을 "./"(root)로 설정한다.
    "outDir": "./",
    "rootDir": "./src",

src 아래에 lib 폴더를 만들고 type.ts, logger.ts 파일을 만든다.
그리고 root 아래에 @types 폴더를 만들고, 그 아래에 모듈 이름의 폴더를 만들고 그 폴더 안에 index.d.ts.파일을 만든다.(./@types/[module_name]/index.d.ts)
그리고 package.json에 typing 값은 위 index.d.ts의 위치를 입력해준다.(./@types/[module_name]/index.d.ts)

index.d.ts파일의 내용을 다음과 같이 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
declare module gyUtils {
    interface type {
        isObject(source: any) : boolean;
        isFunction(source: any) : boolean;
        isNumber(source: any) : boolean;
        isString(source: any) : boolean;
        isBoolean(source: any) : boolean;
        isDate(source: any) : boolean;
        isArray(source: any) : boolean;
        isError(source: any) : boolean;
        isUndefined(source: any) : boolean;
        isEmpty(source: any) : boolean;
        isNull(source: any) : boolean;
        isUndefinedOrNull(source: any) : boolean;
        isUndefinedOrEmpty(source: any) : boolean;
        isUndefinedOrNullOrEmpty(source: any) : boolean;
    }
 
    interface logger {
        info(data: any): void;
        error(data: any): void;
        warn(data: any): void;
        debug(data: any): void;
        trace(data: any): void;
    }
}
 
export const gyType: gyUtils.type;
export const gyLogger: gyUtils.logger;
cs

아래 export 된 두개의 변수를 이용하여 사용할 것이다

type.ts 파일에는 interface type 의 함수를 구현해준다.
1
2
3
4
5
6
7
export const isObject = (source: any): boolean => {
    return false;
}
 
export const isFunction = (source: any): boolean => {
    return false;
}
cs

함수 여러개를 구현해서 export 하면 된다.

logger도 같은 방식으로 구현한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
export const info = (data: any) => {
    const _a = {
        type: "info",
        datetime: new Date().format(),
        data
    }
    console.info(JSON.stringify(_a));
}
 
export const error = (data: any) => {
    const _a = {
        type: "error",
        datetime: new Date().format(),
        data
    }
    console.error(JSON.stringify(_a));
}
cs

그리고 root에 index.ts(package.json의 main)를 만들고 다음과 같이 한다.

1
2
3
4
5
const _type = require("./lib/type");
const _logger = require("./lib/logger");
 
export const gyType = _type;
export const gyLogger = _logger;
cs

다른 프로젝트에서 require()를 이용해 이 모듈을 불러오면 index.js(package.json의 main)을 호출하게 된다. index.js에서 export된 값이 gyType, gyLogger 두 개이며, 이 두개를 외부에서 사용하기 위해 d.ts에 동일하게 정의를 해준 것이다.

다른 프로젝트에서 다음과 같이 사용하면 된다.
1
2
const utils = require("gyutils");
console.log(utils.gyType.isArray([]));
cs

2021년 2월 12일 금요일

[Typescript] github이나 npm을 통해 배포한 내 모듈의 d.ts 파일 위치

 https://typescript-kr.github.io/pages/module-resolution.html


위 내용을 보면 d.ts 파일을 찾는 방법이 있는데...이게 맞는지 모르겠다.

d.ts 에 들어가는 내용에 따라 인식하는 위치가 다른거 같다.


내가 배포한 모듈의 d.ts 파일 위치는 package.json의 typings 에 세팅하면 된다. 세팅을 안하면 d.ts의 내용을 인식하지 못한다.

그러면 모듈을 받아서 사용하는 사람들은 tsconfig에 typeRoots에 추가없이 사용이 가능하다.

이 때 d.ts에 들어가는 내용은 기본적으로 어느 사이트/블로그를 봐도 나와있는 내용들이다.

예를 들면

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//d.ts
declare module utils {
    interface type {
        isObject(source: any) : boolean;
        isFunction(source: any) : boolean;
        isNumber(source: any) : boolean;
        isString(source: any) : boolean;
        isBoolean(source: any) : boolean;
        isDate(source: any) : boolean;
        isArray(source: any) : boolean;
        isError(source: any) : boolean;
        isUndefined(source: any) : boolean;
        isEmpty(source: any) : boolean;
        isNull(source: any) : boolean;
        isUndefinedOrNull(source: any) : boolean;
        isUndefinedOrEmpty(source: any) : boolean;
        isUndefinedOrNullOrEmpty(source: any) : boolean;
    }
}
 
export const gyType: utils.type;
cs

이런 내용이다.

module이나 namespace를 선언하고, 필요한 선언을 한다.

그런데 나는 위의 일반적인 내용에 더불어 Array의 prototype에 함수를 추가하고 싶었다. Array의 prototype에 함수를 추가하려면 d.ts에 아래의 내용을 추가하고 ts파일에 구현을 하면 된다.

1
2
3
4
5
declare global {
    interface Array<T> {
        deepCopy(): Array<T>;
    }
}
cs

d.ts에 위와 같이 global 내부에 interface 선언 병합을 이용해서 추가를 하고, ts 파일에 구현을 해주면 된다.(명시적 import일 경우에는 global이 필요없는 것으로 보인다.)

declare global 구문을 사용할 때는 하나 이상의 export나 import 구문이 필요하다. 없으면 에러남. export나 import 할 것이 없다면 export {}; 이것을 추가해주면 된다.

이 내용을 구현해서 github에 올린 후, 다른 프로젝트에서 불러와서 사용하려고 하면 Array의 deepCopy를 찾지 못한다.

이유는 모르겠는데, declare global로 구현한 추가 interface의 경우에는 typeRoot에 추가를 해줘야 인식하는거 같다.

그래서 결론적으로 d.ts파일을 소스의 ./@types/[modue_name]/index.d.ts에 넣어놨다.

그리고 package.json의 typings에는 "./@types/[module_name]/index.t.ds"로 하고, 이 모듈을 불러서 사용하는 프로젝트의 tsconfig typeRoot에 "node_modules/[module_name]/@types" 추가를 해줬다.

참고로 tsconfig의 typeRoot에 추가된 path에서 d.ts를 찾을 때, 모듈의 이름으로 된 폴더를 검색하고 그 폴더 안에서 index.d.ts파일을 찾는다. 그래서 모듈에서 d.ts파일을 만들 때 ./@types의 바로 아래에 index.d.ts를 만든게 아니고, module_name의 폴더를 만들고 그 안에 index.d.ts를 넣은 것이다.

2021년 2월 11일 목요일

[Typescript/NodeJS] Array의 prototype에 함수 추가하기

Array의 prototype에 함수를 추가하려면 다음과 같이 한다.

d.ts 파일을 다음과 같이 작성한다.

1
2
3
4
5
declare global {
    interface Array<T> {
        deepCopy(): Array<T>;
    }
}
cs

그리고 ts 파일에 다음과 같이 한다.

1
2
3
4
5
6
7
8
Array.prototype.deepCopy = function() {
    let newArray: any[] = [];
    for(let i = 0; i < this.length; i++) {
        newArray.push(this[i]);
    }
    return newArray;
}
 
cs

위를 보면 export 구문이 없다. 뭐 위 내용을 export = () => {} 처럼 함수를 export 하고 함수 안에서 위 내용을 호출해도 되지만, export 구문이 없어도 된다.

그리고 index.ts(package.json의 main)에서 require("[js파일 경로]"); 를 해주면 된다.

그럼 전역으로 사용할 수 있다.