OmniAICreator/Qiita-1.07M huggingface dataset:
LINEBOTを利用して、送信したキーワードの検索上位URL複数を返信するBOT

LINEBOTを利用して、送信したキーワードの検索上位URL複数を返信するBOTを作成してみました。
Herokuにデプロイ


```Python
from flask import Flask, request, abort

from linebot import (
    LineBotApi, WebhookHandler
)
from linebot.exceptions import (
    InvalidSignatureError
)
from linebot.models import (
    MessageEvent, TextMessage, TextSendMessage,
)
import os
from googleapiclient.discovery import build
import json

app = Flask(__name__)

with open("secret.json") as f:
    secret = json.load(f)

#GOOGLE_API
ENGINE = secret["ENGINE"]
KEY = secret["KEY"]

CUSTOM_SEARCH_ENGINE_ID = ENGINE
API_KEY = KEY

#環境変数取得
YOUR_CHANNEL_ACCESS_TOKEN = os.environ["YOUR_CHANNEL_ACCESS_TOKEN"]
YOUR_CHANNEL_SECRET = os.environ["YOUR_CHANNEL_SECRET"]

line_bot_api = LineBotApi(YOUR_CHANNEL_ACCESS_TOKEN)
handler = WebhookHandler(YOUR_CHANNEL_SECRET)

@app.route("/callback", methods=['POST'])
def callback():
    # get X-Line-Signature header value
    signature = request.headers['X-Line-Signature']

    # get request body as text
    body = request.get_data(as_text=True)
    app.logger.info("Request body: " + body)

    # handle webhook body
    try:
        handler.handle(body, signature)
    except InvalidSignatureError:
        abort(400)

    return 'OK'

#google_apiで検索して、URLを出す
def search_g(word, num):
    search = build(
    "customsearch", 
    "v1", 
    developerKey = API_KEY
    )

    results = search.cse().list(
                    q = word,
                    cx = CUSTOM_SEARCH_ENGINE_ID,
                    num = num
                ).execute()

    results = results["items"]

    result = []
    for i in results:
        result.append(i["link"])

    result = ', '.join(map(str, result))
    
    return result

@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
    num = 5
    line_bot_api.reply_message(
        event.reply_token,
        [TextSendMessage(text=f"「{event.message.text}」での検索上位[{num}]件です！"),
        TextSendMessage(text=search_g(event.message.text, num))
        ]
    )

if __name__ == "__main__":
#    app.run()
    port = int(os.getenv("PORT", 5000))
    app.run(host="0.0.0.0", port=port)
```


![IMG_7394.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2119179/715b0c59-842c-4e34-6724-4d2c91bb35d0.jpeg)
1分でXserverにFlaskを導入する。(Linuxサーバーへ、python3環境を構築する。

Xserver に、Flaskを導入しよう。
そう考えたものの、かなり詰まりまっておりました。。。

ですが、以下の方法により瞬殺でFlask環境を整えることができたので共有します。

https://kaedeee.com/xserver-flask-python/

今すぐやり方を知りたい！と言う方は、記事の半分あたりより確認してみてください。

#バージョン
Xserver X10
Miniconda3-py38_4.8.3-Linux-x86_64.sh
Python 3.8

#解決前に試していたこと
前提として、このやり方では失敗しました。

1. VScode によるSSH 環境を整える
1. Python3, pip3 インストールしたい←brewコマンド使いたい←Linuxbrew入れよう←git, curlインストール必要、、、と言うことで(xserver ではSudoコマンド使えないので、回りくどい方法に、、、）
1. Linuxbrew をxserver オリジナルのgitとcurlを使って入れてみる→失敗。バージョンが低いとのエラー。
1. git,curlの対応バージョンをusr/local内にインストール&パスを通す。
1. Linuxbrewを入れようとするも2021/11現在、homebrew に統合されたため、そちらインストールしてくださいとのこと
1. homebrewインストール時に、curlをhttps対応することが必須だったので、libcurlを独自にアップデートしようとする。
1. アプデしても無理。curlがバグってるのか対応できない。（多分xserver 独自のlibcurl を使用することになっている？？？）

これもうわかんねぇな。

#解決方法
Minicondaをファイルサーバーに直ダウンロードすることで解決しました。（無理矢理感）

結局、Flask導入にpythonが必要だっただけなので、brewコマンドが使えなくても今のところ問題ない！との判断です。


参考URL
https://dattesar.com/xserver-pip-flask/

#注意ポイント
##AnacondaではなくMinicondaを使うことでファイルサイズを減らす
FlaskでPythonパッケージを利用してますが、今のところMinicondaでも問題ないです。分かるのであれば後入れでパッケージ導入すればいいので

##Minicondaのバージョン
Miniconda3-py38_4.8.3-Linux-x86_64.sh が安定バージョンでした。

##Python バージョン
FlaskのPython安定バージョンはPython3.8 なので、3.9の場合不安定かも。（デフォルトでどちらかがインストールされるはず）

##パスを通すこと
パスを通すことを忘れないように。

##Flask関連のファイルとパーミッション
以下　3ファイル　お気をつけくださいませ。

###.htaccess

パーミッションは、644。
常時SSL化(強制https化）バージョン

```
SetEnvIf Request_URI “." Ngx_Cache_NoCacheMode=off SetEnvIf Request_URI “." Ngx_Cache_StaticMode

RewriteEngine On

RewriteCond %{HTTPS} !on
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /index.cgi/$1 [QSA,L]
```

常時SSL化ではないバージョン。

```
SetEnvIf Request_URI “." Ngx_Cache_NoCacheMode=off SetEnvIf Request_URI “." Ngx_Cache_StaticMode

RewriteEngine On

RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /index.cgi/$1 [QSA,L]
```

###index.cgi
パーミッションは、755
Python仮想化など、ディレクトリが以下ではない場合は一行目を変更してください。

```
#! /home/(User Name)/local/miniconda3/bin/python
from wsgiref.handlers import CGIHandler
from app import app
CGIHandler().run(app)
```

###app.py
パーミッションは600

```
from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello, World!'
```

おしまい！閉廷！

https://kaedeee.com/xserver-flask-python/

参考URL
https://dattesar.com/xserver-pip-flask/
[Vue]warn:The “data” option should be a function that returns a per-instance value in component definitions.

##はじめに
この記事はプログラミング初学者による備忘録用の記事であり、また、少しでも他の初学者のお役に立てればと思い書いています。

今回は、Vueを使用している際に``[Vue warn]: The “data” option should be a function that returns a per-instance value in component definitions.``が発生したので、解決策を備忘録としてまとめておきたいと思います。

間違いなどがございましたら、ご指摘のほどよろしくお願い致します。

##エラー内容
```
[Vue warn]: The “data” option should be a function that returns a per-instance value in component definitions.
```
``「コンポーネント定義において、「data」オプションは、インスタンスごとの値を返す関数でなければなりません」``と警告されています。

今回エラーが発生した状況として、複数の異なるコンポーネント間で、それぞれのdataオプションに同名のオブジェクトを定義していました。
Vueでは、**dataオプションは各コンポーネント間で共有する**特性があり、dataオプションで同名のオブジェクトを定義していたので衝突した状態となっていました。

##解決策
複数のコンポーネントでdataオプションを使用する際は、コンポーネントのdataオプションを関数で定義する。

``~例~``

```
data: function () {
  return {
    xxx: y
  }
}
```

``~注意~``
dataオプションは必ず関数である必要はなく、下記の条件下ではオブジェクト型でも機能します。

・複数のコンポーネントを利用しない
・複数のコンポーネントを利用するが、dataオプションで定義するプロパティ名が重複していない

どんな場面でもエラーが起きないように、普段から関数で定義する方が良さそうですが...。
##参考文献
https://jp.vuejs.org/v2/guide/components.html#data-%E3%81%AF%E9%96%A2%E6%95%B0%E3%81%A7%E3%81%AA%E3%81%91%E3%82%8C%E3%81%B0%E3%81%AA%E3%82%8A%E3%81%BE%E3%81%9B%E3%82%93
【永久保存版】BigQuery 実購買データ分析でよく使うSQL RFM分析編

BigQueryを用いたデータ分析で頻繁に出てくるSQL文をここにまとめます。
各自のデータベースに合わせてお使いください。

##前提

今回用いるテーブルのスキーマとデータ例です。

テーブル名：items

|フィールド名|データ型|説明|
|:---|:---|:--|
|user_id|STRING|ユーザ ID|
|order_id|STRING|受注番号|
|total_price|INTEGER|購入合計金額	|
|item_id|STRING|商品 ID|
|item_name|STRING|商品名|
|category_name|STRING|カテゴリ名|
|purchased_at|DATE|購入日|


|行|user_id|order_id|total_price|item_id|item_name|category_name|purchased_at|
|:---:|:---|:--|:--|:--|:--|:--|:--|
|1|62178|272324|2780|702671|ピカチュウのぬいぐるみ|ぬいぐるみ|2021-11-01|
|2|62178|272324|3830|423852|ピカチュウの帽子|帽子|2021-11-01|
|3|43532|272325|3830|940234|コダックのぬいぐるみ|ぬいぐるみ|2021-11-01|
|4|62178|272324|2780|702671|ピカチュウのぬいぐるみ|ぬいぐるみ|2021-11-03|
|5|28564|272327|1200|435666|ミュウのキーホルダー|キーホルダー|2021-11-04|
|・|・・・|・・・|・・・|・・・|・・・|・・・|・・・|・・・|


##RFM分析

###R値
欲しい結果：今日の日付から購入日までの日数を算出

```sql:R値算出
DATE_DIFF(DATE (CURRENT_DATE("Asia/Tokyo")), CAST (購入日 AS DATE), DAY) AS Recently
```

```sql:例文
SELECT
*,
DATE_DIFF(DATE (CURRENT_DATE("Asia/Tokyo")), CAST (purchased_at AS DATE), DAY) AS Recently
FROM
 items
```

結果（本日が2021/11/11と仮定）

|行|user_id|order_id|total_price|item_id|item_name|category_name|purchased_at|Recently|
|:---:|:---|:--|:--|:--|:--|:--|:--|:--|
|1|62178|272324|2780|702671|ピカチュウのぬいぐるみ|ぬいぐるみ|2021-11-01|10|
|2|62178|272324|3830|423852|ピカチュウの帽子|帽子|2021-11-01|10|
|3|43532|272325|3830|940234|コダックのぬいぐるみ|ぬいぐるみ|2021-11-01|10|
|4|62178|272326|2780|702671|ピカチュウのぬいぐるみ|ぬいぐるみ|2021-11-03|7|
|5|28564|272327|1200|435666|ミュウのキーホルダー|キーホルダー|2021-11-04|6|
|・|・・・|・・・|・・・|・・・|・・・|・・・|・・・|・・・|


###F値
欲しい結果：今日までの購入回数を算出

```sql:F値算出 
DENSE_RANK() OVER (PARTITION BY ユーザーID ORDER BY 購入日 ASC ) AS Frequency
```

```sql:例文
SELECT
*,
DENSE_RANK() OVER (PARTITION BY user_id ORDER BY purchased_at ASC ) AS Frequency
FROM
 items
```


結果

|行|user_id|order_id|total_price|item_id|item_name|category_name|purchased_at|Frequency|
|:---:|:---|:--|:--|:--|:--|:--|:--|:--|
|1|62178|272324|2780|702671|ピカチュウのぬいぐるみ|ぬいぐるみ|2021-11-01|1|
|2|62178|272324|3830|423852|ピカチュウの帽子|帽子|2021-11-01|1|
|3|43532|272325|3830|940234|コダックのぬいぐるみ|ぬいぐるみ|2021-11-01|1|
|4|62178|272324|2780|702671|ピカチュウのぬいぐるみ|ぬいぐるみ|2021-11-03|2|
|5|28564|272327|1200|435666|ミュウのキーホルダー|キーホルダー|2021-11-04|1|
|・|・・・|・・・|・・・|・・・|・・・|・・・|・・・|・・・|



###M値
例：今日の日付から購入日までの日数を算出

```sql:F値算出 
SUM(購入額) OVER(PARTITION BY ユーザーID ORDER BY 注文ID ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS Monetary
```

```sql:例文
SELECT
*,
SUM(total_price) OVER(PARTITION BY user_id ORDER BY order_id ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS Monetary
FROM
 items
```


結果

|行|user_id|order_id|total_price|item_id|item_name|category_name|purchased_at|Monetary|
|:---:|:---|:--|:--|:--|:--|:--|:--|:--|
|1|62178|272324|2780|702671|ピカチュウのぬいぐるみ|ぬいぐるみ|2021-11-01|2780|
|2|62178|272324|3830|423852|ピカチュウの帽子|帽子|2021-11-01|6610|
|3|43532|272325|3830|940234|コダックのぬいぐるみ|ぬいぐるみ|2021-11-01|3830|
|4|62178|272324|2780|702671|ピカチュウのぬいぐるみ|ぬいぐるみ|2021-11-03|9390|
|・|・・・|・・・|・・・|・・・|・・・|・・・|・・・|・・・|
CORSで怒られたら

# 当該エラー
```dart
Access to XMLHttpRequest at 'https://server-hoge' from origin 'https://client-hoge' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
```

## サーバー側（FastAPIの場合）
公式ドキュメントなどを元にCORSの許可を設定

```python
app = FastAPI()

origins = [
    "https://client-hoge",
    "http://localhost",
    "http://localhost:8080",
]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)
```

## クライアント側（Flutterの場合）
`'Access-Control-Allow-Origin': '*'`をヘッダに追加

```dart
headers: <String, String>{
      'Content-Type': 'application/json',
      'Access-Control-Allow-Origin': '*'
    }
```

## CORSについて
CORSについてはこの方が詳しく書いているのでそちらを是非
https://qiita.com/att55/items/2154a8aad8bf1409db2b
mujoco-py（v.2.1.0）のUbuntu 16.04へのインストール

# はじめに
近年の強化学習アルゴリズムは，MuJoCoと呼ばれるシミュレーターにおけるタスクの性能によって評価されることが多いです．MuJoCoはかつてライセンスが必要だったのですが，DeepMindさんが無料で公開してくださった（[ニュースリリース](https://deepmind.com/blog/announcements/mujoco)）ので，mujoco-pyをインストールしてみました．以下，試行錯誤で見つけたインストール手順を記します．
インストール対象はUbuntu 16.04 LTSです．

# MuJoCoのダウンロード
まず，[MuJoCoの公式サイト](https://mujoco.org/download)から，「Linux」をクリックしてダウンロードします．
ダウンロードしてきたmujoco210-linux-x86_64.tar.gzを解凍すると，「mujoco210」のフォルダが現れます．これをそのまま，次のようにコピーします．

```sh
mkdir ~/.mujoco
cp -r mujoco210 ~/.mujoco/mujoco210
```

# mujoco-pyのインストール

## いくつかのエラー対策

### 環境変数の登録

まず，環境変数の登録が必要です．
/etc/environmentを編集します．

```sh
sudo gedit /etc/environment
```

このファイルに次の一行を追記します．HOGEはユーザー名に変更してください．

```sh
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/HOGE/.mujoco/mujoco210/bin:/usr/lib/nvidia
```

ちなみにエラーだと.bashrcを編集するように指示されますが，environmentの方を編集しないといけないようです．（[参考](https://github.com/openai/mujoco-py/issues/489#issuecomment-613704415)）

### libglew-devのインストール

「fatal error: GL/glew.h」が起きることを防ぐために，libglew-devをインストールします．（ある場合はスキップ）

```sh
sudo apt-get install libglew-dev
```

### libopengl0のインストール

「ImportError: libOpenGL.so.0: cannot open shared object file」が起きることを防ぐために「libopengl0」をインストールします．

```sh
sudo apt install libopengl0
```

自分の場合は上記の手順でできなかったので，次の手順でインストールしました．（ある場合はスキップ）

```sh
wget http://ftp.br.debian.org/debian/pool/main/libg/libglvnd/libglvnd0_1.3.4-2+b1_amd64.deb
sudo dpkg -i libglvnd0_1.0.0-2ubuntu2.3_amd64.deb
wget http://ftp.br.debian.org/debian/pool/main/libg/libglvnd/libopengl0_1.3.4-2+b1_amd64.deb
sudo dpkg -i libopengl0_1.3.4-2+b1_amd64.deb
```

### mujoco-pyのインストール

最後に，mujoco-pyをインストールします．pipでそのままインストールできる，MujoCo v.2.1.0に対応したバージョンはまだリリースされていないので，GitHubのリポジトリからインストールします．（[参考](https://github.com/openai/mujoco-py/issues/642#issuecomment-963510299)）

```sh
sudo pip3.7 install git+https://github.com/openai/mujoco-py
```

[リポジトリページ](https://github.com/openai/mujoco-py)にある

> To play with mujoco-py interactively, follow these steps:

のコードが動けばおそらくインストール成功です．お疲れ様でした．

## メモ
mujoco-pyのインストールに失敗するときはエラーメッセージを確認してみてください．

### エラー例：MuJoCoが見つからない

```sh
You appear to be missing MuJoCo.  We expected to find the file here: /root/.mujoco/mujoco210
```
のようになっている場合は，指定されているディレクトリにコピーし，上記のenvironmentの追加部分も適宜変更してみてください．

# 参考文献

 - [openai/mujoco-py](https://github.com/openai/mujoco-py) 

# 備考

### ERROR: GLEW initalization error: Missing GL version
描画した時にこのエラーが出た．上の手順でGLEW自体は入っているはず．
/etc/environment に次の一行を追記：（[参考](https://github.com/openai/mujoco-py/issues/268#issuecomment-595177264)）

```sh
LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libGLEW.so
```
VarnishのTimeoutsデフォルトタイムアウト値と変更について(Lumen Edge)

###本項はLumen Edge Application DeliveryでのVarnishについての記述です
https://lumen-28.hubspotpagebuilder.com/lumen-technologies-japan/lumen-edge-cloud-app-delivery

#VarnishのTimeoutsデフォルトタイムアウト値

通常自分でインストールしたVarnishCacheについては、起動時または実行時に `varnishadm`を介して設定されたとえば、timeout_reqを5秒に増やしたい場合は、 `/ etc / sysconfig / varnish`の起動引数に" -p timeout_req = 5 "を追加するという方法もありますが、Lumen Application Delivery - Varnishに於いてはVCLにて記述を行います。

```ruby:VCL
 backend appserver1 {
 .host = "127.0.0.1";
 .port = "80";
 .between_bytes_timeout = 30s;　#ココの設定値と値の入力でタイムアウトの挙動設定を行います
 }
```

クライアント側のタイムアウト

クライアント側のタイムアウトは、エンドユーザがVarnishにアクセスする際の設定値となります。タイムアウトが通知された後、通常、クライアント接続は閉じられます。

####まず、リクエスト初期段階として：

**timeout_idle（デフォルト：5秒）**：クライアントが完全なリクエストヘッダーを送信する必要があるまで、接続を「accept（）」してから待機する時間。

リクエスト処理の初期フェーズが経過すると、2つの異なるタイマーが有効になり始めます。

**send_timeout（デフォルト：600秒）**は、1回のリクエストで最大で動作する時間を制限します。たとえば、大量のダウンロードやリアルタイムで視聴されるビデオファイルを作成する場合は、これを最長のファイルの長さに増やす必要があります。

**idle_send_timeout（デフォルト：60秒）**は、クライアントがこれ以上データを受信したくないことを（TCP受信ウィンドウを介して）拒否できる時間を制限します。


####バックエンドのタイムアウト:

バックエンドのタイムアウトは、VarnishCacheがバックエンド操作の完了を待機する時間を決定します。

**connect_timeout（デフォルト：3.5s→最大30Sec変更可能）**は、バックエンドへのTCP接続が確立されるまで待機する時間です。

**first_byte_timeout（デフォルト：60秒→最大値60秒変更可能）**は、バックエンドの処理時間を制限します。応答の最初のバイトは、このタイムアウト内にTCP接続を経由する必要があります。

**between_bytes_timeout（デフォルト：60s→最大値60秒変更可能）**は、バックエンド接続で2回の読み取りが成功するまで待機する時間を制限します。

これらのいずれかがオフになると、VarnishCacheはFetchErrorログ行を共有メモリログに記録します。複数のバックエンドがあり、再試行/再起動を構成している場合は、別のバックエンドを要求できます。それ以外の場合、これはハードエラーであり、クライアントは（通常）503 Server Error（ "guru meditation"）応答を受け取ります。

##Varnishに於けるKeep Aliveはどのような設定値になるのか？

HTTP　Keep-aliveとはクライアントがサーバ側と接続した際に現行のコネクションを再利用したいのでOPENにしたままにする機能です。これは再度のTCPのリクエストやハンドシェイクを無くして少しでもレスポンス遅延値改善を目指す点では有効です。HTTP1.1ではデフォルトで有効になります。

Varnishではこの値に於ける設定値は特にありません。TCP上でのConnection：Closeにて終了となります。
現在下記2つの設定値についてはベータとなっているようです。
tcp_keepalive_time
tcp_keepalive_intvl
tcp_keepalive_probes
PixiJSでスーファミみたいなモザイクさせる

![モザイク.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1830166/f2ecfe5c-47ef-0929-45f5-d06a10a10dad.gif)
pixi.jsではフィルターでスーパーファミコンのようなモザイク処理(正しい呼び方がわからない)を行うことができます。

##@pixi/filter-pixelateをインストール
pixi.jsのバージョン5ではモザイク処理は標準では入っていません。

なのでインストールする必要があります。
```
npm install @pixi/filter-pixelate
```
これでモザイク処理が使えるようになります。

##使い方
使う際はまずはインポートします。
```
import {PixelateFilter} from '@pixi/filter-pixelate';
```
そしてモザイク処理を行いたい要素(containerなど)に追加します。
```
this.pixelateFilter = new PixelateFilter();
this.pixelateFilter.size = 1;
this.filters = [this.pixelateFilter];
```
ここまでが準備です。このpixelateFilter.sizeがモザイクの大きさです。1は通常の解像度と同じ大きさです。これが大きくなるとモザイクが大きくなります。

フェードインやフェードアウトで使う際にはループでこのpixelateFilter.sizeの値を大きくしたり小さくしたりするとスーファミで見たことのあるような感じのモザイク処理が出来上がります。


ちなみに上の画像のゲームはこちらです(遊んで！)
▷ [おしっこ忍者](https://wgc-cosmo.com/game/pee_ninja/)

## おまけ
★pixi.jsの基本的な使い方の記事
▷ [【PixiJS入門】基本的な使い方まとめ](https://javascript-game.com/basic-pixijs/)
【PHP】PDFから任意のページを切り出す

PDFから任意のページを切り出して、単一ファイルとしてユーザーに保存させたいときに。
Laravelで実行する場合は、最初のrequire_once()が不要。

# 環境
- Windows 10
- PHP 7.3

# FPDIのインストール
composer.jsonに以下を追記して、composer updateを実行。
```json:composer.json
{
    "require": {
        "setasign/fpdf": "1.8.*",
        "setasign/fpdi": "^2.3"
    }
}
```

[FPDI公式サイト](https://www.setasign.com/products/fpdi/)

# プログラム
PDFから1ページ目と2ページ目だけを切り出して、1つのファイルとしてダウンロードする。

```php:Pdf.php
require_once('vendor/autoload.php');

use setasign\Fpdi\Fpdi;

$pdf = new Fpdi();
$pdf->setSourceFile('target.pdf');

$pdf->AddPage();
$tplId = $pdf->importPage(1);
$pdf->useTemplate($tplId);

$pdf->AddPage();
$tplId = $pdf->importPage(2);
$pdf->useTemplate($tplId, 0, 0, null, null, true);

$pdf->Output('D', 'result.pdf', true);
```

useTemplate()の6つ目の引数でページサイズ調整に対応。
Output()の3つ目の引数で日本語のファイル名に対応。

# PDFのバージョン1.5以上のときにエラーが起きる対策
バージョン1.5以上のPDFはエラーが起きるので、[QPDF](https://sourceforge.net/projects/qpdf/files/ "QPDFダウンロードページ")を使って、対象のPDFを事前に変換しておく。
WindowsにQPDFをダウンロードして、コマンドプロンプトでbinフォルダに移動。

PDFのバージョンを1.4に変更。

```
qpdf --force-version=1.4 input.pdf output.pdf
```
もし上記コマンドで変換したPDFでエラーが出たら、バージョン1.4に変更＋圧縮を解く。

```
qpdf --stream-data=uncompress --force-version=1.4 input.pdf output.pdf
```

# 参考
https://blog.starbug1.com/archives/1866

http://pdf-file.nnn2.com/?p=865
VSCodeとデフォルトのターミナルで動作するPythonが異なる問題【Mac】

#この記事で解決する問題
MacでAnaconda環境を構築して、デフォルトのターミナルではインストールしたPython環境が動作するが、VSCodeのターミナルでは異なるPythonが立ち上がる。これの問題点として、VSCodeのターミナルにおいて各種ライブラリをインポートすることができません。
デフォルトのターミナル
![スクリーンショット 2021-11-11 14.39.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300353/862bd991-b3bd-7a25-a440-7a6d05521180.png "デフォルトのターミナル")
VSCode
![スクリーンショット 2021-11-11 14.41.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300353/9f66aa26-804c-6d97-4292-c4d67806178b.png "VSCode")
色々と調べてみると、デフォルトのターミナルはDockから起動してシステム環境を使用することに対して、VSCodeではインスタンスから環境が継承されるようで、これが原因であるようです。

#解決法
VSCodeの設定を変更するだけで解決するようです。まずは以下のように設定を開きます。
![スクリーンショット 2021-11-11 14.42.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300353/668ad8c8-a805-e4c6-e55c-3b6db9a79cf9.png)
設定を開いたら、以下を入力します。

```
terminal.integrated.inheritEnv
```
![スクリーンショット 2021-11-11 14.44.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300353/554f13c4-9420-c90a-ac53-3f25f3a50090.png)
チェックを外して、VSCodeを再起動すると正常に動作しました。
![スクリーンショット 2021-11-11 14.48.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300353/694243cc-3217-4ac4-65c6-d432522c3f27.png)
お疲れ様でした。

#参考記事
上記問題の原因について書かれている記事：[VSCodeアップデートノート](https://code.visualstudio.com/updates/v1_36#_launch-terminals-with-clean-environments)
LaravelでAPIサーバーを立てるまでの過程

 Laravel8でAPIサーバーを立てていく過程を記録していきます


##作成してみよう！LaravelでAPIを扱う方法【初心者向け】
https://techacademy.jp/magazine/18786

##【JWT】 入門
https://qiita.com/Naoto9282/items/8427918564400968bd2b

##JWTを使って認証周りを作る＆jsonで認証データの受け渡しをしてみる
https://www.avyatech.com/rest-api-with-laravel-8-using-jwt-token/

##Laravel8を試したら即効でエラー「Target class [〇〇〇Controller] does not exist.」が表示された

https://qiita.com/tamakiiii/items/e71040173fa0a1fcad83

下記で解決
https://qiita.com/tamakiiii/items/e71040173fa0a1fcad83#routeserviceproviderphp%E3%81%A7%E5%90%8D%E5%89%8D%E7%A9%BA%E9%96%93%E3%82%92%E6%89%8B%E5%8B%95%E3%81%A7%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B

##JWTのメール認証(MailHog使用)
https://inokawablog.org/code/laravel-vue-jwt-email-auth-3/

##midleware作成
https://qiita.com/shizen-shin/items/5e050bf07b2257a6a1d7
draw.ioで図を描いてみました。

draw.ioとは、無料で使用可能な作図ツールです。
・フローチャート
・ER図
・UML
・AWS構成図
などが書けます。
https://www.draw.io/
※ウェブ上で使用可能（デスクトップアプリ、Chromeアプリもあるみたいです）

仕事ではいつもエクセルを使用していました。
はじめてつかってみたのですが。

・線がまっすぐそろう。
・図の下のテキストが書きやすい。きれいに表示される。
・AWSの図もサイドバーから選んでダブルクリックするだけ。

時短になりそうでいいなぁと思いました。

▼作成してみたもの
![システム構成図.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350277/b7e8b1e1-048d-7548-0f33-7311fc0e22d2.jpeg)
R言語とExcelを用いた重回帰分析の方法5(偏回帰係数検定編)

重回帰分析とは、多変量解析のうち複数の説明変数と一つの目的変数が量的なデータの場合に用いることができる解析手法です。

#前回のおさらいと今回すること
前回は座高、体重、足の大きさから身長を予測する重回帰式は信頼できることがわかりました。
今回は、得られた重回帰式の各説明変数の偏回帰係数が信頼できるか検定します。

#偏回帰係数の検定
重回帰分析から得られた結果と重回帰式は以下のとおりです。
赤丸で囲んだところが今回使用する数値です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2253181/429b4bbb-cc68-531a-f501-be50ac3293a5.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2253181/a4d3ccd7-5bfc-c6d1-7e84-627686632de2.png)
重回帰式の検定から重回帰式の有意性が証明されました。
しかし、各説明変数の偏回帰係数の検定を行う必要があります。
偏回帰係数の検定では、各偏回帰係数が有意に0から偏っているかどうかを検定します。

ここで、帰無仮説と対立仮説を設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2253181/fb948237-4991-66df-9d82-d9aa94efddc2.png)
偏回帰係数の検定では重回帰分析結果からt値とt値を2乗したF値から，それぞれt分布表とF分布表を用いて検定を行います。下記はt値を導出する数式です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2253181/6a004625-1f0c-7b78-8dbe-4dfb6842928c.png)
重回帰分析の結果をまとめると、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2253181/c29bf774-618d-834e-3fd5-0ef1c7eac592.png)
上記の結果から下記のことがわかりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2253181/4191db56-7ff0-fea7-4684-85de788b20b7.png)


結果として、座高の偏回帰係数は信頼できることがわかりました。

#まとめと次回の予定
・重回帰式の偏回帰係数の検定を行いました。
・結果として、座高の偏回帰係数は信頼できることがわかりました。
・次回は、座高のみを用いて再度重回帰分析を行います。

#おまけ(定数項a0の検定)
上記から再度重回帰分析を行う必要がわかり、今回定数項を検定する必要はありませんが、一応記しておきます。
定数項a0の検定では、定数項a0が有意に0から偏っているか検定します。
ここで、帰無仮説と対立仮説を設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2253181/1990f060-9853-5595-1459-6d056f45ce0b.png)
定数項a0の検定では重回帰分析結果からt値とt値を2乗したF値から，それぞれt分布表とF分布表を用いて検定を行います。下記はt値を導出する数式です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2253181/f70cb692-dc4a-5b5e-d87c-2ca473b8fd4b.png)
重回帰分析の結果をまとめると、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2253181/34399242-7555-742a-aed1-b7f8ac1cfe8a.png)
上記の結果から、定数項a0は有意差がないことがわかりました。

#あとがき
偏回帰係数の検定から有意差があるのは座高だけでした。
次回、座高のみを用いて再度重回帰分析しますが、ただの単回帰分析になりそうです。
重回帰分析したかったので、適当に作った元データはちょっと変えたさありますが、とりあえず最後まで頑張ります。

ここまでお読みいただきありがとうございます。
今さら聞けないGit②

##前回まで
前回はGitについて基本的な概念を解説しました。
今回もリマインドのため基本的な概念を説明していきますのでご参考に

前回記事になります。

[今さら聞けないGit](https://qiita.com/AInosukey/items/bd9bedfdfb6b2550e823)

##プッシュとは
リモートリポジトリの自分のローカルリポジトリの変更履歴をアップロードすることです。
アップロードすることで変更履歴を共有することができます。

```
プッシュとは？
リモートリポジトリへのアップロードすること
```

##クローンとは?
リモートリポジトリをローカルリポジトリに複製することです。
クローンを実行するとリモートリポジトリの内容をダウンロードしてローカルリポジトリに作成できます。

```
クローンとは?
リモートリポジトリをローカルリポジトリへダウンロードして複製すること
```

##プルとは？
リモートリポジトリからローカルリポジトリを更新することです。
プルを実行するとリモートリポジトリから最新の変更履歴をダウンロードしてその内容を取り込みます。

```
プルとは？
リモートリポジトリをローカルリポジトリへダウンロードして更新すること
```
##マージとは？
マージ(merge)は合併の意味で、他の人の作業の変更を取り込みます。

```
マージとは？
他の人の作業の変更をダウンロードすること
```


最後にプルしてから次のプッシュするまでの間に他の人がプッシュしてリポジトリを更新するまでの間、他の人のコミットが失われてしまうためプッシュができません。
![諸々画像２.001.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1658175/481bd3cc-e393-3150-9ace-b5096e284642.jpeg)


##競合の解決
マージを行うと自動で変更箇所を統合します。
もし変更箇所が今変更したローカルリポジトリと同じだった場合、競合が起こりエラーが発生します。
これらを解決するのが"競合の解決"です。

```
競合の解決とは？
同じ変更箇所を修正し、統合すること
```

##まとめ
今回も前回に引き続きGitの基本的な概念を解説しました。
ご参考にして下さい。


##参考文献サイト
この記事は以下の情報を参考にして執筆しました。

[サル先生のGit入門](https://backlog.com/ja/git-tutorial/)
[今さら聞けないGit](https://qiita.com/AInosukey/items/bd9bedfdfb6b2550e823)
【Xcode】【エラー】Cannot find 'Analytics' in scope

# どういうことか

オレにもわからない。
なんらかのタイミングで突然出てビルドができなくなった。

## 解決策

- Xcodeを終了させる
- /Pods のディレクトリを削除
- アプリ名.xcworkspace のファイルを削除
- `pod install`
- Xcodeを起動

直った。
一見ドキッとする解決策だけど実際はそれほど怖くないょ。

https://github.com/firebase/firebase-ios-sdk/issues/6066#issuecomment-662580211

おわり(´・ω・｀)
【Swift】【エラー】Binary operator '<' cannot be applied to two 'Int?' operands

# どういうことか

たとえばこんなコードを書いたときに発生する。

```swift
let a: Int? = 1
let b: Int? = 2

print(a < b)
```

「**整数型？である2つの被演算子（オペランド）に対して二項演算子（Binary operator）は使うことができない**」と言っている。
ここのキモは `?` が付いたオプショナル型を比較しようとしていることで、どうもオプショナル型の比較はできないっぽい。

## アンラップする

```swift
let a: Int? = 1
let b: Int? = 2

print(a! < b!)

// true
```

これでもいけるけどなるべく強制アンラップは使いたくない。
`if let` で優しくアンラップする。

```swift
let a: Int? = 1
let b: Int? = 2

if let first = a, let second = b {
    print(first < second)
}

// true
```

おわり(´・ω・｀)
Power AutomateでMS Teamsにメンバーを一括登録

#はじめに
　MS Teamsにメンバーを一括登録する方法についてまとめました。

　MS Teams自体には一括登録する機能がなく、AzuruもしくはPowerShellで登録するのが一般的です。
　しかし、AzuruやPowerShellは権限がないとできないなど一般ユーザー向きではありません。

　そこで、PowerAutometeとExcelで一括登録を実現していきます。

#Excelで登録メンバー表を作成

メンバー情報については、手入力でも良いですが社内や学内のcsvによる名簿があれば、それを利用すると便利です。

ID：（お好みで大丈夫です）
氏名：（お好みで大丈夫です）
メールアドレス：この情報を使ってoffice356テナント内の登録情報から参照して登録します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598641/b56c35d9-5b10-39d1-8a72-e279cd27bac7.png)

Excel表の作成とデータの打ち込みが終わったら、SharePointもしくはOneDriveに登録します。（クラウド処理のため必須です！）

#PowerAutometeフロー作成
まずは、先程のExcelデータに[挿入]>[アドインを入手]>【Microsoft Flow for Excel(Preview)】を追加します。

![スクリーンショット 2021-11-11 133845.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598641/080be707-1a8a-dca8-3b67-e8a744a82ef2.png)
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598641/f1c52d41-63df-f853-83b2-e3f56cd412c3.png"width=40%>

[データ]にFlowが追加されます。Flowを開いてください。
![スクリーンショット 2021-11-11 134707.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598641/cb6b17bd-8a44-0c2b-41b8-4d057850cb2d.png)

[新規]>[インスタント クラウド　フロー]からフローを作成していきます。
!![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598641/0e3cca1b-8a33-aa2c-fd49-467da1fb94b8.png)

[選択した行]で自身が保存したクラウドのExcelまでのリンクを設定します。

↓見本です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598641/8df3a6be-6616-a469-cce6-98ac1b1c6f61.png)

次に、[新しいステップ]から【グループへのメンバーの追加】を追加します
ユーザープリンシパル名:1Excelのメールアドレス行を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598641/9362dad2-7d6a-3e8b-b2d3-ec309a31a7c7.png)

※【グループへのメンバー追加】ではなく【チームにメンバーを追加する】でも利用できるようになりました
MSTeamsメインであればこちらが良いかもしれない
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598641/c367ad66-50c1-2fd5-892a-0a0e3e83a27f.png)


#メンバー追加作業
登録したメンバーのメールアドレスを選択して実行ボタン（再生マーク）を押すと登録が始まります。

![スクリーンショット 2021-11-11 140554.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598641/f36b886d-810c-d4e4-4fd4-48d8617120d4.png)
【Vim】【エラー】E325: ATTENTION Found a swap file by the name

# どういうことか

`$ vi ファイル名` を叩いてVimでファイルを編集しようとしたら発生した。

## 答え

注釈にも書いてあるが

```terminal
(1) Another program may be editing the same file.  If this is the case,
    be careful not to end up with two different instances of the same
    file when making changes.  Quit, or continue with caution.

訳
（1）別のプログラムが同じファイルを編集している可能性があります。 このような場合は、
     同じの2つの異なるインスタンスになってしまわないように注意してください
     変更を加えるときにファイルします。 終了するか、注意して続行してください。
```

例えばターミナルの別タブで同ファイルを編集中とか。
閉じたら直った。

おわり(´・ω・｀)
【Swift】iOS12でSHA-256変換する

# どういうことか

iOS13から**CryptoKit**を使って簡単にSHA-256形式でハッシュ化できるっぽいけどiOS12は対応していないのでなんとかして変換する。

## なんとかする

**CommonCrypto**を使用する。

```swift:EncryptionUtil.swift
import CommonCrypto

class EncryptionUtil {
    
    static func convertToSha256(string: String) -> String {
        
        var result: [CUnsignedChar]
        let digestLength = Int(CC_SHA256_DIGEST_LENGTH)
        
        if let cdata = string.cString(using: String.Encoding.utf8) {
            result = Array(repeating: 0, count: digestLength)
            CC_SHA256(cdata, CC_LONG(cdata.count - 1), &result)
        } else {
            fatalError("SHA256の変換に失敗しました")
        }
        return (0..<digestLength).reduce("") {
            $0 + String(format: "%02hhx", result[$1])
        }
    }
}
```

このクラスに文字列を投げて変換する。

```swift
// 呼び出して変換
print(EncryptionUtil.convertToSha256(string: "パスワード"))

// 変換後
// d8b076148c939d9d2d6eb60458969c486794a4c0fcf0632be58fa5bf6d15aafa
```

[SHA256ハッシュ生成ツール](https://www.milk-island.net/javascript/hashgenerator/sha2_256.html)などを使って比べてみると同じものが出力されてるはず。
おわり(´・ω・｀)

### 参考

https://ryukasublog.com/ios13-sha256/
【Swiftlint】一部だけルールを適用したくない、あるいはしたいとき

# どういうことか

たとえばこういうのを書いたとき

```swift
    private var viewModel: ViewModel!
```

`implicitly_unwrapped_optional` という警告がでてしまう。
「いやここはOKでしょ」というとき。

## ルールを適用外にする

コメントアウトの形式で `swiftlint:disable ルール名` を書くと、そのファイルの**これを書いた以降に**そのルールが適用されなくなる。

```swift
    // swiftlint:disable implicitly_unwrapped_optional
    private var viewModel: ViewModel! // implicitly_unwrapped_optionalの警告が出ない

    @IBOutlet weak var titleLabel: UILabel! // private_outletの警告が出る
    @IBOutlet weak var userImageView: UIImageView! // private_outletの警告が出る
    // swiftlint:disable private_outlet
    @IBOutlet weak var dateLabel: UILabel! // private_outletの警告が出ない
```

## ルールを適用する

逆に `swiftlint:enable ルール名` を書くと、そのファイルの**これを書いた以降に**そのルールが適用される。


```swift
    // swiftlint:disable private_outlet
    @IBOutlet weak var titleLabel: UILabel! // 警告が出ない
    @IBOutlet weak var userImageView: UIImageView! // 警告が出ない
    // swiftlint:enable private_outlet
    @IBOutlet weak var dateLabel: UILabel! // 警告が出る
```

おわり(´・ω・｀)
【エラー】unable to load standard library for target 'x86_64-apple-macosx11.0'

# どういうことか

どういうことかわからない。突然出てビルドがコケるようになった。
なんもしてないのに壊れたぞ！
こんな文も出てた。

⚠️ `using sysroot for 'iPhoneSimulator' but targeting 'MacOSX'`

Xcodeの再起動してもダメだった。

## 解決策

SwiftLintが原因っぽい。
ターミナルでコレを叩いたら直った。

```terminal
xcrun --sdk macosx mint run swiftlint
```

https://qiita.com/temoki/items/b0912f97d8e3fe7b0210

**アリガトーッ！！**
【Swift】APIから取得した日付の文字列を整形した文字列にする

# どういうことか

QiitaのAPIを使って取得した "**2021-01-01T00:00:00+09:00**" こんな感じのISO8601形式のString（Date型ではない）を「2021年01月01日」みたいな文字列に整形して表示したい。

## 変換する

この記事では `DateUtil` という変換するクラスを作成した。
**String → Date → String** という整形をしている。

```swift:DateUtil.swift
import Foundation

class DateUtil {

    static func setupEnUsPosixFormatter() -> DateFormatter {
        let formatter = DateFormatter()
        // 端末設定によって書式が変わらない保証があるen_US_POSIXを指定
        formatter.locale = Locale(identifier: "en_US_POSIX")
        return formatter
    }

    // APIから取得した日付を表示用に変換する
    static func dateStringConverter(string: String) -> String {

        let formatter = DateUtil.setupEnUsPosixFormatter()
        // APIから取得したStringがISO8601形式のため、それに合わせる必要がある
        formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
        guard let date = formatter.date(from: string) else { return "" }
        // 表示用に変換する
        formatter.dateFormat = "yyyy年MM月dd日"
        return formatter.string(from: date)
    }
}
```

あとはこのクラスに値を渡して返してもらうだけ。
以下はtableViewのセルに配置したLabelにQiitaAPIから取得した `updated_at` を表示している。

```swift:ViewController.swift
cell.dateLabel.text = DateUtil.dateStringConverter(string: article.updated_at)
```

おわり(´・ω・｀)
Windows+WSL2+Ubuntu+Docker+PhpStorm で Xdebug 使ったり使わなかったりしたい

### 本番環境、Localの開発環境。LocalでXdebug使いたいときなどなど。環境を切り替えてテストしたりコーディングしたり等などしたいという欲望


```Docker:Dockerfile
#全共通なを記述
FROM php:8.0-fpm as production
RUN apt-get update \
    && apt-get install -y curl zip ....
#以下略

#上記の全共通に追加でLocalのみを記述
FROM production as local
RUN apt-get update \
    && apt-get install -y vim procps \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

# local環境に追記でXdebugを使いたい
FROM local as xdebug
RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"
COPY conf/conf.d/xdebug.ini /usr/local/etc/php/conf.d/xdebug.ini
RUN pecl install xdebug \
    && docker-php-ext-enable xdebug.so \
    && echo "xdebug.idekey = PHPSTORM" >> $PHP_INI_DIR/conf.d/xdebug.ini \
    && ....
    # 以下略
```

Targetの指定を変更することで、すきなときにすきなように環境をbuildできて幸せになれる
`target: production`
`target: local`
`target: xdebug`

```docker-compose.yml
  php-fpm:
    container_name: xxx.php-fpm
    build:
      context: ../docker/php-fpm
      target: local  # production|local|xdebug
    image: xxx/php-fpm
    volumes:
      - ../src:/var/www:cached
    environment:
      TZ: "Asia/Tokyo"
      LOG_CHANNEL: 'stack'
    networks:
      - backend
```

```conf/conf.d/xdebug.ini
xdebug.mode=debug
xdebug.start_with_request=yes
xdebug.client_host=host.docker.internal
xdebug.client_port=9003
xdebug.log=/var/log/xdebug.log
xdebug.start_upon_error=yes
xdebug.discover_client_host=false
```
####あとはお好きなように...
```bash
$ docker-compose up -d --build
```
rails new するのにmysql2くんが素直に入ってくれない

ぼくについて：プログラムに触って十ン年経つもののコーディングを真面目に始めてからは数ヶ月のド初心者です。

今回はrails newして新しいこと試すぞー、と思った矢先に心を折られたので初投稿です。
動作環境はこちら。
OS:windows 10 home
ruby:3.0.2←たぶんすべての元凶。
rails:6.1.4
mysql:8.0.22

#概要
`rails new myapp --database=mysql`しただけなのに、エラーが出る。謎い。えー？なんで？
初心者なので、こんな簡単そうなこともわかりません。
ていうかこないだ（※数ヶ月前）に書いたappでは動いてたじゃん。その時は2.6.6だったから、絶対これバージョンアップしたのが悪いんだけど、windows単体じゃバージョン管理は出来ないって調べたら出てくるし……

###やったこと
・とりあえずrubyとMSYSをアンインストールして再インストールした。変わらず。
・調べたら「opensslが古い可能性があるよ」というのが出てきたので、`gem update`をかける。ちょっと表記が進む……！？でもエラー。うーん。
・そもそもmysql2が入ってないんじゃないか？という可能性を調べ、`gem install mysql2`をすることに。エラー。**extconf.rbというファイルがない**というエラーを起こしていることに気がつく。で、それはどうやったら解決すんの？→なんかmysql-develてーのをyumするといいらしい。windows語で言ってくれ

##これから
とりあえず何はともあれ仮想マシンを立ててLinuxでやってみたほうがいいのでは？本番環境もCentOSだし……
awsにssh接続しhttpdは再起動出来たが　外部接続する　http://hogehoge　のIPアドレスが分からない

以下質問書いている途中で思い出したのでメモ失礼いたします。

```
お世話になっております。

時間が出来たため
以前ショッピングカート（？）を作り途中だったawsのEC2を弄っております……

ssh接続は出来て
``
[root@ip-111-22-3-202 ~]# service httpd restart
``
としてふとアクセスしようとしたのですが
awsで動作しているEC2のグローバルIPアドレスが分かりかねます……

ifconfig　で表示された
``
[root@ip-111-22-3-202 ~]# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 9001
        inet 111.22.3.202  netmask 255.255.240.0  broadcast …
``
　　　　　　↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑のIPアドレスではないようなので
どのようにして今ssh接続しているawsのIPアドレスはわかるのでしょうか？

```
……とココまで書いてawsに接続すると”パブリックIPアドレス”とありましたのでこちらですね……
TextMeshProのOverflowについて(2021年11月11日現在)

# TextMeshProのOverflowについて(2021年11月11日現在)
### TextMeshProコンポーネントの各パラメーターを検証していたときに、Overflowに関する情報がネット上にあまり見つからなかったので、検証できた範囲で載せます。

---

## Overflowとは
#### TextMeshProに入力したテキストが、垂直表示範囲を超えている場合にどのように表示するか設定するパラメーター。

---

## Overflowの設定値

```
// TextMeshProのテキストには、下記の内容を入力
あいうえお
かきくけこさしすせそ
たちつてと
なにぬねの
```

### ①Overflow
テキストが表示範囲を超えている場合に、全てのテキストを表示する。
![スクリーンショット 2021-11-11 12.44.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/794916/c408a395-55a0-98e1-c335-651a404065af.png)

### ②Ellipsis
テキストが表示範囲を超えている場合に、表示範囲内の行までは最終行末に「・・・」をつけて表示し、それ以降の行は表示されない。
![スクリーンショット 2021-11-11 12.44.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/794916/34d19b73-df4f-ed62-af1c-b259037d869e.png)

### ③Truncate
テキストが表示範囲を超えている場合に、表示範囲内の行までは表示し、それ以降の行は表示されない。
![スクリーンショット 2021-11-11 12.44.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/794916/3559fef7-d8d9-897b-3fc2-5c81aee0d03a.png)

### ④Page
テキストが表示範囲を超えている場合に、自動ページ分割する。
パラメーターの右側に入力欄が表示されるようになる。
例えば、3ページに分割されているとすると、右側の入力欄に1を入力すると1ページ目、2を入力すると2ページ目が表示される。
#### 1ページ目↓
![スクリーンショット 2021-11-11 12.45.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/794916/f868f81f-d878-405b-d069-963950a228f4.png)

#### 2ページ目↓
![スクリーンショット 2021-11-11 12.45.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/794916/4d359ef3-0680-59c6-2c2e-cdbe78699c8c.png)

#### 3ページ目↓
![スクリーンショット 2021-11-11 12.45.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/794916/c6eb9783-735b-96f2-6036-8f6f14a687e9.png)

### ⑤Linked
テキストが表示範囲を超えている場合に、他のTextMeshProに超えている箇所のテキストを代替表示させる。
パラメーター右側に代替表示させるTextMeshProのオブジェクトを設定できるようになる。
![スクリーンショット 2021-11-11 12.49.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/794916/38de5600-8d4d-654c-fb4b-da41266509fc.png)

#### 代替表示させるTextMeshProをシーンの上部に設置↓
![スクリーンショット 2021-11-11 12.49.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/794916/c8393789-dd55-d3bf-6be6-aac461a7a09e.png)

---

#### ※ MaskingとScroll Rectに関しては、おそらく機能未実装だと思われます。
Maskingの語意から考えて、表示範囲を超えたら超えた分のテキストを隠すなどにするはずですが、現状はOverflowと同じ挙動です。
また、Scroll Rectの語意から考えて、表示範囲を超えたらスクロールバーか何かで表示範囲を変更できるなどにするはずですが、現状はOverflowと同じ挙動です。

---
MySQLのjson型の検索メモ

MySQLのjson型カラムの値での検索を試してみた。

## 準備

```sql:テーブル定義
CREATE TABLE `json_test` (
  `id` int unsigned NOT NULL AUTO_INCREMENT,
  `item` json DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
```

```sql:データ
INSERT INTO `json_test` (`id`, `item`)
VALUES
	(1, '{\"key\": 1, \"value\": \"AAAA\"}'),
	(2, '{\"key\": 10, \"child\": {\"key\": 100, \"value\": \"XXXXX\"}, \"value\": \"AAAA\"}'),
	(3, '{\"items\": [{\"key\": 1, \"value\": \"AAAA\"}, {\"key\": 2, \"value\": \"BBBBB\"}]}'),
	(4, '[{\"key\": 4, \"value\": \"CCCCC\"}, {\"key\": 5, \"value\": \"DDDDD\"}]');
```

## オブジェクトを検索

```json:対象データ
{
  "key": 1,
  "value": "AAAA"
}
```

```sql
SELECT * FROM json_test WHERE item->"$.key" = 1;
```

```sql:文字列の場合
SELECT * FROM json_test WHERE item->"$.value" = "AAAA";
```


## オブジェクト配下のオブジェクトを検索

```json
{
  "key": 10,
  "value": "AAAA",
  "child": {
    "key": 100,
    "value": "XXXXX"
  }
}
```

```sql
SELECT * FROM json_test WHERE item->"$.child.key" = 100;
```

## 配列を検索

```json
[
  {
    "key": 4,
    "value": "CCCCC"
  },
  {
    "key": 5,
    "value": "DDDDD"
  }
]
```

```sql
SELECT * FROM json_test WHERE json_contains(item->"$[*].key", '4');
```

```sql:文字列の場合
SELECT * FROM json_test WHERE json_contains(item->"$[*].value", '"DDDDD"');
```

## オブジェクト配下の配列を検索

```json
{
  "items": [
    {
      "key": 1,
      "value": "AAAA"
    },
    {
      "key": 2,
      "value": "BBBBB"
    }
  ]
}
```

```sql
SELECT * FROM json_test WHERE json_contains(item->"$.items[*].key", '2');
```

## おまけ

同様にselect句でjsonの要素を取得可能。

```
mysql> SELECT item->"$.child.value" FROM json_test WHERE item->"$.child.key" = 100;
+-----------------------+
| item->"$.child.value" |
+-----------------------+
| "XXXXX"               |
+-----------------------+
```

ただ、下記のケースで `DDDDD` だけをselectするにはどうしたらよいのだろうか。

```
mysql> SELECT item->"$[*].value" FROM json_test WHERE json_contains(item->"$[*].value", '"DDDDD"');
+--------------------+
| item->"$[*].value" |
+--------------------+
| ["CCCCC", "DDDDD"] |
+--------------------+
```
記事のリセットします

#なぜ記事をリセットするのか

約5年ぶりの投稿で恐縮ですが、一度記事をリセットしようかなと思っています。
一番の理由としては情報が古すぎるので逆に混乱の原因になりそうだと思ったからです。
今なら5年前よりは少しは進歩しているつもりなので、もう少し分かりやすい投稿が今なら出来るかもしれないと思ったというのも理由の一つです。
(もちろん5年前の記事なので自分が見たくないという気持ちもあります)

今の会社に入社してすぐ右も左も分からず、聞く人も居なくて手探りでやっていた時の備忘録なので、今見ると何とも恥ずかしい気持ちになりますが、5年ぶりにログインした際に今年に入ってもブックマークして下さる人が居る事に驚きありがたい気持ちになりました。ブックマークして下さってた方、本当にありがとうございました。

5年前の記事を5年ぶりに確認しました。主に以下に分類できるかなと思います。
1. docker + gpu 関連
2. Jetsonネタ
3. Windows + gpu pythonライブラリ関連

dockerについては[このNVIDIAの記事](https://medium.com/nvidiajapan/nvidia-docker-%E3%81%A3%E3%81%A6%E4%BB%8A%E3%81%A9%E3%81%86%E3%81%AA%E3%81%A3%E3%81%A6%E3%82%8B%E3%81%AE-20-09-%E7%89%88-558fae883f44)がとても分かりやすく現状が解説されているので、そちらをご参照戴ければ幸いです(NVIDIA Container Toolkitも登場してかなり6年前とは変わってきています)。
JetsonについてはCuPyがaarch64のwheelの公開を開始したりと、色々ネタはありそうなので、家でJetson Nanoで動かしてその辺りも書けたらなぁとは思っています。

Windowsは…CUDA on WSL2が熱いですが、そうではなくWindows上でanacondaを動かされている方も多数いらっしゃると聞きますので、時間があれば…

# 今後の予定
今後は、公式の発信ではなくもう少しゆるく発信したいなぁという時にこちらで投稿していきたいと思います。
時々、複数のお客さんから同じ質問を受ける事があり「この記事を参照して下さい」と言えれば良いのになぁと思う事があるので、そういう用途も含めてゆるく使えればと思います。
Laravel Sanctumでユーザー認証APIを作成する


### Laravel Sanctumとは...
SPA(シングルページアプリケーション)、モバイルアプリケーション、およびシンプルなトークンベースのAPIに軽い認証システム
Reference: https://readouble.com/laravel/8.x/ja/sanctum.html

### 実装準備

``` 
$ composer require laravel/sanctum
$ php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
```

### Http/kernel.phpで下記を書き換えます
```
// sanctumをAPImiddlewareグループに追加する。
// SPAからの受信リクエストがLaravelのセッションクッキーを使用して認証できるようになります。
'api' => [
            
       \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
            'throttle:api',
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],
```


### config/sanctum.phpで下記を書き換えます。
```
// ファーストパーティドメインを設定する(SPAからリクエストを行うドメインを設定)
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
        '%s%s',
        'localhost,localhost:8000,127.0.0.1,127.0.0.1:8000,::1',
        env('APP_URL') ? ',' . parse_url(env('APP_URL'), PHP_URL_HOST) : ''
    ))),
```


### LoginControllerを作成して、ログイン/ログアウト機能を実装する
```
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class LoginController extends Controller
{
    /**
     * Handle an authentication attempt.
     *
     * @param  Request  $request
     * @return \Illuminate\Http\Response
     */
    public function login(Request $request)
    {
        $credentials = $request->validate([
            'email' => ['required', 'email'],
            'password' => ['required'],
        ]);

        if (Auth::attempt($credentials)) {
            $request->session()->regenerate();

            return response()->json(Auth::user());
        }

        return response()->json([], 401);
    }


    /**
     * Log the user out of the application.
     *
     * @param  Request $request
     * @return \Illuminate\Http\Response
     */
    public function logout(Request $request)
    {
        Auth::logout();

        $request->session()->invalidate();

        $request->session()->regenerateToken();

        return response()->json(true);
    }
}
```


### api.phpでmiddlewareにauth:sanctumを設定する
```
Route::group(['middleware' => 'auth:sanctum'], function () {
    // ログイン後にしかできないルーティングを記述
    Route::apiResource('hoges', 'HogeController');
});

// ログイン/ログアウトのルーティング
Route::post('login', 'LoginController@login');
Route::post('logout', 'LoginController@logout');
```


### フロント側に下記を追加して、ログインできているかを確認する
```
import axios from "axios"
useEffect(() => {
    axios.post('/api/login', {
        email: 'hoge@example.com',
        password: 'hogehoge'
    }).then(response => {
        console.log(response)
    })
}, [])
```

上記を追加後、consoleで確認します。
loginできていればloginできたユーザー情報が表示できていると思います。
Laravel8を始めるにあたっての参考サイト、学習過程

来年にLaravel9(LTS)が出るそうなので準備としてLaravel８に触れておこうと思い勉強を始めました。参考サイトや学習過程を記録していきます。

##環境構築
https://www.youtube.com/watch?v=t5PPCfcpq4A

##ダミーデータを入れようとしたところ次のエラー、Call to undefined method Database\Factories\PostFactory::setContainer()
参考にしたサイト
https://stackoverflow.com/questions/57235572/laravel-5-8-call-to-undefined-method-carsetcontainer-when-using-php-artisan
Modelではなくseederを呼ばなければいけませんでした
JetPack4.6でのDeepStreamSDK6.0の動作確認


# 背景

GTC2021の私の担当講演で、講演収録時 JetPack4.6でDeepStreamSDK6.0 BetaはTensorRT version不一致で動作しなかったので、JetPack4.6ではDeepStreamSDK6.0が動いていない等の情報を発表してしまう。

## JetPack4.6でのDeepStreamSDK6.0の対応状況(結論)

最新のJetPack4.6とDeepStreamSDK6.0では、動作確認の結果、問題なく動作する事を確認。

## 検証Pipeline

```
cd /opt/nvidia/deepstream/deepstream/samples/
```

```
gst-launch-1.0 filesrc location= streams/sample_1080p_h264.mp4 ! qtdemux ! h264parse ! nvv4l2decoder  ! m.sink_0 nvstreammux name=m batch-size=4 width=1920 height=1080 ! nvinfer config-file-path= configs/deepstream-app/config_infer_primary.txt  batch-size=4 unique-id=1 ! nvtracker ll-lib-file=/opt/nvidia/deepstream/deepstream-6.0/lib/libnvds_nvmultiobjecttracker.so  ! nvinfer config-file-path= configs/deepstream-app/config_infer_secondary_carcolor.txt batch-size=16 unique-id=2 infer-on-gie-id=1 infer-on-class-ids=0  ! nvmultistreamtiler rows=2 columns=2 width=1280 height=720 ! nvvideoconvert ! nvdsosd ! nvegltransform  ! nveglglessink filesrc location= streams/sample_1080p_h264.mp4 ! qtdemux ! h264parse ! nvv4l2decoder  ! m.sink_1 filesrc location= streams/sample_1080p_h264.mp4 ! qtdemux ! h264parse ! nvv4l2decoder  ! m.sink_2 filesrc location= streams/sample_1080p_h264.mp4 ! qtdemux ! h264parse ! nvv4l2decoder ! m.sink_3
```

## まとめ

講演にて最新情報の方、公開できずに、すみませんでした。JetPack4.6でDeepStreamSDK6.0は対応しています。

情報を訂正します。
メモ〜汎用ビューで指定したモデルの変換ルール

今回のお題
-
汎用ビューで`model`を指定した場合にどのようなキーで`context`の中に保存されるのかを自分用に残しておきます。

ルール１〜大文字は全て小文字に変換
-
そのままです。

例えば

```python
model = Book
```
であればcontextでのキーは`book`になります。

ルール２〜途中にハイフンは入らない
-
よくある`アッパーキャメルケース` > `スネークケース`の変換とは異なり、単語区切りに`-`が入ることはありません。

```django
# モデル
model = CustomUser
# 変換後
{{ customuser }}
```

ルール３〜複数のインスタンスをリストで渡す場合はxxx_list
-
`ListView`などのように条件に合ったものをリストにして渡す場合には、`xxx_list`というキーでcontextに渡ります。

```django
{# veiws.py #}
model = Shops

{# templates #}
{{ shop_list }}
```


終わりに
-
一度覚えてしまえば大したことはないと思いますが、当たり前すぎて調べても意外と出てこなかったので自分で用意しました。
【Rails】Formオプションdisabledとreadonlyの違い

##環境
Ruby 3.0.2
Rails 6.1.4.1


##disabledとreadonlyの違い

```disabled: true```でフォームを送信すると**paramsに値は入らない**
```readonly: true```でフォームを送信すると**paramsに値が入る**

```html.slim
= f.label :name, '名前'
  = f.text_field :name, disabled: true
```

https://bonoponz.hatenablog.com/entry/2020/11/12/%E3%80%90HTML%E3%80%91%3Cinput%3E%E3%82%BF%E3%82%B0%E3%81%AEreadonly%E5%B1%9E%E6%80%A7%E3%81%A8disabled%E5%B1%9E%E6%80%A7%E3%81%AE%E9%81%95%E3%81%84
Lookerで凡例を改行表示させる方法


Lookerで凡例を改行する方法を発見したので忘れないようにメモ投稿しておきます

:::note warn
バージョンはLooker21~の新UIでの対応方法になります。
:::

# 用途
Lookerでグラフ表示対象の項目名に長い名称が付いている場合で、ダッシュボード上で文字がはみ出てしまう。
という悩みを解消できる。

↓ こういう感じのやつ
![Looker_凡例の改行1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242038/d0cdf07d-c319-d5c4-fff5-15c2a6cf5a57.png)



# 作業手順

1) Lookを開いて、Editを選択する
![Looker_凡例の改行2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242038/760a6428-8344-ee42-d976-2aefeeb91609.png)


２） VisualizationのEditから、Seriesを選択し、Customizationsで**改行表示したい項目のLabel内に１文字半角スペースを入れてからLookを保存する**

![Looker_凡例の改行3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242038/46275707-f068-6260-362d-4989ab183b82.png)

:::note info
上記では、「株式会社XXXXX_株価( 終値:７日移動平均値)」という感じで、終値の前に1文字半角スペースを入れてます
:::


３) ダッシュボード上で凡例の文字がはみ出る場合、改行されるようになった！！！
![Looker_凡例の改行4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242038/f34520b8-2551-c39b-82ff-6dbc563cf125.png)

# あとがき
これでダッシュボード上の凡例はみ出る問題は解決となりますが、
**半角スペースを入れると改行される。というのは正直わかりづらいので、凡例の改行はデフォルトで反映してくれると良いですよね。** 凡例は記号化したり短くする方が良い。と言われればそれまでではありますが、稀に長くなっちゃったりすることもあるんです。。
git push コマンド (省略なし)

`git push` コマンドの引数の順番などよく忘れてしまう為覚書。

```shell
git push [オプション] リモート名 ローカルブランチ:リモートのブランチ
```
ちなみにローカルブランチ名を指定せずに記載するとリモートのブランチを削除できる。
削除に関しては、`--delete`, `-d`オプションもあるので、どちらを使っても良い。

https://atmarkit.itmedia.co.jp/ait/articles/2005/21/news023.html
WSLgでLinuxGUIアプリを開こうとしても開けない場合の対処法

# 概要
要するに、DISPLAY変数の設定に気を付けましょうというお話です。

```bash
$ echo ${DISPLAY}
:0
```
になっていればOKです。

以下Xserverの設定をwin10時代に頑張っていた人向け。そうでない人も是非。

# Windows11でついに誰でもWSL2でGUIアプリを使えるようになりました

https://docs.microsoft.com/ja-jp/windows/wsl/tutorials/gui-apps

ここで告知があったように、WSLg（Windows Subsystem for Linux GUI)を導入した場合にはLinuxのGUIアプリが使えるようになりました。
Windows 10 バージョン22000.0以降（つまりWindows 11以降、Windows 10 バージョン21H1では利用不可）を導入している場合に利用可能です。Windows11を使わせようとしていますね。

ただし、最近使えるようになった `wsl --install`で入れるWSL2ではだめで **Microsoft StoreからインストールしたWSLg**でないと2021/11現在ではだめなようです。


https://devblogs.microsoft.com/commandline/a-preview-of-wsl-in-the-microsoft-store-is-now-available/

これまで普通のUbuntuなら誰もが愛用しているであろうGeditですら簡単には動かなかったですが、(内蔵GPUでもいいのでGPUの設定を少しだけすると)`sudo apt install gedit -y`しただけで`gedit ./hoge.txt`が起動できるようになりました。

![gedit.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356864/e940e710-6287-062a-9db4-37e75cb010d5.png)

# Windows10時代のGUIのためのWSL2の設定
私はこれまで、Windows10でWSL2を用いてGUIアプリケーションを動かすために、以下のフローを踏む必要がありました。

- X Serverが必要なのでVcXsrvをWindows側にインストール
- WSL2のファイアウォールの設定を緩くする
    - 「Windows Defender ファイアウォールのプロパティ->パブリック プロファイル->保護されているネットワーク接続: カスタマイズ」を外す
- (bashrcなどを用いて)Linux側でDISPLAY変数の設定を毎回シェル上でする

最後の「(bashrcなどを用いて)Linux側でDISPLAY変数の設定を毎回シェル上でする」については、WSL2では毎回Linux側のホストIPが変わるために、以下の方法がwslのGitHubリポジトリで提案され、日本語記事でも広く取り上げられています。

```bash
export DISPLAY=$(cat /etc/resolv.conf | grep nameserver | awk '{print $2}'):0
```

出所: https://github.com/microsoft/WSL/issues/4106#issuecomment-501885675

# Windows11+WSLgの時代にどうすべきか
このbashrcを流用したまま意気揚々と

```bash
sudo apt install gedit -y
gedit ~/.bashrc
```
をしたところ、うんともすんともいいませんでした。
ただ、同じことに苦しんでいる人がいて解決方法が提示されていました。

https://github.com/microsoft/WSL/issues/7250#issuecomment-951511866

要するに、

```bash
export DISPLAY=$(cat /etc/resolv.conf | grep nameserver | awk '{print $2}'):0
```

これをしなければよかったのです。一件落着。

デフォルトで

```bash
$ echo ${DISPLAY}
:0
```
このようになるので、おそらく`DISPLAY`を書き換えてしまっていたのがよくなかったのでしょう。