OmniAICreator/Qiita-1.07M huggingface dataset:
SpringBoot + FirebaseAdminSDK で FirebaseAuthentication のIDトークンを検証する

## 手順

### Firebaseプロジェクトの暗号鍵を生成する

Firebaseのプロジェクト設定から、秘密鍵を生成する。
ボタン押下で、JSONファイルが出力されるのでそれを保持する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299475/b0825554-c3cf-c074-e487-50135759a02e.png)

### Java側のコード

※gradle or maven の設定は [ココ](https://firebase.google.com/docs/admin/setup#java) 

mainメソッド内で、FirebaseAppの宣言とかしてたりしてるけど、この辺の宣言する場所は良しなにすること。

```Java
@SpringBootApplication
@RestController
public class SpringbootApplication {

  public static void main(String[] args) throws IOException {

    FileInputStream serviceAccount = new FileInputStream("ダウンロードしたJSONファイルへのファイルパス");
    FirebaseOptions options = FirebaseOptions.builder()
        .setCredentials(GoogleCredentials.fromStream(serviceAccount))
        .build();
    FirebaseApp.initializeApp(options);

    SpringApplication.run(SpringbootApplication.class, args);
  }

  @GetMapping("/")
  public String hello() throws FirebaseAuthException {
    String idToken = "検証したいIDトークン";

    // エラー確認用のIDトークン ※よそ（example.com）で生成されたIDトークンが拒否されるの確認用
    // String idToken = "eyJraWQiOiIxZTlnZGs3IiwiYWxnIjoiUlMyNTYifQ.ewogImlzcyI6ICJodHRwOi8vc2VydmVyLmV4YW1wbGUuY29tIiwKICJzdWIiOiAiMjQ4Mjg5NzYxMDAxIiwKICJhdWQiOiAiczZCaGRSa3F0MyIsCiAibm9uY2UiOiAibi0wUzZfV3pBMk1qIiwKICJleHAiOiAxMzExMjgxOTcwLAogImlhdCI6IDEzMTEyODA5NzAsCiAibmFtZSI6ICJKYW5lIERvZSIsCiAiZ2l2ZW5fbmFtZSI6ICJKYW5lIiwKICJmYW1pbHlfbmFtZSI6ICJEb2UiLAogImdlbmRlciI6ICJmZW1hbGUiLAogImJpcnRoZGF0ZSI6ICIwMDAwLTEwLTMxIiwKICJlbWFpbCI6ICJqYW5lZG9lQGV4YW1wbGUuY29tIiwKICJwaWN0dXJlIjogImh0dHA6Ly9leGFtcGxlLmNvbS9qYW5lZG9lL21lLmpwZyIKfQ.rHQjEmBqn9Jre0OLykYNnspA10Qql2rvx4FsD00jwlB0Sym4NzpgvPKsDjn_wMkHxcp6CilPcoKrWHcipR2iAjzLvDNAReF97zoJqq880ZD1bwY82JDauCXELVR9O6_B0w3K-E7yM2macAAgNCUwtik6SjoSUZRcf-O5lygIyLENx882p6MtmwaL1hd6qn5RZOQ0TLrOYu0532g9Exxcm-ChymrB4xLykpDj3lUivJt63eEGGN6DH5K6o33TcxkIjNrCD4XB1CKKumZvCedgHHF3IAK4dVEDSUoGlH9z4pP_eWYNXvqQOjGs-rDaQzUHl6cQQWNiDpWOl_lxXjQEvQ";

    FirebaseToken decodedToken = FirebaseAuth.getInstance().verifyIdToken(idToken);

    return "Hello world!!!" + decodedToken.getUid();
  }
}
```
Webpack5を動かす記事

## はじめに
Webpackをちゃんと理解できたのでとりあえず動く「俺のタレ」を残しておく
ちゃんと理解したい人にはおすすめのUdemyのリンクを最下部に貼っておきます
ちなみにこの記事は学習した上で自分な理に必要な機能を取捨選択して組み直しまうのでご安心を!!書き方も変えてる
~~webppackの記事を書こうとしたら既に昔の自分が書いていた。死ぬほどわかりづらかった~~

~~この記事も仕事終わりのカフェでの勉強中にかいてる~~
殴り書き!! メモだから!!

##　手順と設定ファイルを書いていく

1. `npm init -y`
2. `npm i -D webpack webpack-cli html-loader css-loader mini-css-extract-plugin html-webpack-plugin clean-webpack-plugin webpack-dev-server sass sass-loader`
3. `mkdir src`
4. 起点のファイルで`css`をimportする
5. `touch webpack.config.js`

---
下記で、html,scss,js,画像の取り扱いに対応しています。
その際、htmlに直接cssや画像を記述するのではなく、`dist/`に綺麗に整頓された状態で出力されます
後述のbabelの設定も追加することで、`ES6`を古いブラウザで動くように変換できます。

```js
const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");

module.exports = {
  devtool: "source-map",
  entry: "./src/js/main.js",
  output: {
    path: path.resolve(__dirname, "./dist"),
    filename: "js/main.js",
  },
  module: {
    rules: [
      {
        test: /\.(css|scss|sass)$/,
        use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"],
      },
      {
        test: /\.html/,
        use: "html-loader",
      },
      {
        test: /\.(png|jpg)/,
        type: "asset/resource",
        generator: {
          filename: "img/[name][ext]",
        },
      },
    ],
  },
  plugins: [
    new MiniCssExtractPlugin({ // css
      filename: "./css/main.css",
    }),
    new HtmlWebpackPlugin({ // html
      template: "./src/templates/index.html",
      filename: "index.html",
    }),
    new CleanWebpackPlugin(),
  ],
};
```

## Babelの設定も追加

`npm i -D babel-loader @babel/core`
`npm i -D @babel/preset-env`
`touch babel.config.json`

```js:webpack-config.js
// rulesの一番上に追加
// ぶっちゃけrulesの中ならどこでも良い
{ 
  test: /\.js$/, 
  exclude: /node_modules/, 
  loader: "babel-loader" 
}       
```

```js:babel.config.json
// プロジェクトのルートに設定ファイル
{
  "presets": ["@babel/preset-env"]
}
```

## おすすめ教材
Webpackの情報って結構出回ってます。
わかりにくい情報を含めてね。　この記事みたいな!!笑

下記Udemyは本当におすすめです
webpack4での構築ですが、webpackの設定方法をわかりやすく学べるので、自分でwebpac5も組めちゃうと思います。私は組めました!!

個人的に講座の中の`pug`は使わなくて良い気がする。
それと公式に合わせてるのかrulesの書き方が長い!! 自分で配列でまとめてます。

https://www.udemy.com/course/webpack-config/
[javascript][python][php]デフォルト(オプション)引数

仕事で身に付けた技術や仕事以外で身に付けた知識を、自分用の備忘録として投稿していきたいと思います。

# 今日の内容
会社で先輩方にしていただいた、Vue.jsで書いたコードのフィードバックで、javascriptのデフォルト引数を使ったので、備忘録として残します。

# 使うことになったきっかけ
空配列を初期値とした変数が、なぜか`Undefined`になってしまっていて、どこで`Undefined`が入ってしまっているのかわからなかったので応急処置として使いました。
(はじめは、`if`分岐で`Undefined`が入っていたときの処理を書いていました。デフォルト引数を使うことで、ネストが減りました)

# 使い方
至ってシンプル。引数に続けて`=デフォルト値`を書くだけ。引数が未定義だったとき、デフォルト値が引数にセットされる。
~~~ javascript:sample_undefined.js
//引数が未定義
function sum(x=0, y=0, z=0){
  return x + y + z;
}

sum(); //0
~~~
~~~ javascript:sample.js
function sum(x=0, y=0, z=0){
  return x + y + z;
}

const x = 1;
const y = 1;
const z = 1;

//引数が定義されているのでデフォルト値はセットされない
sum(x,y,z); //3

//nullが代入されているときもデフォルト値は使われない
function message(mess = "Undefined"){
  return mess;
}

const mess = null;

//引数が定義されているのでデフォルト値はセットされない
message(mess); //null
~~~

公式ドキュメント:

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Functions/Default_parameters


# オプション関数が使える開発言語
javascriptだけでなく、PythonやPHP,C#にもオプション関数が存在する。

## Pythonでの書き方
~~~ python:sample.py
#引数が未定義
def Sum(x = 0, y = 0, z = 0):
    return x + y + z  #0
~~~

## PHPでの書き方
~~~ php:sample.php
//引数が未定義
function sum($x = 0, $y = 0, $z = 0){
    return $x + $y + $z;  //0
}
~~~
## C#での書き方
~~~ cs:sample.cs
//引数が未定義
static int Sum(int x = 0, int y = 0, int z = 0){
    return x + y + z; //0
}
~~~
チーム開発の時に頭の中をよぎったら危険なフレーズ3つ

チーム開発を経験させていただく機会があり、とても勉強になったので振り返りを兼ねて記事にしたいと思います。

この記事の対象者

- チーム開発をした事がないから、情報を集めたいと言う人
- 自分に自信があって、怖いものなどないという人
- やった方が良いことより、やってはいけない事を知りたいという人

# チーム開発の時に頭の中をよぎったら危険なフレーズ3つ

1. これで、伝わるだろう
1. みんな、忙しいんだな…
1. これ、大丈夫なのかな？

なぜ危険なのかというと、このフレーズは、全て自分の憶測で始まり、憶測で終わっているからです。

この記事では、「こうすれば上手くいく」という事は話せないですが、

「これはしない方がいい」という事はお話できると思います。

順に話していきます。


## 1.これで、伝わるだろう

この考えによって自分のケースで言うと、以下の失敗がありました。

- 相手が知っている前提で話をしていた。

- 正しく伝わっていないために、チームと自分の間に認識のズレが起きてしまった

実際のMTGでこんなくだりがありました。

自分『次のMTGは、火曜日の9時からでいいですかね？』

チーム『はい』

一見、問題ないように見えますが、この後実際に予定通りにMTGに来れた人は二人くらいでした。

原因は、認識にズレがあったからだと思います。

細かい事ですが、認識のズレを防ぐには誰がどう聞いても同じように捉えられる言葉選びが必要だと感じました。

自分は、火曜日の9時からと言いましたが、午前なのか？午後なのかを伝えるために「21時から」という表現を使うべきでした。チームでの活動は基本的に午後に行われていたので、伝わるだろうと考えていましたが、この「憶測で捉えたままで済ます意識」が他の部分まで及んでしまったのだと思います。

憶測で進めないために必要なことは、多くありますが、ひとつ徹底するならば、

**口頭やチャットでの指示はメモなど記録に取り、まとめて相手に確認をする**

これで余計な言葉を乗せず、指示のみを伝える事ができ、互いに認識のズレが起きる事を防ぐことができます。

この考えは@yutangcさんがコメントで共有してくださいました！

以下は自分の考えです。

- 議事録とは別にチャットで目に付く部分に固定し、メンバーからスタンプなどで反応をもらう

- 自分が話した後に伝えたい部分について伝わったかどうかを確認する

- 誰が見ても聞いても、同じように捉えられる言葉を、表現を選ぶ。

1については以上です。

## 　2.みんな忙しいんだな…

この考えによって、自分のケースで言うと以下の失敗がありました。

- わからない事があった時、申し訳なさを感じてチームに共有ができない

- 「忙しい」ということを重く捉えすぎて、忙しめにスケジュールを組んでしまった

自分の話になるのですが、エラーが出てしまった場合に、そのエラーを解決するために必要な時間を多く見積もる傾向があり、その度に絶望していました。

が、よく考えると一人で立ち向かうのと複数で立ち向かうのでは解決をするのにかかる時間は２、３倍以上に変わってくると思います。

実際に自分が一日かけても解決できなかったエラーをチームに相談したら10分で解決した。と言う事がありました。

もう何倍かも分からないですね…。サラッと解決しすぎて、嬉しさと悔しさその他諸々が混ざり合って複雑な気持ちになったのを覚えています。

また、たいていのエラーは重なって発生します。一つ解決できても、1分後には、またエラーにぶつかります。

２、３回程度の重なりならば、まだ人に聞けると思いますが、４、５回のエラーが重なると相手に申し訳なさを感じてしまったり、聞くときに「すぐ聞くやつ」と思われるのが怖くなるかもしれません。

しかしよく考えると、分からない事が多い初心者の頃こそ、障壁の数が多くなると思います。

ただでさえ、「足手まといになるかもしれない…」と内心に不安を抱えやすい時期なのに障壁に障壁が重なるので、質問をする習慣がない人は質問をする習慣がある人の何倍も苦労をすると思います。

一人で学習をしてきた期間が長い人ほど、「質問をしよう」と頭を切り替えるのにかかる時間が必要になってしまうかもしれません。そして、質問をする必要がある障壁の数が何回も重なると『流石にもう聞けない…』と言う状態になる時が来ると思います。

そんなあなたに向けて、私たちのチームを見守ってくださった方から頂いた言葉があるので、これだけでも持って帰って欲しいです。それは…

**「分かる人に聞け」**

当たり前すぎる事かもしれませんが、普段から実施していないと、いざ自分が問題に直面した時に実施できません。自分はこの言葉がとても身に染みたので、この記事を見てくださった方にはこの言葉が身に染みる前に『質問する事』を習慣づけて、この言葉を実施してほしいです。

2については以上です。

## 3.これ、大丈夫なのかな？

これは、疑問点、不明点、心配な点を見つけた時に頭の中をよぎるフレーズです。

MTGでは楽しい、柔らかい雰囲気で話が進んでいる時に話の途中で「ん？」と感じる事があるかもしれません。

この考えによる自分の失敗は、その場の雰囲気を壊すようで悪い気がし、確認をすることを遠慮してしまったことです。

しかし、チームで共通の認識を持つ事は柔軟に活動する上で重要で、その「チーム」の中には自分も入っているので確認してもいいんです。

自分達のチーム開発を見守ってくださった方がいて、その方はとても鋭くてハッとする指摘をくださりました。

一瞬時が止まったような沈黙が流れる事もありましたが、その後チームでの話し合いも活発になっていたので、少し確認を取った所で雰囲気が悪くなる事は無いと自分は学べました。

3.については以上です。

# まとめ

チーム開発に参加できる機会があった際には…

『伝わっただろう』と憶測で判断せず、
チームで認識のズレが起きないよう伝えたい事が伝わったかを相手に確認する。

『忙しそうだな…』と聞く前から奥手にならず、自分が困っていることは、ハッキリと伝える。
↓
「分かる人に聞く」思考に切り替えるために、普段から質問を習慣づける

『これ、大丈夫かな…』と少しでも気になった事や思いついた事は憶測のまま終わらせずに、チームに話してみる。

当たり前のことかもしれませんが、これら3つのフレーズから学べる事を最後にまとめると

**「憶測で行動を制限してはいけない」**

になると思います。

何か考える時に、自分が憶測で考えていることに気付けるだけでもその後の行動は変わると思います。

皆様が何か壁にぶつかった時、この記事が分岐点に気付けるきっかけになれば幸いです。

追記
よろしければ、ご自身の体験や学び等どんな事でもコメントで残していただけると自分含め、これからチーム開発をしていく人のためになって、とてもありがたいです！
Laravel の view で使う Carbon のサンプル

View で Carbon で created_at からレコード作成日の日付を日本語にして出したいなー
という単純な要望を検索したら以外に手間取ったので初投稿

```
{{\Carbon\Carbon::parse($model->created_at)->format("Y年m月d日")}}
```

あと日付フォーマット
|文字|説明|
|:--|:--|
|Y|年 ４桁 西暦|
|m|月 ２桁 ０埋め|
|d|日 ２桁 ０埋め|
|h|時 ２桁 ０埋め　１２時間単位|
|H|時 ２桁 ０埋め　２４時間単位|
|i|分 ２桁 ０埋め|

参考

https://www.php.net/manual/ja/function.date.php

https://qiita.com/yudsuzuk/items/ff894bd0b76d4657741d
Nginxで特定のIPアドレスをブロックする方法


# はじめに

DoS攻撃への暫定対応として、大量アクセスのあった送信元の特定IPアドレスだけをブロックしたい場合があるかと思います。

本番稼働中にWebサーバに以下のような手順で修正を加えることで、簡易的なブラックリストを実装することができます。備忘がてら残します。



# 手順
## 1.ブラックリストファイルを作成
```sh
$ cd /etc/nginx

# nginx-ip-restrictions.confを作成
$ touch nginx-ip-restiction.conf
```

## 2.ブラックリストに追加
```conf:/etc/nginx/nginx-ip-restrictions.conf;
deny XX.XXX.XX.XX; # IPアドレスに関するコメント
```

## 3.`nginx/conf.d`に読み込ませる
```conf:/etc/nginx/conf.d
include /etc/nginx/nginx-ip-restrictions.conf;
```


## 4.変更の反映
```sh
# 構文エラーがないか確認
$ nginx -t 

#　現在のプロセスを確認
$ ps -aux | grep nginx

# nginx再起動
$ systemctl restart nginx

# プロセスが変わっていることを確認
$ ps -aux | grep nginx
```

## 5.運用
怪しいIPアドレスが来たら`deny`にポコポコ追加していくだけ！

```conf:/etc/nginx/nginx-ip-restrictions.conf;
deny XX.XXX.XX.XX; 
deny YY.YYY.YY.YY; 
```

# 参考
https://codenote.net/nginx/4088.html#:~:text=%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9%E3%81%A7%E3%81%97%E3%81%9F%E3%80%82-,Nginx%20IP%20%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9%20deny%20%E8%A8%AD%E5%AE%9A,%E3%82%92%E8%BF%BD%E8%A8%98%E3%81%99%E3%82%8B%E3%81%A0%E3%81%91%E3%81%A7%E3%81%99%E3%80%82
既存のAndroidアプリに組み込んだFlutterをデバッグする

# Flutterを既存アプリに組み込む

Flutter最大の魅力はマルチプラットフォーム対応です！とは言え、既存のアプリを一度に丸ごとFlutterで書き換えるのは現実的ではなく、部分的にFlutter実装の画面で置き換えていく場合が多いかと思います。詳細は公式 Docsが非常に参考になるので一度は読んでおきましょう。

https://docs.flutter.dev/development/add-to-app

# 組み込まれたFlutterのデバッグ
当然、開発中はデバッグ作業が発生しますが、Androidネイティブに組み込まれたFlutterにattachしてデバッグする方法を簡単にまとめておきます。

- Android Studio Chipmunk | 2021.2.1 Patch 1
- Flutter 2.10.4

### 0. プラグインの用意
AndroidStudioにFlutterプラグインをあらかじめインストールしておきましょう
![スクリーンショット 2022-07-04 18.13.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440643/b3d5ad2e-15d7-0f17-bede-26c374ac9b5c.png)



### 1. Android: デバッグ開始

Flutterを組み込んだAndroidプロジェクト側でデバッグを開始します。
![スクリーンショット 2022-07-04 18.04.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440643/80520ea0-c19f-8781-165c-c4b0e462c397.png)


### 2. Flutter: Attach＆デバッグ開始
組み込んだFlutterパッケージを別のAndroidStudioウィンドウで開いたら、右上のボタンからAndroidアプリにAttachします。

![スクリーンショット 2022-07-04 18.08.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440643/7a9ff17b-d57b-27be-7d21-5d2efed4d635.png)

しばらく待ちましょう。ここでよく失敗するので何回か試してみましょう。接続されたか判別つきづらいですが、下の画像のようになればOK

![スクリーンショット 2022-07-04 17.28.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440643/d58469a2-7c82-e803-42cb-4f9a979dfd5b.png)

あとはブレイクポイント設定して普通にデバッグします。Flutter側のコードでもちゃんとブレイクします。

![スクリーンショット 2022-07-04 17.33.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440643/052d136c-d39a-6b32-545e-aecf351737bf.png)

もちろん Hot Reload, Restartも可能です！
![スクリーンショット 2022-07-04 18.54.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440643/ae0c8f97-7579-8a1d-f9fc-25fd1cc7f1be.png)

よきFlutter開発ライフを！
40代プログラミング初心者のエラー箇所の見つけ方

40代からpythonの勉強を始めた初心者です。

プログラムコードを書くよりもエラーコードを調べている時間がほとんどという悲しさ

最初の頃はサンプルコードを入力してるだけでも動かないというポンコツさ

どこが悪いのか。。。そんな感じで途方に暮れる初心者の方は多いかと思います。

そんなわけで私がやっている方法

<h2>printをたくさん使ってどこまで動いたか確認

頭のいい人ならきっともっといい方法があるのかもしれませんが、私は独学で誰かに聞ける環境ではない。そのため愚直に処理の間にprint文を入れまくってます

print("ここから")
処理1
print("1個め")
処理2
print("2個め")
処理3
みたいな感じでとにかくどこでエラーを吐いているか確認します。

エラーメッセージにLine 11とか行数書いてあるけどね。

でもどこまで正しく動いているか確認するのにprintで確認すると簡単なんですよ

<h3>変数に何が入っているかもprintで確認

変数に思ったものが入っているか、変なものが入っているかもしれない。っこう言うチェックも大事ですよね。

<h2>正しく動く場所を絞り込んで除外していくこと大事

とにかくprintで正しく動く部分を確認していき、どんどんエラーの部分を除外していくことって大事だなと思います。

特に変数に間違ったものが入ってしまっていると、動作はしちゃうので簡単には見つからなくてドツボにはまることも多いです

私は自分に自信がないので数行書いて、実行してエラーが有るかどうか確認して次に進むという感じでやっています。

よし動いた～完成した～！！って思っても、あれ？思ったものと違う・・・

っていう動くけど、そうじゃない！って感じなので

細かくprintでどこまでが正しいか確認するのって大事だなと思います

そんなめんどくさいことやってるの？って思うかもしれませんが、今のところ私にとってはこれがエラーとかうまくいかないときになんとか解決できる方法です。

もちろん、エラーメッセージは読んでいて、それで理解できる部分は対応できるようになっています。

エラーメッセージを吐かない、動作しちゃう系は本と悩む・・・

地味に、以上以下の指定が、より多い、未満とかになってたり、<のむきが逆になってたりするとかも。。。

職業プログラマーさんはタイプミスなく本当にすごいなと思います

もっとこうしたら、エラー対処に強くなれるよってあったら教えてください
Oracle Analytics Cloud 「センチメントの分析」機能を使ってみる。

センチメントの分析は、SNSの記事や、アンケート結果などの自然言語で書かれたデータを分析用に分類してくれる便利な機能です。

Oracle Analytics Cloudには、「センチメントの分析」機能があって、データの前処理を行う「データーフロー」から利用する事が可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728962/92deddae-9f42-f436-713a-26f621de7f71.png)

この例は実際にOACデータフローから生成したデータです。
データのReview欄のデータを解読して、「Positive」「Neutral」「Negative」の情報を生成して、emotion列に分類しています。

※ちなみに、この機能はまだ日本語に対応していませんので、英語データを使いました。

この機能の使い方は簡単です。
#  1.Excelでデータを準備して、データセットとして登録します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728962/fe0f57f8-ca6c-020b-14cc-04900aeb5d28.png)
※今回はシンプルなExcelデータを準備して、Drag&Dropし、データセットを作成しました。

# 2.新規に「データフロー」を作成して、いま登録したデータセットを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728962/a1180607-5b42-817a-88ee-7c547d479f0a.png)
※登録したデータの中身が、下段にプレビュー表示されています。

# 3.「センチメントの分析」をフローに追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728962/dbde7d60-63f1-180a-4449-d2110da61177.png)
※「Positive」「Negative」の判定は、新規に追加された「emotion」列に出力されます。

# 4.センチメントの分析対象となる列を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728962/c1f16a91-5009-5774-c763-0cc6cf2102e4.png)
今回は文字列が入っているReview列を選択します。

# 5.「データセットの保存」機能を追加する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728962/0d8b88d4-9ff8-ea44-d2fb-4469aec3cb0f.png)
まだデータフローを実行していませんが、プレビューされて、emotion列にどのような判定データ生成されるかを確認することができます。

後は、データフローを「実行」し、生成されたデータセットを使って分析を行う流れになります。

ちなみに、日本語対応してないことはわかっているのですが、試しに日本語データを使ってみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728962/afa1aa66-4374-5812-b7db-a01ffaf29026.png)
残念ながら、日本語は処理できないので、すべて「Neutral」の判定になってしまいました。

現段階では、日本語を含むデータを処理したい場合は、REST APIをつかってGoogle翻訳などの翻訳エンジンで、いったん英語データを自動生成してから「センチメントの分析」を行う方法をとるしかなさそうです。
Oracle Analytics Cloud 地図情報をつかったデータ表示

Oracle Analytics Cloudは、簡単に地図上にデータを配置する「Map」機能があります。

前回、「予測」機能の説明のために、OACに米国国立地震情報センターの地震データを取り込んだので、さらにこのデータを使ってデータを地図上に可視化してみたいと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728962/e62c7146-365f-6720-8c66-7ef172283750.png)

Kaggleから取得した米国国立地震情報センターの地震データには、緯度(latitude)経度(longitude)の項目がありますので、地図上に数値データのマグニチュードをに配置することが出来ます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728962/fb0ddcac-11a3-b5b0-00b8-c26907b4c831.png)

(1)ビジュアライゼーションの表示タイプを「マップ」にします。
(2)カテゴリ(場所)に「longitude」「latitude」の項目を配置します。
(3)色にDepth(震源の深さ)を配置します。
　 色に、数値データを配置すると色の濃さで数値の大きさを表現します。
(4)サイズにMagnitudeを配置します。
　 地図上に表現する数値データを、領域の大きさで表現します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728962/f8aeef98-6805-3afb-3921-06180441ef80.png)

背景地図は、「OracleBI」「OracleMap」「OracleStreetMap」の3種類から選択可能です。
・OracleBI：都市名などの表記が無いフラットな地図　シンプルに表現できます。
・OracleMap：平地、山岳が綺麗に表現されているが、都市名が英語表記である。
・OracleStreetMap：都市名の表記が日本語で、国内で使うにはこれが適していると思われます。

その他、GoogleマップやBaiduマップなど、利用可能なWebマップ・サービス(WMS)プロバイダのリストから背景地図を設定することも可能です。
Oracle Analytics Cloud 「予測」機能の「ARIMA」について

Oracle Analytics Cloudには、マウスクリックだけで予測(forcast)を表示する便利な機能があります。
今回は、Kaggleに登録されている米国国立地震情報センターの地震データを使って地震の予測を行います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728962/bf2ef4fe-f05d-f71f-34a8-c21d00bb72fb.png)
折れ線グラフの2016年までは実データで表示されており、2016年以降のグレーになっているデータが予測生成されたデータになります。

予測を表示するのは簡単で、グラフ上で右クリックして「統計の追加」から「予測」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728962/1ee42c87-b03f-5d0c-b84d-8013739ee8e4.png)

左下のプロパティを確認すると、予測モデルとして「季節性ARIMA」が使われていることが確認できます。
「季節性ARIMA」は、一般的にはSARIMAと呼ばれます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728962/45f64168-48e7-0693-bb6c-4fa5031ede5d.png)

ARIMAは、「AR」「I」「MA」を合わせた分析モデルの事です。
AR：AutoRegression　自己回帰
I：Integration ARとMAを結合する
MA：Moving Average 移動平均

ARは、時系列の前後の数値の違いを「変化」ととらえます。
つまり、現在の値と過去の値とは相関しているととらえて、過去の値に係数を掛けることによって将来を予測しようとします。

MAは、時系列の前後の数値の違いを「エラー」としてとらえます。
つまり、MAは過去の値を使用してその将来を予測するのではなく、過去の予測の誤差を 予測値のインパルスとして使用します。

ARとMAを統合したARIMAモデルは、単変量の時系列予測モデルで、過去に観測されたデータの変化に基づいて予測を行い、予測するデータ(ターゲット変数)以外のデータを使用しないため扱いやすく、Pythonで予測プログラムを書く場合にもよく使われるモデルです。

今回の例で言えば、過去の地震発生回数を使って、将来の地震発生回数を予測することになります。

話はそれますが、地学、地震学の学問の観点から見れば、これではナンセンスで「科学の欠如」と言われるかもしれません。

ほんらい地震の発生回数は、気候や気圧変動など、「そのほかの観測データ」が関与しています。ここで言う「そのほかのデータ」を、分析では外部変数(X)と言います。

外部のデータをさらに取り込んで時系列モデル予測を行う場合は、SARIMAXモデルを使います。
SARIMAXの最後のXは「外部変数X」のことで、このような予測分析は「多変量時系列モデルの予測」と呼ばれます。
OACで「多変量時系列モデルの予測」を行う場合は、データフローを使うことになりますので、データ準備が少々複雑になってしまいます。
OACの「単変量の時系列予測」は、マウスクリックだけで予測できるので、まずはここから始めるのがよいでしょう。
Oracle Analytics Cloudで簡単に分析画面を作る方法


Oracle Analytics Cloudに、バージョン6.4(2022年1月)からAuto Insights機能が追加されました。そして現在のバージョン6.5(2022年3月)のバージョンでは、正式に日本語対応され、分析に利用するデータだけでなく、表の名称、項目の名称にも日本語の利用が可能です。

Oracle Analytics CloudのAuto Insights機能により、自動生成された表、グラフなどのビジュアライゼーションをDrag&Dropするだけで、視覚的な分析画面が生成できますので、従来のように分析者が、データソースを解析し、白紙の画面からビジュアライゼーションを作成する必要が無くなりました。

それでは、自動的に生成された分析画面を見てみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728962/103dfa29-ab2c-2e7e-72bf-045ec8c156bf.png)

すごいですね！
ちなみに、ハンズオンセミナーで使っているデータからAutoInsightsをかけて画面生成したのですが、セミナーの内容がほとんど出来てます。

ちなみにこの機能がない時は、左データソース表の項目を選んで、表示形式(棒グラフにするか、円グラフにするかなど)を考えて、いちから分析画面を作成する必要がありました。

PowerPointで資料を作る時などでも、誰かが作成した既存資料に追加変更かけていく方が効率的に資料作成できるますね。
AutoInsightsは、OACが自動生成してくれた分析画面に手を加えて、軸の変更や項目追加して、目的の分析を作っていく方法です。分析業務がはかどるとても良い機能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728962/83f8e125-c896-3a43-1011-c5c780d8818e.png)


分析画面を自動生成してくれる事について便利だと述べてきましたが、私がもっとも便利だと感じているのは、分析に必要な計算項目も自動生成してくれるところです。

従来は「マイ計算」を新規作成して、関数やデータ項目を選択して、計算項目を作成していましたが、AutoInsightsは、これも自動生成してくれます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728962/2f916775-8aba-0d2c-8bcb-d3fa22b12da8.png)

分析者の表現したい画面イメージを選択して配置すれば、マイ計算が表示されますので、「計算の編集」で、どんな関数をどのように使っているかを確認し、分析に必要になる式にアレンジする使い方が良いでしょう。
【ARKit】赤ちゃんの身長計測の技術

## はじめに
株式会社マイスター・ギルド新規事業部のヒツジーです。
弊社新規事業部では、新規サービスの立ち上げを目指して
日々、アイディアの検証やプロトタイプの作成などを行っています！

が！今回は自社開発した赤ちゃんの身長計測ができるiOSアプリ [BabyScale](https://www.m-gild.com/app/babyscale/) の裏側についてお話します！（こういうのもいいでしょう）
スマホ一つで簡単に身長計測できちゃうんですが、その原理って気になりませんか？
惜しみなく公開しちゃいます！

## 身長計測アプリの概要
下のスクショのように、寝ている赤ちゃんをカメラで撮影して、点を打つだけで身長計測が完了する優れものです！
では、この計測はどんな原理なのかを以降で紹介します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556658/9d734100-a36c-e4b3-73b9-02f9faf0f999.png)

## 身長計測の概要
身長計測には、
Appleが提供するiOS向けARライブラリ [ARKit](https://developer.apple.com/jp/augmented-reality/arkit/)の平面検出の技術を利用しています。

流れは至ってシンプルです。

1. 平面を検出
2. 平面上に点を複数打つ
3. 点と点の間の距離を算出し、合計する

下の写真のように、UI上は赤ちゃんに対して点を打っているように見えますが、
**実は赤ちゃんを認識しているわけではありません。**
**平面を検出し、平面上に点を打っているだけです。**
（開発中は平面も表示させてましたが、リリース時に非表示にしています。）
<img width="300" alt="baby" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556658/ac4dff75-d654-c8e7-2d3d-27c839f08760.png">

図にすると下のようなイメージです。
![スクリーンショット 2022-07-04 18.22.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556658/45162a51-958b-1e45-c2ac-549ba7d5444c.png)

二本足で立てる赤ちゃんは身長計測がある程度簡単だけど、寝ている赤ちゃんは身長計測しにくいよね。
このアプリは寝ている赤ちゃんの計測に集中すべき。
という考えのもと、水平面だけの検出だけでいいよねということで、水平面しか検出できないように制限しています。
ARKitとしては水平面と垂直面の両方を検出できます。

## 長さの計算
> 点と点の間の距離を算出し、合計する

と上で書きましたが、具体的にどういうことかを説明します。

平面上の点の座標は、ワールド座標と呼ばれる座標情報$(x,y,z)$として取得可能です。
要するに３次元の座標情報です。

例えば、点A$(x_a, y_a, z_a)$と点B$(x_b, y_b, z_b)$の二点間の距離$L$は以下の式で簡単に計算できます。
$$L = \sqrt{(x_b - x_a)^2 +(y_b - y_a)^2 +(z_b -z _a)^2 }$$

これで、各点各点の間の距離を求めて、足し合わせるだけで身長計測は完了するというわけです。

ちなみに**ARKitにおけるワールド座標の原点がどこか**気になると思いますが、
ヒツジー調べでは**ARSessionが起動したときのカメラの位置**にあたります。
（printでめっちゃ座標出力して調べた）
※間違ってたらコメントで教えてください。

## 最後に
結局、ARKitすごい！Appleすごい！ってところに落ち着く話になるんですが、
上に書いたような方法で赤ちゃんの身長を簡単に計測できるようになりました。

余談ですが、
iPhone12Pro以上からiOSのデフォルトアプリ「計測」で[人の身長計測](https://support.apple.com/ja-jp/guide/iphone/iph341d4a993/ios)が**スマホをかざすだけ**でできるようになりました。
この技術の詳細は公開されてないみたいなので、この技術を赤ちゃんに適用するのは現状難しそうですが、将来的にはできるようになるかもしれませんね。できたらいいですね。
変更セットリリース時の「Lightning ページの関連付けられたオブジェクトは変更できません。」というエラーの解消方法

変更セットを使ってカスタムオブジェクトをリリースしようとしたときに遭遇したエラー。

カスタムオブジェクトのリリース時はLightningページもセットで変更セットに含めなきゃいけないのはなんとなく覚えていたので、変更セットに追加してリリースすると以下のようなエラーが。

![2022-07-04_18h09_20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228212/49291083-4366-cb0e-290a-9b93d243745e.png)
(ググっても「Lightning ページの関連付けられたオブジェクトは変更できません。」では全然引っかからなかったので、エラー文を英語にしようと英語環境になってます)


原因としては、リリースしようとしてるLightningページのAPI名がすでに本番環境に存在していたというシンプルなもの。(Sandbox作成後に別のカスタムオブジェクトが本番環境でリリースされていた → LightningページのAPI名は連番で自動生成されるため名称がかぶった)

解消方法はリリースしたいカスタムオブジェクトのページから右上のギアマーク → 編集ページ → API 参照名 を変更するのみ。
![2022-07-04_18h21_45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228212/4682bfa9-64eb-3c63-34f7-e531ab2b5a8d.png)


Sandboxの更新の狭間でカスタムオブジェクトがリリースされるケースってあんまりないかもしれないけど前も詰まった気がするので忘備録として残しておく。

(Lightningページって気づいたら量産されてるの謎。ちょっと整理しないとなと161という連番を見て思うなど)
FIDを改善するためにサードパーティ製のコードを遅延読み込み

## はじめに
SEO対策としてCoreWebVitalの改善をするためにPageSpeedInsightやlighthouseで調査していると、JavaScriptの削減を提案されることがある。
サードパーティ製のスクリプトを使用しており、削減できなかったので遅延読み込みで対応してみた。

## Youtubeを遅延読み込み
今回は [lazysizes](https://github.com/aFarkas/lazysizes) を使用して、[Youtube Iframe API](https://developers.google.com/youtube/iframe_api_reference?hl=ja) のリクエストを遅延読み込みする。
具体的には、lazysizesがlazybeforeunveilイベントを発火するので、これを受け取ったらYoutubeIframeAPIにリクエストを送り、指定したidのdivタグをyoutubeの埋め込みiframeタグに変換する。

```html
<html>
  <head>
...
    <script src="lazysizes.min.js" async></script>
...
  </head>

  <body>
...
    <div class="lazyload">
        <div id="player1"></div>
    </div>

    <div class="lazyload">
        <div id="player2"></div>
    </div>
...

    <footer>
...
        <script>
            var ytData = [
                {div_id:"player1", video_id:"hogehoge"},
                {div_id:"player2", video_id:"fugafuga"}
            ];
            var ytPlayer = [];
            var player;
            var ytEvent = {
                "onReady": function (event) {
                    ytPlayer[ytPlayer.length] = event.target
                }
            };

            var tag = document.createElement('script');
            tag.src = "https://www.youtube.com/iframe_api";
            var firstScriptTag = document.getElementsByTagName('script')[0];
            firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

            function onYouTubeIframeAPIReadyLazyLoad(div_id) {
                var data = ytData.filter(function(value) {
                    return value.div_id == div_id;
                });

                player = new YT.Player(data[0]['div_id'], {
                    height: 360,
                    width: 100%,
                    videoId: data[0]['video_id'],
                    events: ytEvent,
                    playerVars: {
                        loop: 10,
                        rel: 0,
                        playsinline: 1,
                        controls: 0,
                        showinfo: 0,
                        playlist: data[0]['video_id'],
                        origin: location.protocol + '//' + location.hostname + "/"
                    }
                }); 
            }

            document.addEventListener("lazybeforeunveil", function(e) {
                    var childElementId = e.target.firstElementChild.id;
                    onYouTubeIframeAPIReadyLazyLoad(childElementId)
            })
        </script>
...
    </footer>
  </body>
</html>
```

## 結果
変更前後をLighthouseで計測。
TBTが **280ms → 80ms** (FIDはLighthouseで計測できないため、TBTで代用)、
Speed Indexが **3.8s → 1.8s** に改善した。

lazyloadは画像のみ適応できると思い込んでいたので、使い所によってはもっと改善できそう。
SpringBootでWebAPI開発

# はじめに
妻がSpringBootを触ってみたいとのことなので、
環境構築からやること・必要なことなどをまとめておく。

# 前提

|キーワード|中身|
|:--|:--|
|PC|Mac book pro(Intel 2016)|
|OS|macOS Monterey 12.4|
|IDE|IntelliJ IDEA Community Edition , VS Code|
|JDK|temurin-17.0.3|
|Build Tool|Gradle|
|Docker|Docker Desktop for Mac|
|version管理|Github & Sourcetree|
|API Client|Postman|

# 学ぶこと

|キーワード|中身|
|:--|:--|
|[Spring Initializr](https://start.spring.io)|Springのライブラリの選択について|
|Java|Java17までに追加された構文|
|Gradle|ビルドツール|
|Docker|起動方法とか|

# 環境構築 - Install - 

1. OSを最新化する
1. [JetBrains](https://www.jetbrains.com/ja-jp/idea/download/#section=mac) より `IntelliJ IDEA Community Edition` をインストール
1. [VS Code](https://azure.microsoft.com/ja-jp/products/visual-studio-code/) をインストール
1. [Postman](https://www.postman.com/downloads/?utm_source=postman-home) をインストール
1. [Docker Desktop for Mac](https://docs.docker.com/desktop/mac/install/) をインストール
1. [Docker Hub](https://hub.docker.com/signup)でアカウントを作成する
1. Githubでアカウントを作成する
1. [Sourcetree](https://www.sourcetreeapp.com) をインストール
1. `Sourcetree` でGithubのアカウントと連携する

# 環境構築 - Create Project - 

## Create Github Repository

1. Githubでリポジトリを作成する
1. 作成したリポジトリのデフォルトブランチを切り替え & 保護
  Settings -> Braches -> Default branch -> developへ
1. 作成したリポジトリを `Sourcetree` を使ってローカルに clone
  `$ git clone https://github.com/{user_id}/{repository_name}.git`
1. Githubで issue を起票
1. 起票した issue から `create branch`
1. Sourcetree で作成した branch に切り替える
  `$ git checkout {branch_name}`

## Create Java Project

1. IntelliJ IDEA でローカルのリポジトリを取り込む
1. [Spring Initializr](https://start.spring.io) より、Javaプロジェクトを作成し、zipファイルをダウンロード
  dependency に、以下を指定  
  ・Lombok  
  ・Spring Web  
  ・SpringData JPA 
  ・MySQL Driver
  ・Spring Boot Actuator 
1. ダウンロードしたzipファイルを解凍する
1. IntelliJ IDEA で解凍したファイルを取り込む
1. IntelliJ IDEA でSDKの設定で `Eclipse Temurin` をダウンロードし、 `temurin-17.0.3` という名前でインストールする
1. 一度 Gradleのメニューより BootRun(Tasks->application->bootRun) し、起動を確認する

## Merge

1. Sourcetree でファイルを commit & push する
1. Githubで Pull Request を作成する
1. 作成した Pull Request から develop に merge する  
 作成した branch を delete する

# 環境構築 - Docker -

1. Githubで issue を起票
1. 起票した issue から `create branch`
1. Sourcetree で作成した branch に切り替える
1. `docker-compose.yml` を作成する
  `$ mkdir docker`
  `$ vi ./docker/docker-compose.yml`
1. docker-compose.yml に `mysql` , `phpmyadmin` のイメージを指定する
1. 起動確認
  `$ docker-compose -f ./docker/docker-compose.yml up --build --remove-orphans` で起動する
1. 起動確認後、コマンドを `README.md` か issue に記載する
1. Sourcetree でファイルを commit & push する
1. Githubで Pull Request を作成する
1. 作成した Pull Request から develop に merge する  
 作成した branch を delete する

# 製造

1. phpmyadmin より `create database`
  例) `$ create database sample;`
1. `application.yml` に mysql の設定を追記する
  例) `spring.datasource.url=jdbc:mysql://localhost:3306/sample`
1. phpmyadmin より `create table`
  例) `$ create table sample.hoge;`
1. 作ったテーブルに対応する `@Entity` がついた class を作成する
1. Entity を操作する Repository を extends した interface を作成する
1. Controller から上記 Repository を操作し、jsonを返却してみる
1. Postman で動作確認を行う

# ふりかえり  

WIP
Pythonの標準ライブラリ一覧

| \_\_future__      | \_\_main__    | _thread   | abc        | aifc         | argparse     | array      |
|:----------------|:------------|:----------|:-----------|:-------------|:-------------|:-----------|
| ast             | asynchat    | asyncio   | asyncore   | atexit       | audioop      | base64     |
| bdb             | binascii    | binhex    | bisect     | builtins     | bz2          | calendar   |
| cgi             | cgitb       | chunk     | cmath      | cmd          | code         | codecs     |
| codeop          | collections | colorsys  | compileall | concurrent   | configparser | contextlib |
| contextvars     | copy        | copyreg   | crypt      | csv          | ctypes       | curses     |
| dataclasses     | datetime    | dbm       | decimal    | difflib      | dis          | distutils  |
| doctest         | email       | ensurepip | enum       | errno        | faulthandler | fcntl      |
| filecmp         | fileinput   | fnmatch   | fractions  | ftplib       | functools    | gc         |
| getopt          | getpass     | gettext   | glob       | graphlib     | grp          | gzip       |
| hashlib         | heapq       | hmac      | html       | http         | imaplib      | imghdr     |
| imp             | importlib   | inspect   | io         | ipaddress    | itertools    | json       |
| keyword         | linecache   | locale    | logging    | lzma         | mailbox      | mailcap    |
| marshal         | math        | mimetypes | mmap       | modulefinder | msilib       | msvcrt     |
| multiprocessing | netrc       | nis       | nntplib    | numbers      | operator     | optparse   |
| os              | ossaudiodev | pathlib   | pdb        | pickle       | pickletools  | pipes      |
| pkgutil         | platform    | plistlib  | poplib     | posix        | pprint       | pty        |
| pwd             | py_compile  | pyclbr    | pydoc      | queue        | quopri       | random     |
| re              | readline    | reprlib   | resource   | rlcompleter  | runpy        | sched      |
| secrets         | select      | selectors | shelve     | shlex        | shutil       | signal     |
| site            | smtpd       | smtplib   | sndhdr     | socket       | socketserver | spwd       |
| sqlite3         | ssl         | stat      | statistics | string       | stringprep   | struct     |
| subprocess      | sunau       | symtable  | sys        | sysconfig    | syslog       | tabnanny   |
| tarfile         | telnetlib   | tempfile  | termios    | test         | textwrap     | threading  |
| time            | timeit      | tkinter   | token      | tokenize     | trace        | traceback  |
| tracemalloc     | tty         | turtle    | types      | typing       | unicodedata  | unittest   |
| urllib          | uu          | uuid      | venv       | warnings     | wave         | weakref    |
| webbrowser      | winreg      | winsound  | wsgiref    | xdrlib       | xml          | xmlrpc     |
| zipapp          | zipfile     | zipimport | zlib       | zoneinfo     |              |            |

[Python 標準ライブラリ](https://docs.python.org/ja/3/library/)のPython 3.10.4時点より
bash設定ファイル

```sh:bash_profile
# default:cyan / root:red
if [ $UID -eq 0 ]; then
    PS1="\[\033[31m\]\u@\h\[\033[00m\]:\[\033[01m\]\w\[\033[00m\]\\$ "
else
    PS1="\[\033[36m\]\u@\h\[\033[00m\]:\[\033[01m\]\w\[\033[00m\]\\$ "
fi

# "-F":ディレクトリに"/"を表示 / "-G"でディレクトリを色表示
alias ls='ls -FG'
alias ll='ls -alFG'

#ブランチ名表示
source /usr/local/etc/bash_completion.d/git-prompt.sh
source /usr/local/etc/bash_completion.d/git-completion.bash
GIT_PS1_SHOWDIRTYSTATE=true
#export PS1='\[\033[00m\]\u@\h\[\033[00m\]:\[\033[00m\]\w\[\033[33m\]$(__git_ps1)\[\033[00m\]\n\$ '
#export PS1='\[\033[00m\]\u@\h\[\033[00m\]:\[\033[00m\]\w\[\033[33m\]$(__git_ps1)\[\033[00m\] \$ '
export PS1='\[\033[00m\]\u@\A\[\033[00m\]:\[\033[00m\]\w\[\033[33m\]$(__git_ps1)\[\033[00m\] \$ '

# function parse_git_branch {
#     git branch --no-color 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/ [\1]/'
# }
# function promps {
#     # 色は気分で変えたいかもしれないので変す宣言しておく
#     local  BLUE="\[\e[1;34m\]"
#     local  RED="\[\e[1;31m\]"
#     local  GREEN="\[\e[1;32m\]"
#     local  WHITE="\[\e[00m\]"
#     local  GRAY="\[\e[1;37m\]"
#
#     case $TERM in
#         xterm*) TITLEBAR='\[\e]0;\W\007\]';;
#         *)      TITLEBAR="";;
#     esac
#     local BASE="\u@\h"
#     PS1="${TITLEBAR}${GREEN}${BASE}${WHITE}:${BLUE}\W${GREEN}\$(parse_git_branch)${BLUE}\$${Blue} "
# }
# promps

#git補完機能
source ~/.git-completion.bash

if [ -f ~/.bashrc ]; then
  . ~/.bashrc
fi

```



```sh:bashrc
# 出力の後に改行を入れる
function add_line {
  if [[ -z "${PS1_NEWLINE_LOGIN}" ]]; then
    PS1_NEWLINE_LOGIN=true
  else
    printf '\n'
  fi
}
PROMPT_COMMAND='add_line'


# "-F":ディレクトリに"/"を表示 / "-G"でディレクトリを色表示
alias ls='ls -FG'
alias ll='ls -alFG'
alias rm='rm -i'
alias grep='grep --color=auto'

cd ()
{
    builtin cd "$@" && ls
}

#docker
alias d='docker'
alias dp='docker ps'
alias di='docker images'
alias dc='docker-compose'
```
viエディタの基本コマンドをまとめます

viエディタの基本コマンドがなかなか覚えられず、何度も検索してしまうため
自身の備忘・メモを兼ねて初投稿したいと思います。

<h2>基本操作</h2>
<li></li>
<ul>・ファイルを開く　　⇨　vi ファイル名</ul>
<ul>・ファイルを閉じる　⇨  [esc] 押下後　:q</ul>
<ul>・ファイルを保存する⇨  [esc] 押下後　:w</ul>
<ul>・ファイルを保存して閉じる　⇨　[esc] 押下後　:wq</ul>
<ul>・コマンドモード⇆インサートモード　⇨ i　：カーソル位置に入力</ul>
<ul>　　　　　　　　　　　　　　　　　　   a　：カーソルのある文字の後に入力</ul>
<ul>　　　　　　　　　　　　　　　　　　　I　：行の先頭に入力</ul>
<ul>　　　　　　　　　　　　　　　　　　　A　：行の最後に入力</ul>
<ul>　　　　　　　　　　　　　　　　　 [esc]：コマンドモードへ</ul>
<ul>・カーソルの移動　⇨右：l　左：h　上：k　下：j</ul>
【Ruby on Rails】検索機能追加

# 開発環境
Rails 6.1.4
ruby 2.6.3

# 前提条件
- devise導入
- Bootstrap導入
- Userモデル、Bookモデル実装済み
- ユーザーの一覧表示と投稿一覧は部分テンプレートで作成済み

# 目次
- コントローラー作成
- ルーティング
- モデル定義
- View作成

## ①コントローラー作成
まずは検索機能のコントローラーを作成します。
同時にコントローラーアクションも作成します。

```ruby:ターミナル
$ rails g controller searches search
```    

searchesコントローラーのsearchアクションを定義します
```ruby:searches.contoroller.rb
class SearchesController < ApplicationController
  before_action :authenticate_user!

  def search
    @range =params[:range]
    @word =params[:word]

    if @range == "User"
      @users = User.looks(params[:search], params[:word])
    else
      @books = Book.looks(params[:search], params[:word])
    end
  end
end
``` 
- 下記コードにて検索フォームからの情報を受け取っています。
　検索モデル→params[:range]
　検索方法  →params[:search]
　検索ワード→params[:word]

- if文を使い、検索モデルUserorBookで条件分岐させます。

- looksメソッドを使い、検索内容を取得し、変数に代入します。
　検索方法`params[:search]`と、検索ワード`params[:word]`を参照してデータを検索し、
　1：インスタンス変数`@users`にUserモデル内での検索結果を代入
　2：インスタンス変数`@books`にBookモデル内での検索結果を代入

また、インスタンス変数`@word`に検索ワードを代入するため定義します。
（検索結果の画面で使用します）

## ②ルーティング

ルーティングを定義します。
searches controller作成と同時にルーティングも作成されているはずなので、
ここではチェックのみ行います。

```ruby:routes.rb
get "search" => "searches#search"
``` 

## ③ モデル定義

モデルを定義します。


```ruby:user.rb
  def self.looks(search, word)
    if search == "perfect_match"
      @user = User.where("name LIKE?", "#{word}")
    elsif search == "forward_match"
      @user = User.where("name LIKE?","#{word}%")
    elsif search == "backward_match"
      @user = User.where("name LIKE?","%#{word}")
    elsif search == "partial_match"
      @user = User.where("name LIKE?","%#{word}%")
    else
      @user = User.all
    end
  end
``` 


```ruby:book.rb
  def self.looks(search, word)
    if search == "perfect_match"
      @book = Book.where("title LIKE?","#{word}")
    elsif search == "forward_match"
      @book = Book.where("title LIKE?","#{word}%")
    elsif search == "backward_match"
      @book = Book.where("title LIKE?","%#{word}")
    elsif search == "partial_match"
      @book = Book.where("title LIKE?","%#{word}%")
    else
      @book = Book.all
    end
  end
``` 

各検索方法を下記のように指定。
検索フォーム作成時に記載した内容を見返してみてください。
・完全一致→perfect_match
・前方一致→forward_match
・後方一致→backword_match
・部分一致→partial_match

送られてきたsearchによって条件分岐させましょう。

そして、whereメソッドを使いデータベースから該当データを取得し、変数に代入します。

完全一致以外の検索方法は、
`#{word}`の前後(もしくは両方に)、`%`を追記することで定義することができます。
これにより、検索方法毎に適した検索が行われるようになりました。

## ④View作成
最後に、viewファイルを作成します。

検索フォームは部分テンプレートで作成します。

```ruby:_search_form.html.erb
<% if user_signed_in? %>
  <div class="search_form">
    <%= form_with url: search_path, local: true, method: :get do |f| %>
      <%= f.text_field :word %>
      <%= f.select :range, options_for_select([['User'], ['Book']]) %>
      <%= f.select :search, options_for_select([["完全一致","perfect_match"], ["前方一致","forward_match"],  ["後方一致","backward_match"], ["部分一致","partial_match"]]) %>
      <%= f.submit "検索", class: "btn btn-primary" %>
    <% end %>
  </div>
<% end %>
``` 

これで完成です！お疲れ様でした！
あくまで備忘録なので足りない説明等多々あるかと思います。
行き詰まった際の助けになれば幸いです。
Cloud BuildでDocker Compose V2を使う

## 背景

- Cloud Build上でE2Eテストなんかをするときに、たまーに`docker compose`コマンドが使いたくなる
- [ガイド](https://cloud.google.com/build/docs/configuring-builds/use-community-and-custom-builders?hl=ja)から辿れるコミュニティ提供のビルダーには[v1用のもの](https://github.com/GoogleCloudPlatform/cloud-builders-community/tree/master/docker-compose)しかない
- v1からv2への差分として例えば以下がある
    - `docker-compose.yml`だけでなく`compose.yml`もデフォルトで読み込まれるようになった
    - `compose.yml`で`version`を設定する必要がなくなった
    - `docker-compose`コマンドでも動くが、dockerのサブコマンドとしての`docker compose`コマンドが推奨されるようになった
    - 若干早くなった気がするけど多分気のせい
- 妥協してv1のビルダーを使うこともできるが、上記差分をわざわざ古い方に寄せて書くのも癪なので、v2のビルダーを作成する

## 結論

```Dockerfile
FROM ubuntu:bionic

ARG DOCKER_COMPOSE_VERSION

# Dockerインストール
RUN apt-get update && apt-get -y install ca-certificates curl docker.io && \
   rm -rf /var/lib/apt/lists/*

# Docker Compose V2インストール
WORKDIR /usr/local/libexec/docker/cli-plugins
RUN curl -L https://github.com/docker/compose/releases/download/v${DOCKER_COMPOSE_VERSION}/docker-compose-linux-x86_64 -o docker-compose && chmod +x docker-compose

ENTRYPOINT ["docker", "compose"]
```

```cloudbuild.yaml
substitutions:
  _DOCKER_COMPOSE_VERSION: 2.6.1 # 使用したいバージョンに置き換え
steps:
- name: 'gcr.io/cloud-builders/docker'
  args:
  - 'build'
  - '--build-arg'
  - 'DOCKER_COMPOSE_VERSION=${_DOCKER_COMPOSE_VERSION}'
  - '-t'
  - 'gcr.io/$PROJECT_ID/docker-compose:latest'
  - '-t'
  - 'gcr.io/$PROJECT_ID/docker-compose:${_DOCKER_COMPOSE_VERSION}'
  - '.'
- name: 'gcr.io/$PROJECT_ID/docker-compose'
  args: ['version']

images:
- 'gcr.io/$PROJECT_ID/docker-compose:latest'
- 'gcr.io/$PROJECT_ID/docker-compose:${_DOCKER_COMPOSE_VERSION}'
tags: ['cloud-builders-community']
```

この2ファイルを作成して`gcloud builds submit`すればOK。
[JavaScript]Object.assignを基礎から理解する

# はじめに
今回は、JavaScriptのObject.assignメソッドについて学んだことをまとめておきたいと思います。

# 1. Object.assignメソッドとは

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

Object.assign()は、第一引数に指定したコピー先のオブジェクトに、第二引数以降の全てのオブジェクトのプロパティをマージしてくれるメソッドです。
## 基本構文
```js
const mergeObject = Object.assign(target, ...sources);
```
`sources`には複数のオブジェクトを指定することができます。

## サンプルコード
### オブジェクトをマージする
```js
const animals1 = { dog: 'いぬ', cat: 'ねこ'}
const animals2 = { tiger: 'とら', rabbit: 'うさぎ'}

const mergeAnimals = Object.assign(animals1, animals2);

console.log(mergeAnimals)
//{ dog: 'いぬ', cat: 'ねこ', tiger: 'とら', rabbit: 'うさぎ'}
```
### オブジェクトをマージする(同じプロパティを持つ場合)
引数に指定したオブジェクトが同じプロパティを持つ場合、後に指定したオブジェクトの値で上書きされます。
```js
const animals1 = { dog: 'いぬ', cat: 'ねこ'}
const animals2 = { cat: '猫', rabbit: 'うさぎ'}

const mergeAnimals = Object.assign(animals1, animals2);

console.log(mergeAnimals)
//{ dog: 'いぬ', cat: '猫', rabbit: 'うさぎ'}
```
### オブジェクトをコピーする
空のオブジェクトとコピーしたいオブジェクトをマージすることで、実現できます。
```js
const animals1 = { dog: 'いぬ', cat: 'ねこ'}
const animals2 = Object.assign({}, animals1);

console.log(animals2)
//{ dog: 'いぬ', cat: 'ねこ'}
```
### 引数のプロパティにオブジェクトがネストされている場合
Object.assignは**Shallow Copy**なので、ネストされている場合、そのオブジェクトは参照がコピーされてしまいます。

https://developer.mozilla.org/en-US/docs/Glossary/Shallow_copy

```js
const animals1 = { dog: 'いぬ', cat: 'ねこ', birds: { duck: 'あひる'}}
const animals2 = Object.assign({}, animals1);

animals2.birds.duck = '家鴨';

console.log(animals1)
//{ dog: 'いぬ', cat: 'ねこ', birds: { duck: '家鴨'}　}
console.log(animals2)
//{ dog: 'いぬ', cat: 'ねこ', birds: { duck: '家鴨'}　}
```

このような場合は、オブジェクトをJSON文字列に一度変換した後に、オブジェクトに戻すことで解決できます。

```js
const animals1 = { dog: 'いぬ', cat: 'ねこ', birds: { duck: 'あひる'}}
const animals2 = Object.assign({}, JSON.parse(JSON.stringify(animals1)));

animals2.birds.duck = '家鴨';

console.log(animals1)
//{ dog: 'いぬ', cat: 'ねこ', birds: { duck: 'あひる'}　}
console.log(animals2)
//{ dog: 'いぬ', cat: 'ねこ', birds: { duck: '家鴨'}　}
```
# 3. 終わりに
Object.assignの基本的な使い方を理解することができました。
また、Object.assignを使わずにスプレッド構文で書くこともできるそうなので、調べてみたいと思います。

# 4. 参考文献

https://reffect.co.jp/html/javascript-object-assign
Selenium(Capybara)+Firefox+Rubyでconsole.logを取得する

## このページについて
Firefox + Selenium(Capybara) で console.log に出力される値を取得する方法について、苦戦したので備忘録です。

## 環境
* Ruby 2.6
* Capybara 3.32.1
* Firefox ２０２２/7/5 時点で最新のもの
* Geckodriver ２０２２/7/5 時点で最新のもの
## やりたいこと
console.log に出力される値を Selenium で取得し、ログに出力したい。

Chrome の場合は `driver.manage.logs.get` で簡単に取得できますが、Geckodriver ではこの方法は現時点では使えません。
以下 issue に代替案が書かれていますので、こちらを参考にします。
https://github.com/mozilla/geckodriver/issues/284

## コード
Capybara の設定に `devtools.console.stdout.content` を追加します。
```ruby
Capybara.register_driver :selenium_headless do |app|
  options = ::Selenium::WebDriver::Firefox::Options.new
  options.headless!
  options.add_preference('devtools.console.stdout.content', true)  # ここを追加
  Capybara::Selenium::Driver.new(app, browser: :firefox, options: 
  options)
end
```
Geckodriver 側の設定は以上です。
さらに Selenium の `logger.level` を `debug` にします。

```ruby
Selenium::WebDriver.logger.level = :debug
Selenium::WebDriver.logger.output = 'selenium.log'
```
これで console.log の値が `selenium.log` へ出力されるようになります。

Selenium のログレベルが `debug` でないと、 Selenium が Geckodriver のログを抑制してしまうそうです。
https://github.com/SeleniumHQ/selenium/issues/7140#issuecomment-486993770
`debug` レベルだとログの出力量が膨大になってしまいますが仕方ありません・・・

## ログのサンプル
console 関連のログは以下のように出力されます。
```
console.warn: SearchSettings: "get: No settings file exists, new profile?" (new NotFoundError("Could not open the file at /tmp/hoge/search.json.mozlz4", (void 0)))
console.log: "JQMIGRATE: Migrate is installed with logging active, version 3.4.0"
```
【AWS CLI】s3 rmでdryrunを使って削除対象を確認

# S3でファイルを一括で削除したいが必要なファイルは絶対に消したくない！
awscliのs3のrmコマンドで `--recursive` オプションを使ってファイルを一括削除したいが、includeやexcludeの指定を失敗して削除しては行けないファイルを削除してしまうことを防ぎたいと思いました。

```shell
aws s3 rm --recursive s3://example-backet/aiueo/12345/ --include "*foo*" --exclude "*bar*"
```

例えば上記コマンドを実行したいと思っても本当に削除対象が自分が削除したいものなのかは実行してみないとわかりません。
実行してからファイルの復活はできませんし、削除前にコピーしておいて…とかはよっぽど出ない限りやりたくありません。

# --dryrunオプションを使う
そういうときにdryrunオプションを使うと、実行はしないが、実行したかのようなcli上の確認が取れます

>Checks whether you have the required  permissions  for  the  action,
          without actually making the request, and provides an error response.
          If you have the required permissions, the error response is  DryRun-
          Operation . Otherwise, it is UnauthorizedOperation .


https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-usage-help.html

https://docs.aws.amazon.com/cli/latest/reference/s3/rm.html

なので

```shell
aws s3 rm --recursive s3://example-backet/aiueo/12345/ --include "*foo*" --exclude "*bar*" --dryrun
```

このように実行すると、本当に削除したいファイルが対象かがわかります。
このdryrunはs3に限らないので、他のコマンドも同じように実行が不安であれば試してみるといいと思います。
SIerとして1年半働いた振り返り


業界未経験で、中小SIerに転職しました。
もうすぐ1年半になるので、振り返りをします。
実際SIerって何をしているのか、参考になれば嬉しいです。

## 【入社～2週間】社内研修
最初の3日間くらいは、新入社員向けの動画教材を見ました。
RDBMS、Javaとか、システム開発の基礎的な知識の解説動画でした。

その後、サーブレット、JSPを用いた、簡単なシステム開発をしました。
設計書は一応用意されていたので、それを見ながらという感じです。
テストに関しては、仕様書から自分で作るスタイルでした。
基本的な内容だらけでしたが、レビューもいただきました。

## 【１～４ヶ月目】社内システムの改修
社内で開発しているシステムの改修をやらせてもらえました。
詳しくは言えませんが、言語はJava、フレームワークはSpringなどではなく独自のものでした。
最初に、先輩社員から改修の方法をある程度教えていただき、すぐに作業に入りました。
ちなみに、このシステム改修は急ぎでなかったこともあり、私しかやる人がいませんでした。

部長から、こういう機能欲しい、と口頭で説明を受け、実装するという流れでした。
設計書はメンテされていない事も多々あり、現行に合うように修正＆改修分を追記していました。
テストは、伝家の宝刀エクセルスクショでしたし、社内限定のシステムなので、しっかりしたものは求められませんでした。

ちょうど4ヶ月目の後半から、退職予定の技術バリバリ系の方に色々と教えていただく機会がありました。
コードレビューや設計書レビューもしていただけて、かなりためになりました。
また、このシステムのコード自体が良いものとは言えないという事を教えていただき、衝撃を受けました。笑

自分からレビューしてもらいに行くなどの行動を起こすべきだったなと少し反省しています。

## 【５～９ヶ月目】初の社外案件参画＆新入社員サポート
社内システムから卒業しました。
そして、以下の３つの事が並行稼働しました。
* 保守案件（Androidアプリ）のお手伝い（5ヶ月目の1週間のみ）
* 新入社員のサポート（5ヶ月目のみ）
* 先輩社員が参画している案件（C＃）への参画

1つ目のAndroidは、ほんとに1週間だけでしたので、簡単な画面作成ができるようになって程度です。

2つ目は、新人が新人を教えるという、教えられる側からすれば、不安でしかない状況でした。
私自身は、研修の復習になったし、教えるという経験をできたのはよかったです。
幸い教えた新人が、めちゃくちゃ優秀だったので、助かりました。

3つ目が、メインの仕事です。
今までJavaのみでしたが、突然のC#案件です。
詳細設計書は用意されており、PGから単体テストを担当しました。
最初は名前空間ってなんやねん状態から、先輩にサポートを受けてなんとか作業しました。
ただ、アドオン開発でしたので、そこまでC#を意識することはありませんでした。
生産管理系のシステムだったので、業務理解の方が大変でした。
開発フェーズが結合テストに入ったあたりで案件から外れました。
結合テストはちゃんとはやらせてもらってませんが、結合テストの不具合修正と修正確認をしていたので、実質していたと思います。笑

## 【１０ヶ月目】次の案件
次の案件とありますが、元請は同じ会社です。1ヶ月だけヘルプという形で参画。
顧客が違うだけで、使う技術もほぼ同じでした。
使うVisual Studioのバージョンが古すぎて(2008とか？)、デバッグがまともにできなかったのがしんどかったです。。。

## 【１１ヶ月目】保守案件
直請の保守案件をお手伝いしていました。
社内システムと同じようなつくりのシステムでした。
HTML,CSS,JS(jQuery)を使った画面ならだいたい作れる感じになってきました。
JSもJavaも複雑な事はあんまりしてなかったので、単純に簡単だったというのもあるかもしれません。

## 【１２ヶ月目】社内システム
社内システムのリメイクが始まりました。
お客様向けのリメイクで、かなり大規模なものになっていました。
要件定義フェーズが終わったタイミングで参画しました。
この時点で納期も決まっており、どう考えても間に合わない、素人目にみても炎上するだろうなという状況でした。
私は1ヶ月で別案件に参画になったのですが、今も絶賛炎上中です。
ちなみに、どんな感じかというと、
* 設計と開発は並行
* WBSがその日暮らし状態
* がっつり設計できる人が少ないので、負荷が集中
* 作業者はやれることが少ないので、炎上してるけど定時帰宅
何とかしようと動いてはいますが、現時点であまり改善されていないようです。

## 【～1年半】BI画面作成、クラウド基盤移行
とある企業で、プラットフォームをクラウドへ移行する動きがあり、そのプロジェクトの端くれ案件になります。
オンプレで運用しているシステムをクラウドに移行＆ついでにBIツール使っちゃおうぜ、っていうノリです。
一応AWSとかDWHとかいろんなツールを触る事ができています。
ただあくまで下請けの末端の人間なので、作業者止まりです。
AWSの設定とか一切しません。
用意された環境、ロールを使って作業するだけです。知識ゼロでいけてます。
ツールを並べると、SIerにしてはすごいモダンな感じでいいやん、って思いますが、下請けは作業するのみです。
こういうのを経験すると、元請けに近いところが良いなって思います。
アーキテクト的な知識が手に入ると思ってましたが、なかなか思ったように行きませんでした。

## 最後に
会社によるんでしょうが、巷で言われているほどSIer悪くなかったです。
ちなみに今のところ残業ほぼ０でいけています。
お給料は400前半と、少な目かもしれませんが、もっと寄こせと言えるほどの実力がないので、もっとがんばります。

SIerというより、その下請け構造がよくないんだろうなって思ったりもします。
やる気があっても、下請けでやれることは限られます。
とてつもないコミュ力、行動力でその垣根を飛び越えていける人はいいのかもしれませんが、現実問題難しいと感じます。

エクセルのドキュメント作成・管理は、言われている通り、けっこうあります。
役職が上がれば上がるほどそうなっていくことでしょう。
log4j の出力を rsyslog に食わせる

プロセス内から別のプロセスを呼ぶような jar があって、それぞれが同じファイルにログを出力する場合にサブプロセスからのログ出力が無視されそうな場合の対処として rsyslog を使いたい。

log4j には最初から syslog に出力するような Appender があるけれども単純にそれだけだとメッセージしか出力されずクラス名メソッド名などが拾えないのでどうにかしたい

## rsyslog を更新する

CentOS7,8では出力した構造化データを解析して云々するためのモジュール mmpstrucdata.so がインストールされないので更新する

https://www.rsyslog.com/rhelcentos-rpms/

```
cd /etc/yum.repos.d/
wget http://rpms.adiscon.com/v8-stable/rsyslog.repo
yum install rsyslog
```

## rsyslog.conf を編集する

以下

```
# 以下コメントアウトを解除する
$ModLoad imudp
$UDPServerRun 514

# モジュール mmpstrucdata をロードする
module(load="mmpstrucdata")
action(type="mmpstrucdata")

# 出力フォーマットを定義する
template(name="MyAppFormat" type="list") {
    property(name="timereported" dateFormat="rfc3339")
    constant(value=" ")
    property(name="hostname")
    constant(value=" ")
    property(name="syslogtag")
    constant(value=" ")
    property(name="$!rfc5424-sd!location@32473!class")
    constant(value=" (")
    property(name="$!rfc5424-sd!location@32473!method")
    constant(value=":")
    property(name="$!rfc5424-sd!location@32473!line")
    constant(value=") ")
    property(name="msg" droplastlf="on")
    constant(value="\n")
}

# ファシリティ local0 の出力指定
local0.*                                                /var/log/application.log;MyAppFormat
```

## log4j の設定

```
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="OFF">
	<Properties>
		<Property name="ptn">
    %d{yyyy-MM-dd HH:mm:ss.SSS} [%p] %C#%M %m %n %throwable
    </Property>
	</Properties>
	<Appenders>
		<Console name="console" target="SYSTEM_OUT">
			<PatternLayout pattern="${ptn}" />
		</Console>
		<RollingFile name="file" fileName="/var/log/fooapp/fooapp.log"
			filePattern="/var/log//fooapp/fooapp_%d{yyyyMMdd}_%i.log"
			append="true">
			<PatternLayout pattern="${ptn}" />
			<Policies>
				<SizeBasedTriggeringPolicy size="10 MB" />
			</Policies>
			<DefaultRolloverStrategy max="10" />
		</RollingFile>
		<Syslog name="syslog" host="localhost" port="514" protocol="UDP" facility="local0" appName="app" >
			<Rfc5424Layout appName="MyApp" facility="LOCAL0">
				<LoggerFields enterpriseId="32473" sdId="location">
				  <KeyValuePair key="logger" value="%c" />
				  <KeyValuePair key="class" value="%C" />
				  <KeyValuePair key="method" value="%M" />
				  <KeyValuePair key="line" value="%L" />
				</LoggerFields>
			</Rfc5424Layout>
		</Syslog>   
	</Appenders>
	<Loggers>
		<Root level="trace">
			<AppenderRef ref="syslog" />
			<AppenderRef ref="file" />
		</Root>
	</Loggers>
</Configuration>
```

Appender "Syslog" を追加する

## その他

syslog出力はたしか fluentd に拾わせることが出来たと思うので、出力を mongodbに食わせるとかもできるかも。
タスクスケジューラ

tis

https://qiita.com/iwaohig/items/8853ed4433f6653396c2

https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/get-eventlog?view=powershell-5.1

https://blog.engineer-memo.com/2022/04/27/%E7%89%B9%E5%AE%9A%E3%81%AE%E6%96%87%E5%AD%97%E5%88%97%E3%82%92%E5%90%AB%E3%82%80%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E3%83%AD%E3%82%B0%E3%81%AE%E5%87%BA%E5%8A%9B%E6%99%82%E3%81%AB%E3%82%BF%E3%82%B9/

https://social.technet.microsoft.com/Forums/en-US/382b9023-01a9-4131-b2f2-8560b593bc3f/scheduled-task-trigerred-by-event-getting-data-into-the-scripts-as-parameters-question