<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>jade.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Wed, 26 Mar 2025 02:33:46 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>jade.log</title>
            <url>https://velog.velcdn.com/images/to_world/profile/b11d0236-c035-43e1-ab20-880960325999/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. jade.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/to_world" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Divide and Conquer]]></title>
            <link>https://velog.io/@to_world/Divide-and-Conquer</link>
            <guid>https://velog.io/@to_world/Divide-and-Conquer</guid>
            <pubDate>Wed, 26 Mar 2025 02:33:46 GMT</pubDate>
            <description><![CDATA[<h2 id="1-개념">1. 개념</h2>
<p><strong>Divide</strong> 큰 문제를 작은 문제로 쪼개는 것</p>
<p><strong>Conquer</strong> 작은 문제들을 다시 합치는 것</p>
<p><strong>Top-down</strong> approach : divide -&gt; conquer -&gt; combine</p>
<p><strong>시간복잡도 time complexity</strong> : 
<img src="https://velog.velcdn.com/images/to_world/post/a80ede79-41de-445e-a380-f9b4c590648f/image.png" alt=""></p>
<h2 id="2-예시1-binary-search-tree">2. 예시1: binary search (tree)</h2>
<p>정렬된 배열에서는 최악의 경우에도 optimal algorithm!</p>
<h3 id="1-code">1) code</h3>
<pre><code class="language-python"></code></pre>
<h3 id="2">2)</h3>
]]></description>
        </item>
        <item>
            <title><![CDATA[Image Equalization, Matching]]></title>
            <link>https://velog.io/@to_world/Image-Equalization-Matching</link>
            <guid>https://velog.io/@to_world/Image-Equalization-Matching</guid>
            <pubDate>Mon, 24 Mar 2025 15:13:45 GMT</pubDate>
            <description><![CDATA[<h2 id="1-image-equalization">1. Image Equalization</h2>
<h3 id="1-equalization-이란">1) equalization 이란?</h3>
<p>자동으로 대비가 향상되게 함(균등 분배!)
CDF 값만 있으면 가능!</p>
<p>Equaliztion의 목표</p>
<ul>
<li>최대한 균등하게 분포시킴</li>
<li>입력에서 같은 intensity 값을 가진 픽셀들은 동일한 출력 intensity로 변환되어야 함</li>
</ul>
<h3 id="2-equalization의-수학계산">2) Equalization의 수학계산</h3>
<p><img src="https://velog.velcdn.com/images/to_world/post/69fbff2c-c330-4ca0-ae87-2b7960ed7900/image.png" alt=""></p>
<p>s: 결과 이미지의 intensity
중간에 적분이 들어가는데 이 사진에서는 생략됨</p>
<h3 id="3-문제점-wash-out">3) 문제점: wash out</h3>
<p>input의 histogram이 너무 편향적일 경우(너무 어둡거나 밝은 부분만 존재)
equalization은 무조건 균등분포를 목표로 하기 때문에 모든 밝기 값을 비슷한 비율로 강제 배분을 함
-&gt; 기존의 밝기 구조나 분포를 전혀 고려하지 않은 결과값이 나옴: wash out</p>
<h2 id="2-histogram-matching">2. Histogram Matching</h2>
<blockquote>
<p>이 이미지의 톤을 저 이미지처럼 바꿔줘!</p>
</blockquote>
<h3 id="1-계산-방법">1) 계산 방법</h3>
<ol>
<li>입력 이미지를 equalization</li>
<li>참조 이미지를 equalization</li>
<li>역변환!<img src="https://velog.velcdn.com/images/to_world/post/802811bb-024d-4793-9983-692573b82ed7/image.png" alt="">
<img src="https://velog.velcdn.com/images/to_world/post/6b4e1475-6e44-4a51-ba3d-11da98af184c/image.png" alt="">
<img src="https://velog.velcdn.com/images/to_world/post/ef926313-f802-4068-87b3-b93a52c8736d/image.png" alt=""></li>
</ol>
<ul>
<li><strong>Before -&gt; After</strong>
<img src="https://velog.velcdn.com/images/to_world/post/03676413-3155-48e5-8a76-6d2c9ee300b5/image.png" alt=""></li>
</ul>
<h2 id="3-color-이미지에서의-equalization-matching-방법">3. color 이미지에서의 equalization, matching 방법</h2>
<ol>
<li>색을 RGB로 분리</li>
<li>RGB -&gt; YIQ 로 변환
Y: 밝기 / I: 색상, Q: 채도</li>
<li>밝기Y만 equalization matching 수행</li>
<li>YIQ -&gt; RGB로 다시 변환</li>
<li>RGB를 합쳐서 output  출력!</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[Histogram Stretching]]></title>
            <link>https://velog.io/@to_world/histogram-stretching</link>
            <guid>https://velog.io/@to_world/histogram-stretching</guid>
            <pubDate>Mon, 24 Mar 2025 11:58:21 GMT</pubDate>
            <description><![CDATA[<h2 id="1-histogram-stretching-이란">1. histogram stretching 이란?</h2>
<p>픽셀 값의 범위를 늘려 이미지의 대비를 향상시킴</p>
<p><strong>계산방법</strong></p>
<ul>
<li>x = 원래 intensity</li>
<li>y = 결과 intensity</li>
<li>a(i~i+1) : 입력 image에서 intensity 구간</li>
<li>b(i~i+1) : 결과 image에서 mapping 구간
<img src="https://velog.velcdn.com/images/to_world/post/68a35e89-590c-4492-b9bb-a7cf8a6c9acf/image.png" alt=""></li>
<li>before vs after
<img src="https://velog.velcdn.com/images/to_world/post/89cf411f-274f-419d-b15d-001dd134a23c/image.png" alt=""></li>
</ul>
<h2 id="2-gamma-correction-감마-보정">2. gamma correction 감마 보정</h2>
<p>픽셀의 밝기를 어두운 건 더 어둡거나 밝게, 밝은 건 더 밝거나 어둡게</p>
<h3 id="1-계산법">1) 계산법</h3>
<p><strong>계산공식</strong></p>
<ul>
<li>x = 원래 intensity</li>
<li>y = 감마 값</li>
<li>a,b : 입력 범위</li>
<li>c,d : 결과 범위
<img src="https://velog.velcdn.com/images/to_world/post/315d8e02-87c8-47c7-af35-1cc38cfbddd4/image.png" alt=""></li>
<li>Before -&gt; After
<img src="https://velog.velcdn.com/images/to_world/post/2254ef1b-6556-407f-b824-625eb6addf6a/image.png" alt=""></li>
</ul>
<h3 id="2-gamma1-vs-gamma1">2) gamma&lt;1 vs gamma&gt;1</h3>
<ul>
<li>gamma&lt;1: 어두운 픽셀을 밝게!</li>
<li>gamma&gt;1: 밝은 픽셀을 어둡게!
<img src="https://velog.velcdn.com/images/to_world/post/ead8c60c-1bd0-477c-b3cd-d7cb63657b52/image.png" alt=""></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Image Histogram, PDF, CDF]]></title>
            <link>https://velog.io/@to_world/image-histogram-PDF-CDF</link>
            <guid>https://velog.io/@to_world/image-histogram-PDF-CDF</guid>
            <pubDate>Mon, 24 Mar 2025 11:49:30 GMT</pubDate>
            <description><![CDATA[<h2 id="1-image-histogram-이란">1. image histogram 이란?</h2>
<p>각 intensity가 얼마나 많이 등장하였는지 나타내는 것
이를 통해</p>
<ul>
<li>얼마나 어둡고 밝은지?</li>
<li>이미지의 대비 정도</li>
</ul>
<p>를 알 수 있다.</p>
<p><code>전체 면적=전체 픽셀 수</code> 이다.</p>
<p>예시그림: 블랙과 회색이 많은 그림 -&gt; 어두운 부분과 중간 부분에 peak 가 보인다.
<img src="https://velog.velcdn.com/images/to_world/post/5cc24713-a618-45eb-aa8b-5e58978830ec/image.png" alt=""></p>
<h2 id="2-histogram-vs-pdf">2. histogram vs PDF</h2>
<p>PDF: 확률밀도함수: histogram을 정규화한것 : 각 intensity가 등장할 확률을 나타냄
<code>전체 면적 = 1</code> 이다.
<img src="https://velog.velcdn.com/images/to_world/post/f2ceac10-2731-40c2-a583-b9df40da8466/image.png" alt=""></p>
<h2 id="3-pdf-vs-cdf">3. PDF vs CDF</h2>
<p>CDF: 누적 분포 함수: 어떤 값 x 이하가 나올 확률: 지금까지의 확률들을 누적한 값</p>
<p>PDF, CDF 계산 방법
-&gt; CDF에서는 필요시 적분 해야함
<img src="https://velog.velcdn.com/images/to_world/post/acaccef9-ae99-4903-b9c2-dd730120bd53/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[arithemetic operation]]></title>
            <link>https://velog.io/@to_world/arithemetic-operation</link>
            <guid>https://velog.io/@to_world/arithemetic-operation</guid>
            <pubDate>Mon, 24 Mar 2025 11:44:34 GMT</pubDate>
            <description><![CDATA[<h2 id="1-arithmetic-operation">1. Arithmetic operation</h2>
<h3 id="1-add-substract">1) add, substract</h3>
<p>덧셈: 이미지를 더 밝게 , <code>F(i)=i+128</code>
뺄셈: 이미지를 더 어둡게 , <code>F(i)=i-128</code>
<img src="https://velog.velcdn.com/images/to_world/post/10db28c5-7c59-4960-af1f-c061f38eadcd/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/to_world/post/d6b6868b-4711-49f4-a2cd-fff396bd792e/image.png" alt=""></p>
<h3 id="2-complements-보수--색반전">2) complements 보수 =&gt; 색반전</h3>
<p>double 타입: 0.0-1.0 : <code>1-m</code>
unsigned char타입: 0-255 : <code>255-m</code>
<img src="https://velog.velcdn.com/images/to_world/post/6fb01589-92a0-493a-bb93-1f0bef5d5bc7/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Amortized Analysis  ]]></title>
            <link>https://velog.io/@to_world/ComputerAlgorithm</link>
            <guid>https://velog.io/@to_world/ComputerAlgorithm</guid>
            <pubDate>Fri, 14 Mar 2025 04:37:55 GMT</pubDate>
            <description><![CDATA[<p>이 시리즈는 학교 &quot;컴퓨터 알고리즘&quot; 수업 내용을 기반으로 합니다.</p>
<h2 id="1-amortized-analysis">1. Amortized Analysis</h2>
<h3 id="potential-method">Potential method</h3>
<p>배열에 push를 하는데, 배열이 꽉차면 그 배열의 크기를 늘리면서 복사를 해야하기 때문에 갑자기 큰 비용이 발생함
그래서 potential(잠재에너지)개념이 등장
매번 push를 할 때 잠재 에너지에 1씩 저장함 -&gt; 나중에 배열이 꽉차면 잠재에너지로 배열크기를 늘리고(복사) 계속해서 push를 하면 됨 -&gt; 갑자기 큰 비용이 발생하지 않음</p>
<p><strong>Amortized Cost = Actual Cost + Φ(D i) − Φ(D i−1)</strong>
잠재비용 = 실제 비용 + 잠재변화량</p>
<h2 id="2-space-complexity">2. Space complexity</h2>
<p>저장 공간(Storage space)에 들어가야 할 것들</p>
<ul>
<li>명령어(Instructions)</li>
<li>상수, 간단한 변수(constants, simple variables)</li>
<li>입력 데이터와 추가 작업 공간(데이터 구조 포함)</li>
</ul>
<p>입력데이터의 저장 형태</p>
<ul>
<li>배열, 그래프 등등</li>
<li>배열로 저장되면, 추가 작업 공간만 분석하면 됨</li>
<li>그래프와 같은 형태의 경우, 입력되어있는 데이터와 추가작업공간 모두 분석해놔야함</li>
</ul>
<p>분석 방법</p>
<ul>
<li>최악의 경우 공간 분석(Worst-case space analysis)
최악의 입력이 들어왔을 때 알고리즘이 사용하는 최대 메모리 양</li>
<li>평균적인 경우 공간 분석(Average-case space analysis)
모든 가능한 입력에 대해 알고리즘이 사용하는 평균적인 메모리 양</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Fundamentals]]></title>
            <link>https://velog.io/@to_world/OpenSW-CH1.-Fundamentals</link>
            <guid>https://velog.io/@to_world/OpenSW-CH1.-Fundamentals</guid>
            <pubDate>Thu, 13 Mar 2025 05:55:09 GMT</pubDate>
            <description><![CDATA[<h2 id="1-sampling-on-spatial-domain">1. Sampling on Spatial Domain</h2>
<ul>
<li><strong>FoV</strong>: it depends on &#39;sensor size&#39; and &#39;lens focal length&#39;</li>
<li><strong>lens focal length(=f)</strong>: the distance between lens and sensor</li>
<li><strong>CCD sensor size</strong>: <ul>
<li>pixel size * pixel 개수</li>
<li>image quality depends on the CCD sensor size!</li>
</ul>
</li>
<li><strong>Pixel number</strong>:  <ul>
<li>일정 이상(1000 * 1000정도)가 되면 image quality에 큰 영향X</li>
<li>no matter how many pixels you are quantizing, the sensor size and the quality of image is almost same</li>
<li>너무 줄여버리면 <strong>aliasing artifacts</strong>  발생</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[intro]]></title>
            <link>https://velog.io/@to_world/OpenSW-CH0-intro</link>
            <guid>https://velog.io/@to_world/OpenSW-CH0-intro</guid>
            <pubDate>Thu, 13 Mar 2025 04:39:06 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>이 시리즈는 대학교 수업에서 진행하는 내용을 요약한 것입니다.</p>
</blockquote>
<h2 id="1-about-computer-vision">1. About computer vision</h2>
<p>a field that includes methods for acquiring processing analyzing understanding images, as the human being does
all techniques for enabling a computer to see a real-world using <strong>images</strong></p>
<p>images is stored as RGB data in computer</p>
<h2 id="2-lowhigh-level-computer-vision">2. low~high level computer vision</h2>
<h3 id="1-low-level-computer-vision">1) low level computer vision</h3>
<ul>
<li>image enhancement, restoration</li>
<li>image filtering</li>
<li>computational photography(HDR image)</li>
<li>image registration(alignment) -&gt; Structure From Motion</li>
<li><blockquote>
<p>computer vision technique used to create 3D models of an object or scene from a series of 2D images taken from different viewpoints</p>
</blockquote>
<h3 id="2-middle-level-computer-vision">2) Middle-level computer vision</h3>
</li>
<li>image segmentation(here is background, here is human body~)</li>
<li>contour detection</li>
<li><blockquote>
<p>contour is differnt from &#39;edge&#39;</p>
</blockquote>
</li>
<li><blockquote>
<p>edge: point in an image where the pixel value (like brightness or color) changes sharply.</p>
</blockquote>
</li>
<li><blockquote>
<p>contour: A curve or a closed shape that connects all points along a boundary with the same color or intensity</p>
</blockquote>
</li>
<li>image descriptor</li>
<li>3D reconstruction</li>
</ul>
<h3 id="3-high-level-computer-vision">3) High-level computer vision</h3>
<ul>
<li>object classification/recognition</li>
<li>object localization</li>
<li>visual question and answering</li>
<li>scene understanding</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Nodejs Chap8 몽고디비]]></title>
            <link>https://velog.io/@to_world/Nodejs-Chap8-%EB%AA%BD%EA%B3%A0%EB%94%94%EB%B9%84</link>
            <guid>https://velog.io/@to_world/Nodejs-Chap8-%EB%AA%BD%EA%B3%A0%EB%94%94%EB%B9%84</guid>
            <pubDate>Fri, 28 Feb 2025 07:11:47 GMT</pubDate>
            <description><![CDATA[<h2 id="1-mongodb-함수들">1. mongodb 함수들</h2>
<ul>
<li>find: 모두 조회</li>
<li>findOne: 하나만</li>
<li>sort:정렬</li>
<li>limit: 조회할 다큐먼츠  제한</li>
<li>skip: 건너뛸 다큐먼츠 정함</li>
</ul>
<h2 id="2-mongodb-연결">2. mongodb 연결</h2>
<pre><code class="language-js">const mongoose = require(&#39;mongoose&#39;);
const connect = () =&gt; {
    //배포 전(개발중)일때는 debug 하도록
    if (process.env.NODE_ENV !== &#39;production&#39;) {
        mongoose.set(&#39;debug&#39;, true);
    }
    mongoose.connect(&#39;mongodb://root:nodejsbook@localhost:27017/adming&#39;), {
        dbName: &#39;nodejs&#39;,
        useNewUrlParser: true,
        useCreateIndex:true
    }, (error) =&gt; {
        if (error) {
            console.log(&#39;mongodb error&#39;);
        }
        else {
            console.log(&#39;mongodb connect&#39;);
        }
    }
}
mongoose.connection.on(&#39;error&#39;, (error) =&gt; {
  console.error(&#39;몽고디비 연결 에러&#39;, error);
});
mongoose.connection.on(&#39;disconnected&#39;, () =&gt; {
  console.error(&#39;몽고디비 연결이 끊겼습니다. 연결을 재시도합니다.&#39;);
  connect();
});

module.exports = connect;</code></pre>
<h2 id="3-mongodb-스키마-정의">3. mongodb 스키마 정의</h2>
<p>type:자료형
require: 필수 여부
default: 기본값 
unique: 고유여부
ref: 특정 컬랙션의 문서와 연결할 수 있음</p>
<pre><code class="language-js">const mongoose = require(&#39;mongoose&#39;);

const { Schema } = mongoose;
const { Types: { ObjectId } } = Schema;
//ref: &#39;User&#39;: 이 ID는 User 컬렉션의 문서와 연결 
// populate를 사용하면 댓글 작성자의 정보를 가져올 수 있음
const commentSchema = new Schema({
  commenter: {
    type: ObjectId,
    required: true,
    ref: &#39;User&#39;,
  },
  comment: {
    type: String,
    required: true,
  },
  createdAt: {
    type: Date,
    default: Date.now,
  },
});

module.exports = mongoose.model(&#39;Comment&#39;, commentSchema);
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Nodejs Chap7 데이터베이스]]></title>
            <link>https://velog.io/@to_world/Nodejs-Chap7-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4</link>
            <guid>https://velog.io/@to_world/Nodejs-Chap7-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4</guid>
            <pubDate>Tue, 25 Feb 2025 06:58:14 GMT</pubDate>
            <description><![CDATA[<p>sql를 따로 배워야 하는듯... 이해못함...</p>
<h2 id="1-데이터-베이스-mysql">1. 데이터 베이스: MYSQL</h2>
<p>데이터를 영구적으로 저장
<strong>MySQL</strong>: 관계형 데이터베이스</p>
<ul>
<li>관련성을 가지며 중복이 없는 데이터들의 집합</li>
<li>여러 사람이 동시에 접근할 수 있고 권한을 따로 줄 수 있음</li>
<li>다운 받는 주소: <a href="https://downloads.mysql.com/archives/installer/">https://downloads.mysql.com/archives/installer/</a></li>
<li>MySQL cmd에서 작동시키기:
<code>&quot;C:\Program Files\MySQL\MySQL Server 8.0\bin&quot;</code>
<code>C:\Program Files\MySQL\MySQL Server 8.0\bin&gt;mysql -h localhost -u root -p</code></li>
</ul>
<h2 id="2-시퀄라이즈">2. 시퀄라이즈</h2>
<h3 id="1-기본-조작">1) 기본 조작</h3>
<p>js로 sql 조작할 수 있게 하는 도구</p>
<p><strong>초기 터미널 설치</strong>
<code>npm i express morgan nunjucks sequelize sequelize-cli mysql2</code>
<code>npm i -D nodemon</code>
<code>npx sequelize init</code> : 시퀄라이즈 구조 초기화</p>
<p>config 파일에 password 부분을 본인 password로 변경하기</p>
<pre><code class="language-js">&quot;development&quot;: {
    &quot;username&quot;: &quot;root&quot;,
    &quot;password&quot;: &quot;이부분!!!&quot;,
    &quot;database&quot;: &quot;database_development&quot;,
    &quot;host&quot;: &quot;127.0.0.1&quot;,
    &quot;dialect&quot;: &quot;mysql&quot;
  }</code></pre>
<p><strong>데이터베이스 연결</strong></p>
<pre><code class="language-js">sequelize.sync({ force: false })
  .then(() =&gt; {
    console.log(&#39;데이터베이스 연결 성공&#39;);
  })
  .catch((err) =&gt; {
    console.error(err);
  });</code></pre>
<h3 id="2-모델-만들기">2) 모델 만들기</h3>
<p><strong>테이블 관계</strong></p>
<ul>
<li><strong>1:N 관계</strong>:<ul>
<li>시퀄라이즈에서는 hasMany, belongsTo로 표현</li>
<li>belongsTo가 있는 테이블에 컬럼이 생김</li>
</ul>
</li>
<li><strong>1:1관계</strong>:<ul>
<li>hasOne, belongsTo 로 표현</li>
</ul>
</li>
</ul>
<p><strong>코드예제</strong>: 모델 만드는 방법 + 테이블 관계 알아보자</p>
<pre><code class="language-js">//models/user.js
const Sequelize = require(&#39;sequelize&#39;);

class User extends Sequelize.Model {
  static initiate(sequelize) {
    User.init({
      name: {
        type: Sequelize.STRING(20),
        allowNull: false, //notnull
        unique: true,
      },
      age: {
        type: Sequelize.INTEGER.UNSIGNED,
        allowNull: false,
      },
      married: {
        type: Sequelize.BOOLEAN,
        allowNull: false,
      },
      comment: {
        type: Sequelize.TEXT,
        allowNull: true,
      },
      created_at: {
        type: Sequelize.DATE,
        allowNull: false,
        defaultValue: Sequelize.NOW,
      },
    }, {
      sequelize,
      timestamps: false,
      underscored: false,
      modelName: &#39;User&#39;,
      tableName: &#39;users&#39;,
      paranoid: false,
      charset: &#39;utf8&#39;,
      collate: &#39;utf8_general_ci&#39;,
    });
  }

  static associate(db) {
    db.User.hasMany(db.Comment, { foreignKey: &#39;commenter&#39;, sourceKey: &#39;id&#39; });
  }
};

module.exports = User;</code></pre>
<p>comment.js에서는 hasMany가 아닌 belongsTo가 쓰인다.</p>
<pre><code class="language-js">//models.comment.js
static associate(db) {
    db.Comment.belongsTo(db.User, { foreignKey: &#39;commenter&#39;, targetKey: &#39;id&#39; });
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Nodejs Chap6-2 Express]]></title>
            <link>https://velog.io/@to_world/Chap6-2</link>
            <guid>https://velog.io/@to_world/Chap6-2</guid>
            <pubDate>Mon, 24 Feb 2025 10:40:51 GMT</pubDate>
            <description><![CDATA[<h2 id="3-라우팅-분리하기">3. 라우팅 분리하기</h2>
<h3 id="1-분리하는-방법">1) 분리하는 방법</h3>
<p>보통 routes 폴더 안에 여러 route 파일들을 두는 구조를 이용</p>
<pre><code class="language-js">//위치: routes/user.js
const express = require(&#39;express&#39;);
const router = express.Router();
//GET / 라우터
router.get(&#39;/&#39;, (req, res) =&gt; {
    //GET /user/
    res.send(&#39;hello user&#39;);
});

module.exports = router;</code></pre>
<pre><code class="language-js">// app.js
const indexRouter = require(&#39;./routes&#39;);
const userRouter = require(&#39;./routes/user&#39;);

app.use(&#39;/&#39;, indexRouter);
app.use(&#39;/user&#39;, userRouter);
</code></pre>
<h2 id="4-req-res-에-대하여">4. req, res 에 대하여</h2>
<h3 id="1-req">1) req</h3>
<p><strong>req는 클라이언트가 서버로 보낸 HTTP 요청에 대한 정보를 담고 있음</strong></p>
<ul>
<li>req.app: req 객체를 통해 app 객체에 접근, req.app.get(&#39;port&#39;)와 같은 식으로 사용 </li>
<li>req.body: body-parser 미들웨어가 만드는 요청의 본문을 해석한 객체 </li>
<li>req.cookies: cookie-parser 미들웨어가 만드는 요청의 쿠키를 해석한 객체 </li>
<li>req.ip: 요청의 ip 주소가 담겨 있음</li>
<li>req.params: 라우트 매개변수에 대한 정보가 담긴 객체 </li>
<li>req.query: 쿼리스트링에 대한 정보가 담긴 객체 </li>
<li>req.signedCookies: 서명된 쿠키들은 req.cookies 대신 여기에 담겨 있음</li>
<li>req.get(헤더 이름): 헤더의 값을 가져오고 싶을 때 사용하는 메서드 </li>
</ul>
<h3 id="2-res">2) res</h3>
<p><strong>res는 서버가 클라이언트에게 응답을 보낼 때 사용하는 객체</strong></p>
<ul>
<li>res.app: req.app처럼 res 객체를 통해 app 객체에 접근 </li>
<li>res.cookie(키, 값, 옵션): 쿠키를 설정하는 메서드 </li>
<li>res.clearCookie(키, 값, 옵션): 쿠키를 제거하는 메서드 </li>
<li>res.end(): 데이터 없이 응답을 보냄</li>
<li>res.json(JSON): JSON 형식의 응답을 보냄</li>
<li>res.redirect(주소): 리다이렉트할 주소와 함께 응답을 보냄</li>
<li>res.render(뷰, 데이터): 다음 절에서 다룰 템플릿 엔진을 렌더링해서 응답할 때 사용하는 메서드 </li>
<li>res.send(데이터): 데이터와 함께 응답을 보냄. 데이터는 문자열, HTML, 버퍼,객체나 배열 다 가능</li>
<li>res.sendFile(경로): 경로에 위치한 파일을 응답 </li>
<li>res.set(헤더, 값): 응답의 헤더를 설정 </li>
<li>res.status(코드): 응답 시의 HTTP 상태 코드를 지정 </li>
</ul>
<h2 id="5-pug-템플릿-엔진">5. pug 템플릿 엔진</h2>
<p>템플릿 엔진: HTML의 단점을 개선</p>
<ul>
<li>반복문 조건문 변수 등을 사용할 수 있음</li>
<li>동적인 페이지 작성 가능</li>
<li>PHP, JSP 와 유사</li>
<li>대표적으로 pug가 있음 </li>
</ul>
<p>Pug</p>
<ul>
<li>태그를 닫을 필요 X</li>
<li>들여쓰기로 표현</li>
<li>css 처럼 표현 가능! <code>&lt;div class=&quot;jade&quot;&gt;&lt;/div&gt;</code> =&gt; <code>.jade</code>로 표현!</li>
</ul>
<p>보통 <strong>views 폴더 안에 pug 파일들을 위치</strong>시킴
<code>npm i pug</code>: 설치</p>
<p><strong>코드 예제</strong></p>
<pre><code class="language-js">//app.js -&gt; pug 템플릿 설정해줘야함 
app.set(&#39;views&#39;, path.join(__dirname, &#39;views&#39;)); // 템플릿 파일 위치
app.set(&#39;view engine&#39;, &#39;pug&#39;);                   // Pug를 템플릿 엔진으로 설정</code></pre>
<pre><code class="language-js">//views/layout.pug
doctype html
html
  head
    title= title
    link(rel=&#39;stylesheet&#39;, href=&#39;/style.css&#39;)
  body
    block content

//views/index.pug
extends layout
block content
  h1= title
  p Welcome to #{title}

//views/error.pug
extends layout
block content
  h1= message
  h2= error.status
  pre #{error.stack}</code></pre>
<h2 id="6-nonjucks-템플릿-엔진">6. nonjucks 템플릿 엔진</h2>
<p>pug 가 익숙해지지 않으면 nonjucks!
확장자는 html로 함</p>
<p><strong>코드예제</strong></p>
<pre><code class="language-js">//app.js
const nunjucks = require(&#39;nunjucks&#39;);
app.set(&#39;view engine&#39;, &#39;html&#39;);
nunjucks.configure(&#39;views&#39;, {
  express: app,
  watch: true,
});</code></pre>
<pre><code class="language-js">//views/layout.html
&lt;!DOCTYPE html&gt;
&lt;html&gt;
  &lt;head&gt;
    &lt;title&gt;{{title}}&lt;/title&gt;
    &lt;link rel=&quot;stylesheet&quot; href=&quot;/style.css&quot; /&gt;
  &lt;/head&gt;
  &lt;body&gt;
    {% block content %}
    {% endblock %}
  &lt;/body&gt;
&lt;/html&gt;

//views/error.html
{% extends &#39;layout.html&#39; %}
&lt;h1&gt;&lt;%= message %&gt;&lt;/h1&gt;
&lt;h2&gt;&lt;%= error.status %&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;%= error.stack %&gt;&lt;/pre&gt;

//views/index.html
{% extends &#39;layout.html&#39; %}
{% block content %}
&lt;h1&gt;{{title}}&lt;/h1&gt;
&lt;p&gt;Welcome to {{title}}&lt;/p&gt;
{% endblock %}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Nodejs Chap6-1 Express]]></title>
            <link>https://velog.io/@to_world/Nodejs-Chap6-Express</link>
            <guid>https://velog.io/@to_world/Nodejs-Chap6-Express</guid>
            <pubDate>Sun, 23 Feb 2025 06:22:01 GMT</pubDate>
            <description><![CDATA[<h2 id="1-express">1. express</h2>
<h3 id="1-express-다운받기">1) express 다운받기</h3>
<p><code>npm i express</code></p>
<h3 id="2-express-간단히-이용해보기">2) express 간단히 이용해보기</h3>
<p>express를 쓰면 앞장에서 살펴본 것처럼 if 문으로 도배하지 않아도 된다.
훨씬 간단한 코드가 가능해짐</p>
<pre><code class="language-js">const express = require(&#39;express&#39;);
const app = express();
const path = require(&#39;path&#39;);
app.set(&#39;port&#39;, process.env.PORT || 3000);

app.get(&#39;/&#39;, (req, res) =&gt; {
    res.sendFile(path.join(__dirname, &#39;index.html&#39;));
});

app.listen(app.get(&#39;port&#39;), () =&gt; {
    console.log(&#39;express 서버 실행&#39;);
});</code></pre>
<h2 id="2-미들웨어">2. 미들웨어</h2>
<p>여러 종류의 미들웨어가 존재, 미들웨어 간의 코드순서도 중요</p>
<h3 id="1-애플리케이션-레벨-미들웨어">1) 애플리케이션 레벨 미들웨어</h3>
<p><code>use</code>이용,  <code>next()</code>로 실행
<strong>모든 라우터에 적용할 수 있도록 함</strong></p>
<p><code>next()</code>: next를 호출해야 다음 코드로 넘어감</p>
<ul>
<li>next에 인수로 값을 넣으면 에러 핸들러로 넘어감</li>
<li>next(&#39;route&#39;): 인수에 route가 들어간 경우만 다음 라우트로 이동</li>
</ul>
<p><strong>코드 예제</strong>
<code>/category/:name</code>  라우터: 라우트 파라미터로 변수처럼 이용
예를 들어,  <a href="http://localhost:3000/category/python">http://localhost:3000/category/python</a> → hello python 이 나타남</p>
<pre><code class="language-js">//6.1, app.js
const express = require(&#39;express&#39;);
const app = express();
const path = require(&#39;path&#39;);

app.set(&#39;port&#39;, process.env.PORT || 3000);

//use -&gt; 미들웨어, 모든 라우터에 실행됨
//next()로 실행해줘야함
app.use((req, res,next) =&gt; {
    console.log(&quot;모든 요청에 실행됨&quot;);
    next();
});

app.get(&#39;/&#39;, (req, res) =&gt; {
    res.sendFile(path.join(__dirname, &#39;index.html&#39;));
});
app.get(&#39;/category/javascript&#39;,(req, res)=&gt; {
    res.send(&#39;hello javascript&#39;);
});
//404같은 오류가 날때 처리하기 좋음
app.get(&#39;*&#39;, (req, res) =&gt; {
    res.send(&#39;*&#39;); 
});
app.listen(app.get(&#39;port&#39;), () =&gt; {
    console.log(&#39;express 서버 실행&#39;);
});</code></pre>
<h3 id="2--라우터-레벨-미들웨어">2 ) 라우터 레벨 미들웨어</h3>
<p>특정 라우터에만 작동</p>
<pre><code class="language-js">app.get(&#39;/&#39;, (req, res) =&gt; {
    res.sendFile(path.join(__dirname, &#39;index.html&#39;));
})</code></pre>
<h3 id="3-에러-처리-미들웨어">3) 에러 처리 미들웨어</h3>
<p>err,req,res,next까지 매개변수 4개 이용
res.status() -&gt; HTTP 상태 코드 지정(기본값200)
특별한 경우가 아니면 가장 아래에 위치</p>
<p>코드 예제: 에러를 발생시키는 미들웨어를 넣은 뒤, 그 에러를 처리 </p>
<pre><code class="language-js">const express = require(&#39;express&#39;);
const app = express();
const path = require(&#39;path&#39;);

app.set(&#39;port&#39;, process.env.PORT || 3000);
//두개의 미들웨어
//첫번째: 요청이 올때마다 console.log를 출력하고 다음 미들웨어로 넘어감
//두번째: 에러를 발생시키고 next(error)로 에러를 다음 핸들러로 넘김
app.use((req, res,next) =&gt; {
    console.log(&quot;모든 요청에 실행됨&quot;);
    next();
}, (req, res, next) =&gt; {
    try { console.log(asdf); }
    catch (err) {
        next(err);
    }
});

app.get(&#39;/&#39;, (req, res) =&gt; { 
    res.json({ hello: &#39;jade&#39; });
    console.log(&#39;hello jade&#39;);
;}); 

//error 처리
app.use((err,req, res, next) =&gt; {
    res.status(200).send(&#39;404발생&#39;);
    console.log(err);
});
app.use((err,req, res, next) =&gt; {
    res.status(200).send(&#39;에러가 발생했어요ㅜ&#39;);
})

app.listen(app.get(&#39;port&#39;), () =&gt; {
    console.log(&#39;express 서버 실행&#39;);
});</code></pre>
<h3 id="4-서드파티-미들웨어">4) 서드파티 미들웨어</h3>
<p>외부 라이브러리 사용: 대표적으로 morgan, cookie-parser, express-session, multer
<code>npm i margan cookie-parser express-session</code> : 설치</p>
<p><strong>1. morgan, cookie-parser</strong> 예제코드</p>
<ul>
<li>morgan : 어디서 어떤 http 코드를 받았는지 알 수 있음</li>
<li>cookie-parser: 쿠키 관련 조작<pre><code class="language-js">const express = require(&#39;express&#39;);
const app = express();
const path = require(&#39;path&#39;);
const morgan = require(&#39;morgan&#39;);
const cookieParser = require(&#39;cookie-parser&#39;);
</code></pre>
</li>
</ul>
<p>app.set(&#39;port&#39;, process.env.PORT || 3000);
app.use(morgan(&#39;dev&#39;)); // GET / 301 라는 console.log가 뜸
app.use(cookieParser(&#39;zerochopasswd&#39;)); </p>
<p>// 루트 경로
app.get(&#39;/&#39;, (req, res) =&gt; {
    req.cookies;<br>    req.signedCookies; //쿠키 암호화
    res.cookie(&#39;name&#39;, encodeURIComponent(name), {
        expires: new Date(),
        httpOnly: true,
        path:&#39;/&#39;
    });
    res.clearCookie(&#39;name&#39;, encodeURIComponent(name), {
        httpOnly: true,
        path: &#39;/&#39;
    });
    res.sendFile(path.join(__dirname, &#39;index.html&#39;));
});</p>
<p>app.listen(app.get(&#39;port&#39;), () =&gt; {
    console.log(&#39;express 서버 실행&#39;);
});</p>
<pre><code>
**2. express-session** 코드예제
-&gt; 세션 관리용, 로그인/로그아웃 기능을 할때 많이 쓰임

```js
const express = require(&#39;express&#39;);
const session = require(&#39;express-session&#39;);
const app = express();

app.use(session({
    secret: &#39;mySecretKey&#39;,      // 세션 암호화에 사용될 키
    resave: false,              // 세션을 강제로 저장할지 여부
    saveUninitialized: false,   // 초기화되지 않은 세션을 저장할지 여부
    cookie: { secure: false }   // true면 HTTPS에서만 쿠키 전송
}));

app.get(&#39;/&#39;, (req, res) =&gt; {
    req.session.user = &#39;홍길동&#39;; // 세션에 사용자 저장
    res.send(&#39;세션 생성 완료&#39;);
});

app.get(&#39;/session-check&#39;, (req, res) =&gt; {
    if (req.session.user) {
        res.send(`세션 사용자: ${req.session.user}`);
    } else {
        res.send(&#39;세션 없음&#39;);
    }
});

app.get(&#39;/logout&#39;, (req, res) =&gt; {
    req.session.destroy((err) =&gt; {
        if (err) return res.send(&#39;로그아웃 실패&#39;);
        res.send(&#39;로그아웃 완료&#39;);
    });
});

app.listen(3000, () =&gt; {
    console.log(&#39;서버 실행 중...&#39;);
});
</code></pre><p><strong>3. multer</strong></p>
<ul>
<li>multer는 파일 업로드를 처리</li>
<li>디스크 저장, 메모리 저장 모두 가능</li>
<li>파일 크기, 형식 제한 등 다양한 옵션 제공</li>
<li>프로필 사진, 게시판 첨부파일, 이미지 갤러리 같은 기능 구현에 필수</li>
</ul>
<p><strong>+)dotenv</strong>: 민감한 데이터를 별도의 파일에 저장하고 안전하게 불러올 수 있음
ex) key를 환경변수에 숨겨넣는 방법</p>
<pre><code class="language-js">//dotenv.js
const express = require(&#39;express&#39;);
const cookieParser = require(&#39;cookie-parser&#39;);
const session = require(&#39;express-session&#39;);
const dotenv = require(&#39;dotenv&#39;);
const path = require(&#39;path&#39;);

dotenv.config(); //dotenv!
const app = express();
app.set(&#39;port&#39;, process.env.PORT || 3000);

app.use(morgan(&#39;dev&#39;));
app.use(&#39;/&#39;, express.static(path.join(__dirname, &#39;public&#39;)));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser(process.env.COOKIE_SECRET)); //dotenv! 환경변수에 저장
app.use(session({
  resave: false,
  saveUninitialized: false,
  secret: process.env.COOKIE_SECRET, //dotenv!
  cookie: {
    httpOnly: true,
    secure: false,
  },
  name: &#39;session-cookie&#39;,
}));

const multer = require(&#39;multer&#39;);
const fs = require(&#39;fs&#39;);
//uploads 폴더가 있는지 확인, 없으면 생성
try {
  fs.readdirSync(&#39;uploads&#39;);
} catch (error) {
  console.error(&#39;uploads 폴더가 없어 uploads 폴더를 생성합니다.&#39;);
  fs.mkdirSync(&#39;uploads&#39;);
}
const upload = multer({
 //storage: 업로드한 파일을 어디에 저장할 것인지, 어떤 이름으로 저장할 것인지
  storage: multer.diskStorage({
    destination(req, file, done) {
      done(null, &#39;uploads/&#39;); //파일 저장위치
    },
    filename(req, file, done) { //파일 이름
      const ext = path.extname(file.originalname);
      done(null, path.basename(file.originalname, ext) + Date.now() + ext);
    },
  }),
  //limits: 파일 사이즈, 개수
  limits: { fileSize: 5 * 1024 * 1024 },
});

app.get(&#39;/upload&#39;, (req, res) =&gt; {
  res.sendFile(path.join(__dirname, &#39;multipart.html&#39;));
});
//POST 요청 시 파일 업로드 처리
//input 태그의 name=&quot;image&quot;인 파일 하나만 업로드, 성공하면 ok
app.post(&#39;/upload&#39;, upload.single(&#39;image&#39;), (req, res) =&gt; {
  console.log(req.file);
  res.send(&#39;ok&#39;);
});

app.get(&#39;/&#39;, (req, res, next) =&gt; {
  console.log(&#39;GET / 요청에서만 실행됩니다.&#39;);
  next();
}, (req, res) =&gt; {
  throw new Error(&#39;에러는 에러 처리 미들웨어로 갑니다.&#39;)
});</code></pre>
<pre><code class="language-js">//.env 파일
COOKIE_SECRET=cookiesecret</code></pre>
<h3 id="5-내장-미들웨어-express-기본-제공">5) 내장 미들웨어 (Express 기본 제공)</h3>
<p>express.static: 정적 파일 제공
express.json: JSON 데이터 처리</p>
<pre><code class="language-js">app.use(express.json());
app.use(&#39;/&#39;, express.static(__dirname, &#39;public&#39;));
//&#39;요청경로&#39;, express.static(&#39;실제경로&#39;)</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Nodejs Chap5 npm, package]]></title>
            <link>https://velog.io/@to_world/Chap5-npm-package</link>
            <guid>https://velog.io/@to_world/Chap5-npm-package</guid>
            <pubDate>Sun, 23 Feb 2025 06:03:23 GMT</pubDate>
            <description><![CDATA[<h2 id="1-npm-package">1. npm, package</h2>
<p>*<em>npm=node package manager *</em></p>
<ul>
<li>노드의 패키지 매니저</li>
<li>다른 사람들이 만든 소스코드들을 모아둔 저장소 </li>
<li>오픈소스</li>
</ul>
<p><strong>package.json</strong></p>
<ul>
<li>현재 프로젝트에 대한 정보와 사용중인 패키지에 대한 정보를 담은 파일</li>
<li><code>npm init</code> 으로 만들 수 있음</li>
</ul>
<p><strong>package-lock.json</strong>
<code>npm i D nodemon</code>으로 다운</p>
<p><strong>node_modules</strong></p>
<ul>
<li>다운받은 패키지들이 모여있는 곳</li>
<li><code>npm install</code> 로 다운 가능</li>
</ul>
<h2 id="2-npm-명령어">2. npm 명령어</h2>
<p><a href="https://docs.npmjs.com/cli/v9/commands?v=true">https://docs.npmjs.com/cli/v9/commands?v=true</a>
이 주소에 가면 여러 npm 명령어들이 설명되어 있음</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Nodejs Chap4-2 요청과 응답]]></title>
            <link>https://velog.io/@to_world/Chap4-2-%EC%9A%94%EC%B2%AD%EA%B3%BC-%EC%9D%91%EB%8B%B5</link>
            <guid>https://velog.io/@to_world/Chap4-2-%EC%9A%94%EC%B2%AD%EA%B3%BC-%EC%9D%91%EB%8B%B5</guid>
            <pubDate>Fri, 21 Feb 2025 17:36:25 GMT</pubDate>
            <description><![CDATA[<h2 id="1-https-http2">1. https, http2</h2>
<h3 id="1-https">1) https</h3>
<p>웹 서버에 SSL 암호를 거는 모듈 제공
https의 port는 443</p>
<pre><code class="language-js">const https = require(&#39;https&#39;);
const fs = require(&#39;fs&#39;);

//서버가 시작되기 전에 인증서를 읽고 넣어줘야함
//인증서: cert, key, ca -&gt; fs로 가져와야함
//https로 하면 port가 443
https.createServer({
  cert: fs.readFileSync(&#39;도메인 인증서 경로&#39;),
  key: fs.readFileSync(&#39;도메인 비밀키 경로&#39;),
  ca: [
    fs.readFileSync(&#39;상위 인증서 경로&#39;),
    fs.readFileSync(&#39;상위 인증서 경로&#39;),
  ],
}, (req, res) =&gt; {
  res.writeHead(200, { &#39;Content-Type&#39;: &#39;text/html; charset=utf-8&#39; });
  res.write(&#39;&lt;h1&gt;Hello Node!&lt;/h1&gt;&#39;);
  res.end(&#39;&lt;p&gt;Hello Server!&lt;/p&gt;&#39;);
})
  .listen(443, () =&gt; {
    console.log(&#39;443번 포트에서 서버 대기 중입니다!&#39;);
  });</code></pre>
<h3 id="2-http2">2) http2</h3>
<p>SSL 암호화와 더불어 최신 HTTP 프로토콜인 http/2를 사용하는 모듈
요청 및 응답 방식이 기존 http/1.1보다 개선됨
웹의 속도가 개선됨
요청을 하나씩(http)이 아닌 여러개를 동시에 보낼 수 있음</p>
<pre><code class="language-js">//http2
const http2 = require(&#39;http2&#39;);
const fs = require(&#39;fs&#39;);

//여기도 인증서 가져와야함
//port 443
http2.createSecureServer({
  cert: fs.readFileSync(&#39;도메인 인증서 경로&#39;),
  key: fs.readFileSync(&#39;도메인 비밀키 경로&#39;),
  ca: [
    fs.readFileSync(&#39;상위 인증서 경로&#39;),
    fs.readFileSync(&#39;상위 인증서 경로&#39;),
  ],
}, (req, res) =&gt; {
  res.writeHead(200, { &#39;Content-Type&#39;: &#39;text/html; charset=utf-8&#39; });
  res.write(&#39;&lt;h1&gt;Hello Node!&lt;/h1&gt;&#39;);
  res.end(&#39;&lt;p&gt;Hello Server!&lt;/p&gt;&#39;);
})
  .listen(443, () =&gt; {
    console.log(&#39;443번 포트에서 서버 대기 중입니다!&#39;);
  });</code></pre>
<h2 id="2-cluster">2. Cluster</h2>
<p>원래 nodejs는 단일 스레드에서 동작 -&gt; 하나의 cpu 코어만 사용
Cluster -&gt; 여러 개의 프로세스를 생성하여 모든 CPU 코어를 사용가능</p>
<p>요청이 많이 들어왔을 때 병렬로 실행된 서버의 개수만큼 요청이 분산됨-&gt;서버에 무리가 덜감
cluster로 코어 하나 당 노드 프로세스 하나를 배정 가능
단점: 컴퓨터 자원(메모리 세션 등) 공유 못함</p>
<p>워커스레드 기능과 유사</p>
<ul>
<li>워커스레드: 여러 스레드를 만듦</li>
<li>클러스터: 여러 프로세스를 만듦</li>
</ul>
<pre><code class="language-js">const cluster = require(&#39;cluster&#39;);
const http = require(&#39;http&#39;);
const numCPUs = require(&#39;os&#39;).cpus().length;

if (cluster.isMaster) {
  console.log(`마스터 프로세스 아이디: ${process.pid}`);
  // CPU 개수만큼 워커를 생산
  for (let i = 0; i &lt; numCPUs; i += 1) {
    cluster.fork();
  }
  // 워커가 종료되었을 때
  cluster.on(&#39;exit&#39;, (worker, code, signal) =&gt; {
    console.log(`${worker.process.pid}번 워커가 종료되었습니다.`);
    console.log(&#39;code&#39;, code, &#39;signal&#39;, signal);
    cluster.fork();
  });
} else {
  // 워커들이 포트에서 대기
  http.createServer((req, res) =&gt; {
    res.writeHead(200, { &#39;Content-Type&#39;: &#39;text/html; charset=utf-8&#39; });
    res.write(&#39;&lt;h1&gt;Hello Node!&lt;/h1&gt;&#39;);
    res.end(&#39;&lt;p&gt;Hello Cluster!&lt;/p&gt;&#39;);
    setTimeout(() =&gt; { // 워커 존재를 확인하기 위해 1초마다 강제 종료
      process.exit(1);
    }, 1000);
  }).listen(8086);

  console.log(`${process.pid}번 워커 실행`);
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Nodejs Chap4-1 요청과 응답]]></title>
            <link>https://velog.io/@to_world/Chap4-%EC%9A%94%EC%B2%AD%EA%B3%BC-%EC%9D%91%EB%8B%B5</link>
            <guid>https://velog.io/@to_world/Chap4-%EC%9A%94%EC%B2%AD%EA%B3%BC-%EC%9D%91%EB%8B%B5</guid>
            <pubDate>Thu, 20 Feb 2025 16:20:40 GMT</pubDate>
            <description><![CDATA[<h2 id="1-서버와-클라이언트">1. 서버와 클라이언트</h2>
<h3 id="1-서버와-클라이언트의-관계">1) 서버와 클라이언트의 관계</h3>
<ul>
<li>클라이언트가 서버로 &quot;요청request&quot;을 보냄</li>
<li>서버는 요청을 처리</li>
<li>처리 후 클라이언트로 &quot;응답response&quot;을 보냄</li>
</ul>
<h3 id="2-http">2) HTTP</h3>
<pre><code class="language-js">const http = require(&#39;http&#39;);
const server = http.createServer((req, res) =&gt; {
    res.write(&#39;&lt;h1&gt;hello node&lt;/h1&gt;&#39;);
    res.write(&#39;&lt;h2&gt;hello node&lt;/h2&gt;&#39;);
    res.write(&#39;&lt;h3&gt;hello node&lt;/h3&gt;&#39;);
})
    .listen(8080);

server.on(&#39;listening&#39;, () =&gt; {
    console.log(&#39;8080포트에서 서버 대기 중입니다.&#39;);
});
server.on(&#39;error&#39;, () =&gt; {
    console.log(error);
});
</code></pre>
<p><code>localhost8080</code>에 들어가면 hello node 가 나옴!
localhost는 컴퓨터 내부 주소로 외부에서는 접근이 안됨..!</p>
<h2 id="2-fs로-html-읽어-제공하기">2. fs로 HTML 읽어 제공하기</h2>
<pre><code class="language-js">const http = require(&#39;http&#39;);
const fs = require(&#39;fs&#39;).promises;

const server = http.createServer(async(req, res) =&gt; {
    try {
        res.writeHead(200, { &#39;Content-Type&#39;: &#39;text/html; charset=utf-8&#39; });
        const data = await fs.readFile(&#39;./chap4/server2.html&#39;);
        res.end(data);
    }
    catch (error) {
        console.log(error);
        res.writeHead(200, { &#39;Content-Type&#39;: &#39;text/plain; charset=utf-8&#39; });
        res.end(error.message);
    }
})
    .listen(8080);


server.on(&#39;listening&#39;, () =&gt; {
    console.log(&#39;8080포트에서 서버 대기 중입니다.&#39;);
});
server.on(&#39;error&#39;, (error) =&gt; {
    console.log(error);
});
</code></pre>
<h2 id="3-rest-api-서버">3. REST API 서버</h2>
<p>서버에 요청을 보낼 때 주소를 통해 요청의 내용을 표현
-&gt; 서버가 이해하기 쉬운 주소로 보내는게 좋음
<strong>REST API</strong>: 주소를 정하는 규칙</p>
<ul>
<li>ex) /post : 게시글과 관련된 요청</li>
</ul>
<h3 id="1-http-프로토콜">1) HTTP 프로토콜</h3>
<p>RESTful: REST API를 사용한 주소 체계를 이용하는 서버</p>
<p><strong>GET</strong>: 서버 자원을 가져와야 할 때
<strong>POST</strong>: 서버에 자원을 새로 등록하고자 할때
<strong>PUT</strong>: 서버의 자원을 요청에 들어잇는 자원으로 치환하려 할때(전체수정)
<strong>PATCH</strong>: 서버 자원의 일부만 수정하고자 할때(일부수정)
<strong>DELETE</strong>: 서버의 자원을 삭제하고자 할때</p>
<h3 id="2-crud-rest-api-서버-만들어보기">2) CRUD REST API 서버 만들어보기</h3>
<p><strong>이 서버의 설명</strong></p>
<ul>
<li>GET / → restFront.html 제공</li>
<li>GET /about → about.html 제공</li>
<li>GET /users → 저장된 사용자 목록(JSON) 반환</li>
<li>POST /user → 새로운 사용자 추가</li>
<li>PUT /user/:id → 사용자 정보 수정</li>
<li>DELETE /user/:id → 사용자 삭제</li>
<li>파일 제공 기능 → 정적 파일 요청 처리</li>
<li>존재하지 않는 라우트 요청 시 404 NOT FOUND</li>
<li>서버 오류 시 500 INTERNAL SERVER ERROR</li>
</ul>
<p><code>writeHead</code> : http 서버에서 응답헤더를 설정</p>
<ul>
<li>http 상태코드와 응답헤더를 설정한 후 본문을 전송할 준비를 함</li>
<li><code>res.end()</code>로 본문을 전송하여 응답 완료<pre><code class="language-js">const http = require(&#39;http&#39;);
const fs = require(&#39;fs&#39;).promises;
const path = require(&#39;path&#39;);
</code></pre>
</li>
</ul>
<p>const users = {}; // 데이터 저장용</p>
<p>//서버 생성, req: request, res: respond
http.createServer(async (req, res) =&gt; {
  try {
    if (req.method === &#39;GET&#39;) {
      //GET /: restFront.html 파일을 읽어와 응답
      //200 응답코드와 함께 html 반환
      if (req.url === &#39;/&#39;) {
        const data = await fs.readFile(path.join(<strong>dirname, &#39;restFront.html&#39;));
        res.writeHead(200, { &#39;Content-Type&#39;: &#39;text/html; charset=utf-8&#39; });
        //200,201 -&gt; 성공적으로 요청에 응답
        //404 -&gt; 요청에 응답 실패 NOT FOUND
        return res.end(data);
      }
      //GET /about: about.html을 읽어와 응답
      else if (req.url === &#39;/about&#39;) {
        const data = await fs.readFile(path.join(</strong>dirname, &#39;about.html&#39;));
        res.writeHead(200, { &#39;Content-Type&#39;: &#39;text/html; charset=utf-8&#39; });
        return res.end(data);
      }
      //GET/ users: users 객체를 JSON 형식으로 응답
      else if (req.url === &#39;/users&#39;) {
        res.writeHead(200, { &#39;Content-Type&#39;: &#39;application/json; charset=utf-8&#39; });
        return res.end(JSON.stringify(users));
      }
      // /도 /about도 /users도 아니면
      try {
        const data = await fs.readFile(path.join(__dirname, req.url));
        return res.end(data);
      } catch (err) {
        // 주소에 해당하는 라우트를 못 찾았다는 404 Not Found error 발생
      }
    }
    //POST 요청 처리: 사용차 추가
    else if (req.method === &#39;POST&#39;) {
      // POST /user
      if (req.url === &#39;/user&#39;) {
        let body = &#39;&#39;;
        // 데이터를 스트림 형태로 받아 body 변수에 저장
        req.on(&#39;data&#39;, (data) =&gt; {
          body += data;
        });
        // 요청의 body를 다 받은 후 실행됨
        // 받은 JSON 데이터를 파싱하여 사용자 객체에 추가
        return req.on(&#39;end&#39;, () =&gt; {
          console.log(&#39;POST 본문(Body):&#39;, body);
          const { name } = JSON.parse(body);
          const id = Date.now();
          users[id] = name;
          res.writeHead(201, { &#39;Content-Type&#39;: &#39;text/plain; charset=utf-8&#39; });
          res.end(&#39;등록 성공&#39;);
        });
      }
    }
    //PUT /user:id : 해당 사용자의 정보 수정
    else if (req.method === &#39;PUT&#39;) {
      if (req.url.startsWith(&#39;/user/&#39;)) {
        const key = req.url.split(&#39;/&#39;)[2];
        // /user/12345 같은 요청에서 12345를 추출하여 사용자의 키로 사용
        // 수정할 데이터(body)를 받습니다.
        let body = &#39;&#39;;
        req.on(&#39;data&#39;, (data) =&gt; {
          body += data;
        });
        return req.on(&#39;end&#39;, () =&gt; {
          console.log(&#39;PUT 본문(Body):&#39;, body);
          users[key] = JSON.parse(body).name;
          res.writeHead(200, { &#39;Content-Type&#39;: &#39;text/plain; charset=utf-8&#39; });
          return res.end(JSON.stringify(users));
        });
      }
    }
    else if (req.method === &#39;DELETE&#39;) {
      if (req.url.startsWith(&#39;/user/&#39;)) {
        //해당 키를 가진 사용자를 삭제. 삭제 후 응답
        const key = req.url.split(&#39;/&#39;)[2];
        delete users[key];
        res.writeHead(200, { &#39;Content-Type&#39;: &#39;text/plain; charset=utf-8&#39; });
        return res.end(JSON.stringify(users));
      }
    }
    //주소에 해당하는 라우트를 하나도 찾지 못했을 때 -&gt; 404 NOT FOUND
    res.writeHead(404);
    return res.end(&#39;NOT FOUND&#39;);
  } catch (err) {
    console.error(err);
    res.writeHead(500, { &#39;Content-Type&#39;: &#39;text/plain; charset=utf-8&#39; });
    res.end(err.message);
  }
})
  .listen(8082, () =&gt; {
    console.log(&#39;8082번 포트에서 서버 대기 중입니다&#39;);
  });</p>
<pre><code>
## 4. 쿠키, 세션
### 1) 쿠키
요청의 단점: 누가 요청을 보냈는지 알수가 없음
- IP주소와 브라우저 정보 정도만 알 수 있음
- &quot;누가&quot; 요청을 보냈는지를 알려면 쿠키, 세션 필요

**쿠키: 쿠키명=쿠키값 의 쌍**
- ex) name=jade
- 매 요청마다 쿠키를 서버에 동봉해서 보냄
서버가 응답할 때도 쿠키랑 같이 응답
- 서버는 쿠키를 읽어서 누구인지 파악

쿠키 옵션
- Expires, Max-age, Domain(쿠키가 전송될 도메인을 특정), Path(쿠키가 전송될 URL), Secure, HttpOnly 

**예제코드**
- 쿠키문자열을 객체로 변환(parseCookies) 
- 주소가 /login, / 인경우로 나눔
- /login : 이름을 쿠키로 5분간 저장, / 으로 redirect
- / : 쿠키가 있는지 없는지 확인
있으면 환영 인사, 없으면 로그인 페이지 띄움

```js
const http = require(&#39;http&#39;);
const fs = require(&#39;fs&#39;).promises;
const path = require(&#39;path&#39;);
//쿠키문자열을 객체{name:&quot;value&quot;}로 변환
const parseCookies = (cookie = &#39;&#39;) =&gt; 
//cookie가 null/undefined라면 빈문자열
  cookie  //&#39;cookie1=1234; cookie2=5678&#39;
    .split(&#39;;&#39;) //[&quot;cookie1=1234&quot;, &quot;cookie2=5678&quot;]
    .map(v =&gt; v.split(&#39;=&#39;)) //[[&quot;cookie1&quot;, &quot;1234&quot;], [&quot; cookie2&quot;, &quot;5678&quot;]]
    .reduce((acc, [k, v]) =&gt; {
      acc[k.trim()] = decodeURIComponent(v);
      return acc;
      //reduce() 를 이용해 {key:value}형태의 객체 생성
      //k.trim(): 공백 제거
      //decodeURLComponent(v): URL 인코딩된 값을 디코딩
    }, {}); //결과:{cookie1: &quot;1234&quot;},{cookie2: &quot;5678&quot;}

http.createServer(async (req, res) =&gt; {
  const cookies = parseCookies(req.headers.cookie); // { mycookie: &#39;test&#39; }
  // 주소가 /login으로 시작하는 경우(로그인버튼을 눌렀을때)
  if (req.url.startsWith(&#39;/login&#39;)) {
    const url = new URL(req.url, &#39;http://localhost:8084&#39;);
    const name = url.searchParams.get(&#39;name&#39;);
    const expires = new Date();
    // 쿠키 유효 시간을 현재시간 + 5분으로 설정
    expires.setMinutes(expires.getMinutes() + 5);
    res.writeHead(302, { //302-&gt; redirection
      Location: &#39;/&#39;,
      &#39;Set-Cookie&#39;: `name=${encodeURIComponent(name)}; Expires=${expires.toGMTString()}; HttpOnly; Path=/`,
    });
    res.end();
  }
    //주소가 / 이면서 쿠키가 있는 경우
  else if (cookies.name) {
    res.writeHead(200, { &#39;Content-Type&#39;: &#39;text/plain; charset=utf-8&#39; });
    res.end(`${cookies.name}님 안녕하세요`);
  }
  else {//주소가 / 이면서 쿠키가 없는 경우
    try {
      const data = await fs.readFile(path.join(__dirname, &#39;cookie2.html&#39;));
      res.writeHead(200, { &#39;Content-Type&#39;: &#39;text/html; charset=utf-8&#39; });
      res.end(data);
    } catch (err) {
      res.writeHead(500, { &#39;Content-Type&#39;: &#39;text/plain; charset=utf-8&#39; });
      res.end(err.message);
    }
  }
})
  .listen(8084, () =&gt; {
    console.log(&#39;8084번 포트에서 서버 대기 중입니다!&#39;);
  });</code></pre><h3 id="2-세션">2) 세션</h3>
<p>쿠키의 정보는 노출되고 수정되는 위험이 있음 -&gt; 세션 이용</p>
<p><strong>세션 원리</strong>
중요한 정보는 서버에서 관리하고 클라이언트에는 세션 키만 제공
서버에 세션객체 생성 후 키(uniquelnt)를 만들어 속성명으로 이용
속성 값에 정보를 저장하고 uniquelnt를 클라이언트에 제공
<em>6장에 더 깊게 다룰 예정</em></p>
<pre><code class="language-JS">const http = require(&#39;http&#39;);
const fs = require(&#39;fs&#39;).promises;
const path = require(&#39;path&#39;);

const parseCookies = (cookie = &#39;&#39;) =&gt;
  cookie
    .split(&#39;;&#39;)
    .map(v =&gt; v.split(&#39;=&#39;))
    .reduce((acc, [k, v]) =&gt; {
      acc[k.trim()] = decodeURIComponent(v);
      return acc;
    }, {});

const session = {};

http.createServer(async (req, res) =&gt; {
  const cookies = parseCookies(req.headers.cookie);
  if (req.url.startsWith(&#39;/login&#39;)) {
    const url = new URL(req.url, &#39;http://localhost:8085&#39;);
    const name = url.searchParams.get(&#39;name&#39;);
    const expires = new Date();
    expires.setMinutes(expires.getMinutes() + 5);
    //**여기부터 세션**//
    const uniqueInt = Date.now();
    session[uniqueInt] = {
      name,
      expires,
    };
    res.writeHead(302, {
      Location: &#39;/&#39;,
      &#39;Set-Cookie&#39;: `session=${uniqueInt}; Expires=${expires.toGMTString()}; HttpOnly; Path=/`,
    });
    res.end();
  // 세션쿠키가 존재하고, 만료 기간이 지나지 않았다면
  } else if (cookies.session &amp;&amp; session[cookies.session].expires &gt; new Date()) {
    res.writeHead(200, { &#39;Content-Type&#39;: &#39;text/plain; charset=utf-8&#39; });
    res.end(`${session[cookies.session].name}님 안녕하세요`);
  } else {
    try {
      const data = await fs.readFile(path.join(__dirname, &#39;cookie2.html&#39;));
      res.writeHead(200, { &#39;Content-Type&#39;: &#39;text/html; charset=utf-8&#39; });
      res.end(data);
    } catch (err) {
      res.writeHead(500, { &#39;Content-Type&#39;: &#39;text/plain; charset=utf-8&#39; });
      res.end(err.message);
    }
  }
})
  .listen(8085, () =&gt; {
    console.log(&#39;8085번 포트에서 서버 대기 중입니다!&#39;);
  });</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Chap 7 정수론]]></title>
            <link>https://velog.io/@to_world/Chap-7-%EC%A0%95%EC%88%98%EB%A1%A0</link>
            <guid>https://velog.io/@to_world/Chap-7-%EC%A0%95%EC%88%98%EB%A1%A0</guid>
            <pubDate>Thu, 20 Feb 2025 14:20:12 GMT</pubDate>
            <description><![CDATA[<h2 id="1-소수-구하기">1. 소수 구하기</h2>
<h3 id="1-에라토스테네스의-체">1) 에라토스테네스의 체</h3>
<p>에라토스테네스의 체의 원리</p>
<ol>
<li>주어진 범위까지의 배열 생성(1은 제외하고 2부터)</li>
<li>선택한 수의 배수를 모두 삭제(ex, 2의 배수를 모두 삭제)</li>
<li>다음 지워지지 않은 수(3)을 선택, -&gt; 3의 배수를 모두 삭제, 이때 이미 지운 수는 다시 지우지 않음</li>
<li>앞의 과정을 배열의 끝까지 반복</li>
<li>삭제되지 않은 수를 모두 출력</li>
</ol>
<p>에라토스테네스 체의 시간복잡도 -&gt; 문제마다 다름 <code>O(N^2) or O(Nlog(logN))</code> </p>
<h3 id="2-문제1-소수구하기-1929">2) 문제1: 소수구하기 1929</h3>
<ol>
<li>문제: <a href="https://www.acmicpc.net/problem/1929">https://www.acmicpc.net/problem/1929</a>
<img src="https://velog.velcdn.com/images/to_world/post/210af84a-9df9-4346-aaec-addd503ae90f/image.png" alt=""></li>
</ol>
<ol start="2">
<li>코드</li>
</ol>
<ul>
<li>2가 소수 -&gt; 2의 배수들 모두 <code>isPrime: false</code> 처리<pre><code class="language-cpp">#include&lt;iostream&gt; 
#include&lt;vector&gt;
using namespace std;
</code></pre>
</li>
</ul>
<p>int main() {
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);</p>
<pre><code>int m, n;
cin &gt;&gt; m &gt;&gt; n;

vector &lt;bool&gt; isPrime(n + 1, true);
isPrime[0] = false;
isPrime[1] = false;

for (int i = 2; i * i &lt;= n; i++) { 
    if (isPrime[i]) {
        for (int j = i * i; j &lt;= n; j += i) {
            isPrime[j] = false;
        }
    }  
}

for (int i = m; i &lt;= n; i++) {
    if (isPrime[i]) cout &lt;&lt; i &lt;&lt; &quot;\n&quot;;
}
return 0;</code></pre><p>}</p>
<pre><code>### 3) 문제2: 거의 소수 1456
1. 문제
https://www.acmicpc.net/problem/1456
소수의 제곱의 개수를 찾는 문제

2. 코드
- 범위 -&gt; int 가 아닌 longlong을 써야함!
- 거의 소수 구할 때 a와 b사이 범위 안에서 카운트 하도록 조건 넣어줘야함!
```cpp
#include&lt;iostream&gt;
#include&lt;vector&gt;
#include&lt;cmath&gt;
using namespace std;
typedef long long ll;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);

    ll a, b;
    cin &gt;&gt; a &gt;&gt; b;
    int limit = sqrt(b) + 1;
    vector &lt;bool&gt; isPrime(limit + 1, true);
    vector &lt;int&gt;primes;

    //소수구하기
    for (ll i = 2; i &lt;= limit; i++) {
        if (isPrime[i]) {
            primes.push_back(i);
            for (ll j = i * i; i &lt;= b; j += i) {
                isPrime[j] = false;
            }
        }
    }

    //거의 소수 구하기
    ll cnt = 0;
    for (ll i : primes) {
        ll temp = i * i;
        while (temp &lt;= b) {
            if (temp &gt;= a) {
                cnt++;
            }
            if (temp &gt; (b / i)) break;
            temp *= i;
        }
    }
    cout &lt;&lt; cnt;

    return 0;
}</code></pre><h3 id="3-문제3-소수팰린드롬-1747번">3) 문제3: 소수&amp;팰린드롬 1747번</h3>
<ol>
<li><p>문제 <a href="https://www.acmicpc.net/problem/1747">https://www.acmicpc.net/problem/1747</a>
<img src="https://velog.velcdn.com/images/to_world/post/15ec0023-60d5-4974-8fb7-6106b83002a9/image.png" alt=""></p>
</li>
<li><p>코드</p>
</li>
</ol>
<ul>
<li><p>팰린드롬 &lt;- 투포인터로 찾기
숫자를 문자열로 바꾼 후, 투포인터를 이용해 비교</p>
<pre><code class="language-cpp">#include&lt;iostream&gt;
#include&lt;vector&gt;
#include&lt;string&gt; 
using namespace std; 
int main() {
  ios::sync_with_stdio(false);
  cin.tie(NULL); cout.tie(NULL);
  //입력받기
  int n;
  cin &gt;&gt; n;

  vector &lt;bool&gt; isPrime(10000001, true);
  isPrime[0] = false; isPrime[1] = false;

  string num;
  bool pen = false;

  //소수를 찾기
  for (int i = 2; i*i&lt;= 10000000; i++) {
      if (isPrime[i]) {
          for (int j = i * i; j &lt;= 10000000; j += i) {
              isPrime[j] = false;
          }
      }
  }

  //소수의 값을 char 형태로 변환 후 투포인터를 이용해 팰린드롬 여부 확인
  for (int i = n; i &lt;= 10000000; i++) {
      if (isPrime[i]) {
          pen = true;
          num = to_string(i);
          int ind1 = 0; int ind2 = num.length()- 1;
          while (ind1 &lt;= ind2) {
              if (num[ind1] == num[ind2]) {
                  ind1++;
                  ind2--;
              }
              else {
                  pen = false;
                  break;
              }
          }
      }
      if (pen) {
          cout &lt;&lt; num;
          break;
      }
  }
  return 0;
</code></pre>
</li>
</ul>
<p>}</p>
<pre><code>








1016번

오일러피 관련 문제: 11689
유클리드 호제법 문제: 1934 1850 1033
확장 유클리드 호제법: 21568</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[Chap6 그리디 알고리즘]]></title>
            <link>https://velog.io/@to_world/Chap6-%EA%B7%B8%EB%A6%AC%EB%94%94-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</link>
            <guid>https://velog.io/@to_world/Chap6-%EA%B7%B8%EB%A6%AC%EB%94%94-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</guid>
            <pubDate>Mon, 17 Feb 2025 16:58:19 GMT</pubDate>
            <description><![CDATA[<h2 id="1-개념">1. 개념</h2>
<p>현재 상태에서 보는 최선의 선태이 전체 선택지 중 최선의 선택지라고 가정하는 알고리즘</p>
<h2 id="2-대표-코드">2. 대표 코드</h2>
<p>코드 작동 원리</p>
<ul>
<li>해 선택: 현재 상태에서 최선이라고 생각되는 해를 선택</li>
<li>적절성 검사: 현재 선택한 해가 전체 문제의 제약 조건에서 벗어나지 않는지 검사</li>
<li>해검사: 현재까지 선택한 해 집합이 전체 문제를 해결할 수 있는지 검사
  -&gt; 전체 문제를 해결하지 못한다면 처음으로 돌아가 &#39;해 선택&#39;부터 반복</li>
</ul>
<h2 id="3-문제1-동전-0-11047번">3. 문제1: 동전 0 11047번</h2>
<ol>
<li><p>문제: <a href="https://www.acmicpc.net/problem/11047">https://www.acmicpc.net/problem/11047</a>
<img src="https://velog.velcdn.com/images/to_world/post/622e2cb8-2d44-4926-9433-dd64d23b359b/image.png" alt=""></p>
</li>
<li><p>코드</p>
</li>
</ol>
<ul>
<li>가격이 큰 것부터 k보다 작거나 같은 동전이 나올 때까지 탐색</li>
<li>예제코드1로 설명해보면(k=4200) 
4200/1000=4 -&gt; sum=4, k=200 </li>
<li>아직 k가 0보다 크니까, 이 과정을 반복</li>
<li>200/100=2 -&gt; sum+=2, k=0</li>
<li>결과(sum)는 6이 됨<pre><code class="language-cpp">#include&lt;iostream&gt;
#include&lt;vector&gt; 
using namespace std;
</code></pre>
</li>
</ul>
<p>int main() {
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);</p>
<pre><code>int n, k;
cin &gt;&gt; n &gt;&gt; k;

vector &lt;int&gt; coin(n, 0);
for (int i = 0; i &lt; n; i++) {
    cin &gt;&gt; coin[i];
}

int sum = 0;
for (int i = n - 1; i &gt;= 0; i--) {
    if (k &gt;= coin[i]) {
        sum += (k / coin[i]); //4200/1000=4
        k = k % coin[i]; //4200%1000=200
    }
}


cout &lt;&lt; sum;
return 0;</code></pre><p>}</p>
<pre><code>## 4. 문제2: 잃어버린 괄호 1541번
1. 문제: https://www.acmicpc.net/problem/1541
![](https://velog.velcdn.com/images/to_world/post/163b95fc-9073-4f09-a85f-55e2cab1b830/image.png)


2. 코드
- ```atoi()``` -&gt; 문자열을 정수형으로 바꿔주는 기능
- 20-50+40 -&gt; 20-(50+40) 이어야 최솟값이 됨
20-50+40-30+20 -&gt; 20-(50+40)-(30+20) -&gt; 최솟값
=&gt; 덧셈을 최대한 뺄셈으로 바꿔주는 것이 중요
- &#39;-&#39; 를 만난뒤에 나오는 &#39;+&#39; 는 &#39;-&#39; 처리되어야함
&#39;-&#39; 를 만나기 전에 나오는 + 는 그대로 + 처리
- 문제에 - 를 한번만 써야한다는 제약은 없으므로 - 뒤에 나오는 모든 + 를 - 로 계속 바꿔주면 됨
```cpp
#include&lt;iostream&gt;
#include&lt;string&gt; //문자열을 숫자로 바꿔줄 수 있는 기능!
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);

    string number = &quot;&quot;;
    int res = 0;
    string s;
    cin &gt;&gt; s;
    bool isMinus = false;

    for (int i = 0; i &lt;= s.length(); i++) {
        if (s[i] == &#39;+&#39; || s[i] == &#39;-&#39; || i == s.length()) {
            if (isMinus) {
                res -= stoi(number); //문자열을 정수형으로 바꿔줌
                number = &quot;&quot;;
            }
            else {
                res += stoi(number);
                number = &quot;&quot;;
            }
        }
        else { //숫자를 만난 경우
            number += s[i];
        }

        if (s[i] == &#39;-&#39;) {
            isMinus = true;
        }

    }
    cout &lt;&lt; res;
    return 0;
}</code></pre><h2 id="5-못푼-문제들">5 못푼 문제들</h2>
<p><a href="https://www.acmicpc.net/problem/1931">https://www.acmicpc.net/problem/1931</a>
<a href="https://www.acmicpc.net/problem/1744">https://www.acmicpc.net/problem/1744</a>
<a href="https://www.acmicpc.net/problem/1715">https://www.acmicpc.net/problem/1715</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Chap5-2탐색]]></title>
            <link>https://velog.io/@to_world/Chap5-2%ED%83%90%EC%83%89</link>
            <guid>https://velog.io/@to_world/Chap5-2%ED%83%90%EC%83%89</guid>
            <pubDate>Sun, 16 Feb 2025 16:00:24 GMT</pubDate>
            <description><![CDATA[<h2 id="1-이진탐색">1. 이진탐색</h2>
<h3 id="1-개념">1) 개념</h3>
<p><strong>&quot;데이터가 정렬된 상태에서&quot;</strong> 원하는 값을 찾아내는 알고리즘
대상 데이터의 중앙값과 찾고자 하는 값을 비교해 데이터의 크기를 절반씩 줄여나가는 것
시간복잡도: <code>O(logN)</code></p>
<h3 id="2-대표코드">2) 대표코드</h3>
<p><strong>이진 탐색과정</strong></p>
<ul>
<li>현재 데이터의 중앙값 선택 </li>
<li>중앙값&gt;타깃값 -&gt; 중앙값 기준 왼쪽 데이터셋 선택
중앙값&lt;타깃값 -&gt;중앙값 기준 오른쪽 데이터셋 선택</li>
<li>반복하다가 중앙값=타깃값 -&gt; 종료</li>
</ul>
<pre><code class="language-cpp">while (s &lt;= e) {
    int middle= (s + e) / 2;
    if (input[middle] &gt; num) {
        e = middle-1;
    }
    else if (input[middle] &lt; num) {
        s = middle + 1;
    }
    else {
        found = true;
        break;
    }
}</code></pre>
<h3 id="3-문제-원하는-정수-1920번">3) 문제: 원하는 정수 1920번</h3>
<ol>
<li><p>문제: <a href="https://www.acmicpc.net/problem/1920">https://www.acmicpc.net/problem/1920</a>
<img src="https://velog.velcdn.com/images/to_world/post/e940d3ef-3e60-42e6-865c-0e3d0fe03154/image.png" alt=""></p>
</li>
<li><p>코드 </p>
</li>
</ol>
<pre><code class="language-cpp">#include&lt;iostream&gt;
#include&lt;vector&gt; 
#include&lt;algorithm&gt; 
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);

    int n, m;
    cin &gt;&gt; n;
    vector &lt;int&gt; input(n,0);
    for (int i = 0; i &lt; n; i++) {
        cin &gt;&gt; input[i];
    }
    sort(input.begin(), input.end());

    cin &gt;&gt; m;
    for (int i = 0; i &lt; m; i++) {
        int num;
        cin &gt;&gt; num;
        int s = 0; int e = input.size() - 1;
        bool found = false;

        while (s &lt;= e) {
            int middle= (s + e) / 2;
            if (input[middle] &gt; num) {
                e = middle-1;
            }
            else if (input[middle] &lt; num) {
                s = middle + 1;
            }
            else {
                found = true;
                break;
            }
        }
        if (found) cout &lt;&lt; 1 &lt;&lt; &quot;\n&quot;;
        else cout &lt;&lt; 0 &lt;&lt; &quot;\n&quot;;
    }

    return 0;
}</code></pre>
<h3 id="4-문제-기타레슨-2373번">**4) 문제: 기타레슨 2373번</h3>
<ol>
<li>문제: <a href="https://www.acmicpc.net/problem/2343">https://www.acmicpc.net/problem/2343</a>
<img src="https://velog.velcdn.com/images/to_world/post/5f24b4d3-3983-419e-becc-ed2f6676c5b5/image.png" alt=""></li>
</ol>
<ol start="2">
<li>코드</li>
</ol>
<h3 id="5-문제-기타레슨-2373번">**5) 문제: 기타레슨 2373번</h3>
<ol>
<li>문제: <a href="https://www.acmicpc.net/problem/1300">https://www.acmicpc.net/problem/1300</a></li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[Nodejs Chap3.10~3.16)노드 기본기능]]></title>
            <link>https://velog.io/@to_world/Node.js-3.103.16%EB%85%B8%EB%93%9C-%EA%B8%B0%EB%B3%B8%EA%B8%B0%EB%8A%A5</link>
            <guid>https://velog.io/@to_world/Node.js-3.103.16%EB%85%B8%EB%93%9C-%EA%B8%B0%EB%B3%B8%EA%B8%B0%EB%8A%A5</guid>
            <pubDate>Sun, 16 Feb 2025 03:27:48 GMT</pubDate>
            <description><![CDATA[<h2 id="1-내장모듈--worker_threads">1. 내장모듈- worker_threads</h2>
<p><strong>1) 멀티스레딩 지원</strong>
    기본적으로 Node.js는 단일 스레드에서 실행되지만, <strong>worker_threads를 사용하면 여러 개의 스레드를 실행 가능</strong>
    CPU 연산이 많은 작업을 처리할 때 사용하면 성능 향상!</p>
<p><strong>2) 메시지 기반 통신</strong>
    메인 스레드와 워커 스레드는 postMessage()와 on(&#39;message&#39;)를 통해 데이터를 주고받으며 통신 </p>
<p><strong>3) 각 워커는 독립적인 실행 환경을 가짐</strong>
    메모리를 공유하지 않고 실행됨 (단, SharedArrayBuffer를 사용하면 일부 메모리 공유 가능).</p>
<p>*<em>4) 개발의 번거로움, 어려움 존재 *</em>
워커 스레드를 다 나눠줘야하고, 일을 하나하나 시키고 처리해야하는 번거로움, 어려움 존재</p>
<pre><code class="language-js">const { Worker, isMainThread, parentPort,workerData } = require(&#39;worker_threads&#39;);

if (isMainThread) { // 메인 스레드
    const threads = new Set(); //중복되지 않은 배열
    threads.add(new Worker(__filename, {
        workerData: { start: 1 }
    }));
    threads.add(new Worker(__filename, {
        workerData: { start: 2 }
    }));

    for (let worker of threads) {
        worker.on(&#39;message&#39;, (value) =&gt; console.log(&#39;워커로부터:&#39;, value));
        worker.on(&#39;exit&#39;, () =&gt; {
            threads.delete(worker);
            if (threads.size === 0) {
                console.log(&#39;워커 끝&#39;);
            }
        });
    } 
} else { // 워커 스레드
    const data = workerData;
    parentPort.postMessage(data.start+100);
}
/*출력결과
워커로부터: 101
워커로부터: 102
워커 끝
*/
</code></pre>
<h2 id="2-내장모듈--child_process">2. 내장모듈- child_process</h2>
<p><strong>외부 프로세스를 생성하고 실행</strong>할 수 있도록 해주는 내장 모듈
-&gt; 이를 통해 운영 체제 명령어 실행, 다른 프로그램 실행, 병렬 작업 수행 등이 가능</p>
<pre><code class="language-js">//Node.js의 child_process 모듈을 사용하여
//외부 명령어(dir)를 실행하는 예제

const { exec } = require(&#39;child_process&#39;);
//exec()는 외부 명령어(프로그램)를 실행하고, 그 결과를 비동기적으로 반환하는 함수

var process = exec(&#39;dir&#39;);
//Windows에서 dir 명령어를 실행하여 현재 디렉토리의 파일 목록을 출력

process.stdout.on(&#39;data&#39;, function (data) {
    console.log(data.toString());
});</code></pre>
<h2 id="3-파일-시스템">3. 파일 시스템</h2>
<h3 id="내장모듈--fs">내장모듈- fs</h3>
<p>파일 시스템에 접근하는 모듈
파일및 폴더 생성 삭제 존재여부 체크 등</p>
<pre><code class="language-js">fs.readFile(&#39;./chap3/readme.txt&#39;) //읽기
    .then((data) =&gt; {
        console.log(data.toString());
    })
    .catch((err) =&gt; {
        throw err;
    })
//파일 생성
fs.writeFile(&#39;./chap3/writefile.txt&#39;,&quot;writenow&quot;)
    .then(( ) =&gt; {
        return fs.readFile(&#39;./chap3/writefile.txt&#39;);
    })
    //생성한 파일을 읽어서 내용 출력
    .then((data) =&gt; {
         console.log(data.toString())
    })
    .catch((err) =&gt; {
        throw err;
})</code></pre>
<p><strong>!비동기 파일 작업!</strong> </p>
<ul>
<li>파일을 읽는 건 &quot;<strong>비동기</strong>&quot;로 많이 진행됨, 동기로 진행하면 뒷사람이 파일작업을 하기까지 시간이 너무 많이 걸림</li>
<li><code>const fs=require(&#39;fs&#39;).promises</code> : 비동기 작업으로 처리</li>
<li>그러나! <strong>비동기로 하면 코드 실행 순서를 예상할 수 없기</strong> 때문에 이를 잘 처리해주는 것이 중요함</li>
<li>다음 코드를 읽어보면서 익혀보자<pre><code class="language-js">//chap3/fs_async.js
//주의해야할 점!
//비동기함수 -&gt; 백그라운드로 넘어감
// -&gt; 백그라운드에 넘어간 함수들이 동시 실행
// -&gt; 누가 먼저 끝나는지 모른다는 단점 존재
//readFile을 비동기로 여러번 하면 어떤 파일을 먼저 읽을지 모름
//이 코드를 실행시켜보면, 1~4번이 무작위로 출력됨!
const fs = require(&#39;fs&#39;).promises;
fs.readFile(&#39;./chap3/readme.txt&#39;)
  .then((data) =&gt; {
      console.log(&quot;1번&quot;+ data.toString());
  })
  .catch((err) =&gt; {
      throw err;
  })
fs.readFile(&#39;./chap3/readme.txt&#39;)
  .then((data) =&gt; {
      console.log(&quot;2번&quot;+ data.toString());
  })
  .catch((err) =&gt; {
      throw err;
  })
fs.readFile(&#39;./chap3/readme.txt&#39;)
  .then((data) =&gt; {
      console.log(&quot;3번&quot;+ data.toString());
  })
  .catch((err) =&gt; {
      throw err;
  })
fs.readFile(&#39;./chap3/readme.txt&#39;)
  .then((data) =&gt; {
      console.log(&quot;4번&quot;+ data.toString());
  })
  .catch((err) =&gt; {
      throw err;
  })

</code></pre>
</li>
</ul>
<p>//해결1: 비동기 + 순서예측 되게끔 + promise
fs.readFile(&#39;./chap3/readme.txt&#39;)
    .then((data) =&gt; {
        console.log(&quot;1번!&quot;);
        return fs.readFile(&#39;./chap3/readme.txt&#39;);
    })
    .then((data) =&gt; {
        console.log(&quot;2번!&quot;);
        return fs.readFile(&#39;./chap3/readme.txt&#39;);
    })
    .then((data) =&gt; {
        console.log(&quot;3번!&quot;);
        return fs.readFile(&#39;./chap3/readme.txt&#39;);
    })
    .catch((err)=&gt;{
        throw err;
    })</p>
<p>//해결2: async로 해서 더 깔끔하게도 가능
async function main() {
    let data=await fs.readFile(&#39;./chap3/readme.txt&#39;)
    console.log(&quot;1번&quot;);
    data=await fs.readFile(&#39;./chap3/readme.txt&#39;)
    console.log(&quot;2번&quot;);
    data=await fs.readFile(&#39;./chap3/readme.txt&#39;)
    console.log(&quot;3번&quot;);
}
main();</p>
<pre><code>
이외에도 fs 관련 여러 함수들, 기능들이 있다...
파일 복사, 파일 존재여부 체크, 등등
필요하면 그때그때 공식문서, 서칭 등 해보기

### 2) 버퍼buffer
일정한 크기로 모아두는 데이터
일정한 크기가 되면 한번에 통째로 처리
```js
const buffer = Buffer.from(&#39;저를 버퍼로 바꿔보세요&#39;);
console.log(buffer);
console.log(buffer.length);
console.log(buffer.toString());
console.log(Buffer.alloc(5)); //5바이트 버퍼 생성
</code></pre><h3 id="3-스트림stream">3) 스트림stream</h3>
<p>데이터의 흐름
일정한 크기로 나눠서 여러번에 걸쳐 처리
버퍼를 작게 만들어서 주기적으로 전달
스트리밍: 일정한 크기의 데이터를 지속적으로 전달</p>
<p><strong>1. stream 읽기 쓰기 예제</strong></p>
<pre><code class="language-js">//스트림 읽기
const fs = require(&#39;fs&#39;);
const readstream = fs.createReadStream(&#39;./chap3/readme2.txt&#39;);const data = [];
readstream.on(&#39;data&#39;, (chunk) =&gt; {
    data.push(chunk);
    console.log(&#39;data:&#39;, chunk, chunk.length);
});
readstream.on(&#39;end&#39;, () =&gt; {
    console.log(&#39;end&#39;, Buffer.concat(data).toString());
});
readstream.on(&#39;error&#39;, (err) =&gt; {
    throw err;
});
//스트림 쓰기
const writestream = fs.createWriteStream(&#39;./chap3/write2.txt&#39;);
writestream.on(&#39;finish&#39;, () =&gt; {
    console.log(&quot;쓰기 완료&quot;);
});
writestream.write(&#39;글쓰기\n&#39;);
writestream.write(&#39;한번 더 글쓰기\n&#39;);
writestream.end();</code></pre>
<p><strong>2. stream piping 예제</strong></p>
<pre><code class="language-js">//16byte씩 읽고 그 16byte를 바로 writeme.txt에 쓰는 코드
const fs = require(&#39;fs&#39;);
const readstream = fs.createReadStream(&#39;./chap3/readme.txt&#39;,
    {highwatermark:16}
);
const writestream = fs.createWriteStream(&#39;./chap3/write3.txt&#39;);
readstream.pipe(writestream); //**</code></pre>
<h2 id="4-스레드풀과-커스텀-이벤트">4. 스레드풀과 커스텀 이벤트</h2>
<h3 id="1-스레드풀">1) 스레드풀</h3>
<p>노드는 기본적으로 background에서 4개의 thread까지 작업 가능
만약 본인의 코어가 그 이상이어서 본인컴퓨터의 코어만큼 작업시키고 싶으면
<code>SET UV_THREADPOOL_SIZE=8(코어개수)</code>을 터미널에 입력시키면 됨</p>
<h3 id="2-내장-모듈--커스텀-이벤트">2) 내장 모듈- 커스텀 이벤트</h3>
<p>커스텀 이벤트는 사용자가 정의한 이벤트
사용법</p>
<ul>
<li>EventEmitter 클래스를 사용하여 커스텀 이벤트를 정의하고 리스너들을 추가</li>
<li>이벤트 발생 (emit) 시, 해당 이벤트에 등록된 리스너들이 호출됨</li>
</ul>
<pre><code class="language-js">const eventemitter = require(&#39;events&#39;);
const myEvent = new eventemitter();

myEvent.addListener(&#39;event1&#39;, () =&gt; {
    console.log(&quot;1&quot;);
});
myEvent.on(&#39;event2&#39;, () =&gt; {
    console.log(&quot;2&quot;);
});
myEvent.once(&#39;event3&#39;, () =&gt; { //실행이 한번만 됨
    console.log(&quot;3&quot;);
});

myEvent.emit(&#39;event1&#39;);
myEvent.emit(&#39;event2&#39;);
myEvent.emit(&#39;event3&#39;);
myEvent.emit(&#39;event3&#39;);//이미 한번 실행을 해서 이번에는 실행안됨
myEvent.removeAllListeners(&#39;event1&#39;); //event1지우기</code></pre>
<h2 id="5-에러예외-처리하기">5. 에러,예외 처리하기</h2>
<p>예외: 처리하지 못한 에러
노드 스레드를 멈춤 -&gt; 노드는 싱글스레드 -&gt; 전체가 멈춰버림</p>
<p>해결법1: 
<code>try catch</code>  문으로 예외 처리
해결법2:
콜백함수에서 err 처리하기 
<code>if(err) console.log(err);</code> 
해결법3: 
<code>process.on(&#39;uncaughtException&#39;,(err)=&gt;{console.error(&#39;에러발생&#39;);});</code>
-&gt; 에러내용을 기록용, 모든 에러가 이 부분에 모여들어서 저장됨</p>
<p>프로세스 종료하기(강제종료)
<code>taskkill /pid</code>  : 윈도우</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Nodejs Chap3.1~3.9 노드 기본기능]]></title>
            <link>https://velog.io/@to_world/Node.js-3</link>
            <guid>https://velog.io/@to_world/Node.js-3</guid>
            <pubDate>Sat, 15 Feb 2025 09:08:55 GMT</pubDate>
            <description><![CDATA[<h2 id="1-commonjs-모듈-시스템">1. CommonJs 모듈 시스템</h2>
<h3 id="1-모듈화">1) 모듈화</h3>
<p>var.js를 다른 파일에서 받아 쓸 수 있다.
모듈화의 2가지 방법</p>
<ul>
<li>둘 중 한가지 방법만 사용해서 쭉 써야함</li>
<li>방법1을 썼다가 다음 줄에 방법2로 쓰는 식으로 코딩작성하면 안됨</li>
<li>module.exports에 아무것도 안넣으면 기본값으로 빈객체가 생성됨<pre><code class="language-js">//var.js
const odd = &quot;홀수입니다.&quot;;
const even = &quot;짝수입니다&quot;;
</code></pre>
</li>
</ul>
<p>//모듈화 방법1
//두가지 이상을 exports하고 싶을 때 사용 가능
exports.odd = odd;
exports.even = even;</p>
<p>//모듈화 방법2
module.exports = {
    odd: odd, even: even
};</p>
<pre><code>
### 2) require
**기본 개념:**
require가 제일 위에 올 필요는 없음
require을 console.log(require)해보면 require 속성들이 나옴
- require.cache에 한번 require한 모듈에 대한 캐슁 정보가 들어있음
- require.main은 노드 실행 시 첫 모듈을 가리킴
```js
require(&#39;./var&#39;); //var 파일 실행만 됨.

const {odd,even} = require(&#39;./var.js&#39;); //구조분해할당
console.log(odd);
console.log(even);</code></pre><p><strong>순환 참조</strong></p>
<ul>
<li>서로가 서로를 require해서 무한cycle이 도는 경우</li>
<li>순환참조가 발견되면 빈객체로 만들어 무한cycle, 순환참조를 막아버림<pre><code class="language-js">//require1.js
require(&#39;./require2&#39;);
//require2.js
require(&#39;./require1&#39;); //빈객체
</code></pre>
</li>
</ul>
<pre><code>**dynamic import**
```js
const a = true;
if(a) require(&#39;./var&#39;);
else require(&#39;./index&#39;);</code></pre><h2 id="2-es-모듈시스템">2. ES 모듈시스템</h2>
<p><strong>기본 개념:</strong>
확장자를 <code>mjs</code>로 쓰거나, package.json에 <code>type:&quot;module&quot;</code> 로 바꿔줘야한다.
CommonJs -&gt; ES 모듈이 되면서 바뀐 것</p>
<ul>
<li><code>require</code> -&gt; <code>import</code> </li>
<li><code>exports</code>  -&gt; <code>export</code> </li>
<li><code>module.exports</code>  -&gt; <code>export default</code> </li>
<li>require, exports는 함수,객체였으나 import export default는 문법 그 자체(예약어)이다.</li>
<li><code>async+await이 항상 함께</code>  -&gt; <code>async 없이 await을 쓸 수 있음</code> </li>
<li>dynamic import 방식이 바뀜</li>
<li><code>__dirname, __filename 사용 가능</code>  -&gt; <code>사용 불가</code> <pre><code class="language-js">//var.mjs
export const odd = &quot;홀수입니다.&quot;;
export const even = &quot;짝수입니다&quot;;
</code></pre>
</li>
</ul>
<p>//func.mjs
import { odd, even } from &#39;./var.mjs&#39; //확장자까지 꼭 써줘야함
function checkOddorEven(num) {
    if (num % 2) {
        return odd;
    }
    return even;
};
export default checkOddorEven;</p>
<pre><code>**dynamic import in ES 모듈**
```js
const a = true;
if(a) a1 = await import(&#39;./var.mjs&#39;);
else a2 = await import(&#39;./index.mjs&#39;);</code></pre><h2 id="3-process">3. process</h2>
<p><strong>1)기본 개념:</strong> 현재 실행중인 노드 프로세스에 대한 정보에 접근할 수 있음</p>
<pre><code class="language-js">process.upTime(); //프로세스가 시작된 후 지난 시간
process.cwd(); //현재 프로세스가 실행되는 위치
process.pid //프로세스 아이디</code></pre>
<p><strong>process.env : 환경변수</strong></p>
<ul>
<li>시스템 환경변수 정보가 들어있음</li>
<li>비밀키를 보관하는 용도로 쓰임</li>
<li><code>process.env</code>  로 접근</li>
<li>일부 환경변수는 노드 실행시 영향을 줄 수 있음<pre><code class="language-js">const passwd=process.env.SECRET_ID;</code></pre>
</li>
<li><em>process.nextTick*</em></li>
<li>이벤트 루프가 다른 콜백함수보다 <code>process.nextTick</code> 의 콜백함수를 우선적으로 처리<pre><code class="language-js">setImmediate(() =&gt; {
  console.log(&#39;immediate&#39;);
});
</code></pre>
</li>
</ul>
<p>process.nextTick(() =&gt; {
    console.log(&#39;nextTick&#39;);
});</p>
<p>setTimeout(() =&gt; {
    console.log(&#39;timeout&#39;);
}, 0);</p>
<p>Promise.resolve().then(() =&gt; console.log(&#39;promise&#39;));
//nextTick-&gt;promise-&gt;timeout-&gt;immediate</p>
<pre><code>**process.exit**
- 노드 process 종료시킴
- ``` process.exit(0)```  : 정상적으로 종료된 것
- 0 이외의 숫자: 비정상적으로 종료


## 4. 내장모듈- os path
### 1) os
운영체제의 정보
process와 겹치는 부분이 있음
```js
//os.js
const os = require(&#39;os&#39;);  
os.arch() // process.arch와 동일합니다.
os.platform() // process.platform과 동일합니다.
os.type() // 운영체제의 종류를 보여줍니다.
os.uptime() // 운영체제 부팅 이후 흐른 시간(초)을 보여줍니다. //process.uptime()은 노드의 실행 시간이었습니다.
os.hostname() // 컴퓨터의 이름을 보여줍니다.
os.release() // 운영체제의 버전을 보여줍니다.
os.homedir() // 홈 디렉터리 경로를 보여줍니다.
os.tmpdir() // 임시 파일 저장 경로를 보여줍니다.
os.cpus() // 컴퓨터의 코어 정보를 보여줍니다.
os.freemem() // 사용 가능한 메모리(RAM)를 보여줍니다.
os.totalmem() // 전체 메모리 용량을 보여줍니다.
</code></pre><h3 id="2-path">2) path</h3>
<p>경로처리
맥, 리눅스 등에 따라 경로처리가 다름: \을 쓰는 경우도 있고 /를 쓰는 경우도 있고...
이러한 경로들을 path 가 처리해줌</p>
<pre><code class="language-js">const path = require(&#39;path&#39;);
path.join(__dirname, &#39;..&#39;, &#39;var.js&#39;); 
//-&gt; 주어진 경로들을 단순히 이어 붙여 새로운 경로를 만듦
//___dirname에서 한 단계 위(..)로 이동한 후 var.js를 붙인 경로를 반환
///Users/user/project/src/index.js =&gt;/Users/user/project/index.js
path.resolve(__dirname, &#39;..&#39;, &#39;/var.js&#39;);
//-&gt; 절대 경로를 반환
//__dirname에서 한 단계 위(project)로 이동한 후 var.js를 추가
///Users/user/project/src/index.js =&gt;/Users/user/project/index.js</code></pre>
<p>이 예제들 이외에도 굉장히 많음..</p>
<h2 id="5-url-dns-searchparams">5. url dns searchParams</h2>
<h3 id="0-http-해석">0) http 해석</h3>
<p><img src="https://velog.velcdn.com/images/to_world/post/f605fc6f-9734-4856-befd-4039ef5c9cde/image.png" alt=""></p>
<h3 id="1-urlurl-searchparams">1) url(URL) searchParams</h3>
<p>URL, searchParams : 내장 모듈이 아니라 객체, require(&#39;url&#39;) 없어도 됨</p>
<pre><code class="language-js">const url = require(&#39;url&#39;);
const myURL = new URL(&#39;https://www.naver.com/&#39;);
console.log(myURL);
console.log(url.format(myURL)); //문자열로 바꿔줌
/* 출력1
URL {
  href: &#39;https://www.naver.com/&#39;,
  origin: &#39;https://www.naver.com&#39;,
  protocol: &#39;https:&#39;,
  username: &#39;&#39;,
  password: &#39;&#39;,
  host: &#39;www.naver.com&#39;,
  hostname: &#39;www.naver.com&#39;,
  port: &#39;&#39;,
  pathname: &#39;/&#39;,
  search: &#39;&#39;,
  searchParams: URLSearchParams {},        
  hash: &#39;&#39;
}
출력2: https://www.naver.com/ 
*/</code></pre>
<pre><code class="language-js">const myURL = new URL(&#39;http://www.gilbut.co.kr/?page=3&amp;limit=10&amp;category=nodejs&amp;category=javascript&#39;);

console.log(&#39;searchParams:&#39;, myURL.searchParams);
console.log(&#39;searchParams.getAll():&#39;, myURL.searchParams.getAll(&#39;category&#39;));
console.log(&#39;searchParams.get():&#39;, myURL.searchParams.get(&#39;limit&#39;));
console.log(&#39;searchParams.has():&#39;, myURL.searchParams.has(&#39;page&#39;));

console.log(&#39;searchParams.keys():&#39;, myURL.searchParams.keys());
console.log(&#39;searchParams.values():&#39;, myURL.searchParams.values());

myURL.searchParams.append(&#39;filter&#39;, &#39;es3&#39;);
myURL.searchParams.append(&#39;filter&#39;, &#39;es5&#39;);
console.log(myURL.searchParams.getAll(&#39;filter&#39;));

myURL.searchParams.set(&#39;filter&#39;, &#39;es6&#39;);
console.log(myURL.searchParams.getAll(&#39;filter&#39;));

myURL.searchParams.delete(&#39;filter&#39;);
console.log(myURL.searchParams.getAll(&#39;filter&#39;));

console.log(&#39;searchParams.toString():&#39;, myURL.searchParams.toString());
myURL.search = myURL.searchParams.toString();</code></pre>
<h3 id="2-내장모듈--dns">2) 내장모듈- dns</h3>
<p>내장 모듈
주로 도메인을 통해 IP나 기타 dns를 찾는데 쓰임</p>
<pre><code class="language-js">import dns from &#39;dns/promises&#39;;
const ip = await dns.lookup(&#39;gilbut.co.kr&#39;);
console.log(ip); //ip 주소 가져옴
const a = await dns.resolve(&#39;gilbut.co.kr&#39;, &#39;A&#39;);
console.log(a);  //ipv4 주소
const mx = await dns.resolve(&#39;gilbut.co.kr&#39;, &#39;MX&#39;);
console.log(mx); //메일서버 관련 정보들(=레코드 라고 부름)
const cname = await dns.resolve(&#39;www.gilbut.co.kr&#39;, &#39;CNAME&#39;);
console.log(cname); //별칭(www가 붙은 주소는 별칭인 경우가 많다) 
const any = await dns.resolve(&#39;gilbut.co.kr&#39;, &#39;ANY&#39;);
console.log(any); 
</code></pre>
<h2 id="6-내장모듈--crypto-util">6. 내장모듈- crypto, util</h2>
<h3 id="1-crypto">1) crypto</h3>
<p>암호화: 평문 -&gt; 암호, 복호화: 암호 -&gt; 평문
<strong>해시</strong>: <strong>단방향 암호화의 대표주자</strong>: 암호화만 되고 복호화가 안됨</p>
<pre><code class="language-js">const crypto = require(&#39;crypto&#39;);
console.log(crypto.createHash(&#39;sha512&#39;).update(&#39;비밀번호&#39;).digest(&#39;base64&#39;))
//비밀번호 라는 문자열을 해시로 바꿈</code></pre>
<p><strong>cipher, decipher : 양방향 암호화</strong></p>
<pre><code class="language-js">const cipher = crypto.createCipheriv(algorithm, key, iv);
const decipher = crypto.createDecipheriv(algorithm, key, iv);</code></pre>
<h3 id="2-util">2) util</h3>
<p>각종 편의 기능을 모아둠</p>
<p><strong>deprecate</strong>
그 함수가 사용되었을 때 경고창을 띄움</p>
<pre><code class="language-js">const util = require(&#39;util&#39;);

const dontuse = util.deprecate((x, y) =&gt; {
    console.log(x + y);
}, &#39;dontuse 함수는 더이상 사용하지 마세요&#39;);</code></pre>
<ul>
<li><code>console.log(x + y)</code> 를 실행하여 8을 출력.</li>
<li>동시에 <code>DeprecationWarning(사용 중단 경고)</code> 이 발생하며, <code>dontuse 함수는 더이상 사용하지 마세요</code> 라는 메시지가 표시됨</li>
</ul>
<p><strong>promisify</strong>
콜백 기반 함수를 Promise 기반 함수로 변환</p>
<pre><code class="language-js">// crypto.randomBytes를 Promise 기반 함수로 변환
const promiseme = util.promisify(crypto.randombytes);
promiseme(64)
    .then((buf) =&gt; {
        console.log(buf.toString(&#39;base64&#39;));
    })
    .catch((error) =&gt; {
        console.log(error);
    });</code></pre>
]]></description>
        </item>
    </channel>
</rss>