OmniAICreator/Qiita-1.07M huggingface dataset:
HTML/CSS 簡単に横並びにできるflexboxについて

『コンテンツや文字を横並びにする』のに
flexboxが非常に便利なので、簡単に解説していきます。

```
<div class="container">
    <div class="left">
      <p>左です</p>
    </div>
    <div class="right">
      <p>右です</p> 
    </div>
</div>

<style>
.left{
    color: white;
    background-color: lightcoral;
    width: 100px;
    height: 100px;
    text-align: center;
}

.right{
    color: white;
    background-color: lightblue;
    width: 100px;
    height: 100px;
    text-align: center;
}
</style>
```

これを更新すると

![スクリーンショット 2020-11-10 15.32.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/746919/90b89d56-54da-55e9-9aab-a39bc2a96f7a.png)

こうなるので、親要素の.containerにdisplay: flex;を追加します。

```
<style>
    .container{
      display: flex;
    }
.left{
    color: white;
    background-color: lightcoral;
    width: 100px;
    height: 100px;
    text-align: center;
}

.right{
    color: white;
    background-color: lightblue;
    width: 100px;
    height: 100px;
    text-align: center;
}
  </style>
```

すると

![スクリーンショット 2020-11-10 15.36.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/746919/41787899-4073-83ae-4ca4-693d3102ea7c.png)

横並びになりました。
二つのボックスを離して配置したいときは、親要素にjustify-content: space-around;もしくはjustify-content: space-between;を追加します。

![スクリーンショット 2020-11-10 15.39.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/746919/3861ad4e-bc68-681b-fa1b-21cd004e5eb0.png)

ボックスがいい感じに配置されましたね。space-betweenを適応するとボックスが両端に配置されますので、ご自身の手で検証してみてください。

また、レスポンシブ対応させる時にボックスを左右入れ替えたい時は親要素にflex-direction: row-reverse;を追加すると、左右が入れ替わりますし、
flex-direction: column;を追加するとまた縦並びに戻ります。


```
.container{
      display: flex;
      flex-direction: row-reverse;
      justify-content: space-around;
    }
```

![スクリーンショット 2020-11-10 15.39.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/746919/a89bc348-63c2-c7ec-ec62-6e2677c76c0f.png)

```
.container{
      display: flex;
      flex-direction: column;
      justify-content: space-around;
    }
```

![スクリーンショット 2020-11-10 15.51.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/746919/e165f3bf-5222-2ce1-6f99-8d0d17388be6.png)

簡単な解説は以上になります。他にも色々機能があるのでご自身で試してみてください。
<br>タグの意外な使い道

# brタグの一般的な使い方
結論改行です。
HTMLでは改行したい場合は基本的にbrタグを使うか、
新しくブロックを作るかの２択になります。
個人的には後者の方が利用頻度が高かったので、
あまり使う場面がないなーとも思ってました。

# 意外な使い道は？
結論、floatなどの回り込みの解除になります。
brタグに回り込みの解除がついています。
ちなみに私は今までdivタグにclearプロパティを付与して
回り込みを解除していました。
※brタグにclearプロパティをつけることもできますが、clearプロパティはブロック要素につけるものなので、
インライン要素であるbrタグに付与することは文法的に間違いになるみたいです。

# 結論
brタグにはfloatの回り込みを解除する役割がある。
色々なコードの使い道をまた学んだら、ブログに書いていきます。
【Ruby on Rails】配列の繰り返し処理を何度も書きたくない場合

配列の繰り返し処理を何度も書きたくない場合どうするか
-
→ __全ての配列を処理するためのメソッドを一箇所に定義します__

<br>

* 繰り返し処理した配列を再び配列に生成し直す場合のお話です（処理メソッドはmapを使います）。

<br>

* 今回用意するモデル例（別に何でも良いのですが）
 * User（ユーザーモデル） 
 * Article（記事モデル）
 * Comment（コメントモデル）<br>

としておきます。
<br>

それぞれの配列を繰り返し処理するメソッドの定義
--
 * ArticleモデルならArticlesController、CommentモデルならCommentsControllerと様々なControllerで利用することになると思うので、`Concern`ファイルにて定義していきます。

 * app/controllers/concern配下に適当にloop_array_concern.rbという名前のファイルを作成してそこにメソッドを記述していくことにします。そして、このConcernファイルはApplicationControllerへincludeします。

>```ruby:app/controllers/concern/loop_array_concern.rb
module LoopArrayConcern
　
  extend ActiveSupport::Concern
　
  included do
    helper_method :loop_array
　end
　
  def loop_array(array_data)  # array_dataは引数をハッシュとして受け取る。キーはobjectとobject_typeとします。
    object = array_data[:object]
    object_type = array_data[:object_type]
    object.map do |obj|
        case object_type
        when "users"
            # Userモデル1件に対して実行したい処理をここに記述
        when "articles"
            # Articleモデル1件に対して実行したい処理をここに記述
        when "comments"
            # Commentモデル1件に対して実行したい処理をここに記述
        end
    end
  end
　
end
```

>```ruby:app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
　
  include LoopArrayConcern  # モジュール名を記述
　
end
```

<br>

それぞれのコントローラにて配列のループ処理を行わせる（`loop_array()メソッドを呼び出す`）
-

>* UsersController

 >```ruby
 def action
   loop_array(object: User.all, object_type: "users")
 end
```

>* ArticlesController

 >```ruby
 def action
   loop_array(object: Article.all, object_type: "articles")
 end
```

>* CommentsController

 >```ruby
 def action
   loop_array(object: Comment.all, object_type: "users")
 end
```

<br>

解説
--

 * object_typeキーによってどのモデルを処理するのかの条件分岐を行ってくれます。
 * こうすることでコードも見易くなり、修正も行い易くなり、追加で配列の処理を行いたい場合も数行の記述で済みます。

<br>

利用例
--
 * 例えば、全てのUserのそれぞれのIDを取得したい場合はどうすれば良いかを見てみます。
 * それでは仮にUser.allで取得できるデータが、`User.all = [ {id: 1, name: "田中"}, {id: 2, name: "佐藤"}, {id: 3, name: "マイケル"} ]`だとします。

>```ruby:UsersController
def action
   loop_array(object: User.all, object_type: "users")
end
```

>```ruby:app/controllers/concern/loop_array_concnern.rb
def loop_array(array_data)
    object = array_data[:object]
    object_type = array_data[:object_type]
    object.map do |obj|
        case object_type
        when "users"
+          {id: obj.id}  # Userモデル1件のIDを取得
        when "articles"
            # Articleモデル1件に対して実行したい処理
        when "comments"
            # Commentモデル1件に対して実行したい処理
        end
    end
end
```

>と、上記のように記述すると、`loop_array(object: User.all, object_type: "users")`で取得できる配列は、

>```ruby
 @users_id = loop_array(object: User.all, object_type: "users")
　
 # @user_id = [ {id: 1}, {id: 2}, {id: 3} ]
```

>となります。

<br>

以上です🙇‍♂️
HeidiSQL上でMariaDBのデータベースをそのままエクスポート＆インポートしたらエラーになっちゃたよぉ～の原因と対応

#バージョン
Windows10 Pro バージョン1909 OSビルド18363.1171
MariaDB 10.5.4
HeidiSQL 11.0.0.5919


#どんな時起こったん？
HeidiSQL上でデータベースをそのままSQLとしてエクスポート。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/4d838216-3579-1ea6-2652-b1d8c7c48a39.png)

そのSQLをそのまま実行すればデータベースがまるっと復元されると思ったけどエラー。
`SQLエラー（1064）: You have an error in your SQL syntax; check the manual than corresponds to your MariaDB server version for the right syntax to use near …`
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/8ccf046c-f430-7f7f-dda5-80c39aa7bc9e.png)


#原因
データベース内に存在しないテーブルを参照しているビューがあった。
**テーブル名を変更したのにそのテーブルを参照しているビューを変更し忘れた**、ってそれだけのこと…。


#対応
HeidiSQL上でビューを修正すればOK。
修正前に下図のエラー出るけど無視してSQL直して保存でOK。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/b0be9065-28ac-8718-4914-bf2e786108fc.png)


#蛇足
HeidiSQLはviewを変更しようとした時は整合性チェックするけど、テーブルを変更した時はビューの整合性をチェックしてくれません。
まあ、使う側が影響範囲確認しようねって話ではあるんだけど…、チェックしてくれるとありがたいなあ…。
MacでUnityのC#スクリプトを編集できるようにする

Spotlight検索で「テキストエディット」を開きます。
![スクリーンショット 2020-11-10 15.08.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208216/12005b83-6460-f297-3d10-f1c8102862f9.png)

「テキストエディット」の［ファイル］メニューから「新規」を選択してファイルを作成します。
![スクリーンショット 2020-11-10 15.09.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208216/91483b01-f353-994e-0f4f-faff3258dc7d.png)

同様に［ファイル］メニューから「保存...」を選択してファイルを保存します。
![スクリーンショット 2020-11-10 15.09.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208216/883fee65-73c8-f21e-92b5-0243af99cc71.png)

保存するファイルの名前は「noname.cs」など拡張子として.csを付けます。
![スクリーンショット 2020-11-10 15.09.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208216/565fecce-c1ae-ed66-e24a-d3ca185d46fc.png)

デスクトップ上にnoname.csというからのファイルが作成されました。
![スクリーンショット 2020-11-10 15.10.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208216/e0ad1af8-513d-4475-5331-d1bf2e600029.png)

noname.csのアイコンを右クリックして,「このアプリケーションで開く」から「その他...」を選択します。
![スクリーンショット 2020-11-10 15.10.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208216/fbc32b1e-c820-fc70-f528-a2a086d6931a.png)

アプリケーションの一覧から,「テキストエディット」など自分の好きなテキストエディタを選択します。
![スクリーンショット 2020-11-10 15.10.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208216/ac12007c-aba3-8bd2-8314-81b22b69578f.png)

以上の操作で,できるはず！
CSVファイル(2列）をpython matplotlibにて折れ線／散布図を描く

このようなcsvファイルをpython (matplotlib)でプロットしたいとする。。

<pre>
$ head tmp2
1000,0.059820690
2000,0.093225007
3000,0.139737644
4000,0.185947643
5000,0.249426903
6000,0.280377022
7000,0.325663341
8000,0.374918515
9000,0.421537361
10000,0.467402504
</pre>

■ scatter（散布図）の場合は、for文で一つ一つプロットしていく。
■ plot(折れ線）の場合は、リストで一気に渡す。

というイメージである。

コードを見てみる。。。

折れ線の場合（14-16行目に注目）

<pre>
     1import numpy as np
     2import matplotlib.pyplot as plt
     3
     4data_set = np.loadtxt(
     5    fname="tmp2",
     6    dtype="float",
     7    delimiter=",",
     8)
     9
    10x = []
    11y = []
    12
    13for data in data_set:
    14    #plt.scatter(data[0], data[1], c='black')                                                                                                                                         
    15    x.append(data[0])
    16    y.append(data[1])
    17
    18plt.plot(x, y)
    19
    24plt.show()
</pre>


![plot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163445/1309f42a-f683-4f0f-3927-75cdfdc79316.png)

散布図の場合（14-16行目に注目）

<pre>
     1import numpy as np
     2import matplotlib.pyplot as plt
     3
     4data_set = np.loadtxt(
     5    fname="tmp2",
     6    dtype="float",
     7    delimiter=",",
     8)
     9
    10x = []
    11y = []
    12
    13for data in data_set:
    14    plt.scatter(data[0], data[1], c='black')                                                                                                                                         
    15    #x.append(data[0])
    16    #y.append(data[1])
    17
    18plt.plot(x, y)
    19
    24plt.show()
</pre>
https://github.com/RuoAndo/qiita/blob/master/plot-x-y.py

![scatter.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163445/b834c6d7-fb8d-e04a-f59e-17a467019306.png)
[UE4] Memory Insightsを使用したメモリトラッキング

#1. はじめに
[検証バージョン：UE4.26.0 Preview]
　UE4.26でBetaとして追加されるMemory Insightsを使用したメモリトラッキング方法について説明します。

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/364110/311a724f-f387-0847-e847-07f1d289b614.png)

#2. Memory Insightsの特徴
ゲーム中に使用しているメモリをトラッキングできるツールで、主に以下のような特徴があります。

**[特徴]**
　・長時間のメモリトラッキングが可能
　・計測のコストは軽量でゲーム中の動作に及ぼす影響もそこまで大きくない
　・カテゴリ別(LLMタグ毎)にトラッキングすることが可能
　・メモリの使用量や傾向は分かるが、細かいメモリが確保されている箇所までは分からない
　・メモリの計測はゲーム起動時から終了時までに限定される
　・Debug/Developmentビルドで使用可能、Test/Shippingビルドは不可

#3. Memory Insightsの使い方
Memory Insightsは[Unreal Insights](https://docs.unrealengine.com/ja/Engine/Performance/UnrealInsights/index.html)の機能の一部です。
よって同じような"trace"によってMemory Insightsのチャネル"memory"を指定するだけです。

**[キャプチャ方法]**
① アプリケーション起動前にUnreal Insightsを起動
② アプリケーションの起動引数に以下のパラメータを追加してアプリケーションを起動

```
-trace=memory
```

後はアプリケーションを終了して、Unreal Insightsのトレースを開くだけです。
長期で計測する場合は、コンソールコマンドの"quit"で終了させるなどを仕込んでおくと良いです。

#4. Memory InsightsのUI

Memory Insightは以下のようなUIがあります。
画面左はトラッキングしたグラフがカテゴリ別に表示されています。ここを見てメモリの使用状況を確認したり、傾向をチェックします。
![2020-11-10_12h30_40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/364110/cb06dd6f-abee-0453-a12f-af674be5df7f.png)

画面右には[LLMタグ](https://qiita.com/donbutsu17/items/dd410cd6ee53b0b348ca#41-%E3%82%BF%E3%82%B0)毎の設定ができる表示があります。

![LLMTag.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/364110/387ea9f2-f612-d0e3-7f4e-8ec4924fa43a.png)

|名称           	|説明                      				|
|:---------------	|:------------------------				|
| Trackerタブ		|グラフの表示を[プラットフォームタグ]/[全タグ]を切り替えます	| 
| Group byタブ		|グラフの表示を行うタグの検索用グループを表示します		| 
| ✕,＋ボタン		|グラフの表示を[全タグ非表示]/[全タグ表示]を切り替えます	|
| Load XML...ボタン	|グラフとして読み込む.xmlファイルを指定します		|
| ↕S,↕M,↕Lボタン		|グラフの表示領域をそれぞれS,M,Lのサイズ指定で整列します	|

例) ↕S
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/364110/8bb9714d-44e8-a3b5-cf2a-60e578941421.png)

例) ↕M
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/364110/c3a01b34-74f0-1f92-dd5d-78f8b875df35.png)

#5. メモリトラッキング
UIの右側のグラフの傾向を見て、特定のタグが増加傾向にある場合、そのタグでリークが起きていることを確認します。下の図では"Meshes"のタグが増加傾向にあるのでリークの可能性があります。

![2020-11-10_15h20_48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/364110/741220d5-293b-7cc7-bf24-bc8917121c33.png)

Memory Insightsでは使用状況のみ計測できますが、「どこで確保されたメモリが漏れているのか」までを特定することはできません。更に調べる場合には、以下のような方法によって実際のどこで確保したメモリが解放されていないかを調べることになります。

[[UE4] Malloc Profiler/Memory Profiler2を使用したメモリトラッキング](https://qiita.com/donbutsu17/items/a72a282587390f43d12d)
[[UE4] MemProを使用したメモリトラッキング](https://qiita.com/EGJ-Ken_Kuwano/items/288fe494cd6bf4f934c3)
[[UE4] MallocLeakReporterを使用したメモリトラッキング](https://qiita.com/donbutsu17/items/7258955cbb458c1256c9)

#6. まとめ
Memory Insightsを使うとメモリの使用状況を簡単に調べる事ができます。
定期的にメモリを調べたり、Unreal Insightsでパフォーマンスを調べたい時に併用するなど、手軽に使っていきましょう。
Autoscalingを利用した簡単自動復旧構成

#あらまし
AWSでは可用性を高める為、オートスケーリングを基本的に利用すること(＝Multi-AZ)がベストプラクティスです。

**とはいえ**

オートスケーリングには**スケーリングの構想(発火する為の監視の値など)が必要**だったり、**CLBや最低2台のインスタンス費用**、**浦島コンテンツ対策**などなどなど、考えることが多過ぎてなかなか自社の構築部隊の頭を縦に振らせる提案ができないという難点があります。

また、費用の点でも単純に倍に増えるので、お客様からも**まず省略できないか**と言われてしまう場所でもあります。

#なるべくお金をかけない自動復旧構成
案はこうです。

**オートスケーリンググループで最小インスタンス台数、最大最小スケールインスタンスを全て1にしてしまう**

これであれば必要なのは＋CLBの費用だけで済み、インスタンス障害時にはオートスケーリンググループから新しいインスタンスが立ち上がり
**サービスの停止を最低限**で済ませることができます。

#実際にやってみた
細かい設定はドキュメントを見ながらして欲しい。
肝なのは「希望する容量」「最小」「最大」の項目をすべて1にすること。
あとは普通にオートスケーリンググループを作るだけ。
【Auto Scaling グループ】
![01.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536700/3d370603-6381-5885-1d3c-a4965c2c7bb9.jpeg)
疑似障害として、インスタンスを停止する。
![06.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536700/8f7ca4b9-769f-28b7-a33b-b303f625e921.jpeg)
新しいインスタンスが立ち上がった！！
![07.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536700/8fc714b4-0578-7fb1-fbe8-e0826001a3d5.jpeg)
ロードバランサ―にもしっかり紐づいております。
![08.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536700/0b0a43a1-6727-5f82-3b53-e63f908f5ad0.jpeg)

#さいごに
この構成であればAWSフルマネージドで自動復旧構成が組めるので便利ですね。
ただ、基本的にAMIから復旧させるので**コンテンツディレクトリはEFSを使う**など+αが必要になってくると思います。
構成自体は大したことありませんが、お値段お安く、コスト以上にメリットがある設定なので一度は試してみてはいかがでしょうか。
WordPress開発を快適に！　VSCode設定+プラグイン

# はじめに
WordPressの学習やテーマ開発をしている時、インデントがズレてしまって見づらい！！！
そんな時、スペースやタブで見た目を揃えていませんか？
今回は、コード整形とテンプレートタグのインテリセンス(自動補完)について紹介します。

# インテリセンス用プラグイン
WordPressのテンプレートタグはPHPの組み込み関数ではないので補完候補として出てきてくれません。
以下のプラグインを入れるだけで特別な設定はせずとも補完候補として出てきてくれるようになります。
[WordPress Snippets](https://marketplace.visualstudio.com/items?itemName=wordpresstoolbox.wordpress-toolbox)

最初のうちはメソッド名を全て手打ちして覚えるという学習方法もアリかと思います。
ですが、慣れてくると長いメソッドをタイプするのは面倒になってきます。。。
例えば、`get_template_directory_uri()`
単語の頭文字を順番に入力するとインテリセンスが機能する様になっているので有効活用していきましょう！!
![wordpress_snippets.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/843917/4e9c030a-80f5-37a7-e503-4e68b638a559.gif)

# コード整形用プラグイン
今回は２通り紹介します。
工数はどちらもそれほど大差がないのでお好みで！

以下のどちらかのプラグインを入れてください。
1. [Format HTML in PHP](https://marketplace.visualstudio.com/items?itemName=rifi2k.format-html-in-php)
2. [PHP Intelephense](https://marketplace.visualstudio.com/items?itemName=bmewburn.vscode-intelephense-client)

プラグインを入れ終わったら、setting.jsonを開いて以下の設定を追記してください！
settings.jsonはこちらの[リンク](https://qiita.com/nabecima/items/64ba4c1c8cf5b5d44f99)を参照ください
settings.json内の別の場所で`"editor.formatOnSave": true`が記述されていれば、以下の記述はしなくても問題ありません。

```json:settings.json
  "[php]": {
    "editor.formatOnSave": true
  }
```
これでファイルを保存するたびに自動でコード整形してくれるようになります！

## PHP Intelephenseを入れた方対象
PHP Intelephenseはテンプレートタグが組み込み関数ではないので、エラーのように存在しないメソッドは赤い波線が表示されます。
これを解決するにはこちらの[サイト](https://monoxa.net/2019/12/wordpress-vscode-problem-solving-method-that-wordpress-function-is-treated-as-an-error-in-php-intelephense-extension/)をご参照ください。

# おわりに
インデントが揃うだけでもかなり気分的にスッキリするのでお試しあれ！
データカタログに手元のcsvファイルを登録する。

#データファイルの登録

データカタログに、何かのデータを追加してみましょう。
今回は手元にある「ローカル・ファイル」をカタログにアップロードしてみます。
画面の右上の「ローカル・ファイル」をクリックします。
![スクリーンショット 2020-10-31 23.43.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295123/53bc616a-9de0-292b-b53f-428519aff621.png)

ファイル追加の画面になります。
![スクリーンショット 2020-10-31 23.45.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295123/74707c96-fced-040c-5115-d78926420ef8.png)

csvなどのファイルを画面左上の点線枠内にドラッグアンドドロップし、右側の「説明」に入力します。
今回は擬似個人情報のcsvファイルを使用します。
「ビジネス用語」は未設定なので、今回は入力しないです。
タグには「PII」と入力してみて、＋ボタンをクリックします。
「分類」では「Personally Identification Information」を選択します。
「プライバシー」では「パブリック」を選択します。
![スクリーンショット 2020-10-31 23.48.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295123/2795db9a-9837-0013-fe74-f0208c636223.png)
そして「追加」ボタンを押します。


カタログにファイルをアップロード中です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295123/002ed787-6ec6-1eeb-5603-a4ef811c5b8b.png)


カタログにファイルが登録されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295123/d27f636d-5497-8c0e-d887-8bfa19f3e53c.png)

#登録されたファイルの確認
ファイルが登録されています。個人情報のように見えますが、本物の個人情報ではなく、偽の情報です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295123/f9667d6a-f3b8-d27d-fd74-0e08bff99635.png)
環境変数の設定

#はじめに
LINE-botを開発する際に自分がつまづいた**環境変数**について書きたいと思います！

###**環境変数**とは
まず「**環境変数**ってなんや？」って方もいると思うので（僕がそうでした😅）**環境変数**の説明からします！
**環境変数**とは

>OSが提供するデータ共有機能の一つ。OS上で動作するモノがデータを共有するための仕組みである。(wikipedia)

です。
要は、プログラミングで使う変数のようにあらかじめ設定して置くことで後で呼び出せるようにしておく箱のようなモノです！
イメージはこちらのサイトが分かりやすかったです👉　[環境変数](https://wa3.i-3-i.info/word11027.html)

###環境変数のメリット
**環境変数**のメリットは大きく３つ！！

1.OSレベルでの標準機能なのでプログラミング言語に依存しない
2.KeyValueペアで存在するだけのシンプルな機能
3.文字列、型等も持たない

###いつ使うのか？
次は**環境変数**を使う場面ですが主に「機密情報をアプリケーションに渡す」際に使用されます。
GitやGithubでコードを管理していると不特定多数に見られることを前提にしていますがLINEの**アクセストークン**や**シークレット**などの機密情報は隠さないといけません。

そのためOS上に**環境変数**を設定し、コードで呼び出すという方法が使用されています。

#実行した環境
今回はLINEのアクセストークンとシークレットを**環境変数**として登録し、Pythonファイルで呼び出すということを行いました！　実行環境は以下です。
OS：MacOS
言語：Python
環境：Cloud9
シェル：bash

#やり方
まずターミナルで**環境変数**の登録を行います！
※「＄」はターミナルで打ってますよーという意味なので実際には打ちません！

```
$export LINE_CHANNEL_ACCESS_TOKEN="ここにLINEbotのアクセストークンを入力!"
$export LINE_CHANNEL_SECRET="ここにはシークレットを入力！"
```

次はコードを書いて設定した環境変数を呼び出します！

```python:python_file.py
#osモジュールをインポート
import os

#環境変数の呼び出し
LINE_CHANNEL_ACCESS_TOKEN = os.environ["LINE_CHANNEL_ACCESS_TOKEN"]
LINE_CHANNEL_SECRET = os.environ["LINE_CHANNEL_SECRET"]
```

これでOSに設定した環境変数を呼び出すことができます。
なお、**環境変数**はターミナルを立ち上げるごとに設定しないといけないためご注意を！！
[Rails]”通知を何かしらの方法で知らせる”の実装

__通知機能にチャレンジしたけど、なぜか上手くいかない。__

## お知らせ通知

[![Image from Gyazo](https://i.gyazo.com/73121a0468ba3396a7db386ccfdce49e.png)](https://gyazo.com/73121a0468ba3396a7db386ccfdce49e)
↑こんな感じで未読のお知らせがあったら、赤い点をつけるみたいなやつを、javascriptとか、helperファイルのアクションを使わずに実装する方法。

まだお知らせ機能自体を実装していない方は下記ののような分かりやすい記事を参考に実装しましょう！
* https://qiita.com/nekojoker/items/80448944ec9aaae48d0a
* https://qiita.com/yuto_1014/items/2db1dd4fcd7945b980f7

上記の記事でチャレンジしたけど、上手くいかない、、といった私と同じような問題を抱えている方へ向けて。

## 表示したいビューに紐づくコントローラーのアクションに変数を定義しておく
```events:events_controller.rb
  def index
    @notification = Notification.all
  end
```
notificationsテーブルの情報を取得.


## [簡単]html.erbに記述を追加するだけ

```event:index.html.erb
　　<div class="alert-header">
      <%= link_to notifications_path do %>
        <span class="material-icons" id="alert">notification_important</span> 
        <% @notification.each do |notification| %>
          <% if (notification.visited_id == current_user.id) && notification.checked == false %>
            <span class="material-icons" id="on-alert">fiber_manual_record</span>
            <% break %>
          <% end %>
        <% end %>
      <% end %>
    </div>
```

■解説

```
<% @notification.each do |notification| %>
```

コントローラーで定義した@notificationの変数をeachメソッドを用いて通知それぞれに対して処理が行われるようにする。
ブロック変数は今回`notification`としたが何でもOK。
<br>

```
<% if (notification.visited_id == current_user.id) && notification.checked == false %>
    <span class="material-icons">fiber_manual_record</span>
    <% break %>
<% end %>
```

if条件式を用いて、`visited_id`（コメントをされた側のユーザーのid）が`current_user.id`(現在ログインしているユーザーのid)、
尚且つ、`notification_checked`（notificationsテーブルのcheckedカラム）の値がfalse(未読)であれば以下の処理をする、という記述。

`break`としないと、通知の数だけ処理が繰り返されてしまうので注意。

以上。
何度やっても上手くいかなかったので、自分なりにアレンジしてみました。

## 備考
current_user.idはサインインしているユーザーを取得するためのgem 'devise'を導入した事で使えるようになるヘルパーメソッドですが、ログインしているユーザーのIDを取得できればOK。

__マテリアルアイコンの導入は下記の記事を参考にどうぞ__

* [マテリアルアイコンの導入方法](https://qiita.com/takumi_murakami/items/e2d82c774d5ad3054eec)
MetricFireのデータビュー機能

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614998/515c5489-eb5d-3c77-4264-7090c90ffbd0.png)

[MetricFire](https://www.metricfire.com/japan/?utm_source=blog&utm_medium=Qiita&utm_campaign=Japan&utm_content=Data%20Views)のHosted Graphiteは、送信したデータに対してさまざまな統計ビューを自動的に生成し、ダッシュボードで表示するのに最適な解像度でメトリックの高速ビューを提供します。

#なぜデータビューがすごいのか

データを詳しく解析したい際に役立つのがデータビュー機能です。普通ある一定間隔でデータポイントを表示する場合、オープンソースのgraphiteなどでは、あるレゾーリュション間の最後のデータがデータポイントとして表示されます。
しかし、[MetricFire](https://www.metricfire.com/japan/?utm_source=blog&utm_medium=Qiita&utm_campaign=Japan&utm_content=Data%20Views)では、そのレゾリューションの全てのデータの平均値や最高値などの詳細なデータを表示することができます。これは、あるレゾリューション間での１つのデータだけを参考にするわけではなく、全てのデータを参照するため、かなり高精度な監視を行うことができるのです。
これを他のSaaSツールなどで行うとそれなりに金額がかかってしまうものですが、MetricFireでは、このデータビュー機能をデフォルトで提供されているのも魅力です。

#View

すべてのGraphiteメトリックに対してデフォルトで保持するさまざまなビューは次のとおりです。

###：avg

平均（デフォルト）

###：sum

現在のグラフ解像度の時間枠中に受信したデータポイントの合計。 これはズームレベルによって異なります。
例：30秒ごとにデータポイントが描画されるグラフで：sumを使用すると、30秒ごとに受信したすべてのデータポイントの合計が表示されます。

###：sumrate

合計をデータポイント間の秒数で割ると、1秒あたりのレートが得られます。
：sumと：sumrateは、Counterメトリックで使用する最も一般的なビューです。

###：sum30：sum60：sumN：

sumrateから計算された、指定された秒数で受信した合計を提供します。 例えば。 ”：sum30”は、30秒にわたる合計を提供します。
これは、表示しているデータ解像度に関係なく一貫性のあるメトリックの合計が必要な場合に役立ちます。
より広いタイムスケールでグラフを描画する場合、それらを描画するために使用可能なスペースよりも多くのデータポイントがあります。 ”：sumN”構文を使用すると、指定された秒数にわたって正確にスケーリングされた合計を確認できます。

###：min
最小値

###：max
最大値

###：obvsrate
観測値を収集期間の秒数で割ると、1秒あたりのレートがわかります。

###：90pct：95pct：99pct
任意のパーセンタイルデータが必要ですか？ コロンの後に数字を追加し、その後に「pct」を続けます。 01から99までの値を受け入れます。100パーセンタイルが必要な場合は、「：max」を使用する必要があります。

#使用例

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614998/c68b6ee5-18d7-abc3-f65f-294848314502.png)

StatsDとの比較
Hosted Graphiteビューは、statsdと完全に類似しているわけではありませんが、一般的に使用する場合は、ほとんど同じことを実行します。

- counting -> ‘:sum’ or ‘:obvs’
- rates -> ‘:sumrate’ or ‘:obvsrate’
- timers -> ‘:avg’ or ‘:min’ or ‘:max’
  
#データビューとGraphite関数
Graphite関数は、1つ以上のデータ系列に作用し、それらを新しいデータ系列に変換します。 Graphite関数を使用する場合、次の点に注意することが重要です。

- クエリで指定されたデータビューは、関数によって変更されません。 [sumSeries（）関数](http://graphite.readthedocs.io/en/latest/functions.html#graphite.render.functions.sumSeries)を使用する場合、クエリでも：sumを使用しない限り、各シリーズの平均値を合計することになります。
- グラフの解像度は関数によって変更できますが、データ系列の解像度は変更できません。 たとえば、summary（）を使用すると、指定した時間枠内のすべてのデータポイントを1つにグループ化できます。 グラフのズームレベルを変更しても、[summary（）関数](http://graphite.readthedocs.io/en/latest/functions.html#graphite.render.functions.summarize)によって出力される間隔は変更されませんが、使用可能なデータポイントの数が変更される可能性があります。
EDITOR=vi rails credentials:editするもCouldn't decrypt config/credentials.yml.enc. Perhaps you passed the wrong key?と言われる

## 記事の目的
タイトルの通り、EDITOR=vi rails credentials:editのコマンドを実行するも
credentials.yml.encが開けない状況に...😭

しかしググりながら開けたので、その過程を共有し誰かのお役に立ればと思い記事にしました。

初学者なので間違いがある可能性があります。その際は、ご指摘下さい。

##エラーから現状把握（結論:master.keyが既存のcredentials.yml.ercに対して使えないのが原因）

credentials.yml.encに情報を入れたく、viコマンドを打つと、以下のエラー内容が出た。

```
$ EDITOR=vi rails credentials:edit                                 
Adding config/master.key to store the encryption key: 

Save this in a password manager your team can access.

If you lose the key, no one, including you, can access anything encrypted with it.

      create  config/master.key

Couldn't decrypt config/credentials.yml.enc. Perhaps you passed the wrong key?
```

内容はこんな感じかと思います。
・暗号化キーを保存するのに、config/master.keyを追加しといたぞ〜
・復号できません。もしや...キー間違えてない？

暗号？復号？キー？credentials.yml.erc?は？という方は、以下の記事を読むといいかもしれません。
https://qiita.com/NaokiIshimura/items/2a179f2ab910992c4d39
https://hirocorpblog.com/rails-credentials-master/

また、復号された内容を閲覧する為のコマンドを打つと別のエラーが出る。（このエラーが糸口になりました）

```
$ rails credentials:show(エラーログは長いので抜粋)

OpenSSL::Cipher::CipherError

ActiveSupport::MessageEncryptor::InvalidMessage (ActiveSupport::MessageEncryptor::InvalidMessage)
```

OpenSSL::Cipher::CipherErrorのエラーは拾ってないです、すみません。
ActiveSupport::MessageEncryptor::InvalidMessageについては、以下の記事で触れられており、
「上のコマンドで新しく生成された鍵が既存のcredentials.yml.ercに対して使えない」為、エラーが出ているようでした。以下の記事のおかげで現状が把握できました🙇‍♂️

https://qiita.com/scivola/items/cc06ddbfd94d3118f693
https://qiita.com/kenz-dev/items/67ac14d1c89f7c5641c1
##解決策（credentials.yml.encを作り直す）

config/credentials.yml.encのファイル名を
config/credentials_backup.yml.enc等にファイル名を適当に変更します。
（以下のコマンドで新しいcredentilals.ymlを作成する為に、名前の重複を防ぐ為に名前を変更します）

そして、EDITOR=vi rails credentials:editを再度実行....開けました！！

```
$ EDITOR=vi rails credentials:edit
File encrypted and saved.
(↓viコマンドにより表示された中身)
# aws:
#   access_key_id: 123
#   secret_access_key: 345
# Used as the base secret for all MessageVerifiers in Rails, including the one protecting cookies.
secret_key_base: 
~                                                                                                                                                            
~                                                                                                                
```
また、「ファイルは暗号化され、保存されたぞ〜」と言ってくれましたね。
※先ほど、名前変更したcredentials_backup.yml.ercはもう不要なので削除して下さい。

##なぜcredentials.yml.encは開けた？
これは、$ EDITOR=vi rails credentials:editによって、
credentials.yml.encが新しく作成され、上で作った鍵と紐づくからです。
（編集のコマンドなのに、鍵がなければ鍵を、credentials.yml.ercがなければcredentials.yml.ercを作成するようですね。）

まとめると、既存のcredentials.yml.ercをcredentials_backup.yml.ercに変更した為、credentials.yml.ercがない扱いになり、その状態で上のコマンドを実行すると、新しいcredentials.yml.ercが作成され、鍵と紐づいたということになります。

紐づいた後は、変更したcredentials_backup.yml.ercは不要なので削除して下さい。
このように「ファイルの名前変更→新たにファイル作成→名前変更したものの削除」の流れで作業しましたが、以下の記事で紹介している「既存のcredentials.yml.ercを削除する」解決策とやってることは一緒かと思いますので、「既存ファイルの削除→新たにファイル作成」でもよいかと思います！

https://qiita.com/kenz-dev/items/67ac14d1c89f7c5641c1
H2databaseのリカバリ方法

DBファイルの破損等の障害が発生した際に慌てるようなことが無いようリカバリ方法を備忘録として残しておく。

H2DatabaseにはPosgreSQLの「VACUUM」のようなDBファイルのお掃除機能がないようなので、本リカバリ手順でそれと同等のことが実現できることから、長期間の運用でDBの肥大化が発生してしまった場合にも使えるものと思われる。

余談ではあるが、H2databaseの「1.4.199」というバージョンではDBファイル破損が発生するようなので、「1.4.199」を使用している人は早急に「1.4.200」へバージョンアップすることをお勧めする。

DBファイル破損の根本原因は不明ではあるが、長期間運用していると、JVMのクラッシュ等を契機にDBファイルの破損が発生することがあるようで、一度DBファイルの破損のエラーが発生してしまうと再びDBへ接続できなくなる症状に陥ってしまう。

但し、「1.4.199」でDBファイルの破損が発生しても、2020年11月時点で最新版となる1.4.200のJDBCを使って接続すると問題無く接続できるといった現象もみられることから、内部的になんらかの不整合が発生しているだけでDBファイルの破損自体は発生していない可能性も考えられる。

# リカバリ用スクリプト生成(バックアップ)

リカバリ用のスクリプト(SQL)をファイル自動生成

```
$ java -cp h2-1.4.200.jar org.h2.tools.Script -url "jdbc:h2:file:./<DBファイル名>" -user sa -password <パスワード> -script recovery.sql
```

該当のDBファイルが存在しなくても、エラー等出力されずに、うまく処理されたように見えるため、出力後は必ず、recovery.sqlをエディタ等で開いて該当DBファイルのDDL(CREATE文)とDML(INSERT文)が正常に出力されていることを確認する

# 旧DBファイルの退避

バックアップ対象のDBファイルを任意の場所に退避し、対象のDBファイルを任意の場所に退避する。

```
$ mv ./<DBファイル名> /tmp/backup
```

# リカバリ実行

```h2:組み込みモードの場合
$ java -cp h2-1.4.200.jar org.h2.tools.RunScript -url "jdbc:h2:file:./<DBファイル名>" -user sa -password <パスワード> -script recovery.sql -showResults
```

```h2:サーバーモードの場合
$ java -cp h2-1.4.200.jar org.h2.tools.RunScript -url "jdbc:h2:tcp://<H2DB-IP>:/./<DBファイル名>" -user sa -password <パスワード> -script recovery.sql -showResults
```
※「-showResults」を指定すると実行結果を標準出力に出力する

実行後、以下のようにrecovery.sqlの実行結果が表示されば成功

```
CREATE USER IF NOT EXISTS "SA" SALT 'XXXX・・・' HASH 'XXXX・・・' ADMIN;
CREATE SEQUENCE "PUBLIC"."SYSTEM_SEQUENCE_XXXX・・・" START WITH 385 BELONGS_TO_TABLE;
CREATE SEQUENCE "PUBLIC"."SYSTEM_SEQUENCE_XXXX・・・" START WITH 385 BELONGS_TO_TABLE;
```

尚、接続先に指定したDBファイルが無い場合、自動的にDBファイルが作成されてしまうので注意が必要
【流出解析】シリーズ　第4回　流域実蒸発散量の推定―蒸発散比法―

# 移転のお知らせ

こちらの記事は下記のサイトに移転しました。

> [NNテックブログ](https://nnhiroba.xsrv.jp/nnTechBlog/Article/Article?ID=36)
SQLで複雑なデータの取得方法

下記の記事でSQL文の基礎について投稿しました。
(https://qiita.com/yyy752/items/78896d2af72edf318c87)
SQL文に`WHERE 条件式`を加えることで、条件を絞ってデータを取得できるのですが、他にも複雑なデータを取得する方法があるので、今回はそれを紹介します。

##複雑なデータを取得できるSQL文

|文法|意味|
|:---:|:---:|
|AND, OR|取得するデータの条件同士をつなげる|
|BETWEEN|指定した値の範囲と比較する|
|IN|指定したリストの値が含まれるか比較する|
|LIKE|パターンに合致するか比較する|
|LIMIT|取得するデータの行数の上限を設定する|
|GROUP BY|データをグループ化する|
|HAVING|グループ化したデータに対して取得する条件を設定する|

今回は例文は除いて基本文のみ紹介します。

##AND,OR 取得するデータの条件同士をつなげる
`AND:かつ`　`OR:もしくは` という意味です。
`SELECT カラム名 FROM データベース名.テーブル名 WHERE 条件式① ANDもしくはOR 条件式②` 


##BETWEEN 指定した値の範囲と比較する
`指定の範囲に含まれるデータを抽出`したい時に使用します。
`SELECT カラム名①,② FROM DB名.テーブル名 WHERE カラム名 BETWEEN 最小値 AND 最大値`
最初に`取得したいカラム名`を指定して、WHEREから`条件を絞りたいカラム名と範囲`を指定します。

##IN 指定したリストの値が含まれるか比較する
`指定したリストに含まれるデータを抽出`したい時に使用します。
`SELECT カラム名 FROM DB名.テーブル名 WHERE カラム名 IN ('値','値','値')`
最初に取得したいカラム名を指定して、WHEREから条件を絞りたいカラム名と取得したい値を指定します。
また、`NOT IN`にすることで指定した値に`該当しないデータ`を取得できます。

##LIKE パターンに合致するか比較する
`特定の文字列パターンに合致するデータを抽出したい`時に使用します。
`SELECT カラム名① FROM DB名.テーブル名 WHERE カラム名 LIKE 'パターン%もしくは_'`
`%`：`任意の0文字以上の文字列`
→A%Bの場合、AB、ACB、ADDB、ACHDBのように'Aで始まり、Bで終わるデータ'を取得する。
`_`：`任意の1文字`
→A_Bの場合、ASB、ADB、AFBのように'AとBの間に一文字のみ入るデータ'が取得される。

##LIMIT 取得するデータの行数の上限を設定する
`抽出できるレコード数の上限を設定`したい時に使用します。
`SELECT カラム名 FROM DB名.テーブル名 LIMIT 最大件数`

##GROUP BY データをグループ化する
`特定のカラムの値を基準にグループ化してデータを抽出`したい時に使用します。
`SELECT カラム名 FROM DB名.テーブル名 GROUP BY カラム名,カラム名`

SELECT文を使って`グループ単位のデータを取得`するとき、`SQLに用意されている関数`を使用して、`集計などの計算結果`も抽出することができます。
`SELECT name, sum(sales) FROM shop.users group by name;`
例えば、これで`name(従業員)ごとのsales(売上)の合計値`を抽出できます。

##HAVING グループ化したデータに対して取得する条件を設定する
`グループ化したデータに対して更に条件を指定してデータを絞り込みたい`時に使用します。 
`SELECT カラム名 FROM DB名.テーブル名 GROUP BY カラム名 HAVING 条件式`
`SELECT カラム名 FROM DB名.テーブル名 WHERE 条件式① GROUP BY カラム名 HAVING 条件式`
 HAVINGの後に記述する条件式は、`WHEREの場合と同様に記述可能`。

`SELECT name, sum(sales) FROM shop.users group by name HAVING sum(sales) >= 2000;`
例えば、これで`name(従業員)ごとのsales(売上)の合計が2000以上`のデータを取得できます。
いつもと違うPCでpushしてみたら、GitHubの草が生えない（Contributionが増えない）

# はじめに

GitHubの同じアカウントに対して、
2台のPCを使い、それぞれでGitコマンドを使ってファイルをアップロードしていたのですが、
片方のPCでファイルアップロード(`$ git push`)してもContributionが増えない、
いわゆる草が生えない状況に陥りました。

その解決方法を記します。


# この記事でわかること

- リモートリポジトリ（GitHub）へアクセスするユーザーのアカウント情報の変更方法
- $ git configコマンドを使ったuser.nameの変更方法

# 環境

- Git 2.28.windows.1(1st PC)
- Git 2.25.1(2nd PC)

# 原因

## 原因だったのは何？

結論から述べると、
GitHubのアカウントに登録しているメールアドレスと、
Git上で設定しているuser.emailが一致していないために今回の事態となりました。

1台目のPCではこれらが一致していたのですが、2台目のPCでは一致していませんでした。
このため、2台目のPC上で `$ git push` を何度も行っても草が生えない状態になっていたのです。

より具体的にいえば、
GitHubアカウントはhogehoge@example.comで登録しているのに対して、
1台目のPCのgitのemail設定はhogehoge@example.com 、
2台目のPCではfoofoo@example.com
と設定していたといったところです。


## 原因のさがしかた

メールアドレスの不一致が原因かどうかは、git configコマンドを使って判断します。

ここではGitHubのアカウントに使用しているメールアドレスが **hogehoge@example.com** であるとします。

```1st.PC
$ git config user.email

hogehoge@example.com

```

```2nd.pc
$ git config user.email

user.email=hoge
```

以上のことから、2台目のPC（2nd.PC）はGitHubアカウントのメールアドレスと一致していないことがわかります。

# 解決方法

gitに設定しているuser.emailを、GitHubに登録しているメールアドレスに変更します。

```2nd.PC
$  git config --global user.email hogehoge@example.com
```
【Unity】【ECS】向いている方向へ動かしたい

## やりたいこと
Unity ECS でオブジェクトを描画し、個別に向いている方向へ進ませたい

## 問題・試したこと
`transform.Translate(Vector3.forward * Time.deltaTime);`は使えません。どうしたものか。

## 解決方法
`translation.Value += LocalToWorld.Up * deltaTime * <速度>;`で解決しました。

## コード例

```C#:MoveSystem.cs
﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Entities;
using Unity.Transforms;

public class MoveSystem : ComponentSystem
{
  protected override void OnUpdate(){
    var dt = Time.deltaTime;
    Entities.ForEach((ref Translation translation, ref Speed speed, ref Rotation rotat, ref LocalToWorld ltw) => {
        speed.velocity += dt * speed.accel;//AccelをもとにVelocityに反映
        translation.Value += ltw.Up * dt * speed.velocity;
        //頭方向にVelocityずつtranslationを更新
      });
  }
}
```

LocalToWorldを理解するとだいぶ扱いやすくなりますね。
anyhowを試していたら?と型でハマった


初心者が、anyhowを試していた時にハマりました。

# エラーの型でハマる

anyhow
https://docs.rs/anyhow/1.0.34/anyhow/

## anyhowのサンプル

```rs
use std::fs::File;
use anyhow::Result;

fn main() -> Result<()> {
   let l = File::open("bar.txt")?;
   Ok(())
}
```

ファイルがないのでエラーが返ります。

```
Error: 指定されたファイルが見つかりません。 (os error 2)
error: process didn't exit successfully: `target\debug\test.exe` (exit code: 1)
```

anyhowはエラーをいい感じにまとめてくれるすばらしいやつです。
勝手にResultをすべてよしなにしてくれるような気になりました。

ふとそのまま返してみると

```rs
fn main() -> Result<()> {
   let l = File::open("bar.txt");
   
   match l {
       Ok(f) => f,
       Err(e) => return Err(e),
   };
   
   Ok(())
}
```

型が違うのでコンパイルエラーになってしまいました。

```
error[E0308]: mismatched types
  --> src\main.rs:10:29
   |
10 |        Err(e) => return Err(e),
   |                             ^ expected struct `anyhow::Error`, found struct `std::io::Error`
```

## 修正版



```rs
fn main() -> Result<()> {
   let l = File::open("bar.txt");
   
   match l {
       Ok(f) => f,
       Err(e) => return Err(e.into()),/*intoが必要*/
   };
   
   Ok(())
}

```

intoが必要でした。
?がキャストしてくれるのですぐに気づきませんでした。


余談ですが、anyhow::Errorが返るマクロもあるようです。

```rs
fn main() -> Result<()> {
   let l = File::open("bar.txt");
   
   match l {
       Ok(f) => f,
       Err(e) => return Err(anyhow!("エラー：{}",e)),
   };
   
   Ok(())
}
```

```
Error: エラー：指定されたファイルが見つかりません。 (os error 2)
error: process didn't exit successfully: `target\debug\test.exe` (exit code: 1)
```




# 非同期でハマる

普通にawaitする場合はそのまま

```rs
use anyhow::*;
use tokio::fs::File;

#[tokio::main]
async fn main() -> Result<()> {
    File::open("foo.txt").await?;
    Ok(())

}
```

```
Error: 指定されたファイルが見つかりません。 (os error 2)
error: process didn't exit successfully: `target\debug\test.exe` (exit code: 1)
```

エラーが返ります。

よくspawnしている例があるのでspawnしてみると

```rs
#[tokio::main]
async fn main() -> Result<()> {
     let handle = tokio::spawn(File::open("foo.txt"));
     let result = handle.await?;

    Ok(())
}
```

エラーになるのを期待していたのですが、正常終了してしまいます。

## 修正版

```rs
#[tokio::main]
async fn main() -> Result<()> {
     let handle = tokio::spawn(File::open("foo.txt"));
     let result = handle.await??;  /*2ついる*/

    Ok(())
}
```

?が2つ必要でした。
handleはJoinHandleに包まれた型`tokio::task::JoinHandle<std::result::Result<tokio::fs::File, std::io::Error>>`
になっていてawaitすると
`std::result::Result<std::result::Result<tokio::fs::File, std::io::Error>, tokio::task::JoinError>`
とResultがネストした形になっているためでした。



# 結論

型をちゃんとみろってことですね。

# 追記

https://cha-shu00.hatenablog.com/entry/2020/12/08/060000
詳しく解説してくださっています。
iOSでFirebase Cloud Messagingのプッシュ通知が届かない(AuthKey使用)

何度も実装しているFCMでiOSにプッシュ通知が届かないという現象にハマりました。

原因は `Team ID` と `App Id Prefix` が異なっていたせいです。
歴史的経緯で App Id Prefixの候補が複数ある環境で、Team IDと異なるApp Id Prefixが利用されている場合、以下のような状況になります。

- FirebaseのiOSアプリ登録はプロビジョニングから取得される `App Id Prefix` が指定する
- プッシュ通知の設定でAuthKeyを使用しようとすると、↑から `App Id Prefix` の値が `Team ID` として自動的に登録される。しかも変更できない。
- しかしAuthKeyは本当の `Team ID` を指定する必要がある
- そのためプッシュ通知が届かない

# 解決方法
1. AuthKeyを諦めて、証明書を使う
2. [ここ](https://developer.apple.com/library/archive/technotes/tn2311/_index.html)を参考に `App Id Prefix` のマイグレーションを行う


# 参考
https://github.com/firebase/quickstart-ios/issues/674#issuecomment-521142199
https://github.com/firebase/quickstart-ios/issues/381
https://qiita.com/shtnkgm/items/12535e9530498178bcf0
np.meanとnp.average速さ対決

　NumPyで平均をとる方法として`np.mean`と`np.average`の2つがある(他にもあるかも知れないが)。ここでは、その二つの違いに関しては他の記事に任せるとして、処理速度としてはどちらが優秀なのかを見ていく。
　なお、以下のコードはこの[サイト](https://note.nkmk.me/python-timeit-measure/, "Pythonのtimeitモジュールで処理時間を計測")を参考した。
# 実行環境
CentOS Linux release 7.6.1810 (Core)
Python 3.8.5
# 実行コード1
まずは単純に1次元の配列を平均する。

```python:test1.py
import timeit
import numpy as np

def func_average(n):
    return np.average(np.arange(n**2))

def func_mean(n):
    return np.mean(np.arange(n**2))

n = 1000
loop = 1000

result_average = timeit.timeit(lambda: func_average(n), number=loop)
result_mean = timeit.timeit(lambda: func_mean(n), number=loop)

print('average: ', result_average / loop)
print('mean:    ', result_mean / loop)
```
実行結果

```
average:  0.0015093836802989244
mean:     0.001964871450792998
```
この他にも4回計測したが、いずれも`np.average`が20~30%ほど速かった。
# 実行コード2
次に、2次元配列の平均をとる。

```python:test.py
import timeit
import numpy as np

def func_average(n):
    return np.average(np.arange(n**2).reshape(n, n))

def func_mean(n):
    return np.mean(np.arange(n**2).reshape(n, n))

n = 1000
loop = 1000

result_average = timeit.timeit(lambda: func_average(n), number=loop)
result_mean = timeit.timeit(lambda: func_mean(n), number=loop)

print('average: ', result_average / loop)
print('mean:    ', result_mean / loop)
```
実行結果

```
average:  0.0016613604403100909
mean:     0.002270303561817855
```
こちらの場合でも、`np.average`が速かった。

# 考察
　他にも似たような条件を試してみたのだが、どうやっても`np.average`の方が計算速度が速いという結果が出た。これは`np.mean`の意味が無いのでは...
　さすがにそんなはずはないと思い、さらに検索してみるとこのような[スレッド](https://stackoverflow.com/a/38783757/12582258, "mean vs average")を発見。以下翻訳、改変して引用：
> (上略)
`average`と`mean`の考慮すべき違いは他にもある(この前のスレッドで違いが他にも述べられている)。`average`はmaskを考慮せずに配列の値全部の平均を取るのに対して、`mean`はmaskを考慮するため、maskされていない値のみで平均を取る。

```python
g = [1,2,3,55,66,77] 
f = np.ma.masked_greater(g,5) # 5より大きい値をマスクする -> [1,2,3,--,--,--]

print(np.average(f)) # 34.0 (= (1+2+3+55+66+77) / 6)
print(np.mean(f)) # 2.0 (= (1+2+3) / 3)
```
なるほど、欠損値を含む配列を扱う場合は`mean`を使うべきであるようである。

# 結論
* 単純な処理速度だけでいえば`average`。
* 欠損値を含むデータを扱うなどで`numpy.ma`を使う場合は、`mean`。

用途に応じて使い分けるのが一番だが、プログラム全体にかかる時間からするとそれに占める`average`や`mean`の割合は微々たるものであると思うため、何も考えず`mean`を使うという選択肢もアリではなかろうか。
Windows版Neovim(-qt)でdeol.nvimでgit-bashのbash.exeを使いたい時のおまじない

# 前提

- Neovim
    - v0.4.4
- Windows
    - Windows10 Build: 2004

※あらかじめgit-bashで起動されるbash.exeにはパスを通しておいてください

# 概要

(Neo)vimには以下のようにコマンドなどで実行する際に仕様するシェルを選択することができる

例えば私の場合はbashが使いたいので `set shell=bash` として、bashを使用できるようにしている

```init.vim
if has('win32')
  set shell=bash
endif
```

これを設定することでNeovimやVim8で実装されているターミナルモード (`:terminal`) でWindowsでもbashが使用できる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507143/2fe73902-8030-a7c3-fa79-08b80d9a6f3a.png)

ところで、 [deol.nvim](https://github.com/Shougo/deol.nvim) というプラグインがある

これは、このターミナルモードをNeovimのフローティングなどを使用しながら利用できるようにしたもの、と今のところ理解している (間違ってたら本当にすみません。。。)

もちろん、Deinでインストールができる

私は、このようにしてCtrl+oで小さなターミナルウィンドウをNeovimの上に表示させるようにしている

```dein.toml
[[plugins]]
repo = "Shougo/deol.nvim"
hook_add = '''
  " 【Ctrl + o】 float windowでターミナルを表示
  nnoremap <silent><C-o> :<C-u>Deol -split=floating<CR>
  " 【ESC】 ターミナルモードから抜ける
  tnoremap <ESC>   <C-\><C-n>
'''
```

# 問題

WindowsでNeovimでdeol.nvimを使用した場合、次のようにエラーでそのまま終了する、という問題がある

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507143/8a90c458-203e-c2a2-5681-50bfd7df8b64.png)

# 解決方法

[このIssue](https://github.com/vim/vim/issues/5136#issuecomment-547422388)にすべては載っていた

つまり、先ほどの `set shell=bash` の後ろに次の2行を追加すれば良い

```diff
if has('win32')
  set shell=bash
+  set shellcmdflag=-c
+  set shellquote="
endif
```

このように解決できる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507143/308e6625-5e05-b988-1353-c393bafb7eb1.png)
RNN_LSTM2　自然言語処理

[Aidemy](https://aidemy.net/)　2020/11/10
#はじめに
　こんにちは、んがょぺです！バリバリの文系ですが、AIの可能性に興味を持ったのがきっかけで、AI特化型スクール「Aidemy」に通い、勉強しています。ここで得られた知識を皆さんと共有したいと思い、Qiitaでまとめています。以前のまとめ記事も多くの方に読んでいただけてとても嬉しいです。ありがとうございます！
　今回は、RNN_LSTMの二つ目の投稿になります。どうぞよろしくお願いします。

＊本記事は「Aidemy」での学習内容を「自分の言葉で」まとめたものになります。表現の間違いや勘違いを含む可能性があります。ご了承ください。

今回学ぶこと
・形態素解析など
・深層学習による自然言語処理

#RNN/LSTMによる自然言語処理
##自然言語処理について復習
・自然言語処理では、__単語ごとに文を分ける__必要がある。その手法には__「形態素解析」__と__「N-gramモデル」__があり、主に__MeCab__などの形態素解析機が使われる。こちらについては後述。
・__N-gramモデル__は__N次ごとに単語を切り分け__たり、N単語ごとに文を切り分けて__出現頻度を集計する__手法である。こちらは日本語に限らず__どの言語でも使える__。

##日本語の形態素解析
・日本語の自然言語処理で一番最初に行われることが__「形態素解析」__である。今回はMeCabを使って形態素解析を行うこととする。
・使い方は、まず__「MeCab.Tagger('')」__でインスタンスを作成し、それに__「parse()」__を使うことで形態素解析を行うことが可能である。

##構文解析
・形態素解析を行った後に行うのが__構文解析__である。構文解析とは、各文を__文節に分解__し、文節同士の__係り受けを決定する__手法のことである。
・構文解析を行うプログラムを構文解析器といい、__「CaboCha」__や__「KNP」__などがある。

#深層学習による自然言語処理
##データの前処理
・__データの前処理__は自然言語処理で__非常に大切なステップ__である。主な流れは以下の通り。（詳細は「自然言語処理」参照）
①__クレンジング処理__：HTMLタグなど、文章に関係ないものを除去
②__形態素解析__
③__単語の正規化__：表記揺れなどの統一
④__ストップワード除去__：頻出の割に意味の薄い単語（助詞など）の除去
⑤__ベクトル化__：単語をベクトル化（数値化）

##MeCabによる分かち書き
・MeCabによる__分かち書きのみ__を行うときは__「MeCab.Tagger('-Owakati')」__とすれば良い。これを__「parse(text)」__で実行し、スペース区切りの単語をそれぞれ__「split(' ')」__で区別する。
・分けたもののうち、同じ単語を__「sorted(set(word_list))」__で辞書順でリストを作成する。
・このリスト(vocab)に対し、__「{c: i for i,c in enumerate(vocab)}」__で__「{単語:id}」__の辞書を作成している。
・これをword_listのそれぞれに適用して__idをリスト化__する。（__[vocab_to_int[x]for x in word_list]__）

・コード![スクリーンショット 2020-11-10 13.05.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698700/42e409e1-a194-f8c8-e2c5-f4c33c5bdff4.png)


・結果![スクリーンショット 2020-11-10 13.05.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698700/da7b1a42-7ab9-0a38-e237-bcaef1a1d274.png)

##Embedding
・__単語をベクトル化する__には、__Embedding層__を使うと良い。実装は__Sequentialモデル__の中で行う。
・前項の最後で作成したidのリスト「int_list」をmodelに適用できる形（input_data）にして、model.predictで渡すとベクトル化されたリストが返される。

・コード![スクリーンショット 2020-11-10 13.06.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698700/2d92b0ed-b69b-5dba-ed7b-9f6c26fe0160.png)


##LSTMによる自然言語処理の実装
・今回扱うデータは自然言語のデータであるが、実装自体は今までやってきたものと大きくは変わらないので、ここではコードの掲載に留める。

・コード![スクリーンショット 2020-11-10 13.07.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698700/65b2e6b5-6bd8-7517-ecbc-2efd8b701f01.png)

#まとめ
・深層学習で自然言語処理を行うときは、__データを前処理すること__が大切である。具体的には__「単語をベクトル化（数値化）」__しなければならないので、まずは__形態素解析__で文を単語ごとに分け、__必要のない部分を取り除く__といったことを行わなければならない。
・単語をベクトル化する時は、__Embedding__を使う。実装はSequentialモデルを使う。
・自然言語処理を行うモデルの実装自体は__他のモデルと同様に行えば良い__。

今回は以上です。最後まで読んでいただき、ありがとうございました。
teraterm ログ取得方法

###こんにちわ [@darry6335](https://twitter.com/darry6335)です。
teratermでログ取得する際、自動ログ取得の設定にしているのですが
ログの生成を行うとログ内にESCやらm~やらの必要ない情報が出力されて
ログを見直す際とても可読性が悪いです。
![1キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/866385/1351cb7e-f85b-f5f6-5f96-aa09f3fc2980.png)
調べたところ、改行コードを出力してるようでした。

設定>その他の設定>ログを確認したところ、、、
![2キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/866385/6f59aac8-6e21-b733-9774-7196809d12f1.png)

オプションのプレーンテキストにチェックが入っていました。
つまり改行した部分が、ESCとしてログに出力されてしまっているのかな？
と思いオプションのレ点をバイナリに変更しましたことろESCがログに出力されなくなり
ログの可読性も良くなりました。
![3キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/866385/9cc47a25-9777-1cc9-604d-18d695519698.png)
AWSを勉強する - IAM


AWS Identity and Access Management(IAM)は、AWSを使用するユーザーのアクセス権限を管理する。

#AWSのアカウントの種類

###ルートユーザー
AWSアカウント作成時に作られるIDアカウント
ルートユーザーは、ネットワーク上のどこからでも操作できる権限を持っている。（Administrator的存在）
AWSでシステムを構築・運用する際は、このアカウントを使うことは極力避ける！！！

ルートユーザーしかできないこと

- AWSルートアカウントのメールアドレスやパスワードの変更
- IAMユーザーの課金情報へのアクセスに関するactivate/deactivate
- 他のAWSアカウントへのRoute53のドメイン登録の以降
- CloudFrontのキーペアの作成
- AWSサービス（サポートなど）のキャンセル
- AWSアカウントの停止
- コンソリデイテッドビリングの設定（複数アカウントを統合した請求の設定）
- 脆弱性診断フォームの提出（AWSに脆弱性の診断ができる）
- 逆引きDNS申請

###IAMユーザー
AWSを利用する各利用者向けに作成されるアカウント
システム構築・運用する際は、このアカウントを使う。

###AWS Organizations（組織アカウント）
IAMのアクセス管理を大きな組織でも楽に実施できるようにするサービス

- 複数のAWSアカウントを一元管理：AWSアカウントをグループ化してポリシーを適用して一元的に管理できる
- 一括請求：複数AWSアカウントの請求をひとまとめにする一括決済が可能
- 新規アカウント作成の自動化：コンソール、SDK、CLIでAWSアカウントを新規作成して、作成内容をログ管理できる


#IAMの機能
IAMには次の４つの機能がある。

- IAMポリシー
- IAMユーザー
- IAMグループ
- IAMロール

##IAMポリシー
Action（どのサービスの）、Resource（どういう機能や範囲を）、Effect（許可／拒否）という3つの大きなルールに基づいて権限を設定する。

ポリシー：ユーザーやグループ、ロールに付与する権限をオブジェクトとして管理する

- インラインポリシー：対象ごとに作成・付与するポリシー
- 管理ポリシー：1つのポリシーを複数のユーザーやグループに適用できる
    - AWS管理ポリシー：AWS側が用意しているポリシー
    - カスタマー管理ポリシー：ユーザー自身が管理するポリシー

基本的には、AWS管理ポリシーで基本的な権限を付与し、カスタマー管理ポリシーでIPアドレス制限などの制約を行う。
インラインポリシーは、管理が煩雑になるので、基本的には使わない。（一時的に個別のユーザーに管理を付与するときに利用するなど）


##IAMユーザーとIAMグループ
ユーザーは、AWSを利用するために各利用者に1つずつ与えられる認証情報（ID）。
IAMユーザーの認証方法は、次の2つ

- ユーザーIDとパスワード：Webコンソールにログインするときに使用。
- アクセスキーとシークレットアクセスキー：CLIやAPIからAWSのリソースにアクセスする場合に使用。

グループは、同じ権限を持ったユーザーの集まり。
認証されたユーザーがどういった権限（サービスの利用可否）を持つかを管理する。

グループとユーザーは、多対多の関係である。

###IAMユーザー
1アカウントで5000ユーザーまで作成可能

設計内容

- ユーザー名
- パス（オプション）：パスを元にユーザーの検索ができ、組織階層やプロジェクトなどを設定できる
- 所属グループ：10のグループまで設定可能
- パーミッション：AWSサービスへのアクセス権限

###IAMグループ
1アカウントで300グループまで作成可能

設計内容

- グループ名
- パス
- パーミッション：グループに設定したパーミッションは、IAMユーザーに付与したパーミッションと同時に評価する


##IAMロール
一時的にAWSリソースへのアクセス権限を付与する場合に使用。

例）

- AWSリソースへの権限付与：EC2インスタンス上で稼働するアプリケーションに一時的にAWSのリソースへアクセスする権限を与えたい
- クロスアカウントアクセス：複数のAWSアカウント間のリソースを１つのIAMユーザーで操作したい
- IDフェデレーション：社内のADサーバーに登録されているアカウントを使用して、AWSリソースにアクセスしたい
- Web IDフェデレーション：FacebookやGoogleのアカウントを使用してAWSリリースにアクセスしたい





#参考
- [AWS認定資格試験テキスト AWS認定 ソリューションアーキテクト-アソシエイト (日本語) 単行本](https://www.amazon.co.jp/AWS%E8%AA%8D%E5%AE%9A%E8%B3%87%E6%A0%BC%E8%A9%A6%E9%A8%93%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88-AWS%E8%AA%8D%E5%AE%9A-%E3%82%BD%E3%83%AA%E3%83%A5%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%A2%E3%83%BC%E3%82%AD%E3%83%86%E3%82%AF%E3%83%88-%E3%82%A2%E3%82%BD%E3%82%B7%E3%82%A8%E3%82%A4%E3%83%88-NRI%E3%83%8D%E3%83%83%E3%83%88%E3%82%B3%E3%83%A0%E6%A0%AA%E5%BC%8F%E4%BC%9A%E7%A4%BE/dp/479739739X)
- Udemy
PowerAutomate を使ってTeams Chat を投稿する時に＠メンションする方法

# PowerAutomate を使ってChat 投稿する時にやることのメモ
## ＠メンションの仕方
### HTML で記載する必要があります
HTML としての記載は
### "at" を使ってメンションする
`<at>(youremailaddress)</at>`　とHTMLで記載したら投稿されたChat の中で＠メンションされます。
(youremailaddress) = user ID = 各社で使っている社内Microsoft User ID 
※（）は不要

## Group ID と Chat ID の確認方法
### Group ID (Team ID)
PowerAutomate の選択肢から選択できる。以下の ”Team” と "Channel" は選択肢から選ぶ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573860/18c5f563-678b-44f8-70e7-a4a1acc93219.png)

### Chat ID
各チャットの「横団子メニュー」からリンクをコピーします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573860/8b3dfc59-40a7-cc0b-e171-e45128252b53.png)
メモ帳に貼り付けると以下の様になります。
`https://teams.microsoft.com/l/message/○○○○@thread.skype/●●●●?tenantId=△△△△&groupId=▲▲▲▲&parentMessageId=□□□&teamName=◇◇◇◇&channelName=◆◆◆◆&createdTime=◎◎◎◎◎`
この中から ParentMesasgeID の 「 □□□□ 」をコピーします。この部分がMessage IDとなるので、PowerAutomate の「Message」欄に貼り付けます。

## Chat to Me のTeams Chat へのリンクの作成
以下の通りURL を記載する。
`https://teams.microsoft.com/l/chat/0/0?users=(youremailaddress)`
(youremailaddress) = user ID = 各社で使っている社内Microsoft User ID 
※（）は不要

### HTML としての記載
`<a href="上記のURL">表記したいテキスト</a>`

表記例；
`<a href="https://teams.microsoft.com/l/chat/0/0?users=(youremailaddress)">Teams Chat to Me!</a>`

## Power Automate の条件分け
### Forms の回答を受けて投稿する。
Forms のコネクタを使って簡単に取得出来る。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573860/057a94d5-2909-84c3-3c19-b12fd459d11f.png)

### Condition でForms にコメントが有る時、無い時を判断する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573860/0139d6c6-48c2-b639-c1dc-e843ca4e13fd.png)
[Condition] の左に <Expression> からempty(XXX) と式を入れる
XXX の部分はDynamic Content から Formsの質問事項を選ぶ

[Condition] の右に <Expression> から true を入れる（これで True = Forms に返信・コメントが無い時となる）
以前のPower Automate と仕様が変わっているので注意。
Kerberos协议之TGS_REQ & TGS_REP

# 接上文
前面解释了AS_REQ & AS_REP，在AS_REP中，kdc返回了使用krbtgt hash加密的tgt票据。在TGS_REQ & TGS_REP阶段，就是client拿着AS_REP获得的tgt票据去KDC换可以访问具体服务的tgs票据，然后再使用TGS票据去访问具体的服务。这一阶段，微软引进了两个扩展S4U2SELF和S4U2PROXY。

配置以下Kerberos发包工具。把AS_REP的票据导入，同样勾上RC4加密。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593424/990fd2e3-b4fa-7b56-c0e6-bdc3dd4b13ce.png)

发包
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593424/5373b549-86e3-6b01-0acf-891aef0b4257.png)

# TGS_REQ
在TGS_REQ请求中需要ap-req字段
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593424/3fb73bd7-aeae-a929-23db-b2ea1d698c69.png)
这部分包含了tgt里的信息，kdc以此校验tgt，正确则返回tgs票据。

PA_FOR_USER字段
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593424/1af91904-3ea6-f991-2bca-72a607e0a6dd.png)

类型是S4U2SELF，值是一个唯一的标识符，该标识符指示用户的身份。该唯一标识符由用户名和域名组成。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593424/a544d342-a8ed-c6de-a452-6591fdaff815.png)
S4U2proxy 必须扩展PA_FOR_USER结构，指定服务代表某个用户(图片里面是administrator)去请求针对服务自身的kerberos服务票据。

PA_PAC_OPTIONS字段
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593424/197e048f-009f-813d-d319-0728f09d078d.png)

类型是 PA_PAC_OPTIONS，值是以下flag的组合

1. Claims(0)
2. Branch Aware(1)
3. Forward to Full DC(2)
4. Resource-based Constrained Delegation (3)

微软的MS-SFU 2.2.5， S4U2proxy 必须扩展PA-PAC-OPTIONS结构。
如果是基于资源的约束委派，就需要指定Resource-based Constrained Delegation(RBCD)位。

req-body
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593424/c16f90e8-6994-e26c-2331-2792d6a978b0.png)

sname指要请求的服务名，tgs的票据是由该服务用户的hash加密的。如果该服务名为krbtgt，那么tgs的票据可以当tgt用。

AddtionTicket：附加票据，在S4U2proxy请求里面，既需要正常的TGT，也需要S4U2self阶段获取到的TGS，那么这个TGS就添加到AddtionTicket里面。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593424/24d527ec-3096-82f9-36df-cdeb5a9d5dd6.png)

# TGS_REP
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593424/7c70b0cf-36f6-6f11-04d6-61dd72228780.png)

ticket字段是tgs票据，用于下一步的AP_REQ认证。ticket中的enc_part是使用服务账户的hash加密的，如果有服务账户的hash，就可以自己签发一个给任意用户的tgs票据(白银票据)。

最后一个enc_part可以解密，其中的session_key用作下一阶段的认证密钥。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593424/440c529b-37d8-4ac8-74c7-942ec5907555.png)


挖坑，S4U2SELF、S4U2PROXY和委派暂时放后面说。(等我看懂)

# 参考
1. https://daiker.gitbook.io/windows-protocol/kerberos/2