<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>sun.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Fri, 22 Mar 2024 12:23:32 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. sun.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/youseon__" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[linux] NFS server 및 client 설정]]></title>
            <link>https://velog.io/@youseon__/linux-NFS-server-%EB%B0%8F-client-%EC%84%A4%EC%A0%95</link>
            <guid>https://velog.io/@youseon__/linux-NFS-server-%EB%B0%8F-client-%EC%84%A4%EC%A0%95</guid>
            <pubDate>Fri, 22 Mar 2024 12:23:32 GMT</pubDate>
            <description><![CDATA[<h2 id="nfs-서버-설치-vm1">NFS 서버 설치 (vm1)</h2>
<pre><code class="language-bash">$ sudo apt update
$ sudo apt install nfs-kernel-server</code></pre>
<p>Ubuntu 20.04에서는 NFS 버전 2가 사용되지 않도록 설정됩니다. 버전 3 및 4를 사용할 수 있습니다. 다음 cat 명령을 실행하여 확인할 수 있습니다.</p>
<pre><code class="language-bash">$ sudo cat /proc/fs/nfsd/versions

# -2 +3 +4 +4.1 +4.2</code></pre>
<pre><code class="language-bash">$ mkdir /srv/vm1
$ chmod 777 /srv/vm1</code></pre>
<pre><code class="language-bash">$ vi /etc/exports
...
# 아래 내용 추가
/srv/vm1 10.10.12.*(rw,sync,no_root_squash)
...

$ sudo vi /etc/default/nfs-kernel-server
...
NEED_SVCGSSD=&quot;yes&quot;
...

$ sudo systemctl restart nfs-kernel-server
$ sudo exportfs -a
$ sudo ufw allow 2049/tcp

# 현재 내보내기 상태 확인 방법
$ sudo exportfs -v</code></pre>
<hr>
<h2 id="nfs-client-vm1의-폴더를-공유-할-대상-vm">NFS-Client (vm1의 폴더를 공유 할 대상 VM)</h2>
<pre><code class="language-bash">$ sudo apt update
$ sudo apt install nfs-common

$ mkdir /srv/vm1
$ sudo mount -t nfs -o vers=4 &lt;&lt;vm1의 IP&gt;&gt;:/srv/vm1 /srv/vm1</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Harbor] Docker Limit 오류 Harbor proxy로 해결하기]]></title>
            <link>https://velog.io/@youseon__/Harbor-Docker-Limit-%EC%98%A4%EB%A5%98-Harbor-proxy%EB%A1%9C-%ED%95%B4%EA%B2%B0%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@youseon__/Harbor-Docker-Limit-%EC%98%A4%EB%A5%98-Harbor-proxy%EB%A1%9C-%ED%95%B4%EA%B2%B0%ED%95%98%EA%B8%B0</guid>
            <pubDate>Fri, 22 Mar 2024 12:19:22 GMT</pubDate>
            <description><![CDATA[<ul>
<li>참고한 URL = <a href="https://velog.io/@denver_almighty/Docker-Harbor-%EC%84%A4%EC%B9%98">[Docker] Harbor 설치</a></li>
</ul>
<h2 id="harbor-설치">Harbor 설치</h2>
<pre><code class="language-bash">mkdir -p ~/certs
cd ~/certs
openssl genrsa -out ca.key 4096

#CA인증서 생성

openssl req -x509 -new -nodes -sha512 -days 3650 \
-subj &quot;/C=KR/ST=Seoul/L=Seoul/CN=&lt;&lt;IP&gt;&gt;&quot; \
-key ca.key \
-out ca.crt

#개인키 생성
openssl genrsa -out harbor.ks.io.key 4096

### 인증서 서명 요청(CSR)을 생성
openssl req -sha512 -new \
-subj &quot;/C=KR/ST=Seoul/L=Seoul/OU=Personal/CN=&lt;&lt;IP&gt;&gt;&quot; \
-key harbor.ks.io.key \
-out harbor.ks.io.csr

cat &gt; v3.ext &lt;&lt;-EOF
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names

[alt_names]
DNS.1=&lt;&lt;IP&gt;&gt;
[DNS.2=harbor.ks.io](http://dns.2=harbor.ks.io/)
DNS.3=harbor

EOF

#v3.ext하여 Harbour 호스트에 대한 인증서를 생성
openssl x509 -req -sha512 -days 3650 \
-extfile v3.ext \
-CA ca.crt -CAkey ca.key -CAcreateserial \
-in harbor.ks.io.csr \
-out harbor.ks.io.crt

mkdir -p /data/cert
cp harbor.ks.io.crt /data/cert/
cp harbor.ks.io.key /data/cert/

#/root/certs 에서 진행한다.
openssl x509 -inform PEM -in harbor.ks.io.crt -out harbor.ks.io.cert
mkdir -p /etc/docker/certs.d/harbor.ks.io/
cp harbor.ks.io.cert /etc/docker/certs.d/harbor.ks.io/
cp harbor.ks.io.key /etc/docker/certs.d/harbor.ks.io/
cp ca.crt /etc/docker/certs.d/harbor.ks.io/

# root 에서 실행, Harbor Offline 설치
wget &quot;https://github.com/goharbor/harbor/releases/download/v2.1.3/harbor-offline-installer-v2.1.3.tgz &quot;
tar xfvz harbor-offline-installer-v2.1.3.tgz
cd /harbor
cp harbor.yml.tmpl harbor.yml

# 아래 내용처럼 yml 수정
-------------------------------------------------
hostname: harbor.ks.io

https:
  # https port for harbor, default is 443
  port: 443
  # The path of cert and key files for nginx
  certificate: /data/cert/harbor.ks.io.crt
  private_key: /data/cert/harbor.ks.io.key

harbor_admin_password: &lt;&lt;password&gt;&gt;
-------------------------------------------------

./prepare
./install.sh</code></pre>
<h2 id="다른-vm에서-harbor-proxy-사용-방법"><strong>다른 VM에서 Harbor proxy 사용 방법</strong></h2>
<ul>
<li>전제 조건<ul>
<li>docker가 이미 설치되어있어야 함</li>
</ul>
</li>
</ul>
<ol>
<li><p>Harbor가 설치된 서버의 인증서를 docker image가 필요한 서버로 복사한다.</p>
<pre><code> #root 사용자로 전환 후 아래 내용 입력

 $ cd /data/cert
 $ scp /etc/docker/certs.d/harbor.ks.io/* &lt;VM의 IP&gt;:/etc/docker/certs.d/harbor.ks.io/</code></pre></li>
<li><p>대상 VM docker 재시작</p>
</li>
<li><p>대상 VM hosts 파일에 호스트 추가</p>
<pre><code> &lt;&lt;IP&gt;&gt; harbor.ks.io</code></pre></li>
<li><p>docker pull 테스트</p>
<pre><code> docker pull harbor.ks.io/proxy/&lt;도커네임스페이스&gt;/&lt;docker 이미지명?&gt;

 ex) docker pull harbor.ks.io/proxy/pytorch/pytorch</code></pre></li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스] 과일 장수]]></title>
            <link>https://velog.io/@youseon__/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EA%B3%BC%EC%9D%BC-%EC%9E%A5%EC%88%98</link>
            <guid>https://velog.io/@youseon__/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EA%B3%BC%EC%9D%BC-%EC%9E%A5%EC%88%98</guid>
            <pubDate>Sat, 01 Jul 2023 08:05:18 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<h3 id="문제-설명"><strong>문제 설명</strong></h3>
<p>과일 장수가 사과 상자를 포장하고 있습니다. 사과는 상태에 따라 1점부터 k점까지의 점수로 분류하며, k점이 최상품의 사과이고 1점이 최하품의 사과입니다. 사과 한 상자의 가격은 다음과 같이 결정됩니다.</p>
<ul>
<li>한 상자에 사과를 m개씩 담아 포장합니다.</li>
<li>상자에 담긴 사과 중 가장 낮은 점수가 p (1 ≤ p ≤ k)점인 경우, 사과 한 상자의 가격은 p * m 입니다.</li>
</ul>
<p>과일 장수가 가능한 많은 사과를 팔았을 때, 얻을 수 있는 최대 이익을 계산하고자 합니다.(사과는 상자 단위로만 판매하며, 남는 사과는 버립니다)</p>
<p>예를 들어, <code>k</code> = 3, <code>m</code> = 4, 사과 7개의 점수가 [1, 2, 3, 1, 2, 3, 1]이라면, 다음과 같이 [2, 3, 2, 3]으로 구성된 사과 상자 1개를 만들어 판매하여 최대 이익을 얻을 수 있습니다.</p>
<ul>
<li>(최저 사과 점수) x (한 상자에 담긴 사과 개수) x (상자의 개수) = 2 x 4 x 1 = 8</li>
</ul>
<p>사과의 최대 점수 <code>k</code>, 한 상자에 들어가는 사과의 수 <code>m</code>, 사과들의 점수 <code>score</code>가 주어졌을 때, 과일 장수가 얻을 수 있는 최대 이익을 return하는 solution 함수를 완성해주세요.</p>
<h3 id="제한사항">제한사항</h3>
<ul>
<li>3 ≤ <code>k</code> ≤ 9</li>
<li>3 ≤ <code>m</code> ≤ 10</li>
<li>7 ≤ <code>score</code>의 길이 ≤ 1,000,000<ul>
<li>1 ≤ <code>score[i]</code> ≤ k</li>
</ul>
</li>
<li>이익이 발생하지 않는 경우에는 0을 return 해주세요.</li>
</ul>
<hr>
<h3 id="입출력-예">입출력 예</h3>
<table>
<thead>
<tr>
<th>k</th>
<th>m</th>
<th>score</th>
<th>result</th>
</tr>
</thead>
<tbody><tr>
<td>3</td>
<td>4</td>
<td>[1, 2, 3, 1, 2, 3, 1]</td>
<td>8</td>
</tr>
<tr>
<td>4</td>
<td>3</td>
<td>[4, 1, 2, 2, 4, 4, 4, 4, 1, 2, 4, 2]</td>
<td>33</td>
</tr>
</tbody></table>
<hr>
<h3 id="입출력-예-설명">입출력 예 설명</h3>
<p><strong>입출력 예 #1</strong></p>
<ul>
<li>문제의 예시와 같습니다.</li>
</ul>
<p><strong>입출력 예 #2</strong></p>
<ul>
<li>다음과 같이 사과 상자를 포장하여 모두 팔면 최대 이익을 낼 수 있습니다.</li>
</ul>
<table>
<thead>
<tr>
<th>사과 상자</th>
<th>가격</th>
</tr>
</thead>
<tbody><tr>
<td>[1, 1, 2]</td>
<td>1 x 3 = 3</td>
</tr>
<tr>
<td>[2, 2, 2]</td>
<td>2 x 3 = 6</td>
</tr>
<tr>
<td>[4, 4, 4]</td>
<td>4 x 3 = 12</td>
</tr>
<tr>
<td>[4, 4, 4]</td>
<td>4 x 3 = 12</td>
</tr>
</tbody></table>
<p>따라서 (1 x 3 x 1) + (2 x 3 x 1) + (4 x 3 x 2) = 33을 return합니다.</p>
<h2 id="제출-코드">제출 코드</h2>
<ul>
<li>최초에 sort를 오름차순으로 정렬해서 로직을 구성해서 최대 수익으로 계산이 안됨</li>
<li>내림차순 정렬로 변경하여 계산 시 성공</li>
</ul>
<pre><code class="language-jsx">function solution(k, m, score) {
    let answer = 0;
    let arr = [];
    const sortedScore = score.sort((a, b) =&gt; b - a);
    for (let i = m-1; i&lt;score.length; i+=m){
        let temp = [];
        for(let j = i-(m-1); j&lt;=i; j++) {
            temp.push(sortedScore[j]);
        }
        arr.push(temp);
    }
    console.log(arr)
    for(let a of arr) {
        answer += a[a.length-1]*m;
    }
    return answer;
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[MonoRepo]]></title>
            <link>https://velog.io/@youseon__/MonoRepo</link>
            <guid>https://velog.io/@youseon__/MonoRepo</guid>
            <pubDate>Fri, 12 May 2023 16:24:38 GMT</pubDate>
            <description><![CDATA[<h1 id="monorepo란">Monorepo란</h1>
<p>⭐ <strong>여러개의 개발 프로젝트를, 잘 정의된 관계를 통해서 하나의 Repo에 담은것</strong></p>
<ul>
<li>새 project를 만드는데 편리</li>
<li>쉽게 다른 project에 기여 가능</li>
</ul>
<hr>
<h3 id="monorepo와-monolith-repo는-다름"><strong>monorepo와 monolith repo는 다름.</strong></h3>
<p><code>Monolithic</code>은 project 끼리 분리가 안되있고 거대하지만 <code>Monorepo</code>는 repo만 하나 일 뿐 project끼린 분리가 잘 되어 있다.</p>
<p>페이지를 구분 없이 섞어서 구성하고 마구잡이로 참조해 독립이라는 느낌이 안드는 모듈화 없는방식이 <code>Monolitic Repository</code>라고 한다면, <code>Monorepo</code>는 페이지가 같은 리포지토리에 있지만 확실히 구분을 짓는다. 서로 패키지처럼 참조하도록하고 코드 내부에는 참견하지 않도록 구성한다.</p>
<p>⭐ <strong>핵심은 모듈화</strong></p>
<ul>
<li>각 기능을 모듈로 잘 분리함으로써 캡슐화를 이룰 수 있다</li>
<li>기능이 잘 분리되어있으므로 대규모 프로젝트에서 수많은 코드를 들춰봐야 하는 수고를 줄인다.</li>
<li>소프트웨어 확장이 쉬워진다.</li>
<li>테스트가 쉬워지고, 모듈의 대체성을 높일 수 있으므로 A/B 테스트도 쉬워진다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/pjh1011409/post/cccc47b8-18bc-4b17-98ac-73ee5c515b45/image.png" alt="https://velog.velcdn.com/images/pjh1011409/post/cccc47b8-18bc-4b17-98ac-73ee5c515b45/image.png"></p>
<p><img src="https://velog.velcdn.com/images/pjh1011409/post/d54e8be3-c669-4bc3-a81c-e03c9611fd4c/image.png" alt="https://velog.velcdn.com/images/pjh1011409/post/d54e8be3-c669-4bc3-a81c-e03c9611fd4c/image.png"></p>
<p>모듈화 자체는 PolyRepo로도 잘 구축할 수 있지만, MonoRepo의 각 패키지를 넘나드는 작업이나 서로 참조하기가 쉽다는 특징과 모듈화가 잘 합쳐지면 그 시너지가 크다.</p>
<h3 id="polyrepo">Polyrepo</h3>
<p>일반적으로는 하나의 리포지토리에 하나의 프로젝트가 들어가게 된다. 각 프로젝트는 자율성이 높으며 독립적인 개발, 린트, 테스트, 빌드, 게시, 배포 파이프라인이 존재한다. 팀의 자율성이라는 큰 이유로 이 방식을 선호하지만 단점 또한 존재한다.</p>
<ul>
<li><strong>번거로운 프로젝트 생성</strong><ul>
<li>새로운 공유 패키지를 생성할 때마다 다음과 같이 번거로운 과정을 거친다.</li>
<li>저장소 생성 &gt; 커미터 추가 &gt; 개발 환경 구축 &gt; CI/CD 구축 &gt; 빌드 &gt; 패키지 저장소에 publish</li>
</ul>
</li>
<li><strong>패키지의 중복 코드 가능성</strong><ul>
<li>위의 번거로움을 피하기 위해 각 프로젝트에서 공통 구성 요소를 자체적으로 작성한다면, 초기 시간을 아낄 수 있지만 시간이 지날수록 보안 및 품질 관리 부담을 증가시킨다.</li>
</ul>
</li>
<li><strong>관리 포인트 증가</strong><ul>
<li>늘어난 프로젝트 저장소의 수만큼 관리 포인트가 늘어난다. 린트, 테스트, 개발 모드 실행, 빌드, 게시, 배포 등의 과정을 저장소의 수만큼 반복해야 한다.</li>
</ul>
</li>
<li><strong>일관성 없는 개발자 경험(DX)</strong><ul>
<li>각 프로젝트는 테스트 실행, 빌드, 테스트, 린트, 배포 등을 위해 고유한 명령 집합을 사용한다. 이러한 불일치는 여러 프로젝트에서 사용할 명령을 기억해야 하는 정신적 오버헤드를 만든다.</li>
</ul>
</li>
<li><strong>다른 패키지의 변경 사항 파악</strong><ul>
<li>관련 패키지의 변화를 지켜보거나 통지받지 않으면 문제가 발생할 수 있다.</li>
</ul>
</li>
<li><strong>교차 저장소의 리팩터링 비용</strong><ul>
<li>관련 패키지의 변화가 있을 때 여러 저장소에 걸쳐 변화를 반영하는 것은 쉬운 일이 아닐 것이다.</li>
</ul>
</li>
</ul>
<p><strong>참고</strong> <a href="https://tech.buzzvil.com/handbook/multirepo-vs-monorepo/">멀티리포 vs 모노리포</a></p>
<p><img src="https://velog.velcdn.com/images/pjh1011409/post/1606317a-0f81-4c3b-bb7f-0f58dcf85351/image.png" alt="https://velog.velcdn.com/images/pjh1011409/post/1606317a-0f81-4c3b-bb7f-0f58dcf85351/image.png"></p>
<hr>
<h1 id="장점">장점</h1>
<p>⭐<strong>Unified Versioning</strong></p>
<ul>
<li>하나의 레포지토리는 버전 관리를 한 번에 할 수 있다. 여러 레포지토리로 굴러갈 때는 각자 버전을 관리하다보니 누락되거나 다른 레포지토리와 연결할 때 버전을 계속 확인 및 맞춰줘야 하는 귀찮음이 있다.</li>
<li>하지만 한 레포지토리로 관리하면 아예 버전을 하나로 관리하거나, 여러 모듈의 버전을 관리하기 수월해진다.</li>
</ul>
<p>⭐<strong>Extensive Code Sharing &amp; Reuse</strong></p>
<ul>
<li>가끔은 다른 팀이 만든 코드에 있는걸 사용해야 할 때가 있다. 이를 적절히 공유하고 재사용할 수 있으므로 업무 효율을 높일 수 있다.</li>
</ul>
<p>⭐ <strong>Simplified Dependency Management</strong></p>
<ul>
<li>외부 라이브러리를 사용하는 경우도 분명히 있을텐데, 그런 외부 디펜던시의 버전을 맞추기 용이해진다. MonoRepo를 잘 사용하면 베이스 라이브러리만 변경되더라도 Final Product 단까지 잘 적용할 수 있다.</li>
</ul>
<p>⭐<strong>Atomic Changes</strong></p>
<ul>
<li><p>변경 사항을 보다 Atomic하게 관리할 수 있다.</p>
<p>  (원자적이라는 말은 더 쪼개지지 않는, 그 중간 과정을 확인할 수 없다는 의미로 받아들이면 된다.)</p>
</li>
<li><p>만약 어떤 라이브러리 코드를 바꿔서, 이를 이용하고 있는 다른 PolyRepo 레포지토리들을 돌아다니면서 하나 바꾸고 커밋 찍고, 또 하나 바꾸고 커밋 찍고… 이런 과정이 연속적으로 이뤄지게 된다. 이런게 변화하는 중간 과정이 보인다고 생각할 수 있다. 만약 각 커밋마다 테스트가 돌아간다면 각 레포에서 커밋을 찍을 때마다 테스트가 터져서 마음이 아프기도 할 것이다.</p>
</li>
<li><p>하지만 MonoRepo로 하면 어떤 변경 사항을 여러 독립된 프로젝트에서 적용해야 하면 한번에 고쳐서 하나의 커밋으로 관리할 수 있다. 이걸 변화 과정이 원자적이라고 말할 수 있을 것이다.</p>
</li>
</ul>
<p>⭐ <strong>Large Scale Refactoring</strong></p>
<ul>
<li>여러 독립적인 프로젝트에 적용되어야 하는 변화사항의 경우 각각 돌아다니면서 고치는 것보다는 한 레포지토리에서 고치는게 훨씬 쉽다.</li>
</ul>
<p>⭐ <strong>Flexible Team Boundaries and Code Ownership</strong></p>
<ul>
<li>팀 간 협업이 자유로워진다. 서로 같은 코드 베이스에서 일하고 있기 때문에 변경 사항이 있거나 협업할 일이 있으면 보다 유연하게 코드를 왔다갔다 할 수 있다. 동시에 코드에 대한 Ownership도 자유로워질 것이다.</li>
</ul>
<hr>
<h1 id="단점">단점</h1>
<p>⭐<strong>Dependency 충돌 문제</strong></p>
<ul>
<li>특정 패키지가 특정 버전의 모듈을 필요로 하는 경우, 다른 버전의 모듈을 사용하는 패키지와 Dependency 충돌이 발생할 수 있다.</li>
</ul>
<p>⭐ <strong>단일 리포지토리 문제</strong></p>
<ul>
<li>여러 프로젝트를 하나의 리포지토리에서 관리하기 때문에 오히려 관리가 어려워 질 수 있다.MonoRepo 로 관리하는 패키지가 많지 않을 경우에는 해당되지 않지만, 관리하는 패키지가 증가함에 따라 오히려 가독성이나 여러가지 측면에서 비효율적이게 될 수 있습니다.</li>
</ul>
<p>⭐ <strong>긴 초기 프로젝트 설정시간</strong></p>
<ul>
<li>MonoRepo 로 포함되는 모든 프로젝트를 사용한다면 상관없지만, 그 중 일부만 필요한 경우에도 node_module 설치가 이루어져야 한다.</li>
</ul>
<hr>
<h1 id="참고">참고</h1>
<p>팀규모, 프로덕트 규모에 따라서 정하는 것이 적절하다.</p>
<p>대규모 회사 또는 프로덕트를 가진 경우에는 어려 프로젝트를 한 개발팀이 담당할 경우가 많기 때문에 이런 경우에 MonoRepo를 사용하는 것이 좋다.</p>
<p> <a href="https://blog.mathpresso.com/%ED%8C%80%EC%9B%8C%ED%81%AC-%ED%96%A5%EC%83%81%EC%9D%84-%EC%9C%84%ED%95%9C-%EB%AA%A8%EB%85%B8%EB%A0%88%ED%8F%AC-monorepo-%EC%8B%9C%EC%8A%A4%ED%85%9C-%EA%B5%AC%EC%B6%95-3ae1b0112f1b">PolyRepo를 사용하던 콴다팀의 MonoRepo 변경 일지</a></p>
<p><a href="https://yeoulcoding.me/298">모노레포의 문화적 의의</a></p>
<p><a href="https://d2.naver.com/helloworld/0923884">모던 프론트엔드 프로젝트 구성 기법 - 모노레포 개념 편</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스] 게임 맵 최단거리]]></title>
            <link>https://velog.io/@youseon__/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EA%B2%8C%EC%9E%84-%EB%A7%B5-%EC%B5%9C%EB%8B%A8%EA%B1%B0%EB%A6%AC</link>
            <guid>https://velog.io/@youseon__/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EA%B2%8C%EC%9E%84-%EB%A7%B5-%EC%B5%9C%EB%8B%A8%EA%B1%B0%EB%A6%AC</guid>
            <pubDate>Mon, 27 Mar 2023 09:18:45 GMT</pubDate>
            <description><![CDATA[<hr>
<h2 id="문제">문제</h2>
<h3 id="문제-설명"><strong>문제 설명</strong></h3>
<p>ROR 게임은 두 팀으로 나누어서 진행하며, 상대 팀 진영을 먼저 파괴하면 이기는 게임입니다. 따라서, 각 팀은 상대 팀 진영에 최대한 빨리 도착하는 것이 유리합니다.</p>
<p>지금부터 당신은 한 팀의 팀원이 되어 게임을 진행하려고 합니다. 다음은 5 x 5 크기의 맵에, 당신의 캐릭터가 (행: 1, 열: 1) 위치에 있고, 상대 팀 진영은 (행: 5, 열: 5) 위치에 있는 경우의 예시입니다.</p>
<p><img src="https://grepp-programmers.s3.ap-northeast-2.amazonaws.com/files/production/dc3a1b49-13d3-4047-b6f8-6cc40b2702a7/%E1%84%8E%E1%85%AC%E1%84%83%E1%85%A1%E1%86%AB%E1%84%80%E1%85%A5%E1%84%85%E1%85%B51_sxuruo.png" alt="https://grepp-programmers.s3.ap-northeast-2.amazonaws.com/files/production/dc3a1b49-13d3-4047-b6f8-6cc40b2702a7/%E1%84%8E%E1%85%AC%E1%84%83%E1%85%A1%E1%86%AB%E1%84%80%E1%85%A5%E1%84%85%E1%85%B51_sxuruo.png"></p>
<p>위 그림에서 검은색 부분은 벽으로 막혀있어 갈 수 없는 길이며, 흰색 부분은 갈 수 있는 길입니다. 캐릭터가 움직일 때는 동, 서, 남, 북 방향으로 한 칸씩 이동하며, 게임 맵을 벗어난 길은 갈 수 없습니다.아래 예시는 캐릭터가 상대 팀 진영으로 가는 두 가지 방법을 나타내고 있습니다.</p>
<ul>
<li>첫 번째 방법은 11개의 칸을 지나서 상대 팀 진영에 도착했습니다.</li>
</ul>
<p><img src="https://grepp-programmers.s3.ap-northeast-2.amazonaws.com/files/production/9d909e5a-ca95-4088-9df9-d84cb804b2b0/%E1%84%8E%E1%85%AC%E1%84%83%E1%85%A1%E1%86%AB%E1%84%80%E1%85%A5%E1%84%85%E1%85%B52_hnjd3b.png" alt="https://grepp-programmers.s3.ap-northeast-2.amazonaws.com/files/production/9d909e5a-ca95-4088-9df9-d84cb804b2b0/%E1%84%8E%E1%85%AC%E1%84%83%E1%85%A1%E1%86%AB%E1%84%80%E1%85%A5%E1%84%85%E1%85%B52_hnjd3b.png"></p>
<ul>
<li>두 번째 방법은 15개의 칸을 지나서 상대팀 진영에 도착했습니다.</li>
</ul>
<p><img src="https://grepp-programmers.s3.ap-northeast-2.amazonaws.com/files/production/4b7cd629-a3c2-4e02-b748-a707211131de/%E1%84%8E%E1%85%AC%E1%84%83%E1%85%A1%E1%86%AB%E1%84%80%E1%85%A5%E1%84%85%E1%85%B53_ntxygd.png" alt="https://grepp-programmers.s3.ap-northeast-2.amazonaws.com/files/production/4b7cd629-a3c2-4e02-b748-a707211131de/%E1%84%8E%E1%85%AC%E1%84%83%E1%85%A1%E1%86%AB%E1%84%80%E1%85%A5%E1%84%85%E1%85%B53_ntxygd.png"></p>
<p>위 예시에서는 첫 번째 방법보다 더 빠르게 상대팀 진영에 도착하는 방법은 없으므로, 이 방법이 상대 팀 진영으로 가는 가장 빠른 방법입니다.</p>
<p>만약, 상대 팀이 자신의 팀 진영 주위에 벽을 세워두었다면 상대 팀 진영에 도착하지 못할 수도 있습니다. 예를 들어, 다음과 같은 경우에 당신의 캐릭터는 상대 팀 진영에 도착할 수 없습니다.</p>
<p><img src="https://grepp-programmers.s3.ap-northeast-2.amazonaws.com/files/production/d963b4bd-12e5-45da-9ca7-549e453d58a9/%E1%84%8E%E1%85%AC%E1%84%83%E1%85%A1%E1%86%AB%E1%84%80%E1%85%A5%E1%84%85%E1%85%B54_of9xfg.png" alt="https://grepp-programmers.s3.ap-northeast-2.amazonaws.com/files/production/d963b4bd-12e5-45da-9ca7-549e453d58a9/%E1%84%8E%E1%85%AC%E1%84%83%E1%85%A1%E1%86%AB%E1%84%80%E1%85%A5%E1%84%85%E1%85%B54_of9xfg.png"></p>
<p>게임 맵의 상태 maps가 매개변수로 주어질 때, 캐릭터가 상대 팀 진영에 도착하기 위해서 지나가야 하는 칸의 개수의 <strong>최솟값</strong>을 return 하도록 solution 함수를 완성해주세요. 단, 상대 팀 진영에 도착할 수 없을 때는 -1을 return 해주세요.</p>
<h3 id="제한사항">제한사항</h3>
<ul>
<li>maps는 n x m 크기의 게임 맵의 상태가 들어있는 2차원 배열로, n과 m은 각각 1 이상 100 이하의 자연수입니다.<ul>
<li>n과 m은 서로 같을 수도, 다를 수도 있지만, n과 m이 모두 1인 경우는 입력으로 주어지지 않습니다.</li>
</ul>
</li>
<li>maps는 0과 1로만 이루어져 있으며, 0은 벽이 있는 자리, 1은 벽이 없는 자리를 나타냅니다.</li>
<li>처음에 캐릭터는 게임 맵의 좌측 상단인 (1, 1) 위치에 있으며, 상대방 진영은 게임 맵의 우측 하단인 (n, m) 위치에 있습니다.</li>
</ul>
<hr>
<h3 id="입출력-예">입출력 예</h3>
<table>
<thead>
<tr>
<th>maps</th>
<th>answer</th>
</tr>
</thead>
<tbody><tr>
<td>[[1,0,1,1,1],[1,0,1,0,1],[1,0,1,1,1],[1,1,1,0,1],[0,0,0,0,1]]</td>
<td>11</td>
</tr>
<tr>
<td>[[1,0,1,1,1],[1,0,1,0,1],[1,0,1,1,1],[1,1,1,0,0],[0,0,0,0,1]]</td>
<td>-1</td>
</tr>
</tbody></table>
<h3 id="입출력-예-설명">입출력 예 설명</h3>
<p>입출력 예 #1주어진 데이터는 다음과 같습니다.</p>
<p><img src="https://grepp-programmers.s3.ap-northeast-2.amazonaws.com/files/production/6db71f7f-58d3-4623-9fab-7cd99fa863a5/%E1%84%8E%E1%85%AC%E1%84%83%E1%85%A1%E1%86%AB%E1%84%80%E1%85%A5%E1%84%85%E1%85%B56_lgjvrb.png" alt="https://grepp-programmers.s3.ap-northeast-2.amazonaws.com/files/production/6db71f7f-58d3-4623-9fab-7cd99fa863a5/%E1%84%8E%E1%85%AC%E1%84%83%E1%85%A1%E1%86%AB%E1%84%80%E1%85%A5%E1%84%85%E1%85%B56_lgjvrb.png"></p>
<p>캐릭터가 적 팀의 진영까지 이동하는 가장 빠른 길은 다음 그림과 같습니다.</p>
<p><img src="https://grepp-programmers.s3.ap-northeast-2.amazonaws.com/files/production/d223d017-b3e2-4772-9045-a565133d45ff/%E1%84%8E%E1%85%AC%E1%84%83%E1%85%A1%E1%86%AB%E1%84%80%E1%85%A5%E1%84%85%E1%85%B52_hnjd3b%20%281%29.png" alt="https://grepp-programmers.s3.ap-northeast-2.amazonaws.com/files/production/d223d017-b3e2-4772-9045-a565133d45ff/%E1%84%8E%E1%85%AC%E1%84%83%E1%85%A1%E1%86%AB%E1%84%80%E1%85%A5%E1%84%85%E1%85%B52_hnjd3b%20%281%29.png"></p>
<p>따라서 총 11칸을 캐릭터가 지나갔으므로 11을 return 하면 됩니다.</p>
<p>입출력 예 #2문제의 예시와 같으며, 상대 팀 진영에 도달할 방법이 없습니다. 따라서 -1을 return 합니다.</p>
<h2 id="알고리즘-분류">알고리즘 분류</h2>
<ul>
<li>bfs</li>
</ul>
<h2 id="제출-코드">제출 코드</h2>
<ul>
<li>다른 사람의 코드 참고함 ㅠ</li>
</ul>
<pre><code class="language-jsx">from collections import deque

def solution(maps):
    answer = 0
    n = len(maps)
    m = len(maps[0])
    visited = [[False]* m for _ in range(n)]

    # 동, 서, 남, 북
    position_x = [1,-1,0,0]
    position_y = [0,0,1,-1]

    queue = deque()
    queue.append((0,0)) # 시작
    visited[0][0]=True

    while queue:
        y, x = queue.popleft()

        # 동서남북 확인
        for i in range(4):
            nx = x + position_x[i]
            ny = y + position_y[i]
            # 벽이 아니고 1인 경우 확인
            if 0 &lt;= nx &lt; m and 0 &lt;= ny &lt; n and maps[ny][nx] == 1:
                if not visited[ny][nx]:
                    visited[ny][nx] = True
                    queue.append((ny, nx))
                    maps[ny][nx] = maps[y][x]+1
    if maps[n-1][m-1]==1:
        return -1
    else:
        return maps[n-1][m-1]</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스] 콜라 문제]]></title>
            <link>https://velog.io/@youseon__/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%BD%9C%EB%9D%BC-%EB%AC%B8%EC%A0%9C</link>
            <guid>https://velog.io/@youseon__/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%BD%9C%EB%9D%BC-%EB%AC%B8%EC%A0%9C</guid>
            <pubDate>Tue, 21 Mar 2023 12:07:27 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<h3 id="문제-설명"><strong>문제 설명</strong></h3>
<p>오래전 유행했던 콜라 문제가 있습니다. 콜라 문제의 지문은 다음과 같습니다.</p>
<blockquote>
<p>정답은 아무에게도 말하지 마세요.</p>
<p>콜라 빈 병 2개를 가져다주면 콜라 1병을 주는 마트가 있다. 빈 병 20개를 가져다주면 몇 병을 받을 수 있는가?</p>
<p>단, 보유 중인 빈 병이 2개 미만이면, 콜라를 받을 수 없다.</p>
</blockquote>
<p>문제를 풀던 상빈이는 콜라 문제의 완벽한 해답을 찾았습니다. 상빈이가 푼 방법은 아래 그림과 같습니다. 우선 콜라 빈 병 20병을 가져가서 10병을 받습니다. 받은 10병을 모두 마신 뒤, 가져가서 5병을 받습니다. 5병 중 4병을 모두 마신 뒤 가져가서 2병을 받고, 또 2병을 모두 마신 뒤 가져가서 1병을 받습니다. 받은 1병과 5병을 받았을 때 남은 1병을 모두 마신 뒤 가져가면 1병을 또 받을 수 있습니다. 이 경우 상빈이는 총 10 + 5 + 2 + 1 + 1 = 19병의 콜라를 받을 수 있습니다.</p>
<p><img src="https://grepp-programmers.s3.ap-northeast-2.amazonaws.com/files/production/95ce1c11-2f21-4248-8bfc-e330299cbb9a/image6.PNG" alt="https://grepp-programmers.s3.ap-northeast-2.amazonaws.com/files/production/95ce1c11-2f21-4248-8bfc-e330299cbb9a/image6.PNG"></p>
<p>문제를 열심히 풀던 상빈이는 일반화된 콜라 문제를 생각했습니다. 이 문제는 빈 병 <code>a</code>개를 가져다주면 콜라 <code>b</code>병을 주는 마트가 있을 때, 빈 병 <code>n</code>개를 가져다주면 몇 병을 받을 수 있는지 계산하는 문제입니다. 기존 콜라 문제와 마찬가지로, 보유 중인 빈 병이 <code>a</code>개 미만이면, 추가적으로 빈 병을 받을 순 없습니다. 상빈이는 열심히 고심했지만, 일반화된 콜라 문제의 답을 찾을 수 없었습니다. 상빈이를 도와, 일반화된 콜라 문제를 해결하는 프로그램을 만들어 주세요.</p>
<p>콜라를 받기 위해 마트에 주어야 하는 병 수 <code>a</code>, 빈 병 a개를 가져다 주면 마트가 주는 콜라 병 수 <code>b</code>, 상빈이가 가지고 있는 빈 병의 개수 <code>n</code>이 매개변수로 주어집니다. 상빈이가 받을 수 있는 콜라의 병 수를 return 하도록 solution 함수를 작성해주세요.</p>
<hr>
<h3 id="제한사항">제한사항</h3>
<ul>
<li>1 ≤ <code>b</code> &lt; <code>a</code> ≤ <code>n</code> ≤ 1,000,000</li>
<li>정답은 항상 int 범위를 넘지 않게 주어집니다.</li>
</ul>
<hr>
<h3 id="입출력-예">입출력 예</h3>
<table>
<thead>
<tr>
<th>a</th>
<th>b</th>
<th>n</th>
<th>result</th>
</tr>
</thead>
<tbody><tr>
<td>2</td>
<td>1</td>
<td>20</td>
<td>19</td>
</tr>
<tr>
<td>3</td>
<td>1</td>
<td>20</td>
<td>9</td>
</tr>
</tbody></table>
<hr>
<h3 id="입출력-예-설명">입출력 예 설명</h3>
<p><strong>입출력 예 #1</strong></p>
<ul>
<li>본문에서 설명한 예시입니다.</li>
</ul>
<p><strong>입출력 예 #2</strong></p>
<ul>
<li>빈 병 20개 중 18개를 마트에 가져가서, 6병의 콜라를 받습니다. 이때 상빈이가 가지고 있는 콜라 병의 수는 8(20 – 18 + 6 = 8)개 입니다.</li>
<li>빈 병 8개 중 6개를 마트에 가져가서, 2병의 콜라를 받습니다. 이때 상빈이가 가지고 있는 콜라 병의 수는 4(8 – 6 + 2 = 4)개 입니다.</li>
<li>빈 병 4 개중 3개를 마트에 가져가서, 1병의 콜라를 받습니다. 이때 상빈이가 가지고 있는 콜라 병의 수는 2(4 – 3 + 1 = 2)개 입니다.</li>
<li>3번의 교환 동안 상빈이는 9(6 + 2 + 1 = 9)병의 콜라를 받았습니다.</li>
</ul>
<h2 id="제출-코드">제출 코드</h2>
<pre><code class="language-jsx">function solution(a, b, n) {
    var answer = 0;
    let bottle = n;
    console.log(Math.floor(bottle / a));
    while (Math.floor(bottle / a) &gt;= 1) {
        const sell =  Math.floor(bottle / a) * a;
        // 가져다 줄 수 있는 병 체크
        if(sell &gt; 1){
            answer += Math.floor(bottle / a) * b;
            bottle = bottle - sell + (Math.floor(bottle / a) * b);
        }
    }
    return answer;
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스] 소수 만들기]]></title>
            <link>https://velog.io/@youseon__/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%86%8C%EC%88%98-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@youseon__/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%86%8C%EC%88%98-%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Tue, 21 Mar 2023 11:35:47 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<h3 id="문제-설명"><strong>문제 설명</strong></h3>
<p>주어진 숫자 중 3개의 수를 더했을 때 소수가 되는 경우의 개수를 구하려고 합니다. 숫자들이 들어있는 배열 nums가 매개변수로 주어질 때, nums에 있는 숫자들 중 서로 다른 3개를 골라 더했을 때 소수가 되는 경우의 개수를 return 하도록 solution 함수를 완성해주세요.</p>
<h3 id="제한사항">제한사항</h3>
<ul>
<li>nums에 들어있는 숫자의 개수는 3개 이상 50개 이하입니다.</li>
<li>nums의 각 원소는 1 이상 1,000 이하의 자연수이며, 중복된 숫자가 들어있지 않습니다.</li>
</ul>
<hr>
<h3 id="입출력-예">입출력 예</h3>
<table>
<thead>
<tr>
<th>nums</th>
<th>result</th>
</tr>
</thead>
<tbody><tr>
<td>[1,2,3,4]</td>
<td>1</td>
</tr>
<tr>
<td>[1,2,7,6,4]</td>
<td>4</td>
</tr>
</tbody></table>
<h3 id="입출력-예-설명">입출력 예 설명</h3>
<p>입출력 예 #1[1,2,4]를 이용해서 7을 만들 수 있습니다.</p>
<p>입출력 예 #2[1,2,4]를 이용해서 7을 만들 수 있습니다.[1,4,6]을 이용해서 11을 만들 수 있습니다.[2,4,7]을 이용해서 13을 만들 수 있습니다.[4,6,7]을 이용해서 17을 만들 수 있습니다.</p>
<h2 id="제출-코드">제출 코드</h2>
<pre><code class="language-jsx">function solution(nums) {
    var answer = 0;
    const len = nums.length;
    for(let i = 0; i &lt; len; i++) {
        for(let j = i+1; j &lt; len; j++) {
            for(let k = j+1; k &lt; len; k++) {
                const sum = nums[i] + nums[j] + nums[k];
                if(check(sum)) answer++;
            }
        }
    }

    return answer;
}

// 소수 판별 알고리즘
function check(num) {
    for (let i=2; i&lt;=num-1; i++){
        if(num % i === 0) {
           return false;
         }
    }
    return true;
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준] 바이러스]]></title>
            <link>https://velog.io/@youseon__/%EB%B0%B1%EC%A4%80-%EB%B0%94%EC%9D%B4%EB%9F%AC%EC%8A%A4</link>
            <guid>https://velog.io/@youseon__/%EB%B0%B1%EC%A4%80-%EB%B0%94%EC%9D%B4%EB%9F%AC%EC%8A%A4</guid>
            <pubDate>Mon, 20 Mar 2023 09:42:02 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<p>신종 바이러스인 웜 바이러스는 네트워크를 통해 전파된다. 한 컴퓨터가 웜 바이러스에 걸리면 그 컴퓨터와 네트워크 상에서 연결되어 있는 모든 컴퓨터는 웜 바이러스에 걸리게 된다.</p>
<p>예를 들어 7대의 컴퓨터가 &lt;그림 1&gt;과 같이 네트워크 상에서 연결되어 있다고 하자. 1번 컴퓨터가 웜 바이러스에 걸리면 웜 바이러스는 2번과 5번 컴퓨터를 거쳐 3번과 6번 컴퓨터까지 전파되어 2, 3, 5, 6 네 대의 컴퓨터는 웜 바이러스에 걸리게 된다. 하지만 4번과 7번 컴퓨터는 1번 컴퓨터와 네트워크상에서 연결되어 있지 않기 때문에 영향을 받지 않는다.</p>
<p><img src="https://www.acmicpc.net/upload/images/zmMEZZ8ioN6rhCdHmcIT4a7.png" alt="https://www.acmicpc.net/upload/images/zmMEZZ8ioN6rhCdHmcIT4a7.png"></p>
<p>어느 날 1번 컴퓨터가 웜 바이러스에 걸렸다. 컴퓨터의 수와 네트워크 상에서 서로 연결되어 있는 정보가 주어질 때, 1번 컴퓨터를 통해 웜 바이러스에 걸리게 되는 컴퓨터의 수를 출력하는 프로그램을 작성하시오.</p>
<h3 id="입력">입력</h3>
<p>첫째 줄에는 컴퓨터의 수가 주어진다. 컴퓨터의 수는 100 이하이고 각 컴퓨터에는 1번 부터 차례대로 번호가 매겨진다. 둘째 줄에는 네트워크 상에서 직접 연결되어 있는 컴퓨터 쌍의 수가 주어진다. 이어서 그 수만큼 한 줄에 한 쌍씩 네트워크 상에서 직접 연결되어 있는 컴퓨터의 번호 쌍이 주어진다.</p>
<h3 id="출력">출력</h3>
<p>1번 컴퓨터가 웜 바이러스에 걸렸을 때, 1번 컴퓨터를 통해 웜 바이러스에 걸리게 되는 컴퓨터의 수를 첫째 줄에 출력한다.</p>
<h2 id="알고리즘-분류">알고리즘 분류</h2>
<ul>
<li><a href="https://www.acmicpc.net/problem/tag/7">그래프 이론</a></li>
<li><a href="https://www.acmicpc.net/problem/tag/11">그래프 탐색</a></li>
<li><a href="https://www.acmicpc.net/problem/tag/126">너비 우선 탐색</a></li>
<li><a href="https://www.acmicpc.net/problem/tag/127">깊이 우선 탐색</a></li>
</ul>
<h2 id="제출-코드">제출 코드</h2>
<ul>
<li>이전 dfs, bfs 문제를 열심히 풀어서.. 쉽게 풀었는데 1부터 시작해서 1 본인을 제외하는 -1을 놓침</li>
</ul>
<pre><code class="language-python">import sys

sys.setrecursionlimit(10**9)
input = sys.stdin.readline
#  컴퓨터의 수
n = int(input())
# 네트워크 상에서 직접 연결되어 있는 컴퓨터 쌍의 수
m = int(input())
graph = [[] for _ in range(n + 1)]
visited = [False] * (n+1)

for _ in range(m):
    a, b = map(int, input().split())
    graph[a].append(b)
    graph[b].append(a)

def dfs(value):
    visited[value] = True
    for v in graph[value]:
        if visited[v] == False:
            dfs(v)

dfs(1)
print(visited.count(True)-1)</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준] dfs와 bfs]]></title>
            <link>https://velog.io/@youseon__/%EB%B0%B1%EC%A4%80-dfs%EC%99%80-bfs</link>
            <guid>https://velog.io/@youseon__/%EB%B0%B1%EC%A4%80-dfs%EC%99%80-bfs</guid>
            <pubDate>Mon, 20 Mar 2023 09:41:01 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<p>그래프를 DFS로 탐색한 결과와 BFS로 탐색한 결과를 출력하는 프로그램을 작성하시오. 단, 방문할 수 있는 정점이 여러 개인 경우에는 정점 번호가 작은 것을 먼저 방문하고, 더 이상 방문할 수 있는 점이 없는 경우 종료한다. 정점 번호는 1번부터 N번까지이다.</p>
<h3 id="입력">입력</h3>
<p>첫째 줄에 정점의 개수 N(1 ≤ N ≤ 1,000), 간선의 개수 M(1 ≤ M ≤ 10,000), 탐색을 시작할 정점의 번호 V가 주어진다. 다음 M개의 줄에는 간선이 연결하는 두 정점의 번호가 주어진다. 어떤 두 정점 사이에 여러 개의 간선이 있을 수 있다. 입력으로 주어지는 간선은 양방향이다.</p>
<h3 id="출력">출력</h3>
<p>첫째 줄에 DFS를 수행한 결과를, 그 다음 줄에는 BFS를 수행한 결과를 출력한다. V부터 방문된 점을 순서대로 출력하면 된다.</p>
<h3 id="예제-입력-1">예제 입력 1</h3>
<pre><code>4 5 1
1 2
1 3
1 4
2 4
3 4
</code></pre><h3 id="예제-출력-1">예제 출력 1</h3>
<pre><code>1 2 4 3
1 2 3 4
</code></pre><h3 id="예제-입력-2">예제 입력 2</h3>
<pre><code>5 5 3
5 4
5 2
1 2
3 4
3 1
</code></pre><h3 id="예제-출력-2">예제 출력 2</h3>
<pre><code>3 1 2 5 4
3 1 4 2 5
</code></pre><h3 id="예제-입력-3">예제 입력 3</h3>
<pre><code>1000 1 1000
999 1000
</code></pre><h3 id="예제-출력-3">예제 출력 3</h3>
<pre><code>1000 999
1000 999
</code></pre><h2 id="알고리즘">알고리즘</h2>
<ul>
<li><a href="https://www.acmicpc.net/problem/tag/7">그래프 이론</a></li>
<li><a href="https://www.acmicpc.net/problem/tag/11">그래프 탐색</a></li>
<li><a href="https://www.acmicpc.net/problem/tag/126">너비 우선 탐색</a></li>
<li><a href="https://www.acmicpc.net/problem/tag/127">깊이 우선 탐색</a></li>
</ul>
<h2 id="제출-코드">제출 코드</h2>
<ul>
<li>몇 부분이 헷갈리는 부분이 있지만 DFS는 어느정도 개념을 숙지함</li>
<li>BFS는 할때마다 헷갈림..</li>
</ul>
<pre><code class="language-python">from collections import deque

n, m, v = map(int, input().split())

graph = [[] for _ in range(n + 1)]

for i in range(m):
    a, b = map(int, input().split())
    graph[a].append(b)
    graph[b].append(a)
    graph[a].sort()
    graph[b].sort()

dfs_visited = [False] * (n + 1)
bfs_visited = [False] * (n + 1)

def DFS(v):
    dfs_visited[v] = True
    print(v, end=&#39; &#39;)
    for i in graph[v]:
        if not dfs_visited[i]:
            DFS(i)

def BFS(v):
    queue = deque([v])
    bfs_visited[v] = True
    while queue:  # 더이상 큐에 아무것도 남아 있지 않을때까지 반복
        pop = queue.popleft()
        print(pop, end=&#39; &#39;)
        for i in graph[pop]:
            if not bfs_visited[i]:
                queue.append(i)  # 방문할 때 큐에 넣기
                bfs_visited[i] = True

DFS(v)
print() # print 없으면 같은 줄에 출력됨
BFS(v)</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[vue3 code editor 라이브러리 사용하기]]></title>
            <link>https://velog.io/@youseon__/vue3-code-editor-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@youseon__/vue3-code-editor-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</guid>
            <pubDate>Mon, 20 Mar 2023 09:33:50 GMT</pubDate>
            <description><![CDATA[<h2 id="개발-목적">개발 목적</h2>
<ul>
<li>현재 프로젝트에서 코드 에디터 관련 기능을 제공해야 함. -&gt; 미리 실험적으로 구현 가능 여부와 제공할 기능 범위 파악이 필요하여 기본적인 기능 구현이 필요했음. 기본적인 기능 구현 외에도 기능을 추가하여 공통 컴포넌트화 하여 사용 할 수 있음. </li>
</ul>
<h2 id="사용한-라이브러리">사용한 라이브러리</h2>
<ul>
<li><p>vue3-ace-editor</p>
<p>  <a href="https://github.com/CarterLi/vue3-ace-editor">https://github.com/CarterLi/vue3-ace-editor</a></p>
</li>
</ul>
<h2 id="사용-환경">사용 환경</h2>
<ul>
<li>typescript</li>
<li>vite</li>
<li>vue3</li>
</ul>
<h2 id="설치">설치</h2>
<pre><code class="language-python">npm i vue3-ace-editor --save</code></pre>
<h2 id="사용-방법">사용 방법</h2>
<h3 id="1-config파일-작성">1. config파일 작성</h3>
<ul>
<li><p>ace-editor에서 구문 체크나 검색 박스 등의 추가 기능을 사용하기 위해서는 config 파일을 import 해서 사용해야 한다. 따라서, config폴더 하위에 aceConfig파일을 생성한다.</p>
<pre><code class="language-jsx">  import ace from &#39;ace-builds&#39;;

  import modeJsonUrl from &#39;ace-builds/src-noconflict/mode-json?url&#39;;
  ace.config.setModuleUrl(&#39;ace/mode/json&#39;, modeJsonUrl);

  import modeJavascriptUrl from &#39;ace-builds/src-noconflict/mode-javascript?url&#39;;
  ace.config.setModuleUrl(&#39;ace/mode/javascript&#39;, modeJavascriptUrl);

  import modeHtmlUrl from &#39;ace-builds/src-noconflict/mode-html?url&#39;;
  ace.config.setModuleUrl(&#39;ace/mode/html&#39;, modeHtmlUrl);

  import modeYamlUrl from &#39;ace-builds/src-noconflict/mode-yaml?url&#39;;
  ace.config.setModuleUrl(&#39;ace/mode/yaml&#39;, modeYamlUrl);

  import themeGithubUrl from &#39;ace-builds/src-noconflict/theme-github?url&#39;;
  ace.config.setModuleUrl(&#39;ace/theme/github&#39;, themeGithubUrl);

  import themeChromeUrl from &#39;ace-builds/src-noconflict/theme-chrome?url&#39;;
  ace.config.setModuleUrl(&#39;ace/theme/chrome&#39;, themeChromeUrl);

  import themeMonokaiUrl from &#39;ace-builds/src-noconflict/theme-monokai?url&#39;;
  ace.config.setModuleUrl(&#39;ace/theme/monokai&#39;, themeMonokaiUrl);

  import workerBaseUrl from &#39;ace-builds/src-noconflict/worker-base?url&#39;;
  ace.config.setModuleUrl(&#39;ace/mode/base&#39;, workerBaseUrl);

  import workerJsonUrl from &#39;ace-builds/src-noconflict/worker-json?url&#39;;
  ace.config.setModuleUrl(&#39;ace/mode/json_worker&#39;, workerJsonUrl);

  import workerJavascriptUrl from &#39;ace-builds/src-noconflict/worker-javascript?url&#39;;
  ace.config.setModuleUrl(&#39;ace/mode/javascript_worker&#39;, workerJavascriptUrl);

  import workerHtmlUrl from &#39;ace-builds/src-noconflict/worker-html?url&#39;;
  ace.config.setModuleUrl(&#39;ace/mode/html_worker&#39;, workerHtmlUrl);

  import workerYamlUrl from &#39;ace-builds/src-noconflict/worker-yaml?url&#39;;
  ace.config.setModuleUrl(&#39;ace/mode/yaml_worker&#39;, workerYamlUrl);

  import snippetsHtmlUrl from &#39;ace-builds/src-noconflict/snippets/html?url&#39;;
  ace.config.setModuleUrl(&#39;ace/snippets/html&#39;, snippetsHtmlUrl);

  import snippetsJsUrl from &#39;ace-builds/src-noconflict/snippets/javascript?url&#39;;
  ace.config.setModuleUrl(&#39;ace/snippets/javascript&#39;, snippetsJsUrl);

  import snippetsYamlUrl from &#39;ace-builds/src-noconflict/snippets/yaml?url&#39;;
  ace.config.setModuleUrl(&#39;ace/snippets/javascript&#39;, snippetsYamlUrl);

  import snippetsJsonUrl from &#39;ace-builds/src-noconflict/snippets/json?url&#39;;
  ace.config.setModuleUrl(&#39;ace/snippets/json&#39;, snippetsJsonUrl);

  import &#39;ace-builds/src-noconflict/ext-language_tools&#39;;
  import &#39;ace-builds/src-noconflict/ext-searchbox&#39;;
  ace.require(&#39;ace/ext/language_tools&#39;);
  ace.require(&#39;ace/ext/searchbox&#39;);

  export default ace;</code></pre>
</li>
</ul>
<h3 id="2-code-editor-컴포넌트-생성">2. code editor 컴포넌트 생성</h3>
<ol>
<li><p>CodeEditor.vue 파일을 생성한다. (이름 마음대로 생성)</p>
</li>
<li><p>config 파일과 vue3-ace-editor 라이브러리를 import 한다.</p>
<pre><code class="language-jsx"> &lt;script setup lang=&quot;ts&quot;&gt;
 import { ref, onMounted } from &#39;vue&#39;;
 import &#39;@config/aceConfig&#39;; // 코드 에디터 설정 (필요시 추가 설정 후 임포트해서 사용)
 import { VAceEditor } from &#39;vue3-ace-editor&#39;;</code></pre>
</li>
<li><p>코드 에디터로 표시할 language와 테마 등 옵션과 변수를 설정한다. (props로 부모 컴포넌트에서 값을 받아오는 방법으로 수정 가능함)</p>
<pre><code class="language-jsx"> const lang = &#39;json&#39;; // json / html / yaml / javascript 등등
 const theme = &#39;github&#39;; // monokai / github 등등

 const options = {
   cursorStyle: &#39;wide&#39;,
   useWorker: true,
   enableBasicAutocompletion: true,
   enableSnippets: true,
   enableLiveAutocompletion: true,
   highlightSelectedWord: true,
 };

 let edit = ref&lt;typeof VAceEditor | null&gt;(null);
 let value = ref&lt;string&gt;(&#39;&#39;);</code></pre>
</li>
<li><p>코드 에디터 Init 함수와 Json을 불러오는 Init 함수를 작성한다. (해당 예시에선 vue의 package.json 파일을 불러온다.)</p>
<pre><code class="language-jsx"> // 코드 에디터 Init 함수
 function editorInit(editor: typeof VAceEditor) {
   edit.value = editor;
 }

 // 예시 Json Init 
 async function initJson() {
   value.value = &#39;&#39;;
   value.value = (await import(&#39;../../../../package.json?raw&#39;)).default;
 }</code></pre>
</li>
<li><p>Vue의 onMounted 사이클에서 InitJson 함수를 호출하는 코드를 작성한다.</p>
<pre><code class="language-jsx"> onMounted(() =&gt; {
   initJson();
 });</code></pre>
</li>
<li><p>템플릿 태그 안에 코드 에디터 태그를 사용하여 코드 에디터를 화면에 표시한다.</p>
<pre><code class="language-jsx"> &lt;template&gt;
     &lt;div class=&quot;code-wrap&quot;&gt;
           &lt;v-ace-editor
             v-model:value=&quot;value&quot;
             :lang=&quot;lang&quot;
             :theme=&quot;theme&quot;
             :options=&quot;options&quot;
             :readonly=&quot;true&quot;
             :wrap=&quot;true&quot;
             :default=&quot;true&quot;
             :min-lines=&quot;20&quot;
             :max-lines=&quot;30&quot;
             @init=&quot;editorInit&quot;
           /&gt;
     &lt;/div&gt;
 &lt;/template&gt;</code></pre>
</li>
</ol>
<h3 id="3-단어-검색-및-코드-펼치기-접기-기능-추가">3. 단어 검색 및 코드 펼치기 접기 기능 추가</h3>
<ol>
<li><p>검색창, 이전/다음 버튼 UI와 펼치기 접기 버튼을 추가로 만들고 code editor에서 제공하는 아래 함수들을 이용하여 기능을 추가 제공 할 수 있다. </p>
<pre><code class="language-jsx"> // 코드 검색
 function onFind(keyword) {
   if (edit.value) {
     edit.value.findAll(keyword, {
       backwards: false,
       wrap: true,
       caseSensitive: false,
       wholeWord: false,
       regExp: true,
     });
   }
 }

 // 다음 검색
 function onNext() {
   if (edit.value) {
     edit.value.findNext();
   }
 }
 // 이전 검색
 function onPrevious() {
   if (edit.value) {
     edit.value.findPrevious();
   }
 }
 //펼치기
 function onFold() {
   if (edit.value) {
     edit.value.session.expandFolds(edit.value.session.getAllFolds());
   }
 }
 // 접기
 function onUnFold() {
   if (edit.value) {
     edit.value.session.foldAll();
   }</code></pre>
</li>
</ol>
<h2 id="참고">참고</h2>
<ul>
<li><p>설정 옵션</p>
<p>  <a href="https://github.com/ajaxorg/ace/wiki/Configuring-Ace#editor-options">Configuring Ace</a></p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스] 없는 숫자 더하기]]></title>
            <link>https://velog.io/@youseon__/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%97%86%EB%8A%94-%EC%88%AB%EC%9E%90-%EB%8D%94%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@youseon__/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%97%86%EB%8A%94-%EC%88%AB%EC%9E%90-%EB%8D%94%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sat, 04 Feb 2023 13:56:00 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<p>0부터 9까지의 숫자 중 일부가 들어있는 정수 배열 <code>numbers</code>가 매개변수로 주어집니다. <code>numbers</code>에서 찾을 수 없는 0부터 9까지의 숫자를 모두 찾아 더한 수를 return 하도록 solution 함수를 완성해주세요.</p>
<hr>
<h3 id="제한사항">제한사항</h3>
<ul>
<li>1 ≤ <code>numbers</code>의 길이 ≤ 9<ul>
<li>0 ≤ <code>numbers</code>의 모든 원소 ≤ 9</li>
<li><code>numbers</code>의 모든 원소는 서로 다릅니다.</li>
</ul>
</li>
</ul>
<hr>
<h3 id="입출력-예">입출력 예</h3>
<table>
<thead>
<tr>
<th>numbers</th>
<th>result</th>
</tr>
</thead>
<tbody><tr>
<td>[1,2,3,4,6,7,8,0]</td>
<td>14</td>
</tr>
<tr>
<td>[5,8,4,0,6,7,9]</td>
<td>6</td>
</tr>
</tbody></table>
<hr>
<h3 id="입출력-예-설명">입출력 예 설명</h3>
<p><strong>입출력 예 #1</strong></p>
<ul>
<li>5, 9가 <code>numbers</code>에 없으므로, 5 + 9 = 14를 return 해야 합니다.</li>
</ul>
<p><strong>입출력 예 #2</strong></p>
<ul>
<li>1, 2, 3이 <code>numbers</code>에 없으므로, 1 + 2 + 3 = 6을 return 해야 합니다.</li>
</ul>
<h2 id="제출-코드">제출 코드</h2>
<ul>
<li>분명.. 더 쉬운 방법이 있을거라는 생각을 하긴 했는데 생각나는대로 바로 써내려감..</li>
</ul>
<pre><code class="language-python">def solution(numbers):

    answer = -1
    compare = [1,2,3,4,5,6,7,8,9]
    for num in compare:
        if num not in numbers:
            if answer == -1 : answer = 0
            answer += num
    return answer</code></pre>
<h2 id="다른-사람-코드">다른 사람 코드</h2>
<ul>
<li>ㅎㅎ 나만 바보된 것 같은 알고리즘이다.. 두줄이면 끝나는거였다니.. 문제를 보면 어차피 숫자는 한개씩만 나온다고 했어서 1~9까지 모두 더한 합계 45에서 빼기를 하면 되는 문제였다.</li>
</ul>
<pre><code class="language-python">def solution(numbers):
    return 45 - sum(numbers)</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스] 가장 가까운 글자]]></title>
            <link>https://velog.io/@youseon__/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EA%B0%80%EC%9E%A5-%EA%B0%80%EA%B9%8C%EC%9A%B4-%EA%B8%80%EC%9E%90</link>
            <guid>https://velog.io/@youseon__/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EA%B0%80%EC%9E%A5-%EA%B0%80%EA%B9%8C%EC%9A%B4-%EA%B8%80%EC%9E%90</guid>
            <pubDate>Sat, 04 Feb 2023 04:51:15 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<h3 id="문제-설명"><strong>문제 설명</strong></h3>
<p>문자열 <code>s</code>가 주어졌을 때, <code>s</code>의 각 위치마다 자신보다 앞에 나왔으면서, 자신과 가장 가까운 곳에 있는 같은 글자가 어디 있는지 알고 싶습니다.예를 들어, <code>s</code>=&quot;banana&quot;라고 할 때,  각 글자들을 왼쪽부터 오른쪽으로 읽어 나가면서 다음과 같이 진행할 수 있습니다.</p>
<ul>
<li>b는 처음 나왔기 때문에 자신의 앞에 같은 글자가 없습니다. 이는 -1로 표현합니다.</li>
<li>a는 처음 나왔기 때문에 자신의 앞에 같은 글자가 없습니다. 이는 -1로 표현합니다.</li>
<li>n은 처음 나왔기 때문에 자신의 앞에 같은 글자가 없습니다. 이는 -1로 표현합니다.</li>
<li>a는 자신보다 두 칸 앞에 a가 있습니다. 이는 2로 표현합니다.</li>
<li>n도 자신보다 두 칸 앞에 n이 있습니다. 이는 2로 표현합니다.</li>
<li>a는 자신보다 두 칸, 네 칸 앞에 a가 있습니다. 이 중 가까운 것은 두 칸 앞이고, 이는 2로 표현합니다.</li>
</ul>
<p>따라서 최종 결과물은 [-1, -1, -1, 2, 2, 2]가 됩니다.</p>
<p>문자열 <code>s</code>이 주어질 때, 위와 같이 정의된 연산을 수행하는 함수 solution을 완성해주세요.</p>
<hr>
<h3 id="제한사항">제한사항</h3>
<ul>
<li>1 ≤ <code>s</code>의 길이 ≤ 10,000<ul>
<li><code>s</code>은 영어 소문자로만 이루어져 있습니다.</li>
</ul>
</li>
</ul>
<hr>
<h3 id="입출력-예">입출력 예</h3>
<table>
<thead>
<tr>
<th>s</th>
<th>result</th>
</tr>
</thead>
<tbody><tr>
<td>&quot;banana&quot;</td>
<td>[-1, -1, -1, 2, 2, 2]</td>
</tr>
<tr>
<td>&quot;foobar&quot;</td>
<td>[-1, -1, 1, -1, -1, -1]</td>
</tr>
</tbody></table>
<hr>
<h3 id="입출력-예-설명">입출력 예 설명</h3>
<p>입출력 예 #1지문과 같습니다.</p>
<p>입출력 예 #2설명 생략</p>
<h2 id="알고리즘">알고리즘</h2>
<ul>
<li><strong>완전 탐색 = 모든 경우의 수를 다 체크해서 정답을 찾는 방법</strong></li>
</ul>
<h2 id="제출-코드">제출 코드</h2>
<ul>
<li><p>나의 문제 풀이 방법</p>
<p>  처음에 파이썬의 rfind함수를 활용하여 반복문 돌면서 현재 위치를 기준으로 뒤쪽에서부터 찾는 로직을 짰는데 테스트 케이스에서 4문제 정도 실패하였다.</p>
</li>
</ul>
<pre><code class="language-python">def solution(s):
    set_idx = {}
    answer = []
    for index, char in enumerate(s):
        if char in set_idx: # 딕셔너리에서 해당 알파벳 키 있는지 확인(최종 마지막값 저장)
            answer.append(index-set_idx[char])
            set_idx[char] = index
        else:
            answer.append(-1)
            set_idx[char] = index

    return answer</code></pre>
<h2 id="다른-사람의-풀이">다른 사람의 풀이</h2>
<ul>
<li>rfind 함수 활용</li>
</ul>
<pre><code class="language-python">def solution(s):
    answer = []

    for i in range((len(s))):
        t = s[:i]
        idx = t.rfind(s[i])
        if idx == -1:
            answer.append(-1)
        else:
            answer.append(i-idx)

    return answer</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스] 크기가 작은 부분 문자열]]></title>
            <link>https://velog.io/@youseon__/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%ED%81%AC%EA%B8%B0%EA%B0%80-%EC%9E%91%EC%9D%80-%EB%B6%80%EB%B6%84-%EB%AC%B8%EC%9E%90%EC%97%B4</link>
            <guid>https://velog.io/@youseon__/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%ED%81%AC%EA%B8%B0%EA%B0%80-%EC%9E%91%EC%9D%80-%EB%B6%80%EB%B6%84-%EB%AC%B8%EC%9E%90%EC%97%B4</guid>
            <pubDate>Mon, 30 Jan 2023 13:01:18 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<h3 id="문제-설명"><strong>문제 설명</strong></h3>
<p>숫자로 이루어진 문자열 <code>t</code>와 <code>p</code>가 주어질 때, <code>t</code>에서 <code>p</code>와 길이가 같은 부분문자열 중에서, 이 부분문자열이 나타내는 수가 <code>p</code>가 나타내는 수보다 작거나 같은 것이 나오는 횟수를 return하는 함수 solution을 완성하세요.</p>
<p>예를 들어, <code>t</code>=&quot;3141592&quot;이고 <code>p</code>=&quot;271&quot; 인 경우, <code>t</code>의 길이가 3인 부분 문자열은 314, 141, 415, 159, 592입니다. 이 문자열이 나타내는 수 중 271보다 작거나 같은 수는 141, 159 2개 입니다.</p>
<hr>
<h3 id="제한사항">제한사항</h3>
<ul>
<li>1 ≤ <code>p</code>의 길이 ≤ 18</li>
<li><code>p</code>의 길이 ≤ <code>t</code>의 길이 ≤ 10,000</li>
<li><code>t</code>와 <code>p</code>는 숫자로만 이루어진 문자열이며, 0으로 시작하지 않습니다.</li>
</ul>
<hr>
<h3 id="입출력-예">입출력 예</h3>
<table>
<thead>
<tr>
<th>t</th>
<th>p</th>
<th>result</th>
</tr>
</thead>
<tbody><tr>
<td>&quot;3141592&quot;</td>
<td>&quot;271&quot;</td>
<td>2</td>
</tr>
<tr>
<td>&quot;500220839878&quot;</td>
<td>&quot;7&quot;</td>
<td>8</td>
</tr>
<tr>
<td>&quot;10203&quot;</td>
<td>&quot;15&quot;</td>
<td>3</td>
</tr>
</tbody></table>
<h2 id="알고리즘">알고리즘</h2>
<ul>
<li><strong>완전 탐색 = 모든 경우의 수를 다 체크해서 정답을 찾는 방법</strong></li>
</ul>
<h2 id="제출-코드">제출 코드</h2>
<ul>
<li><p>나의 문제 풀이 방법</p>
<p>  오랜만에 파이썬을 사용하다보니 for문 돌리는 방법을 까먹었다 ^^; 자바스크립트랑 같이 사용하다보면 for in, for of 등등의 for문이 자꾸 머릿속에 맴돈다.</p>
<p>  문제를 보자마자 문자열을 잘라서 비교하는걸 생각했지만 <code>p와 t의 문자열 길이가 동일할 경우</code> 의 체크를 하지 않아서 문제 제출 할 때 몇개 실패했다.</p>
<p>  해당 부분을을 꼭 if조건에서 실행하여 오류가 나지 않게 하는 것이 중요했던 문제인 것 같다</p>
</li>
</ul>
<pre><code class="language-python">def solution(t, p):
    answer = 0
    p_length = len(p) # p의 문자열 길이
    for start in range(0, len(t)):
        end = start + p_length
        t_str = t[start:end]
        if (p_length == len(t_str) and int(t_str) &lt;= int(p)):
            answer+=1

    return answer</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Konga 설치]]></title>
            <link>https://velog.io/@youseon__/Konga-%EC%84%A4%EC%B9%98%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@youseon__/Konga-%EC%84%A4%EC%B9%98%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sat, 28 Jan 2023 04:46:45 GMT</pubDate>
            <description><![CDATA[<aside>
📢 하단의 내용은 버전에 따라 언제든지 달라질 수 있습니다. 참고자료의 공식 문서부터 참고 부탁드립니다.

</aside>

<h1 id="참고-자료">참고 자료</h1>
<ul>
<li><p>공식 깃허브</p>
<p>  <a href="https://github.com/pantsel/konga#production-docker-image">GitHub - pantsel/konga: More than just another GUI to Kong Admin API</a></p>
</li>
<li><p>Kong &amp; Konga 설치 블로그</p>
<p>  <a href="https://ibks-platform.tistory.com/379">Kong API Gateway #2 - Konga &amp; API 등록/요청</a></p>
</li>
</ul>
<h1 id="환경">환경</h1>
<aside>
📢 쿠버네티스를 사용하시거나 환경이 다를 경우 설치방법이 상이합니다.

</aside>

<ol>
<li>Virtual Machine</li>
<li>우분투 18.04.2</li>
<li>도커 환경</li>
</ol>
<h1 id="설치-방법">설치 방법</h1>
<h2 id="1-도커-이미지-pull">1. 도커 이미지 Pull</h2>
<pre><code class="language-jsx">docker pull pantsel/konga</code></pre>
<h2 id="2-데이터베이스-셋팅">2. 데이터베이스 셋팅</h2>
<p>Konga의 Bootstrap환경을 위해 DB 마이그레이션이 필요함</p>
<p>Kong 설치시 생성한 환경(시리즈 1)을 그대로 사용하므로 네트워크는 <code>kong-net</code> DB 접속정보 역시 <code>kong-database</code>로 입력하여 <strong><em>prepare</em></strong>
 명령 실행</p>
<ul>
<li>공식 문서</li>
</ul>
<pre><code class="language-bash">docker run -p 1337:1337 \
             --network {{kong-network}} \ // optional
             --name konga \
             -e &quot;NODE_ENV=production&quot; \ // or &quot;development&quot; | defaults to &#39;development&#39;
             -e &quot;TOKEN_SECRET={{somerandomstring}}&quot; \
             pantsel/konga</code></pre>
<ul>
<li>내가 run 한 방법<ul>
<li>kongpass = kong 설치할때 설정한 DB 비밀번호</li>
<li>명령어<ul>
<li>-c = 명령어</li>
<li>-a = 어댑터 (can be <code>postgres</code> or <code>mysql</code>)</li>
<li>-u = 전체 데이터베이스 연결 URL</li>
</ul>
</li>
</ul>
</li>
</ul>
<pre><code class="language-bash">docker run --rm --network=kong-net pantsel/konga:latest \
-c prepare -a &#39;postgres&#39; \
-u postgresql://kong:kongpass@kong-database:5432/konga</code></pre>
<h2 id="3-konga-실행">3. Konga 실행</h2>
<p>기본포트 <code>1337</code></p>
<p>네트워크는 <code>kong-net</code></p>
<p>환경변수 TOKEN_SECRET - <code>본인 맘대로</code> </p>
<p>DB 접속정보 등 설정</p>
<pre><code class="language-bash">docker run -p 1337:1337 --network=kong-net -e &quot;TOKEN_SECRET=&lt;&lt;난수 생성해서 입력&gt;&gt;&quot; -e &quot;DB_ADAPTER=postgres&quot; -e &quot;DB_URI=postgresql://kong:kongpass@kong-database:5432/konga&quot; -e &quot;NODE_ENV=production&quot; --name konga pantsel/konga</code></pre>
<h2 id="4-konga-접속">4. Konga 접속</h2>
<p>브라우저로 접속</p>
<pre><code class="language-bash">localhost:1337</code></pre>
<h2 id="5-konga-admin-계정-생성">5. Konga admin 계정 생성</h2>
<h2 id="6-konga-connection-설정">6. Konga connection 설정</h2>
<pre><code class="language-bash">name = admin
admin url = http://kong-gateway:8001</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Kong Gateway 설치]]></title>
            <link>https://velog.io/@youseon__/Kong-Gateway-%EC%84%A4%EC%B9%98</link>
            <guid>https://velog.io/@youseon__/Kong-Gateway-%EC%84%A4%EC%B9%98</guid>
            <pubDate>Sat, 28 Jan 2023 03:37:05 GMT</pubDate>
            <description><![CDATA[<h1 id="환경">환경</h1>
<ol>
<li><p>Virtual Machine</p>
</li>
<li><p>우분투 18.04.2</p>
</li>
<li><p>도커 환경</p>
<p> <a href="https://docs.konghq.com/gateway/latest/install/docker/?_ga=2.128313996.1662426081.1674874721-18172733.1674783232">Install Kong Gateway on Docker - v3.1.x | Kong Docs</a></p>
</li>
</ol>
<h1 id="설치-방법">설치 방법</h1>
<h2 id="1-도커-네트워크-설정">1. 도커 네트워크 설정</h2>
<p>docker를 이용하기 때문에 DB, Kong 컨테이너 간 통신을 위해서 docker network를 생성하여 네트워크를 구성</p>
<pre><code class="language-jsx">docker network create kong-net</code></pre>
<h2 id="2-데이터-베이스-설치-및-구동">2. 데이터 베이스 설치 및 구동</h2>
<p>PostgreSQL로 설치</p>
<pre><code class="language-jsx">docker run -d --name kong-database \
  --network=kong-net \
  -p 5432:5432 \
  -e &quot;POSTGRES_USER=kong&quot; \
  -e &quot;POSTGRES_DB=kong&quot; \
  -e &quot;POSTGRES_PASSWORD=kongpass&quot; \
  postgres:9.6</code></pre>
<h2 id="3-데이터-베이스-셋팅">3. 데이터 베이스 셋팅</h2>
<p>2번에서 Database를 PostgreSQL로 설치는 완료했지만, 저 DB는 현재 아무것도 없는 껍데기 상태의 DB이기 때문에, kong의 bootstrap환경을 migration하여 DB 스키마를 최초 설정</p>
<pre><code class="language-jsx">docker run --rm --network=kong-net \
  -e &quot;KONG_DATABASE=postgres&quot; \
  -e &quot;KONG_PG_HOST=kong-database&quot; \
  -e &quot;KONG_PG_PASSWORD=kongpass&quot; \
  -e &quot;KONG_PASSWORD=test&quot; \
 kong/kong-gateway:3.1.1.2 kong migrations bootstrap</code></pre>
<h2 id="4-kong-gateway에서-컨테이너-실행">4. Kong Gateway에서 컨테이너 실행</h2>
<pre><code class="language-jsx">docker run -d --name kong-gateway \
  --network=kong-net \
  -e &quot;KONG_DATABASE=postgres&quot; \
  -e &quot;KONG_PG_HOST=kong-database&quot; \
  -e &quot;KONG_PG_USER=kong&quot; \
  -e &quot;KONG_PG_PASSWORD=kongpass&quot; \
  -e &quot;KONG_PROXY_ACCESS_LOG=/dev/stdout&quot; \
  -e &quot;KONG_ADMIN_ACCESS_LOG=/dev/stdout&quot; \
  -e &quot;KONG_PROXY_ERROR_LOG=/dev/stderr&quot; \
  -e &quot;KONG_ADMIN_ERROR_LOG=/dev/stderr&quot; \
  -e &quot;KONG_ADMIN_LISTEN=0.0.0.0:8001&quot; \
  -e &quot;KONG_ADMIN_GUI_URL=http://localhost:8002&quot; \
  -e KONG_LICENSE_DATA \
  -p 8000:8000 \
  -p 8443:8443 \
  -p 8001:8001 \
  -p 8444:8444 \
  -p 8002:8002 \
  -p 8445:8445 \
  -p 8003:8003 \
  -p 8004:8004 \
  kong/kong-gateway:3.1.1.2</code></pre>
<h2 id="5-구동-확인">5. 구동 확인</h2>
<p>curl이 설치되어 있지 않으면</p>
<pre><code class="language-jsx">apt install curl</code></pre>
<p>localhost:8001번의 /services 엔드포인트로 GET요청하여 확인</p>
<pre><code class="language-jsx">curl -i -X GET --url http://localhost:8001/services</code></pre>
<p>브라우저를 열어서도 확인 가능</p>
<pre><code class="language-jsx">http://localhost:8002</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[OpenStack 소개]]></title>
            <link>https://velog.io/@youseon__/OpenStack-%EC%86%8C%EA%B0%9C</link>
            <guid>https://velog.io/@youseon__/OpenStack-%EC%86%8C%EA%B0%9C</guid>
            <pubDate>Wed, 25 Jan 2023 08:22:02 GMT</pubDate>
            <description><![CDATA[<h1 id="openstack이란">OpenStack이란?</h1>
<p><img src="https://velog.velcdn.com/images/youseon__/post/adfcbd3c-4607-4d78-8615-b58599226b20/image.png" alt=""></p>
<h1 id="openstack에-대한-다른-정의들">OpenStack에 대한 다른 정의들</h1>
<ul>
<li>퍼블릭 클라우드와 사설 클라우드 구출을 가능하게 하는 오픈 소스 소프트웨어</li>
<li>서버, 스토리지, 네트워크와 같은 자원들을 모두 모아, 이들을 제어하고 운영하기 위한 클라우드 오퍼레이팅 시스템</li>
<li>오픈 소스를 기반으로 클라우드를 구축하고 운용하고자 하는 오픈소스 개발자, 회사, 사용자들이 주축이 되어 발전하는 커뮤니티</li>
</ul>
<h1 id="릴리즈-관련">릴리즈 관련</h1>
<ul>
<li>6개월 주기로 릴리즈 발표하며 새로운 특징 및 핵심 기능들은 보통 1년을 주기로 많은 변화가 생김</li>
<li>기본적으로 업그레이드 버전업 미지원하나 최근부터 지원하기 시작함</li>
</ul>
<h1 id="구성-요소">구성 요소</h1>
<p><img src="https://velog.velcdn.com/images/youseon__/post/c3bfb8ff-895b-446a-973e-a383f85a0938/image.png" alt=""></p>
<ul>
<li>Compute<ul>
<li>Nova - VM 인스턴스 관리</li>
</ul>
</li>
<li>Storage<ul>
<li>Swift - 오브젝트 스토리지 관리</li>
<li>Cinder - 블록 스토리지 (가상 하드디스크) 관리</li>
<li>Glance - VM이미지 관리 (CentOS 등)</li>
</ul>
</li>
<li>Identity<ul>
<li>Keystone - 로그인 등 통합 인증 관리 (인가, 인증)</li>
</ul>
</li>
<li>Network<ul>
<li>Neutron (Quantum) - 가상 네트워크 관리</li>
</ul>
</li>
<li>Template<ul>
<li>Heat - 템플릿 관리 (상황별 가상머신 몇개, 디스크 몇 등등 지정)</li>
</ul>
</li>
<li>Metering<ul>
<li>Ceilometer - 얼마나 썻는지</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Vue3, TS 환경에서 StoryBook 구성하기]]></title>
            <link>https://velog.io/@youseon__/Vue3-StoryBook-TypeScript-Vite</link>
            <guid>https://velog.io/@youseon__/Vue3-StoryBook-TypeScript-Vite</guid>
            <pubDate>Thu, 16 Jun 2022 14:16:49 GMT</pubDate>
            <description><![CDATA[<aside>
📢 우선, 결론부터 이야기하자면 vue3로 StoryBook을 구성하는 것은 추천하지 않습니다. (22년 06월 기준) 돌아가세요… 그럼에도 불구하고 시도하는 것에 의의를 두신다면 아래 내용 참고 부탁드립니다.

</aside>

<ul>
<li>주의 사항<ol>
<li>typescript + vue3 + vite 등의 환경 예시입니다.</li>
<li>quasar 디자인 프레임워크를 사용한 예시입니다.</li>
</ol>
</li>
</ul>
<hr>
<h2 id="1-storybook-설치">1. StoryBook 설치</h2>
<pre><code class="language-python">npx -p @storybook/cli sb init --type vue</code></pre>
<h2 id="2-디렉토리-및-script-확인">2. 디렉토리 및 script 확인</h2>
<ul>
<li><p>프로젝트 루트 디렉토리에서 1번 명령어 실행시 루트 디렉토리에 <code>.storybook</code>, <code>./scr/storybook</code> 폴더가 생성되며 package.json에 storybook, build-storybook 명령어가 추가로 자동 생성됨</p>
</li>
<li><p><code>npm run storybook</code> 으로 6006포트에서 storybook 페이지가 열리는지 확인</p>
</li>
<li><p>package.json 참고</p>
<ul>
<li><p>설치 날짜에 따라 버전은 다를 수 있으므로 참고만</p>
<pre><code class="language-jsx">&quot;scripts&quot;: {
  ...
  &quot;storybook&quot;: &quot;start-storybook -p 6006&quot;,
  &quot;build-storybook&quot;: &quot;build-storybook&quot;
}, 
&quot;dependencies&quot;: {
  ...(생략)
},
&quot;devDependencies&quot;: {
  ...
  &quot;@storybook/addon-actions&quot;: &quot;^6.5.8&quot;,
  &quot;@storybook/addon-essentials&quot;: &quot;^6.5.8&quot;,
  &quot;@storybook/addon-interactions&quot;: &quot;^6.5.8&quot;,
  &quot;@storybook/addon-links&quot;: &quot;^6.5.8&quot;,
  &quot;@storybook/builder-vite&quot;: &quot;^0.1.36&quot;,
  &quot;@storybook/testing-library&quot;: &quot;^0.0.11&quot;,
  &quot;@storybook/vue3&quot;: &quot;^6.5.8&quot;
}
}</code></pre>
</li>
</ul>
</li>
</ul>
<h2 id="3-srcstorybook-폴더-수정">3. src/storybook 폴더 수정</h2>
<ul>
<li><p><code>src/storybook</code> 하위 폴더에 기본으로 생성되는 파일 중 example 파일 (introduce 파일)은 우선 삭제하지 않고 그 외 모든 파일은 js 파일이기 때문에 삭제해도 됨 (우리는 ts 파일로 생성 할 것!)</p>
</li>
<li><p><code>src/components/ButtonComp.vue</code> 파일 생성</p>
<pre><code class="language-jsx">  &lt;template&gt;
    &lt;q-btn
      :label=&quot;props.label&quot;
      flat
      :disable=&quot;props.disable&quot;
      @click=&quot;emit(&#39;click:clicked&#39;)&quot;
    /&gt;
  &lt;/template&gt;

  &lt;script lang=&quot;ts&quot; setup&gt;
  import { defineProps, ref } from &#39;vue&#39;;
  // emit
  const emit = defineEmits([&#39;click:clicked&#39;]);
  // button 인터페이스
  interface Button {
    label?: string; // 버튼 라벨
    disable?: boolean; // disable 여부
  }
  const props = withDefaults(defineProps&lt;Button&gt;(), {
    label: &#39;버튼 라벨명&#39;,
    disable: false,
  });

  &lt;/script&gt;</code></pre>
</li>
<li><p><code>src/storybook/button.stories.ts</code> 파일 생성</p>
<pre><code class="language-tsx">  import GButton from &#39;@/components/ButtonComp.vue&#39;;
  import { Meta, StoryFn } from &#39;@storybook/vue3&#39;;

  export default {
    title: &#39;Atoms/Button&#39;,
    component: GButton,
    argTypes: {
      label: { control: &#39;text&#39; },
      disable: { control: &#39;boolean&#39; },
    },
  } as Meta&lt;typeof GButton&gt;;

  // 기본
  export const Basic: StoryFn&lt;typeof GButton&gt; = (args) =&gt; ({
    components: { GButton },
    setup() {
      return { args };
    },
    template: `
    &lt;g-button v-bind=&quot;args&quot;/&gt;
    `,
  });

  // 라벨
  export const Label: StoryFn&lt;typeof GButton&gt; = (args) =&gt; ({
    components: { GButton },
    setup() {
      return { args };
    },
    template: `
    &lt;g-button v-bind=&quot;args&quot;/&gt;
    `,
  });

  Label.args = {
    label: &#39;라벨명&#39;,
  };

  //  선택 불가
  export const Disable: StoryFn&lt;typeof GButton&gt; = (args) =&gt; ({
    components: { GButton },
    setup() {
      return { args };
    },
    template: `
    &lt;g-button v-bind=&quot;args&quot;/&gt;
    `,
  });

  Disable.args = {
    disable: true,
  };
</code></pre>
</li>
</ul>
<h2 id="4-지원되지-않는-플러그인-직접-수정">4. 지원되지 않는 플러그인 직접 수정</h2>
<ul>
<li><p>위 내용까지만 진행해도 실행은 되겠지만 화면에 보이는 source code를 확인해보면 template 부분만 보이지 않고 export const~ 부터 모든 코드가 노출되는 것이 확인됨.</p>
</li>
<li><p>아직 플러그인이 지원되지 않는 문제가 있음</p>
</li>
<li><p><code>.storybook/withSource.js</code> 파일 작성</p>
<ul>
<li><p>코드 참고</p>
<p>  <a href="https://github.com/storybookjs/storybook/issues/13917">https://github.com/storybookjs/storybook/issues/13917</a></p>
</li>
<li><p>주의사항 = lodash 설치 필요</p>
<pre><code class="language-tsx">import { addons, makeDecorator } from &#39;@storybook/addons&#39;;
import kebabCase from &#39;lodash&#39;;
import { h, onMounted } from &#39;vue&#39;;

// this value doesn&#39;t seem to be exported by addons-docs
export const SNIPPET_RENDERED = `storybook/docs/snippet-rendered`;

function templateSourceCode(
templateSource,
args,
argTypes,
replacing = &#39;v-bind=&quot;args&quot;&#39;
) {
const componentArgs = {};
for (const [k, t] of Object.entries(argTypes)) {
  const val = args[k];
  if (
    typeof val !== &#39;undefined&#39; &amp;&amp;
    t.table &amp;&amp;
    t.table.category === &#39;props&#39; &amp;&amp;
    val !== t.defaultValue
  ) {
    componentArgs[k] = val;
  }
}

const propToSource = (key, val) =&gt; {
  const type = typeof val;
  switch (type) {
    case &#39;boolean&#39;:
      return val ? key : &#39;&#39;;
    case &#39;string&#39;:
      return `${key}=&quot;${val}&quot;`;
    default:
      return `:${key}=&quot;${val}&quot;`;
  }
};

return templateSource.replace(
  replacing,
  Object.keys(componentArgs)
    .map((key) =&gt; &#39; &#39; + propToSource(kebabCase(key), args[key]))
    .join(&#39;&#39;)
);
}

export const withSource = makeDecorator({
name: &#39;withSource&#39;,
wrapper: (storyFn, context) =&gt; {
  const story = storyFn(context);

  // this returns a new component that computes the source code when mounted
  // and emits an events that is handled by addons-docs
  // this approach is based on the vue (2) implementation
  // see https://github.com/storybookjs/storybook/blob/next/addons/docs/src/frameworks/vue/sourceDecorator.ts
  return {
    components: {
      Story: story,
    },

    setup() {
      onMounted(() =&gt; {
        try {
          // get the story source
          const src = context.originalStoryFn().template;

          // generate the source code based on the current args
          const code = templateSourceCode(
            src,
            context.args,
            context.argTypes
          );

          const channel = addons.getChannel();

          const emitFormattedTemplate = async () =&gt; {
            const prettier = await import(&#39;prettier/standalone&#39;);
            const prettierHtml = await import(&#39;prettier/parser-html&#39;);

            // emits an event  when the transformation is completed
            channel.emit(
              SNIPPET_RENDERED,
              (context || {}).id,
              prettier.format(`&lt;template&gt;${code}&lt;/template&gt;`, {
                parser: &#39;vue&#39;,
                plugins: [prettierHtml],
                htmlWhitespaceSensitivity: &#39;ignore&#39;,
              })
            );
          };

          setTimeout(emitFormattedTemplate, 0);
        } catch (e) {
          console.warn(&#39;Failed to render code&#39;, e);
        }
      });

      return () =&gt; h(story);
    },
  };
},
});</code></pre>
</li>
</ul>
</li>
<li><p><code>.storybook/main.ts</code> 수정</p>
<pre><code class="language-tsx">  const { loadConfigFromFile, mergeConfig } = require(&#39;vite&#39;);
  const path = require(&#39;path&#39;);

  module.exports = {
    stories: [&#39;../src/**/*.stories.mdx&#39;, &#39;../src/**/*.stories.@(js|jsx|ts|tsx)&#39;],
    addons: [
      &#39;@storybook/addon-links&#39;,
      &#39;@storybook/addon-essentials&#39;,
      &#39;@storybook/addon-interactions&#39;,
    ],
    framework: &#39;@storybook/vue3&#39;,
    core: {
      builder: &#39;@storybook/builder-vite&#39;,
    },
    typescript: {
      check: false,
      checkOptions: {},
      reactDocgen: &#39;react-docgen-typescript&#39;,
      reactDocgenTypescriptOptions: {
        shouldExtractLiteralValuesFromEnum: true,
        propFilter: (prop) =&gt;
          prop.parent ? !/node_modules/.test(prop.parent.fileName) : true,
      },
    },
    features: {
      storyStoreV7: true,
    },

    async viteFinal(previousConfig) {
      const { config } = await loadConfigFromFile(
        path.resolve(__dirname, &#39;../vite.config.ts&#39;)
      );

      return mergeConfig(previousConfig, {
        ...config,
        plugins: [],
      });
    },
  };</code></pre>
</li>
<li><p><code>.storybook/preview.js</code> 파일 수정</p>
<pre><code class="language-tsx">  import &#39;@quasar/extras/roboto-font/roboto-font.css&#39;;
  // These are optional
  import &#39;@quasar/extras/material-icons/material-icons.css&#39;;

  // Loads the quasar styles and registers quasar functionality with storybook
  import &#39;quasar/dist/quasar.css&#39;;
  import { app } from &#39;@storybook/vue3&#39;;
  import { Quasar } from &#39;quasar&#39;;
  import &#39;@styles/index.scss&#39;;

  import { withSource } from &#39;./withSource&#39;;
  // This is also where you would setup things such as pinia for storybook
  app.use(Quasar, {});

  export const parameters = {
    actions: { argTypesRegex: &#39;^on[A-Z].*&#39; },
    controls: {
      matchers: {
        color: /(background|color)$/i,
        date: /Date$/,
      },
    },
  };

  export const decorators = [withSource];</code></pre>
</li>
</ul>
<h2 id="5-결론">5. 결론</h2>
<ul>
<li>위 내용까지 수정 후 run storybook으로 실행하면 source code가 원하는 모습으로 출력됨.</li>
<li>하지만 위 소스 중 template 부분이 문자열 형태로 삽입되어 있음.</li>
<li>추후에 오타 입력시 바로 확인이 어렵고 멀티 컴포넌트를 구성 할 경우 알아보기 힘든 큰 단점이 있음.</li>
<li>따라서, vue로 storybook을 구성하는 것은 현재로썬.. 어려워보임</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[MyBatis HashMap ResultMap Null 오류]]></title>
            <link>https://velog.io/@youseon__/MyBatis-HashMap-ResultMap-Null-%EC%98%A4%EB%A5%98</link>
            <guid>https://velog.io/@youseon__/MyBatis-HashMap-ResultMap-Null-%EC%98%A4%EB%A5%98</guid>
            <pubDate>Tue, 15 Feb 2022 04:27:32 GMT</pubDate>
            <description><![CDATA[<h1 id="문제">문제</h1>
<ol>
<li>모두 select절에 넣어서 하나하나 select를 했음에도 null인 값들은 아예 select해주지 않음</li>
</ol>
<hr>
<h1 id="원인">원인</h1>
<ol>
<li>myBaitis 3.2.2 버전 이후로 resultType에 HashMap(or Map)을 사용하면 데이터가 Null인 컬럼은 Map의 KeySet에 제외가 됨</li>
</ol>
<hr>
<h1 id="해결방법">해결방법</h1>
<ol>
<li>mybatis config xml 파일에 아래 설정 추가<pre><code class="language-XML">&lt;settings&gt;
     &lt;setting name=&quot;callSettersOnNulls&quot; value=&quot;true&quot;/&gt;
&lt;/settings&gt;</code></pre>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spring Cloud GateWay]]></title>
            <link>https://velog.io/@youseon__/Spring-Cloud-GateWay</link>
            <guid>https://velog.io/@youseon__/Spring-Cloud-GateWay</guid>
            <pubDate>Mon, 14 Feb 2022 08:42:41 GMT</pubDate>
            <description><![CDATA[<h1 id="spring-cloud-gateway-에서-사용하는-3가지-명칭">Spring Cloud Gateway 에서 사용하는 3가지 명칭</h1>
<p>우선 Spring Cloud Gateway 에서 사용하는 3가지 용어에 대해서 먼저 알아볼 필요가 있다.</p>
<ol>
<li>Route</li>
<li>Predicate</li>
<li>Filter</li>
</ol>
<h3 id="route-라우트">Route (라우트)</h3>
<p>목적지의 URI와 Predicates라는 조건들의 목록 그리고 필터들을 이용하여 어떤 곳으로 Routing 할 것인지를 명시하는 역할을 한다.</p>
<p>우리는 Routes 에 대한 속성과 정보를 입력하여 Spring Cloud가 어떤 방식으로 동작하라고 지시할 수 있게 된다.</p>
<h3 id="predicate">Predicate</h3>
<p>쉽게 <strong>조건</strong>이라고 생각하면 된다.</p>
<p>아래에서 우리는 Predicates 를 작성할 것인데, 다음과 같이 작성한다.</p>
<pre><code>predicated: -Path=/user/**</code></pre><p>그럼 user 라는 모든 경로를 지정한 것이다.</p>
<ul>
<li>Handler Mapping 시에 필요한 Uri 정보나, Path 정보를 확인하는 주체가 된다.</li>
</ul>
<h3 id="filter">Filter</h3>
<p>프록시 방식으로 동작하며, 한 필터에 pre / post 동작을 정의 할 수 있다.</p>
<p>모든 pre 필터가 처리된 후 요청이 처리되고 나오면서 모든 post 필터가 처리된다.</p>
<p>들어오는 요청과 응답, Request, Response을 특정 필터를 타게 함으로 우리가 원하는 방식으로 요청을 보내거나 헤더를 조작할 수 있고, 해당 필터를 이용해서 로그 파일을 작성하게 할 수 도 있다.</p>
<ul>
<li>Handler Mapping이 된 후 들어온 요청에 대한 필터 작업을 수행할 수 있다.</li>
<li>2개의 필터로 크게 나뉘며 사전(Pre Filter)와 사후(Post Filter)로 나눌 수 있다.<ul>
<li>Pre Filter<ul>
<li>특정 작업이 일어나기 전에 지정</li>
</ul>
</li>
<li>Post Filter<ul>
<li>특정 작업이 끝난 후에 지정</li>
</ul>
</li>
</ul>
</li>
</ul>
<hr>
<h1 id="spring-cloud-gateway-절차">Spring Cloud Gateway 절차</h1>
<p><img src="https://images.velog.io/images/youseon__/post/519a5b91-194c-4895-a331-5caa0b419346/image.png" alt=""></p>
<ol>
<li>Client 는 Spring Cloud Gateway 에 요청을 보낸다.</li>
<li>Gateway Handler Mapping 에서 해당 요청에 대한 Route와 Predicates가 일치한다고 판단하면 해당 요청은 Gateway Web handler로 보내진다.</li>
<li>handler 에서 Filter Chain 을 이용해서 <strong>사전 필터</strong> 혹은 <strong>사후 필터</strong>로 나누어 동작한다.</li>
<li>필터링이 된 후 실제 마이크로서비스에게 전달된다.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[wsl CentOS8 systemctl 오류]]></title>
            <link>https://velog.io/@youseon__/wsl-CentOS8-systemctl-%EC%97%90%EB%9F%AC</link>
            <guid>https://velog.io/@youseon__/wsl-CentOS8-systemctl-%EC%97%90%EB%9F%AC</guid>
            <pubDate>Mon, 14 Feb 2022 08:37:33 GMT</pubDate>
            <description><![CDATA[<h1 id="원인">원인</h1>
<ul>
<li>wsl 환경에서 centos 사용 할 때 systemctl 명령어를 지원하지 않음</li>
</ul>
<h1 id="해결-방법">해결 방법</h1>
<ul>
<li>거의 하루하고도 반나절동안 이 오류에 부딪쳐서 아무것도 할 수 없다가 centos8  키워드를 제거해서 <code>wsl centos systemctl</code> 이라고 검색하니 아래와 같은 해결책을 찾을 수 있었다.</li>
</ul>
<p><img src="https://images.velog.io/images/youseon__/post/65e7eba4-1ab6-4ce8-9c60-ff4ba1569bd2/image.png" alt=""></p>
]]></description>
        </item>
    </channel>
</rss>