<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: drevispas</title>
    <description>The latest articles on DEV Community by drevispas (@drevispas).</description>
    <link>https://dev.to/drevispas</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F308249%2Fe0b4e8de-5d72-4e96-aefb-1595b13fc31c.jpg</url>
      <title>DEV Community: drevispas</title>
      <link>https://dev.to/drevispas</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/drevispas"/>
    <language>en</language>
    <item>
      <title>Quarkus, Just for fun</title>
      <dc:creator>drevispas</dc:creator>
      <pubDate>Thu, 26 Jun 2025 10:40:15 +0000</pubDate>
      <link>https://dev.to/drevispas/quarkus-just-for-fun-f8b</link>
      <guid>https://dev.to/drevispas/quarkus-just-for-fun-f8b</guid>
      <description>&lt;p&gt;미립자의 &lt;code&gt;quark&lt;/code&gt;와 우리의 &lt;code&gt;us&lt;/code&gt;가 합쳐진 Quarkus. 간단한 프로젝트를 레퍼런스를 따라서 타이핑해보고 있다. 아직은 획기적인지 체감이 잘 안 되고 있다.&lt;br&gt;
Dev mode로 시작시키 놓으면 코드 변경을 저장하는 순간 매우 빠르게 리로드된다. 그리고 추가한 extension(외부 의존성)이 oidc라면 Keycloack docker 인스턴스가 자동으로 설정되어 시작된다.&lt;br&gt;
좀 더 타이핑해봐야겠다.&lt;/p&gt;

</description>
      <category>quarkus</category>
      <category>docker</category>
      <category>extensions</category>
      <category>devdiscuss</category>
    </item>
    <item>
      <title>Add Jira ID and branch name in commit message</title>
      <dc:creator>drevispas</dc:creator>
      <pubDate>Fri, 16 Jun 2023 04:20:15 +0000</pubDate>
      <link>https://dev.to/drevispas/add-jira-id-and-branch-name-in-commit-message-di0</link>
      <guid>https://dev.to/drevispas/add-jira-id-and-branch-name-in-commit-message-di0</guid>
      <description>&lt;p&gt;Create a file name &lt;code&gt;.git/hook/prepare-commit-msg&lt;/code&gt; with following content.&lt;br&gt;
.git/hook/prepare-commit-msg:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;

&lt;span class="c"&gt;# Not used for now&lt;/span&gt;
&lt;span class="nv"&gt;COMMIT_MSG_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;
&lt;span class="nv"&gt;COMMIT_SOURCE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;
&lt;span class="nv"&gt;SHA1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$3&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$EXCLUDED_BRANCHES&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
  &lt;span class="c"&gt;# 이 템플릿을 사용하지 않을 브랜치 설정&lt;/span&gt;
  &lt;span class="nv"&gt;EXCLUDED_BRANCHES&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;main release master develop&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nv"&gt;BRANCH_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;git symbolic-ref &lt;span class="nt"&gt;--short&lt;/span&gt; HEAD&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# 브랜치 이름을 분해한다.&lt;/span&gt;
&lt;span class="nv"&gt;BRANCH_PATTERN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"(.*)/([A-Z0-9]{2,5}-[0-9]{1,4}){0,1}[-_/]*(.*)"&lt;/span&gt;
&lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nv"&gt;$BRANCH_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;~ &lt;span class="nv"&gt;$BRANCH_PATTERN&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;
&lt;span class="nv"&gt;BRANCH_TYPE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BASH_REMATCH&lt;/span&gt;&lt;span class="p"&gt;[1]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;span class="nv"&gt;JIRA_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BASH_REMATCH&lt;/span&gt;&lt;span class="p"&gt;[2]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;span class="nv"&gt;BRANCH_DESC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BASH_REMATCH&lt;/span&gt;&lt;span class="p"&gt;[3]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; | &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="s1"&gt;'-'&lt;/span&gt; &lt;span class="s1"&gt;' '&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;

&lt;span class="c"&gt;# 템플릿 미사용 조건들&lt;/span&gt;
&lt;span class="nv"&gt;IS_EXCLUDED_BRANCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s2"&gt;"%s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;EXCLUDED_BRANCHES&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"^&lt;/span&gt;&lt;span class="nv"&gt;$BRANCH_NAME&lt;/span&gt;&lt;span class="s2"&gt;$"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;BRANCH_OCCURRENCES_IN_COMMIT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\[&lt;/span&gt;&lt;span class="nv"&gt;$BRANCH_NAME&lt;/span&gt;&lt;span class="se"&gt;\]&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$BRANCH_NAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nv"&gt;$IS_EXCLUDED_BRANCH&lt;/span&gt; &lt;span class="nt"&gt;-eq&lt;/span&gt; 1 &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nv"&gt;$BRANCH_OCCURRENCES_IN_COMMIT&lt;/span&gt; &lt;span class="nt"&gt;-ge&lt;/span&gt; 1 &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt;.bak &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"1s|^|[&lt;/span&gt;&lt;span class="nv"&gt;$JIRA_ID&lt;/span&gt;&lt;span class="s2"&gt;] &lt;/span&gt;&lt;span class="nv"&gt;$BRANCH_TYPE&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="nv"&gt;$BRANCH_DESC&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;Solves [&lt;/span&gt;&lt;span class="nv"&gt;$JIRA_ID&lt;/span&gt;&lt;span class="s2"&gt;] &lt;/span&gt;&lt;span class="nv"&gt;$BRANCH_TYPE&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="nv"&gt;$BRANCH_DESC&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;|"&lt;/span&gt; &lt;span class="nv"&gt;$1&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you commit, the hook add two lines automatically.&lt;br&gt;
Ex) A branch&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;feature/JIRA-123_this-is-a-description
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;makes a commit message&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[JIRA-123] feature: this is a description
Solves [JIRA-123] feature: this is a description
{commit message}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>git</category>
      <category>jira</category>
    </item>
    <item>
      <title>Mermaid snippet</title>
      <dc:creator>drevispas</dc:creator>
      <pubDate>Tue, 31 May 2022 03:30:29 +0000</pubDate>
      <link>https://dev.to/drevispas/mermaid-snippet-6e4</link>
      <guid>https://dev.to/drevispas/mermaid-snippet-6e4</guid>
      <description>&lt;p&gt;Mermaid is a diagram creation tool built in the Github. You can create a diagram by typing '''mermaid''' on a markdown file (You have to replace quotes with back quotes actually).&lt;br&gt;
Here a sequence diagram snippet being referred as a sample.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;'''mermaid
sequenceDiagram
    %% Participants
    participant A as Alice
    participant B as Bob
    link A: Go to Wiki @ https://en.wikipedia.org/wiki/Alice

    %% Main loop
    autonumber %% Turn on sequence numbers on arrows
    loop Every minute
        opt A is ready
            A-&amp;gt;&amp;gt;+B: OK?
        end
        note left of A: Note for Alice
        note right of B: Note for Bob
        alt B is ready
            B--&amp;gt;&amp;gt;A: Yes
        else B is not ready
            B--&amp;gt;&amp;gt;-A: No
        end
        note over A,B: Note for both
    end
'''
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To render the sequence diagram you wrote at Intellij, enable "mermaid" markdown extension:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oxDo8peN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yq4sryxf8hmd4vc7dqt9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oxDo8peN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yq4sryxf8hmd4vc7dqt9.png" alt="Image description" width="832" height="172"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>diagrams</category>
      <category>markdown</category>
    </item>
    <item>
      <title>Elementary Lambda Calculus (in Korean)</title>
      <dc:creator>drevispas</dc:creator>
      <pubDate>Sun, 12 Sep 2021 05:11:36 +0000</pubDate>
      <link>https://dev.to/drevispas/elementary-lambda-calculus-in-korean-4bie</link>
      <guid>https://dev.to/drevispas/elementary-lambda-calculus-in-korean-4bie</guid>
      <description>&lt;h1&gt;
  
  
  열기
&lt;/h1&gt;

&lt;p&gt;여러 프로그래밍 언어에서 함수형 프로그래밍을 지원한다. 이러한 방식은 람다 대수가 이론적 근간이 된다고 하는데, 어떤 내용인지 궁금하므로 매우 짧게 이런 식이구나 까지만 알아보도록 한다.&lt;/p&gt;

&lt;h1&gt;
  
  
  정의
&lt;/h1&gt;

&lt;p&gt;튜링 머신과 같이 어떤 계산가능한 함수도 표현할 수 있지만, 하드웨어보다는 소프트웨어적인 접근을 취하고 있다.&lt;br&gt;
기본 용어는 name, expression이다. Name은 흔히 말하는 variable이라고 생각하면 되고 알파벳 문자로 표현된다. Expression은 아래와 같이 재귀적으로 표현된다.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--afaVD29l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dtfmrr6ofeorg28n7e0h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--afaVD29l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dtfmrr6ofeorg28n7e0h.png" alt="alt text"&gt;&lt;/a&gt;&lt;br&gt;
따라서 표현식(expression)은 변수(name)이거나 함수(function)이거나 적용(application)이다. 함수(function)는 λ 키워드로 함수임을 알리고 인자(argument)로 변수와 본문(body)로 표현식을 써서 정의한다. 적용(application)은 표현식 하나를 다른 표현식에 적용시킨다는 의미로 이 자체가 표현식이다. 키워드는 점(.)과 람다기호(λ) 2가지 밖에 없다. 가독성을 위해 괄호를 사용할 수 있다.&lt;br&gt;
간단한 함수(function)의 예로 항등 함수(identity function)가 있다.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gEmplRlh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/306xm3pggnkgjygz5h38.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gEmplRlh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/306xm3pggnkgjygz5h38.png" alt="alt text"&gt;&lt;/a&gt;&lt;br&gt;
바(|) 왼쪽은 람다 표현, 오른쪽은 이해를 돕기 위한 코틀린 코드에서의 표현이다(이제 코틀린 기초 문법 보는 중이라 틀렸을 수도 있음). 첫번째 x는 이 함수의 인자(argument)를 나타내고, 두번째 x는 함수의 본문(body)를 나타낸다. 즉 자기자신을 반환하는 함수이다. 일단 여기에서 람다 함수에는 sin(), sum()과 같은 이름이 없다는 것을 알 수 있다.&lt;br&gt;
함수를 표현식에 “적용”할 수 있다. 실제로 표현식을 함수에 대입하지만 반대방향으로 표현한다.&lt;br&gt;
가장 간단한 “적용”은,&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SMTmlJmR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vt64abbbwhnhosdz0kte.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SMTmlJmR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vt64abbbwhnhosdz0kte.png" alt="alt text"&gt;&lt;/a&gt;&lt;br&gt;
이 경우 표현식 x가 함수라고 가정한 경우이다.&lt;br&gt;
항등 함수로 적용의 예를 들면,&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--o_CEcPf0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hx07nk1wdochhqcbriqs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--o_CEcPf0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hx07nk1wdochhqcbriqs.png" alt="alt text"&gt;&lt;/a&gt;&lt;br&gt;
위 적용(λ(x.x))은 인자 x를 변수값 y로 대체하고 본체를 반환하기 때문에 결과는 y이다.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3Z5z6CJk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7xftn7mgpvmg579il5yj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3Z5z6CJk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7xftn7mgpvmg579il5yj.png" alt="alt text"&gt;&lt;/a&gt;&lt;br&gt;
변수는 단지 값을 담는 place holder 역할이므로 x, y, z 등 어떤 이름으로 지어도 상관없다. 즉,&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SR_jLlRC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/36nx25lly4494a1yyl4b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SR_jLlRC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/36nx25lly4494a1yyl4b.png" alt="alt text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  자유 변수(free variable), 종속 변수(bound variable)
&lt;/h1&gt;

&lt;p&gt;위키백과 설명을 보자 (왠지 이해하기 더 어려워졌다):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;논리학과 컴퓨터 과학에서, 자유 변수(自由變數, 영어: free variable)는 수식 속의 변수 가운데 상숫값으로 치환할 수 있는 것이다. 반대로 종속 변수(從屬變數, 영어: bound variable)는 상숫값으로 치환하였을 때 수식이 본래의 의미를 잃게 되는 변수이다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;람다 함수의 예를 보자.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--z6mqARiK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2bhfecstm0yaxojjb0ck.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--z6mqARiK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2bhfecstm0yaxojjb0ck.png" alt="alt text"&gt;&lt;/a&gt;&lt;br&gt;
함수 본문에 있는 변수가 인자에도 있으면 종속되었다고 하고, 그렇지 않으면 자유라고 한다. 따라서 x는 종속 변수이고, y는 자유 변수이다. 주의할 점은 변수 이름은 scope이 함수 하나에 한정된다는 것이다. 이름이 같더라도 옆 함수에서는 사실 다른 변수이다.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--w_4FfmSX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/len31fgbf0lkn9ih6cfz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--w_4FfmSX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/len31fgbf0lkn9ih6cfz.png" alt="alt text"&gt;&lt;/a&gt;&lt;br&gt;
첫번째 표현식 (λx.x)에서 x는 종속 변수이고, 두번째 표현식 (λy.xy)에서 x는 자유 변수이며, 각 표현식의 x는 전혀 다른 변수이다.&lt;/p&gt;

&lt;h1&gt;
  
  
  치환
&lt;/h1&gt;

&lt;p&gt;항등 함수에 항등 함수를 “적용”시킨다면 치환을 이용하여 그 결과를 추론할 수 있다. 위에서 설명했듯이 변수 이름은 함수들을 걸쳐서는 의미가 없으므로 치환하면,&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bKiJUcZQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/352wfrisxdlmznbwpnvh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bKiJUcZQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/352wfrisxdlmznbwpnvh.png" alt="alt text"&gt;&lt;/a&gt; &lt;br&gt;
앞 람다 함수 인자에 뒤의 표현식을 대입하면,&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5s4-03Ox--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g641nqz8ay9fo29p0w4n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5s4-03Ox--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g641nqz8ay9fo29p0w4n.png" alt="alt text"&gt;&lt;/a&gt; &lt;br&gt;
위 함수는 인자와 같은 것을 반환한다는 정의이므로 결과는,&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NN96dDcC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rdvsvu0yx76tmfzxeuan.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NN96dDcC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rdvsvu0yx76tmfzxeuan.png" alt="alt text"&gt;&lt;/a&gt; &lt;br&gt;
즉 다시 항등 함수가 된다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;연습 문제1:&lt;/strong&gt; (λx.(λy.xy))y를 치환하면?&lt;br&gt;
&lt;strong&gt;풀이1:&lt;/strong&gt; scope은 다른데 이름이 같은 변수들이 헷갈리므로 먼저 치환해서 모호함을 없앤다.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZzdA-gO5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gs7k98vak0yyrb4fj90a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZzdA-gO5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gs7k98vak0yyrb4fj90a.png" alt="alt text"&gt;&lt;/a&gt; &lt;br&gt;
맨 오른쪽 y 변수를 인자 x로 치환해서 본체를 반환한다.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--B5rvmtlC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zeiangyj0ej9ttvpar75.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--B5rvmtlC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zeiangyj0ej9ttvpar75.png" alt="alt text"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;연습 문제2:&lt;/strong&gt; (λx.(λy.(x(λx.xy)))y를 치환하면?&lt;br&gt;
&lt;strong&gt;풀이2:&lt;/strong&gt; 대입할 맨 오른쪽 y와 람다 함수 본문의 y는 서로 다른 변수이므로 본문 쪽을 치환&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--o0UvO-c4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s6vi9cjib9etp0zuhho2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--o0UvO-c4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s6vi9cjib9etp0zuhho2.png" alt="alt text"&gt;&lt;/a&gt; &lt;br&gt;
변수 y를 왼쪽 람다 인자로 치환해서 본문을 반환하면,&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--O28B4vAE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1hwk1e8qveq3bbezo7sf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--O28B4vAE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1hwk1e8qveq3bbezo7sf.png" alt="alt text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  산술 연산
&lt;/h1&gt;

&lt;p&gt;람다 대수에서는 모든 것이 함수라 숫자를 표현할 방법이 필요했다. 음이 아닌 정수 체계를 표현하고자 한다면, (1) 시작값(0)과 (2) 다음 값을 구하는 함수(successor), 두 가지만 있으면 구축할 수 있다. 시작값인 zero를 아래와 같이 정의했다(이게 도대체 왜 0이냐는 의문이 생기지만).&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Cd6Ya4j3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ct1o8bq7z0fl7fo28nh6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Cd6Ya4j3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ct1o8bq7z0fl7fo28nh6.png" alt="alt text"&gt;&lt;/a&gt; &lt;br&gt;
Zero는 함수 f(successor)와 변수 z(양의 정수)를 입력으로 받아 다시 변수 z를 반환하는 함수로 정의했다.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rQkCE1wl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/649ku1p6kb09hsvwvofr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rQkCE1wl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/649ku1p6kb09hsvwvofr.png" alt="alt text"&gt;&lt;/a&gt; &lt;br&gt;
2, 3, … 모두 기본값에 successor 함수를 몇 번 적용했는지로 정의된다.&lt;br&gt;
덧셈의 경우에도 함수로 정의되는데, 인자 (a, b)를 받아서 zero에 successor를 a번 적용하고, 그 결과에 다시 successor를 b번 적용한다.&lt;/p&gt;

&lt;h1&gt;
  
  
  마무리
&lt;/h1&gt;

&lt;p&gt;여기까지가 보통 람다 대수 책의 앞 부분이다. 우리의 목적은 대수 이론을 체계적으로 배우기 보다는 함수형 프로그래밍에 근간이 되는 람다 대수가 어떤 느낌인지 확인하는 정도이기 때문에 여기에서 마무리해도 충분해 보인다.&lt;/p&gt;

</description>
      <category>lambda</category>
      <category>calculus</category>
      <category>kotlin</category>
    </item>
    <item>
      <title>Setup Laravel in Local Host</title>
      <dc:creator>drevispas</dc:creator>
      <pubDate>Tue, 29 Jun 2021 13:59:46 +0000</pubDate>
      <link>https://dev.to/drevispas/setup-laravel-in-local-host-3586</link>
      <guid>https://dev.to/drevispas/setup-laravel-in-local-host-3586</guid>
      <description>&lt;p&gt;This guide assume you are installing on a Mac OS.&lt;br&gt;
Install &lt;code&gt;composer&lt;/code&gt; which is a package manager for Laravel.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s2"&gt;"copy('https://getcomposer.org/installer', 'composer-setup.php');"&lt;/span&gt;
php &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s2"&gt;"if (hash_file('sha384', 'composer-setup.php') === '756890a4488ce9024fc62c56153228907f1545c228516cbf63f885e036d37e9a59d27d63f46af1d4d07ee0f76181c7d3') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"&lt;/span&gt;
php composer-setup.php
php &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s2"&gt;"unlink('composer-setup.php');"&lt;/span&gt;
&lt;span class="nb"&gt;sudo mv &lt;/span&gt;composer.phar /usr/local/bin/composer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install &lt;code&gt;laravel&lt;/code&gt; installer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer global require &lt;span class="s2"&gt;"laravel/installer"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;~/.composer/vendor/bin:&lt;span class="nv"&gt;$PATH&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can create a new Laravel project on the working directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;laravel new &lt;span class="o"&gt;{&lt;/span&gt;project&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;project&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the new project with &lt;code&gt;sail&lt;/code&gt; tool.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require laravel/sail &lt;span class="nt"&gt;--dev&lt;/span&gt;
php artisan sail:install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that &lt;code&gt;docer-compser.yml&lt;/code&gt; and &lt;code&gt;Dockerfile&lt;/code&gt; are created. For now &lt;code&gt;mysql 8.0.25&lt;/code&gt; and &lt;code&gt;php8.0&lt;/code&gt; were installed. It builds docker images and prints container logs like &lt;code&gt;tail -f&lt;/code&gt;. You could use &lt;code&gt;sail up -d&lt;/code&gt; to run containers in background.&lt;br&gt;
Save the current code on github for backup.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git init
git add &lt;span class="nb"&gt;.&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"first commit"&lt;/span&gt;
git branch &lt;span class="nt"&gt;-M&lt;/span&gt; main
git remote add origin git@github.com:&lt;span class="o"&gt;{&lt;/span&gt;username&lt;span class="o"&gt;}&lt;/span&gt;/laravel-example.git
git push &lt;span class="nt"&gt;-u&lt;/span&gt; origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's see what containers are running. &lt;code&gt;sail&lt;/code&gt; command is similar to &lt;code&gt;docker-compose&lt;/code&gt; command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# list containers&lt;/span&gt;
sail ps
&lt;span class="c"&gt;# list databases&lt;/span&gt;
sail &lt;span class="nb"&gt;exec &lt;/span&gt;mysql mysql &lt;span class="nt"&gt;-usail&lt;/span&gt; &lt;span class="nt"&gt;-ppassword&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt;&lt;span class="s2"&gt;"show databases"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open a browser and go to &lt;code&gt;http://localhost&lt;/code&gt; to see Laravel.&lt;/p&gt;

&lt;p&gt;To stop containers, open a new terminal and go to {project} directory and run down command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sail down
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lastly install a debugger for php.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# on MacOS&lt;/span&gt;
pecl &lt;span class="nb"&gt;install &lt;/span&gt;xdebug
&lt;span class="c"&gt;# on Ubuntu&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;php-xdebug
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>php</category>
      <category>laravel</category>
    </item>
    <item>
      <title>Spark Introduction</title>
      <dc:creator>drevispas</dc:creator>
      <pubDate>Thu, 17 Dec 2020 09:33:43 +0000</pubDate>
      <link>https://dev.to/drevispas/spark-introduction-45hm</link>
      <guid>https://dev.to/drevispas/spark-introduction-45hm</guid>
      <description>&lt;h1&gt;&lt;strong&gt;Quick View&lt;/strong&gt;&lt;/h1&gt;

&lt;p&gt;Spark의 기본에 대해서 정리해 보자.&lt;/p&gt;

&lt;h2&gt;RDD&lt;/h2&gt;

&lt;ul&gt;
    &lt;li&gt;RDD는 분산 자료구조이다 ≈ 일단 DB 테이블로 생각하자&lt;/li&gt;
    &lt;li&gt;Mutable 특성 ≈ 테이블인데 append만 되는 read-only table이라고 생각하자&lt;/li&gt;
    &lt;li&gt;Lazy execution 특성
&lt;ul&gt;
    &lt;li&gt;RDD "Actions"은 operator이며 결과로 새로운 RDD들을 만들어 낸다.&lt;/li&gt;
    &lt;li&gt;RDD actions 체인을 거쳐서 최종 RDD를 설계한 다음,&lt;/li&gt;
    &lt;li&gt;"Transformations"이 실제로 RDD의 actions들을 실행시킨다.&lt;/li&gt;
&lt;/ul&gt;




&lt;/li&gt;

    &lt;li&gt;DAG (Directed Acyclic Graph)

&lt;ul&gt;
    &lt;li&gt;RDD의 actions / transformation은 결국 DAG를 설계하는 것이다.&lt;/li&gt;
&lt;/ul&gt;




&lt;/li&gt;

    &lt;li&gt;작업 단위

&lt;ul&gt;
    &lt;li&gt;크기 순: Job  &amp;gt; Stage &amp;gt; Task&lt;/li&gt;
    &lt;li&gt;Stage: shuffle이 발생하기 전까지 하나의 executor에 의해서 실행되는 구간&lt;/li&gt;
    &lt;li&gt;Task: map(), filter()와 같은 단위 연산&lt;/li&gt;
&lt;/ul&gt;




&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;SparkSQL&lt;/h2&gt;

&lt;ul&gt;
    &lt;li&gt;RDD에 DB table처럼 schema를 부여하여 SQL 질의를 가능하게 할 수 있다. 이러한 RDD를 "DataFrames"라고 부른다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Spark Streaming&lt;/h2&gt;

&lt;ul&gt;
    &lt;li&gt;Data Source (Kafka/S3/Kinesis/…) → Spark Streaming → Data Destination (Cassandra/HDFS/…)&lt;/li&gt;
    &lt;li&gt;DStream (Discretized Stream)
&lt;ul&gt;
    &lt;li&gt;Stream block을 5초 동안 모아서 하나의 RDD로 만들어 낸 것이다. 결국 Spark Stream도 RDD 단위로 처리하는 셈&lt;/li&gt;
&lt;/ul&gt;




&lt;/li&gt;

&lt;/ul&gt;

&lt;h1&gt;&lt;strong&gt;Spark Installation&lt;/strong&gt;&lt;/h1&gt;

&lt;h2&gt;Installing PySpark on Windows&lt;/h2&gt;

&lt;p&gt;설치 가이드를 따라 진행하다가 막히는 부분들을 여기저기 찾으며 정리한 것이다. Anaconda는 미리 설치되어 있다고 가정한다. Spark는 HDFS 파일시스템 위에서 동작하기 때문에 windows Hadoop을 설치해야 한다. 아래 미리 Windows용으로 빌드된 Hadoop을 설치한다.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/karthikj1/Hadoop-2.7.1-Windows-64-binaries/releases/download/v2.7.1/hadoop-2.7.1.tar.gz"&gt;https://github.com/karthikj1/Hadoop-2.7.1-Windows-64-binaries/releases/download/v2.7.1/hadoop-2.7.1.tar.gz&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;예를 들어, 압축을 풀고 "C:\app\hadoop"으로 이동시킨 후 환경변수를 설정한다. 현재 자바 최신 버전인 JDK 11은 아직 지원되지 않고 문제가 발생하므로 JDK 8 최신 버전을 설정한다.&lt;br&gt;&lt;/p&gt;

&lt;pre class="wp-block-preformatted"&gt;JAVA_HOME=C:\app\Java\8\jdk&lt;br&gt;HADOOP_HOME=C:\app\hadoop&lt;br&gt;ANACONDA_HOME=C:\app\anaconda &lt;br&gt;PYTHONPATH=%ANACONDA_HOME%&lt;br&gt;PYSPARK_PYTHON=%PYTHONPATH%\python.exe&lt;br&gt;PYTHONIOENCODING=UTF-8&lt;br&gt;PATH=%PATH%;%ANACONDA_HOME%;%ANACONDA_HOME%\Library\bin; &lt;br&gt;%HADOOP_HOME%\bin;&lt;/pre&gt;

&lt;p&gt;Anaconda prompt를 열고 환경변수가 잘 설정되었는지 확인하고 pyspark를 설치한다. 현재 최신 PySpark 버전이 2.4.0이지만 dataframe 생성시 exception이 발생하여 2.3.2로 설치한다.&lt;br&gt;&lt;/p&gt;

&lt;pre class="wp-block-preformatted"&gt;echo %JAVA_HOME%&lt;br&gt;echo %HADOOP_HOME%&lt;br&gt;...&lt;br&gt;conda install pyspark=2.3.2&lt;/pre&gt;

&lt;h2&gt;IDE&lt;/h2&gt;

&lt;h3&gt;Jupyter Notebook&lt;/h3&gt;

&lt;p&gt;Anaconda prompt에서 아래 명령어를 실행시키면 데몬이 시작되면서 기본 browser가 자동으로 열린다.&lt;br&gt;&lt;/p&gt;

&lt;pre class="wp-block-syntaxhighlighter-code brush: bash; notranslate"&gt;(base) C:\Users\brad&amp;gt;jupyter notebook
[I 22:47:18.529 NotebookApp] JupyterLab extension loaded from C:\app\anaconda\lib\site-packages\jupyterlab
[I 22:47:18.530 NotebookApp] JupyterLab application directory is C:\app\anaconda\share\jupyter\lab
[I 22:47:18.532 NotebookApp] Serving notebooks from local directory: C:\Users\brad
[I 22:47:18.532 NotebookApp] The Jupyter Notebook is running at:
[I 22:47:18.532 NotebookApp] http://localhost:8888/?token=6d3d60c01b9715eb8d3a94fd862f22eefab07192fe7aa1a0&lt;/pre&gt;

&lt;p&gt;New &amp;gt; Python 3로 새로운 edit 탭을 시작한다.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZJ07r15_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://classx365.files.wordpress.com/2018/12/image.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZJ07r15_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://classx365.files.wordpress.com/2018/12/image.png" alt="" class="wp-image-32"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Syntax highlight와 괄호 닫기 자동 입력을 지원해준다. Shift+Enter로 작성한 상자 안에 코드를 수행해볼 수 있다. 작성 중간 중간에 File &amp;gt; Save를 해준다. 현재 directory 안에 .ipynb 화일로 저장된다.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Mg_JuHuO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://classx365.files.wordpress.com/2018/12/image-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Mg_JuHuO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://classx365.files.wordpress.com/2018/12/image-1.png" alt="" class="wp-image-33"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;PyCharm&lt;/h3&gt;

&lt;p&gt;편리한 편집 기능을 제공하는 PyCharm이다. 단축키와 스타일이 IntelliJ와 유사하다.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--On25Mlm8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://classx365.files.wordpress.com/2018/12/image-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--On25Mlm8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://classx365.files.wordpress.com/2018/12/image-2.png" alt="" class="wp-image-35"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;Troubleshooting&lt;/h4&gt;

&lt;p&gt;Numpy update 후에 PyCharm에서 다음과 같은 오류가 발생한다&lt;/p&gt;

&lt;pre class="wp-block-preformatted"&gt;"DLL Load Failed: The specified procedure could not be found."&lt;/pre&gt;

&lt;p&gt;Windows 환경 변수 PATH에 다음을 추가하고 PyCharm을 restart해보자.&lt;/p&gt;

&lt;pre class="wp-block-preformatted"&gt;%ANACONDA_HOME%\Library\bin &lt;/pre&gt;

&lt;h1&gt;&lt;strong&gt;Anaconda Installation&lt;/strong&gt;&lt;/h1&gt;

&lt;p&gt;Windows 10에 Anaconda를 설치하는 방법을 정리한다. 개인적으로 경로 상에 공백 문자가 없는 것을 선호하기 때문에 C:\app\anaconda 디렉토리 아래에 설치해 보도록 하겠다.&lt;/p&gt;

&lt;h2&gt;Downloading Anacond&lt;/h2&gt;

&lt;p&gt;아래 URL로 가서 최신 Anaconda 설치화일을 다운로드한다.&lt;/p&gt;

&lt;p&gt;https://www.anaconda.com/download/&lt;/p&gt;

&lt;p&gt;현재 최신 버전은, https://repo.continuum.io/archive/Anaconda3-2018.12-Windows-x86_64.exe 이다.&lt;/p&gt;

&lt;p&gt;설치 창에서 경로를 "C:\app\anaconda"로 수정하고 설치를 완료한다.&lt;/p&gt;

&lt;h2&gt;Setting Environment Variables&lt;/h2&gt;

&lt;p&gt;Windows 10의 시스템 환경변수에 다음과 같이 추가한다.&lt;/p&gt;

&lt;pre class="wp-block-preformatted"&gt;ANACONDA_HOME=C:\app\anaconda &lt;br&gt;PYTHONPATH=%ANACONDA_HOME%&lt;br&gt;PYTHONIOENCODING=UTF-8&lt;br&gt;PATH=%PATH%;%ANACONDA_HOME%;%ANACONDA_HOME%\Library\bin;&lt;/pre&gt;

&lt;h2&gt;Adding Mirror Site&lt;/h2&gt;

&lt;p&gt;Anaconda 설치 후 새로 생긴 Anaconda Prompt를 실행한다.&lt;/p&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QB0CF4B7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://classx365.files.wordpress.com/2018/12/image-3.png%3Fw%3D372" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QB0CF4B7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://classx365.files.wordpress.com/2018/12/image-3.png%3Fw%3D372" alt="" class="wp-image-52" width="239" height="210"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;기본적으로 Anaconda는 아래 채널을 갖고 있는데 속도가 느려서 중국의 미러 채널을 추가해 보도록하겠다.&lt;/p&gt;

&lt;pre class="wp-block-preformatted"&gt;default_channels:&lt;br&gt; https://repo.anaconda.com/pkgs/main&lt;br&gt; https://repo.anaconda.com/pkgs/free&lt;br&gt; https://repo.anaconda.com/pkgs/r&lt;br&gt; https://repo.anaconda.com/pkgs/pro&lt;br&gt; https://repo.anaconda.com/pkgs/msys2 &lt;/pre&gt;

&lt;p&gt;다음 URL을 참조하여 채널을 추가한다. &lt;/p&gt;

&lt;p&gt;https://mirrors.tuna.tsinghua.edu.cn/help/anaconda/&lt;/p&gt;

&lt;pre class="wp-block-code"&gt;&lt;code&gt;conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
conda config --set show_channel_urls yes
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/pytorch/&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;테스트 삼아 numpy를 설치해본다.&lt;/p&gt;

&lt;pre class="wp-block-code"&gt;&lt;code&gt;conda install numpy&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Updating Conda Package&lt;/h2&gt;

&lt;p&gt;설치되어 있는 Anaconda package들을 살펴보자.&lt;/p&gt;

&lt;pre class="wp-block-code"&gt;&lt;code&gt;conda list&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Package들을 update해본다.&lt;/p&gt;

&lt;pre class="wp-block-code"&gt;&lt;code&gt;conda update --all&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;캐쉬된 잔여물들을 삭제한다.&lt;/p&gt;

&lt;pre class="wp-block-code"&gt;&lt;code&gt;conda clean --all&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Troubleshooting&lt;/h2&gt;

&lt;h3&gt;Unknown Encoding&lt;/h3&gt;

&lt;p&gt;만일 conda update 중 아래와 같은 메시지를 만나게 된다면 Windows 10에서 기본 문자셋을 UTF-8로 설정했기 때문일 것이다. 환경변수 "PYTHONIOENCODING=UTF8"으로 설정했음에도 불구하고 6500이라는 숫자로 변경되었다.&lt;/p&gt;

&lt;pre class="wp-block-preformatted"&gt;Preparing transaction: done&lt;br&gt; Verifying transaction: done&lt;br&gt; Executing transaction: done&lt;br&gt; Fatal Python error: init_sys_streams: can't initialize sys standard streams&lt;br&gt; LookupError: unknown encoding: 6500&lt;/pre&gt;

&lt;p&gt;Anaconda Prompt를 닫고 "C:\app\anaconda\Scripts\activate.bat" 끝에 아래 라인을 강제로 추가한다.&lt;/p&gt;

&lt;pre class="wp-block-preformatted"&gt;set PYTHONIOENCODING=UTF-8&lt;/pre&gt;

&lt;p&gt;다시 Anaconda Prompt를 열고 encoding을 확인한다.&lt;/p&gt;

&lt;pre class="wp-block-code"&gt;&lt;code&gt;(base) C:\Users\brad&amp;gt;echo %PYTHONIOENCODING%
UTF-8

(base) C:\Users\brad&amp;gt;conda update conda
Solving environment: /&lt;/code&gt;&lt;/pre&gt;





&lt;h1&gt;&lt;strong&gt;Spark SQL&lt;/strong&gt;&lt;/h1&gt;

&lt;p&gt;긴 설명은 생략하고 직관적으로 이해할 수 있도록 Python 샘플 코드를 통해서 레퍼런스처럼 참조할 수 있도록 정리한다. Ctrl+F로 검색하기 쉽도록 외래어는 가능하면 알파벳으로 표시할 것이다.&lt;br&gt;&lt;/p&gt;

&lt;h2&gt;Spark SQL Session&lt;/h2&gt;

&lt;p&gt;Spark에서 DataFrame을 생성하고 SQL을 수행하기 위해서 &lt;br&gt;&lt;code&gt;pyspark.sql.SparkSession&lt;/code&gt; 인스턴스를 만든다.&lt;br&gt;&lt;/p&gt;

&lt;pre class="wp-block-syntaxhighlighter-code brush: python; notranslate"&gt;from pyspark.sql import SparkSession
spark = SparkSession.builder.master("local").appName("MyApp").getOrCreate()&lt;/pre&gt;

&lt;h2&gt;File I/O&lt;/h2&gt;

&lt;p&gt;대부분의 경우 대량의 입력 데이터를 수기로 입력할 수는 없고 다른 data source로부터 받아야 한다. 가장 기본이 되는 방식으로 하나의 File을 읽어서 DataFrame으로 변환해 보자.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;테스트를 위하여 다음 링크에서 붓꽃 데이터를 다운로해서 저장한다.&lt;br&gt;&lt;/p&gt;

&lt;p&gt; &lt;a href="https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data"&gt;https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data&lt;/a&gt;&lt;br&gt;&lt;/p&gt;

&lt;p&gt;아래 예제는 Pyspark v2.4.0 기준이고, 이하 모든 예제는 사용 버전에 따라 코드가 달라질 수 있다.&lt;br&gt;&lt;/p&gt;

&lt;pre class="wp-block-syntaxhighlighter-code brush: python; notranslate"&gt;# spark = SparkSession.builder.getOrCreate()
irisDf = spark.read.csv('data/iris.data', sep=",", header="false", inferSchema="true")&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;sep: 구분자. 기본은 콤마(,)&lt;/li&gt;
&lt;li&gt;header: csv에 헤더가 있는지 여부&lt;/li&gt;
&lt;li&gt;inferSchema: 컬럼 내용을 보고 data type을 유추해서 결정해 준다. Default인 "false"로 하면 string type으로 인식한다.
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;DataFrames&lt;/h2&gt;

&lt;p&gt;방금 CSV file을 읽어서 dataframe 한 개로 전환하였다. Dataframe의 정확한 정의는 따로 있겠지만 이해하기 쉽도록 schema를 가진 RDD라고 생각하자. DB table처럼 schema가 있기 때문에 SQL로 조작이 가능해진다. 이제 dataframe에 대한 기초 조작법을 정리해 보자. &lt;br&gt;&lt;/p&gt;

&lt;h4&gt;Schema&lt;/h4&gt;

&lt;pre class="wp-block-syntaxhighlighter-code brush: python; notranslate"&gt;&amp;gt;&amp;gt;&amp;gt; df.columns
['_c0', '_c1', '_c2', '_c3', '_c4']
&amp;gt;&amp;gt;&amp;gt; df.dtypes
[('_c0', 'double'), ('_c1', 'double'), ('_c2', 'double'), ('_c3', 'double'), ('_c4', 'string')]
&amp;gt;&amp;gt;&amp;gt; df.printSchema()
root
 |-- _c0: double (nullable = true)
 |-- _c1: double (nullable = true)
 |-- _c2: double (nullable = true)
 |-- _c3: double (nullable = true)
 |-- _c4: string (nullable = true)&lt;/pre&gt;

&lt;h2&gt;Print&lt;/h2&gt;

&lt;p&gt;DataFrame을 화면에 출력하는 기능이다.  앞에 chain이 얼마나 길든 상관없이 최종 결과 DataFrame을 화면에 출력한다.&lt;br&gt;&lt;/p&gt;

&lt;pre class="wp-block-syntaxhighlighter-code brush: python; notranslate"&gt;# Print a DataFrame in table format. All the belows print the same table.
irisDf.show(3)
irisDf.select('*').show(3)
irisDf.limit(3).show(3)
# Display
+---+---+---+---+-----------+
|_c0|_c1|_c2|_c3|        _c4|
+---+---+---+---+-----------+
|5.1|3.5|1.4|0.2|Iris-setosa|
|4.9|3.0|1.4|0.2|Iris-setosa|
|4.7|3.2|1.3|0.2|Iris-setosa|
+---+---+---+---+-----------+&lt;/pre&gt;

&lt;h2&gt;Query&lt;/h2&gt;

&lt;h3&gt;First N&lt;br&gt;
&lt;/h3&gt;

&lt;p&gt;전체 row 또는 앞 n 개 row를 질의할 수 있는 몇가지 방법들을 제공한다. 테스트 결과 아래 구문들은 모두 동일한 Row 객체 리스트를 반환한다.&lt;br&gt;&lt;/p&gt;

&lt;pre class="wp-block-syntaxhighlighter-code brush: python; notranslate"&gt;# Whatever methods below return the same list of Row object.
irisDf.head(3)
irisDf.take(3)
irisDf.collect()[:3]
irisDf.limit(3).collect()
irisDf.select('*').limit(3).collect()
# Result
[Row(_c0=5.1, _c1=3.5, _c2=1.4, _c3=0.2, _c4='Iris-setosa'), Row(_c0=4.9, _c1=3.0, _c2=1.4, _c3=0.2, _c4='Iris-setosa'), Row(_c0=4.7, _c1=3.2, _c2=1.3, _c3=0.2, _c4='Iris-setosa')]&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;take(n): 앞의 n개 row를 fetch
&lt;/li&gt;
&lt;li&gt;show(n): 앞의 n개 row를 print
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;API Queries&lt;br&gt;
&lt;/h3&gt;

&lt;p&gt;SQL과 유사한 API로 질의한다.&lt;br&gt;&lt;/p&gt;

&lt;pre class="wp-block-syntaxhighlighter-code brush: python; notranslate"&gt;&amp;gt;&amp;gt;&amp;gt; df.select('_c4').filter('_c0 &amp;gt; 5.0 and _c2 &amp;lt; 1.5').show(3)
+-----------+
|        _c4|
+-----------+
|Iris-setosa|
|Iris-setosa|
|Iris-setosa|
+-----------+
&amp;gt;&amp;gt;&amp;gt; df.groupby('_c4').agg({'_c1':'max', '_c2':'count'}).show()
+---------------+--------+----------+
|            _c4|max(_c1)|count(_c2)|
+---------------+--------+----------+
| Iris-virginica|     3.8|        50|
|    Iris-setosa|     4.4|        50|
|Iris-versicolor|     3.4|        50|
+---------------+--------+----------+&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;filter(): SQL의 WHERE에 해당한다.&lt;/li&gt;
&lt;li&gt;groupby(): SQL과 달리 SELECT가 없고 group by column을 명시하지 않는다.&lt;/li&gt;
&lt;li&gt;agg(): 'column명':'항수명' 형태로 aggregation columns를 표현한다.
&lt;/li&gt;
&lt;li&gt;show(): 앞의 fiter, groupby, agg 등은 transformations여서 실제 수행은 하지 않고 설계만 하는 것이고, action인 show()를 불러야 실제로 조회가 시작된다.
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Columns&lt;/h2&gt;

&lt;p&gt;
지금까지는 windows command 창에서 수행하였는데 코딩이 수월한 PyCharm으로 옮기겠다.

&lt;/p&gt;

&lt;h3&gt;Column Functions&lt;br&gt;
&lt;/h3&gt;

&lt;p&gt; Column를 전문적으로 다루는 module이 따로 있다. Alias, aggregation 등 편리한 기능들이 있다.&lt;br&gt;&lt;/p&gt;

&lt;pre class="wp-block-syntaxhighlighter-code brush: python; notranslate"&gt;from pyspark.sql import functions as F
df.groupby('_c4').agg(F.max('_c1').alias('_c1_max'), F.count('_c2').alias('_c2_count')).show()
+---------------+-------+---------+
|            _c4|_c1_max|_c2_count|
+---------------+-------+---------+
| Iris-virginica|    3.8|       50|
|    Iris-setosa|    4.4|       50|
|Iris-versicolor|    3.4|       50|
+---------------+-------+---------+&lt;/pre&gt;

&lt;h3&gt;Add Column&lt;br&gt;
&lt;/h3&gt;

&lt;pre class="wp-block-syntaxhighlighter-code brush: python; notranslate"&gt;df.withColumn('_c5', F.col('_c1')*2).show(3)
+---+---+---+---+-----------+---+
|_c0|_c1|_c2|_c3|        _c4|_c5|
+---+---+---+---+-----------+---+
|5.1|3.5|1.4|0.2|Iris-setosa|7.0|
|4.9|3.0|1.4|0.2|Iris-setosa|6.0|
|4.7|3.2|1.3|0.2|Iris-setosa|6.4|
+---+---+---+---+-----------+---+
df.show(3)
+---+---+---+---+-----------+
|_c0|_c1|_c2|_c3|        _c4|
+---+---+---+---+-----------+
|5.1|3.5|1.4|0.2|Iris-setosa|
|4.9|3.0|1.4|0.2|Iris-setosa|
|4.7|3.2|1.3|0.2|Iris-setosa|
+---+---+---+---+-----------+
df2 = df.withColumn('_c5', F.col('_c1')*2)
df2.show(3)
+---+---+---+---+-----------+---+
|_c0|_c1|_c2|_c3|        _c4|_c5|
+---+---+---+---+-----------+---+
|5.1|3.5|1.4|0.2|Iris-setosa|7.0|
|4.9|3.0|1.4|0.2|Iris-setosa|6.0|
|4.7|3.2|1.3|0.2|Iris-setosa|6.4|
+---+---+---+---+-----------+---+&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;withColumn(): 새로운 column을 마지막에 추가&lt;/li&gt;
&lt;li&gt;df.show(3): Spark RDD나 DataFrame은 mutable 자료구조라 in-place update가 안 된다. 다른 변수에 assign해서 변경을 유지해 나간다.
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Update Column&lt;/h3&gt;

&lt;pre class="wp-block-syntaxhighlighter-code brush: python; notranslate"&gt;df.withColumn('_c4', df['_c4'].substr(1,4)).show(3)
+---+---+---+---+----+
|_c0|_c1|_c2|_c3| _c4|
+---+---+---+---+----+
|5.1|3.5|1.4|0.2|Iris|
|4.9|3.0|1.4|0.2|Iris|
|4.7|3.2|1.3|0.2|Iris|
+---+---+---+---+----+&lt;/pre&gt;

&lt;h3&gt;Type Casting&lt;br&gt;
&lt;/h3&gt;

&lt;pre class="wp-block-syntaxhighlighter-code brush: python; notranslate"&gt;df.select(F.col('_c0').cast('integer')).show(3)
+---+
|_c0|
+---+
|  5|
|  4|
|  4|
+---+&lt;/pre&gt;

&lt;h2&gt;Join&lt;/h2&gt;

&lt;p&gt;DataFrame class의 member method인 join()은 INNER, LEFT OUTER, RIGHT OUTER, FULL OUTER, CROSS 등의 join 기능을 제공한다.&lt;br&gt;&lt;/p&gt;

&lt;pre class="wp-block-syntaxhighlighter-code brush: python; notranslate"&gt;# Create python lists.
dept = [(1,'hr'), (2,'dev'), (3,'special_force')]
emp = [(11, 'john', 1), (12, 'james', 2), (13, 'jennis', 1), (14, 'brad', 2), (15, 'doctor-x', 4)]
# Create RDDs.
deptRdd = sc.parallelize(dept)
empRdd = sc.parallelize(emp)
# Create DataFrames.
deptDf = spark.createDataFrame(dept, ['dept_id', 'dept_name'])
empDf = spark.createDataFrame(emp, ['emp_id', 'emp_name', 'dept_id'])
# Join two DataFrames.
joinDf = deptDf.join(empDf, on='dept_id')
joinDf.show()
+-------+---------+------+--------+
|dept_id|dept_name|emp_id|emp_name|
+-------+---------+------+--------+
|      1|       hr|    11|    john|
|      1|       hr|    13|  jennis|
|      2|      dev|    12|   james|
|      2|      dev|    14|    brad|
+-------+---------+------+--------+
deptDf.join(empDf, deptDf.dept_id == empDf.dept_id, 'left_outer').show()
+-------+-------------+------+--------+
|dept_id|    dept_name|emp_id|emp_name|
+-------+-------------+------+--------+
|      1|           hr|    11|    john|
|      1|           hr|    13|  jennis|
|      3|special_force|  null|    null|
|      2|          dev|    12|   james|
|      2|          dev|    14|    brad|
+-------+-------------+------+--------+
deptDf.join(empDf, deptDf['dept_id'] == empDf['dept_id'], 'full_outer').show()
+-------+-------------+------+--------+
|dept_id|    dept_name|emp_id|emp_name|
+-------+-------------+------+--------+
|      1|           hr|    11|    john|
|      1|           hr|    13|  jennis|
|      3|special_force|  null|    null|
|      2|          dev|    12|   james|
|      2|          dev|    14|    brad|
|      4|         null|    15|doctor-x|
+-------+-------------+------+--------+&lt;/pre&gt;

&lt;h1&gt;&lt;strong&gt;Spark RDD&lt;/strong&gt;&lt;/h1&gt;

&lt;p&gt;Python sample code를 예로 해서 RDD를 어떻게 다루는지 기본 조작 방법들을 정리해 보자.&lt;br&gt;&lt;/p&gt;

&lt;h2&gt;RDD&lt;/h2&gt;

&lt;p&gt;RDD는 &lt;em&gt;Resilient Distributed Dataset&lt;/em&gt;의 약자인데 이름에 유추할 수 있듯이 fault-tolerant하고 분산되어 병렬 처리되는 자료구조이다. 우리는 보통 S3, HDFS, DB에 있는 source data를 읽어서 RDD 형태로 로드하게 된다.&lt;/p&gt;

&lt;p&gt;Spark SQL이 테이블 형태의 스키마를 가지고 SQL로 조작하기 위한 자료구조라면, RDD는 map-reduce로 조작하기 위한 자료구조이다. 양방향으로 치환이 가능하다. 따라서 주로 python tuple 형태 (k, v)로 data를 만들어 놓고, map/reduce 함수로 조작하게 된다.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;하나의 RDD는 논리적인 하부구조인 하나 이상의 partition으로 이루어진다. &lt;br&gt;&lt;/p&gt;

&lt;p&gt;RDD에 대한 기본 조작을 python 예제로 살펴보자. 관련 method가 많으므로 자주 사용되는 몇가지만 살펴본다.&lt;br&gt;&lt;/p&gt;

&lt;h2&gt;Cluster Structure&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt; Driver program은 우리들이 작성한 Spark code이고 PC client에서 실행할 수도 있고 Spark cluster node 안에서 실행시킬 수도 있다.&lt;/p&gt;

&lt;p&gt;지금부터의 클러스터 내용은 정확하지 않을 수 있는데 나중에 수정하도록 하겠다. Driver가 data를 load해서 cluster의 각 node에 분산시켰다고 하자. Driver는 cluster node 중에 지정된 app master에게 RDD 조작 명령을 내린다. App master는 RDD를 보관하고 있는 각 executor node에게 다시 명령을 전달한다.  &lt;br&gt;&lt;/p&gt;

&lt;h2&gt;Spark Context&lt;/h2&gt;

&lt;p&gt;Spark cluster에 접속하기 위해서 SparkContext를 생성한다.&lt;br&gt;&lt;/p&gt;

&lt;pre class="wp-block-syntaxhighlighter-code brush: python; notranslate"&gt;from pyspark import SparkContext, SparkConf

conf = SparkConf().setAppName('MyApp').setMaster('local[4]')
sc = SparkContext(conf=conf)&lt;/pre&gt;

&lt;h2&gt;Creating RDD&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;아래에서 생성한 RDD는 이후 example에서도 계속 사용된다. &lt;br&gt;&lt;/p&gt;

&lt;h3&gt;From Driver Program&lt;br&gt;
&lt;/h3&gt;

&lt;pre class="wp-block-syntaxhighlighter-code brush: python; notranslate"&gt;# Small printer
import pprint
def pp(o):
    pprint.pprint(o)
    pprint.pprint(type(o))

# parallelize: Get a Python data and distribute on Spark cluster nodes.
personList = [('David',101),('Bob',102),('Charles',103),('Brad',104)]
personRdd = sc.parallelize(personList)
pp(personRdd)
ParallelCollectionRDD[13] at parallelize at PythonRDD.scala:194
&amp;lt;class 'pyspark.rdd.RDD'&amp;gt;&lt;/pre&gt;

&lt;h3&gt;From External Data Source&lt;br&gt;
&lt;/h3&gt;

&lt;pre class="wp-block-syntaxhighlighter-code brush: python; notranslate"&gt;filePath = 'data/hollins.dat.gz'
# textFile: Open a file and return a RDD.
fileRdd = sc.textFile(filePath)
pp(fileRdd.count())
29888
&amp;lt;class 'int'&amp;gt;&lt;/pre&gt;

&lt;h2&gt;Listing Elements&lt;/h2&gt;

&lt;h3&gt;All&lt;br&gt;
&lt;/h3&gt;

&lt;pre class="wp-block-syntaxhighlighter-code brush: python; notranslate"&gt;# collect: Return a python list from a RDD.
pp(personRdd.collect())
[('David', 101), ('Bob', 102), ('Charles', 103), ('Brad', 104)]
&amp;lt;class 'list'&amp;gt;&lt;/pre&gt;

&lt;h3&gt;First N&lt;br&gt;
&lt;/h3&gt;

&lt;pre class="wp-block-syntaxhighlighter-code brush: python; notranslate"&gt;# first: Return the 1st element of list.
pp(personRdd.first())
('David', 101)
&amp;lt;class 'tuple'&amp;gt;

# take: Return the first n elements of list.
pp(personRdd.take(2))
[('David', 101), ('Bob', 102)]
&amp;lt;class 'list'&amp;gt;

# top: Return the largest n elements of list.
pp(personRdd.top(2))
[('David', 101), ('Charles', 103)]
&amp;lt;class 'list'&amp;gt;&lt;/pre&gt;

&lt;h2&gt;Key-Value&lt;/h2&gt;

&lt;pre class="wp-block-syntaxhighlighter-code brush: python; notranslate"&gt;# lookup: like get() in most cache systems
pp(personRdd.lookup('Charles'))
[103]
&amp;lt;class 'list'&amp;gt;&lt;/pre&gt;

&lt;h2&gt;Transformation Operations&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;map/groupby/join 등과 같이 RDD를 변형시키는 연산들이며 연산 결과가 다시 RDD이므로 연산들을 chainning할 수 있다. Lazy approach라서 transformation은 여러 번을 적용하더라도 실제로 연산이 수행되지는 않는다. Action 연산을 적용할 때 한꺼번에 수행된다. Transformation/Action 연산 리스트는 아래 spark guide page에 나열되어 있다.&lt;/p&gt;

&lt;p&gt;https://spark.apache.org/docs/latest/rdd-programming-guide.html&lt;br&gt;&lt;/p&gt;

&lt;h2&gt;Action Operations&lt;/h2&gt;

&lt;p&gt;reduce/count/collect와 같이 RDD를 python scalar나 list 등으로 최종 결과를 얻어낼 때 사용한다. 그 앞에 적용한 transformation 연산들을 있다면 실제로 순서대로 수행하고 마지막에 action을 수행한다.&lt;br&gt;&lt;/p&gt;



</description>
    </item>
    <item>
      <title>Kubernetes in Baremetals</title>
      <dc:creator>drevispas</dc:creator>
      <pubDate>Thu, 17 Dec 2020 09:21:13 +0000</pubDate>
      <link>https://dev.to/drevispas/kubernetes-in-baremetals-317j</link>
      <guid>https://dev.to/drevispas/kubernetes-in-baremetals-317j</guid>
      <description>&lt;h1&gt;
  
  
  Motivation
&lt;/h1&gt;

&lt;p&gt;I have move to a division of my company that is quite different from the before workspace. First of all, I can't use any cloud service due to strong security policies. I was creating a REST API server with Flask and decided to deploy it on containers.&lt;/p&gt;

&lt;h1&gt;
  
  
  Change history
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Dockerfile
&lt;/h2&gt;

&lt;p&gt;At first, I wrote some Dockerfiles for Flask, MongoDB, Docker registry, NginX, Redis. It was good to deal with samll number of images like in my case and was satisfied that all things were in my control. However building and running several images serially was a bit annoying.&lt;/p&gt;

&lt;h2&gt;
  
  
  Docker Compose
&lt;/h2&gt;

&lt;p&gt;My previous team used to deploy systems with Docker compose. So I tried to go with that and was able to combine related imanges with the Docker compose after some investigation. I was happy with the ways in that images were built and run by a single &lt;code&gt;docker-compose.yaml&lt;/code&gt; file.&lt;br&gt;
I could utilize the existing Dockerfiles to make the Docker compose to build images. &lt;code&gt;docker-compose up -d&lt;/code&gt; started up the related containers in a shot. To stop all together, &lt;code&gt;docker-compose stop&lt;/code&gt; made thigns simple. If you delete every containers and images, run &lt;code&gt;docker-compose down&lt;/code&gt;. To delete even the used volumes, just run &lt;code&gt;docker-compse down --volumes&lt;/code&gt;.&lt;br&gt;
Now buding images and running/stopping containers are sufficient. next how should I secure high-availablity and scalability with that? Remind me, I can't use any cloud services. Services like ELB and auto-scaling was not for me. Kubernetes could have helped me.&lt;/p&gt;

&lt;h2&gt;
  
  
  KinD
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;KinD&lt;/code&gt; saved me at that time. I had no servers to test the Kubernetes in my new environment. KinD means "Kubernetes in Docker" and we can deploy multi-node Kubernetes even in a single machine. At first, configuring KinD was not that easy. The version was still beta and had changed during my test. Furthermore I had to rethink the host layout because the nodes was actually containers. Thus I configured Docker port-publishing to access the Kubernetes &lt;code&gt;nodePort&lt;/code&gt; from the hosting machine.&lt;br&gt;
I was quite satified with KinD. I wrote ConfigMaps, Secrets, Services, Deplyments, StatefulSets, and Ingress (of nginx) and run the resources successfully. I really liked Kustomize with that I can update the existing base YAMLs, combine all YAMLs, and even run all together with &lt;code&gt;kubectl apply -k ./&lt;/code&gt;. But I was worried that these configurations are not real and would be much different from the production environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multi-machine Kubernetes
&lt;/h2&gt;

&lt;p&gt;As times passes, I was able to use serveral Linux machines at last and tried to configure multi-node Kubernetes in multiple machines. Consequently KinD is virtually identical to Kubernetes in multiple machines. That was faster to configure Kubernetes than doing for KinD. Plus it's more intuitive than KinD because control plane and work nodes are just hosts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Baremetal-specific
&lt;/h2&gt;

&lt;p&gt;Unfortunately Kubernetes is not a all-in-one solution. By design, they have reserved empty rooms for some specific implementations. For instance, Pod-to-Pod network, LoadBalancer type Service, Ingress, Persistent volume should be added by some means. If I used a cloud service, it would be not that difficult. In baremetal case, I had to configure plugin solutions for those.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Module required&lt;/th&gt;
&lt;th&gt;Solution&lt;/th&gt;
&lt;th&gt;Comment&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Pod-to-Pod networking&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Flannel&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The defualt &lt;code&gt;vxlan&lt;/code&gt; works fine.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Local persistence volume&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Local Persistence Volume Provisioner&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Good for performance but Pod and node are coupled.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Remote persistence volume&lt;/td&gt;
&lt;td&gt;&lt;code&gt;NFS Provisioning&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A NFS server provides volumes dynamically (on demand volume). Intuitive and easy to view the volume contents&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;External load balancer&lt;/td&gt;
&lt;td&gt;&lt;code&gt;MetalLB&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;It make use &lt;code&gt;LoadBalancer&lt;/code&gt;-type Service and assigns an external IP address for the Service. I choose a narrow range of IPs of my subnet.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Helm
&lt;/h2&gt;

&lt;p&gt;Kustomize was convenient to use and easy to understand. Beyond that, Helm is a package manager for Kubernetes and gives us templating feature. Templating is a familiar concept with us if we have experienced Thymeleaf, Ansible, or Flask template. Plus we can manage the version of our Kubernetes packages with Helm.&lt;br&gt;
The package metadata is in &lt;code&gt;Chart.yaml&lt;/code&gt;, values for template variables are in the file &lt;code&gt;values.yaml&lt;/code&gt;, and resource manaifests are located under a directory &lt;code&gt;templates&lt;/code&gt;, Code snippets are in the file &lt;code&gt;templates/_helper.tpl&lt;/code&gt;.&lt;br&gt;
Fist time, I was confused how many parts be in whether values file or manifest files. It may depends on package own usages.&lt;br&gt;
Finally I deployed my Flask and MongoDB with Helm and felt that managment was more superior than Kustomize.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Common SSL Commands</title>
      <dc:creator>drevispas</dc:creator>
      <pubDate>Thu, 09 Apr 2020 15:07:46 +0000</pubDate>
      <link>https://dev.to/drevispas/common-ssl-commands-13i1</link>
      <guid>https://dev.to/drevispas/common-ssl-commands-13i1</guid>
      <description>&lt;p&gt;Here are TLS commands used many times. I will add little by little.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;################################################################################&lt;/span&gt;
&lt;span class="c"&gt;# Let&lt;/span&gt;
&lt;span class="c"&gt;# server.crt: a server certificate file&lt;/span&gt;
&lt;span class="c"&gt;# root.crt: a self-signed root certificate file&lt;/span&gt;
&lt;span class="c"&gt;# All certificates are in the format of PEM.&lt;/span&gt;
&lt;span class="c"&gt;################################################################################&lt;/span&gt;

&lt;span class="c"&gt;# View the contents of a certificate:&lt;/span&gt;
openssl x509 &lt;span class="nt"&gt;-in&lt;/span&gt; server.crt &lt;span class="nt"&gt;-text&lt;/span&gt; &lt;span class="nt"&gt;-noout&lt;/span&gt;

&lt;span class="c"&gt;# Check a certificate chains:&lt;/span&gt;
openssl verify &lt;span class="nt"&gt;-verbose&lt;/span&gt; &lt;span class="nt"&gt;-CAfile&lt;/span&gt; root.crt server.crt
openssl verify &lt;span class="nt"&gt;-verbose&lt;/span&gt; &lt;span class="nt"&gt;-CAfile&lt;/span&gt; &amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;interm.crt root.crt&lt;span class="o"&gt;)&lt;/span&gt; server.crt

&lt;span class="c"&gt;# Extract public key from private key&lt;/span&gt;
openssl rsa &lt;span class="nt"&gt;-pubout&lt;/span&gt; &lt;span class="nt"&gt;-in&lt;/span&gt; server.key &lt;span class="nt"&gt;-out&lt;/span&gt; server.pub

&lt;span class="c"&gt;# Test connection with certificate.&lt;/span&gt;
openssl s_client &lt;span class="nt"&gt;-connect&lt;/span&gt; www.example.com:8443 &lt;span class="nt"&gt;-state&lt;/span&gt; &lt;span class="nt"&gt;-CAfile&lt;/span&gt; como.crt

&lt;span class="c"&gt;# Save server certificate in PEM&lt;/span&gt;
openssl s_client &lt;span class="nt"&gt;-showcerts&lt;/span&gt; &lt;span class="nt"&gt;-connect&lt;/span&gt; www.example.com:443 &amp;lt;/dev/null | openssl x509 &lt;span class="nt"&gt;-outform&lt;/span&gt; PEM &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; example.pem.crt

&lt;span class="c"&gt;# Save server certificate in DER&lt;/span&gt;
openssl s_client &lt;span class="nt"&gt;-showcerts&lt;/span&gt; &lt;span class="nt"&gt;-connect&lt;/span&gt; www.example.com:443 &amp;lt;/dev/null | openssl x509 &lt;span class="nt"&gt;-outform&lt;/span&gt; DER &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; example.der.crt

&lt;span class="c"&gt;# List certificate from pkcs12 keystore&lt;/span&gt;
keytool &lt;span class="nt"&gt;-list&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nt"&gt;-keystore&lt;/span&gt; example.p12 &lt;span class="nt"&gt;-storetype&lt;/span&gt; PKCS12 &lt;span class="nt"&gt;-storepass&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;storepass&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# Extract certificate from pkcs12 keystore&lt;/span&gt;
keytool &lt;span class="nt"&gt;-export&lt;/span&gt; &lt;span class="nt"&gt;-keystore&lt;/span&gt; example.p12 &lt;span class="nt"&gt;-alias&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;alias&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;-file&lt;/span&gt; example.crt

&lt;span class="c"&gt;# Create a new JKS trustore&lt;/span&gt;
keytool &lt;span class="nt"&gt;-import&lt;/span&gt; &lt;span class="nt"&gt;-alias&lt;/span&gt; rootca &lt;span class="nt"&gt;-file&lt;/span&gt; root.crt &lt;span class="nt"&gt;-keystore&lt;/span&gt; truststore.jks &lt;span class="nt"&gt;-storepass&lt;/span&gt; changeit
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Let's see an example says full steps of making root, intermediate, and server certificates:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create a CA key pair&lt;/span&gt;
openssl genrsa &lt;span class="nt"&gt;-out&lt;/span&gt; root.key 8192
&lt;span class="c"&gt;# Create a self-signed CA certificate&lt;/span&gt;
openssl req &lt;span class="nt"&gt;-sha256&lt;/span&gt; &lt;span class="nt"&gt;-new&lt;/span&gt; &lt;span class="nt"&gt;-x509&lt;/span&gt; &lt;span class="nt"&gt;-days&lt;/span&gt; 3650 &lt;span class="nt"&gt;-key&lt;/span&gt; root.key &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-subj&lt;/span&gt; &lt;span class="s2"&gt;"/C=KR/L=Seoul/OU=Example/CN=Example Root CA"&lt;/span&gt; &lt;span class="nt"&gt;-out&lt;/span&gt; root.crt

&lt;span class="c"&gt;# Or you can combined above two commands:&lt;/span&gt;
openssl req &lt;span class="nt"&gt;-nodes&lt;/span&gt; &lt;span class="nt"&gt;-x509&lt;/span&gt; &lt;span class="nt"&gt;-sha256&lt;/span&gt; &lt;span class="nt"&gt;-newkey&lt;/span&gt; rsa:8192 &lt;span class="nt"&gt;-keyout&lt;/span&gt; &lt;span class="s2"&gt;"root.key"&lt;/span&gt; &lt;span class="nt"&gt;-out&lt;/span&gt; &lt;span class="s2"&gt;"root.crt"&lt;/span&gt; &lt;span class="nt"&gt;-days&lt;/span&gt; 3650 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-subj&lt;/span&gt; &lt;span class="s2"&gt;"/C=KR/L=Seoul/OU=Example/CN=Example Root CA"&lt;/span&gt;

&lt;span class="c"&gt;# Create a server key pair&lt;/span&gt;
openssl genrsa &lt;span class="nt"&gt;-out&lt;/span&gt; server.key 4096

&lt;span class="c"&gt;# Create a CSR&lt;/span&gt;
openssl req &lt;span class="nt"&gt;-new&lt;/span&gt; &lt;span class="nt"&gt;-sha256&lt;/span&gt; &lt;span class="nt"&gt;-key&lt;/span&gt; server.key &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-subj&lt;/span&gt; &lt;span class="s2"&gt;"/C=KR/L=Seoul/OU=Example/CN=svc.example.com"&lt;/span&gt; &lt;span class="nt"&gt;-out&lt;/span&gt; server.crt

&lt;span class="c"&gt;# Create a server certificate&lt;/span&gt;
openssl x509 &lt;span class="nt"&gt;-req&lt;/span&gt; &lt;span class="nt"&gt;-in&lt;/span&gt; server.key &lt;span class="nt"&gt;-CA&lt;/span&gt; root.crt &lt;span class="nt"&gt;-CAkey&lt;/span&gt; root.key &lt;span class="nt"&gt;-set_serial&lt;/span&gt; 01 &lt;span class="nt"&gt;-out&lt;/span&gt; server.crt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Do you want to view the contents of certificate chain? Let call the followin script 'chain.sh' and run like "./chain.sh combined_certificates.crt".&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="nv"&gt;chain_pem&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;chain_pem&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Usage: &lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt; BASE64_CERTIFICATE_CHAIN_FILE"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2
    &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi

if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; openssl x509 &lt;span class="nt"&gt;-in&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;chain_pem&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-noout&lt;/span&gt; 2&amp;gt;/dev/null &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;chain_pem&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; is not a certificate"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2
    &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="nt"&gt;-F&lt;/span&gt;&lt;span class="s1"&gt;'\n'&lt;/span&gt; &lt;span class="s1"&gt;'
        BEGIN {
            showcert = "openssl x509 -noout -subject -issuer"
        }

        /-----BEGIN CERTIFICATE-----/ {
            printf "%2d: ", ind
        }

        {
            printf $0"\n" | showcert
        }

        /-----END CERTIFICATE-----/ {
            close(showcert)
            ind ++
        }
    '&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;chain_pem&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="nb"&gt;echo
&lt;/span&gt;openssl verify &lt;span class="nt"&gt;-untrusted&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;chain_pem&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;chain_pem&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



</description>
      <category>security</category>
      <category>ssl</category>
    </item>
    <item>
      <title>PKI Certificates</title>
      <dc:creator>drevispas</dc:creator>
      <pubDate>Tue, 07 Apr 2020 15:36:01 +0000</pubDate>
      <link>https://dev.to/drevispas/pki-certificates-572f</link>
      <guid>https://dev.to/drevispas/pki-certificates-572f</guid>
      <description>&lt;h1&gt;
  
  
  Trust chain
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aLEInDJa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/fsq4z081kcz9ngb5q1fs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aLEInDJa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/fsq4z081kcz9ngb5q1fs.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is importan for web developers to understand the concept of PKI such as private/public key, certificate and CA. Let us see the concepts briefly.&lt;/p&gt;

&lt;p&gt;We are using SSL certificates subconsciously everyday. Our web browsers have pre-built root certificates which are the roots of trust.&lt;br&gt;
When we visit a web page, the web server encrypts some messages and return back to the web browser. The browser realizes that the server certificate is signed by a certificat authority who is one of the pre-built authorities in the browser and then trusts the server finally.&lt;/p&gt;

&lt;h1&gt;
  
  
  Self-signed Certificates
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GuCm7VLB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/0ncwv62lbbeo7w592xdq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GuCm7VLB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/0ncwv62lbbeo7w592xdq.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In most cases, we use certificates from public CAs for https purpose. But if connections happend only in closed networks, it is efficient and convinient to use self-signed certificate as trusted root certificates.&lt;/p&gt;

&lt;p&gt;A private root CA key and self-signed root certificate is created in a secure and closed machine. I used a hardware appliance called HSM to generate or import private root CA private key and certificate. But in small testing scenarios, it is ok just like in a common linux machine.&lt;/p&gt;

&lt;p&gt;Plus we can make intermediate CAs if we want trust hierarchy. I made three tier of certificates comprising a single root, several intermediate, and  device certificate per device.&lt;/p&gt;

&lt;p&gt;A server creates an CSR filled with information like CN and expiration date, then sends it to an intermediate or root CA server. The CA server signs it with its pair of private key and certificate and generates the server certificate that consists of issues, subject, revocation endpoint and public key of the server.&lt;/p&gt;

&lt;p&gt;Next time, I would like to talk about 2-way SSL which makes securer than the above 1-way SSL.&lt;/p&gt;

</description>
      <category>security</category>
      <category>ssl</category>
    </item>
    <item>
      <title>Database High Availability in Old Days</title>
      <dc:creator>drevispas</dc:creator>
      <pubDate>Thu, 13 Feb 2020 14:05:45 +0000</pubDate>
      <link>https://dev.to/drevispas/database-high-availability-in-old-days-2k0p</link>
      <guid>https://dev.to/drevispas/database-high-availability-in-old-days-2k0p</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oSsl0wSb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/30vzmh054462fwewcyzx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oSsl0wSb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/30vzmh054462fwewcyzx.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In old days, under the pressure of budge, we decided to utilize open source HA solution for the production database system.&lt;/p&gt;

&lt;p&gt;I struggled to install Linux packages and find the right version dependencies between packages. After writing the configuration files for each layer like corosync, pacemake, and hearbeat, I tested individual layers and then all layers together. This had ran on the production for quite a while.&lt;/p&gt;

&lt;p&gt;Nowadays DBaaS is really good to lighten the burden of setup.&lt;/p&gt;

</description>
      <category>database</category>
      <category>highavailability</category>
      <category>cluster</category>
    </item>
    <item>
      <title>Heap Sort</title>
      <dc:creator>drevispas</dc:creator>
      <pubDate>Mon, 03 Feb 2020 14:57:58 +0000</pubDate>
      <link>https://dev.to/drevispas/heap-sort-2fmb</link>
      <guid>https://dev.to/drevispas/heap-sort-2fmb</guid>
      <description>&lt;p&gt;The heap sort is useful to get min/max item as well as sorting. We can build a tree to a min heap or max heap. A max heap, for instance, keeps a parent being not smaller than children.&lt;br&gt;
The following code is for a max heap. The &lt;strong&gt;top&lt;/strong&gt; indicates the next insertion position in the array which is identical to the array size.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Heap&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;Heap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;sz&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;sz&lt;/span&gt;&lt;span class="o"&gt;];&lt;/span&gt; &lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="o"&gt;[++&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="o"&gt;]=&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;climbUp&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;];&lt;/span&gt;
            &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;]=&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="o"&gt;--];&lt;/span&gt;
            &lt;span class="n"&gt;climbDown&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;]=&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;size&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;climbUp&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;]&amp;lt;=&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;swapAt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;climbUp&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;climbDown&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;]&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;++;&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;]&amp;gt;=&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;swapAt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;climbDown&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;swapAt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;];&lt;/span&gt;
            &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;]=&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;];&lt;/span&gt;
            &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;]=&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



</description>
      <category>algorithms</category>
      <category>programming</category>
      <category>java</category>
    </item>
    <item>
      <title>Programming Template: BackTraking </title>
      <dc:creator>drevispas</dc:creator>
      <pubDate>Mon, 03 Feb 2020 14:39:56 +0000</pubDate>
      <link>https://dev.to/drevispas/programming-template-backtraking-7je</link>
      <guid>https://dev.to/drevispas/programming-template-backtraking-7je</guid>
      <description>&lt;p&gt;This is a simple code example of backtraking. This traverses the problem space in depth-first order. I memorized it as a solution template.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;MAXC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;finished&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;bt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;candidates&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;MAXC&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;numCand&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;solved&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;numCand&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getCandidates&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;candidates&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;numCand&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;candidates&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="n"&gt;bt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;finished&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



</description>
      <category>programming</category>
      <category>cpp</category>
      <category>algorithms</category>
    </item>
  </channel>
</rss>
