레이블이 computer인 게시물을 표시합니다. 모든 게시물 표시
레이블이 computer인 게시물을 표시합니다. 모든 게시물 표시

[컴][웹] tomcat 에서 log 를 영어로 나오게 하는 법

region / locale / language 변경 /

톰캣 / 톰켓

tomcat log 를 영어로 나오게 하는 법

catalina.bat

chocolatey 를 사용해서 tomcat 을 설치했는데, catalina.bat 를 사용해서 실행하니, 한글로그가 깨져서 나왔다. terminal 을 UTF-8 으로 열면 해결 되지만, 그러고 싶지 않았다.

그래서 catalina.bat 를 수정해서 log 를 영어로 나오도록 설정했다.


language, region option 추가

catalina.bat 에서 JAVA_OPTS 가 설정되는 부분을 찾았다.
  • c:\ProgramData\chocolatey\lib\Tomcat\tools\apache-tomcat-9.0.26\bin\catalina.bat

그리고는 아래처럼 language 와 region 부분을 추가해 줬다.
if not "%JSSE_OPTS%" == "" goto gotJsseOpts
set "JSSE_OPTS=-Djdk.tls.ephemeralDHKeySize=2048 -Duser.language=en -Duser.region=US" 
:gotJsseOpts
set "JAVA_OPTS=%JAVA_OPTS% %JSSE_OPTS%"




References

  1. Set Tomcat’s Default Locale – Knowm.org


[컴][머신러닝] Recurrent Neural Networks 예제

ML / machine learning


Recurrent Neural Networks, RNN


관련글 :  The Unreasonable Effectiveness of Recurrent Neural Networks


원본 소스 : https://gist.github.com/karpathy/d4dee566867f8291f086

python 3 버전

# encoding=utf8

"""
Minimal character-level Vanilla RNN model. Written by Andrej Karpathy (@karpathy)
BSD License
"""
import numpy as np
import codecs

# data I/O
with codecs.open('input.txt', 'r', encoding='utf-8') as fp:
    data = fp.read()
    # data = open('input.txt', 'r').read() # should be simple plain text file
    chars = list(set(data))
    data_size, vocab_size = len(data), len(chars)
    print ('data has %d characters, %d unique.' % (data_size, vocab_size))
    char_to_ix = { ch:i for i,ch in enumerate(chars) }
    ix_to_char = { i:ch for i,ch in enumerate(chars) }

    # hyperparameters
    hidden_size = 100 # size of hidden layer of neurons
    seq_length = 25 # number of steps to unroll the RNN for
    learning_rate = 1e-1

    # model parameters
    Wxh = np.random.randn(hidden_size, vocab_size)*0.01 # input to hidden
    Whh = np.random.randn(hidden_size, hidden_size)*0.01 # hidden to hidden
    Why = np.random.randn(vocab_size, hidden_size)*0.01 # hidden to output
    bh = np.zeros((hidden_size, 1)) # hidden bias
    by = np.zeros((vocab_size, 1)) # output bias

    def lossFun(inputs, targets, hprev):
      """
      inputs,targets are both list of integers.
      hprev is Hx1 array of initial hidden state
      returns the loss, gradients on model parameters, and last hidden state
      """
      xs, hs, ys, ps = {}, {}, {}, {}
      hs[-1] = np.copy(hprev)
      loss = 0
      # forward pass
      for t in range(len(inputs)):
        xs[t] = np.zeros((vocab_size,1)) # encode in 1-of-k representation
        xs[t][inputs[t]] = 1
        hs[t] = np.tanh(np.dot(Wxh, xs[t]) + np.dot(Whh, hs[t-1]) + bh) # hidden state
        ys[t] = np.dot(Why, hs[t]) + by # unnormalized log probabilities for next chars
        ps[t] = np.exp(ys[t]) / np.sum(np.exp(ys[t])) # probabilities for next chars
        loss += -np.log(ps[t][targets[t],0]) # softmax (cross-entropy loss)
      # backward pass: compute gradients going backwards
      dWxh, dWhh, dWhy = np.zeros_like(Wxh), np.zeros_like(Whh), np.zeros_like(Why)
      dbh, dby = np.zeros_like(bh), np.zeros_like(by)
      dhnext = np.zeros_like(hs[0])
      for t in reversed(range(len(inputs))):
        dy = np.copy(ps[t])
        dy[targets[t]] -= 1 # backprop into y. see http://cs231n.github.io/neural-networks-case-study/#grad if confused here
        dWhy += np.dot(dy, hs[t].T)
        dby += dy
        dh = np.dot(Why.T, dy) + dhnext # backprop into h
        dhraw = (1 - hs[t] * hs[t]) * dh # backprop through tanh nonlinearity
        dbh += dhraw
        dWxh += np.dot(dhraw, xs[t].T)
        dWhh += np.dot(dhraw, hs[t-1].T)
        dhnext = np.dot(Whh.T, dhraw)
      for dparam in [dWxh, dWhh, dWhy, dbh, dby]:
        np.clip(dparam, -5, 5, out=dparam) # clip to mitigate exploding gradients
      return loss, dWxh, dWhh, dWhy, dbh, dby, hs[len(inputs)-1]

    def sample(h, seed_ix, n):
      """ 
      sample a sequence of integers from the model 
      h is memory state, seed_ix is seed letter for first time step
      """
      x = np.zeros((vocab_size, 1))
      x[seed_ix] = 1
      ixes = []
      for t in range(n):
        h = np.tanh(np.dot(Wxh, x) + np.dot(Whh, h) + bh)
        y = np.dot(Why, h) + by
        p = np.exp(y) / np.sum(np.exp(y))
        ix = np.random.choice(range(vocab_size), p=p.ravel())
        x = np.zeros((vocab_size, 1))
        x[ix] = 1
        ixes.append(ix)
      return ixes

    n, p = 0, 0
    mWxh, mWhh, mWhy = np.zeros_like(Wxh), np.zeros_like(Whh), np.zeros_like(Why)
    mbh, mby = np.zeros_like(bh), np.zeros_like(by) # memory variables for Adagrad
    smooth_loss = -np.log(1.0/vocab_size)*seq_length # loss at iteration 0
    while True:
      # prepare inputs (we're sweeping from left to right in steps seq_length long)
      if p+seq_length+1 >= len(data) or n == 0: 
        hprev = np.zeros((hidden_size,1)) # reset RNN memory
        p = 0 # go from start of data
      inputs = [char_to_ix[ch] for ch in data[p:p+seq_length]]
      targets = [char_to_ix[ch] for ch in data[p+1:p+seq_length+1]]

      # sample from the model now and then
      if n % 100 == 0:
        sample_ix = sample(hprev, inputs[0], 200)
        txt = ''.join(ix_to_char[ix] for ix in sample_ix)
        print ('----\n %s \n----' % (txt, ))

      # forward seq_length characters through the net and fetch gradient
      loss, dWxh, dWhh, dWhy, dbh, dby, hprev = lossFun(inputs, targets, hprev)
      smooth_loss = smooth_loss * 0.999 + loss * 0.001
      if n % 100 == 0: print ('iter %d, loss: %f' % (n, smooth_loss)) # print progress
      
      # perform parameter update with Adagrad
      for param, dparam, mem in zip([Wxh, Whh, Why, bh, by], 
                                    [dWxh, dWhh, dWhy, dbh, dby], 
                                    [mWxh, mWhh, mWhy, mbh, mby]):
        mem += dparam * dparam
        param += -learning_rate * dparam / np.sqrt(mem + 1e-8) # adagrad update

      p += seq_length # move data pointer
      n += 1 # iteration counter 
fdsfds


결과

무한 loop 이라, 적정한 시점에 알아서 멈추면 된다.

아래 결과는 대략 12시간 정도를 돌렸다. 컴퓨터 스펙은 아래와 같다.

  • CPU:  i7-6700, 3.40GHz
  • RAM: 16GB
----
 beahngy
amo k ns aeo?cdse nh a taei.rairrhelardr nela haeiahe.
Ddelnss.eelaishaner” cot AAfhB ht ltny
ehbih a”on bhnte ectrsnae abeahngy
amo k ns aeo?cdse nh a taei.rairrhelardr nol e iohahenasen
----
iter 9309400, loss: 0.000086
----
 e nh a taei.rairrhelardr naioa aneaa ayio pe e bhnte ayio pe e h’e btentmuhgehi bcgdltt. gey heho grpiahe.
Ddelnss.eelaishaner” cot AAfhB ht ltny
ehbih a”on bhnte ectrsnae abeahngy
amo k ns aeo?cds
----
iter 9309500, loss: 0.000086
----
 jCTCnhoofeoxelif edElobe negnk e iohehasenoldndAmdaI ayio pe e h’e btentmuhgehi bcgdltt. gey heho grpiahe.
Ddelnss.eelaishaner” cot AAfhB ht ltny
ehbih a”on bhnte ectrsnae abeahngy
amo k ns aeo?cds
----
iter 9309600, loss: 0.000086
----
 negnk e iohehasenoldndAmdaI ayio pe e h’e btentmuhgehi bcgdltt. gey heho grpiahe.
Ddelnss.eelaishaner” cot AAfhB ht ltny
ehbih a”on bhnte ectrsnae abeahngy
amo k ns aeo?cdse nh a taei.rairrhelardr
----
iter 9309700, loss: 0.000086
----
 aI ayio pe e h’e btentmuhgehi bcgdltt. gey heho grpiahe.
Ddelnss.eelaishaner” cot AAfhB ht ltny
ehbih a”on bhnte ectrsnae abeahngy
amo k ns aeo?cdse nh a taei.rairrhelardr neli ae e angnI hyho gben
----
iter 9309800, loss: 0.000086
----
 gehi bcgdltt. gey heho grpiahe.
Ddelnss.eelaishaner” cot AAfhB ht ltny
ehbih a”on bhnte ectrsnae abeahngy
amo k ns aeo?cdse nh a taei.rairrhelardr nela dr iohecgrpiahe.
Ddelnss.eelaishaner” cot AA
----
iter 9309900, loss: 0.000086
----
 piahe.
Ddelnss.eelaishaner” cot AAfhB ht ltny
ehbih a”on bhnte ectrsnae abeahngy
amo k ns aeo?cdse nh a taei.rairrhelardr nol e iohahenasenese hbea bhnte ectrsnae abeahngy
amo k ns aeo?cdse nh a t
----
iter 9310000, loss: 0.000086
----
 er” cot AAfhB ht ltny
ehbih a”on bhnte ectrsnae abeahngy
amo k ns aeo?cdse nh a taei.rairrhelardr nela hamnaI ayio pe e h’e btentmuhgnhi beahe
Ddabealohe bee amoi bcgdltt. gey heho grpiahe.
Ddeln
----
iter 9310100, loss: 0.000086
----
 bih a”on bhnte ectrsnae abeahngy
amo k ns aeo?cdse nh a taei.rairrhelardr nol gyio pe e h’e btentmuhgehi bcgdltt. gey heho grpiahe.
Ddelnss.eelaishaner” cot AAfhB ht ltny
ehbih a”on bhnte ectrsnae
----
iter 9310200, loss: 0.000086
----
 beahngy
amo k ns aeo?cdse nh a taei.rairrhelardr ntlhnegnns. e
amo k ns aeh?cdse nh a taei.rairrhelardr nol e iohehengrpiahe.
Ddelnss.eelaishaner” cot AAfhB ht ltny
ehbih a”on bhnte ectrsnae abeah
----
iter 9310300, loss: 0.000086
----
 e nh a taei.rairrhelardr nol’e btentmuhgehi gcdslatha arenbggcodaeta tehr he ni.rhelaney gehnha e ar i ho  bee amote ectrsnae abeahngy
amo k ns aeo?cdse nh a taei.rairrhelardr nol nyio chge heiohecgr
----
iter 9310400, loss: 0.000086
----
 jCTCnhoofeoxelif edElobe negnk e iohehasenoldndAmdaI ayio pe e h’e btentmuhgehi bcgdltt. gey heho grpiahe.
Ddelnss.eelaishaner” cot AAfhB ht ltny
ehbih a”on bhnte ectrsnae abeahngy
amo k ns aeo?cds
----
iter 9310500, loss: 0.000086
----
 negnk e iohehasenoldndAmdaI ayio pe e h’e btentmuhgehi bcgdltt. gey heho grpiahe.
Ddelnss.eelaishaner” cot AAfhB ht ltny
ehbih a”on bhnte ectrsnae abeahngy
amo k ns aeo?cdse nh a taei.rairrhelardr
----
iter 9310600, loss: 0.000086
----
 aI ayio pe e h’e btentmuhgehi bcgdltt. gey heho grpiahe.
Ddelnss.eelaishaner” cot AAfhB ht ltny
ehbih a”on bhnte ectrsnae abeahngy
amo k ns aeo?cdse nh a taei.rairrhelardr nelardae abeahngy
amo k
----
iter 9310700, loss: 0.000086
----
 gehi bcgdltt. gey heho grpiahe.
Ddelnss.eelaishaner” cot AAfhB ht ltny
ehbih a”on bhnte ectrsnae abeahngy
amo k ns aeo?cdse nh a taei.rairrhelardr ntl negnk t hi rsnse nhk br ne” a naeiarairr elirs
----
iter 9310800, loss: 0.000086
----
 piahe.
Ddelnss.eelaishaner” cot AAfhB ht ltny
ehbih a”on bhnte ectrsnae abeahngy
amo k ns aeo?cdse nh a taei.rairrhelardr nelardaenabeahngelareierhi. aif edElobe negrcih gey gey heho grpiahe.
Ddel
----



[컴] app 에서 firebase 사용하기

파이어베이스 / fire base /


Firebase 를 app 에서 사용하기

자세한 내용은 여기 를 참고 하자.
  1. firebase project 생성
  2. app 등록
    1. 앱 닉네임 등록 : 자신의 app 이름을 적자
    2. 그러면 아래 같은 code 를 얻게 된다.
  3. sdk 를 app 에 설치 후 initialize
<!-- The core Firebase JS SDK is always required and must be listed first -->
<script src="https://www.gstatic.com/firebasejs/6.6.2/firebase-app.js"></script>

<!-- TODO: Add SDKs for Firebase products that you want to use
     https://firebase.google.com/docs/web/setup#available-libraries -->

<script>
  // Your web app's Firebase configuration
  var firebaseConfig = {
    apiKey: "AsdfDQ3uOXYZp_MrNQPSauO4sdfsPn4OU8",
    authDomain: "coreal.firebaseapp.com",
    databaseURL: "https://coreal.firebaseio.com",
    projectId: "coreal",
    storageBucket: "",
    messagingSenderId: "997454353605",
    appId: "1:997454353605:web:5354b7543a6d9e68fdcad2"  };
  // Initialize Firebase
  firebase.initializeApp(firebaseConfig);
</script>


관련 에러

app 등록을 안하면 아래같은 warning 이 보인다.

@firebase/database: FIREBASE WARNING: Provided authentication credentials for the app named "[DEFAULT]" are invalid. This usually indicates your app was not initialized correctly. Make sure the "credential" property provided to initializeApp() is authorized to access the specified "databaseURL" and is from the correct project.




[컴][js] nodejs 에서 euc-kr 인코딩 사용법

한글 사용법 / euc-kr / mbcs / convert encoding / decoding / 인코딩 변경 방법 / nodejs / node / 노드에서 인코딩 변경 / euckr / korean / utf8 / 한글파일 읽기 / 한글 읽는 법 / 파일 읽기 / read 하는 법 / write 하는 법 / euc-kr 읽기 /euckr 읽기 / euc kr excel / 엑셀 읽기

nodejs 에서 euc-kr 인코딩 사용법

iconv

iconv 를 설치하려면 build 환경(native code compilation)이 구성되어야 한다.

npm i iconv

iconv-lite

이녀석은 순수 js 로 구성되었다. README 에서는 어떤 경우에는 iconv 보다 빠르다고 이야기 한다.

npm i iconv-lite

사용법

아래처럼 사용할 수 있다.

const iconv = require('iconv-lite');


const stream = fs.createWriteStream(filename);
const header = ['이름', '주소'];

const buf = iconv.encode(header.join(','), 'euc-kr');
stream.write(buf);
stream.end();

euc-kr 로 된 file을 read 할 때는 아래처럼 하면 된다.


import * as fs from 'fs';
import iconv from 'iconv-lite'

try {
    // readFileEncoding
    const data = await fs.promises.readFile(inputPath)
    const utf8Data = iconv.decode(data, 'euc-kr')
    console.log(utf8Data)
} catch (err) {
    return console.error('Error reading file:', err);
}

References

  1. node-iconv git : GitHub - bnoordhuis/node-iconv: node.js iconv bindings - text recoding for fun and profit!
  2. GitHub - ashtuchkin/iconv-lite: Convert character encodings in pure javascript.

[컴] 메신저 별 서버 저장 기간

카톡 / 라인 / 서버 보관 / 대화내용 보관 기간

한국 메신저 대화내용 서버 보관기간

2014년 기준이여서 2019년 현재에는 달라졌을 수 있다. 참고 수준으로 알아두자.


  • 카카오톡 
    • 서버 데이터 저장기간을 2~3일 정도로 줄이기로 결정. (스크린샷 참고)
    • 서버에 보관이 안되기 때문에 누군가의 폰에 대화내용이 남아있지 않다면, 과거 대화는 복구할 수 없다.
  • 라인 : 타이머챗을 이용한 대화와 일반 대화내용은 암호화된 상태로 서버에 저장
    • 라인 '타이머챗' 기능 : 수신자가 메시지를 확인한 이후부터 최소 2초, 최장 1주일 뒤에 메시지가 자동 삭제된다. 그 순간 서버에 저장돼 있던 메시지도 사라진다.
    • 하지만 암호키가 저장된 위치와 서버 저장기간을 공개하지 않고 있다. 라인 측은 "서버 저장기간은 최소한의 기간으로 정확한 기간은 대외비"라며 "암호키의 저장위치 역시 공개할 수 없다".
  • SK플래닛 미국법인 틱톡플래닛의 '프랭클리'
    • 프랭클리 수신자가 메시지를 확인한 뒤 10초가 지나면 발신자와 수신자의 스마트폰은 물론 서버에서 메시지가 자동 삭제
  • 네이트온 : 6개월
    • 사용자가 메시지를 삭제하면 그 즉시 서버에서 메시지가 삭제
  • 마이피플 : 3개월
    • 사용자가 메시지를 삭제하면 그 즉시 서버에서 메시지가 삭제


Screenshots

카카오톡: https://cs.kakao.com/helps?articleId=470002560&service=8&category=24&device=1&locale=ko



References

  1. 카톡 아닌 메신저, 대화는 며칠이나 보관?, 2014.10.10

[컴][js] AdonisJS v3 ---> v4 에서 Encryption 문제

암호화 문제 / 마이그레이션 / encryption / simple encrypt /

Encryption (AdonisJS v3.x --> AdonisJS v4.x migration)

최신버전의 Adonis Encryption/index.js 에서 보면 아래처럼 Encryptor 를 호출할 때 object 를 parameter 로 보낸다.

하지만 옛버전의 Adonis Encryption/index.js 를 보면 그냥 string 을 parameter 로 넘긴다.

// latest version
// <root>\node_modules\@adonisjs\framework\src\Encryption\index.js
const Encryptor = require('simple-encryptor')
...
class Encryption {
  constructor (appKey, options) {
    /**
     * Throw exception when app key doesn't exists.
     */
    if (!appKey) {
      throw GE.RuntimeException.missingAppKey('Encryption')
    }
    this.appKey = appKey
    this.encryptor = Encryptor(Object.assign({ key: appKey }, options))
  }
  ...
// old version
// <root>\node_modules\@adonisjs\framework\src\Encryption\index.js
const Encryptor = require('simple-encryptor')
...
class Encryption {
  constructor (Config) {
    const appKey = Config.get('app.appKey')

    /**
     * Throw exception when app key doesn't exists.
     */
    if (!appKey) {
      throw GE.RuntimeException.missingAppKey('Encryption')
    }

    this.encryptor = Encryptor(appKey)
  }
  ...

simple-encryptor 의 option 이 변경된다.

이로 인해 발생하는 문제는 simple-encryptor 의 default option 이 변경된다.
// simple-encryptor
module.exports = function(opts) {
  if( typeof(opts) == 'string' ) {
    opts = {
      key: opts,
      hmac: true,
      debug: false
    };
  }
  var key = opts.key;
  var verifyHmac = opts.hmac;
  var debug = opts.debug;
  var reviver = opts.reviver;
  ...

해결책

그래서 혹시 이전의 option 을 사용하려 한다면 자신의 AppProvider 를 만들어서 사용해야 할 듯 하다. 아래 소스를 참고하자.
그리고 app.js 에 등록만 해주면 된다. 아래 글을 참고하면 된다.

[컴][nodejs] nodejs 의 crypto module 사용시 주의점



nodejs 의 crypto module 사용시 주의점

nodejs version 과 openssl


대략적으로 NodeJS 는 자체적으로 OpenSSL 을 포함하고 있다.(code)

아래 링크를 가면, nodejs version 에 따른 openssl 버전을 확인할 수 있다.

crypto module 사용시 주의점

How to use the crypto module | Node.js 를 보면 crypto 모듈은 openssl 를 이용한다. 그래서 openssl version 의 특별한 변화가 생기면, nodejs 의 openssl 도 영향을 받는다.

md5 --> sha256,  openssl version 1.1.0

openssl version 이 1.1.0 으로 올라가면서 기본 digest algorithm 이 md5 에서 sha256 으로 변경됐다.

nodejs 에서 openssl version 을 1.1.x 로 옮긴 것은 nodejs 의 version 이 10.0.0 이 된 순간이다.(참고)

그러므로, v10 미만을 사용할 때와 v10 이상을 사용할 때 만약 crypto module 을 사용하고 있다면 주의가 필요하다.

error

OpenSSL 1.0.x 버전에서 얻은 값을 OpenSSL 1.1.x 로 decrypt 를 시도하면 아래와 같은 error 가 발생한다.

error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt

알고리즘 선택

아래 처럼 algorithm 을 명시해주는 것이 나을 수 있다.
var cryptoKey = crypto.createHash('sha256').update(key).digest();

crypto 사용 예제

See Also

  1. 쿠...sal: [컴][알고리즘] AES 암호화 설명

[컴] git flow 자료들

gitflow / git flow 처음 시작 / git clone 후 git flow 적용 /



git flow

Extensions for Visual Studio Code

Git flow cheat sheet

git flow 를 사용하는 git repository 를 사용

1. git clone https://<git-address>

git clone 으로 source 를 가져온다.

2. git flow init

Which branch should be used for bringing forth production releases?
   - develop
   - master
Branch name for production releases: [master]

Which branch should be used for integration of the "next release"?
   - develop
Branch name for "next release" development: [develop]

How to name your supporting branch prefixes?
Feature branches? [feature/]
Bugfix branches? [bugfix/]
Release branches? [release/]
Hotfix branches? [hotfix/]
Support branches? [support/]
Version tag prefix? []
Hooks and filters directory? [C:/a/prog/mainsource/.git/hooks]

git flow feature 사용

3. git flow feature start

git flow feature start 를 이용해서 feature branch 를 만들 수 있다. 이때 어느  branch 에서 만들어도 develop branch에서 만들어준다.

4. git flow feature rebase

base 를 develop branch 의 최신 상태로 rebase 해준다.(참고)

5. git flow feature finish

현재 feature 를 develop branch 에 merge 를 해주고 --> branch 를 없애고 --> develop branch 로 돌아간다.




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

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

[컴] 안드로이드 폰 광고ID 재설정

galaxy / android / 안드로이드 폰 광고 아이디 설정


광고 ID 재설정

  • 갤럭시 기준
  • 설정 --> Google --> 광고 --> 광고 ID 재설정



광고 ID 재설정이 필요한 이유

이 ID 가 웹등에 접속할 때 내가 누군인지를 구분해주는 역할을 하게 된다. 그렇기에 주기적으로 이것을 변경해주면, 어느정도의 익명성이 보장될 수 있다.(하지만 당연하게도, 완벽한 익명성을 보장하진 않는다.)



[컴][js] OpenSSL hmac in NodeJS

노드에서 hmac 사용 / open ssl / openssl hmac 사용법 / 노드제이에스 / node js

OpenSSL hmac in NodeJS


ref. 1 과 ref. 2 를 참고하면 대략적으로 사용법을 알 수 있다.

const crypto = require('crypto');
const hmac = crypto.createHmac('sha256', 'a secret');

hmac.update('some data to hash');
console.log(hmac.digest('hex'));


References

  1. crypto.createHmac
  2. crypto_class_hmac


[컴][js] AdoniJS 에서 큰 DB data 를 retrieve 할 때

chunk / big data / adonijs lucid big data / database cursor / adonis 에서 cursor 사용방법 / db query / size / big size / 쿼리 / node query / how to handle big query result


AdonisJS Lucid 에서 stream 사용

AdonisJS-lucid 의 사용에서 큰 결과 값을 갖는 query 를 다룰 때 stream 을 사용하면 된다. 일반적인 cursor 의 사용이라고 생각하면 될 듯 하다.

AdonisJS Lucid 의 문서에서는 찾기가 힘들었는데, community 에서 자료를 찾았다.(ref. 1)

내용을 정리하면, Lucid는 KnexJS 를 사용하고 있고, KnexJS 에서 streams 를 제공한다. 그것의 사용법은 아래와 같다.

아래 stream 의 예제는 ref. 1 을 참고해서 만들었다.

const ccursor =
  Database.connection('cocktail')
    .raw(
      `SELECT * FROM point AS t1 WHERE t1.id !='tester'
      ORDER BY id ASC`
    ).stream()
  
const prom = new Promise((resolve, reject)=>{
    Logger.error('test2');
    ccursor.on('data', (row)=>{
      Logger.info('test-data');
    })
    ccursor.on('end', () => {
      Logger.info('test-data');
      resolve()
    })
    ccursor.on('error', (param1) => {
      Logger.error('test-error : ' + param1);
      reject()
    })
});
await prom.then((val)=>{
    Logger.info('test-resolve');
}).catch((val)=>{
    Logger.error('test-reject');
});


위의 code 를 실행하면 Logger.info('test-data'); 가 계속 실행되다가 끝날때 Logger.info('test-data'); 가 실행될 것이다.

또는 아래처럼 작성해도 된다.
const prom = new Promise((resolve, reject)=>{
  const ccursor =
    Database.connection('cocktail')
      .raw(
        `SELECT * FROM g5_point AS t1 WHERE t1.mb_id !='admin'
        ORDER BY po_id ASC`
      ).stream();
  ccursor.on('data', (row)=>{
    Logger.error('test-data');
  })
  ccursor.on('end', () => {
    Logger.error('test-end');
    resolve()
  })
  ccursor.on('error', (param1) => {
    Logger.error('test-error : ' + param1);
    reject()
  })
});
await prom.then((val)=>{
  Logger.error('test-resolve');
}).catch((val)=>{
  Logger.error('test-reject');
});


async

아래처럼 async 를 사용할 수 있다.

const prom = new Promise(async (resolve, reject)=>{
  const ccursor =
    Database.connection('cocktail')
      .raw(
        `SELECT * FROM g5_point AS t1 WHERE t1.mb_id !='admin'
        ORDER BY po_id ASC`
      ).stream();
  ccursor.on('data', async (row)=>{
    Logger.error('test-data');
  })
  ccursor.on('end', async () => {
    Logger.error('test-end');
    resolve()
  })
  ccursor.on('error', async (param1) => {
    Logger.error('test-error : ' + param1);
    reject()
  })
});
await prom.then((val)=>{
  Logger.error('test-resolve');
}).catch((val)=>{
  Logger.error('test-reject');
});



아직은 사용하기가 쉽지 않다. 그리고 await/async 와 잘 맞지 않아 보인다. 그래서 자꾸 memory 가 넘치는 듯 하다.

개인적으로 현재로서는 그냥 offset, limit 을 이용해서 일정부분만 retrieve 해서 가져와서 사용하고, 다시 또 일정부분을 가져와서 사용하는 방식이 더 나아 보인다.



See Also

  1. laravel 에서 큰 Database result 를 처리할 때

References

  1. A Way to process large results of database Query in Adonis without consuming too much RAM - Help / Database - Forum - AdonisJS Framework
  2. Knex.js - A SQL Query Builder for Javascript


[컴] 클라우드 플레어 의 문제에 대한 투명한 대처

cloudflare/  투명 / 진단 결과 / 문제 발표 문제해결 / 클라우드 / 플래어 / 플레어 / 소통 / 정확한 / 투명한 / 응답 / 대답 / 고객과의 소통 / 보스 이어폰 /

클라우드 플레어 의 문제에 대한 투명한 대처

7월 2일에 클라우드플레어가 멈췄다.(outage) 이와 관련해서 자세한 내용을 공개했다.
내용의 이해를 떠나서 문제에 대한 투명한 공개의 좋은 예

See Also

  1. Bose QC 35 Firmware 4.5.2 Noise Cancellation Inves... - Bose Community - 285738, 2020-04-02 : Bose 에서 Noise Cancellation 관련 고객들의 의견에 대한 답변, 자세한 분석,