OmniAICreator/Qiita-1.07M huggingface dataset:
今更ながら（Yet Another）JavaでVoIPするためのライブラリ

## はじめに
Minecraftのmod開発に手を出してあれやこれやしてましたが、寄り道してJavaでのVoIPについて色々格闘してました。せっかくなので記事にしてまとめてみようと思います。今更JavaでVoIPなんて。。となる人も多いかもですが、その分逆に情報量が少なかったので参考になれば。目的はもちろんmodでの活用なので色々制限のある中での探検となりました。。
<font color="red">※色々調べはしたもののにわか知識のところもあるので誤りがあったらごめんなさい。。（指摘してもらえると後学のためになる＆訂正します）</font>

## 調べたり試したりしたライブラリ

### JMF(Java Media Framework)

Javaの開発元（当時のSUN）に正式にJavaに取り込まれたメディアフレームワークで、RTPの実装もあります。今も[こちら](https://www.oracle.com/java/technologies/javase/java-media-framework.html)から入手可能な模様。ただ、[Wikipedia](https://ja.wikipedia.org/wiki/Java_Media_Framework)など読むとわかりますが、特にSUNのOracleによる買収後はまともにメンテもされていないらしく、ほぼオワコン感が。。
OpenJDKには含まれていないし、再頒布を前提としたOSS開発で利用するにはちょっとなぁ。。というわけで選択肢から除外。

### FMJ(Freedom for Media in Java)

名前からしてJMFに対抗する気満々のOSSライブラリ。使い物になるなら選択肢かなぁ。。と思いましたがこの[公式サイト？](http://fmj-sf.net/)を見て一気に萎えました。サイトのデザインからしてオワコン感がありますが、おまけにサイト下部にLast Updateが2007年とか書いてあるし。こりゃ今の環境で動くかどうかすらあやしいな、ということでいったんスルーしました。（実は後に戻ってくることになりますが）

### efflux

その後githubのリポジトリを色々探検することに。できるだけ☆の多いやつをたどってみましたがそこで見つけたのがこいつ。しかし。。。リポジトリの最終更新を見ると11 years ago...。スターウォーズかよ。で、依存関係を見てもnettyとか書いてあるし。。。
このライブラリはgithubからcloneしてビルドしようと試みたのですがうまくいかず、使い物にならん！とレッテルを張って封印しました。おそらくもうちょっとがんばったら使えたかもですが、今後メンテされる可能性もまずなさそうだし。。。個人の趣味で作られたライブラリっぽかったし。。

### JVoIP

よくできてました。サイトは[こちら](https://www.mizu-voip.com/Software/SIPSDK/JavaSIPSDK.aspx)。この子も落としてきて動かしてみたけど、ちゃんとネットワーク越しに会話ができるところまで確認。何よりも、ライブラリとしてとことんシンプルに作られているところが好感が持てますね。mavenリポジトリから落としてこれるようになっててもいいと思うけど、この子はjarファイル1個で完結してて、そのjarをクラスパスに通せば動きました。
核となるクラスがAppletを拡張して作られていたため、動かす時にちょっと苦労しましたがサポートに問い合わせたところ（英語）Applet非依存なライブラリも作られていて、当時未公開でしたが先行してそのバージョンを提供してもらい、無事にApplet非依存なライブラリとして動作させることもできました。
ただ。。。最大の難点は有償。。。ちょっと試しに動かしてみる分には無償でダウンロードできますが、再頒布する際にはライセンスの問題を解決する必要あり。無償公開のOSS開発をしようとしている身としては超えられない敷居だったのでGive upしました。。よくできてますけどね。ライセンス費も決して高くないので企業ユースなら検討してもよいかも？

### Asterisk-Java

VoIP、SIPと言えばAsteriskでしょう。。ということでJavaの実装は無いんかな～と思って調べて見つかったのが[こちら](https://asterisk-java.org/)　お！！と思ったけど、ただのAsteriskのWrapperでAsterisk自体、Windowsで動かそうと思ったらcygwinを入れてゴリゴリ。。なんて必要があるみたいなので今回の目的からするとNG。というわけで終了。。。

### Android向けライブラリ

途中過程で色々Android向けのライブラリはヒットしました。ただ、今回はWindowsやらで動くJava版Minecraftでの利用が最終ゴールなのでそれらはすべてスルーしました。。ひょっとしたらWindows上でも使えるのかもしれないけど。まぁ、後述するようにひとまず動かせるライブラリは見つけたので、Androidアプリを開発することにならない限りそれらのライブラリに戻ってくることはないでしょう。

### libjitsi

githubの☆も多かったので実はもっと前に見つけていましたが、最終的にたどり着いたのがこれ。[Jitsi Meet](https://meet.jit.si/)なるOSSをベースとした無償テレカンサービスのライブラリで、VoIP以外にもWebカメの画像も飛ばせます。Jitsi Meet自体は使ったことが無いのでわからないですが、何かで課金するサービスなのかも？
とにかく、このJitsi Meet用に開発されたライブラリのlibjitsiはOSSとして[github](https://github.com/jitsi/libjitsi)でも公開されてます。libjitsi自体はそこまで更新頻度が高くないものの、それを使っているJitsi Meetはちゃんとメンテされており、libjitsiの更新頻度が低いのはほぼ枯れているからかな～と思います（とは言えこの記事執筆中の最終更新は4日前）。
ちなみにこのlibjitsi、使おうとしてわかったんですが前述のFMJを使ってます。よく見ると[FMJの公式サイト？](http://fmj-sf.net/)にJitsiのロゴが。。。どうやらJitsiの開発者によって陰でメンテされている模様。。

ようやくOSSでそれなりにメンテされているライブラリに巡り会えました。ただこのライブラリの最大の難点は。。。ドキュメントがほとんどねー。サンプルコードがついてますがほんのごく一部の機能しか使ってないし、動かすだけでも軽く１週間以上ハマり、ある程度やりたいことをやれるようになるまで理解するのに１カ月近く費やしました。。Javadocと不親切なサンプルコード、コミュニティのQ&Aをググりまくり、それでも解決しなければソースを読む覚悟がないと使えまへん。

また今度libjitsiの使い方についても記事にしたいと思いますが、ひとまず私がやりたいことは一通りこのライブラリでできるようになった（なってきた）のでこのライブラリで色々遊んでみようと思います。
Teams業務効率化まとめ

#Web受付システム

https://note.com/mei_math/n/n8721dc3711aa

#Q&Aシステム

https://mynote365.hatenadiary.com/entry/2020/08/25/191151

#Bot開発

https://qiita.com/chomado/items/6bda10abde0551f25723

#Planner一斉タスク登録　アプリ開発
https://www.softbanktech.co.jp/special/blog/cloud_blog/2020/0067/

https://www.softbanktech.co.jp/special/blog/cloud_blog/2020/0071/
整数型オブジェクト

### idとctypesを用いてメモリの中を確認
Pythonで `a = 10` と変数に値を代入したとき、次のように動作する。
1. メモリ上の番地 0x555f73c4bb20 にオブジェクトとしての数値 10 が格納される
2. 変数 a がメモリ上の番地 0x555f73c4bb20 を参照する

```python
a = 10
# id関数でメモリの番地が分かる # https://docs.python.org/2/library/functions.html#id
print(id(a)) # 93868452526880　10進数のメモリ番地
print(hex(id(a))) # 0x555f73c4bb20 16進数のメモリ番地
```

なお、-5〜256の整数はPythonを起動したときにメモリ上に乗せられるのでステップ1が省略される。この範囲である理由はおそらく使用頻度が高いから。以下のidの逆関数を用いることで-5〜256の整数のidが等間隔(32ずつ)になっており、あらかじめメモリに乗っていることが確認できる。

```python
import ctypes
# idの逆関数でメモリの番地からデータを取得できる
bi = lambda x:ctypes.cast(x, ctypes.py_object).value
# id番号からデータを取ってくる
bi(id(10) + 32) # 11
```

32ずつの間隔について気になったため、メモリ上でどのようにオブジェクトを配置しているのかを調べてみる。
まず、メモリとは次のような構成になっており、1つの番地に1byteを格納できる。
たいていは、オブジェクトに関する情報とともに、複数の番地にまたがって値を格納することになる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614092/091a2bbd-2b9d-f58e-091b-38abd0538cb4.png)

オブジェクトがメモリ空間上でいくつの番地（何バイト)を専有しているかを次のように調べた。

```python
import sys

# sys.getsizeof()でbyte数を確認できる
# https://docs.python.org/3/library/sys.html#sys.getsizeof
print(sys.getsizeof(10)) # 28byte
print(sys.getsizeof(2**30 - 1)) # 28byte
print(sys.getsizeof(2**30)) # 32byte
print(sys.getsizeof(2**60 - 1)) # 32byte
print(sys.getsizeof(2**60)) # 36byte
print(sys.getsizeof("")) # 49byte 文字列型の初期化は49バイト
print(sys.getsizeof("a")) # 50byte
print(sys.getsizeof("ai")) # 51byte
print(sys.getsizeof("1")) # 50byte
print(sys.getsizeof("あ")) # 76byte 日本語だと初期バイトが26増える
print(sys.getsizeof("あい")) # 78byte 一文字につき2バイト増える
print(sys.getsizeof("漢")) # 76byte
print(sys.getsizeof("漢字")) # 78byte 一文字につき2バイト増える
```

「整数の10なんか1byteで収まるやんけ、なんで28byteも使ってるんだ、28bitの間違いでは？」と思ったが、オブジェクトととしての数値は、単なる数ビットの数値という以外にも、色んな機能を持っているから28byteもかかっているのだろう。
自分のPCはメモリが8GBで8,000,000,000個くらいの番地があるため、1つの値に50byteかかるとすると、160,000,000個までの値をメモリに乗せることができる。

試しに以下のコードを実行すると、がっつりフリーズした。

```python
over_list = list(range(10**9))
```


### CPUとレジスタ、メモリの動作
プログラムを実行すると、ソースコードはコンピュータが理解しやすい「機械語」へと翻訳される。（Pythonの場合は一行ずつ翻訳するインタープリタ方式で、C言語は全体をまとめて翻訳するコンパイル方式）
また、CPUの内部にはレジスタと呼ばれる、メモリと比べると小さいが、CPUの演算装置に直結した記憶回路がある。（メモリの番地の数は数十億個で、レジスタは数十個）
メモリはRAMというコンデンサベースの回路、レジスタはフリップフロップというトランジスタベースの回路であり、それぞれ利点・欠点があるため、コンピュータはそれを組み合わせて適材適所で利用している。


例えば単純な加算の命令はメモリ・レジスタ・演算装置を用いて次のように4つの命令としてコンピュータで実行される。各命令はメモリに保存されており、メモリの番地順に取り出される。
1. メモリの番地AAAにあるデータをレジスタ1に取ってくる
2. メモリの番地BBBにあるデータをレジスタ2に取ってくる
3. レジスタ1とレジスタ2の値をCPUの演算装置で足してレジスタ3に保存する
4. レジスタ3のデータをメモリ上の番地CCCに保存する


これを踏まえると、ソースコードは以下のように機械語に置き換わる。

```python
a = 1
b = 2
c = a + b

# メモリから a = 1 という命令をCPUが読み取る
# メモリ番地AAAに1を格納
# メモリから b = 2 という命令をCPUが読み取る
# メモリ番地BBBに2を格納
# メモリから c = a + b という命令をCPUが読み取る
# メモリの番地AAAにあるデータをレジスタ1に取ってくる
# メモリの番地BBBにあるデータをレジスタ2に取ってくる
# レジスタ1とレジスタ2の値をCPUの演算装置で足してレジスタ3に保存する
# レジスタ3のデータをメモリ上の番地CCCに保存する
```
rails sエラーの原因がsqliteのバージョン

Puma caught this error: Error loading the 'sqlite3' Active Record adapter. Missing a gem it depends on? can't activate sqlite3 (~> 1.4), already activated sqlite3-1.3.6. Make sure all dependencies are added to Gemfile. (LoadError)


バージョン1.4系しか使えないのに、1.3を使おうとしている。

ということなので、gemfileのsqlite3のバージョンを変更して、

bundle install

をやったら、解決したーー!!!
int()の例外がTypeErrorになるケース、ValueErrorになるケース

int()でstring型をint型に変換したときの例外が、TypeErrorになるケース、ValueErrorになるケースを忘れがちなので、メモとして残します。

## 正常動作
```
int("100")
# 以下もオーバーロードなので正常動作
int(100)
int(1.6) # 1 になる
int(True) # 1 になる
```

## TypeError

- 型が違う
- 引数の数がオーバー

```
int(["100", "101"])
int(None)
int("100", 10, "100")
```

## ValueError

- 型は合っているが、変換できない

```
int("")
int("abc")
```

以下を参考にしました。
https://stackoverflow.com/questions/48343387/valueerror-and-typeerror-in-python
【Vue.js】Vue.jsを使って「おみくじアプリ」を作ってみた

#概要
Vue.jsを使って「おみくじアプリ」を作ってみました。
アプリの挙動は以下の通りです！

![Omikuji App.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1418672/ad8f9951-3913-4771-e446-c72f56849e1e.gif)

#アプリの機能
「あなたの今日の運勢」ボタンを押下すると
大吉、中吉、小吉、末吉、凶のうちのどれかがランダムで表示されます。

そして運勢結果に合わせて[いらすとや](https://www.irasutoya.com)でゲットした画像も表示されます。

#コードの説明
ランダムにおみくじ結果を表示する処理には乱数生成を利用します。

Math.random()の値は0から1までの間をとるため、
その値に配列の長さをかけて小数点以下を切り捨てることにより、
今回の配列の全要素番号である０から４の値をランダムに出力します。

```javascript:script.js
new Vue({
    el: '#app',
    data(){
        return {
          list: ["大吉","中吉","小吉","末吉","凶"],
          result: null
        }
    },
    methods: {
      start: function(){
        const rnd = Math.floor(Math.random() * this.list.length);
        this.result = this.list[rnd];
      }
    }
});
```

上記の処理で詰めたresultの値をHTML側で表示させます。

```html:index.html
<p class="omikuji-result" v-if="result">{{result}}です！</p>
```

また今回作成したアプリのように結果に合わせて画像を表示させる場合は、
以下のように画像を配置してあげてください。

```html:ディレクトリ構成
├── index.html
├── script.js
├── img
     ├── 大吉.png
     └── 中吉.png
     └── 小吉.png
     └── 末吉.png
     └── 凶.png
```

#コード全量
こちらHTML,JSのコードの全量です。

```html:index.html
<head>
    <meta charset="UTF-8" />
    <title>おみくじアプリ</title>
</head>
<body>
  <div id="app">
    <div class="text-area">
      <button class="omikuji-button" @click="start">あなたの今日の運勢</button>
      <p class="omikuji-result" v-if="result">{{result}}です！</p>
      <p v-if="result == '大吉'"><img src="img/大吉.png" class="image"></p>
      <p v-else-if="result == '中吉'"><img src="img/中吉.png" class="image"></p>
      <p v-else-if="result == '小吉'"><img src="img/小吉.png" class="image"></p>
      <p v-else-if="result == '末吉'"><img src="img/末吉.png" class="image"></p>
      <p v-else-if="result == '凶'"><img src="img/凶.png" class="image"></p>
    </div>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script src="script.js"></script>
</body>
<style scoped>
.omikuji-button {
  font-size: 20px;
  padding: 12px 20px;
  border: none;
  -webkit-appearance: none;
  background:#FF66FF;
  color: #eee;
  border-radius: 4px;
}
.omikuji-result {
  color: #444444;
  font-size: 35px;
  font-weight:700; 
}
.text-area {
  text-align: center;
}
.image {
  width: 15%;
	height: auto;
}
</style>
```

```javascript:script.js
new Vue({
    el: '#app',
    data(){
        return {
          list: ["大吉","中吉","小吉","末吉","凶"],
          result: null
        }
    },
    methods: {
      start: function(){
        const rnd = Math.floor(Math.random() * this.list.length);
        this.result = this.list[rnd];
      }
    }
});
```
#参考
[記事「Vue.jsでおみくじアプリを作ってみた」](https://qiita.com/usumarin/items/225c3679713e39f6a966)
Synology DSM7.0betaで早速システム不具合にあたって治った話。

#何が起きたか
Synology D220jをアップデートし新しいPhotosアプリを使ってみたら
システムハングしまっくてNASが使い物にならなくなった。


#ことの経緯
- GooglePhotoがもうすうぐ有償化。
- これを見据えて購入したSynology D220j。
- でもMomentsやDS Photoがやたら使いづらいし２つあって管理が面倒。
- Momentsのアップロードがやたら遅い
- DMS7.0betaで統合写真機能のSynology Photosが使えるのでアップデートしてみた。

#出来事
DSM7.0betaアップデートの話は省略
アップデート後MomentsとDS Photoは使えなくなって自動的にSynology Photosに統合される。

アップデート後iOSアプリをダウンロード
https://apps.apple.com/jp/app/synology-photos/id1484764501?ign-mpt=uo%3D4

いくつかの問題が発生

### 問題１「共有スペースに過去入れたはずの画像がない」
ログインして共有スペースをみてみると何もない。。。
⇨これはアップデート後にNAS上で再インデックス処理が走るらしく私の画像数の場合２日で解消された。

### 問題２「タイムライン表示がおかしい。」
タイムライン表示を見るとNASを購入した２０２１年初旬に過去アップロードした画像が全て集まってしまっている
⇨これもインデックス処理中の問題なのかしばらくしたら何故か解消した。

### 問題３「システムハング」
共有スペースに写真を個別アップロードするとアップロードが終わらず
アプリ上では同じ画像を何度もアップロードするような動きになる
その後NAS側が応答なしに陥りシステムハング。
しばらくするとActiveInsightからメモリ不足エラー検知のメッセージを受信
WEBログインもSSHも出来ないので、NASの物理電源長押しで停止コマンドを送信し再起動

何度やってもこの事象が繰りかえさえれる

#問題３（システムハング）がどうやったらなおったか
ログをとってサポートに連絡したところ、要約すると
「お前のNASはサービスいっぱい立ち上げてるからメモリ不足なんだよ。色々いらないの止めなさいよ」
と言われた

システムハング時はどうなっていたのかが見えないが
これがDSM7.0起動時の状態。46-５０％程度と結構高め。
色々サービスを停止してみたけどこれが限界。
（DSM６．０の時のメモリ使用状況は覚えていないがもっと低かった気がする。）
![スクリーンショット 2021-05-31 0.07.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/518862/b0a82d3d-f50b-8cd5-8e40-e1363c2aa5e3.png)

この状態で再チャレンジしてみたがまたハング。治らない

iOSアプリを見ているとアップロードは全部失敗したように見えるのが
再起動後にNASのWEB画面からSynology PhotosをWEB閲覧すると。。。写真が全部アップロード完了されているではないですか。
さらに試しにWEB上でファイルアップロードすると普通にアップロードされる。

もしやと思い
**iOSアプリを一度削除⇨再インストール**すると
共有スペースにアップロードした画像たちが出てきた。

その後個別アップロードに特に詰まることもなくメモリエラーが出ることもなく普通に使えています。
MomentsやDS Photoよりもずっと使いやすいのでいい感じです。

#まとめ
- Synology Photo移行後の再インデックスが終わるまではアップロードはやめておいた方が良さそう
- 何からの理由でアプリ側と同期がとれなくなってしまう事象が起きるとファイルアップロード時に問題が発生するようにみえる
- 解消するにはiOSアプリを一旦削除してNAS側のインデックス処理が終わってからリトライすると治るかも

もし同じ症状の方がいましたらご参考になれば。
【React】useStateでstateで画面の表示切替する

<h2>useStateとは</h2>

useStateとは状態を管理するものです。
そのステートに任意の値を渡すことで、画面上に別の描画に切り替えることができます。

その方法について書いていきます。

<h2>実装</h2>

```react:useState
//宣言
const [value,setValue] = useState("INITIAL")
```

上記例では、右側の「INITIAL」を左のvalueに代入しています。
左側にあるsetValueはvalueに値を設定する際に使用されるメソッドになります。
実際に使うと下記のようになります

```react:setState
setState(2)
```
このようにステートを更新していきます。
このステートに合わせて画面遷移させていきます。

```react:react
import React,[Fragment,useState] from "react";

export const Sample {
    const [value,setValue] = useState("INITIALIZE");

    useEffect(() => {
      setValue("LOADING")
    })
    
    setValueHandler(){
        setValue("SUCEESS")
    }
    return (
      {
       value === "INITIALIZE"?
       <Fragment>
         状態は#{value}です
         <button onClick={setValueHandler("LOAING")}>LOADING</button>
      </Fragment>
　　　:
      value === "LOADING"?
      <Fragment>
         状態は#{value}です           
         <button onClick={setValueHandler("SUCCESS")}>SUCCESS</button>
      </Fragment>
      :
      <Fragment>
         状態は#{value}です           
         <button onClick={setValueHandler("INITIALIZE")}>INITIALIZE</button>
      </Fragment>
      }
      
)}
```

ソースのreturn以上の個所ではハンドラが書かれています。

ハンドラとは何らかのイベントに対してどのような動作するかをまとめたものです。

```react:react
//useEffectで最初に読み込まれた時のあたいを設定しています
useEffect(() => {
      setValue("LOADING")
    })

//setvalueHandlerではイベントごとに値を設定しなおしています
    setValueHandler(){
        setValue("SUCEESS")
    }
```

return以下は値に合わせて条件式画面に表示させる値を変更しています

INITIAL状態の画面→LOADING状態の画面SUCCESS状態の画面が表示されるようになります。
画面の表示切替はボタンについているonClickイベントに紐づいたsetValueHandlerによって値が変更され、それに対応して画面が再描画されるといったものです。

ざっくりですがこんな感じです。
いまさらながら最適化アルゴリズム（optimizer）を図と表でまとめる

# はじめに
最近、optimizerについて勉強する機会がありました（E資格対策）

Adamや最急降下法、SGDなど名前やぼやっとした印象は持っていたものの、
数式含めての理解はあまりできてはいなかったんですよね

参考：非常にわかりやすくまとめてあります
https://qiita.com/omiita/items/1735c1d048fe5f611f80
詳細な説明はすでにまとめてありますので、

ここでは図と表を使って、「覚えるために」まとめなおしたいと思います
※図はブログに以前掲載したものからの修正です

https://ai-mechatro.com/e-shikaku-optimizer

# 図でまとめる
図を使って、SGDからAdamまでの流れをまとめてみました
![optimizer3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/618591/41bc105f-3717-738d-37b3-72eea282698a.png)

まとめてみると分かりますが、

```math
w_t = w_{t-1} - \alpha' \nu_t
```
でどのアルゴリズムも基本的に表すことができることが分かります
（まあ更新式なのでそれはそうなんですが…）

※表現として適切かは怪しいところがあります
　例えば $(\nabla_w\mathcal{L}(w))^2 $ は
　本来なら $\nabla_w\mathcal{L}(w) \odot \nabla_w\mathcal{L}(w)$ の方が適切だと思います

※SGDは定義における勾配を取る時刻が違う気がします
　SGDの更新式は $ w_{t+1} = w_t - \alpha \nabla_w \mathcal{L}(w) $ ですが、
　$ \beta=0 $の場合のMomentumの式は $ w_t = w_{t-1} - \alpha \nabla_w \mathcal{L}(w) $ です

# 表でまとめる

```math
w_t = w_{t-1} - \alpha' \nu_t
```
としたときの学習率 $\alpha'$ ,勾配 $\nu_t$ を表にしてみます

|optimizer  |学習率 $\alpha'$  |勾配 $\nu_t$ |
|---|---|---|
|SGD  |$\alpha$  |$\nabla_w\mathcal{L}(w)$  |
|Momentum  |$\alpha$  |$\beta\nu_{t-1} + (1-\beta)\nabla_w\mathcal{L}(w)$     |
|NAG |$\alpha$  |$\beta\nu_{t-1} +(1-\beta)\nabla_w\mathcal{L}(w-\beta\nu_{t-1})$ |
|RMSProp | $s_t = \beta s_{t-1} + (1-\beta)(\nabla_w\mathcal{L}(w))^2$ <br>$\alpha' = \frac{\alpha}{\sqrt{s_t + \epsilon}}$　|$\nabla_w\mathcal{L}(w)$
|Adam |$s_t = \beta s_{t-1} + (1-\beta)(\nabla_w\mathcal{L}(w))^2$ <br>$\alpha' = \frac{\alpha}{\sqrt{s_t + \epsilon}}$ | $\beta\nu_{t-1} + (1-\beta)\nabla_w\mathcal{L}(w)$ |

表でまとめると、一目瞭然ですね
AdamがMomentum + RMSPropで成り立っているのが分かりやすいです

（この表、数式途中で改行をしない良い方法ないんでしょうか…？）
eachの入れ子　問題

# 問題.1
以下のように、果物の名前と値段が入った配列があります。
この配列を用いて、果物の名前とそれぞれの合計額が出力される
コードを記述してください。


fruits_price = [["apple", [200, 250, 220]], ["orange", [100, 120, 80]], ["melon", [1200, 1500]]]

（出力）
appleの合計金額は670円です
orangeの合計金額は300円です
melonの合計金額は2700円です

```
fruits_price = [["apple", [200, 250, 220]], ["orange", [100, 120, 80]], ["melon", [1200, 1500]]]
 
 fruits_price.each do |fruits|
  sum = 0
 fruits[1].each do |price|
  sum += price
 puts"#{fruit[0]}の合計金額は#{sum}円です"
 end
end
```

# 解説
最初に、3行目でfruits_priceから["apple", [200, 250, 220]]という値を取り出し、変数fruitに代入します。
その後4行目〜7行目で、fruitの1番目の値[200, 250, 220]から値を1つずつ取り出して、自己代入しながらsumを出力します。
この結果、appleの合計金額は670円ですと出力されるようになります。この作業を残り2つorange、melonでも繰り返します。
# 語り
配列からデータを取り出す、記述が理解できていなかったので、ruby問題の復習で使いました。
配列の何番目の値を取得する、fruitの配列の何番目を出力するが解けませんでした。
[]での指定を忘れないようにします。
mini_magickで縦書き文字入り画像を生成

# 概要
rubyで画像処理を行うことができるgemである「mini_magick」を使用し、縦書き文字入りの画像を生成する方法です。

# 環境
ruby 2.6.5p114 (2019-10-01 revision 67812)
mini_magick (4.11.0)

# 前提条件
mini_magickが使用できること。

# やり方
以下のようなベースとなる画像を用意し、そこに縦書きの文字を載せていきます。
![base.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1568184/ac42e433-18b8-503d-51be-b86773158238.png)

以下の`create_vertical_word_image`メソッドを実行することで縦書き文字入りの画像を生成することができます。`insert_vertical_word`メソッドの中で１文字ずつ座標をずらしながら描画していきます。「ー」は何もしないと横線のままなので９０度回転させ描画していきます。

```ruby
  # ベース画像に縦書き文字を載せます。
  def create_vertical_word_image
    require 'mini_magick'
    image = MiniMagick::Image.open('./app/assets/images/base.png')
    word = "縦書きですー"
    fontsize = 30
    color = '#000000'
    image.combine_options do |config|
      config.font "../usr/share/fonts/opentype/noto/NotoSansCJK-Bold.ttc"
      config.pointsize fontsize
      config.fill color
      insert_vertical_word(word, 600, 100, fontsize, config)
    end
    image.write "result.png"
  end

  # 一文字ずつ文字を設定していきます。伸ばし棒は９０度回転させています。
  def insert_vertical_word(word, x, y, fontsize, config)
    word.chars.each_with_index do |c, i|
      if c == "ー"
        config.gravity 'SouthWest'
        config.rotate -90
        config.draw "text #{y + i * fontsize + fontsize / 4},#{x - fontsize / 5} '#{c}'"
        config.rotate 90
      else
        config.gravity 'NorthWest'
        config.draw "text #{x},#{y + i * fontsize} '#{c}'"
      end
    end
  end
```
生成された画像がこちらになります。
![result.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1568184/2bbb45a2-c7de-95ae-032f-70e5a437d6e9.png)
SOTA論文通知用Slack botの作成

あるタスクでSOTA（State-of-the-Art; 最も高精度）の論文を探すときに、[Browse the State-of-the-Art in Machine Learning | Papers With Code](https://paperswithcode.com/sota)が有名です。
日進月歩で更新されていくSOTA、きちんと追っていきたい・・・とは心の中では思っていても、他の事に押し流されて過ぎていく日々。
そこで、SOTAが更新されると、SOTAモデルとその提案論文をSlackに通知するbotを作りました。
![githubactions.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1568065/937f5380-ae54-7d77-797f-698daf35460e.png)


## コード
以下のリポジトリに置きました。
Pythonで書いています。
私の場合は、Raspberry Pi上で動かしています。
https://github.com/ryamad/Papers_with_Code_bot

## 使い方
### Slackの設定
Incoming Webhook URLを発行しておきます。
発行方法：[Slack での Incoming Webhook の利用 | Slack](https://slack.com/intl/ja-jp/help/articles/115005265063-Slack-%E3%81%A7%E3%81%AE-Incoming-Webhook-%E3%81%AE%E5%88%A9%E7%94%A8)

### Incoming Webhook URLの登録
リポジトリの環境変数に、Slackで発行したIncoming Webhook URLを登録します。

## 設定
### タスク名
[Browse the State-of-the-Art in Machine Learning | Papers With Code](https://paperswithcode.com/sota)に記載されているタスクに対応しています。
各タスクの一番最後のサブディレクトリを記載してください。
例：`image-classification`の場合
1. 以下の赤枠をクリック![Browse the State-of-the-Art in Machine Learning - Papers With Code_ - paperswithcode.com.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1568065/33e3908e-4104-95c0-1e8d-5840297646b3.png)
2. 一番最後のサブディレクトリを`config.yaml`の`tasks`に追加してください。![last_part_of_url.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1568065/051dde22-8b67-d2be-1333-aa0d13b412a8.png)

## 最後に
これで設定は終わりです。
応用先は幅広いので、どんどん自動化していきたいですね。
【MongoDB】URI形式でアクセスしmongoシェルを使用する

## 概要
MongoDBで運用している場合、サーバに直接アクセスしてコマンドをたたくこともあると思います。ホスト名等が分かっていれば[MongoDBコマンド一覧（自分用メモ）](https://qiita.com/k-staging/items/a386d272abb2c9b92f1a)の記事にあるような形式で、mongoシェルを起動できるのですが、MongoDB Atlasなどで運用していてURI形式でアクセスしたいどうすれば良いのかというのが今回の記事です。

## 対応
MongoDBのドキュメントの[Connect to a MongoDB Replica Set](https://docs.mongodb.com/manual/mongo/#connect-to-a-mongodb-replica-set)にある通り、`mongo "アクセスしたいuri"`の形式で、uriをダブルクオテーションで囲むような形式で、mongoシェルを起動できます。
MongoDB Atlasでは以下のような形式で起動しました。

```
mongo "mongodb+srv://use-name:password@cluster.sample.mongodb.net/?retryWrites=true&w=majority"
```
【Laravel】Seederを使ってダミーデータを作成する方法

今回はLaravelでSeederを用いてダミーデータを簡易的に作成する方法を紹介します。

# 開発環境
PHP 7.3.9
MAMP 5.7
Mysql 5.7.26
Laravel 6.20.7
Composer 2.0.8

# 下準備

Seederを作成するためにプロジェクトを作ります。

```
$ composer create-project laravel/laravel seeder_test --prefer-dist "6.*"
$ cd seeder_test
$ composer require laravel/ui "1.x" --dev
$ php artisan ui bootstrap --auth
$ npm install && npm run dev
```

次にDB接続。
phpMyAdmin等で適宜DBとuserアカウントを作成し、
.envファイルに環境変数を設定して、DB接続をします。

```
$ php artisan migrate
```

--authで認証機能が追加されるのでusersテーブルが作られます。

# Seederでダミーデータを作成する

## ダミーデータの設定

usersテーブルが作成されたのが確認できたらまずUsesTableSeeder.phpというファイルを作成しましょう。

```
$ php artisan make:seeder UsersTableSeeder
```

database/seeds配下にファイルが生成されます。
`public function run (){}`にダミーデータを設定します。


```php:database/seede/UsersTableSeeder
<?php

use Illuminate\Database\Seeder;

class UsersTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        DB::table('users')->insert([
            'name' => Str::random(10),
            'email' => Str::random(10).'@gmail.com',
            'password' => Hash::make('password'),
        ]);
    }
}

```

上記はランダムな10文字でuserの名前をメールアドレスを生成するように記述しています。
passwordに関しては暗号化が必須のためHash::make()を記述します。

ちなみに自分で指定した値にすることも可能です。

```php:database/seede/UsersTableSeeder
<?php

use Illuminate\Database\Seeder;

class UsersTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        DB::table('users')->insert([
            [
            'name' => '太郎',
            'email' => 'taro@sample.com',
            'password' => Hash::make('password')
            ], [
            'name' => '二郎',
            'email' => 'jiro@sample.com',
            'password' => Hash::make('password')
            ], [
            'name' => '三郎',
            'email' => 'saburo@sample.com',
            'password' => Hash::make('password')
            ]
        ]);
    }
}

```

連想配列で複数設定してみました。

次にDatabaseSeeder.phpでUsersTableSeederを紐づける必要があるので以下のように設定します。

```php:database/seeds/DatabaseSeeder.php
<?php

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     *
     * @return void
     */
    public function run()
    {
        $this->call(UsersTableSeeder::class);
    }
}
```

他にSeederファイルを作成した場合は適宜、紐付けが必要になるので注意してください。

## composerのオートローダを再生成

シーダクラスを書き換えた場合はターミナルで下記のを実行しなければなりません。

```
$ composer dump-autoload
```

## DBにダミーデータを保存する

以下のコマンドを実行すればDBにダミーデータが保存されているはずです。

```
$ php artisan db:seed
```

もしすでにデータが保存されている状態で上記コマンドを実行する場合はエラーが発生するはずなので、

```
$ php artisan migrate:refresh
```

を実行すればDBのデータをリセットしてからseedファイルで設定したダミーデータを保存してくれます。

DBを確認してデータが保存されていれば完了です。
「リモートワークが始まって複数のスケジューラーを管理するのが面倒！」そんな悩みをzapierを使って解決！

こんにちは。
私の勤務する会社では、リモートワークが始まってから新たにリモート用のPCが配布されました。
これにより会社では3台PCを使用し、私用も合わせると4台のPCを管理するという事に・・。
しかも、それぞれのOutlookやGoogleのアカウントが異なりスケジューラーを入力するのも一苦労。
そんな悩みを解決してくれるツールをzapierの力を使って作ってみました！

#今回作成したもの
GoogleスプレッドシートとOutlook、Googleカレンダーをzapierを使用し連携させることで、Googleスプレッドシートに入力した情報を各カレンダーへ転記します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1390350/7f0674bf-9945-bfce-95d8-d1d553b86bc6.png)

#使用したツール
・zapier
・Googleスプレッドシート
・Googleカレンダー
・Outlook

#Googleスプレッドシートの準備
下記のように、記録用のスプレッドシートを作成する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1390350/5a00a19e-896d-d3b8-a826-90aec1cb9ae5.png)

#zapierでの操作（ワークフロー全体）
TriggerをGoogleスプレッドシート、ActionをGoogleカレンダー、Outlookに設定する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1390350/293b9ef9-4812-f600-b592-bda43a44add3.png)

#zapierでの操作（Googleスプレッドシート）
下記の通り設定する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1390350/fd834e1d-764f-4433-29f4-bad8c5d20d2e.png)


#zapierでの操作（Googleカレンダー）
下記の通り設定する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1390350/64188ce3-d19e-99c3-257d-9623c327e2ae.png)

#zapierでの操作（Googleカレンダー）
下記の通り設定する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1390350/52869a03-5897-bb4c-bd9e-a88afc389538.png)

#時間の設定
デフォルトでは世界標準時となっているため、マイプロフィールからTimezoneを変更する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1390350/8a59d77b-714b-4adc-2795-ff87684e54fd.png)

#終わりに
非常に簡単に、かつプログラミングなしで複数のアプリケーションを連携させることができることに感動しました！
普段手作業でやっていることも、1時間くらいかければこんなツーるがつくれてしまうなんて・・・！
今後もzapierを使用していこうと思います。
Colabで音声信号処理をする入り口

```python
import IPython
import librosa
import librosa.display
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
sns.set()



# pydubはcolabに入っていない
# loadで読み込み、sr=Noneを明示的に設定すると、元のサンプリングが保持される
# y, sr = librosa.load('menuettm.mp3', sr=None)
y, sr = librosa.load(librosa.ex('trumpet'))

# 波形を表示
librosa.display.waveplot(y, sr=sr)
plt.show()

# メルスペクトログラム（人間の聴覚に適したスペクトログラム）
S = librosa.feature.melspectrogram(y=y, sr=sr)
S_dB = librosa.power_to_db(S, ref=np.max)
librosa.display.specshow(S_dB, sr=sr, x_axis='time', y_axis='mel')
plt.colorbar()


# 音声を流す
IPython.display.Audio(y, rate=sr)

```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614092/65c15bd7-5779-ff8b-0b36-f0e96c08b641.png)
Ubuntu20.04でデュアルディスプレイのひとつの画面しか表示されない

# 事象

Ubuntu20.04につないでいる2枚のディスプレイのうち、1枚にしか画面が表示されない。

# 環境

動作環境は以下の通り。

```bash
$ cat /etc/os-release 
NAME="Ubuntu"
VERSION="20.04.2 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04.2 LTS"
VERSION_ID="20.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal

$ lspci | grep NVIDIA
01:00.0 VGA compatible controller: NVIDIA Corporation GM107GL [Quadro K620] (rev a2)
01:00.1 Audio device: NVIDIA Corporation GM107 High Definition Audio Controller [GeForce 940MX] (rev a1)
```

# 原因調査

ドライバが、GPUメーカ(NVIDIA)製ではなくUbuntu標準のNouveauになっていた。

どうも、Ubuntu 18.04から20.04にアップグレードした際にいつの間にかドライバが変わったらしい。

# 恒久処置

"ソフトウェアとアップデート"画面の"追加のドライバ"タブから"プロプライエタリ,検証済み"となっているドライバ"nvidia-driver-460"に変更する。

![Screenshot from 2021-05-30 23-38-16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114392/bcd9812a-1afe-e7b7-ea1e-069bd483b7a3.png)

# まとめ

Ubuntu20.04へのアップグレードの際に、ディスプレイのデバイスドライバがUbuntu標準に変わったため、デュアルディスプレイができなくなっていた。
ドライバをGPUメーカ製のものに変更することで改善した。
Expoで一瞬でReact Nativeアプリ開発

#Expo.io
react-nativeを使用したアプリを作るトイプロジェクトを実施するための環境設定方法を説明します。初心者でも、react-nativeプロジェクトを簡単に開始できるexpoを活用しました。 Expoを使用しないとReactNative開発に必要な複数ツールを直接セットしなければならないという不便さがあったので選択しました。

#準備
📌 Node.js インストール(npm含む)
📌 expo.io アカウント作り(https://expo.io/)

##👆npmを利用したExpo設置

npmを利用してexpo-cliを設置します。
expo-cliは簡単にreact nativeを開発できるようサポートしてくれます。

```zsh
$ npm install -g expo-cli
```

##✌️expoを利用して希望するディレクトリにreact-nativeプロジェクトを作成します。

```zsh
$ expo init personalPA
```

##👌インストールを終えた後は、expoを利用して直接作成したプロジェクトを作成します。

```zsh
$ cd personalPA
$ npm start
```


#### 👀 以下の全体の実行流れを参考してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/619479/25a09ae8-3998-c466-dda2-91ed5c47c969.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/619479/092ae9cc-f3a3-c879-be96-a4e83f80fd3f.png)

プログラムが正常に起動すると、上記の”BARCODE HERE”のところに大きなQRコードが出てきますが、これをApp StoreからダウンロードしたExpoアプリでスキャンすると、基本的なアプリ画面を確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/619479/687ad88c-e11c-bf07-ccf5-c5634f6f0434.png)

Googleストアでアプリをインストールして実行すると、QRコードをスキャンするボタンがあります。 ボタンを押してスキャンすると、ReactNativeで作ったネイティブアプリケーションが実行されます。 

また、以下のようにプロジェクトソースコードのApp.tsxの文句を直すと、Native Applicationにすぐに反映されることが以下のように確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/619479/ff47e9c9-5117-394e-2639-84f9950a4bc2.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/619479/a16f68bd-c213-5b9f-e91e-a295ce7f0cd9.png)

#まとめ
アプリ開発のための環境設定は簡単に完了しました。このようにEXPOは簡単にコーディングを始められる便利なツールです。 しかし、React-Nativeだけで開発する場合とは異なり、EXPOはネイティブ言語で書かれたライブラリを利用できないという限界がありますので、選択の際に参考にして適切な方法を選択してください。


📚参考講義：[React Native Docs](https://reactnative.dev/docs/getting-started)
新卒でIT会社に入社して約２ヶ月で得た知見と感想

#簡単に自己紹介
中学生の頃からプログラミングに興味を持ち、工業高校の情報科へ進学してC言語やJavaについて学ぶ。そのあとは関西のゲーム/IT系の専門学校に進学し3年間C++やUnity(C#)を学んだのち、4月から関西のIT会社に入社しました。

#研修について
私が入社した会社は2～3ヶ月は試用期間ということで研修を行います。未経験も可とあり、しっかりサポートしてもらえるのかと思っていましたが、会社で用意されたWordのテキストを読んで自分で進めていくといった独学のスタイルでした。もちろん分からない部分があれば上長の方に質問をしたりしています。
そのため独学できるタイプじゃないと結構しんどい印象でした。実際、研修を進めていくうえで一人だと詰まってしまうという人もいました。
そういった場合によくいるのが**「わからない部分をそのままにして後回し」**にしてしまう人です。または**「わかった気でいる」**人です。そのような人はどうなるかというと**人から指摘されない限り直そうとしない**のです。
わからないことをわからないままにして後悔するのは自分ですから、その時にしっかりとわかるようにするべきです。一人の力で出来ないなら他人の力を使うべきです。それが出来なければ申し訳ないが、今後エンジニアとして働くのは厳しいと思う。

#コミュニケーション・人間関係について
よく研修では挨拶をしっかりしましょうと言われるがまさにその通りだ。生半可な挨拶やボソボソだとコミュニケーション能力がないと判断される。まずは挨拶から。
会社では基本的に同期の研修生の人達と会話することが多かった。文系で大卒の人や情報系の専門学校出身の人、前職は営業職だった人など色々な分野の人が集まっていって、自分が知らない世界の話を聞くことができたのはとても良かった。良くも悪くも私はプログラム一筋の人間だったのでそういった話は新鮮だった。また最近は専門学校時代の知り合いともよく通話したりしている。そういった会話をしていく中でこの人とは合う、合わないというのが少なからず出てきた。私の場合は、

**１つ目は「くそ」や「ゴミ」などの口が悪い言葉を使う人。**ただただ不愉快。１人の時ならまだしもわざわざ人が周りにいるのにそういったことを平気で言う人。空気読めないんだろうなあと諦め半分で話してる。
**２つ目は人が何かに対して意見を言ってそれが自分と違った場合に相手の意見を否定ばかりする人。**これも言われた側は不愉快でしかない。相手の意見を尊重して客観的な目線で意見を述べてくれと思う。プライドが高い人に多いイメージ（偏見）。こういった人を論理的に論破できるようになればベストだけどそこまで口論できるタイプじゃない...
**３つ目は自己顕示欲があまりにも強すぎる人。**多少ならいいけどやりすぎ注意。めんどくさい人って思っちゃう。

コミュニケーションや人間関係に関してはあまり多くを語ることができないが、合う、合わないで判断して**合う人だけでコミュニティを作ることをおすすめする。**社会人になると仕事でどうしても合わない人と関わることになるが。その時は合わない人をどう扱うかの知識や経験が必要だろう...

#勉強について
勉強については研修の話でも話したが、**１番は独学ができるようになるといい。**エンジニアになった以上、一生勉強することになる。初めて知る技術や新しい技術を学ぶ時、それについて１から１０まで教えてくれる人なんていない。自分で調べて理解する必要がある。ネットを探せば分かりやすい解説サイトはあるし、参考書もでていたりする、それを見てまずは自分で取り組むことから始めるべきだ。
また独学をするときにおすすめなのは**何かしらの形でアウトプットをすること。**ノートに自分なりの考えや分かりやすい図でまとめたり、学んだことを他の人に教えてあげたりなどもしくは１つの作品（ゲームやwebサイト）を作ってみてもいいと思う。特に作品を作るのは実績ができ、モチベーションも上がり、次に繋げやすいのでおすすめする。
もし独学が難しいのであれば周りにいるできる人に教えてもらうのがいい。**人間関係や環境で勉強の質ってかなり変わる。**


#研修で勉強した内容について
Javaを使って最終的にはwebアプリケーションを作るといった研修だったので以下のようなことを学んだ。
**Java、HTML/CSS、JavaScript、SQL(Oracle)、JDBC、Struts**など
JDKのバージョンが低かったり、フレームワークが古いとかいう文句はあるが基本的なことは理解することができたと思う。
結局は**プログラムの基本的な考え方の定着と論理的思考、問題解決能力**の育成みたいなところが狙いな気がする。
だって配属されるプロジェクトで研修でやったような言語やフレームワーク使わないんだもん。

#研修以外で勉強しておいた方がいいこと
個人的には**ITパスポートや基本情報の内容について**勉強するのがいいと思う。なんやかんや実務で勉強した内容がちらほら出てくるので知っておいて損はない。仕事が忙しくなると勉強する時間なんて無いのでまだ余裕のある時に勉強できるならやるべきかな。国家資格なので合格すれば手当をもらえたりもする。
あとは**ハードウェアの知識も多少あるといいかもしれない。**PCのメモリやCPU、GPU、SSD/HDDとか、会社の上長がPCのメモリ増設１回しかやったことがなかったぽくてあたふたしてたのには笑った。ちなみに研修で使っていたPCはメモリ4GB未満。それでWin10動かすのはキツイ...
プログラム的なことだと**デザインパターンやリーダブルコード**の内容とかかな。

#あとがき
ここ２か月を振り返りながら記事を書いていたが、自分でもあんまり何をしていたか思い出せなかった気がする。気がついたら2ヶ月が本当にあっという間だった。自分自身のプライベートな時間を何に使うかが結構大事だったりするかもしれない。私の場合は基本的に専門学校時代の知り合いと通話して近況報告したり、プログラムのことを教えたり、勉強会を開いたりしていた。また独学でPythonの勉強もしていた。好きなことなら苦にならないのかもしれない。ハングリー精神大事。これからプログラミングを勉強する人にはぜひともプログラミングを好きになってほしいなと思う。
ここまで読んでいただきありがとうございました。皆様の意見も聞きたいので気軽にコメントしていただけると嬉しいです。
Pythonのglobalでのバージョンが切り替えられなかった時の対処法

#環境
- macOS BigSur 11.2.3
- shell:zsh

#問題
macにデフォルトで入っていたpython2.7xから3xへ変更したかったけど、変更できなかった。

#切り替え前のバージョン
```
$ python --version
Python 2.7.10
```
#Homebrewでpyenvをインストール
```
$ brew install pyenv
```
#pyenvの設定
```
$ echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zshrc
$ echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zshrc
$ echo 'eval "$(pyenv init -)"' >> ~/.zshrc
$ source ~/.zshrc
```
#pythonをインストール(今回は3.8.8をインストール)
```
$ pyenv install 3.8.8
```

#globalのバージョンも変更
```
$ pyenv global 3.8.8
```
が、確認してみると

```
$ pyenv global 3.8.8
Python 3.7.10
```

どうやらpyenv アップデートによって、path の設定が変更になったようなので、

```
$ pyenv init
# (The below instructions are intended for common
# shell setups. See the README for more guidance
# if they don't apply and/or don't work for you.)

# Add pyenv executable to PATH and
# enable shims by adding the following
# to ~/.profile and ~/.zprofile:

export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init --path)"

# Load pyenv into the shell by adding
# the following to ~/.zshrc:

eval "$(pyenv init -)"

# Make sure to restart your entire logon session
# for changes to profile files to take effect.
```
記述されているとおり.zprofile、.zshrcにそれぞれ記述する

```
$ open ~/.zprofile 
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init --path)"
```
保存して、同じくzshrcにも追記する

```
$ open ~/.zshrc
eval "$(pyenv init -)"
```
保存し、最後に反映させる

```
source ~/.zshrc       
```
もう一度バージョンを確認

```
$ python --version
Python 3.8.8
```
変更できたみたい！

##参考記事
[pyenvでPythonのバージョンを切り替えられない場合の対処法＋](https://qiita.com/TheHiro/items/88d885ef6a4d25ec3020#%E7%92%B0%E5%A2%83%E6%83%85%E5%A0%B1)
[Python pyenv アップデートでpathの設定が変更](https://timesaving.hatenablog.com/entry/2021/05/15/150000)

初投稿でした
【OCI】新しいバージョンのDRGを試す④ - リージョン跨ぎのtransit routing -

###概要
新しいバージョンのDRGはリージョン跨ぎのtransit routingをサポートします。
[オンプレミス]---(VPN or FastConnect)---[リージョン①]---(リモートVCNピアリング)---[リージョン②]
のような接続構成の場合、
オンプレミスとリージョン②間の通信をリージョン①経由で行うことができるわけです。

例えば国内に拠点を持つお客様が海外のリージョンに閉域網経由で接続したいという要件がある場合
国内から海外のリージョンに直接接続しようとすると高額な回線使用料が発生しますが
国内リージョン経由に接続することにより回線使用料を節約することができます。
　※リージョン間のリモートVCNピアリング時はoutbound課金対象になります

###検証構成
すでに検証済みの
<font color="red">**[【OCI】新しいバージョンのDRGを試す② - リモートVCNピアリング(リージョン間) -][1]**</font>」
の検証環境と<font color="red">**[【OCI】新しいバージョンのDRGを試す③ - サイト間VPN(IPSec) -][2]**</font>」
の検証環境を合わせた構成を使用します。
[1]:https://qiita.com/hongmnh/items/8d0b36682fab1caa1dc0
[2]:https://qiita.com/hongmnh/items/7bb442400ee43f761f9b

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411653/2284bb2a-2bec-992f-01ca-ba63cfa2bb45.png)

###動作確認
On-Premises上のテストPCとTOKYO REGIONのVCN上にあるインスタンス間で
pingによる疎通確認を実施し全ての確認において応答が返ってくることを確認しました。

①192.168.0.100 ⇒ 172.16.1.11
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411653/0d5c04c2-506b-2e6a-78ce-60b080b815f7.png)
②172.16.1.11 ⇒ 192.168.0.100
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411653/ad76fbb6-8baa-46dc-57f5-3c1bdca69680.png)

###その他
・DRGルート表
デフォルトで以下2つのルート表が作成される
①Autogenerated Drg Route Table for RPC, VC, and IPSec attachments
⇒　名前の通りRPC, VC, IPSec attachment用に作成されるルートテーブルのよう。
[次のホップ・アタッチメント・タイプ]が[Virtual Cloud Network]のルートのみが存在する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411653/49b5c634-bb86-702f-9cc2-00b27423d448.png)
②Autogenerated Drg Route Table for VCN attachments
⇒　名前の通りVCN attachment用に作成されるルートテーブルのよう。
[次のホップ・アタッチメント・タイプ]が[Virtual Cloud Network]及び
[Remote Peering Connection]のルートが存在する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411653/376e0a32-e872-c0b5-0721-f590365438e3.png)

・ルーティング動作確認
OCIからオンプレミスのCPEに広報されるルート情報はIPSecトンネル・アタッチメントで使う
DRGルート表のルート・ルール内容と一致する。

ルート・ルールが以下の場合、
[次のホップ・アタッチメント・タイプ]が[Virtual Cloud Network]及び
[Remote Peering Connection]のルート情報がCPE側に広報されることを確認した。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411653/cb7bd69d-2090-704f-86fe-3df33ae8583b.png)
[CPEのルーティングテーブル確認]
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411653/0efbf0b1-e370-25b5-2e2e-eabef5480640.png)

###まとめ
・DRGルート表(2つ)の使い分け方法を詳しく知りたい。
・リージョン跨ぎで通信を行う場合に考慮が必要な障害パターンを把握しておきたい。
(例: 中継ポイントとなるリージョンのどの箇所で障害が発生したら通信影響があるかなど)
コンテナ内でdockerイメージをビルドしてECRにプッシュする


#ローカルのコンテナ内でdockerのイメージをビルドしてECRにプッシュ
CodeBuildのように、amazonlinuxイメージを使用したコンテナ内でイメージをビルドし、ECRにプッシュできることを確かめます。ディレクトリ構造は以下の通りです。

```:ディレクトリ構造
.
├── Dockerfile
└── SpringBootProject
    ├── Dockerfile
    ├── build
    ├── build.gradle
    ├── gradle
    ├── build.sh
    ├── gradlew
    ├── settings.gradle
    └── src    
```

まずはSpringBootProjectをビルドするamazonlinuxのDockerfileです。

```Dockerfile:Dockerfile
FROM amazonlinux

#AWSCLIのインストール
RUN ["yum","install","-y","unzip"]

RUN ["curl","https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip","-o","awscliv2.zip"]

RUN ["unzip","awscliv2.zip"]

RUN ["/aws/install"]

#dockerのインストール
RUN amazon-linux-extras install -y docker

#プロジェクトディレクトリをコピー
COPY ./SpringBootProject/ /SpringBootProject

#ビルドスクリプトの実行
CMD cd SpringBootProject && ./build.sh

```
以下はbuild.shです。

```bash:build.sh
#!/bin/bash

#AWSの認証情報を環境変数に設定
export AWS_DEFAULT_OUTPUT="yaml"
export AWS_CLI_FILE_ENCODING=UTF-8
export AWS_ACCESS_KEY_ID=#your_access_key_id
export AWS_SECRET_ACCESS_KEY=#your_secret_access_key
export AWS_DEFAULT_REGION=ap-northeast-1
aws sts get-caller-identity --no-paginate --no-cli-pager

#gradleを使う為、JAVA＿HOMEを設定
export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.282.b08-1.amzn2.0.1.x86_64

#ビルド
/SpringBootProject/gradlew build

#ECRにプッシュ（先にレポジトリを作っておく必要があります。）
aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin account_id.dkr.ecr.ap-northeast-1.amazonaws.com
docker build -t repository_name .
docker tag repository_name:latest account_id.dkr.ecr.ap-northeast-1.amazonaws.com/repository_name:latest
docker push account_id.dkr.ecr.ap-northeast-1.amazonaws.com/repository_name:latest
```

SpringBootProjectディレクトリ内のDockerfileです。

```Dockerfile:Dockerfile
FROM amazonlinux

RUN yum install -y java-1.8.0-openjdk-devel.x86_64

COPY /build/libs/SpringBootProject.jar /
```

#コンテナ起動
コンテナ内でDockerを使うことになる為、docker.sockをマウントする必要があります。

https://devopscube.com/run-docker-in-docker/#:~:text=To%20run%20docker%20inside%20docker,sock%20as%20a%20volume.&text=Just%20a%20word%20of%20caution,privileges%20over%20your%20docker%20daemon.



```bash:イメージビルド&コンテナ起動
docker build . -t backend
docker run -v /var/run/docker.sock:/var/run/docker.sock -ti backend
```

**-成功-**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/659469/f99b2138-1933-a26c-144b-2c1a9d65d677.png)

#本編
実際にCodeBuildでECRにイメージをプッシュしています。

https://qiita.com/ms2geki/items/da9bd8ac8144d385f3e0
Vue/Reactでaxiosを使用したAPI通信時に500エラー

# はじめに
dockerにaxiosを使用しててAPIからデータを取得する際に、`500 (Internal Server Error)`が出た。
![截屏2021-05-30 22.36.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1065841/ecdc53b6-a0b2-826b-0680-8908f65c9709.png)




**結論先に述べると、container内ではlocalhostのような外部リンクでの通信はできないから。**

 
# 目次
<!-- タイトルとアンカー名を編集 -->
1. [dockerなしの場合](#dockerなしの場合)
2. [dockerの場合](#dockerの場合)
3. [参考文献](#reference)

<!-- 各チャプター -->
<a id="#dockerなしの場合"></a>
# localでの場合
・proxyの設定はこんな感じ


```javascript:frontend/vue.config.js
devServer: {
  proxy: {
   "/api": {
      target: "http://localhost:3000",
      changeOrigin: true,
      secure: false
    }
  }
}
```

```javascript:frontend/views/Login.js
const handleSubmit = async () => {
  try {
    const res = await http.post('/api/users/login')
      console.log("res", res)
  } catch (error) {
     console.log("error", error)
  }
}
```


```javascript:backend/routers/User.js
module.exports = router => {
  router.prefix("/api/users")
  router.post("/login", user.login)
}
```
<br><br>
・まずはpostmanを使って、apiはちゃんと動いているかをチェック。
・そもそもの話だが、バックエンドは実行されているかを確認する。
・`lsof -i -P | grep "LISTEN"`を使って、portはあっているかを確認する。
・フロントはproxyで`/api`を追加したのに、バックエンド側では`/api`を足されていない
・windowsの場合は、 `"target": "localhost:3000"`
　macの場合は、　`"target": "http://127.0.0.1:3000"`




<a id="#dockerの場合"></a>
# docker compose環境の場合
・dockerを使う場合は、`"target": http://container-name:port`
・以下のケースの場合、`"target": http://backend:3000`に設定する必要がある

```dockerfile:docker-compse.yml
version: '3'
services:
 mysql:
  ..........
 backend:
   ........
 frontend:
   ..........
```

<a id="#reference"></a>
# 参考文献
- https://stackoverflow.com/questions/45367298/could-not-proxy-request-pusher-auth-from-localhost3000-to-http-localhost500
- https://www.anchorblogs.com/details/8
winget がバージョン 1.0 へ到達

こんにちは
[Windows Package Manager](https://ja.wikipedia.org/wiki/Windows_Package_Manager) (winget コマンド) がバージョン 1.0 へ到達しました。

* v1.0.11451（2021年5月27日時点）

#### インストール方法
インストール方法はいくつかあるようです：

* [GitHub Latest release](https://github.com/microsoft/winget-cli/releases) からダウンロード＆インストール[^1]
  * ファイル名：```Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle```
*  [Insiderプログラム](https://devblogs.microsoft.com/commandline/windows-package-manager-preview/)に登録[^2]
*  Microsoft ストアから「アプリ インストーラー」（= winget）をインストール
* （予定：デスクトップ版のインストーラーが提供されるとのこと）

[^1]: なおインストール自動化の一例は、「[Microsoft Store アプリケーションのインストール（Powershell スクリプト）](https://qiita.com/kkdd/items/8aead1424315199dc851)」
[^2]: Insiderプログラム登録後、「[アプリ インストーラー](https://www.microsoft.com/ja-jp/p/アプリ-インストーラー/9nblggh4nns1?activetab=pivot:overviewtab)」（[Microsoft Store](https://ja.wikipedia.org/wiki/) 内）をインストール（更新）

#### コマンド使用例

winget コマンドを PowerShell 上で使う例：

```
PS> winget -v   # バージョンを表示
PS> winget upgrade   # アップグレード可能なパッケージを表示
PS> winget search Canonical.Ubuntu   # パッケージ検索例
```

* [Ubuntu](https://ja.wikipedia.org/wiki/Ubuntu) は [Linux ディストリビューション](https://ja.wikipedia.org/wiki/Linuxディストリビューション)の一つ
* 参考： [winget.run](https://winget.run/) (Finding winget packages made simple)

##### winget 利用により各種パッケージをインストールする例

```
PS> winget install -e --id Microsoft.PowerShell
PS> winget install -e --id Microsoft.WindowsTerminal
PS> winget install -e --id QL-Win.QuickLook
PS> winget install -e --id 7zip.7zip
PS> winget install -e --id Git.Git
PS> winget install -e --id GNU.Wget2
```

*  [Windows Terminal](https://ja.wikipedia.org/wiki/Windows_Terminal) はターミナル環境（[端末エミュレータ](https://ja.wikipedia.org/wiki/端末エミュレータ)）
コメント機能の実装で No mthod error が出たことについて

投稿された記事にコメントで機能の実装でno method errorが出力され、単純なミスでのエラーでしたので解決方法を記載

```ruby
class ContentsController<ApplicationController
   省略
 def show
  @comment = Comment.new
  @comments = @content.comments.includes(:user)
 end
```
contentsコントローラーのshowアクションで投稿された記事の詳細画面に遷移されそこで記事に対してコメントをする機能とコメント一覧を表示する機能を実施しようとしたところ, undefined method `comments` for nill: nillclassと出力された。
モデル同士のアソシエーションやタイプミスを考え見直したがどこも間違っておらず他の原因を考えた。
結果としてshowアクションの始めにどの記事かを取得していないことによるエラーであることがわかった。

```ruby
class ContentsController<ApplicationController
   省略
 def show
  @content = Content.find(params[:id])
  @comment = Comment.new
  @comments = @content.comments.includes(:user)
 end
```
@contentでどの記事かを指定、取得しなければ@commentsを定義したとしてもそもそも@contentが無いからnilになってしまいエラーが出力されてしまったという内容でした。

かなり単純なミスでしたので自分の勉強不足が露骨に出てしまいました。
自分では理解したつもりでももう一度各コードの意味とどのように動いているかをアウトプットできるよう頑張ります。
【yukicoder解説】〜Python3で「No.188 HAPPY DAY」を解いてみた〜


# 目次
1. はじめに
2. 問題URL
3. HAPPY DAYとは
4. 考え方
5. 提出コード
6. 解説
7. おわりに

**質問・指摘などがありましたらコメントか[Twitter](https://twitter.com/4voltex/)までお願いします。**

# はじめに
競技プログラミング練習サイトの[yukicoder](https://yukicoder.me/)で簡単な問題として掲載されていたNo.188を解きましたが、正攻法ではない気がしたので備忘録を兼ねて解法を書いておきます。

# 問題URL
・[No.188 HAPPY DAY - yukicoder](https://yukicoder.me/problems/no/188)

# HAPPY DAYとは
問題において定義されている "HAPPY DAY" は、日付をX月Y日として表したとき、Yの数字和 (=各桁の整数の和) がXと等しい日のことを指します。
この問題はグレゴリオ暦2015年について、"HAPPY DAY"が何日あるか求めよ。とのことでしたので、うるう年は考慮しなくて良いです。

# 考え方
問題文の最後には次のように表記されていました。
>365日それぞれの日が成り立つか確認してカウントしても十分速い。

ということで、365日全てにおいて成り立つかどうか確認して求めました。

## 組み込み関数 divmod()
Pythonには```divmod()```という組み込み関数があります。
・[組み込み関数 &#8212; Python 3.9.4 ドキュメント](https://docs.python.org/ja/3/library/functions.html#divmod)
使用例は以下の通りです。

```python
q, mod = divmod(10, 3)
print(q) #3
print(mod) #1
```
```divmod(a, b)```は```(a // b, a % b)```というタプルを返します。上のコードのようにアンパックして取得することができるので、数字和を求めるためにこの関数を使いました。

# 提出コード
```python:188.py
monthl = list(range(1,13))
datel_1 = list(range(1,29)) #2月
datel_2 = list(range(1,31)) #4,6,9,11月
datel_3 = list(range(1,32)) #上記以外の月

res = 0

for i in monthl:
    if i == 2:
        for j in datel_1:
            q, mod = divmod(j,10)
            if i == q + mod:
                res += 1
    elif i == 4 or i == 6 or i == 9 or i == 11:
        for j in datel_2:
            q, mod = divmod(j,10)
            if i == q + mod:
                res += 1
    else:
        for j in datel_3:
            q, mod = divmod(j,10)
            if i == q + mod:
                res += 1

print(res)
```
実行時間は14ms、使用メモリは7580KBでACでした。

# 解説
月、日ともにリストを作り、for文で探索しました。月によって日数が28日、30日、31日と違うので、3種類のリストを作成し、月によって探索するリストを変えています。その後、```divmod()```で成り立つものを調べて数えました。

# おわりに
```divmod()``` を使って解いている人を見かけなかったのでまとめてみました。<br>
この記事で用いたコードを含め、yukicoderやAtCoderに提出したコードは、Githubにアップロードしています。
・[for_yukicoder &#8212; Github/PyRadiolarus](https://github.com/PyRadiolarus/for_yukicoder)
「DeFiのイールドファーミングでいちいち収穫した利息をExcelで管理するのが面倒」という悩みをLINEBotとGASを使って解決する。

皆さんこんにちは。
仮想通貨投資を行っている方の中にはDeFiのイールドファーミングを利用している方も多くいるのではないでしょうか。
Defiサービスの中でも容易に高利回りの利息収入が手にすることもでき、人気がありますが税金計算が厄介ですよね。
確定申告のためにも、受け取った利息の数量とレートを記録していかなければいけません。
利息取得の度、いちいちExcelを開いて記録してなんて本当に面倒くさい！
という事で、LINEとGASを使って手軽にGoogleスプレッドシートにデータを蓄積していくアプリを作ってみました。

#今回作成したもの
LINE、GAS、スプレッドシートを連携させることで、LINEに入力した情報をスプレッドシートへ転記します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1390350/f16a8bd2-82a3-13a4-026f-85270a8d30d5.png)
①LINEへ「$"通貨名" "利息" "通貨のレート"」の形で入力します。
（各要素の間は半角スペース）
②Webhookを利用し、GASへ連携されます。
③Googleスプレッドシートの指定されたセルに入力されます。

#使用したツール
・Googleスプレッドシート
・Google Apps Script
・LINE Messaging API

#Googleスプレッドシートの準備
下記のように、記録用のスプレッドシートを作成する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1390350/27e13131-8ec8-7bc0-f420-d1a2e60f44bc.png)

#Google Apps Script
GASを新規作成する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1390350/7cd734a9-c313-4f22-6eef-9b62c35b4de9.png)

GASのコード全文は下記の通り。

```js

function doPost(e) {
  // 投稿されたメッセージを取得
  var userMessage = JSON.parse(e.postData.contents).events[0].message.text;
   
  if(userMessage.match(/^\$/)) {
    // $から始まるメッセージの場合、$を除いた文字列を再代入
    userMessage = userMessage.substr(1);
  } else {
    // $から始まらない場合は何もしない（処理終了）
    return;
  }
   
  // スプレッドシートへ保存=======================================
  var response = e.postData.getDataAsString();
  var spreadsheetId = "自分のスプレッドシートのID";
  var sheetName = "log";
  var spreadsheet = SpreadsheetApp.openById(spreadsheetId);
  var sheet = spreadsheet.getSheetByName(sheetName);
 
  // 空白・タブ・改行で区切り配列に変換  
  var arr = userMessage.split(/\s/);
 
  // 配列の先頭に日時を代入
  arr.unshift(new Date());
 
  // セルの最下部に配列を転記
  sheet.appendRow(arr);
  // =======================================

return ContentService.createTextOutput(JSON.stringify({'content': 'post ok'})).setMimeType(ContentService.MimeType.JSON);
 }

```
なお、「自分のスプレッドシートのID」は、シートのURL欄の「/d/」と「/edit」の間の乱数がIDに該当します。



コードが完成したら、下記の通りLINE連携用のWebhookURLを取得する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1390350/06a32551-5fa3-6202-407d-aedfb9a6f6f9.png)



#LINEの設定
LINE Developersに登録し、Messaging APIを作成していきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1390350/715f216c-8c4f-51a3-8d46-e6c5ffecd455.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1390350/486a3827-96a1-4da5-f2c4-3710d9b27060.png)

#さいごに
今回は、自身の生活ルーティンの中で面倒だけどもやらなければならないことにフォーカスして作成してみました。
私個人としては、簡単な開発で結構使えるツールができたように感じています！
確定申告は面倒ですが、早目に準備していきましょう。

#参考サイト
[プログラマーになった 「中卒」 男のブログ](https://chusotsu-program.com/line-gas/)
GASのコードを参考にさせて頂いております。
備忘録：GitLab Runnerの登録手順

# はじめに

GitLab CIにおいて、GitLab Runnerを登録した手順を備忘録として残します。

# GitLab Runnerの導入・登録(Docker版)

Dockerがインストール済みの前提です。
GitLab Runnerのconfigファイル(config.toml)を格納するボリュームを作成します。

```zsh
sudo docker volume create gitlab-runner-config
```

GitLab Runnerのコンテナを起動します。タイムゾーンは東京を指定します。

```zsh
sudo docker run -d --name gitlab-runner --restart always \
     -v /var/run/docker.sock:/var/run/docker.sock \
     -v gitlab-runner-config:/etc/gitlab-runner \
     --env TZ=Asia/Tokyo \
     gitlab/gitlab-runner:latest
```

GitLab RunnerをGitLab CIに登録します。

```zsh
sudo docker run --rm -it -v gitlab-runner-config:/etc/gitlab-runner gitlab/gitlab-runner:latest register
```


## GitLab Runnerの導入・登録(Linux版)
OSは RHEL 7 です。

RPMパッケージをダウンロードします。
[GitLabのガイド](https://docs.gitlab.com/runner/install/linux-manually.html#download)では、以下コマンドの`amd64` の部分は `${arch}` となっていますが、その場合`x86_64`に置き換えられ、該当のファイルが存在せず取得できないため、`amd64`を直接指定しています。

```zsh
curl -LJO "https://gitlab-runner-downloads.s3.amazonaws.com/latest/rpm/gitlab-runner_amd64.rpm"
```

ダウンロードしたRPMパッケージをインストールします。

```zsh
sudo rpm -i gitlab-runner_amd64.rpm
```

GitLab RunnerをGitLab CIに登録します。

```zsh
sudo gitlab-runner register
```


# GitLabサーバとGitLab Runnerが同一サーバ上で稼働し、GitLab RunnerでDocker executorを使用する場合の注意点

GitLab RunnerはGitLabサーバ(GitLab CI)と通信を行いますが、GitLabサーバとGitLab Runnerが同一サーバ上で稼働しており、かつ、GitLab RunnerのexecutorがDockerの場合、Dockerコンテナ(executor)からホストOS(GitLab CI)へのアクセスが必要となります。

しかし、Dockerコンテナ(executor)からホストOSのFQDNが名前解決できないため、GitLab Runnerに以下の設定が必要です。

1. DockerコンテナからホストOSにアクセスするためのIPアドレスを確認する (`docker0` インターフェースのIPアドレス)
1. GitLab Runnerの設定ファイル(config.toml)で、`[runners.docker]` セクションに `extra_hosts` を設定する(以下の「other-host」の部分をFQDNで置き換える) ([GitLab Advanced configuration -> The [runners.docker] section](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runnersdocker-section))

```toml
[runners.docker]
  extra_hosts = ["other-host:xxx.xxx.xxx.xxx"]
```
※config.tomlのパス
- Docker版GitLab Runnerの場合　：　`gitlab-runner-config`ボリュームのディレクトリ内の`config.toml`(具体的なパスは `docker volume inspect` で確認
- Linux版GitLab Runnerの場合　： `/etc/gitlab-runner/config.toml`



# 参考

- [Install GitLab Runner](https://docs.gitlab.com/runner/install/)
- [StackOverflow - add hosts redirection in docker](https://stackoverflow.com/questions/34242634/add-hosts-redirection-in-docker/34709445)
linux ターミナルでファイルを作成する 個人メモ

# 目的

- カレントディレクトリに任意のファイル名でファイルを作成する方法をメモ的にまとめる

# 方法

- 任意のディレクトリで下記コマンドを実行する。

    ```terminal
    $ touch ファイル名
    ```