OmniAICreator/Qiita-1.07M huggingface dataset:
Clubhouseを支えるリアルタイム通話サービスagoraを紹介！

# はじめに
今回は、今はやりのClubhouseで使われているリアルタイム通話サービスAgoraの紹介をします！
すごく簡単に導入できるので、興味を持った方は是非試してみてください！

# YouTube動画
文字だけでなく、動画での解説もしています。
興味のある方はこちらも見ていただけると嬉しいです。
[【YouTube動画】Clubhouse を支える音声サービス agora の紹介](https://youtu.be/x_6yohvLhkI)
[![Clubhouse を支える音声サービス agora の紹介](https://img.youtube.com/vi/x_6yohvLhkI/0.jpg)](https://youtu.be/x_6yohvLhkI)

# Agoraとは
[Agora](https://www.agora.io/en/)は、音声やビデオ通話を簡単に実装できるリアルタイム通話サービスです。
料金は、`音声：1000分/$1 　ビデオ：1000分/$4`です。
また、無料枠が10,000分あります。(YouTube動画内では無料枠が1000分となっていますが、無料枠は10,000分のようです。https://www.agora.io/en/pricing/)

類似サービスには、[Twilio](https://www.twilio.com/ja/)や[Skyway](https://webrtc.ecl.ntt.com/)がありますが、いずれもAgoraとほぼ同じことができます。

# 実装方法
Agoraは[公式ライブラリ](https://docs.agora.io/en/Interactive%20Broadcast/landing-page?platform=Web)が充実していて、JavaScriptをはじめ、複数の言語でとても簡単に実装できます。
以下はJavaScriptの例です。

```js
import AgoraRTC from 'agora-rtc-sdk'

const client = AgoraRTC.createClient({ mode: 'rtc', code: 'vp8'})
client.init('<app id>')
client = join('<token>', '<channel>', null, (uid) => {
  const localStream = AgoraRTC.createStream({ audio: true, video true })
  localStream.init(() => {
    localStream.play('me')
    client.publish(localStream)
  })
})

client.on('stream-added', (event) => {
  // ユーザが追加された場合の処理を記載する
})

client.on('stream-removed', (event) => {
  // ユーザが外れた場合の処理を記載する
})

```

なお、SSRができるJavaScriptフレームワーク(Next.jsなど)でAgoraRTCを使う場合、AgoraRTC内でwindowオブジェクトを使用しているため、
サーバサイド側の処理でAgoraRTCをインポートしないように注意してください。


# 他のリアルタイム通話サービスとの比較
他サービス(Twilio, Skywayなど)と比較したAgoraの特徴は以下の３つです。
## 特徴1. 実装が簡単
実装する際のコード量が少なく、実装が簡単です。

## 特徴2. ライブラリが充実
TwilioやSkywayはJavaScriptやAndroid、iOSのライブラリしかないのに比べAgoraは公式ライブラリが充実しており、例えばReactNative、Unity、Cocoa2D、Electron、Windows、MacOSなどもあります。

## 特徴3.ドキュメントがわかりやすい
JavaScriptを使ってみたところ、1時間で双方向通話が可能になるくらい、ドキュメントがわかりやすいです。
ただ、Next.jsなどを使うと詰まってしまうので、ReactやVueを使うのがオススメです。

## まとめ
今回はClubhouseの通話関連サービスAgoraについて紹介しました。Ｃlubhouseは音声だけですが、Agoraを使って音声に何かプラスしたクローンサービスを作ってみると面白いかもしれません。
簡単にデスクトップアプリが作れる！ Electron 入門

# はじめに
今回はWebの技術だけで簡単にデスクトップアプリが作れるElectronについて、始め方や注意点をご紹介します！
デスクトップアプリ開発を始めたいけど始め方が分からない方は、始めの一歩にElectronを選んでみてはいかがでしょう？

# YouTube動画
文字だけでなく、動画での解説もしています。
興味のある方はこちらも見ていただけると嬉しいです。
[【YouTube動画】簡単にデスクトップアプリが作れる！ Electron 入門](https://youtu.be/4aFG5tJIWt0)
[![簡単にデスクトップアプリが作れる！ Electron 入門](https://img.youtube.com/vi/4aFG5tJIWt0/0.jpg)](https://youtu.be/4aFG5tJIWt0)

# Electronとは
Electronとは、HTML、CSS、JavaScriptでデスクトップアプリが作れるものです。
例えば、Slack、VSCode、Atomなど、エンジニアであれば馴染みのある様々なアプリがElectronで作られています。


# Electron Forgeとは
Electronのスタート方法はいくつかありますが、今回はオススメのElectron forgeを説明していきます。
Electron forgeの主な特徴は以下の通りです。

1. Electronのパッケージ化、AutoUpdateに簡単に対応できる
2. TypeScript, Webpackを簡単に導入できる
3. React化も簡単

[公式ページ](https://www.electronforge.io/)にコマンド例が記載されており簡単にElectronを始めることができます。
例えば、TypeScript+Webpack対応済みのElectronプロジェクトを始める場合、
以下のコマンドでできます。
```npx create-electron-app my-new-app --template=typescript-webpack
```


# 開発する時知っておきたいこと
Electronで開発を始める際に、あらかじめ知っておくと便利なことを紹介していきます。

## Nodeとブラウザ
ElectronはNodeとブラウザという２つの要素でできており、それぞれ別で動いています。

Nodeでは、一番最初の起動やブラウザの起動が行われます。また、ブラウザを作ったりサイズを決めたりなどブラウザに関する処理や、メニュー部分での処理もここで行われます。

ブラウザでは、Nodeで作られたブラウザのウィンドウの中のJSやReactが動いています。

Electron ForgeにWebpackを導入した場合、Nodeで動く部分をmain、ブラウザで動く部分をrendererと呼び、この２つでwebpackが分かれています。なので、webpackのconfigは２つです。configは４つできるので混乱しがちですが、実際は２つのconfigが別のファイルをインポートしているため４つに見えます。
![スクリーンショット 2021-03-15 13.39.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/751408/e3eab4dd-dd31-f730-7a38-f47b3263517f.png)


## BrowserWindow
デスクトップアプリの詳細を設定するクラスになります。ウィンドウのサイズやどこに表示させるか、常に最前面にしたり、透明化したりなどの設定ができます。
例えば、ウィンドウを常に最前面に表示したい場合、以下のように書きます。

```js
new BrowserWindow({
    height: 600,
    width: 800,
    alwaysOnTop: true // 常に最前面表示
  });
```

BrowserWindowで使えるオプションは[こちら](https://www.electronjs.org/docs/api/browser-window#new-browserwindowoptions)で確認できます。

## ipcMain, ipcRenderer
Nodeとブラウザを通信させる時に使います。
ipcMainがNode側でipcRendererがブラウザ側で、この２つを通信させることでNodeとブラウザを連携できます。
ipcRendererからはイベントが送れますが、ipcMainからはイベントを送れず、この場合はブラウザウィンドウからipcRendererに送ります。

## Menu,Tray
メニューやアイコンを追加したい時に使うのがMenuとTrayというクラスです。
Menuは、Macでは左上にあるメニューのことです。
Trayは、Macでは右上に表示するアプリのアイコンのことです。
Trayでのアクションをトリガーにブラウザに反映したい時は、Trayでクリックされると、ウィンドウがイベントを送り、ipcRendererが受け取って処理するという流れで書くことが多いです。

# まとめ
HTML、CSS、JSで簡単にデスクトップアプリが作れるElectronについてご紹介しました。Electron forgeで始めるのがオススメです。簡単に作れるのでぜひ試してみてください。
ターミナルでディレクトリー及びファイルを作ってみよう！

では、ターミナルでディレクトリーを作っていきましょう！

今回はわかりやすいように、デスクトップに作っていきます。
ターミナルを起動し、cdコマンドでDesktopに移動しましょう。

#①　touch 
これは空のディレクトリーを作ってくれます。
今回はターミナル上でfooというファイルを作ってみます。
またすでに作成されたファイルに対して最終更新日に変えることができます。
作成されましたか？？


#② mkdir bar
ディレクトリーが作成されます。
また、　-pを付け加えることで更に深い階層まで作ることができます。

#③　mv
これはファイル及びディレクトリーの名前を変えてくれます！！
では先程作ったファイルfooをendという名称に変えてみてください。

#③ cp
これは、ファイルをコピーしてくれます。
今回はendファイルをbooファイルにコピーしていきます。

#④ rm
ファイルを削除します。ただし、ターミナル上では削除確認などはないので消すときは要注意です！！
ディレクトリーを削除する場合はrmに -r ファイル名を追加してください😊
EKSにArgoCDをインストールして使う

## Argo CD

- `Argo CD is a declarative, GitOps continuous delivery tool for Kubernetes.`
    - Kubernetes用GitOps継続デリバリーツール
- GitでCommitが上がったら、Deploymentを再定義みたいなことをしてくれるみたい

## Install

```
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
```

## CLI Install

```
VERSION=$(curl --silent "https://api.github.com/repos/argoproj/argo-cd/releases/latest" | grep '"tag_name"' | sed -E 's/.*"([^"]+)".*/\1/')

sudo curl --silent --location -o /usr/local/bin/argocd https://github.com/argoproj/argo-cd/releases/download/$VERSION/argocd-linux-amd64

sudo chmod +x /usr/local/bin/argocd
```

## 接続
```
kubectl port-forward svc/argocd-server -n argocd 8080:443
```

- `admin/argocd-server-7fdb567cd4-27ssd`

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293481/32f2d795-99b5-3ed6-da70-731758547545.png)




## アプリケーション作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293481/d2d59cff-c2f0-5a3e-4f35-2b7cea306ede.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293481/64daaca7-1c9c-b6e6-d9a7-7a148c94503d.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293481/8f670f4f-ee4d-1fb9-738e-0d2e8cc39b56.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293481/78b7d1e6-2d41-4dd1-42e3-a6587b593d7e.png)


## 参考
https://argoproj.github.io/argo-cd/getting_started/
https://www.eksworkshop.com/intermediate/290_argocd/install/
https://dev.classmethod.jp/articles/eks-argocd-getting-started/
Webの技術でアプリが作れる！？ React Native入門

# はじめに
今回は、Reactでスマホアプリが作れるReactNativeを紹介します！
Reactを触ったことあるけど、ReactNativeは触ったことがない方向けに
ReactNativeの概要をご紹介します。

# YouTube動画
動画はこちらから視聴できます。
記事に書き起こしきれなかったやっすん自身の経験談なども聞くことができますので
ぜひ一度ご覧ください！！

[【YouTube動画】Webの技術でアプリが作れる、ReactNative入門](https://youtu.be/_AKJE0vB-z0)
[![Webの技術でアプリが作れる、ReactNative入門](https://img.youtube.com/vi/_AKJE0vB-z0/0.jpg)](https://youtu.be/_AKJE0vB-z0)

# React(Web)との違い
ReactNativeのコードはこのようになっています。

```react
import { View, Text } from 'react-native'

function App() {
  return(
    <View>
      <Text>テキスト</Text>
    </View>
  )
}
```

Reactとの違いは、JSXで使用するタグ(コンポーネント)です。ReactNativeではViewやTextといったタグを使います。
ReactNativeは、ビルド時にこれらのタグをiOSやAndroid用のクラスに変換することで、ネイティブアプリのように動作させることができます。
ReactNativeで利用できるタグについては[こちら](https://reactnative.dev/docs/components-and-apis)をご覧ください。

# ReactNative開発を始めるときの２つの選択肢
ReactNativeの開発環境構築についてググった時に、Expoというフレーズを目にしたことはありませんか？
実は、ReactNative開発ではExpoとReactNativeという2つの選択肢があります。
それぞれの特徴をご紹介します。

## Expo
ExpoはReactNative開発初心者向けで、主な特徴は以下の通りです。

1. Xcode, AndroidStudio不要なので、web技術ゼロでも大丈夫。
　ExpoではiOSとAndroidの向けアプリをそれぞれ自動的にビルドしてくれます。

2. ビルドが速い
　ビルドや公開については、ExpoのCIサービスが立ち上がってビルドしてくれるようになっているので、XcodeやAndroidでよくあるバグが出ません。

3. Expo用のライブラリがある
　Expoでは通常のReactNative向けライブラリの一部を使用することができません。
　ただし、Expo用のライブラリがとても充実しており、通常開発する範囲で必要となる大体の機能は開発することができます。

ReactNative開発を初めて行う方は、まずはExpoを使って徐々に慣れていくことをオススメします！


## ReactNative
元々iOSやAndroidアプリ開発の経験がある方、Expo開発に慣れもっと高度な機能を実装したい方はReactNative開発がおすすめです。
特徴は以下の通りです。

1. Xcode, AndroidStudio(Gradle)の知識が必要
　アプリ開発環境に関する知識が必要になりますが、Expoよりもきめ細かな設定が可能です。
　ビルド設定はiOSとAndroidそれぞれで行う必要があります。

2. 様々なネイティブのライブラリがある
　Expoと異なり、ReactNative向けのライブラリを全て使うことができます。
　ネイティブのライブラリのインストール方法は、
　　- iOSのインストール：CocoaPods
　　- Andriodのインストール：Gradle

中・上級者の方は、より高度な機能開発ができるReactNativeがオススメです！

# Expo Application Service
Expoでは様々なライブラリが使えないという制約がありますが、[Expo Application Service](https://blog.expo.io/expo-application-services-eas-build-and-submit-fc1d1476aa2e)を使うとネイティブのライブラリを組み込めるようになるらしいので、EAS Build機能の本リリース後は全員ExpoでOKになるかもしれません。
EAS Buildについては[こちら](https://docs.expo.io/build/introduction/)をご覧ください。
※現時点では experimental featureとなっており、本番利用は推奨されていません。


# まとめ
ReactNativeとReactの違いや、ExpoとReactNativeについて主に解説しました。
この記事をきっかけにReactNative開発に触れてみていただけると嬉しいです！
WordPress テーマ作成時に設定しておきたいネイティブ CSS

WordPress の独自テーマで `Classic Editor` を導入する際に発生する

「__TinyMCEエディタのボタン押したけど何も変化しないんだけど？__」問題。

この問題を回避するのに必要な CSS （WordPress Native CSS）を毎回忘れるのでまとめました。

## リセットしたタグの設定

リセットCSS のリセット具合によって変わりますが、以下を設定しておけばそれなりに見れるはず。

```css:css
h2,
h3,
h4,
h5,
h6 {
  margin: 2em 0 1em;
  line-height: 1.4;
}
h2 {
  font-size: 1.8em;
  border-bottom: 1px solid #ddd;
  padding-bottom: 0.2em;
}
h3 {
  font-size: 1.6em;
}
h4 {
  font-size: 1.4em;
}
h5 {
  font-size: 1.2em;
}
h6 {
  font-size: 1em;
}
p {
  line-height: 1.8;
}
p + p {
  margin-top: 1.5em;
}
em {
  font-style: italic;
}
blockquote {
  margin: 1.5em 0;
  border-left: 5px solid #ddd;
  padding: 1em 0 1em 10px;
  color: #777;
}
blockquote p + p {
  margin-top: 0.5em;
}
ul,
ol {
  margin-top: 1.5em;
}
ul {
  list-style-type: disc;
}
ol {
  list-style-type: decimal;
}
li {
  margin-left: 1.5em;
}
```

## WordPress が出力する class の設定

```css:css
.aligncenter {
  display: block;
  margin-right: auto;
  margin-left: auto;
}
.alignright {
  float: right;
  margin-bottom: 20px;
  margin-left: 20px;
}
.alignleft {
  float: left;
  margin-right: 20px;
  margin-bottom: 20px;
}
.wp-caption,
[class*='wp-image'] {
  display: block;
  max-width: 100% !important;
  margin-top: 1.5em;
  text-align: center;
}
.wp-caption-text {
  margin-top: 0;
}
```

## float の解除

左寄せ、右寄せボタンを押すと `float` が設定されるため、
後続の要素で `clear` が必要です。
がしかし、後続の要素は回り込ませる必要もあるため、`<?php the_content(); ?>` の親要素に `clear` の設定をしておきます。

```php:php
<article>
  <?php if (have_posts()) : ?>
      <?php while (have_posts()) : the_post(); ?>
          <h2><?php the_title(); ?></h2>
          <div class="articleBody"><?php the_content(); ?></div>
      <?php endwhile; ?>
  <?php else : ?>
      Not Found
  <?php endif; ?>
</article>
```

```css:css
.articleBody {
  display: flow-root;
}

/* IE11 を含む場合 */
.articleBody::after {
  display: block;
  clear: both;
  content: '';
}
```
Active Storageを用いた画像投稿機能

#Active Storageとは

Active Storageとは画像投稿機能を実装できるGemです。
写真を投稿して一覧表示するアプリ作成にActive　Storageを使ったので、実装方法をまとめました。

またその他にも画像加工のために色々と導入が必要になります。

・ImageMagick・・・画像の作成やサイズ変更、保存形式の変更ができるソフトウェア
　※gemでは無いのでHomebrewからインストールします
・Minimagick・・・ImageMagickの機能をRubyで扱えるようにしてくれるgemです
・ImageProcessing・・・画像サイズを調整するためのgemです


#Active Storageの導入

・brew install imagemagickを行い、imagemagickをインストール

・gemを導入してbundle installを行う

```ruby:qiita.rb
gem 'mini_magick'
gem 'image_processing', '~> 1.2'
```

・rails active_storage:installを行い、Active Storageのインストール
・続けてrails db:migrateを行う

これでデータベースに保存する準備ができました。

#画像投稿の機能

投稿機能を実装するために、以下の２つが必要です

①ActiveStorageのテーブルと関連するテーブルのアソシエーションを定義
②該当するcontroller.rbにて、imageカラムの保存を許可


まずはアソシエーションから。

```ruby:qiita.rb
has_one_attached :image
```

続いてコントローラーで画像を保存できるようにします。

```ruby:qiita.rb
  def meal_params
    params.require(:meal).permit(:date,:image).merge(user_id: current_user.id)
  end
```

簡単にですが、ここまでで投稿機能を作る事ができました。

#投稿した画像の表示

ビューファイルは改善の余地がありますが、これで仮置きしました。

```ruby:qiita.rb
<ul class='meal-list'>
  <% @meals.each do |meal| %>
    <li class='list'>
      <div class='meal-lists p-3 m-3'>
        <div class='item-img-content '>
          <%= image_tag meal.image, class: "item-img" %>
        </div>
        <h3 class='item-date'>
          <%= meal.date %>
        </h3>
        <div class="meal-description-box">
          <span><%= meal.description %></span>
        </div>
      </div>
    </li>
  <% end %>
</ul>
```

表示された画像はこんな形で表示されました。
![画像](https://i.gyazo.com/6ee948834f6d3f1f8a534b8c9e151979.jpg)

#まとめ

ActiveStorageを使えば簡単に画像投稿機能を作る事ができます！！
deviseでのエラー。。。

## 環境

Rails 6.1.3

Docker version 20.10.5

## エラー

```markdown
LoadError in Devise::Sessions・・・・
・
・
・
cannot load such file — coffee_script
```

deviseをインストール時に確認のため、以下のURLに遷移した時、

エラーが出ました。

（※「devise」は、ログイン機能やユーザ登録機能などを簡単に実装できるgemです。）

[http://localhost:4000/users/sign_up](http://localhost:4000/users/sign_up)

## 解決方法

解決方法として、以下の記事を見つけました。

[https://peacejet.hatenablog.com/entry/2018/11/13/112712](https://peacejet.hatenablog.com/entry/2018/11/13/112712)

内容としては、Ruby2.3以後は、以下のGemが必要になるみたいです。

```markdown
gem 'bcrypt-ruby', '~> 3.0.0'
```

なんとか表示が出来ていたのでよかったです。
Vue.jsで学んだこと①

#はじめに
技術力向上のため、最近流行であるVue.jsを学んでみた。
最初はVue.jsはどういったものかというのを学ぶために、以下の書籍を読み一通り確認してみたので、書籍への感想をまとめてみました。

>書籍「Vue.js開発入門」
>https://www.amazon.co.jp/dp/B07KPTGZ4C/ref=cm_sw_r_tw_dp_K97J05KWX054YQ5F85BG

Vue.jsというものをそもそも知らなかったので、完全無知な状態ではじめました。

#読み始め
Javascriptの経験はあったので、はじめのところは理解しやすく、
またVue.jsとJavascriptではどういった違いや書き方があるのかというのがわかりやすかったです。
特にJavascriptの経験者からすると条件文を以下のようにHTMLで書けるのは簡単だと感じると思います。

```html
<button v-if="isShow"></buton>
```

#読み進め
アニメーションをトランジション（transition）で簡単に実装できる！
これもJavascriptの経験者ならわかると思いますが、ライブラリを取得したり、CSSで設定したりと結構わからないことが多いと思います。

Vue.jsでは以下のように書くだけで簡単にアニメーションを実装できるのにビックリしました。

```css
<style>
 .v-enter-active {
   transition: 0.5s;
 }
</style>
```
こうすることで0.5秒でそれぞれ動作するという設定になるようです。
こんなに簡単にアニメーションを使えるなんて、すごい！

#読み終わり
Vue.jsを知らない人としては、はじめのとっかかりとしてはわかりやすく書かれていて
読み終えた時には「Vue.jsを使ってこういうものを作ってみたい」などやる気が出ました。

今後Vue.jsを使って引き続きフロントのページを作っていきたいと思います。
gcloudでGAEをデプロイする際にservice accountに本当に必要な権限

執筆時点で、日本語・英語・公式ドキュメント・各種Q&Aサイトどこにもまとまっていない、あるいは間違っているのでまとめました。

## 素朴に「AppEngineデプロイ担当者(roles/appengine.deployer)」を渡す

権限が全く不足しています。
なんでこんな命名にしたんだ。

## [公式ドキュメント](https://cloud.google.com/iam/docs/understanding-roles?hl=ja#cloud-storage-roles)
こちらによると、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530822/10b296a4-030a-9bca-32c7-0e751191aa43.png)

- AppEngineデプロイ担当者(roles/appengine.deployer)
- サービスアカウントユーザー(roles/iam.serviceAccountUser)
- Computeストレージ管理者（roles/compute.storageAdmin）
- Cloud Build編集者(roles/cloudbuild.builds.editor)

があれば、gcloudからでも、新しいバージョンをデプロイできそうですね。
ですが、公式ドキュメントも誤っています。

## [StackOverFlow](https://stackoverflow.com/a/59662880)のある回答
- `storage.objects.list`が必要なため、「Cloud Build編集者(roles/cloudbuild.builds.editor)」では不十分であり、「Cloud Buildサービスアカウント(roles/cloudbuild.builds.builder)」が必要
- デプロイ後、トラフィック分割の権限が必要なため、「App Engine サービス管理者(roles/appengine.serviceAdmin)」が必要

とのことですね。

ただし、こちらの回答では時期が2020年1月なためか、「サービスアカウントユーザー(roles/iam.serviceAccountUser)」についての記載が不足しています。


## 加えて、Cloud Memorystore等を使用する場合
GAEからVPCネットワークを利用してCloud Memorystore等にアクセスする場合、「サーバーレスVPCアクセスユーザー(roles/vpcaccess.user)」が必要になります。


## 結論

### 常に必要
- AppEngineデプロイ担当者(roles/appengine.deployer)
- App Engine サービス管理者(roles/appengine.serviceAdmin)
- サービスアカウントユーザー(roles/iam.serviceAccountUser)
- Computeストレージ管理者（roles/compute.storageAdmin）
- Cloud Buildサービスアカウント(roles/cloudbuild.builds.builder)

### optional
- サーバーレスVPCアクセスユーザー(roles/vpcaccess.user)

以上です。
こちらで執筆時点では問題なくデプロイできましたが、自分もGCPに不慣れなため、過不足等ございましたら指摘いただけますと助かります。
Ruby on rails〜NoMethodErrorの解決〜

###NoMethodErrorが出た！！！
メソッドが定義されていないよ、というエラー。

**＜エラー画面＞**
![スクリーンショット 2021-03-17 16.19.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/782402/b389c3e3-f48f-76a4-2096-6a1e48352c55.png)

ItemsControllerにuser定義されてないんじゃないの？と言われた。

ItemModelにuserが存在していることを確かめてみる。

**＜Item.rb＞**
![スクリーンショット 2021-03-17 16.20.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/782402/dceb0836-449c-0044-1ad4-dff0eff7686c.png)


うん。ちゃんといますね。

一応データベースもみてみる。

**＜itemのデータベース＞**
![スクリーンショット 2021-03-17 16.21.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/782402/093885ad-2941-27f3-cc8d-dc57fde0f745.png)

おやおや？？user_id？？userどこいった？？
となりました。

そこで、マイグレーションファイル見てみます。
![スクリーンショット 2021-03-17 16.20.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/782402/71cabaa2-a4ff-f368-a468-d718a84dd0cf.png)

userだよな。。。？

しかし！型名はreferences!
references型で設定すると勝手にidが付与される仕組み。
そのため、データベースではuser_idに変わっていた。

と、いうことは、モデルに記述する時もuser_idにしなくては通らない！
ということで・・・

**＜item.rb抜粋＞**
![スクリーンショット 2021-03-17 16.35.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/782402/5d25085d-0772-f07b-c69a-75b99e220937.png)

こう変えたらするっとエラー解決できました！！！

以上。
ターミナルで移動してみよう！

基本的なディレクトリー構造がわかったところで、実際にターミナルで移動していきます。

#lsコマンド
ターミナル起動時、command+spaceでターミナルと打ち込むと開くことができます。
ターミナル起動時、『~』波括弧があるかと思います。これは、今ホームディレクトリーにいますよ〜って意味です😊

```
% ls ディレクトリーを表示してくれます。
% ls -a 隠しファイルを表示してくれます。
% ls -l ディレクトリとファイルの一覧それぞれの詳細表示をしてくれます。
% ls -la 隠しファイルも含めて詳細情報を表示してくれます。
```
#cdコマンド
カレントディレクトリーといいます。フォルダ移動の場合に使います。
カレントディレクトリーとは、簡単に言うと今作業しているフォルダーのことです。

```
% cd Documents ドキュメントディレクトリーに移動します。
% cd ~ ホームディレクトリーに移動します。
% cd .. １つ上のディレクトリーに移動します. ドット２つでひとつ上の階層に移動することになります。
```

#pwdコマンド
これはルートから対象とするディレクトリー及びファイルまでの絶対パスを言います。

![スクリーンショット 2021-03-17 16.28.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1033397/362c30b5-5d86-450e-f781-b1efef29e1b8.png)

下に表示されているのがデスクトップからの絶対パスになります。
HMSの学習方法

# HMSの学習について
次の４つをそろえればよいです。

- HMS開発者アカウント
- HMS学習材料
- HMSの開発環境
- HMSのデバッグ・テスト環境

# HMS開発者アカウント
リンク（画面の右上の[Sign up]をクリック）：

https://developer.huawei.com/consumer/jp/

まずHMS開発者登録をします。開発者アカウントがあれば、[HMS Toolkit](https://developer.huawei.com/consumer/jp/huawei-toolkit/)や[AppGallery Connect](https://developer.huawei.com/consumer/jp/agconnect/)も使えるので、それを触りながら勉強したほうがより早く学べます。

# HMSの学習材料
- 公式ドキュメント
- 公式ビデオ
- HUAWEI Developer Forum
- HUAWEI Codelabs

### 公式ドキュメント
リンク：

https://developer.huawei.com/consumer/jp/doc/overview/HMS

公式ドキュメントに各キットの説明ガイド、APIリファレンス、サンプルコードが全部含まれています。

まず、勉強したいキットの説明ガイドを読み、キットの機能や特徴、基本的な実装方法を習う。より細かいカスタマイズをするときにAPIリファレンスを参照する。キットを体験したい場合はサンプルコードをダウンロードし実行する、といった系統的な学習が可能です。

また、HMSはAndroidだけではなく、キットによりますが、React NativeやCordova、Xamarin、Flutterをサポートするものもあり、それらの説明ガイド、APIリファレンス、サンプルコードも公式ドキュメントに載っています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704548/025b702d-ac4f-8030-aa3a-006296d122be.png)

### 公式ビデオ
YoutubeにHuawei Developersのチャンネルがあります。このチャンネルにHMS関連の動画が大量にあります。
リンク：

https://www.youtube.com/c/HuaweiDevelopers/featured

また、目的に応じて、次の3種類にまとめられています。

キットの概要説明：

https://www.youtube.com/hashtag/hmscoreintro

キットの簡単な実装手順：

https://www.youtube.com/hashtag/hmstips

キットの詳細説明と実装手順：

https://www.youtube.com/hashtag/hmsacademy

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704548/dc8958e8-036b-143c-bc62-25f8260a866b.png)

### HUAWEI Developer Forum
リンク：

https://forums.developer.huawei.com/forumPortal/en/home

HUAWEI Developer ForumはHMS開発者が集まり、様々な意見やソリューションをディスカッションするコミュニティです。

HMS実装中に様々な問題にぶつかると思います。Stack Overflowで調べるのもよいですが、[HUAWEI Developer Forum](https://forums.developer.huawei.com/forumPortal/en/home)で調べることもおすすめします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704548/a2bd9250-79c0-942f-f40c-4da9b66f89ad.png)

### HUAWEI Codelabs
HUAWEI CodelabsはHMS実装手順の紹介に特化したウェブサイトです。公式ドキュメントの説明ガイドと比べて、HUAWEI Codelabsの説明は、AppGallery Connectの準備やbuild.gradleの設定、ソースコードの中身など、全体的な実装の流れが各実装ステップにまとまっており、より分かりやすいし、実践的だと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704548/137a008c-3ac8-2ae4-8404-ac9e7a453650.png)

# HMSの開発環境
Android Studioさえあれば、HMSのコーディングができます。[HMS Toolkit](https://developer.huawei.com/consumer/jp/huawei-toolkit/)は必須ではありません。ただ[HMS Toolkit](https://developer.huawei.com/consumer/jp/huawei-toolkit/)にいろいろ便利な機能があるので、合わせて使えば開発の効率が高まります。

HMS Toolkitについて、こちらの文章をご参照ください：

https://qiita.com/Kirin9000/items/8b4e59c27146e2a31f38

# HMSのデバッグ・テスト環境
Androidアプリのデバッグ・テストは実機かエミュレータで行います。ところが、ファーウェイはHMSのエミュレータを提供していません。その代わりに、HMSの[クラウドデバッグ](https://developer.huawei.com/consumer/jp/agconnect/cloud-adjust/)を提供しています。詳しくはこちらのページをご参照ください。

https://qiita.com/Rei_2020/items/6d0291f77d25b1722e22
【Node.js Express 4.x で Routing Middleware Template(pug) をつかう方法】

Expressでは簡単にルーティングができるが、色々方法があって忘れる。
ということでここでいったんまとめていく

Expressのversionは4系です

#####同じパスに対して複数のハンドラがあるとき

```js:app.js
const express = require('express')
const app = express()

app.route('app/user')
	.get(req, res) => {}
	.post(req, res) => {}
```

#####特定のパス以下のルーティングをまとめるとき

```js:routes/user.js
const express = require('express')
const router = express.Router()

router.get('/', (req, res) => {})
router.get('/edit', (req, res) => {})
router.get('/delete', (req, res) => {})
```

```js:app.js
const express = require('express')
const app = express()

app.use('app/user', (require('./routes/user')))
// app/user以降のパスがroutes/user.jsで指定されているとおりに設定される
```
* * *
#####ミドルウェアの使い方
`app.get()` も`app.set()`もミドルウェアに当たるため、処理をnext()で委譲できる。

#####・特定のパスにミドルウェアを適用する方法

```js:app.js
const express = require('express')
const app = express()

function Middleware(req, res, next){
  console.log('checked Middleware function !!!!')
	next() 
}
// checked Middleware function !!!! を出力後、処理をnext()で委譲している
app.get('app/user', Middleware, (req, res) => {
    res.end()
}
```

#####・アプリケーションレベルのミドルウェアを利用する方法

委譲（next）はuse→getでもget→useでもuse→useでもget→getでもできる。
引数にnextを追加することだけ気をつける。

```js:app.js
const express = require('express')
const app = express()

app.use('app/user', (req, res, next) => {
    console.log('middleware!!!!!!!!!!')
    next()
})
app.get('app/user', (req, res) => {
    res.render('rooms', { title: 'rooms' })
})
```
* * *
#####・テンプレートエンジン（ここではpug）を使う方法

"view engine"をsetして、このファイルと同じ階層にviewsディレクトリを作れば、viewsディレクトリをルートディレクトリとして操作できる。

```js:app.js
const express = require('express')
const app = express()
app.set("view engine", "pug") 

app.get('/room', (req, res) => {
	res.render('room')     // パスが/views/room.pugの場合
	res.render('html/room')// パスが/views/html/room.pugの場合 
})
```

#####・静的ファイルも配信する方法

上記のままではcssやjavascriptファイルが読み込めていないので以下コードを追加

```jsx
app.use(express.static(__dirname + '/views'))
```
* * *
#####・その他、`app.set()`でできる設定たち（他にもいろいろある）
[https://expressjs.com/ja/api.html#app.set](https://expressjs.com/ja/api.html#app.set) ここで確認

```jsx
app.set("case sensitive routing", true or false) 
// routingの際、大文字小文字の区別を有効にするかどうか

app.set('env', 'production')
// 環境モード 本番ではproductionにする

app.set('trust proxy', true or false)
// プロキシを介したHTTPリクエストでも情報を保持できるようにする
```
Rails 超簡単 並べ替え機能 ソート検索 (古い順・最新順)

#  はじめに
筆者は [大学生限定 プログラミングコミュニティ 『GeekSalon』](https://geek-salon.com/?utm_source=Direct&utm_medium=attract&utm_campaign=2Q&utm_content=Fukuoka_E_2Q)で活動している者です！ 
もし少しでも興味がありましたら、ぜひお話を聞きにきてくださいね♪


では本題。
YouTubeでよく人気順に並べ替えたり、最新の動画順に並べ替えたりしますよね！？！？

意外とこの部類の記事がなかったので、今回は似た機能を実装してみたので紹介しやあす！！
(いいね順はいいねを実装するのがちょっとめんどくさいので後ほど更新いたします、、、やってることは同じで応用するだけです)

もっとハイテクなやり方があるかもしれませんが、初心者でもできるような簡単なやり方で実装しています、ご理解くださいませぇ。
#STEP1

viewで使うためにコントローラーで並べ替えた投稿を変数に代入します。
この時、条件分岐によって並べ替え検索の下準備をします。

```ruby:posts_controller.rb
  def index
    if params[:search] == ''
      @posts= Post.all.order(id: "DESC")
    elsif params[:search] == 'newpost'
      @posts= Post.all.order(id: "DESC")
    elsif params[:search] == 'oldpost'
      @posts= Post.all
    end
  end
```

``` @posts= Post.all.order(id: "DESC")```は上からidが大きい順、つまり最新の投稿順にソートするためのコードです。


条件分岐を言葉で上から解説すると、、、

もし並べ替え検索欄に空文字が含まれている、つまり特に検索されていなければ最新順にソートした全ての投稿を```@posts```に代入
もし並べ替え検索欄にnewpostという文字列が送られたら、最新順にソートした全ての投稿を```@posts```に代入
もし並べ替え検索欄にoldpostという文字列が送られたら、古い順にソートした全ての投稿を```@posts```に代入

#STEP2
並べ替え検索のviewページを整えましょう。

```erb:posts/index.html.erb
 <h3>並べ替え</h3>
 <%= form_tag({controller:"posts",action:"index"}, method: :get) do %>
   <%= select_tag("search", options_for_select([['---並べ替え選択---', ''], ['最新の投稿', 'newpost'], ['古い投稿', 'oldpost']])) %>
   <%= submit_tag '並べ替える'  %>
 <% end %>

  <% @posts.each do |t| %>
      <%= t.body %>
      <%= t.created_at %>
  <% end %>
```

```select_tag``` を使って、特定のvalueを送っているのがミソですね！

#最後に
いかがでしたでしょうかああああ

結構雑に書いちゃった&&いいね順めんどくさがってしまったので、時間取れた時にまた改修いたします🙇‍♂️

現段階で補足修正等ございましたら、編集リクエスト送ってくださいまし。

それではバイちゃ〜〜👋
Herockにgitがpush出来ない時の対処法

#Herockにgitをpushしようとするとエラーが

```
$ git push herock master

fatal: 'heroku' does not appear to be a git repository
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
```

要約するとherockにリモートリポジトリねえよ💢と怒られている。

以下のコマンドで登録しているリモートリポジトリを見てみると…
【注意】sampleは各自ディレクトリ名に置き換える

```
$ git remote -v


origin	https://github.com/sample/sample.git (fetch)
origin	https://github.com/sample/sample.git (push)

```
まさかのherockがリモートリポジトリに登録されていない……orz

#Gitにherockを登録する

このエラーはherockをリモートリポジトリとしてgitに登録する事
で解消します。

gitディレクトリ下のconfigファイルを見てみましょう。

以下のコマンドで.gitディレクトリ下のconfigファイルを見ることが出来ます。

```
$ cd .git
.git/ $ vi config
```
```
[remote "origin"]
        url = https://github.com/sample/sample.git
        fetch = +refs/heads/*:refs/remotes/origin/*

```
やはりconfigファイルにもherockがリモートリポジトリとして登録出来ていない!!!

以下のコマンドを入力してリモートリポジトリにherockを登録しましょう!!!
 
```
git remote add heroku https://git.heroku.com/sample.git
```
すると……

```
[remote "heroku"]
        url = https://git.heroku.com/sample.git
        fetch = +refs/heads/*:refs/remotes/heroku/*
[remote "origin"]
        url = https://github.com/sample/sample.git
        fetch = +refs/heads/*:refs/remotes/origin/*
                                                      
```
configファイルにherockが登録出来たのを確認出来たらherockにgitをpushしてみましょう。
UNIX~ディレクトリー構成~

ディレクトリー構成について学習していきます。
ディレクトリーとはパソコンのフォルダのことです。
MacではFinderで開きます👍 またこれらはツリー構造になっていて、ディレクトリーの中に新たに新しいディレクトリーがはいっている感じです。
いくつか構成要素があります。

#ルートディレクトリ−(/)
これを最上位のディレクトリーになっています。　この中には、パソコンの設定ファイルなどが入っています。　パソコンの命みたいなところですね。

#ホームディレクトリ−

これはユーザーごとに作られたディレクトリーになっています。それぞれDocumentsやDesktopなどを含みます。
画像引用▶https://webya.in/blog/2016/11/03/unix-command-for-biginner/
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1033397/d6b6844c-53dd-37ee-2130-31794c6ebc52.png)


![スクリーンショット 2021-03-17 15.41.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1033397/edefa628-4480-3202-7cf0-77303cef9d73.png)

ルートディレクトリーは上記になります。

主に私達が使うのは、/userかなと思います。

では、ターミナルで実際にみていきましょう！！


```
% cd / 　ルートディレクトリへ移動する
% ls /　中身を表示
```
![スクリーンショット 2021-03-17 15.47.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1033397/6657a22d-1b78-32f6-afb3-53c301a6cd70.png)
これでターミナル上でルートディレクトリを開くことができます。

```
% cd ~ ホームディレクトリーへ移動
% ls ~ 中身を表示する
```
![スクリーンショット 2021-03-17 15.50.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1033397/368943c7-deca-4a61-3420-d449a547ff25.png)

中身を表示することができます👍
英語論文の読み方 By大学4年間英語から逃げた者

昨年の初夏に書いてずっと眠ってた下書きを今更投稿してみる

###読む人(ターゲット)
▶英語全然できないけど、英語論文読まなきゃいけない
▶英語論文と聞いただけでアレルギー反応が出
**英語できる人は読まないでw**

#大学院は英語論文を読むことは必須
学部生の時は日本語の論文だけで研究に支障ありませんでしたが、**院に入ってから英語論文はどうしても読まないといけません**。
私は、ジャンルでいうと情報系の大学院の社会科学系の研究室に所属していますが、海外論文はもちろん、国内の論文も英語で書かれているものがたくさんあります。

しかし...
私は学部生4年間英語から逃げてしまいましたw

だとしても研究の為に英語論文を読むことは必須です。

###よっしゃ英語論文読むぞー！！
論文を印刷し、筆記用具と辞書を準備して、さっそく英語の受験勉強のように、読んでみました。
けど要約を読む時点で...
**あっもう無理、やっぱり英語無理だわ**
とすぐに心が折れました

受験勉強のように読んでも時間がかかるし、やってやれません。

それでも英語論文から逃げる事はできないので、インターネットで色んな人たちの英語論文の読み方を見て、自分なりの方法をなんとなく確立させ、今はなんとかですが、読んでいます。

前置きは長くなりましたが、そこで私が今英語論文を読んでいる方法をまとめてみたいと思います。

#私の英語論文の読み方
##選定(←英語苦手な人にとってすごく大事だと思う)
当たり前ですが、論文を読む時、自分の研究あるいは興味のある論文をどんどん読んでいくと思います。僕も日本語論文だったら、興味あれば片っ端から読んでいくようにしています。

しかし、英語苦手な人にとって英語論文を読むという作業は、時間も体力もけっこう使います。
ですので、気になる論文がある場合は、まずabstract(要約)見てみましょう。(実際の英語の読み方は下で説明している)そして研究に関係ありそうか、もっと知りたいか、感覚で選んで、絞ってしまいましょう。

日本語論文でもこの作業は当たり前ですが、**英語が苦手な人にとっての英語論文はこの選定作業がめっちゃ大事だと思います。**たくさん読む体力はないので。
もちろん英語に慣れていけば読む論文の数をどんどん増やしていくべきだと思います！

##じゃあどうやって英語読むか
これはよく言われている事だと思いますが、論文を読む順番とどこを翻訳機能に頼り、どこは自分で読むか決めて読むべきだと思います。
翻訳機能にすべて頼ってしまうと、英語論文がいつになっても読めるようにはならないので、私はせめてabstractと結論は自分で頑張って読むようにしています。
以下は私の読む順番です。

abstract (自分で頑張って読む)

▼ (興味ない関係ない論文だったら、やめる)

結論(自分で頑張って読む　やる気出ないときは翻訳機能)

▼ (読みたいと思ったら、引き続き読む)

内容(翻訳機能)

という形で読んでいます。

翻訳機能は、[shaper](https://dream-exp.net/shaper/)を利用しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/297375/c9700ab4-703e-a035-c159-2c6f102a5cb7.png)

PDFの論文などからそのままコピペして翻訳機能に持っていくと、どうしても段ずれを起こしてしまい、正しく翻訳されません(逆に今は段ずれが起こらなければ、ほぼ正しく翻訳されます。テクノロジーの進歩凄い)

このように私は翻訳機能も活用させつつ、大嫌いな英語論文を読んできました。
**shaperの製作者には感謝いっぱいですm(__)m**

#おわりに
以上が英語苦手な私の英語論文との戦い方でした。
あくまでもこれは私のやり方で色んな考え方があるので、色々試してみて、自分なりのやり方を確立させましょう！
あと、せっかくこんなテクノロジーが発達して、便利な時代になったので、辞書片手に真っ向勝負を挑むのは、英語苦手な人は絶対にやめましょう

いつか英語論文辞書なしですらすら読めるようになりたい！！！

**みなさんの英語論文の読み方、おすすめ、ご意見ありましたら、ぜひコメントお願いします**



追記(2021.3.17 修士1年がそろそろ終わりそう)
このやり方でやってみて、今は少しだけ英語論文が読めるようになった上に、英語論文のアレルギーがなくなっていきました。英語のツイッターをフォローして、英語を普段から読むようにすれば、英語への苦手意識はなくなったような。
後は自分の専門の論文なら、構成やよく出てくる単語が分かってきたので、なんとなく読めるようになっていきました。引き続き頑張ります！
【Python】ファイルの入出力

#はじめに
三日前からPythonについて学習し始め、ファイルの出力についての内容があったので
備忘録として記事にしておくことにしました。

いつかは、AIやデータ分析なども行いたいので、
その結果をファイルに出力する時がくるかなと思ったので・・・。

かなり初心者なので優しい目でご覧ください！

#ファイル出力方法

まずはじめに今回出力するファイル名が存在しないかを確認しておきます。

私のプロジェクトの配下は次のようになります。
（勉強で作ったフォルダなどがありますが気にしないでください！）
![スクリーンショット 2021-03-17 15.21.45.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/797483/3fb7b4de-3f4b-61b3-d945-a674cb5c3d76.jpeg)

今回は`test.txt`というテキストファイルを作成しようと思います。

メインのファイル（言い方があっているかわかりませんが、`__main__`のやつです！）に
下記のコマンドを記載し実行します。

`f = open("test.txt", "w")`は、
ファイル名「test.txt」に「write」（書き込み）してください。
といった意味のコマンドだと思います。

`f.write("test")`は実際に書き込んでいる内容です。

`f.close()`で書き込みを終了します。

```python
f = open("test.txt", "w")
f.write("test")
f.close()
```

これを実行すると、ファイルが作成されているのがわかります。
![スクリーンショット 2021-03-17 15.27.14.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/797483/cb0aba11-5a5d-6180-c837-fa53e1f80ad1.jpeg)
中身にはもちろん`test`の記載がありました。

また、`f.close()`を書かなくても自動でcloseしてくれる
`with`というステートメントがあるらしいので追記しておきます。
（@shiracamus さんありがとうございます！）

```python
with open("test.txt", "w") as f:
    f.write("Test\n")
```

ちなみに`w`だと、毎回上書きするので、
追加したい場合は`a`のappendというオプションを使用すれば追加できます。

```python
with open("test.txt", "a") as f:
    f.write("Test\n")
    f.write("Test\n")
```

出力結果は下記のようになります。

```
Test
Test
```

#さいごに

プログラムを実行する前に`f = open("日付.log", "w")`と記載して
プログラム終了時に`f.close()`を記載すれば、
そのプログラムのログを作成できるのかな？とか思ったりしました！

もしかしたら今後もっと便利なコマンドを学習するかもしれないので楽しみです。

また何か大切そうなことを学んだら備忘録として投稿しようと思います。

以上、最後までご覧頂きありがとうございました！
【Unity】TextMesh Pro を日本語対応した話

フォントの設定を何もしていない状態だと、TextMesh Proで日本語（全角）での入力時にFontに無い文字が文字化けします（豆腐になった）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175894/010e6de4-1129-241c-a131-7682e5e5f9c5.png)

日本語のフォントを使用する場合は、以下の手順で設定が必要です。
※設定の詳しい説明はこの記事ではしません。あくまで最短で設定する手順です。

## 日本語フォントをダウンロードして配置する

フォントを準備します。
ProjectのAssetsにダウンロードしたフォントファイル（.ttfか.otf）を配置します。
フォルダはTextMeshProのResourceフォルダ以外であれば、どこでもいいです。

[日本語フォント一覧](https://coliss.com/articles/freebies/japanese-free-fonts.html)
私は[こちら（源ノ明朝）](https://github.com/adobe-fonts/source-han-serif/releases/download/1.001R/SourceHanSerif.ttc)のフォント使用しました。

## フォントをUnityで使用できるように設定する

メニューの「Window」>「Text Mesh Pro」>「Font Asset Creator」でダイアログを開いたあと、以下の手順で設定します。

1. 「Source Font File」で先ほどダウンロードしたフォントファイルを選択します。
2. 「Atlas Resolution」を（8192*8192等）大きめに取ります。
3. 「Character Set」を「Custom Characters」に変更します。
4. 「Custom Character List」に対応したい文字コードを入力します。
5. 「Generate Font Atlas」をクリックし、生成処理を実行します。※かなり時間がかかった

4.の文字コードには以下のgistで公開されている文字をコピペして貼り付けます。
ありがたし。。

[日本語文字コード](https://gist.github.com/kgsi/ed2f1c5696a2211c1fd1e1e198c96ee4#file-japanese_full-txt)
### 設定イメージ（完了後）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175894/6bd7d077-2421-57e1-9a0e-2a1a52402979.png)

completedになったら、Saveでフォントを保存します。

## TextMesh Pro のコンポーネントでフォントを読み込む

TextMesh Pro を追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175894/54981ecd-fc50-790c-5a25-27f767146aa1.png)

表示するだけであれば、テキストを入力し、Font Assetに先ほど作成したフォントを指定して上げればOK。
![2021-03-17_152310.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175894/0ea8b181-73ab-f4ed-8937-bbe67d572f7c.png)

表示されました。お疲れ様でした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175894/da16526c-caa5-f80d-af5a-7592f3daf45b.png)
Laravel6系以上でもbootstrapを使いたい！

[【mac】MAMPでLaravelを導入する方法](https://qiita.com/kuroudoart/items/366e42d606764b46da7f)

上の記事ではLaravel6系以上のバージョンを導入していたため、bootstrapが使えませんでした。

こちらの記事では[前回](https://qiita.com/kuroudoart/items/366e42d606764b46da7f)の続きとして、Laravel6系以上を導入した環境でbootstrapを使えるようにしたいと思います。

#やることは簡単
①まずはプロジェクトフォルダへ移動してください。
※この記事ではプロジェクト（フォルダ）名を「project」としています。

```コンソール
$ cd /applications/mamp/htdocs/project
```

②以下のコマンドを入力すると残りは簡単です。
下記コードの3.2.0のバージョンは自力で調べてください。
適当な場所で「$ composer require laravel/ui --dev」を実行すれば、コンソールのログで「Using version ~3.2」とか出るはずです。確認が取れたら生成されたフォルダなんかはゴミ箱へポイしてください。
自分の場合はこの方法バージョンを調べて使いました。
荒技（邪道？）なのは承知しているので、スマートな方法を知ってる方は教えてください。

```コンソール
$ composer require laravel/ui "3.2.0" --dev

#問答無用で最新版を入れる場合は
composer require laravel/ui
```

③bootstrapを入れてみましょう。

```コンソール
$ php artisan ui bootstrap
```

④オマケ：vueとreactもついでに入れちゃいましょう

```コンソール
$ php artisan ui vue
$ php artisan ui react
```

ここまででエラーを吐かれてなければ無事に作業が完了しました！
さあ、お好きなだけBootstrapで遊んでください。

**乙したー**
秋月で買えるCO2センサーを使う(MH-Z19C)

[秋月電子で取り扱いの始まったCO2センサーMH-Z19C](https://akizukidenshi.com/catalog/g/gM-16142/)をArduino Nano Everyで使ってみました。

# MH-Z19Cについて
MH-Z19CはNDIR方式のCO2センサで、電源電圧は5.0±0.1V、データの出力はPWMかUART(3.3Vで5.0Vにも対応)です。測定できる範囲はPWMを使うと公称値は400~2000ppm(実測では400~5000ppm)、UARTでは400~5000ppmです(CO2濃度は大気中で約400ppm、室内で約1000ppm、呼気で約30000ppmが目安)。ピンヘッダは2.54mmピッチですが、ピンヘッダとピンヘッダとの間隔が合わずユニバーサル基板に挿すのは難しいので注意してください。

ここでは5V駆動のArduino Nano Everyを使い、PWMとUART両方のデータを読んでみます。

# ハードウェア
## 使ったもの
* MH-Z19C
* Arduino Nano Every
* 5Ｖ出力昇圧DCDCコンバーターとコンデンサー

Arduinoの5V OUTピンの電圧を測ると4.72-4.78Vでセンサーの電圧の範囲から外れていたので、一応4.9~5.1V出力(実測4.98V)の[DCDCコンバーター](https://akizukidenshi.com/catalog/g/gK-13065/)と100μFのコンデンサーをつけました。

## 接続
| MH-Z19C ||
|:-----------|:------------|
|Vin|DCDCコンバーター ← Arduino 3.3V|
|GND|Arduino GND|
|PWM|Arduino A7|
|Hd|Arduino A6|
|Rx|Arduino TX1|
|Tx|Arduino RX1|

# ソフトウェア
## MH-Z19Cの仕様
データシートは[ここ](https://akizukidenshi.com/download/ds/winsen/MH-Z19C.pdf)で読めます。以下の画像はデータシートのものです。
### UART
UARTでCO2濃度の読み取りと自動キャリブレーションの設定ができます。
### PWM
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208257/69675cf3-7216-c5a9-9594-110f1c4e8b08.png)
データシートでは上のようになっていますが、Cppm=5*(パルス幅[ms]-1.2)とするとUARTと同じデータが読み込めました。Arduino Nano EveryのpulseInかセンサーのPWM出力のどちらかが原因だと思います。
手動キャリブレーションはHdピンを使うのでPWMでもできますが、自動キャリブレーションの設定はPWMだけではできません。デフォルトでは24時間ごとに自動キャリブレーションが行われます。(キャリブレーション時にどんな濃度でもそれを400ppmと認識するのではなく、24時間経ったあたりで400ppmに近い状態と判断するとキャリブレーションを行うようです)

## プログラム


```c
uint16_t uartco2; 
unsigned long pwmco2;
bool reset = false;

byte ReadCO2[9] = {0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79};
byte SelfCalOn[9]  = {0xFF, 0x01, 0x79, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xE6};
byte SelfCalOff[9] = {0xFF, 0x01, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86};
byte retval[9];

void setup() {
  pinMode(A7, INPUT);
  pinMode(A6, OUTPUT);
  Serial.begin(9600);
  Serial.print("400ppm");
  Serial.print(",");
  Serial.print("UART");
  Serial.print(",");
  Serial.println("PWM");
  delay(2000);
  Serial1.begin(9600);
  Serial1.write(SelfCalOn,sizeof SelfCalOn);
}


void loop() {
  //PWMでデータ取得
  pwmco2=pulseIn(A7,HIGH,2000000);

  //UARTでデータ取得
  Serial1.write(ReadCO2,sizeof ReadCO2);
  Serial1.readBytes((char *)retval, sizeof retval);
  uartco2 = retval[2]*256 + retval[3];

  //PCに送信
  Serial.print(2*(202000-2000)/1000);
  Serial.print(",");
  Serial.print(uartco2);
  Serial.print(",");   
  Serial.println(5*(pwmco2-1200)/1000);

  delay(100);

  //起動20分後手動キャリブレーション
  if(millis()>1200000 && !reset){
    digitalWrite(A6,LOW);
    delay(8000);
    digitalWrite(A6,HIGH);
    reset=true;
  }
}
```

# 測定結果
Arduino IDEのシリアルプロッタを使って可視化しました。縦軸がCO2濃度[ppm],横軸が起動からの時間(1が100ms)です。

* 換気したとき
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208257/26a6ede1-6a87-bba8-df30-cd756dd5232c.png)


* 人が部屋に入ってきたとき
横軸1600ぐらいで部屋に入っています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208257/646f574e-a02c-ac7e-fe3c-337d7f1c5ff0.png)

* 直接息をふきかけたとき
息をふきかけた直後に値が上昇しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208257/f1dd1eb6-597e-151e-cab9-78d649b83498.png)
RubyonRails再学び直し2 -rail sできない-

https://qiita.com/kadaiho23/items/d7e04b9bfbacf676a3d8
と同じ現象が。

```
Webpacker configuration file not found ~
Please run rails webpacker:install Error: No such file or directory
```

`rails webpacker:install`でいけました。
【Kotlin 初心者】スプラッシュ画面の作り方

## Kotliでスプラッシュ画面の作り方について
そもそもスプラッシュとは？
アプリの立ち上げる刹那に表示される画像のことです

## イメージ
こちらのスプラッシュは私が作った<a href="https://play.google.com/store/apps/details?id=lupri.app">Lupri</a>というアプリのスプラッシュになります。
実装は非常に簡単です

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320838/9f3793b3-b539-6222-8f4b-f78b0ea0d8de.png" width=300>

## 実装方法

```AndroidManifest

        <activity android:name="MainActivity"
            // themeを追加する
            android:theme="@style/AppTheme.Splash">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
```

```
<resources>
    <style name="AppTheme.Splash" parent="Theme.AppCompat.DayNight.NoActionBar">
        // あらかじめdrawableに表示するスプラッシュ画像を用意する
        <item name="android:windowBackground">@drawable/splash</item>
    </style>
</resources>

```
MAMPのバーチャルホストで複数プロジェクトをラクラク管理（方法１）

# もくじ
[はじめに](#はじめに)
[バーチャルホストとは？](#バーチャルホストとは？)
[MAMPのバーチャルホストを設定する](#MAMPのバーチャルホストを設定する)

# はじめに
もしこの記事でうまくいなかい場合は、こちらの記事「[MAMPのバーチャルホストで複数プロジェクトをラクラク管理（方法１）](https://qiita.com/kuroudoart/items/6eb9cec576df19d46a03)」を参考にしてみてください。

# バーチャルホストとは？
MAMPで複数プロジェクトを管理している人（初心者限定？）によくあることですが、
**「htdocsにindex.htmlやstyle.cssなんかをおいてホームページを仮想環境で制作しましょう！」**
という初心者向きの記事を鵜呑みにすると、
**「あれ？ということはmampで作れる（管理できる）プロジェクトは１つしか無理なの？」**
という疑問に当たります。

そこから次に行く着くのが、
**「htdocsの中にプロジェクトごとのフォルダを作って、その中にhtmlとかcssを置けば、localhost:8888/プロジェクト名でいくらでも管理できるじゃん！」**
という考えです。

**<font color="red">はい、間違いです。</font>**
今すぐその認識を捨てましょう。

wordpressじゃなくても良いんですが、生のPHPで現在のURLを取得して、何かしらの判定処理をしようとしたとき、

```test.php
$_SERVER['HTTP_HOST']
```

というコードを使った覚えないですか？

このコード自体はホスト（www.sample.com）を取得するのですが、mamp上で実行すると、「localhost:8888」しか取得できないんです。

「ほしいのは **"localhost:8888"** じゃなくて **"localhost:8888/example"** なんだ！！！！」

まさに自分のことなんですが、こんなしょうもないことで躓いてほしくないので、備忘録も兼ねて、ちゃんとした複数プロジェクトの管理方法をここに残します。

# MAMPのバーチャルホストを設定する

まずは「**/mamp/conf/apache**」から「**<font color="red">httpd.conf</font>**」と「**<font color="red">extra/httpsd-vhosts.conf</font>**」を開きましょう。

わざわざVSCodeとかで御大層にやる必要もないので、メインのエディターとは別に、軽量なエディターとかがあれば便利です。
自分の場合はCotEditorなるものを使ってますが、まじで起動が早いしメモリも圧迫しないので、普通に文章を書くときなんかはこちらを使ってます。
Mac：https://apps.apple.com/jp/app/coteditor/id1024640650?mt=12
Windows：https://coteditor.softonic.jp/mac

とりあえず、何でもいいので上記２つのファイルを開いてください。

**<font color="red">※失敗するとMAMPが死ぬので、この２つのファイルは前もってバックアップしておくこと！！</font>**

### ① httpd.confの
47行目付近の

```httpd.conf
# Listen: Allows you to bind Apache to specific IP addresses and/or
# ports, instead of the default. See also the <VirtualHost>
# directive.
#
# Change this to Listen on specific IP addresses as shown below to 
# prevent Apache from glomming onto all bound IP addresses.
#
#Listen 12.34.56.78:80
Listen 8888

Listen 8001
Listen 8002
#↑こんな感じで追加
```
**Listen 8888**の下に**Listen 8◯◯◯**と必要に応じて追加します。

今回は「htdocs/test」を作り、中にhtmlとかcssを置くことをイメージしてます。
wordpressでもlaravelプロジェクトでも、やることは一緒です。

続けて、576行目付近の

```httpd.conf
#Virtual hosts
#Include /Applications/MAMP/conf/apache/extra/httpd-vhosts.conf
```

のコメントを解除して保存してください。

### ② httpd-vhost.confの行末に

```httpd-vhost.conf
# 普通のサイトの場合はこちら
<VirtualHost *:8◯◯◯>
    DocumentRoot “/Applications/MAMP/htdocs/▲▲example▲▲”
    ErrorLog "logs/▲▲example▲▲-error_log"
    CustomLog "logs/▲▲example▲▲-access_log" common
</VirtualHost>

# Laravelの場合はこちら
<VirtualHost *:8◯◯◯>
    DocumentRoot "/Applications/MAMP/htdocs/▲▲laravel▲▲"
    ErrorLog "logs/▲▲laravel▲▲-error_log"
    CustomLog "logs/▲▲laravel▲▲-access_log" common
</VirtualHost>
```

を追加します。

※▲▲〜▲▲で囲われたところは任意の文字列に置き換えてください。
logs/にログファイルが生成されます。

8◯◯◯は①で追加した「**Listen 8◯◯◯**」と同じ番号を、▲▲▲は「**プロジェクトごとのフォルダ名**」を入力してください。

保存したらMAMPを再起動して、「localhost:8◯◯◯」でアクセスして想定通りの画面が開いたら完了です。

wordpressやec-cubeなどでも同じ用に「htdocs」直下にプロジェクトフォルダを置き、「Listen 8◯◯◯」と「```<virtualHost *:8◯◯◯></virtualHst>```」を追記するだけでいくらでも増やせます。

ec-cubeとかrubyとか、その他のプロジェクトで```<virtualHost *:8◯◯◯></virtualHst>```の記述方法を知りたければ、「mamp 」

**マジで乙したー ＼(^o^)／**
GitHubを二段階認証に変更後git cloneができないエラーの対処方法

[githubを二段階認証に変更後に起こるエラーの対処方法](https://qiita.com/sayama0402/items/670b6b650ebdd8680a0b) 
[GitHubに二段階認証を設定した後にGit操作できない時の解決策](https://qiita.com/kitoko552/items/3f45de6c876c638b690d)

でも解決しなかった点。

## git clone ができない

```
C:\git\myrepo-doc>git clone https://github.com/myrepo-doc/doc
Cloning into 'doc'...
remote: The `myrepo-doc' organization has enabled or enforced SAML SSO. To access
remote: this repository, you must re-authorize the OAuth Application `Git Credential Manager`.
fatal: unable to access 'https://github.com/myrepo-doc/doc/': The requested URL returned error: 403
```

## 解決策
https://stackoverflow.com/questions/66475833/how-to-re-authorize-the-oauth-application-git-credential-manager

> Open Credential Manager in Windows and delete the existing credential for github.com

Windows 10 における 資格情報マネージャ を開く。
`コントロール パネル > ユーザー アカウント > 資格情報マネージャー`

Windows 資格情報の以下を削除する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93824/fa6a7b7a-2aae-093a-59a9-e791ce8fb316.png)


## 関連

https://zenn.dev/yuri0427/articles/9587ae6a578ee9
Gridレイアウトで、全体を中央寄せしつつ、最終行を左寄せにする

## flexboxを使うとうまくいかない
`justify-content: center`だとこうなる。
![ 2021-03-17 14.38.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244893/7b3d8155-5b05-f74c-a59e-e7cbd18ba627.png)

`justify-content: flex-start`だとこうなる。
![ 2021-03-17 14.38.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244893/4d3cac24-faf7-1626-d9bb-399273c376a5.png)

`justify-content: flex-start`+`width`を指定+`margin: auto`だとこうなる。
![ 2021-03-17 14.40.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244893/cd4326cf-6a72-4664-3ce9-0fa38d463e30.png)

## 解決策
`display: grid`を使う

```html:html
<div class="container">
  <div class="item">item1</div>
  <div class="item">item2</div>
  <div class="item">item3</div>
  <div class="item">item4</div>
  <div class="item">item5</div>
  <div class="item">item6</div>
  <div class="item">item7</div>
</div>
```
```css:css
.container {
  display: grid;
  grid-template-columns: repeat(auto-fit, 300px);
  grid-row-gap: 20px;
  grid-column-gap: 10px;
  justify-content: center;
  width: 90%;
  margin: 0 auto;
}

.item {
  padding: 12px;
  background-color: yellow;
}
```
![ 2021-03-17 14.46.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244893/c2c7ca95-e7e2-f5bc-2702-1151d1a8ce4b.png)
![ 2021-03-17 14.47.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244893/e2b7a452-5965-bedd-e74c-fc046f7e7924.png)

<p class="codepen" data-height="265" data-theme-id="light" data-default-tab="html,result" data-user="d0ne1s" data-slug-hash="xxRNwLo" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="xxRNwLo">
  <span>See the Pen <a href="https://codepen.io/d0ne1s/pen/xxRNwLo">
  xxRNwLo</a> by d0ne1s (<a href="https://codepen.io/d0ne1s">@d0ne1s</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>


## 参考
- [【CSS】グリッドレイアウトで全体的に中央に寄せつつ最後の行の子要素だけ左寄せにする方法 - Tomcky's blog](https://tomcky.hatenadiary.jp/entry/2018/03/16/000550)
【Kotlin 初心者】IntentでWebUrlにと遷移する方法

## KotlinでWebUrlに遷移する方法について
Intentと同じ要領でurlをパースして上がればいけますね

## 実装
```MainActiviy.kt

        viewBinding.button.setOnClickListener {
            val context = viewBinding.root.context

            Intent(Intent.ACTION_VIEW).also {
                val url = "https://www.google.co.jp"
                it.data = Uri.parse(url)
                context.startActivity(it)
            }
        }

```
Ruby on rails 〜NameErrorの解決〜

### NameErrorを解決する。

**＜今回出たエラー＞**
![b86b125e964a517319381754d011c093.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/782402/ffd21d96-1582-98fe-3806-869af37d1676.png)

NameErrorだそうです。
class名とファイル名が相違していると出てしまうError。

**＜エラーが出ている箇所のコード＞**
![スクリーンショット 2021-03-17 14.25.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/782402/1200cf1c-6fe3-d233-6fa7-c133d770de2a.png)



まずは素直にファイルをみに行く。
今回の文では、ItemStatusモデルが怪しそう。

**＜item_status.rb＞**
![スクリーンショット 2021-03-17 14.32.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/782402/9e22e200-6bde-b518-8f9e-2b7821fd581d.png)


おや？？？ファイルは "item_status" なのにclass名が "Status" になっている！！！！

ここが原因でerrorが出ていたようです。

class名をItemStatusに変更し無事エラーはなくなりました！！

以上。
dataframeから複数列の文字列を参照して、その内容に応じて新たな列にデータを入力する

前回同様、質問を書くために色々と試していたら上手く行ったので備忘録がてら投稿。

データ量が大きい場合にはもっと上手い方法がありそうな気もする……。

### 主題

表1のデータに対し、表2を参照してデータを追加し、表3のようにしたい

表1　生データ

| 時間  | 種類  |     |
| --- | --- | --- |
| 朝   | ごはん |     |
| 朝   | パン  |     |
| 朝   | パン  |     |
| 夜   | パン  |     |
| 朝   | ごはん |     |

実際の生データは左にIDが入っていて、行ごとに固有のデータ。
データ量は10万行ほど。

表2　参照表

| 時間  | 種類  | 内容   |
| --- | --- | ---- |
| 朝   | ごはん | 茶漬け  |
| 朝   | パン  | トースト |
| 昼   | ごはん | ふりかけ |
| 昼   | パン  | トースト |
| 夜   | ごはん | ごはん  |
| 夜   | パン  | 食パン  |

実際の参照表はそれなりに大きい（100行くらい）。

表3　作りたいデータ

| 時間  | 種類  | 内容   |
| --- | --- | ---- |
| 朝   | ごはん | 茶漬け  |
| 朝   | パン  | トースト |
| 朝   | パン  | トースト |
| 夜   | パン  | 食パン  |
| 朝   | ごはん | 茶漬け  |


### 解法①　参照する2列を結合して1列にした後、表2から辞書ファイルを作って変換
```python
import pandas as pd
#df=表1に該当する生データ
df = pd.DataFrame(
    data=[{'時間': "朝", '分類': "ごはん"},
          {'時間': "朝", '分類': "パン"},
          {'時間': "朝", '分類': "パン"},
          {'時間': "夜", '分類': "パン"},
          {'時間': "朝", '分類': "ごはん"}])

#df_replace=表2に該当するデータ。実際にはエクセル管理しておき、read_excelで取り出す。
df_replace =pd.DataFrame(
    data=[{'時間': "朝", '分類': "ごはん","内容":"茶漬け"},
          {'時間': "朝", '分類': "パン","内容":"トースト"},
          {'時間': "夜", '分類': "ごはん","内容":"ごはん"},
          {'時間': "夜", '分類': "パン","内容":"食パン"}])

df["内容"]=df["時間"]+df["分類"]
df_replace["変換詞"] = df_replace["時間"]+df_replace["分類"]
 #今回のケースの場合、文字列2列の組合せたものを比較するため、まず比較対象列を結合してしまう。

dict_replace = dict(zip(df_replace["変換詞"], df_replace['内容']))
 #読み込んだエクセルファイル(表2)を用いて、変換前文字列-変換後文字列を辞書ファイルに作成する

df["内容"]=df["内容"].replace(dict_replace)
 #replaceで一括変換を掛ける（データ量が大きい場合にはtolist()でリスト化してから処理したほうが多分高速）
```

### 解法②　表2が小さければ条件式を全部書いてしまうのもありか？
```python
import pandas as pd
#dataframeの作成
df = pd.DataFrame(
    data=[{'時間': "朝", '分類': "ごはん"},
          {'時間': "朝", '分類': "パン"},
          {'時間': "朝", '分類': "パン"},
          {'時間': "夜", '分類': "パン"},
          {'時間': "朝", '分類': "ごはん"}])

#条件ごとに.locを使って内容に値を代入
df.loc[(df["時間"] =="朝")&(df["分類"]=="パン"),"内容"]="トースト"
df.loc[(df["時間"] =="朝")&(df["分類"]=="ごはん"),"内容"]="茶漬け"
df.loc[(df["時間"] =="夜")&(df["分類"]=="パン"),"内容"]="食パン"

```

.locを使って条件式を全部書いてしまえばなんとかなるが、今回は表2が大きいのでこれでは面倒臭すぎて失敗。
fargate1.4にしたらコンテナのローカルIPが取れなくなった時の対応

備忘としてメモ

需要はあまりないと思いますが、fargateのプライベートIPを取得して使っているとかのケースで
問題が出る場合がありそうなので掲載します


# 概要

fargate1.4、VPCエンドポイントでの制御が追加になって便利になりましたね。
ものは試しということで1.4にあげてみたところどうやらNICが変わっているようで影響が出ました。


# 現象

keycloakをfargateにのっけて、HA構成で展開しているサービスがあります。
これをfargate1.3 → 1.4にしたところ、クラスタリングがうまくいかず同期されていないような挙動が発生。

具体的には片方でログインしたのに、もう片方のコンテナでセッションが見つからない等のような動きをし始めました。

# 原因と対応

fargate1.4からコンテナにアタッチされるNICに変更があるようです。

fargate1.3までは

```
1: lo inet 127.0.0.1/8 scope host lo\ valid_lft forever preferred_lft forever
3: ecs-eth0 inet 169.254.172.42/22 scope global ecs-eth0\ valid_lft forever preferred_lft forever
4: eth0 inet 10.1.100.187/24 scope global eth0\ valid_lft forever preferred_lft forever
```
のように `eth0` にVPCのローカルIPが割り振られています

これがfargate1.4になると

```
1: lo inet 127.0.0.1/8 scope host lo\ valid_lft forever preferred_lft forever
3: eth0 inet 169.254.172.2/22 scope global eth0\ valid_lft forever preferred_lft forever
4: eth1 inet 10.1.200.45/24 scope global eth1\ valid_lft forever preferred_lft forever
```

というように `eth1` が増えてそこにローカルIPが割り振られるようになっています。
`ecs-eth0` はなくなっていますね。

私の場合、keycloakを立ち上げる時に、クラスタリングの為にfargateインスタンスのローカルIPを取得して
keycloakに食わせています

以下のようなエントリーポイントのシェルで起動していました

```bash
export EXTERNAL_ADDR=`ip -f inet -o addr show eth0 | cut -d" " -f 7 | cut -d/ -f 1`
if [ "$EXTERNAL_ADDR" = "" ]; then
    EXTERNAL_ADDR=127.0.0.1
fi

echo "Use $EXTERNAL_ADDR for clustering."

sh /opt/jboss/tools/docker-entrypoint.sh $@ -Djgroups.bind_addr=$EXTERNAL_ADDR
```

`eth0` を取っているので fargate1.3ではローカルIPを取得できましたが、
fargate1.4ではpublic ipが取れるようになってしまい、コンテナ間のjgroupspingが通らなくなったと思われます。

なので今回は単純にfargate1.4にした状態で `eth0` を `eth1` に変更したところ解決しました。

```bash

# fargate1.4からはローカルIPはeth1から取得
export EXTERNAL_ADDR=`ip -f inet -o addr show eth1 | cut -d" " -f 7 | cut -d/ -f 1`
if [ "$EXTERNAL_ADDR" = "" ]; then
    EXTERNAL_ADDR=127.0.0.1
fi

echo "Use $EXTERNAL_ADDR for clustering."

sh /opt/jboss/tools/docker-entrypoint.sh $@ -Djgroups.bind_addr=$EXTERNAL_ADDR
```

物理的なNICを指定している時点でどうなの、というのはごもっともではありますが。
fargate等のコンテナでIPを固定しない状態において、クラスタリングする時にIP欲しくなるケースがあったりなかったり。
なにかのお役に立てると幸いです