[컴] 비디오 파일 보관 하기 좋은 곳

video repository / 스토리지 / storage

무료 비디오 파일 저장소

자신이 찍은 비디오를 보관하고 싶을 때 어디를 사용하면 될까? 일단 무료중에 현재 생각나는 것들을 정리해 봤다.

  • 구글 포토
    • 이건 원본으로 저장할 때는 무한이 아니다. 하지만 품질을 high quality 로 설정하면 용량에 제한없이 저장된다.
    • https://support.google.com/photos/answer/6193313?co=GENIE.Platform%3DAndroid&hl=en
  • git lfs 
    • github : 용량이 부족하고 느리다.
  • vimeo
    • 좋다. 원본 다운로드도 가능하다. 
    • 다만 비디오 총 용량은 5GB 의 한도가 있다.(Basic)
    • 일주일에 올릴 수 있는 크기가 500MB 로 제한된다.(Basic)
  • youtube
    • 원본을 받을 때는  전 비디오를 한번에 받아야만 한다.
    • 하나씩 받을 수 있지만, 원본 파일을 받을 수는 없다.
    • https://support.google.com/youtube/answer/56100?hl=en
  • telegram
    • upload/download 속도가 느리다.(upload 속도보다는 download 속도가 빠르다.)
    • 저장용량은 무한이다.
    • bot 을 이용하면, 외부 url 을 만들 수도 있다.
      • - https://t.me/TGhost_bot
      • - https://telegram.me/tlgurbot
      • 텔레그램 api 에서 20mb 이하 파일만 가능하다. 그래서 외부링크를 만들어주는 bot이 지원가능한 파일사이즈도 20mb 이하 만 가능하다.



선택

현재로서는 5GB 이내라면 vimeo 가 최선인듯 싶다. 다만 텔레그램을 사용하고 있다면, telegram 을 추천하고 싶다. 다만 backup 용으로만 적절하다. 바로바로 시청을 하고 싶다면, 아무래도 vimeo 가 더 적당할 듯 싶다.


[컴] git rebase 설명

git rebase / 깃 리베이스 /

git rebase

git rebase 는 아래처럼 설명이 된다.

Git - Rebase하기
  1. 실제로 일어나는 일을 설명하자면 일단 두 브랜치가 나뉘기 전인 공통 커밋으로 이동하고 나서
  2. 그 커밋부터 지금 Checkout한 브랜치가 가리키는 커밋까지 diff를 차례로 만들어
  3. 어딘가에 임시로 저장해 놓는다.
  4. Rebase할 브랜치(역주 - experiment)가 합칠 브랜치(역주 - master)가 가리키는 커밋을 가리키게 하고
  5. 아까 저장해 놓았던 변경사항을 차례대로 적용한다.

그림 3-29는 이러한 과정을 나타내고 있다.

다른 vcs 와 연관지어서...

이보다 이해를 돕기 위해 좀 더 근원적인 설명을 해보려 한다.

일단 rebase 의 의미에서 시작하자. rebase 라는 용어는 git 에서 처음사용된 것이 아니다. 이전의 version control software 에서 존재하던 용어이다.

그냥 단순하게 해석하면 "base 를 다시(re)" 만드는 것이다.

그럼 base 가 무엇을 이야기 하는 것일까. 그것은 현재 내가 작업하고 있는 source 다. 그래서 rebase 를 한다는 것은 현재 내가 base 로 사용하던 source 를 새로 다시 받는 것(rebase)이라고 보면 된다.






이것이 결국 git 에서도 같은 방식으로 동작한다.

git rebase 를 하면 현재 내가 branch 를 받은 시점, 즉 내 작업들이 적용되기 전,(commit 을 하기전) 으로 돌아가서, 나의 base 를 새로운 내용이 적용된 base 로 변경한다. 그리고 내가 작업한 내용(commit) 을 적용하게 되는 것이다.

git rebase 는 여기에 더해 훨씬 다양한 기능을 제공한다. 자세한 내용은 git rebase man page 를 확인하자.



[컴] 알아두면 쓸데없는 텔레그램 팁 Telegram Tips

rss reader / rss feed reader / 비번 설정 / 텔레 비번 설정 / 텔레그램에서 전화번호 변경 방법 /

알아두면 쓸데없는 텔레그램 팁 Telegram Tips

rss feed 를 telegram 으로 받기(subscribe the rss feed)

https://t.me/rss2tg_bot  : 이 봇(bot)을 이용하면 된다.

  • 이 봇을 등록하고, 채팅창에서 rss feed 를 넣기만 하면 subscribe 된다.

reminder

  • 이제 telegram 자체 내에 scheduled message 가 추가됐다. 그것을 사용하자.
  • 여기 에서 3개의 reminder bot 을 소개해 준다.
  • telegram 검색창에서 "@Remind me" 를 치면 나온다.

adaptive layout

일정너비 이상 telegram desktop(pc버전) 의 너비(width) 를 늘리면, 말풍선이 왼쪽으로 모입니다.

Last seen & online

이것은 내가 online 인지 여부나, 마지막 접속 시간등을 상대방과 공유할 것인지 여부를 정할 수 있다.

참고로, 상대방과 공유하지 않으면, 나도 상대방의 online 여부 등을 알 수 없다. 그리고 공유하지 않아도, 접속시간이, '최근', '일주일내' 등등 으로 상대방에게 알려진다.

  • Settings \--\> Privacy & security(개인 정보 및 보안) \--\> Privacy 부분 \--\> Last seen & online


전화번호 노출

내 전화번호가 상대방에게 노출되는 것을 막을 수 있다. 

그리고 상대방이 내 번호를 등록했다고 해도, 내가 상대방의 번호를 contacts 에 등록하지 않으면, 상대방은 내 번호를 확인할 수 없다. 이것은 홍콩시위때 중국 정부가 이것을 악용해서 막았다.(참고: 텔레그램, 곧 업데이트… 중국 당국의 홍콩 시위자 신원 추적 가능성 따라)

  • Settings --> Privacy & security --> Privacy 부분 --> Phone number

Local passcode

비밀번호를 설정 하는 방법이다.

  • Settings --> Privacy & security --> Local passcode 부분 --> Turn on local passcode

2단계 로그인

'안전한 메신저' 텔레그램도 뚫렸나? 기사에서도 보듯이 sms 를 통제당하게 되면(sim 카드복사등) 뚫리게 된다. 그래서 "2단계 로그인" 설정을 해놓는 것이 좋다.

  • Settings --> Privacy & security -->보안 부분 --> 2단계 인증

Delete my account

일정시간 텔레그램에 접속하지 않으면, 계정을 삭제한다. 이때 이 일정기간을 정할 수 있다. 최대 1년이다.

  • Settings --> Privacy & security --> Delete my account --> If away for ...

번호변경

번호를 변경하면, 그 번호로 모든 정보가 옮겨진다.

  • Settings --> Edit Profile --> Phone number 에서 클릭

자동 다운로드 방지

기본적으로 그림이나, 파일등은 일정크기 이하라면, 자동으로 다운로드 된다. 이 부분에 대한 설정을 할 수 있다.

  • Settings --> Advanced --> Automatic media download 부분 --> In private chats 

자동으로 메시지 삭제 Auto-Delete Messages

  • Set messages to auto-delete for everyone 24 hours or 7 days after sending.
  • Control auto-delete settings in any of your chats, as well as in groups and channels where you are an admin.
  • To enable auto-delete, right click on the chat in the chat list > Clear History > Enable Auto-Delete.
  • Channel 또는 group 에서 –> 메뉴 –> Channel Info –> 메뉴 버튼 –> Auto-Delete

채널, 그룹에서 캡쳐 못하게 하기

이 기능을 켜면 복사, 캡쳐 모두 안된다. 전달(forward)도 안된다.

  • Channel 또는 group 에서 –> 메뉴 –> Channel Info –> 메뉴 버튼 –> Manage Channel –> Channel Type –> Content Protection –> Restrict saving content 를 on

폴더 만들기

폴더로 채팅방을 구분할 수 있다.

  • Settings –> Folders

markdown 을 이용한, 페이지 만들기

https://telegram.org/blog/instant-view#telegraph

telegraph

  • @telegraph bot 을 이용하면, 자신의 계정을 만들어 작성할 수 있다. 그러면 추후에도 edit 가 가능하다. 하지만 삭제는 안되는 듯 하다.
  • 그렇지 않으면, 그냥 session 이 유효한 동안에만 edit 가 가능하다.
  • https://telegra.ph/ 에서 원하는 페이지를 만들어서 공유하면, 수신자는 instant view 를 통해서 확인해 볼 수 있다. 더 긴글, rich text 등을 사용하고 싶을 때 사용하면 된다.

텔레그램 프리미엄

프리미엄에서 얻을 수 있는 혜택

  • 두배 상승된 제한
    • 그룹, 채널을 1000개 까지 join, 무료는 500개
    • pinned chat 10개, 무료는 5 개
    • public links 는 20개 , 무료는 10개 (t.me/name)
    • Favorite GIFs 에 400개 저장 ,무료는 200개
  • 4GB 파일 업로드 : 무료는 2GB 까지 업로드 가능, 다운로드 제한은 없다.
  • 빨라진 다운로드 : 다운로드 속도제한이 사라진다.
  • 프리미엄 스티커 : 애니메이션 효과가 추가된 이모테콘을 쓸 수 있다. 계속 업데이트 된다.
  • 반응(reactions) 도 프리미엄만 쓸 수 있는 이모지가 추가된다.
  • 음성을 text 로 변환해준다.
  • 기본 chat folder 를 변경할 수 있다. 무료는 All Chats 가 기본이다.
  • 대화 리스트에 보이는 프로필에 영상을 넣을 수 있다.
  • 프리미엄 유저라는 표시(badget) 가 추가된다.
  • 홈화면에 새로운 아이콘이 추가된다.
  • 광고가 없다.

[컴][js] 자바스크립트 code 의 속도 측정

js code speed / 코드 속도 측정 / js engine speed / 벤치마크 / benchmark


js code 의 속도 측정 사이트

위의 사이트에서 특정 js code 를 적고, 실행해서 소요시간을 측정할 수 있다.

특징

  1. 위의 방법을 이용해서 손쉬게 firefox / chromium 의 속도 비교를 할 수 있다.
  2. 다만 주의할점은 처음 수행할 때와 두번째 수행할 때의 속도가 다를 수 있다. 그러므로 여러번 해보고 나서 속도를 판단할 필요가 있다.

[컴] React Native 의 단점과 Flutter 의 장점


Flutter 의 장점

reddit 에 올라온 댓글 (Flutter: A Framework to Surpass React Native : programming) 을 보면, react native 의 단점을 엿볼 수 있다. 더불어 Flutter 의 장점도 알 수 있다.

react native 의 단점

글을 보면 Flutter 가 여러모로 나아보인다.

See Also

  1. Kotlin/Native: kotlin 진영에서도 여러 플랫폼에서 작성할 수 있도록 KMM 이라는 것을 내놨다.
  2. Bringing PC Games to Mobile with Flutter | Rainway
  3. Why Flutter Uses Dart - By
  4. React Native at Airbnb: The Technology | by Gabriel Peal | Airbnb Engineering & Data Science | Medium, 2018-06-19
    1. Airbnb(에어비앤비) 에서 React Native 를 사용하면서 얻을 내용을 공유했다. Native 의 단점들을 세세하게 적어놨다. Airbnb 는 결국 서서히 React Native 를 사용하지 않게 된 이유를 적어놨다. 
    2. 몇줄정리
      1. 처음에 cross-platform에 대한 대처를 쉽게 하기 위해서 사용했다.
      2. 결국 높은 단계의 feature 를 제공하기 위해선 native 를 사용하게 된다. 이것이 처음에 의도했던 하나의 코드로 여러 플랫폼에서 사용하는 것이 더 이상 불가능하게 됐다.
      3. 개발자도 reactive native 에 대한 지식에 더해, iOS, androidOS 에 대한 지식을 갖추어야 했다. 팀은 결국 쪼개질 수 밖에 없었다.
      4. 결국 native 에서 사용할 framework 를 만들었다.
  5. Reflectly — From React Native to Flutter | by Daniel Vestergaard | Reflectly Engineering | Medium
    1. react native 는 결국 android, ios 에서 원하는 UI 모습을 표현하지 못했다. Flutter로는 만족스럽다. 라는 내용의 글

[컴][js] redux-saga 동작 분석




redux-saga 동작 분석

위의 예제로 분석할 것이다.

// saga.js
import { put, takeEvery, all  } from 'redux-saga/effects'

const delay = (ms) => new Promise(res => setTimeout(res, ms))


export function* helloSaga() {
  console.log('Hello Sagas!')
}


// ...

// Our worker Saga: will perform the async increment task
export function* incrementAsync() {
  yield delay(1000)
  yield put({ type: 'INCREMENT' })
}

// Our watcher Saga: spawn a new incrementAsync task on each INCREMENT_ASYNC
export function* watchIncrementAsync() {
  yield takeEvery('INCREMENT_ASYNC', incrementAsync)
}



// notice how we now only export the rootSaga
// single entry point to start all Sagas at once
export default function* rootSaga() {
  yield all([
    helloSaga(),
    watchIncrementAsync()
  ])
}


// main.js
import "babel-polyfill"

import React from 'react'
import ReactDOM from 'react-dom'
import { createStore, applyMiddleware } from 'redux'

import Counter from './Counter'
import reducer from './reducers'
//// default export 인 sagaMiddlewareFactory 를 createSagaMiddleware 에 assign 한 것
import createSagaMiddleware from 'redux-saga'
// import { rootSaga } from './sagas'
import rootSaga from './sagas'

// const store = createStore(reducer)
const sagaMiddleware = createSagaMiddleware()
const store = createStore(
  reducer,
  applyMiddleware(sagaMiddleware)
)
sagaMiddleware.run(rootSaga)

const action = type => store.dispatch({type})

function render() {
  ReactDOM.render(
    <Counter
      value={store.getState()}
      onIncrement={() => action('INCREMENT')}
      onDecrement={() => action('DECREMENT')}
      onIncrementAsync={() => action('INCREMENT_ASYNC')} />,
    document.getElementById('root')
  )
}

render()
store.subscribe(render)

createSagaMiddleware()

createSagaMiddleware() --> sagaMiddlewareFactory() 가 호출된다. sagaMiddlewareFactory 를 확인해보면 대체로 이전버전의 사용법에 대한 error 를 던져주기 위한 용도인듯 하다. 그외에는 sagaMiddleware 라는 function 을 만들어서 return 해준다.

sagaMiddleware() 를 호출할 때 runSaga 에 첫번째 argument 를 assign 해준다.(이것이 boundRunSaga) 그리고 sagaMiddleware.run 을 하면,  이 boundRunSaga  를 호출한다.


createStore() / applyMiddleware()

applyMiddleware() 는 단순하다. 기존의 createStore() 를 실행하고, 그 이외에 다른 동작을 하기 위한 함수라고 보면 된다. python 의 decorator 같은 역할이다.

물론 로직은 좀 더 복잡하게 짜여있다. applyMiddleware() 를 직접실행시키는 것이 아니라createStore 내에서 applyMiddleware() 가 decorator 처럼 동작해야 해서 createStore 내에서 다시 호출(call)한다. 그런 이유로 applyMiddleware() 가 function 을 return 한다. 말이 복잡하다. source code 를 확인하자.

export default function applyMiddleware(...middlewares) {
  return createStore => (...args) => { // pass the createStore as an argument
    const store = createStore(...args)
    let dispatch = () => {
      throw new Error(
        'Dispatching while constructing your middleware is not allowed. ' +
          'Other middleware would not be applied to this dispatch.'
      )
    }

    const middlewareAPI = {
      getState: store.getState,
      dispatch: (...args) => dispatch(...args)
    }
   // 기존의 dispatch 에 middleware 를 추가해서 dispatch 를 새롭게 만든다.
    const chain = middlewares.map(middleware => middleware(middlewareAPI))
    dispatch = compose(...chain)(store.dispatch)

    return {
      ...store,
      dispatch
    }
  }
}
...
export default function createStore(reducer, preloadedState, enhancer) {
  ...
  if (typeof enhancer !== 'undefined') {
    if (typeof enhancer !== 'function') {
      throw new Error('Expected the enhancer to be a function.')
    }

    return enhancer(createStore)(reducer, preloadedState)
  }
  ...
}


sagaMiddleware.run(rootSaga)

sagaMiddleware.run(rootSaga) 를 하면 runSaga() 가 호출된다. runSaga() 에서는 필요한 설정들에 대한 값들을 set 하고(sagaMonitor 같은) proc() 를 호출한다.(proc.js)
proc(env, iterator, context, effectId, getMetaInfo(saga), /* isRoot */ true, noop)

proc 에서 stdChannel 를 생성하는데, 이녀석은 약간의 경고문구만 추가한 eventChannel 이다. 이녀석은 createSagaMiddleware 를 할 때 생성된다.

proc 에서 next() 를 호출하고, next 는 iterator.next() 를 호출한다. iterator 를 이용해서 all() 로 묶인 task 들을 한번에 처리한다.


// saga.js
export default function* rootSaga() {
  yield all([
    helloSaga(),
    watchIncrementAsync()
  ])
}
...

// runSaga.js
function runSaga(_ref, saga) {
  ...

  var iterator = saga.apply(void 0, args);
  ...
  return immediately(function () {
    var task = proc(env, iterator, context, effectId, __chunk_1.getMetaInfo(saga),
    /* isRoot */
    true, __chunk_1.noop);

    if (sagaMonitor) {
      sagaMonitor.effectResolved(effectId, task);
    }

    return task;
  });
}

function proc(env, iterator, parentContext, parentEffectId, meta, isRoot, cont) {
  if (iterator[__chunk_1.asyncIteratorSymbol]) {
    throw new Error("redux-saga doesn't support async generators, please use only regular ones");
  }
  ...
  next(); // then return the task descriptor to the caller
  
  return task;
  /**
   * This is the generator driver
   * It's a recursive async/continuation function which calls itself
   * until the generator terminates or throws
   * @param {internal commands(TASK_CANCEL | TERMINATE) | any} arg - value, generator will be resumed with.
   * @param {boolean} isErr - the flag shows if effect finished with an error
   *
   * receives either (command | effect result, false) or (any thrown thing, true)
   */

  function next(arg, isErr) {
    try {
      var result;
      
      if (isErr) {
        result = iterator.throw(arg); // user handled the error, we can clear bookkept values
        clear();
      } else if (__chunk_1.shouldCancel(arg)) {
        /**
          getting TASK_CANCEL automatically cancels the main task
          We can get this value here
           - By cancelling the parent task manually
          - By joining a Cancelled task
        **/
        ...
      } else if (__chunk_1.shouldTerminate(arg)) {
        // We get TERMINATE flag, i.e. by taking from a channel that ended using `take` (and not `takem` used to trap End of channels)
        ...
      } else {
        result = iterator.next(arg);
      }

      ...
    } catch (error) {
      if (mainTask.status === CANCELLED) {
        throw error;
      }

      mainTask.status = ABORTED;
      mainTask.cont(error, true);
    }
  }
  ...
}


redux-saga 사용

redux-saga 는 특정 이벤트가 끝날때에 대한 작업을 미리 등록해 놓을 수 있다.(saga.js)

그래서 원래라면,

  1. 특정 이벤트가 발생하고, 
  2. 그 작업을 수행한 후(event handler)에 
  3. 우리가 원하는 작업을 실행하기 위해서 우리의 code를 추가해야 한다.(callback) 
하지만 redux-saga 는 그부분의 대한 구현에 관계없이 구현을 하면 된다.

redux-saga 를 이용해서 event 가 끝나는 시점에 호출되는 대신에,
  1. 먼저 특정 event 를 기다리는 code 를 실행하고 
  2. event 가 발생할 때 까지 control 을 다른 곳에 넘겨준다. 그리고 event 가 발생하면 다시 control 을 받아온다.(yield)

  yield takeEvery('INCREMENT_ASYNC', incrementAsync)

간단히 이야기 하면, await/async 를 사용하게 해주는 것이라 보면 된다.


아래 글을 읽으면 자세한 이야기를 알 수 있다.








[컴][js] redux-saga

redux-saga / redux saga / 사가 / 리덕스 사가


redux-saga vs await/async

"ref. 2 --> Why not use ES2016/Next async await?" 를 보면 saga 는 await/async keyword 를 대신해서 사용할 만한 방법인듯 싶다. 다만 이글에서도 언급하고 있지만, 글 자체가 최신의 redux-saga 의 내용이 아니기에 일단 정확한 확인은 필요하다.

await/async 보다 나은점

  1. test case 작성에 유리 : ref. 2 에 따르면 await/async 보다 유리한 점 하나는 request 를 시도할 때 await/async 는 직접적으로 request/fetch 함수를 호출하지만, redux-saga 에서는 call 을 호출하고 관련 parameter 만 전달하기 때문에, test case 를 만들 때 그 함수를 mock up 으로 대체할 수 있다 정도인 듯 싶다.
  2. browser 지원 : 브라우저에서 아직 await/async 를 공식적으로 지원하지 않는다. redux-saga 에서 사용하는 generator 에도 문제는 있다. "generator 에 대한 browser 의 지원"도 모든 브라우저에서 완벽하게 지원하지는 않는다.(적어도 IE 는 전혀 지원하지 않는다.) 그래서 이 경우에는 polyfill 을 따로 다운로드 해야 하는데, 그 파일의 용량이 크다.[ref. 3]

Redux Saga chooses generators over async/await

  • https://redux-saga.js.org/ --> Redux Saga chooses generators over async/await
  • redux-saga 가 async/await 를 안쓰고 generator 를 쓰는 이유를 알려준다. 
    • 스케쥴링의 간단함(scheduling simplicity)과 Promise를 사용하는 현재 Saga 개념들의 semantics 를 유지하기가 어려워진다.
    • async/await 은 간단하게 cacellation 같은 것들이 불가능하다.
    • generator 를 쓰면, effect 들이 언제, 어떻게 실행되는지를 통제할 수 있다.

redux-saga examples

Saga

saga 에 대한 설명은 See Also 2, 3 에서 확인을 하자. 

대체로 saga 는 분산시스템에서 쓰이는 transaction 방식을 이야기 하는 듯 하다. 

만약 분산시스템에서 여러개 transaction 를 수행한다고 하면, 이 여러개의 transaction 이 crash 가 났을 때 roll back 하는 법이 (compensate) 있는 것이다. 그래서 만약 1번째 transaction 부터 3번째 transaction 까지는 잘 동작하고, 4번째 transaction 에서 crash 가 나면, 다시 3번째 transaction 이 완료된 시점으로 가서, 다시 4번째 transaction 을 실행하는 것이다.[see also 3]

See Also

  1. Read Me · Redux-Saga
  2. Confusion about Saga pattern - Roman Liutikov - Medium : saga 에 대한 설명
  3. Clarifying the Saga pattern  by kellabyte, 2012-05-30 : saga 에 대한 설명

References

  1. 5. External Resources · Redux-Saga: 여러가지 Redux-Saga 와 관련된 글들을 확인할 수 있다.
  2. Handling async in Redux with Sagas, 2016-01-23
  3. Master Complex Redux Workflows with Sagas, 2016-02-02