OmniAICreator/Qiita-1.07M huggingface dataset:
Docker Compose で高速 (かつ乱暴) にJupiter Labを立ち上げる

# はじめに

JupyterLabの環境をサクッと(乱暴に)立ち上げる方法に関するメモ。
「dockerでサクッとJupiterLabを立ち上げてxxx試してみたいなあ、、、
でも、今後使うかはわからないし、いちいちDockerfile書いたり、イメージをビルドするのも面倒臭いんだよなあ、、、」
というくらいのモチベーションの時に使うことを想定している。

研究や開発など、再現性が必要なケースではきちんとイメージのビルドをしておくべきだと思う。

# 前提条件

- `docker` および `docker-compose` を実行可能な環境が整っている

# 準備

ディレクトリ構成 (必要に応じて.ipynbファイルなど)

```
.
├─ docker-compose.yml
└─ requirements.txt
```

# 各ファイルの内容

```yaml:docker-compose.yml
version: '2'

services:
  jupyter:
    image: python:3.9.10
    container_name: jupyter
    volumes:
      - .:/app
    ports:
      - "8888:8888"
    working_dir: /app
    command: >
      bash -c "pip install --upgrade pip 
      && pip install -r requirements.txt 
      && jupyter lab --no-browser --port=8888 --ip=0.0.0.0 --allow-root --NotebookApp.token=''"
```

`docker-compose.yml`では`python:3.9.10`イメージからコンテナを起動し、pipのアップグレード、`requirements.txt`に書かれたパッケージのインストール、JupyterLabの起動を行う。

```:requirements.txt
scikit-learn
matplotlib
jupyterlab
```

`requirements.txt`には必要なパッケージの一覧を書く。
上の例ではscikit-learn、matplotlib、jupyterlabをインストールする。

# コンテナの起動と終了

`docker-compose up`で起動。
webブラウザで`http://localhost:8888`などにアクセスすればJupyterLabが使用できる。

`docker-compose down`で終了。
MATLAB 小ネタ集

# はじめに
本記事は、up主の備忘録を兼ねています。
内容としては、一般的ではないけど、そこそこ嵌るMATLABの使い方の記録です。
(何か遭遇するたびに書き足していく予定)

# MATLAB Function内で、関数を明示的にコード生成なしで呼び出す
MATLAB Functionブロックは、実行時にコード生成されるため、コード生成無しで呼び出したい関数に関しては、下記の外部関数宣言が必要になる。コード生成だと変数の動的な拡張ができないようなので・・・
```
coder.extrinsic('関数名'); 
coder.extrinsic('calc_F'); %例
```

# MATLAB Function内の外部宣言した変数の扱い
Simulink中のMATLAB Functionでは、外部宣言した変数の使い方にも注意が必要。mexする際にサイズがわかるように初期化してあげないといけない。
```
%     こういう風に変換しないとmxArrayから逃げられない
    b_F = zeros(N*3,1);
    b_F_t = zeros(N*3,1);
    b_F = F*cgmres.zeta;    
    b_F_t = F_t;
    b = b_F - b_F_t;
```

[公式](https://jp.mathworks.com/help/simulink/ug/calling-matlab-functions.html)
【C#】配列 VS リスト 処理速度対決

# 知りたいと思った理由
今までソフト開発で配列を1度も使用したことがなくリストとの処理速度差が気になったため。

# 環境
- VisualStdio 2022
- .Net6
- C#10.0
- コンソールアプリケーション

# 結果

メモリ使用量(ソフト全体)[byte]

| 要素数 | リスト |  配列 | 差分(リスト-配列)|
|:-:|:-:|:-:|:-:|
|  1,000 |  528,504[byte] | 529,280[byte]  |  -776[byte] |
|  100,000,000(1億) | 40,531,680[byte]  |  40,530,792[byte] |  888[byte] |
|  2,147,483,591(21億) | 8,590,466,040[byte] |  8,590,466,080[byte] | -40[byte]  |

Forでループした場合の時間[ms]

| 要素数 | リスト | 配列 | 差分(リスト-配列)|
|:-:|:-:|:-:|:-:|
|  1,000 | 0[ms]  | 0[ms]  | 0[ms]  |
|  100,000,000(1億) | 449[ms]  | 180[ms]  |  269[ms] |
|  2,147,483,591(21億) | 6616[ms] |  3823[ms] |  2793[ms] |

ForEachでループした場合の時間[ms]

| 要素数 | リスト | 配列 | 差分(リスト-配列)|
|:-:|:-:|:-:|:-:|
|  1,000 | 0[ms]  |  0[ms] |  0[ms] |
|  100,000,000(1億) | 396[ms] | 249[ms]  |  147[ms] |
|  2,147,483,591(21億) | 6462[ms] |  3911[ms] |  2551[ms] |

# 個人的見解
これくらいの誤差であれば途中追加できる`リスト`を使用した方がいいと思いました。たまに**VB.NET**のソースコードで**ReDim**という配列の要素数を再定義しているソース(要素数は3個程度)を見るのですがそんなことするなら処理速度を捨ててソースの可読性を優先して`リスト`を使うべきということが分かりました。要素数が固定されているものは`配列`を使うといいとインターネットの記事を読むと書いてあるのですが、要素数が固定されているものというのは基本的に要素数が少ないので(星座(88種類)や血液型(4種類))`リスト`でも別に問題ないかなと思いました。ただ、`配列`は多次元配列を扱うことができるので多次元配列をどうしても使用しなければならない場合は`配列`を使用してもいいのかなと思いました。(多次元配列は複雑化してソースが読みにくいので極力使わないのがいいと思います。)

# 使用したソースコード

配列の検証ソース

```C#:配列の検証ソース
using System.Diagnostics;

var arrayTestData = Enumerable.Range(0, 2_147_483_591).ToArray();

long currentSet = GC.GetTotalMemory(true);

Console.WriteLine($"Listの場合。要素数：{arrayTestData.Length}。メモリ使用量(ソフトの合計使用量){currentSet:N0}[byte]");

var sw = new Stopwatch();

sw.Restart();

for (int i = 0; i < arrayTestData.Length - 1; i++)
{
    var _ = arrayTestData[i];
}

sw.Stop();

Console.WriteLine($"Forでループ。要素数：{arrayTestData.Length}。実行時間:{sw.ElapsedMilliseconds}[ms]");

sw.Restart();

foreach (var testData in arrayTestData)
{
    var _ = testData;
}

sw.Stop();

Console.WriteLine($"ForEachでループ。要素数：{arrayTestData.Length}。実行時間:{sw.ElapsedMilliseconds}[ms]");
```

リストの検証ソース

```C#:リストの検証ソース
using System.Diagnostics;

var listTestData = Enumerable.Range(0, 2_147_483_591).ToList();

long currentSet = GC.GetTotalMemory(true);

Console.WriteLine($"Listの場合。要素数：{listTestData.Count}。メモリ使用量(ソフトの合計使用量){currentSet:N0}[byte]");

var sw = new Stopwatch();

sw.Restart();

for (int i = 0; i < listTestData.Count - 1; i++)
{
    var _ = listTestData[i];
}

sw.Stop();

Console.WriteLine($"Forでループ。要素数：{listTestData.Count}。実行時間:{sw.ElapsedMilliseconds}[ms]");

sw.Restart();

foreach (var testData in listTestData)
{
    var _ = testData;
}

sw.Stop();

Console.WriteLine($"ForEachでループ。要素数：{listTestData.Count}。実行時間:{sw.ElapsedMilliseconds}[ms]");
```
Heroku のパイプラインでアプリ名を確認する方法

# はじめに
Heroku コマンドを使用する際に、アプリ名を求められることがある。

```shell
heroku config
```

```
 ›   Error: Missing required flag:
 ›     -a, --app APP  app to run command against
 ›   See more help with --help
```

この記事では、パイプラインのアプリ名を確認する方法について解説する。

# アプリとパイプライン
[Heroku のダッシュボード](https://dashboard.heroku.com/apps) にアクセスした際に、アプリの作成とパイプラインの作成がある。

![](https://raw.githubusercontent.com/noraworld/developers-blog-media-ja/master/heroku-pipeline-app-name/Screen%20Shot%202022-03-07%20at%2019.57.04.png)

両者の違いをざっくり説明すると以下の通りである。

| 種類 | 使用用途 | 詳細リンク |
| --- | --- | --- |
| アプリ | Heroku をインフラとして本番環境などのアプリケーションを稼働させたい場合に利用 | |
| パイプライン | 開発環境を簡単に構築しデプロイしたい場合に利用 | [Heroku Pipelineを使ってみる](https://qiita.com/yo-iida/items/f99566fe4617f848fa39) |

# アプリのアプリ名の調べ方
このうち、『アプリ』のアプリ名は自明だ。アプリを作成した際に自分でつけたアプリ名のことである。

![](https://raw.githubusercontent.com/noraworld/developers-blog-media-ja/master/heroku-pipeline-app-name/Screen%20Shot%202022-03-07%20at%2021.15.59.png)

![](https://raw.githubusercontent.com/noraworld/developers-blog-media-ja/master/heroku-pipeline-app-name/Screen%20Shot%202022-03-07%20at%2021.14.21.png)

上記のスクリーンショットでいう赤枠で囲まれた部分 (`d841ad5efac51db4`) が『アプリ』のアプリ名である。

# パイプラインのアプリ名？
では、パイプラインの場合のアプリ名とは、いったい何を指しているのだろうか。ちなみにパイプラインを作成する際の名称はパイプライン名で、アプリ名ではない。

以下のコマンドはアプリ一覧を表示するものなので、パイプラインに関するものは出てこない。

```shell
heroku list # heroku apps と同じ
```

以下のようにパイプライン一覧を表示するコマンドもあるが、`-a` や `--app` オプションで要求されるのはあくまでアプリ名なので、パイプライン一覧を表示させても意味がない。

```shell
heroku pipelines
```

# パイプラインのアプリ名の調べ方
[アプリ・パイプライン一覧のページ](https://dashboard.heroku.com/apps) から、該当するパイプラインを選択する。

![](https://raw.githubusercontent.com/noraworld/developers-blog-media-ja/master/heroku-pipeline-app-name/Screen%20Shot%202022-03-07%20at%2021.24.50.png)

下のスクリーンショットの赤枠で囲まれた部分 (`test-heroku-app-lhk6nz`) が、パイプラインにおけるアプリ名である。

![](https://raw.githubusercontent.com/noraworld/developers-blog-media-ja/master/heroku-pipeline-app-name/Screen%20Shot%202022-03-07%20at%2021.31.40.png)

`Open app` というリンクをクリックするとデプロイされたアプリケーションの URL に飛ぶことができるが、その際のサブドメイン部分から調べることもできる。

たとえば上記のスクリーンショットの例だと `https://test-heroku-app-lhk6nz.herokuapp.com` となるが、その際の `test-heroku-app-lhk6nz` の部分である。

# アプリ名の指定
アプリ名はわかればあとは簡単だ。`-a` または `--app` オプションでアプリ名を指定することで、該当するパイプラインに対する操作を行うことができる。

たとえば該当するパイプラインの環境変数一覧を取得したければ以下のコマンドを実行する。

```shell
heroku config --app <APP_NAME>
```

`<APP_NAME>` は前の項目の例でいう `test-heroku-app-lhk6nz` である。
Power Virtual Agetns と Power Automate で Wordle を作る①

# はじめに

Teams版のPower Virtual AgetnsとPower Automateを利用して、最近話題の [Wordle](https://www.nytimes.com/games/wordle/index.html) を作ってみましたので、全２回にわたって内容を記載します。


<blockquote class="twitter-tweet"><p lang="ja" dir="ltr"><a href="https://twitter.com/hashtag/PowerVirtualAgents?src=hash&amp;ref_src=twsrc%5Etfw">#PowerVirtualAgents</a> で <a href="https://twitter.com/hashtag/Wordle?src=hash&amp;ref_src=twsrc%5Etfw">#Wordle</a> を作ってみました。<br>答えは100の候補からランダムで設定するため、ゲームとしては簡単です笑<br>昨夜はWORDLEの事をよく知らずに適当なものを実装してしまってごめんなさい。<a href="https://twitter.com/hashtag/%E6%B0%97%E3%81%BE%E3%81%BE%E3%81%AB%E5%8B%89%E5%BC%B7%E4%BC%9A?src=hash&amp;ref_src=twsrc%5Etfw">#気ままに勉強会</a> <a href="https://t.co/HMB4VUv1vj">pic.twitter.com/HMB4VUv1vj</a></p>&mdash; Miyake Mito (@MiTo60448639) <a href="https://twitter.com/MiTo60448639/status/1500385230489743360?ref_src=twsrc%5Etfw">March 6, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


# 初期処理の作成

全体象は下図になります。今回は、赤枠で囲った初期処理部分を記載します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/a06f042a-9a35-bbf1-e202-5e62feb05fff.png)

## ①トピック「初期化」

ゲーム開始のトリガーフレーズを受けるトピックを作成します。
フロー「初期化処理」を呼び出し、メイン処理となるトピック「ループ1」を呼び出します。

:::note info
トピック「ループ1」の内容は、次回の記事にて記載します。
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/d2d47e0d-9d18-aba5-73f8-35f96ecc0c98.png)

## ②フロー「初期化処理」

全体像は下図になります。
答え候補の単語を配列で登録し、その中からランダムで一つの単語を今回のゲームの答えとします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/ce9cc37c-b56d-1dd0-a6fd-807629f4be7c.png)

### 答え候補配列の作成

答え候補の配列を作成します。
Wordleの過去の答えの一覧を掲載しているサイトなどから取得し、配列として登録します。

:::note info
配列の要素が多いほど、答えに多様性が発生するため、難易度は上がります。
5文字の単語であれば、日本語など他言語での作成も可能です。
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/1c0a825c-d5f3-098e-d058-50d6ebbffca6.png)

```
[
  "APPLE",
  "POINT",
  "CIGAR",
  "REBUT",
  "SISSY",
  "HUMPH",
  "AWAKE",
  "BLUSH",
  "FOCAL",
  "EVADE"
]
```

### 今回の答えを選択

上記の答え候補から、ランダムで一つの要素を選びます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/e34c8683-f1e1-f2bf-e485-4c8c289212a5.png)

rand()関数を用いて乱数を取得し、上記配列への添え字に指定することで、配列からランダムに一つの要素を取得します。

```
outputs('答えの候補')?[rand(0,length(outputs('答えの候補')))]
```

### 残りの処理

フローの戻り値となる答えには上記で取得したランダムな要素を、回答履歴にはnull値をセットします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/308e8664-28e5-7e2c-f4f4-b90ccb0cb443.png)

### まとめ

今回は、ゲームを開始し、答えとなる単語を選出するまでの処理を記載しました。
次回は、ゲームのメインとなる、回答⇒結果の処理を記載します。
Problem 95: 社交数（3個以上の友愛数）

* 本記事は[ProjectEuler](https://projecteuler.net/about)の「100番以下の問題の説明は記載可能」という規定に基づいて回答のヒントが書かれていますので、自分である程度考えてみてから読まれることをお勧めします。

### 問題 95. 社交数（3個以上の友愛数）

原文 [Problem 95: Amicable chains](https://projecteuler.net/problem=95)

**問題の要約：すべての要素が$10^6$以下の最長の社交数ループの要素の最小値を求めよ**

[社交数(Wikipedia)](https://ja.wikipedia.org/wiki/%E7%A4%BE%E4%BA%A4%E6%95%B0)とはあまりなじみのない言葉ですが[Problem 21: 友愛数](https://qiita.com/masa0599/items/8c87da4f15711fc9f3ce)で出てきた友愛数の3個以上のものを言うようです。

従ってまずそこで作った自分自身を除いた約数（proper divisors）の和」を求める関数**sumpdiv**を使って$10^6$以下の整数の約数の和を配列に格納します。

その配列からループになっている友愛数のチェーンを探す関数**amiChain**を使って探し長さが最大の物を見つけます。

これでも1分強で終了するので、まあOKかなと思いますが。やはりさらなる高速化に挑戦します。

```python 
import sympy
def sumpdiv(n):
  return sum(sympy.divisors(n))-n

def amiChain(spd, i):         # Create a chain
  chain = []
  while i not in chain:       
    if i > N:  return []      # out of range
    chain, i = chain+[i], spd[i]
  return chain[chain.index(i):]

N = 10**6
spd = [sumpdiv(n) for n in range(0,N)]
#print(spd[:20])

maxc = 1 
for i in range(len(spd)):
  chain = amiChain(spd, i)
  if len(chain) > maxc:
    maxc, maxchain = len(chain), chain

print(min(maxchain), len(maxchain), maxchain)
```

### 約数関数の公式を使った高速化

[約数関数(Wikipedia)](https://ja.wikipedia.org/wiki/%E7%B4%84%E6%95%B0%E9%96%A2%E6%95%B0)によると約数関数$\sigma (n)$の公式はいくつかあるみたいですが以下の2つを使います。(ここでは$ \sigma(n)=\sigma_1(n)$とします)

```math 
\large 乗法定理　\sigma(ab)=\sigma(a) \times \sigma(b)\ \ \ \ \  if \ gcd(a,b) = 1　 \cdots (1)\\
\large n = p^k とすると \sigma(p^k)=1+p+p^2+\cdots +p^k　 \cdots (2)\\ \\
```

まず整数$n$に含まれる素数$p$から$(2)$を使って$\sigma(p^k)$を求める関数**pksum**を作ります。要は整数$n$に含まれる素数すべてに関して$\sigma(p^k)$を求めてそれを$(1)$の乗法定理を使って掛ければ$\sigma(n)$が求まるということになります。

```python 
def pksum(n, p):   # calculate 1+p+p^2+p^3+,,,
  ret, pk = 1,1
  while n % p == 0:
    n //= p
    pk *= p
    ret += pk
  return ret
```
次にこの**pksum**を使って[0,nmax]の約数の和を求める**sumdivrange**を作ります。エラストテネスのふるいの原理で素数の倍数に対して**pksum**を計算して掛けて行きます。

後で使うかもしれないので、第二引数の**proper**フラグで整数自身を含むかを指定できるようにしました。

```python 
def sumdivrange(nmax, proper=False):
  sdiv = (nmax + 1) * [1]
  for p in range(2, len(sdiv)):
    if sdiv[p] > 1: continue # not prime
    for pi in range(p, len(sdiv), p):  # pi = p x i
      sdiv[pi] *= pksum(pi, p)         # 1+p+p^2+p^3+,,,
  if not proper: return sdiv
  for i in range(len(sdiv)): sdiv[i] -= i   # for proper divisor, subtract the number itself
  return sdiv
```

これで部品はそろったので、最初のプログラムの"spd = ..."の1行を以下に変更するだけです。実行時間は約24秒とまあまあ改善出来ました。

```python 
spd = sumdivrange(N, proper=True)  # sum of proper divisors
```

（開発環境：Google Colab）
ECS Fargate の起動エラー (StoppedReason) コレクション

# 前置き

自社サービスにて大量の Fargate を起動している (1 分間に数個程度) が、稀に Fargate が起動に失敗することがある。

実にいろいろな理由で失敗するものだなと見返したいので、集めてどうするという話だがまとめてみる。

# コレクション

出現のレア度によって N, SR, SR, SSR でカテゴリ分けした。

## N

### ResourceInitializationError: failed to configure ENI: failed to setup regular eni: context deadline exceeded

よく出る。ENI の設定に失敗ということで、同時刻に複数個の Fargate を起動させるようとすると出る?
ちなみに利用可能な IP は潤沢に余っているので、サブネットの問題ではなさそうである。

### Timeout waiting for network interface provisioning to complete.

これも ENI 関連でよく見かける。同時起動に関わらず出る気がする。

## R

### Task failed to start

シンプルで潔い理由。出てもなんだか許せる。

### ResourceInitializationError: failed to configure ENI: failed to setup regular eni: netplugin failed with no error message

これも ENI で、netplugin が失敗したとのこと。netplugin とは内部モジュールのことなのだろうか?

## SR

### ResourceInitializationError: unable to pull secrets or registry auth: execution resource retrieval failed: unable to retrieve secrets from ssm: service call has been retried 5 time(s): RequestCanceled: request context canceled caused by: context deadli...

SSM Parameter Store のエラーだろうか。`service call` を 5 回リトライしても失敗するとは、なかなか。
エラー文が長すぎて文末がどうなっているかわからないのが残念。

### CannotCreateVolumeError: unable to copy contents to volume on host: containerd: unable to prepare mounts from the snapshot: unable to prepare mounts: 2 errors occurred: * context deadline exceeded * context deadline exceeded

context deadline なので、起動数に関連していそう。

### CannotPullContainerError: ref pull has been retried 1 time(s): failed to read expected number of bytes: unexpected EOF

Pull の失敗も稀に生じる。`unexpected EOF` という状況に少し興味があるが。

### ECS detected degradation of the underlying infrastructure hosting your task.

インフラ側に問題あるよ、という文字通りの内容。具体的にどのようなデグレが生じたのかやはり気になる。

## SSR

### Unexpected EC2 error while attempting to attach network interface to instance

Fargate ではあるが EC2 のエラー。ホスト側の問題だろうか。ほとんど見かけない。

### CannotPullContainerError: ref pull has been retried 1 time(s): failed to extract layer sha256:abc123...: gzip: invalid checksum: unknown

gzip の extract でチェックサムが合わないらしい。そんなことあるのか。

# 所感

多くは同時起動によるスロットリングに起因しているのかなと推測される。
また、時期によってエラーの発生頻度に偏りがみられた。今は見られないエラーもちらほらあり、見えないところで Fargate の改善が進められているのかなと感じる。

Fargate を使ったワークロードがクリティカルなものである場合、後述のリトライが必須である。

# 備考

## Fargate 起動エラーへの基本的な対策

エラーを回避するのは不可能なので、エラー発生時にリトライさせる必要がある。
自前で実装するか、Step Functions でステートマシンを組むなどの方法がある。

https://aws.amazon.com/jp/premiumsupport/knowledge-center/ecs-fargate-network-interface-errors/
【CocoaPods】No `Podfile' found in the project directory.

# 何があったのか？
Xcodeのプロジェクトファイルがある階層でpod initをし、podfileにライブラリ記入後、pod installを実行したにもかかわらず　**No `Podfile' found in the project directory.**　エラーが発生しました。

# 原因
プロジェクトを格納しているフォルダが全角英数字を含むフォルダ名になっている時に**No `Podfile' found in the project directory.** が発生することが分かりました。
そのため、フォルダ名を半角英数字に変更したら解決いたしました。

# 参考
https://teratail.com/questions/224722
UE4 DedicatedサーバでのGameMode以下の処理の流れ


各GameModeとPlayerActorの作成の順序(BeginPlayが呼ばれる順番)

```
// Server
[BP_InGameMode_C_0] Server: Call:BP_InGameMode
[BP_InGameState_C_0] Server: Call:BP_InGameState

//Server Client 1を作成
[BP_InGamePlayerStatus_C_0] Server: Call:BP_InGamePlayerStatus
[BP_InGamePlayerController_C_0] Server: Call:BP_InGamePlayerController
[FirstPersonCharacter_C_0] Server: Call:FirstPersonCharacter

// Client 1
[BP_InGamePlayerController_C_0] Client 1: Call:BP_InGamePlayerController
[BP_InGameHud_C_0] Client 1: Call:BP_InGameHud
// Client 1 Client 1を作成
[FirstPersonCharacter_C_0] Client 1: Call:FirstPersonCharacter
[BP_InGameState_C_0] Client 1: Call:BP_InGameState
[BP_InGameSpectarPawn_C_0] Client 1: Call:BP_InGameSpectarPawn
[BP_InGamePlayerStatus_C_0] Client 1: Call:BP_InGamePlayerStatus

//Server Client 2を作成
[BP_InGamePlayerStatus_C_1] Server: Call:BP_InGamePlayerStatus1
[BP_InGamePlayerController_C_1] Server: Call:BP_InGamePlayerController1
[FirstPersonCharacter_C_1] Server: Call:FirstPersonCharacter1

// Client 1 Client 2を作成
[FirstPersonCharacter_C_1] Client 1: Call:FirstPersonCharacter1
[BP_InGamePlayerStatus_C_1] Client 1: Call:BP_InGamePlayerStatus1

// Client 2
[BP_InGamePlayerController_C_0] Client 2: Call:BP_InGamePlayerController
[BP_InGameHud_C_0] Client 2: Call:BP_InGameHud
// Client 2 Client 2とClient 1を作成
[FirstPersonCharacter_C_0] Client 2: Call:FirstPersonCharacter
[FirstPersonCharacter_C_1] Client 2: Call:FirstPersonCharacter1
[BP_InGamePlayerStatus_C_0] Client 2: Call:BP_InGamePlayerStatus
[BP_InGameState_C_0] Client 2: Call:BP_InGameState
[BP_InGameSpectarPawn_C_0] Client 2: Call:BP_InGameSpectarPawn
[BP_InGamePlayerStatus_C_1] Client 2: Call:BP_InGamePlayerStatus1
```

# DedicatedServer
GameMode
GameState

PlayerStatus
PlayerController
FirstPersonCharacter

PlayerStatus1
PlayerController1
FirstPersonCharacter1



# Client 1
PlayerController
GameHud
FirstPersonCharacter
GameState
SpectarPawn
PlayerStatus

FirstPersonCharacter1
PlayerStatus1

# Client 2
PlayerController
GameHud
FirstPersonCharacter
FirstPersonCharacter1
PlayerStatus
GameState
SpectarPawn
PlayerStatus1

# Clientの基本的な処理の流れ

// Client毎の準備の流れ
PlayerController
GameHud
GameState
SpectarPawn

// PlayerSpawnの流れ
FirstPersonCharacter
PlayerStatus

Server側でFirstPersonCharacter作成されたら
順番に作成が走るのでClient 2の場合は順番が前後している雰囲気
【ActiveModelSerializer】includeオプションの使い方

# inludeオプション
オブジェクトの関連付けをレンダリングできる。

## 例
postに関連づいているpostの著者、コメント、コメントを書いた人を出力できる。

```ruby
render json: posts,
       include: 'author,comments,comments.author'
```

多分こんな感じで返ってくるはず。

```
=> {
"id"=>222,
"author"=>"kato",
"description"=>"ccccccccccccccccccccccccccccccccc",
"created_at"=>"2022-03-07T21:07:22.643+09:00",
"commments"=>
  [{"id"=>1003,
   "content"=>"aaaaaaaaaaaaaaaaaaaaaaa"
   "author"=>"fugafuga"]
}
```


Serializerにアソシエーション書けばワイルドカードでも同じようにレンダリングできる。

```posts_controller.rb
render json: posts,
       include: '**'
```

```post_serializer.rb
class PostSerializer < ActiveModel::Serializer
  attributes :id, :description, :created_at

  belongs_to :author
  has_many :comments
end
```


Serializerにアソシエーション書いてしまえば、includeで関連先を明記しなくてもよさそう…


# 参考

https://github.com/rails-api/active_model_serializers/blob/v0.10.6/docs/general/adapters.md#include-option
querySelectorAllとgetElementsByClassName

Javascriptで要素を取得する為の方法としてquerySelectorAllとgetElementsByClassNameがあることを知ったがどのように使い分けるかを考えられていませんでした。

・**getElementsByClassNameで得られるものはHTMLCollection**
・**querySelectorAllで得られるものはNodelist**
とのことで同じものではないがやっぱり何が違うかはわからない。

以下のブログでそれぞれの違いについてまとめて下さっている方がいらっしゃたので参考にさせていただきました。
https://javascript-k.hatenablog.com/entry/javascript_htmlcollection_nodelist　


キーポイントとしては動的 or 静的という点で先日自分が使用したケース（静的なwebサイト内の文章の日本語⇆英語の切り替えるだけ）であればquerySelectorAllで問題ないかなと納得できました。

仮に、文章の要素が増えるなどダイナミックになる場合はgetElementsByClassName出ないと対応できなくなる？？
今後自分でも確認してみます。
【Rails】オリジナルアプリ　作成の手順　その１【備忘録】

# オリジナルアプリ　作成の手順
オリジナルアプリの作成手順の備忘録です。

１、機能ははどのようなものにするのかアイデアを出す。
２、だれに向けてなのか決める
３、DBの洗い出し

## １、　機能はどのようなものにするのかアイデアを出す。
どのようなアプリの内容にするのかアイデアを出す。
投稿できるもの、チャットできるもの、など


## ２、誰に向けてなのか決める。
誰に向けているのか決める⇨企業、主婦層、学生など決める
さらにどの年代に向けるのかも決める


## ３、アプリケーションの要件定義を洗い出す
どのような機能があり、どのような要件があるのか考える



# 今回作成するアプリ
今回作成するアプリは
１、体温を記録でき、集計することができるもの
２、企業向け、２０代から３０代向け
３、今回の要件定義
![要件定義 - シート.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2573830/f66c5994-ccfc-d30c-1dc7-aae60987635e.png)
接続先サーバーによって秘密鍵を切り替える必要がある場合の「.ssh/config」の書き方

以下のような構成のSSH接続を解決する「.ssh/config」を模索していました。

```
ローカルPC --> 踏み台A --> 踏み台B --> 接続先*
```


- 踏み台A
    - すべてのグローバルIPから接続を受け付ける。
    - ローカルPCの「.ssh/id_rsa（パスフレーズの設定有り）」で接続可能。
    - ホスト名は「bastion-a.example.com」
- 踏み台B
    - 踏み台Aからの接続のみを受け付ける。
    - ローカルPCの「.ssh/id_rsa（パスフレーズの設定有り）」で接続可能。
    - ホスト名は「bastion-b.example.com」
- 接続先* パターン1
    - 踏み台Bからの接続のみを受け付ける。
    - 踏み台Bの「.ssh/id_rsa（パスフレーズの設定無し）」で接続可能。
    - 同じ構成のサーバーが複数台存在する。
    - ホスト名は「target-*.example.com」
- 接続先* パターン2
    - 踏み台Bの「.ssh/id_dsa（パスフレーズの設定無し）」で接続可能。
    - 同じ構成のサーバーが複数台存在する。
    - ホスト名は「target-*.example.com」

まずは「ローカルPC」から「踏み台A」の部分を解決します。何の変哲もない感じですが、これでOKでしょう。

```
Host bastion-a
    HostName bastion-a.example.com
    User foo
    IdentityFile ~/.ssh/id_rsa
```

次に「踏み台A」から「踏み台B」の部分を解決します。踏み台Aを「経由」する場合は `ProxyJump` もしくは `ProxyCommand` を利用することで接続可能です。

`ProxyJump` を利用する場合

```
Host bastion-b
    HostName bastion-b.example.com
    User bar
    ProxyJump bastion-a
```

`ProxyCommand` で `sshコマンド` の `-Wオプション` を利用する場合

```
Host bastion-b
    HostName bastion-b.example.com
    User bar
    ProxyCommand ssh -W %h:%p bastion-a
```

`ProxyCommand` で `sshコマンド` と `ncコマンド` を利用する場合

```
Host bastion-b
    HostName bastion-b.example.com
    User bar
    ProxyCommand ssh bastion-a nc %h %p
```

最後に「踏み台B」から「接続先*」の部分を解決します。
「target-*.example.com」はローカルPCの秘密鍵ではなく、踏み台Bの秘密鍵を使ってSSH接続を行うため、SSHエージェント転送が行われるように `-o` オプションで `ForwardAgent yes` を指定します。
また、踏み台Bの「.ssh/id_rsa」または「.ssh/id_dsa」のいずれか秘密鍵を使うため、 `ssh-add` で両方の鍵の登録を行います。
この書式の場合は `ncコマンド` との組み合わせとなるため、 `nc %h %p` でホストとポート番号が展開されるように記述します。

```
Host target-*.example.com
    User baz
    ProxyCommand ssh -o 'ForwardAgent yes' bastion-b 'ssh-add ~/.ssh/id_dsa && ssh-add ~/.ssh/id_rsa && nc %h %p'
```

しかし、この設定で接続を試みると、サーバーによっては `debug1: Skipping ssh-dss key /PATH_TO/.ssh/id_dsa - not in PubkeyAcceptedKeyTypes` のようにDSA鍵での接続を蹴られてしまう場合があります。
この問題を回避するため、 `PubkeyAcceptedKeyTypes` でDSA鍵での接続を許可する設定を追加します。（まぁDSA鍵を今さら使うなという話もありますが、イニシエの環境というものはどこにでも存在するものです）

```
Host target-*.example.com
    User baz
    PubkeyAcceptedKeyTypes +ssh-dss
    ProxyCommand ssh -o 'ForwardAgent yes' bastion-b 'ssh-add ~/.ssh/id_dsa && ssh-add ~/.ssh/id_rsa && nc %h %p'
```

はい、ということで最終的に以下のような形になりました。

```
Host bastion-a
    HostName bastion-a.example.com
    User foo
    IdentityFile ~/.ssh/id_rsa

Host bastion-b
    HostName bastion-b.example.com
    User bar
    ProxyJump bastion-a

Host target-*.example.com
    User baz
    PubkeyAcceptedKeyTypes +ssh-dss
    ProxyCommand ssh -o 'ForwardAgent yes' bastion-b 'ssh-add ~/.ssh/id_dsa && ssh-add ~/.ssh/id_rsa && nc %h %p'
```

- 参考URL
    - [SSHの鍵(DSA)とかの件](https://tksm.org/wp/archives/3925)
    - [多段 SSH で秘密鍵を「ローカルに持つ」パターンと「踏み台に持つ」パターン](https://qiita.com/mpyw/items/52488034f34a3eba85aa)
AWS EC2 AmazonLinux2 composerをバージョンを指定してインストールする

# 概要

- EC2のAmazonLinux2インスタンスにcomposerを入れて`$ composer`コマンドを実行できるようにする。

# 前提

- 下記の記事どちらかを参考にAmazonLinux2インスタンスにPHP8.0が入っているものとする。
    - [AWS EC2 AmazonLinux2 extrasを使ってPHP8をインストールする](https://qiita.com/miriwo/items/9d876de230b66c70bb39)
    - [AWS EC2 AmazonLinux2 Laravel用のPHPをインストールする](https://qiita.com/miriwo/items/c335eeec6617ddc0bf2d)

# 方法

1. 下記コマンドを実行してcomposerの2.2.6バージョンを指定してインストールする。

    ```
    $ php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
    $ php composer-setup.php --version=2.2.6
    $ php -r "unlink('composer-setup.php');"
    $ sudo mv composer.phar /usr/local/bin/composer
    ```

1. 下記コマンドを実行してパスを通す。

    ```
    $ echo "export PATH=~/.config/composer/vendor/bin:$PATH" >> ~/.bash_profile
    $ source ~/.bash_profile
    ```

1. 下記コマンドを実行してエラーが出なければ問題なくインストールできている。

    ```
    $ composer -v
       ______
      / ____/___  ____ ___  ____  ____  ________  _____
     / /   / __ \/ __ `__ \/ __ \/ __ \/ ___/ _ \/ ___/
    / /___/ /_/ / / / / / / /_/ / /_/ (__  )  __/ /
    \____/\____/_/ /_/ /_/ .___/\____/____/\___/_/
                        /_/
    Composer version 2.2.6 2022-02-04 17:00:38
    ```
# Ruby on Rails で Qiita::Markdownを導入



# 1. gemをインストール
- Gemfileに下記を記述し % bundle installを実行
```
gem 'qiita-markdown'
```
- % bundle install実行するもエラー

```
An error occurred while installing rugged (1.4.2), and Bundler cannot continue.
Make sure that `gem install rugged -v '1.4.2' --source 'https://rubygems.org/'` succeeds before bundling.
```

- ネット検索の結果下記コマンドを実行
```
% gem install rugged -v '1.4.2' --source
% brew install cmake
```
- 無事インストールできたみたいなので再度% bundle installを実行
- 無事gemをインストールできました。
- 下記メッセージが表示されたのでgithubのホームページを確認

```
-------------------------------------------------
Thank you for installing html-pipeline!
You must bundle Filter gem dependencies.
See html-pipeline README.md for more details.
https://github.com/jch/html-pipeline#dependencies
-------------------------------------------------
```
- Gemfileに 「gem 'html-pipeline'」に追記後、下記コマンドを実行するようにあったので実行してみました。
```
% gem install html-pipeline
```

- 下記が表示され無事インストールできました。
```
-------------------------------------------------
Thank you for installing html-pipeline!
You must bundle Filter gem dependencies.
See html-pipeline README.md for more details.
https://github.com/jch/html-pipeline#dependencies
-------------------------------------------------
Successfully installed html-pipeline-2.14.0
Parsing documentation for html-pipeline-2.14.0
Installing ri documentation for html-pipeline-2.14.0
Done installing documentation for html-pipeline after 0 seconds
1 gem installed
```
・下記を記載してbundleinstall
```
gem 'github-linguist'
gem 'rouge'
```
## これでgemのインストールは完了

# 2. ヘルパーとhtmlを編集し実際に使用できるようにします。
- application_helper.rbに下記コードを記述
![スクリーンショット 2022-03-07 20.08.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2533976/5a953932-58cc-8773-eb21-9854f66aaaaf.png)
- マークダウン記法を反映したい箇所に「qiita_markdown(カラム名)」を記述
![スクリーンショット 2022-03-07 20.11.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2533976/6b20b463-ede3-8149-d4e6-9d72dbca8912.png)

# 3.導入できたが、うまく反映されない
* ネット検索するとブートストラップを導入しないと反映されないと発見
-下記をGemfileに記述
```
gem 'bootstrap-sass'
```
- app/assets/stylesheets/ の中にある
application.css を application.cssの拡張子をscss に名前を変更してから
以下の2行を追加。
```
@import "bootstrap-sprockets";
@import "bootstrap";
```
# 4.これで私の場合はマークダウン記法の導入が完了しました。
Blenderのレンダリングで色がしっかり出なかったらColor Managementをいじろう

## この記事の概要

Blenderでモデリングしてライティングして画角を決めて、いざレンダリング！と、実行したのに出力結果の色が微妙に曇って見えることはありませんか？
私はあります。

そもそもMaterialの設定やライティングがちゃんとできていない可能性もありますが、比較的手軽に出力する色の調子を変える方法を記事にしました。

## 環境

| カテゴリー | 内容 | 補足 |
| --- | --- | --- |
| マシン | MacBook Pro (15-inch, 2019) |  |
| OS | macOS Big Sur (11.5.2) |  |
| プロセッサ | 2.6 GHz 6コアIntel Corei7 |  |
| メモリ | 32 GB 2400 MHz DDR4 |  |
| グラフィックス | Radeon Pro 555X 4 GB | このMacは、BlenderにおけるGPUを使ったレンダリングに対応していないモデルなので無意味…… |
| Blender | 3.0.1 |  |

MacBook Pro単騎で3DCGに挑むなんて……という声が聞こえてきますが、これでやっています。

## Color Management

`Render Properties > Color Management > Look`から設定できます。

- Very Low Contrast
- Low Contrast
- Medium Low Contrast
- Medium Contrast
- Medium High Contrast
- High Contrast
- Very High Contrast
- None

以上の8種類があります。
手元で確認した限りだとNoneとMedium Contrastが一緒に見えますが、もしかしたら色々な条件を変えると違いがあるのかも……。
ここは検証しきれていません。

試しに簡単な絵を作って比べてみました。
Lookの設定以外は変えていません。

| Very Low Contrast | Low Contrast | Medium Low Contrast | Medium Contrast | Medium High Contrast | High Contrast | Very High Contrast | None（Mediumと一緒？） |
| --- | --- | --- | --- | --- | --- | --- | --- |
| ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/4539c7af-227b-ef11-0a46-c58605efce51.png) | ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/5bbf7778-6c66-e484-1501-6e94f4f5dd0b.png) | ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/d09fa216-1b42-21e1-15c0-76b9bb88e6a5.png) | ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/29b55dd2-2712-e8b8-1ff8-07f81dc361f6.png) | ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/2ea7f2ca-4038-5053-5f23-70e60fa6c14a.png) | ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/bbade08f-cb5b-1b6a-fb61-5bc5851e0ddd.png) | ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/19547448-9c21-278a-3f06-bb4a97eeeba3.png) | ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/6bb41a6f-ddae-8178-293b-1fa1a61885f6.png) |

## まとめ

- 「ほぼ良いんだけど、もう少しだけコントラストが出て欲しい」ような場面であればColor ManagementのLook設定を変えるだけで対応できる
- コントラストが高ければ良いというものでもないので、実際の結果を見ながら調整するのがベター

---

最後まで読んでくださってありがとうございます！
Twitterでも情報を発信しているので、良かったらフォローお願いします！

https://twitter.com/xrxoxcxox
AWS Lightsail × WordPress × contact form 7 環境からGmailを送信できるようにする

Lightsailで構築したウェブサイトから問い合わせメールが送信できない問題を修正する
※以下の手順は全てGmailを送信したいアカウントで操作してください

![スクリーンショット 2022-03-07 19.06.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869250/217c813d-5622-4fb1-11d6-9567a68c66e1.png)
このように設定しただけではメールが送信されない...


## "WP Mail SMTP"プラグインを入れ,Gmail APIを設定する必要がある
AWSのインスタンスからのメール送信はcontact form 7に加えてWP Mail SMTPというプラグインの設定を行う必要がある
さらに，Gmailから送信するにはGmailAPIを設定する必要もある

プラグインを追加し，"メーラー"の設定でGoogle/Gmailを選択
![スクリーンショット 2022-03-07 19.24.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869250/516d225d-9ecf-437a-92d9-4778371bdcc8.png)


※注意
ググると，"その他のSMTP"から設定する方法も出てくるが，セキュリティ面から不可能になっている模様
![スクリーンショット 2022-03-07 19.22.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869250/82cb6054-6860-edb9-4688-a2b3bf3ed707.png)


GoogleAPIのクライアントIDやクライアントシークレットを設定していく
![スクリーンショット 2022-03-07 19.25.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869250/adff5fd5-20f2-2107-34ef-6bcfc86345d2.png)

GCPのコンソールへアクセス
https://console.cloud.google.com/?hl=ja

まだAPIを使用したことがないない場合，プロジェクトを作成
![スクリーンショット 2022-03-07 19.30.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869250/47eb0c14-5efd-ad3a-dd71-f74fddc154ea.png)

![スクリーンショット 2022-03-07 19.31.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869250/40c07330-5b92-46c3-0ff5-cf21a33a235d.png)

Gmail APIを検索し有効にする
![スクリーンショット 2022-03-07 19.48.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869250/947ff035-bece-8b46-545a-1b0fa2293a7c.png)

![スクリーンショット 2022-03-07 19.49.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869250/d87b335f-91f9-9aa4-91b9-fe9751b4e889.png)


有効にすると．Gmail API設定に飛ぶので，認証情報を作成
![スクリーンショット 2022-03-07 19.50.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869250/27bbe284-aaa5-18e0-61e9-8b4f96325c92.png)


設定を進めていく
![スクリーンショット 2022-03-07 19.53.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869250/d80f0355-1ad6-39f8-3b9b-423ff7667041.png)

![スクリーンショット 2022-03-07 19.53.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869250/154605e5-fc51-f542-cadf-b91ed90d9f02.png)

スコープは省略可
![スクリーンショット 2022-03-07 19.54.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869250/bb3b07b7-893c-e9a7-d8be-a7de0d1aef8b.png)

"承認済みのJavaScript生成元"に自分の
ウェブサイトのURLを入力（最後の/はとってください）
"承認済みのリダイレクトURI"に，WP MAil SMTPの"許可されたリダイレクトURI"の値を貼り付け

![スクリーンショット 2022-03-07 20.01.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869250/a6d71f1d-8d6c-4dd3-6759-67e8981fb9c9.png)


![スクリーンショット 2022-03-07 20.04.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869250/fec2d6f2-8623-43a6-97fb-fd61f8d513db.png)

ここまで設定すると，クライアントIDとクライアントシークレットが発行される
認証情報→OAuth 2.0 クライアント IDに一つ追加されている
この情報をWP Mail SMTPに入力し，承認を行えばメールが送信できるようになる

![スクリーンショット 2022-03-07 20.06.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869250/7b21f0e8-bfe0-ef25-63c8-2211c8030d9c.png)
特定のURLだけBasic認証を掛けない

## まだ出来ない
もう散々やってるのに未だにスムーズに行かないのは
多分Apache2.0/2.2/2.4の書き方を混在させ続けているせい...
変に互換があると良くないです。

## 条件

+ 特定のIPアドレスは全て認証無しでアクセス可
+ ↑以外はBasic認証が必須
+ 特定のURL（/api）はBasic認証不要

## 対応

```apache:ssl-vhost-nikusui.conf
	SetEnvIf Request_URI '/api' valid-url
	SetEnvIf Request_URI '^/index.php' cms

	AuthType Basic
	AuthName "Available only authorized users by Osaka Tokyo"
	AuthUserFile /home/nikusui/.htpasswd
	#Require valid-user

	<RequireAny>
		Require ip 999.999.999.999
		Require valid-user
		Require env valid-url
		Require env cms
	</RequireAny>
```

## 解説

ミソになるのはRequireAnyディレクティブ。
いずれかの条件を満たせばOKのやつ。

Basic認証の一連の処理の中に↓を含めないこと。
```
Require valid-user
```

index.phpをcmsと命名して除外しているのは
WordpressとかLaravelでルートパラメータのRewriteを失敗しないための除外
なのでFrameworkやCMSでない場合は不要

Order Allow/Denyとかはもう使わない前提でやらないとな〜と思った。
（そもそも最近apacheじゃなくてnginxが個人的な主流でもあるので...）
elpyを使ってEmacsのpython環境を構築する

# elpy
EmacsをPythonのIDEにするようなもの．補完とか文法チェックとか色々できるようになる．

## インストールと設定
melpaとかからインストールする．
下記は use-packageを使った例

``` lisp
;;; elpy (melpa-stable)
(use-package elpy
  :ensure t
  :pin melpa-stable
  :defer t
  :init
  (advice-add 'python-mode :before 'elpy-enable)
  :config
  (setq elpy-rpc-python-command "python3")
  (setq python-shell-interpreter "python3")
;;  (setq elpy-rpc-virtualenv-path 'current)
  (when (load "flycheck" t t)
    (setq elpy-modules (delq 'elpy-module-flymake elpy-modules))
    (add-hook 'elpy-mode-hook 'flycheck-mode)))
```

## elpyのconfig

`M-x elpy-config`で設定状況が確認できる．初回実行時に色々自動で設定される．

``` lisp
Elpy Configuration

Emacs.............: 27.2
Elpy..............: 1.35.0
Virtualenv........: None
Interactive Python: python3 3.9.10 (/usr/local/bin/python3)
RPC virtualenv....: rpc-venv (/Users/xxxxxx/.emacs.d/elpy/rpc-venv)
 Python...........: python3 3.8.9 (/Users/xxxxxx/.emacs.d/elpy/rpc-venv/bin/python3)
 Jedi.............: 0.18.1
 Rope.............: 0.23.0
 Autopep8.........: 1.6.0
 Yapf.............: 0.32.0
 Black............: 22.1.0
Syntax checker....: flake8 (/usr/local/bin/flake8)

```

flake8はインストールされなかったので，ターミナルから`pip3 install flake8`でインストールした．

## jedi 0.18.x で補完が効かない問題

jediのバージョンを0.18以上にするとcompanyの補完が効かなくなる問題がある
https://github.com/jorgenschaefer/elpy/issues/1890

0.17.2を使うと動くようなので，elpyのvirtualenvのpython環境でjediのバージョンを下げた．

``` zsh
~/.emacs.d/elpy/rpc-venv/bin/pip3 install jedi==0.17.2
```

このコマンドで見つからないと言われたのでPyPIからwhlをダウンロードしてきてインストールした

``` zsh
~/.emacs.d/elpy/rpc-venv/bin/pip3 install jedi-0.17.2-py2.py3-none-any.whl
```

これで補完が効くようになった
一番シンプルなFlutter環境構築

![header.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/982650/b93ec005-2917-1ead-743f-e667fa1ec9ce.png)

:::note info
- パソコン環境は **macOS 10.15** (2019年) 以降の人向け
- **Mac**で説明しますがWindowsでもほぼ同様です
- (もし誰か**Windows版**を書いてもらえたらリンクを貼らせていただきます)
:::

<br>
<br>

![sec-flutter.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/982650/41dec46a-16a4-f1da-336e-886e79c8ea09.png)

- 💙 1. [公式サイト](https://docs.flutter.dev/get-started/install) からダウンロード
- 💙 2. ダウンロードが終わったら ```Flutterフォルダ``` をその場に取り出しておく

![download-flutter.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/982650/8b116fdb-5a0c-2388-2362-9d3aa0b30770.png)

- 💙 3. ターミナルを開いて以下のコマンドを順番に実行
- この作業のことを **「パスを通す」** と言う

```
$ mkdir ~/dev
$ mv ~/Downloads/flutter ~/dev/
$ echo '\nexport PATH=$PATH:$HOME/dev/flutter/bin\n' >> ~/.zshrc
$ source ~/.zshrc
```

<br>
<br>

![sec-vscode.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/982650/ed9a1942-de07-1f7c-b8b3-fc38ee0b6148.png)

- 💙 4. [公式サイト](https://code.visualstudio.com/download) からダウンロードして起動
- 💙 5. 左上から```Flutter拡張機能``` を検索してインストール

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/982650/6d85d9e5-3e84-0b25-7d92-0e6195581d49.png" width="80%">

<br>
<br>

![sec-chrome.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/982650/8bab9c60-cd9e-35a8-8f42-3a9ce10b1c51.png)

- 💙 6. [公式サイト](https://www.google.com/intl/ja_jp/chrome/) からダウンロードして起動するだけ

<br>
<br>

:::note info
ここまでで環境構築は終わっていますが、せっかくなので自分のアプリを作ってみます
:::

![sec-myapp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/982650/13ba3435-0060-67b9-24d3-ff7bc7f18c0f.png)

- 💙 ターミナルで ```flutter create xxx``` を実行 (xxxはアプリ名英語)
- 💙 VSCode で そのフォルダを開く
- 💙 ```main.dart``` ファイルを開いて Run ボタンを押す

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/982650/6b0132fd-f70b-2165-b527-f37d3c02f2ae.png" width="100%">

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/982650/3663488e-4391-8972-e179-818989fe1a50.png" width="50%">

- 💙 うまくいかなければ下のバーから Chrome を選択して、もう一度 Run ボタンを押してみる

![select-chrome.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/982650/37188ae0-09ba-4cb5-9a0e-0f0154149312.png)

実行できたら、さっそくコードを編集して遊んでみましょう！
それでは皆さんも一緒に Let's Flutter! 💙
Rails タグ投稿機能のコード解説

# モデル作成
```
$ rails g model Tag tag_name:string                     //Tagモデル作成
　
$ rails g model TagMap post:references tag:references  //TagMapモデル作成
```
# 投稿画面
```posts/new.html.erb
<%=form_with(model: @post, url: posts_path, local: true) do |f| %>
             <h1>投稿する</h1>
             <%= f.text_field :tag_name%>・・１
             <input type="submit" value="投稿">
<% end %>
```
## コードの解説
１・・<%= f.text_field :tag_name：この行を記述することで、フォームに入力されたタグが、params[:post][:tag_name]というパラメータとしてcreateアクションへ送信される。
# コントローラの作成
```posts_controller.rb
def create
    @post = Post.new(
      content: params[:content],

      user_id: @current_user.id
    )
     tag_list = params[:post][:tag_name].split(nil)・・１
    if image = params[:post][:image]
      @post.image.attach(image)
    end
    if @post.save
       @post.save_tag(tag_list)・・２
       flash[:notice] = '投稿を作成しました'
       redirect_to('/posts/index')
    else
      render('posts/new')
    end
  end
```
## コードの解説
１・・params[:post][:tag_name]はformから、@postオブジェクトを参照してタグの名前も一緒に送信するのでこの形で取得する。次にsplit(nil)で送信されてきた値を、スペースで区切って配列化する。配列化する理由はあとでこの値をデータベースに保存する際に一つずつ繰り返し処理で取り出す必要があるため。
２・・先ほど取得したタグの配列をデータベースに保存する処理をモデルファイルで行うようにする。
タグで入力した値を配列に収めてる（tag_list)を引数としてモデルファイルに渡す。
# Tag_mapモデルファイルの作成
```models/tag_map.rb
class TagMap < ApplicationRecord
  belongs_to :post・・１
  belongs_to :tag・・１
  validates :post_id, presence: true・・２
  validates :tag_id, presence: true・・２
end
```
## コードの解説
１・・複数のPost、複数のTagに所有されるのでbelongs_toで関連付けを行う。
２・・PostとTagの関係を構築する際、2つの外部キーが存在しなければならないのでvalidatesの記述を書きます。
# Tagモデルファイルの作成
```models/tag.rb
class Tag < ApplicationRecord
  has_many :tag_maps, dependent: :destroy, foreign_key: 'tag_id'
  has_many :posts, through: :tag_maps
end
```
## コードの解説
tag_mapsテーブルとの関連付けを行ってから、tag_mapsを通してpostsテーブルと関連づけています。Tag.postsとすれば、タグに紐付けられたPostを取得できる。
# Postモデルファイルの作成
```models/post.rb
class Post < ApplicationRecord
 　　has_many :tag_maps, dependent: :destroy
  has_many :tags, through: :tag_maps
 

  def save_tag(sent_tags)
    current_tags = tags.pluck(:tag_name) unless tags.nil?・・１
    old_tags = current_tags - sent_tags・・２
    new_tags = sent_tags - current_tags・・３

    old_tags.each do |old|
      tags.delete Tag.find_by(tag_name: old)・・４
    end

    new_tags.each do |new|
      new_post_tag = Tag.find_or_create_by(tag_name: new)・・５
      tags << new_post_tag・・5
    end
  end
end
```
## コードの解説
１・・先ほどcreateアクションにて保存した@postに紐付いているタグが存在する場合、タグの名前を配列として全て取得する。
２・・現在取得した@postに存在するタグから、送信されてきたタグを除いたタグをold_tagsとする。
３・・送信されてきたタグから、現在存在するタグを除いたタグをnew_tagsとする。
４・・古いタグを削除する。
５・・新しいタグの保存（tagsにpost_tagを追加して保存）
# 参考記事
[【Rails】gemなしで投稿に対してタグ付けする機能＋タグで投稿を絞り込み表示する機能の実装手順](https://qiita.com/kurawo___D/items/e9a2dd0bf46cca706e5c#6%E3%82%B3%E3%83%B3%E3%83%88%E3%83%AD%E3%83%BC%E3%83%A9%E3%82%92%E4%BD%9C%E6%88%90)
[[Ruby on rails]タグ付け機能① 複数のタグ付け](https://qiita.com/ki_87/items/a344ea566c88b10b950c)
[railsのself.tags << post_tagの意味](https://teratail.com/questions/112236)
Ruby on Railsチュートリアルを完走してみた。

## はじめに
おはこんばんにちは。　村人Cです。
先日超有名な教材である。「Ruby on Rails チュートリアル」
(以後: Railsチュートリアル)を完走したので、振り返りも兼ねて感想を綴っていこうと思います。

## 　のプロフィール
文系大学生　4年　休学中 22歳
2021年2月後半にProgateを初めて触り9月までweb制作を中心に学習。
9月26日からweb開発の学習を独学で開始し今に至る。

## Ruby on Railsチュートリアルに取り組むまでの学習状況

- デザインカンプからのコーディング＋WP化 (Bootstrapも使ったことがある)
- `JavaScript`の言語仕様について学習経験がある。  (なぜそう書くとこう動くのか？)みたいな 

- `sql`の学習経験
- `git`の学習経験
- `ruby`の学習経験
- `rails`の学習経験
- `Linux`の学習経験

ほとんど独学です。web制作の学習には買い切り型のslackサポート付きの教材を購入しました。
web制作の道に進むのであればお勧めしますが、そうでないなら必要ないと思います。

`JavaScript` `SQL` `Git`はyoutube + Udemy

`Ruby`は　progate + youtube + 本

`Rails`は progate + youtube

`Linux`は`Envader`というサービスを利用しました。

`JavaScript`の学習を始めたのは9月26日ですので、Railsチュートリアル完走までに5ヶ月もかけてますね。
あれもこれもとウロチョロしちゃいました。。。


## Ruby on Railsチュートリアル

### 完走までかかった時間

結論から言うと`51日間`で2週しました。
チュートリアルは1章~14章構成なのですが、13章から実装する機能が切り替わります。
ひとまず12章まで進めて、復習のため再度1章から再度12章まで進めました。
その後13章・14章をクリアして51日間で達成しました。
12章で復習をせず、13章14章を進めていたら`1ヶ月`くらいで終わったと思います。

また51日のうち1週間程度はherokuにpushできないエラーと戦っていました。
(ライセンス関係の問題で、Railsチュートリアルに記載されているgemのversionではpushできないバグでした。)
運営者のtwitter垢の呟きをみて解決できました笑。今後テキストを修正されるそうです。

### 取り組む時に意識したこと
webアプリを作る!!　ではなく理解することを意識しました。

チュートリアルを終わらせることが目標なのではなく、理解してRailsを使えるようにするのが目的なので、私の場合は理解することを意識しました。
もちろん暗記をする必要はなく、そのコードを実装する理由や仕組みを理解できるよう意識しました。

RailsチュートリアルではRailsの使い方というよりも、webアプリケーションの仕組みを学ぶことができます。

CRUD処理の役割やMVCモデルの仕組み。　自動ログイン機能を実装するためにCookieにtokenを保存して認証する仕組みなど、Railsというよりはwebアプリケーションの仕組みを学ぶので他の言語やフレームワークを使うことになっても応用可能な知識の習得ができます。

理解するべき知識量がかなりあるため大変ですが、後々自作のwebアプリを作成する際に必ず役立つと思います。

Railsチュートリアルは、英語で言うなれば基本の単語+文法
スポーツであれば体の動かし方など、基礎となる重要な知見を得られる教材かなと思います。
Railsを使わない企業でもRailsチュートリアルを研修で使うらしいです。

## これから挑む人へのアドアイス
railsチュートリアルは初学者には難しいとよく言われます。

コードを一切書いたことがない人が挑むと挫折する可能性が高くなってしまいますが、ある程度準備をしてから挑めば挫折することなく完走できるでしょう。

**私が1から始めるならこの順番でやります**
`Progate`でHTML/ CSS/を2週。
`Udemy`で静的サイトを作成 [こちらで良いかと思います。 必ずセール期間中に買いましょう](https://www.udemy.com/course/html5css3-b/)
`Git`を学習 [こちらがお勧めです。](https://www.udemy.com/course/unscared_git/learn/lecture/6680202?start=15#content)
`Progate`でRubyを学習
`Progate`でRailsを学習
`Udemy`でRails [最新のrails7対応です](https://www.udemy.com/course/the-ultimate-ruby-on-rails-bootcamp/)

*ここまでを2ヶ月以内に終わらせましょう*

`Ruby on Rails　チュートリアル`に挑戦

しっかりと準備をしてから望めば挫折することなく達成することができると思います。

## 終わりに
Railsチュートリアルはかなりの量がありますし大変でしたが、大変良い学びになりました。
これからも精進していきます。
COMBINEメソッドで、知らなかった事

## 皆もすなるQiitaといふものを、儂もしてみむとてするなり。

と言う訳で、こん＊＊は！はなっち！です。

いくらロボットは何でもできる！と言われていても、ファイルに関する位置情報は教えてあげねばならない訳でして。。。

そのファイル位置情報は、「フルパス」と言ったりしますね。そうです。ドライブレターから始まり、フォルダ間を"￥"記号で連結し、最後にファイル名が記述されている。。。
この情報を基に、ロボットだったりプログラムだったりは、そのファイルへアクセスする訳ですね。

そのアクセスに必要なファイル位置情報は、ロボット内部に直接記述してしまうと、ファイル名を変えたい！格納先を変えたい！などの要望に即対応することが難しくなってしまいます。
そこでよく使われるのが、CONFIG.xlsx上にそれら情報を持たせ、ロボット内部では、そこから情報を得る方法ですね。

フォルダ位置と、ファイル名をそれぞれ連結するには、先のCONFIG.xlsxの例では、文字列の連結をすればいいですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/1ab99272-ca0e-041f-4f18-e96848c61cea.png)

フォルダ位置の指定で、末尾に"￥"記号がなく指定する人もいるかと思います。そういった場合には、陽に"￥"記号を付加したのち、ファイル名を連結してあげればいいのですが、それは手間ですね。
そういった場合に、System.IO.Path.Combineメソッドの出番です！

Path.Combineメソッドは、複数の文字列を1つのパスに結合するメソッドです。

ですので、先ほどのCONFIG.xlsxに持たせたフォルダ位置と、ファイル名をこのPath.Combineメソッドを使って、フルパスにしてから利用すればいいですね。

https://docs.microsoft.com/ja-jp/dotnet/api/system.io.path.combine?view=net-6.0

と、ここまではもう既にご存知のことと思います。
私もこのようにして「うまいこと」やってきました。


先日、同じフォルダに格納されている2つのファイルを扱うロボを作成していました。無論CONFIG.xlsxファイルに各情報を持たせています。
開発を進める最中に、2つ目のファイルは、指定フォルダの一つ下のサブフォルダに格納した方がいいなと思い、ファイル名の先頭に、"￥"記号とサブフォルダを追加したのです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/8be9d083-b9fd-b04b-c9ed-13c6dac84260.png)

実行！成功！と思いきや！異常終了！

なんで？と思ったら、2つ目のファイルが存在しないとの事。。。

ログにそのファイル情報を出力すると、確かにフルパスの形式にはなっておらず…

なんでだろう。Combine(String, String)のそれぞれのString変数には、ちゃんと値が設定されているのに...

ドキュメントを読み返してみると、その注釈に
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/213ce1bb-dd15-bea0-052a-aca1ab31315e.png)

と言う記述があり...

>メソッドの代わりに Combine 、 メソッドまたは メソッドの使用 Join を TryJoin 検討してください。

という記述を自動翻訳のミス！？ってんで、良く読んでいなかったのが敗因。

 **Combine メソッドの代わりに、Join メソッドまたは TryJoin メソッドの使用を検討してください。** が正解なんですね。

で、つまり、Combine(String, String)の最初のString変数には **絶対パス** を指定し、以降のString変数には、 **相対パス** を指定しなければならないって訳ですね。

では、どうしたら便利に指定できるか...

相対パスを指定しなければならないところに、先頭に"￥"記号を付した場合にはおかしい挙動となったので、相対パスのところにの先頭に"￥"記号は除外してあげる。

相対パスの先頭の"￥"記号を除外しているので、絶対パスを指定しなければならないところには、その末尾に"￥"記号を付加してあげてはどうだろう？

ってんで、以下のような代入を考えてみました！

 **絶対パス(第1引数)** 
⇒CONFIG("入力フォルダ位置").ToString.TrimEnd("￥")&"￥"
⇒末尾の"￥"記号をトリムして、トリムした結果に、改めて"￥"記号を付加する

 **相対パス(第1引数以外)** 
⇒CONFIG("入力ファイル名1").ToString.TrimStart("￥")
⇒CONFIG("入力ファイル名2").ToString.TrimStart("￥")
⇒先頭の"￥"記号をトリムする

これらを施してから、Combine(String, String)で1つのパスに結合してあげればいいですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/2a8f3730-5012-4b57-7b3f-5590eb4dcf21.png)






【教訓】
・CONFIG.xlsxに情報を格納させる場合、想定外の値が設定される場合がある事を考えよう
・フォルダ位置に関しては、確実に末尾に"￥"が付くようにしよう。
　空振りしてもいいので、TrimEnd("￥")したのち、"￥"を連結する
・ファイル名（、サブフォルダ￥ファイル名）に関しては、先頭に"￥"が無いようにしよう。空振りしてもいいので、TrimStart("￥")する。
・各メソッドもプログラムの一部。使い方を確認しよう。
・自動翻訳を読み砕く力が必要！

##おわりに
いかがでした？

▼.NETは便利なメソッドが用意されています。これを利用する事は、効率的な開発が期待できます。
▼とはいえ、使用に際しては、注意事項は読み（多少のの忖度力は必要ですが）、理解する必要があります。
▼併せて、開発者が説明する、「設定方法はこうですよ」と言った話は守られない（開発者が注意事項を読まないように。。。）
▼ありとあらゆる場合をカヴァーは意味ないが、何かあったら実行者側で解決できるようなメッセージを出してあげる。
　あるいは、問い合わせ窓口に問い合わせていただくような…

今回も読んでいただきありがとうございました！
是非UiPathでのロボ開発の一助になればと思っています。

ありがとうございました！
Deep dive into Laravel Pagination - PHP IteratorAggregate

![1_j7QLwyWSomxwVlUT327I-g.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1709868/56528188-7d64-4c14-7260-4e2727e2c289.jpeg)

Regarding to [Laravel pagination doc](https://laravel.com/docs/6.x/pagination#displaying-pagination-results), when calling the paginate method, you will receive an instance of [Illuminate\Pagination\LengthAwarePaginator](https://laravel.com/api/6.x/Illuminate/Pagination/LengthAwarePaginator.html). When calling the simplePaginate method, you will receive an instance of [Illuminate\Pagination\Paginator](https://laravel.com/api/6.x/Illuminate/Pagination/Paginator.html). These objects provide several methods that describe the result set. In addition to these helpers methods, the paginator instances are iterators and may be looped as an array.

There is a basic example of Laravel pagination in your project
```php
public function index(Request $request)
   {
       $users = User::paginate(15);
       return view('user.index', ['users' => $users]);
   }
```
```php 
<div class="container">
   @foreach ($users as $user)
       {{ $user->name }}
   @endforeach
</div>
```
Here is what you see in detail of $users variable

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dt3whyaqwd6kx79pyims.png)

Now let look at inside [LengthAwarePaginator class](https://github.com/laravel/framework/blob/6.x/src/Illuminate/Pagination/LengthAwarePaginator.php), we can see that it implements several interfaces such as ArrayAccess, Countable, IteratorAggregate, JsonSerializable which are known as [predefined interfaces in PHP](https://www.php.net/manual/en/reserved.interfaces.php). This class also extends AbstractPaginator which has [getIterator()](https://laravel.com/api/6.x/Illuminate/Pagination/AbstractPaginator.html#method_getIterator) to return ArrayIterator

In this case, we consider the IteratorAggregate is an interface to create an external Iterator which allows you to traverse your custom class objects using foreach. With the [Interface synopsis](https://www.php.net/manual/en/class.iteratoraggregate.php), IteratorAggregate extends Traversable interface itself is an abstract base interface (with no methods as shown in the interface synopsis) that cannot be instantiated. However, it can be used to check whether a class is traversable using foreach or not.

```php
class Food implements IteratorAggregate
{
   public array $arr;
 
   public function __construct() {
       $this->arr = ['Milk', 'Cake', 'Coke'];
   }
 
   public function getIterator() {
       return new ArrayIterator($this->arr);
   }
}
 
$obj = new Food();
 
foreach($obj as $key => $value) {
  echo $key ." =>" . $value . "\n";
}
 
======================================
OUTPUT
 
0 => 'Milk'
1 => 'Cake'
2 => 'Coke'
``` 

IteratorAggregate is an easy way to implement an Iterator. The advantage with IteratorAggregate is the speed, it is much faster than its alternatives. The problem with it it's that... despite the name it's not an iterator but a traversable (so again, no next, key, current, valid, rewind methods).
iPadOSの審査ではEthernet接続が使われている

先日、iOSアプリを審査に出したところ「iPadOSで起動時に通信エラーで進めない」とリジェクトされました。
これまでこのようなリジェクトを受けたことはなく、特にサーバーも問題なく動作していました。

では、なぜ審査落ちになったのでしょう。審査落ちのメッセージに添付されていたスクリーンショットを確認したところ、通信インジケーターが出ていませんでした。通常、ここにはWi-FiやCellularのアイコンが表示されているはずです。

![20220303194545.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/609129/8aeea41b-a695-f12d-607c-3811d3733ff4.png)

一応この点について指摘してみましたが「このデバイスは正しくインターネットに接続している。詳しくは教えられない。」という回答があったのみでした。

## iPhone/iPadに有線LANをつなぐ

Wi-FiやCellularの表示がなくても接続できる状況ってあるか…？いや、そういえばEthernetがありました。

実はiOS 9.3以降で、Lightning to USB3 Camera Adapterを使い、そこにUSB-Ethernetアダプタを繋ぐことでEthernet、つまり有線LANに繋ぐことができるようになっています。もちろん、USB-Cポートを備えたiPad Proであれば、直接USB-CにUSB-CのEthernetアダプタをつなぐこともできます。

## なぜEthernetで通信エラーになっていたのか

LightningポートにEthernetを挿せるように環境を整えました。Ethernetアダプタをポートに接続すると、設定アプリにEthernetの項目が増えます。

![20220303194749.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/609129/658cf82f-354d-56c8-0aff-56ea67cf8156.png)

この状態にすることで、問題を再現できました。

このアプリは通信前にFBNetworkReachabilityライブラリでインターネットの疎通をチェックしていますが、このライブラリはCellular接続でない場合はIPアドレスを検出する動作をしていましたが、これがEthernetの環境ではうまく動作していませんでした。

GitHubの最新のコードではこの問題は解消されていましたが、このバージョンはCocoaPodsにリリースされていません。

GitHubを直接参照する形で更新することもできましたが、ライブラリがObjective-Cで記述されていること、現在のアプリはiOS12以降対応になっている等を鑑みて、[NWPathMonitor](https://developer.apple.com/documentation/network/nwpathmonitor)に置き換えて対応することにしました。


今後、通信の疎通にはEthernet接続もあるというのを考慮に入れるようにしたほうが良いと思いました。