OmniAICreator/Qiita-1.07M huggingface dataset:
props.childrenにpropsを渡す。【React/cloneElement】

# はじめに
props.childrenに対してpropsを持たせたい！となったので実装方法を探してみました。
*こちらは学習用メモです
*ドキュメントにあります。

## cloneElement()
ReactにはcloneElementというAPIがあります。
今回はこちらを使用し、propsを渡していきました。

### cloneElementの役割
> element から新しい React 要素を複製して返します。結果の要素は元の要素の props と新しい props が浅くマージされたものを持ちます。新しい子要素は既存の子要素を置き換えます。key と ref は元の要素から保持されます。（引用：　https://ja.reactjs.org/docs/react-api.html）

上記の通りにelementから新しいReact要素を複製という部分のelementがprops.childrenに値するという考えです。
使用する際は`key と ref は元の要素から保持されます。`こちらに注意しながら実装を行うといいかもしれません。

### cloneElement/引数

```react
React.cloneElement(
  element, // <= 複製するelement
  [props], // <= 複製するelementに適応させるprops
  [...children] // <=複製するelementのchildrenとなる要素を指定
)
```

## 使用例
今回紹介する例はあくまで例なので、都合上props.childrenに渡したいという時に使用することと
本当にコンポーネント設計は正しいか確認の必要があると思います。

### 親コンポーネントの作成

```tsx:ItemList.tsx
import { Item } from './Item'
import { ItemChild } from './ItemChild'

export const ItemList = () => {
  return (
    <div>
      <Item>
        <ItemChild />
      </Item>
    </div>

  )
}

```


### props.childrenにpropsを渡す設定

```tsx:Item.tsx

export const Item = (props) => {

  const items = [
    {id: 1, name: 'hoge1'},
    {id: 2, name: 'hoge2'}
  ]
  // ここで渡す設定を行うコンポーネントを作成。
  const ChildrenItem = (props) => {
    // children === props.children, 渡したいprops === ...newProps
    const { children, ...newProps } = props;
    const childrenWithProps = React.Children.map(children, (child: React.ReactElement) => React.cloneElement(child, { ...newProps }));
  }

  return (
    { 
      items.map((item, index) => {
         // item、 indexがprops.childrenに渡したいprops
        <ChildrenItem item={item} index={index}> 
          {props.children}
        </ChildrenItem>
      }
    }
  )
}

```

### MyItemコンポーネント　(propsを渡される props.children)

```tsx:MyItem.tsx
export const MyItem = (props) => {
　// ItemListコンポーネントではpropsを設定していないがcloneElementの設定により受け取ることができる。
  const { item, index } = props

  return (
    <div>
      <div>index: { index }</div>
      <div>itemName: { item.name }</div>
    </div>

  )
}

```


## 終わりに
実際に開発で使用した実装内容だと必要になったのですが、propsの順を追う時に若干厄介になる可能性があるので使用の際は本当に使う必要があるのかなど考える必要があることがわかりました。


## 参考
[【React の最上位 API】 cloneElement()](https://ja.reactjs.org/docs/react-api.html#cloneelement)
[https://qiita.com/NeGI1009/items/e6ad87320391c836bcf9](https://qiita.com/NeGI1009/items/e6ad87320391c836bcf9)
React.Chilrenについてあまり説明をしていなかったので知りたい方は下記
[Reactのchildren探訪](https://qiita.com/jkr_2255/items/2e40f7c9ecf300e8d945)
私がAPMで見たいもの

# 本旨
過去にとあるAPM(※)を使ったことがあり、また今の仕事でも使うことになったため、
私がAPMで何を確認したいかを書き出してみたいと思います。

※ APM・・・アプリケーション性能監視ツール

こんなのもあるよ、というご意見があると幸いです。

# 補足、注意事項

いわゆる定期報告のケースは現場によって大きく異なるため除き、障害などトラブルに焦点を絞ります。

私が知っているAPMは

- Dynatrace
- New Relic

です。

また、本稿は上記のいずれかにも捉われず、本質的に確認したいことを列挙していきたいと思います。

# ケース１：障害解析＜処理エラー＞（原因究明）
### シナリオ概要
ある日、処理エラーに関するエラー発報があり調査することになった。その原因を特定して解消したい。

### APMで確認すること
|確認したい要素|出ていて欲しい情報|
|-|-|
|どのサーバで発生したか|サーバ名①|
|ロジックのどの箇所でエラー(Exception)が発生したか|エラー発生ロジック名、行数、StackTrace②|
|エラーとなった際に処理しようとしたパラメータは表示されているか|エラー出力ロジック内で指定したパラメータ（自前実装含）③|

### 確認〜解消の仕方

- アラートに記載のリンクからAPMにアクセスする
    - できれば当該エラーリクエストの詳細画面②に飛んで欲しい(できない前提で以下)
- リクエスト一覧から、エラーリクエストを選択し②を確認する
- エラーリクエストの詳細画面に出ている「出ていて欲しい情報」を確認する
- ②に対応するソースコードを開き、③の情報と合わせて原因を特定する
    - 必要に応じてDBログや①のアクセスログを参照する
- ①に対して緊急リリース・再起動等を行い解消する

# ケース２：障害解析＜処理エラー＞（影響調査）
### シナリオ概要
ある日、処理エラーに関するエラー発報があり調査することになった。その影響範囲を特定したい。

### APMで確認すること
|確認したい要素|出ていて欲しい情報|
|-|-|
|現在も継続してエラー発報しているか|エラーレートのグラフ(X:時間, Y:エラー率)④|
|エラーは全てのサーバで発生しているか|サーバ毎のエラーレートのグラフ④(上と同じ)|
|エラーは同じロジック箇所で必ず発生しているか|エラー発生ロジック名、行数、StackTrace②|
|エラーが発生する処理データに法則性があるか|エラー出力ロジック内で指定したパラメータ（自前実装含）③|
|サーバは正常な(負荷)状態か|サーバのリソース情報⑤|

### 確認〜解消の仕方

- APMのダッシュボードを開く(④を含むものを作っておくこと）
- ④からエラーが発生しているサーバのリクエスト一覧を開く
- リクエスト一覧から、エラーリクエストを選択し②を確認する
- 複数のエラーで②・③を確認し集計して影響範囲を検討する
- ④にサーバに偏りがある場合は、サーバのOSログやアクセスログ、⑤を確認する

# ケース3：障害解析＜応答遅延＞（原因究明）
### シナリオ概要
ある日、応答遅延に関するエラー発報があり調査することになった。その原因を特定して解消したい。

### APMで確認すること
|確認したい要素|出ていて欲しい情報|
|-|-|
|遅延は全てのサーバで発生しているか|サーバ×機能毎の応答時間のグラフ⑥|
|サーバは正常な(負荷)状態か|サーバのリソース情報⑤|
|ロジックのどの箇所で遅延が発生したか|エラー発生ロジック名、行数、StackTrace②|
|ロジックのStackTrace毎にどれくらい処理時間がかかっているか|StackTrace毎の処理時間⑦|
|遅延が発生する処理データに法則性があるか|ロジック内での出力ログ（自前実装含）、DBログと突合するためのDBアクセス時間⑧|

### 確認〜解消の仕方

- APMのダッシュボードを開く(⑥を含むものを作っておくこと）
- アラートに記載されたサーバのリクエスト一覧を開く
- リクエスト一覧から、エラーリクエストを選択し②を確認する
- ⑦を確認して、平常時よりも大きくかかっている処理箇所を確認する
- ⑥(⑤)でサーバに偏りがないか、⑧で処理対象データに法則性がないかなど総合的に検討し原因究明する
- 遅延が発生しているサーバに対し、サーバ再起動や緊急リリース、あるいは静観等の対処を実施する

# ケース4：障害解析＜応答遅延＞（影響調査）
### シナリオ概要
ある日、応答遅延に関するエラー発報があり調査することになった。その影響範囲を特定したい。

### APMで確認すること
|確認したい要素|出ていて欲しい情報|
|-|-|
|遅延は全てのサーバで発生しているか|サーバ×機能毎の応答時間のグラフ⑥|
|遅延が発生する処理データに法則性があるか|ロジック内での出力ログ（自前実装含）、DBログと突合するためのDBアクセス時間⑧|

### 確認〜解消の仕方

- APMのダッシュボードを開く(④を含むものを作っておくこと）
- ⑥から以下を確認する
    - どの機能（提供サービス）で発生したか
    - どれくらい(秒数)遅延したか
    - いつからいつまで発生していたか
- ⑧から以下を確認する
    - 対象ユーザの範囲は全員か、特定の範囲か

# 最後に
ダッシュボードはカラフルだと綺麗なんですが、必要な情報だけに絞ったスマートさも追い求めていきたいですね。
よく使うイメージ

# Linux
- busybox `組み込みLinux`
- alpine `muslとBusyBoxをベース`
- debian
- ubuntu

# プログラム言語
- python
    - gcr.io/distroless/python3-debian10
- golang

# データベース
- mysql
- mariadb
- mongo
    - mongo-express
- redis

# webサービス
- nginx
- nginx/unit
- scrapinghub/splash `JavaScriptレンダリング`
- jupyter/scipy-notebook `jupyter`


# その他
- emscripten/emsdk `WebAssembly`
- hectormolinero/xubuntu `x-window`
- dorowu/ubuntu-desktop-lxde-vnc `vnc`
Phaser3で複数のシーンを扱うときの物理（arcade）の追加方法！

Phaser3の[公式？のコード例](https://phaser.io/examples/v3/)的な場所には複数のシーンの切り替え＋物理演算？(arcade)の追加の欲しかったドンピシャの情報が無く、this.うんちゃら....と書かれていて脳筋の数打ちゃで時間を浪費したのでもしよければ用です。
※出来てから気が付いたのですが、コード例の中にもドンピシャの情報はありました。

game = new Phaser.Game(config);で

```
//configの今回関わりそうな部分のみ抜粋
let config = 
{
	type: Phaser.AUTO,
	parent: 'game',
	physics: 
　　　　{
	　　default: 'arcade',
	　　arcade: 
　　　　　　{
	　　　　gravity: 
　　　　　　　　{
                　debug: false,
		　　　y: 300
　　　　　　　　}
　　　　　　}
	},
	scene: [
        Title_Scene,
        About_Scene,
        Game_Scene,
        ]
};
```

```
class Game_Scene extends Phaser.Scene {

	constructor() {
		super({
            key: 'Game_Scene'
        });
	}

	preload() {
        this.load.image('ball', 'img/ball.png');
	}

	create() {
    ball = this.physics.add.sprite(50, 50, 'ball');
    ball.body.velocity.set(150, 150);
    ball.body.collideWorldBounds = true;
    ball.body.bounce.set(1);
	}

	update() {
	}
}
```
で、画面の設定にもよると思いますが画面端で跳ね返るボールが出来ました！！！

ポイントは、
game.physics.startSystem(Phaser.Physics.ARCADE);
    ball = game.add.sprite(50, 50, 'ball');
    game.physics.enable(ball, Phaser.Physics.ARCADE);
のあたりをまとめて、
ball = this.physics.add.sprite(50, 50, 'ball');
の一行でどうにかしていることにあるんですかね...？

web上でスマホアプリみたいなゲームを作ろうとして、phaserの勉強がてら[MNDのブロック崩しゲーム](https://developer.mozilla.org/ja/docs/Games/Tutorials/2D_breakout_game_Phaser)を組み込んでみようとして陥った感じです。

広告で流れてくる鍵を引っこ抜いて溶岩でダバーするゲーム作りたいなと思って始めたphaserでしたがまだまだ道のりは長そうです...
parameter 1 is not of type 'Node'

実務でquerySelectorで最初のクラス要素を取得しようとしたらコンソールで以下のエラーが出た。

```
Uncaught TypeError: Failed to execute 'querySelector' on 'Node': parameter 1 is not of type 'Node'
```

例によってエラー文言で検索すると英語の記事が出てきた。
https://stackoverflow.com/questions/27079598/error-failed-to-execute-appendchild-on-node-parameter-1-is-not-of-type-no

存在しない要素を呼んでてnullが返ってるのだという。
確認すると後から追加された要素なのでDOMで取得できないのは当たり前だった。
WSL2コマンドメモ

# WSL2を使うときにいつも忘れるコマンドメモ
* `wsl --help` が分かりやすいのでそれだけで十分だが、結構分量あるのでよく使う奴だけメモ

## 停止(Linux上でShutdownできないので、PowserShellから実行)

```
# 起動中のディストリビューション確認
PS C:\Users\xxxx.xxx> wsl -l -v
  NAME                   STATE           VERSION
* docker-desktop-data    Stopped         2
  docker-desktop         Stopped         2
  Ubuntu-20.04           Running         2

# 停止(ディストリビューションを指定して停止)
PS C:\Users\xxxx.xxx> wsl -t Ubuntu-20.04 

# 停止確認
PS C:\Users\xxxx.xxx> wsl -l -v
  NAME                   STATE           VERSION
* docker-desktop-data    Stopped         2
  docker-desktop         Stopped         2
  Ubuntu-20.04           Stopped         2 
```

## Linuxのコマンド実行 (今回はUbuntu)
* Linuxコマンド使いたい時に
   * exec使う: `wsl -d Ubuntu-20.04 exec $cmd`
   * 例: `wsl -d Ubuntu-20.04 exec hostname -I`

## PortForwardするとき
* WSL2上で立ち上げたサービスを、「外部から使用するとき」「内部のDockerContainerから使用するとき」に使用
* Windows側のポートを開放し、通信されたらWSL2のポートへと転送する
* 手順 (netsh.exeを使用する為、管理者権限で起動したPowerShell上から実行)
   * 1.古いIPへの転送を停止
   * 2.WSL2側のIPを取得(WSL2を起動するたびにPort変わるので、毎回取得
   * 3.2で取得したIPへPortFoward

```
# 1.古いIPへの転送停止
PS C:\Users\xxxx.xxx>
$ netsh.exe interface portproxy delete v4tov4 listenport=312

# 2.WSL2側のIPを取得(ipを複数取得されるときのためぬい)
PS C:\Users\xxxx.xxx>
$ $IP=wsl -d Ubuntu-20.04 exec hostname -I | %{ $_.Split(" ")[0] }

# 3.2で取得したIPへPortFoward
PS C:\Users\xxxx.xxx>
$ $PORT=3128
PS C:\Users\xxxx.xxx>
$ netsh.exe interface portproxy add v4tov4 listenaddress=* listenport=$PORT connectaddress=$IP connectport=$PORT

# おまけ 監視中のPortFoward設定確認
PS C:\Users\xxxx.xxx>
$ netsh interface portproxy show all
```
Amazon Connect、Get Customer Inputブロックの謎設定 Enter an ARN の設定方法がわかった！


最近、別々のAWSアカウント越しにいろいろ連携する方法をリサーチしています。

今回は、**Amazon Connectのコンタクトフロー**から、**別のAWSアカウントにあるLexボットを呼び出したい！**がゴールです。

## フツーのLexボット連携の場合
Amazon Connectと同一アカウント内のLexボットを連携するフツーのケースでは、Get Customer Inputブロックの**Amazon Lex**セクションで**Select a Lex bot**を選択すると、ドロップダウンリストから目的のLexボットを選べるので、チョロいわけです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308847/e0bdaea1-bef1-3068-26cb-76d4e5713bdd.png)

じゃあ、**Enter an ARNすれば他アカウントのLexボットも呼び出せるんじゃないか？**
と思ったら、、、意外と簡単じゃなかった。。

## Enter an ARNの公式ドキュメントがない問題
Enter an ARNを選んでみるも、パッと見とフィーリングで設定がわからないので
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308847/d1bb24d9-1db0-a52e-1a34-b32193ce33eb.png)



グーグル先生に尋ねると・・・

**公式ドキュメントに記載がなーい！**（2021年8月28日現在）

## LexボットのARNってどうやってゲットするの？問題
・・・じゃあ、適当に設定してみるか。

ということで管理コンソールでAmazon Lexのいろいろなページを見ても、ボットのARNがズバリ！記載されているページがありません。。

[公式ドキュメント](https://docs.aws.amazon.com/ja_jp/lex/latest/dg/security_iam_service-with-iam.html)の例をもとに、`arn:aws:lex:ap-northeast-1:123456789012:bot:OrderFlowers`的な（左記のアカウントIDとボット名は例）ARNをいろいろ試すわけですが
・・・ことごとくこのような
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308847/ef6ae11f-5e0b-1477-5b55-2b7bf6556fee.png)
エラーが出てPublishできません。

試行錯誤の結果たどり着いた答えは、、、

**Amazon Lex v1 （Classic）はARN経由で連携できない**

です。

[このドキュメント](https://docs.aws.amazon.com/ja_jp/connect/latest/adminguide/amazon-lex.html#lex-bot-create-flow-add-bot)の 7.c. には、7.b. のClassicボット（v1）との対比で、「Amazon Lex ボット**の場合は**、ボットエイリアス ARN を手動で設定することもできます。」と書いてありますね。

## Lex v2のボットならコンタクトフローをPublishできる
Lex v1（Classic）ボットの連携がうまく行かないので、目先を変えてLex v2ボットでテストすることにしました。

Lex [V2 開発者ガイド](https://docs.aws.amazon.com/ja_jp/lexv2/latest/dg/security_iam_resource-based-policy-examples.html)を見ると、例として`arn:aws:lex:Region:123456789012:bot-alias/MYBOT/MYBOTALIAS`というARNが載っています。

調べた結果、ここで言う**MYBOT**とは、これ↓を指し
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308847/fa445852-1d18-13ee-00d0-345f11d0d7b2.png)

**MYBOTALIAS**とは、これ↓を指します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308847/11e7812b-f8ff-adf1-d678-2919c8272af4.png)

なので、

`arn:aws:lex:ap-northeast-1:123456789012:bot-alias/DSPP8M6EKZ/O3SUP4JK56`

的な（上記アカウントIDは参考例）ARNを指定すると、**めでたくコンタクトフローがPublishできます！やったー！**

## ところが！
当初このテストをしていた8月11日時点では、Amazon ConnectのコンタクトフローはLex v2ボットとは連携できない制約があり、結局コンタクトフローは動きませんでした。。。

というオチで終わる予定だったのですが

8月末に再調査していたら、なんと8月12日にこの制約がなくなったと[いう](https://aws.amazon.com/jp/about-aws/whats-new/2021/08/amazon-connect-amazon-lex-v2-console-apis/)じゃあーりませんか！
本日（9月14日）再度テストしたところ、**無事に他アカウントのボットを呼び出せました！**
Yay！
MVCモデルとは【初学者向け】

##はじめに
MVCモデルについて初学者向けにまとめてみました。ただしMVCは奥が深いのでこの記事を読んだだけでは完璧な理解には及ばないでしょう。なので少しでもMVCの全体像を掴んでもらえたらいいなと思っています。
この記事を読むにあたって前提知識としてCRUD処理がわかっている必要があります。もし分からない方は下記の記事を先に読んでみて下さい。
<a href="https://blog.senseshare.jp/crud.html">Web開発のキホン「CRUD」をわかりやすく解説 </a>

#目次
・MVCとは
・modelとは
・viewとは
・controllerとは
・なぜMVCを使うのか
・まとめ

##MVCとは
MVCとはmodel, view, controller の略でそれぞれ
model → システムのロジックの部分
view → ユーザーが操作したり、入力をする部分
controller → ユーザーからの入力をmodelやviewに橋渡しする部分
を指します。ただこれだとわかりにくいので今のところは覚えなくて大丈夫です。
そもそもMVCとは機能ではなく概念のことで、別にMVCではなくてもアプリ開発をすることはできます。ただMVCを使い役割ごとに機能を分けて開発をすると良いことが沢山あります。
具体的なメリットは「なぜMVCを使うのか」で解説するのでまずは役割ごとの機能を見ていきましょう！

##modelとは
前述ではシステムのロジックの部分と書いたのですがmodelでは基本的にデータベースとのやり取りの部分を作っていきます。具体的に「作成」「更新」「削除」といった処理を実装します。CRUD処理の「表示」以外ですね。


##viewとは
viewはCRUD処理の「表示」の部分にあたります。
そしてviewではHTMLを「動的」に生成することができます。では動的なHTMLとは何か。
皆さんが知ってるものでわかりやすく例えるとTwitterのタイムラインがあります。タイムラインはアクセス時によって表示順が変わり常にリアルタイムで変動していきますよね。それはアクセスする度にデータベースから最新のツイートを表示するという処理を行なっているからです。このようにアクセスによって表示(HTML)が変わったりするものを動的なHTMLと呼びます。


##controllerとは
controllerは前述ではmodelとviewの橋渡しと記述したのですが、細かく説明するとクライアントからきたリクエストをcontrollerで受け取って受け取った指示をmodelに渡してデータベースからデータを取得それをさらにcontrollerに渡して最後にviewに渡して動的に生成されたHTMLをクライアントに返します。


##流れ
リクエストからレスポンスまでの流れをレストランに例えてまとめてみました。
お客さん(クライアント)からcontroller料理長にオーダー(リクエスト)を頼むと料理長は新人のmodel店員に冷蔵庫(サーバー)から具材を取ってきてと頼みます。そしてmodel店員が持ってきてくれた材料でcontroller料理長はオーダーされた料理(view)を作りお客さん(クライアント)に渡します(レスポンス)。
まとめると
リクエスト→controller→model→controller→view→レスポンス
といった流れになります。
現実世界でもレストランに限らず役割を分けることで効率化や専門性を高めていますよね。



##なぜMVCを使うのか
ここまででmodel,view,controllerについてはある程度理解できたと思いますのでここからはMVCを使うメリット、デメリットについて説明していきます。
####MVCを使うメリット
・役割の応じて専門性の高い仕事が可能。
・「M」「V」「C」でそれぞれ独立性が高いため変更の対応も素早く行える。
・役割をわけることでコードを管理しやすい。
まとめるとMVCと分けて管理することで役割ごとの専門性が高くなり作業効率とクオリティが上がる。またバグの修正やトラブルに応じた変更も素早く行える。

####MVCを使デメリット
・オブジェクトの複数作成が必要で、処理に時間がかかる。
・オブジェクト間のやりとりに制約がかかり、コードを柔軟に記述できなくなる可能性がある。
当たり前ですが開発規模の拡大につれて処理が複雑になり管理が大変になります。それにより結果として修正が困難になる場合があったりします。またMVCフレームワークを使う場合生の言語に比べて制約が多くなったりするのでコードを柔軟に記述できなかったりもします。

##まとめ
お疲れ様です。ここまで読み終われた方はMVCは概念でただ役割を分けているだけであるということはなんとなくわかったはずです。
最後にMVCのメリットデメリットをまとめましたが総合的にMVCは開発者にとって「M」「V」「C」と明確に分割されているため、とても開発しやすくなり快適に仕事が進んだりとメリットの方が多いと言えるでしょう。
冒頭でも話しましたがこれを読んだだけではMVCを理解したとはまだ言えないのであとは手を動かして実際にMVCの概念に触れていくといいと思います。

##参考サイト
Laravelフレームワークで体系的にわかりやすくCRUD処理を実装できる記事を見つけましたのでこの記事を読んだ後にチャレンジしてみることをお勧めします。
<a href="https://qiita.com/sayama0402/items/668f7148759910f65da9">Laravel5.6入門 基本CRUD操作を体で覚える</a>
Linuxコマンド（ユーザー管理編）

#ユーザー管理
ユーザー管理する際に使うコマンドをまとめて見ました。

###suコマンド
```
# su [ユーザー名]

ユーザーを切り替える。指定しなければ、スーパーユーザー(root)に変更する。
戻るときは、exitコマンドを使う。
```

###idコマンド
```
# id [オプション] [ユーザー名]

登録されているユーザアカウントやユーザ情報表示する。

実行結果
uid=200(xxxxx) gid=20(yyyyy) groups=20(yyyy)
```

##passwdコマンド
```
# passwd [ユーザー名]

パスワードを変更する。
```

##User管理コマンド

###useraddコマンド
```
# useradd [オプション] [ユーザー名]

userアカウントを作成する。

---------------------------
オプション

-g [グループ名]　
#プライマリーグループを指定する。
---------------------------
```

###usermodコマンド
```
# usermod [オプション] [ユーザー名]

既存のuserアカウント変更する。

---------------------------
オプション

-g [グループ名]　
#プライマリーグループを指定して変更する。
---------------------------
```

###userdelコマンド
```
# userdel [オプション] [ユーザー名]

userアカウント削除する。

---------------------------
オプション

-f　

#ホームディレクトリも同時に作城する。
---------------------------
```





##Group管理コマンド

###groupaddコマンド
```
# groupadd [グループ名]

groupを作成する。
```

###groupmodコマンド
```
# groupmod [オプション] [グループ名]

既存のグループを変更する。

---------------------------
オプション

-n [変更前グループ名]　 [変更後グループ名]　
#グループ名の変更する。
---------------------------
```

###groupdelコマンド
```
# groupdel [オプション] [ユーザー名]

グループを削除する。
```
##所有者の変更

###chownコマンド
```
# chown [オプション] [ユーザ] [:グループ] or [ファイル名] or [ディレクトリ名]

所有者を変更できるコマンドです。rootユーザのみ

実行例

# chown test:staff hoge.txt
# ls -l

-rw-rw-r-- test staff 2000 9 4 09:00 hoge.txt

hoge.txtのユーザーとグループを変更できる。

---------------------------
オプション

-R 
#指定したディレクトリとその中の全てのファイルの所有者を変更する。
---------------------------
```

###chgrpコマンド
```
# chgrp [オプション] [グループ] 

ファイルやディレクトリの所属するグループを変更できる。
rootユーザーまたは、実行するユーザーが所属しているグループのみ

---------------------------
オプション

-R 
#指定したディレクトリとその中の全てのファイルの所有グループを変更する。
---------------------------
```
Ubuntu上のVScodeで「Ctrl+Shift+E」ショートカットが動作しない問題の解決方法

記事タイトルの問題を解決したときの原因調査結果と解決策について記載してます。

## 動作しなかった原因

Ubuntuのインプットメソッドフレームワークの**ibus**([wiki](https://ja.wikipedia.org/wiki/IBus))の絵文字関連機能にも
「Ctrl+Shift+E」ショートカットキーが設定され、競合していることが原因だった([参考サイト](https://askubuntu.com/questions/1125726/how-to-disable-ctrl-shift-e-keybinding-from-showing-eeeee-and-loading-emoji-opti))。

## 解決方法

以下手順で自分のUbuntu20.04環境にて問題が解決されたことを確認しました。

1. ibusのGUI設定画面を`ibus-setup`コマンドで呼び出す。
2. 「絵文字 > キーボードショートカット > 絵文字ルビ」で設定されている  
   **\<Control>\<Shift>e**を削除する。

![Peek 2021-09-14 16-04.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138429/7ddb6e56-e05a-4f9d-7460-d9453b1b0747.gif)
apache再起動手順



#apache再起動手順

## 目的
初心者でもapacheサービスを再起動できる手順書であること。

## 前提
rootに変更する為のパスワードを把握できていること。

## 手順
### 1. rootユーザになる
以降の操作は全てrootユーザで行いますので、必ずrootに変わってください。

```
su -
```

### 2. パスワードの入力
パスワードの入力を求められるので入力する。

### 3. apacheのプロセスが実行中である事を確認する。
以下のコマンドを投入します。

```
ps -ef | grep httpd
```

以下の画像のように、「/usr/sbin/httpd」という表示が多数見られればOK。

![01.apache-01.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374511/66ccaa72-8c0a-3590-40b7-8688a0c3e1c3.png)

### 4. apacheのサービスが正常に起動している事を確認
以下のコマンドを投入します。

```
systemctl status httpd.service
```

以下のように、「Active: active (running)」という緑色の表記であればOK。

![02.apache-02.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374511/644aa760-84e9-c7bd-88ff-29de88a2d626.png)


### 5. サービスのステータス確認を終了
[ctrl]+[c]で抜ける。

### 6. apacheサービスを再起動
以下のコマンドを投入します。

```
systemctl restart httpd.service
```

コマンド投入後は何も起こらず、改行されたかのように、以下画像のように表示されていればOK。

![03. apache-03.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374511/02aee19b-fbe5-cec1-aa99-ab08be695e31.png)

### 7. apacheのステータスを確認
4と同じコマンドを投入。

```
systemctl status httpd.service
```

以下のように、「Active: active (running)」という緑色の表記であればOK。

![04.apache-04.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374511/20568c0e-f2d6-ac19-59a8-c30865531a7c.png)

### 8. サービスのステータス確認を終了

[ctrl]+[c]で抜ける。

以上です。
[UE4] UE4.25以降のEditorマルチプレイでサーバーへの接続を手動にする

#【概要】
UE4ではEditorでマルチプレイを開始すると、デフォルトでクライアントはサーバーに自動的に接続するように設定されている。
非常に便利で有り難いのだが、たまに手動で接続を行いたい場合もある。
UE4.24までは、Auto Connect To Serverをfalseに設定することで、自動接続をオフにして手動で接続することが出来た。

https://twitter.com/hogetatu/status/816278908903440384

ただし、UE4.25以降ではこの設定が非推奨になり表示されなくなってしまった。

```LevelEditorPlaySettings.h
/**
 * When running multiple players or a dedicated server the client need to connect to the server, this option sets how they connect
 *
 * If this is checked, the clients will automatically connect to the launched server, if false they will launch into the map and wait
 */
UE_DEPRECATED(4.25, "This variable is no longer read. Use PlayNetMode = EPlayNetMode::PIE_Standalone instead to prevent auto-connection.")
UPROPERTY(config)
bool AutoConnectToServer;
```
ここでは、4.25以降で接続を手動にする方法を記載する。

#【方法】
以下の手順でプレイすることにより、手動でサーバーに接続することが出来る。
1.`Editor Preferences > Level Editor > Play > Multiplayer Options > Launch Separate Server`をtrueに設定
2.NetModeを`Play Standalone`に設定しプレイ
3.`open 127.0.0.1:<ポート番号>`でサーバーに接続(ポート番号は同じくEditor設定のServerPortから設定可能)
Firebase ClashlyticsをSPMで導入する際に困ったこと

FirebaseのClashlyticsをSwift Package Managerを使って導入するときに詰まった点があったので備忘録

# FirebaseApp.configure()をしておく

(ここ)[[https://firebase.google.com/docs/ios/setup?authuser=0#initialize-firebase](https://firebase.google.com/docs/ios/setup?authuser=0#initialize-firebase)]にあるように、``pplication:didFinishLaunchingWithOptions:``内でFirebaseApp.configure()を実行しFirebaseを初期化する必要あり（Cocoa PodsでもCarthageでも一緒ですが）

# RunScriptでスクリプトの記述

(ここ)[[https://firebase.google.cn/docs/crashlytics/get-started?hl=ja&platform=ios#set-up-dsym-uploading](https://firebase.google.cn/docs/crashlytics/get-started?hl=ja&platform=ios#set-up-dsym-uploading)]に書いてあるように、レポートを作成する際にプロジェクトのデバッグ シンボル（dSYM）ファイルが必要らしい。これはアプリをビルドする度にXcode側で生成し、dSYMファイルをアップロードする必要があるので、RunScriptに下記のコマンドを実行すると書いてあるが

```cpp
"${PODS_ROOT}/FirebaseCrashlytics/run"
```

これはCocoa PodsでClashlyticsを導入した時のスクリプトなので、spmの際は下記のスクリプトを実行しなければいけない

```cpp
${BUILD_DIR%Build/*}/SourcePackages/checkouts/firebase-ios-sdk/Crashlytics/run
```

RunScriptのinputファイルには下記の二つを指定

```cpp
${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Resources/DWARF/${TARGET_NAME}
$(SRCROOT)/$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)
```

# 実際にクラッシュレポートを送るときはsimulatorとの接続を切る

これで詰まったのだが、XcodeでRunを実行し、立ち上がったアプリだとクラッシュレポートが送れないらしい。なのでアプリを立ち上げた後にXcode側で□ボタンでアプリを停止する。そしてsimulator側でホームボタンを二回押し、該当アプリを上にスライドで消去し、もう一度アプリを一から立ち上げて使えばレポートが送信できるようになる。レポートの送信タイミングはクラッシュした後にXcodeで再びアプリをRunしたときであり、その際にログ画面に`Completed report submission`と表示されていれば送信できているということになる。
Makefile で起動されるシェルをカスタムする

# Overview

Makefile は1行単位でシェルコマンドで起動されるけど、このシェルを変更したいときとかあるじゃないですか。

## 具体的には

デフォルトだと `/bin/sh` なので、 `source` が使えないので bash に差し替えたいときとか。

それ自体は Makefile の `SHELL` 変数に使いたいシェルを指定してあげれば実現できます。
cf. https://qiita.com/nassy20/items/3183cc17f36a3f21e333

```Makefile:Makefile
a:
	@ echo ${SHELL}
	@ echo $${BASH_VERSION}
	@ echo $${ZSH_VERSION}
```

```bash:bash
$ make
/bin/sh
3.2.57(1)-release

$ make SHELL=/bin/bash
/bin/bash
3.2.57(1)-release

$ make SHELL=/bin/zsh
/bin/zsh

5.7.1
```

# 自前のシェルを使いたい

で、内部的にはたぶん `${SHELL} -c "指定されたコマンド"` が実行されてるんですねこれ。
cf. https://stackoverflow.com/questions/40203215/customize-shell-in-makefile-set-shell-my-shell-sh

## なので

上記の stackoverflow のコメントにある通り、

```bash:my.sh
#!/bin/bash
shift  # `-c` を除外
echo "自前のシェルだよ"
eval $*
```

```bash:実行権限をつける
$ chmod +x my.sh
```

```Makefile:Makefile
SHELL := ./my.sh

a:
	@ echo "make target だよ"
```

とかやると、

```bash:bash
$ make
自前のシェルだよ
make target だよ
```

とかできちゃうわけです。

# `pipenv` でもできちゃう

もはやネタの範疇なので、役に立つかというと微妙だけどｗ

```toml:Pipfile
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[packages]
requests = "*"

[dev-packages]

[requires]
python_version = "3.9"
```

```bash:pipenv.sh
#!/bin/bash
shift
eval pipenv run $*
```

```Makefile:Makefile
SHELL := ./pipenv.sh

a:
	pip freeze
	python -V
	pip show requests
```

```bash:実行
$ make
certifi==2021.5.30
charset-normalizer==2.0.4
idna==3.2
requests==2.26.0
urllib3==1.26.6
-------------
Python 3.9.6
-------------
Name: requests
Version: 2.26.0
Summary: Python HTTP for Humans.
Home-page: https://requests.readthedocs.io
Author: Kenneth Reitz
Author-email: me@kennethreitz.org
License: Apache 2.0
Location: /Users/kuryu/workspace/check/pipevn/foo/bar/.venv/lib/python3.9/site-packages
Requires: urllib3, certifi, charset-normalizer, idna
Required-by:
```

毎回 `pipenv run` で起動するのでまぁまぁ遅いです。
`pipenv shell` で起動した中で全部実行できれば理想的なんだけどねぇ。

っていう話。

## ちなみに

↑の話は Makefile の中だけで全部完結できないかなー？って調べてたのが発端なので、

> `pipenv shell` で起動した中で全部実行

するだけなら普通に

```bash:bash
$ pipenv run make
```

でできます。
ユーザビリティをあげるボタンの工夫(フロント)

<h2>はじめに</h2>
本記事では、ボタンでユーザービリティをあげるワザをちょっとご紹介します。
すぐ実践できるものばかりなので、是非参考にしてみてください。


<h4>ボタンの活性化・非活性化</h4>
例えば、フォームを送信するのに2つの質問に答えないといけないものがあるとします。

条件に当てはまっていないとき（質問に１つしか答えていないときなど）は、ボタンを非活性化
条件クリアしたときに、ボタンを活性化しましょう。

こすうることでユーザーが「直感的」に「ボタンが押せないこと」、「何かが足りていないこと」に気づけます。
むやみにボタンを押して「あれ、、、なんで何も反応しないの、、、押してるよね？？？」なんて混乱を防げます。

※↓いったい何のアプリだよっていうツッコミは一旦置いといてください。

![Videotogif (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890970/69d522b8-26a4-7085-6a5f-4a04718848f5.gif)

***👉ワンポイントアドバイス***
グレーアウトではなく、透明化をしよう！

非活性化時に、ボタンをグレーにする場合があります。
しかし、これは
・ボタンの有効時のフルカラーのデザインとかけ離れているためユーザーを驚かせる
・グレーは背景色に馴染まず浮いてします。目立つことになるため、ユーザーは「非活性」であることに気づかずクリックしてしまう
を引き起こす可能性があるためお勧めしません。

代わりに透過させることで、ユーザーを驚かせることなくボタンの無効状態を伝えられます。


参考記事
https://coliss.com/articles/build-websites/operation/work/why-you-shouldnt-gray-out-disabled-buttons.html






<h4>hover, tap時に変化をつける</h4>
ユーザーがボタンをhoverしたときや、クリックしたとき
ボタンの色を変えたり、サイズを変えたり、変化を起こしましょう。
ユーザーが「直感的」に「押せるもの」であること、「正しくクリックできている」ことを認識できます。


![Videotogif (2).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890970/1039a846-3075-ebda-8e68-3b82ca394987.gif)


<h4>アニメーションを付ける</h4>
促したい動作にはアニメーションを付けて見ましょう。
ユーザーに気づいてもらうこと、正しくネクストアクションを提示させることができます。


![Videotogif (3).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890970/b3d30ef2-d692-6f8d-de73-07deeb2fc20b.gif)
helper と decorator の使い分け

例えば下記のようなコードはviewを肥大化させてしまい、さらに変更(`#{@user.midlle_name}` を追加したいなど)があった場合に対応しづらくなってしまう。

```ruby
<%= "#{@user.first_name} #{@user.last_name}" %>
```

そこで下記のようなメソッドに切り分けることを考えると思います。

```ruby
  def full_name
  end
```

これをmodelに定義するのか、helperに定義するのか、はたまたdecoratorに定義するのか、そもそもこれらの違いはなんなのか、というのが今回のテーマです。


#model の肥大化を防ぐ

基本的にメソッドはmodelに定義することで実装できます。ただ全てをmodelに書いてしまうとコード量が増え、可視性が悪くなり扱いづらくなってしまいます。

そこで登場するのが **helper** と **decorator** 。

これらは基本的にviewの肥大化を防ぐために使われます。viewの共通化やロジックを切るときにはmodelではなく、**helper** か **decorator**  を使うようにしましょう。

じゃあ、これらは2つはどのように使い分ければ良いのでしょうか？

#helper と decorator の違いについて

###helper
- Modelに依存しないロジック
→ modelにアクセスする際に定数が必要

```ruby
module ApplicationHelper
  def full_name(model)
    model.first_name + model.last_name
  end
end
```

- グローバルに有効(アプリケーション内のどこでも使える)という特徴があるので、他のファイルでメソッド名が被ってしまったときに、どちらか一方が使えなくなるという事故に繋がるため注意が必要。

###decorator
- Modelに依存するロジック
→ modelにアクセスする際に定数を必要としない

```ruby
module UserDecorator
  def full_name
    first_name + last_name
  end
end
```
- `gem 'draper'`をインストールする必要がある

#まとめ

1. 基本はmodelに書く
2. viewのロジックでModelに依存しないときはhelper
3. viewのロジックでModelに依存するときはdecorator

ちなみに下記のような場合ではdecoratorを使うのが適切かと思います。

```ruby
<%= "#{@user.first_name} #{@user.last_name}" %>
```

<変更後>

```ruby
class UserDecorator
  def full_name
    first_name + last_name
  end
end
```

```ruby
<%= @user.decorate.full_name %>
```
UTC時間とJST時間について

railsでAPIを開発中にUTC時間とJST時間の違いにだいぶ苦しめられたので、調べてみました。

# UTC時間

アメリカ時間　時間のデータの最後にUTCってついてる

例

```cpp
2021-09-03 15:00:00 UTC
```

# JST時間

日本時間　アメリカ時間よりも９時間先に進んでいる　データの最後に+0900ってついてる（これは恐らく世界標準のアメリカ時間から９時間進んでいる時間ですよって表示するためのもの）

```cpp
2021-09-04 00:00:00 +0900
```

両者の二つの例は同じ値を示し、ActiveRecordなどの検索時に時間を指定するとどちらの時間も同一とされ、検索に引っかかるようになる
Swift言語での値型と参照型

値型と参照型について、モヤモヤっとしていたので調べた時の覚書

# Classは参照型

参照型は変数にインスタンスの値のメモリ保管場所を収納する。

なので、インスタンスが入った変数vを他の変数zに代入するとzにもインスタンスの値のメモリアドレスが格納される。つまりvとzは同じインスタンスのメモリアドレスを見てるので、どちらかが変更された場合はその片方の値も変更（されたように見える。vの値が変更されたわけではなく、vの参照しているメモリアドレスに格納されている値が変更されている）される。また、let表記でもプロパティの変更はできる(変数のメモリには参照先のアドレスがあるのみで、そのアドレスを変更しているわけではないから)

```swift
class A {
    var test:Int = 0
}

let v = A()
v.test = 1
let z = v
z.test = 2　 // letだけど変更できる
z = A() // NG!
print(v.test) // 2
print(z.test) // 2
```

# StructやEnumは値型

値型は変数に値そのものを収納する。

なので、変数vとzが見ている先は別のものなので両者はそれぞれ独立している

なので、プロパティを変更するときは、let表記だと変更できない（変数のメモリに値があり、その値を変更しようとしているため）

```swift
class A {
    var test:Int = 0
}

let v = A()
v.test = 1
let z = v
z.test = 2
print(v.test) // 1 変更されていない
print(z.test) // 2
```
DispatchQueue.main.asyncとDispatchQueue.main.syncの違い

# 題意

DispatchQueue.main.asyncにおいて、なぜメインスレッド指定なのに、非同期に実行させているのか不明だったので調査してみた。
# 結果

DispatchQueue.main.syncは呼び出し元のスレッドでの処理にキューとしてつみあげられる。バックグラウンドスレッドでDispatchQueue.main.syncを実行するとバックグラウンドスレッドのキューに積み上げられてしまうイメージ。下記のような実行順序になる。

```swift
DispatchQueue.global().async {
    // 一番目に実行
    DispatchQueue.main.sync {
        // syncなので呼び出し元のスレッドでの処理が終了したときに呼ばれる
				// 二番目に実行
    }
    // 三番目に実行
}
```

しかしDisoatchQueue.main.asyncで呼ぶと呼び出し元のスレッドの処理と同時に非同期処理が行われるようになる。

```swift
DispatchQueue.global().async {
    // 一番目に実行
    DispatchQueue.main.async {
        // asyncなので呼び出し元のスレッドでの処理と並行して処理がよばれる
				// 二番目に実行
    }
    // 二番目に実行（ここでの処理はDispatchQueue.main.asyncの中の処理と同じタイミングで走る）
}
```

だから、asyncを呼ぶときはローディング画面の表示など、バックグラウンドでの処理と並行して呼びたいときに使われるらしい
【laravel-admin】deleteアクションをカスタマイズする

デフォルトのdeleteアクションだと特定の条件だけ削除したい場合や、条件によって確認メッセージを変えたい場合に対応できない。
リレーションを貼ってあるテーブルでリレーション元が消えちゃうとまずい場合とか。

そのためカスタマイズする必要がある。実際はカスタマイズじゃなく、オリジナルの削除処理を実装してそっちを使う。

# カスタムアクションを作る
```bash
php artisan admin:action Post\\Delete --grid-row --name="delete"
```

以下のディレクトリに作られる
`app/Admin/Actions/Post/Delete.php`

```php
<?php

namespace App\Admin\Actions\Post;

use Carbon\Carbon;
use Encore\Admin\Actions\RowAction;

class Delete extends RowAction
{
    public $name = 'delete';

    public function handle()
    {
        // 削除処理
        $this->row->delete();

        return $this->response()->success('Delete Successful')->refresh();
    }

    public function dialog()
    {
        $auths = $this->row->auths;
        $auths = $auths->filter(function($el){
            $now = Carbon::now();
            return $now < $el->auth_expired;
        });
        if(empty($auths->toArray()))
        {
            $message = '削除しますか？';
        }
        else
        {
            $message = '認証済みのようです。本当に削除しますか？';
        }
         
        $this->confirm($message);
    }

}
```

postsテーブルにauthsテーブルが紐づいていて、認証済みだった場合にメッセージを切り替える例。
中身の処理は適宜変更してください。
完全に削除自体を禁止することも可能。

```php
public function dialog()
{
...
}
```

`dialog()` を使うと確認ダイアログが出せます。
こういうの↓
![61606520-4f219080-ac7d-11e9-8a3a-24f7c629f340.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402204/558240ba-b488-7f92-fe3d-d9053f817a2b.png)

```php
public function form()
{
  $type = [
        1 => 'Advertising',
        2 => 'Illegal',
        3 => 'Fishing',
    ];
    
  $this->checkbox('type', 'type')->options($type);
  $this->textarea('reason', 'reason')->rules('required');
}
```

`form()` を使って何らかの入力や選択をさせることもできます。
AWSみたいに「削除」と文字列を送らないと削除させないとか。
![61606916-1be00100-ac7f-11e9-8e71-fae60b26277d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402204/73e58e8e-b34e-50a5-41a7-292db64bcb97.png)

# 作ったカスタムアクションを使うように設定
最後に作ったカスタムアクションを使用するように設定していきます。
合わせてデフォルトの削除アクションはdisabledに変更します。

```php
<?php

namespace App\Admin\Controllers;

use App\Admin\Actions\Post\Delete;
use Encore\Admin\Controllers\AdminController;
use Encore\Admin\Form;
use Encore\Admin\Grid;

class PostController extends AdminController
{
    ...

    /**
     * Make a grid builder.
     *
     * @return Grid
     */
    protected function grid()
    {
        ...
        $grid->actions(function ($actions) {
            $actions->disableDelete(); // オリジナルの削除は非表示
            $actions->add(new Delete);
        });
        ...

        return $grid;
    }
```

# まとめ
結構自由度高くカスタムアクション作れるので、便利ですね。
通常はデフォルトで用意されているdeleteアクションを使えばいいと思いますが、特殊なケースではカスタムアクションを作っていけば問題なさそう。
Gmailのメール本文から判断してGoogleチャットに転送

#背景
お客様に導入したシステムの運用保守しています。システム監視のツール
からアラートメールがよく飛んできます。アラートレベルが、軽度障害、重度障害、またお客様のシステムによっても対応方法が異なったりします。それぞれのアラートレベルなどによって、メールを振り分け、メールの本文をGoogleチャットに転送することをしたいので、その方法について記事を書いていきます。ポイントは、同じメールアドレスからアラートがくるのですが、軽度のアラートか重度かは、メール本文にしか違いが記載されていないので、それをどう情報を取得してチャットに転送するかです。

#必要情報
①取得したいメールに独自のラベルがついている。黄色で囲まれてるやつなど。（コード内のラベル名のやつ）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/650007/0331d8cb-99b3-e87f-4a86-10ad4e133410.png)
②転送したい先のグループチャットのWebhook管理からリンクを取得する。（コード内の任意のWebhook)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/650007/495f79cd-a61b-3e94-9549-4ac86b1d447b.png)

#コードの流れ
1 :合致するラベル名のスレッドを取得
（スレッドはメールとは別。スレッド内に複数のメールがあることも。）
2: 1で取得したスレッドで、未読のメールがあるスレッドのメールを取得し、配列に格納
3: for文繰り返し処理で、一つ一つのメールを message 変数に格納してからメール本文を取得し(Body変数）、本文に記載されているアラートレベルを取得（level変数)
4: level変数が、average など任意のストリングであれば転送したいチャットにメール本文を転送。転送したらメールを既読にする。

#全体のコード

```js
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var sheet = spreadsheet.getSheetByName('シート1');

function myFunction() {
  var threads = GmailApp.getUserLabelByName('G-Star_Zabbix').getThreads();
  var url = "https://chat.googleapis.com/v1/spaces/AAAAUW3Kp_U/messages?key=AIzaSyDdI0hCZtE6vySjMm-WEfRq3CPzqKqqsHI&token=uySHzlczWP7MIEGi2nyVEzh8RQtwWaQWqI0HnxeRImM%3D";
  console.log(threads);
  var messages = [];
  for(i=0; i < threads.length; i++){
    messages = threads[i].getMessages();
    for(j=0; j < messages.length; j++){
      var message = messages[j];
      var messageId = messages[j].getId();
      if( message.isUnread()){
        console.log(message);
        var Body = message.getPlainBody();
        var Body2 = {'text': Body};
        console.log(Body);
        var level = Body.match(/深刻度: (.*)/)
        console.log(level);

        var options ={
          'method': 'POST',
          'headers': {
          'Content-Type': 'application/json; charset=UTF-8'
        },
        'payload':JSON.stringify(Body2)
      };
      if(level != null && level[1] == 'average'){
        UrlFetchApp.fetch(url,options);
        message.markRead();
      }

    }
  　}
    
  }
  
}

```

#まとめ
テストチャットでいけたんで大丈夫だと思いますが、、、何かございましたらお伝えくださいm(__)m
SFTP専用ユーザーを作成し、特定directoryのみ更新できるよう制限する

## これは何

SFTP専用ユーザーを作成し、特定directoryのみ更新できるよう制限してみたので、メモをここに残します。
FTPソフトはCyberduckを使ってます。

## 要件

sftp-userを作成する
/home/sftp-user配下のファイルしか操作できない様にする（chrootする）
ただし、/var/www/html/hogeだけは更新できる様にしたい

## やってみた

**ユーザー作成**

```
useradd sftp-user
```

**httpd install**

```
yum -y install httpd
```

**sftp-userがアップロードしたファイルをApacheが動かせるようにする**

```
gpasswd -a apache sftp-user
```

**SSH directory 作成**

```
cd /home/sftp-user
mkdir .ssh
chmod 700 .ssh
```

**鍵作成**

```
sudo su - sftp-user
cd .ssh
ssh-keygen 
key name : sftp-user
```

**rootに戻る**

```
exit
```

**公開鍵の名称とパーミッションの変更**

```
mv sftp-user.pub authorized_keys
chmod 600 authorized_keys
```

**コピペで保存**

```
cat sftp-user 
(pemファイル)
```

**sftp-user でログイン可能か確認する**

```
(bastionにて)
vi sftp-user.pem
コピペ内容貼り付け
ssh -i sftp-user.pem  sftp-user @Private IP
```

**sftp-userを、ファイル転送専用ユーザーにする**

```
vi /etc/ssh/sshd_config

# override default of no subsystems
Subsystem sftp /usr/libexec/openssh/sftp-server
　　↓

# override default of no subsystems
#Subsystem sftp /usr/libexec/openssh/sftp-server
Subsystem sftp internal-sftp

ファイルの末尾に、以下を追記。

Match User sftp-user
    	ChrootDirectory /home/sftp-user
    	ForceCommand internal-sftp
```

**特定のディレクトリを別のディレクトリにマウントする**
/var/www/htmlディレクトリの内容は、２つの 場所、 /var/www/html と /home/sftp-user/hoge/で利用できるようになる。

```
mount -B /var/www/html /home/sftp-user/hoge/
```

**/home/sftp-userディレクトリの所有者とパーミッションを変更**

```
chown root:root /home/sftp-user
chmod 755 /home/sftp-user
```

**ユーザーディレクトリ内にディレクトリを作成し、ユーザーに所有させる**

```
mkdir /home/sftp-user/hoge
chown sftp-user:sftp-user /home/sftp-user/hoge
chmod 775 /home/sftp-user/hoge
```

**sshdを再起動し、設定を反映**

```
sshd -t
エラーがなければ再起動
service sshd restart
```

**sftpコマンドで転送する。**

```
（hoge directoryにcdしなければ、putは失敗した。）

sftp -i sftp-user.pem sftp-user@踏み台の先のEC2 Private IP
Connected to XXX
sftp> cd /hoge/
sftp> put XXX.jpeg 
Uploading XXX.jpeg to /hoge/XXX.jpeg
XXX.jpeg                                                                                                                                                        100%   11KB  20.3MB/s   00:00    
sftp> exit

/var/www/html配下に移動できているか確認

ls -la /var/www/html/XXX.jpeg 
-rwx------. 1 sftp-user sftp-user 11136 Sep 13 09:56 /var/www/html/XXX.jpeg
```

**一応、ポートフォワーディングを行い、ファイル転送できるか確認**

```
ポートフォワーディング
ssh -f -N -L 10220(任意):踏み台の先のEC2 Private IP:22 -i 秘密鍵 踏み台OSユーザー@踏み台Public IP
```

FTPソフトで接続し、ファイル転送。

![スクリーンショット 2021-09-14 16.30.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1740345/757aae95-f3d9-3737-2653-69688f036cbf.png)


## 総括

なかなかセキュアな環境ができたのではないでしょうか。（konami）

## 参考

```
https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/5/html/global_file_system_2/s1-manage-pathnames
https://lab.taf-jp.com/sftp%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E3%82%92%E4%BD%9C%E6%88%90%E3%81%97%E3%81%A6%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E8%BB%A2%E9%80%81%E7%94%A8%E3%81%AB%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B/
https://cloudpack.media/14365
```

参考にさせていただきました。ありがとうございます。
[Rails]条件分岐を使ってデータのある限り画像を投稿する

##初めに
####なぜこの記事を書きたかったのか or この記事の対象者

####環境
・Macbook Air (Retina, 13-inch,2019)
・プロセッサ 1.6GHz デュアルコアIntel Core i5
・メモリ　8GB 2133 Mhz LPDDR3
・MacOS Big Sur　バージョン 11.5.2

####記事の目次
**１）どういうときに使える？**
**２）　前提（画像を保存する仕組みを作る＆保存する画像にアソシエーションを組む）
**３）DBの限り画像を投稿**
**４）最後に**

##どういうときに使える？
####ユーザが投稿した画像をまとめて見やすくするために一つのウィンドウにまとめれる。
**例えば）LINEで画像を投稿したあと、写真・動画ボタンをクリックすると日付ごとにまとめて見返すことができる。通販サイトの商品を出品順に並び替えることができるなどなど**

##(前提)DBに保存された画像をviewに使えるようにする設定
####（現在制作中、完成後ここにリンクを貼る）

##DBの限り画像を投稿
####１）viewに表示させる場所をつくる
**<1>画像を投稿するということは、DBに画像があるということをどう表現するか**
**<2>複数の画像を投稿と命令するにはどう表現するのか**
**<3>今回は最初に投稿したものをメインに表示させるように命令してみる**

```erb
<1>DBのデータは配列で保存される＝配列になってない真っ白なDBを表現する方法。。。中身がない＝lengthがない。
<% if @テーブル名.length !=0 %>

<2>@テーブル名.each do |テーブル名|のeach doで指定した@テーブル内の各々のデータを使用してくださいとなる。

<3>配列の中身を順番に数えるとき最初は１からではなく０から！
<%= image_tag(テーブル名.image[0] %>
```
![joukenbunkisample.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1102030/e8e9745b-b509-3faa-a64a-a6b604794360.png)

####２）DB内に画像がある場合とない場合の表示の仕方を設定

```erb
<１>・DB内に画像がない場合の表現する方法→画像を投稿していない→存在していない＝presentの有無
<２>presentのあとに"？"をつけることでfalseの場合の処理ができる。

<%= if テーブル名.投稿機能のために作ったモデル.present? %>
  <div class= 'no-image'>
    <span>投稿されてないよー</span>
  </div>
<% end %>
```
**（例２）**
![falsejoukenbunkisample.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1102030/cf4d0478-34ad-8e69-a347-23132c645107.png)


##最後に
記事を一気に書くより、段階を分けて書いたほうが気が楽ということがわかったので、まずは段階的に記事を書いてLGTMをもらったり、自分でこれはわかりやすいとおもう！となったら記事をまとめて投稿しようと思った。一気に完璧を求めるより、作成して修正して完璧に近い記事にすればいいと思った！

ココまで読んでくださいましてありがとう！☺
APIとは・Railsへの導入の仕方

##そもそもAPIとは
APIは「Application Programming Interface」の略でわかりやすく説明すると『アプリケーションをプログラムして出来たインターフェース』となります。ソフトウェアの一部機能を共有する仕組みを指します。具体的には、「機能を公開しているソフトウェア」と「その機能を使いたいソフトウェア」をつなげる窓口のようなものです。
Web APIは、ひとことで言えば、インターネット（Web）を経由して、何らかの処理を行うための、手段や決めごと（API）のことです。
google apiや、amazon apiのように有名なWebAPIがあり、自分でWebAPIを作って自分だけで利用することも可能です。
##APIを利用するメリット
APIを利用するメリットは、短期間でサービスを開発できる点にあります。APIを利用すると、その機能の開発を行う手間を省くことができるようになるため、開発期間の短縮やコストの削減が可能になります。
##Web APIの仕組み
Web APIでは、Web APIで機能を公開しているサーバに対して、インターネットなどの通信ネットワークを通じて依頼内容をHTTPリクエストの形で送信すると、処理結果がHTTPレスポンスの形で送られてきます。送受信されるデータの形式はAPIによって様々だが、Webでよく用いられるXMLやHTML、JSON、各種の画像ファイル形式などが用いられることが多いです。
##Rails APIの作成
###APIモードでRailsアプリの作成
外部からPostというモデルの情報の作成・取得・削除・編集ができるような形式にします。
通常のrails newコマンドの末尾に--apiをつけることでAPIモードでアプリを作成することができます。
(APIに必要ない部分をデフォルトで作成しなくなります。)

``` console
$ rails new アプリ名 --api
```
###モデル・コントローラの作成
通常のRailsアプリ同様モデルとコントローラを作成します。
今回はtitleというstringを持ったpostというテーブルを作成するとします。

```
$ rails g model post title:string
$ rails g controller posts
$ rails db:create
$ rake db:migrate
```
###ルーティングの設定
最初から以下の様にバージョンで名前空間を作成しておくことで今後のAPIのバージョン管理が容易になります。

``` config/routes.rb
Rails.application.routes.draw do
  namespace 'api' do
    namespace 'v1' do
      resources :posts
    end
  end
end
```
###コントローラの設定
```posts.controller.rb
module Api
  module V1
    class PostsController < ApplicationController
      before_action :set_post, only: [:show, :update, :destroy]

      def index
        posts = Post.order(created_at: :desc)
        render json: { status: 'SUCCESS', message: 'Loaded posts', data: posts }
      end

      def show
        render json: { status: 'SUCCESS', message: 'Loaded the post', data: @post }
      end

      def create
        post = Post.new(post_params)
        if post.save
          render json: { status: 'SUCCESS', data: post }
        else
          render json: { status: 'ERROR', data: post.errors }
        end
      end

      def destroy
        @post.destroy
        render json: { status: 'SUCCESS', message: 'Deleted the post', data: @post }
      end
 end
```
##引用記事
[APIの仕組みが分かる・使いこなせる人材になれる記事（Pythonコード付き）](https://qiita.com/Saku731/items/6ae290f72e98723f165d)
[Web APIのメリットと探し方](https://blog.api.rakuten.net/ja/jp-web-api/#APIWeb_API)
[WebAPIについての説明](https://qiita.com/busyoumono99/items/9b5ffd35dd521bafce47)[Railsで超簡単API](https://qiita.com/k-penguin-sato/items/adba7a1a1ecc3582a9c9)
[巨人の力を使っちゃえ！Web APIを使えば、あなたの夢も一発で実現](https://atmarkit.itmedia.co.jp/ait/articles/0703/13/news095_2.html)
SUMIFS関数とSUBTOTAL関数を組み合わせて便利な表とグラフを作る

皆さんは、エクセルのグラフを条件によって変化させたりしたいですか？ピボットグラフを使ったりBIツールを使ったりして作成することができますが、今回はエクセルの元データをそのまま利用して作成する方法を共有します。

元データを見ながら色々シミュレーションが出来るので結構便利です。

今回は以下のサンプルデータを使用します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624137/86d1fc50-b55d-fbe4-cc18-063fff656bea.png)
商品名と売上金額の合計が表示される集計表があります。ここの数字はSUMIFを使っています。
元データには売上日・売上No・商品名・売上金額が記載されております。
今回は、売上日・売上Noでフィルターをかけても、SUMIFの数値が変化するようにしたいと思います。

<h2>SUBTOTAL関数を使ってフィルターを判定しよう！！</h2>

元データに、以下の数式を入力が入った列を追加しました。

セルA11に<b>=SUBTOTAL(3,B11:B11)</b>を入れました。　
※11行以降はコピペしてください
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624137/676597aa-e7bc-a807-f58d-44b3debc50dc.png)
SUBTOTAL関数の3はCOUNTA関数になります。これによって、
<b>"行が表示されているときに1が出力され、非表示のときに0が出力されます。"</b>

これによりフィルター検索し表示されている箇所のみ表示可能になります。
<h2>SUMIFをSUMIFSに変更してフィルターを反映させる</h2>

集計表のSUMIFの計算をSUMIFSにしてE3セルを以下のように変更します。（以降はコピペ）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624137/ae9e75bb-ba78-9ea9-553d-f0c44ca0288c.png)
=SUMIFS(E$11:E$29,$D$11:$D$29,$D3,$A$11:$A$29,1)
※絶対参照にしてからコピペしてください。

<b>商品名が一致してかつ、SUBTOTAL表示用の列が1になっている明細のみが計算されるようになります。</b>
集計表をグラフに反映させるとフィルターに合わせてグラフが変化します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624137/2df1031a-8e08-6401-270b-1c5b7c631d59.png)

まるでPower BIやTableauを触っているかのような感覚だと思いませんか！？！？
<h2>おまけ</h2>

・最初はSUMIFの中にSUBTOTAL関数を入れてみましたが、これだとエラーになってしまいます。こんな式です⇒｛=sumif(D11:D29,D3,subtotal(9,E11:E29))｝　なので今回のような方法を考えました。
・SUBTOTALの列はB列以降であればどのセルでもOKです。※A列だと循環参照になってしまいます。

・この方法ならエクセルが詳しくない方（ピボットテーブルすら分からない）でも色々シミュレーション出来るのではないでしょうか。
ローカルリポジトリをGitHubへアップロードする


## ローカルリポジトリ作成

```Powershell
git init 
git add .
git commit -, "init commit"
```

現在のディレクトリの内容の初期コミットが行われる。

## GitHubで新規リポジトリを作成する

Initialize the repositoryにいろいろとチェックボックスがあるが、それらはチェックしない。  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/467168/08cb6110-0539-f474-8d0e-664dcf3d49ca.png)


作成後、アップロードするのに必要なURLが表示されるので、それをコピーする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/467168/3303bcce-24ca-fdae-9462-12602dfa1c58.png)

ローカルリポジトリに戻る。

## GitHubへアップロードする

```Powershell
git remote add origin {さっきコピーしたURL}
git push origin master
```

originは任意の名前だと思うので他の値でもおそらくいけると思われる。

これにて完了です。
osを作る その15

#概要

osを作る。
俺々RTOSで、時計、書いてみた。


#サンプルコード

タスクは、３つ。
アナログリード、ボタン処理、時計表示。


```
#include <LiquidCrystal.h>
#include "Time.h"

LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

static int Current;
static int Timer_Flag;
static int TC[2 * 3 + 2];
static int valueFromQueue;

void k_Wait(int time) {
	cli();
	TC[2 * Current] = (TC[2 * Current] & 0xC0) + 0x20;
	TC[2 * Current + 1] = time;
	Timer_Flag = 1;
	sei();
}

void task_1(void) {
	valueFromQueue = analogRead(A0);
	k_Wait(50);
}

void task_2(void) {
  int v;
	lcd.setCursor(0, 1);
	if (valueFromQueue > 1000)
	{
		lcd.print("5");
	}
	if (valueFromQueue < 50)
	{
		lcd.print("0");
		setTime(hour(), minute(), 0, day(), month(), year());
	}
	else if (valueFromQueue < 250)
	{
		lcd.print("1");
		v = minute();
		v++;
		if (v > 59) v = 59;
		setTime(hour(), v, 0, day(), month(), year());
	}
	else if (valueFromQueue < 450)
	{
		lcd.print("2");
		v = minute();
		v--;
		if (v < 0) v = 0;
		setTime(hour(), v, 0, day(), month(), year());
	}
	else if (valueFromQueue < 650)
	{
		lcd.print("3");
		v = hour();
		v--;
		if (v < 0) v = 0;
		setTime(v, minute(), 0, day(), month(), year());
	}
	else if (valueFromQueue < 850)
	{
		lcd.print("4");
		v = hour();
		v++;
		if (v > 23) v = 23;
		setTime(v, minute(), 0, day(), month(), year());
	}
	k_Wait(30);
}

void task_3(void) {
	lcd.setCursor(0, 0);
	lcd.print(hour());
	lcd.print(":");
	lcd.print(minute());
	lcd.print(":");
	lcd.print(second());
	lcd.print(" ");
}

void setup(void) {
	int i;
	cli();
	for (i = 1; i <= 3; i++)
	{
		TC[2 * i] = 0x80;
		TC[2 * i + 1] = 0;
	}
	setTime(16, 00, 0, 9, 14, 2021);
	lcd.begin(16, 2);
	Serial.begin(9600);
	while (!Serial)
		continue;
	cli();
	TCCR1A = 0;
	TCCR1B = 0;
	TCNT1 = 0;
	OCR1A = 19990;
	TCCR1B |= (1 << WGM12);
	TCCR1B |= (1 << CS11);
	TIMSK1 |= (1 << OCIE1A);
	Serial.println("ok");
	while (1)
	{
		cli();
		i = 1;
		while (i <= 3)
		{
			if ((TC[2 * i] & 0xE0) == 0x80)
			{
				Current = i;
				switch (i)
				{
				case 1:
					sei();
					task_1();
				break;
				case 2:
					sei();
					task_2();
				break;
				case 3:
					sei();
					task_3();
				break;
				default:
					break;
				}
				i = 1;
			}
			else
			{
				i++;
			}
		}
		sei();
	}
}
ISR(TIMER1_COMPA_vect) {
	int i;
	if (Timer_Flag != 0)
	{
		Timer_Flag = 0;
		for (i = 1; i <= 3; i++)
		{
			if (TC[2 * i] & 0x20)
			{
				TC[2 * i + 1] = TC[2 * i + 1] - 1;
				if (TC[2 * i + 1] == 0)
				{
					TC[2 * i] = (TC[2 * i] & 0xDD) + 2;
				}
				else
				{
					Timer_Flag = 1;
				}
			}
		}
	}
}





```

以上。
nginxのクロスドメイン設定

#やりたかったこと。
APIをPHPで作成する事になったため、nginxの設定でクロスドメインに対応させたかった。

本番環境はクロスドメイン通信を行わないが、開発環境では、

* 画面：http://localhost:3000
* API：http://localhost:8080

のようにドメインが異なったため、開発環境のみにクロスドメイン設定を入れたかった。

# 結果。
nginxの設定ファイルにて、クロスドメイン設定を定義。

```:nginx
  location ~ \.php$ {
    if ($request_method = 'OPTIONS') {
      add_header Access-Control-Allow-Methods 'POST, GET, OPTIONS';
      add_header Access-Control-Allow-Headers 'Origin, Authorization, X-Requested-With, Content-Type, Accept';
      add_header Access-Control-Allow-Origin 'http://localhost:3000';
      add_header Access-Control-Allow-Credentials 'true' always;
      add_header Access-Control-Max-Age 86400;
      add_header Content-Length 0;

      return 204;
    }

    add_header Access-Control-Allow-Origin 'http://localhost:3000';
    add_header Access-Control-Allow-Credentials 'true';

    #以降に通常の設定を定義
```

`Access-Control-Allow-Credentials` は、`always` を付与しておく必要があった。
\# OPTIONS以外の「レスポンス：200」の場合でも必要でした。
\# ちょっと時間が無く、詳しくは調べてません。。。

`'OPTIONS'` によるif文は、API通信で行われる[Preflightリクエスト](https://developer.mozilla.org/ja/docs/Glossary/Preflight_request)の場合です。
Java  イメージをPDFに変換

<p><strong>前の記事では、PDFからほかの様々なファイル形式に変換する方法を紹介しましたが、今回はイメージをPDFに逆変換する方法を紹介したいと思います。もちろん、Spire.PDFというライブラリを必要としますよ。下記の通り、ご案内申し上げます！</strong></p>
<h4><strong>下準備</strong></h4>
<p><strong>1.E-iceblueの公式サイトから<a href="https://www.e-iceblue.com/Download/pdf-for-java.html">Spire.PDF for Java</a>をダウンロードしてください。</strong></p>
<p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/l/lendoris/20210914/20210914162923.png" alt="f:id:lendoris:20210914162923p:plain" width="553" height="207" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p>
<p><strong>2.IDEを起動して新規プロジェクトを作成してから、インストールされたファイルにあった相応しいSpire.PDF.jarを参照に追加してください。</strong></p>
<p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/l/lendoris/20210914/20210914163033.png" alt="f:id:lendoris:20210914163033p:plain" width="238" height="71" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p>
```java
import com.spire.pdf.PdfDocument;
import com.spire.pdf.PdfPageBase;
import com.spire.pdf.graphics.PdfImage;

public class ImageToPDF {
    public static void main(String[] args){
        //PdfDocument オブジェクトを作成します。
        PdfDocument pdf = new PdfDocument();
        //新規ページを追加します。
        PdfPageBase page = pdf.getPages().add();

        //イメージを追加します。
        PdfImage image = PdfImage.fromFile("Hydrangeas.jpg");

        double widthFitRate = image.getPhysicalDimension().getWidth() / page.getCanvas().getClientSize().getWidth();
        double heightFitRate = image.getPhysicalDimension().getHeight() / page.getCanvas().getClientSize().getHeight();
        double fitRate = Math.max(widthFitRate, heightFitRate);
        double fitWidth = image.getPhysicalDimension().getWidth() / fitRate;
        double fitHeight = image.getPhysicalDimension().getHeight() / fitRate;
        page.getCanvas().drawImage(image, new Rectangle2D.Double(0, 0, fitWidth, fitHeight));

        //保存します。
        pdf.saveToFile("ConvertImageToPDF.pdf");
    }
}
```
<h4><strong>実行結果</strong></h4>
<p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/l/lendoris/20210914/20210914163104.png" alt="f:id:lendoris:20210914163104p:plain" width="554" height="576" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p>
<p> </p>