<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>heesan.log</title>
        <link>https://velog.io/</link>
        <description>성공은 제로섬 게임이 아니라 주변인들과 함께 나아가는 것이다.</description>
        <lastBuildDate>Fri, 14 Jul 2023 00:58:43 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>heesan.log</title>
            <url>https://velog.velcdn.com/images/hmesan_93/profile/fff72763-b964-4190-8f08-df64ce45a537/image.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. heesan.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/hmesan_93" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[OOP(객체지향 프로그래밍) (with Dart)]]></title>
            <link>https://velog.io/@hmesan_93/OOP%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-with-Dart</link>
            <guid>https://velog.io/@hmesan_93/OOP%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-with-Dart</guid>
            <pubDate>Fri, 14 Jul 2023 00:58:43 GMT</pubDate>
            <description><![CDATA[<h2 id="서론"><strong>서론</strong></h2>
<p>객체지향 프로그래밍... 개발공부를 시작했을 때 개념강의를 듣고 멘붕(?)이 왔던 용어였습니다. 도대체 무슨 말을 하고 있는 건지... 그래서 이게 뭘 한다는 건지 그때는 전혀 이해하지 못했습니다. 그 때 본 글이 있었는데 프로그래밍에 대해서 계속 공부를 하고 코드를 작성하다보면 저절로 모든 게 이해가 다 될거라는 글이었습니다.</p>
<p>사실, 아직도 100퍼센트 이해했다고는 볼 수 없지만, 어느 정도 뭘 의도하고 프로그래밍을 OOP를 준수하면서 하는지에 대해서 감은 온 것 같습니다.</p>
<p>저번 포스트에 이어서 코드팩토리님의 flutter강의 초반 부분인 OOP에 대한 강의가 있었는데 많은 도움이 되어서 강의를 듣고 정리해보았습니다.
OOP 개념에 대한 글을 따로 정리하진 않았고 코드로 작성한 것들만 보여드리겠습니다.</p>
<p>Dart를 시작하시는 분들 께 많은 도움이 되셨으면 좋겠습니다.
(OOP의 4가지 특징 그것에 대해 형식을 정해서 정리한 건 아닙니다.)</p>
<pre><code class="language-dart">// **Object Oriented Programming**

// 기능들을 한 곳에 모아 놓을 수 있는게 class

// class 통해서 프로그래밍을 하는 것을 OOP 라고 한다.

// 설계사를 만드는 게 클래스의 정의 → 실제로 무언가를 만들어 내는 것 → 그 결과물이 인스턴스

void main() {
// Dart언어에서는 new Idol() 이렇게 해도되고 그냥 Idol() 해도 됨
// Idol blackPink = const Idol(&#39;블랙핑크&#39;, [&#39;지수&#39;, &#39;제니&#39;, &#39;리사&#39;, &#39;로제&#39;]);
// Idol blackPink2 = const Idol(&#39;블랙핑크&#39;, [&#39;지수&#39;, &#39;제니&#39;, &#39;리사&#39;, &#39;로제&#39;]);
// const로 인스턴스 생성시 같은 인스턴스로 취급
// print(&#39;const로 선언시 두 객체는 같다. ${blackPink == blackPink2}이다.&#39;); // true

// Idol blackPink3 = Idol(&#39;블랙핑크&#39;, [&#39;지수&#39;, &#39;제니&#39;, &#39;리사&#39;, &#39;로제&#39;]);
// Idol blackPink4 = Idol(&#39;블랙핑크&#39;, [&#39;지수&#39;, &#39;제니&#39;, &#39;리사&#39;, &#39;로제&#39;]);
// print(&#39;그냥 선언시에는 같지 않다.  ${blackPink3 == blackPink4}이다.&#39;); // false

// Idol bts = Idol(&#39;BTS&#39;, [&#39;RM&#39;, &#39;진&#39;, &#39;슈가&#39;, &quot;제이홉&quot;, &quot;지민&quot;, &quot;뷔&quot;, &quot;정국&quot;]);
  _Idol blackPink = _Idol(&#39;블랙핑크&#39;, [&#39;지수&#39;, &#39;제니&#39;, &#39;리사&#39;, &#39;로제&#39;]);
  _Idol bts = _Idol.fromList([
    [&#39;RM&#39;, &#39;진&#39;, &#39;슈가&#39;, &quot;제이홉&quot;, &quot;지민&quot;, &quot;뷔&quot;, &quot;정국&quot;],
    &#39;BTS&#39;,
  ]);
// print(bts.name);
// print(bts.members);
// bts.sayHello();
// bts.introduce();

  print(blackPink.firstMember); // 지수
  print(bts.firstMember); // RM

// setter 호출
// blackPink.firstMember = &#39;코드팩토리&#39;;
// bts.firstMember = &#39;아이언맨&#39;;

  print(blackPink.firstMember); // 코드팩토리
  print(bts.firstMember); // 아이언맨
}

// Idol class
// name(이름) - 변수
// members(멤버들)- 변수
// sayHello(인사) - 함수
// introduce(멤버소개) - 함수

// constructor (생성자)
// immutable programming -&gt; 인스턴스의 값이 바뀌길 원하지 않음
// 만약 바꾸고 싶다면 차라리 새로운 인스턴스를 만들길 바람.-&gt; final 사용
// 인스턴스를 만들 때 선언이 된다.(class 안에선 거의 대부분 final 사용)

// getter / setter
// 데이터 가져올때 / 데이터를 설정할 때
// 설계도
// class 를 private로 만들고 싶다 -&gt; 클래스이름 앞에 _ 표시한다.
// 현재 파일의 위치에서만 수정가능. 외부에서 import 하더라도 변경 불가
class _Idol {
  // final String name;
  // final List&lt;String&gt; members;
  String name;
  List&lt;String&gt; members;

  // 방법 1
  // Idol(String name, List&lt;String&gt; members)
  //     : this.name = name,
  //       this.members = members;

  // 방법2 -&gt; constructor 이용 (외부에서 파라미터 받기)
  // const 안써도 되지만 const constructor 하는 순간
  // 인스턴스 만들고 나서 재할당 안되고 빌드타임에 알 수 있음
  _Idol(this.name, this.members);

  // 방법3 -&gt; named constructor 이용 (외부에서 파라미터 받기)
  _Idol.fromList(List values)
      : this.members = values[0],
        this.name = values[1];

  void sayHello() {
    print(&quot;안녕하세요. ${this.name}입니다.&quot;);
  }

  void introduce() {
    print(&#39;저희 멤버는 ${this.members.join(&#39;, &#39;)} 입니다.&#39;);
  }

  // getter 값을 가져옴
  String get firstMember {
    return this.members[0];
  }

  // setter 값을 지정 ( 잘 쓰진 않는다. )
  // set firstMember(String name) {
  //   this.members[0] = name;
  // }
}</code></pre>
<h2 id="inheritance"><strong>inheritance</strong></h2>
<pre><code class="language-dart">void main() {
  print(&#39;--------------Idol---------------&#39;);
  Idol apink = Idol(name: &#39;에이핑크&#39;, membersCount: 5);

  apink.sayName();
  apink.sayMembersCount();

  print(&#39;--------------Boy Group---------------&#39;);

  BoyGroup bts = BoyGroup(&#39;BTS&#39;, 7);

  bts.sayName();
  bts.sayMembersCount();
  bts.sayMale();

  print(&#39;--------------Girl Group---------------&#39;);

  GirlGroup redVelvet = GirlGroup(&#39;Red Velvet&#39;, 5);

  redVelvet.sayMembersCount();
  redVelvet.sayName();
  redVelvet.sayFemale();

  print(&#39;-------------Type Comparision-----------&#39;);
  print(apink is Idol); // true
  print(apink is BoyGroup); // false
  print(apink is GirlGroup); // false

  print(&#39;-------------Type Comparision 2-----------&#39;);
  print(bts is Idol); // true
  print(bts is BoyGroup); // true
  print(bts is GirlGroup); // false

  print(&#39;-------------Type Comparision 3-----------&#39;);
  print(redVelvet is Idol); // true
  print(redVelvet is BoyGroup); // false
  print(redVelvet is GirlGroup);  // true
}

// 상속 - inheritance
// 상속을 받으면 부모 클래스의 모든 속성을
// 자식 클래스가 부여 받는다.

class Idol {
  // 이름
  String name;

  // 멤버 숫자
  int membersCount;

  // named parameter 사용
  Idol({
    required this.name,
    required this.membersCount,
  });

  void sayName() {
    print(&#39;저는 ${this.name} 입니다&#39;);
  }

  void sayMembersCount() {
    print(&#39;${this.name}은 ${this.membersCount}명의 멤버가 있습니다.&#39;);
  }
}

// 상속 받을 때 부모의 생성자를 준수해야 한다.
class BoyGroup extends Idol {
  BoyGroup(
    String name,
    int membersCount,
  ) : super(name: name, membersCount: membersCount);

  // 부모 클래스에서는 자식클래스에서 선언한 변수나,메서드를 사용할 순 없다.
  void sayMale() {
    print(&#39;저는 남자아이돌입니다.&#39;);
  }
}

class GirlGroup extends Idol {
  GirlGroup(
    String name,
    int membersCount,
  ) : super(name: name, membersCount: membersCount);

  void sayFemale() {
    print(&quot;저는 여자아이돌입니다.&quot;);
  }
}</code></pre>
<h2 id="overriding"><strong>Overriding</strong></h2>
<pre><code class="language-dart">void main() {
  TimesTwo tt = TimesTwo(2);

  print(tt.calculate());

  TimesFour tf = TimesFour(2);

  print(tf.calculate());
}

// method - function (class 내부에 있는 함수)
// override - 덮어쓰다 ( 우선시하다 ) &lt;- 상속한 자식에 대해서만 오버라이딩할수있다.

class TimesTwo {
  final int number;

  TimesTwo(
    this.number,
  );

  int calculate() {
    // 따로 number가 선언되어 있지 않으면 Dart에서는 this의 number를 가리킴.
    // return number * 2 이렇게 작성해도 됨
    return this.number * 2;
  }
}

class TimesFour extends TimesTwo {
  TimesFour(
    int number,
  ) : super(number);

  // 덮어쓰기를 하자! 그리고 Annotation 적어주는게 좀 직관적이다.
  //   @override 
  //   int calculate() {

  //     // return super.number * 4; 정석대로 super 씀, 하지만 삭제해도 무방
  //     return number * 4;

  //   }

  // 만약 override 한 상태에서 부모의 메서드를 그대로 살리고 싶으면 
  @override
  int calculate(){
    return super.calculate() * 2;
    // 여기서 실수로 만약 this.calculate() 해버리면 자기 자신 계속 호출해서 무한루프빠짐
  }
}</code></pre>
<h3 id="static"><strong>static</strong></h3>
<pre><code class="language-dart">void main() {
  Employee seulgi = Employee(&#39;슬기&#39;);
  Employee chorong = Employee(&#39;초롱&#39;);

  chorong.name = &#39;코드팩토리&#39;; // 이것을 인스턴스에 귀속이 된다고 말을 한다.
  seulgi.printNameBuilding();
  chorong.printNameBuilding();

  Employee.building = &#39;오투타워&#39;;

  seulgi.printNameBuilding();
  chorong.printNameBuilding();

  Employee.printBuilding(); // static 메서드는 객체 생성 없이 호출 가능

}

class Employee {
  // static은 instance에 귀속되지 않고 class에 귀속된다.

  // 알바생이 일하고 있는 건물
  static String? building; // 클래스에다가 귀속시킬 수 있다.!!!

  // 알바생 이름
  // final String name;
  String name;

  Employee(
    this.name,
  );

  void printNameBuilding() {
    print(&#39;제 이름은 $name 입니다. $building 건물에서 근무하고 있습니다.&#39;);
  }

  static void printBuilding() {
    print(&#39;저희는 $building 건물에서 근무중입니다.&#39;);
  }
}</code></pre>
<h3 id="interface-abstract">interface, abstract</h3>
<pre><code class="language-dart">void main() {
  BoyGroup bts = BoyGroup(&#39;BTS&#39;);
  GirlGroup redVelvet = GirlGroup(&#39;레드벨벳&#39;);

  bts.sayName(); // 제 이름은 BTS 입니다
  redVelvet.sayName(); // 제 이름은 레드벨벳 입니다


  // 마찬가지로 상속이랑 똑같은 결과이다. 물려받지만 변경할 수 없는 물려받기라고 생각하면 된다.
  print(bts is IdolInterface); // true
  print(bts is BoyGroup); // true
  print(bts is GirlGroup); // false
}

// interface 다트에서는 그냥 class로 사용
// abstract class들은 인스턴스로 만들지 못한다.
// dart에선 인터페이스를 class 형태로 만들기 때문에 혹시나 실수 방지용..이기도 하다.
abstract class IdolInterface {
  String name;

  IdolInterface(this.name);

  void sayName() {} // 어차피 추상적이기 때문에 형태만 같으면 됨. 안에 내용은 지워도 됌.
}

// 형태를 똑같이 맞춰줘야 함 ( 강제하는 역할 )
class BoyGroup implements IdolInterface {
  String name;

  BoyGroup(this.name);

  void sayName() {
    print(&#39;제 이름은 $name 입니다&#39;);
  }
}

class GirlGroup implements IdolInterface {
  String name;

  GirlGroup(this.name);

  void sayName() {
    print(&#39;제 이름은 $name 입니다&#39;);
  }
}</code></pre>
<h3 id="generic">Generic</h3>
<pre><code class="language-dart">void main() {
  Lecture&lt;String,String&gt; lecture1 = Lecture(&#39;123&#39;, &#39;lecture1&#39;);

  lecture1.printIdType();

  Lecture&lt;int,String&gt; lecture2 = Lecture(123, &#39;lecture2&#39;);

  lecture2.printIdType();
}

// generic - 타입을 변수처럼 외부에서 받을 때 사용(선언시에 타입이 결정 됨)
class Lecture&lt;T, X&gt; {
  final T id;
  final X name;

  Lecture(this.id, this.name);

  void printIdType() {
    print(id.runtimeType);
  }
}</code></pre>
<p>출처 : <a href="https://www.inflearn.com/course/%ED%94%8C%EB%9F%AC%ED%84%B0-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8/dashboard">[초급] Flutter 3.0 앱 개발 - 10개의 프로젝트로 오늘 초보 탈출! </a> ( 코드팩토리 )</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Dart 기본기 정리]]></title>
            <link>https://velog.io/@hmesan_93/Dart-%EA%B8%B0%EB%B3%B8%EA%B8%B0-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@hmesan_93/Dart-%EA%B8%B0%EB%B3%B8%EA%B8%B0-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Fri, 14 Jul 2023 00:45:48 GMT</pubDate>
            <description><![CDATA[<h2 id="서론"><strong>서론</strong></h2>
<p>Flutter를 시작하기로 마음 먹고 &#39;코드 팩토리&#39;님의 인프런 &#39;Flutter 3.0 앱 개발&#39; 강의를 결제해 보았습니다.
Flutter는 구글에서 만든 Dart 프로그래밍 언어로 작성되며, 안드로이드와 iOS 애플리케이션을 동시에 개발할 수 있는 장점이 있다고 하네요.
강의 초반에는 Dart의 기초 문법과 프로그래밍 기법에 대한 강의가 있습니다.</p>
<p>프로그래밍 언어에 대해서 완전히 모르는 건 아니지만 Dart와 친해지기 위해, 그리고 개념을 다시 한번 복습하기 위해 기초 강의를 수강하였고 다음과 같이 정리해 보았습니다. 자바스크립트와 많이 비슷한 것 같고 타입 스크립트처럼 Dart에는 변수와 함수에 타입을 명시할 수 있습니다. 그리고 타입 추론 기능도 있어서 코드 가독성 측면에서도 훌륭한 것 같습니다.</p>
<p>Flutter를 시작하시는 분들께 도움이 되었으면 좋겠네요!!</p>
<pre><code class="language-dart">// Dart 언어에서 사용되는 열거형입니다.
enum Status {
  approved, // 승인됨
  pending, // 보류 중
  rejected, // 거절됨
}

void main() {
  // 사용자 정의 함수인 addNumbers에 값을 넣어 결과값을 얻습니다.
  int result = addNumbers(y: 20, x: 10);
  int result2 = addNumbers(x: 10, y: 30, z: 40);

  // 논리형 변수입니다.
  bool isTrue = true;
  bool isFalse = false;

  // 문자열 변수입니다.
  String name = &#39;레드벨벳&#39;;
  String name2 = &#39;코드팩토리&#39;;

  // var 키워드를 사용하면, Dart가 알아서 변수의 타입을 결정합니다.
  var name3 = &#39;블랙핑크&#39;;
  var number = 20;

  // 두 변수 모두 문자열을 저장하지만, 다른 값을 갖습니다.
  String name4 = &#39;레드벨벳&#39;;
  String name5 = &#39;슬기&#39;;

  // dynamic은 모든 타입의 변수를 저장할 수 있습니다.
  dynamic name6 = &#39;코드팩토리&#39;;
  dynamic number2 = 1;

  // name2는 이전에 이미 선언되어있으므로, 새로운 값을 가진 name2를 다시 선언할 수 없습니다.
  // var name2 = &#39;블랙핑크&#39;;  // 이 줄은 오류를 일으킵니다.

  // null safety 기능을 사용하면, name2가 null 값을 가질 수 있음을 나타냅니다.
  String? name7 = &#39;블랙핑크&#39;;

  // final은 한 번 초기화하면 값이 변경되지 않는 변수를 선언합니다.
  final name8 = &#39;코드팩토리&#39;;

  // const는 컴파일 시점에 값이 결정되는 상수를 선언합니다.
  const String name9 = &#39;블랙핑크&#39;;

  // DateTime 클래스를 사용하여 현재 시간을 가져옵니다.
  final DateTime now = DateTime.now();

  // 정수형 변수입니다.
  int number1 = 1;

  // 논리 연산자를 사용한 예시입니다.
  bool result3 = 12 &gt; 10 &amp;&amp; 1 &gt; 0;
  bool result4 = 12 &gt; 10 &amp;&amp; 0 &gt; 1;
  bool result5 = 12 &gt; 10 || 1 &gt; 0;
  bool result6 = 12 &gt; 10 || 0 &gt; 1;
  bool result7 = 12 &lt; 10 || 1 &gt; 0;
  bool result8 = 12 &lt; 10 || 0 &gt; 1;

  // 문자열과 정수를 저장하는 리스트입니다.
  List&lt;String&gt; blackPink = [&#39;제니&#39;, &quot;지수&quot;, &quot;로제&quot;, &quot;리사&quot;];
  List&lt;int&gt; blackPink1 = [1, 2, 3, 4, 5, 6];

  // 리스트에 항목을 추가하거나 제거합니다.
  blackPink.add(&#39;코드팩토리&#39;);
  blackPink.remove(&#39;코드팩토리&#39;);

  // 문자열을 키로 하고, 다른 문자열을 값으로 가지는 사전입니다.
  Map&lt;String, String&gt; dictionary = {
    &#39;Harry Potter&#39;: &#39;해리포터&#39;,
    &#39;Ron Weasly&#39;: &quot;론 위즐리&quot;,
    &quot;Hermione Granger&quot;: &quot;헤르미온느 그레인저&quot;
  };

  // 문자열을 키로 하고, 불리언을 값으로 가지는 사전입니다.
  Map&lt;String, bool&gt; isHarryPotter = {
    &quot;Harry Potter&quot;: true,
    &quot;Ron weasley&quot;: true,
    &quot;Ironman&quot;: false
  };

  // 사전에서 키를 이용해 항목을 제거합니다.
  isHarryPotter.remove(&quot;Harry Potter&quot;);

  // 집합입니다. 집합은 중복된 값을 가질 수 없습니다.
  final Set&lt;String&gt; names = {
    &quot;Code Facory&quot;,
    &quot;Flutter&quot;,
    &quot;Black Pink&quot;,
  };

  // 집합에 항목을 추가하거나 제거합니다.
  names.add(&#39;Jenny&#39;);
  names.remove(&#39;Jenny&#39;);

  // 정수형 변수입니다.
  int number3 = 3;

  // 정수형 변수를 0으로 초기화합니다.
  int total = 0;
  List&lt;int&gt; numbers = [1,2,3,4,5,6];

  // for 루프를 이용해 리스트에 있는 모든 숫자를 합합니다.
  for(int i = 0; i &lt; numbers.length; i++){
    total += numbers[i];
  }

  // total을 다시 0으로 초기화합니다.
  total = 0;

  // for-in 루프를 이용해 리스트에 있는 모든 숫자를 합합니다.
  for(int number in numbers){
    total += number;
  }

  // while 루프를 이용해 total이 10이 될 때까지 숫자를 계속 더합니다.
  while(total &lt; 10){
    total += 1;
    if(total == 5) break; // total이 5가 되면 루프를 종료합니다.
  }

  // enum을 사용한 예시입니다.
  Status status = Status.approved;

  // 함수형 프로그래밍을 사용한 예시입니다.
  // 함수를 변수에 할당하고, 해당 변수를 이용해 함수를 호출합니다.
  Operation operation = add;
  int result9 = operation(10, 20, 30);

  operation = subtract;
  int result10 = operation(10, 20, 30);

  // 함수를 다른 함수의 인자로 전달하는 고차 함수(higher-order function)의 예시입니다.
  int result11 = calculate(30, 40, 50, add);
  int result12 = calculate(40,50,60,subtract);
}

// typedef를 이용해 함수 타입을 선언합니다.
typedef Operation = int Function(int x, int y, int z);

// 3개의 정수를 받아 합산하는 함수입니다.
int add(int x, int y, int z){
  return x+y+z;
}

// 3개의 정수를 받아 차를 구하는 함수입니다.
int subtract(int x, int y, int z){
  return x-y-z;
}

// 두 개의 숫자를 더하는 함수입니다.
int addNumbers({required int x, required int y, int z = 0}) {
  return x + y + z;
}

// 고차 함수(higher-order function)입니다.
// 연산을 수행할 함수와 인자를 받아 결과를 반환합니다.
int calculate(int a, int b, int c, Operation operation){
  return operation(a,b,c);
}</code></pre>
<p>출처 : <a href="https://www.inflearn.com/course/%ED%94%8C%EB%9F%AC%ED%84%B0-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8/dashboard">[초급] Flutter 3.0 앱 개발 - 10개의 프로젝트로 오늘 초보 탈출! </a> ( 코드팩토리 )</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Programmers lv.1 로또의 최고 순위와 최저 순위(JS)]]></title>
            <link>https://velog.io/@hmesan_93/Programmers-lv.1-%EB%A1%9C%EB%98%90%EC%9D%98-%EC%B5%9C%EA%B3%A0-%EC%88%9C%EC%9C%84%EC%99%80-%EC%B5%9C%EC%A0%80-%EC%88%9C%EC%9C%84JS</link>
            <guid>https://velog.io/@hmesan_93/Programmers-lv.1-%EB%A1%9C%EB%98%90%EC%9D%98-%EC%B5%9C%EA%B3%A0-%EC%88%9C%EC%9C%84%EC%99%80-%EC%B5%9C%EC%A0%80-%EC%88%9C%EC%9C%84JS</guid>
            <pubDate>Sun, 09 Jul 2023 13:32:59 GMT</pubDate>
            <description><![CDATA[<h1 id="로또의-최고-순위와-최저-순위">로또의 최고 순위와 최저 순위</h1>
<p>로또 6/45(이하 &#39;로또&#39;로 표기)는 1부터 45까지의 숫자 중 6개를 찍어서 맞히는 대표적인 복권입니다. 아래는 로또의 순위를 정하는 방식입니다.</p>
<table>
<thead>
<tr>
<th>순위</th>
<th>당첨 내용</th>
</tr>
</thead>
<tbody><tr>
<td>1</td>
<td>6개 번호가 모두 일치</td>
</tr>
<tr>
<td>2</td>
<td>5개 번호가 일치</td>
</tr>
<tr>
<td>3</td>
<td>4개 번호가 일치</td>
</tr>
<tr>
<td>4</td>
<td>3개 번호가 일치</td>
</tr>
<tr>
<td>5</td>
<td>2개 번호가 일치</td>
</tr>
<tr>
<td>6(낙첨)</td>
<td>그 외</td>
</tr>
</tbody></table>
<p>알아볼 수 없는 번호를 0으로 표기하기로 하고, 민우가 구매한 로또 번호 6개가 44, 1, 0, 0, 31, 25라고 가정해보겠습니다. 당첨 번호 6개가 31, 10, 45, 1, 6, 19라면, 당첨 가능한 최고 순위와 최저 순위의 한 예는 아래와 같습니다.</p>
<table>
<thead>
<tr>
<th>당첨 번호</th>
<th>31</th>
<th>10</th>
<th>45</th>
<th>1</th>
<th>6</th>
<th>19</th>
<th>결과</th>
</tr>
</thead>
<tbody><tr>
<td>최고 순위 번호</td>
<td>31</td>
<td>0→10</td>
<td>44</td>
<td>1</td>
<td>0→6</td>
<td>25</td>
<td>4개 번호 일치, 3등</td>
</tr>
<tr>
<td>최저 순위 번호</td>
<td>31</td>
<td>0→11</td>
<td>44</td>
<td>1</td>
<td>0→7</td>
<td>25</td>
<td>2개 번호 일치, 5등</td>
</tr>
</tbody></table>
<h2 id="제한사항">제한사항</h2>
<ul>
<li>lottos는 길이 6인 정수 배열입니다.</li>
<li>lottos의 모든 원소는 0 이상 45 이하인 정수입니다.</li>
<li>0은 알아볼 수 없는 숫자를 의미합니다.</li>
<li>0을 제외한 다른 숫자들은 lottos에 2개 이상 담겨있지 않습니다.</li>
<li>lottos의 원소들은 정렬되어 있지 않을 수도 있습니다.</li>
<li>win_nums은 길이 6인 정수 배열입니다.</li>
<li>win_nums의 모든 원소는 1 이상 45 이하인 정수입니다.</li>
<li>win_nums에는 같은 숫자가 2개 이상 담겨있지 않습니다.</li>
<li>win_nums의 원소들은 정렬되어 있지 않을 수도 있습니다.</li>
</ul>
<h2 id="입출력-예">입출력 예</h2>
<p>lottos, win_nums, result
[44, 1, 0, 0, 31, 25], [31, 10, 45, 1, 6, 19], [3, 5]
[0, 0, 0, 0, 0, 0], [38, 19, 20, 40, 15, 25], [1, 6]
[45, 4, 35, 20, 3, 9], [20, 9, 3, 45, 4, 35], [1, 1]</p>
<h3 id="처음-풀이">처음 풀이</h3>
<p>단순하게 생각해서 풀어보려고 노력했다. 만약 알아 볼 수 없는 번호로 표시된 0이 6개라면 전부다 틀리거나 아니면 전부다 맞거나를 고려해서 [1,6] 으로 예외처리를 해주었고, 모든 숫자가 전부 일치하는 경우도 [1,1] 으로 예외처리 해주었다.</p>
<p>나머지에 대해서 lottos 배열에 win_nums가 있다면 num을 하나씩 더해주었고, 원하는 등수를 맞추기 위해서 [7-count-num, 7-num] 을 리턴하도록 하였다. 그런데 하나의 테스트 케이스에서 통과하지 못하였다. </p>
<pre><code class="language-jsx">function solution(lottos, win_nums) {
    let num = 0
    let count = 0
    for(let i = 0; i &lt; 6; i++){
        if(lottos[i] === 0){
            count = count + 1
        }
    }
    if(count === 6) return [1,6]
    for(let i = 0; i &lt; 6; i++){
        if(lottos.includes(win_nums[i]) === true){
            num = num + 1
        } 
    }
    if(num === 6) return [1,1]
    return [7-count-num,7-num]
}</code></pre>
<p><img src="https://velog.velcdn.com/images/hmesan_93/post/c202ab80-114a-47d1-b259-aaa30aab2974/image.png" alt=""></p>
<h3 id="예외-케이스-발견-후-풀이">예외 케이스 발견 후 풀이</h3>
<pre><code class="language-jsx">function solution(lottos, win_nums) {
    let num = 0
    let count = 0
    for(let i = 0; i &lt; 6; i++){
        if(lottos[i] === 0){
            count = count + 1
        }
    }
    if(count === 6) return [1,6]
    for(let i = 0; i &lt; 6; i++){
        if(lottos.includes(win_nums[i]) === true){
            num = num + 1
        } 
    }
    if(num === 6) return [1,1]
    if(count === 0 &amp;&amp; num === 0) return [6,6]
    return [7-count-num,7-num]
}</code></pre>
<p>계속 생각해보니 만약에 민우가 구입한 로또 용지의 모든 번호가 알아 볼 수 있는데 맞는 번호의 갯수가 하나도 없는 경우....?
그러면 count가 0이고, num도 0이된다. 그러면 내가 위에서 풀이한대로 라면
[7-0-num,7-0] =&gt; [7,7] ....(로또에서 7등이있던가...?)
그렇다.. 문제에서 7등은 없기 때문에 이 경우에 대해서 예외처리를 해주는 것을 깜빡했다.</p>
<p>이 예외를 추가하고 나서는...!!!</p>
<p><img src="https://velog.velcdn.com/images/hmesan_93/post/62a20b25-e6eb-484b-a555-d401d0202361/image.png" alt="">다행히 모두 통과가 되었다. 마냥 그렇게 좋은..풀이는 아닌 느낌이다. 다른사람들의 풀이도 훑어보면서 여러가지 방법에 대해서 생각해보자!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Programmers lv.1 추억점수(JS)]]></title>
            <link>https://velog.io/@hmesan_93/Programmers-lv.1-%EC%B6%94%EC%96%B5%EC%A0%90%EC%88%98JS</link>
            <guid>https://velog.io/@hmesan_93/Programmers-lv.1-%EC%B6%94%EC%96%B5%EC%A0%90%EC%88%98JS</guid>
            <pubDate>Sun, 09 Jul 2023 12:36:49 GMT</pubDate>
            <description><![CDATA[<h1 id="추억-점수">추억 점수</h1>
<h2 id="문제-설명">문제 설명</h2>
<p>사진들을 보며 추억에 젖어 있던 루는 사진별로 추억 점수를 매길려고 합니다. 사진 속에 나오는 인물의 그리움 점수를 모두 합산한 값이 해당 사진의 추억 점수가 됩니다. 예를 들어 사진 속 인물의 이름이 [&quot;may&quot;, &quot;kein&quot;, &quot;kain&quot;]이고 각 인물의 그리움 점수가 [5점, 10점, 1점]일 때 해당 사진의 추억 점수는 16(5 + 10 + 1)점이 됩니다. 다른 사진 속 인물의 이름이 [&quot;kali&quot;, &quot;mari&quot;, &quot;don&quot;, &quot;tony&quot;]이고 [&quot;kali&quot;, &quot;mari&quot;, &quot;don&quot;]의 그리움 점수가 각각 [11점, 1점, 55점]]이고, &quot;tony&quot;는 그리움 점수가 없을 때, 이 사진의 추억 점수는 3명의 그리움 점수를 합한 67(11 + 1 + 55)점입니다.</p>
<p>그리워하는 사람의 이름을 담은 문자열 배열 <code>name</code>, 각 사람별 그리움 점수를 담은 정수 배열 <code>yearning</code>, 각 사진에 찍힌 인물의 이름을 담은 이차원 문자열 배열 <code>photo</code>가 매개변수로 주어질 때, 사진들의 추억 점수를 <code>photo</code>에 주어진 순서대로 배열에 담아 <code>return</code>하는 <code>solution</code> 함수를 완성해주세요.</p>
<h2 id="제한사항">제한사항</h2>
<ul>
<li>3 ≤ <code>name</code>의 길이 = <code>yearning</code>의 길이 ≤ 100</li>
<li>3 ≤ <code>name</code>의 원소의 길이 ≤ 7</li>
<li><code>name</code>의 원소들은 알파벳 소문자로만 이루어져 있습니다.</li>
<li><code>name</code>에는 중복된 값이 들어가지 않습니다.</li>
<li>1 ≤ <code>yearning[i]</code> ≤ 100</li>
<li><code>yearning[i]</code>는 i번째 사람의 그리움 점수입니다.</li>
<li>3 ≤ <code>photo</code>의 길이 ≤ 100</li>
<li>1 ≤ <code>photo[i]</code>의 길이 ≤ 100</li>
<li>3 ≤ <code>photo[i]</code>의 원소(문자열)의 길이 ≤ 7</li>
<li><code>photo[i]</code>의 원소들은 알파벳 소문자로만 이루어져 있습니다.</li>
<li><code>photo[i]</code>의 원소들은 중복된 값이 들어가지 않습니다.</li>
</ul>
<h2 id="입출력-예">입출력 예</h2>
<table>
<thead>
<tr>
<th>name</th>
<th>yearning</th>
<th>photo</th>
<th>result</th>
</tr>
</thead>
<tbody><tr>
<td>[&quot;may&quot;, &quot;kein&quot;, &quot;kain&quot;, &quot;radi&quot;]</td>
<td>[5, 10, 1, 3]</td>
<td>[[&quot;may&quot;, &quot;kein&quot;, &quot;kain&quot;, &quot;radi&quot;],[&quot;may&quot;, &quot;kein&quot;, &quot;brin&quot;, &quot;deny&quot;], [&quot;kon&quot;, &quot;kain&quot;, &quot;may&quot;, &quot;coni&quot;]]</td>
<td>[19, 15, 6]</td>
</tr>
<tr>
<td>[&quot;kali&quot;, &quot;mari&quot;, &quot;don&quot;]</td>
<td>[11, 1, 55]</td>
<td>[[&quot;kali&quot;, &quot;mari&quot;, &quot;don&quot;], [&quot;pony&quot;, &quot;tom&quot;, &quot;teddy&quot;], [&quot;con&quot;, &quot;mona&quot;, &quot;don&quot;]]</td>
<td>[67, 0, 55]</td>
</tr>
<tr>
<td>[&quot;may&quot;, &quot;kein&quot;, &quot;kain&quot;, &quot;radi&quot;]</td>
<td>[5, 10, 1, 3]</td>
<td>[[&quot;may&quot;],[&quot;kein&quot;, &quot;deny&quot;, &quot;may&quot;], [&quot;kon&quot;, &quot;coni&quot;]]</td>
<td>[5, 15, 0]</td>
</tr>
</tbody></table>
<h2 id="입출력-예-설명">입출력 예 설명</h2>
<h3 id="입출력-예-1">입출력 예 #1</h3>
<p>첫 번째 사진 속 &quot;may&quot;, &quot;kein&quot;, &quot;kain&quot;, &quot;radi&quot;의 그리움 점수를 합치면 19(5 + 10 + 1 + 3)점 입니다. 두 번째 사진 속 그리워하는 사람들인 &quot;may&quot;와 &quot;kein&quot;의 그리움 점수를 합치면 15(5 + 10)점입니다. 세 번째 사진의 경우 &quot;kain&quot;과 &quot;may&quot;만 그리워하므로 둘의 그리움 점수를 합한 6(1 + 5)점이 사진의 추억 점수입니다. 따라서 [19, 15, 6]을 반환합니다.</p>
<h3 id="입출력-예-2">입출력 예 #2</h3>
<p>첫 번째 사진 속 그리워하는 사람들인 &quot;kali&quot;, &quot;mari&quot;, &quot;don&quot;의 그리움 점수를 합치면 67(11 + 1 + 55)점입니다. 두 번째 사진 속엔 그리워하는 인물이 없으므로 0점입니다. 세 번째 사진 속 그리워하는 사람은 &quot;don&quot;만 있으므로 55점입니다. 따라서 [67, 0, 55]를 반환합니다.</p>
<h2 id="풀이">풀이</h2>
<pre><code class="language-jsx">function solution(name, yearning, photo) {
    let obj = {};
    // 각 name에 해당하는 그리움 점수를 매핑하는 객체 만듦
    for(let i = 0; i &lt; name.length; i++){
        obj[name[i]] = yearning[i]
    }
    /* 각 리스트에 대해 해당하는
       Key의 value(그리움점수) 를 배열로 만듦( 해당하는 값이 없다면 0을 더함) 
    */
    const result = photo.map(wordList =&gt; {
        return wordList.reduce((totalObj, word) =&gt; {
            return totalObj + (obj[word] || 0);
        }, 0);
    });
    return result;
}
</code></pre>
<p>주어진 name과 yearning의 각각 요소들을 일대일로 매핑하여서 객체로 만들었다.
그리고 주어진 이차원 배열로 주어진 photo의 각 요소들을 순회하면서 각 요소가 가지고 있는 원소들의 합들을 배열로 리턴하였다. 만약 원소들이 있으면 해당하는 이름에 해당하는 그리움점수를 더하고 없다면 0을 더해서 result를 구하는 것으로 문제를 풀었다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[인터넷 네트워크 기초 지식]]></title>
            <link>https://velog.io/@hmesan_93/%EC%9D%B8%ED%84%B0%EB%84%B7-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EA%B8%B0%EC%B4%88-%EC%A7%80%EC%8B%9D</link>
            <guid>https://velog.io/@hmesan_93/%EC%9D%B8%ED%84%B0%EB%84%B7-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EA%B8%B0%EC%B4%88-%EC%A7%80%EC%8B%9D</guid>
            <pubDate>Fri, 07 Jul 2023 02:33:20 GMT</pubDate>
            <description><![CDATA[<p>클라이언트에서 서버까지 어떻게 수많은 복잡한 길을 헤쳐나갈까?</p>
<p>→ IP에 대해 알아보자</p>
<p>어떻게 ‘Hello world’를 주고 받을 수 있을까? → 각각의 IP주소가 있어야 한다.</p>
<hr>
<h2 id="ip">IP</h2>
<p>인터넷 프로토콜 역할</p>
<ul>
<li>지정한 IP 주소(IP Address)에 데이터 전달</li>
<li>패킷(Packet)이라는 통신 단위로 전달</li>
</ul>
<p>메시지를 그냥 그대로 보내는 것이 아니라 ‘IP 패킷’ 규칙에 의해서 보내진다.</p>
<p><img src="https://velog.velcdn.com/images/hmesan_93/post/cd9109d6-a358-4c5c-80b5-109fede1f621/image.png" alt=""></p>
<p>이렇게 IP패킷을 만든 다음에 던지면 목적지(서버) 까지 데이터가 패킷이라는 형태로 전달이 완료된다.</p>
<p><img src="https://velog.velcdn.com/images/hmesan_93/post/7919c5f3-de93-46a8-9252-f10dcfa7919a/image.png" alt=""></p>
<p>서버가 클라이언트가 보낸 데이터를 받으면 OK라는 표시를통해 적절한 응답을 보낸다.</p>
<h3 id="ip-프로토콜의-한계">IP 프로토콜의 한계</h3>
<ul>
<li><p>비연결성</p>
<ul>
<li><p>패킷을 받을 대상이 없거나 서비스 불능 상태여도 패킷 전송</p>
<p>  → 대상 서버가 패킷을 받을 수 있는 상태인지 모름</p>
</li>
</ul>
</li>
<li><p>비신뢰성</p>
<ul>
<li>중간에 패킷이 사라지면? → 여러 서버를 거쳐가다가 특정 서버가 죽은 상태이거나 케이블이 손상이 있을수 있음 </li>
<li>패킷이 순서대로 안오면? → 대략 패킷들이 1500byte 씩 끊어져서 보내지는데 각 패킷들이 서로 다른 노드를 탈 수 도 있음 → 도착 순서가 달라질 수 도 있음</li>
</ul>
</li>
<li><p>프로그램 구분</p>
<ul>
<li>같은 IP를 사용하는 서버에서 통신하는 애플리케이션이 둘 이상이면?</li>
</ul>
</li>
</ul>
<hr>
<h2 id="인터넷-프로토콜-스택의-4계층">인터넷 프로토콜 스택의 4계층</h2>
<p><img src="https://velog.velcdn.com/images/hmesan_93/post/5cf49937-1992-40eb-9478-2a412f4f874f/image.png" alt=""></p>
<p>네트워크 인터페이스 계층 → 랜카드,랜드라이버 등 을 포함한다.</p>
<p><img src="https://velog.velcdn.com/images/hmesan_93/post/d68a4686-0425-4c9d-b5f3-1fb6be1ac527/image.png" alt=""></p>
<p>랜카드를 통해 인터넷으로 전달될 때 Ethernet frame 으로 포장되어서 보내진다.</p>
<p>Ethernet frame은 랜카드에 등록된 MAC주소(물리적인 주소) 등을 담고있다.</p>
<h2 id="tcpip-패킷-정보">TCP/IP 패킷 정보</h2>
<p>그래서 패킷이 뭔가? → 패키지 + 버킷</p>
<p>: <strong>데이터 담는 상자</strong></p>
<p>TCP 정보에는 전송 제어, 순서, 검증 정보 등이 포함된다. IP만으로 해결이 안됐던 문제들이 해결이 된다.</p>
<p><img src="https://velog.velcdn.com/images/hmesan_93/post/ba1192be-1fd9-405f-a73f-3f02a485490d/image.png" alt=""></p>
<hr>
<h2 id="tcp-특징">TCP 특징</h2>
<p>전송 제어 프로토콜( Transmission Control Protocol )</p>
<ul>
<li>연결지향 - TCP 3 way handshake ( 가상 연결 ) → 연결을 한 다음에 데이터를 보냄</li>
<li>데이터 전달 보증 → 만약 전송중에 패킷이 누락되거나 손상되면 알 수가 있음</li>
<li>순서 보장</li>
<li>신뢰 할 수 있는 프로토콜</li>
<li>현재는 대부분 TCP 사용</li>
</ul>
<h3 id="tcp-3-way-handshake">TCP 3 way handshake</h3>
<p><img src="https://velog.velcdn.com/images/hmesan_93/post/4d6c2012-73d8-4996-bbae-9ea0e7e0a60a/image.png" alt=""></p>
<p>서로 총 3번주고 받고 연결이 됐다라는 것을 인식한 후에 데이터를 전송한다.</p>
<p>근데 여기서 연결이 됐다라는 것도 결국 논리적으로 (가상으로) 연결이 됐다라고 개념적으로 생각하는 것이다. 물리적으로 연결이 된 것이 아니다.</p>
<p>만약 클라이언트에서 SYN을 보냄 → 서버에서 응답이 없음 → 클라이언트가 알아차리고 메시지를 보내지 않는다.</p>
<p><strong>요즘은 3번과정인 클라이언트가 ACK를 보낼때 데이터도 함께 보낸다고 한다.</strong></p>
<h4 id="데이터-전달-보증">데이터 전달 보증</h4>
<p><img src="https://velog.velcdn.com/images/hmesan_93/post/42a7706d-0ecc-4a21-9b18-46c2611fc92a/image.png" alt=""></p>
<p>클라이언트에서 데이터 전송을 하고나서 서버가 데이터를 받으면 받았다고 응답을 보내준다. 만약 아무 응답이 없다면 클라이언트 입장에서 어떤 문제가 있다고 인지할 수 있다.</p>
<h4 id="순서-보장">순서 보장</h4>
<p><img src="https://velog.velcdn.com/images/hmesan_93/post/6b30fd77-6a10-4c88-a833-dbd87550bef4/image.png" alt=""></p>
<p>이러한 것들이 어떻게 가능할까? → 위에서 언급한 TCP 데이터안에는 전송 제어, 순서, 검증 정보 들이 추가가 되어 있기 때문에 가능한 것이다. 그래서 TCP를 신뢰할 수 있는 프로토콜이라고 부른다.</p>
<hr>
<h2 id="udp-특징">UDP 특징</h2>
<p>사용자 데이터그램 프로토콜(User Datagram Protocol)</p>
<ul>
<li>하얀 도화지에 비유(기능이 거의 없음)<ul>
<li>HTTP3이 UDP기반 통신 방식</li>
</ul>
</li>
<li>연결지향 - TCP 3 way handshake X</li>
<li>데이터 전달 보증 X</li>
<li>순서 보장 X</li>
<li>데이터 전달 및 순서가 보장되지 않지만, 단순하고 빠름</li>
<li>정리<ul>
<li>IP와 거의 동일하지만 PORT와 체크섬 정도만 추가되어있음</li>
<li>애플리케이션에서 추가 작업 필요</li>
</ul>
</li>
</ul>
<p>→ TCP, UDP 모두 PORT 정보가 포함되어있다. PORT가 무엇일까?</p>
<p>내가 사용하고 있는 PC가 1개라면 IP주소는 하나이다. 그런데 PC에서 게임도 하고, 음악도 듣고 다른 여러 애플리케이션이 동작 중이라고 하면 내 IP로 여러 패킷들이 들어오고 있는 상황이다. 어떻게 들어오는 패킷이 게임패킷인지 음악패킷인 지 구분할 것인가?  라고 할 때 필요한 것이 PORT이다.  PORT는 출입문이라고 생각하면 된다. 하나의 건물에 여러 출입문이 있는 것처럼 하나의 PC에 즉 하나의 IP에 여러 PORT가 있는 것이다. 그리고 데이터들은 검증할 때 필요한 것이 체크섬이다.</p>
<hr>
<h2 id="port">PORT</h2>
<ul>
<li>0 ~ 65535 할당 가능</li>
<li>0 ~ 1023: 잘 알려진 포트, 사용하지 않는 것이 좋음<ul>
<li>FTP - 20, 21</li>
<li>TELNET - 23</li>
<li>HTTP - 80</li>
<li>HTTPS - 443</li>
</ul>
</li>
</ul>
<hr>
<h2 id="dns">DNS</h2>
<p>IP는 외우기 어렵고 변경될 수가 있다. → DNS로 해결 가능</p>
<p>→ <strong>도메인 네임 시스템(Domain Name System) 사용</strong></p>
<ul>
<li>전화번호부</li>
<li>도메인 명을 IP 주소로 변환</li>
</ul>
<p>도메인을 사서 IP주소를 등록해놓는다.</p>
<p>클라이언트가 DNS 서버에다가 원하는 사이트의 주소를 달라고하면 DNS서버가 응답을 하고 원하는 사이트의 IP주소를 준다.</p>
<hr>
<p>출처 : <a href="https://www.inflearn.com/course/http-%EC%9B%B9-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC/dashboard">모든 개발자를 위한 HTTP 웹 기본 지식 </a> ( 김영한 )</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[express + AWS EC2 배포하기]]></title>
            <link>https://velog.io/@hmesan_93/express-AWS-EC2-%EB%B0%B0%ED%8F%AC%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@hmesan_93/express-AWS-EC2-%EB%B0%B0%ED%8F%AC%ED%95%98%EA%B8%B0</guid>
            <pubDate>Wed, 05 Jul 2023 11:56:20 GMT</pubDate>
            <description><![CDATA[<p>node 환경에서 express를 사용하여 간단하게 서버를 구축하고 AWS EC2에 배포하는 것을 테스트 해보자!</p>
<h2 id="시작">시작</h2>
<p><img src ="https://velog.velcdn.com/images/hmesan_93/post/1590110f-5bb0-417a-a5fb-57186d14cc51/image.png
           " width = "200" >먼저 AWS EC2사이트에 접속한 뒤에 EC2 Dashboard에 접속한다.</p>
<p><img src ="https://velog.velcdn.com/images/hmesan_93/post/35e5b2d9-16cb-467d-b91b-b36a3a66813b/image.png
           " width = "500">다음과 같은 화면이 나올텐데 노란색 박스인 &#39;Launch Instance&#39; 박스를 클릭해준다.
<img src = "https://velog.velcdn.com/images/hmesan_93/post/e646a596-f48b-4d69-86f8-106060eb9beb/image.png" width = "500">인스턴스 Name은 &quot;ec2_test&quot;로 해줬고 OS를 선택하는 토글에서는 우분투 22.04 LTS 버전을 선택해주었다.
LTS는 장기간에 걸쳐 지원하도록 고안되어 나온 버전이라 좀 더 안정적이어서 택했다.</p>
<p><img src = "https://velog.velcdn.com/images/hmesan_93/post/571fcb80-36ca-4867-9e7d-e8d20093af38/image.png
            " width = "500" >인스턴스 타입은 프리티어(무료)인 t2.mirco로 해주었다.
기본적인 테스트에 맞게 그리 높지 않은 사양을 선택했고 t2.nano는 500Mib 인데 예전에 사용했을 때 라이브러리들을 설치할때 메모리 부족으로 에러가 많이 났던 것 같다. 이왕이면 조금 더 사양이 높은 t2.micro를 추천한다.</p>
<p><img src = "https://velog.velcdn.com/images/hmesan_93/post/c5ce04c9-a575-4e0f-a3db-ae90795735a5/image.png
            " width = "500" >&#39;Create new key pair&#39; 를 클릭해서 인스턴스에 접속할 수 있는 열쇠를 하나 만들어주자.</p>
<p><img src = "https://velog.velcdn.com/images/hmesan_93/post/d84ceee3-b8a8-4a80-9ebf-9b6b5f8b10bd/image.png
            " width = "500" >키페어 이름은 입력하고  &#39;Create key pair&#39; 버튼을 눌러서 키를 생성하자!</p>
<p>그리고 Network setting 에서 VPC 환경을 미리 만들어 놓았다면 만든 vpc로 해주고 그렇지 않다면 그대로 놔두자.</p>
<p> 여기까지 하고 그외에 밑에 나열되어있는 옵션들에 대해서 딱히 건드릴 건 없는 것같다.
<img src = "https://velog.velcdn.com/images/hmesan_93/post/457d01a0-5927-410d-9890-1dbd28b2cc4e/image.png
" width = "300" >그러면 이제 오른쪽 사이드에 &#39;Lanch instance&#39; 버튼을 눌러 인스턴스를 생성해준다.</p>
<p><img src = "https://velog.velcdn.com/images/hmesan_93/post/5bed8567-a79f-41c1-afe0-d62613e51399/image.png" width = "600">짜짠! Running 상태가 떠있다면 제대로 인스턴스가 작동중인 것을 의미한다.</p>
<p>자 이제 인스턴스에 접속해서 express를 설치해보자!</p>
<p>우선 Instance ID를 클릭해준다.
<img src = "https://velog.velcdn.com/images/hmesan_93/post/e45184a3-5607-46ef-92e3-32c4c25dcfa8/image.png
" witdh = "500">다음과 같은 화면이 보이면 위에 Connect를 누르고 다시 한번더 노란색 버튼의 Connect를 눌러서 인스턴스에 접속한다.</p>
<p>먼저 다음과 같은 명령어를 차례대로 입력해준다.</p>
<pre><code>sudo apt update
sudo apt install curl
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash</code></pre><p>세번째 명령어는 nvm(노드 버전 관리자)을 설치하는 명령어이다.</p>
<pre><code>. ~/.nvm/nvm.sh   &lt;-  nvm 활성화 (터미널에 아무 반응없으면 잘 된 것)
nvm install --lts &lt;-  Node.js 최신 LTS 릴리스 설치</code></pre><p><img src="https://velog.velcdn.com/images/hmesan_93/post/a192bb34-8718-4dff-95cc-639ef14b2697/image.png" alt="">다음과 같이 출력된다며 설치가 잘 된 것이다.</p>
<p>( 만약 아마존 리눅스2를 쓴다면 Node.js 최신 LTS 릴리스 (18.x)를 지원하지 않기 때문에 &#39;nvm install 16&#39;으로 16버전을 설치해야 한다. ) </p>
<pre><code>node -e &quot;console.log(&#39;Running Node.js &#39; + process.version)&quot;</code></pre><p>위의 명령어를 입력하여 &quot;Running Node.js v18.16.1&quot; 문구가 잘 출력되는지 확인하자! 출력이 잘 되면 Node.js가 올바르게 설치되고 잘 실행된다는 것이다.</p>
<p>자 이제 express를 설치하러 가보자!</p>
<pre><code>npx express-generator [폴더이름]</code></pre><p>위의 명령어를 입력한 후에 &quot;Ok to proceed?&quot; 메시지가 나오면 &#39;y&#39;를 입력하고 엔터를 누른다.
express가 설치가 되고 test(전 test로 폴더이름을 정했습니다...) 폴더안에 구조화된 폴더나 파일들이 생성이 되었을 것이다.</p>
<p>잘 실행이되는지 테스트해보자</p>
<pre><code>npm install   &lt;- 관련 라이브러리 설치
npm start</code></pre><p><img src = "https://velog.velcdn.com/images/hmesan_93/post/23139df7-ce5b-4f2b-99c9-63a1ed086a54/image.png
            " width = "500">다음과 같이 나온다면 서버가 잘 실행이 되었다는 뜻이다.
            기본적으로 3000포트로 열리고 SSL/TLS를 추가하지 않은 상태이기 때문에 https가 아닌 http이고 인스턴스의 Public IPv4 addresses를 넣어주어서
            <strong>http</strong>://{Public IPv4 addresses}:3000 와 같이 주소창에 입력해주면!! 
            페이지가 열리지 않을 것이다...(무한로딩..) 왜냐하면 아직 포트를 열어주지 않았기 때문이다.</p>
<p><img src="https://velog.velcdn.com/images/hmesan_93/post/befe7fda-2f00-459d-acd6-1832495a49fd/image.png" alt=""></p>
<p>인스턴스로 들어와서 아래에 Security 탭을 클릭한 후에 밑에 Inbound rules(인바운드 규칙) 을 설정해주어야 한다.</p>
<p>Inbound roles 에 Security groups 컬럼에 해당하는 &quot;launch-wizard-1&quot; 을 선택한다.
<img src="https://velog.velcdn.com/images/hmesan_93/post/22c80456-76e6-4389-9259-d6efee74ccb1/image.png" alt="">여기서 다시 Inbound rules 탭에 들어가서 &quot;Edit inbound rules&quot; 버튼을 누른다
<img src="https://velog.velcdn.com/images/hmesan_93/post/76cbf3d9-78fb-4ff5-bd3b-4ece9121df53/image.png" alt="">위의 사진에서 Add rule 버튼을 눌러서 아래와 같이 규칙을 추가해준다.</p>
<p><img src="https://velog.velcdn.com/images/hmesan_93/post/a9b8b65a-ba24-4081-9ec1-e8de6d22ee67/image.png" alt=""> 설정이 끝났으면 Save rules버튼을 눌러준다. 참고로 HTTP 와 HTTPS 통신은 포트가 80, 443으로 정해져있다.</p>
<p>자 이제 여기까지 설정을 완료했으면 다시 <strong>http</strong>://{Public IPv4 addresses}:3000을 주소창에 입력해보자!</p>
<p><img src="https://velog.velcdn.com/images/hmesan_93/post/fdeb07b4-6a4b-4b28-8c71-4491f9f78447/image.png" alt="">
축하한다. 접속한 페이지에 다음과 같이 나온다면 성공이다.
이제 여러분은 express 서버를 돌리실 수 있게 되었네요.</p>
<h2 id="정리">정리</h2>
<p>AWS EC2를 이용해 가상의 컴퓨터(인스턴스)를 만들고 그 위에 express를 이용하여 서버를 배포하는 것 까지 해보았다.
최대한 초보자도 따라하기 쉽게 설명했지만 처음하는 데 있어서 잘 안될 수도 있을 것이다. 
만약 안되면 처음부터 다시 차근차근 따라해보자.</p>
<p>이로써 글을 마치고 다음에도 도움되는 내용으로 오겠습니다. 감사합니다!</p>
<p>[참고]
AWS 가이드: <a href="https://docs.aws.amazon.com/ko_kr/sdk-for-javascript/v2/developer-guide/setting-up-node-on-ec2-instance.html">https://docs.aws.amazon.com/ko_kr/sdk-for-javascript/v2/developer-guide/setting-up-node-on-ec2-instance.html</a></p>
<p>Express 가이드: <a href="https://expressjs.com/ko/">https://expressjs.com/ko/</a></p>
<p>더욱 자세히 알고 싶으면 위의 웹사이트 참조하면 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Programmers lv.2 카펫(완전탐색)(JS)]]></title>
            <link>https://velog.io/@hmesan_93/Programmers-lv.2-%EC%B9%B4%ED%8E%AB%EC%99%84%EC%A0%84%ED%83%90%EC%83%89JS</link>
            <guid>https://velog.io/@hmesan_93/Programmers-lv.2-%EC%B9%B4%ED%8E%AB%EC%99%84%EC%A0%84%ED%83%90%EC%83%89JS</guid>
            <pubDate>Fri, 30 Jun 2023 10:15:18 GMT</pubDate>
            <description><![CDATA[<h1 id="카펫">카펫</h1>
<h2 id="문제-설명">문제 설명</h2>
<p>Leo는 카펫을 사러 갔다가 아래 그림과 같이 중앙에는 노란색으로 칠해져 있고 테두리 1줄은 갈색으로 칠해져 있는 격자 모양 카펫을 봤습니다.</p>
<p>Leo는 집으로 돌아와서 아까 본 카펫의 노란색과 갈색으로 색칠된 격자의 개수는 기억했지만, 전체 카펫의 크기는 기억하지 못했습니다.</p>
<p>Leo가 본 카펫에서 갈색 격자의 수 <code>brown</code>, 노란색 격자의 수 <code>yellow</code>가 매개변수로 주어질 때 카펫의 가로, 세로 크기를 순서대로 배열에 담아 return 하도록 <code>solution</code> 함수를 작성해주세요.</p>
<h2 id="제한사항">제한사항</h2>
<ul>
<li>갈색 격자의 수 <code>brown</code>은 8 이상 5,000 이하인 자연수입니다.</li>
<li>노란색 격자의 수 <code>yellow</code>는 1 이상 2,000,000 이하인 자연수입니다.</li>
<li>카펫의 가로 길이는 세로 길이와 같거나, 세로 길이보다 깁니다.</li>
</ul>
<h2 id="입출력-예">입출력 예</h2>
<table>
<thead>
<tr>
<th>brown</th>
<th>yellow</th>
<th>return</th>
</tr>
</thead>
<tbody><tr>
<td>10</td>
<td>2</td>
<td>[4, 3]</td>
</tr>
<tr>
<td>8</td>
<td>1</td>
<td>[3, 3]</td>
</tr>
<tr>
<td>24</td>
<td>24</td>
<td>[8, 6]</td>
</tr>
</tbody></table>
<h3 id="처음-풀이">처음 풀이</h3>
<pre><code class="language-jsx">function solution(brown, yellow) {
    var answer = [];
    let num = brown + yellow;
    for (let i = 1; i &lt;= num; i++) {
        if (num % i === 0) {
            let temp = num / i
            if(i &gt;= temp){
                answer.push(i)
                answer.push(temp)
                break;
            }
        }
    }
    return answer;
}</code></pre>
<p>문제를 보고 결국 brown격자와 yellow격자의 합이 곧 총 가로 x 세로 라고 생각했기 때문에 total의 약수를 전부 구하는 과정에서 답을 찾기로 했다. 
예를 들어 brown이 10, yellow가 2 이라면 합이 12이고,
12의 약수는 [1,2,3,4,6,12] 이다. (1, 12), (2, 6), (3,4), (4,3) ... 이렇게 짝을 이루면서 구해볼 수 있는 데 문제의 조건에서 가로의 길이가 세로의 길이보다 같거나 크기 때문에 약수의 중간값 2개가 곧 가로와 세로의 길이가 되고, i가 4가되는 순간 temp는 3이 되어서 [4,3] , 즉 이 값이 정답이라고 생각하였다.
<img src="https://velog.velcdn.com/images/hmesan_93/post/223b2ed2-3a81-410c-a336-9b3d58ede641/image.png" alt="">보다시피 4,6,7 테스트케이스가 통과가 되지 않았고 다른 사람의 풀이를 보던 중에 파라미터가 18,6 으로 들어왔을 때 합이 24이고 반환된 값은 [6,4]가 되었다. 하지만 가로의 길이가 6, 세로의 길이가 4가 된다면 brown의 갯수가 16개이고 yellow의 갯수가 8개가 된다.
입력값의 각각의 격자 수와 일치하지 않는다.</p>
<p>아무래도 이렇게 들어오는 입력값 때문에 통과가 되지 않는 테스트케이스가 있는 것 같아서 다시 아래와 같이 풀이를 수정했다.</p>
<h3 id="예외-케이스-발견-후-풀이">예외 케이스 발견 후 풀이</h3>
<pre><code class="language-jsx">function solution(brown, yellow) {
    var answer = [];
    let total = brown + yellow;
    for (let height = 3; height &lt;= total; height++) {
        if (total % height === 0) {
            let width = total / height;
            // 갈색 격자의 수는 노란색 격자를 둘러싸는 테두리이기 때문에 이 조건에 만족해야함.
            if (2 * (width + height - 2) === brown) {
                return [width, height];
            }
        }
    }
}</code></pre>
<p>위의 코드와 거의 흡사하지만 파라미터로 들어오는 갈색 격자의 수를 검사하는 로직을 넣어주었다. 그렇게 해서 6위에서 언급한 입력값이 (18,6)이 들어왔을 때 조건을 만족하는 [8,3]을 반환해서 제대로 된 값을 구할 수 있었고 모든 테스트에 통과 할 수 있었다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Programmers lv.2 귤 고르기(JS)]]></title>
            <link>https://velog.io/@hmesan_93/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4</link>
            <guid>https://velog.io/@hmesan_93/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4</guid>
            <pubDate>Fri, 30 Jun 2023 08:53:53 GMT</pubDate>
            <description><![CDATA[<h2 id="귤-고르기">귤 고르기</h2>
<h3 id="문제-설명">문제 설명</h3>
<p>경화는 과수원에서 귤을 수확했습니다. 경화는 수확한 귤 중 &#39;k&#39;개를 골라 상자 하나에 담아 판매하려고 합니다. 그런데 수확한 귤의 크기가 일정하지 않아 보기에 좋지 않다고 생각한 경화는 귤을 크기별로 분류했을 때 서로 다른 종류의 수를 최소화하고 싶습니다.</p>
<p>예를 들어, 경화가 수확한 귤 8개의 크기가 <code>[1, 3, 2, 5, 4, 5, 2, 3]</code> 이라고 합시다. 경화가 귤 6개를 판매하고 싶다면, 크기가 1, 4인 귤을 제외한 여섯 개의 귤을 상자에 담으면, 귤의 크기의 종류가 2, 3, 5로 총 3가지가 되며 이때가 서로 다른 종류가 최소일 때입니다.</p>
<p>경화가 한 상자에 담으려는 귤의 개수 <code>k</code>와 귤의 크기를 담은 배열 <code>tangerine</code>이 매개변수로 주어집니다. 경화가 귤 <code>k</code>개를 고를 때 크기가 서로 다른 종류의 수의 최솟값을 <code>return</code> 하도록 <code>solution</code> 함수를 작성해주세요.</p>
<h3 id="제한사항">제한사항</h3>
<ul>
<li>1 ≤ <code>k</code> ≤ <code>tangerine</code>의 길이 ≤ 100,000</li>
<li>1 ≤ <code>tangerine</code>의 원소 ≤ 10,000,000</li>
</ul>
<h3 id="입출력-예">입출력 예</h3>
<table>
<thead>
<tr>
<th><code>k</code></th>
<th><code>tangerine</code></th>
<th><code>result</code></th>
</tr>
</thead>
<tbody><tr>
<td>6</td>
<td><code>[1, 3, 2, 5, 4, 5, 2, 3]</code></td>
<td>3</td>
</tr>
<tr>
<td>4</td>
<td><code>[1, 3, 2, 5, 4, 5, 2, 3]</code></td>
<td>2</td>
</tr>
<tr>
<td>2</td>
<td><code>[1, 1, 1, 1, 2, 2, 2, 3]</code></td>
<td>1</td>
</tr>
</tbody></table>
<h3 id="입출력-예-설명">입출력 예 설명</h3>
<h4 id="입출력-예-1">입출력 예 #1</h4>
<p>본문에서 설명한 예시입니다.</p>
<h4 id="입출력-예-2">입출력 예 #2</h4>
<p>경화는 크기가 2인 귤 2개와 3인 귤 2개 또는 2인 귤 2개와 5인 귤 2개 또는 3인 귤 2개와 5인 귤 2개로 귤을 판매할 수 있습니다. 이때의 크기 종류는 2가지로 이 값이 최소가 됩니다.</p>
<h4 id="입출력-예-3">입출력 예 #3</h4>
<p>경화는 크기가 1인 귤 2개를 판매하거나 2인 귤 2개를 판매할 수 있습니다. 이때의 크기 종류는 1가지로, 이 값이 최소가 됩니다.</p>
<hr>
<h3 id="문제풀이">문제풀이</h3>
<p>처음 문제를 읽고 이해한 바로는 다음과 같다.</p>
<ul>
<li>k개 만큼만 귤을 판매하고자 함.</li>
<li>귤을 크기별로 분류했을 때 서로 다른 종류의 수를 최소화 하고 싶다.</li>
</ul>
<p>파는사람입장에서 이해하기 쉽게 생각했을 때 진열해놓은 귤이 깔끔하게 보이고 싶어서 같은 종류별로 묶어서 파는데 k개 만큼만 진열하고 싶다는 것이다.
그리고 구하고자 하는 값은 이렇게 진열 했을 때 서로 다른 종류의 수가 최소 몇 종류인가? 하는 것이다.</p>
<pre><code class="language-jsx">function solution(k, tangerine) {
    let sum = 0;
    let result = 0;
    let obj = {};
    tangerine.forEach((item) =&gt; {
        // obj[n] 값이 있으면 1을 더해서 카운트해준다.
        // obj[n] 값이 없으면 1을 넣어준다.
        obj[item] = ++obj[item] || 1;
    })
    // obj = { &#39;1&#39;: 1, &#39;2&#39;: 2, &#39;3&#39;: 2, &#39;4&#39;: 1, &#39;5&#39;: 2}
    // 서로 다른 종류의 수의 최솟값을 구하기 위해선 종류는 상관없고 값만 필요.
    // 내림차순정렬
    const typeArr = Object.values(obj).sort((a, b) =&gt; b - a);
    // typeArr = [2, 2, 2, 1, 1]
    for(let i of typeArr){
        result++;
        sum = sum + i

        // 팔려고하는 귤의 갯수를 충족하면 break
        if(sum &gt;= k) break;
    }
    return result
}</code></pre>
<p>귤의 크기가 몇 종류이고 그리고 그 종류만큼 귤이 몇개가 있는가? 에 핵심을 두었다. 그래서 처음에 귤의 크기를 Key값으로 그 크기가 몇개있는지에 대한 값을 value로 해서 obj를 구해주었다.</p>
<p>그리고 최솟값을 구하는 것이기 때문에 한 종류의 갯수가 가장 많은 것부터 카운트해주기 위해서 내림차순으로 정렬해주었다.
그렇게 갯수를 카운트 하였고 한 종류의 갯수의 카운트가 끝날때마다 result(구하고자 하는 값을) +1 해주었고, 총 갯수 즉,sum이 문제에서 주어진 k값 이상이 되었을 때 break 함으로써 답을 구해주었다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[ MySQL에서 반환되는 데이터(+ Entity,DTO)]]></title>
            <link>https://velog.io/@hmesan_93/MySQL%EC%97%90%EC%84%9C-%EB%B0%98%ED%99%98%EB%90%98%EB%8A%94-%EB%8D%B0%EC%9D%B4%ED%84%B0-EntityDTO</link>
            <guid>https://velog.io/@hmesan_93/MySQL%EC%97%90%EC%84%9C-%EB%B0%98%ED%99%98%EB%90%98%EB%8A%94-%EB%8D%B0%EC%9D%B4%ED%84%B0-EntityDTO</guid>
            <pubDate>Wed, 28 Jun 2023 03:02:13 GMT</pubDate>
            <description><![CDATA[<p>프로젝트를 하면서 생긴 일에 대해서 간단히 적어보았습니다.</p>
<p>MySQL에서 데이터를 조회하거나 수정, 추가 요청을 할 때 발생하는 문제에 대해 설명하고자 합니다. 우리는 일반적으로 JavaScript에서 주로 사용하는 카멜 케이스(camelCase)를 따르지만, MySQL에서 반환하는 데이터는 스네이크 케이스(snake_case)로 반환되기 때문에 이에 대한 일관성이 떨어지고, 코드의 가독성이 저하되는 문제가 있었습니다.</p>
<h2 id="문제-상황">문제 상황</h2>
<p>우리 팀에서는 JavaScript를 주로 사용하고, 코드 작성 시에는 카멜케이스(camelCase)를 사용합니다. 그러나, MySQL 데이터베이스에서 조회한 데이터는 스네이크 케이스(snake_case)로 반환되므로, 이로 인해 코드 일관성이 떨어지고 가독성이 저하되었습니다.</p>
<h2 id="해결-방법">해결 방법</h2>
<p>이 문제를 해결하기 위해, 아래 코드의 내용과 같이 MySQL에서 반환된 데이터(엔티티)를 카멜케이스로 변환하여 클라이언트에게 전달하도록 하였습니다. 이를 통해 프로젝트의 전체 코드의 일관성을 유지할 수 있었으며, 코드의 가독성도 향상되었습니다.</p>
<p>다음은 이를 구현한 JavaScript 코드입니다.</p>
<pre><code class="language-js">export function toCamelCase(str: string): string {
  return str.replace(/([-_][a-z])/g, (group) =&gt; group.toUpperCase().replace(&#39;-&#39;, &#39;&#39;).replace(&#39;_&#39;, &#39;&#39;));
}

export function rowToCamelCase(row: any): any {
  const newRow: any = {};
  for (const key in row) {
    const camelKey = toCamelCase(key);
    newRow[camelKey] = row[key];
  }
  return newRow;
}</code></pre>
<h2 id="부록">부록</h2>
<p>&#39;엔티티&#39;와 &#39;DTO&#39;에 대해 간략히 설명하자면, &#39;엔티티&#39;는 DB에 저장되거나 DB로부터 검색되는 실제 데이터를 나타냅니다. 데이터베이스 테이블에 매핑되는 모습으로 이해하면 쉽습니다. </p>
<p>반면에 &#39;DTO(Data Transfer Object)&#39;는 계층 간 데이터를 전송하기 위해 사용되는 객체입니다. DTO는 엔티티의 데이터를 효율적이고 안전하게 전송하기 위해 사용됩니다. 엔티티에서 가져온 데이터를 필요에 따라 결합하거나 변형시킬 수 있으며, 클라이언트가 원하는 형태의 데이터로 전달할 수 있습니다. </p>
<p>따라서, &#39;엔티티&#39;는 내부 도메인 로직을 처리하고 데이터베이스와 상호작용하는 반면, &#39;DTO&#39;는 엔티티를 전달하거나 전송하기 위한 목적으로 사용됩니다.</p>
<hr>
<p>Entity, DAO, DTO의 대해서도 추후에 자세하게 정리하도록 하겠습니다.</p>
<p>이 내용이 다른 분들에게도 도움이 되길 바랍니다. 다음에는 다른 주제로 만나요!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Programmers lv.1 기사단원의 무기(JS)]]></title>
            <link>https://velog.io/@hmesan_93/Programmers-lv.1-%EA%B8%B0%EC%82%AC%EB%8B%A8%EC%9B%90%EC%9D%98-%EB%AC%B4%EA%B8%B0JS</link>
            <guid>https://velog.io/@hmesan_93/Programmers-lv.1-%EA%B8%B0%EC%82%AC%EB%8B%A8%EC%9B%90%EC%9D%98-%EB%AC%B4%EA%B8%B0JS</guid>
            <pubDate>Tue, 27 Jun 2023 13:45:16 GMT</pubDate>
            <description><![CDATA[<h1 id="기사단원의-무기">기사단원의 무기</h1>
<h2 id="문제-설명">문제 설명</h2>
<p>숫자나라 기사단의 각 기사에게는 1번부터 <code>number</code>까지 번호가 지정되어 있습니다. 기사들은 무기점에서 무기를 구매하려고 합니다.
각 기사는 자신의 기사 번호의 약수 개수에 해당하는 공격력을 가진 무기를 구매하려 합니다. 단, 이웃나라와의 협약에 의해 공격력의 제한수치를 정하고, 제한수치보다 큰 공격력을 가진 무기를 구매해야 하는 기사는 협약기관에서 정한 공격력을 가지는 무기를 구매해야 합니다.</p>
<p>예를 들어, 15번으로 지정된 기사단원은 15의 약수가 1, 3, 5, 15로 4개 이므로, 공격력이 4인 무기를 구매합니다. 만약, 이웃나라와의 협약으로 정해진 공격력의 제한수치가 3이고 제한수치를 초과한 기사가 사용할 무기의 공격력이 2라면, 15번으로 지정된 기사단원은 무기점에서 공격력이 2인 무기를 구매합니다. 무기를 만들 때, 무기의 공격력 1당 1kg의 철이 필요합니다. 그래서 무기점에서 무기를 모두 만들기 위해 필요한 철의 무게를 미리 계산하려 합니다.</p>
<p>기사단원의 수를 나타내는 정수 <code>number</code>와 이웃나라와 협약으로 정해진 공격력의 제한수치를 나타내는 정수 <code>limit</code>와 제한수치를 초과한 기사가 사용할 무기의 공격력을 나타내는 정수 <code>power</code>가 주어졌을 때, 무기점의 주인이 무기를 모두 만들기 위해 필요한 철의 무게를 return 하는 solution 함수를 완성하시오.</p>
<h2 id="제한사항">제한사항</h2>
<ul>
<li>1 ≤ number ≤ 100,000</li>
<li>2 ≤ limit ≤ 100</li>
<li>1 ≤ power ≤ limit</li>
</ul>
<h2 id="입출력-예">입출력 예</h2>
<table>
<thead>
<tr>
<th>number</th>
<th>limit</th>
<th>power</th>
<th>result</th>
</tr>
</thead>
<tbody><tr>
<td>5</td>
<td>3</td>
<td>2</td>
<td>10</td>
</tr>
<tr>
<td>10</td>
<td>3</td>
<td>2</td>
<td>21</td>
</tr>
</tbody></table>
<h3 id="문제풀이">문제풀이</h3>
<p>number는 기사단의 수, limit은 공격력의 제한치, power는 제한치를 초과했을 때의 부여받는 공격력입니다. number 주어졌을때 1부터 number까지의 각 해당하는 숫자의 약수의 개수만큼의 공격력이 주어지고 만약 limit을 초과한다면 power 만큼의 공격력이 주어진다는 뜻입니다.</p>
<pre><code class="language-js">function solution(number, limit, power) {
    let arr = []
    for(i = 1; i &lt; number + 1; i++){
        let count = 0
        for(j = 1; j &lt;= i / 2; j++){
            if(i % j === 0){
                count = count + 1
            }
        }
        if(count + 1 &gt; limit){
            arr.push(power)
        }
        else{
            arr.push(count + 1)
        }
    }
    const answer = arr.reduce((acc,cur) =&gt; {
        return acc + cur;
    })
    return answer
}</code></pre>
<p>number까지의 기사 번호에 해당하는 기사들의 공격력을 구하기 위해서 이중 for문을 사용하여 약수의 갯수를 구합니다. 하지만 약수의 개수를 구할때 절반의 크기까지만 확인을 했어요. 왜냐하면 이 문제의 조건에서 원래의 크기까지 확인하여 구한다면 효율성이 너무 떨어져 시간초과가 나기 때문입니다.
어떤 숫자 n의 약수는 1부터 n/2까지의 수 중에서 n을 나누었을 때 나머지가 0인 수들과 n 자신밖에 없어요. 그래서 n/2보다 큰 수들은 n의 약수가 될 수 없기 때문에 절반까지만 확인을 했습니다.</p>
<p>count에 +1을 해준 이유는 n이라는, 즉 자신이 약수인지에 대한 것이 누락되었기 때문에 이것을 포함시키기 위해서 그렇습니다.
10을 예로 든다면, 약수는 1,2,5,10 인데 절반에 해당하는 수까지만 약수를 구하면 1,2,5에 대한 갯수만 카운트하기 때문에 10을 포함하기위해서 +1을 해줘야합니다. 이렇게 해야 약수의 갯수를 정확하게 측정할 수 있어요.</p>
<p>그렇게 배열에 다 담은 값들을 reduce를 이용해서 전체 합을 구하고 그 값을 리턴합니다.</p>
<h2 id="시간초과-문제">시간초과 문제...?</h2>
<pre><code class="language-js">function solution(number, limit, power) {
    let answer = 0;
    for(let i = 1; i &lt;= number; i++){
        let count = 0;
        for(let j = 1; j &lt;= i / 2; j++){
            // 절반까지의 크기에 대한 약수의 갯수를 구하고 있다.
            if(i % j === 0){
                // 절반이 되기전 자신도 포함시켜야 하기때문에 구해진 약수의 갯수에 1을 더한다.
                count = count + 1
            }
        }
        if(count + 1 &gt; limit){
            // 공격력이 제한수치를 넘으면 power로 대치.
            answer = answer + power
        }else{
            // 제한수치를 넘지 않으면 자신의 약수의 갯수가 공격력.
            answer = answer + (count + 1)
        }
    }

    return answer
}</code></pre>
<p>몇번 다시 코드 제출을 했을 때 3개~4개정도 테스트케이스가 시간초과로 통과가 안되는 경우가 있었습니다. 그래서 마지막에 reduce 함수로 공격력의 합을 구하는 것이 아니라 배열을 사용하지 않고 그때그때 for문 안에서 공격력들을 더해주는 방식으로 수정하였습니다.
일단 조금 더 안정적으로 모든 케이스에 대해서 통과는 했지만 효율성이 좋다고 말하는 코드는 아닌 것 같다는 생각이 듭니다.
조금 더 생각해보고 다른 사람들의 풀이를 보면서 조금 더 좋은 방법에 대해서 찾아볼 예정입니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Programmers lv.1 명예의 전당(1)(JS)]]></title>
            <link>https://velog.io/@hmesan_93/Programmers-lv.1-%EB%AA%85%EC%98%88%EC%9D%98-%EC%A0%84%EB%8B%B91JS</link>
            <guid>https://velog.io/@hmesan_93/Programmers-lv.1-%EB%AA%85%EC%98%88%EC%9D%98-%EC%A0%84%EB%8B%B91JS</guid>
            <pubDate>Tue, 27 Jun 2023 11:36:49 GMT</pubDate>
            <description><![CDATA[<h2 id="문제-설명">문제 설명</h2>
<p>&quot;명예의 전당&quot;이라는 TV 프로그램에서는 매일 1명의 가수가 노래를 부르고, 시청자들의 문자 투표수로 가수에게 점수를 부여합니다. 매일 출연한 가수의 점수가 지금까지 출연 가수들의 점수 중 상위 k번째 이내이면 해당 가수의 점수를 명예의 전당이라는 목록에 올려 기념합니다. 즉 프로그램 시작 이후 초기에 k일까지는 모든 출연 가수의 점수가 명예의 전당에 오르게 됩니다. k일 다음부터는 출연 가수의 점수가 기존의 명예의 전당 목록의 k번째 순위의 가수 점수보다 더 높으면, 출연 가수의 점수가 명예의 전당에 오르게 되고 기존의 k번째 순위의 점수는 명예의 전당에서 내려오게 됩니다.</p>
<p>이 프로그램에서는 매일 &quot;명예의 전당&quot;의 최하위 점수를 발표합니다. 예를 들어, k = 3이고, 7일 동안 진행된 가수의 점수가 [10, 100, 20, 150, 1, 100, 200]이라면, 명예의 전당에서 발표된 점수는 아래의 그림과 같이 [10, 10, 10, 20, 20, 100, 100]입니다.</p>
<p>명예의 전당 목록의 점수의 개수 k, 1일부터 마지막 날까지 출연한 가수들의 점수인 score가 주어졌을 때, 매일 발표된 명예의 전당의 최하위 점수를 return하는 solution 함수를 완성해주세요.</p>
<h2 id="제한사항">제한사항</h2>
<ul>
<li>3 ≤ k ≤ 100</li>
<li>7 ≤ score의 길이 ≤ 1,000</li>
<li>0 ≤ score[i] ≤ 2,000</li>
</ul>
<h2 id="입출력-예">입출력 예</h2>
<table>
<thead>
<tr>
<th>k</th>
<th>score</th>
<th>result</th>
</tr>
</thead>
<tbody><tr>
<td>3</td>
<td>[10, 100, 20, 150, 1, 100, 200]</td>
<td>[10, 10, 10, 20, 20, 100, 100]</td>
</tr>
<tr>
<td>4</td>
<td>[0, 300, 40, 300, 20, 70, 150, 50, 500, 1000]</td>
<td>[0, 0, 0, 0, 20, 40, 70, 70, 150, 300]</td>
</tr>
</tbody></table>
<hr>
<h3 id="문제-풀이">문제 풀이</h3>
<p>문제의 핵심은 k번째 이후 날부터 가장 점수가 높은사람부터 나열해서 k번째에 해당하는 사람의 점수를 리턴하는 것입니다.</p>
<pre><code class="language-js">function solution(k, score) {
    var answer = [];
    var arr = [];
    for(var i = 0; i &lt; score.length; i++){
        arr.push(score[i]);
        arr.sort((a, b) =&gt; b - a);
        if(i &gt;= k) arr.pop();
        answer.push(arr[arr.length - 1]);
    }
    return answer;
}</code></pre>
<p>다른 배열에 현재 순회하고있는 인덱스에 해당하는 요소들을 담았고 계속해서 정렬을 해주었습니다. 그 이유는 순위를 매겨서 k번째에 해당하는 값을 리턴하는 것이기 때문입니다.여기서 k번째는 결국 배열의 마지막 요소가 될 것이기 때문입니다.
다시 정리하자면, 요소를 하나씩 탐색할때마다 배열에 담고 정렬을 매번 해주었고 만약 k번째일 이후의 인덱스부터는 pop을 해줌으로써 k번째의 순위, 즉 꼴찌가 배열의 마지막 요소가 될 수 있도록 해주었어요. 그리고 배열의 마지막 요소가 결국 k번째순위(꼴찌) 이기 때문에 이 값들을 answer배열에 담아주었습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Programmers lv.1 가장 가까운 같은 글자(JS)]]></title>
            <link>https://velog.io/@hmesan_93/Programmers-lv.1-%EA%B0%80%EC%9E%A5-%EA%B0%80%EA%B9%8C%EC%9A%B4-%EA%B0%99%EC%9D%80-%EA%B8%80%EC%9E%90</link>
            <guid>https://velog.io/@hmesan_93/Programmers-lv.1-%EA%B0%80%EC%9E%A5-%EA%B0%80%EA%B9%8C%EC%9A%B4-%EA%B0%99%EC%9D%80-%EA%B8%80%EC%9E%90</guid>
            <pubDate>Tue, 27 Jun 2023 08:26:30 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<p>문자열 <code>s</code>가 주어졌을 때, <code>s</code>의 각 위치마다 자신보다 앞에 나왔으면서, 자신과 가장 가까운 곳에 있는 같은 글자가 어디 있는지 알고 싶습니다.</p>
<p>예를 들어, <code>s=&quot;banana&quot;</code>라고 할 때,  각 글자들을 왼쪽부터 오른쪽으로 읽어 나가면서 다음과 같이 진행할 수 있습니다.</p>
<ol>
<li><code>b</code>는 처음 나왔기 때문에 자신의 앞에 같은 글자가 없습니다. 이는 <code>-1</code>로 표현합니다.</li>
<li><code>a</code>는 처음 나왔기 때문에 자신의 앞에 같은 글자가 없습니다. 이는 <code>-1</code>로 표현합니다.</li>
<li><code>n</code>은 처음 나왔기 때문에 자신의 앞에 같은 글자가 없습니다. 이는 <code>-1</code>로 표현합니다.</li>
<li><code>a</code>는 자신보다 두 칸 앞에 <code>a</code>가 있습니다. 이는 <code>2</code>로 표현합니다.</li>
<li><code>n</code>도 자신보다 두 칸 앞에 <code>n</code>이 있습니다. 이는 <code>2</code>로 표현합니다.</li>
<li><code>a</code>는 자신보다 두 칸, 네 칸 앞에 <code>a</code>가 있습니다. 이 중 가까운 것은 두 칸 앞이고, 이는 <code>2</code>로 표현합니다.</li>
</ol>
<p>따라서 최종 결과물은 <code>[-1, -1, -1, 2, 2, 2]</code>가 됩니다.</p>
<p>문자열 <code>s</code>이 주어질 때, 위와 같이 정의된 연산을 수행하는 함수 <code>solution</code>을 완성해주세요.</p>
<hr>
<h3 id="제한사항">제한사항</h3>
<ul>
<li>1 ≤ <code>s</code>의 길이 ≤ 10,000</li>
<li><code>s</code>은 영어 소문자로만 이루어져 있습니다.</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>
<tr>
<td>---</td>
<td></td>
</tr>
<tr>
<td>정리하자면 해당하는 인덱스의 문자와 똑같은 문자가 몇칸 앞에 존재하는가?가 문제 풀이의 핵심입니다. 존재한다면 떨어져있는 칸 수의 크기를 배열에 담아주면 되고 만약 해당하는 문자와 같은 문자가 없다면 -1을 담아주면 됩니다.</td>
<td></td>
</tr>
<tr>
<td>그리고 같은 문자가 여러개 있다면 먼저 발견한 문자의 거리만 고려합니다.</td>
<td></td>
</tr>
<tr>
<td>### 풀이코드</td>
<td></td>
</tr>
<tr>
<td>```js</td>
<td></td>
</tr>
<tr>
<td>function solution(s) {</td>
<td></td>
</tr>
<tr>
<td>var answer = [];</td>
<td></td>
</tr>
<tr>
<td>var arr = [-1];</td>
<td></td>
</tr>
<tr>
<td>let count;</td>
<td></td>
</tr>
<tr>
<td>for(i = 0; i &lt; s.length; i++){</td>
<td></td>
</tr>
<tr>
<td>count = 0</td>
<td></td>
</tr>
<tr>
<td>for(j = arr.length - 1; j &gt;= 0; j--){</td>
<td></td>
</tr>
<tr>
<td>count++</td>
<td></td>
</tr>
<tr>
<td>if(arr[j] === s[i]){</td>
<td></td>
</tr>
<tr>
<td>answer.push(count)</td>
<td></td>
</tr>
<tr>
<td>break;</td>
<td></td>
</tr>
<tr>
<td>}</td>
<td></td>
</tr>
<tr>
<td>if(j === 0){</td>
<td></td>
</tr>
<tr>
<td>answer.push(-1)</td>
<td></td>
</tr>
<tr>
<td>}</td>
<td></td>
</tr>
<tr>
<td>}</td>
<td></td>
</tr>
<tr>
<td>arr.push(s[i])</td>
<td></td>
</tr>
<tr>
<td>}</td>
<td></td>
</tr>
<tr>
<td>return answer;</td>
<td></td>
</tr>
<tr>
<td>}</td>
<td></td>
</tr>
<tr>
<td>```</td>
<td></td>
</tr>
<tr>
<td>먼저 -1을 담고 있는 배열을 하나 만들고 count 변수를 선언한 뒤에 풀이를 시작합니다. -1을 넣은 이유는 문자열의 첫 번째 인덱스에 해당하는 문자는 가장 처음 나오는 문자이기 때문에, 자신보다 앞의 인덱스는 존재하지 않기 때문입니다.그리고 count 변수를 선언해준 이유는 자신이랑 같은 문자가 얼마나 떨어져있는 지를 계산하기 위해서 입니다.</td>
<td></td>
</tr>
</tbody></table>
<p>문자열을 하나씩 순회하면서 자신이랑 같은 문자가 얼마나 떨어져있는 가를 계산하기 위해서 count 변수를 선언해주었습니다.</p>
<p>이제, 하나씩 순회하면서 탐색이 끝난 인덱스는 -1을 담고 있는 배열에 push 해주었습니다. 그 이유는 이중 for문에서 임의로 만든 배열을 탐색하면서, 뒤에서부터 탐색하여 현재 인덱스와 같은 문자가 몇 칸 떨어져 있는지 계산하기 위해서입니다.</p>
<p>그리고 자신과 같은 문자를 발견하면 계산된 count(몇칸 떨어져있는지)를 answer 배열에 담아주었고 break를 사용하여 이중for문의 탐색을 종료해주었습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[회고] 엘리스 트랙후기]]></title>
            <link>https://velog.io/@hmesan_93/%ED%9A%8C%EA%B3%A0-%EC%97%98%EB%A6%AC%EC%8A%A4-%ED%8A%B8%EB%9E%99%ED%9B%84%EA%B8%B0</link>
            <guid>https://velog.io/@hmesan_93/%ED%9A%8C%EA%B3%A0-%EC%97%98%EB%A6%AC%EC%8A%A4-%ED%8A%B8%EB%9E%99%ED%9B%84%EA%B8%B0</guid>
            <pubDate>Fri, 23 Jun 2023 23:47:22 GMT</pubDate>
            <description><![CDATA[<h3 id="회고-엘리스-부트캠프-개발-교육과정을-마무리하며">회고: 엘리스 부트캠프 개발 교육과정을 마무리하며</h3>
<p>안녕하세요, 여러분! 오늘은 엘리스 부트캠프 개발 교육과정을 마무리하면서 느낀 점을 공유하고자 합니다. 이번 과정은 저에게 많은 것을 가르쳐주었고, 앞으로의 개발자로서의 삶에 큰 도움이 될 것이라 믿습니다.</p>
<p>왜 엘리스 SW4 엔지니어 트랙을 선택했는지는 다음과 같습니다. 제가 이미 개발 공부를 시작한 적은 있었지만, 엘리스 트랙은 이론 커리큘럼과 실시간 강의의 구성이 매우 마음에 들어서 선택하게 되었습니다. 기존에 알고 있던 지식에 더하여 훨씬 더 많은 것을 배울 수 있었고, 강의에서는 주입식 학습보다는 <strong>스스로 생각하고 로직을 짜보는 방식을 중심으로 진행</strong>되었습니다. 이러한 방식은 개발 능력 향상에 큰 도움이 되었다고 느껴졌습니다.</p>
<p>엔지니어 트랙은 주로 프론트엔드에 초점을 맞추고 있었지만, 웹 개발을 하기 위해 필요한 웹 통신의 전반적인 흐름을 파악할 수 있는 지식들을 습득할 수 있었습니다. 실무에서 활동하시는 코치 분들의 실시간 강의는 큰 장점 중 하나였습니다. 그들은 현업에서 실제로 사용되는 방식이나 최신 기술들을 가르쳐주셨고, 혼자서는 이해하기 어려운 개념들을 쉽게 이해할 수 있었습니다. 예를 들면 REST API, CRUD, HTTP 통신, 아키텍처 패턴 등을 배웠습니다.</p>
<p>특히 JavaScript를 주로 다루었기 때문에 Node.js도 함께 배울 수 있어서 <strong>프론트뿐만 아니라 백엔드 관련 공부</strong>도 많이 할 수 있었습니다. 이러한 영향으로 인해 프로젝트의 1차와 2차에서는 백엔드 개발을 담당했었습니다. 그러나 제가 생각하는 <strong>개발자는 단순히 프론트와 백으로 나눠져 있는 것이 아닙니다. 기본적인 풀스택 개념을 알고 있는 상태에서 어떤 것을 선택하느냐가 중요</strong>하다고 생각합니다.</p>
<p>이 과정을 통해 어떻게 공부해야 하는지, 여러 사람들과 어떻게 협업하고 소통해야 하는지에 대한 많은 것을 배웠습니다. 이번 과정은 코딩을 처음 시작하는 분들에게도 적극 추천하고 싶습니다. 물론 의지만으로는 부족하며, 부단한 노력이 필요합니다. 꾸준한 학습과 개발 열정이 가장 중요하다고 생각합니다.</p>
<p>4개월이라는 기간이 금방 지나갔습니다. 함께 수료한 모든 분들, 특히 프로젝트와 스터디를 함께했던 동료들을 현업에서 만나길 기원합니다.</p>
<p>엘리스 부트캠프 개발 교육과정을 마무리하면서 느낀 점을 공유해보았습니다. 이번 경험은 저에게 많은 것을 가르쳐주었고, 앞으로의 개발자로서의 삶에 좋은 발판이 되었다고 생각합니다.</p>
<p>감사합니다!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[스택/큐] Programmers lv.2 프로세스(python)]]></title>
            <link>https://velog.io/@hmesan_93/%EC%8A%A4%ED%83%9D%ED%81%90-Programmers-lv.2-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4python</link>
            <guid>https://velog.io/@hmesan_93/%EC%8A%A4%ED%83%9D%ED%81%90-Programmers-lv.2-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4python</guid>
            <pubDate>Fri, 19 May 2023 05:20:23 GMT</pubDate>
            <description><![CDATA[<h2 id="문제-설명"><strong>문제 설명</strong></h2>
<p>운영체제의 역할 중 하나는 컴퓨터 시스템의 자원을 효율적으로 관리하는 것입니다. 이 문제에서는 운영체제가 다음 규칙에 따라 프로세스를 관리할 경우 특정 프로세스가 몇 번째로 실행되는지 알아내는 문제입니다.</p>
<ol>
<li>실행 대기 큐(Queue)에서 대기 중인 프로세스 하나를 꺼냅니다.</li>
<li>큐에 대기 중인 프로세스 중 우선순위가 더 높은 프로세스가 있다면 방금 꺼낸 프로세스를 다시 큐에 넣습니다.</li>
<li>만약 그런 프로세스가 없다면 방금 꺼낸 프로세스를 실행합니다.</li>
<li>1 한 번 실행한 프로세스는 다시 큐에 넣지 않고 그대로 종료됩니다.</li>
</ol>
<p>예를 들어 프로세스 4개 [A, B, C, D]가 순서대로 실행 대기 큐에 들어있고, 우선순위가 [2, 1, 3, 2]라면 [C, D, A, B] 순으로 실행하게 됩니다.</p>
<p>이때, 현재 실행 대기 큐(Queue)에 있는 프로세스의 중요도가 순서대로 담긴 배열 <strong><code>priorities</code></strong>와, 몇 번째로 실행되는지 알고싶은 프로세스의 위치를 알려주는 <strong><code>location</code></strong>이 매개변수로 주어집니다. 해당 프로세스가 몇 번째로 실행되는지를 반환하는 함수 <strong><code>solution</code></strong>을 작성해야 합니다.</p>
<h2 id="제한사항"><strong>제한사항</strong></h2>
<ul>
<li><strong><code>priorities</code></strong>의 길이는 1 이상 100 이하입니다.</li>
<li><strong><code>priorities</code></strong>의 원소는 1 이상 9 이하의 정수입니다.</li>
<li><strong><code>priorities</code></strong>의 원소는 우선순위를 나타내며 숫자가 클수록 우선순위가 높습니다.</li>
<li><strong><code>location</code></strong>은 0 이상 (대기 큐에 있는 프로세스 수 - 1) 이하의 값을 가집니다.</li>
<li><strong><code>priorities</code></strong>의 가장 앞에 있으면 0, 두 번째에 있으면 1과 같이 표현합니다.</li>
</ul>
<h2 id="입출력-예"><strong>입출력 예</strong></h2>
<table>
<thead>
<tr>
<th>priorities</th>
<th>location</th>
<th>return</th>
</tr>
</thead>
<tbody><tr>
<td>[2, 1, 3, 2]</td>
<td>2</td>
<td>1</td>
</tr>
<tr>
<td>[1, 1, 9, 1, 1, 1]</td>
<td>0</td>
<td>5</td>
</tr>
</tbody></table>
<pre><code class="language-python">from collections import deque
def solution(priorities, location):
    queue = []
    answer = 0
    # 왼쪽부터 실행되는데 만약 더 우선순위 높은 프로세스가 있다면 다시 큐에 넣는다.
    for i,prior in enumerate(priorities):
        # 튜플 요소(우선순위)랑 인덱스 같이 저장한다.
        queue.append((prior,i))
    dq = deque(queue)
    while len(dq) &gt; 0: 
        # 만약 우선순위 높은 애가 나간다면 그다음 높은애로 최댓값을 갱신해줘야 함
        maxPriority = max(dq, key=lambda x: x[0])
        # 실행된 애가 maxPriority면 실행해버리고 아니면 큐의 맨 끝으로 다시 넣는다.
        # 어차피 0인덱스로 해도 큐니까 계속 첫번째애가 바뀜
        # 그리고 지금 실행되는 요소가 location 인덱스의 요소 ,그러니까 구해야 하는 요소와 같은지 확인
        if dq[0][0] == maxPriority[0]: # 실행될 애가 우선순위가 가장 높은 애라면
            if dq[0][1] == location:
                answer = answer + 1
                return answer
            else:
                answer = answer + 1
                dq.popleft()

        # 실행될 요소가 최댓값이 아니라면
        else:
            dq.append(dq.popleft()) # 빼자마자 넣는다. 
</code></pre>
<p>-&gt; 입출력 예를 보면 2번쨰 예시 priorities가 [1,1,9,1,1,1] 일 때 location이 0인 요소 즉 첫번째 요소인 1이 꺼내지고 실행이 안되었을 때 다시 큐로 삽입이 되는데 어떻게 지금 들어간 1이 location 인덱스에 1이라는 걸 증명하는 가에 대해 많은 고민을 했다. 그러다가 flag가 있으면 좋겠다고 생각하고 결국 객체, 즉 튜플자료형을 사용하기로 하였고, 인덱스를 기억해놓으면 되겠다라는 점에 포인트를 두고 문제를 풀었다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[얕은 복사 & 깊은 복사]]></title>
            <link>https://velog.io/@hmesan_93/%EC%96%95%EC%9D%80-%EB%B3%B5%EC%82%AC-%EA%B9%8A%EC%9D%80-%EB%B3%B5%EC%82%AC</link>
            <guid>https://velog.io/@hmesan_93/%EC%96%95%EC%9D%80-%EB%B3%B5%EC%82%AC-%EA%B9%8A%EC%9D%80-%EB%B3%B5%EC%82%AC</guid>
            <pubDate>Fri, 24 Mar 2023 05:41:22 GMT</pubDate>
            <description><![CDATA[<h3 id="개요">개요</h3>
<p>깊은 복사 &amp; 얕은 복사 이야기를 하기전에 먼저 자바스크립트의 데이터타입에 대해서 설명하려고 합니다.</p>
<p>자바스크립트가 제공하는 7가지 데이터 타입은 크게 원시 타입과 객체 타입으로 구분 할 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/hmesan_93/post/57cd4ff5-17c6-47b2-b05a-ff02b8cbbc62/image.png" alt=""></p>
<p>이 두 가지 타입은 크게 세가지 측면에서 다릅니다.</p>
<ol>
<li><p>원시 타입의 값, 즉 원시 값은 변경 불가능한 값이다. 이에 비해 객체 타입의 값, 즉 객체는 변경 가능한 값이다.</p>
</li>
<li><p>원시 값을 변수에 할당하면 변수에는 실제 값이 저장된다. 이에 비해 객체를 변수에 할당하면 변수에는 참조 값이 저장된다.</p>
</li>
<li><p>원시 값을 갖는 변수를 다른 변수에 할당하면 원본의 원시 값이 복사되어 전달된다. 이를 <strong>값에 의한 전달</strong>이라 한다. 이에 비해 객체를 가리키는 변수를 다른 변수에 할당하면 원본의 참조 값이 복사되어 전달된다. 이를 <strong>참조에 의한 전달</strong>이라 한다. </p>
</li>
</ol>
<p>값에 의한 전달(pass by value)와 참조에 의한 전달(pass by reference) 이 두가지 키워드에 집중하시면 됩니다.</p>
<p>여기서 &quot;원시 값은 변경 불가능한 값이다&quot;라고 하는데 이 말은 원시 값 자체를 변경 할 수 없다는 것이고 변수에 재할당을 할 수 없다는 것은 아닙니다.
변수는 재할당을 통해 언제든지 변경할 수 있습니다.</p>
<p>간단히 설명을 마쳤으니 본격적으로 얕은 복사와 깊은 복사의 예시를 보여드리겠습니다.</p>
<hr>
<h3 id="값에-의한-전달-얕은-복사">값에 의한 전달 (얕은 복사)</h3>
<pre><code class="language-jsx">var score = 80;
var copy = score;

console.log(score); // 80
console.log(copy); // 80

score = 100;

console.log(score); // 100
console.log(copy); // ?</code></pre>
<p>? 에 들어갈 정답은 80입니다.
<code>copy = score;</code> 에서 score는 변수값 80으로 평가되므로 copy 변수에도 80이 할당될 것입니다. 이때 새로운 숫자 값 80이 생성되어 copy 변수에 할당됩니다.</p>
<p>새로운 숫자 80이 생성된다는 것은 다른 메모리 공간에 80이라는 값이 할당이 된다는 것입니다. 두 개의 80이라는 값이 각각 다른 메모리 공간을 차지하고 있다고 보시면 됩니다.</p>
<p>이처럼 변수에 원시 값을 갖는 변수를 할당하면 할당받는 변수에는 할당되는 변수의 원시 값이 복사되어 전달된다. 이를 <strong>값에 의한 전달</strong>이라 한다.</p>
<p><img src="https://velog.velcdn.com/images/hmesan_93/post/1b35904e-e211-4092-bbaa-799b5471ddb0/image.png" alt=""></p>
<h3 id="참조에-의한-전달깊은-복사">참조에 의한 전달(깊은 복사)</h3>
<p>객체를 가리키는 변수를 다른 변수에 할당하면 원본의 참조 값이 복사되어서(pass by reference) 전달이 됩니다.
예시와 함께 보시겠습니다.</p>
<pre><code class="language-jsx">var person = {
  name: &#39;Lee&#39;
};

// 참조값을 복사(얕은 복사). copy와 person은 동일한 참조값을 갖는다.
var copy = person;

// copy와 person은 동일한 객체를 참조한다.
console.log(copy === person); // true

// copy를 통해 객체를 변경한다.
copy.name = &#39;Kim&#39;;

// person을 통해 객체를 변경한다.
person.address = &#39;Seoul&#39;;

// copy와 person은 동일한 객체를 가리킨다.
// 따라서 어느 한쪽에서 객체를 변경하면 서로 영향을 주고 받는다.
console.log(person); // {name: &quot;Kim&quot;, address: &quot;Seoul&quot;}
console.log(copy);   // {name: &quot;Kim&quot;, address: &quot;Seoul&quot;}</code></pre>
<p>원시값을 할당한 변수는 원시 값 자체를 값으로 갖는다고 위에서 설명하였습니다. 하지만 <code>copy = person;</code> 에서 copy변수에는 person의 변수에 할당된 값이 아닌 person이 가리키고 있는 참조 값을 할당합니다.
따라서 copy와 person 두개의 변수는 같은 메모리 주소를 가리키고 있고 같은 객체를 참조하고 있습니다.</p>
<p>이것을 <strong>참조에 의한 전달</strong>이라고 합니다.
그러므로 만약 어느 한쪽에서 객체의 값을 동적으로 변경한다면 서로 같은 객체를 참조하고 있기 때문에 서로 영향을 주고 받는 것입니다.</p>
<hr>
<h3 id="정리">정리</h3>
<p>결국 &quot;값에 의한 전달&quot;과 &quot;참조에 의한 전달&quot;은 식별자가 기억하는 메모리 공간에 저장되어 있는 값을 복사해서 전달한다는 면에서는 동일합니다. 다만 변수에 저장되어 있는 값이 값이냐,참조값이냐의 차이만 있을 뿐입니다.</p>
<p>따라서 이뜻을 놓고 보았을 때는 자바스크립트에서는 &quot;값에 의한 전달&quot;만 존재한다고 말할 수 있습니다. 참조값도 값이니까요.</p>
<p>크게 나누었을때 자바스크립트의 데이터 타입 두 가지를 예로 들어서 얕은 복사와 깊은 복사를 설명해보았습니다.</p>
<p>도움이 되셨다면 좋겠습니다.감사합니다.</p>
<p><em>참조 문서 : &#39;모던 자바스크립트 Deep Dive&#39;</em></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[호이스팅, var, let, const 차이]]></title>
            <link>https://velog.io/@hmesan_93/%ED%98%B8%EC%9D%B4%EC%8A%A4%ED%8C%85-var-let-const-%EC%B0%A8%EC%9D%B4</link>
            <guid>https://velog.io/@hmesan_93/%ED%98%B8%EC%9D%B4%EC%8A%A4%ED%8C%85-var-let-const-%EC%B0%A8%EC%9D%B4</guid>
            <pubDate>Tue, 21 Mar 2023 15:37:42 GMT</pubDate>
            <description><![CDATA[<h1 id="호이스팅">호이스팅</h1>
<h2 id="변수-선언의-실행-시점과-변수-호이스팅">변수 선언의 실행 시점과 변수 호이스팅</h2>
<pre><code class="language-jsx">console.log(score); // undefined

var score; // 변수 선언문</code></pre>
<p>위의 예제를 보면 변수 선언문보다 변수를 참조하는 코드가 앞에 있다. 자바스크립트 코드는 인터프리터에 의해 한줄씩 순차적으로 실행되므로 <code>console.log(score);</code> 가 가장 먼저 실행되고 순차적으로 다음 줄에 있는 <code>var scroe;</code>를 실행한다. 따라서 <code>console.log(score);</code> 가 실행되는 시점에는 score 변수의 선언이 실행되지 않았으므로 참조 에러가 발생할 것으로 보인다. 하지만 참조 에러가 발생하지 않고 undefined가 출력된다. </p>
<p>그 이유는 변수 선언이 소스코드가 한 줄씩 순차적으로 실행되는 시점, 즉 런타임이 아니라 그 이전 단계에서 먼저 실행되기 때문이다. </p>
<p>자바스크립트 엔진은 소스코드를 한 줄씩 순차적으로 실행하기에 앞서 먼저 소스코드의 평가 과정을 거치면서 소스코드를 실행하기 위한 준비를 한다. 이때 소스코드 실행을 준비 단계인 소스코드의 평가 과정에서 자바스크립트 엔진은 변수 선언을 포함한 모든 선언문을 소스코드에서 찾아서 먼저 실행한다. 그리고 소스코드의 평가 과정이끝나면 비로소 변수 선언을 포함한 모든 선언문을 제외하고 소스 코드를 한 줄씩 순차적으로 실행한다. </p>
<p>즉, 자바스크립트 엔진은 변수 선언이 소스코드의 어디에 있든 상관없이 다른 코드보다 먼저 실행된다. 따라서 변수 선언이 소스코드의 어디에 위치하는지와 상관없이 어디서든지 변수를 참조할 수 있다. </p>
<p>위의 예제는 변수 선언이 소스코드가 순차적으로 실행되는 런타임 이전 단계에서 먼저 실행된다는 증거이다.  이처럼 변수 선언문이 코드의 선두로 끌어 올려진 것처럼 동작하는 자바스크립트 고유의 특징을 변수 호이스팅이라 한다.</p>
<p>사실 변수 선언뿐 아니라 var, let, const, function, function*, class 키워드를 사용해서 선언하는 모든 식별자는 호이스팅된다.</p>
<h1 id="var-let-const-차이">var, let, const 차이</h1>
<p>var는 함수레벨 스코프를 따른다.</p>
<p>중복선언 시에도 에러가 발생하지 않는다.</p>
<p>var함수를 사용하면 변수의 사용 범위가 넓어지므로 의도치않은 변수의 변경등의 문제가 발생한다.</p>
<p>그래서 ES6부터는 let, const 라는 키워드가 등장했다.</p>
<p>let, const는 블록레벨 스코프를 따르고, 변수의 중복 선언이 불가능하다.</p>
<p>let은 재할당이 가능하고, const는 재할당이 불가능하다.</p>
<p>그리고 호이스팅에서도 var와 let, const는 차이가 있다</p>
<p>var는 변수 호이스팅이 일어나면 선언과 초기화단계가 같이 일어나기때문에 변수가 실제로 선언된 위치 이전에서 변수를 호출하더라고 오류가 나지 않고 undefined가 출력된다.</p>
<p>하지만 let, const는 변수 호이스팅이 일어나긴하지만 변수의 선언과 초기화 단계가 따로 이루어지기 때문에 변수가 실제로 선언된 위치 이전에서 호출을 하게 되면 오류가 발생한다. 초기화를 하는 단계에서 메모리에 할당되는 것이기 때문에 초기화 전에 참조하면 에러가 난다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[실행 컨텍스트에 대해서]]></title>
            <link>https://velog.io/@hmesan_93/%EC%8B%A4%ED%96%89-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8%EC%97%90-%EB%8C%80%ED%95%B4%EC%84%9C</link>
            <guid>https://velog.io/@hmesan_93/%EC%8B%A4%ED%96%89-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8%EC%97%90-%EB%8C%80%ED%95%B4%EC%84%9C</guid>
            <pubDate>Tue, 21 Mar 2023 15:35:21 GMT</pubDate>
            <description><![CDATA[<h1 id="실행-컨텍스트">실행 컨텍스트</h1>
<ul>
<li>실행 컨텍스트는 쉽게 말하면 실행 환경이다.</li>
<li>실행 컨텍스트 안에 Record와 Outer가 있다.</li>
<li>자바스크립트 코드를 실행시키면 JS엔진은 콜 스택에 전역 실행컨텍스트를 담는다.</li>
<li>그리고 전역에서 함수A를 호출하면 함수 A의 실행 컨텍스트를 담는다. 이런식으로 콜 스택에 실행 컨텍스트 들이 쌓인다.</li>
<li>콜스택에서는 가장 최근에 추가된 실행 컨텍스트만 활성화 된다.</li>
<li>이렇게 함수들이 모두 종료되면서 실행 컨텍스트 들이 다 사라지고 전역이 있는 코드의 마지막 라인까지 모두 실행되면 전역 실행컨텍스트도 사라진다.</li>
</ul>
<h3 id="record-로-js-호이스팅-이해하기">Record 로 JS 호이스팅 이해하기</h3>
<pre><code class="language-jsx">console.log(TV); // undefined
// var 키워드로 선언하였기 때문에 선언과 동시에 초기화가 이루어지고 undefined로 초기화가됨

var TV = &quot;Netflix&quot;

console.log(TV) // &quot;Netflix&quot;
// 선언 라인 전에도 에러가 나지 않고 참조할 수 있는 현상을 호이스팅 이라고 한다.</code></pre>
<ul>
<li>호이스팅은 선언문이 마치 최상단에 끌어올려진 듯한 현상이다.</li>
<li>선언문이 있는 코드 라인을 물리적으로 최상단에 끌어올렸기 때문이 아니라 자바스크립트 엔진이 먼저 전체 코드를 스캔하면서 변수 같은 정보를 실행 컨텍스트 어딘가에 미리 기록해놓기 때문이다.</li>
<li>바로 실행 컨텍스트 안에 있는 Record에 기록을 해놓는다.</li>
<li>Record : 정식 명칭은 environment record (환경 레코드) 이고 식별자와 식별자에 바인딩된 값을 기록해두는 객체.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hmesan_93/post/ec662349-b34a-43d5-a338-a38129d1e18e/image.png" alt=""></p>
<ul>
<li>실행에 앞서 스캔하고 준비하는 단계를 생성 단계라고 한다. ( 실행컨텍스트를 생성하고 선언문만 실행해서 환경레코드에 기록)</li>
<li>마지막 라인인 console.log(TVChannel) 코드가 실행되게되면 JS엔진은 환경레코드를 참조해서 TVChannel의 값을 “Netflix”로 결정해 낸다.</li>
<li>var가 아닌 let이나 const로 선언했을 경우에는 선언 라인 이전에 식별자를 참조 할수가 없다.(Reference Error) → ‘일시적 사각지대’ 라고 부른다. ( 선언 이전에 식별자를 참조할 수 없는 구역 )</li>
<li>let이나 const는 선언과 동시에 초기화가 이루어지지 않기 때문에 자연스럽게 할당문 직전까지는 변수에 값이 담기지 않는다. 따라서 읽어올 수도 없다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hmesan_93/post/ca6756d8-9609-4995-b497-c7026d361be4/image.png" alt=""></p>
<ul>
<li>함수 표현식은 함수를 변수에 담고있기 때문에 변수 호이스팅과 동일하게 동작한다.</li>
<li>만약 function 키워드를 사용해 함수 선언문 방식으로 함수를 선언하는 경우에는  JS엔진이 함수 선언과 동시에 완성된 함수 객체를 생성해서 환경레코드에 기록해둔다. 따라서 함수실행코드문이 더 윗줄에 있더라도 실행이 가능하다.</li>
</ul>
<pre><code class="language-jsx">let star = &quot;twinkle&quot;

console.log(star)
// JS엔진은 현재 활성화된 실행컨텍스트의 환경 레코드를 보고 star의 값을 쉽게 찾아낸다.</code></pre>
<p>출처 : [10분 테코톡] 하루의 실행 컨텍스트 ( <a href="https://www.youtube.com/watch?v=EWfujNzSUmw">https://www.youtube.com/watch?v=EWfujNzSUmw</a> )</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[브라우저 저장소( 로컬,세션 스토리지, 쿠키 ,인덱스 DB)]]></title>
            <link>https://velog.io/@hmesan_93/%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80-%EC%A0%80%EC%9E%A5%EC%86%8C-%EB%A1%9C%EC%BB%AC%EC%84%B8%EC%85%98-%EC%8A%A4%ED%86%A0%EB%A6%AC%EC%A7%80-%EC%BF%A0%ED%82%A4-%EC%9D%B8%EB%8D%B1%EC%8A%A4-DB</link>
            <guid>https://velog.io/@hmesan_93/%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80-%EC%A0%80%EC%9E%A5%EC%86%8C-%EB%A1%9C%EC%BB%AC%EC%84%B8%EC%85%98-%EC%8A%A4%ED%86%A0%EB%A6%AC%EC%A7%80-%EC%BF%A0%ED%82%A4-%EC%9D%B8%EB%8D%B1%EC%8A%A4-DB</guid>
            <pubDate>Tue, 21 Mar 2023 15:31:50 GMT</pubDate>
            <description><![CDATA[<h2 id="웹-스토리지">웹 스토리지</h2>
<p><strong>웹 스토리지(Web Storage)</strong>는 웹 브라우저에서 데이터를 저장하는 기술로, HTML5에서 등장</p>
<ul>
<li>웹 스토리지는 클라이언트 측에서 데이터를 저장하고, 저장된 데이터는 서버와 통신하지 않고 로컬에서 사용됩니다. 이를 통해 빠르게 데이터를 접근할 수 있음</li>
</ul>
<p>웹 스토리지는 크게 두 가지 종류가 있다.</p>
<ol>
<li><strong>로컬 스토리지(</strong>Local Storage): 로컬 스토리지는 키-값 쌍으로 데이터를 저장하는 기술로, 웹 브라우저에서 영구적으로 데이터를 저장할 수 있다. 로컬 스토리지에 저장된 데이터는 브라우저가 닫혀도 유지되므로, 사용자가 다시 웹 사이트를 방문했을 때 이전 데이터를 불러와 사용할 수 있다.</li>
<li><strong>세션 스토리지</strong>(Session Storage): 세션 스토리지는 로컬 스토리지와 비슷하지만, 브라우저를 닫을 때 저장된 데이터가 삭제된다. 세션 스토리지에 저장된 데이터는 해당 브라우저 세션에서만 유효하며, 브라우저가 닫히면 삭제됩니다. 따라서, 세션 스토리지는 로그인 정보나 장바구니 등의 임시적인 데이터를 저장할 때 유용합니다.</li>
</ol>
<p>웹 스토리지는 JavaScript를 사용하여 쉽게 조작할 수 있다. 예를 들어, 로컬 스토리지에 데이터를 저장하려면 다음과 같이 코드를 작성할 수 있다.</p>
<pre><code class="language-jsx">localStorage.setItem(&#39;key&#39;, &#39;value&#39;);</code></pre>
<p>위 코드는 &#39;key&#39;라는 이름으로 &#39;value&#39;라는 값을 로컬 스토리지에 저장한다. 저장된 데이터는 다음과 같이 가져올 수 있다.</p>
<pre><code class="language-jsx">const data = localStorage.getItem(&#39;key&#39;);
console.log(data); // &quot;value&quot;</code></pre>
<p>또한, 저장된 데이터를 삭제하려면 다음과 같이 코드를 작성할 수 있다.</p>
<pre><code class="language-jsx">localStorage.removeItem(&#39;key&#39;);</code></pre>
<p>이와 같이 웹 스토리지를 사용하여 로컬 데이터를 쉽게 저장하고 관리할 수 있다.</p>
<hr>
<h3 id="쿠키">쿠키</h3>
<p>쿠키(Cookie)는 클라이언트 측에서 사용하는 작은 파일로, 브라우저에 저장되며, 해당 웹사이트를 다시 방문할 때 사용된다.</p>
<p>웹사이트는 클라이언트에게 쿠키를 전송하고, 클라이언트는 이를 브라우저에 저장한다. 이후에 같은 웹사이트를 방문할 때, 브라우저는 해당 쿠키를 웹사이트 서버에 다시 보내게 된다.</p>
<p>쿠키는 다양한 용도로 사용되며 예를 들자면, 로그인 정보나 사용자의 환경 설정을 저장하거나, 광고 추적 등에 사용될 수 있다.</p>
<p>쿠키는 일반적으로 브라우저 설정에서 사용자가 수동으로 삭제할 수 있고  웹 개발자는 쿠키의 만료 시간과 유효한 도메인을 설정하여 쿠키의 사용을 제어할 수 있다는 장점도 있다.</p>
<hr>
<h3 id="indexeddb"><strong>indexedDB</strong></h3>
<ul>
<li>웹 스토리지(Web Storage)의 일종이긴 한데  조금 다른 데이터베이스 기술이다.</li>
<li>객체 지향 데이터베이스로, 웹 브라우저에서 대규모 데이터를 저장하고 관리할 수 있다.</li>
<li>로컬에서 영구적으로 데이터를 저장할 수 있으며, 브라우저가 닫혀도 데이터를 유지할 수 있다.</li>
<li>대용량 데이터를 처리하기에 적합하며, 복잡한 데이터를 쉽게 검색하고 인덱싱할 수 있다.</li>
<li>트랜잭션도 지원한다.  트랜잭션은 데이터베이스에서 여러 개의 연속된 작업을 하나의 논리적 단위로 묶어서 실행하는 것을 말한다.</li>
</ul>
<p><strong>indexedDB</strong>를 사용하여 데이터베이스를 생성하고 데이터를 저장하는 방법은 다음과 같다.</p>
<pre><code class="language-jsx">const request = indexedDB.open(&#39;myDatabase&#39;, 1);

request.onupgradeneeded = function(event) {
  const db = event.target.result;
  const objectStore = db.createObjectStore(&#39;myObjectStore&#39;, { keyPath: &#39;id&#39; });
  objectStore.createIndex(&#39;name&#39;, &#39;name&#39;, { unique: false });
};

request.onsuccess = function(event) {
  const db = event.target.result;
  const transaction = db.transaction([&#39;myObjectStore&#39;], &#39;readwrite&#39;);
  const objectStore = transaction.objectStore(&#39;myObjectStore&#39;);
  const data = { id: 1, name: &#39;John&#39;, age: 30 };
  const request = objectStore.add(data);

  request.onsuccess = function(event) {
    console.log(&#39;Data added to the database&#39;);
  };

  transaction.oncomplete = function(event) {
    console.log(&#39;Transaction completed&#39;);
  };
};</code></pre>
<p>위 코드는 <strong>myDatabase</strong>라는 이름의 데이터베이스를 생성하고, <strong>myObjectStore</strong>라는 이름의 객체 스토어를 추가합니다. <strong>id</strong>를 기본 키로 사용하며, <strong>name</strong>을 인덱스로 추가한다.</p>
<p>그리고 데이터베이스에 <strong><code>{ id: 1, name: &#39;John&#39;, age: 30 }</code></strong>라는 데이터를 추가한다.</p>
<p><strong>indexedDB</strong>는 웹 스토리지와는 달리 JavaScript로 직접 데이터베이스를 조작해야 하기 때문에 코드가 좀 더 복잡해질 수 있다. 그러나 <strong>대규모 데이터</strong>를 다루는 경우에는 <strong>indexedDB</strong>를 사용하는 것이 더욱 좋다.</p>
<pre><code class="language-jsx">const request = indexedDB.open(&#39;myDatabase&#39;, 1);

request.onupgradeneeded = function(event) {
  const db = event.target.result;
  const objectStore = db.createObjectStore(&#39;myObjectStore&#39;, { keyPath: &#39;id&#39; });
};

request.onsuccess = function(event) {
  const db = event.target.result;
  const transaction = db.transaction([&#39;myObjectStore&#39;], &#39;readwrite&#39;);
  const objectStore = transaction.objectStore(&#39;myObjectStore&#39;);
  const data = { id: 1, name: &#39;John&#39;, age: 30 };
  const request = objectStore.add(data);

  request.onsuccess = function(event) {
    console.log(&#39;Data added to the database&#39;);
  };

  transaction.oncomplete = function(event) {
    console.log(&#39;Transaction completed&#39;);
  };
};</code></pre>
<p>위 코드에서 <strong><code>db.transaction()</code></strong> 메서드를 호출하여 데이터베이스 트랜잭션을 생성한다.</p>
<p>트랜잭션 모드로 &#39;readwrite&#39;를 지정하면 데이터를 추가하거나 수정할 수 있다.</p>
<p>이후에 <strong><code>transaction.objectStore()</code></strong> 메서드를 호출하여 객체 스토어에 접근하 고,<strong><code>objectStore.add()</code></strong> 메서드를 호출하여 데이터를 추가한다.</p>
<p>트랜잭션이 완료되면 <strong><code>transaction.oncomplete</code></strong> 이벤트가 발생한다.</p>
<p>이벤트 핸들러 함수에서는 데이터베이스 작업이 완료되었음을 알리는 메시지를 출력한다.</p>
<p>이와 같이 <strong>indexedDB</strong>에서 트랜잭션을 사용하면 데이터베이스 작업을 보다 안전하고 일관성 있게 수행할 수 있다.</p>
<h3 id="대규모-데이터를-저장한다고-했는데-그러면-용량을-얼마만큼-저장할-수-있는가">대규모 데이터를 저장한다고 했는데 그러면 용량을 얼마만큼 저장할 수 있는가?</h3>
<p><strong>indexedDB</strong>의 용량은 웹 브라우저마다 다르며, 사용자의 로컬 저장소 공간을 기준으로 결정된다.</p>
<p>대체로 대부분의 브라우저에서는 50MB ~ 500MB의 저장 용량을 제공하며, 브라우저마다 최대 저장 용량이 다르기 때문에 사용자가 얼마나 많은 공간을 사용할 수 있는지 확인하는 것이 중요하다.</p>
<p>또한, 사용자의 컴퓨터 하드웨어의 용량이나 브라우저 설정 등에 따라 저장 용량이 제한될 수 있다.</p>
<p>따라서, 대규모 데이터를 다룰 때는 브라우저의 저장 용량 제한을 고려하여 데이터를 분할하거나, 필요하지 않은 데이터를 삭제하여 용량을 최적화하는 것이 좋다.</p>
<p>또한, 브라우저에서 <strong>indexedDB</strong>를 사용할 때는 사용자가 데이터를 언제든지 지울 수 있으므로, 보안에 대한 고민도 필요하고 민감한 정보를 저장할 때는 암호화하여 보호하거나, 서버측 데이터베이스에 저장하는 것이 좋다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Git, Github에 대해서]]></title>
            <link>https://velog.io/@hmesan_93/Git-Github%EC%97%90-%EB%8C%80%ED%95%B4%EC%84%9C</link>
            <guid>https://velog.io/@hmesan_93/Git-Github%EC%97%90-%EB%8C%80%ED%95%B4%EC%84%9C</guid>
            <pubDate>Tue, 21 Mar 2023 14:46:52 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/hmesan_93/post/85e0783c-c398-4cae-aa5c-c420bce75bff/image.png" alt=""></p>
<h3 id="개요">개요</h3>
<hr>
<p>우리가 혼자서 또는 여러 명이서 프로젝트를 할 때 작업물을 만드는 과정에서 끊임없이 수정사항 등이 발생한다.
예를 들어, 이전에 썼던 코드를 다시 복원해야 할 수도 있고 실수로 오류가 난 코드들을 다시 되돌려야 할 일도 생긴다.
게다가 오류가 난 코드가 어디 있는지도 확인해야 할 상황이 생기기 마련이다.
예전 회사에 다닐 때는 작성한 엑셀파일을 저장할 때 수정한 날짜와 작성자의 이름을 파일 이름으로 저장했던 기억이 있다.
이렇게 돼버리면 파일이 계속해서 생겨나기 때문에 파일을 담고 있는 폴더의 크기가 계속해서 커지게 되고 용량을 비효율적으로 사용하게 돼버리는 일이 생긴다.</p>
<p>개발 공부를 하면서 알게 된, 대부분의 개발자들이 사용하고 있다고 해도 무방한 깃과 깃허브에 대해서 간단하게 다뤄보겠다.</p>
<h1 id="git">Git</h1>
<hr>
<p>위에서 말했듯이, 프로젝트를 진행하는 과정에서 중간중간 백업은 반드시 필요하다. 그리고 개발자들에게 있어서 협업을 할 때 내가 짠 코드를 테스트하고 싶어 하는 경우가 계속 생기는데 이 코드를 테스트하려면 소프트웨어 프로젝트의 경우에는 내용이 통째로 있어야만 테스트가 가능하다.
이것을 만약 이메일이나 클라우드로 서로 공유하면서 주고받으면 얼마나 번거로운가?
<strong><em>-&gt; 깃 등장 !!!</em></strong></p>
<h3 id="정의">정의</h3>
<ul>
<li>컴퓨터 파일의 변경사항을 추적하고 여러 명의 사용자들 간의 해당 파일들의 작업을 조율하기 위한 스냅샷 스트림 기반의 분산버전관리 시스템</li>
</ul>
<hr>
<h2 id="git은-버전관리-툴이다-소프트웨어-">Git은 버전관리 툴이다. (소프트웨어 )</h2>
<ul>
<li>오픈 소스 버전 관리 시스템 ( VCS: Version Control System )</li>
<li>로컬에서 버전 관리</li>
<li>소프트웨어 개발 및 소스 코드 관리에 사용</li>
</ul>
<p>위 3가지 내용이 깃에대한 설명인데 그래서 깃을 도대체 왜 사용하는 것인가?</p>
<ol>
<li>프로젝트를 진행함에 있어서 ‘버전 관리’ 는 필수<ul>
<li>파일 크기가 백업 수에 비례하여 늘어나지 않음</li>
<li>파일의 무엇이, 어디서, 몇 번, 누구에 의해 등 모든 변경 사항이 기록됨</li>
</ul>
</li>
<li>‘협업’<ul>
<li>메인 폴더 기준으로 각 개발자들이 파트를 맡아 진행하게 된다. 소프트웨어 프로젝트는 간단한 테스트를 하려고 해도 모든 파일과 폴더가 전체적으로 구성되어 있어야 가능함</li>
</ul>
</li>
</ol>
<p>이렇게 깃의 여러 가지 장점은 많지만 그중에서도 깃을 사용하면서 제일 좋았던 건 &quot;브랜치&quot;이다. 로컬에서 독립적으로 브랜치를 만들어서 새로운 내용을 작업을 하고 그게 마음에 들면 메인 브랜치로 병합도 할 수 있고, 마음에 들지 않으면 브랜치를 다시 삭제할 수도 있는 자유로움이 정말 편하다고 생각한다.</p>
<p>하지만 좋은 점들도 있지만 단점도 있다. 그중에서도 직접 겪어본 단점은 팀원들과 협업을 할 때, 각자가 로컬 저장 소리는 개인적인 공간에서 작업을 하기 때문에 같은 파트를 작업하는 사람들끼리 소통이 되질 않으면 실시간으로 서로가 작업하는 내용을 알 수 없다. 만약 같은 부분을 수정한다 할지라도 서로의 작업을 확인할 수 없다.
그리고 같은 부분을 작업해서 충돌이 나는 경우가 발생할 수도 있다.</p>
<h1 id="github">Github</h1>
<hr>
<p>깃허브를 한 줄로 요약하자면, <strong>깃으로 저장돼서 원격전송된 내용들이 저장되는 공간을 제공하는 클라우드 기반의 서비스이다.</strong>
왜 깃허브를 사용할까?</p>
<ol>
<li>버전 관리, 개발용, 운영용, private 한 코드들을 저장하는 등 여러 가지에 유용</li>
<li>협업 시 외장 장치를 이용하여 코드나 데이터를 공유하는 것보다 원격으로 공유하는 게 훨씬 빠르고 편함</li>
<li>여러 클라우딩 컴퓨팅 플랫폼들과 연동하여 배포를 효율적으로 관리할 수 있다.</li>
<li>&#39;백업&#39;에 있어 유리하다.</li>
</ol>
<ul>
<li>Why? -&gt; 모든 컴퓨터에는 &#39;확실한 것&#39;과 &#39;불확실한 것&#39;이 있다. 전자는 &#39;컴퓨터는 언젠가 고장 난다는 것&#39;이고 후자는 &#39;언제 고장 날지 모른다는 것&#39;이다.</li>
</ul>
<p>내가 작성한 코드들을 안전하게 원격 저장소(깃허브)에 백업을 해두자.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Scope & Closure]]></title>
            <link>https://velog.io/@hmesan_93/Scope-Closure</link>
            <guid>https://velog.io/@hmesan_93/Scope-Closure</guid>
            <pubDate>Thu, 09 Mar 2023 17:25:35 GMT</pubDate>
            <description><![CDATA[<h2 id="스코프">스코프</h2>
<p>변수 이름, 함수 이름, 클래스 이름과 같은 식별자가 본인이 선언된 위치에 따라 다른 코드에서 자신이 참조될 수 있을지 없을지 결정되는 것 → ‘유효범위’</p>
<ul>
<li><p>스코프가 계층적으로 연결되어 있는 것을 ‘<strong>스코프 체인’</strong> 이라고 한다. ( 스코프체인은 아래에서 위로 단방향성이다.)</p>
</li>
<li><p>변수를 참조할때 자바스크립트 엔진은 스코프체인을 통해 변수를 참조한다. 코드가실행된 지역의 스코프안에 참조하려고 하는 식별자를 찾을때까지 스코프체인을 통해 타고타고 올라간다. 전역 스코프에도 원하는 식별자를 찾을 수 없으면 참조에러가 난다.</p>
</li>
<li><p>대부분의 프로그래밍 언어는 함수나,if문,for문 모두 코드 블록이 지역스코프를 만든다 → <strong>블록 레벨 스코프</strong></p>
</li>
<li><p>자바스크립트에서는 var키워드로 선언된 변수는 오로지 함수 블록만이 지역스코프를 만든다. → <strong>함수 레벨 스코프</strong></p>
</li>
<li><p><strong>자바스크립트에서도 블록 레벨 스코프를 가지고 싶어함. → let ,const ( ES6 ) 도입</strong></p>
<p>  <strong>→ let 과 const 키워드로 선언된 변수는 for문이나 if문의 코드 블록안에서도 지역스코프를 만들 수가 있다.</strong></p>
</li>
<li><p>자바스크립트는 렉시컬 스코프( 정적 스코프 ) 를 따르기 때문에 함수가 정의되는 시점에 즉, 소스코드 평가 과정에서 상위 스코프가 결정이 된다. 그리고 해당 함수에 의해 함수 객체가 생성이 되면 해당함수의 객체는 본인의 상위 스코프를 항상 알 수 있게 된다.</p>
<p>  → 어떻게 알 수 있는가? 자바스크립트에서는 함수는 정의되는 시점에 자신의 내부슬롯에 상위 스코프의 참조를 저장하기 때문이다.</p>
</li>
<li><p>렉시컬 환경 : 어떠한 코드가 어디서 실행이 되고 본인 주변의 어떤 코드들이 있는지 대체적인 정보를 담고있는 환경이라고 할 수 있음.</p>
</li>
<li><p>함수가 호출 → 실행 컨텍스를 생성하고 콜스택에 푸시함 → 함수 자신의 렉시컬 환경 생성 ( 포함하는 식별자, 식별자에 바인딩 된 값, 상위 렉시컬 환경에 대한 참조 ) → 코드의 실행이 끝나면 콜스택에서 해당 실행컨텍스트를 pop하여 제거한다.</p>
</li>
</ul>
<h2 id="클로져">클로져</h2>
<pre><code class="language-jsx">const x = 1;

function out() {
    const x = 10;
    const inner = function() {
        console.log(x);
    };

    return inner;
}

const ethan = out();
ethan(); // 10
// 참조가 가능하다.</code></pre>
<ul>
<li><p>어떻게 out함수가 실행이 종료되면서 out함수 안에서 선언된 x변수의 생명주기가 끝났음에도 불구하고 inner함수안에서 x를 참조할 수 있었을까?</p>
</li>
<li><p>생명주기를 마감한 외부함수의 지역변수를 참조할 수 있다면 이때 이 함수를 <strong>클로져</strong> 라고 한다.</p>
</li>
<li><p>이 위에서 inner() 함수가 클로져가 된다.</p>
</li>
<li><p>클로져에 의해 참조된 변수를 자유변수라고 한다.</p>
</li>
<li><p>이러한 클로져는 하나의 state가 의도치 않게 변경되지 않도록 state를 안전하게 은닉하고 또는 특정 함수에게만 state 변경을 허용하기 위해 사용함</p>
</li>
<li><p>추가 : let,const는 블록안에서도 지역스코프(local)를 만든다.</p>
</li>
</ul>
<p><strong>참고자료 출처</strong> </p>
<ul>
<li><a href="https://www.youtube.com/watch?v=PVYjfrgZhtU">https://www.youtube.com/watch?v=PVYjfrgZhtU</a>  ( 10분 테코톡 )</li>
<li><a href="https://www.youtube.com/watch?v=QtOF0uMBy7k">https://www.youtube.com/watch?v=QtOF0uMBy7k</a> ( 생활코딩 )</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>