Apache Zeppelin 설치 및 빌드하기

맥북 포맷하여 제플린 빌드가 날아간 기념으로 Apache Zeppelin을 설치 및 빌드하는 튜토리얼을 적어본다.

  1. Apache Zeppelin 깃헙에 들어간다. 나는 컨트리뷰션을 할 예정이니 저장소를 바로 클론하지 말고 내 계정에 Fork (내 계정에 복제 라고 생각하면 된다)를 먼저 한다. (컨트리뷰션 튜토리얼은 다른 글에 작성 예정)

https://github.com/apache/zeppelin 깃헙 저장소 우상단의 ‘Fork’를 누른다.

2. 포크하여 내계정이름/zeppelin 으로 변경된 저장소에서 ‘Code’ 버튼을 누르고 클립보드 버튼을 눌러 포크된 저장소 URL 을 복사한다.

3. 포크를 원하는 폴더에 git clone 을 해준다. (git clone https://github.com/내계정명/zeppelin.git 명령어 입력)

4. 제플린 설치 가이드에 들어가보면 JDK 1.8을 먼저 설치해야 된다 나와있다.

5. 구글에 JDK 1.8 을 검색하면 제일 위에 나오는 오라클 홈페이지에서 본인의 OS에 맞는 파일을 다운로드 해준다 (누르면 오라클 계정 입력하라 나오는데 회원가입 해야한다 흑흑)

6. 잘 다운로드 되었는지 확인하기 위해 자바 설치경로를 체크해본다. 맥은 /usr/libexec/java_home -v 1.8 를 입력하면 나온다. 보통
/Library/Java/JavaVirtualMachines
에 설치되어있다. 방금 1.8을 설치해서 /Library/Java/JavaVirtualMachines/jdk1.8.0_271.jdk/Contents/Home 로 반환되었다.

7. 경로를 알았으니 JAVA_HOME 을 설정하기 위해 홈으로 빠져나와(cd ~) 배쉬 설정파일을 접근한다. 각자 사용하는 shell마다 파일 이름이 다를것이다. 나는 zsh등이 아닌 기본 bash를 사용해서 vi .bash_profile 명령어를 입력하였다.

8. i를 눌러 인서트모드로 바꾼 후, 다음과 같이 입력하고 저장(esc누르고 :wq) 한다

JAVA_HOME=여러분의경로
PATH=$PATH:$JAVA_HOME/bin
export JAVA_HOME
export PATH

9. 설정이 저장되었으면 source .bash_profile  를 입력해 환경설정을 저장한다. 그리고 echo $JAVA_HOME 명령어를 입력했을 때 아까 적은 자바 경로가 제대로 나오면 성공!

10. 나는 프론트엔드만 컨트리뷰션할거라 백엔드는 도커로 띄울것이다. 도커가 없는 분들은 도커를 다운로드 한다.

11. Docker Desktop 이 잘 설치되었는지 확인한다

12. 공식문서에 나와있는 오피셜 도커를 띄우는 명령어는 docker run -p 8080:8080 –rm –name zeppelin apache/zeppelin:0.9.0 이다. 하지만 나는 포트포워딩을 사용할것이기 때문에
docker run -e ZEPPELIN_ADDR=0.0.0.0 -p 8081:8080 –rm –name zeppelin apache/zeppelin:0.9.0

로 포트를 살짝 바꿔서 띄운다.

13. 이제 프론트엔드를 띄울것이다. 새로운 angular 프론트를 사용할것이기 때문에 cd zeppelin-web-angular/ 로 들어간다. 먼저 README.md를 읽어본다.

서버 프록시를 사용하려면 .env 파일에 포워드하고싶은 포트를 입력하라고 적혀있다.

14. 아까 서버를 8081포트에 띄웠으니 .env 파일을 만들어 SERVER_PROXY=http://localhost:8081 라고 적어주고 저장한다.

15. npm install 명령어로 의존성을 설치해준다.

16. npm start 를 통해 서버를 켠다.

17. :4200번 포트에 프론트엔드가 잘 뜬것을 볼 수 있다!

GitHub Actions로 Vuepress 배포하기

내 TIL 사이트는 Vuepress로 말아져 있다

http://milooy.github.io/TIL/
커스텀하기 편하고 가볍다.
정적 사이트 장점을 살려 GitHub Pages에 배포해뒀다.

사이트를 배포하는 가장 기본적인 방법은
매번 글을 작성할때마다 로컬에서 빌드 -> gh-pages 브랜치에 force push 하는건디
증맬 귀찮은 일이다.

package.json에 deploy 스크립트를 만들어서 가-끔 생각날때마다 돌려주곤 했는데…

"scripts": {
    "dev": "vuepress dev documents",
    "build": "vuepress build documents",
    "commit": "vuepress build documents && git add build -f && git commit -m 'Subtree commit'",
    "deploy": "git push origin `git subtree split --prefix build master`:gh-pages --force"
  },

GitHub Actions를 사용해
코드를 푸시할때마다 자동으로 위 스크립트가 돌도록 업데이트를 해봤다.
(그전까진 왜 안한겨.. 생각보다 나의 참을성이 좋구머잉)

하는법 간단히 기록해두기~

Step 1: Vuepress로 사이트를 만든다

다큐멘테이션 보면 금방 만들어용 https://vuepress.vuejs.org/
다 만들면 GitHub 저장소에 푸시하셈.

Step 2: 저장소에 GitHub Pages 세팅하기.

저장소 Settings탭 -> GitHub Pages 섹션에 가서
Source를 ‘gh-pages’로 바꾼다. 그러면 gh-pages브랜치에 있는 index.html 읽어서 사이트를 보여줌.

image

Step 3: workflow 파일 생성

저장소 루트에 .github/workflows/main.yml 파일을 만든다. main말고 원하는 다른 이름 써도 무방.

아래 코드를 복사하고 저장한다.
jenkey2011이란 깃헙 유저가 배포한 action 가져다 쓴거다.
https://github.com/marketplace/actions/vuepress-deploy

Dockerfile, Docker Hub 이라고 생각함 될듯. 선언적 문법 매력적이다. 일해라 절해라 적어두기.

name: Build and Deploy
on: [push]
jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
    - name: Checkout
      uses: actions/checkout@main

    - name: Vuepress deploy
      uses: jenkey2011/vuepress-deploy@1.0.1
      env:
        ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
        BUILD_SCRIPT: yarn && yarn build
        TARGET_BRANCH: gh-pages
        BUILD_DIR: build/

Step 4: GitHub 저장소에 환경변수 세팅

위 yaml 파일 보면 ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}를 쓰는데, GitHub 저장소에 ACCESS_TOKEN 환경변수를 세팅해줘야 한다.

먼저 내가 나라는걸 증명하는 프라이빗 토큰을 발급받자.
Settings > Developer settings > Personal access tokens에 들어가
https://github.com/settings/tokens

Generate new token 하면 된다(기존에 만들어놨다면 재활용 해도 된다)
image

이렇게 만든 토큰을
저장소 Settings > Secrets > New secret에 key는 ACCESS_TOKEN라 적고 value에 토큰을 복사 붙여넣기 하면 된다. 고럼 yaml 파일이 돌면서 저장소 환경변수를 참고해감.

image

Step 5: Happy TIL-ing!

yaml 파일을 GitHub에 올린다. 코드를 Push할때마다 자동으로 GitHub액션이 돌며 위에 선언한 Yaml코드가 실행된다.
저장소 Actions 탭에서 확인 가능!

image

npx create-react-app 에서 A template was not provided. This is likely because you’re using an outdated version of create-react-app. 에러가 날 때

Problem

CRA 공식 문서대로 npx create-react-app my-app 명령어를 입력했는데

A template was not provided. This is likely because you're using an outdated version of create-react-app.

에러가 나면서 빈 react app이 생성되었다.
훗 뭐 예전에 글로벌로 설치했던 cra 때문이겠지 하고 npm uninstall -g create-react-app 돌리고 재실행했는데 여전히 위에 에러가 났다.

npm list -g 로 글로벌 모듈을 봐도 create-react-app이 없는데 무슨 일이지… 했음

Solution

which create-react-app

명령어로 컴에 아직 cra가 남아있는지 찾는다. 나는 /usr/local/bin/create-react-app 에 있더라.

rm -rf /usr/local/bin/create-react-app

위 명령어로 가뿐하게 지워준다.
다시 npx create-react-app my-app 하면 이젠 template 껴져서 제대로 된다 🙂

Conference Site for ‘Data Science is a Team Sport!’

Background


Build a conference landing site with Vue.js.
Made a ‘Electronic display’ section to show sponsor list,
and show session detail information like a sports player with animation.

Results

Show session information like sports player introduction
Main page
Timetable page

Zepl Front End UI/UX Renewal Project

Background

Before, Zepl doesn’t had a designer and there’s no rule for the UI/UX guideline.

I teamed up with one designer and do the UI/UX renewal with building a reusable components and setting up design guidelines.

Participants: Yurim(Front End Engineer), Youngjin(Designer)
Project Period: 2018.06~2019.02
URL: https://www.zepl.com/

Before

Has no consistency on Font hierarchy, margins, the way to show the datasets.

After (Components that I made)

Overall app behavior
Carousel, Dropdown with Skeleton loading indicator
Modal with searchable dropdown components
Filterable/Sortable/Searchable Table with Pin feature
Item box and Overlay with micro interactions
Clickable list and Pagination
Collapsible with Real-time Graphs and Table
Outline sidebar with search feature
Create-able Select box which supports Validation, Copy/Paste from Excel sheet
Code snippets

[일일코딩 #35] String incrementer

Question

스트링에서 넘버만 따다가 +1 하는것. 자릿수 지키기.

https://www.codewars.com/kata/string-incrementer/javascript

Your job is to write a function which increments a string, to create a new string.

If the string already ends with a number, the number should be incremented by 1.
If the string does not end with a number. the number 1 should be appended to the new string.
Examples:

foo -> foo1

foobar23 -> foobar24

foo0042 -> foo0043

foo9 -> foo10

foo099 -> foo100

Attention: If the number has leading zeros the amount of digits should be considered.

My answer

정규식으로 number만 따다가 +1 해주고 원래 자릿수를 구해서 0을 그만큼 채워줬다.
마음에 안 듦.

function incrementString (str) {
    const numRegex = /[0-9]+/.exec(str);
    if (numRegex) {
        const numStr = numRegex.pop();

        const newNum = Number(numStr) + 1;
        const zeroNums = numStr.length - newNum.toString().length;
        const zeroStr = (zeroNums > 0) ? Array(zeroNums).fill("0").join("") : "";

        return str.replace(numStr, `${zeroStr}${newNum}`)
    }
    return `${str}1`;
}

Others' answer

Azuaron, Nakid..

function incrementString (input) {
    // 맨끝이 not a number면 그냥 + "1" 
    if(isNaN(parseInt(input[input.length - 1]))) return input + '1';

    // "001"을 넘겼다면 match는 001, p1은 00, p2는 1
    return input.replace(/(0*)([0-9]+$)/, function(match, p1, p2) {
        var up = parseInt(p2) + 1;

        // +1한 숫자 자릿수가 원본자릿수보다 크다면 0을 하나 뺀만큼 앞에 붙여주고 아니면 원본 0갯수만큼 붙여주기
        return (up.toString().length > p2.length) ? p1.slice(0, -1) + up : p1 + up;
    });
}
  • String.replace 첫번째 인자에 정규식을 넘길수 있고, 두 번째 인자에 함수를 넘길 수 있구나!
  • 정규식에 ()으로 그룹을 지어서 두번째 이후 인자로 받을 수 있구나
  • String.slice(0, -1)은 마지막 한글자를 떼는거구나

산산조각, 정호승

모든 선택지
혹은 선택할 수 없이 당한 일도
의미가 있고 다 옳은 길이지

 

 

 


룸비니에서 사온

흙으로 만든 부처님이

마룻바닥에 떨어져 산산조각이 났다

팔은 팔대로 다리는 다리대로

목은 목대로 발가락은 발가락대로

산산조각이 나

얼른 허리를 굽히고

서랍 속에 넣어두었던

순간접착제를 꺼내 붙였다

그 때 늘 부서지지 않으려고 노력하는

불쌍한 내 머리를

다정히 쓰다듬어 주시면서

부처님이 말씀하셨다

산산조각이 나면

산산조각을 얻을 수 있지

산산조각이 나면

산산조각으로 살아갈 수가 있지