[
  {
    "path": ".github/workflows/action.yml",
    "content": "name: \"Pull Request Action\"\non: \n  pull_request:\n    types: [opened]\n\njobs:\n  test:\n    runs-on: ubuntu-latest\n    steps:\n    - name: Create link\n      uses: Im-D/Im-Bot/packages/pr-supporter@master\n      with:\n        myToken: ${{ secrets.GITHUB_TOKEN }}\n    - name: Create reviewRequest\n      uses: Im-D/Im-Bot/packages/pr-reviewer@master\n      with:\n        myToken: ${{ secrets.GITHUB_TOKEN }}\n    - name: Create Link at README file\n      uses: Im-D/Im-Bot/packages/update-readme@master\n      with:\n        myToken: ${{ secrets.GITHUB_TOKEN}}\n        linkLocTarget: '### 📅 History'"
  },
  {
    "path": ".mergify.yml",
    "content": "pull_request_rules:\n  - name: Automatic merge on review\n    # https://doc.mergify.io/examples.html#require-all-requested-reviews-to-be-approved\n    conditions:\n      - \"#approved-reviews-by>=4\"\n      - \"#changes-requested-reviews-by=0\"\n      - base=master\n      - label=approval + 3\n    actions:\n      merge:\n        method: merge\n      delete_head_branch: {}\n\n  - name: Add Label needs author response\n    conditions:\n      - \"#changes-requested-reviews-by>=1\"\n    actions:\n      label:\n        add: [\"needs author response\"]\n        remove: [\"needs review\"]\n\n  - name: Remove Label needs author response\n    conditions:\n      - \"#changes-requested-reviews-by=0\"\n    actions:\n      label:\n        add: [\"needs review\"]\n        remove: [\"needs author response\"]\n\n  - name: Add Label approval + 1\n    conditions:\n      - \"#approved-reviews-by=1\"\n    actions:\n      label:\n        add: [\"approval + 1\"]\n\n  - name: Add Label approval + 2\n    conditions:\n      - \"#approved-reviews-by=2\"\n    actions:\n      label:\n        add: [\"approval + 2\"]\n        remove: [\"approval + 1\"]\n  - name: Add Label approval + 3\n    conditions:\n      - \"#approved-reviews-by=3\"\n    actions:\n      label:\n        add: [\"approval + 3\"]\n        remove: [\"approval + 2\"]\n"
  },
  {
    "path": "Android/application fundamentals.md",
    "content": "# 안드로이드 (Android)\n\nAndroid 앱은 Kotlin, Java, C++ 언어를 사용하여 작성할 수 있습니다. Android SDK(Software Development Kit) 도구는 모든 데이터 및 리소스 파일과 함께 코드를 컴파일하여 하나의 **APK(Android PacKage)** 를 만듭니다. Android Package는 접미사가 .apk인 아카이브 파일입니다. 한 개의 APK 파일에는 Android 앱의 모든 콘텐츠가 들어 있으며, Android로 구동하는 기기가 앱을 설치할 때 바로 이 파일을 사용합니다.\n\nAndroid 시스템은 **최소 권한의 원리( Principle of least privilege )** 를 구현합니다. 다시 말해, 각 앱은 기본적으로 자신의 작업을 수행하기 위해 **필요한 구성 요소에만 액세스 권한을 가지고 그 이상은 허용되지 않습니다.** 이렇게 하면 대단히 안전한 환경이 구성되어 앱이 시스템에서 권한을 부여받지 못한 부분에는 액세스할 수 없게 됩니다. \n\n앱이 다른 앱과 데이터를 공유하고 시스템 서비스에 액세스하는 방법은 여러 가지가 있습니다. 그 중에서 '권한'을 살펴보도록 하겠습니다. 앱은 사용자의 연락처, SMS 메시지, 마운트 가능한 저장소(SD 카드), 카메라, 블루투스를 비롯한 여러 가지 기기 데이터에 액세스할 '권한'을 요청할 수 있습니다. 사용자는 이러한 **권한(Permission)** 을 명시적으로 부여해야 합니다. \n\n> 권한(Permission) 부여하는 방법\n\n앱은 앱 매니페스트에 <uses-permission> 태그를 포함하여 필요한 권한을 추가해야 합니다. 예를 들어 **SMS 메시지를 보내야 하는 앱** 은 [매니페스트(manifest)](https://developer.android.com/guide/topics/manifest/manifest-intro?hl=ko)에 다음 줄이 있어야 합니다.\n```xml\n<manifest ... >\n    <uses-permission android:name=\"android.permission.SEND_SMS\"/> <!-- SMS 메시지 권한 추가 -->\n    ...\n</manifest>\n```\n\n\n# 앱 기본요소 (Application Fundamentals)\n\n- **Manifests**: 구성 요소를 선언하고 앱에 필수적인 기기 특징을 선언할 수 있는 매니페스트 파일.\n- **App components**: 앱을 정의하는 핵심 프레임워크 구성 요소.\n- **Resource**: 앱 코드로부터 별도로 분리되어 있으며 앱이 다양한 기기 구성에 맞게 자신의 동작을 안정적으로 최적화할 수 있도록 하는 리소스.\n\n## 1. Manifests\n모든 앱 프로젝트는 프로젝트 소스 세트의 루트에 **AndroidManifest.xml** 파일(정확히 이 이름)이 있어야 합니다. 매니페스트 파일은 Android 앱에서 필요한 모든 구성요소, Android 빌드 도구, Android 운영체제 및 Google Play에 앱에 관한 필수 정보를 설명합니다. 정리하면 다음과 같습니다.\n\n- Package: 앱의 패키지 이름(일반적으로 코드의 네임스페이스와 일치)\n- App Components: 앱의 구성 요소(모든 Activity, Service, Broadcast Receiver, Content Provider 포함)\n- Permission: 앱이 시스템 또는 다른 앱의 보호된 부분에 액세스하기 위해 필요한 권한\n- 앱에 필요한 하드웨어 및 소프트웨어 기능\n\n\n매니페스트 파일의 추가적인 역할은 다음을 참고해주세요. \n- [매니페스트 파일](https://developer.android.com/guide/components/fundamentals?hl=ko#Manifest)\n- [앱 매니페스트 개요](https://developer.android.com/guide/topics/manifest/manifest-intro?hl=ko)\n\n## 2. App components\n앱 구성 요소(App components)는 Android 앱의 필수적인 기본 구성 요소입니다. 각 구성 요소는 **시스템이나 사용자가 앱에 들어올 수 있는 진입점**입니다. **다른 구성 요소에 종속되는 구성 요소**도 있습니다. 각 유형은 **뚜렷한 목적**을 수행하고 **각자 나름의 수명 주기**가 있어 구성 요소의 생성 및 소멸 방식을 정의합니다.\n\n### 1) Activities\n액티비티는 사용자와 상호작용하기 위한 진입점입니다. 이것은 **사용자 인터페이스를 포함한 화면 하나**를 나타냅니다. 여러 액티비티가 함께 작동하여 앱에서 짜임새 있는 사용자 환경을 구성하는 것은 사실이지만, **각자 서로 독립**되어 있습니다. 액티비티 하나를 `Activity` 클래스의 하위 클래스로 구현합니다. \n\n#### Activity Stack 구조\n<img src=\"https://user-images.githubusercontent.com/43839938/82186432-cff4fb80-9925-11ea-9d15-4dba92eea159.png\" width=\"450\" height=\"180\">\n\n#### Activity Life Cycle\n<img src=\"https://user-images.githubusercontent.com/43839938/82185881-e3ec2d80-9924-11ea-8de3-c3db8422bc9a.png\" width=\"350\" height=\"450\">\n\n### 2) Services\nService는 **백그라운드**에서 오래 실행되는 작업을 수행할 수 있는 애플리케이션 구성 요소이며 **사용자 인터페이스를 제공하지 않습니다.**\n\n- [포그라운드] 사용자가 다른 앱에 있는 동안에 *백그라운드에서 음악을 재생*한다.\n- [백그라운드] 사용자와 액티비티 간의 상호작용을 차단하지 않고 *네트워크를 통해 데이터를 가져온다*.\n- [바인드] 다른 구성 요소(예: 액티비티)가 서비스를 시작한 다음 실행되도록 두거나 자신에게 *바인딩*하여 상호작용한다. (라이브 배경화면, 알림 리스너, 화면 보호기, 입력 메서드, 접근성 서비스 및 여러 가지 기타 핵심 서비스 기능)\n\n시작된 서비스는 작업이 완료될 때까지 해당 서비스를 계속 실행하라고 **시스템**에 지시합니다. \n\n```xml\n<manifest ... >\n  ...\n  <application ... >\n      <service android:name=\".ExampleService\" />\n      ...\n  </application>\n</manifest>\n```\n\n##### 서비스는 Service 하위 클래스로 구현됩니다. \n##### 참고: Android 5.0(API 레벨 21) 이상을 대상으로 하는 앱의 경우 `JobScheduler` 클래스를 사용하여 작업을 예약하세요.\n\n### 3) Broadcast receivers\nBroadcast Receiver는 **시스템이 정기적인 사용자 플로우 밖에서 이벤트를 앱에 전달하도록 지원하는 구성 요소**로, 앱이 시스템 전체의 브로드캐스트 알림에 응답할 수 있게 합니다.\n\n\n### 4) Content providers\n콘텐츠 제공자는 파일 시스템, SQLite 데이터베이스, 웹상이나 앱이 액세스할 수 있는 다른 모든 영구 저장 위치에 저장 가능한 앱 데이터의 공유형 집합을 관리합니다. 다른 앱은 콘텐츠 제공자를 통해 해당 데이터를 쿼리하거나, 콘텐츠 제공자가 허용할 경우에는 수정도 가능합니다. \n\n\n구성 요소 유형 네 가지 중 세 가지 **(Activities, Services, Broadcast Receiver)** 는 **인텐트라는 비동기식 메시지로 활성화**됩니다. 인텐트는 런타임에서 각 구성 요소를 서로 바인딩합니다. 이것은 일종의 메신저라고 생각하면 됩니다. 즉 구성 요소가 어느 앱에 속하든 관계없이 다른 구성 요소로부터 작업을 요청하는 역할을 합니다.\n\n\n## 3. Resource\n\n리소스는 코드에서 사용하는 추가 파일과 정적인 콘텐츠입니다. 예를 들어 비트맵, 레이아웃 정의, 사용자 인터페이스 문자열, 애니메이션 지침 등이 있습니다.\n\n이미지나 문자열과 같은 앱 리소스는 항상 코드에서 외부화해야 합니다. 그래야 이들을 독립적으로 유지관리할 수 있습니다. 특정 기기 구성에 대한 대체 리소스도 제공해야 합니다. 이것은 특별하게 명명한 리소스 디렉토리에 그룹화하는 방법을 씁니다. Android는 런타임에 현재 구성을 근거로 적절한 리소스를 사용합니다. 예를 들어 여러 가지 화면 크기에 따라 여러 가지 UI 레이아웃을 제공하거나 언어 설정에 따라 각기 다른 문자열을 제공하고자 할 수 있습니다.\n\n앱 리소스를 외부화하면 프로젝트 R 클래스에서 발생하는 리소스 ID로 액세스할 수 있습니다. \n\n자세한 내용은 다음을 참고해주세요.\n- [앱 리소스 개요](https://developer.android.com/guide/topics/resources/providing-resources?hl=ko#top_of_page)\n\n## 4. Intent\nIntent는 **메시징 객체**로, **다른 앱 구성 요소로부터 작업을 요청하는 데 사용**할 수 있습니다. 기본적인 사용 사례는 크게 세 가지로 나눌 수 있습니다.\n- Starting an activity\n- Starting a service\n- Delivering a broadcast\n\n### 유형\n\n- **명시적 인텐트**는 인텐트를 충족하는 애플리케이션이 무엇인지 지정합니다. 이를 위해 대상 앱의 패키지 이름 또는 완전히 자격을 갖춘 구성 요소 클래스 이름을 제공합니다. 명시적 인텐트는 일반적으로 앱 안에서 구성 요소를 시작할 때 씁니다. 시작하고자 하는 액티비티 또는 서비스의 클래스 이름을 알고 있기 때문입니다. 예를 들어, 사용자 작업에 응답하여 새로운 액티비티를 시작하거나 백그라운드에서 파일을 다운로드하기 위해 서비스를 시작하는 것 등이 여기에 해당됩니다.\n- **암시적 인텐트**는 특정 구성 요소의 이름을 대지 않지만, 그 대신 수행할 일반적인 작업을 선언하여 다른 앱의 구성 요소가 이를 처리할 수 있도록 해줍니다. 예를 들어 사용자에게 지도에 있는 한 위치를 표시하고자 하는 경우, 암시적 인텐트를 사용하여 해당 기능을 갖춘 다른 앱이 지정된 위치를 지도에 표시하도록 요청할 수 있습니다.\n    <img src=\"https://user-images.githubusercontent.com/43839938/82185232-de421800-9923-11ea-8086-8b6086c75c14.png\" width=\"450\" height=\"180\">\n\n#### 암시적 인텐트 수신하기\n앱이 수신할 수 있는 암시적 인텐트가 어느 것인지 알리려면, <intent-filter> 요소를 사용하여 각 앱 구성 요소에 대해 하나 이상의 인텐트 필터를 매니페스트 파일에 선언합니다. 각 인텐트 필터는 인텐트의 작업, 데이터 및 카테고리를 기반으로 어느 유형의 인텐트를 수락하는지 지정합니다. **시스템은 인텐트가 인텐트 필터 중 하나를 통과한 경우에만 암시적 인텐트를 앱 구성 요소에 전달합니다.**\n\n> 예를 들어 데이터 유형이 텍스트인 경우 ACTION_SEND 인텐트를 수신할 인텐트 필터가 있는 액티비티 선언은 다음과 같습니다.\n```xml\n<activity android:name=\"ShareActivity\">\n    <intent-filter>\n        <action android:name=\"android.intent.action.SEND\"/>\n        <category android:name=\"android.intent.category.DEFAULT\"/>\n        <data android:mimeType=\"text/plain\"/>\n    </intent-filter>\n</activity>\n```\n> 소셜 공유 앱의 매니페스트 파일 예시\n```xml\n<activity android:name=\"MainActivity\">\n    <!-- This activity is the main entry, should appear in app launcher -->\n    <intent-filter>\n        <action android:name=\"android.intent.action.MAIN\" />\n        <category android:name=\"android.intent.category.LAUNCHER\" />\n    </intent-filter>\n</activity>\n\n<activity android:name=\"ShareActivity\">\n    <!-- This activity handles \"SEND\" actions with text data -->\n    <intent-filter>\n        <action android:name=\"android.intent.action.SEND\"/>\n        <category android:name=\"android.intent.category.DEFAULT\"/>\n        <data android:mimeType=\"text/plain\"/>\n    </intent-filter>\n    <!-- This activity also handles \"SEND\" and \"SEND_MULTIPLE\" with media data -->\n    <intent-filter>\n        <action android:name=\"android.intent.action.SEND\"/>\n        <action android:name=\"android.intent.action.SEND_MULTIPLE\"/>\n        <category android:name=\"android.intent.category.DEFAULT\"/>\n        <data android:mimeType=\"application/vnd.google.panorama360+jpg\"/>\n        <data android:mimeType=\"image/*\"/>\n        <data android:mimeType=\"video/*\"/>\n    </intent-filter>\n</activity>\n```\n\n### Reference\n* [애플리케이션 기본 항목](https://developer.android.com/guide/components/fundamentals?hl=ko)\n\n\n"
  },
  {
    "path": "Browser/BrowserXY.md",
    "content": "# 브라우저의 XY\n\n브라우저에 event가 발생했을 때에 x, y 좌표 값을 얻는 방법에는 크게 4가지가 있다.\n\n- clientX / clientY\n- pageX / pageY\n- screenX / screenY\n- offsetX / offsetY\n\n이렇게 4가지가 존재하는데 어떤 차이가 있는지 알아보았다.\n\n## clientX / clientY\n\nclient는 viewport와 매칭된다고 생각하면 쉽다.\n\n브라우저의 화면인 viewport를 기준으로 좌표를 계산한다. 브라우저의 현재 보이는 화면을 기준으로 어느 곳을 선택했는지 반환한다.\n\n스크롤을 하게 되어도 화면의 같은 곳을 클릭하면 같은 값이 반환된다.\n브라우저의 크기가 달라져도 화면의 같은 곳에서는 같은 값이 변경된다.\n\n어느 정도 절대값이라고 할 수 있다.\n\n## pageX / pageY\n\npage는 html문서와 매칭된다.\n\nclient는 현재 브라우저에 보여지는 부분이다. page는 그것과 상관없이 렌더된 html문서가 기준이다.\n\n스크롤을 하게 되면 값이 달라진다.\n브라우저의 크기를 줄여도 값과는 상관없다.\n\n## screenX / screenY\n\nscreen은 user device의 모니터를 기준으로 한다.\n모니터의 어느 부분을 클릭했는지 물리적인 값을 반환한다.\n\n따라서 브라우저 상단의 tab, bookmark와 같은 정보들의 높이도 포함한다.\n\n스크롤을 해도 달라지지 않는다.\n브라우저의 크기가 달라지는 것은 관계가 없다. 다만 브라우저를 작게하여 모니터상의 브라우저 위치를 이동하면 값이 달라질 수 있다.\n\n## offsetX / offsetY\n\noffset은 이벤트가 걸린 DOM기준이다. 예를들어 div를 클릭했다면 div의 왼쪽 상단 모서리가 0, 0이 된다.\n\n스크롤을 해도 달라지지 않는다.\n브라우저가 달라져도 값은 달라지지 않는다.\n\n다만 event.target의 크기가 변경된다면 달라질 수 있다.\n\n## 사진으로 보기\n\n글로만 보면 상당히 헷갈린 개념이다. 여러 링크에서 사진들을 모아봤으니 눈으로 확인하자.\n\n![](https://user-images.githubusercontent.com/24724691/59552616-4970c500-8fc4-11e9-93ae-a15ebd27b2cb.png)\n\n![](https://user-images.githubusercontent.com/24724691/59552615-4970c500-8fc4-11e9-9995-fb8bbbcc6cf3.jpg)\n\n![](https://user-images.githubusercontent.com/24724691/59552617-4a095b80-8fc4-11e9-9a39-c56ce0d2baf1.png)\n\n마지막 사진은\n\n- yellow : screen\n- blue : client\n- red : page\n\n로 매칭된다.\n\n사진의 출처는 아래에 링크로 대체한다.\n\n## 예제로 확인하기\n\n헷갈린 개념은 직접 디버깅하는 것이 좋다.\n\n```html\n<!DOCTYPE html>\n<html>\n  <head>\n    <title>Document</title>\n    <style>\n      * {\n        margin: 0;\n        padding: 0;\n      }\n\n      .container {\n        overflow-x: scroll;\n        overflow-y: scroll;\n        background-color: #fcc2d7;\n      }\n\n      .click {\n        width: 150%;\n        height: 120vh;\n        margin: 0 auto;\n        padding: 20px;\n        border: 10px solid #000;\n        background-color: #74c0fc;\n      }\n    </style>\n  </head>\n  <body>\n    <div class=\"container\">\n      <div class=\"click\">target</div>\n    </div>\n  </body>\n  <script>\n    const click = document.querySelector('.click');\n    window.addEventListener('load', () => {\n      click.addEventListener('click', event => {\n        console.log(`client: (${event.clientX}, ${event.clientY})`);\n        console.log(`page: (${event.pageX}, ${event.pageY})`);\n        console.log(`screen: (${event.screenX}, ${event.screenY})`);\n        console.log(`offset: (${event.offsetX}, ${event.offsetY})`);\n      });\n    });\n  </script>\n</html>\n```\n\n---\n\n### 참고자료\n\n- [screen, client, page, offset compare](https://m.blog.naver.com/PostView.nhn?blogId=sung487&logNo=220418825028&proxyReferer=https%3A%2F%2Fwww.google.com%2F)\n- [clientX, offsetX, pageX, screenX의 차이](http://megaton111.cafe24.com/2016/11/29/clientx-offsetx-pagex-screenx%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%A0%90/)\n- [What is the difference between screenX/Y, clientX/Y and pageX/Y?](https://stackoverflow.com/questions/6073505/what-is-the-difference-between-screenx-y-clientx-y-and-pagex-y)\n- [What is the difference between pageX/Y clientX/Y screenX/Y in Javascript?](https://stackoverflow.com/questions/9262741/what-is-the-difference-between-pagex-y-clientx-y-screenx-y-in-javascript/17705548)\n"
  },
  {
    "path": "Browser/Cookie.md",
    "content": "브라우저에는 다양한 저장소가 있다.\n\n<p align=\"center\">\n  <img src=\"https://user-images.githubusercontent.com/24274424/58260975-698cda00-7db2-11e9-90d9-1cfabfe6a94a.png\" alt=\"Storage\">\n</p>\n\n> [참고] Chrome 개발자 도구 - Application Tab\n\n위 사진은 Chrome 개발자 도구에 들어가서 Application Tab을 누르게 되면 왼쪽 메뉴에 보이는 Storage로 총 **5개**가 있다. 그 중 가장 아래에 있는 Cookie에 대해서 알아보자\n\n# Cookie\n\n쿠키는 브라우저에 저장되는 작은 크기의 문자열로, **RFC 6265** 명세에서 정의한 HTTP 프로토콜의 일부이다.\n\n서버가 HTTP 응답 헤더(header)의 `Set-Cookie`에 내용을 넣어 전달하면, 브라우저는 이 내용을 자체적으로 브라우저에 저장하는데 이것이 쿠키이다.\n\n브라우저는 사용자가 쿠키를 생성하도록 동일 서버(사이트)에 접속할 때마다 쿠키 내용을 Cookie 요청 헤더에 넣어서 함께 전달한다.\n\n이를 사용하여 쿠키는 클라이언트 식별 같은 인증에 가장 많이 쓰인다.\n\n1. 사용자가 로그인하면 서버는 HTTP 응답 헤더의 `Set-Cookie`에 담긴 세션 식별자(session identifier) 정보를 사용해 쿠키를 설정한다.\n2. 사용자가 동일 도메인에 접속하려고 하면 브라우저는 HTTP Cookie 헤더에 인증 정보가 담긴 고유값(세션 식별자)을 함께 서버에 요청으로 보낸다.\n3. 서버는 브라우저가 보낸 요청 헤더의 세션 식별자를 읽어 사용자를 식별한다.\n \n`document.cookie` 프로퍼티를 이용하면 브라우저에서도 쿠키에 접근할 수 있다.\n\n```js\nconsole.log(document.cookie);\n```\n\n`document.cookie`는 `name=value` 쌍으로 구성되어 있으며, 쌍은 `;`로 구분된다. 쌍 하나는 하나의 독립된 쿠키이다.\n\n`document.cookie`에 직접 값을 쓸 수 있다. cookie는 데이터 프로퍼티가 아닌 접근자(accessor) 프로퍼티이다.\n\n```js\n// getter\ndocument.cookie = \"user=SeonHyungJo\";\nconsole.log(document.cookie);\n```\n\n`document.cookie`에 값을 할당하면, 브라우저는 이 값을 받아 해당 쿠키를 갱신한다. 다른 쿠키의 값은 변경되지 않는다.\n\n```js\ndocument.cookie = \"user=SeonHyungJo\";\nconsole.log(document.cookie); // user=SeonHyungJo\ndocument.cookie = \"newuser=SeonHyungJo\";\nconsole.log(document.cookie); // user=SeonHyungJo; newuser=SeonHyungJo\n```\n\n쿠키의 이름과 값엔 특별한 제약이 없다. 하지만 형식의 유효성을 일관성 있게 유지하기 위해 반드시 내장 함수 `encodeURIComponent`를 사용하여 이름과 값을 이스케이프 처리를 해주는 것이 좋다.\n\n```js\nlet name = 'origin';\nlet value = \"github/SeonHyungJo\";\n\ndocument.cookie = encodeURIComponent(name) + '=' + encodeURIComponent(value);\n\nconsole.log(document.cookie); // origin=github%2FSeonHyungJo\n```\n\n## 단점\n\n- 용량 : **4kb**로 매우 작은 용량이다.\n- 속도 : 요청 때마다 포함되어서 간다. 작은 용량이라고 하지만 필요 없는 데이터가 전달되는 낭비가 발생한다.\n- 보안 : 위험성이 크다.\n\n## 옵션\n\n### path\n\n- `path=/mypath`\n\nURL path(경로)의 접두사로, 경로나 경로의 하위 경로에 있는 페이지만 쿠키에 접근할 수 있다. 절대 경로이어야 하고, 기본값은 현재 경로이다.\n\n`path=/user` 옵션을 사용하여 설정한 쿠키는 `/user`과 `/user/something`에선 볼 수 있지만, `/partner` 이나 `/adminpage`에선 볼 수 없다.\n\n특별한 경우가 아니라면, path 옵션을 `path=/`같이 루트로 설정해 웹사이트의 모든 페이지에서 쿠키에 접근할 수 있도록 한다.\n\n### domain\n\n- `domain=imdev.com`\n\n쿠키에 접근 가능한 domain(도메인)을 지정한다. 다만, 몇 가지 제약이 있어서 아무 도메인이나 지정할 수 없다.\n\ndomain 옵션에 아무 값도 넣지 않았다면, 쿠키를 설정한 도메인에서만 쿠키에 접근할 수 있다. `imdev.com`에서 설정한 쿠키는 `other.com`에서 얻을 수 없다. 서브 도메인(subdomain)인 `forum.imdev.com`에서도 쿠키 정보를 얻을 수 없다.\n\n```js\n// imdev.com에서 쿠키를 설정함\ndocument.cookie = \"user=SeonHyungJo\"\n\n// imdev.com의 서브도메인인 forum.imdev.com에서 user 쿠키에 접근하려 함\nalert(document.cookie); // 찾을 수 없음\n```\n\n서브 도메인이나 다른 도메인에서 쿠키에 접속할 방법은 없다. `imdev.com`에서 생성한 쿠키를 `other.com`에선 절대 전송받을 수 없다.\n\n이런 제약사항은 안정성을 높이기 위해 만들어졌는데, 민감한 데이터가 저장된 쿠키는 관련 페이지에서만 볼 수 있도록 하기 위해서다.\n\n정말 `forum.imdev.com`과 같은 서브 도메인에서 `imdev.com`에서 생성한 쿠키 정보를 얻을 방법이 없는 걸까? `imdev.com`에서 쿠키를 설정할 때 domain 옵션에 루트 도메인인 `domain=imdev.com`을 명시적으로 설정해 주면 된다.\n\n```js\n// imdev.com에서\n// 서브 도메인(*.imdev.com) 어디서든 쿠키에 접속하게 설정할 수 있다.\ndocument.cookie = \"user=SeonHyungJo; domain=imdev.com\"\n\n// 이렇게 설정하면\n// forum.imdev.com와 같은 서브도메인에서도 쿠키 정보를 얻을 수 있다.\nalert(document.cookie); // user=SeonHyungJo 쿠키를 확인할 수 있다.\n```\n\n하위 호환성 유지를 위해 (imdev.com 앞에 점을 붙인) `domain=.imdev.com`도 `domain=imdev.com`과 같이 작동한다. 오래된 표기법이긴 하지만 구식 브라우저를 지원하려면 이 표기법을 사용하는 것이 좋다.\n\n이렇게 domain 옵션값을 적절히 사용하면 서브 도메인에서도 쿠키에 접근할 수 있다.\n\n> 테스트 해보기(도메인 설정을 한 경우, 안 한 경우)\n\n### expires와 max-age\n\nexpires(유효 일자)나 max-age(만료 기간) 옵션이 지정되어있지 않으면, 브라우저가 닫힐 때 쿠키도 함께 삭제된다. 이런 쿠키를 **세션 쿠키(session cookie)** 라 부른다.\nexpires 나 max-age 옵션을 설정하면 브라우저를 닫아도 쿠키가 삭제되지 않는다.\n\n- `expires=Tue, 19 Jan 2038 03:14:07 GMT`\n\n브라우저는 설정된 유효 일자까지 쿠키를 유지하다가, 해당 일자가 도달하면 쿠키를 자동으로 삭제한다.\n\n쿠키의 유효 일자는 반드시 GMT(Greenwich Mean Time) 포맷으로 설정해야 한다. `date.toGMTString` (`toUTCString`) 을 사용하면 해당 포맷으로 쉽게 변경할 수 있다.\n\n```js\n// 지금으로부터 하루 뒤\nlet date = new Date(Date.now() + 86400e3);\ndate = date.toGMTString();\ndocument.cookie = \"user=SeonHyungJo; expires=\" + date;\n```\n\nexpires 옵션값을 과거로 설정하면 삭제된다.\n\n- `max-age=3600`\n\nmax-age는 expires 옵션의 대안으로, 쿠키 만료 기간을 설정할 수 있다. 현재부터 설정하고자 하는 만료일시까지의 시간을 초로 환산한 값을 설정한다. 0이나 음수값을 설정하면 쿠키는 바로 삭제된다.\n\n```js\n// 1시간 뒤에 쿠키가 삭제된다.\ndocument.cookie = \"user=SeonHyungJo; max-age=3600\";\n\n// 만료 기간을 0으로 지정하여 쿠키를 바로 삭제한다\ndocument.cookie = \"user=SeonHyungJo; max-age=0\";\n```\n\n### secure\n\n- `secure`\n\n이 옵션을 설정하면 HTTPS로 통신하는 경우에만 쿠키가 전송된다.\n\nsecure 옵션이 없으면 기본 설정이 적용되어 `http://imdev.com`에서 설정(생성)한 쿠키를 `https://imdev.com`에서 읽을 수 있고, `https://imdev.com`에서 설정(생성)한 쿠키도 `http://imdev.com`에서 읽을 수 있다.\n\n쿠키는 기본적으로 도메인만 확인하지 프로토콜을 확인하지 않는다.\n\n하지만 secure 옵션이 설정된 경우, `https://imdev.com`에서 설정한 쿠키는 `http://imdev.com`에서 접근할 수 없다. 쿠키에 민감한 내용이 저장되어 있어 암호화되지 않은 HTTP 연결을 통해 전달되는 걸 원치 않는다면 이 옵션을 사용하면 된다.\n\n```js\n// (https:// 로 통신하고 있다고 가정 중)\n// 설정한 쿠키는 HTTPS 통신시에만 접근할 수 있음\ndocument.cookie = \"user=SeonHyungJo; secure\";\n```\n\n## samesite\n\n다른 보안 속성인 samesite 옵션은 크로스 사이트 요청 위조(cross-site request forgery, XSRF) 공격을 막기 위해 만들어진 옵션이다.\n\n아래 XSRF 공격 시나리오를 통해 이 속성의 동작 방식과 언제 이 속성을 유용하게 사용할 수 있는지 알아보자.\n\n### XSRF 공격\n\n현재 bank.com에 로그인되어 있을 때. 해당 사이트에서 사용되는 인증 쿠키가 브라우저에 저장되고, 브라우저는 bank.com에 요청을 보낼 때마다 인증 쿠키를 함께 전송한다. 서버는 전송받은 쿠키를 이용해 사용자를 식별하고, 보안이 필요한 재정 거래를 처리한다.\n\n이제 (로그아웃하지 않고) 다른 창을 띄워서 웹 서핑을 하던 도중에 뜻하지 않게 evil.com이라는 사이트에 접속했다 가정하면, 이 사이트엔 해커에게 송금을 요청하는 폼(form) `<form action=\"https://bank.com/pay\">`이 있고, 이 폼은 자동으로 제출되도록 설정되어 있다.\n\n폼이 evil.com에서 은행 사이트로 바로 전송될 때 인증 쿠키도 함께 전송된다. bank.com에 요청을 보낼 때마다 bank.com에서 설정한 쿠키가 전송되기 때문이다. 은행은 전송받은 쿠키를 읽어 (해커가 아닌) 계정 주인이 접속한 것으로 생각하고 해커에게 돈을 송금한다.\n\n이런 공격을 크로스 사이트 요청 위조라고 부른다.\n\n실제 은행은 당연히 이 공격을 막을 수 있도록 시스템을 설계한다. bank.com에서 사용하는 모든 폼에 **XSRF 보호 토큰(protection token)**이라는 특수 필드를 넣는다. 이 토큰은 악의적인 페이지에서 만들 수 없고, 원격 페이지에서도 훔쳐 올 수 없도록 구현되어 있다. 따라서 악의적인 페이지에서 폼을 전송하더라도 보호 토큰이 없거나 서버에 저장된 값과 일치하지 않기 때문에 요청이 무용지물이 된다.\n\n하지만 이런 절차는 구현에 시간이 걸린다.\n\n> 참고 : [CSRF 공격이란? 그리고 CSRF 방어 방법](https://itstory.tk/entry/CSRF-%EA%B3%B5%EA%B2%A9%EC%9D%B4%EB%9E%80-%EA%B7%B8%EB%A6%AC%EA%B3%A0-CSRF-%EB%B0%A9%EC%96%B4-%EB%B0%A9%EB%B2%95)\n\n### samesite 옵션\n\n쿠키의 samesite 옵션을 이용하면 XSRF 보호 토큰 없이도 크로스 사이트 요청 위조를 막을 수 있다.\n\n이 옵션엔 두 가지 값을 설정할 수 있다.\n\n- `samesite=strict`\n\n사용자가 사이트 외부에서 요청을 보낼 때, `samesite=strict` 옵션이 있는 쿠키는 절대로 전송되지 않는다.\n\n메일에 있는 링크를 따라 접속하거나 evil.com과 같은 사이트에서 폼을 전송하는 경우 등과 같이 제3의 도메인에서 요청이 이뤄질 땐 쿠키가 전송되지 않는다.\n\n인증 쿠키에 samesite 옵션이 있는 경우, XSRF 공격은 절대로 성공하지 못한다. evil.com에서 전송하는 요청엔 쿠키가 없을 것이고, bank.com은 미인식 사용자에게 지급을 허용하지 않을 것이기 때문이다.\n\n만약 사용자가 메모장 등에 bank.com에 요청을 보낼 수 있는 링크를 기록해 놓았다가 이 링크를 클릭해 접속하면 bank.com이 사용자를 인식하지 못하는 상황이 발생하기 때문이다. 실제로 이런 경우 `samesite=strict` 옵션이 설정된 쿠키는 전송되지 않는다.\n\n이런 문제는 쿠키 두 개를 함께 사용해 해결할 수 있다. \"Hello, SeonHyungJo\"과 같은 환영 메시지를 출력해주는 \"일반 인증(general recognition)\"용 쿠키, 데이터 교환 시 사용하는 `samesite=strict` 옵션이 있는 쿠키를 따로 두는 것이다.\n\n- `samesite=lax` (Chrome default 값)\n\n> [관련 이슈](https://brocess.tistory.com/263)\n\n`samesite=lax`는 사용자 경험을 해치지 않으면서 XSRF 공격을 막을 수 있는 느슨한 접근법이다.\n\nstrict와 마찬가지로 lax도 사이트 외부에서 요청을 보낼 때 브라우저가 쿠키를 보내는 걸 막아준다. 하지만 예외사항이 있다.\n\n아래 두 조건을 동시에 만족할 때는 `samesite=lax` 옵션을 설정한 쿠키가 전송된다.\n\n1. 안전한 HTTP 메서드인 경우(예: GET 방식. POST 방식은 해당하지 않음). \n\n> 또는 `a href`, `link href`\n\n안전한 HTTP 메서드 목록은 RFC7231 명세에서 확인할 수 있다. 안전한 메서드는 읽기 작업만 수행하고 쓰기나 데이터 교환 작업은 수행하지 않는다. 참고로, 링크를 따라가는 행위는 항상 GET 방식이기 때문에 안전한 메서드만 쓰인다.\n\n2. 작업이 최상위 레벨 탐색에서 이루어질 때(브라우저 주소창에서 URL을 변경하는 경우).\n\n대다수의 작업은 이 조건을 충족한다. 하지만 `<iframe>`안에서 탐색이 일어나는 경우는 최상위 레벨 탐색이 아니기 때문에 충족하지 못한다. AJAX 요청 또한 탐색 행위가 아니므로 이 조건이 안된다.\n\n브라우저를 이용해 자주 하는 작업인 \"특정 URL로 이동하기\"를 실행하는 경우, `samesite=lax` 옵션이 설정되어 있으면 쿠키가 서버로 전송된다. 하지만 외부 사이트에서 AJAX 요청을 보내거나 폼을 전송하는 등의 복잡한 작업을 시도할 때는 쿠키가 전송되지 않는다. 이런 제약사항이 있어도 괜찮다면, `samesite=lax` 옵션은 사용자 경험을 해치지 않으면서 보안을 강화해주는 방법으로 활용할 수 있을 것이다.\n\nsamesite는 좋은 옵션이긴 하지만, 한가지 문제점이 있다.\n\n- 오래된 브라우저(2017년 이전 버전)에선 samesite 옵션을 지원하지 않는다.\n\nsamesite 옵션으로만 보안 처리를 하게 되면, 구식 브라우저에서 보안 문제가 발생할 수 있다. 구식 브라우저에 대응하지 못한다는 문제가 있긴 하지만, samesite 옵션을 XSRF 토큰 같은 다른 보안 기법과 함께 사용하면 보안을 강화할 수 있다.\n\n구식 브라우저가 사용되지 않는 그날을 위해...\n\n## 함수로 만들어서 사용하기\n\n### getCookie\n\n```js\nconst getCookie = (name) => {\n  let matches = document.cookie.match(new RegExp(\n    \"(?:^|; )\" + name.replace(/([\\.$?*|{}\\(\\)\\[\\]\\\\\\/\\+^])/g, '\\\\$1') + \"=([^;]*)\"\n  ));\n  return matches ? decodeURIComponent(matches[1]) : undefined;\n}\n```\n\n### setCookie\n\n```js\nconst setCookie = (name, data, expire = '', path = '') => {\n  const date = new Date();\n  date.setDate(date.getDate() + expire);\n  date.setHours(0, 0, 0, 0)\n\n  document.cookie = `${name}=${data};` + `expires=${date.toGMTString()};` + `path=${path};`;\n}\n```\n\n### removeCookie\n\n```js\nconst removeCookie = (name) => {\n  document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:01 GMT;';\n}\n```\n\n#### Reference\n\n- https://ko.javascript.info/cookie#ref-271\n- https://ifuwanna.tistory.com/223\n"
  },
  {
    "path": "Browser/Cookie_Store.md",
    "content": "# New Cookie Store API(after Chrome 87)\n\n2020년 11월 01일 기준 Chrome의 버전은 `86.0.4240.111`이다.\n\n![chrome_version](https://user-images.githubusercontent.com/24274424/97792446-d223eb80-1c21-11eb-8733-36687902850a.png)\n\n추후 버전 87에 추가되는 기능 중에서 Cookie관련 API를 알아보자.\n\n# Release\n\nCookie Store API는 HTTP 쿠키를 서비스 워커에서도 접근이 가능하며, `document.cookie`에서 비동기적으로 사용가능하도록 하는 기능이라고 명세가 되어있다.\n\n> [Chrome Platform Status](https://www.chromestatus.com/feature/5658847691669504)\n\n![chrome_status](https://user-images.githubusercontent.com/24274424/97792406-372b1180-1c21-11eb-9fcc-f8ef35f8385c.png)\n\n위와 같이 87 버전에 포함된 항목은 추후 업데이트를 하게 되면 확인가능하며, 다른 브라우저들은 아직 적용이 안됨으로 사용하는데 주의가 필요하다.\n\n## 관련 Issue\n\n1. [Add cookie accessor/setter methods? · Issue #707 · w3c/ServiceWorker](https://github.com/w3c/ServiceWorker/issues/707)\n\n2. [Possible API Sketch · Issue #14 · WICG/cookie-store](https://github.com/WICG/cookie-store/issues/14)\n\n# Document\n\nW3C Community Group에서 처음 나온 초안으로 관련 레포인 [WICG/cookie-store](https://github.com/WICG/cookie-store)을 들어가면 설명이 있다.\n\n새로운 API 기존의 cookie의 스펙을 바꾸지 않고 사용하는 방식이며 위에서 언급되었던 바와 같이 Service Worker에서의 접근과 비동기적으로 처리할 수 있게 하는 것을 주 목표로 삼고 있다(Promise 사용).\n\n간단하게 인터페이스를 살펴보자.\n\n```cpp\n[Exposed=(ServiceWorker,Window), SecureContext]\n\ninterface CookieStore : EventTarget {\n  Promise<CookieListItem?> get(USVString name);\n  Promise<CookieListItem?> get(optional CookieStoreGetOptions options = {});\n\n  Promise<CookieList> getAll(USVString name);\n  Promise<CookieList> getAll(optional CookieStoreGetOptions options = {});\n\n  Promise<undefined> set(USVString name, USVString value);\n  Promise<undefined> set(CookieInit options);\n\n  Promise<undefined> delete(USVString name);\n  Promise<undefined> delete(CookieStoreDeleteOptions options);\n\n  [Exposed=Window]\n  attribute EventHandler onchange;\n};\n\ndictionary CookieStoreGetOptions {\n  USVString name;\n  USVString url;\n};\n\nenum CookieSameSite {\n  \"strict\",\n  \"lax\",\n  \"none\"\n};\n\ndictionary CookieInit {\n  required USVString name;\n  required USVString value;\n  DOMTimeStamp? expires = null;\n  USVString? domain = null;\n  USVString path = \"/\";\n  CookieSameSite sameSite = \"strict\";\n};\n\ndictionary CookieStoreDeleteOptions {\n  required USVString name;\n  USVString? domain = null;\n  USVString path = \"/\";\n};\n\ndictionary CookieListItem {\n  USVString name;\n  USVString value;\n  USVString? domain;\n  USVString path;\n  DOMTimeStamp? expires;\n  boolean secure;\n  CookieSameSite sameSite;\n};\n\ntypedef sequence<CookieListItem> CookieList;\n```\n\n`interface CookieStore`를 살펴보기 전 상단의 코드를 보게 되면, window뿐만 아니라 ServiceWorker가 있는 것을 확인할 수 있다.\n\n`interface CookieStore`에는 우리가 사용할 수 있는 메서드들과 이벤트 핸들러가 있는 것을 볼 수 있는데, 이벤트 핸들러는 window에서만 사용이 가능하다.\n\n`getAll`, `get`, `delete` 메서드를 사용하는 방법은 기본적으로 cookie의 이름만으로 사용할 수 있고, option이라는 것을 통해서 가져오거나 삭제가 가능하다. 자세한 형태는 아래를 살펴보면 된다.\n\n간단하게 `dictionary CookieInit` 부분을 보게 되면 cookie에서 사용하는 설정 중 CookieSameSite의 기본값이 strict라는 것을 알 수 있다. \n\n최근 Chrome 86에서 변경된 Cookie 정책을 알고 있다면, 86 버전 이전 기본값이 `none`이였다면, 86이후에는 기본값이 `lax`로 바뀐 것을 알 것이다. 그런데 해당 API에서는 기본값이 `strict`이다.\n\n이 부분의 차이점을 알고있는 것이 중요하다.\n\n> [Browser Cookie](https://github.com/im-d-team/Dev-Docs/blob/master/Browser/Cookie.md)\n\n# Explainer\n\n[Cookie Store API Explainer](https://wicg.github.io/cookie-store/explainer.html)\n\n## Method\n\n### 일반적인 사용법\n\n```js\ndocument.cookie =\n  '__Secure-COOKIENAME=cookie-value' +\n  '; Path=/' +\n  '; expires=Fri, 12 Aug 2016 23:05:17 GMT' +\n  '; Secure' +\n  '; Domain=example.org';\n// now we could assume the write succeeded, but since\n// failure is silent it is difficult to tell, so we\n// read to see whether the write succeeded\nvar successRegExp =\n  /(^|; ?)__Secure-COOKIENAME=cookie-value(;|$)/;\nif (String(document.cookie).match(successRegExp)) {\n  console.log('It worked!');\n} else {\n  console.error('It did not work, and we do not know why');\n}\n```\n\n### set\n\n```js\nconst one_day_ms = 24 * 60 * 60 * 1000;\ncookieStore.set(\n  {\n    name: 'imd',\n    value: '1',\n    expires: Date.now() + one_day_ms,\n  }).then(function() {\n    console.log('It worked!');\n  }, function(reason) {\n    console.error(\n      'It did not work, and this is why:',\n      reason);\n  });\n```\n\n### get\n\n```js\ntry {\n  const cookie = await cookieStore.get('imd');\n  if (cookie) {\n    console.log(`Found ${cookie.name} cookie: ${cookie.value}`);\n  } else {\n    console.log('Cookie not found');\n  }\n} catch (e) {\n  console.error(`Cookie store error: ${e}`);\n}\n```\n\n### getAll\n\n```js\ntry {\n  const cookies = await cookieStore.getAll('imd');\n  for (const cookie of cookies)\n    console.log(`Result: ${cookie.name} = ${cookie.value}`);\n} catch (e) {\n  console.error(`Cookie store error: ${e}`);\n}\n```\n\n### delete\n\n```js\ntry {\n  await cookieStore.delete('imd');\n} catch (e) {\n  console.error(`Failed to delete cookie: ${e}`);\n}\n```\n\n### event\n\n```js\ncookieStore.addEventListener('change', event => {\n  console.log(`${event.changed.length} changed cookies`);\n  for (const cookie of event.changed)\n    console.log(`Cookie ${cookie.name} changed to ${cookie.value}`);\n\n  console.log(`${event.deleted.length} deleted cookies`);\n  for (const cookie in event.deleted)\n    console.log(`Cookie ${cookie.name} deleted`);\n});\n```\n\n### Reference\n\n- [Cookie Store API](https://wicg.github.io/cookie-store/)\n- [web-platform-tests/wpt](https://github.com/web-platform-tests/wpt/tree/master/cookie-store)\n- [Digital Information World](https://www.digitalinformationworld.com/2020/10/chrome-87-beta-is-aiming-to-become-much.html)\n- [web-platform-tests/wpt](https://github.com/web-platform-tests/wpt/tree/master/cookie-store)\n- [Asynchronous Access to HTTP Cookies | Web | Google Developers](https://developers.google.com/web/updates/2018/09/asynchronous-access-to-http-cookies)\n- [Asynchronous Cookie Access on the Web](https://docs.google.com/document/d/1ak6JzOMMO5q3dXvu4mHFWR-LLvaDc09XDvdeJZLtZd4/edit#heading=h.7nki9mck5t64)\n"
  },
  {
    "path": "Browser/FOUC.md",
    "content": "# FOUC(Flash of Unstyled Content)\n\n`FOUC(Flash of Unstyled Content)`란 브라우저에서 웹 페이지에 접근했을 때, 미처 스타일이 적용되지 못한 상태로 화면이 나타나는 현상을 말한다. \n\n스타일이 적용되기 전의 상태가 먼저 화면에 렌더링된 후 그 상태에서 스타일이 적용되기 때문에 스타일이 적용되는 과정이 사용자에게 그대로 노출되는 현상이다. 이러한 현상은 사용자의 경험(UX)를 떨어트리게 된다는 문제가 있다.\n\n`FOUC`는 특히 `IE(Internet Explorer)` 브라우저에서 주로 발생되며 `IE11`에서도 여전히 발생되고 있는 문제다.\n\n## FOUC의 발생 원인\n\n`FOUC`의 발생 원인은 다양하지만 몇 가지만 우선적으로 살펴보면 다음과 같다.\n\n### CRP(Critical Rendering Path)\n\n![Webkit](https://user-images.githubusercontent.com/24724691/62412567-bf49f200-b63f-11e9-9ed4-ec8215d04a7d.png)\n\n위처럼 브라우저에서 화면이 그려지기까지의 주요한 과정을 `CRP(Critical Rendering Path)`라고 한다.\n\n1. HTML 마크업을 처리하고 DOM 트리를 빌드한다.\n2. CSS 마크업을 처리하고 CSSOM 트리를 빌드한다.\n3. DOM 및 CSSOM을 결합하여 Rendering 트리를 형성한다.\n4. Rendering 트리에서 레이아웃을 실행하여 각 노드의 기하학적 형태(화면의 위치)를 계산한다.\n5. 개별 노드를 화면에 paint한다.\n\n`Render Tree`가 노출된 후 CSS와 JS 파일등으로 변경되면 이 변경 사항들이 화면에 노출될 수 있다. 이 현상이 `FOUC`다.\n\n웹 브라우저의 작동 원리에 대해 좀 더 자세히 알고 싶다면 [다음](https://github.com/im-d-team/Dev-Docs/blob/master/Browser/%EC%9B%B9%20%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80%EC%9D%98%20%EC%9E%91%EB%8F%99%20%EC%9B%90%EB%A6%AC.md)을 참고하길 바란다.\n\n최근의 웹 페이지들은 여러 개의 CSS 파일을 참조하거나 웹 폰트를 사용함으로써 DOM 구조를 변경하기 때문에 더욱 자주 발생할 수 있는 환경이다.\n\n### `@import`를 사용한 CSS \n\nIE(Internet Explorer)를 제외한 브라우저의 경우, 참조(`@import`)되는 스타일이 적용될때까지 화면에 표시하지 않는다. 하지만, IE의 경우 화면에 노출된 상태로 스타일이 적용되어 FOUC를 유발한다.\n\n### 웹 폰트의 사용\n\n이또한 `@import`를 사용하여 스타일링을 할 때와 같은 원리로 `FOUC`가 발생하게 된다. IE는 웹 폰트를 사용할 경우 기본 폰트를 불러들이고 이를 사용된 웹 폰트로 다시 재변경되게 되는데 이 과정을 그대로 화면에 노출시키게 된다.\n\n## FOUC 해결\n\n### JS import 위치 변경\n\n일반적으로 자바스크립트를 선언할 때는 성능을 위해 `</body>` 태그 바로 위에 위치시키곤 한다.\n하지만 이를 `<head>`태그 안으로 위치시킴으로써 `FOUC`를 개선할 수 있다. 하지만 이 방법으로는 웹 폰트나 `@import`를 사용한 CSS로 인한 `FOUC` 발생을 막을 수는 없다.\n\n### FOUC 발생 위치의 컴포넌트 숨기기\n\n`@import` 사용으로 인한, 웹 폰트로 인한 `FOUC`발생을 막기 위해서는 `FOUC`가 발생하는 위치의 컴포넌트를 숨겼다가 웹 폰트 혹은 참조(`@import`) CSS의 로딩이 완료되면 보여주는 방법이 있다. 물론, 숨기는 것은 한 예시일 뿐이고 로딩바를 보여준다거나 스켈레톤 UI를 보여준다거나 할 수 있다.\n\n```html\n<html class=\"no-js\">\n  <head>\n    <style>\n      .js #fouc {\n        display: none\n      }\n    </style>\n    <script>\n      (function (H) {\n        H.className = H.className.replace(/\\bno-js\\b/, 'js')\n      })(document.documentElement)\n      </script>\n  </head>\n\n  <body>\n    <div id=\"fouc\">\n      FOUC 발생 지점\n    </div> <!-- /#fouc -->\n    <script>\n      document.getElementById(\"fouc\").style.display = \"block\";\n    </script>\n  </body>\n</html>\n```\n[소스 출처 - webdir.tistory.com](https://webdir.tistory.com/416)\n\n위 소스에 대해 간단히 설명하면 자바스크립트와 CSS 스타일이 모두 로딩되었을 경우, `fouc` ID를 가진 컴포넌트를 렌더링시켜준다.\n\n`FOUC`의 발생은 최근에는 대부분 `IE`에서 발생하기 때문에 `IE`에 대해서만 분기 처리를 한 후 `FOUC`에 대한 처리를 하는 것도 좋은 방법이 될 수 있다.\n\n---\n\n#### Reference\n\n- [화면 깜빡임(FOUC) 문제해결](https://webdir.tistory.com/416)\n- [UZULAB - #3 FOUC, 화면 깜박임 문제](https://uzulab.tistory.com/4)\n"
  },
  {
    "path": "Browser/HTTP2_Websocket.md",
    "content": "# HTTP2.0과 Web Socket\n\n## HTTP란\n\nHTTP는 HyperText Transfer Protocol의 약자다. Request와 Response로 이루어진 통신 규약이다.\n\n이 HTTP의 단점 중 하나는 Request가 있어야만 Response가 존재한다는 점이다. 이 요청은 URL로 이루어져 새로운 요청을 보내려면 새로운 페이지가 필요하다. 예를들어 회원가입시 ID 중복확인을 하려면 새 페이지로 넘어가야 한다.\n\n또한 페이스북처럼 정보를 거의 실시간으로 확인 할 수 있는 SNS의 경우, 정보의 갱신이 매우 빠르게 일어나는데 이를 업데이트 하려면 항상 클라이언트의 Request가 필요하다. 만약 이 경우 서버의 정보가 갱신되지 않았다면 통신의 낭비가 일어나기도 한다.\n\nHTTP의 대표적인 단점으로는\n\n- 1개의 커넥션에 1개의 리퀘스트만 가능하다.\n- Request는 클라이언트 사이드에서만 시작할 수 있다.\n- 헤더가 압축되지 않는다.\n- 우선순위가 없다.\n\n등 다양하다.\n\n## 문제해결\n\n이러한 문제들중 몇가지를 해결하기 위해 등장한 것이 AJAX와 COMET방식이다.\n\n### AJAX\n\n---\n\n구글의 AJAX는 HTTP 통신을 사용은 하지만 HttpRequst가 아닌 XMLHttpRequest를 사용하여 새로운 HTML을 사용하지 않고 페이지의 일부만 수정할 수 있게 된다.\n\n### COMET\n\n---\n\nComet은 서버측의 데이터 갱신이 있을때 Request를 기다리지 않고 Response를 보내기 위한 방법이다. Comet의 경우 Request에 따른 Response를 반환하지 않고 보류해둔다. 그 뒤 서버의 데이터가 갱신되면 Response를 반환하는 방식이다. 롱폴링(long polling)방식이라고도 한다.\n\n위의 두가지 방법은 모두 프로토콜 레벨의 방법은 아니며 HTTP가 가진 근본적인 단점을 해결해 줄 수는 없다.\n\n## SPDY\n\n느린 HTTP를 해결하기 위해 나온 것이 SPDY다. 구글이 시도했던 실험 프로토콜이다. Page Load Time을 50%로 줄이기 위함이 목표였다.\n\n핵심적인 변화는 이러하다. 기존의 데이터는 플레인 텍스트로 통신을 하였는데 이를 바이너리로 인코딩하여 **프레임** 이라는 단위로 변경하여 전송한다. 즉 하나의 chunk에서 frame이라는 단위로 쪼개기가 가능해진다. 이를 통해 요청/응답 다중화, 우선순위 지정 및 헤더 압축이 목표였다.\n\n이게 2012년의 이야기이며 이를 본 HTTP-WG(HTTP Working Group)이 HTTP2.0을 만든다.\n\n이 HTTP2.0은 SPDY의 사양을 채택해 출발하게 되고 2015년 SPDY는 지원을 중단하며 HTTP2.0으로 사실상 통합되게 된다.\n\n## Web Socket\n\n2014년 HTML5의 등장과 함께 Web Socket이 등장한다.\n\nHTTP와 같이 Web Socket은 프로토콜이며 양방향 소통을 지원하는 프로토콜이다. HTTP가 가진 근본적인 문제 중 하나인 **Request는 클라이언트 사이드에서만 시작할 수 있다.** 를 완전히 해결할 수 있는 프로토콜이다.\n\n시작점은 클라이언트에게 있지만 처음 HTTP로 연결한 뒤 그 뒤로는 WebSocket 프로토콜을 이용하여 양쪽 모두 송신이 가능하게 된다.\n\n또한 처음 HTTP 통신 이후에는 헤더의 사이즈를 감소시켜 통신량을 줄이게 된다.\n\n## HTTP 2.0\n\nHTTP 2.0의 도입배경은 SPDY를 통해 소개를 했다.\n\n핵심적인 변화로는 Binary Framing부터 시작한다. 새로운 메커니즘으로 아래와 같은 구조를 가진다.\n\n- 스트림(바이트의 흐름)\n- 메시지(전체 시퀀스며 Request / Response의 단위다.)\n- 프레임(통신의 최소단위)\n\n프레임이 모여 메시지가 되고 메시지가 모여 스트림이 된다.\n\n장점을 알아보자\n\n### 요청 및 응답 다중화\n\n---\n\n프레임은 헤더나 메시지 페이로드 등을 전송하며 **인터리빙**이 가능하다. 즉 데이터를 읽을 때 순서대로가 아니게 읽는 것이 가능하며 대역폭 증가의 효과를 가진다.\n\n인터리빙으로 병렬처리가 가능해지면서 통신 단위의 변경이 가능해집니다.\n\nHTTP 1.0은 기존의 메시지가 단위였다면 2.0부터는 스트림이 단위가 된다. 따라서 동시에 여러 메시지를 처리할 수 있게 되고 Request의 순서와 상관없이 Response를 보낼 수 있게 되었다.\n\nHTML 파싱 시 여러 Request가 필요한데 이것의 순서가 없어져 Response를 기다려야하는 통신의 낭비가 사라진다.\n\n### 우선순위 지정\n\n---\n\n인터리빙에 따른 병렬처리로 서버와 클라이언트측에 각각 요청이 전달되는 순서가 성능 이슈로 떠오릅니다. 따라서 가중치를 통해 우선순위를 줄 수 있게 됩니다.\n\n### 서버푸쉬\n\n---\n\n서버푸쉬는 웹소켓과는 다른 개념이다.\n\n예를들어 초기 페이지에 index.html만이 아니라 많은 css, js, image파일과 같은 추가적인 리소스가 필요하다면 이를 클라이언트가 요청하지 않아도 서버가 푸쉬할 수 있는 방식이다.\n\n### 헤더압축\n\n---\n\n기존의 HTTP는 헤더를 항상 일반텍스트로 보냈다.\n이를 HTTP 2.0에서는 HPACK 압축방식을 이용하여 보내게끔 되어있다.\n"
  },
  {
    "path": "Browser/IndexedDB_WebSQL.md",
    "content": "# IndexDB WebSQL\n\n데이터 저장소는 서버 DB를 사용해서 데이터를 저장하고 꺼내서 보여줄 수 있도록 데이터를 저장하는 공간이다. 이러한 데이터를 저장할 수 있는 공간이 브라우저에도 존재하는데 이것을 통틀어서 스토리지라고 부른다. \n\n스토리지에는 여러 종류가 존재하는데 로컬 스토리지, 세션 스토리지, 쿠키, indexedDB, Web SQL 이렇게 5가지가 존재한다. 그중에서 오늘 살펴볼 내용은 **indexedDB와 Web SQL이다.**\n\n나머지 3가지에 대해 알아보길 원하면 아래의 링크를 확인하면 됩니다.\n\n> [Cookie, Local Storage](https://github.com/SeonHyungJo/FrontEnd-Dev/blob/master/Browser/Cookie_Storage_Local.md)\n\n<br/>\n\n## IndexedDB\n\n먼저 어디서 볼 수 있나?\n\n개발자들이 많이 사용하는 브라우저 중 하나인 크롬을 열어서 Dev Tool을 열고 Application 탭에 들어가면 좌측에 좀 전에 말했던 5가지의 저장소가 있는 것을 볼 수 있다.\n\n그중에서 우리가 보려는 **IndexedDB**도 있다. \n\nIndexedDB는 새로 등장했다고 하기에는 오래되었는데 2009년 말경 Web SQL의 대안으로 탄생했다. 즉 현재 Web SQL은 사양 책정이 중지된 상태이다. IndexedDB는 자바스크립트 객체 단위의 데이터 저장이 용이하고 객체를 대상으로 인덱스를 걸 수 있어 간단한 구현과 효율적인 검색을 수행할 수 있다.\n\n> `많은 양의 구조화된 데이터를 클라이언트 측에 저장하기 위한 저수준의 API` - Mozilla\n\nIndexedDB는 SQL언어와 무관하며 단순한 저장구조(Key-Value Storage)를 갖추고 있다. 간단한 자바스크립트 API만으로도 데이터베이스 조작이 가능하며, 브라우저 친화적이고 표준화 작업을 쉽게 이끌 수 있다는 장점이 있다. 결국 모바일 환경에서의 가벼운 로컬 DB 컨셉은 관계형 DB보다는 IndexedDB와 같은 객체기반의 비 관계형 DB가 더 어울린다고 할 수 있다.\n\n흔히 PWA에서, IndexedDB를 사용해서 어떻게 오프라인 기반의 애플리케이션을 만들 수 있는지 자세하게 다루고 있다.\n\n> [Progressive Web App용 오프라인 저장소](https://developers.google.com/web/fundamentals/instant-and-offline/web-storage/offline-for-pwa?hl=ko)\n\n- IndexedDB는 브라우저에 많은 양의 구조화된 데이터를 영구적으로 저장할 수 있으며, 네트워크 상태에 상관없이 여러 기능을 사용할 수 있다. (최대 하드디스크의 50%라고 한다. => 실제로 컴퓨터의 하드디스크 50%를 채울 수 있는지에 대한 테스트를 진행하지 못했습니다.)\n- IndexedDB는 서비스 워커를 사용한다면 동기적으로 사용이 가능하나 그렇지 않을 경우는 비동기가 기본이다. 그래서 대부분은 Promise로 만들어진 라이브러리를 사용한다. - [idb](https://www.npmjs.com/package/idb)\n\n<br/>\n\n## 실제로 사용해보기\n\n### 브라우저 지원여부확인\n\n```js\nif (!window.indexedDB) {\n    console.log(\"Your browser doesn't support a stable version of IndexedDB. Such and such feature will not be available.\")\n}\n```\n\n<br/>    \n\n### 데이터베이스 열기\n\n기본적으로 비동기로 작동을 하며, 작동의 결과를 4가지의 콜백 이벤트로 전달받는다.\n\n- success : 데이터베이스 연결 성공\n- error : 데이터베이스 연결 실패\n- upgradeneeded : 데이터베이스를 처음 만들거나, 데이터베이스 버전이 변경되었을 때 작동하는 함수\n- blocked : 이전의 연결을 닫지 않았을 경우 실행됨(이번에 사용하지 않을 예정)\n\n```js\n// indexedDB 지원유무\nif (\"indexedDB\" in window) {\n  idbSupported = true;\n}\n\nif (idbSupported) {\n  // indexedDB 열기\n  const openRequest = indexedDB.open(\"test\", 1);\n\n  openRequest.onupgradeneeded = function (e) {\n    console.log(\"Upgrading\");\n  }\n\n  openRequest.onsuccess = function (e) {\n    console.log(\"Success!\");\n    db = e.target.result;\n  }\n\n  openRequest.onerror = function (e) {\n    console.log(\"Error\");\n    console.dir(e);\n  }\n}\n```\n\n### 처음 접속시\n\n처음 접속 시 `onupgradeneeded`를 타게 되며 이후 버전업이 이루어지지 않는 한 실행되지 않는다.\n\n![image](https://user-images.githubusercontent.com/24274424/59140159-18e1c780-89d5-11e9-99d3-896ca66b2a9b.png)\n\n### 2번째 접속시\n\n![image](https://user-images.githubusercontent.com/24274424/59140161-1bdcb800-89d5-11e9-9fa6-3f5ed4bf073b.png)\n\n### 에러 발생시\n\n![image](https://user-images.githubusercontent.com/24274424/59140165-1e3f1200-89d5-11e9-90e6-3c0b21cbf9c6.png)\n\n### Object Stores(객체 저장소)\n\n위에서 말했듯이 IndexedDB의 컨셉은 객체 저장소이다. \n\n```js\nif (\"indexedDB\" in window) {\n  idbSupported = true;\n}\n\nif (idbSupported) {\n  const openRequest = indexedDB.open(\"test_2\", 1);\n\n  openRequest.onupgradeneeded = function (e) {\n    console.log(\"running onupgradeneeded\");\n    const thisDB = e.target.result;\n    if (!thisDB.objectStoreNames.contains(\"testBox\")) {\n      thisDB.createObjectStore(\"testBox\");\n    }\n  }\n\n  openRequest.onsuccess = function (e) {\n    console.log(\"Success!\");\n    db = e.target.result;\n  }\n\n  openRequest.onerror = function (e) {\n    console.log(\"Error\");\n    console.dir(e);\n  }\n}\n```\n\n<br/>\n\n### 데이터 추가하기\n\n데이터를 조작하기 위해서는 `transaction`을 사용해야한다. transaction는 2개의 인자를 받는데 첫번째는 우리가 조작할 테이블이 `Array`로 들어가며, 두번째 인자는 `readonly`, `readwrite` 둘 중의 1개로 타입을 명시해준다.\n\n`const transaction = db.transaction([\"people\"], \"readwrite\");` \n\n`const store = transaction.objectStore(\"people\");`\n\n```html\n<!doctype html>\n<html>\n<head>\n</head>\n<body>\n  <input type=\"text\" id=\"name\" placeholder=\"Name\"><br />\n  <input type=\"email\" id=\"email\" placeholder=\"Email\"><br />\n  <button id=\"addButton\">Add Data</button>\n</body>\n<script>\n    let db;\n\n    function indexedDBOk() {\n      return \"indexedDB\" in window;\n    }\n\n    document.addEventListener(\"DOMContentLoaded\", function () {\n\n      //indexedDB 지원 유무\n      if (!indexedDBOk) return;\n      //idarticle_people 네임인 DB생성.\n      const openRequest = indexedDB.open(\"idarticle_people\", 1);\n      openRequest.onupgradeneeded = function (e) {\n        const thisDB = e.target.result;\n        // people ObjectStore 생성(테이블이라고 생각하면 될것 같음..)\n        if (!thisDB.objectStoreNames.contains(\"people\")) {\n          thisDB.createObjectStore(\"people\");\n        }\n      }\n\n      openRequest.onsuccess = function (e) {\n        console.log(\"running onsuccess\");\n        db = e.target.result;\n\n        //Listen for add clicks\n        document.querySelector(\"#addButton\").addEventListener(\"click\", addPerson, false);\n      }\n\n      openRequest.onerror = function (e) {\n      }\n    }, false);\n\n    function addPerson(e) {\n      const name = document.querySelector(\"#name\").value;\n      const email = document.querySelector(\"#email\").value;\n\n      console.log(\"About to add \" + name + \"/\" + email);\n      //people 테이블에 데이터 add 선언..\n      const transaction = db.transaction([\"people\"], \"readwrite\");\n      const store = transaction.objectStore(\"people\");\n\n      //Define a person\n      const person = {\n        name: name,\n        email: email,\n        created: new Date()\n      }\n\n      //Perform the add\n      const request = store.add(person, 1);\n\n      request.onerror = function (e) {\n        console.log(\"Error\", e.target.error.name);\n        //some type of error handler\n      }\n\n      request.onsuccess = function (e) {\n        console.log(\"Woot! Did it\");\n      }\n    }\n  </script>\n\n</html>\n```\n\n위의 경우는 2번째 추가를 하게 될 경우 키가 같아서 에러가 발생한다.\n\n![image](https://user-images.githubusercontent.com/24274424/59140257-1d5ab000-89d6-11e9-97b2-6200c263f278.png)\n\n<br/>\n\n### Keys\n\n키를 지정하는 것은 총 3가지의 방법이 있다. \n\n1. 위에서처럼 직접 명시하는 것이다. 자신이 직접 만든 로직으로 **unique한 키**를 만들 수 있다.\n2. **keypath**를 사용하는 것으로, 데이터 자체의 속성을 기반으로 하는 방법이다.\n3. 우리가 많이 알고 제일 쉬운 방법으로 키 생성기를 사용하는 것이다. 자동 번호 기본키와 매우 유사하며 키를 지정하는 가장 간단한 방법이다.\n\n```js\n// second option : keypath\nthisDb.createObjectStore(\"test1\", { keyPath : \"email\" });\n// third option : key generator\nthisDb.createObjectStore(\"test2\", { autoIncrement : true });\n```\n\n<br/>\n\n### 데이터 읽기\n\n아래의 예제는 개별 데이터를 읽는 방법이다. 테이블로 말하면 하나의 row만 갖고 오는 것이다.\n\n```js\n// db에서 test 객체(테이블)을 읽는다고 선언.\nconst transaction = db.transaction([\"test\"], \"readonly\");\nconst objectStore = transaction.objectStore(\"test\");\n\n//x is some value\nconst ob = objectStore.get(x);\n\n// 가져오는 것을 성공했을 경우\nob.onsuccess = function(e) {\n  consoel.log(e.target.result)\n}\n\n// 한줄로 만들기\n// db.transaction([\"test\"], \"readonly\").objectStore(\"test\").get(X).onsuccess = function(e) { }\n```\n\n<br/>\n\n### 범위 조회\n\n범위조회를 위해서는 `createIndex`가 선행되어야한다.\n\n```js\nconst store = thisDB.createObjectStore(\"people\", { autoIncrement: true });\nstore.createIndex(\"name\",\"name\", {unique:false});\n\n```\n\n```js\n//Values over 39\nconst oldRange = IDBKeyRange.lowerBound(39);\n//Values 40a dn over\nconst oldRange2 = IDBKeyRange.lowerBound(40,true);\n//39 and smaller...\nconst youngRange = IDBKeyRange.upperBound(40);\n//39 and smaller...\nconst youngRange2 = IDBKeyRange.upperBound(39,true);\n//not young or old\nconst okRange = IDBKeyRange.bound(20,40)\n```\n\n```js\nfunction getPeople(e) {\n    const name = document.querySelector(\"#nameSearch\").value;\n    const endname = document.querySelector(\"#nameSearchEnd\").value;\n\n    if(name == \"\" && endname == \"\") return;\n\n    const transaction = db.transaction([\"people\"],\"readonly\");\n    const store = transaction.objectStore(\"people\");\n    const index = store.index(\"name\");\n\n    let range;\n    if(name != \"\" && endname != \"\") {\n        range = IDBKeyRange.bound(name, endname);\n    } else if(name == \"\") {\n        range = IDBKeyRange.upperBound(endname);\n    } else {\n        range = IDBKeyRange.lowerBound(name);\n    }\n\n    let s = \"\";\n\n    index.openCursor(range).onsuccess = function(e) {\n        const cursor = e.target.result;\n\n        if(cursor) {\n            s += \"<h2>Key \"+cursor.key+\"</h2><p>\";\n            for(var field in cursor.value) {\n                s+= field+\"=\"+cursor.value[field]+\"<br/>\";\n            }\n            s+=\"</p>\";\n            cursor.continue();\n        }\n\n        document.querySelector(\"#status\").innerHTML = s;\n    }\n}\n```\n\n### Can I use...\n\n![image](https://user-images.githubusercontent.com/24274424/59140311-c73a3c80-89d6-11e9-99e2-3eb5f947aade.png)\n\n<br/>\n\n## WebSQL\n\nWebSQL은 **클라이언트 측의 관계형 데이터베이스를 위한 API**로, SQLite와 유사하다. 2010년 이후로 W3C 웹 어플리케이션 워킹 그룹은 이 스펙에 대한 작업을 중단했다. WebSQL은 이제 더이상 HTML 스펙이 아니므로, 사용하지 말자\n\n<br/>\n\n#### Reference\n\n- [https://github.com/wonism/TIL/blob/master/front-end/javascript/client-storage.md](https://github.com/wonism/TIL/blob/master/front-end/javascript/client-storage.md)\n- [https://iamawebdeveloper.tistory.com/99](https://iamawebdeveloper.tistory.com/99)\n- [https://code-examples.net/ko/docs/dom/indexeddb_api](https://code-examples.net/ko/docs/dom/indexeddb_api)\n- [https://dongwoo.blog/2016/12/19/클라이언트-측의-저장소-살펴보기/](https://dongwoo.blog/2016/12/19/%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8-%EC%B8%A1%EC%9D%98-%EC%A0%80%EC%9E%A5%EC%86%8C-%EC%82%B4%ED%8E%B4%EB%B3%B4%EA%B8%B0/)"
  },
  {
    "path": "Browser/Layer_Model.md",
    "content": "# Layer Model\n\n브라우저의 layer model에 대해 알아보자.\n\n## layer란\n\n브라우저는 크게 layer를 두가지로 분류한다.\n\n- RenderLayer\n- GraphicsLayer\n\n### RenderLayer\n\n렌더 레이어는 DOM의 subTree에 대응되는 [rendering critical path](https://github.com/Im-D/Dev-Docs/blob/master/Browser/%EC%9B%B9%20%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80%EC%9D%98%20%EC%9E%91%EB%8F%99%20%EC%9B%90%EB%A6%AC.md#rendering-engine)의 render tree(frame tree)의 결과를 말한다.\n\n### GraphicsLayer\n\n그래픽스 레이어는 그 외의 레이어를 말한다. 이 글에서 render layer는 크게 중요하지 않으니 그래픽스 레이어만 다루도록 하자.\n\n그래픽스 레이어는 GPU에 텍스쳐로 업로드된다.(GraphicsLayers are what get uploaded to the GPU as textures)\n\n이 GPU의 텍스쳐에 대해 조금 알아보자.\n\n#### GL - GPU\n\ntexture는 RAM(주기억장치)에서 GPU의 VRAM(비디오메모리)으로 이동하는 image라고 생각하면 된다.\nimage가 GPU에 올라가게 되면 mesh geometry라는 것과 매핑된다.\n\n이 mesh는 아래 그림처럼 3차원 모델을 만들 때 다각형의 집합으로 이루어진 모델같은 것이다.\n\n![mesh](https://user-images.githubusercontent.com/24724691/59143838-5876d680-8a0a-11e9-84d0-298b28d622be.png)\n\n[출처: unity documentation](https://docs.unity3d.com/kr/current/Manual/class-Mesh.html)\n\n#### layer-texture\n\n크롬은 각 그래픽스 레이어를 texture로 취급하여 GPU에 올린다.\n\n즉 한 장의 image 파일처럼 취급하여 GPU에게 위임한다.\nGPU에서 texture는 사각형의 메쉬로 만들어진다.\n그래서 layer의 position을 수정한다거나 변형(transformation)하는 경우 매우 저렴한 비용으로 매핑될 수 있다.\n\n3D CSS는 이러한 방식으로 작동한다.\n\n## layer 생성 기준\n\n이러한 layer가 생성되는 기준은 다음과 같다.\n\n- 3D나 perspective를 표현하는 CSS transform 속성을 가진 경우\n- 하드웨어 가속 디코딩을 사용하는 <video> 엘리먼트\n- 3D 컨텍스트(WebGL) 혹은 하드웨어 가속 2D 컨텍스트를 가지는 <canvas> 엘리먼트\n- (플래시와 같은) 플러그인 영역\n- 투명도(opacity) 속성 혹은 webkit transform의 애니메이션의 사용\n- 가속 가능한 CSS 필터를 가진 경우[css filter](https://developer.mozilla.org/en-US/docs/Web/CSS/filter)\n- 합성 레이어(Compositing Layer)를 하위 노드로 가진 경우\n- 낮은(lower) z-index를 가진 형제 노드(Sibling)가 합성 레이어(Compositing Layer)를 가진 경우\n\n## layer 눈으로 확인하기\n\nlayer를 확인하는 가장 좋은 방법은 개발자 도구를 이용하는 것이다.\n개발자 도구를 열어서 rendering - layer borders 옵션을 켜면 오렌지색 테두리로 레이어를 보여준다.\n\n### 단일 layer\n\n```html\n<!DOCTYPE html>\n<html>\n  <body>\n    <div>this is single layer</div>\n  </body>\n</html>\n```\n\n![singleLayer](https://user-images.githubusercontent.com/24724691/59145371-e9a37880-8a1d-11e9-9359-9c6c73fc7437.PNG)\n\n### transform 사용하여 layer 나누기\n\ncss transform 속성을 사용하면 layer가 나뉘게 된다.\n\n```html\n<!DOCTYPE html>\n<html>\n  <body>\n    <div style=\"transform: rotateY(30deg) rotateX(-30deg); width: 200px;\">\n      this is detached layer\n    </div>\n  </body>\n</html>\n```\n\n![transformLayer](https://user-images.githubusercontent.com/24724691/59145396-41da7a80-8a1e-11e9-8f5f-6abac2af8ce1.PNG)\n\ntransform을 사용하면 div와 body가 구분되어 layer를 가지는 것을 확인 할 수 있다.\n\n### animation\n\nlayer를 분리하면 가장 좋은 점은 reflow(relayouting)와 repaint를 하지 않는다는 점이다.\n\n```html\n<!DOCTYPE html>\n<html>\n  <head>\n    <style>\n      div {\n        animation-duration: 5s;\n        animation-name: slide;\n        animation-iteration-count: infinite;\n        animation-direction: alternate;\n        width: 200px;\n        height: 200px;\n        margin: 100px;\n        background-color: gray;\n      }\n      @keyframes slide {\n        from {\n          transform: rotate(0deg);\n        }\n        to {\n          transform: rotate(120deg);\n        }\n      }\n    </style>\n  </head>\n  <body>\n    <div>this is animation</div>\n  </body>\n</html>\n```\n\n![animation](https://user-images.githubusercontent.com/24724691/59145581-da71fa00-8a20-11e9-855f-b83835a20aee.gif)\n\n위 사진에서는 초록색 부분이 페인트다.\n레이어가 분리되어 다르게 동작하기때문에 paint는 처음에만 일어나며 다시 일어나지 않는다.\n\n### reflow repaint\n\n```html\n<!DOCTYPE html>\n<html>\n  <head>\n    <style>\n      div {\n        animation-duration: 5s;\n        animation-name: slide;\n        animation-iteration-count: infinite;\n        animation-direction: alternate;\n        width: 200px;\n        height: 200px;\n        margin: 100px;\n        background-color: gray;\n      }\n      @keyframes slide {\n        from {\n          transform: rotate(0deg);\n        }\n        to {\n          transform: rotate(120deg);\n        }\n      }\n    </style>\n  </head>\n  <body>\n    <div id=\"foo\">I am a strange root.</div>\n    <input id=\"paint\" type=\"button\" value=\"repaint\" />\n    <script>\n      var w = 200;\n      document.getElementById('paint').onclick = function() {\n        document.getElementById('foo').style.width = w++ + 'px';\n      };\n    </script>\n  </body>\n</html>\n```\n\n다음의 코드는 버튼을 클릭하면 1px씩 증가한다.\n\n따라서 화면을 재 계산해야 하기 때문에 reflow(relayouting) 후 repaint를 하게 된다.\n\n위 코드는 직접 개발자도구를 실행시켜 확인해보자.\n\n## 종합\n\n레이아웃을 중심으로 브라우저가 DOM을 렌더링 하는 과정은 다음과 같다.\n\n1. DOM을 얻고 그것들을 레이어들로 분리합니다.\n2. 이 레이어들 각각을 독립적인 소프트웨어 비트맵으로 출력합니다.\n3. 그것들을 GPU에 텍스쳐로써 업로드합니다.\n4. 다양한 레이어를 최종 스크린 이미지로 함께 합성(composite)합니다.\n\n강제로 레이어를 분리하여 코딩하면 repaint를 일으키지 않고 동작하기 때문에 성능에 매우 유리하다.\n\n좋은 예로는 [네이버 모바일페이지](https://m.naver.com/)에서 화면을 좌/우로 변경하면서 layer를 확인해보자.\n\n처음에만 paint를 하고 그 뒤로는 layer만 변경되는 것을 찾아볼 수 있다.\n\n### 단점\n\n만능은 아니다.\n\n당연히 레이어별로 메모리를 다르게 할당한다.\n\n또한 GPU의 video memory는 RAM과 물리적으로 다른 공간에 위치한다.\n따라서 texture를 옮기는 데이터 송수신의 손실도 발생한다.\n\n또한 RAM => VRAM으로 이동하려면 결국 CPU -> RAM에서 texture 로드 -> GPU VRAM으로 전송의 과정이 필요하다.\n\nCPU가 연산하지 않으면 안된다. CPU가 직접 처리하지 않을 뿐 CPU가 작동하지 않는 것은 아니다.\n\ntexture 데이터를 다루는 시간도 고려해야 한다.\n\n---\n\n### 참고자료\n\n- [프론트엔드 개발자를 위한 크롬 렌더링 성능 인자 이해하기](https://medium.com/@cwdoh/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%A5%BC-%EC%9C%84%ED%95%9C-%ED%81%AC%EB%A1%AC-%EB%A0%8C%EB%8D%94%EB%A7%81-%EC%84%B1%EB%8A%A5-%EC%9D%B8%EC%9E%90-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0-4c9e4d715638)\n- [Accelerated Rendering in Chrome](https://www.html5rocks.com/en/tutorials/speed/layers/)\n- [Unity documentation](https://docs.unity3d.com/Manual/index.html)\n"
  },
  {
    "path": "Browser/WebWorker.md",
    "content": "# Web Worker\n\n`WebWorker`는 `script` 실행을 메인 쓰레드가 아니라 백그라운드 쓰레드에서 실행할 수 있도록 해주는 기술이다.\n\n이 기술을 통해 무거운 작업을 분리된 쓰레드에서 처리할 수 있다. 브라우저에서 메인쓰레드라 함은 Rendering을 처리하는 UI쓰레드를 말하는데, 이를 통해 메인 쓰레드가 멈추거나 속도저하 없이 동작할 수 있다.\n\n다음과 같은 작업들을 백그라운드에서 실행하여 더욱 증가한 UX를 제공할 수 있다.\n\n- 매우 복잡한 계산 작업\n- 원격리소스에 대한 액세스 작업\n- UI 쓰레드에 방해 없이 지속적으로 수행해야 하는 작업(timer, pusher, parser)\n\n## WebWorker의 개념\n\nWorker는 `Worker()` 생성자를 통해 생성되며 지정된 Javascript 파일의 코드를 Worker 쓰레드에서 실행한다. Worker는 현재 `Window` 와 분리된 `DuplicatedWorkerGlobalScope` 라는 별도의 `Global context` 에서 동작한다.\n\nWorker 쓰레드에서 어떠한 코드도 실행할 수 있지만, 몇가지 예외가 있다.\n\n예를들어 Worker 내에서는 `DOM` 을 직접 다룰 수 없다. 또한 `Window` 의 기본 메서드와 속성을 사용할 수 없다. 메인쓰레드와 자원을 공유하기 때문이다.\n\n### 사용예시\n\nMessage System을 통해 Worker 와 메인 쓰레드 간에 데이터를 교환할 수 있다.\n\n```html\n<div id=\"result\"></div>\n<button id=\"btn\">run</button>\n<script>\n  const sleep = (delay) => {\n    const start = new Date().getTime();\n    while (new Date().getTime() < start + delay);\n  };\n\n  document.querySelector('#btn').addEventListener('click', function () {\n    sleep(3000);\n    const div = document.createElement('div');\n    div.textContent = Math.random();\n    document.querySelector('#result').appendChild(div);\n  });\n</script>\n```\n\n`sleep()`의 while이 메인 쓰레드의 콜스택을 점유하기 때문에 3000ms 가 되기 전까지는 다른 작업을 진행 할 수 없다.\n\n```html\n<div id=\"result\"></div>\n<button id=\"btn\">run</button>\n<script>\n  document.querySelector('#btn').addEventListener('click', () => {\n    const worker = new Worker('./worker.js');\n    worker.addEventListener('message', (e) => {\n      const div = document.createElement('div');\n      div.textContent = e.data;\n      document.querySelector('#result').appendChild(div);\n      worker.terminate();\n    });\n    worker.postMessage('워커작동 시작');\n  });\n</script>\n```\n\n```js\n// worker.js\nconst sleep = (delay) => {\n  const start = new Date().getTime();\n  while (new Date().getTime() < start + delay);\n};\n\nself.onmessage = (e) => {\n  console.log(e.data);\n  sleep(3000);\n  const random = Math.random();\n  console.log(random);\n  self.postMessage(random);\n};\n```\n\n이렇게 변경하면 3초를 점유하는 작업은 다른 쓰레드에서 진행하기 때문에 메인쓰레드에는 영향을 주지 않게 된다.\n\n`Worker.postMessage()`를 통해 데이터를 전송할 수 있으며, `Worker.onmessage()` 를 통해 응답할 수 있다. 전송되는 데이터는 공유되지 않으며 복제를 통해 전달되게 된다.\n\n부모와 동일한 origin이라면 Worker내에서 새로운 Worker를 생성하는 것도 가능하다. 또한 이렇게 생겨난 Worker들끼리 서로 통신하는 것 역시 가능하다.\n\n### 유형\n\n- Dedicated Worker\n  - 헌신하는 전용 Worker다. 아래의 Shared Worker와 대비된다.\n- Shared worker\n  - 윈도우 창이나 iframe, Worker등의 다른 브라우징 컨텍스트에서도 공유되는 Worker다.\n  - 이름 혹은 URL로 식별된다. Socket 통신처럼 Worker들은 port를 할당받고 이를 통해 통신한다.\n  - `new SharedWorker()`로 생성하며 공유하는 전역 스코프를 가진다.\n  - [MDN SharedWorker](https://developer.mozilla.org/ko/docs/Web/API/SharedWorker) \n- ServiceWorker\n  - Proxy Server의 역할을 한다. \n  - 효율적인 오프라인 경험을 구축하고, 네트워크 요청을 가로채어 통신이 가능한지 여부에 따라 적절한 동작을 수행하며, 서버에 존재하는 자원들을 갱신할 수 있다.\n  - 푸시 알림이나 백그라운드 동기화 API에 접근을 허용한다.  \n- Audio Workers\n  - 스크립트를 통해 직접적인 오디오 처리만을 담당하는 Worker다.\n  - 단순한 오디오 출력만이 아니라 Audio API를 이용하여 오디오에 이펙트를 추가하거나 시각화와 같은 작업으로 오디오 객체를 조작할 수 있다.\n  - [MDN Web Audio API](https://developer.mozilla.org/ko/docs/Web/API/Web_Audio_API) \n\n현재 브라우저 지원범위는 [여기](http://caniuse.com/#search=webworker)에서 확인 할 수 있는데, 거의 모든 현대 브라우저에서 작동한다.\n\n---\n\n#### Reference\n\n- [MDN-WebWorker](https://developer.mozilla.org/ko/docs/Web/API/Web_Workers_API)\n- [MDN 예제](https://github.com/mdn/simple-web-worker)\n- [Shared Worker 블로그](https://m.blog.naver.com/sef16/70163116505)\n- [google developers - serviceworker](https://developers.google.com/web/fundamentals/primers/service-workers?hl=ko)\n- [웹 워커-zerocho](https://www.zerocho.com/category/HTML&DOM/post/5a85672158a199001b42ed9c)\n"
  },
  {
    "path": "Browser/Worklet.md",
    "content": "# Worklet\n\n## Worklet이란\n\n> Worklet 인터페이스는 Web Workers의 경량 버전이며 개발자가 렌더링 파이프 라인의 하위 수준에 접근할 수 있도록 해준다. \n> Worklet을 사용하면 JavaScript 및 WebAssembly 코드를 실행하여 고성능이 필요한 경우 그래픽 렌더링 또는 오디오 처리를 수행 할 수 있다. - MDN\n\n- 기본적으로 Worker는 한 Thread에 하나가 생성이 가능하지만, Worklet은 한 Thread에 여러 개 생성이 가능합니다.\n- 메인 Thread에서 만들 수 있습니다.\n- 독립적인 GlobalScope와 Event loop를 가집니다.\n\n### Worklet Type\n\n- **PaintWorklet**\n- **LayoutWorklet**\n- AnimationWorklet\n- AudioWorklet\n\n그리고\n\n- Typed OM \n  \n## Houdini\n\n- Houdini(후디니)라는 Working Group입니다.\n- Houdini 프로젝트는 Mozilla, Apple, Opera, Microsoft, HP, Intel 그리고 Google의 엔지니어들로 구성되어있습니다.\n- 이 프로젝트는 공식 W3C 표준으로 채택되기 위한 *표준 초안*들을 작성하고 있습니다..\n- \"Houdini\"라 하면 표준 문서들의 내용을 의미합니다. 표준안 개발 작업이 진행되는 동안 [Houdini 표준안 초안](http://dev.w3.org/houdini/)들은 미완성 단계이며 일부 초안은 다소 가안입니다.\n\n## 들어가기전에\n\n- `Chrome://flag` ⇒  `Experimental Web Platform features` => `Enable`\n\n## CSS Painting API\n\nCSS Painting API를 사용하게 되면 CSS 속성 중 이미지 타입에 사용할 수 있는 모양을 정의할 수 있습니다.\n\nImage Type?\n\n- [background-image](https://googlechromelabs.github.io/houdini-samples/paint-worklet/parameter-checkerboard/)\n- [border-image](https://googlechromelabs.github.io/houdini-samples/paint-worklet/border-color/)\n- list-style-image\n\n이 중 background-image속성을 사용하면 CSS가 적용된 대상이 그려지는 모양을 정의할 수 있습니다.\n\n```css\n.slide-checkbox{\n  background-image: paint(slide);\n}\n```\n\nPaint는 대상을 그리는 방법을 다루는 단계입니다.\n\n![rendering-pipline](https://user-images.githubusercontent.com/24274424/66269511-2ffdcc80-e884-11e9-9684-ea3035cb46ce.png)\n\n위의 렌더링 파이프라인은 **Chrome** 기준이며 브라우저에 따라 차이가 있을 수 있습니다.\n\nCSS Painting API는 Worklet의 형태로 개발자가 정의한대로 대상을 그리는 코드를 추가합니다.\n\n![rendering-pipline2](https://user-images.githubusercontent.com/24274424/66278813-af70b780-e8e7-11e9-8cc7-29bc4d56ac03.png)\n\n위에서 언급했듯이 Worklet은 Worker의 경량 버전이라고도 합니다.\n\n하지만 Worker와는 다르게 한 스레드에 여러개가 생성될 수 있고, 메인 스레드에서 실행될 수 있습니다.\n\n![threadInWorklet](https://user-images.githubusercontent.com/24274424/66278723-eb574d00-e8e6-11e9-9841-eb4e1a909950.png)\n\nWorklet은 독립적인 GlobalScope와 Event Loop를 가지고 있습니다.\n\n![image](https://user-images.githubusercontent.com/24274424/66278789-84866380-e8e7-11e9-91e0-9137bba2fd5d.png)\n\n결국, 그려야 할 대상이 많거나, 성능이 필요한 경우에 여러 개의 Thread에서 병렬로 동작할 수 있게 합니다.\n\n## 기본 형태\n\n독립적인 파일을 만들어서 addModule을 하는 형태입니다.\n\n```js\nCSS.paintWorklet.addModule(\"slideWorklet.js\")\n```\n\n위의 파일을 js class로 작성을 하며 `registerPaint`를 사용하여 해당 paint를 등록합니다.\n\n```js\nclass Slide {\n  static get inputArguments() { \n    return [];\n  }\n\n  static get inputProperties() {\n    return [];\n  }\n\n  paint(ctx, geom, props, args){\n  }\n}\n\nregisterPaint(\"slide\", Slide);\n```\n\npaint method에는 기본 4가지의 인자가 있습니다.\n\n- ctx : PaintRenderingContext2D 객체로, 대상이 어떻게 그려질지 표현합니다.\n- geom : 대상의 가로, 세로 크기정보입니다.\n- props : 대상에게 적용된 스타일 정보입니다.\n- args : CSS에서 전달한 값을 입력받습니다.\n\nprops와 args는 각각 `inputProperties()`, `inputArguments()`를 사용하여 입력받을 값(속성명)을 지정하여야 합니다. \n\n### 예제\n\n**index.html**\n```html\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  <meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">\n  <link rel=\"stylesheet\" href=\"index.css\">\n  <script src=\"index.js\"></script>\n  <title>Document</title>\n</head>\n\n<body>\n  <input type=\"checkbox\" class=\"switch\">\n\n  <label class=\"switch\">\n    <input type=\"checkbox\">\n    <span class=\"slider round\"></span>\n  </label>\n</body>\n```\n\n**index.js**\n```js\nCSS.registerProperty({\n  name: '--slide-on',\n  syntax: '<number>',\n  inherits: true,\n  initialValue: \"0\"\n});\nCSS.paintWorklet.addModule(\"slideWorklet.js\")\n```\n\n**index.css**\n```css\n/* CSS Paint API */\n.slide-checkbox{\n  background-image: paint(slide);\n  display: block;\n  color: green;\n  width: 60px;\n  height: 34px;\n  --slide-on : 0;\n  -webkit-appearance: none;\n  transition: --slide-on 200ms\n}\n\n.slide-checkbox:checked{\n  --slide-on : 1;\n  background-image: paint(slide);\n}\n\n\n/* Custom Checkbox for CSS */\n.switch {\n  position: relative;\n  display: inline-block;\n  width: 60px;\n  height: 34px;\n}\n\n.switch input { \n  opacity: 0;\n  width: 0;\n  height: 0;\n}\n\n.slider {\n  position: absolute;\n  cursor: pointer;\n  top: 0;\n  left: 0;\n  right: 0;\n  bottom: 0;\n  background-color: #ccc;\n  -webkit-transition: .2s;\n  transition: .2s;\n}\n\n.slider:before {\n  position: absolute;\n  content: \"\";\n  height: 28px;\n  width: 28px;\n  left: 3px;\n  bottom: 3px;\n  background-color: white;\n  -webkit-transition: .2s;\n  transition: .2s;\n}\n\ninput:checked + .slider {\n  background-color: #2196F3;\n}\n\ninput:focus + .slider {\n  box-shadow: 0 0 1px #2196F3;\n}\n\ninput:checked + .slider:before {\n  -webkit-transform: translateX(26px);\n  -ms-transform: translateX(26px);\n  transform: translateX(26px);\n}\n\n.slider.round {\n  border-radius: 34px;\n}\n\n.slider.round:before {\n  border-radius: 50%;\n}\n```\n\n**slideWorklet.js**\n```js\nconst DEG_360 = Math.PI * 2;\nconst FG_COLOR = \"white\";\nconst BG_COLOR = \"#E1E1E1\";\nconst BG_COLOR_ON = \"#FFCD00\";\nconst CIRCLE_MARGIN = 3;\n\nclass Slide {\n  // static get inputArguments() { \n  //   return ['on|off'];\n  // }\n\n  static get inputProperties() {\n    return ['--slide-on'];\n  }\n\n  paint(ctx, geom, props, args){\n    const {width, height} = geom;\n    const halfOfCircleSize = height / 2;\n    const innerWidth = width - height;\n    const on = parseFloat(props.get('--slide-on')).toString();\n    const x = halfOfCircleSize + innerWidth * on\n\n    ctx.fillStyle = on == 1 ? BG_COLOR_ON : BG_COLOR;\n    ctx.beginPath();\n\n    // 양쪽에 원을 그린다.\n    ctx.arc(halfOfCircleSize, halfOfCircleSize, halfOfCircleSize, 0, DEG_360);\n    ctx.arc(width - halfOfCircleSize, halfOfCircleSize, halfOfCircleSize, 0, DEG_360);\n    // 가운데 사각형을 그려준다.\n    ctx.rect(halfOfCircleSize, 0, innerWidth, height);\n    ctx.fill();\n\n    ctx.fillStyle = FG_COLOR;\n    ctx.beginPath();\n    ctx.arc(x, halfOfCircleSize, halfOfCircleSize - CIRCLE_MARGIN, 0, DEG_360);\n    ctx.fill();\n  }\n}\n\nregisterPaint(\"slide\", Slide);\n```\n\n### 성능비교\n\n렌더링 파이프라인은 이전 단계의 결과물이 다음 단계의 입력으로 사용됩니다.\n\n따라서 엘리먼트가 많아지게 되면 DOM 객체가 많아지고 이후 모든 과정들의 연산량과 메모리 사용량이 증가하게 됩니다.\n\n![rendering-pipline](https://user-images.githubusercontent.com/24274424/66269511-2ffdcc80-e884-11e9-9684-ea3035cb46ce.png)\n\n위의 슬라이드 체크박스를 약 5,000개를 만들었을 경우, \n5000 * 3개의 엘리먼트가 5000개의 엘리먼트로 대체됩니다.\n\n## CSS Layout API\n\nCSS Layout API를 사용하면 CSS가 적용된 대상의 자식 엘리먼트들의 배치를 정의할 수 있습니다.\n\n```css\n.cloud{\n  display: layout(cloud);\n}\n```\n\n렌더링 파이프라인 중 Layout 단계는 대상을 배치하는 방법을 다룹니다.\n\n![image](https://user-images.githubusercontent.com/24274424/66270222-bec21780-e88b-11e9-9355-671d7e59cada.png)\n\nCSS Layout API는 Worklet의 형태로 자식 엘리먼트를 개발자가 정의한대로 배치하는 코드를 추가합니다.\n\n![image](https://user-images.githubusercontent.com/24274424/66279040-8bae7100-e8e9-11e9-951d-a6b0b2bb80df.png)\n\n기존의 방법은, 렌더링이 끝난 후, JS로 재배치하면 렌더링 파이프라인을 한번 더 수행합니다.\n\n![image](https://user-images.githubusercontent.com/24274424/66270222-bec21780-e88b-11e9-9355-671d7e59cada.png)\n\n### 기본 형태\n\n```js\nclass CloudLayout {\n  static get inputProperties() {\n  }\n  \n  *intrinsicSizes(children, edges, styleMap) {\n  }\n  *layout(children, edges, constraints, styleMap){\n  }\n}\n\nregisterLayout(\"cloud\", CloudLayout);\n```\n\npaint method에는 기본 4가지의 인자가 있습니다.\n\n- children : 자식 요소들의 정보입니다.\n\n각각의 layoutNextFragment() 함수를 호출해서 자식요소의 크기를 알 수 있습니다.\n\nlayout() 함수는 자식요소들의 비동기 처리를 위해서 제네레이터 함수로 작성해야 합니다.\n\nlayoutNextFragment 함수는 LayoutFragment 객체를 반환합니다.\n\nLayoutFragment 객체는 4가지의 정보를 가지고 있습니다.\n\n1. blockSize\n2. blockOffset\n3. inlineSize\n4. inlineOffset\n\nblockSize, inlineSize는 fragment의 크기를 나타냅니다.\n\nblockOffset, inlineOffset은 fragment가 원점으로 부터 떨어진 거리를 나타냅니다.\n\n![image](https://user-images.githubusercontent.com/24274424/66270435-8d971680-e88e-11e9-9d81-781412c4be15.png)\n\n- edges : 레이아웃이 적용된 요소의 외곽선 정보입니다.\n- constraints : 레이아웃이 적용된 요소의 크기 정보입니다.\n- styleMap : 레이아웃이 적용된 요소의 Object Model style Map\n\npaint API와 동일하게 대상 엘리먼트에 적용된 스타일 정보를 읽어올 수 있습니다.\n\n마찬가지로 `static inputProperties` 필드로 읽어오려는 속성의 이름을 미리 선언해야합니다.\n\n### 예제\n\n**index.html**\n```html\n<head>\n  <link rel=\"stylesheet\" href=\"index.css\">\n  <script src=\"index.js\"></script>\n</head>\n<body>\n  <div class=\"cloud\">\n    <div class=\"child\">Websquare</div>\n    <div class=\"child\">Websquare</div>\n    <div class=\"child\">Websquare</div>\n    <div class=\"child\">Websquare</div>\n    <div class=\"child\">Websquare</div>\n    <div class=\"child\">Websquare</div>\n    <div class=\"child\">Websquare</div>\n    <div class=\"child\">Websquare</div>\n    <div class=\"child\">Websquare</div>\n  </div>\n</body>\n```\n\n**index.js**\n```js\nCSS.layoutWorklet.addModule('cloudLayout.js');\n```\n\n**index.css**\n```css\n.cloud{\n  display: layout(cloud);\n  --random-seed: 30;\n  width : 500px;\n  height : 500px;\n  background: rgba(0,0,0,0.2);\n  border-radius: 25px;\n}\n\n.child{\n  font-size: 24px;\n  font-weight: blod;\n  color: #918EFB;\n  text-shadow: 0px 2px 2px white;\n}\n```\n\n**cloudLayout.js**\n```js\nclass CloudLayout {\n  static get inputProperties() {\n    return [\"--random-seed\", \"--cloud-level\"];\n  }\n  \n  *intrinsicSizes(children, edges, styleMap) {\n  }\n  *layout(children, edges, constraints, styleMap){\n    const childFragments = yield children.map(child => {\n      const level = parseInt(child.styleMap.get(\"--cloud-level\"))\n      return child.layoutNextFragment({...constraints, level: level})\n    })\n\n    const availableInlineSize = constraints.fixedInlineSize;\n    const availableBlockSize = constraints.fixedBlockSize;\n    const randomSeed = parseInt(styleMap.get(\"--random-seed\"));\n\n    let seed = randomSeed;\n    const random = () => {\n      let x = Math.sin(seed++) * 10000;\n      return x - Math.floor(x);\n    }\n\n    let nextBlockOffset = 0;\n    for (const fragment of childFragments) {\n      let i = 0;\n      console.log(fragment)\n      fragment.blockOffset = random() * availableBlockSize;\n      fragment.inlineOffset = random() * availableInlineSize;\n    }\n\n    return{\n      childFragments\n    }\n  }\n}\n\nregisterLayout(\"cloud\", CloudLayout);\n```\n\n## Typed OM\n\nCSS에는 CSSOM이 있습니다.\n\n> CSSOM은 JavaScript에서 CSS를 조작할 수 있게 해주는 API입니다. CSSOM은 웹 페이지에서 발견되는 CSS 스타일의 기본 '맵'으로, DOM과 결합된 CSSOM은 브라우저에서 웹 페이지를 표현하는데 사용됩니다.\n\nJavaScript에서 .style을 read 또는 set할 때 항상 아래와 같이 사용해왔습니다.\n\n```js\n// 요소의 스타일\nel.style.opacity = 0.3;\ntypeof el.style.opacity === 'string' // true??\n \n// 스타일시트 규칙\ndocument.styleSheets[0].cssRules[0].style.opacity = 0.3;\n```\n\n### CSS Typed OM이란?\n\n새로 나온 CSS Typed Object Model(Typed OM)은 CSS 값에 타입과 메소드, 적절한 객체모델을 추가함으로써 세계관을 넓혔습니다.\n\n값이 문자열이 아닌 JavaScript 객체로 나타나기 때문에 CSS를 효율적으로(정상적으로) 조작할 수 있습니다.\n\n기존의 사용하던 element.style 대신, `.attributeStyleMap` 속성을 사용하여 스타일에 접근할 수 있습니다. \n\n스타일시트 규칙에는 `.styleMap` 속성을 사용합니다. \n\n두 속성 모두 StylePropertyMap 객체를 반환합니다.\n\n```js\n// 요소의 스타일\nel.attributeStyleMap.set('opacity', 0.3);\ntypeof el.attributeStyleMap.get('opacity').value === 'number' // true 숫자값이다!!!!\n \n// 스타일시트 규칙\nconst stylesheet = document.styleSheets[0];\nstylesheet.cssRules[0].styleMap.set('background', 'blue');\n```\n\nStylePropertyMap은 Map과 유사한 객체이기 때문에, 일반적인 함수(get/set/keys/values/entries)를 전부 지원합니다. 따라서 아래와 같이 유연하게 작업할 수 있습니다.\n\n```js\n// 아래 3가지가 모두 동일하다.\nel.attributeStyleMap.set('opacity', 0.3);\nel.attributeStyleMap.set('opacity', '0.3');\nel.attributeStyleMap.set('opacity', CSS.number(0.3)); // 'Unit values' 파트 참고\n// el.attributeStyleMap.get('opacity').value === 0.3\n \n// StylePropertyMaps은 반복 가능하다.\nfor (const [prop, val] of el.attributeStyleMap) {\n  console.log(prop, val.value);\n} // → opacity, 0.3\n \nel.attributeStyleMap.has('opacity') // true\nel.attributeStyleMap.delete('opacity') // opacity 제거\nel.attributeStyleMap.clear(); // 모든 스타일 제거\n```\n\n두 번째 예에서 opacity를 문자열 '0.3'으로 set 했지만 속성을 read 할 때는 숫자로 읽힌다는 것을 명심하세요.\n\n> 주어진 CSS 속성이 숫자를 지원한다면, Typed OM은 문자열 값을 입력하더라도 항상 숫자값을 반환합니다!\n\n### 장점\n\nCSS Typed OM이 해결하려는 문제가 무엇일까요? \nCSS Typed OM이 이전의 Object Model보다 훨씬 장황하다고 주장할 수도 있습니다.\n\nTyped OM을 작성하기 전에 아래의 몇 가지 주요 특징을 고려하세요.\n\n1. 적은 버그 – 예) 숫자 값은 문자열이 아니라 항상 숫자로 반환됩니다.\n\n```JavaScript\nel.style.opacity += 0.1;\nel.style.opacity === '0.30.1' // CSSOM은 문자열로 붙는다!\n\nel.style.opacity += 0.1;\nel.style.opacity === '0.30.1' // CSSOM은 문자열로 붙는다!\n```\n\n2. 산술 연산 및 단위 변환 – 절대 길이 단위를 변환하고(px → cm), 기본 수학 연산을 수행할 수 있습니다.\n3. 값 클램핑 & 반올림 – Typed OM은 값을 반올림 및 클램핑해서 속성의 허용 범위 내에 있을 수 있습니다. ex) opacity <= 1\n\n> 컴퓨터 그래픽에서 '클램핑'이란, 어떤 위치를 범위 안으로 한정시키는 방법입니다. 위치를 제일 가까운 사용 가능한 값으로 옮깁니다.\n\n4. 성능 향상 – 브라우저는 문자열 값을 직렬화, 병렬화하는 작업을 줄여야 합니다. 이제 엔진은 JS, C++과 비슷한 방식으로 CSS 값을 이해합니다. Tab Akins는 초기 CSS 벤치마크에서 Typed OM이 기존의 CSSOM을 사용할 때보다 초당 작동 속도가 30%까지 빠르다는 것을 입증했습니다. 이는 requestionAnimationFrame()를 사용하여 빠른 CSS 애니메이션을 구현할 때 중요합니다.\n5. 오류 처리 – 새로운 파싱 메소드는 CSS 세계에서 오류 처리를 제공합니다.\n6. CSSOM은 이름이 camel-case인지 문자열인지 가늠할 수 없었습니다(ex. el.style.backgroundColor vs el.style['background-color']). Typed OM의 CSS 속성 이름은 항상 문자열이며, 실제 CSS에서 작성한 것과 일치시키면 됩니다.\n\n## 그러나...\n\n![image](https://user-images.githubusercontent.com/24274424/66271104-3779a180-e895-11e9-9574-e9f081b0f244.png)\n\n---\n\n#### Reference\n\n- [houdini-draft](https://drafts.css-houdini.org/)\n- [googlechromelabs-sample](https://googlechromelabs.github.io/houdini-samples/)\n- [masonry - sample](https://googlechromelabs.github.io/houdini-samples/layout-worklet/masonry/)\n- [css-houdini.rocks](https://css-houdini.rocks/)\n- [Is houdini ready yet](https://ishoudinireadyyet.com/)"
  },
  {
    "path": "Browser/웹 브라우저의 작동 원리.md",
    "content": "# 웹 브라우저의 작동 원리\n\n## Rendering Engine\n\n현대 브라우저들의 렌더링 엔진은 다양하다. gecko기반의 spider monkey를 사용하는 firefox, webkit - blink기반의 V8을 사용하는 chrome, webkit을 사용하는 safari 등 상당히 종류가 많다.\n\n하지만 모든 브라우저는 크게 비슷한 flow로 동작하며 다음의 그림은 그 뼈대인 main flow다.\n\n![mainflow](https://user-images.githubusercontent.com/24724691/62412557-96296180-b63f-11e9-9f0c-fe14a3914629.png)\n\n1. DOM Tree 구축을 위한 HTML parsing\n2. Render Tree 구축\n3. Render Tree의 배치\n4. paint\n\n모든 브라우저는 위의 과정을 거쳐 화면에 그린다.\n\n모든 작업은 UX를 위해 점진적으로 진행된다.\n\n내용을 최대한 빠르게 paint하기 위해 모든 HTML이 parsing 되기를 기다리지는 않고 layout과 paint 일부를 먼저 처리한다.\n\n중요한 것은 위와 같은 flow로 작동한다는 점이다.\n\n### 예시\n\nHTML5rocks라는 구글이 했던 프로젝트의 [How Browsers Work: Behind the scenes of modern web browsers](https://www.html5rocks.com/en/tutorials/internals/howbrowserswork/)의 유명한 그림이다.\n\n- Webkit Engine 기반\n\n![Webkit](https://user-images.githubusercontent.com/24724691/62412567-bf49f200-b63f-11e9-9ed4-ec8215d04a7d.png)\n\n- Gecko Engine 기반\n\n![Gecko](https://user-images.githubusercontent.com/24724691/62412568-bf49f200-b63f-11e9-86a9-743f6d911e54.png)\n\n이미 너무 예전 그림이며 현대에는 더욱더 복잡한 과정을 거친다. 고전적인 rendering 과정이지만 두 엔진은 용어가 조금 다를 뿐 main flow는 비슷하게 작동함을 알 수 있다.\n\n## Critical Rendering Path(CRP)\n\n위처럼 브라우저에서 화면이 그려지기까지의 주요한 과정을 Critical Rendering Path라고 한다.\n\n1. HTML 마크업을 처리하고 DOM 트리를 빌드한다.\n2. CSS 마크업을 처리하고 CSSOM 트리를 빌드한다.\n3. DOM 및 CSSOM을 결합하여 Rendering 트리를 형성한다.\n4. Rendering 트리에서 레이아웃을 실행하여 각 노드의 기하학적 형태(화면의 위치)를 계산한다.\n5. 개별 노드를 화면에 paint한다.\n\n이 과정을 정리한 유명한 글은 Google Developers의 [주요 렌더링 경로](https://developers.google.com/web/fundamentals/performance/critical-rendering-path/?hl=ko)가 있다.\n\nwebkit과 gecko, 다른 모든 렌더링 엔진은 이 Critical Rendering Path를 따른다.\n\n### HTML 파싱 / DOM Tree 빌드\n\n컴파일러는 Source Code를 기계어로 변환한다.\n\n![compilation](https://user-images.githubusercontent.com/24724691/62412956-4731fb00-b644-11e9-8614-977ad4a5cc73.png)\n\n위 그림은 그 변환 과정 중 하나인 parsing 과정이다.\n\n문서는 lexer(tokenizer)와 parser(syntax 분석)가 함께 작업하여 tree를 만든다.\n\n브라우저도 마찬가지다.\n\n브라우저는 HTML 문서를 파싱해 DOM Tree를 만든다.\n모든 HTML 태그에는 노드가 있고 각각의 노드는 Tree형태로 구현된다.\n\n![Domtree](https://user-images.githubusercontent.com/24724691/62413000-fd95e000-b644-11e9-9fd0-059f49f6cf48.png)\n\n### CSSOM Tree 빌드\n\nHTML 파싱 중 CSS 링크를 만나면 리소스를 받아온다.\n같은 프로세스로 CSS도 Tree형태로 만들어진다.\n\n이를 CSSOM(CSS Object Model)이라고 부른다.\n\n![CSSOM](https://user-images.githubusercontent.com/24724691/62413025-52395b00-b645-11e9-9c88-3c3dafedbe46.png)\n\n#### script and css in HTML parsing\n\nHTML parsing과정에서 코드를 읽는 중 script나 css만난 경우 어떻게 처리될까?\n\n- script\n\n  script는 기본적으로 parsing을 중단(block)시킨다.\n  script가 외부에 있다면 네트워크 과정을 기다린다.\n  이는 HTML4, 5의 spec에도 명시되어 있다.\n  이러한 중단을 막고자 4에서는 defer, 5에서는 async라는 옵션이 추가되었다.\n\n  최근에는 외부 script의 parsing은 main parser가 하지 않으며 별도의 쓰레드에서 작업한다.\n\n- css\n\n  이론적으로 css는 dom tree를 수정하지 않기 때문에 block하지 않는다. 하지만 script가 css 정보를 이용해야 하는 경우가 있다. 이 경우 브라우저 엔진이 최적화 작업을 진행하여 문제가 될 경우만 block한다.\n\n### Render Tree 생성\n\nDOM Tree와 CSSOM를 결합하여 Render Tree를 만든다.\n\n![render-tree](https://user-images.githubusercontent.com/24724691/62413187-ee646180-b647-11e9-960f-06d2a85cdcff.png)\n\n![render-tree2](https://user-images.githubusercontent.com/24724691/62413188-ef958e80-b647-11e9-9975-b6bf1c5a8c09.png)\n\n위 그림들은 Render Tree를 추상화 한 그림이다.\n\nRender Tree는 DOM Tree에 있는 것 중에 실제 보이는 것들로만 구성한다.\n\n**ex) style='display : none;'은 Render Tree에서 제외된다. Header 역시 제외된다.**\n\n### Layout(Reflow)\n\nRender Tree가 만들어진 뒤 기기의 viewport를 기준으로 노드들의 정확한 위치와 크기를 계산하는 과정이다.\n\n위치와 관련된 속성(position, width, height 등)들을 계산한다.\n\n**ex) width:100%인 상태에서 브라우저를 resize하면, Render Tree는 변경되지 않고 Layout 이후 과정만 다시 거치게 된다.**\n\n### Paint\n\n실제 웹페이지를 화면에 그리는 작업이다.\n\n렌더러의 \"paint\" 메서드가 호출된다.\n\n**색이 바뀐다거나 노드의 스타일이 바뀌는 것으로는 Layout 과정을 거치지 않고 Paint만 일어난다.**\n\n#### modern browser\n\n최근의 브라우저들은 Critical Rendering Path에 몇 가지 과정이 추가된다.\n\n1. layout 과정 이후 Update Layer Tree라는 단계가 생겼다.\n\n   Render Object는 layout 이후 정해진 기준에 따라 layer를 나누게 된다.\n\n   여기에서 layer는 포토샵의 layer와 비슷한 개념이다.\n   [Layer Model](https://github.com/Im-D/Dev-Docs/blob/master/Browser/Layer_Model.md)로 글을 대체한다.\n\n   Layer는 Render Layer와 Graphics Layer 두 종류가 있는데 이 두 기준으로 Layer Tree를 만든다.\n\n2. 각각의 layer는 paint 과정을 거친 후 composite layers이라는 새로운 과정을 거친다.\n\n   layer들을 합성하여 하나의 bitmap으로 만든 뒤 최종 page를 만든다.\n\n#### Reference\n\n- [How Browsers Work: Behind the scenes of modern web browsers](https://www.html5rocks.com/en/tutorials/internals/howbrowserswork/)\n- [Naver D2 - 브라우저의 작동 원리(위 글 번역)](http://d2.naver.com/helloworld/59361)\n- [critical rendering path](https://developers.google.com/web/fundamentals/performance/critical-rendering-path/?hl=ko)\n- [웹 성능 최적화에 필요한 브라우저의 모든 것](https://tv.naver.com/v/4578425)\n"
  },
  {
    "path": "Browser/최신_브라우저의_내부_살펴보기.md",
    "content": "# 최신 브라우저의 내부 살펴보기\n\n개인적으로 일을 하다보면 성능(performance)를 올려야하는 일은 당연하게 된다. 성능이 나와야 제품을 사용하는 사람이 생기기 마련이다.\n\n그러다 보면 당연하게 GPU를 사용하는 방법을 택하게 된다. 흔히 우리가 알고 있는 **하드웨어 가속화**를 사용하게 되는 것이다. \n\n> 특정 작업을 CPU가 아닌 다른 특별한 장치를 통해 수행 속도를 높이는 것을 \n> '**하드웨어 가속(hardware accelerated)**'이라 한다. \n> \n> 브라우저에서 하드웨어 가속은 주로 GPU를 사용한 그래픽 작업의 가속을 의미한다. \n> 간단한 작업을 동시에 수많은 코어가 수행하는 GPU의 특성을 기반으로 그래픽 작업이 훨씬 빠르게 처리될 수 있다.\n\n브라우저에 대해 알아보기 전에 기본적인 내용을 알아보고 가자\n\n## CPU\n\n컴퓨터 부품에서 가장 중요한? **중앙처리장치**이다. 흔히 연산을 담당하는 사람으로 따지면 두뇌라고 한다. 예전 CPU는 단일로 구성되어 있었지만 요즘은 CPU하나 안에 코어가 여러개가 들어가서 성능을 더 높이고 있다. \n\n## GPU\n\nGPU는 그래픽처리장치로 CPU와 다르게 GPU는 간단한 작업에만 특화가 되었는데 여러 GPU 코어를 동시에 사용하여 작업을 할 수 있다.\n\n이름에서 알 수 있듯이 GPU는 **그래픽 작업을 처리하기 위해 개발**되었다. 그래서 빠른 렌더링과 매끄러운 표현을 하는데 관련되어있다. 최근 몇 년 동안 GPU 가속을 통해 GPU가 단독으로 처리할 수 있는 계산이 점점 더 많아졌다.\n\n## 프로세스와 스레드(Process and Thread)\n\n브라우저 아키텍처를 살펴보기 전에 파악해야 할 또 다른 개념은 **프로세스와 스레드**이다. \n\n프로세스는 애플리케이션이 실행하는 **프로그램**이라고 하며, 스레드는 프로세스 내부에 있으며 프로세스로 실행되는 프로그램의 **일부를 실행**한다.\n\n애플리케이션을 시작하면 프로세스가 하나가 만들어진다. 프로세스가 작업을 하기 위해 스레드를 생성할 수도 있지만 **선택 사항**이며, 애플리케이션을 닫으면 프로세스가 사라지고 운영체제가 메모리를 비운다.\n\n프로세스는 여러 작업을 수행하기 위해 운영체제에 다른 프로세스를 실행하라고 요청할 수 있다. 그러면 메모리의 다른 부분이 새 프로세스에 할당된다. 두개 이상의 프로세스가 서로 정보를 공유해야 할 때는 **IPC(inter process communication, 프로세스 간 통신)** 을 사용한다. 대부분의 애플리케이션이 이 방식으로 설계되어 있다. 작업 프로세스가 응답하지 않을 때 애플리케이션의 다른 부분을 실행하는 프로세스를 중지하지 않고 응답하지 않는 프로세스만 다시 시작할 수 있다.\n\n## 브라우저 아키텍처\n\n브라우저는 프로세스와 스레드를 어떻게 사용할까? 크게 방법은 2가지가 있다.\n\n1. 스레드를 많이 사용하는 프로세스 하나만 사용\n2. 스레드를 조금만 사용하는 프로세스를 여러 개 만들어 IPC로 통신\n\n### **Chrome의 최근 아키텍처**\n\n상위 브라우저 프로세스는 애플리케이션의 각 부분을 맡고 있는 다른 프로세스를 조정한다. Renderer 프로세스는 여러 개가 만들어져 각 탭마다 할당이 된다. \n\n최근까지 Chrome은 **탭마다 프로세스를 할당**했다. 이제는 사이트(iframe에 있는 사이트 포함)마다 프로세스를 할당한다.\n\n### **어떤 프로세스가 무엇을 담당하나**\n\n- 브라우저 프로세스\t : 주소 표시줄, 북마크 막대, 뒤로 가기 버튼, 앞으로 가기 버튼 등 애플리케이션의 \"chrome\" 부분을 제어한다. 네트워크 요청이나 파일 접근과 같이 눈에 보이지는 않지만 권한이 필요한 부분도 처리한다.\n- 렌더러 프로세스\t: 탭 안에서 웹 사이트가 표시되는 부분의 모든 것을 제어한다.\n- 플러그인 프로세스\t: 웹 사이트에서 사용하는 플러그인(예: Flash)을 제어한다.\n- GPU 프로세스 : GPU 작업을 다른 프로세스와 격리해서 처리한다. GPU는 여러 애플리케이션의 요청을 처리하고 같은 화면에 요청받은 내용을 그리기 때문에 GPU 프로세스는 별도 프로세스로 분리되어 있다.\n\n이 외에도 확장 프로그램(Extension) 프로세스, 유틸리티 프로세스 등 더 많은 프로세스가 있다.\n\nChrome에서 실행 중인 프로세스를 확인이 가능하다.(도구 더보기 > 작업 관리자) \n\n### **다중 프로세스 아키텍처가 Chrome에 주는 이점**\n\nChrome은 렌더러 프로세스를 여러 개 사용한다. 예로 탭마다 렌더러 프로세스를 하나 사용하는 경우를 생각해보면. 3개의 탭이 열려 있고 각 탭은 독립적인 렌더러 프로세스에 의해 실행된다. \n\n이때 한 탭이 응답하지 않으면 그 탭만 닫고 실행 중인 다른 탭으로 이동할 수 있다. 모든 탭이 하나의 프로세스에서 실행 중이었다면 탭이 하나만 응답하지 않아도 모든 탭이 죽는일이 벌어졌을 것이다.\n\n브라우저의 작업을 여러 프로세스에 나눠서 처리하는 방법의 또 다른 장점은 **보안과 격리**이다. 운영체제를 통해 프로세스의 권한을 제한할 수 있어 브라우저는 특정 프로세스가 특정 기능을 사용할 수 없게 제한할 수 있다. \n\n예를 들어 Chrome은 렌더러 프로세스처럼 임의의 사용자 입력을 처리하는 프로세스가 임의의 파일에 접근하지 못하게 제한한다.\n\n프로세스는 전용 메모리 공간을 사용하기 때문에 공통부분(예를 들어 Chrome의 JavaScript 엔진인 V8)을 복사해서 가지고 있는 경우가 많다. 동일한 프로세스의 스레드가 메모리를 공유할 수 있는 데 반해 서로 다른 프로세스는 메모리를 공유할 수 없어 메모리 사용량이 더 많아질 수밖에 없다. Chrome은 메모리를 절약하기 위해서 실행할 수 있는 프로세스의 개수를 제한한다. 정확한 한도는 기기의 메모리 용량과 CPU 성능에 따라 다르지만 프로세스의 개수가 한도에 다다르면 동일한 사이트를 열고 있는 여러 탭을 하나의 프로세스에서 처리한다.\n\n### 더 많은 메모리 절약 - Chrome의 서비스화\n\nChrome은 브라우저의 각 부분을 서비스로 실행해 여러 프로세스로 쉽게 분할하거나 하나의 프로세스로 통합할 수 있도록 아키텍처를 변경하고 있다.\n\n성능이 좋은 하드웨어에서 Chrome이 실행 중일 때에는 각 서비스를 여러 프로세스로 분할해 안정성을 높이고, 리소스가 제한적인 장치에서 실행 중일 때에는 서비스를 하나의 프로세스에서 실행해서 메모리 사용량을 줄이는 것이 기본 아이디어이다. 메모리 절약을 위해 프로세스를 합치는 이런 방식은 `Android`와 같은 플랫폼에서는 이전부터 사용되었다.\n\n### 프레임별로 실행되는 렌더러 프로세스 - 사이트 격리\n\n`iframe`의 사이트를 별도의 렌더러 프로세스에서 실행하는 것이다. 탭마다 렌더러 프로세스를 할당하는 모델에서는 `iframe`의 사이트가 같은 렌더러 프로세스에서 작동하기 때문에 서로 다른 사이트 간에 메모리가 공유될 수 있다는 문제가 있어 지속적으로 논의가 있었다. \n\na.com 사이트의 웹 페이지와 b.com 사이트의 웹 페이지를 동일한 렌더러 프로세스에서 실행하는 것이 문제가 없어 보일 수 있다. 하지만 동일 출처 정책(same origin policy)은 웹 보안 모델의 핵심이다. 한 사이트는 동의 없이 다른 사이트의 데이터에 접근할 수 없어야 한다. \n\n이 정책을 우회하는 것이 바로 보안 공격의 주요 목표이다. 프로세스를 격리하는 것이 사이트를 격리하는 가장 효과적인 방법이다. **Meltdown과 Spectre 사태**로 여러 프로세스를 사용해 사이트를 격리해야 한다는 것이 더욱 분명해졌다. Chrome 67부터 데스크톱에서 사이트 격리를 기본으로 사용하도록 설정하면서 탭에서 `iframe` 의 사이트에 별도의 렌더러 프로세스가 적용된다.\n\n사이트 격리를 위해 여러 해에 걸친 노력이 있었다. 사이트 격리는 다른 렌더러 프로세스를 할당하는 것만큼 간단하지 않다. `iframe` 이 서로 통신하는 방식을 근본적으로 바꿔야 하기 때문이다. 다른 프로세스에서 실행되는 `iframe` 이 있는 웹 페이지에서 개발자 도구를 자연스럽게 사용하게 하려면 눈에 보이지 않은 많은 작업이 뒤에서 이루어져야 한다. 또 단순히 `Ctrl + F` 키를 눌러 페이지에서 단어를 찾으려고 해도 서로 다른 렌더러 프로세스를 오가며 찾아야 한다.\n\n#### Reference\n\n- [최신 브라우저의 내부 살펴보기 1 - CPU, GPU, 메모리 그리고 다중 프로세스 아키텍처](https://d2.naver.com/helloworld/2922312)\n- [인텔 사태, CPU 보안 이슈 정리, 멜트다운(Meltdown)](https://fillin.tistory.com/259)"
  },
  {
    "path": "CS/Binding.md",
    "content": "# 바인딩(Binding)\n**바인딩**은 **이름**을 어떠한 **속성**과 **연결** 시키는 것이다. 더 나아가 바인딩은, 값들을 확정시켜 더 이상 **변경할 수 없는 상태**로 만든다. 또한, **메모리 번지를 연결** 시키는 것도 바인딩이다. 좀 더 정확하게 말하면 바인딩은 식별자(identifiers)를 개체(entity)와 결합(association; 연관)시키는 것이다. \n\n> bind는 묶다, 결속시키다 등의 뜻을 가지고 있는데, 고정, 구속, 속박 등과 같이 틀 안에 가둬 놓는 뉘앙스를 띈다.\n\n> 이름을 연결하는 것이기 때문에 'Name binding' 이라고도 한다.\n\n<br/>\n\n## 바인딩 타임(Binding Time)\n\n바인딩은 프로그램 실행 과정 중 어떤 단계에서 이루어지는지에 따라 역할이 달라진다. 이 때, 특정 단계에서 바인딩이 되는 순간을 바인딩 타임이라 한다. \n\n### 바인딩 타임의 종류\n\n1. 언어 설계(정의) 시간(Language Design/Definition Time)\n- 언어의 근본적인 요소를 결정\n- 기본 제공 함수, 키워드의 기본 요소 등을 결정\n\n    > e.g. int는 정수값을 나타내는 타입명, +는 덧셈 연산자를 나타내는 기호\n\n2. 언어 구현 시간(Language Implementation Time)\n- 언어 설계 시간에 정해진 각 유형들의 세부정보를 결정\n- 타입의 크기, 파일 표현, 런타임 예외 등을 결정\n\n    > e.g. java에서 int의 범위는 -2147483648 ~ 2147483647\n\n3. 컴파일 타임(Compile Time)\n- 원시 코드(source code)를 기계어로 매핑(mapping)\n- 변수와 변수 타입을 연결(type binding)\n4. 링크 타임(Link Time)\n- 함수와 외부에서 참조된 객체(e.g. 라이브러리)의 유효성과 주소 검사 및 수정\n5. 로드 타임(Load time; 적재 시간)\n- 변수를 메모리에 할당(allocation) 하는 단계(주소 결정)\n6. 런타임(Run Time/Execution Time; 실행 시간)\n- 프로그램을 실행하는 단계\n\n<br/>\n\n## 변수의 바인딩\n\n변수의 바인딩은 바인딩 타임에 따라 달라진다. 런타임 이전에 바인딩 된 것을 정적 바인딩(static binding), 런타임에 바인딩 되는 것을 동적 바인딩(dynamic binding)이라고 한다.\n\n### 정적 바인딩(Static Binding)\n\n정적 바인딩은 이른 바인딩(early binding)이라고 부르기도 한다. **컴파일 타임에 바인딩이 결정**되고, **바인딩이 변하지 않은 상태로 유지**되어야 정적 바인딩이다.\n> e.g. 전역(static) 변수\n\n### 동적 바인딩(Dynamic Binding)\n\n동적 바인딩은 늦은 바인딩(late binding)이라고도 한다. 실행 파일을 만들 때에는 바인딩이 되지 않고 보류되었다가, **프로그램이 실행될 때 바인딩** 되는 것이다. 따라서 정적 바인딩에 비해 **유연**하며, 이를 이용해 OOP의 **다형성을 구현**할 수 있다.\n\n하지만, 동적 바인딩은 메모리 위치 및 크기가 정해져있지 않아 정적 바인딩에 비해 비효율적이다. 또한, 바인딩에 필요한 메모리 번지를 저장할 포인터를 가지고 있어야 한다. 따라서 **정적 바인딩에 비해 자원 소모가 크다.**\n\n### 자바(Java)에서...\n\n자바는 동적 바인딩을 사용한다.\n```java\nclass Child extends Parent{\n    public String parentMethod(){\n        return \"Inheritance Method\";\n    }\n    \n    public String childMethod() {\n        return \"Child Method\";\n    }\n    \n}\n\nclass Parent{\n    public String parentMethod(){\n      return \"Parent Method\";\n    }\n}\n\npublic class Test01{\n  public static void main(String[] args) {\n    // test01 - 타입 체크를 통과하여 컴파일이 되지만, 실제 값의 할당은 런타임에 이루어진다.\n    try {\n      String[] arr = new String[1]; // test01 - RuntimeException \n      arr[2] = \"0\";\n    } catch (RuntimeException e) {\n      System.out.println(\"test01 - RuntimeException \");\n    }\n    // test02 - 마찬가지로 컴파일시 타입 체크를 하지만, 실제 값이 할당되지 않는다.\n    try {\n      Child test02 = (Child)new Parent(); // test02 - RuntimeException \n    // 컴파일시에는 값이 타입에 정의된 내용의 범위 안에 있는지 판단한다.\n      System.out.println(\"test02 - \" + test02.parentMethod());\n      System.out.println(\"test02 - \" + test02.childMethod());\n    } catch (RuntimeException e) {\n      System.out.println(\"test02 - RuntimeException\");\n    }\n    // test03 - 부모 타입을 사용한다면, 부모 타입 내에 정의된 것과 같은 형식의 메소드를 호출 할 수 있다.\n    try {\n      Parent childInstance = new Child();\n      Parent parentInstance = new Parent();            \n            \n      System.out.println(\"test03 - \" + childInstance.parentMethod()); // test03 - Inheritance Method\n      System.out.println(\"test03 - \" + parentInstance.parentMethod()); // test03 - Parent Method         \n      // childInstance.childMethod() // The method childMethod() is undefined for the type Parent - Compile Error\n    } catch (RuntimeException e) {\n      System.out.println(\"test03 - RuntimeException\");\n    }\n  }\n}\n```\n<br/>\n\n## 타입 바인딩\n\n **타입 바인딩은 컴파일 타임에 이루어진다.** 타입이 결정 되는 것이기 때문에 타이핑(typing)이라고도 한다. **바인딩 대상(변수)의 타입이 고정적인지 유동적인지에 따라** 정적 타입 바인딩(static type binding)과 동적 타입 바인딩(dynamic type binding)으로 나뉜다.\n\n### 정적 타입 바인딩(Static Type Binding; Static Typing)\n\n정적 타입 바인딩은 'strongly typed' 되었다고 표현하기도 한다. **자료형을 한 번 선언하면 더 이상 변경할 수 없다.**\n\n> e.g.\n> 1. 자바나 C 등의 언어에서 선언 한 변수의 타입은 더 이상 변경 불가능하다.(명시적 선언)\n> 2. 과거 포트란에서, 문자 i~n으로 시작하는 변수는 정수 이다.(묵시적 선언)\n\n### 동적 타입 바인딩(Dynamic Type Binding; Dynamic Typing)\n\n'weakly typed' 혹은 'loosely typed' 되었다고 표현하기도 한다. 동적 타입 바인딩은 **컴파일러가 데이터의 타입을 추론**한다. 사용하기 쉽다는 장점이 있지만, 타입 바인딩 시 타입 추론으로 인한 비용이 증가하고, 컴파일 중에 타입 에러가 발생하지 않는 단점이 있다.\n\n> e.g. JavaScript나 python 등의 언어에서 변수 선언이 타입에 관계없이 통일되어 있다.\n\n---\n\n#### Reference\n\n- [자바 :: 바인딩(binding)](https://m.blog.naver.com/PostView.nhn?blogId=reeeh&logNo=220716449491&proxyReferer=https%3A%2F%2Fwww.google.co.kr%2F)\n- [Binding의 개념](https://twinw.tistory.com/58)\n- [Link time - Wikipedia](https://en.wikipedia.org/wiki/Link_time)\n- [정적 바인딩과 동적 바인딩](https://wookss-blog.tistory.com/6)\n- [Name binding - Wikipedia](https://en.wikipedia.org/wiki/Name_binding)\n- [Binding - 정보통신기술용어해설](http://www.ktword.co.kr/word/abbr_view.php?m_temp1=2670&m_search=%EB%B0%94%EC%9D%B8%EB%94%A9)\n"
  },
  {
    "path": "CS/Bomb-Lab(1).md",
    "content": "# Bomb Lab(1)\n\nBomb Lab은 Carnegie Mellon University의 시스템 프로그래밍 과제인 Lab 시리즈 중 하나이다. 과제에는 bomb라는 바이너리 파일이 제공된다. 과제의 목적은 gdb(GNU 디버거의 약자로 Unix/Linux 환경에서 C/C++ 디버깅에 사용)를 이용해 해당 파일을 리버스 엔지니링 하여 총 6단계의 문구를 찾아 폭탄을 해체하는 것이다. 과제의 특성상 어셈블리를 분석해야 하기 때문에 문제를 해결하는 과정에서 어셈블리와 친숙해질 수 있다.\n\n해당 문서에서 사용되는 어셈블리는 [AT&T 문법](http://doc.kldp.org/KoreanDoc/html/Assembly_Example-KLDP/Assembly_Example-KLDP.html)을 따른다.\n\n## 사전지식\n\n### 어셈블리의 구성\n\n`[Label]: [operator]  [operand1], [operand2] # [comment]`\n\n`L1: mov %eax, %ebx # comment`\n\n`L1:`은 기계어 코드로 번역되지 않고 분기 명령([JMP](https://github.com/im-d-team/Dev-Docs/blob/20201101/dididy/CS/Bomb-Lab(1).md#%EC%96%B4%EC%85%88%EB%B8%94%EB%A6%AC-%EB%AA%85%EB%A0%B9%EC%96%B4) - FLAG 값을 기반으로 조건에 따라 특정 위치로 점프하도록 하는 명령어) 등에서 참조될 때에 번지의 계산에 사용된다. `mov`는 operand2의 값을 operand1에 할당할 때 사용한다.\n\noperand 앞에 붙는 기호 중 `$`는 상수, `%`는 레지스터를 나타낸다.\n\n- AT&T 방식에서는 `[instruction] [src], [dest]` 의 순서로 명렁이 구성된다.(Intel 방식의 경우 이와 반대로 `[instruction] [dest], [src]` 순서)\n\n### 어셈블리 명령어\n\n\n![어셈블리 명령어](https://t1.daumcdn.net/cfile/tistory/27304750588DB45C07)\n\n> 출처: https://aistories.tistory.com/12\n\n![JMP 조건 점프 명령어](https://t1.daumcdn.net/cfile/tistory/26231D4556925CA016)\n\n> 출처: https://8jz5.tistory.com/50\n\n### 주소지정 방식\n- 즉시 지정 방식\n  - `mov $0x1, %eax`: eax에 1을 할당하는 것처럼 값을 직접 대응시키는 방식이다.\n- 레지스터 지정방식\n  - `mov %esp, %ebp`: 레지스터 ebp에 레지스터 esp의 값을 할당하는 방식이다.\n- 직접 주소 지정방식\n  - `mov &0x127f, %eax `: 주소 0x127f에 있는 값을 eax에 할당하는 것처럼 메모리의 주소를 직접 지정해서 할당하는 방식이다.\n- 레지스터 간접 주소 지정방식(괄호 안의 값)\n  - `mov (%ebx), %eax`: ebx의 값을 주소로 하여 간접적으로 eax 레지스터에 할당하는 방식이다.\n- 베이스 상대 주소 지정방식\n  - `mov 0x4(%esi), %eax`: esi레지스터에서 4 Byte를 더한 주소의 값을 eax 레지스터에 할당하는 방식이다.\n\n### 범용 레지스터\n\n- 레지스터의 첫 글자는 32bit에서 E, 64bit에서 R로 사용된다. 해당 문서에서는 64bit를 기준으로 작성하였다.\n\n- 데이터 레지스터\n  - RAX(Accumulator): 곱셈, 나눗셈 등 각종 연산에 많이 사용되는 변수이다. 주로 return 값을 저장한다.\n  - RBX(Base): 목적이 없는 레지스터이다. 공간이 필요할 때 메모리 주소 지정 시 사용한다.\n  - RCX(Count): for 문에서 i 역할을 한다. ECX는 미리 값을 정해놓고 0이 될 때까지 진행한다. 변수로 사용해도 무방하다.\n  - RDX(Data): 각종 연산에 쓰이는 변수이다. 나눗셈에서 EAX와 함께 사용한다. 부호 확장 명령 등에 사용한다.\n- 인덱스 레지스터\n  - RSI(Source Index), RDI(Destination Index): 문자열이나 각종 반복 데이터를 처리하거나 메모리를 옮기는 데 사용한다. 각각 Source의 주소와 Destination의 주소를 가리킨다.\n- 포인터 레지스터\n  - RSP(Stack Pointer): Stack의 상위 주소(최종점)를 가리키는 레지스터이다.\n  - RBP(Base Pointer): Stack의 Base 주소를 가리키는 레지스터이다. ESP를 대신해 스택에 저장된 함수의 파라미터 지역 변수의 주소를 가리키는 용도로 사용된다.\n- 상태 레지스터\n  - RIP(Instruction Pointer): 실행할 명령의 주소를 가리키는 레지스터이다. 각각의 명령이 실행될 때, EIP에 CPU가 현재 실행하고 있는 주소가 저장된다.\n\n## GDB\n\n### 기본 명령어\n\n- `run`: 프로그램을 실행한다. break point가 걸려있다면 break point까지 실행한다.\n- `continue`: break point가 걸려있는 경우 다음 break point까지 실행한다.\n- `break`: break point를 지정한다. b로 줄여 쓸 수 있다.\n- `display $eax`: EAX(accumulator)를 보여주는 역할을 한다.\n- `ni`: next instruction의 약자다. 즉 다음 명령어로 넘어간다는 것을 의미한다. 함수 안으로 진입하지 않는다.\n- `si`: ni와 동일하게 다음 명령어로 넘어간다는 것을 의미한다. 함수 안으로 들어갈 수 있다.\n- `b explode_bomb`: 폭탄 터져서 점수를 잃지 않도록 방지하는 역할을 한다.\n- `x/[출력 횟수] [출력 형식] [출력 단위] [출력 위치]`: 메모리 상태와 내용을 확인할 수 있다.\n  - 출력 형식: t(2), o(8), d, u(10), x(16), c, f, a, s(string), i\n  - 출력 단위: b(1 Byte), h(2 Byte), w(4 Byte), g(8 Byte)\n- `disas [함수명]`: 함수의 어셈블리 코드 출력\n- `disas [시작 주소] [끝 주소]`: 주소 범위의 어셈블리 코드 출력\n- `p $[레지스터 명]`: 레지스터값 확인\n- `i r`: info registers를 줄여 쓴 것이다. 레지스터값 전체를 한 번에 확인할 수 있다.\n\n### TUI(Text User Interface)\n\n- gdb에서 디버깅 정보들을 분리된 창에서 상시로 확인할 수 있게 해준다.\n- Source file, Assembly, register info, gdb command 총 4가지 종류의 정보를 띄울 수 있다.\n\n- `tui enable`: TUI를 활성화한다. 혹은  gdb를 실행할 때 `--tui` 옵션을 줘서 실행시킬 수도 있다.\n- `layout asm`: Assembly 디버깅 정보를 표시하는 TUI를 활성화 한다.\n\n## bomb 파일 분석\n\n`gdb bomb` 명령어로 bomb 파일을 gdb를 이용해 분석해보도록 하자.\n\n### main\n\n```shell\n(gdb) disas main\nDump of assembler code for function main:\n   0x000000000000116a <+0>:\tpush   %rbx\n   0x000000000000116b <+1>:\tcmp    $0x1,%edi\n   0x000000000000116e <+4>:\tje     0x126c <main+258>\n   0x0000000000001174 <+10>:\tmov    %rsi,%rbx\n   0x0000000000001177 <+13>:\tcmp    $0x2,%edi\n   0x000000000000117a <+16>:\tjne    0x12a1 <main+311>\n   0x0000000000001180 <+22>:\tmov    0x8(%rsi),%rdi\n   0x0000000000001184 <+26>:\tlea    0x17d9(%rip),%rsi        # 0x2964\n   0x000000000000118b <+33>:\tcallq  0xfc0 <fopen@plt>\n   0x0000000000001190 <+38>:\tmov    %rax,0x203519(%rip)        # 0x2046b0 <infile>\n   0x0000000000001197 <+45>:\ttest   %rax,%rax\n   0x000000000000119a <+48>:\tje     0x127f <main+277>\n   0x00000000000011a0 <+54>:\tcallq  0x17d8 <initialize_bomb>\n   0x00000000000011a5 <+59>:\tlea    0x183c(%rip),%rdi        # 0x29e8\n   0x00000000000011ac <+66>:\tcallq  0xee0 <puts@plt>\n   0x00000000000011b1 <+71>:\tlea    0x1870(%rip),%rdi        # 0x2a28\n   0x00000000000011b8 <+78>:\tcallq  0xee0 <puts@plt>\n   0x00000000000011bd <+83>:\tcallq  0x1af2 <read_line>\n   0x00000000000011c2 <+88>:\tmov    %rax,%rdi\n   0x00000000000011c5 <+91>:\tcallq  0x12c4 <phase_1>\n   0x00000000000011ca <+96>:\tcallq  0x1c36 <phase_defused>\n   0x00000000000011cf <+101>:\tlea    0x1882(%rip),%rdi        # 0x2a58\n   0x00000000000011d6 <+108>:\tcallq  0xee0 <puts@plt>\n   0x00000000000011db <+113>:\tcallq  0x1af2 <read_line>\n   0x00000000000011e0 <+118>:\tmov    %rax,%rdi\n   0x00000000000011e3 <+121>:\tcallq  0x12e4 <phase_2>\n   0x00000000000011e8 <+126>:\tcallq  0x1c36 <phase_defused>\n   0x00000000000011ed <+131>:\tlea    0x17a9(%rip),%rdi        # 0x299d\n   0x00000000000011f4 <+138>:\tcallq  0xee0 <puts@plt>\n   0x00000000000011f9 <+143>:\tcallq  0x1af2 <read_line>\n   0x00000000000011fe <+148>:\tmov    %rax,%rdi\n   0x0000000000001201 <+151>:\tcallq  0x1353 <phase_3>\n   0x0000000000001206 <+156>:\tcallq  0x1c36 <phase_defused>\n   0x000000000000120b <+161>:\tlea    0x17a9(%rip),%rdi        # 0x29bb\n   0x0000000000001212 <+168>:\tcallq  0xee0 <puts@plt>\n   0x0000000000001217 <+173>:\tcallq  0x1af2 <read_line>\n   0x000000000000121c <+178>:\tmov    %rax,%rdi\n   0x000000000000121f <+181>:\tcallq  0x1440 <phase_4>\n   0x0000000000001224 <+186>:\tcallq  0x1c36 <phase_defused>\n   0x0000000000001229 <+191>:\tlea    0x1858(%rip),%rdi        # 0x2a88\n   0x0000000000001230 <+198>:\tcallq  0xee0 <puts@plt>\n   0x0000000000001235 <+203>:\tcallq  0x1af2 <read_line>\n   0x000000000000123a <+208>:\tmov    %rax,%rdi\n   0x000000000000123d <+211>:\tcallq  0x14af <phase_5>\n   0x0000000000001242 <+216>:\tcallq  0x1c36 <phase_defused>\n   0x0000000000001247 <+221>:\tlea    0x177c(%rip),%rdi        # 0x29ca\n   0x000000000000124e <+228>:\tcallq  0xee0 <puts@plt>\n   0x0000000000001253 <+233>:\tcallq  0x1af2 <read_line>\n   0x0000000000001258 <+238>:\tmov    %rax,%rdi\n   0x000000000000125b <+241>:\tcallq  0x14f5 <phase_6>\n   0x0000000000001260 <+246>:\tcallq  0x1c36 <phase_defused>\n   0x0000000000001265 <+251>:\tmov    $0x0,%eax\n   0x000000000000126a <+256>:\tpop    %rbx\n   0x000000000000126b <+257>:\tretq\n   0x000000000000126c <+258>:\tmov    0x20341d(%rip),%rax        # 0x204690 <stdin@@GLIBC_2.2.5>\n   0x0000000000001273 <+265>:\tmov    %rax,0x203436(%rip)        # 0x2046b0 <infile>\n   0x000000000000127a <+272>:\tjmpq   0x11a0 <main+54>\n   0x000000000000127f <+277>:\tmov    0x8(%rbx),%rcx\n   0x0000000000001283 <+281>:\tmov    (%rbx),%rdx\n   0x0000000000001286 <+284>:\tlea    0x16d9(%rip),%rsi        # 0x2966\n   0x000000000000128d <+291>:\tmov    $0x1,%edi\n   0x0000000000001292 <+296>:\tcallq  0xfb0 <__printf_chk@plt>\n   0x0000000000001297 <+301>:\tmov    $0x8,%edi\n   0x000000000000129c <+306>:\tcallq  0xfe0 <exit@plt>\n   0x00000000000012a1 <+311>:\tmov    (%rsi),%rdx\n   0x00000000000012a4 <+314>:\tlea    0x16d8(%rip),%rsi        # 0x2983\n   0x00000000000012ab <+321>:\tmov    $0x1,%edi\n   0x00000000000012b0 <+326>:\tmov    $0x0,%eax\n   0x00000000000012b5 <+331>:\tcallq  0xfb0 <__printf_chk@plt>\n   0x00000000000012ba <+336>:\tmov    $0x8,%edi\n   0x00000000000012bf <+341>:\tcallq  0xfe0 <exit@plt>\nEnd of assembler dump.\n```\n\nmain 함수를 disassemble 하면 메인 함수는 총 6개 phase로 구성된 것을 확인할 수 있다. break point 없이 run 명령어를 실행하면 문자열을 입력받는 상태가 된다. 여기서 제대로 된 문자열을 입력해야만 폭탄이 터지지 않는다. 이 과정을 6번 거쳐 제대로 된 문자열을 입력하면 폭탄을 해체할 수 있다.\n\n각 phase함수들을 disassemble 하여 어셈블리를 분석하거나 적절하게 break point를 건 뒤 단서를 찾아 폭탄을 해체할 수 있는 입력값들을 발견할 수 있다.\n\n과제는 진행 상황에 따라 웹(score board)을 통해 실시간으로 점수를 확인할 수 있다. 각 phase를 처음 통과할 때 점수를 얻는다. 각 phase에 잘못된 문자열을 입력하여 폭탄이 터지면 터질 때마다 일정 점수를 잃는다.\n\n폭탄이 터져 점수를 잃는 것을 방지하기 위해서는 `b explode_bomb` 명령어를 사용하여 break point를 걸고 시작하면 된다.\n\n### phase_1\n\n`disas phase_1` 명령어로 첫 번째 phase 함수의 어셈블리 코드를 출력할 수 있다. 그 결과는 아래와 같다.\n\n```shell\n(gdb) disas phase_1\nDump of assembler code for function phase_1:\n   0x00000000000012c4 <+0>:\tsub    $0x8,%rsp\n   0x00000000000012c8 <+4>:\tlea    0x17dd(%rip),%rsi        # 0x2aac\n   0x00000000000012cf <+11>:\tcallq  0x1771 <strings_not_equal>\n   0x00000000000012d4 <+16>:\ttest   %eax,%eax\n   0x00000000000012d6 <+18>:\tjne    0x12dd <phase_1+25>\n   0x00000000000012d8 <+20>:\tadd    $0x8,%rsp\n   0x00000000000012dc <+24>:\tretq\n   0x00000000000012dd <+25>:\tcallq  0x1a75 <explode_bomb>\n   0x00000000000012e2 <+30>:\tjmp    0x12d8 <phase_1+20>\nEnd of assembler dump.\n```\n\n먼저 `phase_1` 함수는 `+11`에서  ` strings_not_equal` 함수를 호출함을 확인할 수 있다.  `+16`의 test 명령은  %eax를 AND 연산한다. 즉 %eax의 값이 0인지, 1인지를 판별하는 것이다. `+18`에서 jne(Jump If Not Equal) 명령은 `+16`이 1(Equal)인 경우 `+20`으로 넘어가고 0(Not Equal)인 경우 `+25`로 넘어가 `explode_bomb` 함수가 호출되어 폭탄이 터지게 된다.\n\n그렇다면 `strings_not_equal` 함수는 어떻게 구성되어 있을까?  `disas strings_not_equal`로 확인해보면 아래와 같다.\n\n```shell\n(gdb) disas strings_not_equal\nDump of assembler code for function strings_not_equal:\n   0x0000000000001771 <+0>:\tpush   %r12\n   0x0000000000001773 <+2>:\tpush   %rbp\n   0x0000000000001774 <+3>:\tpush   %rbx\n   0x0000000000001775 <+4>:\tmov    %rdi,%rbx\n   0x0000000000001778 <+7>:\tmov    %rsi,%rbp\n   0x000000000000177b <+10>:\tcallq  0x1754 <string_length>\n   0x0000000000001780 <+15>:\tmov    %eax,%r12d\n   0x0000000000001783 <+18>:\tmov    %rbp,%rdi\n   0x0000000000001786 <+21>:\tcallq  0x1754 <string_length>\n   0x000000000000178b <+26>:\tmov    $0x1,%edx\n   0x0000000000001790 <+31>:\tcmp    %eax,%r12d\n   0x0000000000001793 <+34>:\tje     0x179c <strings_not_equal+43>\n   0x0000000000001795 <+36>:\tmov    %edx,%eax\n   0x0000000000001797 <+38>:\tpop    %rbx\n   0x0000000000001798 <+39>:\tpop    %rbp\n   0x0000000000001799 <+40>:\tpop    %r12\n   0x000000000000179b <+42>:\tretq\n   0x000000000000179c <+43>:\tmovzbl (%rbx),%eax\n   0x000000000000179f <+46>:\ttest   %al,%al\n   0x00000000000017a1 <+48>:\tje     0x17ca <strings_not_equal+89>\n   0x00000000000017a3 <+50>:\tcmp    0x0(%rbp),%al\n   0x00000000000017a6 <+53>:\tjne    0x17d1 <strings_not_equal+96>\n   0x00000000000017a8 <+55>:\tadd    $0x1,%rbx\n   0x00000000000017ac <+59>:\tadd    $0x1,%rbp\n   0x00000000000017b0 <+63>:\tmovzbl (%rbx),%eax\n   0x00000000000017b3 <+66>:\ttest   %al,%al\n   0x00000000000017b5 <+68>:\tje     0x17c3 <strings_not_equal+82>\n   0x00000000000017b7 <+70>:\tcmp    %al,0x0(%rbp)\n   0x00000000000017ba <+73>:\tje     0x17a8 <strings_not_equal+55>\n   0x00000000000017bc <+75>:\tmov    $0x1,%edx\n   0x00000000000017c1 <+80>:\tjmp    0x1795 <strings_not_equal+36>\n   0x00000000000017c3 <+82>:\tmov    $0x0,%edx\n   0x00000000000017c8 <+87>:\tjmp    0x1795 <strings_not_equal+36>\n   0x00000000000017ca <+89>:\tmov    $0x0,%edx\n   0x00000000000017cf <+94>:\tjmp    0x1795 <strings_not_equal+36>\n   0x00000000000017d1 <+96>:\tmov    $0x1,%edx\n   0x00000000000017d6 <+101>:\tjmp    0x1795 <strings_not_equal+36>\nEnd of assembler dump.\n```\n\n비교할 문자열과 입력받은 문자열이 같은지를 확인하는 과정이다. 그렇다면 어셈블리 코드상에서 비교할 문자열이 있는 부분을 찾으면 된다. `b string_not_equal`과 `r`을 실행한 뒤 `layout asm`으로 TUI 환경을 enable 시키고 `ni` 명령어로 한 줄씩 확인해보았다.\n\n![](https://user-images.githubusercontent.com/16266103/97117767-47d31780-1749-11eb-97ab-37041e56b5bd.png)\n\n`x/s` 명령어로 %rdi와 %rsi의 메모리의 내용을 string 형식으로 출력해보았다.  %rdi 레지스터에는 `phase_1` 함수를 실행했을 때 입력했던 값이 들어가 있고 %rsi 레지스터에는 프로그램이 가지고 있는 문자열인 `Wow! Brazil is big`이 들어가 있는 것을 확인 할 수 있었다. bomb 실행 후 `phase_1` 입력값에 해당 문자열을 넣어보았는데 `phase_2`로 넘어가는 것에 성공하였다.\n\n### phase_2\n\n`disas phase_2` 명령어로 두 번째 phase 함수의 어셈블리 코드를 출력해보았다.\n\n```shell\n(gdb) disas phase_2\nDump of assembler code for function phase_2:\n   0x00000000000012e4 <+0>:\tpush   %rbp\n   0x00000000000012e5 <+1>:\tpush   %rbx\n   0x00000000000012e6 <+2>:\tsub    $0x28,%rsp\n   0x00000000000012ea <+6>:\tmov    %fs:0x28,%rax\n   0x00000000000012f3 <+15>:\tmov    %rax,0x18(%rsp)\n   0x00000000000012f8 <+20>:\txor    %eax,%eax\n   0x00000000000012fa <+22>:\tmov    %rsp,%rsi\n   0x00000000000012fd <+25>:\tcallq  0x1ab1 <read_six_numbers>\n   0x0000000000001302 <+30>:\tcmpl   $0x0,(%rsp)\n   0x0000000000001306 <+34>:\tjne    0x130f <phase_2+43>\n   0x0000000000001308 <+36>:\tcmpl   $0x1,0x4(%rsp)\n   0x000000000000130d <+41>:\tje     0x1314 <phase_2+48>\n   0x000000000000130f <+43>:\tcallq  0x1a75 <explode_bomb>\n   0x0000000000001314 <+48>:\tmov    %rsp,%rbx\n   0x0000000000001317 <+51>:\tlea    0x10(%rbx),%rbp\n   0x000000000000131b <+55>:\tjmp    0x1326 <phase_2+66>\n   0x000000000000131d <+57>:\tadd    $0x4,%rbx\n   0x0000000000001321 <+61>:\tcmp    %rbp,%rbx\n   0x0000000000001324 <+64>:\tje     0x1337 <phase_2+83>\n   0x0000000000001326 <+66>:\tmov    0x4(%rbx),%eax\n   0x0000000000001329 <+69>:\tadd    (%rbx),%eax\n   0x000000000000132b <+71>:\tcmp    %eax,0x8(%rbx)\n   0x000000000000132e <+74>:\tje     0x131d <phase_2+57>\n   0x0000000000001330 <+76>:\tcallq  0x1a75 <explode_bomb>\n   0x0000000000001335 <+81>:\tjmp    0x131d <phase_2+57>\n   0x0000000000001337 <+83>:\tmov    0x18(%rsp),%rax\n   0x000000000000133c <+88>:\txor    %fs:0x28,%rax\n   0x0000000000001345 <+97>:\tjne    0x134e <phase_2+106>\n   0x0000000000001347 <+99>:\tadd    $0x28,%rsp\n   0x000000000000134b <+103>:\tpop    %rbx\n   0x000000000000134c <+104>:\tpop    %rbp\n   0x000000000000134d <+105>:\tretq\n   0x000000000000134e <+106>:\tcallq  0xf00 <__stack_chk_fail@plt>\nEnd of assembler dump.\n```\n\n`phase_2` 함수는 `+25`에서 `read_six_numbers` 함수를 호출한다. 이름으로 여섯 개의 숫자를 입력받는다고 유추해볼 수 있다. `b read_six_number`로 해당 함수에 break point를 건 뒤 `r`로 실행해보자. 이때 `b explode_bomb`를 미리 실행해서 폭탄이 터지지 않도록 하는 것을 잊지 않도록 한다.\n\n```shell\n(gdb) disas read_six_numbers\nDump of assembler code for function read_six_numbers:\n   0x0000555555555ab1 <+0>:\tsub    $0x8,%rsp\n   0x0000555555555ab5 <+4>:\tmov    %rsi,%rdx\n   0x0000555555555ab8 <+7>:\tlea    0x4(%rsi),%rcx\n   0x0000555555555abc <+11>:\tlea    0x14(%rsi),%rax\n   0x0000555555555ac0 <+15>:\tpush   %rax\n   0x0000555555555ac1 <+16>:\tlea    0x10(%rsi),%rax\n   0x0000555555555ac5 <+20>:\tpush   %rax\n   0x0000555555555ac6 <+21>:\tlea    0xc(%rsi),%r9\n   0x0000555555555aca <+25>:\tlea    0x8(%rsi),%r8\n   0x0000555555555ace <+29>:\tlea    0x12b4(%rip),%rsi        # 0x555555556d89\n   0x0000555555555ad5 <+36>:\tmov    $0x0,%eax\n   0x0000555555555ada <+41>:\tcallq  0x555555554fa0 <__isoc99_sscanf@plt>\n   0x0000555555555adf <+46>:\tadd    $0x10,%rsp\n   0x0000555555555ae3 <+50>:\tcmp    $0x5,%eax\n   0x0000555555555ae6 <+53>:\tjle    0x555555555aed <read_six_numbers+60>\n   0x0000555555555ae8 <+55>:\tadd    $0x8,%rsp\n   0x0000555555555aec <+59>:\tretq\n   0x0000555555555aed <+60>:\tcallq  0x555555555a75 <explode_bomb>\nEnd of assembler dump.\n```\n\n`+7`부터 `+29`까지 베이스 상대 주소 지정방식으로 값을 읽어오고 있음을 알 수 있다. 해당 값의 내용을 확인해보기 위해 `ni`와 `x/d $rip+0x12b4`명령어로 무슨 내용인지를 확인해보았다.\n\n![](https://user-images.githubusercontent.com/16266103/97119113-6b01c500-1751-11eb-8d02-979e4d264d53.png)\n\n그 결과 6개의 숫자를 스페이스로 구분해서 받는다는 것을 확인할 수 있었다. 또한 `+41`을 보면 `<__isoc99_sscanf@plt>`로 무엇인가를 입력받는다는 것을 확인할 수 있다. `+53`은 jle(Jump Less or Equal)이며 `+50`의 cmp명령어에서 비교된 5($0x5)보다 작은 수들임을 알 수 있다. 즉, 5보다 작은 6개의 숫자를 스페이스로 구분하는 형식의 값을 입력해야 하는 것이다.\n\n단서를 얻었으니 `phase_2` 함수를 분석해보자. `+30`의 cmpl명령어는 값이 0($0x0)인지를 판별한다. `+34`의 jne(Jump If Not Equal)는 0인경우 `+43`으로 넘어가 `explode_bomb`를 실행하게 된다. 즉, 첫 번째 값은 0임을 유추할 수 있다.\n\n첫 번째 값을 맞혀 `+36`으로 넘어가면 이번엔 cmpl 명령어로 두 번째 값이 1인지를 검사한다. 따라서 두 번째 값은 1임을 알 수 있다.\n\n `+41`에서 je(Jump If Equal)명령어로 1인 경우 `+48`로 넘어가게 되며 mov명령어로rbx 레지스터에 rsp 레지스터의 값이 복사된다. `+51`에서 rbp 레지스터에 rbx 레지스터의 주소 값이 복사된다. 따라서 세 번째 값은 1이 된다.\n\njmp 명령어를 통해 `+66`으로 이동 후 eax 레지스터에 rbx 레지스터의 값이 복사된다. 그 후 eax 레지스터의 값과 rbx 레지스터의 값을 더하고 cmp 명령어로 현재 rbx 레지스터의 값과 eax 값이 같은지 확인 후 같으면 `+57`로 보낸다. 즉 네 번째 값은 2가 된다.\n\n여기까지 진행해보면 피보나치 수열의 규칙을 찾을 수 있다. `0 1 1 2 3 5`를 `phase_2` 함수의 입력값으로 넣게 되면 `phase_3`으로 넘어갈 수 있다.\n\n`phase_3` ~ `phase_6` 에 입력될 올바른 문자열을 찾는 방법에 대해서는 다음에 작성하게 될 Bomb Lab(2) 문서에서 설명해보려고 한다."
  },
  {
    "path": "CS/Call-By-Sharing.md",
    "content": "# Call By Sharing(a.k.a Call By Object, Call By Object-Sharing)\n\n## Call By Value와 Call By Reference\n\n들어가기에 앞서, 메소드의 호출 방식에는 크게 두 가지가 있다. **call by value(값에 의한 호출)** 과 **call by reference(주소에 의한 호출)** 이다. 이 두 가지 방법은 매개 변수로 전달된 값의 유형으로 구분한다. 이처럼 함수 호출 시 전달 값의 종류를 결정하는 방법을 [평가 전략(Evaluation strategy)](https://en.wikipedia.org/wiki/Evaluation_strategy) 이라고 한다.\n\n함수에 전달한 매개변수는 **actual parameter(actual argument; 실질 인자)** 라고 하고, 함수에서 수신받은 매개변수는 **formal parameter(formal argument; 형식인자)** 라고 한다.\n\n```js\nvoid method(formal parameter){}\n\nmethod(actual paramter)\n```\n\n> 하지만 acutal과 formal을 제외하고 parameter와 argument로 나누어 것을 많이볼수있다. 이 경우 parameter는 **formal** parameter(formal argument)를 뜻하고, argument는 **actual** parameter(actual argument)를 뜻한다. \n>\n>헷갈리면 다음을 참고하자 [Parameter_(computer_programming)](https://en.wikipedia.org/wiki/Parameter_(computer_programming))\n\n### Call By Value\n\ncall by value 방식은 actual parameter의 값을 formal parameter에 복사한다. 각각은 서로 다른 메모리 공간에 할당된다. 따라서 call by value 방식에서는 formal parameter가 지역변수 처럼 사용되고, formal parameter의 변경은 actual parameter에 영향을 주지 않는다.\n\n```js\nint i = 0;\n\nfunction changeValue(i){\n    i = 1;\n}\n\nchangeValue(i); // i == 0\n```\n\n### Call By Reference\n\ncall by reference 방식은 formal parameter가 actual parameter를 그대로 사용한다. 따라서 formal parameter가 변경되면 actual parameter도 변경된다.\n\n```js\nint i = 0;\n\nfunction changeValue(i){\n    i = 1;\n}\n\nchangeValue(i); // i == 1\n```\n\n이러한 방식은 대부분의 고급언어에서는 구현이 불가능하다. 비교적 저급언어에 가까운 c의 pointer를 이용하면 이를 확인할 수 있다.\n\n> call by reference의 예시 c언어의 swap 함수 구현이 많이 사용된다.\n> 참고 - [C Program to Swap two Numbers](https://www.geeksforgeeks.org/c-program-swap-two-numbers/)\n\n## 객체 기반 언어의 메소드 호출\n\njava, JS, python 등의 고급 언어는 객체(Object)를 기반으로 구현되어 있다. 원시값(primitive value)을 제외한 모든 것은 객체인데, 객체를 변수에 할당하면 값이 아닌 주소 값이 저장된다. 따라서 객체가 할당된 변수를 사용하는 것은 주소를 참조하는 것과 같다. 이 때문에 다음과 같은 동작이 가능하다.\n\n```js\nclass Main{\n    main(){\n        VO vo = new VO(0);\n        changeValue(vo); // vo.i == 1;\n    }\n\n    function changeValue(VO vo){\n        vo.i = 1;\n    }\n}\n```\n\n이러한 동작 때문에 call by reference 라고 생각할 수 있지만 그렇지 않다.\n\n> 예시(java)\n>\n> ```java\n> public class Main{\n>     public static void main(String[] args){\n>         VO vo = new VO(); // vo.i ==null;\n>         changeValue(vo); // vo.i == 1;\n>         changeReference(vo); // vo.i == 1;\n>     }\n>\n>     private static void changeValue(VO vo){\n>         vo.i = 1;\n>     }\n>\n>     private static void changeReference(VO vo){\n>         vo = new VO();\n>         vo.i = 2;\n>     }\n> }\n>\n> class VO{\n>     Integer i;\n> }\n> ```\n\n> 예시(JS)\n>\n> ```js\n> var test = { i: 0 }; // test.i === 0\n>\n> // change value\n> ((test) => {\n>   test.i = 1;\n> })(test); // test.i === 1\n>\n> // change reference\n> ((test) => {\n>   test = { i: 2 };\n> })(test); // test.i === 1\n> ```\n\n위의 예시처럼 parameter를 바꿔도 argument가 바뀌지 않지만, parameter가 객체인 경우 그 멤버를 변경하면 argument의 멤버도 변경된다. 위의 java 예시는 아래와 같이 동작한다.\n\n![call by sharing](../assets/images/call-by-sharing01.png)\n\n이러한 평가 전략을 call by sharing이라고 한다.\n\n## Call By Sharing\n\n> call by sharing은 [CLU](<https://en.wikipedia.org/wiki/CLU_(programming_language)>) 라는 언어에서 처음 사용되었다.\n\ncall by sharing은 의 주요 컨셉은 **actual parameter와 formal parameter가 객체만을 주고받는 것**이다.\n\n모든 값을 박스처럼 생각하는 것과 비슷하다. 박스를 주고 받을 때, 박스 자체가 바뀌지 않는다면 그 박스의 내용물은 바뀔 수 있다. 즉 객체 자체가 바뀌지 않는다면 객체의 멤버가 변화하는 것이 actual parameter에 전달된다.\n\ncall by value 방식만으로도 이러한 동작을 설명할 수 있기 때문에 call by value라고 설명하기도 하지만 call by sharing이라고 하는 것이 더 정확하다. **call by sharing은 call by value와 달리 actual parameter가 변화한다는 개념을 포함** 하고 있기 때문이다. 또한 **call by sharing은 언어의 값이 객체를 기반으로 한다는 의미를 포함** 한다는 차이가 있다.\n\n---\n\n#### Refereces\n\n- [Difference between Call by Value and Call by Reference](https://www.geeksforgeeks.org/difference-between-call-by-value-and-call-by-reference/)\n\n- [Evaluation strategy](https://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_sharing)\n\n- [[프로그래밍언어] Formal parameter, Actual parameter, 그리고 parameter passing](https://yunmap.tistory.com/entry/프로그래밍언어-Formal-parameter-Actual-parameter-그리고-parameter-passing)\n\n- [Call by Sharing](http://www.pmg.lcs.mit.edu/papers/thetaref/node34.html)\n"
  },
  {
    "path": "CS/Counting-sort.md",
    "content": "# 계수 정렬(Counting Sort)\n\n비교정렬(comparison sort)의 시간복잡도의 하한은 O(nlogn) 이다.\n\n계수 정렬은 non-comparison sort 기법이며, 정렬에 드는 계산복잡도을 O(n) 으로 낮추기 위한 알고리즘이다.\n\n정확히 말하면, 정렬할 수 중 가장 큰 값을 k라고 했을 때 계수정렬의 계산복잡도는 O(n+k) 이다.\n\n따라서 정렬할 수의 최대값이 낮을때 효과적이며, k의 값이 매우 커지게 되면 다른 정렬 알고리즘에 비해 성능이 떨어진다.\n\n> 가령 k가 n^2보다 커지게 되는 경우 선택, 삽입, 버블 정렬 등의 기본적인 정렬 알고리즘보다도 속도가 느리게 된다.\n\n## 수행 과정\n\n계수 정렬은 정렬하려는 수들의 개수를 세어 누적합을 구한 뒤, 누적합에 따라 수를 정렬하는 것이다.\n\n이 때, 정렬 대상의 원소는 모두 양의 정수여야한다.\n\n1. 정렬 대상에서 중복되는 값의 개수를 구하여 저장한다.\n2. 저장한 중복 횟수를 누적합으로 바꾼다.\n3. 정렬 대상을 역순으로 순회하며 결과를 출력한다.\n\n### 예시1\n\n```js\n// 아래의 배열을 정렬\narr = {2, 0, 2, 0, 4, 1, 5, 5, 2, 0, 2, 4, 0, 4, 0, 3}\n```\n\n- 배열 arr 에 들어있는 요소들이 몇 개씩 들어있는지 파악한다.\n\n  ```js\n  cnt = {5, 1, 4, 1, 3, 2}\n  cnt[0] 0의 개수이다. 배열 A에 0이 5개 들어있기 때문에 cnt[0] 의 값은 5가 된다.\n  ```\n\n- 배열 cnt 의 요소값에 이전 요소들의 누적값을 더해준다.\n\n  ```js\n  cnt = {5, 6, 10, 11, 14, 16}\n  cnt[1] = cnt[0] + cnt[1] // 5 + 1\n  cnt[2] = cnt[0] + cnt[1] + cnt[2] // 5 + 1 + 4\n  cnt[3] = cnt[0] + cnt[1] + cnt[2] + cnt[3] // 5 + 1 + 4 + 1\n  ...\n  ```\n\n  이 과정을 거치지 않고, 순서대로 출력하면 된다고 생각할 수 있다.\n\n  이 경우 정렬 대상의 최대값에 큰 영향을 받기 때문에 오히려 비효율적이다.\n\n  non-comparison 방식으로 정렬을 하기 위해서는 배열 cnt 의 길이가 정렬 대상의 최대값과 같아야하기 때문이다.\n\n  각 요소를 비교하지 않고 누적합을 이용하기 때문에 non-comparison이 된다.\n\n  또한, 원본배열을 역순으로 순회하며 정렬하는 방식을 이용하면 stable한 상태를 유지할 수 있다.\n\n  > stable하다는 것은 처음 순서대로 정렬이 된다는 것인데, 위의 예시에서는 첫 번째 0과 두 번째 0이 뒤바뀌지 않고 정렬된다. 이는 아래 [예시2](#예시2) 에서 설명할것이다.\n\n- 배열 arr 의 요소값을 역순으로 저장한다.\n\n  ```c\n  int[arr.length] result; // 결과값 배열의 크기는 정렬 대상과 같아야 한다.\n  for(i = arr.length-1; i>=0; i--){\n    result[cnt[arr[i]] = arr[i];\n    /* 배열 cnt의 값이 result의 인덱스가 되기 때문에,\n     * 값을 저장한 수의 누적값을 감소시켜야 한다.\n     */\n    cnt[arr[i]]--;\n  }\n  ```\n\n### 예시2\n\n계수정렬은 stable한 정렬이고, 이를 위해 카운팅 이후 한 번의 과정을 더 거친다.\n\n숫자의 정렬 예시 만으로는 그 이유가 한 눈에 들어오지 않을 수 있다.\n\n좀 더 쉬운 이해를 위해 이번에는 단어 **banana** 를 정렬해보자.\n\n확인을 위해 순번 `seq` 필드를 추가한 `Alphabet` 타입을 사용할 것이다.\n\n```java\nAlphabet{\n  int seq = 0;\n}\n\nAlphabet b, a, n, a, n, a = new Alphabet();\n\n// 아래의 배열을 정렬\nAlphabet[] word = {b, a, n, a, n, a};\n```\n\nword를 카운팅한 누적합의 인덱스는 쉬운 이해를 위해 영문으로 표기할 것이다.\n\n또한 크기가 a...n 이고 각 요소가 0으로 초기화된 배열 `count` 가 있다고 가정한다.\n\n```java\n// 중복 개수 카운팅\nfor(Alphabet alphabet : word){\n  count[alphabet] ++;\n  // 카운팅 순서 저장\n  alphabet.seq = count[alphabet];\n}\n// 누적합\nfor(int i = 1; i < word.length; i ++;){\n  word[i] += word[i-1];\n}\n```\n\n누적합이 구해진 `count` 배열은 아래와 같을 것이다.\n\n| a   | b   | n   |\n| --- | --- | --- |\n| 3   | 4   | 6   |\n\n예시1과 마찬가지로, 배열 `word` 에 저장된 알파벳을 역순으로 꺼내서 결과 배열에 저장하면 stable하게 저장된 결과를 얻을 수 있을 것이다.\n\n역순으로 꺼내는 것과 비교 하기 위해 이번에는 원본 배열을 앞에서 부터 순회해보자.\n\n```java\n// word == {b, a, n, a, n, a};\n// count == {3, 4, 6}\n\nresult[3] = b; // b.seq == 1, count == {3, 3, 6}\nresult[2] = a; // a.seq == 1, count == {2, 3, 6}\nresult[5] = n; // n.seq == 1, count == {2, 3, 5}\nresult[1] = a; // a.seq == 2, count == {1, 3, 5}\nresult[4] = n; // n.seq == 2, count == {1, 3, 4}\nresult[0] = a; // a.seq == 3, count == {0, 3, 4}\n\n```\n\n앞에서부터 정렬할 경우도 **a a a b n n** 의 순서로 정렬되는 것은 동일하지만, 원본 배열 `word` 와 순서가 달라진 정렬이 된다.\n\n이는 stable한 정렬이 아니다. `result[0]` 의 `a` 는 `word[5]` 의 `a` 와 같고, `result[1]` 의 `a` 는 `word[3]` 의 `a` 와 같기 때문이다.\n\nstable한 정렬은 `result[0]` 의 `a` 가 `word[1]` 의 `a` 와 같아야 하고 `result[1]` 의 `a` 가 `word[3]` 의 `a` 와 같아야 한다. 즉 원본 배열의 순서를 유지한채로 정렬이 되어야 한다.\n\n---\n\n#### References\n\n- [Counting Sort : 계수 정렬 ](https://bowbowbow.tistory.com/8)\n- [카운팅 정렬, 래딕스 정렬 ](https://ratsgo.github.io/data%20structure&algorithm/2017/10/16/countingsort/)\n"
  },
  {
    "path": "CS/Graph.md",
    "content": "# 그래프\n\n## 쾨니히스베르크 다리 문제\n\n![](../assets/images/Graph-쾨니헤스베르크_다리.png)\n\n프로이센의 쾨니히스베르크(오늘날 러시아 칼리닌그라드)에 강이 있고 강으로 둘러싸인 섬이 하나 있다. 섬을 잇는 다리가 7개가 있는데 이를 모두 한 번씩만 건너서 출발한 곳으로 다시 돌아오려고 하는 사람들이 있었지만, 아무도 답을 찾지 못했다. 수학자 오일러가 이는 불가능하다는 것을 밝혀냈는데, 여기서 나온 방법론이 방법이 한 번쯤은 들어봤을 법한, 한붓그리기라는 개념이다.\n\n> 참고 - [한붓그리기](https://ko.wikipedia.org/wiki/%ED%95%9C%EB%B6%93%EA%B7%B8%EB%A6%AC%EA%B8%B0)\n\n이처럼 이동할 수 있는 방법을 탐색하는 방법론을 그래프 이론 혹은 그래프 알고리즘이라 한다. 더 정확히는 객체 간의 짝을 이루는 관계를 모델링하기 위한 수학 구조를 그래프라 한다.\n\n<br/>\n\n## 그래프의 구성\n\n그래프는 **꼭짓점(vertex;정점 혹은 교점;node 혹은 점;point)** 으로 구성되며, 이들은 **변(edge; 간선 혹은 link)** 으로 연결된다. 이때 두 꼭짓점 사이에 변이 존재하는 것을 **인접(adjacent)** 이라고 한다. 또한, 어떠한 변을 구성하는 꼭짓점들은 해당 변과 '**근접(incident)하다'** 라고 한다.\n\n![](../assets/images/Graph-그래프.png)\n\n<br/>\n\n## 보행(walk)\n\n보행은 꼭짓점과 변이 교대로 나타나는 열(sequence)이면서, 각 변의 앞과 뒤에 위치한 꼭짓점을 그 변의 양 끝점으로 갖는 열을 뜻한다.\n\n> 간단히 말하면, 보행은 그래프상에서 어딘가를 지나가는 것이다.\n\n보행의 종류는 다음과 같다.\n\n- 트레일(trail) : 변이 중복되지 않는 보행\n- 경로(path) : 꼭짓점이 중복되지 않는 트레일. 변과 꼭짓점이 모두 중복되지 않는 보행과 같다.\n- 닫힌 보행(closed walk) : 시작점과 끝이 같은 보행이다.\n- 닫힌 트레일(closed trail) : 변이 겹칠 수 없는 닫힌 보행이다.\n- 순환(cycle) : 꼭짓점이 겹치지 않는 닫힌 트레일을 뜻한다. 다른 말로는 회로(circuit) 또는 여행(tour)라고 한다.\n\n![](../assets/images/Graph-보행.png)\n\n위 그래프에서,\n\nAHDGAB는 트레일이다. 중복되는 변이 없지만, 꼭짓점 A가 반복되므로 경로는 아니다.\n\nHAB와 HDG는 경로이다. 변과 꼭짓점이 모두 중복되지 않는 보행이기 때문이다.\n\nBDEFDB는 닫힌 보행이다. 변 BD가 반복되기 때문이다.\n\nBDEFDCB는 닫힌 트레일이다. 꼭짓점 D가 반복되므로 순환이 아니다.\n\nHDGH는 순환이다.\n\n<br/>\n\n## 그래프 크기의 척도\n\n- 거리(distance) : 두 꼭짓점 사이의 경로 가운데 가장 짧은 것의 변의 수이다. 만약 이러한 경로가 존재하지 않는다면, 거리의 길이는 무한대이다.\n- 이심률(eccentricity) : 한 꼭짓점에서 다른 모든 꼭짓점 사이의 거리 중 가장 큰 거리\n- 지름(diameter) : 그래프의 최대 이심률\n- 가중치(weight) : 정점 또는 변에 할당된 비용 또는 거리\n\n![](../assets/images/Graph-크기.png)\n\n> - 무게는 정점 또는 변에 할당된 비용 또는 거리이다.\n\n- 그래프 문제 중 최단 경로 문제는 가중치의 합이 최소가 되는 경로를 구하는 문제이다.\n- 가중치 그래프(weighted graph)는 네트워크(network)라고도 한다.\n\n<br/>\n\n## 그래프의 종류\n\n그래프는 크게 유향 그래프와 무향 그래프로 나눌 수 있다. 유향 그래프는 말 그대로 그래프에 방향성이 있는 것이다.\n\n> 모든 보행이 양방향인 유향 그래프는 무향 그래프이다.\n\n![](../assets/images/Graph-종류.png)\n\n### 무향 그래프의 요소\n\n- 차수(degree) : 한 꼭짓점에 이어져 있는 변의 수\n\n<br/>\n\n### 유향 그래프의 요소\n\n- 입력 차수(in-degree) : 한 꼭짓접으로 들어오는 변의 개수\n- 출력 차수(out-degree) : 한 꼭짓점에서 나가는 변의 개수\n\n<br/>\n\n## 그래프의 표현\n\n그래프는 크게 인접, 근접, 차수를 이용하여 표현할 수 있다. 그중 인접을 이용한 인접 행렬과 인접 리스트로 표현하는 경우가 많다.\n\n> 그래프를 행렬로 나타낼 경우 직관적이다. 하지만, 2차원 배열로 그래프를 표현하기 때문에 불필요한 정보의 저장이 많아진다. 따라서 알고리즘에는 리스트가 주로 사용된다.\n\n<br/>\n\n### 인접 행렬(Adjacency Matrix)\n\n인접 행렬 그래프는 보행을 1, 보행할 수 없는 꼭짓점의 관계를 0으로 표현한다.\n\n![](../assets/images/Graph-행렬.png)\n\n### 인접 리스트 그래프(Adjacency List)\n\n인접 리스트 그래프는 리스트(List)나 벡터(Vector) 등의 자료구조를 이용하여 보행이 가능한 꼭짓점들을 저장한다.\n\n![](../assets/images/Graph-리스트_무향.png)\n\n![](../assets/images/Graph-리스트_유향.png)\n\n---\n\n#### References\n\n- [쾨니히스베르크 다리 문제 - 수학 이야기](https://suhak.tistory.com/54)\n- [그래프 이론 기초 정리 - kwangsik lee's blog](http://www.kwangsiklee.com/2017/11/%EA%B7%B8%EB%9E%98%ED%94%84-%EC%9D%B4%EB%A1%A0-%EA%B8%B0%EC%B4%88-%EC%A0%95%EB%A6%AC/)\n- [쉽게 쓴 그래프 알고리즘 기초 - 코딩과 디버깅 사이](https://m.blog.naver.com/occidere/220923695595)\n- [그래프 이론 - 위키백과](https://ko.wikipedia.org/wiki/%EA%B7%B8%EB%9E%98%ED%94%84_%EC%9D%B4%EB%A1%A0)\n- [가중 그래프 - 위키백과](https://ko.wikipedia.org/wiki/%EA%B0%80%EC%A4%91_%EA%B7%B8%EB%9E%98%ED%94%84)\n- [경로(그래프 이론) - 위키백과](<https://ko.wikipedia.org/wiki/%EA%B2%BD%EB%A1%9C_(%EA%B7%B8%EB%9E%98%ED%94%84_%EC%9D%B4%EB%A1%A0)>)\n- [IT CookBook, 쉽게 배우는 알고리즘](http://www.hanbit.co.kr/store/books/look.php?p_code=B7707942187)\n"
  },
  {
    "path": "CS/Memory.md",
    "content": "# Memory\n\n메모리는 말그대로 저장소다. 뭔가를 하려면 어떤 데이터를 어떻게 처리하라고 한다. 즉 데이터와 처리명령 두가지가 필요하다.\n\n그래서 메모리도 두 영역으로 나뉘어 있다. Program / Data 부분이 나뉜다.\n\n## 메모리 계층구조\n\n메모리는 당연히 빠를수록 비싸다. 그래서 빠르고 비싼 메모리는 용량이 작다. 반대로 느리면서도 싼 메모리는 용량이 크다. 아주 쉽게 생각할 것은 HDD와 SSD의 차이를 생각해보면 된다.\n\n![memoryHierachy](/assets/images/memoryHier.png)\n\n그래서 위와 같은 그림이 나온다. 레지스터와 캐시는 CPU 내부에 존재한다. 그만큼 작고 빠르다. Cache는 SRam과 같다. Memory는 Dram이다. 흔히 RAM 이라고 부른다. 8GB DDR4 램 사면 이거다. Disk는 하드디스크 그거다.\n\n보통 레지스터, 캐시, 메모리를 주 기억장치, 디스크를 보조 기억장치라고 부른다. 주 기억장치는 보조보다는 빠르나 전원을 끄면 데이터가 날아간다.(휘발성)\n\n## 메모리 구조\n\n메모리는 다음 그림과 같이 공간을 나누어 관리한다.\n\n![memoryModel](/assets/images/memorymodel.png)\n\n그림에 따라 low address와 high address가 반대가 되어 스택이 쌓이는 구조로 보이기도 한다. 그러나 중요한 점은 메모리는 사용용도에 따라 구역을 나누어 관리하고 순서가 있다는 점이다.\n\n### TEXT\n\n프로그램 코드가 저장되는 영역이다. 따라서 코드영역이라고도 불린다. 물론 개발자가 작성한 소스코드는 아니고 기계어로 저장된다.\n\nRead-Only Data다. CPU가 이 영역의 데이터를 fetch해서 실행한다.\n\n### DATA(GVAR + BSS)\n\n전역변수, static 변수가 저장되는 공간이다.\n\n초기화된 데이터는 data 영역에 저장되고, 초기화 되지 않은 데이터는 BSS(Block Stated Symbol)영역에 저장된다.\n\n    js의 var let const의 호이스팅 시 선언, 초기화, 할당에 관한 내용 중 초기화와 관련한 내용이지 않을까 싶다.\n    let과 const는 선언만 되며 초기화가 되지않아 메모리에 없다.\n    그런데 js는 전역 스코프 역시 객체다. 그럼 참조타입이라 heap에 저장될 것 같다.\n    실행 컨텍스트와 관련된 내용같은데 자세히 좀 더 알아보자\n\n프로그램이 실행될 때만 생성되고 종료시 반환하는 영역이다.\n\n### HEAP\n\n흔히 참조타입이 저장된다. 이 영역에 저장하기 위해 `new` 키워드를 사용한다.\n\n개발자가 임의로 만들 수 있는 영역이라 동적 할당영역이라고 부른다.\n\nHEAP을 참조하는 영역이 없으면 GC가 돌면서 마킹을 통해 제거하는 영역이다.\n\n### STACK\n\n지역변수, parameter, 리턴 값 등이 임시로 저장되었다가 사라지는 영역입니다.\n\n원시 값 타입이 저장되는 공간입니다.\n\nstack은 함수 호출 시 할당되며 함수 종료(return)시 제거됩니다.\n\n엄격하게 LIFO가 지켜집니다. 이렇게 스택에 저장되는 호출정보를 stack frame이라고 합니다. 흔히 우리가 부르는 call stack은 stack frame과 연관이 있습니다.\n\n### 흐름\n\n1. 개발자가 소스코드를 완성하여 컴파일 => 실행단계가 되면 코드는 TEXT에 올라간다.\n2. 프로그램이 실행되면 프로그램은 프로세스가 된다.(프로세스 == 실행중인 프로그램)\n3. 프로세스의 흐름에 따라 DATA영역에 전역과 static변수를 만든다.\n4. 코드의 흐름에따라 HEAP과 STACK영역을 움직이며 메모리를 사용한다.\n5. 프로그램이 종료되면 DATA영역을 반환한다.\n\n### 문제\n\n너무 자주 봐왔고, 참조변수와 포인터에 관한 이야기다.\n\n```js\nconst arr = [1, 2, 3];\n\nconst foo = arr => {\n  arr[1] = 100;\n  arr = [4, 5, 6];\n\n  console.log(arr);\n};\n\nfoo(arr);\n\nconsole.log(arr);\n```\n\n어떻게 나올지는 항상 언제 물어봐도 메모리 그림을 그려 대답할 수 있도록 하자.\n\n### 참고자료\n\n- [메모리 저장구조 이해하기](https://m.blog.naver.com/PostView.nhn?blogId=itperson&logNo=220821884483&proxyReferer=https%3A%2F%2Fwww.google.com%2F)\n- [TCP school 메모리의 구조](http://tcpschool.com/c/c_memory_structure)\n"
  },
  {
    "path": "CS/Radix-sort.md",
    "content": "# 기수 정렬(Radix Sort)\n\n비교(comparison) 기반 정렬 알고리즘의 가장 낮은 복합도는 `O(nlogn)` 이다.\n\n반면 계수 정렬(counting sort)은 선형 시간 정렬 알고리즘이다. 검색 대상의 범위가 1부터 k까지라고 할 때 `O(n+k)` 의 복합도를 가진다.\n\n> [선형 시간(lineart time)](https://ko.wikipedia.org/wiki/%EC%84%A0%ED%98%95_%EC%8B%9C%EA%B0%84) : 계산 복잡도 이론에서 입력된 길이 n에 대하여 실행시간이 `O(n)` 이 되는 것\n>\n> 참고 : [계수 정렬](https://github.com/Im-D/Dev-Docs/blob/master/CS/Counting-sort.md)\n\n하지만 대상의 범위 k가 n^2 보다 커질 경우 `O(n^2)` 이상의 복잡도를 가지게 된다. 이는 비교 기반 정렬 알고리즘보다 성능이 좋지 않다.\n\n이런 경우 기수 정렬을 통해 선형 시간을 갖는 정렬을 할 수 있다. \n\n## 수행과정\n\n기수 정렬은 각 자릿수마다 순차적으로 정렬하는 방식이다. \n\n10진수를 사용한다면 각 자릿수는 최소 0에서 최대 9까지의 값만 나올 수 있다.\n\n따라서 각 자릿수 마다 계수 정렬을 실행한다면, 계수 정렬 대상의 수는 항상 10 이하로 정해진다.\n\n> 계수 정렬을 사용하기 때문에 부동 소수점은 정렬이 불가능하다.\n\n수행과정은 다음과 같다.\n\n```java\n// 정렬 대상\nint arr[] = {170, 45, 75, 90, 802, 24, 2, 66};\nint max = 정렬 대상의 최대값\n    \nfor (자릿수 = 1; max/자릿수 > 0; 자릿수 *= 10) {\n\t계수정렬 실행\n} \n```\n\n> 참고 :  [수행과정 - Radix Sort | GeeksforGeeks](https://youtu.be/nu4gDuFabIM?t=18)\n\n\n\n자릿수의 개수만큼 반복해야하기 때문에 최고 자릿수가 `d` 일 때 기수 정렬의 시간 복잡도는 `O(dn)` 이다. 예를 들어, 가장 큰 수가 10000이라면, 최고 자릿수가 5이기 때문에 `O(5n)` 이 된다.\n\n따라서 특정 조건을 만족하면 아주 빠른 알고리즘이지만, 자릿수 만큼의 저장 공간이 추가로 발생하기 때문에 공간 복잡도가 좋지 않다.\n\n## 기수 정렬의 다른 방법\n\n위에서 알아본 계수 정렬 방법은 일반적인 방법으로 가장 오른쪽 부터 시작하는 LSD radix sort이다. 반대로 가장 왼쪽 부터 시작하는 경우는 MSD라고 한다.\n\n> LSD(Least Significant Digit; 최하위 자릿수)\n>\n> MSD(Most Significant Digit; 최대 자릿수)\n\nLSD의 경우 stable하지만, MSD는 stable 하지 않다. 따라서 기수 정렬의 서브루틴으로 계수 정렬을 사용하기 위해서는 LSD를 사용해야한다.\n\nLSD는 모든 자릿수를 정렬해야 정렬된 결과를 얻을 수 있지만, MSD의 경우 중간에 정렬이 완료될 수 있다. 하지만 이를 위해 추가적인 연산과정과 메모리가 필요하다. 자세한 사항은 다음을 참고하자.\n\n> 참고 : [In-place MSD radix sort implementations - wikipedia](https://en.wikipedia.org/wiki/Radix_sort#In-place_MSD_radix_sort_implementations)\n\n### 버킷 정렬(bucket sort)\n\n이외에도 큐 혹은 버킷을 이용하여 기수 정렬을 구현하는 경우가 있다. 이는 버킷 정렬을 사용한다.\n\n![bucketsort](../assets/images/bucket-sort.png)\n\n버킷 정렬은 정렬 대상의 값들이 일정하게 분포되어 있을 때 효과적인 방법이다.\n\n값의 분포에 따라 특정 범위를 지정한다. 이 때, 지정한 범위가 버킷이다.\n\n범위에 해당되는 값들을 각 버킷에 담고 버킷 내의 값들을 정렬하는 방법이다.\n\n이 때, 버킷 내의 값들은 버킷 정렬을 반복하여 적용시키거나, 다른 알고리즘을 사용하여 정렬한다.\n\n이러한 원리를 이용하여 기수 정렬을 병렬 컴퓨팅에 적용하는 경우도 있는데 이는 다음을 참고하자\n\n> 참고 \n>\n> - [Application to parallel computing - wikipedia](https://en.wikipedia.org/wiki/Radix_sort#Application_to_parallel_computing)\n> - [Fastest sorting algorithm for distributed systems (Parallel Radix Sort) [Difficulty: Medium]](https://summerofhpc.prace-ri.eu/fastest-sorting-algorithm-for-distributed-systems-parallel-radix-sort-difficulty-medium/)\n\n---\n\nReferences\n\n- [Bucket Sort - GeeksforGeeks](https://www.geeksforgeeks.org/bucket-sort-2/)\n- [What are the differences between radix sort and bucket sort? - Quora](https://www.quora.com/What-are-the-differences-between-radix-sort-and-bucket-sort)\n- [Radix Sort - BRILLIANT](https://brilliant.org/wiki/radix-sort/)\n- [Radix sort - wikipedia](https://en.wikipedia.org/wiki/Radix_sort)\n- [기수 정렬(Radix Sort) - tubuk.tistory.com](https://tubuk.tistory.com/16)\n"
  },
  {
    "path": "CS/aspect-oriented-programming.md",
    "content": "# 관점(관심) 지향 프로그래밍(Aspect Oriented Programming)\n\n## 관점(Aspect)과 횡단 관심사(Cross-cutting Concern)\n\n관점 지향 프로그래밍은 관점을 기반으로 한 개발 패러다임이다. 여기서 관점이라는 말이 모호한데, 컴퓨팅 용어 **aspect** 를 직역한 표현이라 바로 와 닿지 않는다.\n\n프로그래밍 용어로써 aspect는 프로그램의 다른 부분들과 연결되어있지만, 프로그램의 주요 기능과는 연결되지 않은 부분을 뜻한다. 핵심 관심사(core concerns)를 가로지르는(crosscut) 부분들을 모듈화시킨 것이다. 이때, 핵심 관심사를 가로지르는 부분을 **횡단 관심사(cross-cutting concern)** 라고 한다. 이때 가로지른다는 것은 공통의 관심사를 수직이 아닌 수평적으로 찾아낸다는 것이다. 전통적인 추상화 방식에서는 상위 클래스와 하위 클래스 간의 공통 관심사를 수직적으로 묶지만, 관점 지향 프로그래밍에서는 연관이 없는 클래스들의 공통 관심사를 수평적으로 묶어 캡슐화한다.\n\n![crosscut.png](https://github.com/Dae-Hwa/diagrams/blob/master/aop/crosscut.png?raw=true)\n\n가장 쉬운 예시로는 로그를 쌓고자 하는 경우를 들 수 있다. 클래스 혹은 함수단위의 로그를 쌓고자 하는 경우 해당 객체의 핵심 기능과 별개의 코드가 필요하다.\n\n```java\nclass NonAspectOrientedSample {\n    private void logging() {\n        // ...\n    }\n    \n    public void doSomething() {\n        logging();\n        // ...\n    }\n    \n    public void doOtherthing() {\n        logging();\n        // ...\n    }\n}\n```\n\n하지만 코드는 계속해서 중복되기 때문에 새로운 추상화가 필요한데 전통적인 개발 방식만으로는 추상화가 모호해질 가능성이 크다. 추상화를 하여 함수를 재정의(overriding)하더라도 해당 클래스에는 핵심 기능과 별개의 코드가 포함되는 것이기 때문이다.\n\n```java\nclass NonAspectOrientedSample implements Logger {\n    @Override\n    public void logging() {\n        // ...\n    }\n    \n    public void doSomething() {\n        logging();\n        // ...\n    }\n    \n    public void doOtherthing() {\n        logging();\n        // ...\n    }\n}\n```\n\n이처럼 핵심 기능과 별개의 코드가 클래스에 포함되는 것은 엄밀히 따지면 [단일 책임 원칙](https://github.com/im-d-team/Dev-Docs/blob/master/CS/srp.md)을 위반하는 것이다. 이런 경우 횡단 관심사를 분리하여 해결할 수 있다.\n\n## 사용되는 용어들\n\n### Join Point\n\naspect는 기존 프로그램의 동작과 관계없이 추가, 변경 가능해야 한다. 관점 지향 언어들은 기존 프로그램의 동작과 관계없이 실행 지점을 설정할 수 있도록 지원해주는데 이를 **join point**라고 한다. 메소드 실행(method execution)이나 메소드 콜(method call)과 같은 시스템의 실행을 포인트로 지정하는 것이다. \n\n### Pointcut\n\njoin point를 언어 수준에서 표현한 것이다. 언어 구조 내에서 지원하거나, 쿼리와 유사한 표현식을 사용하여 표현할 수 있다. \n\n### Advice\n\npointcut을 만족하는 join point에 도달했을 때 실행할 코드 모음이다. 이때 advice의 종류에 따라 실행 시점이 달라진다. 실행 시점에 따라 다음과 같은 종류가 있다.\n\n-   before advice : 메소드 실행 이전\n-   after advice\n\n    -   after returning advice : 메소드가 정상 작동한 이후\n    -   after throwing advice : 예외 발생 시\n    -   after finally advice : 메소드가 실행 된 이후 반드시 실행\n-   around advice : 모든 시점 실행\n\n### Inter-type Declaration(ITD)\n\n클래스 멤버나 클래스 계층을 임의로 변경하는 것이다. 예를 들어, 클래스 실행 시간을 로깅하고 싶지만 해당 클래스에 관련 멤버가 없다면 aspect 실행 시점에 실행시간 필드를 추가할 수 있다.\n\n### Aspect\n\naspect는 pointcut과 advice, inter-type declaration이 합쳐진 것이다. 즉 하나의 실행 단위이다.\n\n>   spring aop에서는 aspect를 advisor라고 부른다.\n\n### Weaving\n\nAdvice를 join point에 합쳐준다. 컴파일 혹은 로드 타임에 바이트 코드를 조작하거나 런타임에 프록시를 생성하여 합치는 방법이 있다.\n\n## AOP는 만능인가?\n\n위에서 본 개념들만 살펴봤을 때는 AOP가 구세주처럼 느껴질 수 있다. 하지만 AOP에도 문제 발생 가능성이 있다. AOP를 사용할 경우 아래 사항들을 인지한 뒤 도입해야 한다.\n\n첫째로 언어 차원에서 타겟 클래스에 표시하지 않도록 되어있다면 해당 코드 작성자 이외에는 해당 코드에 aspect가 적용되는 것인지 알 수 없다. 해당 코드 이외에 전체적인 시스템의 흐름이 파악되어야 정확히 이해할 수 있다. 특히 pointcut이 훼손될 경우 찾아내는 데 큰 어려움을 겪을 수 있다.\n\n둘째로 aspect를 통한 모듈화가 오히려 모듈화를 방해할 수 있다. AOP는 핵심 로직에만 집중할 수 있도록 돕는 도구인데 AOP가 주가 되어버리는 경우이다. \n\n셋째로 동시에 여러 개의 aspect가 적용될 경우 문제가 발생할 수 있으며, aspect가 자기 자신에게 적용된다면 의도하지 않은 결과가 나올 수 있다.\n\n---\n\n#### References\n\n-   [Aspect-oriented software development](https://en.wikipedia.org/wiki/Aspect-oriented_software_development#Concepts_and_terminology)\n-   [Aspect-oriented programming](https://en.wikipedia.org/wiki/Aspect-oriented_programming)\n-   [Aspect (computer programming)](https://en.wikipedia.org/wiki/Aspect_(computer_programming))\n-   [Cross-cutting concern](https://en.wikipedia.org/wiki/Cross-cutting_concern)\n-   [Intertype declarations in AspectJ (member injection)](https://programmer.help/blogs/intertype-declarations-in-aspectj-member-injection.html)\n"
  },
  {
    "path": "CS/cohension&coupling.md",
    "content": "# 응집도(Cohension)와 결합도(Coupling)\n\n좋은 프로그램은 높은 응집도와 낮은 결합도를 가진다.\n\n## 응집도 \n\n응집도는 모듈 내부의 기능적인 응집 정도를 뜻한다. 이상적인 응집도는 모듈 내부의 모든 기능이 단일한 목적을 위해 수행되는 것이다. 응집도는 클 수록 좋다.\n\n* 기능적 응집도(Functional Cohesion)\n  * 모듈 내부의 모든 기능이 단일한 목적을 위해 수행되는 경우\n* 순차적 응집도(Sequential Cohesion)\n  * 모듈 내에서 한 활동으로 부터 나온 출력값을 다른 활동이 사용할 경우\n* 교환적 응집도(Communication Cohesion)\n  * 동일한 입력과 출력을 사용하여 다른 기능을 수행하는 활동들이 모여있을 경우\n* 절차적 응집도(Procedural Cohesion)\n  * 모듈이 다수의 관련 기능을 가질 때 모듈 안의 구성요소들이 그 기능을 순차적으로 수행할 경우\n* 시간적 응집도(Temporal Cohesion)\n  * 연관된 기능이라기 보단 특정 시간에 처리되어야 하는 활동들을 한 모듈에서 처리할 경우\n* 논리적 응집도(Logical Cohesion)\n  * 유사한 성격을 갖거나 특정 형태로 분류되는 처리 요소들이 한 모듈에서 처리되는 경우\n* 우연적 응집도(Coincidental Cohesion)\n  * 모듈 내부의 각 구성요소들이 연관이 없을 경우\n\n> 우연적 응집도 < 논리적 응집도 < 시간적 응집도 < 절차적 응집도 < 교환적 응집도 < 순차적 응집도 < 기능적 응집도\n\n위에서 아래로 내려올 수록 응집도가 낮아진다(나빠진다)고 할 수 있다. 기능적 응집도가 이상적인 응집정도이다.\n\n## 결합도\n\n결합도는 의존성 정도이다. 이상적인 결합도는 인터페이스의 파라미터를 통해서만 상호 작용이 일어나며, 파라미터는 값으로 이루어져야 한다. 결합도는 낮을 수록 좋다.\n\n* 자료 결합도(Data Coupling)\n  * 모듈간의 인터페이스 전달되는 파라미터를 통해서만 모듈간의 상호 작용이 일어나는 경우\n  * 깔끔한 Call by value\n* 스탬프 결합도(Stamp Coupling)\n  * 모듈간의 인터페이스로 배열이나 오브젝트, 스트럭쳐등이 전달되는 경우\n* 제어 결합도(Control Coupling)\n  * 단순히 처리를 해야할 대상인 값만 전달되는게 아니라 어떻게 처리를 해야 한다는 제어 요소(명령어, Flag등)이 전달되는 경우.\n* 외부 결합도(External Coupling)\n  * 어떤 모듈에서 반환한 값을 다른 모듈에서 참조해서 사용하는 경우\n* 공통 결합도(Common Coupling)\n  * 파라미터가 아닌 모듈 밖에 선언되어 있는 전역 변수를 참조하고 전역변수를 갱신하는 식으로 상호작용하는 경우\n* 내용 결합도(Content Coupling)\n  * 다른 모듈 내부에 있는 변수나 기능을 다른 모듈에서 사용 하는 경우\n\n> 자료 결합도 < 스탬프 결합도 < 제어 결합도 < 외부 결합도 < 공통 결합도 < 내용 결합도\n\n위에서 아래로 내려올 수록 결합도가 커진다(나빠진다)고 할 수있다. 자료 결합도가 가장 이상적인 결합정도이다.\n\n---\n\n#### References\n\n- [응집도(Cohension)](http://itwiki.kr/w/%EC%9D%91%EC%A7%91%EB%8F%84)\n- [결합도(Coupling)](http://itwiki.kr/w/%EA%B2%B0%ED%95%A9%EB%8F%84)\n\n"
  },
  {
    "path": "CS/compression.md",
    "content": "# 압축\n\n압축은 크게 데이터 손실압축과 데이터 비손실압축 두 가지로 나뉜다.\n\n데이터 손실 압축은 우리가 흔히 보는 사진, 영상의 해상도를 낮추는 압축이다. 사진의 픽셀을 일부 제거해 원본데이터가 손상되지만 사진을 보는데는 큰 지장이 없다.\n\n이런 경우 손실 압축을 해도 큰 상관이 없다. 그렇지만 문서의 경우는 다르다.\n'내가 A에게 500만원을 보냈다' 라는 정보를 압축했는데 원본 데이터에 손실이 일어나면 큰일이다.\n따라서 이 경우 데이터 비손실 압축으로 압축해야 한다.\n\n## 비손실 압축\n\n비손실 압축에는 크게 Run-Length, LZ(lempel-ziv), Huffman 등이 있다. 이 세가지가 가장 대표적이며 보통의 압축 알고리즘은 결국 이 세가지를 조합하거나 조금씩 변형한 것들이다.\n\n### Run-Length\n\n만일 데이터가 `WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWBWWWWWWWWWWWWWW` 이렇게 생겼다고 가정하자.\n\n이를 `12WB12W3B24WB14W`로 변경한다면 데이터를 손쉽게 압축할 수 있다. 압축을 해제하는 것 역시 직관적이며 쉬울 것이다.\n\n인코딩 이전의 데이터는 67글자였으나 인코딩 이후의 데이터는 16글자다.\n\n이 알고리즘의 단점은 일정한 패턴의 데이터를 압축할 수 없다는 점이다. `BWWBWWBWWBWWBWWBWW` 이 데이터는 Run-Length를 이용해 처리할 수 없다.\n\n### LZ(lempel-ziv)\n\nLZ 알고리즘은 기본적으로는 Run-Length의 방식과 동일하다. Run-Length는 글자 하나를 기준으로 한다면 LZ는 단어를 기준으로 한다. 이를 사전방식(Dictonary methods)이라고 한다.\n\n예를 들어 다음과 같은 문장이 있다고 하자.\n\n`TOBEORNOTTOBETONOT` 이걸 압축해보자.\n\n`TOBEORNOT TOBE TONOT` 저 가운데 TOBE는 사실 앞에서 한번 쓰였다. 그럼 굳이 다시 쓰지 않고 앞에서 쓰였다고 표시만 해주면 되지 않을까? 이 개념이 LZ알고리즘이다.\n\n그래서 아래와 같은 결과를 가진다.\n\n`TOBEORNOT TOBE TO NOT`\n\n`[TOBEORNOT][9,4][4,2][9,3]`\n\n이런식의 블록을 만든다. [9, 4]의 의미는 9번째 떨어진 곳으로부터 4글자가 반복되므로 그걸 사용하라는 의미다.\n\n실제로 완전히 이렇게 생긴것은 아니다. 실제로는 `(0,0)T (0,0)O (0,0)B ... (9,4)T (4,2) N...` 대충 이런식의 형태를 띈다. 참고로 저건 그냥 예시다. 저 TOBEORNOT... 의 인코딩 결과와는 다르다.\n\n그럼 실제 긴 텍스트를 블록 형태의 데이터로 변환할 수 있다.\n\n이러한 LZ 알고리즘은 LZ77, LZ78, LZMA, LZSS 등 엄청 다양한 알고리즘이 있다.\n\n그 차이는 블록(토큰)을 얼마나 길게 나누느냐에 따라 조금씩 다르다. TOBE를 TO BE의 두개의 블록으로 나눌 수 있듯 말이다.\n\nLZSS = winRAR, LZMA = 7zip 등 압축 형식에따라 조금씩 다른 알고리즘을 사용한다.\n\n### Huffman Coding\n\n허프만 코딩은 지난 글에서 설명한 엔트로피와 관련이 깊다. 물론 다른 알고리즘도 엔트로피와 연관이 있지만 이건 더 직관적으로 이해되게 연결된다. 글의 흐름을 따라가보자.\n\n#### ASCII CODE\n\n아스키 코드는 256개의 문자를 7비트 혹은 8비트로 나타내는 규칙이다. 예를들어 abcd라는 글자는 1100001 1100010 1100011 1100100로 나타낼 수 있다. 이런식으로 모든 글자를 치환하는것이 가능하다.\n\n이는 고정 길이 코드(Fixed Length Code)다. 그래서 단점이다.\n\ne와 x가 한 문서에 등장할 확률은 다르다. 정보이론에 따르면 확률이 다른 글자는 e와 x는 같은 한 글자지만 정보량이 다르다.\n\n그런데 7, 8비트로 고정해버리면 다른 각각의 정보량을 같게 표현해버린다.\n\n즉 고정길이코드는 항상 최대 정보량을 사용하게 된다.\n\n#### 가변 길이 코드\n\n그래서 나온 개념이 가변 길이 코드다. 예를들어 문서에는 space, e, s, t, i, a ... 의 순서로 글자가 나온다고 하자.\n\n`space : 0, e : 1, s : 00, t: 01, i: 10, a: 11 ...` 이런식으로 가변길이의 비트를 부여한다. 그럼 문서의 총 비트수는 엄청나게 줄어들 수 있을 것이다.\n\n여기에는 매우 치명적인 단점이 있다. 고정비트의 경우 8비트를 한 문자로 보고 끊어 읽으면 된다. 그런데 가변비트는 그럴 방법이 없다. `0011010010101...`의 코드가 있다고 하자. 그럼 앞에서부터 읽을 때 읽어야할 글자가 0(space)인지 00(s)인지 001인지 모른다.\n\n#### 접두어 코드(prefix code)\n\n가변 길이 코드의 문제는 [0, 1, 01, 010]의 식으로 코드를 부여하면 중복이 발생한다는 점이다. 그럼 중복이 발생하지 않게 부여하면 어떨까??\n\n예를들어 a,b,c,d를 [00, 010, 100, 101]으로 부여한다면 헷갈리지 않을 것이다. 이게 바로 허프만 코딩이다.\n\n#### 허프만 트리\n\n허프만은 빈도가 높은 글자를 작은 코드로 만들면서 동시에 서로 중복이 발생하지 않는 코드를 만들기 위해 이진트리 개념을 사용했다.\n\n![huffman](https://user-images.githubusercontent.com/24724691/58369631-0927a500-7f38-11e9-9aa6-684c2486cef0.png)\n[출처](https://spherez.blog.me/60175047026)\n\n이진 트리를 기준으로 왼쪽은 0, 오른쪽은 1을 부여하면 된다.\n\n그림처럼 {D: 00, E: 10, F: 11, C: 011, A: 0100, B: 0101}로 비트를 부여한다면 서로 중복되지 않고 비트를 빈도를 기준으로 부여할 수 있다.\n\n이 경우 어떤 글자는 8비트를 훨씬 넘어선다. 중복을 제거했으니 경우의 수가 늘어난다.\n\n그런데 그래도 괜찮다. 문서에 얼마 안나오기 때문이다.\n\n## Gzip\n\nHTTP 통신 시 자주 사용되는 Gzip은 Deflate 알고리즘을 사용하는 알고리즘이다.\n\nDeflate는 데이터를 우선 LZ77 알고리즘을 사용하여 압축한 결과를 Huffman Coding으로 한번 더 압축하는 방식을 사용한다.\n\n---\n\n참고자료\n\n- 리버싱 핵심원리, 이승원, 인사이트\n- [Text Compression for Web Developers](https://www.html5rocks.com/ko/tutorials/speed/txt-compression/)\n- [Raul Fraile: How GZIP compression works](https://2014.jsconf.eu/speakers/raul-fraile-how-gzip-compression-works.html)\n- [The LZ77 Compression Family (Ep 2, Compressor Head)](https://www.youtube.com/watch?v=Jqc418tQDkg)\n- [How Computers Compress Text: Huffman Coding and Huffman Trees](https://www.youtube.com/watch?v=JsTptu56GM8)\n- [허프만 코딩을 이용한 데이터 압축](https://softwareji.tistory.com/5)\n- [DEFLATE](https://ko.wikipedia.org/wiki/DEFLATE)\n"
  },
  {
    "path": "CS/dependency-inversion-principle.md",
    "content": "# 의존 역전 원칙(Dependency Inversion Principle)\n\n이름 그대로 의존 관계를 역전시키라는 원칙이다. 의존 역전 원칙은 다음과 같이 정의된다.\n\n1.  고수준 모듈(high level module)은 저수준 모듈(low level module)에 의존하면 안된다. 또한, 두 모듈은 추상화된 것(abstarctions)에 의존해야 한다.\n2.  추상화된 것은 상세한 것(details)을 의존하면 안된다. 상세한 것은 추상화된 것을 의존해야 한다.\n\n의존 역전 원칙의 정의 또한 다른 원칙의 정의처럼 많이 추상화되어 있는데, 각 단어들이 낯설게 느껴질 수 있다. 사용되는 용어들 부터 살펴보자면 아래와 같다.\n\n**의존(dependency)**\n\n여기서 의존이란 다른 객체를 포함 또는 사용하고 있다는 것이다.\n\n```java\nclass A {\n    private B b\n}\n\nclass B {\n    \n}\n```\n\n위의 경우 클래스 `A` 는 클래스 `B` 에 의존한다. uml로 표현하면 다음과 같다.\n\n![dip01-dependency.png](https://github.com/Dae-Hwa/diagrams/blob/master/dip/dip01-dependency.png?raw=true)\n\n**모듈의 수준**\n\n-   고수준 모듈이란 실제로 사용하는 것과 근접해있는 것이다. 모듈의 본질적인 기능과 책임이 어떤 것인지 나타내는 것이다.\n\n-   저수준 모듈이란 모듈 내부를 구성하는 각각의 동작들을 의미한다. 고수준 모듈에서 기능을 수행하기 위해 도와주는 역할을 한다.\n\n|   고 수준 모듈   |                         저 수준 모듈                         |\n| :--------------: | :----------------------------------------------------------: |\n| 파일을 불러온다. |  불러오기 원하는 파일을 찾는다.<br />찾은 파일을 반환한다.   |\n| 파일을 저장한다. | 입력값을 이용하여 파일을 생성한다.<br />생성한 파일을 저장한다. |\n| 파일을 수정한다. |      기존 파일을 삭제한다.<br />변경된 파일을 저장한다.      |\n| 파일을 삭제한다. |     삭제 대상 파일을 찾는다.<br />찾은 파일을 삭제한다.      |\n\n## 저수준 모듈에 의존하는 고수준 모듈\n\n![dip01-typical-file.png](https://github.com/Dae-Hwa/diagrams/blob/master/dip/dip01-typical-file.png?raw=true)\n\n위 다이어그램에서 고수준 모듈인 `FilePolicy` 클래스는 저수준 모듈에 의존한다.\n\n만약 압축기능이 추가로 필요하다면? 다음과 같이 변경을 해야할 것이다.\n\n![dip01-typical.png](https://github.com/Dae-Hwa/diagrams/blob/master/dip/dip01-typical.png?raw=true)\n\n이는 [개방 폐쇄 원칙](https://github.com/im-d-team/Dev-Docs/blob/master/CS/open-closed-principle.md)에서 살펴봤던 예시와 비슷한 상황이다. 압축을 하는 것은 모든 파일에서 가능하지만, 압축을 푸는 것은 압축된 파일에서만 동작해야한다. 만약 압축을 풀기위한 클래스를 만든다면 개방 폐쇄 원칙에 위배될 것이기 때문에 인터페이스를 도출하게 될 것이다. 인터페이스를 도출하면 자연스럽게 의존의 역전이 일어난다.\n\n## 의존 역전\n\n![dip01-inversion2.png](https://github.com/Dae-Hwa/diagrams/blob/master/dip/dip01-inversion2.png?raw=true)\n\n`FileHandler`를 인터페이스로 도출한다면 위와 같이 될 것이다. 이것이 의존 역전이 일어난 것인데, 상위 모듈에서 하위 모듈을 사용하기 때문에 의존방향이 상위 모듈에서 하위 모듈을 향해야 한다. 하지만 가운데 추상화 된 인터페이스를 추가시켜 하위 모듈의 방향이 반대로 되었다. 즉 상위 모듈과 하위 모듈의 의존성이 제어의 흐름(flow of control)과 반대 방향이 되었다. \n\n![dip01-inversion3.png](https://github.com/Dae-Hwa/diagrams/blob/master/dip/dip01-inversion3.png?raw=true)\n\n엄밀히 말하면 런타임에 결정되는 의존성은 그대로지만, 컴파일타임에 결정되는 의존성이 변경된다. 이로인해 위에서 얘기했던 저수준 모듈을 의존하는 경우의 단점이 해결 될 수 있다. \n\n>   위의 예시는 인터페이스 분리 원칙에 위배되는데 이에 대한 해결과정은 [CS/interface-segregation-principle](https://github.com/im-d-team/Dev-Docs/blob/master/CS/interface-segregation-principle.md)을 참고하자.\n\n의존 역전을 위해 적용된 인터페이스는 상위 레이어와 같은 레벨이 된다.\n\n![dip01-layer.png](https://github.com/Dae-Hwa/diagrams/blob/master/dip/dip01-layer.png?raw=true)\n\n즉 경계가 분리 될 때 의존성이 역전되어야 상위 모듈에서 하위 모듈을 사용하는 것이 유연해진다. \n\n## 의존 주입(DI)과 의존 역전 원칙(DIP)\n\n의존성에 대해 다루는 비슷한 용어가 있다. 의존 주입(dependency injection)인데, 이를 잘못 이해하면 의존 역전 원칙과 같은 사항으로 오해할 수 있다.\n\n의존 주입은 말 그대로 의존성을 외부에서 주입하는 것이다. 클래스 `A`가 클래스 `B`를 의존하고 있을 때 다음과 같은 코드를 작성할 수 있을 것이다.\n\n```java\nclass A {\n    public void someMethod() {\n        B b = new B();\n    }\n}\n```\n\n위의 예시는 클래스 `B`를 직접 생성하여 사용하는 것이다. 만약 의존성을 주입하려면 클래스 `B`의 생성을 외부에서 하도록 유도하면 된다.\n\n```java\nclass A {\n    public void someMethod(B b) {\n        b.doSomething();\n    }\n}\n```\n\n만약 멤버변수를 이용하여 의존성을 주입한다면 우리가 흔히 접하던 코드가 된다.\n\n```java\nclass A implements Injector<B>{\n    private B b;\n    \n    // constructor injection\n    public A(B b) {\n        this.b = b;\n    }\n    \n    // setter injection\n    public void setB(B b) {\n        this.b = b;\n    }\n    \n    // interface injection\n    @Override\n    public void inject(B b) {\n        this.b = b;\n    }\n}\n```\n\n## 마치며\n\n의존 역전 원칙은 어떻게 보면 앞에서 다뤄봤던 다른 원칙들을 포괄하는 개념일 수 있다. 레이어를 넘나드는 아키텍쳐를 구성하는 근간 원리이기 때문이다. 이를 따르면 변경에 강한 코드 구조가 되는데 추상화된 인터페이스를 바탕으로 상위 모듈과 하위 모듈의 관계를 느슨하게 만들어주기 때문이다.\n\n주의해야 할 점은 위에서 살펴봤듯, 컴파일 타임 의존성을 변경시켜 구조를 유연하게 만드는 것이지 레이어의 순서를 뒤바꾸는 것이 아니다. 상위 모듈은 하위 모듈에 의존하되 런타임 단계에서 의존 관계가 결정될 수 있도록 의존 관계 사이에 추상화된 인터페이스를 둬서 유연성을 최대한 보장하도록 하는 것이 핵심이다.\n\n----\n\n#### References\n\n-   [The Dependency Inversion Principle](https://www.labri.fr/perso/clement/enseignements/ao/DIP.pdf)\n\n-   [클린 코더스 강의 15.1. DIP(Dependency Inversion Principle)](https://www.youtube.com/watch?v=mI1PsrgogCw&ab_channel=%EB%B0%B1%EB%AA%85%EC%84%9D)\n"
  },
  {
    "path": "CS/grasp.md",
    "content": "# GRASP - General Responsibility Assignment Software Patterns\n\n직역하자면 일반적으로 책임을 할당할 때 사용할 수 있는 소프트웨어 패턴이다. 말 그대로 책임 할당에 관한 패턴을 이야기한다. 특이한 점은 보통 생각하는 패턴들과는 달리 실체가 없고 추상적인 개념들이다. 따라서 [SOLID 원칙](http://www.nextree.co.kr/p6960/)과 유사하게 어떤 식으로 책임을 부여해야 할지에 대한 원칙과 철학을 담고 있다.\n\n## 책임이란?\n\n객체지향에서 책임은 매우 중요한 개념이다. RDD(Responsibility Driven Design)에서는 책임을 **특정 작업을 수행하거나, 정보를 알아야 할 의무(an obligation to perform a *task* or know *information*)** 라고 정의한다. 즉 행동(behavior; doing)과 아는것(data; knowing)을 명확히 구분한다. 따라서 객체의 책임은 다음과 같이 정의할 수 있다.\n\n### 행동(Behavior; Doing)\n\n- 스스로 하는 것(doing something itself)\n- 다른 객체와 협력 하는 것(initiating and coordinating actions with other objects)\n\n```java\npublic class Customer {\n    // doing something itself\n    private Customer() {\n        //...\n    }\n \n    // doing something itself\n    public Customer(String email, String name, UniquenessChecker customerUniquenessChecker) {\n        this.email = email;\n        this.name = name;\n\n        // initiating and coordinating actions with other objects\n        if (!customerUniquenessChecker.isUnique(id)) {\n            throw new BusinessRuleValidationException(\"Customer with this email already exists.\");\n        }\n\n        this.addDomainEvent(new CustomerRegisteredEvent(this));\n    }\n    \n    // doing something itself\n    public void addOrder(Order order) {\n    \t//...\n    }\n\n}\n```\n\n### 아는 것(Data; Knowing)\n\n- 객체의 데이터를 감추거나 공개하는 것(private and public object data)\n- 연관된 객체의 참조를 연결하는 것(related objects references)\n- 해당 객체가 도출해낼 수 있는 것(things it can derive)\n\n```JAVA\npublic class Customer extends Entity/*knowing*/{    \n    @Getter @Setter private Guid id;   // knowing\n    @Getter @Setter private String email; // knowing\n    @Getter @Setter private String name; // knowing\n    @Getter private List<Order> orders; // knowing\n```\n\n## GRASP\n\nGRASP은 다음의 9가지 패턴으로 이루어져있다. 각 패턴은 특정 객체가 가져야할 책임이 무엇인지에 대한 것이다. \n\n1. Information Expert\n2. Creator\n3. Controller\n4. Low Coupling\n5. High Cohesion\n6. Indirection\n7. Polymorphism\n8. Pure Fabrication\n9. Protected Variations\n\n### Information Expert\n\n객체에 책임을 할당하는 기본 원칙에 관한 것이다. 동작에 필요한 정보가 있는 객체에 책임을 지정해야 한다. 다르게 말하면 동작에 필요한 정보가 있는 객체는 해당 동작을 할 수있는 책임을 지녀야 한다. 반대로 동작에 필요한 정보가 없는 객체는 관련된 동작을 해서는 안된다.\n\n```java\npublic class Customer {\n    private List<Order> orders;\n\t\n\tpublic int getOrdersTotal(Guid orderId) {\n\t    return orders.stream()\n                .map(Order::getValue)\n                .sum();\n\t}\n}\n```\n\n위의 예시에서 `Customer` 클래스는 모든 고객의 주문(`List<Orrder>)`을 알고 있다. 따라서 `Customer` 클래스는 주문의 총액을 계산할 수 있는 책임을 지녀야 한다.\n\n### Creator\n\n객체를 생성하는 책임에 관한 것이다. 객체 A와 B가 있다고 가정 했을 때, 객체 B가 다음의 조건 중 하나라도 만족한다면 객체 A를 생성하는 책임을 가져야 한다. 조건을 만족하는 개수는 많을수록 좋다.\n\n- B가 A를 포함하거나 복합적으로 집계\n- B가 A를 기록\n- B가 A를 밀접하게 사용\n- B가 A의 초기화 데이터 보유\n\n```java\npublic class Customer {\n    private List<Order> orders; \n\n    public void addOrder(List<OrderProduct> orderProducts) {\t\n\tOrder order = new Order(orderProducts); // Creator\n\n        if (2 <= orders.stream().filter(Order::isOrderedToday).count()) {\n            throw new BusinessRuleValidationException(\"You cannot order more than 2 orders on the same day\");\n        }\n\n        orders.add(order);\n\n        addDomainEvent(new OrderAddedEvent(order));\n    }\n}\n```\n\n`Customer` 클래스는 주문을 집계하고 기록하고 사용한다. 무엇보다도 `Customer` 클래스가 주문(`Order`)을 포함한다. \n\n### Controller\n\nUI 레이어를 넘나들며 시스템 작동의 제어권을 수신하고 조정하는 객체에 관한 것이다. 시스템, 루트객체, 시스템 실행에 필요한 장치, 핵심 서브시스템을 나타내거나 시스템 동작이 발생하는 시나리오(유스케이스)를 표현하는 객체일 경우 컨트롤러의 책임을 가져야 한다.\n\n```java\npublic class CustomerOrdersController {\n    private OrderService customerOrderService;\n\n    public CustomerOrdersController(OrderService customerOrderService) {\n        this.customerOrderService = customerOrderService;\n    }\n\n    @PostMapping(\"/{customerId}/orders\")\n    public String addCustomerOrder(Guid customerId, HttpServletRequest request)\t{\n        //...\n    }\n}\n```\n\n위는 전형적인 Spring MVC의 컨트롤러인데, 좀 더 엄밀히 말하면 [DispatcherServlet](https://docs.spring.io/spring/docs/3.0.0.M4/spring-framework-reference/html/ch15s02.html)이 Front Controller 역할을 해주는 일종의 GRASP 컨트롤러라고 말할 수 있다. \n\n### Low Coupling\n\n결합도(coupling)가 낮게 유지되도록 책임을 할당 해야 한다. 낮은 결합도는 변화의 영향을 줄이고 낮은 의존성과 재사용성을 증가시키는 방법이다. 위의 Controller 예시는 의존성 주입을 이용해 결합도가 낮다. `OrderService` 인터페이스의 명세가 바뀌지 않으면 이를 구현하는 서비스 객체가 바뀌어도 큰 영향을 받지 않을 것이다.\n\n### High Cohension\n\n좋은 객체는 높은 응집력(cohension)을 가져야 한다. 응집력은 객체 내부의 책임이 얼마나 연관성이 있는지에 관한 것이다. 만약 `Customer` 클래스가 주문 뿐만 아니라 상품의 가격을 관리하는 책임을 가지게 된다면 해당 클래스의 응집력은 크게 떨어진다.\n\n### Indirection\n\n컴포넌트나 서비스가 직접 연결되지 않도록 중재 역할을 해주는 책임을 갖는 객체를 이용하는 것이다. MVC패턴에서 모델과 뷰 사이에 컨트롤러를 구성하는 것을 예시로 들 수 있다. 혹은 [Mediator Pattern](https://springframework.guru/gang-of-four-design-patterns/mediator-pattern/)을 이용할 수 있다. 객체가 직접 연결되어 있지 않다는 것은 시스템을 유연하게 만드는 것을 도와줄 수 있지만, 가독성과 추론을 어렵게 만들 수 있는 trade off가 있기 때문에 직접 구현하게 된다면 이를 잘 고려해야 한다.\n\n### Polymorphism\n\n유형에 따라 서로 다른 케이스를 처리하고 싶을 경우 다형성을 이용할 수 있다. \n\n```java\nprivate Guid id;\n\npublic Customer(string email, string name, UniquenessChecker customerUniquenessChecker) {\n    this.Email = email;\n    this.Name = name;\n \n    if (!customerUniquenessChecker.isUnique(id)) {\n        throw new BusinessRuleValidationException(\"Customer with this email already exists.\");\n    }\n \n    this.AddDomainEvent(new CustomerRegisteredEvent(this));\n}\n```\n\n`UniquenessChecker`가 `Customer`에 사용될 경우 `CustomerUniquenessChecker` 다른 곳에 사용될 경우 `OtherUniquenessChecker`를 사용하는 식으로 책임은 같지만 구현에 따라 동작이 달라질 경우 유용하게 쓰일 수 있다.\n\n### Pure Fabrication\n\n다른 원칙들을 적용하여 높은 응집력과 낮은 결합력을 유지하기 힘들 경우(정확한 책임을 할당하기 힘든 경우) 도메인에 독립적인 클래스와 인터페이스를 만드는 것이 좋을 수 있다.\n위에서 살펴봤던 예시들을 사용하다 환전 기능을 추가하게 되었다. 이는 `Customer`혹은 `Order`의 책임이라고 명확하게 정의하기 애매한데, 이런 경우 적용할 수 있다. 아래는 이에 따라 작성된  독립적인 인터페이스와 구현 클래스이다.\n\n```java\npublic interface ForeignExchange {\n    List<ConversionRate> getConversionRates();\n}\n\npublic class ForeignExchangeImpl implements ForeignExchange {\n    private CacheStore cacheStore;\n\n    public ForeignExchange(CacheStore cacheStore) {\n        this.cacheStore = cacheStore;\n    }\n\n    @Override\n    public List<ConversionRate> getConversionRates() {\n        //...\n    }\n\n    private static List<ConversionRate> getConversionRatesFromExternalApi() {\n        // Communication with external API\n    }\n}\n```\n\n### Protected Variations\n\n변화가 많거나 변경의 가능성이 높은 불안정한 객체나 서브시스템은 안정적인 인터페이스로 감쌀 수 있다.\n\n```java\npublic class CustomerOrdersRepository {\n\n    private JdbcTemplate jdbcTemplate;\n\n    public void setDataSource(DataSource dataSource) {\n        this.jdbcTemplate = new JdbcTemplate(dataSource);\n    }\n\n    // JDBC-backed implementations of the methods...\n}\n\n@Configuration\npublic class SpringJdbcConfig {\n    @Bean\n    public DataSource mysqlDataSource() {\n        DriverManagerDataSource dataSource = new DriverManagerDataSource();\n        dataSource.setDriverClassName(\"com.mysql.jdbc.Driver\");\n        dataSource.setUrl(\"jdbc:mysql://localhost:3306/springjdbc\");\n        dataSource.setUsername(\"guest_user\");\n        dataSource.setPassword(\"guest_password\");\n \n        return dataSource;\n    }\n}\n```\n\n위의 예시는 `DataSource`라는 안정적인 인터페이스 안에서 데이터 베이스 setup에 대한 책임을 담당한다. 데이터 베이스가 교체되더라도 `DataSource` 객체의 명세를 그대로 사용하기 때문에 이를 구현한 클래스를 교체하거나 내부 구현의 내용만 바꿔주면 다른 시스템에 피해 없이 작업을 수행할 수 있다.\n\n## 마치며\n\n객체를 정의할때 가장 중요하지만 그만큼 어려운 것이 책임을 정의하고 그에 따라 설계하는 것이다. SOLID원칙과 마찬가지로 이를 완벽하게 지키기는 힘들다. 하지만 마찬가지로 지키지 않을 수록 절차지향적 코드에 가까워진다. 절차지향적인 프로그램이 나쁜 것은 아니지만, 본인이 객체 지향 프로그래밍을 의도하며 만들었다면 마땅히 따라야할 원칙과도 같은 것이기 때문에 최대한 지키기 위해 노력하는 것이 바람직하다.\n\n---\n\n#### References\n\n- [GRASP – General Responsibility Assignment Software Patterns Explained](http://www.kamilgrzybek.com/design/grasp-explained/)\n"
  },
  {
    "path": "CS/information_theory.md",
    "content": "# 정보이론\n\n## 소통\n\n소통에는 늘 잡음이 낀다.\n\n이웃이 주식으로 돈을 좀 많이 벌었다라는 사실이 있다면 정보는 왜곡되고 과장이 되기 마련이다.\n그 이웃은 돈을 벌어 집도 사고 차도 새로 뽑는다. 친구의 뒷통수를 쳐 돈을 벌었으며 곧 해외로 도망간단다.\n\n꼭 소문만이 아니다. 실제로 정보의 통신에는 잡음이 낀다. 무전기로 통신을 할 때 잡음이 생기는걸 생각해보면 된다.\n\n신호는 전송 도중 에너지를 빼앗겨 그 신호가 약해진다. 봉화에 불을 붙이면 가까이선 잘 보이지만 멀리선 당연히 잘 안 보인다.\n\n0과 1로 이루어진 신호 역시 통신시에는 잡음이 생긴다.\n\n## 통신과 잡음\n\n우리가 컴퓨터로 통신할 때 잡음이 생긴다면 어떨까? 내가 1000만원을 송금했는데 잡음이 생겨 0이 하나 빠져 100만원이 송금된다면? 끔찍하다.\n\n그럼 어떻게 메시지를 온전하게 전달할 수 있을까? 정보를 온전히 전달하는 기술은 정보이론에 기초한다. 정보이론은 1948년 클로드 섀년이 그의 나이 32세에 탄생시킨다.\n\n### 잡음에 대한 다른 시각\n\n통신에는 잡음이 생긴다고 했다. 1948년에는 잡음은 물리적인 현상이며 이를 물리(하드웨어, 아날로그)적인 방식으로 어떻게 극복할 수 있을까 고민했다.\n\n메시지 전달속도를 높이려면 주파수를 높이거나, 잡음이 생긴다면 신호를 강하게 만들면 된다거나 하는 방법으로 말이다.\n\n하지만 섀년은 달랐다. 하드웨어가 아니라 소프트웨어(보내려는 메시지)적인 방법으로 해결하고자 했다.\n\n## 정보량\n\n소프트웨어인 메시지에 주목하고자 먼저 한 일은 정보량에 대해 정리하는 일이었다.\n\n정보의 양은 뭘까? 섀넌은 확률을 기준으로 정보량을 정리했다.\n\n예를들어 '하겠습니' 다음에는 '다'가 나올 확률이 '까'가 나올 확률보다 훨씬 높다. '하겠습니다'는 '하겠습니까'보다 자주 나오므로 예측하기 쉽다. 예측하기 쉬우면 정보의 양이 적다.\n\n왜 예측하기 쉬우면 정보의 양이 적을까? 쉽게 장마철을 생각해보자. 장마철에 비가오는건 당연하다. 확률이 높다. 장마철에 내일도 비가 올 것입니다 라는 정보는 그다지 중요하지 않다.\n\n반대로 가뭄에 비가 올 확률은 매우 적다. 한 달 동안 가뭄인 상태에서 내일은 드디어 비가 올 것 같습니다 라는 정보는 훨씬 더 중요하다. 즉 훨씬 더 중요하며 정보량이 많다.\n\n위의 논리라면 알파고의 78수가 나올 확률은 0.007%이며 이는 매우 중요한 정보라는 것이 증명된다.\n\n### 엔트로피\n\n이는 엔트로피의 개념과 같다. 나는 문과 출신이라 엔트로피에 대해 잘 모른다. 쉽게 무질서의 정도라고 한다.\n\n예를들어 문서에 a, b, c, d만 등장하며, 각각의 문자가 등장할 확률이 모두 25%로 같다고 하자. 그렇다면 이 문서의 정보량은 엔트로피의 공식에 의해 2라고 한다.\n\n확률이 모두 같다면 가장 정돈된 상태다. 가장 정돈된 상태가 네 글자로 만들 수 있는 최대 정보량이다. 확률이 달라진다면 어떤 글자가 나올지 예측하기가 쉬워지며 정보의 양이 줄어든다.\n'하겠습니' 뒤에는 '다'가 나올 확률이 높으니 정보가 줄어드는 것처럼 영어에는 e가 제일 많이 나와 정보의 양이 줄어든다.\n\n즉 확률이 서로 다르면 무질서한 상태가 된다. 무질서할수록 정보의 양은 줄어든다.\n\n### 정보량과 잡음\n\n아까도 말했듯 통신에는 잡음이 생긴다. 이를 물리적인 방법으로 해결하는 데에는 한계가 있다. 메시지의 강도를 높이면 잡음도 심해지기 때문이다.\n\n섀넌은 통신의 한계는 물리적인 것에 있다고 보지 않았다. 통신의 한계점은 정보량에 기준한다는 새로운 패러다임을 제시한다.\n\n    정보량은 초당 H이며 온전히 전달할 수 있는 채널 용량이 초당 C라고 가정하자.\n    H <= C 라면 정보에 비해 용량이 크므로 온전하게 전달 할 수 있다.\n    H > C 라면 잡음은 H-C미만으로 줄일 수 없다.\n\n섀넌은 위와 같은 정의를 내린다.\n\n이에 C를 키우기 위해 신호의 전력을 키우면 잡음도 증가한다를 수식적으로 증명한다.\n\n기존의 개념은 채널의 용량인 C를 키워 통신을 온전하게 만들자는 것이었다. 하지만 섀넌은 잡음을 더 줄일 수 없으니 H를 줄이자라는 길을 제시했다.\n\nH는 정보의 양이며 정보량을 줄이는 방법은 엔트로피를 조정하면 된다. 이 개념에서 시작된 것이 압축이다.\n\n---\n\n참고자료\n\n- [정보이론 1편](https://brunch.co.kr/@chris-song/68)\n- 컴퓨터과학이 여는 세계, 이광근, 인사이트\n- 성공과 실패를 결정하는 1%의 네트워크 원리, Tsutomu Tone, 이도희 역, BM성안당\n"
  },
  {
    "path": "CS/integer_representation.md",
    "content": "# 정수 표현(Integer Representation)\n\n전자기기는 신호가 켜졌는지, 꺼졌는지 구분을 하는 것이 효율적이기 때문에 컴퓨터 또한 2진법을 기반으로 발전하였다.\n\n![img](http://ktword.co.kr/img_data/5048_1.jpg)\n\n>   그림 출처 : [정보통신기술용어해석](http://ktword.co.kr/abbr_view.php?nav=2&id=122&m_temp1=5048)\n\n컴퓨터는 위와 같이 수를 표현한다. 이때 2진수 자리 한 칸을 비트(bit; binary digit)라 한다.\n\n수의 양 끝에는 MSB(most significant bit; 최상위 비트)와 LSB(least significant bit; 최하위 비트)가 있다. MSB는 주로 부호를 나타내는 데 사용된다.\n\n### 수 표현 단위\n\n#### 비트(Bit; Binary Digit)\n\n위에서 봤듯 가장 기본적인 수 표현 단위는 비트다. 비트 n 개당 2^n 개의 수를 표현할 수 있다. 비트는 0과 1로 이루어진 2진법 체계를 사용하기 때문이다.\n\n>   예를 들어 3비트로 0(000)부터 7(111)까지의 8개(2^3개)의 수를 나타낼 수 있다.\n\n>   하나의 비트를 논릿값(true, false)을 나타내는 데 사용할 수 있다. 논릿값은 두 가지의 경우만 표현하면 되기 때문이다.\n\n#### 바이트(Byte; Octet)\n\n바이트는 8개의 요소를 하나의 그룹으로 묶은 것이다. 때문에 옥텟이라고 부르기도 한다. 즉, 하나의 바이트는 8개의 비트로 이루어져 있다.\n\n>   1kb는 1024byte 이다.\n\n## 음수 표현\n\n비트는 0과 1로만 이루어지기 때문에 컴퓨터는 음수 기호를 사용할 수 없다. 2진수 만으로 음수를 표현하기 위해 첫 번째 자리로 부호를 표기하는 방식을 사용한다. 때문에 가장 왼쪽에 있는 비트인 MSB는 주로 부호 비트(sign bit) 로 사용된다.\n\n>   만약 음수를 사용하지 않고 양의 정수를 더 크게 나타내고 싶을 경우 MSB를 부호 비트로 사용하지 않을 수 있다. 이를 지원하는 언어에서는 부호 비트를 사용하지 않는 정수 표현이라는 의미로 unsigned int 와 같이 표시하기도 한다.\n\n### 부호 크기 체계(Signed Magnitude System; 부호 절대값 형식)\n\n부호 크기 체계는 부호 비트 이외에 나머지 비트를 절댓값 크기로 표현하는 것이다. 예를 들어, 4비트로 정수를 표현할 때 5는 0101이 된다. 부호 크기는 -5를 1101과 같이 표현한다. 1(-부호) + 101(10진수로 5)와 같이 표현하는 것이다. 이처럼 표현하면 -7 부터 7 까지 2^4 - 1개(15개)의 수를 나타낼 수 있다. 이를 수식으로 일반화하면 다음과 같다.\n\n-   표현 범위 : 2^(n-1) + 1 ~ 2^(n-1) - 1\n-   표현 가능 개수 : 2^n - 1\n\n### 보수(Complement)\n\n보수는 보충을 해주는 수를 의미한다. 예를 들어 1에 대한 10의 보수는 9(10 - 1), 4에 대한 15의 보수는 11(15 - 4)이 되는 것이다. 2진수에서는 1의 보수와 2의 보수를 사용할 수 있다. 컴퓨터는 이 중 2의 보수를 이용하여 음수를 나타낸다.\n\n#### 1의 보수(One's Complement)\n\n2진수에서 1의 보수는 각 자릿수를 1에서 빼주는 것과 같다. 이는 or(|) 연산을 하는 것과 같이 동작한다. 예를 들어 2진수 0101의 보수는 1010이 되는 것이다. 4비트로 정수를 표현 할 때는 0 부터 7까지는 0000부터 0111까지, -7 부터 0까지는 1000 부터 1111까지로 나타낼 수 있다. 표현 범위와 표현 가능 개수는 부호 크기 체계를 사용할 때와 같지만, 부호 비트가 음수를 나타낼 경우 절댓값으로 표현할 때와 달리 나머지 비트가 작을수록 더 작은 수를 나타낸다.\n\n-   표현 범위 : 2^(n-1) +1 ~ 2^(n-1) -1\n-   표현 가능 개수 : 2^n -1\n\n#### 2의 보수(Two's Complement)\n\n2의 보수는 각 자릿수를 2에서 빼주는 것과 같다. 이는 or(|) 연산을 한 뒤 1을 더해주는 것과 같다. 2진수에서 1에 대한 2의 보수는 2 - 1이 될 것인데, 이는 1 - 1을 한 뒤 1을 더해주는 것과 같기 때문이다. 따라서 2진수 0101의 보수는 1011이 된다. 2의 보수를 사용할 경우 -0이 없어진다. 0에 대한 1의 보수에 1을 더하면 다시 0이 되기 때문이다. 따라서 다른 방식보다 하나의 음수를 더 표현할 수 있다.\n\n>   0000의 보수는 1111이다. 여기에 1을 더해주면 10000이 되는데, 지금은 4비트로 정수를 표현하고 있기 때문에 이는 0000으로 표현된다.\n\n-   표현 범위 : 2^(n-1) ~ 2^(n-1) -1\n-   표현 가능 개수 : 2^n\n\n### 2의 보수를 사용하는 이유\n\n#### 보수를 사용하는 이유\n\n보수를 사용하면 덧셈만으로 뺄셈 연산을 할 수 있다. 컴퓨터에는 덧셈을 위한 회로만 있기 때문에 만약 부호 이외의 값을 절댓값으로 표현한다면 뺄셈을 위한 회로가 추가되어야 한다. 따라서 뺄셈을 위해서 보수를 구한 뒤 더하는 방식으로 뺄셈 연산을 한다. 2 - 3을 계산해야 한다고 생각해보자. 이는 2 + (-3) 과 같은 수식이다. 따라서 3을 음수로 바꿔주고 덧셈 연산을 하면 뺄셈을 하는 것과 연산이 같아진다.\n\n또한, 부호 이외의 값을 절댓값으로 표현하면 음수 비교 연산 시 모순이 발생한다. 보수를 이용하면 이러한 모순이 해결된다.\n\n#### 2의 보수를 사용하는 이유\n\n2의 보수를 사용하면 1의 보수와 달리 0이 하나로 표현된다. -0에 대한 처리를 따로 하지 않아도 된다. 또한, 뺄셈을 할 경우 캐리(carry; 올림 수) 처리를 해주지 않아도 된다. 이는 다음 예시를 보자.\n\n##### 1의 보수 뺄셈\n\n-   예시 : 1101 - 1010 \n\n    1.  1010의 1의 보수는 0101이므로 1101에 0101을 더한 값은 10010이 된다. \n\n    2.  이 때 범위가 초과된 최상위 비트 1을 없애고 1을 더해준다. 이에 따라 1101 - 0101 = 0011 이라는 결과가 나온다.\n\n        >   이러한 캐리를 end aroud carry 라고 한다. MSB에서 발생한 캐리를 뜻한다.\n\n##### 2의 보수 뺄셈\n\n-   예시 : 1101 - 1010\n\n    1.  1010의 2의 보수는 0110이다. 1101 + 0110은 10011이 된다.\n\n    2.  최상위에 있는 비트는 표현 범위를 넘어갔으니 제외하면 0011 이라는 결과를 얻을 수 있다.\n\n        >   2의 보수를 사용하면 end around carry를 무시하고 연산 할 수 있다.\n\n## 오버플로우(Overflow)\n\n계산과정에서 결괏값이 표현 가능한 값의 범위를 넘어갈 경우 오버플로우가 발생하게 된다. 4비트로 부호가 있는 정수를 표현할 때 -4와 -5를 더하면 -9가 되므로 표현 범위를 넘어가게 된다. 따라서 이런 경우가 발생하기 전에 더 큰 범위를 지정해줘야 한다. 오버플로우를 감지하는 방법은 부호 사용 여부에 따라 달라지는데 이는 [오버플로우(Overflow) 조건](https://janggom.tistory.com/328)을 참고하자.\n\n----\n\n#### References\n\n-   [정보통신기술용어해석 - 2의 보수, 1의 보수](http://ktword.co.kr/abbr_view.php?nav=2&id=122&m_temp1=4088)\n\n-   [정보통신기술용어해석 - 보수(complement)](http://ktword.co.kr/abbr_view.php?nav=2&id=122&m_temp1=4556)\n\n-   [dreamincalm의 블로그 - 1의 보수, 2의 보수](https://blog.naver.com/dreamincalm/130081559335)\n"
  },
  {
    "path": "CS/interface-segregation-principle.md",
    "content": "# 인터페이스 분리 원칙(Interface Segregation Principle)\n\n인터페이스 분리 원칙은 클라이언트는 자신이 사용하지 않는 메서드에 의존하면 안된다는 것이다. 만약 인터페이스가 거대하여 많은 기능을 담고 있다면 해당 인터페이스는 높은 응집도를 갖기 힘들다. 클래스의 인터페이스가 가진 함수들을 그룹화 하여 나눌 수 있다면 해당 인터페이스를 사용하는 클라이언트도 여러 개다. \n\n쉽게 말해, 인터페이스 내부의 함수들의 그룹을 구분할 수 있다면, 해당 인터페이스에 여러 가지 책임이 혼재되어 있는 상태라는 것이다. 이 경우 하나의 인터페이스를 여러 개의 클라이언트에서 사용하지만, 사용하는 기능은 클라이언트별로 한정적일 것이다.\n\n따라서 인터페이스 분리 원칙은 하나의 클래스에 여러 개의 책임을 가진 인터페이스를 사용해야 하는 경우에 관한 이야기이다. 이 때, 클라이언트는 구현된 객체 대신 응집력 있는 인터페이스를 가진 추상 기본 클래스에 의존해야 한다. 이러한 추상 기본 클래스를 '인터페이스', '프로토콜' 또는 '서명(signiture)' 이라고 한다.\n\n## 예시\n\n전역한 한국인은 예비군을 가게 된다.\n\n```java\nclass Korean {\n    public void participateReserveForcesTraining() {\n        // 예비군 훈련 참여\n    };\n}\n```\n\n하지만 모든 남자가 예비군 훈련에 가는 것은 아니다. 전역을 한 사람 대상이다. 전역을 했다는 상태값을 나타내도록 간단히 수정해보면 아래와 같을 것이다.\n\n```java\nabstract class Korean {\n    public abstarct boolean isDischarged();\n}\n\nclass DischargedKoraen extends Korean {\n    @Override\n    public boolean isDischarged() {\n        return true;\n    }\n    \n    public void participateReserveForcesTraining() {\n        // 예비군 훈련 참여\n    };\n}\n\nclass ReserveForcesTrainingClient {\n    public void doReserveForcesTraining(Korean korean) {\n        if(KoreanPerson.isDischarged()) {\n            ((DischargedKorean) korean).participateReserveForcesTraining();\n        }\n    }\n}\n```\n\n이 경우 상위 클래스와 하위 클래스가 다른 동작을 한다. [리스코프 치환 원칙](https://github.com/im-d-team/Dev-Docs/blob/master/CS/liskov_substitution_principle.md)을 위배한다. 이를 해결해보면 다음과 같을 것이다.\n\n```java\ninterface Korean {\n    boolean isDischarged();\n    void participateReserveForcesTraining(boolean discharged);\n}\n\nclass DischargedKoraen implements Korean {\n    @Override\n    public boolean isDischarged() {\n        return true;\n    };\n    \n    @Override\n    public void participateReserveForcesTraining(boolean discharged) {\n        if(discharged) {\n            // ...\n        }\n    };\n}\n\nclass ReserveForcesTrainingClient {\n    public void doReserveForcesTraining(Korean korean) {\n        korean.participateReserveForcesTraining(korean.isDischarged());\n    }\n}\n```\n\n이렇게 고칠 경우 `Korean` 의 다른 케이스에서도 반드시 예비군 훈련에 관한 구현이 포함되어야 한다.\n\n```java\nclass NonDischargedKoraen implements Korean {\n    @Override\n    public boolean isDischarged() {\n        return false;\n    };\n    \n    @Override\n    public void participateReserveForcesTraining(boolean discharged) {\n        throw new UnsupportedOperationException(\"전역하지 않은 사람은 예비군 훈련에 참여할 수 없습니다.\");\n    };\n}\n```\n\n이런 경우, 인터페이스가 오염되었다고 말한다. 또한, 위 예제는 기능이 적기 때문에 인터페이스가 비대해 보이지 않다. 하지만 만약 `Korean` 인터페이스에서 추상화된 모든 기능을 제공할 경우 실제 구현 클래스는 메소드 중 일부분만 사용하지만 거대한 인터페이스의 모든 기능을 재정의해야 할 것이다.\n\n이런 경우 인터페이스 분리를 해주어 해결할 수 있는 것이다.\n\n>   위 경우 [개방-폐쇄 원칙](https://github.com/im-d-team/Dev-Docs/blob/master/CS/open-closed-principle.md)도 위반하였을 가능성이 높다. 예비군에 관한 조건이 변경될 경우 `Korean` 을 구현한 모든 클래스가 변경되어야 할 것이기 때문이다.\n\n```java\nclass Korean {\n    // ...\n}\n\ninterface Discharged {\n    void participateReserveForcesTraining();\n}\n\nclass DischargedKoraen extends Korean implements Discharged {\n    @Override\n    public void participateReserveForcesTraining() {\n        // ...\n    };\n}\n\nclass ReserveForcesTrainingClient {\n    public void doReserveForcesTraining(Discharged dischargedPerson) {\n        dischargedPerson.participateReserveForcesTraining();\n    }\n}\n```\n\n`Korean`에 대한 일반화가 이루어졌으며, 전역자에 대한 책임도 분리되었다. 예비군 훈련을 담당하는 클라이언트는 전역에 관한 메세지를 전달할 수 있는 인스턴스만 사용할 수 있도록 강제되었다.  만약, 전역을 한 것과 동시에 여러 개의 책임이 추가된 사람에 대한 객체를 구현하더라도, 전역을 했다는 인터페이스만 구현하게 되면 예비군 훈련에 참가할 수 있게 된다.\n\n```java\nclass DischaregedKoreanStudent extends Korean implements Discharged, Student {\n    @Override\n    public void participateReserveForcesTraining() {\n        // 학생 예비군으로 참여\n    }    \n    // ...\n}\n```\n\n## 마치며\n\n하나의 거대한(일반화된) 인터페이스보다 여러 개의 구체적인 인터페이스가 낫다는 것이 인터페이스 분리 원칙의 핵심이다. [단일 책임 원칙](https://github.com/im-d-team/Dev-Docs/blob/master/CS/srp.md)과 서로 상충하는 개념처럼 보일 수 있다. 단일 책임 원칙에서는 클래스에서 하나의 책임만 담당해야 한다고 하지만, 인터페이스 분리 원칙은 하나의 클래스에서 여러 개의 책임을 갖는 경우가 있음을 인정하는 것이기 때문이다.\n\n하지만 이는 두가지 원칙의 관점이 다르기 때문인데, 단일 책임 원칙은 도메인(실행 대상)의 관점에서 책임을 나누지만, 인터페이스 분리 원칙은 클라이언트(실행하는 곳)의 관점에서 책임을 나누기 때문이다. 예를 들어 단일 책임 원칙은 해당 클래스 내부에서 여러 책임이 발생하는 것이 문제가 되는 것이다. 인터페이스 분리 원칙 또한 해당 클래스 내부에서 사용하지 않는 클래스를 재정의 해야 한다는 점이 문제지만, 이를 다시 생각해보면 클라이언트에 노출되면 안되는 메소드가 노출되는 것이 문제점이다. 이와 같이 생각해보면 큰 혼동 없이 이를 구분할 수 있을 것이다.\n\n---\n\n#### References\n\n-   [The Interface Segregation Principle - Robert C. Martin](https://drive.google.com/file/d/0BwhCYaYDn8EgOTViYjJhYzMtMzYxMC00MzFjLWJjMzYtOGJiMDc5N2JkYmJi/view)\n\n-   [객체지향 개발 5대 원리: SOLID - NEXTREE](http://www.nextree.co.kr/p6960/)\n\n"
  },
  {
    "path": "CS/liskov_substitution_principle.md",
    "content": "# 리스코프 치환 원칙(Liskov Substitution Principle)\n\n> 바바라 리스코프(Barbara Liskov)가 1988년 제시한 파생(상속) 에 관한 원칙.\n\n리스코프 치환 원칙은 하위 타입을 상위 타입으로 치환(substitution)하더라도 같은 동작을 해야 한다는 원칙이다. 상속 시 부모와 자식의 관계가 반드시 IS-A 관계를 맺도록 하면 자식 타입과 부모 타입은 치환 가능하다.\n\n바바라 리스코프는 타입이 `S`인 객체 `o1`과 타입이 `T`인 객체 `o2`가 있을 때, `T`가 정의된 프로그램 `P` 에서 `o2`를 `o1`으로 치환하여도 `P`에서 동작의 변화가 없을 경우 `S`는 `T`의 서브타입이라 할 수 있는 치환 원칙이 필요하다고 했다.\n\n쉽게 얘기하면  호출하는 프로그램 입장에서 부모 타입인지 자식 타입인지 신경써야하는 상황을 없애야 하고, 이를 위해서는 자식 클래스에서 부모 클래스에서 가능한 동작이 보장되어야 한다는 것이다. 그리고 이를 만족하면 자식과 부모클래스가 치환되어도 프로그램의 동작에 문제가 생기지 않는다.\n\n```java\npublic class Line {\n  private Point p1;\n  private Point p2;\n    \n  public Line(Point p1, Point p2) {\n    //...\n  } \n\n  public boolean isOn(Point p) {\n    //...\n  }\n} \n\npublic class LineSegment extends Line {\n  public LineSegment(Point p1, Point p2) {\n    super(p1, p2);   \n  }        \n\n  public double getLength() {\n    //...\n  }\n\n  //Line.isOn()의 참이 아래에서는 거짓이 될 수 있음.\n  @Override\n  public boolean isOn(Point p) {\n    //...\n  }\n}\n```\n\n위 코드에서 `LineSegment`는 `Line`의 `isOn()` 메소드를 재정의 하였다. \n\n```java\npublic class LineClient {\n  void doSomething(Line line) {\n    if(line.isOn(point)) {\n      //...\n    }\n  }\n}\n```\n\n위 코드는 매개변수 `line`의 `isOn()` 메소드가 `true` 를 반환할 것을 기대하고 작성 되었다. 하지만 이 경우 `line`의 인스턴스가 `Line` 이아닌  `LineSegment` 일 경우 제대로 동작하지 않을 수 있다. 버그가 잠재적인 코드인 것이다.\n\n만약 리스코프 치환 원칙을 준수하지 않는다면 부모 클래스에 따라 작성된 클라이언트의 코드가 변경되어야 하는 상황을 피하기 힘들다. \n\n> 이외에 직사각형과 정사각형에 대한 예시가 자주 나오는데, 이 또한 하위 타입의 변경에 의해 상위 타입을 바탕으로 정의한 동작이 제대로 작동하지 않는 경우에 관한 얘기이다. 참고 - [The Liskov Substitution Principle](https://drive.google.com/file/d/0BwhCYaYDn8EgNzAzZjA5ZmItNjU3NS00MzQ5LTkwYjMtMDJhNDU5ZTM0MTlh/view)\n\n## LSP 준수 방법\n\n- [계약에 의한 설계(design by contract; DBC)](https://en.wikipedia.org/wiki/Design_by_contract)  : overriding 시 부모 클래스와 같거나 약한 수준에서 동작하는 선행조건을 지정하고, 부모 클래스와 같거나 더 강한 수준에서 동작하는 후행 조건을 정의해야 한다.\n\n  > 선행조건(pre-condition) : 모듈을 호출하기 위해 참이어야 하는 조건.\n  >\n  > 후행조건(post-condition) : 모듈이 동작한 뒤 반드시 참이어야 하는 조건.\n\n  ```java\n  @Override\n  public boolean isOn(Point p) {\n    if(isSomthingStartWithBaseClassTrue()) { // 선행조건\n      // ...\n    }\n    \n    if(isEndWithSomthingWrong()) { // 후행조건\n      throw new SomeException();\n    }\n  }\n  ```\n\n- 상속(추출) 대신 공통 인자를 추출한다.\n\n  ```java\n  public abstract class LinearObject {\n    private Point p1;\n    private Point p2;\n  \n    public LinearObject(Point p1, Point p2) {\n      //...    \n    }\n  \n    public abstract boolean isOn(Point p);\n  }\n  \n  public class Line extends LinearObject{    \n    public Line(Point p1, Point p2) {\n      super(p1, p2);\n    } \n  \n    @Override\n    public boolean isOn(Point p) {\n      //...\n    }\n  } \n  \n  public class LineSegment extends LinearObject {\n    public LineSegment(Point p1, Point p2) {\n      super(p1, p2);   \n    }        \n  \n    public double getLength() {\n      //...\n    }\n  \n    @Override\n    public boolean isOn(Point p) {\n      //...\n    }\n  }\n  \n  ```\n\n  만약 아까와 같이 `Line` 의 `isOn()` 을 이용한 동작이 보장되야 되는경우가 문제 없어진다. 그리고 만약 인스턴스와 무관하거나 인스턴스에 따라 동작이 달라져야 하는 경우라면 추상 클래스(혹은 인터페이스)를 타입으로 사용하면 된다.\n\n  ```java\n  public class LineClient {\n    void doSomething(LinearObject linearObject) {\n      //...\n        \n      // 인스턴스에 따라 동작이 달라져야 하는 경우\n      if(linearObject.isOn(point)) {\n        //...\n      }\n    }\n  }\n  ```\n\n## 결론\n\n상속을 정의할 때 IS-A 관계만 생각할 경우 가능 범위가 너무 넓어질 수 있다. 이럴 경우 다음 그림을 떠올려보자.\n![liskov_duck](https://user-images.githubusercontent.com/24666330/88468977-55002080-cf26-11ea-9269-6c42815ee481.jpg)\n> 유사해 보여도 동작이 달라져야 한다면 이는 잘못된 추상화일 가능성이 높다.\n\n이외에 더 자세한 내용을 원한다면 [리스코프 치환 원칙](https://ko.wikipedia.org/wiki/리스코프_치환_원칙)을 참고해도 좋다. 더 구체적인 조건이 명시되어 있다. 또는 로버트 마틴의 글 [The Liskov Substitution Principle](https://drive.google.com/file/d/0BwhCYaYDn8EgNzAzZjA5ZmItNjU3NS00MzQ5LTkwYjMtMDJhNDU5ZTM0MTlh/view)를 참고해도 좋다. 구체적 예시가 포함되어 있다.\n\n---\n\n#### References\n\n- [LSP : The Liskov Substitution Principle](https://sites.google.com/site/anyflow/software-design/aejail-gaebal-wonchig-agile-development-principle/lsp-the-liskov-substitution-principle)\n\n- [The Liskov Substitution Principle](https://drive.google.com/file/d/0BwhCYaYDn8EgNzAzZjA5ZmItNjU3NS00MzQ5LTkwYjMtMDJhNDU5ZTM0MTlh/view)\n"
  },
  {
    "path": "CS/methods_in_IPC.md",
    "content": "# IPC(Inter Process Communication) 기법\n\n프로세스는 서로 접근이 불가능하다. 프로세스는 커널만 접근할 수 있기 때문이다. 하지만 병렬처리가 필요하거나 서로 다른 프로세스 간의 상호작용이 필요할 수 있다. 예시를 떠올리기 힘들다면 서버-클라이언트 모델을 생각해보면 이해하기 쉽다. 서버와 클라이언트는 서로 다른 프로세스이지만 정보를 주고받아야 한다. 이걸 해결하는 방법이 IPC(Inter Process Communication; 프로세스 간 커뮤니케이션)이다.\n\n### 들어가기 전에\n\n가장 쉽게 IPC를 구현하는 방법으로 파일을 사용하는 방법이 있다. 하나의 파일에 필요한 자원이나 메세지를 입력하여 공유하는 것이다. 하지만 업데이트 상황을 감지하기 어렵고 저장 매체를 지속적으로 사용해야 하므로 하드웨어 인터럽트가 발생할 것이고 성능이 떨어질 것이다. 때문에 커널 공간을 이용한 기법들이 대부분이다.![프로세스2](https://github.com/Dae-Hwa/diagrams/blob/master/os/process/%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A42.png?raw=true)\n\n모든 프로세스에는 커널 영역이 할당되어 있다. 똑같은 커널 영역을 사용하기 때문에 프로세스에 있는 커널 영역은 물리 메모리에 올라가 있는 하나의 커널 영역을 참조한다. 만약 프로세스 A와 B에서 커널 영역에 접근 하게 된다면 같은 영역에 접근하게 되는 것이다. 즉, 커널 영역을 사용할 수 있도록 [시스템 콜](https://ko.wikipedia.org/wiki/%EC%8B%9C%EC%8A%A4%ED%85%9C_%ED%98%B8%EC%B6%9C)을 제공한다면 IPC를 구현할 수 있다.\n\n## IPC 기법\n\nIPC에 대한 대표적인 접근방식은 아래와 같다.\n\n> 항목은 [Inter-process communication - Wikipedia](https://en.wikipedia.org/wiki/Inter-process_communication#Approaches) 를 바탕으로 linux에서 사용할 수 있는 것들을 기준으로 선정했다.\n\n- 파일(file)\n- 공유 메모리(shared memory)\n- 메세지 패싱(message passing)\n    - 파이프(pipe)\n    - 메세지 큐(message queue)\n    - 시그널(signal)\n    - 소켓(socket)\n    - 세마포어(semaphore)\n\n파일을 이용한 IPC 외에는 크게 두 가지 컨셉이 있다. 프로세스끼리 공유할 수 있는 메모리를 만들어 함께 접근하거나, 메세지를 주고받는 것(메세지 패싱)이다. \n\n> 참고 - https://www.geeksforgeeks.org/inter-process-communication-ipc/\n\n### 공유 메모리(Shared Memory)\n\n물리 메모리 공간에 변수처럼 사용할 수 있도록 공간을 만드는 것이다. key와 접근권한을 부여하여 등록하고 사용할 수 있다.\n\n![공유메모리1.png](https://github.com/Dae-Hwa/diagrams/blob/master/os/ipc/%EA%B3%B5%EC%9C%A0%EB%A9%94%EB%AA%A8%EB%A6%AC1.png?raw=true)\n\n#### 장점\n\n- 메모리에 있는 것을 그대로 사용할 수 있기 때문에 속도가 빠르다. \n- 구현도 간단하다. \n- 여러 프로세스가 동시에 접근할 수 있다.\n\n#### 단점\n\n- 동기화(synchronize) 이슈가 생길 수 있다.\n- 커널에서 설정된 용량에 종속적이다.\n- 데이터를 읽어야 되는 시점을 알 수 없다.    \n    > 사용자(consumer)가 어떤 데이터를 사용할지 직접 명시해야 하기 때문이다. 다른 방식은 메세지를 전달받기 때문에 해당 메세지에 해당하는 데이터를 읽으면 된다.\n\n### 파이프(Pipe)\n\n한 프로세스가 넣으면 다른 프로세스가 읽는 큐 형태의 구조이다. 하지만 방향이 고정되어있어 한 방향으로만 통신할 수 있다. 물탱크에서 관(파이프)을 통해 수도꼭지로 물이 나오는 것을 생각해보면 이해하기 쉽다. 즉, 파이프의 입력부분과 출력 부분이 정해지면 입력 부분이 구현된 프로세스에서는 입력만, 출력 부분이 구현된 프로세스에서는 출력만 가능하다. 또한, 읽기와 쓰기가 block 모드로 이루어지기 때문에 양방향으로 구현하더라도 반이중(half-duplex) 통신으로 동작한다. 반이중 통신의 대표적인 예로 무전기가 있는데 이와 유사하게 동작하는 것이다.\n\n#### 장점\n\n- 매우 간단하게 사용할 수 있다.\n\n#### 단점\n\n- 부모-자식 간에만 사용할 수 있다.\n- 단방향(unidirection) 통신이다.\n- 양방향(bidirection)으로 구현하여도 반이중 통신이다.\n\n#### Named Pipe(후술 FIFO)\n\n앞에서 살펴본 파이프는 엄밀히 따지면 익명 파이프(anonymous pipe)라고 불린다. 이 방식의 단점 중 부모-자식 프로세스에서만 사용할 수 있다는 것인데, FIFO는 그러한 단점을 해결하기 위한 것이다. 즉 관련 없는 프로세스들에서 파이프를 이용한 IPC를 구현하기 위해 사용할 수 있다.\n\n> 서버-클라이언트 모델에 사용되는 방식이다.\n\n### 메세지 큐(Message Queue)\n\nkey를 이용한 큐 방식이다. 선입선출 외에 지정한 key 중 가장 먼저 입력된 자료를 꺼낼 수 있다. 양방향으로 통신할 수 있다.![메세지큐1.png](https://github.com/Dae-Hwa/diagrams/blob/master/os/ipc/%EB%A9%94%EC%84%B8%EC%A7%80%ED%81%901.png?raw=true)\n\n#### 장점\n\n- 프로세스 간의 비동기(asynchronization) 통신이 가능하다.\n- 키를 이용하면 권한이 있는 모든 프로세스에서 접근할 수 있다.    \n    > 하지만 큐이기 때문에 동기화 이슈를 염려할 필요 없다.\n\n#### 단점\n\n- 대기열이 지나치게 길어지면 병목현상이 발생할 수 있다.\n\n### 시그널(Signal)\n\n커널 또는 프로세스에서 다른 프로세스에 어떤 이벤트가 발생했는지 알려주는 기법이다. 프로세스의 실행 종료 등을 알려준다. 프로세스에서 시그널을 재정의하면 시그널의 기본 동작과 다른 동작을 할 수 있다. 이를 이용하기 위해 유저 정의 시그널(리눅스의 경우 SIGUSR1, 2)을 제공한다.\n\n> 시그널 무시, 시그널 블록(block), 핸들러에 정의된 동작 수행(콜백 함수처럼 동작한다)\n\n시그널의 좀 더 자세한 동작 원리는 인터럽트가 종료되어 사용자 모드로 전환하는 시점에 pcb(process control block)에 있는 시그널과 관련된 자료구조의 상태를 확인하는 것이다. 이를 이용하여 다른 IPC 기법과 조합하여 사용할 수 있다. 데이터를 직접 전송할 수 없다는 단점이 있다.\n\n### 소켓(Socket)\n\n기본적으로 네트워크 통신을 위한 기술로 클라이언트와 서버 간의 요청과 응답을 처리하는 기술이다. 앞에서 파이프의 발전된 형태인 FIFO를 잠깐 살펴봤는데 소켓은 FIFO가 양방향으로 구성된 것과 흡사하다. 근본적으로 서로 다른 네트워크의 프로세스를 연결하는 기술이지만, [Unix Domain Socket(IPC socket)](https://en.wikipedia.org/wiki/Unix_domain_socket)을 이용하여 커널 내부의 커뮤니케이션에 사용할 수 있다. \n\n#### 장점\n\n- 양방향으로 많은 데이터가 오고 가야 할때 유리하다.\n\n#### 단점\n\n- 프로그램의 규모가 작다면 오버헤드가 클 수 있다.\n\n### 세마포어(Semaphore)\n\n세마포어는 조금 특이하다. 원래는 동기화 이슈를 해결하기 위한 방법론 중 하나이기 때문이다. 동기화 이슈가 생기는(동시에 접근하면 안 되는) 부분을 임계 영역(critical section)이라고 한다. 여기에 대한 동시 접근을 막는 것을 상호배제(MUTial EXclusion; MUTEX)라고 하는데, 세마포어는 동시 접근 할 수 있는 프로세스의 개수를 정해놓는 기법이다.\n\n```pseudocode\n/**\n * S : 임계 영역에 동시에 진입할 수 있는 스레드 수\n *\n * P \n *  - 임계 영역에 들어가기 전에 실행 가능 여부 판단(S가 0보다 작을 경우 실행 불가)\n *  - 실행 불가능 시 locking\n *  - 실행 가능하면 S--\n * V : 임계 영역에서 빠져나올 때 완료 체크(완료 시 S++)\n */\n\nP(S) {\n    while S <=0;\n    S--;\n}\n\nV(S) {\n    S++;\n}\n```\n\n>   비효율성을 해결하기 위해 대기 큐를 적용할 수 있다. 주제에서 벗어나기 때문에 다음을 참고 - [세마포어 - 위키백과](https://ko.wikipedia.org/wiki/%EC%84%B8%EB%A7%88%ED%8F%AC%EC%96%B4#%EC%A0%81%EC%9A%A9)\n\n실제 구현 시 특정 임계 영역을 정해놓고 세마포어가 사용 가능할 때까지 기다린다. 따지고 보면 임계 영역이 공유되는 영역이기 때문에 IPC로 이용할 수 있는 것이다. \n\n#### 장점\n\n- 다른 동기화 방법보다 효율적이다.\n- 임계 영역에 접근 가능한지 여부를 제공하기때문에 busy waiting을 사용하지 않아도 된다.    \n    > busy waiting : 특정 자원이 사용가능한지 계속 확인하는 것으로 자원 낭비가 일어날 수 있다.\n\n#### 단점\n\n- 동기화에 대한 조건을 다뤄야하기 때문에 오류 없이 구현하기 까다롭다.\n\n## 마치며\n\n이외에도 여러 가지 IPC기법들이 있는데, 잘 생각해봐야 할 것은 위에서도 잠깐 언급되었지만 여러가지 IPC기법을 필요에 따라 조합하여 사용할 수 있다는 것이다. 따라서 구성하려는 시스템의 요구사항이 무엇인지 잘 파악해야 할 것이다.\n\n본문에서는 리눅스를 기반으로 설명하였는데, 윈도우에서 사용되는 IPC가 궁금하다면 [Interprocess Communications - MSDN](https://docs.microsoft.com/ko-kr/windows/win32/ipc/interprocess-communications?redirectedfrom=MSDN)를 참고하자.\n\n이외에 자세한 구현이 궁금하다면 [IPC - joinc](https://www.joinc.co.kr/w/Site/system_programing/Book_LSP/ch08_IPC#s-2.4), [Linux System V and POSIX IPC Examples](http://hildstrom.com/projects/ipc_sysv_posix/index.html)와 [Beej's Guide to Unix IPC](http://beej.us/guide/bgipc/html/single/bgipc.html) 에 잘 정리가 되어있다.\n\n---\n\n#### References\n\n- [POSIX shared-memory API - GeeksforGeeks](https://www.geeksforgeeks.org/posix-shared-memory-api/)\n\n- [Inter-process communication - Wikipedia](https://en.wikipedia.org/wiki/Inter-process_communication#Approaches) \n\n- [Interprocess Communications - MSDN](https://docs.microsoft.com/ko-kr/windows/win32/ipc/interprocess-communications?redirectedfrom=MSDN)\n\n- [Linux System V and POSIX IPC Examples](http://hildstrom.com/projects/ipc_sysv_posix/index.html)\n\n- [IPC - joinc](https://www.joinc.co.kr/w/Site/system_programing/Book_LSP/ch08_IPC#s-2.4)\n\n- [파이프 (유닉스) - 위키백과](https://ko.wikipedia.org/wiki/%ED%8C%8C%EC%9D%B4%ED%94%84_(%EC%9C%A0%EB%8B%89%EC%8A%A4))\n\n- [IPC  InterProcess Communication  프로세스 간 통신 - 정보통신기술용어해설](http://www.ktword.co.kr/abbr_view.php?m_temp1=302)\n\n- [Beej's Guide to Unix IPC](http://beej.us/guide/bgipc/html/single/bgipc.html)\n"
  },
  {
    "path": "CS/non-blocking.md",
    "content": "# non-blocking\n\nNon-blocking은 os와 알고리즘에 대한 것이다. 공유자원을 안전하게 동시 사용할 수 있도록 하는 방법론이다.\n\nNon-blocking은 하나의 작업이 실패하거나 정지하더라도 다른 스레드에 영향을 주지 않도록 한다. 이를 위해 Non-blocking 알고리즘은 [lock-free](https://en.wikipedia.org/wiki/Non-blocking_algorithm#Lock-freedom) 특성과 [wait-free](https://en.wikipedia.org/wiki/Non-blocking_algorithm#Wait-freedom) 특성을 포함한다. lock-free는 wait-free를 포함하는 개념이다. 이로인해 non-blocking은 동시성(concurrency)을 갖는다.\n\n> 동시성 : 프로그램을 실행할 때 단 하나의 실행 순서를 갖도록 하는 제약을 없애고 각 부프로그램이 다른 부프로그램과 병렬적으로 동시에 실행되는 것\n\nlock-free 알고리즘이라는 것은 하나의 작업이 시작되어도, 시스템 전체의 진행이 보장되는 것이다.(A non-blocking algorithm is lock-free if there is guaranteed system-wide progress)<br/>\nwait-free 알고리즘은 각 스레드의 진행이 각각 보장되는 것(A non-blocking algorithm is wait-free if there is also guaranteed per-thread progress)이다. <br/>\n![non-blocking i/o](/assets/images/non-blocking.png)\nblocking 모델은 요청이 동작 가능할때까지 스레드가 블록된다. 반면, non-blocking 모델은 요청이 동작 불가능하다는 것을 알려주어 블록상태 없이 계속해서 진행가능하다. 즉, 다른 스레드의 작업을 기다리지 않는다. 이를 통해 대기 상태 없이 공유 자원에 접근할 수 있다.\n\n> Java의 멀티 스레드 어플리케이션에서 Synchronized를 시키는 것은 BlockingQueue Interface를 구현하는 것이라고 생각하면 된다. 당연히 non-blocking은 이와 반대다.\n\n<br/>\n\n## Non-blocking I /O\n\nNon-blocking I/O 는 I/O와 관계없이 프로세스가 계속해서 진행되는 것을 뜻한다. 기존 방식(blocking 혹은 synchronous한 I/O모델)에서는 I/O처리를 시작하면 작업이 끝날 때 까지 기다려야한다. 즉 프로그램이 block된다. 반면, Non-blocking I/O 모델에서는 입,출력을 외부에 맡겨 I/O의 진행 상황과 관계없이 프로그램이 진행된다.\n\n<br/>\n\n## Asynchronous Programming과 Non-blocking I/O\n\n프로그램의 주 실행흐름을 멈추거나, 대기 상태 없이 즉시 다음 작업을 수행할 수 있도록 하는 것이 asynchronous 방식이다.\n\nAnsynchronous programming은 언어 차원에서 지원하거나, 함수 전달을 통해 처리하는 방식을 통해 구현한다.<br/>언어차원에서 지원하는 방식은 future, promise와 같이 객체 형태의 결과를 돌려받거나 특정 문법을 이용하여 구현할 수 있다.<br/>함수 전달을 통해 처리하기 위해서는 함수를 값처럼 사용(일급 함수)를 지원하는 언어에서 Callback을 전달하여 결과를 처리할 수 있다. \n\nnon-blocking 알고리즘과, non-blocking I/O 모델의 관점이 다른 것 처럼, Asnychronous programming은 Asynchronous I/O 와 다르다. 따라서 Asnychronous programming과 Non-blocking I/O는 서로 바라보는 관점이 다르다. Event-loop를 사용하여 동시성을 확보하였어도 I/O 작업이 blocking될 수 있기 때문이다.\n\n<br/>\n\n만약 I/O 모델들의 조합을 알아보고 싶다면 다음을 참고하길 바란다. - [Asynchronous IO 개념 정리 - Uno's Blog](https://djkeh.github.io/articles/Boost-application-performance-using-asynchronous-IO-kor/)\n\n---\n\n#### Refereces\n\n- [Non-blocking Algorithms - jenkov.com](http://tutorials.jenkov.com/java-concurrency/non-blocking-algorithms.html)\n- [Blocking and Non-Blocking Algorithms - modernescpp](https://www.modernescpp.com/index.php/blocking-and-non-blocking)\n- [Non-Blocking Algorithms in Java - netjs.blogspot.com](https://netjs.blogspot.com/2016/06/non-blocking-algorithms-in-java.html)\n- [Non-blocking algorithm - wikipedia](https://en.wikipedia.org/wiki/Non-blocking_algorithm)\n- [멈추지 않고 기다리기(Non-blocking)와 비동기(Asynchronous) 그리고 동시성(Concurrency) - Peoplefund Tech](https://tech.peoplefund.co.kr/2017/08/02/non-blocking-asynchronous-concurrency.html)\n"
  },
  {
    "path": "CS/non-linear-search.md",
    "content": "# 비선형(Non-Linear) 구조의 탐색\n\n## 선형 구조\n\n선형 구조를 간단히 설명하면, 말 그대로 진행하는 방향이 직선으로(일자로) 되어있는 구조이다. 알고리즘에서는 데이터가 연속적으로 연결되어있는 모양으로 구성이 된 것을 선형 구조라 한다. 선형 구조는 연결리스트, 스택, 큐, 덱 등이 있다.\n\n> 선형 구조를 탐색하는 일반적인 방법론에는 순차검색과 이진검색이 있다.\n\n<br/>\n\n## 비선형 구조\n\n비선형 구조는 선형이 아닌 구조이다. 어떤 원소를 탐색했을 때 다음에 탐색할 수 있는 원소가 여러 개 존재하는 구조가 비선형 구조이다. 비선형 구조는 트리나 그래프 형태로 표현할 수 있다.\n\n> 트리는 순환(cycle)이 없는 그래프이다.\n\n<br/>\n\n## 비선형 구조 탐색\n\n비선형 구조는 탐색해야 할 데이터가 순차적이지 않다. 따라서 단순한 반복만으로 탐색할 수 없다. 이 때문에 스택이나 큐와 같은 자료구조를 활용하여 탐색할 방법과 순서를 만들어 탐색한다. 일반적으로 깊이우선탐색(depth first search; DFS)과 너비우선탐색(breadth first search; BFS)을 이용한다. 만약 탐색 대상이 그래프일 경우 탐색이 완료되면 [신장트리(spanning tree)](http://59.23.150.58/30stair/spanning_tree/spanning_tree.php?pname=spanning_tree#spanning)가 만들어진다.\n\n![search](../assets/images/non-linear-search.gif)\n\n> DFS와 BFS는 완전 탐색을 위한 방법이며, 가중치가 있는 그래프의 최단 거리를 찾기 위해서는 다익스트라와 플로이드-워셜 알고리즘이 주로 사용된다.\n\n<br/>\n\n### 깊이우선탐색(DFS)\n\n시작점에서 더는 이동할 수 없는 지점까지 탐색한 뒤, 인접한 정점이 있었던 곳으로 돌아가 같은 방법으로 차례로 탐색하는 방법이다. 이때 시작점(부모노드)으로 되돌아오는 과정을 백트래킹이라고 한다.\n\n이러한 탐색 과정은 스택을 이용하는 것과 동일하기 때문에 스택을 사용하거나 재귀호출을 이용하여 구현한다.\n\n![dfs](../assets/images/non-linear-search-dfs.png)\n\n현 경로상의 노드만 기억하면 되기 때문에 저장공간이 비교적 적게 필요하다. 또한, 목표 노드가 깊을 경우 유리하다.\n\n반면, 해가 없는 너무 깊은 곳까지 탐색하게 되거나 목표에 이르는 경로가 많을 경우 비효율적이다. 또한, 찾은 경로가 최단 거리가 아닐 수 있다.\n\n> 재귀호출을 하면 스택을 사용하는 것과 같은 효과를 낼 수 있다.\n\n<br/>\n\n### 너비우선탐색(BFS)\n\n시작 정점을 방문한 후 시작정점에 인접한 모든 정점을 방문한 뒤, 해당 정점들과 인접한 정점을 탐색하는 방법이다. 이는 큐와 동일하다.\n\n![bfs](../assets/images/non-linear-search-bfs.png)\n\n하나의 레벨에서 보행 가능한 정점을 모두 찾아보기 때문에 목표 노드까지의 최단 길이가 결과로 나오는 것이 보장된다.\n\n반면, 경로가 길 경우(깊을 경우) 많은 기억 공간이 필요하다. 또한, 무한그래프의 경우 탐색이 불가능하다.\n> 무한 그래프는 정점이 무한한 그래프를 뜻한다. \n> - DFS의 경우 하나의 정점의 결과값을 찾아 들어가기 때문에 무한한 정점 중에서 하나의 해를 구할 수 있으면 된다.\n> - 반면 BFS의 경우, 정점이 무한하다면 다음 수준으로 나아가는 것 자체가 불가능해진다.\n\n---\n\n#### References\n\n- [[알고리즘] 비선형구조의 탐색, 그래프의 구현 - https://12bme.tistory.com](https://12bme.tistory.com/123)\n- [깊이*우선*탐색 - 위키백과](https://ko.wikipedia.org/wiki/%EA%B9%8A%EC%9D%B4_%EC%9A%B0%EC%84%A0_%ED%83%90%EC%83%89)\n- [너비*우선*탐색 - 위키백과](https://ko.wikipedia.org/wiki/%EB%84%88%EB%B9%84_%EC%9A%B0%EC%84%A0_%ED%83%90%EC%83%89)\n- [[그래프] DFS와 BFS 구현하기 :: 마이구미 - https://mygumi.tistory.com](https://mygumi.tistory.com/102)\n- [[DFS][BFS] DFS 와 BFS - https://cru6548.tistory.com](https://cru6548.tistory.com/10)\n"
  },
  {
    "path": "CS/open-closed-principle.md",
    "content": "# 개방-폐쇄 원칙(Open-Closed Principle)\n\n개방-폐쇄 원칙은 **확장에 열려있고, 변경에는 닫혀있어야 한다**는 원리이다. 열려있다는 것(개방; open)은 소프트웨어는 확장(기능 추가 등의)할 수 있어야 한다는 것이고, 닫혀있다는 것(폐쇄; closed)은 기존 코드를 수정하지 않고 확장할 수 있어야 한다는 것이다. 즉 소프트웨어는 **수정 없이 확장할 수 있어야 한다**.\n\n열려있다는 것은 비교적 명확하나 닫혀있다는 것의 의미가 애매할 수 있다. 닫혀있다는 것에 대해 좀 더 자세히 말하면, 새로운 기능을 추가할 때 기존 시스템의 수정 없이 변경할 수 있어야 한다는 것이다. 닫혀있는 프로그램은 기존 소스를 새롭게 컴파일하거나 배포할 필요 없이 새롭게 추가된 부분만 배포하면 된다. 이를 위해 폐쇄된 모듈은 잘 은닉되어있고, 사용 혹은 재사용에 반드시 필요한 부분만 인터페이스로 정의되어 있어야 한다.\n\n## 적용 방법\n\n- 변경(확장)이 일어날 수 있는 부분과 변하지 않을 부분을 명확히 정의한다.\n- 변경이 일어날 수 있는 모듈과 변하지 않는 모듈의 사이에 인터페이스를 만들어 이를 통하여 메세지를 주고받도록 한다.\n- 정의한 인터페이스에 의존하도록 한다(구현에 영향을 받지 않도록).\n\n## 예시1 - 계산기\n\n```java\ninterface Calculator {\n  void calculate();\n  int getResult();\n}\n\nclass BasicCalculator implements Calculator {\n  private final static String PLUS = \"+\";\n  private final static String MINUS = \"-\";\n  private final static String MULTIPLY = \"*\";\n  private final static String DIVISION = \"/\";\n\n  private int left;\n  private int right;\n  private String operator;\n  private int result;\n\n  public BasicCalculator(int left, int right, String operator) {\n    this.left = left;\n    this.right = right;\n    this.operator = operator;\n  }\n\n  public void calculate() {\n    if (operator.equals(PLUS)) {\n      result = left + right;\n    } else if (operator.equals(MINUS)) {\n      result = left - right;\n    } else if (operator.equals(MULTIPLY)) {\n      result = left * right;\n    } else if (operator.equals(DIVISION)) {\n      result = left / right;\n    }\n  }\n\n  public int getResult() {\n    return result;\n  }\n}\n```\n\n위의 사칙연산 계산기에서 새로운 기능을 추가하려면 기존 소스를 변경해야 한다. 다음과 같을 것이다.\n\n```java\npublic void calculate() {\n  if (operator.equals(PLUS)) {\n    result = left + right;\n  } else if (operator.equals(MINUS)) {\n    result = left - right;\n  } else if (operator.equals(MULTIPLY)) {\n    result = left * right;\n  } else if (operator.equals(DIVISION)) {\n    result = left / right;\n  } // 추가 할 기능 작성 e.g. 나머지 연산 제곱 연산 제곱근 연산 등등...\n}\n```\n\n첫째로 상속을 생각해볼 수 있겠지만, 핵심 로직을 변경해야 하는 것은 마찬가지이고 이 경우는 특히나 [캡슐화](https://www.geeksforgeeks.org/encapsulation-in-java/)를 위반할 가능성이 높다. 자식 클래스에서 부모 클래스의 기능을 이용한 변경이 일어날 수 있기 때문이다. 따라서 각 책임을 새롭게 분리해 볼 수 있다.\n\n```java\nclass PlusCalculator implements Calculator {\n  private int left;\n  private int right;\n  private int result;\n\n  public PlusCalculator(int left, int right) {\n    this.left = left;\n    this.right = right;\n  }\n\n  @Override\n  public void calculate() {\n    result = left + right;\n  }\n\n  @Override\n  public int getResult() {\n    return result;\n  }\n}\n\nclass MinusCalculator implements Calculator {\n  // ...\n    \n  @Override\n  public void calculate() {\n    result = left - right;\n  }\n    \n  // ...\n}\n```\n\n각 연산 별로 새로운 클래스를 정의했다. 새로운 기능을 추가할때 새로운 클래스만 작성하면 되는것 처럼 보이지만 클라이언트에 문제가 생긴다.\n\n```java\nclass CalculatorClient {\n  private final static String PLUS = \"+\";\n  private final static String MINUS = \"-\";\n  private final static String MULTIPLY = \"*\";\n  private final static String DIVISION = \"/\";\n\n  // +,1,2와 같이 입력이 되었다고 가정\n  public static void main(String[] args) {\n    for (String arg : args) {\n      Calculator calculator;\n\n      String[] inputs = arg.split(\",\");\n      String operator = inputs[0];\n      int left = Integer.parseInt(inputs[1]);\n      int right = Integer.parseInt(inputs[2]);\n\n      if (operator.equals(PLUS)) {\n        calculator = new PlusCalculator(left, right);\n      } else if (operator.equals(MINUS)) {\n        calculator = new MinusCalculator(left, right);\n      } // ... 다른 연산\n\n      calculator.calculate();\n      System.out.println(calculator.getResult());\n    }\n  }\n}\n```\n\n클라이언트에서 또 다른 분기가 이루어져서 추가적인 관리 포인트가 생겼다. 클라이언트와 핵심 로직 사이에 인터페이스를 추가하여 개선해볼 수 있다. 여러가지 방법을 사용해볼 수 있는데, 간단한 팩토리를 이용하여 개선해보겠다.\n\n```java\nclass CalculatorFactory {\n  private final static String PLUS = \"+\";\n  private final static String MINUS = \"-\";\n  private final static String MULTIPLY = \"*\";\n  private final static String DIVISION = \"/\";\n\t   \n  private Calculator calculator;\n\n  private CalculatorFactory(Calculator calculator) {\n    this.calculator = calculator;\n  }\n\n  public static Calculator createByOperator(int left, int right, String operator) {\n    if (operator.equals(PLUS)) {\n      return new PlusCalculator(left, right);\n    } else if (operator.equals(MINUS)) {\n      return new MinusCalculator(left, right);\n    } // ... 다른 연산\n  }\n}\n```\n\n```java\nclass CalculatorClient {\n  // +,1,2와 같이 입력이 되었다고 가정\n  public static void main(String[] args) {\n    for (String arg : args) {\n      Calculator calculator;\n\n      String[] inputs = arg.split(\",\");\n      String operator = inputs[0];\n      int left = Integer.parseInt(inputs[1]);\n      int right = Integer.parseInt(inputs[2]);\n\t\n      caluclator = CalculatorFactory.createByOperator(left, right, operator);\n      calculator.calculate();\n      System.out.println(calculator.getResult());\n    }\n  }\n}\n```\n\n클라이언트 부분은 해결됐다. 여기까지만 해도 OCP원칙이 어느정도 적용되었다고 볼 수 있지만, 좀 더 완벽한 구현을 위해 enum 객체를 활용해보겠다.\n\n```java\nenum Calculator {\n  PLUS(\"+\") {\n    public void calculate(int left, int right) {\n      result = left + right;\n    }    \n  },\n  MINUS(\"-\") {\n    public void calculate(int left, int right) {\n      result = left - right;\n    }\n  },\n  MULTYPLY(\"*\") {\n    public void calculate(int left, int right) {\n      result = left * right;\n    }\n  },\n  DIVISION(\"/\") {\n    public void calculate(int left, int right) {\n      result = left / right;\n    }\n  };\n    \n  public final String OPERATOR;\n    \n  private int result;\n    \n  Calculator(String operator) {\n      this.OPERATOR = opeartor;\n  }\n          \n  public abstract void calculate(int left, int right);\n    \n  public int getResult() {\n      return result;\n  }\n    \n  public static Calculator getCalculatorByOperator(String operator) {\n      // ... 해당하는 enum 객체 반환\n  }\n}\n```\n\n## 예시2 - 플러그인 시스템\n\n거시적인 관점으로 생각해보면 플러그인 아키텍쳐를 개방-폐쇄 원칙의 좋은 예시로 볼 수 있다. 플러그인을 사용하게되면 수정이나 재배포 없이 여러가지 도구(tool)들을 쉽게 확장(추가)할 수 있다. 시스템은 플러그인에 대해 모르고, 플러그인은 시스템에 대해서 알고 있기 때문이다. 플러그인은 시스템에 종속성을 가지지만, 시스템은 플러그인에 종속되지 않는다. 플러그인 중 하나가 잘못되면 해당 기능이 제대로 동작하지 않을 뿐이지, 시스템 전체에 영향을 주지 않는다.\n\n우리는 플러그인 시스템을 dependency manager 혹은 package manager와 유사한 이름으로 프레임워크 관리에 사용하고 있다. 이러한 관리 시스템에서 현재 프로젝트에 새로운 기능을 추가하는 것은 특별한 경우를 제외하면 기존의 플러그인과 독립적으로 이루어진다.\n![open-closed-principle_plugins](https://user-images.githubusercontent.com/24666330/87766360-0252a480-c854-11ea-90bf-2a44b60f1587.png)\n\n소스 레벨까지 가지 않더라도 IDE를 생각해보면 변경이나 재배포 없이 플러그인을 이용하여 손쉽게 확장이 가능하다.\n![open-closed-principle_ide](https://user-images.githubusercontent.com/24666330/87748312-7da25f00-c830-11ea-91af-79951517a430.png)\n\n\n\n## 결론\n\n위에서 여러가지 방법을 이용하여 개방-폐쇄 원칙에 부합하는 프로그램을 만들었다. 하지만 이는 의미 없게 보일 수 있는데, 우리들이 쓰고 있는 언어들과 설계들은 일반적으로 새로운 기능들이 시스템의 다른 부분들과 분리되어 배포, 컴파일, 작성되는 것을 허용하지 않기 때문이다.\n\n또한 복잡한 시스템이라면 현재의 시스템이 변경에 닫혀있는지, 새로운 기능의 확장에 열려있는지 확인하기 어렵다. 따라서 실제로 새로운 기능을 추가할 때 기존 소스에서 많은 변경이 이루어진다([산탄총수술](https://refactoring.guru/smells/shotgun-surgery)이 바람직하지 않다는 것을 알면서도).\n\n개방-폐쇄 원칙은 실제 개발에서 유용하게 쓰이기 힘들다는 의견이 많다. 하지만 플러그인 아키텍쳐가 그러한 의견이 틀렸다는 반증이다. Robert C. Martin (Uncle Bob)은 플러그인 아키텍쳐가 미래의 소프트웨어 시스템에서 중요한 부분을 차지할 것이라고 했다. 잘 생각해보면 현재 인기가 많은 언어들은 플러그인과 유사하게 의존성을 관리한다. 플러그인 시스템이 모든 것을 해결해주지는 않겠지만, 현재 시점에서 가장 좋은 OCP원칙의 best practice라고 말할 수 있을 것이다.\n\n---\n\n#### References\n\n- [The Open Closed Principle](https://blog.cleancoder.com/uncle-bob/2014/05/12/TheOpenClosedPrinciple.html)\n\n- [객체지향 개발 5대 원리: SOLID](http://www.nextree.co.kr/p6960/)\n"
  },
  {
    "path": "CS/soc.md",
    "content": "# 관심사 분리(Separation of Concerns; SoC)\n\n관심사 분리는 프로그램의 각 부분이 자신의 관심사만을 다루도록 분리되어야 한다는 것이다. 여기서 `관심사`란 프로그램 코드에 영향을 주는 일련의 정보를 의미한다.\n\n> **예시**\n> 자동차 창문을 여는 장치가 망가져 수리를 한다. 간단한 고장이기 때문에 금방 수리를 했다.\n> 하지만 창문은 잘 고쳤는데 갑자기 시동이 걸리지 않는다. 원인은 자동차를 자동차를 제어하는 배선이 너무 복잡해 창문을 제어하는 배선을 만지면 차량의 시동을 거는 배선에도 영향을 주기 때문이었다.\n> 만약 창문을 제어하는 배선과 시동을 거는 배선이 잘 분리되어 있다면 이런 일은 발생하지 않았을 것이다.\n\n만약 위의 예시를 프로그램화 했다면 창문을 제어하는 기능과 시동을 거는 기능을 분리하는 것으로 생각해볼 수 있다. 이처럼 각 기능들이 서로 얽히지 않고 각각의 역할만 하도록 하는 것을 관심사 분리라고 한다. 각각의 모듈은 각자의 기능만을 해결해야 한다.\n\n관심사 분리는 추상화의 한 형태이다. 때문에 관심사 분리를 위해서 캡슐화가 잘 되어야 한다. 기능의 구현은 내부적으로 숨겨놓고 해당 모듈을 실행시켰을 때 정확한 기능이 동작하도록 보장되어야 한다. 인터페이스 뒤에 모듈의 구현 세부사항을 숨기면 다른 부분의 세부사항을 알 필요 없이 해당 코드를 개선하거나 수정할 수 있다. 이렇게 되면 다른 기능에 영향을 주지 않고 유지 보수가 가능하다.\n\n계층화(layered) 된 설계는 관심사 분리의 좋은 예시이다. 예를들어 MVC패턴의 각 계층(layer)은 각각의 관심사만을 수행하도록 구성된다. 이외에도 객체 지향 언어에서는 관심사를 객체로 분리할 수 있으며 절차 지향 언어에서는 관심사를 메소드 혹은 프로시저로 분리할 수 있다.\n\n웹 프로그램을 개발할 때 JSP 파일 안에 SQL을 작성하지 않는다. 결과를 계산하는 모듈에서 HTML 파일을 생성하지 않는다. 또한 비즈니스 규칙은 데이터베이스 스키마와 독립적으로 이루어져야한다. 만약 그렇게 작성한다면 하나의 기능에 대한 수정때문에 모든 기능이 중단될 수 있다. 이는 관심사 분리를 해야하는 이유이다.\n\n---\n\n#### References\n\n- [The Single Responsibility Principle](https://blog.cleancoder.com/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html)\n"
  },
  {
    "path": "CS/srp.md",
    "content": "# 단일 책임 원칙(Single Responsibility Principle; SRP)\n\n단일 책임 원칙은 **클래스(혹은 모듈)는 오직 하나의 책임만을 가져야 한다는 것**이다. 또한 **클래스가 변경되어야 하는 이유는 단 하나여야 한다**는 것이다. 여기서 '책임'과 '이유' 가 무엇인지 모호할 수 있다. 단일 책임 원칙을 이해하기 위해서 먼저 알아 둬야 할 개념들이 있기 때문이다. 단일 책임 원칙은 **관심사 분리**, **응집도와 결합도**에 관한 내용이다. 따라서 이에 대한 이해가 선행되어야 한다.\n\n- [관심사 분리](soc.md)\n\n- [응집도와 결합도](cohension&coupling.md)\n\n클래스는 오직 하나의 책임만을 가져야 한다. 여기서 책임은 각 클래스의 관심사라고 할 수 있다. 즉 단일 책임 원칙은 각 클래스의 관심사가 잘 분리되어 있어야 한다는 것이다. 쉽게 얘기하면 각 클래스는 하나의 기능만을 구현해야 한다. 이를 위해 인터페이스를 사용하여 캡슐화 시키고 노출되어야할 기능에 대한 코드만 응집시켜야 한다.\n\n또한 클래스가 변경되어야 할 이유는 단 하나여야 한다. 즉 같은 이유로 변하는 것은 하나로 모으고, 다른 이유로 변하는 것은 분리해야 한다. 잘 응집된 클래스는 다른 기능을 위한 분기처리가 필요없다. 다른 기능을 실행시키기 위한 상태가 필요없으므로 낮은 결합도를 유지할 수 있게 된다.\n\n## 적용 방법\n\n기본 설계 원칙을 위반하고 설계 품질에 부정적인 영향을 미치는 구조로 코드가 작성된 것을 [code smell](https://en.wikipedia.org/wiki/Code_smell)이라고 한다. code smell은 리팩토링의 징후라고 할 수 있는데, 리팩토링의 근본정신도 객체들의 책임을 최상의 상태로 분배한다는 것이다. 따라서 code smell이 발견 될 경우 단일 책임 원칙을 적용해 볼 수 있는데, code smell 중 '여러 원인에 의한 변경'과 '산탄총 수술'이 단일 책임 원칙과 연관이 깊은 것들이다.\n\n- 여러 원인에 의한 변경(Divergent Change)\n  - 단일 클래스에 많은 변경이 있는 경우 클래스를 추출하여 책임을 분리해준다.\n  - 책임만 분리하는 것이 아니라 분리된 두 클래스간의 관계의 복잡도를 줄인다.\n\n  > 여러 원인에 의한 변경을 확산적 변경이라고 부르기도 하는데, 여러 원인에 의한 변경이라고 부르는 것이 더욱 직관적이다.\n\n- 산탄총 수술(Shotgun Surgery)\n  - 변경을 할 때마다 수정해야 할 클래스가 많다면 책임이 분산되어 있는 것이다.\n  - 이 경우 수술이 잘 끝나면 상관없지만, 수정해야 할 클래스가 너무 많아 빼먹는 경우가 생긴다면 고통이 계속될 것이다.\n  - 해결을 위해 분산된 책임을 모아 응집도를 높일 수 있다.\n\n## 예시1 - 계산기\n\n```java\nclass Calculator {\n    public void calculate(int left, int right, String operator) {\n        if (operator.equals(\"+\")) {\n            System.out.println(left + right);\n        } else if (operator.equals(\"-\")) {\n            System.out.println(left - right);\n        } else if (operator.equals(\"*\")) {\n            System.out.println(left * right);\n        } else if (operator.equals(\"/\")) {\n            System.out.println(left / right);\n        }\n    }\n}\n```\n\n위의 클래스는 '계산' 이라는 하나의 책임(기능)만 갖고 있는 것 처럼 보이지만 그렇지 않다. 사칙연산의 기능을 모두 갖고 있고 이를 출력하는 책임까지 갖는다. 여러가지 책임을 갖는 것이다. 클라이언트가 사용하기 편리해 보일지 모르지만, 한 가지 로직만 잘못되어도 이 프로그램은 제대로 동작 하지 않을 것이다. 뿐만 아니라 변경의 이유도 하나가 아니다.\n\n각 기능을 메소드로 분리하여 설계하면 다음과 같은 인터페이스가 작성될 것이다.\n\n```java\ninterface Calculator {\n    void calculate();\n    int getResult();\n}\n\ninterface Printer {\n    void print();\n}\n```\n\n이에 따라 클래스를 작성해보면 다음과 같을 것이다.\n\n```java\nclass BasicCalculator implements Calculator{ // 연산\n    private final static String PLUS = \"+\";\n    private final static String MINUS = \"-\";\n    private final static String MULTIPLY = \"*\";\n    private final static String DIVISION = \"/\";\n    \n    private int left;\n    private int right;\n    private String operator;\n    private int result;\n    \n    public BasicCalculator(int left, int right, String operator) {\n        this.left = left;\n        this.right = right;\n        this.operator = operator;\n    }\n    \n    public void calculate() {\n        if (operator.equals(PLUS)) {\n            result = left + right;\n        } else if (operator.equals(MINUS)) {\n            result = left - right;\n        } else if (operator.equals(MULTIPLY)) {\n            result = left * right;\n        } else if (operator.equals(DIVISION)) {\n            result = left / right;\n        }\n    }\n    \n    public int getResult() {\n        return result;\n    }\n}\n\nclass IntPrinter implements Printer { // 출력\n    private int i;\n    \n    public IntPrinter(int i){\n        this.i = i;\n    }\n    \n    public void print() {\n        System.out.println(i);\n    };\n}\n```\n\n각각의 클래스는 하나의 책임만 갖게 되었다. 또한 각각의 기능의 의존성이 사라졌다. 이렇게 책임이 분리 되면 변화에 훨씬 유연하게 대처할 수 있다. 만약 좌항을 최초 한 번만 입력할 수 있다는 비즈니스 로직이 추가되거나, 출력을 하는 방법이 바뀌거나, 연산이 추가되는 등의 변화가 생기더라도 해당되는 클래스만 변경해주면 된다. \n\n## 예시2 - 회사\n\n예시1에서 만들어본 계산기를 통해 단일 책임 원칙의 '책임'은 프로그램의 책임이라는 것을 이해 할 수 있다. 버그 수정이나 리팩토링 같은 작업은 프로그래머의 책임이지 프로그램의 책임이 아니다. 하지만 단일 책임 원칙에 대해 이야기한 로버트 마틴은 단일 책임 원칙은 사람에 대한 것이라고 말한다.  또 다시 미궁에 빠지는 느낌이다.\n\n> \"This principle is about people\" - Robert C. Martin\n\n변경사항의 이유는 하나여야 한다고 했다. 어떤 것이 변경사항이 발생할 이유를 정의할지 생각을 해봐야 한다. 변경사항이 발생하는 이유는 다르게 말하면 책임이라고 말 할 수 있다. 우리는 책임을 정의하는 것이 무엇인지 생각해봐야 한다. 즉 누가 프로그램의 설계에 책임을 져야 하는지 생각해봐야 한다.\n\n회사의 최상위에 CEO가 있고 그 밑에 CFO, COO, CTO와 같은 C-level 경영진들이 있다고 생각해보자. CFO는 회사의 재무를 관리하는 책임이 있고, COO는 회사 운영 및 관리에 책임이 있다. 그리고 CTO는 회사의 기술 환경 및 개발에 대한 책임이 있다.\n\n우리는 이 회사에 새로 입사하게 되어 다음과 같은 업무를 배정 받았다.\n\n- 직원의 계약, 상태, 근무 시간 등을 기준으로 특정 직원의 지급액을 결정\n- 직원 객체가 관리하는 데이터를 데이터베이스에 저장\n- 감찰 시 직원이 적절한 시간동안 작업하고, 적절한 보상을 받고있는지 확인하기 위한 보고서 내용 전달\n\n이를 인터페이스로 나타내면 다음과 같이 정의할 수 있다.\n\n```java\npublic interface Employee {\n    public Money calculatePay();\n    public void save();\n    public String reportHours();\n}\n```\n\n`calculatePay` 부터 살펴보자. C-level 경영진 중 `calculatePay` 메소드의 동작에 대해 설계해야 하는 사람은 누구일까? 만약 `calculatePay`가 오작동 한다면 누가 그 책임을 져야될까? 바로 CFO다. 너무 명확하다.\n\n직원의 급여를 결정하는 것은 재무의 책임이다. 만약 CFO의 조직의 누군가 급여를 계산하는 규칙을 잘못 정해서 2배의 급여를 받았다면, CEO는 CFO에게 책임을 물을 것이다. 즉 `calculatePay` 메소드의 알고리즘에 변경이 발생한다면 CFO가 이끄는 조직에 의해 변경사항이 요청되어야 한다.\n\n다른 메소드도 마찬가지다. `save` 메소드는 기업의 데이터 베이스에 관한 기능이다. 만약 여기에 문제가 생긴다면 CTO가 책임을 질 것이고, `reportHours` 가 잘못된다면 COO가 책임을 질 것이다. CTO가 요청한 변경사항때문에 COO가 책임을 져서는 안된다. 만약 `save` 메소드를 변경했는데 `reportHours` 메소드가 제대로 동작하지 않는다면, COO는 CTO에게 해당 메소드를 수정하지말라고 압박을 줄 것이다.\n\n## 결론\n\n단일 책임 원칙은 다른 객체지향 원칙들에 비해 단순한 개념이다. 프로그램은 하나의 책임만을 갖도록 하면 된다는 내용이기 때문이다. 만약 여러 원인에 의한 변경 혹은 산탄총 수술이 필요한 경우 단일 책임 원칙에 위배되지 않았는지 점검해볼 필요가 있다.\n\n하지만 이 원리를 적용하여 직접 클래스를 설계하는 것은 매우 힘들다. 예시2 에서 나온 상황들이 단일 책임 원칙을 복잡하게 만들기 때문이다. 만약 비즈니스 프로세스와 관련된 프로그램을 작성하게 된다면 단일 책임 원칙이 사람에 관한 것이라는 구문을 다시 생각해보자. \n\n변경사항의 원인은 변경을 요청하는 사람(혹은 조직)이다. 따라서 소프트웨어를 설계할때 어떤 한 사람 또는 밀접하게 연관된 집단이 단 하나의 비즈니스 기능을 세심하게 정의해서 요청해야 할 것이다. 또한 모듈들이 조직의 복잡성으로부터 독립되어 단 하나의 비즈니스 기능에 대해 대응하고 책임지도록 시스템을 설계해야 한다.\n\n\n\n---\n\n#### References\n\n- [The Single Responsibility Principle](https://blog.cleancoder.com/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html)\n\n- [Code smell](https://en.wikipedia.org/wiki/Code_smell)\n- [객체지향 개발 5대 원리 : SOLID](http://www.nextree.co.kr/p6960/)\n"
  },
  {
    "path": "CS/union-find.md",
    "content": "# 유니온 파인드(Union Find)\n\n상호 배타적집합(disjoint-set) 이라고도 한다. 여러 노드 중 두 개의 노드씩 같은 집합으로 묶어가며 다른 노드가 같은 집합에 있는지 확인하는 그래프 알고리즘이다. 집합을 표현하기 위해 트리를 사용하며, 이를 위해 두 가지 연산을 한다.\n\n​\t노드 x와 y를 찾았다고 가정\n\n-   Find : 노드 x가 어떤 집합에 포함되어 있는지 찾는 연산\n-   Union : 노드 x가 포함된 집합과 노드 y가 포함된 집합을 합치는 연산\n\n>   예시 문제 - [섬 연결하기(프로그래머스)](https://programmers.co.kr/learn/courses/30/lessons/42861)\n\n## Union Find\n\n### 부모 노드\n\n트리를 이용하여 부모와 원소의 인덱스를 매핑한다. `parent[i]` 를 노드 `i` 의 부모 노드로 정의한다. 따라서 `parent[i] = i` 라면 루트 노드이다.\n\n```java\nfor (int i = 0; i < MAX_SIZE; i++) {\n    parent[i] = i;\n}\n```\n\n>   초기 값으로 자기 자신을 부모 노드라고 정의해준다.\n\n### Find\n\n`parent[i] = i` 인 점을 이용해서 부모 노드를 찾을 때 까지 반복하여 탐색한다.\n\n```java\nint find(int x) {\n    if (parent[x] == x) {\n        return x;\n    }\n    \n    return find(parent[x]);\n}\n```\n\n>   예시\n>\n>   ```text\n>   [0] : 1, [1] : 2, [2] : 2, [3] : 1\n>   \n>     [2]\n>      |\n>     [1]\n>    ┌─┴─┐\n>   [0] [3]\n>   ```\n>\n>   위의 경우 루트 노드는 index와 value가 같은 [2]이다.\n\n### Union\n\n매개변수로 두 개의 노드를 받은 뒤 각 집합을 합쳐준다. `x` 를 `y` 에 합치든 `y` 에 `x` 를 합치든 똑같다. \n\n```java\nvoid union(int x, int y) {\n    int rootX = find(x);\n    int rootY = find(y);\n    parent[rootX] = rootY;\n}\n```\n\n\n\n>   예시\n>\n>   ```text\n>   [0] : 1, [1] : 2, [2] : 2, [3] : 1, [4] : 4\n>   \n>     [2]  [4]\n>      |\n>     [1]\n>    ┌─┴─┐\n>   [0] [3]\n>   \n>   union(2, 4);\n>   \n>   [0] : 1, [1] : 2, [2] : 4, [3] : 1, [4] : 4\n>   \n>     [4]\n>      |\n>     [2] \n>      |\n>     [1]\n>    ┌─┴─┐\n>   [0] [3]\n>   ```\n>\n>   위의 경우 루트 노드는 index와 value가 같은 [2]이다.\n\n## 시간복잡도 개선\n\n위에서 살펴본 방법의 시간복잡도는 `O(n)` 이다. 위의 예시는 최악의 케이스에 가까운데, `union`의 예시처럼 높이가 낮은 트리에 높은 트리가 자식 노드로 붙게 되면 해당 트리는 끊임없이 길어질 것이다. 이 때, `find` 가 최하위에 있는 자식부터 탐색을 할 경우 트리의 높이만큼 올라가며 탐색해야한다. 이를 해결하기 위해  **path compression** 과 **union by rank** 가 사용된다. 이 기법들을 적용하면 시간복잡도가 `O(log n)` 으로 개선된다.\n\n\n\n### Path Compression\n\n말 그대로 경로를 압축해주는 것인데, `find` 를 할 때, 루트 노드를 찾은 경우 루트 노드의 자식 노드로 현재 노드를 붙여준다.\n\n```java\nint find(int x) {\n    if (parent[x] == x) {\n        return x;\n    }\n    \n    parent[x] = find(parent[x]); // 루트 노드를 찾으면 x의 부모를 루트로 바꿔준다.\n    return parent[x];\n}\n```\n\n>   예시\n>\n>   ```\n>   [0] : 1, [1] : 2, [2] : 2, [3] : 1\n>   \n>     [2]\n>      |\n>     [1]\n>    ┌─┴─┐\n>   [0] [3]\n>   \n>   find(0);\n>   \n>   [0] : 2, [1] : 2, [2] : 2, [3] : 1\n>   \n>     [2]\n>    ┌─┴─┐\n>   [0] [1]\n>        |\n>       [3]\n>   ```\n\n### Union By Rank\n\n말 그대로 순위에 따라 `union` 을 하는 것이다. 자식 노드의 개수에 따라 우선 순위를 매기고 합치는 것이다. 따라서 `rank` 배열을 따로 만들어준다.\n\n```java\nfor (int i = 0; i < MAX_SIZE; i++) {\n    rank[i] = i;\n}\n```\n\n`rank` 를 이용하여 더 낮은 쪽에 합쳐준다.\n\n```java\nvoid union(int x, int y) {\n    int rootX = find(x);\n    int rootY = find(y);\n    \n    if (rootX == rootY) {\n    // rootX와 rootY가 같다는 것은 같은 그룹이라는 뜻이다.\n      return;\n    }\n  \n    if (rank[rootX] < rank[rootY]) {\n        parent[rootX] = rootY;\n        rank[rootY] += rank[rootX];\n        return;\n    }\n    \n    parent[rootY] = rootX;\n    rank[rootX] += rank[rootY];\n}\n```\n\n```text\n[0] : 1, [1] : 2, [2] : 2, [3] : 1, [4] : 4\n\n  [2]  [4]\n   |\n  [1]\n ┌─┴─┐\n[0] [3]\n\nunion(2, 4);\n\n[0] : 1, [1] : 2, [2] : 4, [3] : 1, [4] : 4\n\n    [2] \n   ┌─┴─┐\n  [1] [4]\n ┌─┴─┐\n[0] [3]\n```\n\n## 공간복잡도 개선\n\n하지만 위와 같은 방식은 똑같은 크기의 `parent` 와 `rank` 가 존재하여 메모리를 많이 차지한다. 이를 위해 부모노드와 순위를 함께 표시할 수 있다. `parent` 배열에 음수를 함께 넣어 부모 노드와 rank를 함께 저장하는 것이다.\n\n예를 들어, `parent[2]` 의 값이 `-3` 일 경우 2번 노드를 포함하여 총 3개의 노드로 이루어진 트리라는 뜻이다.\n\n>   자식의 수는 2개\n\n또한 `parent[3]` 의 값이 5일 경우 3번 노드의 부모는 5번 노드라는 것이다.\n\n쉽게 얘기하면 `parent[i] == i` 인 경우를 없애고 해당 경우에 트리의 노드 개수를 저장하는 것이다. 이외의 경우는 자식이 부모 노드를 가리킨다.\n\n### 부모 노드\n\n모두 -1 로 초기화해준다.  만약 `parent[i]` 가 0보다 작을 경우 `i` 는 루트 노드다.\n\n```java\nfor (int i = 0; i < MAX_SIZE; i++) {\n    parent[i] = -1;\n}\n```\n\n### Find\n\n기본적인 동작은 이전과 같고, 매개변수 `x` 가 루트 노드인지 판단할 때 0보다 작은지 판단한다.\n\n```java\nint find(int x) {\n    if (parent[x] < 0) {\n        return x;\n    }\n    \n    parent[x] = find(parent[x]);\n    return parent[x];\n}\n```\n\n### Union\n\n주의할 점은 마찬가지로 루트 노드의 값이 음수라는 점이다. 즉, 트리의 높이를 판단할 때 `parent[root]` 의 값이 음수이기 때문에 작을 수록 높은 트리이다. 직관적인 판단을 위해 -1씩 곱해줬다.\n\n>   -1을 곱하지 않으면 높이 3인 트리의 루트 노드 `parent[x]` 는 -3, 높이 5인 루트 노드 `parent[y]` 는 -5가 되기 때문에 `parent[y]` 의 값이 더 높지만 판단을 거꾸로 해야 한다.\n\n```java\nvoid union(int x, int y) {\n    int rootX = find(x);\n    int rootY = find(y);\n\n    if (rootX == rootY) {\n        return;\n    }\n\n    if (parent[rootY] * -1 < parent[rootX] * -1 ) {\n        parent[rootX] += parent[rootY];\n        parent[rootY] = rootX;\n        return;\n    }\n\n    parent[rootY] += parent[rootX];\n    parent[rootX] = rootY;\n}\n```\n\n## 마치며\n\n단순한 집합 구성이나 사이클 판단 외에도 [최소 신장 트리(Minimum Spanning Tree; MST)](https://ratsgo.github.io/data%20structure&algorithm/2017/11/28/MST/) 를 얻는데 사용할 수 있다. 이 때는 단독으로 사용되지는 않고 [크루스칼 알고리즘](https://ko.wikipedia.org/wiki/%ED%81%AC%EB%9F%AC%EC%8A%A4%EC%BB%AC_%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98)의 사이클 판단에 사용된다.\n\n---\n\n#### References\n\n-   [Disjoint Set (Or Union-Find) | Set 1 (Detect Cycle in an Undirected Graph)](https://www.geeksforgeeks.org/union-find/)\n-   [Union-Find Algorithm | Set 2 (Union By Rank and Path Compression)](https://www.geeksforgeeks.org/union-find-algorithm-set-2-union-by-rank/)\n-   [Union/Find and the Parent Pointer Implementation](https://opendsa-server.cs.vt.edu/ODSA/Books/Everything/html/UnionFind.html)\n-   [[Algorithm] 유니온 파인드(Union - Find)](https://ssungkang.tistory.com/entry/Algorithm-%EC%9C%A0%EB%8B%88%EC%98%A8-%ED%8C%8C%EC%9D%B8%EB%93%9CUnion-Find)\n"
  },
  {
    "path": "CS/페이징과 세그먼테이션.md",
    "content": "# 페이징 기법과 세그먼트 기법\n\n## 가상기억장치\n\n가상기억장치는 **주기억장치의 용량이 부족할 때 하드디스크의 일부 공간을 마치 주기억장치처럼 사용하는 기억장치**를 말한다.  \n가상기억장치에 프로그램을 저장할 때는 불필요한 메모리 낭비를 줄이기 위해 프로그램을 여러 개의 블록 단위로 나눠 보관한다. 각각의 블록은 **mapping** 과정을 통해 주기억장치에 적재된다.   \n주기억장치와 가상기억장치 간 프로세스를 무슨 단위로 load하고 store할지 정하는 방법에는 페이징 기법과 세그먼테이션 기법이 있다.\n\n<br/>\n\n## 페이징 기법  \n\n### Page와 Page frame, Swapping  \n\n![Page Pageframe](../assets/images/page_pageframe.png)    \n\n우선 페이징 기법은 위 그림과 같이 가상기억장치의 블록을 **고정 크기**로 나눈다. 이 블록을 **Page** 라고 부르며, 프로그램 실행시 요구되는 블록만 주기억장치에 적재된다. 주기억장치의 메모리 역시 Page와 같은 단위의 블록으로 나뉘는데, 이 명칭을 **Page frame** 이라고 한다.   \n주기억장치에 모든 작업이 상주하지 않기 때문에 프로그램 실행 중 필요한 부분만 교체할 수 있다. 이를 **Swapping** 이라고 한다.   \n\n<br/>\n\n### Page mapping - Page fault\n\nPage mapping 과정을 위해서는 주기억장치에 **Page table** 이 생성된다.(때문에 Page의 크기가 작을수록 더 많은 주기억장치의 메모리가 낭비된다.) Page table은 Page의 번호, Page Frame의 시작주소 등이 저장되어있다.  \nPage frame에 적재되는 Page가 교체되거나 Page fault가 발생할 때마다 Page Table은 갱신된다.    \n\n**Page fault** 는 프로그램에서 필요로 하는 Page가 주기억장치에 있지 않는 경우에 발생하는 현상이다. Page fault가 발생하면 Page를 찾아 mapping하고 Page Table이 갱신되는 일이 발생된다. 이러한 현상을 줄이기 위해서 Page frame의 크기를 늘릴 수 있다.\n\n<br/> \n\n### Thrashing\n\n너무 많은 Page fault 현상으로 페이지 교체 시간이 프로세스 수행 시간보다 많은 경우를 말한다. Thrashing이 발생하면 CPU 이용률이 급격히 감소하므로 이를 방지하기 위해 다중 프로그래밍의 정도를 낮추거나 Page frame의 크기를 늘려야 한다.  \n\n<br/>\n\n### 내부단편화\n\n프로그램의 크기가 30k이고, 각 page의 고정 크기가 4k라고 한다면 마지막 page의 실질적 크기는 2k가 될 것이다. 따라서 마지막 page가 주기억장치에 적재될 때 2k만큼의 **내부단편화**가 발생된다. 즉 필요한 공간보다 더 큰 메모리가 할당되어 불필요하게 메모리가 낭비되는 현상을 내부단편화라고 한다. 이를 해결하기 위해 page를 작게 만들 수도 있지만 위에서 언급했듯이 page를 무조건 작게 만드는 것이 능사는 아니다.   \n\n<br/>\n\n## 세그먼테이션 기법\n\n세그먼테이션 기법은 페이징 기법과 달리 프로그램을 기능별로 분할하는 것을 말한다. 또한 주기억장치는 구분하지 않고, 전체를 비연속적으로 할당받는다. 따라서, 페이징 기법이 프로그램을 물리적으로 분할한 개념이라면 세그먼테이션은 논리적으로 분할한 개념이다.    \n\n![segmentation](../assets/images/segmentation.png)  \n\n### Seg fault, 외부 단편화\n\n세그먼테이션 기법에서는 세그먼트 길이에 맞는 주기억장치의 영역을 할당받지 못한 경우 해당 프로그램이 다른 프로그램의 영역을 침범하는 **Seg fault**가 발생할 수 있다.    \n\n또한 고질적인 문제로 **외부단편화**가 발생할 수 있다. 위 그림에서 `B-1`의 크기가 6K,남은 공간이 3K라고 가정해보자. `B-1`의 프로세스가 끝나고 메모리를 해제하면 주기억장치에는 `A-1 / 빈공간(6k) / B-3 / 빈공간(3k)`가 있을 것이다. 여기에 7k 크기의 프로세스가 들어오려고 한다면, 총 공간은 9k지만 각 공간이 7k보다 작기 때문에 적재될 수 없다. 이런 현상을 외부 단편화라고 한다. 이를 해결하기 위해 `통합` 또는 `압축`을 할 수 있다.   \n  \n다음의 그림과 같이, 통합은 빈 공간의 주소가 인접한 경우 하나로 합치는 방법이고 압축은 프로세스의 재배치를 통해 모든 빈 공간을 하나로 합치는 방법이다. \n\n![coalescing](/assets/images/coalescing.png)  \n![compaction](/assets/images/compaction.png)\n   \n\n\n#### Reference\n[특수기억장치 및 기억장치의 분류](http://junhojohn.blogspot.com/2018/11/blog-post_12.html)"
  },
  {
    "path": "CS/플로이드-와샬-알고리즘.md",
    "content": "# 플로이드 와샬 알고리즘(Floyd Warshall Algorithm)\n\n플로이드 알고리즘이라고도 많이 부른다. 모든 정점의 쌍에 대한 최단 경로의 길이를 알아야 하는 경우 사용된다. 즉 그래프에서 나올 수 있는 최단 경로를 모두 채워야 하는 경우이다.\n\n한 정점(vertex; 노드)에서 다른 정점으로 가는 최단거리의 합이 가장 적은 곳을 구하여 가장 좋은 입지를 구하는 데 사용할 수 있을 것이다. 또한, 두 개의 임의 지점에서 뭔가(패킷과 같은)를 전달할 때 걸리는 최대 시간을 구할 때 사용할 수도 있다. 또한, 가장 효과적인 출발지점을 찾기 위해 특정 정점에서 도착할 수 있는 모든 정점을 찾아내는 데 사용할 수도 있다.\n\n> 여기서 모든 정점에 대해 각 정점에서 갈 수 있는 정점의 갯수를 계산하는 것을 추이적 폐포(transitive closure)를 찾는 것이라 할 수 있다. 추이적은 원소의 원소를 대상으로한다는 것이고, 폐포는 그 집합을 포함하면서 그 성질을 만족시키는 가장 작은 대상이다. 즉 원소의 원소를 포함하는 가장 작은 집합이라는 것인데, 도착할 수 있는 불필요한 경우의 수를 모두 걷어내고 최단거리만 포함한 최소화 된 집합을 유지할 수 있다. \n\n위에서 나온 예시들은 모든 정점에서 다익스트라 알고리즘을 각각 호출하여 풀이할 수도 있지만, 플로이드 와샬 알고리즘을 사용하면 매우 간단하게 풀이할 수 있다.\n\n모든 칸을 채우는 개념이기 때문에 인접 행렬(adjacency matrix)을 사용하는 것이 좋다. 표현하거나 생각하기도 쉽고, 어차피 모든 칸을 채워야 하기 때문에 공간이 낭비되는 것도 아니다. 아래는 플로이드 와샬의 결과로 나온 인접 행렬이다.\n| 1    | 2    | 3    | 4    | 5    |\n| ---- | ---- | ---- | ---- | ---- |\n| 0    | 2    | 3    | 1    | 4    |\n| 12   | 0    | 15   | 2    | 5    |\n| 8    | 5    | 0    | 1    | 1    |\n| 10   | 7    | 13   | 0    | 3    |\n| 7    | 4    | 10   | 6    | 0    |\n\nrow가 출발지고 column이 도착지다. 위의 그래프를 참고하여 1번에서 출발하여 4번에 도착하는 최소 거리는 1임을 알 수 있다.\n\n## 구현\n\n### 초기화\n\n```java\n\nint[][] weight = new int[n][n];\n\n// 최댓값으로 초기화\nfor (int i = 0; i < n; i++) {\n    for (int j = 0; j < n; j++) {\n        int[i][j] = i != j ? MAX : 0;\n    }\n}\n```\n\n인접 행렬로 가중치 그래프를 만든다. 정점 사이에 간선(edge)이 없는 경우(이동이 불가능한 경우)는 `MAX`로 초기화한다. 그래프의 지름이 초기화한 `MAX`보다 작을 경우 해당 부분은 무시된다. 예를 들어, int의 최댓값으로 초기화하면 가장 먼 거리(지름), 즉, 나올 수 있는 거리의 최댓값이 int의 최댓값 미만이어야 한다.\n\n> 그래프에서 가장 먼 두 정점 사이의 거리를 지름이라고 한다.\n\n> `MAX`는 최댓값 + 1로 설정해야 한다. 최댓값과 똑같이 설정하면 간선이 있는 것으로 판단하게 된다.\n\n> int를 사용할 경우 `Integer.MAX_VALUE/2` 이하의 값을 최댓값으로 사용할 수 있다. `k`를 거치는 경우 두 값을 더하기 때문에 int 최댓값을 사용하면 안 된다. [그래프 완성하기](#그래프-완성하기)를 보고 다시 보면 이해가 될 것이다.\n\n```java\nint[][] edges = ...; // edges[n][0] 은 시작점, [1]은 도착점, [2]는 가중치이며, 충분한 데이터가 들었다고 가정한다.\n\n// 가중치 옮기기\nfor (int i = 0; i < edges.size(); i++) {\n    int x = edges[i][0];\n    int y = edges[i][1];\n    int curWeight = weight[x][y];\n    int newWeight = edges[i][2];\n    \n    weight[x][y] = newWeight < curWeight ? newWeight : curWeight;\n}\n```\n\n가중치 그래프가 만들어졌으면 가지고 있는 정점이나 간선의 정보를 토대로 가중치를 옮긴다. 이미 가중치 그래프가 있다면 생략한다.\n\n### 그래프 완성하기\n\n우선 n번만큼 반복한다. 0부터 n-1까지 증가하는 변수 `k`를 중간 정점의 후보로 사용한다. k 번째 반복일 경우 `k`를 지나가는 경로의 가중치 합과 기존에 계산해둔 가중치 중 큰 값을 선택한다. \n\n>   **예시**\n>\n>   만약 `k`가 3이고 `i`와 `j`가 각각 1, 5일 경우, 정점3을 거쳐 가는 경로와 바로 가는 경로를 비교한다. 즉, `weight[1][3]`를 거쳐 `weight[3][5]`로 가는 경로의 가중치 합과 `weight[1][5]`의 가중치 합 중 작은 값을 선택한다.\n\n```java\nfor (int k = 0; k < n; k++) {\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < n; j++) {\n            if (weight[i][k] + weight[k][j] < weight[i][j]) {\n                weight[i][j] = weight[i][k] + weight[k][j];\n            }\n            /* 위의 조건문은 아래와 같다\n             * weight[i][j] = Math.min(weight[i][k] + weight[k][j], weight[i][j]);\n             */\n        }\n    }\n}\n```\n\n어떻게 두 개의 경로만 계속 비교하여 모든 그래프를 완성할 수 있는지 의문이 들 수 있는데, 위에서 들었던 예시에서 봤던 `k`가 3인 경우는 `k`가 1과 2였을 때, 그래프를 한 바퀴 순회하며 정점1과 정점2를 거쳐 가는 경우의 최솟값으로 채워져 있는 상태이다. 가령, `k`가 3이고 `i`가 5, `j`가 4인 경우, 정점5에서 정점3을 거쳐 정점4로 가는 경우를 확인한다. 이때, 정점5에서 정점3으로 가는 가중치의 합이 가장 낮은 경로가 정점5에서 정점1, 정점1에서 정점2를 거쳐 가는 것이라면 `k`가 1이었을 때, 그리고 2였을 때 이미 반영되어 있다.\n\n![플루이드와샬 설명](https://raw.githubusercontent.com/Dae-Hwa/Dae-Hwa.github.io/master/data/blog/post/2021-02-28--%ED%94%8C%EB%A1%9C%EC%9D%B4%EB%93%9C-%EC%99%80%EC%83%AC-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-floyd-warshall-algorithm/%ED%94%8C%EB%A1%9C%EC%9D%B4%EB%93%9C%EC%99%80%EC%83%AC01.png)\n\n간단히 정리해보면, A에서 B까지의 가장 빠른 경로는 A에서 B로 바로 가는 것 혹은 A에서 k로 가는 가장 빠른 경로와 k에서 B로 가는 가장 빠른 경로를 합친 것이다. 반대로 말하면 A에서 B로 가는 경로보다 빠른, 정점 `k`를 지나는 경로가 있어야 경로가 달라진다.\n\n어려운 문제를 간단하게 나누어 풀기 때문에 동적 프로그래밍(dynamic programming)으로 분류되기도 한다. 그리디(greedy)라 생각할 수도 있는데 각 정점에서 가장 빠른 경로를 찾는 것이 아니라, 전체를 고려하여 최적의 경로를 찾아내는 것이기 때문에 그리디가 아닌 동적 프로그래밍이다.\n\n## [다익스트라 알고리즘(Dijkstra Algorithm)](https://ko.wikipedia.org/wiki/%EB%8D%B0%EC%9D%B4%ED%81%AC%EC%8A%A4%ED%8A%B8%EB%9D%BC_%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98)과 비교\n\n다익스트라 알고리즘 또한 가중치가 있는 그래프에서 최단 거리를 구하는 알고리즘이다. 다익스트라 알고리즘은 모든 간선의 최단 거리가 아닌 한 정점에서 도착점까지의 최단 거리를 구한다. 해당 경우는 다익스트라 알고리즘이 빠르지만, 앞서 말했듯, 한 정점에서 특정 도착점까지의 최단 거리를 구하는 것이다. 따라서 플로이드 와샬을 사용할 때처럼 모든 경로를 채워야 한다면, 각 정점에서 다익스트라를 계속해서 실행해야 하므로 해당 경우는 플로이드 와샬이 효과적이다.\n\n또한, 다익스트라 알고리즘은 그리디 기반이기 때문에 음의 가중치가 있는 그래프의 경우는 판단하지 못한다. 반면, 플로이드 와샬은 음의 가중치가 있는 그래프에서도 사용 가능하며, 음수 사이클도 판단할 수 있다. 음의 사이클이 생기면 `i==j`의 경로가 변하기 때문에 해당 결과가 나오면 음의 사이클이라 판단할 수 있다.\n\n---\n\n#### References\n\n- [플로이드-워셜 알고리즘](https://ko.wikipedia.org/wiki/%ED%94%8C%EB%A1%9C%EC%9D%B4%EB%93%9C-%EC%9B%8C%EC%85%9C_%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98)\n\n- [Programming Challenges: 알고리즘 트레이닝 북](https://www.hanbit.co.kr/store/books/look.php?p_code=B5937184860)\n"
  },
  {
    "path": "CSS/CJK.md",
    "content": "# CJK\n\n실무에서 은근히 신경 쓰이면서 잘 모르고 있던 것을 발견하여 알아보려고 한다. \n\n대부분의 사이트에서 텍스트가 많은 경우는 드물다. 그렇기 때문에 내가 지정한 영역 안에서 나오는 텍스트의 넘치는 부분을 무심히 구글링하여 CSS로 처리를 하거나 신경 쓰지 않고 있던 부분이다.\n\n그러나 이 부분은 **CJK**라 불리는 것의 차이를 말하는 것과 동일하다.\n\n먼저 생소한 단어인 CJK에 대해서 먼저 알아보자.\n\nW3C 문서에서는 중국어, 일본어, 한글을 통칭하여 CJK(Chinese, Japanes, Korean의 약자)라 지칭하고 있다.\n\n> 왜 중국, 일본, 한국 순인지는 모르지만, K가 앞에 있으면 좋았을 텐데 우리나라의 영향력을 보여주는 부분 같아 아쉽다.\n\n그리고 CJK를 제외한 나머지를 통칭하여 non-CJK(숫자, 영어, 베트남어 등)라 지칭하자.\n\n그렇다면 본론으로 돌아가서 왜 CJK와 non-CJK를 분리하게 된 이유는 두 가지의 따라서 **단어 분리 방법**이 달라지기 때문이다.\n\n## `word-break`와 `overflow-wrap`\n\n두 CSS 속성은 주로 줄 바꿈을 위해서 사용한다. 각각의 속성이 무엇인지 간단하게 살펴보면,\n\n- word-break : 단어의 분리를 어떻게 할 것인지 결정한다.\n  - (공백/띄어쓰기) 스터디가·좋아요\n  - (음절) 스·터·디·가·좋·아·요\n- overflow-wrap : 박스의 가로 영역을 넘친 단어 내에서 임의의 분리 여부를 결정한다.\n\n<p align=\"center\">\n  <img width=\"600\" alt=\"overflow-wrap\" src=\"https://user-images.githubusercontent.com/24274424/80282842-9ed24280-874e-11ea-93a8-713f3243eff1.png\">\n</p>\n\n위의 두 속성은 역할이 다르지만 줄 바꿈을 위해 필요한 상황에 따라 선언하며, 또한 조합하여 선언한다.\n\n## `word-break` 속성\n\n줄 바꿈은 허용된 중단점에서 수행되는 것이며, 모든 속성이 기본값이라는 전제하에 줄 바꿈은 대부분의 non-CJK의 경우 공백(띄어쓰기), CJK의 경우 음절로 구분된다.\n\n### 속성값\n\n- normal\n- break-all\n- keep-all(IE에서는 계속 지원하였으나 webkit에서는 15년 6월부터 지원)\n\n> [W3C의 word-break](https://www.w3.org/TR/css-text-3/#word-break)\n\n#### 예제\n\n원본\n\n```txt\n스터디가 좋아요 这是一些汉字 and some Latin و کمی نوشتنن عربی และตัวอย่างการเขียนภาษาไทย\n```\n\n`word-break: normal`\n\n```txt\n스·터·디·가·좋·아·요·这·是·一·些·汉·字,·and·some·Latin·و·کمی·خط·عربی·และ·ตัวอย่าง·การเขียน·ภาษาไทย\n```\n\n`word-break: break-all`\n\n```txt1212\n스·터·디·가·좋·아·요·这·是·一·些·汉·字·a·n·d·s·o·m·e·L·a·t·i·n·و·ﮐ·ﻤ·ﻰ·ﺧ·ﻁ·ﻋ·ﺮ·ﺑ·ﻰ·แ·ล·ะ·ตั·ว·อ·ย่·า·ง·ก·า·ร·เ·ขี·ย·น·ภ·า·ษ·า·ไ·ท·ย\n```\n\n`word-break: keep-all`\n\n```txt\n스터디가·좋아요·这是一些汉字·and·some·Latin·و·کمی·خط·عربی·และ·ตัวอย่าง·การเขียน·ภาษาไทย\n```\n\n### 단어의 분리는 CJK, non-CJK에 따라 다르다.\n\n| |normal(기본값)|break-all|keep-all|\n|-|------------|---------|--------|\n|non-CJK|공백(띄어쓰기, 하이픈'-')|음절|공백(띄어쓰기, 하이픈'-')|\n|CJK|음절|음절|공백(띄어쓰기, 하이픈'-', 그 외 기호|\n\n**하이픈도 공백과 같이 인식을 한다는 것과 `keep-all`에서 CJK에서 기호들이 된다는 것에 주의를 해야 한다.**\n\n## `overflow-wrap` 속성\n\n넘친 단어를 대상으로 줄 바꿈을 하고 싶다면, `overflow-wrap` 속성의 값을 바꾸면 된다. 넘친 단어의 분리는 음절에서 발생하며 `white-space` 속성이 기본값(`normal`)일 때만 적용된다.\n\n> 이전에는 `word-wrap` 속성이라고 불렸으나 CSS3부터는 `overflow-wrap`으로 변경되었다.\n\n### 속성값\n\n- normal\n- break-word\n\n#### 예제\n\nnormal\n\n<p align=\"center\">\n  <img width=\"600\" alt=\"over-flow_normal\" src=\"https://user-images.githubusercontent.com/24274424/80283841-b9f48080-8755-11ea-9dc6-686388bbb693.png\">\n</p>\n\nbreak-word\n\n<p align=\"center\">\n  <img width=\"600\" alt=\"over-flow_break-word\" src=\"https://user-images.githubusercontent.com/24274424/80283884-f7590e00-8755-11ea-95d5-3fe3b57dba5e.png\">\n</p>\n\n### 줄바꿈은 CJK, non-CJK에 따라 다르다.\n\n|       |normal(기본값)|break-word|\n|-------|:----------:|:--------:|\n|non-CJK|단어넘침 O|단어넘침 X|\n|CJK    |단어넘침 X|단어넘침 X|\n\n\n\n## 그래서 우리는 어떻게 해야하나?\n\n<p align=\"center\">\n  <img width=\"400\" alt=\"CJK-wrap\" src=\"https://user-images.githubusercontent.com/24274424/80282603-48183900-874d-11ea-8c01-a484718dfb67.jpeg\">\n</p>\n\n참고로 오타가 있는데 `break-all`이 아니라 `break-word`이다.\n\n> [참고 - MDN_overflow-wrap](https://developer.mozilla.org/ko/docs/Web/CSS/overflow-wrap)\n\n#### Reference\n\n- [word-break 속성과 word-wrap 속성 알아보기](https://wit.nts-corp.com/2017/07/25/4675)\n- [overflow-wrap | CSS-Tricks](https://css-tricks.com/almanac/properties/o/overflow-wrap/)\n- [CSS Text Module Level 3](https://www.w3.org/TR/css-text-3/#word-break)"
  },
  {
    "path": "CSS/WebToMobile.md",
    "content": "# 웹으로 모바일 슬라이드 화면처럼 만들어보기\n\n<div align=\"center\">\n <image style=\"border: 1px solid black\" src=\"../assets/gif/MobileCSS.gif\"/>\n</div>\n\n오늘은 위와 같이 앱에서 보는 슬라이드 레이아웃을 웹으로 만들어보자.\n\n## 우리가 아는 슬라이드는\n\n우리가 아는 슬라이드는 네이버나 구글에서 검색하고 내리면서 보여주는 위아래 또는 좌우로 움직이는 부드러운 모양새이다.\n\nCSS 속성에 `scroll-snap-type` 이라는 것이 있다.\n이 속성은 스크롤에 대한 유형을 지정해줄 수 있는 속성으로 스냅 포인트가 있는 경우 스냅 포인트가 엄격하게 적용되는 정도를 설정할 수 있다.\n\n> [MDN - scroll-snap-type](https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-snap-type)\n\n```css\nscroll-snap-type: x mandatory;\n```\n\n위의 속성을 주게 되면 X축을 기준으로 스냅을 필수적으로 설정하는 것으로 스크롤이 완료된 경우 해당 포인트로 움직이게 된다.\n\n이를 가지고 앱에서 보이는 슬라이드 레이아웃을 구현해볼 수 있다.\n\n### 예제\n\n<div align=\"center\">\n <image src=\"../assets/gif/MobileLayout.gif\"/>\n</div>\n\n```html\n<!DOCTYPE html>\n<html lang=\"ko\">\n\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  <title>Document</title>\n</head>\n<style>\n  * {\n    box-sizing: border-box;\n    margin: 0;\n    padding: 0;\n  }\n\n  body {\n    overflow-y: hidden;\n  }\n\n  .slider {\n    font-family: sans-serif;\n    scroll-snap-type: x mandatory;\n    display: flex;\n    overflow-x: scroll;\n  }\n\n  section {\n    height: 100vh;\n    width: 100vw;\n    scroll-snap-align: center;\n    min-width: 100vw;\n  }\n</style>\n\n<body>\n  <div class=\"slider\">\n    <section id=\"slide-1\" style=\"background-color: blueviolet;\">\n    </section>\n    <section id=\"slide-2\" style=\"background-color: lightgreen;\">\n    </section>\n    <section id=\"slide-3\" style=\"background-color: lightblue;\">\n    </section>\n    <section id=\"slide-4\" style=\"background-color: rgb(226, 43, 144);\">\n    </section>\n  </div>\n</body>\n</html>\n```\n\n## 하단 Dock 내비게이터\n\n앱에서 많이 사용되고 기본이 되는 하단 Dock 내비게이터를 만들기 위해서 CodePen에 있는 오픈 소스를 가져와서 사용하였다.\n\n> [내비게이터 확인하기](https://codepen.io/milanraring/pen/qBEPzKB?utm_campaign=CSS%20Animation%20Weekly&utm_medium=email&utm_source=Revue%20newsletter)\n\n해당 소스를 가져와서 입맛에 맞게 수정하여 하단에 배치하고 꾸며보았다.\n\n<div align=\"center\">\n <image style=\"border: 1px solid black\" src=\"../assets/gif/MobileDock.gif\"/>\n</div>\n\n모든 아이콘은 HTML5에서 지원하는 SVG로 만들어졌으며 애니메이션 효과는 CSS의 Transform을 사용해서 구현되어있다. \n\n이 2가지의 방법만 사용하게 되면 사용자 친화적인 인터렉티브하게 구현 가능하다.\n\n이렇게 2가지의 모양을 만들었다면 이제 2개의 다른 화면을 연동하는 작업을 해주어야 한다.\n\n## JS를 사용해서 연결시켜주기\n\n페이지를 이동할 방법은 2가지가 있다.\n\n1. 슬라이드 움직여 Dock 맞추기\n2. Dock 메뉴를 눌러 화면 맞추기\n\n### 1. 슬라이드 움직여 Dock 맞추기\n\n슬라이드를 하여 해당 화면이 보이면 하단의 Dock 아이콘이 활성화되도록 구현하였다. 모든 화면을 `IntersectionObserver`을 사용하여 감시하고 있다가 화면의 90%가 보이게 되면 input box을 체크하여 활성화를 시켜주었다.\n\n모든 슬라이드에는 고유의 idx를 넣어주어 하단 Dock과 idx를 맞춰주었다.\n\n```js\nconst sliders = document.querySelectorAll('section')\nlet targetIdx = 1\n\nconst interselect = new IntersectionObserver((entries) => {\n  entries.forEach((entry) => {\n    if (entry.isIntersecting) {\n      if (targetIdx === parseInt(entry.target.id.split('-')[1], 10)) {\n        return\n      }\n      targetIdx = parseInt(entry.target.id.split('-')[1], 10)\n\n      const targetId = 'tab-0' + targetIdx\n      const targetEl = document.getElementById(targetId)\n\n      targetEl.checked = true\n    }\n  })\n}, {\n  threshold: 0.9\n})\n\nsliders.forEach((slider) => {\n  interselect.observe(slider)\n})\n```\n\n### 2. Dock 메뉴를 눌러 화면 맞추기\n\nDock 아이콘을 눌러서 페이지를 이동하는 기능을 구현하였다.\n\n문제가 있다면 `scroll-snap-type`을 사용하게 되면 원하는 scroll 위치를 이동하는 데 있어 문제가 발생하게 된다. 어떤 값을 주더라도 한 번에 1페이지씩 이동이 되지 않는 것이 문제가 되었다.\n\n그래서 해당 인덱스 간 비교를 하여 해당 수 만큼 반복문을 돌려서 `scrollBy`로 이동하였다.\n\n```js\nconst sliderC = document.querySelector('.slider')\nconst tabs = document.querySelector('.tabs')\nlet targetIdx = 1\n\ntabs.addEventListener('click', function (e) {\n  if (e.target.tagName === \"INPUT\") {\n    const clickedIdx = parseInt(e.target.id.split('-')[1], 10)\n    const move = clickedIdx - targetIdx\n\n    for (let index = 0; index < Math.abs(move); index++) {\n      sliderC.scrollBy(move, 0)\n    }\n\n    targetIdx = clickedIdx\n  }\n})\n```\n\n## 후기\n\n웹에서 모바일 앱과 같은 모양을 만들어서 비슷한 기능까지 넣어보았다.\n\n생각보다 디자인이 이쁘게 나오며 애니메이션이 잘 구현되어있다면, 이번에 구현된 모양보다는 더더욱 좋을 것으로 생각된다.\n\n한가지 문제가 있다면 웹에서 슬라이드를 했을 때 더뎌보이는 문제가 보였으나 모바일로 보게 되면 훨씬 부드워러진 것을 보았다.\n\n모바일용이라고 생각한다면 생각보다 좋았다. 그리고 CSS가 단순한 스타일만 아니라 더욱 멋있고 이쁘고 인터렉티브하고 만들어질 수 있는 요소라는 게 느껴졌으면 한다.\n\n아래의 참고를 보고 이 대단한 CSS를 감상해보자\n\n#### Reference\n\n- [Best Practices To Use Scrolling Effects (With Examples)](https://uxplanet.org/best-practices-to-use-scrolling-effects-with-examples-a448ac761bb9)\n- [Snowfall](https://codepen.io/shubniggurath/full/WgJZJo?utm_campaign=CSS%20Animation%20Weekly&utm_medium=email&utm_source=Revue%20newsletter)\n- [Push to Hide](https://codepen.io/eliortabeka/pen/wXwPeb?utm_campaign=CSS%20Animation%20Weekly&utm_medium=email&utm_source=Revue%20newsletter)\n- [CSS Pentagonal Bipryamid Gallery (Hover to navigate)](https://codepen.io/jh3y/pen/PowLmMX?utm_campaign=CSS%20Animation%20Weekly&utm_medium=email&utm_source=Revue%20newsletter)\n- [Card Hover Animation (Cookie Run)](https://codepen.io/richard_w_here/pen/eYmXZMN?utm_campaign=CSS%20Animation%20Weekly&utm_medium=email&utm_source=Revue%20newsletter)\n- [Insta-hearts](https://codepen.io/chrisgannon/details/BaNyWyd?utm_campaign=CSS%20Animation%20Weekly&utm_medium=email&utm_source=Revue%20newsletter)\n- [Cut/Copy/Paste](https://codepen.io/cobra_winfrey/full/abzqxVr?utm_campaign=CSS%20Animation%20Weekly&utm_medium=email&utm_source=Revue%20newsletter)\n- [Animated Night Hill Illustration - Pure CSS](https://codepen.io/aybukeceylan/pen/OJJzXde?utm_campaign=CSS%20Animation%20Weekly&utm_medium=email&utm_source=Revue%20newsletter)\n"
  },
  {
    "path": "CSS/safe-area.md",
    "content": "# Safe-Area(IOS 11 이상 대응하기)\n\n## 안전영역(Safe-Area)이란?\n\n안전영역(Safe-Area)이라는 말은 TV에서 처음 도입된 개념이라고 한다.\n\nTV 해상도 비율이 다양해지면서 영상에서 타이틀, 자막 등의 필수 콘텐츠 노출을 보장할 수 있는 영역이다.\n\n더욱 자세한 정보는 아래의 링크를 추가하였습니다.\n\n> [Caption/Title Safe Area](http://www.indefilms.net/html/title_safe_area.html)\n\n위에서 언급한 것 같이 원래는 TV에서 쓰이는 개념이었지만 프론트엔드 개발자의 입장에서 찾아보며 이해하는 시간을 가지려고 한다.\n\n처음부터 이 개념을 알고 찾아본 것이 아녔다.\n\n회사에서 웹을 개발하다 보면 다양한 Vendor들의 화면을 그리거나 작동하는 방식의 차이로 인해서 이런저런 일을 많이 겪지만, 이번 일은 처음이라 기록으로 남기려고 한다. \n\n우리나라에서도 아이폰 유저가 많은 비율을 차지하고 있으며 그중에는 많은 버전의 아이폰이 있지만, IOS 11과 함께 출시된 아이폰 X를 기준으로 노치 디자인이 생기고 홈 버튼이 존재하지 않는다.\n\n모든 사건과 사고는 혁신에서 찾아오는 법이다. 애플에서 사건을 만들어 주었다.\n\n<center>\n  <img src=\"https://user-images.githubusercontent.com/24274424/82733281-be5c8b00-9d4d-11ea-8855-f1ba7217b72d.png\" alt=\"Iphone 11\" width=\"200\">\n</center>\n\n> 드디어 시뮬레이터를 써먹은 나의 MAC\n\n정말 이쁘고 탈모탈모한 디자인인데, 문제가 하나 존재한다. 오직 프론트엔드에게만 골칫거리다.\n\n<center>\n  <img src=\"https://user-images.githubusercontent.com/24274424/82733424-94f02f00-9d4e-11ea-8fee-7e906740584d.png\" alt=\"not bad\" width=\"400\">\n</center>\n\n가만히 살펴보고 있으면 잘 나오고 있는 게 아니냐고 생각할 수 있다. 잘 생각해보면 저런 게 되어있으면 `아이텍`이라는 글자와 홈 버튼이 겹치게 되어 글자가 눌리지 않게 될 것이다.\n\n이렇게 겹치는 현상이 발생하게 된다.\n\n단순하게 그럼 아래를 공통으로 높이면 되지 않나? 라고 생각할 수 있다. 그러나 그렇게 되면 아이폰 X 이상의 유저만이 아닌 다른 유저들에게는 좋은 경험을 선사하지 못하게 될 수 있다. 특히 하단 Nav가 있는 디자인이라면 더욱더 그러하다.\n\n예시로 네이버에서는 하단에 29px이 직접 박혀있는 것을 확인하였는데 이처럼 한 것이 아이폰을 노리고 한 것인지는 모르나 저렇게 하면서 모든 Vendor를 위한 공통으로 제작하면 된다.(이 또한 좋은 방법일지도...)\n\n우리는 다른 방법으로 해결해보자.\n\n## Home Indicator\n\n앱 개발을 하시는 분들이 어떻게 부르는지 잘 모르나, 약간 찾아본 결과 하단에 있는 홈 버튼 영역을 저렇게 지칭한다고 한다.\n\nHome Indicator를 신경쓰는 웹 사이트는 많이 않다고 생각한다. 그러나 웹뷰를 가지고 서비스를 하는 기업 또는 하단 Nav를 사용하는 기업이 대상이라고 생각한다.\n\n![Area-Data](https://user-images.githubusercontent.com/24274424/82733628-067cad00-9d50-11ea-9c83-f59ed839491b.png)\n\n> 출처 : https://carrotdesign.tistory.com/entry/iPhone-X-iPhone-11의-안전영역Safe-area을-알아보자\n\n어떤 잘 하시는 분이 이쁘게 정리를 하셔서 가져왔다. 위에 사진을 보게 되면 세로 모드 가로 모드에 따라 각각의 영역이 얼마나 되는지 그림과 수치로 보여주고 있다.\n\n![Data-Table](https://user-images.githubusercontent.com/24274424/82733661-49d71b80-9d50-11ea-8409-f32e99e8c88c.png)\n\n여기서 내가 겪었던 부분은 세로 모드일 때 34pt 가로 모드일 때 21pt인 부분이다. 그러나 위에서 언급했듯이 우리는 직접 하드코딩으로 넣지 말고 다르게 넣어보자.\n\n## 해결방안\n\n우리가 해결하려는 화면이 아래와 같다고 하자. 원래는 Home Indicator만 해결해보려고 했으나 추가로 발생할 수 있는 이슈도 같이 해결해보자.\n\n<center>\n  <img src=\"https://user-images.githubusercontent.com/24274424/82733747-04ffb480-9d51-11ea-94d1-62ce8ae5b808.png\" alt=\"Test1_Port\" width=\"200\">\n  <img src=\"https://user-images.githubusercontent.com/24274424/82733751-0b8e2c00-9d51-11ea-9845-5dd1a31bc8e3.png\" alt=\"Test1_Land\" width=\"400\">\n</center>\n\n위의 사진에서 걸리는 부분이 있다. 가로 모드일 때 이상하게 좌우 흰색영역이 거슬린다. 먼저 없애주자.\n\n```html\n<meta name='viewport' content='initial-scale=1, viewport-fit=cover'>\n```\n\n간단하게 `viewport-fit=cover`를 주게 되면 해결된다. \n\n<center>\n  <img src=\"https://user-images.githubusercontent.com/24274424/82733917-3b89ff00-9d52-11ea-8503-9018251f0de9.png\" alt=\"Test2_Port\" width=\"200\">\n  <img src=\"https://user-images.githubusercontent.com/24274424/82733922-3e84ef80-9d52-11ea-8a39-df4785d4cad9.png\" alt=\"Test2_Land\" width=\"400\">\n</center>\n\n위와 같이 메타 태그의 기본값은 `auto`이다. 그러나 cover를 주게 되면 꽉 차는 화면을 가지게 된다. 그러나 여기서 보이는 문제는 header라는 글자와 footer라는 글자가 보이지 않게 된다.\n\n### `constant()`, `env()`\n\n애플이 위와 같은 문제를 해결하기 위해 제공하는 CSS 속성이 있다. \n\nIOS 11 당시 `constant()`라는 속성을 제공하였으나 IOS 11.2로 업데이트가 되면서 `env()` 속성으로 변경이 되었다. 업데이트하지 않은 만약의 경우를 생각해서 둘 다 넣어주면 된다.\n\n```css\nheader {\n  position: fixed;\n  left: 0px;\n  top: 0px;\n\n  width: 100%;\n  height: 30px;\n\n  padding-left: constant(safe-area-inset-left);\n  padding-right: constant(safe-area-inset-right);\n\n  padding-left: env(safe-area-inset-left);\n  padding-right: env(safe-area-inset-right);\n\n  background-color: green;\n}\n```\n\n```css\nfooter {\n  position: fixed;\n  left: 0px;\n  bottom: 0px;\n\n  width: 100%;\n  height: 30px;\n\n  padding-bottom: constant(safe-area-inset-bottom);\n  padding-left: constant(safe-area-inset-left);\n  padding-right: constant(safe-area-inset-right);\n\n  padding-bottom: env(safe-area-inset-bottom);\n  padding-left: env(safe-area-inset-left);\n  padding-right: env(safe-area-inset-right);\n\n\n  background-color: blue;\n}\n```\n\n각각 속성 명은 아래와 같이 4개가 된다.\n\n- `safe-area-inset-top`\n- `safe-area-inset-bottom`\n- `safe-area-inset-left`\n- `safe-area-inset-right`\n\n아이폰 X 이상의 폰이 아니라면 해당 CSS 적용되지 않는다.\n\n<center>\n  <img src=\"https://user-images.githubusercontent.com/24274424/82734049-29f52700-9d53-11ea-8f6b-a739dedf6ccd.png\" alt=\"Test3_Port\" width=\"200\">\n  <img src=\"https://user-images.githubusercontent.com/24274424/82734053-2cf01780-9d53-11ea-845c-f102470df08e.png\" alt=\"Test3_Land\" width=\"400\">\n</center>\n\n## 결과물\n\n비록 제가 적용한 부분이 아니지만, 아래와 같이 결과물이 나옵니다.\n\n<center>\n  <img src=\"https://user-images.githubusercontent.com/24274424/82734120-940dcc00-9d53-11ea-9061-d18194a988f0.png\" alt=\"Test3_Port\" width=\"200\">\n  <img src=\"https://user-images.githubusercontent.com/24274424/82734039-19dd4780-9d53-11ea-87d9-8e20cbefb51e.png\" alt=\"Test3_Land\" width=\"200\">\n</center>\n\n#### Reference\n\n- [아이폰X 안전영역(Safe Area) 대응 사례 | WIT블로그](https://wit.nts-corp.com/2019/10/24/5731)\n- [아이폰X를 생각하며 디자인하자. | 라이트브레인 블로그](http://blog.rightbrain.co.kr/?p=8499)\n- [iPhone X, iPhone 11의 안전영역(Safe area)을 알아보자.](https://carrotdesign.tistory.com/entry/iPhone-X-iPhone-11%EC%9D%98-%EC%95%88%EC%A0%84%EC%98%81%EC%97%ADSafe-area%EC%9D%84-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90)\n- [아이폰X 노치영역 대응 최적화하기 – dohoons(도훈) _(≥∇≤)ノミ☆](https://dohoons.com/blog/1468/)\n"
  },
  {
    "path": "Database/DB Connection Pool.md",
    "content": "# DB Connection Pool\n\nAPI 서버를 구동하고 있었는데, 이따금씩 Nginx `502 Bad Gateway` 오류가 났다. \n\n![1](https://user-images.githubusercontent.com/43839938/97099038-524ccd00-16c7-11eb-8cbb-439763a3599f.png)\n\n서버는 Nginx- PM2 - Node.js - MySQL로 구성돼있었는데 도대체 문제 원인이 무엇인지, 한참 찾았다. 로컬 환경에서는 추가한 node_module을 Git에서는 ignore 해줬기 때문에 실 서버에서 npm install 을 하지 않아서 생기는 문제이기도 했고, Node.js 코드 자체에 문제가 있는 경우에도 `502 Bad Gateway` 가 뜨곤했다. 그런데 이번에는 npm install도 해주고 코드에도 이상이 없는데 처음에는 잘 작동되다가 갑자기 `502 Bad Gateway` 가 뜨는 것.\n\nNginx 에러 로그, PM2 에러 로그, winston을 이용한 에러로그 확인을 모두 했으나 뾰족하게 원인을 찾기 힘들었다. 이곳 저곳 물어보다가 결국 `DB Connection Pool` 을 Release 하지 않아서 발생한 문제라는 것을 알게 됐다. \n\n구글링을 해보니 `DB Connection Pool` 문제로 인해 서버 오류가 터졌을 때 그 원인이 `DB Connection Pool` 이라는 것을 단번에 찾기 어렵다는 글이 많았다. ~~(휴 발견해서 다행 ㅋ)~~\n\n그래서 정리해보려 한다. `DB Connection Pool` 은 무엇이며 `Pool`을 `Release` 해준다는 것은 어떤 의미인가? 만약 `Pool`은 여러 개 생성만 하고 `Release`를 하지 않으면 어떤 문제가 발생하는가? 알아보자.\n\n# DB Connection Pool 이란?\n\n### Single Connection\n\n`Single Connection`을 사용할 경우 해당 `Connection`에 여러 `Statement`를 사용하게 된다. 여러 `Statement` 중 한 `Statement`에서 예외가 발생하면 `Rollback`을 수행해야 하는데 `Single Connection`의 경우는 해당 `Connection`을 통해 생성된 다른 모든 `Statement`의 작업도 `Rollback`되게 된다. (원치 않는 작업이 발생한다)\n\n> [npm mysql2](https://www.npmjs.com/package/mysql2#using-connection-pools)\n\n```jsx\n// get the client\nconst mysql = require('mysql2');\n \n// create the connection to database\nconst connection = mysql.createConnection({\n  host: 'localhost',\n  user: 'root',\n  database: 'test'\n});\n \n// simple query\nconnection.query(\n  'SELECT * FROM `table` WHERE `name` = \"Page\" AND `age` > 45',\n  function(err, results, fields) {\n    console.log(results); // results contains rows returned by server\n    console.log(fields); // fields contains extra meta data about results, if available\n  }\n);\n \n// with placeholder\nconnection.query(\n  'SELECT * FROM `table` WHERE `name` = ? AND `age` > ?',\n  ['Page', 45],\n  function(err, results) {\n    console.log(results);\n  }\n);\n```\n\n참고> 위 예시는 날 쿼리를 그대로 사용했기 때문에 [SQL Injection](https://ko.wikipedia.org/wiki/SQL_%EC%82%BD%EC%9E%85)의 위험이 있을 수 있다. 그래서 [Prepared Statement](https://www.npmjs.com/package/mysql2#using-prepared-statements)라는 것을 대신 사용한다. 이유는 [이 사이트](https://stackoverflow.com/questions/8263371/how-can-prepared-statements-protect-from-sql-injection-attacks)를 참조.\n\n### 단순 Multiple Connection\n\n![2](https://user-images.githubusercontent.com/43839938/97099039-537dfa00-16c7-11eb-8b24-6f9b9bbe3fa7.png)\n\n\n위의 문제를 해결하려면 클라이언트의 각 요청에 대해 개별 `Connection`을 사용해야 한다. 하지만 다수의 클라이언트가 요청을 하는 경우, 매번 `Connection`객체를 각각 생성해야 하기 때문에 생성에 대한 소요 시간이 많아진다. \n\n### Connection Pool\n\n![3](https://user-images.githubusercontent.com/43839938/97099041-54af2700-16c7-11eb-8b01-b4971dafc7bf.png)\n\n`Connection Pool`은 `단순 Multiple Connection` 의 문제를 해결할 수 있다. `Connection Pool`은 미리 일정량의 `Connection` 객체를 생성하고 `Pool`이라는 공간에 저장한다. DB에 `Connection`해야하는 클라이언트 요청이 들어올 때, 해당 `Pool`에 가서 이미 생성되어 있고, 사용가능한 `Connection`을 찾아 DB에 접근한다. \n\nnpm mysql2 문서에는 다음과 같이 설명되어 있다. \n\n> Connection pools help **reduce the time** **spent connecting to the MySQL server by reusing a previous connection**, leaving them open instead of closing when you are done with them.\n>\n> This improves the latency of queries as you avoid all of the overhead that comes with establishing a new connection.\n\n### Connection Release\n\n이 `Connection`은 사용 이후 반드시 `Pool`에 다시 반납해줘야 한다. `Pool`에 있는 `Connection`을 재활용해야하기 때문이다. 가령, `Pool`에서 생성가능한 `Connection`의 개수가 최대 4개라고 할 때, `Release`하지 않은 상태에서 계속 `Connection`요청이 들어온다면, 5번째 요청 부터는 제대로 응답받지 못할 것이다. `Pool`에서 이미 4개의 `Connection`이 사용 중이고, 더 이상 사용가능한 `Connection`이 없어서 대기 상태에 빠지기 때문이다.\n\n실제 실행 결과는 [이 포스트](http://blog.naver.com/PostView.nhn?blogId=pjt3591oo&logNo=221505148267&parentCategoryNo=&categoryNo=55&viewDate=&isShowPopularPosts=false&from=postView)의 `Connection limit` 부분을 참조하시라.\n\n```jsx\n...\n\n\n\ntry {\n    const connection = await pool.getConnection(async conn => conn);\n    try {\n\n        const Query;\n        const Params;\n\n        const [ResultSet] = await connection.query(\n            Query,\n            Params\n        );\n\n    } catch (err) {\n        connection.release(); // 다음과 같이 사용 이후에는 release를 해줘야 한다.\n        return res.json({ isSuccess: false, code: 500, message: \"서버 오류\" });\n    }\n} catch (err) {\n    return res.json({ isSuccess: false, code: 501, message: \"서버 오류\" });\n\n```\n\n`Connection`연결 이후 **잘 사용 되고 나서도** `Release`를 해줘야 하지만, **Error가 발생했을 때도** 반드시 `Release`를 해줘야 한다. ( 나는 이 모든 부분을 고려하지 못해서 결국 `502 Bad Gateway` 문제가 발생했었다;)\n\n## Pool에서 Connection의 최대 개수는 몇 개가 적당한가?\n\n다음은 8개의 `Connection`을 최대로 활용할 수 있을 때 4개는 사용 중이고 4개는 대기 중인 상태의 `Connection Pool`의 상태이다.\n\n![4](https://user-images.githubusercontent.com/43839938/97099042-5547bd80-16c7-11eb-8a1c-64ead16af993.png)\n\n\n![image](https://user-images.githubusercontent.com/43839938/97099080-db640400-16c7-11eb-932c-d932ac936877.png)\n\n\n위 4개 속성에 대한 조건은 논리적으로 따져서 결정하면 되지만, (가령, `maxIdle`은 `minIdle` 보다 작으면 안된다 등) 4개 속성을 모두 동일한 개수로 설정해도 무방하다. 중요한 건, `maxActive`의 값 자체이다. \n\n`Connection`의 개수를 크게 하면 메모리 소모가 크고 적게 하면 `Connection`이 많이 발생할 때 대기 시간이 발생하기 때문에 `Connection Pool`의 `Connection`개수는 어플리케이션의 요구사항과 사용자의 수, 서버 메모리, 서버 부하 등의 여러 요소를 고려해서 결정해야 한다.\n\n---\n#### Reference\n- [NPM mysql2](https://www.npmjs.com/package/mysql2)\n- [Commons DBCP 이해하기](https://d2.naver.com/helloworld/5102792)\n- [DB Connection Pool에 대한 이야기](https://www.holaxprogramming.com/2013/01/10/devops-how-to-manage-dbcp/)\n- [Node.js mysql 사용부터 pool 관리까지](http://blog.naver.com/pjt3591oo/221505148267)\n"
  },
  {
    "path": "Database/Query Builder ( Knex.js).md",
    "content": "# Query Builder - Knex.js\n\nREST API를 설계 /  구현할 때, 각 API에 해당하는 SQL문을 직접 만들어서 코드에 넣곤 했다. 가령, **회원정보 조회 API** (`GET` `/users`)라면 `Select를 이용한 Query`를, **회원정보 수정 API** (`PATCH` `/user/{userNo}`)라면 `Update를 이용한 Query`를 코드에 넣었다. 하지만 **조회** 시에 몇 가지 필터를 건다든가 **수정**을 할 때 매번 넘겨주는 컬럼의 종류 / 개수가 다른 경우에는 그에 맞게 Query를 변경해줘야 하는 이슈가 생긴다. 물론 각각의 조건을 걸어서 그에 맞는 Query를 작성할 수 있지만, 이를 좀 더 수월하게 해주는 Query Builder를 사용하기로 했다. \n\n현재는 Node.js로 API를 구성하고 있기 때문에 Node.js에서 많이 사용되는 Query Builder를 찾았다. 바로 `[Knex.js](http://knexjs.org/)`라는 라이브러리이다.\n\n> **Knex.js** (pronounced /kəˈnɛks/) is a \"batteries included\" SQL query builder for **Postgres, MSSQL, MySQL, MariaDB, SQLite3, Oracle, and Amazon Redshift** designed to be flexible, portable, and fun to use. It features both traditional node style callbacks as well as a promise interface for cleaner async flow control, a stream interface, full featured query and **schema builders**, **transaction support (with savepoints)**, **connection pooling** and standardized responses between different query clients and dialects.\n\nKnex.js는 다양한 DBMS(**Postgres, MSSQL, MySQL, MariaDB, SQLite3, Oracle, and Amazon Redshift**)를 지원하고 있고 단순 Query 생성 뿐만 아니라 **schema builder, transaction, connection pooling** 등의 기능도 지원하고 있다. 자세한 내용은 [공식홈페이지](http://knexjs.org)를 살펴보자.\n\n우선 프로젝트에 `npm install knex —save` 로 knex 모듈을 추가하고 다음과 같이 DB에 연결한다. \n\n```jsx\n// knex.js\n\nconst knex = require('knex')({\n    client: 'mysql2',\n    connection: {\n        host: '',\n        user: '',\n        password:'',\n        database: ''\n    }\n}) //  DB 구성에 맞게 설정하자.\n\nmodule.exports = {\n    knex: knex\n};\n```\n\n위의 예시에서 mysql 모듈을 사용하면 다음과 같은 오류 발생하여 [구글링](https://www.inflearn.com/questions/3637)을 해보니 mysql2 모듈을 사용하여 해결할 수 있었다.\n\n```\nError: ER_NOT_SUPPORTED_AUTH_MODE: Client does not support authentication protocol requested by server; consider upgrading MySQL client\n```\n\n예제를 살펴보자. 우선 나는 **일부 수정을 위한 API** 에서 클라이언트가 어떤 컬럼을 수정하고 싶은지 모르는 상태이다. (가령 회원정보 수정 API라면 name, age, birth 등) 하지만 몇 개를 수정하든 상관없이 넘겨 주는 컬럼 값들에 대해서 수정할 수 있는 Query를 만들기 위해 Knex.js를 사용하고 싶었다. 이 해결의 실마리는 다음 코드에서 살펴볼 수 있다.\n\n```jsx\nknex('books')\n  .where('published_date', '<', 2000)\n  .update({\n    status: 'archived',\n    thisKeyIsSkipped: undefined\n  })\n// Outputs:\nupdate `books` set `status` = 'archived' where `published_date` < 2000\n```\n\n`thisKeyIsSkipped: undefined`로 설정한 Query Builder의 Outputs을 보면 thisKeyIsSkipped는 Query에 들어가지 않는 것을 확인할 수 있다. 만일 이런 Query Builder를 사용하지 않고 날 Query를 일일이 만들어줘야 한다면 어떤 컬럼이 undefined인지 확인 하고 그에 해당하는 Query를 만들어 줘야 하기 때문에 코드가 복잡해질 것이다.\n\n위를 바탕으로 다음과 같이 코드를 작성하면 자잘한 일에 시간을 쏟지 않아도 된다.  \n\n```jsx\n// userController.js\n\n// Client로 부터 userAge, userName, userBirth가 있으면 받아오는 코드\n\nknex('User')\n  .where('published_date', '<', 2000)\n  .update({\n    age: userAge,\n    name: userName,\n    birth: userBirth\n  })\n```\n\n이렇게 작성하면 Client에서 age만 넘기든, age와 name을 넘기든 혹은 3가지를 다 넘기든 상관없이 undefined인 컬럼을 제외한 Query가 자동으로 생성될 것이다.\n\ntransaction의 기능도 제공하니, transaction 처리가 필요한 곳에서도 knex.js를 통해 사용할 수 있다. 다음 코드는 `Catalogues` 테이블에 Old Books를 추가하고 Old Books `Catalogues`에 속하는 책 3권을 `Books` 테이블에 넣어주는 로직을 transaction으로 처리하고 있다. \n\n```jsx\n// Using trx as a transaction object:\nknex\n  .transaction(function (trx) {\n    const books = [\n      { title: \"Canterbury Tales\" },\n      { title: \"Moby Dick\" },\n      { title: \"Hamlet\" },\n    ];\n    knex\n      .insert({ name: \"Old Books\" }, \"id\")\n      .into(\"catalogues\")\n      .transacting(trx)\n      .then(function (ids) {\n        books.forEach((book) => (book.catalogue_id = ids[0]));\n        return knex(\"books\").insert(books).transacting(trx);\n      })\n      .then(trx.commit)\n      .catch(trx.rollback);\n  })\n  .then(function (inserts) {\n    console.log(inserts.length + \" new books saved.\");\n  })\n  .catch(function (error) {\n    // If we get here, that means that neither the 'Old Books' catalogues insert,\n    // nor any of the books inserts will have taken place.\n    console.error(error);\n  });\n```\n\nawait/async 방식은 다음과 같이 사용할 수 있다.\n\n```jsx\ntry {\n  await knex.transaction(async trx => {\n\n    const books = [\n      {title: 'Canterbury Tales'},\n      {title: 'Moby Dick'},\n      {title: 'Hamlet'}\n    ];\n\n    const ids = await knex('catalogues')\n      .insert({\n        name: 'Old Books'\n      }, 'id')\n      .transacting(trx)\n\n    books.forEach(book => book.catalogue_id = ids[0])\n    await knex('books')\n      .insert(books)\n      .transacting(trx)\n\n    console.log(inserts.length + ' new books saved.')\n  })\n} catch (error) {\n  console.error(error);\n}\n```\n\n물론, 날 SQL를 작성하는 것이 Knex.js를 통한 작성보다 쉬울 때가 많다. 그 때는 날 SQL문을 사용하고 (Query Builder에서 Raw SQL도 지원한다), 날 SQL이 아닌 Query Builder가 좀 더 수월하게 코드를 작성할 경우에는 Query Builder를 사용하여 작성하면 된다.\n\n---\n#### Reference\n- [Knex.js](http://knexjs.org)\n- [nodejs와 mysql 연동 에러](https://www.inflearn.com/questions/3637)\n"
  },
  {
    "path": "Database/Types of Databases.md",
    "content": "# Types of Databases: The Right Database for the Right Service \n그동안 DB를 사용할 때는 RDB(Relational Database, 관계형 데이터베이스)만 사용했다. 어느 순간 부터 RDB와 무언가 대조되는 듯한 느낌을 주는 NoSQL DB의 존재를 알게 됐다. 이 문서에서 NoSQL이 정확히 무엇인지 언제 사용하는지(왜 존재하는지) 등을 정리하고자 한다.\n\n## NoSQL이란?\n\nNoSQL이란 No SQL, Not Only SQL 등 여러 의미로 해석되지만 현재 대다수가 Not Only SQL로 풀어내고 있다. 이는 곧 단순히 기존 RDB가 갖고 있는 특성뿐만 아니라 다른 특성들을 부가적으로 지원한다는 것을 의미한다.\n\n> 참고: SQL은 Structured Query Language의 약자로 RDB의 데이터를 관리하는 특수 목적의 프로그래밍 언어이다. 우리는 데이터베이스를 비교하는 것이다. 이 문서에서는 RDB (SQL을 사용) vs NoSQL DB를 비교한다고 생각하면 된다.\n\nNoSQL을 구체적으로 이해하기 위해 먼저 RDB가 무엇인지 살펴보자. RDB는 1970년대 탄생 이후 지금까지 수십년간 가장 많이 사용된 DB 모델이다. RDB는 데이터를 정형화된 구조(Strict Schema)에 따라 테이블(Table)에 저장하는 형식이다. 각 테이블은 관계(Relations)를 갖고 있는데 이는 RDB가 데이터의 중복을 방지하고 [참조 무결성](https://ko.wikipedia.org/wiki/%EC%B0%B8%EC%A1%B0_%EB%AC%B4%EA%B2%B0%EC%84%B1)이 보장되도록 한다. 더불어 [ACID 속성](https://ko.wikipedia.org/wiki/ACID)을 갖고 있다. 예시로는 MySQL, PostgreSQL, MariaDB, Oracle SQL, MSSQL 등이 있다.\n\n그렇다면 이런 RDB의 특성과 대비한 NoSQL의 특성은 무엇일까? NoSQL은 RDB가 갖고 있던 데이터 완결성을 조금 포기하고 **유연한 데이터 모델** / **대량의 데이터 처리** / **짧은 지연시간 (Low Latency)** 이 중요한 애플리케이션들에 적용되고 있다. AWS에서 설명하는 [RDS vs NoSQL DB 표](https://aws.amazon.com/ko/nosql/)를 살펴보자.\n\n|   | 관계형 데이터베이스  |  NoSQL 데이터베이스 |\n|---|---|---|\n|최적의 워크로드| 관계형 데이터베이스는 일관성이 뛰어난 온라인 트랜잭션 프로세싱(OLTP) 애플리케이션을 위해 설계되어 온라인 분석 프로세싱(OLAP)에 적합합니다.  | NoSQL 데이터베이스는 낮은 지연 시간의 애플리케이션을 포함한 수많은 데이터 액세스 패턴에 맞도록 설계되었습니다. NoSQL 검색 데이터베이스는 반정형 데이터에서 분석을 위해 설계되었습니다   |\n|데이터 모델|관계형 모델은 데이터를 행과 열로 구성된 테이블로 정규화합니다. 스키마는 테이블, 행, 열, 인덱스, 테이블 간 관계, 기타 데이터베이스 요소를 정확하게 규정합니다. 데이터베이스는 테이블 사이의 관계에서 참조 무결성을 실현합니다. |NoSQL 데이터베이스는 키-값, 문서, 그래프 등 성능과 규모 확장에 최적화된 다양한 데이터 모델을 제공합니다. |\n|ACID 속성|\t관계형 데이터베이스는 원자성, 일관성, 격리성 및 지속성(ACID, atomicity, consistency, isolation, and durability)의 속성을 제공합니다 1) 원자성은 완벽하게 실행하거나 혹은 전혀 실행하지 않는 트랜잭션을 필요로 합니다. 2) 일관성은 트랜잭션이 커밋되면 데이터가 데이터베이스 스키마를 준수하도록 요구합니다. 3) 격리성은 동시에 일어나는 트랜잭션들이 각기 별도로 실행되어야 함을 의미합니다. 4) 내구성은 예기치 못한 시스템 장애 또는 정전 시 마지막으로 알려진 상태로 복구하는 기능을 필요로 합니다.|NoSQL 데이터베이스는 흔히 수평으로 확장할 수 있는 보다 유연한 데이터 모델을 위해 관계형 데이터베이스의 일부 ACID 속성을 완화함으로써 조정합니다. 이로써 NoSQL 데이터베이스는 단일 인스턴스의 한계를 넘어 수평으로 확장해야 하는 사용 사례에서 높은 처리량, 낮은 지연 시간을 위한 탁월한 선택이 됩니다.|\n|성능|\t성능은 일반적으로 디스크 하위 시스템에 따라 다릅니다. 최고 성능을 달성하기 위해서는 쿼리, 인덱스 및 테이블 구조를 자주 최적화해야 합니다.|성능은 일반적으로 기본 하드웨어 클러스터 크기, 네트워크 지연 시간 및 호출 애플리케이션의 기능입니다.|\n|확장|\t관계형 데이터베이스는 일반적으로 하드웨어의 계산 성능을 높이거나 읽기 전용 워크로드의 복제물을 추가함으로써 확장됩니다.|NoSQL 데이터베이스는 일반적으로 거의 무제한적인 범위에서 일관된 성능을 제공하는 처리량 제고를 위해 분산형 아키텍처를 사용해 액세스 패턴이 확장 가능하기 때문에 분할성이 있습니다.|\n|API|데이터를 저장 및 검색하기 위한 요청은 **SQL(구조화 질의 언어)** 을 준수하는 쿼리를 사용하여 전달됩니다. 쿼리는 관계형 데이터베이스에 의해 구문 분석되고 실행됩니다.|**객체 기반 API**를 통해 앱 개발자가 데이터 구조를 쉽게 저장 및 검색할 수 있습니다. 파티션 키를 사용하면 앱에서 키-값 페어, 열 세트 또는 일련의 앱 객체 및 속성을 포함하는 반정형 문서를 검색할 수 있습니다.|\n\n\n## NoSQL의 종류\nNoSQL에는 여러 가지 종류가 있다. 여기서는 대표적인 3가지만 소개하려고 한다.\n\n![databases](https://user-images.githubusercontent.com/43839938/91643449-48637080-ea6e-11ea-8950-989d5367f716.png)\n\n\n### 1. Key-Value: DynamoDB, Redis(In-memory), Cassandra(이는 Wide Column DB로 분류되기도 함)\n#### 특징\n- 키를 고유한 식별자로 사용하는 키-값 쌍의 집합으로 데이터를 저장한다.\n- 일반적으로 키-값 데이터베이스는 관계형 데이터베이스에 비하여 페이지당 제공하는 [오버헤드](https://ko.wikipedia.org/wiki/%EC%98%A4%EB%B2%84%ED%97%A4%EB%93%9C)가 적다. (데이터 양이 많아져도 일관적인 성능을 갖는다.)\n\n#### 구조\n![key-value](https://user-images.githubusercontent.com/43839938/91649679-52f32980-eab1-11ea-8088-fcb0b23f7ff2.png)\n\n#### 사례\n- 대량의 multi-player 온라인 게임에서 각 플레이어들의 세션(레벨, 상태 등)을 관리할 때\n- 온라인 쇼핑의 장바구니를 관리할 때 (이후의 주문 트랜젝션은 RDB를 사용하는게 좋다.)\n\n\n### 2. Document Database: MongoDB, CouchDB 등\n#### 특징\n- schema 없이 임의의 property 를 추가할 수 있다. (유연한 구조)\n- 개발자들이 자신의 애플리케이션 코드에서 사용하는 것과 동일한 문서 모델 형식을 사용하여 데이터베이스에서 보다 손쉽게 데이터를 저장하고 쿼리할 수 있다. (JSON이나 XML 같은 문서 데이터를 저장할 수 있다.)\n\n#### 구조\n다음은 책들을 저장해 놓은 Document DB의 예시이다. \n```json\n[\n    {\n        \"year\" : 2013,\n        \"title\" : \"Turn It Down, Or Else!\",\n        \"info\" : {\n            \"directors\" : [ \"Alice Smith\", \"Bob Jones\"],\n            \"release_date\" : \"2013-01-18T00:00:00Z\",\n            \"rating\" : 6.2,\n            \"genres\" : [\"Comedy\", \"Drama\"],\n            \"image_url\" : \"http://ia.media-imdb.com/images/N/O9ERWAU7FS797AJ7LU8HN09AMUP908RLlo5JF90EWR7LJKQ7@@._V1_SX400_.jpg\",\n            \"plot\" : \"A rock band plays their music at high volumes, annoying the neighbors.\",\n            \"actors\" : [\"David Matthewman\", \"Jonathan G. Neff\"]\n        }\n    },\n    {\n        \"year\": 2015,\n        \"title\": \"The Big New Movie\",\n        \"info\": {\n            \"plot\": \"Nothing happens at all.\",\n            \"rating\": 0\n        }\n    }\n]\n```\n#### 사례\n- 카탈로그 정보를 저장할 때: 가령 전자 상거래 애플리케이션에서 제품마다 일반적으로 속성 수가 다른데, RDB에서는 모든 속성을 고려해야 했다면(RDB에서 수천 개의 속성을 관리하는 것은 비효율적이며 읽기 성능에 영향을 미친다.) Document DB는 각 제품에 맞게 속성을 부여할 수 있다.\n\n### 3. Graph Database: AllegroGraph, neo4j 등\n#### 특징\n- 그래프 데이터베이스는 node를 사용하여 데이터 엔터티를 저장하고 edge로는 엔터티 간의 관계를 저장한다.\n- 노드 간의 관계가 쿼리 시간에 계산되지 않고 데이터베이스에 유지되기 때문에 조인 또는 관계를 순회하는 것이 매우 빠르다.\n- 직관적인 쿼리를 짤 수 있다.\n\n#### 구조\n동일한 스포츠를 follow한 다른 사람이 구매한 제품을 다른 사용자에게 추천 할 수 있다. 또는 친구가 있지만 아직 서로를 알지 못하는 사람을 식별한 다음 친구 추천을 할 수 있다. \n![graph](https://user-images.githubusercontent.com/43839938/91651332-75437200-eac6-11ea-9afd-d7a203262907.png)\n\n#### 사례\n- 추천 엔진: 그래프 데이터베이스를 사용하면 고객 관심사, 친구 및 구매 내역과 같은 정보 범주 간의 관계를 그래프로 저장할 수 있다. \n\n\n## 실제 사례: 하나의 Application에 여러 가지 DATABASE를 사용하는 사례\n\n### Airbnb\n![airbnb](https://user-images.githubusercontent.com/43839938/91651726-116f7800-eacb-11ea-885a-fd8b7fee6ec1.png)\n\n\n### duolingo\n![duolingo](https://user-images.githubusercontent.com/43839938/91651712-f1d84f80-eaca-11ea-948e-309bf5420473.png)\n\n\n> In-memory: 가령, 베스트셀러(leader board) 리스트를 뽑아야 한다고 가정하자. 관련 모든 Table을 스캔해야하고 group by, order by, ... 등 매번 저 베스트 셀러를 조회하는 API를 요청할 때마다 이 작업을 반복해야 한다. 게다가 Order가 늘어날 수록 Query Performance는 더 느려진다. 따라서 미리 베스트셀러 리스트를 저장해놓고, Order가 늘어날 때 그 리스트와 함께 처리하도록 한다. [Redis](https://aws.amazon.com/ko/redis/)가 대표적인 DB이다.\n\n## 결론, 하나의 어플리케이션에서 각 서비스에 맞는 DB를 선택하자\nRDB와 NoSQL은 경쟁의 관계가 아니라 상생의 관계다. 각 특성에 맞게 적절히 사용한다면 보완적인 관계를 극대화 할 수 있다.\nNoSQL은 특정 목적에 맞게 종류가 다양하듯(a purpose-built strategy for databases) 구현할 서비스를 세분화하고 각각의 목적을 고려해 어떤 DB를 사용하는 것이 좋을지 선택해야 한다. 이 문서에서는 이런 선택의 기준을 제시하기 위해 여러 종류의 DB를 살펴봤다.\n\n---\n#### Reference\n- [NoSQL이란?](https://aws.amazon.com/ko/nosql/)\n- [NoSQL이란 무엇인가?](https://www.samsungsds.com/global/ko/support/insights/1195843_2284.html)\n- [SQL vs NoSQL 5분컷 설명!](https://youtu.be/Q_9cFgzZr8Q)\n- [Understanding Key-Value Databases](https://www.dataversity.net/understanding-key-value-databases/)\n- [NoSQL 개념, 특징과 장점, CAP 이론, 데이터모델 분류](https://sjh836.tistory.com/97)\n- [AWS re:Invent 2018: [REPEAT 1] Databases on AWS: The Right Tool for the Right Job](https://youtu.be/-pb-DkD6cWg)\n"
  },
  {
    "path": "Deprecated/AMD와 CommonJS.md",
    "content": "# AMD와 CommonJS\n\n## 배경\n\n자바스크립트(ES5 기준)는 파이썬, 루비, 다른 스크립트 언어 계열과 차이점이 존재한다.\n\n바로 **모듈 사용의 표준이 존재하지 않는다는 것**이다.\n\nNode.js를 사용하고 있는 개발자들은 `module.exports`를 통해 모듈을 정의하고 `require()` 함수를 통해 정의한 모듈을 불러와 사용하고 있다.\n\n이러한 방식을 **CommonJS**라고 한다.\n\n프론트엔드에서는 위와 같은 모듈 제공 방식이 없었다.\n\n이에 따라 `window`객체를 이용하여 모듈의 리소스를 전달하는 방식을 이용했었다.\n\n```js\n//math.js\nvar sum = function() {\n    var total = 0;\n    for (var idx in arguments) {\n        total += arguments[idx];\n    }\n    return total;\n};\n\nwindow.Math = {\n    sum: sum\n};\n```\n\n```js\n//main.js\nif (typeof Math !== 'undefined') {\n    if (typeof Math.sum === 'function') {\n        console.log(Math.sum(1, 2));\n    } else {\n        throw new Error('Math.sum function is not defined.');\n    }\n} else {\n    throw new Error('A module `Math` is undefined.');\n}\n```\n\n위 소스를 보면 **전역 오브젝트인 `window` 객체를 통해 다른 자바스크립트 파일에 리소스를 전달** 하고 있다.\n\n하지만 이것도 사용하는 HTML에서 불러오는 모듈 파일을 먼저 로드해야한다.\n\n즉, **대상 모듈이 존재할수도, 존재하지 않을 수도 있는 상태**가 된다.\n\n이후 점차 프로젝트 규모가 커지게 되면서 프론트엔드에서 좀 더 효율적인 모듈화를 제공하기 위헤 `AMD`와 `CommonJS` 방식이 생겨나게 됐다.\n\n<br/>\n\n## AMD(Asynchronous Module Definition)\n\nAMD에서는 `define`을 사용한다.\n\n```js\n//math.js\ndefine([], function() {\n    return {\n      sum: function() {\n          var total = 0;\n          for (var idx in arguments) {\n              total += arguments[idx];\n          }\n          return total;\n      }\n    };\n});\n```\n\n```js\n//main.js\nrequirejs.config({\n    baseUrl: './'\n});\n\nrequire(['math'], function(Math) {\n  console.log(Math.sum(1, 2));\n});\n```\n\n원래 AMD의 규칙을 따르는 도구를 사용해 모듈을 정의하고 불러와야하지만 위의 코드에선 ReuireJS를 사용했다.\n\n<br/>\n\n## CommonJS\n\nCommonJS 방식은 위에서도 말했듯이 **Node.js에서 사용하고 있는 모듈 방식**이다. 이것이 CommonJS 방식의 제공이 중요한 이유다.\n\n```js\nmodule.exports = {\n    sum: function() {\n        var total = 0;\n        for (var idx in arguments) {\n            total += arguments[idx];\n        }\n        return total;\n    }\n};\n```\n\n```js\nvar math = require('./math');\n\nconsole.log(math.sum(1, 2));\n```\n\n### CommonJS 방식으로 제공되어야 하는 경우\n\n---\n\n* 프론트엔드 라이브러리일지라도 Node.js 코드를 통해 유닛 테스팅을 하는 경우\n\n* `moment.js`, `underscore.js`처럼 Node.js에서도 사용 가능해야하는 라이브러리 일 경우 \n\n<br/>\n\n## 모듈 제공의 방향과 ES6\n\n이전 Module 제공 방식의 추세가  AMD vs CommonJS였다면, CommonJS와 ES6 타입으로 축약되는 것으로 보인다. \n\n즉, **AMD 방식은 사양되는 분위기**다.\n\n하지만 여전히 일부 라이브러리가 AMD방식을 사용하고 있어 지금도 번들링은 UMD로 하고 있다.\n\n위의 내용까지는 ES5기준으로 본 모듈 방식의 정의고 ES6기준으로 보면 또 다른 모듈 방식이 존재한다.\n\n**ES6 모듈은 import를 제공하여 모듈을 불러오는 방식**이다.\n\nrequire.js와 import를 사용하여 모듈을 불러올 때 각각의 차이 중 하나는 **Tree-Shaking**을 할 때 알 수 있다.\n\n**`import`를 사용한 방식은 라이브러리의 특정 모듈만을 가져와 번들링할 수 있지만, `require` 방식으로 가져온 라이브러리는 모듈 전체를 번들링**해야한다.\n\n즉, **`require` 방식으로 가져온 모듈에 대해서는 Tree-shaking을 진행할 수 없다.**\n\n<br/>\n\n---\n\n#### Reference\n\n- [자바스크립트 모듈 제공을 위한 AMD, CommonJS 그리고 RequireJS 소개](https://blog.pigno.se/post/157992405313/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EB%AA%A8%EB%93%88-%EC%A0%9C%EA%B3%B5%EC%9D%84-%EC%9C%84%ED%95%9C-amd-commonjs-%EA%B7%B8%EB%A6%AC%EA%B3%A0-requirejs-%EC%86%8C%EA%B0%9C)\n- [JavaScript 표준을 위한 움직임: CommonJS와 AMD](https://d2.naver.com/helloworld/12864)"
  },
  {
    "path": "Deprecated/Async-Await.md",
    "content": "# Aync-Await\n\n## Aync-Await에 도달하기 위해서\n\n1. Iterator\n2. Generator\n3. Promise\n4. Aync-Await\n\n<br/>\n\n## 먼저\n\n그전에 가장 먼저 `for-of`에 대해서 알아보자\n<br/>\n\n우리가 흔히 사용하고 많이 사용하는 `for`문이 있다. 그러나 어디서부터 어디까지 지정을 하는것이 아닌 전체를 순회한다고 하면 `for-in`이나 `foreach`를 사용한다.\n<br/>\n\n`for-in`은 각각의 `key`를 받아와서 그 키를 가지고 `value`를 가져와야하며 `foreach`는 중간에 나올 수 없다는 단점을 가지고 있다.\n<br/>\n\n**이러하여 생긴것이 `for-of` 이다.**\n<br/>\n\n**ECMA2015**에 새로운 문법으로 추가가 되었으며 이것은 배열은 물론 `object`까지 순회가 가능하다.(물론 key가 있어야 가능)\n<br/>\n\n**for-of문은 열거가 가능한 객체라면 무엇이든 순회가 가능하다.**\n<br/>\n\n그렇다면 열거가능한 객체란 무엇인가? \n\n:point_right: 배열(Array)는 물론, TypedArray, 문자열(String), Map, Set, DOM Collection 등을 말한다.\n\n<br/>\n\n```js\n/* array */\nlet iterable = [10, 20, 30];\n\nfor (let value of iterable) {\n    console.log(value); // 10 20 30\n}\n\n/* string */\nlet iterable = \"boo\";\n\nfor (let value of iterable) {\n    console.log(value); // \"b\" \"o\" \"o\"\n}\n\n/* Typed Array */\nlet iterable = new Uint8Array([0x00, 0xff]);\n\nfor (let value of iterable) {\n    console.log(value); // 0 255\n}\n\n/* Map */\nlet iterable = new Map([[\"a\", 1], [\"b\", 2], [\"c\", 3]]);\n\nfor (let entry of iterable) {\n    console.log(entry); // [a, 1] [b, 2] [c, 3]\n}\n\nfor (let [key, value] of iterable) {\n    console.log(value); // 1 2 3\n}\n\n/* Set */\nlet iterable = new Set([1, 1, 2, 2, 3, 3]);\n\nfor (let value of iterable) {\n    console.log(value); // 1 2 3\n}\n\n/* DOM Collection */\nlet articleParagraphs = document.querySelectorAll(\"article > p\");\n\nfor (let paragraph of articleParagraphs) {\n    paragraph.classList.add(\"read\");\n}\n```\n\n어떻게 순회를 할 수 있는 것일까 :grey_question:\n<br/>\n\n:point_right: **`iterator` 덕분이다.**\n<br/>\n\n`Collection`들은 내부적으로 `Iterable Protocol`을 구현한다.\n<br/>\n\n## Iterable Protocol\n\n어떤객체가 순회가 되기 위해서는 `iteration`동작에 대해 정의가 되어 있어야 한다.\n<br/>\n\n`Iterable Protocol`에 의하면 `Iterator`는 `next()`함수를 구현해야하고 이 함수는 결과값으로 `{value: value, doen: boolean}` 같은 객체를 반환해야 한다고 한다.\n<br/>\n\nEx) 구현해보기\n\n```js\nfunction makeRangeIterator(start = 0, end = Infinity, step = 1) {\n    var nextIndex = start;\n    var n = 0;\n\n    var rangeIterator = {\n        next: function() {\n            var result;\n\n            if (nextIndex < end) {\n                result = { value: nextIndex, done: false }\n            } else if (nextIndex == end) {\n                result = { value: n, done: true }\n            } else {\n                result = { done: true };\n                nextIndex += step;\n                n++;\n                return result;\n            }\n        };\n    return rangeIterator;\n}\n\n// run iterator\nconst it = makeRangeIterator(1, 4);\nlet result = it.next();// 처음 한번 실행\n\nwhile (!result.done) {\n    console.log(result.value); // 1 2 3\n    result = it.next();\n}\n```\n\n`ECMA2015`에서는 `Iterator protocol`을 이용하여 열거가능한 객체를 만들 수 있다.\n<br/>\n\n`[Symbol.iterator]()` 와 `next()`를 이용하면 쉽게 정의할 수 있다.\n<br/>\n\n`for-of`는 `[Symbol.iterator]()`를 호출하여 반복을 실행하게 된다.\n<br/>\n\n예제 :point_down:\n\n```js\nconst iterable = {\n    [Symbol.iterator]() {\n        return {\n            i: 0,\n            next() {\n                if (this.i < 3) {\n                    return { value: this.i++, done: false };\n                }\n\n                return { value: undefined, done: true };\n            }\n        };\n    }\n};\n\nfor (var value of iterable) {\n    console.log(value); // 0 1 2\n}\n```\n\n<br/>\n\n## Generator\n\n`Iterator`와 비슷한 이녀석은 일종의 **코루틴(Co-Routine)**인데, 다른 언어에서는 곧 잘 사용하는 개념이다.\n\n> 코루틴(Co-Routine) : 어느 작업을 하다가 중간에 멈추고  멈춘부분부터 다시 시작이 가능한\n<br/>\n\n`Generator`는 함수 실행도중에 잠시 멈췄다가 다시 실행할 수 있는 독특한 함수이다. `Generator`는 `function*`키워드를 사용해서 생성하며,\n<br/>\n\n**`Generator`를 호출하면 실행되는 것이 아니라 `Iterator`객체가 반환된다.**\n<br/>\n\n따라서 `Iterator`에서 구현한 `next()` 함수를 호출하면 `Generator`가 실행되면서 `yield`를 만날 때까지 실행되고, 이때 컨텍스트는 저장된 상태로 남아 있게 된다.\n\n예제 :point_down:\n\n```js\nfunction* idMaker(){\n    var index = 0;\n    while(index < 3)\n        yield index++;\n}\n\nconst gen = idMaker(); // iterator객체가 반환\n\nconsole.log(get.next());\nconsole.log(get.next());\nconsole.log(get.next());\n```\n\n<br/>\n\n`Generator`를 사용하면 `Iterable Protocol`을 구현하는 것보다 좀 더 쉽게 `Iterator`를 사용할 수 있다.\n<br/>\n\n`Generator`의 진면목은 비동기 프로그래밍에서 볼 수 있다. 함수가 실행 도중에 멈춘다니. 언제 응답이 올지 알 수 없기 때문에, `callback`을 등록하는 비동기 프로그래밍에 응용하면 `callback hell`을 탈출할 수 있지 않을까?\n<br/>\n\n`generator`도 역시 `ES5`스펙이 아니다 `ES6`이다.\n<br/>\n\n그렇다면 `Generator`는 또 어떻게 구현이 되어있는 것인가?\n\n```js\n// ES6\nfunction* foo(){\n    yield bar();\n}\n\n// ES5 Compiled\n\"use strict\";\n\nvar _marked = /*#__PURE__*/ regeneratorRuntime.mark(foo);\n\nfunction foo() {\n    return regeneratorRuntime.wrap(\n        function foo$(_context) {\n            while (1) {\n                switch ((_context.prev = _context.next)) {\n                    case 0:\n                        _context.next = 2;\n                        return bar();\n                    case 2:\n                    case \"end\":\n                        return _context.stop();\n                }\n            }\n        },\n        _marked, this\n    );\n}\n```\n\n`Genrator`는 결국 `iterable Protocel`를 구현하는 객체이다. 그러나 프로토콜과 관련된 어느것도 보이지 않는다. \n<br/>\n\n대신 `regeneratorRuntime`이것이 보인다.\n<br/>\n\n`babel`에서는 `regeneratorRuntime`라이브러리를 사용해서 구현을 했다.\n<br/>\n\n코드의 역사를 따라가다 보면 `facebook/regenerator repository`에 도달하게 된다.\n<br/>\n\n> [https://github.com/facebook/regenerator/blob/master/packages/regenerator-runtime/runtime.js](https://github.com/facebook/regenerator/blob/master/packages/regenerator-runtime/runtime.js)\n<br/>\n\n이 라이브러리는 2013년 `Node.js v0.11.2`에서 `generator syntax`를 지원하기 위해 만들어 졌으며, `Babel`에서는 이 라이브러리를 사용하여 `generator`를 구현하고 있다.\n실제 코드를 들여다보면 `Symbol`과 `Iterator`를 이용해서 `Iterable Protocol`을 구현하고 있다.\n<br/>\n\n## Async-await\n\n이제 본론으로 돌아와서 `Async-await`은 어떻게 구현이 되었는가??\n<br/>\n\n`Async-await`는 `ECMA-262`에서 초안으로 처음 등장했으며, `ECMAScript 2017`에서 표준으로 정의되었다.(`ES8`에서 표준이 되었다.)\n\n먼저 `Babel`에서 `Async-await`를 돌리게 되면 `ES5`버전으로 나온다. 그렇다면 `ES5`로 구현이 가능하다는 것이다. 실제로 `Babel`로 돌리게 되면 아래와 같은 결과가 나온다.\n\n```js\n// ES7\nasync function foo() {\n    await bar();\n}\n\n// ES5 complied\nlet foo = (() => {\n   var _ref = _asyncToGenerator(function*() {\n       yield bar();\n   });\n\n    return function foo() {\n       return _ref.apply(this, arguments);\n    };\n})();\n\nfunction _asyncToGenerator(fn) {\n    return function() {\n        var gen = fn.apply(this, arguments);\n\n        return new Promise(function(resolve, reject) {\n            function step(key, arg) {\n                try {\n                    var info = gen[key](arg);\n                    var value = info.value;\n                } catch (error) {\n                    reject(error);\n                    return;\n                }\n\n                if (info.done) {\n                    resolve(value);\n                } else {\n                    return Promise.resolve(value).then(\n                        function(value) {\n                            step(\"next\", value);\n                        },\n                        function(err) {\n                            step(\"throw\", err);\n                        }\n                    );\n                }\n            }\n            return step(\"next\");\n        });\n    };\n}\n```\n\n위에 컴파일됨 구문을 보게 되면 `async keyword`를 `generator`로 바꾸고 `await keyword`는 `yield`로 바꾸었다.\n<br/>\n\n`Generator`는 `yield`를 만날 때까지 실행된다. 이때 `Context`는 저장된 상태로 남아있게 된다.\n<br/>\n\n즉 `Generator`로 비동기 로직이 끝날때마다 적절히 `next()`를 적절하게 호출해주면 `Async-Await`함수가 만들어 지는 것이다.\n<br/>\n\n그러나 `bar()`함수의 작업이 종료되는 시점은 `bar()`함수밖에 모른다. 그렇다고 `next()`를 `bar()`함수 내에서 직접 실행하게 된다면 의존성이 생기게 된다. \n<br/>\n\n그렇다면 어떻게 의존성을 분리 할 수 있을까?\n<br/>\n\n:star: `Promise`\n<br/>\n\n`Babel`은 `promise`와 `재귀함수`를 이용하여 `next()`를 대신 호출해주는 함수를 만드는데, 그게 바로 `_asyncToGenerator`이다.\n<br/>\n\n`fn.apply`를 실행하여 인자로 넘어온 `Generator`를 실행하여 `iterator`객체를 **클로저로 저장해둔다.** 나머지는 클로저에 저장한 `iterator`를 실행시키고, 반환된 `promise`객체를 재귀함수를 통해 반복실행\n<br/>\n\n정리하자면 `Generator`는 비동기적 패턴을 `yield`를 통해 동기적인 “모습\"으로 바꾸어주고, `Promise`는 `Generator`로 만든 `iterator`를 반복해서 실행해주는 역할을 한다. `await keyword`에 사용하는 함수가 항상 `promise`를 반환해야하는 이유가 여기에 있다.\n<br/>\n\n> Promise => **프로미스는 자바스크립트 비동기 처리에 사용되는 객체입니다.** 여기서 자바스크립트의 비동기 처리란 ‘특정 코드의 실행이 완료될 때까지 기다리지 않고 다음 코드를 먼저 수행하는 자바스크립트의 특성’을 의미합니다\n<br/>\n\n:point_right: `Promise`로만 구현할 경우\n\n```js\nconst makeRequest = () => {\n    return getJSON()\n        .then(data => {\n            if (data.needsAnotherRequest) {\n                return makeAnotherRequest(data)\n                    .then(moreData => {\n                        console.log(moreData)\n                        return moreData\n                    })\n            } else {\n                console.log(data)\n                return data\n            }\n        })\n}\n```\n\n:point_right: `async-await`로 구현할 경우\n\n```js\nconst makeRequest = async () => {\n    const data = await getJSON()\n\n    if (data.needsAnotherRequest) {\n        const moreData = await makeAnotherRequest(data);\n        console.log(moreData)\n        return moreData\n    } else {\n        console.log(data)\n        return data\n    }\n}\n```\n\n<br/>\n\n---\n\n#### Reference\n\n- [Generator](https://meetup.toast.com/posts/73)\n- [iterator](https://medium.com/@la.place/javascript-iterator-b16ca3c51af2)\n- [Aync-Await](\nhttps://medium.com/@la.place/async-await%EB%8A%94-%EC%96%B4%EB%96%BB%EA%B2%8C-%EA%B5%AC%ED%98%84%ED%95%98%EB%8A%94%EA%B0%80-fa08a3157647)\n"
  },
  {
    "path": "Deprecated/B_EventLoop.md",
    "content": "# Event Loop\n\n자바스크립트는 싱글 쓰레드이다. 그래서 비동기를 처리하기 위해서는 다른 누군가의 도움이 필요하다. \n\n우리가 자바스크립트를 기본적으로 브라우저에서 사용을 한다. 그렇다면 당연하게 자바스크립트의 한계를 보완해주는 역할은 브라우저가 해준다는 것이다. 브라우저가 해주는 많은 역할 중 하나는 비동기처리를 도와주는 것이다.\n\n오늘은 비동기를 처리하는데 있어서 큰 역할을 하고 있는 것을 알아보도록 하자.\n<br/>\n\n## 목차\n\n- [x]  Heap\n- [x]  Stack\n- [x]  Browser or Web APIs\n- [x]  Event Table\n- [x]  Event Loop\n\n자바스크립트는 스크립트가 실행이 되는 엔진이 있다. 크롬을 기준으로 본다면 엔진은 V8이 된다. 이 엔진을 구성하는 요소는 크게보면 Heap과 Stack으로 구성이 되어있다.\n<br/>\n\n### Heap\n\n객체는 Heap에 할당이 된다. Heap은 메모리에서 대부분 구조화되지 않은 영역을 나타낸다.\n<br/>\n\n### Stack\n\n자바스크립트 코드 실행을 위해 제공된 단일 쓰레드이다. 함수를 호출하게 되면 하나의 Stack Frame이 형성이 된다. \n\n더이상의 자세한 내용은 CallStack에 대해서 작성한 글을 참고 해주세요.\n\n> [CallStack 알아보기](https://github.com/SeonHyungJo/FrontEnd-Dev/blob/master/Javascript/Basic_1_CallStack.md)\n\n<br/>\n\n### Browser or Web APIs\n\n흔히 WebAPI라 불리는 API들은 웹 브라우저에 내장되어 있으며 브라우저 및 이외 컴퓨터 환경에서 데이터를 노출 할 수 있으며 복잡한 환경에서 유용하게 사용할 수 있다.(ex. 위치정보등등)\n\n이것은 자바스크립트에 포함되는 것이 아니며 자바스크립트 언어를 사용하는데 있어 강력한 성능을 제공한다.\n<br/>\n\n## 예제로 살펴보기\n\n```javascript\nfunction main(){\n    console.log('A');\n    setTimeout(\n    function display(){ console.log('B'); }\n    ,0);\n    console.log('C');\n}\nmain();\n//\tOutput\n//\tA\n//\tC\n//  B\n```\n\n![event_loop](https://github.com/SeonHyungJo/FrontEnd-Dev/blob/master/assets/image/basic_event_loop.png?raw=true)\n\n1. main함수가 실행이 되어서 처음에 들어가게 된다. main함수 안에 있는 `console.log` 가 스택에 쌓이게 된다. 함수가 실행이 되면 알파벳이 콘솔창에 출력이 된다.\n2. 다음으로 `setTimeout` 이 들어오면서 실행이 된다. `setTimeout` 은 `browserAPI` 의 콜백을 지연하는 함수를 사용한다. \n3. 브라우저에서 타이머가 이루어지는 동안 `console.log` 가 실행이 되고 C가 출력이 된다. 여기서 초가 0이더라도 콜백은 메시지 큐에 담기게 되어 브라우저는 그것을 받는다.\n4. main함수가 모두 다 끝나게 되면 스택이 비게 된다. 그러면 브라우저가 큐에 쌓았던 콜백을 실행하게 된다. \n\n스택이 비었을때 자바스크립트 엔진은 메시지 큐가 비었는지 확인을 한다. 만약에 비었다면 엔진은 첫번째 메시지를 지우고 함수의 안을 실행한다. 이때 새로운 스택프레임(inital frame)이 생성이 되고 스택에 쌓인다.  함수가 끝났다면 initial 프레임이 스택에서 제거가 된다. 이러한 과정은 메시지 큐가 없을 때까지 이루어진다. \n<br/>\n\n## The Event Loop\n\n위에서 언급을 했던 끊임없이 비었는지 검사하는 것이 바로 이벤트 루프이다. 이벤트 큐에 대기중인 항목이 있으면 호출 스택으로 이동한다. 그렇지 않으면 아무일도 일어나지 않는다.\n\n```javascript\nsetTimeout(() => console.log('first'), 0)\n\nconsole.log('second')\n```\n\n위의 경우는 second가 찍히고 first가 찍히게 된다.\n\n멀티쓰레드라면 하나의 일을 하고 있을 때 다른 쓰레드를 사용해서 일을 처리할 수 있지만 자바스크립트는 싱글쓰레드이기 때문에 불가능하다. 그래서 비동기를 하는데 있어서 이벤트 루프는 필수적이다.\n\n```javascript\nwhile (await messageQueue.nextMessage()) {\n  let message = messageQueue.shift();\n  message.run();\n}\n```\n\n이벤트 루프는 메시지 큐에 메시지가 더 있는지 확인하는 루프이다.\n\n메시지 큐에 메시지가 있으면 메시지 큐에서 다음 메시지를 제거하고 그 메시지와 연관된 기능을 실행한다. 그렇지 않으면 새 메시지가 메시지 대기열에 추가 될때까지 대기를 한다. 이벤트루프가 자바스크립트에게 비동기를 허용하는 기본 모델이다.\n\n---\n\n#### Reference\n\n- [JavaScript Event Loop Explained]([https://medium.com/front-end-weekly/javascript-event-loop-explained-4cd26af121d4](https://medium.com/front-end-weekly/javascript-event-loop-explained-4cd26af121d4))\n- [What is the Event Loop in Javascript]([https://www.wptutor.io/web/js/javascript-event-loop](https://www.wptutor.io/web/js/javascript-event-loop))\n- [Understanding JS: The Event Loop]([https://hackernoon.com/understanding-js-the-event-loop-959beae3ac40](https://hackernoon.com/understanding-js-the-event-loop-959beae3ac40))\n- [Event loop in javascript]([https://code.likeagirl.io/what-the-heck-is-event-loop-1e414fccef49](https://code.likeagirl.io/what-the-heck-is-event-loop-1e414fccef49))\n- [The JavaScript Event Loop]([https://flaviocopes.com/javascript-event-loop/](https://flaviocopes.com/javascript-event-loop/))\n- [Tasks, microtasks, queues and schedules]([https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/](https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/))"
  },
  {
    "path": "Deprecated/B_Module.md",
    "content": "# Module\n\n**Webpack** 및 **SystemJS**와 같은 도구는 무엇일까? 또는 **AMD**, **UMD**, **CommonJS**는 또 무엇인가? 그것들은 어떻게 관련이 있는건가? 그리고 왜 그걸 왜 필요로 하게 되었을까?\n<br/>\n\n## 모듈이란?\n\n모듈은 구현사항을 캡슐화하고 기능에 따라 Public API로 노출하여 다른 곳에서 쉽게 불러서 사용하도록 하며 재사용이 가능하도록 한 코드의 뭉치이다.\n\n그렇다면 왜 모듈이 필요하게 되었을까?\n\n- 추상적인 코드 : 전문 라이브러리에 기능을 위임하여 실제 구현의 복잡성을 이해할 필요가 없도록 하기 위해서\n- 코드 캡슐화 : 코드를 변경하지 못하도록 하기 위해 모듈 내부의 코드를 숨기기 위해서\n- 재사용 코드 : 같은 코드를 계속해서 사용하기 위해서\n- 의존성 관리 : 우리의 코드를 다시 작성하지 않고 쉽게 종속성을 변경하기 위해서\n\n<br/>\n\n## Module patterns in ES5\n\n원래 자바스크립트라는 것은 모듈을 염두해두고 설계가 된 언어가 아니다. 시간이 지나면서 사람들이 필요에 따라 다양한 패턴을 만들게 된 것이다.\n\n우리가 간단하게 볼만한 패턴은 **IIFE와 공개 모듈 패턴**이 있다.\n<br/>\n\n## 즉시 실행 함수 표현(Immediately-invoked Function Expression)\n\nIIFE는 ES5기준으로 가장 많이 사용되던 패턴 중 하나이다. `Scope Block` 을 만드는 유일한 방법은 함수이기 때문이다. 따라서 아래와 같은 예제는 `ReferenceError` 가 나온다.\n\n```javascript\n(function() {\n    var scoped = 42;\n}());\n    \nconsole.log(scoped); // ReferenceError\n```\n\nIIFE는 오픈소스라이브러리에서 Block scope를 만드는데 사용이 되었다. 이렇게 하게 되면 우리가 만들면서 공개하는 것과 아닌것을 구분할 수 있게 된다.\n\n```javascript\nvar myModule = (function() {\n    // private variable, accessible only inside the IIFE\n    var counter = 0;\n    \n    function increment() {\n        counter++;\n    }\n    \n    // publicly exposed logic\n    return {    \n        increment: increment\n    }\n}());\n```\n\nES6에서는 modules라는 스펙이 추가가 되어 modules를 사용할 수 있다. 현재 이 모듈은 자신의 범위를 선언하고 모듈 내부에서 생성된 변수는 전역객체에서 부를 수 없도록 한다.\n\n```javascript\n!function() {\n    alert(\"Hello from IIFE!\");\n}();\n```\n\n위의 예제는 놀랍게도 IIFE이다. 우리가 흔히 알고 있는 모양새와 다르다고 생각해서 아니라고 할 수 있다.  그러나 우리가 사용하는 IIFE에서의 괄호는 표현식으로 나타내는 것에 불가하다. 그래서 표현식으로 나타낼 수 있는 어떤 것이든 생성후 바로 실행이 되도록하는 문장이 될 수 있는 것이다.\n\n```javascript\nvoid function() {\n    alert(\"Hello from IIFE!\");\n}();\n```\n\n또한 `void` 역시 기본적으로 함수가 표현식으로 취급되도록 한다.\n<br/>\n\n## 전통적인 IIFE\n\n처음에 예제에서 보았듯이 IIFE 패턴의 핵심은 함수를 표현식으로 바꾸고 즉시 실행하는 것이다.\n\n```javascript\n(function() {\n    alert(\"I am not an IIFE yet!\");\n});\n```\n\n위의 코드는 단순하게 함수를 괄호로 감싸고 있다. 그러나 이 함수식은 실행이 바로 되지 않으므로 즉시 실행 함수가 아니다. 이걸 IIFE로 바꾸기 위해서는 2가지의 스타일을 변환이 필요하다.\n\n```javascript\n// Variation 1\n(function() {\n    alert(\"I am an IIFE!\");\n}());\n    \n// Variation 2\n(function() {\n    alert(\"I am an IIFE, too!\");\n})();\n```\n\n위의 예제에는 익숙한 문법이 있기도 하고 문법이 이상하다고 생각되는 것도 있다. 이걸 간단하게 살펴보면\n\n1. Variation 1의 4행에서 호출을 위한 괄호를 안쪽에 넣었다. 다시 바깥 괄호는 함수 밖의 함수 표현식을 만드는데 필요하게 된다.\n2. Variation 2에서 마지막줄의 괄호는 함수 표현식을 호출하기 위한 괄호가 밖에 위치하고 있다.\n\n두가지 방법은 널리 사용되고 있다. 나중에 핵심부분으로 들어가게되면 2가지의 작동이 다르다. 그러나 상관없이 자신이 원하는 방법을 사용하면 된다.\n\n작동하는 예제와 작동하지 않는 두가지 예제를 보자 익명의 함수를 사용하는 것은 좋은 방법이 아니므로 지금부터는 IIFE의 이름을 적어주자\n\n```javascript\n// Valid IIFE\n(function initGameIIFE() {\n    // All your magical code to initalize the game!\n}());\n    \n// Following two are invalid IIFE examples\nfunction nonWorkingIIFE() {\n    // Now you know why you need those parentheses around me!\n    // Without those parentheses, I am a function definition, not an expression.\n    // You will get a syntax error!\n}();\n    \nfunction () {\n    // You will get a syntax error here as well!\n}();\n```\n\n위의 예제를 실행하게 되면서 우리가 왜 괄호가 필요한지 알게 될 것이다. IIFE를 만들려고 하면 우리는 표현식이 필요하다. 함수 선언, 함수 문장은 필요가 없다.\n<br/>\n\n### IIFEs and private variables\n\n```javascript\n(function IIFE_initGame() {\n    // Private variables that no one has access to outside this IIFE\n    var lives;\n    var weapons;\n        \n    init();\n    \n    // Private function that no one has access to outside this IIFE\n    function init() {\n        lives = 5;\n        weapons = 10;\n    }\n}());\n```\n\n<br/>\n\n### IIFEs with a return value\n\n```javascript\nvar result = (function() {\n    return \"From IIFE\";\n}());\n    \nalert(result); // alerts \"From IIFE\"\n```\n\n<br/>\n\n### IIFEs with parameters\n\n```javascript\n(function IIFE(msg, times) {\n    for (var i = 1; i <= times; i++) {\n        console.log(msg);\n    }\n}(\"Hello!\", 5));\n```\n\n<br/>\n\n## Classical JavaScript module pattern\n\n우리는 전체 시퀀스를 손상시키지않도록 작동하는 싱글톤 객체를 구현해보려고 한다.\n\n```javascript\n var Sequence = (function sequenceIIFE() {\n        \n    // Private variable to store current counter value.\n    var current = 0;\n        \n    // Object that's returned from the IIFE.\n    return {\n    };\n        \n}());\n    \nalert(typeof Sequence); // alerts \"object\"\n```\n\n위의 예제를 간단하게 설명하면 `sequenceIIFE` 라는 이름을 가진 함수를 표현식으로 나타내어 IIFE 패턴을 적용하였으며 private 변수로 `current` 를 선언해서 0을 담았으며 `return` 으로 `Object` 를 반환해서 `Sequence` 라는 변수에 담고 있다. 그러므로 당연하게 그것의 타입은 `object` 가 나오게 된다.\n\n```javascript\nvar Sequence = (function sequenceIIFE() {\n        \n    // Private variable to store current counter value.\n    var current = 0;\n        \n    // Object that's returned from the IIFE.\n    return {\n        getCurrentValue: function() {\n            return current;\n        },\n            \n        getNextValue: function() {\n            current = current + 1;\n            return current;\n        }\n    };\n}());\n    \nconsole.log(Sequence.getNextValue()); // 1\nconsole.log(Sequence.getNextValue()); // 2\nconsole.log(Sequence.getCurrentValue()); // 2\n```\n\n좀 더 그럴듯하게 꾸며보자. 위의 예제에서 `return Object` 에 `getCurrentValue`, `getNextValue` 2가지의 함수를 만들어서 반환하고 있다. 그리고 후에 반환된 `Object` 의 함수를 실행시켜서 IIFE안쪽에 `current` 값을 바꾸거나 가져오고 있다.\n\n위의 `current` 라는 변수는 IIFE의 전용이므로, 클로저를 통해 접근할 수 있는 함수 외에는 변수를 수정하거나 직접 접근은 불가능하다.\n\n이렇게 IIFE와 클로져를 같이 사용해서 구현을 해보았다. 이것은 모듈패턴에 대한 매우 기본적인 변형이다. 더 많은 패턴들이 존재하지만 거의 모든 패턴이 IIFE를 사용하여 폐쇄범위를 만든다.\n<br/>\n\n## When you can omit parentheses\n\n```javascript\nvar result = function() {\n    return \"From IIFE!\";\n}();\n```\n\n함수 표현식 주위의 괄호는 기본적으로 함수가 명령문이 아닌 표현식이 되도록 한다. 위의 예에서 `function` 키워드는 명령문의 첫 단어가 아니라서 자바스크립트가 이걸 선언문이나 정의로 취급하지 않는다. 마찬가지로 표현식이라는 것을 알 경우 괄호를 생략할 수 있다.\n\n그러나 다른 개발자들분들도 그렇게 생각할지 모르지만 항상 괄호를 붙이는 것이 가독성에 좋다.\n\n싱글톤 대신 모듈로 구현하여 생성자 함수를 노출할 수도 있다.\n\n```javascript\n// Expose module as global variable\nvar Module = function(){\n    \n    // Inner logic\n    function sayHello(){\n        console.log('Hello');\n    }\n    \n    // Expose API\n    return {\n        sayHello: sayHello\n    }\n}\n\nvar module = new Module();\n\nmodule.sayHello();  \n// => Hello\n```\n\n<br/>\n\n## Module formats\n\n기존의 ES6이전에는 자바스크립트에 모듈을 정의하는 공식문법이 존재하지 않았다. 그래서 다양한 모듈을 정의해왔었는데\n\n- Asynchronous Module Definition (AMD)\n- CommonJS\n- Universal Module Definition (UMD)\n- System.register\n- ES6 module format\n\n<br/>\n\n### Asynchronous Module Definition (AMD)\n\nAMD 형식은 브라우저에서 사용되며 정의함수를 사용하여 모듈을 정의한다.\n\n```javascript\n//Calling define with a dependency array and a factory function\ndefine(['dep1', 'dep2'], function (dep1, dep2) {\n    \n    //Define the module value by returning a value.\n    return function () {};\n});\n```\n\n<br/>\n\n### CommonJS format\n\nCommonJS 형식은 Node.js에서 사용되며 `require` 과 `module.exports` 를 사용하여 종속성 및 모듈을 정의한다.\n\n```javascript\nvar dep1 = require('./dep1');  \nvar dep2 = require('./dep2');\n    \nmodule.exports = function(){  \n  // ...\n}\n```\n\n<br/>\n\n### Universal Module Definition (UMD)\n\nUMD는 브라우저와 Node에서 모두 사용이 가능하다.\n\n```javascript\n(function (root, factory) {\n    if (typeof define === 'function' && define.amd) {\n        // AMD. Register as an anonymous module.\n        define(['b'], factory);\n    } else if (typeof module === 'object' && module.exports) {\n        // Node. Does not work with strict CommonJS, but\n        // only CommonJS-like environments that support module.exports,\n        // like Node.\n        module.exports = factory(require('b'));\n    } else {\n        // Browser globals (root is window)\n        root.returnExports = factory(root.b);\n    }\n}(this, function (b) {\n    //use b in some fashion.\n    \n    // Just return a value to define the module export.\n    // This example returns an object, but the module\n    // can return a function as the exported value.\n    return {};\n}));\n```\n\n<br/>\n\n### System.register\n\n`System.register` 형식은 ES5에서 ES6 모듈 구문을 지원하도록 설계되었습니다.\n\n```javascript\nimport { p as q } from './dep';\n    \nvar s = 'local';\n    \nexport function func() {  \n    return q;\n}\n    \nexport class C {  \n}\n```\n\n<br/>\n\n### ES6 module format\n\n```javascript\n    // lib.js\n    \n    // Export the function\n    export function sayHello(){  \n      console.log('Hello');\n    }\n    \n    // Do not export the function\n    function somePrivateFunction(){  \n      // ...\n    }\n```\n\n사용하려면 import로 불러서 사용한다.\n\n```javascript\nimport { sayHello } from './lib';\n    \nsayHello();  \n// => Hell\n```\n\n아직 브라우저는 ES6문법을 지원하지 않는다. 이미 ES6 모듈 포맷을 사용할 수 있지만 브라우저에서 코드를 실제로 실행하기 전에 코드를 **AMD** 나 **CommonJS** 와 같은 **ES5 모듈 형식으로 바꾸기 위해 Babel과 같은 변환기가 필요하게 된다.**\n<br/>\n\n## Module loaders\n\n모듈 로더는 특정 모듈 형식으로 작성된 모듈을 해석하고 load한다.\n\n런타임 시점에 loader를 실행한다.\n\n- 브라우저에서 모듈 로더를 로드한다.\n- 모듈로더에게 어느 파일을 로드할 것인지 알려준다.\n- 모듈로더가 주파일을 다운로드해서 해석한다.\n- 필요한 경우에는 모듈 로더가 파일을 다운로드한다.\n\n널리 사용되는 모듈 로더는 아래와 같이 있다.\n\n- RequireJS : AMD 형식의 모듈 용 로더\n- SystemJS : AMD, CommonJS, UMD 또는 System.register 형식의 모듈 용 로더\n\n<br/>\n\n## Module bundlers\n\n모듈 번들러는 모듈 로더를 대체한다. 그러나 로더와 차이점은 모듈 번들은 빌드시에 실행이 된다.\n\n- 빌드를 할 때 모듈 번들을 실행하여 번들파일을 생성한다.\n- 브라우저에서 번들을 로드한다.\n\n널리 사용되는 모듈 번들러는 아래와 같이 있다.\n\n- Browserify : CommonJS 모듈 용 bundler\n- Webpack : AMD, CommonJS, ES6 모듈 용 bundler\n\n<br/>\n\n---\n\n#### Reference\n\n- [Essential JavaScript: Mastering Immediately-invoked Function Expressions](https://medium.com/@vvkchandra/essential-javascript-mastering-immediately-invoked-function-expressions-67791338ddc6)\n- [Do ES6 Modules make the case of IIFEs obsolete?](https://hashnode.com/post/do-es6-modules-make-the-case-of-iifes-obsolete-civ96wet80scqgc538un20es0)\n- [JavaScript Modules: A Beginner’s Guide](https://medium.freecodecamp.org/javascript-modules-a-beginner-s-guide-783f7d7a5fcc)\n- [ES6 modules, Node.js and the Michael Jackson Solution](https://medium.com/dailyjs/es6-modules-node-js-and-the-michael-jackson-solution-828dc244b8b)\n- [A 10 minute primer to JavaScript modules, module formats, module loaders and module bundlers](https://www.jvandemo.com/a-10-minute-primer-to-javascript-modules-module-formats-module-loaders-and-module-bundlers/)\n- [JavaScript Modules: A Beginner’s Guide](https://medium.freecodecamp.org/javascript-modules-a-beginner-s-guide-783f7d7a5fcc)"
  },
  {
    "path": "Deprecated/CORS(Cross-Origin Resource Sharing).md",
    "content": "# CORS(Cross-Origin Resource Sharing)\n\n## Same Origin Policy\n\n기본적으로 HTTP 요청은 Cross-Site HTTP Requests가 가능하다.\n\n즉, `<img>`, `<link>`, `<script>` 태그로 **다른 도메인의 이미지, CSS, 자바스크립트 라이브러리를 가져오는 것이 가능**하다.\n\n하지만, `<script></script>`내의 스크립트에서 생성된 HTTP Request는 **Same Origin Policy**가 적용되기 때문에 Cross-Site Http Requests 가 불가능하다. \n\n**Same Origin Policy**란 다른 출처의 Resource와의 통신을 제한하는 보안 방식이다. 출처가 같다는 것은 현재 페이지와 동일한 프로토콜, 포트, 호스트를 갖는 것을 말한다. 따라서, Cross-Site Http Requests가 불가능하다는 것은 Http Request가 그 페이지와 같은 서버에 있는 주소로만 전달될 수 있다는 것을 말한다. \n\n그러나, `AJAX`가 널리 사용되면서 `<script></script>`로 둘러싸여 있는 스크립트에서 생성되는 **XMLHttpRequest에 대해서도 Cross-Site HTTP Requests가 가능해야 한다는 요구**가 늘어났고 W3C에서 **CORS**라는 이름의 권고안이 나오게 되었다.\n\n<br/>  \n\n## CORS\nCORS는 Same Origin Policy에 반해 외부 요청을 허용하는 방식 중 하나이다. 서버에서 외부 요청을 허용함으로써 다른 출처의 스크립트, 문서 등을 주고 받을 수 있다. CORS 요청의 종류 중 하나로 **Preflight**이 있다. \n\n### Preflight Request\n\n![preflight-process](/assets/images/preflight-process.png)\n\n`Preflight Request`는 사전 요청과 본 요청으로 나뉘어 전송된다. \n\n요청하는 URL이 외부 도메인일 경우에, **브라우저에서는 서버에 사전 요청을 먼저 보낸다.**\n\n사전 요청(Preflight Request)을 보내 **요청할 수 있는 권한을 확인하는 것**이다.\n\n요청이 허용된 경우 본 요청을 서버에 전송하게 된다.\n\n따라서 서버 측에서는 사전 요청을 처리할 수 있는 기능이 추가되어야 한다.\n\n<br/>\n\n### Request 헤더\n\n---\n\n|           HTTP Header            |          Description           |\n| :------------------------------: | :----------------------------: |\n|   Origin    |     요청을 보내는 `페이지 출처`     |\n| Access-Control-Request-Method |    실제 요청하려는 `메서드`     |\n|   Access-Control-Request-Headers   |    실제 요청에 포함된 `헤더` 설정     |\n\n\n<br/>\n\n### Response 헤더 - 요청 핸들링\n\n---\n\n|           HTTP Header            |          Description           |\n| :------------------------------: | :----------------------------: |\n|   Access-Control-Allow-Origin    |     접근 가능한 `url` 설정     |\n| Access-Control-Allow-Credentials |    접근 가능한 `쿠키` 설정     |\n|   Access-Control-Allow-Headers   |    접근 가능한 `헤더` 설정     |\n|   Access-Control-Allow-Methods   | 접근 가능한 `http method` 설정 |\n|   Access-Control-Max-Age   | 캐시 유지 시간 |\n\n\n예제\n```java\nAccess-Control-Allow-Origin : *  //(1)\nAccess-Contorl-Allow-Credentials : true //(2)\nAccess-Control-Allow-Headers : X-Requested-With, Content_Type, Origin, Accept, Access-Control-Request-Method, Access-Control-Request-Headers, Authorization   \nAccess-Control-Allow-Methods : GET, POST, DELETE, OPTIONS // (3)\nAccess-Control-Max-Age : 3600 //(4)\n```\n(1) * 이면 모든 도메인의 요청을 허용한다.  \n(2) request에서 쿠키를 통해 자격 증명을 하는 경우 true로 지정해줘야 요청이 성공된다.  \n(3) `GET`, `POST`, `DELETE`, `OPTIONS` 메소드를 허용한다. 특히 `OPTIONS`메소드는 `Preflight request`를 받기 위해 허용해줘야한다.     \n(4) `Preflight request` 캐시를 유지할 시간을 말한다. 3600은 1시간으로, 1시간 동안 서버에 재요청을 하지 않아도 된다.\n\n<br/>\n\n위의 **`Request Header` 값을 보고 서버 측에서는 `Response Header`에서 해당 도메인(Origin)에 해당하는 요청 스펙을 알려주면 된다.** \n\nSpring Framework에서는 Filter나 Interceptor를 이용해 구현하거나 CORS를 서포트 해주는 어노테이션으로 구현할 수 있다.\n\n<br/>\n\n## JSONP(JSON with Padding)\n\nCORS 구현이 안되어 있는 서버로 접근하고자 할 때 Same Origin Policy를 회피할 수 있는 방법 중 하나로 JSONP가 있다.\n\n위에서도 말했듯이 `<scirpt>`로 받아오는 리소스 파일은 Same Origin Policy에 영향을 받지 않고, 받아올 수 있다. \n\n이러한 점을 이용해 **서버에서 js 리소스 파일을 읽어오듯이 요청에 대한 결과를 json으로 바꿔주는 방식**이다. \n\n`Jsonp` 는 Json 데이터가 들어 있는 함수 형태의 데이터를 받아서 내 함수를 호출 하는 방식으로 실행된다.\n\n```js\n$.ajax({ \n    url: url, \n    dataType: 'json', \n    data: data, \n    success: \n    callback \n}); \n\n$.getJSON(url, data, callback); \n```\n\n```js\n$.ajax({ \n    url: url, \n    dataType: 'jsonp', \n    jsonpCallback: \"myCallback\", \n    success: callback \n}); \n\n$.getJSON(url + \"?callback=?\", data, callback);\n```\n\n여기서 알아야 할 것은 **Callback 함수명으로 감싸주는 것은 클라이언트 단에서 지원하여 처리해주는 것이 아니다.**\n\n서버에서 감싸진 형태의 Text로 내려주어야 한다.\n\n하지만 GET 방법만을 지원하고 보안상 이슈로 인해 CORS 방법을 추천하는 분위기라고 한다.\n\n<br/>\n\n## \n\n---\n\n#### Reference\n\n- [Cross Origin Resource Sharing - CORS](https://homoefficio.github.io/2015/07/21/Cross-Origin-Resource-Sharing/)\n- [JSONP 알고 쓰자](http://kingbbode.tistory.com/26)\n- [javascript ajax 크로스 도메인 요청하기(CORS)](http://enterkey.tistory.com/409)\n- [CORS 크로스 도메인 이슈 (No 'Access-Control-Allow-Origin' header is present on the requested resource)](http://ooz.co.kr/232)\n- [Enabling Cross Origin Requests for a RESTful Web Service](https://spring.io/guides/gs/rest-service-cors/)\n- [javascript ajax 크로스도메인 요청-CORS](https://brunch.co.kr/@adrenalinee31/1)\n"
  },
  {
    "path": "Deprecated/CSS 애니메이션 vs JS 애니메이션.md",
    "content": "# CSS 애니메이션 vs JS 애니메이션\n\n<br/>\n\n## CSS 애니메이션\n\n다음 코드는 W3C tutorial에 있는 코드를 가져와 CSS 애니메이션으로 수정한 코드다.\n\n```html\n<button onclick=\"myMove()\">Click Me</button> \n\n<div id =\"container\">\n<div id =\"animate\"></div>\n</div>\n```\n\n```css\n#container {\n  width: 400px;\n  height: 400px;\n  position: relative;\n  background: yellow;\n}\n#animate {\n  width: 50px;\n  height: 50px;\n  position: absolute;\n  background-color: red;\n}\n\n.animation-move {\n  animation: move 4s\n}\n/* @keyframes rule */\n@keyframes move {\n    from {\n        left: 0;\n        top : 0;\n    }\n\n    to {\n      \ttop : 350px;\n        left: 350px;\n    }\n}\n```\n```javascript\nfunction myMove() {\n  var elem = document.getElementById(\"animate\");   \n  elem.className = \"animation-move\";\n}\n```\n\n**CSS 코드를 보면 `@keyframes`를 사용하여 애니메이션명을 지정하고 이를 `animation-move`라는 클래스 명을 가지는 요소**에 입히고 있다.\n\n그에 따라 버튼을 클릭하면 `div`요소에 `animation-move`라는 클래스를 먹인다. \n\n* [@keyframes에 관한 구체적인 예시](https://poiemaweb.com/css3-animation)\n\n### 트랜지션 vs 애니메이션\n\n---\n\n#### 트랜지션\n\n> * 요소의 변화를 일정 기간(duration)동안 일어나게 함\n> * `hover`나 `click` 같은 **이벤트 트리거에 의해 동작**\n> * layout을 변경시킬 경우, reflow 발생을 줄이기 위해 **낮은 계층의 요소에 효과를 주는 것이 좋음**\n\n#### 애니메이션\n\n> * 트랜지션은 시작하기 위해 이벤트가 필요하지만 애니메이션은 **시작, 정지, 반복까지 제어 가능**(물론, 이벤트 제어도 가능)\n> * 하나 또는 복수의 **`@keyframes`으로 이루어짐**\n\n<br/>\n\n## JS 애니메이션\n\n```html\n<button onclick=\"myMove()\">Click Me</button> \n\n<div id =\"container\">\n<div id =\"animate\"></div>\n</div>\n```\n\n```css\n#container {\n  width: 400px;\n  height: 400px;\n  position: relative;\n  background: yellow;\n}\n#animate {\n  width: 50px;\n  height: 50px;\n  position: absolute;\n  background-color: red;\n}\n```\n\n```javascript\nfunction myMove() {\n  var elem = document.getElementById(\"animate\");   \n  var pos = 0;\n  var id = setInterval(frame, 5);\n  function frame() {\n    if (pos == 350) {\n      clearInterval(id);\n    } else {\n      pos++; \n      elem.style.top = pos + 'px'; \n      elem.style.left = pos + 'px'; \n    }\n  }\n}\n```\n\nJS애니메이션으로 위의 CSS애니메이션과 같은 효과를 먹인 코드다.\n\n**JavaScript 코드를 보면 `setInterval`을 주고 일정 주기마다 `frame()` 함수를 실행시켜 요소의 위치를 이동**시키고 있다.\n\n<br/>\n\n## CSS 애니메이션과 JS 애니메이션의 차이\n\nCSS 애니메이션은 낮은 버전의 브라우저에서는 지원을 하지 않는 경우가 있다.(특히, IE). \n\n즉, **1. 크로스 브라우징면에서는 JS 애니메이션을 사용하는 것이 낫다.**\n\n하지만, CSS 애니메이션은 **모든 동작을 CSS에서 관리하고 필요하다면 JS는 이벤트 감지를 위해서만 사용**한다.\n\n**2.실행 로직을 브라우저 자체에서 실행하기 때문에 메모리 소비를 최적화**해준다.\n\n**3. JavaScript에서는 css, 동작을 모두 관리해줘야하는 반면, CSS애니메이션은 CSS안에서 다 관리하기 때문에 관리에 용이하다.**\n\n<br/>\n\n## velocity.js\n\n사실상, **CSS 애니메이션을 사용하는게 생각보다 JS 애니메이션과 비교해서 빠르지 않다.** 오히려, JS 애니메이션이 더 빠를 수 있다.\n\n하지만, **CSS 애니메이션이 jQuery의 `animate()`를 사용하는 것보단 빠르다.**\n\n결론부터 얘기하자면, **velocity.js, GSAP과 DOM 라이브러리로 구현했을 때, CSS와 jQuery 라이브러리로 애니메이션을 구현했을 때 보다 빠르다.**\n\n> * 8K 밖에 되지 않는 라이브러리\n> * jQuery의 `animate()`를 `velocity()`로만 바꿔줘도 사용 가능\n> * `setInterVal()`이 아닌 `requestAnimationFrame()`을 사용하기 때문에 **브라우저가 최적의 상태인지 판단하고 실행**\n> * 3d-transform과 같은 애니메이션에는 CSS의 작성이 필요함.\n\n<br/>\n\n---\n\n#### Reference\n\n- [CSS vs. JS Animation: Which is Faster?](https://davidwalsh.name/css-js-animation)\n- [CSS Animation](https://poiemaweb.com/css3-animation)\n- [CSS와 자바스크립트 애니메이션](https://developers.google.com/web/fundamentals/design-and-ux/animations/css-vs-javascript?hl=ko)\n\n"
  },
  {
    "path": "Deprecated/CallByReference.md",
    "content": "# Call By Value VS Call By Reference\n\n<div align=center>\n\n![Main_pic](https://github.com/SeonHyungJo/FrontEnd-Dev/blob/master/assets/image/CallByValue.png?raw=true)\n\n</div>\n\n## :speech_balloon: Contents\n\n- 평가전략\n- [Parameter, Arguments](#Parameter,-Arguments)\n- [Call By Value](#Call-By-Value)\n- [Call By Reference](#Call-By-Reference)\n- Call By Sharing\n\n<br/>\n\n> [평가 전략(Evaluation Strategy)](https://ko.wikipedia.org/wiki/%ED%8F%89%EA%B0%80_%EC%A0%84%EB%9E%B5_(%EC%BB%B4%ED%93%A8%ED%84%B0_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D)) 은 프로그래밍 언어에서 함수 호출의 아규먼트(argument)의 순서를 언제 결정하고 함수에 어떤 종류의 값을 통과시킬지 결정하는 것이다.\n\n**함수에 인자로 무엇을 넣는냐에 따라 함수가 어떻게 실행이 될 것인지?**\n\n<br/>\n<br/>\n\n## Parameter, Arguments\n\nparameter는 **함수 선언부**에 정의\n<br/>\narguments는 **함수 호출부**에서 사용\n\n<br/>\n\n```js\nvar a = 1;\nvar func = function(b) { // parameter, formal parameter, 매개변수, 형식 매개변수\n  // code...\n};\nfunc(a); // arguments, actual parameter, 인자, 실인자\n```\n\n<br/>\n\n## Call By Value\n\n### 기본특성\n\n1. Arguments로 값이 넘어온다.\n2. 값이 넘어올 때 복사된 값이 넘어온다.\n3. Caller(함수를 호출하는)가 인자를 **복사해서 넘겨줬으므로** Callee(함수)에서 해당 인자에 변경을 하고 수정을 한다고 해도 Caller는 영향을 받지 않는다.\n\n<br/>\n\n```js\nvar value = 1;\nvar func = function(value) { // callee\n\n    console.log(value) // 1\n    value = value + 1;\n    console.log(value) // 2\n}\n\nfunc(value); // caller\nconsole.log(value); // 1\n```\n\n<br/>\n\n값의 복사본인 함수 인자 `value` 는 해당 수의 **지역변수로 선언되고 정의되었다.**\n<br/>\n\n즉, 전역변수로 선언 및 정의된 `value` 는 문자열과는 \"+\" 연산자를 통해 합쳐지지 않는다.\n<br/>\n\n간단한 실험 문자열 비교를 통해 값에 의해서 비교가 되는지 확인할 수 있다.\n<br/>\n\n만약 두 문자열이 값에 의해 비교되면 두 문자열은 동일할 것이고 참조에 의해 비교되면 동일하지 않을 것이다.\n\n```js\nvar s1 = 'hello';\nvar s2 = 'hell' + 'o';\n\nconsole.log(s1 === s2); //true\n\nvar obj1 = {\n    str: 'hello'\n}\n\nvar obj2 = {\n    str: 'hell' + 'o'\n}\n\nconsole.log(obj1.str === obj2.str); //true\n```\n\n<br/>\n\n## Call By Reference\n\n### 기본특성\n\n1. Arguments로 reference(**값에 대한 참조 주소, 메모리 주소를 담고있는 변수**)를 넘겨준다.\n2. reference를 넘겨서 해당 reference가 가리키는 **값을 복사하지는 않는다.**\n3. Caller(함수를 호출하는)가 인자를 복사해서 넘기지 않았으므로 Callee(함수)에서 해당 인자에 변경을 하고 수정을 하면 Caller는 영향을 받는다.\n\n<br/>\n\n```js\nvar obj = {};\nvar func = function(obj) { // callee\n  obj.a = 1;\n}\n\nfunc(obj); // caller\nconsole.log(obj.a); // 1\n```\n\n<br/>\n\n객체를 정의한 `obj` 전역 변수는 함수의 매개변수로 \"값\" 과 \"복사본\"이 아닌 값에 의한 **참조가 지역변수로 전달 되었기 때문에** 내부에서 언제든 참조값 수정이 가능하게 되었다.\n<br/>\n\n> 기본적으로 자바스크립트는 참조 타입을 arguments로 넘겨주면 call by reference의 형태로 작동한다.\n\n따라서 caller가 객체 `obj` 를 parameter로 넘겼을 때 실제 arguments로 넘어오는 값은 객체 `obj` 에 대한 reference이지 복사된 객체 `obj` 가 아니다.\n\n> 따라서 callee 내부에서 영향을 받기 때문에 조심해서 사용해야한다.라고들 오해하고 있다.\n\n<br/>\n\n## Call By Sharing\n\n```js\nvar obj = {};\nvar func = function(obj) { // callee\n  obj = 1;\n}\n\nfunc(obj); // caller\nconsole.log(obj); // {}\n```\n\n<br/>\n\n참조 타입을 넘겼는데 값이 변하지 않았다.\n<br/>\n\n**자바스크립트에서는 무조건 Call By Value로 작동하기 때문이다.**\n<br/>\n\n사람들이 참조 타입을 넘기면 Call By Reference로 작동한다고 알고있으나, 위 코드가 그 생각은 잘못됬다는 것을 알려주고 있다.\n<br/>\n\n자바스크립트(자바, 루비, 파이썬 등등도 마찬가지…)에서는 참조 타입을 인자로 넘기면 참조값에 대한 복사본을 만들어서 넘긴다.\n\n<br/>\n\n![CallBySharing](https://github.com/SeonHyungJo/FrontEnd-Dev/blob/master/assets/image/CallBySharing.png?raw=true)\n\n<br/>\n\n### Quiz\n\n```js\nvar a = {};\nvar func = function(b) {\n  b = b.a = 1;\n  b.b = 2;\n\n  console.log(b); // ??\n  console.log(b.b); // ??\n}\n\nfunc(a);\nconsole.log(a); // ??\nconsole.log(a.b); // ??\n```\n\n<br/>\n\n## 결론\n\n- 자바스크립트에서 `Call By Reference`는 존재하지 않고 `Call By Value`만 존재한다.\n- 참조 타입을 인자로 넘기면 참조값에 대한 복사본이 넘어간다.\n- 혼동을 줄이고자 `call by sharing`이란 용어로 부르기도 한다.\n\n---\n\n#### Reference\n\n- [무하프로젝트](http://mohwaproject.tistory.com/entry/%EC%9E%90%EB%B0%94%EC%8A%A4%EB%A6%BD%ED%8A%B8%EC%97%90%EC%84%9C-%EA%B0%92%EA%B3%BC-%EC%B0%B8%EC%A1%B0%EC%9D%98-%EC%B0%A8%EC%9D%B4)\n- [자알쓰](https://blog.perfectacle.com/2017/10/30/js-014-call-by-value-vs-call-by-reference/)\n\n## 번외\n\n아래는 간단한 객체 상속 관계에서 참조값을 다루는 코드예제이다.\n\n```js\nfunction fn(){}\nfn.prototype = {'arr': []};\nnew fn().arr.push(1);\n\nconsole.log(new fn().arr); // 1\nconsole.log(fn.prototype.arr); // 1\n```\n\n왜 [1]이 반환되는 걸까?\n\n- 첫번째 반환 => 또 다시 자식을 new로 생성을 하여 arr값을 가져왔더니 이미 [1]이라는 것이 담겨있었다.\n\n- 두번째 봔환 => 기존에 만들어 놨던 fn(){}에서 protptype.arr만 만들었는데 자식에서 추가를 했음에도 불구하고 fn.prototype.arr에 [1]이 담겨있다.\n\n\"자바스크립트\" 에서 객체는 참조만 전달되기 때문이다. 즉, 자식( new fn() ) 객체 에서 속성 ({'arr': []})  값을 수정하면 부모 객체 속성 ({'arr': []}) 또한 수정되어 버립니다."
  },
  {
    "path": "Deprecated/EventLoop.md",
    "content": "# 자바스크립트의 이벤트루프와 콜백함수\n\n## 이벤트루프와 싱글 쓰레드\n\n자바스크립트와 콜백은 뗄레야 뗄 수 없는 관계라고 생각한다. 흔히들 자바스크립트는 싱글쓰레드 기반이라고 얘기합니다. 그게 바로 이벤트루프가 싱글 쓰레드기 때문에 하는 얘기다. 그럼 이 이벤트 루프는 무엇일까?\n\n## 자료구조\n\n스택은 밑이 비어있는 컵 모양에 넣고 빼는 것이며 큐는 양쪽이 뚫려있는 튜브라고 말한다. 스택은 LIFO이며 큐는 FIFO다.\n\n이 자료구조는 자바스크립트 엔진에서 사용됩니다. 바로 호출 '스택'과 태스크 '큐'입니다.\n\n호출 스택은 어느 언어에서도 존재한다. 쉽게 생각하자면 [main(), a(), b()] 구조로 호출되면 b -> a -> main 순으로 빠져 나간다. 자 그러면 이제 `setTimeout()`을 생각해보자.\n\n```js\nfunction foo() {\n  console.log('b');\n}\nconsole.log('a');\nsetTimeout(foo, 0);\nconsole.log('c');\n```\n\n이러면 출력결과는 당연히 a -> c -> b가 된다.. 의사코드로 소스를 분석해봅시다.\n\n1. a를 출력해라\n2. 0초 뒤에 foo를 실행해라\n3. c를 출력해라\n\n그렇다면 a -> b -> c가 되어야 하는것 아닐까 할 수 있다. 이는 호출스택에서는 당연히 맞지만 자바스크립트에서는 그렇지 않다. 자바스크립트는 호출 스택만 사용하지 않기 때문이다. 자바스크립트는 호출스택, 백그라운드, 태스크 큐(es6+부터는 큐 관리방식이 변화되어 태스크 큐 이외도 존재)라는 개념이 존재한다.\n[자바스크립트 비동기 작업 3가지](./EventLoop_Advanced.md)\n\n![eventLoop](/assets/images/EventLoop.png)\n\n이런 구조입니다. 자 이제 코드대로 생각을 해보자.\n\n1. main() 스택에 들어감\n2. log(\"a\") 도 스택에 들어간 뒤 실행\n3. setTimeout()이 스택에 들어간 뒤 실행 - 백그라운드에서 0초뒤에 foo를 \"실행\"시키라고 명령\n4. 0초가 지나 \"태스크큐\"에 foo()들어감\n5. log(\"c\") 가 스택에 들어간 뒤 실행\n6. main() 종료\n7. 태스크 큐에 있던 foo()를 호출스택에 밀어넣음 (이벤트 루프가 전역 컨텍스트의 main이 종료되면 큐 실행)\n8. foo()가 호출스택에 들어간 뒤 실행\n\n이래서 결과가 위와 같았다.\n\n## 콜백함수\n\n이런 자바스크립트의 싱글 쓰레드 구조에서 비동기성의 이벤트 기반 실행이나 ajax요청이 필요하다면, 콜백 함수를 이용해 백그라운드로 보내고 큐를 통해 호출 스택으로 보내 해결하게 된다.\n\n자바스크립트에서는 쓰레드를 통해 병렬처리가 안되기 때문에 콜백함수의 사용은 뗄 수가 없게 되는 것이다.\n\n## 큐와 콜백\n\n이러한 이벤트 루프의 가장 중요한 점은 바로 위 과정의 3번과 4번 그리고 7번이다. 흔히 setTimeout(foo, 3)이라는 함수를 말할 때 foo 함수를 3초 뒤에 실행시켜라 라고 생각한다. 그러나 4번에 보듯 foo는 일정시간 뒤에 실행되는게 아니라 큐에 들어가게 된다.\n\n3번에 `백그라운드에서 0초뒤에 foo를 \"실행\"시키라고 명령`이라고는 적었지만 정확히 말하자면 `foo를 \"큐\"에 집어넣어라` 가 맞는 것이다. 큐에 아무것도 없다면 3초뒤에 바로 실행이 되겠지만 만일 다른 콜백으로 인해 다른 작업들이 존재한다면 어떻게 될까??\n\n맞다. 3초가 넘어가서 실행되게 됩니다. setTimeout()이라는 함수는 n초 뒤에 콜백을 단순히 큐에 집어넣는게 끝이다. 이 큐에 들어간 콜백은 이벤트 루프가 스택으로 밀어넣어 실행된다다. 코드를 간단히 보자면 아래와 같다.\n\n```js\nvar eventLoop = [];\nvar event;\n\nwhile (true) {\n  // 틱!\n  if (eventLoop.length > 0) {\n    event = eventLoop.shift();\n  }\n\n  try {\n    event(); // 호출스택으로 밀어넣는다\n  } catch (err) {\n    //...\n  }\n}\n```\n\n이 큐에 이미 대기번호가 100개가 있다면 foo는 101번째 대기표를 받게 될 것이다. 따라서 setTimeout()은 지정한 시간동안은 실행되지 않는 것은 보장할 수 있지만 지정한 시간에 실행되는것은 보장할 수 없다!\n\n## 현재 이벤트 루프\n\nes6+부터는 잡큐와 같은 새로운 개념이 등장하고 promise를 이용해 콜백을 처리하게 되는데 이는 나중에 더 다루도록 하겠습니다.\n[자바스크립트 비동기 작업 3가지](./EventLoop_Advanced.md)\n"
  },
  {
    "path": "Deprecated/EventLoop_Advanced.md",
    "content": "# EventLoop_Advanced\n\n## 브라우저에서 비동기 작업을 해보자\n\n1. 자바스크립트 비동기 작업 3가지\n2. `RequestAnimationFrame`에 대해서 자세히 알아보기\n3. `MutationObserver, ResizeObserver, intersectionObserver`\n\n<br/>\n\n## 자바스크립트 비동기 작업 3가지(크롬 기준)\n\n자바스크립트는 본래 싱글스레드를 기반으로 작동을 했었다. 그러나 구글에서 비동기 호출이라는 것을 선보이면서 더이상 웹에서는 라우터로 이동을 해야만 화면전환이 되는 등의 비동기 작업이 가능해졌다. \n<br/>\n\n그 당시에 `Jquery` 로 보자면 `Ajax` 일 것이다. 그러만 구현부를 뜯어보지는 않았지만 `setTimeOut()` 이나 `xmlHttpRequest()` 로 구현이 되어있을 것으로 생각이 된다.\n<br/>\n\n이후에도 자바스크립트의 발전과 브라우저의 발전으로 다양한 방법으로 비동기를 할 수 있는 수단이 생겼다. \n<br/>\n\n그 중에서 우리가 아는 것도 있을 것이라 생각한다.\n<br/>\n\n이번 내용은 정말 알아두면 정말 자신에게 좋을 만한 내용이다. 기존 내용 [Event loop](https://github.com/SeonHyungJo/FrontEnd-Dev/blob/master/Browser/EventLoop.md) 에서 나온 내용을 보면 브라우저에는 비동기를 지원하기 위한 Event loop가 있다고 되어있다. 여기 Event loop에 있는 Event queue를 자세히 살펴보게 되면 3가지로 나눌수 있게 된다.\n<br/>\n\n1. `setTimeOut(Task Queue)` : 가장 사람들이 잘 알고 있는 비동기 작업의 하나\n2. `Promise(Micro Task Queue)` : ES8에 `Async Await`(Async Await도 결국 Promise이지만)\n3. `AnimationFrame`\n\n<br/>\n\n크게는 이렇게 3개로 볼 수 있다. 어느 블로그를 가더라도 거의 위의 2가지를 설명해주고 있다.(다른 자료를 찾아보세요.)\n<br/>\n\n:point_right: 질문\n\n- 위의 3가지의 우선순위는 어떻게 되나?\n\n위에 보이듯이 우리가 잘 알고있는 `setTimeOut, setInterval`은 `Task Queue` 에 `Promise, async` 는 `Micro Task Queue` 에 들어가게 된다.\n<br/>\n\n그리고 다른 한가지 `AnimationFrame` 는 그냥 `AnimationFrame` 이라고 하자 하나의 `Web API` 이니까(브라우저별로 다름). 먼저 그렇다면 어떤것이 먼저 실행되고 끝나는지 예제를 보고 해보자.\n<br/>\n\n```js \nconsole.log('script start'); \n\nsetTimeout(function() { \n  console.log('setTimeout'); \n}, 0); \n\t\nPromise.resolve()\n  .then(function() { \n    console.log('promise1'); \n  })\n  .then(function() { \n    console.log('promise2'); \n  }); \n\nconsole.log('script end');\n```\n\n<br/>\n\n---\n**Task**\n\n---\n**Micro Task**\n\n---\n**jsStack**\n\n---\n**log**\n\n---\n\n<br/>\n\n### 참고 및 예제 문제\n\n- [예제 문제](https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules)\n\n`setTimeOut` 하나의 `Run script` 가 마무리가 되어야 실행이될 수 있다. 프로미스는 하나의 `script`에서 실행된다. \n<br/>\n\n이부분에서 순서의 차이가 일어난다.위의 결과는 맞춰보자\n<br/>\n\n다른 예제 2개도 풀어보기 [살펴보기]((https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules)) <= Event Click 문제 풀기\n<br/>\n\n## AnimationFrame(RequestAnimationFrame)_크롬 기준\n\n1. [`RequestAnimationFrame`와 `requestIdleCallback` 에 대해서](https://www.slideshare.net/deview/133-vsync)\n2.  예제 파일로 돌려보기(애니메이션 효과 => 물론 js)\n\n<br/>\n\n## MutationObserver, ResizeObserver, intersectionObserver\n\n1. MutationObserver : https://codepen.io/seonhyungjo/pen/pQqOpv\n2. InteractionObserver : https://codepen.io/seonhyungjo/pen/wQQYdz\n3. ResizeObserver : https://codepen.io/seonhyungjo/pen/pQqOBy\n   \n\n### MutationObserver\n\n돔 변형에 감지, 대응하기 위해 제공되는 `API`로 `Mutation Events`를 대체할 목적으로 설계됨\n\n`MutationObserver`가 `MutationEvent`와 다른점\n\n- 비동기\n- 변형시마다 바로 실행 되는 것이 아니라 `Micro Task` 마지막에 배치로 DOM 변형들(Array 형태의 MutationRecord)을 콜백에 전달함\n\n```js\nlet mo = new MutationObserver((mutations, thisMo) => {\n  mutations.forEach(mutation => {\n    // 개별 변형 대응\n  });\n});\n\nlet target = document.querySelector(\"body\");\nlet options = {\n childList: true,\n attributes: true,\n subtree: true,\n characterData: true\n};\n \nmo.observe(target, options);\n```\n\n### MutationObserverInit\n\n- childList : 타겟 노드의 자식 엘레멘트(텍스트 노드를 포함)들의 추가 혹은 제거를 관찰해야할 때 true\n- attributes : 타겟 노드의 속성들의 변형들을 관찰해야할 때 true\n- characterData : 타겟 노드의 데이터를 관찰해야할 때 true\n- subtree : 타겟 노드부터 자손 노드들의 변형들까지 관찰해야할 때 true\n- attributeOldValue : attributes이 true면서 타겟 노드의 변경된 속성들 이전 값을 기록해야할 때 true\n- characterDataOldValue : characterData true면서 타겟 노드의 변경된 데이터 이전 값을 기록해야할 때 true\n- attributeFilter : 모든 속성들을 관찰하고 싶지않을 때 관찰할 속성명의 Array"
  },
  {
    "path": "Deprecated/Funtional.md",
    "content": "# Functinonal Programming\n\n<div align=center>\n\n![Main_pic](https://github.com/SeonHyungJo/FrontEnd-Dev/blob/master/assets/image/Functional_Programming_Main.png?raw=true)\n\n</div>\n\n## :speech_balloon: Contents\n\n- [Introduction](#introduction)\n- [What is Funtional Programming :question:](#what-is-funtional-programming)\n    - [Immutable Data](#immutable-data)\n    - [순수함수](#순수함수)\n- [Why we use it again :question:](#why-we-use-it-again)\n\n<br/>\n\n## Introduction\n\n많은 함수형 프로그래밍관련 책들이 나오고 있다. 그렇다고 최신 개념도 아니다. 나온 것은 오래되었다. 그런데 왜 다시 주목을 받고 있을까?\n<br/>\n\n> 함수형 프로그래밍은 반응형 프로그래밍(즉, Reactive programming)에서 활용이 되어 더욱이 선행학습으로 좋다고 생각했다.\n\n<br/>\n\n## What is Funtional Programming\n\n### 함수형 프로그래밍(Functional Programming)\n\n- 먼저, 모든 것은 ***객체*** 이다.\n- 2가지 큰 특징\n    - :star: 순수함수\n    - :star::star: Immutable Data(불변하는 데이터)\n\n<br/>\n\n### 순수함수\n\n**먼저** 순수함수란\n\n1. 순수 함수는 같은 입력 값을 넣었을 때 항상 같은 출력 값을 반환한다.\n\n```js\n\n    function add(x){\n        return 10 + x;\n    }\n\n```\n\n2. 유용한 순수 함수는 최소 한 개의 매개변수를 가진다.\n\n```js\n\n    function(func){\n        func();\n    }\n\n```\n\n3. 유용한 순수 함수는 반드시 무엇인가를 반환한다.\n\n```js\n\n    return func(){};\n\n```\n\n**함수형 프로그래밍은 단순히 순수 함수를 작성하는 게 아니다.**\n\n함수형 프로그래밍은 **부작용을 제거할 수 없다.** 단지 그 부작용을 제어할 수 있을 뿐이다. 왜냐하면 프로그램은 실제 세계와 맞닿는 부분이 존재하기 때문에 몇몇 부분은 비 순수할 수 밖에 없다.\n<br/>\n\n목표는 비 순수한 코드를 최소한으로 줄이는 것이고, 그것들을 순수 함수로부터 구분을 하여 별도 공간에 분리시키는 것이다.\n<br/>\n\n### Immutable Data\n\n함수형 프로그래밍을 특징 중 하나는 바로 immutable data(불변의 데이터)\n\n> 예를 들어 List를 만든다고하자, 그렇다면 우리는 당연히 List에 추가 / 삭제가 일어나게 되면 기존의 List에 추가를 하려고 한다. <br> 그러나 이것은 기존의 List는 그대로 유지를 하되, 추가 또는 삭제가 일어나면 새로운 List를 만들어 return 한다. (이러한 자료구조를 Persistent Data Structure라고 한다.) 성능상에 문제가 있을 거라고 생각을 한다. 그러나 그렇지 않다??\n\n프로그래머가 바꾸고자하는 변수 외에는 바뀌어서는 안된다는 뜻으로 **즉 원본 데이터는 불변해야한다.**\n\n> 함수형 프로그래밍에서는 변수가 없다.\n\n우리는 코딩을 하다보면 당연하게 아래의 3가지를 사용한다.\n\n- 분기문(if ~ else ~)\n- 반복문(for, while...)\n- 변수(var)\n\n<br/>\n\n그러나 함수 반복은 **변함(Mutability)** 을 요구한다. 그렇기 때문에 좋지 않다.\n\n:point_right: 이에 반복문을 사용하는 것보다는 재귀를 사용해서 반복을 처리해야한다. 그러나 재귀에도 장점만 있는 것이 아니다. 재귀의 깊이가 길어지게 되면, 당연하게 `stack`이 많이 쌓이게 되어 `stack over flow`가 오게 된다.\n<br/>\n\n그렇다면 다른 방법은 없는 것인가?\n<br/>\n\n고차함수를 이용하자.\n\n> 함수형 프로그래밍에서는 함수라는 게 1급 시민이다. 다른 말로 함수는 또 다른 값일 뿐이다.\n\n우리가 잘 알고있는 `map`, `reduce`, `filter`가 여기에 속한다. 이 내용까지는 담기에 내용이 많아 링크를 걸어두었습니다.\n\n`map`, `filter`, `reduce` 각각의 함수는 `boilerplate`,  `for-loop`의 반복 없이 일반적인 배열의 조작을 가능하게 한다. **중요한 점은 Return값으로 기존 데이터를 넘기는 것이 아닌 새로 만들어서 Return 해준다.**\n\n> 고차함수는 함수를 매개변수로 받을 뿐만 아니라 함수를 반환하기도 한다.\n\n<br/>\n\n[:point_right: map, reduce, filter에 대해 알아보기](https://seonhyungjo.github.io/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%A0%95%EB%A6%AC-2/)\n\n<br/>\n\n위에서 간단하게 언급은 하였지만 고차함수는 함수를 매개변수로 받을 수 있고, 반환도 한다. 이 개념은 흔히 볼 수 있는 **클로저** 개념과 같다.\n\n> 클로저라는 것은 **함수에 대한 참조로 인해 계속 살아있는 함수의 스코프**다.\n\n그러나 자바스크립트에서 클로저는 문제가 있다 변수가 변할 수 있기 때문이다. 즉 봔환된 함수가 호출되는 동안은 값이 변경이 가능하다는 것이다.\n\n:point_right: **Closure Example**\n\n```js\n\nfunction grandParent(g1, g2) {\n    var g3 = 3;\n    return function parent(p1, p2) {\n        var p3 = 33;\n        return function child(c1, c2) {\n            var c3 = 333;\n            return g1 + g2 + g3 + p1 + p2 + p3 + c1 + c2 + c3;\n        };\n    };\n}\n\n```\n\n<br/>\n\n## Currying\n\n> 여러개의 인자를 가진 함수를 호출 할 경우, 파라미터의 수보다 적은 수의 파라미터를 인자로 받으면 누락된 파라미터를 인자로 받는 기법\n\n커링이란 함수형 프로그래밍 기법 중 하나로 함수를 재사용하는데 유용하게 쓰일 수 있는 기법이다.\n<br/>\n\n개발자라면 누구나 한 번짜놓은 코드가 있다면 다시 만들기 귀찮아한다. 이에 2개이상의 함수를 합성?을 하여 사용하면 정말 편하다고 생각할 것이다.\n<br/>\n\n```js\n\nfunction add(x, y){\n    return x + y;\n}\n\nfunction mult5(x){\n    return x * 5\n}\n\nvar mult5AfterAdd10 = value => mult5(add(10));\n\n```\n\n위의 예시는 어떤 값을 넣어서 10을 더하고 5를 곱하는 합성함수이다.\n그러나 내가 생각한대로 작동을 안한다. 이유는 당연히 `add()`에서는 2개의 인자를 받아야하는데 2개를 받아서 그런다.\n\n> 커링 함수는 한 번에 오직 **1개의 매개변수만 받는 함수**다.\n\n그런데 커링함수라 함은 1개의 매개변수만 받는 함수이다. 그렇다면 먼저 첫번째 매개변수를 받고, 나중에 나머지 한개를 받도록 하면되지 않을까?\n\n```js\n\nfunction add(x){\n    return function(y){\n        return x + y\n    };\n}\n\n// arrow function으로 한다면 이런 형태일 것이다.\nvar add = x => y => x + y\n\nadd(10)(5)\n\n```\n\n위에처럼 `add(10)(5)`처럼 하나씩 분리해서 받는 기법이 `커링`이다.\n이러한 기법은 여러 파라미터를 한번에 받지않고 부분적으로 받은 후 함수의 실행을 늦출 수 있다고 한다. (전체가 아닌 부분적으로 파라미터를 받는다고 해서 함수가 실행되지 않는다)\n<br/>\n\n## Why we use it again\n\n> 멀티코어가 기본이 되면서 ‘동시성' 처리에 함수형 프로그래밍이 강점을 보이기 때문이 아닐까.\n멀티 쓰레드 프로그래밍이 불과 몇 년전까지도 가능한 피해야 할 문제였다면 이제는 반드시 고려해야 하는 기본이 되었다.\n<br/>\n\n> 그러나 아직 보통의 많은 개발자들은 어려워한다. 준비가 덜 되어 있다.  \n\n가장 본질적인 장점은 `side-effect`에 의존한 코드에 비해 유지보수가 용이하다는 점, 코드를 이해하기 수월하다는 점이 있을 것이다.\n<br/>\n\n---\n\n#### Reference \n\n- [jooyunghan_medium](https://medium.com/@jooyunghan/%ED%95%A8%EC%88%98%ED%98%95-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EC%86%8C%EA%B0%9C-5998a3d66377)\n\n- [JaeYeopHan_github](https://github.com/JaeYeopHan/Interview_Question_for_Beginner/tree/master/Development_common_sense#object-oriented-programming)\n\n- [kakao tech](http://tech.kakao.com/2016/03/03/monad-programming-with-scala-future/)\n\n- [함수형-프로그래머가-되고-싶다고?](https://github.com/FEDevelopers/tech.description/wiki/%ED%95%A8%EC%88%98%ED%98%95-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EA%B0%80-%EB%90%98%EA%B3%A0-%EC%8B%B6%EB%8B%A4%EA%B3%A0%3F-(Part-1))\n\n<br/>\n\n---\n---\n\n## :unlock: 번외\n\n### :heavy_plus_sign: 모나드란?\n\n[모나드 참고사이트](https://www.haruair.com/blog/2986)\n\n모나드는 순서가 있는 연산을 처리하는데 사용하는 디자인패턴이다.\n<br/>\n\n모나드는 타입으로 감싸 빈 값을 자동으로 전파하거나 또는 비동기 코드를 단순화하는 등의 행동을 추가하는 역할을 한다.\n<br/>\n\n### :heavy_plus_sign: Immutable js\n\n자바스크립트에서 Immutable하게 만들어주는 라이브러리\n<br/>\n\n### :heavy_plus_sign: 반응형 프로그래밍(Reactive Programming)\n\n- **명령형 프로그래밍의 반대말** 이다.\n- **데이터의 흐름에서 시작** 된다."
  },
  {
    "path": "Deprecated/Higher_Order_Functions.md",
    "content": "# Higher Order Function\n\n## 코드의 복잡성\n\n큰 프로그램은 복잡성이 올라간다. 그 복잡성은 코드를 이해하기 어렵게 만들고 코드 간의 의존성을 높인다. 이러한 코드는 버그를 유발하고 유지보수가 어려워진다.\n\n흔히 프로그래밍을 공부하면 알 수 있는 원론적인 내용이다. 아래 코드를 비교해보자. 순서대로 1번과 2번 코드다.\n\n```js\nlet total = 0,\n  count = 1;\nwhile (count <= 10) {\n  total += count;\n  count += 1;\n}\nconsole.log(total);\n```\n\n```js\nconsole.log(sum(range(1, 10)));\n```\n\n두개의 코드는 완전히 동일한 기능을 한다. 물론 아래의 코드의 sum이나 range는 정의되지 않았다.\n역시 sum이나 range의 내부 코드가 얼마나 복잡하게 구현되어 있는지는 모른다.\n\n2번의 sum이나 range의 구현 코드는 1번의 코드의 loop이나 변수, 조건문이 똑같이 들어 있을 것이다. 따라서 **코드의 길이는 1번이 더 짧을 수 있다.**\n\n그러나 2번째 코드는 훨씬 **직관적** 이다. 1번 코드는 코드를 보면서 실행 플로우를 따라가야 한다. 아래의 코드는 1~10을 sum한다라고 직관적으로 이해할 수 있다.\n\n이렇게 훨씬 단순하게 표현하는 것을 프로그래밍에서 우리는 **추상화** 라 부른다.\n\n## 추상화\n\n> Abstractions hide details and give us the ability to talk about problems at a higher (or more abstract) level. - 자바스크립트 개론(Eloquent JavaScript)\n\n추상화는 상세한 것을 숨겨 문제를 higher level에서 이야기 할 수 있도록 하는 것이다.\n\nCS에서 low level과 high level은 아주 간단하게 말하면 얼마나 복잡하냐를 이야기한다. low-level일수록 더욱 구체적이며 high-level일수록 더욱 추상적이다.\n\nlow-level language는 기계어와 가까우며 high-level language는 인간의 언어와 더욱 가깝다.\n\n다시 돌아가서 추상화라는 것은 문제를 higher level에서 이야기 할 수 있게 만든다.\n\nhigher level에서 문제를 다룰수록 문제점을 더욱 명확하게 바라볼 수 있고, 단순하게 접근하여 큰 그림을 그릴 수 있게 된다.\n\n## Higher order function\n\n고차함수는 수학에서 온 단어로 아래 **두 조건 중 한 가지를 만족** 하는 함수다.\n\n- 하나 이상의 함수를 인수로 취한다.\n- 함수를 결과로 반환한다.\n\n고차함수는 값만이 아니라 동작을 추상화 시킨다. 즉 행위도 추상화에 포함이다.\n\n```js\nconsole.log(sum(range(1, 10)));\n```\n\n다시 예시를 가져오자면 이 예시는 1~10까지 나열하는 것, 모두 더하는 것이 추상화 된 결과다.\n\n### javascript HOF\n\n자바스크립트에서 함수는 일급객체다. 일급객체는 쉽게 설명해서 생성, 대입, 연산, 인자 또는 반환값으로서의 전달 등 기본 연산이 가능한 대상을 말한다.\n\n바로 위에서 설명하듯 인자 또는 반환값으로 전달이 가능하다.\n\n따라서 자바스크립트의 함수는 위의 두 조건을 만족할 수 있고 만족하게 코딩했다면 HOF일 수 있다.\n\n## 예시\n\n### 예시-1\n\nrepeat 예시를 가져와봤다. 일단 아래 코드를 보자. 0부터 99까지 출력하자.\n\n```js\nfor (let i = 0; i < 100; i++) {\n  console.log(i);\n}\n```\n\n요구사항이 변경되어 999까지 출력해보자. 그럼 100을 1000으로 변경하면 될 것이다. 근데 요구사항이 또 바뀔수 있지 않은가?\n\n```js\nfunction repeat(n) {\n  for (let i = 0; i < n; i++) {\n    console.log(i);\n  }\n}\n\nconsole.log(1000);\n```\n\n근데 요구사항이 출력이 아니라면 어쩔까...? 만약 배열로 만들어달라면 코드를 바꿀수도 있다. 코드를 바꾸자니 `repeat()`을 사용하는 다른 코드가 있을 수 있다. 또 배열과 출력을 동시에 해달라하면 또 바꿀건가??\n\n문제는 의존성을 줄이는 것이다. 이 때 필요한 것이 추상화다. 핵심 로직을 분기하고 변경이 있을 수 있는 부분을 분기한다.\n\n```js\nfunction repeat(n, fn) {\n  for (let i = 0; i < n; i++) {\n    fn(i);\n  }\n}\n\nrepeat(1000, console.log);\n\nconst list = [];\nrepeat(1000, i => list.push(i));\n```\n\n### 예시-2\n\n```js\nfunction unless(test, then) {\n  if (!test) then();\n}\n\nrepeat(3, n => {\n  unless(n % 2 == 1, () => console.log(n, 'is even'));\n});\n// → 0 is even\n// → 2 is even\n```\n\n이렇게 조건을 함수로 만들 수 도 있다. 만일 조건이 꽤나 복잡하다면 함수를 이용해서 추상화 시킬 수도 있다는 것이다.\n\n### 예시-3\n\n함수를 결과로 반환하는 예시는 자주 사용되는 map, filter, reduce, some, every같은 함수들이다.\n\n```js\nfunction filterExample(arr, fn) {\n  let resultArr = [];\n\n  for (let i = 0; i < arr.length; i++) {\n    resultArr.push(fn(arr[i]));\n  }\n\n  return resultArr;\n}\n\nfunction greaterThan(n) {\n  return m => m > n;\n}\n\nconst arr = [1, 2, 3, 4, 5];\n\nfilterExample(arr, greaterThan(3));\n```\n\n**위 코드는 실제 filter와는 다르다.** 단순 예제이다.\n함수를 리턴하여 추상화를 진행하였다. 위의 두 함수는 모르겠고 우리는 제일 아래 두 줄에 집중한다. arr을 만들고 3보다 큰지 안큰지만 알려달라고 행동을 추상화 했다.\n\n## 추가로...\n\nHOF는 함수형 프로그래밍과 연관된다. [함수형 프로그래밍](https://github.com/Im-D/Dev-Docs/blob/master/Language/Funtional.md) 이란 순수함수와 immutable, side effect 최소화와 관련이 있다.\n\n자세한 설명은 위로 대체하고, 간단하게만 해보자.\n\n함수형 프로그래밍은 람다 계산법에서 출발했다. 이는 수학의 람다식처럼 함수를 조합한다. 함수가 조합되려면 함수가 인자로 취급되어야 한다. 즉 HOF의 형태다.\n\nJavascript는 함수가 일급객체기 때문에 HOF가 가능하며 HOF가 가능하기에 함수형 프로그래밍이 가능하다.\n\n---\n\n### 참고자료\n\n- [Eloquent JavaScript - higher order functions](http://eloquentjavascript.net/05_higher_order.html)\n- [poiemaweb 고차함수](https://poiemaweb.com/js-array-higher-order-function)\n- [Higher-Order Function 이란 무엇인가](https://medium.com/@la.place/higher-order-function-%EC%9D%B4%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80-1c61e0bea79)\n"
  },
  {
    "path": "Deprecated/Javascript_BuildTool.md",
    "content": "# Webpack과 Gulp 그리고 Grunt\n\n현재 Build Tool의 대세는 당연코 Webpack이다. 그런데 이 이전에는 Gulp와 Grunt가 있었다. 나는 자바스크립트 빌드의 개념을 배울 때 이미 웹팩이 대중화되는 시기였다. 그래서 그냥 웹팩을 사용했다. 그런데 모든 새로운 기술에는 등장이유가 있으며 장점과 단점이 존재한다. 웹팩이 다른 기술들과는 어떤 차이점을 가지는지 간단하게 알아보자.\n\n## Webpack과 Gulp&Grunt는 태생부터 다르다\n\n### Gulp와 Grunt\n\n---\n\nwebpack과 gulp, grunt는 사실 아예 다르다. Gulp와 Grunt(이하 걸프로 통일하겠음)는 Task Runner라고 한다.\n용어로 얘기하면 되게 생소해 보이지만 별건 없다. 간단한 Task를 실행해주는 것이다. uglify나 압축등의 반복 가능한 간단한 작업을 자동화해주는 툴이다.\n\n### 서로의 차이점\n\n---\n\ngulp와 grunt의 하는일은 같지만 만들어내는 방식이 다르다. grunt는 package.json처럼 json형식으로 설정을 선언하여 사용한다. 이와 다르게 gulp는 nodeJS의 스트림 기능을 이용하여 자바스크립트 코드를 사용한다. 이건 현재 유행하는 기술도 아니고 크게 중요한 점도 아니니 넘어가도록 하자.\n\n## Webpack\n\n이전 툴들이 Task Runner인 것과 다르게 웹팩은 이름부터 다르다. `Module Bundler` 혹은 `Package Bundler` 라고 불린다. 모듈 개념은 이미 한 번 정리 했었다. [Module](./Module.md)\n\n### 모듈번들러\n\n---\n\n모듈 번들러가 뭐냐면 이 각각의 모듈들의 의존성을 파악하여 번들(묶는다)해주는 것이다. 모듈과 의존성이라는 단어가 낯설다. 이 단어들에 대해서 다시 생각해보자.\n\n### 모듈과 의존성\n\n---\n\n자바스크립트는 큰 소스를 나눠 편하게 개발하고 유지보수하기 위해 모듈이라는 추상적인 개념을 사용한다. 마치 클래스와 비슷하다 이렇게 모듈 방식으로 코딩을하고 거기에 모듈별로 파일까지 나누어 개발하면 참 좋다. 모듈과 파일이 분기된 개념은 보통은 노드JS에서 많이 사용한다.\n\n모듈화 된 각각의 파일들은 서로의 의존성을 가진다. 의존성이란 쉽게 말해 `import * from './index'` 이 구문이다. 현재 파일에서 다른 파일을 이용하게되면 서로 의존성이 생긴다.\n\n그런데 브라우저 상에서는 이러한 의존성을 표현하기가 어렵다. 특히 HTTP/1.1을 사용해야 하는 환경이라면 더욱 힘들다. HTTP/2.0의 경우 한 번의 요청에 여러 파일을 받아올 수 있지만 1.1의 경우는 의존성을 통해 여러 파일이 필요하게 된다면 너무 많은 네트워크 자원을 소모하게 된다.\n\n그러면 많은 의존성으로 엮인 JS파일들을 그냥 하나의 JS파일로 압축해서 만들면 어떨까?? 요청 한 번에 그 압축파일 하나만 주면 땡! 하게 말이다. 그게 웹팩이다. 꼭 하나는 아니다. 라이브러리 / 핵심 소스를 나누어 파일을 두개로 분기할 수도 있다. 요점은 다양한 파일들을 번들(bundle)해서 네트워크 비용을 최소화하여 파일을 번들한다! 라는 것이다.\n\nGulp나 Grunt처럼 필요한 자동화 기능까지 더해 빌드 해주는 것이 바로 모듈 번들러다.\n\n### 더 나아가\n\n---\n\n웹팩은 위에서 말한 자바스크립트의 의존성을 파악하여 번들하는 것만이 아니다. 모든 리소스(javascript, css, image, font, 심지어 typescript, coffeescript, less, sass 등)에 대한 dependancy graph를 생성하여 빌드 시켜준다. 요즘처럼 SPA를 구현하게 되면 이러한 의존성은 꼬리에 꼬리를 물고 Graph(Tree) 형태로 만들어지게 되는데 이걸 번들링하여 하나의 js 파일로 딱 만들어주는게 모듈 번들러의 역할이다.\n\n## 결론\n\n두 종류의 빌드 툴 모두 리소스들을 압축한다는 공통점이 있다.\n\nGulp나 Grunt는 단순 자동화 작업으로 파일을 압축하는 작업을 많이 하게 된다. 그러나 웹팩의 경우 자바스크립트의 각 모듈 혹은 파일, 심지어는 다양한 리소스들까지 의존성을 파악하여 묶어주기 때문에 엄청나게 큰 차이점을 보인다.\n\n따라서 현재 코드가 모듈화 된 코드가 아니거나, 다양한 의존성을 다루어야 하는 작업이 아니라면 Gulp나 Grunt도 충분히 좋은 빌드 툴이 될 수 있다. 그러나 꽤 준수한 프로젝트 규모를 가지거나, 자바스크립트를 모듈화하여 코딩하거나, 무거워질 수 밖에 없는 프레임워크를 사용하는 프로젝트 등에는 웹팩이 훨씬 더 좋은 툴이 될 것이다.\n"
  },
  {
    "path": "Deprecated/Module.md",
    "content": "# javascript의 module\n\nJava나 Python과 같은 OOP 언어들에서는 Class라는 이름으로 객체지향 프로그래밍을 구현해왔다. OOP의 보통 특징으로는 널리 알려져있듯 encapsulation, inheritance, polymorphism이 있다. 그 중 자바스크립트의 scope를 공부하고 있었는데 encapsulation과 관련이 있었으며, 자연스레 class와 비슷한 기능을 하는 자바스크립트의 module을 공부해봤다.\n\njavascript에서는 이 scope를 기준으로 캡슐화를 한다. 그래서 자연스레 이 scope를 이용하여 외부로부터 보호하려는 노력이 있어왔다. ES5에서는 함수가 scope의 기준이기 때문에 당연히도 함수의 scope를 이용해 encapsulation을 시도했다. 또한 자신의 스코프의 참조를 가진다는 클로저를 이용해 내부 속성들을 사용할 수 있게 했다.\n\n## ES 5의 모듈화\n\n크게 세가지가 있었다. IIFE(즉시실행함수표현식), 노출식 모듈 패턴, AMD다. 여기서 AMD는 크게 중요하지 않다고 생각되어 define을 사용한다고만 하고 넘어가겠다.\n\n### IIFE\n\n---\n\n함수를 즉시 호출시켜 스코프를 오염시키지 않는 방식이다.\n\n```js\nfunction moduleFunction() {\n\n  var a = 3;\n\n  function helloWorld(){\n    console.log('Hello');\n  }\n\n  return {\n    a : a,\n    sayHello: helloWorld\n  }\n}()\n\nmoduleFunction.sayHello();\ndoSomething(moduleFunction.a);\n```\n\n함수를 바로 실행시킨 뒤 object를 반환하여 전역 네임을 한번만 사용하여 스코프를 오염시키지 않는다. 또한 외부에서 내부 코드로의 접근을 차단하여 보호한다. 모듈의 개념을 잘 이행하고 있다. 다만 의존성관리가 되지 않는다. 코드를 재 작성하지 않으면 다른 파일에서 재사용이 불가능하다.\n\n### 노출식 모듈패턴\n\n---\n\nIIFE와 크게 다르는 않다. 반환값을 변수에 담으면 되는데 singleton 의 패턴이다.\n\n```js\nvar singleton = (function moduleFunction() {\n  var a = 3;\n\n  function helloWorld() {\n    console.log('Hello');\n  }\n\n  return {\n    a: a,\n    sayHello: helloWorld\n  };\n})();\n\nsingleton.sayHello();\ndoSomething(singleton.a);\n```\n\n비슷하다. 이 역시 문제는 의존성관리가 안된다.\n\n## Node JS의 모듈화\n\n의존성 관리 문제 때문에 ES5에서는 AMD, UMD, CommonJS 와 같은 모듈 포맷을 사용했는데 여기서는 가장 흔히 알려진 CommonJS방식에 대해 알아보자\n\n```js\nvar dep1 = require('./dep1');\nvar dep2 = require('./dep2');\n\nmodule.exports = function() {\n  // ...\n};\n```\n\n와 같은 구조다. 흔히 구글링한 코드에서 찾아볼 수 있는 `require`, `module.exports` 구조다. 외부의 dep1.js를 `module.exports`로 내보내고 `require()`로 불러와 사용하는 방식이다. 사실 내부적으로는 IIFE와 크게 다르지 않다. 내보낼 module을 파라미터로하여 IIFE를 실행시키고 반환하는 방식이다.\n하지만 파일 외부에서 작성하고 불러온다는 점에서 많이 나아진 방식이다.\n\n## ES 6 모듈\n\nES 6에서는 모듈을 사용하기 위한 내장 문법을 지원한다. 바로 `export`다.\n\n```js\n// some.js\nexport function helloWorld() {\n  console.log('Hello');\n}\n\nfunction somePrivateFunction() {\n  // ...\n}\n\n// ===========\n// ===========\n\n// something.js\nimport { helloWorld as hello } from './some';\n// import * from './some' 도 가능합니다.\n\nhello();\n```\n\n이렇게 하면 파일을 분리하고 그 파일에서 필요한 부분만 반환하여 사용할 수 있게 된다. 또한 재사용성이 극대화되어 의존성 관리도 가능하게 된다.\n\n현재 예제 코드에서는 함수만 반환했지만 당연히 object도 가능하다.\n\n또한 단일 값을 반환할 경우 default 형식을 지원한다. 이 경우 {} 를 사용하지 않아도 된다.\n\n```js\n// lib.js\n\n// Export default function\nexport default function sayHello(){\n  console.log('Hello');\n}\n\n\n// Export non-default function\nfunction sayGoodbye(){\n  console.log('Goodbye');\n}\n\n// Export simple value\nconst apiUrl = '...';\n\nreturnObject = {\n    goodbye : sayGoodbye,\n    apiUrl : apiUrl\n}\nexport returnObject;\n\n// Export object\nexport const settings = {\n  debug: true\n}\n\n// app.js\nimport sayHello, { returnObject, settings } from './lib';\n\nsayHello();\nreturnObject.sayGoodBye();\n```\n\n하지만 현재 이러한 모듈 포맷은 모든 브라우저에서 지원하지 않는다. 따라서 Babel과 같은 변환기를 통해 ES5에서 사용하던 방식인 AMD나 CommonJS 형식으로 코드를 변환한 뒤 사용한다.\n"
  },
  {
    "path": "Deprecated/Promise1.md",
    "content": "# Promise1\n\n## 콜백을 구하라\n\n프로미스를 몇번 사용은 해봤다. 그러나 사실 이게 왜 대단한지 크게 알 수 가 없었다. 체이닝이 되서 추적이 쉽다는것? async / wait 을 이용해서 비동기/동기를 이동할 수 있다는 것? 정도만 알고 있었다.\n\n하지만 이번에 공부하면서 이게 왜 등장했으며 어떤 장점이 있는지 조금은 알게 되었다.\n\n## 제어의 역전\n\n콜백 지옥의 문제점은 제어의 역전이다. 믿음직하지 못한 어떤 비동기 프로그램에게 우리 프로그램의 호출 제어권을 넘겨주어 어떤 일이 발생할 수 있다는 것이다.\n\n이전 시리즈의 예를 다시 들어보자.[Callback](./Callback.md)\n\n```js\nsolutionUtil.trackPurchase(purchaseData, function CBF() {\n  // 결제데이터를 넘긴 뒤\n  // 비동기적인 처리가 완료되면 콜백실행\n  assignCredit(); // 결제\n  goThanksPage(); // 페이지 이동\n});\n```\n\n저 유틸의 trackPurchase 라는 함수는\n\n- purchaseData 와 콜백함수 두가지 인자를 받는다.\n- 우리는 알 수 없는 어떤 로직 진행 후 완료가되면 콜백함수를 실행한다.\n\n이 과정의 문제점은 콜백의 실행 제어권이 저 함수에게 넘어간다는 점이다. 저 함수안에서 어떤 일이 잘못되어 콜백함수가 5 번 실행될 수 있다는 게 가장 큰 문제였다.\n\n## 제어의 재역전\n\n자 이제 저 제어권을 돌려받자. 콜백을 저 함수가 아니라 우리가 실행할 수 있게 만들자는 개념이 promise 다.\n먼저 예시를 들어보자.\n\n1. 어떤 작업을 하려고 foo()라는 함수를 부른다.\n2. foo()의 내용은 관심이 없지만 foo()가 끝나길 기다린다.\n3. foo()가 끝나면 어떤 작업을 실행한다.\n\n콜백 베이스의 코드라면 foo()를 실행할 때 콜백을 넘겨준다.\n\n```js\nfoo(someData, bar(), barErr());\n```\n\n이렇게 하면 foo 가 자신이 끝나면 bar()를 **백그라운드**에서 실행한다. 하지만 자바스크립트에는 이벤트 방식도 존재한다.\n\n```js\nfunction foo(x) {\n  // 어떤 일을 실행하고 이벤트를 반환\n  return listner;\n}\n\nvar evt = foo(42);\n\nevt.on('completion', bar());\nevt.on('failure', barErr());\n```\n\n이거다 바로. 이게 사실 프로미스가 실행되는 방식이다.\n위의 코드를 잘 생각해보자. foo 가 비동기적으로 실행되고 그 결과를 받아 evt 에 저장한다.foo(42)가 완료되어 evt 에 할당되면 그걸 우리가 읽고 다음 단계를 실행한다.\n\n콜백 패턴을 뒤집었다. 정확히 정반대이다.\n즉 제어권을 다시 역전시킨 것이다.\n\n조금 더 간단하게는\n\n```js\nvar evt = foo(42);\n\nbar(evt);\nbarErr(evt);\n```\n\n이렇게 바뀐다.\n\n위의 예시와 아래의 예시를 잘 보면 크게 다른것 같지 않은데? 그냥 코딩스타일 차이 아닌가? 라고 생각할 수 도 있다. 그렇지만 제어권을 기준으로 보자. foo라는 함수가 끝나면 콜스택의 제어권을 누가 가지고 있는지가 중요하다\n\n## 리스너를 프로미스로\n\n이벤트 리스너가 아니라 프로미스로 조금만 바꿔보자.\n\n```js\nfunction foo(x) {\n  // 어떤 일을 실행하고 프로미스를 반환\n\n  return new Promise(function(resolve, reject) {});\n}\n\nvar p = foo(42);\n\nbar(p);\n```\n\n여기서 bar 의 내부를 보자면\n\n```js\nfunction bar(fooPromise) {\n  fooPromise.then(\n    function() {}, // resolve 시 작업\n    function() {} // reject 시 작업\n  );\n}\n```\n\n이렇게 되어있을 것이다. 현대의 코드는 then()과 catch()를 많이 사용하지만 기본은 resolve 와 reject 다.\n\n이러한 프로미스는 단 한번만 결과값이 귀결된다. 이 값은 불변성을 가져 변하지 않는다. 믿음을 준다. (믿음성)\n\n단 한번만 결과값이 도출되기에 여러번 호출하지 않고, 값이 변하지 않기 때문에 그 결과로 다른 로직에 이용되도 같은 결과가 도출된다. 또한 에러가 발생하더라도 프로그램의 흐름은 멈추지 않는다. 그냥 예외가 되었기에 버림콜백(reject)로 진행한다.\n\n그렇다면 프로미스가 과연 믿음직스러운건가?? 아직 조금 부족하다.\n"
  },
  {
    "path": "Deprecated/Promise2.md",
    "content": "# Promise2\n\n## Promise.resolve()\n\n프로미스는 사실 별게 아니다. 콜백을 넘겨주는 위치를 달리했을 뿐이다. foo()에 콜백을 넘기는 것이 아닌 foo()에서 프로미스를 받은 뒤 이 프로미스에 콜백을 준 것이다.\n\n프로미스가 나오게 된 가장 중요한 점은 믿음이다.\n근데 중요한 것은 이 받은 프로미스가 진짜 프로미스가 아니라면? 단지 .then()을 쓸 수 있는 object 라면 어떨까?\n\n이를 책 *You Don't Know JS*에서는 Thenable 이라고 한다.\n\n```js\nvar p = {\n  then: function(foo, err) {\n    foo(42);\n    err('하이');\n  }\n};\n\np.then(\n  function resolve(val) {\n    console.log(val);\n  },\n  function rejected(err) {\n    console.log(err);\n  }\n);\n```\n\n이 Object p처럼 then()이 있는 thenable은 모두 프로미스처럼 보이게 동작할 수 있다.\n\n이 경우 Promise.resolve()로 해결이 가능하다. Promise.resolve()를 거치면 이 값으로 이루어진 프라미스 객체가 반환된다.\n\n이게 굉장히 중요하다. 프로미스가 등장한 이유가 믿음성인데 이 믿음성을 해결해준다.\n\n```js\nvar p1 = new Promise(function(resolve, reject) {\n  resolve(42);\n});\nvar p2 = Promise.resolve(42);\n\np1 === p2; // true\n```\n\n자 이제 Thenable 한 값을 Promise.resolve()에 들어가면 정규화시켜보자.\n\n```js\nPromise.resolve(p).then(\n  function resolve(val) {\n    console.log(val);\n  },\n  function rejected(err) {\n    console.log(err); // 실행 안됌\n  }\n);\n```\n\n자 그럼 이제 할 일은 아래와 같다. 만일 foo()가 어떤 비동기 행위이며 반환값이 프로미스인지 확신하게끔 만들자.\n\n```js\nfoo(42).then(function(v) {\n  console.log(v); // 멍청\n});\n\nPromise.resolve(foo(42)).then(function(v) {\n  console.log(v); // 현명\n});\n```\n\n이러면 어떠한 경우에도 무리가 없다. 믿음이 확실해진다.\n\n## 익숙한 ajax\n\n그럼 자주 사용하는 ajax 에 응용해보자.\n\n가장 중요하게 기억해야 할 것은 기존의 콜백은 백그라운드에서 호출, 프로미스는 호출스택에서 호출한다는 점이다.\n\n```js\nfunction request(url) {\n  return new Promise(function(resolve, reject) {\n    // ajax의 콜백함수가 일반 함수가 아니라 방금 생성한 promise의 resolve가 된다.\n    ajax(url, resolve);\n  });\n}\n\nrequest('https://...')\n  .then(function(response1) {\n    return request('https://.../?q=' + response1);\n  })\n  .then(function(response2) {\n    console.log(response2);\n  });\n```\n\n자주 사용되는 AJAX 공통 코드를 Promise를 이용해서 더욱 믿음을 가지고 사용할 수 있게 될 것이다.\n"
  },
  {
    "path": "Deprecated/Reactive.md",
    "content": "# Reactive\n\n사람들이 흔히 말하는 리액티브의 3가지 의미\n\n- 리액티브 시스템 (구조 및 설계)\n- **리액티브 프로그래밍 (선언적 이벤트 기반)**\n- 함수형 리액티브 프로그래밍 (FRP)\n\n<br/>\n\n## 지난 함수형\n\n- 순수함수\n- 불변 데이터 타입\n- 공유상태, 부작용(side-effect)피하기\n- 명령형이 아닌 선언적\n\n> 선언적 언어(declarative language)란 ‘어떻게’ 보다는 ‘무엇’에 대해 기술하는 방식의 컴퓨터 언어\n\n<br/>\n\n## 함수형에서의 side-effect가 없다하는 것은?\n\n> 콜백이나 옵저버 패턴이 스레드에 안전하지 않은 이유는 같은 자원에 여러 스레드가 Race condition(경쟁조건??)에 빠지게 되었을 때 알 수 없는 결과가 나오기 때문이다\n\n<br/>\n\n### 명령형이란 :question:\n\n작성된 코드가 정해진 순서대로 실행됨\n\n### 명령형의 반댓말\n\nReactive - 데이터 흐름을 먼저 정의하고 데이터가 변경되었을 때 연관되는 **함수나 수식이 업데이트 되는 방식** => pull이 아닌 push\n<br/>\n\n## **Reactive Programming**\n\n> 반응형(Reactive) 기술의 아이디어는 1980년대에 논문(\"On the Development of Reactive System\") 이 나왔고,1990년대, 2000년대초반에 이미 저수준은 제공되고 있어왔다. (Select, ePoll, IOCP등 네트워크 비동기화에서 부터 쓰레드의 추상층등) 그런것들을 토대로 자연스러운 데이터흐름을 다루는것에 대한 벽돌이 쌓아 올려져 RxJava, Node.js, Play(Akka Streaming), Microsoft Reactive Extensions 등이 생겨났다.\n\n<br/>\n\n![Reative](http://sculove.github.io/blog/2016/06/22/Reactive-Programming/stream.png)\n\n<br/>\n\n- Reactive Programing은 기본적으로 모든 것을 스트림(stream)으로 본다. 이벤트, ajax call, 등 모든 데이터의 흐름을 시간순서에 의해 전달되어지는 스트림으로 처리한다. **즉, 스트림이란, 시간순서에 의해 전달되어진 값들의 collection 정도로 이해해 보자.**\n- 각각의 스트림은 새로 만들어(branch)져서 새로운 스트림이 될 수도 있고, 여러개의 스트림이 합쳐(merge) 질수 있다.\n- 스트림은 map, filter과 같은 함수형 메소드를 이용하여, immutable하게 처리할 수 있다.(고차함수 사용)\n- 스트림을 listening 함으로써 데이터의 결과값을 얻는다. 이를 subscribe라고 표현한다.\n\n<br/>\n\n**데이터의 흐름과 변화 전파에 중점을 둔 프로그래밍 패러다임이다. (데이터 흐름에 중점을 둔다.)**\n<br/>\n\n![Reative](http://sculove.github.io/blog/2016/06/22/Reactive-Programming/rxjs_stream.png)\n\n<br/>\n\n## Reative의 4가지 주요 속성\n\n- [Responsive](#Responsive(응답성)) : 사용자에 대한 반응(React)\n- [Scalable(Elastic)](#Scalable(Elastic)(확장성))  : 부하(road)에 대한 반응(React)\n- [Resillent](#Resillent(탄력성)) : 실패상황에 대한 반응(React)\n- [Event-driven](#Event-driven(이벤트-주도)) : 이벤트에 대한 반응(React)\n  \n<br/>\n\n### Responsive(응답성)\n\n쉽게 말해서 웹브라우저의 사용자가 한참 기다리지 않게 하는 것이다.\n<br/>\n\n즉 정해진 시간안에 반드시 결과를 받아 볼 수 있게 하자는것. 그 결과가 진짜 결과가 아니라 \"지금 처리중입니다\" 라는 메세지일지라도.\n<br/>\n\n추가적으로 우리가 엑셀을 사용 할때 A가 `=SUM(B1,C1)`라면, B1이 3일때, C1 의 값을 97로 변경하면 자연스럽게 A는 100이 될것임을 알 수 있다.\n<br/>\n\n이것처럼 우리가 어떤 행동을 했을 때 자연스럽게 사용자에게 반응하기 위한 노력을 하자는 의미로 볼 수 있다.\n<br/>\n\n### Scalable(Elastic)(확장성)\n\n규모변경 성질이다.\n<br/>\n\nScalable은 주로 확장의 의미가 있기 때문에 요즘은 확장되었다가 다시 축소도 시킬 수 있다는 의미로 Elastic을 사용하기도 한다.\n<br/>\n\n어플리케이션을 수평확장시키는 방식은 여러모로 굉장히 어려운 도전이다.\n<br/>\n  \n### Resillent(탄력성)\n\n버그가없는, 실패하지 않는 소프트웨어를 만드는것은 거의 불가능에 가깝다.  \n<br/>\n\n이러한 실패를 피해 완벽한 프로그램을 개발하는 것 보다 reactive 패러다임은 실패를 포함하는 설계를 하도록 한다.\n<br/>\n\n즉 충돌하게 내버려둬라는 철학을 가지고 있다.\n<br/>\n\n관리자 역할을 하는 액터는 자동으로 실패를 감지하고 원상태로 회복하게 만드는데\n<br/>\n\n즉 재앙을 최소화하는것에 관심을 두고 있다.\n<br/>\n\n### Event-driven(이벤트 주도)\n\n웹서버에서 동기식 멀티쓰레드로 request 가 대응되는것이 아니라, 비동기식 event 별로 처리를 하게되면 리소스 활용성이 높아진다 (메모리 및 CPU).\n<br/>\n\n하지만 공유상태를 나눠갖는것에 있어서 어려움이 생길 수 있다.\n<br/>\n\n따라서 그런 어려움을 방어 하기 위해 immutable 상태 지향의 개발, Actor, STM 등의 기술이 함께 따라다닌다.\n<br/>\n\n즉 데이터가 흘러감에 있어서 변경가능한 상태에서의 알 수 없는 변화는 지옥의 버그를 창조하므로 자연스럽게 함수형패러다임이 가미가 되는 것이다.\n<br/>\n\n![Event_pic](https://github.com/SeonHyungJo/FrontEnd-Dev/blob/master/assets/image/Event_Loop.png?raw=true)\n\nEvent 를 처리하는 루프(쓰레드)가 있으며 해당 이벤트를 받기위해 구독을 신청한 노드의 핸들러에게 메세지(이벤트)를 전달해준다.\n<br/>\n\n물론 그 이벤트루프에 이벤트를 발생하는 녀석도 있을 것이다.\n<br/>\n\n즉\n<br/>\n\n- Events : 웹으로 말하면 브라우저에서의 Request 및 미들웨어로의 요청\n- Event Loop : Reqeust 를 처리하는 엔진\n- Event Handler : Request 를 받아서 비니지스로직을 구현. 이것은 주로 우리가 만드는 것\n  \n로 이루어져있다.\n<br/>\n\n## 그럼 왜 Reactive Programming 인가?\n\n- 함수형으로 만들기 때문에, 하나의 함수는 그 역할 자체에 집중할수 있다.\n- Promise의 장점을 극대화할 수 있다.\n\nReactive Programming에서 갑자기 Promise를 이야기하는 이유는, RxJS의 Observable이 Promise와 개념적으로 유사하다. 차이가 있다면, Promise는 단 하나의 value를 다룰 수 있지만, Observable은 다수의 value를 다룰 수 있다.\n\n```js\n\nmyObservable.subscribe(successFn, errorFn);\nmyPromise.then(successFn, errorFn);\n\n```\n\n> The Promise is an Observable<br/>\n> The Observable is not a Promise<br/>\n> ES7 스펙에 Observable이 제안되어 있지만 현재는 표준이 아니다. 하지만, Promise는 Promises/A+ 표준이다.\n\n처음 Promise를 접할 때에는 좀 낯설었지만, 실제 구현상의 편리함이나, 로직의 심플함, 비동기 처리를 동기식으로 개발할 수 있는 장점 덕분에, 좀더 알아먹기 쉬운 코딩을 할수 있다. 익숙해지면, Observable은 Promise보다 더 강력하다.\n\n- Observable은 A steam에 의해 B stream이 영향을 받는 경우, A만 바꿔도 B가 자동으로 바꿀 수 있도록 구성할 수 있어서,데이터의 동기화를 간편하게 할 수 있다. 이러한 이유는 A와 B stream 사이의 관계를 선언적으로 선언했기 때문에 가능하다.\n\n## Rx js?\n\n> **RX = OBSERVABLE + OBSERVER + SCHEDULERS**\n\n<br/>\n\n---\n\n#### Reference \n\n- [찰스의 안드로이드](https://www.charlezz.com/?p=189)\n- [한빛미디어](http://www.hanbit.co.kr/media/channel/view.html?cms_code=CMS6076376207)\n- [HAMA Blog](http://hamait.tistory.com/761)"
  },
  {
    "path": "Deprecated/Repaint와 Reflow.md",
    "content": "# Repaint와 Reflow\n\n<br/>\n\n## 브라우저의 rendering 과정\n\n![rendering](/assets/images/rendering.png)\n\n위의 그림과 같이 브라우저는 화면을 rendering하는 과정에서 **배치\\(flow\\)** 와 **그리기\\(paint\\)** 의 과정을 거친다.\n\n<br/>\n\n## Reflow의 발생\n\n생성된 DOM 노드의 레이아웃이 변경될 떄, 변경 후 영향을 받는 모든 노드를 다시 계산하고 렌더 트리를 재생성 한다.\n\n이러한 과정을 `reflow`라 하고 `reflow`가 일어난 후, `repaint`가 일어난다.\n\n```javascript\nfunction reFlow() {\n    var container = document.getElementById('container');\n\n    container.style.padding = '20px';\n    container.style.border = '20px';\n    container.appendChild(document.createTextNode('hello'));\n}\n\n```\n\n<br/>\n\n## Repaint의 발생\n\n생성된 DOM 노드에 대하여 style을 변경시켰을 때, **무조건 `reflow`가 발생하진 않는다.**\n**레이아웃 수치에 대한 변경이 일어나지 않는다면, `reflow`가 일어나지 않고, `repaint`만 일어난다.**\n이러한 경우에는, 색상변경과 같이 레이아웃의 변경이 없는 경우가 있다.\n\n```javascript\nfunction repaint() {\n    var container = document.getElementById('container');\n\n    container.style.backgroundColor = 'black';\n    container.style.color = 'white';\n}\n\n```\n\n<br/>\n\n## Repaint와 Reflow의 최적화\n\n`Repaint`와 `Reflow`가 많아질수록 애플리케이션의 렌더링 성능은 느려지게 된다.\n즉, 이를 줄일수록 성능을 높일 수 있다.\n\n### DOM객체의 캐싱\n\n---\n\n```javascript\n//Before\nfor(var i=0; i<100; i++) {\n\tdocument.getElementById('container').style.padding = i + 'px';\n}\n\n//After\nvar container = document.getElementById('container');\n\nfor(var i=0; i<100; i++) {\n    container.style.padding = i + 'px';\n}\n```\n\n### class명과 cssText사용\n\n---\n\n```javascript\n//Before\nvar container = document.getElementById('container');\n\ncontainer.style.padding = \"20px\";\ncontainer.style.border = \"10px solid red\";\ncontainer.style.color = \"blue\";\n\n//After cssText\ncontainer.style.cssText = 'padding:20px;border:10px solid red;color:blue;';\n\n//After class\ncontainer.className = 'test';\n```\n\n### 애니메이션이 들어간 노드는 가급적 position:fixed 또는 position:absolute로 지정\n\n---\n\n``` javascript\n<div id=\"animation\" style=\"background:blue;position:absolute;\"></div>\n```\n\n프레임에 따라 reflow비용이 많은 애니메이션 효과의 경우엔 노드의 `position`을 `absolute`나 `fixed`로 주면 전체 노드에서 분리된다.\n이 경우엔, **전체 노드에 걸쳐 Reflow 비용이 들지 않으며 해당 노드의 Repaint 비용만 들어가게 된다.**\n\n### 테이블 레이아웃을 피한다.\n테이블로 구성된 페이지 레이아웃의 경우, 점진적 페이지 렌더링이 일어나지 않고 모든 계산이 완료된 후, 화면에 렌더링이 되기 때문에 피하는게 좋다.\n\n<br/>\n\n## Virtual DOM\n\n**Virtual DOM**은 React나 Angular와 같은 UI/UX기반의 라이브러리 혹은 프레임워크에서의 컨셈이 되는 개념이다.\n\n기존에 javascript나 jQuery에서 사용되던 DOM 직접접근 방식의 문제는 reflow와 repaint의 연관성도 빼놓을 수 없다.\n\n**DOM은 정적이다.**\nDOM 요소에 접근하여 동적으로 이벤트를 주어 layout을 바꾸게 되면 reflow와 repaint가 일어나게 된다.\n\n이 과정에서 규모가 큰 애플리케이션일수록 recalculate할 양이 늘어나고 이는 성능에 큰 영향을 미친다.\n\n### Virtual DOM의 사용\n\n> 1. 데이터가 업데이트되면, 전체 UI 를 Virtual DOM 에 리렌더링.\n> 2. 이전 Virtual DOM 에 있던 내용과 현재의 내용을 비교.\n> 3. 바뀐 부분만 실제 DOM 에 적용.\n\n즉, **Virtual DOM을 사용함으로써 바뀐 부분(Component)만 rerendering하기 때문에 컴포넌트가 업데이트 될 때, 레이아웃 계산이 한 번만 일어나게 된다.**\n\n<br/>\n\n---\n\n#### Reference\n\n- [Reflow or Repaint(or ReDraw)과정 설명 및 최적화 방법](http://webclub.tistory.com/346)\n- [DOM의 문제점과 Virtual DOM](https://velopert.com/775)\n\n"
  },
  {
    "path": "Deprecated/WebWorker.md",
    "content": "# Web Worker\n\n`WebWorker`는 `script` 실행을 메인 쓰레드가 아니라 백그라운드 쓰레드에서 실행할 수 있도록 해주는 기술이다.\n<br/>\n\n이 기술을 통해 무거운 작업을 분리된 쓰레드에서 처리할 수 있으며, 이를 통해 메인 쓰레드(일반적으로 UI 쓰레드)는 멈춤, 속도저하 없이 동작할 수 있다.\n<br/>\n\n## WebWorker의 개념과 활용\n\n`Worker` 는 `Worker()` 생성자를 통해 생성되며 지정된 `Javascript` 파일에 포함된 코드를 `Worker` 쓰레드에서 실행하며, (`Worker`는 현재 `Window` 와 분리된 `DuplicatedWorkerGlobalScope` 라는 별도의 `Global context` 에서 동작) `Worker` 쓰레드에서 어떠한 코드도 실행할 수 있지만, 몇가지 예외가 있다.\n<br/>\n\n예를들어 `Worker` 내에서는 `DOM` 을 직접 다룰 수 없다. 또한 `Window` 의 기본 메서드와 속성을 사용할 수 없다.\n<br/>\n\n`Message System` 을 통해 `Worker` 와 메인 쓰레드 간에 데이터를 교환할 수 있다.\n<br/>\n\n`Worker.postMessage()` 메서드를 통해 데이터를 전송할 수 있으며, `Worker.onmessage` 이벤트 핸들러 `Attribute` 를 통해 응답할 수 있다. (전송되는 메세지는 `MessageEvent.data` 에 포함). 전송되는 데이터는 공유되지 않으며 복제를 통해 전달되게 된다.\n<br/>\n\n부모페이지와 동일한 `Origin` 내에서 `Worker` 는 새로운 `Worker` 를 생성할 수 있다.  `Worker` 들은 `XMLHttpRequest` 를 통해 네트워크 통신을 할 수 있지만 `XMLHttpRequest` 의 `responseXML` 과 `channel attribute` 는 항상 `null` 을 반환한다.\n<br/>\n\n지금까지 알아본 `Dedicated Worker` 와 다른 유형의 `Worker`들도 존재한다.\n<br/>\n\n- `Shared worker` 는 `Worker` 가 동일한 도메인 내에 존재하는 여러 `script` 에 의해 사용될 수 있다. `Shared Worker` 는 `Dedicated worker` 보다 좀더 복잡성을 가지고 있다. 예를들어 `Script` 들은 반드시 활성화된 `Port` 를 통해 통신해야 한다.\n- `ServiceWorker` 는 웹 어플리케이션 사이의 `Proxy Server`와 브라우저로서 역할을 하며 (만약 가능하다면)통신을 구축한다. 이를 통해 효율적인 오프라인 경험을 구축하고, 네트워크 요청을 가로채어 통신이 가능한지 여부에 따라 적절한 동작을 수행하며, 서버에 존재하는 자원들을 갱신할 수 있다. 또한 푸시 알림이나 백그라운드 동기화 API에 접근을 허용한다.\n- `Chrome Worker` 는 `Firefox` 에서만 사용 가능한 `worker` 유형으로 Add-on을 제작할 때나 확장기능에서 `Worker` 를 사용하고 싶을 때 사용할 수 있으며, `Worker` 에서 `js-ctypes` 에 접근할 수 있다.\n- `Audio Workers` 는 스크립트를 통한 직접적인 오디오 처리를 `Web Worker` 에서 처리할 수 있도록 해준다.\n\n<br/>\n\n---\n\n#### Reference\n\n- [MDN-WebWorker](https://developer.mozilla.org/ko/docs/Web/API/Web_Workers_API)\n- [MDN 예제](\nhttps://github.com/mdn/simple-web-worker)\n\n\n"
  },
  {
    "path": "Deprecated/animation.md",
    "content": "# CSS Animation\n\n크게 애니메이션을 구현하는 방법은 2가지가 있다. 하나는 자바스크립트로 작성하는 방법이며, 다른 하나는 CSS의 animation 속성을 사용하는 방법이다.\n\n각각의 특성을 살펴보면,\n\n<br/>\n\n## CSS 애니메이션\n\n1. 자바스크립트를 모르더라도 간단하게 애니메이션을 만들 수 있다.\n2. 자바스크립트를 이용한 애니메이션은 잘 만들어졌더라도 성능이 좋지 못할때가 있다. CSS 애니메이션은 `frame-skipping` 같은 여러 기술을 이용하여 최대한 부드럽게 렌더링된다.\n3. 브라우저는 애니메이션의 성능을 효율적으로 최적화할 수 있다. 예를 들어 현재 안보이는 엘리먼트에 대한 애니메이션은 업데이트 주기를 줄여 부하를 최소화할 수 있다.\n4. CSS에서 미리 정의된 애니메이션을 브라우저의 기능을 이용해서 애니메이션의 중간 상태를 나타내는 `@keyframe`을 계산해서 애니메이션을 브라우저에서 렌더링한다.\n5. 정해진 시간에 정해진 동작을 하도록 선언한 후 정해진 애니메이션을 브라우저에서 표현한다.\n6. 선언형 애니메이션\n\n<br/>\n\n## JavaScript 애니메이션\n\n1. 다양한 컨트롤 또는 사용자 입력에 의해서 상태가 변하는 애니메이션을 구현하기 위해서 사용한다.\n2. 애니메이션의 시간, 효과등의 제한이 없이 구현이 가능하다.\n3. 프레임 단위로 애니메이션을 정의한다.\n4. setInterval, setTimeOut을 이용한 애니메이션과 requestAnimationFrame을 이용한 애니메이션이 있다.\n5. 명령형 애니메이션\n\n<br/>\n\n## animation 속성은?\n\n- animation-delay : 엘리먼트가 로드되고 나서 언제 시작될지\n- animation-direction : 애니메이션이 종료되고 다시 처음부터 시작할지 역방향으로 진행할지?\n- animation-duration : 한 싸이클의 애니메이션이 어느 정도의 시간에 걸쳐 일어날지 지정\n- animation-fill-mode : 애니메이션이 시작되기 전이나 끝나고 난 후 어떤 값이 적용될지 지정\n- animation-name : 이 애니메이션의 중간 상태를 지정, 중간 상태란 `@keyframe` 규칙을 이용하여 기술한다.\n\n<br/>\n\n### animation-delay\n\n애니메이션의 시작할 시점을 지정하는 것으로, 시간을 값으로 넣어준다.\n\ntime값으로 초 또는 밀리 초(ms)를 넣을 수 있으며, 음수도 넣을 수 있다. 음수를 넣게 되면 바로 실행이 되지만 해당 초가 지난 후의 모습부터 진행한다.\n\n```css\n/* Single animation */\nanimation-delay: 3s;\nanimation-delay: 0s;\nanimation-delay: -4000ms;\n\n/* Multiple animations */\nanimation-delay: 1s, 300ms;\n```\n\n> [Animation-Delay](https://codepen.io/seonhyungjo/pen/aeOpxp)\n\n\n<br/>\n\n### animation-direction\n\n애니메이션이 앞으로, 뒤로 또는 앞뒤로 번갈아 재생되어야하는지 여부를 지정한다.\n\n```text\nnormal | reverse | alternate | alternate-reverse\n```\n\n- normal : 매 사이클마다 정방향으로 재생한다.\n- reverse : 매 사이클마다 역방향으로 재생한다.\n- alternate : 매 사이클마다 각주기의 방향을 뒤집으며, 첫 번째 반복은 정방향으로 진행한다.\n- alternate-reverse : 매 사이클마다 각주기의 방향을 뒤집으며, 첫 번째 반복은 역방향으로 진행한다.\n\n> [Animation-Direction](https://codepen.io/seonhyungjo/pen/zgGZRE)\n\n<br/>\n\n### animation-duration\n\n한 사이클을 완료하는데 걸리는 시간을 지정한다.\n\n```css\nanimation-duration: 6s;\nanimation-duration: 120ms;\n```\n\n> [Animation-Duration](https://codepen.io/seonhyungjo/pen/ZgGeVJ)\n\n<br/>\n\n### animation-fill-mode\n\n애니메이션이 실행 전과 후에 대상에 스타일을 적용하는 방법을 지정한다.\n\n```text\nnone | forwards | backwards | both\n```\n\n> [Animation-fill-mode](https://codepen.io/seonhyungjo/pen/qedrgM)\n\n<br/>\n\n---\n\n## animation-name\n\n애니메이션의 중간 상태를 지정한다. 중간상태는 `@keyframe` 규칙을 이용하여 기술한다.\n\n```css\n/* Single animation */\nanimation-name: none;\nanimation-name: sildeIn;\n```\n\n### keyframe\n\n애니메이션 중간중간의 특정 지점들을 거칠 수 있는 키프레임들을 설정함으로써 CSS 애니메이션 과정의 중간 절차를 제어할 수 있다.\n\n키프레임 규칙을 이용해서 두개 이상의 중간 상태를 기술할 수 있다.\n\n중간 상태에 명시한 스타일이 언제 등장할지를 `%`를 이용해서 지정한다. `0%`는 시작시점을 의미하며,  `100%`는 마지막 지점이 된다. 최소한 이 두 시점은 기술되어야 브라우저가 언제 애니메이션이 시작되고 끝나는지 알 수 있다.\n\n> [Animation-keyframe](https://codepen.io/seonhyungjo/pen/VoLbdL)\n\n<br/>\n\n## 한방에 적어서 사용하기\n\nanimation CSS 속성은 다수의 스타일을 전환하는 애니메이션을 적용할 수 있다. \n\n`animation-name`, `animation-duration`, `animation-timing-function,` `animation-delay`, `animation-iteration-count`, `animation-direction`, `animation-fill-mode`, `animation-play-state`의 단축 속성이다.\n\n```css\nanimation: 3s ease-in 1s 2 reverse both paused slidein;\n```\n\n---\n\n#### Reference\n\n- [CSS 애니메이션 사용하기 - MDN](https://developer.mozilla.org/ko/docs/Web/CSS/CSS_Animations/Using_CSS_animations)\n- [Web Animations 명세](https://www.w3.org/TR/web-animations/)\n"
  },
  {
    "path": "Deprecated/setState.md",
    "content": "# Functional setState()\n\n제목을 보고 React를 아는 사람들은 `setState()`를 보고 아~ 했을 것이다.\n흔히 `setState()` 함수(저런 형태는 기본적으로 함수니까)는\n\n```js\n\nonChangeEvent({target}){\n    this.setState({\n        value : target.value\n    })\n}\n\n```\n\n위와 같은? 방법으로 사용할 것 같다. (맞나?)\n<br/>\n\n그러나 이번에는 새로운 소식으로 제목에 따르면 setState()가 `Functional Programming`이라는 것이다.\n<br/>\n\n## setState()는 functional programming이다. \n\n함수형 프로그램의 특성은 작성한 글이 있다.\n<br/>\n\n> [함수형 프로그래밍](https://github.com/SeonHyungJo/FrontEnd-Dev/blob/master/Functional_Programming/README.md)\n<br/>\n\n함수형 프로그래밍에 있어서 가장 중요한 것은 2가지로 요약할 수 있다.\n<br/>\n\n1. 순수함수(Pure Function)\n    1. 순수 함수는 같은 입력 값을 넣었을 때 항상 같은 출력 값을 반환한다.\n    2. 유용한 순수 함수는 최소 한 개의 매개변수를 가진다.\n    3. 유용한 순수 함수는 반드시 무엇인가를 반환한다.\n2. 불변성(Immutable)\n\n<br/>\n\n## React는 Component 기반의 UI 라이브러리이다.\n\n먼저 React는 Component 기반의 UI 라이브러리이다.\n<br/>\n\nReact의 Component는 보통 자체 상태(State)가 포함 된 독립적이고 재사용 가능한 코드 조각(pieces of code)이다.\n<br/>\n\n이것은 어플리케이션의 UI를 구성하는 리액트 엘리먼트(element)를 반환한다.\n<br/>\n\n로컬 상태를 포함하는 컴포넌트에는 state라는 속성(property)이 있다.\n<br/>\n\nthis.props 및 this.state는 비동기적(asynchronously)으로 업데이트 될 수 있으므로 다음 상태(state)를 계산하는 데는 이 값을 의존해서는 안된다.\n<br/>\n\n## setState()에 대해서...\n\n### 이미 알고있는 것\n  \n- 업데이트 할 상태의 부분을 포함하는 **객체**를 setState의 인자로 전달한다.\n- 전달한 객체에는 상태의 키에 해당하는 키를 포함\n\n```js\n\nthis.setState({ key: value})\n\n```\n\n위에서부터 보게 되면 `setState()`의 인자로는 `Object`를 보내게 된다.\n<br/>\n\n인자로 `String`, `int`를 보내게 되면 에러가 발생한다.\n<br/>\n\n`setState()` 인자로 `key`와 `value`가 넘어가고 `key`로 비교를 해서 있다면 덮어씌우고 없다면 새로 생성하는 역할을 하기 때문이다.\n<br/>\n\n이러한 형태는 `Map`형태와 유사하다.\n\n- `setState()`는 그 객체를 상태에 `Merge`하여 상태를 업데이트하거나 새로 설정\n- `setState()`는 **비동기적** 으로 업데이트가 이루어질 수 있다.\n  \n<br/>\n\n### 당신이 몰랐을 수 있는 것\n\n**객체 대신 함수를 넘길 수 있다.** \n<br/>\n\n```js\n\nthis.setState(\n    function (state, props) {\n        return { score: state.score - 1 };\n    }\n);\n\n```\n\n<br/>\n\n- 함수를 넘길 수 있다는 것은 함수형 프로그래밍의 특성 중 하나이다.\n\n<br/>\n\n**그렇다면 왜 함수를 전달할까**\n\n<br/>\n\n- state 업데이트가 비동기로 실행이 된다.\n- 현재 상태의 값을 안정적으로 가져올 수 있다.\n\n<br/>\n\n```js\nsubmit(){\n    this.setState(\n        function(prevState, props){\n            return {\n                showForm: !prevState.showForm\n            }\n        }\n    );\n}\n```\n\n<br/>\n\n### setState()가 호출이 되면...\n\n- 전달한 객체를 현재 상태로 합치고 Merge \n- (간단히 보자면) 새로운 리액트 엘리먼트 트리를 만들고(Render), 이전 트리와 비교하고 변경된 부분을 DOM에 적용\n\n<br/>\n<br/>\n\n## 리액트는 단순하게 상태를 세팅하지 않는다\n\n리액트는 여러 setState() 호출을 성능 향상을 위해 단일 배치 방식으로 작업을 할 수도 있다.\n<br/>\n\n여러 setState() 호출은 setState()를 한 번 이상 단일 함수 내에서 호출하는 것을 의미 할 수 있다. => 무슨 말인가\n\n<br/>\n\n```js\n//constructor\nstate = {score : 0}; // multiple setState() calls\n\nincreaseScoreBy3 () {\n    this.setState({score : this.state.score + 1});\n    this.setState({score : this.state.score + 1});\n    this.setState({score : this.state.score + 1});\n}\n```\n\n<br/>\n\nsetState()에 전달하는 것은 **일반 객체**이다.\n<br/>\n\n여러 setState() 호출을 만나면 전달 된 모든 객체를 추출하여 :point_right: **배치 작업**을 수행하고 이를 `Merge`하여 단일 객체를 만들고 그 단일 객체를 사용하여 `setState()`를 진행\n<br/>\n\n그렇담 `Merge`를 어떻게 진행 할까\n<br/>\n\n예상)\n해당되는 객체들을 전부 가져와서 복사를 한다.\n같은 프로퍼티 즉 같은 key를 가지고 있다면 맨마지막 key의 값을 넣는다.\n<br/>\n\n```react\n\nconst singleObject =\n    Object.assign(\n        {},\n        objectFromSetState1,\n        objectFromSetState2,\n        objectFromSetState3 // 3개가 같다면 3번이 우선\n    );\n\n```\n\n<br/>\n\n위와 같은 패턴을 `Object Composition`이라고 한다.\n<br/>\n\n`Javascript`에서 만약 3개의 객체가 동일한 키를 가지고 있다면 `Object.assign()`에 마지막으로 전달 된 객체의 `key`값이 우선이 된다.\n<br/>\n\n```js\n\nconst me = {name : \"Justice\"},\n      you = {name : \"Your name\"},\n      we = Object.assign({}, me, you);\n\nwe.name === \"Your name\"; // true\nconsole.log(we); // {name : \"Your name\"}\n\n```\n\n<br/>\n\n## **중요**\n\n즉, 위의 increaseScoreBy3 함수를 사용하면 리액트가 setState() 호출 순서로 상태를 즉시 업데이트하지 않기 때문에 함수의 최종 결과는 3 대신 1이 된다.\n<br/>\n\n리액트는 이처럼 먼저 모든 객체를 하나로 결합한 후에 계산한다.\n<br/>\n\n`{score : this.state.score + 1}`\n<br/>\n\n새로 만든 객체로 \"setState\"를 한 번만 수행했다.\n<br/>\n\n`User.setState ({score : this.state.score +1}`\n<br/>\n\n중요한 것은 +3이 아니라 +1이 된다는 점 이유는 위에 나와있지만 간단한게 여러 `setState`가 이루어지면 모든 **객체를 단일 객체로 만들고 그 단일 객체를 setState()한다.**\n<br/>\n\n`React`가 객체를 `Merge`하는 대신 <여러 Functional setState() 호출> 를 만나면 **호출된 순서대로 함수를 큐에 넣는다.**\n<br/>\n\n`React`는 \"큐(queue)\"의 각 함수를 호출하여 상태를 업데이트하고 이전 상태, 즉 첫 번째 함수형 setState() 호출 이전 상태를 전달한다 (첫 번째 함수형 setState() 인 경우). 만약 첫 번째 함수형 setState() 호출이 아니라면, 큐 내의 이전의 함수형 setState() 호출로부터 최신 갱신된 상태를 전달한다.\n<br/>\n\n이걸 해결한 함수를 넘기기 함수를 넘기게 되면 큐에 순서대로 첫번째 함수가 실행이 되고 얻어진 상태(최신의 상태)가 넘어간다.\n<br/>\n\n## 리액트 일급 비밀\n\n지금까지 리액트에서 여러 함수형 `setState`를 수행하는 것이 왜 안전한지 깊게 살펴 봤다.\n<br/>\n\n실제로 함수형 `setState`를 완벽하게 정의하지는 못했다.\n<br/>\n\n\"상태 변경을 컴포넌트 클래스와 분리해서 작성하라.\"\n<br/>\n\n수년간, `setState`에 전달하는 함수 또는 객체는 항상 컴포넌트 클래스 안에 존재했다.\n<br/>\n\n```js\n// outside your component class\nfunction increaseScore (prestate, props) {\n  return {score : state.score + 1}\n}\nclass User{\n  ...\n// inside your component class\n  handleIncreaseScore () {\n    this.setState( increaseScore)\n  }\n  ...\n}\n```\n\n컴포넌트 클래스 외부에서 상태 업데이트 로직을 선언한다.\n<br/>\n\n그런 다음 컴포넌트 클래스 내에서 호출한다.\n<br/>\n\n**이것은 선언적(declarative)이다!**\n<br/>\n\n컴포넌트 클래스는 더이상 상태 업데이트 방법을 고려하지 않는다. 단순히 원하는 업데이트 유형을 선언한다.\n<br/>\n\n많은 상태(state)가 있는 복잡한 컴포넌트에 대해 생각해보자. 각 상태를 다른 액션으로 업데이트 할 것이다. 때로는, 각각의 업데이트 함수에는 많은 코드가 포함되어 있을 수 있다. 이 모든 로직이 컴포넌트 내에 있는 것이다.\n<br/>\n\n그러나 더 이상은 그럴 필요가 없다!\n\n```js\nimport {increaseScore} from \"../stateChanges\";\n\nclass User{\n  ...\n  // inside your component class\n  handleIncreaseScore () {\n    this.setState( increaseScore)\n  }\n  ...\n}\n```\n\n<br/>\n\n다음 상태를 계산하기 위해 추가 인자를 전달할 수도 있다.\n\n```js\n// outside your component class\nfunction increaseScore (plus) {\n  return function(prestate, props){\n        return {score : state.score + plus};\n      }\n    }\n}\nclass User{\n  ...\n// inside your component class\n  handleIncreaseScore () {\n    this.setState(increaseScore(1))\n  }\n  ...\n}\n```\n\n<br/>\n\n---\n\n#### Reference \n\n- https://www.vobour.com/%ED%95%A8%EC%88%98%ED%98%95-setstate%EA%B0%80-%EB%A6%AC%EC%95%A1%ED%8A%B8-react-%EC%9D%98-%EB%AF%B8%EB%9E%98%EC%9D%B4%EB%8B%A4-functiona\n- https://www.vobour.com/-setstate-%EB%A9%94%EC%8F%98%EB%93%9C-%ED%8C%8C%EB%9D%BC%EB%AF%B8%ED%84%B0%EB%A1%9C-%EA%B0%9D%EC%B2%B4-%EB%8C%80%EC%8B%A0-%ED%95%A8%EC%88%98-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0-using\n- https://meetup.toast.com/posts/110\n\n\n"
  },
  {
    "path": "Deprecated/기본적인 렌더링 최적화 방법.md",
    "content": "# 기본적인 렌더링 최적화 방법\n\n<br/>\n\n## HTTP 요청의 최소화\n\n대부분의 웹사이트 구성 요소(이미지, 스타일시트, 자바스크립트, 마크업 등)는 웹 서버에 존재한다.\n사용자의 컴퓨터에서 웹 사이트를 띄울 때 이 요소들을 가져오는데는 그 만큼의 네트워크 비용이 들기 마련이다. \n\n### CSS 스프라이트 기법\n\n---\n\nCSS 스프라이트 기법은 이미지 여러 개를 하나로 만들고 `background-position` 속성을 이용해 필요한 부분의 이미지만 보여준다.\n\n만약 다수의 이미지가 포함된 웹 사이트라면, 이미지의 갯수만큼 HTTP 요청을 했던 방식을 **한 번의 요청으로 줄일 수 있어** 렌더링 속도가 향상될 수 있다.\n\n```css\n#spriteImg span {\n  background: url(images/buttons-bg.png) no-repeat;\n}\n\n#spriteImg #profile span {background-position: 0 0;}\n#spriteImg #github span {background-position: 0 -15px;}\n```\n\n### 캐시 저장\n\n---\n\n```html\n// 1. 파일 이름에 날짜 추가\n<script type=\"text/javascript\" src=\"test_20181004.js\"></script>\n\n// 2. 쿼리스트링 이용\n<script type=\"text/javascript\" src=\"test.js?20181004\"></script>\n\n```\n\n위와 같이 파일에 만료날짜를 추가해놓으면 사용자가 웹 사이트에 접근했을 때 사용자의 컴퓨터에 요소를 저장한다.\n\n이후, 다시 접근하면 외부 네트워크가 아닌 **사용자의 컴퓨터에서 요소를 받아오기 때문에 추가적인 요청을 하지 않을 수 있다.**\n\n> * 만약 파일이 수정되었다면, 파일 이름이나 쿼리 스트링을 변경하거나 새로 추가해주어야 한다.\n\n### 자바스크립트 파일 통합\n\n---\n\n이는 유지보수측면에서 바라보는게 좋을 것 같은데, 우선적으로 **기존에 있던 파일이 현재 웹 사이트에서도 유효한지 파악할 필요가 있다.**\n\n또한 여러 개의 파일로 나뉘어져 있다면 **하나로 통합**해 관리하면 요소를 다운 받는 시간도 줄일 수 있을 것이다.\n\n<br/>\n\n## 파일 크기 최소화\n\n다운 받는 파일의 크기를 최소화 한다.\n\n### Gzip 압축\n\n---\n\n보통 스타일 시트 파일과 자바스크립트 파일을 압축한다.\n\n아파치 서버를 예로 들면, Gzip 압축을 주로 사용한다.\n\n> * 웹 사이트가 렌더링 될 때, 클라이언트에서 웹 서버에 파일의 **인코딩 여부를 물어보게 된다.**\n> * 서버에서는 헤더 정보에 인코딩 여부를 포함해 전송하고 **인코딩된 요소라면 클라이언트에서는 압축을 해제**한다.\n> * 압축을 해제할 때 CPU연산이 들어가기 때문에 파일의 압축 크기는 **1~2KB 이상일 떄 압축하는 것이 좋다.**\n\n### 쿠키 크기 최소화\n\n---\n\n보통 요즘 일반적인 웹 사이트에선 쿠키를 사용할 일이 많이 없을 수도 있다.\n\n하지만 포털 사이트 같은 경우에는 쿠키를 많이 사용하게 되는데 이를 줄이는 것도 방법이 될 수 있다.\n\n* **필요없는 쿠키는 삭제**한다.\n\n* 쿠키의 **만료 날짜를 필요한 만큼만 설정**한다.\n\n* 쿠키를 설정할 때 **최상위 도메인을 사용하지 않는다.**\n\n* 쿠키 정보가 필요 없는 **이미지, 스타일시트, 자바스크립트 파일은 별도의 도메인으로 사용**한다. 최상위 도메인이 같지 않으면 쿠키 정보는 공유되지 않는 점을 활용한 방법이다.\n\n<br/>\n\n## 렌더링 성능 향상\n\n[웹 브라우저의 작동 원리](https://github.com/Im-D/Dev-Docs/blob/master/Browser/%EC%9B%B9%20%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80%EC%9D%98%20%EC%9E%91%EB%8F%99%20%EC%9B%90%EB%A6%AC.md)를 이해하면 렌더링의 성능 향상은 개발을 할 때 필수적으로 고려해야할 사항들이다.\n\n### 스타일시트와 자바스크립트 배치\n\n---\n\n스타일시트 즉 CSS 파일은 렌더 트리를 만드는데 필수적으로 필요한 요소다. **따라서 `<head></head>`태그 사이에 두고 최대한 빨리 다운로드** 받아야 한다.\n\n하지만, 자바스크립트 파일의 경우 브라우저가 파싱을 하고 배치하고 그리는 과정에서 **자바스크립트 요소를 만나면 이를 다운로드해서 실행하기 전까지 모든 동작을 멈춘다.**\n\n따라서, **자바스크립트 파일의 경우엔 `</body>`태그 바로 위에 즉, 마지막에 두는 것이 효율적**이다.\n\n물론, js애니메이션이 필요한 부분의 경우 해당 요소만 `<head></head>`에 두는 것도 방법이 될 수 있다.\n\n### 초기 렌더링시 Ajax 요청 최소화\n\n---\n\n> * 1.  사용자가 페이지를 요청한다.\n> * 2. 서버에서 보낸 마크업을 다운로드해 화면을 구성하는 레이아웃을 그린다.\n> * 3. 자바스크립트 다운로드와 렌더링이 끝난 후 onload 이벤트가 발생한다.\n> * 4. Ajax 통신을 실행하고 데이터를 화면에 그린다.\n\n위와 같이 동적인 웹 페이지가 렌더링 될 때, Ajax통신이 이루어진다면, **사용자 입장에선 레이아웃이 그려지고 다시 한 번 더 그려지는 상황을 보게 될 것**이다.\n\n이를 해결하기 위해선 **서버에서 마크업을 모두 그린 후, 사용자의 동작(이벤트)이 발생할 때만 서버에 다시 요청을 하면 체감 속도를 높일 수 있다.**\n\n### 마크업 최적화\n\n---\n\n1. **되도록이면 `<table>` 태그를 사용하지 않는다.** `<table>` 태그는 그 안의 모든 데이터를 파싱하기 전까지 화면을 그리지 않기 때문이다.\n\n2. **`<div>` 태그와 스타일시트를 이용해 레이아웃을 구성**한다.\n\n3. **본문 전체를 `<table>`태그로 감싸지 않는다.**\n\n4. **전체 태그의 갯수를 줄이고, 부분적으로 태그의 중첩을 최소화**한다.\n\n<br/>\n\n---\n\n#### Reference\n\n- [[자바스크립트] 기본적인 웹 사이트 최적화 방법](http://12bme.tistory.com/128)\n\n"
  },
  {
    "path": "Deprecated/웹 브라우저의 작동 원리.md",
    "content": "# 웹 브라우저의 작동 원리\n\n<br/>\n\n## Rendering Engine\n\n* Webkit Engine : Chrome, Safari\n<br/>\n\n![Webkit](/assets/images/Webkit.png)\n\n* Gecko Engine : Firefox\n<br/>\n\n![Gecko](/assets/images/Gecko.jpg)\n\n<br/>\n\n## Critical Rendering Path\n\n웹 브라우저가 화면을 그리는데(Rendering) 거치는 주요한 과정\n\n1. HTML데이터를 파싱하고 DOM Tree를 빌드.\n2. 파싱 중 CSS링크를 만나면, CSSOM(CSS Object Model) Tree를 빌드.\n3. DOM Tree와 CSSOM Tree를 이용해 Render Tree 생성.\n4. Render Tree의 노드들의 위치를 계산(Layout)\n5. 화면에 웹 페이지를 그린다.\n\n<br/>\n\n### 1. HTML 데이터 파싱 / DOM Tree 빌드\n\n---\n\n브라우저는 HTML 데이터를 파싱해 DOM Tree를 만든다.\n모든 HTML 태그에는 노드가 있고 각각의 노드는 Tree형태로 구현된다.\n이를 DOM Tree라 한다.\n\n```javascript\n<html>\n    <head>\n        <title>BKJang</title>\n    </head>\n    <body>\n        <div>\n        \t<button> up </button>\n            middle\n            <button> down </button>\n        </div>\n    </body>\n</html>\n```\n\n### 2. CSSOM Tree 빌드\n\n---\n\nHTML 파싱 중 CSS 링크를 만나면 리소스를 받아온다.\n받아온 파일은 파싱되고 CSSOM Tree를 빌드한다.\nCSSOM이 구성되어야 다음 과정이 진행된다.(Rendering의 Blocking 요소)\n\n\n### 3. Render Tree 생성\n\n---\n\nDOM Tree와 CSSOM Tree를 결합, Render Tree를 빌드.\nRender Tree는 DOM Tree에 있는 것들 중에 실제 보이는 것들로만 구성.\n**ex) style='display : none;'은 Render Tree에서 제외. 메타태그 역시 제외.**\n\n\nRender Tree에는 Render Object Tree, Render Layer Tree, Render Style Tree, InlineBox Tree등이 포함.\n\nRender Object의 필요에 따라 **Render Layer**가 만들어지고 GPU 처리 여부에 따라 **Graphic Layer** 생성.(하드웨어 가속)\n\n기본적으로 Layer는 하나고 CPU가 렌더링에 주요한 역할.\n\n* CSS 3D Transform(translate3d, preserve-3d 등)이나 perspective 속성이 적용된 경우\n\n* CSS 애니메이션함수나 필터함수를 사용하는 경우\n\n* video나 canvas 요소를 사용하는 경우\n\n* 자식 요소가 레이어로 구성된 경우\n\n* z-index가 낮은 형제 요소가 레이어로 구성된 경우\n\n\n### 4. Layout\n\n---\n\nRender Tree가 만들어지고, 각각의 노드들의 위치를 계산하는 과정.\n위치 관련된 속성 계산(position, width, height 등).\n\n**ex) width:100%인 상태에서 브라우저를 리사이즈하면, Render Tree는 변경되지 않고 Layout 이후 과정만 다시 거치게 된다.**\n\n#### 5. Paint\n\n실제 웹페이지를 화면에 그리는 작업.\n\n**색이 바뀐다거나 노드의 스타일이 바뀌는 걸로는 Layout 과정을 거치지 않고 Paint만 일어난다.**\n\n\n<br/>\n\n## CSS와 JavaScript의 위치\n\n브라우저의 렌더링 과정에서 DOM Tree를 빌드한 후, 스타일 규칙이 없으면 Rendering이 불가.\n\n인터프리터은 HTML을 위에서 아래로 읽기 때문에 CSS를 `<head></head>`태그 사이에 두면 CSS 리소스를 최대한 빨리 받을 수 있다.\n\n반면, JavaScript는 DOM객체를 컨트롤하기 때문에 CSS처럼 위에 두게 되면 파싱을 멈추고 스크립트 파일을 읽기 때문에 성능이 저하된다. 따라서, JavaScript 소스는 주로 `</body>`태그 위에 모아두는게 좋다.\n\n단, 이런 경우 JS 애니메이션이 나중에 적용되어 사용자 입장에서 깜빡임 현상이 생길 수 있기 때문에 애니메이션 부분만 `<head></head>`사이에 두는 것도 방법이다.\n\n<br/>\n\n---\n\n#### Reference\n\n- [Naver D2 - 브라우저의 작동 원리](http://d2.naver.com/helloworld/59361)\n- [브라우저가 웹페이지를 그리는 법](https://isme2n.github.io/devlog/2017/07/06/browser-rendering/)\n- [웹브라우저에서 HTML문서 렌더링 과정](http://jeong-pro.tistory.com/90)\n\n"
  },
  {
    "path": "Deprecated/점진적향상_우아한하향.md",
    "content": "# 점진적 향상, 우아한 하향\n\n2가지 개발접근법이 있다. 우아한 낮춤과 점진적인 향상.<br/>\n간단히 정리하자면 다음과 같이 정의할 수 있다.\n<br/>\n\n## 우아한 낮춤(Graceful degradation)\n\n- 원하는 기능을 갖는 또다른 버전을 제공하거나, 사용자가 제품의 결점이 사용성을 보장하기 위한 안전 조치때문이라는 것을 인지하도록 만드는 것이다.\n- 최신 기술 기반 또는 기기에서 동작하는 기능을 만들고 나서 오래된 기술 기반 혹은 기기에서도 유사한 성능으로 동작하도록 조치하는 것이다.\n- 사용자들의 기기를 위해 별도의 버전을 만들어 놓는 것이다.\n\n<br/>\n\nex) 사용자의 브라우저가 javascript를 지원하지 않을 때\n\n- js를 지원하지 않는 기기를 위해 <noscript> 태그를 사용하여 사용자에게 \"javascript가 지원되는 브라우저를 사용해 주세요!\" 와 같은 알람을 띄워주는 것\n\n<br/>\n\n## 점진적 향상(Progressive enhancement)\n\n- 사용가능한 기능을 바탕으로, 향상된 기능을 적용하기 전에 테스트를 통해 풍부한 사용자 경험을 하나씩 증가시키는 것이다.\n- 많은 테스트를 통해 말그대로 기능을 점진적으로 향상시키는 것.\n- 기초부터 차곡차곡 쌓아서 발전해 나가는 방법\n\n<br/>\n\nex ) 웹 페이지를 구성할 때\n\n1. HTML로 마크업을 구성한다.\n2. CSS로 스타일을 입힌다.\n3. JS로 사용자 경험을 향상 시킨다.\n\n<br/>\n\n---\n\n#### Reference \n\n- [적절한 낮춤 대 점진적 향상](http://www.clearboth.org/51_graceful_degradation_versus_progressive_enhancement/)"
  },
  {
    "path": "Design_Pattern/Composite.md",
    "content": "# Composite 패턴\n\n## Composite 패턴이란?\n\n- 기존 객체를 `재사용`하여 복합 객체를 구성하는 패턴이다\n- 새로운 객체를 구성할 때, 새로운 기능을 모두 작성하는 대신에 이미 존재하는 객체들을 기능을 복합적으로 엮어 처리할 수 있다\n- 트리 구조, 즉 `재귀적인 구조`로 구성하여 `전체-부분(Whole-part)`의 관계를 표현한다\n- 단일 객체들을 한 곳에 모아서 효율을 강화하는 것에 목적을 둔다\n\n\n> #### Decorator 패턴 VS Composite 패턴\n>\n>- Decorator 패턴: 특정 객체에 기능을 덧붙여 주는 디자인 패턴\n>\n>- Composite 패턴: 기존 객체들을 통해 복합 객체를 만들어 내는 디자인 패턴\n>\n>##### 차이점\n>\n>\n>1) 확장 방식\n>\n> Composite 패턴은 상속을 이용하여 하위 클래스를 생성하는 방법으로 확장하여 오버라이딩을 통해 기능을 전부 명시해 줘야 한다. \n\n반면,\n\n> Decorator 패턴은 기본 객체에 추가하는 객체를 생성하는 방법으로 확장을 하여 기본 기능은 놔두고 추가되는 기능만 명시가 가능하다. \n>\n>\n>2) 목적\n>\n>\n>Composite 패턴은 생성되어 있는 객체들 간의 합성에, Decorator 패턴은 객체에 새로운 행동을 추가하는데에 목적을 가지고 있다.\n>\n>###### 참고\n>-[Decorator Pattern](https://scorpio-mercury.tistory.com/19)\n\n## Composite 패턴의 구성요소\n\n![image](https://user-images.githubusercontent.com/43839951/82136295-3ce59400-9847-11ea-8f06-9c4cb10e5117.png)\n\n### Component\n\n\n- 객체들의 집합 내에 들어있는 모든 객체들에 대한 인터페이스를 정의\n\n\n- 인터페이스/ 추상 클래스로 정의되며 모든 객체들에게 공통되는 메소드를 정의해야 함\n\n\n### Leaf\n\n\n- 단일 객체의 행동을 정의\n\n- 다른 객체에 대한 참조를 가질 수 없음\n\n- Composite에서 지원하는 기능을 구현\n\n\n### Composite\n\n\n- 단일 객체를 가질 수 있는 구성요소의 행동을 정의\n\n\n- 복합 객체와 단일 객체의 기능 모두 구현\n\n## 예시\n\n### Entry\n```Java\npublic abstract class Entry {\n\t\n\tpublic abstract String getName();\n\tpublic abstract int getSize(); \n\tpublic abstract Entry add();\n\n\tpublic void printList() {\n\t\tprintList(\"\");\n\t}\n\n\tprotected abstract void printList(String prefix);\n\n\tpublic String toString() { // 문자열 표현\n\t\treturn getName();\n\t}\n}\n```\n### Directory\n```java\npublic class Directory extends Entry {\n\tprivate String name;\n\n\t// 디렉토리 엔트리의 집합\n\tprivate Vector directory = new Vector(); \n\t\n\tpublic Directory(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic String getName() { \n\t\treturn name;\n\t}\n\n\tpublic int getSize() {\n\t\tint size = 0;\n\n\t\t// 자신이 가지고 있는 모든 엔트리에 대해서, getSize( )호출하여 더한다.\n\t\tIterator it = directory.iterator();\n\t\twhile (it.hasNext()) {\n\n\t\t\tEntry entry = (Entry) \n\t\t\tit.next();\n\t\t\t\n\t\t\t// entry가 디렉토리인 경우에는, 다시 이 디렉토리의 getSize( )가 재귀적으로 호출된다. \n\t\t\tsize += entry.getSize(); \n\t\t}\n\t\treturn size;\n\t}\n\n\tpublic Entry add(Entry entry) {\n\n\t\t//Entry(File 또는 Directory 객체)를 벡터에 저장\n\t\tdirectory.add(entry);\n\n\t\treturn this;\n\t}\n\n\tprotected void printList(String prefix) {\n\n\t\t // 엔트리의 일람\n\t\tSystem.out.println(prefix + \"/\" + this);\n\n\t\t// 자신이 가지고 있는 모든 엔트리에 대해서, printList( )호출한다.\n\t\tIterator it = directory.iterator();\n\n\t\twhile (it.hasNext()) {\n\t\t\tEntry entry = (Entry) it.next();\n\t\t\tentry.printList(prefix + \"/\" + name);\n\t\t}\n\t}\n}\n```\n\n### File\n```java\npublic class File extends Entry {\n\tprivate String name;\n\n\tprivate int size;\n\n\tpublic File(String name, int size) {\n\t\tthis.name = name;\n\t\tthis.size = size;\n\t}\n\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\n\tpublic int getSize() {\n\t\treturn size;\n\t}\n\n\tprotected void printList(String prefix) {\n\t\tSystem.out.println(prefix + \"/\" + this);\n\t}\n}\n\n```\n### Main\n```java\n     public static void main(String[] args) {\n       \n            Directory rootdir = new Directory(\"Dev-Docs\");\n\n            Directory CSS = new Directory(\"CSS\");\n            rootdir.add(CSS);\n\n            Directory Javascript = new Directory(\"Javascript\");\n            rootdir.add(Javascript);\n\n            File Ajax = new File(\"Ajax.md\", 100);\n            Javascript.add(Ajax);\n            \n            File WebToMobile = new File(\"WebToMobile.md\", 100);\n            CSS.add(WebToMobile);\n            File Observer = new File(\"Observer.md\", 100);\n            \n            Javascript.add(Observer);\n            \n            rootdir.printList();\n\n            System.out.println(\"\");\n            System.out.println(\"CSS = \" + CSS.getSize() + \" size\");     \n            System.out.println(\"Javascript = \" + Javascript.getSize() + \" size\");     \n    }\n```\n### Result\n```\n/Dev-Docs/CSS\n/Dev-Docs/CSS/WebToMobile.md\n/Dev-Docs/Javascript\n/Dev-Docs/Javascript/Ajax.md\n/Dev-Docs/Javascript/Observer.md\n\nCSS = 100 size\nJavascript = 200 size\n```\n## Composite 패턴의 사용\n\n- 객체들 간 계층 구조가 있을 경우\n\n- 클라이언트가 단일 객체와 복합 객체를 구분하지 않고 동일한 형태로 사용하고자 경우\n\n- 개별적인 객체들과 복합 객체의 처리 방법 차이가 없을 경우\n\n## 패턴의 장단점\n\n### 장점:\n\n- 복합 객체를 사용하고 있는지, 단일 객체를 사용하고 있는지에 대해서 신경 쓰지 않아도 되므로 클라이언트를 단순화시킬 수 있다\n\n- 복합 객체를 하나의 단일화된 객체처럼 취급 할 수 있으므로 **일괄적인 관리(반복 잡업 등)** 시 편리하다\n\n- 개별 객체들을 조합하여 동작이 다른 여러 복합 객체들을 만들어 낼 수 있어 **확장성**이 뛰어나다\n\n- 기존의 코드를 **수정하지 않아도** 새로운 종류의 객체를 추가하기 쉽다\n\n### 단점:\n\n- 설계를 일반화시키기 때문에 특정 Component 객체로만 Composite 객체를 구성하고 싶을 경우에 문제가 발생할 수 있다.\nComposite 패턴에서 Component 클래스의 모든 하위 클래스 객체는 동일하게 Composite 객체를 구성하기 위한 요소로 사용될 수 있기 때문이다\n\n## 논의점\n\nComposite 패턴에서는 `1) 계층구조를 관리하는 일` `2) 하위 객체와 관련된 작업을 처리하는 일`의 2가지 역할을 하고 있는데, 이는 단일 역할 원칙에 위배되는 것이 아닌가?\n- Composite 패턴은 단일 역할 원칙을 깨는 대신에 투명성을 확보 할 수 있는 패턴이라고 할수 있다. 투명성(transparency)란 추상 클래스에 하위 객체 관리, Leaf의 기능을 모두 넣음으로써 클라이언트에서 일괄적인 처리가 가능하도록 만든 효과를 말한다.\n\n\n\n#### Reference\n\n\n[DesignPattern : 컴포지트 (Composite)](http://egloos.zum.com/EireneHue/v/979992)\n\n\n[헤드퍼스트 디자인 패턴: 11. 컴포지트 패턴](https://plposer.tistory.com/29)\n\n\n[[디자인 패턴 7편] 구조 패턴, 컴퍼지트(Composite)](https://dailyheumsi.tistory.com/193)\n"
  },
  {
    "path": "Design_Pattern/JSP model.md",
    "content": "살짝(?) 늦은 감이 있지만 MVC에 대해 정확히 알아보고자 문서를 새로 작성하기로 하였다.\n\n저번 시간에  MVC1, MVC2 model의 차이점을 알아보았는데 사실 MVC1, MVC2 model은 실제로 존재하지 않는다고 한다.\n\n대개 사람들은 MVC2가 우리가 말하는 MVC model이라고 불리는데, 이 둘은 완전히 다른 개념이다.\n\n웹 프로그래밍과 MVC에 대해 차근차근 알아보자.\n\n# 웹 애플리케이션의 디자인 모델\n웹 애플리케이션이란, 웹 브라우저와 사용자와 대화하는 대화식으로서 인터넷을 이용하는 일종의 컴퓨터 프로그램을 말한다.\n\n웹 애플리케이션의 디자인에는 일반적으로 두 가지의 디자인 모델이 있다.\n\n바로 `Model 1 JSP programming`, `Model 2 JSP programming`이다. \n이것이 MVC1, MVC2라고 불리게 된 원인이다.\n\n## Model 1 JSP programming\n\n### Servlet\n> JAVA 코드 내에  HTML 코드 삽입\n\n![servlet](https://user-images.githubusercontent.com/43868540/99893233-df804300-2cc0-11eb-9514-78cc6c21b25d.PNG)\n\n> [출처 mingyu0403.tistory](https://mingyu0403.tistory.com/49)\n\n처음에 웹 개발은 `Sevlet`을 이용하여 개발하였다. 서블릿은 자바를 이용해서 작성하기 때문에 자바언어에 대한 지식을 가지고 있어야 했다. 하지만 웹 디자이너들은 쓰여진 JAVA 코드를 이해해야했고 코드를 유지하면서 프레젠테이션 로직을 변경하는 것이 어려웠다. 또한, `Sevlet`을 이용한 웹 페이지는 코드가 수정되면 다시 .class 파일을 컴파일을 해야 하는 단점이 있었다.\n\n### JSP\n> HTML 코드 내에 JAVA 코드 삽입\n\n![jsp](https://user-images.githubusercontent.com/43868540/99893226-c7a8bf00-2cc0-11eb-8be9-46139aeb99b9.PNG)\n\n> [출처 mingyu0403.tistory](https://mingyu0403.tistory.com/49)\n\n이 문제를 해결하기 위해서 `Sevlet` 대 `JSP`개념이 등장하게 되었고 디자이너는 JAVA 지식을 가질 필요가 없어졌다. 또한, `JSP`를 활용해 웹 디자이너는 프레젠테이션 로직만 따로 기술해 코드를 유지하기가 쉬워졌다.\n\n이것이 바로 `Model 1 JSP programming`이라고 불려왔고 `MVC1`이라고도 불렸다.\n\n![JSP Model 1](https://user-images.githubusercontent.com/43868540/99762801-a919bb00-2b3c-11eb-9abc-0dbcaab37dea.png)\n\n> [출처 wikipedia](https://en.wikipedia.org/wiki/JSP_model_1_architecture)\n\n1. 브라우저가 JSP 페이지에 대한 요청을 보낸다.\n2. JSP는 Java Bean에 액세스하고 비즈니스 로직을 호출한다.\n3. Java Bean은 데이터베이스에 연결하고 데이터를 가져오거나 저장한다.\n4. 응답은 JSP에 의해 생성된 브라우저로 전송된다.\n\n하지만 `JSP`를 이용한 프로그래밍도 단점이 있다. 개발자들은 `JSP`를 이용해 데이터베이스에서 접근하였고 `Sevlet`역할도 하였다. 따라서 요청 처리, 데이터 유효성 검사, 비즈니스 로직 처리 및 응답 등 요청에 대한 모든 책임을 `JSP`에서 처리하였다. 즉, 프레젠테이션 로직과 비즈니스 로직을 분리하지 못하였다.\n\n## MVC\n프레젠테이션 로직과 비즈니스 로직을 분리하기 위해 Trygve Reenskaug가 `MVC` 패턴을 발명하였다.\n`MVC`는 Model-View-Controller로 이루어져 프로그램 로직을 나누고 개발하는 소프트웨어 설계 패턴이다.\n\n따라서\n- `Sevlet`이 `Controller`역할을 하여 프레젠테이션 로직과 비즈니스 로직 사이의 상호 동작을 관리한다.\n- 기존에 `JSP`에 쓰였던 프레젠테이션 로직을 `View`에 기술하여 인터페이스 요소를 나타내고\n- 데이터베이스에 접근하기 위해 `Bean`을 작성해 `Model`역할을 한다.\n\n이렇게 로직을 분리해 대규모 프로그램을 개발하고 유지 보수하기에 수월해졌다.\n\n1. 브라우저가 요청을 보내고 Contoller(SERVLET)로 전달한다.\n2. 요청받은 Controller는 비즈니스 요구사항을 충족하는 데 필요한 모델(Bean)을 가져온다.\n3. 응답 프레임을 설정하고 응답을 뷰 구성요소(JSP)로 전달한다.\n\n## Model 2 JSP programming\n이렇게 로직을 분리하여 개발한 프로그래밍이 `Model 2 JSP programming`이라고 한다. 이것 또한 역시 `MVC2`라고 잘못 불린 개념이다. \n`Model 2`는 비즈니스 로직과 프레젠테이션 로직을 분리하므로 일반적으로 MVC ( 모델-뷰-컨트롤러 ) 패러다임을 활용한 모델이라고 할 수 있다.\n\n![Model 2 JSP programming](https://user-images.githubusercontent.com/43868540/99875933-9b486080-2c36-11eb-86bd-38d38b4d2058.PNG)\n\n>[출처 wikipedia](https://en.wikipedia.org/wiki/JSP_model_2_architecture#cite_note-5)\n\n`Model 2`는 로직을 `JSP`에서 분리하여 `Sevlet`에 배치하고 `Sevlet`이 `Controller` 로 이용된다.\n`Controller`는 사용자로부터 응답을 받아 로직을 수행하고 `Model`을 가져온다. 그 후에 응답을 전달받은 `View`는 사용자에게 응답을 보여준다.\n\n이처럼 복잡한 설계 패턴 때문에 중형 및 대형 애플리케이션에 권장된다.\n\n# 오해\n일반적으로 사람들에게 널리 알려진 `MVC2`라는 개념은 `MVC` 패턴에서 발전된 차세대 패턴이라는 잘못된 믿음을 주기 쉽다.\n하지만 이는 `MVC`패턴을 이용한 `Model 2 JSP programming`이었고 `MVC2`라는 용어는 남용되고 있었다는 것을 알 수 있었다.\n아마 `model2` 용어가 너무 길기 때문에 줄여서 부르다 보니 만들어진 해프닝인 것 같다.\n\n아직 많은 사람이 MVC 패턴이 MVC2 모델이라고 알고 있고 나 또한 그랬었다. 이번 시간을 통해 정확히 개념을 바로잡는 시간이 되었기를 바란다.\n\n잘못된 개념을 바로 잡아준 @Dae-Hwa 님께 감사합니다 :)\n\n----\n#### Reference\n- [JSP 모델 1 아키텍쳐](https://en.wikipedia.org/wiki/JSP_model_1_architecture)\n- [JSP 모델 2 아키텍쳐](https://en.wikipedia.org/wiki/JSP_model_2_architecture#cite_note-5)\n- [MVC 패턴](https://ko.wikipedia.org/wiki/%EB%AA%A8%EB%8D%B8-%EB%B7%B0-%EC%BB%A8%ED%8A%B8%EB%A1%A4%EB%9F%AC)\n- [MVC1과 MVC2의 차이](https://technicalrecyclebin.wordpress.com/2012/11/14/difference-between-mvc1-and-mvc2/)\n- [Model 1 vs Model 2](https://www.oreilly.com/library/view/programming-jakarta-struts/0596006519/ch01s04.html)\n"
  },
  {
    "path": "Design_Pattern/MSA.md",
    "content": "# MicroService Architecture\n\n## Monolithic Architecture\n> Monolithic : 단단히 짜여 하나로 되어 있는\n\nMonolithic Architecture는 전통적인 웹 시스템 개발 스타일로, 모든 컴포넌트가 하나의 애플리케이션 내에 들어가 있는 구조이다. 예를 들어 온라인 쇼핑몰 애플리케이션을 구현할 때, 하나의 애플리케이션에 유저관리 서비스, 상품관리 서비스, 주문 관리 서비스 등을 만들고 하나의 서버(예를 들어 Tomcat)에서 이를 처리하도록 하는 것을 말한다.   \n  \n하나의 애플리케이션만 개발하면 되기 때문에 관리, 배포 및 테스트가 편리하고,\n서비스간의 상호작용은 Method 호출을 이용하기 때문에 높은 성능을 보인다는 장점이 있다. 하지만 대형 시스템 개발 시에는 몇가지 문제점을 보인다. \n\n* 부분 장애가 전체 서비스 장애로 확대된다.\n\n* 특정 기능에 한정해 선택적으로 확장할 수 없다. \n\n* 여러 컴포넌트가 하나의 서비스에 강결합 형태로 되어 있어 서비스의 변경이 매우 어렵고, 수정시 장애 영향도를 파악하기 힘들다.\n\n* 빌드 시간, 테스트 시간이 길어진다.\n\n* 지속적인 배포가 어려워진다.\n\n<br/>\n\n## MicroService Architecture\n\n이러한 문제점을 해결하기 위해 등장한 것이 MSA이다. MSA는 각 서비스를 하나의 프로젝트로 구현하는 것을 의미한다. 즉, 각 서비스는 저마다의 서버와 DB를 갖는다. 구분된 각 단위를 **MS**라고 하며, MS가 합쳐져 **MSA**를 이루게 된다. MSA의 장점 및 특징은 다음과 같다. \n\n* 하나의 서비스가 다른 서비스에 영향을 주지 않는다.\n\n* 선택적 확장이 가능하다.\n\n* 빌드 및 테스트 시간이 단축된다.\n\n* 지속적인 배포가 가능하다.\n\n* 서비스간의 상호작용은 REST 방식의 호출을 통해 이루어지기 때문에 응답 처리 속도 및 성능 이슈가 있다. \n\n* 서비스가 여러 DB로 나뉘어 있기 때문에 데이터의 정합성을 유지하기 위한 트랜잭션 처리가 어려울 수 있다.  \n계좌이체 과정을 예를 들어, 통장에서 돈을 출금하는 서비스를 호출한 후 다른 통장에 입금하는 서비스를 호출하다가 에러가 발생했다면 Monolithic Architecture에서는 Rollback을 통해 간단히 처리할 수 있지만, MSA에서는 불가능할 수 있다.     \n이를 해결하기 위한 방법으로 `보상 트랜잭션`이 있다. 돈을 출금하는 서비스를 만들 때, 돈을 다시 입금하는 서비스를 만들어 놓고, 에러 발생 시 이 보상 트랜잭션을 호출하는 방법이다.   \n또 다른 방법으로 분산 트랜잭션 시나리오 자체를 없애는 것이 있다. 분산 트랜잭션이 꼭 필요한 경우에는 Monolithic Architecture 방식으로 접근하는 것이 사실 맞는 방법이다. MSA는 트랜잭션 보장이 중요한 시스템보다는 대규모의 B2C형 서비스에 적합하다.  \n\n\n<br/>\n\n## Circuit Breaker  \n\n위에서 언급했듯이, MSA의 장점 중 하나는 한 서비스에 장애가 생겨도 다른 서비스는 제공된다는 점이다. 그런데 만약, 장애가 생긴 서비스에 어떤 서비스가 접근한다면 어떻게 될까? 특정 서비스의 장애가 다른 서비스에도 전파되는, **장애 전파**가 발생한다. 이를 해결하기 위해서 등장한 것이 **Circuit Breaker** 다.  \n\nNefilx는 MSA를 제일 잘하는 기업 중에 하나이며 MSA 구축을 편하게 하는 기술과 갖가지 이슈에 대한 해결책을 제공하고 있다. 그 중 **Hystrix** 는 Neflix에서 제공하는 Circuit Breaker 구현체이다. \n\n### Hystrix 패턴\n\n![hystrix](../assets/images/hystrix.png)  \n\n `closed` 는 서비스의 초기 상태로, 서비스 호출 결과가 정상적인 경우 `closed` 상태를 유지한다.  \n 만약 결과가 비정상적인 경우에는 `fallback` 으로 정의된 내용이 return되고 서비스가 `open` 상태로 바뀐다. 이 상태에서는 서비스로의 모든 접속이 차단되며 정해놓은 `timeout` 이 지나면 `half-open` 상태로 바뀐다.  \n `half-open` 상태는 `open` 상태의 서비스가 `closed` 상태로 변환될 수 있는지 지속적으로 체크하는 상태로 볼 수 있다. `half-open` 상태인 서비스를 호출을 해보고 성공을 하면 `closed` 상태로 바뀌고 끝이 난다.   하지만, 실패를 하면 `open` 상태로 다시 돌아가게 되고 이 서비스는  `timeout` 이 지난 후 다시 `half-open` 상태가 되는 이런 루틴이 반복된다.  \n\n<br/>\n\n## API GATEWAY\n\nMSA는 한 서비스에 한 개 이상의 서버가 존재하기 때문에 이 서비스를 사용하는 클라이언트 입장에서는 다수의 end point가 생기게 되며, end point가 변경되었을 때 관리하기가 힘들다. 그래서 MSA 환경에서 서비스에 대한 도메인을 하나로 통합할 수 있는 **API GATEWAY**가 필요하다. API GATEWAY는 API 서버 앞단에서 인증, 라우팅 기능 등 많은 기능을 담당할 수 있다. \n\n### Zuul \n\nZuul은 Netflix에서 제공하는 API GATEWAY로, 다양한 형태의 Filter에 기능을 정의하여 이슈사항을 대비하고 있다. Filter를 크게 4가지로 나누면 다음과 같다.\n\n* PRE Filter   \n라우팅전에 실행되며 필터이다. 주로 logging, 인증등이 이곳에서 이루어진다.  \n\n* ROUTING Filter   \n요청에 대한 라우팅을 다루는 필터이다. Apache httpclient를 사용하여 정해진 Url로 보낼수 있고, [Neflix Ribbon](https://coe.gitbook.io/guide/load-balancing/ribbon)을 사용하여 동적으로 라우팅 할 수도 있다.  \n\n* POST Filter   \n라우팅 후에 실행되는 필터이다. response에 HTTP header를 추가하거나, response에 대한 응답속도, Status Code, 등 응답에 대한 statistics and metrics을 수집한다.  \n\n* ERROR Filter   \n에러 발생시 실행되는 필터이다.\n\n<br/>  \n\n### 인증  \n\n클라이언트에 대한 인증을 API GATEWAY에서 직접적으로 하는 것은 아니다. API GATEWAY의 뒷단의 인증 서버에서 클라이언트를 인증하면 API GATEWAY는 APItoken을 발급해준다.   \nAPItoken은 API를 호출할 수 있는 권한 정보를 갖는다. 권한 정보는 토큰 자체에 저장되거나 서버에 저장될 수 있는데, 토큰 자체에 저장하는 형태를 클레임 기반의 토큰이라고 한다. 근래에 유행하는 JWT(JSON Web Token)이 여기에 해당된다. \n```\n  {\n    “name”:”JHRla”,\n    “role”:[“admmin”,”enduser”]\n  }\n```\n클레임 기반 토큰은 일정량 이상의 정보를 담기 어려우며 한번 발급된 토큰은 변경이 어렵다. 때문에 토큰의 유효기간을 설정하여 주기적으로 재발급하는 방식이 사용된다.\n\n서버에 권한 정보를 저장하는 경우에는 클라이언트에 unique한 값만 부여한다. 때문에 보안상 유리하고, 많은 정보를 담을 수 있다. 하지만 모든 API 호출마다 서버에서 정보를 가져와야하기 때문에 DBMS보다는 [redis](https://github.com/Im-D/Dev-Docs/blob/master/Network/Cookie%EC%99%80%20Session%20%EA%B7%B8%EB%A6%AC%EA%B3%A0%20Redis.md#redis%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-session-%EA%B4%80%EB%A6%AC)와 같은 메모리 기반의 고속 storage를 사용하는 것이 좋다. \n\n<br/>\n\n#### Reference\n[Monolithic Architecture 란?](https://alwayspr.tistory.com/19)  \n[Microservice Architecture 란?](https://alwayspr.tistory.com/20)  \n[대용량 웹서비스를 위한 마이크로 서비스 아키텍쳐의 이해](https://bcho.tistory.com/m/948)  \n[배민 API GATEWAY - spring cloud zuul 적용기](http://woowabros.github.io/r&d/2017/06/13/apigateway.html)  \n[MSA 아키텍쳐 구현을 위한 API 게이트웨이의 이해](https://bcho.tistory.com/1005)    \n[행복을 찾기 위한 우리의 여정](https://medium.com/coupang-tech/%ED%96%89%EB%B3%B5%EC%9D%84-%EC%B0%BE%EA%B8%B0-%EC%9C%84%ED%95%9C-%EC%9A%B0%EB%A6%AC%EC%9D%98-%EC%97%AC%EC%A0%95-94678fe9eb61)  \n[Hystrix](https://coe.gitbook.io/guide/circuit-breaker/hystrix)  \n"
  },
  {
    "path": "Design_Pattern/MVC1, MVC2.md",
    "content": "# MVC1 vs MVC2\n주제를 무엇으로 하면 좋을까 생각하다가 MVC model에는  `MVC1`, `MVC2` 이렇게 두 가지 모델이 있다는 것을 발견하였다. \n\n생소한 단어였기 때문에 정리를 해보았다.\n\n## MVC\n우선 MVC란 `Model`, `View`, `Controller`의 줄임말로써 사용자와 상호작용하는 S/W를 디자인함에 있어 세 가지 요소로 쪼개어 하는 것을 가리킨다. \n\n### MVC를 사용하는 이유\n비즈니스 로직을 분리하여 애플리케이션의 시각적 요소나 그 이면에서 실행되는 비즈니스 로직을 서로 영향 없이 쉽게 고칠 수 있는 애플리케이션을 만들 수 있기 때문에 사용한다.\n\n예를 들어 디자인이 수시로 바는 경우 로직을 분리하지 않으면 서로 영향 없이 코드를 고치기에는 쉽지 않을 것이다. \n\nMVC 모델을 사용한다면 유지 보수 및 확장성을 높일 수 있다. \n\n**1. Model**\n> 프로그램의 내부 상태, 내부 비즈니스 로직을 처리하기 위한 역할이다.\n\n**2. Controller**\n> 사용자의 입력 처리와 흐름 제어를 담당하고 뷰와 모델을 분리하는 역할을 한다.\n\n**3. View**\n> 사용자 인터페이스 요소를 뜻하는데, 유저에게 보여주는 화면을 말한다. \n\n## MVC1\n쉽게 말해 `M+(V+C)`라고 보면 된다.\n\n- 웹 브라우저의 요청을 jsp 페이지가 받아서 처리하는 구조이고, **JSP가 Controller와 View의 기능을 모두 담당**한다.\n- jsp 페이지에 비즈니스 로직을 처리하기 위한 코드와 웹 브라우저에 결과를 보여주기 위한 출력 관리 코드가 뒤섞여 있는 구조이다.\n- jsp 내부에서 java로 Controller의 기능을 수행한다. view는 HTML과 CSS로 처리하고 event 처리 및 제어는 javascript로 실행한다.\n- 재사용이 힘들고, 코드가 뒤섞여 있어 가독성이 떨어진다.\n> 많은 프로세싱이 요구되는 대형 프로젝트의 경우 적합하지 않다.\n\nMVC1의 이해를 돕기 위해 [예제](https://itsaessak.tistory.com/64)을 참고하길 바란다. \n\n![MVC1 model](https://user-images.githubusercontent.com/43868540/88455376-c18c0880-ceaf-11ea-90b2-fcf2be11b7f6.png)\n- [출처 creator0609.tistory](https://creator0609.tistory.com/entry/MVC1-MVC2-차이)\n\n### 장점\n- 단순해서 **개발 시간 단축**에 유리하다.\n- **중소형 프로젝트**에 적합하다.\n\n#### 단점\n- 웹 애플리케이션이 복잡해질수록 유지 보수가 힘들어진다.\n- 디자이너와 개발자 간의 원활한 소통이 필요하다.\n\n## MVC2\n일반적으로 MVC라고 하면 MVC2모델을 이야기한다고 보면 된다.\n\n- MVC1 구조와 달리 웹 브라우저의 요청을 하나의 `서블릿`이 받게 된다. 여기서 서블릿은 `controller`이다. \n- `서블릿`은 웹 브라우저의 요청을 알맞게 처리한 후 그 결과를 jsp 페이지로 넘기게 된다.\n> 서블릿은 웹 프로그래밍에서 클라이언트의 요청을 처리하고 그 결과를 다시 클라이언트에게 전송하는 자바 프로그래밍을 이야기한다. \n- 요청 처리, 데이터 접근, 비즈니스 로직을 포함하는 **Controller와 View가 엄격히 구분**되어 있다. \n> 대형 프로젝트의 경우에는 적합하나 구조 설계를 위한 충분한 시간이 필요하다. \n\nMVC2의 예제도 [이곳](https://itstudyroom.tistory.com/entry/MVC2-게시판-2-로그인)을 참고하면 MVC1모델과는 다른 것을 확인할 수 있다.\n\n![MVC2 model](https://user-images.githubusercontent.com/43868540/88455358-a5886700-ceaf-11ea-9be5-38e234dbfd7c.png)\n- [출처 creator0609.tistory](https://creator0609.tistory.com/entry/MVC1-MVC2-차이)\n\n### 전체적인 컴포넌트 설계\n![전체적인 컴포넌트 설계](https://user-images.githubusercontent.com/43868540/88455435-39f2c980-ceb0-11ea-8123-4e31d9db21e1.png)\n- [출처 creator0609.tistory](https://creator0609.tistory.com/entry/MVC1-MVC2-차이)\n\n### 장점\n- 비즈니스 로직과 뷰가 분리되어 **유지 보수 및 확장성**이 뛰어나기 때문에 큰 프로젝트에서 사용된다.\n- 개발자, 디자이너의 역할이 분리되어 **책임이 분명**해진다.\n\n### 단점\n- 개발 초기 비용 증가 및 개발 기간이 늘어난다. \n----\n#### Reference\n- [MVC1과 MVC2의 개념](https://nickjoit.tistory.com/9)\n- [MVC1,2의 장단점](http://blog.naver.com/PostView.nhn?blogId=koliaok&logNo=220566166684&categoryNo=0&parentCategoryNo=0&viewDate=&currentPage=1&postListTopCurrentPage=1&from=postView)\n"
  },
  {
    "path": "Design_Pattern/MVC_MVP_MVVM.md",
    "content": "# MVC, MVP, MVVM\n\n간단하게 많이 사용하는 패턴을 정리를 해보자.\n<br/>\n\n웹개발시 쓰이는 패턴들은 다양하게 존재한다.<br/>\n그 중에서 3개를 보게되면 공통점은 모두 화면에 보여주는 로직과 실제 데이터가 처리 되는 로직이 분리되어 있다는 것이다.\n<br/>\n\n솔직히 패턴을 사용하지 않고도 충분히 짤 수는 있겠지만 모든 것은 나중에 한 번에 터지듯이 쌓이다 보면 한꺼번에 리팩토링을 하기에는 무리가 있는 것이다.\n<br/>\n\n## **MVC (Model + View + Controller)**\n\nMVC 패턴은 3가지의 요소로 구성이 되어있다.\n<br/>\n\n- Controller : 사용자의 입력을 받고 처리하는 부분\n- Model : 프로그램에서 사용되는 실제 데이터 및 데이터 조작 로직을 처리하는 부분\n- View : 사용자에게 제공되어 보여지는 UI 부분\n\n<br/>\n\n처음 알게된 패턴이 바로 이 패턴이었다. 당시 내용은 스프링으로 작업을 할 때 많이 봤었다. \n<br/>\n\n![MVC](https://github.com/SeonHyungJo/FrontEnd-Dev/blob/master/assets/image/MVC.png?raw=true)\n\n<br/>\n\n1. 사용자가 처음 주소를 입력하고 Enter를 누르게 되면 `Controller`에 먼저 요청이 들어간다.\n2. 이에 `Controller`는 해당 주소에 맞는 데이터를 `Model`에 요청을 하며 불러오게 되고,\n3. `Model`은 해당 데이터들을 보여줄 `View`를 선택해서 화면에 보여주게 된다.\n\n<br/>\n\n**MVC의 단점은 View와 Model이 서로 의존적이라는 점이다.**\n<br/>\n\n## **MVP (Model + View + Presenter)**\n\n여기서는 한눈에 보아도 눈에 띄는 것은 바로 `Presenter`입니다.\n<br/>\n\n- Presenter : `View`에서 요청한 정보를 `Model`로 부터 가공해서 `View`로 전달하는 부분\n- Model : 프로그램에서 사용되는 실제 데이터 및 데이터 조작 로직을 처리하는 부분\n- View : 사용자에게 제공되어 보여지는 UI 부분\n\n<br/>\n\n이제 사용자의 입력의 시작은 `View`에서 시작을 한다. 이에 `Presenter`는 `Model`과 `View`의 중간자 역할을 한다. 데이터를 처리하는 `Model`과 `View`는 서로 의존성이 떨어지게 된다.\n<br/>\n\n![MVP](https://github.com/SeonHyungJo/FrontEnd-Dev/blob/master/assets/image/MVP.png?raw=true)\n\n<br/>\n\n1. `View`로 사용자의 입력이 들어옵니다.\n2. `View`는 `Presenter`에 작업 요청을 합니다.\n3. `Presenter`에서 필요한 데이터를 `Model`에 요청 합니다.\n4. `Model`은 `Presenter`에 필요한 데이터를 응답 합니다.\n5. `Presenter`는 `View`에 데이터를 응답 합니다.\n6. `View`는 `Presenter`로부터 받은 데이터로 화면에 보여주게 됩니다.\n\n<br/>\n\n이것의 단점은 이제 `Model`과 `View`의 의존성은 떨어지게 되었지만 **`View`와 `Presenter`가 1:1로 강한 의존성을 가지게 된다는 것입니다.**\n<br/>\n\n## **MVVM (Model + View + ViewModel)**\n\n이제는 `Presenter`, `Controller`대신하여 `ViewModel`이라는 것이 생겼습니다.\n<br/>\n\n- ViewModel : `View`를 표현하기 위해 만들어진 `View`를 위한 `Model`\n- Model : 프로그램에서 사용되는 실제 데이터 및 데이터 조작 로직을 처리하는 부분\n- View : 사용자에게 제공되어 보여지는 UI 부분\n\n<br/>\n\n`MVVM`은 **2가지 디자인 패턴을 사용한다고 한다.** 바로 `Command패턴`과 `DataBinding`입니다.\n<br/>\n\n위의 2가지 패턴으로 인해 `View`와 `ViewModel`은 의존성이 완전히 사라지게 됩니다.\n<br/>\n\n`MVP`과 마찬가지로 `View`에서 입력이 들어오며, 입력이 들어오게 되면 `Command`패턴을 통해 `ViewModel`에 명령을 내리게 되고(Action) `DataBinding`으로 인해 `ViewModel`의 값이 변화하면 바로 `View`의 정보가 바뀌에 되는 것입니다.\n<br/>\n\n![MVVM](https://github.com/SeonHyungJo/FrontEnd-Dev/blob/master/assets/image/MVVM.png?raw=true)\n\n<br/>\n\n1. `View`에 입력이 들어오면 `Command`패턴으로 `ViewModel`에 명령을 합니다.\n2. `ViewModel`은 필요한 데이터를 `Model`에 요청 합니다.\n3. `Model`은 `ViewModel`에 필요한 데이터를 응답 합니다.\n4. `ViewModel`은 응답 받은 데이터를 가공해서 저장 합니다.\n5. `View`는 `ViewModel`과의 `Data Binding`으로 인해 자동으로 갱신 됩니다.\n\n<br/>\n\n위와 같은 **MVVM 패턴**은 SPA에서 리액트나 뷰의 진형에서 사용되고 있는 패턴이다. 모든 패턴들이 완벽하지는 않다 시간이 지나고 사용을 하면서 발전하는 것이 바로 패턴인 것이다. :running:\n\n---\n\n#### Reference\n\n- [마기의 개발블로그](https://magi82.github.io/android-mvc-mvp-mvvm/)"
  },
  {
    "path": "Design_Pattern/Memoization.md",
    "content": "# Memoization\n\n`React` 10월 말을 기준으로 **새로운 릴리즈**가 올라왔다.\n<br/>\n`React.memo`라는 새로운 기능이 나오게 되었다.\n<br/>\n\n최근 회사에서 사용하는 `vue`의 컴포넌트를 1300개 가량을 그리게 되면 13초의 시간이 걸리는 이슈가 생겨서 생각을 하고 있었는데 `React`에서는 16.6버전에 `Memoization`기능이 추가가 되었다. 더 많은 기능의 설명은 해당 주소로 이동하면 된다.\n<br/>\n\n`Memoization`을 간단하게 말을 하자면 컴포넌트를 캐시를 해놓고 같은 컴포넌트를 만들때 캐시된 내용을 먼저 보고 있다면 새로 만드는 것이 아닌 캐시된 컴포넌트 내용을 보고 만드므로써 성능, 속도를 향상 시키는 것이다.\n<br/>\n\n그렇다면 js에서는 어떻게 사용할 수 있을까?\n<br/>\n\n자바스크립트에서는 반복적으로 계산되는 함수는 **메모이제이션 패턴**으로 구현을 한다.\n<br/>\n\n계산 결과를 저장해 놓아 이후에 **다시 계산할 필요없이 사용가능하도록 저장해놓은 캐싱과 같은 기능 메모이제이션**이라고 한다.\n<br/>\n\n가장 좋은 예시는 피보나치 수열로 하는 것이다.\n기존의 3!에서 4!을 다시 구하는데 있어서 새로 처음부터 계산을 해나가는 것이 아니다.\n<br/>\n\n아래에서 피보나치수열로 예를 들어보도록 하자.\n<br/>\n\n피보나치수열은 `0, 1, 1, 2, 3, 5, 8, 13, 21, ... `으로 나타나는 수열이다.\n<br/>\n\n## 일반코드 \\#1\n\n```js\nfunction fibonacci(n) {\n    if (n < 2) {\n         return n;\n    }\n    else {\n         return fibonacci(n-1) + fibonacci(n-2);\n    }\n}\nfibonacci(5);\n```\n\n<br/>\n\n## 일반코드 \\#2\n\n삼항연산자를 사용하여 코드 정리\n\n```js\nfunction fibonacci(n) {\n    return n < 2 ? n : fibonacci(n-1) + fibonacci(n-2);\n}\nfibonacci(5);\n```\n\n<br/>\n\n## Memoization을 사용한 코드 \\#3\n\n`memo` 배열에 계산한 값을 저장해 놓은 후, 다시 계산하지 않고 사용하도록 개선\n\n```js\nlet memo = [0,1];\n\nfunction fibMemoization(n) {\n   if(typeof memo[n] !== 'number') {\n     memo[n] = fibMemoization(n-1) + fibMemoization(n-2);\n   }\n   return memo[n];\n}\nfibMemoization(5);\n```\n\n연산할 값이 크면 클수록 `Memoization`을 사용했을 때와 하지 않았을때의 성능은 크게 차이가 난다.\n<br/>\n\n재귀적으로 `fibonacci`함수를 몇번 호출하는지 비교를 통해서 알아볼 수 있다.\n<br/>\n\n```js\nvar count = 0;\n\nfunction fib(n) {\n   count++;\n   console.log('called fib: ', count);\n   return n<2 ? n : fib(n-1) + fib(n-2);\n}\n\nvar beforeDate = new Date();\n\nfib(15);\n\nvar afterDate = new Date();\n\nconsole.log(afterDate - beforeDate);\n```\n\n<br/>\n\n```js\nvar memo = [0,1];\nvar count = 0;\n\nfunction fibMemoization(n) {\n   count++;\n   console.log('called fibMemoization: ', count);\n   if(typeof memo[n] !== 'number') {\n     memo[n] = fibMemoization(n-1) + fibMemoization(n-2);\n   }\n   return memo[n];\n}\n\nvar beforeDate = new Date();\n\nfibMemoization(15);\n\nvar afterDate = new Date();\n\nconsole.log(afterDate - beforeDate);\n```"
  },
  {
    "path": "Design_Pattern/RxJS.md",
    "content": "# [FEConf2017] RxJS\n\n## 주제 : RxJS 써야겠어요? 안써야겠어요?_손창욱\n\nRxJS에 대한 약간의 오해와 본질을 바라보는 시간을 가지려는 시간\n<br/>\n\n## 비동기처리\n\nRxJS 말고도 현재는 \n\n- CallBack\n- Promise\n- Generator\n- Async/Await(심지어 비동기를 동기처럼 사용하고 싶어서 만들어짐)\n\n가 있다.\n<br/>\n\n위에 있는 이것들은 모두 표준이다. \n<br/>\n\n표준을 알고있다면 어떻게 변하든 개발자입장에서는 좋다. 그런데 **RxJS도 표준이다.**\n<br/>\n\n## Functional과의 관련성\n\nRxJS가 연관은 있지만 본질은 아니다.\n<br/>\n\nRxJS가 담당하는 영역\n\n- **비동기 처리**\n- **데이터 전파**\n- **데이터 처리**\n\n위와 같이 3가지로 바라볼 수 있다.\n<br/>\n\n## 결국 RxJS는!!\n\n**일관된방식으로 안전하게 데이터 흐름을 처리하는 라이브러리 이다.**\n\n모든 어플리케이션은 궁극적으로 상태머신이다.\n<br/>\n~~입력값에 따라 로직을 짜고 상태변화에 따라 결과값이 나오게 된다.~~\n<br/>\n\n## 개발자가 처리하는 입력값은 어떤 것들이 있는가?\n\n- 배열 데이터도 입력값으로\n- 함수 반환값도 입력값으로\n- 키보드를 누르는것도 입력값으로\n- 마우스를 움직이는 것도 입력값으로\n- 원격지의 데이터도 입력값으로\n- DB데이터도 입력값으로\n- ...\n\n## 개발자의 고민 중하나\n\n어떤것은 동기\n<br/>\n어떤것은 비동기\n<br/>\n동기는 흐름대로 가기 때문에 편안하다. 그러나 느리다라는 단점을 가지고 있다. 이래서 비동기를 사용한다.\n<br/>\n\n우리의 처리방법은 ...\n\n- 어떤것은 함수 호출\n- 어던것은 이벤트\n- 어떤것은 callback\n- 어떤것은 Promise\n\n각각에 따라 처리해야한다는 문제가 있다.\n\n- 배열을 처리하는 경우는  ...\n- 함수를 호출하는 경우는 ...\n- 마우스를 클릭하는 경우 ...\n- Ajax를 호출하는 경우 ...\n\n위의 4가지의 경우는 **결국 시간축에 있어서는 동기와 비동기는 같다.!!!**\n<br/>\nRx가 위에서 말했듯이 하나의 처리로 이루어진다.\n<br/>\n\n## Observable\n\n시간을 인덱스로 둔 컬렉션, **Observable자체가 Immuable**이다.\n<br/>\n\n**모두 Observable로 처리한다.**\n<br/>\n\n모든 어플리케이션은 \n<br/>\n~~궁극적으로 상태머신이 아니다.~~ 궁극적으로 상태머신의 집합이다. \n<br/>\n\n의존관계가 있는 상태머신에게 변경된 상태 정보를 어떻게 전달하지?\n<br/>\n\n## Reactive Programming\n\n데이터흐름과 상태변화 전파에 중점을 둔 프로그램 패러다임이다.\n<br/>\n\n사용되는 프로그래밍 언어에서 데이터 흐름을 쉽게 표현할 수 있어야하며 기본 실행 모델이 변경사항을 **데이터흐름**을 통해 **자동으로 전파한다는 것**을 의미한다.\n<br/>\n\n## 이미 우리는 알고 있다. ⇒ **옵저버 패턴(Observer pattern)**\n\nSubject의 변경사항이 생기면 자동으로 Observer의 update를 호출한다.\n<br/>\n\n**Observer pattern을 적용하자**\n<br/>\n\n상태 자동 전파(Loosely coupling) => RxJS는 next, error, complete의 3가지 상태를 전달받는다.\n<br/>\n\n## 데이터를 받은 후에는 뭐하니?\n\n데이터를 받은 후에 받은 데이터를 가공한다.\n<br/>\n\n### 기존\n\n1. Ajax로 데이터를 받음 ⇒ 데이터를 받고 받은 것을 가지고 처리한다.\n2. 데이터를 가공함 ⇒ process함수\n\n조건문, 반복문 덩어리로 구성되어있다.\n\n조건문은 **코드의 흐흠을 분리**하고\n\n반복문은 **코드의 가독성**을 떨어뜨림\n\n주관심사인 **비즈니스 로직은 코드에 파묻힘**\n\n⇒ **고차함수를 제공한다.**\n<br/>\n\n## 고차함수\n\n다름함수를 인자로 받거나 그 결과로 함수를 반환하는 함수\n\n> 고참함수는 변경되는 주요 부분을 함수로 제공함으로서 동일한 패턴 내에 존재하는 문제를 손쉽게 해결할 수 있는 고급 프로그래밍 기법이다.\n\nfilter, map, reduce, ...와 같은 고차함수의 operator를 제공\n<br/>\n\n내가 실행한 로직이 나의 의도와 상관없게 외부에 영향을 미친다면?\n<br/>\n\n## Side Effect(부수효과)\n\n함수에 드러나지 않는 입력값은 부원인(Side Cause) 라고 하고 이로 인해 발생한 결과를 부작용(Sdie Effect) ⇒ 호출할 때마다 달라진다.\n<br/>\n\n그래서,\n<br/>\n\n모든입력값을 명시적으로 나타내거나, Immuable데이터를 사용한다(순수함수 형태로 한다. 그래야 컨트롤이 편해진다.).\n<br/>\n\n## Functional Programming\n\n함수형 프로그래밍 은 자료 처리를 수학적 함수의 계산으로 취급하고 상태변경과 가변 데이터를 피하려는 프로그래밍 패러다임의 하나이다.\n\nFunctional Programming은 **순수함수를 지향한다.**\n\n- 같은 입력이 주어지면, 항상 같은 출력을 반환한다.\n- 부작용을 발생시키지 않는다.\n- 외부의 Muable한 데이터에 의존하지 않는다.\n\n**RxJS는 함수형 프로그래밍의 순수함수를 지향한다.**\n\n## RxJS 주요개념\n\n- Observable\n- Operator(map, filter, reduce)\n- Observer\n- Subscription\n- ~~Subject~~\n- ~~Scheduler~~\n\n하지만 4대 천왕만 알면된다.\n<br/>\n다른거는 심화과정\n<br/>\n\n## RxJS 개발방법\n\n1. 데이터 소스를 Observable로 생성\n2. Observable의 Operator를 사용 ⇒ 데이터를 변경, 추출, 합침, 분리\n3. 원하는 데이터를 받아 처리하는 Observer를 만든다.\n4. Observable의 subscribe를 통해 Observer를 등록한다.\n5. Observable 구독을 정지하고 자원을 해지한다.\n\n# RxJS는\n\n**일관된방식으로** \n<br/>\n**안전하게** \n<br/>\n**데이터 흐름을 처리하는** \n<br/>\n**라이브러리이다.**\n\n---\n\n## Referece\n\n- [쉽게 써봅시다. RxJS! - 손찬욱](https://www.youtube.com/watch?v=2f09-veX4HA&list=PLZl3coZhX98pQQx4nFLdjx8xvWBNt0YEN&index=5)\n- [RxJS 써야겠어요? 안써야겠어요?](http://sculove.github.io/blog/2017/10/21/shoulduserxjs/)\n- [발표자료](https://sculove.github.io/slides/rxjs/#/2)"
  },
  {
    "path": "Design_Pattern/Singleton.md",
    "content": "# Singleton 패턴   \n\n## Singleton 패턴이란?   \n\n`Singleton`패턴은 클래스에 객체가 단 하나만 필요한 경우에 사용되는 디자인 패턴이다. \n예를 들어 시스템 안에서 1개밖에 존재하지 않는 것(ex. 컴퓨터 자체, 윈도우 시스템)을 프로그램으로 표현하고 싶을 때 사용한다.   \n\n>프로그래머가 주의를 기울여 객체를 1개만 생성한다면 `Singleton` 패턴을 사용하지 않을 수도 있겠지만 확실히 **보장 할 수 없다**.\n\n즉,\n- 지정한 클래스의 객체가 **절대로** 1개밖에 존재하지 않는 것을 **보증**하고 싶을 때\n- 객체가 1개밖에 존재하지 않는 것을 프로그램 상에서 표현하고 싶을 때\n\n`Singleton`패턴을 사용한다.\n\n## 자바의 Singleton 패턴 구현 방식\n\n### singleton 패턴 구현 \n\n- **static** 속성을 이용하여 객체를 인스턴스화 하지 않고 사용\n- 객체의 접근 제한자가 **private**이므로 직접적인 접근 불가능\n- 생성자가 **private** 으로 선언 되어있으므로 외부에서 new()를 통한 접근 불가능\n- **getInstance()** 메소드를 통해서만 객체에 접근 가능\n\n`Singleton` 패턴은 몇가지 방식으로 구현 할 수 있다.\n\n\n\n### eager Initialization\n\n```java\npublic class Singleton {\n    // Singleton 객체 하나를 생성해서 가리키는 정적 필드\n    // 클래스가 메모리에 로드될 때 한번 실행\n    private static Singleton makeInstance = new Singleton();\n\n    // private construct , new를 통한 객체 생성 불가\n    private Singleton() {}\n\n    // Singleton 객체 반환\n    public static Singleton getInstance() {\n        return makeInstance;\n    }\n}\n```\n`eager Initialization` 방식은 Singleton 인스턴스를 미리 생성해 놓는 방식으로, \n**Multi-thread** 환경이 아니면서 Singleton 인스턴스가 많은 일을 하지 않을 때 사용 할 수 있다. \n\n\n### Static block\n\n```java\npublic class Singleton {\n    //Instance\n    private static Singleton makeInstance;\n\n    //private construct\n    private Singleton() {}\n\n    static {\n        try { makeInstance = new Singleton();}\n        catch(Exception e) { \n\tthrow new RuntimeException(\"Create instace fail. error msg = \" + e.getMessage() ); }\n    }\n\n    public static Singleton getInstance() {\n        return makeInstance;\n    }\n}\n```\n`Static block` 방식은 `eager Initialization`방식에서 예외처리가 가능해진 형태이다.\n\n>**Static block** : 클래스가 로딩되고 클래스 변수가 준비된 후 자동으로 실행되는 블록\n\n\n\n위의 두방식은 클래스가 로딩될 때 실행되며,\n객체가 사용되기 이전 메모리를 점유하는 문제가 발생한다.\n\n\n\n\n### lazy Initialization\n\n```java\npublic class Singleton {\n\t\n\tprivate static Singleton makeInstance;\n\n\tprivate Singleton() {}\n\n\tpublic static Singleton getInstance() {\n\t\tif (instance == null) { makeInstance = new Singleton();}\n\t\treturn makeInstance;\n\t}\n}\n```\n\n`lazy Initialization`은 **getInstance()** 메소드가 호출 될 때, 클래스의 인스턴스가 사용되는 시점에 Singleton 객체를 생성한다. \n\n\n\n\n앞선 세가지 방식 모두 `Multi-thread`환경에서는 동작이 보장되지 못한다. \n\n\n\n\n![쓰레드](https://user-images.githubusercontent.com/43839951/79640641-8ce02500-81cd-11ea-8bc4-1f920b96c33c.JPG)\n\n만약, 위 그림의 상황에서 `스레드A`와 `스레드B`가 동시에 **getInstance()** 를 호출한 경우, 먼저 cpu를 할당받은 `스레드A`가 Singleton 객체를 생성하고, \n**makeInstance** 변수에 할당하기 직전에, `스레드B`가 CPU를 할당받고 **getInstance( )** 를 호출한다면,\n`스레드B` 또한 Singleton 객체를 생성 할 것이다.\n\n\n\n\n\n### Lazy Initialization with synchronized\n\n```java\npublic class Singleton {\n    private static Singleton makeInstance;\n\n    private Singleton() {\n    }\n\n    public static synchronized Singleton getInstance() {\n        if (makeInstance == null) {\n            makeInstance = new Singleton();\n        }\n        return makeInstance;\n    }\n}\n```\n\n `Multi-thread`환경에서 Singleton 패턴을 보장하기 위해서  **getInstance( )** 메소드를 `synchronized`로 선언하여 thread에서의 동시 접근에 대한 문제를 해결 할 수 있다. \n하지만 위의 방식은 객체 생성의 유무와 관계없이 **synchronized block** 을 거치게 되어 성능이 크게 저하된다.\n\n\n\n\n### Lazy Initialization. Double-Checked Locking(DCL)\n\n```java\npublic class Singleton {\n    private static Singleton makeInstance;\n\n    private Sigleton() {}\n\n    // Lazy Initialization. DCL\n    public Singleton getInstance() {\n      // instance가 null인 경우에만 synchronized block에 접근\n      if(makeInstance == null) {\n         synchronized(Singleton.class) {\n            if(makeInstance == null) {\n               makeInstance = new Singleton(); \n            }\n         }\n      }\n      return makeInstance;\n    }\n}\n```\n\n`DCL 방식`은 **객체가 아직 생성되어 있지 않은** 경우에만 `synchronized block`에 접근하므로 성능저하를 보완할 수 있다.\n\n\n\n\n\n\n## Singleton 패턴의 장점\n\n- 한번의 생성으로 객체를 사용하기 때문에 **고정된 메모리 영역**을 얻을 수 있으므로 `메모리 낭비`를 방지 할 수 있다.\n\n- Singleton으로 만들어진 객체는 `전역 객체`이기 때문에 다른 클래스의 객체들이 데이터를 **공유**하기 쉽다.\n\n\n\n\n## Singleton 패턴의 한계\n\n- Singleton으로 만든 객체의 역할이 복잡한 경우라면 해당 객체를 사용하는 \n`객체간의 상호 의존도`가 높아져서 **객체 지향 설계 원칙** 중 하나인 **개방-폐쇄 원칙** 에 어긋나게 된다.\n\n> **개방- 폐쇄 원칙(OCP, Open-Closed Principle)** : 소프트 웨어 개체(클래스, 모듈, 함수 등등)는 확장에 대해 열려 있어야 하고, 수정에 대해서는 닫혀있어야 한다는 객체 지향의 설계 원칙\n#### 참고\n-[개방 폐쇄 원칙 OCP (Open-Closed Principle)](https://lng1982.tistory.com/124)\n\n- `multi-thread`환경에서 동기화 처리 문제가 발생 할 수 있다. \n\n----\n#### Reference\n- [Java에서 싱글톤(Singleton) 패턴을 사용하는 이유와 주의할 점](https://elfinlas.github.io/2019/09/23/java-singleton/)   \n- [싱글톤 패턴(Singleton pattern)을 쓰는 이유와 문제점](https://jeong-pro.tistory.com/86)   \n- [싱글턴 패턴(Singleton Pattern)](https://medium.com/webeveloper/%EC%8B%B1%EA%B8%80%ED%84%B4-%ED%8C%A8%ED%84%B4-singleton-pattern-db75ed29c36)\n"
  },
  {
    "path": "Design_Pattern/Throttle and Debounce.md",
    "content": "# 쓰로틀링과 디바운싱\n\n## 공통점\n\n함수를 호출할 때 호출이 너무 많이 되어 과부화 됨을 방지하기 위한 장치다.\n\n함수 호출이 잦은 예로는 브라우저의 이벤트가 있다. onscroll 이나 onchange 와 같은 이벤트의 콜백으로 함수를 호출하는 경우 굉장히 많은 호출이 발생할 수 있다.\n\n## 예시\n\ninfinite scroll 이나 자동완성 기능의 경우 사용자의 특정 이벤트에 따라 비동기 콜백을 호출하는 방식이다. 이 경우 이벤트가 매우 빈번하게 일어나며, 많은 호출을 제어하지 않으면 브라우저가 버티지 못할 것이다. 이때 사용하는것이 쓰로틀링과 디바운싱이다.\n\n## 차이점\n\n### 쓰로틀링\n\n---\n\nThrottle 은 정해진 시간동안 특정 행위를 한 번만 호출하도록 하는 것이다. 예를 들어 스크롤 행위가 1 초에 500 번이 발생한다면 이를 0.2 초에 한 번만 실행하게 만들 수 있다. Throttle 처리가 되지 않은 경우 콜백이 500 번 발생한다. 하지만 Throttle 처리가 된다면 5 번만 실행되게 만드는 기술이다.\n\n생각보다 스크롤 이벤트의 경우 작은 움직임에도 엄청나게 많은 이벤트가 발생한다. 따라서 1 초 미만으로 쓰로틀링을 하여 같은 동작의 여러번 호출을 1 번으로 제어하는 것이 좋겠다.\n\n### 디바운싱\n\n---\n\nDebounce 는 한 행위를 여러번 반복하는 경우, 마지막 행위 이후 특정 시간이 흐른 뒤에 콜백을 호출하도록 하는 방식이다. 말이 되게 어려운데 자동완성 즉 autocomplete 를 떠올리면 편하다.\n\n자동완성을 구현해본다고 생각하자.\ninput 의 `onChange`가 일어나면 callback 으로 AJAX 를 이용해 관련 데이터를 긁어온다. 그런데 사용자의 모든 입력에 AJAX 호출을 한다면 브라우저가 견디지 못할 것이다. 그래서 일정시간동안 Timer 를 만든다. 이 타이머의 시간동안 입력이 발생해 변경이 일어나면 Timer 를 초기화 한다. 입력이 멈추어 Timer 가 다 되면 AJAX 를 호출한다.\n\n이를 가장 쉽게 눈으로 볼 수 있게 만든 곳이 아래입니다.\n[CSS-Tricks 의 Throttling 과 Debouncing](https://css-tricks.com/debouncing-throttling-explained-examples/)\n\nThrottling 과 Debouncing 은 실제로 개발 시 자주 사용되는 기술이다. 따라서 좋은 라이브러리가 만들어져 있다. [Lodash](https://lodash.com/) 와 [Underscore](https://underscorejs.org/) 를 사용해보자.\n"
  },
  {
    "path": "ECMAScript/ArrowFunction.md",
    "content": "# 화살표 함수\n\n## 화살표 함수의 선언과 호출\n\n**화살표 함수는 `function` 대신 `=>`를 사용**함으로써 좀 더 간결하게 함수를 선언할 수 있다.\n\n또한 화살표 함수는 익명 함수로만 사용할 수 있기 때문에 **함수 표현식**을 사용한다.\n\n익명함수와 함수 선언식, 표현식의 차이를 알고 싶다면 [다음](https://github.com/im-d-team/Dev-Docs/blob/master/Javascript/%ED%95%A8%EC%88%98%20%EC%84%A0%EC%96%B8.md)을 참고하면 좋을 것 같다.\n\n```js\nconst foo = () => {...} //매개변수가 없을 때\nconst foo = x => {...} //매개변수가 하나일 때\nconst foo = (x, y) => {...} //매개변수가 여러 개일 때\n\nconst foo = x => { return x; }\nconst foo = x => x; // 함수의 블록이 한줄이라면 중괄호와 return을 생략\n\nconst sum = (x, y) => {\n    return x + y;\n}\n\nconsole.log(sum(1, 2)); //3\n```\n\n```js\n//ES5\nvar arr = ['JS', 'Java', 'Go'];\nvar foo = arr.map(function(element) {\n    return { 'Lang' : element };\n});\n\nconsole.log(foo); //[{Lang: \"JS\"}, {Lang: \"Java\"}, {Lang: \"Go\"}]\n\n//ES6\nconst arr = ['JS', 'Java', 'Go'];\nconst foo = arr.map(element => {\n    return {'Lang' : element};\n});\n\nconsole.log(foo); //[{Lang: \"JS\"}, {Lang: \"Java\"}, {Lang: \"Go\"}]\n```\n\n\n\n## this 바인딩\n\n\n`function` 키워드로 선언했을 때와 `=>`로 선언했을 때의 가장 큰 차이는 **`this `바인딩**에 있다.\n\n### function의 this 바인딩\n\nES5에서 `function`키워드를 사용했을 때 this 바인딩의 경우를 보면 다음과 같다.\n\n* 객체의 메서드를 호출할 때 : this는 해당 **메서드를 호출한 객체**에 바인딩\n* 함수를 호출할 때(내부 함수의 this 바인딩) : 함수 내부에서 사용된 **this는 전역객체**에 바인딩\n* 생성자 함수를 호출할 때 : this는 일반 함수를 호출할 때와 다르게 **새로 생성되는 빈 객체**에 바인딩\n* call과 apply메서드의 사용을 통한 this 바인딩 : 명시적으로 **특정 객체(지정한 객체)** 에 바인딩\n\n```js\nvar lang = 'Korean';\n\nvar obj = {\n    lang : 'English',\n    outerFunc : function() {\n        var that = this;\n        console.log('outerFunc : ', this.lang);\n\n        innerFunc1 = function() {\n            console.log('innerFunc1 : ', that.lang);\n\n            innerFunc2 = function() {\n                console.log('innerFunc2 : ', that.lang);\n            }\n\n            innerFunc2();\n        }\n\n        innerFunc1();\n    }\n}\n\nobj.outerFunc();\n\n/*\nouterFunc : English\ninnerFunc1 : English\ninnerFunc2 : Engilsh\n*/\n```\n위와 같이 객체의 메서드를 호출할 때 그 **메서드 내의 내부 함수의 경우에는 `this`가 전역 객체에 바인딩**된다.\n\n코드를 보면 `obj` 객체에 바인딩된 `this`를 원하므로 **변수 `that`에 `this`를 할당**하고 내부 함수에는 `this`대신 `that`을 사용하여 원하는 값을 출력하고 있다.\n\n\n\n### 화살표 함수에서의 this 바인딩\n\n위에서 보았듯이 일반 함수는 **함수의 호출 방식에 따라 this가 동적으로 바인딩**이 이뤄진다.\n\n하지만 화살표 함수에서는 this가 무조건 상위 스코프의 this를 가리킨다.\n\n즉 정적인 방식으로 this가 바인딩이 되는데 이를 **Lexical this** 라고 한다.\n\n위의 소스를 화살표 함수를 이용해서 바꾸면 `var that = this;`라는 구문을 쓸 필요가 없다.\n\n```js\nconst lang = 'Korean';\n\nconst obj = {\n    lang : 'English',\n    outerFunc() { //ES6의 축약 메서드 표현\n        console.log('outerFunc : ', this.lang);\n\n        innerFunc1 = () => {\n            console.log('innerFunc1 : ', this.lang);\n\n            innerFunc2 = () => {\n                console.log('innerFunc2 : ', this.lang);\n            }\n\n            innerFunc2();\n        }\n\n        innerFunc1();\n    }\n}\n\nobj.outerFunc();\n\n/*\nouterFunc : English\ninnerFunc1 : English\ninnerFunc2 : Engilsh\n*/\n```\n\n\n## 항상 화살표 함수일까?\n\n\n\n화살표 함수는 위에서 본 것 처럼 정적으로 this를 바인딩(Lexical this)을 지원하기 때문에 콜백 함수로 쓰기 매우 편하다. 하지만, 주의해서 써야할 경우가 몇 가지 있다.\n\n\n### addEventListener의 콜백 함수 선언\n\n```js\nconst btn = document.getElementById('submitBtn');\n\nbtn.addEventListener('click', () => {\n    console.log(this); //Window\n});\n```\n\n위에서 볼 수 있듯이 `addEventListener`의 **콜백 함수를 화살표 함수로 선언하면 `this`는 `window`에 바인딩되므로 그냥 일반함수를 사용하여 선언**하여야 한다.\n\n\n\n### 객체의 메서드에 선언\n\n객체의 메서드를 선언할 때, **화살표 함수를 쓰면 그 객체에 this가 바인딩되지 않고 전역(window)에 바인딩**된다.\n\n```js\nvar lang = 'Korean';\n\nconst obj = {\n    lang : 'English',\n    foo : () => { \n        console.log('outerFunc : ', this.lang);\n    }\n}\n\nobj.foo(); //outerFunc : Korean\n```\n\n위에선 English가 나온다고 생각할 수도 있다.\n\n하지만, `foo` 선언할 때 화살표 함수를 사용했고 이에 따라 **상위 컨텍스트인 `window`에 `this`가 바인딩** 되기 때문에 결과는 Korean이 나온다.\n\n따라서 원하는 결과가 English라면 축약 메서드 표현법으로 정의하는 것이 맞다.\n```js\nvar lang = 'Korean';\n\nconst obj = {\n    lang : 'English',\n    foo () { \n        console.log('outerFunc : ', this.lang);\n    }\n}\n\nobj.foo(); //outerFunc : English\n```\n\n\n### 프로토타입 객체의 메서드 선언\n\n프로토타입 객체에 메서드를 화살표 함수로 정의하면 객체의 메서드에 화살표 함수로 선언할 때와 같이 **`this`가 `window`에 바인딩**된다.\n\n```js\nconst devleoper = {\n  name: 'BKJang',\n};\n\nObject.prototype.renderData = () => console.log(this.name);\n\ndevleoper.renderData(); //undefined\n```\n\n\n\n### 생성자 함수 선언\n\n**화살표 함수는 `prototype` 프로퍼티를 갖고 있지 않다.** 따라서 생성자 함수를 선언할 때 화살표 함수를 쓰면 인스턴스를 생성할 수 없다.\n\n```js\nconst Person = (name) => {\n    this.name = name;\n}\n\nconst jang = new Person('BKJang'); //Uncaught TypeError: Person is not a constructor\n```\n\n#### Reference\n\n- [화살표 함수](https://poiemaweb.com/es6-arrow-function)\n- [화살표 함수(MDN web docs)](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Functions/%EC%95%A0%EB%A1%9C%EC%9A%B0_%ED%8E%91%EC%85%98)\n"
  },
  {
    "path": "ECMAScript/Destructuring_Assignment.md",
    "content": "# 구조 분해 할당\n\n```js\nconst { store } = this.props;\n```\n\n오른쪽의 객체에서 원하는 부분만 뽑아 사용하는 저런 구문을 react에서 처음 접했다. 처음엔 신기해서 그냥 쓰다가 어느 순간 궁금해지기 시작하여 이번에 다루어 봤다.\n\n위처럼 오른쪽의 특정 값을 해체하여 왼쪽에 할당하는 표현식(expression)을 destructuring assignment라고 한다.\n\n이 표현식은 ES6부터 추가 되었으며 배열이나 객체의 속성을 분해하여 다룰 수 있다.\n\n## 배열\n\n```js\nvar x = [0, 1, 2, 3, 4, 5];\nvar [a, b, , c] = x;\nconsole.log(a, b, c); // 0 1 3\n```\n\n말로 설명해야 할까 싶을 정도로 단순하다. line 2의 코드의 우변의 배열에서 각각 해당하는 요소들을 우변의 변수에 할당해준다.\n\n이는 파이썬과 같은 언어들에서 찾아 볼 수 있다.\n\n### 응용\n\n---\n\n이를 응용하는 방식으로는 대표적으로 변수의 값 교환(swap)하는 알고리즘을 간단히 바꿀 수 있다.\n\n```js\nvar x = 1;\nvar y = 2;\nvar tmp = x;\n\nx = y;\ny = tmp;\n\nconsole.log(x, y);\n```\n\n보통의 경우 swap은 간단하게 이렇게 구현한다. 그런데 구조 분해 할당을 이용하면 매우 간결해진다.\n\n```js\nvar x = 1;\nvar y = 2;\n\n[x, y] = [y, x];\nconsole.log(x, y);\n```\n\n조금 더 나아가 sperad operator를 함께 사용할 수도 있다.\n\n```js\nvar [x, ...y] = [1, 2, 3];\nconsole.log(x); // 1\nconsole.log(y); // [2, 3]\n```\n\n## 객체\n\n```js\nvar x = { a: 1, b: 'hello' };\nvar { a, b } = x;\n\nconsole.log(a, b); // 1, 'hello'\n```\n\n배열을 잘 이해했다면 딱히 어려움 없이 이해할 수 있다. `x.a`와 `x.b`를 각각 전역스코프 변수 a와 b에 할당한다.\n\n### 응용\n\n---\n\n위와 같이 사용하면 변수의 이름은 a와 b밖에 사용하지 못한다. 전역스코프의 변수명을 다르게 하고 싶다면 아래와 같이 사용 가능하다.\n\n```js\nvar x = { a: 1, b: 'hello' };\nvar { a: count, b: text } = x;\n\nconsole.log(count, text); // 1, 'hello'\n```\n\n또한 객체에서도 마찬가지로 sperad operator를 사용할 수 있습니다.\n\n```js\nvar x = { a: 1, b: 'hello', c: 2, d: true };\nvar { a, b, ...rest } = x;\n\nconsole.log(a, b, c); // 1, 'hello', {c: 2, d: true}\n```\n"
  },
  {
    "path": "ECMAScript/ECMA2019.md",
    "content": "# ECMAScript 2019\n\n기본적으로 여기에 나오는 내용들은 TC39 committee에서 승인처리가 된 새로 추가가 되는 기능이다.\n\n1. [Array#{flat,flatMap}]\n2. [Object.fromEntries]\n3. [String#{trimStart,trimEnd}]\n4. [Symbol#description]\n5. [try { } catch {} // optional binding]\n6. [JSON ⊂ ECMAScript]\n7. [Well-formed JSON.stringify]\n8. [Stable Array#sort]\n9. [Revised Function#toString]\n\n## Array#{flat,flatMap}\n\nArray 함수에 2가지 메소드가 추가가 되었다.\n\n> [https://tc39.github.io/proposal-flatMap/](https://tc39.github.io/proposal-flatMap/)\n\n### flat()\n\n이 메서드는 호출 된 배열의 병합된 모양을 반환한다.\n\n```js\nconst arr = [1,2,[1,2],[2,3]];\nconst flatArr = arr.flat();\n    \nconsole.log(flatArr); // [1,2,1,2,2,3]\n```\n\n추가적으로 선택적인 옵션을 제공하는데 내가 원하는 `depth`를 정할 수 있다. `default` 값은 1이다. 중첩 수준이 1보다 큰 배열에서 `flat` 메서드를 호출하게 되면 첫 번째 수준만 병합되는 것이다.\n\n```js\nconst arr = [1,2,[1,2,[4,5]],[2,3]];\nconst flatArr = arr.flat();\n    \nconsole.log(flatArr); // [1, 2, 1, 2, [4 5], 2, 3]\n```\n\n위에서 보이듯이 아무 설정값을 주지 않아 1이 기본값이 된다. 옵션으로 넣고 싶다면 아래와 같이 하면 된다.\n\n```js\nconst arr = [1,2,[1,2,[4,5]],[2,3]];\nconst flatArr = arr.flat(2);\n    \nconsole.log(flatArr); // [1, 2, 1, 2, 4, 5, 2, 3]\n```\n\n그러나 경우에 따라 모든 깊이를 `flat`하게 만들고 싶어지는 경우가 생긴다.\n\n```js\nconst arr = [1,2,[1,2,[4,5,[6,7]]],[2,3]];\nconst flatArr = arr.flat(Infinity);\n    \nconsole.log(flatArr); // [1, 2, 1, 2, 4, 5, 6, 7, 2, 3]\n```\n\n### flatMap()\n\n이 메서드는 `map () + flat ()` 을 사용하는 것과 동일한 효과 / 기능을 갖는다. \n\n즉, 값을 새로운 것으로 매핑한 다음 결과를 병합한다. 차이점은 평면에 있는 것과 같이 깊이에 대한 옵션을 지원하지 않는다. 1의 깊이를 사용한다.\n\n```js\nconst names = [\"John\", \"Johny\", \"Peter\"];\nconst mapOnly = names.map((name, idx) => [idx, name]);\nconst flatMap = names.flatMap((name, idx) => [idx, name]);\n    \nconsole.log(mapOnly); // [[0, “John”],[1, “Johny”],[2, “Peter”]]\nconsole.log(flatMap); // [0, “John”,1, “Johny”,2, “Peter”]\n```\n\n## Object.fromEntries\n\n이 메소드는 `Object.entries ()` 의 반대이다.\n\n`Object.entries()` 는 객체 항목을 [key, value] 쌍의 **배열로 변형**하지만 `Object.fromEntries()` 는 [key, value] 쌍의 목록을 **객체로 변환**합니다.\n\n```js\nconst map = new Map().set(\"id\", 1).set(\"name\", \"John\");\nconst arr = [[\"id\", 1], [\"name\", \"John\"]];\n    \nconst mapObj  = Object.fromEntries(map);\nconst arrObj = Object.fromEntries(arr);\n    \nconsole.log(mapObj); // {id: 1, name: ‘John’}\nconsole.log(arrObj); // {id: 1, name: ‘John’}\n```\n\n## String#{trimStart,trimEnd}\n\n많은 브라우저가 이미 `trimRight` 및 `trimLeft` 를 지원하지만 `padStart` 및 `padLeft` 와 일관성을 유지하기 위해 `trimStart` 및 `trimEnd` 를 만들었다고 한다.\n\n```js\nconst exampleStr = \"      first class js     \";\nconst trimStart = exampleStr.trimStart();\nconst trimEnd = exampleStr.trimEnd();\n    \nconsole.log(trimStart); // \"first class js     \"\nconsole.log(trimEnd);   // \"      first class js\"\n```\n\n## Symbol#description\n\nSymbol 객체에 새로운 읽기 전용 속성이 추가되었다. 선택 사항이며 심볼의 설명을 반환한다.\n\n```js\nconst mySymbol = Symbol(“first”);\nconst description = mySymbol.description;\n    \nconsole.log(description); // “first”\n```\n\n## try { } catch {} // optional binding\n\n선택적 `catch` 바인딩이 도입이 되었다. \n\n우리는 `catch` 절에 대한 예외 변수를 다음과 같이 바인딩 해야했다.\n\n```js\ntry {\n // do something\n} catch(err) {\n // throw custom error, i.e. don’t use the err variable\n}\n```\n\n예외 변수를 생략하고 다음을 수행 할 수 있다.(`throw custom error`가 가능해지는 것이다.)\n\n```js\ntry {\n // do something\n} catch {\n // throw custom error\n}\n```\n\n## JSON ⊂ ECMAScript\n\n줄 분리 기호 (U + 2028) 및 단락 분리 기호 (U + 2029) 기호는 **문자열 리터럴**에 사용할 수 없다.\n\n기존에는 사용하게 되면 SyntaxError가 나왔으나, 앞으로는 사용이 가능하다.\n\n```js\n// Produces invalid string before ES2019\neval('\"\\u2028\"');\neval('\"\\u2029”’);\n    \n// Valid in ES2019\neval('\"\\u2028\"');\neval('\"\\u2029”’);\n```\n\n## Well-formed JSON.stringify\n\n`ES2019` 이전에는 대용 `UTF-8` 코드(U + D800에서 U + DFFF까지)로 `JSON.stringify()` 를 호출하면 단일 `UTF-16` 코드 단위가 리턴되었지만 이제는 문자열로 나타내게 된다.\n\n이렇게하면 `JSON.parse ()`를 사용하여 원래 표현으로 다시 변환 할 수 있다.\n\n```js\n// Before ES2019\nJSON.stringify('\\uD800'); // \"\" \n    \n// Now \nJSON.stringify('\\uD800'); // \"\\ud800\" => 현재 크롬에서는 이렇게 나오고 있다.\n```\n\n## Stable Array#sort\n\n`Mathias Bynens`의 트윗에 따르면 배열의 정렬 방법은 안정적으로 되었다고 한다. 불안정한 `QuickSort`가 아닌 10 개 이상의 요소에 대한 배열을 위해 안정적인 `TimSort` 알고리즘을 사용한다고 한다.\n\n> Array.prototype.sort is now stable in @v8js v7.0 / Chrome 70!\n>\n> Previously, V8 used an unstable QuickSort for arrays with more than 10 elements. Now, we use the stable TimSort algorithm.\n>\n> — Mathias Bynens\n\n## Revised Function#toString\n\n이 메소드는 우리가 이미 알고있고 사용하는 것이라고 하는데, **무엇이 바뀌었을까?**\n\n기존에는 `toString()`을 하게 되면 공백과 주석을 제거하고 코드를 반환을 했다.\n\n그러나 이제는 그렇게 안 한다는 것이다.\n\n```js\nBefore:\nfunction /* this is comment */ testFunc() {}\nconsole.log(testFunc.toString()); // function testFunc() {}\n\nNow:\nfunction /* this is comment */ testFunc() {}\nconsole.log(testFunc.toString()); // function /* this is comment */ testFunc() {}\n```\n\n---\n\n#### reference\n\n- [ECMAScript 2019(ES2019) – New Features with Examples]([https://firstclassjs.com/ecmascript-2019es2019-new-features-with-examples/#stable-array-sort])"
  },
  {
    "path": "ECMAScript/ES6-module-in-Browser.md",
    "content": "# ES6 Module in Browser\n\n## module\n\n모듈은 쉽게 생각하면 코드 뭉치다. 코드를 chunk로 만들어 재사용하거나 추상화한다.\n\nJS 모듈에 관한 글은 여기저기 많다. 아래의 링크로 간단한 모듈의 정의와 역사는 대체한다.\n\n- [B_Module](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/B_Module.md)\n- [javascript의 module](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/Module.md)\n- [AMD와 CommonJS](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/AMD%EC%99%80%20CommonJS.md)\n\n이 글에서는 현재 브라우저에서 최신모듈을 어떻게 사용하는지 알아보도록 하자.\n\n## js module의 역사\n\n위의 링크들에도 잘 나와 있지만 간단하게만 짚고 넘어가자. 궁금한 단어들은 위의 링크에서 찾아보자.\n\n### 기본\n\n가장 기본은 모듈을 파일별로 구분하고 파일을 모두 불러오는 것이다.\n\n```html\n<script src=\"some.js\"></script>\n<script src=\"another.js\"></script>\n<script src=\"other.js\"></script>\n```\n\n이 경우 단점은 전역변수 사용, 의존성 관리 불가, request 수 증가 등등 다양할 것이다.\n\n### Module patterns\n\n즉시 실행 함수 표현식(IIFE)을 통해 chunk끼리 분리하여 작동하게 만들어 기존의 단점을 보완하였다.\n\n### Module 경쟁과 종말\n\nJS에서 공식 스펙으로 채택한 모듈이 없었고 따라서\n\n- commonJS\n- AMD\n- UMD\n\n이러한 방식들이 등장해 서로 경쟁하였다.\n\nES2015의 등장과 함께 ES6 Modules라는 표준 방식이 등장하였다.\n\n## ES6 Modules\n\nES6 모듈의 스펙과 사용법은 다음과 같다.\n\n- private가 기본값이다.\n- strict mode로 실행된다.\n- 노출하고자 하는 것은 `export` 키워드를 사용한다.\n- `import` 키워드를 사용해 불러온다.\n\n이전에는 브라우저가 이것을 지원하지 않아 [bundler나 transpiler](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/Javascript_BuildTool.md)를 사용해서 ES6 모듈을 사용했었다.\n\n### 브라우저에서 사용\n\n[이 버전들](https://caniuse.com/#feat=es6-module)부터는 브라우저가 ES6 모듈을 사용할 수 있다.\n\n- Chrome 61 이상\n- Firefox 60 이상\n- Edge 16 이상\n- Safari 11 이상\n- IE는 불가\n\n#### 사용 방법\n\n```html\n<script type=\"module\" src=\"./app.js\" />\n```\n\n```html\n<script type=\"module\">\n  import * as lib from './lib.js';\n\n  lib.parse(\"12abc345\");\n<script>\n```\n\n`type=\"module\"`을 script 태그 안에 넣어주게 되면 뒤의 script를 module로 취급하여 실행한다.\n\n#### 비동기처리\n\n`type=\"module\"` 로 불러오게 되면 defer가 기본값이다. defer는 script를 비동기로 불러온 뒤 HTML parsing이 완료되면 script가 실행되는 속성이다.\n\n관련 자료는 [이곳](https://blog.asamaru.net/2017/05/04/script-async-defer/)에서 보자.\n\n비동기처리가 기본 속성이므로 script 파일 간의 순서를 보장해야 하는 경우 잘 고려해서 사용하자.\n\n```html\n<!-- runs SECOND -->\n<script type=\"module\">\n  // this is inline\n  // do something...\n</script>\n\n<!-- runs THIRD -->\n<script defer src=\"c.js\"></script>\n\n<!-- runs FIRST -->\n<script src=\"a.js\"></script>\n\n<!-- runs FOURTH -->\n<script type=\"module\" src=\"b.js\"></script>\n```\n\n#### feature detect\n\nbrowser가 module을 지원하지 않는다면 `type=\"module\"`을 설정한 코드의 src를 무시해버린다.\n따라서 실행이 안 된다.\n\n그래서 지원하는 것이 nomodule 속성이다.\n\n```html\n<script type=\"module\" src=\"app.js\"></script>\n<script nomodule src=\"classic-app.js\"></script>\n```\n\nmodule을 인식하는 브라우저라면 윗 코드를, 구식 브라우저라면 아랫 코드를 실행한다.\n\n관련 스펙은 [이 곳](https://html.spec.whatwg.org/multipage/scripting.html#attr-script-nomodule)에서 확인할 수 있다.\n\n## 미래를 대비하자.\n\n이제 브라우저에서도 ES6 모듈을 사용할 수 있다.\n\n물론 현대적인 방식의 대다수 개발에선 번들러를 사용하며 그 중 webpack이 가장 인기있다.\n\njs 뿐만 아니라 css의 의존성 관리, image 관리, transpiling 등을 한꺼번에 처리할 수 있는 webpack은 매우 강력하다.\n\n그렇지만 영원한 승리자는 없다. 이미 무거워져버린 webpack을 어떻게 대체할 것인가에 대해 많은 이야기가 나오고 있다.\n\nwebpack이 아니더라도 표준 방식으로 ES6 모듈을 사용할 수 있음을 기억해두자.\n\n---\n\n### 참고자료\n\n- [B_Module](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/B_Module.md)\n- [javascript의 module](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/Module.md)\n- [AMD와 CommonJS](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/AMD%EC%99%80%20CommonJS.md)\n- [javascript build tool](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/Javascript_BuildTool.md)\n- [module can i use](https://caniuse.com/#feat=es6-module)\n- [script의 async와 defer 속성](https://blog.asamaru.net/2017/05/04/script-async-defer/)\n- [html spec(whatwg)](https://html.spec.whatwg.org/multipage/scripting.html#attr-script-nomodule)\n- [Understanding ES6 Modules](https://www.sitepoint.com/understanding-es6-modules/)\n"
  },
  {
    "path": "ECMAScript/Generator와 async-await.md",
    "content": "# Generator와 async-await\n\n`Generator`는 `ES6`에서 도입되었으며 `Iterable`을 생성하는 함수다. `Generator`를 사용하면 `Iteration Protocol`을 사용하여 `Iterable`을 생성하는 방식보다 간편하다.<br/>\n`Iteration Protocol`에 대한 자세한 내용은 [다음](https://github.com/Im-D/Dev-Docs/blob/master/ECMAScript/Iteration_Protocol.md)을 참고하길 바란다.\n\n<br/>\n\n## Generator 함수의 정의\n\n`Generator` 함수는 코드 블록을 한 번에 실행하지 않고 함수 코드 블록의 실행을 중지했다가 필요한 시점에 다시 시작할 수 있는 함수다.<br/>\n`Generator` 함수는 `function *` 키워드를 사용하며 하나 이상의 `yield` 문을 포함한다.\n\n```js\n// 함수 선언문\nfunction* decFunc() {\n  yield 1;\n}\n\nlet genObj = decFunc();\n\n// 함수 표현식\nconst expFunc = function* () {\n  yield 1;\n};\n\ngenObj = expFunc();\n\n// 메서드\nconst obj = {\n  * objectMethod() {\n    yield 1;\n  }\n};\n\ngenObj = obj.objectMethod();\n\n// 클래스 메서드\nclass GenClass {\n  * classMethod() {\n    yield 1;\n  }\n}\n\nconst genClass = new GenClass();\ngenObj = genClass.classMethod();\n```\n\n<br/>\n\n## Generator 객체\n\n`Generator` 함수를 호출하면 코드 블록이 실행되는 것이 아니라 `Generator` 객체를 반환한다. `Generator` 객체는 이터러블이면서 동시에 이터레이터다. 따라서 `Symbol.iterator`를 사용하여 이터레이터를 생성할 필요 없다.\n\n```js\nfunction* counter() {\n  console.log('First');\n  yield 1;\n  console.log('Second');\n  yield 2;\n  console.log('Third');\n  yield 3;\n  console.log('The end');\n}\n\nconst genObj = counter();\n\nconsole.log(genObj.next()) //{value: 1, done: false}\nconsole.log(genObj.next()) //{value: 2, done: false}\nconsole.log(genObj.next()) //{value: 3, done: false}\nconsole.log(genObj.next()) //{value: undefined, done: true}\n```\n\n`Generator` 객체는 이터러블이면서 이터레이터이기 때문에 `next()`메서드를 가지고 있다. 따라서 `next()` 메서드를 호출하면 `yield`문까지 실행되고 일시 중지된다. 다시 `next()` 메서드를 호출하면 다음 `yield`문을 만날 때까지 실행된 뒤 일시 중지된다. 위의 코드에서는 `next()`메서드를 호출하면 `value`값으로 `yield`문의 오른쪽에 선언된 값이 반환된다.\n\n<br/>\n\n## Generator 객체를 이용한 이터러블 구현\n\n```js\nconst genObj = (function* () {\n  let i = 0;\n\n  while(true) {\n    yield ++i;\n  }\n}());\n\nfor (let item of genObj) {\n  if (item === 10) break;\n  console.log(item);\n}\n```\n\n```js\n// Generator 함수에 파라미터 전달\nconst genObj = function* (max) {\n  let i = 0;\n\n  while(true) {\n    if (i === max) break;\n    yield ++i;\n  }\n}\n\nfor (let item of genObj(10)) {\n  console.log(item);\n}\n```\n\n```js\n// next 메서드에 파라미터 전달\nfunction* genFunc(n) {\n  let res;\n  res = yield n;\n\n  console.log(res);\n  res = yield res;\n\n  console.log(res);\n  res = yield res;\n\n  console.log(res);\n  return res;\n}\nconst genObj = genFunc(0);\n\nconsole.log(genObj.next());\nconsole.log(genObj.next(1));\nconsole.log(genObj.next(2));\nconsole.log(genObj.next(3));\n\n```\n\n<br/>\n\n## Generator를 이용한 비동기 처리\n\n`Generator`의 진면목은 비동기 프로그래밍에서 볼 수 있다. 함수가 실행 도중에 멈춘다니. 언제 응답이 올 지 알 수 없기 때문에, callback을 등록하는 비동기 프로그래밍에 응용하면 callback hell을 탈출할 수 있지 않을까?\n\n```js\nfunction getId(phoneNumber) {\n    // …\n    iterator.next(result);\n}\n\nfunction getEmail(id) {\n    // …\n    iterator.next(result);\n}\n\nfunction getName(email) {\n    // …\n    iterator.next(result);\n}\n\nfunction order(name, menu) {\n    // …\n    iterator.next(result);\n}\nfunction* orderCoffee(phoneNumber) {\n    const id = yield getId(phoneNumber);\n    const email = yield getEmail(id);\n    const name = yield getName(email);\n    const result = yield order(name, 'coffee');\n    return result;\n}\n\nconst iterator = orderCoffee('010-1234-1234');\niterator.next();\n```\n\n<br/>\n\n## async-await를 이용한 비동기 처리\n\n`async-await`를 활용하면 `Generator`를 이용했을 때 처럼 제어권을 다시 `Generator`에 넘기기 위해 각 비동기 함수마다 `next()`를 호출하지 않아도 된다.\n\n```js\nasync function orderCoffee(phoneNumber) {\n    const id = await getId(phoneNumber);\n    const email = await getEmail(id);\n    const name = await getName(email);\n    return await order(name, 'coffee')\n}\n\norderCoffee('011-1234-5678').then(result => {\n    console.log(result);\n});\n```\n\n<br/>\n\n## Generator는 어떻게 구현되어 있을까?\n\n```js\n// ES6\nfunction* foo(){\n    yield bar();\n}\n\n// ES5 Compiled\n\"use strict\";\n\nvar _marked = /*#__PURE__*/ regeneratorRuntime.mark(foo);\n\nfunction foo() {\n    return regeneratorRuntime.wrap(\n        function foo$(_context) {\n            while (1) {\n                switch ((_context.prev = _context.next)) {\n                    case 0:\n                        _context.next = 2;\n                        return bar();\n                    case 2:\n                    case \"end\":\n                        return _context.stop();\n                }\n            }\n        },\n        _marked, this\n    );\n}\n```\n\n`Genrator`는 결국 `iterable Protocol`를 구현하는 객체이다. 그러나 프로토콜과 관련된 어느것도 보이지 않는다.\n\n대신 `regeneratorRuntime`이 보인다.\n\n`babel`에서는 `regeneratorRuntime`라이브러리를 사용해서 구현을 했다.\n\n코드의 역사를 따라가다 보면 [facebook/regenerator](https://github.com/facebook/regenerator/blob/master/packages/regenerator-runtime/runtime.js) repository에 도달하게 된다.\n\n이 라이브러리는 2013년 Node.js v0.11.2에서 generator syntax를 지원하기 위해 만들어 졌으며, Babel에서는 이 라이브러리를 사용하여 generator를 구현하고 있다. 실제 코드를 들여다보면 Symbol과 Iterator를 이용해서 Iterable Protocol을 구현하고 있다.\n\n---\n\n### Reference\n\n- [Poiemaweb-Generator와 async/await](https://poiemaweb.com/es6-generator)\n- [ES6의 제너레이터를 사용한 비동기 프로그래밍](https://meetup.toast.com/posts/73)\n- [MDN Docs-Genenrator](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Generator)\n"
  },
  {
    "path": "ECMAScript/Includes_IndexOf.md",
    "content": "# Includes와 IndexOf\n\n## 소개\n\n두 메서드 모두 배열에 어떤 값이 있는지 찾을 때 비슷하게 사용한다. 정확히는 사용 용도가 조금은 다르지만, 배열에 어느 값이 있는지 확인할 때 사용할 수 있다. includes는 ES6부터 새로 생긴것인데 어떤 차이점이 있는지 알고 왜 이 메서드를 사용해야하는지 알아보자.\n\n## 공통점\n\nincludes는 boolean을, indexOf 는 Number를 반환한다. indexOf는 찾고자하는 값이 있는 배열의 숫자를 반환하고 없으면 -1을 반환한다.\n\n아래와 같이 사용할 수 있다.\n\n```javascript\nconst array = [0, 1, 2, 3, 4];\n\narray.includes(2) ? console.log('yes') : console.log('no');\narray.indexOf(2) > -1 ? console.log('yes') : console.log('no');\n```\n\n## 차이점\n\n배열 안의 값이 조금 특별해지면 이야기가 달라진다.\n\n```javascript\nconst array = [1, null, NaN, , -0]; // 빈값은 undefined\n\narray.includes(1) ? console.log('yes') : console.log('no');\narray.indexOf(1) > -1 ? console.log('yes') : console.log('no');\n\narray.includes(null) ? console.log('yes') : console.log('no');\narray.indexOf(null) > -1 ? console.log('yes') : console.log('no');\n\n// 달라지는 구간\narray.includes(NaN) ? console.log('yes') : console.log('no');\narray.indexOf(NaN) > -1 ? console.log('yes') : console.log('no');\n\narray.includes(undefined) ? console.log('yes') : console.log('no');\narray.indexOf(undefined) > -1 ? console.log('yes') : console.log('no');\n\n// 둘다 버그\narray.includes(+0) ? console.log('yes') : console.log('no');\narray.indexOf(+0) > -1 ? console.log('yes') : console.log('no');\n```\n\n1, null에는 큰 이상이 없지만 NaN, undefined는 includes만 잡아낸다. -0, +0은 모두 잡지 못한다.\n\n## 결론\n\n배열안의 값을 확인하는 경우 큰 차이는 없지만 NaN, undefined와 관련한 버그가 발생할 수 있다. 따라서 이왕이면 includes를 사용하는 것이 더 좋아보인다.\n"
  },
  {
    "path": "ECMAScript/Iteration_Protocol.md",
    "content": "# Iteration Protocol\n\n`Iteration Protocol`은 ES6에서 도입되었다. 이는 새로운 구문이 아닌 하나의 프로토콜, 규약이다. 즉, 같은 규칙을 준수하는 객체에 의해 구현될 수 있다. `Iteration Protocol`에는 **Iterable Protocol** 과 **Iterator Protocol** 이 있다.\n\n<br/>\n\n## Iterable\n\n`Iterable`은 `Iterable Protocol`을 준수한 객체다. `Iterable`은 반복 가능한 객체이며 `Symbol.iterator` 메서드를 구현하거나 프로토타입 체인에 의해 상속한 객체를 말한다. `Iterable`은 `for...of`문에서 반복 가능하며 [Spread Operator](https://github.com/Im-D/Dev-Docs/blob/master/ECMAScript/Spread_Operator.md)의 대상이 될 수 있다.\n\n`Iterable`은 `Symbol.iterator`을 가지기 때문에 해당 메서드가 없는 객체는 Iterable 객체가 아니다.\n\nIterable 객체로는 내장 객체인 `Array`, `Map`, `Set`, `String` 등이 있다.\n\n```js\nconst iterator = [1, 2, 3][Symbol.iterator]();\n\niterator.next().value; // 1\niterator.next().value; // 2\niterator.next().value; // 3\niterator.next().done; // true\n```\n\n반면, 일반 객체는 `Symbol.iterator` 메서드를 가지고 있지 않다. 따라서 일반 객체는 Iterable 객체가 아니다.\n\n```js\nconst obj = { a: 1, b: 2 };\n\nconsole.log(Symbol.iterator in obj); // false\n\n// TypeError: obj is not iterable\nfor (const item of obj) {\n  console.log(item);\n}\n```\n\n하지만 일반 객체도 `Iterable Protocol`을 준수하도록 구현하면 Iterable 객체가 될 수 있다.\n\n```js\nconst iterableObj = function (max) {\n  let i = 0;\n\n  return {\n    [Symbol.iterator]() {\n      return {\n        next() {\n          return {\n            value: ++i,\n            done: i === max\n          };\n        }\n      };\n    }\n  };\n};\n\nconst iterator = iterableObj(10);\n\nfor (let item of iterator) {\n  console.log(item);\n}\n```\n\n<br/>\n\n## Iterator\n\n`Iterator Protocol`은 `next` 메서드를 가진다. `next` 메소드를 호출하면 Iterable 객체를 순회하며 `value`, `done` 프로퍼티를 갖는 Iterator Reuslt 객체를 반환한다. 이 규약을 준수한 객체가 Iterator 객체다.\n\n위에서 잠깐 봤던 코드의 일부분을 다시 한 번 살펴보자.\n\n```js\n[Symbol.iterator]() {\n  return {\n    next() {\n      return {\n        value: ++i,\n        done: i === max\n      };\n    }\n  };\n}\n```\n\n`Symbol.iterator` 메서드를 실행하면 `next` 메서드를 가진 객체를 반환하고 `next` 메서드를 실행하면 `value`, `done` 프로퍼티를 가진 객체를 반환한다. 그렇다. <br/> Iterable 객체가 가진 `Symbol.iterator` 메서드를 실행하면 Iterator 객체를 반환한다.\n\n```js\nconst array = [1, 2, 3];\n\nconst iterator = array[Symbol.iterator]();\n\nconsole.log('next' in iterator); // true\n\niterator.next().value; // 1\niterator.next().value; // 2\niterator.next().value; // 3\niterator.next(); // { value: undefined, done: true }\n```\n\nIterator 객체의 `next` 메서드가 반환하는 Iterator Result 객체의 `value` 프로퍼티는 Iterable 객체의 값을 반환하고 `done` 프로퍼티는 Iterable 객체의 반복 완료 여부를 반환한다.\n\n<br/>\n\n## Iteration Protocol이 왜 필요할까?\n\n`for...of`, `Spread Operator`, `Destructuring`, `Map/Set constructor`등을 **데이터 소비자(Data Consumer)** 라고 한다.<br/> 반면, `배열`, `문자열`, `Map`, `Set`, `DOM Data Structure` 등과 같은 Iterable 객체는 **데이터 공급자(Data Provider)** 라고 한다.\n\n만약, 위와 같은 Data Provider인 Iterable 객체들이 각각 다른 방식의 순회 방식을 갖는다면 어떨까? 당연히 효율적이지 못하다.\n\n순회 방식에 대한 하나의 규약을 정해놓고 사용한다면 Data Consumer가 여러 구조의 Iterable을 효율적으로 사용할 수 있을 것이다. 즉, Iteration Protocol은 Data Consumer와 Data Provider를 연결하는 인터페이스 역할을 해주기 때문에 필요하다고 볼 수 있다.\n\n---\n\n### Reference\n\n- [Poiemaweb - 이터레이션과 for...of 문](https://poiemaweb.com/es6-iteration-for-of)\n- [wonism.github.io - JavaScript iterables와 iterator 이해하기](https://wonism.github.io/javascript-iteration-protocol/)\n- [MDN Docs - Iteration protocols](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Iteration_protocols)\n"
  },
  {
    "path": "ECMAScript/ModulePattern_class.md",
    "content": "# Module Pattern과 class\n\n## Module Pattern\n\n캡슐화는 객체 지향 프로그래밍(OOP; Object Oriented Programming)의 대표적인 특징 중 하나로 **정보 은닉**의 개념을 포함한다.\n하지만, 대개 객체 지향 언어는 객체 내의 은닉하고자 하는 정보와 그렇지 않은 정보를 `private`과 `public`과 같은 접근제어자를 통해 구분한다. 그러나 자바스크립트에서는 이와 같은 접근제어자를 제공하지 않으며, 대신 아래와 같은 방법을 이용해 캡슐화를 구현할 수 있다.\n\n```js\n//ES5\n'use strict';\nvar Person = (function() {\n    //생성자 함수 정의\n    function Person(name, job) {\n        this.name = name;\n        this.job = job;\n    }\n\n    Person.prototype.sayInfo = function() {\n        console.log('Name : ' + this.name + ', Job : ' + this.job);\n    }\n\n    return Person;\n}());\n\nvar bkJang = new Person('BKJang', 'Developer');\n\nbkJang.sayInfo(); //Name : BKJang, Job : Developer\n```\n\n마지막 출력 값을 보면 **인스턴스인 `bkJang`의 프로토타입 객체가 `Person.prototype` 객체임을 알 수 있고 이는 상속을 구현할 수 있음을 의미**한다.\n\n## class\n\n**자바스크립트는 기본적으로 `Prototype`기반의 객체지향 언어**다. 그리고 `Module Pattern`을 통해 자연스럽게 이해할 수 있을 것이다. 하지만 `ES5`의 `Module Pattern`을 사용하면 기본적으로 JS의 실행 컨텍스트, 클로저 등과 같은 개념을 정확히 알아야 구현이 가능하다. 물론, 실행 컨텍스트나 클로저 같은 개념을 몰라도 된다는 것은 아니지만 `ES6`의 `class`문법을 사용하면 우리가 좀 더 쉽게 익숙한 문법으로 캡슐화를 구현할 수 있다.  \n\n즉, `ES6`의 `class`또한 프로토타입을 기반으로 동작하며 이는 기존의 자바스크립트에서 객체지향적으로 설계할 때의 방식을 좀 더 편하게 보완한 `Syntatic Sugar`다.\n\n## 클래스의 정의\n\n`ES6`에서 `class`가 생기기 전 우리는 위와 같은 방식으로 생성자 함수와 프로토타입을 이용해 객체지향 프로그래밍을 진행했었다. 위와 같은 코드를 `ES6`의 `class`를 사용하여 구현하면 아래와 같이 좀 더 간결하게 구현할 수 있다.\n\n```js\n//ES6\nclass Person {\n    constructor(name, job) {\n        this.name = name;\n        this.job = job;\n    }\n\n    sayInfo() {\n        console.log(`Name : ${this.name}, Job : ${this.job}`);\n    }\n}\n\nconst bkJang = new Person('BKJang', 'Developer');\n\nbkJang.sayInfo(); //Name : BKJang, Job : Developer\n```\n\n클래스는 기본적으로 위와 같이 **`class Person {}`으로 정의하며, 흔치는 않지만 `const Person = class Myclass {};`처럼 함수 표현식으로도 정의 가능**하다.\n\n둘의 또 다른 차이점은 생성자 함수를 이용하여 선언하면 `window`에 할당되지만, **`class`를 이용하여 선언하면 `window`에 할당되지 않는다.**\n\n또한 **`class` 안에 있는 코드는 항상 [strict mode](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Strict_mode) 로 실행**되기 때문에 \"use strict\" 명령어가 없더라도 동일하게 동작한다.\n\n```js\nfunction Person() {}\nclass Developer {}\n\nconsole.log(window.Person); //ƒ Person() {}\nconsole.log(window.Developer); //undefined\n```\n\n## 인스턴스의 생성과 호이스팅\n\n`class`를 사용하여 인스턴스를 생성할 때는 반드시 `new`를 이용해 호출해야하며 `new`를 사용하지 않으면 `Type Error`가 발생한다.\n\n```js\nclass Foo {\n\n}\n\nconst foo = Foo(); //Uncaught TypeError: class constructor Foo cannot be invoked without 'new'\n```\n\n`ES6`의 `class`는 [let, const](https://bkdevlog.netlify.com/posts/let-const)와 마찬가지로 호이스팅이 일어나지만, **선언이 일어나고 할당이 이뤄지기 전 `TDZ(Temporary Dead Zone)`에 빠지기 때문에 할당 이전에 호출하면 `Reference Error`가 발생**한다.\n\n```js\nconst foo = new Foo(); //Uncaught ReferenceError: Foo is not defined\n\nclass Foo {\n\n}\n```\n\n## constructor\n\n`constructor`는 인스턴스를 생성하고 `class`의 `property`를 초기화한다. `ES5`에서는 생성자 함수를 이용해 `property`를 초기화하고 **생성자 함수를 반환**함으로써 객체지향을 구현했었다. \n\n### class는 constructor를 반환하며 생략할 수 있다.\n\n**`const foo = new Foo()`와 같이 선언했을 때 `Foo`는 `class`명이 아닌 `constructor`다.**\n\n```js\nclass Foo {\n\n}\n\nconst foo = new Foo();\n\nconsole.log(Foo == Foo.prototype.constructor); //true\n```\n\n위의 코드에서 볼 수 있듯이 `new`와 함께 호출한 `Foo`는 `constructor`와 같음을 확인할 수 있다.\n\n또 확인할 수 있는 것은 `class Foo`내부에 `constructor`를 선언하지 않았음에도 인스턴스의 생성이 잘 이뤄지는 것을 볼 수 있다. 이는 **`class`내부에 `constructor`는 생략할 수 있으며 생략하면 `class`에 `constructor() {}`를 포함한 것과 동일하게 동작**하기 때문이다. 즉, 빈 객체를 생성하기 때문에 `property`를 선언하려면 인스턴스를 생성한 이후, `property`를 동적 할당해야 한다.\n\n```js\nconsole.log(foo); //Foo {}\n\nfoo.name = 'BKJang';\n\nconsole.log(foo); //Foo {name: \"BKJang\"}\n```\n\n### class의 property는 constructor 내부에서 선언과 초기화가 이뤄진다.\n\n`class`의 몸체에는 메서드만 선언 가능하며, `property`는 `constructor`내부에서 선언하여야 한다.\n\n```js\nclass Foo {\n    name = ''; //Syntax Error\n}\n```\n\n```js\nclass Bar {\n    constructor(name = '') {\n        this.name = name;\n    }\n}\n\nconst bar = new Bar('BKJang');\nconsole.log(bar); //Bar {name: \"BKJang\"}\n```\n\n> `constructor`내부에서 선언한 `property`는 `class`의 인스턴스를 가리키는 `this`에 바인딩 된다.\n\n## getter, setter\n\n`class`의 프로퍼티에 접근하기 위한 인터페이스로서, `getter`와 `setter`를 정의할 수 있다.\n\n```js\nclass Person {\n    constructor(name) {\n        this.name = name;\n    }\n\n    //getter\n    get personName() {\n        return this.name ? this.name : null;\n    }\n\n    //setter\n    set personName(name) {\n        this.name = name;\n    }\n}\n\nconst person = new Person('BKJang');\n\nconsole.log(person.personName); //BKJang\nperson.personName = 'SHJo';\nconsole.log(person.personName); //SHJo\n```\n\n## Static 메서드\n\n`class`에서는 정적 메서드를 정의할 때, `static` 키워드를 사용하여 정의한다. **정적 메서드는 인스턴스를 생성하지 않아도 호출가능하며, 인스턴스가 아닌 `class`의 이름으로 호출한다.** 이와 같은 특징 때문에 애플리케이션을 위한 유틸리티성 함수를 생성하는데 주로 사용한다.\n\n또한 **정적 메서드 내부에서는 `this`가 `class`의 인스턴스가 아닌 `class`자기 자신을 가리킨다.**\n\n```js\nclass Person {\n    constructor(name) {\n        this.name = name;\n    }\n\n    //getter\n    get personName() {\n        return this.name ? this.name : null;\n    }\n\n    //setter\n    set personName(name) {\n        this.name = name;\n    }\n\n    static staticMethod() {\n        console.log(this);\n        return 'This is static';\n    }\n}\n\nconsole.log(Person.staticMethod()); \n/*\nclass Person { ... }\nThis is static\n*/\n\nconst instance = new Person('BKJang');\n\nconsole.log(instance.staticMethod()); //Uncaught TypeError: instance.staticMethod is not a function\n```\n\n위에서 볼 수 있듯이 인스턴스로는 `class`의 정적 메서드를 호출할 수 없다. \n\n또한 **정적 메서드는 `prototype`에 추가되지 않는다.**\n\n```js\nconsole.log(Person.staticMethod === Person.prototype.staticMethod); //false\nconsole.log(new Person().personName === Person.prototype.personName); //true\n```\n\n## 클래스의 상속\n\n`class`를 이용하여 `OOP`의 특징 중 하나인 상속을 구현할 수 있다.`class`의 상속을 위해서는 `extends`와 `super` 키워드에 대해서 알아야 한다.\n\n```js\nclass Person {\n    constructor(name, sex) {\n        this.name = name;\n        this.sex = sex;\n    }\n\n    getInfo() {\n        return `Name : ${this.name}, Sex : ${this.sex}`;\n    }\n\n    getName() {\n        return `Name : ${this.name}`;\n    }\n\n    getSex() {\n        return `Sex : ${this.sex}`;\n    }\n}\n\nclass Developer extends Person { //extends를 사용하여 Person 클래스 상속\n    constructor(name, sex, job) {\n        //super메서드를 사용하여 부모 클래스의 인스턴스를 생성\n        super(name, sex);\n        this.job = job;\n    }\n\n    //오버라이딩\n    getInfo() {\n        //super 키워드를 사용하여 부모 클래스에 대한 참조\n        return `${super.getInfo()} , Job: ${this.job}`;\n    }\n\n    getJob() {\n        return `Job : ${this.job}`;\n    }\n}\n\nconst person = new Person('SHJo', 'Male'); \nconst developer = new Developer('BKJang', 'Male', 'Developer');\n\nconsole.log(person); //Person {name: \"SHJo\", sex: \"Male\"}\nconsole.log(developer); //Developer {name: \"BKJang\", sex: \"Male\", job: \"Developer\"}\n\nconsole.log(person.getInfo()); //Name : SHJo, Sex : Male\n\nconsole.log(developer.getName()); //Name : BKJang\nconsole.log(developer.getSex()); //Sex : Male\nconsole.log(developer.getJob()); //Job : Developer\nconsole.log(developer.getInfo()); //Name : BKJang, Sex : Male , Job: Developer\n\nconsole.log(developer instanceof Developer); //true\nconsole.log(developer instanceof Person); //true\n```\n\n위의 소스를 기준으로 중요한 특징을 정리하자면 다음과 같다.(대부분의 객체 지향 언어에서 상속의 특징과 거의 동일하다.)\n\n- **부모 클래스(슈퍼 클래스)의 메서드를 사용할 수 있다.**\n\n- **부모 클래스의 메서드를 오버라이딩(Overriding)할 수 있다.**\n\n- **`super` 키워드를 통해 부모 클래스의 메서드에 접근**할 수 있다.\n\n- **`super` 메서드**(위의 Developer 클래스의 constructor내부에 선언)**는 자식 클래스의 `constructor` 내부에서 부모 클래스의 constructor(`super-constructor`)를 호출**한다.\n\n---\n\n### Reference\n\n- [자바스크립트 객체지향 프로그래밍](https://poiemaweb.com/js-object-oriented-programming)\n- [MDN Web Docs - Classes](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Classes)\n- [[ES6] 6. Class sugar syntax](https://jaeyeophan.github.io/2017/04/18/ES6-6-Class-sugar-syntax/)\n- [Class 클래스](https://poiemaweb.com/es6-class)\n"
  },
  {
    "path": "ECMAScript/Number_isNaN.md",
    "content": "# isNaN\n\n## NaN\n\nNaN은 Not a Number이다. 그런데 이건 조금 특이하다. 단순히 숫자가 아닌것이 아니다. 조금 정확히 하자면 Not a Number 보다는 Invaild Number라는 표현이 조금 더 정확할 것 같다. 무슨말이나면 숫자긴 숫자인데 에러가 발생하는 숫자라는 의미다.\n\n```javascript\nvar a = 2 / 'hello';\n\ntypeof a; // 'number'\n```\n\nNaN은 연산의 결과에서 에러가 발생(undefined or unpresentable) 할 때 생성된다. 위의 경우처럼 숫자를 문자열로 나누는 것처럼 말이다.\n\n## NaN의 비교 (isNaN())\n\n너무 유명한 주제인데 NaN은 서로 동등비교 할 수 없다. NaN은 자신과도 같지 않기 때문이다.\n\n```javascript\nvar a = NaN;\n\na === a; // false\na === NaN; // false\n```\n\n그래서 내장 전역 함수인 isNaN()을 사용했었다.\n그런데 치명적인 문제는 이 역시 의미가 모호하다. 이유는 메커니즘에 있다. 주어진 인자 x 가 Number가 아니라면 Number(x)의 형태로 강제 형변환을 한 뒤 이게 NaN인지 비교하는 방식이다.\n\n```javascript\nisNaN(NaN); // true\nisNaN('hello'); // true\nisNaN('37'); // false\n```\n\n즉 isNaN은 NaN인지는 확인이 가능하다. 그러나 `\"hello\"` 와 같이 NaN이 아닌 값도 NaN으로 판단한다. 즉 숫자로 강제 변환되지 않는 값은 NaN으로 취급하는 에러가 발생한다.\n\n따라서 `isNaN(\"NaN\") // true` 이런 일도 발생해 버린다.\n\n## NaN의 비교 (Number.isNaN())\n\nES6부터 이를 해결하기 위해 Number.isNaN()라는 메서드가 등장했다. 원래의 전역 isNaN보다 조금 더 엄격한 버전이다.\n\n```javascript\nNumber.isNaN(NaN); // true\nNumber.isNaN('hello'); // false\nNumber.isNaN('37'); // false\nNumber.isNaN('NaN'); // false\n```\n\n아주 직관적으로 잘 작동한다. 그런데 ES6부터기 때문에 폴리필이 필요할 수 있다. 폴리필을 보면 코드가 실제로 어떻게 작동하는지 알수 있기 때문에 유용한데 안은 정말정말 간단하게 되어있다.\n\n```javascript\nNumber.isNaN =\n  Number.isNaN ||\n  function(value) {\n    return value !== value;\n  };\n```\n\n한줄이 끝이다. `value !== value` 인 것만 확인하면 된다. 생각보다 매우 잘 작동한다. 혹시 isNaN을 사용할 일이 있다면 에러가 발생할 수 있기 때문에 모두 Number.isNaN으로 바꿔주도록 하자.\n"
  },
  {
    "path": "ECMAScript/Spread_Operator.md",
    "content": "# Spread Operator\n\n## 전개 연산자\n\nES2015인 ES6부터 새롭게 추가된 연산자다. 배열을 각 요소로 확장하는 연산자다. 생긴건 `...` 이렇게 생겼다. 말로 설명하자면 좀 복잡하고 개발자답게 코드로 보는 것이 가장 쉽다.\n\n그런데 대표적인(typically) 예가 좀 애매하다. 이 전개 연산자는 여러가지를 대체할 수 있기 때문이다. 그래서 몇가지 예시 찾아봤다.\n\n## 기존의 문제점\n\n```js\nvar midArr = [3, 4];\nvar arr = [1, 2, midArr, 5, 6];\n\nconsole.log(arr); // [1, 2, Array(2), 5, 6]\n```\n\n우리가 원한건 이게 아니다.\n\n## concat의 확장\n\n위의 문제를 해결하는게 원래 concat과 같은 메서드다. 다만 concat은 앞뒤를 이어주기만 하지 중간으로 들어갈 수가 없다.\n\n```js\nlet a = [1, 2, 3];\nlet b = ['foo', 'bar'];\n\nlet c = a.concat(b);\nconsole.log(c); // [1, 2, 3, \"foo\", \"bar\"]\n```\n\n단순히 앞뒤를 더해 새로 만드는 것은 concat이 성능적으로 조금 더 좋다. 다만 중간에 추가하는 다음과 같은 경우는 spread를 사용한다.\n\n```js\nlet a = [1, 2, 3];\nlet b = ['foo', 'bar', ...a];\n\nconsole.log(b); // [\"foo\", \"bar\", 1, 2, 3]\n// let c = [...a, ...b] 이 코드는 그다지 좋지 않다.\n```\n\n`...`을 사용하면 기존 `[1,2,3]`의 배열이 `1 2 3`으로 변경된다. 말그대로 spread다.\n\n이걸 조금 더 강력하게 사용할 수 있는 점은 중간에 넣을 수도 있다는 것이다.\n\n```js\nlet a = [1, 2, 3];\nlet b = ['foo', ...a, 'bar'];\n\nconsole.log(b); // [\"foo\", 1, 2, 3, \"bar\"]\n```\n\n## 인자의 배열 대체\n\n함수의 인자에 들어가는 배열을 대체할 수 있다.\n\n함수호출은 그냥 `함수명()`으로 실행한다. 아래와 같은 상황에서 사용될 수 있다.\n\n```js\nlet arr = [1, 2, 3, 4, 5];\nlet arr2 = [1, 2, 3];\nlet sum = (a, b, c, d, e) => a + b + c + d + e;\n\nlet sumArr = sum(...arr);\nlet sumArr2 = sum(...arr2, 10, 100);\n\nconsole.log(sumArr); // 15\nconsole.log(sumArr2); // 116\n```\n\n## 배열복사\n\n배열 복사는 사실 코딩하다보면 꽤나 많이 쓰이는 기능이다. 기존의 배열에 영향을 주지 않고 어떤 기능을 하기 위해서 많이 쓰인다.\n\n그냥 간단하게 사용하면 된다.\n\n```js\nlet arr = [1, 2, 3, 4];\nlet arr2 = [...arr];\n```\n\n## String to Array\n\n사실상 구체적으로 보자면 배열복사와 크게 다르진 않지만 쉽게 쓰이는 트릭이다. 흔히들 문자열을 배열로 만드려면 `str.split(\"\")`이렇게 사용하지만 좀 더 명확하게 spread operator를 사용할 수 있다.\n\n```js\nlet str = 'helloWorld!';\nlet strArr = [...str];\n\nconsole.log(strArr); //[\"h\", \"e\", \"l\", \"l\", \"o\", \"W\", \"o\", \"r\", \"l\", \"d\", \"!\"]\n```\n\n## object 복사(할당)\n\nobject는 iterable 객체는 아니지만 값을 할당할 때는 spread operator를 사용할 수 있다. react의 setState에서 사용하는 기술과 동일하다.\n\n```js\nlet obj1 = {\n  '1': 'a',\n  '2': 'b'\n};\n\nlet obj2 = {\n  ...obj1,\n  '3': 'c'\n};\n\nconsole.log(obj2); // { '1': 'a', '2': 'b', '3': 'c' }\n```\n"
  },
  {
    "path": "ECMAScript/Tagged_Template_Literals.md",
    "content": "# Tagged Template Literals\n\n## Template literals\n\nliterals 즉 입력하는 값에 백틱(`)과 치환자(\\${})로 템플릿을 설정할 수 있는 기능이다. ES6에서 추가 된 기능이다. 이미 너무 많은곳에서 사용하고 있기에 간단하게만 알아보자.\n\n```js\nvar area = '서울';\nvar temper = 10;\n\nconsole.log('이번달 ' + area + '의 평균온도는 ' + temper + '도입니다.'); // 1\nconsole.log('이번달', area, '의 평균온도는', temper, '도입니다.'); // 2\n\n//이번달 서울의 평균온도는 10도입니다.\n//이번달 서울 의 평균온도는 10 도입니다.\n```\n\nTemplate Literals를 사용하지 않았을 때의 방법이다. 1번이 전통적인 방법이며 2번의 경우 사용은 편하지만 공백이 자동으로 달라붙어 조금 귀찮다.\n\n```js\nconsole.log(`이번달 ${area}의 평균온도는 ${temper}도입니다.`);\n```\n\nTemplate Literals를 사용해 1번의 결과와 완벽히 똑같이 만들수 있다.\n\n참고로 Template String이라고도 이야기하는데 이는 오래된 표현이며 Literal이 옳은 표기법이다\n\n## Expression\n\n단순히 사용만 편한것은 아니다. 저 \\${} 사이에는 expression(표현식)이 들어갈 수 있다.\n\n```js\nvar a = 5;\nvar b = 8;\nconsole.log(`${a}와 ${b}의 합은 ${a + b}이며,\n${a}와 ${b}의 곱은 ${a * b}입니다.\n`);\n// 5와 8의 합은 13이며,\n// 5와 8의 곱은 40입니다.\n```\n\n표현식을 사용한 예제다. 참고로 멀티라인을 지원하는데 이 경우 LF(\\n)으로 줄바꿈된다.\n\n```js\nvar nike = true;\nvar shoes = ['Adidas', 'Vans', 'Puma'];\nvar out = `Shoes : ${nike ? shoes.join(',') : ''}`;\n\nconsole.log(out);\n// Shoes : Adidas,Vans,Puma (nike가 true)\n// Shoes :  (nike가 false)\n```\n\n표현식을 이용하여 다양하게 활용이 가능하다.\n\n## Tagged Template Literals\n\n이제 태그가 붙여진 Template Literals다.\n\n```js\nvar shoes = ['Adidas', 'Vans', 'Puma'];\nvar result = js`제 신발은 ${shoes[0]}입니다. ${shoes[1]}와${shoes[2]}도 있습니다`;\n\nfunction js(strings, expr1, expr2, expr3) {\n  debugger;\n  return 'complete';\n}\n```\n\ntag는 js라고 임의의 이름으로 만들었다. Template Literal 앞에 붙은 태그는 함수다.\n\n브라우저에서 디버거로 strings를 확인하면 `[\"제 신발은 \", \"입니다. \", \"와\", \"도 있습니다\"]` 다. 즉 순수 string부분이다. expr1, 2, 3은 차례대로 들어온 표현식의 결과 값이다. 즉 기존의 문자열과 표현식을 구분하여 사용할 수 있게 된다.\n\n그런데 태그가 함수라면 그냥 함수를 사용하지 이렇게 사용해야 하는 이유가 뭘까? 라고 생각할 수 있다.\n\n```js\nvar shoes = ['Adidas', 'Vans', 'Puma'];\nvar result = js(`제 신발은 ${shoes[0]}입니다. ${shoes[1]}와${shoes[2]}도 있습니다`);\n\nfunction js(strings, expr1, expr2, expr3) {\n  return 'complete';\n}\n```\n\n이렇게 말이다. 그런데 이렇게 사용하면 strings는 하나의 완성된 string이며 expr 1, 2, 3은 undefined다. 완성된 결과만 가질 수 있다.\n\n```js\nvar shoes = ['Adidas', 'Vans', 'Puma'];\n//debugger\nvar result = js(['제 신발은 ', '입니다. ', '와', '도 있습니다'], shoes[0], shoes[1], shoes[2]);\n\nfunction js(strings, expr1, expr2, expr3) {\n  return 'complete';\n}\n```\n\n따라서 이렇게 표기해야만 같은 기능을 한다.\n\n## 활용\n\n그렇다면 이를 어디에 사용할까?? 사실 사용방법은 굉장히 다양하겠지만 react에서 아주 쉽게 찾아볼 수 있는 styled-components를 생각해보자.\n\n```js\nconst Button = styled.button`\n  font-size: ${props => (props.primary ? '2em' : '1em')};\n`;\n```\n\n만일 tagged template literals가 없었다면 styled-components의 이 표기법은 존재할 수 없다.\n\n또 [es2015-i18n-tag](https://github.com/skolmer/es2015-i18n-tag) 라고하는 i18n / l10N 라이브러리도 있다.\n\n```js\nconsole.log(i18n`Hello ${name}, you have ${amount}:c in your bank account.`);\n// Hallo Steffen, Sie haben € 1,250.33 auf Ihrem Bankkonto.\n```\n\n영어를 받아서 미리 지정해둔 언어로 교체할 수 있다. strings를 받아 언어를 변경한다.\n\nTagged Template Literals를 통해 HTML이나 CSS 파서등을 만들 수도 있을 것이다. 더 나아가 [XRegExp](http://xregexp.com/) 라고 정규표현식을 파싱한 라이브러리도 존재한다.\n\n---\n\n#### Reference\n\n[The magic behind 💅 styled-components](https://mxstbr.blog/2016/11/styled-components-magic-explained/)\n[Tagged Template literals — Its more than you think](https://codeburst.io/javascript-es6-tagged-template-literals-a45c26e54761)\n[ES2015 Tagged Template Literal](https://www.zerocho.com/category/ECMAScript/post/5aa7ecc772adcb001b2ed6f3)-zerocho\n[ES6 번역프로젝트 - 8.Template리터럴](https://github.com/ES678/Exploring-ES6/blob/master/08%20Template%20%EB%A6%AC%ED%84%B0%EB%9F%B4/README.md)\n[ES6 Tagged Template Literals](https://www.youtube.com/watch?v=c9j0avG5L4c&t=335s) - youtube video\n"
  },
  {
    "path": "Git/gitBy_.git.md",
    "content": "# .git으로 이해하는 GIT\n\n깃은 분산된 형상관리 툴(DVCS)이다.\n\n단순하게만 생각하면 별거 없다. 게임 문명을 하다보면... 다른 문명이 내 원더 대신 만들면 돌려서 다른걸 생산해야 한다.\n\n프로젝트도 이처럼 저장과 불러오기가 필요한데 이게 바로 깃이다.\n\n## 개념\n\n기본 개념은 아래의 그림과 같다.\n\n![git life cycle](/assets/images/gitBy_.git_gitlifecycle.png)\n\nindex가 staged, staging area다.\n\n## git init\n\n`init` 명령어는 local repository를 만든다. 이 로컬 저장소는 바로 .git에 들어가있다.\n\n.git에는 아래와 같은 내용이 초기 세팅된다.\n\n    config\n    description\n    HEAD\n    hooks/\n    info/\n    objects/\n    refs/\n\n## git add\n\nadd 명령은 working directory의 파일을 staging area로 옮긴다.\n\n그럼 이 staging area(이하 staged)는 뭘까?\n\nstaged는 .git의 index다. add를 하는 순간 .git에는 인덱스가 생긴다.\n\n동시에 objects에는 blob타입의 객체가 생성된다. 이는 파일에 대한 내용이다. 파일 내용을 가지고 hash하여 만들어진다.\n\n깃은 모든 파일을 blob 타입의 객체로 관리한다. 그런데 파일의 내용이 기준이기 때문에 파일의 내용이 변경되면 새로운 객체가 생긴다. 파일 두개를 add하면 당연히 두개의 blob객체가 생성되고, 기존의 파일 1개의 내용을 변경하여 add하면 새로운 객체가 생겨 총 3개의 객체가 생성된다.\n\n인덱스는 tree형태로 구성되며 객체의 이름과 hash값을 가진다. 그걸 가지고있으니 추적할 수 있게된다.\n\n## git commit\n\n깃은 커밋이 핵심이다.\n\n게임에서 사실 되돌일 일은 많이 없지 않나? 그래서 저장이 제일 중요하다. 이 저장이 커밋이다.\n\n커밋을 하면 .git/objects/에는 tree, commit 두 개의 객체가 생긴다.\n\ncommit객체는 tree객체의 hash와 Author, Date, Msg, 부모 커밋의 hash를 가진다.\n\ntree 객체는 커밋시의 index의 스냅샷을 가진다.\n\n그래서 예를들어 push하면 `Compressing objects: 100% (5/5), done.` 이와 비슷한 표준출력이 발생한다. 5개의 객체가 전달되는 것이다.\n\n## git status\n\n파일을 생성하고 status를 치면 working tree와 index의 blob객체의 내용이 서로 다르다. 그래서 git add 하라고 뜬다.\n\nadd 하고 파일을 변경한 뒤 status를 칠 때도 마찬가지다. index의 blob객체와 내용이 다르면 이거 확인하라고 뭐라뭐라 뜬다.\n\nadd 상태에서 status를 치면 head -> branch -> commit -> tree 객체의 내용과 index를 비교하여 다른게 있는지 알려준다.\n\nworking tree, index, head/branch/commit/tree가 서로 일치하면 클린한 상태가 된다.\n\n## git branch\n\nHEAD는 참조변수다. branch 역시 참조변수다. HEAD는 보통의 경우 branch를 가리킨다. branch는 커밋을 가리킨다.\n\ncheckout은 이 HEAD를 변경하는 명령어이며, reset은 HEAD의 참조값과 branch의 참조값을 모두 변경한다.\n\ninit부터 여기까지의 어려웠던 내용이 바로 아래 그림이다.\n\n![git_objects](/assets/images/gitBy_.git_gitobjects.png)\n\n## git pull & git fetch\n\n위의 그림의 좌측 맨위를 보면 HEAD는 ref/heads/master 를 바라본다. 설명을 위해 master브랜치에서만 작업한다고 가정하자. 로컬에서는 9번 커밋까지만 진행하고 누군가 10번 커밋을 진행해 push했다고 가정하자.\n\n`fetch` 명령을 같은 master 브랜치로 실행한다면 remote 저장소의 objects, branch등을 로컬 저장소로 가져온다. 그럼 ref/remotes/origin/master 즉 origin/master 브랜치 참조변수는 remote에서 변경된 10번 커밋을 바라볼 것이다.\n\n| ref/heads/master | ref/remotes/origin/master |\n| ---------------- | ------------------------- |\n| 9번커밋          | 10번커밋                  |\n\n이게 현재 상황이다. 같은 master 브랜치지만 remotes와 local이 바라보는 커밋이 다르다.\n\n이 때 merge 작업을 진행해 HEAD를 움직여준다.\n\n`pull` 명령은 remote 저장소의 변경사항을 받아 merge까지 진행한다. HEAD가 변경되고 그에따라 커밋이 바라보는 tree객체가 변경된다. 따라서 tree에 쓰인 파일 정보가 달라 working tree 까지 반영한다.\n\n## stash\n\n임시저장소다. 작업하다가 master 브랜치의 버그가 발생한 것을 인지 한경우 커밋을 할 순 없으니 stash에 저장한 뒤 master로 이동한다.\n\n---\n\n### 참고자료\n\n- [git의 원리 (git object를 중심으로)(빨간색코딩)](https://sjh836.tistory.com/37)\n- [쩜깃의 이해](https://jusths.tistory.com/64)\n\n두 사이트 모두 정말 큰 도움 됐습니다.\n\n- [생활코딩 gistory youtube](https://www.youtube.com/watch?v=QpTzoiiYoV4&list=PLuHgQVnccGMC6_JRFarkLPBfSNFwrGVlJ&index=6&t=0s)\n- [pro git](https://git-scm.com/book/ko/v2)\n"
  },
  {
    "path": "HTML/ARIA.md",
    "content": "# ARIA(Accessible Rich Internet Applications)\n\nARIA란 웹 콘텐츠와 웹 어플리케이션을 제작할 때 누구든 쉽게 접근할수 있도록 하는 접근성 향상 방법 중 하나이다. ARIA를 사용하여 내비게이션 랜드마크, 위젯, 서식 힌트, 에러메시지, 실시간 콘텐츠 업데이트 등을 표현하여 **접근성**을 부여할 수 있다.\n\nARIA는 접근성 관련 **속성(attribute)** 이며, HTML에 최적화 되어 있다. `role` 속성을 사용하여 객체(article, alert, slider 등등)의 일반 타입을 정의하고, 이 외 ARIA 속성을 추가로 사용하여 서식에 관한 설명이나 상태바의 현재 값을 제공하는 등 유용한 프로퍼티들을 제공한다.\n\n> [role 종류에 대해서 자세히 알아보기](https://www.w3.org/TR/wai-aria-1.1/#role_definitions) <br/>\n> [ARIA_Techniques - MDN 문서](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques)\n\n대부분의 브라우저들과 스크린 리더 기기는 ARIA를 지원한다. 그러나 구현방식이 상이하여 지원을 하더라도, 오래된 기기 혹은 브라우저의 경우에는 제대로 적용되지 않는 경우가 있다. 애플리케이션의 기능을 [우아한 하향](https://github.com/Im-D/Dev-Docs/blob/master/Performance/%EC%A0%90%EC%A7%84%EC%A0%81%ED%96%A5%EC%83%81_%EC%9A%B0%EC%95%84%ED%95%9C%ED%95%98%ED%96%A5.md)를 하여 ARIA를 사용하거나, 사용자에게 기기를 최신 버전으로 업그레이드할 것을 요청해야 한다.\n\n**role** 속성은, **tabIndex** 속성과 항상 같은 곳에서 적용되어야 한다. **그래야 설정된 role이 의도된 element에서 정확히 수행될 수 있다**. ARIA를 통해 바꿀 수 있는 것은 오직, **Accessibility Tree** 뿐이다. Element의 외형, 동작, focusability, keyboard event handling 등등 다른 것은 아무것도 바뀌지 않는다.\n<br/>\n\n## ARIA 레이블과 관계\n\n### aria-label\n\n**`aria-label`** 을 사용하여 접근 가능한 label 문자열을 지정할 수 있다. **`aria-label`** 은 label Element처럼 네이티브 labelling을 모두 무시한다. 예를 들어, **`button`** 에 텍스트 콘텐츠와 **`aria-label`** 이 모두 있는 경우 **`aria-label`** 값만 사용된다.\n\n텍스트 대신 그래픽을 사용하는 버튼과 같이, Element의 목적을 시각적으로 표시할 때 **`aria-label`** 속성을 사용할 수 있다. 그러나 이미지만 사용하여 표시하는 버튼 같은 것은 시각적 인지할 수 없는 사용자를 위해 다른 방법으로 Element의 목적을 표시해야 한다.\n\n![aria1](https://user-images.githubusercontent.com/24274424/57572191-f0a48e80-7451-11e9-9ff0-e426757e33c2.png)\n<br/>\n\n### aria-labelledby\n\n**`aria-labelledby`** 를 사용하면 DOM에 있는 다른 Element의 ID를 해당 Element의 레이블로 지정할 수 있다.\n\n![aria2](https://user-images.githubusercontent.com/24274424/57572192-f0a48e80-7451-11e9-88c5-8835061ee040.png)\n\n이것은 몇 가지 차이점이 있는 label Element이라고 생각하면 된다.\n\n1. **`aria-labelledby`** 는 레이블 지정 가능한 Element뿐 아니라 어떤 Element에서든 사용할 수 있다.\n2. **`label`** Element는 자신이 레이블을 지정하는 대상을 참조하지만 **`aria-labelledby`** 의 경우에는 관계가 다르다. \n3. 한 레이블 Element만 레이블 지정 가능한 Element와 연결할 수 있지만, **`aria-labelledby`** 는 IDREF 목록을 선택하여 여러 Element에서 레이블을 작성할 수 있다. 레이블은 IDREF가 지정되는 순서대로 연결된다.\n4. **`aria-labelledby`** 를 사용하여 숨겨져 있거나 접근성 트리에 없는 Element를 참조할 수 있다. 예를 들어, 레이블을 지정하려는 Element 옆에 숨겨진 **`span`** 을 추가하고 **`aria-labelledby`** 로 참조할 수 있다.\n5. 하지만 ARIA는 접근성 트리에만 영향을 주므로 **`aria-labelledby`** 를 사용하면 label Element를 사용할 때처럼 레이블 클릭 동작을 구현할 수는 없다.\n\n중요한 점은, **`aria-labelledby`** 한 Element에 대한 다른 **모든** 이름 소스를 재정의 한다. 예를 들어, 어떤 Element에 **`aria-labelledby`** 와 **`aria-label`** 이 모두 있거나 **`aria-labelledby`** 와 네이티브 label이 있는 경우에는 **`aria-labelledby`** **레이블이 항상 우선한다.**\n<br/>\n\n## 관계\n\n**`aria-labelledby`** 는 *관계 속성*의 예이다. **관계 속성은 DOM 관계와는 무관하게 페이지에 있는 Element들 사이의 의미 체계 관계를 생성** 한다. **`aria-labelledby`** 의 경우 의미 체계 관계는 이 Element가 저 Element에 레이블을 지정한다.\n\n**`aria-activedescendant`**, **`aria-controls`**, **`aria-describedby`**, **`aria-labelledby`**, **`aria-owns`** 는 하나 또는 그 이상의 Element를 참조하여 페이지에 있는 Element들 사이에 새로운 링크를 생성한다.\n<br/>\n\n### aria-owns\n\n**`aria-owns`** 는 가장 널리 사용되는 ARIA 관계 중 하나이다. 이 속성을 사용하여 DOM에 있는 별개의 Element를 현재 Element의 하위 Element로 처리해야 한다고 알려주거나 기존 하위 Element를 다른 순서로 재정렬할 수 있다.\n\n![aria3](https://user-images.githubusercontent.com/24274424/57572193-f13d2500-7451-11e9-852a-dcd2ca642647.png)\n<br/>\n\n### aria-activedescendant\n\nElement의 활성화된 하위 항목을 설정하여 상위 항목에 실제로 포커스가 있을 때 그 Element를 사용자에게 포커스된 Element로 표시해야 함을 알려줄 수 있다. \n\n예를 들어, 목록 상자에서 목록 상자 컨테이너에 페이지 포커스를 남겨두고 싶지만 **`aria-activedescendant`** 속성은 현재 선택한 목록 항목에 맞춰 계속 업데이트 유지할 수도 있다. 이를 통해 현재 선택한 항목이 마치 포커스된 항목인 것처럼 나타나게 할 수 있다.\n\n![aria4](https://user-images.githubusercontent.com/24274424/57572194-f13d2500-7451-11e9-81f6-e7c49d8d0cbe.png)\n<br/>\n\n### aria-describedby\n\n**`aria-describedby`** 는 **`aria-labelledby`** 가 레이블을 제공하는 것과 똑같은 방식으로 액세스 가능한 설명을 제공한다. **`aria-labelledby`** 와 마찬가지로, **`aria-describedby`** 는 DOM에서 숨겨지거나 숨겨졌는지에 상관없이 다른 방법으로는 보이지 않는 Element를 참조한다. 이는 사용자에게만 적용되든 모든 사용자에게 적용되든 상관없이, 사용자에게 추가적인 설명문이 필요할 때 유용한 기법이다.\n\n![aria5](https://user-images.githubusercontent.com/24274424/57572195-f13d2500-7451-11e9-9fb6-4774a8f7fe38.png)\n<br/>\n\n### aria-posinset 및 aria-setsize\n\n나머지 관계 속성은 앞서 설명한 속성과는 약간 다르게 사용된다. **`aria-posinset`**과 **`aria-setsize`**는 목록과 같이 집합을 이루고 있는 형제 Element 간의 관계를 정의하는 속성이다.\n\nDOM에 있는 Element로는 집합의 크기를 결정할 수 없을 때 **`aria-setsize`** 는 실제 집합 크기를 지정할 수 있고 **`aria-posinset`** 는 집합에서 Element의 위치를 지정할 수 있다. 예를 들어, Element 개수가 1,000개인 집합의 경우 DOM에서 특정 Element가 맨 처음에 나타나더라도 **`aria-posinset`** 가 857이라고 하고 동적 HTML 기술을 사용해 사용자가 필요할 때 전체 목록을 탐색하도록 할 수 있다.\n\n![aria6](https://user-images.githubusercontent.com/24274424/57572196-f13d2500-7451-11e9-8649-9b65bbc90f54.png)\n<br/>\n\n### aria-hidden\n\n사용자를 위한 사용 환경의 미세 조정에서 중요한 다른 기술은 페이지에서 관련 부분만 노출 시킨다. DOM의 한 부분이 접근성 API에 노출되지 않도록 하는 방법은 여러 가지가 있다.\n\n먼저 DOM에서 명시적으로 숨겨진 콘텐츠는 접근성 트리에도 포함되지 않는다. 따라서 **`visibility: hidden`** 또는 **`display: none`** 의 CSS 스타일이 있거나 HTML5 **`hidden`** 속성을 사용하는 콘텐츠 역시 숨겨져 사용자가 인식할 수 없다.\n\n하지만 시각적으로 렌더링되지 않지만 명시적으로 숨겨지지는 않는 Element는 여전히 접근성 트리에 포함된다. 한 가지 일반적인 기법은 절대 위치상 화면 밖에 있는 Element에 스크린 리더 전용 텍스트를 포함하는 것이다.\n\n```css\n.sr-only {  \n  position: absolute;  \n  left: -10000px;  \n  width: 1px;  \n  height: 1px;  \n  overflow: hidden;\n}\n```\n\n또한, 다른 상황이었다면 숨겨지는 Element를 참조하는 **`aria-label`**, **`aria-labelledby`** 또는 **`aria-describedby`** 속성을 통해 스크린 리더 전용 텍스트를 제공할 수 있다.\n\n마지막으로, ARIA는 **`aria-hidden`** 속성을 사용하여 시각적으로 숨겨지지 않는 콘텐츠를 제외하기 위한 매커니즘을 수행하는데, Element에 이 속성을 적용하면 사실상 Element와 *모든 하위 항목*이 접근성 트리에서 제거된다. **`aria-labelledby`** 또는 **`aria-describedby`** 속성이 참조하는 Element가 유일한 예외이다.\n\n```html\n<div class=\"deck\">  \n  <div class=\"slide\" aria-hidden=\"true\">    \n    Sales Targets  \n  </div>  \n  <div class=\"slide\">    \n    Quarterly Sales  \n  </div>  \n  <div class=\"slide\" aria-hidden=\"true\">    \n    Action Items  \n  </div>\n</div>\n```\n\n예를 들어, 기본 페이지에 대한 액세스를 차단하는 모달 UI를 생성하려는 경우 **`aria-hidden`** 을 사용할 수 있다. 이 경우 시력이 정상인 사용자에게는 페이지 대부분을 현재 사용할 수 없음을 나타내는 반투명 오버레이가 표시될 수 있겠지만, 스크린 리더 사용자는 페이지의 다른 부분을 계속 탐색할 수 있다. \n<br/>\n\n### aria-live\n\n개발자는 **`aria-live`** 를 사용해 페이지 중 어떤 부분을 '라이브'로 표시할 수 있다. 즉, 사용자가 페이지를 탐색하다가 그저 우연히 그런 '라이브' 부분을 발견하는 것이 아니라, 페이지의 어느 위치에 있든 상관없이 새롭게 업데이트된 정보를 사용자에게 즉시 알릴 수 있다. **`aria-live`** 속성을 가진 Element가 있는 경우 페이지에서 이런 Element와 그 하위 항목을 포함한 부분을 *라이브 영역*이라고 한다.\n\n![aria7](https://user-images.githubusercontent.com/24274424/57572197-f1d5bb80-7451-11e9-8206-763d58b362ba.png)\n\n예를 들어, 라이브 영역은 사용자 작업의 결과로서 나타나는 상태 메시지일 수 있다. 시력이 정상인 사용자의 시선을 끌어야 할 중요한 메시지인 경우 **`aria-live`** 속성을 설정하여 사용자의 관심 역시 충분히 끄는 것이 중요하다. 아래의 일반적인 **`div`** 를\n\n```html\n  <div class=\"status\">Your message has been sent.</div>\n```\n\n'라이브' `div`로 나타내면\n\n```html\n  <div class=\"status\" aria-live=\"polite\">Your message has been sent.</div>\n```\n\n**`aria-live`** 에는 **`polite`**, **`assertive`**, **`off`** 의 세 가지 값이 허용된다.\n\n- **`aria-live=\"polite\"`** 는 현재 어떤 작업을 하고 있든 그 작업을 마치면 사용자에게 변경 사항을 알리도록 하는 역할을 한다. 긴급하지 않은 변경사항일 경우에 적합하며 **`aria-live`** 는 대부분 이런 용도로 사용된다.\n- **`aria-live=\"assertive\"`** 는 수행 중인 작업이 무엇이든 중단하고 사용자에게 변경 사항을 **즉시 알리도록 하는 역할**을 한다. '서버 오류가 발생하여 변경 내용이 저장되지 않습니다. 페이지를 새로 고치세요' 같은 상태 메시지나  위젯에 있는 버튼처럼 사용자 작업의 직접적 결과로서 입력란이 업데이트되는 경우와 중요하고 긴급한 업데이트에 사용된다.\n- **`aria-live=\"off\"`** 는 **`aria-live`** 인터럽트를 일시적으로 중단하도록 하는 역할을 한다.\n\n라이브 영역이 제대로 작동하도록 하기 위한 방법이 몇 가지 있다.\n\n첫째, 처음에 페이지를 로드할 때 **`aria-live`** 영역을 설정해야 한다. 엄격히 지켜야 할 규칙은 아니지만 **`aria-live`** 영역에 어려운점이 있을 경우 문제가 된다.\n\n둘째, 스크린 리더는 다양한 유형의 변화에 각기 다르게 반응한다. 예를 들어, 하위 Element의 **`hidden`** 스타일을 `true`에서 `false`로 전환해 스크린 리더에서 경고를 발생시킬 수 있다.\n\n**`aria-live`** 와 함께 사용하는 다른 속성들은 라이브 영역이 바뀔 때 사용자에게 전달할 내용을 미세하게 조정하는 데 도움이 된다.\n\n**`aria-atomic`** 은 업데이트를 전달할 때 영역 전체를 하나의 전체로서 간주해야 할 지 여부를 나타낸다. 예를 들어 일, 월, 년으로 구성된 날짜 위젯에 **`aria-live=true`** 와 **`aria-atomic=true`** 가 있고 사용자가 컨트롤을 사용해 월의 값만 변경할 경우 날짜 위젯의 전체 콘텐츠가 다시 읽는다. **`aria-atomic`** 의 값은 **`true`** 또는 **`false`**(기본값)일 수 있다.\n\n**`aria-relevant`** 는 사용자에게 표시해야 할 변경 사항의 유형을 나타낸다. 별도로 사용하거나 목록으로 사용할 수 있는 옵션이 있다.\n\n- *additions*: 라이브 영역에 추가하는 Element가 중요하다는 뜻이다. 예를 들어, 상태 메시지의 기존 로그에 범위를 추가할 경우 이는 사용자에게 그 범위를 알려줄 것이라는 의미이다(**`aria-atomic`** 이 **`false`** 라고 가정).\n- *text*: 하위 노드에 추가하는 텍스트 콘텐츠가 관련성이 있다는 뜻이다. 예를 들어, 사용자설정 텍스트 필드의 **`textContent`** 속성을 수정하면 수정한 텍스트를 사용자에게 읽어주게 된다.\n- *removals*: 텍스트나 하위 노드 제거를 사용자에게 전달해야 한다는 뜻이다.\n- *all*: 모든 변경 사항이 관련성이 있다는 뜻이다. 하지만 **`aria-relevant`** 의 기본값은 **`additions text`** 인데, 이는 곧 **`aria-relevant`** 를 지정하지 않으면 Element에 추가되는 항목에 대해 사용자에게 표시되는 내용을 업데이트할 것이라는 의미이다.\n\n마지막으로, **`aria-busy`** 를 사용하면 Element에 대한 변경 사항을 일시적으로 무시해야 한다고 알려줄 수 있다(예: 로딩중일 때). 모든 절차를 끝낸 후 리더의 작동을 정상화하려면 **`aria-busy`** 를 `false`로 설정해야 한다.\n<br/>\n\n#### Reference\n\n- [ARIA - MDN](https://developer.mozilla.org/ko/docs/Web/Accessibility/ARIA)\n- [왜 ARIA인가?](https://starkying.tistory.com/entry/%EC%99%9C-ARIA%EC%9D%B8%EA%B0%80)\n- [ARIA 레이블과 관계](https://developers.google.com/web/fundamentals/accessibility/semantics-aria/aria-labels-and-relationships?hl=ko)\n- [콘텐츠 숨기기 및 업데이트](https://developers.google.com/web/fundamentals/accessibility/semantics-aria/hiding-and-updating-content?hl=ko)\n- [Why, How, and When to Use Semantic HTML and ARIA](https://css-tricks.com/why-how-and-when-to-use-semantic-html-and-aria/)\n- [레진 WAI-ARIA 가이드라인 소개](https://tech.lezhin.com/2018/04/20/wai-aria)"
  },
  {
    "path": "HTML/DOM API.md",
    "content": "# DOM API\n브라우저에서는 W3C DOM, WHATWG DOM 표준에 근거하여 노드의 형태로 DOM을 구현하고, 이를 사용하기 위한 프로퍼티와 메소드를 제공한다. 이 프로퍼티와 메소드의 집합을 **DOM API**라고 한다. 구현된 DOM은 OOP의 형태라 대체로 객체로 제공되기 때문에 javascript와 같은 스크립트 기반 언어가 접근하여 수정할 수 있다.\n\n<br/>\n\n## 요소 접근\n* [getElementById](#getelementbyid)\n* [getElementsByClassName](#getelementsbyclassname)\n* [querySelector와 querySelectorAll](#queryselector-&-queryselectorall)\n\n### getElementById\n```html\n<p id=\"getId\">getId</p>\n\n<script>\n    document.getElementById(\"getId\");\n</script>\n```\nid 속성값으로 Element node를 하나 선택한다.   \n> (출력값) `<p id=\"getId\">getId</p>`\n\n### getElementsByClassName\n```html\n<p class=\"getClass\">class1</p>\n<p class=\"getClass\">class2</p>\n<p class=\"getClass\">class3</p>\n<p class=\"getClass\">class4</p>\n\n<script>\n    document.getElementsByClassName(\"getClass\");\n</script>\n```\n> (출력값) `HTMLCollection(4) [p.getClass, p.getClass, p.getClass, p.getClass]`\n\nclass 속성값으로 모든 Element node를 선택한다.   \n선택된 node들은 `HTMLCollection`으로 반환된다.\n`HTMLCollection`은 **유사배열**이며, **실시간으로 node의 변경이 반영**된다. 따라서 다음과 같은 특징을 갖는다.\n\n* 배열 메소드를 사용할 수 없다.\n    ```js\n    var classes = document.getElementsByClassName(\"getClass\");\n    classes.forEach(el => el.innerText = \"changed\");\n    //에러발생\n    ```\n* `length` 속성과 `index`를 사용할 수 있다.\n* 클래스 변동시 반복문 사용에 유의해야한다.\n    ```js\n    var classes = document.getElementsByClassName(\"getClass\");\n    for(let i = 0; i<classes.length; ++i){\n        classes[i].className = \"changed\";\n    }\n    ```\n    예상대로라면 `classes[0]`부터 `classes[3]`까지 요소들의 className이 바뀌었을 것 같지만 실제로는 `classes[0]`과 `classes[2]`의 className만 바뀐다. 이유는 다음과 같다.\n    1. `i=0`일 때 `classes.length = 4`이고 `classes[0]`은 `HTMLCollection`의 첫번째 요소를 가리킨다. className이 변경된 후 `HTMLCollection`에 node의 변경이 실시간으로 적용된다. 즉, `HTMLCollection`의 첫번째 요소가 사라져 `length`와 `index`가 다음과 같이 변경된다.  \n    ![HTMLCollection](/assets/images/HTMLCollection.png)\n    2. 따라서 `i=1`일 때 `classes.length = 3`이 되고 `classes[1]`는 이전 `HTMLCollection`의 세번째 요소를 가리키게 된다. \n    3. 또 다시 node의 변경이 적용되어 `classes.length = 2`가 되어 반복문이 종료된다.   \n    \n    이 문제를 해결하기 위해 다음 방법들을 쓸 수 있다.  \n    * 반복문을 역방향으로 돌린다. \n        ```js\n        var classes = document.getElementsByClassName(\"getClass\");\n        for(let i=classes.length-1; i >= 0; --i){\n            classes[i].className = \"changed\";\n        }\n        ```\n    * HTMLCollection을 배열로 변경한다.\n        * Spread 이용\n        ```js\n        var classes = document.getElementsByClassName(\"getClass\");\n        var arrClass = [...classes]; \n        for(let i=0; i < arrClass.length; ++i){\n            arrClass[i].className = \"changed\";\n        }\n        ```\n        * `Array.from` 이용\n         ```js\n        var classes = document.getElementsByClassName(\"getClass\");\n        var arrClass = Array.from(classes);\n        for(let i=0; i < arrClass.length; ++i){\n            arrClass[i].className = \"changed\";\n        }\n        ```\n\n### querySelector & querySelectorAll\n`querySelector`와 `querySelectorAll`를 이용하면 `#`, `.`, `input[type=text]` 등과 같은 css 선택자로 요소에 접근할 수 있다.   \n`querySelectorAll`은 가져온 모든 요소를 **NodeList**로 가져온다. `NodeList`는 `HTMLCollection`과 달리 **node의 변동이 실시간으로 적용되지 않는다.** \n\n<br/>\n\n## 요소 탐색\n* 노드탐색  \n    parentNode  \n    childNode, firstChild, lastChild   \n    previousSibling, nextSibling 등\n* 요소탐색   \n    children, firstElementChild, lastElementChild  \n    previousElementSibling, nextElementSibling 등\n\n\n노드 탐색 시 주의해야할 점은 요소간의 공백도 텍스트 노드로 취급한다는 것이다. 따라서 탐색결과가 기대와 다를 수 있다. \n```HTML\n<ul>\n    <li id=\"a\" class=\"1\"></li>  \n    <li id=\"b\" class=\"2\"></li>\n    <li class=\"3\"></li>\n</ul>\n```\n즉, `li.a`의 `nextSibling`으로 `li.b`를 기대했지만 공백이 반환될 수도 있다. 이런 상황을 피하기 위해 위의 요소 탐색을 할 수 있다.   \n또한 여러 요소가 반환되는 경우 노드 탐색은 `NodeList`로, 요소 탐색 `HTMLCollection`으로 반환된다. \n\n<br/>\n\n## 요소 조작 - classList\n\n`classList`에는 다음과 같은 메소드가 있다. \n\n```js\nvar target = document.getElementById(\"target\");\ntarget.classList.add('added');\ntarget.classList.remove('added');\ntarget.classList.contains('added'); //boolean 반환\ntarget.classList.replace('target', 'changed');\ntarget.classList.toggle('active');\n```\n\n특히 다음과 같이 `toggle`을 사용하는 경우, `add`와 `remove`를 일일이 해줄 필요가 없기 때문에 매우 편리하다.\n\n```html\n<body>\n    <div class=\"bg\">\n        <button id=\"btn\"></button>\n    </div>\n</body>\n```\n```html\n.bg {\n    background: #e2e2e2;\n    border-radius: 15px;\n    width: 70px;\n}\n\n#btn {\n    position: relative;\n    height: 30px;\n    width: 30px;\n    outline: none;\n    background: white;\n    border-radius: 15px;\n}\n\n.toggleTrue {\n    left: 40px;\n}\n```\n```js\ndocument.getElementById(\"btn\").addEventListener(\"click\", function(e){\n    let target = e.target;\n    target.classList.toggle('toggleTrue');\n});\n```\n<br/>\n\n---\n#### Reference\n[문서 객체 모델(Document Object Model)](https://poiemaweb.com/js-dom)\n"
  },
  {
    "path": "HTML/DOM.md",
    "content": "# DOM\n\n![DOM](https://user-images.githubusercontent.com/24274424/57984686-291f1a80-7a99-11e9-9fbc-b2bbcc663209.png)\n\n들어가기에 앞서 먼저 BOM에 대해서 알아보자.\n\n웹은 브라우저에서 돌아가기 때문에 브라우저와 밀접한 관계를 가진다. 브라우저와 관련된 객체들의 집합을 브라우저 객체 모델(BOM : Browser Object Model)이라고 부른다. BOM을 사용하면 창을 이동하고 상태 표시줄의 텍스트를 변경하는 페이지 내용과 직접 관련이 없는 브라우저와 관련된 기능을 사용할 수 있다. **DOM은 이 BOM 중 하나이다.** \n\n> 예시)  `history`, `location`, `navigator`,  `screen`\n\nBOM의 최상위 객체는 window라는 객체이고, DOM은 window 객체의 하위 객체이다.\n\n![GIF_window document](https://user-images.githubusercontent.com/24274424/57984688-291f1a80-7a99-11e9-8926-09a8b8adb39c.gif)\n<br/>\n\n## DOM이란?\n\n> 문서 객체 모델(The Document Object Model(DOM)) 은 HTML, XML 문서의 프로그래밍 interface 이다. - MDN\n\nHTML에는 `<html>`, `<head>`, `<body>`와 같은 많은 태그가 있는데 이를 JavaScript로 사용할 수 있도록 객체로 만들면 그것을 **Document Object라고 한다.**\n\nDOM은 문서의 구조화된 표현을 제공하며 **프로그래밍 언어(JavaScript 등)가 DOM 구조에 접근할 수 있는 방법을 제공하여 문서 구조, 스타일, 내용 등을 변경할 수 있도록 해준다.** \n<br/>\n\n### DOM은 어떻게 생겼나?\n\nDOM의 모양을 이해하는데 선행되는 자료구조는 **Tree 구조**이다. DOM이 바로 Tree 형식의 자료구조를 가지고 있기 때문이다.\n\n이름 그대로 Tree 구조는 나무가 땅에서 솟아 위로 뻗어 나가면서 가지를 치면서 나가는 모양으로, DOM은 거꾸로 있는 모양이다.\n\n<p align=\"center\">\n  <img src=\"https://user-images.githubusercontent.com/24274424/57984687-291f1a80-7a99-11e9-811b-bc9b3b1dfef5.png\" alt=\"DOM_Tree\"/>\n</p>\n> The HTML DOM Tree of Object(by w3school)\n<br/>\n\n## DOM과 HTML 코드의 차이점\n\n우리는 웹페이지를 만들 때 HTML을 작성한다. 그렇다면 우리가 작성하는 이 소스가 DOM과 똑같을까?\n\n우리가 작성한 소스는 브라우저가 읽어서 DOM Tree를 만든다. \n\n> 참고) Im-D/Dev-Docs [ 브라우저의 작동 원리](https://github.com/Im-D/Dev-Docs/blob/master/Browser/%EC%9B%B9%20%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80%EC%9D%98%20%EC%9E%91%EB%8F%99%20%EC%9B%90%EB%A6%AC.md)\n\nHTML 코드는 DOM과 똑같은 것으로 예상되지만 브라우저에서 생성한 DOM과는 엄연히 다르다. 예시로 우리가 작성한 코드 중 중대한 오류가 아닌 이상 브라우저가 자동으로 소스 코드의 오류를 수정한다. (Ex. `tbody`)\n\n<p align=\"center\">\n  <img src=\"https://user-images.githubusercontent.com/24274424/57984677-27eded80-7a99-11e9-8a67-62516944a1ab.png\" alt=\"code1\" width=\"400\"/>\n\n  <img src=\"https://user-images.githubusercontent.com/24274424/57984678-27eded80-7a99-11e9-8ebb-45d120464b0f.png\" alt=\"code1_devtool\" width=\"400\"/>\n</p>\n위의 사진을 비교하게 되면 왼쪽은 실제 코드를 작성한 것이고 오른쪽은 실제 DOM으로 만들어진 모양이다. 실제로 `tbody` 태그를 작성하지 않았지만 만들어주는 것을 보여준다.\n\n이외\n\n- HTML 파일에 단어 하나라도 존재하면 브라우저는 이를 `html`과 `body` 으로 감싸고 `head`를 필수적으로 추가한다.\n\n<p align=\"center\">\n  <img src=\"https://user-images.githubusercontent.com/24274424/57984679-27eded80-7a99-11e9-87bd-acc9fbafd3e3.png\" alt=\"code2\" width=\"400\"/>\n\n  <img src=\"https://user-images.githubusercontent.com/24274424/57984680-28868400-7a99-11e9-8dbb-0bb56a3ad599.png\" alt=\"code2_devtool\" width=\"400\"/>\n</p>\n\n- DOM을 생성할 때 여는 태그만 작성하고 닫는 태그는 작성하지 않는다면, 자동 생성하여 맞춰서 오류가 발생하지 않는다.\n\n<p align=\"center\">\n  <img src=\"https://user-images.githubusercontent.com/24274424/57984681-28868400-7a99-11e9-95e4-f0c8797dfceb.png\" alt=\"code3\" width=\"400\"/>\n\n  <img src=\"https://user-images.githubusercontent.com/24274424/57984682-28868400-7a99-11e9-93f5-68542db5cf5e.png\" alt=\"code3_devtool\" width=\"400\"/>\n</p>\n\n우리가 작성한 코드로 만들어진 실제 DOM은 어떻게 볼 수 있을까?\n<br/>\n\n## DevTools\n\n우리가 브라우저로 소스를 열어서 `F12`버튼 또는 `Ctrl + Shift + i`를 누르게 되면 브라우저 DevTools이 나오게 된다. \n\n![dev_tools](https://user-images.githubusercontent.com/24274424/57984683-28868400-7a99-11e9-8d75-64216c78a9c7.gif)\n<br/>\n\n### Element Tab\n\nElement가 실제로 그려진 DOM Tree를 볼 수 있는 곳으로 **Element의 스타일 이벤트 등을 볼 수 있으며 실제로 조작을 하면서 변화를 확인해 볼 수 있다.**\n<br/>\n\n### Console Tab\n\nJavaScript를 사용해서 DOM을 조작할 수 있다. 실제로 JavaScript 엔진을 사용해서 테스트를 해보고 싶을 때 많이 사용하는 공간으로 IntelliSense를 보는 공간으로도 사용 가능하다.\n\n브라우저에서 테스트시 원하는 Element를 JavaScript로 찾기란 어렵다. 이에 Element Tab에서 해당 Element를 클릭 후 Console 창에서 `$0`으로 호출하여 바로 확인이 가능하다.\n\n기본적으로 브라우저에서 클릭 된 history를 보관하고 있어 이전에 선택한 Element를 다시 가져올 수 있다.\n\n![devtools2](https://user-images.githubusercontent.com/24274424/57984684-291f1a80-7a99-11e9-95a2-24a9d55afe10.gif)\n\n---\n\n#### Reference\n\n- [introduction to the dom](https://www.digitalocean.com/community/tutorials/introduction-to-the-dom)\n- [What’s the Document Object Model, and why you should know how to use it.](https://medium.freecodecamp.org/whats-the-document-object-model-and-why-you-should-know-how-to-use-it-1a2d0bc5429d)\n- [What is the DOM?](https://css-tricks.com/dom/)\n- W3C: [What is the Document Object Model?](http://www.w3.org/TR/DOM-Level-2-Core/introduction.html)\n- MDN: [Introduction - Document Object Model](https://developer.mozilla.org/en-US/docs/DOM/DOM_Reference/Introduction)\n- Wikipedia: [Document Object Model](http://en.wikipedia.org/wiki/Document_Object_Model)"
  },
  {
    "path": "HTML/HTML-Templating.md",
    "content": "# HTML Templating\n\n서버에서 데이터를 받아온 뒤, DOM 트리에 추가하거나 삭제하거나 교체할 경우가 생길 수 있다. 이러한 작업이 반복적이고(특히 AJAX를 사용할 때) 매번 필요한 태그가 비슷하다면, 즉 구조가 비슷한데 데이터만 다를경우 **templating**이 효율적인 방법일 수 있다.\n\n<br/>\n\n**Templating**은 HTML과 데이터를 합쳐서 웹 화면에 출력을 해주는 것이다. 이 작업은 클라이언트에서 할 수도 있고 서버에서 할 수도 있다.\n> 클라이언트에서 html을 그리는 것을 CSR(Client-Side Rendering ), 서버에서 그리는 것을 SSR(Server-Side Rendering)이라고 한다.<br/>참고 - [서버 사이드 렌더링(SSR)](https://github.com/Im-D/Dev-Docs/blob/master/Performance/%EC%84%9C%EB%B2%84%20%EC%82%AC%EC%9D%B4%EB%93%9C%20%EB%A0%8C%EB%8D%94%EB%A7%81(SSR).md#%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8-%EC%82%AC%EC%9D%B4%EB%93%9C-%EB%A0%8C%EB%8D%94%EB%A7%81-vs-%EC%84%9C%EB%B2%84-%EC%82%AC%EC%9D%B4%EB%93%9C-%EB%A0%8C%EB%8D%94%EB%A7%81)\n\n슬라이드를 만든다고 생각해보자, 버튼을 누르면 그림이 바뀌어야 한다.\n\n![HTML-Templating1](../assets/images/HTML-Templating1.png)\n\n이 때 그림을 미리 불러와서 저장해두는 것이 아니라, 미리 만들어진 HTML 양식 안에 서버에서 불러오는 데이터를 넣어주는 식이다.\n\n<br/>\n\n## 템플릿과 데이터 결합\n\n![HTML-Templating2](../assets/images/HTML-Templating2.png)\n\n위의 예시를 코드로 표현하면 아래와 같을 것이다.\n\n```js\nvar html = \"<li><h4>{title}</h4><p>{content}</p><div>{price}</div></li>\";\nvar resultHTML = html\n  .replace(\"{title}\", data.title)\n  .replace(\"{content}\", data.content)\n  .replace(\"{price}\", data.price);\n```\n\n저장해둔 템플릿을 이런 식으로 처리할 수 있는데, 데이터가 여러 개라면 루프를 이용하여 처리할 수도 있다.\n\n> 참고 - [JavaScript Templating Without a Library](https://jonsuh.com/blog/javascript-templating-without-a-library/)\n\n또한, 처리해야 하는 양이 너무 많다면 서버에서 처리한 뒤 가져오는 것도 방법이 될 수 있다.\n\n<br/>\n\n## 템플릿 보관\n\n위와 같이 자바스크립트에 HTML을 직접 보관하는 것은 좋지 않은 방법이다.\n\n이외에 템플릿을 보관할 수 있는 두 가지 방법이 있다.\n\n1. 서버에서 file에 보관하고, Ajax로 요청해서 불러온다.\n2. HTML 코드 안에 숨겨둔다.\n\n<br/>\n\n템플릿이 많고 복잡할 경우 1번의 방법을 사용하는 것이 좋을 것이다. 하지만, 간단한 템플릿의 경우 HTML 코드 안에서 숨겨서 사용할 수도 있다.\n\n<br/>\n\n`<script>` 태그의 `type`이 **javascript 가 아니면, 렌더링 하지 않고 무시한다.** 이를 이용해 템플릿을 숨겨둘 수 있다.\n\n```html\n<script id=\"item\" type=\"text/template\">\n  <li>\n    <h4>{title}</h4>\n    <p>{content}</p>\n    <div>{price}</div>\n  </li>\n</script>\n```\n\n가져올 때는 이렇게 하면 된다.\n\n```js\nvar html = document.querySelector(\"#item\").innerHTML;\n```\n\n또한, 특정 부위에 넣고 싶으면 `insertAdjacentHTML` 을 사용할 수도 있다.\n\n<br/>\n\n## Template 태그\n\nHTML5 에서는 `<template>` 태그가 추가됐다.\n\n```html\n<template>\n  <li>\n    <h4 id=\"title\" />\n    <p id=\"content\" />\n    <div id=\"price\" />\n  </li>\n</template>\n```\n\n<br/>\n\n`<script>` 로 넣는 것과 차이점은 텍스트가 아닌, **element** 로 보관이 된다. 따라서 `innerHTML` 을 사용하지 않아도 자식 요소를 넣을 수 있기 때문에 보다 안전하다. 하지만, 브라우저 지원이 한정적이다.\n\n![HTML-Templating3](../assets/images/HTML-Templating3.png)\n\n> 템플릿 태그는 HTML태그로 인식되지만, 활성화 되지 않으면 렌더링되지 않는다. 이 때, 활성화는 `importNode()` 혹은 `cloneNode()` 등을 사용한 경우와 같이 **deep copy** 를 하여 템플릿의 `.content` 를 복사하는 경우를 말한다. 이 때, `.content` 속성은 템플릿의 내부를 포함하는 읽기 전용의 DocumentFragment 이다.\n> ```js\n> <template>\n>   <h2>Template</h2>  \n> </template>\n>\n> <script>\n> // 1. importNode 사용\n>  var t = document.querySelector(\"#myTemplate\");\n>  var clone = document.importNode(t.content, true);\n>  document.body.appendChild(clone);\n>\n> // 2. cloneNode 사용> \n>   var temp2 = document.getElementsByTagName(\"template\")[0];\n>   var clone2 = temp.content.cloneNode(true);\n>   document.body.appendChild(clone2);\n> </script>\n> ```\n\n<br/>\n\n## Template 리터럴\n뿐만 아니라, ES6의 템플릿 리터럴을 사용하여 템플레이팅 작업을 할 수 있다.\n\n참고 - [Tagged Template Literals](https://github.com/Im-D/Dev-Docs/blob/master/ECMAScript/Tagged_Template_Literals.md)\n\n---\n\n#### References\n\n- [부스트코스 - HTML templating](https://www.edwith.org/boostcourse-web/lecture/16761/)\n- [부스트코스 - HTML templating 실습](https://www.edwith.org/boostcourse-web/lecture/16761/)\n- [HTML <template> Tag](https://www.w3schools.com/tags/tag_template.asp)\n- [HTML's New Template Tag](https://www.html5rocks.com/ko/tutorials/webcomponents/template/)\n"
  },
  {
    "path": "HTML/Head_Meta.md",
    "content": "# **Head Meta**\n\n**HTML** `<meta>` 요소는...\n<br/>\n\n`<base>, <link>, <script>, <style>` 또는 `<title>`과 같은 다른 메타관련 요소로 나타낼 수 없는 메타데이터를 나타낸다.\n<br/>\n\n메타데이터는 **데이터를 설명하는 데이터**이다.\n<br/>\n\n## 인코딩 셋팅\n\n`<meta charset=\"utf-8\">`\n<br/>\n\n이 요소는 문서의 `character incoding` 에 대해서 간단히 표시한다.\n당연히 요즘에는 `utf-8` 을 사용하는게 좋다. 그렇게 대부분이 사용한다.\n<br/>\n\n```html\n// html5이전\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=IANAcharset\">\n```\n\n**Naver와 Google** 역시 `<head>` 최상단에 선언하고 있다.\n<br/>\n\n많은 `<meta>` 요소가 `name` 과 `content` 속성을 가진다:\n<br/>\n\n- `name` 은 메타 요소의 형태를 알려준다. 이것이 어떤 타입의 정보를 가지고 있는지.\n  - 이 속성은 문서 레벨의 메타데이터의 이름을 정의한다. `itemprop, http-equiv` 또는 `charset` 속성 중 하나라도 설정이 된 경우에는 설정할 수 없다.\n  - `application-name` : 웹 페이지 내에서 실행될 어플리케이션의 이름을 정의한다.\n  - `author` : 문서의 작성자를 정의한다.\n  - `description` : 페이지의 내용에 대한 짧고 정확한 요약을 담고 있다. Firefox나 오페라와 같은 여러 브라우저에서는 이를 즐겨 찾기 페이지의 기본 설명으로 사용한다.\n  - `generator`:페이지를 생성한 소프트웨어의 식별자를 담고 있다.\n  - `keywords` : 콤마(`,`)로 구분된 페이지의 내용과 관련된 단어를 담고 있다.\n  - `referrer` : 문서에서 전송된 요청에 첨부된 `HTTP` 헤더의 참조자(Referer)를 제어한다.(Naver : 문서의 Origin을 전송)\n  - `creator` : 문서를 만든사람을 정의.\n  - `googlebot` : `robot`과 비슷하지만 구글봇이 수집한다.\n  - `publisher` : 문서 게시자의 이름을 정의.\n  - `robots` : 협동 크롤러 또는 `robot`이 페이지와 함께 사용해야하는 동작을 정의.\n  - `slurp` : 야후 검색을 위한 크롤러에서 사용\n  - `viewport` : 뷰포트의 초기 크기 크기에 대한 힌트를 제공한다. 휴대 기기에서만 사용됨.\n\n- `http-equiv` : 이 속성은 속성의 이름(`http-equiv(alent)`)에서 알 수 있듯이, `HTTP` 헤더의 이름을 값으로 가질 수 있다. 이 속성의 값으로 서버나 사용자 에이전트의 작동방식을 변경할 수 있는 지시를 정의할 수 있다. 지시 값은 `content` 속성 안에 정의하는데 다음 중 하나 일 수 있다:\n  - `content-security-policy` :  이 값을 이용해 현재 페이지에 대한 컨텐트 정책(content policy)를 정의할 수 있다. 컨텐트 정책은 주로 허용된 `server origins`과 `script endpoints`를 명시함으로써 `cross-site scripting` 공격을 막는 것을 돕는다.\n  - `refresh`\n    - `content` 속성에 양의 정수 값이 설정된 경우, 페이지가 재로딩될 때까지의 시간(초)을 의미한다.\n    - `content` 속성이 양의 정수 값을 가지고 그 값의 뒤에 `;url=` 문자열과 함께 유효한 URL이 설정된 경우, 다른 페이지로 리디렉션될 때까지의 시간(초)을 의미한다.\n  - `X-UA-Compatible` : 마이크로소프트는 `X-UA-Compatible` 태그로 웹의 호환성을 지정할 수 있도록 하였다.(익스플로러 버전별 호환성 쿼크 설정)\n\n- `content` : 이 속성은 `http-equiv` 또는 `name` 속성 중 어떤 것이 사용되느냐에 따라 해당 속성의 값을 갖는다.\n\n```html\n<meta name=\"author\" content=\"Chris Mills\">\n<meta name=\"description\" content=\"The MDN Learning Area aims to provide\ncomplete beginners to the Web with all they need to know to get\nstarted with developing web sites and applications.\">\n```\n\n## 특정사이트에 사용하는 메타태그\n\n웹 사이트에서 볼 수있는 기능들은 특정 사이트 (예 : 소셜 네트워킹 사이트)에 사용할 수있는 특정 정보를 제공하도록 설계된 독점 제작물이다.\n\n### Facebook\n\n`Open Graph Data` 는 `Facebook`이 웹 사이트에 더 풍부한 메타 데이터를 제공하기 위해 발명한 메타 데이터 프로토콜이다.\n\n```html\n<meta property=\"og:image\" content=\"https://developer.cdn.mozilla.net/static/img/opengraph-logo.dc4e08e2f6af.png\">\n<meta property=\"og:description\" content=\"The Mozilla Developer Network (MDN) provides\ninformation about Open Web technologies including HTML, CSS, and APIs for both Web sites\nand HTML5 Apps. It also documents Mozilla products, like Firefox OS.\">\n<meta property=\"og:title\" content=\"Mozilla Developer Network\">\n```\n\n### Twitter\n\n```html\n<meta name=\"twitter:title\" content=\"Mozilla Developer Network\">\n```\n\n---\n\n#### Reference\n\n- [MDN](https://developer.mozilla.org/ko/docs/Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML)\n- [MDN](https://developer.mozilla.org/ko/docs/Web/HTML/Element/meta)"
  },
  {
    "path": "HTML/Standard&QuirksMode.md",
    "content": "# 표준모드 :vs: 쿽스모드\n\n## 들어가기에 앞서...\n\n1. **DTD(Document Type Definition)**\n2. 표준모드와 쿽스모드의 차이점은\n\n<br/>\n\n```html\n<!DOCTYPE ... > //예시\n```\n\n<br/>\n\n## DTD란\n\n> 문서 형식 정의(DTD:Document Type Definition)는 마크업 문서의 요소와 속성등을 해석하는 기준을 명시하는 것입니다.\n<br/>\n\n전체적인 Markup 문서를 **어떤 형식에 맞춰서** 해석해야하는지 명시를 해준다는 것이다.\n<br/>\n\n문서 형식에는 크게 **HTML5, XHTML, HTML** 의 3가지가 존재한다.\n<br/>\n\n이전 버전의 **HTML(HTML2 ~ HTML4)** 은 [SGML](https://ko.wikipedia.org/wiki/SGML)에 기반을 두어 만들어졌기 때문에 상세한 `DTD` 참조가 필요하며, 이 때문에 `DOCTYPE` 선언을 하려면 **공개 식별자**와 **시스템 식별자**가 포함된 긴 문자열을 작성해야 한다.\n\n:point_right: `HTML 4.01 Strict` 모드로 문서 형식을 정의할 경우의 예\n\n```html\n<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n\nPUBLIC \"-//W3C//DTD HTML 4.01//EN\" //공개 식별자\n\"http://www.w3.org/TR/html4/strict.dtd\" //시스템 식별자\n```\n\n<br/>\n\n## **XHTML :vs: HTML5**\n\n### **SGML과 XML**\n\n`SGML(Standard Generalized Markup Language)`은 문서용 마크업 언어를 정의하기 위한 메타 언어이다.\n<br/>\n\n`SGML`은 정부나 항공우주 기업의 대규모 계획 사업 과정에서 기계 판독형(machine-readable) 문서를 공유할 목적으로 설계되었다.\n<br/>\n\n`SGML`은 인쇄와 출판 산업에 광범위하게 사용되었지만, 너무 복잡한 이유로 소규모 범용 목적으로 사용하는데 걸림돌이 되었다.\n<br/>\n\n`XML`은 `SGML`에서 파생된 언어이다. `SGML`을 단순화하려는 시도로 시작되어, `XHTML`, `RSS` 등을 포함해 여러 방면에서 응용되고 있다.\n<br/>\n\n### **XHTML**\n\n`XHTML(Extensible Hypertext Markup Language)`은 `HTML`과 동등한 표현 능력을 지닌 마크업 언어로, **`HTML`보다 엄격한 문법을 가진다.**\n<br/>\n\n`HTML`이 `SGML`의 응용인 데 반해,  `XHTML`은 `SGML`의 제한된 부분집합인 **`XML`의 응용이다.**\n<br/>\n\n`XHTML` 문서는 하나의 `XML` 문서로서 문법적으로 정확해야 하기 때문에, `HTML`과 달리 **표준 `XML` 라이브러리를 이용한 자동화된 처리가 가능하다.**\n<br/>\n\n`XHTML 1.0`은 2000년 1월 26일, `W3C(World Wide Web Consortium: 월드 와이드 웹 콘서시엄)`의 권고안이 되었다.\n<br/>\n\n### **XHTML vs HTML 5**\n\n2004년 W3C 회의에서 모질라 재단과 오페라 소프트웨어가 새로운 **HTML 표준**을 제안했지만, W3C에 의해 \"웹의 혁명을 위한 기존의 지향점에 위배된다\"고 거절당했다.\n<br/>\n\n이에 인터넷 익스플로러를 제외한 애플, 모질라, 오페라가 `WHATWG`라는 새로운 웹 표준 기관을 설립하고 `HTML5` 표준을 제정했다.  \n<br/>\n\n비슷한 시기에 `XHTML 2.0`이 나왔지만 기존의 표준과 너무 동떨어져서 개발자들에게 널리 사용되지 않았고, 2009년 폐기되기에 이르렀다.\n<br/>\n\n2014년부터 `HTML5`가 새로운 권고안이 되었다.\n<br/>\n\n### **HTML5**\n\nHTML5는 HTML의 완전한 5번째 버전\n<br/>\n\nHTML5는 HTML 4.01, XHTML 1.0, DOM 레벨 2 HTML에 대한 차기 표준 제안.\n<br/>\n\n비디오, 오디오 등 다양한 부가기능과 최신 멀티미디어 콘텐츠를 액티브X 없이 브라우저에서 쉽게 볼 수 있게 하는 것을 목적으로 한다.\n<br/>\n\n## DTD를 정의하지 않으면 쿽스 모드(Quirks mode)로 렌더링된다\n\n`DOCTYPE` 선언이 존재하지 않거나 잘못 적혀있을 경우, 웹 브라우저는 웹문서를 쿽스 모드로 해석한다.\n<br/>\n\n쿽스 모드란 ***오래된 웹 브라우저를 위하여 디자인된 웹 페이지의 하위 호환성을 유지하기 위해 웹 브라우저가 웹문서를 해석하는 방식*** 입니다.\n<br/>\n\n반대로, 표준 모드(Standards Mode)는 W3C나 IETF(국제 인터넷 표준화 기구)의 표준을 엄격히 준수하여 문서를 해석한다.\n<br/>\n\n쿽스 모드에서는 같은 코드라도 웹 브라우저마다 서로 다르게 해석하므로 전혀 다른 결과물을 보여주게 된다.\n<br/>\n\n오래된 브라우저의 경우 HTML과 CSS 명세(W3C 표준)가 완성되기도 전에 개발되어서 표준에 부응하지 못하였고, 그를 위해 쿽스 모드가 오래된 브라우저의 행동을 모방하도록 만들어진 것이다.\n<br/>\n\n## 표준 모드와 쿽스 모드의 차이\n\n비표준 모드 :  Quirks mode, <br/>\n표준 모드 :  Standards mode, <br/>\n거의 표준 모드 : almost standards mode, 엄격 모드 : strick mode <br/>\n<br/>\n\n> 거의 표준 모드는 표준 모드와 한가지만 빼고 동일함. table 셀에서 비표준모드로 실행하고, 그외 나머지는 표준을 따름 따라서, 테이블 안에 조각난 이미지를 넣을 때, 표준 모드보다 비표준 모드, 거의 표준 모드일 때 이미지 간격이 떨어질 가능성이 덜함\n<br/>\n\n### 표준모드와 쿽스모드가 다르게 나타나는 부분(넘어가도 됨)\n\nIE 박스 모델 버그\n\n- 비표준 모드:  width 계산 시, padding, border 를 포함 함.\n- 표준 모드: width 계산 시, padding, border를 포함하지 않음.\n\n인라인 요소의 수직 정렬\n\n- 비표준 모드: 박스의 border bottom에 맞추어 이미지를 정렬\n- 표준 모드: baseline에 맞추어 정렬\n\ntable 안의 font size 상속\n\n- 비표준 모드: table 안에서 텍스트는 기본 font size를 상속하지 않음\n- 표준 모드: table 안에서의 텍스트는 기본 font size값을 상속 함.\n\n<br/>\n\n## 모든 Doctype 선언 방법\n\n### HTML 5\n\n```html\n<!DOCTYPE html>\n```\n\n### HTML 4.01 Strict\n\n- HTML 4.01 는 세가지 DTD가 있는데,  DTD는 지원하는 요소에 따라 다름\n\n1. HTML 모든 요소와 속성을 포함.\n2. 표현적인 것과 퇴화 요소는 포함하지 않음.\n3. Font 태그 지원 안 함. Frameset 지원 안 함.\n\n```html\n<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n```\n\n### HTML 4.01 Transitional\n\n1. HTML 모든 요소와 속성 포함\n2. 표현적인 것과 퇴화 요소도 포함 (Font 태그 지원)\n3. Frameset 지원 안 함.\n\n```html\n<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n```\n\n### HTML 4.01 Frameset\n\n1. Strict DTD에 있는 것\n2. 퇴화 요소와 속성(대부분 시각적 표현에 관한 것).\n3. Transitional DTD + Frameset을 허용함.\n\n```html\n<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Frameset//EN\" \"http://www.w3.org/TR/html4/frameset.dtd\">\n```\n\n### XHTML 1.0 Strict\n\n1. HTML모든 요소와 속성을 포함\n2. 표현적인 것과 퇴화 요소는 포함하지 않음\n3. Font 태그 지원 안함. Frameset 지원 안 함.\n4. **Markup은 잘 조직된 XML로 쓰여져야 함.**\n\n```html\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n```\n\n### XHTML 1.0 Transitional\n\n1. HTML모든 요소와 속성을 포함.\n2. 표현적인 것과 퇴화 요소는 포함( font 태그 지원)\n3. Frameset 지원 안 함.\n4. **Markup은 잘 조직된 XML로 쓰여져야 함.**\n\n```html\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n```\n\n### XHTML 1.0 Frameset\n\n1. HTML모든 요소와 속성을 포함.\n2. 표현적인 것과 퇴화 요소는 포함( Font 태그 지원)\n3. Frameset 지원.\n4. **Markup은 잘 조직된 XML로 쓰여져야 함.**\n\n```html\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Frameset//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd\">\n```\n\n### XHTML 1.1\n\n1. XHTML 1.0 Strict와 같음.\n2. Modules을 추가하도록 허용\n\n예를 들어 동아시아언어를 위한 ruby 지원 함.\n\n```html\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n```\n\n<br/>\n\n## 정리\n\n- Doctype이 무엇을 하는 것인가요?\n\n:point_right: 문서 형식을 정의하기 위한 구문.\n\n- HTML5를 사용한다면\n\n:point_right: Example\n\n```html\n<!DOCTYPE html>\n```\n\n이것만 쓰면 됨.\n\n- 표준모드(standards mode)와 쿽스모드(quirks mode)의 다른 점은 무엇인가?\n\n:point_right: 표준모드는 W3C나 IETF의 표준을 준수하여 웹페이지를 렌더링한다.\n\n쿽스모드는 오래된 웹 브라우저에서도 호환되도록 비표준적인 방법의 `CSS`를 적용해 웹페이지를 렌더링하며, 렌더링 방식은 브라우저에 따라 다르다.\n<br/>\n\n`DOCTYPE` 선언이 존재하지 않거나 잘못 적혀있을 경우 브라우저는 웹페이지를 쿽스모드로 해석한다.\n\n---\n\n#### Reference\n\n- [DTD.md](https://gist.github.com/crispynap/09a560619431c599ea3be3553b102791)\n- [비표준 모드quirks mode, 표준 모드 standards mode 차이와 DOCTYPE](http://aboooks.tistory.com/m/169)\n"
  },
  {
    "path": "HTML/WebM&WebP.md",
    "content": "# WebM & WebP\n\n구글에서 만들고 많이 사용되고 최근 많은 사이트에서 최적화의 방안으로 많이 사용되는 WebP에 대해서 정리를 하였다.\n\n구글은 이전에 Media 포맷도 만들었다는 사실을 알게되었다. WebP에 대해서 알아보기 전에 동영상 포맷 1개, 이미지 포맷 1개를 알아보자.\n\n동영상과 이미지 포맷을 알아보기 전에 알아야하는 선행 지식에 대해서 간단히 알아보자.\n\n## 컨테이너 포맷, 비디오 코덱, 오디오 코덱\n\n우리가 아는 동영상은 영상과 소리의 정보를 가진 파일을 가리킨다. \n\n### 컨테이너 포맷\n\n동영상 파일을 말할 때는 컨테이너 포맷, 비디오 코덱, 오디오 코덱에 대한 정보를 모두 이야기해야한다. 파일 확장자만 이야기하면 안된다.\n\n![컨테이너_포맷](https://user-images.githubusercontent.com/24274424/79058465-815e9c80-7ca9-11ea-9775-3938d6ad4664.jpeg)\n\n위의 그림은 mkv파일을 그림으로 그린 것이다.\n\n컨테이너 포맷은 비디오와 오디오를 담아주는 상자라고 생각하면 된다. \n그림에서는 비디오는 x264코덱으로 만들어졌고, 오디오는 DTS코덱으로 만들어졌다. 이처럼 컨테이너는 비디오와 오디오를 하나의 파일로 만드는 역할을 하는 것이다.\n\n우리가 흔히 보는 것은 확장자를 보는 것이다. 하지만 동영상을 판단할 때 확장자를 보아서는 단지 컨테이너 상자가 무엇인지 알 수 있을 뿐이지, 상자안에 있는 비디오와 오디오가 어떤 코덱으로 만들어졌는지는 모르는 것이다.\n\navi, mkv, asf, mp4, mov등은 모두 컨테이너 포맷을 가리키는 파일 형식인 것이다.\n컨테이너를 포함한 비디오와 오디오를 만드는 과정을 인코딩이라고하며, 코덱이 담당한다.\n비디오와 오디오를 재생하는 과정을 디코딩이라고 하며, 이 역시 코덱이 담당한다.\n\n만약 동영상이 재생되지 않는다면, 컨테이너 포맷을 확인하는 것도 중요하지만, 비디오 코덱과 오디오 코덱을 확인하는 것이 더 중요하다. \n\n### 코덱을 확인해보자.\n\n우리가 보는 파일에서 컨테이너 포맷은 바로 확인이 가능하지만, 비디오 코덱과 오디오 코덱은 파일명으로는 알 수 없다.\n\n개인적으로 Mac 유저로써 App Store를 찾아본 결과 Media Info라는 앱을 찾아서 설치하였다.\n\n아래는 임의의 영상 하나를 알아본 결과이다. \n\n![Video_info](https://user-images.githubusercontent.com/24274424/79058627-334a9880-7cab-11ea-9962-e2c79d7f127b.png)\n\n![Audio_info](https://user-images.githubusercontent.com/24274424/79058628-3a71a680-7cab-11ea-962d-2c94b7318b16.png)\n\n## WebM\n\n구글에서 지원하고 개발하는 오픈소스 동영상 포맷이다.\n구글이 VP8을 개발한 On2 테크놀로지스를 인수하면서 함께 발표하였다. 파일 확장자(컨테이너 포맷)는 `.webm`을 사용하며, 이름처럼 Web에서 최적화된 미디어 포맷이기 때문에 HTML5의 Video 태그를 이용해서 온라인에서 재생할 수 있다. 비디오 코덱은 VP8, VP9, AV1을 지원하며, 오디오 코덱은 Vorbis, Opus를 사용할 수 있다.\n\n각각의 코덱에 대한 정보를 서술하기에는 너무 장황하여 아래 링크로 대체한다.\n\n- [VP8](https://namu.wiki/w/VP8)\n- [VP9](https://namu.wiki/w/VP9(비디오%20코덱))\n- [AV1](https://namu.wiki/w/AV1)\n- [Vorbis](https://namu.wiki/w/Vorbis)\n- [Opus](https://namu.wiki/w/Opus(오디오%20코덱))\n\n이 컨테이너에서 사용되는 비디오 코덱과 오디오 코덱 전부 무료이기 때문에 유튜브에서는 일부 사용되고 있으며, 지원하지 않는 브라우저일 경우에만 서버에서 보내주는 방식이다.\n\n[![image](https://user-images.githubusercontent.com/24274424/79058737-9ab51800-7cac-11ea-9ad4-c7f4a3d0da69.png)](https://caniuse.com/#search=webm)\n\n관련 코덱이 완전 무료라는 점에서 사용량이 조금씩 늘었다. GIF와 비교해 가장 큰 이점은 바로 압축률이다. 동일한 화질의 경우 WebM의 용량이 1/10가량 적게 나온다.\n\n이에 넷플릭스에서도 사용하고 유튜브에서도 사용되었으나 현재는 다른 포맷을 사용하고 있다.\n\n### 실제로 유튜브에서 사용하는 컨테이너 및 코덱\n\n유튜브에서는 화질에 따라 다르게 가져가는 정책을 채택하고 있다. 저화질에서는 webm을 사용하며 고화질에서는 MP4를 사용한다고 한다. 내부적인 비디오 코덱은 AV1이다.\n\n## WebP\n\n2010년 구글에서 만든 이미지 포맷이다. 이름처럼 Web을 위해서 만들어진 이미지 포맷이다. 기존의 이미지 포맷인 GIF, PNG, JPEG으로 삼분되어 있었던 진영을 WebP는 이 세가지 모두 포맷으로 전부 대체 가능하다.\n\nWebM과 동일하게 On2를 사들이고 나서 VP8 비디오 코덱의 기술에 기반한 영상 압축 방식을 사용했다.\n\n### 특징\n\n- 공식 홈페이지에 따르면 손실압축을 사용할 경우 JPEG 포맷보다 30% 정도 파일 크기가 작다고 한다. \n- 비손실 압축을 사용할 경우 PNG 포맷보다 20~30% 정도 파일 크기가 작아진다고 한다.\n- GIF을 대체 할 수 있는 애니메이션을 지원한다.\n- PNG 포맷처럼 알파채널을 지원한다.\n\n### 실제로 유튜브에서 사용하는 WebP\n\n1. 먼저 유튜브에 접속을 한다.\n2. 개발자도구를 연다.\n- <kbd>F12</kbd> \n- <kbd>Command</kbd>+<kbd>Option</kbd>+<kbd>i</kbd> \n\n![youtube_devtool](https://user-images.githubusercontent.com/24274424/79059098-08fbd980-7cb1-11ea-98b8-652f3b14b718.png)\n\n### 지원 브라우저\n\n[![image](https://user-images.githubusercontent.com/24274424/79058771-1fa03180-7cad-11ea-9cd3-0bcaf1a744d0.png)](https://caniuse.com/#search=webp)\n\n----\n\n#### Reference\n\n- [Can I use... Support tables for HTML5, CSS3, etc](https://caniuse.com/)\n- [WebP - 나무위키](https://namu.wiki/w/WebP)\n- [WebM - 나무위키](https://namu.wiki/w/WebM)\n- [동영상의 기본적인 이해 (컨테이너 포맷이란?, 동영상의 변환이란?)](https://m.blog.naver.com/PostView.nhn?blogId=dbfan24&logNo=10128721121&proxyReferer=&proxyReferer=https:%2F%2Fwww.google.com%2F)\n"
  },
  {
    "path": "HTML/input태그의_value바꾸기(input태그의_dirty flag).md",
    "content": "# input태그의 value바꾸기(input태그의 dirty flag)\n\n`<input>`태그의 내용(value)이 변경되면 `setAttribute()`로 값을 변경하여도 브라우저 화면에 반영되지 않는다.\n\n```js\nfunction test() {\n  inputText.setAttribute(\"value\", \"test\");\n  console.log(\"test value: \"+inputText.value);\n  console.log(\"test default: \"+inputText.defaultValue);\n}\n```\n\n```html\n<input type=\"text\" id=\"inputText\" name=\"testName\"> // 만약 텍스트박스에 무언가 입력한다면\n<input type=\"button\" value=\"test\" onclick=\"test()\">// 버튼을 눌러도 화면에 변화가 없다.\n```\n> [예시(codepen)](https://codepen.io/dae-hwa/pen/gJMwQq)\n\n<br/>\n\n## dirty value flag\n\n`<input>` element에 **dirty value flag(이하 더티 플래그)** 라는 속성이 있다. boolean 타입이고, **false가 초기값**이다. **value가 변경되면 true**로 바뀐다.\n\nvalue의 속성이 add, set, remove될 때, **더티 플래그의 값이 false인 경우 element의 값이 value값이 된다.** (더티 플래그가 true일 경우 element의 값이 value의 속성 값으로 설정되지 않는다.)\n\nvalue속성을 add, set, remove하는 것은 value의 `default value`프로퍼티를 변경하는 것이다. 즉, 더티 플래그가 **false인 경우 element의 default value의 값이 value 프로퍼티의 값이 된다.**\n\n```js\nfunction test() {\n  inputText.setAttribute(\"value\", \"test\");\n  console.log(\"test value: \"+inputText.value);\n  console.log(\"test default: \"+inputText.defaultValue);\n}\n```\n\n```html\n<input type=\"text\" id=\"inputText\" name=\"testName\"> // 만약 텍스트박스에 \"무언가\"를 입력한다면 \n                                                   // inputText의 defaultValue와 value프로퍼티의 값은 \"무언가\", \n                                                   // dirty value flag는 true로 변하게 된다.\n\n<input type=\"button\" value=\"test\" onclick=\"test()\">// 버튼을 클릭하면\n                                                   // inputText의 value 프로퍼티의 값은 여전히 \"무언가\"이지만,\n                                                   // default value는 test로 바뀐다.\n```\n> [예시(codepen)](https://codepen.io/dae-hwa/pen/RmRzzV)\n\n<br/>\n\n## .value\n\n더티 플래그가 true로 바뀌면, attribute를 바꾸는 방식으로 value프로퍼티의 값이 바뀌지 않는다. 이때, value 프로퍼티로 값을 직접 변경 할 수 있다.\n\n```\ndocument.getElementById(\"id\").value=\"new value\";\n```\n\nvalue 프로퍼티는 값을 가져올때(get) element의 현재 값을 반환하고, **새 값으로 설정(set; =연산자 사용)할 경우 더티 플래그가 true로 바뀐다.**\n\n```js\nfunction test() {\n  inputText.setAttribute(\"value\", \"test\");\n  console.log(\"test value: \"+inputText.value);\n  console.log(\"test default: \"+inputText.defaultValue);\n}\n```\n\n```html\n<input type=\"text\" id=\"inputText\" name=\"testName\">\n// test3 혹은 test4를 누르는 순간부터 dirty value falg는 true가 되고,\n// test1, test2를 눌러도 화면에 보이는 inputText의 값이 바뀌지 않는다.\n<input type=\"button\" value=\"test1(setAttribute)\" onclick=\"test1()\">\n<input type=\"button\" value=\"test2(setAttribute)\" onclick=\"test2()\">\n<input type=\"button\" value=\"test3(.value)\" onclick=\"test3()\">\n<input type=\"button\" value=\"test4(.value)\" onclick=\"test4()\">\n```\n> [예시(codepen)](https://codepen.io/dae-hwa/pen/WBxxKK)\n\n<br/>\n\nMDN Docs는 `setAttribute()`가 일관성 없이 동작할 수 있기 때문에 프로퍼티를 사용할 것을 권장한다.(e.g.`Element.value`)\n\n---\n\n#### Reference\n\n- [MDN docs - Element.setAttribute()](https://developer.mozilla.org/en-US/docs/Web/API/Element/setAttribute#Notes)\n- [W3C Recommendation,Forms](https://www.w3.org/TR/html5/sec-forms.html#input-dirty-value-flag)\n\n\n"
  },
  {
    "path": "HTML/preload&prefetch.md",
    "content": "# Preload, Preconnect, Prefetch\n\n## 브라우저는\n\n인터넷을 통해서 브라우저에 전송되는 모든 자원들이 동일하게 중요한 것은 아니다. \n\n브라우저들은 가장 중요한 리소스를 우선 로드(예: 스크립트나 이미지보다 CSS 우선)하기 위해 최선을 다해서 추측을 하고 가져오려고 노력한다.\n<br/>\n\n### 브라우저의 우선순위 기본값\n\n기본적으로 `head` 태그안에 있는 `script` 태그는 크롬에서 높은 우선 순위(가장 높은 CSS 다음이라고 함)로 로드된다. `defers` 속성이 있다면 `script` 태그가 낮음으로 우선 순위가 변경된다.\n\n![defer](https://user-images.githubusercontent.com/24274424/61136241-3a672f00-a4fe-11e9-8172-5aa84121752a.png)\n\n> defer를 사용하지 않는 경우\n\n![no-defer](https://user-images.githubusercontent.com/24274424/61136318-61256580-a4fe-11e9-9e56-4b4c05ed9367.png)\n\n> defer를 사용하는 경우\n\n우선 순위를 쉽게 볼 수 있는 곳은 Chrome Dev Tool Network이다.\n\n자신이 원하는 우선 순위와 다르게 우선 순위가 표시된 리소스를 찾았다면 어떻게 해야할까?\n\n오늘의 주제로 보면 세 가지 방법이 있다. \n\n리소스가 사용자 환경에 필수적이지만 너무 낮은 우선 순위로 로드된다면, preload나 preconnect 두 가지 방법 중 하나로 수정할 수 있고, 브라우저가 다른 모든 작업을 끝낸 후 일부 리소스를 가져오도록 하고 싶다면, prefetch를 사용하면 된다.\n<br/>\n\n## Preload\n\n- 기본형태\n\n```html\n<link rel=\"preload\">\n<link rel=\"preload\" as=\"script\" href=\"super-important.js\">\n<link rel=\"preload\" as=\"style\" href=\"critical.css\">\n```\n\n브라우저에게 로딩 중인 리소스의 유형을 알려줌으로써 올바르게 처리되도록 한다. 브라우저는 `as` 속성이 없을 경우 preload된 리소스를 사용하지 않는다. \n\n리소스는 다른 때와 동일한 우선 순위로 로드되지만, 브라우저에게 미리 알기 때문에 다운로드가 더 일찍 시작되는 것을 허용한다는 점이 다르다.\n\n**preload 방법에 있어서 실수로 두 번 가져오거나, 필요하지 않는 것을 가져오지 않도록 신중하게 작업을 해야한다.**\n\n`<link rel=\"preload\">`를 작성하였지만, 현재 페이지에서 3초 내에 사용되지 않으면 콘솔에 경고가 뜬다.\n\n![error](https://user-images.githubusercontent.com/24274424/61136703-06d8d480-a4ff-11e9-9af4-134c4a45f493.png)\n\n<br/>\n\n### Font(FOUC FOIT 방지)\n\nFOUC와 FOIT의 내용은 아래의 링크로 대체하겠습니다.\n\n> [FOUT, FOIT, FOFT](https://css-tricks.com/fout-foit-foft/)\n\nfont는 반드시 가져와야 하는 리소스의 좋은 예이다. font는 한 페이지가 로드하는 여러 CSS파일의 맨 아래에 위치하는 경우도 있다. \n\n사용자가 사이트의 텍스트 콘텐츠를 기다리는 시간을 감소시키고, 시스템 font와 선호 font가 충돌하여 발생하는 플래시를 방지하기 위해 `<link rel=\"preload\">`를 HTML에 사용하면 font가 필요하다는 것을 브라우저가 즉시 알 수 있다.\n\n```html\n<link rel=\"preload\">\n```\n\n여기서 `crossorigin`을 사용하는 것이 매우 중요하다. 이 속성가 없다면, 브라우저가 preload된 font를 무시하고 새로 가져온 항목이 그 자리를 차지한다. 통상 브라우저를 통해 익명으로 가져오며, preload 요청은 `crossorigin` 속성 사용을 통해서만 익명을 처리할 수 있기 때문이다.\n\n> crossorigin을 사용함으로써 CORS를 허용한다.\n> [CORS 허용](https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes)\n\n> Caution: Google Fonts와 같은 CDN을 사용 중이라면 미리 로딩한 font 파일이 CSS에 있는 것과 일치하는지 확인해야 한다. 유니코드 범위, 두께, 다양한 font로 인해 이 작업이 어려울 수 있다. font은 또한 정기적으로 업데이트될 수 있으며, 새로운 버전에 대해 CSS를 사용할 때 이전 버전을 미리 로드했다면 동일한 font을 두 번 다운로드하여 사용자의 대역폭을 낭비하는 결과를 낳게 될 수 있습니다. 손쉬운 유지관리를 위해 `<link rel=\"preconnect\">`를 대신 사용하는 것을 고려해 보세요.\n\n<br/>\n\n### CSS 및 자바스크립트 주요경로\n\n페이지 성능에 관해 이야기할 때의 중요한 개념으로 주요 경로라는 것이 있다. 주요 경로란 초기 렌더링 전에 반드시 로드되어야 하는 리소스를 일컫는다. 이러한 리소스(예를 들어 CSS)는 사용자 화면의 첫 픽셀을 얻는 데 매우 중요하다.\n\n이전에는 콘텐츠를 HTML에 인라인 처리하는 것이 권장되었다. 그러나 페이지 수가 많고 서버 측에서 렌더링되는 경우 이렇게 하면 바이트 낭비가 심해지게 된다. 주요 코드의 변경이 인라인 처리된 모든 페이지를 무효화하기 때문에 버전 관리도 더욱 어렵게 된다. \n\n`<link rel=\"preload\">`는 개별 파일 버전 관리 및 캐싱의 이점을 유지하면서도 리소스를 가능한 한 빠르게 요청하는 메커니즘을 선사한다.\n\n```html\n<link rel=\"preload\" as=\"script\" href=\"super-important.js\">\n<link rel=\"preload\" as=\"style\" href=\"critical.css\">\n```\n\n`preload` 이용에는 한가지 단점이 있다. 추가적인 왕복에 영향을 받는다는 것이다. 이러한 추가적인 왕복은 브라우저가 우선 HTML을 가져온 다음에야 다음 리소스에 대해 알 수 있다는 점에 기인한다.\n\n추가적인 왕복을 피하는 방법 중 하나는 HTML을 전송하는 것과 동일한 연결을 통해 선점적인 주요 자산을 첨부하는 경우, HTTP/2 푸시를 대신 사용하는 것이다. 이 방법을 이용하면 사용자의 브라우저가 HTML을 가져오고 주요 자산의 다운로드를 시작하는 사이의 다운타임이 없다. 그러나 **HTTP/2** 를 이용할 때는 주의해야 한다. 사용자의 대역폭 사용을 매우 강제적으로 제어하는 방법이며 브라우저가 이미 캐시에 있는 파일을 가져오지 않는 등의 자체 결정을 내릴 수 있는 여지를 거의 남기지 않기 때문이다.\n<br/>\n\n## Preconnect\n\n`<link rel=\"preconnect\">`는 **브라우저에 우리의 페이지가 다른 출발지에 연결하도록 구축되었다는 것과, 가능한 한 빠르게 처리를 시작하고자 한다는 것을 알린다.**\n\n느린 연결에서는 연결 구축에 보통 상당한 시간이 소요되며, 특히 보안 연결의 경우에는 DNS 룩업 리디렉션, 사용자의 요청을 처리하는 최종 서버로의 여러 차례 왕복이 관여할 수 있다. 이 모든 것을 미리 처리하면 대역폭 사용에 대한 부정적인 영향이 없이 사용자에게 애플리케이션이 빠르다는 인상을 줄 수 있다. 연결 구축에 걸리는 시간 대부분은 데이터 교환이 아니라 기다리는데 소요되기 때문이다.\n\n```html\n<link rel=\"preconnect\" href=\"https://example.com\">\n```\n\n위와 같은 경우는 [https://example.com에](https://example.com에) 연결하고 여기에서 콘텐츠를 가져오려 한다는 것을 알린다.\n\n`<link rel=\"preconnect\">`에는 꽤 적은 비용이 들긴 하지만 여전히 상당한 CPU 시간을 차지할 수 있으며, 보안 연결의 경우 더욱 유념해야한다. 이것은 특히 연결이 10초이내로 사용되지 않아 브라우저가 닫히면, 이전의 모든 연결 작업을 낭비하기 때문에 좋지 않다.\n<br/>\n\n### 사용 사례: 미디어 스트리밍\n\n연결 단계에서 시간을 절약하려 하지만 반드시 콘텐츠를 바로 가져올 필요는 없는 경우가 있다.\n\n페이지가 스트림된 콘텐츠를 처리하는 방법에 따라 스크립트가 로드되고 스트림을 처리할 준비가 될 때까지 기다리고 싶을 수 있다. preconnect는 일단 가져오기를 시작할 준비가 되면서 단일 왕복으로 대기 시간을 줄이는 데 도움이 된다.\n<br/>\n\n## Prefetch\n\n`<link rel=\"prefetch\">` 는 중요한 것이 더 빠르게 일어나도록 하는 것이 아니라 기회가 있으면 중요하지 않은 것을 먼저 발생시키려 한다는 점에서 위의 2개와 다르다.\n\n이 작업은 향후 탐색이나 사용자 상호작용에 필요할 수 있는 리소스를 브라우저에게 알림으로써 수행된다. 이러한 리소스는 현재 페이지가 로딩을 마쳤으며 사용가능한 대역폭이 있을 때 Chrome에서 가장 낮은 우선순위로 가져온다.\n\n즉 prefetch는 사용자가 다음에 할 행동을 선점하여 준비하는데 가장 적합하다는 것을 의미한다. 예를 들어 결과 목록에서 첫 번째 제품 상세 페이지를 가져오거나 페이지 번호가 있는 콘텐츠의 다음 페이지를 가져오는 것이 여기에 해당한다.\n\n```html\n<link rel=\"prefetch\" href=\"page-2.html\">\n```\n\n단, 미리 가져오기는 귀납적으로 작동되지 않는다. 위의 예에서 여러분은 HTML만 가져왔다. `page-2.html`에 필요한 리소스는 여러분이 명시적으로 미리 가져오지 않는 한 다운로드 되지 않는다.\n<br/>\n\n### 미리 가져오기는 재정의로 사용할 수 없음\n\n기존 리소스의 우선 순위를 낮추는 방식으로 `<link rel=\"prefetch\">`를 이용할 수 없다는 점을 아는 것이 중요하다. 다음 HTML에서 미리 가져오기에 `optional.css`를 선언하면 뒤따르는 `<link rel=\"stylesheet\">`의 우선 순위를 낮출 것이다.\n\n```html\n<html>\n  <head>\n    <link rel=\"prefetch\" href=\"optional.css\">\n    <link rel=\"stylesheet\" href=\"optional.css\">\n  </head>\n  <body>\n    Hello!\n  </body>\n</html>\n```\n\n그러나, 사실 이 방법은 스타일 시트를 두 번 가져오도록 하며, 미리 가져오기가 각각의 가져오기에서 실행될 때 한번은 가장 높은 우선순위 기본값, 다른 한 번은 가장 낮은 우선순위로 가져온다.\n\n![image](https://user-images.githubusercontent.com/24274424/61138686-e6ab1480-a502-11e9-9b84-3aa4e762d5dd.png)\n\n<br/>\n\n---\n\n#### Reference\n\n- [Link prefetching FAQ](https://developer.mozilla.org/ko/docs/Link_prefetching_FAQ)\n- [리소스 우선순위 지정 - 브라우저의 도움 받기](https://developers.google.com/web/fundamentals/performance/resource-prioritization?hl=ko)\n- [Preload, Prefetch And Priorities in Chrome](https://medium.com/@koh.yesl/preload-prefetch-and-priorities-in-chrome-15d77326f646)\n"
  },
  {
    "path": "HTML/웹 컴포넌트(Web Component).md",
    "content": "# 웹 컴포넌트(Web Component)\n\nHTML에서 제공하는 엘리먼트들은 브라우저와 운영체제에 따라 다르게 보이는 경우가 많다. 이를 해결하기 위해서는 외부 JS 라이브러리를 사용하는 것이 일반적인데 이 경우 문제는 다음과 같다.\n\n- JS 파일과 CSS 파일을 포함해야 하고 권장하는 마크업 구조를 따라가야 하기 때문에 **개발자의 능력에 따라 사용하기 어려울 수 있다.**\n- **라이브러리의 크기에 따라 실행 속도가 느려질 수 있다.**\n\n위와 같은 문제를 해결하기 위해 W3C에서 만든 것이 웹 컴포넌트(Web Component)다.\n\n웹 컴포넌트 명세에는 HTML템플릿(Template), HTML imports, 커스텀 엘리먼트(Custom Element), 섀도우 돔(Shadow DOM) 4가지가 있다.\n\n<br/>\n\n## HTML템플릿(Template)\n\n일반적인 JavaScript 컴포넌트는 문자열 형태로 템플릿을 가지거나, 사전에 특정 엘리먼트의 구조를 만드는 형식으로 많이 사용한다.\n\n웹 컴포넌트도 동일하게 특정 엘리먼트의 구조가 필요하며, 이 때 사용하는 것이 템플릿(Template)이다.\n\n```js\ndocument.querySelect('#target').innerHTML = [\n    '<div class=\"wrapper\">',\n    '<div class=\"content\">',\n    '<div> helloWorld </div>',\n    '</div>',\n    '</div>'\n].join('');\n```\n\n위의 코드는 `innerHTML`을 사용하여 동적으로 `HTML`엘리먼트를 추가하는 코드다. 위와 같이 작성하면 좀 더 직관적으로 코드를 작성할 수 있다. 하지만 반복적인 엘리먼트나 조건에 따라 다른 템플릿을 구현할 때 혹은 내부 엘리먼트에 접근할 때 불편한 점이 있다.\n\n```html\n<template>\n    <style>\n        /* styleSheet */\n    </style>\n    <div class=\"wrapper\">\n        <div class=\"content\">\n            <div> helloWorld </div>\n        </div>\n    </div>\n</template> \n```  \n\n`<template>` 태그에 있는 엘리먼트는 DOM의 구조를 가지고 있지만 렌더링되지 않으며 이미지와 같은 리소스 파일을 내려받지 않는다. 즉, `<template>`태그 내의 엘리먼트들은 사용되기 전까지는 파싱은 되나 렌더링되지 않는다. 활성화 되지 않은 하나의 **DOM chunk**라고 볼 수 있다.\n\nHTML템플릿(Template)은 웹 컴포넌트의 다른 명세 중 하나인 섀도우 돔(Shadow DOM)과 함께 사용했을 때 훨씬 더 유용하게 사용가능하다.\n\n<br/>\n\n## HTML imports\n\nHTML템플릿은 HTML로 작성되어야하기 때문에 컴포넌트를 제어하는 자바스크립트(컨트롤러)와 뷰에 해당하는 HTML이 분리되어야 한다. 컴포넌트를 분리했을 때, 재사용이 가능해야한다. HTML템플릿과 커스텀 엘리먼트로 구성된 컴포넌트를 재사용하기 위해서는 각각 HTML과 JS 파일 2개가 필요하다. 이러한 점은 하나의 모듈로서 컴포넌트로 만들기에 불편하다. 이를 해결한 것이 **HTML imports**다.\n\nHTML 템플릿이 새로운 템플릿을 만들게 해준다면, HTML imports는 다른 HTML 파일에서 템플릿을 가져오게 해준다.\n\nHTML imports는 HTML/CSS/JS를 묶음 형태로 사용하며 단일 URL로 호출한다. 단, 다른 도메인의 리소스를 로딩하기 위해서 [CORS](https://github.com/Im-D/Dev-Docs/blob/master/Security/CORS(Cross-Origin%20Resource%20Sharing).md) 활성화가 필요하다. \n\n```html\n<!-- main page -->\n<head>\n    <link rel=\"import\" href=\"bootstrap.html\">\n</head>\n```\n\n<br/>\n\n## 커스텀 엘리먼트(Custom Element)\n\n커스텀 엘리먼트는 개발자가 새로운 엘리먼트를 만드는 것과 같다. 커스텀 태그를 통해 엘리먼트를 생성할 수 있도록 해주며 엘리먼트를 상속하고 있어 `createElement` 메서드나 생성자로 만들 수 있다.\n\n```js\nclass ExpandingList extends HTMLElement {\n  constructor() {\n    super();\n\n    //엘리먼트 기능 작성\n    ...\n  }\n}\n```\n\n```js\ncustomElements.define('expanding-list', ExpandingList, { extends: \"ul\" });\n```\n\n위 코드는 커스텀 엘리먼트를 정의하는 방법이다. `expanding-list`라는 엘리먼트를 만들고 `ExpandingList`라는 클래스 오브젝트를 사용하며 `ul`엘리먼트를 상속받는다는 뜻이다.\n\n커스텀 엘리먼트의 클래스 오브젝트는 ES6의 `class`문법을 주로 사용한다.\n\nHTML표준에 정의되어 있지 않으면서, 커스텀 엘리먼트 이름 규칙에 맞지 않는 태그들에는 HTMLUnknownElement인터페이스가 할당된다.\n\n결과적으로 다음과 같이 사용할 것이다.\n\n```html\n<expanding-list>\n\n  ...\n\n</expanding-list>\n```\n\n<br/>\n\n## 섀도우 돔(Shadow DOM)\n\n섀도우 DOM은 DOM의 구조를 가지고 있으나 외부에는 노출되지 않은 DOM을 말하며, DOM의 구조를 캡슐화할 때 사용한다.\n\nWeb Component에서는 섀도우 DOM을 이용하여, 커스텀 엘리먼트를 설명할 때 말했던 클래스 오브젝트내의 기능을 정의한다.\n\n```js\nclass ExpandingList extends HTMLElement {\n  constructor() {\n    super();\n\n    // mode 속성이 open이면 외부에서 shadow DOM에서 접근 가능하며 closed라면 외부에서 접근이 불가능하다.\n    const shadowRoot = this.attachShadow({mode: 'open'});\n    \n    shadowRoot.innerHTML = `\n        ...\n    `;\n  }\n}\n```\n\n기존의 컴포넌트는 DOM 트리가 렌더링된 후, DOM 트리 전체를 변경하기 때문에 reflow나 repaint와 같은 비용이 발생한다. 하지만 섀도우 DOM을 사용하면 섀도우 호스트 즉, `expanding-list`를 만나는 순간 렌더링이 되기 때문에 리렌더링에 따른 비용을 줄일 수 있다.\n\n<br/>\n\n위에서 말했던 Web Component 명세를 적용하여 엘리먼트를 만들면 다음과 같다.\n\n```html\n<!-- nameTagTemplate.html -->\n<!-- HTMLTemplate을 이용하여 템플릿 엘리먼트 구현 -->\n<template id=\"nameTagTemplate\">\n<style>\n    .outer {\n      border: 2px solid brown;\n      background: red;\n    }\n    .name {\n      color: black;\n    }\n</style>\n<div class=\"outer\">\n  <div class=\"name\">\n    Bob\n  </div>\n</div>\n</template>\n\n<script>\nclass NameTag extends HTMLElement {\n    constructor() {\n        super();\n        // Shadow DOM에 NameTag Template 추가\n        const shadowRoot = this.attachShadow({mode: 'open'});\n        const template = document.querySelector('#nameTagTemplate');\n        const clone = document.importNode(template.content, true);\n        shadowRoot.appendChild(clone);\n    }\n}\n// name-tag라는 커스텀 엘리먼트 정의\ncustomElements.define('name-tag', NameTag);\n</script>\n```\n\n```html\n<!DOCTYPE html>\n<html lang=\"ko-KR\">\n  <head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">\n    <title>웹 컴포넌트</title>\n\n    <!-- HTML imports -->\n    <link rel=\"import\" href=\"./nameTagTemplate.html\">\n\n  </head>\n  <body>\n\n    <!-- 커스텀 엘리먼트  -->\n    <name-tag></name-tag>\n\n  </body>\n</html>\n```\n\n---\n\n#### Reference\n\n- [kyu.io - 웹 컴포넌트(4) — 템플릿 엘리먼트(Template Element)와 HTML Imports](https://kyu.io/%EC%9B%B9-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B84%E2%80%8A-%E2%80%8Atemplate-element-html-imports/)\n- [yamoo9/WebComponent](https://github.com/yamoo9/WebComponent)\n- [Naver D2 - 웹 컴포넌트](https://d2.naver.com/helloworld/188655)\n- [Custom Elements](https://www.html5rocks.com/en/tutorials/webcomponents/customelements/)\n"
  },
  {
    "path": "Java/ArrayList vs LinkedList 그리고 Vector.md",
    "content": "# ArrayList vs LinkedList 그리고 Vector\n\n`ArrayList`와 `LinkedList`는 `JCF(Java Collection Framework)`의 형태로 제공되며 `List` 인터페이스를 상속한다.\n\n## ArrayList\n\n`ArrayList`는 **데이터들이 순서대로 쭉 늘어선 배열의 형식**을 가지고 있으며 요소를 추가하거나 삭제 할 때는 이미 리스트의 크기가 정해져 있어서 **임시 배열을 생성해서 데이터를 복사**하는 방법을 사용한다.\n\n![array_list](/assets/images/array_list.png)\n\n`ArrayList`는 각 요소의 위치 값 즉, `index`를 가지고 있으므로 **해당 요소의 `index` 값을 통해 값에 접근**할 수 있다.\n\n<br/>\n\n## LinkedList\n\n`LinkedList`는 각 노드의 앞과 뒤에 있는 **노드의 주솟값으로 연결**되어 있어서 요소를 추가하거나 삭제 할 때는 앞과 뒤쪽 노드의 주솟값만 바꿔주면 된다.\n\n![linked_list](/assets/images/linked_list.png)\n\n`LinkedList`는 **앞의 요소부터 차례대로 노드가 참조하고 있는 주소 값을 찾아가야 하므로** 검색이 느리다.\n\n<br/>\n\n> 즉, 데이터의 삽입, 삭제에 대한 처리가 많으면 `LinkedList`가 성능 상 유리하고 데이터의 검색 즉, 참조 처리가 많으면 `ArrayList`를 사용하는 것이 유리하다.\n\n<br/>\n\n## Vector\n\n`Vector`의 기본적인 동작은 `ArrayList`와 동일하다. 하지만, 가장 큰 차이점은 동기화 처리에서 나온다.\n\n**멀티쓰레드 환경에서 데이터의 동기화 처리는 중요한 부분**이다.<br/> `동기화`는 복수의 쓰레드로부터 데이터의 추가나 삭제가 일어났을 때 내부의 데이터는 안전하게 처리되도록 하는 것이다.\n\n`Vector`의 경우 **무조건 동기화**처리를 한다. 즉, 싱글쓰레드 환경에서의 `Vector`는 `ArrayList`나 `LinkedList`보다 성능이 떨어진다.\n\n사실, Java 1.2 버전 이상부터의 `Vector`는 이전 버전과의 호환을 위해서 많이 쓰인다. 동기화 처리가 필요환 환경에서는 `Collection.synchronizedCollection(Collection c)`나 `synchronized List, Map`을 사용하는 것이 성능상 더 유리하다.\n\n<br/>\n---\n\n#### Reference\n\n- [자료구조: Linked List 대 ArrayList](http://www.nextree.co.kr/p6506/)\n- [ArrayList와 LinkedList의 차이](https://sung-studynote.tistory.com/49)\n- [Java Vector와 ArrayList, LinkedList의 차이점](https://seeit.kr/36)\n\n"
  },
  {
    "path": "Java/Comparable vs Comparator.md",
    "content": "# Comparable vs Comparator\n\n정렬을 위해서 사용하는 인터페이스들이다.<br/>\n`Comparable` 인터페이스는 정렬 기준을 설정할 클래스가 `Comparable` 인터페이스를 직접 상속해 `compareTo` 메소드를 오버라이딩 해야한. <br/>반면, `Comparator`는 직접 구현해서 `Arrays.sort()`나 `Collections.sort()` 같은 정렬 메소드에 추가 인자로 넘겨 정렬 기준을 직접 설정해 줄 수 있다.\n\n## Comparable\n\n정렬 기능을 사용하기 위해서는 비교를 위한 메소드(`compareTo`)가 정의되어 있어야 한다.<br/>\n자바에서 제공하는 자료형들은 **이미 해당 메소드가 정의되어 있지만, 사용자 정의 자료형의 경우에는 이를 따로 정의**해주어야 한다.<br/>\n`Comparable` 인터페이스에 추상 메소드인 `compareTo` 메소드가 선언되어 있으며, 사용자 정의 자료형의 비교를 원하는 경우 `Comparable` 인터페이스를 상속받아 구현하면 된다. \n\n```java\npackage testtest;\n\nimport java.util.*;\n\npublic class test2 {\n    public static void main(String[] args) {\n        List<Point> pointList = new ArrayList<>();\n        pointList.add(new Point(3, 5));\n        pointList.add(new Point(5, 2));\n        pointList.add(new Point(14, 23));\n        pointList.add(new Point(7, 10));\n        pointList.add(new Point(1, 9));\n        pointList.add(new Point(1, 14));\n        pointList.add(new Point(1, 7));\n        pointList.add(new Point(-2, 23));\n        pointList.add(new Point(12, 3));\n        Collections.sort(pointList);\n        \n        for(Point p : pointList) {\n        \tSystem.out.println(p);\n        }\n    }\n}\n\nclass Point implements Comparable<Point> {\n    private int x, y;\n\n\tpublic Point(int x, int y) {\n    \tthis.x = x;\n    \tthis.y = y;\n    }\n\n    /**\n     * compareTo() 구현\n     *\n     * 현재 객체 < 파라미터로 넘어온 객체: 음수 리턴\n     * 현재 객체 == 파라미터로 넘어온 객체: 0 리턴\n     * 현재 객체 > 파라미터로 넘어온 객체: 양수 리턴\n     * 음수 또는 0이면 객체의 자리가 그대로 유지되며, 양수인 경우에는 두 객체의 자리가 바뀐다.\n     */ \n    @Override\n    public int compareTo(Point p) {\n        if(this.x > p.x) {\n            return 1; // x에 대해서는 오름차순\n        } else if(this.x == p.x) { //x가 같을 경우\n            if(this.y < p.y) { // y에 대해서는 내림차순\n                return 1;\n            }\n        }\n        return -1;\n    }\n    \n    public String toString() {\n    \treturn String.format(\"(%d, %d)\", this.x, this.y);\n    }\n\n}\n\n/*  실행결과\n    (-2, 23)\n    (1, 14)\n    (1, 9)\n    (1, 7)\n    (3, 5)\n    (5, 2)\n    (7, 10)\n    (12, 3)\n    (14, 23)\n*/\n```\n\n<br/>\n\n## Comparator\n\n**정렬 가능한 클래스(Comparable 인터페이스를 구현한 클래스)들의 기본 정렬 기준과 다르게 정렬 하고 싶을 때** 사용하는 인터페이스 \n\n- 주로 익명 클래스로 이용\n- 기본적인 정렬 방법인 오름차순 정렬을 내림차순으로 정렬할 때 많이 사용\n\n```java\npackage testtest;\n\n//Main\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.awt.Point;\nimport java.util.Comparator;\n\npublic class test2 {\n\n\tpublic static void main(String[] args) {\n\t\tList<Point> pointList = new ArrayList<>();\n\t\tpointList.add(new Point(30, 50));\n\t\tpointList.add(new Point(40, 30));\n\t\tpointList.add(new Point(20, 10));\n\t\tMyComparator myComparator = new MyComparator();\n\t\tCollections.sort(pointList, myComparator); //Collections.sort()나 Arrays.sort() 메서드에 커스텀된 Comparator 객체를 추가 인자로 넘긴다.\n\t\t\n\t\tfor(Point p : pointList) {\n\t\t\tSystem.out.println(p.toString());\n\t\t}\n\t}\n}\n\n//MyComparotor 클래스(x 좌표를 기준으로 내림차순 적용)\nclass MyComparator implements Comparator<Point> {\n\n    /**\n     * compare() 구현\n     *\n     * 첫 번째 파라미터로 넘어온 객체 > 두 번째 파라미터로 넘어온 객체: 음수 리턴\n     * 첫 번째 파라미터로 넘어온 객체 == 두 번째 파라미터로 넘어온 객체: 0 리턴\n     * 첫 번째 파라미터로 넘어온 객체 < 두 번째 파라미터로 넘어온 객체: 양수 리턴\n     * 음수 또는 0이면 객체의 자리가 그대로 유지되고 양수이면 두 객체의 자리가 변경된다\n     * 비교하는 첫번째 객체의 위치에 따라 오름차순 내림차순으로 정렬할 수 있다\n\t */\n    @Override\n\tpublic int compare(Point p1, Point p2) {\n\t\tif (p1.x < p2.x) {\n\t\t\treturn 1;\n\t\t}else if(p1.x > p2.x){ \n\t\t\treturn -1;\n\t\t}else {\n\t\t\treturn 0;\n\t\t}\n\t}\n}\n\n//java.awt.Point[x=40,y=30]\n//java.awt.Point[x=30,y=50]\n//java.awt.Point[x=20,y=10]\n```\n\n```java\n//익명 클래스 이용\n\nimport java.awt.Point;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.List;\n\npublic class Main {\n\n\tpublic static void main(String[] args) {\n\t\tComparator<Point> myComparator = new Comparator<Point>() {\n\t\t\t  @Override\n\t\t\t  public int compare(Point p1, Point p2) { \n\t\t\t\t  if (p2.x > p1.x) {\n\t\t\t\t\t\treturn 1;\n\t\t\t\t\t}else if(p2.x < p1.x){ \n\t\t\t\t\t\treturn -1;\n\t\t\t\t\t}else {\n\t\t\t\t\t\treturn 0;\n\t\t\t\t\t}\n\t\t\t  }\n\t\t\t};\n\n\t\t\tList<Point> pointList = new ArrayList<>();\n\t\t\tpointList.add(new Point(20, 10));\n\t\t\tpointList.add(new Point(40, 10));\n\t\t\tpointList.add(new Point(30, 10));\n\t\t\tCollections.sort(pointList, myComparator);\n\t\t\t\n\t\t\tfor(Point m :pointList) {\n\t\t\t\tSystem.out.println(m.toString());\n\t\t\t}\n\n\t}\n\n}\n//java.awt.Point[x=40,y=10]\n//java.awt.Point[x=30,y=10]\n//java.awt.Point[x=20,y=10]\n```\n\n<br/>\n\n---\n\n#### Reference\n\n- [[Java] Comparable와 Comparator의 차이와 사용법](https://gmlwjd9405.github.io/2018/09/06/java-comparable-and-comparator.html)\n- [Comparable_Comparator](https://github.com/JHRla/SIST-TEAM01/blob/master/%EB%B0%9C%ED%91%9C%EC%9E%90%EB%A3%8C/Comparable_Comparator.md)\n\n"
  },
  {
    "path": "Java/Dependency Injection(DI).md",
    "content": "# Dependency Injection(DI)\nDependency Injection는 **Framework에 의해** 객체의 의존성이 주입되는 설계 패턴을 말한다.  \n개발자가 class를 만들고 어떤 의존성을 주입할 것인지 설정하면, Framework가 **객체를 생성**하고 **동적으로 의존성을 주입**하는 형태이다.\nSpring Framework에서는 **Spring container**가 이 역할을 한다.  \n\n**Spring Container**는 객체를 관리하는데, 이 객체를 **빈(bean)** 이라고 부른다.  \n그래서 스프링에서는 이 빈(bean)들을 관리한다는 의미로 컨테이너를 **빈 팩토리(Bean Factory)** 라고 부른다.   \n이렇게 오브젝트의 생성과 오브젝트 사이의 런타임 의존 관계를 설정하는 DI관점으로 볼 때는 컨테이너를 빈 팩토리라고 한다.   \n하지만 스프링의 DI container는 단순한 DI작업보다 더 많은 일을 한다. 그래서 DI기능에 엔터프라이즈 애플리케이션을 개발하는 데 필요한 여러 가지 컨테이너 기능을 추가하여 **애플리케이션 컨텍스트(Application Context)** 라고 부르기도 한다.   \n\n<br/>  \n\n## 강한 의존 관계 / 약한 의존 관계\n\n먼저 컨테이너를 사용하지 않은 코드를 작성하면 다음과 같다. \n```java\npublic class OracleDAO {\n    public void insert(){ }\n}\n\npublic class MySQLDAO {\n    public void insert(){ }\n}\n\npublic class Service {\n    OracleDAO dao = new OracleDAO();\n    dao.insert();\n}\n```\n`Service`클래스는 `OracleDAO`의 객체를 직접 생성하고 있다. 그런데 만약 `OracleDAO` 대신 `MySQLDAO`의 객체를 사용하고 싶다면, `Service`클래스의 `OracleDAO dao = new OracleDAO();`를 `MySQLDAO dao = new MySQLDAO();`로 직접 고쳐줘야한다. 만약, 이런 클래스가 더 있다면? 일일이 그 클래스를 찾아 수정해줘야한다. 이러한 경우를 강한 의존관계라고 한다.  \n\n이보다 의존관계를 약화시키기 위해 다음과 같이 `interface`를 사용할 수 있다.\n\n```java\npublic interface DAO {\n    public void insert(){ }\n}\n\npublic class OracleDAO implements DAO{\n    @Override\n    public void insert(){ }\n}\n\npublic class MySQLDAO implements DAO{\n    @Override\n    public void insert(){ }\n}\n\npublic class Service {\n    DAO dao = new OracleDAO();\n    dao.insert();\n}\n```\n하지만, 이 방식도 `Service`에서 객체를 생성하기 때문에 큰 차이는 없다.   \n더 의존성을 약화시키기 위해 다음과 같이 **컨테이너**를 사용할 수 있다. \n\n```xml\n<!--applicationContext.xml-->\n<bean id=\"dao\" class=\"com.test.OracleDAO\"/>\n```\n```java\npublic class Service {\n    //스프링 컨테이너 생성\n    AbstractApplicationContext context = new GenericXmlApplicationContext(\"classpath:com/test/applicationContext.xml\");\n\n    try {\n        //스프링 컨테이너에서 객체를 가져옴\n        DAO dao = (DAO)context.getBean(\"dao\");\n        dao.insert();\n    } finally {\n        context.close();\n    }\n}\n```\n\n개발자는 xml에 객체 생성 정보 및 의존성을 설정한다. 그리고 컨테이너를 생성할 때 `classpath`로 해당 xml을 읽도록 한다.  \n컨테이너는 거기서 `<bean>`태그를 읽고 객체 생성 정보를 담는다. 따라서 `context`에는 'dao'의 생성 정보가 담겨 있다.\n컨테이너에 담겨진 객체를 가져오기 위해서는 `getBean()`을 쓴다. 이때 반환되는 객체의 타입은 `Obeject`이기 때문에 다운캐스팅을 해줘야한다.  \n다운캐스팅이 번거롭다면 `context.getBean(DAO.class)`처럼 쓸 수 있다.  \n본론으로 돌아가서, 만약 `dao`가 `MySQLDAO` 의 객체가 되도록 하려면 applicationContext.xml에서 `class`속성값만 바꿔주면 된다.  \n결과적으로 객체간의 **의존 관계는 약해지며, 재사용성이 높아진다.** 또한 프로그램의 제어권을 framework가 가져가는 **IoC(Inversion of Control)** 이 발생한다.   \n\n<br/>  \n\n## 의존 관계 설정\n\n의존관계를 설정하는 방법에는 Constructor Injection, Property Injection, Field Injection이 있다. \n\n### Constructor Injection\n\n```java\npublic interface MemberService {\n   public String print();\n}\n\npublic class MemberServiceImpl implements MemberService{\n   private String name;\n   private int age;\n   \n   MemberServiceImpl() {\n      this.name = \"Kim\";\n      this.age = 20;\n   } \n\n   @Override\n   public String print() {\n      return \"name : \" + name + \"\\nage : \" + age;\n   }\n}\n```\n```java\npublic class Member {\n   private MemberService memberService;\n   \n   Member(MemberService memberService){\n      this.memberService = memberService;\n   }\n   \n   public String result() {\n      return memberService.print();\n   }\n}\n```\n```xml\n<!--applicationContext.xml-->\n<bean id=\"memberService\" class=\"com.test.MemberServiceImpl\"/>\n<bean id=\"member\" class=\"com.test.Member\">\n    <constructor-arg ref=\"memberService\"></constructor-arg>\n</bean>\n```\n`Member`클래스에서는 생성자 인자를 받기 때문에 `<constructor-arg>`태그를 사용하게 된다.     \n생성자 인자가 기본형이면 속성으로 `value`를 넣어주고, 참조형이면 `ref`를 사용하게 된다. \n\n<br/>  \n\n### Property Injection\n\n`setter()`를 이용해 의존관계를 설정할 때에는 `<property>`로 값을 지정해준다.\n```java\npublic interface MemberService {\n   public String print();\n}\n\npublic class MemberServiceImpl implements MemberService{\n   private String name;\n   private int age;\n   \n   public void setName(String name) {\n      this.name = name;\n   }\n   public void setAge(int age) {\n      this.age = age;\n   }\n\n   @Override\n   public String print() {\n      return \"name : \" + name + \"\\nage : \" + age;\n   }\n}\n```\n```java\npublic class Member {\n   private MemberService memberService;\n   \n   public void setMemberService(MemberService memberService) {\n      this.memberService = memberService;\n   }\n\n   public String result() {\n      return memberService.print();\n   }\n}\n```\n```xml\n<bean id=\"memberService\" class=\"com.test.MemberServiceImpl\">\n    <property name=\"name\" value=\"Kim\"></property>\n    <property name=\"age\" value=\"10\"></property>\n</bean>\n\n<bean id=\"member\" class=\"com.test.Member\">\n    <property name=\"memberService\" ref=\"memberService\"></property>\n</bean>\n```\nxml의 `p 네임스페이스`를 사용하면 다음과 같이 간단하게 쓸 수 있다. \n```xml\n<bean id=\"memberService\" class=\"com.test.MemberServiceImpl\" p:name=\"kim\" p:age=\"10\"/>\n<bean id=\"member\" class=\"com.test.Member\" p:memberService-ref=\"memberService\"/>\n```\n\n<br/>  \n\n\n### 의존관계 자동설정\n\n`autowire`속성을 이용해 의존관계를 자동으로 설정할 수 있다. \n속성값에는 `constructor`, `byName`, `byType`이 있다.\n```xml\n<!--생성자를 이용한 의존관계-->\n<bean id=\"member\" class=\"com.test.Member\" autowire=\"constructor\"/>\n<!--프로퍼티를 이용한 의존관계-->\n<bean id=\"member\" class=\"com.test.Member\" autowire=\"byName\"/>\n```\n\n<br/>  \n\n\n### 객체 생성 예제\n\n- **Collection**\n\n```java\npublic class MemberServiceImpl implements MemberService{\n   private Map<String, String> address;\n   private List<String> hobby;\n   \n   public void setAddress(Map<String, String> address) {\n      this.address = address;\n   }\n   public void setHobby(List<String> hobby) {\n      this.hobby = hobby;\n   }\n\n   @Override\n   public String print() {\n      String str = null;\n\n      str = \"======= 친구 주소록 ======= \\n\";\n      Iterator<String> it = address.keySet().iterator();\n      while(it.hasNext()) {\n         String key = it.next();\n         String value = address.get(key);\n         \n         str += key + \" - \" + value + \"\\n\";\n      }\n      str += \"===========================\\n\";\n      \n      str += \"========== 취미 ===========\\n\";\n      for(String s : hobby) {\n         str += s + \"     \";\n      }\n      str += \"\\n===========================\\n\";\n      \n      return str;\n   }\n}\n```\n```xml\n<bean id=\"memberService\" class=\"com.test.MemberServiceImpl\">\n    <property name=\"address\">\n        <map>\n            <entry key=\"Kim\" value=\"Incheon\"></entry>\n            <entry key=\"Lee\" value=\"Seoul\"></entry>\n            <!-- 객체를 담는 경우\n            <entry key-ref=\"obj\" value-ref=\"obj\"></entry>-->\n        </map>\n    </property>\n    <property name=\"hobby\">\n        <list>\n            <value>sports</value>\n            <value>online-game</value>\n             <!-- 객체를 담는 경우\n            <ref-bean=\"obj\"/>-->\n        </list>\n    </property>\n</bean>   \n<bean id=\"member\" class=\"com.test.Member\" p:memberService-ref=\"memberService\"/>\n```\n\n- **lookup-method**\n\n추상 클래스의 자식 객체를 생성한다.\n\n```java\npublic class Member {\n   private static AtomicLong num = new AtomicLong();\n   private String name;\n   \n   public Member() {\n      num.incrementAndGet();\n   }\n\n   public void setName(String name) {\n      this.name = name;\n   }\n\n   @Override\n   public String toString() {\n      return \"name : \" + name + num;\n   }\n}\n```\n```java\npublic abstract class MemberService {\n   public abstract Member checkMember();\n}\n```\n```xml\n<bean id=\"memberService\" class=\"com.test.MemberService\">\n    <lookup-method name=\"checkMember\" bean=\"member1\"/>\n</bean>   \n\n<bean id=\"member1\" class=\"com.test.Member\" p:name=\"Kim\" scope=\"prototype\"/>\n```\n```java\npublic class App {\n   public static void main(String[] args) {\n      AbstractApplicationContext context = new GenericXmlApplicationContext(\"classpath:com/test/applicationContext.xml\");\n      \n      try {\n         MemberService ms = context.getBean(MemberService.class);\n\n         System.out.println(ms.checkMember());\n         System.out.println(ms.checkMember());\n         System.out.println(ms.checkMember());\n         System.out.println(ms.checkMember());\n      } finally {\n         context.close();\n      }\n   }\n}\n/*\n    name : Kim1\n    name : Kim2\n    name : Kim3\n    name : Kim4\n*/\n```\n추상클래스는 자식 객체를 생성하지 않고는 사용하지 못한다. xml에서 `<lookup-method>`를 이용해 메소드가 호출될 때 자식 객체를 생성할 수 있다. `scope`의 default는 singleton이기 때문에 항상 같은 객체를 리턴하지만 속성값을 `prototype`으로 줌으로써 항상 다른 객체를 생성하게 만들었다. 따라서 Member객체의 num이 계속 증가한 것을 확인할 수 있다.\n\n- **.properties**  \n\nxml의 `context 네임스페이스`를 사용해 파일을 읽고 `EL(Expression Language) 표현식` 이용해 값을 불러올 수 있다.\n```xml\n<context:property-placeholder location=\"classpath:com/user5/user.properties\"></context:property-placeholder>\n   \n<bean id=\"userService\" class=\"com.user5.UserServiceImpl\">\n    <property name=\"name\" value=\"${name}\"/>\n    <property name=\"tel\" value=\"${tel}\"/>\n    <property name=\"age\" value=\"${age}\"/>\n</bean>\n\n<bean id=\"userBean\" class=\"com.user5.UserBean\" p:userService-ref=\"userService\"/>\n```  \n\n#### Reference\n---  \n\n[DI 컨테이너](http://www.nextree.co.kr/p11247/)\n"
  },
  {
    "path": "Java/JSP와 Servlet처리.md",
    "content": "![Server_side](/assets/images/server_side.png)  \n\n# Web Server\n## 기능\n1. Web Server는 클라이언트에서 HTTP 요청을 받은 후, 반환될 페이지의 정적인 컨텐츠를 처리해준다. 정적인 컨텐츠는 Web Server가 주어진 파일 경로를 따라갔을 때 반환되는 컨텐츠로, 항상 동일한 컨텐츠가 반환된다. 그 예로는 HTML, CSS, Javascript 파일 등이 있다. \n2. Web Server가 처리하지 못하는 동적 컨텐츠들은 Web Server의 요청에 따라 WAS (Web application Server)로 넘어간다. 동적 컨텐츠는 인자에 따라 반환되는 컨텐츠가 달라지는데, JSP, Servlet이 여기에 속한다.    \n\n<br/>  \n  \n\n## 종류\nApach Server, IIS, nginx 등\n\n<br/>  \n\n# Web Application Server\nWAS는 위에서도 언급했듯이 JSP, Servlet 등을 처리하기 위해 쓰인다. JSP와 Servlet은 자바를 기반으로한 웹 프로그래밍 언어이기 때문에 thread로 요청을 처리한다.\n\n## JSP 처리\nJSP파일은 먼저 Servlet Class 형태의 java 소스 파일로 변환된다. \n\n![ServletClass](/assets/images/ServletClass.png) \n\n이 java 파일 안에는 다음의 메소드가 정의되어 있다. \n```java\npublic void _jspInit() {\n  }\n\npublic void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)\n    throws java.io.IOException, javax.servlet.ServletException { \n\n} \n\npublic void _jspDestroy() {\n}\n\n\n```\n* `_.jspInit()` 메소드  \n  jsp 파일이 최초로 요청되거나, 코드가 수정된 후 요청된 경우에만 실행되는 메소드이다. jsp의 인스턴스 변수를 초기화하며 Servlet을 메모리에 로딩한다. 만약 같은 페이지에 대한 요청이 있으면, 이미 변환된 Servlet 파일이 서비스된다. \n* `_.jspService()` 메소드  \n  java의 `main()` 메소드 역할을 한다. ` _.jspInit()`메소드가 실행된 후 요청된 jsp 파일의 jsp 태그 및 HTML이 메소드에 삽입된다. 이 메소드는 서버가 Servlet에 요청을 전달할 때마다 실행된다.\n* `_.jspDestroy()` 메소드  \n  서블릿 파일을 종료하고 메모리에서 파괴하는 메소드로, Tomcat이 종료될 때 실행된다.\n\n<br/>  \n  \n## Servlet 처리\nServlet을 처리하기 위해 대부분 `GenericServlet` 클래스나 `HttpServlet` 클래스를 상속한다.   \n\n![ServletArchitecture](/assets/images/servletArchitecture.png)\n\n### GenericServlet Override\n`GenericServlet`은 `Servlet`을 구현한 클래스로, `GenericServlet`을 오버라이딩할 때에는 `Servlet`의 `service()` 메소드를 구현해야 한다. 이 메소드는 `GET`방식과 `POST`방식을 모두 처리한다. 파라미터로는 `ServletRequest`와 `ServletResponse`를 받는다.\n```java\npublic class HelloServlet extends GenericServlet{\n\n\tprivate static final long serialVersionUID = 1L;\n\n\t@Override\n\tpublic void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {\n\t\n\t\ttry {\n\t\t\tString name = req.getParameter(\"name\");\n\t\t\tint age = Integer.parseInt(req.getParameter(\"age\"));\n\t\t\n\t\t\tString msg = \"이름 : \" + name + \" / 나이 : \" + age;\n\t\t\t\n\t\t\tres.setContentType(\"text/html; charset=UTF-8\");\n\t\t\t\n\t\t\tPrintWriter out = res.getWriter();\n\t\t\t\n\t\t\tout.print(\"<html>\");\n\t\t\tout.print(\"<body>\");\n\t\t\tout.print(msg);\n\t\t\tout.print(\"</body>\");\n\t\t\tout.print(\"</html>\");\n\t\t\t\n\t\t} catch(Exception e) {\n\t\t\tgetServletContext().log(\"erros\");\n\t\t}\n\t}\n}\n```\n \n<br/>  \n  \n### HttpServlet Override\n`HttpServlet`은 `GenericServlet`을 상속받은 클래스로 HTTP환경에 최적화되어 있다. `GenericServlet`의 `service()`는 이미 구현되어 있기 때문에 여기서 직접 `service()`메소드를 구현할 필요가 없다. 대신 파라미터 `HttpServletRequest`의 메소드 타입이 `GET`이면 `doGet()`메소드를 타고, `POST`이면 `doPost()` 메소드를 타기 때문에 `doGet()`과 `doPost()`를 구현해야한다.\n\n```java\n@WebServlet(\"/demo\")\npublic class DemoServlet extends HttpServlet {\n\n\tprivate static final long serialVersionUID = 1L;\n\t\n\t@Override\n\tprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {\n\t\t// GET 방식 처리\n\t\tRequestDispatcher rd = req.getRequestDispatcher(\"/WEB-INF/views/demo/write.jsp\");\n\t\trd.forward(req, resp);\n\t}\n\n\t@Override\n\tprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {\n\t\t// POST 방식 처리\n\t\treq.setCharacterEncoding(\"utf-8\");\n\t\t\n\t\tString name = req.getParameter(\"name\");\n\t\t\n\t\tresp.setContentType(\"text/html;charset=utf-8\");\n\t\tPrintWriter out = resp.getWriter();\n\t\t\n\t\tout.print(\"<html>\");\n\t\tout.print(\"<body>\");\n\t\tout.print(name);\n\t\tout.print(\"</body>\");\n\t\tout.print(\"</html>\");\n\t}\n}\n```\n \n<br/>  \n  \n## 종류\nTomcat, Jeus 등이 있다.    \n\n\n<br/>  \n\n----\n#### Reference\n[JSP 동작원리 및 변환 방식](http://egloos.zum.com/rebirth/v/481080)   \n[서블릿의 기본](https://m.blog.naver.com/PostView.nhn?blogId=yswon72&logNo=51544546&proxyReferer=https%3A%2F%2Fwww.google.com%2F)  \n[서블릿 문법](https://levin01.tistory.com/595)  \n[Web Server와 WAS의 차이와 웹 서비스 구조](https://gmlwjd9405.github.io/2018/10/27/webserver-vs-was.html)\n"
  },
  {
    "path": "Java/JVM(Java Virtual Machine).md",
    "content": "# JVM(Java Virtual Machine)\n\n<br/>\n\n## JVM이란?\n\n`Java`는 기본적으로 `JVM`위에서 작동된다. `JVM`은 `Java`와 OS(운영체제)사이에 중간 역할을 함으로써, **`Java`애플리케이션이 OS에 관계 없이 작동할 수 있도록 해준다.** 즉, `Java`로 작성된 애플리케이션은 Mac이든 Windows든 Linux든 해당 OS에 적합한 `JVM`을 설치해주면 그 위에서 작동하기 떄문에 어떤 OS든 같은 코드로 동작할 수 있다.\n\n`JVM`은 **스택 기반의 가상 머신**이며, 메모리 관리와 GC(Garbage Collector)의 역할을 수행한다.\n\n<br/>\n\n`JVM`은 `Class Loader`, `Execution Engine`, `Runtime Data Areas`로 구성되며 다음과 같은 실행 과정을 거친다.\n\n1. `JVM`은 OS로부터 프로그램을 실행하는데 필요한 메모리를 할당받는다.\n\n2. `Class Loader`를 통해 컴파일된 자바 코드(.class)를 `JVM`으로 로딩한다.\n\n3. `Class Loader`를 통해 로딩된 자바 바이트 코드가 `Runtime Data Areas`로 배치된다.\n\n4. `Runtime Data Areas`에 배치된 바이트코드를 `Execution Engine`에서 해석하고 실행한다.\n\n## Class Loader\n\n`JVM`에 **Runtime 시점**에 동적으로 클래스를 로딩한다. OS에서 할당 받은 메모리 `jar`파일 내의 클래스들을 로딩하며 사용하지 않는 클래스는 메모리에서 삭제한다.\n\n<br/>\n\n## Runtime Data Areas\n\nJVM이 프로그램의 수행을 위해 할당 받은 메모리 공간을 말한다.\n\n![java_Runtime_Data_Areas](/assets/images/java_Runtime_Data_Areas.jpg)\n\n<br/>\n\n![java_runtime_data_area](/assets/images/java_runtime_data_area.png)\n\n\n<br/>\n\n## Execution Engine\n\n로딩된 클래스 파일들은 `Execution Engine`에 의해서 실행 된다. **`Execution Engine`은 자바 바이트 코드를 해석하고 실행**한다. 그리고 이를 해석하는 방식에는 인터프리터 방식과 JIT(Just In Time)컴파일러에 의한 방식 두 가지가 있다.\n\n<br/>\n\n### 인터프리터\n\n`JVM`이 처음 나왔을 때는 **자바 바이트 코드를 명령어 단위로(한줄씩) 해석하기 떄문에 느리다**는 단점이 있다.\n\n### JIT(Just In Time)\n\n인터프리터 방식의 단점을 해결하기 위해 JIT 방식이 도입되었다. 한줄씩 해석하여 실행하는 것이 아닌 자바 바이트 코드 전체를 한 번에 컴파일하여 Native코드로 변경하여 실행한다. 변경된 코드는 인터프리터에 의한 해석이 필요 없기 때문에 빨라질 수 있다.<br/> 하지만 이처럼 **컴파일 하는데도 비용이 발생하기 떄문에 `JVM`은 모든 코드를 JIT방식으로 컴파일하지 않고 인터프리터 방식으로 해석하다가 일정 기준이 넘어가면 JIT 방식으로 컴파일하고 실행하는 방식**을 사용하고 있다.\n\n<br/>\n\n---\n\n#### Reference\n\n- [자바가상머신, JVM(Java Virtual Machine)이란 무엇인가?](https://asfirstalways.tistory.com/158)\n- [JVM 이란?](https://medium.com/@lazysoul/jvm-%EC%9D%B4%EB%9E%80-c142b01571f2)\n\n"
  },
  {
    "path": "Java/Java Garbage Collection(GC).md",
    "content": "# Java Garbage Collection(GC)\n\n## Garbage란?\n\n프로그램을 실행하다보면 `Garbage` 즉, 쓰레기가 발생하게 되는데 이는 쉽게 말하자면 **정리되지 않은 메모리**, **유효하지 않은 주소**다.\n\n```java\nint[] arr = new int[3];\n\narr[0] = 1;\narr[1] = 2;\narr[2] = 3;\n\narr = new String[3];\n\narr[0] = \"Java\";\narr[1] = \"JavaScript\";\narr[2] = \"Node.js\";\n```\n\n위의 코드를 보면 `int`타입의 배열 `arr`를 사용하다가 `String`타입의 배열을 만들고 `arr`가 이를 가리키도록 하고 있다.\n\n여기서 처음 생성했던 `int`타입의 배열은 **사용할 수 없는 메모리**가 되고 이를 **프로그래밍 언어로는 `Dangling Object`, 자바에서는 `Garbage`라고 한다.**\n\n<br/>\n\n## GC(Garbage Collector)의 구조\n\n`Garbage Collector`가 담당하는 메모리 영역은 [JVM](https://github.com/Im-D/Dev-Docs/blob/master/Java/JVM(Java%20Virtual%20Machine).md)에서 `Heap`영역을 다룬다.\n\n`Young`, `Old`, `Permanent` 세 영역으로 나뉘게 되며 이를 세분화 하면 총 4개의 영역으로 나뉘게 된다.\n\n- **Young** : `Eden`, `Survivor`\n- **Old** : `Old`\n- **Permanent** : `Permanent(이하 Perm)`\n\n#### Perm 영역\n\n`Perm`영역에서 담고 있는 정보는 다음과 같다.\n\n- Class 의 Meta정보\n- Method의  Meta 정보\n- Class와 관련된 배열 객체 Meta 정보\n- Static 객체\n- 상수화된 String 객체\n- JVM 내부적인 객체들과 JIT의 최적화 정보\n\n프로젝트가 커지면 `perm gen`이 커서 에러가 나는데 이때 `MaxPermSize` 옵션을 JVM 옵션에 크게 주면 해결할 수 있다.\n\nJava 8에서는 고질적인 `perm gen space error`를 해결하기 위해서 perm 영역을 없애버렸고 이에 따라 `-XX:MaxPermSize` 설정이 사라지고 `-XX:MaxMetaspaceSize` 로 바뀌게 되었다.\n\n<br/>\n\n## GC(Garbage Collector)의 작동 원리\n\nGC의 역할의 공통적인 원리는 `Heap`내의 객체 중 `Garbage`를 찾아 이를 처리하고 메모리를 회수한다는 것이다.\n\n이 과정에서 객체가 `Garbage`인지 아닌지를 판단하기 위해 `reachability`개념을 사용한다. 보통 하나의 객체는 다른 객체를 참조하고 그 객체는 또 다른 객체를 참조하게 되는데 여기서 **최초에 참조한 객체를 `Root Set`이라고 한다.**\n\n![java_gc_object](/assets/images/java_gc_object.png)\n\n위의 그림과 같이 각각의 객체가 서로 참조하면서 참조 사슬이 형성되는데 `Root Set`에서 참조 사슬에 의해  `Unreachable`한 객체들은 **Garbage Collection**의 대상이 된다.\n\n<br/>\n\n## GC(Garbage Collector)의 종류\n\n![java_gc_heap](/assets/images/java_gc_heap.png)\n\n`Garbage Collector`는 크게 `Minor GC`와 `Major GC`가 있다.\n\n<br/>\n\n### Minor GC\n\n`Minor GC`는 `Young` 영역에서 발생하는 GC다.\n\n**새롭게 생성된 객체는 주로 `Eden`영역**에 위치하게 된다. <br/>`Eden`영역에서 `Garbage Collection`이 발생하고 **남은 객체는 `Survivor`영역**으로 넘어가게 된다. <br/>이 과정을 반복하게 되며 **계속해서 남아 있는 객체는 `Old`영역**으로 넘어간다.\n\n이를 정리하면 다음과 같다.\n\n- **객체 생성** : `Eden`영역에 위치.\n- **Garbage Collection 발생** : 남은 객체는 `Survivor`영역으로 이동.\n- **위 과정을 반복** : 계속해서 남아 있는 객체는 `Perm`영역으로 이동.\n\n### Major GC\n\n`Magejor GC`는 `Old` 영역에서 발생하는 GC다. Old 영역의 데이터가 가득 찼을 때, 발생된다.\n\n`Old` 영역에 있는 **모든 객체들을 검사하여 참조되지 않고 있는 모든 객체들을 한 번에 삭제**한다.<br/>\n이 과정은 시간이 오래 걸리고 실행 중 프로세스가 정지된다.(Stop the world)\n\n`Major GC`가 발생하면 GC를 실행하는 쓰레드를 제외한 나머지 쓰레드는 모두 작업을 멈춘다.\n\n<br/>\n\n## GC(Garbage Collection)의 방식\n\n빈번한 `Garbage Collection`의 수행은 성능에 영향을 줄 수 있고 이 때문에 `Garbage Collection`의 수행 타이밍은 별도의 알고리즘을 기반으로 수행된다.\n\n<br/>\n\n### Serial GC\n\n**적은 메모리와 CPU의 코어 갯수가 적을 때 적합한 방식**으로 운영 서버에서는 사용하지 않는 방식이다.\n\n`Young`영역에서는 위에서 설명한 `Minor GC`에서 사용하던 방식을 사용하고 `Old`영역에서는 `mark-sweep-compact`라는 알고리즘을 사용한다.\n\n- Old 영역에서 살아있는 객체를 마크(Mark)한다.\n- `Heap`의 앞 부분부터 확인하여 살아 있는 것만 남긴다.(Sweep)\n- 각 객체들이 연속되게 쌓이도록 다시 `Heap`의 앞부분부터 채워 넣는다.(Compaction)\n\n### Parallel GC(Throuhput GC)\n\n`Serial GC`와 기본적인 알고리즘은 같지만 GC를 처리하는 쓰레드가 여러 개다. 즉, 더 빠르게 `Garbage Collection`을 수행할 수 있다. 코어의 갯수가 많고 메모리가 충분하면 유리한 방식이다.\n\n### Parallel Old GC\n\nJDK 5 update 6부터 제공한 GC 방식이다. 이름에서 알 수 있듯이 `Parallel GC`와 비교하면 `Old`영역에서 알고리즘이 다르다. `Mark-Summary-Compaction`이라는 알고리즘을 사용하는데 **`Sweep` 단계가 아닌 `Summary` 단계를 거치게 된다.**\n\n`Summary` 단계는 앞서 GC를 수행한 영역에 대해서 별도로 살아 있는 객체를 식별하며 좀 더 복잡한 단계를 거친다.\n\n> Java 7 Update 4 이후부터는 `XX:+UseParallelGC` 사용시에도 `-XX:+UseParallelOldGC`를 **default**로 사용하게 된다.<br/>\n> Java 7 Update 4 이상이면 `UseParallelGC`와 `UseParallelOldGC` 중 어느 하나만 사용해도 결국 `UseParallelOldGC` 처럼 동작한다. <br/>\n> `-XX:+UseParallelGC`만 쓰면 되고, `UseParallelOldGC`에 의해 수행되었던 역할을 굳이 끄고 싶을 때만 `XX:-UseParallelOldGC`을 사용하라고 한다.\n\n- [CMS GC, G1 GC](https://d2.naver.com/helloworld/1329)\n\n<br/>\n\n#### Parallel vs CMS\n\n- `Parallel`은 최대 처리량을 위한 GC 방식이며 `Mark`, `Sweep`, `Compaction` 단계가 동시에 일어나기 때문에 상대적으로 멈춤(pause) 시간이 크다.\n\n- `CMS`는 `Full GC`시 멈춤 시간이 짧은 편이지만 `Parallel`에 비해 처리량이 적고 더 많은 자원을 사용한다.\n\n<br/>\n\n---\n\n#### Reference\n\n- [Naver D2 - Java Garbage Collection](https://d2.naver.com/helloworld/1329)\n- [Java :: 가비지 컬렉터(Garbage Collector)란](https://wanzargen.tistory.com/15)\n- [#가비지 컬렉션(Garbage Collection) / JVM 구동원리에 이어서](https://asfirstalways.tistory.com/159?category=660807)\n\n"
  },
  {
    "path": "Java/Mybatis.md",
    "content": "# Mybatis(마이바티스) Framework\n## 마이바티스란?\n 마이바티스를 설명하기 위해서 JDBC 개념을 알아야한다.\n \n-  JDBC(Java Database Connectivity)란 Java에서 데이터베이스에 접속할 수 있도록 하는 자바 API이다.\n자바는 JDBC를 통해 mysql, oracle 등 데이터베이스 종류에 상관없이 접근할 수 있다.\n기존에 [JDBC를 이용하여 프로그래밍을 하는 방식](https://blog.outsider.ne.kr/6)은 프로그램 소스 안에 SQL 문을 작성하는 방식이었다.\n그렇기 때문에 한 파일에 java 언어와 sql 언어가 있어 재사용성이 안 좋고 가독성이 떨어진다는 단점이 있다.\n\n\n- Mybatis는 JDBC의 단점을 보완해 작업을 간편하게 해주는 프레임워크이다. \nSQL 쿼리문을 xml 형식의 파일로 분리시켜 저장관리할 수 있다.\n또한, 개발자가 작성한 SQL 명령어와 자바 객체를 매핑해주는 기능을 제공하며, 기존에 사용하던 SQL 명령어를 재사용한다는 장점이 있다. \n\n따라서 SQL의 변경 등이 발생할 경우, 프로그램(java 파일)을 수정하기 때문에 그 유연성이 좋지 못했는데, MyBatis에서는 SQL을 xml 파일에 작성하기 때문에, SQL의 변환이 자유롭고, 가독성이 좋다는 장점이 있다.\n\n## Mybatis를 쓰는 이유\n###### Mybatis가 없었을 때의 소스 방식\n```java\npublic Entity selectFAQList(UserConnection conn, Entity param) throws SQLException {\n       UserStatement stmt = null;\n       ResultSet rslt = null;\n       StringBuffer sql = new StringBuffer();\n       sql.append(\"\\n SELECT *\");\n       sql.append(\"\\n FROM\");\n       sql.append(\"\\n TABLE1\");\n       stmt = conn.prepareStatement(sql.toString());\n       rslt = stmt.executeQuery();\n       Entity _DATA = new Entity();\n       _DATA.put(\"_DATA\", EntityUtil.ResultSetToClobList(rslt));\n       return _DATA;\n}\n```\n.java 파일 안에 StringBuffer라는 클래스를 호출해 sql이라는 객체를 만들어 문자를 계속 이어주면서 sql query를 작성하고 있다. \n\n이 경우 쿼리가 수정될 때마다 .java에 들어가 .append()메소드를 추가하고 저장해 유지 보수가 힘들고 가독성이 떨어져 sql query구문의 분리가 어려워진다. \n\n또한, 쿼리 양이 많아질수록 .java에는 자바 코드뿐만 아니라 쿼리 코드로 인해 양이 방대해진다.\n그래서 sql 구문과 java 코드의 분리 필요성을 느끼게 된다. \n\n###  Mybatis적용 후 소스 방식\n```java\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n  <ENTITY id=\"table.getTable1List\" type=\"SQL\" return=\"List\">\n    <![CDATA[\n        SELECT *\n            FROM\n            TABLE1\n    ]]>\n    <PARAMS>    \n    </PARAMS>\n  </ENTITY>\n```\n\nxml로 빼내서 쿼리문을 작성하면 내부적 처리는 Mybatis에서 모두 처리해 주므로 Entity id 값을 DAO에서 호출하기만 하면 된다. \n\n우리가 사용할 sql 문을 Mapper에 등록해놓고선 편리하게 나중에 sqlSession을 통해서 id 값을 이용해 불러오고 사용하면 훨씬 편리하다.\n\n\n## 스프링 웹 프로젝트의 구조\n![웹 프로젝트의 구조](https://user-images.githubusercontent.com/43868540/79679996-af158980-8245-11ea-9cbb-66248dc0678e.png)\n\n핵심적으로 DAO는 SessionTemplate를 통해 Mybatis를 호출해 데이터베이스에 접근한다. \n\n## Mybatis 연동하기\nspring과 Mybatis는 연결한 전체 구조는 아래의 그림과 같다. \n![Mybatis를 이용한 spring, DB연결 구조](https://user-images.githubusercontent.com/43868540/79680054-6f9b6d00-8246-11ea-9658-d5fb79be24d3.png)\n**1. Mybatis 라이브러리 추가**\n\n스프링에서 MyBatis를 사용하려면 라이브러리가 필요하다. \nMaven을 이용하면 라이브러리의 추가가 굉장히 쉽다. <br>\nMaven은 내가 사용할 라이브러리뿐만 아니라 해당 라이브러리가 작동하는데 필요한 다른 라이브러리들까지 관리하여 네트워크를 통해서 자동으로 다운받아 준다.<br>\n라이브러리를 쉽게 관리할 수 있다.\n\npom.xml의 <dependency>태그 추가하기!\n\n```java\n<!-- mybatis -->\n      <dependency>\n         <groupId>org.mybatis</groupId>\n         <artifactId>mybatis</artifactId>\n         <version>3.4.6</version>\n      </dependency>\n      \n      <dependency>\n         <groupId>org.mybatis</groupId>\n         <artifactId>mybatis-spring</artifactId>\n         <version>1.3.2</version>\n      </dependency>\n\n      <dependency>\n         <groupId>org.springframework</groupId>\n         <artifactId>spring-jdbc</artifactId>\n         <version>${org.springframework-version}</version>\n       </dependency>\n\t\t \n\t <dependency>\n    \t<groupId>org.springframework</groupId>\n    \t<artifactId>spring-test</artifactId>\n    \t<version>4.3.18.RELEASE</version>\n\t</dependency>\n      \n\t<!--jdbc의 Datasource 사용을 위한 dbcp도 추가해준다.-->\n      <dependency>\n         <groupId>org.apache.commons</groupId>\n         <artifactId>commons-dbcp2</artifactId>\n         <version>2.6.0</version>\n      </dependency>\n\t  <!--여기까지 공통으로 들어가는 라이브러리-->\n\t  \n      <!-- mariaDB DB에 따라서 추가할 라이브러리가 다르다. --> \n      <dependency>\n         <groupId>org.mariadb.jdbc</groupId>\n         <artifactId>mariadb-java-client</artifactId>\n         <version>2.2.1</version>\n      </dependency>\n```\n\n**2. Mybatis와 Spring 연결**\n스프링 프레임워크에서 Mybatis를 사용하기 위한 xml 설정을 하는 단계\n\n/WEB_INF/spring/appServlet경로에 root-context.xml 파일 생성!\n\n```java\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n   xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n   xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd\">\n   \n<!--DB 연결 정보-->\n<bean id=\"dataSource\" class=\"org.apache.ibatis.datasource.pooled.PooledDataSource\">\n         <property name=\"driver\" value=\"org.mariadb.jdbc.Driver\" />\n        <property name=\"url\" value=\"jdbc:mariadb://127.0.0.1:3306/test\" />\n         <property name=\"username\" value=\"root\" />\n         <property name=\"password\" value=\"passwd\" />\n   </bean>\n```\n  \n```java\n<!--    Mybatis의 xml파일들을 읽기 위한 설정-->\n   <bean id=\"sqlSessionFactory\"\n        class=\"org.mybatis.spring.SqlSessionFactoryBean\">\n        <property name=\"dataSource\" ref=\"dataSource\"></property>\n```\n위 부분은 sqlSession을 생성하기 위해 sqlSessionFactory를 정의하고 있다. \n또한, property의 name과 ref가 dataSource로 정의 되어있다. 이 두 가지는 같은 것을 의미하지 않는다. name은 위에서 등록한 sqlSession 빈(bean)에서 사용할 이름이 dataSource이고, ref의 dataSource는 우리가 7행에서 정의한 빈(bean)을 참조하는 것을 의미한다. \n\n```java\n        <property name=\"configLocation\"\n            value=\"classpath:sql/mybatis-config.xml\">\n        </property>\n    </bean>\n```\n위 부분은 src/main/resources 경로의 mybatis-config.xml 파일의 위치를 지정해 주는 것이다.\nmybatis-config.xml는 우리가 작성할 sql 문이 모여있는 xml 파일이다.\n\n```java\n   <bean id=\"sqlSession\" class=\"org.mybatis.spring.SqlSessionTemplate\">\n        <constructor-arg  ref=\"sqlSessionFactory\"></constructor-arg>\n    </bean>   \n\t\n\t<bean id=\"sqlSessionTemplate\" class=\"org.mybatis.spring.SqlSessionTemplate\"> <constructor-arg index=\"0\" ref=\"sqlSession\"/> \n   </bean> \n   </beans>\n```\n위 부분은 sqlSessionTemplate를 정의하고 있다.\nsqlSessionTemplate은 마이바티스 스프링 연동 모듈의 핵심이다. SQLSessionTemplate은 SqlSession을 구현하고, 코드에서 SqlSession을 대체하는 역할을 한다.\n\n* sqlSessionFactory <br>\nMybatis에서는 SqlSession를 생성하기 위해 SqlSessionFactory를 사용한다. \nsqlSessionFactory를 생성 하기위해 SqlSessionFactoryBean 이 사용된다.\n세션을 한번 생성하면 세션을 이용해서 매핑된 구문을 실행하거나 커밋 또는 롤백을 하기 위해 세션을 사용할 수 있다. \n그리고 마지막으로 더 이상 필요하지 않은 상태가 되면 세션을 닫는다. \n\n* sqlSessionTemplate <br>\nSqlSessionTemplate은 마이바티스 스프링 연동 모듈의 핵심이다. \nSqlSessionTemplate은 SqlSession을 구현하고 코드에서 SqlSession를 대체하는 역할을 한다. \n\n**3. mybatis-config.xml 작성**\n```java\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE configuration\nPUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n\"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <mappers>\n        <mapper resource=\"sql/user-mapper.xml\"/>\n        <mapper resource=\"sql/searchSubject-mapper.xml\"/>\n        <mapper resource=\"sql/member-mapper.xml\"/>\n        <mapper resource=\"sql/claim-mapper.xml\"/>\n        <mapper resource=\"sql/patent-mapper.xml\"/>\n        <mapper resource=\"sql/memo-mapper.xml\"/>\n        <mapper resource=\"sql/paper-mapper.xml\"/>\n    </mappers>\n</configuration>\n```\n\nmybatis-config.xml은 mapper들이 모인 xml 파일이다. \n \n즉, mybatis-config.xml의  지정해줌으로써 모든 xml 파일을 읽어들인다. \n \n**4 web.xml 작성**\n\nweb.xml은 서버가 최초로 실행될 때 해당 위치에 있는 context 파일을 모조리 읽어들이는 것을 뜻한다. \ncontext 파일을 읽어들이면서 xml을 인식한다. \n```java\n<context-param>\n      <param-name>contextConfigLocation</param-name>\n      <param-value>\n          /WEB-INF/spring/root-context.xml\n       </param-value>\n   </context-param>\n```\n   \n   \n**5 DAO 작성**\n\n마지막으로 실제 소스에서 위에서 선언한 SqlSessionTemplate을 사용할 DAO를 만들어준다. \n스프링의 Data Access Object (DAO) 지원은 JDBC, Hibernate, JPA, JDO같은 데이터 접근 기술과 관련된 작업을 일관된 방법으로 쉽게 할 수 있게 도와준다.\nDAO는 sql 문의 id를 통해 데이터베이스와 sql 문을 연결해준다.\n\n1) src/main/java 폴더의 first > common 패키지 밑에 dao 패키지를 생성한다.\n\n2) dao 패키지 안에 AbstractDAO.java를 생성한다.\n\n3) AbstractDAO.java에 코드 작성한다.\n```java\npublic class AbstractDAO { \n\tprotected Log log = LogFactory.getLog(AbstractDAO.class); \n\t@Autowired private SqlSessionTemplate sqlSession; \n\tpublic Object insert(String queryId, Object params){ \n\t\treturn sqlSession.insert(queryId, params); \n\t} \n\t\treturn sqlSession.update(queryId, params); \n\t} \n\tpublic Object delete(String queryId, Object params){ \n\t\treturn sqlSession.delete(queryId, params); \n\t} \n\tpublic Object selectOne(String queryId){ \n\t\treturn sqlSession.selectOne(queryId); \n\t} \n\tpublic Object selectOne(String queryId, Object params){ \n\t\treturn sqlSession.selectOne(queryId, params); \n\t} \n\t@SuppressWarnings(\"rawtypes\") \n\tpublic List selectList(String queryId){\n\t\treturn sqlSession.selectList(queryId); \n\t} \n\t@SuppressWarnings(\"rawtypes\") \n\tpublic List selectList(String queryId, Object params){ \n\t\treturn sqlSession.selectList(queryId,params); \n\t} \n}\n```\n\n앞에서 SqlSessionTemplate을 설정하였고, 이는 SqlSession을 대체한다.\n3번째 줄에 SqlSessionTemplate을 선언을 한다.\n\n쿼리는 sqlSession.메서드를 호출하면 되는데 쿼리 문의 id에 접근해 사용한다. \n\n**6  SQL.xml 파일 작성**\n\n이제 SQL.xml 파일을 작성하면 완료~\n\n앞서 21행에서 설정한 <value>classpath:sql/mybatis-config.xml</value>\n이 부분대로 src/main/resources/sql/_.xml 파일을 생성해서 사용하면 된다.\n\npaper-mapper.xml\n```java\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper\nPUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"paperMapper\">\n\n<select id =\"SELECT_paperOverChk\" parameterType=\"java.util.HashMap\" resultType= \"String\">\n       SELECT    paper_id\n       FROM    paper_tb\n       WHERE   cn = #{cn}\n  </select>\n```\n\n##  Mybatis의 특징\n- 간단한 퍼시스턴스 프레임워크이다.\n- 코드재사용으로 인한 개발자의 부담을 줄여주고 생산성을 높인다. \n- SQL문이 어플리케이션 소스코드로부터 완전히 분리되어 가독성이 높다.\n\n## Mybatis의 단점\n- SQL을 직접 작성하여 반복되는 작업이 존재\n- SQL과 데이터베이스 벤더에 대한 종속성(오라클에서 mySQL로 바꾸면 함수들을 바꿔줘야한다.)\n\n#### Reference <br>\n- [Mybatis개념](https://sjh836.tistory.com/127)\n- [마이바티스와 sql연동하기](https://baessi.tistory.com/8)\n- [마이바티스연동과 개념](https://addio3305.tistory.com/62)\n- [개발환경 설정](https://velog.io/@wimes/2.-개발환경설정-Spring-MyBatis-MySQL의-설정-2zk4cf5gof)\n- [Mybatis와 JPA 비교](https://jar100.tistory.com/25)\n"
  },
  {
    "path": "Java/Set.md",
    "content": "# Iterable\n![Collection_Hierarchies](/assets/images/Collection_Hierarchies.png)\n\n주요 컬렉션 인터페이스에는 `List<E>`, `Set<E>`, `Queue<E>` 그리고 `Map<K,V>`가 있다.    \n`List<E>`, `Set<E>`, `Queue<E>`의 최상위 인터페이스는 `Collection<E>`이고, `Collection<E>`은 `Iterable<T>`를 구현한다. `Iterable`은 컬렉션에 대한 반복자로, `Iterable<T>`을 구현한 클래스 객체는 `hasNext()`, `next()`, `for-each Loop` (향상된 for문)등을 사용할 수 있다. \n```java\npublic class test {\n\tpublic static void main(String[] args) {\n\t\tList<Integer> list = Arrays.asList(1, 2, 3, 4, 5);\n\n\t\t//for-each Loop\n\t\tfor(Integer i : list) {\n\t\t\tSystem.out.printf(\"%d \", i);\n\t\t}\n\n\t\t//hasNext(), next();\n\t\tIterator<Integer> it = list.iterator();\n\t\t\n\t\twhile(it.hasNext()){\n\t\t\tSystem.out.printf(\"%d \", it.next()\t);\n\t\t}\n\t}\n}\n```\n  \n<br/>  \n\n# Set\n1. 중복을 허용하지 않는다. \n2. 동기화를 지원하지 않는다. \n\n\t[참고 ) Collection Synchronization](https://madplay.github.io/post/java-collection-synchronize)\n\n## HashSet\n### 중복확인\n```java\npublic class Test {\n\tpublic static void main(String[] args) {\n\t\tSet<String> set = new HashSet<String>();\n\t\tString str = \"java\";\n\t\t\n\t\t//중복 허용 X\n\t\tSystem.out.println(set.add(str));\n\t\tSystem.out.println(set.add(str));\n\t\t\n\t\t//해시코드 확인\n\t\tSystem.out.println(set.hashCode());\n\t\tSystem.out.println(str.hashCode());  \n\t}\n}\n\n//true\n//false \n//3254818\n//3254818\n```\nHashSet은 요소의 중복을 체크하기 위해 `hashCode()`를 호출해 반환된 해시값으로 검색할 범위를 결정한 뒤, 해당 범위 내의 요소들을 `equals()`로 비교한다. 다만, 객체를 생성할 때에는 다음과 같이 같은 값을 갖는 인스턴스를 만들어도 서로 다른 해시코드가 반환되기 때문에 같은 값을 갖는 인스턴스들이 중복되어 저장될 수 있다. 따라서 객체를 저장할 때에는 `hashcode()`와 `equals()`를 오버라이딩 해주어야한다. \n```java\npublic class Test {\n\tpublic static void main(String[] args) {\n\t\tSet<Person> set = new HashSet<Person>();\n\t\tPerson p1 = new Person(\"Kim\", 10);\n\t\tPerson p2 = new Person(\"Kim\", 10);\n\t\t\n\t\t//중복 허용 \n\t\tSystem.out.println(set.add(p1));\n\t\tSystem.out.println(set.add(p2));\n\t\t\n\t\t//해시코드 확인\n\t\tSystem.out.println(p1.hashCode());\n\t\tSystem.out.println(p2.hashCode());\n\t}\n}\n\n//true\n//true\n//2018699554\n//1311053135\n```\n`hashcode()`와 `equals()` 오버라이딩\n```java\npublic class Person {\n\tprivate String name;\n\tprivate int age;\n\t\n\tpublic Person(String name, int age) {\n\t\tthis.name = name;\n\t\tthis.age = age;\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn (name + age).hashCode();\n\t}\n\t\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif(obj instanceof Person) {\n\t           Person temp = (Person)obj;\n\t           return this.name.equals(temp.name) && (this.age == temp.age);\n\t    } else {\n\t           return false;\n\t    }\n    }\n}\n```  \n<br/>\n\n### HashTable\nHashSet은 **HashTable**에 원소를 저장한다. HashTable은 해시값으로 데이터를 매핑하기 때문에 작은 크기의 메모리로 데이터를 관리할 수 있다. 또한 데이터에 해시값으로 접근하기 때문에 모든 데이터를 살피지 않고 검색과 삽입/삭제 등을 빠르게 할 수 있다. 따라서 성능면에서는 HashSet이 가장 우수하다.  \n\n![HashTable](/assets/images/HashTable.png) \n\t\n<br/>\n\n## LinkedHashSet\nLinkedHashSet은 **HashTable**과 **LinkedList**를 구현한 클래스로, HashSet의 문제점인 순서의 불명확성을 제거한 방법이다. LinkedHashSet에 삽입한 순서대로 저장된다.\n```java\n//HashSet\npublic class Test {\n\tpublic static void main(String[] args) {\n\t\tSet<Person> set = new HashSet<Person>();\n\t\tPerson p1 = new Person(\"Kim\", 10);\n\t\tPerson p2 = new Person(\"Lee\", 12);\n\t\tPerson p3 = new Person(\"Choi\", 14);\n\t\tPerson p4 = new Person(\"Park\", 16);\n\t\tPerson p5 = new Person(\"Kang\", 18);\n\t\t\n\t\tset.add(p1);\n\t\tset.add(p2);\n\t\tset.add(p3);\n\t\tset.add(p4);\n\t\tset.add(p5);\n\t\t\n\t\tfor(Person p : set) {\n\t\t\tSystem.out.println(p.toString());\n\t\t}\n\t}\n}\n/*\nname : Choi / age : 14\nname : Lee / age : 12\nname : Kang / age : 18\nname : Kim / age : 10\nname : Park / age : 16\n*/\n```\n```java\n//LinkedHashSet\npublic class Test {\n\tpublic static void main(String[] args) {\n\t\tSet<Person> set = new LinkedHashSet<Person>();\n\t\tPerson p1 = new Person(\"Kim\", 10);\n\t\tPerson p2 = new Person(\"Lee\", 12);\n\t\tPerson p3 = new Person(\"Choi\", 14);\n\t\tPerson p4 = new Person(\"Park\", 16);\n\t\tPerson p5 = new Person(\"Kang\", 18);\n\t\t\n\t\tset.add(p1);\n\t\tset.add(p2);\n\t\tset.add(p3);\n\t\tset.add(p4);\n\t\tset.add(p5);\n\t\t\n\t\tfor(Person p : set) {\n\t\t\tSystem.out.println(p.toString());\n\t\t}\n\t}\n}\n/*\nname : Kim / age : 10\nname : Lee / age : 12\nname : Choi / age : 14\nname : Park / age : 16\nname : Kang / age : 18\n*/\n```\n<br/>\n\n## TreeSet\nTreeSet은 삽입한 요소들의 값들을 정렬해서 반환해준다. TreeSet은 Comparable 인터페이스의 `compareTo()`나 Comparator 인터페이스의 `compare()`메소드를 이용해 값을 정렬하기 때문에, 사용자가 생성한 객체를 정렬하고자 하는 경우에는 Comparable 인터페이스나 comparator인터페이스를 구현한 클래스로 객체를 생성해야한다. \n\n> 참고 ) Im-D/Dev-Docs [Comparable vs Comparator\n](https://github.com/Im-D/Dev-Docs/blob/master/Java/Comparable%20vs%20Comparator.md) \n\n```java\npublic class Person implements Comparable<Person>{\n\tprivate int age;\n\t\n\tPerson(int age){\n\t\tthis.age = age;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn \"나이 : \" + this.getAge();\n\t}\n\n\t@Override\n\tpublic int compareTo(Person o) {\n\t\t// 오름차순\n\t\treturn this.age - o.age;\n\t}\n}\n```\n```java\npublic class test2 {\n\tpublic static void main(String[] args) {\n\t\tSet<Person> set = new TreeSet<Person>();\n\n\t\tset.add(new Person(14));\n\t\tset.add(new Person(12));\n\t\t\n\t\tfor(Person p : set) {\n\t\t\tSystem.out.println(p.toString());\n\t\t}\n\t}\n}\n```\n\n---\n#### Reference  \n\n[해싱, 해시함수, 해시테이블](https://ratsgo.github.io/data%20structure&algorithm/2017/10/25/hash/)\n\n\n[Set 컬렉션 클래스](http://tcpschool.com/java/java_collectionFramework_set)\n"
  },
  {
    "path": "Java/String, StringBuilder, StringBuffer.md",
    "content": "# String, StringBuilder, StringBuffer\n\n<br/>\n\n## String\n\n`Java`에서 `String`객체의 특성을 알고 있어야 `StringBuilder`와 `StringBuffer`의 차이를 알 수 있다.\n\n`String`객체는 `char[]`배열로 이뤄져있으며, 기본적으로 `immutable(변경불가능)`하다. <br/>`+`나 `concat` 메서드를 이용해 새로운 문자열을 합치려하면 **기존 `String`객체가 가리키고 있던 문자열을 복사하고 새로운 문자열을 덧붙여 새로운 객체를 반환**한다. 이후 기존 객체는 `GC`에 의해 메모리가 회수된다.\n\n이러한 특성 때문에 `String`객체는 메모리의 낭비로 이어질 수 있다는 단점이 있다. 하지만, `immutable`한 특성 때문에 `thread-safe`하다. 즉, `multi-thread`환경에서 동시에 객체에 접근하더라도 변하지 않기 때문에 동기화를 고려하지 않고 내부적으로 데이터를 공유할 수 있다.\n\n<br/>\n\n## StringBuilder vs StringBuffer\n\n`StringBuilder` 와 `StringBuffer`는 `mutable(변경 가능)`하다. 문자열을 덧붙이거나 합칠 시 새로운 객체를 반환하지 않고 기존 객체의 버퍼 크기를 늘리며 문자열을 추가한다.\n\n단, 이 두 가지의 차이점은 `multi-thread`환경에서의 **동기화 문제에 대한 처리**에서 나온다.\n\n<br/>\n\n### StringBuilder\n\n---\n\n`StringBuilder`는 `String`에서 `+`나 `concat`메서드를 통한 연산이 많은 경우 사용하는것이 좋다. 단, **동기화에 대한 처리를 하지 않는다.** 따라서 `StringBuffer`에 비해 성능 면에서 좋고, `multi-thread`환경이 아니라면 `StringBuilder`을 사용하는 것이 좋다.\n\n사실, `jdk1.5`이후 부터 `String`객체는 컴파일 타임에 `StringBuilder`로 변경된다. 즉, `String` 클래스를 이용하여 객체를 생성하더라도 `StringBuilder`로 컴파일되어 동작하기 때문에 `jdk1.5`이후부터는 `StringBuilder`를 사용할 이유가 없어졌다.\n\n\n### StringBuffer\n\n---\n\n`StringBuffer`는 내부적으로 모든 메소드에 대해 `synchronized` 키워드가 붙어있다. 즉, **동기화 처리를 하고 있고 이 덕분에 `StringBuilder`와 비교해서 `thread-safe`하다.**\n\n하지만, `multi-thread`환경이 아닐 때 사용한다면 `StringBuilder`에 비해 **성능 면에서 떨어질 수 있기 때문에 이 점을 고려하여 사용**해야 한다.\n\n> `Java`의 `synchronized` 키워드는  쉽게 생각하면 **multi-thread로 동시접근되는것을 막는다** 라고 볼 수 있다. <br/>\n> 예를 들어, **함수에 synchronized를 걸면 그 함수가 포함된 해당 객체에 lock을 건다**라고 볼 수 있다.\n\n<br/>\n\n---\n\n#### Reference\n\n- [자바가상머신, JVM(Java Virtual Machine)이란 무엇인가?](https://asfirstalways.tistory.com/158)\n- [JAVA String, StringBuffer, StringBuilder 차이점](https://jeong-pro.tistory.com/85)\n\n"
  },
  {
    "path": "Java/String,StringBuilder, StringBuffer차이.md",
    "content": "# String, StringBuilder, StringBuffer의 차이점과 장단점\nString, StringBuilder, StringBuffer는 문자열 클래스들이다. 모두 문자열을 저장하고 관리하는 클래스인데 무엇이 다를까?\n\n면접 시 자주 나오는 질문 중에 하나이기 때문에 정리를 해보았다.\n\n## String\n`String`은 문자열을 대표하는 것으로 문자열을 조작하는 경우 유용하게 사용할 수 있다.\n\n먼저 `String`과 다른 클래스(StringBuffer, StringBuilder)의 차이점은 String은 **immutable**(불변), `StringBuffer`, `StringBuilder`는 **mutable**(변함)에 있다.\n\n`String` 객체는 한번 생성되면 할당된 **메모리 영역이 변하지 않는다**. \n\n`+연산자` 또는 `concat` 메소드를 통해 기존에 생성된 String 객체 문자열에 다른 문자열을 붙인다고 하자,\n\n기존 문자열에 새로운 문자열을 붙이는 것이 아니라 새로운 String 객체를 만든 후, 새 String 객체에 연결된 문자열을 저장하고 그 객체를 참조하도록 한다.\n\n즉, `String` 클래스 객체는 **Heap 메모리 영역**(가비지 컬렉션이 동작하는 영역)에 생성하고 한번 생성된 객체의 내부 내용을 변화시킬 수 없다.\n\n이렇게 새로운 문자열이 만들어지면 '기존의 문자열'은 가비지 컬렉터에 의해 제거돼야 하는 단점이 있다.\n\n> **heap 메모리 영역**이란 프로그램이 운영체제로부터 할당받는 메모리 공간 중 하나로, 메모리 공간이 동적으로 할당되고 해제된다. \n\n> **Garbage Collection**란 Heap 영역의 메모리를 JVM이 판단해 더 이상 사용되지 않는 인스턴스는 자동으로 할당된 메모리를 삭제하는 역할을 하는 행위이다.  \n\n이해를 돕도록 아래의 예시를 보자.\n\n<img width=\"689\" alt=\"String 객체\" src=\"https://user-images.githubusercontent.com/43868540/90954396-e1aee780-e4ae-11ea-8e48-87104b8c0fde.png\">\n<img width=\"492\" alt=\"String 객체 특성\" src=\"https://user-images.githubusercontent.com/43868540/90954520-dc05d180-e4af-11ea-9c7a-f4559a2fd088.png\">\n<img width=\"577\" alt=\"String 주소값\" src=\"https://user-images.githubusercontent.com/43868540/90955221-b0d2b080-e4b6-11ea-8ca3-4c340a5218ed.png\">\n\n> [출처 ifuwanna.tistory](https://ifuwanna.tistory.com/221)\n\n위에 예제에서 \"hello\"값을 가지고 있던 String 클래스의 참조 변수 str이 가리키는 곳에 \"world\"문자열을 더해 \"hello world\"로 변경한 것으로 착각할 수 있다.\n\n하지만 \"hello\"값이 들어가 있던 String 클래스의 참조 변수 str이 \"hello world\"라는 값을 가지고 있는 새로운 메모리 영역을 가리키게 변경되고 기존에 \"hello\"로 값이 할당되어 있던 메모리 영역은 가비지 컬렉션에 의해 사라지게 된다.\n\n이클립스를 사용해 주소값을 출력해보니 가리키는 메모리 영역이 다른 것을 확인할 수 있다.\n\n따라서 `String` 객체는 이러한 이유로 문자열 연산이 많은 경우, 계속해서 문자열 객체를 만들기 때문에 **오버헤드**가 발생해 그 성능이 좋지 않다.\n\n하지만 `String` 객체와 같이 **Immutable**한 객체는 간단하게 사용 가능하고 불변하기 때문에 동기화에 대해 신경 쓰지 않아도 되기 때문에 멀티 스레드 환경에서 사용가능하다. \n\n### String 클래스가 적절한 경우\n결론적으로 `String` 클래스는 문자열 연산이 적고, 자주 참조하는 경우에 사용하면 좋다. \n\n## StringBuffer와 StringBuilder\n그러면 `StringBuffer`와 `StringBuilder` 클래스를 한번 보도록 하자\n\n`StringBuffer`/`StringBuilder`는 `String`과 다르게 동작한다.\n\n`String` 과는 반대로 `StringBuffer/StringBuilder`는 가변성을 가지기 때문에 `.apppend()` `.delete()` 등의 API를 이용하여 동일 객체 내에서 문자열을 변경하는 것이 가능하다.\n\n<img width=\"701\" alt=\"StringBuffer, StringBuilder\" src=\"https://user-images.githubusercontent.com/43868540/90954550-1a02f580-e4b0-11ea-9881-a103c93c1d8a.png\">\n<img width=\"556\" alt=\"StringBuffer 주소\" src=\"https://user-images.githubusercontent.com/43868540/90955243-e7a8c680-e4b6-11ea-9f26-fa5c0d67fa90.png\">\n\n> [출처 ifuwanna.tistory](https://ifuwanna.tistory.com/221)\n\n위에 `StringBuffer` 클래스가 참조하는 sb 객체에 \"hello\"를 저장하고, 이 객체에 `.append()`를 이용해 \"world\"를 더하면 sb 객체가 가리키는 메모리 영역은 변하지 않는다.\n`StringBuilder` 클래스를 사용하는 경우에도 값은 동일했다.\n\n문자열 연산을 할 때, 클래스는 한 번만 만들고 메모리의 값을 변경시켜서 문자열을 변경한다. 문자열 연산(추가, 수정, 삭제)이 자주 있을 때 사용하면 성능이 좋다는 장점이 있다.\n\n그렇다면 두 클래스의 차이점은 무엇일까?\n바로 **동기화 여부**이다.\n\n`StringBuffer`는 각 메소드 별로 **Synchronized Keyword**가 존재하여, 멀티 스레드 환경에서도 **동기화를 지원**한다. \n\n여러 스레드로부터 동시에 접근이 일어나도 프로그램의 실행에 문제가 없는 것을 **thread-safe**라고 한다.\n\n반면, `StringBuilder`는 동기화를 보장하지 않기 때문에 thread-safe 하지 않다.\n\n이러한 특성 때문에 멀티 스레드 환경이라면 값 동기화 보장을 위해 `StringBuffer`를 사용하고, \n단일 스레드 환경이라면 `StringBuilder`를 사용하는 것이 좋다.\nStringBuilder가 동기화를 고려하지 않기 때문에 단일 스레드 환경에서 StringBuffer에 비해 연산처리가 빠른 장점이 있다.\n\n### StringBuffer, StringBuilder가 적절한 경우\n결론적으로 문자열 연산이 많을 때 두 클래스를 사용하지만 멀티 스레드 환경에서는 `StringBuffer`를 사용하면 좋고, 단일 스레드 환경이거나 멀티 스레드여도 굳이 동기화가 필요 없는 경우에는 `StringBuilder`를 사용하는 것이 좋다.\n\n### 정리\n- `String` : 문자열 연산이 적고 멀티 쓰레드 환경일 경우\n- `StringBuffer` : 문자열 연산이 많고 멀티 쓰레드 환경일 경우\n- `StringBuilder` : 문자열 연산이 많고 단일 쓰레드이거나 동기화를 고려하지 않아도 되는 멀티 쓰레드일 경우\n\n----\n#### Reference\n- [String, StringBuffer, StringBuilder의 차이](https://12bme.tistory.com/42)\n- [String, StringBuffer, StringBuilder](https://jeong-pro.tistory.com/85)\n"
  },
  {
    "path": "Java/Upcasting과 Downcasting.md",
    "content": "# Upcasting / Downcasting\n먼저, casting이란 형변환을 말하며 Upcasting과 Downcasting은 참조형을 형변환하는 개념이다.   \n참조형이 형변환되는 경우는 다음과 같다.\n1. 클래스 상속시\n2. 인터페이스 확장시  \n\n때문에 Upcasting과 Downcasting은 다형성과 관련이 높다.\n\n<br/>\n\n# 클래스 상속에서의 Upcasting\n`Parent parent = new Child();`\n1. 자식 클래스로 생성한 객체가 부모 클래스 타입으로 형변환되는 형태이다.\n2. 자식 클래스는 부모 클래스의 변수 및 메소드를 갖고 있기 때문에 암묵적 형변환이 가능하다.  \n3. 형변환된 객체는 본래 클래스의 변수 및 메소드에 접근할 수 없다. 다시 접근하기 위해서는 Downcasting이 필요하다. \n4. Upcasting을 이용해 한 곳에서 제어할 수 있다. \n\n```java\npublic class Vehicle {\n    private int seat;\n\n    public Vehicle() { }\n\n    public Vehicle(int seat) {\n        this.seat = seat;\n    }\n\n    public String ride() {\n        return \"운전중\";\n    }\n\n    public int getSeat() {\n        return seat;\n    }\n\n    public void setSeat(int seat) {\n        this.seat = seat;\n    }\n}\n```\n```java\npublic class Bus extends Vehicle{\n    private String company;\n\n    Bus(int seat, String company){\n        super(seat);\n        this.company = company;\n    }\n\n    public String getCompany() {\n        return company;\n    }\n\n    public void setCompany(String company) {\n        this.company = company;\n    }\n}\n```\n```java\npublic class Car extends Vehicle{\n    private String operator;\n\n    public Car() { };\n\n    public Car(int seat, String operator) {\n        super(seat);\n        this.operator = operator;\n    }\n\n    public String getOperator() {\n        return operator;\n    }\n\n    public void setOperator(String operator) {\n        this.operator = operator;\n    }\n}\n```\n```java\npublic class Person {\n\t\n    public String driving(Vehicle vehicle) {\n        return vehicle.ride();\n    }\n}\n```\n위의 예제에서 `Car`와 `Bus`는 `Vehicle`을 상속 받고 있으며, `Person`클래스는 파라미터로 `Vehicle`의 객체를 받아, `ride()`를 실행하는 메소드를 가지고 있다. 다음 `main()`를 확인해보자.\n\n```java\npublic class Main {\n\t\n    public static void main(String[] args) {\n        Person p = new Person();\n\n        Car c1 = new Car(4, \"operator1\");\n        Car c2 = new Car(6, \"operator2\");\n        Bus b1 = new Bus(10, \"company1\");\n        Bus b2 = new Bus(40, \"company2\");\n\n        System.out.println(p.driving(c1));\n        System.out.println(p.driving(c2));\n        System.out.println(p.driving(b1));\n        System.out.println(p.driving(b2));\n    }\n}\n```\n`driving()`는 파라미터로 `Vehicle`타입을 받는 메소드다. 하지만 위 예제처럼 `Car`와 `Bus`타입을 파라미터로 넘겨줘도 메소드는 정상적으로 작동된다. 자동적으로 `Car`와 `Bus`의 객체들이 `Vehicle`타입으로 **Upcasting**되었기 때문이다. 따라서 객체마다 따로따로 파라미터로 넘겨줘도 상관은 없지만, 다음과 같이 Upcasting을 직접 해주면 한 곳에서 처리해줄 수 있다.   \n\n```java\npublic class Main {\n\t\n    public static void main(String[] args) {\n    \t  Person p = new Person();\n\n          List<Vehicle> list = new ArrayList<Vehicle>();\n          list.add(new Car(4, \"operator1\"));\n          list.add(new Car(6, \"operator2\"));\n          list.add(new Bus(10, \"company1\"));\n          list.add(new Bus(40, \"company2\"));\n\n          for(Vehicle v : list) {\n              System.out.println(p.driving(v));\n          }\n    }\n}\n```\n\n한편, 위에서 Upcasting의 또 다른 특징으로 Upcasting된 객체는 더이상 자식클래스의 변수 및 메소드에 접근할 수 없다고 적어놨다. 하지만, 부모클래스의 메소드를 오버라이딩한 메소드는 접근할 수 있다. 다음 코드를 보자. \n\n```java\npublic class Bus extends Vehicle{\n\tprivate String company;\n\n    Bus(int seat, String company){\n        super(seat);\n        this.company = company;\n    }\n\n    public String getCompany() {\n        return company;\n    }\n\n    public void setCompany(String company) {\n        this.company = company;\n    }\n\n\t@Override\n\tpublic String ride() {\n\t\treturn \"버스 운행중\";\n\t}\n}\n```\n```java\npublic class Car extends Vehicle{\n    private String operator;\n\n    public Car() { };\n\n    public Car(int seat, String operator) {\n        super(seat);\n        this.operator = operator;\n    }\n\n    public String getOperator() {\n        return operator;\n    }\n\n    public void setOperator(String operator) {\n        this.operator = operator;\n    }\n\n\t@Override\n\tpublic String ride() {\n\t\treturn \"소형차 운행중\";\n\t}\n}\n```\n```java\npublic class Main {\n\t\n    public static void main(String[] args) {\n        Person p = new Person();\n\n        List<Vehicle> list = new ArrayList<Vehicle>();\n        list.add(new Car(4, \"operator1\"));\n        list.add(new Car(6, \"operator2\"));\n        list.add(new Bus(10, \"company1\"));\n        list.add(new Bus(40, \"company2\"));\n\n        for(Vehicle v : list) {\n            System.out.println(p.driving(v));\n        }\n    }\n}\n```\n`Bus`와 `Car`는 각각 `ride()`를 오버라이딩했고, 위 코드의 실행결과로 다음이 출력된다. \n```java\n// 소형차 운행중\n// 소형차 운행중\n// 버스 운행중\n// 버스 운행중\n```\n<br/>\n\n# 인터페이스에서의 Upcasting\n다음 코드를 먼저 보자.\n```java\npublic interface CarImpl {\n    public String ride();\n}\n```\n```java\npublic class Bus implements CarImpl{\n\n    @Override\n    public String ride() {\n        \n        return \"버스 운행중\";\n    }\n}\n```\n```java\npublic class Main {\n\t\n    public static void main(String[] args) {\n        Bus bus = new Bus();\n\n        System.out.println((bus instanceof CarImpl)?\"CarImpl\":\"Bus\");\n    }\n}\n```\n`Bus`은 `CarImpl`을 확장한 클래스다. `main()`에서 `instanceof` 연산을 통해 `bus`의 실제 타입을 알아보았다. 만약 `bus`의 실제 타입이 `CarImpl`이라면 `true`가 반환되어 `CarImpl`이 출력될 것이고, 아니라면 `false`가 반환되어 `Bus`이 출력될 것이다. 출력 결과는 `CarImpl`이다.  \n`bus`은 `CarImpl`로 **upcasting**된 것이다.  \n\n<br/>\n\n# Downcasting\n```java\nParent parent = new Child(); //Upcasting\nChild child = (child) parent;\n```\n1. 부모 클래스로 생성한 객체가 자식 클래스 타입으로 형변환되는 형태이다.\n2. 부모 클래스는 자식 클래스의 모든 변수 및 메소드를 갖지 않기 때문에 명시적으로 형변환을 해줘야한다.  \n\n## Downcasting / ClassCastException 에러  \n만약 위의 코드를 다음과 같이 수정하면 컴파일 에러, `ClassCastException`가 발생한다.\n```java \nChild child = (Child) new Parent();\n``` \nJVM은 `Parent`의 객체를 `Child`타입으로 형변환하려고 한다. 하지만, `Parent`는 `Child`에서 확장된 변수 및 메소드를 갖지 않고, JVM은 `Child`의 데이터를 알 수 없기 떄문에 형변환을 해줄 수 없다. \n```java\nParent parent = new Child();\nChild child = (child) parent;\n``` \n이 코드가 정상적으로 실행되는 이유는 `Child` 객체로 생성된 `parent`로 JVM이 `Child`의 데이터를 알 수 있었기 때문이다.      \n<br/>  \n\n---\n#### Reference\n[Casting (형변환 : 캐스팅)](https://inor.tistory.com/40)  \n[JAVA - DownCasting(다운캐스팅)](https://mommoo.tistory.com/51)\n"
  },
  {
    "path": "Java/WAS.md",
    "content": "# WAS(Web Application Server)\n\n## 웹 서버(Web Server)\n\n클라이언트가 요청한 문서나 자원을 전달하는 역할을 한다.\n\n클라이언트는 서버에게 서비스를 요청한다.\n\n서버는 서비스 제공한다.\n\n![tier1](../assets/images/was1.png)\n\n<br/>\n\n## 2-Tier Architecture\n\n![tier2](../assets/images/was2.png)\n\n### DBMS(Data Base Management System)\n\nDBMS등장 이전에는 데이터를 저장하고 불러오는것을 직접 구현 해야했다. 하지만, 데이터가 많아지며 별도의 관리가 필요해졌고 DBMS가 등장하였다. \n\n<br/>\n\nDMBS는 보통 서버 형태로 서비스를 제공한다. 따라서 DBMS에 직접 접속해서 동작하는 클라이언트 프로그램이 만들어졌다.\n\n이러한 방식은 클라이언트의 로직이 많아지고, 클라이언트 프로그램의 크기가 커지며, 로직이 변경되면 클라이언트가 새로 배포되어야 한다.\n\n또한, 로직이 클라이언트에 포함되어 배포되기 때문에 보안이 나쁘다.\n\n<br/>\n\n### CGI(Common Gateway Interface)\n\n초기 웹은 정적 데이터만 보여줬다. 웹 서버 본연의 기능은 미리 준비된 정보(정적 리소스)를 클라이언트의 요청에 따라 응답해주는 것이기 때문이다.\n\n웹이 발전하며 동적인 기능을 요구하기 시작했다. 지금은 너무 당연하지만, 웹에서 데이터를 입력하고 조회하는 것 또한 동적인 기능이다.\n\n당연히, 이러한 기능들은 별도의 프로그래밍을 통해 구현해야 한다. 이를 위해 웹 서버에서 프로그래밍 기능이 들어가는 방식을 CGI라고 한다.\n\n> 서버 프로그램 내부의 프로그램에서 처리한 결과를 클라이언트에 응답하도록 서버와 내부 프로그램을 이어주는 방법 혹은 규칙이 CGI이다.\n\n<br/>\n\n단순한 프로그래밍에서는 문제가 없었다. 하지만, 프로그램이 복잡해지고 DBMS와 연계되는 작업이 많아지면서 사용자가 증가할수록 성능이 떨어지는 문제가 발생했다.\n\n<br/>\n\n## 3-Tier Architecture\n\n![tier3](../assets/images/was3.png)\n\n### 미들웨어(MiddleWare)\n\n2-Tier Architecture의 단점으로 미들웨어가 등장하게 되었다. 클라이언트와 데이터베이스 서버 사이에 다른 서버를 두는 방식이다.\n\n클라이언트는 요청만 보내고, 미들웨어에서 로직을 수행한다. 만약, 데이터 조작이 필요하면 미들웨어가 DBMS에 작업을 맡기고 그 결과를 클라이언트에게 전달한다.\n\n클라이언트는 응답을 받아서 출력만 하면되고, 미들웨어에 요청만 보내면 되기 때문에 프로그램의 크기가 줄어든다. 또한, 로직이 바뀌어도 다시 배포할 필요 없이 미들웨어만 수정하면 된다.\n\n<br/>\n\n## WAS(Web Application Server)\n\n넓은 의미에서 미들웨어라고 할 수 있다.\n\n웹 클라이언트의 요청 중 웹 애플리케이션이 동작하도록 지원하는 목적을 가진다.\n\n<br/>\n\n### 기능\n\n- 프로그램 실행환경과 데이터 베이스 접속 기능을 제공한다.\n- 여러 개의 트랜젝션을 관리한다.\n- 업무 처리 비즈니스 로직을 수행한다.\n\n<br/>\n\n이외에도 웹 서버의 기능도 기본적으로 제공한다(톰캣만 설치해도 별도의 웹 서버가 필요 없는 이유이다).  하지만, 초창기의 WAS는 내장 웹서버의 성능이 좋지 않았다. 따라서 아파치 서버와 톰캣 서버를 함께 실행을 해서 사용하는 경우가 많았다. 하지만, 현재는 WAS에 내장되어 있는 웹 서버의 성능이 많이 개선되어 톰캣만으로도 충분히 동작하는 경우가 많아졌다.\n\n하지만, 그럼에도 큰 규모의 프로젝트에서는 웹 서버에서 정적인 컨텐츠를 웹 브라우저로 전송하고, WAS는 동적인 결과를 전송하는 역할을 하도록 나눈다.\n\n![tier4](../assets/images/was4.png)\n\n### WAS와 웹 서버를 나누는 이유\n\n- 자원 이용의 효율성\n    - 웹 서버는 보다 간단하게 만들어졌다. 따라서, 정적인 동작은 웹 서버에서 하는 것이 더 효율적이다.\n- 장애 극복(failvoer)\n    - WAS에서 동작하도록 만든 프로그램이 오작동하여 WAS자체에 문제가 발생할 수 있다. 따라서 WAS를 재시작 해야 하는 경우가 생길 수 있다. 만약 WAS 서버가 여러개 있다면, 문제가 발생한 WAS에 웹 서버에서 클라이언트가 접근 하지 못하게 한 뒤  WAS의 문제를 처리할 수 있다. 따라서, 무중단으로 서비스를 운영할 수 있다.\n        > 참고 - [로드밸런싱과 클러스터링](https://github.com/Im-D/Dev-Docs/blob/master/Network/%EB%A1%9C%EB%93%9C%EB%B0%B8%EB%9F%B0%EC%8B%B1%20&%20%ED%81%B4%EB%9F%AC%EC%8A%A4%ED%84%B0%EB%A7%81.md)\n- 배포 및 유지 보수의 편의성\n\n<br/>\n\n---\n\n#### References\n\n- [WAS - 부스트코스](https://www.edwith.org/boostcourse-web/lecture/16666/)\n- [CGI - 정보통신기술용어해설](http://www.ktword.co.kr/word/abbr_view.php?m_temp1=651&m_search=cgi)\n- [common gateway interface (CGI)](https://whatis.techtarget.com/definition/common-gateway-interface-CGI)\n- [What is Difference Between Two-Tier and Three-Tier Architecture?](http://www.softwaretestingclass.com/what-is-difference-between-two-tier-and-three-tier-architecture/)\n"
  },
  {
    "path": "Java/copy-object.md",
    "content": "# 객체 복사\n\n객체 지향 프로그래밍에서 객체를 복사하는 방법에 크게 두 가지가 있다.\n\n- 얕은 복사(shallow copy) : 참조(메모리 주소)를 복사\n- 깊은 복사(deep copy) : 참조하는 메모리 안의 값을 복사\n\n> 참고 - [객체 복사 - 복사 방식](https://ko.wikipedia.org/wiki/%EA%B0%9D%EC%B2%B4_%EB%B3%B5%EC%82%AC#%EB%B3%B5%EC%82%AC_%EB%B0%A9%EC%8B%9D)\n\n## 얕은 복사\n\n얕은 복사를 할 경우 객체 인스턴스의 주소가 복사된다.\n\n```java\nObject original = new Object();\nObject shallowCopy = original;\n\noriginal.equals(new Object()); // false\noriginal.equals(shallowCopy); // true\n```\n> 참조를 저장한 변수 명은 달라지지만, 같은 인스턴스를 공유한다. 정확히는 같은 인스턴스를 공유하는 다른 이름의 변수가 생성된 것이다.\n\n얕은 복사는 같은 인스턴스를 공유한다. 따라서 복사한 변수를 이용하여 인스턴스의 필드를 바꾸게 되면 원본 객체의 필드도 변화한다.\n\n```java\nclass UserInfo{\n    private String name;\n    \n    // standard constructors, getters and setters\n}\n```\n\n```java\nvoid shallowCopyTest(){\n    UserInfo someUser = new UserInfo(\"someName\");\n    UserInfo shallowCopy = someUser;\n    \n    shallowCopy.setName(\"changedName\");\n    \n    someUser.getName(); // It returns \"changedId\"\n    shallowCopy.getName(); // It return \"changedId\"\n}\n```\n\n깊은 복사를 할 경우 이를 해결할 수 있다.\n\n## 깊은 복사\n\n깊은 복사를 할 경우 복사한 변수를 이용하여 인스턴스의 필드를 변경해도 원본 객체가 변하지 않는다.\n\n```java\nvoid deepCopyTest(){\n    UserInfo someUser = new UserInfo(\"someName\");\n    UserInfo deepCopy = ...; /*something for deep copy...*/\n    \n    deepCopy.setName(\"changedName\");\n    \n    someUser.getName(); // It returns \"someId\"\n    deepCopy.getName(); // It returns \"changedId\"\n}\n```\n\nJava에서 깊은 복사를 하는 방법에는 크게 세 가지가 있다.\n\n- 새로운 객체를 생성하여 값을 직접 넣어준다.\n- 복사 생성자나 팩토리 메서드를 사용한다.\n- Cloneable Interface를 구현한다.\n\n### 값을 직접 넣어주기\n\n가장 간단한 방법이다.\n\n```java\nvoid deepCopyTest(){\n    UserInfo someUser = new UserInfo(\"someId\", \"someName\");\n    UserInfo deepCopy = new UserInfo(someUser.getId(), someUser.getName());\n    \n    deepCopy.setId(\"changedId\");\n    deepCopy.setId(\"changedName\");\n    \n    someUser.getId(); // It returns \"someId\"\n    deepCopy.getId(); // It returns \"changedId\"\n}\n```\n\n예제는 `UserInfo` 클래스의 필드가 두 개 밖에 없으므로 간단히 작성할 수 있지만, 만약 필드가 많아진다면 객체를 복사할 때 마다 많은 작업을 해야 할 것이다.\n\n```java\nUserInfo deepCopy = new UserInfo(someUser.getId(), someUser.getName(), someUser.getAddress(), someUser.getCellPhoneNumber, someUser.getSex(), someUser.getAlias(), someUser.get...);\n```\n\n생성자를 사용하지 않는다면 매번 필드 수 만큼의 불필요한 라인이 추가될 것이다.\n\n```java\nUserInfo deepCopy1 = new UserInfo();\ndeepCopy.setId(someUser.getId());\ndeepCopy.setName(someUser.getName())\ndeepCopy.setAddress(someUser.getAddress())\ndeepCopy.setCellPhoneNumber(someUser.getCellPhoneNumber)\ndeepCopy.setSex(someUser.getSex());\ndeepCopy.setAlias(someUser.getAlias());\ndeepCopy.set...;\n\nUserInfo deepCopy2 = new UserInfo();\ndeepCopy.setId(someUser.getId());\ndeepCopy.setName(someUser.getName())\ndeepCopy.setAddress(someUser.getAddress())\ndeepCopy.setCellPhoneNumber(someUser.getCellPhoneNumber)\ndeepCopy.setSex(someUser.getSex());\ndeepCopy.setAlias(someUser.getAlias());\ndeepCopy.set...;\n```\n\n다른 방법들을 사용하면 이 문제를 해결할 수 있다.\n\n### 복사 생성자(Copy Constructor)\n\n복사 생성자는 말 그대로 객체를 복사하는 생성자를 만들어 주는 것이다.\n\n```java\n// UserInfo의 복사 생성자\npublic UserInfo(UserInfo userInfo){\n    this.name = userInfo.getName();\n    this.Address = new Address(userInfo.getAddress());\n    /* 다음과 같이 구현할 수도 있다.\n     * this(userInfo.getName(), userInfo.getAddress());\n     */\n}\n\n// Address의 복사 생성자\npublic Address(Address address){\n    this.name = address;\n}\n```\n\n### 복사 팩토리(Static Factory Method, 정적 팩토리 메서드)\n\n복사 팩토리는 복사 생성자의 변형이다.\n\n> 팩토리 패턴과 다르다.\n\n```java\npublic static UserInfo newInstanceCopiedByUserInfo(UserInfo userInfo){\n    return new UserInfo(userInfo);\n    /* 복사 생성자를 만들지 않았다면 다음과 같이 구현할 수도 있다.\n     * this(userInfo.getName(), userInfo.getAddress());\n     */\n}\n```\n\n> 복사 팩토리는 이름을 가질 수 있기 때문에 복사 생성자를 쓴 것 보다 기능을 더욱 명확하게 나타낼 수 있는 장점이 있다. 복사 생성자는 기능이 명확하고 단순하기 때문에 복사 팩토리의 장점이 많이 드러나지 않지만, 일반적으로 생성자 대신 복사 팩토리를 사용하면 생기는 이점들이 있다. 이는 다음 글들을 참고하면 좋을 것 같다.\n>\n> - [Java Constructors vs Static Factory Methods](https://www.baeldung.com/java-constructors-vs-static-factory-methods)\n> - [정적 팩토리 메서드(static factory method)](https://johngrib.github.io/wiki/static-factory-method-pattern/)\n\n### Cloneable Interface\n\n복사를 구현할 객체에 `Cloneable`을 구현하고, `Object.clone()`을 재정의 하여 사용한다. `Cloneable`을 구현하지 않고 `Object.clone()`만 재정의하여 사용할 경우 `CloneNotSupportedException`이 발생한다.\n\n```java\nclass UserInfo implements Cloneable{\n    private String id;\n    private String name;\n    \n    // standard constructors, getters and setters\n    \n    @Override\n    protected UserInfo clone() throws CloneNotSupportedException {\n      return (UserInfo) super.clone();\n  }\n}\n```\n\n```java\nvoid cloneableTest(){\n    UserInfo someUser = new UserInfo(\"some id\", \"some name\");\n    UserInfo deepCopy = someUser.clone();\n    \n    deepCopy.setId(\"changed id\");\n    deepCopy.setId(\"changed name\");\n    \n    someUser.getId(); // It returns \"someId\"\n    deepCopy.getId(); // It returns \"changedId\"\n}\n```\n\n>  참고 - [Interface Cloneable](https://docs.oracle.com/javase/8/docs/api/java/lang/Cloneable.html)\n\n```java\nclass UserInfo implements Cloneable{\n    private String name;\n    private Address address;\n    \n    // standard constructors, getters and setters\n    \n    @Override\n    protected UserInfo clone() throws CloneNotSupportedException {\n      return (UserInfo) super.clone();\n  }\n}\n\nclass Address {\n  private String name;\n\n  // standard constructors, getters and setters\n}\n```\n\n만약 위와 같이 클래스 필드가 값이 아닌 주소를 참조하는 객체일 경우 해당 객체는 깊은 복사가 되지 않는다.\n\n```java\nvoid cloneableTest(){\n    UserInfo someUser = new UserInfo(\"some name\", new Address(\"address name\"));\n    UserInfo deepCopy = someUser.clone();\n    \n    deepCopy.getAddress().setName(\"changed address Name\");\n    \n    someUser.getAddress().getName(); // It returns \"changed address Name\"\n    someUser.getAddress().getName(); // It returns \"changed address Name\"\n}\n```\n\n이럴 경우 `Address`에 `clone()` 메소드를 구현한 뒤 , `UserInfo`의 `clone()` 메소드를 아래처럼 정의해야 한다.\n\n```java\n@Override\nprotected UserInfo clone() throws CloneNotSupportedException {\n    UserInfo result = (UserInfo) super.clone();\n    result.setAddress(result.getAddress().clone());\n\n    return result;\n}\n```\n\n> 참조로 인한 변경 가능성을 낮추기 위해 객체 필드를 final로 선언할 경우 위와 같은 방법은 사용할 수 없다.\n\n### Cloneable은 지양하는 것이 바람직하다\n\n#### 언어모순적이다\n\nJava에서 새로운 객체를 생성하기 위해서 `new` 키워드와 생성자를 사용하기로 약속되어있다. 하지만 `clone()`을 사용하면 이러한 동작 없이 새로운 객체를 생성한다. 새로운 객체를 생성하는 규칙을 클라이언트에게 맡기는 것은 위험한 일이다.\n\n#### clone의 규약은 허술하다\n\n`clone()`의 일반 규약은 매우 허술하다. api문서에서 조차 클래스마다 'copy'의 의미가 달라질 수 있다고 말한다. 따라서 예시에서 사용했던 것과 같이 특정 클래스의 경우 `clone()`이 잘 동작하게 하기 위해 새롭게 재정의하여야 한다.\n\n> 참고 - [Object.clone](https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#clone--)\n\n#### 고려해야 할 사항이 많다\n\n1. `Cloneable` 은 해당 클래스가 `Object.clone()`을 사용할 것이라고 명시적으로 선언해주는 역할을 하는 인터페이스다. `Cloneable` 인터페이스 내에 아무 것도 작성되어있지 않기 때문에 `Object`의 `clone()` 을 직접 재정의해야 한다. 이 때, `clone()`은 `Object` 타입을 리턴하기 때문에 리턴타입을 수정하고 `return` 문에서는 형변환을 해주어야 쓰기 편리하다.\n\n2. 정상적인 설계라면 `Clonable` 안에 `clone()`을 정의하여 `Cloneable`을 구현할때 `clone()`을 구현하지 않을 경우 컴파일 오류를 발생 시키는 식으로 되어야 한다. \n   ![interface Clonealbe](../assets/images/copy-object01.png)\n    > `java.lang.Cloneable`은 위와 같이 작성되어있다.\n    \n   하지만, 위에서 설명했듯 `Clonable` 인터페이스 내에 아무것도 작성되어있지 않다.\n   이러한 설계 오류로 인해 `clone()` `CloneNotSupportedException`을 추가했다. 따라서 `clone()` 을 편하게 쓰려면 이에 대한 처리를 해줘야 한다.\n\n   ```java\n   @Override\n   protected UserInfo clone() throws CloneNotSupportedException {\n       try {\n         UserInfo result = (UserInfo) super.clone();\n         result.setAddress(result.getAddress().clone());\n   \n         return result;\n       } catch (CloneNotSupportedException e) {\n         throw new AssertionError(); // 발생할 수 없는 일이다.\n       }\n   }\n   ```\n\n3. 또한 방어적 코딩을 위해 validation을 해주는 것이 필요할 수 있다.\n\n   ```java\n   if(someUser instanceof Cloneable){\n       deepCopy = someUser.clone();\n   }\n   ```\n\n복사 생성자 혹은 복사 팩토리와 `Cloneable`을 잘 비교한 글들이 있는데, 더 자세히 알고 싶다면 아래의 글을 읽어보길 권한다.\n\n- [Copy Constructor versus Cloning - Josh Bloch on Design](https://www.artima.com/intv/bloch.html#part13)\n- [Java Cloning - How Copy Constructors are Better Than Cloning](https://www.programmingmitra.com/2017/01/Java-cloning-copy-constructor-versus-Object-clone-or-cloning.html)\n\n#### References\n\n- [Effective Java 3/E](https://github.com/WegraLee/effective-java-3e-source-code)\n"
  },
  {
    "path": "Java/date-api-in-java.md",
    "content": "# Java의 날짜 API\n\nJDK8 이전의 Java에서는 `java.util.Date` 클래스와 `java.util.Calendar` 클래스를 이용하여 날짜를 다룬다. 하지만 이는 사용하기 불편하기 때문에 대체하는 여러 라이브러리가 나왔는데, JDK8 이후에는 이를 반영한 개선된 API를 제공한다.\n\n날짜와 시간 계산은 사회 제도나 과학과 복잡하게 얽혀있다. Java의 API들도 마찬가지로 이에 따른 영향을 받는다. Java의 API들을 본격적으로 살펴보기 전에 그 배경을 잠깐 살펴보고, JDK8이전의 날짜 API와 이후의 API를 살펴보자.\n\n## 율리우스력과 그레고리력\n\n### 최초의 달력과 율리우스력\n\n날짜는 고대 농경사회에서 비슷한 기후나 온도를 기억하기 위해 만들어졌다. 최초의 달력은 이집트에서 만들어졌는데 이집트 사람들의 경우 4년마다 1일의 윤일이 있어야 한다는 사실을 알고 있었지만 이를 적용하지는 않았다고 한다. 이는 로마 시대까지 이어져 1년 355일짜리 달력을 사용하였는데, 날짜가 계속해서 틀어지는 것을 발견했다. 1년이 365.25일인 것을 확인한 뒤 4년마다 하루를 끼워 넣는 방식으로 사용하기 시작했고, 홀수달은 31일, 짝수달은 30일로 맞추었다. 이렇게 계산하면 1년이 366일이 되는데, 당시에는 3월이 1년의 시작이었기 때문에 1년의 마지막 달인 2월에서 하루를 빼 29일로 만들었다. 이것이 율리우스력이다.\n\n>   율리우스력에서 8월(august)은 짝수월인데도 31일까지 있다. 이는 로마제국 황제였던 옥타비아누스가 아우구스투스라는 칭호를 사용하며 2월에서 하루를 빼 8월에 더해줬기 때문이다.\n\n>   이름이 율리우스력인 이유는 날짜 개혁을 진행했던 초대 로마제국 황제의 이름이 '가이우스 율리우스 카이사르 옥타비아누스'였기 때문이다.\n\n>   당시 3월이 한 해의 시작(1월) 이었는데, 옥타비아누스 이전 로마 공화국의 율리우스 카이사르가 집정관에 빨리 취임하기 위해 11월(january)을 1월로 바꾸었고, 10월(december)은 12월이 되었다.\n\n### 율리우스력의 오차와 그레고리력\n\n율리우스력은 기존의 달력체계보다 정교했지만, 한 가지 놓친 부분이 있었는데, 정확한 1년은 365.24219일이라는 것이다. 기존의 달력을 사용하면 400년이 지나면 3일이 넘는 오차가 생기는데, 이것이 누적되며 1582년에는 12일의 오차가 생겼고, 이를 없애고자 한 것이 그레고리력이다. 참고로, 12일의 오차가 생겼지만, 사람들의 혼동을 최소한으로 하기 위해 10일을 건너뛰는 것으로 결정했다.\n\n그레고리력은 1582년 교황 그레고리 13세가 제정한 달력이다. 기본적 틀은 율리우스력과 같지만 위에서 계산한 약 3일의 차이를 없애기 위해 100의 배수가 되는 해의 윤년을 없앤다. 그렇게 되면 400년간의 오차가 정확히 4일이 되기 때문에 400의 배수가 되는 연도에는 윤년을 넣는다. 이것이 그레고리력이고 현대의 달력은 이를 기반으로 한다.\n\n>   100년, 200년, 300년은 윤년 없이 넘어가고 400년에만 윤년을 적용하면 400년 동안 윤년이 97일이 된다. 이를 적용하지 않으면 400년간의 윤년은 100일이 되는데 이를 이용하여 3일의 오차를 없앤 것이다.\n\n>   그레고리력도 365.24219일을 반올림하여 365.24일로 계산한 것이기 때문에 수만 년이 지나면 달력을 수정해야 한다. 이는 오늘날까지도 그레고리력의 문제점으로 꼽히고 있다.\n\n## Java의 달력 API\n\n### Calendar 클래스\n\n글을 시작하며 `java.util.Date` 클래스와 `java.util.Calendar` 클래스를 이용하여 날짜를 다룬다. 하지만 이는 사용하기 불편하다고 했다. 왜 그런지 알아보자.\n\n#### 불규칙\n\n`Calendar` 클래스의 경우 위에서 살펴본 율리우스력과 그레고리력뿐만 아니라 여러 가지 사회 제도나 과학과 얽혀있다. 따라서 불규칙이 곳곳에 숨어있는데, 대표적인 몇 가지 사례가 있다.\n\n우선 UTC(Universal Time Coordinated, 세계협정시) 시간대를 기준으로 1582년 10월 4일에 하루를 더하면 1582년 10월 15일이 된다.\n\n```java\npublic void calendarTest_UTC() {\n    TimeZone utcTimeZone = TimeZone.getTimeZone(\"UTC\");\n    Calendar calendar = Calendar.getInstance(utcTimeZone);\n    // 처음 날짜 - 1582년 10월 4일\n    calendar.set(1582, Calendar.OCTOBER, 4);\n    \n    String pattern = \"yyyy.MM.dd\";    \n    SimpleDateFormat format = new SimpleDateFormat(pattern);\n    format.setTimeZone(utcTimeZone);\n    String theDay = format.format(calendar.getTime());\n    System.out.println(theDay); // \"1582.10.04\"\n    \n    // 하루를 더해준다.\n    calendar.add(Calendar.DATE, 1);\n    String nextDay = format.format(calendar.getTime());\n    System.out.println(nextDay); // \"1582.10.15\"\n}\n```\n\n 이는 위에서 살펴봤던 그레고리력에서 건너뛴 10일 때문이다. 위에서 사용한 `Calendar.getInstance()` 메소드는 `java.util.GregorianCalendar` 클래스의 인스턴스를 반환한다. `GregorianCalendar ` 클래스는 그레고리력과 율리우스력을 같이 구현하고 있는데, AD 4년의 3월 1일 이전에는 윤년을 불규칙하게 두어 `GregorianCalendar ` 클래스로 구한 날짜는 정확하지 않다고 한다.\n\n>   위에서 살펴본 내용은 `GregorianCalendar ` 클래스의 [API 문서](https://docs.oracle.com/javase/8/docs/api/java/util/GregorianCalendar.html)에 나와있다.\n\n`Calendar.getInstance()` 메소드는 이외에도 Locale 설정에 따라 `JapaneseImperialCalendar`, `BuddhistCalendar ` 등도 반환한다.\n\n우리나라 날짜(Asia/Seoul 시간대)의 경우 1961년 8월 9일 23시 59분의 1분 후를 계산할 경우 불규칙이 발생한다.\n\n```java\npublic void calendarTest_AsiaSeoul() {\n    TimeZone seoulTimeZone = TimeZone.getTimeZone(\"Asia/Seoul\");\n    Calendar calendar = Calendar.getInstance(seoulTimeZone);\n    // 처음 날짜 - 1961년 8월 9일 23시 59분\n    calendar.set(1961, Calendar.AUGUST, 9, 23, 59);\n    \n    // 하루를 더해준다.\n    calendar.add(Calendar.MINUTE, 1);\n    \n    String pattern = \"yyyy.MM.dd HH:mm\";    \n    SimpleDateFormat format = new SimpleDateFormat(pattern);\n    format.setTimeZone(seoulTimeZone);\n    \n    String nextDay = format.format(calendar.getTime());\n    System.out.println(nextDay); // \"1961.08.10 00:30\"\n}\n```\n\n이외에 Asia/Seoul TimeZone에서 1988년 5월 8일 1시의 1시간 후를 계산하면 5월 8일 3시가 된다. 이는 일광 절약 시간제(서머타임) 적용 때문이다. \n\n>   현재 우리나라에서는 일광 시간 절약 제를 사용하지 않지만, 이전에 시행했던 기간은 [여기에](https://ko.wikipedia.org/wiki/%EC%9D%BC%EA%B4%91_%EC%A0%88%EC%95%BD_%EC%8B%9C%EA%B0%84%EC%A0%9C#%EB%8C%80%ED%95%9C%EB%AF%BC%EA%B5%AD) 정리되어 있다.\n\n마지막으로 UTC 2012년 6월 30일에는 윤초가 적용되어야 하는데, `Calendar` 클래스에서는 구현되지 않았다. 이 때문에 당시 Java 기반의 서버나 Cassandra, Hadoop, Elasticsearch 등을 사용하는 많은 시스템에서 장애를 일으켰다고 한다.\n\n>   참고 - [\"윤초 때문에…\" 포스퀘어-링크드인 장애](https://zdnet.co.kr/view/?no=20120702094444)\n\n>   윤초의 경우 이후에 나온 라이브러리나 API에서도 적용되지 않았는데, 윤초를 동기화할 경우 많은 오류를 동반할 가능성이 크기 때문으로 보인다.\n\n#### 불변(immutable) 객체가 아니다\n\nVO(value object)는 값에 의해 동등성이 판단되어야 한다. 따라서 불변 객체로 생성되어야 별칭(alias) 문제, 스레드 불안정성 등에서 자유로워지고, 여러 객체에서 공유되어도 안전해진다. C#, Python 등의 언어에서는 날짜 클래스가 한 번 생성된 이후에 내부 속성을 변경할 수 없는 불변 객체로 생성된다. 반면, Java의 기본 날짜, 시간 클래스는 불변 객체가 아니다. `Calendar`클래스와 `Date` 클래스에는 값을 변경할 수 있는 setter 메소드가 존재한다. 따라서 안전하게 구현하기 위해서 방어복사 기법을 사용하는 것이 바람직하다.\n\n```java\npublic class DateSample {\n    private final Date wrongDateSample;\n    private final Date rightDateSample;\n    \n    public DateSample(Date wrongDateSample, Date rightDateSample) {\n        this.wrongDateSample = wrongDateSample;\n        this.rightDateSample = new Date(rightDateSample.getTime());\n    }\n    \n    public Date getWrongDateSample() {\n        return wrongDateSample;\n    }\n    \n    public Date getRightDateSample() {\n        return new Date(rightDateSample.getTime());\n    }\n}\n```\n\n>   `wrongDateSample` 필드처럼 사용되는 경우 정적 분석 도구에서 취약점으로 판단한다고 한다.\n\n#### int 상수 필드의 남용\n\n`Calendar`를 사용하여 날짜를 할 경우, 위에서 살펴봤던 예제들처럼 첫 번째 매개변수로 `Calendar.SECOND` 와 같은 상수 필드를 사용해야 한다. 하지만 이는 int 타입의 숫자로 구현되어 있어 엉뚱한 숫자나 상수를 넣어도 컴파일 시점에서 확인하기 힘들다.\n\n```java\ncalendar.add(Calendar.HOUR, 1); // Calendar.HOUR의 값은 10(int)이다.\ncalendar.add(10, 1); // ?\ncalendar.add(Calendar.NOVEMBER, 1); // ???\n```\n\n위의 예시에서 세 가지 코드 모두 같은 동작을 한다. 즉, 의도하지 않은 동작이 이루어질 수 있다.\n\n#### 헷갈리는 월 지정\n\n위의 예시에서 `Calendar.NOVEMBER`는 11월을 의미하지만 실제로 값은 10이다. 이는 `Date` 클래스와 `Calendar` 클래스는 1월을 0으로 표현했기 때문인데, 이를 인지하지 못하거나 깜빡한다면 다음과 같은 실수를 할 수 있다.\n\n```java\ncalendar.set(1582, 10 , 4);  // 1582년 10월 4일을 원했으나, 실제로는 11월 4일이 저장될 것이다.\n```\n\n#### 일관성 없는 요일 상수\n\n`Calendar` 클래스에서는 일요일을 1로 표현했지만, `Date` 클래스의 경우 일요일을 0으로 표현한다.\n\n#### 불편한 역할 분담\n\nJDK1.1 이후 `Calendar` 클래스가 생기면서 날짜 간의 연산 혹은 국제화 지원 등의 역할은 `Calendar` 클래스에서 담당하게 되었고 `Date` 클래스에서 기존에 사용하던 많은 기능이 deprecated 되었다.\n\n이로 인해 특정 시간대를 생성하기 위해 `Calendar` 클래스를 이용하여 값을 지정하거나 연산하고 다시 `Date` 객체를 반환하여 저장해야 한다. 특히 `Calendar` 클래스는 생성 비용이 비싼 편이기 때문에 불필요한 `Calendar` 클래스의 생성은 비효율적이다. 또한, `Date` 연산에 쓰이는 다른 라이브러리 또한 `Calendar` 클래스를 생성한다.\n\n#### 예외가 발생하지 않는 시간대 ID 지정 오류\n\n```java\nTimeZone zone = TimeZone.getTimeZone(\"Seoul/Asia\"); // Asia/Seoul 이 올바른 시간대 ID이다.\n```\n\n위와 같이 시간대 ID를 잘못 입력한 경우 시간대 ID가 `GMT`로 지정된다. 에러가 발생하지 않기 때문에 관련된 오류를 찾아내기 힘들어진다.\n\n#### 잘못된 하위 클래스\n\n`java.sql.Date` 클래스는 `java.util.Date`클래스를 상속한 클래스이다. 자식 클래스와 부모 클래스의 이름이 같은데, 기본 클래스로 사용된다. `java.sql.TimeStamp` 클래스 또한 `java.util.Date` 클래스를 상속받은 클래스인데, 나노초(nanosecond) 필드가 추가돼있다. 이 클래스는 `equals()` 메소드의 대칭성을 어기며 작성되었다. 따라서 `Date` 타입과 `TimeStamp` 타입을 섞어 쓰면 `a.equals(b)` 와 `b.equals(a)` 의 값이 서로 다른 경우가 생길 수 있다.\n\n>   참고 - [Compare Date object with a TimeStamp in Java](https://stackoverflow.com/questions/8929242/compare-date-object-with-a-timestamp-in-java)\n\n>   `java.sql.Date` 클래스의 경우 `Comparable` 인터페이스 재정의가 되지 않고 상위 클래스에서만 이루어져 관련 제네릭 설정이 복잡하다고 하는데, 간단한 테스트 시에는 큰 문제를 발견하지 못했다.\n\n### JSR-310\n\nJDK8 부터 JSR-310이라는 새로운 표준 명세 및 날짜와 시간에 대한 API가 추가되었다. [Joda-Time](https://www.joda.org/joda-time/)에 가장 큰 영향을 받았고, [Time and Money](http://timeandmoney.sourceforge.net/)나 [ICU](http://site.icu-project.org/home) 등의 오픈소스 라이브러리를 참고하여 만들었다고 한다. 위에서 살펴봤던 예제들을 다시 구현하며 새로운 날짜 API를 살펴보자.\n\n```java\npublic void jsr310Test_UTC() {\n    LocalDate theDay = IsoChronology.INSTANCE.date(1582, 10, 4);\n    String pattern = \"yyyy.MM.dd\";\n    DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);\n    System.out.println(theDay.format(formatter)); // 1582. 10. 04\n\n    LocalDate nextDay = theDay.plusDays(1); // 새로운 객체 반환\n    System.out.println(nextDay.format(formatter)); // 1582. 10. 05\n    \n    ZonedDateTime utcDay = theDay.atStartOfDay(ZoneId.of(\"UTC\")); // 타임존이 명시 된 날짜로 변환\n    System.out.println(utcDay.plusDays(1).format(formatter)); // 1582. 10. 05\n}\n```\n\n기본적으로 날짜를 초기화하는 소스가 훨씬 직관적이게 되었다. 사용되는 format 생성 클래스도 생성자가 아닌, 팩토리 메소드를 사용한다. 특히 날짜를 더하는 부분은 날짜를 더하게 되면 새로운 객체를 반환하게 하여 불변 객체를 유지할 수 있도록 설계됐음을 알 수 있다. 만약 시간대(timezone) 설정이 필요하다면 `ZonedDateTime`을 사용하면 된다.\n\n```java\npublic void jsr310Test_AsiaSeoul_movedTimeZone() {\n    ZoneId seoulTimeZone = ZoneId.of(\"Asia/Seoul\");\n    ZonedDateTime theTime = ZonedDateTime.of(1961, 8, 9, 23, 59, 59, 0, seoulTimeZone);\n    DateTimeFormatter formatter = DateTimeFormatter.ofPattern(\"yyyy.MM.dd HH:mm\");\n    System.out.println(theTime.format(formatter)); // \"1961.08.09 23:59\"\n\n    ZonedDateTime after1Minute = theTime.plusMinutes(1);\n    // 시간대가 변경되며 발생한 불규칙에 대한 개선은 이루어지지 않았다.\n    System.out.println(after1Minute.format(formatter)); // \"1961.08.10 00:30\"\n}\n```\n\n```java\npublic void jsr310Test_AsiaSeoul_summerTime() {\n    ZoneId seoulTimeZone = ZoneId.of(\"Asia/Seoul\");\n    DateTimeFormatter formatter = DateTimeFormatter.ofPattern(\"yyyy.MM.dd HH:mm\");\n    ZonedDateTime beforeSummerTime = ZonedDateTime.of(1988, 5, 8, 1, 0, 0, 0, seoul);\n    System.out.println(beforeSummerTime.format(formatter));\n    // ZoneRules 클래스를 이용하여 서머타임인지 확인할 수 있도록 개선되었다.\n    ZoneRules seoulTimeZoneRules = seoul.getRules();\n    System.out.println(seoulTimeZoneRules.isDaylightSavings(Instant.from(beforeSummerTime)));\n\n    ZonedDateTime afterSummerTime = beforeSummerTime.plusHours(1);\n    System.out.println(afterSummerTime.format(formatter));\n    System.out.println(seoulTimeZoneRules.isDaylightSavings(Instant.from(afterSummerTime)));\n}\n```\n\n월이나 날짜 등을 잘못 입력하면 예외가 발생한다.\n\n```java\npublic void jsr310Test_wrongDate() {\n    LocalDate.of(2020, 11, 31); // java.time.DateTimeException: Invalid date 'NOVEMBER 31'\n    ZoneId.of(\"Seoul/Asia\"); // java.time.zone.ZoneRulesException: Unknown time-zone ID: Seoul/Asia\n}\n```\n\n이외에도 요일의 경우 아예 `DayOfWeek`라는 enum 클래스로 만들어버렸으며, 나노초 단위의 정밀성을 가지도록 하였다. 또한, 시계의 개념도 도입되어 시간과 관련된 기능을 테스트할 때도 유용하게 쓰인다고 한다.\n\nSpring 프레임워크는 4.0부터 JSR-310을 기본 지원한다. `ZoneDateTime`을 Controller에서 받아오면 문자열을 날짜 객체로 자동변환해준다. 굳이 `String`으로 받아온 값을 변환해주는 번거로운 작업을 해주지 않아도 된다.\n\n## 마치며\n\nJDK8이 나온 지 꽤 되었기 때문에 새로 나온 API라고 하기에도 민망하지만, 아직도 기본 제공되는 날짜 관련 클래스를 사용하는 경우가 있다. JSR-310에 확실한 개선점들이 있다. 뿐만 아니라 JDK8 이전의 버전에서 사용할 수 있는 백포팅 모듈도 있기 때문에 이를 사용하는 것이 보다 바람직할 것이며, 최신 버전의 Spring 프레임워크 및 Spring boot에서는 이에 대한 지원도 잘 되어있어 편하게 사용할 수 있다. \n\n>   참고 - [ThreeTen Backport](https://www.threeten.org/threetenbp/)\n\n본문에서는 날짜 API에 대한 이해, 기존 API의 문제점과 새로운 API의 개선점 등을 알아보았다. 이외에 보다 자세한 사용법을 알고 싶다면 [여기](https://wickso.me/java/java-8-date-time/)에 잘 정리가 되어있어 참고하면 좋을 것 같다. 혹은 다른 기능들을 살펴보고 싶다면 \n\n[Package java.time](https://docs.oracle.com/javase/8/docs/api/java/time/package-summary.html)을 참고하자.\n\n\n\n---\n\n#### References\n\n-   [달력이야기 <율리우스력 그레고리력>](https://m.post.naver.com/viewer/postView.nhn?volumeNo=12082924&memberNo=6178993)\n-   [[호기심으로 배우는 역사] 달력의 유래와 역사 (2) - voakorea](https://www.voakorea.com/archive/35-2010-01-06-voa27-91423439)\n-   [Java의 날짜와 시간 API - Naver D2](https://d2.naver.com/helloworld/645609)\n"
  },
  {
    "path": "Java/junit-setup.md",
    "content": "# JUnit 설정해보기\n\n## JUnit\n\n[JUnit](https://junit.org/junit5/)은 Java 언어용 [단위 테스트](https://ko.wikipedia.org/wiki/%EC%9C%A0%EB%8B%9B_%ED%85%8C%EC%8A%A4%ED%8A%B8) 프레임워크다. Java 진영에서 가장 많이 쓰이고 있는 테스트 프레임워크이고 JUnit 없이 TDD를 논하기 힘들 것이다.\n\n### JUnit5의 ParametizedTest\n\nJUnit의 최신 버전은 JUnit5인데, 테스트용 매개변수 입력을 아주 강력하게 지원해준다. 테스트를 작성할 때 프레임워크의 도움을 받지 않으면 힘든 부분이 여러 가지가 있겠지만, 개인적으로 가장 힘들었던 부분은 아래 같은 경우이다.\n\n```java\nclass SomeClass {\n    public int someFunction(int a, int b) {\n      return a + b;\n    }\n}\nclass SomeClassTest {\n    SomeClass someClass = new SomeClass();\n    public test() {\n      System.out.println(\"test 1 : \" + (someClass.someFunction(1, 1) == 2));\n      System.out.println(\"test 2 : \" + (someClass.someFunction(2, 2) == 4));\n      System.out.println(\"test 3 : \" + (someClass.someFunction(3, 3) == 6));\n    }\n}\n```\n\nJUnit5 는 `ParametizedTest` 라는 기능을 제공하는데 이를 이용하면 아래와 같이 수정할 수 있다.\n\n```java\nclass SomeClassTest {\n  @ParameterizedTest\n  @CSVSource({\n    \"1, 1, 2\",\n    \"2, 2, 4\",\n    \"3, 3, 6\"\n  })\n  void someFunction(int a, int b, int expected) {\n    SomeClass someClass = new SomeClass();\n    int result = someClass.someFunction(a, b);\n\n    assertThat(result).isEqualTo(expected);\n  }\n}\n```\n\n만약 테스트 케이스가 늘어난다면 `@CSVSource` 어노테이션의 매개변수로 값만 추가해주면 된다.\n\n이외에도 `ParameterizedTest` 에 매개변수를 넣는 방법이 여러 가지가 있는데 그 중 `MethodSource` 를 추천한다.\n[@MethodSource - JUnit 5 User Guide](https://junit.org/junit5/docs/current/user-guide/#writing-tests-parameterized-tests-sources-MethodSource) 에 나와있는 설명을 보고 따라하면 금방 익힐 수 있을 것이다.\n\n> https://www.baeldung.com/parameterized-tests-junit-5 에도 설명이 잘 나와있다.\n\n## 내 프로젝트에 설정해보기\n\n> 인텔리J를 기준으로 작성하는데, 이클립스도 크게 다르지 않다.\n\n크게 세 가지 경우가 있다.\n\n1. Java 프로젝트\n2. Maven 프로젝트\n3. Gradle 프로젝트\n\n하나씩 살펴보자\n\n### 공통\n\n어떤 프로젝트든 우선적으로 설정해야 할 것이 있다. Test 소스용 root path를 지정해야 한다.\n\n우선 File-Project Structure-Modules에 들어간다.\n\n> 이클립스는 프로젝트의 Java Build Path에서 설정할 수 있다.\n\n![junit설정해보기-03.png](https://raw.githubusercontent.com/Dae-Hwa/Dae-Hwa.github.io/master/data/blog/post/2021-01-05--junit-%EC%84%A4%EC%A0%95%ED%95%B4%EB%B3%B4%EA%B8%B0/junit%EC%84%A4%EC%A0%95%ED%95%B4%EB%B3%B4%EA%B8%B0-03.png)\n\n그다음 새 폴더를 생성하고 테스트 디렉토리로 설정한다.\n![junit설정해보기-04.png](https://raw.githubusercontent.com/Dae-Hwa/Dae-Hwa.github.io/master/data/blog/post/2021-01-05--junit-%EC%84%A4%EC%A0%95%ED%95%B4%EB%B3%B4%EA%B8%B0/junit%EC%84%A4%EC%A0%95%ED%95%B4%EB%B3%B4%EA%B8%B0-04.png)\n![junit설정해보기-05.png](https://raw.githubusercontent.com/Dae-Hwa/Dae-Hwa.github.io/master/data/blog/post/2021-01-05--junit-%EC%84%A4%EC%A0%95%ED%95%B4%EB%B3%B4%EA%B8%B0/junit%EC%84%A4%EC%A0%95%ED%95%B4%EB%B3%B4%EA%B8%B0-05.png)\n\n### Java Project\n\n`Alt + Insert` 혹은 `Shift + Shift` 입력 후 검색을 하여 `Generate` 를 호출하면 `Test...` 라는 옵션이 있다.\n![junit설정해보기-06.png](https://raw.githubusercontent.com/Dae-Hwa/Dae-Hwa.github.io/master/data/blog/post/2021-01-05--junit-%EC%84%A4%EC%A0%95%ED%95%B4%EB%B3%B4%EA%B8%B0/junit%EC%84%A4%EC%A0%95%ED%95%B4%EB%B3%B4%EA%B8%B0-06.png)\n![junit설정해보기-07.png](https://raw.githubusercontent.com/Dae-Hwa/Dae-Hwa.github.io/master/data/blog/post/2021-01-05--junit-%EC%84%A4%EC%A0%95%ED%95%B4%EB%B3%B4%EA%B8%B0/junit%EC%84%A4%EC%A0%95%ED%95%B4%EB%B3%B4%EA%B8%B0-07.png)\n\n선택하면 아래와 같은 상자가 나온다. OK를 클릭하자.\n\n> 아래의 Member에서 원하는 테스트 케이스를 함께 생성할 수도 있다.\n\n![junit설정해보기-08.png](https://raw.githubusercontent.com/Dae-Hwa/Dae-Hwa.github.io/master/data/blog/post/2021-01-05--junit-%EC%84%A4%EC%A0%95%ED%95%B4%EB%B3%B4%EA%B8%B0/junit%EC%84%A4%EC%A0%95%ED%95%B4%EB%B3%B4%EA%B8%B0-08.png)\n\n생성된 클래스에 `@Test` 어노테이션을 입력 후 `Alt + Enter` 를 입력하면 아래와 같은 옵션들이 나온다. JUnit5를 사용할 것이니 선택해준다.\n\n![junit설정해보기-09.png](https://raw.githubusercontent.com/Dae-Hwa/Dae-Hwa.github.io/master/data/blog/post/2021-01-05--junit-%EC%84%A4%EC%A0%95%ED%95%B4%EB%B3%B4%EA%B8%B0/junit%EC%84%A4%EC%A0%95%ED%95%B4%EB%B3%B4%EA%B8%B0-09.png)\n\n이제 설정이 완료됐다. 이후 테스트 코드를 작성해본다.\n\n![junit설정해보기-10.png](https://raw.githubusercontent.com/Dae-Hwa/Dae-Hwa.github.io/master/data/blog/post/2021-01-05--junit-%EC%84%A4%EC%A0%95%ED%95%B4%EB%B3%B4%EA%B8%B0/junit%EC%84%A4%EC%A0%95%ED%95%B4%EB%B3%B4%EA%B8%B0-10.png)\n\n초록색 재생 버튼이 나오는데 클릭하면 실행시킬 수 있다. 잘 동작하는지 실행시켜보자.\n\n![junit설정해보기-11.png](https://raw.githubusercontent.com/Dae-Hwa/Dae-Hwa.github.io/master/data/blog/post/2021-01-05--junit-%EC%84%A4%EC%A0%95%ED%95%B4%EB%B3%B4%EA%B8%B0/junit%EC%84%A4%EC%A0%95%ED%95%B4%EB%B3%B4%EA%B8%B0-11.png)\n\n테스트에 성공했다고 하단에 나온다. 성공이다!\n\n![junit설정해보기-12.png](https://raw.githubusercontent.com/Dae-Hwa/Dae-Hwa.github.io/master/data/blog/post/2021-01-05--junit-%EC%84%A4%EC%A0%95%ED%95%B4%EB%B3%B4%EA%B8%B0/junit%EC%84%A4%EC%A0%95%ED%95%B4%EB%B3%B4%EA%B8%B0-12.png)\n\n### Maven 프로젝트\n\n아래 depencency를 `pom.xml`에 추가해준다. 이후 [Java Project](#java-project) 를 따라가면 된다.\n\n```xml\n<dependency>\n    <groupId>org.junit.jupiter</groupId>\n    <artifactId>junit-jupiter</artifactId>\n    <version>RELEASE</version>\n    <scope>test</scope>\n</dependency>\n```\n\n### Gradle 프로젝트\n\n아래 dependency를 `build.gradle`에 추가해준다. 이후 [Java Project](#java-project) 를 따라가면 된다.\n\n```gradle\ntestCompile group: 'org.junit.jupiter', name: 'junit-jupiter', version: 'latest.release'\n```\n\n## 단위테스트 그리고 TDD\n\n단위 테스트는 특정 모듈이 의도한 대로 동작하는지 검증하는 절차인데 쉽게 말하면 메소드에 대한 테스트 케이스를 작성하고 잘 동작하는지 확인하는 것이다.\n\n메소드 단위로 확인하기 때문에 제대로 작성만 해놓는다면 문제가 발견하면 어디서 잘못되었는지 파악하기 쉽다. 특히 입력과 출력에 대해 정확히 정의하고 테스트하면 [side effect(부작용, 부수효과)](<https://ko.wikipedia.org/wiki/%EB%B6%80%EC%9E%91%EC%9A%A9_(%EC%BB%B4%ED%93%A8%ED%84%B0_%EA%B3%BC%ED%95%99)>) 를 줄이는 효과를 줄 수 있다.\n\n또한, 테스트 코드가 잘 짜여있으면 리팩토링을 하더라도 이전과 똑같이 동작하는지 지속적으로 확인할 수 있기 때문에 좀 더 편안한 마음으로 리팩토링을 진행할 수 있다.\n\n마지막으로 상향식 개발 방법을 사용하면 더욱 효과적이다. 쉽게 말하면 메소드가 동작하도록 일단 만든 다음 점진적 개선을 해나가며 개발하는 것이다. 예를 들자면, 아래와 같은 일단 동작만 하는 소스를 만들어 놓고 세부 사항을 추가해가며 구현하는 것이다.\n\n> 상향식 하향식은 도메인 지식에 어느 정도의 이해도가 있느냐에 따라 효율성이 달라질 수 있다. 이외에도 여러 고려사항이 있겠지만, 이번에는 JUnit을 사용할 때의 관점에서만 살펴봤다.\n\n```java\nclass SomeClass {\n    public int someFunction() {\n      return 0;\n    }\n}\n\nclass SomeClassTest {\n    @Test\n    void someFunctionTest() {\n      int result = new SomeClass().someFunction();\n      int expected = 0;\n      assertThat(result).isEqualTo(expected);\n    }\n}\n```\n\n이러한 장점은 [TDD](https://en.wikipedia.org/wiki/Test-driven_development)의 사상에 부합하는데, TDD의 개발 사이클은 아래와 같다.\n\n1. 테스트를 추가한다.\n2. 테스트를 실행한다.\n3. 테스트가 실패한다면 테스트를 통과할 수 있도록 코드를 수정한다.\n4. 테스트를 실행한다. 실패한다면 성공할때까지 3을 반복한다.\n5. 리팩토링을 진행한다.\n6. 1번부터 반복한다.\n\n이를 위해 TDD는 아주 작은 단위의 테스트부터 작성하여 점진적으로 늘려가는 방식을 사용하는데 이는 위에서 말한 장점과 겹친다.\n\n## 마치며\n\nJUnit은 기본적으로 단위 테스트를 위해 만들었고, 버전이 5까지 나왔을 정도로 지속적인 개선이 이루어졌기 때문에 편리하게 테스트 할 수 있도록 많은 기능을 제공한다.\n\n스프링과 같은 프레임워크에서도 JUnit을 더 잘 활용할 수 있도록 여러가지 기능을 제공한다. 또한 잘 활용하면 단위 테스트 뿐만 아니라, 통합 테스트 도구로도 사용할 수 있다.\n\n대부분의 경우에서 실보다 득이 많다. 한 번도 사용해보지 않았으면 막연한 공포감이 들 수도 있지만, 위에서 살펴봤듯 아주 간단하게 적용할 수 있으니 조금씩이라도 연습해보자.\n"
  },
  {
    "path": "Javascript/Ajax.md",
    "content": "# AJAX(Asynchronous JavaScript And XML)\n\n## 들어가기 전에...\n\n1990년대까지 웹은 정적 환경이었다. **클라이언트가 서버로 요청**을 보내면, 서버는 **반드시 새로운 웹 페이지를 만들어 클라이언트에 보내야 한다.** 아주 작은 요청에도 새로운 페이지를 만들어야 하는 단점이 있다.\n\n이를 해결하기 위해 만들어진 것이 `XMLHttpRequest`이다. `XMLHttpRequest`는 현재 대부분의 주요 웹 브라우저에 내장되어있는 객체로, **비동기 데이터 전송**을 도와준다. 이는 전체 페이지를 유지하며 필요한 데이터만 주고 받을 수 있도록 해준다.\n\n비동기 웹 기술이 처음 나왔을때는 웹의 영향력이 미미하여 큰 관심을 끌지 못했다. 이후 구글이 액티브X나 플래쉬같은 플러그인 없이 구글맵을 구현하여 크게 주목 받기 시작했다(별도의 설치나 창의 호출 없이 브라우저 화면 안에서 이러한 서비스를 하는 것은 큰 충격이었다고 한다). 또한, Google Groups, Gmail 등에 비동기 웹 기술을 적용하였다. Google Page에 사용한 기술을 소개한 글에서 이러한 기술을 Ajax라고 소개하며 Ajax라는 용어가 처음 등장하였다.\n\n<br/>\n\n## Ajax\n\nAjax는 Asynchronous JavaScript And XML의 약어이다. 자바스크립트를 통하여 XML(통신 데이터)를 비동기로 송수신 하는 것으로, 하나의 특정한 기술이 아닌 **기술의 묶음**이다. 넓은 의미로는 **페이지 새로고침 없이 비동기적으로 콘텐츠를 변경하기 위해 사용하는 모든 기술**을 의미한다. 간단히 말하면 **XMLHttpRequest 객체를 이용하여, 비동기 방식으로 서버와 데이터를 주고받는 것**이다.\n\n#### 사용기술\n\n* 표현 정보 : HTML([XHTML](https://ko.wikipedia.org/wiki/XHTML))과 CSS\n\n* 동적 요소 : DOM과 자바 스크립트\n\n* 데이터 포맷: [XML](https://ko.wikipedia.org/wiki/XML), [XSLT](https://ko.wikipedia.org/wiki/XSLT)(뿐만 아니라, 미리 정의된 HTML이나 일반 텍스트, [JSON](https://ko.wikipedia.org/wiki/JSON), [JSON-RPC](https://ko.wikipedia.org/wiki/JSON-RPC)를 이용할 수도 있다.)\n\n  > 현재는 거의 JSON을 이용한다. 따라서 최근 Ajax는 약어가 아닌 고유명사처럼 쓰인다.\n\n* 데이터 호출 :  XMLHttpRequset(XHR)객체\n\n<br/>\n\n## 작동 방식\n\n![XMLHttpRequest](../assets/images/ajax.png)\n\n1. 웹 페이지에서 이벤트 발생(페이지로드, 버튼 클릭)\n2. XMLHttpRequset 객체가 JavaScript에 의해 생성\n3. XMLHttpRequset 객체가 서버에 요청(Request)\n4. 서버가 요청 처리\n5. 서버가 웹 페이지에 응답(Response)\n6. XMLHttpRequest 객체가 응답 확인\n7. JavaScript가 데이터 처리\n\n기존 방식과 차이점은 클라이언트와 서버가 **전체 페이지가 아닌, 데이터만 주고 받는다**는 것이다. 결과적으로 클라이언트는 XML이나 JSON과 같은 형식 문서를 서버와 주고 받고, 그 결과만 클라이언트에서 출력해주기때문에 페이지의 새로고침 없이 일부분만 변경할 수 있다.\n\n<br/>\n\n## 장점\n\n* 고속으로 화면 전환 가능\n* 비동기 요청 가능(서버를 기다리지 않는다 → 요청 후 다른 작업 수행 가능)\n* 송신 데이터 양이 줄어든다 → 웹 서버 처리량도 줄어든다\n\n<br/>\n\n## 단점\n\n* 브라우저 호환성의 문제\n* 클라이언트의 PC로 요청을 보낼 수 없다.\n* 클라이언트 풀링(pooling) 방식을 사용하기 때문에 실시간 서비스가 불가능하다.\n* 페이지 이동없는 통신을 하면 보안상의 문제가 생길 수 있다 \n* 지원하는 Charset이 한정됨\n* 서버단과 클라이언트 단의 코드가 섞여있어 문제 확인이 힘들 수 있다.\n* 비동기 요청 후 다음 작업을 진행하려면 callback함수를 써야 한다.\n  * Promise를 통해 극복 가능하다. - [Promise1](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/Promise1.md) / [Promise2](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/Promise2.md) / [PromisePattern](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/PromisePattern.md) 참고\n* 비동기 요청이기 때문에 요청이 너무 많아지면 서버 부하가 심해질 수 있다\n* 동일-출처 정책으로 인해 다른 도메인과 통신이 불가능\n  * 이를 해결하기 위한 방안으로 [CORS](https://github.com/Im-D/Dev-Docs/blob/master/Security/CORS(Cross-Origin%20Resource%20Sharing).md)가 있다.\n\n> 동일-출처 정책(same-origin policy) : 웹 애플리케이션의 보안모델. 프로토콜(URI scheme), 호스트, 포트가 동일해야 한다는 제약 사항\n\n<br/>\n\n## 한계\n\n비동기식으로 요청을 하지만, 완전한 양방향 통신은 아니다. 요청에 응답한 뒤 세션이 종료되는 기존 HTTP프로토콜의 방식을 그대로 사용하기 때문이다. 이에 대한 대안으로 웹 소켓(Web Socket)이 등장하였다.\n\n> 참고 - [HTTP2.0과 Web Socket](https://github.com/Im-D/Dev-Docs/blob/master/Browser/HTTP2_Websocket.md)\n\n------\n\n#### Reference\n\n* [Ajax 시작하기 - MDN docs](https://developer.mozilla.org/ko/docs/Web/Guide/AJAX/Getting_Started)\n\n* [웹사이트 접근의 새로운 혁명 Ajax](https://pringles.tistory.com/201)\n\n* [[ Ajax 강좌 ] 1강. Ajax는 무엇일까요.](https://blog.nonamex.kr/5)\n\n* [Ajax & CORS Overview](https://huns.me/development/1291)\n\n* [Ajax - 생활코딩](https://opentutorials.org/course/1375/6843)\n\n* [AJAX   Asynchronous Java Script and XML - 정보통신기술용어해설](http://www.ktword.co.kr/abbr_view.php?nav=2&id=1382&m_temp1=3571)\n\n* [Ajax - 위키백과](https://ko.wikipedia.org/wiki/Ajax)\n\n"
  },
  {
    "path": "Javascript/Animation.md",
    "content": "# CSS 애니메이션 vs JS 애니메이션\n\n웹기술이 발전되면서 좀 더 사용자 친화적으로 개발하려는 노력을 하고 있다.\n이에 방법 중 하나로 애니메이션을 추가함으로써 더욱 이쁘고 완성도가 높은 웹을 만든다.\n\n예전에는 단순하게 CSS와 JS를 사용해서 애니메이션을 구현했다. \n\n그 예시로 stackoverflow의 만우절 이벤트를 들 수 있다.\n\n![stackoverflow](https://user-images.githubusercontent.com/24274424/68475826-83d94800-026c-11ea-90d1-760751c82d1f.png)\n\n현재는 WebGL, Canvas, SVG, Observer API / Web-Lottie, D3 등등 여러 기술과 라이브러리가 있어 구현할 수 있는 방법이 다양해졌다.\n\n그 중에서 기본이 되는 CSS와 JS 애니메이션을 살펴보자.\n\n## CSS 애니메이션\n\n먼저 간단하게 CSS 애니메이션의 특징을 살펴보게 되면,\n\n1. JS를 모르더라도 간단한 애니메이션을 만들 수 있다.\n2. JS를 이용한 애니메이션은 잘 만들어졌더라도 성능이 좋지 못한 경우가 있다. CSS 애니메이션은 `frame-skipping` 같은 여러 기술을 사용되어 최대한 부드럽게 렌더링된다.(성능최적화로 렌더링된다.)\n3. 브라우저가 애니메이션의 성능을 효율적으로 최적화한다. 예를 들어 안 보이는 엘리먼트에 대한 애니메이션은 업데이트 주기를 줄여 부하를 최소화한다.\n4. CSS에서 미리 정의된 애니메이션을 브라우저의 기능을 이용해서 애니메이션의 중간 상태를 나타내는 `@keyframe`을 계산 후 애니메이션을 브라우저에서 렌더링한다.\n5. 정해진 시간에 정해진 동작을 하도록 선언한 후, 애니메이션을 브라우저에 표현한다.(선언적)\n\n간단한 애니메이션을 만들어보자.\n\n```html\n<style>\n  #container {\n    width: 400px;\n    height: 400px;\n    position: relative;\n    background: yellow;\n  }\n\n  #animate {\n    width: 50px;\n    height: 50px;\n    position: absolute;\n    background-color: red;\n  }\n\n  .animation-move {\n    animation: move 4s\n  }\n\n  /* @keyframes rule */\n  @keyframes move {\n    from {\n      left: 0;\n      top: 0;\n    }\n\n    to {\n      top: 350px;\n      left: 350px;\n    }\n  }\n</style>\n\n<body>\n  <button onclick=\"myMove()\">Click Me</button>\n\n  <div id=\"container\">\n    <div id=\"animate\"></div>\n  </div>\n</body>\n<script>\n  function myMove() {\n    var elem = document.getElementById(\"animate\");\n    elem.className = \"animation-move\";\n  }\n</script>\n```\n\n**CSS 코드를 보게되면 `@keyframes`를 사용해 애니메이션명을 지정하고 이를 `animation-move`라는 클래스 명을 해당 요소**에 넣어주고 있다.\n\n이에 버튼을 클릭하게 되면 `div`요소에 `animation-move`라는 클래스가 추가되면서 애니메이션이 실행된다.\n\n* [@keyframes에 관한 구체적인 예시](https://poiemaweb.com/css3-애니메이션)\n\n### 트랜지션과 애니메이션\n\nCSS로 애니메이션을 표현하는 방법은 크게 2가지 있다.\n\n#### 트랜지션\n\n- 요소의 변화를 일정 기간(duration)동안 일어나게 한다.\n- `hover`나 `click` 같은 **이벤트 Trigger에 의해 동작한다.**\n- layout을 변경시킬 경우, reflow 발생을 줄이기 위해 **낮은 계층의 요소에 효과를 주는 것이 좋다.**\n\n#### 애니메이션\n\n- 트랜지션은 시작하기 위해 이벤트가 필요하지만 애니메이션은 **시작, 정지, 반복까지 제어 가능하다.**(물론, 이벤트 제어도 가능)\n- 하나 또는 복수의 **`@keyframes`으로 이루어진다.**\n\n### 간단하게 살펴보는 기본 Animation 속성\n\n- animation-delay : Element가 load되고 얼마 뒤에 시작될지 설정\n- animation-direction : 애니메이션이 종료되고 다시 처음부터 시작할지 역방향으로 진행할지 설정\n- animation-duration : 한 싸이클의 애니메이션이 어느 정도의 시간에 걸쳐 일어날지 설정\n- animation-fill-mode : 애니메이션이 시작되기 전이나 끝나고 난 후 어떤 값이 적용될지 설정(forwards | backwards | both)\n- animation-name : 애니메이션의 중간 상태를 지정한다. 중간 상태란 `@keyframe` 규칙을 이용하여 기술한 keyframe 이름이다.\n\n#### Example\n\n- [Animation-Delay](https://codepen.io/seonhyungjo/pen/aeOpxp)\n- [Animation-Direction](https://codepen.io/seonhyungjo/pen/zgGZRE)\n- [Animation-Duration](https://codepen.io/seonhyungjo/pen/ZgGeVJ)\n- [Animation-fill-mode](https://codepen.io/seonhyungjo/pen/qedrgM)\n\n### keyframe\n\n애니메이션 중간 중간 특정 지점들을 지나는 키프레임들을 설정함으로써 CSS 애니메이션 과정의 중간 절차를 제어할 수 있도록 도와주는 속성이다.\n\n키프레임 규칙을 이용해서 두 개 이상의 중간 상태를 기술할 수 있다.\n\n중간 상태에 명시한 스타일이 언제 등장할지를 `%`를 이용해서 지정한다. `0%`는 시작시점을 의미하며, `100%`는 마지막 지점이 된다. 최소한 이 두 시점은 기술되어야 브라우저가 언제 애니메이션이 시작되고 끝나는지 알 수 있다.\n\n> [Animation-keyframe](https://codepen.io/seonhyungjo/pen/VoLbdL)\n\n### 한방에 적어서 사용하기\n\nanimation CSS 속성은 다수의 스타일을 전환하는 애니메이션을 적용할 수 있다. \n\n`animation-name`, `animation-duration`, `animation-timing-function,` `animation-delay`, `animation-iteration-count`, `animation-direction`, `animation-fill-mode`, `animation-play-state`의 단축 속성이다.\n\n```css\nanimation: 3s ease-in 1s 2 reverse both paused slidein;\n```\n\n## JS 애니메이션\n\n1. 다양한 컨트롤 또는 사용자 입력에 의해서 상태가 변하는 애니메이션을 구현하기 위해서 사용한다.\n2. 애니메이션의 시간, 효과 등의 제한없이 구현이 가능하다.\n3. 프레임 단위로 애니메이션을 정의한다.\n4. setInterval, setTimeOut을 이용한 애니메이션과 requestAnimationFrame을 이용한 애니메이션이 있다.\n\n```html\n<style>\n  #container {\n    width: 400px;\n    height: 400px;\n    position: relative;\n    background: yellow;\n  }\n\n  #animate {\n    width: 50px;\n    height: 50px;\n    position: absolute;\n    background-color: red;\n  }\n</style>\n\n<body>\n  <button onclick=\"myMove()\">Click Me</button>\n\n  <div id=\"container\">\n    <div id=\"animate\"></div>\n  </div>\n</body>\n<script>\n  function myMove() {\n    var elem = document.getElementById(\"animate\");\n    var pos = 0;\n    var id = setInterval(frame, 5);\n\n    function frame() {\n      if (pos == 350) {\n        clearInterval(id);\n      } else {\n        pos++;\n        elem.style.top = pos + 'px';\n        elem.style.left = pos + 'px';\n      }\n    }\n  }\n</script>\n```\n\nJS 애니메이션으로 위에서 살펴본 CSS 애니메이션과 같은 효과를 넣은 코드이다.\n\n**JavaScript 코드를 보면 `setInterval`을 주고 일정 주기마다 `frame()` 함수를 실행시켜 요소를 이동**시키고 있다.\n\n## CSS 애니메이션과 JS 애니메이션의 차이\n\nCSS 애니메이션은 낮은 버전의 브라우저에서는 지원을 하지 않는 경우가 있다.(특히, IE). \n즉, **1. 크로스 브라우징면에서는 JS 애니메이션을 사용하는 것이 좋다.**\n\n하지만, CSS 애니메이션은 **모든 동작을 CSS에서 관리하고 필요하다면 JS는 이벤트 감지를 위해서만 사용**한다.\n\n**2. CSS 애니메이션 실행 로직은 브라우저 자체관리는 해주기 때문에 메모리 소비를 최적화**해준다.\n**3. JavaScript에서는 CSS, 동작을 모두 관리해줘야하는 반면, CSS 애니메이션은 CSS안에서 다 관리하기 때문에 관리에 용이하다.**\n\n---\n\n#### Reference\n\n- [CSS vs. JS 애니메이션: Which is Faster?](https://davidwalsh.name/css-js-애니메이션)\n- [CSS 애니메이션](https://poiemaweb.com/css3-애니메이션)\n- [CSS와 자바스크립트 애니메이션](https://developers.google.com/web/fundamentals/design-and-ux/애니메이션s/css-vs-javascript?hl=ko)\n- [CSS 애니메이션 사용하기 - MDN](https://developer.mozilla.org/ko/docs/Web/CSS/CSS_Animations/Using_CSS_animations)\n- [Web Animations 명세](https://www.w3.org/TR/web-animations/)\n"
  },
  {
    "path": "Javascript/B_Async.md",
    "content": "# Async\n\n자바스크립트는 기본적으로 싱글 쓰레드이다. 이 말을 쉽게 하면 한번에 1가지의 일을 할 수 밖에 없다. 간단한 예제를 들자면 우리가 요리를 한다고 하면, 야채를 썰면서 물을 끓이는 행위를 동시에 할 수 없다는 것을 뜻한다. 이러한 불편한 점을 알았는지 벤더들은 자바스크립트의 싱글 쓰레드를 확장 시켜줄 API를 만들어 주었다.\n\n- [x] setInterval\n- [x] setTimeout\n- [x] requestAnimationFrame\n- [ ] requestIdleCallback\n\n<br/>\n\n## **setInterval**\n\n자바스크립트는 브라우저 내에서 작동하며 기본 동작은 2번째 인자로 받은 `ms` 마다 1번째 인자로 받은 `CallBack Function` 을 실행하는 것을 전제로 한다. \n\n`setInterval` 이 실행이 되면 WEB API에서 시간을 기다리고 있다가 특정시간 마다 큐에 넣게 된다. 그러나 이것은 `CallStack` 이 비어있어야 하며 다른 작업을 계속해서 하고 있다면 한 없이 기다리게 될 수도 있다.\n\n이렇게 `setInterval` 은 지연이 발생할 수 있으며 시간에 따라 증가하게 된다.\n\n이러한 이유는 3가지로 정리 할 수 있다.\n\n- 앱을 실행하는 기기의 하드웨어 제한사항\n- 브라우저의 비활성탭에서 실행되도록 앱남기기(멈추지 않고 계속해서 실행이 된다.)\n- 최적화되지 않은 전체 코드베이스\n\n![Async_1](/assets/image/Async_1.png)\n\n위의 사진을 간단하게 보면 `dummyMethod1()` 이 오래 걸리면 자바스크립트의 이벤트 루프는 본연의 특징으로 인해서 스택에 걸려버렸다. 이런 상황이 되면 실행하기 위해서 기다리는 방법밖에 없다. \n\n이렇게 우리가 조작을 할 수 없는 3번의 순간에 보낸다. 타이머라는게 이상적인 상황일 때는 우리가 생각하는 그 시간에 갈 수 있지만 브라우저와 자바스크립트는 그렇게 이상적이지 않다.\n\n<br/>\n\n## **setTimeout**\n\n`setTimeout` 은 `setInterval` 을 한 번 실행하는 것과 동일하다.\n\n![Async_2](/assets/image/Async_2.png)\n\n위에서 했던 내용을 이번에는 `setTimeout` 의 재귀적 호출로 해보자 그렇게 된다면 결국 `setTimeout` 의  `CallBack Function` 에 `setTimeout` 이 다시 불리는 구조가 될 것이다. 이렇게 만들어서 실행을 한다면 우리가 생각했던 것과 더욱이 달라질 것이다. `setInterval` 은 내가 정한 시간에 맞춰서 CallBack을 실행 하려고 큐에 담았을 것이다. 그러나 `setTimeout` 은 `callback function`이 불려야 다음 `setTimeout` 이 실행이 될 수 있는 조건이 되어 `interval` 보다 지연이 더 심해 질 수 있다.\n\n### 지연예시\n\n```javascript\nvar counter = 0;\n    \nvar fakeTimeIntensiveOperation = function() {\n    \n    for(var i =0; i< 50000000; i++) {\n        document.getElementById('random');\n    }\n    \n    let insideTimeTakingFunction  = new Date().toLocaleTimeString();\n    console.log('insideTimeTakingFunction', insideTimeTakingFunction);\n}\n    \n    \nvar timer = setInterval(function(){ \n    \n    let insideSetInterval = new Date().toLocaleTimeString();\n    \n    console.log('insideSetInterval', insideSetInterval);\n    \n    counter++;\n    if(counter == 1){\n        fakeTimeIntensiveOperation();\n    }\n    \n    if (counter >= 5) {\n        clearInterval(timer);\n    }\n}, 1000);\n    \n//insideSetInterval 13:50:53\n//insideTimeTakingFunction 13:50:55\n//insideSetInterval 13:50:55 <---- not called after 1s\n//insideSetInterval 13:50:56\n//insideSetInterval 13:50:57\n//insideSetInterval 13:50:58 \n```\n\n<br/>\n\n## **requestAnimationFrame**\n\n기본적으로 브라우저는 **60FPS** 이다 그래서 1초에 60번을 실행하게 되면 애니메이션이 깔끔하게 보인다. 그렇다면 위에서 알게 된 `setInterval` 을 사용해서 표현을 하면\n\n```javascript\nsetInterval(function() {\n    // animiate something\n}, 1000/60);\n```\n\n이런식으로 표현이 가능하다. 그러나 위에서 언급을 했지만 문제가 있다.\n이에 2017년 `requestAnimationFrame` 이라는 기능이 크롬의 `Paul Irish`에 의해서 추가가 되었다.\n\nPaul의 설명에 의하면\n\n- 브라우저가 애니메이션을 최적화 할 수 있으므로 애니메이션이 부드럽게 처리될 수 있다.\n- 비활성 탭의 애니메이션이 중지되어 CPU가 시원해진다.\n- 더욱이 배터리 친화적이다.\n\n가장 간단한 예제를 보면\n\n```javascript\nfunction repeatOften() {\n    // Do whatever\n    requestAnimationFrame(repeatOften);\n}\n\nrequestAnimationFrame(repeatOften);\n```\n\n한번 실행하면 재귀적으로 호출한다.\n\n\n```javascript\nrequestAnimationFrame 역시 취소하기 위햇 setTimeout setInterval과 마찬가지로 ID를 반환한다.\n\nglobalID = requestAnimationFrame(repeatOften);\n\ncancelAnimationFrame(globalID);\n```\n\n그러나 아래의 링크를 보면 알게되지만 모든 브라우저가 지원하는 것은 아니다.\n\n> 브라우저 지원여부 확인하기(https://caniuse.com/#feat=requestanimationframe)\n\n### 예제\n\n[https://codepen.io/seonhyungjo/pen/MRVPxL](https://codepen.io/seonhyungjo/pen/MRVPxL)\n\n## 이외의 Async\n\n### **requestIdleCallback**\n\n### **Observer**\n\n- mutation\n- resize\n- intersection\n- performance\n\n---\n\n#### Reference\n\n- [https://javascript.info/settimeout-setinterval](https://javascript.info/settimeout-setinterval)\n- [https://dev.to/akanksha_9560/why-not-to-use-setinterval--2na9](https://dev.to/akanksha_9560/why-not-to-use-setinterval--2na9)\n- [https://develoger.com/settimeout-vs-setinterval-cff85142555b](https://develoger.com/settimeout-vs-setinterval-cff85142555b)\n- [https://www.amitmerchant.com/Handling-Time-Intervals-In-Javascript/](https://www.amitmerchant.com/Handling-Time-Intervals-In-Javascript/)\n- [https://css-tricks.com/using-requestanimationframe/](https://css-tricks.com/using-requestanimationframe/)\n- [http://www.javascriptkit.com/javatutors/requestanimationframe.shtml](http://www.javascriptkit.com/javatutors/requestanimationframe.shtml)\n- [https://yoiyoy.wordpress.com/](https://yoiyoy.wordpress.com/)"
  },
  {
    "path": "Javascript/B_Call_Apply_Bind.md",
    "content": "# Call Apply Bind \n\n## Function vs Method\n\n한가지 예제를 살펴보고 `console.log()`가 어떻게 출력이 되는지 확인해보자. \n\n```js\n// 함수\nconst greeting = () => {\n  console.log(this);\n}\n\nconst module = {\n  greeting() {\n    console.log(this);\n  }\n}\n\ngreeting(); // window object\n\nmodule.greeting(); // module object\n```\n\n흔히 사람들이 실수하는 코드 중 하나이다.\n\n여기서 제일 유심히 보아야 하는 것은 `this`가 다르다는 것이다. Java나 다른 언어에서의 `this`와는 다르게 작동하고 있다.\n\n`this`에 대한 더 많은 내용은 아래의 참고 글을 읽어보길 바란다. \n\n> 참고 <br/>\n> [scope this](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/scope_this.md) <br/>\n> [JavaScript의 this](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/JavaScript%EC%9D%98%20this.md)\n\n```js\nfunction Module(name) {\n    this.name = name;\n}\n\nModule.prototype.getName = function() {\n  var changeName = function() {\n    console.log(this); // window\n    return this.name + '입니다.';\n  }\n    return changeName();\n}\n\nconst module = new Module('sNyung');\n\nconsole.log(module.getName());\n```\n\n위와 같이 메서드 내부에서 함수를 정의하고 `this`를 사용하게 되면 Module이라고 생각하지만 `window`를 바라보고 있다. 그리고 이걸 해결하는 방법으로 흔히 `self` 또는 `that`을 사용한다.\n\n```js\nfunction Module(name) {\n    this.name = name;\n}\n\nModule.prototype.getName = function() {\n  const self = this;\n  // const that = this;\n  \n  const changeName = function() {\n    console.log(self); // Module\n    return self.name + '입니다.';\n  }\n    return changeName();\n}\n\nconst module = new Module('sNyung');\n\nconsole.log(module.getName());\n```\n\n또는 ES6에서 추가가 된 화살표 함수(Arrow Function)를 사용해서 해결 가능하다.\n\n```js\nfunction Module(name) {\n    this.name = name;\n}\n\nModule.prototype.getName = function() {\n  const changeName = () => {\n    console.log(this); // Module\n    return this.name + '입니다.';  \n  }\n    return changeName();\n}\n\nconst module = new Module('sNyung');\n\nconsole.log(module.getName());\n```\n\n<br/>\n\n## call()\n\n자바스크립트에서 object를 효율적으로 사용하면서 재사용 패턴까지 구현할 수 있는 유용한 방법으로 `Function.prototype.call()` 함수가 있다. \n\ncall은 ES6에서 화살표 함수가 나오기 전 `self` 또는 `that`를 사용하지 않고 `this`까지 해결할 수 있는 방법이다.\n\n```js\n function Module(name) {\n    this.name = name;\n}\n\nModule.prototype.getName = function() {\n  const changeName = function() {\n    console.log(this);\n    return this.name + '입니다.';\n  }\n  // return changeName.call(this, 1,2,3,4);\n  return changeName.call(this);\n}\n\nconst module = new Module('sNyung');\n\nconsole.log(module.getName());\n```\n\ncall은 호출하는 즉시 Function을 실행시킨다.  \n\n```js\nfun.call(thisArg[, arg1[, arg2[, ...]]])\n```\n\n<br/>\n\n## apply()\n\n이번에는 call과 매우 유사한 apply를 보자. \n\n```js\nfunction Module(name) {\n    this.name = name;\n}\n\nModule.prototype.getName = function() {\n  const changeName = function() {\n    console.log(this);\n    return this.name + '입니다.';\n  }\n  \n    // return changeName.apply(this, [1,2,3,4]);\n  return changeName.apply(this);\n}\n\nconst module = new Module('sNyung');\n\nconsole.log(module.getName());\n```\n\napply도 호출하는 즉시 Function을 실행시킨다.  \n\n```js\nfun.apply(thisArg, [argsArray])\n```\n    \ncall과 apply는 첫 번째 인자의 `this`를 실행할 함수의 `this`로 설정해준다. apply는 call과 같이 첫 번째 인자로 `this`를 받는 건 똑같지만 뒤에 넘겨줄 값을 `[1,2,3,4,5]`처럼 배열 형태로 넘겨준다. (`call` 같은 경우에는 `1,2,3,4,5`처럼 배열이 아닌 `,`로 전달한다)\n\n<br/>\n\n## bind()\n\ncall과 apply는 실행할 함수의 `this`로 설정하고 바로 실행한다. bind는 함수를 실행하지는 않고 this를 재정의한 새로운 함수를 반환한다.\n\n```js\nfunction Module(name) {\n    this.name = name;\n}\n\nModule.prototype.getName = function() {\n  const changeName = function() {\n    console.log(this);\n    return this.name + '입니다.';\n  }\n  let bindChangeName = changeName.bind(this);\n    return bindChangeName();\n}\n\nconst module = new Module('sNyung');\n\nconsole.log(module.getName());\n```\n\n---\n\n#### Reference\n\n- [https://blog.feruden.com/blog/call-apply-bind-in-javascript](https://blog.feruden.com/blog/call-apply-bind-in-javascript)\n- [https://wayhome25.github.io/javascript/2017/02/18/js-oop-1/](https://wayhome25.github.io/javascript/2017/02/18/js-oop-1/)\n"
  },
  {
    "path": "Javascript/B_Callback.md",
    "content": "# Callback Hell\n\n콜백은 단일스레드 환경(이벤트 루프 큐가 단일 쓰레드)인 자바스크립트에서는 필수 불가결이라고 생각한다.\n[이유를 설명하는 EventLoop](./EventLoop.md)\n\n그런데 이 콜백 때문에 발생될 수 있는 버그가 너무 많고 그 버그를 최근에는 Promise 를 통해 해결한다.\n\n이 콜백이 어떤 문제가 있는지 먼저 살펴본 뒤 다음에는 프로미스가 뭔지도 알아보자.\n\n## 콜백은 어렵다.\n\n콜백은 사실 어렵지 않다.\n\n```js\n//A\najax('...', function thisIsCallBack() {\n  //C\n});\n//B\n```\n\n어렵지 않다. 코드가 '지금' 실행되는 것이 아닌 '나중'에 실행되는 코드다. 그런데 코드가 길어지고 콜백에 콜백에 콜백을 넘어가기 시작하면 지옥에 빠지게 된다.\n\n## 멀티태스킹이 아닌 콘텍스트\n\n인간의 뇌는 기본적으로 싱글쓰레드의 빠른 context 교환기다. 멀티태스킹이 불가능하다. 전화를 받으면서 수학문제를 푼다면 얼핏보기에는 가능할 수 있지만 사실은 전화를 할때와 문제를 풀때는 재빠르게 뇌가 실행기를 움직이며 작동할 뿐이다. 멀티 쓰레딩처럼 따로 움직일 수는 없다.\n\n그래서 백그라운드에 옮겨저 '나중'에 실행되는 콜백과 같은 비동기적 흐름은 인간의 뇌의 flow 와 다르다. 그래서 쉽게 이해가 되지 않는다.\n\n## 단순히 이해만 안되는게 아니다\n\n```js\nlisten('click', function handler(evt) {\n  setTimeout(function request() {\n    ajax('http://....', function response(text) {\n      if (text === 'hello') {\n        handler();\n      } else if (text === 'world') {\n        request();\n      }\n    });\n  }, 500);\n});\n```\n\n이러한 코드는 조금 연습하면 따라 갈 수 있다. 그런데 이 경우 다양한 상황의 에러처리가 안 되어있다. 만일 클릭 이벤트를 통해 ajax()의 url 에서 어떤 작업을하는 중에 또 다시 클릭을 누른다면?? setTimeout 도중 다른 noise 가 발생한다면? 이건 단순한 코드라 몇가지 안되겠지만 코드가 더 복잡하다면?? 더 예를들어 콜백 사이에 다른 콜백이 들어가고 이벤트 루프에 복수의 콜백이 동시에 들어가거나, 분기(경합, 걸쇠)(이건 추후에 설명)를 해야한다거나?? 모든 경우의 수를 따져 코딩하게된다면 엄청난 하드 코딩이 필요할 것이며 코드를 관리하기가 정말 너무나도 힘들게 된다.\n\n## 믿음성\n\n위 내용까지 콜백이 인간의 뇌와는 흐름이 달라 힘들기 어려우며, 경우의 수도 너무 많기 때문에 관리가 힘듦을 보았다.\n그렇지만 사실 콜백의 가장 치명적인 문제는 이해가 힘든 것도, 관리가 잘 되기 힘든 것도 아니다. 믿음성의 문제다.\n\n## 제어권(control)\n\n```js\n//A\najax('...', function thisIsCallBack(data) {\n  //C\n});\n//B\n```\n\n다시 이 코드를 보자. 이 코드는 프로그램이 진행중에 ajax 가 실행완료가 되면 thisIsCallBack 을 큐에 넣으라는 의미다. 여기서 ajax 는 콜스택에 밀어넣는 이벤트 루프의 행위로 콜스택의 제어권(control)을 가지게 된다. 이게 중요하다. 제어권. 이를 제어의 역전*Inversion of Control*이라고 한다.\n\n이 제어권이 넘어가게 되면 믿음의 문제가 생긴다. 내가 실행하는 환경의 call stack을 누군가가 임의로 제어할 수 있다는 것이다.\n\n예를 들어보자. ajax 를 통해 API를 호출한다. 이 API는 내가 작성한 코드가 아니며 서드파티 유틸리티거나 누군가 만들어 놓은 라이브러리를 이용해 data 만 받는다. 위의 코드처럼 비동기 호출을 하게되면 이 외부 라이브러리가 내 콜스택을 조절할 수 있는 제어권을 갖게된다. 그게 문제다.\n\n## 콜백지옥\n\nYOU DON'T KNOW JS 의 예시를 빌려오자. 현재 상황은 쇼핑몰 전자상거래 결제 시스템이다. 고객이 확인 버튼을 누르면 어떤 분석 추적 솔루션의 함수를 호출해서 구매정보를 추적한다고 하자. 추적이 완료되면 결제가 승인되며, 결제완료 페이지로 넘어간다. 의사코드를 보자면 아래와 같다.\n\n```js\nsolutionUtil.trackPurchase(purchaseData, function CBF() {\n  // 결제데이터를 넘긴 뒤\n  // 비동기적인 처리가완료되면 콜백실행\n  assignCredit(); // 결제\n  goThanksPage(); // 페이지 이동\n});\n```\n\n흔히 볼 수 있는 코드다.\n\n그런데 저 유틸리티가 어떤 특정 조건에서는 초당 한번씩 받아온 콜백(CBF())을 호출한다고 하자. 제어권이 넘어가 콜백함수를 실행시키는것이 우리의 프로그램이 아니라 백그라운드의 저 함수다.\n그런데 만일 저 유틸리티가 콜백을 잘못 호출하게끔 코드를 변경했다고 생각해보자. 내 문제는 없다. 다만 저 유틸이 잘못되어 고객이 5 번 결제가 되었다고 한다. 끔찍하다. 그냥 유틸리티를 제공한 솔루션회사에게 책임을 맡기고 업체를 다른곳으로 바꾸면 될까?? 애초에 잠재적인 버그가 있는 코드라면 없애야 맞다.\n\n```js\nvar tracked = false;\n\nsolutionUtil.trackPurchase(purchaseData, function CBF() {\n  if (!tracked) {\n    tracked = true;\n    assignCredit();\n    goThanksPage();\n  }\n});\n```\n\n때문에 관문을 만들었다. 한번 이상은 실행되지 않는다. 근데 만일 또 코드가 잘못되어 한번도 호출하지 않는다면? 그 이외에도 콜백을 너무 일찍 부르거나, 늦게 부르거나, 많이부르거나 에러(exception) 발생이라던가 데이터가 비정상이라던가... 모든 예외의 경우를 모두 처리해줄 것인가? 그럼 또 하드코딩인데? **콜백 지옥**에 빠지게 된다.\n\n## 큰 문제점은 믿음\n\n중요한 점은 외부의 비동기적 코드를 100% 믿을 수 없다는 점이다. 그런데 그 못 믿을 코드에게 내 콜스택을 움직일 수 있는 제어권을 넘겨준다?? 분명히 버그가 발생할 수 있다.\n\n꼭 외부의 코드만 문제가 되는 것은 아니다. 내가 짠 코드도 예상치 못한 곳에서 잠재적인 버그를 가질 수 있다. 그런데 문제는 이 제어권을 그 못믿는 코드에게 줄 수 밖에 없는 디자인이라는 것이다.\n\n## ES5 에서의 해결\n\n두가지 방법을 혼용해서 \"방지\"할 수는 있다.\n\n```js\nfunction success(data) {\n  console.log(data);\n}\nfunction failure(err) {\n  console.log(err);\n}\nvar a = 0;\n\najax('url...', asyncify(success(data)), failure(err));\n```\n\n`asyncify()`에는 비동기를 동기화 시켜서 success 를 실행하고 혹시 ajax 의 결과가 에러면 failure 를 실행시킨다. 이러면 에러처리가 우선 해결된다. 그리고 asyncify 를 통해서 일시적으로 동기화를 시켜 비동기 결과가 아직 도착한 뒤 콜백을 실행시키게 만들 수는 있다. 그런데 이를 위해 저 asyncify 라는 함수를 만들어야 하고 거기서 에러는 없는지 테스트 해보고... 점점 무거워질 것이다.\n\n이를 해결하기 위해 ES6 에서 등장한것이 바로 Promise 다.\n[Promise1.md](./Promise1.md)\n"
  },
  {
    "path": "Javascript/B_Class.md",
    "content": "# Class\n \n ES6에 Class 문법이 추가되었다. Class는 특별하게 새로 만들어진 것이 아니다. 기존에 존재하고 있던 상속과 생성자 함수를 기본으로 한 `Proptotype`의 **syntactic sugar**이다.\n \n Class 문법이 나오기 전 사람들은 JavaScript를 OOP답게 사용하고 싶어 했다. 그래서 다양한 방법을 사용해서 구현했다.\n\n<br/>\n\n## Constructor Function\n\n> constructor function은 일반 function이며, 설명상 명확하게 나타내기 위하여 대문자를 사용하였습니다.\n\nClass 문법이 생기기 전에는 JavaScript에서는 모든 것을 Function으로 만들어야 했다. 그래서 사람들이 Class처럼 사용하기 위해서 Constructor function을 사용해서 비슷하게 사용하였다.\n\n```js\nfunction Vehicle(make, model, color) {\n    this.make = make,\n    this.model = model,\n    this.color = color,\n    this.getName = function () {\n        return this.make + \" \" + this.model;\n    }\n}\n```\n\n위와 같이 함수를 선언함으로써 Java에서 사용하는 Class와는 모양새는 다르지만, Class에 좀 더 가까워졌다. 이제 우리는 `Vehicle`이라는 것을 선언했으니 인스턴스를 만들어보자\n\n```js\nconst car = new Vehicle(\"Toyota\", \"Corolla\", \"Black\");\nconst car2 = new Vehicle(\"Honda\", \"Civic\", \"White\");\n```\n\n위와 같이 `new` 키워드를 사용해서 인스턴스를 만들 수 있다. \n\n**그런데 문제가 있다.** \n\n새로운 `Vehicle()`을 만들 때 JavaScript 엔진은 두 객체의 각각에 대한 Vehicle Constructor 함수 사본을 만든다. 즉 각각의 인스턴스의 공간이 만들어지는 것이다. 또한 속성과 메소드는 `Vehicle()`의 모든 인스턴스에 복사가 된다. \n\n이게 왜 문제가 되는가? 라고 생각할 수 있다. 문제는 Constructor 함수의 멤버 함수(메서드)가 **모든 객체에서 반복된다는 것이다.**\n\n다른 문제는 **기존의 만든 객체에 새로운 속성이나 메서드를 추가 하지 못한다는 것이다.**\n\n```js\ncar2.year = \"2019\"\n```\n\n위와 같이 추가를 하더라도 다른 인스턴스에는 새로운 속성이나 메서드는 따로따로 넣어주어야 한다.\n\n```js\nfunction Vehicle(make, model, color, year) {\n    this.make = make,\n    this.model = model,\n    this.color = color,\n    this.year = year, // 위와 같이 추가를 해야한다.\n    this.getName = function () {\n        return this.make + \" \" + this.model;\n    }\n}\n```\n\n<br/>\n\n## Prototype\n\nJavaScript는 내부적으로 새로운 함수가 만들어지면 JavaScript엔진이 `prototype` 속성을 추가해준다.\n\n![image](https://user-images.githubusercontent.com/24274424/58709477-3b804900-83f5-11e9-882d-f6dbddae0254.png)\n\n`prototype` 중 `__proto__` 속성은 **dunder proto** 라고 불리고, Constructor 함수의 `prototype` 속성을 가리킨다.\n\n생성자 함수의 새로운 인스턴스를 만들어질 때마다 **dunder proto**는 다른 속성, 메서드와 함께 인스턴스에 복사가 된다.\n\n![image](https://user-images.githubusercontent.com/24274424/58709719-b5b0cd80-83f5-11e9-93fc-b5ac236dca0f.png)\n\n`prototype` 객체는 아래와 같이 Constructor 함수의 속성, 메서드를 추가 가능하며 Constructor 함수의 모든 인스턴스에서 사용할 수 있다.\n\n```js\nVehicle.prototype.year = \"2019\"\n```\n\n![image](https://user-images.githubusercontent.com/24274424/58710008-569f8880-83f6-11e9-8754-071bc6f58d3c.png)\n\n이 접근법에는 주의사항이 있다. `prototype` 속성과 메서드는 Constructor 함수의 모든 인스턴스와 공유된다. 인스턴스의 기본 속성이 변경되면, 모든 인스턴스가 아닌 해당 인스턴스에서만 변경이 이루어진다.\n\n다른 한 가지는 참조 유형 속성이 모든 인스턴스 간에 항상 공유되는 것이다. 하나의 인스턴스에서 수정하면 모든 인스턴스의 참조 유형 속성이 수정된다.\n\n![image](https://user-images.githubusercontent.com/24274424/58710329-0674f600-83f7-11e9-9d5d-6438ed6eec9c.png)\n\n<br/>\n\n## Class\n\n지금까지 Constructor 함수와 `prototype`에 대해 알아봤다. 이제 Class에 대해 알아보자. 위의 2개를 살펴보면 좀 더 쉽게 이해할 수 있다. Class는 이전의 것들과 크게 차이가 나는 것이 없기 때문이다. \n\nJavaScript 클래스는 `prototype` 기능을 활용하여 Constructor 함수를 작성하는 새로운 방법일 뿐이다.(**syntactic sugar**)\n\n```js\nclass Vehicle {\n    constructor(make, model, color) {\n        this.make = make;\n        this.model = model;\n        this.color = color;\n    }\n\n    getName() {\n        return this.make + \" \" + this.model;\n    }\n}\n```\n    \n위와 같이 Class를 생성할 수 있다. \n\nClass도 마찬가지로 우리가 앞서 만든 것과 동일하게 `new` 키워드를 사용하여 인스턴스를 생성한다.\n\n```js\nconst car = new Vehicle(\"Toyota\", \"Corolla\", \"Black\");\n```\n\nClass로 만든 것을 기존 방법으로 다시 작성한다면 아래와 같을 것이다.\n\n```js\nfunction Vehicle(make, model, color) {\n    this.make = make;\n    this.model = model;\n    this.color = color;\n}\n\nVehicle.prototype.getName = function () {\n    return this.make + \" \" + this.model;\n}\n    \nconst car = new Vehicle(\"Toyota\", \"Corolla\", \"Black\");\n```\n    \n\n이것은 Class가 Constructor 함수를 수행하는 새로운 방법이라는 것을 증명한다. 더욱 실제 Class와 비슷하게 만들기 위해서 도입된 몇 가지 규칙이 있다.\n\n#### 생성자가 작동하려면 `new` 키워드가 필요하다.\n\n```js\nconst car = new Vehicle(\"Toyota\", \"Corolla\", \"Black\");\n````\n\n`new`를 사용하지 않고 만들 경우 아래와 같은 에러가 발생한다.\n\n#### Class의 메서드는 non-enumerable 하다. \n\nJavaScript에서 객체의 각 속성에는 해당 속성에 대해 `enumerable flag` 가 있다. Class는 `prototype`에 정의된 모든 메서드에 대해 이 `flag`를 `false`로 설정한다.\n\n#### Class에 생성자를 추가하지 않으면 기본 빈 `constructor()`가 자동으로 추가된다.\n\n```js\nconstructor(){ }\n```\n\n####  Class 안의 코드는 항상 **`strict` 모드** 이다. \n\n이것은 오류가 없는 코드를 작성하거나, 잘못된 입력 또는 코드 작성 중 구문 오류 또는 다른 곳에서 참조된 실수로 일부 코드를 제거하여 코드를 작성하는 데 도움을 준다.\n\n#### Class는 호이스팅이 되지 않는다.\n\n![image](https://user-images.githubusercontent.com/24274424/58710983-8059af00-83f8-11e9-91ae-f6b3fb887146.png)\n\n#### Class는 Constructor 함수나 객체 리터럴과 같은 속성 값 할당을 허용하지 않는다. \n\n함수 또는 `getter/setter` 만 가질 수 있다. `property:value` 할당은 불가능하다.\n\n<br/>\n\n### Class Features\n\n#### `constructor`\n\n`constructor`는 함수 자체를 정의하는 **Class 선언의 특수 함수**이다. 인스턴스를 새로 만들면 `constructor()`가 자동으로 호출된다.\n\n```js\nconst car = new Vehicle(\"Honda\", \"Accord\", \"Purple\"); // call constructor\n```\n\n`constructor`는 `super` 키워드를 사용하여 확장된 Class `constructor`를 호출할 수 있다.\n\n**하나 이상의 생성자 함수를 가질 수 없다.**\n\n#### Static Methods\n\nStatic Methods는 `prototype` 에 정의된 Calss의 다른 메서드와는 다르게 `prototype`이 아닌 Class 자체의 함수이다.\n\nStatic Methods는 `static` 키워드를 사용하여 선언하며 주로 유틸리티 함수를 만드는 데 사용된다. Class의 인스턴스를 만들지 않고 호출 가능하다. \n\n```js\nclass Vehicle {\n    constructor(make, model, color) {\n        this.make = make;\n        this.model = model;\n        this.color = color;\n    }\n\n    getName() {\n        return this.make + \" \" + this.model;\n    }\n\n    static getColor(v) {\n        return v.color;\n    }\n}\n\nlet car = new Vehicle(\"Honda\", \"Accord\", \"Purple\");\n\nVehicle.getColor(car); // \"purple\"\n```\n\n**정적 메서드는 Class 인스턴스에서 호출할 수 없다.**\n\n#### Getter / Setter\n\ngetter/setter를 사용하여 속성값을 가져오거나 속성값을 설정할 수 있다. \n\n```js\nclass Vehicle {\n    constructor(model) {\n        this.model = model;\n    }\n    \n    get model() {\n        return this._model;\n    }\n\n    set model(value) {\n        this._model = value;\n    }\n}\n```\n\ngetter/setter는 Class `prototype`에 정의된다.\n\n![image](https://user-images.githubusercontent.com/24274424/58711552-bb101700-83f9-11e9-8298-959c243f3989.png)\n\n#### Subclassing\n\nSubclassing은 Javascript Class에서 상속을 구현할 수 있는 방법으로 `extends` 키워드는 Class의 하위 클래스를 만드는 방법이다.\n\n```js\nclass Vehicle {\n    constructor(make, model, color) {\n        this.make = make;\n        this.model = model;\n        this.color = color;\n    }\n\n    getName() {\n        return this.make + \" \" + this.model;\n    }\n}\n\nclass Car extends Vehicle{\n    getName(){\n        return this.make + \" \" + this.model +\" in child class.\";\n    }\n}\n\nconst car = new Car(\"Honda\", \"Accord\", \"Purple\");\n\ncar.getName(); // \"Honda Accord in child class.\"\n```\n\n\n`getName()`를 호출하면 자식클래스의 함수가 호출된다.\n\n가끔 부모의 함수를 사용해야 할 때가 있다. 그럴 때는 `super` 키워드를 사용하면 된다.\n\n```js\nclass Car extends Vehicle{\n    getName(){\n        return super.getName() +\"  - called base class function from child class.\";\n    }\n}\n```\n\n- 옛날 방식인 `prototype`을 사용해서 상속 구현해보기\n\n```js\nfunction Vehicle(make, model, color) {\n    this.make = make;\n    this.model = model;\n    this.color = color;\n}\n\nVehicle.prototype.getName = function() {\n    return this.make + \" \" + this.model;\n};\n\nfunction Car(make, model, color) {\n    this.make = make;\n    this.model = model;\n    this.color = color;\n}\nObject.setPrototypeOf(Car, Vehicle);\nObject.setPrototypeOf(Car.prototype, Vehicle.prototype);\nCar.prototype.getName = function() {    \n    return this.make + \" \" + this.model +\" in child class.\";\n};\n\nconst vehicle = new Vehicle(\"Honda\", \"Accord\", \"Purple\");\nconst car = new Car(\"Honda\", \"Accord\", \"Purple\");\n\nconsole.log(vehicle.getName()); // Honda Accord\nconsole.log(car.getName()); // Honda Accord in child class.\n```\n\n<br/>\n\n## 팩토리 디자인 패턴 간단히 살펴보기\n\n위의 코드를 아래와 같이 변경을 함으로써 `new` 키워드를 사용하지 않고 매번 새로운 객체를 만들어서 전달받는다. \n\n```js\nconst Vehicle = function(make, model, color){\n    const newVehicle = {};\n    newVehicle.make = make;\n    newVehicle.model = model;\n    newVehicle.color = color;\n    \n    newVehicle.getName = function(){\n        return this.make + \" \" + this.model;\n    }\n    return newVehicle;\n};\n\nconst vehicle = Vehicle(\"Honda\", \"Accord\", \"Purple\");\n\nconsole.log(vehicle.getName()) //Honda Accord\n```\n\n---\n\n#### Reference\n\n- [Understanding Classes in JavaScript](https://www.digitalocean.com/community/tutorials/understanding-classes-in-javascript)\n- [How ES6 classes really work and how to build your own](https://medium.com/@robertgrosse/how-es6-classes-really-work-and-how-to-build-your-own-fd6085eb326a)\n- [Understand the Factory Design Pattern in plain JavaScript](https://medium.com/front-end-weekly/understand-the-factory-design-pattern-in-plain-javascript-20b348c832bd)\n- [Javascript Classes — Under The Hood](https://medium.com/tech-tajawal/javascript-classes-under-the-hood-6b26d2667677)\n"
  },
  {
    "path": "Javascript/B_Function.md",
    "content": "# **Function**\n\n## **목차**\n\n- [x] Global Scope\n- [x] Local Scope\n- [x] Functional Scope\n- [x] Block Scope\n- [x] Lexical Scope \n- [x] Function\n    - [x] Function Declaration\n    - [x] Function Expression\n    - [x] Named Function Expression\n- [x] IIFE(Immediately Invoked Function Expression)\n\nFunction에 대해서 자세히 알아보기 전에 우리는 자바스크립트의 Scope에 대해서 알아보자\n자바스크립트에서의 Scope는 크게 2가지이다.\n\n- **Global Scope**\n- **Local Scope**\n\n함수 안에서 정의가 된 변수들은 기본적으로 **Local Scope** 에서 선언이 되었다고 하면, 함수 외부에 정의된 변수는 **Global Scope** 에서 선언이 되었다고 한다. 함수 외부라고 하면 단순하게 중첩된 함수에서의 외부가 아닌 **함수 1개가 있다는 기준에서의 외부** 이다. 이렇게 완전한 외부를 우리는 **Window** 라고 하자.\n\n또한 각각의 함수들은 실행이 되면 내부적으로 New Scope를 생성하고 가지게 된다.\n<br/>\n\n## **Global Scope**\n\n우리가 자바스크립트를 실행하게 되면 이미 **Global Scope** 안에 있는 것이다. 그래서 우리가 Function 안쪽에서 선언하지 않고 기본적으로 선언하는 것들은 **Global Scope** 에서 선언하는 것이다.\n\n```javascript\n// 이 부분이 바로 기본값인 Global Scope이다.\nconst name = 'sseon';\nconst age = '27';\n```\n\nGlobal로 선언한 변수는 다른 Scope 어디에서든 접근이 가능하다.\n\n```javascript\nconst name = 'sseon';\n    \nconsole.log(name); // 같은 Scope에서의 호출은 된다. => logs 'sseon'\n    \nfunction logName() {\n    console.log(name); // 'name' 이라는 변수가 어디서든 접근이 가능하다.\n}\n    \nlogName(); // logs 'sseon'\n```\n\n<br/>\n\n## **Local Scope**\n\n함수안에 선언한 변수는 **Local Scope** 안에 있는 것이다. 우리는 같은 변수의 이름을 다른 함수안에서 각각 정의를 할 수 있는데, 해당 변수가 서로 다른 Scope에 바인딩이 되어 각각의 함수에서는 접근이 불가능하게 된다.\n\n```javascript\n// Global Scope\nfunction someFunction() {\n    // Local Scope #1\n    function someOtherFunction() {\n        // Local Scope #2\n    }\n}\n    \n// Global Scope\nfunction anotherFunction() {\n    // Local Scope #3\n}\n// Global Scope\n```\n\n위와 같이 코드가 짜였다고 한다면 **Local Scope#1** 에서 선언한 변수는 **Local Scope#2** 에서는 접근이 가능하지만 **Local Scope#3** 에서는 접근이 불가하다. 마찬가지로 **Local Scope#3** 에서 선언된 변수는 **Local Scope#1**, **Local Scope#2** 에서 접근이 불가하다. **Local Scope#2** 에서 **Local Scope#1** 접근이 가능한 이유는 뒤에서 다룰 것이다.\n<br/>\n\n## **Functional Scope**\n\n자바스크립트는 위에서 본 것과 같이 **함수를 단위로 Scope를 구분한다.** 즉 같은 함수안에서 선언된 변수들은 같은 Level의 Scope를 가지게 되는 것이다. 각각의 함수는 독립적인 Scope를 가지게 되어 다른 함수의 Scope에 접근을 할 수 없다.\n\n```javascript\n// Global Scope\nfunction someFunction() {\n    if (true) {\n        var name = 'sseon'; \n    }\n}\n```\n\n위와 같이 Global Scope에 `someFunction()` 을 선언하고 내부에 if문 괄호 안에 선언한 변수는 **someFunction function Scope** 에 붙게 되는 것이다.\n<br/>\n\n## **Block Scope**\n\nBlock Statement는 우리가 많이 보는 if문, switch문, for, while문이다. 이러한 문장들은 괄호로 감싸진 부분이 존재하지만 새로운 Scope를 만들지는 않는다. Block Statement 안에서 정의한 변수는 가장 가까운 함수의 Scope에 붙게 된다.\n\n```javascript\nif (true) {\n    // this 'if' conditional block doesn't create a new scope\n    var name = 'sseon'; // name is still in the global scope\n}\n    \nconsole.log(name); // logs 'sseon'\n```\n\nECMAScript6에서 `let`, `const`가 추가 되었다. 이 2개는 `var` 대용으로 사용된다. 그러나 그보다 더 중요한 개념이 들어간다. 바로 **Block Level Scope** 라는 것이다. 기존의 자바스크립트는 위에서 본 것처럼 **Functional Scope** 이다. 그러나 `let`, `const` 를 사용하게 되면 **Block Level Scope** 지원이 가능하다. 아래의 예제를 보자\n\n```javascript\nif (true) {\n    // this 'if' conditional block doesn't create a new scope\n    var name = 'sseon'; // name is still in the global scope\n    let likes = 'Coding';\n    const skills = 'Javascript';\n}\n    \nconsole.log(name); // logs 'sseon'\nconsole.log(likes); // Uncaught ReferenceError: likes is not defined\nconsole.log(skills); // Uncaught ReferenceError: skills is not defined\n```\n\n`var`와는 다르게 `let`, `const`는 Block Statement내에서 **Local Scope** 를 지원한다. 즉 이제 Scope가 가장 가까운 function에 붙는 것이 아닌 해당 Block에 붙게 되는 것이다.\n\n**Global Scope는 응용 프로그램이 살아있을 때까지 유효하며, Local Scope은 함수가 호출되고 실행되는한 유지가 된다.**\n<br/>\n\n## **Lexical Scope**\n\n**Lexical Scope** 는 중첩된 함수에서 내부 함수는 부모 Scope의 변수와 다른 자원에 접근이 가능하다. 즉, 하위 함수는 부모의 실행 컨텍스트에 바인딩된다. **Lexical scope** 는 때때로 **Static Scope** 라고도 불린다.\n\n```javascript\nfunction grandfather() {\n    var name = 'sseon';\n        // likes is not accessible here\n    function parent() {\n            // name is accessible here\n            // likes is not accessible here\n        function child() {\n            // Innermost level of the scope chain\n            // name is also accessible here\n            var likes = 'Coding';\n        }\n    }\n}\n```\n\n<br/>\n\n## **Function**\n\n함수는 자바스크립트에서 중요한 컨셉이다. 자바스크립트에서 함수는 1급 객체이다. \n\n1. **Function Declaration(함수 선언식)**\n2. **Function Expression(함수 표현식)**\n3. **Named Function Expression(이름이 있는 함수 표현식)**\n\n<br/>\n\n## **함수 선언식**\n\n```javascript\nfunction [name](param1, param2, ...param3) {\n    // Function Body & Logic\n}\n```\n\n`[function name]` 앞에 `[function keyword]` 를 붙인다. 항상 앞에 function으로 시작하며 함수의 이름을 지어주어야 한다. 그리고 선언식의 주요한 개념은 전체 기능이 **호이스팅** 이 된다는 것이다. \n\n**이러한 호이스팅으로 인해서 함수를 선언하기전에 함수를 실행하는 코드를 넣어도 작동하는 것이다.**\n\n이러한 선언 방법은 일부 논리를 함수 본문으로 추상화를 하고 나중에 실제 구현이 완료될때 유용하다.\n\n```javascript\nvar num1 = 10;\nvar num2 = 20;\nvar result = add(num1, num2); // ==> 30 [Executing before declaring]\n\nfunction add(param1, param2) {\n    return param1 + param2 ;\n}\n```\n\n그러나 이러한 코드는 좋지 못하다. 항상 호이스팅을 이용하는 것이 아닌 함수를 먼저 선언을 하고 실행하는 습관을 들이는 것이 좋다.\n<br/>\n\n## **함수 표현식**\n\n어떤 값을 다른 변수에 할당하는 명령문은 표현식으로 간주된다.\n\n```javascript\nvar a = 100;\nvar b = 'Hello World';\n```\n\n함수 표현식의 경우 이름이 없이 함수를 작성을 하며 변수에 할당을 한다.\n\n```javascript\nvar [name] = function(param1, param2, ...param3) {\n    // Function Body & Logic\n}\n\nfoo(1,3,4);\n```\n\n함수 선언식과 다르게 정의될 때까지 함수를 사용할 수 없다. 즉 호이스팅이 일어나지 않는다는 것을 의미한다. 정확하게 보면 변수는 호이스팅이 일어나지만 할당이 이루어지는 행위는 호이스팅이 안된다고 보는 것이 좋을 듯 하다.\n\n```javascript\nvar num1 = 10;\nvar num2 = 20;\nvar result = add(num1, num2);  \n// Uncaught TypeError: add is not a function\nvar add = function(param1, param2) {\n    return param1 + param2 ;\n}\n```\n\n위와 같은 코드는 작동하지 않는다. 아래와 같이 작성을 하여야한다.\n\n```javascript\nvar num1 = 10;\nvar num2 = 20;\nvar add = function(param1, param2) {\n    return param1 + param2 ;\n}\nvar result = add(num1, num2); // ==> 30\n```\n\n<br/>\n\n### 함수 표현식의 장점\n\n선언식보다 표현식이 더 유용하게 사용되는 몇가지 이유\n\n- As closures\n- As arguments to other functions\n- **As Immediately Invoked Function Expressions (IIFE)**\n\n<br/>\n\n## **이름이 있는 함수 표현식 - 두 가지 접근 방식의 결합**\n\n선언식과 표현식의 차이점을 보고 두가지를 섞으면 어떻게 되는지 살펴보자.\n\n```javascript\nvar num1 = 10;\nvar num2 = 20;\nvar addVariable = function addFunction(param1, param2) {\n    return param1 + param2 ;\n}\n```\n\n위에 코드를 보게 되면 표현식이 더이상 익명이 아니고 `addFunction` 이라는 이름을 가지고 있다. 또한 `addVariable` 이라는 변수명에 할당을 하였다.\n\n우리가 함수의 이름으로 `addFunction` 을 추가했다고 실행할 수 있는 것은 아니다.\n\n```javascript\nvar result = addFunction(num1, num2); \n// ==> Uncaught ReferenceError: addFunction is not defined\n```\n\n우리가 할당한 `addVariable` 변수로만 사용이 가능하다.\n\n```javascript\nvar result = addVariable(num1, num2); \n// ==> 30\n```\n\n**고려해야할 사항**\n\n1. `addFunction` 이 `addVariable` 보다 콜스택상 먼저 나오게 된다.\n2. 외부에서 `addFunction` 을 호출하게 되면 에러가 나오게 된다.\n    1. 그러나 내부에서는 `addFunction` 을 사용할 수 있다.\n\n```javascript\nvar num1 = 10;\nvar num2 = 20;\nvar addVariable = function addFunction(param1, param2) {\n    var res = param1 + param2;\n    if (res === 30) {\n        res = addFunction(res, 10);\n    }\n    return res;\n}\nvar result = addVariable(num1, num2); // ==> 40\n```\n\n결과가 30이 아니라 내부적으로 `addFunction` 이 한번 더 호출되어 40이 나오게 된다.\n\n3. IE8이하에서는 이름이 있는 함수 표현식을 사용하게 되면 심각한 이슈가 발생하게 되는데, 바로 완전히 다른 두개의 함수객체를 생성한다는 것이다.(**Double take**).\n\n**IE8을 지원해야하는 일이 있으면 익명의 표현식을 사용하는 것을 추천한다.**\n\n<br/>\n\n## **Statements, Expressions**\n\n**Expressions** 는 단일 값이 되는 자바스크립트 코드 Snippets이다. 표현식은 원하는만큼 길게 사용이 가능하지만 단일 값이다.\n\n```javascript\n2 + 2 * 3 / 2\n    \n(Math.random() * (100 - 20)) + 20\n    \nfunctionCall()\n    \nwindow.history ? useHistory() : noHistoryFallback()\n    \n1+1, 2+2, 3+3\n    \ndeclaredVariable\n    \ntrue && functionCall()\n    \ntrue && declaredVariable\n```\n\n위의 예제들은 모두 표현식이다. 흔히 값을 원할때 어디서든 사용하는 방법이다. 그래서 아래의 예제에서도 값이 단일값으로 나오게 된다.\n\n```javascript\nconsole.log(true && 2 * 9) // 18\n```\n\n**표현식은 상태를 변경하지 않는다.**\n\n```javascript\nvar assignedVariable = 2; //this is a statement, assignedVariable is state\n\nassignedVariable + 4 // expression\nassignedVariable * 10 // expression\nassignedVariable - 10 // expression\n\nconsole.log(assignedVariable) // 2\n```\n\n위의 예제들은 표현식임에도 할당된 값은 마지막까지 2로 남는다. 함수 호출은 표현식이지만 함수 상태를 변경할 수 있는 문장은 필수적이다.\n\n```javascript\nconst foo = () => {\n    assignedVariable = 14\n}\n```\n\n`foo()` 는 표현식이지만 undefined나 다른 값을 반환한다. 그러나 이렇게 사용하게 됨으로써 상태를 변화시킬 수 있다. \n\n```javascript\nconst foo = () => {\n  return 14 //explicit return for readability\n}\n\nassignedVariable = foo()\n```\n\n더 좋은 방법은 아래와 같이 작성하는 것이다.\n\n```javascript\nconst foo = () => {\n  return 14 //explicit return for readability\n}\n    \nassignedVariable = foo()\n```\n\n```javascript\nconst foo = (n) => {\n    return n//explicit return for readability\n}\n\nassignedVariable = foo(14)\n```\n\n이렇게 작성을 하면 코드가 읽기 쉽게 구성이 가능하며 표현식과 명령문을 명확하게 구분할 수 있다. 이런 것이 선언적 자바스크립트의 근본이다.\n<br/>\n\n## **Statements**\n\n기본적으로 문장은 행동을 수행한다. \n\n자바스크립트에서 값이 필요한 곳에서는 명령문을 사용할 수 없다. 그래서 함수의 인수, 할당의 오른쪽, 연산자, 피연산자, 반환값으로 사용할 수 없다.\n\n```javascript\nfoo(if () {return 2}) \n```\n\n명령문의 종류\n\n1. if\n2. if-else\n3. while\n4. do-while\n5. for\n6. switch\n7. for-in\n8. with (deprecated)\n9. debugger\n10. variable declaration\n\n브라우저 콘솔창에서 아래와 같이 입력을 치게 되면,\n\n```javascript\nif (true) { 9+9 }\n```\n\n18을 반환한다. 그러나 원하는 곳에 사용은 할 수 없다. 명령문은 아무것도 반환하지 않기를 바란다. 우리가 그것을 사용할 수 없다면 반환된 값은 쓸모가 없어지기 때문이다.\n<br/>\n\n## **IIFE(Immediately Invoked Function Expression)**\n\n우리가 흔히 **즉각 실행함수** 라 부르는 패턴이다. 이것을 사용하면 함수는 새로운 Scope를 만들게 된다. **IIFE** 는 단순하게 함수 표현식이다. 인터프리터가 즉각적으로 실행한다.\n\n익명함수의 표현식과 비슷하게 생겼다. \n\n```javascript\nvar foo = 'foo';\n    \n(function bar () {\n  console.log('in function bar');\n})()\n    \nconsole.log(foo);\n```\n\n위에서 간단하게 보면 `foo` 가 출력되기 전에 `bar()` 를 호출하지 않았는데 **in function bar** 가 출력이 되었다. \n\n- `(` 괄호를 사용해서 함수를 감싸서 선언식이 아닌 표현식이 된다.\n- 마지막에 `()` 괄호를 다시 써서 표현식을 즉시 실행하는 구문이 된다.\n\nES6 이전에는 IIFE를 사용해서 외부에서 접근하지 못하도록 변수를 숨기고 제한하는데 사용이 되었다. 또한 비동기 작업을 실행하고 IIFE 범위에서 변수상태를 보존하려는 경우에도 매우 유용하다. \n\n```javascript\nfor (var i = 0; i < 5; i++) {\n    setTimeout(function () {\n        console.log('index: ' + i);\n    }, 1000);\n}\n```\n\n위에 코드는 흔히 발생하는 잘못된 코드이다. 이와 같은 코드를 IIFE를 사용해서 해결할 수 있다.\n\n```javascript\nfor (var i = 0; i < 5; i++) {\n    (function logIndex(index) {\n        setTimeout(function () {\n            console.log('index: ' + index);\n        }, 1000);\n    })(i)\n}\n```\n\n그러나 ES6+를 사용한다면 **Block Level Scope** 를 지원하는 `let` 또는 `const` 를 사용하면 된다.\n<br/>\n\n## **부록**\n\n### **Semi-colon vs Comma operator**\n\n세미콜론을 사용함으로써 표현식을 표현식 문장으로 변환 시킬 수 있다. `2+2` 자체는 표현식이지만 완전한 라인은 문장이다.\n\n```javascript\n2+2 // on its own is an opposition\n    \nfoo(2+2) //so you can use it anywhere a value is expected\n    \ntrue ? 2+2 : 1 + 1\n    \nfunction foo () {return 2+2}\n    \n2+2; //expression statement\nfoo(2+2;) //syntaxError\n```\n\n세미콜론을 사용하면 여러 줄을 한 줄로 표현이 가능하다.\n\n```javascript\nconst a; function foo () {}; const b = 2\n```\n\n쉼표 연산자를 사용하면 여러 표현식을 연결하여 마지막 표현식만 반환이 가능하다.\n\n```javascript\nconsole.log( (1+2,3,4) ) //4\nconsole.log( (2, 9/3, function () {}) ) // function (){}\nconsole.log( (3, true ? 2+2 : 1+1) ) // 4\n```\n\n모든 표현식은 왼쪽에서 오른쪽으로 계산이 되고 마지막 표현식이 반환된다.\n<br/>\n\n---\n\n#### Reference\n\n- [Understanding Scope in JavaScript](https://www.telerik.com/blogs/understanding-scope-in-javascript)\n- [Understanding Scope in JavaScript](https://scotch.io/tutorials/understanding-scope-in-javascript)\n- [Understanding Scope in JavaScript](https://www.telerik.com/blogs/understanding-scope-in-javascript)\n- [JavaScript Scope and Closures](https://css-tricks.com/javascript-scope-closures/)\n- [JavaScript Functions — Understanding The Basics](https://codeburst.io/javascript-functions-understanding-the-basics-207dbf42ed99)\n- [All you need to know about Javascript's Expressions, Statements and Expression Statements](https://dev.to/promhize/javascript-in-depth-all-you-need-to-know-about-expressions-statements-and-expression-statements-5k2)\n- [Quick Tip: Function Expressions vs Function Declarations](https://www.sitepoint.com/function-expressions-vs-declarations/)\n- [JavaScript Function — Declaration vs Expression](https://medium.com/@raviroshan.talk/javascript-function-declaration-vs-expression-f5873b8c7b38)\n- [Function Declarations vs. Function Expressions](https://medium.com/@mandeep1012/function-declarations-vs-function-expressions-b43646042052)"
  },
  {
    "path": "Javascript/B_Type.md",
    "content": "# Type\n\n## Primitive Type\n\n한국말로 간단하게 말하면 원시 자료형이라고 하는 자바스크립트의 타입에 대해서 알아보자!\n\n자바스크립트는 자바나 C언어와는 다른게 동적 타입언어라고 불린다. 동적 타입 언어의 자료형은 컴파일시 자료형을 정하는 것이 아니고 실행시에 결정이 된다. \n\n자바스크립트의 타입의 종류와 사용법에 대해서 알아보자.\n<br/>\n\n### 6가지의 기본 Type\n\nES6 이전에는 기본적으로 5가지의 타입이 있었다. 추가적으로 ES6에서 Symbol 타입이 추가되었다.\n\n- String : 텍스트를 셋팅하는데 사용하는 타입.\n- Number : 숫자를 셋팅하는데 사용하는 타입. 기본적으로 소수점도 가능하다.(`infinity`, `-inifinity`, `NaN` 표현이 가능하다.)\n- Null : null타입은 정확히는 1개의 값은 가지고 있지만 비어있다는 뜻이다.\n- Undefined : 값이 할당되지 않는 것을 나타내는 타입.\n- Boolean : `true` 또는 `false` 로 나타내는 타입.\n- Symbol : 새로 추가된 타입으로 **unique하고 immutable한 원시값** 으로 사용된다.\n\n위에서 보이듯이 기본적으로 6가지의 형태를 가지고 있으며 나머지는 **Object형** 이라고 통칭한다.\n\n- Array : 우리가 알고 있는 배열, 리스트의 형태를 가지고 있다.\n- Function : Javascript에서는 Function Object가 존재하지만 결국 Function도 Object.\n- Object  : Map처럼 사용하는 즉, key : value의 형태로 사용하고 있는 Object.\n\n위에서 보았던 6가지 기본타입을 생성하는 방법은 크게 2가지이다.\n\n1. Literal로 생성하기\n\nLiteral로 생성한다고 하면 우리가 가장 많이 사용하는 방법이라고 생각된다. 단순하게 변수를 초기화 후 할당하는 방법과 초기화를 하고 나중에 할당을 하는 방법으로 구분을 지을 수 있다.\n\n```javascript\nvar bol = true;\nvar str = \"hello\";\nvar num = 3.14;\nvar nullType = null;\nvar undef = undefined;\n\nvar bol2;\nvar str2;\nbo2 = false\nstr2 = \"world\"\n```\n\n2. Wrapper Object를 사용해서 만들기\n\nWrapper Object를 사용해서 만든다고 하면 Constructor를 사용해서 만드는 것을 말한다. 쉽게 말하자면 `new` 를 사용해서 만드는 것을 말한다.\n\n```javascript\nnew Boolean(false);\nnew String(\"world\");\nnew Number(42);\n\nSymbol(\"foo\"); //Symbol 타입의 생성방법\n```\n\nLiteral로 생성하는 방법과 Wrapper Object를 사용해서 만드는 방법은 차이점이 존재한다. 아래의 예제를 보자.\n\n```javascript\ntypeof true; //\"boolean\"\ntypeof Boolean(true); //\"boolean\"\ntypeof new Boolean(true); //\"object\"\ntypeof (new Boolean(true)).valueOf(); //\"boolean\"\n     \ntypeof \"abc\"; //\"string\"\ntypeof String(\"abc\"); //\"string\"\ntypeof new String(\"abc\"); //\"object\"\ntypeof (new String(\"abc\")).valueOf(); //\"string\"\n     \ntypeof 123; //\"number\"\ntypeof Number(123); //\"number\"\ntypeof new Number(123); //\"object\"\ntypeof (new Number(123)).valueOf(); //\"number\"\n```\n\n중간중간 이상하게 new를 사용하지 않고 사용하는 것들은 `window.Boolean`,  `window.String` 이런것으로 생각하면 되며, 이러한 Function은 해당 타입으로 변환하는 작업을 할 때 사용이 된다.\n\n위에서 보게 되면 Literal로 생성한 것의 타입은 6가지 중 하나로 나오게 된다. 그런데 new를 사용하여 Wrapper Object로 만들게 되면 Object타입이 나오게 된다. 사용을 하려면 valueOf라는 Function을 사용해야만 입력한 값이 나오게 된다.\n\n아래의 예제를 보자. 어떻게 결과가 어떻게 6이 나올 수 있는 것인가?\n\n```javascript\nvar str = 'string'\n\nstr.length // 6\n```\n\n위의 예제는 단순하게 str 변수안에 'string'이라는 String 타입의 값을 할당을 했다. 그런데 해당 변수는 Wrapper 객체가 아닌데 어떻게 갯수를 세는 Method를 사용하고 있는 것인가?\n\n```javascript\nString.prototype.returnMe= function() {\n    return this;\n}\n     \nvar a = \"abc\";\nvar b = a.returnMe();  \n     \na; //\"abc\" \ntypeof a; //\"string\" (still a primitive)\n\nb; //\"abc\"\ntypeof b; //\"object\"\n```\n\n위의 예제를 보게 되면 답이 나오게 된다. 우리가 사용하는 `var str` 를 사용하게 되면 Wrapper 객체로 임시변환이 이루어지고 `returnMe()` 와 같은 함수를 사용하면 다시 Wrapper 객체가 사라지게 된다. \n<br/>\n\n## 심화내용\n\n자바스크립트에서는 신기하게도 숫자타입을 하나로 사용하고 있다. 어떻게 하나의 타입으로 모든 것을 표현할 수 있는 것일까? **Number타입은 국제 표준 부동 소수점 IEEE 754를 따르고 있다.** 기본적으로 컴퓨터가 실수를 표현하는 방식은 2진법에 따라서\n\n- 13 = 8 + 4 + 1 이므로 해당 자리 숫자를 1로 표현하고 나머지는 0으로 표현하게 되고 1101이 된다.\n- 0.75 = 0.5 + 0.25 이므로 0.11 로 표현할 수 있다.\n\n일반적으로 소수점을 표현하는 방법은 2가지 방법이 있다. \n<br/>\n\n### **고정 소수점**\n\n- 정수를 표현하는 비트수와 소수를 표현하는 비트수를 미리 정해놓고 해당 비트만큼 사용해서 숫자를 표현하는 방식\n- 예) 실수 표현에 4byte(32bit)를 사용하고 그 중 **부호1bit, 정수 16bit, 소수 15bit** 를 사용하도록 약속해 놓은 시스템에 있다. 이렇게 약속된 시스템에서 263.3을 표현하면 (0)0000000100000111.010011001100110 이렇게 표현된다.\n- 정수를 표현하는 비트수를 늘리면 큰 숫자를 표현할 수 있지만 정밀한 숫자를 표현하긴 힘들다. 그래서 소수를 표현하는 bit를 늘릴 경우 정밀한 숫자를 표현할 수 있지만 큰 숫자를 표현하지 못한다.\n\n이런 문제를 해결하기 위해서 소수점을 고정하지 않고 표현할 수 있는 **부동 소수점(floating point)** 을 사용하게 되었다.\n<br/>\n\n### **부동소수점**\n\n부동 소수점을 표현하는 방식도 정하는 방식에 따라 다를 수 있지만 일반적으로 사용하고 있는 방식은 위에서 언급한 IEEE 754에서 표준으로 제안한 방식을 따른다.\n\n우선 고정 소수점으로 나타낸 263.3을 2진수 부동 소수점 방식으로 변환을 해보면, 100000111.010011001100110... 으로 표현되던 것을 맨 앞에 있는 1 바로 뒤로 소수점을 옮겨서 표현하도록 변환하게 되면 1.00000111010011001100110... * 2^8(2의 8승) 으로 표현된다.\n\n- 2^8의 8을 지수라고 하고 지수 부분에 기록을 하고(IEEE 754 표현 방식에서는 **127 + 지수를 기록한다.** )\n- 소수점 이후 숫자열 전체를 가수라고 하고 가수 부분에 기록을 한다.\n\n최종적인 모양을 아래와 같다.\n\n- 부호 비트(1 bit) : 0 (양수)\n- 지수 비트(8 bit) : 10000111 (127 + 8 = 135)\n- 가수 비트(23 bit) : 00000111010011001100110 \n  \n이렇게 표현하게 된다.\n\n하지만 여기서도 0.010011001100110은 정확히 0.3을 나타낼 수 없게 된다. 10진수로 나타내 보면 0.29998779296875로 나오게 된다. 그래서 자바스크립트에서 0.1 + 0.2를 하게 되면 0.30000000000000004가 나오는 이유이다.\n\n> 블록체인에서는 부동소수점에서 8자리까지를 사용한다고 한다.\n\n<br/>\n\n## 값타입과 참조타입\n\n기본적으로 원시타입을 값타입이라고 한다면 Object를 참조타입이다. \n<br/>\n\n### 원시타입은 값타입이다.\n\n```javascript\nvar a = 13         // assign `13` to `a`\nvar b = a          // copy the value of `a` to `b`\n\nb = 37             // assign `37` to `b`\n\nconsole.log(a)     // => 13\n```\n\n위에서 b에 a의 값을 복사를 했다. 그리고 b의 값을 변경을 했는데 a에는 영향이 가지 않았다. 이유는 당연하게 2개의 값이 저장된 공간이 다르기 때문이다.\n\n```javascript\nvar a = 5;\nvar b = a;\n\na = 10;\n\nconsole.log(a); // 10\nconsole.log(b); // 5\n// string, boolean, null, undefined은 같은 결과가 나온다.\n```\n\n<br/>\n\n### Object는 참조타입이다.\n\n```javascript\nvar a = { c: 13 }  // assign the reference of a new object to `a`\nvar b = a          // copy the reference of the object inside `a` to new variable `b`\nb.c = 37           // modify the contents of the object `b` refers to\nconsole.log(a)     // => { c: 37 }\n```\n\n원시타입과는 다르게 복사한 것을 변경을 했더니 a에도 영향이 간다. 이유는 당연하게 같은 값의 주소를 복사를 하여서 a에 들어있는 주소의 공간이 바뀌었으므로 a로 바뀐값을 불러오는 것이다.\n\n```javascript\nvar a = {};\nvar b = a;\n\na.a = 1;\n\nconsole.log(a); // {a: 1}\nconsole.log(b); // {a: 1}\n```\n\narray의 경우에 있어도 예외는 없다.\n\n```javascript\nvar a = [];\nvar b = a;\n\na.push(1);\n\nconsole.log(a); // [1]\nconsole.log(b); // [1]\nconsole.log(a === b); // true\n```\n\n```javascript\nfunction changeAgeImpure(person) {\n    person.age = 25;\n    return person;\n}\nvar alex = {\n    name: 'Alex',\n    age: 30\n};\nvar changedAlex = changeAgeImpure(alex);\n\nconsole.log(alex); // -> { name: 'Alex', age: 25 }\nconsole.log(changedAlex); // -> { name: 'Alex', age: 25 }\n```\n\n```javascript\nfunction changeAgePure(person) {\n    var newPersonObj = JSON.parse(JSON.stringify(person));\n    newPersonObj.age = 25;\n    return newPersonObj;\n}\n    \nvar alex = {\n    name: 'Alex',\n    age: 30\n};\nvar alexChanged = changeAgePure(alex);\n\nconsole.log(alex); // -> { name: 'Alex', age: 30 }\nconsole.log(alexChanged); // -> { name: 'Alex', age: 25 }\n```\n\n<br/>\n\n### 문제\n\n```javascript\nfunction changeAgeAndReference(person) {\n    person.age = 25;\n    person = {\n        name: 'John',\n        age: 50\n    };\n        \n    return person;\n}\n    \nvar personObj1 = {\n    name: 'Alex',\n    age: 30\n};\n    \nvar personObj2 = changeAgeAndReference(personObj1);\n\nconsole.log(personObj1); // -> ?\nconsole.log(personObj2); // -> ?\n```\n\n### **답**\n\n:point_right: [답 확인하기](https://codepen.io/seonhyungjo/pen/qwXMNb)\n\n<br/>\n\n## 명시적 변환, 암시적 변환, 덕 타이핑\n\n### 명시적 변환 vs 암묵적 변환\n\n개발자가 `Number(value)` 와 같은 코드를 작성하여 변환할 의사를 명확하게 표현하는 것을 **명시적 변환**이라고 한다. JavaScript는 약타입 언어이므로 값을 자동으로 여러 유형간에 변환을 자동으로 한다. 이것을 **암묵적 변환** 이라고 한다.\n\n예를 들어 일반적으로 연산자를 다양한 유형의 값에 적용하면 `1 == null`, `2 / '5'`, `null + new Date ()` 또는 `if (value) {...}` 와 같이 문법에 의해 발생할 수 있다.\n\n우리가 가장 많이 사용하는 암시적 타입 변환을 하지 않는 연산자는 `===` 이며, **완전 항등 연산자** 라고 한다. 반면에 **느슨한 항등 연산자** `==` 는 필요하다면 **비교와 타입 강제 변환을 수행** 합니다.\n\n암시적 타입 변환으로 `==` 을 사용하게 되면, 가독성을 잃지 않으면서 적은 코드로 작성할 수있는 유용한 매커니즘이다. 그러나 ES6+를 사용한다면 느슨한 항등 연산자는 사용하지 않는 것을 추천한다. 완전하게 항등연산자를 이해하고 결과값을 예상할 수 있는 경우가 아니라면 내가 생각한 것과 다른 결과가 나올 확률이 매우 높다.\n\n기본적으로 변환은 3가지 유형의 전환이 있다.\n\n- **to string**\n- **to boolean**\n- **to number**\n\n<br/>\n\n### String 변환\n\n명시적으로 값을 문자열로 변환하려면 `String()` 함수를 사용하면 된다. 암시적 강제 변환은 `binary` 연산자가 아닌것에 `+` 연산자를 사용하면 변환이 이루어진다. \n\n```javascript\nString(123) // 명시적\n\n123 + ''    // 암시적\n```\n\n아래의 예제를 보면 예상대로 다 문자열로 변환이 잘 이루어지고 있다.\n\n```javascript\nString(123)                   // '123'\nString(-12.3)                 // '-12.3'\nString(null)                  // 'null'\nString(undefined)             // 'undefined'\nString(true)                  // 'true'\nString(false)                 // 'false'\n```\n\nSymbol에 대해서는 생각과는 다르게 나온다.\n\n```javascript\nString(Symbol('my symbol'))   // 'Symbol(my symbol)'\n'' + Symbol('my symbol')      // TypeError is thrown\n```\n\n`Symbol` 변환은 명시적으로만 변환될 수 있고, 암시적 변환은 되지 않는다.\n<br/>\n\n### Boolean 변환\n\n명시적으로 값을 Boolean으로 변환하려면 `Boolean()` 함수을 사용하면 된다. 암시적 변환은 논리 Context에서 발생하거나 논리 연산자에 의해 작동을 하게 된다.( `||`, `&&`, `!` )\n\n```javascript\nBoolean(2)          // 명시적\nif (2) { ... }      // 논리적 문맥 때문에 암시적\n!!2                 // 논리적 문맥 때문에 암시적\n2 || 'hello'        // 논리적 문맥 때문에 암시적\n```\n\n논리 연산자(예 : `||` 및 `&&` )에 따른 Boolean 변환을 내부적으로 수행하지만 Boolean값이 아니더라도 원래 피연산자의 값을 실제로 반환한다. 아래를 보게 되면 Boolean 변환을 해서 검사는 하지만 실제로는 123도  반환되고 있다.\n\n```javascript\n// true를 반환하는 것이 아닌 123를 반환하고 있다.\n// 'hello' and 123 은 표현식을 계산하기 위해서 Boolean으로 강제 변환을 한다.\nlet x = 'hello' && 123;   // x === 123\n```\n\nBoolean 변환의 결과는  `true`, `false` 2개만 있다. `false` 값 목록은 쉽게 기억이 가능하다.\n\n```javascript\nBoolean('')           // false\nBoolean(0)            // false     \nBoolean(-0)           // false\nBoolean(NaN)          // false\nBoolean(null)         // false\nBoolean(undefined)    // false\nBoolean(false)        // false\n```\n\n목록에 없는 값 `object`, `function`, `Array`, `Date`, 사용자 정의 유형등은 `true` 로 변환한다.\n\n```javascript\nBoolean({})             // true\nBoolean([])             // true\nBoolean(Symbol())       // true\n!!Symbol()              // true\nBoolean(function() {})  // true\n```\n\n<br/>\n\n### Numeric 변환\n\n명시적 변환의 경우 `Boolean()` 및 `String()` 에서와 마찬가지로 `Number()` 함수를 사용하면 된다. 암시적 변환은 많은 경우에서 작동이 되기 때문에 까다롭다.\n\n- 비교 연산자(`>`, `<`, `<=`,`>=`)\n- 비트 연산자( `|` `&` `^` `~`)\n- 산수 연산자 (`-` `+` `*` `/` `%` ).\n    - 참고로, `+`는 피연산자가 문자열일 때 숫자 변환을 하지 않고 문자열 변환을 한다.\n- 단항 연산자(기호로 사용하는) `+`\n- 느슨한 비교 연산자 `==` (`!=`).\n    - 두 피연산자가 모두 문자열 인 경우 `==` 는 숫자 변환을 하지 않는다.\n\n```javascript\nNumber('123')   // 명시적\n+'123'          // 암시적\n123 != '456'    // 암시적\n4 > '5'         // 암시적\n5 / null        // 암시적\ntrue | 0        // 암시적\n```\n\n```javascript\nNumber(null)                   // 0\nNumber(undefined)              // NaN\nNumber(true)                   // 1\nNumber(false)                  // 0\nNumber(\" 12 \")                 // 12\nNumber(\"-12.34\")               // -12.34\nNumber(\"\\n\")                   // 0\nNumber(\" 12s \")                // NaN\nNumber(123)                    // 123\n```\n\n문자열을 숫자로 변환할 때 엔진은 먼저 앞뒤의 공백, `\\ n`, `\\ t` 문자를 제거하고, 문자열이 유효한 숫자를 나타내지 않으면 `NaN` 을 반환한다. `string`이 비어 있으면 0을 반환합니다.\n\n`null`와 `undefined`는 다르게 처리가 되는데 `null`은 0으로 `undefined`는 `NaN`으로 된다.\n\nSymbol은 명시적 또는 암시적으로 숫자로 변환될 수 없다. 또한 `TypeError`는 `undefined`로 발생하는 것처럼 `NaN`으로 자동 변환하는 대신 `throw` 된다.\n\n```javascript\nNumber(Symbol('my symbol'))    // TypeError is thrown\n+Symbol('123')                 // TypeError is thrown\n```\n\n기억해야 할 두 가지 특별한 규칙이 있는데\n\n1. `==` 를 `null` 또는 `undefined` 에 적용하면 숫자 변환이 발생하지 않는다. `null` 는 `null`, `undefined`과 동일하다.\n\n```javascript\nnull == 0               // false, null is not converted to 0\nnull == null            // true\nundefined == undefined  // true\nnull == undefined       // true\n```\n\n2. `NaN`은 그 자체가 동등하지 않다.\n\n```javascript\nif (value !== value) { console.log(\"we're dealing with NaN here\") }\n```\n\n<br/>\n\n---\n\n## Object 강제 변환\n\n참고: [https://medium.freecodecamp.org/js-type-coercion-explained-27ba3d9a2839](https://medium.freecodecamp.org/js-type-coercion-explained-27ba3d9a2839)\n\n---\n\n<br/>\n\n## 심화\n\n### **덕 타이핑(Duck Typing)이란?**\n\n쉽게 정의를 하자면 사람이 오리처럼 행동하면 오리로 봐도 무방하다라는게 덕 타이핑(Duck Typing)이다. \n\n이것은 타입을 미리 정하는게 아니라 실행이 되었을 때 해당 Method들을 확인하여 타입을 정한다는 것으로  타입의 변화가 느슨하다.\n\n- 장점\n  - 타입에 대해 매우 자유롭다.\n  - 런타임 데이터를 기반으로 한 기능과 자료형을 만들어 내는 것\n- 단점\n  - 런타임 자료형 오류가 발생할 수 있다. 런타임에서, 값은 예상치 못한 유형이 있을 수 있고, 그 자료형에 대한 무의미한 작업이 적용된다.\n  - 이런 오류가 프로그래밍 실수 구문에서 오랜 시간 후에 발생할 수 있다\n  - 데이터의 잘못된 자료형의 장소로 전달되는 구문은 작성하지 않아야 한다. 이것은 버그를 찾기 어려울 수도 있다.\n\n<br/>\n\n### Reference\n\n- [How numbers are encoded in JavaScript](http://2ality.com/2012/04/number-encoding.html)\n- [What Every JavaScript Developer Should Know About Floating Point Numbers](https://blog.chewxy.com/2014/02/24/what-every-javascript-developer-should-know-about-floating-point-numbers/)\n- [Here is what you need to know about JavaScript’s Number type](https://blog.angularindepth.com/javascripts-number-type-8d59199db1b6)\n- [The Secret Life of JavaScript Primitives](https://javascriptweblog.wordpress.com/2010/09/27/the-secret-life-of-javascript-primitives/)\n- [Primitive Types](https://flow.org/en/docs/types/primitives/)\n- [(Not) Everything in JavaScript is an Object](http://blog.brew.com.hk/not-everything-in-javascript-is-an-object/)\n- [JavaScript data types and data structures - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Primitive_values)\n- [Explaining Value vs. Reference in Javascript](https://codeburst.io/explaining-value-vs-reference-in-javascript-647a975e12a0)\n- [Primitive Types & Reference Types in JavaScript](https://gist.github.com/branneman/7fb06d8a74d7e6d4cbcf75c50fec599c)\n- [Value types, reference types and scope in JavaScript](https://medium.com/@benastontweet/lesson-1b-javascript-fundamentals-380f601ba851)\n- [Back to roots: JavaScript Value vs Reference](https://medium.com/dailyjs/back-to-roots-javascript-value-vs-reference-8fb69d587a18)\n- [JavaScript Reference and Copy Variables](https://hackernoon.com/grasp-by-value-and-by-reference-in-javascript-7ed75efa1293)\n- [(Not) Everything in JavaScript is an Object](http://blog.brew.com.hk/not-everything-in-javascript-is-an-object/)\n- [JavaScript type coercion explained](https://medium.freecodecamp.org/js-type-coercion-explained-27ba3d9a2839)"
  },
  {
    "path": "Javascript/Build Tool.md",
    "content": "# Build Tool\n\n빌드 작업은 한 번 구성을 하게되면 다시 빌드를 할 때는 단순 반복을 한다. 이에 빌드를 도와주는 도구들이 생겨나게 되었고, 시간이 지남에 따라 종류가 다양해지고 기능도 많아졌다. \n\n현재 가장 많은 기능을 지원하며, 많은 곳에서 사용되는 도구로는 **Webpack**이 있으며, 이전에도 많은 빌드 도구들이 있었지만, 대표적으로 **Grunt와 Gulp**가 있다.\n\n## Grunt\n\n![image](https://user-images.githubusercontent.com/24274424/63153384-2658a500-c049-11e9-9c9c-0c962b7ba815.png)\n\n위에 보이는 돼지? 가 바로 Grunt의 마크이다.\n메인 타이틀이 돼지인 이유는 Grunt 단어 뜻에서 찾아볼 수 있다.\n\n> (돼지처럼) 꿀꿀 거리다(거리는 소리), 불평의 소리\n> 꿀꿀거리다, 불평하다, 좋지 않은\n\nGithub [Grunt](https://github.com/gruntjs/grunt)를 찾아보면,\n> The JavaScript Task Runner \n\n라고 설명되어 있다.\n\n간단히 풀어서 보자면 Minify, Compile, Unit Test, Lint 등 주기적인 task들을 자동으로 수행하기 위해 사용되는 도구로 Javascript Task runner이다.\n\n기본적으로 task들을 만들어 작동하며, 사용자 지정 task들을 수행하기 위해 **Command Line**를 사용한다. \n\nGrunt는 Node.js로 작성되어 있으며, npm을 통해 배포하고 있다.\n\n2019년 8월 기준으로, Grunt 생태계에 6,000개 이상의 플러그인을 사용할 수 있다고 한다.\n\n### 예제\n\n```js\nmodule.exports = function(grunt) {\n\n  // Task configuration\n  grunt.initConfig({\n    taskName1: 'Task1 Configuration',\n    taskName2: 'Task2 Configuration'\n  });\n\n  // Loads plugins\n  grunt.loadNpmTasks('pluginName1');\n  grunt.loadNpmTasks('pluginName2');\n\n  // Custom tasks\n  grunt.registerTask('customTaskName1', 'Custom task description', function(taskParameter) {\n    // Custom statements\n  });\n\n  // Combining multiple tasks to a single task\n  grunt.registerTask('customTaskName2', ['taskName1', 'customTaskName1']);\n  // Default task - runs if task name is not specified\n  grunt.registerTask('default', ['customTaskName2']);\n\n};\n```\n\n> [Grunt에서 사용하는 Gruntfile.js](https://github.com/gruntjs/grunt/blob/master/Gruntfile.js)<br/>\n> [grunt-cli](https://github.com/gruntjs/grunt-cli/blob/master/bin/grunt)\n\n### grunt-eslint로 task 살펴보기\n\n```js\n'use strict';\nconst chalk = require('chalk');\nconst eslint = require('eslint');\n\nmodule.exports = grunt => {\n\tgrunt.registerMultiTask('eslint', 'Validate files with ESLint', function () {\n\t\tconst options = this.options({\n\t\t\toutputFile: false,\n\t\t\tquiet: false,\n\t\t\tmaxWarnings: -1,\n\t\t\tfailOnError: true,\n\t\t});\n\n\t\tif (this.filesSrc.length === 0) {\n\t\t\tgrunt.log.writeln(chalk.magenta('Could not find any files to validate'));\n\t\t\treturn true;\n\t\t}\n\n\t\tconst formatter = eslint.CLIEngine.getFormatter(options.format);\n\n\t\tif (!formatter) {\n\t\t\tgrunt.warn(`Could not find formatter ${options.format}`);\n\t\t\treturn false;\n\t\t}\n\n\t\tconst engine = new eslint.CLIEngine(options);\n\n\t\tlet report;\n\t\ttry {\n\t\t\treport = engine.executeOnFiles(this.filesSrc);\n\t\t} catch (error) {\n\t\t\tgrunt.warn(error);\n\t\t\treturn false;\n\t\t}\n\n\t\tif (options.fix) {\n\t\t\teslint.CLIEngine.outputFixes(report);\n\t\t}\n\n\t\tlet results = report.results;\n\n\t\tif (options.quiet) {\n\t\t\tresults = eslint.CLIEngine.getErrorResults(results);\n\t\t}\n\n\t\tconst output = formatter(results);\n\n\t\tif (options.outputFile) {\n\t\t\tgrunt.file.write(options.outputFile, output);\n\t\t} else if (output) {\n\t\t\tconsole.log(output);\n\t\t}\n\n\t\tconst tooManyWarnings = options.maxWarnings >= 0 && report.warningCount > options.maxWarnings;\n\n\t\tif (report.errorCount === 0 && tooManyWarnings) {\n\t\t\tgrunt.warn(`ESLint found too many warnings (maximum: ${options.maxWarnings})`);\n\t\t}\n\n\t\treturn options.failOnError ? report.errorCount === 0 : 0;\n\t});\n};\n\n```\n\n## Gulp\n\n![image](https://user-images.githubusercontent.com/24274424/63156272-4ab78000-c04f-11e9-94fd-ce717e80045e.png)\n\nGulp의 마크는 마치 콜라를 떠올리는 모양이다.\n단어의 뜻을 살펴보면 \n\n> 꿀꺽꿀꺽\\[꿀떡꿀떡\\] 마시다, 쭉 들이켜다\n\n이다.\n\nFractal Innovations과 Github 오픈 소스 커뮤니티의 오픈 소스 Javascript 툴킷으로, 프론트엔드 웹 개발의 **스트리밍 빌드 시스템**으로 사용된다.\n\n> The streaming build system\n\nGulp는 steaming build system을 표방하고 있다. 즉, Node의 스트리밍 기능으로 이득을 얻은 빌드 시스템이다.\n\n현재 2019년 08월을 기준으로 4,000개 이상의 플러그인을 사용할 수 있다.\n\n> **Streaming에 대해서**\n> \n> Node.js는 이벤트 루프에 기반한 비동기 I/O를 제공하고 있다.\n>  \n> 파일 시스템에서 읽기/쓰기 작업을 할 때나 HTTP 요청을 전달할 때 Node.js는 노드는 응답을 기다리는 동안 다른 이벤트들을 처리할 수 있는데, 이를 non-blocking I/O 라고 부른다. \n> \n> Stream은 이보다는 더 확장된 개념으로 메모리 버퍼와 대역폭을 절약할 수 있는 이벤트 기반의 I/O 인터페이스를 제공하는 것을 말한다.\n> \n> 예를 들어, 스트림은 대용량 파일의 파일 같은 경우, 파일 전체를 모두 로드하기 전에 메모리 버퍼를 절약하기 위해 무엇인가 다른 일을 빠르게 처리할 수 있다.\n> \n> 그래서 우리는 파일이 전체로 로드될 때까지 기다릴 필요없이 파일의 일부를 쓰거나 어떤 처리를 할 수 있다.\n\n### 예제\n\n```js\nconst { src, dest, parallel } = require('gulp');\nconst pug = require('gulp-pug');\nconst less = require('gulp-less');\nconst minifyCSS = require('gulp-csso');\nconst concat = require('gulp-concat');\n\nfunction html() {\n  return src('client/templates/*.pug')\n    .pipe(pug())\n    .pipe(dest('build/html'))\n}\n\nfunction css() {\n  return src('client/templates/*.less')\n    .pipe(less())\n    .pipe(minifyCSS())\n    .pipe(dest('build/css'))\n}\n\nfunction js() {\n  return src('client/javascript/*.js', { sourcemaps: true })\n    .pipe(concat('app.min.js'))\n    .pipe(dest('build/js', { sourcemaps: true }))\n}\n\nexports.js = js;\nexports.css = css;\nexports.html = html;\nexports.default = parallel(html, css, js);\n```\n\n### Grunt와 Gulp의 차이점\n\nGrunt와 Gulp의 하는 일은 같지만 만들어내는 방식이 다르다. Grunt는 package.json처럼 json형식으로 설정을 선언하여 사용한다. 즉, 설정 파일 기반이다. 이와 다르게 Gulp는 NodeJS의 스트림 기능을 이용하여 Javascript 코드를 사용하여 작성한다.\n\nGulp는 동시에 여러 작업을 처리할 수 있지만, Grunt는 일반적으로 한 번에 하나의 작업만 처리한다.\n\n## Webpack\n\nGulp와 Grunt가 Task Runner인 것과 다르게 Webpack은 이름부터 남다르다. Webpack은 `Module Bundler` 혹은 `Package Bundler` 라고 불린다. \n\nModule 개념은 다른 글을 통해서 알 수 있다.\n\n> [Module](./Module.md) <br/>\n> Module Bundler : 각각의 모듈들의 의존성을 파악하여 번들(묶는다)해주는 것.\n\nWebpack 사이트에 들어가면 자신을 이렇게 설명하고 있다.\n\n> webpack is a module bundler. Its main purpose is to bundle JavaScript files for usage in a browser, yet it is also capable of transforming, bundling, or packaging just about any resource or asset.\n\nWebpack은 `Module Bundler`이다. 주된 목적은 브라우저에서 사용하기 위해 JavaScript 파일을 번들링하는 것이지만, 거의 모든 리소스를 변환, 번들링 또는 패키징할 수 있다.\n\n### 모듈과 의존성\n\nJavascript는 커다란 소스를 나누어서 편하게 개발하고 유지 보수하기 위해 모듈이라는 추상적인 개념을 사용한다. 마치 이는 Java의 Class와 비슷하다. 이렇게 모듈 방식으로 코딩하고 거기에 모듈별로 파일까지 나누어 개발하면 편리하다. \n\n모듈과 파일이 분기된 개념은 보통은 NodeJS에서 많이 사용했었다.\n\n모듈화된 각각의 파일들은 서로의 의존성을 가진다. 이때 의존성이란 쉽게 말해 `import * from './index'` 구문이다. 현재 파일에서 다른 파일을 가져와서 사용하게 되면 서로 의존성이 생긴다.\n\n브라우저상에서는 이러한 의존성을 표현하기가 어렵다. 특히 `HTTP/1.1`을 사용해야 하는 환경이라면 더욱더 힘들다. `HTTP/2.0`의 경우 한 번의 요청에 여러 파일을 받아올 수 있지만 1.1의 경우는 의존성을 통해 여러 파일이 필요하게 된다면 너무 많은 네트워크 자원을 소모하게 된다.\n\n그럼 많은 의존성으로 엮인 JS 파일들을 하나의 JS 파일로 압축해서 만들면 어떨까? 즉, 요청(request) 한 번에 압축파일 하나만 생성해주는 것이다. \n\n그러한 방법을 할 수 있도록 도와주는 것이 Webpack이다. 꼭 파일이 하나는 아니다. 라이브러리 / 핵심 소스를 나누어 파일을 두 개로 분기할 수도 있다. 요점은 다양한 파일들을 번들(bundle)해서 네트워크 비용을 최소화하여 파일을 번들한다! 라는 것이다.\n\n결국, **Gulp나 Grunt처럼 자동화 기능을 해주며, 의존성관리까지 해서 번들해주는 것이 바로 Webpack이다.**\n\n### 더 나아가\n\nWebpack은 위에서 언급했듯이 단순히 Javascript의 의존성을 파악하여 번들하는 것만이 아니라, 모든 리소스(javascript, css, image, font, 심지어 typescript, coffeescript, less, sass 등)에 대한 dependancy graph를 생성하여 빌드를 한다. 요즘처럼 SPA를 구현하게 되면 이러한 의존성은 꼬리에 꼬리를 물고 Graph(Tree) 형태로 만들어지게 되는데 이것을 번들링하여 하나 또는 그 이상의 파일로 만들어주는 것이 `Module Bundler`의 역할이다.\n\n## 결론\n\nGrunt, Gulp 모두 task runner라는 공통점이 있다.\n\nGulp나 Grunt는 단순 자동화 작업을 하는 데 사용된다. 그러나 Webpack의 경우 Javascript의 각 모듈 혹은 파일, 심지어는 다양한 리소스들까지 의존성을 파악하여 묶어주기 때문에 엄청나게 큰 차이점을 보인다.\n\n따라서 현재 코드가 모듈화된 코드가 아니 거나, 다양한 의존성을 다루어야 하는 작업이 아니라면 Gulp나 Grunt도 충분히 좋은 빌드 도구가 될 수 있다. 프로젝트 규모가 커지거나, Javascript를 모듈화하여 코딩하거나, 무거워질 수밖에 없는 프레임워크를 사용하는 프로젝트 등에는 Webpack이 훨씬 더 좋은 도구가 될 것이다.\n\n---\n\n#### Reference\n\n- [Grunt](https://github.com/gruntjs/grunt)\n- [Gulp](https://github.com/gulpjs/gulp)\n- [Grunt 관련 플러그인들](https://www.npmjs.com/search?q=keywords:gruntplugin)\n- [Node Stream 관련 참고자료](https://github.com/FEDevelopers/tech.description/wiki/Node.js-Stream-%EB%8B%B9%EC%8B%A0%EC%9D%B4-%EC%95%8C%EC%95%84%EC%95%BC%ED%95%A0-%EB%AA%A8%EB%93%A0-%EA%B2%83)\n- [Webpack](https://github.com/webpack/webpack)"
  },
  {
    "path": "Javascript/CallStack.md",
    "content": "# Basic_CallStack\n\n### 기본 정리 내용들\n\n- [x]  Heap\n- [x]  Call Stack\n- [x]  Web API\n- [x]  Queue\n- [x]  Event Loop\n- [x]  Execution Context\n\n## Intro\n\n먼저 들어가기에 앞서 우리가 사용하려는 언어는 스크립트 언어로 이름은 **자바스크립** 이다.\n\n그렇다면 우리가 사용할 언어가 어떻게 실행되는지 알아보기 위해서는 엔진에 대해서 알아야 한다.\n\n우리가 사용할 엔진은 **자바스크립트 엔진** 이다.\n\n## **V8 Engine**\n\n요즘에 많이 사용하고 좋다고 생각하는 브라우저는 **크롬** 이다. 크롬에서 사용되는 자바스크립트 엔진은 구글의 **V8 엔진** 이다. \n\n이 엔진에서의 2가지 Main Components가 있다.\n\n1. Memory Heap : 메모리의 할당이 일어나는 곳.\n2. Call Stack : Stack Frame이 실행되는 곳. 쉽게 말해서 우리가 작성한 코드가 실행되는 곳.\n\n## **Call Stack**\n\nCall Stack은 **LIFO** (Last In, First Out) 원리를 사용하여 함수 호출을 임시 저장하고 관리하는 데이터 구조\n\n> LIFO : Last In, First Out의 데이터 구조 원칙에 따라 호출 스택이 작동한다. 스택으로 푸시 된 마지막 함수가 처음으로 튀어 나옴을 의미한다.\n\n:point_right: **자바스크립트에서**\n\nCall Stack은 주로 함수 호출에 된다. Call Stack이 하나이기 때문에 함수 실행은 위에서 아래로 한 번에 하나씩 수행된다.\n\n기본적으로 자바스크립트는 싱글 쓰레드 프로그래밍 언어이다. 이 말은 싱글 Call Stack을 가지고 있다는 것을 의미한다. 다른말로 하자면 한 번에 한가지의 일만 한다는 것이다.\n\n```javascript\n  function multiply(x, y) {\n      return x * y;\n  }\n  function printSquare(x) {\n      var s = multiply(x, x);\n      console.log(s);\n  }\n  printSquare(5);\n```\n\n위와 같은 코드가 있다고 한다면 `printSquare(5) ⇒ multiply(x, x) ⇒ console.log(s) ⇒ printSquare(5)` 으로 쌓이고 실행이 된다는 것을 의미한다.\n\n> 각각의 한 줄을 `Stack Frame`이라고 한다.\n\n```javascript\n  function foo() {\n      throw new Error('SessionStack will help you resolve crashes :)');\n  }\n\n  function bar() {\n      foo();\n  }\n\n  function start() {\n      bar();\n  }\n\n  start();\n```\n\n위와 같은 코드를 크롬에서 실행을 한다면 당연하게 에러가 떨어지면서 Stack형태를 자세히 볼 수있다.\n\n다른 경우로는 Call Stack의 사이즈를 넘어서서 쌓이는 경우도 발생한다.\n\n```javascript\n  function foo() {\n      foo();\n  }\n\n  foo();\n```\n\n위와 같은 코드를 사용하면 안되겠지만 위와 같은 경우는 브라우저에서 계속 쌓아가다가 **16000개가** 넘어가는 순간에 Stack Size가 넘쳤다고 나올 것이다.\n\n싱글 쓰레드는 멀티 쓰레드보다 다루기는 쉽다. (Deadlock_교착상태 같은 일이 발생하지 않으므로)\n\n그러나 역시 제한적이다.\n\n예시로 내가 버튼을 눌러서 서버에서 사진을 가져오려고 할 때. 버튼을 누르고 사진을 가져올 때까지 브라우저는 멈춘 상태가 되어 버린다.\n\n이에 대안으로 **Asynchronous Callbacks** 이다.\n\n## **Web API**\n\n우리가 사용하는 자바스크립트에도 제공이 되지않는 것들이 있다. 가령 우리가 비동기를 사용하기 위해서 사용하는 `setTimeOut()`, `setInterval()` 등등은  브라우저에서 제공하는 API라고 생각하면 된다. \n\n간략하게 지원하는 API로는 \n\n1. DOM\n2. AJAX(==XMLHttpRequest)\n3. setTimeOut\n4. 등등\n\n이 있다. \n\n> 브라우저 웹 API : DOM 이벤트, XMLHttpRequest, setTimeout 등과 같은 비동기 이벤트를 처리하기 위해 C ++로 구현 된 **브라우저로 만든 쓰레드**\n\n## **Queue(Message Queue || CallBack Queue)**\n\n자바스크립트 런타임에는 처리할 메시지 목록과 콜백 함수인 메시지 Queue이 있다. 현재 Stack의 용량이 충분하다면 Queue에서 메시지를 가져와서 처리된 것의 CallBack function을 실행한다.\n\n기본적으로 이러한 메시지는 콜백 기능이 제공되면 외부 비동기 이벤트에 대한 응답을 한다. 예를 들어 사용자가 버튼을 클릭하고 콜백 함수가 제공되지 않은 경우 아무런 메시지도 Queue에 추가되지 않게 되는 것이다.\n\n## **Event Loop**\n\n네크워크는 느리다. 그래서 사진을 불러오는 것은 느리다. 이에 사용하는 것이 우리가 흔히 `AJAX` 라고 부르는 **비동기 함수** 이다. 만약 이러한 작업이 동기라면 위와 같이 멈추는 현상이 일어날 것이다.\n\n가장 쉬운 해결책이 **비동기 Callbacks** 이다. 위에서 언급한 **Web API** 에서 제공하는 것에 **비동기 Callbacks**이다.\n\n`console.log()`와 다르게 바로 실행이 되지 않는다. 그렇다면 이런 것들은 어떻게 되는 것인가?\n\n응답에서 호출자를 분리하면 비동기 작업이 완료되고 콜백이 시작될때까지 기다리는 시간동안 자바스크립트 런타임에서는 다른 작업을 할수 있다. \n\nWeb API에서 요청한 작업을 완료한 후 Callbacks을 실행해야한다. 그러나 만약 작업이 완료가 되고 직접 Web API쪽에서 Call Stack에 실행코드를 넣을 수 있다면 마음대로 바로 나타날 것이다. \n\n그래서 있는 것이 **Queue** 이다. Web API에서 요청한 작업을 완료한 후에 **Queue** 에 넣어 준다. \n\n**Event Loop는 이제 Call Stack이 비었을 때 Queue에서 들어온 Callbacks를 수행한다.**\n\n## **Execute Context**\n\n실행 컨텍스트는 자바 스크립트 코드가 평가되고 실행되는 환경의 추상적인 개념이다. 자바 스크립트에서 코드를 실행할 때마다 실행 컨텍스트 내에서 실행된다.\n\n기본적으로 자바스크립트 내에는 3가지 타입의 실행컨텍스트가 있다고 한다.\n\n1. Global \n2. Functional\n3. ~~Eval Function~~\n\n그러나 중요한 것은 **1번과 2번**이다.\n\n### Execution Stack\n\n실행 스택은 우리가 위에서 보았다. Call Stack의 개념이다.\n\n> LIFO (Last In, First Out) 원리를 사용하여 함수 호출을 임시 저장하고 관리하는 데이터 구조이다.\n\n:point_right: 어떻게 실행 컨텍스트를 만드는가?\n\n실행컨텍스트를 만드는데 2개의 단계가 있다.\n\n1. Creation 단계\n2. Execute 단계\n\n#### Creation 단계\n\n한국말로는 만드는 단계이다. 먼저 2가지를 만든다.\n\n1. **LexicalEnvironment**\n2. VariableEnvironment\n\n기본적인 형태는 아래와 같다.\n```javascript\n  ExecutionContext = {\n    LexicalEnvironment = <ref. to LexicalEnvironment in memory>,\n    VariableEnvironment = <ref. to VariableEnvironment in  memory>,\n  }\n```\n\n#### Lexical Environment\n\nLexical Environment은 **식별자, 변수 맵핑**을 가지고 있는 구조이다. \n\n>여기서 식별자는 변수/함수의 이름을 가리키며 변수는 실제 객체 [함수 객체 및 배열 객체 포함] 대한 참조입니다.\n\n```javascript\n  var a = 20;\n  var b = 40;\n  function foo() {\n    console.log('bar');\n  }\n```\n\n위와 같은 코드가 있다고 하면\n\nLexical Environment은\n\n```javascript\n  lexicalEnvironment = {\n    a: 20,\n    b: 40,\n    foo: <ref. to foo function>\n  }\n```\n\n위와 같이 만들어 질 것이다.\n\n여기에는 3가지의 정보를 가지고 있다.\n\n1. **Environment Record** : 변수 및 함수 선언이 Lexical Environment 내에 저장되는 장소\n2. **Reference to the outer environment** : 외부 환경에 대한 참조\n3. **This binding** : `this`가 결정되거나 설정된다.\n\n#### Environment Record\n\n기본적으로 2가지 정보를 담고 있다.\n\n- **Declarative environment record**(선언적 환경 정보) : 변수 및 함수 선언을 저장합니다.\n- **Object environment record**(객체 환경 정보) :  전역 코드의 Lexical Environment에는 객체 환경 레코드가 포함되어 있다. 변수 및 함수 선언 외에 객체 환경 레코드는 전역 바인딩 개체 (브라우저의 창 개체)도 저장합니다. 따라서 각 바인딩 객체의 속성에 대해 새 항목이 레코드에 만들어진다.\n\n함수 코드의 경우 Environment Record에는 함수에 전달 된 인덱스와 인수 사이의 매핑과 함수에 전달 된 인수의 길이가 포함 된 `arguments` 객체도 포함이 된다. \n\n예를 들어, 아래 함수에 대한 인수 객체는 다음과 같습니다.\n\n```javascript\n  function foo(a, b) {\n    var c = a + b;\n  }\n\n  foo(2, 3);\n\n  // argument object\n  Arguments: {0: 2, 1: 3, length: 2},\n```\n\n#### Reference to the Outer Environment\n\n외부 환경에 대한 참조는 outer environment에 액세스 할 수 있음을 의미한다. 즉, 자바 스크립트 엔진은 현재 lexical environment에서 찾을 수 없는 경우 outer environment에서 변수를 찾을 수 있다.\n\n#### This Binding\n\n여기에는 어렵고도 중요한 개념인 `this`가 결정되거나 설정된다.\n\n전역 실행 컨텍스트에서이 값은 전역 개체를 참조합니다.\n\n함수 실행 컨텍스트에서이 값은 함수가 호출되는 방식에 따라 다르게 `this`가 나온다. 객체 참조에 의해 호출되면 `this` 값은 해당 객체로 설정되고, 그렇지 않으면이 값은 전역 객체로 설정되거나 정의되지 않는다.\n\n```javascript\n  const person = {\n    name: 'peter',\n    birthYear: 1994,\n    \n    calcAge: function() {\n      console.log(2018 - this.birthYear);\n    }\n  }\n\n  person.calcAge(); \n  // 'this' refers to 'person', because 'calcAge' was called with //'person' object reference\n  \n  const calculateAge = person.calcAge;\n  calculateAge();\n  // 'this' refers to the global window object, because no object reference was given\n```\n\n#### Variable Environment\n\n이것은 위에서 봐왔던 LexicalEnvironment와 같다.\n\nES6에서 LexicalEnvironment 구성 요소와 VariableEnvironment 구성 요소의 차이점 중 하나는 함수 선언과 변수 (`let` 및 `const`)바인딩을 저장하는데 사용되는 반면, 후자는 변수 (`var`)바인딩만 저장하는 데 사용된다.\n\n#### Execute 단계\n\n이 단계에서 모든 변수에 대한 할당이 완료되고 코드가 최종적으로 실행된다.\n\n```javascript\n  let a = 20;\n  const b = 30;\n  var c;\n  \n  function multiply(e, f) {\n   var g = 20;\n   return e * f * g;\n  }\n  \n  c = multiply(20, 30);\n```\n\n```javascript\nGlobalExectionContext = {\n  LexicalEnvironment: {\n    EnvironmentRecord: {\n      Type: \"Object\",\n      // Identifier bindings go here\n      a: < uninitialized >,\n      b: < uninitialized >,\n      multiply: < func >\n    }\n    outer: <null>,\n    ThisBinding: <Global Object>\n  },\n  \n  VariableEnvironment: {\n    EnvironmentRecord: {\n      Type: \"Object\",\n      // Identifier bindings go here\n      c: undefined,\n    }\n    outer: <null>,\n    ThisBinding: <Global Object>\n  }\n}\n```\n\n```javascript\nGlobalExectionContext = {\n    \n  LexicalEnvironment: {\n    EnvironmentRecord: {\n      Type: \"Object\",\n      // Identifier bindings go here\n      a: 20,\n      b: 30,\n      multiply: < func >\n    }\n    outer: <null>,\n    ThisBinding: <Global Object>\n  },\n    \n  VariableEnvironment: {\n    EnvironmentRecord: {\n      Type: \"Object\",\n      // Identifier bindings go here\n      c: undefined,\n    }\n    outer: <null>,\n    ThisBinding: <Global Object>\n  }\n}\n```\n\n```javascript\n  FunctionExectionContext = {\n  LexicalEnvironment: {\n      EnvironmentRecord: {\n        Type: \"Declarative\",\n        // Identifier bindings go here\n        Arguments: {0: 20, 1: 30, length: 2},\n      },\n      outer: <GlobalLexicalEnvironment>,\n      ThisBinding: <Global Object or undefined>,\n    },\n  VariableEnvironment: {\n      EnvironmentRecord: {\n        Type: \"Declarative\",\n        // Identifier bindings go here\n        g: undefined\n      },\n      outer: <GlobalLexicalEnvironment>,\n      ThisBinding: <Global Object or undefined>\n    }\n  }\n\n```\n\n```javascript\n  FunctionExectionContext = {\n  LexicalEnvironment: {\n      EnvironmentRecord: {\n        Type: \"Declarative\",\n        // Identifier bindings go here\n        Arguments: {0: 20, 1: 30, length: 2},\n      },\n      outer: <GlobalLexicalEnvironment>,\n      ThisBinding: <Global Object or undefined>,\n    },\n  VariableEnvironment: {\n      EnvironmentRecord: {\n        Type: \"Declarative\",\n        // Identifier bindings go here\n        g: 20\n      },\n      outer: <GlobalLexicalEnvironment>,\n      ThisBinding: <Global Object or undefined>\n    }\n  }\n```\n\n함수가 완료된 후 반환 값은 c 안에 저장된다. 그래서 글로벌 Variable Environment이 업데이트된다. 그 후, 전역 코드가 완료되고 프로그램이 완료가 된다.\n\n`let` 및 `const` 정의 변수는 생성 단계에서 연관된 값이 없지만 `var` 정의 변수는 `undefined` 로 설정된다.\n\n이는 생성 단계에서 함수 선언이 환경에 전체적으로 저장되는 동안 변수 및 함수 선언에 대해 코드가 검색되고 변수가 초기에 `undefined` (`var`의 경우)로 설정되거나 초기화되지 않은 상태로 유지되기 때문이다. `let`과 `const`의 경우).\n\n이것이 `var` 정의 변수가 선언되기 전에 (정의되지는 않았지만) `var` 정의 변수에 액세스 할 수 있지만 `let` 및 `const` 변수가 선언되기 전에 액세스 할 때 참조 오류가 발생하는 이유이다.\n\n실행 단계에서 자바스크립트 엔진이 `let` 변수의 값을 소스 코드에서 선언된 실제 위치에서 찾지 못하면 정의되지 않은 값을 할당합니다."
  },
  {
    "path": "Javascript/Closure.md",
    "content": "# 클로저\n\n생성된 함수 객체는 `[[Scopes]]` 프로퍼티를 가지게 된다. \n\n`[[Scopes]]` 프로퍼티는 **함수 객체만이 소유하는 내부 프로퍼티(Internal Property)로서 현재 실행 컨텍스트의 스코프 체인이 참조하고 있는 객체를 값으로 설정**한다. \n\n\n\n![JavaScript](https://bkdevlog.netlify.com/assets/img/js_scope_property.png)\n\n\n내부 함수의 `[[Scopes]]` 프로퍼티는 **자신의 실행 환경(Lexical Enviroment)** 과 자신을 포함하는 **외부 함수의 실행 환경과 전역 객체**를 가리킨다.\n\n이 때, 자신을 포함하는 **외부 함수의 실행 컨텍스트가 소멸하여도 `[[Scopes]] `프로퍼티가 가리키는 외부 함수의 실행 환경(Activation Object)은 소멸하지 않고 참조**할 수 있다. 이것이 **클로저**이다.\n\n\n외부함수에서 내부함수를 반환하는 코드를 보자.\n\n```js\nfunction foo() {\n    var x = 'variable of outerFunc';\n\n    function bar() {\n        console.log(x); \n    }\n\n    return bar;\n}\n\nvar innerFunc = foo();\ninnerFunc(); //variable of outerFunc\n```\n\n위의 코드를 보면 외부함수 `foo()`에서 `bar()`를 반환하고 소멸한다.\n\n**외부함수 `foo()`는 실행된 이후, 실행 컨텍스트 스택에서 제거되기 때문에 변수 `x`도 같이 소멸될 것으로 보인다.** 이에 따라 변수 `x`에 접근할 방법이 없어 보인다.\n하지만 `innerFunc()`함수를 호출하면 변수 x의 값이 출력되는 것을 볼 수 있다.\n\n이처럼 **클로저는 외부함수(`foo()`) 밖에서 내부함수(`bar()`)가 호출되더라도 외부함수의 지역 변수(`var x`)에 접근할 수 있다.**\n\n\n\n![JavaScript](https://bkdevlog.netlify.com/assets/img/js_closure_scope.png)\n\n\n\n클로저가 외부함수 밖에서 내부함수가 호출되더라도 외부함수의 지역 변수에 접근할 수 있는 이유를 설명한 그림이다.\n\n외부함수인 `foo()`함수가 종료되면 함수 실행 컨텍스트도 소멸하지만 **`foo()` 함수 실행 컨텍스트의 활성 객체는 유효**하다.\n\n이 때문에 **외부 함수 `foo()`가 실행이 종료되어도 내부 함수 `bar()`에서 접근이 가능한 것**이다.\n\n\n\n> 클로저를 사용하면 **클로저에서의 스코프 체인 접근 방식**, **메모리의 부담** 등의 이유로 성능적인 면과 자원적인 면에서 손해를 볼 수 있다. 그렇기 때문에 좋은 구현을 위해서는 충분한 경험을 쌓을 필요가 있다.\n\n\n\n## 클로저를 활용한 전역 변수의 사용 억제\n\n\n\n클로저를 활용한 대표적인 예로 카운터가 있다.\n우선, 전역 변수를 사용한 예를 한 번 살펴보자.\n\n```js\nvar counter = 0;\n\nfunction calculator() {\n    return console.log(++counter);\n}\n\ncalculator(); //1\ncalculator(); //2\ncalculator(); //3\n```\n\n위의 결과는 에상대로 잘 나오고 있지만 전역 변수 `counter`를 쓰고 있다.\n전역 변수는 **어디서든 접근이 가능하기 때문에 값이 변할 수 있고** 이에 따라 오류를 불러올 수 있다.\n\n```js\nvar outerFunc = (function () {\n    var counter = 0;\n\n    function calculater() {\n        return console.log(++counter);\n    }\n\n    return calculater;\n}());\n\nouterFunc(); //1\nouterFunc(); //2\nouterFunc(); //3\n```\n\n위의 코드와 같이 클로저를 이용하면 전역 변수의 사용을 줄일 수 있다.\n\n## 클로저를 이용한 상태 변경\n\n클로저가 가장 유용하게 사용되는 상황 중 하나는 현재 상태를 기억하고 변경된 최신 상태를 유지하는 것이다.\n\n```js\nvar box = document.querySelector('.box');\nvar toggleBtn = document.querySelector('.toggle');\n\nvar toggle = (function () {\n  var isShow = false;\n\n  return function () {\n    box.style.display = isShow ? 'block' : 'none';\n    isShow = !isShow;\n  };\n})();\n\ntoggleBtn.onclick = toggle;\n```\n\n위의 예시와 같이 클로저를 사용하면 `isShow`변수를 전역에 두지 않고도 현재의 상태를 기억해둘 수 있게 된다.\n\n## 루프 안에서의 클로저 활용\n\n클로저를 활용하는데 있어 주의할 사항에 대해 설명할 때 가장 많이 등장하는게 이 경우다.\n\n```js\nfunction count(numberOfCount) {\n    for(var i=1; i <= numberOfCount; i++) {\n        setTimeout(function(){\n            console.log(i);\n        }, i*1000)\n    }\n}\n\ncount(4);\n```\n\n보면 알겠지만, 위 코드의 의도는 1초 간격으로 1,2,3,4를 출력하는 것이다. 하지만 결과는 예상과 다르게 **5가 4번 1초 간격으로 출력**된다.\n\n그 이유는 **변수 `i`는 외부함수의 변수가 아닌 전역변수이고 `setTimeout()`함수가 실행되는 시점은 `count()`함수가 종료된 이후**다.\n이 때는 이미 `i`의 값이 5인 상태이다.\n\n```js\nfunction count(numberOfCount) {\n    for(var i=1; i <= numberOfCount; i++) {\n        (function (j) {\n            setTimeout(function(){\n                console.log(j);\n            }, i*1000)\n        }(i))\n    }\n}\n\ncount(4);\n```\n\n즉시 실행 함수를 실행시켜 루프의 `i` 값을 `j`에 복사하고 `setTimeout()`함수에서 사용했다.\n이 때 **`j`는 상위스코프의 자유변수이므로 그 값이 유지**된다.\n\n이러한 문제는 자바스크립트의 함수형 스코프로 인해 위 예제의 for 루프의 초기문에서 사용된 변수는 `count`함수 내의 스코프를 가지기 때문에 발생한다.\n\nES6에서는 `let`을 이용해 **블록 레벨 스코프**를 구현할 수 있다.\n\n```js\nfunction count(numberOfCount) {\n    for(let i=1; i <= numberOfCount; i++) {\n        setTimeout(function(){\n            console.log(i);\n        }, i*1000)\n    }\n}\n\ncount(4);\n```\n첫 번째 코드에서 `var`를 `let`으로만 바꿔주면 위의 코드처럼 깔끔하게 구현할 수 있다.\n\n\n#### Reference\n\n- 인사이드 자바스크립트 (송형주, 고형준)\n- [클로저](https://poiemaweb.com/js-closure)\n"
  },
  {
    "path": "Javascript/Control_CSSOM.md",
    "content": "# Control CSSOM\n\n`CSSOM(CSS Object Model)` . 즉, 자바스크립트로 `CSS`를 조작할 수 있도록 하는 `API`이다.\n<br/>\n\n위에 관련된 자세한 내용은 웹의 렌더링과정에 대한 내용을 보면 이해하는데 도움이 될 것으로 생각이 된다.\n<br/>\n\n> [MDN에서도 잘 설명이 되어있다.](https://developer.mozilla.org/ko/docs/Web/API/CSS_Object_Model)\n\n그렇다면 우리는 어떻게 사용하고 있을까?\n<br/>\n\n## Element.style\n\n우리가 많이 사용하는 방법이다.\n일반적으로 개발자들이 자바스크립트로 `CSS`를 변경하려고 할 때 많이 사용하는 방법 중 하나이다.(Jquery를 사용안한다는 전제)\n<br/>\n\n```js\ndocument.body.style.backgroundColor = 'black';\ndocument.body.style.padding = '100px';\n```\n\n위와같이 하게 되면서 스타일이 변하면서 `inline` 스타일로 들어가게 된다.\n또한 `width`나 `height`의 경우는 초기에 입력한 값과 실제로 렌더링된 값이 다를 수 있는 경우가 생기게 된다.\n<br/>\n\n그렇다면 실제로 렌더링 결과의 값을 가져올 방법이 없는 것일까?\n<br/>\n\n이럴때 사용하는 것이 `CSSOM` 이다. 화면이 렌더링되면서 `DOM TREE` 를 그리고 `CSSOM` 를 그리고 `렌더링트리` 가 만들어지는데 이 과정에서의 결과값이 `CSSOM`에 들어가게 된다. \n<br/>\n\n결론적으로 `CSSOM` 안에 있는 `style` 을 가져오게 되면 실제 우리가 보는 화면의 스타일을 알 수 있다는 것이다.\n<br/>\n\n## 계산된(computed) 스타일 가져오기\n\n`API` 적으로 지원을 해주고 있어서 쉽게 가져와서 읽을 수 있다. \n\n```js\nwindow.getComputedStyle(document.body) // 너무 많은 정보를 보여준다.\n```\n\n위와 같이 콘솔에 찍어보면 엄청난 정보가 쏟아진다. 내가 입력했던 정보뿐만 아니라 `Default`값들도 보여주기 때문이다.\n\n```js\nwindow.getComputedStyle(document.body).font; \nwindow.getComputedStyle(document.body).color; \n```\n\n이제 위와 같이 입력을 하게 되면 내가 필요한 정보만을 얻을 수 있게 된다.\n<br/>\n\n또한 위에서 언급했듯이 실제 계산된 값을 보여주기 때문에 `width`와 `height`의 값이 숫자로 보여주게 되는 것이다.\n<br/>\n\n### 속성을 가져오는 여러가지 방법\n\n```js\n// 점(.) 이용, camel case를 사용한다. \nwindow.getComputedStyle(el).backgroundColor; \n\n// [대괄호] 이용, - 사용 : lint 에서 권고하지 않음. \nwindow.getComputedStyle(el)['background-color']; \n\n// getPropertyValue() 메소드를 이용, - 사용 \nwindow.getComputedStyle(el).getPropertyValue('background-color');\n```\n\n<br/>\n\n## 가상 요소(pseudo-element)에 접근\n\n`window.getComputedStyle`의 두번째 인자를 전달하면 가상요소의 속성에 접근이 가능하다.\n\n```css\n.box::before { \n    display: block; \n    width: 50px; \n    content: 'Example'; \n}\n```\n\n```js\nlet box = document.querySelector('.box'); \nwindow.getComputedStyle(box, '::before').width; // '50px'\n```\n\n<br/>\n\n## 사용할 수 있는 API\n\n- setProperty() : 설정, 2개의 인자 (속성,값)\n- getProperty() : 가져오기, 1개의 인자\n- item() : 가져오려는 속성의 인덱스를 인자로 사용\n- removeProperty() : 삭제\n\n```js\n// 설정(set) \ndocument.body.style.setProperty('color', 'lime'); document.body.style.setProperty('font-size', '16px'); // - 를 사용한것에 주목! \n// 읽기(get) \ndocument.body.style.getPropertyValue('color'); // 'lime' \n\n// item() 이용, 인자값은 인덱스 숫자 \ndocument.body.style.item(0) // 'color' \ndocument.body.style.item(1) // 'font-size' \n\n// 제거(remove), 제거 후에는 빈 문자열을 반환한다. \ndocument.body.style.removeProperty('color') // 'lime' \ndocument.body.style.item(1) // '' \n```\n\n<br/>\n\n---\n\n#### Reference\n\n- [Javascript로 CSS 제어하기](http://ibrahimovic.tistory.com/56)"
  },
  {
    "path": "Javascript/DocumentFragment.md",
    "content": "# DocumentFragment\n\n<br/>\n\n## repaint와 reflow\n\n브라우저는 생성된 DOM 노드의 레이아웃이 변경될 때, 모든 노드를 다시 계산하고 렌더 트리를 재생성한다.\n이러한 과정을 `reflow`라 하고 `reflow`가 일어난 후, `repaint`가 일어난다.\n\n즉, **DOM의 노드가 변경될 때 마다 DOM tree라는 자료구조에 접근**해야 하기 때문에 DOM의 레이아웃을 변경하는 코드를 작성할 때는 이를 최적화하기 위한 고민이 필요하다.\n\n### reflow\n\n---\n\n```js\nfunction reFlow() {\n    var container = document.getElementById('container');\n\n    container.appendChild(document.createTextNode('hello'));\n}\n```\n\n위의 코드를 보면 `conatiner`라는 엘리먼트에 `hello`라는 `TextNode`를 추가했다. 이로 인해 DOM 노드의 레이아웃이 바뀌며 `reflow`와 `repaint`가 일어날 것이다.\n\n### repaint\n\n---\n\n```js\nfunction repaint() {\n    var container = document.getElementById('container');\n\n    container.style.backgroundColor = 'black';\n    container.style.color = 'white';\n}\n```\n\n위의 코드에서는 이전의 코드와 다르게 엘리먼트의 `style`만 변경했다. 이러한 경우 DOM 노드의 레이아웃은 변경되지 않았고 `style`속성만 변경되었기 때문에 `reflow`는 일어나지 않고 `repaint`만 일어나게 된다.\n\n`reflow`와 `repaint`가 많아질수록 애플리케이션의 렌더링 성능은 느려지게 되기 때문에 이를 줄일수록 성능을 높일 수 있다.\n\n이에 대한 구체적인 설명은 [Repaint와 Reflow](https://github.com/Im-D/Dev-Docs/blob/master/Performance/Repaint%EC%99%80%20Reflow.md)를 참고하면 된다.\n\n<br/>\n\n## Why DocumentFragment?\n\n`DocumentFragment`를 활용하는 것은 `reflow`를 줄이기 위한 방법 중 하나다.\n\n```html\n<body>\n\t<select id=\"timer\">\n    </select>\n</body>\n```\n\n```js\nfunction addElements() {\n    var target = document.getElementById('timer');\n \n    for (var i = 0; i < 24; i++) {\n        var option = document.createElement('option');\n \n        option.innerText = i;\n        target.appendChild(option);\n    }\n}\n```\n\n위 코드는 0시부터 23시까지의 `option`엘리먼트를 셀렉트 박스에 추가하는 예제이다.\n\n`timer`셀렉트박스에 0부터 23까지 반복을 돌려 매번 셀렉트 박스에 엘리먼트를 추가하고 있다. 24번의 DOM 레이아웃 변경이 일어나게 되기 때문에 24번의 `reflow`와 `repaint`가 각각 일어나게 된다.\n\n`DocumentFragment`를 활용했을 때의 가장 큰 차이는 `DocumentFragment`객체는 활성화된 DOM트리의 일부가 아니기 때문에 `DocumentFragment`객체에서 일어나는 변경사항은 DOM에 영향을 주지 않는다. 즉, `reflow`를 일으키지 않으며 성능에 큰 영향을 미치지 않게 된다.\n\n```js\nfunction addElements() {\n    var target = document.getElementById('timer');\n    var docFrag = document.createDocumentFragment();\n    for (var i = 0; i < 24; i++) {\n        var option = document.createElement('option');\n \n        option.innerText = i;\n        docFrag.appendChild(option);\n    }\n\n    target.appendChild(docFrag.cloneNode(true));\n}\n```\n\n위의 코드를 보면 DOM레이아웃을 변경시키는 경우는 `timer`셀렉트 박스 엘리먼트에 추가할 때 발생한다. 즉, `DocumentFragMent`객체를 셀렉트 박스 엘리먼트에 추가할 때 1번만 DOM 레이아웃이 변경된다. 따라서 각각 24번의 `reflow`와 `repaint`가 일어나던 것을 1번씩만 일어나도록 줄일 수 있게 된다.\n\n최신 브라우저의 경우에는 `reflow`가 발생하지 않도록 엔진을 최적화하기 때문에 `DocumentFragment`를 통한 성능 향상을 체감할 수 없는 경우가 많다. 그러나 DOM 객체에 대한 다수의 접근을 필요로하는 작업을 수행해야 하는 상황에서는 충분한 성능 향상을 체감할 수 있다.\n\n---\n\n#### Reference\n\n- [MDN Docs - Document​Fragment](https://developer.mozilla.org/ko/docs/Web/API/DocumentFragment)\n- [DocumentFragment를 이용한 JavaScript 성능 최적화](https://untitledtblog.tistory.com/44)\n- [Repaint와 Reflow](https://github.com/Im-D/Dev-Docs/blob/master/Performance/Repaint%EC%99%80%20Reflow.md)"
  },
  {
    "path": "Javascript/Event Delegation.md",
    "content": "# Event Delegation\n\n이벤트 위임의 개념에 앞서, 가장 먼저 이해해야 하는 상황은 다음과 같다.\n\n```html\n<html>\n  <body>\n    <div id=\"1\">\n      <div id=\"2\">\n        <div id=\"3\"></div>\n      </div>\n    </div>\n  </body>\n</html>\n```\n\n이러한 구조일 때 id가 3인 div를 클릭했다고 하자. `div#3(이하 div3)`은 html > body > div1 > div2 하위에 있다.\n\n그럼 3을 누르면 html body div1 div2 div3을 모두 누른 셈이다. 하위 노드지만 사실 겹쳐있기 때문이다. 어떤 것을 눌렀다고 정의하기 어렵다.\n\n더 나아가 클릭 이벤트는 저 5개의 태그 중 어디에서 발생하는 것이 맞는 걸까?\n\n## 이벤트 등록\n\n```html\n<body>\n  <ul>\n    <li><span>11111</span></li>\n    <li><span>22222</span></li>\n    <li><span>33333</span></li>\n    <li><span>44444</span></li>\n  </ul>\n</body>\n```\n\n```javascript\nconst lists = document.querySelectorAll('ul > li');\n\nfor (let i = 0; i < lists.length; i++) {\n  lists[i].addEventListener('click', function(evt) {\n    const target = evt.target;\n    target.innerHTML += 'clicked';\n  });\n}\n```\n\n위 코드는 li를 클릭하면 clicked를 추가하는 코드다. 의도대로 잘 작동한다.\n그런데 이 경우 브라우저는 이벤트 리스너를 4개를 기억하고 있다. li가 훨씬 많다면 비효율적이다.\n\n또 새로운 li가 동적으로 추가된다면, event가 추가되지 않는다. 이 부분은 잠재적인 버그를 가진 코드가 될 것이다.\n\n```javascript\nconst ul = document.querySelector('ul');\nul.addEventListener('click', function(evt) {\n  console.log(evt.currentTarget, evt.target);\n});\n```\n\n위와 같이 코드를 작성하고 span태그를 클릭하면 어떨까?\n\n역시 제대로 작동한다.\n\n이벤트를 줄 요소가 아닌 그 요소의 **부모 요소**를 지정하여 이벤트 리스너를 달고, 하위에서 발생한 클릭 이벤트를 감지하도록 했다.\n\n즉 이벤트를 대상 요소에 직접 주는 것이 아니라 상위의 요소에 위임시켰다. 이를 **이벤트 위임**이라고 한다.\n\nli와 span은 ul의 하위에 속하기 때문에 ul의 이벤트에도 반응하게 되어있다.\n\n실제로 클릭한 곳은 span이지만 span > li > ul 순으로 찾아 올라가며 이벤트리스너가 있는지 확인한다.\n\n이를 이벤트 버블링이라고 한다.\n\n## Event Bubbling, EventCapturing\n\n![event_delegation](https://user-images.githubusercontent.com/24724691/63207547-0c7b9880-c103-11e9-8548-efdc34c9c378.png)\n\n![event_diagram](https://user-images.githubusercontent.com/24724691/63207546-0c7b9880-c103-11e9-9c5a-314bd828fae4.png)\n\n### Event Bubbling\n\n방금의 예시가 버블링이다.\n\n즉 span을 눌렀을 때 span, li, ul이 동시에 모두 눌린 것으로 간주하지만 발생하는 순서가 하위 > 상위이다.\n\n이벤트가 발생했을 때, 하위 요소부터 상위 요소로 전파하는 이벤트 전파 방식을 **event bubbling** 이라고 한다.\n\n### Event Capturing\n\n```javascript\nconst ul = document.querySelector('ul');\nconst liAll = document.querySelectorAll('li');\nconst spanAll = document.querySelectorAll('span');\nconst cb = e => console.log(`나는 ${e.currentTarget.tagName}`);\n\nul.addEventListener('click', e => cb(e), { capture: true });\nliAll.forEach(li => li.addEventListener('click', e => cb(e), { capture: true }));\nspanAll.forEach(span => span.addEventListener('click', e => cb(e), { capture: true }));\n\n/*\n나는 UL\n나는 LI\n나는 SPAN\n*/\n```\n\nEvent Capture를 테스트하기 위해 `addEventListener()`함수에 `capture : true`라는 옵션을 추가했다.\n\n결과값을 보듯 아까와는 반대로 ul > li > span의 순서로 진행된다.\n\n이벤트가 발생했을 때, 상위 요소부터 하위요소로 전파시키는 이벤트 전파 방식을 **event capturing** 이라고 한다.\n\n## target과 currentTarget\n\n추가로 위에서 사용된 코드를 다시 보자.\n\n```javascript\nul.addEventListener('click', function(evt) {\n  console.log(evt.currentTarget, evt.target);\n});\n```\n\n이러한 코드가 있다. currentTarget과 target은 조금 다르다. currentTarget은 event가 바인딩 된 요소, 즉 이벤트 리스너가 있는 곳을 가리킨다.\n\ntarget은 event가 발생한 끝 지점, 즉 클릭한 곳을 가리킨다.\n\n두 가지의 사용 용도가 다르니 주의하자.\n\n## Event Delegation의 장점\n\n- 상위 요소에서 이벤트 리스너를 관리하기 때문에 하위 요소에는 자유롭게 요소를 추가할 수 있다. 즉, **동적인 element를 관리하기에 수월하다.**\n\n- **이벤트 핸들러를 한 곳에서 관리하기 때문에 관리하기 수월하다.**\n\n- 동적으로 추가되는 요소에 대한 이벤트가 없기 때문에 **메모리의 사용이 줄어든다.**\n\n- 이벤트 핸들러가 줄어들기 때문에 **메모리 누수의 가능성도 줄어든다.**\n\n## bubbling이 안되는 event\n\n보통의 경우 bubbling이 기본으로 적용된다. 그런데 아닌 이벤트들도 존재한다.\n\nfocus, blur, load, scroll등의 몇몇 이벤트들은 bubbling이나 capturing이 되지 않는다.\n\n![focusEvent.png](https://user-images.githubusercontent.com/24724691/63207869-967a3000-c108-11e9-9ee9-94ba1d1bb589.PNG)\n\n위는 focus event의 mdn 설명이며 bubble이 안되는 것을 볼 수 있다.\n\n관련 부분은 [Wiki DOM events](https://en.wikipedia.org/wiki/DOM_events#Events)같은 문서에서 한 눈에 확인할 수 있다.\n\n---\n\n### Reference\n\n- [이벤트 버블링, 이벤트 캡처 그리고 이벤트 위임까지](https://joshua1988.github.io/web-development/javascript/event-propagation-delegation/)\n- [Event delegation(이벤트 위임)](http://paiai.tistory.com/42)\n- [DOM events](https://en.wikipedia.org/wiki/DOM_events#Events)\n- [Element: focus event MDN](https://developer.mozilla.org/en-US/docs/Web/API/Element/focus_event)\n"
  },
  {
    "path": "Javascript/InsertAdjacentHTML.md",
    "content": "# insertAdjacentHTML\n\n## DOM 추가\n\nDocument Object Model이라고 한다. 웹브라우저가 작동하는 원리에 따라 브라우저가 렌더링 될 때 HTML을 파싱한 뒤 DOM Tree를 만든다. 이 DOM Tree의 DOM과 같다.\n\n이렇게 만들어진 DOM Tree를 HTML과 같은 텍스트(string)로 수정해야 할 경우가 있다. 최근의 SPA방식에서는 자주 사용되지는 않지만 Vanilla Script나 JQuery 방식에서는 자주 사용되는 패턴이다.\n\n두가지 방법이 존재한다.\n\n- innerHTML\n- insertAdjacentHTML\n\n## innerHTML\n\n```js\ndocument.addEventListener('DOMContentLoaded', function() {\n  let bodyContent = document.querySelector('.content');\n  const elem = '<div>hello<div/>';\n\n  for (let i = 0; i < 500; i++) {\n    bodyContent.innerHTML += elem;\n  }\n});\n```\n\ncontent라는 div아래에 div를 5000개 추가하는 코드다.\n\n[Mozilla의 MDN web docs](https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML)에 따르면 bodyContent가 가지는 값은 아래와 같다..\n\n> A DOMString containing the HTML serialization of the element's descendants.\n\nDOMString이라는 string 값을 받게 되는데 이는 하위 노드들을 모두 직렬화(serialization)한다. 그리고 난뒤 값을 재설정하게 되면 아래와 같은 설명이 나온다.\n\n> Setting the value of innerHTML removes all of the element's descendants and replaces them with nodes constructed by parsing the HTML given in the string htmlString.\n\ninnerHTML의 값을 바꾸면(setting) 기존의 하위 노드는 모두 삭제되고 새로 받은 String을 가지고 새로운 노드로 대체된다. 즉 값을 추가할 때마다 받은 string을 파싱한 뒤 DOM을 다시 생성하게 된다.\n\n## 향상된 innerHTML\n\n따라서 아래와 같이 수정하면 성능이 향상될 수 있다.\n\n```js\ndocument.addEventListener('DOMContentLoaded', function() {\n  let bodyContent = document.querySelector('.content');\n  let elem = '<div>hello<div/>';\n\n  for (let i = 0; i < 5000; i++) {\n    elem += '<div>hello<div/>';\n  }\n  bodyContent.innerHTML = elem;\n});\n```\n\n이 경우 innerHTML의 값의 수정은 단 한번만 일어나게 된다. string을 파싱하는 과정이 한번만 일어나기 때문에 성능이 향상된다.\n\n### 성능 테스트\n\n---\n\n![insertAdjacentHTML_1](/assets/images/insertAdjacentHTML_1.PNG)\n\n![insertAdjacentHTML_2](/assets/images/insertAdjacentHTML_2.PNG)\n\n두 사진은 테스트 시 위와 아래의 각각 소요시간을 보여준다. 65초에서 1.3초정도로 엄청나게 줄어든 것을 확인 할 수 있다. 또한 위의 경우 parseHTML이 5000번이 실행되었다. anonymous 아래의 파랑색의 많은 칸이 parseHTML부분이다.\n\n그러나 아래의 경우 parseHTML은 한 번만 실행되어 엄청난 성능 향상을 보여준다.\n\n## insertAdjacentHTML\n\n> element.insertAdjacentHTML(position, text);\n\ninsertHTML의 경우 위와 같이 사용하는 메서드인데 인자가 두개다. 쉽게 생각해 position에 text를 추가한다.\n\nposition은 아래 네가지 단어를 사용한다.\n\n- 'beforebegin' // element 앞에\n- 'afterbegin' // element 안에 가장 첫번째 child\n- 'beforeend' // element 안에 가장 마지막 child\n- 'afterend' // element 뒤에\n\n이제 코드로 보자.\n\n```js\ndocument.addEventListener('DOMContentLoaded', function() {\n  let bodyContent = document.querySelector('.content');\n  const elem = '<div>hello<div/>';\n\n  for (let i = 0; i < 5000; i++) {\n    bodyContent.insertAdjacentHTML('beforeend', elem);\n  }\n});\n```\n\n위의 두가지 코드와 같은 기능이다. 그런데 이 메서드의 크리티컬한 부분은 바로 파싱에 순서에 있다.\n\n역시 [MDN 문서](https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML)에 따르면 아래와 같이 써 있다.\n\n> The insertAdjacentHTML() method parses the specified text as HTML or XML and inserts the resulting nodes into the DOM tree at a specified position. It does not reparse the element it is being used on, and thus it does not corrupt the existing elements inside that element. This avoids the extra step of serialization, making it much faster than direct innerHTML manipulation.\n\n요약 하자면 text로 받은 string을 먼저 파싱한 뒤 기존의 DOM Tree에 추가하는 방식이다. 따라서 전체를 reparse하지 않아 기존의 element에 영향을 적게 준다. 전체를 수정하지 않으니 직렬화 과정이 줄어들며 성능이 향상되는 것이다.\n\n### 성능 테스트\n\n---\n\n![insertAdjacentHTML_3](/assets/images/insertAdjacentHTML_3.PNG)\n\n훨씬 빨라진 것을 볼 수 있다. parseHTML은 5000번이 똑같이 호출되지만 전체를 수정하는 것이 아니라 확실히 성능이 향상되었다. 단순하게 아무것도 없는 html에 추가만 하는 테스트 코드인데도 이 정도의 성능 향상을 보였다. 복잡한 문서라면 더욱 드라마틱한 성능 향상을 보일 것으로 예상된다.\n\n## 사용 시 주의점\n\n이렇게 String 기반으로 DOM요소를 수정하는 모든 경우 크로스 스크립팅에 취약하다. 예를들어 사용자의 입력 값을 받아 그 String으로 DOM을 수정하는 경우다. 이 경우 입력 값을 script로 넣어버릴 수 있기 때문이다.\n\n따라서 입력값을 받아 DOM을 수정하는 경우 항상 조심해서 사용해야 합니다.\n"
  },
  {
    "path": "Javascript/JavaScript의 this.md",
    "content": "# JavaScript의 this\n\n<br/>\n\n자바스크립트에서 `this`의 바인딩은 함수의 호출 방식에 따라 결정된다.\n\n- **객체의 메서드 호출**\n- **일반 함수 호출**\n- **생성자 함수의 호출**\n- **`call`과 `apply`를 이용한 `this` 바인딩**\n\n<br/>\n\n## 객체의 메서드 호출\n\n```js\nvar obj = {\n    organization : 'Im-D',\n    sayHello : function() {\n        return 'Welcome to ' + this.organization;\n    }\n}\n\nconsole.log(obj.sayHello());\n```\n\n객체의 메서드를 호출할 때 `this`는 **해당 객체에 바인딩**된다.\n\n<br/>\n\n## 일반 함수 호출\n\n```js\nvar organization = 'Im-D';\n\nfunction sayHello() {\n    var organization = 'Kyonggi';\n    return 'Welcome to ' + this.organization\n}\n\nconsole.log(sayHello());\n```\n\n일반 함수를 호출할 때, 자바스크립트의 `this`는 **전역 객체(window 객체)에 바인딩** 된다.\n\n<br/>\n\n## 생성자 함수의 호출\n\n```js\nfunction Organization(name, country) {\n    this.name = name;\n    this.country = country;\n}\n\nvar imD = new Organization('Im-D', 'South Korea');\nvar kyonggi = Organization('Kyonggi', 'South Korea');\n\nconsole.log(imD);\n\nconsole.log(kyonggi);\n```\n\n생성자 함수를 `new`키워드를 통해 호출할 경우, **새로 생성되는 빈 객체에 바인딩** 된다. 단, `new`키워드를 사용하지 않으면 `thsi`는 전역객체에 바인딩된다.\n\n<br/>\n\n## `call`과 `apply`를 활용한 `this`바인딩\n\n```js\nfunction Organization(name, country) {\n    this.name = name;\n    this.country = country;\n}\n\nvar obj = {};\n\nOrganization.apply(obj, ['ImD', 'South Korea']);\n\nconsole.log(obj);\n\nOrganization.call(obj, 'Kyonggi', 'South Korea');\n\nconsole.log(obj);\n```\n\n`call`과 `apply`을 사용할 경우 **특정 객체에 `this`를 바인딩** 시킬 수 있다.\n\n```js\nfunction sayHello() {\n    console.log(arguments);\n    var args = Array.prototype.slice.apply(arguments);\n    console.log(args);\n}    \n\nsayHello('Im-D', 'South Korea');\n```\n\n또한 `call`이나 `apply`메서드를 활용하여 **유사배열 객체를 일반 배열로 바꿀 수도 있다.**\n\n<br/>\n\n## ES6의 등장\n\n<br/>\n\n### 화살표 함수\n\n---\n\n```js\nvar obj = {\n    organization : 'Im-D',\n    outerFunc : function() {\n        var that = this;\n        console.log(this.organization);\n\n        innerFunc = function() {\n            console.log(that.organization);\n            console.log(this.organization);\n        }\n\n        innerFunc();\n    }\n}\n\nobj.outerFunc();\n```\n\n```js\nvar obj = {\n    organization : 'Im-D',\n    outerFunc : function() {\n        console.log(this.organization);\n\n        innerFunc = () => {\n            console.log(this.organization);\n        }\n\n        innerFunc();\n    }\n}\n\nobj.outerFunc();\n```\n\n`ES5`에서는 원래 내부 함수에서의 `this`는 `window`객체에 바인딩 되었기 때문에 `var that=this;`와 같이 선언하여 `that`에 `this`를 할당하고 내부 함수에서는 `that`을 활용하는 방식을 사용했었다.\n\n하지만, `ES6`에서 등장한 **화살표 함수에서는 this가 무조건 상위 스코프의 this를 가리킨다.**<br/>\n이에 따라 내부함수에서 `var that=this;`와 같은 구문을 사용할 필요가 없다.<br/>\n이처럼 정적으로 `this`가 바인딩되기 때문에 **`Lexical this`**라고 한다.\n\n<br/>\n\n### Spread Operator\n\n---\n\n`this`와는 크게 관계없지만 위에서 `apply`를 이용하여 유사배열객체인 `arguments`객체를 배열로 바꾸는 예제를 `ES6`에서는 좀 더 쉽게 구현할 수 있다.\n\n```js\nfunction sayHello() {\n    console.log(arguments);\n    const args = [...arguments];\n    console.log(args);\n}    \n\nsayHello('Im-D', 'South Korea');\n```\n\n위와 같이 **`ES6`의 `Spread Operator(...)`를 사용하면 굳이 `call`과 `apply`같은 함수를 사용하지 않고도 유사배열객체를 배열로 변환**할 수 있다.\n\n---\n\n#### Reference\n\n- [함수의 호출과 this](https://bkdevlog.netlify.com/posts/this-of-js)\n"
  },
  {
    "path": "Javascript/Javascript_Engine.md",
    "content": "# Javascript_Engine\n\n회사에서 `SWT` 에 `CEF` 를 넣어서 통신시키도록 하는 작업을 했다. 그러다 보니 `JS엔진`에 대해서 알고 싶어졌다. \n<br/>\n\n그러다 찾게된 곳을 토대로 엔진들의 공통적인 파이프라인에 대해서 알아보려고 한다.\n<br/>\n\n## JS엔진이란?\n\nJS코드를 실행하는 **프로그램(가령 브라우저) 또는 인터프리터** 를 말한다.\n<br/>\n\n### V8\n\n제일 유명하고 사람들이 많이 사용하는 크롬에 들어가있는 `V8` 이 있다. 현재 `Electron, Nodejs` 에서도 사용이 되고 있고 `CEF` 의 안에도 들어있다.\n<br/>\n\n### SpiderMonkey\n\n**최초의 자바스크립트 엔진** 으로, JS의 창시자인 브랜던 아이크가 넷스케이프 브라우저를 위해 개발이 되었다. 지금은 `Mozilla` 재단에서 관리하며, `FireFox` 에서 사용되는 엔진이다.\n<br/>\n\n### Chakra\n\n**마이크로소프트가 개발한 엔진** 이며, `Edge` 브라우저에 사용되고 있고 앞으로는 **V8** 로 바꾼다는 말이 있다. (현재 시점으로 앞으로는 V8엔진을 사용한다고 올라왔다.)\n<br/>\n\n`Chakra` 엔진의 중요 부분은 `Chakra Core` 라는 오픈 소스로 구성되어있다.\n<br/>\n\n### Javascript Core\n\n애플에서 개발한 JavaScript Core는 처음에 **WebKit 프레임워크** 를 위해 개발. 최근에는 `Safari`와 `React Native App`에서 사용된다고 한다. (RN에서는 웹뷰에서 사용한다는 것 같다.)\n<br/>\n\n## 자바스크립트 엔진 파이프라인\n\n소스코드를 기계어로 만드는 과정에 대해서 알아보려고 한다. \n<br/>\n\n1.  자바스크립트 **소스를 파싱해서 AST(추상 구문 트리)로 만든다.**\n2. **AST를 토대로 인터프리터는 바이트코드로 만들어준다.**\n\n코드를 더 빨리 실행하기 위해서, 바이트코드는 프로파일링 된 데이터와 함께 `optimizing compiler` 로 보내지고 여기서는 **프로파일된 데이터를 기반으로 하여 최적의 기계어를 생성** 하게 된다.\n\n> 바이트 코드  + 프로파일된 데이터 => 최적의 기계어\n\n그러나 정확하지 않은 결과(쉽게 자주 사용하지 않는다고 하자)가 나왔다면 다시 `deoptimizes`하여 바이트코드로 되돌린다.\n<br/>\n\n## 인터프리터 / 컴파일러 파이프라인\n\n위에서 말한것이 기본적인 파이프라인이다. **바이트코드로 만들고 자주 사용되고 빨리 실행해야하는 것들은 최적화를 시킨다.**\n<br/>\n\n- 인터프리터 : 최적화 되지 않은 바이트코드를 빠르게 생성\n- 최적화 컴파일러 : 매우 최적화된 기계어 코드를 시간을 들여서 생성. (인터프리터보다 느리다는 말이된다.)\n\n바이트코드는 **중간 언어** 이다. 인터프리터모드라면 한줄 한줄 읽으면서 해석을 할 것이며, JIT모드라면 컴파일을 하고 실행할 것이다.\n<br/>\n\n> 바이트코드(Bytecode, portable code, p-code)는 특정 하드웨어가 아닌 가상 컴퓨터에서 돌아가는 실행 프로그램을 위한 이진 표현법이다. 하드웨어가 아닌 소프트웨어에 의해 처리되기 때문에, 보통 기계어보다 더 추상적이다.\n<br/>\n\n> JIT 컴파일(just-in-time compilation) 또는 동적 번역(dynamic translation)은 프로그램을 실제 실행하는 시점에 기계어로 번역하는 컴파일 기법이다. 이 기법은 프로그램의 실행 속도를 빠르게 하기 위해 사용된다.\n<br/>\n\n## 다시 V8\n\n제일 공통의 파이프라인과 비슷하다. `Ignition` 이라고 불리는 인터프리터를 통해서 코드를 **점화** 하여 바이트 코드를 생성 및 실행을 한다. \n<br/>\n\n바이트코드가 실행될 때 인터프리터는 프로파일링 데이터를 수집하여 나중에 실행 속도를 빠르게 한다.(위에서 말한 최적화된 코드를 생성하는데 사용됨)\n<br/>\n\n특정 함수를 자주 사용하게 되면 뜨거워지는 이를 바이트코드와 프로파일링된 데이터를 **TurboFan** 이라고 불리는 최적화 컴파일러로 보내서 식혀준다. 최적화 컴파일러는 2개의 데이터를 통해서 최적화된 코드를 뽑아낸다.\n<br/>\n\n최근 엔진들은 최적화를 적용하는데 있어서 **JITC이 아닌 Adative Compilation을 적용한다고 한다.** 이는 반복되는 정도에 따라 서로 다른 최적화를 적용한다는 것이다.\n<br/>\n\n## SpiderMonkey   \n\n`SpiderMonkey` 는 최적화된 컴파일러가 **2개** 이다. `Baseline Complier` 을 토대로 약간 최적화된 코드를 만들어내고 코드를 실행하는 동안에 수집된 프로파일링 데이터와 합쳐져서 `IonMonkey` 라는 최적화 컴파일러로 보내져서 고도로 최적화 된 코드를 만들어 낸다.\n<br/>\n\n만약에 추측성 최적화가 실패하게 되면, **IonMonkey는 이를 Baseline 코드로 되돌리게 된다.** 그렇다면 바이트코드까지를 다시 `decompile` 이 안된다는 말이 되는 듯 하다.\n<br/>\n\n## Chakra Core\n\n`Chakra Core` 역시 `spider monkey` 와 동일하게 **2개의 컴파일러를 가진다.** \n<br/>\n\n`SimpleJIT` 를 통해서 약간 최적화된 코드를 만들어내고 `FullJIT` 를 통해서 프로파일링 데이터와 함께 더욱 고도로 최적화 된 코드를 생성한다. \n<br/>\n\n> 어째 얘는 decompile이 이루어지면 바이트코드로 들어간다.(최적화된 것을 풀수도 있다는 말)\n<br/>\n\n## Javascript Core\n\n`JSC` 는 **3개의 컴파일러를 가지고 있다.** `LLInt(Low-Level Interpreter)` 라는 인터프리터 `Baseline` 컴파일러로 제일 어림짐작해서 약간 최적화된 코드를 만들어내고, 이후에는` DFG(Data Flow Graph)과 FTL(Faster Than Light)` 라는 최적화 컴파일러를 사용한다.\n<br/>\n\n## 처리방법의 차이점과 공통점\n\n왜 많은 최적화 컴파일러를 가지고 있을까?? \n<br/>\n\n바로 `trade-off` 때문이라고 한다.\n<br/>\n\n인터프리터는 바이트코드를 빠르게 생성할 수 있지만 효율적인 코드는 아니다. 반대로 최적화 컴파일러는 시간이 조금 더 걸리지만 훨씬 효율적인 기계 코드를 생성한다. \n<br/>\n\n따라서, 어떤 엔진은 여러 개의 최적화 컴파일러를 선택함으로써 복잡해지는 비용을 감수하고 이러한 인터프리터와 컴파일러 사이의 균형을 필요에 따라 세부적으로 제어할 수 있도록 한 것이다. \n\n결국, 자바스크립트 엔진마다 구체적인 최적화 과정은 차이가 있으나, 파서와 인터프리터/컴파일러가 포함된 동일한 아키텍쳐로 구성이 된 것이다.\n<br/>\n\n---\n\n#### Reference \n\n- [Velog](https://velog.io/@godori/JavaScript-%EC%97%94%EC%A7%84-%ED%86%BA%EC%95%84%EB%B3%B4%EA%B8%B0-mdjowmjlcb)\n- [TostMeetup_JITC, Adaptive Compilation](https://meetup.toast.com/posts/77)\n- [TostMeetup_Hidden class, Inline Caching](https://meetup.toast.com/posts/78)"
  },
  {
    "path": "Javascript/Javascript_메모리관리.md",
    "content": "# Javascript_메모리관리\n\n고급 언어 인터프리터는 `가비지 콜렉터` 라는 소프트웨어를 가지고 있다. \n<br/>\n\n## 가비지 콜렉터란 \n\n**메모리 할당을 추적하고 할당된 메모리가 더 이상 필요 없어졌을 때 해제하는 작업을 한다.**\n<br/>\n\n일반적인 경우에 어떤 메모리가 필요없는지 알아내는 것은 알고리즘으로 풀 수 없는 비결정적인 문제이다.\n<br/>\n\n가비지 컬렉션자바스크립트의 메모리 관리는 우리에게는 보이지 않게 **자동으로** 실행된다.\n<br/>\n\n우리가 원시타입의 변수나 혹은 객체, 함수를 선언할때도 모두 메모리를 사용한다. 만약에 이러한 것들이 더이상 필요없게 된다면\n**자바스크립트 엔진은 어떻게 이것들을 찾아내어 삭제하는걸까?**\n<br/>\n\n## 접근 가능성(Reachability)\n\n자바스크립트 메모리 관리의 주요 개념은 **접근 가능성** 이다. \n<br/>\n\n간단하게 말하면 **접근 가능한** 값은 어떻게든 엑세스가 가능하거나 사용할 수 있는 값임을 뜻한다. 이들은 메모리에 유지되는것을 보장받는다.\n<br/>\n\n1. 명백한 이유로 삭제될 수 없는 본질적으로 값에 접근 가능한 기본 세트가 있다. 이런 것들을 뿌리(Root)라고 부르겠다.\n\n   - 현재 함수의 지역 변수와 매개변수\n   - 다른 함수의 중첩 호출로 실행된 함수의 경우 현재의 스코프 체인으로 접근 가능한 변수와 매개변수\n   - 전역 변수\n\n2. 기타 다른 값은 참조(Reference) 또는 레퍼런스의 참조(A chain of references)에 의해 루트에서 도달 가능한 것으로 간주한다. \n\n예를 들어 로컬 변수가 특정 객체를 참조하고 있고 그 객체가 또다른 객체를 참조하는 프로퍼티를 가지고 있다면 그 객체에 도달 가능하다 라고 간주한다. 그리고 그것들이 참조하는 다른 것들도 도달할 수 있다.\n<br/>\n\n자바스크립트 엔진의 백그라운드 프로세스로 동작하는 **가비지 콜렉터** 라는 것이 있다. 이것은 모든 객체들을 모니터링 하며 그것들이 접근 불가능하게 되었을 때 삭제하는 작업을 수행한다.\n<br/>\n\n```js\n// user는 객체에 대한 참조를 가지고 있습니다.\nlet user = { name: \"SeonHyung\"};\n```\n\n![Javascript_메모리관리_1](https://github.com/SeonHyungJo/FrontEnd-Dev/blob/master/assets/image/Memory_management_1.png?raw=true)\n\n여기에 표시된 화살표는 객체 참조를 보여준다.\n<br/>\n\n전역 변수 `user` 는 `{name: \"SeonHyung\"}` 객체를 참조한다.\n<br/>\n\n존의 `name` 프로퍼티는 원시 타입을 저장하여 객체의 내부에 위치합니다. 여기에서 우리가 `user` 의 값을 덮어쓰게 되면 참조를 잃게 된다. \n<br/>\n\n`user = null;` 이제 SeonHyung 은 접근이 불가능하게 되었다. 여기에 접근할 방법은 없으며 아무도 SeonHyung 을 참조하지 않게 되었다. \n<br/>\n\n가비지 콜렉터는 데이터를 회수하고 메모리를 비운다. \n<br/>\n\n## 두개의 참조\n\n이번에는 `user` 를 `admin` 으로 참조를 복제하였다고 상상 해 보겠습니다.\n\n```js\nlet user = { name: \"SeonHyung\"};\nlet admin = user;\n```\n\n이제 우리는 똑같은 작업을 한번 더 해보면.\n\n```js\nuser = null; \n```\n\n하지만 여전히 `admin` 변수가 SeonHyung 을 참조하고 있으므로 메모리에 유지된다. 우리가 `admin` 도 null로 선언을 한다면 그때 삭제 될 것이다. \n<br/>\n\n![Javascript_메모리관리_2](https://github.com/SeonHyungJo/FrontEnd-Dev/blob/master/assets/image/Memory_management_2.png?raw=true)\n\n## 상호 연결된 객체\n\n이번엔 좀 더 복잡한 예제를 살펴보자. \n\n```js\nfunction marry(man, woman) {   \n    woman.husband = man;   \n    man.wife = woman;   \n\n    return {      \n        father: man,      \n        mother: woman   \n    }\n}\n\nlet family = marry({       \n        name: \"Any\"   \n    }, {       \n        name: \"Jerry\"   \n    }\n);\n```\n\n`marry` 는 두 개의 객체를 서로 참조하게 하고 이 둘을 참조하고 있는 새로운 객체를 반환하는 결혼(?)을 시키는 함수이다.\n<br/>\n\n메모리 구조의 결과는 다음과 같이 나온다.\n<br/>\n\n![Javascript_메모리관리_3](https://github.com/SeonHyungJo/FrontEnd-Dev/blob/master/assets/image/Memory_management_3.png?raw=true)\n\n모든 객체는 서로 접근 가능하게 되었다. 이제 두 개의 참조를 삭제하게 되면.\n\n```js\ndelete family.father;\ndelete family.mother.husband;\n// 전에도 글을 썻지만 delete를 사용하는 것보다는 null을 넣어주는 것이 더 좋다.\n```\n\n이 두개의 참조중에 하나만 삭제할 경우에는 여전히 모든 객체가 접근 가능하므로 객체가 삭제되기에 충분하지 않게 되는데 2개를 모두 삭제를 하는 아래와 같은 경우는 더이상 존재하지 않게 된다.\n<br/>\n\n![Javascript_메모리관리_4](https://github.com/SeonHyungJo/FrontEnd-Dev/blob/master/assets/image/Memory_management_4.png?raw=true)\n\n그러므로 애니는 이제 접근 불가능하게 되었고 메모리에서 제거되게 된다.\n<br/>\n\n가비지 콜렉션이 동작한 이후에는 다음과 같이 나오게 된다.\n<br/>\n\n![Javascript_메모리관리_5](https://github.com/SeonHyungJo/FrontEnd-Dev/blob/master/assets/image/Memory_management_5.png?raw=true)\n\n## 접근 불가능한 섬\n\n외부에서 접근 불가능한, 자기들끼리만 상호 참조하여 만들어진 완벽한 형태의 섬도 메모리에서도 삭제가 가능하다.\n<br/>\n\n소스코드는 위와 동일하다고 가정하자\n<br/>\n\n이 예제는 접근 가능성에 대한 매우 중요한 개념을 보여주는 예제라고 생각하면 좋다.\n<br/>\n\n애니과 제리는 연결되어있다.\n<br/>\n\n그 둘은 안/밖으로 연결되는 링크들 모두를 가지고 있다.\n<br/>\n\n![Javascript_메모리관리_6](https://github.com/SeonHyungJo/FrontEnd-Dev/blob/master/assets/image/Memory_management_6.png?raw=true)\n\n하지만 이전의 `family` 객체는 루트(Root)와의 연결이 끊어지게 되었다. 그러므로 이 완벽한 섬은 접근 불가능하게 되었으며 삭제될 것이다.\n<br/>\n\n## 내부 알고리즘\n\n기본적인 가비지 콜렉션의 알고리즘은 `마크 앤 스윕(Mark-and-sweep)`이라고 불린다. 일반적으로 가비지 콜렉션은 다음의 과정을 거치게 된다.\n\n> [마크 앤 스윕(Mark-and-sweep)](https://ko.wikipedia.org/wiki/%EC%93%B0%EB%A0%88%EA%B8%B0_%EC%88%98%EC%A7%91_(%EC%BB%B4%ED%93%A8%ED%84%B0_%EA%B3%BC%ED%95%99))\n\n- 가비지 콜렉터는 루트를 획득하여 그들을 마크(기억)한다.\n- 그리고 그들이 참조하고 있는 모든 것들에 방문하여 마크한다.\n- 그리고 마크한 모든 객체에 방문하여 그들의 참조 역시 마크한다. 모든 객체들을 기억하고 나면 미래에는 같은 객체를 두 번 방문하지 않는다.\n- 루트로부터 접근 가능한 방문하지 않은 참조가 있다면 계속해서 반복한다.\n- 마크되지 않은 모든 객체는 삭제된다.\n\n예를 들어 다음과 같은 객체의 구조가 있다고 해보자. 우리는 오른편에 **접근 불가능한 섬** 을 발견할 수 있다. \n<br/>\n\n이제 가비지 콜렉터가 진행하는 마크 앤 스윕 과정이 이것을 어떻게 다루는지 보자. \n<br/>\n\n![Javascript_메모리관리_7](https://github.com/SeonHyungJo/FrontEnd-Dev/blob/master/assets/image/Memory_management_7.png?raw=true)\n\n다음은 루트로부터 첫번째 과정 결과 :\n<br/>\n\n![Javascript_메모리관리_8](https://github.com/SeonHyungJo/FrontEnd-Dev/blob/master/assets/image/Memory_management_8.png?raw=true)\n\n이후에 그들의 참조들도 마크 결과 :\n<br/>\n\n![Javascript_메모리관리_9](https://github.com/SeonHyungJo/FrontEnd-Dev/blob/master/assets/image/Memory_management_9.png?raw=true)\n\n그리고 그들의 참조도 가능할 때까지 반복 :\n<br/>\n\n![Javascript_메모리관리_10](https://github.com/SeonHyungJo/FrontEnd-Dev/blob/master/assets/image/Memory_management_10.png?raw=true)\n\n이제 방문할 수 없는 객체들은 접근 불가능한것으로 간주되어 삭제될 것이다. 이것이 **가비지 콜렉터** 가 동작하는 개념이다.\n<br/>\n\n![Javascript_메모리관리_11](https://github.com/SeonHyungJo/FrontEnd-Dev/blob/master/assets/image/Memory_management_11.png?raw=true)\n\n자바스크립트 엔진은 어플리케이션의 실행에 영향을 주지 않고 빠르게 수행되도록 하기 위해 많은 최적화 옵션을 적용하고 있다.\n\n- 세대별 수집 : 객체는 **새로운 객체와 이전 객체** 두 개의 세트로 나뉘어진다. 많은 객체들은 나타나고 그들의 일을 수행하고 빨리 죽는다. 이것들은 공격적으로 청소될 수 있다. 하지만 충분히 오래 살아남은 객체들은 **오래된** 객체가 되어 덜 자주 검사를 받게 된다(JS엔진을 보면 더 명확해 질 듯).\n- 증분 수집 : 많은 객체가 있고 이러한 많은 객체를 한번에 전부 다 방문하며 마크하는 과정을 거치게 되면 실행에 눈에 띄는 지연이 발생할 수 있다(당연히). 그래서 엔진은 이러한 수거 작업을 여러 조각으로 나누어 수행한다. 이렇게 나눈 조각의 변화를 추적할 수 있도록 부가적인 처리가 필요하지만 큰 한번의 딜레이 대신에 짧은 단위의 딜레이를 가질 수 있다.\n- 유휴 시간 수집 : 가비지 콜렉터는 CPU가 유휴상태일 때만 실행되어 어플리케이션의 실행에 끼치는 영향을 줄인다.\n\n이것 말고도 가비지 콜렉터의 다른 최적화 기능들이 있다. 각 엔진들이 구현하고 있는 추가적인 테크닉들이 있으며 엔진의 발전에 따라 지속적으로 변화하고 있다. 정리하면 아래와 같다.\n<br/>\n\n- 가비지 콜렉션은 자동으로 실행\n- 객체는 그들이 접근 가능한 동안 메모리에 유지\n- 참조가 된다는 것이 루트(Root)에서 참조 가능한 것과 같은 말은 아니다 : 상호 참조하고 있는 객체들이 전체에서 보면 참조 불가능할 수 있습니다.(접근 불가능한 섬 같은 경우)\n\n---\n\n#### Reference\n\n- [MDN-Memory_Management](https://developer.mozilla.org/ko/docs/Web/JavaScript/Memory_Management)\n- [가비지 컬렉션](http://theeye.pe.kr/archives/2872)\n"
  },
  {
    "path": "Javascript/Javascript의_동작원리-변수객체(VariableObject).md",
    "content": "# 자바스크립트의 동작 원리 - 변수 객체(Variable Object)\n[자바스크립트의 동작 원리 - 실행 컨텍스트(Execution Contexts)]()에 이어서...\n\n## 변수 객체(Varaiable Object; VO)\n\n**변수 객체**는 **실행 컨텍스트의 프로퍼티**로, **실행에 필요한 정보**(어디에 어떤 데이터가 저장되고, 어떻게 호출할 수 있는지)를 담고 있다. \n또한, 변수 객체는 코드가 실행될 때 **엔진에 의해 참조**되며 **코드에서는 접근할 수 없다**. \n\n> 변수 객체의 구성요소\n\n- 변수 선언(variable declaration)\n- 함수 선언(function declaration; FD)\n- 매개변수(formal parameters)와 인수정보(arguments)\n\n<br/>\n\n## 데이터 선언(Data Declaration)\n\n**변수나 함수를 선언**하는 것은 **변수 객체에** 변수의 이름과, 이름에 할당된 값을 갖는 **새로운 프로퍼티를 만드는 것**과 같다.\n\n```js\nvar a = 10;\n     \nfunction test(x) {\n  var b = 20;\n};\n     \ntest(30);\n\n// 전역 콘텍스트의 변수 객체\nVO(globalContext) = {\n  a: 10,\n  test: <reference to function>\n};\n     \n// test 함수 콘텍스트의 변수 객체\nVO(test functionContext) = {\n  x: 30,\n  b: 20\n};\n```\n\n<br/>\n\n\n## 변수 객체의 value\n\n**변수 객체는** 프로퍼티이기 때문에 **값을 갖는데,** 이 값은 **다른 객체를 참조**한다. \n이 때, 전역 컨텍스트와 함수 컨텍스트는 **참조하는 객체가 다르다**. 전역코드와 함수 코드의 내용이 다르기 때문이다. \n하지만, 모든 종류의 실행 컨텍스트에서 공통적으로 동작하는 작업이 있다.\n\n> e.g. 변수 초기화, 변수 객체의 동작\n> \n- \"From this viewpoint it is convenient to present the **variable object as an abstract base thing\"**\n```js\nAbstractVO // generic behavior of the variable instantiation process\n║\n╠══> GlobalContextVO // 전역 컨텍스트의 변수 객체는 전역 객체이다.\n║ (VO === this === global) \n║\n╚══> FunctionContextVO // 함수 코드의 실행 컨텍스트에서 변수 객체는 활성 객체이다.\n  (VO === AO // <arguments> object and <formal parameters> are added\n```\n> ES5에서는 변수객체, 활성화 객체의 개념이 Lexical Enviroments(어휘적 환경)모델로 대체되었다.\n\n<br/>\n\n## 전역 컨텍스트의 변수 객체\n\n전역 컨텍스트의 변수 객체는 전역 객체이다.\n\n```js\nvar x = 'xxx';\n    \nfunction foo () {\n  var y = 'yyy';\n\n  function bar () {\n    var z = 'zzz';\n    console.log(x + y + z);\n  }\n  bar();\n}\nfoo();\n```\n\n![ec-vo-global](https://s3.us-west-2.amazonaws.com/secure.notion-static.com/4d04926a-02d8-441a-8a0b-0f7458e98d65/ec-vo-global.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ASIAT73L2G45KK2GYH5R%2F20190525%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20190525T131046Z&X-Amz-Expires=86400&X-Amz-Security-Token=AgoJb3JpZ2luX2VjEOL%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaCXVzLXdlc3QtMiJGMEQCICpOsfUz1CPK1D65zkc8u9hafV8Iv07PKDeOy%2FkLzkNtAiBqEDls4HELllnKXPeGLZlv8FfVFskKX5bR%2BUNWjdrE1CrjAwjr%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F8BEAAaDDI3NDU2NzE0OTM3MCIMcZT7l7vvSLSqV1l8KrcD9dV5u8xMb2pkxwKeVOXfBhmVbvCCyM0pFZAtRJk2GjVzkxBVxP8LaZa8pklFu8d64f56Ny1zz6mTehBq6g1YRGy6WSBFTmETSduze9MCR7lI0LJn1%2B5m2W7A1aSzheDCzuxDL%2FU%2FxG6ringqpQt%2FU2r76s5EDQQpY%2BCJyl3C9YDLS2pCZRMuAnIGFYIcgvp%2B%2B7YVpBFt1LdrR9HaDSNvsJtcJw0xRIBph5XlOk6aRr2Ss2Gbknw55s0R6P5GzpcMN2FuRt0RgnkzwM3%2B%2BrucMVS8Gc5cOGinV4NLz8qlEn9OBvPb8KFNt4LWirc069ZG0m1qhnMC3tKjoDpNibB5s%2FjsszPwnhdGvR84Gx96xNp1%2F4cyhLbi1DZRWGAywWvNKcTIEwVLeAsnz63YPBZ9z9SfqqrxapQ7vB%2Fiovg2icRud0VMMbA7dx3xe8cwlI2x7Ow8i2Eb4K5SvaU4O1mR1xYY5hR9H%2BDYg7rd%2BCaV6XCis2NZcHt7fENfnPyi%2Fo84iX5R1XImkZuy4l2enaX2gsEZqb%2FZYM%2BXPZcb6Dub%2Fken%2BRjscNbN01Ki4vguCj6f7xhapPXKUzCfk6TnBTq1AQffTGcQNldDAD46FY9QGM%2BzOzeH3Sjmu70bqB%2F9N8SlEIn7C6uUNzsLdxD%2FZ5HOuxPDKwPodRTBxKBKqHAj0OV%2BknRncQD7UPKi05NzAC83G7emqnfmUdUpi0gEYPAdTGNHOr5qQVHeJEds70Tq6w6R2CWtMB5meAoHt6ncSj2XSfk8FDrlzY0QPnhc2ftBVFvyeSXswOOZ7cDCUVc8mDYSEJI%2BDwIaFF4TNLuXO9QJRHsztwM%3D&X-Amz-Signature=633a520f56d081a8e1fb180d2ad7a7a3883faaf4d8380166266d38fccd92b682&X-Amz-SignedHeaders=host&response-content-disposition=filename%20%3D%22ec-vo-global.png%22)\n\n변수객체는 코드에서 **직접(directly) 접근이 불가능**하다. 하지만, 전역 컨텍스트의 변수 객체에 있는 변수(variable)는 간접적으로 참조 가능하다. 전역 컨텍스트의 변수 객체는 전역 객체이다. 즉, **전역 객체(GO)에 있는 변수만 간접적으로 참조 가능**(위의 예제에서 `foo`, `x`)하다. 변수를 선언하는 것은 VO에 프로퍼티를 만드는 것이기 때문에 **변수 객체의 프로퍼티명을 통해서 참조 가능**하다.  따라서, 전역 컨텍스트에서 변수를 선언하면 변수 객체의 프로퍼티를 통해서 간접적으로 접근할 수 있다.\n\n```js\n// 위의 예제에 이어서\nalert(x); // VO(globalContext)에 직접적으로 접근한다. \"xxx\" 출력 \nalert(window['x']); // 전역 객체 === VO(globalContext)인 점을 이용해서 간접적으로 접근한다. \"xxx\" 출력\nalert(x === this.x); // true \n\nvar key = 'x';\nalert(window[key]); // 동적인 프로퍼티 명으로 간접적으로 접근. \"xxx\" 출력\n```\n\n<br/>\n\n## 함수 컨텍스트의 변수 객체\n\n마찬가지로, 함수 코드의 실행 컨텍스트에서 **변수 객체는 직접 접근이 불가능**하다. \n전역 객체에서는 변수 객체를 간접적으로 참조하여 접근하지만, 함수 컨텍스트에서 이 역할은 활성화 객체(Activation objcet; AO)가 수행한다.\n\n```js\nvar x = 'xxx';\n\nfunction foo () {\n  var y = 'yyy';\n\n  function bar () {\n    var z = 'zzz';\n    console.log(x + y + z);\n  }\n  bar();\n}\nfoo();\n```\n\n![ec-vo-foo](https://s3.us-west-2.amazonaws.com/secure.notion-static.com/339c4880-e854-4327-9077-d4fdcf99a82b/ec-vo-foo.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ASIAT73L2G45F3FYW6EI%2F20190525%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20190525T131259Z&X-Amz-Expires=86400&X-Amz-Security-Token=AgoJb3JpZ2luX2VjEOL%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaCXVzLXdlc3QtMiJGMEQCIDC0pw0hiRk%2F77IjvScAiEhUrXY1pUFuQ4znsFHBnBIwAiAwfehU7%2BIrxknd05ZPi%2BS%2F%2BXNrXcg2uZg3NUeUsqWCICrjAwjr%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F8BEAAaDDI3NDU2NzE0OTM3MCIMXzhtWBY2bblxqkC4KrcD0GUAeN6JafXO35kuEfrq%2B%2FzOEOtb%2FSRG619CyDfFeFXr%2FNopVQAK5cBhBI4fFiDhgLWnsV4EEjtO6aZPNNg6b70DMwR%2FELrZrMmA32Y10P2Vmsgb94LV7xVKAp6jTZ0SujPavHadHpA2U5NLt5U0UObwZGxLMsN7viuRsOPOghiSN3zXmG46WHFuX13pMHFjE0lfmnD0i0vXjB%2BOHDnRsmm4bbg40xEtvCKhn8DKqdUMsc33FADaUDF0ZtHh0xRyDql5RU91PQaabNq35zDTuazrP3LBZSEmnkQV%2Fwg7TsZc8fCuz%2Fk8sAxSKZMI4QO2UPgW7Oxy8eaYwC6aT8t%2FgwvApXqWKwCXhpg1B4T5yfbAms0qPIrnQiFFkak%2BoTW7HClmKFwk56pgtz2z8BpLfI3x4MXCTXdXDoBTgunyVMeWU2oM7NvzXXamKNE2rBhXLHoZ70btEaBlfO%2BnRev8Yt%2BNjEybHncbfA6MaXv25j%2F2YOew3cz6Fk%2Bkmb6Zi%2FplLyfK9ILhgecAU5Jm7Ee2PlGczM7FAO3Znwq96LWXfq3wnaG0s1Lc9LCZEbX0VNiwzX8ffqMmzjDNoaTnBTq1ARJPX2l4Fe3SDP6Q8kIHSFxcFYc6HTch0JhN03JSQnF2GpK8s3nTQcZBqGqsfjweKdMMxkmp8geAZrOa39UdQJktz9GY0NDOjP5KhYRg55aB5Wa%2BnkMOyTXe3Md3J6lefIg9xU%2B29GA4plZswFvJu51LQi3fvuVWSdTwdIt3pDOy5O3HgDcUvyNZj5gvPZ14j6%2BHFO1jk9YGldprK8VsR1F2MNY6emJsBXcHz7GjubBcMm5PTJ0%3D&X-Amz-Signature=fc5f8e5b948bc43f0aee8b901108a9c20ae377faad98646040f5526655361095&X-Amz-SignedHeaders=host&response-content-disposition=filename%20%3D%22ec-vo-foo.png%22)\n\n<br/>\n\n## 활성화 객체(Activation Object)\n\n활성화 객체는 함수 코드의 컨텍스트로 진입할 때 생성되고, 값이 `Arguments` 객체인 `arguments` 프로퍼티로 초기화된다.\n```js\nAO = {\n  arguments: <ArgO>\n};\n```\n> 활성화 객체의 프로퍼티\n- Arguments 객체 - 활성화 객체의 프로퍼티\n- callee - 현재 함수에 대한 참조\n- length - 실제로 전달된 인자의 수\n- properties-indexes(\"num\")\n    - 함수 매개 변수의 값(왼쪽부터 오른쪽 까지 매개 변수의 리스트)\n    - arguments.length와 개수가 같다.\n    - arguments객체의 properties-indexes와 제공된 매 변수는 실제로 전달된 값을 공유한다.\n\n```js\nfoo(10, 20);\n\nfunction foo(x, y, z) {\n\n  alert(foo.length); // 정의된 함수 매개변수 x,y,z의 수량 : 3 \n  alert(arguments.length); // 실제로 전달된 매개변수(x, y)의 수량 : 2\n  alert(arguments.callee === foo); // 함수 자신에 대한 참조 : true\n \n  // 매개변수 공유\n  alert(x === arguments[0]); // true\n  alert(x); // 10\n \n  arguments[0] = 20;\n  alert(x); // 20\n \n  x = 30;\n  alert(arguments[0]); // 30\n \n  // 전달되지 않은 매개변수 z는 공유되지 않는다.  \n  z = 40;\n  alert(arguments[2]); // undefined\n \n  arguments[2] = 50;\n  alert(z); // 40 \n}\n```\n\n<br/>\n\n## 컨텍스트 코드 실행 단계(Phases of processing the context code)\n\n실행 컨텍스트 코드의 실행은 두 단계에 걸쳐서 이루어진다.\n\n1. 실행 컨텍스트 진입\n2. 코드 실행\n\n이 단계에서 변수 객체의 프로퍼티가 채워지며, 값이 할당된다.\n\n<br/>\n\n## 실행 컨텍스트 진입\n\n실행 컨텍스트로 들어가면 VO는 아래의 프로퍼티로 채워진다.\n\n- 함수의 매개 변수를 위한 프로퍼티(함수 컨텍스트의 경우)\n    - 매개변수(formal parameter)의 이름과 값을 갖는 변수 객체의 프로퍼티\n    - 값(인수; arguments)이 전달되지 않으면 값이 undefined\n- 함수 선언을 위한 프로퍼티(FunctionDeclaration; FD)\n    - 함수 객체의 이름과 값을 갖는 변수 객체의 프로퍼티\n    - 이미 같은 이름의 변수가 있으면, 새로운 값으로 교체\n- 변수 선언을 위한 프로퍼티(VariableDeclaration; var)\n    - 변수의 이름과 undefined 값을 갖는 변수 객체의 프로퍼티\n    - 변수의 이름이 이미 선언된 매개변수나 함수의 이름과 같다면, 변수 선언은 무시된다.\n\n> 실행 컨텍스트에 진입 하는 단계에서 VO에 프로퍼티는 설정되지만, 값이 할당되지는 않는다.(호이스팅)\n\n```js\nfunction test(a, b) {\n  var c = 10;\n  function d() {}\n  var e = function _e() {};\n  (function x() {});\n}\n \ntest(10); // 호출\n```\n\ntest의 함수 컨텍스트\n```js\nAO(test) = {\n  a: 10,\n  b: undefined,\n  c: undefined,\n  d: <reference to FunctionDeclaration \"d\">\n  e: undefined\n};\n```\n\n함수 `x`는 선언식이 아니라, 함수 표현(FunctionExpression; FE)이기 때문에 VO에 영향을 주지 않는다.\n\n함수 `_e` 또한 표현식이지만, 변수 e에 할당되기 때문에 e를 통하여 접근할 수 있다.\n\n<br/>\n\n## 코드 실행\n\n코드가 해석되는 동안 AO/VO의 프로퍼티가 변경된다.\n\n> 실행 컨텍스트로 진입하면 AO/VO가 프로퍼티로 채워지지만, 모든 프로퍼티에 실제 값이 할당되어있지는 않다.\n\n```js\n// 위의 예제에 이어\nAO['c'] = 10;\nAO['e'] = <reference to FunctionExpression \"_e\">;\n```\n\n표현식 `_e` 가 선언된 변수`e` 에 저장되어 있기 때문에 메모리에 존재한다. 반면, 함수 `x`는 존재하지 않는다. \n`x`를 호출하여도 `\"x\" is not defined`라는 에러가 나오게 된다. \n변수에 저장하지 않은 표현식은 정의된 곳에서 호출하지 않으면, 재귀적인 방법으로만 호출할 수 있기 때문이다.\n\n> 예시, 코드가 해석되기 전과 후의 차이\n\n```js\nalert(x); // function\n \nvar x = 10;\n\nalert(x); // 10\n \nx = 20; \n\nfunction x() {} \n\nalert(x); // 20\n```\n\n> 참고 - [Hoisting(MDN Docs)](https://developer.mozilla.org/ko/docs/Glossary/Hoisting)\n\n<br/>\n\n## 변수의 경우\n\n변수는 오직 `var` 키워드를 이용하여 선언한다. 따라서, `var` 키워드를 이용하지 않으면 전역변수가 된다는 것은 틀린 말이다. \n`var` 키워드를 이용하지 않고 값을 할당하는 것은 전역 객체에 새로운 프로퍼티(변수가 아닌)를 추가하는 것이다.\n\n> 변수가 아니라는 것은 값을 할당하고 변경하고 참조하는 등이 불가능하다는 것이 아니다.  ECMAScript에서 말하는 변수의 개념이 아니라는 뜻이다.\n\n```js\nalert(a); // undefined\nalert(b); // \"b\" is not defined\n \nb = 10;\nvar a = 20;\n```\n\nb는 변수가 아니므로, VO안에 없다(호이스팅이 이루어지지 않는다).\n\n```js\nVO = {\n  a: undefined\n}; \n```\n\n```js\na = 10;\n\nalert(window.a); // 10 \nalert(delete a); // true \nalert(window.a); // undefined\n \nvar b = 20;\nalert(window.b); // 20 \nalert(delete b); // false \nalert(window.b); // 여전히 20\n```\n\n또한, 변수는 `DontDelete` 속성을 가지고 있다. 반면, 단순 프로퍼티는 그렇지 않기 때문에 `delete` 연산자를 이용하여 삭제할 수 있다.\n\n> ES5에서 `DontDelete` 는 `Configurable` 로 이름이 변경되었고 `Object.defineProperty` 메서드를 이용해서 수동으로 조작할 수 있다.\n\n<br/>\n\n## eval의 경우\n\n```js\neval('var a = 10;');\n\nalert(window.a); // 10 \nalert(delete a); // true \nalert(window.a); // undefined\n```\n\n변수에 `DontDelete` 속성이 설정되지 않는다.\n\n> Firebug는 콘솔에서 코드를 실행하기 위해 `eval` 을 사용한다. 따라서 변수를 `delete` 로 삭제할 수 있다.\n\n---\n\n#### Reference\n\n- [ECMAScript Language Specification (HTML version) - Bob Clary](https://bclary.com/2004/11/07/ecma-262.html)\n- [ECMA-262-3 in detail. Chapter 2. Variable object - Dmitry Soshnikov](http://dmitrysoshnikov.com/ecmascript/chapter-1-execution-contexts/)\n- [ECMA-262-3 in detail. Chapter 2. Variable object 번역 - 개발왕 김코딩](https://huns.me/development/159)\n- [실행 컨텍스트와 자바스크립트의 동작 원리 - poiemaweb](https://poiemaweb.com/js-execution-context)\n"
  },
  {
    "path": "Javascript/Javascript의_동작원리-실행컨텍스트(Execution Contexts).md",
    "content": "# 자바스크립트의 동작 원리 - 실행 컨텍스트(Execution Contexts)\n\n> ES3을 기반으로 설명\n\n<br/>\n\n## 실행 컨텍스트(Execution Contexts)\n\nECMA-262-3에서는 \"**실행 가능한 코드(Executable code; 이하 실행 코드)** 의 유형을 **나누고(형상화)**, **구별**하기 위한 추상적인 개념\"으로 정의한다. 실행 코드를 실행하기 위해 **필요한 환경**을 뜻한다.\n\n실행 컨텍스트는 추상적인 개념이지만, **물리적으로는 객체의 형태**이며 **코드 실행에 필요한 정보(변수, 함수 선언, 스코프, this)** 가 들어있다.\n\n> 실행 코드 : 특정 순간의 실행 컨텍스트로 하나의 실행 컨텍스트에서 처리되는 코드의 단위를 뜻한다.\n\n**실행 코드의 종류에 따라** 실행 컨텍스트의 **초기화 과정**이 달라지고, 실행 컨텍스트의 **성격이 결정**된다.\n\n> 실행 코드의 종류 : 전역 코드, 함수 코드, eval 코드\n\n실행코드로 **제어(control)** 가 전달되면 해당 제어는 실행 컨텍스트로 **진입**한다.\n\n> 제어 : 명령어가 적절한 순서로 수행하도록 제어하는 컴퓨터의 구성 장치로, 제어가 전달(이동)된다는 것은 프로그램의 처리 흐름이 이동하는 것이라 생각하면 된다.\n\n<br/>\n\n## 실행 컨텍스트의 구조\n\n실행 컨텍스트들은 논리적으로 **스택(stack)의 형태**를 구성하고 있다.\n\n> 예시\n\n```js\nvar x = 'xxx';\n\nfunction foo () {\n  var y = 'yyy';\n\n  function bar () {\n    var z = 'zzz';\n    console.log(x + y + z);\n  }\n  bar();\n}\nfoo();\n```\n\n![ECStack](/assets/images/javascript의_동작원리-실행컨텍스트(ExecutionContexts)-1.png)\n\n스택의 **바닥(bottom)** 에는 항상 **전역 컨텍스트(global context)** 가 있다.\n\n  > 전역 컨텍스트 : 유일하며, 최상위에 위치하고 모든 전역변수, 전역 함수 등을 포함한다.\n\n  - 전역 컨텍스트는 해당 애플리케이션이 종료될 때(웹페이지에서 나가거나, 브라우저를 닫을 때)까지 유지된다.\n- 프로그램 시작(초기화 단계)시 ECstack\n  \n```js\nECStack = [\n    globalContext\n  ];\n```\n  \n**꼭대기(top)** 에는 현재 **활성화 된 실행 컨텍스트**가 있다.\n\n> 활성화된 실행 컨텍스트를 활성 객체(activation object; AO)라고 한다.\n\n실행 컨텍스트가 들어오고 나가면서 변경(push/pop)된다. \n새로운 실행 컨텍스트는 직전의 실행 컨텍스트 위에 쌓이고 실행 컨텍스트가 종료되면, 해당 실행 컨텍스트를 파기하고 직전 컨텍스트에 제어를 반환한다.\n> `bar`의 실행 컨텍스트가 종료되면 해당 실행 컨텍스트는 파기되고, `foo`의 실행 컨텍스트로 제어가 이동한다.\n\n<br/>\n\n## 전역 코드(Global Code)\n\n- 프로그램 수준에서 실행되는 코드로, 전역 컨텍스트에서 처리된다.\n- 로딩된 외부 `.js`파일을 실행하거나, 지역 인라인 코드(`<script>`태그 안쪽)를 만나면 생성된다.\n- 함수 body 안의 코드는 전역 코드에 포함되지 않는다. 함수 body의 내용은 함수 코드에 포함되고, 함수 실행 컨텍스트에서 처리된다.\n\n<br/>\n\n## 함수 코드(Function Code)\n\n- 함수가 호출되어 함수 코드로 진입할 때, ECStack에 새로운 활성 객체(AO)가 생성된다.\n- 새로 생성된 실행 컨텍스트는 호출된 함수(concrete function)의 코드에 중첩된 내부 함수(inner functions)의 코드를 포함하지 않는다.\n- 함수가 종료될 때마다 활성 객체는 제어를 반환하고, ECStack에서 제거된다(일반적인 스택의 동작 방식을 따라서 진행). 이 작업이 끝나면, ECStack에는 globalContext만 남아있다.\n\n> 실행 컨텍스트의 구조에서 함수를 호출하는 예제를 보았다.<br/>\n> 재귀 함수의 호출은 어떻게 될지 생각해보자\n>\n> ```js\n> (function foo(flag) {\n>     if (flag) {\n>        return;\n>     }\n>     foo(true);\n> })(false);\n> ```\n\n<br/>\n\n## Eval 코드(Eval Code)\n\n- 호출 컨텍스트(calling context)에서 처리\n\n  > 호출 문맥 : eval 함수가 호출된 문맥\n\n- eval에 의해서 만들어진 변수나 함수 정의는 호출 컨텍스트에 영향을 준다.\n\n```js\n// 전역 코드이므로, 전역 컨텍스트에 영향을 준다.\neval('var x = 10');\n\n(function foo() {\n  // 함수 안에 선언된 함수 코드이므로, foo 함수안의 지역 컨텍스트에 만들어진다.\n  eval('var y = 20');\n})();\n\nalert(x); // 10\nalert(y); // \"y\" is not defined\n```\n\n```js\nECStack = [\n  globalContext\n];\n \n// eval('var x = 10');\nECStack.push({\n  context: evalContext,\n  callingContext: globalContext\n});\n \n// eval exited context\nECStack.pop();\n \n// foo funciton call\nECStack.push(<foo> functionContext);\n \n// eval('var y = 20');\nECStack.push({\n  context: evalContext,\n  callingContext: <foo> functionContext\n});\n \n// return from eval \nECStack.pop();\n \n// return from foo\nECStack.pop();\n```\n\n<br/>\n\n## 실행 컨텍스트 생성 과정\n\n1. 전역 코드에 진입\n2. 스코프 체인 생성 및 초기화\n3. 변수 객체화(VO/AO에 프로퍼티와 값 추가)\n4. this 바인딩(this의 value 결정)\n5. 코드 실행\n\n<br/>\n\n## 실행 컨텍스트의 프로퍼티\n\n![property of EC](/assets/images/javascript의_동작원리-실행컨텍스트(ExecutionContexts)-2.png)\n\n- 변수객체(Variable Object; VO)\n- 스코프 체인(Scope Chain)\n- this Value\n\n<br/>\n\n---\n\n#### Reference\n\n- [인사이드 자바스크립트(송형주, 고현준 - 한빛미디어)](https://books.google.co.kr/books?id=gSVJDgAAQBAJ&hl=ko&source=gbs_navlinks_s)\n- [ECMA-262-3 in detail. Chapter 1. Execution Contexts. - Dmitry Soshnikov](http://dmitrysoshnikov.com/ecmascript/chapter-1-execution-contexts/)\n- [ECMA-262-3 in detail. Chapter 1. Execution Contexts 번역 - 개발왕 김코딩](https://huns.me/development/159)\n- [실행 컨텍스트와 자바스크립트의 동작 원리 - poiemaweb](https://poiemaweb.com/js-execution-context)\n"
  },
  {
    "path": "Javascript/Jest.md",
    "content": "# Jest로 테스트 코드 작성하기\n\n개발자로서 살아가다 보면 테스트 코드의 중요성에 대해 들어본 적 있을 것이다. 과연 테스트 코드는 중요할까?\n\n개발 방법론 중 하나인 TDD는 테스트 주도의 개발을 의미한다. 로직을 작성하기 전에 테스트 케이스를 정의하여 테스트를 통과하지 못하는 상태를 만들고(Red) 로직을 완성시켜가면서(Blue) 최종적으로 테스트를 통과하도록(Green) 하는 방식으로 진행된다. 번거롭다고 느낄 수 있는 방식을 사용하여 개발을 하는 이유가 무엇일까? 바로 테스트 코드를 작성하면서 얻을 수 있는 장점이 있기 때문이다.\n\n장점은 아래와 같다.\n\n1. 방금 작성한 코드가 잘 작동하는 코드인지를 판별할 수 있다.\n2. 코드를 어떻게 작성해야 할지 무엇을 해야 할지 결정하는 데 도움을 준다.\n3. 리팩토링을 하거나 새로운 기능을 구현 시 기존 테스트 코드를 기반으로 사이드 이펙트를 방지할 수 있다.\n4. 버그 발생 시 실패한 테스트로부터 원인을 찾는 데 도움을 줄 수 있다. 즉, 디버깅 시간을 줄여준다.\n5. 테스트 문서 및 스펙 문서의 역할을 할 수 있다.\n\n종합해보면 테스트 코드를 작성하면 변화에 대응하거나 유지 보수하기 쉽고 새롭게 투입된 인원이 테스트 코드를 기반으로 프로젝트를 파악하는데 수월해질 수 있다.\n\n물론 장점만 있는 건 아니다. 개발자가 테스트 코드 작성에 익숙해지는 데까지의 비용이 들 수 있다. 즉, 생산성 측면에서 초기에는 어려움이 있을 수밖에 없는 구조이다\n\n그럼에도 React나 Vue, ESLint 등 JavaScript 기반 오픈소스 프로젝트를 보면 테스트 코드가 포함되어 있는 경우가 많다. 테스트 코드 작성은 규모가 큰 오픈소스 프로젝트의 경우 보편적이며 거의 필수적으로 진행되고 있다.\n\n이번 글에서는 Jest를 이용해 테스트 코드를 작성하는 방법에 대해서 설명해보고자 한다.\n\n## Jest를 이용한 테스트 코드 작성\n\nJest는 Test Runner, Test Matcher, Test Mock까지 제공해 주는 All in one 테스팅 프레임워크이다. 이러한 테스팅 도구를 사용하게 되면 작성된 코드가 제대로 동작되는지를 확인할 수 있다. 테스트 코드의 유무는 일종의 보증서 역할을 하기 때문에 프로젝트의 볼륨이 커지는 경우 side-effect를 발견하기 쉬워진다. 또한 잘 작성된 테스트 코드는 기능을 정의한 문서로서의 역할을 할 수 있다.\n\nJest를 사용해 간단한 Unit Test를 작성할 수 있다. 이번 시간에 Jest는 어떻게 구성되어 있는지, 어떻게 사용해야 하는지를 알아볼 것이다.\n\n### 설치 및 기본 사용법\n\nJest는 node 환경이 구성되어 있는 경우 아래와 같이 npm 명령을 통해 설치할 수 있다. 이후 package.json 파일의 test 스크립트를 `jest`로 수정해 준 뒤 `npm run test` 명령어로 jest를 실행할 수 있다. jest 옵션으로 `--watchAll --coverage`를 사용하게 되면 파일 변경 시 테스트를 다시 실행해 주며 모든 파일에 대한 커버리지 확인이 가능하다.\n\n```shell\n$ mkdir jest-test\n$ cd jest-test\n$ npm init -y\n\n$ npm i -D jest\n// package.json\n...\n  \"scripts\": {\n    \"test\": \"jest --watchAll --coverage\"\n  },\n...\n```\n\nexample.test.js 파일을 만들고 아래와 같이 테스트 코드를 작성 후 jest를 실행시키면 테스트가 통과함을 알 수 있다.\n\n```javascript\ntest('1 is 1', () => {\n  expect(1).toBe(1);\n});\n```\n\nJest로 작성되는 테스트 코드의 구조는 다음과 같다.\n\n```javascript\ntest('테스트 설명', () => {\n  expect('검증 대상').toXxx('기대 결과');\n});\n```\n\n테스트 코드를 작성하는 경우 테스트 코드가 제대로 동작하는지 검증하기 위해 처음에는 실패하는 테스트를 작성한 뒤 테스트를 통과하게 수정하는 과정을 거치게 된다.\n\n### Matcher\n\nexpect 뒤에 붙는 `.toXxx` 부분이 Test Matcher이다. Test Matcher는 검증 대상에 대해 다양한 측면에서 테스트를 할 수 있도록 도와준다. Test Matcher의 종류는 아래와 같다.\n\n- `.toBe()` : 검증 대상과 기대 결과가 동일한지를 검증한다. 객체를 검증해야 하는 경우에는 사용하지 못한다.\n\n```javascript\ntest('two plus two is four', () => {\n  expect(2 + 2).toBe(4);\n});\n```\n\n- `.toEqual()` : 위와 마찬가지로 검증 대상과 기대 결과가 동일한지를 검증한다. 객체, 배열도 재귀적으로 확인하므로 검증 가능하다.\n\n```javascript\ntest('object assignment', () => {\n  const data = { one: 1 };\n  data['two'] = 2;\n  expect(data).toEqual({ one: 1, two: 2 });\n});\n  ```\n\n- `.toBeTruthy()`, `.toBeFalsy()` : 검증 대상이 true 인지, false 인지 검증한다.\n\n```javascript\ntest('null', () => {\n  const n = null;\n  expect(n).toBeNull();\n  expect(n).toBeDefined();\n  expect(n).not.toBeUndefined();\n  expect(n).not.toBeTruthy();\n  expect(n).toBeFalsy();\n});\n\ntest('undefined', () => {\n  const u = undefined;\n  expect(u).not.toBeNull();\n  expect(u).not.toBeDefined();\n  expect(u).toBeUndefined();\n  expect(u).not.toBeTruthy();\n  expect(u).toBeFalsy();\n});\n\ntest('zero', () => {\n  const z = 0;\n  expect(z).not.toBeNull();\n  expect(z).toBeDefined();\n  expect(z).not.toBeUndefined();\n  expect(z).not.toBeTruthy();\n  expect(z).toBeFalsy();\n});\n```\n\n- `.toHaveLength()` : 검증 대상의 배열의 길이를 검증한다.\n\n```javascript\nconst shoppingList = [\n  'diapers',\n  'kleenex',\n  'trash bags',\n  'paper towels',\n  'beer',\n];\n\ntest('the number of shopping list', () => {\n  expect(shoppingList).toHaveLength(5);\n});\n```\n\n- `.toContain()` : 검증 대상의 배열에 특정 원소가 있는지를 검증한다.\n\n```javascript\nconst shoppingList = [\n  'diapers',\n  'kleenex',\n  'trash bags',\n  'paper towels',\n  'beer',\n];\n\ntest('the shopping list has beer on it', () => {\n  expect(shoppingList).toContain('beer');\n  expect(new Set(shoppingList)).toContain('beer');\n});\n```\n\n- `.toMatch()` : 검증 대상에 대해 정규식 기반으로 검증이 필요할 경우 사용한다.\n\n```javascript\ntest('there is no I in team', () => {\n  expect('team').not.toMatch(/I/);\n});\n\ntest('but there is a \"stop\" in Christoph', () => {\n  expect('Christoph').toMatch(/stop/);\n});\n```\n\n- `.toThrow()` : exception 발생 여부를 검증한다. 문자열 혹은 정규식을 인자로 넘기면 에러 메시지와 동일한지 검증한다.\n\n```javascript\nfunction compileAndroidCode() {\n  throw new Error('you are using the wrong JDK');\n}\n\ntest('compiling android goes as expected', () => {\n  expect(compileAndroidCode).toThrow();\n  expect(compileAndroidCode).toThrow(Error);\n\n  expect(compileAndroidCode).toThrow('you are using the wrong JDK');\n  expect(compileAndroidCode).toThrow(/JDK/);\n});\n```\n\n## 마무리하며\n\nJavaScript 테스트 코드를 Jest의 Matcher로 어떻게 작성할 수 있는지 기본적인 부분을 다뤄보았다. 추후에 함수와 모듈을 mocking 하거나 비동기 테스트 진행 혹은 테스트 전/후처리에 대해서 작성해볼 계획이다.\n\n리액트에 Jest(+ React Testing Library)를 이용해 유닛 테스트를 하는 방법은 [프런트엔드에서 TDD가 가능하다는 것을 보여드립니다.](https://www.youtube.coM/watch?v=L1dtkLeIz-M) 영상에서 자세히 설명되어 있다.\n\n#### Reference\n\n- [Jest 공식문서](https://jestjs.io/en/)\n"
  },
  {
    "path": "Javascript/Learning_more_about_this.md",
    "content": "# this 더 알아보기\n\n지난 포스팅에서 [scope 관점에서의 this](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/scope_this.md)에 대해 알아봤다.\n\n이어서 this와 관련해서 어떤 재밌는게 있을까 궁금하여 this를 사용하는 것을 더 찾아봤다.\n\n**`new` operator** , **prototype pattern**, **method chaining** 세가지에 대해 알아봤다.\n\njs의 this는 항상 헷갈려서 어렵게 생각할 수도 있지만 쉬운 내용이라 생각해보자.\n\n## new operator\n\n`new`는 js의 생성자 패턴과 관련된 내용이다.\n\njs는 생성자 패턴을 이용하여 마치 다른 언어의 클래스와 비슷하게 동작하도록 만든다. es6의 class 키워드도 객체지향언어의 클래스처럼 보이지만 사실은 생성자 패턴의 syntatic sugar다.\n\n### 생성자 pattern 설명\n\n```js\nconst Person = function(name, age) {\n  this.name = name;\n  this.age = age;\n};\n\nconst person1 = Person('Jin', 26);\ncL;\nconst person2 = new Person('Jin', 26);\ncL;\nconsole.log(person1); // undefined\nconsole.log(person2); // Person {name: \"Jin\", age: 26}\n```\n\n`new` 키워드를 사용하지 않으면 Person은 단순 함수다. 따라서 `person1` 은 값이 `undefined`다.\n\n`new` 키워드를 사용하여 만든 person2는 `__proto__`(dunder proto)가 Person의 prototype을 가리킨다.\n\nMDN문서에서는 `new` 연산자로 객체의 인스턴스를 생성한다고 쓰여있다.\n\n### new가 하는 일\n\n그럼 `new`가 내부적으로 어떻게 실행되길래 인스턴스를 만들 수 있으며 Person이라는 함수의 this가 작동하는 것일까??\n\n생성자 패턴에서 new를 사용하게 되면 다음과 같은 일이 일어난다.\n\n1. 비어있는 새 객체(object)가 만들어진다.\n2. 새 객체의 \\_\\_proto\\_\\_가 생성자함수.prototype 으로 연결된다.\n3. 새로 생성된 객체는 생성자함수 호출 시 **this로 바인딩** 된다.\n4. 이 함수가 다른 객체를 반환하지 않는 한 1번의 새로 생성된 객체를 반환한다.\n\n즉 `new`로 만들면 객체 하나가 만들어지고 함수의 실행시 그 객체를 this로 사용하게 한다. 그런 뒤 반환값이 `return this`가 되게 만든다.\n\n3번의 이유로 생성자 함수에서의 this가 새로 만들어진 this가 된다. 그래서 `this.name = name`과 같은 statement가 가능하다. 또한 4번의 결과로 반환된 this객체가 person2에 할당된다.\n\n## 프로토타입에서의 this\n\n`new`의 연장선이니 위에 주제가 이해 됐다면 조금은 편한 마음으로 보자.\n\n```js\nconst Person = function(name, age) {\n  this.name = name;\n  this.age = age;\n};\n\nPerson.prototype.getName = function() {\n  return this.name;\n};\n\nPerson.prototype.setFullName = function(FamilyName) {\n  const personName = this.getName();\n  this.fullName = personName + FamilyName;\n};\n\nconst person1 = new Person('Jin', 26);\n\n// #1\nconsole.log(person1.getName === Person.prototype.getName);\nconsole.log(person1.getName());\nconsole.log(Person.prototype.getName());\n\n// true\n// Jin\n// undefined\n\n// #2\nconsole.log(person1.setFullName === Person.prototype.setFullName);\n\nperson1.setFullName('Kang');\nPerson.prototype.setFullName('Kang');\n\nconsole.log(person1.fullName);\nconsole.log(Person.prototype.fullName);\n\n// true\n// JinKang\n// undefinedKang\n```\n\n다음은 프로토타입 패턴으로 객체의 메서드를 정의하였다.\n\n\\#1에서 person1로 실행한 것과 Person.prototype을 실행한 메서드는 동일하지만 결과 값이 다르다.\n\n[이전에 소개했던 포스팅](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/scope_this.md) 의 객체 this바인딩 원칙에 따라 각각 인스턴스, 프로토타입 객체가 this가 된다.\n\n\\#2에서도 역시 같은 원리로 this.getName()을 내부적으로 실행하지만 결과가 다르다. person1으로 실행한 것은 this.getName()이 `person1.getName()`이 되며, prototype은 `Person.prototype.getName()`이 된다.\n\n같은 코드의 내부의 this가 다르게 바인딩되는 dynamic scope 규칙처럼 작동하는 this 덕분에 프로토타입 패턴이 가능하게 되었고, 이는 자바스크립트에서도 OOP가 가능하게 만든 핵심이다.\n\nJS에서의 OOP 구현은 프로토타입이 굉장히 핵심적이고 중요하다. 하지만 dynamic scope를 지원하는듯한 this가 있어 인스턴스와 클래스의 개념을 비슷하게 만들 수 있게 되었다.\n\n## method chaining\n\n메서드 체이닝이란 객체에 연속적으로 메서드를 호출하는 패턴을 말한다.\n\n`myobj.method1('hello').method2().method3('world').method4();`\n\n이런식으로 체인할 수 있는 것을 말한다. 이러한 패턴은 가독성에 매우 큰 도움이 된다.\n\n현대 프로그래밍은 성능보다도 가독성이 훨씬, 정말 수십배는 중요하다. 프로그램에서 제일 중요한 것은 유지보수이며 유지보수에 도움을 주는 것은 성능만 좋은 엉망인 코드보다 성능이 조금 안좋더라도 가독성있는 코드다.\n\n이러한 가독성 좋은 메서드 체이닝은 어떻게 가능한 것일까? 바로 this다.\n\n### 기존의 함수방식\n\n[1, 2, 3, 4, 5]를 2배 곱하고 3씩 더하여 [5, 7, 9, 11, 13]로 만들어보자.\n\n```js\nconst arr = [1, 2, 3, 4, 5];\n\nfunction multi(arr, N) {\n  const newArr = [];\n\n  for (let i of arr) {\n    newArr.push(i * N);\n  }\n\n  return newArr;\n}\n\nfunction add(arr, N) {\n  const newArr = [];\n  for (let i of arr) {\n    newArr.push(i + N);\n  }\n\n  return newArr;\n}\n\nconsole.log(add(multi(arr, 2), 3)); // [5, 7, 9, 11, 13]\n```\n\npure function을 이용하여 의존성을 낮춘 코드지만 함수 호출부를 보자니 조금 지저분해진다.\n\n### 의존성 주입패턴\n\n```js\nfunction CustomArray(arr) {\n  this.arr = arr;\n}\n\nCustomArray.prototype.multi = function(N) {\n  const newArr = [];\n\n  for (let i of this.arr) {\n    newArr.push(i * N);\n  }\n\n  this.arr = newArr;\n};\n\nCustomArray.prototype.add = function(N) {\n  const newArr = [];\n\n  for (let i of this.arr) {\n    newArr.push(i + N);\n  }\n\n  this.arr = newArr;\n};\n\nconst arr = [1, 2, 3, 4, 5];\nconst customArray = new CustomArray(arr);\n\n// =================여기===================\ncustomArray.multi(2);\ncustomArray.add(3);\n// ====================================\n\nconsole.log(arr); // [1, 2, 3, 4, 5]\nconsole.log(customArray.arr); // [5, 7, 9, 11, 13]\n```\n\n프로토타입을 만들고 pure functionc처럼 의존성을 낮추기 위해 DI를 적용시켜 원본 배열 수정을 막았다.\n\n그런데도 문제는 `여기`라고 표시된 부분이 길어지면 한눈에 보기 힘들어 진단 점이다.\n\n### 메서드 체이닝 방식\n\n```js\nfunction CustomArray(arr) {\n  this.arr = arr;\n}\n\nCustomArray.prototype.multi = function(N) {\n  const newArr = [];\n\n  for (let i of this.arr) {\n    newArr.push(i * N);\n  }\n\n  this.arr = newArr;\n\n  return this;\n};\n\nCustomArray.prototype.add = function(N) {\n  const newArr = [];\n\n  for (let i of this.arr) {\n    newArr.push(i + N);\n  }\n\n  this.arr = newArr;\n\n  return this;\n};\n\nconst arr = [1, 2, 3, 4, 5];\nconst customArray = new CustomArray(arr);\n\ncustomArray.multi(2).add(3);\n\nconsole.log(customArray.arr);\n```\n\n위 코드에서 `return this`만 추가해주면 이렇게 메서드 체이닝이 구현된다. 그런데 이 경우도 조금 아쉬운 점은 메서드가 내부적으로 원본 데이터(this.arr)를 수정한다는 점이다.\n\n그래서 체이닝을 지원하는 map, filter, reduce, some, every 등의 메서드는 다음과 같은 방식으로 구현된다.\n\n```js\nfunction CustomArray(arr) {\n  this.arr = arr;\n}\n\nCustomArray.prototype.multi = function(N) {\n  const newArr = [];\n\n  for (let i of this.arr) {\n    newArr.push(i * N);\n  }\n\n  return new CustomArray(newArr);\n};\n\nCustomArray.prototype.add = function(N) {\n  const newArr = [];\n\n  for (let i of this.arr) {\n    newArr.push(i + N);\n  }\n\n  return new CustomArray(newArr);\n};\n\nconst arr = [1, 2, 3, 4, 5];\nconst customArray = new CustomArray(arr);\n\nconst resultArr = customArray.multi(2).add(3);\n\nconsole.log(resultArr.arr);\n```\n\n### 참고자료\n\n- [MDN-new](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/new)\n- [Jaehee's WebClub - Chaining Pattern of JavaScript](https://webclub.tistory.com/528)\n- [Understanding Method Chaining In Javascript](https://medium.com/backticks-tildes/understanding-method-chaining-in-javascript-647a9004bd4f)\n- [자바스크립트 메소드 체이닝패턴](http://blog.saltfactory.net/javascript-method-chaining-pattern/)\n- You Dont Know JS this와 객체 프로토타입, 비동기와 성능, 카일 심슨, 한빛미디어, 이일웅 옮김\n- [JavaScript : 프로토타입(prototype) 이해](http://www.nextree.co.kr/p7323/)\n- [Poiemaweb - 프로토타입](https://poiemaweb.com/js-prototype)\n"
  },
  {
    "path": "Javascript/Module.md",
    "content": "# Module\n\nJava나 Python 같은 OOP 언어들에서는 Class라는 이름으로 객체지향 프로그래밍을 구현한다. OOP의 특징으로는 *Encapsulation, Inheritance, Polymorphism*이 있다. \n\nJavascript의 Module은 OOP 언어에서의 Class와 비슷한 기능을 한다.\n\nJavascript에서는 scope를 기준으로 Encapsulation한다. 예전부터 Javascript는 scope를 이용해서 외부로부터 보호하려는 노력을 해왔다. ES5에서는 **함수가 scope의 기준**이기 때문에 함수의 scope를 이용해서 시도했다. 또한 클로져를 이용해서 내부 속성들을 만들어서 사용하였다.\n\n<br/>\n\n## Module이란?\n\nModule은 구현내용을 캡슐화하고 기능에 따라 Public API로 노출하여 다른 곳에서 쉽게 불러서 사용하며, 재사용이 가능하도록 한 코드뭉치이다.\n\n왜 Module이 필요하게 되었나?\n\n- **추상적인 코드** : 라이브러리에 기능을 위임하여 실제 구현의 복잡성을 이해할 필요가 없도록 하기 위해서\n- **코드 캡슐화** : 코드를 변경하지 못하도록 하며, Module 내부의 코드를 숨기기 위해서\n- **재사용 코드** : 같은 코드를 계속해서 사용하기 위해서\n- **의존성 관리** : 코드를 다시 작성하지 않고 종속성을 변경하기 위해서\n\n<br/>\n\n## Module patterns in ES5\n\nJavascript는 Module을 염두해두고 설계가 된 언어가 아니다. 시간이 지나면서 사람들이 필요에 따라 다양한 패턴을 만들었다.\n\n다양한 패턴의 시작지점인 **IIFE(즉시실행함수 표현식), 노출식(공개) 모듈 패턴**을 살펴보자.\n\n<br/>\n\n## IIFE(Immediately-invoked Function Expression)\n\nIIFE는 ES5 기준 가장 많이 사용되던 패턴 중 하나이다. `Scope Block` 을 만드는 유일한 방법은 함수를 사용하는 것이다. 따라서 아래와 같은 예제는 `ReferenceError` 가 나온다.\n\n```js\n(function() {\n  var scoped = 42;\n}());\n    \nconsole.log(scoped); // ReferenceError\n```\n\n![ReferenceError](![image](https://user-images.githubusercontent.com/24274424/63151836-5a31cb80-c045-11e9-8686-107cfc6b8dc4.png)\n\nIIFE는 오픈소스라이브러리에서 `Block scope`를 만드는데 사용된다. 아래 예제와 같이 사용하게 되면 공개하는 것과 아닌 것을 구분할 수 있게 된다.\n\n```js\nconst moduleFunction = (function () {\n  // private\n  let a = \"Hello World\";\n\n  function helloWorld(){\n    console.log(a);\n  }\n\n  // public\n  return {\n    sayHello: helloWorld\n  }\n})()\n\nmoduleFunction.sayHello();\n```\n\n함수를 바로 실행한 후 Object를 반환하여 전역 네임을 한번만 사용하여 scope를 오염시키지 않는다. 외부에서 내부로의 접근을 차단하여 보호한다.  \n\n**다만 의존성관리가 되지 않는다. 코드를 재작성하지 않으면 다른 파일에서 재사용이 불가능하다.**\n\n```js\n(function() {\n  console.log(\"I am not an IIFE yet!\");\n});\n```\n\n위의 코드는 함수를 괄호로 감쌌다. 이 함수식은 실행이 바로 되지 않아 즉시 실행 함수가 아니다. IIFE로 바꾸기 위한 2가지의 스타일을 변환이 있다.\n\n```js\n// Variation 1\n(function() {\n  console.log(\"I am an IIFE!\");\n}());\n\n// Variation 2\n(function() {\n  console.log(\"I am an IIFE, too!\");\n})();\n```\n\n1. Variation 1는 4행에서 호출을 위한 괄호를 안쪽에 넣었다. 다시 바깥 괄호는 함수 밖의 함수 표현식을 만든다.\n2. Variation 2는 마지막줄의 괄호는 함수 표현식을 호출하기 위한 괄호로 함수 밖에 위치하고 있다.\n\n두 가지 방법은 널리 사용된다. 후에 핵심부분을 공부하게 되면 2가지의 작동이 다르다는 것을 알 수 있다.\n\n작동하는 예제와 작동하지 않는 두 가지 예제를 살펴보자.\n\n```js\n// Valid IIFE\n(function initGameIIFE() {\n  console.log('valid')\n}());\n    \n// Following two are invalid IIFE examples\nfunction nonWorkingIIFE() {\n  console.log('invalid')\n}();\n    \nfunction () {\n  console.log('invalid')\n}();\n```\n\n위의 예제를 보게되면 왜 괄호가 필요한지 알 수 있다. **IIFE를 만들려면 표현식이 필요하다. 함수 선언, 함수 문장은 필요없다.**\n\n> [함수에 대해 더 알아보기](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/B_Function.md)\n\n<br/>\n\n## 노출식 모듈 패턴\n\n형태는 IIFE와 크게 다르지 않으며 반환값을 변수에 담으면 된다.\n\n```js\nconst singleton = (function moduleFunction() {\n  let a = 3;\n\n  function helloWorld() {\n    console.log('Hello');\n  }\n\n  return {\n    a: a,\n    sayHello: helloWorld\n  };\n})();\n\nsingleton.sayHello();\ndoSomething(singleton.a);\n```\n\nIIFE와 클로져를 같이 사용해서 구현을 해보았다. Module 패턴에 대한 기본적인 변형이다. 더 많은 패턴들이 존재하지만 거의 모든 패턴이 IIFE를 사용하여 폐쇄범위를 만든다.\n\n앞서 IIFE의 문제는 의존성 관리가 힘들다는 것이었다. 노출식 모듈패턴 역시 같은 문제가 있다.\n\n<br/>\n\n## NodeJs의 모듈화\n\n의존성 관리 문제 때문에 ES5에서는 AMD, UMD, CommonJS 와 같은 모듈 포맷을 사용했다. 각각에 대해서 알아보자.\n\n- Asynchronous Module Definition (AMD)\n- CommonJS\n- Universal Module Definition (UMD)\n- [추가] System.register\n\n<br/>\n\n### Asynchronous Module Definition (AMD)\n\nAMD 형식은 브라우저에서 사용되며 define를 사용하여 Module을 정의한다.\n\n```js\ndefine(['dep1', 'dep2'], function (dep1, dep2) {\n    \n  //Define the module value by returning a value.\n  return function () {};\n});\n\n```\n\n<br/>\n\n### CommonJS format\n\nCommonJS 형식은 Node.js에서 사용되며 `require` 과 `module.exports` 를 사용하여 종속성 및 Module을 정의한다.\n\n```js\nmodule.exports = {\n  sum: function() {\n    var total = 0;\n\n    for (var idx in arguments) {\n        total += arguments[idx];\n    }\n\n    return total;\n  }\n};\n\n// -------------------------\n\nvar math = require('./math');\n\nconsole.log(math.sum(1, 2));\n```\n\n내부적으로는 IIFE와 크게 다르지 않다. 내보낼 Module을 파라미터로 하여 IIFE를 실행시키고 반환하는 방식이다. 하지만 파일 외부에서 작성하고 불러온다는 점에서 좋아진 방식이다.\n\n<br/>\n\n### Universal Module Definition (UMD)\n\nUMD는 브라우저와 Node에서 모두 사용이 가능하다.\n\n```js\n(function (root, factory) {\n  if (typeof define === 'function' && define.amd) {\n    // AMD. Register as an anonymous module.\n    define(['b'], factory);\n  } else if (typeof module === 'object' && module.exports) {\n      // Node. Does not work with strict CommonJS, but\n      // only CommonJS-like environments that support module.exports,\n      // like Node.\n      module.exports = factory(require('b'));\n  } else {\n      // Browser globals (root is window)\n      root.returnExports = factory(root.b);\n  }\n}(this, function (b) {\n  return {};\n}));\n```\n\n<br/>\n\n### System.register\n\n`System.register` 형식은 ES5에서 ES6 모듈 구문을 지원하도록 설계되었다.\n\n```js\nimport { p as q } from './dep1';\n    \nconst s = 'test';\n    \nexport function func() {  \n    return q;\n}\n    \nexport class C {  \n}\n```\n\n<br/>\n\n## 모듈 제공의 방향과 ES6\n\nModule 제공 방식의 추세가 AMD vs CommonJS였다면, CommonJS와 ECMAScript Modules로 축약되는 것으로 보인다.\n\n하지만 여전히 일부 라이브러리가 AMD방식을 사용하고 있어 지금도 번들링은 UMD로 하고 있다.\n\nrequire과 import를 사용하여 모듈을 불러올 때 차이 중 하나는 `Tree-Shaking`을 할 때 알 수 있다.\n\nimport를 사용한 방식은 라이브러리의 특정 모듈만을 가져와 번들링할 수 있지만, require 방식으로 가져온 라이브러리는 모듈 전체를 번들링해야한다.\n\n**즉, require 방식으로 가져온 모듈에 대해서는 Tree-shaking을 진행할 수 없다.**\n\n<br/>\n\n## ES6 module format\n\nES6에서는 Module을 사용하기 위한 내장 문법을 지원한다. 바로 export다.\n\n```js\n// some.js\nexport function helloWorld() {\n  console.log('Hello');\n}\n\nfunction somePrivateFunction() {\n  // ...\n}\n\n// something.js\nimport { helloWorld as hello } from './some';\n// import * from './some' 도 가능하다.\n\nhello();\n```\n\n이렇게 하면 파일을 분리하고 그 파일에서 필요한 부분만 반환하여 사용할 수 있게 된다. 또한 재사용성이 극대화되어 의존성 관리도 가능하게 된다.\n\n또한 단일 값을 반환할 경우 `default` 형식을 지원한다. 이 경우 `{}`를 사용하지 않아도 된다.\n\n```js\n// Export default function\nexport default function sayHello(){\n  console.log('Hello');\n}\n\n// Export non-default function\nfunction sayGoodbye(){\n  console.log('Goodbye');\n}\n\nconst apiUrl = '...';\n\nreturnObject = {\n    goodbye : sayGoodbye,\n    apiUrl : apiUrl\n}\nexport returnObject;\n\n// Export object\nexport const settings = {\n  debug: true\n}\n\nimport sayHello, { returnObject, settings } from './lib';\n\nsayHello();\nreturnObject.sayGoodBye();\n```\n\n~~아직 브라우저는 ES6문법을 지원하지 않는다. ES6 모듈 포맷을 사용할 수 있지만 브라우저에서 코드를 실제로 실행하기 전에 코드를 **AMD** 나 **CommonJS** 와 같은 **ES5 모듈 형식으로 바꾸기 위해 Babel과 같은 변환기가 필요하게 된다.**~~\n\n이전에는 브라우저가 이것을 지원하지 않아 bundler나 transpiler를 사용해서 ES6 모듈을 사용했었다.\n\n### 브라우저에서 사용\n\n이 버전들부터는 브라우저가 ES6 모듈을 사용할 수 있다.\n\n- Chrome 61 이상\n- Firefox 60 이상\n- Edge 16 이상\n- Safari 11 이상\n\n> 관련 링크 [ES6 Module in Browser](https://github.com/Im-D/Dev-Docs/blob/master/ECMAScript/ES6-module-in-Browser.md#es6-modules)\n\n<br/>\n\n## Module loaders\n\n모듈 로더는 특정 모듈 형식으로 작성된 모듈을 해석하고 load한다.\n\n런타임 시점에 loader를 실행한다.\n\n- 브라우저에서 모듈 로더를 로드한다.\n- 모듈로더에게 어느 파일을 로드할 것인지 알려준다.\n- 모듈로더가 주파일을 다운로드해서 해석한다.\n- 필요한 경우에는 모듈 로더가 파일을 다운로드한다.\n\n널리 사용되는 모듈 로더는 아래와 같이 있다.\n\n- RequireJS : AMD 형식의 모듈용 로더\n- SystemJS : AMD, CommonJS, UMD 또는 System.register 형식의 모듈용 로더\n\n<br/>\n\n## Module bundlers\n\n모듈 번들러는 모듈 로더를 대체한다. 그러나 로더와 차이점은 모듈 번들은 빌드시에 실행이 된다.\n\n- 빌드를 할 때 모듈 번들을 실행하여 번들파일을 생성한다.\n- 브라우저에서 번들을 로드한다.\n\n널리 사용되는 모듈 번들러는 아래와 같이 있다.\n\n- Browserify : CommonJS 모듈용 bundler\n- Webpack : AMD, CommonJS, ES6 모듈용 bundler\n\n<br/>\n\n---\n\n#### Reference\n\n- [B_Module](https://github.com/Im-D/Dev-Docs/edit/master/Deprecated/B_Module.md)\n- [Module](https://github.com/Im-D/Dev-Docs/blob/master/Deprecated/Module.md)\n- [AMD와 CommonJS](https://github.com/Im-D/Dev-Docs/blob/master/Deprecated/AMD%EC%99%80%20CommonJS.md)\n- [Essential JavaScript: Mastering Immediately-invoked Function Expressions](https://medium.com/@vvkchandra/essential-javascript-mastering-immediately-invoked-function-expressions-67791338ddc6)\n- [Do ES6 Modules make the case of IIFEs obsolete?](https://hashnode.com/post/do-es6-modules-make-the-case-of-iifes-obsolete-civ96wet80scqgc538un20es0)\n- [JavaScript Modules: A Beginner’s Guide](https://medium.freecodecamp.org/javascript-modules-a-beginner-s-guide-783f7d7a5fcc)\n- [ES6 modules, Node.js and the Michael Jackson Solution](https://medium.com/dailyjs/es6-modules-node-js-and-the-michael-jackson-solution-828dc244b8b)\n- [A 10 minute primer to JavaScript modules, module formats, module loaders and module bundlers](https://www.jvandemo.com/a-10-minute-primer-to-javascript-modules-module-formats-module-loaders-and-module-bundlers/)\n- [JavaScript Modules: A Beginner’s Guide](https://medium.freecodecamp.org/javascript-modules-a-beginner-s-guide-783f7d7a5fcc)\n"
  },
  {
    "path": "Javascript/MouseEvent.md",
    "content": "# Mouse Event\n\n오늘은 약간 심플하면서도 약간 헷갈릴만한 주제로 해보려고한다.\n<br/>\n\n바로 `Mouse Event`\n<br/>\n\n오늘 작업을 하다보니 내가 평소에 알고 있던 마우스 이벤트들인데 왜 이렇게 어렵지라고 생각되는 것이 있어서 정리를 하면서 다시 학습해보려고 한다.\n<br/>\n\n기본적으로 내가 알고 있는 마우스 이벤트는 4가지였다.\n<br/>\n\n- mousedown : 마우스 누른 상태\n- mousemove : 해당 Element 위에서 움직이는 상태\n- mouseup : 마우스 떼는 상태\n- click : mousedown와 mouseup이 한번 일어난 상태\n\n위의 4가지의 상태는 우리가 흔히 사용하는 마우스 이벤트이다. 그리고 지금 어디선가 누군가도 이것을 사용하고 있을 것이다.\n<br/>\n\n간단한 예제를 만들어 보자면\n<br/>\n\n```html\n<html>\n    <head></head>\n    <body>\n        <div style=\"\n            width:  100px;\n            height:  100px;\n            background-color: black;\n        \">\n        black\n        </div>\n    </body>\n</html>\n```\n\n간단한 검은색 Div를 만들어서 이 Element에 이벤트를 입힌다.\n\n```js\nvar div = document.getElementsByTagName(\"div\")\n\n// MouseDown\ndiv[0].addEventListener(\"mousedown\", function(){\n    console.log(\"mousedown\")\n})\n\n// MouseMove\ndiv[0].addEventListener(\"mousemove\", function(){\n    console.log(\"mousemove\")\n})\n\n// MouseUp\ndiv[0].addEventListener(\"mouseup\", function(){\n    console.log(\"mouseup\")\n})\n\n// Click\ndiv[0].addEventListener(\"click\", function(){\n    console.log(\"click\")\n})\n```\n\n예제를 만들어보고 한번 움직이고, 클릭하고 해보자 그러면 더욱 이해가 잘 될 것이다.\n\n자 이제 제일 기본이 되는 이벤트를 알아 보았다. 이제는 헷갈렸던 작업으로 가보자\n<br/>\n\n## MouseOver MouseOut\n\n알고는 있었지만 추가적으로 알았다고 하자.\n\n- mouseover : 마우스를 `Element` 위에 올린 상태\n- mouseout : 마우스를 `Element` 위에 올린 상태에서 벗어난 상태\n\n쉽게 보자면 내가 이벤트를 선언한 `Element` 위에 마우스를 위치하나 빼냐에 대한 이벤트이다.\n<br/>\n\n이번에는 다른 이벤트를 보자\n<br/>\n\n## MouseEnter MouseLeave\n\n- mouseleave : 마우스를 `Element` 위에 올린 상태\n- mouseenter : 마우스를 `Element` 위에 올린 상태에서 벗어난 상태\n\n이상하다. 위에서의 2개의 이벤트 아래의 이벤트들과 똑같은데? 왜 때문에 같은 기능을 가진 이벤트가 2개씩 있는 것일까?\n<br/>\n\n> 이거 때문에 한동안 헤맸다.\n\n## MouseOver MouseOut VS MouseEnter MouseLeave\n\n2종류의 이벤트는 같은 기능을 하는 것처럼 보이지만 약간의 다른 차이점이 존재한다.\n<br/>\n\n먼저 예제를 보자 => [예제보기](https://codepen.io/seonhyungjo/pen/wRwWXO)\n<br/>\n\n2겹의 `Div` 가 존재한다. 그리고 `Outer div` 에 각각 `MouseOver` 와 `MouseEnter` 이벤트를 추가했다. 그리고 `Inner Div` 에는 이벤트를 추가하지 않았다.\n<br/>\n\n결과는 신기하게도 `MouseOver` 이벤트는 자식 `Element`까지 이벤트가 적용이 되었다.\n<br/>\n\n결과적으로 `MouseOver MouseOut` 이벤트들은 `Bubble`과 `Capture` 일어나며 다르게 `MouseEnter MouseLeave` 이벤트들은 전파가 되지 않고 선언한 곳에서만 일어나는 것을 확인할 수 있다.\n<br/>\n\n관련글을 읽는 것도 도움이 된다. [Event Delegation](https://github.com/SeonHyungJo/FrontEnd-Dev/blob/master/Javascript/Event%20Delegation.md)\n<br/>\n\n이 사실은 너무나도 중요하다. 내가 원하는 위치에 `MouseOver` 이벤트를 먹였는데 이상하게 내가 선언하지 않은 곳의 위치에서 작동이 일어나고 있다는 것이 아닌가? \n<br/>\n\n이것은 정말 크리티컬한 이슈가 될 수 있는 것이다.\n<br/>\n\n그렇다면 이것을 해결할 수 있는 방법이 있지 않을까?\n당연하게 있다. 그리고 사람들은 이미 알고 있다. \n<br/>\n\n---\n\n#### Reference \n\n- http://webclub.tistory.com/116\n- http://webclub.tistory.com/456\n- [MDN - MouseEnter](https://developer.mozilla.org/en-US/docs/Web/Events/mouseenter)\n- [MDN - preventDefault](https://developer.mozilla.org/ko/docs/Web/API/Event/preventDefault)\n- [MDN - stopPropagation](https://developer.mozilla.org/ko/docs/Web/API/Event/stopPropagation)"
  },
  {
    "path": "Javascript/Object.create&Object.assign.md",
    "content": "# Object.create() & Object.assign()\n\n## Object.create()\n\n```js\nObject.create(prototype_object, propertiesObject)\n```\n\n`Object.create()`는 기준이 되는 Object를 prototype으로 만들고 **새로운 객체를 생성**한다.\n\n`Object.create()`는 주로 객체를 상속하기 위해 사용하는 메서드다. 첫 번째 인자를 상속하며, 두 번째 인자의 속성들을 추가로 구성한다.\n\n<br/>\n\n### 두번째 인자 - 속성의 구성요소\n\n공통의 구성요소는\n\n1. **`configurable`** 속성의 값을 변경할 수 있고, 삭제할 수도 있다면 `true`로 설정한다. 기본값은 `false`.\n2. **`enumerable`** 속성이 대상 객체의 속성 열거 시 노출이 되게 하려면 `true`로 설정한다. 기본값은 `false`.\n\n데이터 서술을 하는 데 사용되는 키는\n\n1. **`value`** 속성값. 아무 JavaScript 값(숫자, 객체, 함수 등)이나 가능하다. 기본값은 `undefined`\n2. **`writable`** 할당 연산자로 속성의 값을 바꿀 수 있다면 `true`로 설정한다. 기본값은 `false`.\n\n접근자 서술을 하는 데 사용되는 키는\n\n1. **`get`** 속성 접근자로 사용할 함수, 접근자가 없다면 `undefined`. \n   - 속성에 접근하면 이 함수를 매개변수 없이 호출하고, 반환 값이 속성의 값이 된다. 이때 `this` 값은 이 속성을 가진 객체이다. 기본값은 `undefined`.\n2. **`set`** 속성 설정자로 사용할 함수, 설정자가 없다면 `undefined`. \n   - 속성에 값을 할당하면 이 함수를 하나의 매개변수로 호출한다. 이때 `this` 값은 이 속성을 가진 객체이다. 기본값은 `undefined`.\n\n**`Object.create()`의 2번째 인자는 `Object.defineProperties()`를 따른다.**\n\n<br/>\n\n---\n\n위의 구성요소는 이전에 사용하던 `Object.defineProperties()`에서 나오는 개념이다. 그 전에 `Object.defineProperties()`의 단일 설정 함수인 `Object.defineProperty()`를 살펴보자\n\n<br/>\n\n### Object.defineProperty()\n\n`Object.defineProperty()`는 객체에 직접 새로운 속성을 정의하거나 이미 존재하는 속성을 수정한 후, **그 객체를 반환한다.**\n\n```js\nObject.defineProperty(obj, prop, descriptor)\n```\n\n- **`obj`** : 속성을 정의할 객체.\n- **`prop`** : 새로 정의하거나 수정하려는 속성의 이름 또는 `Symbol`.\n- **`descriptor`** : 새로 정의하거나 수정하려는 속성을 기술하는 객체.\n\n아래의 예제는 자세히 보아야 한다. 여러 개념이 들어가 있는 예제이다.\n\n```js\nconst obj = {\n  age: 27, \n  country : 'seoul'\n}\nlet oldCountry = 'Yongin'\n\nconsole.log('init str', obj) // init str {age: 27, country: \"seoul\"}\n\nconst descriptor = {\n  enumerable: true,\n  configurable: true,\n  get: function(){\n    return '???'\n  },\n  set: function(value){\n    oldCountry = value\n  }\n}\n\nconst newObj = Object.defineProperty(obj, 'country', descriptor) // 기존의 속성에서 새로운 속성을 정의\nconsole.log('obj values => ',obj, obj.age, obj.country) // obj values =>  {age: 27} 27 ???\nconsole.log('newObj values => ',newObj, newObj.age, newObj.country) // newObj values =>  {age: 27} 27 ???\nconsole.log('oldCountry => ', oldCountry) // oldCountry =>  Yongin\n\nnewObj.age = 28\nnewObj.name = 'sNyung'\nnewObj.country = 'Re Seoul'\nconsole.log('After newObj && obj values are => ', obj, obj.age, obj.country) // After newObj && obj values are =>  {age: 28, name: \"sNyung\"} 28 ???\nconsole.log('oldCountry => ', oldCountry) // oldCountry =>  Re Seoul\n```\n\n<br/>\n\n### Object.defineProperties()\n\n```js\nObject.defineProperties(obj, props)\n```\n\n`Object.defineProperty()`의 복수 버전이다.\n\n```js\nObject.defineProperties(obj, {\n  'property1': {\n    value: true,\n    writable: true\n  },\n  'property2': {\n    value: 'Hello',\n    writable: false\n  }\n});\n```\n---\n\n### Object.create() - Sample 1\n\n```js\nconst prototypeObject = {\n  fullName: function(){\n    return this.firstName + \" \" + this.lastName\t\t\n  }\n}\n\nconst person = Object.create(prototypeObject, {\n  'firstName': {\n    value: \"sNyung\", \n    writable: true, \n    enumerable: true\n  },\n  'lastName': {\n    value: \"jo\",\n    writable: true,\n    enumerable: true\n  }\n})\n    \nconsole.log(person) // {firstName: \"sNyung\", lastName: \"jo\"}\n```\n\n![image](https://user-images.githubusercontent.com/24274424/59965008-b7c50280-9543-11e9-805e-4fcc55430d0e.png)\n\n<br/>\n\n### New VS Object.create()\n\n`Object.create()`와 `new Constructor()`는 꽤 비슷하지만, 다른 점이 있다. 다음은 이 둘의 차이를 보여주는 예제이다.\n\n```js\nfunction Dog(){\n  this.pupper = 'Pupper';\n};\nDog.prototype.pupperino = 'Pups.';\n\nconst maddie = new Dog();\nconst buddy = Object.create(Dog.prototype);\n\n// Object.create()\nconsole.log(buddy.pupper); // undefined\nconsole.log(buddy.pupperino); // Pups.\n\n// New\nconsole.log(maddie.pupper); // Pupper\nconsole.log(maddie.pupperino); // Pups.\n```\n\n성능상으로 new 생성자를 사용하는 것이 좋다고 한다. 아래와 같이 성능 테스트를 해보면 왜 new 생성자를 사용하는 것이 더 좋은지 알 수 있다.\n<br/>\n\n### 성능 테스트\n\n[https://jsperf.com/snyung-new-vs-object-create](https://jsperf.com/snyung-new-vs-object-create)\n\n```js\nfunction Obj() {\n  this.p = 1;\n}\n\nObj.prototype.chageP = function(){\n  this.p = 2\n};\n\nconsole.time('Object.create()');\nvar obj;\nfor (let i = 0; i < 10000; i++) {\n  obj = Object.create(propObj);\n}\nconsole.timeEnd('Object.create()');\n// Object.create(): 약 12.994140625ms\n\nconsole.time('constructor function');\nvar obj2;\nfor (let i = 0; i < 10000; i++) {\n  obj2 = new Obj();\n}\nconsole.timeEnd('constructor function');\n// new: 약 2.379150390625ms\n```\n\n<br/>\n\n### Polyfill\n\n```js\nObject.create = (function () {\n  function obj() {};\n\n  return function (prototype, propertiesObject) {\n    // 첫 번째 인자를 상속하게 한다.\n    obj.prototype = prototype || {};\n\n    if (propertiesObject) {\n      // 두 번째 인자를 통해 속성을 정의한다.\n      Object.defineProperties(obj.prototype, propertiesObject);\n    }\n\n    return new obj();\n  };\n})();\n\n//--------------TEST---------------\n\nconst Vehicle = function(){\n  this.wheel = 4\n}\n\nVehicle.prototype.getWheel = function() {\n  return this.wheel\n}\n\nconst Motorcycle = Object.create(Vehicle.prototype, {'wheel': {value: 3, writable: true}});\nconsole.log(Motorcycle)\n```\n\n<br/>\n\n### Compat Table\n\n![image](https://user-images.githubusercontent.com/24274424/59957350-70525e00-94d2-11e9-97ea-a483763149d1.png)\n\n<br/>\n\n## Object.assign()\n\n`Object.assign()` 메서드는 열거할 수 있는 하나 이상의 출처 객체로부터 대상 객체로 속성을 복사할 때 사용한다. 대상 객체를 반환한다.\n\n- **`target`** : 대상 객체.\n- **`sources`** : 하나 이상의 출처 객체.\n\n```js\nconst obj = { a: 1 };\nconst copy = Object.assign({}, obj);\n\nconsole.log(copy); // { a: 1 }\n```\n\n`Object.assign()`은 첫 번째 인자로 들어오는 target을 대상으로 두 번째 이후로 들어오는 인자를 병합할 때 사용한다. \n<br/>\n\n### 예시\n\n같은 properties가 들어올 경우 마지막에 들어온 값이 덮어쓰게 된다.\n\n```js\n// app.js\n\nlet o1 = { a: 21, b: 22, c: 24 };\nlet o2 = { b: 23, c: 25 };\nlet o3 = { c: 26 };\n\nlet finalObj = Object.assign({}, o1, o2, o3);\nconsole.log(finalObj); // {a: 21, b: 23, c: 26}\n```\n\n그러나 안타깝게도 `Object.assign()`는 ES6 문법의 Spread Operator가 나오면서 관심이 많이 줄어들게 되었다.\n같은 기능을 포함하고 있는 ES6 문법의 Spread는 숙련도에 따라 다양하게 사용될 수 있다.\n\n가장 많이 사용되는 기능 3가지를 포함하고 있는 예시를 보게 되면,\n\n```js\n// Create Function with REST\nconst add = function(...arg){\n  console.log('arg', arg)\n  arg.map(e => console.log(e))\n}\n\n// Create Object\nconst obj = { a : 1, b : 2, c: 3, d: 4}\n// Create Arr + Spread\nconst arr = ['a', ...Object.values(obj), 'b', 'c']\nconsole.log(...arr)\nadd(...arr)\n\nconst {a,b, ...rest} = obj\nconsole.log(a, b, rest)\n```\n\n위와 같이 `...`은 사용 방법에 따라 다양하게 사용될 수 있다. 더 많은 기능을 찾아보기를 바란다.\n<br/>\n\n### Polyfill\n\n```js\nObject.defineProperty(Object, \"assign\", {\n  value: function assign(target, varArgs) { // .length of function is 2\n    'use strict';\n    if (target == null) { // TypeError if undefined or null\n      throw new TypeError('Cannot convert undefined or null to object');\n    }\n\n    var to = Object(target);\n\n    for (var index = 1; index < arguments.length; index++) {\n      var nextSource = arguments[index];\n\n      if (nextSource != null) { // Skip over if undefined or null\n        for (var nextKey in nextSource) {\n          // Avoid bugs when hasOwnProperty is shadowed\n          if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {\n            to[nextKey] = nextSource[nextKey];\n          }\n        }\n      }\n    }\n    return to;\n  },\n  writable: true,\n  configurable: true\n});\n```\n\n<br/>\n\n### Compat Table\n\n![image](https://user-images.githubusercontent.com/24274424/59957367-9ed03900-94d2-11e9-80af-cfcad4784f78.png)\n\n<br/>\n\n#### Reference\n\n- [Object.create() - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create)\n- [Object.create in JavaScript](https://hackernoon.com/object-create-in-javascript-fa8674df6ed2)\n- [Object.create(): the New Way to Create Objects in JavaScript](https://www.htmlgoodies.com/beyond/javascript/object.create-the-new-way-to-create-objects-in-javascript.html)\n- [Basic Inheritance with Object.create](http://adripofjavascript.com/blog/drips/basic-inheritance-with-object-create.html)\n- [Understanding the difference between Object.create() and the new operator.](https://medium.com/@jonathanvox01/understanding-the-difference-between-object-create-and-the-new-operator-b2a2f4749358)\n- [JavaScript Object Creation: Patterns and Best Practices](https://www.sitepoint.com/javascript-object-creation-patterns-best-practises/)\n- [object-create.md - wonism](https://github.com/wonism/TIL/blob/master/front-end/javascript/object-create.md)\n- [Object.assign() = MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)\n"
  },
  {
    "path": "Javascript/Observer.md",
    "content": "# Observer\n\n<br/>\n\n## 옵저버 패턴(Observer Pattern)\n\n옵저버 패턴은 데이터를 기반으로 하는 인터페이스가 데이터의 변화를 감시하는 구조를 말한다. 특정 이벤트가 일어나고 해당 이벤트에 의해 특정 데이터가 변경되었다고 가정해보자. 해당 데이터와 관련된 모든 요소는 자동으로 변경이 되어야 한다. \n\n즉, 옵저버 패턴은 데이터를 보유한 주체를 여러 객체들이 감시하면서 데이터가 변화했을 때 각 객체에서 이를 감시하다가 알아서 각 객체들이 할 일을 각자 수행하는 구조다.\n\n예시는 [다음](https://github.com/Im-D/Dev-Docs/blob/master/Language/Reactive.md#async)으로 대체한다.\n\n자바스크립트에서는 옵저버 패턴을 이용한 API가 크게 5가지 제공된다.\n\n- Mutation Observer\n- Intersection Observer\n- Resize Observer\n- Performance Observer\n- Reporting Observer\n\n그렇다면 이제 각각을 살펴보도록 하자.\n\n<br/>\n\n## Mutation Observer\n\n`Mutation Observer`을 가장 먼저 소개하는 이유는 다른 `Observer`들에 비해 가장 활용도가 높기 때문이다.\n\n`Mutation Observer`는 객체의 속성 변화를 감지하며 객체의 속성이 변화될 때마다 특정 행위를 수행하도록 한다.\n\n```js\nlet mo = new MutationObserver((mutations, thisMo) => {\n  mutations.forEach(mutation => {\n    // 개별 변형 대응\n  });\n});\n\nlet target = document.querySelector(\"body\");\nlet options = {\n childList: true,\n attributes: true,\n subtree: true,\n characterData: true\n};\n \nmo.observe(target, options);\n```\n\n### MutationObserverInit\n\n- childList : 타겟 노드의 자식 엘레멘트(텍스트 노드를 포함)들의 추가 혹은 제거를 관찰해야할 때 true (default: false)\n- attributes : 타겟 노드의 속성들의 변형들을 관찰해야할 때 true (default: false)\n- characterData : 타겟 노드의 데이터를 관찰해야할 때 true (default: none)\n- subtree : 타겟 노드부터 자손 노드들의 변형들까지 관찰해야할 때 true (default: false)\n- attributeOldValue : attributes이 true면서 타겟 노드의 변경된 속성들 이전 값을 기록해야할 때 true (default: none)\n- characterDataOldValue : characterData true면서 타겟 노드의 변경된 데이터 이전 값을 기록해야할 때 true (default: none)\n- attributeFilter : 모든 속성들을 관찰하고 싶지않을 때 관찰할 속성명의 Array (default: none)\n\n**최소한 `childList`, `attributes`, `characterData` 중 하나가 `true`여야 한다. 그렇지 않으면 `TypeError`가 발생한다.**\n\n- [MutationObserver 예시](https://codepen.io/seonhyungjo/pen/pQqOpv)\n\n<br/>\n\n## Intersection Observer\n\n`Intersection Observer`는 용어 뜻 그대로 그대로 특정 DOM 객체가 우리가 보는 화면 영역(viewport)과 교차 되는 것을 감시한다.\n\n이를 이용해서 우리는 `scroll event`를 쓰지 않고 `Lazy Loading`을 구현할 수 있다. 예를 들어, 우리가 스크롤이 특정 위치에 도착했을 때 이벤트를 일으켜 해당 부분의 데이터를 가져와 볼 수 있다면 어떨까? 그렇다면 초기에 모든 데이터를 가져올 필요가 없기 때문에 초기 로딩 속도를 높일 수 있다.\n\n뿐만 아니라 `threshold` 옵션을 이용해여 관측 대상에 대한 전체 상자 영역(루트)에 대한 교차 영역의 비율을 지정하고 교차하는 부분이 명시한만큼 보이면 작동하도록 할 수도 있다.\n\n- [IntersectionObserver 예시](https://codepen.io/seonhyungjo/pen/wQQYdz)\n\n<br/>\n\n## Resize Observer\n\n`Resize Observer` 또한 용어 그대로의 역할을 수행한다. DOM 객체의 크기 변화를 감시한다.\n\n예를 들어, viewport의 크기 변화에 따라 다른 크기의 이미지를 보여줘야 한다고 해보자. 이 때 viewport의 크기에 따라 콜백 함수를 활용하여 해당 이미지를 로드해서 보여주면 된다. 다만, 이는 최신 크롬 환경에서만 동작하기 떄문에 polyfill을 이용하여 구현해야한다.\n\n- [ResizeObserver 예시](https://alligator.io/js/resize-observer/#simple-demo)\n\n<br/>\n\n## Performance Observer\n\n`Performance Observer`는 FCP(First Contentful Paint), FMP(First Meaningful Paint) 등을 측정할 수 있게 해준다.\n\n- FCP: 텍스트나 이미지가 출력되기 시작하는 순간이다.\n- FMP: 사용자에게 의미 있는 콘텐츠가 그려지기 시작하는 첫 순간이다. 콘텐츠를 노출하는데 필요한 CSS, 자바스크립트 로드가 시작되고 스타일이 적용되어 주요 콘텐츠를 읽을 수 있다.\n\n단, 해당 옵저버는 최신 기능이다보니 polyfill도 완벽하게 적용되어있지 않다. 또 다른 퍼포먼스 측정 툴에는 [Perfume.js](https://github.com/Zizzamia/perfume.js)가 있다.\n\n<br/>\n\n## Reporting Observer\n\n`Reporting Observer`는 실험적인 기능이다보니 사실상 지원하는 브라우저가 거의 없다.\n\n`Reporting Observer`는 사용자의 window 객체를 조회해서 정책적으로 너무 오래된 메서드가 쓰이면 경고를 주는 기능을 한다.\n\n- [MDN Docs - Reporting Observer](https://developer.mozilla.org/en-US/docs/Web/API/ReportingObserver)\n\n<br/>\n\n---\n\n#### Reference\n\n- [Huskyhoochu 기술 블로그 - JS: The Observers](https://www.huskyhoochu.com/js-observers/)\n- [alligator.io - resize observer](https://alligator.io/js/resize-observer/#simple-demo)\n- [레진 기술블로그 - intersection observer](https://tech.lezhin.com/2017/07/13/intersectionobserver-overview)\n- [Toast UI FE Guide - 성능 최적화](https://ui.toast.com/fe-guide/ko_PERFORMANCE/)\n"
  },
  {
    "path": "Javascript/Optional_Chaining.md",
    "content": "# Optional Chaining\n\n## 소개\n\n이 내용은 아직 공식 스펙으로 채택하지 않았다. 다만 추후 추가될만한 소지가 있으며 충분히 매력적이므로 소개해본다.\n\n조건적으로 체이닝을 할 수 있다. 이게 무슨 소릴까? 무슨 조건을 이야기 하는 것일까?\n\n바로 undefined나 null의 경우 선택적으로 체이닝 할 수 있게하는 문법이다. javascript 뿐만아니라 C#, Swift, CoffeeScript 에서도 지원하는 문법이다.\n\n## 기존의 방식\n\n```js\nvar person = {\n  name: {}\n};\nvar certif = person.spec.certification;\nconsole.log(certif); // Cannot read property 'certification' of undefined\n```\n\n이런 에러를 받아보는 경우가 상당하다. 보통 object 형식에서 데이터를 받아 온 뒤 그 데이터를 사용해야하는 경우인데, 아직 받아오지 않은 상태에서 작업을 해야하는 경우다.\n\n그래서 보통은 몇 가지 방법으로 방어적인 코드를 사용한다.\n\n```js\nvar person = {\n  name: 'tom'\n};\n\nvar certif = '';\n\n// 1번\nif (person.hasOwnProperty('spec')) {\n  certif = person.spec.certification;\n}\n\n// 2번\nif (!!person.spec) {\n  certif = person.spec.certification;\n}\n\n// 3번\ntry {\n  certif = person.spec.certification;\n} catch (e) {\n  certif = '';\n}\nconsole.log(certif); // ''\n```\n\n나는 개인적으로 3가지 방식 모두 자주 사용하고 있었다.\n\n혹은 `user.name && user.name.lastName` 처럼 null을 체크하는 방식들도 자주 보인다.\n\n그런데 이러한 방식들은 코드의 가독성을 해친다. 또한 자료구조가 조금 복잡해진다면 엄청나게 중요한 코드가 아님에도 생산성이 저하될 수 있다.\n\n## 새로운 방식\n\n방법은 매우 너무나도 간단하다.\n\n```js\nvar person = {\n  name: {}\n};\nvar certif = person?.spec?.certification;\nconsole.log(certif);\n```\n\n. 앞에 ? 를 추가해주면 끝이다.\n\nnull이나 undefined가 아니라면 그냥 실행하는 방식이다.\n\n```js\nconst obj = {\n  foo: {\n    bar: {\n      baz: 100\n    }\n  }\n};\n\nconst baz = obj?.foo?.bar?.baz; // 100\nconst baz = obj && obj.foo && obj.foo.bar && obj.foo.bar.baz;\n```\n\n이는 babel 공식문서의 소개글의 예시다. 충분히 더 복잡한 자료구조와 씨름할 수 있는 상황이 많다. 따라서 이 문법을 사용한다면 얼마나 편한지 안보고도 알 수 있을 것 같다.\n\n## 한계\n\n현재 babel의 Stage 1에 머물러 있다.\n\n- optional construction: new a?.()\n- optional template literal: a?.`{b}`\n- constructor or template literals in/after an Optional Chain: new a?.b(), a?.b`{c}`\n- optional property assignment: a?.b = c\n\n이러한 이유들 때문이다. 사용 케이스가 있긴 하지만 아직 불안정하기 때문에 지원하지 않는다고 한다.\n\n---\n\n### 참고자료\n\n- [Optional Chaining for JavaScript](https://github.com/tc39/proposal-optional-chaining)\n- [@babel/plugin-proposal-optional-chaining](https://babeljs.io/docs/en/next/babel-plugin-proposal-optional-chaining.html)\n- [Javascript Optional Chaining](https://dev-momo.tistory.com/entry/Javascript-Optional-Chaining)\n- [Optional Chaining Operator in JavaScript](https://www.youtube.com/watch?v=FKRVqtP8o48)\n- [9 Tricks for Kickass JavaScript Developers in 2019](https://levelup.gitconnected.com/9-tricks-for-kickass-javascript-developers-in-2019-eb01dd3def2a?gi=4624a912a47f)\n"
  },
  {
    "path": "Javascript/PromisePattern.md",
    "content": "# 프로미스 패턴\n\n두개 이상의 프로미스를 사용한 비동기 흐름을 제어할 때 사용한다. 예를들어 a 와 b 라는 비동기 작업이 모두 완료되면 c 라는 비동기 작업을 진행해야 한다고 하면 이 경우 어떻게 해야할까를 정의한 것이 프로미스 패턴이다.\n\n## All 과 Race\n\n### Promise.all([])\n\n---\n\n관문패턴이다. 프로세스를 모두 나중으로 미뤄 모두 준비가 되면 시작한다.\n\n```js\n// request는 promise 패턴의 비동기 사용자 정의 함수라고 가정\nvar p1 = request('https://');\nvar p2 = request('https://');\n\nPromise.all([p1, p2])\n  .then(function(value) {\n    return request('http://');\n  })\n  .then(function(msg) {\n    console.log(msg);\n  });\n```\n\n이 배열 안의 값은 promise, thenable, 즉시값 모두 가능하다. 현재는 비동기 처리 후 프로미스가 들어간다. 다만 어떠한 값이 들어가도 상관없다. 그 이유는 Promise.resolve()로 정규화를 하기 때문이다.\n\n여기서 중요한 점은 배열안의 값이 버림처리되면(reject) 모든 결과가 무효처리 되어 버린다. 그렇기 때문에 꼭 에러 처리기를 붙이도록 하자.\n\n### Promise.race([])\n\n---\n\n걸쇠 혹은 경합이라고 불리는 패턴이다. 먼저 온 것만 실행된다. 배열 안의 값은 어떤것이 들어가도 상관없다. 즉시값이 들어가도 되지만 즉시값은 순서가 1 순위라 의미가 없다.\n\n사용법은 all 과 동일하다.\n\n### 타임아웃 경합\n\n---\n\n경합 패턴을 사용하면 타임아웃 패턴을 구현할 수 있다.\n\n```js\nfunction timeoutPromise(time) {\n  return new Promise(function(resolve, reject) {\n    setTimeout(function() {\n      reject('타임아웃');\n    }, time);\n  });\n}\n\nPromise.race(foo, timeoutPromise(3000)).then(\n  function() {\n    //\n  },\n  function(err) {\n    // err\n  }\n);\n```\n"
  },
  {
    "path": "Javascript/Prototype_Chain.md",
    "content": "## 프로토타입 체인\n\n특정 객체의 메서드나 프로퍼티에 접근하고자할 때, **해당 객체에 접근하려고 하는 프로퍼티나 객체가 없다면** 프로토타입 링크(`[[Prototype]]` 프로퍼티)를 따라 **자신의 부모 역할을 하는 프로토타입 객체를 차례로 검색**한다. 이를 프로토타입 체인이라 한다.\n\n```javascript\nvar developer = {\n    name : 'BKJang',\n    age : 25,\n    sex : 'male'\n};\n\nconsole.log(developer.hasOwnProperty('name')); //true\nconsole.log(developer.__proto__ === Object.prototype); //true\nconsole.log(Object.prototype.hasOwnProperty('hasOwnProperty')); //true\n```\n\n`developer`객체에는 `hasOwnProperty()`메서드가 존재하지 않지만 에러가 나지 않는다. \n이는 `developer` 객체의 **부모 객체에 해당하는 `Object.prototype`의 메서드를 검색하기 때문**이다.\n\n\n\n## 객체 리터럴 방식으로 생성했을 때 프로토타입 체인\n\n```javascript\nvar developer = {\n    name : 'BKJang',\n    age : 25,\n    sex : 'male'\n};\n\nconsole.log(developer.__proto__ === Object.prototype); //1.true\nconsole.log(Object.prototype.constructor === Object); // 2.true\nconsole.log(Object.__proto__ === Function.prototype); //3.true\nconsole.log(Function.prototype.__proto__ === Object.prototype); //4.true\n```\n\n\n![JavaScript](https://bkdevlog.netlify.com/assets/img/prototype_literal.png)\n\n\n\n`developer` 객체와 `Function.prototype` 객체의 **프로토타입 객체는 `Object.prototype` 객체**다.\n\n> 객체리터럴 방식으로 객체를 생성하면, 해당 객체의 프로토타입 객체는 `Object.prototype` 객체다. 좀 더 자세히 설명하면, 객체리터럴 방식으로 객체를 생성하면 `Object()`생성자 함수를 통해 객체가 생성되기 때문에 해당 객체의 프로토타입 객체는 `Object.prototype`객체가 된다.\n\n\n## 생성자 함수를 생성했을 때 프로토타입 체인\n\n\n\n```javascript\nfunction Developer(name) {\n    this.name = name;\n}\n\nvar web = new Developer('BKJang');\n\nconsole.log(web.__proto__ === Developer.prototype); //1.true\nconsole.log(Developer.prototype.__proto__ === Object.prototype); //2.true\nconsole.log(Developer.prototype.constructor === Developer); //3.true\nconsole.log(Developer.__proto__ === Function.prototype); //4.true\nconsole.log(Function.prototype.__proto__ === Object.prototype); //5.true\n```\n\n`Developer.prototype` 객체와 Developer() 생성자 함수의 프로토타입 객체인 `Function.prototype` 객체의 **프로토타입 객체는 `Object.prototype` 객체**다.\n\n\n\n![JavaScript](https://bkdevlog.netlify.com/assets/img/prototype_Func.png)\n\n\n\n### 프로토타입 체인의 종점(End of prototype chain)\n\n> 객체 리터럴 방식으로 객체를 생성하든 생성자 함수를 이용해 객체를 생성하든 **결국 모든 객체의 부모 객체(프로토타입 객체)는 `Object.prototype` 객체**다. 이 때 `Object.prototype` 객체를 **프로토타입 체인의 종점**이라 한다.\n\n\n\n## 프로토타입 객체의 확장\n\n\n\n프로토타입 객체 역시 객체다. 따라서, 객체의 **프로퍼티를 동적으로 추가하거나 삭제할 수 있다.**\n\n```javascript\nfunction Developer(name) {\n    this.name = name;\n}\n\nvar web = new Developer('BKJang');\n\nweb.printAge(25); // Uncaught TypeError: web.printAge is not a function\n```\n\n위의 코드의 결과를 보면 **web객체에서 `printAge()`라는 메서드가 없기 때문에** 에러가 나는 것을 볼 수 있다.\n\n```javascript\nfunction Developer(name) {\n    this.name = name;\n}\n\nvar web = new Developer('BKJang');\n\nDeveloper.prototype.printAge = function(age) {\n    console.log('The age of this developer is', age);\n};\n\nweb.printAge(25); // The age of this developer is 25\n```\n\nweb 객체의 프로토타입 객체(부모 객체)인 `Developer.prototype` 객체에 `printAge(age)`라는 메서드를 추가했다.\n\n이에 따라 **web 객체에서 `printAge(age)`메서드에 접근하면 결과 값을 출력**하는 것을 볼 수 있다.\n\n\n\n![JavaScript](https://bkdevlog.netlify.com/assets/img/prototype_extenstion.png)\n\n\n\n## 기본 데이터 타입의 확장\n\n\n\n자바스크립트에서 **숫자, 문자열과 같은 기본 데이터 타입에서 사용되는 표준 메서드의 경우 `Number.prototype`과 `String.prototype` 객체에 정의**되어 있다.\n\n```javascript\nvar str = 'hello world';\n\nstr.printStr = function(text) {\n    console.log(text);\n};\n\nstr.printStr('This is the test'); //Uncaught TypeError: str.printStr is not a function\n```\n원시 데이터 타입인 문자열의 경우에는 객체가 아니기 때문에 프로퍼티를 동적으로 추가할 수 없다.\n\n그렇다면, 위에서 str 변수에 printStr 메서드를 동적으로 추가하는 코드에서는 왜 에러가 발생하지 않을까?\n\n그 이유는 **기본 데이터 타입으로 프로퍼티나 메소드를 호출하면 기본 데이터 타입과 연관된 객체로 일시적으로 변환되어 프로토타입 객체를 공유하게 되기 때문**이다.\n\n```javascript\nvar str = 'hello world';\n\nString.prototype.printStr = function(text) {\n    console.log(text);\n};\n\nstr.printStr('This is the test'); //This is the test\n'this is string'.printStr('This is the test'); //This is the test\n```\n문자열 타입의 경우, `String.prototype` 객체에 표준 메서드가 정의 되어있기 때문에 **해당 객체에 메서드를 추가해주면 기본 데이터 타입에서도 해당 메서드를 사용할 수 있다.**\n\n```javascript\nvar str = 'hello world';\n\nString.prototype.printStr = function(text) {\n    console.log(text);\n};\n\nconsole.log(str.__proto__ === String.prototype); //1.true\nconsole.log(String.prototype.__proto__ === Object.prototype); //2.true\nconsole.log(String.prototype.constructor === String); //3.true\nconsole.log(String.__proto__ === Function.prototype); //4.true\nconsole.log(Function.prototype.__proto__ === Object.prototype); //5.true\n\nstr.printStr('This is the test'); //This is the test\n```\n\n\n\n![JavaScript](https://bkdevlog.netlify.com/assets/img/prototype_extenstion_primitive.png)\n\n\n\n## 프로토타입 객체의 변경\n\n\n\n자바스크립트에서 특정 객체는 **부모 객체인 프로토타입 객체를 임의로 변경할 수 있다.**\n\n```javascript\nfunction Developer(name) {\n    this.name = name;\n}\n\nvar web = new Developer('BKJang');\n\nDeveloper.prototype = { age : 25 };\n\nvar android = new Developer('YAKim');\n\nconsole.log(web.age); //undefined\nconsole.log(android.age); //25\n\nconsole.log(web.constructor); //Developer(name)\nconsole.log(android.constructor); //Object()\n```\n\n\n* **변경 전 :** 파란색 번호\n* **변경 후 :** 주황색 번호\n\n![JavaScript](https://bkdevlog.netlify.com/assets/img/prototype_change.png)\n\n\n\n\n**프로토타입 객체를 변경하기 전,** web객체의 `constructor`는 프로토타입 체이닝에 따라 **`Developer()`생성자 함수**를 가리킨다.\n\n**프로토타입 객체를 변경한 후,** android객체의 `constructor`는 **`Object()` 함수**를 가리킨다.\n\n프로토타입 객체가 변경되면서 **`Developer.prototype` 객체의 `constructor` 프로퍼티와 `Developer()` 생성자 함수의 연결이 깨진다.**\n\n이에 따라 **프로토타입 체인이 동작하고** android 객체의 `constructor`는 `Object.prototype` 객체의 `constructor` 프로퍼티가 가리키는 **`Object()` 함수**가 되는 것이다.\n\n\n\n> * 프로토타입 객체를 변경하기 전과 후의 프로토타입 링크([[Prototype]] 프로퍼티)는 **각각 다른 프로토타입 객체와 바인딩 된다.**\n> * 프로토타입 객체를 변경한 후에는, **프로토타입 객체의 constructor 프로퍼티와 생성자 함수와의 연결이 깨진다.**\n\n\n\n## 프로토타입 체인의 동작 조건\n\n\n\n> 프로토타입 체인은 객체의 특정 프로퍼티에 접근할 때, 그 프로퍼티가 해당 객체에 없는 경우 동작한다.\n\n```javascript\nfunction Developer(name) {\n    this.name = name;\n}\n\nDeveloper.prototype.age = 25;\nDeveloper.prototype.sex = 'male';\n\nvar web = new Developer('BKJang');\nvar android = new Developer('YAKim');\n\nandroid.sex = 'female';\n\nconsole.log(web.age); //1.25\nconsole.log(web.sex); //2.male\n\nconsole.log(android.age); //1.25\nconsole.log(android.sex); //3.female\n```\n\n\n![JavaScript](https://bkdevlog.netlify.com/assets/img/prototype_chaining_condition.png)\n\n\n\n> 1. `web` 객체에는 age와 sex 프로퍼티가 없기 때문에 **프로토타입 체인에 따라 `Developer.prototype` 객체의 `age`와 `sex` 프로퍼티에 접근**하고 있다.\n\n> 2. `android` 객체에는 age 프로퍼티는 없지만 sex 프로퍼티는 있기 때문에 **`sex` 프로퍼티의 경우엔 프로토타입 체인이 동작하지 않고 android 객체의 `sex` 프로퍼티 값을 반환**하고 있다.\n\n\n#### Reference\n- [인사이드 자바스크립트 (송형주, 고형준)](http://www.yes24.com/Product/Goods/37157296)"
  },
  {
    "path": "Javascript/Proxy.md",
    "content": "# Proxy\n\n사람들이 흔히 생각하는 프록시 패턴이 아닌 프록시 객체에 대해서 알아보는 시간을 가지자\n\n## `Proxy` 객체?\n\nES6는 [Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) 라는 새로운 생성자를 정의 해놓았다.\n\n이 생성자는 2개의 인자를 넣으면 되는 것으로\n\n- *target* 객체 : 대상객체\n- *handler* 객체 : 우리가 정의 해놓은 메소드들 \n\n:point_right: 예를 보자\n\n```js\n  const target = {}\n  const handler = {}\n\n  const proxy = new Proxy(target, handler) // 간단하게 생성을 해보았다.\n```\n\nproxy 객체와 target 객체가 어떻게 연결되는지 살펴보자\n\nproxy 객체의 동작 방식을 한 문장으로 설명할 수 있다. proxy 객체는 모든 내부 메소드 호출을 target 객체로 전달한다. 즉, 누군가 `proxy.[MethodName]()` 메소드를 호출하면, `target.[[MethodName]]()` 메소드가 그 결과를 리턴한다는 것이다.\n\n우리가 상식적으로 알고 있던 프록시의 모양이다.\n\n자 `proxy.[[Set]]()` 메소드가 호출이 될 수 있도록 테스트를 진행해보자\n\n```js\n  proxy.color = \"pink\"\n```\n\n이렇게 테스트를 진행하게 되면, `proxy.[[Set]]()` 메소드가 호출되면 자동적으로 `target.[[Set]]()` 메소드가 호출이 되고, target 객체에 새로운 속성을 만들고 그안에는 `pink`라는 string이 들어가게 된다.\n\n```js\n  target.color // result \"pink\"\n```\n\n나머지 **내부 메소드들도 마찬가지로 동작**한다. \n\n\n이 프록시 객체는 대부분은 타겟 객체인 것처럼 동작한다.\n\n< `proxy !== target` >\n\n프록시는 타겟과 다르다. 그래서 proxy 는 target 이 성공하는 타입 체크에 실패를 하곤 하는데, 예를 들어 proxy 의 target 이 **DOM Element** 인 경우, proxy 자신은 *진짜로는* Element 가 아니여서 `document.body.appendChild(proxy)` 같은 코드는 `TypeError` 를 내면서 실패하게 된다.\n\n## **프록시 핸들러 (Proxy handler)**\n\nhandler 객체가 프록시를 유용하게 만들어 준다.\n\nhandler 객체의 메소드들을 통해 프록시 객체의 모든 내부 메소드들을 **오버라이드**해서 사용할 수 있다.\n\n객체의 속성에 값을 할당하는 모든 시도를 가로채고 싶다면, 그냥 [[MDN]handler.set()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/handler/set) 메소드를 정의하면 된다.\n\n```js\n  const target = {}\n  const handler = {\n    set: function (target, key, value, receiver) {\n        throw new Error(\"Please don't set properties on this object.\");\n    }\n  };\n\n  const proxy = new Proxy(target, handler);\n    \n  proxy.name = \"angelina\"\n    //Error: Please don't set properties on this object.\n```\n\nhandler 객체로 오버라이딩 가능한 메소드들의 목록은 `Proxy` 에 대한 [MDN 문서](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy#Methods_of_the_handler_object)를 보면 됩니다. \n\n목록에는 총 14개의 메소드들이 있으며, 메소드들 각각이 **ES6** 가 정의하는 14개의 내부 메소드들에 해당한다.\n\n모든 handler 메소드들은 옵셔널이다. 만약 내부 메소드가 handler 객체에 의해 가로채어지지 않는다면, 우리가 이전에 본 것처럼 해당 메소드 호출은 그냥 target 객체로 전달한다.\n\n## 예제: 1. 불가능 자동 생성 객체\n\n이제 프록시를 이용해서 신기한 일을 해낼 수 있을만큼 프록시에 대해 충분히 알게 되었다.\n\n여기 첫번째 연습 과제가 있습니다. `Tree()` 함수를 만들어 봅시다.\n\n```js\n    var tree = Tree()\n    tree // { }\n    tree.branch1.branch2.twig = \"apple\"\n\n    tree // { branch1: { branch2: { twig: \"green\" } } }\n\n    tree.branch1.branch3.twig = \"Persimmon\" // { branch1: { branch2: { twig: \"green\" }, branch3: { twig: \"yellow\" }}}\n```\n\nbranch1, branch2, branch3 같은 모든 중간 객체들이 마법처럼 필요할 때마다 자동으로 생성이 되고 있다.\n\n지금까지는 이런 일을 하는 방법이 없었다. 하지만 프록시를 이용하면 아주 짧은 코드로 이런 일을 해낼 수 있게 된다. \n\nhandler에 `tree.[[Get]]()` 메소드에 끼어들기만 하면 된다.\n\n:saxophone: 해답\n\n```js\n    function Tree() {\n      return new Proxy({}, handler)\n    }\n    \n    var handler = {\n      get: function (target, key, receiver) {\n        if (!(key in target)) {\n          target[key] = Tree()  // auto-create a sub-Tree\n        }\n        return Reflect.get(target, key, receiver)\n      }\n    };\n```\n\n마지막의 `Reflect.get()` 구문에 주의해야 한다. 프록시 핸들러 메소드를 구현할 때 **이제 그냥 원래 하던 동작을 할 수 있도록 target 객체로 메소드 호출을 전달해주세요** 라고 말하는 기능이다. \n\nES6 는 14개의 메소드들과 함께 새로운 [Reflect 객체](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect)\n\n\n## 예제: 2. 읽기전용 뷰 (read-only view)\n\n이제 우리는 `readOnlyView(object)` 함수를 구현하려고 한다. 이 함수는 임의의 객체를 인자로 전달받아서 그 객체와 똑같이 동작하는 프록시 객체를 리턴한다. *하지만* 리턴된 객체는 변경할 수 없습니다. \n\n예를 들자면 다음처럼 동작해야 한다.\n\n```js\n  const newMath = readOnlyView(Math)\n  newMath.min(54, 40) // 40\n  newMath.max = Math.min // Error: can't modify read-only view\n  delete newMath.sin // Error: can't modify read-only view\n```\n\n첫번째 단계는 타겟 객체를 변경할 수 있는 모든 내부 메소드들을 가로채는 것입니다. 5개의 메소드들이 여기에 해당합니다.\n\n```js\n    function NOPE() {\n      throw new Error(\"can't modify read-only view\");\n    }\n    \n    var handler = {\n      // Override all five mutating methods.\n      set: NOPE,\n      defineProperty: NOPE,\n      deleteProperty: NOPE,\n      preventExtensions: NOPE,\n      setPrototypeOf: NOPE\n    };\n    \n    function readOnlyView(target) {\n      return new Proxy(target, handler);\n    }\n```\n\n이 코드는 동작합니다. 이 코드는 읽기전용 뷰(read-only view)가 할당 작업, 신규 속성 정의 작업 등을 하지 못하도록 막는 것이다.\n\n가장 큰 문제점은 `[[Get]]` 메소드(그리고 다른 몇개의 메소드)가 여전히 수정 가능한 객체를 리턴한다는 것입니다. 그래서 만약 어떤 객체 `x` 가 읽기전용 뷰(read-only view)라고 하더라도 `x.prop` 객체는 수정 가능합니다! 이건 큰 구멍입니다.\n\n이 구멍을 메꾸려면 `handler.get()` 메소드를 수정해야 합니다.\n\n```js\n    var handler = {\n      ...\n    \n      // Wrap other results in read-only views.\n      get: function (target, key, receiver) {\n          // Start by just doing the default behavior.var result = Reflect.get(target, key, receiver);\n    \n          // Make sure not to return a mutable object!if (Object(result) === result) {\n          // result is an object.return readOnlyView(result);\n        }\n        // result is a primitive, so already immutable.return result;\n      },\n    \n      ...\n    };\n```\n\n이것도 아직도 부족하다. `getPrototypeOf` 와 `getOwnPropertyDescriptor` 같은 다른 메소드들에도 비슷한 코드를 적용해야 한다.\n\n아직도 문제가 더 존재하는데, 이런 종류의 프록시에 있는 getter 나 다른 메소드가 호출될 때, 메소드에 전달되는 `this` 는 통상 프록시 객체 자신이다. 하지만 우리가 조금 전에 본 것처럼, 많은 접근자들과 메소드들이 프록시 객체가 통과할 수 없는 타입 체킹을 수행한다. 이쯤 되면 타겟 객체를 프록시 객체로 바꾸는 것이 더 좋을 것 같다. \n\n## 정리\n\n- 프록시는 무엇에 알맞은가\n\n프록시는 어떤 객체에 대한 접근을 관찰하거나 로그를 남길 때 확실히 유용하다. 프록시는 디버깅할 때가 이상적이다. 테스트 프레임워크들이 [가짜 객체 (mock object)](https://en.wikipedia.org/wiki/Mock_object)를 만들 때 프록시를 이용할 수 있습니다.\n\n프록시는 보통의 객체보다 아주 약간 느린 동작이 필요한 경우에 유용합니다. 예를 들면 게으르게 반환되는 속성 (lazily populating properties) 같은 경우입니다.\n\n프록시를 사용하는 코드 내부에서 어떤 일이 일어나고 있는지 확인하는 가장 좋은 해결책 중 하나는 바로 프록시의 핸들러 객체를 다시 *다른 프록시*로 감싸는 것이다. 그래서 핸들러의 메소드가 호출될 때마다 콘솔에 로그가 출력되도록 만드는 것이다.\n\n프록시는 우리가 `readOnlyView` 로 했던 것처럼 어떤 객체에 대한 접근을 제한하기 위해 사용할 수 있다.Firefox 는 내부적으로 프록시를 사용해서 서로 다른 도메인들 사이에 존재하는 [보안 장벽 (security boundary)](https://developer.mozilla.org/en-US/docs/Mozilla/Gecko/Script_security)을 구현하고 있다. 이것이 Firefox 보안 모델의 핵심이다.\n\n- WeakMap \n\n`readOnlyView` 예제에서, 우리는 객체에 접근할 때마다 매번 새로운 프록시를 생성했다. 우리가 생성하는 프록시를 `WeakMap` 에 캐시하면 아주 많은 메모리를 절약할 수 있습니다. 그러면 어떤 객체가 여러번 `readOnlyView` 에 전달되더라도, 프록시는 한번만 생성되도록 만들 수 있습니다.\n\n- 폐기 가능한 프록시(revocable proxy) \n  \nES6 는 또 `Proxy.revocable(target, handler)` 이라는 함수도 제공한다 이 함수는 `new Proxy(target, handler)`함수처럼 프록시 객체를 리턴하는데 이 함수를 통해 생성되는 프록시는 나중에 폐기시킬 수 있습니다. (`Proxy.revocable` 함수는 어떤 객체를 리턴한다. 이 객체에는 `.proxy` 속성과 `.revoke` 메소드가 존재한다.) 일단 프록시를 폐기시키면, 해당 프록시는 더이상 동작하지 않습니다. 폐기된 이후 호출되는 내부 메소드들은 예외를 발생시킵니다.\n\n- **객체의 불변조건(object invariants).** \n\n어떤 경우에는, ES6 에서 프록시 핸들러 메소드가 target 객체의 상태와 일치하는 결과를 보고하도록 강제해야 할 때가 있다. 이렇게 하는 이유는 모든 객체들(심지어 프록시 객체들까지 포함해서)에서 변경불가(immutability) 원칙을 관철시키기 위해서 입니다. 예를 들어, 타겟 객체가 확장 불가능(inextensible) 하지 않은데, 프록시 객체가 확장 불가능하다고 주장할 수는 없다.\n\n정확한 규칙을 설명하기에는 지면이 부족하다. 하지만 만약 `proxy can't report a non-existent property as non-configurable` 같은 에러 메시지를 보게 된다면, 바로 이런 이유 때문이다. 이때 좋은 처방은 프록시가 자신에 대해 보고하는 바를 수정하는 것이다. 또다른 처방은 프록시가 보고하는 내용에 따라 그때그때 타겟을 수정하는 것이다.\n\n## 프록시를 지금 당장 쓸 수 있을까\n\n웹에서는 지금 당장 쓸 수 없다. 더구나 폴리필도 존재하지 않는다.\n\n---\n\n#### Reference\n\n- [ES6 In Depth: 프락시 (Proxy)](http://hacks.mozilla.or.kr/2016/03/es6-in-depth-proxies-and-reflect/)\n- [babel](https://babeljs.io/docs/en/learn#proxies)\n"
  },
  {
    "path": "Javascript/Reduce.md",
    "content": "# Reduce\n\nArray.prototype이 가지고 있는 리듀스라는 함수다. 이 리듀스는 흔히 SUM의 기능을 가진다고 생각을 많이 한다. 그러나 생각보다 더 많은 기능을 구현할 수 있다.\n\n## 함수 설명\n\nReduce는 구조가 좀 특이하다. 일단 파라미터로 두가지를 받을 수 있는데 콜백함수와 초기값이다. 그런데 이 콜백에 4가지 파라미터가 있으나 2개가 필수 2개가 optinal이다. 보기쉽게 구조를 그려보자.\n\n```markdown\n- reduce\\*\n  - callback\\*\n    - total\\* // 누적 값\n    - currentValue\\* // 현재 값\n    - currentIndex\n    - arr // reduce가 호출된 배열\n  - initialValue // 초기값\n```\n\nreduce라는 함수에 파라미터로 콜백이 있고 이 콜백에 파라미터로 또 인자가 있는 구조다.\n\n### sum\n\nreduce로 할 수 있는 대표적인 기능이다. 매우 간단하니 코드로 살펴보자.\n\n```javascript\nvar arr = [1, 2, 3, 4, 5];\n\nvar sum = arr.reduce((acc, cur) => {\n  return acc + cur;\n});\n\nconsole.log(sum); // 15\n```\n\n```javascript\nvar arr = [1, 2, 3, 4, 5];\nvar reducer = (acc, cur) => {\n  return acc + cur;\n};\n\nvar sum = arr.reduce(reducer);\n\nconsole.log(sum); // 15\n```\n\n위와 아래는 완전히 동일하다. 함수의 동작 방식은 생각보다 간단한데 map과 유사하다. map처럼 배열의 요소를 하나씩 가져온 것을 cur에 담는다. return 값이 acc가 되어 다음 반복 때 사용할 수 있다.\n\n이러한 메커니즘 때문에 덧셈이 가능하다.\n\n```javascript\nvar arr = [1, 2, 3, 4, 5];\nvar reducer = (acc, cur, index) => {\n  console.log('acc, cur, index : ' + acc, cur, index);\n  return acc + cur;\n};\n\nvar sum = arr.reduce(reducer, 10);\n\nconsole.log(sum);\n// 위의 결과\n// acc, cur, index : 10 1 0\n// acc, cur, index : 11 2 1\n// acc, cur, index : 13 3 2\n// acc, cur, index : 16 4 3\n// acc, cur, index : 20 5 4\n// 25\n\n// 초기값이 없다면\n// acc, cur, index : 1 2 1\n// acc, cur, index : 3 3 2\n// acc, cur, index : 6 4 3\n// acc, cur, index : 10 5 4\n// 15\n```\n\n위와 같이 초기값을 정해주면 그 초기값이 첫번째 틱의 acc가 된다. 초기값을 정하지 않으면 index는 1부터, 초기값을 정하면 0부터 시작하게 된다.\n\n### 응용\n\n자바스크립트의 강점은 타입 선언이 동적이다. 파라미터의 타입역시 동적일 수 있다. 이게 응용을 가능하게 한다. 예를 들어 초기 값이 배열이라면? object라면? 여기서 출발한다.\n\n```javascript\nvar arr = ['Kim', 'Kim', 'Kang', 'Jang', 'Jo', 'Kang', 'Jo'];\n\nvar reducer = (acc, cur, index) => {\n  if (!acc[cur]) {\n    acc[cur] = 1;\n  } else {\n    acc[cur] = acc[cur] + 1;\n  }\n\n  return acc; // 여기\n};\n\nvar sorting = arr.reduce(reducer, {});\n\nconsole.log(sorting); // { Kim: 2, Kang: 2, Jang: 1, Jo: 2 }\n```\n\n배열의 같은것을 찾아 개수를 세어봤다. 여기서 중요한 것은 누적 값인 object를 return한다는 점이다.\n\n다음으로는 배열로 만들어 봅시다. 보통 map과 filter를 동시에 이용하는 로직의 경우 reduce로 한방에 처리가 가능합니다. 예를들어\n짝수만 찾아서 요소들을 2를 곱해야 한다고 하면 아래와 같이 처리가 가능합니다.\n\n```javascript\nvar arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 15, 16, 20];\n\nvar reducer = (acc, cur, index) => {\n  if (cur % 2 === 0) acc.push(cur * 2);\n  return acc;\n};\n\nvar double = arr.reduce(reducer, []);\n\nconsole.log(double);\n```\n\n아래와 같이 object에서 특정값만 뽑아내는것도 가능합니다.\n\n```javascript\nconst input = [\n  {\n    title: '슈퍼맨',\n    year: '2005',\n    cast: ['장동건', '권상우', '이동욱', '차승원']\n  },\n  {\n    title: '스타워즈',\n    year: '2013',\n    cast: ['차승원', '신해균', '장동건', '김수현']\n  },\n  {\n    title: '고질라',\n    year: '1997',\n    cast: []\n  }\n];\nconst key = 'cast';\n\nconst flatMapReducer = (acc, cur) => {\n  cur[key].reduce((acc2, cur2) => {\n    if (acc2.indexOf(cur2) === -1) acc2.push(cur2);\n    return acc2;\n  }, acc);\n\n  return acc;\n};\nconst flattenCastArray = input.reduce(flatMapReducer, []);\n// ['장동건', '권상우', '이동욱', '차승원', '신해균', '김수현']\n\nconsole.log(flattenCastArray);\n```\n\n참고자료\n\nhttps://medium.com/@hongkevin/js-3-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EB%B0%B0%EC%97%B4-%EB%A9%94%EC%84%9C%EB%93%9C-reduce-100-%ED%99%9C%EC%9A%A9%EB%B2%95-feat-egghead-io-97c679857ece\n"
  },
  {
    "path": "Javascript/Redux State 정규화.md",
    "content": "# Redux State 정규화(Normalization)\n\n<br/>\n\n## 상태 정규화의 필요성\n\n많은 애플리케이션들은 실제로 중복된 데이터들을 많이 처리한다. Facebook의 타임라인을 예로 들어보자.\n\n각각의 포스트가 있고 그 포스트에는 많은 사람들의 댓글, 좋아요, 공유 등의 작업이 일어난다.\n\n이렇듯 상태 데이터 구조가 복잡해질수록 정규화가 필요한 이유에 대해 Redux docs에서는 다음과 같이 설명하고 있다.\n\n> * When a piece of data is duplicated in several places, it becomes harder to make sure that it is updated appropriately.<br/>**(데이터가 제대로 업데이트 되었는지 확인하기 어렵다.)**\n> * Nested data means that the corresponding reducer logic has to be more nested and therefore more complex. In particular, trying to update a deeply nested field can become very ugly very fast.<br/>**(Nested 데이터가 늘어나고 깊이 내장되어 있는 데이터일수록 업데이트하기 어려워진다.)**\n> * Since immutable data updates require all ancestors in the state tree to be copied and updated as well, and new object references will cause connected UI components to re-render, an update to a deeply nested data object could force totally unrelated UI components to re-render even if the data they're displaying hasn't actually changed.<br/>**(불변 데이터를 업데이트 할 때 깊이 내장된 데이터일수록 상위 데이터들까지 업데이트 되어야하고 이는 관련되지 않은 UI 컴포넌트까지 리렌더링될 수 있다.)**\n\n<br/>\n\n## 상태 정규화\n\n보통의 포스팅과 댓글은 아래와 같은 데이터 구조를 가질 것이다.\n\n```js\nconst blogPosts = [\n  {\n    id: 'post1',\n    author: { username: 'user1', name: 'User 1' },\n    body: '......',\n    comments: [\n      {\n        id: 'comment1',\n        author: { username: 'user2', name: 'User 2' },\n        comment: '.....'\n      },\n      {\n        id: 'comment2',\n        author: { username: 'user3', name: 'User 3' },\n        comment: '.....'\n      }\n    ]\n  },\n  {\n    id: 'post2',\n    author: { username: 'user2', name: 'User 2' },\n    body: '......',\n    comments: [\n      {\n        id: 'comment3',\n        author: { username: 'user3', name: 'User 3' },\n        comment: '.....'\n      },\n      {\n        id: 'comment4',\n        author: { username: 'user1', name: 'User 1' },\n        comment: '.....'\n      },\n      {\n        id: 'comment5',\n        author: { username: 'user3', name: 'User 3' },\n        comment: '.....'\n      }\n    ]\n  }\n  // and repeat many times\n]\n```\n\n이를 정규화하면 다음과 같이 변경될 수 있다.\n\n```js\n{\n    posts : {\n        byId : {\n            \"post1\" : {\n                id : \"post1\",\n                author : \"user1\",\n                body : \"......\",\n                comments : [\"comment1\", \"comment2\"]\n            },\n            \"post2\" : {\n                id : \"post2\",\n                author : \"user2\",\n                body : \"......\",\n                comments : [\"comment3\", \"comment4\", \"comment5\"]\n            }\n        },\n        allIds : [\"post1\", \"post2\"]\n    },\n    comments : {\n        byId : {\n            \"comment1\" : {\n                id : \"comment1\",\n                author : \"user2\",\n                comment : \".....\",\n            },\n            \"comment2\" : {\n                id : \"comment2\",\n                author : \"user3\",\n                comment : \".....\",\n            },\n            \"comment3\" : {\n                id : \"comment3\",\n                author : \"user3\",\n                comment : \".....\",\n            },\n            \"comment4\" : {\n                id : \"comment4\",\n                author : \"user1\",\n                comment : \".....\",\n            },\n            \"comment5\" : {\n                id : \"comment5\",\n                author : \"user3\",\n                comment : \".....\",\n            },\n        },\n        allIds : [\"comment1\", \"comment2\", \"comment3\", \"commment4\", \"comment5\"]\n    },\n    users : {\n        byId : {\n            \"user1\" : {\n                username : \"user1\",\n                name : \"User 1\",\n            },\n            \"user2\" : {\n                username : \"user2\",\n                name : \"User 2\",\n            },\n            \"user3\" : {\n                username : \"user3\",\n                name : \"User 3\",\n            }\n        },\n        allIds : [\"user1\", \"user2\", \"user3\"]\n    }\n}\n```\n\n* 각각의 데이터는 자신만의 테이블을 가지도록 한다.<br/>(위에선 post, comments, users로 분리하였다.)\n\n* 각 테이블들은 해당 테이블과 관련된 개별적인 아이템들을 하나의 객체 안에 저장한다.\n\n* 각각의 아이템에 대한 참조는 ID를 통해 수행된다.\n\n* 배열(`posts.allIds`) 안의 ID들은 **순서**를 나타낸다. \n\n<br/>\n\n## Redux State Normalization\n\n결론적으로 **Redux 상태 정규화는 Database의 정규화를 생각하면 편하다.**\n\n어떤 애플리케이션이든 중복된 데이터 구조를 가지는 것은 당연하고 DB에서는 이를 정규화를 통해 해결한다. 예를 들어 다대다(Many to Many) 관계를 가지는 테이블 사이에 관계 테이블을 만들어 중첩되는 필드를 분리한다. \n\n이처럼 각각의 데이터를 각각의 테이블 구조로 만들고 내부의 데이터들은 ID배열을 가지고 참조하는 방식으로 구성하는 것이다.\n\n이처럼 구조를 개선했을 때 **가장 큰 장점은 ID 값을 기반으로 참조를 하기 때문에 특정 데이터가 바뀌었을 때 상위 데이터들의 업데이트를 신경쓰지 않아도 되는 것**이다.\n\n예를 들어, 댓글을 수정할 경우 `comments.byId.comment` 부분의 새로운 복사본만 필요로 할 것이다.\n\n상태 정규화를 위해 주로 사용되는 라이브러리에는 [Normalizr](https://github.com/paularmstrong/normalizr)가 있다.\n\n<br/>\n\n---\n\n#### Reference\n\n- [Structuring Reducers - Normalize State Shape](https://redux.js.org/recipes/structuring-reducers/normalizing-state-shape)\n"
  },
  {
    "path": "Javascript/Regular_Expressions.md",
    "content": "# 정규 표현식(Regular Expressions)\n\n## 개념\n\n정규표현식은 줄여서 정규식(영어로 Regular Expression이며, 줄여서 `Regex`, `Regexp` 등으로 불린다.)이라고 한다.\n\n컴퓨터 과학의 *정규언어*로부터 유래된 것으로 **특정한 규칙을 가진 문자열의 집합을 표현하기 위해 쓰이는 형식언어**이다.\n\n> 참고 [정규언어 - wiki](https://ko.wikipedia.org/wiki/%EC%A0%95%EA%B7%9C_%EC%96%B8%EC%96%B4)\n\n이 말을 풀어보자면 `텍스트 내에서 특정한 형태나 규칙을 가진 문자열을 찾기 위해 그 형태나 규칙을 나타내는 패턴을 정의하는 것`을 **정규 표현식**이라고 한다.\n\n<br/>\n\n## 종류(또는 역사)\n\n정규 표현식은 검색 엔진, 워드 프로세서와 문서 편집기의 찾아 바꾸기 대화상자, 또 sed, AWK와 같은 문자 처리 유틸리티, 어휘분석 등 여러 분야에서 쓰였다. 각 분야의 정규식은 서로 영향을 주고 받으면서 발전해서 지금에 이르렀다. 정규식이 쓰이는 곳이 다양했지만 ***아름다운*** 역사 때문에 정규식에는 하나의 통일된 표준이 없다는 문제가 있다.\n\n처음 유닉스 명령줄 도구들에서 사용하던 정규 표현식은 후에 `POSIX` 표준에 편입되었다. 이 시기의 표준으로 받아들여진 형식을 **POSIX 정규식**이라고 부른다. 이후 다시 **POSIX 정규식**은 POSIX BRE(POSIX 기본 정규식)와 POSIX ERE(POSIX 확장 정규식)으로 버전이 나뉘게 된다.\n\n그 외에 BRE를 기본 골격으로 한 **vim 정규식**이 있다. 이 **vim 정규식**은 vim 편집기 내에서 찾기/바꾸기 등의 동작에서 범위를 지정하는데 사용된다. 하지만 시간이 흐르면서 개선과 확장을 거듭하면서 이 **vim 정규식** 역시 **POSIX 표준**과는 좀 다른 규격으로 취급이 되었다.\n\nvim 내에서도 [magic 모드, very magic 모드](https://soooprmx.com/archives/4698)라는 것이 있는데, 이후의 확장 정규식의 일부 기능을 사용하거나, 일부 punctuation 문자를 매칭하는 방법이 다시 갈리게 되었다.\n\n>  [punctuation 문자](https://docs.microsoft.com/ko-kr/cpp/c-language/punctuation-and-special-characters?view=vs-2019) : one of ( ) [ ] { } * , : = ; ... #\n\n문자열을 다루는데 특화된 스크립트 언어인 [펄(perl)](https://www.perl.org/)의 정규식 체계의 기본은 POSIX와 비슷한 골격에서 디자인이 되었다. 그런데 엄청나게 많은 확장이 들어가게 되면서, 펄의 정규식은 PCRE라는 규격으로 정리되었으며, 이후 많은 프로그래밍 언어들이 이 규격을 차용하거나 계승했다. 여기서 중요한 것은 **일부 차용**이라는 것이다. 이 규격은 방대해서 PCRE를 그대로 가져다 쓰지 않는 이상, 구현할게 너무 많기 때문이다.\n\n<br/>\n\n## 기본 문법\n\n정규식 기분 문법은 크게 세 가지로 나눌 수 있다. \n\n1. **패턴 그대로를 매칭**하는 경우 : 편집기에서 '찾기' 기능을 통해서 특정 단어를 찾는 것과 동일하게, 단어 그대로를 패턴으로 사용하여 매치 `ex)textbox, regExp`\n2. **메타문자** 및 **수량 한정자**를 적용하는 경우 : 정규식 패턴에 쓰이는 문자 중에는 특별한 의미를 가지는 메타 문자를 사용하여 보다 폭넓은 패턴에 매치\n3. **Group** 및 **look around** 기능을 사용하는 경우 : 고급 정규식이라 할 수 있는 부분으로, 패턴의 일부를 Group으로 묶거나, 특정 패턴의 앞 뒤로 다른 패턴이 오는 조건을 더하는 경우\n\n<br/>\n\n### 정규식 메타 문자\n\n**메타 문자는 특정한 문자 혹은 문자 계열을 대신하여 표시하는 문자이다.** 메타문자를 이용하면 특정한 규칙을 가진 여러 단어를 하나의 패턴으로 함축할 수 있다.\n\n메타 문자 | 의미 | 예\n----------|------|------\n^ |\t문자열의 시작을 의미. `[...]` 내에서 쓰이면 '일치하지 않는'이라는 의미 | `^http`는 문자열의 **맨 처음에** http가 온 경우에 매치\n$ |\t문자열의 끝을 의미 | `them$`은 문자열이 them으로 끝난 경우에 them에 매치\n\\b | 단어의 경계. 공백(space), 탭(tab), 콤마(,), 대시(-) 등이 가능 | `\\bplay\\b`는 play의 양 끝에 단어 경계가 오는 경우에만 play에 매치. 'playground'의 play에는 매치하지 않음\n\\B | `\\b`의 반대. |\t`\\bplay\\B`는 play뒤에 단어 경계가 아닌 것이 왔을 때 play에 매치. play에는 매치하지 않지만 playground, playball의 play에는 매치\n\\s | 공백문자 | 공백, 탭에 매치한다.\n\\S | 공백문자가 아닌 것\t\n\\d | 숫자. `[0-9]`와 동일\n\\D | 숫자가 아닌 것. `[^0-9]`와 동일\t\n\\w | 단어를 만들 수 있는 글자. **알파벳 대소문자, 숫자, 언더스코어가 포함**\t\n\\W | `not \\w` 위의 것이 아닌 글자들이 해당\t\n\\n | 개행문자. 캐리지리턴(CR)은 `\\r`에 매치 | 그 외에 탭 문자는 `\\t`에 매치\n\\ | escape용 문자. 정규식 상의 특별한 의미가 있는 기호들을 문자 그대로 사용할 때 사용 |\t`\\.`, `\\*`, `\\$`, `\\(` 등과 같이 메타 문자를 리터럴하게 매치할 때 사용.\n. | 임의의 문자 1개에 대응한다.\t\n\n> 라인피드(LF : Line Feed) => 현재 위치에서 바로 아래로 이동 <br/>\n> 캐리지리턴(CR: Carriage return) => 커서의 위치를 앞으로 이동\n\n> 정규식 메타문자에서는 대소문자가 바뀌면 반대의 의미를 지니는 것들이 있다. <br/>\n> [테스트 사이트](https://regexr.com/) <br/>\n> [시각화 사이트](https://regexper.com/)\n\n**메타 문자의 패턴을 유심히 살펴보면, 소문자를 쓴 것과 대문자를 쓴 것이 서로 반대의 의미를 지닌다.**\n\n<br/>\n\n### 선택 패턴\n\n`|` 문자를 이용하면 `A | B` 의 패턴으로 A 혹은 B에 매칭할 수 있다. 예를 들어 tomato와 potato에 모두 매칭하고 싶다면 `tomato|potato` 라고 쓸 수 있다. 선택 패턴은 이후에 등장하는 그룹 패턴과 같이 사용하여 보다 강력하게 쓰일 수 있다.\n\n그 외의 선택 패턴으로는 `[ ... ]`이 있다. 대괄호속에 넣은 문자 중에서 하나에 매칭하는 것이다. `[cfh]all` 이라는 패턴은 `call`, `fall`, `hall`에 모두 매치될 수 있다. \n\n선택 패턴은 대시(`A-B`)를 통해서 특정 범위를 표현할 수도 있는데, 숫자의 경우 `[0-9]`, 알파벳 소문자의 경우 `[a-z]`, 알파벳대문자의 경우 `[A-Z]` 와 같은 식으로 한 글자에 매칭하는 것이 가능하다. 유니코드를 지원하는 정규식에서는 `[ㄱ-힣]`을 이용해서 한글 한 글자에 매칭하는 것도 가능하다.\n\n위에서 언급 되었던 것처럼, 선택 패턴 내에서 `^` 이 쓰이면 `not`의 의미가 되며, 문자 뒤에 오는 문자들은 제외하게 된다. `[^cfh]all` 은 앞서 나온 `call`, `fall`, `hall`에는 매치하지 않으며 `mall`에는 매치하게 된다.\n\n<br/>\n\n### Group\n\n괄호로 둘러싼 단위는 Group을 나타낸다. **Group은 전체 패턴 내에서 다시 하나로 묶여지는 패턴 조각을 나타낸다.** 특히 `|` 나 뒤에 나오는 수량 한정자를 Group에 붙이는 형태로 많이 사용되며, 한 번 매치한 Group을 다시 반복하여 사용할 수 있다.\n\n- `(tom|pot)ato` : tomato, potato에 모두 매치되는 패턴을 Group을 써서 좀 더 줄였다.\n- `(a|i){3}bc` : a 혹은 i가 3개 온 후에 bc가 오는 패턴. `aaabc, iiibc, aiabc, aaibc, iiabc` 등에 매치된다.\n\n괄호를 써서 묶은 부분은 1번부터 시작하는 Group으로 참조할 수 있다. 앞서 매치한 Group을 패턴 내에서 재사용하려면 `\\1`과 같이 Group번호를 역슬래시로 escape하여 표현한다. tomato에서 to가 두 번 반복되는데 이는 다음과 같이 표현할 수 있다.\n\n```text\n(to)ma\\1   # 이 패턴을 각 절로 나누어서 살펴보면,\n----\n(to)       # to 에 매치하는 첫번째 Group을 캡쳐한다.\n    ma     # ma에 매치\n        \\1   # 1번 Group인 to가 다시 나온다.\n```\n\n좀 더 응용하면 아래와 같은 패턴도 만들 수 있다.\n\n```text\n(a|b|c){2}ma\\1\n```\n\n이 패턴은 a 혹은 b 혹은 c 중에서 매치되는 두 글자를 Group으로 캡쳐하고 ma 뒤에 동일한 글자가 반복되는 패턴이다. 따라서 aamaaa, bcmabc, abmaab 등에 매치된다. 캡쳐된 Group을 재사용하는 **패턴은 Group의 패턴이 아닌 캡쳐된 내용에 매치**하므로 **aamabb에는 매치되지 않는다.**\n\n<br/>\n\n### 비캡쳐링 Group\n\n`(?: )` 을 사용하면 Group으로 묶어는 주지만 캡쳐는 하지 않는 비캡쳐링 Group이 된다. 특정한 수량 한정자 등을 적용은 하려 하지만 최종 결과에서 따로 구분하여 사용할 필요가 없는 경우에 적용한다. (사실 캡쳐만 해놓고 사용하지 않아도 된다.)\n\n<br/>\n\n### 수량 한정자\n\n동일한 글자 혹은 동일한 가족(family)이 n개 만큼 나오는 경우에 수량한정자를 뒤에 붙일 수 있다.\n\n메타 문자 | 의미 | 예\n----------|------|------\n? |\t앞의 표현식이 없을 수 있다.| `apples?` 에서 `s?` 는 있을 수도 없을 수도 있다는 의미이며, 이 패턴은 apple, apples 모두에 매치\n\\* | 0개 이상 | `n\\d*` 는 n 뒤에 숫자가 0개 이상이라는 의미. `n, n1, n12` 등이 모두 매치\n\\+ | 1개 이상 | `*`와 달리 적어도 1개는 있어야 매치\n{n} | n 개 있다.\t| `n\\d{3}` 은 n 뒤에 숫자가 3개 온다는 의미. `n1, n23, n3464` 등은 매치되지 않음\n{n, m} | n개 이상, m 개 이하의 범위\t| 숫자 두 개를 사용해서 범위를 지정\n{n,} | n개 이상\t| 우측 경계가 없는 범위로, **최소값 이상**을 의미한다.\n\n수량 한정자와 관련하여 `*`, `+` 는 기본적으로 greedy 하게 동작한다. 즉 가능한 많은 글자를 먹고 다음 패턴을 찾는다는 것이다. 예를 들어\n\n```text\ni like apples and bananas\n``` \n\n라는 문장에 대해서 `^.*s`를 매치하면 `.` 문자(아무 글자)는 욕심을 부려서 다 먹어치우기 때문에 bananas의 s까지, 전체 문장이 다 매치된다.\n\n이 때, `*` 와 `?` 를 조합하는 경우에는 반대로 동작하면서 가장 처음에 나오는 패턴까지 매치한다. 즉 `^.*?s`로 패턴을 주면 `i like apples` 까지만 매치한다.(lazy하게 동작한다고 한다.)\n\n<br/>\n\n### Look Around(고급)\n\n메타 문자 | 의미 \n----------|------\n(?=) | 긍정형 전방탐색\n(?!) | 부정형 전방탐색\n(?<=) |\t긍정형 후방탐색\n(?<!) |\t부정형 후방탐색\n\n> 일부 정규 표현식 문서에 일치하는 영역을 반환하는 동작을 표현할 때 소비한다(consume)라는 용어를 사용하는데, 전방탐색은 소비하지 않는다(not consume)라고 한다.\n\n<br/>\n\n### 전방탐색\n\n```text\nhttp://www.forta.com\nhttps://mail.forta.com\nftp://ftp.forta.com\n```\n\n`.+(?=:)`와 같은 전방탐색을 하게 되면 아래와 같은 결과값이 나온다.\n\n```text\nhttp\nhttps\nftp\n```\n\n위에서 언급한 내용과 동일하게 전방탐색은 소비하지 않는다. 일반적인 일치하는 영역을 반환하도록 하는 소비하게 하는 패턴을 작성하게 되면 `.+:`와 같이 작성하면 된다.\n<br/>\n\n### 후방탐색\n\n```text\nABC01: $23.45\nHGG42: $5.31\nCFMX1: $899.00\nXTC99: $69.96\nTotal items found: 4\n```\n\n`(?<=\\$)[0-9.]+`와 같은 후방탐색을 하게 되면 아래와 같은 결과값이 나온다.\n\n```text\n23.45\n5.31\n899.00\n69.96\n```\n\n`$` 기호와 일치하지만 소비하지 않고 뒤에 숫자만 반환한다.\n<br/>\n\n### 전방탐색과 후방탐색 함께 사용하기\n\n```text\n<HEAD>\n<Title>Ben Forta`s Homepage</Title>\n</HEAD>\n```\n\n`(?<=\\<[tT][iI][tT][lL][eE]\\>).*(?=\\<\\/[tT][iI][tT][lL][eE]\\>)`와 같은 패턴을 적용하게 되면 아래와 같은 결과값이 나온다.\n\n```text\nBen Forta`s Homepage\n```\n\n`(?<=\\<[tT][iI][tT][lL][eE]\\>)`는 후방탐색 작업으로 `<TITLE>`과 일치하며 소비하지 않으며,\n`(?=\\<\\/[tT][iI][tT][lL][eE]\\>)`도 같은 방식으로 `</Title>`과 일치하며, 소비하지 않는다. \n따라서 제목 텍스트만 반환하는 형태가 나오게 된다.\n<br/>\n\n### 부정형\n\n부정형 전방탐색은 앞쪽에서 지정한 패턴과 일치하지 않는 텍스트를 찾고 부정형 후방탐색도 마찬가지로 뒤쪽에서 지정한 패턴과 일치하지 않는 텍스트를 찾는다.\n\n```text\nI paid $30 for 100 apples,\n50 oranges, and 60 pears.\nI saved $5 on this order.\n```\n\n긍정형 패턴인 `(?<=\\$)\\d+`으로 테스트를 하게 되면 `30 5`이 나오게 되며, 부정형 패턴인 `\\b(?<!\\$)\\d+\\b`으로 테스트를 하게 되면, `100 60`이 나오게 된다.\n<br/>\n\n### Flag\n\nFlag | Description\n-----|------------\ng | 전역 검색\ni | 대소문자 구분 없는 검색\nm | 다중행(multi-line) 검색\nu | 유니코드; 패턴을 유니코드 코드 포인트의 나열로 취급한다.\n\n---\n\n#### Reference\n\n- [많이 사용하는 패턴 정리](https://github.com/SeonHyungJo/Dont_Waste_Your_Time/issues/15)\n- [정규표현식의 개념과 기초 문법](https://soooprmx.com/archives/7718)\n- [[정규식] 사용방법 / 정규식 예제](https://mkil.tistory.com/205)\n- [정규 표현식 (좀 더) 깊이 알아보기](https://medium.com/@originerd/%EC%A0%95%EA%B7%9C%ED%91%9C%ED%98%84%EC%8B%9D-%EC%A2%80-%EB%8D%94-%EA%B9%8A%EC%9D%B4-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0-5bd16027e1e0)\n- [정규식 테스트 사이트 모음](https://m.blog.naver.com/PostView.nhn?blogId=syung1104&logNo=220847918251&proxyReferer=https%3A%2F%2Fwww.google.com%2F)\n- [정규식 - MDN](https://developer.mozilla.org/ko/docs/Web/JavaScript/Guide/%EC%A0%95%EA%B7%9C%EC%8B%9D)\n- [https://regexr.com/](https://regexr.com/)\n- [https://regexper.com/](https://regexper.com/)"
  },
  {
    "path": "Javascript/Scope.md",
    "content": "# 스코프\n\n## 함수형 스코프\n\n자바스크립트는 기본적으로 **함수형 스코프**를 가진다.(EcmaScript6에서부터는 `let`과 `const`를 이용하여 블록 레벨 스코프를 사용할 수 있다.)\n\n```javascript\nvar x = 10;\n\nif(true) {\n    var y = 100;\n    console.log('local x :', x); //local x : 10\n    console.log('local y :', y); //local y : 100\n}\n\nfunction test() {\n    var x = 100;\n    var z = 200;\n    console.log('Function Level x:', x);\n    console.log('Function Level z:', z);\n}\n\nconsole.log('global x:', x); //global x: 10\nconsole.log('global y:', y); //global y: 100\ntest(); \n/*\nFunction Level x: 100\nFunction Level z: 200\n*/\nconsole.log('global z:', z); //Uncaught ReferenceError: z is not defined\n```\n\n보통 Java의 경우에는 if문(블록)안에서의 변수 선언은 지역 변수를 가지기 때문에 지역 스코프를 가진다.\n\n하지만 **자바스크립트에서 `var` 선언을 이용해 변수를 선언할 경우, 함수형 스코프를 가지기 때문에 위에서의 y는 전역 변수 z는 `test()` 함수의 지역 변수**가 된다.\n\n여기서 let을 잠깐 소개하자면, let은 위에서도 말했지만 **블록 스코프**를 가진다고 했다.\n\n```javascript\nlet x = 10;\n\nif(true) {\n    let y = 100;\n    console.log('local x :', x); //local x : 10\n    console.log('local y :', y); //local y : 100\n}\n\nconsole.log('global x:', x); //global x: 10\nconsole.log('global y:', y); //Uncaught ReferenceError: y is not defined\n```\n\n즉, **x는 전역 스코프, y는 if문 안에서의 지역 스코프**를 가지기 때문에 마지막 결과는 에러가 발생한다.\n\n## 내부함수의 스코프\n\n```javascript\nvar x = 'g';\n\nfunction outerFunc() {\n    var x = 'l';\n    console.log('outerFunc :', x);\n\n    function innerFunc() {\n        console.log('innerFunc :', x);\n    }\n\n    innerFunc();\n}\n\nouterFunc();\n\nconsole.log('global :', x);\n\n/*\nouterFunc : l\ninnerFunc : l\nwindow : g\n*/\n```\n\n> **내부 함수는 자신을 포함하고 있는 외부 함수의 변수에 접근할 수 있다.**\n\n내부함수인 `innerFunc()`에서 참조하는 변수 x는 `outerFunc()`에서 선언된 지역변수이다. 이는 **실행 컨텍스트의 스코프 체인에 의해 `innerFunc()`에서 참조하는 순위에서 전역변수 x가 밀렸기 때문**이다.\n\n실행 컨텍스트에 대한 내용은 이어질 포스팅에서 다룰 예정이다.\n\n## 렉시컬 스코프(Lexical Scope)\n\n자바스크립트는 렉시컬 스코프를 지원한다.\n\n우선적으로, 자바스크립트 엔진에서 코드를 컴파일 하는 과정을 보면 다음과 같다.\n\n> * **토크나이징/렉싱** - 코드를 잘게 나누어 토큰으로 만든다.\n> * **파싱** - 나눈 토큰을 의미있게 AST(Abstract Syntax Tree)라는 트리로 만든다.\n> * **코드생성** - AST를 기계어로 만든다.\n\n렉시컬 스코프란 1단계에서 발생하는 즉, 렉싱 과정에서 정의되는 스코프를 말한다. \n**프로그래머가 변수와 스코프 블록을 어떻게 구성하는냐에 따라 렉싱 타임에서 정의되는 스코프를 렉시컬 스코프**라고 한다.\n\n```javascript\nvar x = 'global'\n\nfunction test1() {\n    var x = 'local';\n    test2();\n}\n\nfunction test2() {\n   console.log(x);\n}\n\ntest1(); //global\ntest2(); //global\n```\n\n위의 코드에서 `test2()`함수를 **어디서 호출하는지가 아닌 어디에 선언되어있냐에 집중**할 필요가 있다.\n\n즉, **`test2()`함수의 상위 스코프는 test1()과 전역이 아닌 전역**이다. 이에 따라 `test2()`에서 출력한 값은 'global'이 나올 것이다.\n\n쉽게 말하면, **렉시컬 스코프는 함수를 어디서 호출하는지가 아닌 어디서 선언했는지에 따라 결정**된다. 이러한 특성때문에 **정적 스코프(Static Scope)** 라고도 한다.\n\n## 전역 변수의 최소화\n\n전역 변수를 많이 쓰면 안좋다고 흔히들 말한다.\n그 이유를 알 수 있는 간단한 예를 보자.\n\n```javascript\nvar x = 100;\n\nfunction test() {\n    x = 10;\n    console.log('10이 나오겠지?', x);\n}\n\ntest();\nconsole.log('100을 출력해볼까 ?', x);\n\n/*\n10이 나오겠지? 10\n100을 출력해볼까 ? 10\n*/\n```\n\n**지역 스코프에서 전역변수를 참조할 수 있으므로** 전역변수의 값도 변경할 수 있다.\n\n**내부 함수의 경우에는, 전역변수는 물론 상위 함수에서 선언한 변수에 접근/변경이 가능**하다.\n\n프로젝트가 클수록, 협업이 이루어질수록 전역 변수가 많아지면 원하는 결과가 아닌 다른 결과가 나타날 수 있다.\n\n그렇다면 전역 변수를 줄이기 위한 방법에는 어떤 것들이 있을까?\n\n### 네임스페이스 패턴(Namespace Pattern)\n\n네임스페이스 패턴은 **말 그대로 이름 공간을 선언하여 다른 공간과 구분하는 패턴**이라고 보면 된다.\n\n```javascript\nvar APP_GLOBAL = {\n    name : 'BKJang',\n    age : '25',\n    getInfo : function() {\n        console.log('name :', this.name, 'age :', this.age);\n    }\n}\n\nconsole.log(APP_GLOBAL); //{name: \"BKJang\", age: \"25\", getInfo: ƒ}\nconsole.log(APP_GLOBAL.name, APP_GLOBAL.age); //BKJang 25\nAPP_GLOBAL.getInfo(); //name : BKJang age : 25\n```\n\n이처럼 **전역 변수 사용을 위해 전역 객체 하나를 만들어 사용**하는 것이다.\n\n하지만 네임스페이스 패턴을 사용했을 경우, 결국 전역 객체(`APP_GLOBAL`)의 `property`는 변경이 가능하다는 단점이 있다.\n\n### 즉시 실행 함수 표현식(IIFE, Immediately-Invoked Function Expression)\n\n즉시 실행 함수를 사용하면 **함수가 실행되고 전역에서 사라진다.** 이 방법으로 라이브러리를 많이 만들곤 한다.\n\n```javascript\n(function moduleFunction() {\n\n  var a = 3;\n  \n  function helloWorld(){\n    console.log('Hello');\n  }\n\n  helloWorld(); //Hello\n})();\n\nhelloWorld(); //Uncaught ReferenceError: helloWorld is not defined\n```\n\n즉시실행함수가 실행되고 전역에서 사라지기 때문에 그 밖에선 출력 값이 에러가 발생하는 것을 볼 수 있다. \n\n```javascript\nvar singleton = (function () {\n\n  var a = 3;\n  \n  function helloWorld(){\n    console.log('Hello');\n  }\n\n  return {\n    a : a,\n    sayHello: helloWorld\n  }\n})();\n\nsingleton.sayHello(); //Hello\nconsole.log(singleton.a); //3\n\n```\n\n위와 같이 **반환 값을 변수에 담아 전역 변수를 한 번 만 사용**하여 전역 변수의 사용을 줄일 수도 있다.\n\n#### Reference\n- [JavaScript: 네임스페이스 패턴(Namespace Pattern) 바로 알기](http://www.nextree.co.kr/p7650/)\n"
  },
  {
    "path": "Javascript/Some_Every.md",
    "content": "# Some과 Every\n\n흔히 javascript의 배열과 관련된 메서드로 map, filter, reduce를 생각한다.\n사실 이 세가지 아니 정확히는 reduce 하나만으로도 모든것을 구현할 수 있다.\n하지만 언제나 그렇듯 코드의 가독성과 생산성을 위해 다양한 메서드를 알고 있다면 유익하다.\n\n이번에 some을 이용해서 코드를 짜볼 기회가 있었어서 알아봤는데 every와 비슷한것 같았다. 자주 사용되지는 않지만 간단하고 꽤나 쓸모가 있는 Some과 Every를 알아봤다.\n\n## some\n\nsome은 배열의 요소가 특정 조건에 한번이라도 만족하는지 검사하는 메서드다.\n\nsome의 정의는 아래와 같다.\n\n> arr.some(callback[, thisArg])\n\n- callback\n  - currentValue // 현재값\n  - index (Optional) // 인덱스\n  - array (Optional) // array\n- thisArg (Optional) // this\n\n코드로 보자면 아래와 같다.\n\n```js\nvar array = [1, 2, 3, 4, 5];\n\nvar isThree = function(element) {\n  return element === 3;\n};\n\nconsole.log(array.some(isThree)); // true\n```\n\n한번이라도 조건을 만족하면 true다. 조건에 만족하면 그 즉시 true를 리턴한다. 위의 코드의 경우 2번 요소인 3까지만 callback이 실행되고 4부터는 실행되지 않는다.\n\n또한 map, filter와 비슷하게 호출한 배열을 변형하지 않는다.(side effect 최소화)\n\n## every\n\nevery는 some과 비슷하지만 좀 다르다. 배열의 요소가 특정 조건에 모두 만족하는지 검사하는 메서드다.\n\n> every.some(callback[, thisArg])\n\n- callback\n  - currentValue // 현재값\n  - index (Optional) // 인덱스\n  - array (Optional) // array\n- thisArg (Optional) // this\n\ncallback에 들어가는 요소도 동일하다.\n\n```js\nvar array = [10, 20, 30, 40, 50];\n\nvar overThirty = function(element) {\n  return element < 30;\n};\n\nconsole.log(array.every(overThirty)); // false\n```\n\n모든 요소가 조건을 만족하면 true다. 즉 모든 경우가 N번 실행되게 된다. some과는 반대로 조건에 만족하지 않으면 그 즉시 true를 리턴한다. 위의 코드의 경우 3번 요소인 40까지만 callback이 실행되고 50은 실행되지 않는다.\n\n이또한 map, filter와 비슷하게 호출한 배열을 변형하지 않는다.(side effect 최소화)\n\n### 결론\n\n실제로 내가 이렇게 사용하기도 했지만, 어떤 작업을 시작하기 전 혹은 작업을 마치고 난 후 null 체크나 값 확인용으로 사용하기 좋은 간단한 메서드다.\n\n---\n\n#### 참조\n\n- [MDN-Some](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/some)\n- [MDN-Every](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/every)\n"
  },
  {
    "path": "Javascript/Storybook.md",
    "content": "# Storybook\n\n프론트엔드에서 컴포넌트 단위로 개발을 진행하는 경우 해당 컴포넌트의 UI를 독립적으로 개발 및 테스트하며 작업하고자 한다면 어떻게 해야 할까? Storybook을 사용하면 원하는 방식으로 작업 할 수 있다.\n\nStorybook은 프론트엔드 UI 컴포넌트 개발 도구이다. React, Vue, Angular 등 컴포넌트 단위로 개발을 하는 프레임워크(혹은 라이브러리)에 적용하여 사용해볼 수 있다. Storybook을 사용하면 UI 테스트를 손쉽게 할 수 있으므로 테스팅 툴로서 많이 사용되고 있다.\n\n![Storybook 지원 범위](https://user-images.githubusercontent.com/16266103/103472343-e1651800-4dcf-11eb-959e-abd2411b3b5f.png)\n\n> 출처: [Storybook 공식 홈페이지](https://storybook.js.org/)\n\nReact를 기준으로 CRA(Create React App)환경에서 Storybook 구조와 사용법에 관해서 설명해보도록 하겠다.\n\n## Storybook 시작해보기\n\n```bash\n$ npx create-react-app <Project Directory>\n```\n\nStorybook을 시작하기에 앞서 CRA(Create React App)으로 새로운 React 프로젝트를 생성해보도록 하자.\n\n```bash\n$ cd <Project Directory>\n$ npx sb init\n```\n\n앞서 생성해둔 React 프로젝트 디렉토리로 이동한 뒤 `npx sb init` 명령어를 사용하면 Storybook 실행 환경이 자동으로 설정된다.\n\n![Storybook init 이후의 변화](https://user-images.githubusercontent.com/16266103/103472346-e3c77200-4dcf-11eb-8f47-471a73a8eee8.png)\n\n> `npx sb init` 이후의 변화\n\n명령어 실행 후에 `package.json`에 storybook 실행 및 빌드를 위한 `script`가 추가되었으며 `devDependencies`에 storybook 관련 의존성이 추가되었음을 확인할 수 있다. 또한 `.storybook` 폴더와 src폴더 내부에 `stories` 폴더가 생성되었다.\n\n```bash\n$ npm run storybook\n```\n\nStorybook 실행 환경 설정이 끝난 후  `npm run storybook` 명령어를 사용하면 Storybook을 실행해볼 수 있다.\n\n![Storybook 실행 화면](https://user-images.githubusercontent.com/16266103/103472348-e629cc00-4dcf-11eb-9dc8-2ea40d230d4d.png)\n\n> Storybook을  실행한 모습\n\nStorybook을 실행해보면 기존 프로젝트와 독립된 상태로 빌드되며 별도의 웹서버를 통해 실행되게 된다. 따라서 Storybook을 독립적으로 빌드하여 배포하는 것도 가능하다. 이러한 특성으로 UI 컴포넌트 테스트 외에도 UI 컴포넌트 문서화, QA 등에 유용하게 사용할 수 있다.\n\n```bash\n$ npm run build-storybook\n```\n\nStorybook을 빌드하기 위해서는 `build-storybook` 명령어를 사용할 수 있다. 해당 명령어를 실행할 경우 빌드 결과물인 `storybook-static` 폴더가 프로젝트 최상단에 생성된다.\n\n## Storybook 작성해보기\n\nCRA(Creat React App)으로 React 프로젝트를 생성할 경우 자동으로 만들어지는 App.js를 Storybook에서 확인해볼 수 있도록 해보자.\n\nStorybook에 각 컴포넌트를 연결하기 위해서는 `<filename>.stories.js` 와 같이 파일명과 확장자명 사이에 `stories` 문자열을 dot(`.`) 사이에 넣어주면 된다. Storybook 실행 환경 설정 시 만들어지는 `./src/stories` 폴더를 보면 `Button.stories.js`, `Header.stories.js`, `Page.stories.js` 이렇게 세 개의 예시를 확인해볼 수 있다.\n\n이제 `./src/App.stories.js` 파일을 만들어보자\n\n```javascript\n/* App.stories.js */\nimport React from \"react\";\n\nimport App from \"./App\";\n\nexport default {\n  title: \"App\",\n  component: App,\n};\n\nconst Template = () => <App />;\n\nexport const Default = Template.bind({});\n```\n\n내용을 위처럼 작성하고 저장 후 `npm run storybook` 으로 Storybook을 실행해보면 Storybook 사이드바에 App 항목이 생긴 것을 확인할 수 있다.\n\n![App.stories.js 추가 후 Storybook 실행 화면](https://user-images.githubusercontent.com/16266103/103472349-e75af900-4dcf-11eb-93fc-3bd7bdd98a6b.png)\n\n`export default { title: \"App\" ... };` 에서 title의 value에 해당하는 부분이 사이드바의 항목 이름이 된다.\n\n만약 계층을 설정하여 비슷한 항목을 묶고 싶은 경우 `export default { title: \"Main/App\" ... };` 와 같이 slash 로 구분하여 설정할 수 있다. 해당 작업은 `start-storybook` 를 재실행해야 제대로 반영된다.\n\n![Main 계층 추가 후 Storybook 실행 화면](https://user-images.githubusercontent.com/16266103/103472350-e7f38f80-4dcf-11eb-8e1b-661e0a4394cc.png)\n\n이번에는 `App.js`에 Props를 전달할 수 있도록 수정하고 Props에 따른 Storybook 항목을 생성해보자.\n\n```jsx\n/* App.js */\nimport logo from \"./logo.svg\";\nimport \"./App.css\";\n\nfunction App({ title = \"Learn React\" }) {\n  return (\n    <div className=\"App\">\n      <header className=\"App-header\">\n        <img src={logo} className=\"App-logo\" alt=\"logo\" />\n        <p>{title}</p>\n      </header>\n    </div>\n  );\n}\n\nexport default App;\n```\n\n`App.js` 에 `title` Props를 추가하고 기본값을 설정하였다.\n\n```javascript\n/* App.stories.js */\nimport React from \"react\";\n\nimport App from \"./App\";\n\nexport default {\n  title: \"Main/App\",\n  component: App,\n};\n\nconst Template = (args) => <App {...args} />;\n\nexport const Default = Template.bind({});\n\nexport const Test = Template.bind({});\nTest.args = {\n  title: \"Test\",\n};\n\nexport const Sentence = Template.bind({});\nSentence.args = {\n  title: \"Storybook 좋아요!\"\n};\n```\n\n`App.stories.js` 에 Props에 따라 각각 세 가지 경우에 대해 렌더링할 수 있도록 항목을 설정하였다.\n\n\n![Props 추가 후 Storybook 실행 화면](https://user-images.githubusercontent.com/16266103/103472351-e88c2600-4dcf-11eb-86a3-85b38f016efe.png)\n\n\n위 스크린샷과 같이 설정한 대로 각 Props를 설정한 항목들이 생성되는 것을 확인할 수 있다. 또한 하단에 있는 Add-on 사이드바의 Controls 탭에 Props에 대한 항목들이 생기게 된다. 각 Props 항목들을 변경할 경우 실시간으로 반영된다.\n\n\n## 마무리\n\n이번 글을 통해 Storybook이 무슨 목적을 위해 사용되는지, 어떻게 설정하는지에 대하여 설명해보았다. 나의 경우 Storybook이 생산성에 긍정적인 영향을 주어 최근 거의 모든 프로젝트마다 필수적으로 설정하여 사용하고 있다. 특히 팀원들(기획자, 개발자, 디자이너)간에 컴포넌트 개발 진행 상황을 손쉽게 공유할 수 있으므로 협업할 때 매우 유용하다.\n\n아쉽게도 아직 설명하지 못한 Storybook의 강력한 기능들이 많다. Storybook의 심화적인 부분에 대해서는 다음에 기회가 되면 다뤄볼 예정이다.\n\n#### References\n\n- [Storybook 공식 문서](https://storybook.js.org/docs/react/get-started/introduction)\n- [실용적인 프론트엔드 테스트 전략 (2)](https://meetup.toast.com/posts/178)\n"
  },
  {
    "path": "Javascript/Sync&Async_Multi&Single_Thread.md",
    "content": "# Sync & Async, Multi & Single Thread\n\n## Sync programming\n\n동기 프로그래밍은 쉽게 설명하자면 순차적인 프로그래밍을 이야기한다. 예를들어 파스타를 만들어보자.\n\n1. 물을 끓인다. (3분)\n2. 면을 넣고 10분동안 기다린다. (13분)\n3. 면을 체에 건진다. (13.5분)\n4. 마늘과 버섯을 알맞은 크기로 자른다. (15분)\n5. 팬에 올리브유를 두르고 마늘과 버섯을 넣고 볶는다. (18분)\n6. 면수와 치킨스톡을 넣고 기름과 섞은 뒤 면을 넣고 30초정도 볶아준다. (20분)\n\n1번이 끝나면 2번을 시작, 2번이 끝나면 3번을 시작해서 6번까지 순차적으로 실행하는 방식이 바로 동기 프로그래밍이다.\n\n## Async Programming\n\n비동기 프로그래밍은 동기의 반대인 순차적이지 않은것이다. 좀 더 정확히는 정해진 순서대로 일을 맡기고 기다리는 방식이다. 방금의 파스타 만들기를 비동기로 바꾸어보자.\n\n1. 물을 끓인다.\n2. 물이 끓는동안 마늘과 버섯을 자른다.\n3. 물이 끓으면 면을 넣고 10분동안 기다린다. (3분)\n4. 10분 기다리는 동안 팬에 올리브유를 두르고 마늘과 버섯을 볶는다.\n5. 면수와 치킨스톡을 넣고 기름과 섞는다.\n6. 면을 건진 뒤 만든 소스에 넣고 30초정도 볶아준다. (13.5분)\n\n동기의 상황과 순서는 조금 다르다. 하지만 본질은 같다. 큰 차이점은 시간이다. 그 이유는 전자는 물이 끓고 면을 삶는동안 기다렸고, 후자는 다른 작업을 했기 때문이다.\n\n전자는 물이 끓는동안 나는 할 일이 없다. 하지만 후자는 물을 끓이고 면은 삶아지게 일을 맡겨놓고 나는 다른 일을 처리한다. 다른일을 하다가 물이 끓으면 면을 넣고 다른일을 한다. 면이 다 삶아지면 건지고 또 다른일을 한다.\n\n---\n\n쓰레드에 대한 이야기를 해보자. 이제는 내가 푸드코트에서 일을 하게 되었다고 생각하자. 저 파스타를 10명이 1그릇씩 주문한다고 하자.\n\n## Multi-Thread\n\n멀티쓰레드는 주문을 받는 곳이 여러개다. 마치 대형마트의 계산대처럼 말이다. Sync와 Async 두가지 경우가 있을 것이다.\n\n만일 계산대가 4개라고 하자.\n\n### Multi & Sync\n\n- 1, 2, 3, 4번 손님을 각각 1, 2, 3, 4번 계산대에 보내 음식을 주문한다.\n- 손님은 계산대에서 음식이 다 완료될때까지 기다리고 음식이 나오면 자리로 간다.\n- 음식이 완료되어 계산대가 비게되면 5번 손님을 빈 계산대로 보낸다.\n\n### Multi & Async\n\n- 1, 2, 3, 4번 손님을 각각 1, 2, 3, 4번 계산대에 보내 음식을 주문한다\n- 주문이 완료되면 자리로 가 번호표를 받고 음식을 기다린다.\n- 계산이 완료되어 계산대가 비게되면 5번 손님을 빈 계산대로 보낸다.\n- 음식이 나오면 번호를 알려주고 음식을 받는다.\n\n## Single-Thread\n\n싱글쓰레드는 주문을 받는 곳이 한개다. 계산대가 하나인 것이다. 마찬가지로 Sync와 Async의 두가지 경우가 있을 것이다.\n\n### Single & Sync\n\n- 1번 손님을 계산대에 보내 음식을 주문한다.\n- 손님은 계산대에서 음식이 다 완료될때까지 기다리고 음식이 나오면 자리로 간다.\n- 음식이 완료되어 계산대가 비게되면 2번 손님을 빈 계산대로 보낸다.\n\n### Single & Async\n\n- 1번 손님을 계산대에 보내 음식을 주문한다\n- 주문이 완료되면 자리로 가 번호표를 받고 음식을 기다린다.\n- 계산이 완료되어 계산대가 비게되면 2번 손님을 빈 계산대로 보낸다.\n- 음식이 나오면 번호를 알려주고 음식을 받는다.\n\n정리하자면 멀티쓰레드는 10가지 업무를 나누어 처리하고 싱글쓰레드는 10가지 업무를 차례대로 처리한다.\n\n## 장단점\n\n멀티쓰레드\n\n- 여러가지 업무를 동시에 처리할 수 있다. 따라서 빠른 업무가 가능하고 기다림이 적다.\n- 계산대에 모두 손님을 보내고 남은 사람들이 한줄서기처럼 기다린다면, 빈 계산대를 찾아 보내주는 관리자가 필요하다.\n- 공유 자원이 있다면 관리가 필요하다. 이를 block / lock이라고 한다.\n\n싱글쓰레드\n\n- 순차적이라 복잡하지 않고 block과 관리비용이 없다.\n- 다만 한번에 하나밖에 못한다.\n\n## Javascript\n\n자바스크립트는 싱글쓰레드에 Async 방식을 사용한다.\n\n작업공간인 쓰레드는 하나지만 Async를 사용하여 시간을 공유한다. 면이 삶아지는 동안 소스를 만드는 것처럼 시간을 공유하는 것이다.\n\n기본적으로 자바스크립트에서는 event를 이용해 Async를 구현한다. 화면을 클릭하거나 스크롤, 사용자의 입력, 화면의 사이즈 등 event가 발생하면 callback을 실행한다.\n\n또한 AJAX와 같은 기술로 외부와 통신한다던가 하는 작업을 비동기로 처리한다.\n\n그래서 유명한 다음 그림이 나온다.\n\n![javascript_execute](/assets/images/Sync&Async_Multi&Single_Thread_1.jpg)\n\n이를 더 자세히 보려면 이제 이벤트루프에 대한 개념이 필요하다. 이는 [eventLoop](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/EventLoop.md) 에서 설명한다.\n"
  },
  {
    "path": "Javascript/TimeInJS.md",
    "content": "# Time in JS\n\njs를 사용하여 시간을 측정해야하는 경우가 있다.\n\n예를 들어 내 코드가 얼마만큼의 시간을 사용했는지 알고 싶은 경우다.\n또 [쓰로틀링](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/throttling%EA%B3%BC%20rAF.md)처럼 몇 초 동안 이벤트가 한 번만 발생하게 만들어야 하는 경우도 있다.\n\n물론 프론트의 js 코드에서는 엄청 정밀한 시간이 필요한 경우가 많지는 않다.\n하지만 정확도 높은 시간을 사용한 코드는 언제 어떻게 실행되어도 동일하게 동작한다는 것을 보장한다. 품질이 좋아진다.\n\n따라서 시간을 측정하는 방법을 알아둘 필요가 있다.\n\njs에서 시간을 측정하는 방법은 크게 4가지가 존재한다.\n\n- Date.now\n- console.time\n- process.hrtime (nodeJS)\n- performance\n\n## Date.now\n\nDate는 가장 고전적이며 쉽게 접근할 수 있는 API다.\n\nDate.now를 사용하면 1970년 1월 1일 0시 0분 0초부터 현재까지 경과된 밀리 세컨드(milliseconds)를 Number 타입으로 반환한다.\n\n특정 코드 이전과 이후에 Date.now를 사용하면 그 코드의 실행 시간을 알 수 있다.\n\n```js\nconst start = Date.now();\n\nlet arr = ['1'];\nfor (let i = 0; i < 10000000; i++) {\n  arr.push('' + i);\n}\n\nconst end = Date.now();\n\nconsole.log((end - start) / 1000);\n```\n\nDate.now 메서드는 시스템 시간을 기준으로 현재 타임스탬프를 받는다. 그래서 user agent에 따라 다를 수 있어 신뢰성이 떨어진다.\n\n## console.time\n\n이걸 사용하면 Date.now보다 간편하게 이용할 수 있다.\n\n```js\nconsole.time('pushTest');\n\nlet arr = ['1'];\nfor (let i = 0; i < 10000000; i++) {\n  arr.push('' + i);\n}\n\nconsole.timeEnd('pushTest');\n```\n\npushTest라는 label을 붙일 수 있다.\n\n하는 일은 동일하다. console 객체에 있는 profile과 같은 메서드를 사용하여 dev tools에서 더 다양한 정보를 볼 수도 있다.\n\n![devtools-profiler](https://user-images.githubusercontent.com/24724691/59844588-4136d200-9396-11e9-9246-202df143ab0f.PNG)\n\n## process.hrtime\n\nnodejs에서는 위의 두가지 방법보다 더욱 정밀한 방법으로 process.hrtime를 제공한다.\n\n이는 nanoseconds까지 정확히 측정가능하며 [clock drift](https://en.wikipedia.org/wiki/Clock_drift) free하다.\n\n```js\nconst hrstart = process.hrtime();\n\nlet arr = ['1'];\nfor (let i = 0; i < 10000000; i++) {\n  arr.push('' + i);\n}\n\nconst hrend = process.hrtime(hrstart);\n\nconsole.log(hrend);\n//[2, 488580674]\n```\n\nhrtime은 반환값이 array인데 각각 [seconds, nanoseconds]다.\n\n## performance\n\n브라우저에서는 μs라고 표기하는 마이크로 세컨드까지 정확한 API를 제공한다. 이 performance는 시스템 clock과는 무관하다.\n\nconsole.time의 ms는 밀리세컨드로 1s / 1000 이다.\nperformance에서 제공하는 μs는 1ms / 1000 이다.\n\n사용방법은 Date.now와 동일하다.\n\n```js\nconst start = performance.now();\n\nlet arr = ['1'];\nfor (let i = 0; i < 10000000; i++) {\n  arr.push('' + i);\n}\n\nconst end = performance.now();\n\nconsole.log((end - start) / 1000);\n```\n\nperformance.now의 반환값은 DOMHighResTimeStamp다. 이는 ms(밀리 세컨드)인데 소수점을 포함한다. 따라서 마이크로 세컨드까지 정확하다.\n\nperformance.now가 측정되는 시간은 [performance.timing.navigationStart](https://www.w3.org/TR/navigation-timing/#dom-performancetiming-navigationstart)부터다.\n이 시간은 이전 document가 unload되며 새로운 document를 fetch하는([fetchStart](https://www.w3.org/TR/navigation-timing/#dom-performancetiming-fetchstart)) 시점이다.\n\n브라우저에서 제공하는 방법들은 web worker를 사용한다. 현재 performance가 그 중에 가장 정확한 시간을 측정할 수 있다.\n\n---\n\n### 참고자료\n\n- [Measurement of Node.js execution time](https://blog.abelotech.com/posts/measure-execution-time-nodejs-javascript/)\n- [Measuring Execution Times in JavaScript with console.time()](https://mariusschulz.com/blog/measuring-execution-times-in-javascript-with-consoletime)\n- [Discovering the High Resolution Time API](https://www.sitepoint.com/discovering-the-high-resolution-time-api/)\n- [When milliseconds are not enough: performance.now](https://developers.google.com/web/updates/2012/08/When-milliseconds-are-not-enough-performance-now)\n- [performance.now()-mdn](https://developer.mozilla.org/ko/docs/Web/API/Performance/now)\n"
  },
  {
    "path": "Javascript/Variable.md",
    "content": "# 자바스크립트의 변수\n\n## 자바스크립트의 실행\n\n자바스크립트가 브라우저에서 해석될 때, 해당 자바스크립트가 실행되기 위한 최소한의 메모리를 확보하는 과정을 거친다.\n이 과정에서 자바스크립트 변수는 [호이스팅](https://bkjang.github.io/Variables_and_DataTypes/) 과정을 거친다.\n\n그렇다면 변수가 선언됐을 때 자바스크립트에서 어떤 과정이 일어나는지 살펴보자.\n\n### 선언\n\n값을 할당하지 않고 **선언만 하는 과정**을 거친다.\n\n`var a;`에서 자바스크립트 엔진은 데이터의 공간을 만들고 그 공간에 a라는 이름을 붙인다.\n\n### 초기화\n\n이 단계에서 변수는 `undefined`로 초기화된다.\n\n### 할당\n\n`undefined`로 초기화된 변수에 **값을 할당하는 과정**이다. `var a = '';`에서 **a라는 변수에 ''를 할당한다**고 한다.\n\n## let\n\n### 호이스팅\n\n이쯤에서 **변수의 호이스팅(Hositing)** 의 개념을 알고 넘어갈 필요가 있다.\n\n이전에 스코프에 대해 간략히 설명하면 `var`를 이용하여 선언한 자바스크립트의 변수는 기본적으로 **함수형 스코프**를 가진다. 하지만 ES6에서부터는 `let`과 `const`를 이용하여 블록 레벨 스코프를 사용할 수 있다.\n\n자바스크립트는 변수의 선언부를 해당 스코프의 가장 위로 끌어올린다. 이는 함수형 스코프든 블록 레벨 스코프든 동일하다.\n\n코드로 살펴보자.\n\n```javascript\nconsole.log(x);\n\nvar x = 1000;\n\nconsole.log(x);\n\n/*\nundefined\n1000\n*/\n```\n위의 출력 결과를 보면 가장 첫 줄의 `console.log(x)`는 에러가 나야할 것 같지만, undefined로 출력이 된다.\n이는 자바스크립트에서의 호이스팅이라는 개념으로 인해 변수의 선언부가 최상위로 끌어올려져서 나타나는 현상이다.\n즉, 자바스크립트에서는 위와 같은 코드를 다음과 같이 해석한다.\n\n```javascript\nvar x;\n\nconsole.log(x);\n\nx = 1000;\n\nconsole.log(x);\n\n```\n\n여기서 많은 개발자들이 착각하고 있는 부분이 있다. \n\n**'`let`으로 선언된 변수는 호이스팅 과정을 거치지 않는다'** 라는 것이다.\n\n하지만 이것은 틀린 말이다. 자바스크립트 파일의 메모리를 할당하는 과정이 필요하기 때문에 호이스팅이 발생한다.\n\n![ES6](https://bkdevlog.netlify.app/assets/img/TDZ.jpg)\n\n위 그림에서 보면 알 수 있듯이 `let`으로 선언되면 초기화 단계 이전에 `TDZ(Temporal Dead Zone)`에 빠지게 된다. 아래 예제를 살펴보자.\n\n```js\n//ES5(var)\nconsole.log(a); //undefined\n\nvar a = 1;\n\nconsole.log(a); //1\n```\n\n```js\n//ES6(let)\nconsole.log(b); //Reference Error: b is not defined\n\nlet b = 1;\n\nconsole.log(b);\n```\n\n위의 예제에서 볼 수 있듯이 `let`으로 선언한 변수를 그 이전에 사용하려고 하면 `Reference Error`가 발생한다. 이를 보면 호이스팅이 발생하지 않는다고 보일 수 있다.\n\n하지만, 호이스팅이 일어나 메모리 공간을 확보한 뒤, **일시적 사각지대(TDZ)** 에 빠져있는 상태이기 때문에 `Reference Error`가 발생하는 것이다.\n\n`TDZ`와 관련하여 좀 더 자세히 잘 설명해놓은 글을 함께 소개하도록 하겠다.\n\n- https://ui.toast.com/weekly-pick/ko_20191014/\n\n### 블록레벨 스코프\n\n`var`는 **함수레벨 스코프**라면 `let`은 **블록레벨 스코프**를 지원한다.\n\n즉, `var`로 선언한 변수는 함수 내에 선언하지 않고 `if`나 `for`와 같은 블록 내에서 선언하면 전역(window) 스코프에 할당된다.\n\n반면, `let`으로 선언한 변수는 `if`나 `for`와 같은 블록 내에서 선언을 하면 전역이 아닌 해당 블록 내의 스코프에 할당된다.\n\n```js\n//ES5(var)\nif(true) {\n    var result = 'helloWorld';\n}\n\nconsole.log(result); //helloWorld\n```\n\n```js\n//ES6(let)\nif(true) {\n    let result = 'helloWorld';\n}\n\nconsole.log(result); //ReferenceError: result is not defined\n```\n\n`if`문 내에서 `let`으로 선언한 변수는 `var`와 다르게 **블록 내의 지역 변수**로 할당 되기 때문에 블록 외부에서는 이를 호출하면 `Reference Error`가 발생하게 된다.\n\n### 변수 중복 선언 불가\n\n`let`으로 선언한 변수는 중복 선언이 불가하다.\n\n`var`로 선언한 변수는 **같은 레벨에서 재선언이 가능**하지만, `let`으로 선언한 변수를 **같은 레벨 내에서 다시 선언하면 에러가 발생**한다.\n\n```js\n//ES5(var)\nvar result = 'hello';\nvar result = 'world';\n\nconsole.log(result); //world\n```\n\n```js\n//ES6(let)\nlet result = 'hello';\nlet result = 'world'; \n\n//Uncaught SyntaxError: Identifier 'result' has already been declared\n```\n\n### 클로저(Closure)\n\n`var`를 사용할 때 보다 `let`을 사용할 때 직관적이고 편하다고 생각할 수 있는 대표적인 예가 루프안에서 클로저를 구현할 때다.\n\n```js\n//ES5(var)\nfunction count(number) {\n    for(var i=1; i <= number; i++) {\n        (function (j) {\n            setTimeout(function(){\n                console.log(j);\n            }, i*1000)\n        }(i))\n    }\n}\n\ncount(4);\n/*\n1\n2\n3\n4\n/*\n```\n\n즉시 실행 함수를 실행시켜 루프의 `i` 값을 `j`에 복사하고 `setTimeout()`함수에서 사용했다.\n이 때 **`j`는 상위스코프의 자유변수이므로 그 값이 유지**된다.\n\n위처럼 구현하는 이유는\n\n```js\nfunction count(numberOfCount) {\n    for(var i=1; i <= numberOfCount; i++) {\n        setTimeout(function(){\n            console.log(i);\n        }, i*1000)\n    }\n}\n\ncount(4);\n/*\n5\n5\n5\n5\n*/\n```\n이와 같이 구현했을 때 결과는 예상과 다르게 **5가 4번 1초 간격으로 출력**되기 때문이다.\n\n이는 for 루프의 초기문에서 사용된 변수는 **함수 레벨 스코프**로 인해 **전역 변수로 할당**되기 때문에 문제가 발생하기 때문이다.\n\n```js\n//ES6(let)\nfunction count(numberOfCount) {\n    for(let i=1; i <= numberOfCount; i++) {\n        setTimeout(function(){\n            console.log(i);\n        }, i*1000)\n    }\n}\n\ncount(4);\n/*\n1\n2\n3\n4\n*/\n```\n\n하지만 `let`은 **블록 레벨 스코프**를 가지기 때문에 변수 `i`는 for문 블록 내의 **지역 변수로 할당**이 된다.\n\n따라서 위와 같이 간단하게 원하는 결과를 출력할 수 있다.\n\n## const\n\n### 재할당 불가\n\n`const`는 상수 즉, **변하지 않는 값**을 선언하기 위해 사용한다.\n\n이에 따라 `const`로 선언된 변수는 `var`나 `let`으로 선언된 변수처럼 **재할당이 불가능**하다.\n\n```js\nconst FOO = 123;\n\nFOO = 234;\n//Uncaught TypeError: Assignment to constant variable.\n```\n\n위 처럼 `const`로 선언된 변수에 다른 값을 재할당하려하면 에러가 발생한다.\n\n### 블록레벨 스코프\n\n`const`로 선언된 변수 또한 `let`으로 선언된 변수처럼 블록 레벨 스코프를 가진다.\n\n### 객체의 할당\n\n`const`로 선언된 변수는 위에서 말한 것처럼 재할당이 불가능하다.\n\n하지만, `const`로 선언된 변수의 값이 객체로 할당이 된 경우, **객체 자체를 재할당하는 것은 불가능**하지만 **객체의 프로퍼티 값은 보호되지 못한다.**\n\n```js\nconst Developer = {\n    name : 'BKJang',\n    age : 25,\n    lang : 'Javascript'\n}\n\nDeveloper.lang = 'Java';\n\nconsole.log(Developer); //{name: \"BKJang\", age: 25, lang: \"Java\"}\n\nDeveloper = {\n    name : 'BKJang',\n    age : 25,\n    lang : 'Java'\n}\n//Uncaught TypeError: Assignment to constant variable.\n```\n\n> 위 내용들을 살펴보았을 때, `let`과 `const`가 있는데 왜 `var`가 존재하는지 의문이 생길 수 있을 것 같다.   \n> `let`과 `const`는 `var`가 가지고 있던 단점들을 보완하기 위해 ES6(ECMA2015)부터 등장하게 된 새로운 문법이며 새로운 개발을 진행하게 될 때 `var`를 사용할 일은 아마도 없을 것 같다.\n\n#### Reference\n\n- [let & const](https://jaeyeophan.github.io/2017/04/18/let-const/)\n- [ES6 let,const 알아보기](http://takeuu.tistory.com/86)\n- [let, const와 블록 레벨 스코프](https://poiemaweb.com/es6-block-scope)\n\n"
  },
  {
    "path": "Javascript/WebRTC.md",
    "content": "# WebRTC\n\nWebRTC(Web Real-Time Communication)는 Google이 시작한 오픈소스 프로젝트로 별도의 플러그인이나 소프트웨어 없이 Web과 Android, iOS 등에서 p2p 방식으로 음성, 영상 혹은 텍스트 같은 데이터를 주고받을 수 있게 만든 기술이다.\n\nWebRTC 이전에 Real-time Communication에 사용되던 HLS(HTTP Live Streaming)의 경우 보안이 취약하고 Latency가 느린 문제가 있었다.  Active X, Flash 또한 여러 단점들이 존재했다. WebRTC는 이렇듯 기존에 사용되던 기술들의 문제점을 해결하기 위해 탄생하였다.\n\nWebRTC의 라이센스는 BSD이며 국제 인터넷 표준화 기구 프로토콜 표준화 작업을, W3C가 API정의를 진행하였다.\n\nWebRTC는 서로 상호 작용하는 API들과 Protocol들로 구성되어 있다. Google에서 제공하는 [Adapter.js](https://github.com/webrtcHacks/adapter) 라이브러리를 사용하게 되면 플랫폼 간 WebRTC 구현의 차이점으로 인한 호환성 문제가 해결된 상태로 개발할 수 있다. 해당 라이브러리는 [npm package](https://www.npmjs.com/package/webrtc-adapter) 형태로도 제공된다.\n\n## WebRTC API\n\nWebRTC에는 다음과 같은 세 종류의 API가 구현되어 있다.\n\n- MediaStream(GetUserMedia)\n   - 카메라와 마이크에 접근하여 하나의 스트림으로 비디오, 오디오의 Track들을 동기화해주는 역할\n- RTCPeerConnection\n   - 각 Peer 간 오디오, 비디오 통신을 활성화하고 신호처리, 코텍 관리, P2P 통신, 보안, 대역폭 관리 등을 수행\n   - 각 Peer 간의 커넥션은 해당 인터페이스를 이용하여 수신자와 발신자를 등록하여 MediaStream과 RTCDataChannel을 커넥션에 연결할 수 있음\n   - 각 Peer 간의 데이터를 효율적이고 안정적으로 통신하게 처리하는 기능을 제공\n- RTCDataChannel\n   - 각 Peer 간에 데이터(JSON/text)를 처리하는 채널을 추상화하여 API 형태로 제공\n   - 웹 소켓 API와 유사한 메소드와 이벤트로 설계된 유연하고 강력한 솔루션\n\n## WebRTC 동작 흐름\n\n### 1. Fetching\n\nMediaStream(GetUserMedia) API를 사용하여 영상 및 음성 정보를 가져온다.\n\n### 2. Signaling\n\nSignaling은 서로 다른 네트워크에 있는 각 peer끼리 Session Description 정보를 교환하여 p2p가 형성되도록 연결하는 과정이다. 이를 통해 IP, Port, Video, Audio 코덱 정보를 주고받아서 정상적인 기능을 수행한다.\n\nSignaling은 다음과 같은 세 종류의 정보를 교환한다.\n\n- Network Configuration\n   - ICE(Interactive Connectivity Establishment)를 사용해 Candidate(IP, Port)를 찾음\n   - IP 주소와 Port 교환\n- Media Capabilities\n   - SDP(Session Description Protocol) 형식의 blob인 offer와 answer를 주고받음\n   - SDP는 p2p로 서로 간 주고받을 코덱 해상도 등의 데이터를 이해하는데 사용되는 메타데이터\n   - 웹 브라우저 간 호환 가능한 코덱들과 해상도를 교환\n- Session Control Messages\n   - 통신의 초기화, 종료 및 Error 리포트를 교환\n\n이러한 프로세스를 Signaling이라고 하며 Signaling을 진행하기 위해서는 Signaling 서버가 필요하다. WebRTC 표준에 Signaling은 정의되어 있지 않아 임의로 개발해야 한다. Signaling 서버의 동작 순서는 다음과 같다.\n\n![](https://www.hellonms.net/upload/image/2016/09/09/17/55/41009_32.PNG)\n\n> 출처: https://www.hellonms.net/blog.do?mode=view&startNo=0&bbs_id=8\n\n#### 2.1 Media Capability(SDP) + Session Control Message 교환\n\nSignaling 프로세스는 call을 하는 유저가 Offer를 만들면서 시작된다. 해당 Offer는 세션 정보를 SDP(Session Description Protocol) 포맷으로 callee에게 전달된다. callee는 caller에게 SDP Description을 포함한 Answer 메시지를 보낸다. 현시점에서 A와 B는 어떤 코덱들과 어떤 Video Parameter들이 사용되는지 알게 된다. 하지만 여전히 미디어 데이터 자체를 전송하지 못한다.\n\n1. B가 RTCPeerConnection.createOffer를 호출해 Offer SDP를 생성\n2. B가 Offer SDP를 Signaling Server를 사용하여 전송\n3. A는 Signaling Channel에서 Offer SDP를 받아, RTCPeerConnection.setRemoteDescription을 수행\n4. A의 RTCPeerConnection 객체는 상대 Session에 대한 정보를 알고 있게 되었고, RTCPeerConnection.createAnswer를 호출하여 Answer SDP를 생성하여 Signaling Channel을 통해 B에게 전달\n5. B도 마찬가지로 자신의 RTCPeerConnection.setRemoteDescription을 호출해, 전달받은 Answer SDP를 등록\n6. A, B 각 측에서 setRemoteDescription이 성공적으로 수행되었다면, 각 브라우저에서는 서로의 peer에 대해 인지하고 있는 상태이므로 p2p 연결이 성공적으로 완료 \n\n#### 2.2 Network Configuration(ICE Candidate) 교환\n\n상대 Peer와 연결하기 위해 통신할 수 있는 네트워크 정보인 ICE Candidate를 교환해야 한다. ICE(Interactive Connectivity Establishment)는 p2p 간 직접적인 통신을 위한 기술로 서로의 기기와 통신하기 위해 최적의 경로를 찾을 수 있도록 도와준다.\n\nSDP를 결정한 후에는 ICE Candidate들을 교환하기 시작하며 여러 경로 중 최고의 ICE를 결정한다.\n\nICE는 연결에 사용할 수 있는 모든 가능한 IP 후보군(사설 IP, STUN이 돌려주는 공인 IP)들을 조사하고, Peer 간 직접 연결을 맺을 수 있는지를 확인하는 기술이다. 연결 테스트를 위해 SDP(Session Description Protocol)를 사용하여 미디어 패킷을 흘려보내며 연결 가능 여부를 테스트한다.\n\n각 Peer는 검색되는 순서대로 Candidate를 보내고, 이미 스트리밍이 시작됐다 하더라도 모든 가능한 Candidate가 전송 될 때까지 계속 보낸다.\n\nSDP를 결정한 후에는 ICE Candidate들을 교환하기 시작하며 여러 경로 중 최고의 ICE를 결정하게 한다. 이 과정 때문에 이미 미디어 스트리밍이 시작됐다고 하더라도 연결 초반에는 영상 품질이 낮을 수 있다.\n\nICE Candidate의 절차는 다음과 같다.\n\n1. RTCPeerConnection Object를 새롭게 생성하고 RTCPeerConnection.onicecandidate 핸들러를 통해 현재 내 Client의 ICE Candidate가 확보되면 실행될 Callback을 전달\n2. 내 Client의 ICE Candidate가 확보되면, 중간 매개자인 Signaling 서버를 통해 상대 Peer에게 Serialized 된 ICE Candidate정보를 서로에게 전송\n3. 상대 Peer의 ICE Candidate가 도착하면, RTCPeerConnection.addIceCandidate를 통해 상대 Peer의 네트워크 정보를 서로가 각각 등록\n\n### 3. Connection\n\nSignaling으로 상대방의 정보가 포함된 RTCPeerConnection을 얻게 되면 연결이 성공적으로 이루어진 것이다.\n\n### 4. Communication\n\nWebRTC를 통해서 각 Peer 간에 주고받는 데이터는 크게 아래의 두 가지 형태이다.\n\n1. 비디오와 오디오 데이터 Stream\n2. 직렬화된 텍스트 데이터\n\n각 Peer들의 연결이 이루어지기 전에 데이터 Stream이나 채널을 미리 준비하고, 연결이 완료되면 데이터를 받았을 때의 callback을 통해 받은 데이터를 처리하게 된다. 조금 더 자세한 내용은 다음과 같다.\n\n#### 4.1 비디오와 오디오의 데이터 Stream\n\n- 전달하는 입장\n   - MediaStream(GetUserMedia) API 등으로 비디오와 오디오 데이터 Stream source를 취득해 RTCPeerConnection을 생성할 당시에 데이터 stream 채널을 연결할 수 있도록RTCPeerConnection.addTrack() 사용\n   - Signaling을 통한 연결이 이루어지기 전에 미리 설정이 되어야 함\n\n- 받는 입장\n   - RTCPeerConnection.ontrack의 callback을 커스텀하게 설정해서, connection이 성공적으로 이루어진 후에 상대방의 Track (비디오와 오디오 Stream)이 감지되면 어떤 동작을 할지 설정할 수 있음\n   - 보통 받은 Track의 데이터 Stream을 DOM의 `<video srcObject={[Stream]}/>` 에 연결\n\n#### 4.2 직렬화된 텍스트 데이터\n\n- 전달하는 입장\n   - RTCPeerConnection.createDataChannel을 통해 특정 이름의 데이터 전달 채널을 개설할 수 있음\n   - Signaling을 통한 연결이 이루어지기 전에 미리 설정이 되어야 함\n\n- 받는 입장\n   - RTCPeerConnection.ondatachannel의 callback을 커스텀하게 설정해서, connection이 성공적으로 이루어진 후에 상대방이 Data channel을 통해 어떤 데이터를 보냈을 때의 동작을 설정할 수 있음\n\n## ETC\n\n### 1. Signaling 단계에서의 STUN과 TURN의 역할\n\n보통 클라이언트는 사설 IP주소를 사용하는 내부 호스트인데 P2P로 연결 요청하면 NAT/Firewall에서 막혀서 응답을 받을 수 없다. Signaling 단계에서 이와 같은 상황이 발생할 경우 TURN 혹은 STUN을 이용해 문제를 해결할 수 있다.\n\n![](https://i.stack.imgur.com/rqnKf.png)\n\n> 출처: https://stackoverflow.com/questions/55670149/webrtc-does-server-or-another-peer-see-my-internal-ip-address\n\n#### 1.1 STUN(Session Traversal Utilities for NAT)\n\n![](http://io13webrtc.appspot.com/images/stun.png)\n\n> 출처: http://io13webrtc.appspot.com/images/stun.png\n\nWebRTC의 p2p 연결을 위해 NAT/Firewall 뒷 단의 클라이언트들은 사설 IP를 내부에서 보유하고 있다. 이럴 경우 외부 통신을 위해 자신의 공인 IP 정보를 스스로 파악하여 서로에게 알려주어야 한다. 이때 사설 IP를 보유한 장비들의 공인 IP 정보를 알려주어 접근할 수 있도록 해주는 서버가 STUN(Session Traversal Utilities for NAT)이다.\n\n#### 1.2 TURN(Traversal Using Relays around NAT)\n\n![](https://t1.daumcdn.net/cfile/tistory/2409CF4D58B638E20E)\n\n> 출처: https://www.html5rocks.com/ko/tutorials/webrtc/basics/#toc-rtcpeerconnection\n\n공인 IP 간 연결을 테스트해보고 연결할 수 있으면 WebRTC 클라이언트들은 p2p 연결이 된 것이지만, 만약 연결이 실패한다면 인터넷상의 중계 서버(Relay Server)를 사용해야 하는데, 이 서버가 TURN(Traversal Using Relays around NAT) 서버이다.\n\nTURN 서버는 STUN 서버를 이용한 연결이 실패했을 경우 오디오, 비디오 등의 데이터를 릴레이 해주는 역할을 한다. TURN 서버를 통해 모든 정보를 중계하게 되기 때문에 대안이 전혀 없는 경우에만 사용하는 것이 좋다.\n\n### 2. Web Topologies\n\n![](https://miro.medium.com/max/2000/0*VketTspbtHNGP9ho.png)\n\n> 출처: https://medium.com/@khan_honney/5-reasons-to-prefer-ant-media-server-over-sfu-bbea131807f\n\n#### 2.1 Mesh(p2p)\n\nMesh Topology 방식은 Session의 각 Peer가 서버를 사용하지 않고 다른 모든 Peer와 직접 연결하는 방식이다. 이런 종류의 연결은 비용이 가장 적고 쉽기 때문에 작은 규모의 화상 회의에서 적절하다. 그러나 컨퍼런스가 커질 경우 CPU 사용량이 많아지거나 네트워크 지연이 발생할 수 있기 때문에 모든 참가자 간의 연결 유지에 어려움을 겪을 수 있다.\n\n#### 2.2 MCU(Multipoint Control Unit)\n\nMCU Topology 방식은 Session의 각 참가자가 다중 연결 제어장치(MCU) 역할을 하는 서버에 연결하는 방식이다. 각 참가자로부터 받은 미디어를 단일 스트림으로 합친 다음 각 클라이언트에게 제공한다. 서버 측면에서 대역폭 사용량과 Downstream 연결에서 CPU 점유율의 여유를 가져올 수 있지만, 오디오와 비디오 미디어를 단일 Stream으로 합치기 위한 CPU 할당이 필요하게 된다.\n\n가장 낮은 대역폭이기 때문에 네트워크 조건이 좋지 않을 때 유리하다. 또한 위상의 제한이 없어 다수의 참가자 연결에 적절하다. 하지만 미디어를 서버에서 다루는 과정에서 Latency가 높아질 수 있다.\n\n#### 2.3 SFU(Selective Forwarding Unit)\n\nSFU Topology 방식은 Session의 각 참가자가 SFU(Selective Forwarding Unit) 역할을 하는 서버에 연결하는 방식이다. 각 참가자는 암호화된 비디오 Stream을 서버에 업로드하고 서버는 Stream을 다른 참가자들에게 전달한다.\n\n클라이언트 측에선 하나의 Upstream 연결만이 존재하므로 Mesh Topology 방식보다 업로드 효율이 높다. 이러한 특징으로 인해 Mesh Topology 방식보다 더 많은 참가자를 수용할 수 있다.\n\n---\n\n#### Reference\n\n- [MDN: WebRTC API](https://developer.mozilla.org/ko/docs/Web/API/WebRTC_API)\n- [WebRTC 이해하기](https://usinuniverse.bitbucket.io/blog/webrtc.html)\n- [Getting Started with WebRTC](https://www.html5rocks.com/ko/tutorials/webrtc/basics/)\n- [2018 webRTC 정리](http://jaynewho.com/post/36)\n"
  },
  {
    "path": "Javascript/Web_Storage_API.md",
    "content": "# Web Storage API\n\n개발을 진행하다가 클라이언트에서 특정 값을 저장해야 하는 기능 구현 필요성이 생겼다면 어떻게 해야 할까? 쿠키를 사용할 경우 생성할 수 있는 개수 및 데이터 크기 등의 제약 사항이 생길 수 있다. Web Storage API를 사용하게 되면 앞서 의도한 목적에 맞게 기능을 구현할 수 있다.\n\n쿠키의 경우 서버와 효율적으로 통신하기 위해 탄생했다. 실제로 쿠키는 HTTP 헤더에 담겨 서버와 클라이언트가 서로를 식별하는 인증 과정을 위해 가장 많이 사용된다.\n\n이와 다르게 Web Storage는 클라이언트 로컬 영역에만 값을 저장한다. 또한 서버가 HTTP 헤더로 값을 조작할 수 없다. 오로지 자바스크립트로만 Web Storage의 값을 제어할 수 있다.\n\nWeb Storage로 저장되는 값은 Key, Value로 이루어진 객체 형태이며 대부분의 브라우저에서 최소 2MB 이상의 객체를 저장할 수 있다. 4KB밖에 저장하지 못하고 개수 제한이 있는 쿠키와 비교했을 때 Web Storage는 값을 저장하는 용도로 좀 더 적합하다고 볼 수 있다.\n\nWeb Storage를 [지원 가능한 브라우저 목록](https://caniuse.com/namevalue-storage)은 아래와 같으며 W3C와 WHATWG에서 표준을 정의하고 있다.\n\n<img width=\"1358\" alt=\"Screen Shot 2020-11-22 at 1 14 39 PM\" src=\"https://user-images.githubusercontent.com/16266103/99893582-b2ce2a80-2cc4-11eb-8715-207d9df35b32.png\">\n\n> 출처: https://caniuse.com/namevalue-storage\n\n## 1. 공통 프로퍼티\n\nWeb Storage는 Local Storage와 Session Storage로 나뉜다. 두 Storage는 동일한 메서드와 프로퍼티를 제공하는데 이는 아래와 같다.\n\n- `setItem(key, value)` – 키-값 쌍을 보관\n- `getItem(key)` – 키에 해당하는 값을 받아옴\n- `removeItem(key)` – 키와 해당 값을 삭제\n- `clear()` – 모든 것을 삭제\n- `key(index)` – 인덱스(`index`)에 해당하는 키를 받아옴\n- `length` – 저장된 항목의 개수를 얻음\n\nWeb Storage에 저장되는 key와 value는 모두 String이어야 한다. 숫자나 객체를 넣을 경우 자동으로 문자열로 변경된다.\n\n## 2. Local Storage\n\nWeb Storage는 기본적으로 쿠키와 동일하게 오리진(domain/port/protocol)에 따라 값에 대한 접근이 제한된다. Local Storage의 경우 특정 오리진에 저장된 데이터가 있더라도 다른 오리진에서 접근할 수 없다. 오로지 오리진이 같아야만 해당 데이터에 접근할 수 있다.\n\nLocal Storage는 아래와 같이 setItem 메소드를 통해 key와 value를 지정하여 데이터를 설정할 수 있다.\n\n```javascript\nlocalStorage.setItem('id', 'dididy');\n```\n\nLocal Storage에 저장된 데이터를 가져오기위해서는 아래와 같이 getItem 메소드의 매개변수로 가져오고 싶은 key 값을 넣어주면 된다.\n\n```javascript\nlocalStorage.getItem('id'); // dididy\n```\n\nLocal Storage에 저장된 데이터를 삭제하기 위해서는 removeItem 메서드의 매개변수로 지우고 싶은 key를 넣어주면 해당 값을 삭제할 수 있다.\n\n```javascript\nlocalStorage.removeItem('id');\n```\n\n데이터를 추가하거나 삭제할 때 오리진이 같다면 URL 경로가 다르더라도 다른 탭, 다른 브라우저 창에서 데이터가 변경되었음을 확인할 수 있을 것이다. 즉 오리진에 따라 모든 탭과 브라우저 창의 localStorage의 값은 공유되며 데이터의 변화가 Storege Event에 의해 반영된다.\n\n위에서 메서드를 사용한 방법 이외에 권장하진 않지만, 일반 객체처럼 사용하기도 한다. 만약 이와같이 일반 객체처럼 사용할 경우 메서드 이름을 키로 사용할 때의 예외처리를 해줘야 하며 Storage Event가 발생하지 않는다.\n\n```javascript\n// setItem\nlocalStorage.id = 'dididy';\n\n// getItem\nconsole.log(localStorage.id); // dididy\n\n// removeItem\ndelete localStorage.id;\n```\n\nChrome 브라우저의 경우 DevTools의 Application 탭에서 Local Storage를 수정하고 삭제할 수 있다.\n<img width=\"1134\" alt=\"localStorage\" src=\"https://user-images.githubusercontent.com/16266103/99893104-82d05880-2cbf-11eb-8085-80e7cfd8ae14.png\">\n\n## 3. Session Storage\n\nSession Storage와 Local Storage의 차이점은 데이터 지속 여부와 접근할 수 있는 데이터 범위에 있다.\n\n저장되면 영구적으로 데이터가 저장되는 Local Storage와 다르게 Session Storage는 브라우저를 닫는 등 세션이 종료되면 데이터가 삭제된다. Session Storage의 이러한 특성으로 인해 보안이 필요한 경우 사용하면 좋다.\n\n앞서 설명했듯이 Local Storage는 오리진이 같다면 전역으로 데이터를 공유할 수 있었다. 하지만 Session Storage의 경우 오리진이 같더라도 서로 다른 탭 혹은 서로 다른 브라우저라면 서로의 데이터를 침범할 수 없다. 즉 Local Storage와 달리 해당 탭에 대해 종속되어 있게 된다.\n\nwindow.open을 이용해 새로운 창을 열게 되면 기존 창의 Session Storage의 값이 복사되기는 하지만 두 창의 데이터가 공유되지는 않는다.\n\nSession Storage의 프로퍼티 사용 방법은 Local Storage와 일치한다.\n\n## 4. Storage Event\n\nLocal Storage와 Session Storage에서 데이터가 갱신될 경우 Storage Event가 실행되는데 이에대한 프로퍼티는 아래와 같다.\n\n- `key` – 변경된 데이터의 키(`.clear()`를 호출했다면 `null`)\n- `oldValue` – 이전 값(키가 새롭게 추가되었다면 `null`)\n- `newValue` – 새로운 값(키가 삭제되었다면 `null`)\n- `url` – 갱신이 일어난 문서의 url\n- `storageArea` – 갱신이 일어난 `localStorage`나 `sessionStorage` 객체\n\nLocal Storage에서 같은 오리진인 경우 Local Storage의 값이 변경되는 경우 window객체로 전송한다. event.url을 사용하면 갱신된 문서의 URL을 알 수 있다.\n\n```javascript\nwindow.addEventListener('storage', (event) => {\n  if (event.key != 'now') return;\n  alert(event.key + ':' + event.newValue + \" at \" + event.url);\n});\n\nlocalStorage.setItem('now', Date.now());\n```\n> 출처: https://ko.javascript.info/localstorage\n\n## 마무리\n\nWeb Storage을 잘 응용한 사례는 다음과 같은 경우가 있다.\n\n- 웹서버의 데이터 캐시\n- 같은 오리진일 경우 서버를 통하지 않고 모든 탭, 브라우저 창의 정보 갱신([Broadcast Channel API](https://developer.mozilla.org/en-US/docs/Web/API/Broadcast_Channel_API)의 폴리필 구현 시 사용할 수 있음)\n- 글쓰기 등 창이 닫힐 경우를 대비해 값을 저장해야 하는 경우\n- base64로 변환된 Canvas나 이미지 임시 저장\n- 웹페이지의 개인화 설정 저장 및 제공(캐시로서의 역할)\n\n<img width=\"375\" alt=\"Screen Shot 2020-11-22 at 1 20 59 PM\" src=\"https://user-images.githubusercontent.com/16266103/99893931-9252a000-2cc5-11eb-9c28-f01d2f272ccc.png\">\n\n> Netflix Local Storage에 저장되는 정보\n\n---\n\n#### Reference\n\n- [MDN: Web Storage API](https://developer.mozilla.org/ko/docs/Web/API/Web_Storage_API)\n\n- [W3C: Web Storage](https://www.w3.org/TR/webstorage/)\n\n- [Modern Javascript Tutorial: localSotrage와 sessionStorage](https://ko.javascript.info/localstorage)\n"
  },
  {
    "path": "Javascript/ajax(2).md",
    "content": "# Ajax (Asynchronous Javascript And XML)\n- JavaScript 라이브러리인 Jquery의 기능 중 하나이며, Asynchronous Javascript And Xml의 약자이다.\n- 전체 페이지를 새로 고치지 않고 페이지의 일부만을 위한 데이터를 로드하는 기법이다.  JavaScript를 사용한 비동기 통신, 클라이언트와 서버 간에 XML 데이터를 주고받는 기술이다. 이는 동적인 화면 처리를 가능하게 해준다.\n즉, 자바스크립트를 사용하여 서버에 데이터를 요청하는 것이다.\n\n#### 비동기 방식이란?\n\n- 비동기 방식이란 요청을 보냈을 때 그에 따른 응답이 올 때까지 기다리는 것이 아닌 다른 작업을 할 수 있는 방식을 말한다.\n- 비동기 방식을 이용하면 클라이언트가 데이터 요청을 보냈을 때 다른 작업을 하면서 데이터를 받는 것이므로 데이터가 올 때마다 부분 로딩이 된다. 따라서 시간 낭비를 줄여 속도가 빠른 장점이 있다.\n\n\n## Ajax를 사용하는 이유\n- 기본적으로 [HTTP 프로토콜](https://github.com/Im-D/Dev-Docs/blob/master/Network/HTTP%20vs%20WebSocket.md#http)은 클라이언트 쪽에서 Request를 보내면 서버 쪽에서 Response를 보내 페이지 전체가 리로드됨.\n따라서 화면의 내용을 갱신하기 위해서는 다시 request, response를 하는 과정을 거쳐 페이지 전체를 갱신해야 한다. 하지만 이럴 경우, 자원낭비와 시간낭비를 초래하게 된다.\n\n- Ajax는 HTML 페이지 전체가 아닌 일부분만 갱신할 수 있도록 JSON이나 XML 형태로 필요한 데이터만 받아 갱신하기 때문에 그만큼의 자원과 시간을 아낄 수 있다.\n\n## Ajax의 장단점\n###   Ajax의 장점\n- 웹페이지의 속도를 향상시켜준다.\n- 서버의 처리가 완료될 때까지 기다리지 않고 처리 가능하다.\n- 수신 데이터의 양을 줄일 수 있다.\n\n###   Ajax의 단점\n- 연속으로 데이터를 요청하면 서버 부하가 증가할 수 있다.\n- Ajax를 이용하면 웹브라우저의 history 기능과 연동이 되지 않아 히스토리 관리가 어렵다.\n\n웹 브라우저는 서버에서 받아온 웹 페이지를 로컬에 저장해둔다. 페이지가 바뀔 때마다 그 웹페이지를 저장해 두고, 만약 사용자가 뒤로 가기 버튼을 누르면, 서버와의 통신 없이 자신의 로컬에 저장해 둔 웹페이지 화면을 보여준다. 이것을 [history](https://developer.mozilla.org/ko/docs/Web/API/Window/history)기능이라고 한다. 다시 말해 `html`을 `history`에 저장한다. 하지만 브라우저는 'html'만을 히스토리에 저장하고 'XmlHttpRequest'에 의해 받아온 것들은 'history'에 저장하지 않는다. 만약 'Ajax'를 이용하여 데이터를 받아왔다면 사용자가 뒤로 가기 버튼을 클릭하였을 때 히스토리에 남아있지 않기 때문에 아예 첫 화면으로 가버리는 상황이 발생한다.\n이 때문에 'history'객체의 관리가 어렵다는 단점이 있다.\n\n\n## Ajax 구현방식\n### 1. XMLHttpRequest 객체\n- 서버와 통신하기 위해 XMLHttpRequest 객체를 사용해서 Ajax를 요청하고 전송한다.  \n- xml, json, http 등 다양한 포맷을 주고받을 수 있다. \n- XMLHttpRequest를 이용하면 웹 페이지를 전부 로딩하지 않고도 일부만을 갱신하는게 가능해진다.\n\n###  AJAX의 요청 및 응답처리 과정\n**1.XMLHTTP request object를 만든다.**\n```java\nvar xhr= new XMLHttpRequest();\n```\n\nrequest를 보낼 준비를 브라우저에게 시키는 과정이다. \n이것을 위해서 필요한 method를 갖춘 object가 필요하다.\n\n**2.Open a request**\n\n```java\nxhr.open(‘GET’,”sidebar.html”,true);\n```\n\n세 개의 매개변수(HTTP 메서드/요청 처리할 페이지의 URL/비동기 여부)를 정의한다.\n\npost, get메소드에 따라 전송 방식에 차이가 있다. \n\n- GET 메소드의 경우, URL의 일부분인 쿼리문자열(query string)로 데이터를 서버로 전송한다.\n- POST 메소드의 경우, 데이터(페이로드)를 Request Body에 담아 전송한다.\n\n**3.send the request**\n```java\nxhr.send();\n```\n\n준비된 request를 서버에 전송한다.\n\n\n**4.callback 함수를 만든다.**\n\n```java\nxhr. onreadystatechange = function(){\n\t if(xhr.readyState===4){\n\t\tdocument.getElementById(‘ajax’).innerHTML= xhr.responseText;   \n     }\n}\n```\n\n- 'onreadystatechange' : 서버에서 response가 와서 변화가 일어났을 때, 이에 대응해서 일어나는 메소드\n\n- 'readyState' : response가 돌아왔는지 아닌지를 추적하는 property\n\n|  숫자  |  상태 |\n| ------------ | ------------ |\n| 0  | request 가 초기화가 안된 상태  |\n|  1 |  서버에 연결이 완료된 상태 |\n| 2  | 서버가 request를 받은 상태  |\n| 3  | 서버가 request를 처리하는 상태  |\n| 4 | request 처리가 끝나고, response가 준비된 상태 |\n\n\n## 2. $.ajax()메소드 (jQuery 사용)\n\n1. type : get, post 등의 전송 방식을 결정\n2. url : 접근할 url을 입력\n3. data: 전달할 파라미터 값을 설정\n4. dataType : 파싱할 파일 형태를 입력(Ex. json, html, xml)\n5. success : 성공할 경우 불러올 콜백함수, 반환되는 코드(html, xml 등등)를 사용가능\n6. error : 실패할 경우 불러올 콜백함수\n7. complete : 성공 또는 실패 뒤에 실행할 콜백함수\n8. jsoncallback : 성공시 불러올 함수\n\n>### 예제\n```java\n$.ajax({ \n\turl:'/study/tmp/test.php', //request 보낼 서버의 경로  \n\ttype:'post', // 메소드(get, post, put 등)  \n\tdata:{'id':'admin'}, //보낼 데이터  \n\tdataType:'json'  \n\tsuccess: function(data) {  \n\t\t//서버로부터 정상적으로 응답이 왔을 때 실행  \n\t},   \n\terror: function(err) {  \n\t\t//서버로부터 응답이 정상적으로 처리되지 못했을 때 실행\n\t}  \n})  \n\t\n```\n\t\n####  jquery를 이용해서 Ajax를 사용하는 이유 \n일반 javascript로  Ajax를 하게 되면 코딩 양도 많아지고 브라우저별로 구현 방법이 다른 단점이 있다.\njquery를 이용하면 더 적은 코딩 양과 동일한 코딩 방법으로 대부분의 브라우저에서 같은 동작을 할 수 있음\n\n\n\n\n------------\n\n\n\n\n#### Reference \n- [Ajax 기존 구문 및 예제](https://dororongju.tistory.com/96) \n- [Ajax의 과정](https://poiemaweb.com/js-ajax)\n- [jquery를 이용하는 이유](https://kdarkdev.tistory.com/26) \n\n"
  },
  {
    "path": "Javascript/bind.md",
    "content": "# bind() 메소드\n\n## 정의\n\n```js\nfunc.bind(thisArg[, arg1[, arg2[, ...]]])\n```\n\n`bind()` 메서드는 새로운 함수를 생성한다. `bind()` 가 호출된 함수의 `this` 키워드를 주어진 값으로 설정하고, 새로운 함수의 인수(argument)보다 먼저 지정한 인수(`arg1`, `arg2`, ...)가 사용된다.\n\nECMAScript 5.1 (ECMA-262)에 추가되었다.\n\n<br/>\n\n## bind()가 사용되는 상황\n\n```js\nvar healthObj = {\n  name: \"달리기\",\n  lastTime: \"PM10:12\",\n  showHealth: function() {\n    console.log(\n      this.name + \"님, 오늘은 \" + this.lastTime + \"에 운동을 하셨네요\"\n    );\n  }\n};\n\nhealthObj.showHealth(); // \"달리기님, 오늘은 PM10:12에 운동을 하셨네요\"\n```\n\n`showHealth` 안의 `this` 는 해당 함수가 참조하는 객체에 있는 `name` 과 `lastTime` 을 참조한다.\n\n<br/>\n\n```js\nvar healthObj = {\n  name: \"달리기\",\n  lastTime: \"PM10:12\",\n  showHealth: function() {\n    test();\n  }\n};\n\nvar test = function() {\n  console.log(this.name + \"님, 오늘은 \" + this.lastTime + \"에 운동을 하셨네요\");\n};\n\nhealthObj.showHealth(); // 님, 오늘은 undefined에 운동을 하셨네요\n```\n\n현재 `test`는 `window` 아래에 생성되어 있다. 따라서 `test` 를 호출하면 `test` 는 `window.name` 과 `window.lastTime` 을 호출하게 된다.\n> ```js\n> test(); // 님, 오늘은 undefined에 운동을 하셨네요\n> ```\n\n<br/>\n\n```js\nvar healthObj = {\n  name: \"달리기\",\n  lastTime: \"PM10:12\",\n  showHealth: function() {\n    console.log(\n      this.name + \"님, 오늘은 \" + this.lastTime + \"에 운동을 하셨네요\"\n    );\n  }\n};\n\nvar test = healthObj.showHealth;\ntest(); // 님, 오늘은 undefined에 운동을 하셨네요\n```\n\n마찬가지로, 함수가 전역 컨텍스트에서 호출되었기 때문에 `this` 가 `window` 를 가리킨다.\n\n<br/>\n\n```js\nvar healthObj = {\n  name: \"달리기\",\n  lastTime: \"PM10:12\",\n  showHealth: function() {\n    setTimeout(function() {\n      console.log(\n        this.name + \"님, 오늘은 \" + this.lastTime + \"에 운동을 하셨네요\"\n      );\n    }, 1000);\n  }\n};\n\nhealthObj.showHealth(); // 님, 오늘은 undefined에 운동을 하셨네요\n```\n\n새로 만들어진 콜백 함수 안의 `this` 는 `window` 를 가리킨다. 콜백 함수는 `showHealth` 가 실행되는 순간 바로 실행되는 것이 아니고, `showHealth` 가 실행된 뒤 이벤트 큐에 저장되어 있다가 실행되기 때문이다.\n\n<br/>\n\n## 바인딩된 함수 생성\n\n위와 같은 경우들에서, 함수가 호출된 객체에 `this` 를 바인딩하고 싶다면 해당 함수 뒤에 `bind()` 를 사용하면 된다.\n\n```js\nvar healthObj = {\n  name: \"달리기\",\n  lastTime: \"PM10:12\",\n  showHealth: function() {\n    test();\n  }\n};\n\nvar test = function() {\n  console.log(this.name + \"님, 오늘은 \" + this.lastTime + \"에 운동을 하셨네요\");\n}.bind(healthObj);\n```\n\n```js\nvar healthObj = {\n  name: \"달리기\",\n  lastTime: \"PM10:12\",\n  showHealth: function() {\n    console.log(\n      this.name + \"님, 오늘은 \" + this.lastTime + \"에 운동을 하셨네요\"\n    );\n  }\n};\n\nvar test = healthObj.showHealth.bind(healthObj);\n```\n\n```js\nvar healthObj = {\n  name: \"달리기\",\n  lastTime: \"PM10:12\",\n  showHealth: function() {\n    setTimeout(\n      function() {\n        console.log(\n          this.name + \"님, 오늘은 \" + this.lastTime + \"에 운동을 하셨네요\"\n        );\n      }.bind(this),\n      1000\n    );\n  }\n};\n```\n\n> `setTimeout` 은 `healthObj` 에 바인딩 되어 있다. 이 때, 콜백함수 또한 해당 컨텍스트 안에서 정의되기 때문에 `bind(this)` 가 유효하다.\n\n> 화살표 함수는 `.bind(this)`를 사용한 것과 같이 동작한다.<br/>\n> ```js\n> ()=>{...} // 아래와 같이 동작한다.\n> function(){}.bind(this)\n> ```\n\n함수 뒤에 `.` 를 사용하면 함수가 객체로 변하고, `function native` 객체에 있는 메서드들을 부를 수 있게 된다. `bind()` 도 그 중 하나인데, 해당 함수 안의 `this` 를 원하는 객체에 바인딩 시킨다.\n\n더욱 정확히 말하면 `bind()`가 `this`를 해당되는 객체로 바꾸어 새로운 함수를 리턴한다.\n\n```js\nvar test = function() {\n  console.log(this.name + \"님, 오늘은 \" + this.lastTime + \"에 운동을 하셨네요\");\n}.bind(healthObj);\n```\n\n위의 코드에서 `bind(healthObj)` 는 다음과 같은 함수를 리턴한다.\n\n```js\nfunction(){\n    console.log(healthObj.name + \"님, 오늘은 \" + healthObj.lastTime + \"에 운동을 하셨네요\");\n}\n```\n\n<br/>\n\n## 부분 적용 함수\n\n이외에도 `bind()` 는 초기 인수 값을 지정할 수 있다.\n\n```js\nfunction addArguments(arg1, arg2) {\n  return arg1 + arg2;\n}\n\nvar result1 = addArguments(1, 2); // 3\n\n// 첫 번째 인수를 지정하여 함수를 생성\nvar addThirtySeven = addArguments.bind(null, 37);\n\nvar result2 = addThirtySeven(5); // 37 + 5 = 42\n\n// 두 번째 인수는 무시됩니다.\nvar result3 = addThirtySeven(5, 10); // 37 + 5 = 42\n```\n> 위 예시에서 `bind`의 첫 번째 인자로 `null`이 사용됐다. 이는 알아보기 쉽도록 넣은 것이며, <br/>실제 상황에서는 `Object.create(null)` 혹은 `{}` 을 사용하여 빈 객체를 만들어주는 것이 안전한 방법이다. 아래의 예시도 마찬가지다.<br/> 참고 - [자바스크립트 this 바인딩 우선순위(김정환 블로그)](http://jeonghwan-kim.github.io/2017/10/22/js-context-binding.html#%EC%98%88%EC%99%B8%EC%83%81%ED%99%A9%EB%93%A4)\n\n## 생성자\n\n또한, 생성자에서 쓰일 때는 첫 번째 매개변수가 무시된다.\n\n```js\nfunction Point(x, y) {\n  this.x = x;\n  this.y = y;\n}\n\nPoint.prototype.toString = function() {\n  return this.x + \",\" + this.y;\n};\n\nvar YAxisPoint = Point.bind(null, 0);\nvar axisPoint = new YAxisPoint(5);\naxisPoint.toString(); // '0,5'\n```\n\n<br/>\n\n---\n\n#### References\n\n- [부스트코스 - bind메소드로 this제어하기](https://www.edwith.org/boostcourse-web/lecture/16780/)\n- [MDN - Function.prototype.bind()](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Function/bind)\n"
  },
  {
    "path": "Javascript/object.md",
    "content": "# 객체\n\n연관된 속성의 집합을 객체라고 한다.\n\n객체지향 프로그래밍에서는 클래스가 반환한 객체 인스턴스를 통해 메서드에 접근하고, 이 메서드를 통해 속성들을 제어한다.\n\n이 경우 복잡한 구조를 모듈화 시켜서 사용할 수 있는 장점이 있다. 연관된 작업끼리 분류하여 묶은 뒤 호출하여 사용하는 것이다.\n\n자바스크립트에서도 객체를 사용한다. 원시타입을 제외한 모든 타입은 객체이다.\n\n> 자바스크립트의 원시타입(primitive type)은 Number, String, Boolean, Symbol(ES6~), Undefined 이다.\n\n<br/>\n\n객체 생성방법에는 세 가지가 있다.\n\n- 리터럴 표기 사용\n- 생성자 함수 사용\n- Object.create() 메소드 사용\n\n<br/>\n\n## 객체 리터럴\n\n자바스크립트의 객체는 매우 간단한 구조로 되어있다. 키와 밸류로 구성된 해시 맵 구조의 형태이다. 이러한 자바스크립트의 객체 표기법을 객체 리터럴이라고 한다. 객체 리터럴은 다음과 같이 만들고 접근할 수 있다.\n\n```js\nvar objectExample = {\n  propertyExample: \"value\", // 쉼표로 구분(세미 콜론이 아니다.)\n  methodExample: function() {\n    console.log(objectExample.propertyExample);\n  }\n};\n\nconsole.log(objectExample.propertyExample); // value\nconsole.log(objectExample[\"propertyExample\"]); // value\nobjectExample.methodExample(); // value\n```\n\n객체의 프로퍼티(property; 속성)는 숫자, 배열, 오브젝트 등 모든 타입을 표현할 수 있고, 중첩시켜서 표현할 수 있다. 프로퍼티의 값이 함수일 경우 메소드(method)라고 표현한다.\n\n> 프로퍼티를 정의하지 않으면 빈 객체가 생성된다. 또한 객체를 생성한 이후 프로퍼티를 동적으로 추가하거나 삭제할 수도 있다.\n\n대괄호(`[]`) 를 이용하여 프로퍼티를 호출할 경우, 동적 호출이 가능하다.\n\n> `objectExample[someObject]` 혹은, `objectExample[\"val\"+\"ue\"]` 와 같이 호출이 가능하다.\n\n<br/>\n\n객체의 구성요소는 `객체.속성` 와 같이 `.` 을 표기하여 접근할 수 있다.\n\n객체지향 언어에서 필드 혹은 멤버 변수에 직접 접근하는 것은 좋지 않은 방법인데, 자바 스크립트에서도 마찬가지로 값을 할당하는 프로퍼티에 직접 접근하는 것은 좋지 않은 방법이다. 다음과 같은 패턴으로 해결할 수 있다.\n\n```js\nconst obj = {\n  //name : name 을 다음과 같이 축약할 수 있다(ES6~)\n  name,\n  //getName : function(){ ... }을 다음과 같이 축약할 수 있다(ES6~).\n  getName() {\n    return this.name;\n  },\n  setName(name) {\n    this.name = name;\n  }\n};\n\nobj.setName(\"Name\");\nconst result = obj.getName();\n```\n\n<br/>\n\n## 생성자 함수\n\n- `new` 연산자와 생성자를 사용하여 객체 생성 및 초기화를 하는 방법이다.\n- 자바스크립트에서 제공하는 생성자 혹은 직접 작성한 생성자를 사용할 수 있다.\n- 해당 생성자의 프로토타입(prototype)을 상속 받는다.\n\n<br/>\n\n### 자바스크립트에서 제공하는 생성자 사용\n\n```js\nvar objectConstructor = new Object(...;)\n```\n\n> 객체 리터럴은 `new Object()` 로 객체를 생성한 것과 같다.\n\n위와 같은 방식은 인자(argument)를 지정할 수 있다. 이는 안티패턴으로 분류되는데, 인자의 타입에 따라 원하는 결과와 다른 결과가 나올 수 있기 때문이다.\n\n```js\nvar obj = new Object(1);\n\nconsole.log(obj); // Number {1}\n\nobj.str = \"String\";\nconsole.log(obj); // Number {1, str: \"String\"}\n```\n\n<br/>\n\n### 생성자 작성\n\n```js\nfunction ConstructorExample(a, b, c) {\n  this.a = a;\n  this.b = b;\n  this.c = c;\n}\n\nvar objectExample = new ConstructorExample(1, 2, 3);\n```\n\n객체지향 언어에서 사용하던 생성자와 같은 패턴이다.\n\n주의할 점은 생성자 함수 또한 함수라는 것이다. 때문에, 다른 함수와 구분을 위해 첫 글자를 대문자로 작성해준다.\n\n<br/>\n\n## Object.create()\n\n프로토타입으로 지정하고 싶은 객체와 프로퍼티를 인자로 넣어 객체 생성을 할 수 있다.\n\n```js\nfunction Obj(){};\n\nvar obj = Object.create(Obj, {\n    ...;//생략가능\n});\n```\n\n다른 방법들과는 다르게 객체자체가 프로토타입이 된다.\n\n따라서, 객체에 직접 프로퍼티를 넣어야 참조하는 객체에서 프로퍼티를 사용 할 수 있다.\n\n```js\nObj.newMethod = function() {\n  console.log(\"newMethod\");\n};\nobj.newMethod(); //newMethod\n```\n\n`Object.create()` 를 사용하면 보다 기존의 객체지향 언어와 가깝게 느껴진다.\n\nES6에서는 이를 보완한 `class` 를 사용한다.\n\n> 클래스 알아보기 - [Class](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/B_Class.md)\n\n<br/>\n\n---\n\n#### References\n\n- [[자바스크립트 패턴] ① 리터럴을 이용한 객체 생성 패턴 - IT 마이닝](https://itmining.tistory.com/73)\n- [객체 리터럴과 this - 부스트코스](https://www.edwith.org/boostcourse-web/lecture/16779/)\n"
  },
  {
    "path": "Javascript/object_create_pattern-constructor.md",
    "content": "# 객체 생성 패턴 - 생성자 패턴\n\n객체를 생성하는 쉽고 단순한 방법에는 `Object` 객체의 인스턴스를 만드는 것과 객체 리터럴을 이용한 방법이 있다.\n\n```js\n// Object의 인스턴스 생성\nvar person = new Object();\nperson.name = \"per\";\nperson.age = 22;\nperson.getName = function() {\n    return this.name;\n}\n\n// 객체 리터럴 사용\nvar person = {\n    name : \"son\",\n    age : 28,\n    getName : function() {\n        return this.name;\n    }\n}\n```\n\n> `var person = {}` 과 `var person = new Object()` 는 같은 동작을 한다.\n\n객체를 하나만 만든다면 상관없지만, 같은 인터페이스를 가지는 객체를 여러개 만들 경우 비효율적이다. 간단한 팩토리를 사용하여 이를 해결할 수 있다.\n\n<br/>\n\n```js\nfunction createPerson(name, age) {\n  var obj = {};\n\n  obj.name = name;\n  obj.age = age;\n\n  obj.getName= function() {\n    return this.name;\n  };\n  return obj;\n}\n\nvar person1 = createPerson(\"per\", 22);\nvar person2 = createPerson(\"son\", 28);\n\nperson1.getName(); // per\nperson2.getName(); // son\n ```\n\n하지만 위의 경우 생성된 객체의 타입이 명확하지 않다.\n\n```js\ntypeof person1; // object\ntypeof person2; // object\n```\n\n때문에 생성자 패턴을 사용한다.\n\n<br/>\n\n## 생성자 패턴\n\n```js\nfunction Person(name, age) {\n  this.name = name;\n  this.age = age;\n  this.getName = function() {\n    return this.name;\n  }\n}\n// new 연산자로 새 객체를 만듭니다.\nvar person1 = new Person(\"per\", 22);\nvar person2 = new Person(\"son\", 28);\n\nconsol.log(person1 instanceof Person); // true\nconsol.log(person2.constructor == Person); // true\n```\n\n하지만 생성자 패턴만 사용할 경우 문제점이 있다.\n\n### 문제점 1 - 함수로 동작하는 생성자\n\n생성자 함수는 함수 타입이기 때문에 new 연산자를 사용하지 않을 경우 함수와 같은 동작을 한다.\n\n```js\nPerson(\"person\", 99); // 프로퍼티와 메서드가 window객체에 추가된다.\n\nwindow.getName() // person\n```\n\n### 문제점 2 - 인스턴스마다 새로운 메소드 생성\n\n```js\nfunction Person(name, age) {\n  this.name = name;\n  this.age = age;\n  // 위에서 만들었던 getName 메소드들은 다음과 같다.\n  this.getName = new Function('return this.name;');\n}\n\nvar person1 = new Person(\"per\", 22);\nvar person2 = new Person(\"son\", 28);\n\nconsole.log(person1.getName == person2.getName); // false\n```\n\n`getName` 메소드는 계속해서 같은 동작을 하지만, 매번 새로 생겨날 것이다. 메소드를 생성자 바깥에 정의하여 해결할 수 있다.\n\n```js\nfunction getName () {\n  return this.name;\n}\n\nfunction Person(name, age) {\n  this.name = name;\n  this.age = age;\n  this.getName = getName;\n}\n\nvar person1 = new Person(\"per\", 22);\nvar person2 = new Person(\"son\", 28);\n\nconsole.log(person1.getName == person2.getName); // true\n```\n\n이렇게하면 메소드가 새로 생겨나는 것은 막을 수 있겠지만, 전역스코프에 함수를 정의한다는 문제가 있다.\n\n이는 프로토타입을 이용하여 해결할 수 있다.\n\n<br/>\n\n---\n\nReference\n\n- [객체 생성 - 이지코드](http://ezcode.kr/study/view/203)\n"
  },
  {
    "path": "Javascript/object_생성패턴.md",
    "content": "# 객체 생성 패턴\n\n## 전역 변수 사용\n```js\nfunction Parent() {}\nfunction Child() {}\n\nvar some_var = 1;\nvar module1 = {};\nvar module2 = {};\n```\n위와 같이 손쉽게 객체 혹은 함수와 변수를 정의할 수 있지만, 이는 바람직하지 못하다. 자바스크립트에서 전역변수를 자주 사용하는 것은 바람직 하지 않다.\n\n크게 네 가지 문제가 있다.\n\n- 암묵적 결합\n- 긴 생명 주기\n- 스코프 체인 상에서 종점에 존재\n- 네임 스페이스 오염\n\n<br/>\n\n### 암묵적 결합\n\n전역 변수는 어느 위치에서든 접근할 수 있다. 다시 말해 언제든 참조하고 변경할 수 있다. 이를 암묵적 결합이라고 한다. \n\n편리해 보이지만, 다르게 말하면 의도하지 않은 상태 변경이 일어날 위험이 항상 존재한다고 할 수 있다.\n\n### 긴 생명 주기\n\n전역 변수의 생명주기는 애플리케이션이 종료될 때 까지 지속된다. 따라서 이는 리소스의 낭비로 이어질 수 있다.\n\n### 스코프 체인 상에서 종점에 존재\n\n전역 변수는 스코프 체인의 가장 마지막에 존재하기 때문에 가장 마지막에 검색이 된다. \n\n전역 변수를 사용하는 것은 가장 간단하지만, 가장 느린 방법이다.\n\n### 네임 스페이스 오염\n\n자바스크립트는 파일이 분리되어 있어도, 하나의 전역 스코프를 공유한다. \n\n또한, 자바스크립트는 변수의 중복 선언을 허용하기 때문에 의도한대로 작동하지 않을 수 있다.\n\n<br/>\n\n## 네임 스페이스 패턴\n\n가장 쉽게 객체를 구현할 수 있는 패턴이다.\n\n전역 변수가 줄어들고, 객체 안에 함수를 정의하여 함수의 이름이 지나치게 길어지는 것을 막아준다.\n\n```js\nvar MYAPP = {}; // 객체는 일반적으로 대문자로 선언한다.\nMYAPP.Parent = function() {};\nMYAPP.Child = function() {};\n\nMYAPP.some_var = 1;\n\nMYAPP.modules = {};\nMYAPP.modules.module1.data = {a:1, b:2};\nMYAPP.modules.module2 = {};\n```\n\n하지만, 모든 변수와 함수에 접두어를 붙여야하기 때문에 코드량이 많아지며 파일의 크기가 증가한다. \n\n또한, 전역 인스턴스가 하나이기 때문에 부분이 수정되면 다른 인스턴스도 모두 수정된다. \n\n뿐만 아니라, 이름이 길어지기 때문에 검색시간이 길어진다.\n\n<br/>\n\n## 범용 네임스페이스 함수\n\n네임 스페이스를 사용할 때, 프로그램의 크기가 커지면 다음과 같은 점검을 해주는 것이 바람직하다.\n\n```js\nvar MYAPP = {};\n// 1. 기본\nif (typeof MYAPP === \"undefined\") {\n  var MYAPP = {};\n}\n// 2. 축약\nvar MYAPP = MYAPP || {};\n```\n\n위의 코드를 이용하여 네임 스페이스를 생성하는 함수를 만들 수 있다.\n\n```js\nvar MYAPP = MYAPP || {};\n\nMYAPP.namespace = function(ns_string) {\n  var parts  = ns_string.split('.'),\n      parent = MYAPP,\n      i;\n\n  if (parts[0] === \"MYAPP\") {\n    parts = parts.slice(1);\n  }\n\n  for (i = 0; i < parts.length; i += 1) {\n    if (typeof parent[parts[i]] === \"undefined\") {\n      parent[parts[i]] = {};\n    }\n      // 참조를 변경한다. ( parent -> MYAPP 에서 parent -> MYAPP.parts[i]로 변경)\n      parent = parent[parts[i]];\n  }\n\n  return parent;\n}\n\nMYAPP.namespace(\"MYAPP.modules.module2\");\n\nvar module2 = MYAPP.namespace(\"MYAPP.modules.module2\");\nmodule2 === MYAPP.modules.module2; // true\n```\n\n`MYAPP.namespace()` 의 결과로 만들어진 객체는 다음의 코드로 만든 객체와 같다.\n\n```js\nvar MYAPP = {\n  modules : {\n    module2 : {}\n  }\n};\n```\n\n<br/>\n\n## 의존 관계 선언\n\n```js\nvar myFunction = function () {\n  var event = YAHOO.util.Event,\n      dom   = YAHOO.util.Dom;\n};\n```\n\n함수나 모듈 내의 최상단에 의존 관계가 있는 모듈을 선언하는 것이다.\n\n의존 관계가 명시적이기 때문에, 반드시 포함돼야 하는 파일을 쉽게 알 수 있다.\n\n지역 변수 값을 탐색하는 것이 중첩 프로퍼티(e.g. `YAHOO.util.Event`)를 사용하는 것 보다 훨신 빠르다.\n\n또한 전역 변수명을 수정하는 것은 위험하기 때문에, 고급 Compressor 는 전역변수명을 축약하지 않는다. 반면, 지역변수는 a 등으로 축약한다.\n\n```\n// 전역 변수를 그대로 사용한 경우\nfunction test1() {\n  alert(MYAPP.modules.m1);\n  alert(MYAPP.modules.m1);\n}\n// 위 코드 압축 결과\n// alert(MYAPP.modules.m1);alert(MYAPP.modules.m2);\n\n// 지역 변수를 사용한 경우\nfunction test2() {\n  var modules = MYAPP.modules;\n  alert(modules.m1);\n  alert(modules.m2);\n}\n// 위 코드 압축 결과 :\n// var a=MYAPP.modules;alert(a.m1);alert(a.m2);\n```\n\n<br/>\n\n## 비공개 프로퍼티와 메소드\n\n클로저를 이용하여 프로퍼티에 `private` 키워드와 같은 효과를 줄 수 있다.\n\n```js\n// 생성자를 이용하는 경우\nfunction Gadget() {\n    var name = \"iPhone\";\n    this.getName = function() {\n      return name;\n    };\n}\nvar toy = new Gadget();\nconsole.log(toy.name); // undefined\nconsole.log(toy.getName()); // \"iPhone\"\n\n// 객체 리터럴을 이용하는 경우 1\nvar myobj;\n(function () {\n  var name = \"Android\";\n\n  myobj = {\n    getName: function() {\n      return name;\n    }\n  };\n}());\n\nmyobj.getName(); // \"Android\"\n\n// 객체 리터럴을 이용하는 경우 2\nvar myobj = (function () {\n  var name = \"Android\";\n  return {\n    getName: function() {\n      return name;\n    }\n  };\n}());\n\nmyobj.getName(); // \"Android\"\n ```\n\n하지만 이와 같은 방법은 새로운 객체를 만들때마다 비공개 멤버가 재생성된다는 단점이 있다. 생성자에 선언하기 때문에 객체를 생성할때마다 코드가 실행되기 때문이다.\n\n이러한 문제는 프로토타입을 이용하여 보완할 수 있다.\n\n```js\n// 생성자를 이용\nfunction Gadget() {\n  var name = \"Android\";\n  this.getName = function () {\n    return name;\n  };\n}\n\n// 프로토타입을 이용\nGadget.prototype = (function () {\n  var browser = \"Mobile\";\n  return {\n    getBrowser : function() {\n      return browser;\n    }\n  };\n}());\n\nvar toy = new Gadget();\nconsole.log(toy.getName()); // 객체 인스턴스의 비공개 멤버\nconsole.log(toy.getBrowser()); // 프로토타입의 비공개 멤버\n ```\n\n> 이 경우 프로토타입에 새로운 프로퍼티를 추가하는 것이 아닌 프로토타입 자체를 수정하는 것이기 때문에, <br/> `newToy` 의 `__proto__` 는 생성자 `Gadget()` 을 가리키지 않는다.<br/>\n> 참고 - [프로토타입 객체의 수정과 변경](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/prototype.md#%ED%94%84%EB%A1%9C%ED%86%A0%ED%83%80%EC%9E%85-%EA%B0%9D%EC%B2%B4%EC%9D%98-%EC%88%98%EC%A0%95%EA%B3%BC-%EB%B3%80%EA%B2%BD)\n\n> 하지만, `newToy` 가 `Gadget()` 의 인스턴스라는 것은 변함이 없으며, `Gadget()` 은 변경된 프로토타입을 참조한다.\n\n<br/>\n\n---\n\n#### References\n\n- [전역변수를 왜 지양해야 하는가](https://www.codeameba.com/2019/05/10/js-no-more-global-variable/)\n- [Javascript Pattern 요약 - 객체 생성 패턴](https://joshua1988.github.io/web-development/javascript/javascript-pattern-object/#%EB%B9%84%EA%B3%B5%EA%B0%9C-%ED%94%84%EB%A1%9C%ED%8D%BC%ED%8B%B0%EC%99%80-%EB%A9%94%EC%84%9C%EB%93%9C)\n"
  },
  {
    "path": "Javascript/prototype(2).md",
    "content": "# Prototype(2)\n\n일반적으로 객체지향 프로그래밍을 할 경우 클래스를 사용해서 객체를 생성한다. 하지만 자바스크립트는 클래스 기반이 아닌 prototype 기반으로 객체를 생성한다. ES6에 클래스가 추가되었지만, 내부적으로는 prototype 을 바탕으로 동작하게 되므로 엄밀히 말하면 클래스로서 동작하는 것이 아니라 클래스를 흉내 낸 것에 가깝다.\n\n따라서 프로토타입에 대해 이해해야 자바스크립트에 더 깊게 다가갈 수 있다. 프로토타입을 간단히 정의하자면 자바스크립트 객체에 [[Prototype]] 으로 명명된 인터널 슬롯(내부 속성, 은닉 속성)이라는 내부 프로퍼티(프로토타입 링크; `__proto__`)가 있고, 다른 객체를 참조하는 레퍼런스로 사용한다.\n\n현재 객체 내의 특정 프로퍼티에 접근할 경우 프로퍼티가 존재하지 않으면 [[Prototype]] 을 따라가 프로퍼티가 존재하는지 탐색하게 된다.\n\n```javascript\nconst object = { valOne: 1, valTwo: 2 };\n\nconsole.log(object.valOne); // 1\nconsole.log(object.valTwo); // 2\nconsole.log(object.valThree); // undefined\nconsole.log(object.toString()); // - ??\n```\n\n위 코드는 프로토타입 체이닝의 예시이다. `toString()` 메서드는 object에 존재하지 않지만, 메소드로서 호출할 수 있다.\n\nobject의 프로토타입 링크가 다른 객체를 참조하고 있고, 그 객체에 `toString()` 메소드가 정의되어 있어 참조가 가능한 것이다.\n\n## 프로토타입을 왜 사용할까?\n\n```javascript\nfunction Car() {\n  this.wheel = 4;\n  this.body = 1;\n}\n\nconst truck  = new Car();\nconst bus = new Car();\nconsole.log(truck.wheel); // 4\nconsole.log(truck.body); // 1\nconsole.log(bus.wheel); // 4\nconsole.log(bus.body); // 1\n```\n\n위 예제를 보면 truck과 bus 모두 wheel과 body 프로퍼티에 할당된 값이 같다. 하지만 객체를 계속 생성하게 되는 경우 객체의 개수만큼 변수가 메모리에 할당되기 때문에 비효율적이다. 이 경우 프로토타입을 통해 문제를 해결 할 수 있다.\n\n```javascript\nfunction Car() {}\n\nCar.prototype.wheel = 4;\nCar.prototype.body = 1;\n\nconst truck  = new Car();\nconst bus = new Car();\nconsole.log(truck.wheel); // 4\nconsole.log(truck.body); // 1\nconsole.log(bus.wheel); // 4\nconsole.log(bus.body); // 1\n```\n\nCar.prototype에 직접 프로퍼티를 할당해 Car 함수로부터 생성된 객체가 프로토타입 체이닝을 통해 프로퍼티를 호출할 수 있다. 이 경우 객체를 계속해서 생성하더라도 메모리에 할당된 변수는 2개이므로 효율적인 코드를 작성할 수 있다.\n\n## 프로토타입 객체(`.prototype`)\n\n다음과 같이 생성자 함수를 이용해 객체를 생성할 수 있다.\n\n```javascript\nfunction Car() {};\n\nconst truck = new Car();\n```\n\n```javascript\nconst bus = {};\n```\n\n위와 같이 객체 리터럴을 사용하더라도 실제로는 아래와 같이 동작한다.(단, 생성자 함수와 객체 리터럴의 퍼포먼스 차이는 존재한다. - [reference](https://stackoverflow.com/questions/21545687/javascript-vs-new-object-performance))\n\n```javascript\nconst bus = new Object();\n```\n\n생성자 함수는 자바스크립트에서 기본적으로 제공하는 함수이다. 이것을 토대로 알 수 있는 건 객체는 언제나 함수로 생성된다는 것이다. 생성자 함수 외에도 Function, Array 또한 함수로 정의되어 있다. 일반 객체가 [[Prototype]] 만 가지고 있는 것과 달리 함수는 프로토타입 프로퍼티도 가지고 있다.\n\n함수가 정의될 때 아래와 같은 2가지 상황이 발생한다.\n\n<p align=\"center\">\n<img width=\"543\" alt=\"Screen Shot 2020-08-02 at 11 54 32 PM\" src=\"https://user-images.githubusercontent.com/16266103/89126438-a14bf180-d520-11ea-8e1c-511991161135.png\">\n</p>\n\n### 1. 해당 함수에 Constructor(생성자) 자격 부여\n\n생성자 함수 키워드인 new를 통해 객체를 만들기 위해선 Constructor 자격이 필요하다. 함수를 정의하게 되면 Constructor 자격이 부여되어 new를 사용할 수 있다.\n\n```javascript\nconst bus = {};\nconst truck = new bus(); // Uncaught TypeError: bus is not a constructor(...)\n```\n\nbus 자체는 함수를 정의하지 않았고 객체 리터럴의 Object함수와 생성자를 사용하여 객체를 만들었으므로 bus는 Constructor를 가지고 있지 않다. 따라서 위와 같이 에러가 발생하게 된다.\n\n### 2. 해당 함수의 Prototype Object 생성 및 연결\n<p align=\"center\">\n<img width=\"256\" alt=\"Screen Shot 2020-08-02 at 11 57 56 PM\" src=\"https://user-images.githubusercontent.com/16266103/89126440-a3ae4b80-d520-11ea-870f-d50922e0bc88.png\">\n</p>\n\n함수를 정의하게 되면 Prototype Object도 생성되게 된다. 생성된 함수는 프로토타입 프로퍼티를 통해 Prototype Object에 접근하게 되고 Prototype Object는 일반적인 객체의 형태로 위와 같이 constructor와 `__proto__`([[Prototype]]) 프로퍼티를 가지고 있다.\n\nPrototype Object는 일반적인 객체이므로 프로퍼티 추가 및 삭제가 가능하다. 따라서 현재 객체에 프로퍼티가 없더라도 프로토타입 프로퍼티가 Prototype Object와 연결되어 있고 Prototype Object의 해당 프로퍼티에 값이 할당되어 있으면 `Car.prototype.something` 형태로 참조해 사용할 수 있다.\n\n## 프로토타입 링크(`[[Prototype]]`)\n\n### 프로토타입 체인\n<p align=\"center\">\n<img width=\"544\" alt=\"Screen Shot 2020-08-03 at 12 22 20 AM\" src=\"https://user-images.githubusercontent.com/16266103/89126441-a610a580-d520-11ea-97a5-10fe14d99271.png\">\n</p>\n\n모든 객체는 [[Prototype]] 을 가지고 있다. [[Get]] 이 객체 내부에 프로퍼티를 찾아 못하면 [[Prototype]] 링크를 따라가 프로퍼티를 탐색한다. 모든 일반 객체의 최상위 프로토타입 체인은 내장 `Object.prototype`이고 이 지점에서도 찾지 못하면 undefined를 반환하며 탐색이 종료된다.\n\n```javascript\nconst something = {\n  value: true\n}\n\nconst other = Object.create(something);\n\nother.value // true\n```\n\n`Object.create(proto[, propertiesObject])`는 아래에서 설명할 프로토타입 메서드의 한 종류로서 [[Prototype]] 이 proto를 참조하는 빈 객체를 만든다. 이렇게 만들어진 other는 something이랑 [[Prototype]] 이 링크된다. other 내부에 value 프로퍼티가 없지만 연결된 something에서 해당 프로퍼티를 찾아 something의 프로퍼티인 value의 값인 true가 반환된 것이다.\n\n`for...in` 루프에서도 객체를 순회할 때 prototype 연결을 통해 탐색 가능한 프로퍼티라면 모두 열거한다.\n\n```javascript\nfor(let i in other){\n  console.log(`${i} 프로퍼티 존재`)\n}\n```\n\n## 프로토타입 메서드와 `__proto__`가 없는 경우\n\n사실 `__proto__`는 표준이 아니지만 대부분의 브라우저에 구현되어 있기 때문에 사실상 표준(de-facto standard)이 된 케이스이다.\n\n역사적으로 2012년, 표준에 `Object.create` 가 추가되어 프로토타입을 사용해 객체를 만들 수 있게 되었다. 하지만 프로토타입을 얻고 설정하는 것을 할 수 없었기 때문에 `__proto__`라는 비표준 접근자를 구현해 프로토타입을 설정할 수 있도록 했다.\n\n3년 뒤인 2015년에 Object.setPrototypeOf와 Object.getPrototypeOf가 표준에 추가되었기 때문에 `__proto__`가 의도했던 기능을 동일하게 사용할 수 있게 되었다.\n\n### 프로토타입 메서드\n\n프로토타입 메서드는 아래와 같이 세 가지 종류가 있다.(arrow function에서는 동작하지 않는다.)\n\n- [Object.create(proto[, propertiesObject])](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/create) – `[[Prototype]]`이 `proto`를 참조하는 빈 객체를 만들고 이때 프로퍼티 설명자를 추가로 넘길 수 있다. propertiesObject의 경우 immutable 하게 할건지 등을 설정하는 경우에 사용 가능하다.\n- [Object.getPrototypeOf(obj)](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/getPrototypeOf) – `obj`의 `[[Prototype]]`을 반환한다.\n- [Object.setPrototypeOf(obj, proto)](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/setPrototypeOf) – `obj`의 `[[Prototype]]`이 `proto`가 되도록 설정한다.\n\n`__proto__`가 `Object.getPrototypeOf()`와 `Object.setPrototypeOf()`로 대체된 이유는 유일하게 `\"__proto__\"`라는 문자열만 key로 사용할 수 없기 때문이다.\n\n```javascript\nconst obj = {};\n\nlet key = prompt(\"입력하고자 하는 key는 무엇인가요?\", \"__proto__\");\nobj[key] = \"...값...\";\n\nalert(obj[key]); // \"...값...\"이 아닌 [object Object]가 출력됨\n```\n\n위 예제를 실행하고 프롬프트에 `__proto__`를 입력하면 값이 제대로 할당되지 않음을 확인할 수 있다. 문자열은 프로토타입이 될 수 없기 때문에 발생하는 문제이다. `__proto__`는 객체 혹은 null이어야만 한다.\n\n하지만 객체가 할당되는 상황이라면 어떨까? 할당 값이 객체일 경우 프로타입이 바뀔 수 있다. 이렇게 될 경우 예상치 못한 일이 발생하게 된다.\n\n프로토타입이 중간에 바뀌는 시나리오는 버그의 원인을 찾는 것을 더 어려워지게 만든다. 또한 서버 사이드에서 사용 중일 경우에도 취약점으로 작용할 수 있다.\n\n`__proto__`는 객체의 프로퍼티가 아니라 Object.prototype의 접근자 프로퍼티이다. 그렇기 때문에 사실상 `__proto__`는 [[Prototype]] 에 접근하기 위한 방법일 뿐 [[Prototype]] 그 자체는 아니다.\n\n### `__proto__`가 없는 경우\n\n```javascript\nconst obj = Object.create(null);\n\nlet key = prompt(\"입력하고자 하는 key는 무엇인가요?\", \"__proto__\");\nobj[key] = \"...값...\";\n\nalert(obj[key]); // \"...값...\"이 제대로 출력됨\n```\n\n`Object.create(null)` 처럼 아주 단순한 객체를 만들면 `__proto__`에서 getter와 setter를 상속받지 않는다. 따라서 Object.prototype의 접근자 프로퍼티가 아닌 평범한 프로퍼티로 동작하게 되어 예제가 버그 없이 잘 동작하게 된다.\n\n하지만 Object.prototype에 정의된 `toString()` 같은 메서드는 사용 할 수 없는 단점이 생긴다. 그럼에도 연관 배열로 사용하게 되면 Object.keys(obj) 같이 객체 관련 메서드들은 대부분 Object.something(...) 형태이므로 단점이 문제가 되지 않는다.\n\n무엇보다도 가장 좋은 것은 [[Prototype]] 을 변경하는 상황을 만들지 않는 것이다. 자바스크립트 엔진은 객체를 생성할 때만 [[Prototype]] 을 설정하고 수정하지 않는 것에 최적화되어있다. 따라서 `Object.setPrototypeOf()`나 `obj.__proto__=`를 사용하여 프로토타입을 바꾸는 연산을 하게 되면 최적화를 망치게 되므로 느려지게 된다.\n\n이 모든 상황을 이해하는 경우가 아니라면 [[Prototype]] 을 바꾸지 않는 것이 좋다.\n\n---\n\n**Reference**\n\n- [[Javascript ] 프로토타입 이해하기](https://medium.com/@bluesh55/javascript-prototype-이해하기-f8e67c286b67)\n\n- [prototype methods - 모던 JavaScript 튜토리얼](https://ko.javascript.info/prototype-methods)\n\n"
  },
  {
    "path": "Javascript/prototype.md",
    "content": "# 프로토타입(Prototype)\n\n자바스크립트로 객체지향 프로그래밍을 할 수 있다. 하지만 대부분의 객체지향 언어와 달리 클래스가 아닌, 프로토타입으로 객체지향 프로그래밍을 구현한다. 또한, 클래스라는 개념이 없기 때문에 별도의 객체 생성 방법이 존재한다.\n\n> 참고 - [객체](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/object.md)\n\n> ES6부터는 자바스크립트에도 `class` 가 생겼는데, 이는 프로토타입 기반 패턴의 Syntatic sugar 이다.<br/>\n> 참고 - [class](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/B_Class.md)\n\n<br/>\n\n## 프로토타입 객체\n\n프로토타입 객체(이하 프로토타입)는 자바스크립트에서 생성된 객체들의 부모 역할을 한다. 모든 객체는 프로토타입의 프로퍼티 또는 메소드를 상속받아 사용한다.\n\n생성된 객체의 프로토타입은 다음과 같은 메소드들을 가진다.\n\n![prototype1](../assets/images/prototype1.png)\n\n```js\nconst protoTestObj = {};\n\n// protoTestObj에 정의하지 않은 메소드를 사용할 수 있다.\nprotoTestObj.toString();\n```\n\n다음과 같이 프로토타입에 프로퍼티를 정의하여 사용할 수 있다. 프로토타입에 프로퍼티를 정의한 뒤 참조하는 것과 같다. 따라서 각각의 객체마다 프로퍼티를 정의해야하는 문제점을 해결해준다.\n\n```js\nprotoTestObj.__proto__.testProperty = \"prototype test!\";\n\nprotoTestObj.testProperty; // prototype test!\n```\n\n프로토타입은 객체를 생성할 때 결정된다. 결정된 프로토타입 객체는 다른 객체로 변경할 수 있다. 즉, 프로토타입을 동적으로 변경할 수 있는 것이다. 프로토타입은 생성된 객체의 부모이다. 따라서 이를 이용하여 상속을 구현할 수 있다.\n\n```js\nconst protoTestObj2 = {\n  test() {\n    console.log(\"test\");\n  }\n};\nprotoTestObj.__proto__ = protoTestObj2;\n\nprotoTestObj.test; // test\n```\n\n<br/>\n\n## 프로토타입 프로퍼티\n\n### [[Prototype]]\n\n모든 객체는 `[[Prototype]]` 프로퍼티를 가지며, 자신의 프로토타입 객체를 가리킨다.\n\n> 크롬 브라우저에서 `[[Prototype]]` 은 `__proto__` 로 표현된다.\n\n<br/>\n\n### prototype\n\n함수도 객체이기 때문에 `[[Prototype]]` 을 가지며, 추가적으로 `prototype` 프로퍼티를 가진다. 함수의 `[[Prototype]]` 은 `Function.prototype` 을 가리킨다.\n\n```js\nconst testFunc = () => {};\n\ntestFunc.__proto__ === Function.prototype; // true\n```\n\n<br/>\n\n`prototype` 프로퍼티는 함수 객체가 생성자로 사용될 때 인스턴스화 된 객체의 부모 역할을 할 프로토타입을 가리킨다. 다시 말하면 같은 생성자 함수로 만든 객체는 같은 프로토타입을 가리킨다.\n\n```js\nfunction TestConstructor() {}\n\nconst testInstance1 = new TestConstructor();\nconst testInstance2 = new TestConstructor();\n\ntestInstance1.__proto__ === TestConstructor.prototype; // true\ntestInstance2.__proto__ === TestConstructor.prototype; // true\ntestInstance2.__proto__ === TestConstructor.__proto__; // false\n```\n\n또한, `prototype` 프로퍼티도 객체이기 때문에 `[[Prototype]]` 프로퍼티를 갖는다.\n\n<br/>\n\n### constructor\n\n프로토타입 객체는 `constructor` 프로퍼티를 갖는다. `constructor` 프로퍼티 `constructor` 프로퍼티는 자신을 생성한 객체를 가리킨다.\n\n```js\n// testInstance는 TestConstructor의 프로토타입을 상속받기 때문에 constructor 프로퍼티를 갖는다.\ntestInstance1.constructor === TestConstructor; //true\n```\n\n<br/>\n\n`constructor` 프로퍼티는 원본 객체를 가리킨다. 또한 해당 `constructor` 프로퍼티의 `prototype` 객체는 다시 `constructor` 프로퍼티를 갖는다. 프로토타입 객체의 `constructor` 프로퍼티는 원본 객체를 가리키므로 `prototype` 과 `constructor` 는 서로 참조한다고 할 수 있다.\n\n```js\nTestConstructor.prototype.constructor === TestConstructor; // true\nTestConstructor.prototype.constructor.prototype === TestConstructor.prototype; // true\n```\n\n<br/>\n\n## 프로토타입 체인\n\n객체의 프로퍼티나 메소드에 접근할 때, 해당 객체에 해당되는 프로퍼티가 없다면 `[[Prototype]]` 이 가리키는 프로토타입의 프로퍼티를 검색한다.\n\n<br/>\n\n### 객체의 프로토타입\n\n생성자 함수를 통해 생성된 객체는 원본 객체를 가리킨다. 즉 `Object()` 생성자 함수로 만들어진 객체는 `Object` 객체를 기리킨다.\n\n> 객체 리터럴 또한 `Object` 객체를 가리킨다. <br/>\n참고 - [객체](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/object.md#%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EC%97%90%EC%84%9C-%EC%A0%9C%EA%B3%B5%ED%95%98%EB%8A%94-%EC%83%9D%EC%84%B1%EC%9E%90-%EC%82%AC%EC%9A%A9)\n\n또한, 자바스크립트에서 제공하는 내장 객체들의 `[[Prototype]]` 은 `Object` 객체의 프로토타입을 가리킨다.\n\n따라서 모든 객체는 최종적으로 `Object` 객체의 프로토타입을 가리킨다.\n\n![prototype2](../assets/images/prototype2.png)\n\n<br/>\n\n### 함수의 프로토타입\n\n함수는 내부적으로 `Function()` 생성자 함수를 이용하여 생성된다. 따라서 함수는 `Function` 객체의 프로토타입에 정의된 프로퍼티들을 사용할 수 있다. 또한, `Function` 객체의 `[[Prototype]]` 은 `Object` 를 가리킨다.\n\n<br/>\n\n## 원시 타입(Primitive type)의 프로토타입\n\n자바스크립트의 원시 타입은 객체가 아니다. 하지만 프로토타입을 가지고 있다.\n\n```js\nconst num = 1;\nconst numObj = new Number(\"1\");\n\nnum.__proto === numObj.proto__;\n```\n> 위와 같은 이유로, `string` 타입의 변수는 원시타입임에도 `String` 객체의 메소드를 호출하여 사용할 수 있다.\n> ```js\n> const str = \"str\"\n> str.length // 3\n> ```\n\n<br/>\n\n## 프로토타입 객체의 수정과 변경\n\n프로토타입 객체를 수정하는 것은 프로토타입 참조에 영향을 주지 않는다. 하지만, 프로토타입 객체를 다른 객체로 변경하는 것은 프로토타입 참조에 영향을 준다.\n\n```js\nfunction TestConstructor() {}\nconst testInstance1 = new TestConstructor();\n\nTestConstructor.prototype.testProperty = \"test property!\";\nconst testInstance2 = new TestConstructor();\n\nTestConstructor.prototype = {};\ntestInstance3 = new TestConstructor();\n\ntestInstance1.testProperty; // test property\ntestInstance2.testProperty; // test property\ntestInstance3.testProperty; // undefined\n```\n\n위의 경우 `property` 객체가 변했기 때문에 `property` 객체 안에는 `constructor` 객체가 존재하지 않을 것이다. 대신 빈 객체가 존재한다. 따라서 `protoperty` 와 `constructor` 의 연결이 깨진다.\n\n---\n\n#### References\n\n- [Prototype - poiemaweb](https://poiemaweb.com/js-prototype)\n"
  },
  {
    "path": "Javascript/scope_this.md",
    "content": "# 스코프와 this, 그리고 화살표 함수\n\nES6에서는 화살표 함수 `() => {}`가 등장했다. 화살표 함수에 없는 것 등을 구글링하면 쉽게 찾아볼 수 있다.\n\n그 중 하나로 this가 있다. 흔히 화살표 함수에는 this가 없다고들 말한다.\n\n그런데 이게 단순히 this가 없다고 말하기에는 너무 아쉬운 점이 많다. 이 this가 없다는 것이 스코프와 어떤 관계일지 생각해보려고 글을 적는다.\n\n## 스코프\n\n스코프는 범위다. 프로그래밍 언어에서는 유효범위라고 해석한다. 정확히는 식별자를 찾아내기 위한 **규칙** 을 따르는 **유효범위** 를 스코프라고 한다.\n\n이 스코프에는 함수레벨 스코프, 블록레벨 스코프, 전역 스코프, 로컬 스코프와 같은 개념들이 있다. 그 중 동적 스코프와 정적 스코프라는 개념도 있다.\n\n### Dynamic, Static Scope\n\n동적, 정적이라는 단어는 서로 반대다. 타입에 관해서도 동적 타입, 정적 타입 언어라고 얘기한다.\n\n흔히 자바, C와 같은 언어는 정적 타입이라 부르고 파이썬, js와 같은 언어는 동적 타입이라 부른다. 실행과 관련해 정해지는 것은 동적, 실행 이전과 관련해 정해지는 것은 정적이라 부른다.\n\n스코프도 마찬가지다. 함수의 실행과 관련없이 코드가 만들어졌을 때, 즉 **어디서 선언 되었는지** 가 기준이면 정적 스코프라 부른다. 반대로 선언과 상관없이 함수가 **어디서 실행 되었는지** 가 기준이면 동적 스코프라고 부른다.\n\n### Lexical Scope\n\n#### 컴파일\n\njs의 정적스코프를 흔히 Lexical Scope라고도 부른다. 그 이유는 컴파일 단계에 있다.\n\nJS는 컴파일과 인터프리터의 장점을 모두 가지기 위해 두가지 단계를 모두 거친다.\n\n컴파일은 아주 많은 단계가 있다. 보통의 컴파일러는 아래와 같은 단계를 가진다.\n\n![컴파일러 단계](/assets/images/compilerDesign.jpg)\n\n이걸 JS로 바꾸어 쉽게 요약해보자\n\n    Source code => Lex => Parse => AST => Code Generator\n\n이런 단계를 거친다.\n\n설명을 좀 해보자면 **소스코드** 를 렉싱한다. 잘게 쪼갠다는 의미다. `var, x, =, 2, ;`이렇게 토큰을 나눈다고 한다.\n\n그리고 이를 파싱하여 AST라는 트리 단계로 만든다. 그런 뒤 즉시 실행코드로 만든다.\n\n#### 렉시컬\n\n중요한 것은 이 Lex 단계다. JS의 스코프의 기준은 이 렉싱타임에 결정난다. 그래서 렉시컬 스코프라고 부르는 것이다.\n\n함수가 어디서 실행되는지는 관심없고 이 렉싱 타임에서 스코프가 결정난다. 그래서 정적이며 렉시컬 스코프라고 부르는 것이다.\n\n## this\n\n### 일반 함수\n\n위의 내용까지는 JS가 가지는 Lexical Scope의 특징에 대해 알아봤다. 기본적으로 JS는 Lexical Scope다. 그런데 Dynamic Scope와 비슷하게 동작하는 것이 바로 이 this다.\n\n```js\nvar x = 5;\n\nfunction foo() {\n  let x = 50;\n  console.log(this.x); // 5\n  console.log(x); // 50\n}\n\nfoo();\n```\n\n함수 스코프의 렉시컬과는 다르다. foo()가 실행된 곳은 global이기 때문에 this는 global execution context를 가리킨다.\n\n```js\nvar obj = {\n  x: 5,\n  foo: function() {\n    console.log(this.x);\n  },\n  bar: function(fn) {\n    fn();\n  },\n  baz: function() {\n    function aa() {\n      console.log(this.x);\n    }\n    aa();\n  }\n};\n\nvar x = 50;\nobj.foo(); // 5\nobj.bar(obj.foo); // 50\nobj.baz(); // 50\n```\n\n객체의 메서드의 경우 조금 복잡하다. 객체의 메서드의 this는 객체에 묶인다.(lexical)\n\n콜백은 dynamic이며 내부함수의 경우도 dynamic이다.\n\n그럼 아래와 같은 예시를 보자\n\n```js\nvar obj = {\n  x: 5,\n  foo: function() {\n    console.log(this.x); // 5\n    setTimeout(function() {\n      console.log(this.x); // 50\n    }, 1000);\n  }\n};\n\nvar x = 50;\nobj.foo();\n```\n\nfoo는 객체의 메서드다. 따라서 this.x는 5다. 그런데 setTimeout의 콜백은 콜백이므로 dynamic으로 작동한다. 따라서 50이다.\n\n### 화살표 함수\n\n이에 화살표 함수가 등장했다. 화살표 함수의 실행컨텍스트는 일반함수와 비슷하다. 하지만 this 바인딩이 일반 함수처럼 작동하지 않는다.\n\n**즉 일반함수의 Dynamic Scope 규칙을 따르지 않는다.**\n\n대신 자신을 둘러싼 Lexical Scope의 this값을 가져온다. 아까의 예시를 다시보자\n\n```js\nvar obj = {\n  x: 5,\n  foo: function() {\n    console.log(this.x); // 5\n    setTimeout(() => {\n      console.log(this.x); // 5\n    }, 1000);\n  }\n};\n\nvar x = 50;\nobj.foo();\n```\n\n이번엔 둘 다 5다. foo의 this는 객체의 this라 5다.\n\n콜백의 this는 일반함수라면 dynamic이다. 그러나 화살표함수다. 따라서 this가 자신을 둘러싼 Lexical Scope의 this 즉 객체의 this를 가져오게 된다. 따라서 5다.\n\n## 문제점\n\n화살표 함수는 이렇게 this가 없어졌기 때문에 기존에 지원하던 객체의 메서드의 경우 문제가 생길 수 있다.\n\n```js\nconst objNormal = {\n  x: 3,\n  foo: function() {\n    console.log(this.x);\n  }\n};\n\nconst objArrow = {\n  x: 3,\n  foo: () => {\n    console.log(this.x);\n  }\n};\n\nvar x = 30;\nobjNormal.foo(); // 3\nobjArrow.foo(); // 30\n```\n\n원래 지원하던 this를 없애버리는 경우다. 이럴 때는 함수 축약형을 사용한다.\n\n```js\nconst obj = {\n  x: 3,\n  foo() {\n    console.log(this.x);\n  }\n};\n\nvar x = 30;\nobj.foo(); // 3\n```\n\n추가적인 예로 프로토타입, 생성자함수, addEventListner의 콜백으로의 사용 등이 있다.\n\n## 결론\n\n화살표 함수는 단순히 this가 없는 것 그 이상의 의미를 가진다.\n\n일반함수의 this는 Lexical, Dynamic Scope 두가지를 혼용하여 사용하였다. 그러나 화살표 함수의 등장으로 this가 통일되게 Lexical Scope의 규칙을 따르게 된다.\n\n이것이 큰 변화다.\n\n그렇지만 단점도 분명히 있기 때문에 잘 알고 사용하는 것이 중요하다.\n\n---\n\n### 참고자료\n\n- [You don't know JS 타입과 문법, 스코프와 클로저], 카일심슨, pp. 279 ~ 282\n- [Poiemaweb 6.3 Arrow function 화살표 함수](https://poiemaweb.com/es6-arrow-function)\n"
  },
  {
    "path": "Javascript/throttling과 rAF.md",
    "content": "# throttling과 rAF\n\n## throttling(쓰로틀링)\n\n`Throttling`은 스크롤 이벤트에서 주로 사용되는 기술로 지나치게 많은 이벤트가 발생하는 것을 몇 초에 한 번, 또는 몇 밀리초에 한 번씩만 실행되게 제한을 두는 것이다.<br/>\n\n```js\nvar timer;\ndocument.querySelector('#input2').addEventListener('input', function (e) {\n    if (!timer) {\n        timer = setTimeout(function() {\n            timer = null;\n            console.log('ajax 요청', e.target.value);\n        }, 2000);\n    }\n});\n```\n\n위의 코드에서 보다시피 `setTimeout`을 이용하여 2초 동안에 한 번만 ajax요청을 하도록 하고 있다. 하지만 `setTimeout`은 지정된 시간 뒤에 무조건 실행되는 것을 보장할 수 없다. 위의 코드는 2초 뒤에 콜백 함수를 실행하는 것이 아니라 2초 뒤에 `Task Queue`에 넣는 것을 의미한다. <br/>**`Task Queue`에 들어간 함수는 순차적으로 `Call Stack`에 옮겨지고 실행**되는데 만약 `Call Stack`이 비워져 있지 않다면, 지정한 시간 이후에 실행되는 것을 보장할 수 없다.\n\n<br/>\n\n## requestAnimationFram(rAF)\n\n**`rAF`는 브라우저의 최적화 상태를 고려하여 이벤트를 실행**한다. 즉, `setTimeout`처럼 무조건 지정된 시간에 한 번씩 이벤트를 트리거하지 않아도 된다.\nJbee님 포스팅 중 [스크롤 이벤트 최적화](https://jbee.io/web/optimize-scroll-event/)를 보면 `rAF`를 이용하여 스크롤 이벤트를 구현하는 방식을 살펴 볼 수 있는데 간단히 보면 다음과 같다.\n\n```js\nfunction rAFScroll(callback) {\n  let tick = false\n\n  return function trigger() {\n    if (tick) {\n      return;\n    }\n\n    tick = true\n    return requestAnimationFrame(function task() {\n      tick = false\n      return callback();\n    })\n  }\n}\n```\n\n`trigger`함수를 보면 `tick`의 값이 `false`일 경우에만 `requestAnimationFrame`의 콜백이 실행된다. <br/>즉, **콜백 함수(`callback`)가 `rAF`에 의해 브라우저가 최적화된 상태에서만 `tick`의 값이 `false`가 되고 실행**된다. 순차적으로 정리하면 다음과 같다.\n\n1. `rAF`의 콜백 함수인 `task`함수가 `animation frame`에 들어간다.\n2. `tick`의 값이 `true`라면 `trigger`함수가 호출되어도 콜백 함수가 실행되지 않는다.\n3. `task`함수가 실행되면서 `tick`이 `false`가 되면 다시 콜백 함수가 실행될 수 있는 환경이 된다.\n\n이처럼 쓰로틀링을 사용하지 않고 `rAF`을 사용하여 이벤트 최적화가 가능하며 `rAF`는 애니메이션의 최적화에도 많이 사용되는 API이기 때문에 잘 알아두는게 좋다.\n\n<br/>\n\n---\n\n#### Reference\n\n- [스크롤 이벤트 최적화](https://jbee.io/web/optimize-scroll-event/)\n- [쓰로틀링과 디바운싱](https://www.zerocho.com/category/Javascript/post/59a8e9cb15ac0000182794fa)\n\n"
  },
  {
    "path": "Javascript/tricks_of_js.md",
    "content": "# 자바스크립트 꿀팁\n\njs로 개발하면서 엄청 대단한 것은 아니지만 생각보다 소소한 팁을 정리해봤다.\n\n## Array.length\n\n보통 배열의 길이를 구할 때 사용하는 속성이다. 그런데 이 속성을 이용하면 좀 더 재밌는 것을 할 수 있다.\n\n### 빈 배열에 length 속성 할당\n\n```js\nconst arr = [];\narr.length = 100;\nconsole.log(arr); // (100) [empty × 100]\n```\n\n이렇게 만들면 빈 100칸짜리 배열이 만들어 진다.\n\n### 반대로 배열의 length보다 작은 값 할당\n\n```js\nconst arr = [1, 2, 3, 4, 5];\narr.length = 3;\nconsole.log(arr); // (3) [1, 2, 3]\n```\n\n길이를 기준으로 뒤의 원소들을 그냥 지워버린다.\n\n## switch문 대체하기\n\nswitch문은 다중 조건문에서 `if-else if-else` 구조보다 코드를 읽기 좋게 만들어준다.\n\n```js\nconst doit = 'add';\n\nswitch (doit) {\n  case 'add':\n    console.log('this is add');\n    break;\n  case 'delete':\n    console.log('this is delete');\n    break;\n  case 'update':\n    console.log('this is update');\n    break;\n  case 'get':\n    console.log('this is get');\n    break;\n\n  // ...\n\n  default:\n    console.log('this is nothing');\n    break;\n}\n```\n\n그런데 이 역시도 문제가 있다. 조건이 많아지면 코드가 꽤나 지저분해진다는 점이다. 이를 해결하는 방법이 자바스크립트 객체의 메서드를 이용하는 방법이다. 파이썬에서는 dispatching method라고도 불리는 방법이다.\n\n```js\nconst obj = {\n  add: () => console.log('this is add'),\n  delete: () => console.log('this is delete'),\n  update: () => console.log('this is update'),\n  get: () => console.log('this is get'),\n  post: () => console.log('this is post'),\n  foo: () => console.log('this is foo')\n};\n\nconst doit = 'add';\n\nobj[doit]();\n```\n\n## filter(Boolean)\n\nArray.prototype.filter() 메서드는 유용하게 사용되는 메서드다. callback의 return value가 true인 것만 반환된다.\n\n사용 예시는 다음과 같다.\n\n```js\nconst arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];\n\nconsole.log(arr.filter(x => x > 5)); // (5) [6, 7, 8, 9, 10]\n```\n\n그럼 아래와 같은 경우는 어떨까?\n\n```js\nconst arr = ['', '[', \"'abc'\", undefined, '', '', undefined, '33', undefined, ' true', ']', ''];\n\nconst filteredArr = arr.filter(x => Boolean(x));\nconsole.log(filteredArr); // (5) [\"[\", \"'abc'\", \"33\", \" true\", \"]\"]\n```\n\n이를 깔끔하게 더 줄이는 것도 가능하다.\n\n```js\nconst arr = ['', '[', \"'abc'\", undefined, '', '', undefined, '33', undefined, ' true', ']', ''];\n\nconst filteredArr = arr.filter(Boolean);\n```\n\n결과는 완전히 동일하다. 비슷한 방식으로 아래와 같은 것도 가능하다.\n\n```js\nconst stringNumbers = ['1', '2', '3', '4', '5', '6', '7', '8'];\nconst numbers = stringNumbers.map(Number);\n```\n\n- [JavaScript Tip: Remove ?falsy? Items Out of an Array](http://www.devign.me/javascript-tip-remove-falsy-items-out-of-an-array)\n\n## Object.prototype.assign()\n\n개발을 하다보면 객체를 파라미터로 넘겨야하는 경우가 있다. 그리고 심지어 파라미터로 받은 객체의 값을 수정해야 하는 경우도 생긴다.\n\n물론 의존성의 측면에서 이는 매우 좋지 않으며 상태를 직접 변경하기 때문에 side-effect가 발생할 수 있다.\n\n하지만 그런 이론적 배경에도 불구하고 객체를 넘겨야하는 경우가 있다. 그런데 문제는 객체의 값을 할당하기만 하면 포인터만 이동하여 얕은 복사가 된다는 점이다.\n\n그러나 단순 복사가 아니라 깊은 복사가 필요한 경우가 있는데 이 때 assign을 이용하면 내용만 같은 새로운 객체가 만들어진다.\n\n아래는 동작하진 않는 예제 코드다.\n\n```js\nconst obj = { x: 10, y: 20 };\n\nconst changeValue = obj => {\n  obj.x = 15;\n  doSomething(obj);\n};\n\nchangeValue(obj);\n\ndoAnoter(obj); // bug :  x는 10이어야 합니다.\n```\n\ndoAnother는 꼭 x가 10이어야 하는 경우다.\n\n이 경우 assign을 이용하여 아예 다른 객체를 넘길 수 있다.\n\n```js\nconst obj = { x: 10, y: 20 };\n\nconst changeValue = obj => {\n  obj.x = 15;\n  doSomething(obj);\n};\n\nchangeValue(Object.assign({}, obj));\n\ndoAnoter(obj);\n```\n\nmdn 문서에 따르면 함수 정의는 다음과 같다.\n\nThe Object.assign() method is used to copy the values of all enumerable own properties **from one or more source objects** **to a target object**. It will **return the target object**\n\nObject.assign(target, ...sources)\n\n- target\n  - 대상 객체.\n- sources\n  - 하나 이상의 출처 객체.\n\n핵심은 from sources to target then return target이다.\n\n---\n\n### 참고자료\n\n- [JavaScript Tip: Remove ?falsy? Items Out of an Array](http://www.devign.me/javascript-tip-remove-falsy-items-out-of-an-array)\n- [Object​.assign()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)\n"
  },
  {
    "path": "Javascript/underscore와 lodash그리고 Native.md",
    "content": "# underscore와 lodash 그리고 native\n\n`underscore`와 `lodash`는 자바스크립트 개발을 진행하다보면 많이 듣게 되는 라이브러리다.<br/> 이 둘은 모두 자바스크립트의 **유티릴리성 라이브러리**로서 개발 중 자주 사용하게 되는 함수들을 정의하고 있다. 또한 Native 즉, 일반적으로 `ECMAScript`에서 지원해왔던 함수에도 유틸리성 함수는 존재한다.\n\n<br/>\n\n## underscore / lodash\n\n---\n\n`underscore`는자바스크립트의 함수형 프로그래밍에 초점을 맞춘 유틸리티성 라이브러리로 `Backbone`에 의존성을 가지고 있다.<br/>`lodash` 또한 자바스크립트 유틸리티성 라이브러리로 크로스환경에 더 안전성을 주고자 하는데 목적이 있다.\n\n현재는 `underscore`의 superset 형태로 함수, 문서, 유닛 테스트, 성능이 더 뛰어나다고 한다.\n\n`lodash`는 `underscore`의 API를 구현함과 동시에 `underscore`에 존재하지 않는 함수들도 추가로 개발하였다. `lodash`의 성능이 `underscore`보다 더 좋다고들 한다.\n\n이 두 라이브러리는 모두 `_func()`의 형태로서 배열을 예로 들어보자.\n\n```js\n//lodash\n_.forEach([4, 8], console.log(n * n)); //16, 64\n\n//underscore\n_.each([4, 8], console.log(n * n));\n```\n\n<br/>\n\n## Native\n\n---\n\n위와 같은 예를 자바스크립트의 기본 메서드만 활용하여 구현해보면 다음과 같다.\n\n```js\n[4, 8].forEach(item => console.log(item * item);); //16, 64\n```\n\n코드로만 봤을때는 별 차이가 없지만 중요한 차이는 `lodash`와 `underscore`에서느 배열을 인자로 전달한다는 것이다.\n\n기본적으로 `arr.forEach()`의 경우에 **`arr`가 배열이 아닌 경우 에러가 발생**한다. **하지만 `lodash`와 `underscore`에서는 에러가 발생하지 않는다.** 즉, 스크립트가 뻗지 않는다.\n\n예를 들어, `document.getElementByClassName()`으로 얻은 값은 배열이 아닌 유사배열객체이기 때문에 `forEach`를 돌렸을 때 에러가 발생할 것이다. 하지만, 위 2개의 라이브러리는 에러를 발생시키지 않고 정상적으로 동작한다.\n\n```js\ndocument.getElementsByClassName('className').forEach(item=>{ console.log(item) }); \n//Uncaught TypeError: document.getElementsByClassName(...).forEach is not a function\n```\n\n당연히 개발자가 위와 같은 에러가 발생하지 않도록 예외 처리를 잘해줘야 겠지만, `lodash`나 `underscore`를 사용하면 이런 예외 처리를 해줄 필요가 없다.\n\n<br/>\n\n## underscore / lodash vs Native\n\n`underscore`나 `lodash`는 다양한 용도의 메서드가 제공된다. 이 부분은 `JS`의 내장함수로는 얻을 수 없는 명확한 이점이다. 또한 **두 라이브러리는 다양한 객체 타입에서도 사용 가능하기 때문에 데이터 처리를 하는데 있어서 유용**하다. 이에 따라 상당한 **생산성 향상**으로 이어질 수 있다.\n\n하지만 기본 JS 내장함수를 사용하는 것이 **성능 상 유리**하고 **협업시 라이브러리의 사용보다는 기본 내장 함수를 사용하는 것이 유지보수 측면에서도 유리**할 것이다.<br/> 또한 브라우저와의 **호환성 문제**도 무시할 수는 없을 것이다. `lodash`의 경우에는 V8엔진에서만 지원하기 때문이다.\n\n또한 JS는 ES6의 등장으로 ES5의 한계를 많이 극복했다.\n\n```js\n[...document.getElementsByClassName('className')].forEach(item=>{ console.log(item) });\n```\n\n위와 같이 ES6의 `Spread`를 이용하여 충분히 유사배열객체를 배열로 쉽게 변환할 수 있다.\n\n<br/>\n\n---\n\n#### Reference\n\n- [underscore Docs](https://underscorejs.org/)\n- [lodash Docs](https://lodash.com/docs/4.17.11)\n- [native vs lodash vs underscore in javaScript(>ES5)](http://blog.kazikai.net/?p=180)\n"
  },
  {
    "path": "Javascript/window.history.md",
    "content": "# window.history\n\n**SPA(Single Page Application)** 사이트를 만들어 보신 분들은 한 번쯤 생각하게 되는 고민이 있다. 어떻게 앞으로 가기, 뒤로 가기, 새로 고침을 구현해야 할까? 라는 고민이다.\n\n기존의 사이트들은 페이지 이동 Link를 누르게 되면 해당 주소에 맞는 Resource를 내려받아 화면에 보여주면서 화면이 전환되는 형태였다면, SPA는 1개의 `html` 파일에서 JavaScript를 사용하여 컴포넌트를 붙였다 떼었다를 한다. 여러 페이지로 구성된 사이트처럼 보이도록 앞으로 가기 뒤로 가기가 불가능하다.\n\n만약 앞으로 가기, 뒤로 가기, 새로 고침이 구현되지 않은 상태에서 브라우저에서 지원하는 앞으로 가기, 뒤로 가기 기능을 이용한다고 하자.\n같은 도메인에서 이동한 적이 없으니 이전 또는 이후에 방문한 도메인으로 이동을 하게 된다.\n새로 고침을 하면 현재 사이트의 메인페이지로 이동하게 될 것이다.\n\n대개 개발자분들의 해결방법은 라이브러리를 사용해서 구현한다. Single Page이지만 Page가 여러 개인듯한 모양을 만들어준다. 하물며 앞으로 가기, 뒤로 가기, 새로 고침도 잘된다. \n그러나 우리가 알고 있어야 하는 부분은 단순하게 이 라이브러리를 사용하니까 잘된다가 아니라 **어떻게 이렇게 되는 거지?** 하는 궁금증이 우선 되어야 한다.\n\n우리는 React를 기준으로 어떻게 앞으로 가기, 뒤로 가기, 새로 고침이 가능한지를 살펴보자.\n<br/>\n\n## react-router-dom\n\nReact로 사이트를 만들 때 Router가 필요하다면 react-route-dom을 사용할 것이다. 이 라이브러리를 사용함으로써 간편하게 주소에 따라 다른 페이지가 보이고, 이동이 가능하며 뒤로 가기도 가능하다.\nreact-router-dom은 reactDOM을 위해 존재하는 Router 라이브러리로 싱글 페이지를 여러 페이지로 이동하는 듯한 느낌을 준다. \n\nreact-router-dom의 상위 프로젝트로 react-router라는 프로젝트가 존재한다. \n\n해당 패키지들을 살펴보면\n\n- [react-router Package](https://github.com/ReactTraining/react-router/tree/master/packages)\n\n![react-router Package](https://user-images.githubusercontent.com/24274424/61193172-b925bd00-a6f4-11e9-877e-8d1f5f6febf2.png)\n\n\nDOM과 Native라고 적혀있는 폴더를 볼 수 있다. 이를 통해 react-router라는 공통의 패키지가 존재하며 하위의 패키지로 DOM과 Native를 위한 패키지가 있구나라는 것을 알 수 있다. 이제 우리는 웹을 개발할 때 사용하는 react-router-dom을 열어보자\n\nreact-router-dom 패키지의 *modules/index.js*를 살펴보게 되면\n\n- [modules/index.js](https://github.com/ReactTraining/react-router/blob/master/packages/react-router-dom/modules/index.js)\n\nReact에서 react-router-dom을 사용하면서 보았던 `BrowserRouter`, `Link`, `NavLink`가 있는 것을 확인할 수 있다. 그중에서 우리가 기본으로 사용하는 `BrowserRouter.js` 파일을 열어보자\n\n```js\nimport React from \"react\";\nimport { Router } from \"react-router\";\nimport { createBrowserHistory as createHistory } from \"history\";\nimport PropTypes from \"prop-types\";\nimport warning from \"tiny-warning\";\n\n/**\n * The public API for a <Router> that uses HTML5 history.\n */\nclass BrowserRouter extends React.Component {\n  history = createHistory(this.props);\n\n  render() {\n    return <Router history={this.history} children={this.props.children} />;\n  }\n}\n\nif (__DEV__) {\n  BrowserRouter.propTypes = {\n    basename: PropTypes.string,\n    children: PropTypes.node,\n    forceRefresh: PropTypes.bool,\n    getUserConfirmation: PropTypes.func,\n    keyLength: PropTypes.number\n  };\n\n  BrowserRouter.prototype.componentDidMount = function() {\n    warning(\n      !this.props.history,\n      \"<BrowserRouter> ignores the history prop. To use a custom history, \" +\n        \"use `import { Router }` instead of `import { BrowserRouter as Router }`.\"\n    );\n  };\n}\n\nexport default BrowserRouter;\n```\n\n`BrowserRouter.js` 파일 안쪽을 보게되면 생각보다 심플하게 36라인으로 구성되어있는 것을 볼 수 있다. 그 중에서도 개발모드를 제외하면 10라인도 되지 않는다.\n\n```js\nimport React from \"react\";\nimport { Router } from \"react-router\";\nimport { createBrowserHistory as createHistory } from \"history\";\n\n/**\n * The public API for a <Router> that uses HTML5 history.\n */\nclass BrowserRouter extends React.Component {\n  history = createHistory(this.props);\n\n  render() {\n    return <Router history={this.history} children={this.props.children} />;\n  }\n}\n\nexport default BrowserRouter;\n```\n\n본론으로 돌아와 우리가 보아야 하는 내용은 BrowserRouter class에서 `createHistory()`라는 함수이다. 이 함수는 **history** 라이브러리를 통해서 가져왔으며, history를 만들고 그것을 라우터라는 컴포넌트에 props로 넘겨주고 있다.\n\n위에서 주석에서도 보이듯이 \n\n```text\nThe public API for a <Router> that uses HTML5 history.\n```\n\nHTML5 history를 사용하고 있다고 알려주고 있다.\n<br/>\n\n### [history 라이브러리](https://github.com/ReactTraining/history)\n\nhistory 라이브러리의 설명을 보면 이렇게 적혀있다.\n\n- `createBrowserHistory` is for use in modern web browsers that support the HTML5 history API (see cross-browser compatibility)\n- `createMemoryHistory` is used as a reference implementation and may also be used in non-DOM environments, like React Native or tests\n- `createHashHistory` is for use in legacy web browsers\n\n`createBrowserHistory`는 HTML5 history API를 제공하는 모던 웹 브라우저에서 사용,\n`createMemoryHistory`는 DOM 환경이 아닌 Native나 tests에서 사용하는 것,\n`createHashHistory`는 예전 웹 브라우저를 위해서 사용되는 것이라고 설명되어있다. \n\n위에서 react-router-dom에서 보았던 `createBrowserHistory` 함수가 있는 것을 확인했다. \n<br/>\n\n#### createBrowserHistory.js\n\n[createBrowserHistory 확인하기](https://github.com/ReactTraining/history/blob/763fc13bc8a52aff91d9594a7c1d944faa97961a/modules/createBrowserHistory.js#L38)\n\n위의 코드 중 일부분을 가져오면\n\n```js\n/**\n * Creates a history object that uses the HTML5 history API including\n * pushState, replaceState, and the popstate event.\n */\nfunction createBrowserHistory(props = {}) {\n  const globalHistory = window.history;\n  const canUseHistory = supportsHistory();\n  const needsHashChangeListener = !supportsPopStateOnHashChange();\n  ...\n```\n\n`const globalHistory = window.history;`에서 보이듯이 `window.history`라는 HTML5 history API를 사용하고 있는 것을 볼 수 있다.\n\n추가적으로 뒤에서 설명할 HTML5 history API 몇가지가 사용되는 것을 확인할 수 있다.\n\n```js\nfunction setState(nextState) {\n    Object.assign(history, nextState);\n    history.length = globalHistory.length;\n    transitionManager.notifyListeners(history.location, history.action);\n  }\n\n---\n\nglobalHistory.pushState({ key, state }, null, href);\n\n---\n\nglobalHistory.replaceState({ key, state }, null, href);\n\n---\n\nfunction go(n) {\n  globalHistory.go(n);\n}\n```\n\n<br/>\n\n## HTML5 history API\n\n> [MDN - History](https://developer.mozilla.org/ko/docs/Web/API/History)\n\nJavascript에서 자체적으로 history를 관리할 수 있는 객체이다.\n`window.history` 속성은 읽기 전용이며 `History object`를 반환한다. 또한 브라우저 세션 히스토리(현재 페이지가 있는 탭 또는 브라우저에서 방문한 페이지)를 조작하기 위한 인터페이스를 제공한다. 이렇게 조작이 가능하여 SPA에서도 페이지가 이동한 것과 같은 기능을 만들 수 있는 것이다.\n<br/>\n\n### Syntax\n\n```js\nconst historyObj = window.history;\n```\n\n최상위 페이지의 경우 `History object`를 통해 접근할 수 있는 세션 히스토리 목록은 브라우저의 뒤로 가기, 앞으로 가기 버튼 옆의 드롭다운 목록에서 볼 수 있다. (크롬의 경우 버튼 우클릭)\n<br/>\n\n### History Interface\n\nHistory 인터페이스는 브라우저의 세션 히스토리를 조작할 수 있게 해준다. 세션 히스토리에는 탭에서 방문했던 페이지들이나, 현재 페이지가 로딩된 프레임들이 포함되어있다.\n\nHistory 인터페이스는 어떤 속성도 상속받지 않는다.\n<br/>\n\n### Properties\n\n- `History.length` : 세션 히스토리의 현재 로딩된 페이지를 포함한 요소 숫자들을(정수 값) 반환한다. 예를 들면, 새로운 탭의 로딩된 페이지는 1을 반환한다.\n- `History.scrollRestoration` : 웹 어플리케이션에서 히스토리 네비게이션의 default 스크롤 복원 기능을 명시적으로 선언한다 .이 속성은 자동 또는 수동이 가능하다.\n- `History.state` : 히스토리 스택의 가장 상위에 있는 상태 값을 반환한다. popstate 이벤트 콜없이 바로 상태를 볼 수 있는 방법이다.\n\n<br/>\n\n### Methods\n\n#### History 내 이동\n\n1. 앞으로 가기와 뒤로가기\n- `History.back()` : 세션히스토리의 이전 페이지로 이동한다. 브라우저 백 버튼을 눌렀을 때와 똑같은 효과, `history.go(-1)` 와 동등한 기능이다.\n- `History.forward()` : 세션히스토리의 다음 페이지로 이동한다. 브라우저의 앞으로가기 버튼을 눌렀을 때와 같은 효과, `history.go(1)`와 동등한 기능이다.\n\n2. 히스토리에서 특정 위치로 가기\n- `History.go()` : 세션히스토리의 특정 페이지를 로딩한다, 현재 페이지의 상대적인 위치에 따라 페이지 순서가 정의된다. 예를 들어, -1은 이전 페이지, 1은 다음 페이지. 변수 값을 넘기지 않거나, 0의 값을 가진 go() 메서드는 현재 페이지를 새로고침을 한다.​​​​​​​\n<br/>\n\n#### History Entry 추가 및 변경\n\nHTML5는 사용자가 History Entry를 추가하거나 변경할 수 있는 `history.pushState()`와 `history.replaceState()` 메서드를 제공한다. 이 메서드들은 `window.onpopstate` 이벤트와 연동하여 동작한다.\n\n- `History.pushState()`\n- `History.replaceState()`\n\n<br/>\n\n#### pushState() 메서드\n\n```js\nconst stateObj = {foo : \"foo\"};\nhistory.pushState(state, \"page1\", \"page1.html\");\n```\n\n`pushState()`는 세 개의 변수를 가진다. state 객체, title(예약되어 있으나 내부 역할 없음), 옵션인 URL. 이 변수들에 대해 상세히 알아보면\n\n- state 객체 : `pushState()`에 의해 생성된 새로운 history를 포함하고 있는 자바스크립트 객체이다. 사용자가 새로운 상태로 이동할 때 마다, popstate 이벤트가 발생하고, 이 이벤트의 state 속성은 히스토리의 state객체 사본을 가진다.\n\n- title : Firefox는 현재 이 변수를 무시한다. 나중에 사용될 수도 있기 때문에 빈 문자열을 지정해 놓는 것은 안전하다고 한다. 빈 문자열 대신 이동하고자 하는 state마다 짧은 명칭을 부여하는 것도 좋다.\n\n- URL : 새로운 히스토리 엔트리의 URL을 지정한다. `pushState()` 호출 이후에는 브라우저가 이 URL을 로딩하지 않는 것을 명심해야 한다. 하지만 아마 나중에도 사용될 수도 있다. 새롭게 할당되는 URL은 현재의 URL에 기준하기 때문에, 절대 경로일 필요는 없다. 새로운 URL은 기존의 URL을 기준으로 해석된다. 새로운 URL은 현재 URL에서 유추될 수 없다면 `pushState()`는 예외가 발생한다. 이 변수는 선택 사항으로, 명시되지 않는다면, 현재 URL로 지정된다.\n\n<br/>\n\n#### replaceState() 메서드\n\n```js\nconst stateObj = {foo : \"bar\"};\nhistory.pushState(stateObj, \"page2\", \"page2.html\");\n```\n\n`history.replaceState()`는 `history.pushState()`와 동일하게 동작한다. `replaceState()`는 새로운 히스토리를 하나 생성하는 대신에 현재의 히스토리 엔트리를 변경한다.\n\n`replaceState()` 는 state 객체나 사용자의 동작에 따라 현재 히스토리 엔트리의 URL을 업데이트 하려고 할 때 유용하다.\n<br/>\n\n#### popstate 이벤트\n\npopstate 이벤트는 현재 활성화된 히스토리 엔트리에 변화가 있을 때 마다 실행된다. 만약 pushState 함수나 replaceState 함수에 의해 현재 활성화되어 있는 히스토리 엔트리가 조작 및 변경된다면, popstate 이벤트의 state 속성은 히스토리 항의 state 객체의 사본이 된다.\n<br/>\n\n#### 현재 상태 읽기\n\n페이지가 로딩이 되었을 때, state 객체는 null이 아닐 수 있다. \n예를 들어, 페이지가 `pushState()`나 `replaceState()`를 이용하여 state 객체를 설정한 상태에서 브라우저를 재시작했을 때가 있다.\n페이지를 다시 불렀을 때 onload 이벤트만 페이지에 들어가고, popstate는 호출되지 않는다. 그러나 `history.state` 속성에 접근하면, state 객체는 마치 popstate 발생시에 얻을 수 있는 객체와 동일한 객체를 얻을 수 있다.\n\npopstate 이벤트를 기다릴 필요 없이, 아래와 같은 명령어를 이용하여 현재 히스토리 엔트리의 상태에 접근할 수 있다.\n\n```js\nconst currentState = history.state;\n```\n\n<br/>\n\n#### Reference\n\n- [MDN - History_API](https://developer.mozilla.org/ko/docs/Web/API/History_API)\n- [MDN - History](https://developer.mozilla.org/ko/docs/Web/API/History)\n- [MDN - onpopstate](https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onpopstate)\n"
  },
  {
    "path": "Javascript/논리연산자.md",
    "content": "# 논리연산자\n\n다른 프로그래밍 언어들과 마찬가지로 자바스크립트도 논리연산자 문법을 사용할 수 있습니다. `||`(OR), `&&`(AND), `!`(NOT) 총 세 종류의 논리 연산자가 존재합니다. 피연산자로 모든 타입의 값을 받을 수 있고 평가는 Boolean 형으로 변환되어 진행되게 됩니다. 결과 또한 모든 타입이 될 수 있습니다.\n\n## Boolean\n\njavascript에서 Boolean 값은 true와 false 중 하나의 값입니다. javascript에서 거짓으로 판정되는 값(falsy)은 `undefined`, `null`, `0`, `-0`, `NaN`, `\"\"` 총 6개입니다. 참으로 판정되는 값(truthy)은 앞서 거짓으로 판정되는 6개 값을 제외한 값들입니다.\n\n## || (OR)\n\n`||`(OR) 연산자는 비교하는 두 개의 인수 중 하나라도 true인 경우 true를 반환하고 그 외의 경우에 false를 반환합니다.\n\n```javascript\ntrue || true // true\ntrue || false // true\nfalse || true // true\nfalse || false // false\n```\n\n## && (AND)\n\n`&&`(AND) 연산자는 비교하는 두 개의 인수 모두 true인 경우 true를 반환하고 그 외의 경우에 false를 반환합니다.\n\n```javascript\ntrue && true // true\ntrue && false // false\nfalse && true // false\nfalse && flase // false\n```\n\n`&&`(AND) 는 `!`(NOT) 보다 우선순위가 낮고 `||`(OR) 보다 우선순위가 높습니다.\n\n## ! (NOT)\n\n`!`(NOT) 연산자는 피연산자를 Boolean 형으로 변환한 뒤 변환된 값의 역을 반환합니다.\n\n```javascript\n!true // false\n!false // true\n\n!\"something\" // false\n!undefined // true\n```\n\nBoolean형으로 변환된 값이 true인 경우는 false로 false인 경우는 true로 변환됩니다.\n\n```javascript\nalert(!!undefined); // false\nalert(Boolean(undefined)); // false\n\nalert(!!\"something\") // true\nalert(Boolean(\"something\")) // true\n```\n\n`!!` 같이 사용할 경우 특정 값을 Boolean형으로 변환 가능합니다. 또한 `Boolean` 내장 함수를 사용해도 특정 값을 Boolean 형으로 변환 가능합니다.\n\n## 연산자 우선순위\n\n논리연산자의 연산자 우선순위는 `!`(NOT),  `&&`(AND), `||`(OR) 순으로 실행됩니다.\n\n## 숏 서킷 평가\n\n자바스크립트 논리연산자는 왼쪽에서 오른쪽 평가를 진행합니다. `||`(OR) 연산자의 경우 평가가 진행되는 도중 truthy를 만나면 평가를 멈추는 특성을 가지게 되는데 이것을 숏 서킷 평가(short circuit evaluation)라고 합니다.\n\n```javascript\ntrue || true;\n// true\ntrue || false;\n// true\nfalse || false;\n// false\n```\n\n위 세 가지 경우에 대한 예제 중 첫 번째, 두 번째의 경우 모두 첫 번째 값이 truthy 이기 때문에 오른쪽 인수가 무엇이 되었든 상관없이 거기서 평가를 멈추고 true를 반환하게 됩니다.\n\n```javascript\nfalse || alert(\"alert 창이 뜰까요??\")\ntrue || alert(\"alert 창이 뜰까요??\")\n```\n\n다음은 숏 서킷 평가에서 truthy를 만나면 평가를 멈춘다는 것을 좀 더 명확하게 확인하기 위한 예제입니다. 첫 번째 경우는 왼쪽 인수가 false이기 때문에 다음 인수 평가로 넘어가게 되고 truthy이므로 alert 창이 뜨게 됩니다. 하지만 두 번째 경우 왼쪽 인수가 truthy 이므로 숏 서킷 평가에 의해 평가를 멈추게 되어 alert창이 뜨지 않습니다.\n\n이렇듯 숏 서킷 평가는 왼쪽 조건이 falsy일 경우에만 오른쪽 인수를 실행하도록 할 때 사용할 수 있습니다.\n\n```javascript\nvar car = {\n wheel: 4\n}\nconsole.log(car.body || 'white'); // white\n```\n\n```javascript\nvar car = {\n wheel: 4,\n body: 'black'\n}\nconsole.log(car.body || 'white'); // black\n```\n\n위 예제들과 같이 car라는 객체에 body라는 key가 없어  undfined를 반환하더라도 안전하게 처리할 수 있도록 해준다.\n\n```javascript\nvar a;\nvar b = null;\nvar c = undefined;\nvar d = 4;\nvar e = 'five';\n\nvar f = a || b || c || d || e;\n\nconsole.log(f);\n```\n\n다음은 [stack overflow](https://stackoverflow.com/questions/2100758/javascript-or-variable-assignment-explanation)에서 실제로 화제가 되었던 코드입니다. console에 무엇이 출력될까요?\n\n```javascript\nvar a; // undefined (falsy value)\nvar b = null; // null (falsy value)\nvar c = undefined; // undefined (falsy value)\nvar d = 4; // number (truthy)\nvar e = 'five'; // assigment short circuits before reaching here\n\nvar f = a || b || c || d || e;\n```\n\n`a`부터 `c`까지 falsy value 이므로 평가를 진행하다 `d`에서 truthy를 반환하므로 평가를 멈추됩니다. 따라서 변수 `f` 에 저장되는 값은 변수 `d`의 값인 4가 됩니다.\n\n---\n\n#### Reference\n- [logical operators - 모던 JavaScript 튜토리얼](https://ko.javascript.info/logical-operators)\n- [JavaScript: What is short-circuit evaluation?](https://codeburst.io/javascript-what-is-short-circuit-evaluation-ff22b2f5608c)\n"
  },
  {
    "path": "Javascript/렉시컬_속이기(eval).md",
    "content": "# 렉시컬 속이기 - eval()\n\n주변에서 eval은 사용하면 안된다고들 말한다. 왜 그런지 깊숙하게 알아보았다.\n\n자바스크립트에는 렉시컬 스코프라는 개념이 있다. 이를 알기 위해선 scope에 대한 정의가 필요하다.\n\n## 스코프와 렉시컬 스코프란\n\n**스코프**란 자바스크립트 엔진이 Identifier(확인자, 구별자)로 현재 스코프 혹은 그 상위의 스코프 내에서 변수를 찾아내는(LHS, RHS) 규칙을 얘기한다. LHS와 RHS는 추후 설명하겠다.\n\n쉽게말해 자바스크립트 엔진이 변수를 찾는 규칙이다. 지식을 늘려보자.\n\n**렉시컬 스코프**를 이해하려면 자바스크립트의 컴파일에 대해 조금 알아야 한다.\n\n_기본적으로 자바스크립트는 컴파일 언어다._ 이에 대해서도 다음에 한번 더 다루겠다.\n컴파일에는 크게 세가지 단계가 존재한다.\n\n1. 토크나이징/렉싱 - 코드를 잘게 나누어 토큰으로 만든다.\n2. 파싱 - 나눈 토큰을 의미있게 AST(Abstract Syntax Tree)라는 트리로 만든다.\n3. 코드생성 - AST를 기계어로 만든다.\n\n렉시컬 스코프란 저 1단계에서 발생하는 즉, 렉싱 과정에서 정의되는 스코프를 말한다. 무슨소리냐면 프로그래머가 변수와 스코프 블록을 어떻게 구성하는냐에 따라, 컴파일의 렉싱 타임에서 정의되는 스코프의 방식을 렉시컬 스코프라고 한다.\n\n## 렉시컬 속이기\n\n어려운 얘기였지만 쉽게 말하면 프로그래머가 코드를 어떻게 작성하는지에 따라 엔진이 판단하고 스코프를 만드는게 렉시컬 스코프다. 즉 컴파일 과정에서 발생한다. 그런데 이를 런타임 과정에서 수정하게 되면 렉시컬을 속일 수 있다.\n\n방법은 크게 두가지다. Eval과 With가 있다.\n\nWith의 경우 최근 거의 사용하지 않는다. 다만 Eval 은 옛날 코드에서 종종 발견된다.\n구글링을 하다보면 Eval을 사용하지 말아라! 라는 말을 종종 보게 된다. 단순히 Eval을 사용하지 말자가 아니라 왜 사용하면 안되는지에 대해서 알아보자.\n\n### Eval\n\n---\n\n`eval()` 함수는 받아들인 파라미터를 마치 코드처럼 실행하는 함수다. 직접 코드를 보자.\n\n```js\nfunction foo(str, a) {\n  eval(str);\n  console.log(a, b);\n}\n\nvar b = 2;\nfoo('var b = 3;', 1); // 출력되는 a와 b는 각각 1, 3\n```\n\n여기서 `var b = 3;`은 마치 원래 있던 코드처럼 실행되고 이 코드가 새로운 변수 b를 선언하고 초기화하며 이미 존재하는 foo()의 렉시컬 스코프를 수정하게 된다. 즉 foo()안에 변수 b를 만들어 바깥 스코프의 변수 b를 가리게 된다. 이를 Shadowing 이라고 한다.\n\n렉시컬 스코프의 기본 정의는 프로그래머가 코딩을 할 때 정한 스코프이며 이는 **컴파일** 과정에서 만들어진다.\neval()과 같은 함수는 이미 정의된 스코프를 **런타임** 시 수정할 수 있게 된다. 즉 정의를 흔드는 행위다.\n\n이와 비슷한 효과를 내는 함수로는 `setTimeout(), setInterval()`과 같은 함수들이 있다. 또한 `new Function()`도 비슷한 방식으로 동적으로 렉시컬 스코프를 변경한다. 개념은 조금씩 다르지만 근본적으로 이 함수들의 공통점은 렉시컬 스코프를 변경할 수 있다는 점이다.\n\n## 결론\n\n흔히들 주변에서 `eval()`을 사용하면 안된다고들 알려준다. 뭐 성능이 안좋다라는 이야기들을 들을 수 있다. 근데 프로그래머라면 항상 의심해봐야 한다. 진짜 안좋을까?\n\n장점도 물론 있다. 코딩의 유연성? 같은 요소들 말이다.\n\n그렇지만 단점이 너무 치명적이다. 자바스크립트는 다시 말하지만 컴파일 언어다. 이 컴파일 언어는 컴파일 단계에서 최적화 작업을 진행한다. 예를들어 렉시컬 스코프를 만들어 Identifier를 미리 확인하여 추후 Identifier 검색을 빠르게 만든다.\n\n그런데 eval()과 같이 이 렉시컬 스코프를 뒤흔들 수 있는 함수를 사용한다고 하자. 그러면 이미 확인했던 Identifier의 위치가 달라질 수 있다. 즉 기존에 진행했던 최적화작업이 확실하지 않을 수 있게 된다는 점이다. 불확실한 작업을 할 수는 없다. 즉 하나마나한 최적화 작업이 되어 버린다.\n\n즉 엔진이 프로그래머가 작성한 코드를 바탕으로 렉시컬 스코프를 만든다. 이를통해 최적화 작업을 수행한다. 그런데 `eval()`을 사용하게 되면 이 렉시컬 스코프를 수정할 수 있게된다. 이러한 가정 때문에 최적화 작업은 무효화 된다. 따라서 `eval()`과 같은 함수는 사용하지 않는것이 적절하다.\n"
  },
  {
    "path": "Javascript/배열 내장함수.md",
    "content": "# 배열 내장함수\n\n자바스크립트의 배열에서는 기본적으로 많은 종류의 내장 함수를 제공하고 있고 이를 이용하면 보다 간단한 코드로 다양한 기능을 구현할 수 있다.\n\n<br/>\n\n## forEach, map, filter\n\n`forEach`와 `map`, `filter`함수는 기본적으로 배열을 반복하는데 초점을 둘 필요가 있다.  \n\n### forEach\n\n`forEach`는 배열을 반복하여 기존 값을 가져오는데 주로 쓰인다.\n\n```js\nconst arr = [1, 2, 3, 4, 5];\n\narr.forEach(item => {\n  console.log(item); //1 2 3 4 5\n});\n```\n\n### map\n\n`map`과 `forEach`의 차이는 배열을 반복하면서 각각의 원소에 대하여 특정 로직을 수행한 뒤, 새로운 배열을 반환하고 싶을 때 주로 사용한다.\n\n```js\nconst arr = [1, 2, 3, 4, 5];\n\nconst newArr = arr.map(item => {\n  return item * 2;\n});\n\nconsole.log(arr); //[1, 2, 3, 4, 5]\nconsole.log(newArr); //[2, 4, 6, 8, 10]\n```\n\n위에서 볼 수 있듯이 `map`을 통해 반환한 배열은 깊은 복사를 사용하기 때문에 기존 배열을 영향을 주지 않고 새로운 배열을 반환한다.\n\n### filter\n\n`filter`함수의 기능은 이름 그대로 배열을 반복하며 각각의 원소들 중 특정 조건에 해당하는 원소들만 뽑아내어 새로운 배열을 반환한다.\n`filter`또한 `map`과 마찬가지로 기존 배열에 영향을 주지 않는다.\n\n```js\nconst arr = [1, 2, 3, 4, 5];\n\nconst newArr = arr.filter(item => {\n  return item >= 3;\n})\n\nconsole.log(arr); //[1, 2, 3, 4, 5]\nconsole.log(newArr); //[3, 4, 5]\n```\n\n<br/>\n\n## indexOf, findIndex, find\n\n### indexOf\n\n`indexOf`함수는 배열에서 찾고자 하는 원소가 있다면 그 원소의 `index`값을 반환한다.\n\n```js\nconst arr = ['a', 'b', 'c', 'd'];\n\nconsole.log(arr.indexOf('c')); //2\n```\n\n### findIndex\n\n`findIndex`함수도 `indexOf`함수와 마찬가지로 찾고자 하는 원소의 `index`값을 반환한다. 하지만 원소가 객체로 되어있거나 배열로 되어있을 때 `indexOf`함수로는 `index`값을 찾을 수 없다. 반면, `findIndex` 함수는 조건 처리를 통하여 `index`값을 찾을 수 있다.\n\n```js\nconst arr = [\n  {\n    id: 1,\n    name: 'BKJang',\n    age: 27,\n  },\n  {\n    id: 2,\n    name: 'JHKim',\n    age: 25,\n  }\n]\n\nconsole.log(arr.findIndex(item => item.id === 2)); //1\n```\n\n### find\n\n`find`함수는 `findIndex`함수와 사용법은 동일하지만 반환하는 값이 `index`값이 아닌 찾아낸 값 자체를 반환한다.\n\n```js\nconst arr = [\n  {\n    id: 1,\n    name: 'BKJang',\n    age: 27,\n  },\n  {\n    id: 2,\n    name: 'JHKim',\n    age: 25,\n  }\n]\n\nconsole.log(arr.find(item => item.id === 2)); \n// {id: 2, name: \"JHKim\", age: 25}\n```\n\n<br/>\n\n## splice, slice \n\n`splice`와 `slice`함수는 배열에서 특정 원소들을 제거할 때 사용하는 함수다.\n\n### splice\n\n`splice`함수의 첫번째 파라미터는 **지우기 시작할 원소의 `index`**, 두번째 파라미터는 **지울 원소의 갯수**를 넘긴다.\n\n```js\nconst arr = ['a', 'b', 'c', 'd', 'e'];\n\nconst arr2 = arr.splice(2, 3);\n\nconsole.log(arr); //[\"a\", \"b\"]\nconsole.log(arr2); //[\"c\", \"d\", \"e\"]\n```\n\n### slice\n\n`slice`함수와 `splice`함수의 가장 큰 차이점은 `slice`함수는 기존 배열에 영향을 주지 않고 새로운 배열을 반환한다는 것이다.<br/>\n또 다른 차이점은 `slice`함수는 두번째 파라미터로 보낸 원소의 `index`값 전까지 원소를 제거한다.\n\n```js\nconst arr = ['a', 'b', 'c', 'd', 'e'];\n\nconst arr2 = arr.slice(1, 3);\n\nconsole.log(arr); //[\"a\", \"b\", \"c\", \"d\", \"e\"]\nconsole.log(arr2); //[\"b\", \"c\"]\n```\n\n<br/>\n\n## shift, unshift, push, pop\n\n`shift`, `unshift`, `push`, `pop` 함수는 기존 배열에 앞, 뒤로 새로운 원소를 추가하거나 기존 배열의 원소를 하나씩 제거하는 함수다.<br/>\n이 함수들은 모두 기존 배열에 영향을 미치는 함수들이다. 보통 `Queue`나 `Stack`을 구현할 때 많이 사용하는 함수들이다.\n\n### shift\n\n`shift`함수는 기존 배열의 원소를 앞에서부터 하나씩 제거한다.\n\n```js\nconst arr = [1, 2, 3, 4, 5];\n\narr.shift();\nconsole.log(arr); //[2, 3, 4, 5]\n\narr.shift();\nconsole.log(arr); //[3, 4, 5]\n```\n\n### unshift\n\n`unshift`함수는 기존 배열에 새로운 원소를 앞에 추가한다.\n\n```js\nconst arr = [1, 2, 3, 4, 5];\n\narr.unshift(0);\nconsole.log(arr); //[0, 1, 2, 3, 4, 5]\n\narr.unshift(-1);\nconsole.log(arr); //[-1, 0, 1, 2, 3, 4, 5]\n```\n\n### push\n\n`push`함수는 기존 배열에 새로운 원소를 뒤에 추가한다.\n\n```js\nconst arr = [1, 2, 3, 4, 5];\n\narr.push(6);\nconsole.log(arr); //[1, 2, 3, 4, 5, 6]\n\narr.push(7);\nconsole.log(arr); //[1, 2, 3, 4, 5, 6, 7]\n```\n\n### pop\n\n`pop`함수는 기존 배열의 원소를 뒤에서부터 하나씩 제거한다.\n\n```js\nconst arr = [1, 2, 3, 4, 5];\n\narr.pop();\nconsole.log(arr); //[1, 2, 3, 4]\n\narr.pop();\nconsole.log(arr); //[1, 2, 3]\n```\n\n<br/>\n\n## concat, join\n\n### concat\n\n`concat`은 여러 개의 배열을 하나로 합쳐주는 함수다. 기존 배열들에는 영향을 끼치지 않고 새로운 배열을 반환한다. `ES6`에서는 `concat`대신 `Spread Operator`를 많이 사용한다.\n\n```js\n//concat\nconst arr1 = ['a', 'b'];\nconst arr2 = ['c', 'd', 'e'];\n\nconst newArr = arr1.concat(arr2);\n\nconsole.log(arr1); //[\"a\", \"b\"]\nconsole.log(arr2); //[\"c\", \"d\", \"e\"]\nconsole.log(newArr); //[\"a\", \"b\", \"c\", \"d\", \"e\"]\n```\n\n```js\n//ES6 Spread Operator\nconst arr1 = ['a', 'b'];\nconst arr2 = ['c', 'd', 'e'];\n\nconst newArr = [...arr1, ...arr2];\n\nconsole.log(arr1); //[\"a\", \"b\"]\nconsole.log(arr2); //[\"c\", \"d\", \"e\"]\nconsole.log(newArr); //[\"a\", \"b\", \"c\", \"d\", \"e\"]\n```\n\n### join\n\n`join`함수는 배열의 원소들을 합쳐 문자열 형태로 반환한다.\n\n```js\nconst arr = ['a', 'b', 'c', 'd', 'e'];\n\nconsole.log(arr.join(', ')); //a, b, c, d, e\nconsole.log(arr.join('')); //abcde\n```\n\n<br/>\n\n## every, some\n\n`every`와 `some`함수는 배열을 반복을 돌리면서 원소들이 특정 조건에 대하여 통과하는지 여부에 대해 검사한다.\n\n### every\n\n`every`함수는 특정 조건에 대하여 배열의 모든 원소가 통과해야만 `true`를 반환하며 빈 배열에 대해서는 무조건 `true`를 반환한다.\n\n```js\nconst arr = [1, 2, 3, 4, 5];\n\nconst result1 = arr.every(item => item <= 5);\nconst result2 = arr.every(item => item < 3);\n\nconsole.log(result1, result2); //true false\n```\n\n### some\n\n`some`함수는 특정 조건에 대하여 배열의 어떤 한 요소라도 통과하면 `true`를 반환하며 빈 배열에 대해서는 무조건 `false`를 반환한다.\n\n```js\nconst arr = [1, 2, 3, 4, 5];\n\nconst result1 = arr.some(item => item <= 5);\nconst result2 = arr.some(item => item < 3);\n\nconsole.log(result1, result2); //true true\n```\n\n<br/>\n\n## sort\n\n`sort`함수는 정렬 기능을 제공하는 함수다. 실제로 `Grid`의 정렬 기능을 구현할 때 많이 사용된다.\n\n```js\nconst fruit = ['orange', 'apple', 'banana'];\n\nfruit.sort();\nconsole.log(fruit); //[\"apple\", \"banana\", \"orange\"]\n```\n\n```js\nconst imD = [\n    { name : \"BKJang\", age : 27},\n    { name : \"JHKim\", age : 25},\n    { name : \"SHJo\", age : 28},\n    { name : \"DHJung\", age : 29},\n    { name : \"JSKang\", age : 23}\n]\n\n/* 이름순 */\nimD.sort((a, b) => { // 오름차순\n    return a.name < b.name ? -1 : a.name > b.name ? 1 : 0;\n});\n/**\n0: {name: \"BKJang\", age: 27}\n1: {name: \"DHJung\", age: 29}\n2: {name: \"JHKim\", age: 25}\n3: {name: \"JSKang\", age: 23}\n4: {name: \"SHJo\", age: 28}\n*/\n\nimD.sort((a, b) => { // 내림차순\n    return a.name > b.name ? -1 : a.name < b.name ? 1 : 0;\n});\n/**\n0: {name: \"SHJo\", age: 28}\n1: {name: \"JSKang\", age: 23}\n2: {name: \"JHKim\", age: 25}\n3: {name: \"DHJung\", age: 29}\n4: {name: \"BKJang\", age: 27}\n*/\n\n/* 나이순 */\nconst sortingField = 'age';\n\nimD.sort((a, b) => { // 오름차순\n    return a[sortingField] - b[sortingField];\n});\n/**\n0: {name: \"JSKang\", age: 23}\n1: {name: \"JHKim\", age: 25}\n2: {name: \"BKJang\", age: 27}\n3: {name: \"SHJo\", age: 28}\n4: {name: \"DHJung\", age: 29} \n*/\n\nimD.sort((a, b) => { // 내림차순\n    return b[sortingField] - a[sortingField];\n});\n/**\n0: {name: \"DHJung\", age: 29}\n1: {name: \"SHJo\", age: 28}\n2: {name: \"BKJang\", age: 27}\n3: {name: \"JHKim\", age: 25}\n4: {name: \"JSKang\", age: 23} \n*/\n```\n\n<br/>\n\n## reduce\n\n`reduce`함수는 누적 값과 현재 값을 이용하여 여러 가지 기능을 구현할 수 있는 매우 유용한 함수다. 사실, `reduce`만 잘 사용할 줄 알아도 `filter`함수의 기능까지도 구현할 수 있다.\n\n`reduce`에 대해서는 간단히 설명하는 것 보다는 상세히 설명된 글로 대체한다.\n\n- [Im-D/Dev-Docs - Reduce](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/Reduce.md)\n\n<br/>\n\n---\n\n#### Reference\n\n- [MDN Docs - Array.some()](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/some)\n- [MDN Docs - Array.every()](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/every)\n- [DUDMY HOME - 자바스크립트 정렬 함수, sort()](http://dudmy.net/javascript/2015/11/16/javascript-sort/)\n- [비비로그 - 자바스크립트의 유용한 배열 메소드 사용하기... map(), filter(), find(), reduce()](https://bblog.tistory.com/300)\n"
  },
  {
    "path": "Javascript/상태관리 라이브러리.md",
    "content": "# 상태관리 라이브러리\n\n<br/>\n\n## 상태관리 라이브러리의 필요성\n\n**'상태관리 라이브러리는 왜 필요할까?'** 라는 것에 초점을 두어야 한다.\n\n**규모가 작은 프로젝트**라면 굳이 상태관리 라이브러리를 사용할 필요는 없다.\n\nReact를 예로 들면, 16.3 버전에서부터 **Context API** 가 더욱 좋아지면서 글로벌 상태 관리 또한 별도의 라이브러리 없이 할 수 있게 되었다.\n\n하지만, **프로젝트의 규모가 커지면서**  `setState`로 상태를 구성하고, 이를 `props`로 넘겨주는 등의 일이 점점 복잡해진다.<br/> 뿐만 아니라 **상태 업데이트 로직이 컴포넌트 별로 존재**하면서 유지보수가 어려워질 수 있다.\n\n사실, 상태관리 라이브러리를 사용하는 이유를 말하자면 간단하다.\n\n> 애플리케이션의 상태를 **단일 스토어**에서 관리하고 상태의 흐름을 **단방향**으로 통일하기 위해서이다.\n\nReact에서 주로 사용되는 상태관리 라이브러리에는 **Redux**와 **Mobx**가 있다.\n\n<br/>\n\n## Flux Architecture\n\nFlux 구조는 MVC 구조의 Model, View, Controller의 역할 배분의 구조가 아닌 **이벤트와 데이터의 흐름에 집중**한다.\n\nFacebook을 예로 들면, 타임라인만 봐도 수많은 사람들이 매번 글을 올리고 그 글에 몇천, 몇만명의 사람들이 댓글을 쓰고 좋아요를 누른다.\n\n이런 복잡한 **데이터 흐름을 단방향으로 통일**시킴으로써 문제를 해결한 것이 Flux 구조다.\n\n![flux_architecture](/assets/images/flux_architecture.png)\n\n- **Action** : 앱에서 발생한 **이벤트(조작), 데이터의 변화**에 대한 정보를 담고 있다. Action이 만들어지는 것만으로는 앱에 변화를 주진 않는다.\n\n- **Dispatcher** : Action을 **순서대로** Store로 전달하는 역할을 한다.\n\n- **Store, View** : Dispatcher로 받은 Action을 기반으로 Store 내의 상태를 변경하고 이를 View에 반영하여 화면에 그린다.\n\nFlux 구조를 사용한 대표적인 라이브러리가 **Redux**와 **Mobx**다.\n\n<br/>\n\n## Redux vs Mobx\n\n### Redux\n\n---\n\n- **단 하나의 스토어**를 애플리케이션의 모든 상태를 관리한다. 이는 애플리케이션의 상태를 예측가능하기 쉽게 한다.\n\n- **함수형 프로그래밍 패러다임**을 기본적으로 따른다. 익숙하지 않은 개발자들에게는 낯설 수 있다.\n\n- **불변성**을 필수적으로 지켜줘야한다.\n\n- 하나의 스토어로 관리하기 때문에 애플리케이션 전체의 흐름을 잘 통제하는 만큼 수많은 Dispatcher가 발생했을 때 병목현상이 발생할 수 있다.(이를 막기 위해 `Redux-thunk`나 `Redux-saga`와 같은 **미들웨어를 사용**한다.)\n\n### Mobx\n\n---\n\n- **다수의 스토어**를 가질 수 있고 **기본적으로 Observable을 사용**한다. 이는 Redux보다 데이터 흐름을 쉽게 관리할 수 있게 한다.\n\n- Redux에서 중요하게 신경썼던 **불변성을 신경쓰지 않아도 된다.**\n\n- 새롭게 알아야하는 개념(Reducer, Immutable, connect, Action, Dispatcher, 미들웨어)이 많은 Redux에 비해 **Running-Curve가 적다고 한다.**\n\n<br/>\n\n---\n\n#### Reference\n\n- [Mungue Lee님의 Medium](https://medium.com/@RianCommunity/%EB%A6%AC%EC%95%88-%EA%B0%9C%EB%B0%9C-%EC%9D%BC%EA%B8%B0-2-front-end-%EA%B0%9C%EB%B0%9C-react-9f6ccb5b016d)\n- [상태 관리 라이브러리의 미학: Redux 또는 MobX 를 통한 상태 관리](https://velog.io/@velopert/redux-or-mobx)\n- [Immutable.js 혹은 Immer.js 를 사용한 더 쉬운 불변성 관리](https://velog.io/@velopert/20180908-1909-%EC%9E%91%EC%84%B1%EB%90%A8-etjltaigd1)\n"
  },
  {
    "path": "Javascript/이벤트 루프(Event Loop).md",
    "content": "\n# 이벤트 루프(Event Loop)\n\n<br/>\n\n## 자바스크립트는 싱글쓰레드 기반이다.\n\n자바스크립트를 공부해본 개발자라면 한 번쯤은 `자바스크립트는 싱글 쓰레드 기반의 언어다.`라는 말을 들어봤을 것이다. 하지만 우리는 실제 웹 애플리케이션에서 여러 개의 작업이 동시에 처리되는 것처럼(비동기적) 느끼는 일이 더 많다. 싱글 쓰레드 기반의 언어에서 즉, 한 번에 하나의 작업만 처리가능한 환경에서 어떻게 많은 작업이 동시에 처리되는 것처럼 느낄 수 있을까? 그 답은 **이벤트 루프**에 있다.\n\n브라우저 환경을 간단히 표현하면 다음 이미지와 같다.\n\n![eventLoop](/assets/images/event_loop.jpeg)\n\n우선, 위의 그림에서 보여지는 각각에 대해서 살펴본 후, 전체적으로 이벤트 루프가 동작하는 방식을 살펴보도록 하자.\n\n<br/>\n\n## 자바스크립트 엔진\n\n### Heap\n\n동적으로 생성된 객체 인스턴스는 Heap에 할당이 된다. Heap은 메모리에서 대부분 구조화되지 않은 영역을 나타낸다.\n\n### Call Stack(호출 스택)\n\n호출 스택은 이름 그대로 `Stack`이며 LIFO(Last-In-First-Out)구조를 갖는다. 함수를 호출하면(작업을 요청하면) 작업은 순차적으로 호출 스택에 쌓이고 실행된다. 자바스크립트 엔진은 하나의 스택만 가지고 있기 때문에 하나의 작업이 끝나기 전까지 다른 작업을 수행할 수 없다.\n\n## Web APIs\n\n흔히 WebAPI라 불리는 API들은 실행환경에 내장되어 있다.\n\n이것은 자바스크립트에 포함되는 것이 아니다. 즉, 우리는 Web API의 내부는 조작할 수 없으며 호출만 가능하다. 또한 자바스크립트 언어를 사용하는데 있어 강력한 성능을 제공한다. \n\nWeb API의 종류는 [다음](https://developer.mozilla.org/en-US/docs/Web/API)을 참조하면 알 수 있다.\n\n### 콜백함수\n\n자바스크립트의 싱글 쓰레드 구조에서 비동기성의 이벤트 기반 실행(대표적으로 `setTimeout`)이나 `ajax`요청이 필요하다면, 콜백 함수를 큐로 보내고 큐에서는 호출 스택으로 보내 해결하게 된다.\n\n자바스크립트에서는 쓰레드를 통해 병렬처리가 안되기 때문에 콜백 함수의 사용은 필수불가결하게 되는 것이다.\n\n<br/>\n\n## Event Queue(이벤트 큐)\n\n이벤트 큐는 말 그대로 콜백 함수들이 대기하는 `Queue`이며 `FIFO(First-In-First-Out)`의 구조를 갖는다. 이벤트 루프는 호출 스택이 비워질 때마다 큐에서 콜백 함수를 호출 스택에 넣어주는 역할을 해준다.\n\n<br/>\n\n## 이벤트 루프를 통한 비동기적 처리\n\n이벤트 루프의 역할은 생각보다 단순한다. 호출 스택에 실행 중인 작업이 있는지, 이벤트 큐에 대기 중인 작업이 있는지 반복해서 확인한다. 만약 호출 스택이 비어있다면 이벤트 큐에 있는 작업을 호출 스택으로 옮긴다. 그리고 이 작업을 수행하는 것은 결국 호출 스택이다.\n\n```js\nfunction func1() {\n  console.log('func1');\n  func2();\n}\n\nfunction func2() {\n  setTimeout(function () {\n    console.log('func2');\n  }, 0);\n\n  func3();\n}\n\nfunction func3() {\n  console.log('func3');\n}\n\nfunc1();\n```\n\n위 예제는 이벤트 루프를 설명할 때 가장 많이 사용되는 예제다. 만약, 이벤트 루프가 수행하는 과정이 없고 순차적으로 호출 스택에만 쌓이게 된다면 `func1`, `func2`, `func3`의 순서로 출력될 것이다. 하지만 실제로 위 코드를 실행해보면 `func1`, `func3`, `func2`의 순서로 출력되는 것을 볼 수 있을 것이다. 이런 결과가 나오는 이유는 위에서 설명한 것 처럼 이벤트 큐와 이벤트 루프를 통해 비동기 처리를 수행하는 `setTimeout`함수가 다른 함수들과 다르게 동작하기 때문이다.\n\n아래 이미지는 위 코드가 실행되는 과정을 보여준다.\n\n<br/>\n\n![event_loop_gif](/assets/images/event_loop_gif.gif)\n\n> 이미지 출처: https://poiemaweb.com/js-event\n\n<br/>\n\n위 과정을 순차적으로 정리하면 다음과 같다.\n\n> 1. `func1`함수가 호출되고 이는 호출 스택에 올라가고 `console.log('func1')`이 실행된다.\n> 2. `func2`함수가 호출 스택에 올라가고 `setTimout`함수를 호출한다.\n> 3. 호출된 `setTimeout`함수의 수행은 비동기적 처리를 수행하는 Web API에 넘어간다.\n> 4. `func3`함수가 호출 스택에 올라가고 `console.log('func3')`이 실행된다.\n> 5. Web API에서 `setTimout`함수에서 지정한 시간이 지나면 `callback`함수를 이벤트 큐로 넘긴다.\n> 6. 작업이 끝난 `func3`, `func2`, `func1`은 순차적으로 호출 스택에서 제거된다.\n> 7. 이벤트 루프는 호출 스택에 작업 중인 태스크가 없는 것을 확인하고 이벤트 큐에 있는 `callback`함수를 호출 스택으로 올린다.\n> 8. 호출 스택에 올라간 `callback`함수가 실행되면서 `console.log('func3')`가 실행된다.\n\n위 설명에서 주의 깊게 볼 것은 비동기 함수인 `setTimeout`함수에 세팅된 시간이 3초라면 `3초 후에 콜백 함수를 실행시켜라`가 아닌 `3초 후에 콜백 함수를 이벤트 큐에 넣어라`가 된다는 것이다. \n\n즉, `setTimeout` 함수는 n초 뒤에 콜백을 단순히 큐에 집어넣는게 끝이다. 코드를 간단히 보자면 아래와 같다.\n\n```js\nvar eventLoop = [];\nvar event;\n\nwhile (true) {\n  // 틱!\n  if (eventLoop.length > 0) {\n    event = eventLoop.shift();\n  }\n\n  try {\n    event(); // 호출스택으로 밀어넣는다\n  } catch (err) {\n    //...\n  }\n}\n```\n\n이 큐에 이미 대기번호가 100개가 있다면 `func3`는 101번째 대기표를 받게 될 것이다. 따라서 `setTimeout`은 지정한 시간동안은 실행되지 않는 것은 보장할 수 있지만 지정한 시간에 실행되는것은 보장할 수 없다.\n\n```js\nwhile (await messageQueue.nextMessage()) {\n  let message = messageQueue.shift();\n  message.run();\n}\n```\n\n결론적으로, 이벤트 루프는 메시지 큐에 메시지가 더 있는지 확인하는 루프이다.\n\n메시지 큐에 메시지가 있으면 메시지 큐에서 다음 메시지를 제거하고 그 메시지와 연관된 기능을 호출 스택으로 보낸다. 그렇지 않으면 새 메시지가 메시지 대기열에 추가될 때까지 대기를 한다. 이벤트 루프가 자바스크립트에게 비동기를 허용하는 기본 모델이다.\n\n<br/>\n\n## ES6이후의 변화된 비동기 처리와 이벤트 루프\n\n기본적으로 이벤트 루프는 위에서 설명한 내용이 큰 틀이다. 큐와 스택을 감시하며 스택의 작업이 없으면 큐의 작업을 스택에 올린다. 다만, `ES6`이후에는 몇 가지 비동기적 작업을 수행하는 API들이 추가되었고 이에 따라 약간의 추가된 내용이 있다. 하지만, 전체적인 실행 방식은 동일하며 각각의 비동기 처리에 수행 순서에 초점을 두고 살펴보자.\n\n기존에 살펴보았던 이벤트 큐(Event Queue)를 좀 더 자세히 나눠보면 다음과 같다.\n\n1. `Task Queue` : 가장 사람들이 잘 알고 있는 비동기 작업인 `setTimeout`이 들어가는 큐\n2. `Micro Task Queue` : ES6에서 추가된 `Promise`와 ES8의 `Async Await`(Async Await도 결국 Promise)\n3. `AnimationFrame`: `requestAnimationFrame(rAF)`의 콜백 함수가 들어간다.\n\n```js\nconsole.log(\"script start\");\n\nsetTimeout(function() {\n  console.log(\"setTimeout\");\n}, 0);\n\nPromise.resolve().then(function() {\n  console.log(\"promise1\");\n}).then(function() {\n  console.log(\"promise2\");\n});\n\nrequestAnimationFrame(function {\n    console.log(\"requestAnimationFrame\");\n})\nconsole.log(\"script end\");\n```\n\n위의 코드를 실행하면 다음과 같은 결과가 출력된다.\n\n```js\nscript start\nscript end\npromise1\npromise2\nrequestAnimationFrame\nsetTimeout\n```\n\n즉, 이벤트 큐에서 나눠지는 3가지 영역의 우선 순위는 다음과 같다.\n\n> Micro Task Queue => AnimationFrame => Task Queue\n\n기존에 이벤트 루프에 대해서 이해가 된 상태라면 이 내용은 크게 어렵지 않다. 쉽게 보면 비동기 작업을 처리하는 방법이 추가되었고 이에 따라 이벤트 큐에서 내부적으로 처리하는 로직에 약간의 변화가 생겼을 뿐이다. 결국, 정리하면 다음과 같다.\n\n1. 비동기 작업으로 등록되는 작업은 `Task`와 `Micro Task`, 그리고 `AnimationFrame`으로 구분된다.\n2. `Micro Task`는 `Task`보다 먼저 처리된다.\n3. `Micro Task`가 처리된 이후 `requestAnimationFrame`이 호출되고 이후 브라우저 랜더링이 발생한다.\n\n- [Task Queue와 Micro Task Queue의 처리 과정](https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/)\n\n<br/>\n\n---\n\n#### Reference\n\n- [JavaScript Event Loop Explained](https://medium.com/front-end-weekly/javascript-event-loop-explained-4cd26af121d4)\n- [What is the Event Loop in Javascript](https://www.wptutor.io/web/js/javascript-event-loop)\n- [Understanding JS: The Event Loop](https://hackernoon.com/understanding-js-the-event-loop-959beae3ac40)\n- [Event loop in javascript](https://code.likeagirl.io/what-the-heck-is-event-loop-1e414fccef49)\n- [The JavaScript Event Loop](https://flaviocopes.com/javascript-event-loop/)\n- [Tasks, microtasks, queues and schedules](https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/)\n- [Poiemaweb - 자바스크립트/이벤트](https://poiemaweb.com/js-event)\n"
  },
  {
    "path": "Javascript/클래스(class).md",
    "content": "# 클래스(class)\n\n기본적으로 자바스크립트는 프로토타입 기반의 객체지향언어다. `ES6`부터 추가된 `class`문법은 기존의 `ES5`까지 사용하던 객체지향 설계 방식의 **Syntatic Sugar**다.\n\n<br/>\n\n## ES5 vs ES6\n\n```javascript\n//ES5\nvar Book = (function() {\n    var name = '';\n    var category = '';\n\n    //생성자 함수\n    function Book(arg1, arg2) {\n        name = arg1;\n        category = arg2;\n    }\n\n    Book.prototype.getInfo = function() {\n        console.log('Name : ' + name + ', Category : ' + category);\n    }\n\n    return Book;\n}());\n\nvar dom = new Book('DOM을 깨우치다', 'Web');\n\ndom.getInfo();\n```\n\n```javascript\n//ES6\nclass Book {\n    constructor(arg1, arg2) {\n        this.name = arg1;\n        this.category = arg2;\n    }\n\n    getInfo() {\n        console.log(`Name : ${this.name}, Category : ${this.category}`);\n    }\n}\n\nvar dom = new Book('DOM을 꺠우치다', 'Web');\n\ndom.getInfo();\n```\n\n<br/>\n\n## class는 window에 할당되지 않으며 생성자를 반환한다. 생성자는 생략할 수 있다.\n\n```javascript\nclass Developer {\n\n}\n\nconsole.log(window.Developer); //undefined\nconsole.log(Developer === Developer.prototype.constructor); //true\n```\n\n생성자를 생략하면 빈 객체를 생성하고 `property`를 동적으로 생성할 수 있다.\n\n```javascript\nclass Developer {\n\n}\n\nconst jang = new Developer();\n\nconsole.log(jang); //Developer {}\n\njang.nation = 'Korea';\n\nconsole.log(jang); //Developer {nation: \"Korea\"}\n```\n\n<br/>\n\n## class내부의 몸체에는 메서드만 선언 가능하며 property의 선언과 초기화는 생성자에서 이뤄진다.\n\n```javascript\nclass Foo {\n    const name = ''; //Uncaught SyntaxError: Unexpected identifier\n}\n```\n\n```javascript\nclass Bar {\n    constructor(name = '') {\n        this.name = name;\n    }\n}\n\nconst bar = new Bar('BKJang');\nconsole.log(bar); //Bar {name: \"BKJang\"}\n```\n\n## class에서는 getter와 setter를 구현할 수 있다.\n\n```javascript\nclass Person {\n    constructor(name) {\n        this.name = name;\n    }\n\n    //getter\n    get personName() {\n        return this.name ? this.name : null;\n    }\n\n    //setter\n    set personName(name) {\n        this.name = `Developer ${name}`;\n    }\n}\n\nconst person = new Person('BKJang');\n\nconsole.log(person.personName); //BKJang\nperson.personName = 'BKJang';\nconsole.log(person.personName); //Developer BKJang\n```\n\n- 프로퍼티에 접근하면 `getter`가 호출된다.\n- 프로퍼티에 값을 할당하면 `setter`가 호출된다.\n\n<br/>\n\n## Static 메서드를 정의할 수 있다.\n\n- `class`의 **Static 메서드**는 인스턴스로는 접근할 수 없고, 클래스 명으로 접근한다.\n\n```javascript\nclass Foo {\n    constructor(name) {\n        this.name = name;\n    }\n\n    static staticMethod() {\n        console.log(this);\n    }\n}\n\nconst bkjang = new Foo('BKJang');\n\nFoo.staticMethod(); //class Foo { ... }\nbkjang.staticMethod(); //bkjang.staticMethod is not a function\n```\n\n- `class`의 **Static 메서드**내부에서는 `this`를 통해 property에 접근할 수 없다.\n\n```javascript\nclass Bar {\n    constructor(name) {\n        this.name = name;\n    }\n    \n    returnThis() {\n        console.log(`returnThis : ${this}`);\n    }\n\n    static staticMethod() {\n        console.log(`staticMethod : ${this}`);\n        console.log(this.name);\n    }\n}\n\nconst bkjang = new Bar('BKJang');\n\nbkjang.returnThis(); //returnThis : [object Object]\nBar.staticMethod();\n```\n\n- `class`의 **Static 메서드**는 `prototype`에 추가되지 않는다.\n\n```javascript\nclass Bar {\n    constructor(name) {\n        this.name = name;\n    }\n    \n    returnThis() {\n        console.log(`returnThis : ${this}`); \n    }\n\n    static staticMethod() {\n        console.log(`staticMethod : ${this}`);\n        console.log(this.name);\n    }\n}\n\nconst bkjang = new Bar('BKJang');\n\nconsole.log(bkjang.returnThis === Bar.prototype.returnThis); //true\nconsole.log(Bar.staticMethod === Bar.prototype.staticMehtod); //false\n```\n\n<br/>\n\n## class는 상속을 구현할 수 있다.(`extends`, `super`)\n\n```javascript\nclass Person {\n    constructor(name, sex) {\n        this.name = name;\n        this.sex = sex;\n    }\n\n    getInfo() {\n        return `Name : ${this.name}, Sex : ${this.sex}`;\n    }\n\n    getName() {\n        return `Name : ${this.name}`;\n    }\n\n    getSex() {\n        return `Sex : ${this.sex}`;\n    }\n}\n\nclass Developer extends Person { //extends를 사용하여 Person 클래스 상속\n    constructor(name, sex, job) {\n        //super메서드를 사용하여 부모 클래스의 인스턴스를 생성\n        super(name, sex);\n        this.job = job;\n    }\n\n    //오버라이딩\n    getInfo() {\n        //super 키워드를 사용하여 부모 클래스에 대한 참조\n        return `${super.getInfo()} , Job: ${this.job}`;\n    }\n\n    getJob() {\n        return `Job : ${this.job}`;\n    }\n}\n\nconst person = new Person('SHJo', 'Male'); \nconst developer = new Developer('BKJang', 'Male', 'Developer');\n\nconsole.log(person); //Person {name: \"SHJo\", sex: \"Male\"}\nconsole.log(developer); //Developer {name: \"BKJang\", sex: \"Male\", job: \"Developer\"}\n\nconsole.log(person.getInfo()); //Name : SHJo, Sex : Male\n\nconsole.log(developer.getName()); //Name : BKJang\nconsole.log(developer.getSex()); //Sex : Male\nconsole.log(developer.getJob()); //Job : Developer\nconsole.log(developer.getInfo()); //Name : BKJang, Sex : Male , Job: Developer\n\nconsole.log(developer instanceof Developer); //true\nconsole.log(developer instanceof Person); //true\n```\n<br/>\n\n---\n\n#### Reference\n\n- [[ES6] 6. 클래스(Class)](https://bkdevlog.netlify.com/posts/class)\n- [MDN Web Docs - Classes](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Classes)\n"
  },
  {
    "path": "Javascript/클로저.md",
    "content": "# 클로저\n\n<br/> \n\n## 렉시컬 스코프란\n\n\n```js\nfunction outerFunc() {\n    var x = 10;\n    var innerFunc = function() {console.log(x);};\n    innerFunc();\n}\n\nouterFunc(); // 10\n```\n\n```js\nvar x = 1;\n\nfunction outerFunc(){\n    var x = 10;\n    innerFunc();\n}\n\nfunction innerFunc() {\n    console.log(x);\n}\n\nouterFunc(); // 1\n```\n\n함수의 상위 스코프는 **함수가 어디서 호출되었는지** 또는 **함수를 어디서 선언하였는지**에 따라 결정된다. 첫번째 방식을 **동적 스코프(Dynamic scope)**, 두번째 방식을 **렉시컬 스코프(lexical scope)** 또는 정적 스코프(static scope)라고 한다. 자바스크립트를 포함한 대부분의 언어가 렉시컬 스코프를 따른다.  \n\n따라서 첫번째 예제에서 `innerFunc()`의 상위 스코프는 `outerFunc()`와 `전역 스코프`가 되고, 두번째 예제에서 `innerFunc()`의 상위 스코프는 `전역 스코프`가 된다. \n\n<br/>\n\n## 스코프 체인  \n\n스코프 체인은 **하위 함수가 참조하는 상위 함수의 변수 또는 함수의 메모리를 참조하는 것**을 말한다. 스코프 체인에는 렉시컬 스코프의 레퍼런스가 차례대로 저장되어 있고, 이 순서를 따라 자바스크립트 엔진이 검색을 한다.   \n\n첫번째 예제의 스코프 체인을 나타내면 다음과 같다.  \n\n![scopechain](/assets/images/ScopeChain.png)  \n\n자바스크립트 엔진은 `innerFunc()` 스코프 내에서 변수 `x`를 검색한다. `x`가 없기 때문에 다음 리스트인 `outerFunc()`의 스코프 내에서 `x`를 검색한다. 그리고 `outerFunc()`에서 찾은 `x`를 참조해 결과를 반환한다. \n\n<br/>\n\n## 클로저란\n\n이번에는 `outerFunc()`이 내부함수를 반환하고 소멸하도록 바꿔보자.\n\n```js\nfunction outerFunc() {\n    var x = 10;\n    return {\n        innerFunc1 : function(){ console.log(x+1)}\n        , innerFunc2 : function(){ console.log(x+2)}\n    }\n}\n\nvar inner = outerFunc();\ninner.innerFunc1();\ninner.innerFunc2();\n```\n`outerFunc()`이 소멸되고 `inner()`에는 `innerFunc1()`과 `innerFunc2()`가 담겨있다.  \n`innerFunc1()`과 `innerFunc2()`는 `outerFunc()`의 `x` 변수를 참조했었는데, `outerFunc()`가 소멸되었으므로 `x`를 참조하지 못할 것 같지만, 각각의 결과로 11, 12가 정상 출력된다.   \n이처럼 **생명주기가 끝난 외부함수의 변수를 참조하는 방법을 클로저**라고 한다. 클로저는 **자신이 선언되었을 때의 환경(lexical Environment), 즉 스코프**를 기억해, 선언된 환경 밖에서 호출되어도 해당 환경에 접근할 수 있는 함수이다.  \n\n클로저가 가능한 이유는 `outerFunc()`의 실행컨텍스트는 소멸되지만 `활성화 객체(AO)`는 **소멸되지 않기 때문**이다. 때문에 `innerFunc1()`과 `innerFunc2()`의 ScopeChain은 유지되어 자바스크립트는 `x`변수를 `outerFunc()`에서 검색할 수 있다. 즉, 클로저는 실제 변수의 복사본이 아닌 그 변수를 직접 참조한다. \n\n<br/>\n\n#### Reference\n* [클로저](https://poiemaweb.com/js-closure)\n* [JavaScript : Scope 이해](http://www.nextree.co.kr/p7363/)\n* [실행 컨텍스트와 자바스크립트의 동작 원리](https://poiemaweb.com/js-execution-context)\n\n"
  },
  {
    "path": "Javascript/함수 선언.md",
    "content": "# 함수 선언식 / 함수 표현식\n연산자 `function`을 이용해 함수를 정의하는 방법에는 함수 선언식과 함수 표현식이 있다.  \n\n## 함수 선언식\n```javascript       \nfunction fnc() {    \n    /*실행코드*/\n}\n```  \n함수 선언식으로 정의된 함수는 자바스크립트가 로딩되는 시점에 인터프리터가 초기화하고 VO에 저장된다. 따라서 함수 선언 위치와 상관없이 소스 내 어느 곳에서든지 호출이 가능하다.   \n<br/>  \n \n## 함수 표현식\n```javascript\n//변수에 할당\nvar fnc = function fnc() {\n    /*실행코드*/\n};\n\nvar fnc = function() {\n    /*실행코드*/\n}\n\n//즉시실행함수\n(function fnc(){\n\n}());\n\n(function(){\n\n}());\n```\n함수표현식은 자바스크립트 로딩시점에 VO에 함수를 저장되지 않고, runtime시에 해석된다. \n<br/>  \n따라서 함수 선언식으로 함수를 정의하면 사용하기 쉽지만, 너무 많은 코드가 VO에 저장되어 애플리케이션의 응답속도가 느려질 수 있다는 것을 주의해야한다. \n<br/>  \n하지만, 스크립트 파일을 모듈화하고 비동기 방식으로 로딩할 경우 응답속도를 향상시킬 수 있다.  \n\n<br/>     \n\n\n# 익명함수 / 기명함수\n\n```javascript\nfunction add(x, y){\n    return x+y;\n}\n```\n위와 같이 정의된 함수는 자바스크립트 엔진에 의해 다음과 같이 바뀐다. \n\n```javascript\nvar add = function add(x,y) {\n    return x+y;\n};\n```\n즉, 기명함수와 같은 이름에 함수가 변수로 선언된다. (함수변수)  따라서 `add(3, 5)`와 같은 명령을 내리면 이는 함수변수의 내부 함수에 접근한 것이 아니라 함수변수에 접근한 것이다. 다음은 함수변수와 내부함수의 이름이 다른 경우이다. \n\n```javascript\nvar add = function sum(x, y){\n    return x + y;\n};\n```\n`sum(3, 5)`를 명령한 경우 sum함수가 정의되지 않았다는 에러가 뜬다. 함수변수의 내부함수에 직접 접근할 수 없기 때문이다. 따라서 `add(3, 5)`와 같이 함수변수를 통해 명령을 내려줘야 한다.   \n\n<br/>  \n\n함수변수의 내부변수는 함수변수 내부에서 디버깅이나 재귀호출에 쓰인다. 다음은 재귀호출의 예이다.\n```javascript\nvar factorialFn = function factorial(x){\n    if(x <= 1){\n        return 1;\n    }\n    return factorial(x-1) * x \n};\n```  \n\n<br/>  \n \n\n\n# arguments\narguments 객체는 함수를 호출할 때 암묵적으로 내부에 전달되는 **유사객체**이다. (유사객체는 배열이 아니지만 length 속성을 가진 객체를 말한다. 단, 배열처럼 index로 접근하지 못한다.) arguments 객체는 다음과 같은 4가지 property를 가진다. \n1. 함수를 호출할 때 전달된 인자 (배열형태)\n2. length : 인자의 개수\n3. callee : 호출된 함수\n4. `__proto__`  \n\n위의 property 중 `callee`를 이용하면 addEventListener에서 넘겨준 익명함수를 removeEventListener에서 삭제할 수 있다. \n\n## removeEventListener_익명함수\n먼저, 기명함수로 addEventListener와 removeEventListener를 사용하면 다음과 같다. \n\n```javascript\n//addEventListener\ndocument.querySelector(\"#addEvent\").addEventListener(\"click\", fnc);\n\n//removeEventListener\ndocument.querySelector(\"#addEvent\").removeEventListener(\"click\", fnc);\n```\n이 경우 넘겨준 함수가 이름을 가지고 있기 때문에, removeEventListener도 잘 적용된다. 하지만 다음과 같이 익명함수를 전달해주면 removeEventListener가 적용되지 않는다.\n\n```javascript\n//addEventListener\ndocument.querySelector(\"#addEvent\").addEventListener(\"click\", function(e){\n    var targetId = e.target.id;\n    fnc(target);\n});\n\n//removeEventListener\ndocument.querySelector(\"#addEvent\").removeEventListener(\"click\", function(e){\n    var targetId = e.target.id;\n    fnc(target);\n});\n```\n이 때 arguments의 callee를 이용하면 익명함수로 전달된 함수도 remove해줄 수 있다. \n```javascript\n//removeEventListener\ndocument.querySelector(\"#addEvent\").removeEventListener(\"click\", arguments.callee);\n```  \n\n<br/>  \n\n---\n\n#### Reference\n- [Javascript:함수(function)다시보기] www.nextree.co.kr/p4150\n- 인사이드 자바스크립트 송형주, 고현준\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2018-2020 Im-D\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "Language/Currying.md",
    "content": "# Currying\n\nCurrying은 여러 개의 인자를 가진 함수를 호출할 경우, 파라미터의 수보다 적은 수의 파라미터를 인자로 받으면 누락된 파라미터를 인자로 받는 기법을 말한다.\n부분적으로 인자가 적용된 함수를 체인으로 연결하여 값을 처리하는 것이 본질이다.\n\n<br/>\n\n## 함수의 인자를 분리해서 받는다.\n\n```js\nfunction add(x){\n    return function(y){\n        return x + y\n    };\n};\n\n// arrow function으로 한다면 이런 형태일 것이다.\nvar add = x => y => x + y;\nvar firstAdd = add(10);\n\nadd(10); //y => x + y\nadd(10)(5); //15\nfirstAdd(5); //15\n```\n\n위 코드를 보면 `add(10)`의 결과가 함수를 반환하는 것을 볼 수 있다. 즉, `add`함수의 인자가 2개라고 했을 때 2개의 인자를 모두 받지 않으면 함수는 실행되지 않는다.\n\n위 처럼 함수의 인자를 분리해서 받으면 어떤 이점이 있을까?\n\n- 함수의 실행을 늦출 수 있다.(부분적으로 파라미터를 받게 되면, 모든 파라미터를 받기 전까지 함수는 실행되지 않는다)\n- firstAdd 함수처럼 고정적인 부분은 별도로 정의함으로써 재사용이 가능하다.\n\n위의 코드에서는 함수의 인자 개수가 2개로 정해져 있다. 하지만, 함수의 인자가 동적이거나 훨씬 많다면 모든 경우를 생각하여 모든 함수를 각각 만들어줄 수는 없을 것이다. 이때 curry 함수를 구현하여 함수의 인자를 동적으로 받을 수 있다.\n\n```js\nFunction.prototype.curry = function(one) {\n  var origFunc = this;\n  var target = origFunc.length;\n  var args = [];\n  function next(nextOne) {\n    args = [...args, nextOne];\n    if (args.length === target) {\n      return origFunc.apply(null, args);\n    } else {\n      return nextOne => { return next(nextOne) };\n    }\n  }\n  return next(one);\n}\n\nconst add = (a, b, c, d) => {\n  return a + b + c + d;\n}\n\nadd.curry(1)(2)(3)(4); //10\n```\n\n<br/>\n\n## 합성함수에서의 Currying\n\n[합성함수](https://github.com/Im-D/Dev-Docs/blob/master/Language/%ED%95%A8%EC%88%98%ED%98%95%20%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D.md#%ED%95%A9%EC%84%B1%ED%95%A8%EC%88%98Function-Composition)는 함수형 프로그래밍에서 사용되는 프로그래밍 기법 중 하나로 말그대로 두 가지 이상의 함수가 합성되었음을 뜻한다. 즉, 각각의 역할을 수행하는 함수를 필요에 따라 합성하여 원하는 결과 값을 만들어낸다. 그러려면 합성하는 역할을 하는 함수를 만들어야 하는데 이때 Currying을 사용하여 함수를 구현할 수 있다.\n\n\n```js\nconst compose = (...fns) => x => fns.reduceRight((v, f) => f(v), x);\n\nconst square = num => num * num;\nconst addTen = num => num + 10;\nconst minusTen = num => num - 10;\n\nconst squareAfterAddTen = compose(square, addTen);\nconst squareAfterMinusTen = compose(square, minusTen);\n\nconsole.log(squareAfterAddTen(10)); //400\nconsole.log(squareAfterMinusTen(30)); //400\n```\n\n위의 `compose`함수가 2개 이상의 함수를 합성하는 역할을 해주는 함수다. 코드를 보면 합성할 함수들를 받은 다음 뒤에서 부터 순서대로 실행시키고 그 결과 값을 다음 함수의 인자로 전달하고 있다.\n\n합성 함수의 핵심은 여러 함수를 원하는 경우에 따라 합성하여 사용하고 내부적으로 각각의 함수들이 어떤 로직을 수행하는지에는 관심이 없다는 것이다. 즉, 각각의 함수의 역할만 알고 있으면 이를 상황에 따라 합성하여 사용할 수 있기 때문에 재사용성을 높일 수 있다. 그리고 이러한 장점을 가진 합성 함수를 사용하는데 있어 Currying은 필수적으로 알고 있어야할 개념 중 하나기 때문에 알아둘 필요가 있다.\n\nCurrying이 함수형 프로그래밍을 위해서 있는 것이 아니며 최근 함수형 프로그래밍에 대한 관심이 높아지면서 Currying의 개념이 다시 한 번 나타나게 된걸로 생각하면 좋을 것 같다.\n\n<br/>\n\n---\n\n#### Reference\n\n- [Zero Cho Blog - Currying(커링) vs Partial application](https://www.zerocho.com/category/JavaScript/post/579236d08241b6f43951af18)\n- [JavaScript에서 커링 currying 함수 작성하기](https://edykim.com/ko/post/writing-a-curling-currying-function-in-javascript/)\n- [Lazysoul Medium - Currying(커링)](https://medium.com/@lazysoul/currying-%EC%BB%A4%EB%A7%81-b7af0b2aaef1)\n"
  },
  {
    "path": "Language/Lamda.md",
    "content": "# 람다\n\n## 람다 대수(Lambda calculus)\n\n람다의 근간은 수학에서, 그리고 초기 튜링기계에 사용되었던 *람다 대수 or 람다 계산 (Lambda Calculus)*다. 람다 대수는 수학에서의 함수를 단순하게 표현하는 방법이다. 예를들어 f( g(f(x) g(x))) 이런 수학 기호가 람다 대수다.\n\n람다 대수는 다음과 같은 특징이 있다.\n\n1. 람다 대수는 이름을 가질 필요가 없다. (익명 함수)\n2. 두 개 이상의 입력이 있는 함수는 최종적으로 1개의 입력만 받는 람다 대수로 단순화 될 수 있다. (커링)\n\n즉 익명함수이면서 커링이 가능하다.\n\n## 익명함수\n\n람다 대수의 영향을 받아 만들어진 함수다. 이름이 없는 함수를 의미한다.\n\n변수 V1이 있는 람다식을 `λV1. V1 x V1`라고 할 때 이를 프로그래밍에서 표현하는 방법은 `x => x * x`다. 이래서 람다 대수의 영향을 받았다고 한다.\n\n```js\nvar foo = x => x * x;\n```\n\n이렇게 쓰던 화살표 함수가 바로 람다대수의 영향을 받은 익명함수다. 다만 자바스크립트에서는 이렇게 사용하지만 언어별로 지원하는 방법이 조금 다르다. 람다 표현식(expression)만 지원하는 경우와 같은 것이 있다. 그러나 공통점은 모두 일급 객체라는 점이다.\n\n## 일급 객체(first class citizen)\n\n일급객체는 쉽게 설명해서 생성, 대입, 연산, 인자 또는 반환값으로서의 전달 등 기본 연산이 가능한 대상을 말한다.\n\n더 쉽게 설명하자면 변수와 같은 것이다.\n\n```js\nvar x; // 생성\nx = 1; // 대입\nvar y = 2;\nx + y; // 연산\nfoo(x); // 인자\nreturn x; // 반환값\n```\n\n변수는 생성, 대입, 연산, 인자 또는 반환값으로서의 전달이 모두 가능하다.\n\nJS에서는 함수도 마찬가지로 모두 가능하다.\n\n즉 함수가 일급 객체를 지원하면 커링이 가능하며, 거기에 익명함수까지 지원한다면 람다 함수라 할 수 있다.\n\n## 함수형 프로그래밍, HOF(고차함수), 일급객체, 람다\n\n이게 사실 다 연관되는 내용이다.\n\n- 일급객체 ⇒ 기본연산이 가능\n- 람다 ⇒ 익명 + 커링\n- HOF ⇒ 함수를 인수로 취하거나 결과로 반환\n- 함수형 프로그래밍 ⇒ 순수함수 + immutable\n\n이렇게 간단하게나마 정리할 수 있다. 4가지의 연결고리는 아래와 같다.\n\n함수가 일급 객체이며, 람다(익명 + 커링) 함수다. 그렇다면 고차함수가 될 수 있다. 고차함수가 되게 함수를 만들고 사용한다면 함수형 프로그래밍에 가까워진다.\n\n## 람다의 특징\n\n코드가 간결해진다. 람다는 불필요한 루프문에 대한 정의를 삭제한다.\n\niteration 방식과 다르다. 0부터 9까지 1씩 증가하면서 실행해라고 명령하는 것이 아니라 그냥 여기 있는거 다 해라고 설명하는 방식이다.\n\n그래서 함수형 프로그래밍과 HOF와 철학이 비슷한것이다.\n\n```js\nfor (var i = 0; i < 10; i++) {\n  console.log(i);\n}\n\n[0, 1, 2, 3, 4, 5, 6, 7, 8, 9].forEach(console.log);\n```\n\n아래의 방식이 바로 람다 방식이다.\n\n---\n\n### 참고자료\n\n- [람다, 익명 함수, 클로저 블로그 글](<[https://hyunseob.github.io/2016/09/17/lambda-anonymous-function-closure/](https://hyunseob.github.io/2016/09/17/lambda-anonymous-function-closure/)>)\n- [람다식 나무위키](<[https://namu.wiki/w/람다식](https://namu.wiki/w/%EB%9E%8C%EB%8B%A4%EC%8B%9D)>)\n- [람다대수 위키](<[https://ko.wikipedia.org/wiki/람다_대수](https://ko.wikipedia.org/wiki/%EB%9E%8C%EB%8B%A4_%EB%8C%80%EC%88%98)>)\n- [Functinonal Programming](https://github.com/Im-D/Dev-Docs/blob/master/Language/Funtional.md)\n- [Higher Order Functions](https://github.com/Im-D/Dev-Docs/blob/master/Language/Higher_Order_Functions.md)\n"
  },
  {
    "path": "Language/Reactive.md",
    "content": "# Reactive\n\nReactive Programming의 3가지\n\n- Reactive Programming\n- Functional Reactive Programming\n- Reactive Extensions(Rx-\\*)\n\n## Reactive Programming\n\n> Reactive Programming is programming with asynchronous data streams. You can listen to that stream and react accordingly.\n\nReactive Programming은 비동기 데이터 스트림을 이용한 프로그래밍이다.\n\n이게 무슨 소리인지 직관적으로 이해가 가진 않는다.\n\n그런데 우리가 가장 많이 사용하고 있는 RP의 개념 중 하나가 button click이다.\n\n![RP-button](https://user-images.githubusercontent.com/24724691/64065845-d8998a80-cc4d-11e9-9620-1d662eed78c5.png)\n\nevent는 stream으로 취급하고 이를 클릭하는 처리는 모두 비동기로 진행된다. 바로 감은 오지 않을 것이다. 조금 더 돌아가 보자.\n\n### 역사\n\n반응형(Reactive) 기술의 아이디어는 1980년대에 논문(\"On the Development of Reactive System\") 에서 나왔고, 1990년대, 2000년대 초반에 이미 저수준은 제공되고 있었다.\n그것들을 토대로 자연스러운 데이터 흐름을 다루는 벽돌이 쌓아 올려져 Node.js, Play(Akka Streaming), Microsoft Reactive Extensions 등이 생겨났으며 RxJava, RxJs, RxSwift 등의 Rx 시리즈가 등장했다.\n\n### RP 특징\n\n#### Stream\n\nReactive Programing은 기본적으로 모든 것을 스트림으로 본다. 이벤트, ajax call, 변수, 데이터 등 모든 데이터의 흐름을 시간순에 의해 전달되는 스트림으로 처리한다.\n**스트림이란 쉽게 말하자면 시간에 흐름에 의해서 전달된 값들이다.**\n\n다음의 그림처럼 event이외에 다른 점들도 stream이 될 수 있다.\n\n![RP](https://user-images.githubusercontent.com/24724691/64065933-14811f80-cc4f-11e9-9483-a3f6eb4ffdf9.png)\n\n이렇게 모든 것을 데이터의 흐름으로 보고 어떠한 변화를 전파하는 것에 중점을 둔 프로그래밍 패러다임이다.\n\n### Async\n\nAsync를 처리하기 위해 RP에서는 Observer Pattern을 채택한다.\n\n비동기를 해결하기 위한 방식으로 callback과 어느 정도 비슷하다.\ncallback은 특정 행위가 일어나면 callback을 실행한다. observer pattern은 구독이다. 특정 행위가 일어나면 구독자들에게 알린다.\n\n예를 들어 카톡이 왔다고 하자. 카톡을 확인하려고 대화창을 클릭하면 동시에 여러 일이 벌어져야 한다고 하자.\n\n1. 화면에 실제 카톡 내용이 보인다.\n2. 알림을 알려주는 badge의 아이콘이 사라진다.\n3. 좌측 화면의 카톡 알림이 사라진다.\n\n이걸 옵저버 패턴에서 처리하려면 의사코드는 다음과 같다.\n\n```js\nchatView.subscribe(chatViewList, show);\nbadgeAlram.subscribe(chatViewList, deleteBadge);\nalram.subscribe(chatViewList, deleteAlram);\n\nclass chatViewList extends Observable\nchatViewList.click();\n\n// ...\nthis.observers = [];\nclick() {\n    observers.map(observer => observer());\n    // ...\n}\n```\n\n카톡내용, 뱃지, 알람 세 뷰는 모두 `chatViewList`를 구독한다. 클릭이 발생하면 구독자들에게 상태가 변경됨을 공지하고 다른 행동을 각자 발생시킨다.\n\n이렇게 프로그램을 비동기 + 스트림으로 처리하는 방식이 RP다. 아직도 이해가 잘 안 되겠지만 마지막에 코드를 보면 조금 더 이해가 잘 될 것이다.\n\n## Functional Reactive Programming\n\n> Functional Reactive Programming is a programming paradigm for reactive programming using the building blocks of functional programming\n\nRP를 FP를 이용하여 만든 것이다.\n\n[함수형 프로그래밍](https://github.com/Im-D/Dev-Docs/blob/master/Language/함수형%20프로그래밍.md) 을 참고하면 함수형의 기본적인 철학은 선언형 프로그래밍이다. 이 점이 RP와 매우 잘 맞는다.\n\n예를 들면 SNS에서 좋아요를 누르면 특정 로직을 거친 후 숫자가 1 올라가고 하트의 색이 변한다. 이를 하나의 스트림과 비동기로 취급하면 RP고 벌써 이야기했듯 선언적으로 처리하면 FP다.\n\n`like().filter(somthing).addNumber(1).changeColor('red');` 처럼 코드를 짠다면 선언적으로 매우 알아보기 쉽게 만들 수 있을 것이다.\n\n둘의 궁합이 굉장히 좋기 때문에 FRP에 대해 많이 이야기한다.\n\n## Rx-\\*\n\n> Reactive Extensions are an API for asynchronous programming with observable streams\n\n옵저버 스트림을 이용한 비동기 프로그래밍을 위한 API다. RP에 대한 특징이 들어가있는 API라고 생각하면 된다.\nRP가 대두되면서 RxJava, RxPY, RxSwift, RxJs등등 RP를 쉽게 구현하기 위한 API들이 시리즈로 줄줄이 등장했다.\n\nRP나 FRP는 프로그래밍 기법 혹은 패러다임이다. 문제를 해결하기 위해 프로그램을 설계하는 방법이다. Rx는 이 RP를 쉽게 구현하기 위한 도구다.\n\n```js\nconst button = document.querySelector(\".button\");\nconst clickStream = Rx.Observable.fromEvent(button, \"click\");\nconst throttle = 250;\n\nconst singleClickStream = clickStream\n  .buffer(() => clickStream.throttle(throttle))\n  .map(list => list.length)\n  .filter(x => x === 1);\n```\n\n250ms 이내에 발생한 클릭 이벤트를 리스트에 누적시키는 로직이다.\n2번째 줄에서 Rx의 Observable을 사용하였으며 5번째 줄에서는 함수형 프로그래밍을 이용하여 선언적으로 구현했다.\n\nRx 라이브러리처럼 RP를 구현하기 쉽게 제공하는 API를 Rx-\\*로 부른다.\n\n---\n\n### Reference\n\n- [Getting Started with Functional Reactive Programming Using RxJS](https://blog.hax0r.info/2018-05-10/getting-started-with-functional-reactive-programming-using-rxjs/)\n- [찰스의 안드로이드](https://www.charlezz.com/?p=189)\n- [한빛미디어](http://www.hanbit.co.kr/media/channel/view.html?cms_code=CMS6076376207)\n- [HAMA Blog](http://hamait.tistory.com/761)\n- [Reactive Programming](https://brunch.co.kr/@oemilk/79)\n- [ㅇㅁReactive Programming](http://blog.weirdx.io/post/56004)\n- [[번역] 반응형 프로그래밍과 RxJS 이해하기](https://hyunseob.github.io/2016/10/09/understanding-reactive-programming-and-rxjs/)\n"
  },
  {
    "path": "Language/XML_JSON.md",
    "content": "# JSON과 XML\n저번 시간에 [soap api](https://github.com/im-d-team/Dev-Docs/blob/master/Network/SOAP%20API.md)를 정리하면서 데이터 형식에는 `JSON 형식`과 `XML 형식`이 있다고 들었다. \n\n둘의 차이와 파싱하는 법을 정리를 해보았다.\n\n## XML이란?\nXML은 EXtensible Markup Language의 약자로, HTML과 매우 비슷한 문자 기반의 마크업 언어이다.\nXML 태그는 HTML 태그처럼 미리 정의되어 있지 않고, 사용자가 직접 정의할 수 있다.\n\n### XML 문법\n![xml문법](https://user-images.githubusercontent.com/43868540/86515903-730ebf80-be57-11ea-83fd-85a2c1afb8aa.PNG)\n\n[출처 myeonguni.tistory](https://myeonguni.tistory.com/1087)\n- xml 선언부가 있으며 인코딩 방식과 버전을 기입한다.\n- `element`는 시작과 종료 태그로 한 쌍이 되어야 한다.\n- 요소의 시작 태그와 끝 태그 사이에 들어있는 텍스트는 `element content`라고 부르고 그냥 데이터이다.\n- xml에는 `속성(attribute)`이라고 하는 부가적인 정보를 작성하여 넣을 수 있다. \n> <food id=\"001\" 저장위치=\"작은 냉장고\">처럼 food 태그에 id와 저장위치 같은 부가적인 정보를 지정할 수 있다.\n- XML 태그는 대소문자 구분이 있다. \n\n### XML 장점\n- 작성하기가 **간편**하다.(tag구조)\n- 사람이 읽기가 쉽다. 즉, 정보들이 의미하는 바를 한눈에 보기 좋다.\n\n### XML 단점\n- tag 때문에 실 데이터에 비해 문서의 양이 필요 이상으로 많아진다.\n- 배열 형식이나 반복 구조의 경우 불필요한 데이터가 계속해서 나타난다. 결국 파싱이 힘들어지고 속도는 느려진다.\n\n## JSON\nJSON은 JavaScript Object Notation의 약자로, 데이터를 저장하거나 전송할 때 많이 사용되는 데이터 교환 형식이다. 최근에는 JSON이 용량이 더 작아서 XML을 대체에서 데이터 전송 등에 많이 사용한다. \n\n### JSON 문법\n![JSON 문법](https://user-images.githubusercontent.com/43868540/86515808-a9980a80-be56-11ea-9269-a15c597bda1f.PNG)\n\n[출처 surim014.log](https://velog.io/@surim014/JSON%EC%9D%B4%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80)\n- json 형식은 자바스크립트 객체와 마찬가지로 `key/value`가 존재할 수 있으며 key 값이나 문자열은 항상 쌍따옴표를 이용하여 표기해야 한다. \n- 일반 자바스크립트의 객체처럼 원하는 만큼 중첩시켜서 사용할 수도 있다.\n- json 형식에서는 null, number, string, array, object, boolean을 사용할 수 있다.\n\n### JSON 장점\n- 내용이 **함축적**으로 최소한의 정보만을 가지고 있다.\n- **최소한의 정보**만 가지고 있기 때문에 속도는 그만큼 빨라진다.\n- 파싱이 매우 **간편**하고 사용하기 쉽다.\n\n### JSON 단점\n- 내용이 함축적이다 보니 내용의 의미를 파악하기 힘들다.\n- **적은 규격의 데이터 전송**에 적합한 방식이기 때문에 XML보다는 빠르지만 대용량급 데이터 송수신엔 부적합하다.\n\n## XML parse\nXML 파싱하는 방법에는 DOM, SAX, PULL 이렇게 총 3가지가 있는데 그중 pull 파싱을 사용하였다.\n\n`XmlPullParser`가 안드로이드에서 XML을 파싱하는 효율적이고 유지관리가 쉬운 방법이라 알려져 있어 사용하였다.\n\n각 파싱에 대한 간단한 설명은 [이곳](http://sunphiz.me/wp/archives/298)을 참고하길 바란다.\n\n**test2.xml**\n``` xml\n<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<CONTACT>\n    <NO>1</NO>\n    <NAME>제갈은</NAME>\n    <PHONE>010-2614-6938</PHONE>\n    <OVER20>true</OVER20>\n</CONTACT>\n```\n마찬가지로 assets 폴더 안에 `test2.xml` 파일을 생성해준다.\n\n**activity_main.xml**\n``` xml\n<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\"\n    android:padding=\"16dp\"\n    tools:context=\".MainActivity\">\n\n    <TableLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:stretchColumns=\"1\">\n\n        <TableRow\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\">\n\n            <TextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:gravity=\"center\"\n                android:textSize=\"24sp\"\n                android:text=\"No\" />\n\n            <EditText\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginLeft=\"20dp\"\n                android:textSize=\"24sp\"\n                android:id=\"@+id/editTextNo\"/>\n        </TableRow>\n\n        <TableRow\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\">\n\n            <TextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:gravity=\"center\"\n                android:textSize=\"24sp\"\n                android:text=\"Name\" />\n\n            <EditText\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginLeft=\"20dp\"\n                android:textSize=\"24sp\"\n                android:id=\"@+id/editTextName\"/>\n        </TableRow>\n\n        <TableRow\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\">\n\n            <TextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:gravity=\"center\"\n                android:textSize=\"24sp\"\n                android:text=\"Phone\" />\n\n            <EditText\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginLeft=\"20dp\"\n                android:textSize=\"24sp\"\n                android:id=\"@+id/editTextPhone\"/>\n        </TableRow>\n\n        <TableRow\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\">\n\n            <TextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:gravity=\"center\"\n                android:textSize=\"24sp\"\n                android:text=\"Over20\" />\n\n            <CheckBox\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginLeft=\"20dp\"\n                android:textSize=\"24sp\"\n                android:id=\"@+id/checkBoxOver20\"\n                android:text=\"Over 20 years?\"/>\n        </TableRow>\n\n    </TableLayout>\n\n</LinearLayout>\n```\n화면을 구성해 줄 TextView와 CheckBox, EditText 등을 생성한다. \n\n**MainActivity.java**\n``` java\npackage com.example.myapplication;\n\nimport androidx.appcompat.app.AppCompatActivity;\n\nimport android.content.res.AssetManager;\nimport android.os.Bundle;\nimport android.view.View;\nimport android.widget.CheckBox;\nimport android.widget.EditText;\nimport android.widget.TextView;\n\nimport org.xmlpull.v1.XmlPullParser;\nimport org.xmlpull.v1.XmlPullParserFactory;\n\nimport java.io.IOException;\n\npublic class MainActivity extends AppCompatActivity {\n\n    final int STEP_NONE = 0 ;\n    final int STEP_NO = 1 ;\n    final int STEP_NAME = 2 ;\n    final int STEP_PHONE = 3 ;\n    final int STEP_OVER20 = 4 ;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_main);\n\n        AssetManager am = getResources().getAssets();\n        InputStream is = null;\n\n        try {\n            int no = -1;\n            String name = null;\n            String phone = null;\n            boolean isOver20 = false;\n\n            // XML 파일 스트림 열기\n            is = am.open(\"test2.xml\");\n\n            // XML 파서 초기화\n            XmlPullParserFactory parserFactory = XmlPullParserFactory.newInstance();\n            XmlPullParser parser = parserFactory.newPullParser();\n\n            // XML 파서에 파일 스트림 지정.\n            // XML 파서에는 openFile()과 같은, 직접적으로 XML 파일을 여는 함수가 존재하지 않는다. 대신 파서가 처리할 입력 스트림을 지정하는 setInput() 함수가 존재한다.\n            parser.setInput(is, \"UTF-8\");\n            \n            int eventType = parser.getEventType();     \n            int step = STEP_NONE ;\n            while (eventType != XmlPullParser.END_DOCUMENT) {                   // XML파일의 끝에 도달할 때까지\n                if (eventType == XmlPullParser.START_DOCUMENT) {                // XML파일의 처음 시작했을 때 \n                    // XML 데이터 시작\n                } else if (eventType == XmlPullParser.START_TAG) {              // element의 시작태그를 만났을 때\n                    String startTag = parser.getName();\n                    if (startTag.equals(\"NO\")) {\n                        step = STEP_NO;\n                    } else if (startTag.equals(\"NAME\")) {\n                        step = STEP_NAME;\n                    } else if (startTag.equals(\"PHONE\")) {\n                        step = STEP_PHONE;\n                    } else if (startTag.equals(\"OVER20\")) {\n                        step = STEP_OVER20;\n                    } else {\n                        step = STEP_NONE;\n                    }\n                } else if (eventType == XmlPullParser.END_TAG) {                // element의 종료태그를 만났을 때 \n                    String endTag = parser.getName();                           // 태그를 파싱\n                    if ((endTag.equals(\"NO\") && step != STEP_NO) ||\n                            (endTag.equals(\"NAME\") && step != STEP_NAME) ||\n                            (endTag.equals(\"PHONE\") && step != STEP_PHONE) ||\n                            (endTag.equals(\"OVER20\") && step != STEP_OVER20)) {\n                        // TODO : error\n                    }\n                    step = STEP_NONE;\n                } else if (eventType == XmlPullParser.TEXT) {\n                    String text = parser.getText();                             //태그 안에 데이터 값 얻기\n                    if (step == STEP_NO) {\n                        try {\n                            no = Integer.parseInt(text);\n                        } catch (Exception e) {\n                            no = 0;\n                        }\n                    } else if (step == STEP_NAME) {\n                        name = text;\n                    } else if (step == STEP_PHONE) {\n                        phone = text;\n                    } else if (step == STEP_OVER20) {\n                        isOver20 = Boolean.parseBoolean(text);\n                    }\n                }\n\n                eventType = parser.next();                                       //다음 element로..\n            }\n\n            if (no == -1 || name == null || phone == null) {\n                // ERROR : XML is invalid.\n            } else {\n\n                EditText editTextNo = (EditText) findViewById(R.id.editTextNo);\n                editTextNo.setText(Integer.toString(no));\n\n                EditText editTextName = (EditText) findViewById(R.id.editTextName);\n                editTextName.setText(name);\n\n                EditText editTextPhone = (EditText) findViewById(R.id.editTextPhone);\n                editTextPhone.setText(phone);\n\n                CheckBox checkBoxOver20 = (CheckBox) findViewById(R.id.checkBoxOver20);\n                checkBoxOver20.setChecked(isOver20);\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n}\n```\nxml 데이터를 파싱할 때는 루프를 돌면서 XML 요소(element)를 파싱하는 방법을 사용한다. \n\n위에 코드에서 볼 수 있듯이 while 루프 내에서 `next()` 함수를 호출하면서 element가 무엇인지 판단하고 파싱하는 것이다.\n\n해당 실 데이터(text)가 어떤 태그의 데이터인지 판단하기 위해 `step`이라는 변수를 이용하여 태그를 저장하고 검사하였다. \n\n- 태그를 파싱했을 때 태그의 이름을 가져올 때는 `getName()`을 사용한다.\n- 태그를 파싱했을 때 텍스트의 내용을 가져올 때는 `getText()`를 사용한다.\n\n위에 코드에서 속성에 대한 설명은 아래 사진을 참고하길 바란다.\n\n<img width=\"443\" alt=\"XMLparser속성\" src=\"https://user-images.githubusercontent.com/43868540/86525423-ddf4e080-bec1-11ea-8350-452b48180759.png\">\n<img width=\"313\" alt=\"xmlparse 속성2\" src=\"https://user-images.githubusercontent.com/43868540/86525524-2bbe1880-bec3-11ea-84a9-f6385d7c7044.png\">\n\n[출처 codedragon.tistory](https://codedragon.tistory.com/6755)\n\n### 결과화면\n<img width=\"419\" alt=\"xmlparse\" src=\"https://user-images.githubusercontent.com/43868540/86514641-4efab080-be4e-11ea-9efb-311c2c7ed013.png\">\n\n## JSON parse\n**test.json**\n``` json\n[\n  {\"name\":  \"제갈은\", \"msg\":  \"경기도 안산\", \"birthday\": {\"month\":  3, \"day\":  23}},\n  {\"name\":  \"심세영\",\"msg\":  \"경기도 안양\", \"birthday\": {\"month\": 6,\"day\": 19}}\n]\n```\n위와 마찬가지로 assets 폴더 안에 jsons 폴더를 생성한다. 만든 jsons 폴더 안에 test.json을 생성한다.\n\n**activity_main.xml**\n``` xml\n<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\"\n    android:padding=\"16dp\"\n    tools:context=\".MainActivity\">\n\n    <Button\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"json parse\"\n        android:onClick=\"clickBtn\"/>\n    <TextView\n        android:id=\"@+id/tv\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:padding=\"8dp\"/>\n\n</LinearLayout>\n```\nButton과 TextView를 화면에 추가해주었다. TextView에는 tv라는 id를 부여해주었다.\n\n**MainActivity.java**\n``` java\npackage com.example.myapplication;\n\nimport androidx.appcompat.app.AppCompatActivity;\n\nimport android.content.res.AssetManager;\nimport android.os.Bundle;\nimport android.view.View;\nimport android.widget.TextView;\n\nimport org.json.JSONArray;\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\n\npublic class MainActivity extends AppCompatActivity {\n\n    TextView tv;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_main);\n\n        tv = findViewById(R.id.tv);\n    }\n    public void clickBtn(View view) {\n\n        //json 파일 읽어와서 분석하기\n\n        //assets폴더의 파일을 가져오기 위해\n        //창고관리자(AssetManager) 얻어오기\n        AssetManager assetManager = getAssets();\n\n        //assets/ test.json 파일 읽기 위한 InputStream\n        try {\n            InputStream is = assetManager.open(\"jsons/test.json\");  \n            InputStreamReader isr = new InputStreamReader(is);\n            BufferedReader reader = new BufferedReader(isr);\n\n            StringBuffer buffer = new StringBuffer();\n            String line = reader.readLine();\n            while (line != null) {\n                buffer.append(line + \"\\n\");\n                line = reader.readLine();\n            }\n\n            String jsonData = buffer.toString();\n\n            //json 데이터가 하나의 배열일 때\n            //jsonObject 객체 생성\n//            JSONObject jsonObject= new JSONObject(jsonData);\n//            String name= jsonObject.getString(\"name\");\n//            String msg= jsonObject.getString(\"msg\");\n//\n//            tv.setText(\"이름 : \"+name+\"\\n\"+\"메세지 : \"+msg);\n\n            //json 데이터가 []로 시작하는 여러 배열일때..\n            //JSONArray 객체 생성\n            JSONArray jsonArray = new JSONArray(jsonData);\n\n            String s = \"\";\n\n            for (int i = 0; i < jsonArray.length(); i++) {\n                JSONObject jo = jsonArray.getJSONObject(i);\n\n                String name = jo.getString(\"name\");\n                String msg = jo.getString(\"msg\");\n                JSONObject flag = jo.getJSONObject(\"birthday\");\n                int aa = flag.getInt(\"month\");\n                int bb = flag.getInt(\"day\");\n\n                s += name + \" : \" + msg + \", 생일 :  \" + aa + \"월\" + bb + \"일\\n\";\n            }\n            tv.setText(s);\n\n        } catch (IOException e) {\n            e.printStackTrace();\n        } catch (JSONException e) {\n            e.printStackTrace();\n        }\n\n    }\n}\n```\n\njson 파싱은 기본적으로 `JSONObject`와 `JSONArray`으로 json을 파싱할 수 있다.\n\n데이터가 하나의 배열일 때는 `JSONObject`를 사용하고 여러 배열일 때는 `JsonArray`를 사용한다. \n\n`JSONArray`를 사용할 때는 for문을 사용해 `JSONObject`를 하나씩 생성해 값을 가져온다. \n\n### 결과 화면\n<img width=\"431\" alt=\"jsonparse\" src=\"https://user-images.githubusercontent.com/43868540/86513605-89604f80-be46-11ea-91d9-30d9d99a6acf.png\">\n\n---\n\n#### Reference\n- [JSON과 XML](http://tcpschool.com/json/json_intro_xml)\n- [XML 구조](https://usroom.tistory.com/entry/XML%EC%9D%98-%EB%AC%B8%EB%B2%95)\n- [XML과 JSON의 장단점](https://usbs.tistory.com/entry/XML-JSON-%EA%B0%84%EB%8B%A8%ED%95%9C-%EB%B9%84%EA%B5%90-%EB%B6%84%EC%84%9D)\n- [XML 파싱](https://recipes4dev.tistory.com/137)\n- [JSON 파싱](https://lcw126.tistory.com/101)\n"
  },
  {
    "path": "Language/고차함수(High Order Function).md",
    "content": "# 고차함수(High Order Function)\n\n<br/>\n\n## 코드의 복잡성\n\n큰 프로그램은 복잡성이 올라간다. 그 복잡성은 코드를 이해하기 어렵게 만들고 코드 간의 의존성을 높인다. 이러한 코드는 버그를 유발하고 유지보수가 어려워진다.\n\n흔히 프로그래밍을 공부하면 알 수 있는 원론적인 내용이다. 아래 코드를 비교해보자. 순서대로 1번과 2번 코드다.\n\n```js\nlet total = 0,\n  count = 1;\nwhile (count <= 10) {\n  total += count;\n  count += 1;\n}\nconsole.log(total);\n```\n\n```js\nconsole.log(sum(range(1, 10)));\n```\n\n두 개의 코드는 완전히 동일한 기능을 한다. 물론 아래의 코드의 sum이나 range는 정의되지 않았다.\n역시 sum이나 range의 내부 코드가 얼마나 복잡하게 구현되어 있는지는 모른다.\n\n2번의 sum이나 range의 구현 코드는 1번의 코드의 loop이나 변수, 조건문이 똑같이 들어 있을 것이다. 따라서 **코드의 길이는 1번이 더 짧을 수 있다.**\n\n그러나 2번째 코드는 훨씬 **직관적** 이다. 1번 코드는 코드를 보면서 실행 플로우를 따라가야 한다. 아래의 코드는 1~10을 sum한다라고 직관적으로 이해할 수 있다.\n\n이렇게 훨씬 단순하게 표현하는 것을 프로그래밍에서 우리는 **추상화** 라 부른다.\n\n## 추상화\n\n> Abstractions hide details and give us the ability to talk about problems at a higher (or more abstract) level. - 자바스크립트 개론(Eloquent JavaScript)\n\n추상화는 상세한 것을 숨겨 문제를 higher level에서 이야기 할 수 있도록 하는 것이다.\n\nCS에서 low level과 high level은 아주 간단하게 말하면 얼마나 복잡하냐를 이야기한다. low-level일수록 더욱 구체적이며 high-level일수록 더욱 추상적이다.\n\nlow-level language는 기계어와 가까우며 high-level language는 인간의 언어와 더욱 가깝다.\n\n다시 돌아가서 추상화라는 것은 문제를 higher level에서 이야기할 수 있게 만든다.\n\nhigher level에서 문제를 다룰수록 문제점을 더욱 명확하게 바라볼 수 있고, 단순하게 접근하여 큰 그림을 그릴 수 있게 된다.\n\n## Higher order function\n\n고차함수는 수학에서 온 단어로 아래 **두 조건 중 한 가지를 만족** 하는 함수다.\n\n- 하나 이상의 함수를 인수로 취한다.\n- 함수를 결과로 반환한다.\n\n고차함수는 값만이 아니라 동작을 추상화 시킨다. 즉 행위도 추상화에 포함이다.\n\n```js\nconsole.log(sum(range(1, 10)));\n```\n\n다시 예시를 가져오자면 이 예시는 1~10까지 나열하는 것, 모두 더하는 것이 추상화된 결과다.\n\n### javascript 고차함수\n\n자바스크립트에서 함수는 일급객체다. 일급객체는 쉽게 설명해서 생성, 대입, 연산, 인자 또는 반환값으로서의 전달 등 기본 연산이 가능한 대상을 말한다.\n\n바로 위에서 설명했듯이 인자 또는 반환값으로 전달이 가능하다.\n\n따라서 자바스크립트의 함수는 위의 두 조건을 만족할 수 있고, 개발자가 이를 만족하게 코딩했다면 고차함수가 된다.\n\n## 예시\n\n### 예시-1\n\nrepeat 예시를 가져와봤다. 일단 아래 코드를 보자. 0부터 99까지 출력하자.\n\n```js\nfor (let i = 0; i < 100; i++) {\n  console.log(i);\n}\n```\n\n요구사항이 변경되어 999까지 출력해보자. 그럼 100을 1000으로 변경하면 될 것이다. 근데 요구사항이 또 바뀔수 있지 않은가?\n\n```js\nfunction repeat(n) {\n  for (let i = 0; i < n; i++) {\n    console.log(i);\n  }\n}\n\nconsole.log(1000);\n```\n\n근데 요구사항이 출력이 아니라면 어쩔까...? 만약 배열로 만들어달라면 코드를 바꿀수도 있다. 코드를 바꾸자니 `repeat()`을 사용하는 다른 코드가 있을 수 있다. 또 배열과 출력을 동시에 해달라하면 또 바꿀건가??\n\n문제는 의존성을 줄이는 것이다. 이 때 필요한 것이 추상화다. 핵심 로직을 분기하고 변경이 있을 수 있는 부분을 분기한다.\n\n```js\nfunction repeat(n, fn) {\n  for (let i = 0; i < n; i++) {\n    fn(i);\n  }\n}\n\nrepeat(1000, console.log);\n\nconst list = [];\nrepeat(1000, i => list.push(i));\n```\n\n### 예시-2\n\n```js\nfunction unless(test, then) {\n  if (!test) then();\n}\n\nrepeat(3, n => {\n  unless(n % 2 == 1, () => console.log(n, 'is even'));\n});\n// → 0 is even\n// → 2 is even\n```\n\n이렇게 조건을 함수로 만들 수 도 있다. 만일 조건이 꽤나 복잡하다면 함수를 이용해서 추상화 시킬 수도 있다는 것이다.\n\n### 예시-3\n\n함수를 결과로 반환하는 예시는 자주 사용되는 map, filter, reduce, some, every와 같은 [배열 내장 함수](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/%EB%B0%B0%EC%97%B4%20%EB%82%B4%EC%9E%A5%ED%95%A8%EC%88%98.md)들이다.\n\n```js\nfunction filterExample(arr, fn) {\n  let resultArr = [];\n\n  for (let i = 0; i < arr.length; i++) {\n    resultArr.push(fn(arr[i]));\n  }\n\n  return resultArr;\n}\n\nfunction greaterThan(n) {\n  return m => m > n;\n}\n\nconst arr = [1, 2, 3, 4, 5];\n\nfilterExample(arr, greaterThan(3));\n```\n\n**위 코드는 실제 filter와는 다르다.** 단순 예제이다.\n위의 코드를 실제 `filter`함수로 구현하면 다음과 같다.\n\n```js\nfunction filterExample(arr, fn) {\n  return arr.filter(fn);\n}\n\nfunction graterThan(n) {\n  return m => m > n;\n}\n\nconst arr = [1, 2, 3, 4, 5];\n\nfilterExample(arr, graterThan(3));\n```\n\n위의 두 함수는 무시하고 아래 두 줄에 집중해보자. 실제 `filterExample`함수가 어떻게 구현되어있는지는 중요하지 않다. `arr`을 만들고 3보다 큰지 안 큰지만 알려달라고 행동을 추상화했다. 이처럼 행동을 추상화함으로써 요구사항이 변경되었을 때 해당 로직을 수행하는 함수만 수정해주면 되기 때문에 의존성을 분리시킬 수 있게 된다. 즉, 유지 보수를 좀 더 쉽게 만들 수 있고 이것이 고차함수가 유용한 이유다.\n\n## 추가로...\n\n고차함수는 함수형 프로그래밍과 연관된다. [함수형 프로그래밍](https://github.com/Im-D/Dev-Docs/blob/master/Language/함수형%20프로그래밍.md) 이란 순수함수와 immutable, side effect 최소화와 관련이 있다.\n\n함수형 프로그래밍은 람다 계산법에서 출발했다. 이는 수학의 람다식처럼 함수를 조합한다. 함수가 조합되려면 함수가 인자로 취급되어야 한다. 즉, 고차함수의 형태다.\n\nJavascript는 함수가 일급객체기 때문에 고차함수가 가능하며 고차함수가 가능하기에 함수형 프로그래밍이 가능하다.\n\n람다에 대해서 간단히 설명하자면, 현재 사용되고 있는 람다의 근간은 수학과 기초 컴퓨터과학 분야에서의 람다 대수이다. 람다 대수는 간단히 말하자면 수학에서 사용하는 함수를 보다 단순하게 표현하는 방법이다.\n\n좀 더 쉽게 표현하면, `Expression`과 `Statement`를 갖는 이름 없는 함수다. Javascript에서 람다식을 단순히 화살표 함수로 오해를 하곤 하는데 엄연히 말하면 화살표 함수는 익명 함수를 좀 더 **람다스럽게** 표현할 수 있도록 해준 것이다.\n\n```js\n// ES5의 Lambda\n[0, 1, 2, 3, 4].map(function(n) {\n  return n * n;\n});\n```\n\n```js\n// ES6의 Lambda\n[0, 1, 2, 3, 4].map(n => n * n);\n```\n\n위의 코드처럼 화살표 함수를 통해 익명함수를 보다 람다스럽게 표현할 수 있게 되었다.\n\n좀 더 자세한 설명은 [다음](https://github.com/Im-D/Dev-Docs/blob/master/Language/Lamda.md)을 참조하길 바란다.\n\n---\n\n### 참고자료\n\n- [Eloquent JavaScript - higher order functions](http://eloquentjavascript.net/05_higher_order.html)\n- [poiemaweb 고차함수](https://poiemaweb.com/js-array-higher-order-function)\n- [Higher-Order Function 이란 무엇인가](https://medium.com/@la.place/higher-order-function-%EC%9D%B4%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80-1c61e0bea79)\n- [hyunseob.github.io - 람다, 익명 함수, 클로저](https://hyunseob.github.io/2016/09/17/lambda-anonymous-function-closure/)\n"
  },
  {
    "path": "Language/함수형 프로그래밍.md",
    "content": "# 함수형 프로그래밍\n\n<br/>\n\n## 함수형 프로그래밍이란?\n\n함수형 프로그래밍은 객체지향 프로그래밍과 같은 프로그래밍 패러다임의 한 예다. 함수형 프로그래밍은 몇 가지 기본 규칙을 기반으로 애플리케이션을 구성하게 된다.\n\n함수형 프로그래밍을 이해하기 위해서는 몇몇의 핵심 개념들을 이해해야하며 이는 위에서 말한 기본 규칙들에 해당된다.\n\n- [선언형 프로그래밍](#선언형-프로그래밍)\n- [순수함수(Pure Function)](#순수함수Pure-function)\n- [고차함수(High Order Function)](#고차함수High-Order-Function)\n- [합성함수(Function composition)](#합성함수Function-Composition)\n- [공유 상태를 피하라(Avoid shared state)](#공유-상태를-피하라Avoid-shared-state)\n- [불변성(Immutable)](#불변성Immutable)\n\n<br/>\n\n## 선언형 프로그래밍\n\n먼저, 함수형 프로그래밍은 선언형 프로그래밍에 속한다. 선언형 프로그래밍을 이해하려면 명령형 프로그래밍에 대한 이해도 수반되어야 한다. 이에 따라 명령형 프로그래밍과 선언형 프로그래밍에 대해 같이 알아보자.\n\n- 명령형 : `어떻게 할 것인가?(HOW?)`를 설명한다.\n- 선언형 : `무엇을 할 것인가?(WHAT?)`를 설명한다.\n\n```js\n// 명령형\n$(\"#btn\").click(function() {\n  $(this).toggleClass(\"highlight\")\n  $(this).text() === 'Add Highlight'\n    ? $(this).text('Remove Highlight')\n    : $(this).text('Add Highlight')\n});\n```\n\n```js\n// 선언형\n<button\n  onToggleHighlight={this.handleToggleHighlight}\n  highlight={this.state.highlight}>\n    {this.state.buttonText}\n</button>\n```\n\n위의 코드를 보면 명령형 프로그래밍을 기반으로 작성하면 버튼을 클릭했을 때 해당 버튼을 어떻게 처리할 것인지를 설명하고 있다. <br/> 반면, 선언형 프로그래밍을 기반으로 작성한 코드는 버튼의 `ToggleHighlight`이벤트가 일어났을 때 무엇을 할 것인지 즉, 어떤 함수를 부를 것인지를 설명하고 있다.\n\n좀 더 쉬운 예로 사당역에서 강남역을 간다고 해보자.\n\n- 명령형\n  - 사당역 9번 출구까지 약 205m 걷기\n  - 사당역 승차 후 강남역에서 하차\n  - 강남역 6번 출구로 나와서 강남역 2호선까지 약 187m 걷기\n\n- 선언형\n  - 출발 : 사당역 2호선\n  - 도착 : 강남역 2호선\n\n위의 예에서도 각각 **어떻게 할 것인지**와 **무엇을 할 것인지**를 표현하는 것을 알 수 있다.\n\n<br/>\n\n## 순수함수(Pure Function)\n\n순수함수는 다음과 같은 특징을 갖고 있다.\n\n- 같은 입력이 주어지면, 항상 같은 출력 값을 반환한다.\n- 유용한 순수 함수는 최소 한 개의 매개변수를 가진다.\n- 반드시 반환값이 있다.\n- 함수의 실행은 프로그램의 실행에 영향을 미치지 않아야 한다. (`Side effect` 가 없어야 한다)\n  - 예를 들어, 함수 내부에서 인자의 값을 변경하거나 애플리케이션의 상태에 영향을 미치는 것이 있다.\n\n```js\n// 비순수 함수, DOM을 변경하는 Side Effect(부수 효과)를 발생\nconst NameContainer = (name) => {\n  let h1 = document.createElement('h1');\n  h1.innerText = name;\n  document.body.appendChild(h1);\n}\n```\n\n```js\n// 순수 함수\n// DOM을 변경하는 책임은 애플리케이션의 다른 부분이 담당\nconst NameContainer = (props) => <h1>{props.name}</h1>\n```\n\n순수 함수를 사용하면 애플리케이션의 상태에 영향을 주지 않기 때문에 입력 값에 대한 결과를 예상하기 쉽고 이에 따라 테스트하기도 용이하다.\n\n<br/>\n\n## 고차함수(High Order Function)\n\n[고차함수(HOF)](https://github.com/Im-D/Dev-Docs/blob/master/Language/%EA%B3%A0%EC%B0%A8%ED%95%A8%EC%88%98(High%20Order%20Function).md)는 다른 함수를 인자로 사용하거나 함수를 반환하는 함수, 또는 두 가지 특징을 모두 가진 함수다.\n\n우리가 잘 알고있는 `map`, `reduce`, `filter`와 같은 [배열 내장 함수](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/%EB%B0%B0%EC%97%B4%20%EB%82%B4%EC%9E%A5%ED%95%A8%EC%88%98.md)들이 여기에 속한다.\n\n```js\nconst numbers = [1, 2, 3, 4, 5];\n\nconst square = number => number * number;\nconst multiple10 = number => number * 10;\nconst squareAfterMlt10 = number => square(multiple10(number));\n\nconst resultArr = numbers.map(squareAfterMlt10);\n\nconsole.log(resultArr); // [100, 400, 900, 1600, 2500]\n```\n\n## 합성함수(Function Composition)\n\n합성함수는 말그대로 두 가지 이상의 함수가 합성되었음을 뜻한다.\n함수형 프로그램은 여러 작은 순수 함수들로 이루어져있기 때문에 이 함수들을 연쇄적으로 또는 병렬로 호출해서 더 큰 함수를 만드는 과정으로 전체 프로그램을 구축해야 한다.\n\n위의 고차함수의 예제에서 주어진 숫자에 10을 곱하고 이를 제곱한 값을 반환하는 `suqareAfterMlt10`이라는 함수를 구현했었다. 하지만 합성 함수를 사용하면 이를 좀 더 간결하고 직관적으로 작성할 수 있다.\n\n```js\nconst numbers = [1, 2, 3, 4, 5];\n\nconst compose = (...fns) => x => fns.reduceRight((v, f) => f(v), x);\nconst square = number => number * number;\nconst multiple10 = number => number * 10;\n\nconst squareAfterMlt10 = compose(square, multiple10);\n\nconst resultArr = numbers.map(squareAfterMlt10);\n\nconsole.log(resultArr); // [100, 400, 900, 1600, 2500]\n```\n\n참고로 위 코드에서 `compose`함수에 사용된 문법은 [Currying](https://github.com/Im-D/Dev-Docs/blob/master/Language/Currying.md)이라는 것인데 여러개의 인자를 가진 함수를 호출 할 경우, 파라미터의 수보다 적은 수의 파라미터를 인자로 받으면 누락된 파라미터를 인자로 받는 기법을 말한다.\n\n<br/>\n\n## 공유 상태를 피하라(Avoid shared state)\n\n공유 상태는 공유 범위(shared scope) 내에 있는 변수, 객체 또는 메모리 공간, 범위 간에 전달되는 객체의 속성 등이다. 공유 범위에는 전역 범위 또는 클로저가 포함될 수 있다.\n\n예를 들어, 컴퓨터 게임에 캐릭터와 게임 아이템이 저장된 유저 객체가 있다고 가정하자. 사용자가 `save()`API를 호출하여 상태를 저장한다고 하자. <br/>호출하여 저장되는 동안 사용자는 `update()` API를 사용하여 게임 캐릭터의 무기를 변경하고, 다른 `save()` API를 호출한다. \n\n만약 두 번째 호출에 대한 응답이 먼저 수신된다면 어떻게 될까? 두번 째 호출에 대한 응답이 이전의 것으로 다시 덮어씌워질 것이다. 이는 공유 상태와 관련된 일반적인 버그인 `경쟁 조건(race condition)`의 예다.\n\n즉, 공유 상태는 해당 함수가 사용하거나 영향을 미치는 모든 공유 변수의 히스토리를 알아야 한다는 문제가 존재한다.\n\n```js\n// 원래 의도한 결과\nconst x = {\n  val: 2\n};\n\nconst x1 = () => x.val += 1;\nconst x2 = () => x.val *= 2;\n\nx1();\nx2();\n\nconsole.log(x.val); // 6\n```\n\n```js\n// 공유 상태에 의한 버그\nconst y = {\n  val: 2\n};\n\nconst y1 = () => y.val += 1;\nconst y2 = () => y.val *= 2;\n\ny2();\ny1();\n\nconsole.log(y.val); // 5\n```\n\n```js\n// 공유 상태를 피했을 때\nconst x = {\n  val: 2\n};\n\nconst x1 = x => {\n  return {...x, val: x.val + 1 };\n};\nconst x2 = x => {\n  return { ...x, val: x.val * 2 };\n};\n\nconsole.log(x1(x2(x)).val); // 5\n\n\nconst y = {\n  val: 2\n};\n\nx2(y);\nx1(y);\n\nconsole.log(x1(x2(y)).val); //5\n```\n\n마지막 예제를 살펴보면, 여전히 합성의 순서를 변경하면 출력이 변경된다. 즉, 실행 순서는 여전히 중요하다. 하지만 중요한 것은 더 이상 함수를 기존의 객체가 제대로 변경되었는지 확인하고 실행할 필요가 없다는 것이다. \n\n즉, 순수 함수를 사용하여 공유 상태를 피했기 때문에 함수 호출 타이밍에 대한 종속성이 제거되고 함수의 호출은 항상 의도한대로 이뤄질 수 있게 된다.\n\n<br/>\n\n## 불변성(Immutable)\n\n함수형 프로그래밍에서는 불변성을 유지해야한다. 즉, 데이터가 변할 수 없다. 이를 불변성을 가진다, **Immutable하다** 라고 한다.\n데이터 변경이 필요한 경우, 원본 데이터 구조를 변경하지 않고 그 데이터의 복사본을 만들어 작업을 진행한다.\n\n```js\n// mutable\nconst numbers = [1, 2, 3, 4, 5];\n\nconst square = arr => {\n\tfor(let i=0; i<arr.length; i++) {\n\t\tarr[i] = arr[i] * arr[i];\n    }\n\n\treturn arr;\n}\n\nconsole.log(square(numbers)); // [1, 4, 9, 16, 25]\nconsole.log(numbers); // [1, 4, 9, 16, 25]\n```\n\n```js\nconst numbers = [1, 2, 3, 4, 5];\n\n// immutable\nconst squareWithDeepCopy = arr => arr.map(item => item * item);\n\nconsole.log(squareWithDeepCopy(numbers)); // [1, 2, 3, 4, 5]\nconsole.log(numbers); // [1, 4, 9, 16, 25]\n```\n\n`squareWithDeepCopy`에서 사용된 배열 내장 함수 중 하나인 `map`은 `Deep Copy`를 통해 연산을 진행하므로 원본 데이터인 `numbers`를 바꾸지 않는다. 이를 `Immutable`하다라고 한다.<br/>\n반면, `square`함수를 통해 연산을 진행하면 원본 데이터인 `numbers`배열의 원소 값을 변경하게 된다. 이를 `Mutable`하다라고 한다.\n\n<br/>\n\n> 함수형 프로그래밍은 생소한 개념이 아니다. 이전에도 존재했던 개념이며 다시 주목받고 있을 뿐이다. 그 이유는 여러 가지가 있겠지만, 가장 본질적인 장점은 `side-effect`에 의존한 코드에 비해 유지보수가 용이하다는 점, 코드를 이해하기 수월하다는 점이 있을 것이다.\n\n> 함수형 프로그래밍은 **부수 효과(Side Effect)를 제거할 수 없다.** 단지 제어할 수 있을 뿐이다. <br/>왜냐하면 애플리케이션은 실제 세계와 맞닿는 부분이 존재하기 때문에 몇몇 부분은 비 순수할 수 밖에 없다.<br/>\n목표는 비 순수한 코드를 최소한으로 줄이는 것이고, 그것들을 순수 함수를 이용하여 구분하고 별도 공간에 분리시키는 것이다.\n\n---\n\n#### Reference\n\n- [jooyunghan_medium](https://medium.com/@jooyunghan/%ED%95%A8%EC%88%98%ED%98%95-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EC%86%8C%EA%B0%9C-5998a3d66377)\n- [JaeYeopHan_github](https://github.com/JaeYeopHan/Interview_Question_for_Beginner/tree/master/Development_common_sense#object-oriented-programming)\n- [kakao tech](http://tech.kakao.com/2016/03/03/monad-programming-with-scala-future/)\n- [함수형-프로그래머가-되고-싶다고?](https://github.com/FEDevelopers/tech.description/wiki/%ED%95%A8%EC%88%98%ED%98%95-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EA%B0%80-%EB%90%98%EA%B3%A0-%EC%8B%B6%EB%8B%A4%EA%B3%A0%3F-(Part-1))\n- [번역 - 함수형 프로그래밍이란 무엇인가?](https://sungjk.github.io/2017/07/17/fp.html)\n- [고차 함수](http://jeonghwan-kim.github.io/js/2017/04/03/high-order-function-in-javascript.html)\n- [WONISM - 함수형 프로그래밍이란?](https://wonism.github.io/what-is-fp/)\n"
  },
  {
    "path": "ML/머신러닝이란.md",
    "content": "# 머신 러닝(Machine Learning, ML)이란?\n\n프로그래밍을 간단하게 말하자면, 입력 데이터가 있을 때, 데이터를 집어넣어 원하는 결과 데이터를 출력하는 알고리즘을 만드는 것을 말한다.\n\n머신 러닝은 문제를 해결하기 위해 우리가 만든 맞춤 코드를 사용하는 것이 아니라, 어떤 데이터가 있다면, 무엇인가 흥미로운 것을 알려줄 수 있는 일반적인 알고리즘이 있다는 관점에서 시작한다.\n\n어떤 언어로 어떤 코드를 작성하는 지는 상관 없이, 데이터를 어떻게 효율적으로 가공하고, **패턴이나 관계를 찾아 존재하지 않는 결과를 예측**한다면 목적을 이뤘다고 본다. 즉 인간이 하나부터 열까지 직접 가르치는 기계를 의미하는 것이 아니라, 학습할 것을 일단 던져주고 이걸 가지고 스스로 학습하는 기계를 의미한다.\n\n> \"Field of study that gives computers the ability to learn without being explicitly programmed”\n프로그램을 명시적으로 짜 놓는 것이 아닌, 컴퓨터가 스스로 학습할 수 있는 능력을 부여하는 연구분야\n\n## Machine Learning의 분류\n\n![ML 종류](https://user-images.githubusercontent.com/24274424/91469635-97729f80-e8ce-11ea-9ee5-264c73e94910.png)\n\n\n> 출처 : [생활코딩](https://opentutorials.org/course/4548/28934)\n\n현재 머신러닝는 크게 3개로 분류된다.\n\n## 지도 학습(Supervised Learning)\n\n정답(Label)을 알려주며 학습시키는 것이다.\n\n> 지도 학습 (Supervised Learning)은 훈련 데이터(Training Data)로부터 하나의 함수를 유추해내기 위한 기계 학습(Machine Learning)의 한 방법이다. - [위키백과](https://ko.wikipedia.org/wiki/%EC%A7%80%EB%8F%84_%ED%95%99%EC%8A%B5)\n\n지도 학습은 각각의 입력값과 그에 대응하는 결과값을 모두 알려주는 방식이다. 학습 목적에 따라 분류와 회귀로 나뉜다. 데이터 세트로 학습된 알고리즘을 통해 알지 못했던 결과값을 정확하게 예측하는 것이 목적이다.\n\n지도 학습에서 훈련 데이터는 일반적으로 입력값을 벡터 형태로 가지고 있으며 각각의 벡터에 대해 원하는 결과(Label)가 무엇인지 표시되어 있다. 이렇게 유추된 함수 중 **연속적인 값을 출력하는 것을 회귀 분석**이라 하고 주어진 **입력 벡터가 어떤 종류의 값인지 표시하는 것을 분류**라 한다.\n\n### 평가 방법\n\n훈련 데이터로부터 하나의 함수가 유추되고 나면, 해당 함수에 대한 평가를 통해 파라미터를 최적화한다. 이러한 평가를 위해 교차 검증이 이용되며, 이를 위해 검증 집합을 다음의 3가지로 나눈다.\n\n- 훈련 집합(A Training Set)\n- 검증 집합(A Validation Set)\n- 테스트 집합(A Test Set)\n\n### 분류\n\n분류는 주어진 데이터를 정해진 카테고리에 따라 분류하는 문제다. 최근 많은 이미지 분류도 분류 문제 중에 하나다.\n\n예를 들어 스팸메일을 예측한다고 가정하면 해당 메일이 스팸메일인가 일반메일인가 로 **Labelling** 될 수 있다. 이처럼 예, 아니오 로 구분될 수 있는 분류를 **Binary Classification(이진 분류)** 라고 한다.\n\n문제가 예, 아니오 로 구분되지 않을 수도 있다. 예를 들어 이 동물이 무엇일까? 라고 했을 때 강아지, 고양이, 나무늘보 등으로 예측하는 상황이 있다. 이러한 분류를 **Multi-label Classification(멀티 라벨 분류)** 라고 한다.\n\n### 회귀\n\n회귀는 어떤 데이터들의 특징을 기준으로 연속된 값을 예측하는 문제이다.(연속된 값이란 흔히 그래프를 말한다.)\n\n주로 어떤 패턴이나 트렌드, 경향을 예측할 때 사용되며, 일반적으로 집의 크기에 대해 매매 가격을 예로 든다. `ex) 보스턴 집값 예측`\n\n지도 학습의 가장 큰 문제는 데이터를 확보하는 것이다. 따라서 지도 학습의 단점을 보완하기 위해 비지도 학습에 대한 중요성과 관심이 높아지고 있다.\n\n## 비지도 학습(Unsupervised Learning)\n\n정답을 따로 알려주지 않고(label이 없음, 지도학습은 각각에 label이 존재), 비슷한 데이터들을 **군집화** 하는 것이다.\n\n> 비지도 학습(Unsupervised Learning)은 기계 학습의 일종으로, 데이터가 어떻게 구성되는지를 알아내는 문제의 범주에 속한다. 이 방법은 지도 학습(Supervised Learning) 혹은 강화 학습(Reinforcement Learning)과는 달리 입력값에 대한 목표치가 주어지지 않는다. - 위키백과\n\n결과값을 알려주지 않은 데이터를 보고 스스로 학습하는 방식이다. 데이터가 무작위로 분포되어 있을 때 비슷한 것끼리 묶는 **군집화(Clustering) 모델**이 대표적이다.\n\n흔히 데이터의 숨겨진 특징이나 수평적, 수직적 구조를 발견하고 분석하는 데 사용된다.\n\n예를 들어 강아지, 고양이, 기린, 원숭이 사진을 비지도 학습으로 분류한다고 하면, 각각의 동물들이 어떤 동물인지 정답을 알려주지 않았기 때문에, 이 동물을 '무엇' 이라고는 정의할 수는 없지만, 동물의 특징별로 분류하게 된다.\n\n다리가 4개인 강아지, 고양이, 기린은 한 분류가 될 수 있고 또는 목이 긴 기린이 한 분류, 다리가 2개인 원숭이가 한 분류로 나뉘게 될 것이다.\n\n따라서 비지도 학습은 예측 등이 아닌 데이터가 어떻게 구성되어있는지 밝히는 데 주로 사용하고, 일종의 그룹화 알고리즘으로 볼 수 있다.\n\n## 강화 학습(Reinforcement Learning)\n\n상과 벌이라는 보상(Reward)을 주어 상을 최대화하고 벌을 최소화하도록 강화 학습하는 방식이다.\n\n> 강화 학습(Reinforcement learning)은 기계 학습의 한 영역이다. 행동심리학에서 영감을 받았으며, 어떤 환경 안에서 정의된 에이전트가 현재의 상태를 인식하여, 선택 가능한 행동 중 보상을 최대화하는 행동 혹은 행동 순서를 선택하는 방법이다. - 위키백과\n\n앞서 말한 지도 학습이나 비지도 학습과 다른 성격으로, 데이터를 줬을 때 어떠한 행동을 취하고 그에 따른 보상을 얻으면서 학습을 진행한다. **학습의 최종 목표는 보상을 최대화하는 것이다**.\n\n주어진 동적 환경에서의 최선의 선택을 찾기 위한 다양한 분야에 응용되고 있다. \n\n구글의 알파고도 바로 이 강화 학습을 통해 바둑을 습득한 것으로 알려져 있다.\n\n개인적으로는 강화학습을 AWS Deep Racer로 경험을 해보았다. 해당 기능을 사용해본 경험으로는 Reward Function을 설정해주면서 가상환경에서 차량이 실시간으로 보내온 이미지를 분석해서 Reward Function을 사용해 점수를 주는 방식이다.\n\n> AWS DeepRacer : [https://aws.amazon.com/ko/deepracer/](https://aws.amazon.com/ko/deepracer/)\n\n## 간단한 이미지 분류 모델을 만들어보자.\n\n1. 쉽게 이미지 분류를 할 수 있는 사이트 : [Image Model - Teachable Machines](https://teachablemachine.withgoogle.com/train/image)\n\n2. 직접 학습시킨 모델을 가지고 커스텀 가능한 사이트 : [머신러닝머신](https://ml-app.yah.ac/)\n\n## 만들어진 모델을 가지고 웹에 심어서 테스트해보기\n\n평상시의 이미지와 마스크를 착용한 이미지를 학습시켜서 분류를 할 수 있는 모델을 만들었다. 이를 가지고 [tensorflow.js](https://www.tensorflow.org/js)를 가지고 웹에 적용해서 웹캠으로 실시간으로 착용여부를 확인할 수 있도록 만들었다.\n\n- [마스크 착용여부 모델](https://seonhyungjo.github.io/tensorflow-2.0-study/%EB%A7%88%EC%8A%A4%ED%81%AC_%EC%B0%A9%EC%9A%A9_%EC%97%AC%EB%B6%80/)\n\n#### Reference\n\n- [머신러닝1 - 생활코딩](https://opentutorials.org/course/4548)\n- [[인공지능] 지도학습, 비지도학습, 강화학습 :: ebb and flow](https://ebbnflow.tistory.com/165)\n- [[AI] 머신러닝 지도학습(Supervised Learning) , 비지도학습(Unsupervised Learning) 차이점과 장단점](https://wendys.tistory.com/169)\n- [지도 학습 - 위키백과, 우리 모두의 백과사전](https://ko.wikipedia.org/wiki/%EC%A7%80%EB%8F%84_%ED%95%99%EC%8A%B5)\n- [비지도 학습 - 위키백과, 우리 모두의 백과사전](https://ko.wikipedia.org/wiki/%EB%B9%84%EC%A7%80%EB%8F%84_%ED%95%99%EC%8A%B5)\n- [[머신러닝] 지도학습(Supervised), 비지도학습(Unsupervised), 강화학습(Reinforcement)](https://marobiana.tistory.com/155)\n"
  },
  {
    "path": "Network/3-way handshaking & 4-way handshaking.md",
    "content": "# 3-way handshaking & 4-way handshaking\n이번 시간에는 TCP 통신에서 쓰이는 `3-way handShaking`과 `4-way handShaking`을 정리해보았다.\n\n# TCP\nTCP는 OSI 7계층 중 **전송 계층**에서 사용하는 프로콜로서, 장치들 사이에 논리적인 접속을 위한 연결을 설정하여 **신뢰성을 보장**하는 연결형 서비스이다.\n> OSI 7계층에 대한 설명은 [이곳](https://github.com/im-d-team/Dev-Docs/blob/master/Network/OSI7%20Layer.md)을 참고하길 바란다.\n\n## TCP의 특징\n- 인터넷상에서 데이터를 메시지의 형태로 보내기 위해 `IP`와 함께 사용하는 프로토콜이다.\n- 연결형 서비스로 [흐름제어](https://github.com/im-d-team/Dev-Docs/blob/master/Network/Flow%20control.md) 및 [혼잡제어](https://github.com/im-d-team/Dev-Docs/blob/master/Network/congestion%20control.md)를 제공한다.\n> 연결형 서비스란 `3-way handshaking`과정을 통해 연결을 설정하고, `4-way handshaking`을 통해 연결을 해제하는 것을 의미한다.\n- 높은 신뢰성을 보장한다.\n- UDP보다 속도가 느리다.\n> TCP와 달리, UDP는 연결설정과 연결해제과정, 흐름제어를 해주지 않기 때문에 속도가 빠름\n- 전이중(Full-Duplex), 점대점 방식(Point to Point)이다.\n> 전이중이란 전송이 양방향으로 동시에 일어날 수 있는 것을 의미하고, 점대점은 각 연결이 정확히 2개의 종단점을 가지고 있는 것을 의미한다.\n- 연속성보다 신뢰성 있는 전송이 중요할 때에 사용된다.\n\n여기서 연속성이라는 것은, 중간에 데이터가 유실되더라도 끊기지 않고 전송하는 것을 뜻한다. UDP는 데이터만 전송하고 도착유무는 확인하지 않는다. 따라서 중간에 데이터가 유실되더라도 타격이 없는 실시간 스트리밍에 UDP가 대표적으로 사용된다.\n\n그리고 신뢰성은 데이터의 도착 유무를 확인하고 재전송을 거치므로 정확한 전송을 보장한다는 점에서 신뢰성이 높다고 표현한다. TCP가 신뢰성이 높은 프로토콜이며 웹 HTTP 통신, 이메일, 파일전송 등 정확한 데이터 전송이 중요한 곳에 쓰인다.\n\n## TCP 헤더\n![TCP헤더](https://user-images.githubusercontent.com/43868540/103455518-2a19c400-4d31-11eb-8f3f-a0e4090402bf.jpg)\n> [출처 afteracademy](https://afteracademy.com/blog/what-is-a-tcp-3-way-handshake-process)\n\n헤더는 3-way handshaking을 설명하기 위한 일부만 하고 나머지 요소는 @sNyung님의 [TCP와 UDP](https://github.com/im-d-team/Dev-Docs/blob/master/Network/TCP%20%26%20UDP.md) 글을 참고 바람!\n-  SYN : Synchronize sequence numbers의 약자로, 연결요청하고 세션을 설정하는 데 사용된다.\n-  ACK : Acknowledgment의 약자로, 신뢰성을 보장한다.\n\n여기서 시퀀스 번호를 보내는데, 처음에 시퀀스 번호를 ISN(Initial Sequence Number)이라고 한다. ISN은 난수의 숫자를 생성해 보낸다고 한다. 왜 순차적인 번호가 아닌 난수일까?\n\n연결을 맺을 때 사용하는 포트(port)는 유한 범위 내에서 사용하고 시간이 지남에 따라 재사용된다. 따라서 두 통신 호스트가 과거에 사용된 포트 번호 쌍을 사용하는 가능성이 존재한다. 서버 측에서는 SYN을 보고 패킷을 구분하는데 순차적인 번호가 전송된다면 이전의 connection으로부터 오는 패킷으로 인식할 가능성이 크다. 이러한 가능성을 줄이기 위해 난수로 시퀀스 번호를 설정하는 것이다.\n\n## TCP의 연결설정 및 해제 과정\nTCP 통신을 이용하여 데이터를 전송하기 위해서는 네트워크 연결을 설정하는 과정이 필수적이다. 네트워크 연결을 하기 위해서 TCP는 `3-way handshaking`이라는 과정을 거친다.\n\n## 3-way handshaking\n`3-way handshaking`이란 `TCP/IP` 프로토콜을 이용해서 통신하는 응용 프로그램이 데이터를 전송하기 전에 정확한 전송을 보장하기 위해 상대방 컴퓨터와 사전에 세션을 수립하는 과정을 의미한다. \n\n### why 3-way handshaking?\n왜 3번의 과정을 거쳐야 할까? 2번의 과정을 거치면 왜 안될까?\n\n\nClient ------SYN-----> Server\n\nClient <-----ACK------ Server\n\n\nTCP는 양방향 연결을 지향하기 때문에 3번의 과정을 거쳐야 한다. 과정을 더 자세히 뜯어보면 두 개의 단순연결이 되어있는 것이다. \n\n위에 사진처럼 2번의 과정을 거치면 무슨 일이 일어날까 생각해보자.\n\nA 친구가 B 친구한테 멀리서 소리친다. \"너 잘 들려?\"\nB 친구는 A 친구한테 소리친다. \"응 잘 들려!\"\n만약 A 친구가 말할 줄만 알고 소리를 못 들으면 B 친구가 아무리 소리쳐봤자 안들린다. B 친구도 A 친구가 잘들리는 지 확인해야 한다. \n\n통신도 마찬가지로 데이터를 보내기 전에 내가 보낼 데이터를 상대방이 받을 수 있는지 먼저 확인해야 한다.\n클라이언트는 SYN을 던져 서버의 상태를 확인하는 패킷을 던진다. 서버는 잘 들린다는 신호인 ACK를 보낸다.\n여기서 클라이언트도 잘 들을 수 있는지 확인하기 위해 서버는 SYN을 던진다. 역시 클라이언트도 잘 들린다는 신호인 ACK를 보낸다. \n\n개시자는 SYN을 보내고 응답자는 ACK를 보낸다. 이것은 하나의 단순 연결이 된다. 따라서 TCP는 두 개의 단순연결이라는 것이다.\n`3-way handshaking`을 통해 실제로 데이터 전달이 시작하기 전에 수행하여 논리적인 접속을 성립한다.\n\n![3-way](https://user-images.githubusercontent.com/43868540/103471183-634d4500-4dc0-11eb-8e9c-3e914d8b9e78.jpg)\n\n> [출처 mdpi](https://www.mdpi.com/2076-3417/6/11/358/htm)\n\n1. 클라이언트가 서버에게 연결 요청 메시지를 전송한다. (SYN)\n2. 메시지를 수신한 서버는 요청을 수락하며 클라이언트에게 포트를 열어달라는 메시지도 전송한다. (SYN+ACK)\n3. 서버가 요청을 수락했다는 메시지를 받은 클라이언트가 수락 확인을 보내 연결을 맺는다. (ACK)\n\n### TCP 상태\n|상태|설명|\n|------|---|\n|LISTEN|SYN을 기다리는 상태|\n|SYN-SENT|SYN을 보내고 ACK를 기다리는 상태|\n|SYN-RECEVED|SYN+ACK을 보내고 ACK를 기다리는 상태|\n|ESTABLISHED|커넥션이 생성된 상태, 데이터를 전송할 수 있다.|\n\n## 4-way handshaking\nTCP 연결을 하였다면 연결 해지하기 위해 `4-way handshaking`이라는 과정을 거친다.\n이것 또한 왜 여러 번 패킷을 주고받을까? 그 이유도 역시 TCP의 신뢰성을 보장하기 위함에 있다.\n그러므로 연결 종료 시에도 양측이 서로 확인하에, 즉 당사자가 연결을 종료하고 싶어하며 종료할 준비가 됐는지 확인한 후에 각자의 종료 과정을 거치게 되는 것이다.\n\n![4-way handshaking](https://user-images.githubusercontent.com/43868540/103454298-f84f3000-4d25-11eb-8e39-6771a1cecd1a.png)\n\n> [출처 hongpossible.tistory](https://hongpossible.tistory.com/entry/TCP-UDP-34-Way-HandShaking)\n\n1. 클라이언트가 연결을 종료하겠다는 메시지를 전송한다 (FIN)\n2. 서버는 클라이언트의 메시지를 받고 확인 메시지를 전송하고 통신이 종료될 때까지 기다린다. (ACK)\n3. 서버는 데이터를 모두 보내고 연결 해지할 준비 완료되었다는 메시지를 전송한다. (FIN)\n4. 클라이언트는 서버의 메시지를 확인했다는 메시지를 보내고 기다린다. (ACK)\n> 클라이언트가 보낸 ACK가 네트워크 오류 등으로 도착하지 않았을 경우, 서버가 보낸 FIN보다 늦게 데이터가 도착한 경우를 고려한 것이다.\n5. 서버는 클라이언트의 확인 메시지를 받고 소켓 연결을 닫는다 (CLOSE)\n\n### 클라이언트 상태\n|상태|설명|\n|------|---|\n|FIN_WAIT 1|클라이언트가 연결 종료 메시지를 보낸 상태|\n|FIN_WAIT 2|서버의 연결 해지를 위해 대기하는 상태|\n|TIME_WAIT|연결 해지할 준비 완료 되었다는 상태|\n|CLOSED|클라이언트의 세션을 닫은 상태|\n\n### 서버 상태\n|상태|설명|\n|------|---|\n|CLOSE_WAIT|클라이언트가 연결 종료 메시지를 보낸 상태|\n|LAST_ACK|연결 해지를 위한 준비완료했다는 상태|\n|CLOSE|서버의 세션을 닫은 상태|\n\n----\n#### Reference\n- [3-way handshaking & 4-way handshaking](https://k39335.tistory.com/21?category=653558)\n- [why not just 2-way?](https://networkengineering.stackexchange.com/questions/24068/why-do-we-need-a-3-way-handshake-why-not-just-2-way)\n- [why randominzed sequence number?](https://asfirstalways.tistory.com/356)\n"
  },
  {
    "path": "Network/CORS.md",
    "content": "# CORS(Cross-Origin Resource Sharing)\n\n## Same Origin Policy\n\n일반적인 HTTP 요청은 다른 도메인의 자원을 요청하는 것이 가능하다 이를 Cross-Site HTTP Request라고 한다.\n\n그렇지만 script에서 다른 자원의 요청은 원칙적으로 동일한 도메인에서만 허용한다.\n이를 [Same-Origin Policy](https://developer.mozilla.org/ko/docs/Web/Security/Same-origin_policy)라고 한다.\n\n**Same Origin Policy**란 script 내에서 다른 도메인의 script와 상호작용 하는 것을 제한하는 정책이다. 출처가 같다는 것은 같은 도메인, 정확하게는 동일한 protocol, port, host를 갖고 있음을 말한다.\n\n[XHR](https://developer.mozilla.org/ko/docs/Web/API/XMLHttpRequest), [AJAX](https://ko.wikipedia.org/wiki/Ajax)를 사용하며 개발하게 되면 이 정책을 깨고 자원을 이용하는 경우가 너무 많다.\n\n특히 현대의 SPA(Single Page Application) 방식의 개발은 필수적이다.\n\n이 Same Origin Policy을 깨트리며 통신하는 대표적인 방법으로 CORS, JSONP가 있다.\n\n## CORS\n\nCORS는 크로스 도메인 이슈를 해결하는 사실상의 표준 방법이다. 클라이언트 측에서는 따로 설정할 것이 없다. 서버측에서 HTTP response Header에 허용 가능한 도메인을 설정해주면 된다.\n\n### Preflight Request\n\n![preflight-process](/assets/images/preflight-process.png)\n\nCORS를 이용하면 위의 그림처럼 preflight와 실제 요청으로 나뉘어 총 두 번의 request가 발생한다.\n\n1. 클라이언트가 서버에 자원의 이용 권한이 어떻게 되는지 OPTIONS 메서드를 이용해 Preflight request 보낸다.\n2. 서버는 관련 정보를 헤더에 담아 response를 보낸다.\n3. 실제 request를 보낸다.\n\n이 때 OPTIONS라는 HTTP method는 body가 없고 header만 주고 받는다.\n\n### Request 헤더\n\n---\n\n|           HTTP Header            |          Description           |\n| :------------------------------: | :----------------------------: |\n|   Origin    |     요청을 보내는 `페이지 출처`     |\n| Access-Control-Request-Method |    실제 요청하려는 `메서드`     |\n|   Access-Control-Request-Headers   |    실제 요청에 포함된 `헤더` 설정     |\n\n### Response 헤더\n\n---\n\n|           HTTP Header            |          Description           |\n| :------------------------------: | :----------------------------: |\n|   Access-Control-Allow-Origin    |     접근 가능한 `url` 설정     |\n| Access-Control-Allow-Credentials |    접근 가능한 `쿠키` 설정     |\n|   Access-Control-Allow-Headers   |    접근 가능한 `헤더` 설정     |\n|   Access-Control-Allow-Methods   | 접근 가능한 `http method` 설정 |\n|   Access-Control-Max-Age   | 캐시 유지 시간 |\n\n\n```http\nAccess-Control-Allow-Origin : *  //(1)\nAccess-Contorl-Allow-Credentials : true //(2)\nAccess-Control-Allow-Headers : X-Requested-With, Content_Type, Origin, Accept, Access-Control-Request-Method, Access-Control-Request-Headers, Authorization   \nAccess-Control-Allow-Methods : GET, POST, DELETE, OPTIONS // (3)\nAccess-Control-Max-Age : 3600 //(4)\n```\n1. \\* 이면 모든 도메인의 요청을 허용한다.  \n2. 쿠키를 사용하여 인증하는 경우 \n3. `GET`, `POST`, `DELETE`, `OPTIONS` 메소드를 허용한다. 특히 `OPTIONS`메소드는 `Preflight request`를 받기 위해 허용해줘야한다. \n4. 캐시를 유지할 시간이며 ms단위.\n\n## JSONP(JSON with Padding)\n\nCORS 등장 이전에 사용되던 방식이다.\n\n위에서도 말했듯이 script 내에서는 다른 도메인의 script를 사용할 수 없다. \n\nscript 내에서는 실행할 수 없지만 html이 `<script>` 태그를 요청하여 실행 것은 여전히 허용된다.\n\n이 점을 이용한 방법이 JSONP방식이다.\n\nclient\n\n```js\n\nfunction myCallback(data){\n  // do something\n};\n\nconst script = document.createElement('script');\nscript.src = '//test.com/jsonp?callback=myCallback&q=jin';\ndocument.getElementsByTagName('head')[0].appendChild(script); // 함수 실행\n```\n\nserver\n\n```js\nconst userCallback = request.params.callback;\nconst query = request.params.q;\nconst data = model.find(query);\nres.send(`${userCallback}(${data})`);\n```\n\n1. 클라이언트에서 콜백을 미리 정의한다.\n2. script의 url에 콜백 이름을 같이 보낸다.\n3. 서버에서는 로직 처리 이후 `callback명(data)` 의 형식으로 함수를 실행하는 string을 보낸다.\n4. script태그를 dom에 붙이면 바로 요청-응답이 이루어지며 string을 스크립트처럼 실행시킨다.\n\n이렇게 html의 `<script>` 태그를 이용하여 콜백을 실행시키는 방법이 JSONP다.\n\nW3C의 CORS 등장 이후 CORS가 거의 표준처럼 자리잡은 뒤로는 잘 사용하지 않는다.\n\n---\n\n#### Reference\n\n- [Cross Origin Resource Sharing - CORS](https://homoefficio.github.io/2015/07/21/Cross-Origin-Resource-Sharing/)\n- [JSONP 알고 쓰자](http://kingbbode.tistory.com/26)\n- [javascript ajax 크로스 도메인 요청하기(CORS)](http://enterkey.tistory.com/409)\n- [CORS 크로스 도메인 이슈 (No 'Access-Control-Allow-Origin' header is present on the requested resource)](http://ooz.co.kr/232)\n- [Enabling Cross Origin Requests for a RESTful Web Service](https://spring.io/guides/gs/rest-service-cors/)\n- [javascript ajax 크로스도메인 요청-CORS](https://brunch.co.kr/@adrenalinee31/1)\n"
  },
  {
    "path": "Network/DHCP&DNS.md",
    "content": "# DHCP, DNS 프로토콜\n\n### 이전 글 복습하기\n\n1. [네트워크 기초 - IP](https://github.com/im-d-team/Dev-Docs/blob/master/Network/IP.md)\n2. [네트워크 기초 - SubnetMask](https://github.com/im-d-team/Dev-Docs/blob/master/Network/Subnetmask.md)\n3. [네트워크 기초 - Types of IP](https://github.com/im-d-team/Dev-Docs/blob/master/Network/TypesOfIP.md)\n4. [네트워크 기초 - OSI 7 계층과 TCP/IP 계층](https://github.com/im-d-team/Dev-Docs/blob/master/Network/OSI7%20Layer.md)\n5. [네트워크 기초 - TCP & UDP](https://github.com/im-d-team/Dev-Docs/blob/master/Network/OTCP%20%26%20UDP.md)\n\n- 네트워크 : 두 대 이상의 컴퓨터가 논리적 또는 물리적으로 연결되어 통신이 가능한 상태(PAN, LAN, MAN, WAN).\n- IP 주소 : 네트워킹이 가능한 장비를 식별하는 주소.\n- IPv4, IPv6\n- A, B, C 클래스 : 네트워크 영역과 호스트 영역을 구분한 기준\n  - A : `0.0.0.0` ~ `127.255.255.255`\n  - B : `128.0.0.0` ~ `191.255.255.255`\n  - C : `192.0.0.0` ~ `223.255.255.255`\n- 네트워크 주소 : 호스트 부분이 모두 0인 경우\n- 브로드캐스트 주소 : 호스트 부분이 모두 1인 경우\n- 서브넷마스크 : 네트워크와 호스트 영역을 구분하기 위한 값\n- 서브네팅 : 네트워크 관리자가 네트워크 성능을 향상하기 위해, 자원을 효율적으로 분배하는 것\n- 공인 IP : 인터넷 사용자의 로컬 네트워크를 식별하기 위해서 ISP에서 제공하는 IP 주소. 즉, 외부에 공개된 IP 주소.\n- 사설 IP : 전체 IP 대역 중 특수한 목적으로 사용하는 대역. 아래의 대역이 사설 IP 대역.\n  - A : `10.0.0.0` ~ `10.255.255.255`\n  - B : `172.16.0.0` ~ `172.31.255.255`\n  - C : `192.168.0.0` ~ `192.168.255.255`\n- 고정 IP : 고정적으로 부여된 IP로 한번 부여되면 IP를 반납하기 전까지는 다른 장비에 부여할 수 없는 IP 주소\n- 동적 IP : 장비에 고정적으로 IP를 부여하지 않고 컴퓨터를 사용할 때 남아 있는 IP 중에서 돌아가면서 부여하는 IP 주소.\n- OSI 7계층 : OSI는 `Open Systems Interconnection`의 약자로 개방형 시스템이라는 뜻이다. OSI 7계층은 네트워크에서 통신이 일어나는 과정을 7단계로 나눈 것.\n  - 물리, 링크, 네트워크, 전송, 세션, 표현, 응용\n- TCP/IP 4계층 : 네트워크 전송 시 데이터 표준을 정리한 것이 ISO 7계층이라고 한다면, 이 이론을 실제 사용하는 인터넷 표준에서 사용하는 계층.\n  - 네트워크 엑세스(물리, 링크), 인터넷, 전송, 응용(세션, 표현, 응용)\n- TCP\n    - 연결이 성공해야 통신이 가능하다(연결형 프로토콜).\n    - 데이터의 경계를 구분하지 않는다.\n    - 신뢰성 있는 데이터 전송이 이루어진다(재전송).\n- UDP\n    - 비연결 프로토콜이다.\n    - 데이터의 경계를 구분한다(데이터그램).\n    - 비신뢰성 있는 데이터 전송이 이루어진다.\n\n## DHCP(Dynamic Host Configuration Protocol)\n\nDHCP이란 네트워크상에서 동적으로 IP주소 및 기타  구성정보 등을 부여/관리하는 프로토콜로 해당 호스트에게 `IP 주소`, `서브넷마스크`, `기본 게이트웨이 IP 주소`, `DNS 서버 IP주소`를 자동으로 **일정 시간** 할당 해주는 인터넷 프로토콜이다.\n\nDHCP를 통한 IP 주소 할당은 `임대(Lease)`라는 개념을 가지고 있다. 이는 DHCP 서버가 IP 주소를 영구적으로 단말에 할당하는 것이 아니고 **임대 기간(IP Lease Time)을 명시하여 그 기간 동안만 단말이 IP 주소를 사용**하도록 하는 것이다. \n\n단말은 임대 기간 이후에도 계속 해당 IP 주소를 사용하고자 한다면 **IP 주소  임대 기간 갱신(IP Address Renewal)** 을 DHCP 서버에 요청해야 하고 또한 단말은 임대 받은 IP 주소가 더 이상 필요치 않게 되면 **IP 주소 반납 절차(IP Address Release)** 를 수행하게 된다.\n\n즉, **유동 IP를 할당한다** 라는 말은 DHCP서버로부터 IP를 DHCP서버에서 설정 해놓은 사용 시간만큼 임대하는 것을 의미한다.\n\n### DHCP 서버 입장에서\n\nDHCP 서버는 인터넷을 제공해주는 곳의 서버에서 실행되는 프로그램으로 일정한 범위의 IP 주소를 다른 클라이언트에게 할당하여 자동으로 설정해주는 역할을 한다. DHCP 서버는 클라이언트에게 할당된 IP 주소를 변경 없이 유지해 줄 수 있다.\n\n> 참고 : Iptime 공유기를 이용한 DHCP 알아보기 [https://m.blog.naver.com/hello3311/220159169605](https://m.blog.naver.com/hello3311/220159169605)\n\n### DHCP 클라이언트 입장에서\n\n클라이언트들은 시스템이 시작하면 DHCP서버에 자신의 시스템을 위한 IP 주소를 요청하고, DHCP 서버로부터 IP 주소를 부여받으면 TCP/IP 설정이 초기화되고 다른 호스트와 TCP/IP를 사용해서 통신을 할 수 있게 된다.\n\n### DHCP 임대 절차\n\nIP 주소 임대(Lease) 절차에 사용되는 DHCP 메시지는 아래 그림과 같이 **4개의 메시지**로 구성되어 있다.\n\n![DHCP 임대 절차](https://user-images.githubusercontent.com/24274424/88188463-da5baa80-cc72-11ea-9153-bcdf62c111e5.png)\n\n**1. DHCP Discover**\n\n- 패킷 방향 : 클라이언트 -> DHCP 서버\n- 브로드캐스트 패킷 : Destination MAC = `FF:FF:FF:FF:FF:FF`\n- 의미 : **클라이언트가 DHCP 서버를 찾기 위한 메시지**. LAN상에(동일 subnet상에) 브로드캐스팅을 하여 \"DHCP 서버 있으면 내게 응답 좀 해 주세요\"라고 단말이 메세지를 보낸다. 이 Discover 패킷에는 IP 주소가 필요한 호스트의 MAC 주소가 담겨져 있어서 DHCP 서버가 응답할 때 패킷을 수신할 수 있게 된다.\n- 주요 파라미터(패킷 내용)\n    - Client MAC : 클라이언트의 MAC 주소\n\n**2. DHCP Offer**\n\n- 패킷 방향 : DHCP 서버 -> 클라이언트\n- 브로드캐스트 메시지 : Destination MAC = `FF:FF:FF:FF:FF:FF` 혹은 `Unicast`.\n\n    이는 클라이언트가 보낸 DHCP Discover 메시지 내의 Broadcast Flag의 값에 따라 달라지는데, 이 Flag=1이면 DHCP 서버는 DHCP Offer 메시지를 Broadcast로, Flag=0이면 Unicast로 보내게 된다.\n\n- 의미 : DHCP 서버가 \"저 여기 있어요\"라고 응답하는 메시지이다. 단순히 DHCP 서버의 존재만을 알리지 않고, 클라이언트에 할당할 IP 주소 정보를 포함한 **다양한 네트워크 정보를** 함께 실어서 클라이언트에 전달한다.\n- 주요 파라미터(패킷 내용) :\n    - Client MAC: 단말의 MAC 주소\n    - Your IP: 단말에 할당(임대)할 IP 주소\n    - Subnet Mask (Option 1)\n    - Router (Option 3): 단말의 Default Gateway IP 주소\n    - DNS (Option 6): DNS 서버 IP 주소\n    - IP Lease Time (Option 51): 단말이 IP 주소(Your IP)를 사용(임대)할 수 있는 기간(시간)\n    - DHCP Server Identifier (Option 54): 본 메시지(DHCP Offer)를 보낸 DHCP 서버의 주소이다. 2개 이상의 DHCP 서버가 DHCP Offer를 보낼 수 있으므로 각 DHCP 서버는 자신의 IP 주소를 본 필드에 넣어서 단말에 보낸다.\n\n> **Unitcast** : 유니캐스트(Unicast) 전송이란 고유 주소로 식별된 하나의 네트워크 목적지에 1:1로 (one-to-one) 트래픽 또는 메시지를 전송하는 방식을 말한다. - 출처 : 위키백과\n\n**3. DHCP Request**\n\n- 패킷 방향 : 클라이언트 -> DHCP 서버\n- 브로드캐스트 메시지 : Destination MAC = `FF:FF:FF:FF:FF:FF`\n- 의미: 단말은 DHCP 서버(들)의 존재를 알았고, DHCP 서버가 단말에 제공할 네트워크 정보(IP 주소, subnet mask, default gateway등)를 알았다. 이제 단말은 DHCP Request 메시지를 통해 하나의 DHCP 서버를 선택하고 **해당 서버에게 \"단말이 사용할 네트워크 정보\"를 요청**한다.\n- 주요 파라미터(패킷 내용) :\n    - Client MAC: 단말의 MAC 주소\n    - Requested IP Address (Option 50): 난 이 IP 주소를 사용하겠다. (DHCP Offer의 Your IP 주소가 여기에 들어감)\n    - DHCP Server Identifier (Option 54): 2대 이상의 DHCP 서버가 DHCP Offer를 보낸 경우, 단말은 이 중에 마음에 드는 DHCP 서버 하나를 고르게 되고, 그 서버의 IP 주소가 여기에 들어감. 즉, DHCP Server Identifier에 명시된 **DHCP** **서버에게** **\"DHCP Request\"** **메시지**를 보내어 단말 IP 주소를 포함한 네트워크 정보를 얻는 것.\n\n**4. DHCP Ack**\n\n- 패킷 방향 : DHCP 서버 -> 클라이언트\n- 브로드캐스트 메시지 : Destination MAC = `FF:FF:FF:FF:FF:FF` 혹은 `Unicast`.\n\n    이는 단말이 보낸 DHCP Request 메시지 내의 Broadcast Flag=1이면 DHCP 서버는 DHCP Ack 메시지를 Broadcast로, Flag=0이면 Unicast로 보내게 된다.\n\n- 의미 : DHCP 절차의 마지막 메시지로, DHCP 서버가 단말에게 \"네트워크 정보\"를 전달해 주는 메시지. 앞서 설명한 DHCP Offer의 '네트워크 정보\"와 동일한 파라미터가 포함된다.\n- 주요 파라미터(패킷 내용) : DHCP Request 패킷의 파라미터와 동일하다.\n\n### 대여 갱신\n\n1. **대여 기간의 1/2(T1)** 이 경과한 후에 클라이언트는 대여한 서버에게 DHCP Request를 전송한다.\n2. 서버는 클라이언트에게 DHCP ACK 또는 DHCP NAK을 전송한다.\n    - 만약 DHCP NAK을 수신하면, 클라이언트는 DHCP Discover을 사용하여 새로운 주소를 획득해야 한다.\n    - **T2(0.875 * lease_duration** 시간 전에 DHCP ACK를 수신하지 못하면 (Rebinding state), DHCP Request를 브로드캐스트한다.\n\n### DHCP의 장단점\n\n#### 장점\n\n1. 비용 절약 : 네트워크를 사용하는 기기만 IP가 할당되어 고정 IP에 비해 IP 절약 효과가 있다.\n2. 효율적인 네트워크 관리 : IP 방식에 비해 사용자 IP망 설계 변경이 자유롭다. 사용자에게 IP를 할당할 경우 네트워크 정보가 바뀌더라도 DHCP 서버에만 네트워크 정보를 변경해주면 반영이 되어 네트워크 정보 변경에 유연하다.\n\n#### 단점\n\n1. 단말은 초기 부팅 시 Broadcast 트래픽(DHCP Discover 메세지)이 발생한다.\n    1. 한 개의 설정 범위에 있는 모든 단말에 전송되므로 네트워크의 성능 저하가 발생할 수 있다.\n2. 기기 전원을 OFF할 경우 Lease Time까지 IP가 다른 단말에 할당되지 못하게 되어 IP 주소 낭비가 발생하게 된다.\n3. IP를 할당해주는 서버에 전적으로 의존한다.\n    1. 서버가 다운되면 IP를 받을 수 없으므로 인터넷을 사용할 수 없게 된다.\n\n## DNS(Domain Name Server)\n\n인터넷에 연결된 모든 네트워크 또는 컴퓨터 서버에도 고유한 주소가 있다. 우리가 자주 방문하는 사이트의 각 IP 주소를 매번 기억하는 것은 사실 불가능한 일에 가깝다. 그래서 우리는 도메인 이름(www.으로 시작하는 주소)을 사용하는데, 사용자가 [https://snyung.com](https://snyung.com) 과 같이 입력한 주소를 `178.128.17.49`와 같은 IP 주소로 변환해주는 일을 바로 DNS가 하는 것이다. 이러한 DNS를 운영하는 서버를 **네임서버(Name Server)** 라고 한다.\n\n### DNS 절차\n\n1. 특정 사이트를 방문하기위해 사용자가 브라우저에 URL을 입력한다.\n2. 브라우저는 DNS에 접속하여 입력한 도메인 이름과 관련된 IP 주소를 요청한다.\n3. 획득한 IP 주소를 사용하여 브라우저는 그 컴퓨터와 통신하고 사용자로부터 요청된 특정 페이지를 요청할 수 있다.\n\n![DNS 절차](https://d1.awsstatic.com/Route53/how-route-53-routes-traffic.8d313c7da075c3c7303aaef32e89b5d0b7885e7c.png)\n\n## One more thing\n\n- 노트북의 DNS를 변경해보기\n- DNS에서 가져온 IP 보기\n- 네트워크 유틸리티 살펴보기\n\n#### Reference\n\n- [https://m.blog.naver.com/PostView.nhn](https://m.blog.naver.com/PostView.nhn?blogId=hai0416&logNo=221578608161&proxyReferer=https:%2F%2Fwww.google.com%2F)\n- [더-편리한-인터넷을-위해-DHCP-DNS-프로토콜](https://velog.io/@hidaehyunlee/%EB%8D%94-%ED%8E%B8%EB%A6%AC%ED%95%9C-%EC%9D%B8%ED%84%B0%EB%84%B7%EC%9D%84-%EC%9C%84%ED%95%B4-DHCP-DNS-%ED%94%84%EB%A1%9C%ED%86%A0%EC%BD%9C)\n"
  },
  {
    "path": "Network/Flow control.md",
    "content": "최근에 네트워크에 관심이 생겨 네트워크에 대해 앞으로 조금씩 정리해볼 예정이다.\n\n# 흐름제어 (Flow control)\n**흐름제어**란 송신 측이 수신 측의 처리 속도보다 더 빨리 데이터를 보내지 못하도록 제어해 주는 것을 의미힌다.\n\n수신 측이 송신 측보다 속도가 빠른 것은 아무 문제가 되지 않지만 송신 측이 수신 측보다 속도가 빠르면 문제가 발생한다.\n\n무슨 문제가 발생할까?\n\n수신 측에서 수신된 데이터를 저장용량(queue)에 저장하고 처리해서 위에 계층으로 서비스를 하게 되는데,\n\n만약에 송신 측에서 보내는 데이터의 속도가 더 빠르다면 제한된 저장용량(queue)를 초과하여 이후에 도착하는 데이터의 손실을 가져올 수 있다.\n\n이것을 `오버플로우(Overflow)`이라고 표현한다. \n\n그렇다면 송신과 수신 측간에 불필요하게 응답과 재전송이 이루어지기 때문에 효율이 떨어진다.\n\n이러한 `오버플로우`가 일어나지 않기 위해 수신 측에서 데이터를 그만 발송하라는 메시지를 송신측에 통보해야 하는 피드백 메커니즘이 필요하다.\n\n이를 `흐름 제어`이라고 한다.\n> 데이터를 수신하는 노드가 전송하는 노드에게 현재 자신의 상태에 대한 정보를 보내주는 것이다.\n\n위 문제를 해결하기 위해서는 두 가지 방법이 있다.\n\n`stop and wait`과 `Sliding-Window` 방식이다.\n\n### stop and wait\n이 방법의 개념은 간단하다.\n\n매번 전송한 패킷에 대해 확인 응답을 받아야만 그다음 패킷을 전송하는 방법이다.\n\n즉, 수신 측에서 오류 없이 데이터가 무사히 도착했다는 메시지인 `ACK`를 보낸다. \n송신 측에서 이러한 메시지인 `ACK`를 받으면 다음 데이터 블록을 전송한다. \n\n이에 따라 송신 측은 `ACK`의 유무에 따라 다음 데이터 블록을 전송하거나 재전송한다. \n\n1. Timeout을 설정한 후 Frame(data)을 전송하고\n2. 이 시간(Timeout) 동안 수신 노드로부터 `ACK`이 도착하지 않으면 전송에 실패한 것으로 간주하고\n3. 같은 Frame을 다시 전송하는 것이다.\n\n다만, 이 방법은 다음과 같은 문제가 발생한다.\n\n1. Frame이 손실되는 경우\n2. ACK가 손실되는 경우\n3. Timeout 기간이 너무 짧은 경우 --> 수신 노드가 ACK을 보내도 이미 Timeout이 돼버려 송신 노드는 같은 Frame을 재전송\n\n위와 같은 문제로 효율적이지 않지만 가장 큰 문제는 일정 시간 동안 한 개의 Frame밖에 보내지 못한다는 것이다.\n\n그래서 이러한 효율성을 개선하고자 나온 방법이 `Sliding-Window`방식이다.\n\n### Sliding-Window\n이 방법은 수신 측에서 윈도우 사이즈를 설정하여 이 크기만큼 세그먼트를 연속적으로 전송하는 기법이다.\n\n매 세그먼트(Segment) 전송 시마다 `ACK`를 수신한 후 전송하게 되면 RTT가 길 경우 단위 시간당 데이터 전송량이 매우 떨어지게 된다. \n> RTT(Round-Trip Time)은 패킷이 목적지에 도달한 후, 그에 대한 응답이 돌아오기까지의 시간이다. 쉽게 말하자면 패킷의 왕복 시간이다.\n\n따라서 효율적으로 전송하기 위해 수신 측에서 받을 수 있는 범위 내에서 연속적으로 전송한다. \n\n수신 측에서 설정한 윈도우 크기만큼 송신 측에서 `ACK`를 받지 않아도 세그먼트를 전송할 수 있게 하여 데이터 흐름을 동적으로 조절하여 제어하는 기법이다.\n\n이 방식에서는 각 프레임에 순서 번호(Sequence Number)를 부여한다. \n\n이것은 수신 측에서 기대하는 다음 프레임의 순서 번호를 포함하는 `ACK`를 송신 측으로 보내줌으로써 계속 받을 수 있는 프레임들의 번호를 알려준다. \n\n예를 한번 들어보겠다.\n\n먼저, 송신자(A)와 수신자(B)는 각자 버퍼를 준비한다.\n\nA는 자신의 버퍼에 데이터를 쓰고, B는 자신의 버퍼에서 데이터를 읽어오는 것이다. \n\n1. A가 B에게 100,000 byte의 파일을 전송하겠다!\n2. 그러면 TCP가 이 파일을 100개의 패킷으로 나눈다(가정)\n3. A와 B 사이에 연결이 된다.\n4. B가 자신의 Receive Window Size를 A에게 알려준다.\n5. A는 이 Size에 맞추어 B에게 데이터를 전송한다.\n\n![flow_control](https://user-images.githubusercontent.com/43868540/93662932-ced40680-fa9e-11ea-9d11-b0e0dce8bf14.png)\n\n사진을 보면서 이해해보자.\n\n송신자 A의 버퍼 상황이다.\n\nA는 각 패킷에 번호를 매기고 패킷마다 Time을 건 다음 B에게 패킷을 전송한다.\n\n위와 같은 상황에서 B가 3번 패킷을 받았다는 ack을 보내면 A는 8번 패킷을 전송한다.\n\n이것처럼 윈도우에 포함되는 모든 패킷을 전송하고 패킷들의 전달이 확인되는 대로 윈도우를 옆으로 옮김(Slide)으로서 다음 패킷을 전송한다. \n\n1. 만약 B가 자신의 `RWS`가 3,000 bytes라고 하면 A는 `30`개의 패킷을 전송한다.(window = 30)\n2. 송신 측에서 `Seq #`를 부여하여 `window`사이즈인 `30`만큼 수신 측으로 전송한다.\n3. 수신 측은 `Seq #1`을 받으면 `Ack #31`을 보낸다. \n4. 송신 측은 `Ack #31`을 받으면 한 칸씩 `window`를 옮겨 `Seq #31`을 수신 측에게 전송한다.\n> 즉 `ack #`와 다음 패킷을 보낼 `seq #`가 같다.\n5. 만약 Time 안에 각 패킷에 대한 `ack #`이 오지 않으면 `ack #`을 받지 못한 패킷에 대해 재전송을 한다.\n따라서 A는 자신이 전송한 가장 마지막 순서 패킷의 번호와 가장 최근에 받은 ack의 번호를 기억해야한다.\n\n> 위 그림의 경우 2번은 A가 가장 최근에 받은 ACK 패킷의 번호이고,\n7번은 A가 전송한 패킷 중 가장 마지막 순서 패킷의 번호이다.\n\n이것을 왜 기억해야 하는가?\n\n만약에 `seq #2`를 보냈으나 `ack #32`가 오지 않은 상황이다.\n\n그렇다면 `seq #1` 과 `ack #31`까지는 잘 전송되었다는 의미이기도 하다.\n\n송신 측에서 `Seq #2`를 다시 전송하기 위해 `seq #1` 과 `ack #31`을 기억해야 '여기까지 잘 왔구나' 생각하여 다음 패킷을 보낼 수 있다.\n\n이 [동영상](https://www.youtube.com/watch?v=LnbvhoxHn8M)을 참고하면 이해에 도움이 될 것이다. (4분부터 시청 권장)\n\nB의 데이터를 읽는 속도가 떨어질 경우, WS(Window Size)를 줄여가며 송신자의 데이터 전송을 컨트롤할 수 있다.\n\n또한 수신 쪽의 확인(응답)을 받지 않고도 윈도우 크기만큼 데이터를 보내는 것이 가능하므로 `stop-and-wait`보다 네트워크를 효율적으로 사용할 수 있다.\n\n이번 시간에는 `호스트`와 `호스트` 간의 데이터 처리를 효율적으로 하는 `Flow Control`에 대해 알아봤다면\n\n다음 시간에는 `호스트`와 `네트워크` 상의 데이터 처리를 효율적으로 하는 `Congestion control`에 대해 알아볼 것이다.\n\n----\n#### Referece\n- [Flow control](https://velog.io/@directorhwan59/TCP-IP-흐름제어-flow-control)\n- [Sliding window](https://m.blog.naver.com/gaegurijump/110188012832)\n"
  },
  {
    "path": "Network/HTTP3.md",
    "content": "# HTTP3\n\n### 네트워크 관련 글 보기\n\n1. [네트워크 기초 - IP](https://github.com/im-d-team/Dev-Docs/blob/master/Network/IP.md)\n2. [네트워크 기초 - SubnetMask](https://github.com/im-d-team/Dev-Docs/blob/master/Network/Subnetmask.md)\n3. [네트워크 기초 - Types of IP](https://github.com/im-d-team/Dev-Docs/blob/master/Network/TypesOfIP.md)\n4. [네트워크 기초 - OSI 7 계층과 TCP/IP 계층](https://github.com/im-d-team/Dev-Docs/blob/master/Network/OSI7%20Layer.md)\n5. [네트워크 기초 - TCP & UDP](https://github.com/im-d-team/Dev-Docs/blob/master/Network/OTCP%20%26%20UDP.md)\n6. [네트워크 기초 - DHCP & DNS](https://github.com/im-d-team/Dev-Docs/blob/master/Network/DHCP&DNS.md)\n\n## 도입\n\n> 이 글은 HTTP에 대한 지식이 있다는 전제하에 진행되는 글입니다.\n> HTTP에 대한 내용은 [링크](https://github.com/im-d-team/Dev-Docs/blob/master/Network/HTTP%20vs%20WebSocket.md)를 참고하세요.\n\nHTTP/3는 HTTP(Hypertext Transfer Protocol)의 세 번째 Major 버전으로, 기존의 HTTP/1, HTTP/2와는 다르게 UDP 기반의 프로토콜인 QUIC을 사용하여 통신하는 프로토콜이다.\n\n## HTTP/1.1\n\n![3 way handshake + TLS](https://user-images.githubusercontent.com/24274424/89713585-9fc47280-d9d3-11ea-9b7d-092bb435fb05.png)\n\nHTTP 명세서의 HTTP/1.1 개정판은 'keep-alive' 연결의 개념을 도입한 것으로 이전에 요청을 보내기 전 TCP와 TLS Handshake가 완료되어야 하는 문제를 해결하려 했다. 클라이언트가 TCP 연결을 재사용하는 것을 허용하여 복수의 요청에서 발생할 수 있는 초기 연결 확립과 [슬로우 스타트](http://ktword.co.kr/abbr_view.php?m_temp1=3391)에 드는 비용을 줄여준다. \n\n복수의 요청이 같은 연결을 공유할 수 있으나, 하나씩 순서대로 보내야 하므로 각 연결에서는 한 번에 하나의 요청 또는 응답 교환만을 처리할 수 있다.\n\n웹이 진화하면서, 각 웹 사이트에서 필요한 자원(CSS, 자바스크립트, 이미지 등등)의 양이 갈수록 증가함에 따라 웹 페이지를 다운로드받고 렌더링하기 위해 브라우저는 더 많은 동시성을 필요하게 되었다. 하지만 HTTP/1.1에서는 클라이언트가 한 번에 하나의 HTTP 응답/요청만을 해야 하므로, 네트워크 계층에서 동시성을 높일 수 있는 유일한 방법은 동일 오리진에 대해 복수의 TCP 연결을 병렬로 만드는 것인데, 이 경우 'keep-alive' 연결의 장점이 사라지게 된다. 일정 수준(하지만 낮은 쪽)으로 연결은 재사용 되지만, 다시 처음 문제로 돌아가게 되는 것이다.\n\n## HTTP/2\n\nHTTP/2가 발표되고 여러 가지 개선되었으나, 그중 HTTP `Stream`의 개념이 가장 눈에 띈다. HTTP 구현이 동일한 TCP 연결에 복수의 HTTP 응답/요청 교환을 동시 다중 송신할 수 있도록 하여, 브라우저가 TCP 연결을 더 효율적으로 재사용할 수 있도록 한 것이다.\n\nHTTP/2는 복수의 요청/응답이 동시에 같은 연결 위에서 전송될 수 있도록 하여 단일 TCP 연결의 사용 비효율성이라는 최초의 문제를 해결하였다.\n\n**하지만 모든 응답과 요청은 패킷 손실에 대해서 하나의 요청에만 관계된 것이라도 동등하게 영향을 받는다.** HTTP/2 계층이 서로 다른 HTTP 응답/요청 교환을 별개의 스트림으로 분리하였지만, TCP는 그러한 추상화에 대해 알지 못하고 바이트로만 보기 때문이다.\n\nTCP의 역할은 전체 데이터를 순서대로 한 곳에서 다른 곳으로 전달하는 것이다. 데이터 일부를 담고 있는 TCP 패킷이 네트워크 경로상에서 손실되면 데이터 스트림에 누락 구간이 생기고 TCP는 손실이 탐지되었을 때 영향받은 패킷만을 재전송한다. \n\n그러는 동안 분실과 관계없는 완전히 독립된 HTTP 요청에 속하는 경우, 분실된 데이터 이후에 성공적으로 받은 데이터는 어플리케이션으로 전달되지 못한다. TCP는 잃어버린 데이터 없이 어플리케이션이 진행 가능한지 알지 못하므로 불필요한 지연이 발생하게 된다. 이는 **HoLB(head-of-line blocking)** 이라고 알려진 문제이다.\n\n## HTTP/3\n\n![QUIC](https://user-images.githubusercontent.com/24274424/89713563-79063c00-d9d3-11ea-92db-1b82f6d1bf72.png)\n\nHTTP/3은 여러 특징 중 전송 계층에 스트림을 기본 구조로 도입한 **QUIC(Quick UDP Internet Connection)** 을 사용한다. QUIC 스트림은 동일 QUIC 연결을 공유하므로 새 스트림을 만들 때 추가적인 Handshake나 [슬로우 스타트](http://ktword.co.kr/abbr_view.php?m_temp1=3391)가 필요하지 않다. QUIC 스트림은 독립적으로 전달되어 어떤 스트림에 패킷 손실이 있는 경우에도 다른 스트림에는 영향이 없다. 이는 QUIC 패킷이 UDP 데이터그램 위에 캡슐화되어 있기 때문이다.\n\nUDP를 사용하는 것은 TCP보다 더 유연하며 QUIC 구현을 완전히 사용자 수준 구현으로 할 수 있게 한다. 프로토콜의 구현 업데이트는 TCP의 경우처럼 운영체제 업데이트에 묶여있지 않다.\n\nQUIC은 TCP의 전형적인 3 Way Handshake와 TLS 1.3의 Handshake를 결합했다. 이런 결합은 암호화와 인증이 기본으로 제공되고 연결을 더 빨리 만들 수 있게 한다. 즉 HTTP의 첫 요청에 필요한 QUIC 연결을 새로 만들 때에도 데이터 전송 시작까지 걸리는 지연 시간은 TCP상의 TLS보다 작다\n\n## HTTP/3가 UDP를 사용하는 이유\n\nHTTP/3는 QUIC을 기반으로 돌아가는 프로토콜이기 때문에 우리가 HTTP/3를 이해하려면 QUIC에 초점을 맞춰야 한다. QUIC은 TCP의 문제들을 해결하고 레이턴시(latency)의 한계를 뛰어넘고자 구글이 개발한 UDP 기반의 프로토콜이다.\n\nQUIC은 처음부터 TCP의 Handshake 과정을 최적화하는 것에 초점을 맞추어 설계되었고, UDP를 사용함으로써 이를 실현해냈다.\n\n### TCP Header\n\n![TCP Header](https://user-images.githubusercontent.com/24274424/89713594-a9e67100-d9d3-11ea-928e-746f4edc6e81.png)\n\nTCP의 경우 워낙 오래전에 설계되기도 했고, 여러 기능이 많이 포함된 프로토콜이다 보니 이미 헤더가 거의 꽉 찼다. TCP에 기본적으로 정의된 기능 외에 다른 추가 기능을 구현하고 싶다면 가장 하단에 있는 옵션(Options) 필드를 사용해야 하는데, 옵션 필드도 무한정 배당해 줄 수는 없으니 최대 크기를 `320 bits`로 정해놓았다.\n\n그러나 TCP의 단점을 보완하기 위해 나중에 정의된 MSS(Maximum Segment Size), WSCALE(Window Scale factor), SACK(Selective ACK) 등 많은 옵션들이 이미 옵션 필드를 차지하고 있기 때문에 실질적으로 사용자가 커스텀 기능을 구현할 수 있는 자리는 거의 남지도 않았다.\n\n### UDP Header\n\n![UDP Header](https://user-images.githubusercontent.com/24274424/89713599-b2d74280-d9d3-11ea-817b-804cdd55cdd1.png)\n\nUDP의 헤더에는 출발지와 도착지, 패킷의 길이, 체크섬밖에 없다. 이때 체크섬은 패킷의 무결성을 확인하기 위해 사용되는데, TCP의 체크섬과는 다르게 UDP의 체크섬은 사용해도 되고 안 해도 되는 옵션이다.\n\n즉, UDP 프로토콜 자체는 TCP보다 신뢰성이 낮기도 하고 흐름 제어도 안되지만, 이후 개발자가 어플리케이션에서 구현을 어떻게 하냐에 따라서 TCP와 비슷한 수준의 기능을 가질 수도 있다.\n\n물론 TCP가 신뢰성을 확보하기 위해 여러 기능을 제공해주는 것이 개발자 입장에서는 편하고 좋지만, 한 가지 슬픈 점은 이 기능들이 프로토콜 자체에 정의된 필수 과정이라서 개발자가 커스터마이징 할 수 없다는 것이다. 결국 여기서 발생하는 레이턴시들을 어떻게 더 줄여볼 시도조차 하기 힘들다.\n\n### QUIC\n\nUDP는 `User Datagram Protocol`이라는 이름에서도 알 수 있듯이 데이터그램 방식을 사용하는 프로토콜이기 때문에 애초에 각각의 패킷 간의 순서가 존재하지 않는 독립적인 패킷을 사용한다. 또한 데이터그램 방식은 패킷의 목적지만 정해져있다면 중간 경로는 어딜 타든 신경쓰지 않기 때문에 종단 간의 연결 설정을 하지 않는다. 즉, Handshake 과정이 필요없다는 것이다.\n\n결론적으로 UDP는 TCP가 신뢰성을 확보하기 위해 거치던 많은 과정을 거치지 않기 때문에 속도가 더 빠를 수 밖에 없다는 것인데, 그렇다면 UDP를 사용하게되면 기존의 TCP가 가지던 신뢰성과 패킷의 무결함도 함께 사라지는 걸까?\n\nUDP를 사용하더라도 기존의 TCP가 가지고 있던 기능을 전부 구현할 수 있다. UDP의 진짜 장점은 **바로 커스터마이징이 용이하다는 것이기 때문이다.**\n\n## HTTP/3가 UDP를 사용함으로써 기존 프로토콜보다 나아진 점\n\n지금까지 HTTP/3의 뼈대로 사용되는 QUIC이 왜 TCP가 아닌 UDP를 사용했는지 간략하게 알아보았다. 그렇다면 실제로 UDP를 사용함으로써 얻는 이득에는 무엇이 있을까? 진짜로 HTTP/3는 UDP를 사용함으로써 기존의 HTTP+TCP+TLS를 사용했던 방법보다 더 좋아진 것일까?\n\n### 연결 설정 시 지연시간 감소\n\nQUIC은 TCP를 사용하지 않기 때문에 통신을 시작할 때 번거로운 **3 Way Handshake** 과정을 거치지 않아도 된다. 클라이언트가 보낸 요청을 서버가 처리한 후 다시 클라이언트로 응답해주는 사이클을 RTT(Round Trip Time)이라고 하는데, TCP는 연결을 생성하기 위해 기본적으로 1 RTT가 필요하고, 여기에 TLS를 사용한 암호화까지 하려고 한다면 TLS의 자체 Handshake까지 더해져 총 3 RTT가 필요하다.\n\n반면 QUIC은 첫 연결 설정에 1 RTT만 소요된다. 클라이언트가 서버에 어떤 신호를 한번 주고, 서버도 거기에 응답하기만 하면 바로 본 통신을 시작할 수 있다는 것이다. 즉, 연결 설정에 드는 시간이 반 정도밖에 안 된다.\n\n어떻게 이게 가능한 걸까? 첫번째 Handshake를 거칠 때, 연결 설정에 필요한 정보와 함께 데이터도 보내버리는 것이다. TCP+TLS는 데이터를 보내기 전에 신뢰성 있는 연결과 암호화에 필요한 모든 정보를 교환하고 유효성을 검사한 뒤에 데이터를 교환하지만, QUIC은 묻지도 따지지도 않고 그냥 바로 데이터부터 보내기 시작한다.\n\n결국 말하고자 하는 것은 TCP+TLS는 서로 자신의 세션 키를 주고받아 암호화된 연결을 성립하는 과정을 거치고 나서야 세션 키와 함께 데이터를 교환할 수 있지만, QUIC은 서로의 세션 키를 교환하기도 전에 데이터를 교환할 수 있기 때문에 연결설정이 더 빠르다는 것이다.\n\n단, 클라이언트가 서버로 첫 요청을 보낼 때는 서버의 세션 키를 모르는 상태이기 때문에 목적지인 서버의 Connection ID를 사용하여 생성한 특별한 키인 초기화 키(Initial Key)를 사용하여 통신을 암호화한다.\n\n그리고 한번 연결에 성공했다면 서버는 그 설정을 캐싱해놓고 있다가, 다음 연결 때는 캐싱해놓은 설정을 사용하여 바로 연결을 성립시키기 때문에 0 RTT만으로 바로 통신을 시작할 수도 있다. 이런 점들 때문에 QUIC은 기존의 TCP+TLS 방식보다 레이턴시를 더 줄일 수 있다.\n\nTCP SYN 패킷은 한 패킷당 약 `1460 Byte`만 전송할 수 있도록 제한하지만 QUIC은 데이터 전체를 첫 번째 라운드 트립에 포함해서 전송할 수 있기 때문에 주고받아야 할 데이터가 큰 경우에는 여전히 QUIC가 유리하다고 할 수 있다.\n\n### 패킷 손실 감지에 걸리는 시간 단축\n\nQUIC도 TCP와 마찬가지로 전송하는 패킷에 대한 흐름 제어를 해야 한다. 왜냐하면 QUIC, TCP 모두 결국 본질적으로는 ARQ 방식을 사용하는 프로토콜이기 때문이다. 통신 과정에서 발생한 에러를 어떻게 처리할 것인지를 이야기하는 것인데, ARQ 방식은 에러가 발생하면 재전송을 통해 에러를 복구하는 방식을 말한다.\n\nTCP는 여러 ARQ 방식 중에서 `Stop and Wait ARQ` 방식을 사용하고 있다. 이 방식은 송신 측이 패킷을 보낸 후 타이머를 사용하여 시간을 재고, 일정 시간이 경과해도 수신 측이 적절한 답변을 주지 않는다면 패킷이 손실된 것으로 판단하고 해당 패킷을 다시 보내는 방식이다.\n\nTCP에서 패킷 손실 감지에 대한 대표적인 문제는 송신 측이 패킷을 수신 측으로 보내고 난 후 얼마나 기다려줄 것인가, 즉 타임아웃을 언제 낼 것인가를 동적으로 계산해야한다는 것이다. 이때 이 시간을 RTO(Retransmission Time Out)라고 하는데, 이때 필요한 데이터가 바로 RTT(Round Trip Time)들의 샘플들이다.\n\n한번 패킷을 보낸 후 잘 받았다는 응답을 받을 때 걸렸던 시간들을 측정해서 동적으로 타임 아웃을 정하는 것이다. 즉, RTT 샘플을 측정하기 위해서는 반드시 송신 측으로 부터 ACK를 받아야하는데, 정상적인 상황에서는 딱히 문제가 없으나 타임 아웃이 발생해서 패킷 손실이 발생하게 되면 RTT 계산이 애매해진다.\n\n이때 이 ACK가 어느 패킷에 대한 응답인지 알기 위해서는 타임 스탬프를 패킷에 찍어주는 등 별도의 방법을 또 사용해야 하고, 또 이를 위한 패킷 검사도 따로 해줘야 한다. 이를 재전송 모호성(Retransmission Ambiguity)이라고 한다.\n\n이 문제를 해결하기 위해 **QUIC는 헤더에 별도의 패킷 번호 공간을 부여했다.** 이 패킷 번호는 패킷의 전송 순서 자체만을 나타내며, 재전송 시 같은 번호가 전송되는 시퀀스 번호와는 다르게 전송마다 모노토닉하게 패킷 번호가 증가하기 때문에, 패킷의 전송 순서를 명확하게 파악할 수 있다.\n\nTCP의 경우 타임스탬프를 통해 패킷의 전송 순서를 파악하거나 타임스탬프를 사용할 수 없는 상황이라면 시퀀스 번호에 기반하여 암묵적으로 전송 순서를 추론했다. 이에 반해 QUIC는 패킷마다 고유한 패킷 번호를 이용함으로써 앞서 봤던 불필요한 과정을 생략하고 패킷 손실 감지에 걸리는 시간을 단축할 수 있다.\n\n이 외에도 QUIC는 대략 5가지 정도의 기법을 사용하여 이 패킷 손실 감지에 걸리는 시간을 단축했는데, 자세한 내용은 QUIC Loss Detection and Congestion Control의 [2.1 Relevant Differences Between QUIC and TCP](http://www.watersprings.org/pub/id/draft-ietf-quic-recovery-02.html#rfc.section.2.1) 챕터를 한번 읽어보는 것을 추천한다.\n\n### 멀티플렉싱을 지원\n\n멀티플렉싱(Multiplexing)은 위에서 TCP의 단점으로 언급했던 HOLB(Head of Line Blocking)을 방지하기 때문에 매우 중요하다. 여러 개의 스트림을 사용하면, 그중 특정 스트림의 패킷이 손실되었다고 하더라도 해당 스트림에만 영향을 미치고 나머지 스트림은 사용할 수 있기 때문이다.\n\n참고로 멀티플렉싱은 여러 개의 TCP 연결을 만든다는 의미가 아니라, 단일 연결 안에서 여러 개의 데이터를 섞이지 않게 보내는 기법이다. 이때 각각의 데이터의 흐름을 스트림이라고 하는 것이다.\n\nHTTP/1의 경우는 하나의 TCP 연결에 하나의 스트림만 사용하기 때문에 HOLB 문제에서 벗어날 수 없었다. 또한 한 번의 전송이 끝나게 되면 연결이 끊어지기 때문에 다시 연결을 만들기 위해서는 번거로운 Handshake 과정을 또 겪어야 했다.\n\n비록 keep-alive 옵션을 통해 어느 정도의 시간 동안 연결을 유지할 수는 있지만 결국 일정 시간 안에 액세스가 없다면 연결이 끊어지게 되는 것은 똑같다.\n\n그리고 HTTP/2는 하나의 TCP 연결 안에서 여러 개의 스트림을 처리하는 멀티플렉싱 기법을 도입하여 성능을 끌어올린 케이스이다. 이 경우 한번의 TCP 연결로 여러 개의 데이터를 전송할 수 있기 때문에 Handshake 횟수도 줄어들게 되어 효율적인 데이터 전송을 할 수 있게 된다.\n\nHTTP/3도 HTTP/2와 같은 멀티플렉싱을 지원한다.\n\nQUIC 또한 HTTP/2와 동일하게 멀티플렉싱을 지원하기 때문에, 이런 이점을 그대로 가져가고 있다. 혹여나 하나의 스트림에서 문제가 발생한다고 해도 다른 스트림은 지킬 수 있게 되어 이런 문제에서 벗어날 수 있다.\n\n### 클라이언트의 IP가 바뀌어도 연결이 유지\n\nTCP의 경우 소스의 IP 주소와 포트, 연결 대상의 IP 주소와 포트로 연결을 식별하기 때문에 클라이언트의 IP가 바뀌는 상황이 발생하면 연결이 끊어져 버린다. 연결이 끊어졌으니 다시 연결을 생성하기 위해 결국 3 Way Handshake 과정을 다시 거쳐야 한다는 것이고, 이 과정에서 다시 레이턴시가 발생한다.\n\n요즘에는 모바일로 인터넷을 사용하는 경우가 많아서 Wi-Fi에서 셀룰러로 전환되거나 그 반대의 경우, 혹은 다른 Wi-Fi로 연결되는 경우와 같이 클라이언트의 IP가 변경되는 일이 굉장히 잦다.\n\n반면 QUIC은 Connection ID를 사용하여 서버와 연결을 생성한다. Connection ID는 랜덤한 값일 뿐, 클라이언트의 IP와는 전혀 무관한 데이터이기 때문에 클라이언트의 IP가 변경되더라도 기존의 연결을 계속 유지할 수 있다. 이는 새로 연결을 생성할 때 거쳐야하는 Handshake 과정을 생략할 수 있다.\n\n#### Reference \n\n- [HTTP/3: 과거, 현재 그리고 미래](https://blog.cloudflare.com/ko/http3-the-past-present-and-future-ko/)\n- [HTTP/3는 왜 UDP를 선택한 것일까? | Evan's Tech Blog](https://evan-moon.github.io/2019/10/08/what-is-http3/)"
  },
  {
    "path": "Network/IP.md",
    "content": "# 네트워크 기초 - IP\n\n## 네트워크란\n\n두 대 이상의 컴퓨터가 논리적 또는 물리적으로 연결되어 통신이 가능한 상태를 말한다.\n일반적으로 규모에 따른 네트워크 종류는 아래와 같다.\n\n1. PAN (Personal Area, Network) : 가장 작은 규모의 네트워크.\n2. LAN (Local Area Network) : 근거리 영역 네트워크, 근거리 통신망을 의미하며 지역적 좁은 범위 내에서 고속 통신이 가능한 통신망.\n3. MAN (Metropolitan Area Network) : 대도시 영역 네트워크.\n4. WAN (Wide Area Network) : 광대역 네트워크, Wide Area Network 광대역 통신망으로 LAN보다 넓은 지역을 나타내며 지역과 지역, 지방과 지방, 나라와 나라 또는 대륙과 대륙을 연결하는 통신망.\n\n![WAN, LAN](https://user-images.githubusercontent.com/24274424/83945517-17481b00-a846-11ea-8848-d351a8b0dbed.png)\n\n> [출처 : Computer Science Bea](https://sites.google.com/site/computersciencebea/networks/types-of-networks/network-cabling-speeds/networks-protocols/mac-addresses/network-topologies/the-internet/the-www/wan-lan-pan)\n\n## IP(Internet Protocol)주소란?\n\n먼저 IP 주소라는 말에서 IP를 먼저 알아보자. 위키의 내용을 살펴보면, 아래와 같다.\n\n> 인터넷 프로토콜(IP, Internet Protocol)은 송신 호스트와 수신 호스트가 **패킷 교환 네트워크**(패킷 스위칭 네트워크, Packet Switching Network)에서 정보를 주고받는 데 사용하는 정보 위주의 **규약**(프로토콜, Protocol)이며, OSI 네트워크 계층에서 호스트의 주소지정과 패킷 분할 및 조립 기능을 담당한다. \n\n이에 IP 주소는 네트워킹이 가능한 장비를 식별하는 주소이다. 네트워크상에서 통신을 하기 위해서는 몇 가지 통신규약(Protocol)을 따라야 하는데, 그런 조약 중에는 \"네트워킹을 하는 장비들에 숫자 12개의 고유한 주소를 주어 그 주소를 통해 서로를 인식하고 통신하도록 하자\"라는 의미의 규약이 존재한다.\n\n**하나의 네트워크 안에서 IP들은 네트워크 영역은 같아야 하고, 호스트 IP는 서로 달라야 통신이 가능하다.**\n\n### IPv4 주소\n\nIP version 4의 줄임말이다. IPv4 주소는 오늘날 일반적으로 사용하는 IP 주소이다. 이 주소의 범위는 32bit로 보통 0~255 사이의 10진수 4개를 사용하며 `.`으로 구분하여 나타낸다. 0.0.0.0부터 255.255.255.255까지가 된다. 이론적으로 42억 9,496만7,296개의 IP가 존재한다. 중간의 일부 번호들은 특별한 용도를 위해 예약되어 있다. 예를 들어 127.0.0.1은 localhost(로컬 호스트)로 자기 자신을 가리킨다.\n\n### 예약된 IP 주소\n\n많은 IP 중 특수한 용도로 사용하기 위해서 따로 지정이 되어있는 IP 주소를 예약된 IP 주소라 한다. 이에 해당하는 주소들은 아래와 같다.\n\n- 127.0.0.1 - 루프백(Loopback) 주소, 자기 자신을 가리키는 주소이다.\n- 192.168.0.0 - 사설 네트워크\n- 224.0.0.0 - 멀티캐스트\n- 240.0.0.0 - 미래의 사용될 것을 생각하여 예약된 주소이다.\n\n#### One more thing...\n\n![IPv4](https://user-images.githubusercontent.com/24274424/83947941-24203b00-a855-11ea-9941-f8ba30808376.png)\n\n> [출처 : IT 동아](http://it.donga.com/21854/)\n\nIPv4에서 점으로 각각의 숫자를 구분하고 있는데 각각의 마디를 **옥텟**이다고 한다.\n\n\n### IPv6 주소\n\nIP address가 처음 생겼을 당시에는 지금처럼 네트워킹이 가능한 장비의 종류가 다양하지 않았으나, 기술이 발전하고 한 사람이 가지는 네트워킹이 가능한 단말기의 수가 1개 이상이 되어버리자 IPv4 주소의 수가 부족해졌다. 그래서 등장한 것이 IPv6이다. 이러한 주소 방법은 약 43억x43억x43억x43억개... 를 만들어 낼 수 있으며,  IPv6 주소는 보통 두 자리 16진수 여덟 개를 쓰고 각각을 `:` 기호로 구분한다.\n\n## IP 주소의 클래스(A, B, C class)란?\n\nIP 주소에는 클래스라는 개념이 있다. 클래스의 개념을 알아야 어디까지가 네트워크 영역이고 호스트 영역인지 알 수 있다. 즉, 클래스는 하나의 IP주소에서 네트워크 영역과 호스트 영역을 나누는 방법이자, 약속이다. IP 주소를 3개의 클래스로 나누는 기준은 **네트워크 크기에 따른 구분**이라 생각하면 된다.\n\n> **하나의 네트워크 안에서 IP들은 네트워크 영역은 같아야 하고, 호스트 IP는 서로 달라야 통신이 가능하다.**\n\n하나의 네트워크에서 몇 개의 호스트 IP까지 가질 수 있는가에 따라서 클래스를 나눌 수 있다. 즉, 네트워크 범위가 커질수록 호스트 주소 범위는 작아지는 반비례 관계이다.\n\nIP 주소 클래스는 총 5개가 있다(A, B, C, D, E). 하지만 보통 A, B, C 3개 정도만 알고 있으면 충분하다. (나머지 D, E 클래스는 멀티캐스트용, 연구용으로 사용한다)\n\n예를 들어 `203.240.100.1`에서 `203.240.100`은 네트워크 영역이고 `1`은 호스트 영역이다. \n\n![IP 클래스](https://user-images.githubusercontent.com/24274424/83946405-93912d00-a84b-11ea-89c3-584763a6ff7a.png)\n\n> 출처 한국인터넷정보센터\n\nD Class 네트워크는 멀티캐스트를 위해서 존재하는 네트워크라고 했는데, 여기서 멀티캐스트라는 것은 한 번의 메시지 송신으로 특정 네트워크 안에 있는 두 개 이상의 컴퓨터에 전송할 수 있도록 하는 기술이다.\n\n### A 클래스\n\n먼저 A 클래스는 하나의 네트워크가 가질 수 있는 호스트 주소가 제일 많은 클래스이다. IP 주소를 32자리 2진수로 표현했을 때, 맨 앞자리 수가 항상 0인 경우 바로 A 클래스이다. 즉 `0xxx xxxx. xxxx xxxx. xxxx xxxx. xxxx xxxx`와 같이 되어있다. `x`는 0 또는 1이다. 이 범위를 10진수로 표현하면 `0.0.0.0` ~ `127.255.255.255` 이다.\n\n그런데 A 클래스에서 네트워트 주소는 `1.0.0.0` ~ `126.0.0.0` 까지로 규정되어 있다. 그래서 IP주소 중 맨 앞자리 수가 1부터 126으로 시작하는 네트워크는 A 클래스라고 생각하면 된다.\n\n그리고 호스트 주소가 가질 수 있는 갯수는 `(2^24) - 2`개 이다. \n\n**-2 이유는 모두가 1인경우 브로드캐스트 주소로 사용하고 모두 0인 경우엔 네트워크 주소로 사용하기 때문이다.**\n\n> 브로드캐스트 주소 : 네트워크 망에서 할당할 수 있는 IP 주소 중 가장 큰 값\n\n예를 들어 A클래스로 `15.0.0.0` 네트워크 주소를 할당 받았을 때, 가능한 호스트 IP를 10진수로 나타내면 `15.0.0.0` ~ `15.255.255.255` 이다. 하지만 여기서 `15.0.0.0`은 네트워크 주소를 표현하기 위해서 호스트 주소로 사용하면 안된다. 또, `15.255.255.255` 역시 브로드캐스트 주소로 사용하기 때문에 호스트 IP로 사용하면 안된다. 따라서 `(2^24) - 2`를 해준다.\n\n### B 클래스\n\nB 클래스의 IP주소를 32자리 2진수로 표현했을때, 맨 앞자리 수는 항상 `10`이여야 한다. 즉 `10xx xxxx. xxxx xxxx. xxxx xxxx. xxxx xxxx` 이 범위를 10진수로 표현하면 `128.0.0.0` ~ `191.255.255.255` 이다.\n\n네트워크 주소 범위는 `10xx xxxx. xxxx xxxx` 에서 x들이 가질 수 있는 경우의 수, `2^14` 개 이고, 호스트 주소 범위는 `xxxx xxxx. xxxx xxxx`에서 x들의 경우의 수인 `(2^16) - 2`개 이다.\n\n### C 클래스\n\nC 클래스의 IP주소는 2진수로 표현했을 때 반드시 `110`으로 시작한다. 즉 `110x xxxx. xxxx xxxx. xxxx xxxx. xxxx xxxx`이다. 이 범위를 10진수로 표현하면 `192.0.0.0` ~ `223.255.255.255`\n\n네트워크 범위는 `110x xxxx. xxxx xxxx. xxxx xxxx`에서 x들이 가질 수 있는 경우의 수, `2^21`개 이고, 호스트 주소 범위는 `xxxx xxxx`에서 x들이 가질 수 있는 경우의 수, `(2^8) - 2` 개 이다.\n\n### 간단한 문제로 확인하기\n\n각각의 클래스, 네트워크 부분, 호스트 부분은?\n\n#### 문제. 10.3.4.3\n\n<details>  \n<summary> 정답 </summary>\n\n- 클래스 : A\n- 네트워크 부분 : 10.0.0.0\n- 호스트 부분 : 3.4.3\n\n</details>\n\n#### 문제2. 132.12.11.4\n\n<details>\n  \n<summary> 정답 </summary>\n\n- 클래스 : B\n- 네트워크 부분 : 132.12.0.0\n- 호스트 부분 : 11.4\n\n</details>\n\n#### 문제3. 203.10.1.1\n\n<details>\n  \n<summary> 정답 </summary>\n\n- 클래스 : C\n- 네트워크 부분 : 203.10.1.0\n- 호스트 부분 : 1\n\n</details>\n\n#### 문제4. 192.12.100.2\n\n<details>\n  \n<summary> 정답 </summary>\n\n- 클래스 : C\n- 네트워크 부분 : 192.12.100.0\n- 호스트 부분 : 2\n\n</details>\n\n#### 문제5. 130.11.4.1\n\n<details>\n  \n<summary> 정답 </summary>\n\n- 클래스 : B\n- 네트워크 부분 : 130.11.0.0\n- 호스트 부분 : 4.1\n\n</details>\n\n#### 문제6. 261.12.4.1\n\n<details>\n  \n<summary> 정답 </summary>\n\n이런 IP 주소는 없음\n\n</details>\n\n\n\n\n---\n\n#### Reference\n\n- [IP address 란?](https://velog.io/@hidaehyunlee/IP-address%EB%9E%80)\n- [[Network]네트워크 클래스(Network Class)](https://hyoje420.tistory.com/31)\n- [[Network] IP주소 클래스(A,B,C class)란?](https://limkydev.tistory.com/168)\n- [IP - 나무위키](https://namu.wiki/w/IP)\n"
  },
  {
    "path": "Network/JSend.md",
    "content": "# JSend\n\nRESTful하게 개발하는 건 2019년 현재 개발 트렌드다.\n\nbackend - frontend를 완전히 구분하고 자원에 대한 API를 REST하게 설계한다. 이 둘은 JSON 형태로 데이터를 주고받는다.\n\nREST와 관련된 자료는 아래 두 자료를 참고하자.\n\n- [Dev-Docs rest](https://github.com/Im-D/Dev-Docs/blob/master/Network/REST.md)\n- [그런 rest api로 괜찮은가](https://www.youtube.com/watch?v=RP_f5dMoHFc)\n\n두번째 자료인 그런 rest api로 괜찮은가를 보면 생각보다 rest api를 구축하기는 상당히 어렵다.\n이를 도와주는 약속 중 하나가 JSend다.\n\n## JSend란?\n\n[JSend](https://github.com/omniti-labs/jsend)는 JSON 응답에 대한 스펙이다. \n\n[JSON](https://ko.wikipedia.org/wiki/JSON) 형식은 더글라스 크락포드가 만든 key-value형식의 데이터 포맷이다. 형식이 매우 자유로운 편이다. 그래서 유연하다.\n\n대신 문제가 있다. 형식이 자유로운 만큼 표준이 없다. 따라서 사이트마다 응답 데이터의 생김새가 모두 다르다.\n모양이 다른 문제는 결국 front-end 개발자가 개발할 때마다 다른 모양에 맞춰야 한다는 점이다.\n\n사이트마다, 팀마다, 사람마다 response의 포맷은 같지만, 형식이 다르다면 엄청 귀찮은 일이 될 것이다.\n\n이를 해결하고자 나온 아주 간단한 JSON 스펙이 JSend다.\n\n## specification\n\n```js\n{\n    status : \"success\",\n    data : [\n      { \"id\" : 1, \"category\" : \"A blog post\", \"body\" : \"Some useful content\" },\n      { \"id\" : 2, \"category\" : \"A Film\", \"body\" : \"parasite\" }\n    ]\n}\n```\n생김새는 위와 같다.\n\n꽤 많은 사이트에서 위와 같은 포맷의 response를 확인할 수 있다.\n\n매우 간단한 스펙이다. status와 data를 나눈다.\n\nstatus의 타입도 간단하게 세 가지다.\n\n| TYPE    | Description                                                                                         | Required Keys   | Optional Keys |\n|---------|-----------------------------------------------------------------------------------------------------|-----------------|---------------|\n| success | All went well, and (usually) some data was returned.                                                | status, data    |               |\n| fail    | There was a problem with the data submitted, or some pre-condition of the API call wasn't satisfied | status, data    |               |\n| error   | An error occurred in processing the request, i.e. an exception was thrown                           | status, message | code, data    |\n\n- success: 성공\n- fail: 데이터에 어떤 문제가 생겼을 때\n- error: 프로세스에서 에러가 발생했을 때\n\n### 참고할만한 사항\n\n- data가 null인 경우에도 success일 수 있다. 조회한 데이터의 결과가 null일 수 있기 때문이다.\n- post values에 문제가 생겼을 경우 data object의 key가 그 post value와 일치해야 한다.\n    ex) title 값이 잘못된 경우 => { \"status\": \"fail\", \"data\" : { \"title\" : \"A title is required\" } }\n- 에러의 message는 end-user-readable해야한다. error code 같은 것은 optional data로 추가되어야지 message에 들어가면 안 된다.\n\n### 사용이유\n\nHTTP의 status가 있다. 그래도 굳이 body에 status를 표기하는 JSend를 사용하는 이유가 있다.\n\nHTTP는 상태 코드가 너무 많다. 41개 이상의 상태 코드가 있다. 200, 404와 같은 코드들 말이다.\n표준이 확실히 있는 것은 좋지만 그만큼 관리하기 어렵다는 문제가 있다.\n\n개발자가 41개의 모든 상태 코드를 다 알고 대응해야 한다. 301과 같은 코드들은 사람이 바로 알 수 없다. human-readable하지 않다.\n\nJSend는 spec이 작고 제한적이다. application-level의 약속이라 protocol에 반하지도 않는다. \n따라서 응용도가 높고 독립적으로 응용이 가능하다.\n\n사용하기 편리하고 가볍고 간단한 표준이다. 따라서 개발단계에서 응답 형식에 얽매이지 않고 바로 개발할 수 있기에 이와 같은 규칙을 사용하면 좋다.\n\n---\n\n#### 참고자료\n\n- [Dev-Docs rest](https://github.com/Im-D/Dev-Docs/blob/master/Network/REST.md)\n- [그런 rest api로 괜찮은가](https://www.youtube.com/watch?v=RP_f5dMoHFc)\n- [JSend](https://github.com/omniti-labs/jsend)\n- [JSend란](https://krksap.tistory.com/1216)"
  },
  {
    "path": "Network/OSI7 Layer.md",
    "content": "# OSI 7 계층과 TCP/IP 계층\n\n### 이전 글 복습하기\n\n[네트워크 기초 - IP](https://github.com/im-d-team/Dev-Docs/blob/master/Network/IP.md)\n[네트워크 기초 - SubnetMask](https://github.com/im-d-team/Dev-Docs/blob/master/Network/Subnetmask.md)\n[네트워크 기초 - Types of IP](https://github.com/im-d-team/Dev-Docs/blob/master/Network/TypesOfIP.md)\n\n- 네트워크 : 두 대 이상의 컴퓨터가 논리적 또는 물리적으로 연결되어 통신이 가능한 상태(PAN, LAN, MAN, WAN).\n- IP 주소 : 네트워킹이 가능한 장비를 식별하는 주소.\n- IPv4, IPv6\n- A, B, C 클래스 : 네트워크 영역과 호스트 영역을 구분한 기준\n  - A : `0.0.0.0` ~ `127.255.255.255`\n  - B : `128.0.0.0` ~ `191.255.255.255`\n  - C : `192.0.0.0` ~ `223.255.255.255`\n- 네트워크 주소 : 호스트 부분이 모두 0인 경우\n- 브로드캐스트 주소 : 호스트 부분이 모두 1인 경우\n- 서브넷마스크 : 네트워크와 호스트 영역을 구분하기 위한 값\n- 서브네팅 : 네트워크 관리자가 네트워크 성능을 향상하기 위해, 자원을 효율적으로 분배하는 것\n- 공인 IP : 인터넷 사용자의 로컬 네트워크를 식별하기 위해서 ISP에서 제공하는 IP 주소. 즉, 외부에 공개된 IP 주소.\n- 사설 IP : 전체 IP 대역 중 특수한 목적으로 사용하는 대역. 아래의 대역이 사설 IP 대역.\n  - A : `10.0.0.0` ~ `10.255.255.255`\n  - B : `172.16.0.0` ~ `172.31.255.255`\n  - C : `192.168.0.0` ~ `192.168.255.255`\n- 고정 IP : 고정적으로 부여된 IP로 한번 부여되면 IP를 반납하기 전까지는 다른 장비에 부여할 수 없는 IP 주소\n- 동적 IP : 장비에 고정적으로 IP를 부여하지 않고 컴퓨터를 사용할 때 남아 있는 IP 중에서 돌아가면서 부여하는 IP 주소.\n\n\n## OSI 7계층\n\nOSI는 `Open Systems Interconnection`의 약자로 개방형 시스템이라는 뜻이다. OSI 7계층은 네트워크에서 통신이 일어나는 과정을 7단계로 나눈 것을 말한다.\n\n## OSI 7계층을 나눈 이유는?\n\n이는 서로 이질적인 네트워크 간의 연결에 어려움이 많아 호환성의 결여를 막기 위한 것으로, ISO(국제 표준화 기구)에서는 OSI 참조모델을 제시했다.\n\n**아무리 그래도 왜 이렇게 많은 계층으로 나누어서 우리를 시험에 들게 하나?**\n\n1. 통신이 일어나는 과정을 단계별로 파악할 수 있다.\n2. 특정한 곳에 이상이 생긴다면 다른 단계의 장비 또는 소프트웨어를 건들이지 않고 이상이 생긴 단계만 고칠 수 있다.\n\n## 왜 계층이라 했을까?\n\n상하구조를 가지기 때문이다. 예를 들어 5계층이 잘 작동하기 위해서는 1 ~ 4계층이 모두 완벽하게 작동되어야 한다는 것이다.\n\n## 각각의 계층에 대해서\n\n![OSI 7](https://user-images.githubusercontent.com/24274424/86514723-94b77900-be4e-11ea-8456-ad39b27d9ba9.png)\n\n> [출처 - OSI 7 계층이란?, OSI 7 계층을 나눈 이유](https://shlee0882.tistory.com/110)\n\n### 1 계층 - 물리 계층(Physical Layer)\n\n물리 계층은 전기적, 기계적, 기능적인 특성을 이용해서 통신 장비로 데이터를 전송하게 된다.\n\n물리 계층에서 사용되는 통신 단위는 Bit로 1과 0으로 나타낸다. 즉 전기적으로 On, Off 상태라고 생각하면 된다.\n\n물리 계층에서는 단지 데이터를 전달만 한다. 전송할 때(또는 받을 때) 데이터가 무엇인지, 어떤 에러가 있는지 등에는 전혀 신경 쓰지 않는다. 정말 단순하게 데이터를 전기적인 신호로 변환해서 주고받는 기능만 할 뿐이다.\n\n결국 물리 계층은 어떤 에러가 있는지 전혀 관여하지 않는다.\n\n- PDU : 비트(Bit)\n- 프로토콜 : Modem, Cable, Fiber, RS-232C\n- 대표장비 : 허브, 리피터\n\n> 프로토콜 데이터 단위(PDU, Protocol Data Unit)는 데이터 통신에서 상위 계층이 전달한 데이터에 붙이는 제어정보를 뜻한다.\n\n### 2 계층 - 링크 계층(Link Layer)\n\n링크 계층은 네트워크 기기들 사이의 데이터를 전송하는 역할을 한다. 물리 계층을 통해 송수신되는 정보의 오류와 흐름을 관리하여 안전한 정보의 전달을 수행할 수 있도록 도와주는 역할을 한다.\n\n링크 계층에서는 프레임에 주소값을 물리적으로 할당받는데 이는 **맥(MAC; Media Access Control) 주소**라고 불린다.\n\n결국 링크 계층은 **에러검출 / 재전송 / 흐름제어** 역할을 한다.\n\n- PDU : 프레임(Frame)\n- 프로토콜 : 이더넷, MAC, PPP, ATM, LAN, Wifi\n- 대표장비 : 브릿지, 스위치\n\n### 3 계층 - 네트워크 계층(Network Layer)\n\n**네트워크 계층은 네트워크에서 아주 중요하다.**\n\n중요한 기능 중 하나는 라우팅이다. 이는 데이터를 목적지까지 안전하고 빠르게 전달하는 기능을 말한다. 경로를 선택하고 주소를 정하고 경로에 따라 패킷을 전달해주는 것이 네트워크 계층의 역할이다.\n\n네트워크 계층은 사용되는 프로토콜 종류도 다양하고 라우팅하는 기술도 다양하다. 또한 어느 컴퓨터에게 데이터를 전송할지 주소를 가지고 있어서 이를 바탕으로 통신한다. 우리가 아는 IP 주소가 바로 네트워크 계층의 헤더에 있다.\n\n결국 네트워크 계층은 **주소 부여(IP) / 경로 설정(Route)** 역할을 한다.\n\n- PDU : 패킷(Packet)\n- 프로토콜 : IP, ICMP 등\n- 대표장비 : 라우터, L3 스위치\n\n### 4 계층 - 전송 계층(Transport Layer)\n\n전송 계층은 통신을 할성화하기 위한 계층이다. 양 끝단의 사용자들이 신뢰성있는 데이터를 주고 받게 해주는 역할을 한다.\n\n보통 TCP 프로토콜을 이용하며, 포트를 열어서 응용프로그램이 전송을 할 수 있게 한다.\n\n중요한 것은 데이터 전송을 위해서 Port 번호가 사용된다는 점이다. 대표적인 프로토콜로 TCP와 UDP가 있다. 이 계층에서 사용하는 데이터 단위는 세그먼트이다.\n\n결국 전송 계층은 **패킷 생성(Assembly/Sequencing/Deassembly/Error detection/Request repeat/Flow control) 및 전송** 역할을 한다.\n\n- PDU : 세그먼트(Segment)\n- 프로토콜 : TCP, UDP , ARP, RTP\n- 대표장비 : 게이트웨이, L4 스위치\n\n### 5 계층 - 세션 계층(Session Layer)\n\n통신 세션을 구성하는 계층으로, 포트(Port)번호를 기반으로 연결한다. 통신장치 간의 상호작용을 설정하고 유지하며 동기화한다. \n\n> 세션이란 **데이터가 통신하기 위한 논리적인 연결**을 말한다. (통신을 하기 위한 문)\n\n세션 계층은 **TCP/IP 세션을 만들고 없애는 책임**을 진다.\n\n결국 세션 계층은 통신을 하기 위한 세션을 확립 / 유지 / 중단 역할을 한다. (운영체제가 해줌)\n\n- PDU : 데이터(Data)\n- 프로토콜 : NetBIOS, SSH, TLS\n\n### 6 계층 - 표현 계층(Presentation Layer)\n\n표현 계층(Presentation layer)은 코드 간의 번역을 담당하여 사용자 시스템에서 데이터의 형식상 차이를 다루는 부담을 응용 계층으로부터 덜어 준다. MIME 인코딩이나 암호화 등의 동작이 표현 계층에서 이루어지는 것이다.\n\n예를 들면, EBCDIC로 인코딩된 문서 파일을 ASCII로 인코딩된 파일로 바꿔 주는 것, 해당 데이터가 TEXT인지, 그림인지, GIF인지 JPG인지의 구분 등이 표현 계층의 몫이다.\n\n결국 표현 계층은 사용자의 명령어를 완성 및 결과 표현하며, 압축 / 암호화 역할을 한다.\n\n- PDU : 데이터(Data)\n- 프로토콜 : JPG, MPEG, SMB, AFP\n\n### 7 계층 - 응용 계층(Application Layer)\n\n응용 계층은 사용자와 바로 연결되어 있으며 응용 SW를 도와주는 계층이다. 사용자로부터 정보를 입력받아 하위 계층으로 전달하고 하위 계층에서 전송한 데이터를 사용자에게 전달한다.\n\n파일 전송, DB, 메일 전송 등 여러가지 응용 서비스를 네트워크에 연결해주는 역할을 한다.\n\n결국 응용 계층은 응용 프로세스와 직접 관계하여 일반적인 **응용 서비스를 수행**한다.\n\n- PDU : 데이터(Data)\n- 프로토콜 : DHCP, DNS, FTP, HTTP\n\n## TCP/IP 4계층\n\n네트워크 전송 시 데이터 표준을 정리한 것이 ISO 7계층이라고 한다면, 이 이론을 실제 사용하는 인터넷 표준이 TCP/IP 4계층이라고 생각하면 된다.\n\nTCP/IP는 인터넷 프로토콜 중 가장 중요한 역할을 하는 TCP와 IP의 합성어로 데이터의 흐름 관리, 정확성 확인, 패킷의 목적지 보장을 담당한다. 데이터의 정확성 확인은 TCP가, 패킷을 목적지까지 전송하는 일은 IP가 담당한다.\n\n이로써 우리는 7계층이라는 것에서 조금은 벗어나게 된다.\n\n![TCP IP](https://user-images.githubusercontent.com/24274424/86516133-1f04da80-be59-11ea-800f-0626926fb29c.png)\n\n> [출처 - \"데이터가 전달되는 원리\" OSI 7계층 모델과 TCP/IP 모델](https://velog.io/@hidaehyunlee/%EB%8D%B0%EC%9D%B4%ED%84%B0%EA%B0%80-%EC%A0%84%EB%8B%AC%EB%90%98%EB%8A%94-%EC%9B%90%EB%A6%AC-OSI-7%EA%B3%84%EC%B8%B5-%EB%AA%A8%EB%8D%B8%EA%B3%BC-TCPIP-%EB%AA%A8%EB%8D%B8)\n\n### 1 계층 - 네트워크 액세스 계층(Network Access Layer or Network Interface Layer)\n\nOSI 7계층의 물리 계층과 데이터 링크 계층에 해당한다.\n\n### 2 계층 - 인터넷 계층(Internet Layer)\n\nOSI 7계층의 네트워크 계층에 해당한다. \n\n### 3 계층 - 전송 계층(Transport Layer)\n\nOSI 7계층의 전송 계층에 해당한다.\n \n### 4 계층 - 응용 계층(Application Layer)\n\nOSI 7계층의 세션 계층, 표현 계층, 응용 계층에 해당한다.\n\n#### Reference\n\n- [https://reakwon.tistory.com/59](https://reakwon.tistory.com/59)\n- [TCP/IP 4계층](https://tar-cvzf-studybackup-tar-gz.tistory.com/38)\n- [TCP/IP 4계층(TCP/IP 4 Layer)](https://hahahoho5915.tistory.com/15)\n- [[OSI 7계층, TCP/IP 4계층] 네트워크의 기본 계층 구조](https://ryusae.tistory.com/4)\n- [\"데이터가 전달되는 원리\" OSI 7계층 모델과 TCP/IP 모델](https://velog.io/@hidaehyunlee/%EB%8D%B0%EC%9D%B4%ED%84%B0%EA%B0%80-%EC%A0%84%EB%8B%AC%EB%90%98%EB%8A%94-%EC%9B%90%EB%A6%AC-OSI-7%EA%B3%84%EC%B8%B5-%EB%AA%A8%EB%8D%B8%EA%B3%BC-TCPIP-%EB%AA%A8%EB%8D%B8)\n"
  },
  {
    "path": "Network/REST API.md",
    "content": "\n\n# REST API란\n문제 정의: Client와 *Web* Server는 어떻게 소통하는가?\n\n<br/>\n\n## REST (REpresentational State Trasfer)\n**HTTP** 기반의 **네트워크 아키텍처 원리** 중 하나.   \n- **HTTP**: Web 상에서 Data를 주고받을 수 있는 Protocol\n- **네트워크 아키텍처 원리**: Resource(자원)을 정의하고 Resource에 대한 URI를 지정하는 방법 전반을 일컫는다.\n\n<br/>\n\n## API (Application Programming Interface)\n프로그램과 또 다른 프로그램을 연결해주는 매개체\n### 예시\n\n* 내 서비스에 구글 맵을 띄우고 싶을 때, 구글 Map API를 이용해서 구현한다.\n* 앱에 카카오톡 로그인을 넣고 싶을 때, 카카오톡 로그인 API를 사용한다.\n* 사용자 A에 대한 정보가 필요할 때 DB에 직접 접속하지 않고 getInfo같은 API를 통해 정보를 가져온다.\n\n### API 작성 방법\n\n[작성 방법](https://github.com/yoondo/http-api-design/tree/master/ko)\n\n\n<br/>\n\n## REST API\nREST를 통해 API를 구현한 것. Web에서 사용한다.  \n\n### HTTP Packet(데이터 형식)  \n\n![image](https://user-images.githubusercontent.com/43839938/77837073-ab8b6700-719f-11ea-90ee-ae1d2f4b314f.png)![image](https://user-images.githubusercontent.com/43839938/77837076-be05a080-719f-11ea-91fb-f5bf195875a9.png)  <br>\n\n#### [Request Line]  HTTP METHOD\n\n| METHOD  | Description  |\n| ------------ | ------------ |\n| GET | 리소스 조회  |\n| POST  | 리소스 생성 |\n| PUT   | 리소스 수정  |\n| DELETE   | 리소스 삭제  |\n| PATCH | 리소스 일부 수정 |  \n\n\n**PUT**: 자원 전체 교체, 자원 내 **모든 필드** 필요. (일부만 전달할 시에 나머지 필드는 모두 null 혹은 초기값 처리 되므로 주의)  \n**PATCH**: 자원 부분 교체, 자원 내 일부 필드 필요.\n\n```\nGET /members/1  #1번 member의 정보 조회\nPOST /members/2 # 2번 member의 정보 생성(추가)\n```\n\n#### [Request Line] 변수 전달 방법\n\n##### 1) Path Variable\n> GET /users/14579\n> GET /users/:userNo  \n> GET /users/{userNo}  \n##### 2) Query String(Params)\n> GET /users/?age=14&name=%이%\n\n### [HEADER]  \n\nheader: meta-data (data에 대한 설명을 제공하는 data)  \n<img src=\"https://user-images.githubusercontent.com/43839938/77837595-d678b980-71a5-11ea-879b-5118474e1d22.png\" width=\"50%\">\n### [BODY] Data 종류\n\n##### 1) RAW: XML, JSON [[XML과 JSON의 차이]](https://12bme.tistory.com/202)\n\t참고: XML에 비한 JSON의 장점 \n\t1) 저장할 data가 줄어든다. (data와 직접적인 연관이 없는 태그들이 사용되지 않기 때문이다.) \n\t2) JSON은 Object 형태이다. 다루기 용이하다. \n\n##### 2) Form\n\n<br/>\n\n## RESTful 한 API 설계 방법\n### REST API 중심 규칙\n\n1) URI는 정보의 자원을 표현한다. (Resource명은 명사로)\n> GET /members/delete/1 (잘못됨)\n2) 자원에 대한 행위는 HTTP Method로 표현한다.\n> DELETE /members/1 (위의 예시를 바르게 표현한 경우)\n\n**즉, [행위(V) - 자원(N)] [Method - URI(Resource)]를 구분함으로써 RESTful한 API를 설계할 수 있다.**\n\n### 주의점\n\n1) 슬래시(/)는 계층 관계를 나타낼 때 사용한다.\n> GET /houses/apartments/12345\n> GET /animals/mammals/whales/1\n\n\n2) URI 마지막 문자로 슬래시(/)를 포함하지 않는다.\n> GET /houses/apartments/ (X)\n> GET /houses/apartments  (0)\n\n\n3) 밑줄(_)이 아닌 하이픈(-)으로 의미를 구분하자.\n> POST /users/14579/blocked-user\n\n\n4) URI 경로는 소문자가 적합하다.\n\n\n5) 파일 확장자는 URI에 포함시키지 않는다. \n\n\n6) Collection은 복수로 표현하자.\n> GET sports/soccer/players/13\n\n### 응답코드\n\n![응답코드](https://user-images.githubusercontent.com/43839938/77838355-2f4c5000-71ae-11ea-85b6-ae1ad5cc8532.JPG)\n\n------------\n#### 참고자료\n* **REST API 제대로 알고 사용하기**  https://meetup.toast.com/posts/92   \n* **REST** https://ko.wikipedia.org/wiki/REST  \n* **REST API** https://link.medium.com/SbA8UFpRw4   \n* **API 란?**  https://link.medium.com/FDERJUxX83  \n* **GET, POST** https://mommoo.tistory.com/60  \n* **HTTP** https://withbundo.blogspot.com/2017/07/http-10-http.html?spref=tw\n* **Internet과 Web** http://tcpschool.com/webbasic/intro\n* **Types of Internet Protocols** http://bitly.kr/AuC7wV  \n응용 계층 - 전송 계층 - 인터넷 계층 - 링크 계층 \n응용계층: HTTP, HTTPS, FTP, SMTP, MQTT, SSH, TSL/SSL\n전송계층: TCP/UDP\n*  Internet 구성원으로서의 **Server, Client:** http://tcpschool.com/webbasic/www  \n* **URL, URI** 차이 http://bitly.kr/6WSgNSeY  \nURL(Uniform Resource Locator): 자원(이 있는 곳)  \nURI (Uniform Resource Identifier): 자원 식별자 / 자원에 접근하기 위한 표현 방식.   \nURL, URI를 명확하게 구분하는 것 보다 URI는 REST 등장 이후 의미 단위로 구분하기 위한 용어임을 알아두자.\n* **SDK, API** 차이\nhttps://hyesunzzang.tistory.com/90\n"
  },
  {
    "path": "Network/REST.md",
    "content": "# REST\n\n## REST(REpresentational State Transfer)란\n\n### HTTP에서의 representation   \nHTTP GET 요청에 대한 응답으로 다음을 받았다고 가정해보자.\n\n```html\nHTTP/1.1 200 OK  \nContent-Length: 6  \nDate: Sun, 18 Aug 2019 10:20:47 GMT  \nLast-Modified: Sun, 18 Aug 2019 08:00:00 GMT  \nContent-Type: text/plain  \nContent-Language: en   \n    \nhello\n```  \n\n이 응답을 보고, 요청에 대한 결과로 `hello`라는 resource를 받았다고 표현하는 경우가 흔하다. 하지만 이는 엄밀히 말해 틀린 말이다. `hello`는 resource가 아닌 **representation data** 이기 때문이다.   \n\nGET 메소드 정의는 다음과 같다.  \n\n```\nThe GET method requests a representation of the specified resource.\n```  \n\n즉, GET 메소드는 특정 리소스에 대한 하나의 representation을 반환한다. 그러므로 `hello를 담고 있는 문서`가 리소스고, `hello`는 representation이다. representation은 representation metadata와 representation data로 구성된다. 위에서 받은 응답을 나눠보면 다음과 같다. \n\n```html\n<!--representation metadata-->\nContent-Type: text/plain  \nContent-Language: en  \n```\n\n```html\n<!--representation data-->\nhello\n```  \n\n### REpresentational State Transfer\nHTTP에서의 representation은 REST의 representation에서 도입된 개념이다.   \n*REpresentational State Transfer*의 단어를 각각 해석하면 다음과 같다.   \n* Representation : 어떤 리소스의 특정 시점에 대한 상태를 반영하고 있는 정보\n* State : 웹 애플리케이션(웹 서버에 접속하여 사용자에게 가치를 제공하는 웹 브라우저)의 상태\n* Transfer : 서버에서 클라이언트로 리소스의 상태 전송\n\n클라이언트가 `https://example.com/A`에서 `https://example.com/B`로 이동했다고 가정해보자.  \n페이지를 이동하면서 새로운 representation이 transfer 되었고, state가 변경되었다. 이를 REpresentational State Transfer, REST라고 한다.  \n\n### 아키텍처 스타일\nREST는 자원지향구조(ROA: Resource Oriented Architecture)이다. 웹 사이트의 텍스트, 이미지, DB 내용 등을 전부 하나의 자원으로 파악하여 각 자원에 고유한 HTTP URI를 부여한다. 그리고 해당 자원에 대한 CRUD작업을 HTTP의 기본 명령어인 POST, GET, PUT, PATCH, DELETE를 통해서 처리한다.  \n\nREST는 HTTP 프로토콜을 활용해 웹의 장점을 극대화시키는 아키텍처 스타일이다. REST(Representational State Transfer)가 소프트웨어 아키텍처 스타일로 제안된 이후, REST는 급속하게 OPEN API 개발의 기본이 되었다.\n\n<br/>\n\n## REST API\n \n### 중심규칙\nREST API는 다음의 중심규칙을 갖는다.  \n\n* URI는 자원을 표현하는 데에 집중한다. 즉, 동사보다 명사를 사용하도록 한다.\n    \n    ```js\n    form.method = \"get\";\n    // bad\n    const url = \"todo/show/A\";\n    // good\n    const url = \"todo/A\";\n\n    ```\n\n* 행위에 대한 정의는 HTTP Method를 사용한다.\n    \n    ```js\n    // bad\n    form.method = \"get\";\n    const url = \"todo/delete/A\";\n    // good\n    form.method = \"delete\";\n    const url = \"todo/A\";\n    ```  \n\n<br/>  \n\n### URI 설계 시 주의할 점 \n* **/** 는 계층 관계를 나타낸다.\n    ```html\n    http://restapi.example.com/houses/apartments  \n\n    http://restapi.example.com/animals/mammals/whales\n    ```\n* URI 마지막에는 **/** 를 포함시키지 않는다.\n    ```html\n    http://restapi.example.com/houses/apartments/ (X)  \n    http://restapi.example.com/houses/apartments  (0)\n    ```\n* URI의 가독성을 높히고자 할 때에는 **_(밑줄)**   보단 **-(하이픈)** 을 사용한다.  \n\n    밑줄은 보기 어렵거나 밑줄 때문에 문자가 가려지기도 하므로 밑줄 대신 하이픈을 사용하는 것이 좋다.\n* 대문자 사용은 피하도록 한다.  \n\n    대소문자에 따라 다른 리소스로 인식되기 때문에 대문자 사용을 피하도록 한다.\n* 파일 확장자는 URI에 포함시키지 않는다. \n\n<br/>  \n\n### HTTP Method\n|Method|Action|역할|\n|------|---|---|\n|GET|index/retrieve|모든/특정 리소스 조회|\n|POST|create|리소스 생성|\n|PUT|update all|리소스 전체 갱신|\n|PATCH|update|리소스 일부 갱신|\n|DELETE|delete|리소스 삭제|\n\n<br/>   \n  \n### REST API의 상태코드  \n\n|코드|이름|정보|  \n|------|---|---|\n|200|OK|요청 성공 상태|\n|201|Created|새로운 자원을 생성한 상태 (POST 요청시 많이 사용됨)|\n|400|Bad Request|잘못된 요청으로 인한 실패 상태|\n|401|Unauthorized|요청에 대한 인증이 필요한 상태|\n|403|Forbidden|서버에서 요청을 거부한 상태(접근 권한이 없음을 의미)| \n|404|Not Found|요청한 자원을 찾을 수 없음|\n|409|Conflict|요청에 대해 충돌이 발생한 상태|  \n\n기타 부수적인 코드는 [REST 관련 HTTP 상태 코드](https://zetawiki.com/wiki/REST_%EA%B4%80%EB%A0%A8_HTTP_%EC%83%81%ED%83%9C_%EC%BD%94%EB%93%9C)에서 확인 가능하다.  \n\n<br/>  \n\n### 제약조건  \n\n* Server-Client 구조 : 일관적인 인터페이스로 분리되어야한다. \n* Cacheable : HTTP 프로토콜을 따라 클라이언트의 응답을 캐싱할 수 있어야한다. \n* Stateless : HTTP 프로토콜을 따라 REST Server 역시 stateless(무상태) 해야한다. 즉, 서버에 클라이언트의 context 정보를 저장하지 않아야 하며 각각의 요청을 별개의 것으로 인식하고 처리해야 한다. \n* Layered System : REST를 사용하면 서버 A에 API를 배포하고, 서버 B에 데이터를 저장하고, 서버 C에 요청을 하는 계층화된 시스템을 구현할 수 있다. 계층화된 시스템에서는 비즈니스 로직을 수행하는 서버의 앞단에서 사용자 인증, 암호화 등의 보안 처리를 할 수 있으며, [로드 밸런싱](https://github.com/Im-D/Dev-Docs/blob/master/Network/%EB%A1%9C%EB%93%9C%EB%B0%B8%EB%9F%B0%EC%8B%B1%20%26%20%ED%81%B4%EB%9F%AC%EC%8A%A4%ED%84%B0%EB%A7%81.md)이나 공유 캐시 기능을 통해 시스템 규모 확장성을 향상시킬 수 있다.  \n* Code-On-Demand(optional) : Server는 클라이언트에게 java applet이나 js로직 등이 포함된 html을 전송하여 서비스의 기능을 확장할 수 있다. 클라이언트가 응답을 받아 페이지가 표시되면, java applet이나 js로직 등이 브라우저에서 실행되는 방식이다. 하지만 이는 보안상 문제가 있을 수 있기 때문에 Code-On-Demand 방식은 필수조건이 아니며, 요즘은 많이 사용되지 않고 있다. java 7부터는 신뢰할 수 없는 응용프로그램의 실행을 차단하는 보안 지침이 업데이트 되었고, Chrome에서는 java applet에 필요한 기술인 NPAPI를 지원하지 않는 등의 방향으로 바뀠었기 때문이다.\n\n\n<br/>  \n\n### 장점\n* HTTP 프로토콜의 인프라를 그대로 사용하므로 REST API 사용을 위한 별도의 인프라를 구축할 필요가 없다.\n* HTTP 표준 프로토콜을 따르는 모든 플랫폼에서 사용 가능하다.\n* REST API 메시지가 의도하는 바를 명확하게 나타내므로 의도하는 바를 쉽게 파악할 수 있다.\n* 서버와 클라이언트의 역할이 명확히 구분된다. REST Server는 API를 제공하고 비즈니스 로직    처리 및 저장을 책임지며 클라이언트는 사용자 인증이나 context 정보를 직접 관리하고 책임진다. \n\n----\n#### Reference\n[REST(Representational State Transfer) API](https://poiemaweb.com/js-rest-api)  \n[REST의 representation이란 무엇인가](https://blog.npcode.com/2017/04/03/rest의-representation이란-무엇인가/)  \n[REST란? REST API란? RESTful이란?](https://gmlwjd9405.github.io/2018/09/21/rest-and-restful.html)  \n[REST API Tutorial](https://restfulapi.net/rest-architectural-constraints/#layered-system)  \n[REST API를 위한 HTTP 상태 코드](https://mygumi.tistory.com/230)  \n[Code_on_demand](https://en.wikipedia.org/wiki/Code_on_demand)"
  },
  {
    "path": "Network/SOAP API.md",
    "content": "# SOAP API\nAPI를 사용하면서 여러 종류의 API가 있다는 사실을 알게 되었다. 가장 대표적인 두 가지 방식으로는 SOAP와 REST가 있다. 두 가지 방식은 비슷하지만 본질적으로 다른 기술이다. [SOAP는 프로토콜이고, REST는 아키텍처 스타일](http://blog.wishket.com/soap-api-vs-rest-api-두-방식의-가장-큰-차이점은/)이기 때문이다.\n\nSOAP와 REST는 일반적으로 웹 서비스라고 불린다. 이러한 서비스는 서로 다른 컴퓨터에서 네트워크를 통해 데이터를 주고받는 통신이라고 생각하면 된다. \n\n저번 시간에는 [REST API](https://github.com/im-d-team/Dev-Docs/blob/master/Network/REST%20API.md)에 대해 자세히 알아보았으니 이번 시간에는 SOAP에 대해서 자세히 알아보는 시간을 가지자.\n\n## SOAP API?\nSOAP는 Simple Object Access Protocol의 약자이며 HTTP, HTTPS, SMTP 등을 통해 `XML 기반`의 메시지를 분산된 컴퓨터 네트워크 환경에서 교환하는 `프로토콜`이다.\n보안이나 메시지 전송 등에 있어서 많은 표준들이 정해져있기 때문에 REST API보다 조금 더 복잡하다.\n\nSOAP는 SSL을 지원하고 WS-Security라는 자체 표준의 보안 기능을 가지고 있기 때문에 보안 수준이 엄격하다. \n\n> SSL는 보안 소켓 계층(Secure Socket Layer)이며 클라이언트와 서버 간의 데이터 전송 시 암호화하여 보안을 유지한다.\n\n> WS-Security는 웹서비스에 보안을 적용하기 위하여 SOAP 메시지에 보안을 강화한 것이다.\n\n따라서 은행용 모바일 앱, 신뢰할 수 있는 메시징 앱 등 보안 수준이 높아야 하거나 또는 ACID(원자성, 일관성, 고립성, 지속성)를 준수해야 하는 경우라면 SOAP 방식이 더욱 선호된다.\n\n> **원자성**: 작업들이 부분적으로 실행되다가 중단되지 않는 것을 보장하는 능력이다.\n\n> **일관성**: 트랜잭션이 실행을 성공적으로 완료하면 일관성 있는 데이터베이스 상태를 유지하는 것을 의미한다.\n\n> **고립성**: 트랜잭션 실행 시 다른 트랜잭션이 끼어들지 못하도록 보장하는 것을 의미한다.\n\n> **지속성**: 성공적으로 실행된 트랜잭션은 영원히 반영되어야 함을 의미한다.  \n\n## SOAP 아키텍처\nSOAP는 일반적으로 UDDI 레지스토리를 통해 웹 서비스를 `등록(Publish)`하고, `탐색(find)`하고, `바인딩(Bind)`하여 사용한다. \n\n### 동작원리\n\n![SOAP 동작원리](https://user-images.githubusercontent.com/43868540/84564061-1ad62780-ad9b-11ea-862f-9ca9563e6c57.png)\n> [출처](https://devkingdom.tistory.com/12)\n\n1. 서비스 요청자가 SOAP로 인코딩하여 웹 서비스 요청을 서비스 제공자에게 전달한다.\n2. 서비스 제공자는 이를 디코딩하여 적절한 서비스 로직을 수행시켜서 결과를 얻는다.\n3. 로직을 수행시켜서 얻은 결과를 SOAP로 인코딩하여 반환한다. \n\n여기서 WSDL(Web Services Description Language)과 UDDI(Universal description, discovery, and integration)의 개념이 모호할 것이다. \n웹 서비스가 제공하는 서비스에 대한 정보를 기술하기 위한 XML 기반의 마크업 언어가 `WSDL`이다. WSDL은 웹 서비스를 기술하고 웹 서비스가 실제 어디에 위치하고 있는 지와 웹 서비스를 이용하기 위한 Binding정보를 담고 있는 문서이다. 이 WSDL은 서비스 제공자가 기술한다. WSDL 정보를 해석하면 soap를 사용해 필요한 웹 서비스를 사용할 수 있다.\n그렇다면 WSDL은 어디에 저장되어 있을까?\n\n이러한 WSDL이 위치한 저장소가 `UDDI 레지스토리`이다. \n이러한 저장소에 있는 자료를 꺼내기 위해 실행 프로토콜인 `SOAP`를 사용한다. \n\n**한번 발행된 WSDL은 UDDI(레지스토리)에 저장이 되며 잠재적인 사용자가 원하는 기능의 웹서비스가 구현되었는지 검색하는데 사용된다.**\nSOAP을 사용해 필요한 웹서비스의 대한 정보를 UDDI를 통해 탐색, 선택을 하면 선택된 웹 서비스의 WSDL을 파싱하여 SOAP 메시지로 인코딩하여 반환한다. \n\n<img width=\"597\" alt=\"SOAP인코딩과정\" src=\"https://user-images.githubusercontent.com/43868540/89731760-8d564180-da84-11ea-9b9c-173b51868512.png\">\n\n> [출처](http://egloos.zum.com/tequiero35/v/929083)\n\n위의 설명은 soap를 이용한 웹 서비스 호출과 응답하는 과정을 자세히 설명한 이미지이다. \n\n더욱 자세한 설명이 필요하다면 [이곳](http://www.nextree.co.kr/p11842/)을 참고하길 바란다. \n\n그렇다면 SOAP의 메시지 구조를 한번 살펴보자.\n\n![SOAP 메시지 구조](https://user-images.githubusercontent.com/43868540/84564122-a780e580-ad9b-11ea-9f6d-e4803e1c9a6e.jpeg)\n> [출처](https://mygumi.tistory.com/55)\n\n크게 `HTTP Header`와 `SOAP part`, `Attachment` 3개로 나누어 진다.\n\n`HTTP Header`에는 송수신하면서 필요한 정보들(시간, 인터넷 호스트와 포트, 상태 코드, 인코딩 등)을 표시한다. \n\n요청과 응답에 대한 코드의 상세한 설명은 [이곳](http://egloos.zum.com/tequiero35/v/1026372)를 참고하길 바란다.\n\n<img width=\"570\" alt=\"스크린샷 2020-06-14 오전 12 12 21\" src=\"https://user-images.githubusercontent.com/43868540/84572270-d87d0c80-add3-11ea-8817-d81df090eb4f.png\">\n\n> [출처](https://www.slideshare.net/yjaeseok/soap-rest)\n\n`SOAP Part`안에는 위의 사진처럼 xml 형태로 데이터가 들어가 있다. \n\nSOAP 봉투(envelope), SOAP 헤더(header), SOAP 바디(body)로 구성된 하나의 xml 문서로 표현된다. \n\n`<env:Envelop>`는 루트 엘리먼트로, SOAP 메시지를 위한 네임스페이스이다. 충돌 방지와 호출을 위한 네임스페이스를 지정해 주어야 한다. \n\n`<env:Body>`는 web service를 이용하기 위한 실제 메시지를 기술하는 곳이다. \n\n서비스를 호출하고 응답에 관한 내용을 적는다. 위의 사진은 요청자에게 응답할 id와 password가 기술된 메시지이다. \n\n또한, `<env:Body>`는 에러가 있을 때 SOAP Fault를 기술하는 곳이기도 하다. \n\n`<env:Fault>`는 `<env:Body>` 엘리먼트의 하위 엘리먼트로, SOAP 문서 처리할 때 에러가 발생한 경우, 그 내용을 기술한다.\n\n각각의 엘리먼트와 예제 등 자세한 내용은 [이곳](http://egloos.zum.com/tequiero35/v/1026372)를 참고하길 바란다. \n\n이러한 복잡한 구성으로 인해 HTTP 상에서 전달되기 무겁고, 메시지 인코딩/디코딩 과정 등 웹 서비스 개발의 난이도가 높아 개발 환경의 지원이 필요하다. \n\n\n## SOAP의 장점과 단점\n### 장점\n- SOAP는 플랫폼과 프로그래밍 언어에 **독립적**이다.\n> 어떤 언어로 작성되더라도 SOAP만 준수된다면 플랫폼 독립적이라 데이터 통신이 가능함\n- SOAP는 웹 서비스를 제공하기 위한 **표준(WSDL, UDDI, WS-Security)이 잘 정립**되어 있다.\n- SOAP는 **에러 처리**에 대한 내용이 기본으로 내장되어 있다.\n- SOAP는 **분산 환경**에 적합하다.\n\n### 단점\n- REST에 비해 구조가 복잡하기 때문에 상대적으로 **무겁고 속도도 느리다**.\n- 메시지 인코딩/디코딩 과정 등 **개발 난이도가 높아 개발 환경의 지원이 필요하다**.\n\n#### Reference\n- [SOAP vs REST](http://blog.wishket.com/soap-api-vs-rest-api-두-방식의-가장-큰-차이점은/)\n- [ACID](https://goodgid.github.io/ACID/)\n- [SOAP](https://mygumi.tistory.com/55)\n- [WDSL, UDDI](https://beatz.tistory.com/entry/SOAP-WSDL-UDDI)\n"
  },
  {
    "path": "Network/Subnetmask.md",
    "content": "# 네트워크 기초 - 서브넷마스크(Subnetmask)\n\n### 이전 글 복습하기\n\n[네트워크 기초 - IP](https://github.com/im-d-team/Dev-Docs/blob/master/Network/IP.md)\n\n- 네트워크 : 두 대 이상의 컴퓨터가 논리적 또는 물리적으로 연결되어 통신이 가능한 상태(PAN, LAN, MAN, WAN).\n- IP 주소 : 네트워킹이 가능한 장비를 식별하는 주소.\n- IPv4, IPv6\n- A, B, C 클래스 : 네트워크 영역과 호스트 영역을 구분한 기준\n  - A : `0.0.0.0` ~ `127.255.255.255`\n  - B : `128.0.0.0` ~ `191.255.255.255`\n  - C : `192.0.0.0` ~ `223.255.255.255`\n- 네트워크 주소 : 호스트 부분이 모두 0인 경우\n- 브로드캐스트 주소 : 호스트 부분이 모두 1인 경우\n\n## 서브넷마스크(Subnetmask) 이란?\n\n이전 글을 다시 보게되면 IP의 부족이 발생하여 IPv6가 나왔다. 그러나 그 이전에 서브넷마스크라는 것이 먼저 나왔으며, 제한적인 자원을 낭비 없이 아껴쓰기 위한 방법 중 하나로 지금도 많이 사용되고 있다.\n\n서브넷마스크는 기본적으로 1과 0으로 구성되어 있으며, IP 크기와 동일하게 32자리 2진수로 표현된다. 크기가 똑같은 이유는 **IP주소와 서브넷 마스크를 AND 연산**하기 위해서 이다.\n\n서브넷마스크는 IP와 크기는 같으나 표현에 있어서 차이가 있다. 서브넷마스크는 1이 연속으로 나와야 한다. 예를 들어 1101와 같은 표현은 없다. **무조건 0이 나오기 시작하면 그 뒤는 0이라고 생각하면 된다.**\n\n우리가 흔히 알고 있는 공유기로 예를 들어보자.\n\nIP 주소에서 `192.168.0.1/24`라고 되어있다. 이는 C 클래스이며 기본 서브넷 마스크는 `255.255.255.0`이다. 우리가 아는 A, B, C 클래스에는 각각의 기본 서브넷 마스크가 존재하여 네트워크 영역과 호스트 영역으로 나뉜다. 결국 각각의 클래스가 가지고 있는 **기본 서브넷마스크**으로 인해서 네트워크 영역과 호스트 영역이 정해지는 것이다.\n\n> 기본 서브넷 마스크 : 별개의 서브넷마스크를 생성하지 않아도 기본적으로 적용되어 있는 서브넷마스크\n\n`255.255.255.0`을 이진수로 표현하면, `1111 1111. 1111 1111. 1111 1111. 0000 0000`이다. 위에서 언급했듯이 한 번 0이 나오기 시작하면 뒤로는 다 0인 것을 확인할 수 있다. 또한 앞에서부터 1의 개수를 세면 24이다. 이에 위에서 `/24`로 표현이 되었다.\n\n### 논리 AND 연산 방법\n\n논리 AND 연산은 `1 AND 1 = 1`, `1 AND 0 = 0`, `0 AND 1 = 0`, `0 AND 0 = 0` 이다.\n\n`1100 0000. 1010 1000. 0000 0000. 0000 0001` = `192.168.0.1` (IP 주소)\n\n`1111 1111. 1111 1111. 1111 1111. 0000 0000` = `255.255.255.0` (C 클래스 기본 서브넷마스크)\n\n`1100 0000. 1010 1000. 0000 0000. 0000 0000` = `192.168.0.0` (네트워크 주소)\n\n## 서브넷네트워크\n\n별개의 서브넷마스크를 생성하지 않아도 기본적으로 적용되어 있는게 기본 서브넷마스크이고, 기본 서브넷마스크로 쪼개진 네트워크 주소를 서브넷 네트워크라고 한다.\n\n새로운 예제로 서브넷마스크를 이해해보자.\n\n`1001 0110. 1001 0110. 0110 0100. 0000 0001` = `150.150.100.1`(IP주소)\n\n`1111 1111. 1111 1111. 1111 1111. 0000 0000` = `255.255.255.0`(C클래스 기본서브넷마스크)\n\n`1001 0110. 1001 0110. 0110 0100. 0000 0000` = `150.150.100.0`(서브넷네트워크)\n\n위에서 봤던 예제와는 뭔가가 다르다고 느꼈다면 이미 클래스, 서브넷마스크에 대한 이해가 완벽한 것이다.\n\n`150.150.100.1`은 분명 B 클래스인데, 서브넷 마스크가 C 클래스이다. `150.150.100.1`의 기본 서브넷마스크인 `255.255.0.0`를 사용하지 않고 C 클래스 `255.255.255.0`를 사용한다는 것은 B 클래스 주소를 마치 C 클래스 주소처럼 사용하겠다는 것을 의미한다.\n\n다시 말해 B 클래스의 기본 서브넷마스크에 의해서 `150.150` 까지가 네트워크 영역이고 나머지 3,4번째 옥탯은 호스트 영역이다. C 클래스 기본 서브넷마스크인 `255.255.255.0`를 씌우면서 `150.150.100`까지 네트워크 영역이 되고 4번째 옥탯만 호스트 IP를 배정할 수 있게 만든 것이다.\n\n**즉 네트워크 영역을 늘리고 호스트 영역을 줄이겠다는 뜻을 내포하고 있다는 것을 눈치채야 한다.** 이렇게 하나의 주소에 서브넷 마스크를 씌워서 자신에게 맞는 네트워크를 만드는 것을 서브네팅이라고 한다. \n\n> 참고. 서브넷마스크로 나뉘어진 서브넷네트워크간 통신은 라우터를 통해서 통신이 되어야 한다. 다른 말로 서브넷네트워크는 하나의 독립적인 네트워크이다.\n\n#### 문제\n\n`1100 1001. 1101 1110. 0000 0101. 0000 0000` = `201.222.5.0`(IP 주소)\n\n`1111 1111. 1111 1111. 1111 1111. 1111 1000` = `255.255.255.248`(서브넷마스크)\n\n`1111 1111. 1111 1111. 1111 1111.` = (C 클래스가 가질 수 있는 네트워크 영역)\n\n**위와 같이 서브넷마스크를 적용했을 때, 서브넷네트워크의 개수는?**\n\n<details>\n<summary> 정답 </summary>\n\n - 사용자가 지정한 네트워크영역(4옥텟 기준) : `11111`\n - 사용자가 지정한 호스트영역(4옥텟 기준) : `000`\n\n사용자가 지정한 호스트 영역은 `000`으로 `2^3 = 8`이 나오게 되는 것이다. 그런데 이전 글(IP)에서 언급되었듯이 네트워크 주소와 브로드캐스트 주소는 빼주어야 한다. 그러므로 답은 8개가 아닌 6개이다.\n\n</details>\n\n진정한 의미에 서브넷마스크는 A 클래스, B 클래스, C 클래스의 기본 서브넷마스크에서 가질 수 있는 네트워크영역과 호스트영역을 더 쪼개서 더 효율적으로 **서브네팅**하는 것이다. \n\n## 서브네팅이란(Subnetting)?\n\n네트워크 관리자가 네트워크 성능을 향상하기 위해, 자원을 효율적으로 분배하는 것을 서브네팅이라고 한다. \n\n여기서 말하는 자원을 효율적으로 분배한다는 것은 네트워크 영역과 호스트 영역을 분할하는 것으로 생각하면 된다.\n\n네트워크 측면에서는 너무 큰 브로드캐스트 도메인은 네트워크 환경에서 패킷 전송을 느리게 하고 성능 저하를 발생시킨다. 이에 네트워크를 쪼개서 통신 성능을 보장하는 것이다. 또한 IP는 32자리 2진수로 표현할 수 있는데 이 말은 2의 32승만큼의 표현만 가능하다는 뜻이다. 그래서 등장한 것이 서브넷마스크라는 녀석이다. 서브넷 마스크는 필요한 네트워크 주소만 호스트 IP로 할당할 수 있게 만들어 네트워크 낭비를 방지한다.\n\n서브네팅의 반댓말인 슈퍼네팅도 있다. \n\n> 슈퍼넷팅(Supernetting) : 네트워크를 합쳐 네트워크를 확장하는 것\n> \n> 서브네팅(Subnetting) : 네트워크 성능 보장을 위해서, 자원을 효율적으로 분배하기 위해 네트워크 영역과 호스트 영역을 쪼개는 것\n\n### One more thing...\n\n하나의 IP는 네트워크 부분 + 호스트 부분으로 구성되어있다. 하나의 네트워크 즉 하나의 브로드캐스트 도메인에 있는 IP끼리 통신하기 위해선 네트워크 영역이 같아야 하며, 호스트 IP는 달라야 한다. 호스트 IP가 다르지 않다면 IP는 충돌 나게 된다. 그렇다면 네트워크 영역이 다르다고 해서 통신할 수 없을까? 아니다. 네트워크 영역이 달라도 라우터나 게이트웨이와 같은 통신장비를 통해 통신할 수 있다. 다만 라우터와 네트워크 장비 없이 통신할 수 있는 영역을 우리는 브로드캐스트 도메인이라고 하며 하나의 네트워크는 같은 네트워크 영역을 가지는 반면, 호스트 IP는 자신의 노드를 식별할 수 있도록 자신 이외의 호스트 IP와는 달라야 한다.\n\n#### Reference \n\n- [넷마스크(Netmask)와 서브넷마스크(Subnetmask)](https://velog.io/@hidaehyunlee/%EB%84%B7%EB%A7%88%EC%8A%A4%ED%81%ACNetmask%EC%99%80-%EC%84%9C%EB%B8%8C%EB%84%B7%EB%A7%88%EC%8A%A4%ED%81%ACSubnetmask)\n- [[Network] 서브넷마스크(Subnet Mask)란?](https://limkydev.tistory.com/166)\n"
  },
  {
    "path": "Network/Switch.md",
    "content": "네트워크 교육을 듣다가 스위치가 layer 계층별로 각각 존재한다는 것을 알게 되었고 더욱 자세히 알고 싶어 정리를 해보았다.\n\n# 스위치(Switch)\n스위치란 허브의 확장된 개념으로 기본 기능은 허브와 같지만 전송 중 패킷의 충돌이 일어나지 않도록 패킷의 목적지로 지정할 포트를 직접 전송한다. 소규모 통신을 위한 허브보다 전송 속도가 개선된 것이다. \n\n간단하게 말해서 아래의 사진처럼 인터넷을 할 수 있는 랜선을 꽂을 수 있는 것을 스위치라고 한다. 하나의 네트워크 라인에 여러 대의 컴퓨터를 연결하는 데 필요한 장치이다.  \n\n![스위치](https://user-images.githubusercontent.com/43868540/104829776-5ea58800-58ba-11eb-8b42-18e63238c6cd.PNG)\n\n> [출처](https://blog.naver.com/PostView.nhn?blogId=wjw1225&logNo=222147131756)\n\n## 허브와 스위치의 차이\n허브의 경우 전송대역을 여러 대의 네트워크가 나눠 쓰는 단점이 있다. 반면 스위치의 경우는 같은 속도로 분배해준다는 장점이 있다.\n\n![스위치와 허브](https://user-images.githubusercontent.com/43868540/104828795-5cd6c700-58b0-11eb-9c5c-c18f53c02339.PNG)\n\n> [출처](https://siran.tistory.com/205)\n\n위에 그림을 보면 허브는 모든 노드가 일정 속도를 나누어 쓰게 되고, 스위치는 네트워크를 동시에 사용 가능해 속도 저하가 거의 없다. 따라서 스위치는 각 Port별로 bandwidth를 제공한다.  \n\n### Layer2 스위치(스위치)\nLayer 2에서 동작하는 스위치로, MAC 주소를 보고 데이터를 단순전달해주는 기능을 담당한다. 허브와는 다르게 포트별로 bandwidth가 정해져 데이터를 전달하기 때문에 속도에 저하가 없다. \n\n- 가장 흔히 볼 수 있는 스위칭 방식이며, 원래 스위치의 정의에 가장 부합하는 형태이다. \n- 패킷의 **MAC 주소**를 읽어 스위칭하고, MAC의 OSI 계층 중 2계층에 해당하기 때문에 Layer 2 스위치라 한다. \n- Broadcast 패킷에 의해 성능 저하가 발생한다. \n> Broadcast란 송신 호스트가 전송한 데이터가 네트워크에 연결된 모든 호스트에 전송되는 방식이다.\n\n하지만 L2 스위치는 MAC 주소로만 동작할 뿐 상위 레이어인 3계층에서 동작하는 ip 등을 이해하지 못한다. 따라서 라우팅을 할 수 없다.\n\n### Layer3 스위치(라우터)\n데이터를 단순전달만 하는 L2와는 달리, L3는 **라우팅 기능이 있어 외부에 연결된 포트도 데이터를 보낼 수 있다.**\nL2 스위치는 서로 다른 네트워크의 경우 통신이 되지 않지만, L3 스위치는 서로 다른 네트워크여도 라우팅하여 통신할 수 있다. 따라서 라우터와의 경계가 모호하다. \n> 라우터와 L3 스위치와의 차이점을 많이 찾아보았지만 결론적으로 거의 같은 의미로 사용한다고 한다. 굳이 기준을 잡고 구분할 수 있겠지만 차이점이 거의 없기 때문에 같은 뜻으로 받아들여도 된다고 한다. \n\n![L3](https://user-images.githubusercontent.com/43868540/104829794-a2988d00-58ba-11eb-9e89-96ef37d732b4.PNG)\n\n> [출처](https://blog.naver.com/PostView.nhn?blogId=wjw1225&logNo=222147131756)\n\n- 패킷의 **IP 주소**를 읽어 스위칭하고, IP가 OSI 7계층 중 3계층에 해당하기 때문에 Layer 3 스위치라 한다. \n- L2 스위치에 라우팅(Routing) 기능을 추가하고 TCP/IP를 이용한다.\n\n### Layer4 스위치(로드밸런싱)\nL4 스위치는 TCP와 UDP의 헤더를 보고 포트를 분별해 적절한 서버로 패킷을 전송한다. 즉, 똑같은 IP여도 포트 번호가 다를 경우 다른 서버로 보낼 수 있다. \n그리고 그것이 FTP인가 HTTP인가 SMTP인가를 보고 어떤 것을 우선시해서 스위칭할지 판단할 수 있다. 또한, 서버나 네트워크의 트래픽을 로드밸런싱을 할 수 있다.\n> 로드밸런싱은 여러 대의 서버를 1대처럼 묶을 수 있는 분산기능이다.\n\n실제로 많은 온라인 서비스들은 대부분 최소 2개 이상의 같은 서버들로 분산처리 되게끔 구성되어있다고 한다. 이때 서비스를 분산시켜주는 장비가 L4이다. 이는 부하를 분산하기 위함도 있고 서비스가 죽는 때를 대비하기 위한 것이다. 이로 인해 서버에 트래픽 과부하를 거는 디도스 공격이 불가능해진다는 장점도 있다.\n\n![L4](https://user-images.githubusercontent.com/43868540/104828573-3ca60880-58ae-11eb-8ba1-5e98db78c670.PNG)\n\n> [출처](https://klero.tistory.com/entry/L2-L3-L4-L7-%EC%8A%A4%EC%9C%84%EC%B9%98-%EA%B5%AC%EB%B6%84-%EB%B0%8F-%EA%B8%B0%EB%B3%B8%EC%A0%81%EC%9D%B8-%EC%84%A4%EB%AA%85)\n\n- 패킷의 IP주소와 Port번호를 읽어 스위칭을 하고 Port가 OSI 7계층 중 4계층에 해당하기 때문에 Layer 4 스위치라 한다. \n- L3와 같이 프로토콜을 기반으로 하며, 어플리케이션별로 우선순위를 두어 스위칭이 가능하다.\n- 많은 양의 트래픽을 여러 서버로 분산할 수 있다.\n\n\n## 정리\n각 어떤 계층에서 수행되는가에 따라 L2, L3 등 분류된다.\n상위 레벨에서 동작하는 스위치는 자신의 하위 레벨 스위치의 기능을 다 갖고 있다. 예를 들어 L4 스위치는 L3, L2 기능도 다 수행할 수 있다.\n\n- L2 스위치는 MAC 정보(MAC Table)를 보고 스위칭을 하는 것이다. (일반적인 스위치의 기능)\n- L3 스위치는 IP 정보(Routing Table)를 보고 스위칭을 하는 것이다. (라우팅 기능이 추가됨)\n- L4 스위치는 IP+Port(Session or Connection)를 보고 스위칭을 하는 것이다. (로드밸런싱을 위해 사용됨)\n\n----\n#### Reference\n- [스위치와 L2,L3,L4](https://startingpitcher.tistory.com/8)\n- [L1,2,3,4,7](ttps://nhj12311.tistory.com/75)\n"
  },
  {
    "path": "Network/TCP & UDP.md",
    "content": "# TCP와 UDP\n\n### 이전 글 복습하기\n\n1. [네트워크 기초 - IP](https://github.com/im-d-team/Dev-Docs/blob/master/Network/IP.md)\n2. [네트워크 기초 - SubnetMask](https://github.com/im-d-team/Dev-Docs/blob/master/Network/Subnetmask.md)\n3. [네트워크 기초 - Types of IP](https://github.com/im-d-team/Dev-Docs/blob/master/Network/TypesOfIP.md)\n4. [네트워크 기초 - OSI 7 계층과 TCP/IP 계층](https://github.com/im-d-team/Dev-Docs/blob/master/Network/OSI7%20Layer.md)\n\n- 네트워크 : 두 대 이상의 컴퓨터가 논리적 또는 물리적으로 연결되어 통신이 가능한 상태(PAN, LAN, MAN, WAN).\n- IP 주소 : 네트워킹이 가능한 장비를 식별하는 주소.\n- IPv4, IPv6\n- A, B, C 클래스 : 네트워크 영역과 호스트 영역을 구분한 기준\n  - A : `0.0.0.0` ~ `127.255.255.255`\n  - B : `128.0.0.0` ~ `191.255.255.255`\n  - C : `192.0.0.0` ~ `223.255.255.255`\n- 네트워크 주소 : 호스트 부분이 모두 0인 경우\n- 브로드캐스트 주소 : 호스트 부분이 모두 1인 경우\n- 서브넷마스크 : 네트워크와 호스트 영역을 구분하기 위한 값\n- 서브네팅 : 네트워크 관리자가 네트워크 성능을 향상하기 위해, 자원을 효율적으로 분배하는 것\n- 공인 IP : 인터넷 사용자의 로컬 네트워크를 식별하기 위해서 ISP에서 제공하는 IP 주소. 즉, 외부에 공개된 IP 주소.\n- 사설 IP : 전체 IP 대역 중 특수한 목적으로 사용하는 대역. 아래의 대역이 사설 IP 대역.\n  - A : `10.0.0.0` ~ `10.255.255.255`\n  - B : `172.16.0.0` ~ `172.31.255.255`\n  - C : `192.168.0.0` ~ `192.168.255.255`\n- 고정 IP : 고정적으로 부여된 IP로 한번 부여되면 IP를 반납하기 전까지는 다른 장비에 부여할 수 없는 IP 주소\n- 동적 IP : 장비에 고정적으로 IP를 부여하지 않고 컴퓨터를 사용할 때 남아 있는 IP 중에서 돌아가면서 부여하는 IP 주소.\n- OSI 7계층 : OSI는 `Open Systems Interconnection`의 약자로 개방형 시스템이라는 뜻이다. OSI 7계층은 네트워크에서 통신이 일어나는 과정을 7단계로 나눈 것.\n  - 물리, 링크, 네트워크, 전송, 세션, 표현, 응용\n- TCP/IP 4계층 : 네트워크 전송 시 데이터 표준을 정리한 것이 ISO 7계층이라고 한다면, 이 이론을 실제 사용하는 인터넷 표준에서 사용하는 계층.\n  - 네트워크 엑세스(물리, 링크), 인터넷, 전송, 응용(세션, 표현, 응용)\n\n## 도입 \n\n우리는 이전 시간에 OSI 7계층과 TCP/IP 계층에 대해서 배웠다. 이번에는 TCP에 대해서 알아보면서 TCP가 속한 전송계층의 다른 프로토콜과 비교해보면서 배워보자.\n\n> 전송계층은 IP에 의해 전달되는 패킷의 오류를 검사하고 재전송 요구 등의 제어를 담당하는 계층이다.\n\n## TCP (Transmission Control Protocol)\n\nTCP는 네트워크 계층 중 전송 계층에서 사용하는 프로토콜로서, 장치들 사이에 접속을 위하여 연결을 설정하여 **신뢰성을 보장**하는 연결형 서비스다. 기본적으로 TCP와 IP를 함께 사용하는데, IP가 데이터의 배달을 처리한다면 TCP는 패킷 추적 및 관리를 한다.\n\n### TCP의 특징\n\n1. 연결형 서비스\n  - 연결형 서비스로 [**가상회선 방식**](#가상회선-패킷-교환-방식)을 제공한다.\n  - [**3-way handshaking**](#tcp-connection-3-way-handshake) 과정을 통해 연결을 설정한다.\n  - [**4-way handshaking**](tcp-disconnection-4-way-handshake) 을 통해 연결을 해제한다.\n\n2. 흐름제어(Flow control)\n  - 데이터 처리 속도를 조절하여 수신자의 버퍼 오버플로우를 방지한다.\n  - 송신하는 곳에서 감당이 안되게 많은 데이터를 빠르게 보낼 때 수신하는 곳에서 문제가 일어나는 것을 막는다.\n  - 수신자가 `윈도우 크기(Window Size)` 값을 통해 수신량을 정할 수 있다.\n  \n3. 혼잡제어(Congestion control)\n  - 네트워크 내의 패킷 수가 넘치게 증가하지 않도록 방지한다.\n  - 정보의 소통량이 과다하면 패킷을 조금만 전송하여 혼잡 붕괴 현상이 일어나는 것을 막는다.\n   \n4. 신뢰성이 높은 전송(Reliable transmission)\n  - Dup [ACK](#ack-제어비트) 기반 재전송\n    - 정상적인 상황에서는 [ACK](#ack-제어비트) 값이 연속적으로 전송되어야 한다. 그러나 [ACK](#ack-제어비트)값이 중복으로 올 경우 패킷 이상을 감지하고 재전송을 요청한다.\n  - Timeout 기반 재전송\n    - 일정 시간동안 [ACK](#ack-제어비트) 값을 수신하지 못할 경우 재전송을 요청한다.\n\n5. 전이중, 점대점 방식\n    - 전이중 (Full-Duplex) : 전송이 양 방향으로 동시에 일어날 수 있다.\n    - 점대점 (Point to Point) : 각 연결이 정확히 2개의 종단점을 가지고 있다.\n\n### TCP Header 정보\n\n![TCP header](https://user-images.githubusercontent.com/24274424/88392336-c50f8900-cdf6-11ea-8d4b-018481dbb96d.png)\n\n> 출처 : [transmission-control-protocol-tcp-header](https://www.gatevidyalay.com/transmission-control-protocol-tcp-header/)\n\n| 필드 | 내용 | 크기(bit) | \n|-----|-----|-----|\n|송수신자의 포트 번호|송수신 프로세스에 할당되는 포트 주소| 16 |\n|데이터 오프셋(Data Offset)|TCP 세그먼트의 시작 위치를 기준으로 데이터의 시작 위치를 표현(TCP 헤더의 크기)|4|\n|시퀀스 번호(Sequence Number)|송신자가 지정하는 순서 번호, 전송되는 바이트 수를 기준으로 증가. SYN = 1 : 초기 시퀀스 번호가 된다. ACK 번호는 이 값에 1을 더한 값. SYN = 0 : 현재 세션의 이 세그먼트 데이터의 최초 바이트 값의 누적 시퀀스 번호\t|32|\n|응답 번호(ACK Number)|수신 프로세스가 제대로 수신한 바이트의 수를 응답하기 위해 사용.|32|\n|예약 필드(Reserved)|사용을 하지 않지만 나중을 위한 예약 필드이며 0으로 채워져야한다.|6|\n|제어 비트(Flag Bit)|SYN, ACK, FIN 등의 제어 번호 -> [아래 표 참고](#제어-비트flag-bit-정보)|6|\n|윈도우 크기(Window)|수신 윈도우의 버퍼 크기를 지정할 때 사용. 0이면 송신 프로세스의 전송 중지|16|\n|체크섬(Checksum)|TCP 세그먼트에 포함되는 프로토콜 헤더와 데이터에 대한 오류 검출 용도|16|\n|긴급 위치(Urgent Pointer)|긴급 데이터를 처리하기 위함, URG 플래그 비트가 지정된 경우에만 유효|16|\n\n### 제어 비트(Flag Bit) 정보\n\n|종류|내용|\n|-|-|\n|URG|긴급 위치를 필드가 유효한지 설정|\n|ACK|응답 번호 필드가 유효한지 설정. 클라이언트가 보낸 최초의 SYN 패킷 이후에 전송되는 모든 패킷은 이 플래그가 설정되어야 한다. 자세한 내용은 아래 추가 설명 참조|\n|PSH|수신 애플리케이션에 버퍼링된 데이터를 상위 계층에 즉시 전달할 때|\n|RST|연결의 리셋이나 유효하지 않은 세그먼트에 대한 응답용|\n|SYN|연결 설정 요구. 동기화 시퀀스 번호. 양쪽이 보낸 최초의 패킷에만 이 플래그가 설정되어 있어야 한다.|\n|FIN|더 이상 전송할 데이터가 없을 때 연결 종료 의사 표시|\n\n\n### ACK(Acknowledgement code) 제어비트\n\n- ACK는 송신측에 대하여 **수신측에서 긍정 응답**으로 보내지는 전송 제어용으로 사용된다.\n- ACK Number를 사용하여 패킷이 도착했는지 확인하며, 송신한 패킷이 제대로 도착하지 않았으면 **재송신**을 요구한다.\n\n### TCP Connection (3-way handshake)\n\nTCP 통신을 이용하여 데이터를 전송하기 위해 네트워크 연결을 설정(Connection Establish) 하는 과정\n\n1. 먼저 open()을 실행한 클라이언트가 `SYN(a)`을 보내고 `SYN_SENT` 상태로 대기한다.\n2. 서버는 `SYN_RCVD` 상태로 바꾸고 `SYN(b)`과 응답 `ACK(a+1)`를 보낸다.\n3. `SYN(b)`과 응답 `ACK(a+1)`을 받은 클라이언트는 `ESTABLISHED` 상태로 변경하고 서버에게 응답 `ACK(b+1)`를 보낸다.\n4. 응답 `ACK(b+1)`를 받은 서버는 `ESTABLISHED` 상태로 변경한다.\n\n![3-way handshake](https://user-images.githubusercontent.com/24274424/87865615-a2264480-c9b2-11ea-881e-1aa5f9e68f1c.png)\n\n> 출처 : [TCP 3 Way-Handshake](https://sleepyeyes.tistory.com/4)\n\n\n### TCP Disconnection (4-way handshake)\n\n1. 먼저 close()를 실행한 클라이언트가 FIN flag를 보내고 `FIN_WAIT1` 상태로 대기한다.\n2. 서버는 `CLOSE_WAIT`으로 바꾸고 응답 ACK를 전달한다. 동시에 해당 포트에 연결되어 있는 어플리케이션에게 close()를 요청한다.\n3. ACK를 받은 클라이언트는 상태를 `FIN_WAIT2`로 변경한다.\n4. close() 요청을 받은 서버 어플리케이션은 종료 프로세스를 진행하고 `FIN`을 클라이언트에 보내 `LAST_ACK` 상태로 바꾼다.\n5. FIN을 받은 클라이언트는 ACK를 서버에 다시 전송하고 `TIME_WAIT`으로 상태를 바꾼다. `TIME_WAIT`에서 일정 시간이 지나면 `CLOSED`된다. ACK를 받은 서버도 포트를 `CLOSED`로 닫는다.\n\n> 주의 : 반드시 서버만 CLOSE_WAIT 상태를 갖는 것은 아니다. 서버가 먼저 종료하겠다고 FIN을 보낼 수 있고, 이런 경우 서버가 FIN_WAIT1 상태가 된다. 누가 먼저 close를 요청하느냐에 따라 상태가 달라질 수 있다.\n\n![4-way handshake](https://user-images.githubusercontent.com/24274424/87865669-1e208c80-c9b3-11ea-8dba-fb42753c0da8.png)\n\n> 출처 : [TCP 4 way handshake 내용 정리](https://sjlim5092.tistory.com/37) \n\n## UDP(User Datagram Protocol)\n\nUDP는 네트워크 계층 중 전송 계층에서 사용하는 프로토콜로서, 장치들 사이에 접속을 위하여 연결을 설정하여 **신뢰성보다는 연속성이 중요한** 비연결형 서비스다. 여기서 데이터그램이란 **독립적인 관계**를 지니는 패킷이라는 뜻이다.\n\n### UDP 특징\n\n- 비연결형 서비스로 데이터그램 방식을 제공한다.\n- 정보를 주고 받을 때 정보를 보내거나 받는다는 신호절차를 거치지 않는다.\n- UDP헤더의 CheckSum 필드를 통해 최소한의 오류만 검출한다.\n- 신뢰성이 낮다.\n- TCP보다 속도가 빠르다.\n\nUDP는 비연결형 서비스이기 때문에, 연결을 설정하고 해제하는 과정이 없다. 서로 다른 경로로 독립적으로 처리함에도 패킷에 순서를 부여하여 재조립을 하거나 흐름 제어, 혼잡 제어와 같은 기능도 처리하지 않기에 TCP보다 속도가 빠르며 네트워크 부하가 적다는 장점이 있지만, 신뢰성있는 데이터의 전송을 보장하지 못한다. 그렇기 때문에 신뢰성보다는 연속성이 중요한 서비스인 실시간 서비스(streaming)에 자주 사용된다.\n\n### UPD Header 정보\n\n응용 계층으로부터 데이터를 받은 UDP도 UDP 헤더를 추가한 후에 이를 IP(네트워크 계층)로 보낸다.\n\n![UDP Header](https://user-images.githubusercontent.com/24274424/87857099-03242d00-c95f-11ea-80c5-af06d8821799.png)\n\n|필드|내용|크기(bit)|\n|--|---|--------|\n|송수신자의 포트 번호|데이터를 보내는 받는 애플리케이션의 포트 번호|16|\n|데이터의 길이|UDP 헤더와 데이터의 총 길이|16|\n|체크섬(Checksum)|데이터 오류 검사에 사용|16|\n\nTCP 헤더와 다르게 UDP 헤더에는 포함된 정보가 적다. 이는 UDP는 수신자가 데이터를 받는지 여부에 대해 관심이 없기 때문이다. 즉, 신뢰성을 보장해주지 않지만 간단하고 속도가 빠른 것이 특징이다.\n\n## 결국\n\n|TCP(Transfer Control Protocol)|UDP(User Datagram Protocol)|\n|-|-|\n|연결이 성공해야 통신 가능(연결형 프로토콜)|비연결형 프로토콜(연결 없이 통신이 가능)|\n|데이터의 경계를 구분하지 않음(Byte-Stream Service)|데이터의 경계를 구분함(Datagram Service)|\n|신뢰성 있는 데이터 전송(데이터의 재전송 존재)|비신뢰성 있는 데이터 전송(데이터의 재전송 없음)|\n|일 대 일(Unicast) 통신|일 대 일, 일 대 다(Broadcast), 다 대 다(Multicast) 통신|\n\n## One more thing\n\n패킷 교환 방식은 접속 방식에 따라서 데이터 그램 방식과 가상회선 방식이 있다.\n\n### 가상회선 패킷 교환 방식\n\n데이터를 전송하기 전에 논리적 연결이 설정되는데, 이를 가상회선이라 한다.(**연결 지향형**) 각 패킷에는 가상회선 식별 번호(VCI)가 포함되고, 모든 패킷을 전송하면 가상회선이 해제되고 패킷들은 전송된 순서대로 도착한다.\n\n데이터 그램은 패킷마다 라우터가 경로를 선택하지만, 가상회선 방식은 경로를 설정할 때 한 번만 수행한다.\n\n### 데이터그램 패킷 교환 방식\n\n데이터를 전송하기 전에 논리적 연결이 설정되지 않으며 패킷이 독립적으로 전송된다. 이를 `데이터그램`이라 한다.\n\n패킷을 수신한 라우터는 최적의 경로를 선택하여 패킷을 전송하는데 하나의 메시지에서 분할된 여러 패킷은 서로 다른 경로로 전송될 수 있다.(**비연결 지향형**)\n\n**송신 측에서 전송한 순서와 수신 측에 도착한 순서가 다를 수 있다.**\n\n### 비교\n\n정해진 시간 안이나 다량의 데이터를 연속으로 보낼 때는 **가상회선 방식**이 적합하다. 짧은 메시지의 일시적인 전송에는 **데이터그램 방식**이 적합하다. 네트워크 내의 한 노드가 다운되면 **데이터그램 방식**은 다른 경로를 새로 설정하지만, **가상회선 방식**은 그 노드를 지나는 모든 가상회선을 잃게 된다.\n\n#### Reference\n\n- [https://mangkyu.tistory.com/15](https://mangkyu.tistory.com/15)\n- [https://madplay.github.io/post/network-tcp-udp-tcpip](https://madplay.github.io/post/network-tcp-udp-tcpip)\n- [https://woovictory.github.io/2018/12/28/Network-Packet-Switching-Method/](https://woovictory.github.io/2018/12/28/Network-Packet-Switching-Method/)\n- [https://www.slideshare.net/bluem31/tcp-47441568?qid=04ddad59-7ebb-4557-99d7-50435e9a5f92&v=&b=&from_search=5](https://www.slideshare.net/bluem31/tcp-47441568?qid=04ddad59-7ebb-4557-99d7-50435e9a5f92&v=&b=&from_search=5)\n- [https://m.blog.naver.com/PostView.nhn?blogId=ksg7514&logNo=220772997742&proxyReferer=https:%2F%2Fwww.google.com%2F](https://m.blog.naver.com/PostView.nhn?blogId=ksg7514&logNo=220772997742&proxyReferer=https:%2F%2Fwww.google.com%2F)\n- [https://gmlwjd9405.github.io/2018/09/19/tcp-connection.html](https://gmlwjd9405.github.io/2018/09/19/tcp-connection.html)\n"
  },
  {
    "path": "Network/TypesOfIP.md",
    "content": "# 네트워크 기초 - Types of IP\n\n### 이전 글 복습하기\n\n[네트워크 기초 - IP](https://github.com/im-d-team/Dev-Docs/blob/master/Network/IP.md)\n[네트워크 기초 - SubnetMask](https://github.com/im-d-team/Dev-Docs/blob/master/Network/Subnetmask.md)\n\n- 네트워크 : 두 대 이상의 컴퓨터가 논리적 또는 물리적으로 연결되어 통신이 가능한 상태(PAN, LAN, MAN, WAN).\n- IP 주소 : 네트워킹이 가능한 장비를 식별하는 주소.\n- IPv4, IPv6\n- A, B, C 클래스 : 네트워크 영역과 호스트 영역을 구분한 기준\n  - A : `0.0.0.0` ~ `127.255.255.255`\n  - B : `128.0.0.0` ~ `191.255.255.255`\n  - C : `192.0.0.0` ~ `223.255.255.255`\n- 네트워크 주소 : 호스트 부분이 모두 0인 경우\n- 브로드캐스트 주소 : 호스트 부분이 모두 1인 경우\n- 서브넷마스크 : 네트워크와 호스트 영역을 구분하기 위한 값\n- 서브네팅 : 네트워크 관리자가 네트워크 성능을 향상하기 위해, 자원을 효율적으로 분배하는 것\n\n---\n\n## 어디선가 들어본 IP 종류\n\n1. 공인 IP (Public IP)\n2. 사설 IP (Private IP)\n3. 고정 IP (Static IP)\n4. 동적 IP (Dynamic IP)\n\n위 4개의 IP 종류를 봤을 수도 있고, 누구는 처음 봤을 수도 있다. 4개를 하나의 기준으로 구분하지 않는다. 대개 1번과 2번을 묶어서 설명하며, 3번과 4번을 묶어서 설명한다.\n\n그렇다면 각각의 IP는 무엇이며 왜 사람들은 1, 2를 하나로 묶고 3, 4를 하나로 묶어서 구분하는지 알아보자.\n\n## 공인 IP (Public IP)\n\n인터넷 사용자의 로컬 네트워크를 식별하기 위해서 ISP(Internet Service Provieder, 인터넷 서비스 공급자)에서 제공하는 IP 주소이다. 공용 IP 주소라고도 불리며 **외부에 공개된 IP 주소**이다.\n\n> ISP(인터넷 서비스 공급자) : 개인이나 기업체들에 인터넷 접속 서비스, 웹사이트 구축 및 웹호스팅 서비스 등을 제공하는 회사이다. 대표적으로 한국에서는 KT 인터넷, SK브로드밴드, LG U+ 등이 있다. - 출처 : 위키\n\n공인 IP는 전 세계에서 유일한 IP 주소를 갖는다.\n\n공인 IP 주소는 외부에 공개되어 있기에 인터넷이 연결된 다른 PC로부터 접근이 가능하다. 따라서 공인 IP 주소를 사용하는 경우에는 방화벽 등의 보안 프로그램을 설치할 필요가 있다.\n\nIPv4 주소는 임의로 우리가 부여하는 것이 아니다. 전 세계적으로 [ICANN](https://ko.wikipedia.org/wiki/ICANN) 이라는 기관이 국가별로 사용할 IP 대역을 관리하고 우리나라의 경우 인터넷 진흥원(KISA)에서 우리나라에서 사용하는 주소를 관리하고 있다. 임의로 아무 IP 주소나 내 컴퓨터에 지정한다고 인터넷이 되는 것이 아니라 할당받은 주소를 부여해야만 인터넷에 접속할 수 있다.\n\n### IP 부족 사태\n\nIP 부족 사태는 인터넷 발전 초기에 IP 주소를 무계획적으로 배분했기 때문에 발생하는 문제다. 대표적으로 미국의 일반 기업인 IBM이나 모토롤라 등은 초기에 인터넷 주소를 부여받으면서 A 클래스를 부여받았고, 우리나라에서도 KAIST나 서울대 등은 B 클래스를 보유하여 학교 내의 PC들에게도 마구 공인 IP를 부여하고 있다.\n\n반면 최근에 IP를 신청하는 기업은 큰 비용을 지불하고도 C 클래스 대역조차 얻기가 쉽지 않은 현실이다.\n\n## 사설 IP (Private IP)\n\n전체 IP 대역 중에서 특수한 목적으로 사용하기 위해서 몇 개의 대역을 제외하고 공인 IP 대역으로 할당하고 있는데, 제외된 대역 중에서 사설 IP로 사용되는 대역은 사용자가 임의로 부여하고 사용할 수 있지만 인터넷상에서 서로 연결되지 않게 되어 있다. 전체 IP 대역 중에서 다음의 대역이 사설 IP 대역이다\n\n### 사설 IP 주소 대역\n\n사설 IP 주소는 다음 3가지 주소 대역으로 고정된다.\n\n- Class A : `10.0.0.0` ~ `10.255.255.255`\n- Class B : `172.16.0.0` ~ `172.31.255.255`\n- Class C : `192.168.0.0` ~ `192.168.255.255`\n\n사설 IP 주소만으로는 인터넷에 직접 연결할 수 없다. 라우터를 통해 1개의 공인(Public) IP만 할당하고, 라우터에 연결된 개인 PC는 사설(Private) IP를 각각 할당받아 인터넷에 접속할 수 있다.\n\n## 고정 IP (Static IP)\n\n고정 IP는 컴퓨터에 고정적으로 부여된 IP로 한번 부여되면 IP를 반납하기 전까지는 다른 장비에 부여할 수 없는 IP 주소를 말한다.\n\n개인적으로 하나의 서버를 운영해야 한다면 고정 IP를 사용해야 한다. 그렇지 않으면 우리가 할당받는 IP는 유동 IP로 일정 시간 사용하지 않게 되면 IP가 바뀌게 된다. 그렇게 될 경우 서버로 사용하는 사용자에게 문제가 발생하게 된다.\n\n이에 서버로 사용하는 경우 고정 IP를 사용한다.\n\n## 동적 IP (Dynamic IP)\n\n동적 IP는 장비에 고정적으로 IP를 부여하지 않고 컴퓨터를 사용할 때 남아 있는 IP 중에서 돌아가면서 부여하는 IP를 뜻한다. 유동 IP라고도 불린다.\n\n부여받은 IP가 10개이고 접속해야 할 컴퓨터가 20대라면 10대는 고정 IP를 부여할 경우 IP가 모자라므로 유동 IP로 10개를 20대가 돌아가면서 사용하여 자원을 조금 더 효율적으로 사용하는 것이다.\n\n## 결국\n\n우리가 집에서 사용하는 인터넷 서비스 업체는 가정마다 공인 IP를 동적 IP로 부여하고, 공유기 내부에서는 사설 IP를 동적 IP로 부여하는 것이 일반적이라고 보면 될 것이다.\n\n## One more thing...\n\n### NAT (Network Address Translation)\n\nNAT는 네트워크 주소를 변환시켜주는 기술을 말하며, NAT의 장점은 하나의 공인 IP를 여러 사람이 공유해서 쓸 수 있게 해주며, 외부 공공망으로 부터 고유한 사설망으로의 침입을 어느 정도 방지해줄 수 있는 특징이 있다. NAT의 예를 보면 공유기를 통해 여러 디바이스를 하나의 아이피로 연결해서 사용할 수 있게 해주는 기술이다.\n\n- SNAT(Source NAT) : 내부 사설 IP에서 외부 공인 IP로 변환\n- DNAT(Destination NAT) : 외부 공인 IP에서 내부 사설 IP로 변환\n\n#### Reference\n\n- [공인(Public) && 사설(Private) IP의 차이점](https://velog.io/@hidaehyunlee/%EA%B3%B5%EC%9D%B8Public-%EC%82%AC%EC%84%A4Private-IP%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%A0%90)\n- [공인 IP, 사설 IP, 고정 IP, 유동 IP](http://gotocloud.co.kr/?p=320)\n- [공인아이피 사설아이피 정의 및 이해 : 네이버 블로그](https://m.blog.naver.com/mogni/70183970559)\n"
  },
  {
    "path": "Network/comet.md",
    "content": "# comet\n \n## Http 통신 방식  \n\nHTTP는 클라이언트의 요청이 있을 때만 서버가 응답하여 처리한 후에 연결을 끊는 **단방향 통신**이다.  \n따라서 서버에서 클라이언트로 데이터를 전송하는 **Server Push** 가 불가능하다.   \n하지만 실시간으로 변하는 데이터를 클라이언트에게 전달하기 위해 양방향 통신의 필요성이 대두되었다.  \n이에 클라이언트가 양방향 통신이 되고 있는 것처럼 느낄 수 있도록 하는 일종의 편법, **comet** 이 고안되었다.  \n즉, comet은 실시간으로 작동하는 것이 아니라 짧은 시간 간격으로 웹페이지를 업데이트 하는 방법이다.  \ncomet에는 `Polling`, `Long Polling`, `Streaming` 등이 있다. \n\n\n<br/>\n\n## Polling  \n\n![polling](/assets/images/polling.png)  \n\nPolling은 클라이언트가 서버에 **주기적으로** 요청을 보내는 방식으로, 다음과 같은 특징을 갖는다.    \n\n* 시간마다 요청이 일괄적으로 전달된다. \n* 실시간 통신이 중요한 서비스에 적합하지 않다.  \n실시간으로 통신하는 느낌을 주기 위해 요청 시간의 간격을 줄일 수 있으나 이는 서버에 무거운 부하를 주게된다.  \n이유는 다음의 프로세스를 반복해야 하기 때문이다. \n\n    ```\n    요청 발생 -> 연결 생성 -> HTTP header 파싱 -> 쿼리 수행 -> 응답 생성 -> 응답 전송 -> 연결 닫음\n    ```   \n    \n* 또한, 서버에서 보낼 데이터가 없어도 데이터를 전송해야하므로 서버의 리소스를 낭비하게 된다. \n\n스포츠 경기를 시청하던 중 네이버의 실시간 중계 서비스를 확인하면, 경기 현황이 실시간으로 반영되지 않는 순간을 본 적이 있을 것이다. 바로 이와 같은 서비스를 Polling 방식을 따르는 서비스라고 할 수 있다.\n\n\n<br/>\n\n## Long Polling  \n\n![Longpolling](/assets/images/LongPolling.png) \n\nLong Polling은 위에서 언급한 Polling의 문제점을 해결하기 위한 방식으로, 클라이언트로부터 받은 요청을 유지하다가 데이터가 발생한 후(즉, 서버 이벤트가 발생되는 시점)에 응답을 전송하는 방식이다.  \n단, 요청을 무한히 유지하는 것이 아니라 time out이 발생하면 해당 요청/응답 트랜잭션을 완료하고 연결을 새로 생성한다.   \nLong Polling의 특징은 다음과 같다.\n\n* 항상 연결이 유지되어 있기 때문에 사실상 실시간 통신이 가능하다.\n* 데이터 이동이 빈번하지 않은 서비스에 적합하다.   \nLong Polling 방식의 채팅방에 1000명이 참여하고 있다고 가정해보자. 한명이 메시지를 연달아 계속해서 보낸다면, 1000명의 Request Queue가 순간적으로 쌓이게 되며 서버에 부하가 생길 수 있다.   \n또한 HTTP는 header가 무거운 프로토콜이기 때문에 요청의 증가에는 많은 비용이 따른다.\n\n<br/> \n\n## Streaming\n\n![streaming](/assets/images/streaming.png) \n\nStreaming 방식은 연결을 계속 유지하고, 이벤트가 발생할 때마다 부분적인 응답으로 브라우저에 데이터를 보내는 방식이다.  \n응답마다 다시 요청해야 하는 Long Polling에 비해 효율적이며, 서버의 상태 변경이 매우 잦은 경우 유리하다. \n\n<br/>\n\n#### Reference\n\n[Long Polling - Concepts and Considerations](https://www.ably.io/concepts/long-polling)  \n[RTCS 실시간 웹 서비스를 위한 도전](https://d2.naver.com/helloworld/1052)  \n[웹채팅 구현시 Long-Polling 방식과 Polling방식 선택하기](https://kuimoani.tistory.com/entry/%EC%9B%B9%EC%B1%84%ED%8C%85-%EA%B5%AC%ED%98%84%EC%8B%9C-Long-Polling-%EB%B0%A9%EC%8B%9D%EA%B3%BC-Polling%EB%B0%A9%EC%8B%9D-%EC%84%A0%ED%83%9D%ED%95%98%EA%B8%B0)\n"
  },
  {
    "path": "Network/congestion control.md",
    "content": "# congestion control(혼잡 제어)\n\n저번 시간에는 송신 측과 수신 측의 데이터 처리 속도를 해결하기 위해 쓰이는 `flow control`에 대해 조사를 하였다.\n\n이번 시간에는 `congestion control`에 대해 조사를 해보았다.\n\n`congestion control`이란 송신 측의 데이터 전달과 네트워크의 **데이터 처리 속도 차이**를 해결하기 위한 기법이다. \n\n송신 측의 데이터는 지역망이나 인터넷으로 연결된 대형 네트워크를 통해 전달된다. 이러한 네트워크상의 라우터가 항상 한가로운 것은 아니기 때문에 데이터가 급격히 몰릴 경우 문제가 발생한다.\n\n만약, 한 라우터에 데이터가 몰릴 경우(=혼잡할 경우) 라우터는 자신에게 온 데이터를 모두 처리할 수 없다. 그렇다면 송신 측에서 데이터를 다시 재전송을 하게 되고 혼잡을 가중하고 오버플로우가 발생해 데이터 손실을 야기시킨다.\n\n따라서, 이러한 네트워크의 혼잡을 피하고자 송신 측에서 보내는 데이터의 전송 속도를 강제로 줄이는 것을 혼잡제어라 한다.\n\n흐름 제어는 송신 측과 수신 측 사이의 전송속도를 다루는 데에 반해 혼잡제어는 호스트와 라우터를 포함한 보다 넓은 관점에서의 전송 문제를 다루게 된다.\n\n혼잡 제어 알고리즘에는 네 가지가 있다.\n\n1. AIMD (Additive/Multicative Decrease)\n2. Slow start (느린 시작)\n3. Fast Retransmit (빠른 재전송)\n4. Fast Recovery (빠른 회복)\n\n하나씩 살펴보기 전에 `MSS`에 대해 알고 넘어가야 한다.\n\n## 혼잡 윈도우 크기 초기화하기\n통신을 하는 중간에는 `ACK`가 유실된다거나 타임아웃이 난다거나 하는 등의 정보를 사용하여 네트워크의 혼잡 상황을 유추할 수 있지만, \n통신을 시작하기 전에는 그런 정보가 하나도 없기 때문에 혼잡 윈도우 크기를 정하기가 조금 애매하다. 여기서 등장하는 것이 바로 `MSS(Maximum Segment Size)`이다. \n\n`MSS`는 한 세그먼트에 최대로 보낼 수 있는 데이터의 양을 나타내는 값인데, 대략 다음과 같은 계산을 통해 구할 수 있다.\n> MSS = MTU - (IP헤더길이+IP옵션길이) - (TCP헤더길이+TCP옵션길이)\n\n여기서 `MTU(Maximum Transmission Unit)` **한번 통신할 때 보낼 수 있는 최대 단위를 의미한다.**\n\n즉, `MSS`는 한번 전송할 때 보낼 수 있는 최대 단위가 정해져 있는 상황에서 IP 헤더, TCP 헤더 등 데이터가 아닌 부분을 전부 발라내고 **데이터를 담을 수 있는 공간**이 얼마나 남았는지를 나타내는 것이다.\n\n![MTU](https://user-images.githubusercontent.com/43868540/95658420-2ffa7180-0b55-11eb-8913-594d8438ac87.PNG)\n> 우리집 컴퓨터의 MTU값.\n\nMTU 기본값으로 `1500 bytes`가 설정되어 있는 것을 확인 할 수 있다. OSX는 기본적으로 `MTU`를 `1500 bytes`로 설정한다.\n\n이때 TCP와 IP의 헤더크기가 각각 `20bytes`라고 하면 MSS는 `1500-40=1460bytes`가 되는 것이다.\n\n## AIMD\n`AIMD (Additive/Multicative Decrease)` 방식은 우리 말로 직역하면 **합 증가/곱 감소 방식**이라는 뜻이다.\n\n즉, 네트워크에 아직 별문제가 없어 전송 속도를 더 빠르게 하기 위해서 `cwnd`를 **1씩 증가**시킨다. 하지만 중간에 데이터가 유실되거나 응답이 오지 않는 등의 혼잡 상태가 감지되면 `cwnd`를 **반**으로 줄인다.\n>  cwnd란 혼잡 윈도우 크기로 송신 측에 있는 윈도우 크기이다. 쉽게 말해서 한번에 전송할 수 있는 데이터양이다.\n\n늘어날 때는 `cwnd+1`, 줄어들 때는 `cwnd*0.5`이다.\n\n이렇게 늘어날 때는 선형적으로 조금씩 늘어나고 줄어들 때는 반으로 확 줄어드는 `AIMD`의 특성때문에 혼잡 윈도우 크기를 그래프로 그려보면 다음과 같은 톱니 모양이 나타난다.\n\n![AIMD](https://user-images.githubusercontent.com/43868540/94355427-eb83c600-00be-11eb-83aa-cf7377e5df8c.png)\n- [출처 evan-moon.github](https://evan-moon.github.io/2019/11/26/tcp-congestion-control/)\n\n그러나 `AIMD`의 문제점은 네트워크 대역이 많이 남아도는 상황에도 윈도우 크기를 너무 조금씩 늘리면서 접근한다는 것이다.\n\n그런 이유로 `AIMD`은 네트워크의 모든 대역을 활용하여 제대로 된 속도로 통신하기까지 시간이 조금 걸린다. \n\n## Slow Start\n요즘 네트워크의 발전으로 인해 네트워크의 혼잡 상황이 발생하는 빈도가 많이 줄어들었다. 이에 따라 혼잡이 발생하지도 않았는데 제대로 속도를 내는 데까지 오래 걸리는 `AIMD` 방식의 단점이 점점 부각되었다. 이를 해결하기 위해 `Slow Start`의 개념이 등장한다. \n\n`Slow Start`는 기본적인 원리는 `AIMD`와 비슷하다. 윈도우 크기를 증가시킬 때는 지수적으로 증가시키다가 손실 이벤트(혼잡)가 있으면 윈도우 크기를 `1`로 줄여버리는 방식이다.\n\n이 방식은 보낸 데이터의 `ACK`가 도착할 때마다 윈도우 크기를 증가시키기 때문에 처음에는 윈도우 크기가 조금 느리게 증가할지 몰라도, 시간이 가면 갈수록 `ACK`의 수도 늘어나기 때문에 윈도우 크기가 점점 빠르게 증가한다는 특징이 있다.\n\n![slow start](https://user-images.githubusercontent.com/43868540/95658695-502b3000-0b57-11eb-9ebc-5a05d5d725ba.PNG)\n> [출처 evan-moon.github](https://evan-moon.github.io/2019/11/26/tcp-congestion-control/)\n\n`slow start`의 차트를 확인해보면 `AIMD`보다는 급격하게 윈도우 크기가 커지고 급격하게 `1`로 감소하는 것을 확인해 볼 수 있다. \n\n하지만 윈도우 크기가 기하급수적으로 늘어나면 제어가 힘들어지고 네트워크의 혼잡 또한 빈번하게 발생하게 된다. 그럴 때마다 계속 윈도우 사이즈를 `1`로 줄이는 것이 효율적이지 않을 것이다.\n따라서 빠르게 값을 증가시키는 것보다는 `AIMD`보다는 빠르게, 조금씩 증가시키는 편이 훨씬 안전할 것이다. \n\n이때 나오는 개념이 `Slow start 임계점`이다.\n\n### Slow start 임계점(ssthresh)\n`ssthresh`는 쉽게 말하면 `여기까지만 Slow Start를 사용하겠다.`라는 의미를 가진다. \n\n![ssthresh](https://user-images.githubusercontent.com/43868540/95659718-ec583580-0b5d-11eb-9a11-6fd269d690c4.PNG)\n> [출처 evan-moon.github](https://evan-moon.github.io/2019/11/26/tcp-congestion-control/)\n\n`Slow Start` 상태에서는 확인 응답(ack)를 받을 때마다 가용 폭을 `1MSS`부터 `1MSS`씩 증가시킨다. `MSS`가 늘어나면 그에 따라 확인 응답(ack)도 늘어나는데, 그 늘어난 확인 응답이 `MSS`도 또다시 증가시키기 때문에 결국에는 기하급수적으로 늘어나는 지수적 증가가 된다.\n\n이런 지수적 증가는 Timeout에 의한 손실 이벤트(혼잡)가 있으면 끝나게 되는데, 가장 보수적으로 `cwnd`값을 다시 `1`로 줄이게 된다.\n\n그래서 특정한 임계점(Threshold)을 정해놓고, 임계점을 넘어가게 되면 `AIMD` 방식을 사용하여 선형적으로 윈도우 크기를 증가시킨다. 그래서 이 임계점을 칭하는 단어가 `ssthresh(Slow Start Threshold)`인 것이다.\n\n송신 측은 본격적인 통신이 시작하기 전에 `ssthresh` 값을 자신의 혼잡 윈도우의 절반 크기인 `0.5 MSS`으로 초기화하고, 통신을 시작한다.\n\n## Fast Retransmit\n빠른 재전송은 TCP의 혼잡 조절에 추가된 정책이다. 저번 시간에 배웠듯이 수신 측에서 보내는 `ACK` 패킷은 다음 받을 패킷의 순번을 실어서 보내게 된다.\n\n하지만 송신 측에서 패킷을 보내다가 손실되게 되면 수신 측에서는 `ACK` 패킷에 유실된 패킷의 번호를 담아서 보내게 된다.\n송신 측은 순번이 중복된 `ACK` 패킷을 받게 되고, 중복된 순번의 패킷을 3개 연속으로 받으면 재전송을 하게 된다. \n\n같은 순번의 패킷을 3개 연속으로 받으면 혼잡임을 감지하고 `cwnd`를 줄이게 된다.\n\n![Fast Transmit](https://user-images.githubusercontent.com/43868540/95826607-83470c80-0d6d-11eb-9f58-8bcaf0704e42.PNG)\n> [출처 movefast.tistory](https://movefast.tistory.com/36) \n\n## Fast Recovery\n빠른 회복은 `Slow Start`로 인해 `cwnd`를 `1MSS`로 떨어뜨리게 된다면 다시 데이터의 흐름 속도를 회복하는데 오래 걸릴 것이다. \n그렇기 때문에 빠르게 회복하기 위해 두 가지의 방법이 쓰인다.\n\n**1. TCP Tahoe**\n\n`TCP Tahoe`는 `Slow Start`를 사용한 혼잡 제어 정책의 초기 버전으로, `빠른 재전송` 기법이 처음으로 도입된 방법이다. `Tahoe`는 처음에는 `Slow Start`를 사용하여 자신의 윈도우 크기를 지수적으로 빠르게 증가시키다가 `ssthresh`를 만난 이후부터는 `AIMD`에서 사용하는 합 증가 방식을 사용하여 선형적으로 윈도우 크기를 증가시킨다. 그러다가 `ACK Duplicated`나 `Timeout` 즉, 손실이벤트가 발생하면 네트워크에 혼잡이 발생했다고 판단하고, `ssthresh`와 자신의 `cwnd`를 무조건 **`1MSS`로 줄이고**, `slow Start` 단계로 들어간다.\n\n**2. TCP Reno**\n\n`Tahoe` 이후에 나온 버전으로 **손실의 종류**에 따라 `cwnd`를 수정하는 방식이 다르다. 우선, **3개의 중복 ACK에 의한 손실이 발생**하면 `cwnd` 크기를 `1MSS`로 줄이는게 아니라 현재 **cwnd 크기의 절반**으로 줄인 다음 `1MSS`씩 선형으로 증가를 시킨다. 하지만 만약 **타임아웃에 의한 손실**이라면 `Tahoe`와 마찬가지로 **`1MSS`로 초기화** 되고 `Slow Start`를 진행한다.\n\n![congestion control](https://user-images.githubusercontent.com/43868540/95659402-ba45d400-0b5b-11eb-8561-5ee1718ec8f1.PNG)\n > 출처 [blog.naver](http://blog.naver.com/PostView.nhn?blogId=sjc02183&logNo=221686794605&parentCategoryNo=&categoryNo=55&viewDate=&isShowPopularPosts=false&from=postView)\n \n위 그림을 보면 9라운드부터 Tahoe와 Reno의 모양이 달라지는 것을 확인할 수 있다.\n\n손실 발생 시, `TCP Tahoe`는  `1MSS`로 떨어진다. 반면에 `TCP Reno`는 중복 ack가 3개 발생했을 때는 절반으로,  타임아웃으로 인한 패킷 손실이면 `1MSS`로 떨어진다.\n\n----\n#### Reference\n- [TCP의 혼잡제어](https://evan-moon.github.io/2019/11/26/tcp-congestion-control/)\n- [혼잡제어](https://ko.wikipedia.org/wiki/%ED%98%BC%EC%9E%A1_%EC%A0%9C%EC%96%B4)\n"
  },
  {
    "path": "Network/get&post.md",
    "content": "# GET & POST\n\nGET과 POST는 HTTP를 이용해서 서버에 무언가를 전달하는 방법(method)이다.\n\n<br/>\n\n## 들어가기 전에...\n\nHTTP는 클라이언트와 서버가 소통하기위해 만들어진 프로토콜로, HTTP메세지를 서로 주고 받는다.\n\n![get&post](/assets/images/get&post.png)\n\n<br/>\n\n## GET Method\n\nGET은 서버에 있는 **정보를 조회**할때 사용된다. 따라서 전송되는 정보는 요청(request)을 위한 것이다.\n\n데이터를 Body에 담지 않고 **URL형태(쿼리 스트링)로 표현**한다. 따라서, URL형식에 맞지 않은 데이터는 인코딩하여 전달하여야 한다.\n> URL은 [퍼센트 인코딩](https://ko.wikipedia.org/wiki/%ED%8D%BC%EC%84%BC%ED%8A%B8_%EC%9D%B8%EC%BD%94%EB%94%A9)을 한다.\n> 예시는 다음과 같다.\n> ```html\n> https://ko.wikipedia.org/wiki/퍼센트_인코딩 <!-- 아래와 같이 인코딩 된다.-->\n> https://ko.wikipedia.org/wiki/%ED%8D%BC%EC%84%BC%ED%8A%B8_%EC%9D%B8%EC%BD%94%EB%94%A9\n> ```\n\n<br/>\n\n데이터를 쿼리스트링으로 표현하여 전송하기 때문에, **body가 빈 상태**로 전송된다. 또한 헤더에 content-type이 들어가지 않는다. \n\n```\nhttp://example.com/date.html?key=value&key=value\n```\n\n`?` 뒤에 key와 value의 쌍을 전송하고, `&`구분자를 통해 데이터를 나열한다.\n\n> content-type : 데이터 설명 및 타입 명시\n\n### 특징\n\n* 캐싱이 가능하다.\n\n* 브라우저 기록에 남는다.\n\n* 북마크 될 수 있다.\n\n* 절대  민감한 데이터를 다루면 안된다.\n\n* 길이 제한이 있다.\n\n* 데이터 요청에 사용된다(수정불가)\n\n<br/>\n\n## POST Method\n\nPOST는 서버의 리소스를 **생성하거나 수정**하기 위해 데이터를 보내는 것이다. **데이터는 body에 저장되어 전송**된다.\n\n```\nPOST /target.html HTTP/1.1\nHost: example.com\nContent-Type: text/html; charset=utf-8\nname1=value1&name2=value2\n```\n\n헤더필드에 content-type이 들어간다.\n\n### 특징\n\n* 캐싱 사용 불가\n\n* 브라우저 기록에 남지 않는다.\n\n* 북마크 될 수 없다.\n\n* 데이터 길이제한이 없다.\n\n<br/>\n\n## 언제 써야하는가?\n\n### GET은 가져오는 것\n\nGET은 sql에 비유하면, SELECT적인 성향을 가진다. GET은 서버에서 데이터를 가져와서 보여주고 싶을 때 사용하는 것이다. 서버의 값이나 상태등을 바꾸지 않는다. 검색을 하거나 게시판의 글을 볼 때 주로 사용된다.\n\n<br/>\n\n### POST는 수행하는 것\n\n서버의 값이나 상태를 바꾸기 위해 사용된다. 예를들어, 글쓰기를 하면 글의 내용이 서버에(DB) 저장되고, 수정을 하면 서버의 값이 수정되는 것이다.\n\n<br/>\n\n### 더 나아가서\n\n기본적으로 두 방식 모두 클라이언트 측에서 볼 수 있기 때문에 보안을 위해서는 암호화 해야한다.\n\nGET방식의 요청은 캐싱(데이터저장)때문에 더 빠르다.\n\n하지만, 비밀번호와 같은 민감한 정보의 경우 GET방식 대신 POST를 사용하여야 한다. 정보가 URL에 그대로 드러나는 문제도 있다. 또한, get방식은 requset를 통해 보낸 parameter가 브라우저에 기록에 남아 있는 방식이다. 반면, post는 parameter가 브라우저 기록이나 웹 서버 로그에 남지 않는다.\n\n위와 같은 이유로 GET방식은 새로고침과 무관하지만, POST방식은 새로고침이나 뒤로가기한 뒤 페이지에 새로 접근하게되면 데이터가 다시 제출된다.\n\n<br/>\n\n------\n\n#### Reference\n\n* <https://blog.outsider.ne.kr/312>\n* <https://mommoo.tistory.com/60>\n* <http://www.ktword.co.kr/abbr_view.php?m_temp1=4884>\n* <https://www.w3schools.com/tags/ref_httpmethods.asp>\n"
  },
  {
    "path": "Network/http-caching.md",
    "content": "# HTTP caching\n\n웹 자원을 요청할 때 같은 자원을 재요청하지 않기 위해 사본을 만들어 저장하는 데 이를 캐싱이라 한다.\n\n아주 간단한 예로 랜딩 페이지의 로고 같은 것은 랜딩 페이지를 도착할 때마다 요청한다. 이를 캐싱해놓으면 재요청을 보내지 않음으로 네트워크 트래픽을 줄인다.\n\n네트워크 트래픽 말고도 장점이 한 가지 더 있다.\n통신은 물리적인 거리와도 연관이 있다. 그 속도마저 너무 빨라 우리 눈에 보이지는 않지만, 거리에 따라 속도가 다르다.\n\n만일 실제 서버와 클라이언트의 물리적인 거리가 멀고 요청하는 자원의 크기가 크고 양이 많다면 속도가 느려질 수 있다.\n쉽게 유튜브를 떠올리자.\n유튜브의 실제 서버가 미국에 있다고 가정하면 한국 클라이언트들은 미국 클라이언트들보다 현저히 응답 속도가 느릴 수 있다.\n이 때 한국에 캐시 서버를 만들어 이 문제를 해결할 수 있다.\n\n## 캐싱의 종류\n\n캐싱에는 public, private로 크게 두 가지 종류가 있다. 거창한 것은 아니다.\n\n### public caching\n\npublic caching의 다른 명칭으로는 proxy cache, cache proxy server 등으로도 부른다.\n\n큰 회사나 ISP(Internet Service Provider)의 방화벽에 설치된다.\n\n### private caching\n\n브라우저가 저장하는 캐시다. 브라우저는 자주 쓰이는 자원을 개인용 컴퓨터의 디스크와 메모리에 캐시해 놓은 후 불러온다.\n\n![caching-in-browser](https://user-images.githubusercontent.com/24724691/61453854-32920980-a99a-11e9-91ba-728a2aaf2e18.PNG)\n\n브라우저에서 개발자도구를 열면 위와 같은 화면을 볼 수 있다.\n\n## Cache-control\n\n캐시를 컨트롤하는 방법이다. 이 자원은 필히 캐시 되어야 한다 / 캐시 되면 안된다 / 캐시된 자원을 24시간 동안만 사용하고 그 뒤로는 다시 받아라 등의 명령을 내리는 것이 캐시 컨트롤이다.\n\n현대의 브라우저에서는 이 HTTP-header를 이용하여 캐시 컨트롤을 한다.\nheader는 HTTP 1.0과 1.1버전에 따라 조금 다르다.\n\n|            | 1.0 req           | 1.0 res       | 1.1 req       | 1.1 res       |\n| ---------- | ----------------- | ------------- | ------------- | ------------- |\n| validation | If-Modified-Since | Last-Modified | If-None-Match | ETag          |\n| freshness  | Pragma            | Expires       | Cache-Control | Cache-Control |\n\n### Cache-control header\n\n![cache-control](https://user-images.githubusercontent.com/24724691/61639150-e31f4680-acd5-11e9-9381-d9114d619497.PNG)\n\n위 사진과 같이 사용하는 것이 cache-control 헤더다.\n\ncache control의 헤더는 request, response 모두 사용이 가능하다.\n\n`Cache-Control: no-store`\n`Cache-Control: no-cache, no-store, must-revalidate`\n\n위와 같이 두 가지 표기법 모두 사용할 수 있다.\n\n- `Cache-Control: no-store` : 캐시 하지 않음. 캐시를 저장(store)하지 않음을 의미하며 사본을 만드는 것을 금지한다.\n- `Cache-Control: no-cache` : 사본을 저장은 한다. 즉 캐싱은 발생하지만, 서버와 재검사(revalidation) 과정을 거치고 클라이언트에게 제공된다. 영문으로는 **DO NOT Serve from cache without revalidation** 가 더 정확한 표현일 것이다.\n- `Pragma: no-cache` : no-cache와 동일하지만 1.0방식임.\n\n`no-store, no-cache`는 검증되지 않은 캐시가 제공되는 것을 막는다.\n\n- `Cache-Control: private` : private caching에서만 가능\n- `Cache-Control: public` : 모두 가능\n- `Cache-Control: max-age=<seconds>` : cache가 유효한 시간. 즉 freshness를 보장할 수 있는 시간을 말한다. 요청을 보냈던 시간으로부터 상대적인 시간을 나타내며 초로 표기한다.\n- `Cache-Control: s-maxage=<seconds>` : shared(공유)에서만 작동. 즉 public에서 작동함. maxage의 하이픈이 변경된 것에 주의하자.\n- `Cache-Control: must-revalidate` : 특정한 상황(네트워크 연결 끊김)일 때 freshness 하지 않아도 캐시 파일을 제공하는 경우가 있다. 이를 막는다.\n- `Cache-Control: proxy-revalidate` : shared(proxy)에서 작동하는 revalidate\n- `Cache-Control: no-transform` : 이미지와 같은 리소스들에 저장 최적화를 위해 포맷하는 경우를 막는다.\n\n## 캐시 동작 방식\n\n버전이 다르면 동작 방식도 조금 다르므로 모두 알아보자.\n\n### 공통\n\n캐시가 동작하는 공통 로직은 다음과 같다.\n\n최초 요청 후 응답헤더에 `Last-Modified, Etag, Expires, Cache-Control: max-age` 항목이 존재한다면 캐시 한다.\n\n### 1.0\n\n1.0 방식에서는 응답 헤더에 Expires를 받는다.\n\n`Expires: 19 July 2019`\n\n유효기간의 절댓값을 받기 때문에 이 절댓값을 클라이언트의 시간과 비교한다. 기간이 만료되었다면 서버를 거치지 않고 캐시한 자원을 사용한다.\n\nExpires가 지난 경우 validation 작업을 진행한다.\n\n브라우저는 최초 응답 헤더의 Last-Modified 값을 If-Modified-Since의 값으로 설정하여 요청을 보낸다.\n\n> 브라우저 ==== `If-Modified-Since: 10 July 2019` ===> 서버\n\n`10 July 2019`가 Last-Modified 값이다.\n\n서버는 이 요청을 받아 서버 자원의 마지막 수정날짜가 동일하다면 변동되지 않았다고, 동일하지 않으면 변동되었다고 판단한다.\n변동되지 않았으면 304(Not Modified)번, 변동되었다면 200번 코드와 함께 새로운 자원을 내려보낸다.\n\n### 1.1\n\n1.1 방식에서는 응답 헤더에 max-age를 받는다.\n\n`Cache-Control: max-age=3600`\n\n상댓값이며 요청 시간(request를 보낸 시간)을 기준으로 계산한다. 기간이 만료되었다면 서버를 거치지 않고 캐시한 자원을 사용한다.\n\n유효 기간이 지났다면 역시 validation 작업을 진행한다.\n\n1.1은 Etag(Entity Tag)를 사용한다.\n\n1.0과 비슷하게 Etag값을 If-None-Match의 값으로 설정하여 요청을 보낸다.\n\n> 브라우저 ==== `If-None-Match: e1qwok/-qwe1` ===> 서버\n\n서버는 자원이 갱신되면 항상 Etag값을 갱신한다. 따라서 값이 같다면 변동되지 않았으므로 304, 다르다면 변동된 파일이므로 200번 값을 응답한다.\n\n### 우선순위\n\n브라우저는 1.1 방식을 우선 탐색한다. 만일 `Cache-Control`과 같은 것이 없다면 1.0방식이 있는지 찾게 된다.\n\n`Cache-Control, Expires`가 모두 없다면 `Last-Modified`를 기준으로 [휴리스틱 방법](https://ko.wikipedia.org/wiki/%ED%9C%B4%EB%A6%AC%EC%8A%A4%ED%8B%B1_%EC%9D%B4%EB%A1%A0)을 이용하여 어림짐작한다.\n\n휴리스틱 추측 중 하나로 LM인자 알고리즘이 있는데 간단하게만 알아보자.\n\n- 캐시된 문서의 `Last-Modified`(변경된 날짜)가 오래전이라면 자주 변경되지 않으므로 조금 더 가지고 있어도 괜찮을 것이다.\n- 캐시된 문서가 최근에 변경되었다면 자주 변경되는 문서이므로 짧게 캐시 해야 할 것이다.\n\n이러한 기준을 바탕으로 브라우저마다 조금씩 다르게 유효기간을 정한다.\n\n예를 들어 크롬은 `freshnessLifeTime = (headerDate - lastModified) / 10`을 사용한다.\n\n---\n\n### 참고자료\n\n- [HTTP 캐싱](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching?hl=ko)\n- [HTTP caching](https://developer.mozilla.org/ko/docs/Web/HTTP/Caching)\n- [Cache-Control](https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/Cache-Control)\n- [알아둬야 할 HTTP 쿠키 & 캐시 헤더](https://www.zerocho.com/category/HTTP/post/5b594dd3c06fa2001b89feb9)\n- [더 빠른 웹을 위하여](https://cyberx.tistory.com/9)\n- [휴리스틱 이론](https://ko.wikipedia.org/wiki/%ED%9C%B4%EB%A6%AC%EC%8A%A4%ED%8B%B1_%EC%9D%B4%EB%A1%A0)\n- HTTP 완벽가이드 - 웹은 어떻게 동작하는가, 인사이트ORIEILLY\n"
  },
  {
    "path": "Network/로드밸런싱 & 클러스터링.md",
    "content": "# 로드밸런싱 & 클러스터링\n\n한 웹 사이트에 접속자가 한 두명이 아닌 수천명이 접속한다면 서버는 모든 접속자에게 응답해주려고 하지만 결국 동작을 멈추게 될 것이다. <br/>예를 들면, 선착순 이벤트에서 동시 접속자 수가 급격하게 증가했을 때 서버가 죽는 것이 이와 같은 경우다.\n\n<br/>\n\n## 성능 개선 방식\n\n- **`scale-up`** : 하드웨어의 성능을 높여 서버가 빠르게 동작하도록 하는 방식\n- **`scale-out`** : 여러 대의 서버가 나눠서 동작하도록 하여 성능을 개선하는 방식\n\n`scale-out`방식은 `scale-up`방식에 비해 **비용이 적게 들고 여러 대의 서버 덕분에 무중단 서비스를 제공**할 수 있다.\n로드밸런싱과 클러스터링은 모두 `scale-out`방식이다.\n\n<br/>\n\n## 로드밸런싱\n\n로드밸런싱이란 트래픽이 많을 때 가상 IP를 통해 여러 서버에 접속하도록 분배하는 기능이다.\n\n로드밸런싱을 이용하면 **한 서버가 내려가더라도 이중화시킨 다른 서버에서 서비스를 지속하도록 할 수 있기 때문에 접속자들이 문제 없이 서비스를 이용**할 수 있다.\n\n로드밸런싱의 문제는 **세션(Session)** 이다.<br/>세션이 저장된 서버가 아닌 다른 서버에 접속하게 되는 경우, 해당 클라이언트의 세션이 유지되지 않기 때문이다.\n\n세션을 고정(session sticky)함으로써 이를 해결 할 수 있다. 이 방법으로 특정 사용자의 요청이 전달될 노드를 고정시킬 수 있다.<br/> 하지만 **고정된 세션의 노드에 장애가 발생하면 고정한 의미가 없어지기 때문에 장애가 발생하여 비활성화된 노드에 대한 고려가 필요**하다.\n\n<br/>\n\n### 로드밸런서의 Server 선택 기준\n\n---\n\n- **Round Robin** : 단순히 Round Robin으로 분산하는 방식이다.\n\n- **Least Connections** : 연결 개수가 가장 서버를 선택하는 방식으로 트래픽으로 인해 세션이 길어지는 경우 권장한다.\n\n- **Source** : 사용자의 IP를 Hashing하여 분배하는 방식으로 사용자가 항상 같은 서버로 연결되는 것을 보장한다.\n\n<br/>\n\n## 클러스터링\n\n여러 대의 컴퓨터를 병렬로 연결하여 하나의 컴퓨터처럼 사용할 수 있게 해준다.<br/>\n특정 장비에 문제가 생기거나 실행중인 애플리케이션에 문제가 발생하더라도 서비스에 영향을 미치지 않도록 해준다.\n\n<br/>\n\n### 로드밸런싱과의 차이\n\n로드밸런싱은 한 쪽 서버에 부담이 가지 않도록 트래픽을 분산해주는 역할을 한다. <br/>반면,  클러스터링은 여러 개의 서버를 하나로 묶어 성능을 높여 많은 양의 트래픽을 처리하도록 하는 것이다.\n\n**클러스터링은 각 노드 간의 상태를 공유하기 떄문에 클러스터링된 서버 중 하나가 죽더라도 기존의 세션 연결이 끊기지 않고 다른 서버로 `failover`된다.**\n\n\n### 세션 클러스터링\n\n`WAS`가 2대 이상 설치되어 있을 경우, 각각의 `WAS`가 다른 세션을 가질 수 있다. 이는 **세션에 대한 처리 불일치**가 일어날 수 있다.\n\n이에 따라 각 `WAS`에 대한 **세션을 하나의 세션으로 관리**하게 함으로써 새로운 `WAS`에 접속하더라도 세션에 대한 불일치를 막는다. 이를 세션 클러스터링이라고 한다.\n\n이외에도 `Redis`를 사용하여 세션 서버를 따로 두고 세션을 일치시키는 방법도 있다.\n\n<br/>\n\n---\n\n#### Reference\n\n- [로드 밸런서(Load Balancer)란?](https://nesoy.github.io/articles/2018-06/Load-Balancer)\n- [세션 클러스터링](https://brownbears.tistory.com/168)\n- [로드밸런싱과 클러스터링](https://asfirstalways.tistory.com/m/320?category=656859)\n"
  },
  {
    "path": "Network/사용자 인증 방식(Cookie, Session & oAuth 2.0 & JWT).md",
    "content": "# 사용자 인증 방식\n## 목차 \n1. 서버 기반 인증 (Cookie-Session)\n2. 토큰 기반 인증 (oAuth 2.0, JWT) \n\n## 1. 서버 기반 인증 (Cookie-Session)\n![image](https://user-images.githubusercontent.com/43839938/80296521-f906ee00-87b6-11ea-9e6f-fbf0a1e9712c.png)\n\n- 설명: 전통적인 방식이다. HTTP의 `stateless`한 속성을 보완할 필요성이 생겨서 탄생했다.\n- 장점: `stateful` 유지 가능\n- 단점:  서버 부하 (유저의 인증 정보를 서버측에 담아둠)\n\n> `stateful`: server side 에 client와 server의 연속된 동작 상태정보를 저장하는 형태  \n> `stateless`: server side 에 client와 server의 연속된 동작 상태정보를 저장하지 않는 형태\n\n## 2. 토큰 기반 인증 (oAuth 2.0, JWT)\n![image](https://user-images.githubusercontent.com/43839938/80296527-0c19be00-87b7-11ea-86b1-500f6c269339.png)\n- 설명: 서버 기반 인증 방식과 달리 stateless한 방식이다. 서버 부하를 덜 수 있다.\n### (1) oAuth 2.0\n> oAuth 에서 사용하는 `Refresh Token`- `Access Token` 구조\n![image](https://user-images.githubusercontent.com/43839938/80296620-c14c7600-87b7-11ea-93aa-814375724d0a.png)\n\n> oAuth 2.0 동작 방식\n![image](https://user-images.githubusercontent.com/43839938/80296794-d2e24d80-87b8-11ea-97e2-514ef8fbfd23.png)\n\n- 설명: `Access Token`, `Refresh Token`을 이용한 인증 방식은 한 서버에서 모두 관리하는 반면, 여기 OAuth에서는 Authorization Server에서 인증+권한 관리를 하고 Resource Server에서는 자원에 대한 관리만 한다.\n- 장점: 보안성 좋다. (`Access Token`을 지속적으로 발급받아야 하므로)\n- 단점: 필요한 Resource가 너무 많다. `Access Token`이 만료될 때마다 새롭게 발급하는 과정에서 생기는 HTTP 요청이 잦다.\n\n> `Access Token`: API를 요청할 때 사용하는 토큰. 유효기간이 짧다.  \n> `Refresh Token`: Access Token의 유효기간이 만료되면 `Access Token`을 다시 발급받기 위해 사용되는 Token. `Access Token`보다 유효기간이 길다.\n\n### (2) JWT (JSON Web Token)\n- 설명: 토큰 자체가 data를 가지고 있다. \n- 장점: 토큰 기반 인증의 장점 (서버 부하 덜 수 있음)\n- 단점: Packet(보내는 데이터) 양이 크다. 토큰 자체를 탈취하면 ID, PW 자체를 알 수 있다. (따라서 `HTTPS` 통신을 권장한다.)\n\n###### HTTPS 관련 자료: [HTTPS란](https://github.com/im-d-team/Dev-Docs/blob/master/Security/HTTPS%EC%99%80%20SSL.md)\n\n![image](https://user-images.githubusercontent.com/43839938/80296561-5dc24880-87b7-11ea-8a48-8e8ab99e611b.png)\n\n![image](https://user-images.githubusercontent.com/43839938/80297158-af6cd200-87bb-11ea-92f1-82cadb6c8643.png)\n사이트: https://jwt.io/\n\n1) **헤더 (Header)**\n```json\n{\n  \"typ\": \"JWT\",\n  \"alg\": \"HS256\"\n}\n```\n> typ: 토큰의 타입을 지정한다. 여기서는 JWT이다.\n\n> alg: 해싱 알고리즘을 지정한다. 해싱 알고리즘으로는 보통 HMAC SHA256 혹은 RSA 가 사용된다. 이 알고리즘은 토큰을 검증 할 때 사용되는 signature 부분에서 사용된다.\n\n2) **정보 (Payload)**\n\n3) **서명 (Signature)**    \n헤더(Header)의 인코딩 값과, 정보(Payload)의 인코딩 값을 합친 후 주어진 비밀키로 해쉬를 하여 생성한다.\n\n4) JWT 사용 예제\n> JWT 토큰 생성\n```php\nuse Firebase\\JWT\\JWT;\n\nfunction getJWToken($id, $pw, $secretKey)\n{\n    $data = array(\n        'date' => (string)getTodayByTimeStamp(),\n        'id' => (string)$id,\n        'pw' => (string)$pw\n    );\n\n    return $jwt = JWT::encode($data, $secretKey);\n}\n\n(...)\nconst JWT_SECRET_KEY = \"(시크릿 키 입니다.)\"\n\n$jwt = getJWToken($req->id, $req->pw, JWT_SECRET_KEY);\n```\n> JWT 키로 decoding 하기\n```php\nfunction getDataByJWToken($jwt, $secretKey)\n{\n    try{\n        $decoded = JWT::decode($jwt, $secretKey, array('HS256'));\n    }catch(\\Exception $e){\n        return \"\";\n    }\n\n    // print_r($decoded);\n    return $decoded;\n\n}\n```\n#### Reference\n- [[JWT] JSON Web Token 소개 및 구조](https://velopert.com/2389)\n- [쉽게 알아보는 서버 인증 2편(Access Token + Refresh Token)](https://tansfil.tistory.com/59)\n- [[JWT를 구현하면서 마주치게 되는 고민들]](https://swalloow.github.io/implement-jwt)\n"
  },
  {
    "path": "Node.js/make_meta_file.md",
    "content": "# Notion API를 이용해서 Meta html만들기\n\n오늘은 간단하게 이직을 하고 두 달이 되고 나서 겪었던 일을 바탕으로 진행했던 개인적인 프로젝트에 대해서 이야기를 하려고 한다.\n\n## 배경\n\n- 서비스를 운영하면서 Into 페이지에 설정된 Meta 태그를 바꾸는 경우가 2달에 1번 발생한다.\n- Meta 태그를 변경하게 되면 현재 구조에서는 다시 빌드하도록 신경써주어야 한다.\n- Meta 태그 변경은 프론트엔드 개발자가 임의로 바꾸는 것이 아닌 마케팅을 위해 변경한다.\n\n## 해결하고 싶은 부분\n\n- 빌드 시점에 변경 사항을 자동으로 반영하고 싶다.\n- 마케팅과 개발자가 변경되는 Meta 태그 정보를 주고 받지 않아도 반영되고 싶다.\n- 개발자보다는 Meta 태그를 어떻게 설정하면 좋은 지 더 잘 알고 있는 마케터가 Meta 태그 코드를 작성할 수 있게 하고 싶다.\n\n위와 같이 생각하고 있던 중 현재 회사가 사용하는 도구 중 Notion을 이용하면 좋은 프로젝트가 될 수 있겠다는 생각으로 진행했다.\n\n'**먼저 Notion을 어떻게 사용할 것인가**' 다. Notion이라는 도구는 회사 내에서 모든 사람이 사용하는 도구로 **글을 작성하거나 DataBase**로 사용한다. 그렇다면 Meta 정보는 Notion에 작성하고, Meta 정보는 API로 가져오면 될 것 같다.\n\n글을 작성할 당시 Notion에서는 별도의 API를 지원하지 않는다. 그래서 직접 조사를 해야 했다.\n\nNotion은 웹을 지원한다(실제로는 앱도 웹이다.). 개발자 도구를 열어 'Network' 탭을 열고 **XHR** 통신이 어떻게 이루어지는지 알아보자.\n\n우리가 찾아야 하는 정보는 아래와 같다.\n\n- API\n- Request Data\n- Cookie(로그인 정보)\n- Response\n\n![chrome dev tool](https://user-images.githubusercontent.com/24274424/92750428-01f10880-f3c2-11ea-87d9-dab87306bca4.png)\n\n이제 우리가 작성할 Meta 태그에 대한 정보를 Notion에 적으면 Notion API로 변경된 데이터를 가져올 수 있지 않을까? 라는 생각을 했다.\n\nNotion에 Meta 태그만 작성할 공간을 DataBase 페이지로 만들었다. 그리고 해당 페이지의 데이터는 어떻게 가져오는지 API를 실행해보자.\n\n우리가 만든 DataBase 형식은 `queryCollection` API를 사용해서 가져오는 것을 확인했다.\n\n![response data](https://user-images.githubusercontent.com/24274424/92750942-82b00480-f3c2-11ea-95d6-faf24ca9a9f7.png)\n\nChrome 개발자 도구로 더 자세히 살펴보니 payload 부분에 아래와 같은 양식으로 호출하는 것을 확인했다. 좀 더 커스텀을 하면 정말 원하는 데이터만 가져올 수 있겠지만 이번에는 아래의 형식을 그래도 사용하기로 했다.\n\n```json\n{ \n    collectionId: \"\"\n    collectionViewId: \"\"\n    loader: {\n        type: \"table\", \n        limit: 70, \n        searchQuery: \"\", \n        userTimeZone: \"Asia/Seoul\", \n        loadContentCover: true\n    }\n    limit: 70\n    loadContentCover: true\n    searchQuery: \"\"\n    type: \"table\"\n    userTimeZone: \"Asia/Seoul\"\n    query: {\n        aggregations: [\n            {property: \"title\", aggregator: \"count\"}\n        ]\n    }\n    aggregations: [{property: \"title\", aggregator: \"count\"}]\n}\n```\n\n여기서 중요하게 생각한 것은 `collectionId`와 `collectionViewId`다. 각각은 Unique한 키로 원하는 데이터를 가져오기 위한 PK이다. Notion에서는 이 2개의 키로 원하는 페이지 데이터를 찾아서 가져오는 것이다.\n\n또한 해당 API에 권한이 있는지 확인은 어떻게 하는지가 중요했다. API 요청에 대한 주소, 메서드, Payload는 알았지만 실제로 권한이 없으면 소용없다.\n\nNotion이 PC 앱을 지원하면서 내부적으로 웹을 사용하는데 자동 로그인이 유지되는 것을 보니 어딘가 로그인 정보를 유지하리라 생각했다. \n\n실제로 개발자 도구에서 cookie를 보게 되면 다양한 정보가 담기는 것을 확인할 수 있다.\n\n```js\naxios(config)\n  .then(function (response) {\n    console.log(JSON.stringify(response.data));\n  })\n  .catch(function (error) {\n    console.log(error);\n  });\n```\n\n간단한 코드로 위에서 찾은 API를 호출해서 잘 가져오는 것을 확인했다.\n\n이제 Notion에 작성할 Meta 데이터 양식에 대해서 알아보고 형식을 만들어야 했다. 마케터분들이 작성한 데이터들이 `html` 형식에 맞게 구성되고 파일로 만들 수 있도록 하는게 목표이다.\n\n현재 `head` 태그 안에 들어가는 모든 Tag를 조사하여, Column으로 Name, Type, MetaType, Contents 항목들을 만들었다.\n\n- Name : Tag Name\n- Type : Tag Type\n- MetaType : Type이 Meta일 경우 선택하는 항목으로 name과 property 중 하나이다.\n- Contents : 실제 값\n\n![notion col name](https://user-images.githubusercontent.com/24274424/92750264-dd952c00-f3c1-11ea-9a43-1aeb0f10782a.png)\n\n\n![notion meta data](https://user-images.githubusercontent.com/24274424/92750134-bfc7c700-f3c1-11ea-84fa-fde8a37474a2.png)\n\n모두 정리했다.\n\n생각보다 깔끔하게 정리가 됐다. 이렇게 구성하게 되면 추후에 새로운 태그가 추가될 경우 한 줄을 추가하고 입력하면 된다.\n\n[이제 실제로 테스트를 해보자.](https://github.com/SeonHyungJo/metatag-generator-for-notion)\n\n이제 이 과정을 빌드할 때 같이 해주면 된다. 우리가 기본적으로 사용하는 `npm script`는 `npm run build`다. 우리는 이 Meta 태그 파일을 빌드 시점 이전에 실행해서 만들고, 만들어진 결과물을 이용해서 같이 빌드를 하는 것을 원한다. 이에 `npm run prebuild` 시점에 Meta 파일을 만들도록 추가하였다."
  },
  {
    "path": "Node.js/nodejs의_특징.md",
    "content": "# Node.js의 특징\n* 자바스크립트 런타임\n    * 언어나 프레임워크, 라이브러리가 아니다.\n    * 자바스크립트가 브라우저 환경에서 돌아가는 대신 내 컴퓨터에서 서비스 혹은 런타임으로 실행된다.\n\n* V8자바스크립트 엔진을 사용한다.(크롬브라우저와 동일)\n> 참고 - [Javascript_Engine](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/Javascript_Engine.md)\n\n* 언어 차원에서 네트워크를 지원한다.\n    * 서버사이드 언어로 사용할 수 있다.\n\n<br/>\n\n## 왜 사용하는가?\n#### 빠르고, 효율적이고, 확장성이 아주 크다\n* Event driven이기 때문에 싱글 루프에서 실행되고, non-blocking이다. 따라서 non-blocking i/o model을 가진다.\n> blocking 모델에서는 하나의 스레드에 프로세스가 할당되면 끝날 때까지 기다려야 한다(sit and wait). 비동기적 작동이 안되기 때문에 요청이 발생할때마다 새로운 스레드를 생성한다. 반면, non-blocking i/o는 이벤트 루프로 처리를 하기 때문에 응답을 기다리지 않고 계속해서 요청을 보낼 수 있다.\n\n#### 인기가 많다!\n> [mean stack](https://en.wikipedia.org/wiki/MEAN_(software_bundle)) 혹은 mern stack의 n이 노드다!\n* 리엑트, 뷰, 앵귤러 등과 자주 사용되는데, 같은 언어로 프런트와 백을 할 수 있기 때문\n\n<br/>\n\n## 동작방식\nNode.js는 **싱글 스레드(Single Thread)**로 동작하고, 비동기적인 **[event driven](https://terms.naver.com/entry.nhn?docId=822661&cid=50376&categoryId=50376)**방식을 사용한다.\n\n이는 자바스크립트와 같다. 자바스크립트 엔진을 사용하기 때문이다.\n\n차이점은 `setTimer()`과 같은 함수 혹은 `XHR` 등을 사용하는  대신, `EventEmitter` 클래스를 사용하여 이벤트와 리스너를 바인딩(binding) 한다.\n\n또한, node.js는 수많은 연결이 하나의 스레드를 통해서 이루어진다. **Non-blocking I/O**를 사용하기 때문이다.\n\n이때, 이벤트 루프를 이용하여 데이터 통신을 한다. 따라서, 이전의 데이터 전송의 완료여부와 상관없이 다음 작업이 진행된다.\n> Event loop에 대한 내용은 [B_EventLoop](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/B_EventLoop.md), [EventLoop](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/EventLoop.md), [EventLoop_Advanced](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/EventLoop_Advanced.md) 를 참고\n\n<br/>\n\n## Node.js에 적합한 프로젝트 타입\n간단하게 요약하면 CPU intensive하지 않은 것이 적합하다.\n\n앞서 말했듯, node.js의 I/O실행은 비동기적이다. Blocking 없이 통신을 할 수 있는 것이 장점이다.\n\n하지만, 많은 CPU 사용이 요구되어 CPU의 작업 처리가 한계에 다다른다면 결국 서버가 느려질 것이다. 그렇게되면 당연히 어플리케이션이 느려진다.\n\n따라서 다음과 같은 프로젝트들이 어울린다.\n\n* micro services 및 REST API\n\n* 리얼타임 서비스(채팅, 라이브업데이트)\n\n* CRUD Apps\n  \n    > 블로그나, 쇼핑카트, 소셜 네트워크 등\n\n> CPU intensive하지 않은 선에서 툴이나 유틸리티도 괜찮다.\n\n<br/>\n\n## NPM(Node Package Manager)\nNode.js를 설치하면 NPM이 생기는데, [써드 파티](https://ko.wikipedia.org/wiki/%EC%84%9C%EB%93%9C_%ED%8C%8C%ED%8B%B0_%EA%B0%9C%EB%B0%9C%EC%9E%90) 패키지나 모듈을 설치하는데 사용된다.\n\n패키지들은 `node_modules`폴더에 저장된다.\n\n설치된 패키지나 denpendency는 `package.json`에 담긴다.\n> node.js의 모듈들은 package의 dependency를 통하여 연결된다.\n\n```ps\nnpm init // Generates a package.json file\nnpm install express // installs a package locally\nnpm install -g nodemon // installs a package globally (-g플래그를 더해주면 된다.)\n```\n\n<br/>\n\n## Modules of Node.js\n모듈은 노드의 아주 큰 부분이다.\n\n* 기본적으로 node.js에 포함된 코어 모듈이 있고,\n\n* NPM을 통해 받을 수 있고\n\n* 내가 만들 수도 있다.\n\n변수들과 함수들과 클래스들 혹은 기타등등을 모듈에 포함시킬 수 있다.\n\n모듈은 모듈 이름을 사용하여 불러올 수 있다. \n\n또한 경로를 적어주어서 불러올 수도 있다.\n\n```js\nconst path = require('path');\nconst myFile = require('./myFile');\n```\n\n<br/>\n\n---\n\n#### Reference\n\n* [Node.js Crash Course](https://www.youtube.com/watch?v=fBNz5xF-Kx4&feature=youtu.be)\n"
  },
  {
    "path": "OpenCV/이미지전처리.md",
    "content": "# 이미지 전처리 과정\n\n## 개요\n\n이미지에는 매우 많은 데이터가 존재한다.\n이때 원하는 객체를 검출하기 위해서는 불필요한 데이터를 줄이고,\n유의미한 데이터를 정제하는 과정이 필요하다.\n이러한 이미지 전처리 과정에서 필터를 사용하면 효과적으로 객체를 검출 할 수 있다.\n\n## grayscale   \n\n`grayscale`은 다중 채널(RGB/RGBA) 이미지를 단일 채널(명암값) 이미지로 변환하여\n데이터 폭을 줄이는 역할을 한다. 여기서 데이터 폭을 줄인다는 것은 데이터의 양을 줄인다는 것과 같다.\n3-4개의 채널을 가지고 있는 컬러 이미지와는 달리 1개의 채널을 가지고 있으므로\n데이터의 양을 최대 1/4 까지 줄일 수 있다.\n\n#### Example\n```python\nimg_ori = cv2.imread('1.jpg')\ncv2.imshow(\"org\",img_ori)\ngray = cv2.cvtColor(img_ori, cv2.COLOR_BGR2GRAY)\ncv2.imshow(\"gray\",gray)\n```\n<br>![1](https://user-images.githubusercontent.com/43839951/78467561-eade2880-7748-11ea-9d2e-028ab843b9dd.jpg)\n\n\n\n<br>![gray](https://user-images.githubusercontent.com/43839951/78553294-f5311d00-7843-11ea-95a1-b25881264a0e.JPG)\n\n\n\n\n\n\n## Thresholding   \n이미지를 0(검은색)과 1(흰색)로만 표현한 것을 **binary(이진화)** 이미지라고 한다.   \n**Thresholding**이란 임계값을 기준으로 데이터 값을 두 가지 부류로 나누는 것으로,    \n**binary image**를 만드는 가장 대표적인 방법이다.   \ngrayscale로 바꾼 컬러 이미지에서 각 픽셀의 값이 경계 값을 넘으면 255,넘지 못하면 0의 값으로 지정한다.   \n\n```python\nret,img_thresh = cv2.threshold(\n    gray,\n    127,255.0,\n    cv2.THRESH_BINARY_INV\n)\ncv2.imshow(\"thresholding\",img_thresh)\n```\n-`gray` : grayscale 이미지  \n-`127` : threshold 값   \n-`255.0` : 경계 값 기준에 만족하는 픽셀에 적용할 값   \n-`cv2.THRESH_BINARY_INV` : 픽셀 값이 경계 값을 넘지 못하면 value를 지정하고 ,넘지 못하면 0을 지정   \n\n<br>![thresholding](https://user-images.githubusercontent.com/43839951/78467590-2547c580-7749-11ea-9e3b-5989f33957c6.JPG)<br><br>\n\n이러한 이진화 과정에서는 적당한 임계값을 찾는 것이 가장 중요하다.<br>\n\n## AdaptiveThresholding\n\n`Thresholding`은 임계값을 이미지 **전체에 적용**하여 처리하기 때문에,   \n원본 영상에 조명이 일정하지 않거나 배경색이 여러 가지인 경우에는 아무리 여러번    \n경계값을 바꿔가며 시도해도 일부 영역이 모두 흰색 또는 검정색으로 보여지게 된다.   \n'AdaptiveThresholding'은 이미지를 작은 영역으로 나누어 각 영역 별로 thresholding을 하는 것이다.   \n\n```python\n #threshold only\n img_thresh = cv2.adaptiveThreshold\n (gray,\n maxValue=255.0,\n adaptiveMethod=cv2.ADAPTIVE_THRESH_GAUSSIAN_C,\n thresholdType=cv2.THRESH_BINARY_INV, \n blockSize=19,\n C=9)\n```\n-`gray` : grayscale 이미지    \n-`maxValue` : threshold 값보다 클 경우 이미지의 해당 픽셀에 지정될 값   \n-`adaptiveMethod` : 사용할 adaptive Threholding 알고리즘 지정   \n-`thresholdType` : threshold 적용 방법 지정    \n-`blockSize` : threshold값을 계산하기 위한 블럭 크기. 적용 될 픽셀이 블럭의 중심이 되므로 홀수여야 함   \n-`C` : 보정 상수.양수이면 계산된 adaptive threshold값에서 빼고, 음수면 더함   \n\n<br>![thresholdingOnly](https://user-images.githubusercontent.com/43839951/78467594-2ed12d80-7749-11ea-909f-dcf9c6c977bc.JPG)<br><br>\n\n## **필터를 이용한 노이즈 제거**\n\n### Gaussian Blur 필터   \n\nGaussian 분포를 가지고 있는 커널을 이용하여 블러링을 하는 것을 Gaussian 블러링이라고 한다.   \n이러한 Gaussian Blur를 이용한 `Gaussian Filter`는 현재 픽셀값과 주변 이웃 픽셀값들의 **가중 평균(weighted average)**\n을 이용하여 현재 픽셀의 값을 대체한다.    \n따라서 **Gaussian Filter**를 이용하면 `엣지(edge)`와 같이 공간적으로 급변하는 부분 이외의 **노이즈**를 제거 할 수 있다.   \n\n>**커널(kernel)**: 여러가지 이미지 처리를 위한 가중치를 가진 행렬. 주변 픽셀들 중에 어디까지를 포함할 것인지, 결과 값을 어떻게 산출 할 것인지를\n결정하는 것. ex)3 * 3 커널은 이미지를 변환하기 위한 9개의 행렬을 의미   \n>**블러링(bluring)**: 영상을 초점이 맞지 않은 것처럼 흐릿하게 만드는 것.\n\n<br>![gaussianblurGraph](https://user-images.githubusercontent.com/43839951/78467745-ad7a9a80-774a-11ea-8d8d-4fa7da24b791.JPG)<br><br>\n\n\n다음은 필터의 한 종류인 **Gaussian Blur 필터**를 사용한 효과를 보여 준다\n\n```python\n #blur and threshold\n img_blurred = cv2.GaussianBlur(gray, ksize=(5, 5), sigmaX=0)\n #gray : 입력 영상   \n #ksize : 커널 크기   \n #sigmaX : X 방향 표준편차. 값이 높을수록 이미지가 흐려짐\n \n img_blur_thresh = cv2.adaptiveThreshold\n (img_blurred,\n maxValue=255.0,\n adaptiveMethod=cv2.ADAPTIVE_THRESH_GAUSSIAN_C,\n thresholdType=cv2.THRESH_BINARY_INV,\n blockSize=19,\n C=9)\n```\n\n<br>![Gaussian](https://user-images.githubusercontent.com/43839951/78467606-3bee1c80-7749-11ea-93bc-29a93b7327cb.JPG)<br><br>\n\n\n## 결론\n\n이미지 전처리 과정에 정해진 방식이 있는 것은 아니다.   \n상황에 따라 다양한 필터와 전처리 과정의 순서를 바꿔거며 최상의 결과를 얻을 수 있는   \n방법은 ***caseBycase***이다.\n"
  },
  {
    "path": "Performance/DeadLock(교착상태).md",
    "content": "# DeadLock(교착상태)\n\n- **한정된 자원을 여러 곳에서 사용**하려고 할 때 발생한다.\n\n- 어떤 프로세스가 자원을 요청 했을 때 그 시각에 그 자원을 사용할 수 없는 상황이 발생할 수 있고 그 때는 프로세스가 **대기 상태**로 들어 간다.\n\n- **대기 상태로 들어간 프로세스가 실행 될 수 없는 상황**을 교착 상태라 한다.\n\n<br/>\n\n## DeadLock의 발생 조건\n\nDeadLock은 한 시스템 내에서 4가지 조건이 동시에 성립 할 때 발생한다. 즉, 4가지 조건 중 **하나라도 성립하지 않으면 DeadLock은 발생하지 않는다.**\n\n- **상호배제(Mutual exclusion)** : 하나의 프로세스가 자원을 사용할 경우 다른 프로세스는 그 자원을 사용할 수 없는 것\n\n- **점유대기(Hold and wait)** :  프로세스가 자신이 가질 수 있는 자원은 가지고 있으면서 다른 자원이 오기를 기다리고 있는 것\n\n- **비선점(No Preemption)** : 프로세스가 어떤 자원의 사용을 끝낼 때까지 그 자원을 뺏을 수 없는 것\n\n- **순환대기(Circular wait)** : 첫 번째 프로세스와 마지막 프로세스의 자원할당이 겹치게 되어 원형에 있는 모든 프로세스가 자원 할당을 받고자 기다리는 형태가 만들어지는 것\n\n<br/>\n\n## DeadLock의 예방과 회피\n\n### DeadLock의 예방\n\n---\n\n- **상호배제 예방** : 상호배제 사용하지 않음(**동시액세스 허락**)\n\n- **점유대기 예방**: 프로세스가 필요로 하는 자원을 **일시에 요구/할당**\n\n- **비선점 예방** : **자원 임시 할당 해제 및 원상 복구**\n\n- **순환대기 예방** : 모든 자원의 **고유번호 지정**한다.\n\n위의 4가지 조건 중 하나라도 발생하지 않도록 시스템 차원에서 막아버리면 해결된다.\n\n근데 이 방법은 대부분 자원이 낭비되는 경향이 있다. 그리고 애초에 발생 가능성을 시스템 차원에서 막아버리면 성능이 나빠지거나 또 다른 문제의 원인이 될 수 있다.\n\n### DeadLock의 회피\n\n---\n\n교착상태의 발생 조건은 놔두고, **발생을 막는 알고리즘을 적용**해서 해결하는 방법이다.\n\n대표적으로 **은행원 알고리즘**이 있다.\n\n**은행원 알고리즘(Banker's Algorithm)** 은 프로세스가 자원을 요구할 때 시스템이 자원을 할당한 후 안정 상태로 남아있는지를 사전에 검사한 후 **안정 상태라면 자원을 할당**하는 방식이다.\n\n만약, 안정 상태가 아니라면 **다른 프로세스들이 점유한 자원을 해제할 때까지 대기**한다.\n\n1. 자원 상황와 자원 종류의 최대 수를 파악.\n\n2. 프로세스가 자원 할당 요구.\n\n3. 시스템 상태를 파악 후 자원 할당 여부를 결정.\n\n4. 안정 상태라면 할당 아니라면 대기.\n\n<br/>\n\n#### 은행원 알고리즘의 자료 구조\n\n- Available[n] : 자원 n의 사용 가능 개수.\n\n- Max[m,n] : 프로세스 m 의 자원 n의 최대 요구 개수 \n\n- Allocation[m,n] : 프로세스 m 에 할당된 자원 n의 개수\n\n- Need[m,n] : 프로세스 m이 추가적으로 필요로 하는 자원 n의 개수\n\n<br/>\n\n---\n\n#### Reference\n\n- [운영체제 - 교착상태, 기아상태, 은행가 알고리즘](https://m.blog.naver.com/PostView.nhn?blogId=dong5053&logNo=220717510273&proxyReferer=https%3A%2F%2Fwww.google.com%2F)\n- [DeadLock 발생 조건 4가지 및 해결 방법](https://blog.lael.be/post/1304)\n"
  },
  {
    "path": "Performance/HTTP2.0의 필요성.md",
    "content": "# HTTP2.0의 필요성\n\n## HTTP/1.1\n\nHTTP/1.1의 동작 방식은 간단하다. Connection하나 당 하나의 요청만 처리한다. 따라서 **동시 전송이 불가능하고 요청과 응답이 순차적으로 처리된다.** 처리할 리소스(img, css, script)가 많아질수록 Latency(대기시간)은 길어지게 되고 이는 치명적이다.\n\n<br/>\n\n### Header와 3-way Handshake의 반복\n\n---\n\nHTTP/1.0의 또 다른 문제로는 매 **Connection마다 중복된 헤더 요청이 일어나고, 매 요청마다 3-way Handshake가 반복적으로 일어난다.** Header가 Body보다 무거운 경우가 발생할 수 있으며, `3-way Handshake`가 반복적으로 발생하면 `RTT(Round Trip Time)`이 증가하게 되고 성능이 저하된다.\n\n<br/>\n\n## 성능 향상\n\n### Pipelining\n\n---\n\n위에서 설명한 HTTP/1.1의 단점인 하나의 Connection 당 하나의 처리만 가능한 것을 보완해 **하나의 Connection에 다수의 리소스를 요청할 수 있는 기법으로서 `Pipelining`이 있다.**\n\n하지만 만약 첫 번째 리소스의 응답 시간이 길어지게 되면 응답 처리가 완료되기 전까지 나머지 리소스의 요청은 대기 상태에 빠진다. 이는 `Pipelining`의 문제이며 이를 **HOLB(Head of Line Blocking)**라고한다.\n\n<br/>\n\n### Image Spriting(CSS Spriting)\n\n---\n\nImage Spriting은 이미지 여러 개를 하나로 만들고 `background-position` 속성을 이용해 필요한 부분의 이미지만 보여준다. 즉, 해당 이미지의 좌표 값을 지정해 렌더링한다.\n\n이미지의 갯수만큼 HTTP 요청을 했던 방식을 **한 번의 요청으로 줄일 수 있어** 렌더링 속도가 향상될 수 있다.\n\n```css\n#spriteImg span {\n  background: url(images/buttons-bg.png) no-repeat;\n}\n\n#spriteImg #profile span {background-position: 0 0;}\n#spriteImg #github span {background-position: 0 -15px;}\n```\n\n<br/>\n\n### 도메인 샤딩(Domain Sharding)\n\n---\n\n**`도메인 샤딩`은 여러 개의 서브도메인을 생성하여 리소스를 병렬로 가져온다. 기본적으로 HTTP/1.1에서는 도메인 당 동시 요청의 갯수가 제한되기 때문에 이는 해결책이 될 수 있다.** \n\n하지만, 각 하위 도메인의 DNS 조회를 하고 이는 시간, CPU 전력을 생각보다 많이 소모하게 된다. 또한 현재 많은 모바일 브라우저가 `Piplining`을 구현하고 있기 때문에 근본적인 해결책은 될 수 없다. \n\n\n### Minification\n\n리소스의 용량을 줄이기 위해 CSS, Script 코드를 축소하여 적용하는 방식이다.\n\n\n## HTTP2.0\n\n위의 여러 방법들이 있지만 분명 한계가 존재하기 때문에 HTTP2.0이 필요해졌고 이에 대한 설명은 [HTTP2.0과 Web Socket](https://github.com/Im-D/Dev-Docs/blob/master/Browser/HTTP2_Websocket.md)에서 대체한다.\n\n---\n\n#### Reference\n\n- [나만 모르고 있던 - HTTP/2](https://www.popit.kr/%EB%82%98%EB%A7%8C-%EB%AA%A8%EB%A5%B4%EA%B3%A0-%EC%9E%88%EB%8D%98-http2/)\n- [도메인 샤딩](https://wonism.github.io/domain-sharding/)"
  },
  {
    "path": "Performance/Reflow Repaint.md",
    "content": "# Layout(Reflow), Repaint\n\n## 브라우저 Rendering 과정\n\n![rendering](/assets/images/rendering.png)\n\n브라우저는 화면을 Rendering하는 과정에는 **배치\\(flow\\)**, **그리기\\(paint\\)** 가 포함되어있다.\n\n> [브라우저 작동원리](/Browser/웹%20브라우저의%20작동%20원리.md)\n\n### [들어가기전에] 60fps 및 기기 새로 고침 빈도\n\n오늘날 대부분의 기기는 초당 60회의 빈도로 화면 뿌려주고 있다. 실행 중인 애니메이션 또는 화면전환이 있거나, 사용자가 페이지를 스크롤 중이면, 브라우저가 기기의 빈도에 일치하도록 각 화면 새로 고침에 대해 하나의 새 그림이나 프레임을 제공하려고 하고 있다.\n\n각 프레임에는 **16ms** 가량의 시간이 할당된다. (1초/60 = 16.66ms). 실제로 브라우저는 실행 준비를 해야 하므로 10ms 내에 모든 작업을 완료해야 한다. 이 제한 시간을 충족하지 못하면 프레임 속도가 떨어지고 화면에서 콘텐츠가 끊어진다. 이러한 현상을 우리는 흔히 버벅거림 현상이라고 한다.\n\n더 자세한 내용을 알고 싶으면 아래의 NAVER D2 자료를 참고하면 된다.\n\n> [Frame의 차이 맛보기](https://codepen.io/seonhyungjo/pen/mdbMLeo)\n\n> [참고 자료 - 브라우저는 vsync를 어떻게 활용하고 있을까](https://www.slideshare.net/deview/133-vsync)\n\n#### 60fps Example\n\n```html\n<body>\n  <p>The Caterpillar and Alice looked at each other for some time in silence:\n    at last the Caterpillar took the hookah out of its mouth, and addressed\n    her in a languid, sleepy voice.</p>\n</body>\n<style>\n  p {\n    display: inline;\n    animation-duration: 3s;\n    animation-name: slidein;\n  }\n\n  @keyframes slidein {\n    from {\n      margin-left: 100%;\n      width: 300%\n    }\n\n    to {\n      margin-left: 0%;\n      width: 100%;\n    }\n  }\n</style>\n```\n\n![60fps_example](https://user-images.githubusercontent.com/24274424/64056788-cf1e0d00-cbd0-11e9-910a-c266e84317be.png)\n\n\n우리가 위와 같이 부드럽게 보이도록 작업할 수 있는 영역을 간단하게 표현하게 되면 아래와 같이 5개의 단계가 있다. 오늘은 그 중 Layout과 Paint에 대해서 보자.\n\n![image](https://user-images.githubusercontent.com/24274424/64056321-4e114680-cbcd-11e9-9e64-9febc4e37071.png)\n\n## Layout(Reflow)\n\n생성된 DOM 노드의 레이아웃이 변경될 때, 브라우저는 변경 후 영향을 받는 모든 노드를 다시 계산하고 렌더트리를 재생성한다.\n\n이러한 과정을 `Reflow`라 하고 `Reflow`가 일어나게 되면 위의 사진에서 보이듯이 `paint`, `composite`이 일어난다.\n\n브라우저의 특정 api에는 강제로 Reflow를 일으키는 것들이 있다. 아래의 링크를 확인해보자.\n\n> [What forces layout / Reflow](https://gist.github.com/paulirish/5d52fb081b3570c81e3a)\n\n### Forced Reflow Example\n\n```html\n<body>\n  <p>The Caterpillar and Alice looked at each other for some time in silence:\n    at last the Caterpillar took the hookah out of its mouth, and addressed\n    her in a languid, sleepy voice.</p>\n</body>\n<script>\n\n  const pElement = document.getElementsByTagName('p')[0];\n\n  function test() {\n    for (let i = 0; i < 1000; i++) {\n      const offsetLeft = pElement.offsetLeft\n    }\n  }\n\n  test();\n</script>\n```\n\n![foreced_Reflow1](https://user-images.githubusercontent.com/24274424/64056918-ed383d00-cbd1-11e9-8191-7eb6111b898c.png)\n\ntest function 안쪽을 돌게 되면 style을 재계산을 하고 Laytout 하는 것을 볼 수 있다.\n\n![foreced_Reflow2](https://user-images.githubusercontent.com/24274424/64056970-76e80a80-cbd2-11e9-967b-407278014a74.png)\n\nLayout 영역을 열어보면 line by line로 걸린 시간 역시 Dev Tool에서 확인할 수 있다.\n\n## Repaint\n\n생성된 DOM 노드에 대하여 style을 변경시켰을 때, **`Reflow`는 발생하지 않는다.**\n**레이아웃 수치에 대한 변경이 일어나지 않는다면, `Reflow`가 일어나지 않고, `Repaint`만 일어난다.**\n\n```html\n<body>\n  <p id=\"test\">The Caterpillar and Alice looked at each other for some time in silence:\n    at last the Caterpillar took the hookah out of its mouth, and addressed\n    her in a languid, sleepy voice.</p>\n\n\n</body>\n<script>\n  setTimeout(() => {\n    document.getElementById('test').style.color = 'red'\n  }, 3000);\n</script>\n```\n\n![image](https://user-images.githubusercontent.com/24274424/64056658-e9a3b680-cbcf-11e9-8d43-4e9ad1265d40.png)\n\n## Repaint, Reflow의 최적화\n\n`Repaint`와 `Reflow`가 많아질수록 애플리케이션의 렌더링 성능은 느려지게 된다.\n즉, 이를 줄일수록 성능을 높일 수 있다.\n\n#### 1. 클래스 변경을 통해 Style을 변경하는 경우, 최대한 말단의 노드의 클래스를 변경한다.\n\n#### 2. 인라인 Style을 사용하지 않는다.\n\n- Style 속성을 통해 설정하면, Reflow가 발생한다.\n- Element의 클래스가 변경될 때 한 번의 Reflow만 발생한다.\n- Inline Style은 HTML이 다운로드될 때, 레이아웃에 영향을 미치면서 추가 Reflow를 발생시킨다.\n\n#### 3. 애니메이션이 들어간 Element는 `position: fixed` 또는 `position: absolute` 로 지정한다.\n\n``` html\n<div id=\"animation\" style=\"background:blue;position:absolute;\"></div>\n```\n\n프레임에 따라 Reflow 비용이 많은 애니메이션 효과엔 노드의 `position`을 `absolute`나 `fixed`로 주면 전체 노드에서 분리된다.\n이 경우엔, **전체 노드에 걸쳐 Reflow 비용이 들지 않으며 해당 노드의 Repaint 비용만 들어가게 된다.**\n\n#### 4. 부드러운 애니메이션이 성능을 저하시킨다.\n\n- 한 번에 1px씩 Element를 이동하면 부드러워 보이지만, 성능이 저하되는 원인이 될 수 있다.\n- Element를 한 프레임당 4px씩 이동하면 덜 부드럽게 보이겠지만, Reflow 처리의 `1/4`만 필요하게 된다.\n\n#### 5. 레이아웃을 위한 `<table>`을 피한다.\n\n- `<table>`은 점진적으로 렌더링되지 않고, 모두 불려지고 계산된 다음에서야 렌더링이 된다. 또한, 작은 변경만으로도 테이블의 다른 모든 노드에 대한 Reflow가 발생한다.\n- 레이아웃 용도가 아닌 데이터 표시 용도의 `<table>`을 사용하더라고, `table-layout: fixed` 속성을 주는 것이 좋다. `table-layout: fixed`를 사용하면, 열 너비가 머리글 행 내용을 기반으로 계산되기 때문이다.\n\n#### 6. CSS 하위 셀렉터를 최소화한다.\n\n- 사용하는 규칙이 적을수록 Reflow가 빠르다.\n\n#### 7. 숨겨진 Element를 변경한다.\n\n- `display: none;` 으로 숨겨진 Element는 변경될 때, Repaint나 Reflow를 일으키지 않는다. 그렇기 때문에 Element를 표시하기 전에 Element를 변경한다.\n\n#### 8. JavaScript를 통해서 Style을 변경할 경우, `.cssText`를 사용하거나, 클래스를 변경한다.\n\n```js\n//Before\nconst container = document.getElementById('container');\n\ncontainer.style.padding = \"20px\";\ncontainer.style.border = \"10px solid red\";\ncontainer.style.color = \"blue\";\n\n//After cssText\ncontainer.style.cssText = 'padding:20px;border:10px solid red;color:blue;';\n\n//After class\ncontainer.className = 'test';\n```\n\n#### 9. JavaScript를 통해 리스트를 추가하는 경우, DOM Fragment를 통해 추가한다.\n\n- 3 개의 리스트를 추가하는 경우, 한 번에 하나씩 추가하면 최대 7 개의 Reflow가 발생한다.\n  - `<ul>` 이 추가될 때\n  - `<li>` 에 대해 3번\n  - 텍스트 노드에 대해 3번\n\n```js\nconst frag = document.createDocumentFragment();\nconst ul = frag.appendChild(document.createElement('ul'));\n\nfor (let i = 1; i <= 3; i++) { \n  li = ul.appendChild(document.createElement('li')); li.textContent = `item ${ i }`;\n}\n\ndocument.body.appendChild(frag);\n```\n\n> [createDocumentFragment - MDN](https://developer.mozilla.org/ko/docs/Web/API/Document/createDocumentFragment)\n\n#### 10. 캐쉬를 활용한 Reflow 최소화.\n\n- 브라우저는 레이아웃 변경을 큐에 저장했다가 한 번에 실행함으로써 Reflow를 최소화하는데, `offset`, `scrollTop` 과 같은 계산된 Style 정보를 요청할 때마다 정확한 정보를 제공하기 위해 큐를 비우고, 모든 변경을 다시 적용한다.\n- 이를 최소화하기 위해 수치에 대한 Style 정보를 변수에 저장하여 정보 요청 횟수를 줄임으로써 Reflow를 최소화한다.\n\n```js\nfor (let i = 0; i < len; i++) {\n  el.style.top = `${el.offsetTop + 10}px`; el.style.left = `${el.offsetLeft + 10}px`;\n}\n// Bad practice\n\nlet top = el.offsetTop, left = el.offsetLeft, elStyle = el.style;\n\nfor (let i = 0; i < len; i++) {\n  top += 10; left += 10; elStyle.top = `${top}px`; elStyle.left = `${left}px`;\n}\n// Good practice\n```\n\n#### 11. will-change를 통한 layer분리 시키기\n\nElement에 어떠한 변경을 할 것인지를 미리 브라우저에 알려주는 것이 `will-change` 속성의 역할이다. 이를 사용하면 변경이 시작되기 전에 미리 브라우저에게 알려주어 `will-change` 속성이 사용된 특정 Element와 컨텐츠는 별도릐 Layer로 관리되고 나중에 다시 합쳐진다. 즉, 페이지 출력에 악영향을 줄 수 있는 처리 비용을 줄일 수 있다는 것이다. \n\n이를 사용하게 되면 효율적으로 Element의 변경 또는 렌더링을 처리할 수 있고 페이지는 순식간에 갱신되어 부드러운 화면 처리가 가능하게 된다.\n\n그러나 will-change는 무분별하게 사용하면 성능저하가 발생하고 결과적으로 페이지의 작동이 중단되는 사태가 발생할 수 있다.\n\n#### 12. Dev Tool을 사용해서 직접 측정해서 최적화하기(Performace Tab)\n\n---\n\n#### Reference\n\n- [Reflow or Repaint(or ReDraw)과정 설명 및 최적화 방법](http://webclub.tistory.com/346)\n- [DOM의 문제점과 Virtual DOM](https://velopert.com/775)\n- [Reflow-Repaint](https://github.com/wonism/TIL/blob/master/front-end/browser/Reflow-Repaint.md)\n- [Layout Performance](https://kellegous.com/j/2013/01/26/layout-performance/)\n- [렌더링 성능 - Google](https://developers.google.com/web/fundamentals/performance/rendering/?hl=ko)\n- [CSS 애니메이션 성능 개선 방법(Reflow 최소화, will-change 사용)](https://wit.nts-corp.com/2017/06/05/4571)"
  },
  {
    "path": "Performance/Throttling vs Debouncing.md",
    "content": "## 쓰로틀링 vs 디바운싱\n\n함수를 호출할 때 호출이 너무 많이 되어 과부화 됨을 방지하기 위한 기술이다.\n\n함수 호출이 잦은 예로는 브라우저의 이벤트가 있다. `onScroll` 이나 `onChange` 와 같은 이벤트의 콜백으로 함수를 호출하는 경우 굉장히 많은 호출이 발생할 수 있다.\n\ninfinite scroll 이나 자동완성 기능의 경우 사용자의 특정 이벤트에 따라 비동기 콜백을 호출하는 방식이다. 이 경우 이벤트가 매우 빈번하게 일어나며 많은 호출을 제어하지 않으면 브라우저가 버티지 못할 것이다. 이 때 사용하는 것이 쓰로틀링과 디바운싱이다.\n\n### 쓰로틀링(Throttling)\n\nThrottle 은 정해진 시간동안 특정 행위를 한 번만 호출하도록 하는 것이다. 예를 들어 스크롤 행위가 1 초에 500 번이 발생한다면 이를 0.2 초에 한 번만 실행하게 만들 수 있다. \n\nThrottle 처리가 되지 않은 경우 콜백이 500 번 발생한다. 하지만 Throttle 처리가 된다면 5 번만 실행되게 만드는 기술이다.\n\n스크롤 이벤트의 경우 작은 움직임에도 엄청나게 많은 이벤트가 발생한다. 따라서 1 초 미만으로 쓰로틀링을 하여 같은 동작의 여러번 호출을 1 번으로 제어하는 것이 좋다.\n\n```js\nvar timer;\ndocument.querySelector('#input').addEventListener('input', function (e) {\n    // 1. timer 값이 undefined니까 if문 실행\n    if (!timer) {\n        // 2. timer 에 time함수 설정\n        timer = setTimeout(function () {\n            // 3. 설정시간에 맞춰 timer 초기화 및 함수 실행\n            timer = null;\n            console.log('비동기 요청', e.target.value);\n        }, 2000);\n    }\n});\n```\n\n### 디바운싱(Debouncing)\n\nDebounce 는 한 행위를 여러 번 반복하는 경우, 마지막 행위 이후 특정 시간이 흐른 뒤에 콜백을 호출하도록 하는 방식이다. 자동완성 즉 autocomplete 를 떠올리면 편하다.\n\ninput 의 `onChange`가 일어나면 callback 으로 AJAX 를 이용해 관련 데이터를 긁어온다. 그런데 사용자의 모든 입력에 AJAX 호출을 한다면 브라우저가 견디지 못할 것이다. \n그래서 일정시간동안 Timer 를 만든다. 이 타이머의 시간동안 입력이 발생해 변경이 일어나면 Timer 를 초기화 한다. \n입력이 멈추어 Timer 가 다 되면 AJAX 를 호출한다.\n\n```js\nvar timer;\ndocument.querySelector('#input').addEventListener('input', function (e) {\n    // 1. timer 값이 undefined니까 if문 실행\n    if (timer) {\n        // 3-1. setTimeout이 끝나기 전에 다시 이벤트 실행 시 time함수 클리어 (이벤트 호출 시 마다 반복)\n        clearTimeout(timer);\n    }\n    // 2. 함수 할당\n    // 3-2. 함수 할당 (이벤트 호출 시 마다 반복)\n    timer = setTimeout(function () {\n        console.log('비동기 요청', e.target.value);\n    }, 2000);\n    // 4. 설정 시간 지나면 함수 종료\n});\n```\n\n[Lodash](https://lodash.com/) 와 [Underscore](https://underscorejs.org/)에는 해당 기능들이 구현되어 있다.\n\n---\n\n#### 🙏Reference\n\n- [[JS] 쓰로틀링(Throttling)과 디바운싱(Debouncing)](https://jm-web.tistory.com/33)\n- [zerocho blog - 쓰로틀링과 디바운싱](https://www.zerocho.com/category/JavaScript/post/59a8e9cb15ac0000182794fa)\n- [CSS-Tricks 의 Throttling 과 Debouncing](https://css-tricks.com/debouncing-throttling-explained-examples/) => 예시가 구현되어 있음\n"
  },
  {
    "path": "Performance/requestAnimationFram(rAF).md",
    "content": "# requestAnimationFrame(rAF)\n\n사용자들이 서비스를 선택하는데 있어서 기준은 다양하다. 그 중에서 하나는 인터렉션(Interaction)이다. 인터렉션은 상호 작용이라는 사전적 뜻을 가지며, 서비스 차원에서는 **사용자가 제품이나 서비스를 사용하면서 상호간 작용하는 것**이라는 넓은 의미를 가진다.\n\n이에 서비스를 운영하는 기업들은 부드러운 인터렉션을 만들어내기 위해서 노력을 하고 있다.\n\n개발자의 입장에서 생각을 하면 부드러운 인터렉션을 만들어내기 위해서 프레임 수에 맞도록 시각적인 효과를 만들어야 한다.\n\n오늘날의 기기들은 시각적인 효과를 위해서 초당 60번 화면을 다시 그린다.(요즘에는 주사율이 좋은 모니터들이 많다.) 그러므로 60개 화면안에서 시각적인 효과를 표현해야한다.\n\n초당 60개의 프레임을 렌더링해야한다는 말은 1프레임이 약 16ms(1000ms/60frames)라는 것을 의미한다. 즉 부드러운 화면을 위해서 우리는 16ms미만으로 새로 보여줄 화면을 만들면 된다.\n\n우리가 16ms안에 화면을 만들기 전에 렌더링 파이프라인에 대해서 알아야 한다.\n\n![Pipeline](https://user-images.githubusercontent.com/24274424/69901968-b12c9800-13cb-11ea-9e6f-26ad0167ad53.png)\n출처 : https://developers.google.com/web/fundamentals/performance/rendering/?hl=ko\n\n> 참고: [웹 브라우저의 작동 원리](https://github.com/Im-D/Dev-Docs/blob/master/Browser/%EC%9B%B9%20%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80%EC%9D%98%20%EC%9E%91%EB%8F%99%20%EC%9B%90%EB%A6%AC.md)\n\n- 애니메이션 및 기타 작업들을 수행하는 `Javascript`\n- CSS 규칙을 어떤 요소에 적용할지 계산하는 `Style`\n- 브라우저가 요소에 어떤 규칙을 적용할지 알게 되면 화면에서 얼마나 공간을 차지하고 어디에 배치되는지 계산하는 `Layout(reflow)`\n- 픽셀을 채우는 `Paint(redraw)`\n- 이러한 작업들이 개별적인 레이어에서 진행되고 이를 합치는 `Composite`\n\n때에 따라 다르지만 기본적으로는 한 번의 화면을 그리기 위해서 위와 같은 과정을 수행한다. \n\n이전에는 애니메이션을 구현하는데 있어서 `setTimeout()` 또는 `setInterval()`을 사용되었다. 하지만 주어진 시간내에 동작을 할 뿐이지 위에서 언급한 프레임은 고려되지 않는다.\n\n이에 사용되는 것이 `requestAnimationFrame()`이다.\n\n이 메소드는 실제 화면이 갱신되어 표시되는 주기에 따라 함수를 호출해주기 때문에 Callback이 프레임 시작시 실행되는 것이 보장된다.\n\nCallback의 수는 보통 1초에 60회지만, 일반적으로 대부분의 브라우저에서는 W3C 권장사항에 따라 그 수가 디스플레이 주사율과 일치하게 된다. \n\n대부분의 최신 브라우저에서는 성능과 배터리 수명 향상을 위해 `requestAnimationFrame()` 호출은 백그라운드 탭이나 hidden `<iframe>`에서 실행이 중단된다.\n\n## 예시\n\nJbee님 포스팅 중 [스크롤 이벤트 최적화](https://jbee.io/web/optimize-scroll-event/)를 보면 `rAF`를 이용하여 스크롤 이벤트를 구현하는 방식을 살펴볼 수 있는데 간단히 보면 다음과 같다.\n\n```js\nfunction rAFScroll(callback) {\n  let tick = false\n\n  return function trigger() {\n    if (tick) {\n      return;\n    }\n\n    tick = true\n    return requestAnimationFrame(function task() {\n      tick = false\n      return callback();\n    })\n  }\n}\n```\n\n`trigger`함수를 보면 `tick`의 값이 `false`일 경우에만 `requestAnimationFrame`의 콜백이 실행된다. <br/>즉, **콜백 함수(`callback`)가 `rAF`에 의해 브라우저가 최적화된 상태에서만 `tick`의 값이 `false`가 되고 실행**된다. 순차적으로 정리하면 다음과 같다.\n\n1. `rAF`의 콜백 함수인 `task`함수가 `animation frame`에 들어간다.\n2. `tick`의 값이 `true`라면 `trigger`함수가 호출되어도 콜백 함수가 실행되지 않는다.\n3. `task`함수가 실행되면서 `tick`이 `false`가 되면 다시 콜백 함수가 실행될 수 있는 환경이 된다.\n\n이처럼 쓰로틀링을 사용하지 않고 `rAF`을 사용하여 이벤트 최적화가 가능하며 `rAF`는 애니메이션의 최적화에도 많이 사용되는 API이기 때문에 잘 알아두는게 좋다.\n\n## 브라우저 호환성\n\n![image](https://user-images.githubusercontent.com/24274424/69902311-539a4a80-13cf-11ea-85b8-774690c747b0.png)\n\n---\n\n#### Reference\n\n- [스크롤 이벤트 최적화](https://jbee.io/web/optimize-scroll-event/)\n- [requestAnimationFrame() 개념 정리하기](https://fullest-sway.me/blog/2019/01/28/requestAnimationFrame/)\n- [Deview 2018 - 웹 성능 최적화에 필요한 브라우저의 모든 것](https://www.slideshare.net/deview/125-119068291)"
  },
  {
    "path": "Performance/기본적인 렌더링 최적화 방법.md",
    "content": "# 기본적인 렌더링 최적화 방법\n\n> 렌더링 최적화와 관련해서는 무수한 내용이 있으며 하나의 파일에 담아내는 데 한계가 있다고 판단하여 (기존의 내용 + Front-End-Performance-Checklist 레포지토리)를 정리하여 작성하였습니다.\n> \n> 이외에도 많은 최적화 내용이 있으니 찾아보시는 걸 추천해 드립니다.\n\n프론트엔드 분야가 관심을 받게 되면서, 성능 향상을 도와주는 기술과 도구들이 많이 생겼다. 지금, 이 순간에도 만들어지고 있다. \n\n분야별로 많은 최적화 방법이 있지만, 프론트엔드에서 가장 많이 보면서 사용하는 5가지에 대해서만 알아보려고 한다.\n\n<br/>\n\n## ![html5_img] HTML\n\n- [ ] **HTML 코드를 압축**하며, 최종적으로 나오는 번들된 파일에서 주석, 공백, 줄바꿈을 제거한다.\n\n프로트엔드 개발을 하는 데 있어서 Webpack 같은 번들링 도구를 사용하면서 플러그인을 적용해주면 HTML 파일도 Compress 작업을 거치기 때문에 크게 고려하지 않아도 된다. 실제로 크기를 줄이고 측정 시 로딩 속도를 높여주며, 다운로드 시간을 줄여주는 것을 확인했다.\n\n간단하게 Big Size의 파일을 가지고 확인을 해보자\n\n> :link: [Online html-minifier](http://minifycode.com/html-minifier/)\n\n- [ ] **CSS 태그를 자바스크립트 태그 앞에** 두어 자바스크립트 코드보다 먼저 로드가 되도록 한다.\n\n자바스크립트 전에 CSS 태그를 두면 브라우저의 렌더링 속도를 높이는 병렬 다운로드가 가능해진다.\n\n- [ ] 다른 기술적 가능성이 없을 때 iframe을 사용하고, **최대한 iframe을 사용하지 말아야 한다.**\n\niframe을 기본적으로 Main 페이지와 리소스를 공유하지 않아서 iframe 내부적으로 리소스를 다시 호출한다. 이렇게 되면 한 화면의 2개의 렌더링 페이지를 보게 되는 것과 동일하게 된다.\n\n<br/>\n\n## ![css_img] CSS\n\n- [ ] **CSS 파일을 압축**하고, 최종적으로 나오는 번들된 파일에서 주석, 공백, 줄바꿈을 제거한다.\n\n프로트엔드 개발을 하는 데 있어서 Webpack 같은 번들링 도구를 사용하면서 플러그인을 적용해주면 CSS 파일도 Compress 작업을 거치기 때문에 크게 고려하지 않아도 된다. 실제로 크기를 줄이고 측정 시 로딩 속도를 높여주며, 다운로드 시간을 줄여주는 것을 확인했다.\n\n- [ ] DOM이 로드되는 데 시간이 오래 걸리지 않도록 **CSS 파일은 Non-Blocking**이 되어야 한다.\n\nCSS 파일은 페이지 로드와 렌더링을 지연시킬 수 있다. 이에 방안으로 `preload`를 통해 브라우저가 페이지의 콘텐츠를 보여주기 전에 CSS 파일을 미리 로드할 수 있다.\n\n```html\n<link rel=\"preload\" href=\"style.min.css\" as=\"style\" onload=\"this.rel='stylesheet'\">\n<noscript><link rel=\"stylesheet\" href=\"style.min.css\"></noscript>\n```\n\n위와 같이 link tag에 `rel=\"preload\"` 와 `as=\"style\"` 를 넣어주면 된다.\n\n이와 관련된 아래의 글을 읽어보는 것을 추천한다.\n\n> :link: [preload & preconnect & prefetch](https://github.com/Im-D/Dev-Docs/blob/master/HTML/preload%26prefetch.md)\n\n- [ ] **CSS 크리티컬**(또는 '스크롤 없이 볼 수 있는 부분')은 페이지의 보이는 부분을 렌더링하는데 사용되는 모든 CSS를 수집한다. 주요 CSS 호출 전, `<style></style>` 사이에 한 줄로 추가하게 된다.\n\n화면에 필요한 부분만 모아서 inline으로 삽입하면서, 초기 렌더링 속도를 높이면서 inline으로 삽입하여 request를 줄이게 된다.\n\n- [ ] **외부 또는 인라인 CSS를 `<body>` 안에 작성해서는 안된다.** (HTTP/2에서는 다르게 평가될 수 있다.)\n\n먼저 디자인에서 콘텐츠를 분리하는 것이 좋다. 또한 코드 유지보수를 쉽게 만들고 사이트 접근성을 높인다. \n\nHTML 페이지의 파일 크기와 로딩 시간을 줄여준다.\n\n결론적으로 항상 외부 스타일을 사용하거나 CSS를 `<head>`에 작성한다.\n\n- [ ] **스타일 시트를 분석**하여 불필요한 중복 CSS 선택자를 찾는다.\n\n중복, 또는 유효성 처리가 CSS 코드에서 발생한다. CSS 파일을 분석하고 복잡성을 해결하게 되면 파일을 읽는 속도를 높일 수 있다.\n\n- [ ] CSS 스프라이트 기법을 사용하여 많은 아이콘을 사용하는 곳에서 request의 수를 줄인다.\n\nCSS 스프라이트 기법은 이미지 여러 개를 하나로 만들고 `background-position` 속성을 사용하여 필요한 부분의 이미지만 보여주는 기법이다.\n\n다수의 이미지가 포함된 웹 사이트의 경우, 이미지의 수 만큼 HTTP 요청을 했던 방식을 **한 번의 요청으로 줄일 수 있어** 초기 Rendering에 걸리는 시간을 줄인다.\n\n```html\n<style>\n    .up,\n    .down,\n    .right,\n    .left {\n        background: url(\"./img_css_image_sprites.png\") no-repeat;\n    }\n\n    .up {\n        width: 21px;\n        height: 20px;\n        background-position: 0 0;\n    }\n\n    .down {\n        width: 21px;\n        height: 20px;\n        background-position: -21px 0;\n    }\n\n    .right {\n        width: 22px;\n        height: 20px;\n        background-position: -42px 0;\n    }\n\n    .left {\n        width: 22px;\n        height: 20px;\n        background-position: -65px 0;\n    }\n</style>\n\n<body>\n    <div class=\"up\"></div>\n    <div class=\"down\"></div>\n    <div class=\"right\"></div>\n    <div class=\"left\"></div>\n</body>\n```\n\n<br/>\n\n## ![fonts_img] Fonts\n\n- [ ] 웹 또는 어플리케이션에서 **WOFF(Web Open Font Format) 2 포맷** 을 사용하는 것이 좋다.\n\nWOFF 이후 WOFF2 형식이 개발되었는데, WOFF에 비해 30%~50% 정도 더 압축되어 훨씬 가벼워졌다. 2018년 기준으로는 IE를 제외한 거의 모든 브라우저의 최신 버전에서 지원하고 있다.\n\n> :link: [Can I use... - woff2](https://caniuse.com/#search=woff2)\n\n구글의 자료에 따르면 WOFF 2.0 폰트 압축 포맷은 WOFF 1.0보다 평균 30% 더 많이 쓰인다고 한다. \n\n- [ ] 폰트를 더 빨리 로드하기 위해 **`preconnect`** 를 사용한다.\n\n```html\n<link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin>\n```\n\n웹 사이트에 접속하면, 브라우저는 DNS 서버를 찾고, 리소스(폰트, CSS...) 수집이 끝나기 전, 조회가 완료될 때까지 대기한다. \n\n이 경우 prefetch와 preconnect를 사용하게 되면 브라우저가 DNS 정보를 찾고 폰트 파일을 호스팅하는 서버에 대한 TCP 연결을 허용받는다. \n\n브라우저가 폰트 정보와 서버에 요청해야 하는 폰트 파일이 담긴 CSS 파일을 파싱할 때 DNS 정보를 확인하고, 커넥션 풀에 있는 서버에 대한 개방형 연결을 준비하게 되어 성능을 높일 수 있다.\n\n> :link: [preload & preconnect & prefetch](https://github.com/Im-D/Dev-Docs/blob/master/HTML/preload%26prefetch.md)\n\n<br/>\n\n## ![images_img] Images\n\n- [ ] 이미지는 최적화되어야 한다. 최종 사용자에게 영향을 미치지 않는 선에서 **압축**되어야 한다.\n\n당연히 압축된 이미지는 용량이 작아지기 때문에 브라우저에서 더 빨리 로드되고, 적은 데이터를 소비한다.\n\n- [ ] **적절한 이미지 형식.**\n\n적절한 이미지 형식이란 웹 사이트를 느리게 만들지 않을 형식을 사용하자는 것이다. 요즘은 차세대 포맷인 JPEG 2000m, JPEG XR 또는 WebP를 사용하는 것이 좋다.\n\n대부분의 브라우저에서 현재 WebP 포맷이 지원되고 있다. (사파리 제외)\n\n> :link: [Can I use - webP](https://caniuse.com/#search=WebP)\n\n- [ ] **Image Lazy Loading**\n\n이미지 레이지 로딩에 관련된 많은 글이 존재한다. \n\n레이지 로딩에 따른 여러 방법이 존재하지만, 기본적인 방법인 \n\n1. facebook과 같이 **skeleton UI** 를 사용하는 방법, \n2. Medium과 같은 **progressive image loading**, \n3. 무한스크롤시 IntersectionObserver를 사용하여 클래스로 background-image를 주는 방법 \n\n등등이 있다. \n\n위와 관련된 글은 아래의 참조 글을 읽어보는 것이 좋다.\n\n> :link: (Developers Google)[https://developers.google.com/web/fundamentals/performance/lazy-loading-guidance/images-and-video/]\n\n<br/>\n\n## ![javascript_img] JavaScript\n\n- [ ] **JS 파일을 압축**하고, 최종적으로 나오는 번들된 파일에서 주석, 공백, 줄바꿈을 제거한다.\n\n프로트엔드 개발을 하는 데 있어서 Webpack 같은 번들링 도구를 사용하면서 플러그인을 적용해주면 JS 파일도 Compress 작업을 거치기 때문에 크게 고려하지 않아도 된다. 실제로 크기를 줄이고 측정 시 로딩 속도를 높여주며, 다운로드 시간을 줄여주는 것을 확인했다.\n\n- [ ] **자바스크립트 코드를 `<body>` 중간에 두어서는 안 된다.**\n\n코드를 그룹화를 하여 외부 파일로 만들거나 페이지의 마지막(`</body>` 이후)에 작성하는 것이 좋다.\n\n자바스크립트 코드를 `<body>` 중간에 넣게 되면 DOM이 구성되는 과정에서 코드가 로드되기 때문에 페이지 속도를 떨어뜨리게 된다.\n\n가장 좋은 옵션은 외부 파일을 `async` 또는 `defer` 속성과 함께 사용하여 DOM 로딩을 막지 않도록 하는 것이다. \n\n- [ ] 자바스크립트 파일을 비동기적으로 로드하기 위해 **`async`를 사용하거나 지연시키기 위해 `defer` 속성을 사용**해야 한다.\n\n```html\n<!-- Defer Attribute -->\n<script defer src=\"foo.js\">\n<!-- Async Attribute -->\n<script async src=\"foo.js\">\n```\n\n자바스크립트는 HTML 문서의 파싱을 차단하기 때문에, 파서는 `<script>` 태그에 도달할 때 (특히 `<head>` 안에 있을 때) 파싱을 멈추고 스크립트를 실행한다. 스크립트를 페이지의 상단에 두는 경우 `async` 또는 `defer`를 사용하는 것이 권장되지만 언제나 이 속성을 사용하여 성능 이슈를 피하는 것은 좋은 습관이다.\n\n> :link: [ES6-module-in-Browser](https://github.com/Im-D/Dev-Docs/blob/master/ECMAScript/ES6-module-in-Browser.md)\n\n- [ ] **외부 라이브러리를 잘 보고 선택해서 사용하자.** 대부분의 경우, 똑같은 기능을 하지만 더 가벼운 라이브러리가 있다.\n\n- [ ] **자바스크립트 파일의 성능 문제를 확인**해야 한다.\n\n자바스크립트의 복잡도는 런타임 성능을 떨어뜨릴 수 있다. 크롬 개발자 도구의 타임라인 툴을 이용하여 스크립트 이벤트를 테스트하고 너무 오랜 시간이 걸리는 이벤트를 찾아서 수정하여야 한다.\n\n---\n\n#### Reference\n\n- [Front-End-Performance-Checklist](https://github.com/ParkSB/Front-End-Performance-Checklist)\n- [성능이 중요한 이유](https://developers.google.com/web/fundamentals/performance/why-performance-matters/?hl=ko)\n\n[html5_img]:https://img.icons8.com/dusk/24/000000/html-5.png\n[css_img]:https://img.icons8.com/dusk/24/000000/css3.png\n[fonts_img]:https://img.icons8.com/dusk/24/000000/woff.png\n[images_img]:https://img.icons8.com/dusk/24/000000/image-file.png\n[javascript_img]:https://img.icons8.com/color/24/000000/javascript.png"
  },
  {
    "path": "Performance/서버 사이드 렌더링(SSR).md",
    "content": "# 서버 사이드 렌더링(SSR)\n\n<br/>\n\n## SPA의 등장\n\n모바일 웹이 등장하고 활성화되기 시작하면서 일반 데스크탑보다 성능이 낮은 모바일에서도 웹 페이지를 출력할 일이 늘었고 이에 따라 SPA가 등장하게 되었다.\n\n**SPA(Single Page web Application)는 최초 한 번 페이지를 로딩한 뒤 데이터가 변하면 변한 부분만 다시 로드하는 방식의 애플리케이션**을 말한다.\n\n<br/>\n\n## 클라이언트 사이드 렌더링 vs 서버 사이드 렌더링\n\n### 클라이언트 사이드 렌더링\n\n---\n\n- **일관성 있는 코드의 작성**\n\n**서버에서는 JSON만 넘겨주고 html을 그리는 역할이 클라이언트 측으로 넘어가면서 JS를 이용해 화면을 그리게 되었다.**\n\n클라이언트 사이드 방식을 통해 클라이언트 측에서는 좀 더 편하게 일관성 있는 코드를 작성할 수 있다.\n\n하지만, 클라이언트 사이드 렌더링 방식에는 문제가 존재한다.\n\n- **초기 구동 속도의 증가**\n\n페이지를 그리고, JS 파일을 다운받고, 그리고 JS가 화면을 그리는 시간이 모두 지나야 화면이 사용자에게 보여진다. 즉, **초기 구동 속도가 낮아 사용자 경험을 떨어트리게 된다.** <br/> 비록, 초기 구동 속도가 느리지만 초기 화면을 로드한 후 화면을 데이터의 변화에 따라 그릴 때는 빠른 인터렉션을 보인다.\n\n- **검색 엔진 최적화(Search Engine Optimization, SEO)**\n\n클라이언트 사이드 렌더링 방식에서는 초기 html에는 컨텐츠가 없는 **빈 껍데기**인 상태이다.\n\n모든 검색 엔진이 그런 것은 아니지만, **검색 엔진에서 컨텐츠를 검색할 때 JS 파일의 내용은 읽어들이지 못하기 때문에** B2C를 목적으로 하는 웹 사이트의 경우에는 치명적인 문제가 될 수 있다.\n\n### 서버 사이드 렌더링\n\n---\n\n서버 사이드 렌더링의 경우, 클라이언트 사이드와 반대로 생각하면 편하다.\n\n서버 사이드 렌더링이란 개념은 **서버에서 미리 페이지를 그려 클라이언트에 보낸다.**\n\n이 때 **가상DOM을 활용하여 바뀐 부분만 바꿔주는 등 클라이언트에서의 부하는 최소화**한다.\n\n- **초기 구동 속도의 감소**\n\n위에서 말했듯이 서버에서 미리 페이지를 그려 클라이언트에 보내기 때문에 사용자 경험이 개선 되고 사용자 입장에서는 화면이 바뀌는 과정을 보지 않고 **최초에 완성된 화면을 볼 수 있게 된다.**\n\n- **검색엔진 최적화(Search Engine Optimization, SEO)**\n\n이또한 마찬가지로 서버에서 컨텐츠를 포함하여 화면을 그리고 클라이언트 측으로 넘겨주기 때문에 **검색엔진에서는 컨텐츠를 포함한 내용을 검색**하게 된다. 즉, 클라이언트 사이드 렌더링에서 존재했던 SEO 문제를 해결할 수 있다.\n\n- **복잡도와 서버의 부하 증가**\n\nReact를 쓴다고 가정했을 때 서버 쪽에서 JSX를 사용할 수 있도록 빌드하거나 변환하는 과정이 필요해진다. 최초 세팅 시 어려움이 증가하게 되는 것이다. 물론 이러한 러닝 커브를 줄이기 위해 React에서는 `Next.js`와 Vue에서는 `Nuxt.js`와 같은 **서버사이드 라이브러리**가 존재한다.\n\n그리고 클라이언트측에서의 부하가 없어진 것이 아닌 서버로 넘어간 것이기 때문에 써드 파티 라이브러리를 통해 비동기식으로 렌더링이 발생하도록 만들어주거나 웹 서버와 API 서버를 분리하는 등의 작업이 필요하다.\n\n<br/>\n\n---\n\n#### Reference\n\n- [카카오페이지 웹 React 포팅 후기](https://medium.com/@ljs0705/%EC%B9%B4%EC%B9%B4%EC%98%A4%ED%8E%98%EC%9D%B4%EC%A7%80-%EC%9B%B9-react-%ED%8F%AC%ED%8C%85-%ED%9B%84%EA%B8%B0-76402cc5e031)\n- [서버사이드 렌더링 그리고 클라이언트 사이드 렌더링](http://asfirstalways.tistory.com/244)\n- [JSX — React JS+ Java server side rendering (SSR) — 2018](https://codeburst.io/jsx-react-js-java-server-side-rendering-ssr-2018-cf3aaff7969d)\n- [서버사이드 렌더링](https://velopert.com/3425)\n"
  },
  {
    "path": "Performance/점진적향상_우아한하향.md",
    "content": "# 점진적 향상, 우아한 하향\n\n2가지 개발접근법이 있다. 우아한 하향과 점진적인 향상.<br/>\n간단히 정리하자면 다음과 같이 정의할 수 있다.\n<br/>\n\n## 우아한 하향(Graceful degradation)\n\n`Graceful Degradation`, 이 자체는 사실 단어만 보면 크게 와닿지 않는다.\n이는 기능을 제대로 구현하면서, 기술적인 이유나 Device의 호환성 여부에 의해 해당 기능을 제공받지 못하는 사용자에게 다른 버전의 대체 기능을 제공한다.\n혹은, 단순히 `맥 OS에서는 해당 기능을 제공할 수 없기 때문에 Windows 컴퓨터를 이용해주세요.`와 같은 문구를 제공한다.\n\n정리하면 다음과 같다.\n\n- 원하는 기능을 갖는 또다른 버전을 제공하거나, 사용자가 제품의 결점이 사용성을 보장하기 위한 안전 조치때문이라는 것을 인지하도록 만드는 것.\n- 최신 기술 기반 또는 기기에서 동작하는 기능을 만들고 나서 오래된 기술 기반 혹은 기기에서도 유사한 성능으로 동작하도록 조치하는 것.\n- 사용자들의 기기를 위해 별도의 버전을 만들어 놓는 것.\n\n`Graceful Degradation`이 유용한 경우가 있다.\n\n- 오랜된 제품을 새로 개발하기엔 시간이 부족하고 방법과 영향도를 파악할 수 없는 경우.\n- 일반적으로 `Graceful Degradation`을 통해 개발이 진행되면 성능이 더 좋을 확률이 높기 때문에 수행 속도에 민감한 애플리케이션의 경우.(ex, rAF vs jQuery .animate)\n\n<br/>\n\n## 점진적 향상(Progressive enhancement)\n\n`Progressive Enhancement`는 `Graceful Degradation`과 반대로 생각하면 된다.\n웹의 관점에서 봤을 때 이에는 몇 가지 원칙이 있는데 다음과 같다.\n\n- 컨텐츠가 모든 브라우저에서 표현.\n- 기능이 모든 브라우저에서 사용.\n- `Semantic Markup`으로 표시.(HTML5)\n- 레이아웃의 향상은 `CSS`로 처리.\n- 동작의 향상은 `unobtrusive javascript`로 처리.\n- 사용자가 브라우저 설정을 원하는대로 변경해도 기능이 잘 동작함.\n\n> unobtrusive javascript란 필수적인 기능들을 HTML만으로 최대한 처리하고 그 위에 JS를 이용해 기능을 추가한다는 의미.\n\n몇 가지 특징을 정리해보면 다음과 같다.\n\n- 사용가능한 기능을 바탕으로, 향상된 기능을 적용하기 전에 테스트를 통해 풍부한 사용자 경험을 **하나씩 증가**시키는 것이다.\n- 많은 테스트를 통해 말그대로 **기능을 점진적으로 향상**시키는 것.\n- **기초부터 차곡차곡** 쌓아서 발전해 나가는 방법\n\n해당 개발접근법을 적용한 대표적인 예로 `jQuery`가 있다. HTML의 기능을 충분히 활용하도록 설계되었기 때문에 다른 JS의 사용을 최소화할 수 있다고 설명하고 있다.\n\n결국, `jQuery`도 JS기 떄문에 살짝 모순적인 얘기일 수 있다.\n하지만, `jQuery`가 크로스 브라우징을 해결할 수 있는 대표적인 방법 중 하나라는 것은 이를 방증한다고 볼 수 있을 것 같다.\n\n보통 우리는 `Graceful Degradation`을 많이 봐왔을 것이다. 브라우저가 다양화되고 기술의 지원 여부가 브라우저에 따라 상이하기 때문이다.\n하지만, 어떻게 보면 `Progressive Enhancement`접근법을 통해 개발된 애플리케이션의 경우, 사용자가 인지할 수 없기 때문에 전자가 더 많다고 보기도 어려울 수 있다.\n\n<br/>\n\n---\n\n#### Reference\n\n- [적절한 낮춤 대 점진적 향상](http://www.clearboth.org/51_graceful_degradation_versus_progressive_enhancement/)\n- [Progressive Enhancement와 Graceful Degradation](https://m.blog.naver.com/PostView.nhn?blogId=sef16&logNo=70164174952&proxyReferer=https%3A%2F%2Fwww.google.com%2F)\n- [W3C - Graceful degradation versus progressive enhancement](https://www.w3.org/wiki/Graceful_degradation_versus_progressive_enhancement)\n"
  },
  {
    "path": "README.md",
    "content": "# Dev Docs\n\n개개인이 공부한 내용을 문서화하여 공유하는 공간\n\n- [📑 **Category(to Wiki)**](https://github.com/Im-D/Dev-Docs/wiki)\n- [✏️ This Week Post](#-this-week-post)\n- [📅 History](#-history)\n\n### 🔒 Rule\n\n- 마크 다운을 작성할 때는 다음과 같은 형식을 따른다.\n\n  [마크다운 규칙](https://github.com/im-d-team/Dev-Docs/blob/master/Rules/Markdown.md)\n  \n- 커밋은 다음을 참고하여 작성 \n  \n  [커밋 규칙](https://github.com/im-d-team/Dev-Docs/blob/master/Rules/Commit.md)\n\n### 🔒 Meeting Note Rule\n\n- **자신이 원하는 주제** 를 조사한다.(어떤 내용이 되어도 상관은 없다.)\n- 작성한 글을 주제에 맞게 올리고 **링크** 를 넣는다.(링크 양식은 아래 참조)\n- 글의 작성은 미리 정한 **Rule에** 맞게 작성한다.\n\n<details>\n<summary> 링크 양식 </summary>\n\n```md\n[POST_NAME](POST_ADDRESS)\n```\n\n</details>\n\n<details>\n<summary> 멤버 체크양식 </summary>\n\n#### xx월 xx일\n\n- [ ] BKJang : []()\n- [ ] SeonHyungJo : []()\n- [ ] Jinseong : []()\n- [ ] Dae-Hwa: []()\n\n</details>\n\n<details>\n<summary> Deprecated </summary>\n\n```md\n~[Title of contents](Link)~\n```\n\n- ex) ~[브라우저 Redering 과정](https://github.com/Im-D/Dev-Docs/blob/master/Deprecated/%EC%9B%B9%20%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80%EC%9D%98%20%EC%9E%91%EB%8F%99%20%EC%9B%90%EB%A6%AC.md)~\n\n</details>    \n\n---\n\n### [OS](https://github.com/im-d-team/Dev-Docs/blob/master/CS/OS.md)\n\n- ch3 Process\n  - 3.1 Process Concept : dididy(2021.04.04)\n  - 3.2 Process Scheduling : SeonHyungJo(2021.04.11)\n  - 3.3 Operations on Processes : BKJang(2021.04.18)\n  - 3.4 Interprocess Communication : Dae-Hwa(2021.04.25)\n  - 3.5 IPC in Shared-Memory Systems : Dae-Hwa(2021.04.25)\n  - 3.6 IPC in Message-Passing Systems : dididy(2021.05.02)\n  - 3.7 Examples of IPC Systems\n    - 3.7.4 Pipes : SeonHyungJo(2021.05.09)\n  - 3.8 Communication in Client–Server Systems\n    - 3.8.1 Sockets : BKJang(2021.05.16)\n\n### 📅 History\n- [x] dididy : [OS/Ch05-CPU Scheduling](https://github.com/im-d-team/Dev-Docs/blob/master/OS/Ch05-CPU%20Scheduling.md)\n\n- [x] dididy : [CS/Ch04-Threads&Concurrency](https://github.com/im-d-team/Dev-Docs/blob/master/CS/Ch04-Threads&Concurrency.md)\n\n\n<!--<details>\n<summary> 2021년 3월 </summary>-->\n\n#### 03월 28일\n\n- [ ] SeonHyungJo : [Security/Response_Header_Security](https://github.com/im-d-team/Dev-Docs/blob/master/Security/Response_Header_Security.md)\n\n<!--</details>-->\n\n<!--<details>\n<summary> 2021년 2월 </summary>-->\n\n#### 02월 28일\n\n- [ ] Dae-Hwa : [CS/플로이드-와샬-알고리즘](https://github.com/im-d-team/Dev-Docs/blob/master/CS/%ED%94%8C%EB%A1%9C%EC%9D%B4%EB%93%9C-%EC%99%80%EC%83%AC-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98.md)\n- [ ] dididy : [Javascript/Jest](https://github.com/im-d-team/Dev-Docs/blob/master/Javascript/Jest.md)\n\n#### 02월 07일\n\n- [ ] Dae-Hwa : [Java/junit-setup](https://github.com/im-d-team/Dev-Docs/blob/master/Java/junit-setup.md)\n\n<!--</details>-->\n\n<!--<details>\n<summary> 2021년 1월 </summary>-->\n\n#### 01월 24일\n\n- [ ] SeonHyungJo : [React/React Server Components](https://github.com/im-d-team/Dev-Docs/blob/master/React/React%20Server%20Components.md)\n- [ ] EUNJIHA : [iOS/Xcode](https://github.com/im-d-team/Dev-Docs/blob/master/iOS/Xcode.md)\n\n#### 01월 17일\n\n- [x] Dae-Hwa : [CS/union-find](https://github.com/im-d-team/Dev-Docs/blob/master/CS/union-find.md)\n- [x] JegalEun : [Network/Switch](https://github.com/im-d-team/Dev-Docs/blob/master/Network/Switch.md)\n\n#### 01월 10일\n\n- [ ] EUNJIHA : [Java/JPA](https://github.com/im-d-team/Dev-Docs/blob/master/Java/JPA.md)\n- [x] SeonHyungJo : [React/SWR](https://github.com/im-d-team/Dev-Docs/blob/master/React/SWR.md)\n\n#### 01월 03일\n\n- [x] Dae-Hwa : [CS/methods_in_IPC](https://github.com/im-d-team/Dev-Docs/blob/master/CS/methods_in_IPC.md)\n- [x] dididy : [Javascript/Storybook](https://github.com/im-d-team/Dev-Docs/blob/master/Javascript/Storybook.md)\n- [x] JegalEun : [Network/3-way handshaking & 4-way handshaking](https://github.com/im-d-team/Dev-Docs/blob/master/Network/3-way%20handshaking%20&%204-way%20handshaking.md)\n\n<!--</details>-->\n\n<details>\n<summary> 2020년 12월 </summary>\n\n#### 12월 27일\n\n- [x] EUNJIHA : [Tool/Package Manager](https://github.com/im-d-team/Dev-Docs/blob/master/Tool/Package%20Manager.md)\n\n</details>\n\n<details>\n<summary> 2020년 11월 </summary>\n\n#### 11월 22일\n\n- [x] dididy : [Javascript/Web_Storage_API](https://github.com/im-d-team/Dev-Docs/blob/master/Javascript/Web_Storage_API.md)\n- [x] JegalEun : [Design_Pattern/JSP model](https://github.com/im-d-team/Dev-Docs/blob/master/Design_Pattern/JSP%20model.md)\n- [x] Dae-Hwa : [CS/integer_representation](https://github.com/im-d-team/Dev-Docs/blob/master/CS/integer_representation.md)\n\n#### 11월 08일\n- [x] BKJang : [Javascript/OOP_of_JS](https://github.com/im-d-team/Dev-Docs/blob/master/Javascript/OOP_of_JS.md)\n- [x] SeonHyungJo : [Browser/Cookie_Store](https://github.com/im-d-team/Dev-Docs/blob/master/Browser/Cookie_Store.md)\n- [x] EUNJIHA : [React/Component, Props, State](https://github.com/im-d-team/Dev-Docs/blob/master/React/Component,%20Props,%20State.md)\n\n#### 11월 01일\n- [x] dididy : [CS/Bomb-Lab(1)](https://github.com/im-d-team/Dev-Docs/blob/master/CS/Bomb-Lab(1).md)\n- [x] Dae-Hwa : [CS/aspect-oriented-programming](https://github.com/im-d-team/Dev-Docs/blob/master/CS/aspect-oriented-programming.md)\n- [x] JegalEun : [Network/congestion control](https://github.com/im-d-team/Dev-Docs/blob/master/Network/congestion%20control.md)\n\n</details>\n\n<details>\n<summary> 2020년 10월 </summary>\n\n#### 10월 11일\n- [x] Dae-Hwa : [Java/date-api-in-java](https://github.com/im-d-team/Dev-Docs/blob/master/Java/date-api-in-java.md)\n- [x] SeonHyungJo : [Browser/Cookie](https://github.com/im-d-team/Dev-Docs/blob/master/Browser/Cookie.md)\n- [x] EUNJIHA : [Database/DB Connection Pool](https://github.com/im-d-team/Dev-Docs/blob/master/Database/DB%20Connection%20Pool.md)\n\n</details>\n\n<details>\n<summary> 2020년 9월 </summary>\n\n#### 09월 27일\n- [x] dididy : [Javascript/WebRTC](https://github.com/im-d-team/Dev-Docs/blob/master/Javascript/WebRTC.md)\n- [x] EUNJIHA : [Database/Query Builder ( Knex](https://github.com/im-d-team/Dev-Docs/blob/master/Database/Query%20Builder%20(%20Knex.js).md)\n- [x] JegalEun : [Network/Flow control](https://github.com/im-d-team/Dev-Docs/blob/master/Network/Flow%20control.md)\n\n#### 09월 13일\n- [x] BKJang : [React/ImmutableState](https://github.com/im-d-team/Dev-Docs/blob/master/React/ImmutableState.md)\n- [x] SeonHyungJo : [Node.js/make_meta_file.md](https://github.com/im-d-team/Dev-Docs/blob/master/Node.js/make_meta_file.md)\n- [x] Dae-Hwa : [CS/dependency-inversion-principle](https://github.com/im-d-team/Dev-Docs/blob/master/CS/dependency-inversion-principle.md)\n\n</details>\n\n<details>\n<summary> 2020년 8월 </summary>\n\n#### 08월 30일\n\n- [x] EUNJIHA : [Database/Types of Databases](https://github.com/im-d-team/Dev-Docs/blob/master/Database/Types%20of%20Databases.md)\n- [x] BKJang : [Performance/Throttling vs Debouncing](https://github.com/im-d-team/Dev-Docs/blob/master/Performance/Throttling%20vs%20Debouncing.md)\n- [x] dididy : [Javascript/논리연산자](https://github.com/im-d-team/Dev-Docs/blob/master/Javascript/%EB%85%BC%EB%A6%AC%EC%97%B0%EC%82%B0%EC%9E%90.md)\n- [x] SeonHyungJo : [ML/머신러닝이란](https://github.com/im-d-team/Dev-Docs/blob/master/ML/%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D%EC%9D%B4%EB%9E%80.md)\n\n#### 08월 23일\n\n- [x] dididy : [Javascript/prototype(2)](https://github.com/im-d-team/Dev-Docs/blob/master/Javascript/prototype(2).md)\n- [x] JegalEun : [Java/String,StringBuilder, StringBuffer차이](https://github.com/im-d-team/Dev-Docs/blob/master/Java/String,StringBuilder,%20StringBuffer%EC%B0%A8%EC%9D%B4.md)\n- [x] Dae-Hwa : [CS/interface-segregation-principle](https://github.com/im-d-team/Dev-Docs/blob/master/CS/interface-segregation-principle.md)\n\n#### 08월 09일\n\n- [x] EUNJIHA : [Android/application fundamentals](https://github.com/im-d-team/Dev-Docs/blob/master/Android/application%20fundamentals.md)\n- [x] BKJang : [Browser/FOUC](https://github.com/im-d-team/Dev-Docs/blob/master/Browser/FOUC.md)\n- [x] SeonHyungJo : [Network/HTTP3](https://github.com/im-d-team/Dev-Docs/blob/master/Network/HTTP3.md)\n\n</details>\n\n<details>\n<summary> 2020년 7월 </summary>\n\n#### 07월 26일\n\n- [x] JegalEun : [Design_Pattern/MVC1, MVC2](https://github.com/im-d-team/Dev-Docs/blob/master/Design_Pattern/MVC1,%20MVC2.md)\n- [x] Dae-Hwa : [CS/liskov_substitution_principle](https://github.com/im-d-team/Dev-Docs/blob/master/CS/liskov_substitution_principle.md)\n- [x] SeonHyungJo : [Network/DHCP&DNS](https://github.com/im-d-team/Dev-Docs/blob/master/Network/DHCP&DNS.md)\n\n#### 07월 19일\n\n- [x] BKJang : [ECMAScript/ArrowFunction](https://github.com/im-d-team/Dev-Docs/blob/master/ECMAScript/ArrowFunction.md)\n- [x] SeonHyungJo : [Network/TCP & UDP](https://github.com/im-d-team/Dev-Docs/blob/master/Network/TCP%20&%20UDP.md)\n\n#### 07월 05일\n\n- [x] JegalEun : [Language/JSON_XML](https://github.com/im-d-team/Dev-Docs/blob/master/Language/JSON_XML.md)\n- [x] Dae-Hwa : [CS/grasp](https://github.com/im-d-team/Dev-Docs/blob/master/CS/grasp.md)\n- [x] SeonHyungJo : [Network/OSI7 Layer](https://github.com/im-d-team/Dev-Docs/blob/master/Network/OSI7%20Layer.md)\n\n</details>\n\n<details>\n<summary> 2020년 6월 </summary>\n\n#### 06월 21일\n\n- [x] BKJang : [Javascript/Closure](https://github.com/im-d-team/Dev-Docs/blob/master/Javascript/Closure.md)\n- [x] SeonHyungJo : [Network/TypesOfIP](https://github.com/im-d-team/Dev-Docs/blob/master/Network/TypesOfIP.md)\n\n#### 06월 14일\n\n- [x] JegalEun : [Network/SOAP API](https://github.com/im-d-team/Dev-Docs/blob/master/Network/SOAP%20API.md)\n- [x] Dae-Hwa : [CS/open-closed-principle](https://github.com/im-d-team/Dev-Docs/blob/master/CS/open-closed-principle.md)\n- [ ] ssy0619 : [OpenCV/filter](https://github.com/im-d-team/Dev-Docs/blob/master/OpenCV/filter.md)\n- [x] SeonHyungJo : [Network/Subnetmask](https://github.com/im-d-team/Dev-Docs/blob/master/Network/Subnetmask.md)\n\n#### 06월 07일\n\n- [x] BKJang : [Javascript/Scope](https://github.com/im-d-team/Dev-Docs/blob/master/Javascript/Scope.md)\n- [x] SeonHyungJo : [Network/IP](https://github.com/im-d-team/Dev-Docs/blob/master/Network/IP.md)\n\n</details>\n\n<details>\n<summary> 2020년 5월 </summary>\n\n#### 05월 31일\n\n- [x] Dae-Hwa : [CS/srp](https://github.com/im-d-team/Dev-Docs/blob/master/CS/srp.md)\n\n#### 05월 24일\n\n- [x] SeonHyungJo : [CSS/safe-area](https://github.com/im-d-team/Dev-Docs/blob/master/CSS/safe-area.md)\n\n#### 05월 17일\n\n- [x] Dae-Hwa : [Java/copy-object](https://github.com/im-d-team/Dev-Docs/blob/master/Java/copy-object.md)\n- [x] JegalEun : [Tool/Framework vs Library](https://github.com/im-d-team/Dev-Docs/blob/master/Tool/Framework%20vs%20Library.md)\n- [ ] ssy0619 : [Design_Pattern/Composite](https://github.com/im-d-team/Dev-Docs/blob/master/Design_Pattern/Composite.md)\n\n</details>\n\n\n<details>\n<summary> 2020년 4월 </summary>\n\n#### 04월 26일\n\n- [x] EUNJIHA : [Network/사용자 인증 방식(Cookie, Session & oAuth 2.0 & JWT)](https://github.com/Im-D/Dev-Docs/blob/master/Network/사용자%20인증%20방식(Cookie,%20Session%20&%20oAuth%202.0%20&%20JWT).md)\n- [x] SeonHyungJo : [CSS/CJK](https://github.com/Im-D/Dev-Docs/blob/master/CSS/CJK.md)\n- [x] BKJang : [Javascript/Variable](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/Variable.md)\n\n#### 04월 19일\n\n- [x] ssy0619 : [Design_Pattern/Singleton](https://github.com/Im-D/Dev-Docs/blob/master/Design_Pattern/Singleton.md)\n- [x] JegalEun : [Java/Mybatis](https://github.com/Im-D/Dev-Docs/blob/master/Java/Mybatis.md)\n- [x] Dae-Hwa : [CS/Call-By-Sharing](https://github.com/Im-D/Dev-Docs/blob/master/CS/Call-By-Sharing.md)\n\n#### 04월 12일\n\n- [x] SeonHyungJo : [HTML/WebM&WebP](https://github.com/Im-D/Dev-Docs/blob/master/HTML/WebM&WebP.md)\n- [x] EUNJIHA : [WPF/wpf](https://github.com/Im-D/Dev-Docs/blob/master/WPF/wpf.md)\n- [x] BKJang : [Javascript/Prototype_Chain](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/Prototype_Chain.md)\n\n#### 04월 05일\n\n- [x] Dae-Hwa : [Radix-sort](https://github.com/Im-D/Dev-Docs/blob/master/CS/Radix-sort.md)\n- [x] JegalEun : [Javascript/ajax(2)](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/ajax(2).md)\n- [x] ssy0619 : [OpenCV/이미지전처리](https://github.com/Im-D/Dev-Docs/blob/master/OpenCV/이미지전처리.md)\n\n</details>\n\n<details>\n<summary> 2020년 3월 </summary>\n\n#### 03월 28일\n\n- [x] SeonHyungJo : 나는 이 시국에 어떻게 마스크를 구매했나?\n- [x] EUNJIHA : [Network/REST API](https://github.com/Im-D/Dev-Docs/blob/master/Network/REST%20API.md)\n- [x] BKJang : [ECMAScript/ModulePattern_class](https://github.com/Im-D/Dev-Docs/blob/master/ECMAScript/ModulePattern_class.md)\n\n</details>\n\n<details>\n<summary> 2020년 2월 </summary>\n  \n#### 02월 23일\n- [x] JegalEun : 블록체인\n- [x] Dae-Hwa : [CS/Counting-sort](https://github.com/Im-D/Dev-Docs/blob/master/CS/Counting-sort.md)\n\n#### 02월 16일\n\n- [x] EUNJIHA : Web Summary\n- [x] SeonHyungJo : [CSS/WebToMobile](https://github.com/Im-D/Dev-Docs/blob/master/CSS/WebToMobile.md)\n- [x] BKJang : [Network/HTTP vs WebSocket](https://github.com/Im-D/Dev-Docs/blob/master/Network/HTTP%20vs%20WebSocket.md)\n\n#### 02월 09일\n\n- [x] SeonHyungJo : [Tool/Chrome_80_DevTool](https://github.com/Im-D/Dev-Docs/blob/master/Tool/Chrome_80_DevTool.md)\n- [x] Dae-Hwa: [SQL Injection](https://github.com/Im-D/Dev-Docs/blob/master/Security/SQL_Injection.md)\n\n</details>\n\n<details>\n<summary> 2019년 12월 </summary>\n\n#### 12월 01일\n\n- [x] BKJang : [점진적향상 우아한하향](https://github.com/Im-D/Dev-Docs/blob/master/Performance/점진적향상_우아한하향.md)\n- [x] SeonHyungJo : [requestAnimationFrame(rAF)](https://github.com/Im-D/Dev-Docs/blob/master/Performance/requestAnimationFram(rAF).md)\n- [x] Jinseong : [Web Worker](https://github.com/Im-D/Dev-Docs/blob/master/Browser/WebWorker.md)\n- [x] Dae-Hwa : [객체 생성 패턴 - 생성자 패턴](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/object_create_pattern-constructor.md)\n\n</details>\n\n<details>\n<summary> 2019년 11월 </summary>\n  \n#### 11월 10일\n\n- [x] BKJang : [Generator와 async-await](https://github.com/Im-D/Dev-Docs/blob/master/ECMAScript/Generator%EC%99%80%20async-await.md)\n- [x] SeonHyungJo : [CSS 애니메이션 vs JS 애니메이션](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/Animation.md)\n- [x] Jinseong : [CORS(Cross-Origin Resource Sharing)](https://github.com/Im-D/Dev-Docs/blob/master/Network/CORS.md)\n- [x] Dae-Hwa: [객체 생성 패턴](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/object_%EC%83%9D%EC%84%B1%ED%8C%A8%ED%84%B4.md)\n</details>\n\n<details>\n<summary> 2019년 10월 </summary>\n\n#### 10월 13일\n\n- [x] BKJang : [Iteration Protocol](https://github.com/Im-D/Dev-Docs/blob/master/ECMAScript/Iteration_Protocol.md)\n- [x] SeonHyungJo : [Worklet](https://github.com/Im-D/Dev-Docs/blob/master/Browser/Worklet.md)\n- [x] Jinseong : [JSend](https://github.com/Im-D/Dev-Docs/blob/master/Network/JSend.md)\n- [x] Dae-Hwa: [비선형 구조의 탐색](https://github.com/Im-D/Dev-Docs/blob/master/CS/non-linear-search.md)\n\n</details>\n<details>\n<summary> 2019년 09월 </summary>\n\n#### 09월 29일\n\n- [x] BKJang : [Observer](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/Observer.md)\n- [x] SeonHyungJo : [기본적인 렌더링 최적화 방법](https://github.com/Im-D/Dev-Docs/blob/master/Performance/%EA%B8%B0%EB%B3%B8%EC%A0%81%EC%9D%B8%20%EB%A0%8C%EB%8D%94%EB%A7%81%20%EC%B5%9C%EC%A0%81%ED%99%94%20%EB%B0%A9%EB%B2%95.md)\n- [x] Jinseong : [Virtual DOM](https://github.com/Im-D/Dev-Docs/blob/master/React/Virtual%20DOM.md)\n- [x] Dae-Hwa : [그래프](https://github.com/Im-D/Dev-Docs/blob/master/CS/Graph.md)\n\n#### 09월 01일\n\n- [x] BKJang : [Event Loop](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/%EC%9D%B4%EB%B2%A4%ED%8A%B8%20%EB%A3%A8%ED%94%84(Event%20Loop).md)\n- [x] SeonHyungJo : [Reflow Repaint](https://github.com/Im-D/Dev-Docs/blob/master/Performance/Reflow%20Repaint.md)\n- [x] Jinseong : [Reactive](https://github.com/Im-D/Dev-Docs/blob/master/Language/Reactive.md)\n- [x] Dae-Hwa: [protoType](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/prototype.md)\n- [x] JHRla: [MSA](https://github.com/Im-D/Dev-Docs/blob/master/Design_Pattern/MSA.md)\n\n</details>\n<details>\n<summary> 2019년 08월 </summary>\n\n#### 08월 18일\n\n- [x] BKJang : [고차함수(High Order Function)](<https://github.com/Im-D/Dev-Docs/blob/master/Language/%EA%B3%A0%EC%B0%A8%ED%95%A8%EC%88%98(High%20Order%20Function).md>), [Currying](https://github.com/Im-D/Dev-Docs/blob/master/Language/Currying.md)\n- [x] SeonHyungJo : [Javascript BuildTool](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/Build%20Tool.md)\n- [x] Jinseong : [Event Delegation](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/Event%20Delegation.md)\n- [x] Dae-Hwa: [객체](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/object.md)\n- [x] JHRla: [Rest](https://github.com/Im-D/Dev-Docs/blob/master/Network/REST.md)\n\n#### 08월 04일\n\n- [x] BKJang : [함수형 프로그래밍](https://github.com/Im-D/Dev-Docs/blob/master/Language/%ED%95%A8%EC%88%98%ED%98%95%20%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D.md)\n- [x] SeonHyungJo : [Module](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/Module.md)\n- [x] Jinseong : [웹 브라우저의 작동 원리](https://github.com/Im-D/Dev-Docs/blob/master/Browser/%EC%9B%B9%20%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80%EC%9D%98%20%EC%9E%91%EB%8F%99%20%EC%9B%90%EB%A6%AC.md)\n- [x] Dae-Hwa: [bind메소드](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/bind.md)\n- [x] JHRla: [comet](https://github.com/Im-D/Dev-Docs/blob/master/Network/comet.md)\n\n</details>\n\n<details>\n<summary> 2019년 07월 </summary>\n\n#### 07월 21일\n\n- [x] BKJang : [Cookie와 Session 그리고 Redis](https://github.com/Im-D/Dev-Docs/blob/master/Network/Cookie%EC%99%80%20Session%20%EA%B7%B8%EB%A6%AC%EA%B3%A0%20Redis.md)\n- [x] SeonHyungJo : [CSS - animation](https://github.com/Im-D/Dev-Docs/blob/master/CSS/animation.md)\n- [x] Jinseong : [http-caching](https://github.com/Im-D/Dev-Docs/blob/master/Network/http-caching.md)\n- [x] Dae-Hwa: [HTML Templating](https://github.com/Im-D/Dev-Docs/blob/master/HTML/HTML-Templating.md)\n- [x] JHRla: [페이징 세그먼테이션](https://github.com/Im-D/Dev-Docs/blob/master/CS/%ED%8E%98%EC%9D%B4%EC%A7%95%EA%B3%BC%20%EC%84%B8%EA%B7%B8%EB%A8%BC%ED%85%8C%EC%9D%B4%EC%85%98.md)\n\n#### 07월 14일\n\n- [x] BKJang : [배열 내장함수](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/배열%20내장함수.md)\n- [x] SeonHyungJo : [preload, prefetch](https://github.com/Im-D/Dev-Docs/blob/master/HTML/preload%26prefetch.md)\n- [x] Dae-Hwa: [WAS](https://github.com/Im-D/Dev-Docs/blob/master/Java/WAS.md)\n- [x] JHRla: [클로저](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/%ED%81%B4%EB%A1%9C%EC%A0%80.md)\n\n#### 07월 07일\n\n- [x] BKJang : [Typescript ( 제네릭 )](<https://github.com/Im-D/Dev-Docs/blob/master/Typescript/제네릭(Generic).md>)\n- [x] SeonHyungJo : [window.history](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/window.history.md)\n- [x] Jinseong : [ES6 Module in Browser](https://github.com/Im-D/Dev-Docs/blob/master/ECMAScript/ES6-module-in-Browser.md)\n- [x] Dae-Hwa: [Non-blocking](https://github.com/Im-D/Dev-Docs/blob/master/CS/non-blocking.md)\n\n</details>\n\n<details>\n<summary> 2019년 06월 </summary>\n\n#### 06월 30일\n\n- 🎇 **[2019 Google I/O Extended 컨퍼런스 참여](https://github.com/Im-D/Dev-Docs/issues/47)** 🎇\n\n#### 06월 23일\n\n- [x] BKJang : [Typescript ( 인터페이스 )](<https://github.com/Im-D/Dev-Docs/blob/master/Typescript/인터페이스(Interface).md>)\n- [x] SeonHyungJo : [Object.create & Object.assign](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/Object.create%26Object.assign.md)\n- [x] Jinseong : [Time in js](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/TimeInJS.md)\n- [x] Dae-Hwa: [node.js의 특징](https://github.com/Im-D/Dev-Docs/blob/master/Node.js/nodejs의_특징.md)\n- [x] JHRla: [Dependency Injection](<https://github.com/Im-D/Dev-Docs/blob/master/Java/Dependency%20Injection(DI).md>)\n\n#### 06월 16일\n\n- [x] BKJang : [클래스(class) (Typescript)](<https://github.com/Im-D/Dev-Docs/blob/master/Typescript/%ED%81%B4%EB%9E%98%EC%8A%A4(class).md>)\n- [x] SeonHyungJo : [정규 표현식](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/Regular_Expressions.md)\n- [x] Jinseong : [BrowserXY](https://github.com/Im-D/Dev-Docs/blob/master/Browser/BrowserXY.md)\n- [x] Dae-Hwa: [GET&POST](https://github.com/Im-D/Dev-Docs/blob/master/Network/get%26post.md)\n- [x] JHRla: [DOM API](https://github.com/Im-D/Dev-Docs/blob/master/HTML/DOM%20API.md)\n\n#### 06월 09일\n\n- [x] BKJang : [정적 타이핑(TypeScript)](https://github.com/Im-D/Dev-Docs/blob/master/Typescript/%EC%A0%95%EC%A0%81%20%ED%83%80%EC%9D%B4%ED%95%91.md)\n- [x] SeonHyungJo : [IndexDB, WebSQL]()\n- [ ] Jinseong : []()\n- [x] Dae-Hwa: [바인딩(Binding)]()\n- [x] JHRla: [CORS](<https://github.com/Im-D/Dev-Docs/blob/master/Security/CORS(Cross-Origin%20Resource%20Sharing).md>)\n\n#### 06월 02일\n\n- [x] BKJang : [Web Component](<https://github.com/Im-D/Dev-Docs/blob/master/HTML/%EC%9B%B9%20%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8(Web%20Component).md>)\n- [x] SeonHyungJo : [Basic_Javascript this, call, apply, bind](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/B_Call_Apply_Bind.md)\n- [x] Jinseong : [Composite_Layers](https://github.com/Im-D/Dev-Docs/blob/master/Browser/Layer_Model.md)\n- [x] Dae-Hwa: [Ajax](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/Ajax.md)\n- [x] JHRla: [Set](https://github.com/Im-D/Dev-Docs/blob/master/Java/Set.md)\n\n</details>\n\n<details>\n<summary> 2019년 05월 </summary>\n\n#### 05월 26일\n\n- [x] BKJang : [DocumentFragment](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/DocumentFragment.md)\n- [x] SeonHyungJo : [Basic_Javascript 팩토리와 클래스](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/B_Class.md)\n- [x] Jinseong : [압축](https://github.com/Im-D/Dev-Docs/blob/master/CS/compression.md)\n- [x] Dae-Hwa: [자바스크립트의 동작 원리 - 변수 객체(Variable Object)](<https://github.com/Im-D/Dev-Docs/blob/master/Javascript/Javascript%EC%9D%98_%EB%8F%99%EC%9E%91%EC%9B%90%EB%A6%AC-%EB%B3%80%EC%88%98%EA%B0%9D%EC%B2%B4(VariableObject).md>)\n- [x] JHRla: [Upcasting과 Downcasting](https://github.com/Im-D/Dev-Docs/blob/master/Java/Upcasting%EA%B3%BC%20Downcasting.md)\n\n#### 05월 19일\n\n- [x] BKJang : [React의 props와 state](https://github.com/Im-D/Dev-Docs/blob/master/React/props와%20state.md)\n- [x] SeonHyungJo : [Basic_Javascript DOM](https://github.com/Im-D/Dev-Docs/blob/master/HTML/DOM.md)\n- [x] Jinseong : [정보이론](https://github.com/Im-D/Dev-Docs/blob/master/CS/information_theory.md)\n- [x] Dae-Hwa: [자바스크립트의 동작 원리 - 실행 컨텍스트(Execution Contexts)](<https://github.com/Im-D/Dev-Docs/blob/master/Javascript/Javascript%EC%9D%98_%EB%8F%99%EC%9E%91%EC%9B%90%EB%A6%AC-%EC%8B%A4%ED%96%89%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8(Execution%20Contexts).md>)\n- [x] JHRla: [JSP와 Servlet처리](https://github.com/Im-D/Dev-Docs/blob/master/Java/JSP%EC%99%80%20Servlet%EC%B2%98%EB%A6%AC.md)\n\n#### 05월 12일\n\n- [x] BKJang : [React의 Composition](https://github.com/Im-D/Dev-Docs/blob/master/React/Composition.md)\n- [x] SeonHyungJo : [ARIA attribute](https://github.com/Im-D/Dev-Docs/blob/master/HTML/ARIA.md)\n- [ ] Jinseong : []()\n- [x] Dae-Hwa: [input태그의\\_value바꾸기(input태그의\\_dirty flag)](<https://github.com/Im-D/Dev-Docs/blob/master/HTML/input%ED%83%9C%EA%B7%B8%EC%9D%98_value%EB%B0%94%EA%BE%B8%EA%B8%B0(input%ED%83%9C%EA%B7%B8%EC%9D%98_dirty%20flag).md>)\n- [x] JHRla: [함수 선언](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/%ED%95%A8%EC%88%98%20%EC%84%A0%EC%96%B8.md)\n\n#### 05월 05일\n\n- [ ] BKJang : []()\n- [x] SeonHyungJo : [Basic_Javascript Engine](https://github.com/SeonHyungJo/FrontEnd-Dev/blob/master/Javascript/Basic_7_Engine.md), [Basic_Bitwise Operator](https://github.com/SeonHyungJo/FrontEnd-Dev/blob/master/Javascript/Basic_8_Bitwise_Operator.md)\n- [x] Jinseong : [자바스크립트 코딩 꿀팁](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/tricks_of_js.md)\n\n</details>\n\n<details>\n<summary> 2019년 04월 </summary>\n\n#### 04월 28일\n\n- [x] BKJang : [Element와 Component](https://github.com/Im-D/Dev-Docs/blob/master/React/Element%EC%99%80%20Component.md)\n- [x] SeonHyungJo : ~[Basic\\_메시지 큐와 이벤트 루프](https://github.com/Im-D/Dev-Docs/blob/master/Deprecated/B_EventLoop.md)~\n- [x] Jinseong : [this 더알아보기](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/Learning_more_about_this.md)\n\n#### 04월 21일\n\n- [x] BKJang : [클래스(class)](<https://github.com/Im-D/Dev-Docs/blob/master/Javascript/%ED%81%B4%EB%9E%98%EC%8A%A4(class).md>)\n- [x] SeonHyungJo : [Basic_Async](https://github.com/Im-D/Dev-Docs/tree/master/Javascript/B_Async.md)\n- [x] Jinseong : [Scope와 This](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/scope_this.md)\n\n#### 04월 14일\n\n- [x] BKJang : [DeadLock(교착상태)](<https://github.com/Im-D/Dev-Docs/blob/master/Performance/DeadLock(%EA%B5%90%EC%B0%A9%EC%83%81%ED%83%9C).md>)\n- [x] SeonHyungJo : ~[Basic_Module](https://github.com/Im-D/Dev-Docs/tree/master/Deprecated/B_Module.md)~\n- [x] Jinseong : [Memory](https://github.com/Im-D/Dev-Docs/blob/master/CS/Memory.md)\n\n#### 04월 07일\n\n- [x] BKJang : [ArrayList vs LinkedList 그리고 Vector](https://github.com/Im-D/Dev-Docs/blob/master/Java/ArrayList%20vs%20LinkedList%20%EA%B7%B8%EB%A6%AC%EA%B3%A0%20Vector.md)\n- [x] SeonHyungJo : [Basic_Function](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/B_Function.md)\n- [x] Jinseong : [.git으로 이해하는 GIT](https://github.com/Im-D/Dev-Docs/blob/master/Git/gitBy_.git.md)\n\n</details>\n\n<details>\n<summary> 2019년 03월 </summary>\n\n#### 03월 31일\n\n- [x] BKJang [Comparable vs Comparator](https://github.com/Im-D/Dev-Docs/blob/master/Java/Comparable%20vs%20Comparator.md)\n- [x] SeonHyungJo [Basic_Type](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/B_Type.md)\n- [x] Jinseong : [람다](https://github.com/Im-D/Dev-Docs/blob/master/Language/Lamda.md)\n\n#### 03월 24일\n\n- [x] BKJang : [String, StringBuilder, StringBuffer](https://github.com/Im-D/Dev-Docs/blob/master/Java/String%2C%20StringBuilder%2C%20StringBuffer.md)\n- [x] SeonHyungJo : [호출 스택](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/B_CallStack.md)\n- [x] Jinseong : ~[Higher Order Functions](https://github.com/Im-D/Dev-Docs/blob/master/Deprecated/Higher_Order_Functions.md)~\n\n#### 03월 17일\n\n- [x] BKJang : [로드밸런싱 & 클러스터링](https://github.com/Im-D/Dev-Docs/blob/master/Network/%EB%A1%9C%EB%93%9C%EB%B0%B8%EB%9F%B0%EC%8B%B1%20%26%20%ED%81%B4%EB%9F%AC%EC%8A%A4%ED%84%B0%EB%A7%81.md)\n- [x] SeonHyungJo : [최신 브라우저의 내부 살펴보기](https://github.com/Im-D/Dev-Docs/blob/master/Browser/최신_브라우저의_내부_살펴보기.md)\n- [x] Jinseong : [Some과 Every](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/Some_Every.md)\n\n#### 03월 10일\n\n- [x] BKJang : [Java Garbage Collection](<https://github.com/Im-D/Dev-Docs/blob/master/Java/Java%20Garbage%20Collection(GC).md>)\n- [x] SeonHyungJo : [JavaScript 2019 new feature](https://github.com/Im-D/Dev-Docs/blob/master/ECMAScript/ECMA2019.md)\n- [x] Jinseong : [Sync & Async, Multi & Single Thread](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/Sync%26Async_Multi%26Single_Thread.md)\n\n#### 03월 03일\n\n- [x] BKJang : [Java Virtual Machine(JVM)](<https://github.com/Im-D/Dev-Docs/blob/master/Java/JVM(Java%20Virtual%20Machine).md>)\n- [x] SeonHyungJo : [React.memo()](https://github.com/Im-D/Dev-Docs/blob/master/React/React.memo.md)\n- [x] Jinseong : [Optional Chaining](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/Optional_Chaining.md)\n\n</details>\n\n<details>\n<summary> 2019년 02월 </summary>\n\n#### 02월 24일\n\n- [x] BKJang : [throttling과 rAF](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/throttling%EA%B3%BC%20rAF.md)\n- [x] SeonHyungJo : [Vue의 LifeCycle](https://github.com/Im-D/Dev-Docs/blob/master/Vue/Vue_LifeCycle.md)\n- [x] Jinseong : [Includes_IndexOf](https://github.com/Im-D/Dev-Docs/blob/master/ECMAScript/Includes_IndexOf.md)\n\n#### 02월 17일\n\n- [x] BKJang : [React의 LifeCycle](https://github.com/Im-D/Dev-Docs/blob/master/React/React%EC%9D%98%20Lifecycle%20Event.md)\n- [x] SeonHyungJo : [React Hooks 간단하게 살펴보기](https://github.com/SeonHyungJo/react-hook-sample)\n- [x] Jinseong : [Number_isNaN](https://github.com/Im-D/Dev-Docs/blob/master/ECMAScript/Number_isNaN.md)\n\n#### 02월 10일\n\n- [x] BKJang : [HTTP2.0의 필요성](https://github.com/Im-D/Dev-Docs/blob/master/Performance/HTTP2.0%EC%9D%98%20%ED%95%84%EC%9A%94%EC%84%B1.md)\n- [x] SeonHyungJo : [JavaScript Engine](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/Javascript_Engine.md)\n- [x] Jinseong : [Tagged Template Literals](https://github.com/Im-D/Dev-Docs/blob/master/ECMAScript/Tagged_Template_Literals.md)\n\n#### 02월 03일\n\n- [x] BKJang [JavaScript의 this](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/JavaScript%EC%9D%98%20this.md)\n- [x] SeonHyungJo [Proxy Object](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/Proxy.md)\n- [ ] Jinseong []()\n\n</details>\n\n<details>\n<summary> 2019년 01월 </summary>\n\n#### 01월 20일\n\n- [x] BKJang [underscore와 lodash 그리고 Native](https://github.com/Im-D/Dev-Docs/blob/a37e231e79263c8759bc2eeb9fc1135193e242cb/Javascript/underscore%EC%99%80%20lodash%EA%B7%B8%EB%A6%AC%EA%B3%A0%20Native.md)\n- [x] SeonHyungJo [FEConf2017 RxJS](https://github.com/Im-D/Dev-Docs/blob/master/Design_Pattern/RxJS.md)\n- [x] Jinseong [리만가설과 소수정리 RSA](https://github.com/Im-D/Dev-Docs/blob/6612f07ff60d4c3c072321d2b153674a3cf2c667/Security/%EB%A6%AC%EB%A7%8C%EA%B0%80%EC%84%A4%EA%B3%BC%20%EC%86%8C%EC%88%98%EC%A0%95%EB%A6%AC.md)\n\n#### 01월 13일\n\n- [x] BKJang [HTTPS(SSL)](https://github.com/Im-D/Dev-Docs/blob/master/Security/HTTPS%EC%99%80%20SSL.md)\n- [x] SeonHyungJo [Control CSSOM](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/Control_CSSOM.md)\n- [x] Jinseong [HTTP2.0과 Web Socket](https://github.com/Im-D/Dev-Docs/blob/master/Browser/HTTP2_Websocket.md)\n\n</details>\n\n<details>\n<summary> 2018년 12월 </summary>\n\n#### 12월 27일\n\n- [x] BKJang [Redux State Normalization](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/Redux%20State%20%EC%A0%95%EA%B7%9C%ED%99%94.md)\n- [x] SeonHyungJo [JS 메모리관리 살펴보기](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/Javascript_%EB%A9%94%EB%AA%A8%EB%A6%AC%EA%B4%80%EB%A6%AC.md)\n- [x] Jinseong [insertAdjacentHTML](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/InsertAdjacentHTML.md), [디스트럭처링](https://github.com/Im-D/Dev-Docs/blob/master/ECMAScript/Destructuring_Assignment.md)\n\n#### 12월 16일\n\n- [x] BKJang [SSR](<https://github.com/Im-D/Dev-Docs/blob/master/Performance/%EC%84%9C%EB%B2%84%20%EC%82%AC%EC%9D%B4%EB%93%9C%20%EB%A0%8C%EB%8D%94%EB%A7%81(SSR).md>)\n- [x] SeonHyungJo ~[Web Worker](https://github.com/Im-D/Dev-Docs/blob/master/Deprecated/WebWorker.md)~\n- [ ] Jinseong []()\n\n#### 12월 1일\n\n- [x] BKJang [상태 관리 라이브러리](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/%EC%83%81%ED%83%9C%EA%B4%80%EB%A6%AC%20%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC.md)\n- [x] SeonHyungJo [MV\\* pattern](https://github.com/Im-D/Dev-Docs/blob/master/Design_Pattern/MVC_MVP_MVVM.md)\n- [x] Jinseong [Reduce](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/Reduce.md)\n\n</details>\n\n<details>\n<summary> 2018년 11월 </summary>\n\n#### 11월 18일\n\n- [x] BKJang ~[AMD와 CommonJS](https://github.com/Im-D/Dev-Docs/blob/master/Deprecated/AMD%EC%99%80%20CommonJS.md)~\n- [x] SeonHyungJo [HTML Meta](https://github.com/Im-D/Dev-Docs/blob/master/HTML/Head_Meta.md)\n- [x] Jinseong [Spread Operator](https://github.com/Im-D/Dev-Docs/blob/master/ECMAScript/Spread_Operator.md)\n\n#### 11월 11일\n\n- [x] BKJang [객체지향프로그래밍(OOP)](<https://github.com/Im-D/Dev-Docs/blob/master/Language/%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5%20%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D(OOP).md>)\n- [x] SeonHyungJo [표준모드와 쿼크모드(Doctype), 메모이제이션 패턴, Bundler History](https://github.com/Im-D/Dev-Docs/blob/master/HTML/Standard%26QuirksMode.md)\n- [ ] Jinseong []()\n\n</details>\n\n<details>\n<summary> 2018년 10월 </summary>\n\n#### 10월 28일\n\n- [x] BKJang [XSS와 CSRF](https://github.com/Im-D/Dev-Docs/blob/master/Security/XSS%EC%99%80%20CSRF.md), ~[JSONP(JSON Padding)와 CORS(Cross-Origin Resource Sharing)](<https://github.com/Im-D/Dev-Docs/blob/master/Deprecated/CORS(Cross-Origin%20Resource%20Sharing).md>)~\n- [x] SeonHyungJo [점진적향상 우아한 하향](https://github.com/Im-D/Dev-Docs/blob/master/Performance/%EC%A0%90%EC%A7%84%EC%A0%81%ED%96%A5%EC%83%81_%EC%9A%B0%EC%95%84%ED%95%9C%ED%95%98%ED%96%A5.md)\n- [x] Jinseong [쓰로틀링과 디바운싱](https://github.com/Im-D/Dev-Docs/blob/master/Design_Pattern/Throttle%20and%20Debounce.md), [프로미스 패턴](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/PromisePattern.md)\n\n#### 10월 14일\n\n- [x] BKJang ~[렌더링 최적화 기법](https://github.com/Im-D/Dev-Docs/blob/master/Deprecated/%EA%B8%B0%EB%B3%B8%EC%A0%81%EC%9D%B8%20%EB%A0%8C%EB%8D%94%EB%A7%81%20%EC%B5%9C%EC%A0%81%ED%99%94%20%EB%B0%A9%EB%B2%95.md)~, ~[JS 애니메이션 vs CSS 애니메이션](https://github.com/Im-D/Dev-Docs/blob/master/Performance/CSS%20%EC%95%A0%EB%8B%88%EB%A9%94%EC%9D%B4%EC%85%98%20vs%20JS%20%EC%95%A0%EB%8B%88%EB%A9%94%EC%9D%B4%EC%85%98.md)~\n- [x] SeonHyungJo ~[Async-await 구현](https://github.com/Im-D/Dev-Docs/blob/master/Deprecated/Async-Await.md)~, ~[setState](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/setState.md)~\n- [x] Jinseong ~[Callback Hell](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/B_Callback.md)~, ~[Promise1](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/Promise1.md)~, ~[Promise2](https://github.com/Im-D/Dev-Docs/blob/master/Javascript/Promise2.md)~\n\n</details>\n\n<details>\n<summary> 2018년 9월 </summary>\n\n#### 9월 30일\n\n- [x] BKJang ~[Event Delegation](<https://github.com/Im-D/Dev-Docs/blob/master/Deprecated/%EC%9D%B4%EB%B2%A4%ED%8A%B8%20%EC%9C%84%EC%9E%84(Event%20Delegation).md>)~, ~[Repaint & Reflow and SPA](https://github.com/Im-D/Dev-Docs/blob/master/Deprecated/Repaint%EC%99%80%20Reflow.md)~\n- [x] SeonHyungJo ~[Reactive Programmming](https://github.com/Im-D/Dev-Docs/blob/master/Deprecated/Reactive.md)~, ~[Call By xxx](https://github.com/Im-D/Dev-Docs/blob/master/Deprecated/CallByReference.md)~\n- [x] Jinseong ~[Javascript Build Tools](https://github.com/Im-D/Dev-Docs/blob/master/Deprecated/Javascript_BuildTool.md)~, ~[EventLoop_Advanced](https://github.com/Im-D/Dev-Docs/blob/master/Deprecated/EventLoop_Advanced.md)~\n\n#### 9월 16일\n\n- [x] BKJang ~[브라우저 Redering 과정](https://github.com/Im-D/Dev-Docs/blob/master/Deprecated/%EC%9B%B9%20%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80%EC%9D%98%20%EC%9E%91%EB%8F%99%20%EC%9B%90%EB%A6%AC.md)~\n- [x] SeonHyungJo ~[Functional](https://github.com/Im-D/Dev-Docs/blob/master/Deprecated/Funtional.md)~,\n- [x] Jinseong [렉시컬 속이기 - eval()](<https://github.com/Im-D/Dev-Docs/blob/master/Javascript/%EB%A0%89%EC%8B%9C%EC%BB%AC_%EC%86%8D%EC%9D%B4%EA%B8%B0(eval).md>), ~[JS-Module](https://github.com/Im-D/Dev-Docs/blob/master/Deprecated/Module.md)~\n\n</details>\n\n<br/>\n\n**[⬆ Top](#Dev-Docs)**\n"
  },
  {
    "path": "React/Component, Props, State.md",
    "content": "# Component, Props, State\n\nReact는 `Component`개념에 집중되어 있는 라이브러리다. `Component`는 JavaScript의 함수와 유사하다고 할 수 있는데, `Props`라는 데이터를 입력 받고 화면에 표시될 React `Element`를 반환한다. 한마디로 **재사용 가능한 UI 조각**이라고 생각하면 된다.\n\n> `Element` 는 React App의 가장 작은 단위이다. 화면에 표시할 내용을 기술한다. `Element`는 브라우저 DOM Element와 달리 일반 객체(plain object)이다.\n\n1) 브라우저 DOM 태그로 나타낸 React Element: `firstElement`\n\n```jsx\nconst firstElement= <h1>Hello, world</h1>;\n\n// ReactDOM.render 함수를 통해 Element를 DOM에 붙일 수 있다.\nReactDOM.render(firstElement, document.getElementById('root'));\n```\n\n2) 사용자 정의 `Component` (`Welcome`)로 나타낸 React Element: `secondElement`\n\ncf. React Component 이름은 다음 `Welcome`과 같이 항상 **대문자**로 시작한다.\n\n```jsx\nfunction Welcome(props) {\n  return <h1>Hello, {props.name}</h1>;\n}\n\n// React는 {name: 'Sara'}를 props로 하여 Welcome를 호출한다.\nconst secondElement = <Welcome name=\"Sara\"/>; // 어떤 것이든 넘어가긴 함\n\nReactDOM.render(\n  secondElement,\n  document.getElementById('root')\n);\n```\n\n# 1. Component\n\n## 1) Component 종류\n\nReact Component 에는 `Function Component`와 `Class Component`가 있다. 이 Component들의 가장 큰 차이점은 `LifeCycle`과 `State`이다. (추후에 다룰 예정)\n\n### (1) JavaScript 함수로 작성: `Function Component`\n\n```jsx\nfunction Welcome(props) {\n\n  // function 컴포넌트는 state를 useState를 통해 관리할 수 있다.\n  // const [content, setConent] = React.useState(\"\");\n  \n  return <h1>Hello, {props.name}</h1>;\n}\n```\n\nprops(객체 형태)를 받고 React Element를 return 해주고 있다.\n\n### (2) ES6 Class로 작성: `Class Component`\n\n```jsx\nclass Welcome extends React.Component {\n\n  // class 컴포넌트는 props, state를 다음과 같은 형태로 관리할 수 있다.\n  // constructor(props) {\n  //   super(props);\n  //   this.state = {content: \"\"};\n  // }\n\n  render() {\n    return <h1>Hello, {this.props.name}</h1>;\n  }\n}\n```\n\n`Function Component`와 달리 render() 메소드 내에서 return 해야 한다.\n\n## 2) Component 합성과 추출\n\n### (1) Component 합성\n\n`App` Component에 `Welcome` Component 여러 개가 합성되어 있다. 이처럼 자신의 컴포넌트에 다른 컴포넌트들을 참조할 수 있다.\n\n```jsx\nfunction Welcome(props) {\n  return <h1>Hello, {props.name}</h1>;\n}\n\nfunction App() {\n  return (\n    <div>\n      <Welcome name=\"Sara\" />\n      <Welcome name=\"Cahal\" />\n      <Welcome name=\"Edite\" />\n    </div>\n  );\n}\n\nReactDOM.render(\n  <App />,\n  document.getElementById('root')\n);\n```\n\n![2-1](https://user-images.githubusercontent.com/43839938/99895454-a9948c00-2ccb-11eb-8935-54533513d421.png)\n\n\n### (2) Component 추출\n\n추출을 사용하면 컴포넌트를 재사용할 일이 많은 App 에서는 유지 보수가 더 수월해진다. 1) UI 일부가 여러 번 사용되거나(Button, Panel, Avatar) 2) UI 일부가 자체적으로 복잡한 경우에는(App, FeedStory, Comment) 별도의 컴포넌트로 만드는 게 좋다. \n\n다음 `Comment` Component에는 유저사진 / 유저이름 / 내용 / 날짜가 브라우저 DOM 태그 형태 그대로 포함되어 있다. \n\n```jsx\nfunction Comment(props) {\n  return (\n    <div className=\"Comment\">\n      <div className=\"UserInfo\">\n        <img className=\"Avatar\"\n          src={props.author.avatarUrl}\n          alt={props.author.name}\n        />\n        <div className=\"UserInfo-name\">\n          {props.author.name}\n        </div>\n      </div>\n      <div className=\"Comment-text\">\n        {props.text}\n      </div>\n      <div className=\"Comment-date\">\n        {formatDate(props.date)}\n      </div>\n    </div>\n  );\n}\n```\n\n위를 다음처럼 UserInfo로 분리해서 간결하게 표현할 수 있다.\n\n```jsx\nfunction Comment(props) {\n  return (\n    <div className=\"Comment\">\n      <UserInfo user={props.author} />\n      <div className=\"Comment-text\">\n        {props.text}\n      </div>\n      <div className=\"Comment-date\">\n        {formatDate(props.date)}\n      </div>\n    </div>\n  );\n}\n```\n\n전체 코드는 다음과 같다.\n\n```jsx\nfunction formatDate(date) {\n  return date.toLocaleDateString();\n}\n\nfunction Avatar(props) {\n  return (\n    <img\n      className=\"Avatar\"\n      src={props.user.avatarUrl}\n      alt={props.user.name}\n    />\n  );\n}\n\nfunction UserInfo(props) {\n  return (\n    <div className=\"UserInfo\">\n      <Avatar user={props.user} />\n      <div className=\"UserInfo-name\">{props.user.name}</div>\n    </div>\n  );\n}\n\nfunction Comment(props) {\n\tconst {author, } = props\n\n  return (\n    <div className=\"Comment\">\n      <UserInfo user={props.author} />\n      <div className=\"Comment-text\">{props.text}</div>\n      <div className=\"Comment-date\">\n        {formatDate(props.date)}\n      </div>\n    </div>\n  );\n}\n\nconst comment = {\n  date: new Date(),\n  text: 'I hope you enjoy learning React!',\n  author: {\n    name: 'Hello Kitty',\n    avatarUrl: 'https://placekitten.com/g/64/64',\n  },\n};\nReactDOM.render(\n  <Comment\n    date={comment.date}\n    text={comment.text}\n    author={comment.author}\n  />,\n  document.getElementById('root')\n);\n```\n\n![2-2](https://user-images.githubusercontent.com/43839938/99895455-ab5e4f80-2ccb-11eb-8aa9-76acf3dee035.png)\n\n\n# 2. Props 와 State (속성과 상태)\n\n`Props`와 `State`는 React Component가 다루는 데이터이다. 간단하게 말하자면 `Props`는 부모 `Component`가 자식 `Component`에게 주는 변경할 수 없는 값이고 `State`는 `Component`내부에서 선언하며(비공개) `Component`에 의해 완전히 제어된다.\n\n## 1) Props\n\n### (1) Props는 변경 불가\n\n모든 React 컴포넌트는 자신의 `Props`를 다룰 때 반드시 `순수함수` 처럼 동작해야 한다.\n\n> `순수함수` 란 입력 값을 바꾸지 않는 함수이다. 동일한 입력값에 대해서 항상 동일한 결과를 반환한다.\n\n```jsx\n// 순수함수 O\nfunction sum(a, b) {\n  return a + b;\n}\n\n// 순수함수 X: 입력값 account를 변경하고 있다.\nfunction withdraw(account, amount) {\n  account.total -= amount;\n\treturn { ...account, total: account.total - amount }\n}\n\n// 매개변수, return 있고 매개변수를 직접 바꾸지 않는다.\n// 이러면 새로운 객체가 리턴 된다. \nconst obj = withdraw(account, amount);\n\n```\n\n### (2) defaultProps\n\nprops에 값이 없을 때를 대비하기 위해 defaultProps를 설정할 수 있다.\n\n```jsx\nimport React, { Component } from 'react';\n\nclass MyName extends Component {\n  render() {\n    return (\n      <div>\n        안녕하세요! 제 이름은 <b>{this.props.name}</b> 입니다.\n      </div>\n    );\n  }\n}\n\nfunction MyName(props) {\n  const { name = '기본이름' } = props; // default parameter\n\n  return (\n  );\n}\n\nMyName.defaultProps = {\n  name: '기본이름'\n};\n\nexport default MyName;\n```\n\n`<MyName name = \"은지\">` 대신 `<MyName />` 과 같이 사용하면 위의 defaultProps인 '기본이름'을 name 으로 인식하게 된다.\n\n## 2) State\n\nReact 컴포넌트는 state를 통해 위 규칙을 위반하지 않고 사용자 액션, 네트워크 응답 및 다른 요소에 대한 응답으로 시간에 따라 자신의 출력값을 변경할 수 있다.\n\n매 초마다 시간이 업데이트 되는 화면을 만들어보자.\n\n```jsx\nclass Clock extends React.Component {\n  // (2) <Clock />의 constructor가 호출된다. state도 초기화한다.\n  constructor(props) { \n    super(props);\n    this.state = {date: new Date()};\n  }\n\n  // (4) (3)이 처음 실행된 직후 componentDidMount() 생명주기 메서드가 실행된다. \n  componentDidMount() {\n    this.timerID = setInterval(\n      () => this.tick(),\n      1000\n    );\n  }\n\t\n\n  // (6) <Clock />이 DOM에서 삭제되었다면 componentWillUnmount() 생명주기 메서드가 실행된다.\n  componentWillUnmount() {\n    clearInterval(this.timerID);\n  }\n\n  // (5) setState() 메서드가 있으므로 새로운 state로 render() 메소드를 다시 호출한다. (this.state ~ 로 직접 수정하는게 아니다!)\n  tick() {\n    this.setState({\n      date: new Date()\n    });\n  }\n\n  // (3) <Clock />의 render() 메서드를 호출한다. 화면에 표시할 내용이다. (2)에서 초기화된 state를 기반으로 화면에 Mount한다.\n  render() {\n    return (\n      <div>\n        <h1>Hello, world!</h1>\n        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>\n      </div>\n    );\n  }\n}\n\n// (1) <Clock /> Component가 있음을 인지한다.\nReactDOM.render(\n  <Clock />,\n  document.getElementById('root')\n);\n```\n\n### (1) State를 직접 수정하면 안된다.\n\n직접 수정할 수 없는 것은 Props와 마찬가지이다. (다만 state는 다른 방식으로 값을 수정할 수 있다.)\n\n```jsx\n// Wrong: render() 함수를 부르지 않는다.\nthis.state.comment = 'Hello';\n\n// Correct: 이후 render() 함수를 부른다.\nthis.setState({comment: 'Hello'});\n```\n\nthis.state는 constructor 내에서만 사용할 수 있다.\n\n### (2) State 업데이트는 비동기적일 수도 있다.\n\nReact는 성능을 위해 여러 setState() 호출을 단일 업데이트로 한꺼번에 처리할 수 있다. 따라서 **직전 값을 기반으로 업데이트를 해야할 경우**에는 setState(객체) 가 아닌 setState(함수) 를 사용하자. setState(함수) 는 첫번째 인자로 이전 state 첫 번째 인자를, 두번째 인자로 업데이트가 적용된 시점의 props를 받는다.\n\n```jsx\n// Wrong (객체)\nthis.setState({\n  counter: this.state.counter + this.props.increment,\n});\n\n// Correct (화살표함수)\nthis.setState((state, props) => ({\n  counter: state.counter + props.increment\n}), (prev, next) => {\n  console.log(prev);\n  this.setState((state, props) => {\n    return { \n     counter: state.counter + props.increment;\n    }\n  })\n});\nthis.setState((state, props) => ({\n  counter: state.counter + props.increment\n}));\nthis.setState((state, props) => ({\n  counter: state.counter + props.increment\n}));\n// Correct (일반함수)\nthis.setState(function(state, props) {\n  return {\n    counter: state.counter + props.increment\n  };\n});\n```\n\n### Reference\n- [Components and Props](https://ko.reactjs.org/docs/components-and-props.html)\n- [State와 생명주기](https://ko.reactjs.org/docs/state-and-lifecycle.html)\n- [누구든지 하는 리액트 1편: 리액트는 무엇인가](https://velopert.com/3612)\n- [누구든지 하는 리액트 4편: props 와 state](https://velopert.com/3629)\n"
  },
  {
    "path": "React/Composition.md",
    "content": "# Composition(합성)\n\n<br/>\n\nReact에서는 일반적으로 상속이 아닌 합성을 이용하여 컴포넌트를 재사용한다.\n\n## children prop\n\n`React`에서 어떠한 컴포넌트가 있을 때 그 컴포넌트의 자식 엘리먼트를 어떤 것이 들어올지 알 수 없는 경우가 있다.\n예를 들어, Dialog나 일반적인 웹 페이지에서 Header와 Footer를 제외한 Contents부분이 있을 수 있다.\n\n```js\nfunction Border(props) {\n    return (\n        <div>\n            {props.children}\n        </div>\n    );\n}\n```\n\n```js\nfunction WelcomeDialog() {\n    return (\n        <div>\n            <Border>\n                {/* Border 컴퍼넌트가 구현 할 요소를 선언. props.children으로 호출한다.*/}\n                <h1 className=\"Dialog-title\">\n                    Welcome\n                </h1>\n                <p className=\"Dialog-message\">\n                    Thank you for visiting our spacecraft!\n                </p>\n            </Border>\n            <Border>\n                {/* Border 컴퍼넌트가 구현 할 요소를 선언. props.children으로 호출한다.*/}\n                <h1 className=\"Dialog-title\">\n                    Second Title\n                </h1>\n                <p className=\"Dialog-message\">\n                    Wassup\n                </p>\n            </Border>\n        </div>\n    );\n}\n \nReactDOM.render(\n    <WelcomeDialog/>, document.getElementById('root')\n);\n```\n\n<br/>\n\n## 여러 개의 자식 엘리먼트\n\n```js\nfunction Contacts(){\n    return (\n        <div>Contacts!</div>\n    );\n}\n \nfunction Chat(){\n    return (\n        <div>Chat!</div>\n    );\n}\n```\n\n```js\nfunction SplitPane(props) {\n    return (\n        <div className=\"SplitPane\">\n            <div className=\"SplitPane-left\">\n                {props.left}\n            </div>\n            <div className=\"SplitPane-right\">\n                {props.right}\n            </div>\n        </div>\n    );\n}\n \nfunction App() {\n    return (\n        <SplitPane left={<Contacts />} right={<Chat />}/>\n    );\n}\n \nReactDOM.render(\n    <App/>, document.getElementById('root')\n);\n\n```\n\n위와 같이 컴포넌트가 여러 개 필요할 경우, 위와 같이 각각의 자식 엘리먼트를 props로 전달하면 된다. `React`에서는 props로 전달할 수 있는 것에 제한이 없기 때문이다.\n\n<br/>\n\n## Specialization\n\n`React`에서는 **상속이 아닌 합성(Composition)을 권장**하고 있으며 아래와 같이 `Dialog`라는 일반적인 컴포넌트를 이용하여 `WelcomDialog`라는 특수화된 컴포넌트를 구현한 뒤 이를 `SignUpDialog` 클래스 컴포넌트에서 이용하고 있다.\n\n```js\nfunction Dialog(props) {\n  return (\n    <FancyBorder color=\"blue\">\n      <h1 className=\"Dialog-title\">\n        {props.title}\n      </h1>\n      <p className=\"Dialog-message\">\n        {props.message}\n      </p>\n      {props.children}\n    </FancyBorder>\n  );\n}\n```\n\n```js\nfunction WelcomeDialog() {\n  return (\n    <Dialog\n      title=\"Welcome\"\n      message=\"Thank you for visiting our spacecraft!\">\n        {props.childern}\n    </Dialog>\n\n  );\n}\n```\n\n```js\nclass SignUpDialog extends React.Component {\n  constructor(props) {\n    super(props);\n    this.handleChange = this.handleChange.bind(this);\n    this.handleSignUp = this.handleSignUp.bind(this);\n    this.state = {login: ''};\n  }\n\n  render() {\n    return (\n      <WelcomeDialog>\n        <input value={this.state.login}\n               onChange={this.handleChange} />\n\n        <button onClick={this.handleSignUp}>\n          Sign Me Up!\n        </button>\n      </WelcomeDialog>\n    );\n  }\n\n  handleChange(e) {\n    this.setState({login: e.target.value});\n  }\n\n  handleSignUp() {\n    alert(`Welcome aboard, ${this.state.login}!`);\n  }\n}\n```\n\n---\n\n#### Reference\n\n- [Composition vs Inheritance](https://ko.reactjs.org/docs/composition-vs-inheritance.html)\n- [[React] 11. Component 간의 합성(Composition)](https://blog.sonim1.com/186)\n"
  },
  {
    "path": "React/Element와 Component.md",
    "content": "# Element와 Component\n\n<br/>\n\n## Element\n\n`React`에서 `element`는 일반 객체(Plain Object)이다. 따라서 생성하는데 큰 어려움이 없이 생성이 가능하다.<br/>\n단, 한 번 생성된 `element`는 변경불가능하다. 즉, `element`를 생성한 이후에는 해당 엘리먼트의 자식이나 속성을 변경할 수 없다.\n\n```js\nconst element = React.createElement(\n  'div',\n  {id: 'login-btn'},\n  'Login'\n)\n```\n\n`React.createElement()`함수는 아래와 같이 일반 객체를 반환한다.\n\n```js\n{\n  type: 'div',\n  props: {\n    children: 'Login',\n    id: 'login-btn'\n  }\n}\n```\n\n### React Element 렌더링과 업데이트\n\n---\n\n`React Element`를 렌더링하기 위해서는 `element`를 생성하고 이를 `ReactDOM.render()`로 `root DOM Node`와 생성한 `element`를 넘기면 된다.\n\n```js\nconst element = React.createElement(\n  'div',\n  {id: 'login-btn'},\n  'Login'\n);\nReactDOM.render(element, document.getElementById('root'));\n```\n\n[React 공식 문서 - Rendering Element](https://codepen.io/pen?&editable=true&editors=0010)\n\n\n`React Element`는 불변 객체기 때문에 변경할 수 없다. 따라서 업데이트하기 위해서는 새로운 `element`를 생성하여 `ReactDOM.render()`로 넘겨주면 된다.\n\n[React 공식 문서 - Update Element](https://codepen.io/pen?&editable=true&editors=0010)\n\n<br/>\n\n## Component\n\n`React`에서 `Component`는 함수와 비슷하다고 보면 된다.\n\n```js\nconst Button = ({ onLogin }) =>\n  <div onClick={onLogin} />\n```\n\n위와 같이 `Component`를 생성하면 `JSX`에서는 이를 아래와 같이 `transpile`한다.\n\n```js\nconst Button = ({ onLogin }) => React.createElement(\n  'div',\n  { onClick: onLogin },\n  'Login'\n)\n```\n\n[React 공식 문서 - Component Rendering](https://ko.reactjs.org/redirect-to-codepen/components-and-props/rendering-a-component)\n\n<br/>\n\n### Class Component vs Function Component\n\n---\n\n`Component`를 생성하는 방법에는 2가지가 있는데 첫 번째로 가장 간단한 방법은 `JS`함수를 작성하면 된다.\n\n```js\n//JS function 생성\nfunction HelloWorld(props) {\n    return <h1>Hello World {props.name}</h1>;\n}\n```\n\n또 다른 방법은 `ES6`의 `class`문법을 사용하여 생성하는 것이다.\n\n```js\n//ES6 class 사용\nclass HelloWorld extends React.Component {\n  render() {\n    return <h1>Hello World {props.name}</h1>;\n  }\n}\n```\n\n> 만약, `Component`가 `state`나 `LifeCycle Method`가 필요하다면 `class Component`를 사용하면 되고, 그게 아니라면 `function Component`를 사용하면 된다.\n\n---\n\n#### Reference\n\n- [sudheerj/reactjs-interview-questions](https://github.com/sudheerj/reactjs-interview-questions#what-is-the-difference-between-element-and-component)\n- [react Docs - 엘리먼트 렌더링](https://ko.reactjs.org/docs/rendering-elements.html)\n- [react Docs - Component와 Props](https://ko.reactjs.org/docs/components-and-props.html)\n"
  },
  {
    "path": "React/ImmutableState.md",
    "content": "### React의 상태 불변성\n\n`react`와 `redux`의 공식 문서를 읽다 보면 `Immutability`를 강조하는 대목을 종종 볼 수 있다. \n왜 불변성(Immutability)를 유지해줘야 할까?\n\n불변성을 지키지 않으면 우리는 컴포넌트를 최적화 할 수 없다.\n\n리액트가 컴포넌트를 렌더링하는 과정을 살펴보자.\n\n> 1. setState를 호출 (혹은 부모로부터 props를 전달 받음)\n> 2. shouldComponentUpdate를 실행했는데 false를 리턴하면 여기서 멈추고, true를 리턴하면 다음 단계로 이동\n> 3. 가상 DOM과 실제 DOM을 비교해서 변경사항이 있으면 화면을 다시 그린다\n\n핵심은 2번에 있다. 다음과 같은 2개의 상태를 비교한다고 가정해보자.\n\n```js\nconst array = [1,2,3,4];\nconst sameArray = array;\nsameArray.push(5);\n\nconsole.log(array !== sameArray); // false\n```\n\n```js\nconst array = [1,2,3,4];\nconst differentArray = [...array, 5];\nconsole.log(array !== differentArray); // true\n```\n첫 번째 코드의 `array`와 `sameArray`변수가 참조하고 있는 배열의 주소 값은 서로 같다. 하지만, 두 번째 코드의 각각의 배열은 다른 레퍼런스를 가지기 때문에 비교했을 때 다르다는 결과 값이 나오게 된다.\n이와 같이 불변성을 유지하여 코드를 작성하면 각 객체의 값이 아닌 레퍼런스 값만 비교를 해주면 된다.\n\n즉, `shouldComponentUpdate`내의 코드는 한 줄이면 컴포넌트를 최적화할 수 있게 된다.\n\n하지만, 불변성을 유지하며 코드를 작성하다보면 상태 업데이트 로직이 복잡해질 수 있다.\n\n```js\nstate = {\n    where: {\n        are: {\n            you: {\n                now: 'faded',\n                away: true // 이 부분을 바꾸고 싶다\n            },\n            so: 'lost'\n        },\n        under: {\n            the: true,\n            sea: false\n        }\n    }\n}\n```\n\n```js\nconst { where } = this.state;\nthis.setState({\n    where: {\n        ...where,\n        are: {\n            ...where.are,\n            you: {\n                ...where.are.you,\n                away: false\n            }\n        }\n    }\n});\n```\n\n위의 예시만 봐도 충분히 복잡해지는 것을 볼 수 있다. 이런 상태 업데이트 로직을 편하게 해주는 대표적인 라이브러리가 우리가 `React`를 사용하면서 패턴 처럼 많이 사용해왔던 `Immutable.js`이다. \n\n정리하자면, React의 상태는 컴포넌트 최적화를 위해 불변성을 유지해야하며 이를 편하게 하기 위해 `Immutable.js`같은 불변 객체를 반환해주는 라이브러리를 사용한다.\n\n#### 🙏 Reference\n\n- [누구든지 하는 리액트: 9편 불변성을 지키는 이유와 업데이트 최적화](https://velopert.com/3640)\n- [리액트의 불변성과 Immutable.js 사용하기 - 1](https://byseop.github.io/2018/06/19/react-immutablejs01.html)\n- [React state가 불변이어야 하는 이유](https://medium.com/@ljs0705/react-state%EA%B0%80-%EB%B6%88%EB%B3%80%EC%9D%B4%EC%96%B4%EC%95%BC-%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0-ec2bf09c1021)\n"
  },
  {
    "path": "React/React Server Components.md",
    "content": "# React Server Component\n\n지난 2020년 12월 React Team에서 진행하고 있는 연구에 대해서 공유했다. 해당 내용에 대해서 자세히 알고 싶으면 [RFC](https://github.com/reactjs/rfcs/blob/bf51f8755ddb38d92e23ad415fc4e3c02b95b331/text/0000-server-components.md) 나 [YouTube](https://www.youtube.com/watch?v=TQQPAU21ZUw&feature=emb_title) 영상을 보는 것을 추천하다.\n\n## Intro\n\n오늘은 진행되고 있는 연구에 대해서 알아보는 시간이 되면서, 앞으로 프론트엔드가 어떻게 변화될 수 있을까? 생각해보는 시간을 가졌으면 한다.\n\n**RSC**라 불리는 이번 주제는 **React Server Component**의 약자이다. 이 기능은 모던 UX 서버 기반 모델에서 착안하였다고 한다.\n\n이는 우리가 이미 알고 있는 SSR(Server Side Rendering)과 다른 결과물로, Client-Side의 JS bundle을 줄여주는 것이 메인이다. 아직 Production Version에는 아직 올라오지 않았지만, [RFC](https://github.com/reactjs/rfcs/blob/bf51f8755ddb38d92e23ad415fc4e3c02b95b331/text/0000-server-components.md) 나 [YouTube](https://www.youtube.com/watch?v=TQQPAU21ZUw&feature=emb_title) 으로 확인 가능하다.\n\n위 영상의 Full Name은 **zero-bundle-size** React Server Component이다. 영상에는 설명뿐만 아니라 데모 영상과 데모 Repo도 알려주고 있어 따라 해볼 수 있다.\n\n## 주요 특징\n\n- 번들 사이즈를 줄인다.\n- Server Side Resource에 접근할 수 있다.\n- 데이터를 서버에서 로드하고 Component를 만드는데 필요한 데이터를 Client로 보낸다(JSON, HTML이 아니다).\n- Client에서 필요한 Component만 호출한다.\n- Server Component는 파일명이 `.server.js`다.\n- Client Component는 파일명이 `.client.js`다.\n- 두 군데 모두 사용하는 Shared Component는 파일명이 `.js`다.\n\n## SSR(Server Side Rendering)의 한계\n\n우리는 SSR을 Client Side의 차선책으로 사용한다. Server에서 HTML String을 만들어서 내려준다. 만들어진 HTML은 브라우저로 가서 First Contentful Paint 또는 Largest Contentful Paint로 보인다.\n\nSSR은 보통 초기 렌더링에만 쓰이고 다시 사용되지 않는다.\n\nRSC는 주기적으로 refetch 할 수 있다. rerendering이 필요할 때(data가 바뀌었을 때) 서버에서 만들어 Client로 보낸다.\n\nClient로 보내는 데이터는 단순한 JSON 또는 HTML이 아니라 React에서 사용되는 데이터 형식이라고 한다.\n\n```jsx\n// NoteWithMarkdown.js: *before* Server Components\n\nimport marked from 'marked'; // 35.9K (11.2K gzipped)\nimport sanitizeHtml from 'sanitize-html'; // 206K (63.3K gzipped)\n\nfunction NoteWithMarkdown({text}) {\n  const html = sanitizeHtml(marked(text));\n  return (/* render */);\n}\n```\n\n> Third Party Package를 사용하면 필요하지 않은 코드가 들어가게 되어 번들 사이드가 커진다.\n\n그러나 React의 새로운 Server Component는 Server Side Rendering을 보완하여 JavaScript 번들에 추가하지 않고도 중간 추상화 형식으로 렌더링할 수 있다고 한다.\n\nserver-tree와 client-tree state는 서로 유실없이 scaling up 할 수 있다. 이는 SSR에서는 검색 입력 텍스트, 포커스 및 선택 상태가 유지되지 않으나, Server Component에서는 가능하다는 것이다.\n\nServer Component가 SSR을 대체할 수 없다. 그러나 같이 사용할 수 있게 만들어질 수 있으며, 시너지가 좋을 것으로 생각된다.\n\nFacebook 팀에서 Server Component는를 적용해 본 결과, 번들 사이즈가 줄었다고 한다. 초기 측정 시 **-18%** 였으며, 최근에는 **-29%** 까지 되었다고 한다. \n\n```jsx\n// NoteWithMarkdown.server.js - Server Component === zero bundle size\n\nimport marked from 'marked'; // zero bundle size\nimport sanitizeHtml from 'sanitize-html'; // zero bundle size\n\nfunction NoteWithMarkdown({text}) {\n  // same as before\n}\n```\n\n> Server Component를 적용하게 되면 Third Party Package는 번들에 포함되지 않게 되며, Client에 내려주는 경우 필요한 정보만을 내리기 때문에 더욱 절약된다고 한다.\n\n## SSR vs Server Component\n\n- Server Component 코드가 Client에 전송되지 않는다. 반면 기존 SSR은 모든 Component 코드가 JS 번들로 Client에 전송된다.\n- Server Component를 사용하면 Tree의 어디에서나 백엔드에 직접 접근할 수 있다. Next.js에서는 `getServerProps()` 내부의 백엔드에 접근할 수 있지만, 최상위 페이지 수준에서만 작동하므로 Component화가 매우 제한적이다.\n- Server Component는 Tree 내부의 client state를 잃지 않고 다시 설정할 수 있다. 기본 전송이 HTML보다 풍부하여 내부 state(예: 검색 입력 텍스트, 포커스 및 선택)를 날려보내지 않고 서버 렌더링 부분(예: 검색 결과 목록)을 다시 가져올 수 있다.\n\n## Auto Code Splitting\n\nbest practice 중 하나는 Code Splitting 해서 User가 필요한 코드를 필요할 때 가져올 수 있다. 기존에 우리가 사용하던 `React.lazy()`은 휴리스틱에 의존했었다.\n\n```jsx\n// PhotoRenderer.js (before Server Components)\nimport React from 'react';\n\n// one of these will start loading *when rendered on the client*:\nconst OldPhotoRenderer = React.lazy(() => import('./OldPhotoRenderer.js'));\nconst NewPhotoRenderer = React.lazy(() => import('./NewPhotoRenderer.js'));\n\nfunction Photo(props) {\n  // Switch on feature flags, logged in/out, type of content, etc:\n  if (FeatureFlags.useNewPhotoRenderer) {\n    return <NewPhotoRenderer {...props} />; \n  } else {\n    return <PhotoRenderer {...props} />;\n  }\n}\n```\n\n### code-splitting의 문제점\n\n- 메타 프레임워크 (예 : Next.js) 외부에서 최적화는 수동으로 처리하여 `import`문을 `Dynamic import`로 대체해야 하는 경우가 많다.\n- 응용 프로그램이 사용자 환경에 영향을 미치는 Component를 로드하기 시작하면 지연될 수 있다.\n\nServer Component의 Client Component는 `import`를 최대한 code-splitting 지점으로 처리하여 auto code-splitting을 해준다.\n\n또한, 개발자는 서버에서 미리 사용할 Component를 선택할 수 있어, Client rendering에서 미리 가져올 수 있다.\n\n```jsx\n// PhotoRenderer.server.js - Server Component\nimport React from 'react';\n\n// one of these will start loading *once rendered and streamed to the client*:\nimport OldPhotoRenderer from './OldPhotoRenderer.client.js';\nimport NewPhotoRenderer from './NewPhotoRenderer.client.js';\n\nfunction Photo(props) {\n  // Switch on feature flags, logged in/out, type of content, etc:\n  if (FeatureFlags.useNewPhotoRenderer) {\n    return <NewPhotoRenderer {...props} />;\n  } else {\n    return <PhotoRenderer {...props} />;\n  }\n}\n```\n\n## 마무리\n\n간단하게 React 팀에서 하는 새로운 연구를 살펴보았다. 아직은 완성되지 않았지만, 연구가 새로운 생각을 만들어주었으면 앞으로가 기대된다.\n\n이를 통해서 앞으로의 프론트엔드를 점지할 수는 없지만, 여러 방향 중 하나는 알아보는 시간이 되었다고 생각한다.\n\n#### Reference\n\n- [React Server Components](https://addyosmani.com/blog/react-server-components)\n- [React 서버 컴포넌트](https://ui.toast.com/weekly-pick/ko_20210119)\n- [RFC: React Server Components](https://github.com/reactjs/rfcs/blob/bf51f8755ddb38d92e23ad415fc4e3c02b95b331/text/0000-server-components.md#summary)\n- [SSR vs Server Component](https://news.ycombinator.com/item?id=25499171)\n"
  },
  {
    "path": "React/React.memo.md",
    "content": "# React memo()\n\n리액트를 사용하게 되면 데이터가 변하게 되면 화면이 다시 렌더링이 이루어진다.\n\n그러나 데이터의 변화가 자주 일어나게 되고 그 데이터가 변하지 않았음에도 불구하고 렌더링이 이루어진다는 것을 알게 된다.\n\n리액트 팀에서는 이러한 퍼포먼스를 줄이고자 다양한 기능을 넣어두었다.\n\n오늘은 `memo()`에 대해서 알아보고 한다.\n\n<br/>\n\n## Intro\n\n일단 들어가기에 앞서 우리는 기본적인 `Class` 기반의 `Component` 를 많이 봐왔을 것이다.\n\n```js\nimport React from 'react';\n\nclass Test extends React.Component {\n  constructor(props) {\n      super(props);\n        this.state = {\n          count: 0\n        }\n  }\n\n  render() {\n      return (\n        <div >\n          {this.state.count}\n          <button onClick={()=>this.setState({count: 1})}>Click Me</button>\n        </div>\n      );\n  }\n}\n\nexport default Test;\n```\n\n<br/>\n\n## shouldComponentUpdate(LifeCycle)\n\n우리가 가장 먼저 접하는 이 `Class` 기반의 `Component`에 있어 라이프사이클의 하나로 `shouldComponentUpdate`를 넣어 주었다.\n\n> 자세한 라이프 사이클에 대해서는 [링크](https://github.com/SeonHyungJo/React-Lifecycle)를 참조\n\n일단 모양새를 이러하다.\n\n```js\nshouldComponentUpdate(nextProps, nextState) {\n  return true        \n}\n```\n\n기본적인 형태는 `Class`기반 `Component`로 선언한 안에서 `shouldComponentUpdate`라는 메소드를 만들고 2개의 인자를 받는다. `nextProps`와 `nextState`이다.(이름은 무엇으로 하든 상관은 없다.) \n\n이 2개의 인자에는 각각의 바뀐 데이터가 들어오게 된다. 이 단계에서 내가 원하는 데이터가 바뀌었을 때만 렌더링을 한다는 의미에서 `return` 값으로 `true` 를 주면 된다. \n\n당연하게 `false` 를 돌려주게 되면 렌더링을 하지 않는다.\n\n<br/>\n\n## Pure Component\n\n`Pure Component` 는 리액트 버전 **v15.5** 에 추가가 되었다.\n\n```js\nimport React from 'react';\n\nclass Test extends React.PureComponent {\n  constructor(props) {\n      super(props);\n      this.state = {\n          count: 0\n      }\n  }\n  render() {\n      return ( \n          <div> \n          { this.state.count } \n          <button onClick = {\n              () => this.setState({ count: 1 })\n          }> Click Me </button> \n          </div >\n      );\n  }\n}\n\nexport default Test;\n```\n\n사용방법은 간단하다. `Class`기반 `Component`에서 `React.PureComponent` 를 사용해서 `extends`를 하면 되는 것이다. \n\n이렇게 함으로써 우리가 위에서 보았던 `shouldComponentUpdate`과 같은 역할을 하는 것이다.\n\n**얕은 비교**를 하고 나서 렌더링을 할 지 판단하게 된다.\n\n## memo()\n\n때는 리액트 팀에서 **v16.6**으로 버전업을 하면서이다. `memo()` 라는 새로운 기능 말고도 `Suspense and Lazy Load` 라는 것도 있다. \n\n우리는 여기서는 `memo()` 에 대해서만 자세히 살펴보자. \n\n리액트에 있어서 컴포넌트를 생성하는 방법은 3가지가 있다고 한다.(한 블로그에서 그러하였다.)\n\n1. Component\n2. PureComponent\n3. Functional Component\n\n1번은 우리가 흔히 많이 사용하는 클래스기반의 컴포넌트이며 2번은 우리가 위에서 보았던 `shouldComponentUpdate` 를 알아서 해주는 컴포넌트이다. \n\n마지막으로 남은 `functional Component`에 대해서 알아보자.\n\n```js\nconst Funcomponent = ()=> {\n  return (\n      <div>\n          Hiya!! I am a Funtional component\n      </div>\n  )\n}\n```\n\n쉽게 말하면 우리가 클래스로 만들던 화면들을 함수로 만드는 것이다.\n\n우리가 이렇게 사용하게 되면 문제가 생기게 된다.\n\n클래스기반에 컴포넌트에서 발생하는 다수의 렌더링을 막기 위해서 사용하면 `shouldComponentUpdate` 나 `PureComponent` 를 사용할 수 없다는 것이다.\n\n이에 리액트팀에서는 함수형으로 나아가기 위해서 하나의 기능을 추가해 주었다. 그것이 바로 `React.memo()` 라는 것이다. \n\n```js\nconst Test = (props) => {\n    console.log('Rendering TestC :', props)\n    return ( \n        <div>\n        { props.count }\n        </>\n    )\n}\n\nexport default React.memo(Test);\n```\n\n기능은 따로 새롭다고 할 수 없다. 우리가 기존에 사용하고 있던 `shouldComponentUpdate` 나 `PureComponent` 와 비슷하기 때문이다. \n\n`memo()`는 `PureComponent` 와 더욱이 비슷하다. **얕은 비교**를 하고 렌더링을 판단을 하게 된다.\n\n`memo()`를 사용하는 것은 퍼포먼스 적으로 좋은 기능이라고 할 수 있지만 우리가 간과해서 안될 것은 **얕은 비교라는 것이다.**\n\nReference타입의 객체를 잘못 사용한다면 데이터가 바꼈음에도 불구하고 화면이 바뀌지 않는 현상이 발생하게 될 것이다.\n\n#### Reference\n\n- [Improving Performance in React Functional Components using React.memo()](https://blog.bitsrc.io/improve-performance-in-react-functional-components-using-react-memo-b2e80c11e15a)"
  },
  {
    "path": "React/React의 Lifecycle Event.md",
    "content": "# React의 Lifecycle Event(라이프사이클 이벤트)\n\n<br/>\n\n## 라이프사이클 이벤트\n\n`React`의 컴포넌트 생명 주기를 가지며, **컴포넌트가 생성되고 소멸되기까지의 과정에서 특정 시점에 호출되는 메서드들을 이용해 이를 제어**할 수 있다.\n\n<br/>\n\n## React v16.3 이전\n\n`React v16.3`이전의 라이프사이클과 이후의 라이프사이클은 약간의 차이를 보인다. 우선 이전의 라이프 사이클을 전체적으로 보면 다음과 같다.\n\n![react_lifecylce](/assets/images/react_lifecylce.png)\n\n<br/>\n\n### componentWillMount()\n\n---\n\n엘리먼트를 DOM에 추가하기 직전에 호출되는 메소드다.\nDOM을 조작할 수 없고, `render`가 호출되기 전이기 때문에 `setState`를 사용해도 `render`가 호출하지 않는다.\n\n```js\ncomponentWillMount() {\n    console.log('componentWillMount!');\n}\n```\n\n### componentDidMount()\n\n---\n\n컴포넌트가 렌더링 된 이후(`render`함수가 실행된 후)에 실행되는 메서드다. 비동기 통신으로 초기 데이터를 가져올 때 주로 사용된다.\n\n```js\ncomponentDidMount() {\n    console.log('componentDidMount');\n}\n```\n\n### componentWillReceiveProps(nextProps)\n\n---\n\n컴포넌트가 처음 마운트되는 시점에서는 호출되지 않고, 첫 렌더링을 마친 후 실행된다. `props`를 받아 `state`를 변경할 때 사용하며 내부에서 `setState`를 사용해도 추가적인 렌더링이 발생하지 않는다.\n\n```js\ncomponentWillReceiveProps(nextProps){\n  console.log(\"componentWillReceiveProps: \" + JSON.stringify(nextProps));\n}\n```\n\n### shouldComponentUpdate(nextProps, nextState)\n\n---\n\n컴포넌트 업데이트 직전에 호출되는 메서드며, 리렌더링 방지를 위해 사용한다.\n`props`나 `state`가 변경되었을 때, `true`값을 반환하면 리렌더링을 진행하고, 아니라면 리렌더링을 하지 않는다.\n\n```js\nshouldComponentUpdate(nextProps, nextState){\n  console.log(\"shouldComponentUpdate: \" + JSON.stringify(nextProps) + \" \" + JSON.stringify(nextState));\n  return true;\n}\n```\n\n### componentWillUpdate(nextProps, nextState)\n\n---\n\n`shouldComponentUpdate`가 실행된 직후 컴포넌트 업데이트 직전에 호출된다. 새로운 `props` 또는 `state`가 반영되기 직전 새로운 값들을 받는다. `setState`를 사용하면 무한 루프가 일어난다.\n\n```js\ncomponentWillUpdate(nextProps, nextState){\n  console.log(\"componentWillUpdate: \" + JSON.stringify(nextProps) + \" \" + JSON.stringify(nextState));\n}\n```\n\n### componentDidUpdate(prevProps, prevState)\n\n---\n\n컴포넌트가 업데이트 되고 난 후, 호출되는 메서드다.\n\n```js\ncomponentDidUpdate(prevProps, prevState){\n  console.log(\"componentDidUpdate: \" + JSON.stringify(prevProps) + \" \" + JSON.stringify(prevState));\n}\n```\n\n### componentWillUnmount()\n\n---\n\n컴포넌트가 DOM에서 소멸된 후, 실행되는 메서드다. 비동기 API나 값을 초기화 시켜줄 필요가 있을 때 사용한다.\n\n```js\ncomponentWillUnmount(){\n  console.log(\"componentWillUnmount\");\n}\n```\n\n<br/>\n\n## React v16.3 이후\n\n<br/>\n\n`React v16.3`이후 바뀐 부분들이 몇 가지 있다.\n\n- `componentWillMount`, `componentWillReceiveProps`, `componentWillUpdate`는 v17 부터 사용불가\n- `componentReceiveProps` => `getDerivedStateFromProps`\n- `componentWillUpdate` => `getSnapshotBeforeUpdate`\n- 에러 핸들링 API 추가(`componentDidCatch`)\n\n<br/>\n\n### getDerivedStateFromProps\n\n---\n\n`componentWillReceiveProps`에서는 `setState`를 사용했지만, `getDerivedStateFromProps`에서는 `state`를 갱신할 객체를 반환한다. 새로 넘어온 `props`가 `state`의 변경을 필요로 하지 않을 떄는 `null`을 반환한다.\n\n```js\n//componentReceiveProps\ncomponentWillReceiveProps(nextProps) {\n    if (this.props.name !== nextProps.name) {\n        this.setState({ name: nextProps.name });\n    }\n}\n```\n\n```js\n//getDerivedStateFromProps\nstatic getDerivedStateFromProps(nextProps, prevState) {\n    if (prevState.name !== nextProps.name) {\n        return { name: nextProps.name };\n    }\n\n    return null;\n}\n```\n\n### getSnapshotBeforeUpdate\n\n---\n\n많이 사용되는 메서드는 아니지만, 렌더링이 일어나는 동안 수동으로 특정 시점을 유지할 때 사용할 수 있다.\n\n### componentDidCatch\n\n---\n\n자신의 에러는 잡아내지 못하고 자식 컴포넌트에서 에러가 발생했을 때 실행된다.\n\n```js\nclass ErrorComponent extends React.Component {\n    constructor(props) {\n        super(props);\n        this.state = { isError : false };\n    }\n\n    componentDidCatch(error, info) {\n        this.setState({ isError : true });\n    }\n\n    render() {\n        if(this.state.isError)\n            return <h1>ERROR Occured!</h1>\n        \n        return this.props.contents;\n    }\n}\n```\n\n---\n\n#### Reference\n\n- [리액트 교과서 - 컴포넌트와 라이프사이클 이벤트](https://velog.io/@kyusung/%EB%A6%AC%EC%95%A1%ED%8A%B8-%EA%B5%90%EA%B3%BC%EC%84%9C-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8%EC%99%80-%EB%9D%BC%EC%9D%B4%ED%94%84%EC%82%AC%EC%9D%B4%ED%81%B4-%EC%9D%B4%EB%B2%A4%ED%8A%B8)\n- [라이프사이클 설명](http://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/)\n- [react Docs - State and Lifecycle](https://reactjs.org/docs/state-and-lifecycle.html)\n"
  },
  {
    "path": "React/SWR.md",
    "content": "![swr_intro](https://snyung.com/static/42030513b7a862660ae0bcec80b18c05/a6d36/SWR_Intro.png)\n\n# SWR\n\n## Intro\n\n새로운 프로젝트를 하게 되면서, 프로젝트에 적용할 많은 새로운 스펙을  찾아보았고, **Preact + Vite**를 메인으로 사용하였다. 관련하여 글을 작성하였으니 궁금하면 [Preact, Vite 일주일 사용후기](https://snyung.com/content/2020-12-20--Preact%20Vite%20%EC%9D%BC%EC%A3%BC%EC%9D%BC%20%EC%82%AC%EC%9A%A9%ED%9B%84%EA%B8%B0)를 확인하길 바란다.\n\n그중 Store 관리를 위한 도구로 Redux VS Context + Reducer를 고민했으나, 전역으로 Store를 관리하는 데 있어 불편함을 느끼던 찰나, 같은 고민을 하시던 분들의 글을 읽고 SWR를 도입하였다. 사용해본 결과 공유를 하면 좋을 거 같아 작성하였다.\n\n## What\n\n[공식사이트](https://swr.vercel.app) 상단에 단순하고 명확하게 무엇인지 알려주고 있다.\n\n> **React Hooks library for data fetching**\n\n**데이터를 가져오기 위한 React Hook 라이브러리**이다. SWR의 이름은 `HTTP RFC 5861`에서 사용되는 HTTP 캐시 무효화 전략인 `stale-while-revalidate`에서 가져왔다.\n\nSWR의 전략은 캐싱된 데이터가 있으면 먼저 가져오며, 서버 데이터 가져온 후 마지막으로 최신의 데이터를 업데이트한다.\n\n### 특징\n\n- Lightweight\n- Backend Agnostic\n- Realtime\n- [Jamstack](https://snyung.com/content/2021-01-08--JAMstack) Oriented\n- TypeScript Ready\n- Remote + Local\n\n## 사용법\n\n### 기본형태\n\nSWR의 기본형태는 아래와 같다.\n\n```jsx\nimport useSWR from 'swr'\n\nfunction Profile() {\n  const { data, error } = useSWR('/api/user', fetcher)\n\n  if (error) return <div>failed to load</div>\n  if (!data) return <div>loading...</div>\n\n  return <div>hello {data.name}!</div>\n}\n```\n\n`useSWR`로 React Hook으로, 주된 인자로 key와 fetcher가 있다. 첫 번째 인자는 API URL면서 캐싱할 때 사용되는 key가 된다. 이는 `useSWR('/api/user', fetcher)`를 여러 컴포넌트에서 사용하여도 같은 key의 데이터가 있다면 캐싱된 것을 가져오는 것이다.\n\n두 번째 인자는 fetcher이다. [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)를 기본으로 하며, 제일 많이 사용되는 [Axios](https://github.com/axios/axios)나 [GraphQL](https://graphql.org/)을 사용할 수 있다.\n\n자세한 내용은 아래의 사이트를 참고하면 된다.\n\n> [SWR - Data Fetching](https://swr.vercel.app/docs/data-fetching)\n\n## Why\n\nSWR은 왜 나오게 되었으며, 왜 사용하게 되었나 간단한 예제를 통해서 살펴보자.\n\n![swr_example](https://snyung.com/static/babf0180fa33b84a2f95ebec4a07d034/a6d36/SWR_Example.png)\n\n위와 같은 화면이 있다고 하자.\n\nWebsite에서는 Avatar와 Content 둘 다 user 데이터를 사용하는 것을 볼 수 있다. 예전부터 우리는 상위 컴포넌트 `useEffect`에서 Data Fetching하고 props를 통해서 하위 컴포넌트에 데이터를 전달하는 방식을 주로 사용하였다. \n\n이러면 Data Fetching을 상위 컴포넌트에서 유지하고 모든 컴포넌트에 데이터를 props로 넘긴다. 새로운 데이터 또는 컴포넌트가 늘어나게 되면 다시 상위 컴포넌트의 구조를 바꾸고 하위 컴포넌트에서 필요한 데이터는 추가, 변경하여 하위 컴포넌트로 넘긴다.\n\n그러나 상위 컴포넌트에 모든 것을 하게 되면서 관리의 어려움이 발생한다.\n\n```jsx\n// page component\nfunction Page () {\n  const [user, setUser] = useState(null)\n\n  // fetch data\n  useEffect(() => {\n    fetch('/api/user')\n      .then(res => res.json())\n      .then(data => setUser(data))\n  }, [])\n\n  // global loading state\n  if (!user) return <Spinner/>\n\n  return <div>\n    <Navbar user={user} />\n    <Content user={user} />\n  </div>\n}\n\n// child components\nfunction Navbar ({ user }) {\n  return <div>\n    ...\n    <Avatar user={user} />\n  </div>\n}\n\nfunction Content ({ user }) {\n  return <h1>Welcome back, {user.name}</h1>\n}\n\nfunction Avatar ({ user }) {\n  return <img src={user.avatar} alt={user.name} />\n}\n```\n\nprops의 사용을 피하기 위해서 Context를 사용한다. 이 역시 Dynamic Component에서 문제가 발생한다. 페이지 내 Component가 Dynamic 할 경우 최상위 컴포넌트는 자식 컴포넌트의 어떤 데이터가 필요한지 알지못할 수 있다.\n\nSWR은 이 문제를 해결해준다.\n\n```jsx\n// page component\nfunction Page () {\n  return <div>\n    <Navbar />\n    <Content />\n  </div>\n}\n\n// child components\nfunction Navbar () {\n  return <div>\n    ...\n    <Avatar />\n  </div>\n}\n\nfunction Content () {\n  const { user, isLoading } = useUser()\n\n  if (isLoading) return <Spinner />\n\n  return <h1>Welcome back, {user.name}</h1>\n}\n\nfunction Avatar () {\n  const { user, isLoading } = useUser()\n\n  if (isLoading) return <Spinner />\n\n  return <img src={user.avatar} alt={user.name} />\n}\n```\n\n간단하게 `useSWR` Hook를 해당 데이터가 필요한 컴포넌트에 바인딩한다. 이렇게 되면 상위 컴포넌트가 데이터를 가지면서, 전달에 신경 쓸 필요가 없다.\n\n쉽게 말하면 컴포넌트가 필요로 하는 데이터를 필요한 곳에 바인딩하는 것이다. Container 컴포넌트는 사용하지 않아도 된다.\n\n같은 SWR 키를 사용하면, 요청에 대해 자동으로 중복제거, 캐시, 공유되어 API 요청이 하나만으로 가능하다.\n\n또 하나 좋은 기능으로 아래 상황에서 자동으로 revalidate 한다.\n\n- User Focus\n- Network Reconnect\n- 탭 전환\n- 절전 모드 해제\n\n## How\n\n새로운 기술을 적용하기에 앞서 항상 해당 기술이 현재 사용하고 있는 것을 대안으로 할 만큼 Cover 하나 확인하고 검증하는 단계가 필요하다. \n\n두 가지를 살펴보도록 하자.\n\n### mutate(local + remote)\n\nData Fetching은 파악되었다. 그러나 현재 웹사이트의 수정이 일어나게 되면 서버로 요청하고 서버의 데이터를 다시 요청해서 업데이트하는 방식은 네트워크 비용이 들기에 유저에게 좋지 못한 경험을 준다.\n\n대신 데이터를 로컬로 업데이트하는 것이 서버의 데이터를 변경해서 반영하는 방법보다 더 좋은 방법이다.\n\n`mutate`를 사용하면 로컬 데이터를 업데이트하는 동시에 유효성을 다시 검사하고 최신 데이터로 바꿀 수 있다.\n\n```jsx\nimport useSWR, { mutate } from 'swr'\n\nfunction Profile () {\n  const { data } = useSWR('/api/user', fetcher)\n\n  return (\n    <div>\n      <h1>My name is {data.name}.</h1>\n      <button onClick={async () => {\n        const newName = data.name.toUpperCase()\n        \n        // 로컬 데이터를 바로 업데이트한다. 대신 3번째 인자를 false로 두어 재요청을 하지 않는다.\n        mutate('/api/user', { ...data, name: newName }, false)\n        \n        // 데이터를 업데이트하는 요청을 한다.\n        await requestUpdateUsername(newName)\n        \n        // 재요청을 한다.\n        mutate('/api/user')\n      }}>Uppercase my name!</button>\n    </div>\n  )\n}\n```\n\n위와 같이 로컬 데이터를 우선적으로 업데이트하여 유저에서 변경사항을 보여주며 수정 API를 동기적으로 요청 후 완료가 되면 수정된 데이터를 가져와서 로컬데이터를 업데이트 한다.\n\n더 자세한 내용은 아래의 주소를 참고하면 된다.\n\n> [mutate](https://swr.vercel.app/docs/mutation)\n\n### Reusable\n\nuseSWR을 각각의 컴포넌트에 적용하는 방법도 충분히 간단하지만, 더 쉽게 Hook으로 구성해서 사용할 수 있다. \n\n한 개의 API를 호출할 때도 유용하지만 2개이상의 API를 같이 사용하는 데이터 형식에서도 유용하다.\n\n```jsx\nfunction useUser (id) {\n  const { data, error } = useSWR(`/api/user/${id}`, fetcher)\n\n  return {\n    user: data,\n    isLoading: !error && !data,\n    isError: error\n  }\n}\n```\n\n```jsx\nfunction Avatar ({ id }) {\n  const { user, isLoading, isError } = useUser(id)\n\n  if (isLoading) return <Spinner />\n  if (isError) return <Error />\n\n  return <img src={user.avatar} />\n}\n```\n\n위와 같은 패턴으로 사용하면 명령적 방식으로 사용하지 않고, 원하는 컴포넌트에 원하는 데이터를 넣는 선언적 방식으로 사용할 수 있다.\n\n## 마무리\n\n물론 Redux를 사용해서 Selector와 Dispatch를 사용해서도 할 수 있다. 그러나 Redux를 사용하더라도 데이터를 가져와 저장하고 Selector를 지정하는 등 많은 것을 해야해서 불편함을 느꼈다. 그러던 중 각각의 컴포넌트별 사용할 데이터를 선언적으로 개발할 수 있다는 건 정말 좋았다. \n\n한 가지 아쉬운 것은 Fetching 이외의 수정, 삭제는 따로 개발해서 사용해야한다.\n\n현재 SWR 이외의 Data Fetching하는 도구는 많이 나오고 있다. 앞으로 더 좋은 도구들이 나오길 바라며, 앞으로 행보가 기대된다.\n\n#### Reference\n\n- [SWR 공식사이트](https://swr.vercel.app)\n- [전역 상태 관리에 대한 단상 (stale-while-revalidate)](https://jbee.io/react/thinking-about-global-state/)\n"
  },
  {
    "path": "React/Virtual DOM.md",
    "content": "# Virtual DOM\n\nreact에서는 Virtual DOM(Document Object Model)이라는 개념이 있다. 이 Virtual DOM에 대해 알아보자.\n\n## 브라우저의 렌더링\n\nvirtual DOM을 알아보기 앞서 먼저 브라우저 렌더링 프로세스를 생각해야 한다.\n\n[웹 브라우저의 작동 원리](https://github.com/Im-D/Dev-Docs/blob/master/Browser/%EC%9B%B9%20%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80%EC%9D%98%20%EC%9E%91%EB%8F%99%20%EC%9B%90%EB%A6%AC.md)에 따르면 브라우저에서 화면은 크게 JS - Style - Layout - Paint - Composite의 단계로 그려진다.\n\n![rendering process](https://user-images.githubusercontent.com/24724691/62412567-bf49f200-b63f-11e9-9ed4-ec8215d04a7d.png)\n\ndisplay가 완료된 상태에서 DOM 조작을 하게 되면 보통의 경우 tree를 수정하게 된다. 그럼 render tree - layout - painting의 단계를 다시 거치게 된다.\n이와 관련된 내용은 [Reflow Repaint](https://github.com/Im-D/Dev-Docs/blob/master/Performance/Reflow%20Repaint.md)에서 확인할 수 있다.\n\n다수의 DOM 조작이 발생하여 잦은 reflow/repaint를 발생시킨다면 성능에 영향을 줄 것이다. 한 화면에서 DOM을 변경하여 기능을 구현하는 SPA의 경우 이 DOM조작이 많을 수 밖에 없다.\n\n이 때 사용되는 것이 virtual DOM이다.\n\n## 메모리에 있는 가상의 DOM\n\nvirtual DOM은 메모리에 존재하는 가상 DOM이다. react는 메모리에 virtual DOM을 가지고 있다가 view의 변화를 감지하면 virtual DOM을 1차적으로 변화시킨다.\n\n그런 뒤 이를 한꺼번에 모아 실제 DOM에 전달한다. (batch)\n\n![react-virtual-dom](https://user-images.githubusercontent.com/24724691/64325552-5ae5ce00-d003-11e9-9c50-ae0e888919e1.png)\n출처 https://auth0.com/blog/face-off-virtual-dom-vs-incremental-dom-vs-glimmer/\n\n실제 dom에 바로 적용한다면 rendering process의 일부분을 매번 다시 발생시킨다. 하지만 memory의 virtual dom에 모았다가 발생시킨다면 rendering process는 한번만 일어나게 된다.\n\n## Why react\n\n이 개념은 사실 react에만 특별히 있는 것은 아니다. document fragment로 dom조작을 하면 이 개념과 크게 다르지 않다.\n\n그런데 react가 이렇게 주목받는 이유는 dom fragment 관리를 자동화 해주기 때문이다. virtual dom을 추상화하여 내부에서 처리하기 때문에 개발자가 따로 관리해야 할 것이 많지 않다.\n\nvanilla script로 복잡한 상태와 다양한 view를 관리해봤다면 이 불편함을 잘 알 것이다. 이를 반자동의 느낌으로 다룰 수 있어 인기가 많다.\n\n반자동이기에 성능은 vanilla를 이길 수 없다. 하지만 생산속도와 유지보수에 엄청난 강점을 가진다. 성능을 약간 포기하고 개발의 편리성을 끌어올리는 것이 react의 사용 이유다.\n\n## Reconciliation\n\n그럼 내부적으로 어떤 작업이 일어나길래 좋은 성능을 가질 수 있을까?\n\nVirtual DOM을 갱신할 때 [Reconciliation](https://reactjs.org/docs/reconciliation.html) 작업을 한다. Reconciliation 작업은 Virtual DOM과 DOM을 비교해 DOM을 갱신하는 작업이다.\n\n## virtual dom 갱신 방법\n\nvirtual dom을 변경하는 제일 일반적인 방법 중 하나는 `setState()`다.\n`setState()`로 state를 변경하면 `ReactUpdates.enqueueUpdate()`를 실행해 변경 대상 컴포넌트로 등록한다.\n그런 뒤 나중에 배치작업 시 이를 실제로 갱신한다.\n\n화면의 변화가 일어나는 것은 이 갱신 타임에 일어난다.\n\nthis.state 값을 직접 변경하는 경우 변경 대상 컴포넌트로 등록하는 작업이 일어나지 않아 따로 등록처리가 일어나기 이전에는 갱신이 발생하지 않는다.\n\n이 외에도 `render()`를 실행하면 하위 컴포넌트들을 돌며 갱신한다. 이 `render()` 방식은 redux에서 store 변경 시 일어난다.\n\n### diffing algorithm\n\n대상 컴포넌트에 등록된 (enqueue) 컴포넌트들은 비교 알고리즘을 통해 virtual dom과 실제 dom을 비교하게 된다.\n\n이 비교 알고리즘을 거친 뒤 변경되었다고 판단되면 추후 배치 업데이트가 된다.\n\n그런데 문제는 최신의 비교 알고리즘도 O(n^3)의 복잡도를 가진다.\n\n컴포넌트가 100개만 되어도 1000000번의 비교연산이 수행된다. 성능이 너무 좋지 않다.\n\n리액트는 n^3의 오래걸리는 알고리즘을 채택하는 대신 '휴리스틱 알고리즘'을 사용한다.\n\n[휴리스틱](https://ko.wikipedia.org/wiki/%ED%9C%B4%EB%A6%AC%EC%8A%A4%ED%8B%B1_%EC%9D%B4%EB%A1%A0)이란 어림짐작하는 방법이다.\n\na와 b를 직접 비교하지 않고 특정 기준만 보고 어 다른데? 하고 판단하는 것이다.\n\n이 휴리스틱의 판단 기준은 두가지다.\n\n1. 다른 타입의 엘리먼트는 더이상 비교하지 않고 다르다고 판단한다.\n2. key prop이 변경되었다면 다르다고 판단한다.\n\n#### 다른 타입의 엘리먼트 \n\n```diff\n-<div>\n+<span>\n  <Counter />\n-</div>\n+</span>\n```\n\n이와 같이 `div` => `span`으로 변경되었다면 엘리먼트의 타입이 변경된 경우다. 이 경우 하위는 비교하지 않는다.\n\n그냥 변한것이며 트리를 아예 다시 그린다. 따라서 unmount 후 state를 버리고 다시 마운트 한다.\n\n타입은 그대로지만 state => props가 변경되는 경우 componentWillRecieveProps => componentWillUpdate => render가 불려 다시 렌더링이 일어난다. \n\n#### key prop\n\n```jsx\n<ul>\n  <li>1</li>\n  <li>2</li>\n  <li>3</li>\n</ul>\n```\n이런 데이터가 있을때 4가 추가된다고 하자.\n\n```diff\n<ul>\n  <li>1</li>\n  <li>2</li>\n  <li>3</li>\n+ <li>4</li>\n</ul>\n\n<ul>\n+ <li>4</li>\n  <li>1</li>\n  <li>2</li>\n  <li>3</li>\n</ul>\n```\n\n위와 아래는 표면적으로 크게 차이가 없어보인다. 하지만 react는 전자를 하위 노드 추가, 후자를 전체 하위 노드 변경으로 취급하여 둘을 다르게 처리한다.\n\n따라서 고유한 key prop을 통해 최적화 한다.\n\n```jsx\n<ul>\n  <li key={'2019'}>4</li>\n  <li key={'2016'}>1</li>\n  <li key={'2017'}>2</li>\n  <li key={'2018'}>3</li>\n</ul>\n```\n\n이렇게 하면 새로 추가된 li가 2019라는 것을 명확하게 알 수 있기 때문에 비교 알고리즘에 2019만 걸리고 이를 업데이트 한다.\n\n---\n\n### 참고자료\n\n- https://auth0.com/blog/face-off-virtual-dom-vs-incremental-dom-vs-glimmer/\n- https://velopert.com/3236\n- https://hashnode.com/post/the-one-thing-that-no-one-properly-explains-about-react-why-virtual-dom-cisczhfj41bmssp53mvfwmgrq\n- https://d2.naver.com/helloworld/9297403\n- https://reactjs.org\n"
  },
  {
    "path": "React/props와 state.md",
    "content": "# props와 state\n\n<br/>\n\n## props\n\n`React`에서 `props`는 컴포넌트에 전달되는 입력 값이다. 함수의 매개변수를 생각하면 쉽다. 사용 방법은 `HTML`의 태그에서 속성과 같은 문법으로 컴포넌트에 전달하고 자식 컴포넌트에서는 `this.props`를 통해 사용한다. <br/>`props`는 함수형 컴포넌트나 클래스 컴포넌트 모두에서 사용할 수 있다. 함수형 컴포넌트에서는 다이얼로그와 같이 `props`만 받아와서 해당 컴포넌트를 렌더링만 할 때 사용하면 유용하다.\n\n```js\n//class 컴포넌트\nimport React, {Component} from 'react';\n\nclass Dialog extends Component {\n    static defaultProps ={\n        title : '환영합니다!'\n    }\n\n    render() {\n        return() {\n            <div>\n                {this.props.title}\n            </div>\n        }\n    }\n}\n\nexport default Dialog;\n```\n\n```js\n//functional 컴포넌트\nimport React from 'react';\n\nconst Dialog = ({title}) => {\n    return() {\n        <div>\n            {title}\n        </div>\n    }\n}\n\nexport default Dialog\n```\n\n```js\nimport React, {Component} from 'react';\nimport Dialog from './Dialog';\n\nclass App extends Component {\n    render() {\n        return() {\n            <Dialog title='Welcome to Im-D' />\n        }\n    }\n}\n\nexport default App\n```\n\n쉽게 생각하면 `props`는 특정 컴포넌트에 커스텀된 입력 값을 전달하기 위해 존재하는 개념이라고 보면 된다.\n\n<br/>\n\n## state\n\n`React`에서 `state`는 컴포넌트의 변경 될 수 있는 정보를 보유하는 객체다. `state`는 private하기 때문에 컴포넌트 외부에서는 직접적으로 접근할 수 없다.\n\n`state`를 정의하는 방법은 다음과 같다.\n\n```js\nimport React, { Component } from 'react';\n\nclass Developer extends Component {\n  state = {\n    name: 'BKJang',\n    skill: 'Javascript'\n  }\n\n  render() {\n    return (\n      <div>\n        <h1>Developer</h1>\n        <div>Info: {this.state.name} / {this.state.skill}</div>\n      </div>\n    );\n  }\n}\n\nexport default Developer;\n```\n\n위와 같이 `state`를 정의하는 방법이 `class fields` 문법을 사용하는 방법이다.\n이는 편의를 위한 방법이며 이외에 `constructor`를 사용하는 방법이 있다.\n\n```js\nimport React, { Component } from 'react';\n\nclass Developer extends Component {\n  constructor(props) {\n      super(props);\n      this.state = {\n        name: 'BKJang',\n        skill: 'Javascript'\n      }\n  }\n\n  render() {\n    return (\n      <div>\n        <h1>Developer</h1>\n        <div>Info: {this.state.name} / {this.state.skill}</div>\n      </div>\n    );\n  }\n}\n\nexport default Developer;\n```\n\n`constructor` 에서 `super(props)` 를 호출 한 이유는 React의 Component 를 상속하기 때문에 React Component가 갖고 있던 생성자를 `super` 를 통하여 미리 실행한 이후, 우리가 필요한 `state`를 설정해주는 것이다.\n\n그렇다면 `state`값을 바꾸고 싶을 땐 어떻게 하면 될까? `React`에서는 `state`를 변경하기 위해서는 무조건 `setState`함수를 통해서 상태를 변경해주어야 한다. `React`에서는 `setState`함수가 호출되면 컴포넌트가 리렌더링되도록 되어 있기 때문이다.\n\n### setState함수를 통한 state 변경\n\n---\n\n- **객체 전달을 통한 state 변경**\n\n```js\nstate = {\n    name: 'BKJang',\n    skill: 'Javascript'\n}\n  \nthis.setState({\n    skill : 'Java' \n})\n```\n\n- **two depth이상의 state 변경**\n\n```js\nstate = {\n    name: 'BKJang',\n    skill: {\n        frontEnd : 'Javascript',\n        backEnd: 'Java'\n    }\n}\n  \nthis.setState({\n    skill : {\n        ...this.state.skill,\n        backEnd: 'Node.js'\n    } \n})\n```\n\n위의 예시 처럼 `skill`에서 `backEnd`에 해당하는 상태 값만 변경하고 싶다면 [Spread Operator(전개 연산자)](https://bkdevlog.netlify.com/posts/spread-rest)를 사용하여 변경하면 된다.\n\n- **함수 전달을 통한 state 변경**\n\n```js\nstate = {\n    dialogVisible : false\n}\n  \nthis.setState(\n    (state) => ({\n        dialogVisible : !state.dialogVisible\n    })\n)\n```\n\n위와 같이 현재 `state`를 매개변수로 전달하고 이를 이용해 `state`값을 변경하는 방법을 사용할 수 있다.\n\n```js\nthis.setState(\n    ({dialogVisible}) => ({\n        dialogVisible : !dialogVisible\n    })\n)\n```\n\n혹은 위와 같이 `ES6`의 [Destructuring(비구조화 할당)](https://bkdevlog.netlify.com/posts/destructuring)을 사용하여 `state`를 변경할 수도 있다.\n\n위 2가지 방법은 어떤 것이 더 좋다라고 할 수 없다. 상황에 따라 더 적절한 방법을 선택하는 것이 맞다.\n\n### setState함수 실행 이후의 콜백\n\n---\n\n`setState`함수를 무조건 실행한 이후 특정 함수를 콜백으로 실행해야할 경우가 있다. <br/>`setState`는 비동기적으로 실행되기 때문에 JS의 이벤트 루프상 `setTimeout`과 같은 비동기 함수를 사용하여 동기적으로 콜백 함수를 동작하도록 할 수도 있다. 하지만 `setState`함수의 2번째 인자로 특정 함수를 전달해주면 `setState`함수의 콜백 함수로 동작하기 때문에 다음과 같이 사용할 수 있다.\n\n```js\nstate = {\n    currentMonth : 5;\n}\n\nhandleMonthWithNext = () => {\n    this.setState(({currentMonth}) => ({\n       currentMonth : currentMonth + 1; \n    }), () => {\n     this.getCalendarData(this.state.currentMonth)\n    })\n}\n\ngetCalendarData = () => {\n    console.log(this.state.currentMonth); //6\n}\n```\n\n<br/>\n\n## props vs state\n\n`props`와 `state`는 모두 JS의 순수 객체다. 둘 다 렌더링에 영향을 주는 정보를 가지고 있다. <br/>단, `props`는 함수의 매개변수와 비슷하게 해당 컴포넌트로 전달되는 반면, `state`는 함수 내에서 선언된 변수와 유사하게 해당 컴포넌트 내에서 관리된다.\n\n---\n\n#### Reference\n\n- [sudheerj/reactjs-interview-questions](https://github.com/sudheerj/reactjs-interview-questions#what-is-state-in-react)\n- [Velopert - 누구든지 하는 리액트 4편: props 와 state](https://velopert.com/3629)\n"
  },
  {
    "path": "Rules/Commit.md",
    "content": "# Commit Rules\n\n## Commit Type\n\n커밋의 사용되는 타입은 크게 4가지로 구분한다.\n\n- create: Create docs(새로운 문서 생성)\n- update/{reviewerName}: Update docs(PR상 올라가 있는 문서 수정)\n- hotfix: Update docs without brach(Master 머지 후 발견된 수정 사항)\n- maintain: Update README.md(기타 문서 수정)\n\n### Example\n\n```md\n// 괄호도 포함하는 메시지\n\n[create]: Create Scope.md\n\n[update] : Scope 설명 코드 예시 보충(최대한 자세하게)\n[update/BKJang]: 서브넷 네트워크와 네트워크 주소 차이 추가(최대한 자세하게)\n[update/sNyung]: 네트워크 주소 예시 수정(최대한 자세하게)\n\n[hotfix]: 띄어쓰기\n[hotfix]: 오탈자 수정\n\n[maintain]: Update README.md (Add commit message type)\n```\n\n## 커밋 작성 예시\n\n### github.com에서 새로운 파일 올리기\n\n![레포 화면 버튼](https://user-images.githubusercontent.com/24274424/85224874-5199e680-b408-11ea-9ea5-f573d1fbe979.png)\n\n> Create new file => Click\n\n![글작성 페이지](https://user-images.githubusercontent.com/24274424/85224898-71310f00-b408-11ea-9079-31ed804861f6.png)\n\n> 자신의 글 작성 및 하단으로 이동\n\n![커밋 메시지 작성](https://user-images.githubusercontent.com/24274424/85224950-9f165380-b408-11ea-9cac-d5a00d61a1ff.png)\n\n> 커밋메시지 타입 중 create를 사용하여 작성\n\n### github.com에서 파일 수정하기\n\n![PR 화면](https://user-images.githubusercontent.com/24274424/85225028-38456a00-b409-11ea-9c43-8cf821d15f2d.png)\n\n> 자신의 PR로 들어감\n\n![image](https://user-images.githubusercontent.com/24274424/85225044-54490b80-b409-11ea-83e3-4fbe1a8eff7e.png)\n\n> Files changed => 우측 vertical dots 클릭 => edit file 클릭\n\n![글 수정 및 하단 메시지](https://user-images.githubusercontent.com/24274424/85225071-865a6d80-b409-11ea-997c-bcfbf311cd6b.png)\n\n> 글 수정 및 하단 메시지 이동\n\n![update 메시지 작성](https://user-images.githubusercontent.com/24274424/85225088-9eca8800-b409-11ea-870c-b26a30fe36bf.png)\n\n> update 타입을 사용하여 작성 및 commit 클릭\n"
  },
  {
    "path": "Rules/Markdown.md",
    "content": "# Mardown_Rule\n\n## 대제목\n\n당연하게 `#` 한개\n\n```\n#\n```\n\n## 중제목\n\n```\n##\n```\n\n## 소제목\n\n```\n###\n\n--- // # 3개는 라인이 생기지 않으므로 넣어줌\n```\n\n## 리스트\n\n```\n1.\n2.\n3.\n```\n\n## 점 리스트\n\n```\n-\n```\n\n## 소스\n\n```\n`내용` //단어나 한줄짜리\n\n//Multi line\n```js\n```// javascript => 축약형으로\n\n```\n\n## 사진첨부\n\nCaption 내용은 파일명_Number로 진행\n\n```\n![파일명_number]()\n```\n\n## 링크\n\n```\n[]()\n```\n\n## 참조\n\n```\n>\n>\n```\n\n## 라인바꾸기\n\n```\n<br/>\n```\n\n## 제목간 간격\n\n```\n중제목 \n<br/>\n중제목\n```\n\n```\n중제목 //없음\n소제목\n```\n\n```\n소제목\n소제목\n```\n\n## 참조 \n\n라인을 넣는 것에 대해서는 지금은 넣는 것으로 진행\n\n```\n---\n\n#### Reference\n```\n"
  },
  {
    "path": "Security/HTTPS와 SSL.md",
    "content": "# HTTPS와 SSL\n\n<br/>\n\n## HTTP(Hypertext Transfer Protocol)\n\nHTTP 프로토콜은 Hypertext인 HTML을 전송하기 위한 통신 규약을 의미한다.<br/>교환 방식은 복잡한 바이너리 데이터가 아닌 단순 텍스트를 통해 이뤄진다. 여기서 HTTP프로토콜의 문제가 여실히 드러난다.\n\n만약 **서버와 클라이언트간의 데이터를 누군가가 중간에서 가로챘다**고 해보자. 그 데이터를 가로채 변조한다거나 악의적인 감청이 일어난다면 데이터는 **단순 텍스트**이기 때문에 문제가 생길 것이다.<br/>예를 들어, **로그인을 위해서 서버로 비밀번호를 전송**할 때 악의적인 감청이나 데이터의 변조등이 일어날 수 있다는 것이다.\n\n이를 보완한 것이 **HTTPS**고 이를 이해하기 위해선 약간의 암호화 기법 지식이 필요하다.\n\n<br/>\n\n## 암호화 기법\n\nHTTPS를 설명하기 위해서 알아야 할 암호화 기법에는 **대칭키 암호화 기법**과 **비대칭 키 암호화 기법**이 있다.\n\n### 대칭키 암호화 기법\n\n---\n\n대칭키 암호화 기법은 하나의 키를 가지고 암호화와 복호화가 가능한 것이다. 간단하다.\n\n클라이언트와 서버가 암호화와 복호화 하는 방법을 모두 알고 있다면 이를 대칭키 암호화 기법이라고 보면 된다. 대칭키 암호화 기법은 **암호를 주고 받는 사람들만 키 값을 알고 있다면 안전**하다. 하지만 **문제는 대칭키를 서로 공유하기 힘들다.**\n\n공유를 위해 만약 최초에 클라이언트에서 서버에 데이터를 전송할 때 대칭키를 같이 전송하는 과정에서 대칭키가 해커에게 탈취된다면 암호화 방식 전체를 바꿔야할 것이다.\n\n### 비대칭키 암호화 기법(공개키 암호화)\n\n---\n\n비대칭키 암호화 기법은 암호화와 복호화를 하기 위한 키가 다르다는 것이다. 즉 암호화를 하는 방법과 복호화를 하는 방법이 다르기 때문에 중간에 암호화된 데이터가 탈취된다고 해도 복호화를 할 방법이 없다. \n\n<br/>\n\n![https_asymmetric_key](/assets/images/https_asymmetric_key.png)\n\n<br/>\n\n하지만 여기서 생각해봐야 할 것이 있는데 **'서버로 전송된 데이터가 클라이언트에서 전송한 것인지, 안전한 데이터라고 확신할 수 있을까?'** 라는 것이다.\n\n<br/>\n\n## HTTPS\n\n이를 위해 우리는 **SSL 인증서**를 사용한다. 서버로 전송된 데이터가 안전한 데이터라는 것을 SSL 인증서를 통해 확인하는 것이다. 그리고 이 인증서를 발급해주는 민간 기관을 **CA**라고 하고 이 **CA 리스트를 브라우저는 내부적으로 가지고 있다.**<br/>즉, 비대칭키 암호화 기법을 이용해 암호화된 데이터를 서버로 전송하는 과정에서 SSL 인증을 받은 데이터만 서버에서는 신뢰하는 것이다.\n\n하지만 이 방식은 느릴 수 있기 때문에 대칭키 암호화와 비대칭키 암호화를 같이 사용하기도 한다.\n\n<br/>\n\n---\n\n#### Reference\n\n* [비둘기로 설명하는 HTTPS(HTTPS explained with carrier pigeons)](https://www.vobour.com/%EB%B9%84%EB%91%98%EA%B8%B0%EB%A1%9C-%EC%84%A4%EB%AA%85%ED%95%98%EB%8A%94-https-https-explained-with-car)\n* [무하프로젝트 - HTTP, HTTPS 프로토콜이란? ](http://mohwaproject.tistory.com/entry/HTTPS%EB%9E%80)\n* [HTTPS와 SSL 인증서](https://opentutorials.org/course/228/4894)"
  },
  {
    "path": "Security/Response_Header_Security.md",
    "content": "# 웹 보안, 웹 취약점 막기\n\n웹 개발자들이 많이 알고 사용하고 있는 웹 페이지 사이트로 테스트를 진행해보고 보안 관련한 이슈를 해결해보자.\n\n아래의 사이트를 들어가서 본인의 사이트를 입력한 후 테스트를 진행하면, 진단 후 종합테스트 결과를 보여준다.\n\n> [성능 체크하기](https://www.webpagetest.org/)\n\n![performance 1](https://user-images.githubusercontent.com/24274424/112757684-cf3cf380-9025-11eb-91f6-8450c4c4e29c.png)\n\n### 설정 전\n\n![prev-setting](https://user-images.githubusercontent.com/24274424/112757694-d7952e80-9025-11eb-9d68-402b483fbe26.png)\n\n설정 전에는 보안 영역에서 F가 나온 것을 볼 수 있다.\n\n### 설정 후\n\n![post-setting](https://user-images.githubusercontent.com/24274424/112757704-debc3c80-9025-11eb-9387-2db68f9601fa.png)\n\n추후 설정을 하고 나서 A등급으로 변경된 것을 확인할 수 있다.\n\n### 설정이 필요한 요소\n\n사이트를 테스트해보니 위에서 설정 전처럼 **F 등급**이 나왔다. 자세히 보기 위해서 버튼을 누르게 되면 부족한 설정과 어떤 설정을 해주어야 하는지 친절하게 설명해준다.\n\n![security-list](https://user-images.githubusercontent.com/24274424/112757711-eaa7fe80-9025-11eb-9c39-d7a52eee4f21.png)\n\n각각의 설정에 대해서 알아보고 Cloudfront + S3 구조로 되어있는 곳에서 어떻게 설정해야 하는지 살펴보자.\n\n## Strict Transport Security\n\n흔히 **HSTS**라 불리는 항목으로 http를 사용하는 대신 https를 사용하여 액세스 해야 한다고 알려주는 Header다. \n\n```text\nstrict-transport-security: max-age={number}; includeSubdomains\n```\n\n**Cache-Control**과 동일한 **max-age**를 설정하여 언제까지 https로만 액세스해야 하는지 설정하며, **includeSubdomains**은 서브도메인까지 포함해서 설정하려고 할 때 사용하는 값이다.\n\n![strict-transport-security](https://user-images.githubusercontent.com/24274424/112757716-eda2ef00-9025-11eb-892a-34a606fe174a.png)\n\n> 참고 : [naver.com](https://naver.com)\n\n네이버에서는 위의 사진과 같이 설정해서 사용하고 있다. preload라는 설정값도 있지만, 해당 값은 적용되지 않는 브라우저도 있으며, 네이버에서도 여러 이유로 사용하고 있지 않은 것으로 보인다.\n\n> [MDN : Strict Transport Security](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security)\n\n## X-Content-Type-Option\n\nResource를 다운로드할 때 해당 Resource의 **MIME type**이 일치하지 않는 경우 차단한다.\n\n```text\nX-Content-Type-Options: nosniff\n```\n\n위와 같이 설정하게 되면 Style Sheet는 MIME type이 `text/css`와 일치할 때까지 Style Sheet를 로드하지 않는다. 또한 공격자가 다른 확장자(jpg)로 서버에 파일을 올린 후 script 태그들의 src 경로를 변경하여 script를 로드하는 등의 공격을 막아준다.\n\n![x-content-type-option](https://user-images.githubusercontent.com/24274424/112757737-03181900-9026-11eb-8c86-e5eafba72b95.png)\n\n> [MDN : X-Content-Type-Options](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options)\n\n## X-Frame-Options\n\n이 Header는 사용자의 눈에 보이지 않는 영역을 추가하고, 사용자는 의도한대로 버튼을 누르지만 실제로는 다른 곳을 클릭하게 만드는 [**ClickJacking**](https://en.wikipedia.org/wiki/Clickjacking)을 방지할 수 있는 옵션이다.\n\n- X-Frame-Options : DENY => 모든 표시를 거부.\n- X-Frame-Options : SAMEORIGIN => 동일한 출처에 대한 것만 표시.\n- X-Frame-Options : ALLOW FROM https://snyung.com => https://snyung.com에 대해서만 허용.\n\n![x-frame-options](https://user-images.githubusercontent.com/24274424/112757740-057a7300-9026-11eb-8033-d54fec75205c.png)\n\n> [MDN : X-Frame-Options](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options)\n\n## Content Security Policy(CSP)\n\n브라우저에서 XSS와 관련된 공격을 막아주는 Header다. 브라우저는 페이지에서 요청하는 모든 코드를 내려받아 실행한다. \n\n하지만 CSP를 설정함으로써 브라우저에게 특정 조건의 Resource를 실행하거나 Rendering 지시를 내릴 수 있다. 지시문의 종류는 `default-src`, `script-src`, `child-src`등이 있다.\n\nCSP를 적용하기는 쉽지 않다. 모든 페이지를 정확히 알고 있지 않은 한 어디에 무슨 코드가 숨어있을지 알 수 없기 때문이다. 실제 해당 내용을 바로 적용하는 것이 아니라 위반 사항이 발견될 경우 Report만 받는 것으로 설정을 할 수 있다.\n\n**이 설정은 네이버에서도 사용하고 있지 않는 것으로 보인다.**\n\n> [MDN : CSP](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP)\n\n## X-XSS-Protection\n\n이 Header는 한 번 https로 접속하는 경우 이후의 모든 요청을 http로 요청하더라도 브라우저가 자동으로 https로 요청한다.\n\n```text\nX-XSS-Protection: 1;mode=block\n```\n\n위처럼 설정하면 브라우저가 XSS 공격을 감지하면 자동으로 내용을 치환한다. **mode=block** 유무에 따라 내용만 치환하고 사용자 화면에 보여주거나 페이지 로드 자체를 block 할 수 있다.\n\n위 Header는 브라우저의 내장 **XSS Filter**에 의해 처리되므로 브라우저마다 처리 방식이 다를 수 있다. 모든 공격을 막을 수는 없기 때문에 추가적으로 Filter를 설정하여 방어해야 한다.\n\n![x-xss-protection](https://user-images.githubusercontent.com/24274424/112757744-09a69080-9026-11eb-8b57-b780a60ec124.png)\n\n> [MDN : X-XSS-Protection](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection)\n\n## 최종 결과물 (Chrome_DevTool)\n\n![response-headers](https://user-images.githubusercontent.com/24274424/112757781-2ba01300-9026-11eb-8325-d343db05ae3d.png)\n\n## CloudFront + Lambda@Edge로 설정하기\n\nCloudFront + S3 구조를 사용하게 되면 Header를 넣어주는 방법을 찾을 수 없다. Cache-Control과 같은 설정은 S3의 설정으로 추가하면 되지만 Response의 Header는 해줄 수 없는 것이다.\n\n그러나 AWS에서는 다른 방법으로 제공해주고 있다. 바로 **Lambda@Edge**이다.\n\nLambda를 사용해서 CloudFront로 들어와 S3에서 Resource를 가져온 후 Response 전 Lambda Function을 호출하여 Header 값을 추가해줄 수 있는 것이다.\n\n![lambda-1](https://user-images.githubusercontent.com/24274424/112757782-2e026d00-9026-11eb-9620-623044a3949b.png)\n\n아직은 블루프린트에서 cloudfront-modify-response-header 항목이 없어서 버지니아 북부로 설정해주고 생성해야한다.\n\n![lambda-2](https://user-images.githubusercontent.com/24274424/112757785-3064c700-9026-11eb-9276-e77c86968f4a.png)\n\n함수 명을 작성하고 생성하게 되면 CloudFront를 선택하라는 화면이 나오면서 원하는 CloudFront와 연결할 수 있다.\n\n![lambda-3](https://user-images.githubusercontent.com/24274424/112757790-32c72100-9026-11eb-93d3-7d40c7b3b518.png)\n\n아래를 확인해보면 Request에 연결할 것인지, Response에 연결할 것인지 선택할 수 있다. 우리는 Response에 연결해주면 된다.\n\n### Lambda 코드\n\n```js\nexports.handler = async (event, context) => {\n  const response = event.Records[0].cf.response;\n  const headers = response.headers;\n\n  headers['strict-transport-security'] = [{key: 'Strict-Transport-Security', value: 'max-age=63072000; includeSubdomains;'}]; \n  headers['content-security-policy'] = [{key: 'Content-Security-Policy', value: default-src 'none'; img-src 'self'; script-src 'self'; style-src 'self'; object-src 'none'}]; \n  headers['x-content-type-options'] = [{key: 'X-Content-Type-Options', value: 'nosniff'}]; \n  headers['x-frame-options'] = [{key: 'X-Frame-Options', value: 'DENY'}]; \n  headers['x-xss-protection'] = [{key: 'X-XSS-Protection', value: '1; mode=block'}]; \n  headers['referrer-policy'] = [{key: 'Referrer-Policy', value: 'same-origin'}]; \n\n  return response;\n};\n```\n\n#### Reference\n\n- [https://www.webpagetest.org/](https://www.webpagetest.org/)\n"
  },
  {
    "path": "Security/SQL_Injection.md",
    "content": "# SQL Injection\n\nSQL인젝션은 웹 페이지 입력을 통해 SQL 구문에 악의적인 코드를 위치시키는 코드 인젝션 기술이다. \n\n이를 통해 데이터베이스에 피해를 입힌다. 가장 흔한 웹 해킹 기술 중 하나이다. \n\n대표적인 기법만 서술하였으며, 자세한 공격기법은 `sql injection cheat sheet` 를 참고하면 된다. \n\n![SQL Injection - 행안부 시큐어코딩 가이드](/assets/images/SQL_Injection_1.png)\n\n![SQL Injection Joke](/assets/images/SQL_Injection_2.png)\n\n<br/>\n\n## 목적 및 영향\n\n### 인증 우회\n\n로그인 폼(form)을 대상으로 공격을 수행한다. 공격에 성공하면 정확한 정보 없이 로그인에 성공한다.\n\n> [여기 어때 해킹 사례(2017.03)](https://www.bloter.net/archives/278144)\n> - 보안이 허술한 특정 웹 페이지를 대상으로 SQL 인젝션 공격을 시도해서 관리자 세션을 탈취, 개인정보 유출\n\n### DB 데이터 조작 및 유출\n\n조작된 쿼리가 실행되게 하여 개인정보 혹은 기밀정보에 접근하여 데이터를 획득한다. \n\n또한, 데이터 값을 변경하거나 테이블을 지워버릴 수 있다.\n\n> [뽐뿌 해킹 사례(2015.09)](http://www.korea.kr/news/pressReleaseView.do?newsId=156081058)\n> - 보안이 허술한 웹 페이지에서 정상적인 입력값 외의 질의 구문 삽입 및 실행\n\n### 시스템 명령어 실행\n\n일부 데이터베이스의 경우 확장 프로시저 호출도 가능하다. 이를 이용하면 원격으로 시스템 명령어를 수행할 수 있다. \n\n즉, 해당 서버의 모든 자원에 접근할 수 있게된다.\n\n> 참고 - [SQL 구문삽입을 이용한 운영체제 명령어 실행](https://webhack.dynu.net/?idx=20170109.001)\n\n<br/>\n\n## 공격 원리\n\nSQL인젝션은 다음 조건을 모두 만족해야 가능하다.\n\n1. DB와 연동된 웹 애플리케이션\n\n2. 외부 입력값을 DB 쿼리문에 사용\n\n웹 애플리케이션의 경우 대부분이 위 두가지 조건을 충족하기 때문에 SQL인젝션은 유효한 공격 기법이 될 수 있다.\n\n<br/>\n\n## SQL 인젝션\n\n### 쿼리 조건 무력화\n\nWhere 조건이 무조건 참이 되도록 조작한다. \n\n주석을 이용해 조건절이 작동하지 않게 하거나, `or '1' = '1'` 과 같은 항상 참인 조건을 이용한다.\n\n```sql\n# 주석을 이용\n[ 외부 입력값 ]\nUserID: admin'--\nPassword: 1234\n\n[ 실행되는 쿼리문 ]\nSelect * From Users Where UserID = 'admin'-- And Password = '1234'\n\n# 항상 참인 조건을 이용\n[ 외부 입력값 ]\nUserID: test\nPassword: 1234' or '1'='1\n\n[ 실행되는 쿼리문 ]\nSelect * From Users Where UserID = 'test' And Password='1234' or '1'='1'\n```\n\n또한, 이를 응용하여 두 개 이상의 명령어를 연속으로 실행시킬 수 있다.\n\n```sql\n# 세미콜론을 이용하여 여러개의 구문 실행\n[ 외부 입력값 ]\nUserID: admin' ; DELETE From Users--\nPassword: 1234\n\n[ 실행되는 쿼리문 ]\nSelect * From Users Where UserID = 'admin' ; DELETE From Users -- And Password='1234'\n```\n\n<br/>\n\n### 고의적 에러 유발 후 정보 획득\n\nUNION을 이용하여 원본 쿼리가 반환하는 컬럼의 수를 알아낸다.\n\n```sql\n[ 외부 입력값 ]\nUserID: test' UNION SELECT 1,1,1,1 --\nPassword: 1234\n\n[ 실행되는 쿼리문 ]\nSelect * From Users Where UserID = 'test' UNION SELECT 1,1,1,1 -- And Password='1234'\n```\n\n> 에러 페이지 컨트롤을 하지 않으면 클라이언트에게 에러를 보여준다. 이를 이용하여 컬럼을 알아낼 수 있다.\n\n또한 알아낸 컬럼 수를 기반으로 시스템 테이블의 정보를 조회할 수도 있다.\n\n```sql\nSelect * \nFrom Users \nWhere UserID = 'test' \nUNION \n  SELECT name, object, 1,1 \n  FROM sys.tables \n  # 시스템 정보를 담은 테이블은 데이터베이스마다 다르다. \n  # 중요한것은 이와 같은 쿼리로 테이블을 관리하는 테이블에서 정보를 추출할 수 있다는 것이다.\n-- And Password='123'\n```\n\n<br/>\n\n### 시스템 명령어 실행\n\nMS SQL 서버의 경우 프로시저를 이용하여 DB조회 결과에 프로그램 실행 결과를 포함시킬 수 있는데, \n\n이를 이용하여 운영체제 명령어를 실행시킬 수 있다.\n\n이외에도 조회결과를 파일로 저장하는 기능 등에 웹쉘을 삽입하여 공격할 수 있다.\n\n<br/>\n\n## Blind SQL 인젝션\n\n일반적인 SQL 인젝션 공격은 공격하는 대상 웹페이지가 오류를 출력하거나, 쿼리 결과 리스트를 제공해야 한다. \n\n그렇지 않을 경우 유효한 공격 기법이 Blind SQL 인젝션이다.\n\nBlind SQL 인젝션은 쿼리 결과의 참/거짓 으로부터 DB 값을 유출해내는 기법이다.\n\n가장 간단한 예시로는 ID 찾기 혹은 게시판 검색 같은 기능의 결과값이 제대로 출력되는지 확인하여 참/거짓 판별 요소를 찾는 것이다.\n\n### Boolean-based Blind 공격\n\nAND 조건에 논리식을 대입하여 참/거짓 여부를 알아내는 방식이다.\n\n```sql\n# 유효한 검색단어와 항상 참이되는 조건 부여\n[ 외부 입력값 ]\n검색 : 게시글명' AND 1=1--\n\n# 유효한 검색단어와 항상 거짓이 되는 조건 부여\n[ 외부 입력값 ]\n검색 : 게시글명' AND 1=2--\n\n#실행되는 쿼리\nSELECT * FROM TB_Boards WHERE Title = 'hello' AND ...\n```\n\n위와 같이 게시판을 이용하여 참과 거짓 조건을 판단할 수 있다. \n\n또한, 여기에 AND 조건을 덧붙여 알고싶은 정보를 추출할 수 있다.\n\n<br/>\n\n### Time-based Blind 공격\n\n만약 참/거짓에 따른 응답이 항상 같다면 응답결과만으로 참/거짓을 판단할 수 없다. \n\n이럴 경우 시간을 지연시키는 쿼리를 주입하여 참/거짓 여부를 판단할 수 있다.\n\n```sql\n[ 외부 입력값 ]\n검색: 게시글 명' ;  IF SYSTEM_USER='sa' WAITFOR DELAY '00:00:5'--  # MS SQL 예시\n```\n\n만약 시스템  계정의 이름이 'sa' 라면 응답이 5초 지연될 것이고, 아니라면 응답이 즉시 이루어질 것이다.\n\n<br/>\n\n## 대응 방안\n\n### 웹 방화벽(Web Application Firewall; WAF) 도입\n\n웹 방화벽은 응용계층(application layer)의 패킷 내용을 기준으로 패킷의 보안성을 평가하고, 정해진 규칙에 따라 제어한다. \n\nSQL 인젝션에 대한 규칙을 설정하여 공격에 대비할 수 있다. \n\n#### 물리적 웹 방화벽\n\n기업의 규모가 크거나, 보안이 중요한 환경 혹은 예산이 충분하다면 물리적 방화벽 도입이 가장 좋은 방법이다. \n\n어플라이언스 형태의 제품을 사용하거나, SECaaS(Security as a Service) 형태의 클라우드 기반의 솔루션 도입도 좋은 방법일 수 있다.\n\n> 어플라이언스(appliance) : 설치나 설정 없이 하드웨어 자체로 이용할 수 있는 기기 혹은 특정 소프트웨어가 이미 장착되어 최적화된 상태의 기기\n\n<br/>\n\n#### 논리적 웹 방화벽(공개 웹 방화벽)\n\n전용 웹 방화벽 장비 도입이 어렵다면, 공개 웹 방화벽을 고려해볼 수 있다. \n\n물리적인 장비 대신 논리적인 구성으로 웹 방화벽 역할을 수행한다.\n\n> 윈도우 서버에서는 WebKnight, 아파치 서버에서는 ModSecurity가 주로 사용된다. 많이 사용하기 때문에 미리 정의된 규칙을 적용하여 사용할 수 있다.\n\n<br/>\n\n### 시큐어 코딩\n\n#### 입력값 유효성 검사\n\n보안적 측면에서 외부 입력값은 신뢰하면 안된다. 모든 입력값을 의심해야한다. \n\n이 때, 입력값은 사용자가 입력한 값 뿐만 아니라 프록시 변조와 같은 외부 값 또한 포함된다.\n\n> 프록시 변조를 이용한 입력값 조작은 burp suite과 같은 툴을 이용하여 테스트 할 수 있다.\n\nSQL 인젝션의 가장 기본적인 대응 전략은 입력값 유효성을 검사하는 것이다. \n\n검사를 위한 방법은 블랙리스트 방식과 화이트리스트 방식이 있다.\n\n<br/>\n\n##### 블랙리스트 방식\n\n특정 문자나 키워드를 제한하는 방식이다. 공격에 사용되는 주석 문자나, IF, UNION과 같은 키워드등을 필터링 하는 것이다.\n\n<br/>\n\n##### 화이트리스트 방식\n\n블랙리스트 방식보다 강력한 방법이다. 블랙리스트는 특정 키워드를 제외한 모든 입력값을 허용하지만, \n\n화이트리스트 방식에서는 허용된 문자를 제외한 모든 입력값을 금지한다.\n\n> 웹 어플리케이션의 기능에 따라 화이트리스트를 다르게 유지해야 한다.\n\n<br/>\n\n#### 동적 쿼리 사용 제한\n\n웹 애플리케이션에서 정적쿼리만 사용한다면 SQL 인젝션을 신경 쓸 필요가 없다. \n\n하지만, 현실적으로 동적 쿼리를 사용하지 않을 수 없다. 따라서 매개변수화된 쿼리(미리준비된 쿼리)를 사용해야 한다.\n\n구조화된 쿼리는 동적 쿼리를 정적 쿼리처럼 사용하는 기법이다. 쿼리 구문에서 외부 입력값이 SQL 구문의 구조를 변경하지 못하도록 정적 구조로 처리한다.\n\n쉽게 말해, 입력값을 매개변수로 처리하는 것이다.\n\n##### 예시\n\n```java\n// JDBC\nString sql = \"SELECT column FROM table WHERE column = ?\";\nPreparedStatement pstmt = conn.preparedStatement(sql);\n\npstmt.setString(1,\"name of column\");\n```\n```js\n// Node-mySql\nlet sql = 'SELECT column FROM table WHERE column = ?';\nlet param = 'column name';\nconn.query(sql, param, function(err, rows, fields){});\n```\n\n<br/>\n\n#### 에러메세지 출력 제한\n\nDB 오류 정보를 사용자에게 그대로 노출하면 안된다. \n\n개발단계에서 디버깅을 위해 내부 정보를 상세히 알려주는 경우가 많은데, 이러한 정보가 노출되면 DB 구조를 파악하여 데이터 유출을 시도할 수 있다. \n\n따라서 사용자에게 커스텀 오류 페이지를 제공해야 한다.\n\n<br/>\n\n또한, 너무 자세한 안내 메세지도 주의하여야 한다. \n\n가장 접하기 쉬운 예로, 로그인에 실패했을 때 ID와 비밀번호가 무엇이 틀렸는지 알려주는 것이 있다. 이는 공격의 범위를 좁히는 수단이 될 수 있다. \n\n이러한 경우 `로그인에 실패하였습니다.` 와 같은 추상적인 메세지가 더 좋을 수 있다.\n\n<br/>\n\n### DB보안\n\n관리자가 사용하는 DB 계정과 어플리케이션에서 접근하는 DB 계정을 분리하여 관리해야 한다. \n\n또한, 어플리케이션에서 접근하는 DB 계정에는 최소 권한 원칙(least privilege policy)을 적용하여 최소한의 권한만 부여한다.\n\n> 이를 응용하여 모든 DB 액세스를 프로시저로 만들고, 해당 프로시저들의 실행 권한만 부여하는 방법, CRUD 각각의 권한을 분리하여 접근을 제한하는 방법이 있다.\n\n또한, 반드시 필요한 프로시저가 아니면 제거하는 것이 좋다.\n\n> MS SQL Server의 xp_cmdshell 프로시저는 db에서 시스템 명령을 실행할 수 있도록 해주는 확장 프로시저이다. 이러한 프로시저는 제거하는 것이 좋다.\n\n<br/>\n\n### 취약점 점검과 모니터링\n\n#### 지속적 취약점 점검\n\n모의 해킹 혹은 취약점 점검 툴을 이용하여 취약점 점검을 정기적으로 수행해야 한다. 웹사이트의 업데이트는 빈번하게 이루어지기 때문이다. \n\n다른 곳의 보안이 철저하더라도, 이벤트 페이지가 잘못 작성되었으면 공격이 이루어질 수 있다.\n\n<br/>\n\n#### 로깅과 모니터링\n\nSQL 인젝션은 오류를 유발시키거나 동일한 페에지 및 기능을 반복적으로 호출하는 형태로 이루어진다. \n\n따라서 500오류가 비정상적으로 많이 발생하거나, 동일한 IP에서 동일한 페이지를 과다하게 호출하는 경우에 대한 규칙을 설정하여 관리해야한다.\n\n<br/>\n\n---\n\n#### References\n\n- [[웹 보안]SQL Injection](http://m.mkexdev.net/427)\n- [SQL Injection Cheat Sheet 번역](https://ragonfly.tistory.com/entry/SQL-Injection-Cheat-Sheet-%EB%B2%88%EC%97%AD)\n- [SQL Injection Cheat Sheet - netsparker](https://www.netsparker.com/blog/web-security/sql-injection-cheat-sheet/)\n- JAVA 시큐어 코딩 가이드 - 행정안전부\n"
  },
  {
    "path": "Security/리만가설과 소수정리.md",
    "content": "# 리만가설과 소수정리, RSA\n\n이 세가지는 서로 연관이 있다.\n\n리만가설 => 소수정리 => 암호학과 연결된다. 일단 리만가설부터 출발한다.\n\n## 리만가설\n\n주어진 수보다 작은 소수의 개수에 관하여... 라는 논문에서 제타함수의 성질들을 열거한 것이 리만가설이다.\n\n여기서 소수란 2, 3, 5, 7, 9, 11, 13 등과 같은 수를 말한다.\n\n- 관련 수식은 아래와 같다.\n\n  ![](https://wikimedia.org/api/rest_v1/media/math/render/svg/e9bd691fccd9541432c60dc5ad456a236fcd395b)\n\n  이게 주어진 수(s)보다 작은 소수의 개수를 구하는 방식이다. 이 해를 구하고자 고민하다가 발견한 것이 주어진 수가 -2n의 형식이면(이때 n은 자연수) 항상 0이된다라는 것을 발견했다.\n\n  ![](https://wikimedia.org/api/rest_v1/media/math/render/svg/d1fde30fa0ef08e41740321cb277b57f98588d03)\n\n- 이 때 수학적으로 -2n의 구조를 자명한 근 이라고 한다. 자명한 근은 확실한 해를 이야기한다. 그렇다면 자명하지 않은 근은 이 반대인 여집합을 말한다.\n- 리만에 따르면 자명한 근은 -2n의 구조를 가지며 자명하지 않은 근은 4개를 찾았다. 그런데 모두 a+bi의 복소수 형태를 가지고 있음을 확인했다. 더 나아가 1/2 + 000i(000은 자릿수)의 형태까지 일치함을 확인했다.\n- 이 후 다른 더 많은 해를 찾지 못하다가 튜링이 튜링머신을 만들어 자명하지 않은 근을 1104개의 더 찾았으며 모두 이 형식과 같았다.(그래프의 직선상에 위치)\n\n## 소수정리\n\n어떤 양수 이하의 소수가 몇개인가? 라는 질문이다.\n\n- 소수정리의 수식은 아래와 같다.\n\n  ![](https://wikimedia.org/api/rest_v1/media/math/render/svg/8e4100bd4f7c4e6054eca3fbbfd6a90d3a37c6ec)\n\n  이게 x / logx 정도 된다고 한다. 이 소수정리를 증명하는데 리만가설의 제타함수가 사용된다. 그래서 리만가설과 소수정리가 연결된다.\n\n- 소수정리를 증명하려면 제타함수의 실수부가 필요하다. 즉 1/2 + 000i 부분의 1/2부분이 필요하다.\n\n- 제타함수에서 실수부가 1보다 작다 라는 것만 증명하면 소수정리는 증명된다고 한다.\n\n## 암호학\n\n- 이제 암호학과 소수정리를 연결시켜보자.\n\n- RSA 암호방식은 소수 x 소수 => 큰 숫자를 만들어 내는 방식이다.\n\n  `K1 * K2 = X` 라고 하자. 이 때 K1과 K2는 소수다.\n\n  X가 엄청나게 큰 수라면 X만 가지고 K1과 K2를 찾아내기는 쉽지않다.\n\n  이게 RSA 암호의 기본 틀이다.\n\n- **소수는 규칙이 없다.** 가 현재의 믿음이다.\n\n  암호화 후 X만 주고 소인수 분해하여 K1과 K2를 찾아내야지 복호화가 가능하다. 그런데 사실상 K1과 K2를 찾아내는 일은 너무 많은 연산이 필요하다.\n\n이에 만일 리만가설이 증명되어 소수의 규칙을 찾아내는 방식이 나온다면, 현재의 RSA 암호체계가 위협을 받을 수도 있다는 문제가 발생할 수 도 있다. 그래서 현제 리만가설을 풀어내려는 수학 과학계의 움직이미 암호학에 영향을 미칠 수 있어 이슈가 되고 있다.\n"
  },
  {
    "path": "Tool/Chrome_80_DevTool.md",
    "content": "# Chrome 80 DevTool Update\n\n## 콘솔창에서 `let` 과 `class` 재선언을 지원한다.\n\n `let` 과 `class` 의 재선언을 지원한다. 재선언을 할 수 없는 것은 콘솔창을 가지고 새로운 Javascript 코드를 실험하는 개발자에게는 엄청난 불편함이었다. \n\nscript 안쪽에 있는 `let` 이나 `class`를 재선언하는 것은 이전과 동일하게 `SyntaxError`를 발생시킬 것이다.\n\n예를 들어, 이전에는, `let`과 같은 로컬 변수를 재선언 했을 경우, 콘솔창에서 에러를 던진다.\n\n![image](https://user-images.githubusercontent.com/24274424/74095008-d0fbdd00-4b2d-11ea-88cc-40deaba2465b.png)\n\n이제는, 콘솔창에서 재선언이 허용된다.\n\n![image](https://user-images.githubusercontent.com/24274424/74095014-ec66e800-4b2d-11ea-84e2-41654d770014.png)\n\nChromium issue [#1004193](https://crbug.com/1004193)\n\n## WebAssembly 디버깅 향상\n\nDevTools [DWARF Debugging Standard](http://dwarfstd.org/) 지원 시작한다. 이는 DevTool안에서 우리의 소스로 단계별로 진행하거나, 중단점을 잡거나, 스택추적을 해결하는 데 도움을 준다. 이에 대한 상세한 내용은 아래 글에 소개되어 있다.\n\nGoogle Developers: [Improved WebAssembly debugging in Chrome DevTools](https://developers.google.com/web/updates/2019/12/webassembly)\n\n![image](https://user-images.githubusercontent.com/24274424/74095018-01dc1200-4b2e-11ea-808e-1cda18156298.png)\n\n## Network panel 업데이트\n\n### Request Initiator Chains in the Initiator tab\n\n중첩된 목록으로 network 요청의 initiators와 dependencies 정보를 볼 수 있다. 이는 리소스가 호출된 이유를 보거나, 특정 스크립트와 같은 리소스들로 인해 발생한 네트워크 활동을 보는 데 유용할 것이다.\n\n![image](https://user-images.githubusercontent.com/24274424/74095021-09032000-4b2e-11ea-8fd9-a08561dc5e89.png)\n\n네트워크 패널에서 [네트워크 활동을 로깅](https://developers.google.com/web/tools/chrome-devtools/network)한 후 리소스를 클릭하고 **Initiator** 탭으로 이동하여  **Request Initiator Chain**을 볼 수 있다.\n\n- *inspected resource*는 굵게 되어있다. 스크린샷 아래를 보게 되면, `https://web.dev/default-627898b5.js` 는 inspected resource이다.\n- inspected 리소스위의 리소스는 *initiators*. 스크린 샷을 보면, `https://web.dev/bootstrap.js` 는 `[https://web.dev/default-627898b5.js](https://web.dev/default-627898b5.js)` 의 initiator이다. 다른 말로, `https://web.dev/bootstrap.js` 는`https://web.dev/default-627898b5.js` 를 네트워크 요청한다.\n- The resources below the inspected 리소스 밑의 리소스는 *dependencies*이다. 스크린 샷을 보면, `[https://web.dev/chunk-f34f99f7.js](https://web.dev/chunk-f34f99f7.js)` 는  `[https://web.dev/default-627898b5.js](https://web.dev/default-627898b5.js)` 의 dependency 이다. 다른 말로,  `https://web.dev/default-627898b5.js` 는  `https://web.dev/chunk-f34f99f7.js` 를 네트워크 요청한다.\n\nInitiator와 dependency 정보는 Shift 키를 누른 상태에서 network 리소스에 올리면 볼 수 있다. [View initiators and dependencies](https://developers.google.com/web/tools/chrome-devtools/network/reference).\n\nChromium issue [#842488](https://crbug.com/842488)\n\n### Overview에서 선택된 network 요청 하이라이팅\n\n네트워크 리소스를 확인하기 위해서 클릭을 하면, Network 패널에 **Overview**에 해당 리소스 주위에 파란색 선이 생긴다. 이를 통해서 네트워크 요청이 생각보다 빠르게 또는 느리게 왔는지 확인 가능하다.\n\n![image](https://user-images.githubusercontent.com/24274424/74095028-20420d80-4b2e-11ea-874a-bfe6ec64c7ec.png)\n\nChromium issue [#988253](https://crbug.com/988253)\n\n### Network panel에서의 URL과 path 행렬\n\n**Network** 패널에서 상대경로와 전체 URL을 각각의 network 리소스 별로 새로운 **Path와** **URL** 행렬 사용이 가능하다. \n\n![image](https://user-images.githubusercontent.com/24274424/74095029-246e2b00-4b2e-11ea-9b77-89fec563c287.png)\n\n**Waterfall** 테이블 헤더 우클릭으로 새로운 **Path** 또는 **URL** 행렬을 볼 수 있다.\n\nChromium issue [#993366](https://crbug.com/993366)\n\n### Updated User-Agent strings\n\nDevTools 은 **Network Conditions** 탭에서 커스텀  User-Agent string 셋팅을 지원한다. User-Agent string은 network 리소스와 관련된 `User-Agent` HTTP header, 그리고 `navigator.userAgent` 값에 영향을 미친다. \n\n사전정의된 User-Agent string들은 최신 브라우저 버전을 반영하도록 업데이트되었다.\n\n![image](https://user-images.githubusercontent.com/24274424/74095036-4a93cb00-4b2e-11ea-97cb-4b9e106dc5d6.png)\n\n**Network Conditions 에** 접근하기 위해서, [the Command Menu](https://developers.google.com/web/tools/chrome-devtools/command-menu) 를 열고 `Network Conditions` 명령어를 실행시키면 된다.\n\nChromium issue [#1029031](https://crbug.com/1029031)\n\n## Audits 패널 업데이트\n\n### 새로운 설정 UI\n\n설정 UI는 새롭고, 반응형 디자인이며 throttling 설정 옵션이 단순화되었다. 변경에 대한 더 많은 정보는 [Audits Panel Throttling](https://github.com/GoogleChrome/lighthouse/blob/master/docs/throttling.md#devtools-audits-panel-throttling) 에 들어가서 확인할 수 있다.\n\n![image](https://user-images.githubusercontent.com/24274424/74095037-4f587f00-4b2e-11ea-8c14-b93caef94e65.png)\n\n## Coverage 탭 업데이트\n\n### Per-function 또는 per-block 커버리지 모드\n\n[Coverage tab](https://developers.google.com/web/tools/chrome-devtools/coverage)는 **per function** 또는 **per block** 로 커버리지 데이터를 수집할지 지정할 수 있는 새로운 드롭다운 메뉴를 가지고 있다.. **Per block** 커버리지는 더욱 상세하게 수집할 수 있지만, 비용이 더 든다. DevTools의 기본값은 **per function** 커버리지를 사용한다.\n\n**per function** 또는 **per block** 모드 사용여부에 따라 HTML파일에서 코드 커버리지 적용 범위가 달라진다. \n\n**per function** 모드를 사용하면, HTML 파일의 인라인 스크립트는 함수로 취급된다. 스크립트가 조금이라도 실행되면 DevTools는 전체 스크립트를 사용된 코드로 표시한다.스크립트가 전혀 실행되지 않는 경우에만 DevTools는 스크립트를 사용하지 않는 코드로 표시한다.\n\n![image](https://user-images.githubusercontent.com/24274424/74095038-52536f80-4b2e-11ea-85e7-1027ddb72abc.png)\n\n### Coverage 페이지 새로고침으로 시작해야한다.\n\n페이지 새로고침 없이 코드 커버리지를 토글링하는것은 제거되었다. 커버리지 데이터를 신뢰할 수 없기 때문이다. 예를 들어, 함수가 오래전에 실행되어 V8 가비지 컬렉션 대상이 된 경우 해당 함수가 실행되지 않은 것으로 보고될 수 있다.\n\nChromium issue [#1004203](https://crbug.com/1004203)\n\n#### Reference\n\n- [https://developers.google.com/web/updates/2019/12/devtools](https://developers.google.com/web/updates/2019/12/devtools)\n"
  },
  {
    "path": "Tool/Framework vs Library.md",
    "content": "# Framework vs Library\r\n\r\n프레임워크와 라이브러리는 많이 들어보았지만 차이점을 설명해보라고 한다면 정확히 대답을 못하기에 정리를 해보았다.\r\n\r\n먼저 프레임워크와 라이브러리의 개념에 대해 살펴보고 차이점에 대해 알아보겠다.\r\n\r\n## Framework(프레임워크)\r\n프레임워크는 Application 개발 시 코드의 품질, 필수적인 코드, 알고리즘, 암호화, 데이터베이스 연동 같은 기능들이 어느 정도 구성 되어있는 뼈대(구조)를 제공하도록 만들어진 것이다.\r\n소프트웨어에서의 프레임워크는 '소프트웨어의 특정 문제를 해결하기 위해서 상호 협력하는 클래스와 인터페이스의 집합'이라 할 수 있으며, 완성된 어플리케이션이 아니기 때문에 프로그래머는 제공된 프레임워크의 구조를 이용하여 어플리케이션을 완성해야 한다.\r\n\r\n## Library(라이브러리)\r\n라이브러리는 특정 기능에 대한 API(도구/함수)를 모은 집합을 라이브러리라고 한다.\r\n그 기능을 사용하기 위해 불러와서 호출하는 방식을 생각하면 쉽다.\r\n\r\n## Framework와 Library의 차이\r\n위의 내용으로만 봤을 때는 단순히 라이브러리가 모이면 프레임워크처럼 보일 수 있다.\r\n\r\n하지만 프레임워크와 라이브러리의 핵심적인 차이는 'Flow(흐름)에 대한 제어 권한이 어디에 있느냐'이다.\r\n\r\n프레임워크는 전체적인 흐름을 자체적으로 제어하며 프로그래머는 프레임워크 안에 필요한 코드를 작성한다. 반면에 라이브러리는 전체적인 흐름을 자체적으로 제어할 수 없으며 사용자가 흐름에 대해 제어를 하는 도중 필요한 상황에 가져다 쓰는 것이다. \r\n\r\n이 내용을 한 문장으로 정리하면 프레임워크에는 `제어의 역전(Inversion Of Control)`이 적용되어 있다는 것이다.\r\n\r\n## 제어의 역전(Inversion Of Control)\r\n\r\n**제어의 역전**이란 어떠한 일을 하도록 만들어진 프레임워크에 제어의 권한을 넘김으로써 클라이언트 코드가 신경 써야 할 것을 줄이는 전략이다. 이것을 '제어가 역전되었다'라고 한다. \r\n\r\n일반적으로 프로젝트를 생성하고 Main 함수를 만들어서 시작 지점을 형성한다. 그리고 Main 함수에서 프로그램의 흐름을 정하는 것은 프로그래머의 몫으로 우리가 어떠한 순서를 부여하느냐에 따라 흐름을 제어하는 것이 일반적인 사고이다.\r\n하지만 여기서 프레임워크는 일반적인 사고와 반대되는 모습을 보여주는데 실행의 흐름을 프레임워크 자체가 가지고 있어서 우리의 코드를 프레임워크 안에 넣어서 개발을 진행해야 한다. \r\n일반적으로 프로그래머가 가지고 있어야 하는 제어의 권한을 프레임워크에게 주었기 때문에 이를 제어의 역전이라고 말한다. \r\n\r\n다시 말해, 라이브러리는 이를 가져다가 사용하고 호출하는 측에 전적으로 주도성이 있는 반면, 프레임워크는 그 틀 안에 이미 제어 흐름에 대한 주도성을 내재하고 있다는 것이 핵심이다.\r\n프레임워크는 가져다가 사용한다는 개념보다는 거기에 들어가서 사용한다는 느낌으로 접근할 수 있다.\r\n\r\n그렇다면 대체 어떻게 프레임워크가 나의 메소드를 호출할 수 있는가에 대한 의문이 생긴다.\r\n\r\n제어를 역전시키는 가장 쉽게 생각할 수 있는 접근 방법은 프레임워크의 [event, delegate](https://blog.hexabrain.net/151)에 나의 메소드를 등록시키는 것이다.\r\n<!--\r\nevent는 '특정 사건이 벌어지면 알리는 메시지'라고 할 수 있다. delegate를 사용하여 event처리를 한다.\r\ndelegate는 한마디로 말해서 대리자라고 말할 수 있다. event가 발생하면 delegate를 이용해서 발생한 event처리에 대한 메소드를 호출한다. \r\n-->\r\n\r\n예를 들면 사용자로부터 몇 가지 정보를 얻는 커멘드라인 프로그램을 작성한다고 하면 다음과 같다.\r\n\r\n~~~ c\r\n  puts 'What is your name?'\r\n  name = gets\r\n  process_name(name)\r\n  puts 'What is your quest?'\r\n  quest = gets\r\n  process_quest(quest)\r\n~~~\r\n\r\n이 상호 작용에서 언제 질문을 할 것인가? 응답을 언제 읽을 것인가? 이 결과들을 언제 처리할 것인가?를 개발자가 결정한다. 즉, 개발자가 코드를 제어하고 있다.\r\n\r\n그러나, 윈도우시스템을 위한 작업을 한다면 다음과 같다. 다음의 예시는 파이썬의 TKinter 프레임워크를 사용한 예시이다.\r\n~~~ py\r\nrequire 'tk'\r\n  root = TkRoot.new() //루트 윈도우 생성\r\n  name_label = TkLabel.new() {text \"What is Your Name?\"} // 라벨 위젯\r\n  name_label.pack // 위젯을 적당한 곳에 위치시킨다.\r\n  name = TkEntry.new(root).pack //입력을 받을 위젯을 생성하고 위치시킨다.\r\n  name.bind(\"FocusOut\") {process_name(name)} //위젯 밖으로 나갔을 때 함수 실행\r\n  quest_label = TkLabel.new() {text \"What is Your Quest?\"}\r\n  quest_label.pack\r\n  quest = TkEntry.new(root).pack\r\n  quest.bind(\"FocusOut\") {process_quest(quest)}\r\n  Tk.mainloop() //다양한 이벤트로부터 오는 메시지를 받고 전달\r\n~~~\r\n\r\n커맨드 라인 프로그램에서는 `process_name` 과 `process_quest` 메소드를 호출한다.\r\n하지만 윈도우 시스템에서는 폼을 만들 때의 바인딩을 기반으로 개발자가 정의한 메소드를 호출한다. 개발자가 주도적으로 메소드를 호출하는 것이 아니라 프레임워크가 개발자의 메소드를 호출해 실행한다. 이 현상을 제어의 역전이라고 한다.\r\n\r\n## 정리\r\n간단히 정리하자면 라이브러리는 함수나 기능 모음을 가져다가 쓰는 것이고, 프레임워크는 프레임워크가 실행되다가 중간중간에 특정 비지니스나 특정 구현 단에서만 사용자의 코드를 사용하는 형태라고 할 수 있다.\r\n라이브러리와는 달리 프레임워크는 프로그래밍할 규칙이 정해져 있다.\r\n\r\n아직 개념이 모호할 것 같아서 예를 들어보겠다.  \r\n프레임워크는 공장과 같다. 옷 공장, 신발 공장, 만두 공장 등 공장마다 서로 다른 제품을 생산한다. 각자 목적에 맞는 공장들이 있다.\r\n제품을 만들기 위해 어떤 재료를 사용하냐에 따라 제품의 품질, 디자인 등 여러 면이 달라진다. 하지만 공장이라는 개념만 봤을 경우 재료를 준비하고 가공하고 생산하는 일은 같다. 여기서 공장은 프레임워크이고 재료는 라이브러리이다. \r\n\r\n만약, 웹 어플리케이션을 구축한다고 하자. 웹 어플리케이션을 구축하려면 웹에 맞는 환경설정과 DB와 연동하기 위해 무엇을 써넣어야 하는지, 소스 파일을 어느 위치에 넣어야 하는지 정해져 있다. 이렇게 필수적으로 구현해야 하는 코드를 삽입함으로써 프레임워크는 흐름을 주도적으로 제어할 수 있다. 개발자는 그 흐름 안에서 필요한 기능을 넣어서 구현한다. \r\n이것이 프레임워크를 사용하는 것이고, 그 안에 필요한 기능을 넣는 것이 라이브러리이다. \r\n\r\n프레임워크를 사용한다면 라이브러리만을 사용해서 만드는 것보다 훨씬 비용과 시간이 적게 든다는 장점이 있다. \r\n\r\n\r\n#### Reference\r\n- [프레임워크와 라이브러이의 차이](https://mangkyu.tistory.com/4)\r\n- [제어의 역전](https://webclub.tistory.com/458)\r\n- [제어의 역전 예](https://vandbt.tistory.com/43)\r\n- [Tkinter](http://pythonstudy.xyz/python/article/120-Tkinter-소개)\r\n"
  },
  {
    "path": "Tool/Package Manager.md",
    "content": "# Package Manager\n\njavascript의 npm, java의 maven, gradle, php의 composer, python의 pip등 외부 라이브러리를 관리하기 위해서 사용했던 Package Manager에 대해 알아보자.\n\n## Package Manager란 무엇인가?\n\n패키지 관리자(Package Manager)란 프로젝트 환경을 구축하고 외부 라이브러리를 쉽게 사용할 수 있도록 관리해주는 툴이다. 하나의 서비스를 만드려고 할 때, A부터 Z까지 모든 것을 구현하는 것이 아니라 이미 잘 구현되어 있는 라이브러리가 있다면 그것을 프로젝트에 가져다 쓰면 된다. 반대로 내가 만든 프로젝트를 \"Package\"화 해서 다른 사람들을 위해 공유할 수도 있다.\n\n## 대표적인 Package Manager\n\n### 1. Python\n\n**Managers**: `pip` / `conda`\n\n**Repository**: `PyPI`\n\npip, conda는 Python에서 사용할 수 있는 Package Manager이다. 이 둘은 비슷한 개념으로 많이 사용되는데 명확하게는 서로 다른 목적을 가지고 있다. 다음 표를 살펴보자. 자세한 설명은 [이곳](https://www.anaconda.com/blog/understanding-conda-and-pip)을 참고하면 된다.\n\n![Comparison of conda and](https://user-images.githubusercontent.com/43839938/103164402-2c21e580-484e-11eb-9892-320d23658459.png)\n\n\npip는 python software에 한정되어 있는 반면 conda는 C, C++ libraries 등도 포괄한다.\n\n또 하나의 핵심 차이는 두 개 모두 각 프로젝트 단위로 라이브러리를 설치하도록 하는 '가상환경' 을 사용할 수 있지만 접근 방식이 조금 다르다는 점이다. conda의 경우 '가상환경'이 내장되어 있지만, pip는 virtualenv등을 따로 설치해서 사용해야 한다.\n\n> '가상환경'에 대해서는 [이곳](https://medium.com/@dan_kim/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EC%B4%88%EC%8B%AC%EC%9E%90%EB%A5%BC-%EC%9C%84%ED%95%9C-pip-%EA%B7%B8%EB%A6%AC%EA%B3%A0-virtualenv-%EC%86%8C%EA%B0%9C-a53512fab3c2)을 살펴보자.\n\n`conda`와 `pip`를 결합해서 사용하는 경우도 존재한다. `conda` 의 Repository인 [Anaconda](https://www.anaconda.com/)에서는 데이터 과학, 기계 학습 등 AI 프레임워크를 포함한 1,500개 이상의 패키지를 제공하기 때문에 `conda`를 사용한다. 그럼에도 `pip`와 결합해서 사용하는 이유는 Anaconda에서 제공하지 않는 다른 패키지들이 [PyPI](https://pypi.org/)(Python Package Index)에 무수히 많기 때문이다. \n\n### 2. Java\n\n**Managers**: `Maven`, `Gradle`\n\n**Repository**: `Maven Central`\n\n Java의 Package Managers는(Build Tool이라고도 불린다.) [`Maven`](https://maven.apache.org/), [`Gradle`](https://gradle.org/)이 있다. `Maven`은 pom.xml을 이용한 정형화된 빌드 시스템이다. `Gradle`은 `Maven`의 단점을 보완하고자 나온 것인데 `Gradle` 공식 사이트에 이 둘에 대한 차이점이 잘 설명되어 있다. [이곳](https://gradle.org/maven-vs-gradle/)을 참고하자. `Maven`과 비교했을 때 `Gradle`의 대표적인 장점은 다음과 같다.\n\n**1. XML로 정의하기 어려웠던 동적인 요소를 Groovy 스크립트로 표현한다.** \n> Maven, Gradle 문법 차이\n1) `Maven`의 pom.xml 예시\n\n```xml\n    <?xml version=\"1.0\" encoding=\"UTF-8\"?>\n    <project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n       <modelVersion>4.0.0</modelVersion>\n\n       <groupId>com.example</groupId>\n       <artifactId>demo-maven</artifactId>\n       <version>0.0.1-SNAPSHOT</version>\n       <packaging>jar</packaging>\n\n       <name>demo-maven</name>\n       <description>Demo project for Spring Boot</description>\n\n       <parent>\n          <groupId>org.springframework.boot</groupId>\n          <artifactId>spring-boot-starter-parent</artifactId>\n          <version>1.5.4.RELEASE</version>\n          <relativePath/> <!-- lookup parent from repository -->\n       </parent>\n\n       <properties>\n          <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n          <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n          <java.version>1.8</java.version>\n       </properties>\n\n       <dependencies>\n          <dependency>\n             <groupId>org.springframework.boot</groupId>\n             <artifactId>spring-boot-starter</artifactId>\n          </dependency>\n\n          <dependency>\n             <groupId>org.springframework.boot</groupId>\n             <artifactId>spring-boot-starter-test</artifactId>\n             <scope>test</scope>\n          </dependency>\n       </dependencies>\n\n       <build>\n          <plugins>\n             <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n             </plugin>\n          </plugins>\n       </build>\n\n    </project>\n```\n\n2) `Gradle`의 build.gradle 예시 - `Gradle`역시 `Maven Central`을 레포지토리로 한다.\n\n```groovy\n    buildscript {\n        ext {\n            springBootVersion = '1.5.4.RELEASE'\n        }\n        repositories {\n            mavenCentral()\n        }\n        dependencies {\n            classpath(\"org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}\")\n        }\n    }\n\n    apply plugin: 'java'\n    apply plugin: 'idea'\n    apply plugin: 'org.springframework.boot'\n\n    version = '0.0.1-SNAPSHOT'\n    sourceCompatibility = 1.8\n\n    repositories {\n        mavenCentral()\n    }\n\n    dependencies {\n        compile('org.springframework.boot:spring-boot-starter')\n        testCompile('org.springframework.boot:spring-boot-starter-test')\n    }\n```\n    \n**2. 빌드 시 속도가 더 빠르다.**(`Gradle`은 캐시를 사용하기 때문에 반복해서 빌드하게 되면 차이가 더 커진다.) \n\n**3. 기타**   \nJava의 Repository(Maven Central)에는 개인이 만든 Package를 추가하는 과정이 [복잡하다](https://jojoldu.tistory.com/161). 따라서 Nexus와 같은 사설 Repository를 [사용하기도](https://dev-youngjun.tistory.com/105) 한다.\n\n### 3. JavaScript\n\n**Manager**: `npm`\n\n**Repository**: `npm`\n\n[`npm`](https://www.npmjs.com/)(Node Package Manager)은 JavaScript의 Package Manager이다. 이는 세계에서 가장 큰 소프트웨어 Repository이기도 하다. npm은 jQuery, Bootstrap, React, Angular 등과 같은 인기 있는 Package들을 갖고 있다. Github 저장소를 npm과 연결하면 자신의 프로젝트를 npm에 등록할 수도 있다. JavaScript 프론트엔드든 Node.js 백엔드든 어떤 환경에서도 npm Package를 동시에 사용할 수 있다.\n\ncf. 패키지 매니저, `yarn`  \n`yarn`은 `npm`의 일관성, 보안, 성능과 관련한 이슈를 개선하고자 페이스북에서 만든 패키지 관리자이다. [이곳](https://classic.yarnpkg.com/en/)을 참고하자.\n\n### 4. PHP\n\n**Manager**: `Composer`\n\n**Repository**: `Packagist`\n\nPHP의 Package Manager는 [`Composer`](https://getcomposer.org/), Repository는 [`Packagist`](https://packagist.org/)이다. npm 과 마찬가지로 Github에 Packagist를 연결하면 해당 레포지토리에 원활하게 배포할 수 있다.\n\n## Try it!\n\nPackage Manager, Repository를 통해서 여러 외부 라이브러리들을 사용해보았다면, 이제 여러분이 만들어 볼 차례다!\n\n종속성, 패키지 이름, 작성자, 태그 / 키워드 및 버전 번호 등을 지정해서 Package를 만들고 Repository에 등록해보자. 다른 사람들이 여러분들의 라이브러리를 사용한다는 것, 얼마나 아름다운가? 이로써 개발자는 Package를 사용하고 구현하는 방법에 대해 생각할 수 있고 더 나은 재사용 가능한 Package를 생성할 수 있도록 생각을 넓혀 줄 것이다. 파이팅!\n\n### Reference\n\n- [What is a package manager and why should you use one?](https://blog.idrsolutions.com/2018/07/what-is-a-package-manager-and-why-should-you-use-one/)\n- [Understanding Conda and Pip](https://www.anaconda.com/blog/understanding-conda-and-pip)\n- [Maven vs Gradle](https://bkim.tistory.com/13)\n"
  },
  {
    "path": "Typescript/인터페이스(Interface).md",
    "content": "# 인터페이스(Interface)\n\n## 인터페이스는 타입으로 사용할 수 있다.\n\n`Typescript`의 인터페이스는 변수의 타입으로 활용할 수 있다. 즉, 인터페이스에 지정된 프로퍼티를 가진 변수로 지정할 수 있다.\n\n```ts\ninterface Developer {\n    id : number;\n    name : string;\n    lang : string;\n    skill : string;\n}\n\nlet developer : Developer;\n\ndeveoper = { id : 1, name : 'BKJang', lang: 'Korean', skill : 'Typescript'};\n```\n\n위와 같이 변수의 타입으로서 인터페이스를 활용할 수 있다. 단, 해당 인터페이스 타입의 변수를 선언하여 값을 초기화 할 때는 해당 인터페이스를 준수하여야 한다.\n\n<br/>\n\n## 인터페이스는 함수의 타입으로 사용할 수 있다.\n\n함수의 인터페이스는 타입이 선언된 파라미터 목록과 반환 타입을 정의한다. `Tyepscript`의 특성상 함수 인터페이스를 구현하는 함수는 인터페이스를 준수하여야 한다.\n\n```ts\ninterface helloWorld {\n    (name : string) : string;\n}\n\nconst helloWorld : helloWorld = function (name : string) {\n    return `${name} Hello!`;\n}\n\nconsole.log(helloWorld('BKJang')) // BKJang Hello!\n```\n\n<br/>\n\n## 클래스는 인터페이스를 구현할 수 있다.\n\n`Typescript`에서 클래스가 인터페이스의 구현체가 되는 것은 `Java`와 굉장히 유사하다. 즉, 클래스가 인터페이스를 `implements`하면 지정된 인터페이스를 반드시 구현하여 한다.<br/>\n인터페이스는 메서드도 포함할 수 있다. 단, 모든 메서드는 추상 메서드이어야 한다. 클래스는 인터페이스에서 정의한 프로퍼티와 추상 메서드를 반드시 구현하여야 한다.\n\n```ts\ninterface InterDeveloper {\n    name : string;\n    lang : string;\n    printInfo() : void;\n}\n\nclass Developer implements InterDeveloper {\n    constructor (\n        public name: string,\n        public lang: string\n    ) { }\n\n    printInfo() {\n        console.log(`Developer : ${this.name} / ${this.lang}`);\n    }\n}\n\nfunction hello(devloper: InterDeveloper): void {\n  devloper.printInfo();\n}\n\nconst bkjang = new Developer('BKJang', 'Korean');\nhello(bkjang); // Developer : BKJang / Korean\n```\n\n<br/>\n\n## 인터페이스는 프로퍼티를 선택적 프로퍼티를 선언할 수 있다.\n\n`Typescript`의 인터페이스에서 구현된 프로퍼티는 반드시 인터페이스의 형식을 준수하여야 하지만, `?`키워드를 통해 선택적으로 프로퍼티의 구현을 정할 수 있다.\n\n```ts\ninterface Developer {\n    id : number;\n    name : string;\n    lang : string;\n    skill? : string;\n}\n\nconst bkjang: Developer = {\n    id : 1,\n    name : 'BKJang',\n    lang : 'Korean'\n}\n\nconsole.log(bkjang); // Developer { id : 1, name: BKJang, lang: Korean }\n```\n\n<br/>\n\n## 덕 타이핑 (Duck Typing)\n\n`TypeScript`에서는 해당 인터페이스에서 정의한 프로퍼티나 메서드를 가지고 있다면 그 인터페이스를 구현한 것으로 인정한다. 이것을 **덕 타이핑(duck typing)** 또는 **구조적 타이핑(structural typing)** 이라 한다.\n\n```ts\ninterface Developer {\n    helloworld() : void;    \n}\n\nclass BKJang implements Developer { // 3\n    helloworld() {\n        console.log('BKJang Hello');\n    }\n}\n\nclass SHJo {\n    helloworld() {\n        console.log('SHJo Hello');\n    }\n}\n\nfunction sayHello(helloworld: Developer): void { // 2\n  helloworld.helloworld();\n}\n\nsayHello(new BKJang()); // BKJang Hello\nsayHello(new SHJo()); // SHJo Hello\n```\n\n위의 코드를 보면 `SHJo`클래스는 인터페이스를 상속하고 있지 않지만 `sayHello`메서드를 실행했을 때 정상적으로 작동한다. 이처럼 인터페이스에서 구현된 메서드나 프로퍼티를 가지고 있다면 인터페이스를 구현한 것으로 인정하고 인터페이스의 구현체로서 해당 메서드나 프로퍼티를 실행한다. 이를 **덕 타이핑(Duck Typing)** 이라고 한다.\n\n인터페이스는 개발 단계에서 도움을 주기 위해 제공되는 기능으로 자바스크립트의 표준이 아니다. 따라서 `Typescript`파일을 트랜스파일링하면 인터페이스 코드는 삭제된다.\n\n아래는 위의 코드를 Javascript로 컴파일한 코드이며 인터페이스 코드가 삭제된 것을 확인할 수 있다.\n\n```js\nvar BKJang = /** @class */ (function () {\n    function BKJang() {\n    }\n    BKJang.prototype.helloworld = function () {\n        console.log('BKJang Hello');\n    };\n    return BKJang;\n}());\nvar SHJo = /** @class */ (function () {\n    function SHJo() {\n    }\n    SHJo.prototype.helloworld = function () {\n        console.log('SHJo Hello');\n    };\n    return SHJo;\n}());\nfunction sayHello(helloworld) {\n    helloworld.helloworld();\n}\nsayHello(new BKJang()); // BKJang Hello\nsayHello(new SHJo()); // SHJo Hello\n\n```\n\n---\n\n#### Reference\n\n- [Poiemaweb - 인터페이스](https://poiemaweb.com/typescript-interface)\n- [Typescript : class vs interface](https://medium.com/front-end-weekly/typescript-class-vs-interface-99c0ae1c2136)\n- [Classes vs Interfaces in TypeScript](https://ultimatecourses.com/blog/classes-vs-interfaces-in-typescript)\n"
  },
  {
    "path": "Typescript/정적 타이핑.md",
    "content": "# 정적 타이핑\n\n## Typescript의 등장\n\n기존에 사용하던 `Javascript`는 대표적인 동적 타이핑 언어다. 즉, 타입이 정적이지 않기 때문에 정적 타입 언어인 `Java`나 `C`와 같은 C-Family 언어처럼 좀 더 자유롭게 사용할 수 있다. 물론, 이 부분에 대해서 긍정적인 사람도 있고 부정적인 사람도 있다.\n\n개인적인 생각으로 `Javascript`을 이용하여 큰 규모의 애플리케이션을 개발하면 동적 타입이라는 특성이 불편하게 다가올 때가 많았다. 예를 들어, `string`으로 넘어오는 숫자를 `number`타입으로 명시적 변환을 해야 하는 것이 그 예다.\n\n물론, `Typescript`에는 기존의 `ES5`와 `ES6`에서 제공하던 기능보다 좀 더 많은 기능을 제공하고 있지만, 가장 기본적이고 큰 차이점은 `C-Family` 언어와 같이 정적 타입의 언어라는 것이다.\n\n`ES5`와 `ES6`에서 사용하던 기능들을 그대로 사용하면서도, 정적 타이핑을 제공하고 그에 수반되는 추가적인 기능들까지 제공한다. 덕분에 타입에 대한 에러를 줄이면서 개발할 수 있는 장점이 있다.\n\n<br/>\n\n## 타입의 종류\n\n기존에 `Javascript`에서 사용하던 타입을 그대로 사용하면서 `Typescript`자체적으로 추가적인 타입들을 제공한다.\n\n<br/>\n\n![typescript_type](../assets/images/typescript_type.png)\n\n<br/>\n\n```ts\n// boolean\nconst isTs: boolean = true;\n\n// null\nconst n: null = null;\n\n// undefined\nconst u: undefined = undefined;\n\n// number\nconst num: number = 6;\n\n// string\nconst name = 'BKJang';\nconst greeting: string = `Hello ${name}`;\n\n// object\nconst obj: object = {};\n\n// array\nconst anyList: any[] = [1, 'two', true];\nconst numList: number[] = [1, 2, 3];\n\n// tuple : 고정된 요소수 만큼의 타입을 미리 선언후 배열을 표현\nconst tuple: [string, number];\ntuple = ['hello', 10]; // OK\ntuple = [10, 'hello']; // Error\ntuple = ['hello', 10, 'world', 100]; // OK\ntuple = ['hello', 10, 'world']; // OK\ntuple.push(true); // Error\n\n// enum : 열거형은 숫자값 집합에 이름을 지정한 것이다.\nenum Color1 {Red, Green, Blue};\nconst c1: Color1 = Color1.Green;\n\nconsole.log(c1); // 1\n\nenum Color2 {Red = 1, Green, Blue};\nconst c2: Color2 = Color2.Green;\n\nconsole.log(c2); // 2\n\nenum Color3 {Red = 1, Green = 2, Blue = 4};\nconst c3: Color3 = Color3.Blue;\n\nconsole.log(c3); // 4\n\n/*\nany: var로 선언한 데이터와 동일하다.\n*/\nconst anyData: any = 5;\nanyData = `this is string type`;\nanyData = true;\n\n// void\nfunction printHello(): void {\n  console.log(\"Hello World\");\n}\n\n/*\nnever : never는 함수 표현식의 리턴 타입이거나, 항상 예외를 던지는 화살표 함수 표현식이거나, 리턴하지 않는 표현식이다. \n*/\n\n// Function returning never must have unreachable end point\nfunction error(message: string): never {\n  throw new Error(message);\n}\n\n// Inferred return type is never\nfunction fail() {\n    return error(\"Something failed\");\n}\n\n// Function returning never must have unreachable end point\nfunction infiniteLoop(): never {\n    while (true) {\n    }\n}\n```\n\n위와 같이 `Typescript`의 타입은 모두 소문자다. `Typescript`에서 만약 `string`이 아닌 `String`으로 타입을 선언하면 String 래퍼 객체가 타입으로 지정된다. 즉, 객체도 타입이 될 수 있다.(`Java`에서 `Generics`를 생각하면 쉽다. `Typescript`에도 `Generics`이 있기 때문이다.)\n\n```ts\nlet stringValue: string;\nstringValue = 'Hello'; //It's ok\nstringValue = new String('Hello'); //Error\n\nlet stringObj: String;\n\nstringObj = 'Hello'; //It's ok\nstringObj = new String('Hello'); //It's ok\n```\n\n```ts\n// Date 타입\nconst now: Date = new Date();\n\n// HTMLElement 타입\nconst elem: HTMLElement = document.getElementById('id');\n\nclass Person { }\n// Person 타입\nconst person: Person = new Person();\n```\n\n<br/>\n\n## 함수 매개변수의 타입\n\n`Typescript`에서는 함수의 매개변수도 타입을 지정하여 받을 수 있다. 지정한 타입의 매개변수가 아니라면 에러를 출력하기 때문에 복잡한 애플리케이션에서도 타입 에러를 줄여서 개발할 수 있다.\n\n```ts\nfunction person(name: string, age: number): string {\n    return `name : ${name}, age : ${age}`;\n}\n\nconsole.log(person('BKJang', 27)); //name : BKJang, age : 27\nconsole.log(person('BKJang', '27')); //Type error\n```\n\n<br/>\n\n## 타입 추론\n\n`Typescript`에서 타입의 선언을 만약 생략한다면 최초에 할당된 값의 타입에 따라 타입이 정해진다. 이에 따라 이미 결정된 타입의 변수에 다른 값을 할당하면 에러가 발생한다. 이를 **타입 추론**이라고 한다.\n\n```ts\nlet value = 6; //타입 추론에 의하여 value 변수는 number 타입의 변수로 선언된다.\n\nvalue = 'Hello'; //Type error\n```\n\n만약 `Javascript`와 같은 동적 타입의 언어라면 위와 같이 `Hello`라는 새로운 값을 할당했을 때 에러가 발생하지 않을 것이다. 하지만 `Typescript`에서는 타입 추론에 의해 이미 `value`가 `number`타입으로 정해졌기 때문에 `number`가 아닌 다른 타입의 값을 할당하면 타입 에러가 발생한다.\n\n```ts\nlet value;\n\nvalue = 'Hello'; //It's ok\nvalue = 6; //It's ok\n```\n\n이전 예시와 다르게 `value` 변수를 최초에 선언할 때 값을 할당하지 않으면 `any`타입으로 정해진다. 때문에 `var`와 같이 동적으로 값을 할당할 수 있는 상태가 된다. <br/>\n하지만 `any` 타입의 선언 방식은 `Typescript`를 사용하는 의미가 없어지기 때문에 사용하지 않는 것이 좋다.\n\n<br/>\n\n---\n\n#### Reference\n\n- [Poiemaweb - 정적타이핑](https://poiemaweb.com/typescript-typing)\n- [Typescript hand book - Basic Types](http://www.typescriptlang.org/docs/handbook/basic-types.html)\n- [Typescript hand book - Type Inference](https://www.typescriptlang.org/docs/handbook/type-inference.html)"
  },
  {
    "path": "Typescript/제네릭(Generic).md",
    "content": "# 제네릭(Genenric)\n\n## 제네릭을 사용하는 이유\n\n제네릭(Generic)이란 데이터의 타입(data type)을 일반화한다(generalize)는 것을 의미한다.<br/>\n제네릭은 클래스나 함수에서 사용할 데이터 타입을 미리 지정하는 방법이다.\n\n제네릭을 사용하여 타입을 미리 지정하면 다음과 같은 장점을 얻을 수 있다.\n\n- 클래스나 함수 내부에서 사용되는 데이터의 타입 안정성을 높일 수 있다.\n- 반환 값에 대한 타입 변환 및 타입 검사에 들어가는 노력을 줄일 수 있다.\n\n<br/>\n\n## Javascript vs Typescript\n\n기존에 `Javascript`에서 Queue를 구현하는 클래스를 작성하면 다음과 같이 작성할 수 있다.\n\n```js\nclass NumberQueue {\n    constructor(arr) {\n        this.arr = arr;\n    }\n\n    push(item) {\n        this.arr.push(item);\n    }\n\n    pop() {\n        return this.arr.shift();\n    }\n}\n\nconst queue = new NumberQueue([]);\n\nqueue.push(1);\nqueue.push('2');\n\nconsole.log(queue.pop().toFixed());\nconsole.log(queue.pop().toFixed());\n``` \n\n위와 같이 `Javascript`에서 `NumberQueue`클래스를 작성하고 결과 값을 출력한다면 어떻게 될까?\n\n2번째 값을 출력하려고 할 때 `string`타입에는 `toFixed()`함수가 없기 때문에 `TypeError`가 발생한다. \n\n위와 같은 코드를 안짜면 된다고 생각할 수 있다. 하지만 애플리케이션을 만드는 과정에서 서버에서 준 데이터를 가지고 코딩을 해야한다거나 코드가 복잡해진다거나 하면 충분히 일어날 수 있는 실수다.\n\n`Typescript`로 위의 코드를 수정하면 다음과 같다.\n\n```ts\nclass NumberQueue {\n    protected arr:number[] = [];\n\n    push(item: number) {\n        this.arr.push(item);\n    }\n\n    pop(): number {\n        return this.arr.shift();\n    }\n}\n\nconst queue = new NumberQueue();\n\nqueue.push(1);\nqueue.push('2');\n\nconsole.log(queue.pop().toFixed());\nconsole.log(queue.pop().toFixed());\n```\n\n위와 같이 클래스를 작성한다면 `Argument of type '\"2\"' is not assignable to parameter of type 'number'.`과 같은 에러를 사전에 감지하고 수정할 수 있게 된다.\n\n하지만 위와 같이 작성했을 때 약간의 문제가 있다.\n\n`Queue`는 굉장히 일반적인 개념이기 때문에 위와 같이 작성하면 모든 타입의 `Queue`클래스를 작성해줘야 한다. `NumberQueue`, `StringQueue` 등과 같이 말이다. 즉, 재사용성이 떨어지게 된다.\n\n이럴 때 사용할 수 있는 것이 **제네릭(Generic)** 이다.\n\n<br/>\n\n## 제네릭(Generic)의 활용\n\n제네릭은 선언 시점이 아니라 생성 시점에 타입을 명시하여 하나의 타입만이 아닌 다양한 타입을 사용할 수 있도록 하는 기법이다.<br/> 즉, 한 번의 선언으로 다양한 타입으로 재사용이 가능해진다.\n\n```ts\nclass Queue<T> {\n    protected arr: Array<T> = [];\n  \n    push(item: T) {\n      this.arr.push(item);\n    }\n  \n    pop(): T {\n      return this.arr.shift();\n    }\n}\n  \nconst numberQueue = new Queue<number>();\n  \nnumberQueue.push(1);\nnumberQueue.push(2);\n  \nconsole.log(numberQueue.pop().toFixed()); //1\nconsole.log(numberQueue.pop().toFixed()); //2\n  \nconst stringQueue = new Queue<string>();\n  \nstringQueue.push('BKJang');\nstringQueue.push('Hello');\n  \nconsole.log(stringQueue.pop().toUpperCase()); //BKJang\nconsole.log(stringQueue.pop().toUpperCase()); //Hello\n  \nconst objQueue = new Queue<{name: string, age: number}>();\n  \nobjQueue.push({name: 'BKJang', age: 27}); \nobjQueue.push({name: 'JHKim', age: 25});\n  \nconsole.log(objQueue.pop()); //27\nconsole.log(objQueue.pop()); //25\n```\n\n위의 코드를 보면 `T`라는 것을 볼 수 있는데 이는 제네릭을 선언할 때 `Typescript`에서 뿐만이 아니라 다른 언어에서도 관용적으로 사용되는 표현이다. `T`는 타입 파라미터(Type Parameter)라고 한다.\n\n제네릭을 사용하면 위와 같이 `Queue`클래스 하나만 작성해두고 `number`든 `string`이든 `object`든 모든 타입에 대해서 재사용이 가능해진다.\n\n### 함수에서의 제네릭(Generic)\n\n함수도 마찬가지로 제네릭을 사용할 수 있으며 함수는 인수의 타입에 의해 매개변수의 타입도 결정된다.\n\n```ts\nfunction foo<T>(arr: T[]): T[] {\n    return { ...arr };\n}\n\nconsole.log(foo([1, 2, 3, 4, 5])); //{ '0': 1, '1': 2, '2': 3, '3': 4, '4': 5 }\nconsole.log(foo(['a', 'b', 'c'])); //{ '0': 'a', '1': 'b', '2': 'c' }\n```\n\n`foo`함수는 배열을 객체로 변환하는 함수이다. 다양한 타입의 배열을 인자로 전달받아 매개변수의 타입을 결정한다.\n\n참고로 화살표 함수를 사용하여 선언할 때는 다음과 같이 선언할 수 있다.\n\n```ts\nconst foo = <T> (arr: T[]) => {\n    return { ...arr };\n}\n```\n\n<br/>\n\n---\n\n#### Reference\n\n- [Poiemaweb - 제네릭](https://poiemaweb.com/typescript-generic)\n- [Typescript hand book - Generic](https://www.typescriptlang.org/docs/handbook/generics.html)\n"
  },
  {
    "path": "Typescript/클래스(class).md",
    "content": "# 클래스(class)\n\n## ES6 class vs Typescript class\n\n`Typescript`에서 `class`는 `ES6`가 도입되며 등장한 `class`의 개념과 비슷하지만 `ES6`의 `class`에서 제공하는 기능을 포함하는 동시에 좀 더 확장된 기능을 제공하고 있다.\n\n```js\nclass Developer {\n    constructor(name, lang) {\n        this.name = name;\n        this.lang = lang;\n    }\n\n    printPersonalInfo() {\n        console.log(`${this.name}'s main programming language is ${this.lang}`);\n    }\n}\n```\n\n```ts\nclass Developer {\n    name : string;\n    lang : string;\n\n    constructor(name: string, lang: string) {\n        this.name = name;\n        this.lang = lang;\n    }\n\n    printPersonalInfo() {\n        console.log(`${this.name}'s main programming language is ${this.lang}`);\n    }\n}\n\nconst bkjang = new Developer('BKJang', 'Typescript');\nbkjang.printPersonalInfo(); // BKJang's main programming language is Typescript\n```\n\n위의 소스에서 볼 수 있듯이 `Typescript`에서는 `class`를 정의할 때 `ES6`와 다르게 클래스 몸체에 클래스 프로퍼티를 사전 선언하여야 한다.\n\n<br/>\n\n## 접근 제어자\n\n`Typescript`에서 제공하는 접근 제어자는 `public`, `protected`, `private`이 있다.\n\n`Typescript`의 default 접근 제어자는 `public`이다. 따라서 자식 클래스와 클래스의 인스턴스에서도 프로퍼티와 메서드에 접근하길 원하면 일반적으로 접근제어자를 생략한다.\n\n각각의 접근 제어자는 아래와 같은 접근 가능성을 가진다.\n\n<br/>\n\n![typescript_access_modifier](../assets/images/typescript_access_modifier.png)\n\n<br/>\n\n```ts\nclass Parent {\n    public x : string;\n    protected y : string;\n    private z : string;\n\n    constructor(x: string, y: string, z: string) {\n        this.x = x;\n        this.y = y;\n        this.z = z;\n    }\n}\n\nconst parent = new Parent('x', 'y', 'z');\n\n// 1. 클래스의 인스턴스\nconsole.log(parent.x); // x\n\nconsole.log(parent.y); // error\n\nconsole.log(parent.z); // error\n```\n\n```ts\nclass Child extends Parent {\n    constructor(x: string, y: string, z: string) {\n        super(x, y, z);\n    }\n\n    // 2. 자식 클래스에서의 public\n    console.log(x); // x\n\n    // 3. 자식 클래스에서의 protected\n    console.log(y); // y\n\n    // 4. 자식 클래스에서의 private\n    console.log(z); // error\n}\n```\n\n### 생성자 매개변수에 접근 제어자 적용\n\n생성자의 매개변수에서도 마찬가지로 접근 제어자를 적용할 수 있다. 접근 제어자가 적용된 매개변수는 생성자 내부에서 별도의 초기화 과정이 없어도 자동으로 초기화 과정이 수행된다.\n\n생성자의 매개변수에는 `public`과 `private` 접근 제어자가 사용되며 특성은 위에서 설명한 것과 동일하다.\n\n```ts\nclass Person {\n    constructor(public name: string, private age: number) { }\n}\n\nconst bkjang = new Person('BKJang', '27');\n\nconsole.log(bkjang); // Person { name: 'BKJang', age: 27 }\n\nconsole.log(bkjang.name); // 'BKJang'\n\n// private으로 선언된 생성자의 매개변수는 클래스 외부에서 접근할 수 없다.\nconsole.log(bkjang.age); // error\n```\n\n생성자의 매개변수에 접근 제어자를 선언하지 않으면 생성자 매개변수는 생성자 내부에서만 유효한 지역변수가 되기 떄문에 생성자 외부에서 참조가 불가능하다. (클래스 내부에서도 생성자의 외부라면 접근이 불가하다.)\n\n```ts\nclass Foo {\n    constructor(x: string) { }\n}\n\nconst foo = new Foo('BKJang');\nconsole.log(foo); // Foo {}\n```\n\n<br/>\n\n## readonly\n\n`Typescript`에서는 `readonly`키워드를 제공하고 있다. 키워드의 이름만 보면 읽기 전용이라는 느낌이 든다. 즉, 기존 `Javascript`의 `const`와 다를게 없어 보이지만 `readonly`는 생성자 내에서만 값을 할당할 수 있다. 일반적으로 상수 선언에 많이 사용된다.\n\n```ts\nclass Person {\n    private readonly MAX_AGE: number;\n\n    constructor() {\n        this.MAX_AGE = 30;\n    }\n\n    setMaxAge() {\n        this.MAX_AGE = 20; // Cannot assign to 'MAX_AGE' because it is a constant or a read-only property.\n        console.log(this.MAX_AGE); // 30\n    }\n}\n\nconst person = new Person();\n\nperson.setMaxAge();\n```\n\n<br/>\n\n## static\n\n`Typescript`에서 제공하는 `static` 키워드는 `ES6`와 마찬가지로 인스턴스 명이 아닌 `class`명으로 접근한다. 즉, 인스턴스를 생성하지 않아도 접근할 수 있다.\n\n```js\nclass ES6 {\n    constructor() { }\n\n    static helloWorld() {\n        console.log('Hello ES6');\n    }\n}\n\nconst es6 = new ES6();\n\nES6.helloWorld(); // Hello ES6\nes6.helloWorld(); // Uncaught TypeError: es6.helloWorld is not a function\n```\n\n단, `Typescript`에서는 `static`키워드를 클래스 몸체의 프로퍼티에서도 사용할 수 있다. <br/>사실, 어떻게 생각하면 클래스의 프로퍼티를 `Typescript`에서는 클래스 몸체에 사전 선언하는 점을 생각하면 당연히 가능한 것일 수도 있다.\n\n```ts\nclass Person {\n    static lang = 'Javascript';\n\n    constructor() {\n        lang = 'Typescript';\n    }\n}\n\nconst person = new Person();\n\nconsole.log(Person.lang); // Typescript\nconsole.log(person.lang); // error : Property 'lang' does not exist on type 'Person'\n```\n\n위에서 볼 수 있듯이 `Typescript`에서도 `static`키워드가 붙은 프로퍼티나 메서드는 클래스 명으로만 접근할 수 있다.\n\n---\n\n#### Reference\n\n- [Poiemaweb - 클래스](https://poiemaweb.com/typescript-class)\n- [bkdevlog - [ES6]6. 클래스(class)](https://bkdevlog.netlify.com/posts/class)\n- [Typescript hand book - Classes](https://www.typescriptlang.org/docs/handbook/classes.html)"
  },
  {
    "path": "Vue/Vue_LifeCycle.md",
    "content": "# Vue - LifeCycle\n\n## Contents\n\nReact와 비교해서 라이프사이클이 외우기? 쉽고 간단하다. 또한 React와는 다르게 공식 사이트 한글문서가 너무 잘되어있어 읽어보면 쉽게 이해가 될 것이다.\n\n> [React라이프 사이클 살펴보기](http://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/)\n\n- beforeCreate\n- create\n- beforeMount\n- mount\n- beforeUpdate\n- update\n- beforeDestroy\n- destroy\n- nextTick\n- errorCaptured\n\n<br/>\n\n### Diagram\n\n![vue-lifecycle](/assets/images/Vue-lifecycle.png)\n\n<br/>\n\n## beforeCreate\n\n```js\nbeforeCreate () {\n  //can't use Data(this.title ...), events(vm.$on, vm.$once, vm.$off, vm.$emit)\n}\n```\n\n뷰에서 가장 먼저 실행되는 훅이다. `data`와 이벤트`($on, $once, $off, $emit)`, 감시자(`$watch`)등이 설정 되기 전에 호출이 된다.\n\n여러 곳을 찾아봤지만 어떻게 사용을 하고 운용을 할 수 있는지에 대해서는 자세히 찾지 못했다. 아무것도 만들어지고 아무것도 사용할 수 없는데 무엇을 할 수 있을까?\n\n<br/>\n\n## created\n\n```js\ncreated : {\n  titleComputed() {\n    //can use Data(this.title, this.titleComputed ...), events(vm.$on, vm.$once, vm.$off, vm.$emit)\n    //don't use $el\n  }\n}\n```\n\n이 훅에서는 이제 `data`와 `events`가 활성화가 되어 이제는 접근이 가능한 것이 생겼다. \n\n여전히 아직 DOM에 컴포넌트가 마운트 되지않은 상태이기 때문에 \n하지만 `$el`은 사용할 수 없다.\n\n<br/>\n\n## beforeMount\n\n```js\nbeforeMount() {\n    console.log(`this.$el doesn't exist yet, but it will soon!`)\n}\n```\n\n이 훅은 템플릿과 render 함수들이 컴파일된 후에 **첫 렌더링이 일어나기 직전**에 실행된다.\n\n위에서 말했듯이 컴포넌트 초기에 `data`가 세팅되어야 한다면 `created` 훅을, **렌더링 되고 DOM을 변경해야 한다면** `mounted` 훅을 사용하면 된다.\n\n그래서 거의 사용하지 않는 라이프 사이클 훅이라고 한다.\n\n<br/>\n\n## mounted\n\n```js\nmounted() {\n  console.log(this.$el.textContent) // can use $el\n  this.$nextTick(function () {\n    // 모든 화면이 마운트되었다는 것이 보장이 된다.\n  })\n}\n```\n이 훅에서는 컴포넌트, 템플릿, 렌더링된 돔에 접근할 수 있다.\n\n컴포넌트가 DOM에 추가 된 후 호출되는 훅이다. `$el`을 사용하여 DOM에 접근 할 수 있습니다. \n\n`mounted` 훅이 호출되었다고 모든 컴포넌트가 마운트 되었다고 보장할 수 없다. (자식 컴포넌트까지 마운트가 되었다고 보장이 되지 않는다.) <- 이 부분은 React와의 차이점\n\n![Parent_Child_workflow](/assets/images/Parent_Child_workflow.png)\n\n전체가 렌더링 보장된 상태에서 작업을 하기 위해서는 `$nextTick`을 사용해야 한다. (마지막 부록 부분 참고)\n\n<br/>\n\n## beforeUpdate\n\n```js\nbeforeUpdate() {\n  console.log('beforeUpdate');\n}\n```\n\n데이터가 변경되면, 가상 DOM `re-render`와 패치가 이뤄지기 전에 호출된다.\n\n`re-rendering` 전의 새 상태의 데이터를 얻을 수 있고 더 많은 변경이 가능하다. 그러나 추가로 `re-render`가 이루어지지 않는다고 한다. \n\n<br/>\n\n## updated\n\n```js\nupdated() {\n  console.log('updated');\n  this.$nextTick(function () {\n    // 모든 화면이 마운트되었다는 것이 보장이 된다.\n  })\n}\n```\n이 훅은 데이터가 변경되어 가상 DOM이 재 렌더링되고 패치되면 호출된다.\n\nDOM이 업데이트 완료된 상태이므로 DOM 종속적인 연산을 할 수 있다. \n\n그러나 여기서 상태를 변경하면 무한루프에 빠질 수 있다. \n`mounted`와 유사하게 모든 자식 컴포넌트의 재 렌더링 상태를 보장하지는 않는다.\n\n<br/>\n\n## beforeDestroy\n\n```js\nbeforeDestroy() {\n    console.log('beforeDestory');\n}\n```\n\n이 훅은 해체(뷰 인스턴스 제거)되기 직전에 호출된다. 컴포넌트는 원래 모습과 모든 기능들을 그대로 가지고 있다. \n\n이벤트 리스너를 제거하거나 `reactive subscription`을 제거하고자 한다면 이 훅에서 진행하면 된다.\n\n<br/>\n\n## destroyed\n\n```js\ndestroyed() {\n    console.log('destroyed');\n}\n```\n\n이 훅은 해체(뷰 인스턴스 제거)된 후에 호출된다. \n\nVue 인스턴스의 모든 디렉티브가 바인딩 해제 되고 모든 이벤트 리스너가 제거되며 **모든 하위 Vue 인스턴스도 삭제된다.**\n\n<br/>\n\n## 부록\n\n### Vue.nextTick( [callback, context] )\n\n```js\n// 데이터를 변경합니다\nvm.msg = 'Hello'\n// 아직 DOM 업데이트가 되지 않았습니다\nVue.nextTick(function () {\n  // DOM이 업데이트 되었습니다\n})\n\n// usage as a promise (2.1.0+, see note below)\nVue.nextTick()\n  .then(function () {\n    // DOM updated\n  })\n```\n\n다음 DOM 업데이트 사이클 이후 실행하는 콜백을 연기한다. \n\nDOM 업데이트를 기다리기 위해 일부 데이터를 변경한 직후 사용해야한다.\n\n<br/>\n\n### vm.$nextTick( [callback] )\n\n```js\nmethods: {\n  // ...\n  example: function () {\n    // 데이터 수정\n    this.message = 'changed'\n    // 아직 DOM 이 갱신되지 않음\n    this.$nextTick(function () {\n      // DOM이 이제 갱신됨\n      // `this` 가 현재 인스턴스에 바인딩 됨\n      this.doSomethingElse()\n    })\n  }\n}\n```\n\n다음 DOM 업데이트 사이클 이후 실행될 콜백을 연기한다. DOM 업데이트를 기다리기 위해 일부 데이터를 변경한 직후 사용한다. \n\n콜백의 this컨텍스트가 이 메소드를 호출하는 인스턴스에 자동으로 바인딩되는 점을 제외하고 전역 `Vue.nextTick` 과 같다.\n\n<br/>\n\n### errorCaptured\n\n```js\nerrorCaptured (err, vm, info) {\n    this.error = true\n}\n```\n\n자손 컴퍼넌트로부터의 에러가 캡처되었을 때에 불린다.(React에서 추가된 `getDerivedStateFromError(err)`와 비교)\n\n오류를 트리거 한 컴포넌트 인스턴스 및 오류가 캡처된 위치에 대한 정보가 들어있는 문자열의 세 가지 전달인자를 받는다. \n\n이 훅은 false를 반환하여 오류가 더 전파되지 않도록 할 수도 있다.\n\n#### 에러 전파 규칙\n\n기본적으로 모든 오류는 정의 된 경우 전역 `config.errorHandler` 로 보내지므로 분석 서비스에 한 곳에 계속 보고할 수 있다.\n\n여러 개의 `errorCaptured` 훅이 컴포넌트의 상속 체인이나 부모 체인에 존재하면, 모두 동일한 에러로 호출됩니다.\n\n`errorCaptured` 훅에서 에러를 `throw` 하면, 이 에러와 원래 캡쳐 된 에러 모두가 글로벌 `config.errorHandler` 로 보내진다\n\n`errorCaptured` 훅은 오류가 더 전파되지 않도록 false를 반환 할 수 있다. 이것은 본질적으로 **이 오류가 처리되었으므로 무시해야한다.** 를 의미합니다. 추가로 `errorCaptured` 훅이나 글로벌 `config.errorHandler` 가 이 에러를 위해 호출되지 않도록 한다.\n\n<br/>\n\n#### Reference\n\n- [Vue 공식사이트(라이프사이클-훅)](https://kr.vuejs.org/v2/api/#%EC%98%B5%EC%85%98-%EB%9D%BC%EC%9D%B4%ED%94%84%EC%82%AC%EC%9D%B4%ED%81%B4-%ED%9B%85)\n- [Vue.js 2.0 라이프사이클 이해하기](https://medium.com/witinweb/vue-js-%EB%9D%BC%EC%9D%B4%ED%94%84%EC%82%AC%EC%9D%B4%ED%81%B4-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0-7780cdd97dd4)\n- [vue 인스턴스 생명주기](https://hyeooona825.tistory.com/40)"
  },
  {
    "path": "WPF/wpf.md",
    "content": "# WPF(Window Presentation Foundation)\n\n## 목차  \n[1. WPF](#1.-What-is-WPF?)  \n[2. Resource](#2-Resource)  \n[3. Data Binding](#3-Data-binding)  \n[4. 프로젝트 활용](#4-프로젝트-활용)  \n\n\n## 1. What is WPF?\n\n### 1) 정의\nWPF는 마이크로소프트의 최신 GUI 프레임워크이다. 닷넷 프레임 워크를 기반에 둔다. Windows Presentation Foundation의 약자이다. (WPF, which stands for Windows Presentation Foundation, is Microsoft's latest approach to a GUI framework, used with the .NET framework.)\n### 2) 구성 요소\nXAML + CodeBehind  \n- XAML은 eXtensible Application Markup Language의 약자로 마이크로소프트 XML의 한 형태이다. 디자인을 위한 요소이다.\n- CodeBehind는 XAML과 연동되어 어플리케이션의 로직을 처리하는 요소이다. C# 또는 Visual Basic을 사용한다.  \n\n\n## 2. Resource\n* WPF의 Resource란? [참고](https://docs.microsoft.com/ko-kr/dotnet/framework/wpf/advanced/resources-wpf) \n> WPF supports different types of resources. These resources are primarily two types of resources: XAML resources and resource data files. Examples of XAML resources include brushes and styles. Resource data files are non-executable data files that an application needs.\n( XAML 리소스와 데이터 파일 두 가지로 분류된다. XAML 리소스의 예로는 브러시, 스타일이 있고 데이터 파일은 응용 프로그램에 필요한 비실행 데이터 파일이다. )\n\n### 1) StaticResource vs. DynamicResource\nStaticResource는 XAML이 로드될 때 단 한 번 할당 된다. 동적으로 리소스를 변경할 수 없다. 반면 DynamicResource는 필요할 때마다 할당 가능한 자원이다. 디자인(XAML) 시에 존재하지 않았던 리소스들을 CodeBehind 단(C#, Visual Basic)에서 사용할 수 있다. 다음 코드의 `ComboBoxItems`, `WindowBackgroundBrush`는 각각 StaticResource, DynamicResource 이다.  \n```xml\n<!--testControl.xaml-->\n<Window.Resources>\n        <sys:String x:Key=\"ComboBoxTitle\">Items:</sys:String>\n\n        <x:Array x:Key=\"ComboBoxItems\" Type=\"sys:String\">\n            <sys:String>Item #1</sys:String>\n            <sys:String>Item #2</sys:String>\n            <sys:String>Item #3</sys:String>\n        </x:Array>\n\n        <LinearGradientBrush x:Key=\"WindowBackgroundBrush\">\n            <GradientStop Offset=\"0\" Color=\"Silver\"/>\n            <GradientStop Offset=\"1\" Color=\"Gray\"/>\n        </LinearGradientBrush>\n</Window.Resources>\n```\n### 2) Scope\nresource의 scope는 1. Local -> 2. Window -> 3. Application 순으로 올라간다. 다음 세 개의 코드에서 `ComboBoxTitle`에 주목해 보자.\n\n1. Local Resource\n```xml\n<!--testControl.xaml-->\n<StackPanel Margin=\"10\">\n    <StackPanel.Resources>\n        <sys:String x:Key=\"ComboBoxTitle\">Items:</sys:String>\n    </StackPanel.Resources>\n    <Label Content=\"{StaticResource ComboBoxTitle}\" />\n</StackPanel>\n```\nStackPanel의 자식 계층인 Label에 `ComboBoxTitle`을 바인딩 하고 있다. Local Resource(여기서는 StackPanel.Resource)의 `ComboBoxTitle`와 바인딩 한다.  \n\n2. Window Resource\n```xml\n<!--testControl.xaml-->\n<Window x:Class=\"WpfTutorialSamples.WPF_Application.ExtendedResourceSample\"\n        xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xmlns:sys=\"clr-namespace:System;assembly=mscorlib\"\n        Title=\"ExtendedResourceSample\" Height=\"160\" Width=\"300\"\n        Background=\"{DynamicResource WindowBackgroundBrush}\">\n    <Window.Resources>\n        <sys:String x:Key=\"ComboBoxTitle\">Items:</sys:String>\n    </Window.Resources>\n    <StackPanel Margin=\"10\">\n        <Label Content=\"{StaticResource ComboBoxTitle}\" />\n    </StackPanel>\n</Window>\n```\nStackPanel의 자식 계층인 Label에 `ComboBoxTitle`을 바인딩 한다. StackPanel(여기서는 로컬) 자체에 `ComboBoxTitle`란 리소스가 없으므로 Window.Resource에 있는 `ComboBoxTitle`과 바인딩한다.  \n\n3. Application Resource\n```xml\n<!--app.xaml-->\n<Application x:Class=\"WpfTutorialSamples.App\"\n             xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n             xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n             xmlns:sys=\"clr-namespace:System;assembly=mscorlib\"\n             StartupUri=\"WPF application/ExtendedResourceSample.xaml\">\n    <Application.Resources>\n        <sys:String x:Key=\"ComboBoxTitle\">Items:</sys:String>\n    </Application.Resources>\n</Application>\n```\nStackPanel의 자식 계층인 Label에 `ComboBoxTitle`을 바인딩 한다고 가정하자. StackPanel(여기서는 로컬) 자체에 `ComboBoxTitle`란 리소스가 없고 Window.Resource에 `ComboBoxTitle`란 리소스가 없을 때는 App.xaml에 있는 리소스를 탐색한다. 즉 Application.Resources 는 최상위 계층이다.  \n\n### 3) Code-behind Resource\n```xml\n<!--App.xmal-->\n<Application x:Class=\"WpfTutorialSamples.App\"\n             xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n             xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n             xmlns:sys=\"clr-namespace:System;assembly=mscorlib\"\n             StartupUri=\"WPF application/ResourcesFromCodeBehindSample.xaml\">\n    <Application.Resources>\n        <sys:String x:Key=\"strApp\">Hello, Application world!</sys:String>\n    </Application.Resources>\n</Application>\n```\n```xml\n<!--Window.xaml-->\n<Window x:Class=\"WpfTutorialSamples.WPF_Application.ResourcesFromCodeBehindSample\"\n        xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xmlns:sys=\"clr-namespace:System;assembly=mscorlib\"\n        Title=\"ResourcesFromCodeBehindSample\" Height=\"175\" Width=\"250\">\n    <Window.Resources>\n        <sys:String x:Key=\"strWindow\">Hello, Window world!</sys:String>\n    </Window.Resources>\n    <DockPanel Margin=\"10\" Name=\"pnlMain\">\n        <DockPanel.Resources>\n            <sys:String x:Key=\"strPanel\">Hello, Panel world!</sys:String>\n        </DockPanel.Resources>\n\n        <WrapPanel DockPanel.Dock=\"Top\" HorizontalAlignment=\"Center\" Margin=\"10\">\n            <Button Name=\"btnClickMe\" Click=\"btnClickMe_Click\">Click me!</Button>\n        </WrapPanel>\n\n        <ListBox Name=\"lbResult\" />\n    </DockPanel>\n</Window>\n```\n다음 코드에서 `lbResult`에 Local, Window, App 리소스를 붙이고 있다.\n```csharp\nusing System;\nusing System.Windows;\n\nnamespace WpfTutorialSamples.WPF_Application\n{\n\tpublic partial class ResourcesFromCodeBehindSample : Window\n\t{\n\t\tpublic ResourcesFromCodeBehindSample()\n\t\t{\n\t\t\tInitializeComponent();\n\t\t}\n\n\t\tprivate void btnClickMe_Click(object sender, RoutedEventArgs e)\n\t\t{\n\t\t\tlbResult.Items.Add(pnlMain.FindResource(\"strPanel\").ToString());\n\t\t\tlbResult.Items.Add(this.FindResource(\"strWindow\").ToString());\n\t\t\tlbResult.Items.Add(Application.Current.FindResource(\"strApp\").ToString());\n\t\t}\n\t}\n}\n\n```\n### 4) Resource Dictionary\n[WPF Resource Dictionary 참고](https://docs.microsoft.com/ko-kr/windows/uwp/design/controls-and-patterns/resourcedictionary-and-xaml-resource-references)\n\n## 3. Data binding\n### 1) 정의 \nData Binding은 코드에서 UI 레이어로 데이터를 가져오는 데 선호되는 방식이다. ListBox를 구성할 때, 디자인단에서 수동으로 Control의 속성을 설정하거나 코드 단에서 loop를 돌려 item을 배치할 수도 있지만, 가장 깔끔한 방식은 Binding을 추가하는 것이다. Data binding은 WPF에서 큰 비중을 차지한다. \n\n### 2) 사용\n```\n{Binding Path=Text, ElementName=txtValue}\n```\nPath에는 Property명을, ElementName은 x:Key=? 의 이름을 사용한다. Binding에는 ElementName이라는 Property외에 [Source](https://www.wpf-tutorial.com/ko/502/%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%B0%94%EC%9D%B8%EB%94%A9/data-binding-via-code-behind/), [UpdateSourceTrigger](https://www.wpf-tutorial.com/ko/37/%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%B0%94%EC%9D%B8%EB%94%A9/updatesourcetrigger-%EC%86%8D%EC%84%B1/) 등의 Property를 갖는다.\n\n### 3) 예시\n![image](https://user-images.githubusercontent.com/43839938/79631135-00fcd780-8192-11ea-926f-b5c6d493f6c9.png)  \n`TextBox`의 `Text`와 `TextBlock`의 `Text`가 binding 되어 있다. \n```xml\n<Window x:Class=\"WpfTutorialSamples.DataBinding.HelloBoundWorldSample\"\n        xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        Title=\"HelloBoundWorldSample\" Height=\"110\" Width=\"280\">\n    <StackPanel Margin=\"10\">\n\t\t<TextBox Name=\"txtValue\" />\n\t\t<WrapPanel Margin=\"0,10\">\n\t\t\t<TextBlock Text=\"Value: \" FontWeight=\"Bold\" />\n\t\t\t<TextBlock Text=\"{Binding Path=Text, ElementName=txtValue}\" />\n\t\t</WrapPanel>\n\t</StackPanel>\n</Window>\n```\n## 4. 프로젝트 활용\nhttps://www.slideshare.net/EUNJIHA4/wpf-232222167\n#### Reference\n- [What is WPF?](https://www.wpf-tutorial.com/about-wpf/what-is-wpf/)\n- [Resource](https://www.wpf-tutorial.com/wpf-application/resources/)\n- [Data binding](https://www.wpf-tutorial.com/data-binding/introduction/)\n"
  },
  {
    "path": "assets/IndexDB/TodoList/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  <meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">\n  <title>Document</title>\n  <link href=\"https://fonts.googleapis.com/css?family=Nanum+Gothic|Noto+Sans+KR&display=swap\" rel=\"stylesheet\">\n  <link rel=\"stylesheet\" href=\"todoStyle.css\">\n</head>\n\n<body>\n  <div style=\"margin:auto; width : 80%\">\n    <h1 id=\"title\">TODO List(IndexedDB)</h1>\n    <div class=\"newTodoContainer defaultContainer\">\n      <span class=\"todoSubTitle left\">TODO:</span>\n      <input type=\"text\" id=\"newTodoInput\" placeholder=\"새로운 할 일을 적어주세요\" autofocus/>\n      <button type=\"button\" id=\"newTodoBtn\" class=\"defaultBtn right\">+New</button>\n    </div>\n    <div id=\"newTodoList\" class=\"defaultContainer\"></div>\n    <div class=\"doneTodoContainer defaultContainer\">\n      <span class=\"todoSubTitle left\">TODO</span>\n      <span class=\"todoSubTitle bigTitle\">Done</span>\n      <button type=\"button\" id=\"removeButton\" class=\"defaultBtn right\">Clear</button>\n    </div>\n    <div id=\"doneTodoList\" class=\"defaultContainer\"></div>\n  </div>\n  <div class=\"commonBtnContainer\">\n    <button type=\"button\" id=\"buttonAllClear\">All Clear</button>\n    <button type=\"button\" id=\"buttonSave\">Save</button>\n  </div>\n</body>\n<script type=\"text/javascript\" src=\"./js/indexDB.js\"></script>\n<script type=\"text/javascript\" src=\"./js/todo.js\"></script>\n\n</html>"
  },
  {
    "path": "assets/IndexDB/TodoList/js/indexDB.js",
    "content": "\n(function () {\n  console.log('link indexDB file')\n  let idbSupported = false\n\n  if (\"indexedDB\" in window) {\n    idbSupported = true;\n  }\n\n  if (idbSupported) {\n    // indexedDB 열기\n    const openRequest = indexedDB.open(\"TodoListDB\", 1);\n\n    openRequest.onupgradeneeded = function (e) {\n      console.log(\"indexedDB onupgradeneeded\");\n      const thisDB = e.target.result;\n\n      // firstOS이라는 저장소가 없으면\n      if (!thisDB.objectStoreNames.contains(\"TodoListTable\")) {\n        // 저장소를 만들어줌\n        thisDB.createObjectStore(\"TodoListTable\", { autoIncrement: true });\n      }\n    }\n\n    openRequest.onsuccess = function (e) {\n      console.log(\"indexedDB open Success!\");\n\n      db = e.target.result;\n      const transaction = db.transaction([\"TodoListTable\"],\"readonly\");\n      const store = transaction.objectStore(\"TodoListTable\");\n\n      //기존의 데이터를 불러오기\n      store.getAll().onsuccess = function(e) {\n        const result = e.target.result;\n\n        for (let index = 0; index < result.length; index++) {\n          const element = result[index];\n          TODO_LIST[element.key] = element\n          if(element.done){\n            document.getElementById(DOINGDONE_ARR[1]).appendChild(createTodoLine(element.value, element.key, element.done));\n          }else{\n            document.getElementById(DOINGDONE_ARR[0]).appendChild(createTodoLine(element.value, element.key, element.done));\n          }\n        }\n      }\n      \n      // 이벤트 등록\n      document.querySelector(\"#buttonSave\").addEventListener(\"click\", addToDoList, false);\n      document.querySelector(\"#buttonAllClear\").addEventListener(\"click\", clearToDoList, false);\n    }\n\n    openRequest.onerror = function (e) {\n      console.log(\"Error\", e);\n    }\n  }\n\n  function addToDoPromise(todo) {\n    const promise = new Promise(function(resolve, reject){\n      const transaction = db.transaction([\"TodoListTable\"], \"readwrite\");\n      const store = transaction.objectStore(\"TodoListTable\");\n      let request\n\n      console.log('store', store) \n      request = store.add(todo);\n  \n      request.onerror = function (e) {\n        console.warn(\"Error\", e.target.error.name);\n        reject()\n      }\n  \n      request.onsuccess = function (e) {\n        console.log(\"Woot! Did it\", todo);\n        resolve()\n      }\n    })\n    return promise\n  }\n\n  function addToDoList(e) {\n    let resolve = Promise.resolve();\n    const values = Object.values(TODO_LIST);\n\n    if(values.length === 0){\n      alert(\"저장할 내역이 없습니다.\");\n      return;\n    }\n\n    const transaction = db.transaction([\"TodoListTable\"], \"readwrite\");\n    const store = transaction.objectStore(\"TodoListTable\");\n    store.clear();\n\n    for (let index = 0; index < values.length; index++) {\n      const element = values[index];\n      resolve = resolve.then(addToDoPromise(element))\n    }\n\n    resolve.then(() => {\n      alert(\"저장완료\")\n    })\n  }\n\n  function clearToDoList(e) {\n    const transaction = db.transaction([\"TodoListTable\"], \"readwrite\");\n    const store = transaction.objectStore(\"TodoListTable\");\n    store.clear();\n  }\n})()"
  },
  {
    "path": "assets/IndexDB/TodoList/js/todo.js",
    "content": "const TODO_LIST = {};\nconst DOINGDONE_ARR = [\"newTodoList\", \"doneTodoList\"];\n\nconst createTodoLine = (inputValue, key, done = 'false') => {\n  const newTodoContainer = document.createElement(\"div\");\n  const newCheckbox = document.createElement(\"input\");\n  const newSpan = document.createElement(\"span\");\n\n  newTodoContainer.dataset.key = key\n  newTodoContainer.className = \"todoContainer\"\n\n  newSpan.textContent = inputValue\n  newSpan.className = \"newTodoText\"\n\n  newCheckbox.setAttribute(\"type\", \"checkbox\");\n  newCheckbox.checked = done\n  newCheckbox.addEventListener(\"click\", moveTodo);\n\n  newTodoContainer.appendChild(newCheckbox);\n  newTodoContainer.appendChild(newSpan);\n\n  return newTodoContainer;\n}\n\nconst moveTodo = (e) => {\n  const checkbox = e.target;\n  const parentId = checkbox.parentNode.parentNode.getAttribute(\"id\");\n  const moveIndex = Math.abs(DOINGDONE_ARR.length - DOINGDONE_ARR.indexOf(parentId) - 1)\n\n  TODO_LIST[checkbox.parentNode.dataset.key].done = !TODO_LIST[checkbox.parentNode.dataset.key].done\n\n  document.getElementById(DOINGDONE_ARR[moveIndex]).appendChild(checkbox.parentNode);\n}\n\n(function () {\n  console.log('Run Todo JS file')\n\n  // keydown과 관련된 handler추가\n  const keydownHandler = (e) => {\n    switch (e.keyCode) {\n      case 13:\n        generateTodo(e.target.value);\n        break;\n\n      default:\n        break;\n    }\n  }\n\n  // Create Todo\n  const generateTodo = function (inputValue) {\n    if (inputValue === '') {\n      alert('내용을 입력해주세요')\n      return\n    }\n    const todo = {\n      key: '_' + Math.random().toString(36).substr(2, 9),\n      value: inputValue,\n      done: false,\n      created: new Date()\n    }\n\n    // Append New Todo\n    document.getElementById(DOINGDONE_ARR[0]).appendChild(createTodoLine(inputValue, todo.key, false));\n    TODO_LIST[todo.key] = todo\n    // Reset InputBox\n    document.getElementById(\"newTodoInput\").value = \"\";\n  }\n\n  const removeAllTodo = function () {\n    removeNewTodo();\n    removeDoneTodo();\n  }\n\n  const removeNewTodo = function () {\n    const newTodoContainer = document.getElementById(DOINGDONE_ARR[0]);\n\n    while (newTodoContainer.firstChild) {\n      delete TODO_LIST[newTodoContainer.firstChild.dataset.key]\n      newTodoContainer.removeChild(newTodoContainer.firstChild);\n    }\n  }\n\n  const removeDoneTodo = function () {\n    const doneTodoContainer = document.getElementById(DOINGDONE_ARR[1]);\n\n    while (doneTodoContainer.firstChild) {\n      delete TODO_LIST[doneTodoContainer.firstChild.dataset.key]\n      doneTodoContainer.removeChild(doneTodoContainer.firstChild);\n    }\n  }\n\n  document.getElementById(\"newTodoInput\").addEventListener(\"keydown\", keydownHandler, false)\n  document.getElementById(\"newTodoBtn\").addEventListener(\"click\", () => generateTodo(document.getElementById(\"newTodoInput\").value), false)\n  document.getElementById(\"removeButton\").addEventListener(\"click\", removeDoneTodo, false)\n  document.getElementById(\"buttonAllClear\").addEventListener(\"click\", removeAllTodo, false)\n})()\n\n"
  },
  {
    "path": "assets/IndexDB/TodoList/todoStyle.css",
    "content": "html body{\n  font-family: 'Noto Sans KR', sans-serif;\n  font-family: 'Nanum Gothic', sans-serif;\n  font-size: 16px;\n}\n\n#title{\n  text-align: center;\n}\n\n.defaultContainer{\n  margin : 10px;\n  padding : 10px;\n  border: 2px solid black;\n\n  min-height: 20px;\n}\n\n.newTodoContainer, .doneTodoContainer{\n  text-align: center;\n}\n\n.todoSubTitle{\n  font-size: 18px;\n  font-weight: bold;\n}\n\n.commonBtnContainer{\n  text-align: center;\n  padding : 10px;\n}\n\n.defaultBtn{\n  display: inline-block;\n  position: static;\n\n  color: black;\n  background-color: white;\n\n  border: 1px solid black;\n  border-radius: 10px;\n\n  width: 70px;\n  height: 25px;\n}\n\n.defaultBtn:hover{\n  color: white;\n  background-color: darkgrey;\n  border: 1px solid darkgrey;\n  box-shadow: 0px 0px 5px 2px lightgrey;\n}\n\n.defaultBtn:active{\n  color: white;\n  background-color: darkkhaki;\n  border: 1px solid darkkhaki;\n  box-shadow: 0px 0px 5px 2px lightgrey;\n}\n\n.todoContainer{\n  margin: 0px 5px;\n  padding: 10px 0px;\n\n  font-size: 16px;\n\n  border-bottom: 0.5px solid lightgrey;\n\n  width: 100%;\n}\n\n.newTodoText{\n  margin: 5px;\n  font-size: 16px;\n}\n\n#newTodoInput{\n  padding : 3px;\n  font-size: 14px;\n  width: 65%\n}\n\n#buttonSave, #buttonAllClear{\n  display: inline-block;\n  position: static;\n\n  margin: auto;\n  margin-top: 5px;\n  margin-bottom: 5px;\n\n  color: black;\n  background-color: white;\n\n  border: 1px solid black;\n  font-size: 18px;\n  font-weight: bold;\n\n  width: 200px;\n  height: 40px;\n}\n\n#buttonSave:hover{\n  color: white;\n  background-color: darkgrey;\n  border: 0px\n}\n\n#buttonAllClear:hover{\n  color: white;\n  background-color: darkgreen;\n  border: 0px\n}\n\n#buttonSave:active, #buttonAllClear:active{\n  color: black;\n  background-color: white;\n  border: 0px\n}\n\n::-webkit-input-placeholder { /* Chrome/Opera/Safari */\n  color: pink;\n  font-size: 14px;\n}\n\n.left {\n  float:left;\n}\n\n.right {\n  float:right;\n}\n\n.bigTitle {\n  font-size: 22px;\n}\n"
  },
  {
    "path": "assets/IndexDB/index2.html",
    "content": "<!doctype html>\n<html>\n\n<head>\n</head>\n\n<body>\n  <input type=\"text\" id=\"name\" placeholder=\"Name\"><br />\n  <input type=\"email\" id=\"email\" placeholder=\"Email\"><br />\n  <button id=\"addButton\">Add Data</button><br />\n\n  <input type=\"text\" id=\"nameSearch\" placeholder=\"Name\"><br />\n  <input type=\"text\" id=\"nameSearchEnd\" placeholder=\"Name\"><br />\n  <button id=\"getButton\">Get Person</button>\n  <div id=\"status\"></div>\n</body>\n<script>\n  let db;\n\n  function indexedDBOk() {\n    return \"indexedDB\" in window;\n  }\n\n  document.addEventListener(\"DOMContentLoaded\", function () {\n\n    //indexedDB 지원 유무\n    if (!indexedDBOk) return;\n    //idarticle_people 네임인 DB생성.\n    const openRequest = indexedDB.open(\"idarticle_people\", 1);\n    openRequest.onupgradeneeded = function (e) {\n      const thisDB = e.target.result;\n      // people ObjectStore 생성(테이블이라고 생각하면 될것 같음..)\n      if (!thisDB.objectStoreNames.contains(\"people\")) {\n        var store = thisDB.createObjectStore(\"people\", { autoIncrement: true });\n        store.createIndex(\"name\",\"name\", {unique:false});\n      }\n    }\n\n    openRequest.onsuccess = function (e) {\n      console.log(\"running onsuccess\");\n      db = e.target.result;\n\n      //Listen for add clicks\n      document.querySelector(\"#addButton\").addEventListener(\"click\", addPerson, false);\n      document.querySelector(\"#getButton\").addEventListener(\"click\", getPeople, false);\n    }\n\n    openRequest.onerror = function (e) {\n      //Do something for the error\n    }\n\n  }, false);\n\n  function addPerson(e) {\n\n    const name = document.querySelector(\"#name\").value;\n    const email = document.querySelector(\"#email\").value;\n\n    console.log(\"About to add \" + name + \"/\" + email);\n    //people 테이블에 데이터 add 선언..\n    const transaction = db.transaction([\"people\"], \"readwrite\");\n    const store = transaction.objectStore(\"people\");\n\n    //Define a person\n    const person = {\n      name: name,\n      email: email,\n      created: new Date()\n    }\n\n    //Perform the add\n    const request = store.add(person);\n\n    request.onerror = function (e) {\n      console.log(\"Error\", e.target.error.name);\n      //some type of error handler\n    }\n\n    request.onsuccess = function (e) {\n      console.log(\"Add Success\");\n    }\n  }\n\n\n  function getPeople(e) {\n    const name = document.querySelector(\"#nameSearch\").value;\n    const endname = document.querySelector(\"#nameSearchEnd\").value;\n\n    if (name == \"\" && endname == \"\") return;\n\n    const transaction = db.transaction([\"people\"], \"readonly\");\n    const store = transaction.objectStore(\"people\");\n    const index = store.index(\"name\");\n\n    //Make the range depending on what type we are doing\n    let range;\n    if (name != \"\" && endname != \"\") {\n      range = IDBKeyRange.bound(name, endname);\n    } else if (name == \"\") {\n      range = IDBKeyRange.upperBound(endname);\n    } else {\n      range = IDBKeyRange.lowerBound(name);\n    }\n\n    let s = \"\";\n\n    index.openCursor(range).onsuccess = function (e) {\n      const cursor = e.target.result;\n      if (cursor) {\n        s += \"<h2>Key \" + cursor.key + \"<h2>&<p>\";\n        for (var field in cursor.value) {\n          s += field + \"=\" + cursor.value[field] + \"&lt;br/>\";\n        }\n        s += \"<p>\";\n        cursor.continue();\n      }\n      // const myDiv = document.getElementById(\"#status\")\n      // myDiv.innerHTML = s;\n      console.log(cursor)\n    }\n  }\n</script>\n\n</html>"
  },
  {
    "path": "assets/TEST/bigfile.html",
    "content": "<!DOCTYPE html>\r\n<html data-v-240ff122=\"\" data-v-75109770=\"\" data-tooltip=\"false\" class=\"\" data-uuid=\"-3\" data-parent=\"-1\"\r\n    data-type=\"DocumentElement\" data-container=\"true\" data-quicktoolbar=\"true\" data-highlight=\"false\"\r\n    data-role=\"component\">\r\n\r\n<head data-v-240ff122=\"\" data-uuid=\"-2\" data-rect-x1=\"-1\" data-rect-x2=\"-1\" data-rect-y1=\"-1\" data-rect-y2=\"-1\"\r\n    data-container=\"true\" data-quicktoolbar=\"true\" data-role=\"component\">\r\n    <title>Studio-JCEF-editor</title>\r\n    <link type=\"text/css\" rel=\"stylesheet\" href=\"/_vue/dist/static/css/_intelliWeb_designer.css?idx=1568796401270\"\r\n        data-csslink-uuid=\"-1\" data-targettag=\"Main\">\r\n    <link type=\"text/css\" rel=\"stylesheet\" href=\"/websquare/_stylesheet.css?idx=1568796401270\"\r\n        data-csslink-uuid=\"undefined\" data-targettag=\"Main\">\r\n    <div id=\"--styleDeafultStartLine\"></div>\r\n    <link type=\"text/css\" rel=\"stylesheet\" href=\"/arch/samsungfire/cm/css/all.css?idx=1568796401270\"\r\n        data-csslink-uuid=\"0\" data-targettag=\"Main\">\r\n    <link type=\"text/css\" rel=\"stylesheet\" href=\"/arch/samsungfire/cm/css/contents.css?idx=1568796401270\"\r\n        data-csslink-uuid=\"0\" data-targettag=\"Main\">\r\n    <style type=\"text/css\" data-style-uuid=\"0\" data-targettag=\"Main\"></style>\r\n    <style type=\"text/css\" data-style-uuid=\"0\" data-targettag=\"Main\"></style>\r\n    <div id=\"--styleDeafultEndLine\"></div>\r\n</head>\r\n\r\n<body data-v-240ff122=\"\" data-uuid=\"-1\" data-container=\"true\" data-quicktoolbar=\"true\" data-tooltip=\"false\"\r\n    data-highlight=\"false\" data-role=\"component\" id=\"-1\" class=\"\"\r\n    style=\"position: static; top: 0px; left: 0px; width: 100%; height: 100%; overflow: initial !important;\">\r\n\r\n    <body id=\"--internal-shadowBody\" data-uuid=\"-1\" data-tooltip=\"false\" data-container=\"true\" class=\"\"\r\n        style=\"z-index: -2147483647; position: absolute; top: 0px; left: 0px; width: 1018px; height: 791px; margin: 0px; padding: 0px; overflow: initial !important;\">\r\n    </body>\r\n    <!---->\r\n    <div id=\"_iwd_15qeucfujs\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n        class=\"component-guideline component hammer w2group sub_contents\" data-uuid=\"_iwd_15qeucfujs\" data-parent=\"-1\"\r\n        data-container=\"true\" data-quicktoolbar=\"true\" data-role=\"component\" style=\"padding: 20px;\">\r\n        <!---->\r\n        <div id=\"_iwd_15qeucq830\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n            class=\"component-guideline component hammer w2group pgtbox\" data-role=\"component\"\r\n            data-uuid=\"_iwd_15qeucq830\" data-parent=\"_iwd_15qeucfujs\" rootelm=\"\" data-container=\"true\"\r\n            data-quicktoolbar=\"true\">\r\n            <!---->\r\n            <div id=\"_iwd_15qeucv9hk\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                class=\"component-guideline component hammer w2group fl\" data-role=\"component\"\r\n                data-uuid=\"_iwd_15qeucv9hk\" data-parent=\"_iwd_15qeucq830\" rootelm=\"\" data-container=\"true\"\r\n                data-quicktoolbar=\"true\">\r\n                <!---->\r\n                <div id=\"_iwd_15qeus7hi4\" tabindex=\"-1\" data-resizable=\"true\" data-role=\"component\"\r\n                    class=\"component-guideline component hammer w2textbox pgt_tit\" data-uuid=\"_iwd_15qeus7hi4\"\r\n                    data-parent=\"_iwd_15qeucv9hk\" rootelm=\"\">Individual General</div>\r\n                <div id=\"_iwd_15qeushv6w\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                    class=\"component-guideline component hammer w2group pgt_icobox\" data-role=\"component\"\r\n                    data-uuid=\"_iwd_15qeushv6w\" data-parent=\"_iwd_15qeucv9hk\" rootelm=\"\" data-container=\"true\"\r\n                    data-quicktoolbar=\"true\">\r\n                    <!----> <a id=\"_iwd_15qev32b0w\" href=\"javascript:void(0);\" data-role=\"component\" data-state=\"init\"\r\n                        data-taborder=\"true\" data-resizable=\"true\"\r\n                        class=\"component-guideline component hammer w2anchor2 btn_help\" data-uuid=\"_iwd_15qev32b0w\"\r\n                        data-parent=\"_iwd_15qeushv6w\" rootelm=\"\">Help</a><a id=\"_iwd_15qev7375g\"\r\n                        href=\"javascript:void(0);\" data-role=\"component\" data-state=\"init\" data-taborder=\"true\"\r\n                        data-resizable=\"true\" class=\"component-guideline component hammer w2anchor2 btn_home\"\r\n                        data-uuid=\"_iwd_15qev7375g\" data-parent=\"_iwd_15qeushv6w\" rootelm=\"\">Main</a><a\r\n                        id=\"_iwd_15qev7a65k\" href=\"javascript:void(0);\" data-role=\"component\" data-state=\"init\"\r\n                        data-taborder=\"true\" data-resizable=\"true\"\r\n                        class=\"component-guideline component hammer w2anchor2 btn_bookmark\" data-uuid=\"_iwd_15qev7a65k\"\r\n                        data-parent=\"_iwd_15qeushv6w\" rootelm=\"\">Favorites</a></div>\r\n            </div>\r\n            <div id=\"_iwd_15qev7gqcc\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                class=\"component-guideline component hammer w2group fr\" data-role=\"component\"\r\n                data-uuid=\"_iwd_15qev7gqcc\" data-parent=\"_iwd_15qeucq830\" rootelm=\"\" data-container=\"true\"\r\n                data-quicktoolbar=\"true\">\r\n                <!----> <a id=\"btn_sch_A011\" href=\"javascript:void(0);\" data-role=\"component\" data-state=\"init\"\r\n                    data-taborder=\"true\" data-resizable=\"true\"\r\n                    class=\"component-guideline component hammer default_event_wrap w2anchor2 btn_cm btn_cm_tbup\"\r\n                    data-uuid=\"_iwd_15qev7lfpk\" data-parent=\"_iwd_15qev7gqcc\" rootelm=\"\">Search</a></div>\r\n        </div>\r\n        <div id=\"_iwd_15qev7so7c\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n            class=\"component-guideline component hammer w2group wq_tbc_box mt10\" data-role=\"component\"\r\n            data-uuid=\"_iwd_15qev7so7c\" data-parent=\"_iwd_15qeucfujs\" rootelm=\"\" data-container=\"true\"\r\n            data-quicktoolbar=\"true\">\r\n            <!---->\r\n            <div id=\"_iwd_15qev7wuz4\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                class=\"component-guideline component hammer w2group\" data-role=\"component\" data-uuid=\"_iwd_15qev7wuz4\"\r\n                data-parent=\"_iwd_15qev7so7c\" rootelm=\"\" data-container=\"true\" data-quicktoolbar=\"true\"\r\n                style=\"overflow: hidden;\">\r\n                <!---->\r\n                <div id=\"tbx_RenderingTime_A011\" tabindex=\"-1\" data-resizable=\"true\" data-role=\"component\"\r\n                    class=\"component-guideline component hammer w2textbox\" data-uuid=\"_iwd_15qev80anw\"\r\n                    data-parent=\"_iwd_15qev7wuz4\" rootelm=\"\"\r\n                    style=\"height: 23px; color: red; float: left; margin-right: 15px;\"></div>\r\n                <div id=\"tbx_RenderingTime2_A011\" tabindex=\"-1\" data-resizable=\"true\" data-role=\"component\"\r\n                    class=\"component-guideline component hammer w2textbox\" data-uuid=\"_iwd_15qev85sck\"\r\n                    data-parent=\"_iwd_15qev7wuz4\" rootelm=\"\" style=\"height: 23px; color: red; float: left;\"></div>\r\n            </div>\r\n            <div id=\"_iwd_15qevs9zew\" data-resizable=\"true\" class=\"component-guideline component hammer wq_tbc cb\"\r\n                data-role=\"component\" data-uuid=\"_iwd_15qevs9zew\" data-parent=\"_iwd_15qev7so7c\" rootelm=\"\">\r\n                <ul class=\"w2tabcontrol_tabhost \">\r\n                    <li id=\"tabs1\" data-resizable=\"true\"\r\n                        class=\"component hammer w2tabcontrol_li w2tabcontrol_li_0 w2tabcontrol_active w2tabcontrol_over\"\r\n                        data-role=\"component\" data-uuid=\"_iwd_15qewh0g7c\" style=\"height: 25px; margin-right: 0px;\">\r\n                        <div class=\"w2tabcontrol_tab_center\"><a>Basic Info</a></div>\r\n                        <div class=\"w2tabcontrol_tab_left\"></div>\r\n                        <div class=\"w2tabcontrol_tab_right\">\r\n                            <div class=\"w2tabcontrol_tab_close\" style=\"display: none;\"></div>\r\n                        </div>\r\n                    </li>\r\n                </ul>\r\n                <div class=\"w2tabcontrol_container default_tabcontainer_style\">\r\n                    <div id=\"content1\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                        class=\"component-guideline component hammer w2group component hammer w2tabcontrol_contents w2group\"\r\n                        data-role=\"component\" data-uuid=\"_iwd_15qexitj78\" data-parent=\"_iwd_15qevs9zew\"\r\n                        data-container=\"true\" data-quicktoolbar=\"true\"\r\n                        style=\"overflow: auto; display: block; visibility: inherit;\">\r\n                        <!---->\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div id=\"_iwd_15qexj4788\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                class=\"component-guideline component hammer w2group tbbox mt10\" data-role=\"component\"\r\n                data-uuid=\"_iwd_15qexj4788\" data-parent=\"_iwd_15qev7so7c\" rootelm=\"\" data-container=\"true\"\r\n                data-quicktoolbar=\"true\">\r\n                <!---->\r\n                <table id=\"_iwd_15qexj7e4c\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                    class=\"component-guideline component hammer w2group w2tb tb\" data-role=\"component\"\r\n                    data-uuid=\"_iwd_15qexj7e4c\" data-parent=\"_iwd_15qexj4788\" rootelm=\"\" data-container=\"true\"\r\n                    data-quicktoolbar=\"true\" style=\"position: relative; width: 100%;\">\r\n                    <!---->\r\n                    <colgroup id=\"_iwd_15qextv6h8\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                        class=\"component-guideline component hammer w2group\" data-role=\"component\"\r\n                        data-uuid=\"_iwd_15qextv6h8\" data-parent=\"_iwd_15qexj7e4c\" rootelm=\"_iwd_15qexj7e4c\"\r\n                        data-container=\"true\" data-quicktoolbar=\"true\">\r\n                        <!---->\r\n                        <col id=\"_iwd_15qey0quls\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qey0quls\" data-parent=\"_iwd_15qextv6h8\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\" style=\"width: 10%;\">\r\n                        <col id=\"_iwd_15qey625c0\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qey625c0\" data-parent=\"_iwd_15qextv6h8\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\" style=\"width: 20%;\">\r\n                        <col id=\"_iwd_15qey67hb4\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qey67hb4\" data-parent=\"_iwd_15qextv6h8\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\" style=\"width: 10%;\">\r\n                        <col id=\"_iwd_15qey6bmx8\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qey6bmx8\" data-parent=\"_iwd_15qextv6h8\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                        <col id=\"_iwd_15qey6fn24\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qey6fn24\" data-parent=\"_iwd_15qextv6h8\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\" style=\"width: 10%;\">\r\n                        <col id=\"_iwd_15qey6qtrc\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qey6qtrc\" data-parent=\"_iwd_15qextv6h8\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                        <col id=\"_iwd_15qey6yu14\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qey6yu14\" data-parent=\"_iwd_15qextv6h8\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\" style=\"width: 10%;\">\r\n                        <col id=\"_iwd_15qey73k64\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qey73k64\" data-parent=\"_iwd_15qextv6h8\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                    </colgroup>\r\n                    <tr id=\"_iwd_15qey77w9k\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                        class=\"component hammer w2group\" data-role=\"component\" data-uuid=\"_iwd_15qey77w9k\"\r\n                        data-parent=\"_iwd_15qexj7e4c\" rootelm=\"_iwd_15qexj7e4c\" data-container=\"true\"\r\n                        data-quicktoolbar=\"true\">\r\n                        <!---->\r\n                        <th id=\"_iwd_15qey7c29k\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_th\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qey7c29k\" data-parent=\"_iwd_15qey77w9k\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!----> <span id=\"_iwd_15qeylm87w\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2span ast\" data-role=\"component\"\r\n                                data-uuid=\"_iwd_15qeylm87w\" data-parent=\"_iwd_15qey7c29k\" rootelm=\"\">Name</span></th>\r\n                        <td id=\"_iwd_15qeylu4eg\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_td\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qeylu4eg\" data-parent=\"_iwd_15qey77w9k\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!----> <input data-v-0f1195ec=\"\" id=\"_iwd_15qeyu62mk\" data-resizable=\"true\"\r\n                                data-taborder=\"true\" type=\"text\" readonly=\"readonly\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2input --internal-input-cursor w2input_ref_binding ast\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qeyu62mk\" data-parent=\"_iwd_15qeylu4eg\"\r\n                                rootelm=\"\" style=\"width: 74.65%;\"></td>\r\n                        <th id=\"_iwd_15qeyudppc\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_th\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qeyudppc\" data-parent=\"_iwd_15qey77w9k\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!----> <span id=\"_iwd_15qeyujhcc\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2span ast\" data-role=\"component\"\r\n                                data-uuid=\"_iwd_15qeyujhcc\" data-parent=\"_iwd_15qeyudppc\" rootelm=\"\">Public ID\r\n                                Number</span></th>\r\n                        <td id=\"_iwd_15qeyun2z0\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_td\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qeyun2z0\" data-parent=\"_iwd_15qey77w9k\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!----> <input data-v-0f1195ec=\"\" id=\"_iwd_15qeyur79w\" data-resizable=\"true\"\r\n                                data-taborder=\"true\" type=\"text\" readonly=\"readonly\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2input --internal-input-cursor w2input_disabled w2input_ref_binding\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qeyur79w\" data-parent=\"_iwd_15qeyun2z0\"\r\n                                rootelm=\"\" style=\"width: 100%;\"><a id=\"_iwd_15qeyuuur8\" href=\"javascript:void(0);\"\r\n                                data-role=\"component\" data-state=\"init\" data-taborder=\"true\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2anchor2\" data-uuid=\"_iwd_15qeyuuur8\"\r\n                                data-parent=\"_iwd_15qeyun2z0\" rootelm=\"\" style=\"width: 100px; height: 23px;\">Insert\r\n                                Text</a></td>\r\n                        <th id=\"_iwd_15qeyv263s\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_th\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qeyv263s\" data-parent=\"_iwd_15qey77w9k\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!----> <span id=\"_iwd_15qeyv67jw\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2span\" data-role=\"component\"\r\n                                data-uuid=\"_iwd_15qeyv67jw\" data-parent=\"_iwd_15qeyv263s\" rootelm=\"\">Sex</span></th>\r\n                        <td id=\"_iwd_15qeyvbngo\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_td\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qeyvbngo\" data-parent=\"_iwd_15qey77w9k\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!---->\r\n                            <div id=\"_iwd_15qezogch0\" data-taborder=\"true\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2radio\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qezogch0\" data-parent=\"_iwd_15qeyvbngo\"\r\n                                rootelm=\"\">\r\n                                <div class=\"w2radio_item\"><input type=\"radio\" index=\"0\" tabindex=\"0\"\r\n                                        class=\"w2radio_input\"> <label index=\"0\" class=\"w2radio_label\">M</label></div>\r\n                                <div class=\"w2radio_item\"><input type=\"radio\" index=\"1\" tabindex=\"0\"\r\n                                        class=\"w2radio_input\"> <label index=\"1\" class=\"w2radio_label\">F</label></div>\r\n                            </div>\r\n                        </td>\r\n                        <th id=\"_iwd_15qezq7j8o\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_th\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qezq7j8o\" data-parent=\"_iwd_15qey77w9k\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!----> <span id=\"_iwd_15qezqclyg\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2span\" data-role=\"component\"\r\n                                data-uuid=\"_iwd_15qezqclyg\" data-parent=\"_iwd_15qezq7j8o\" rootelm=\"\">Nationality</span>\r\n                        </th>\r\n                        <td id=\"_iwd_15qezqfzeo\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_td\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qezqfzeo\" data-parent=\"_iwd_15qey77w9k\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!---->\r\n                            <div id=\"_iwd_15qezqjydw\" data-taborder=\"true\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2radio\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qezqjydw\" data-parent=\"_iwd_15qezqfzeo\"\r\n                                rootelm=\"\">\r\n                                <div class=\"w2radio_item\"><input type=\"radio\" index=\"0\" tabindex=\"0\"\r\n                                        class=\"w2radio_input\"> <label index=\"0\" class=\"w2radio_label\">Non-Korean</label>\r\n                                </div>\r\n                                <div class=\"w2radio_item\"><input type=\"radio\" index=\"1\" tabindex=\"0\"\r\n                                        class=\"w2radio_input\"> <label index=\"1\" class=\"w2radio_label\">Korean</label>\r\n                                </div>\r\n                            </div>\r\n                        </td>\r\n                    </tr>\r\n                    <tr id=\"_iwd_15qezr7lp4\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                        class=\"component hammer w2group\" data-role=\"component\" data-uuid=\"_iwd_15qezr7lp4\"\r\n                        data-parent=\"_iwd_15qexj7e4c\" rootelm=\"_iwd_15qexj7e4c\" data-container=\"true\"\r\n                        data-quicktoolbar=\"true\">\r\n                        <!---->\r\n                        <th id=\"_iwd_15qezrbgnw\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_th\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qezrbgnw\" data-parent=\"_iwd_15qezr7lp4\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!----> <span id=\"_iwd_15qezrlbdc\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2span\" data-role=\"component\"\r\n                                data-uuid=\"_iwd_15qezrlbdc\" data-parent=\"_iwd_15qezrbgnw\" rootelm=\"\">Verification</span>\r\n                        </th>\r\n                        <td id=\"_iwd_15qezrp6vk\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_td\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qezrp6vk\" data-parent=\"_iwd_15qezr7lp4\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!---->\r\n                            <div id=\"realNmYn\" data-taborder=\"true\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer default_binding_wrap default_event_wrap default_binding_event_wrap w2radio\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qezrzbb0\" data-parent=\"_iwd_15qezrp6vk\"\r\n                                rootelm=\"\">\r\n                                <div class=\"w2radio_item\"><input type=\"radio\" index=\"0\" tabindex=\"0\"\r\n                                        class=\"w2radio_input\"> <label index=\"0\" class=\"w2radio_label\">Verified</label>\r\n                                </div>\r\n                                <div class=\"w2radio_item\"><input type=\"radio\" index=\"1\" tabindex=\"0\"\r\n                                        class=\"w2radio_input\"> <label index=\"1\" class=\"w2radio_label\">Not\r\n                                        verified</label></div>\r\n                            </div><a id=\"_iwd_15qezsrw0c\" href=\"javascript:void(0);\" data-role=\"component\"\r\n                                data-state=\"init\" data-taborder=\"true\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2anchor2 btn_cm\"\r\n                                data-uuid=\"_iwd_15qezsrw0c\" data-parent=\"_iwd_15qezrp6vk\" rootelm=\"\"\r\n                                style=\"margin-left: 5px;\">Get verified.</a>\r\n                        </td>\r\n                        <th id=\"_iwd_15qezszj8o\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_th\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qezszj8o\" data-parent=\"_iwd_15qezr7lp4\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!----> <span id=\"_iwd_15qezt3z9s\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2span\" data-role=\"component\"\r\n                                data-uuid=\"_iwd_15qezt3z9s\" data-parent=\"_iwd_15qezszj8o\" rootelm=\"\">Type</span></th>\r\n                        <td id=\"_iwd_15qezt7c3s\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_td\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qezt7c3s\" data-parent=\"_iwd_15qezr7lp4\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!---->\r\n                            <div id=\"_iwd_15qeztbf68\" data-taborder=\"true\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2radio\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qeztbf68\" data-parent=\"_iwd_15qezt7c3s\"\r\n                                rootelm=\"\">\r\n                                <div class=\"w2radio_item\"><input type=\"radio\" index=\"0\" tabindex=\"0\"\r\n                                        class=\"w2radio_input\"> <label index=\"0\" class=\"w2radio_label\">Direct\r\n                                        Sales</label></div>\r\n                                <div class=\"w2radio_item\"><input type=\"radio\" index=\"1\" tabindex=\"0\"\r\n                                        class=\"w2radio_input\"> <label index=\"1\"\r\n                                        class=\"w2radio_label\">Transferred</label></div>\r\n                            </div>\r\n                        </td>\r\n                        <th id=\"_iwd_15qezu6vt8\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_th\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qezu6vt8\" data-parent=\"_iwd_15qezr7lp4\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!----> <span id=\"_iwd_15qezucs8g\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2span\" data-role=\"component\"\r\n                                data-uuid=\"_iwd_15qezucs8g\" data-parent=\"_iwd_15qezu6vt8\" rootelm=\"\">Verification</span>\r\n                        </th>\r\n                        <td id=\"_iwd_15qezuhdl8\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_td\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qezuhdl8\" data-parent=\"_iwd_15qezr7lp4\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!---->\r\n                            <div id=\"_iwd_15qezuoo8s\" data-resizable=\"true\" data-taborder=\"true\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2selectbox\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qezuoo8s\" data-parent=\"_iwd_15qezuhdl8\"\r\n                                rootelm=\"\" style=\"width: 100%;\">\r\n                                <table cellspacing=\"0\" cellpadding=\"0\" class=\"w2selectbox_table_main\">\r\n                                    <tbody>\r\n                                        <tr class=\"w2selectbox_row w2selectbox_row_main\">\r\n                                            <td class=\"w2selectbox_col_label\">\r\n                                                <div class=\"w2selectbox_label\">Individual (Public ID Number)</div>\r\n                                            </td>\r\n                                            <td class=\"w2selectbox_col_button\"></td>\r\n                                        </tr>\r\n                                    </tbody>\r\n                                </table>\r\n                            </div>\r\n                        </td>\r\n                        <th id=\"_iwd_15qezvrmmw\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_th\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qezvrmmw\" data-parent=\"_iwd_15qezr7lp4\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!----> <span id=\"_iwd_15qezvzcss\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2span\" data-role=\"component\"\r\n                                data-uuid=\"_iwd_15qezvzcss\" data-parent=\"_iwd_15qezvrmmw\" rootelm=\"\">Nationality</span>\r\n                        </th>\r\n                        <td id=\"_iwd_15qezw56tw\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_td\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qezw56tw\" data-parent=\"_iwd_15qezr7lp4\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!---->\r\n                            <div id=\"_iwd_15qezwcjkg\" data-resizable=\"true\" data-taborder=\"true\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2selectbox\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qezwcjkg\" data-parent=\"_iwd_15qezw56tw\"\r\n                                rootelm=\"\" style=\"width: 100%;\">\r\n                                <table cellspacing=\"0\" cellpadding=\"0\" class=\"w2selectbox_table_main\">\r\n                                    <tbody>\r\n                                        <tr class=\"w2selectbox_row w2selectbox_row_main\">\r\n                                            <td class=\"w2selectbox_col_label\">\r\n                                                <div class=\"w2selectbox_label\">ROK</div>\r\n                                            </td>\r\n                                            <td class=\"w2selectbox_col_button\"></td>\r\n                                        </tr>\r\n                                    </tbody>\r\n                                </table>\r\n                            </div>\r\n                        </td>\r\n                    </tr>\r\n                    <tr id=\"_iwd_15qezxuk8s\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                        class=\"component hammer w2group\" data-role=\"component\" data-uuid=\"_iwd_15qezxuk8s\"\r\n                        data-parent=\"_iwd_15qexj7e4c\" rootelm=\"_iwd_15qexj7e4c\" data-container=\"true\"\r\n                        data-quicktoolbar=\"true\">\r\n                        <!---->\r\n                        <th id=\"_iwd_15qezxzwao\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_th\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qezxzwao\" data-parent=\"_iwd_15qezxuk8s\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!----> <span id=\"_iwd_15qezy4bsc\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2span ast\" data-role=\"component\"\r\n                                data-uuid=\"_iwd_15qezy4bsc\" data-parent=\"_iwd_15qezxzwao\" rootelm=\"\">Occupation</span>\r\n                        </th>\r\n                        <td id=\"_iwd_15qezy7tbs\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_td\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qezy7tbs\" data-parent=\"_iwd_15qezxuk8s\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!----> <input data-v-0f1195ec=\"\" id=\"_iwd_15qezybzmw\" data-resizable=\"true\"\r\n                                data-taborder=\"true\" type=\"text\" readonly=\"readonly\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2input --internal-input-cursor w2input_disabled w2input_ref_binding\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qezybzmw\" data-parent=\"_iwd_15qezy7tbs\"\r\n                                rootelm=\"\" style=\"width: 30%;\"><a id=\"_iwd_15qezyh5z8\" href=\"javascript:void(0);\"\r\n                                data-role=\"component\" data-state=\"init\" data-taborder=\"true\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2anchor2 btn_search\"\r\n                                data-uuid=\"_iwd_15qezyh5z8\" data-parent=\"_iwd_15qezy7tbs\" rootelm=\"\"></a><input\r\n                                data-v-0f1195ec=\"\" id=\"_iwd_15qezym8go\" data-resizable=\"true\" data-taborder=\"true\"\r\n                                type=\"text\" readonly=\"readonly\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2input --internal-input-cursor w2input_disabled w2input_ref_binding\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qezym8go\" data-parent=\"_iwd_15qezy7tbs\"\r\n                                rootelm=\"\" style=\"width: 20%;\"><input data-v-0f1195ec=\"\" id=\"_iwd_15qezypu8w\"\r\n                                data-resizable=\"true\" data-taborder=\"true\" type=\"text\" readonly=\"readonly\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2input --internal-input-cursor w2input_disabled w2input_ref_binding\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qezypu8w\" data-parent=\"_iwd_15qezy7tbs\"\r\n                                rootelm=\"\" style=\"width: 10%;\"></td>\r\n                        <th id=\"_iwd_15qezytgsw\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_th\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qezytgsw\" data-parent=\"_iwd_15qezxuk8s\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!----> <span id=\"_iwd_15qezyy2e0\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2span ast\" data-role=\"component\"\r\n                                data-uuid=\"_iwd_15qezyy2e0\" data-parent=\"_iwd_15qezytgsw\" rootelm=\"\">Driving</span></th>\r\n                        <td id=\"_iwd_15qezz1guc\" tabindex=\"-1\" rowspan=\"1\" colspan=\"3\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_td\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qezz1guc\" data-parent=\"_iwd_15qezxuk8s\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!---->\r\n                            <div id=\"_iwd_15qezzhzzc\" data-resizable=\"true\" data-taborder=\"true\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2selectbox\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qezzhzzc\" data-parent=\"_iwd_15qezz1guc\"\r\n                                rootelm=\"\" style=\"width: 50%;\">\r\n                                <table cellspacing=\"0\" cellpadding=\"0\" class=\"w2selectbox_table_main\">\r\n                                    <tbody>\r\n                                        <tr class=\"w2selectbox_row w2selectbox_row_main\">\r\n                                            <td class=\"w2selectbox_col_label\">\r\n                                                <div class=\"w2selectbox_label\">Yes</div>\r\n                                            </td>\r\n                                            <td class=\"w2selectbox_col_button\"></td>\r\n                                        </tr>\r\n                                    </tbody>\r\n                                </table>\r\n                            </div><input data-v-0f1195ec=\"\" id=\"_iwd_15qf007epw\" data-resizable=\"true\"\r\n                                data-taborder=\"true\" type=\"text\" readonly=\"readonly\"\r\n                                class=\"component-guideline component hammer w2input --internal-input-cursor w2input_disabled\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf007epw\" data-parent=\"_iwd_15qezz1guc\"\r\n                                rootelm=\"\" style=\"width: 16%;\"><input data-v-0f1195ec=\"\" id=\"_iwd_15qf00aves\"\r\n                                data-resizable=\"true\" data-taborder=\"true\" type=\"text\" readonly=\"readonly\"\r\n                                class=\"component-guideline component hammer w2input --internal-input-cursor w2input_disabled\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf00aves\" data-parent=\"_iwd_15qezz1guc\"\r\n                                rootelm=\"\" style=\"width: 16%;\">\r\n                        </td>\r\n                        <th id=\"_iwd_15qf00eamw\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_th\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf00eamw\" data-parent=\"_iwd_15qezxuk8s\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!----> <span id=\"_iwd_15qf00it24\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2span ast\" data-role=\"component\"\r\n                                data-uuid=\"_iwd_15qf00it24\" data-parent=\"_iwd_15qf00eamw\" rootelm=\"\">Acquisition\r\n                                Mode</span></th>\r\n                        <td id=\"_iwd_15qf00mbog\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_td\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf00mbog\" data-parent=\"_iwd_15qezxuk8s\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!---->\r\n                            <div id=\"_iwd_15qf00qmdw\" data-resizable=\"true\" data-taborder=\"true\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2selectbox\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf00qmdw\" data-parent=\"_iwd_15qf00mbog\"\r\n                                rootelm=\"\" style=\"width: 100%;\">\r\n                                <table cellspacing=\"0\" cellpadding=\"0\" class=\"w2selectbox_table_main\">\r\n                                    <tbody>\r\n                                        <tr class=\"w2selectbox_row w2selectbox_row_main\">\r\n                                            <td class=\"w2selectbox_col_label\">\r\n                                                <div class=\"w2selectbox_label\">Online</div>\r\n                                            </td>\r\n                                            <td class=\"w2selectbox_col_button\"></td>\r\n                                        </tr>\r\n                                    </tbody>\r\n                                </table>\r\n                            </div>\r\n                        </td>\r\n                    </tr>\r\n                    <tr id=\"_iwd_15qf01gh0o\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                        class=\"component hammer w2group\" data-role=\"component\" data-uuid=\"_iwd_15qf01gh0o\"\r\n                        data-parent=\"_iwd_15qexj7e4c\" rootelm=\"_iwd_15qexj7e4c\" data-container=\"true\"\r\n                        data-quicktoolbar=\"true\">\r\n                        <!---->\r\n                        <th id=\"_iwd_15qf01kxa4\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_th\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf01kxa4\" data-parent=\"_iwd_15qf01gh0o\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!----> <span id=\"_iwd_15qf01oxnc\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2span ast\" data-role=\"component\"\r\n                                data-uuid=\"_iwd_15qf01oxnc\" data-parent=\"_iwd_15qf01kxa4\" rootelm=\"\">Home Phone</span>\r\n                        </th>\r\n                        <td id=\"_iwd_15qf01si1k\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_td\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf01si1k\" data-parent=\"_iwd_15qf01gh0o\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!---->\r\n                            <div id=\"_iwd_15qf01wtis\" data-resizable=\"true\" data-taborder=\"true\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2selectbox\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf01wtis\" data-parent=\"_iwd_15qf01si1k\"\r\n                                rootelm=\"\" style=\"width: 30%;\">\r\n                                <table cellspacing=\"0\" cellpadding=\"0\" class=\"w2selectbox_table_main\">\r\n                                    <tbody>\r\n                                        <tr class=\"w2selectbox_row w2selectbox_row_main\">\r\n                                            <td class=\"w2selectbox_col_label\">\r\n                                                <div class=\"w2selectbox_label\">Seoul</div>\r\n                                            </td>\r\n                                            <td class=\"w2selectbox_col_button\"></td>\r\n                                        </tr>\r\n                                    </tbody>\r\n                                </table>\r\n                            </div><input data-v-0f1195ec=\"\" id=\"_iwd_15qf036fcc\" data-resizable=\"true\"\r\n                                data-taborder=\"true\" type=\"text\" readonly=\"readonly\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2input --internal-input-cursor w2input_ref_binding\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf036fcc\" data-parent=\"_iwd_15qf01si1k\"\r\n                                rootelm=\"\" style=\"width: 30%;\"><input data-v-0f1195ec=\"\" id=\"_iwd_15qf039xyo\"\r\n                                data-resizable=\"true\" data-taborder=\"true\" type=\"text\" readonly=\"readonly\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2input --internal-input-cursor w2input_ref_binding\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf039xyo\" data-parent=\"_iwd_15qf01si1k\"\r\n                                rootelm=\"\" style=\"width: 30%;\">\r\n                        </td>\r\n                        <th id=\"_iwd_15qf03dbkg\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_th\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf03dbkg\" data-parent=\"_iwd_15qf01gh0o\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!----> <span id=\"_iwd_15qf03hxjg\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2span ast\" data-role=\"component\"\r\n                                data-uuid=\"_iwd_15qf03hxjg\" data-parent=\"_iwd_15qf03dbkg\" rootelm=\"\">Address</span></th>\r\n                        <td id=\"_iwd_15qf03ldro\" tabindex=\"-1\" rowspan=\"1\" colspan=\"5\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_td\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf03ldro\" data-parent=\"_iwd_15qf01gh0o\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!---->\r\n                            <div id=\"_iwd_15qf03xlyw\" data-resizable=\"true\" data-taborder=\"true\"\r\n                                class=\"component-guideline component hammer w2selectbox\" data-role=\"component\"\r\n                                data-uuid=\"_iwd_15qf03xlyw\" data-parent=\"_iwd_15qf03ldro\" rootelm=\"\"\r\n                                style=\"width: 15%;\">\r\n                                <table cellspacing=\"0\" cellpadding=\"0\" class=\"w2selectbox_table_main\">\r\n                                    <tbody>\r\n                                        <tr class=\"w2selectbox_row w2selectbox_row_main\">\r\n                                            <td class=\"w2selectbox_col_label\">\r\n                                                <div class=\"w2selectbox_label\">Road</div>\r\n                                            </td>\r\n                                            <td class=\"w2selectbox_col_button\"></td>\r\n                                        </tr>\r\n                                    </tbody>\r\n                                </table>\r\n                            </div><input data-v-0f1195ec=\"\" id=\"_iwd_15qf04lq98\" data-resizable=\"true\"\r\n                                data-taborder=\"true\" type=\"text\" readonly=\"readonly\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2input --internal-input-cursor w2input_disabled w2input_ref_binding\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf04lq98\" data-parent=\"_iwd_15qf03ldro\"\r\n                                rootelm=\"\" style=\"width: 16%;\"><a id=\"_iwd_15qf04pkww\" href=\"javascript:void(0);\"\r\n                                data-role=\"component\" data-state=\"init\" data-taborder=\"true\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2anchor2 btn_search\"\r\n                                data-uuid=\"_iwd_15qf04pkww\" data-parent=\"_iwd_15qf03ldro\" rootelm=\"\"></a><a\r\n                                id=\"_iwd_15qf04ufdg\" href=\"javascript:void(0);\" data-role=\"component\" data-state=\"init\"\r\n                                data-taborder=\"true\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2anchor2 btn_del\"\r\n                                data-uuid=\"_iwd_15qf04ufdg\" data-parent=\"_iwd_15qf03ldro\" rootelm=\"\"></a><input\r\n                                data-v-0f1195ec=\"\" id=\"_iwd_15qf04z3yw\" data-resizable=\"true\" data-taborder=\"true\"\r\n                                type=\"text\" readonly=\"readonly\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2input --internal-input-cursor w2input_disabled w2input_ref_binding\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf04z3yw\" data-parent=\"_iwd_15qf03ldro\"\r\n                                rootelm=\"\" style=\"width: 25%;\"><input data-v-0f1195ec=\"\" id=\"_iwd_15qf052icg\"\r\n                                data-resizable=\"true\" data-taborder=\"true\" type=\"text\" readonly=\"readonly\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2input --internal-input-cursor w2input_disabled w2input_ref_binding\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf052icg\" data-parent=\"_iwd_15qf03ldro\"\r\n                                rootelm=\"\" style=\"width: 20%;\"><input data-v-0f1195ec=\"\" id=\"_iwd_15qf055ubw\"\r\n                                data-resizable=\"true\" data-taborder=\"true\" type=\"text\" readonly=\"readonly\"\r\n                                class=\"component-guideline component hammer w2input --internal-input-cursor w2input_disabled\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf055ubw\" data-parent=\"_iwd_15qf03ldro\"\r\n                                rootelm=\"\" style=\"width: 5%;\">\r\n                        </td>\r\n                    </tr>\r\n                    <tr id=\"_iwd_15qf059pdg\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                        class=\"component hammer w2group\" data-role=\"component\" data-uuid=\"_iwd_15qf059pdg\"\r\n                        data-parent=\"_iwd_15qexj7e4c\" rootelm=\"_iwd_15qexj7e4c\" data-container=\"true\"\r\n                        data-quicktoolbar=\"true\">\r\n                        <!---->\r\n                        <th id=\"_iwd_15qf05e6ps\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_th\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf05e6ps\" data-parent=\"_iwd_15qf059pdg\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\"><span>Mobile</span> <span id=\"_iwd_15qf06aju8\" tabindex=\"-1\"\r\n                                data-resizable=\"true\" class=\"component-guideline component hammer w2span\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf06aju8\" data-parent=\"_iwd_15qf05e6ps\"\r\n                                rootelm=\"\">Occupation</span></th>\r\n                        <td id=\"_iwd_15qf06ro74\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_td\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf06ro74\" data-parent=\"_iwd_15qf059pdg\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!---->\r\n                            <div id=\"_iwd_15qf06z4ps\" data-resizable=\"true\" data-taborder=\"true\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2selectbox\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf06z4ps\" data-parent=\"_iwd_15qf06ro74\"\r\n                                rootelm=\"\" style=\"width: 30%;\">\r\n                                <table cellspacing=\"0\" cellpadding=\"0\" class=\"w2selectbox_table_main\">\r\n                                    <tbody>\r\n                                        <tr class=\"w2selectbox_row w2selectbox_row_main\">\r\n                                            <td class=\"w2selectbox_col_label\">\r\n                                                <div class=\"w2selectbox_label\">010</div>\r\n                                            </td>\r\n                                            <td class=\"w2selectbox_col_button\"></td>\r\n                                        </tr>\r\n                                    </tbody>\r\n                                </table>\r\n                            </div><input data-v-0f1195ec=\"\" id=\"_iwd_15qf08d8vs\" data-resizable=\"true\"\r\n                                data-taborder=\"true\" type=\"text\" readonly=\"readonly\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2input --internal-input-cursor w2input_ref_binding\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf08d8vs\" data-parent=\"_iwd_15qf06ro74\"\r\n                                rootelm=\"\" style=\"width: 30%;\"><input data-v-0f1195ec=\"\" id=\"_iwd_15qf08h300\"\r\n                                data-resizable=\"true\" data-taborder=\"true\" type=\"text\" readonly=\"readonly\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2input --internal-input-cursor w2input_ref_binding\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf08h300\" data-parent=\"_iwd_15qf06ro74\"\r\n                                rootelm=\"\" style=\"width: 30%;\">\r\n                        </td>\r\n                        <th id=\"_iwd_15qf08l52c\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_th\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf08l52c\" data-parent=\"_iwd_15qf059pdg\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!----> <span id=\"_iwd_15qf08q284\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2span ast\" data-role=\"component\"\r\n                                data-uuid=\"_iwd_15qf08q284\" data-parent=\"_iwd_15qf08l52c\" rootelm=\"\">E-Mail</span></th>\r\n                        <td id=\"_iwd_15qf08ti80\" tabindex=\"-1\" rowspan=\"1\" colspan=\"3\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_td\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf08ti80\" data-parent=\"_iwd_15qf059pdg\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!----> <input data-v-0f1195ec=\"\" id=\"_iwd_15qf09eq6s\" data-resizable=\"true\"\r\n                                data-taborder=\"true\" type=\"text\" readonly=\"readonly\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2input --internal-input-cursor w2input_ref_binding\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf09eq6s\" data-parent=\"_iwd_15qf08ti80\"\r\n                                rootelm=\"\" style=\"width: 30%;\"><span id=\"_iwd_15qf09oqao\" tabindex=\"-1\"\r\n                                data-resizable=\"true\" class=\"component-guideline component hammer w2span ast\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf09oqao\" data-parent=\"_iwd_15qf08ti80\"\r\n                                rootelm=\"\">@</span><input data-v-0f1195ec=\"\" id=\"_iwd_15qf09t63g\" data-resizable=\"true\"\r\n                                data-taborder=\"true\" type=\"text\" readonly=\"readonly\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2input --internal-input-cursor w2input_ref_binding\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf09t63g\" data-parent=\"_iwd_15qf08ti80\"\r\n                                rootelm=\"\" style=\"width: 30%;\">\r\n                            <div id=\"_iwd_15qf09x1iw\" data-resizable=\"true\" data-taborder=\"true\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2selectbox\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf09x1iw\" data-parent=\"_iwd_15qf08ti80\"\r\n                                rootelm=\"\" style=\"width: 30%;\">\r\n                                <table cellspacing=\"0\" cellpadding=\"0\" class=\"w2selectbox_table_main\">\r\n                                    <tbody>\r\n                                        <tr class=\"w2selectbox_row w2selectbox_row_main\">\r\n                                            <td class=\"w2selectbox_col_label\">\r\n                                                <div class=\"w2selectbox_label\">Naver</div>\r\n                                            </td>\r\n                                            <td class=\"w2selectbox_col_button\"></td>\r\n                                        </tr>\r\n                                    </tbody>\r\n                                </table>\r\n                            </div>\r\n                        </td>\r\n                        <th id=\"_iwd_15qf0auphg\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_th\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf0auphg\" data-parent=\"_iwd_15qf059pdg\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!----> <span id=\"_iwd_15qf0b0f48\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2span\" data-role=\"component\"\r\n                                data-uuid=\"_iwd_15qf0b0f48\" data-parent=\"_iwd_15qf0auphg\" rootelm=\"\">Grade</span></th>\r\n                        <td id=\"_iwd_15qf0b4q4s\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_td\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf0b4q4s\" data-parent=\"_iwd_15qf059pdg\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!----> <input data-v-0f1195ec=\"\" id=\"_iwd_15qf0b8y28\" data-resizable=\"true\"\r\n                                data-taborder=\"true\" type=\"text\" readonly=\"readonly\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2input --internal-input-cursor w2input_disabled w2input_ref_binding\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf0b8y28\" data-parent=\"_iwd_15qf0b4q4s\"\r\n                                rootelm=\"\" style=\"width: 90%;\"></td>\r\n                    </tr>\r\n                </table>\r\n            </div>\r\n        </div>\r\n        <div id=\"_iwd_15qf0bdd38\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n            class=\"component-guideline component hammer w2group wq_tbc_box mt10\" data-role=\"component\"\r\n            data-uuid=\"_iwd_15qf0bdd38\" data-parent=\"_iwd_15qeucfujs\" rootelm=\"\" data-container=\"true\"\r\n            data-quicktoolbar=\"true\">\r\n            <!---->\r\n            <div id=\"tcr_Second_A011\" data-resizable=\"true\"\r\n                class=\"component-guideline component hammer default_event_wrap wq_tbc cb\" data-role=\"component\"\r\n                data-uuid=\"_iwd_15qf0bqsvw\" data-parent=\"_iwd_15qf0bdd38\" rootelm=\"\">\r\n                <ul class=\"w2tabcontrol_tabhost \">\r\n                    <li id=\"tabs1\" data-resizable=\"true\"\r\n                        class=\"component hammer w2tabcontrol_li w2tabcontrol_li_0 w2tabcontrol_active w2tabcontrol_over\"\r\n                        data-role=\"component\" data-uuid=\"_iwd_15qf0byue4\" style=\"height: 25px; margin-right: 0px;\">\r\n                        <div class=\"w2tabcontrol_tab_center\"><a>Additional Info</a></div>\r\n                        <div class=\"w2tabcontrol_tab_left\"></div>\r\n                        <div class=\"w2tabcontrol_tab_right\">\r\n                            <div class=\"w2tabcontrol_tab_close\" style=\"display: none;\"></div>\r\n                        </div>\r\n                    </li>\r\n                    <li id=\"tabs2\" data-resizable=\"true\" class=\"component hammer w2tabcontrol_li w2tabcontrol_li_1 \"\r\n                        data-role=\"component\" data-uuid=\"_iwd_15qf0c9ch8\" style=\"height: 25px; margin-right: 0px;\">\r\n                        <div class=\"w2tabcontrol_tab_center\"><a>Contract</a></div>\r\n                        <div class=\"w2tabcontrol_tab_left\"></div>\r\n                        <div class=\"w2tabcontrol_tab_right\">\r\n                            <div class=\"w2tabcontrol_tab_close\" style=\"display: none;\"></div>\r\n                        </div>\r\n                    </li>\r\n                    <li id=\"tabs3\" data-resizable=\"true\" class=\"component hammer w2tabcontrol_li w2tabcontrol_li_2 \"\r\n                        data-role=\"component\" data-uuid=\"_iwd_15qf0cjewg\" style=\"height: 25px; margin-right: 0px;\">\r\n                        <div class=\"w2tabcontrol_tab_center\"><a>Family</a></div>\r\n                        <div class=\"w2tabcontrol_tab_left\"></div>\r\n                        <div class=\"w2tabcontrol_tab_right\">\r\n                            <div class=\"w2tabcontrol_tab_close\" style=\"display: none;\"></div>\r\n                        </div>\r\n                    </li>\r\n                    <li id=\"tabs4\" data-resizable=\"true\" class=\"component hammer w2tabcontrol_li w2tabcontrol_li_3 \"\r\n                        data-role=\"component\" data-uuid=\"_iwd_15qf0crap4\" style=\"height: 25px; margin-right: 0px;\">\r\n                        <div class=\"w2tabcontrol_tab_center\"><a>Policy</a></div>\r\n                        <div class=\"w2tabcontrol_tab_left\"></div>\r\n                        <div class=\"w2tabcontrol_tab_right\">\r\n                            <div class=\"w2tabcontrol_tab_close\" style=\"display: none;\"></div>\r\n                        </div>\r\n                    </li>\r\n                    <li id=\"tabs5\" data-resizable=\"true\" class=\"component hammer w2tabcontrol_li w2tabcontrol_li_4 \"\r\n                        data-role=\"component\" data-uuid=\"_iwd_15qf0cyt2g\" style=\"height: 25px; margin-right: 0px;\">\r\n                        <div class=\"w2tabcontrol_tab_center\"><a>Notices</a></div>\r\n                        <div class=\"w2tabcontrol_tab_left\"></div>\r\n                        <div class=\"w2tabcontrol_tab_right\">\r\n                            <div class=\"w2tabcontrol_tab_close\" style=\"display: none;\"></div>\r\n                        </div>\r\n                    </li>\r\n                    <li id=\"tabs6\" data-resizable=\"true\" class=\"component hammer w2tabcontrol_li w2tabcontrol_li_5 \"\r\n                        data-role=\"component\" data-uuid=\"_iwd_15qf0d6obo\" style=\"height: 25px; margin-right: 0px;\">\r\n                        <div class=\"w2tabcontrol_tab_center\"><a>Contact</a></div>\r\n                        <div class=\"w2tabcontrol_tab_left\"></div>\r\n                        <div class=\"w2tabcontrol_tab_right\">\r\n                            <div class=\"w2tabcontrol_tab_close\" style=\"display: none;\"></div>\r\n                        </div>\r\n                    </li>\r\n                    <li id=\"tabs7\" data-resizable=\"true\" class=\"component hammer w2tabcontrol_li w2tabcontrol_li_6 \"\r\n                        data-role=\"component\" data-uuid=\"_iwd_15qf0debxw\" style=\"height: 25px; margin-right: 0px;\">\r\n                        <div class=\"w2tabcontrol_tab_center\"><a>CRM</a></div>\r\n                        <div class=\"w2tabcontrol_tab_left\"></div>\r\n                        <div class=\"w2tabcontrol_tab_right\">\r\n                            <div class=\"w2tabcontrol_tab_close\" style=\"display: none;\"></div>\r\n                        </div>\r\n                    </li>\r\n                </ul>\r\n                <div class=\"w2tabcontrol_container default_tabcontainer_style\">\r\n                    <div id=\"content1\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                        class=\"component-guideline component hammer w2group component hammer w2tabcontrol_contents w2group\"\r\n                        data-role=\"component\" data-uuid=\"_iwd_15qf0dm10w\" data-parent=\"_iwd_15qf0bqsvw\"\r\n                        data-container=\"true\" data-quicktoolbar=\"true\"\r\n                        style=\"overflow: auto; display: block; visibility: inherit;\">\r\n                        <!---->\r\n                    </div>\r\n                    <div id=\"content2\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                        class=\"component-guideline component hammer w2group component hammer w2tabcontrol_contents w2group\"\r\n                        data-role=\"component\" data-uuid=\"_iwd_15qf0drovs\" data-parent=\"_iwd_15qf0bqsvw\"\r\n                        data-container=\"true\" data-quicktoolbar=\"true\"\r\n                        style=\"overflow: auto; display: none; visibility: hidden;\">\r\n                        <!---->\r\n                        <div id=\"_iwd_15qf0dweek\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group gvwbox mt10\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf0dweek\" data-parent=\"_iwd_15qf0drovs\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!---->\r\n                            <div id=\"_iwd_15qf11wi1k\" data-resizable=\"true\" data-press=\"false\" data-taborder=\"true\"\r\n                                class=\"component-guideline component hammer w2grid wq_gvw\" data-role=\"component\"\r\n                                data-uuid=\"_iwd_15qf11wi1k\" data-parent=\"_iwd_15qf0dweek\" rootelm=\"\"\r\n                                style=\"overflow: auto; border-spacing: 0px; border-collapse: collapse; table-layout: fixed; height: 100px;\">\r\n                                <!---->\r\n                                <div mark=\"grid.mainDiv\">\r\n                                    <table width=\"1310\" class=\"component-guideline component hammer\"\r\n                                        data-role=\"component\" data-uuid=\"_iwd_15qf1apezs\" data-parent=\"_iwd_15qf11wi1k\"\r\n                                        style=\"border-spacing: 0px; border-collapse: collapse; table-layout: fixed;\">\r\n                                        <colgroup>\r\n                                            <!---->\r\n                                            <!---->\r\n                                            <col width=\"120\">\r\n                                            <col width=\"80\">\r\n                                            <col width=\"80\">\r\n                                            <col width=\"150\">\r\n                                            <col width=\"120\">\r\n                                            <col width=\"120\">\r\n                                            <col width=\"100\">\r\n                                            <col width=\"120\">\r\n                                            <col width=\"100\">\r\n                                            <col width=\"120\">\r\n                                            <col width=\"100\">\r\n                                            <col width=\"100\">\r\n                                        </colgroup>\r\n                                        <thead class=\"gridHeaderTableDefault\">\r\n                                            <tr class=\"component hammer gridHeaderTRDefault\" data-role=\"component\"\r\n                                                data-uuid=\"_iwd_15qf1b18zw\" style=\"height: 20px;\">\r\n                                                <!---->\r\n                                                <!---->\r\n                                                <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                    width=\"120\" colspan=\"\" rowspan=\"2\" rootelm=\"_iwd_15qf11wi1k\"\r\n                                                    class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf1b8sak\"\r\n                                                    data-parent=\"_iwd_15qf1b18zw\" style=\"height: 20px;\">\r\n                                                    <div class=\"grid_column_text_input_type\">\r\n                                                        <nobr>Policy No</nobr>\r\n                                                    </div>\r\n                                                </th>\r\n                                                <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                    width=\"80\" colspan=\"\" rowspan=\"2\" rootelm=\"_iwd_15qf11wi1k\"\r\n                                                    class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf1gli0w\"\r\n                                                    data-parent=\"_iwd_15qf1b18zw\" style=\"height: 20px;\">\r\n                                                    <div class=\"grid_column_text_input_type\">\r\n                                                        <nobr>Contractor</nobr>\r\n                                                    </div>\r\n                                                </th>\r\n                                                <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                    width=\"80\" colspan=\"\" rowspan=\"2\" rootelm=\"_iwd_15qf11wi1k\"\r\n                                                    class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf1gzi1c\"\r\n                                                    data-parent=\"_iwd_15qf1b18zw\" style=\"height: 20px;\">\r\n                                                    <div class=\"grid_column_text_input_type\">\r\n                                                        <nobr>Insured</nobr>\r\n                                                    </div>\r\n                                                </th>\r\n                                                <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                    width=\"150\" colspan=\"\" rowspan=\"2\" rootelm=\"_iwd_15qf11wi1k\"\r\n                                                    class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf1h8szo\"\r\n                                                    data-parent=\"_iwd_15qf1b18zw\" style=\"height: 20px;\">\r\n                                                    <div class=\"grid_column_text_input_type\">\r\n                                                        <nobr>Product</nobr>\r\n                                                    </div>\r\n                                                </th>\r\n                                                <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                    width=\"120\" colspan=\"\" rowspan=\"2\" rootelm=\"_iwd_15qf11wi1k\"\r\n                                                    class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf1hhe68\"\r\n                                                    data-parent=\"_iwd_15qf1b18zw\" style=\"height: 20px;\">\r\n                                                    <div class=\"grid_column_text_input_type\">\r\n                                                        <nobr>Signing Date</nobr>\r\n                                                    </div>\r\n                                                </th>\r\n                                                <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                    width=\"120\" colspan=\"\" rowspan=\"2\" rootelm=\"_iwd_15qf11wi1k\"\r\n                                                    class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf1homwc\"\r\n                                                    data-parent=\"_iwd_15qf1b18zw\" style=\"height: 20px;\">\r\n                                                    <div class=\"grid_column_text_input_type\">\r\n                                                        <nobr>Expiration</nobr>\r\n                                                    </div>\r\n                                                </th>\r\n                                                <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                    width=\"100\" colspan=\"\" rowspan=\"2\" rootelm=\"_iwd_15qf11wi1k\"\r\n                                                    class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf1hwzto\"\r\n                                                    data-parent=\"_iwd_15qf1b18zw\" style=\"height: 20px;\">\r\n                                                    <div class=\"grid_column_text_input_type\">\r\n                                                        <nobr>Status</nobr>\r\n                                                    </div>\r\n                                                </th>\r\n                                                <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                    width=\"120\" colspan=\"2\" rowspan=\"\" rootelm=\"_iwd_15qf11wi1k\"\r\n                                                    class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf1i6cjw\"\r\n                                                    data-parent=\"_iwd_15qf1b18zw\" style=\"height: 20px;\">\r\n                                                    <div class=\"grid_column_text_input_type\">\r\n                                                        <nobr>Insurance Table</nobr>\r\n                                                    </div>\r\n                                                </th>\r\n                                                <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                    width=\"120\" colspan=\"\" rowspan=\"2\" rootelm=\"_iwd_15qf11wi1k\"\r\n                                                    class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf1ih14c\"\r\n                                                    data-parent=\"_iwd_15qf1b18zw\" style=\"height: 20px;\">\r\n                                                    <div class=\"grid_column_text_input_type\">\r\n                                                        <nobr>Last premium paid on</nobr>\r\n                                                    </div>\r\n                                                </th>\r\n                                                <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                    width=\"100\" colspan=\"\" rowspan=\"2\" rootelm=\"_iwd_15qf11wi1k\"\r\n                                                    class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf1iqu7g\"\r\n                                                    data-parent=\"_iwd_15qf1b18zw\" style=\"height: 20px;\">\r\n                                                    <div class=\"grid_column_text_input_type\">\r\n                                                        <nobr>Last payment number</nobr>\r\n                                                    </div>\r\n                                                </th>\r\n                                                <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                    width=\"100\" colspan=\"\" rowspan=\"2\" rootelm=\"_iwd_15qf11wi1k\"\r\n                                                    class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf1j0htc\"\r\n                                                    data-parent=\"_iwd_15qf1b18zw\" style=\"height: 20px;\">\r\n                                                    <div class=\"grid_column_text_input_type\">\r\n                                                        <nobr>Final date</nobr>\r\n                                                    </div>\r\n                                                </th>\r\n                                            </tr>\r\n                                            <tr class=\"component hammer gridHeaderTRDefault\" data-role=\"component\"\r\n                                                data-uuid=\"_iwd_15qf1jb2zk\" style=\"height: 20px;\">\r\n                                                <!---->\r\n                                                <!---->\r\n                                                <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                    width=\"120\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf11wi1k\"\r\n                                                    class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf1jjf2c\"\r\n                                                    data-parent=\"_iwd_15qf1jb2zk\">\r\n                                                    <div class=\"grid_column_text_input_type\">\r\n                                                        <nobr>Add payment</nobr>\r\n                                                    </div>\r\n                                                </th>\r\n                                                <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                    width=\"100\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf11wi1k\"\r\n                                                    class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf1jvxok\"\r\n                                                    data-parent=\"_iwd_15qf1jb2zk\">\r\n                                                    <div class=\"grid_column_text_input_type\">\r\n                                                        <nobr>amount</nobr>\r\n                                                    </div>\r\n                                                </th>\r\n                                            </tr>\r\n                                        </thead>\r\n                                    </table>\r\n                                    <div mark=\"grid.dataLayer\">\r\n                                        <table width=\"1310\" class=\"component-guideline component hammer\"\r\n                                            data-role=\"component\" data-uuid=\"_iwd_15qf1sll9s\"\r\n                                            data-parent=\"_iwd_15qf11wi1k\"\r\n                                            style=\"border-spacing: 0px; border-collapse: collapse; table-layout: fixed;\">\r\n                                            <colgroup>\r\n                                                <!---->\r\n                                                <!---->\r\n                                                <col width=\"120\">\r\n                                                <col width=\"80\">\r\n                                                <col width=\"80\">\r\n                                                <col width=\"150\">\r\n                                                <col width=\"120\">\r\n                                                <col width=\"120\">\r\n                                                <col width=\"100\">\r\n                                                <col width=\"120\">\r\n                                                <col width=\"100\">\r\n                                                <col width=\"120\">\r\n                                                <col width=\"100\">\r\n                                                <col width=\"100\">\r\n                                            </colgroup>\r\n                                            <tbody class=\"gridBodyTableDefault\">\r\n                                                <tr class=\"component hammer gridBodyTRDefault\" data-role=\"component\"\r\n                                                    data-uuid=\"_iwd_15qf1sz68k\" style=\"height: 20px;\">\r\n                                                    <!---->\r\n                                                    <!---->\r\n                                                    <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"120\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf11wi1k\"\r\n                                                        class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf1t4pb8\"\r\n                                                        data-parent=\"_iwd_15qf1sz68k\" style=\"height: 20px;\">\r\n                                                        <div class=\"grid_column_text_input_type\">\r\n                                                            <nobr></nobr>\r\n                                                        </div>\r\n                                                    </td>\r\n                                                    <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"80\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf11wi1k\"\r\n                                                        class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf1tgafw\"\r\n                                                        data-parent=\"_iwd_15qf1sz68k\" style=\"height: 20px;\">\r\n                                                        <div class=\"grid_column_text_input_type\">\r\n                                                            <nobr></nobr>\r\n                                                        </div>\r\n                                                    </td>\r\n                                                    <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"80\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf11wi1k\"\r\n                                                        class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf1tn014\"\r\n                                                        data-parent=\"_iwd_15qf1sz68k\" style=\"height: 20px;\">\r\n                                                        <div class=\"grid_column_text_input_type\">\r\n                                                            <nobr></nobr>\r\n                                                        </div>\r\n                                                    </td>\r\n                                                    <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"150\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf11wi1k\"\r\n                                                        class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf1tsoco\"\r\n                                                        data-parent=\"_iwd_15qf1sz68k\">\r\n                                                        <div class=\"grid_column_text_input_type\">\r\n                                                            <nobr></nobr>\r\n                                                        </div>\r\n                                                    </td>\r\n                                                    <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"120\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf11wi1k\"\r\n                                                        class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf1ty298\"\r\n                                                        data-parent=\"_iwd_15qf1sz68k\">\r\n                                                        <div class=\"grid_column_text_input_type\">\r\n                                                            <nobr></nobr>\r\n                                                        </div>\r\n                                                    </td>\r\n                                                    <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"120\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf11wi1k\"\r\n                                                        class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf1u3kk4\"\r\n                                                        data-parent=\"_iwd_15qf1sz68k\">\r\n                                                        <div class=\"grid_column_text_input_type\">\r\n                                                            <nobr></nobr>\r\n                                                        </div>\r\n                                                    </td>\r\n                                                    <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"100\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf11wi1k\"\r\n                                                        class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf1u8wos\"\r\n                                                        data-parent=\"_iwd_15qf1sz68k\">\r\n                                                        <div class=\"grid_column_text_input_type\">\r\n                                                            <nobr></nobr>\r\n                                                        </div>\r\n                                                    </td>\r\n                                                    <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"120\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf11wi1k\"\r\n                                                        class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf1ue3f0\"\r\n                                                        data-parent=\"_iwd_15qf1sz68k\">\r\n                                                        <div class=\"grid_column_text_input_type\">\r\n                                                            <nobr></nobr>\r\n                                                        </div>\r\n                                                    </td>\r\n                                                    <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"100\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf11wi1k\"\r\n                                                        class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf1uj828\"\r\n                                                        data-parent=\"_iwd_15qf1sz68k\">\r\n                                                        <div class=\"grid_column_text_input_type\">\r\n                                                            <nobr></nobr>\r\n                                                        </div>\r\n                                                    </td>\r\n                                                    <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"120\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf11wi1k\"\r\n                                                        class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf1uoivo\"\r\n                                                        data-parent=\"_iwd_15qf1sz68k\">\r\n                                                        <div class=\"grid_column_text_input_type\">\r\n                                                            <nobr></nobr>\r\n                                                        </div>\r\n                                                    </td>\r\n                                                    <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"100\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf11wi1k\"\r\n                                                        class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf1utpzs\"\r\n                                                        data-parent=\"_iwd_15qf1sz68k\">\r\n                                                        <div class=\"grid_column_text_input_type\">\r\n                                                            <nobr></nobr>\r\n                                                        </div>\r\n                                                    </td>\r\n                                                    <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"100\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf11wi1k\"\r\n                                                        class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf1uzqw4\"\r\n                                                        data-parent=\"_iwd_15qf1sz68k\">\r\n                                                        <div class=\"grid_column_text_input_type\">\r\n                                                            <nobr></nobr>\r\n                                                        </div>\r\n                                                    </td>\r\n                                                </tr>\r\n                                            </tbody>\r\n                                        </table>\r\n                                    </div>\r\n                                    <!---->\r\n                                </div>\r\n                            </div>\r\n                        </div>\r\n                    </div>\r\n                    <div id=\"content3\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                        class=\"component-guideline component hammer w2group component hammer w2tabcontrol_contents w2group\"\r\n                        data-role=\"component\" data-uuid=\"_iwd_15qf1v611s\" data-parent=\"_iwd_15qf0bqsvw\"\r\n                        data-container=\"true\" data-quicktoolbar=\"true\"\r\n                        style=\"overflow: auto; display: none; visibility: hidden;\">\r\n                        <!---->\r\n                        <div id=\"_iwd_15qf1v9dcc\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group gvwbox mt10\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf1v9dcc\" data-parent=\"_iwd_15qf1v611s\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!---->\r\n                            <div id=\"_iwd_15qf1ve08o\" data-resizable=\"true\" data-press=\"false\" data-taborder=\"true\"\r\n                                class=\"component-guideline component hammer w2grid wq_gvw\" data-role=\"component\"\r\n                                data-uuid=\"_iwd_15qf1ve08o\" data-parent=\"_iwd_15qf1v9dcc\" rootelm=\"\"\r\n                                style=\"overflow: auto; border-spacing: 0px; border-collapse: collapse; table-layout: fixed; height: 100px;\">\r\n                                <!---->\r\n                                <div mark=\"grid.mainDiv\">\r\n                                    <table width=\"890\" class=\"component-guideline component hammer\"\r\n                                        data-role=\"component\" data-uuid=\"_iwd_15qf1vn7yc\" data-parent=\"_iwd_15qf1ve08o\"\r\n                                        style=\"border-spacing: 0px; border-collapse: collapse; table-layout: fixed;\">\r\n                                        <colgroup>\r\n                                            <!---->\r\n                                            <!---->\r\n                                            <col width=\"140\">\r\n                                            <col width=\"171\">\r\n                                            <col width=\"95\">\r\n                                            <col width=\"100\">\r\n                                            <col width=\"145\">\r\n                                            <col width=\"189\">\r\n                                            <col width=\"50\">\r\n                                        </colgroup>\r\n                                        <thead class=\"gridHeaderTableDefault\">\r\n                                            <tr class=\"component hammer gridHeaderTRDefault\" data-role=\"component\"\r\n                                                data-uuid=\"_iwd_15qf1vr3ro\" style=\"height: 20px;\">\r\n                                                <!---->\r\n                                                <!---->\r\n                                                <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                    width=\"140\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf1ve08o\"\r\n                                                    class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf1vvlvs\"\r\n                                                    data-parent=\"_iwd_15qf1vr3ro\">\r\n                                                    <div class=\"grid_column_text_input_type\">\r\n                                                        <nobr>Relation</nobr>\r\n                                                    </div>\r\n                                                </th>\r\n                                                <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                    width=\"171\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf1ve08o\"\r\n                                                    class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf1wahu8\"\r\n                                                    data-parent=\"_iwd_15qf1vr3ro\">\r\n                                                    <div class=\"grid_column_text_input_type\">\r\n                                                        <nobr>Public ID Number</nobr>\r\n                                                    </div>\r\n                                                </th>\r\n                                                <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                    width=\"95\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf1ve08o\"\r\n                                                    class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf1whgrk\"\r\n                                                    data-parent=\"_iwd_15qf1vr3ro\">\r\n                                                    <div class=\"grid_column_text_input_type\">\r\n                                                        <nobr>Sex</nobr>\r\n                                                    </div>\r\n                                                </th>\r\n                                                <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                    width=\"100\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf1ve08o\"\r\n                                                    class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf1wn4bc\"\r\n                                                    data-parent=\"_iwd_15qf1vr3ro\">\r\n                                                    <div class=\"grid_column_text_input_type\">\r\n                                                        <nobr>Age</nobr>\r\n                                                    </div>\r\n                                                </th>\r\n                                                <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                    width=\"145\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf1ve08o\"\r\n                                                    class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf1wsizo\"\r\n                                                    data-parent=\"_iwd_15qf1vr3ro\">\r\n                                                    <div class=\"grid_column_text_input_type\">\r\n                                                        <nobr>Occupation</nobr>\r\n                                                    </div>\r\n                                                </th>\r\n                                                <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                    width=\"189\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf1ve08o\"\r\n                                                    class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf1wy0zg\"\r\n                                                    data-parent=\"_iwd_15qf1vr3ro\">\r\n                                                    <div class=\"grid_column_text_input_type\">\r\n                                                        <nobr>Mobile</nobr>\r\n                                                    </div>\r\n                                                </th>\r\n                                                <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                    width=\"50\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf1ve08o\"\r\n                                                    class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf1x3hig\"\r\n                                                    data-parent=\"_iwd_15qf1vr3ro\">\r\n                                                    <div class=\"grid_column_checkbox_input_type\">\r\n                                                        <nobr></nobr>\r\n                                                    </div>\r\n                                                </th>\r\n                                            </tr>\r\n                                        </thead>\r\n                                    </table>\r\n                                    <div mark=\"grid.dataLayer\">\r\n                                        <table width=\"890\" class=\"component-guideline component hammer\"\r\n                                            data-role=\"component\" data-uuid=\"_iwd_15qf1x972g\"\r\n                                            data-parent=\"_iwd_15qf1ve08o\"\r\n                                            style=\"border-spacing: 0px; border-collapse: collapse; table-layout: fixed;\">\r\n                                            <colgroup>\r\n                                                <!---->\r\n                                                <!---->\r\n                                                <col width=\"140\">\r\n                                                <col width=\"171\">\r\n                                                <col width=\"95\">\r\n                                                <col width=\"100\">\r\n                                                <col width=\"145\">\r\n                                                <col width=\"189\">\r\n                                                <col width=\"50\">\r\n                                            </colgroup>\r\n                                            <tbody class=\"gridBodyTableDefault\">\r\n                                                <tr class=\"component hammer gridBodyTRDefault\" data-role=\"component\"\r\n                                                    data-uuid=\"_iwd_15qf1xcvxs\" style=\"height: 20px;\">\r\n                                                    <!---->\r\n                                                    <!---->\r\n                                                    <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"140\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf1ve08o\"\r\n                                                        class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf1xgyuo\"\r\n                                                        data-parent=\"_iwd_15qf1xcvxs\">\r\n                                                        <div class=\"grid_column_text_input_type\">\r\n                                                            <nobr></nobr>\r\n                                                        </div>\r\n                                                    </td>\r\n                                                    <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"171\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf1ve08o\"\r\n                                                        class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf1xqh24\"\r\n                                                        data-parent=\"_iwd_15qf1xcvxs\" style=\"height: 20px;\">\r\n                                                        <div class=\"grid_column_text_input_type\">\r\n                                                            <nobr></nobr>\r\n                                                        </div>\r\n                                                    </td>\r\n                                                    <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"95\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf1ve08o\"\r\n                                                        class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf1xw27s\"\r\n                                                        data-parent=\"_iwd_15qf1xcvxs\" style=\"height: 20px;\">\r\n                                                        <div class=\"grid_column_selectbox_input_type\">\r\n                                                            <!---->\r\n                                                        </div>\r\n                                                    </td>\r\n                                                    <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"100\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf1ve08o\"\r\n                                                        class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf1ypcx8\"\r\n                                                        data-parent=\"_iwd_15qf1xcvxs\">\r\n                                                        <div class=\"grid_column_text_input_type\">\r\n                                                            <nobr></nobr>\r\n                                                        </div>\r\n                                                    </td>\r\n                                                    <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"145\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf1ve08o\"\r\n                                                        class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf1z2a78\"\r\n                                                        data-parent=\"_iwd_15qf1xcvxs\">\r\n                                                        <div class=\"grid_column_text_input_type\">\r\n                                                            <nobr></nobr>\r\n                                                        </div>\r\n                                                    </td>\r\n                                                    <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"189\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf1ve08o\"\r\n                                                        class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf1z8wjs\"\r\n                                                        data-parent=\"_iwd_15qf1xcvxs\">\r\n                                                        <div class=\"grid_column_text_input_type\">\r\n                                                            <nobr></nobr>\r\n                                                        </div>\r\n                                                    </td>\r\n                                                    <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"70\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf1ve08o\"\r\n                                                        class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf1zf3rw\"\r\n                                                        data-parent=\"_iwd_15qf1xcvxs\">\r\n                                                        <div class=\"grid_column_checkbox_input_type\">\r\n                                                            <!---->\r\n                                                        </div>\r\n                                                    </td>\r\n                                                </tr>\r\n                                            </tbody>\r\n                                        </table>\r\n                                    </div>\r\n                                    <!---->\r\n                                </div>\r\n                            </div>\r\n                        </div>\r\n                    </div>\r\n                    <div id=\"content4\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                        class=\"component-guideline component hammer w2group component hammer w2tabcontrol_contents w2group\"\r\n                        data-role=\"component\" data-uuid=\"_iwd_15qf1zntw8\" data-parent=\"_iwd_15qf0bqsvw\"\r\n                        data-container=\"true\" data-quicktoolbar=\"true\"\r\n                        style=\"overflow: auto; display: none; visibility: hidden;\">\r\n                        <!---->\r\n                        <div id=\"_iwd_15qf1zsikg\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group tbbox mt10\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf1zsikg\" data-parent=\"_iwd_15qf1zntw8\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!---->\r\n                            <table id=\"_iwd_15qf1zv5mo\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2group w2tb tb\" data-role=\"component\"\r\n                                data-uuid=\"_iwd_15qf1zv5mo\" data-parent=\"_iwd_15qf1zsikg\" rootelm=\"\"\r\n                                data-container=\"true\" data-quicktoolbar=\"true\" style=\"position: relative; width: 100%;\">\r\n                                <!---->\r\n                                <colgroup id=\"_iwd_15qf20bj24\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\"\r\n                                    data-resizable=\"true\" class=\"component-guideline component hammer w2group\"\r\n                                    data-role=\"component\" data-uuid=\"_iwd_15qf20bj24\" data-parent=\"_iwd_15qf1zv5mo\"\r\n                                    rootelm=\"_iwd_15qf1zv5mo\" data-container=\"true\" data-quicktoolbar=\"true\">\r\n                                    <!---->\r\n                                    <col id=\"_iwd_15qf20fx08\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\"\r\n                                        data-resizable=\"true\" class=\"component-guideline component hammer w2group\"\r\n                                        data-role=\"component\" data-uuid=\"_iwd_15qf20fx08\" data-parent=\"_iwd_15qf20bj24\"\r\n                                        rootelm=\"\" data-container=\"true\" data-quicktoolbar=\"true\" style=\"width: 110px;\">\r\n                                    <col id=\"_iwd_15qf20k434\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\"\r\n                                        data-resizable=\"true\" class=\"component-guideline component hammer w2group\"\r\n                                        data-role=\"component\" data-uuid=\"_iwd_15qf20k434\" data-parent=\"_iwd_15qf20bj24\"\r\n                                        rootelm=\"\" data-container=\"true\" data-quicktoolbar=\"true\">\r\n                                </colgroup>\r\n                                <tr id=\"_iwd_15qf20o0io\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                                    class=\"component hammer w2group\" data-role=\"component\" data-uuid=\"_iwd_15qf20o0io\"\r\n                                    data-parent=\"_iwd_15qf1zv5mo\" rootelm=\"_iwd_15qf1zv5mo\" data-container=\"true\"\r\n                                    data-quicktoolbar=\"true\">\r\n                                    <!---->\r\n                                    <th id=\"_iwd_15qf20rhzc\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                                        class=\"component-guideline component hammer w2group w2tb_th\"\r\n                                        data-role=\"component\" data-uuid=\"_iwd_15qf20rhzc\" data-parent=\"_iwd_15qf20o0io\"\r\n                                        rootelm=\"\" data-container=\"true\" data-quicktoolbar=\"true\">\r\n                                        <!----> <span id=\"_iwd_15qf20vyjw\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                            class=\"component-guideline component hammer w2span\" data-role=\"component\"\r\n                                            data-uuid=\"_iwd_15qf20vyjw\" data-parent=\"_iwd_15qf20rhzc\"\r\n                                            rootelm=\"\">Period</span></th>\r\n                                    <td id=\"_iwd_15qf20yz1g\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                                        class=\"component-guideline component hammer w2group w2tb_td\"\r\n                                        data-role=\"component\" data-uuid=\"_iwd_15qf20yz1g\" data-parent=\"_iwd_15qf20o0io\"\r\n                                        rootelm=\"\" data-container=\"true\" data-quicktoolbar=\"true\">\r\n                                        <!---->\r\n                                        <div id=\"_iwd_15qf2c2fio\" data-taborder=\"true\" data-resizable=\"true\"\r\n                                            class=\"component-guideline component hammer default_binding_wrap w2inputCalendar_div ast\"\r\n                                            data-role=\"component\" data-uuid=\"_iwd_15qf2c2fio\"\r\n                                            data-parent=\"_iwd_15qf20yz1g\" rootelm=\"\"\r\n                                            style=\"width: 120px; margin-left: 5px;\">\r\n                                            <div class=\"w2inputCalendar_div_input\" style=\"width: 100%;\"><input\r\n                                                    tabindex=\"-1\" readonly=\"readonly\" class=\"w2inputCalendar_divInput\"\r\n                                                    style=\"width: calc(100% - 25px); height: 100%; box-sizing: border-box;\">\r\n                                                <div class=\"w2inputCalendar_div_img\"\r\n                                                    style=\"display: flex; align-items: center;\"><button tabindex=\"-1\"\r\n                                                        readonly=\"readonly\" class=\"w2inputCalendar_button\"\r\n                                                        style=\"background-image: url(&quot;/websquare/uiplugin/inputCalendar/images/icon_calendar.gif&quot;);\"></button>\r\n                                                </div>\r\n                                            </div>\r\n                                        </div><span id=\"_iwd_15qf2ca0cw\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                            class=\"component-guideline component hammer w2span\" data-role=\"component\"\r\n                                            data-uuid=\"_iwd_15qf2ca0cw\" data-parent=\"_iwd_15qf20yz1g\" rootelm=\"\"\r\n                                            style=\"position: relative;\">~</span>\r\n                                        <div id=\"_iwd_15qf2cico0\" data-taborder=\"true\" data-resizable=\"true\"\r\n                                            class=\"component-guideline component hammer default_binding_wrap w2inputCalendar_div ast\"\r\n                                            data-role=\"component\" data-uuid=\"_iwd_15qf2cico0\"\r\n                                            data-parent=\"_iwd_15qf20yz1g\" rootelm=\"\" style=\"width: 120px;\">\r\n                                            <div class=\"w2inputCalendar_div_input\" style=\"width: 100%;\"><input\r\n                                                    tabindex=\"-1\" readonly=\"readonly\" class=\"w2inputCalendar_divInput\"\r\n                                                    style=\"width: calc(100% - 25px); height: 100%; box-sizing: border-box;\">\r\n                                                <div class=\"w2inputCalendar_div_img\"\r\n                                                    style=\"display: flex; align-items: center;\"><button tabindex=\"-1\"\r\n                                                        readonly=\"readonly\" class=\"w2inputCalendar_button\"\r\n                                                        style=\"background-image: url(&quot;/websquare/uiplugin/inputCalendar/images/icon_calendar.gif&quot;);\"></button>\r\n                                                </div>\r\n                                            </div>\r\n                                        </div>\r\n                                        <div id=\"_iwd_15qf2crgtw\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\"\r\n                                            data-resizable=\"true\"\r\n                                            class=\"component-guideline component hammer w2group fr\"\r\n                                            data-role=\"component\" data-uuid=\"_iwd_15qf2crgtw\"\r\n                                            data-parent=\"_iwd_15qf20yz1g\" rootelm=\"\" data-container=\"true\"\r\n                                            data-quicktoolbar=\"true\">\r\n                                            <!----> <a id=\"_iwd_15qf2cx1zk\" href=\"javascript:void(0);\"\r\n                                                data-role=\"component\" data-state=\"init\" data-taborder=\"true\"\r\n                                                data-resizable=\"true\"\r\n                                                class=\"component-guideline component hammer w2anchor2 btn_cm\"\r\n                                                data-uuid=\"_iwd_15qf2cx1zk\" data-parent=\"_iwd_15qf2crgtw\"\r\n                                                rootelm=\"\">Policy Plan</a><a id=\"_iwd_15qf2d506c\"\r\n                                                href=\"javascript:void(0);\" data-role=\"component\" data-state=\"init\"\r\n                                                data-taborder=\"true\" data-resizable=\"true\"\r\n                                                class=\"component-guideline component hammer w2anchor2 btn_cm\"\r\n                                                data-uuid=\"_iwd_15qf2d506c\" data-parent=\"_iwd_15qf2crgtw\"\r\n                                                rootelm=\"\">Subscription Details</a><a id=\"_iwd_15qf2dazas\"\r\n                                                href=\"javascript:void(0);\" data-role=\"component\" data-state=\"init\"\r\n                                                data-taborder=\"true\" data-resizable=\"true\"\r\n                                                class=\"component-guideline component hammer w2anchor2 btn_cm\"\r\n                                                data-uuid=\"_iwd_15qf2dazas\" data-parent=\"_iwd_15qf2crgtw\"\r\n                                                rootelm=\"\">Search</a></div>\r\n                                    </td>\r\n                                </tr>\r\n                            </table>\r\n                        </div>\r\n                        <div id=\"_iwd_15qf2dhx80\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group gvwbox\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf2dhx80\" data-parent=\"_iwd_15qf1zntw8\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!---->\r\n                            <div id=\"_iwd_15qf2dnco4\" data-resizable=\"true\" data-press=\"false\" data-taborder=\"true\"\r\n                                class=\"component-guideline component hammer w2grid wq_gvw\" data-role=\"component\"\r\n                                data-uuid=\"_iwd_15qf2dnco4\" data-parent=\"_iwd_15qf2dhx80\" rootelm=\"\"\r\n                                style=\"overflow: auto; border-spacing: 0px; border-collapse: collapse; table-layout: fixed; height: 100px;\">\r\n                                <!---->\r\n                                <div mark=\"grid.mainDiv\">\r\n                                    <table width=\"1210\" class=\"component-guideline component hammer\"\r\n                                        data-role=\"component\" data-uuid=\"_iwd_15qf2dx1cw\" data-parent=\"_iwd_15qf2dnco4\"\r\n                                        style=\"border-spacing: 0px; border-collapse: collapse; table-layout: fixed;\">\r\n                                        <colgroup>\r\n                                            <!---->\r\n                                            <!---->\r\n                                            <col width=\"100\">\r\n                                            <col width=\"100\">\r\n                                            <col width=\"120\">\r\n                                            <col width=\"120\">\r\n                                            <col width=\"100\">\r\n                                            <col width=\"80\">\r\n                                            <col width=\"160\">\r\n                                            <col width=\"120\">\r\n                                            <col width=\"120\">\r\n                                            <col width=\"120\">\r\n                                            <col width=\"70\">\r\n                                        </colgroup>\r\n                                        <thead class=\"gridHeaderTableDefault\">\r\n                                            <tr class=\"component hammer gridHeaderTRDefault\" data-role=\"component\"\r\n                                                data-uuid=\"_iwd_15qf2e1yd4\" style=\"height: 20px;\">\r\n                                                <!---->\r\n                                                <!---->\r\n                                                <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                    width=\"100\" colspan=\"\" rowspan=\"2\" rootelm=\"_iwd_15qf2dnco4\"\r\n                                                    class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf2e6j3o\"\r\n                                                    data-parent=\"_iwd_15qf2e1yd4\" style=\"height: 29px;\">\r\n                                                    <div class=\"grid_column_text_input_type\">\r\n                                                        <nobr>Conractor</nobr>\r\n                                                    </div>\r\n                                                </th>\r\n                                                <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                    width=\"100\" colspan=\"\" rowspan=\"2\" rootelm=\"_iwd_15qf2dnco4\"\r\n                                                    class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf2eim4s\"\r\n                                                    data-parent=\"_iwd_15qf2e1yd4\" style=\"height: 29px;\">\r\n                                                    <div class=\"grid_column_text_input_type\">\r\n                                                        <nobr>Insured</nobr>\r\n                                                    </div>\r\n                                                </th>\r\n                                                <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                    width=\"120\" colspan=\"\" rowspan=\"2\" rootelm=\"_iwd_15qf2dnco4\"\r\n                                                    class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf2ep5e8\"\r\n                                                    data-parent=\"_iwd_15qf2e1yd4\" style=\"height: 29px;\">\r\n                                                    <div class=\"grid_column_text_input_type\">\r\n                                                        <nobr>Product</nobr>\r\n                                                    </div>\r\n                                                </th>\r\n                                                <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                    width=\"120\" colspan=\"\" rowspan=\"2\" rootelm=\"_iwd_15qf2dnco4\"\r\n                                                    class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf2euxyk\"\r\n                                                    data-parent=\"_iwd_15qf2e1yd4\" style=\"height: 29px;\">\r\n                                                    <div class=\"grid_column_text_input_type\">\r\n                                                        <nobr>Premium (KRW)</nobr>\r\n                                                    </div>\r\n                                                </th>\r\n                                                <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                    width=\"100\" colspan=\"\" rowspan=\"2\" rootelm=\"_iwd_15qf2dnco4\"\r\n                                                    class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf2f0m1s\"\r\n                                                    data-parent=\"_iwd_15qf2e1yd4\" style=\"height: 29px;\">\r\n                                                    <div class=\"grid_column_text_input_type\">\r\n                                                        <nobr>Status</nobr>\r\n                                                    </div>\r\n                                                </th>\r\n                                                <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                    width=\"120\" colspan=\"6\" rowspan=\"\" rootelm=\"_iwd_15qf2dnco4\"\r\n                                                    class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf2f67qw\"\r\n                                                    data-parent=\"_iwd_15qf2e1yd4\" style=\"height: 29px;\">\r\n                                                    <div class=\"grid_column_text_input_type\">\r\n                                                        <nobr>Subscription</nobr>\r\n                                                    </div>\r\n                                                </th>\r\n                                            </tr>\r\n                                            <tr class=\"component hammer gridHeaderTRDefault\" data-role=\"component\"\r\n                                                data-uuid=\"_iwd_15qf2ffo98\" style=\"height: 20px;\">\r\n                                                <!---->\r\n                                                <!---->\r\n                                                <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                    width=\"80\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf2dnco4\"\r\n                                                    class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf2fkdp8\"\r\n                                                    data-parent=\"_iwd_15qf2ffo98\">\r\n                                                    <div class=\"grid_column_text_input_type\">\r\n                                                        <nobr>System</nobr>\r\n                                                    </div>\r\n                                                </th>\r\n                                                <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                    width=\"160\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf2dnco4\"\r\n                                                    class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf2fqytc\"\r\n                                                    data-parent=\"_iwd_15qf2ffo98\">\r\n                                                    <div class=\"grid_column_text_input_type\">\r\n                                                        <nobr>Tracing No</nobr>\r\n                                                    </div>\r\n                                                </th>\r\n                                                <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                    width=\"120\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf2dnco4\"\r\n                                                    class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf2fxyl8\"\r\n                                                    data-parent=\"_iwd_15qf2ffo98\">\r\n                                                    <div class=\"grid_column_text_input_type\">\r\n                                                        <nobr>Planned Date</nobr>\r\n                                                    </div>\r\n                                                </th>\r\n                                                <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                    width=\"120\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf2dnco4\"\r\n                                                    class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf2g6tsw\"\r\n                                                    data-parent=\"_iwd_15qf2ffo98\">\r\n                                                    <div class=\"grid_column_text_input_type\">\r\n                                                        <nobr>Issued Date</nobr>\r\n                                                    </div>\r\n                                                </th>\r\n                                                <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                    width=\"120\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf2dnco4\"\r\n                                                    class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf2gg450\"\r\n                                                    data-parent=\"_iwd_15qf2ffo98\">\r\n                                                    <div class=\"grid_column_text_input_type\">\r\n                                                        <nobr>E-mail</nobr>\r\n                                                    </div>\r\n                                                </th>\r\n                                                <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                    width=\"70\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf2dnco4\"\r\n                                                    class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf2gpfbo\"\r\n                                                    data-parent=\"_iwd_15qf2ffo98\">\r\n                                                    <div class=\"grid_column_text_input_type\">\r\n                                                        <nobr>LMS</nobr>\r\n                                                    </div>\r\n                                                </th>\r\n                                            </tr>\r\n                                        </thead>\r\n                                    </table>\r\n                                    <div mark=\"grid.dataLayer\">\r\n                                        <table width=\"1210\" class=\"component-guideline component hammer\"\r\n                                            data-role=\"component\" data-uuid=\"_iwd_15qf2gz9vk\"\r\n                                            data-parent=\"_iwd_15qf2dnco4\"\r\n                                            style=\"border-spacing: 0px; border-collapse: collapse; table-layout: fixed;\">\r\n                                            <colgroup>\r\n                                                <!---->\r\n                                                <!---->\r\n                                                <col width=\"100\">\r\n                                                <col width=\"100\">\r\n                                                <col width=\"120\">\r\n                                                <col width=\"120\">\r\n                                                <col width=\"100\">\r\n                                                <col width=\"80\">\r\n                                                <col width=\"160\">\r\n                                                <col width=\"120\">\r\n                                                <col width=\"120\">\r\n                                                <col width=\"120\">\r\n                                                <col width=\"70\">\r\n                                            </colgroup>\r\n                                            <tbody class=\"gridBodyTableDefault\">\r\n                                                <tr class=\"component hammer gridBodyTRDefault\" data-role=\"component\"\r\n                                                    data-uuid=\"_iwd_15qf2h59b4\" style=\"height: 20px;\">\r\n                                                    <!---->\r\n                                                    <!---->\r\n                                                    <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"100\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf2dnco4\"\r\n                                                        class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf2hc0wk\"\r\n                                                        data-parent=\"_iwd_15qf2h59b4\" style=\"height: 20px;\">\r\n                                                        <div class=\"grid_column_text_input_type\">\r\n                                                            <nobr></nobr>\r\n                                                        </div>\r\n                                                    </td>\r\n                                                    <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"100\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf2dnco4\"\r\n                                                        class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf2hrfm0\"\r\n                                                        data-parent=\"_iwd_15qf2h59b4\" style=\"height: 20px;\">\r\n                                                        <div class=\"grid_column_text_input_type\">\r\n                                                            <nobr></nobr>\r\n                                                        </div>\r\n                                                    </td>\r\n                                                    <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"120\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf2dnco4\"\r\n                                                        class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf2i5ufs\"\r\n                                                        data-parent=\"_iwd_15qf2h59b4\">\r\n                                                        <div class=\"grid_column_text_input_type\">\r\n                                                            <nobr></nobr>\r\n                                                        </div>\r\n                                                    </td>\r\n                                                    <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"120\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf2dnco4\"\r\n                                                        class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf2iey7s\"\r\n                                                        data-parent=\"_iwd_15qf2h59b4\">\r\n                                                        <div class=\"grid_column_text_input_type\">\r\n                                                            <nobr></nobr>\r\n                                                        </div>\r\n                                                    </td>\r\n                                                    <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"100\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf2dnco4\"\r\n                                                        class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf2ioico\"\r\n                                                        data-parent=\"_iwd_15qf2h59b4\">\r\n                                                        <div class=\"grid_column_text_input_type\">\r\n                                                            <nobr></nobr>\r\n                                                        </div>\r\n                                                    </td>\r\n                                                    <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"80\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf2dnco4\"\r\n                                                        class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf2iwqyg\"\r\n                                                        data-parent=\"_iwd_15qf2h59b4\">\r\n                                                        <div class=\"grid_column_selectbox_input_type\">\r\n                                                            <!---->\r\n                                                        </div>\r\n                                                    </td>\r\n                                                    <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"160\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf2dnco4\"\r\n                                                        class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf2k2ins\"\r\n                                                        data-parent=\"_iwd_15qf2h59b4\">\r\n                                                        <div class=\"grid_column_text_input_type\">\r\n                                                            <nobr></nobr>\r\n                                                        </div>\r\n                                                    </td>\r\n                                                    <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"120\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf2dnco4\"\r\n                                                        class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf2kch5c\"\r\n                                                        data-parent=\"_iwd_15qf2h59b4\">\r\n                                                        <div class=\"grid_column_text_input_type\">\r\n                                                            <nobr></nobr>\r\n                                                        </div>\r\n                                                    </td>\r\n                                                    <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"120\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf2dnco4\"\r\n                                                        class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf2kkuro\"\r\n                                                        data-parent=\"_iwd_15qf2h59b4\">\r\n                                                        <div class=\"grid_column_text_input_type\">\r\n                                                            <nobr></nobr>\r\n                                                        </div>\r\n                                                    </td>\r\n                                                    <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"120\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf2dnco4\"\r\n                                                        class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf2ksuyo\"\r\n                                                        data-parent=\"_iwd_15qf2h59b4\">\r\n                                                        <div class=\"grid_column_text_input_type\">\r\n                                                            <nobr></nobr>\r\n                                                        </div>\r\n                                                    </td>\r\n                                                    <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"70\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf2dnco4\"\r\n                                                        class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf2l0pg4\"\r\n                                                        data-parent=\"_iwd_15qf2h59b4\">\r\n                                                        <div class=\"grid_column_text_input_type\">\r\n                                                            <nobr></nobr>\r\n                                                        </div>\r\n                                                    </td>\r\n                                                </tr>\r\n                                            </tbody>\r\n                                        </table>\r\n                                    </div>\r\n                                    <!---->\r\n                                </div>\r\n                            </div>\r\n                        </div>\r\n                    </div>\r\n                    <div id=\"content5\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                        class=\"component-guideline component hammer w2group component hammer w2tabcontrol_contents w2group\"\r\n                        data-role=\"component\" data-uuid=\"_iwd_15qf2la618\" data-parent=\"_iwd_15qf0bqsvw\"\r\n                        data-container=\"true\" data-quicktoolbar=\"true\"\r\n                        style=\"overflow: auto; display: none; visibility: hidden;\">\r\n                        <!---->\r\n                        <div id=\"_iwd_15qf2leupg\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group tbbox mt10\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf2leupg\" data-parent=\"_iwd_15qf2la618\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!---->\r\n                            <table id=\"_iwd_15qf2liu2k\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2group w2tb tb\" data-role=\"component\"\r\n                                data-uuid=\"_iwd_15qf2liu2k\" data-parent=\"_iwd_15qf2leupg\" rootelm=\"\"\r\n                                data-container=\"true\" data-quicktoolbar=\"true\" style=\"position: relative; width: 100%;\">\r\n                                <!---->\r\n                                <colgroup id=\"_iwd_15qf2m09m8\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\"\r\n                                    data-resizable=\"true\" class=\"component-guideline component hammer w2group\"\r\n                                    data-role=\"component\" data-uuid=\"_iwd_15qf2m09m8\" data-parent=\"_iwd_15qf2liu2k\"\r\n                                    rootelm=\"_iwd_15qf2liu2k\" data-container=\"true\" data-quicktoolbar=\"true\">\r\n                                    <!---->\r\n                                    <col id=\"_iwd_15qf2m6dr8\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\"\r\n                                        data-resizable=\"true\" class=\"component-guideline component hammer w2group\"\r\n                                        data-role=\"component\" data-uuid=\"_iwd_15qf2m6dr8\" data-parent=\"_iwd_15qf2m09m8\"\r\n                                        rootelm=\"\" data-container=\"true\" data-quicktoolbar=\"true\" style=\"width: 110px;\">\r\n                                    <col id=\"_iwd_15qf2mcd18\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\"\r\n                                        data-resizable=\"true\" class=\"component-guideline component hammer w2group\"\r\n                                        data-role=\"component\" data-uuid=\"_iwd_15qf2mcd18\" data-parent=\"_iwd_15qf2m09m8\"\r\n                                        rootelm=\"\" data-container=\"true\" data-quicktoolbar=\"true\">\r\n                                </colgroup>\r\n                                <tr id=\"_iwd_15qf2mgq4s\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                                    class=\"component hammer w2group\" data-role=\"component\" data-uuid=\"_iwd_15qf2mgq4s\"\r\n                                    data-parent=\"_iwd_15qf2liu2k\" rootelm=\"_iwd_15qf2liu2k\" data-container=\"true\"\r\n                                    data-quicktoolbar=\"true\">\r\n                                    <!---->\r\n                                    <th id=\"_iwd_15qf2mk34c\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                                        class=\"component-guideline component hammer w2group w2tb_th\"\r\n                                        data-role=\"component\" data-uuid=\"_iwd_15qf2mk34c\" data-parent=\"_iwd_15qf2mgq4s\"\r\n                                        rootelm=\"\" data-container=\"true\" data-quicktoolbar=\"true\">\r\n                                        <!----> <span id=\"_iwd_15qf2mokjg\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                            class=\"component-guideline component hammer w2span\" data-role=\"component\"\r\n                                            data-uuid=\"_iwd_15qf2mokjg\" data-parent=\"_iwd_15qf2mk34c\" rootelm=\"\">Sendint\r\n                                            Date</span></th>\r\n                                    <td id=\"_iwd_15qf2mrswc\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                                        class=\"component-guideline component hammer w2group w2tb_td\"\r\n                                        data-role=\"component\" data-uuid=\"_iwd_15qf2mrswc\" data-parent=\"_iwd_15qf2mgq4s\"\r\n                                        rootelm=\"\" data-container=\"true\" data-quicktoolbar=\"true\">\r\n                                        <!---->\r\n                                        <div id=\"_iwd_15qf2mvl5w\" data-taborder=\"true\" data-resizable=\"true\"\r\n                                            class=\"component-guideline component hammer default_binding_wrap w2inputCalendar_div ast\"\r\n                                            data-role=\"component\" data-uuid=\"_iwd_15qf2mvl5w\"\r\n                                            data-parent=\"_iwd_15qf2mrswc\" rootelm=\"\"\r\n                                            style=\"width: 100px; margin-left: 5px;\">\r\n                                            <div class=\"w2inputCalendar_div_input\" style=\"width: 100%;\"><input\r\n                                                    tabindex=\"-1\" readonly=\"readonly\" class=\"w2inputCalendar_divInput\"\r\n                                                    style=\"width: calc(100% - 25px); height: 100%; box-sizing: border-box;\">\r\n                                                <div class=\"w2inputCalendar_div_img\"\r\n                                                    style=\"display: flex; align-items: center;\"><button tabindex=\"-1\"\r\n                                                        readonly=\"readonly\" class=\"w2inputCalendar_button\"\r\n                                                        style=\"background-image: url(&quot;/websquare/uiplugin/inputCalendar/images/icon_calendar.gif&quot;);\"></button>\r\n                                                </div>\r\n                                            </div>\r\n                                        </div><span id=\"_iwd_15qf2mz7y8\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                            class=\"component-guideline component hammer w2span\" data-role=\"component\"\r\n                                            data-uuid=\"_iwd_15qf2mz7y8\" data-parent=\"_iwd_15qf2mrswc\" rootelm=\"\"\r\n                                            style=\"position: relative;\">~</span>\r\n                                        <div id=\"_iwd_15qf2n3zms\" data-taborder=\"true\" data-resizable=\"true\"\r\n                                            class=\"component-guideline component hammer default_binding_wrap w2inputCalendar_div ast\"\r\n                                            data-role=\"component\" data-uuid=\"_iwd_15qf2n3zms\"\r\n                                            data-parent=\"_iwd_15qf2mrswc\" rootelm=\"\" style=\"width: 100px;\">\r\n                                            <div class=\"w2inputCalendar_div_input\" style=\"width: 100%;\"><input\r\n                                                    tabindex=\"-1\" readonly=\"readonly\" class=\"w2inputCalendar_divInput\"\r\n                                                    style=\"width: calc(100% - 25px); height: 100%; box-sizing: border-box;\">\r\n                                                <div class=\"w2inputCalendar_div_img\"\r\n                                                    style=\"display: flex; align-items: center;\"><button tabindex=\"-1\"\r\n                                                        readonly=\"readonly\" class=\"w2inputCalendar_button\"\r\n                                                        style=\"background-image: url(&quot;/websquare/uiplugin/inputCalendar/images/icon_calendar.gif&quot;);\"></button>\r\n                                                </div>\r\n                                            </div>\r\n                                        </div>\r\n                                        <div id=\"_iwd_15qf2n8iac\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\"\r\n                                            data-resizable=\"true\"\r\n                                            class=\"component-guideline component hammer w2group fr\"\r\n                                            data-role=\"component\" data-uuid=\"_iwd_15qf2n8iac\"\r\n                                            data-parent=\"_iwd_15qf2mrswc\" rootelm=\"\" data-container=\"true\"\r\n                                            data-quicktoolbar=\"true\">\r\n                                            <!----> <a id=\"_iwd_15qf2ncekc\" href=\"javascript:void(0);\"\r\n                                                data-role=\"component\" data-state=\"init\" data-taborder=\"true\"\r\n                                                data-resizable=\"true\"\r\n                                                class=\"component-guideline component hammer w2anchor2 btn_cm\"\r\n                                                data-uuid=\"_iwd_15qf2ncekc\" data-parent=\"_iwd_15qf2n8iac\" rootelm=\"\">\r\n                                                Search</a></div>\r\n                                    </td>\r\n                                </tr>\r\n                            </table>\r\n                        </div>\r\n                        <div id=\"_iwd_15qf2njmio\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group gvwbox\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf2njmio\" data-parent=\"_iwd_15qf2la618\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!---->\r\n                            <div id=\"_iwd_15qf2nnab4\" data-resizable=\"true\" data-press=\"false\" data-taborder=\"true\"\r\n                                class=\"component-guideline component hammer w2grid wq_gvw\" data-role=\"component\"\r\n                                data-uuid=\"_iwd_15qf2nnab4\" data-parent=\"_iwd_15qf2njmio\" rootelm=\"\"\r\n                                style=\"overflow: auto; border-spacing: 0px; border-collapse: collapse; table-layout: fixed; height: 100px;\">\r\n                                <!---->\r\n                                <div mark=\"grid.mainDiv\">\r\n                                    <table width=\"960\" class=\"component-guideline component hammer\"\r\n                                        data-role=\"component\" data-uuid=\"_iwd_15qf2nvxhw\" data-parent=\"_iwd_15qf2nnab4\"\r\n                                        style=\"border-spacing: 0px; border-collapse: collapse; table-layout: fixed;\">\r\n                                        <colgroup>\r\n                                            <!---->\r\n                                            <!---->\r\n                                            <col width=\"120\">\r\n                                            <col width=\"130\">\r\n                                            <col width=\"100\">\r\n                                            <col width=\"130\">\r\n                                            <col width=\"80\">\r\n                                            <col width=\"100\">\r\n                                            <col width=\"100\">\r\n                                            <col width=\"100\">\r\n                                            <col width=\"100\">\r\n                                        </colgroup>\r\n                                        <thead class=\"gridHeaderTableDefault\">\r\n                                            <tr class=\"component hammer gridHeaderTRDefault\" data-role=\"component\"\r\n                                                data-uuid=\"_iwd_15qf2o08qs\" style=\"height: 20px;\">\r\n                                                <!---->\r\n                                                <!---->\r\n                                                <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                    width=\"120\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf2nnab4\"\r\n                                                    class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf2o4kzs\"\r\n                                                    data-parent=\"_iwd_15qf2o08qs\">\r\n                                                    <div class=\"grid_column_text_input_type\">\r\n                                                        <nobr>Policy No</nobr>\r\n                                                    </div>\r\n                                                </th>\r\n                                                <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                    width=\"130\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf2nnab4\"\r\n                                                    class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf2ohqao\"\r\n                                                    data-parent=\"_iwd_15qf2o08qs\">\r\n                                                    <div class=\"grid_column_text_input_type\">\r\n                                                        <nobr>Product</nobr>\r\n                                                    </div>\r\n                                                </th>\r\n                                                <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                    width=\"100\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf2nnab4\"\r\n                                                    class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf2onnvk\"\r\n                                                    data-parent=\"_iwd_15qf2o08qs\">\r\n                                                    <div class=\"grid_column_text_input_type\">\r\n                                                        <nobr>Signed Date</nobr>\r\n                                                    </div>\r\n                                                </th>\r\n                                                <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                    width=\"130\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf2nnab4\"\r\n                                                    class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf2oszjk\"\r\n                                                    data-parent=\"_iwd_15qf2o08qs\">\r\n                                                    <div class=\"grid_column_text_input_type\">\r\n                                                        <nobr>Notice</nobr>\r\n                                                    </div>\r\n                                                </th>\r\n                                                <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                    width=\"80\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf2nnab4\"\r\n                                                    class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf2oyhds\"\r\n                                                    data-parent=\"_iwd_15qf2o08qs\">\r\n                                                    <div class=\"grid_column_text_input_type\">\r\n                                                        <nobr>Transfer Mode</nobr>\r\n                                                    </div>\r\n                                                </th>\r\n                                                <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                    width=\"100\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf2nnab4\"\r\n                                                    class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf2p3mc4\"\r\n                                                    data-parent=\"_iwd_15qf2o08qs\">\r\n                                                    <div class=\"grid_column_text_input_type\">\r\n                                                        <nobr>Transfer Status</nobr>\r\n                                                    </div>\r\n                                                </th>\r\n                                                <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                    width=\"100\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf2nnab4\"\r\n                                                    class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf2panvw\"\r\n                                                    data-parent=\"_iwd_15qf2o08qs\">\r\n                                                    <div class=\"grid_column_text_input_type\">\r\n                                                        <nobr>Reason of Not Sending</nobr>\r\n                                                    </div>\r\n                                                </th>\r\n                                                <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                    width=\"100\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf2nnab4\"\r\n                                                    class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf2pj1w4\"\r\n                                                    data-parent=\"_iwd_15qf2o08qs\">\r\n                                                    <div class=\"grid_column_text_input_type\">\r\n                                                        <nobr>Reason of Return</nobr>\r\n                                                    </div>\r\n                                                </th>\r\n                                                <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                    width=\"100\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf2nnab4\"\r\n                                                    class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf2pr9nc\"\r\n                                                    data-parent=\"_iwd_15qf2o08qs\">\r\n                                                    <div class=\"grid_column_text_input_type\">\r\n                                                        <nobr>Returning Date</nobr>\r\n                                                    </div>\r\n                                                </th>\r\n                                            </tr>\r\n                                        </thead>\r\n                                    </table>\r\n                                    <div mark=\"grid.dataLayer\">\r\n                                        <table width=\"960\" class=\"component-guideline component hammer\"\r\n                                            data-role=\"component\" data-uuid=\"_iwd_15qf2q0lj0\"\r\n                                            data-parent=\"_iwd_15qf2nnab4\"\r\n                                            style=\"border-spacing: 0px; border-collapse: collapse; table-layout: fixed;\">\r\n                                            <colgroup>\r\n                                                <!---->\r\n                                                <!---->\r\n                                                <col width=\"120\">\r\n                                                <col width=\"130\">\r\n                                                <col width=\"100\">\r\n                                                <col width=\"130\">\r\n                                                <col width=\"80\">\r\n                                                <col width=\"100\">\r\n                                                <col width=\"100\">\r\n                                                <col width=\"100\">\r\n                                                <col width=\"100\">\r\n                                            </colgroup>\r\n                                            <tbody class=\"gridBodyTableDefault\">\r\n                                                <tr class=\"component hammer gridBodyTRDefault\" data-role=\"component\"\r\n                                                    data-uuid=\"_iwd_15qf2q6otg\" style=\"height: 20px;\">\r\n                                                    <!---->\r\n                                                    <!---->\r\n                                                    <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"120\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf2nnab4\"\r\n                                                        class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf2qdo1w\"\r\n                                                        data-parent=\"_iwd_15qf2q6otg\" style=\"height: 20px;\">\r\n                                                        <div class=\"grid_column_text_input_type\">\r\n                                                            <nobr></nobr>\r\n                                                        </div>\r\n                                                    </td>\r\n                                                    <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"130\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf2nnab4\"\r\n                                                        class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf2qt4os\"\r\n                                                        data-parent=\"_iwd_15qf2q6otg\" style=\"height: 20px;\">\r\n                                                        <div class=\"grid_column_text_input_type\">\r\n                                                            <nobr></nobr>\r\n                                                        </div>\r\n                                                    </td>\r\n                                                    <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"100\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf2nnab4\"\r\n                                                        class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf2r5xyc\"\r\n                                                        data-parent=\"_iwd_15qf2q6otg\">\r\n                                                        <div class=\"grid_column_text_input_type\">\r\n                                                            <nobr></nobr>\r\n                                                        </div>\r\n                                                    </td>\r\n                                                    <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"130\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf2nnab4\"\r\n                                                        class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf2rg1x4\"\r\n                                                        data-parent=\"_iwd_15qf2q6otg\">\r\n                                                        <div class=\"grid_column_text_input_type\">\r\n                                                            <nobr></nobr>\r\n                                                        </div>\r\n                                                    </td>\r\n                                                    <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"80\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf2nnab4\"\r\n                                                        class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf2rnu38\"\r\n                                                        data-parent=\"_iwd_15qf2q6otg\">\r\n                                                        <div class=\"grid_column_text_input_type\">\r\n                                                            <nobr></nobr>\r\n                                                        </div>\r\n                                                    </td>\r\n                                                    <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"100\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf2nnab4\"\r\n                                                        class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf2rueqo\"\r\n                                                        data-parent=\"_iwd_15qf2q6otg\">\r\n                                                        <div class=\"grid_column_text_input_type\">\r\n                                                            <nobr></nobr>\r\n                                                        </div>\r\n                                                    </td>\r\n                                                    <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"100\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf2nnab4\"\r\n                                                        class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf2s0qzc\"\r\n                                                        data-parent=\"_iwd_15qf2q6otg\">\r\n                                                        <div class=\"grid_column_text_input_type\">\r\n                                                            <nobr></nobr>\r\n                                                        </div>\r\n                                                    </td>\r\n                                                    <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"100\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf2nnab4\"\r\n                                                        class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf2s6nbs\"\r\n                                                        data-parent=\"_iwd_15qf2q6otg\">\r\n                                                        <div class=\"grid_column_text_input_type\">\r\n                                                            <nobr></nobr>\r\n                                                        </div>\r\n                                                    </td>\r\n                                                    <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"100\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf2nnab4\"\r\n                                                        class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf2scldc\"\r\n                                                        data-parent=\"_iwd_15qf2q6otg\">\r\n                                                        <div class=\"grid_column_text_input_type\">\r\n                                                            <nobr></nobr>\r\n                                                        </div>\r\n                                                    </td>\r\n                                                </tr>\r\n                                            </tbody>\r\n                                        </table>\r\n                                    </div>\r\n                                    <!---->\r\n                                </div>\r\n                            </div>\r\n                        </div>\r\n                    </div>\r\n                    <div id=\"content6\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                        class=\"component-guideline component hammer w2group component hammer w2tabcontrol_contents w2group\"\r\n                        data-role=\"component\" data-uuid=\"_iwd_15qf2sm6z0\" data-parent=\"_iwd_15qf0bqsvw\"\r\n                        data-container=\"true\" data-quicktoolbar=\"true\"\r\n                        style=\"overflow: auto; display: none; visibility: hidden;\">\r\n                        <!---->\r\n                        <div id=\"_iwd_15qf2spqac\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group tbbox mt10\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf2spqac\" data-parent=\"_iwd_15qf2sm6z0\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!---->\r\n                            <table id=\"_iwd_15qf2sshlc\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2group w2tb tb\" data-role=\"component\"\r\n                                data-uuid=\"_iwd_15qf2sshlc\" data-parent=\"_iwd_15qf2spqac\" rootelm=\"\"\r\n                                data-container=\"true\" data-quicktoolbar=\"true\" style=\"position: relative; width: 100%;\">\r\n                                <!---->\r\n                                <colgroup id=\"_iwd_15qf2t944k\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\"\r\n                                    data-resizable=\"true\" class=\"component-guideline component hammer w2group\"\r\n                                    data-role=\"component\" data-uuid=\"_iwd_15qf2t944k\" data-parent=\"_iwd_15qf2sshlc\"\r\n                                    rootelm=\"_iwd_15qf2sshlc\" data-container=\"true\" data-quicktoolbar=\"true\">\r\n                                    <!---->\r\n                                    <col id=\"_iwd_15qf2tdw1g\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\"\r\n                                        data-resizable=\"true\" class=\"component-guideline component hammer w2group\"\r\n                                        data-role=\"component\" data-uuid=\"_iwd_15qf2tdw1g\" data-parent=\"_iwd_15qf2t944k\"\r\n                                        rootelm=\"\" data-container=\"true\" data-quicktoolbar=\"true\" style=\"width: 110px;\">\r\n                                    <col id=\"_iwd_15qf2tiucw\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\"\r\n                                        data-resizable=\"true\" class=\"component-guideline component hammer w2group\"\r\n                                        data-role=\"component\" data-uuid=\"_iwd_15qf2tiucw\" data-parent=\"_iwd_15qf2t944k\"\r\n                                        rootelm=\"\" data-container=\"true\" data-quicktoolbar=\"true\">\r\n                                </colgroup>\r\n                                <tr id=\"_iwd_15qf2tn52c\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                                    class=\"component hammer w2group\" data-role=\"component\" data-uuid=\"_iwd_15qf2tn52c\"\r\n                                    data-parent=\"_iwd_15qf2sshlc\" rootelm=\"_iwd_15qf2sshlc\" data-container=\"true\"\r\n                                    data-quicktoolbar=\"true\">\r\n                                    <!---->\r\n                                    <th id=\"_iwd_15qf2tqw68\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                                        class=\"component-guideline component hammer w2group w2tb_th\"\r\n                                        data-role=\"component\" data-uuid=\"_iwd_15qf2tqw68\" data-parent=\"_iwd_15qf2tn52c\"\r\n                                        rootelm=\"\" data-container=\"true\" data-quicktoolbar=\"true\">\r\n                                        <!----> <span id=\"_iwd_15qf2tv2bs\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                            class=\"component-guideline component hammer w2span\" data-role=\"component\"\r\n                                            data-uuid=\"_iwd_15qf2tv2bs\" data-parent=\"_iwd_15qf2tqw68\"\r\n                                            rootelm=\"\">Period</span></th>\r\n                                    <td id=\"_iwd_15qf2tz200\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                                        class=\"component-guideline component hammer w2group w2tb_td\"\r\n                                        data-role=\"component\" data-uuid=\"_iwd_15qf2tz200\" data-parent=\"_iwd_15qf2tn52c\"\r\n                                        rootelm=\"\" data-container=\"true\" data-quicktoolbar=\"true\">\r\n                                        <!---->\r\n                                        <div id=\"_iwd_15qf2u3xb4\" data-taborder=\"true\" data-resizable=\"true\"\r\n                                            class=\"component-guideline component hammer default_binding_wrap w2inputCalendar_div ast\"\r\n                                            data-role=\"component\" data-uuid=\"_iwd_15qf2u3xb4\"\r\n                                            data-parent=\"_iwd_15qf2tz200\" rootelm=\"\"\r\n                                            style=\"width: 100px; margin-left: 5px;\">\r\n                                            <div class=\"w2inputCalendar_div_input\" style=\"width: 100%;\"><input\r\n                                                    tabindex=\"-1\" readonly=\"readonly\" class=\"w2inputCalendar_divInput\"\r\n                                                    style=\"width: calc(100% - 25px); height: 100%; box-sizing: border-box;\">\r\n                                                <div class=\"w2inputCalendar_div_img\"\r\n                                                    style=\"display: flex; align-items: center;\"><button tabindex=\"-1\"\r\n                                                        readonly=\"readonly\" class=\"w2inputCalendar_button\"\r\n                                                        style=\"background-image: url(&quot;/websquare/uiplugin/inputCalendar/images/icon_calendar.gif&quot;);\"></button>\r\n                                                </div>\r\n                                            </div>\r\n                                        </div><span id=\"_iwd_15qf2u8b98\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                            class=\"component-guideline component hammer w2span\" data-role=\"component\"\r\n                                            data-uuid=\"_iwd_15qf2u8b98\" data-parent=\"_iwd_15qf2tz200\" rootelm=\"\"\r\n                                            style=\"position: relative;\">~</span>\r\n                                        <div id=\"_iwd_15qf2uckyk\" data-taborder=\"true\" data-resizable=\"true\"\r\n                                            class=\"component-guideline component hammer default_binding_wrap w2inputCalendar_div ast\"\r\n                                            data-role=\"component\" data-uuid=\"_iwd_15qf2uckyk\"\r\n                                            data-parent=\"_iwd_15qf2tz200\" rootelm=\"\" style=\"width: 100px;\">\r\n                                            <div class=\"w2inputCalendar_div_input\" style=\"width: 100%;\"><input\r\n                                                    tabindex=\"-1\" readonly=\"readonly\" class=\"w2inputCalendar_divInput\"\r\n                                                    style=\"width: calc(100% - 25px); height: 100%; box-sizing: border-box;\">\r\n                                                <div class=\"w2inputCalendar_div_img\"\r\n                                                    style=\"display: flex; align-items: center;\"><button tabindex=\"-1\"\r\n                                                        readonly=\"readonly\" class=\"w2inputCalendar_button\"\r\n                                                        style=\"background-image: url(&quot;/websquare/uiplugin/inputCalendar/images/icon_calendar.gif&quot;);\"></button>\r\n                                                </div>\r\n                                            </div>\r\n                                        </div>\r\n                                        <div id=\"_iwd_15qf2ugq9k\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\"\r\n                                            data-resizable=\"true\"\r\n                                            class=\"component-guideline component hammer w2group fr\"\r\n                                            data-role=\"component\" data-uuid=\"_iwd_15qf2ugq9k\"\r\n                                            data-parent=\"_iwd_15qf2tz200\" rootelm=\"\" data-container=\"true\"\r\n                                            data-quicktoolbar=\"true\">\r\n                                            <!----> <a id=\"_iwd_15qf2umho8\" href=\"javascript:void(0);\"\r\n                                                data-role=\"component\" data-state=\"init\" data-taborder=\"true\"\r\n                                                data-resizable=\"true\"\r\n                                                class=\"component-guideline component hammer w2anchor2 btn_cm\"\r\n                                                data-uuid=\"_iwd_15qf2umho8\" data-parent=\"_iwd_15qf2ugq9k\" rootelm=\"\">\r\n                                                Search</a></div>\r\n                                    </td>\r\n                                </tr>\r\n                                <tr id=\"_iwd_15qf2uvzf0\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                                    class=\"component hammer w2group\" data-role=\"component\" data-uuid=\"_iwd_15qf2uvzf0\"\r\n                                    data-parent=\"_iwd_15qf2sshlc\" rootelm=\"_iwd_15qf2sshlc\" data-container=\"true\"\r\n                                    data-quicktoolbar=\"true\">\r\n                                    <!---->\r\n                                    <th id=\"_iwd_15qf2uzx08\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                                        class=\"component-guideline component hammer w2group w2tb_th\"\r\n                                        data-role=\"component\" data-uuid=\"_iwd_15qf2uzx08\" data-parent=\"_iwd_15qf2uvzf0\"\r\n                                        rootelm=\"\" data-container=\"true\" data-quicktoolbar=\"true\">\r\n                                        <!----> <span id=\"_iwd_15qf2v5va4\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                            class=\"component-guideline component hammer w2span\" data-role=\"component\"\r\n                                            data-uuid=\"_iwd_15qf2v5va4\" data-parent=\"_iwd_15qf2uzx08\"\r\n                                            rootelm=\"\">Type</span></th>\r\n                                    <td id=\"_iwd_15qf2vb93w\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                                        class=\"component-guideline component hammer w2group w2tb_td\"\r\n                                        data-role=\"component\" data-uuid=\"_iwd_15qf2vb93w\" data-parent=\"_iwd_15qf2uvzf0\"\r\n                                        rootelm=\"\" data-container=\"true\" data-quicktoolbar=\"true\">\r\n                                        <!---->\r\n                                        <div id=\"_iwd_15qf3ga5f4\" data-taborder=\"true\" data-resizable=\"true\"\r\n                                            class=\"component-guideline component hammer default_binding_wrap w2checkbox\"\r\n                                            data-role=\"component\" data-uuid=\"_iwd_15qf3ga5f4\"\r\n                                            data-parent=\"_iwd_15qf2vb93w\" rootelm=\"\">\r\n                                            <table cellspacing=\"0\" cellpadding=\"0\" class=\"w2checkbox_main\">\r\n                                                <tbody>\r\n                                                    <tr>\r\n                                                        <td class=\"w2checkbox_td_input\"><input type=\"checkbox\" index=\"0\"\r\n                                                                tabindex=\"0\" class=\"w2checkbox_input\"></td>\r\n                                                        <td class=\"w2checkbox_td_label\"><label index=\"0\"\r\n                                                                class=\"w2checkbox_label\">All</label></td>\r\n                                                        <td class=\"w2checkbox_td_input\"><input type=\"checkbox\" index=\"1\"\r\n                                                                tabindex=\"0\" class=\"w2checkbox_input\"></td>\r\n                                                        <td class=\"w2checkbox_td_label\"><label index=\"1\"\r\n                                                                class=\"w2checkbox_label\">Visit</label></td>\r\n                                                        <td class=\"w2checkbox_td_input\"><input type=\"checkbox\" index=\"2\"\r\n                                                                tabindex=\"0\" class=\"w2checkbox_input\"></td>\r\n                                                        <td class=\"w2checkbox_td_label\"><label index=\"2\"\r\n                                                                class=\"w2checkbox_label\">Call</label></td>\r\n                                                        <td class=\"w2checkbox_td_input\"><input type=\"checkbox\" index=\"3\"\r\n                                                                tabindex=\"0\" class=\"w2checkbox_input\"></td>\r\n                                                        <td class=\"w2checkbox_td_label\"><label index=\"3\"\r\n                                                                class=\"w2checkbox_label\">E-mil</label></td>\r\n                                                        <td class=\"w2checkbox_td_input\"><input type=\"checkbox\" index=\"4\"\r\n                                                                tabindex=\"0\" class=\"w2checkbox_input\"></td>\r\n                                                        <td class=\"w2checkbox_td_label\"><label index=\"4\"\r\n                                                                class=\"w2checkbox_label\">Smart Brochure</label></td>\r\n                                                        <td class=\"w2checkbox_td_input\"><input type=\"checkbox\" index=\"5\"\r\n                                                                tabindex=\"0\" class=\"w2checkbox_input\"></td>\r\n                                                        <td class=\"w2checkbox_td_label\"><label index=\"5\"\r\n                                                                class=\"w2checkbox_label\">Coverage Analysis</label></td>\r\n                                                        <td class=\"w2checkbox_td_input\"><input type=\"checkbox\" index=\"6\"\r\n                                                                tabindex=\"0\" class=\"w2checkbox_input\"></td>\r\n                                                        <td class=\"w2checkbox_td_label\"><label index=\"6\"\r\n                                                                class=\"w2checkbox_label\">Policy Planning</label></td>\r\n                                                        <td class=\"w2checkbox_td_input\"><input type=\"checkbox\" index=\"7\"\r\n                                                                tabindex=\"0\" class=\"w2checkbox_input\"></td>\r\n                                                        <td class=\"w2checkbox_td_label\"><label index=\"7\"\r\n                                                                class=\"w2checkbox_label\">Subscription</label></td>\r\n                                                        <td class=\"w2checkbox_td_input\"><input type=\"checkbox\" index=\"8\"\r\n                                                                tabindex=\"0\" class=\"w2checkbox_input\"></td>\r\n                                                        <td class=\"w2checkbox_td_label\"><label index=\"8\"\r\n                                                                class=\"w2checkbox_label\">Pension Analysis</label></td>\r\n                                                        <td class=\"w2checkbox_td_input\"><input type=\"checkbox\" index=\"9\"\r\n                                                                tabindex=\"0\" class=\"w2checkbox_input\"></td>\r\n                                                        <td class=\"w2checkbox_td_label\"><label index=\"9\"\r\n                                                                class=\"w2checkbox_label\">Printing</label></td>\r\n                                                        <td class=\"w2checkbox_td_input\"><input type=\"checkbox\"\r\n                                                                index=\"10\" tabindex=\"0\" class=\"w2checkbox_input\"></td>\r\n                                                        <td class=\"w2checkbox_td_label\"><label index=\"10\"\r\n                                                                class=\"w2checkbox_label\">Money Manager</label></td>\r\n                                                        <td class=\"w2checkbox_td_input\"><input type=\"checkbox\"\r\n                                                                index=\"11\" tabindex=\"0\" class=\"w2checkbox_input\"></td>\r\n                                                        <td class=\"w2checkbox_td_label\"><label index=\"11\"\r\n                                                                class=\"w2checkbox_label\">Life Number</label></td>\r\n                                                    </tr>\r\n                                                </tbody>\r\n                                            </table>\r\n                                        </div>\r\n                                    </td>\r\n                                </tr>\r\n                            </table>\r\n                        </div>\r\n                        <div id=\"_iwd_15qf3kt4xo\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group gvwbox\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf3kt4xo\" data-parent=\"_iwd_15qf2sm6z0\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!---->\r\n                            <div id=\"_iwd_15qf3l1i0k\" data-resizable=\"true\" data-press=\"false\" data-taborder=\"true\"\r\n                                class=\"component-guideline component hammer w2grid wq_gvw\" data-role=\"component\"\r\n                                data-uuid=\"_iwd_15qf3l1i0k\" data-parent=\"_iwd_15qf3kt4xo\" rootelm=\"\"\r\n                                style=\"overflow: auto; border-spacing: 0px; border-collapse: collapse; table-layout: fixed; height: 100px;\">\r\n                                <!---->\r\n                                <div mark=\"grid.mainDiv\">\r\n                                    <table width=\"670\" class=\"component-guideline component hammer\"\r\n                                        data-role=\"component\" data-uuid=\"_iwd_15qf3lfofk\" data-parent=\"_iwd_15qf3l1i0k\"\r\n                                        style=\"border-spacing: 0px; border-collapse: collapse; table-layout: fixed;\">\r\n                                        <colgroup>\r\n                                            <!---->\r\n                                            <!---->\r\n                                            <col width=\"120\">\r\n                                            <col width=\"130\">\r\n                                            <col width=\"120\">\r\n                                            <col width=\"300\">\r\n                                        </colgroup>\r\n                                        <thead class=\"gridHeaderTableDefault\">\r\n                                            <tr class=\"component hammer gridHeaderTRDefault\" data-role=\"component\"\r\n                                                data-uuid=\"_iwd_15qf3lnfwo\" style=\"height: 20px;\">\r\n                                                <!---->\r\n                                                <!---->\r\n                                                <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                    width=\"120\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf3l1i0k\"\r\n                                                    class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf3lvi9g\"\r\n                                                    data-parent=\"_iwd_15qf3lnfwo\">\r\n                                                    <div class=\"grid_column_text_input_type\">\r\n                                                        <nobr>System</nobr>\r\n                                                    </div>\r\n                                                </th>\r\n                                                <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                    width=\"130\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf3l1i0k\"\r\n                                                    class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf3mdpcs\"\r\n                                                    data-parent=\"_iwd_15qf3lnfwo\">\r\n                                                    <div class=\"grid_column_text_input_type\">\r\n                                                        <nobr>Mode</nobr>\r\n                                                    </div>\r\n                                                </th>\r\n                                                <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                    width=\"120\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf3l1i0k\"\r\n                                                    class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf3mnc1c\"\r\n                                                    data-parent=\"_iwd_15qf3lnfwo\">\r\n                                                    <div class=\"grid_column_text_input_type\">\r\n                                                        <nobr>Activated on</nobr>\r\n                                                    </div>\r\n                                                </th>\r\n                                                <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                    width=\"300\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf3l1i0k\"\r\n                                                    class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf3mv9dk\"\r\n                                                    data-parent=\"_iwd_15qf3lnfwo\">\r\n                                                    <div class=\"grid_column_text_input_type\">\r\n                                                        <nobr>Content</nobr>\r\n                                                    </div>\r\n                                                </th>\r\n                                            </tr>\r\n                                        </thead>\r\n                                    </table>\r\n                                    <div mark=\"grid.dataLayer\">\r\n                                        <table width=\"670\" class=\"component-guideline component hammer\"\r\n                                            data-role=\"component\" data-uuid=\"_iwd_15qf3n2cgw\"\r\n                                            data-parent=\"_iwd_15qf3l1i0k\"\r\n                                            style=\"border-spacing: 0px; border-collapse: collapse; table-layout: fixed;\">\r\n                                            <colgroup>\r\n                                                <!---->\r\n                                                <!---->\r\n                                                <col width=\"120\">\r\n                                                <col width=\"130\">\r\n                                                <col width=\"120\">\r\n                                                <col width=\"300\">\r\n                                            </colgroup>\r\n                                            <tbody class=\"gridBodyTableDefault\">\r\n                                                <tr class=\"component hammer gridBodyTRDefault\" data-role=\"component\"\r\n                                                    data-uuid=\"_iwd_15qf3n8iug\" style=\"height: 20px;\">\r\n                                                    <!---->\r\n                                                    <!---->\r\n                                                    <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"120\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf3l1i0k\"\r\n                                                        class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf3ndvqw\"\r\n                                                        data-parent=\"_iwd_15qf3n8iug\" style=\"height: 20px;\">\r\n                                                        <div class=\"grid_column_selectbox_input_type\">\r\n                                                            <!---->\r\n                                                        </div>\r\n                                                    </td>\r\n                                                    <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"130\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf3l1i0k\"\r\n                                                        class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf3oyg38\"\r\n                                                        data-parent=\"_iwd_15qf3n8iug\" style=\"height: 20px;\">\r\n                                                        <div class=\"grid_column_text_input_type\">\r\n                                                            <nobr></nobr>\r\n                                                        </div>\r\n                                                    </td>\r\n                                                    <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"120\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf3l1i0k\"\r\n                                                        class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf3paxuw\"\r\n                                                        data-parent=\"_iwd_15qf3n8iug\">\r\n                                                        <div class=\"grid_column__input_type\">\r\n                                                            <!---->\r\n                                                        </div>\r\n                                                    </td>\r\n                                                    <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"300\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf3l1i0k\"\r\n                                                        class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf3plch0\"\r\n                                                        data-parent=\"_iwd_15qf3n8iug\">\r\n                                                        <div class=\"grid_column_text_input_type\">\r\n                                                            <nobr></nobr>\r\n                                                        </div>\r\n                                                    </td>\r\n                                                </tr>\r\n                                            </tbody>\r\n                                        </table>\r\n                                    </div>\r\n                                    <!---->\r\n                                </div>\r\n                            </div>\r\n                        </div>\r\n                    </div>\r\n                    <div id=\"content7\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                        class=\"component-guideline component hammer w2group component hammer w2tabcontrol_contents w2group\"\r\n                        data-role=\"component\" data-uuid=\"_iwd_15qf3pvqxk\" data-parent=\"_iwd_15qf0bqsvw\"\r\n                        data-container=\"true\" data-quicktoolbar=\"true\"\r\n                        style=\"height: 352px; overflow: auto; display: none; visibility: hidden;\">\r\n                        <!---->\r\n                        <div id=\"_iwd_15qf3q2sbs\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group ly_box\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf3q2sbs\" data-parent=\"_iwd_15qf3pvqxk\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\" style=\"width: 98%;\">\r\n                            <!---->\r\n                            <div id=\"_iwd_15qf3q8mig\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2group box_left ly50\" data-role=\"component\"\r\n                                data-uuid=\"_iwd_15qf3q8mig\" data-parent=\"_iwd_15qf3q2sbs\" rootelm=\"\"\r\n                                data-container=\"true\" data-quicktoolbar=\"true\">\r\n                                <!---->\r\n                                <div id=\"_iwd_15qf3qeczs\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                                    class=\"component-guideline component hammer w2group dfbox mt0\" data-role=\"component\"\r\n                                    data-uuid=\"_iwd_15qf3qeczs\" data-parent=\"_iwd_15qf3q8mig\" rootelm=\"\"\r\n                                    data-container=\"true\" data-quicktoolbar=\"true\">\r\n                                    <!---->\r\n                                    <div id=\"_iwd_15qf3qig28\" tabindex=\"-1\" data-resizable=\"true\" data-role=\"component\"\r\n                                        class=\"component-guideline component hammer w2textbox df_tit fl\"\r\n                                        data-uuid=\"_iwd_15qf3qig28\" data-parent=\"_iwd_15qf3qeczs\" rootelm=\"\">Policy\r\n                                        Subscription Status (Only Maintained Ones)</div>\r\n                                </div>\r\n                                <div id=\"_iwd_15qf3qn1f0\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                                    class=\"component-guideline component hammer w2group gvwbox\" data-role=\"component\"\r\n                                    data-uuid=\"_iwd_15qf3qn1f0\" data-parent=\"_iwd_15qf3q8mig\" rootelm=\"\"\r\n                                    data-container=\"true\" data-quicktoolbar=\"true\">\r\n                                    <!---->\r\n                                    <div id=\"_iwd_15qf3qstlg\" data-resizable=\"true\" data-press=\"false\"\r\n                                        data-taborder=\"true\" class=\"component-guideline component hammer w2grid wq_gvw\"\r\n                                        data-role=\"component\" data-uuid=\"_iwd_15qf3qstlg\" data-parent=\"_iwd_15qf3qn1f0\"\r\n                                        rootelm=\"\"\r\n                                        style=\"overflow: auto; border-spacing: 0px; border-collapse: collapse; table-layout: fixed; height: 50px;\">\r\n                                        <!---->\r\n                                        <div mark=\"grid.mainDiv\">\r\n                                            <table width=\"380\" class=\"component-guideline component hammer\"\r\n                                                data-role=\"component\" data-uuid=\"_iwd_15qf3r5yo0\"\r\n                                                data-parent=\"_iwd_15qf3qstlg\"\r\n                                                style=\"border-spacing: 0px; border-collapse: collapse; table-layout: fixed;\">\r\n                                                <colgroup>\r\n                                                    <!---->\r\n                                                    <!---->\r\n                                                    <col width=\"80\">\r\n                                                    <col width=\"80\">\r\n                                                    <col width=\"110\">\r\n                                                    <col width=\"110\">\r\n                                                </colgroup>\r\n                                                <thead class=\"gridHeaderTableDefault\">\r\n                                                    <tr class=\"component hammer gridHeaderTRDefault\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf3rfc38\"\r\n                                                        style=\"height: 20px;\">\r\n                                                        <!---->\r\n                                                        <!---->\r\n                                                        <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                            width=\"80\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf3qstlg\"\r\n                                                            class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                            data-role=\"component\" data-uuid=\"_iwd_15qf3rny74\"\r\n                                                            data-parent=\"_iwd_15qf3rfc38\">\r\n                                                            <div class=\"grid_column_text_input_type\">\r\n                                                                <nobr>Type</nobr>\r\n                                                            </div>\r\n                                                        </th>\r\n                                                        <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                            width=\"80\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf3qstlg\"\r\n                                                            class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                            data-role=\"component\" data-uuid=\"_iwd_15qf3ssb4o\"\r\n                                                            data-parent=\"_iwd_15qf3rfc38\">\r\n                                                            <div class=\"grid_column_text_input_type\">\r\n                                                                <nobr>Count</nobr>\r\n                                                            </div>\r\n                                                        </th>\r\n                                                        <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                            width=\"110\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf3qstlg\"\r\n                                                            class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                            data-role=\"component\" data-uuid=\"_iwd_15qf3u64vo\"\r\n                                                            data-parent=\"_iwd_15qf3rfc38\">\r\n                                                            <div class=\"grid_column_text_input_type\">\r\n                                                                <nobr>Premium</nobr>\r\n                                                            </div>\r\n                                                        </th>\r\n                                                        <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                            width=\"110\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf3qstlg\"\r\n                                                            class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                            data-role=\"component\" data-uuid=\"_iwd_15qf3ufj2o\"\r\n                                                            data-parent=\"_iwd_15qf3rfc38\">\r\n                                                            <div class=\"grid_column_text_input_type\">\r\n                                                                <nobr>Insurance</nobr>\r\n                                                            </div>\r\n                                                        </th>\r\n                                                    </tr>\r\n                                                </thead>\r\n                                            </table>\r\n                                            <div mark=\"grid.dataLayer\">\r\n                                                <table width=\"380\" class=\"component-guideline component hammer\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf3v6t0o\"\r\n                                                    data-parent=\"_iwd_15qf3qstlg\"\r\n                                                    style=\"border-spacing: 0px; border-collapse: collapse; table-layout: fixed;\">\r\n                                                    <colgroup>\r\n                                                        <!---->\r\n                                                        <!---->\r\n                                                        <col width=\"80\">\r\n                                                        <col width=\"80\">\r\n                                                        <col width=\"110\">\r\n                                                        <col width=\"110\">\r\n                                                    </colgroup>\r\n                                                    <tbody class=\"gridBodyTableDefault\">\r\n                                                        <tr class=\"component hammer gridBodyTRDefault\"\r\n                                                            data-role=\"component\" data-uuid=\"_iwd_15qf3vftxw\"\r\n                                                            style=\"height: 20px;\">\r\n                                                            <!---->\r\n                                                            <!---->\r\n                                                            <td data-type=\"GridColumn\" tabindex=\"-1\"\r\n                                                                data-resizable=\"true\" width=\"80\" colspan=\"\" rowspan=\"\"\r\n                                                                rootelm=\"_iwd_15qf3qstlg\"\r\n                                                                class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                                data-role=\"component\" data-uuid=\"_iwd_15qf3wf5bc\"\r\n                                                                data-parent=\"_iwd_15qf3vftxw\" style=\"height: 20px;\">\r\n                                                                <div class=\"grid_column_selectbox_input_type\">\r\n                                                                    <!---->\r\n                                                                </div>\r\n                                                            </td>\r\n                                                            <td data-type=\"GridColumn\" tabindex=\"-1\"\r\n                                                                data-resizable=\"true\" width=\"80\" colspan=\"\" rowspan=\"\"\r\n                                                                rootelm=\"_iwd_15qf3qstlg\"\r\n                                                                class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                                data-role=\"component\" data-uuid=\"_iwd_15qf3ztbm8\"\r\n                                                                data-parent=\"_iwd_15qf3vftxw\" style=\"height: 20px;\">\r\n                                                                <div class=\"grid_column_text_input_type\">\r\n                                                                    <nobr></nobr>\r\n                                                                </div>\r\n                                                            </td>\r\n                                                            <td data-type=\"GridColumn\" tabindex=\"-1\"\r\n                                                                data-resizable=\"true\" width=\"110\" colspan=\"\" rowspan=\"\"\r\n                                                                rootelm=\"_iwd_15qf3qstlg\"\r\n                                                                class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                                data-role=\"component\" data-uuid=\"_iwd_15qf40140o\"\r\n                                                                data-parent=\"_iwd_15qf3vftxw\">\r\n                                                                <div class=\"grid_column_text_input_type\">\r\n                                                                    <nobr></nobr>\r\n                                                                </div>\r\n                                                            </td>\r\n                                                            <td data-type=\"GridColumn\" tabindex=\"-1\"\r\n                                                                data-resizable=\"true\" width=\"110\" colspan=\"\" rowspan=\"\"\r\n                                                                rootelm=\"_iwd_15qf3qstlg\"\r\n                                                                class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                                data-role=\"component\" data-uuid=\"_iwd_15qf406tko\"\r\n                                                                data-parent=\"_iwd_15qf3vftxw\">\r\n                                                                <div class=\"grid_column_text_input_type\">\r\n                                                                    <nobr></nobr>\r\n                                                                </div>\r\n                                                            </td>\r\n                                                        </tr>\r\n                                                    </tbody>\r\n                                                </table>\r\n                                            </div>\r\n                                            <!---->\r\n                                        </div>\r\n                                    </div>\r\n                                </div>\r\n                            </div>\r\n                            <div id=\"_iwd_15qf40c78w\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2group box_right ly50\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf40c78w\" data-parent=\"_iwd_15qf3q2sbs\"\r\n                                rootelm=\"\" data-container=\"true\" data-quicktoolbar=\"true\">\r\n                                <!---->\r\n                                <div id=\"_iwd_15qf40f7i4\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                                    class=\"component-guideline component hammer w2group ml10\" data-role=\"component\"\r\n                                    data-uuid=\"_iwd_15qf40f7i4\" data-parent=\"_iwd_15qf40c78w\" rootelm=\"\"\r\n                                    data-container=\"true\" data-quicktoolbar=\"true\">\r\n                                    <!---->\r\n                                    <div id=\"_iwd_15qf40ilc8\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\"\r\n                                        data-resizable=\"true\"\r\n                                        class=\"component-guideline component hammer w2group dfbox mt0\"\r\n                                        data-role=\"component\" data-uuid=\"_iwd_15qf40ilc8\" data-parent=\"_iwd_15qf40f7i4\"\r\n                                        rootelm=\"\" data-container=\"true\" data-quicktoolbar=\"true\">\r\n                                        <!---->\r\n                                        <div id=\"_iwd_15qf40mmsc\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                            data-role=\"component\"\r\n                                            class=\"component-guideline component hammer w2textbox df_tit fl\"\r\n                                            data-uuid=\"_iwd_15qf40mmsc\" data-parent=\"_iwd_15qf40ilc8\" rootelm=\"\">\r\n                                            Campaigns</div>\r\n                                    </div>\r\n                                    <div id=\"_iwd_15qf40pems\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\"\r\n                                        data-resizable=\"true\"\r\n                                        class=\"component-guideline component hammer w2group gvwbox\"\r\n                                        data-role=\"component\" data-uuid=\"_iwd_15qf40pems\" data-parent=\"_iwd_15qf40f7i4\"\r\n                                        rootelm=\"\" data-container=\"true\" data-quicktoolbar=\"true\">\r\n                                        <!---->\r\n                                        <div id=\"_iwd_15qf40sr2w\" data-resizable=\"true\" data-press=\"false\"\r\n                                            data-taborder=\"true\"\r\n                                            class=\"component-guideline component hammer w2grid wq_gvw\"\r\n                                            data-role=\"component\" data-uuid=\"_iwd_15qf40sr2w\"\r\n                                            data-parent=\"_iwd_15qf40pems\" rootelm=\"\"\r\n                                            style=\"overflow: auto; border-spacing: 0px; border-collapse: collapse; table-layout: fixed; height: 70px;\">\r\n                                            <!---->\r\n                                            <div mark=\"grid.mainDiv\">\r\n                                                <table width=\"520\" class=\"component-guideline component hammer\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf411bvk\"\r\n                                                    data-parent=\"_iwd_15qf40sr2w\"\r\n                                                    style=\"border-spacing: 0px; border-collapse: collapse; table-layout: fixed;\">\r\n                                                    <colgroup>\r\n                                                        <!---->\r\n                                                        <!---->\r\n                                                        <col width=\"200\">\r\n                                                        <col width=\"80\">\r\n                                                        <col width=\"120\">\r\n                                                        <col width=\"120\">\r\n                                                    </colgroup>\r\n                                                    <thead class=\"gridHeaderTableDefault\">\r\n                                                        <tr class=\"component hammer gridHeaderTRDefault\"\r\n                                                            data-role=\"component\" data-uuid=\"_iwd_15qf415kcg\"\r\n                                                            style=\"height: 20px;\">\r\n                                                            <!---->\r\n                                                            <!---->\r\n                                                            <th data-type=\"GridColumn\" tabindex=\"-1\"\r\n                                                                data-resizable=\"true\" width=\"200\" colspan=\"\" rowspan=\"\"\r\n                                                                rootelm=\"_iwd_15qf40sr2w\"\r\n                                                                class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                                data-role=\"component\" data-uuid=\"_iwd_15qf41dbfo\"\r\n                                                                data-parent=\"_iwd_15qf415kcg\">\r\n                                                                <div class=\"grid_column_text_input_type\">\r\n                                                                    <nobr>Campaign</nobr>\r\n                                                                </div>\r\n                                                            </th>\r\n                                                            <th data-type=\"GridColumn\" tabindex=\"-1\"\r\n                                                                data-resizable=\"true\" width=\"80\" colspan=\"\" rowspan=\"\"\r\n                                                                rootelm=\"_iwd_15qf40sr2w\"\r\n                                                                class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                                data-role=\"component\" data-uuid=\"_iwd_15qf426vk0\"\r\n                                                                data-parent=\"_iwd_15qf415kcg\">\r\n                                                                <div class=\"grid_column_text_input_type\">\r\n                                                                    <nobr>Status</nobr>\r\n                                                                </div>\r\n                                                            </th>\r\n                                                            <th data-type=\"GridColumn\" tabindex=\"-1\"\r\n                                                                data-resizable=\"true\" width=\"120\" colspan=\"\" rowspan=\"\"\r\n                                                                rootelm=\"_iwd_15qf40sr2w\"\r\n                                                                class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                                data-role=\"component\" data-uuid=\"_iwd_15qf42ep44\"\r\n                                                                data-parent=\"_iwd_15qf415kcg\">\r\n                                                                <div class=\"grid_column_text_input_type\">\r\n                                                                    <nobr>Starting</nobr>\r\n                                                                </div>\r\n                                                            </th>\r\n                                                            <th data-type=\"GridColumn\" tabindex=\"-1\"\r\n                                                                data-resizable=\"true\" width=\"120\" colspan=\"\" rowspan=\"\"\r\n                                                                rootelm=\"_iwd_15qf40sr2w\"\r\n                                                                class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                                data-role=\"component\" data-uuid=\"_iwd_15qf42k8yk\"\r\n                                                                data-parent=\"_iwd_15qf415kcg\">\r\n                                                                <div class=\"grid_column_text_input_type\">\r\n                                                                    <nobr>Ending</nobr>\r\n                                                                </div>\r\n                                                            </th>\r\n                                                        </tr>\r\n                                                    </thead>\r\n                                                </table>\r\n                                                <div mark=\"grid.dataLayer\">\r\n                                                    <table width=\"520\" class=\"component-guideline component hammer\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf42psyk\"\r\n                                                        data-parent=\"_iwd_15qf40sr2w\"\r\n                                                        style=\"border-spacing: 0px; border-collapse: collapse; table-layout: fixed;\">\r\n                                                        <colgroup>\r\n                                                            <!---->\r\n                                                            <!---->\r\n                                                            <col width=\"200\">\r\n                                                            <col width=\"80\">\r\n                                                            <col width=\"120\">\r\n                                                            <col width=\"120\">\r\n                                                        </colgroup>\r\n                                                        <tbody class=\"gridBodyTableDefault\">\r\n                                                            <tr class=\"component hammer gridBodyTRDefault\"\r\n                                                                data-role=\"component\" data-uuid=\"_iwd_15qf42tyq8\"\r\n                                                                style=\"height: 20px;\">\r\n                                                                <!---->\r\n                                                                <!---->\r\n                                                                <td data-type=\"GridColumn\" tabindex=\"-1\"\r\n                                                                    data-resizable=\"true\" width=\"200\" colspan=\"\"\r\n                                                                    rowspan=\"\" rootelm=\"_iwd_15qf40sr2w\"\r\n                                                                    class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                                    data-role=\"component\" data-uuid=\"_iwd_15qf42ypn0\"\r\n                                                                    data-parent=\"_iwd_15qf42tyq8\" style=\"height: 20px;\">\r\n                                                                    <div class=\"grid_column_text_input_type\">\r\n                                                                        <nobr></nobr>\r\n                                                                    </div>\r\n                                                                </td>\r\n                                                                <td data-type=\"GridColumn\" tabindex=\"-1\"\r\n                                                                    data-resizable=\"true\" width=\"80\" colspan=\"\"\r\n                                                                    rowspan=\"\" rootelm=\"_iwd_15qf40sr2w\"\r\n                                                                    class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                                    data-role=\"component\" data-uuid=\"_iwd_15qf437yz0\"\r\n                                                                    data-parent=\"_iwd_15qf42tyq8\" style=\"height: 20px;\">\r\n                                                                    <div class=\"grid_column_text_input_type\">\r\n                                                                        <nobr></nobr>\r\n                                                                    </div>\r\n                                                                </td>\r\n                                                                <td data-type=\"GridColumn\" tabindex=\"-1\"\r\n                                                                    data-resizable=\"true\" width=\"120\" colspan=\"\"\r\n                                                                    rowspan=\"\" rootelm=\"_iwd_15qf40sr2w\"\r\n                                                                    class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                                    data-role=\"component\" data-uuid=\"_iwd_15qf43ew4g\"\r\n                                                                    data-parent=\"_iwd_15qf42tyq8\">\r\n                                                                    <div class=\"grid_column_text_input_type\">\r\n                                                                        <nobr></nobr>\r\n                                                                    </div>\r\n                                                                </td>\r\n                                                                <td data-type=\"GridColumn\" tabindex=\"-1\"\r\n                                                                    data-resizable=\"true\" width=\"120\" colspan=\"\"\r\n                                                                    rowspan=\"\" rootelm=\"_iwd_15qf40sr2w\"\r\n                                                                    class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                                    data-role=\"component\" data-uuid=\"_iwd_15qf43m860\"\r\n                                                                    data-parent=\"_iwd_15qf42tyq8\">\r\n                                                                    <div class=\"grid_column_text_input_type\">\r\n                                                                        <nobr></nobr>\r\n                                                                    </div>\r\n                                                                </td>\r\n                                                            </tr>\r\n                                                        </tbody>\r\n                                                    </table>\r\n                                                </div>\r\n                                                <!---->\r\n                                            </div>\r\n                                        </div>\r\n                                    </div>\r\n                                </div>\r\n                            </div>\r\n                        </div>\r\n                        <div id=\"_iwd_15qf43ueaw\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group ly_box\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf43ueaw\" data-parent=\"_iwd_15qf3pvqxk\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\" style=\"width: 98%; height: 40%;\">\r\n                            <!---->\r\n                            <div id=\"_iwd_15qf43yssg\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2group box_left ly50\" data-role=\"component\"\r\n                                data-uuid=\"_iwd_15qf43yssg\" data-parent=\"_iwd_15qf43ueaw\" rootelm=\"\"\r\n                                data-container=\"true\" data-quicktoolbar=\"true\">\r\n                                <!---->\r\n                                <div id=\"_iwd_15qf442y90\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                                    class=\"component-guideline component hammer w2group dfbox\" data-role=\"component\"\r\n                                    data-uuid=\"_iwd_15qf442y90\" data-parent=\"_iwd_15qf43yssg\" rootelm=\"\"\r\n                                    data-container=\"true\" data-quicktoolbar=\"true\">\r\n                                    <!---->\r\n                                    <div id=\"_iwd_15qf446kko\" tabindex=\"-1\" data-resizable=\"true\" data-role=\"component\"\r\n                                        class=\"component-guideline component hammer w2textbox df_tit fl\"\r\n                                        data-uuid=\"_iwd_15qf446kko\" data-parent=\"_iwd_15qf442y90\" rootelm=\"\">Customer\r\n                                        Classification</div>\r\n                                </div>\r\n                                <div id=\"_iwd_15qf449e70\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                                    class=\"component-guideline component hammer w2group gvwbox\" data-role=\"component\"\r\n                                    data-uuid=\"_iwd_15qf449e70\" data-parent=\"_iwd_15qf43yssg\" rootelm=\"\"\r\n                                    data-container=\"true\" data-quicktoolbar=\"true\">\r\n                                    <!---->\r\n                                    <div id=\"_iwd_15qf44cq3o\" data-resizable=\"true\" data-press=\"false\"\r\n                                        data-taborder=\"true\" class=\"component-guideline component hammer w2grid wq_gvw\"\r\n                                        data-role=\"component\" data-uuid=\"_iwd_15qf44cq3o\" data-parent=\"_iwd_15qf449e70\"\r\n                                        rootelm=\"\"\r\n                                        style=\"overflow: auto; border-spacing: 0px; border-collapse: collapse; table-layout: fixed; height: 70px;\">\r\n                                        <!---->\r\n                                        <div mark=\"grid.mainDiv\">\r\n                                            <table width=\"410\" class=\"component-guideline component hammer\"\r\n                                                data-role=\"component\" data-uuid=\"_iwd_15qf44ntps\"\r\n                                                data-parent=\"_iwd_15qf44cq3o\"\r\n                                                style=\"border-spacing: 0px; border-collapse: collapse; table-layout: fixed;\">\r\n                                                <colgroup>\r\n                                                    <!---->\r\n                                                    <!---->\r\n                                                    <col width=\"80\">\r\n                                                    <col width=\"130\">\r\n                                                    <col width=\"200\">\r\n                                                </colgroup>\r\n                                                <thead class=\"gridHeaderTableDefault\">\r\n                                                    <tr class=\"component hammer gridHeaderTRDefault\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf44u1v8\"\r\n                                                        style=\"height: 20px;\">\r\n                                                        <!---->\r\n                                                        <!---->\r\n                                                        <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                            width=\"80\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf44cq3o\"\r\n                                                            class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                            data-role=\"component\" data-uuid=\"_iwd_15qf450pww\"\r\n                                                            data-parent=\"_iwd_15qf44u1v8\">\r\n                                                            <div class=\"grid_column_text_input_type\">\r\n                                                                <nobr>Type</nobr>\r\n                                                            </div>\r\n                                                        </th>\r\n                                                        <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                            width=\"130\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf44cq3o\"\r\n                                                            class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                            data-role=\"component\" data-uuid=\"_iwd_15qf45g7xs\"\r\n                                                            data-parent=\"_iwd_15qf44u1v8\">\r\n                                                            <div class=\"grid_column_text_input_type\">\r\n                                                                <nobr>Category</nobr>\r\n                                                            </div>\r\n                                                        </th>\r\n                                                        <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                            width=\"200\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf44cq3o\"\r\n                                                            class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                            data-role=\"component\" data-uuid=\"_iwd_15qf45nha4\"\r\n                                                            data-parent=\"_iwd_15qf44u1v8\">\r\n                                                            <div class=\"grid_column_text_input_type\">\r\n                                                                <nobr>Description</nobr>\r\n                                                            </div>\r\n                                                        </th>\r\n                                                    </tr>\r\n                                                </thead>\r\n                                            </table>\r\n                                            <div mark=\"grid.dataLayer\">\r\n                                                <table width=\"410\" class=\"component-guideline component hammer\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf45u9hs\"\r\n                                                    data-parent=\"_iwd_15qf44cq3o\"\r\n                                                    style=\"border-spacing: 0px; border-collapse: collapse; table-layout: fixed;\">\r\n                                                    <colgroup>\r\n                                                        <!---->\r\n                                                        <!---->\r\n                                                        <col width=\"80\">\r\n                                                        <col width=\"130\">\r\n                                                        <col width=\"200\">\r\n                                                    </colgroup>\r\n                                                    <tbody class=\"gridBodyTableDefault\">\r\n                                                        <tr class=\"component hammer gridBodyTRDefault\"\r\n                                                            data-role=\"component\" data-uuid=\"_iwd_15qf45yn4s\"\r\n                                                            style=\"height: 20px;\">\r\n                                                            <!---->\r\n                                                            <!---->\r\n                                                            <td data-type=\"GridColumn\" tabindex=\"-1\"\r\n                                                                data-resizable=\"true\" width=\"80\" colspan=\"\" rowspan=\"\"\r\n                                                                rootelm=\"_iwd_15qf44cq3o\"\r\n                                                                class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                                data-role=\"component\" data-uuid=\"_iwd_15qf463qjk\"\r\n                                                                data-parent=\"_iwd_15qf45yn4s\" style=\"height: 20px;\">\r\n                                                                <div class=\"grid_column_text_input_type\">\r\n                                                                    <nobr></nobr>\r\n                                                                </div>\r\n                                                            </td>\r\n                                                            <td data-type=\"GridColumn\" tabindex=\"-1\"\r\n                                                                data-resizable=\"true\" width=\"130\" colspan=\"\" rowspan=\"\"\r\n                                                                rootelm=\"_iwd_15qf44cq3o\"\r\n                                                                class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                                data-role=\"component\" data-uuid=\"_iwd_15qf46fnsc\"\r\n                                                                data-parent=\"_iwd_15qf45yn4s\" style=\"height: 20px;\">\r\n                                                                <div class=\"grid_column_text_input_type\">\r\n                                                                    <nobr></nobr>\r\n                                                                </div>\r\n                                                            </td>\r\n                                                            <td data-type=\"GridColumn\" tabindex=\"-1\"\r\n                                                                data-resizable=\"true\" width=\"200\" colspan=\"\" rowspan=\"\"\r\n                                                                rootelm=\"_iwd_15qf44cq3o\"\r\n                                                                class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                                data-role=\"component\" data-uuid=\"_iwd_15qf46o1ps\"\r\n                                                                data-parent=\"_iwd_15qf45yn4s\">\r\n                                                                <div class=\"grid_column_text_input_type\">\r\n                                                                    <nobr></nobr>\r\n                                                                </div>\r\n                                                            </td>\r\n                                                        </tr>\r\n                                                    </tbody>\r\n                                                </table>\r\n                                            </div>\r\n                                            <!---->\r\n                                        </div>\r\n                                    </div>\r\n                                </div>\r\n                                <div id=\"_iwd_15qf46vcog\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                                    class=\"component-guideline component hammer w2group exe_box mt5\"\r\n                                    data-role=\"component\" data-uuid=\"_iwd_15qf46vcog\" data-parent=\"_iwd_15qf43yssg\"\r\n                                    rootelm=\"\" data-container=\"true\" data-quicktoolbar=\"true\">\r\n                                    <!---->\r\n                                    <div id=\"_iwd_15qf46zlrk\" tabindex=\"-1\" data-resizable=\"true\" data-role=\"component\"\r\n                                        class=\"component-guideline component hammer w2textbox\"\r\n                                        data-uuid=\"_iwd_15qf46zlrk\" data-parent=\"_iwd_15qf46vcog\" rootelm=\"\">※ CRM data\r\n                                        is from the closing date of the previous month, and is updated monthly.</div>\r\n                                    <div id=\"_iwd_15qf476v14\" tabindex=\"-1\" data-resizable=\"true\" data-role=\"component\"\r\n                                        class=\"component-guideline component hammer w2textbox mt5\"\r\n                                        data-uuid=\"_iwd_15qf476v14\" data-parent=\"_iwd_15qf46vcog\" rootelm=\"\">※ Use only\r\n                                        for consulting purposes. Do not provided printed materials to the clients.</div>\r\n                                </div>\r\n                            </div>\r\n                            <div id=\"_iwd_15qf47dhuc\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2group box_right ly50\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf47dhuc\" data-parent=\"_iwd_15qf43ueaw\"\r\n                                rootelm=\"\" data-container=\"true\" data-quicktoolbar=\"true\">\r\n                                <!---->\r\n                                <div id=\"_iwd_15qf47gqw8\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                                    class=\"component-guideline component hammer w2group ml10\" data-role=\"component\"\r\n                                    data-uuid=\"_iwd_15qf47gqw8\" data-parent=\"_iwd_15qf47dhuc\" rootelm=\"\"\r\n                                    data-container=\"true\" data-quicktoolbar=\"true\">\r\n                                    <!---->\r\n                                    <div id=\"_iwd_15qf47jsjg\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\"\r\n                                        data-resizable=\"true\" class=\"component-guideline component hammer w2group dfbox\"\r\n                                        data-role=\"component\" data-uuid=\"_iwd_15qf47jsjg\" data-parent=\"_iwd_15qf47gqw8\"\r\n                                        rootelm=\"\" data-container=\"true\" data-quicktoolbar=\"true\">\r\n                                        <!---->\r\n                                        <div id=\"_iwd_15qf47mwvw\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                            data-role=\"component\"\r\n                                            class=\"component-guideline component hammer w2textbox df_tit fl\"\r\n                                            data-uuid=\"_iwd_15qf47mwvw\" data-parent=\"_iwd_15qf47jsjg\" rootelm=\"\">\r\n                                            Additional Sales Prediction and Recommended Products</div>\r\n                                    </div>\r\n                                    <div id=\"_iwd_15qf47ponk\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\"\r\n                                        data-resizable=\"true\"\r\n                                        class=\"component-guideline component hammer w2group gvwbox\"\r\n                                        data-role=\"component\" data-uuid=\"_iwd_15qf47ponk\" data-parent=\"_iwd_15qf47gqw8\"\r\n                                        rootelm=\"\" data-container=\"true\" data-quicktoolbar=\"true\">\r\n                                        <!---->\r\n                                        <div id=\"_iwd_15qf47t1y8\" data-resizable=\"true\" data-press=\"false\"\r\n                                            data-taborder=\"true\"\r\n                                            class=\"component-guideline component hammer w2grid wq_gvw\"\r\n                                            data-role=\"component\" data-uuid=\"_iwd_15qf47t1y8\"\r\n                                            data-parent=\"_iwd_15qf47ponk\" rootelm=\"\"\r\n                                            style=\"overflow: auto; border-spacing: 0px; border-collapse: collapse; table-layout: fixed;\">\r\n                                            <!---->\r\n                                            <div mark=\"grid.mainDiv\">\r\n                                                <table width=\"400\" class=\"component-guideline component hammer\"\r\n                                                    data-role=\"component\" data-uuid=\"_iwd_15qf484wsw\"\r\n                                                    data-parent=\"_iwd_15qf47t1y8\"\r\n                                                    style=\"border-spacing: 0px; border-collapse: collapse; table-layout: fixed;\">\r\n                                                    <colgroup>\r\n                                                        <!---->\r\n                                                        <!---->\r\n                                                        <col width=\"100\">\r\n                                                        <col width=\"100\">\r\n                                                        <col width=\"100\">\r\n                                                        <col width=\"100\">\r\n                                                    </colgroup>\r\n                                                    <thead class=\"gridHeaderTableDefault\">\r\n                                                        <tr class=\"component hammer gridHeaderTRDefault\"\r\n                                                            data-role=\"component\" data-uuid=\"_iwd_15qf48ble0\"\r\n                                                            style=\"height: 20px;\">\r\n                                                            <!---->\r\n                                                            <!---->\r\n                                                            <th data-type=\"GridColumn\" tabindex=\"-1\"\r\n                                                                data-resizable=\"true\" width=\"100\" colspan=\"\" rowspan=\"\"\r\n                                                                rootelm=\"_iwd_15qf47t1y8\"\r\n                                                                class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                                data-role=\"component\" data-uuid=\"_iwd_15qf48iels\"\r\n                                                                data-parent=\"_iwd_15qf48ble0\">\r\n                                                                <div class=\"grid_column_text_input_type\">\r\n                                                                    <nobr>Protection</nobr>\r\n                                                                </div>\r\n                                                            </th>\r\n                                                            <th data-type=\"GridColumn\" tabindex=\"-1\"\r\n                                                                data-resizable=\"true\" width=\"100\" colspan=\"\" rowspan=\"\"\r\n                                                                rootelm=\"_iwd_15qf47t1y8\"\r\n                                                                class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                                data-role=\"component\" data-uuid=\"_iwd_15qf48z5ow\"\r\n                                                                data-parent=\"_iwd_15qf48ble0\">\r\n                                                                <div class=\"grid_column_text_input_type\">\r\n                                                                    <nobr>Lifetime</nobr>\r\n                                                                </div>\r\n                                                            </th>\r\n                                                            <th data-type=\"GridColumn\" tabindex=\"-1\"\r\n                                                                data-resizable=\"true\" width=\"100\" colspan=\"\" rowspan=\"\"\r\n                                                                rootelm=\"_iwd_15qf47t1y8\"\r\n                                                                class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                                data-role=\"component\" data-uuid=\"_iwd_15qf497p3k\"\r\n                                                                data-parent=\"_iwd_15qf48ble0\">\r\n                                                                <div class=\"grid_column_text_input_type\">\r\n                                                                    <nobr>Pension</nobr>\r\n                                                                </div>\r\n                                                            </th>\r\n                                                            <th data-type=\"GridColumn\" tabindex=\"-1\"\r\n                                                                data-resizable=\"true\" width=\"100\" colspan=\"\" rowspan=\"\"\r\n                                                                rootelm=\"_iwd_15qf47t1y8\"\r\n                                                                class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                                data-role=\"component\" data-uuid=\"_iwd_15qf49gt14\"\r\n                                                                data-parent=\"_iwd_15qf48ble0\">\r\n                                                                <div class=\"grid_column_text_input_type\">\r\n                                                                    <nobr>Savings</nobr>\r\n                                                                </div>\r\n                                                            </th>\r\n                                                        </tr>\r\n                                                    </thead>\r\n                                                </table>\r\n                                                <div mark=\"grid.dataLayer\">\r\n                                                    <table width=\"400\" class=\"component-guideline component hammer\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf49r1bg\"\r\n                                                        data-parent=\"_iwd_15qf47t1y8\"\r\n                                                        style=\"border-spacing: 0px; border-collapse: collapse; table-layout: fixed;\">\r\n                                                        <colgroup>\r\n                                                            <!---->\r\n                                                            <!---->\r\n                                                            <col width=\"100\">\r\n                                                            <col width=\"100\">\r\n                                                            <col width=\"100\">\r\n                                                            <col width=\"100\">\r\n                                                        </colgroup>\r\n                                                        <tbody class=\"gridBodyTableDefault\">\r\n                                                            <tr class=\"component hammer gridBodyTRDefault\"\r\n                                                                data-role=\"component\" data-uuid=\"_iwd_15qf4a083s\"\r\n                                                                style=\"height: 20px;\">\r\n                                                                <!---->\r\n                                                                <!---->\r\n                                                                <td data-type=\"GridColumn\" tabindex=\"-1\"\r\n                                                                    data-resizable=\"true\" width=\"100\" colspan=\"\"\r\n                                                                    rowspan=\"\" rootelm=\"_iwd_15qf47t1y8\"\r\n                                                                    class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                                    data-role=\"component\" data-uuid=\"_iwd_15qf4a87u4\"\r\n                                                                    data-parent=\"_iwd_15qf4a083s\" style=\"height: 20px;\">\r\n                                                                    <div class=\"grid_column_text_input_type\">\r\n                                                                        <nobr></nobr>\r\n                                                                    </div>\r\n                                                                </td>\r\n                                                                <td data-type=\"GridColumn\" tabindex=\"-1\"\r\n                                                                    data-resizable=\"true\" width=\"100\" colspan=\"\"\r\n                                                                    rowspan=\"\" rootelm=\"_iwd_15qf47t1y8\"\r\n                                                                    class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                                    data-role=\"component\" data-uuid=\"_iwd_15qf4annmg\"\r\n                                                                    data-parent=\"_iwd_15qf4a083s\" style=\"height: 20px;\">\r\n                                                                    <div class=\"grid_column_text_input_type\">\r\n                                                                        <nobr></nobr>\r\n                                                                    </div>\r\n                                                                </td>\r\n                                                                <td data-type=\"GridColumn\" tabindex=\"-1\"\r\n                                                                    data-resizable=\"true\" width=\"100\" colspan=\"\"\r\n                                                                    rowspan=\"\" rootelm=\"_iwd_15qf47t1y8\"\r\n                                                                    class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                                    data-role=\"component\" data-uuid=\"_iwd_15qf4azdx8\"\r\n                                                                    data-parent=\"_iwd_15qf4a083s\">\r\n                                                                    <div class=\"grid_column_text_input_type\">\r\n                                                                        <nobr></nobr>\r\n                                                                    </div>\r\n                                                                </td>\r\n                                                                <td data-type=\"GridColumn\" tabindex=\"-1\"\r\n                                                                    data-resizable=\"true\" width=\"100\" colspan=\"\"\r\n                                                                    rowspan=\"\" rootelm=\"_iwd_15qf47t1y8\"\r\n                                                                    class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                                    data-role=\"component\" data-uuid=\"_iwd_15qf4b9vbc\"\r\n                                                                    data-parent=\"_iwd_15qf4a083s\">\r\n                                                                    <div class=\"grid_column_text_input_type\">\r\n                                                                        <nobr></nobr>\r\n                                                                    </div>\r\n                                                                </td>\r\n                                                            </tr>\r\n                                                        </tbody>\r\n                                                    </table>\r\n                                                </div>\r\n                                                <!---->\r\n                                            </div>\r\n                                        </div>\r\n                                    </div>\r\n                                    <div id=\"_iwd_15qf4bkgn4\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\"\r\n                                        data-resizable=\"true\" class=\"component-guideline component hammer w2group mt5\"\r\n                                        data-role=\"component\" data-uuid=\"_iwd_15qf4bkgn4\" data-parent=\"_iwd_15qf47gqw8\"\r\n                                        rootelm=\"\" data-container=\"true\" data-quicktoolbar=\"true\" style=\"height: 49px;\">\r\n                                        <!----> <textarea id=\"_iwd_15qf4n34hw\" data-taborder=\"true\"\r\n                                            data-resizable=\"true\" readonly=\"readonly\"\r\n                                            class=\"component-guideline component hammer w2textarea --internal-textarea-cursor\"\r\n                                            data-role=\"component\" data-uuid=\"_iwd_15qf4n34hw\"\r\n                                            data-parent=\"_iwd_15qf4bkgn4\" rootelm=\"\"\r\n                                            style=\"cursor: default; width: 100%; height: 55px;\"></textarea></div>\r\n                                </div>\r\n                            </div>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div id=\"tbl_First_A011\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                class=\"component-guideline component hammer w2group tbbox mt10\" data-role=\"component\"\r\n                data-uuid=\"_iwd_15qf4nh9lo\" data-parent=\"_iwd_15qf0bdd38\" rootelm=\"\" data-container=\"true\"\r\n                data-quicktoolbar=\"true\">\r\n                <!---->\r\n                <table id=\"_iwd_15qf4nthvo\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                    class=\"component-guideline component hammer w2group w2tb tb\" data-role=\"component\"\r\n                    data-uuid=\"_iwd_15qf4nthvo\" data-parent=\"_iwd_15qf4nh9lo\" rootelm=\"\" data-container=\"true\"\r\n                    data-quicktoolbar=\"true\" style=\"position: relative; width: 100%;\">\r\n                    <!---->\r\n                    <colgroup id=\"_iwd_15qf4o8lh4\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                        class=\"component-guideline component hammer w2group\" data-role=\"component\"\r\n                        data-uuid=\"_iwd_15qf4o8lh4\" data-parent=\"_iwd_15qf4nthvo\" rootelm=\"_iwd_15qf4nthvo\"\r\n                        data-container=\"true\" data-quicktoolbar=\"true\">\r\n                        <!---->\r\n                        <col id=\"_iwd_15qf4odh3c\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf4odh3c\" data-parent=\"_iwd_15qf4o8lh4\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\" style=\"width: 110px;\">\r\n                        <col id=\"_iwd_15qf4oicsc\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf4oicsc\" data-parent=\"_iwd_15qf4o8lh4\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                        <col id=\"_iwd_15qf4omsfk\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf4omsfk\" data-parent=\"_iwd_15qf4o8lh4\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\" style=\"width: 100px;\">\r\n                        <col id=\"_iwd_15qf4or2r4\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf4or2r4\" data-parent=\"_iwd_15qf4o8lh4\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                        <col id=\"_iwd_15qf4ovarc\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf4ovarc\" data-parent=\"_iwd_15qf4o8lh4\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\" style=\"width: 110px;\">\r\n                        <col id=\"_iwd_15qf4ozlrw\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf4ozlrw\" data-parent=\"_iwd_15qf4o8lh4\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                    </colgroup>\r\n                    <tr id=\"_iwd_15qf4p46cw\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                        class=\"component hammer w2group\" data-role=\"component\" data-uuid=\"_iwd_15qf4p46cw\"\r\n                        data-parent=\"_iwd_15qf4nthvo\" rootelm=\"_iwd_15qf4nthvo\" data-container=\"true\"\r\n                        data-quicktoolbar=\"true\">\r\n                        <!---->\r\n                        <th id=\"_iwd_15qf4p8ba0\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_th\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf4p8ba0\" data-parent=\"_iwd_15qf4p46cw\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!----> <span id=\"_iwd_15qf4pcnu4\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2span\" data-role=\"component\"\r\n                                data-uuid=\"_iwd_15qf4pcnu4\" data-parent=\"_iwd_15qf4p8ba0\" rootelm=\"\">Office Phone</span>\r\n                        </th>\r\n                        <td id=\"_iwd_15qf4pggy8\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_td\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf4pggy8\" data-parent=\"_iwd_15qf4p46cw\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!---->\r\n                            <div id=\"_iwd_15qf4plkz8\" data-resizable=\"true\" data-taborder=\"true\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2selectbox\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf4plkz8\" data-parent=\"_iwd_15qf4pggy8\"\r\n                                rootelm=\"\" style=\"width: 32%;\">\r\n                                <table cellspacing=\"0\" cellpadding=\"0\" class=\"w2selectbox_table_main\">\r\n                                    <tbody>\r\n                                        <tr class=\"w2selectbox_row w2selectbox_row_main\">\r\n                                            <td class=\"w2selectbox_col_label\">\r\n                                                <div class=\"w2selectbox_label\">02</div>\r\n                                            </td>\r\n                                            <td class=\"w2selectbox_col_button\"></td>\r\n                                        </tr>\r\n                                    </tbody>\r\n                                </table>\r\n                            </div><input data-v-0f1195ec=\"\" id=\"_iwd_15qf4qwjpw\" data-resizable=\"true\"\r\n                                data-taborder=\"true\" type=\"text\" readonly=\"readonly\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2input --internal-input-cursor w2input_ref_binding\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf4qwjpw\" data-parent=\"_iwd_15qf4pggy8\"\r\n                                rootelm=\"\" style=\"width: 25%;\"><input data-v-0f1195ec=\"\" id=\"_iwd_15qf4r0lh4\"\r\n                                data-resizable=\"true\" data-taborder=\"true\" type=\"text\" readonly=\"readonly\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2input --internal-input-cursor w2input_ref_binding\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf4r0lh4\" data-parent=\"_iwd_15qf4pggy8\"\r\n                                rootelm=\"\" style=\"width: 30%;\">\r\n                        </td>\r\n                        <th id=\"_iwd_15qf4r4jg8\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_th\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf4r4jg8\" data-parent=\"_iwd_15qf4p46cw\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!----> <span id=\"_iwd_15qf4r9npk\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2span\" data-role=\"component\"\r\n                                data-uuid=\"_iwd_15qf4r9npk\" data-parent=\"_iwd_15qf4r4jg8\" rootelm=\"\">Office\r\n                                Address</span></th>\r\n                        <td id=\"_iwd_15qf4rdrs4\" tabindex=\"-1\" rowspan=\"1\" colspan=\"3\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_td\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf4rdrs4\" data-parent=\"_iwd_15qf4p46cw\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!---->\r\n                            <div id=\"_iwd_15qf4ru2nw\" data-resizable=\"true\" data-taborder=\"true\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2selectbox\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf4ru2nw\" data-parent=\"_iwd_15qf4rdrs4\"\r\n                                rootelm=\"\" style=\"width: 15%;\">\r\n                                <table cellspacing=\"0\" cellpadding=\"0\" class=\"w2selectbox_table_main\">\r\n                                    <tbody>\r\n                                        <tr class=\"w2selectbox_row w2selectbox_row_main\">\r\n                                            <td class=\"w2selectbox_col_label\">\r\n                                                <div class=\"w2selectbox_label\">Road</div>\r\n                                            </td>\r\n                                            <td class=\"w2selectbox_col_button\"></td>\r\n                                        </tr>\r\n                                    </tbody>\r\n                                </table>\r\n                            </div><input data-v-0f1195ec=\"\" id=\"_iwd_15qf4ssjv8\" data-resizable=\"true\"\r\n                                data-taborder=\"true\" type=\"text\" readonly=\"readonly\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2input --internal-input-cursor w2input_disabled w2input_ref_binding\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf4ssjv8\" data-parent=\"_iwd_15qf4rdrs4\"\r\n                                rootelm=\"\" style=\"width: 16%;\"><a id=\"_iwd_15qf4swm0c\" href=\"javascript:void(0);\"\r\n                                data-role=\"component\" data-state=\"init\" data-taborder=\"true\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2anchor2 btn_search\"\r\n                                data-uuid=\"_iwd_15qf4swm0c\" data-parent=\"_iwd_15qf4rdrs4\" rootelm=\"\"></a><a\r\n                                id=\"_iwd_15qf4tepjw\" href=\"javascript:void(0);\" data-role=\"component\" data-state=\"init\"\r\n                                data-taborder=\"true\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2anchor2 btn_del\"\r\n                                data-uuid=\"_iwd_15qf4tepjw\" data-parent=\"_iwd_15qf4rdrs4\" rootelm=\"\"></a><input\r\n                                data-v-0f1195ec=\"\" id=\"_iwd_15qf4tmb8o\" data-resizable=\"true\" data-taborder=\"true\"\r\n                                type=\"text\" readonly=\"readonly\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2input --internal-input-cursor w2input_disabled w2input_ref_binding\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf4tmb8o\" data-parent=\"_iwd_15qf4rdrs4\"\r\n                                rootelm=\"\" style=\"width: 25%;\"><input data-v-0f1195ec=\"\" id=\"_iwd_15qf4tqdug\"\r\n                                data-resizable=\"true\" data-taborder=\"true\" type=\"text\" readonly=\"readonly\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2input --internal-input-cursor w2input_disabled w2input_ref_binding\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf4tqdug\" data-parent=\"_iwd_15qf4rdrs4\"\r\n                                rootelm=\"\" style=\"width: 20%;\"><input data-v-0f1195ec=\"\" id=\"_iwd_15qf4tvmkw\"\r\n                                data-resizable=\"true\" data-taborder=\"true\" type=\"text\" readonly=\"readonly\"\r\n                                class=\"component-guideline component hammer w2input --internal-input-cursor w2input_disabled\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf4tvmkw\" data-parent=\"_iwd_15qf4rdrs4\"\r\n                                rootelm=\"\" style=\"width: 5%;\">\r\n                        </td>\r\n                    </tr>\r\n                    <tr id=\"_iwd_15qf4ublfc\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                        class=\"component hammer w2group\" data-role=\"component\" data-uuid=\"_iwd_15qf4ublfc\"\r\n                        data-parent=\"_iwd_15qf4nthvo\" rootelm=\"_iwd_15qf4nthvo\" data-container=\"true\"\r\n                        data-quicktoolbar=\"true\">\r\n                        <!---->\r\n                        <th id=\"_iwd_15qf4ui0r4\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_th\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf4ui0r4\" data-parent=\"_iwd_15qf4ublfc\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!----> <span id=\"_iwd_15qf4uom0s\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2span\" data-role=\"component\"\r\n                                data-uuid=\"_iwd_15qf4uom0s\" data-parent=\"_iwd_15qf4ui0r4\" rootelm=\"\">Others</span></th>\r\n                        <td id=\"_iwd_15qf4utiy8\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_td\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf4utiy8\" data-parent=\"_iwd_15qf4ublfc\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!---->\r\n                            <div id=\"_iwd_15qf4uz978\" data-resizable=\"true\" data-taborder=\"true\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2selectbox\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf4uz978\" data-parent=\"_iwd_15qf4utiy8\"\r\n                                rootelm=\"\" style=\"width: 32%;\">\r\n                                <table cellspacing=\"0\" cellpadding=\"0\" class=\"w2selectbox_table_main\">\r\n                                    <tbody>\r\n                                        <tr class=\"w2selectbox_row w2selectbox_row_main\">\r\n                                            <td class=\"w2selectbox_col_label\">\r\n                                                <div class=\"w2selectbox_label\">02</div>\r\n                                            </td>\r\n                                            <td class=\"w2selectbox_col_button\"></td>\r\n                                        </tr>\r\n                                    </tbody>\r\n                                </table>\r\n                            </div><input data-v-0f1195ec=\"\" id=\"_iwd_15qf4wfj58\" data-resizable=\"true\"\r\n                                data-taborder=\"true\" type=\"text\" readonly=\"readonly\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2input --internal-input-cursor w2input_ref_binding\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf4wfj58\" data-parent=\"_iwd_15qf4utiy8\"\r\n                                rootelm=\"\" style=\"width: 25%;\"><input data-v-0f1195ec=\"\" id=\"_iwd_15qf4wk5fc\"\r\n                                data-resizable=\"true\" data-taborder=\"true\" type=\"text\" readonly=\"readonly\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2input --internal-input-cursor w2input_ref_binding\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf4wk5fc\" data-parent=\"_iwd_15qf4utiy8\"\r\n                                rootelm=\"\" style=\"width: 30%;\">\r\n                        </td>\r\n                        <th id=\"_iwd_15qf4wndec\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_th\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf4wndec\" data-parent=\"_iwd_15qf4ublfc\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!----> <span id=\"_iwd_15qf4wt8ic\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2span\" data-role=\"component\"\r\n                                data-uuid=\"_iwd_15qf4wt8ic\" data-parent=\"_iwd_15qf4wndec\" rootelm=\"\">ETC</span></th>\r\n                        <td id=\"_iwd_15qf4wwfk0\" tabindex=\"-1\" rowspan=\"1\" colspan=\"3\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_td\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf4wwfk0\" data-parent=\"_iwd_15qf4ublfc\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!---->\r\n                            <div id=\"_iwd_15qf4xgfgo\" data-resizable=\"true\" data-taborder=\"true\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2selectbox\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf4xgfgo\" data-parent=\"_iwd_15qf4wwfk0\"\r\n                                rootelm=\"\" style=\"width: 15%;\">\r\n                                <table cellspacing=\"0\" cellpadding=\"0\" class=\"w2selectbox_table_main\">\r\n                                    <tbody>\r\n                                        <tr class=\"w2selectbox_row w2selectbox_row_main\">\r\n                                            <td class=\"w2selectbox_col_label\">\r\n                                                <div class=\"w2selectbox_label\"></div>\r\n                                            </td>\r\n                                            <td class=\"w2selectbox_col_button\"></td>\r\n                                        </tr>\r\n                                    </tbody>\r\n                                </table>\r\n                            </div><input data-v-0f1195ec=\"\" id=\"_iwd_15qf4xkcqs\" data-resizable=\"true\"\r\n                                data-taborder=\"true\" type=\"text\" readonly=\"readonly\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2input --internal-input-cursor w2input_ref_binding\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf4xkcqs\" data-parent=\"_iwd_15qf4wwfk0\"\r\n                                rootelm=\"\" style=\"width: 16%;\"><a id=\"_iwd_15qf4xnot0\" href=\"javascript:void(0);\"\r\n                                data-role=\"component\" data-state=\"init\" data-taborder=\"true\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2anchor2 btn_search\"\r\n                                data-uuid=\"_iwd_15qf4xnot0\" data-parent=\"_iwd_15qf4wwfk0\" rootelm=\"\"></a><a\r\n                                id=\"_iwd_15qf4xrg2g\" href=\"javascript:void(0);\" data-role=\"component\" data-state=\"init\"\r\n                                data-taborder=\"true\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2anchor2 btn_del\"\r\n                                data-uuid=\"_iwd_15qf4xrg2g\" data-parent=\"_iwd_15qf4wwfk0\" rootelm=\"\"></a><input\r\n                                data-v-0f1195ec=\"\" id=\"_iwd_15qf4xv0uk\" data-resizable=\"true\" data-taborder=\"true\"\r\n                                type=\"text\" readonly=\"readonly\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2input --internal-input-cursor w2input_disabled w2input_ref_binding\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf4xv0uk\" data-parent=\"_iwd_15qf4wwfk0\"\r\n                                rootelm=\"\" style=\"width: 25%;\"><input data-v-0f1195ec=\"\" id=\"_iwd_15qf4xxja4\"\r\n                                data-resizable=\"true\" data-taborder=\"true\" type=\"text\" readonly=\"readonly\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2input --internal-input-cursor w2input_disabled w2input_ref_binding\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf4xxja4\" data-parent=\"_iwd_15qf4wwfk0\"\r\n                                rootelm=\"\" style=\"width: 20%;\"><input data-v-0f1195ec=\"\" id=\"_iwd_15qf4y1qqw\"\r\n                                data-resizable=\"true\" data-taborder=\"true\" type=\"text\" readonly=\"readonly\"\r\n                                class=\"component-guideline component hammer w2input --internal-input-cursor w2input_disabled\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf4y1qqw\" data-parent=\"_iwd_15qf4wwfk0\"\r\n                                rootelm=\"\" style=\"width: 5%;\">\r\n                        </td>\r\n                    </tr>\r\n                    <tr id=\"_iwd_15qf4y5vz4\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                        class=\"component hammer w2group\" data-role=\"component\" data-uuid=\"_iwd_15qf4y5vz4\"\r\n                        data-parent=\"_iwd_15qf4nthvo\" rootelm=\"_iwd_15qf4nthvo\" data-container=\"true\"\r\n                        data-quicktoolbar=\"true\">\r\n                        <!---->\r\n                        <th id=\"_iwd_15qf4yaxaw\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_th\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf4yaxaw\" data-parent=\"_iwd_15qf4y5vz4\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!----> <span id=\"_iwd_15qf4yeui8\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2span\" data-role=\"component\"\r\n                                data-uuid=\"_iwd_15qf4yeui8\" data-parent=\"_iwd_15qf4yaxaw\" rootelm=\"\">FAx</span></th>\r\n                        <td id=\"_iwd_15qf4yhgy8\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_td\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf4yhgy8\" data-parent=\"_iwd_15qf4y5vz4\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!---->\r\n                            <div id=\"_iwd_15qf4ylm3o\" data-resizable=\"true\" data-taborder=\"true\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2selectbox\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf4ylm3o\" data-parent=\"_iwd_15qf4yhgy8\"\r\n                                rootelm=\"\" style=\"width: 32%;\">\r\n                                <table cellspacing=\"0\" cellpadding=\"0\" class=\"w2selectbox_table_main\">\r\n                                    <tbody>\r\n                                        <tr class=\"w2selectbox_row w2selectbox_row_main\">\r\n                                            <td class=\"w2selectbox_col_label\">\r\n                                                <div class=\"w2selectbox_label\">02</div>\r\n                                            </td>\r\n                                            <td class=\"w2selectbox_col_button\"></td>\r\n                                        </tr>\r\n                                    </tbody>\r\n                                </table>\r\n                            </div><input data-v-0f1195ec=\"\" id=\"_iwd_15qf4zlkmg\" data-resizable=\"true\"\r\n                                data-taborder=\"true\" type=\"text\" readonly=\"readonly\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2input --internal-input-cursor w2input_ref_binding\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf4zlkmg\" data-parent=\"_iwd_15qf4yhgy8\"\r\n                                rootelm=\"\" style=\"width: 25%;\"><input data-v-0f1195ec=\"\" id=\"_iwd_15qf4zpxc4\"\r\n                                data-resizable=\"true\" data-taborder=\"true\" type=\"text\" readonly=\"readonly\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2input --internal-input-cursor w2input_ref_binding\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf4zpxc4\" data-parent=\"_iwd_15qf4yhgy8\"\r\n                                rootelm=\"\" style=\"width: 30%;\">\r\n                        </td>\r\n                        <th id=\"_iwd_15qf4zu6vw\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_th\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf4zu6vw\" data-parent=\"_iwd_15qf4y5vz4\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!----> <span id=\"_iwd_15qf4zz7zc\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2span\" data-role=\"component\"\r\n                                data-uuid=\"_iwd_15qf4zz7zc\" data-parent=\"_iwd_15qf4zu6vw\" rootelm=\"\">Preferred Mode of\r\n                                Contact</span></th>\r\n                        <td id=\"_iwd_15qf5038no\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_td\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf5038no\" data-parent=\"_iwd_15qf4y5vz4\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!---->\r\n                            <div id=\"_iwd_15qf50a2q0\" data-taborder=\"true\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2checkbox\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf50a2q0\" data-parent=\"_iwd_15qf5038no\"\r\n                                rootelm=\"\">\r\n                                <div class=\"w2checkbox_item\"><input type=\"checkbox\" index=\"0\" tabindex=\"0\"\r\n                                        class=\"w2checkbox_input\"> <label index=\"0\" class=\"w2checkbox_label\">Call</label>\r\n                                </div>\r\n                                <div class=\"w2checkbox_item\"><input type=\"checkbox\" index=\"1\" tabindex=\"0\"\r\n                                        class=\"w2checkbox_input\"> <label index=\"1\"\r\n                                        class=\"w2checkbox_label\">E-Mail</label></div>\r\n                                <div class=\"w2checkbox_item\"><input type=\"checkbox\" index=\"2\" tabindex=\"0\"\r\n                                        class=\"w2checkbox_input\"> <label index=\"2\" class=\"w2checkbox_label\">SMS</label>\r\n                                </div>\r\n                                <div class=\"w2checkbox_item\"><input type=\"checkbox\" index=\"3\" tabindex=\"0\"\r\n                                        class=\"w2checkbox_input\"> <label index=\"3\"\r\n                                        class=\"w2checkbox_label\">Visit</label></div>\r\n                            </div>\r\n                        </td>\r\n                        <th id=\"_iwd_15qf51o2ss\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_th\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf51o2ss\" data-parent=\"_iwd_15qf4y5vz4\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!----> <span id=\"_iwd_15qf51tzrg\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2span\" data-role=\"component\"\r\n                                data-uuid=\"_iwd_15qf51tzrg\" data-parent=\"_iwd_15qf51o2ss\" rootelm=\"\">Postal\r\n                                Address</span></th>\r\n                        <td id=\"_iwd_15qf51yaxk\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_td\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf51yaxk\" data-parent=\"_iwd_15qf4y5vz4\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!---->\r\n                            <div id=\"_iwd_15qf523rb0\" data-resizable=\"true\" data-taborder=\"true\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2selectbox\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf523rb0\" data-parent=\"_iwd_15qf51yaxk\"\r\n                                rootelm=\"\" style=\"width: 100%;\">\r\n                                <table cellspacing=\"0\" cellpadding=\"0\" class=\"w2selectbox_table_main\">\r\n                                    <tbody>\r\n                                        <tr class=\"w2selectbox_row w2selectbox_row_main\">\r\n                                            <td class=\"w2selectbox_col_label\">\r\n                                                <div class=\"w2selectbox_label\">Home</div>\r\n                                            </td>\r\n                                            <td class=\"w2selectbox_col_button\"></td>\r\n                                        </tr>\r\n                                    </tbody>\r\n                                </table>\r\n                            </div>\r\n                        </td>\r\n                    </tr>\r\n                    <tr id=\"_iwd_15qf53t2hc\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                        class=\"component hammer w2group\" data-role=\"component\" data-uuid=\"_iwd_15qf53t2hc\"\r\n                        data-parent=\"_iwd_15qf4nthvo\" rootelm=\"_iwd_15qf4nthvo\" data-container=\"true\"\r\n                        data-quicktoolbar=\"true\">\r\n                        <!---->\r\n                        <th id=\"_iwd_15qf53x6s8\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_th\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf53x6s8\" data-parent=\"_iwd_15qf53t2hc\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!----> <span id=\"_iwd_15qf540kp4\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2span\" data-role=\"component\"\r\n                                data-uuid=\"_iwd_15qf540kp4\" data-parent=\"_iwd_15qf53x6s8\" rootelm=\"\">Date of\r\n                                Birth</span></th>\r\n                        <td id=\"_iwd_15qf543a2o\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_td\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf543a2o\" data-parent=\"_iwd_15qf53t2hc\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!---->\r\n                            <div id=\"_iwd_15qf546p58\" data-taborder=\"true\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2inputCalendar_div ast\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf546p58\" data-parent=\"_iwd_15qf543a2o\"\r\n                                rootelm=\"\" style=\"width: 100px;\">\r\n                                <div class=\"w2inputCalendar_div_input\" style=\"width: 100%;\"><input tabindex=\"-1\"\r\n                                        readonly=\"readonly\" class=\"w2inputCalendar_divInput\"\r\n                                        style=\"width: calc(100% - 25px); height: 100%; box-sizing: border-box;\">\r\n                                    <div class=\"w2inputCalendar_div_img\" style=\"display: flex; align-items: center;\">\r\n                                        <button tabindex=\"-1\" readonly=\"readonly\" class=\"w2inputCalendar_button\"\r\n                                            style=\"background-image: url(&quot;/websquare/uiplugin/inputCalendar/images/icon_calendar.gif&quot;);\"></button>\r\n                                    </div>\r\n                                </div>\r\n                            </div>\r\n                            <div id=\"_iwd_15qf54a6j4\" data-taborder=\"true\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2radio\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf54a6j4\" data-parent=\"_iwd_15qf543a2o\"\r\n                                rootelm=\"\">\r\n                                <div class=\"w2radio_item\"><input type=\"radio\" index=\"0\" tabindex=\"0\"\r\n                                        class=\"w2radio_input\"> <label index=\"0\" class=\"w2radio_label\">Solar</label>\r\n                                </div>\r\n                                <div class=\"w2radio_item\"><input type=\"radio\" index=\"1\" tabindex=\"0\"\r\n                                        class=\"w2radio_input\"> <label index=\"1\" class=\"w2radio_label\">Lunar</label>\r\n                                </div>\r\n                            </div>\r\n                        </td>\r\n                        <th id=\"_iwd_15qf54t9vk\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_th\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf54t9vk\" data-parent=\"_iwd_15qf53t2hc\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!----> <span id=\"_iwd_15qf54wjjo\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2span\" data-role=\"component\"\r\n                                data-uuid=\"_iwd_15qf54wjjo\" data-parent=\"_iwd_15qf54t9vk\" rootelm=\"\">Wedding Day</span>\r\n                        </th>\r\n                        <td id=\"_iwd_15qf54z2ts\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_td\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf54z2ts\" data-parent=\"_iwd_15qf53t2hc\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!---->\r\n                            <div id=\"_iwd_15qf552c9k\" data-taborder=\"true\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2inputCalendar_div ast\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf552c9k\" data-parent=\"_iwd_15qf54z2ts\"\r\n                                rootelm=\"\" style=\"width: 100px;\">\r\n                                <div class=\"w2inputCalendar_div_input\" style=\"width: 100%;\"><input tabindex=\"-1\"\r\n                                        readonly=\"readonly\" class=\"w2inputCalendar_divInput\"\r\n                                        style=\"width: calc(100% - 25px); height: 100%; box-sizing: border-box;\">\r\n                                    <div class=\"w2inputCalendar_div_img\" style=\"display: flex; align-items: center;\">\r\n                                        <button tabindex=\"-1\" readonly=\"readonly\" class=\"w2inputCalendar_button\"\r\n                                            style=\"background-image: url(&quot;/websquare/uiplugin/inputCalendar/images/icon_calendar.gif&quot;);\"></button>\r\n                                    </div>\r\n                                </div>\r\n                            </div>\r\n                            <div id=\"_iwd_15qf555opo\" data-taborder=\"true\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2radio\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf555opo\" data-parent=\"_iwd_15qf54z2ts\"\r\n                                rootelm=\"\">\r\n                                <div class=\"w2radio_item\"><input type=\"radio\" index=\"0\" tabindex=\"0\"\r\n                                        class=\"w2radio_input\"> <label index=\"0\" class=\"w2radio_label\">Single</label>\r\n                                </div>\r\n                                <div class=\"w2radio_item\"><input type=\"radio\" index=\"1\" tabindex=\"0\"\r\n                                        class=\"w2radio_input\"> <label index=\"1\" class=\"w2radio_label\">Married</label>\r\n                                </div>\r\n                            </div>\r\n                        </td>\r\n                        <th id=\"_iwd_15qf55ocjs\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_th\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf55ocjs\" data-parent=\"_iwd_15qf53t2hc\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!----> <span id=\"_iwd_15qf55rjio\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2span\" data-role=\"component\"\r\n                                data-uuid=\"_iwd_15qf55rjio\" data-parent=\"_iwd_15qf55ocjs\" rootelm=\"\">Kindness</span>\r\n                        </th>\r\n                        <td id=\"_iwd_15qf55u210\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_td\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf55u210\" data-parent=\"_iwd_15qf53t2hc\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!---->\r\n                            <div id=\"_iwd_15qf55xvrc\" data-resizable=\"true\" data-taborder=\"true\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2selectbox\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf55xvrc\" data-parent=\"_iwd_15qf55u210\"\r\n                                rootelm=\"\" style=\"width: 100%;\">\r\n                                <table cellspacing=\"0\" cellpadding=\"0\" class=\"w2selectbox_table_main\">\r\n                                    <tbody>\r\n                                        <tr class=\"w2selectbox_row w2selectbox_row_main\">\r\n                                            <td class=\"w2selectbox_col_label\">\r\n                                                <div class=\"w2selectbox_label\">Very Kind</div>\r\n                                            </td>\r\n                                            <td class=\"w2selectbox_col_button\"></td>\r\n                                        </tr>\r\n                                    </tbody>\r\n                                </table>\r\n                            </div>\r\n                        </td>\r\n                    </tr>\r\n                    <tr id=\"_iwd_15qf57brz8\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                        class=\"component hammer w2group\" data-role=\"component\" data-uuid=\"_iwd_15qf57brz8\"\r\n                        data-parent=\"_iwd_15qf4nthvo\" rootelm=\"_iwd_15qf4nthvo\" data-container=\"true\"\r\n                        data-quicktoolbar=\"true\">\r\n                        <!---->\r\n                        <th id=\"_iwd_15qf57h3n8\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_th\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf57h3n8\" data-parent=\"_iwd_15qf57brz8\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!----> <span id=\"_iwd_15qf57m8d8\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2span\" data-role=\"component\"\r\n                                data-uuid=\"_iwd_15qf57m8d8\" data-parent=\"_iwd_15qf57h3n8\" rootelm=\"\">Company</span></th>\r\n                        <td id=\"_iwd_15qf57t19w\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_td\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf57t19w\" data-parent=\"_iwd_15qf57brz8\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!----> <input data-v-0f1195ec=\"\" id=\"_iwd_15qf57ycpk\" data-resizable=\"true\"\r\n                                data-taborder=\"true\" type=\"text\" readonly=\"readonly\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2input --internal-input-cursor w2input_ref_binding\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf57ycpk\" data-parent=\"_iwd_15qf57t19w\"\r\n                                rootelm=\"\" style=\"width: 100%;\"></td>\r\n                        <th id=\"_iwd_15qf582oyk\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_th\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf582oyk\" data-parent=\"_iwd_15qf57brz8\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!----> <span id=\"_iwd_15qf588b1k\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2span\" data-role=\"component\"\r\n                                data-uuid=\"_iwd_15qf588b1k\" data-parent=\"_iwd_15qf582oyk\" rootelm=\"\">Department</span>\r\n                        </th>\r\n                        <td id=\"_iwd_15qf58ciqo\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_td\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf58ciqo\" data-parent=\"_iwd_15qf57brz8\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!----> <input data-v-0f1195ec=\"\" id=\"_iwd_15qf58h260\" data-resizable=\"true\"\r\n                                data-taborder=\"true\" type=\"text\" readonly=\"readonly\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2input --internal-input-cursor w2input_ref_binding\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf58h260\" data-parent=\"_iwd_15qf58ciqo\"\r\n                                rootelm=\"\" style=\"width: 100%;\"></td>\r\n                        <th id=\"_iwd_15qf58l48c\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_th\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf58l48c\" data-parent=\"_iwd_15qf57brz8\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\"><span>Title</span> <span id=\"_iwd_15qf58zetc\" tabindex=\"-1\"\r\n                                data-resizable=\"true\" class=\"component-guideline component hammer w2span\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf58zetc\" data-parent=\"_iwd_15qf58l48c\"\r\n                                rootelm=\"\"></span></th>\r\n                        <td id=\"_iwd_15qf593taw\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_td\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf593taw\" data-parent=\"_iwd_15qf57brz8\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!----> <input data-v-0f1195ec=\"\" id=\"_iwd_15qf598ifs\" data-resizable=\"true\"\r\n                                data-taborder=\"true\" type=\"text\" readonly=\"readonly\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2input --internal-input-cursor w2input_ref_binding\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf598ifs\" data-parent=\"_iwd_15qf593taw\"\r\n                                rootelm=\"\" style=\"width: 100%;\"></td>\r\n                    </tr>\r\n                    <tr id=\"_iwd_15qf59d30s\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                        class=\"component hammer w2group\" data-role=\"component\" data-uuid=\"_iwd_15qf59d30s\"\r\n                        data-parent=\"_iwd_15qf4nthvo\" rootelm=\"_iwd_15qf4nthvo\" data-container=\"true\"\r\n                        data-quicktoolbar=\"true\">\r\n                        <!---->\r\n                        <th id=\"_iwd_15qf59hcq4\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_th\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf59hcq4\" data-parent=\"_iwd_15qf59d30s\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!----> <span id=\"_iwd_15qf59m6c4\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2span\" data-role=\"component\"\r\n                                data-uuid=\"_iwd_15qf59m6c4\" data-parent=\"_iwd_15qf59hcq4\" rootelm=\"\">Recommeded\r\n                                by</span></th>\r\n                        <td id=\"_iwd_15qf59q70g\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_td\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf59q70g\" data-parent=\"_iwd_15qf59d30s\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!----> <input data-v-0f1195ec=\"\" id=\"_iwd_15qf59ut7s\" data-resizable=\"true\"\r\n                                data-taborder=\"true\" type=\"text\" readonly=\"readonly\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2input --internal-input-cursor w2input_disabled w2input_ref_binding\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf59ut7s\" data-parent=\"_iwd_15qf59q70g\"\r\n                                rootelm=\"\" style=\"width: 72%;\"><a id=\"_iwd_15qf59yoq0\" href=\"javascript:void(0);\"\r\n                                data-role=\"component\" data-state=\"init\" data-taborder=\"true\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2anchor2 btn_search\"\r\n                                data-uuid=\"_iwd_15qf59yoq0\" data-parent=\"_iwd_15qf59q70g\" rootelm=\"\"></a><a\r\n                                id=\"_iwd_15qf5a4i24\" href=\"javascript:void(0);\" data-role=\"component\" data-state=\"init\"\r\n                                data-taborder=\"true\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2anchor2 btn_del\"\r\n                                data-uuid=\"_iwd_15qf5a4i24\" data-parent=\"_iwd_15qf59q70g\" rootelm=\"\"></a></td>\r\n                        <th id=\"_iwd_15qf5aaml0\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_th\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf5aaml0\" data-parent=\"_iwd_15qf59d30s\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!----> <span id=\"_iwd_15qf5afja4\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2span\" data-role=\"component\"\r\n                                data-uuid=\"_iwd_15qf5afja4\" data-parent=\"_iwd_15qf5aaml0\" rootelm=\"\">Relation</span>\r\n                        </th>\r\n                        <td id=\"_iwd_15qf5ajr4s\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_td\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf5ajr4s\" data-parent=\"_iwd_15qf59d30s\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!---->\r\n                            <div id=\"_iwd_15qf5aoxs8\" data-resizable=\"true\" data-taborder=\"true\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2selectbox\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf5aoxs8\" data-parent=\"_iwd_15qf5ajr4s\"\r\n                                rootelm=\"\" style=\"width: 100%;\">\r\n                                <table cellspacing=\"0\" cellpadding=\"0\" class=\"w2selectbox_table_main\">\r\n                                    <tbody>\r\n                                        <tr class=\"w2selectbox_row w2selectbox_row_main\">\r\n                                            <td class=\"w2selectbox_col_label\">\r\n                                                <div class=\"w2selectbox_label\">Relative</div>\r\n                                            </td>\r\n                                            <td class=\"w2selectbox_col_button\"></td>\r\n                                        </tr>\r\n                                    </tbody>\r\n                                </table>\r\n                            </div>\r\n                        </td>\r\n                        <th id=\"_iwd_15qf5bretc\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_th\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf5bretc\" data-parent=\"_iwd_15qf59d30s\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!----> <span id=\"_iwd_15qf5bwopg\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2span\" data-role=\"component\"\r\n                                data-uuid=\"_iwd_15qf5bwopg\" data-parent=\"_iwd_15qf5bretc\" rootelm=\"\">Education</span>\r\n                        </th>\r\n                        <td id=\"_iwd_15qf5bzud4\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_td\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf5bzud4\" data-parent=\"_iwd_15qf59d30s\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!---->\r\n                            <div id=\"_iwd_15qf5c5844\" data-resizable=\"true\" data-taborder=\"true\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2selectbox\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf5c5844\" data-parent=\"_iwd_15qf5bzud4\"\r\n                                rootelm=\"\" style=\"width: 100%;\">\r\n                                <table cellspacing=\"0\" cellpadding=\"0\" class=\"w2selectbox_table_main\">\r\n                                    <tbody>\r\n                                        <tr class=\"w2selectbox_row w2selectbox_row_main\">\r\n                                            <td class=\"w2selectbox_col_label\">\r\n                                                <div class=\"w2selectbox_label\">University</div>\r\n                                            </td>\r\n                                            <td class=\"w2selectbox_col_button\"></td>\r\n                                        </tr>\r\n                                    </tbody>\r\n                                </table>\r\n                            </div>\r\n                        </td>\r\n                    </tr>\r\n                    <tr id=\"_iwd_15qf5dfyis\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                        class=\"component hammer w2group\" data-role=\"component\" data-uuid=\"_iwd_15qf5dfyis\"\r\n                        data-parent=\"_iwd_15qf4nthvo\" rootelm=\"_iwd_15qf4nthvo\" data-container=\"true\"\r\n                        data-quicktoolbar=\"true\">\r\n                        <!---->\r\n                        <th id=\"_iwd_15qf5dk1fo\" tabindex=\"-1\" rowspan=\"2\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_th\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf5dk1fo\" data-parent=\"_iwd_15qf5dfyis\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!----> <span id=\"_iwd_15qf5dv3i8\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2span\" data-role=\"component\"\r\n                                data-uuid=\"_iwd_15qf5dv3i8\" data-parent=\"_iwd_15qf5dk1fo\"\r\n                                rootelm=\"\">Customer<br>Agreement</span></th>\r\n                        <td id=\"_iwd_15qf5e3th0\" tabindex=\"-1\" rowspan=\"2\" colspan=\"3\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_td\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf5e3th0\" data-parent=\"_iwd_15qf5dfyis\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!---->\r\n                            <div id=\"_iwd_15qf5eel4k\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2group gvwbox mt0\" data-role=\"component\"\r\n                                data-uuid=\"_iwd_15qf5eel4k\" data-parent=\"_iwd_15qf5e3th0\" rootelm=\"\"\r\n                                data-container=\"true\" data-quicktoolbar=\"true\">\r\n                                <!---->\r\n                                <div id=\"_iwd_15qf5eieh0\" data-resizable=\"true\" data-press=\"false\" data-taborder=\"true\"\r\n                                    class=\"component-guideline component hammer w2grid wq_gvw\" data-role=\"component\"\r\n                                    data-uuid=\"_iwd_15qf5eieh0\" data-parent=\"_iwd_15qf5eel4k\" rootelm=\"\"\r\n                                    style=\"overflow: auto; border-spacing: 0px; border-collapse: collapse; table-layout: fixed; height: 100px;\">\r\n                                    <!---->\r\n                                    <div mark=\"grid.mainDiv\">\r\n                                        <table width=\"590\" class=\"component-guideline component hammer\"\r\n                                            data-role=\"component\" data-uuid=\"_iwd_15qf5evlxo\"\r\n                                            data-parent=\"_iwd_15qf5eieh0\"\r\n                                            style=\"border-spacing: 0px; border-collapse: collapse; table-layout: fixed;\">\r\n                                            <colgroup>\r\n                                                <!---->\r\n                                                <!---->\r\n                                                <col width=\"80\">\r\n                                                <col width=\"100\">\r\n                                                <col width=\"130\">\r\n                                                <col width=\"100\">\r\n                                                <col width=\"100\">\r\n                                                <col width=\"80\">\r\n                                            </colgroup>\r\n                                            <thead class=\"gridHeaderTableDefault\">\r\n                                                <tr class=\"component hammer gridHeaderTRDefault\" data-role=\"component\"\r\n                                                    data-uuid=\"_iwd_15qf5f2p3s\" style=\"height: 20px;\">\r\n                                                    <!---->\r\n                                                    <!---->\r\n                                                    <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"80\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf5eieh0\"\r\n                                                        class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf5f977k\"\r\n                                                        data-parent=\"_iwd_15qf5f2p3s\">\r\n                                                        <div class=\"grid_column_text_input_type\">\r\n                                                            <nobr>System</nobr>\r\n                                                        </div>\r\n                                                    </th>\r\n                                                    <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"100\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf5eieh0\"\r\n                                                        class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf5frcls\"\r\n                                                        data-parent=\"_iwd_15qf5f2p3s\">\r\n                                                        <div class=\"grid_column_text_input_type\">\r\n                                                            <nobr>Job</nobr>\r\n                                                        </div>\r\n                                                    </th>\r\n                                                    <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"130\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf5eieh0\"\r\n                                                        class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf5fyaok\"\r\n                                                        data-parent=\"_iwd_15qf5f2p3s\">\r\n                                                        <div class=\"grid_column_text_input_type\">\r\n                                                            <nobr>Signature</nobr>\r\n                                                        </div>\r\n                                                    </th>\r\n                                                    <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"100\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf5eieh0\"\r\n                                                        class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf5g6pgk\"\r\n                                                        data-parent=\"_iwd_15qf5f2p3s\">\r\n                                                        <div class=\"grid_column_text_input_type\">\r\n                                                            <nobr>Approval Request Date</nobr>\r\n                                                        </div>\r\n                                                    </th>\r\n                                                    <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"100\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf5eieh0\"\r\n                                                        class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf5gflr4\"\r\n                                                        data-parent=\"_iwd_15qf5f2p3s\">\r\n                                                        <div class=\"grid_column_text_input_type\">\r\n                                                            <nobr>Activated on</nobr>\r\n                                                        </div>\r\n                                                    </th>\r\n                                                    <th data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                        width=\"80\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf5eieh0\"\r\n                                                        class=\"component hammer gridHeaderTDDefault gridHeaderTDDefault_data\"\r\n                                                        data-role=\"component\" data-uuid=\"_iwd_15qf5gnrqg\"\r\n                                                        data-parent=\"_iwd_15qf5f2p3s\">\r\n                                                        <div class=\"grid_column_text_input_type\">\r\n                                                            <nobr>Expiration</nobr>\r\n                                                        </div>\r\n                                                    </th>\r\n                                                </tr>\r\n                                            </thead>\r\n                                        </table>\r\n                                        <div mark=\"grid.dataLayer\">\r\n                                            <table width=\"590\" class=\"component-guideline component hammer\"\r\n                                                data-role=\"component\" data-uuid=\"_iwd_15qf5gxc3o\"\r\n                                                data-parent=\"_iwd_15qf5eieh0\"\r\n                                                style=\"border-spacing: 0px; border-collapse: collapse; table-layout: fixed;\">\r\n                                                <colgroup>\r\n                                                    <!---->\r\n                                                    <!---->\r\n                                                    <col width=\"80\">\r\n                                                    <col width=\"100\">\r\n                                                    <col width=\"130\">\r\n                                                    <col width=\"100\">\r\n                                                    <col width=\"100\">\r\n                                                    <col width=\"80\">\r\n                                                </colgroup>\r\n                                                <tbody class=\"gridBodyTableDefault\">\r\n                                                    <tr class=\"component hammer gridBodyTRDefault\" data-role=\"component\"\r\n                                                        data-uuid=\"_iwd_15qf5h3hec\" style=\"height: 20px;\">\r\n                                                        <!---->\r\n                                                        <!---->\r\n                                                        <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                            width=\"80\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf5eieh0\"\r\n                                                            class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                            data-role=\"component\" data-uuid=\"_iwd_15qf5ha5g0\"\r\n                                                            data-parent=\"_iwd_15qf5h3hec\" style=\"height: 20px;\">\r\n                                                            <div class=\"grid_column_selectbox_input_type\">\r\n                                                                <!---->\r\n                                                            </div>\r\n                                                        </td>\r\n                                                        <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                            width=\"100\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf5eieh0\"\r\n                                                            class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                            data-role=\"component\" data-uuid=\"_iwd_15qf5iilis\"\r\n                                                            data-parent=\"_iwd_15qf5h3hec\" style=\"height: 20px;\">\r\n                                                            <div class=\"grid_column_text_input_type\">\r\n                                                                <nobr></nobr>\r\n                                                            </div>\r\n                                                        </td>\r\n                                                        <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                            width=\"130\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf5eieh0\"\r\n                                                            class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                            data-role=\"component\" data-uuid=\"_iwd_15qf5ir0j4\"\r\n                                                            data-parent=\"_iwd_15qf5h3hec\" style=\"height: 20px;\">\r\n                                                            <div class=\"grid_column_text_input_type\">\r\n                                                                <nobr></nobr>\r\n                                                            </div>\r\n                                                        </td>\r\n                                                        <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                            width=\"100\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf5eieh0\"\r\n                                                            class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                            data-role=\"component\" data-uuid=\"_iwd_15qf5iybf0\"\r\n                                                            data-parent=\"_iwd_15qf5h3hec\">\r\n                                                            <div class=\"grid_column_text_input_type\">\r\n                                                                <nobr></nobr>\r\n                                                            </div>\r\n                                                        </td>\r\n                                                        <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                            width=\"100\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf5eieh0\"\r\n                                                            class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                            data-role=\"component\" data-uuid=\"_iwd_15qf5j4uog\"\r\n                                                            data-parent=\"_iwd_15qf5h3hec\">\r\n                                                            <div class=\"grid_column_text_input_type\">\r\n                                                                <nobr></nobr>\r\n                                                            </div>\r\n                                                        </td>\r\n                                                        <td data-type=\"GridColumn\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                                            width=\"80\" colspan=\"\" rowspan=\"\" rootelm=\"_iwd_15qf5eieh0\"\r\n                                                            class=\"component hammer gridBodyDefault gridBodyDefault_data\"\r\n                                                            data-role=\"component\" data-uuid=\"_iwd_15qf5jb0fs\"\r\n                                                            data-parent=\"_iwd_15qf5h3hec\">\r\n                                                            <div class=\"grid_column_text_input_type\">\r\n                                                                <nobr></nobr>\r\n                                                            </div>\r\n                                                        </td>\r\n                                                    </tr>\r\n                                                </tbody>\r\n                                            </table>\r\n                                        </div>\r\n                                        <!---->\r\n                                    </div>\r\n                                </div>\r\n                            </div>\r\n                        </td>\r\n                        <th id=\"_iwd_15qf5jhaac\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_th\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf5jhaac\" data-parent=\"_iwd_15qf5dfyis\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!----> <span id=\"_iwd_15qf5jknns\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2span\" data-role=\"component\"\r\n                                data-uuid=\"_iwd_15qf5jknns\" data-parent=\"_iwd_15qf5jhaac\" rootelm=\"\">Customer\r\n                                Group</span></th>\r\n                        <td id=\"_iwd_15qf5jnoj8\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_td\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf5jnoj8\" data-parent=\"_iwd_15qf5dfyis\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!----> <textarea id=\"_iwd_15qf5jr1ag\" data-taborder=\"true\" data-resizable=\"true\"\r\n                                readonly=\"readonly\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2textarea w2textarea_disabled w2textarea_ref_binding --internal-textarea-cursor\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf5jr1ag\" data-parent=\"_iwd_15qf5jnoj8\"\r\n                                rootelm=\"\" style=\"cursor: default; width: 100%; height: 40px;\"></textarea></td>\r\n                    </tr>\r\n                    <tr id=\"_iwd_15qf5ju6vc\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                        class=\"component hammer w2group\" data-role=\"component\" data-uuid=\"_iwd_15qf5ju6vc\"\r\n                        data-parent=\"_iwd_15qf4nthvo\" rootelm=\"_iwd_15qf4nthvo\" data-container=\"true\"\r\n                        data-quicktoolbar=\"true\">\r\n                        <!---->\r\n                        <th id=\"_iwd_15qf5jx6fk\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_th\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf5jx6fk\" data-parent=\"_iwd_15qf5ju6vc\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!----> <span id=\"_iwd_15qf5k0bbg\" tabindex=\"-1\" data-resizable=\"true\"\r\n                                class=\"component-guideline component hammer w2span\" data-role=\"component\"\r\n                                data-uuid=\"_iwd_15qf5k0bbg\" data-parent=\"_iwd_15qf5jx6fk\" rootelm=\"\">Memo</span></th>\r\n                        <td id=\"_iwd_15qf5k383o\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                            class=\"component-guideline component hammer w2group w2tb_td\" data-role=\"component\"\r\n                            data-uuid=\"_iwd_15qf5k383o\" data-parent=\"_iwd_15qf5ju6vc\" rootelm=\"\" data-container=\"true\"\r\n                            data-quicktoolbar=\"true\">\r\n                            <!----> <textarea id=\"_iwd_15qf5k6fos\" data-taborder=\"true\" data-resizable=\"true\"\r\n                                readonly=\"readonly\"\r\n                                class=\"component-guideline component hammer default_binding_wrap w2textarea w2textarea_ref_binding --internal-textarea-cursor\"\r\n                                data-role=\"component\" data-uuid=\"_iwd_15qf5k6fos\" data-parent=\"_iwd_15qf5k383o\"\r\n                                rootelm=\"\" style=\"cursor: default; width: 100%; height: 82px;\"></textarea></td>\r\n                    </tr>\r\n                </table>\r\n            </div>\r\n        </div>\r\n        <div id=\"_iwd_15qf5k9jf0\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n            class=\"component-guideline component hammer w2group dfbox\" data-role=\"component\" data-uuid=\"_iwd_15qf5k9jf0\"\r\n            data-parent=\"_iwd_15qeucfujs\" rootelm=\"\" data-container=\"true\" data-quicktoolbar=\"true\">\r\n            <!---->\r\n            <div id=\"_iwd_15qf5kbuio\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                class=\"component-guideline component hammer w2group fl\" data-role=\"component\"\r\n                data-uuid=\"_iwd_15qf5kbuio\" data-parent=\"_iwd_15qf5k9jf0\" rootelm=\"\" data-container=\"true\"\r\n                data-quicktoolbar=\"true\">\r\n                <!----> <a id=\"_iwd_15qf5kea0o\" href=\"javascript:void(0);\" data-role=\"component\" data-state=\"init\"\r\n                    data-taborder=\"true\" data-resizable=\"true\"\r\n                    class=\"component-guideline component hammer w2anchor2 btn_cm btn_cm_btr\" data-uuid=\"_iwd_15qf5kea0o\"\r\n                    data-parent=\"_iwd_15qf5kbuio\" rootelm=\"\">Training Material</a></div>\r\n            <div id=\"_iwd_15qf5kj5hc\" tabindex=\"-1\" rowspan=\"1\" colspan=\"1\" data-resizable=\"true\"\r\n                class=\"component-guideline component hammer w2group fr\" data-role=\"component\"\r\n                data-uuid=\"_iwd_15qf5kj5hc\" data-parent=\"_iwd_15qf5k9jf0\" rootelm=\"\" data-container=\"true\"\r\n                data-quicktoolbar=\"true\">\r\n                <!----> <a id=\"_iwd_15qf5kmqhs\" href=\"javascript:void(0);\" data-role=\"component\" data-state=\"init\"\r\n                    data-taborder=\"true\" data-resizable=\"true\"\r\n                    class=\"component-guideline component hammer w2anchor2 btn_cm btn_cm_btr\" data-uuid=\"_iwd_15qf5kmqhs\"\r\n                    data-parent=\"_iwd_15qf5kj5hc\" rootelm=\"\">Add Customer Group</a><a id=\"_iwd_15qf5kstpg\"\r\n                    href=\"javascript:void(0);\" data-role=\"component\" data-state=\"init\" data-taborder=\"true\"\r\n                    data-resizable=\"true\" class=\"component-guideline component hammer w2anchor2 btn_cm btn_cm_btr\"\r\n                    data-uuid=\"_iwd_15qf5kstpg\" data-parent=\"_iwd_15qf5kj5hc\" rootelm=\"\">E-mail</a><a\r\n                    id=\"_iwd_15qf5kypo0\" href=\"javascript:void(0);\" data-role=\"component\" data-state=\"init\"\r\n                    data-taborder=\"true\" data-resizable=\"true\"\r\n                    class=\"component-guideline component hammer w2anchor2 btn_cm btn_cm_btr\" data-uuid=\"_iwd_15qf5kypo0\"\r\n                    data-parent=\"_iwd_15qf5kj5hc\" rootelm=\"\">Policy Planning</a><a id=\"_iwd_15qf5l2tw4\"\r\n                    href=\"javascript:void(0);\" data-role=\"component\" data-state=\"init\" data-taborder=\"true\"\r\n                    data-resizable=\"true\" class=\"component-guideline component hammer w2anchor2 btn_cm btn_cm_btr\"\r\n                    data-uuid=\"_iwd_15qf5l2tw4\" data-parent=\"_iwd_15qf5kj5hc\" rootelm=\"\">Coverage Analysis</a><a\r\n                    id=\"_iwd_15qf5l9hjw\" href=\"javascript:void(0);\" data-role=\"component\" data-state=\"init\"\r\n                    data-taborder=\"true\" data-resizable=\"true\"\r\n                    class=\"component-guideline component hammer w2anchor2 btn_cm btn_cm_btr\" data-uuid=\"_iwd_15qf5l9hjw\"\r\n                    data-parent=\"_iwd_15qf5kj5hc\" rootelm=\"\">Future Plan</a><a id=\"_iwd_15qf5lh4h4\"\r\n                    href=\"javascript:void(0);\" data-role=\"component\" data-state=\"init\" data-taborder=\"true\"\r\n                    data-resizable=\"true\" class=\"component-guideline component hammer w2anchor2 btn_cm btn_cm_btr\"\r\n                    data-uuid=\"_iwd_15qf5lh4h4\" data-parent=\"_iwd_15qf5kj5hc\" rootelm=\"\">Recruiting</a></div>\r\n        </div>\r\n    </div>\r\n    <div data-v-7e9386c2=\"\" id=\"--internal-backgrid\" class=\"background-grid overlay\"\r\n        style=\"z-index: 2147483647; width: 1018px; height: 791px;\"></div> <svg xmlns=\"http://www.w3.org/2000/svg\"\r\n        xmlns:xlink=\"http://www.w3.org/1999/xlink\" version=\"1.1\" id=\"--internal-sketchpad\" fill-rule=\"evenodd\"\r\n        fill=\"none\" stroke=\"none\" stroke-linecap=\"square\" stroke-miterlimit=\"10\" overflow=\"hidden\"\r\n        preserveAspectRatio=\"none\" pointer-events=\"none\" class=\"sketchpad\"\r\n        style=\"z-index: 2147483647; width: 1018px; height: 791px;\">\r\n        <defs>\r\n            <pattern id=\"lightstripe\" patternUnits=\"userSpaceOnUse\" width=\"5\" height=\"5\"><svg\r\n                    xmlns=\"http://www.w3.org/2000/svg\" width=\"5\" height=\"5\">\r\n                    <rect width=\"5\" height=\"5\" fill=\"white\"></rect>\r\n                    <path d=\"M0 5L5 0ZM6 4L4 6ZM-1 1L1 -1Z\" stroke-opacity=\"0.5\" stroke=\"#888\" stroke-width=\"1\"></path>\r\n                </svg></pattern>\r\n        </defs>\r\n        <g pointer-events=\"none\">\r\n            <!---->\r\n            <g pointer-events=\"none\">\r\n                <g pointer-events=\"none\">\r\n                    <path fill=\"none\" stroke=\"black\" stroke-linecap=\"square\" stroke-linejoin=\"miter\"\r\n                        stroke-miterlimit=\"10\" stroke-opacity=\"1\" stroke-width=\"3\" shape-rendering=\"optimizeSpeed\"\r\n                        pointer-events=\"none\" d=\"M 312.5 242.5 L 408.5 242.5 408.5 271.5 312.5 271.5 Z\"></path>\r\n                </g>\r\n                <!---->\r\n                <g pointer-events=\"none\">\r\n                    <path fill=\"url(#inner-glow)\" stroke-linecap=\"square\" stroke-linejoin=\"miter\" stroke-miterlimit=\"10\"\r\n                        stroke-opacity=\"1\" stroke-width=\"1\" shape-rendering=\"optimizeSpeed\" stroke=\"#1d9ef9\" d=\"M 312.5 242.5\r\n                L 408.5 242.5 408.5 271.5 312.5 271.5 Z\"></path>\r\n                </g>\r\n                <g pointer-events=\"none\">\r\n                    <path data-direction=\"e\" data-role=\"resize-handler\" stroke-linecap=\"square\" stroke-linejoin=\"miter\"\r\n                        stroke-miterlimit=\"10\" stroke-opacity=\"1\" stroke-width=\"1\" shape-rendering=\"optimizeSpeed\"\r\n                        pointer-events=\"visiblePainted\" d=\"M 405.5 254 L 411.5 254 411.5 260 405.5 260 Z\"\r\n                        class=\"resize-handler handler-mr\"></path>\r\n                    <path data-direction=\"se\" data-role=\"resize-handler\" stroke-linecap=\"square\" stroke-linejoin=\"miter\"\r\n                        stroke-miterlimit=\"10\" stroke-opacity=\"1\" stroke-width=\"1\" shape-rendering=\"optimizeSpeed\"\r\n                        pointer-events=\"visiblePainted\" d=\"\" class=\"resize-handler handler-br\"></path>\r\n                    <path data-direction=\"s\" data-role=\"resize-handler\" stroke-linecap=\"square\" stroke-linejoin=\"miter\"\r\n                        stroke-miterlimit=\"10\" stroke-opacity=\"1\" stroke-width=\"1\" shape-rendering=\"optimizeSpeed\"\r\n                        pointer-events=\"visiblePainted\" d=\"\" class=\"resize-handler handler-bm\"></path>\r\n                </g>\r\n            </g>\r\n            <g pointer-events=\"none\">\r\n                <!---->\r\n                <!---->\r\n                <!---->\r\n            </g>\r\n            <!---->\r\n            <g>\r\n                <line pointer-events=\"none\" data-role=\"ruler-guide\" data-uuid=\"---internal-ruler-guide-init-0\"\r\n                    shape-rendering=\"optimizeSpeed\" x1=\"0\" x2=\"100%\" y1=\"132.5\" y2=\"132.5\" class=\"ruler-guideline\">\r\n                </line>\r\n                <line pointer-events=\"none\" data-role=\"ruler-guide\" data-uuid=\"---internal-ruler-guide-init-1\"\r\n                    shape-rendering=\"optimizeSpeed\" x1=\"0\" x2=\"100%\" y1=\"268.5\" y2=\"268.5\" class=\"ruler-guideline\">\r\n                </line>\r\n                <line pointer-events=\"none\" data-role=\"ruler-guide\" data-uuid=\"---internal-ruler-guide-init-2\"\r\n                    shape-rendering=\"optimizeSpeed\" x1=\"0\" x2=\"100%\" y1=\"349.5\" y2=\"349.5\" class=\"ruler-guideline\">\r\n                </line>\r\n                <line pointer-events=\"none\" data-role=\"ruler-guide\" data-uuid=\"---internal-ruler-guide-init-3\"\r\n                    shape-rendering=\"optimizeSpeed\" x1=\"0\" x2=\"100%\" y1=\"410.5\" y2=\"410.5\" class=\"ruler-guideline\">\r\n                </line>\r\n                <!---->\r\n            </g>\r\n            <!---->\r\n            <!---->\r\n            <!---->\r\n            <!---->\r\n            <!---->\r\n            <!---->\r\n            <!---->\r\n        </g>\r\n    </svg>\r\n    <!---->\r\n    <!---->\r\n</body>\r\n\r\n</html>"
  },
  {
    "path": "assets/TEST/window.history.demo.html",
    "content": "<!DOCTYPE html>\n<html lang=\"ko\">\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  <meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">\n  <title>Document</title>\n</head>\n<body>\n  <div id='app'/>\n</body>\n<script>\n\nwindow.onpopstate = function(event) {\n  console.log(\"location: \" + document.location + \", state: \" + JSON.stringify(event.state));\n\n  \n  const divElement = document.getElementById('app')\n\n  // Remove all child Element\n  // more faster than innerHTML = '';\n  while (divElement.firstChild) {\n    divElement.removeChild(divElement.firstChild);\n  }\n\n  const curState = event.state\n  if(curState.length === 0) return\n\n  const todoList = curState.todoList\n  \n  for (let index = 0; index < todoList.length; index++) {\n    const element = todoList[index];\n    divElement.insertAdjacentHTML('beforeend', `<div id=\"two\">${element}</div>`); \n  }\n};\n\nconst history = window.history\nconst page1State = {\n  todoList : ['aaa', 'aaa', 'aaa', 'aaa'],\n};\nconst page2State = {\n  todoList : ['bbb', 'bbb', 'bbb', 'bbb'],\n};\n\nhistory.pushState(page1State, \"page1\", \"page1.html\");\nhistory.pushState(page2State, \"page2\", \"page2.html\");\n</script>\n</html>"
  }
]