OmniAICreator/Qiita-1.07M huggingface dataset:
サーバーサイドGoogleタグマネージャーのカスタムテンプレートタグを使ってcookie情報を取得する

# 背景
ITP対応後の計測においてサーバーサイドダグマネージャーにおけるイベント計測が重要になってきます。本稿ではサーバーサイドタグマネージャーのカスタムテンプレートタグを使って独自のタグ処理を実装してきます。

# サーバーサイドタグマネージャーって何？
サーバーサイドタグマネージャーについてはアユダンテさんのこの記事が非常によくまとまっています。

https://ayudante.jp/column/2020-08-21/11-00/

まとめると

- 概要: サーバーサイドで計測が発火するGTM
- メリット:クライアント端末のリソースを食わない
- デメリット: エンジニアリソースが必要
- その他: サーバー発行の1st party cookie(Aレコード)の発行できるので、ITP対策になる

とういう感じでしょうか。


# 作るもの
sGTM経由でイベント情報をGA4とCloudRun経由でBigQueryに送るようなシステムを作ってみます

![Flowchart.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20307/9bf2af37-09b5-41a3-4fe9-1b8bdc3cd268.jpeg)

sGTMのカスタムテンプレートタグで

- Cookie(_ga, FPID)
- サーバーサイドタグで設定する変数

を付与したGET_URLを作成して、Cloud Runに送信します。

※ Cloud Run -> BigQueryの処理に関しては本項では行わない

### 0. 概要を理解する
そもそも、タグマネージャーとは？カスタムテンプレートとは？など用語がわからない場合はこのリンク集で用語理解しましょう

https://qiita.com/munaita_/items/7ba43a1da30914dd0738

### 1. sGTMの設定(webタグ, serverタグ)を行う
ベーシックなsGTMの設定は以下のアユダンテさんの記事が非常に丁寧に記載してあります。こちらを参考にして、まずは **webコンテナGA4タグ** + **サーバーサイドGA4タグ** の設定を作成してください

https://ayudante.jp/column/2020-09-04/11-00/

### 2. カスタムテンプレートの作成

Cloud Runへイベント情報を送信するタグのテンプレートを作成していきます。

サーバーコンテナのコンソールから　テンプレート -> タグテンプレートの新規作成ページへ


![スクリーンショット 2021-12-02 16.24.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20307/cce2b4c6-1c46-5dc9-0fdc-8f4429c7a484.png)
名前を適当に


![スクリーンショット 2021-12-02 16.24.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20307/b1312eeb-5901-487d-ba0e-a84614ed4532.png)
項目タブでendpointとmy_idのフィールドをテキストで追加。後ほどタグ作成時に値を設定します。
※ APIは [サーバーサイド タグ設定 API](https://developers.google.com/tag-manager/serverside/api?hl=ja) を参照



```js:カスタムテンプレートタグコード
const sendHttpGet = require('sendHttpGet');
const getCookieValues = require('getCookieValues');

// タグで定義するendpointを取得
const endpoint = data.endpoint;

// リクエストからcookie情報を取得
const cookie_keys = ['FPID', '_ga'];
let cookie_hash = {};
for (const k of cookie_keys) {
  cookie_hash[k] = getCookieValues(k);
}
let cookie_suffix = '';
for (let k in cookie_hash) {
 cookie_suffix = cookie_suffix + '&' + k + '_cookie=' + cookie_hash[k];
}

// get_urlを作成
const url = endpoint + '&my_id=' + data.my_id + cookie_suffix;

sendHttpGet(url, (statusCode) => {
  if (statusCode >= 200 && statusCode < 300) {
    data.gtmOnSuccess(); 
  } else {
    data.gtmOnFailure();
  }
});
```
コードのタブで上記コードを設定



![スクリーンショット 2021-12-02 16.34.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20307/76d83674-f329-14ad-6c7b-a92effb56a79.png)
権限タブで、Cookieの読み取りを任意、HTTPリクエストの送信を全ての..にします。簡単のため。

保存します。

### 4. カスタムテンプレートを使ったタグを作成

1で作成したGA4タグに追加して、CloudRunに送信するカスタムテンプレートタグを新規作成していきます

コンソールの タグ -> 新規 -> タグの設定の右上の編集マーク -> 作成したテンプレートをクリック

![スクリーンショット 2021-12-02 16.42.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20307/c353b794-068d-9bb6-11c5-64dc276819ba.png)
endpointとmy_idの値をここで設定します。endpointにはcloud runのendpointが入ります。

保存。

これでsGTM経由でGA4とCloudRunに両方イベント情報を送る設定ができました。CloudRun -> BigQueryのへのInsert処理を書けば完了。
New Relic初心者がNew Relicを紹介する

この記事は[New Relic Advent Calendar 2021](https://qiita.com/advent-calendar/2021/newrelic)の7日目の記事です。

## 概要
最近、株式会社WARCに転職しました。
弊社ではNewRelicを導入しておりますが、これまで自分はほぼ触ったことなく今回あらためてNewRelicを端から触ってみたので、良いと思ったものをピックアップして浅く広く紹介していきます。
ちなみに、インフラよわよわバックエンドエンジニア目線での記事になります。

## 紹介
### AWS上のリソースの確認がしやすい
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85138/c75e3632-e864-fc10-62a7-319108d35c3b.png" width="500px">
AWS上のリソースを並べてビジュアライズしてくれます。一部のリソースだけでなく設定したアラートにひっかかった場合はリソースの色が黄色や赤色になるので、高負荷や障害時などに何が原因になってるのかひと目でわかるのがよさそうですね。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85138/847c46c4-3441-b178-8c83-e286842c8e69.png" width="500px">
メトリクスをSQLライクなクエリで参照できます。雰囲気で雑に書いてもそれっぽくなります。


これらがどうやら[簡単に接続できるらしい](https://docs.newrelic.com/jp/docs/infrastructure/amazon-integrations/get-started/connect-aws-new-relic-infrastructure-monitoring/)のがよいですね。


### リクエスト分析
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85138/9a4145a4-d26a-7f37-ed4d-d1542bdd819f.png" width="500px">
アプリケーションをトレーシングして、どのエンドポイントが遅いのか・またそのエンドポイントの中でもコードのどの箇所に時間かかってるのか調査できます。遅い箇所を具体的な関数やSQLで出してくれます。パフォーマンス改善にめっちゃ役立ちます。
`Slowest average response time`だと純粋にレスポンスタイムが長い順に、 `Most time consuming` にするとリクエスト数とレスポンスタイムを鑑みた順にソートしてくれます。
（画像上では具体名が出ている箇所は白塗りにしました、わかりづらくてすみません；）

### クエリ分析
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85138/74a3017d-3e7d-d425-a335-8353553fecec.png" width="500px">
こちらはDBにむけて投げてるクエリの分析。こちらも遅い順にならべてくれます。

### RubyVM
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85138/2b486392-4f02-4116-c65d-5f10acfc767b.png" width="500px">
VMの情報もメトリクス化してくれる。素直にcloudwatchだけだとここまでできないのでこれはありがたい。

### デプロイ別インフォーメーション
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85138/2a254b3a-f37e-ad7a-b59b-c4c0f54447c6.png" width="500px">
設定しておけばデプロイ別のインフォメーションも出してくれます。いつのデプロイでレスポンスタイムがどう変化したのかエラー率がどうなったのかなど。
この機能がなくても色々辿ればだせるけど、こうやって一覧にしてくれるのは嬉しいですね。

### ログ確認
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85138/a3346892-4942-59a1-a3dc-3dc06b35a39f.png" width="500px">
ログがずらずらっと流れます。フィルタがかけやすやすく、GUIでポチポチもできるしクエリで入力もできます。

### スケーリングレポート
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85138/5a20cfab-556b-133b-c82f-6c906ed50532.png" width="500px">
レスポンスタイムvsスループットのグラフ。スループットが増えてもレスポンスタイムが伸びない（=線が水平に近い）とスケールしていると言えると思います。（図は良くない例ですね）

### セッショントレース
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85138/7c14077f-90b4-fdcf-5c33-7a7767f9ea7e.png" width="500px">
Webフロントでの1セッションの動きをトレースしてくれる。ユーザがどう動いたのかを見れる感じですね。

## まとめ
以上紹介記事でした。
他にも、スレッドプロファイルとってくれたり、どこからアクセスされてるとか、Webフロントのどこが遅いなどなど良い機能がたくさんあります。
他社製品にも同じ機能あるよ！などあるかもですが、APMツールとして基本的な機能を抑えつつ使い勝手の良い機能を取り揃えてるのが良いと思いました。
色々導入するのも良いですが、情報が一箇所にまとまってるのは大きなメリットですね。
まだまだ触り始めたばかりで浅い記事になってしまったので、この機会にもっと使っていこうと思います。

（トンチンカンなことを記載していたらすみません） 

## 最後に
株式会社WARCではともにサービスを作っていく仲間を募集しています。
https://www.wantedly.com/companies/company_3787524/projects
【Ruby】nextとreturn


map関数などの繰り返しの処理の中で、
ある条件のときだけ次のループに行きそのまま処理を続けたいときはreturnじゃなくてnextを使う。

##next
nextはもっとも内側のループの次の繰り返しにジャンプします。

https://docs.ruby-lang.org/ja/latest/doc/spec=2fcontrol.html#next

```n + 1```が偶数のときに```puts "hello! #{n + 1}回目"```を実行せずに次のループにいく。

```ruby
def next_method
  5.times do |n|
    next if (n + 1).even?
    puts "hello! #{n + 1}回目"
  end
  puts "完了！"
end

next_method

#=>hello! 1回目
#=>hello! 3回目
#=>hello! 5回目
#=>完了！
```

##return
式の値を戻り値としてメソッドの実行を終了します。

https://docs.ruby-lang.org/ja/latest/doc/spec=2fcontrol.html#return

```n + 1```が偶数のときに処理を抜けるので「２回目」は実行されない。

```ruby
def block_return
  5.times do |n|
    return if (n + 1).even?
    puts "hello! #{n + 1}回目"
  end

  puts "完了！"
end

block_return

#=>hello! 1回目
```

##参考

https://sakaishun.com/2021/04/20/next-break-return/
SIer時代によく使ったワンライナー

Linuxや、Solaris、HP-UXなど、多くのOSには標準的なインストールでperlが入ってたり or インストールが容易ですね。
システムインテグレーションの仕事でサーバ構築やメンテなどを行いたいけど
本番環境ではツール類を気軽にインストールできない、というのはよくある話で、そんな時にもperlは頼もしい存在でした。
(最近はコンテナやサーバレスなどで状況は変わってきましたが。。。)

SIer時代によく使ったperlのワンライナーをいくつか思い出して紹介します。

## 簡易TCPサーバ

ネットワークの疎通確認として
サーバ側で任意のTCPポートでlistenして、クライアント側から接続確認したいことがあるでしょう。
perlの標準入力をソケットに吐き出しているので、ちょっとしたファイル転送にも使えます。

```sh:簡易TCPサーバ
## 8888/tcpポートでサーバ起動
echo ok | perl -MIO::Socket -pe 'BEGIN{select IO::Socket::INET->new(LocalPort=>shift,Listen=>5,ReuseAddr=>1)->accept}' 8888
```

クライアントからはtelnet、curl、nc(netcat)コマンドなど、そこらへんにある適当なコマンドで接続します。

```sh:クライアント側
curl telnet://サーバのIP:8888
```

## HEXダンプを復号する

tcpdumpや、その他のツールやログ出力などでHEXダンプがあったときに、ちょっと復号したいことがあるでしょう。
vim付属の`xxd`コマンドを使う方法もありますが、元のダンプを含むテキストを不要部分除去などの加工をしつつ処理するのにperlを使ってました。

```sh:HEXダンプを復号
## HEXダンプされたファイル(in.dump）を復号
perl -ne 's/\s//g;print pack("H*",$_)' < in.dump > out
```

## CSVやTSVを縦横回転

項目の多いcsv(カンマ区切りテキスト)ファイルやtsv(タブ区切りテキスト)ファイルを見る時に、
mysqlの`\G`メタコマンドやpostgresqlの`\x`メタコマンドのように、縦横を入れ替えて確認したいことがあるでしょう。

以下のようなエイリアスを作って

```sh:csvやtsvを縦横回転
## csvファイルを回転するエイリアス
alias rotcsv='perl -nle '"'"'@c=split(/,/);$max=@c if $max<@c; for ($i=0; $i<$max; $i++) { $r[$i][$l] = $c[$i] }; $l++; END { for (my $j=0; $j < $max; $j++) { print join("\t", @{$r[$j]}) } }'"'"

## tsvファイルを回転するエイリアス
alias rottsv='perl -nle '"'"'@c=split(/\t/);$max=@c if $max<@c; for ($i=0; $i<$max; $i++) { $r[$i][$l] = $c[$i] }; $l++; END { for (my $j=0; $j < $max; $j++) { print join("\t", @{$r[$j]}) } }'"'"
```

以下の感じで使います。
マルチバイト文字の幅計算が面倒なので桁あわせ処理などはしてないけど、項目が多い場合はかなり読みやすくなります。

```sh:使用例
## 元のcsvファイル
$ cat in.csv
id,name,attribute
1,foo,administrator
2,bar,user

## 回転して表示
$ rotcsv < in.csv
id	1	2
name	foo	bar
attribute	administrator	user
```

---

良い年末を!
ImageMinimizerWebpackPluginがSquooshに対応したのでらくらく画像一括置換

:::note warn
2023年4月11日追記
本記事は **Node.JS16以下、かつ、glob 8.x以下** でないと動作しません。
Node.JS18以上、またはglob 9.x以上を利用する場合は以下を参照ください。

**sharpを使って画像を一括最適化、ついでにSVGにも対応した**
https://qiita.com/bananacoffee/items/d7a4b5cb4afff7efd162
:::

:::note warn
2022年9月2日追記
webpackを使わずにNode.jsだけで変換できるプログラムを作成したのでこちらをオススメします

libSquooshを使って画像一括変換
https://qiita.com/bananacoffee/items/1f36854d6fbc0b6e809a
:::

# ついにImageMinimizerWebpackPluginがSquooshに対応！

12/6にメジャーアップデートがあり、ついにSqooshに対応した。
https://www.npmjs.com/package/image-minimizer-webpack-plugin

じつは今までもこのページにはSqooshの使い方が書いてあったのだが、v2ではライブラリが搭載されておらず、**GitHubからmasterをプルした場合のみ使える**状態で、ずっとアップデートを待っていた状態だったのだ。

## 特定ディレクトリ内の画像を一括で変換するだけの処理を作ってみた

### 要件

- `/src/assets/images` 以下の画像を `/public/assets/images` に吐き出す
- サブディレクトリも対象とし、階層構造を維持する
- `png`, `jpg`ファイルが対象
- Webpにロスレスで変換する。 その際のファイル名は `xxx.png.webp`, `xxx.jpg.webp` 
- 読み込み元の画像が削除されても対応できるようにする
- 変換プログラムは都度実行してもよい（watchはしない）  
→ 開発中に画像ファイルがコロコロ変更されることはあまり考えられないため

### 1. なにはともあれインストール

ImageMinimizerWebpackPluginとSquooshをインストールする。

```shell
npm i -D image-minimizer-webpack-plugin @squoosh/lib

# 既にインストール済みで imagemin-xxx を使っている場合は削除
npm rm imagemin-jpegtran imagemin-optipng imagemin-webp

# また、今回必要なパッケージもインストールする
npm i -D copy-webpack-plugin path
```

### 2. webpack.config.js を作成

```webpack.config.js
const CopyWebpackPlugin = require('copy-webpack-plugin')
const ImageMinimizerPlugin = require('image-minimizer-webpack-plugin');
const path = require('path');

module.exports = {
  mode: "development",
  entry: path.resolve(__dirname, 'src/dummy.js'),
  output: {
    clean: true,
    path: path.resolve(__dirname, 'public'),
  },
  plugins: [
    new CopyWebpackPlugin({
      patterns: [{
          from: path.resolve(__dirname, 'src/assets/images'),
          to: path.resolve(__dirname, 'public/assets/images')
        }]
    }),
    new ImageMinimizerPlugin({
      test: /\.(png|jpe?g)$/i,
      minimizer: {
        filename: '[path][name][ext].webp',
        implementation: ImageMinimizerPlugin.squooshMinify,
        options: {
          encodeOptions: {
            webp: {
              lossless: 1,
            },
          },
        },
      },
    }),
    new ImageMinimizerPlugin({
      test: /\.(png|jpe?g)$/i,
      minimizer: {
        implementation: ImageMinimizerPlugin.squooshMinify,
        options: {
          encodeOptions: {
            mozjpeg: {
              quality: 85,
            },
            oxipng: {
              level: 3,
              interlace: false,
            }
          },
        },
      },
    }),
  ]
}
```

### 3. ダミーファイル配置

`/src/dummy.js` に空のファイルを配置

### 4. 実行

```shell
node node_modules/webpack/bin/webpack
```

または package.json に記述して実行

```package.json
  ...
  "scripts": {
    "image": "webpack",
  },
  ...
```

```shell
npm run image
```

### 4. 結果

![result.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104999/7f5c64b8-1fe9-85d7-7294-77c9216a9a5d.png)
【Flutter】freezed なクラスを一瞬で出力するVSCodeスニペット

Riverpod + freezed 便利に使っています。ただ、freezed のクラスを新しく書く時に、どこかからコピーして...クラス名を書き換えて...というのが割と面倒でしたのでVSCodeのスニペット化しました。定型的な作業はできる限り効率化したいですよね。

## 何ができるようになる？

以下のようなfreezed クラスを `frz` という文字を打つだけで作成できます。
import文も含めて生成されるので、自分の作りたいクラス名とフィールド名を追加する作業だけに集中できます。
※`part XXX` のXXXには今のファイル名が自動で補完されます

```
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:flutter/foundation.dart';
part 'XXX.freezed.dart';

@freezed
class DataClass with _$DataClass {
  const factory DataClass({
    @Default(0) int counter, // Add your fields here
  }) = _DataClass;
}
```

## インストール

- `Cmd + Shift + P` を押して(Macの場合) `Configure User Snippet` を入力、選択
- `dart.json` があれば選択、なければ、`New Global Snippet File` を選択し `dart.json` を作成

開いたJSONファイルに以下を追加します。

```
	"Freezed class template": {
		"prefix": "frzclass",
		"description": "Create a Freezed class",
		"body": [
			"import 'package:freezed_annotation/freezed_annotation.dart';",
			"import 'package:flutter/foundation.dart';",
			"part '${TM_FILENAME_BASE}.freezed.dart';",
			"",
			"@freezed",
			"class ${1:DataClass} with _$${1:DataClass} {",
			"\tconst factory ${1:DataClass}({",
			"\t\t@Default(0) int counter, // Add your fields here",
			"\t}) = _${1:DataClass};",
			"}"
		]
	},
```

## 使い方

- .dartファイルを編集中に、 `frz`.. と打つと `frzclass` が候補に出ますので選択
- freezed のクラステンプレートが入力されます
- テンプレートに入っている `DataClass` を自分が作りたいクラス名に変更
- 必要なフィールドも適宜追加します（デフォルトで入ってるcounter変数はサンプルなので削除ください）
- あとは `flutter pub run build_runner build` を実行してコード生成すれば完了です。
SQLとは何者なのか調べてみた

railsの勉強をしている上でかならず出てくるキーワードである"MySQL"。
いまいちわかっていなかったので調べてみることにした。

"MySQLとはオープンソースの(RDBMS)リレーショナルデータベース管理システムの事である"

これだけ言われてもすこしピンとこないので、まずは前提知識となるRDBMSについてさらりと調べてみる。

まずは関係モデルというものがあり、そのモデルを基に構築されたデータベースが関係(リレーショナルデータベース)である。

関係モデルとはデータベースの形態の一つで、テーブルと呼ばれる2元の表でデータを管理するモデルであり、最も一般的に利用されているものである。

関係(リレーショナル)データベースとは、上記のモデルをもとに構築されたデータベースの事で、それぞれの表(テーブル)を組み合わせたデータテーブルを作成することができる。

そしてSQLとは上記のデータベースを管理、操作するデータベース言語のことである。
SQLがデータベースにクエリ(問い合わせ)を送ることでデータベースと対話するようにやりとりする事ができる。

なるほど、ここまでの知識を踏まえると最初の文の内容が少し理解できる。
MySQLとはオープンソースの(RDBMS)リレーショナルデータベース管理システムの事である。
とにかくわからないキーワードを調べていくのは大事だなぁという話。
誰でも簡単プログラミング

#初めに
今回紹介するのは誰でも簡単にプログラミンができるサイトを紹介します。
使うサイトは scratch です。Scratchではブロックをつなげていくだけでプログラミングすることができます。

https://scratch.mit.edu/

#使い方
今回は簡単な動作をいくつか紹介します。
例えば人を10歩だけ歩かせたいときは以下の通りにすると動かせます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2301717/d4dd180e-bab4-9d96-c20a-9378a5b4980d.png)

またずっと歩かせたいときは制御の中から「ずっと」を選択して中の処理を続けさせることが出来ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2301717/f9ada749-7f26-7909-e5ce-cbaf77376990.png)

次に紹介するのはフラグがクリックしたときに反応する動作です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2301717/c34d91b2-fa75-16d7-e69e-38eea00a09b5.png)
クリックすることで自分が指定した時間だけ表示してくれます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2301717/1346bf69-6406-e2be-5a06-4471e5ac4249.png)

#終わりに
今回は簡単な動作だけを紹介しましたが他にも音を鳴らすことが出来たり、簡単なゲームを作るなどいろいろなことができるのでオススメです。少しでも興味を持った人を是非挑戦してみてください！
Scriptable Object の値を保存せずに変更する

# 結果 : Scriptable Object の値を保存せずに変更する方法 がわかる。

Unity Editor 上でゲーム中に Scriptable Object の値を変更すると、その値が保存される。値を保存せずに変更する方法を示す。

# 解決 : NonSerialized な filed を編集する。

```csharp
[CreateAssetMenu]
public class FloatVariable : ScriptableObject, ISerializationCallbackReceiver
{
	public float InitialValue;

	[NonSerialized]
	public float RuntimeValue;

public void OnAfterDeserialize()
{
		RuntimeValue = InitialValue;
}

public void OnBeforeSerialize() { }
}
```

- シリアライズされる変数を `InitialValue` とする
- シリアライズされない変数を `RuntimeValue` とする

NonSerialized 属性をつけると、その変数はシリアライズ化されない。シリアライズ化される値 `InitialValue` を `RuntimeValue` へ代入する。GameObject はシリアライズ化されてない `RuntimeValue` を変更する。`RuntimeValue` への代入はデシリアライズされた後に行う。

`ISerializationCallbackReceiver`　インターフェイスを継承すると、シリアライズ前とデシリアライズ後のタイミングに処理が挟める。

# 参考
https://unity.com/ja/how-to/architect-game-code-scriptable-objects
seleniumでテストを作成するためのスクラップ



#Chromeのユーザーを指定して使う方法
特定のユーザーしか入れない環境や権限のあるページにアクセスしたい…
→自分のChromeアカウント使おう

https://selenium-world.net/selenium-tips/3519/#:~:text=ChromeDriver%E3%81%A7%E3%81%AE%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E3%83%97%E3%83%AD%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E6%8C%87%E5%AE%9A

#逆引きAPI
やりたい動作からメソッドやサンプルコードを検索できる（python、java、Rubyの3つに対応）
https://www.seleniumqref.com/api/webdriver_gyaku.html

#Xpathについて
##xpathの勉強で初めに読む記事
xpathの概念から使い方のテクニックまでの理解
https://qiita.com/rllllho/items/cb1187cec0fb17fc650a

##xpath取得用拡張機能
テストしたいページのxpathを取得する際に便利な拡張機能
スラックが活発だが、課金への誘導が激しめ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/495928/cf419640-080a-418a-b48b-9163f55911b2.png)

https://chrome.google.com/webstore/detail/selectorshub-xpath-plugin/ndgimibanhlabgdgjcpbbndiehljcpfh


#selenium IDEコマンド
全てのコマンドがある（体感）。やりたい操作があればココを見れば解決。

https://qiita.com/oh_rusty_nail/items/77782973b4152992017b
ブラウザーで録音、アップロード

こちらのプログラムを参考にしました。
[addpipe/simple-recorderjs-demo](https://github.com/addpipe/simple-recorderjs-demo)
![recorder_dec07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/7b700597-c7a0-8e3b-aa12-319630d92cec.png)


PHP ファイルを改造して、work_dir に wav ファイルが保存されるようにしました。

フォルダー構造

```text
$ tree
.
├── index.html
├── js
│   └── app.js
├── README.md
├── style.css
├── upload.php
└── work_dir
    └── 2021-12-07T03:01:49.170Z.wav
```

インストール方法

```bash
git clone https://github.com/addpipe/simple-recorderjs-demo
cd simple-recorderjs-demo
mkdir work_dir
chmod 777 work_dir
```

改造した PHP ファイル

```php:upload.php
<?php
print_r($_FILES); //this will print out the received name, temp name, type, size, etc.

$size = $_FILES['audio_data']['size']; //the size in bytes
$input = $_FILES['audio_data']['tmp_name']; //temporary name that PHP gave to the uploaded file
$output = "work_dir/" . $_FILES['audio_data']['name'].".wav"; //letting the client control the filename is a rather bad idea

//move the file from temp name to local folder using $output name
move_uploaded_file($input, $output);

?>
```
[Windows][Chocolatey]タスクスケジューラで環境更新を自動化する

# 発端
いちいちCMDとかChocolateyGUIで毎日最新化をポチポチ作業していた状態から開放されます。
これでウッカリ更新を忘れて古いものを使い続けてた！という事がなくなって快適になります。
（特にVSCode）

# 結論
`cup all`をタスクスケジューラに組み込めば完成です。
`cup`も中身は`choco`なので`choco`のパスが通ってないと使えません。つまり、管理者権限が必要です。

# 分かる人向けの設定画像
タスクスケジューラーを開いて操作タブの設定です。
[<img src = "https://user-images.githubusercontent.com/15845907/144951250-bc7a40fe-0993-44a8-8a17-2900131ea30f.png">](https://user-images.githubusercontent.com/15845907/144951250-bc7a40fe-0993-44a8-8a17-2900131ea30f.png)

# 手順解説
1. [Qiita：そもそもタスクスケジューラーとは？(@nomurasan)](https://qiita.com/nomurasan/items/dba72d1ec1d194b74a33) 
1. [Github：運用面など注意喚起](https://github.com/shimajima-eiji/Chocolatey/blob/master/%E3%82%BF%E3%82%B9%E3%82%AF%E3%82%B9%E3%82%B1%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%A9/cupall.md)

# 参考

- [Qiita画像挿入(大きさ変更と外部リンク送付(@hrichii)](https://qiita.com/SUZUKI_Masaya/items/1fd9489e631c78e5b007)
  - できたら一次ソースを教えてもらえると嬉しいです

# 読了後いいね！をお願いします。
どれだけの方に読んでもらっているか知りたいので、お手数をおかけしますがご協力いただけると嬉しいです。
GO(gin)でlocalhstにアクセスできない

## はじめに

macでdockerを使ってgo言語のginを使ってテストサーバにアクセスできない問題を解消したので備忘録に置いておきます。

## 環境


- Mac(Monterey 12.0.1)
- GO 1.17.1

## 結論

サーバ作成時に
``` err := router.Run("127.0.0.1:8080") ```
ではなく
``` err := router.Run("0.0.0.0:8080") ```
とする。

## 問題

今回の環境では、dockerを用いてgoのサーバを建て、hostからgoサーバにアクセスしようとしたところで問題が起きた。
![env.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150694/364a7d0d-291d-ba5e-1d10-1450aef4cd2f.png)

ブラウザで表示しても応答がない。

![404.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150694/0105a467-95a5-7cc3-176e-8980ba1f8c7a.png)
そこで、コンテナの内部で確認してみる。

![success.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150694/9d7c3d6a-2be5-53ca-3749-a8d2c39a0447.png)

ちゃんと応答している。

つまり、サーバはしっかり起動しているので、HostからDocker、またはDockerからサーバのどちらかの経路に問題があることがわかる。

今回はどちらかというとDockerからサーバにアクセスができなかった。
Ginでサーバを作成時に```127.0.0.1```を指定してしまうと、Dockerからはアクセスができないらしい。```0.0.0.0```でアドレスを特定させずにサーバを起動するとDockerからGinにアクセスできる。
この辺の詳細はまた別の機会に。

## まとめ

Ginに限らずnodeなどでもDockerでサーバーを建てるときには```0.0.0.0```で建てるようにしないと同様の問題で時間をとってしまうので気をつけたい
S3のファイルを更新したのにCloudFrontに反映されない場合の対処

### S3ファイルの更新がCloudFrontに反映されない…
AWS S3にAgularのソースを配置し、CloudFront経由でアクセスさせるというWEBアプリを開発していました。
しかし、修正し固めたAngularソースをS3にアップロードしたのに、CloudFrontにアクセスしても修正が反映されていない…
ブラウザのキャッシュかと思いましたが、何回キャッシュクリアしても変わらず。

### CloudFrontにもキャッシュがあった
結論から言うと、CloudFrontがキャッシュを保持しており、そのキャッシュを参照していたため
S3ソースの修正が反映されていませんでした。

CloudFront > ビヘイビア > キャッシュキーとオリジンクエスト
キャッシュポリシーが「CachingOptimized」になっていました。
![キャッシュ１.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453255/4ec53e25-1cdd-86dd-1655-a97c4f96be07.png)

これを「CachingDisabled」にすると、無事にS3ソースの修正が反映されました。
![キャッシュ２.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453255/4257ee57-54aa-f8d9-ae2e-a5a5d75dc0eb.png)



開発中でしょっちゅうS3のソースを更新する場合は、このキャッシュを無効化しておいた方が良さそうです。
リリース時はパフォーマンスの観点から、キャッシュを有効にしたほうが良いかも。
RuboCop のエラーを全て todo に放り込んで安寧を得る

RuboCop のエラーが多すぎて何から手をつければいいかわからない！という事態が、発生するところでは発生するらしいです。
主に、RuboCop のメンテがうまく行っていない場合に。

そんな時に、ある程度の作業をもって RuboCop を正常終了させるやり方を記載します。

## 前提
- RuboCop がアプリケーションに導入されている
- RuboCop が開発環境に install されている
- `bundle exec rubocop` を実行するとエラーが大量に発生して、正直手をつけられない 

## ゴール
- `bundle exec rubocop` が正常終了すること
- 既存コードの問題はスルーされて、新規の違反があった時だけ指摘されるようにすること

## 試したバージョン
- rubocop: 1.22.3

## やり方

### 光の技術

光の技術は、実施するだけで皆が拍手で歓迎してくれるような作業です。

#### layout 系の自動修正

下記コマンドを実行して layout 関連の変更を自動で適用します。

```bash
$ bundle exec rubocop --fix-layout
```

https://docs.rubocop.org/rubocop/usage/basic_usage.html#rubocop-as-a-formatter

自動修正でも少し layout が変になることがあるので、その場合は手動で修正します。
layout 関連の変更なので、基本的に安全な変更になります。

#### lint 系の自動修正

下記コマンドを実行して lint 系の変更を自動で適用します。

```bash
bundle exec rubocop -l -a
```

https://docs.rubocop.org/rubocop/usage/basic_usage.html#rubocop-as-a-replacement-for-ruby-w

`-a` オプションで実行するので、基本的に安全な変更になります。
https://docs.rubocop.org/rubocop/usage/auto_correct.html#safe-auto-correct

### 罪の技術

ここからは罪を背負いながら行う作業です。

#### rubocop_todo.yml の作成

下記コマンドで、 `rubocop_todo.yml` を自動生成します。
https://docs.rubocop.org/rubocop/configuration.html#automatically-generated-configuration

```bash
$ bundle exec rubocop --auto-gen-config --exclude-limit 999999
```

`--exclude-limit 999999` を指定することで、 RuboCop の exclude の default 値である 15 を超えたファイルを exclude に指定できるようになります。

#### rubocop:todo コメントの一括追加

`rubocop --auto-gen-config` では、 `Metrics/AbcSize` などで違反しているファイルを exclude に指定してくれません。
そのため、違反している箇所に直接 `rubocop:todo` を記載します。
`rubocop:todo` は `rubocop:disable` のエイリアスです。
https://docs.rubocop.org/rubocop/configuration.html#disabling-cops-within-source-code

個別に対応するのは大変なので下記コマンドで、 `rubocop:todo` コメントを一括追加します。

```bash
$ bundle exec rubocop --auto-correct --disable-uncorrectable
```

https://docs.rubocop.org/rubocop/usage/auto_correct.html#generating-comments

## 確認

RuboCop を実行して、正常終了するかを確認します。

```bash
$ bundle exec rubocop
```

違反が見つかった場合は、手動で `rubocop:todo` コメントをつけるなどで違反を解消します。
RuboCop の実行が正常終了すると、作業終了です。

罪の意識を対価に安寧を得ます。

## おまけ

罪の意識に苛まれて、贖罪のために書きました。
(書くことで、自分と同じ気持ちになる人を生み出す可能性もあるのですが、気づかなかったことにします)

生み出されてしまった、 `rubocop_todo.yml` に関しては、 `RuboCop Challenger` を使用して解消していく手法が紹介されています。安心ですね。
https://tech.crassone.jp/posts/resolve-rubocop-todos-step-by-step

それでは、良きコーディングライフを。
Ruby rubocop 「Metrics/CyclomaticComplexity: Cyclomatic complexity for index is too high.」エラーへの対処

# 1.状況

ruby 2.6.3p62
rails 5.2.6

Gemfile にコーディングを精査するrubocopをインストールして実行したところ
以下のような警告が発生した

```
app/controllers/public/posts_controller.rb:3:3: C: Metrics/CyclomaticComplexity: Cyclomatic complexity for index is too high. [11/7]
  def index ...
```

該当箇所のコントローラーファイルは以下のようになっていた。

```app/controllers/public/posts_controller.rb
class Public::PostsController < ApplicationController

def index
    # デフォルトは更新日時の降順に並べる
    @posts = Post.all.order(updated_at: 'DESC').page(params[:page]).per(10)
    @range = params[:range] # 並べ替え選択時のページネーションを場合分け
    case @range
    when "投稿Noが新しい順に"
      @posts = Post.all.order(id: 'DESC').page(params[:page]).per(10)
    when "投稿Noが古い順に"
      @posts = Post.all.order(id: 'ASC').page(params[:page]).per(10)
    when "更新日時が新しい順に"
      @posts = Post.all.order(updated_at: 'DESC').page(params[:page]).per(10)
    when "更新日時が古い順に"
      @posts = Post.all.order(updated_at: 'ASC').page(params[:page]).per(10)
    when "ジャンルidが大きい順に"
      @posts = Post.all.order(genre_id: 'DESC').page(params[:page]).per(10)
    when "ジャンルidが小さい順に"
      @posts = Post.all.order(genre_id: 'ASC').page(params[:page]).per(10)
    when "質問者idが大きい順に"
      @posts = Post.all.order(member_id: 'DESC').page(params[:page]).per(10)
    when "質問者idが小さい順に"
      @posts = Post.all.order(member_id: 'ASC').page(params[:page]).per(10)
    when "PV数の多い順に"
      @posts = Post.all.order(impressions_count: 'DESC').page(params[:page]).per(10)
    when "PV数の少ない順に"
      @posts = Post.all.order(impressions_count: 'ASC').page(params[:page]).per(10)
    end
  end
.....
```

Rubyの循環的複雑度をチェックした際にデフォルト値(7)をオーバーしてたために
発生している警告である。

# 2.対処法

Rubyの循環的複雑度を変えるために「.rubocop.yml」の記述を更新する。
具体的に以下とする

```rubocop.yml
# Rubyの循環的複雑度をデフォルト7から変更
CyclomaticComplexity:
  Max: 13
```

自分の場合「CyclomaticComplexity:」の記述は元々記載されていなかったが
「Max: 7」として処理されていた。

.rubocop.ymlの記述を更新後は該当警告文が発生しなくなった。
[Windows][WSL]いちいち更新コマンドを打ちたくない個人の方向け自動化提案

## 結論
`wsl apt update && apt upgrade`をタスクスケジューラに組み込めば完成です。

### 補足
`apt`の実行のために`sudo`コマンドの実行が必要ですが、パスワードの入力が求められます。
**パスワードの自動入力については本稿では扱いません。**

## 分かる人向けの設定画像
タスクスケジューラーを開いて操作タブの設定です。
[<img src = "https://user-images.githubusercontent.com/15845907/144952566-23b04997-38a9-46df-97ac-dd21806de49a.png">](https://user-images.githubusercontent.com/15845907/144952566-23b04997-38a9-46df-97ac-dd21806de49a.png)

## 手順解説
### 1. そもそもタスクスケジューラーとは？

https://qiita.com/nomurasan/items/dba72d1ec1d194b74a33

### 2. 運用面など注意喚起

https://github.com/shimajima-eiji/Chocolatey/blob/master/%E3%82%BF%E3%82%B9%E3%82%AF%E3%82%B9%E3%82%B1%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%A9/wsl%E3%81%AEapt.md

## 応用
要は`wsl`コマンドの後に引数を与えれば何でもできるので、たとえば`apt`コマンド以外にも日常的に使っているコマンドを入れてあげれば良いです。
pythonを使っているなら`wsl pip`とかでしょうか。

`wsl pip install --upgrade pip && pip-review --auto`

## 備考
過去にWSLで開発環境構築について書いていたんですが「やっぱりWSLにcron要らなくね？」と思い直したので、当時の記事で開発環境を作ってしまった個人の方にご一読いただければと思ってます。

https://qiita.com/nomurasan/items/95837a309f4bc8a0dbae

## 参考
- [aptコマンドチートシート(@SUZUKI_Masaya)](https://qiita.com/hrichii/items/a1b9bf03af0232f9125c)

## コメントへのお願い
`apt`コマンドには正しい使い方があると思っていますが、ここに上げていない他の文献やサイトを参考にしても、技術的な違いは分かっても運用上どう使い分けるべきなのか分かりませんでした。
有識者の方には大変申し訳ないんですが、他の読者の混乱防止のため、`aptコマンドについて`というよりは、**「windowsのタスクスケジューラを使ってWSL内のパッケージ等を更新できるよ！」**という点にとどめて、ご意見をいただきたいです。

## 読了後いいね！をお願いします。
どれだけの方に読んでもらっているか知りたいので、お手数をおかけしますがご協力いただけると嬉しいです。
ログの仕込み方について考えてみる

最近案件で学んだのでまとめてみます。

PHPやRubyで開発していると、「データが無い」エラーとか、シンタックスエラーとかよしなに出してくれますよね。

そこで、ログ周りを実装する場合の自分なりの観点をまとめていきたいと思います。

※例として、LaravelのLogファサードを使用しています。適宜読み替えていただければと思います。

## そもそも何でログが必要なの？
これは、人それぞれ観点があると思いますが、僕は主に「トラブルシューティング」の際に役立つと考えています。
想定外のエラーが起きた時、「誰が」「いつ」「何をしようとして」「結果どうなったか」
ということをログから特定することによって、エラー原因の解消に役立ちます。

## ログ出力(修正前)
```php
public function createAction(){
  // フォームから入力された内容を取得(省略)

  try {
    // Articleテーブルにレコード登録
    $article_repository = new ArticleRepository();
    $article_repository->save($入力値);
  } catch (\Exception $e) {
    Log::error('エラーが起きました');
  }
}

```
これだと、保存に失敗した時に「エラーが起きました」としか出てこないので、原因の特定ができません。
「誰が」「何をしようとして」「結果どうなったか」を意識してみます。

## ログ出力(修正後)
```php
public function createAction(){
  // フォームから入力された内容を取得(省略)

  // 操作をしたユーザー取得
  $account_name(操作をしたユーザーを入れておく)
  // ユニークキー取得
  $unique_key = uniqid('', true);

  Log::info('operation_createAction',
      [
          'operation' => [
              'operator' => $account_name,
              'opetation' => 'Create Article',
              'controller' => 'ArticleController',
              'action' => 'createAction',
              'status' => 'before doing',
              'unique_key' => $unique_key,
          ],
          'request' => [
              'user_id' => $user_id,
              'text' => $text
          ],
      ]
  );


  try {
    // Articleテーブルにレコード登録
    $article_repository = new ArticleRepository();
    $article_repository->save($入力値);
  } catch (\Exception $e) {
      Log::error('error_createAction',
          [
              'operation' => [
                  'operator' => $account_name,
                  'opetation' => 'Create Article',
                  'controller' => 'ArticleController',
                  'action' => 'createAction',
                  'status' => 'failed',
                  'unique_key' => $unique_key,
              ],
              'error' => [
                  'exception_message' => $e->getMessage(),
              ],
          ]
      );
  }
}
```
※ログの時刻は自動で設定されるので省略しています
- 「誰が」「何をしようとして」「結果どうなったか」を意識してみました。
- 「誰が」の部分には、`operator`を入れています
- 「何をしようとして」の部分には、`operation`,`request`を記載しています。
- 「結果どうなったか」の部分には、`error`に記載しています

これにより、`どのコントローラーで、何を保存しようとしてエラーが起きたのか`を特定することができます。

- ユニークキーを設定することによって、操作前から操作後の一連の操作をユニークキーで検索することができます。

```
「どんな時にログが使われるか」
「誰が」「何をしようとして」「結果どうなったか」
```

を意識するとログの精度をより高めることができると思います。
RISKENで社内のAWSアカウントのセキュリティを改善した話

# :sweat_drops: 背景
- ウチでもAWSとか使ってるけど、インフラのセキュリティ対策状況ってそもそもどんな状況なの❓
- ちゃんとモニタリングしてなにかあったらアラートされるようにしておかないと危なくない❓ :scream: 

# :thinking: OSSにもなったRISKEN使おう
## RISKEN is 何❓
>`システム環境に潜む リスク情報 を継続的に収集・モニタリングするための セキュリティ オペレーション プラットフォーム です`

[引用元] [RISKEN - RISKEN](https://docs.security-hub.jp/)

>1. RISKENを利用することでセキュリティの問題を発見することができます
1. セキュリティインシデントを未然に防いだり、事故発生時にも調査・対応を行うためのツールとして活用できます
1. また、開発チーム、クラウド管理者、セキュリティ担当者の成果を可視化し、プロダクトオーナーとのコミュニケーションにも役立ちます

AWSやGCPなどのパブリッククラウド環境の利用状況をセキュリティの観点でモニタリングを実施し、対応が急がれる **リスク** :alarm_clock: や
継続してモニタリング対象として管理した方が良い **リスク予備軍** :eyes: を検知してくれます :bangbang: 

# :computer: 早速、社内AWSアカウントを対象に導入してみた
## :thinking:  :eyes: 導入ってどうやるの❓
詳しい説明は [マニュアルサイト](https://docs.security-hub.jp/aws/overview_aws/)があるので、そちらへ譲りますが、
一言でいうと、

### 「対象のAWSアカウントのアカウントIDとIAMロールを作成して、RISKENへ登録するだけ❗❗」

ご自身のAWSアカウントの情報をデータソースとして設定したら、スキャン可能になります👍

スキャンの仕方は[こちら](https://docs.security-hub.jp/aws/overview_scan/)

## さて、社内利用のアカウントのスキャン結果は❓❓
### 検知されたリスク(スコア0.8以上)の件数は下記👇
#### :alarm_clock: **合計：　１０５件**

#### 意外とあるなー・・・・・という印象 :thinking: :thinking: 

### 具体的に検知されたリスク内容は下記でした
- 💣 SSHやMySQLポート等のセキュリティグループ全解放
- 💣 Admin権限所持のIAMユーザの存在
- 💣 ルートアカウントの2FAの未設定
- 💣 CloudTrailの全リージョンでの有効化が未完
- 💣 インポートされた過去の証明書の有効期限切れ

## これだけ検知されたので急いで対応 :sweat_drops: :sweat_drops: :sweat_drops: 
#### 💣 SSHやMySQLポート等のセキュリティグループ全解放
✅ 社用VPNや業務利用NWのIPアドレスのみ許可設定をするように対応

#### 💣 Admin権限所持のIAMユーザの存在
✅ [PERMAN](https://developers.cyberagent.co.jp/blog/archives/33264/) でのコンソールへのログインをさせる設定を実施
✅ 該当IAMユーザについては不要なものは削除
ちょうどタイミングよく、PERMANについてのブログも公開されていたので、紹介 :gift: 

https://developers.cyberagent.co.jp/blog/archives/33264/

#### 💣 ルートアカウントの2FAの未設定
✅ 2FAを設定して対応済み
[仮想 Multi-Factor Authentication (MFA) デバイスの有効化 (コンソール) - AWS Identity and Access Management](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_credentials_mfa_enable_virtual.html)


#### 💣 CloudTrailの全リージョンでの有効化が未完
✅ 全リージョンでのログ取得設定を対応済み
下記のクラスメソッド様の記事を参考に対応ができました。いつもありがとうございます :exclamation: :bow: 
[CloudTrail全リージョン有効化の詳細と個別リージョン設定からの移行 | DevelopersIO](https://dev.classmethod.jp/articles/cloudtrail-multiregiontrail/)


#### 💣 インポートされた過去の証明書の有効期限切れ
✅ 利用されてないことを確認し、AWS CLIにて削除
マネコンではなぜか削除できなかったのが不思議でした :thinking: 

## 最終結果 :thumbsup: 
### BEFORE 
#### :alarm_clock: **合計：　１０５件**

### AFTER
#### :alarm_clock: **合計：　11件**

９割方撲滅しました❗❗❗❗
残りは過去の古い証明書が多く、削除が大変 :sweat_drops: ですが、継続して絶賛対応中です :sweat_drops: 早く終わらせないと :sweat_smile: 

# まとめ
- OSSにもなったRISKENを使って社内AWSアカウントのセキュリティモニタリングを導入した :thumbsup: 
- 全体のリスクのうち **9割** を撲滅でき、さらに継続して監視されることですぐにリスクが検知される状態になった :dash: :heart_eyes: 
- 今後は、コストチェックアラートも導入して、コスト上昇アラートもやれそう :thinking: 
- [RISKEN](https://docs.security-hub.jp/)、チョー便利です❗皆さんもぜひご利用になってみてください :exclamation: 

# その他参考サイト
- [ca-risken/doc: RISKEN is a monitoring tool for visualizing security risks.](https://github.com/ca-risken/doc)
- [[レポート]600 アカウントのセキュリティを見る – AWS Security Roadshow Japan 2021 #awscloud #AWSSecurityRoadshow | DevelopersIO](https://dev.classmethod.jp/articles/aws-security-roadshow-japan-2021-day2-1005/)
Salesforceで今月の商談オブジェクトの金額を取引先に積み上げ集計で表示させる方法

Salesforceで今月の商談オブジェクトの金額を取引先に積み上げ集計で表示させる方法を紹介します。

積み上げ集計項目は、一定の子オブジェクトのレコードに対してのみ集計することは可能
（例；特定のチェックボックスにチェックがある商談レコードの金額のみ集計　は可能）
ですが、今月の商談のみを絞って集計することはできないため、一ひねり必要です。


今回は数ある方法の中でフローを用いた実装を行おうと思います。
前提条件として今回の実装方法の
メリット：標準機能でコード開発不要で容易に作成可能
デメリット：リアルタイムで集計は不可（今回の場合作成および更新時に最大24時間のタイムラグがあります）
（ただし削除時はリアルタイムで反映されます）

さあ、やってみましょう。

###ステップ１　商談にカスタム項目（チェックボックス型）作成
（ポイント　ステップ１で作成した項目は後ほどフローでチェックを付けたりチェックを外したりするための項目です。ですのでフロー以外でチェックを付けたりチェックを外したりさせないため、ページレイアウトに表示するなどはしないでください）
![step1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/ec8b4879-409d-a1b2-98a6-d3bdfcdcc80e.png)

###ステップ２
取引先に積み上げ集計項目作成。
ステップ１で作成した項目がチェック付きのときのみ商談金額が集計されるように設定をします
![step2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/1f61ecc6-e7bd-6aa3-ca60-5a015c0d7f43.png)


###ステップ３
商談に数式項目(チェックボックス型)作成
数式は
Month(CloseDate) = MONTH(TODAY())

です。
この数式により、今月の完了予定日の場合、チェックボックスにチェックが入ります。

###ステップ４ フロー作成
スケジュールトリガーでフローを作成します
![step4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/7cae4881-adcf-09fb-dadd-7aff908c2e11.png)

スケジュールは「毎日」に設定します
![step42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/190b15a3-c6c4-9f87-e681-5f911797e9f6.png)

オブジェクトは「商談」のすべてのレコードの更新にします

「レコードを更新」を２つ作成します。
１つ目の「レコードを更新」はステップ３で作成した数式項目にチェックがついている場合（今月の場合）
ステップ２で作成した項目をチェック付きに更新します。
![step4a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/f7f68b64-54c1-d93b-2ddd-c22a873735e2.png)

2つ目の「レコードを更新」はステップ３で作成した数式項目にチェックがついていない場合（今月ではない場合）ステップ２で作成した項目をチェックなしに更新します。
![step4b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/8b36380c-ccd0-cab8-caf4-340bd865fd01.png)


あとは「有効化」をクリックするだけ
![有効化.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/ecc63a62-1490-d1a7-2999-f68ff6351387.png)

これにより、ステップ２で作成した取引先の積み上げ集計項目には今月の完了予定日の商談の金額が反映されます


###もうひと頑張りープロセスビルダー作成

上記のフローでは最大24時間の誤差が生まれます。
誤差を少しでもなくすために「商談レコード作成時および更新時」に起動するプロセスビルダーを作成してみるのもいいかもしれませんね。

プロセスビルダーの起動条件は下記数式となります
（完了予定日が今月の場合　の数式です）
MONTH([Opportunity].CloseDate ) = MONTH(TODAY())
![プロセスビルダー１.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/c382a741-c317-4833-f0f3-8e95e679e886.png)

更新条件として
ステップ２で作成した項目をチェック付きに更新します。
![プロセスビルダー２.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/26d18008-a582-beb1-3019-b41f5d5e0de7.png)

残りは、商談更新時に完了予定日が今月ではない場合、ステップ２で作成した項目をチェックを外して更新する設定も作成したほうがいいかもしれませんね。
gymのregisterを変更する。

# 目的
Cartpoleタスクの最大ステップ数を増加しよう！

# はじめに
OpenAIGymから提供されている強化学習のMNIST的存在のCartpole
ノーマルのGymからは、`v0`と`v1`が提供されている。
この２つの違いは、タスククリアとなる`max_episode_steps`と
報酬閾値の`max_episode_steps`の違いだけである。

今回はタスククリアの`max_episode_steps`をプログラム内部から書き換え
られないか調べて出来たので記録として残します。

この方法ならば`env.step(action)`での返り値のdoneがTrueになるタイミングを
600stepや111stepのように任意に指定することができるようになります。

また他のタスクにおいても
https://github.com/openai/gym   にある
`openai/gym/blob/master/gym/envs/__init__.py`
の中にあるregisterの値を変更することができると思います。

# やり方
`env._max_episode_steps = 600`
とするだけ
これでタスクは600step立ち続けないとクリアできないタスクになりました！

## サンプルプログラム

```python:
import gym
import numpy as np

#CLI上に変なメッセージが出ないようにする
gym.logger.set_level(40)

#gymとnp乱数の固定 
SEED = 0
np.random.seed(SEED)
env.seed(SEED)
env.action_space.np_random.seed(SEED)#タスクで取り得る行動の中からランダムに選ばれる行動も固定するならここも指定

#ゲーム名で定義
env = gym.make('CartPole-v0')

#!!!!CartPoleの最大ステップ数を変更する!!!!
env._max_episode_steps = 600

observation = env.reset() #環境のリセット

while True:
    #ゲームの中で取りうることのできる行動をランダムに出力する
    action = env.action_space.sample()
    observation, reward, done, info = env.step(action)#行動を入れることで変化が起こる
    print(observation, done, action)#状態とゲーム状態と選択された行動を出力する

    if done:       
        break
```

# 最後に
max_episode_stepsを変更することはできたものの実際にプログラムの中で
この変更された値を確認する手法を見つけることができませんでした。
確認としてはCartpole-v1で学習させたエージェントの実行時に600step倒立できる確認した所
600step倒立できていたので問題はないと思っています。

# 参考ページ
https://github.com/openai/gym/issues/463
AgoraSDKを使って簡易なライブ配信機材を作れるんじゃないか？

この記事は[ライブ配信/ビデオ通話SDK（Agora）を使用したサービスのアイデアを大募集！【PR】V-CUBE](https://qiita.com/advent-calendar/2021/agora)に参加しています。


##ライブ配信用機材
Youtubeや様々なライブに配信する機材が多くあります。

 - LiveShell
 - Matrox Monarch
 - Teradek VidiU

どれもライブ配信に特化していて、ライブ配信には欠かせない機材だと思います。

##ライブ配信機材の要件
前述に書かれているライブ配信機材の要件や、構造等を改めて確認してみます。

 - コンパクトである
 - 簡単に配信ができる
 - YoutubeやFaceBook等のRTMPの口があるサービスに配信できる


##AgoraSDKで類似の配信機材を妄想してみる
AgoraSDKにはWindows用のSDKがあります。[ElectronSDK](https://docs.agora.io/en/All/downloads?platform=All%20Platforms)もあるので実装の敷居を下げることも可能です。
このSDKを用いてライブ配信機材の実現方法を考えてみます。

###構成
以下のような構成になります。コンパクトさを満たす為にはNUC PCが最適かと思います。
カメラはC920e、マイクはJabra Speak 510くらいなコンパクトなものがよいかと思います。
![無題の図形描画 (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43851/04756ff6-ab96-1f88-e1ad-49a35745b16d.png)

次にソフトウェア面ですが電源ボタンを押すだけで配信開始できる仕組みを考えてみます。

1.アプリが起動した時に自動でChannelにJoin＆配信開始するように実装
2.Windowsのスタートアップにアプリを登録

この流れで簡単に配信をする事が可能になります。
この場合、配信先を変える事ができないので、定点カメラの配信などに活用できるかと思います。

###少し柔軟な配信の実現方法
先ほどの仕組みでは決まったChannelのみに配信になってしまいます。配信先を都度変えたい時にはNUC PCにディスプレイをつないで設定したくなります。
ですが、今回の想定では極力機材っぽくしたいので他の方法を考えてみます。

![無題の図形描画 (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43851/58a0a3b5-00a9-c356-2a90-d30229f52cff.png)

1.事前に配信設定をWebAppに登録
2.NUC PC起動（アプリ起動）時に配信設定を取得
3.配信設定を返却
4.配信開始

##おわりに
今回はライブ配信機材の要件を満たすようなSDKの活用方法を考えてみました。
ソフトウェアを自由にカスタマイズできるので完成版の配信機材よりも細かな機材が作れる可能性があると思います。
Javaを利用してWordテキストボックスでテキストの回転方向を設定する方法

##Javaを利用してWordテキストボックスでテキストの回転方向を設定する方法

##背景
Word文書にテキストボックスを追加し、テキストボックスを水平方向のテキスト配置または垂直方向のテキスト配置に設定するか、テキストボックスでテキストの回転方向までも設定できます。Javaプログラムコードにより、上記のテキストボックスの操作も実現できます。以下は、具体的な実装手順を示すJavaコード例です。

プログラムテスト環境は以下のとおりです。
Wordテストドキュメントバージョン：.docx 2019
Word Jarパッケージツール：**[free spire.doc.jar 3.9.0](https://www.e-iceblue.com/Download/doc-for-java-free.html)**
コードコンパイルツール：IDEA
JDKバージョン：1.8.0
ドキュメントの操作に必要なjarパッケージツールをインポートし、結果は以下の通りです：
![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278784/397354ba-d613-0a28-6477-f2f8976d98cf.png)

##Javaコード
```
import com.spire.doc.*;
import com.spire.doc.documents.*;
import com.spire.doc.fields.TextBox;
import com.spire.doc.fields.TextRange;

import java.awt.*;

public class SetTextDirection {
    public static void main(String[] args) {
        //Word文書を作成する
        Document doc = new Document();
        Section section = doc.addSection();

        //ページ余白を設定する
        section.getPageSetup().getMargins().setLeft(90f);
        section.getPageSetup().getMargins().setRight(90f);
        Paragraph paragraph = section.addParagraph();

        //一番目のテキストボックスを追加する
        TextBox textBox1 = paragraph.appendTextBox(280, 250);

        //テキストボックスを固定位置に設定する
        textBox1.getFormat().setHorizontalOrigin(HorizontalOrigin.Page);
        textBox1.getFormat().setHorizontalPosition(150);
        textBox1.getFormat().setVerticalOrigin(VerticalOrigin.Page);
        textBox1.getFormat().setVerticalPosition(80);

        //テキストの回転方向を設定する
        textBox1.getFormat().setTextAnchor(ShapeVerticalAlignment.Center);
        textBox1.getFormat().setLayoutFlowAlt(TextDirection.Left_To_Right);//テキストを回転（反時計回り）
        //textBox1.getFormat().setLayoutFlowAlt(TextDirection.Left_To_Right_Rotated);//垂直テキスト表示

        //テキストを追加してフォントを設定する
        Paragraph textBoxPara1 = textBox1.getBody().addParagraph();
        TextRange txtRg = textBoxPara1.appendText("名前_______番号_________クラス__________");
        txtRg.getCharacterFormat().setFontName("Contour");
        txtRg.getCharacterFormat().setFontSize(10);
        txtRg.getCharacterFormat().setTextColor(Color.black);
        textBoxPara1.getFormat().setHorizontalAlignment(HorizontalAlignment.Center);

        //ファイルを保存する
        doc.saveToFile("Result.docx");
        doc.dispose();
    }
}
```
プログラムを実行すると、Word文書が生成され、文書を開いた後、テキストボックス内のテキスト回転効果を表示できます。さまざまな回転効果を設定することにより、テキストボックスにテキスト効果を表示できます以下の図に示すように：
###Left_To_Rightの回転効果：
![02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278784/5c2aca83-9a6f-52e3-2080-4c4dd3953cbb.png)

###Left_To_Right_Rotated垂直表示効果：
![03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278784/42ecd308-da33-0350-b2da-4591dff446fb.png)

以上は全ての内容でした、最後まで読んでいただきありがとうございます。
share/info/emacsにdirファイルを作る

elispパッケージによっては、infoファイルを`share/info/emacs`に置くものがある。dirファイルにエントリを作らないと、`C-h i`した時にメニューに現れないので不便。
dirファイルの作り方をいつも忘れるのでメモ。

```
cd /opt/homebrew/Cellar/emacs-mac/emacs-*.*-mac-*.*/share/info/emacs
ls *.info.gz | xargs -n 1 install-info --dir=dir
```
macOS Montereyで導入された新しい初期化を試してみる 

# macOS Montereyで追加された初期化を試す。

OSの調子が悪いのと、その他容量が大きくなったので、いっそ初期化してみたところ、Montereyからだいぶやり方が変わっていたのと、躓くところが多かったので記事にまとめておきます。

なんだかんだ言って、半日ほどで復旧完了しました。前は１日以上かかっていたのでだいぶ楽になりました。

## 環境

- M1 MacbookAir
- macOS Monterey
- VScodeがメインエディタ
- dockerやPHP、Nuxtjsなどを行うフロントエンド開発者

## 全てのコンテンツと設定の消去が追加された

macOS Montereyから環境設定appのメニューから`全てのコンテンツと設定の消去`が行えるようになっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65643/c2d07e23-89d7-44c1-ac5d-b8b179abfe44.png)

iPhoneではお馴染みの初期化機能です。OSの再インストールを行わずに工場出荷状態に戻す機能です。

https://support.apple.com/ja-jp/HT212749

今回はこちらの方法から初期化をおこなってみます。

## 必ずTimeMachineバックアップをとる

今回はTimeMachineから復元しないのですが、後述の方法でファイルを抜き出す作業が発生するので、一度全バックアップを取っておきます。


## 指示に従って初期化する

TimeMachineバックアップがあれば、最悪どんな方法でも復元できるので、自信を持って指示に従って行きます。

## 初期化時間は30分かからなかった

30分もしないうちに、アクティベート画面が開きました。私は有線LANなので何もしなくてよかったのですが、無線LANの人はパスワードなどを入れてネットワーク環境に繋いでアクティベートを続けます。

## 初期化完了

いつものiCloudログインなどをおこなって初期化完了しました。

## ソフトのインストール

業務に必要なソフトは主に以下の通り、

- VSCode
- docker
- Chrome
- Slackやzoomなどのコミュニケーションツール
- Microsoft Office
- Adobe CC

このうちSlackやOfficeはAppStore版を使っていたので、ログインして再ダウンロードをポチポチして終わりです。
AdobeCCもCreativeCloudアプリから最新版をインストールしました。

### 手間取ったところ

#### PHPがない

MontereyにはデフォルトでPHPがありません。Monterey移行時にもおこなったPHPのインストールが必要です。

homebrewから入れてみます。

https://brew.sh/index_ja

```
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```

その後PHPのインストール

```
brew upgrade
brew search php
brew install php
```

ついでに古いシステム用にPHP7.4もインストールします。

```
brew install php@7.4
```

切り替えがうまくいかなくて悩んだのですが、brewのシンボリックリンクを変えてなかったのが敗因でした。

```
brew unlink php
brew link php@7.4

// その後指示に従いシェルの設定に追加する
echo 'export PATH="/opt/homebrew/opt/php@7.4/bin:$PATH"' >> ~/.zshrc
echo 'export PATH="/opt/homebrew/opt/php@7.4/sbin:$PATH"' >> ~/.zshrc
```

### sshファイルを忘れてた

sshの鍵を忘れていたのでTimeMachineから復元しました。

メニューバーのTimeMachineアイコンをoptを押しながら開くと`ほかのバックアップディスクをブラウズ...`という項目が現れ、初期化前にバックアップしたファイルを閲覧することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65643/ec12daba-582a-328c-23d4-94fc93927c2e.png)

ここから無事に.sshフォルダごとコピーして事無きを得ました。

その他にもアプリの設定ファイルなどがあれば随時TimeMachineからコピーして行きます。


### GithubとかBitBucketとかの情報

最近はブラウザログインができるので、VSCode上からGitのサービスへのログインを行うことができて、SSHとかで厳密にログインしなくても大丈夫でした。

### ほとんどSilicon対応している

インストールして気づいたのですが、ほとんどのアプリはSilicon対応しているので、M1 MacbookAirが出始めた時から使っていたごちゃごちゃした環境が一気にスッキリしたように思います。

#### nodebrewがちょっと特殊

nodebrewでnodeをインストールする際にnode14はsilicon対応しているのですが、バイナリが提供されていないので、コンパイルする必要がありました。

```
nodebrew compile v14
```
nodebrewフォルダが巨大になりがちなので、必要であれば`nodebrew clean`も行ってソースファイルを削除しましょう。
3年間のコーディング規約の変遷に見る Kotlin の変化

この記事は[ドワンゴ2021年アドベントカレンダー](https://qiita.com/advent-calendar/2021/dwango)12/8の記事です。
昨日は @yoshikyoto さんの [動画サービスの部署から課金システムに来て学んだこと](https://qiita.com/yoshikyoto/items/9b83e8625451378bdc9e) でした。

先日、Kotlin 1.6.0 がリリースされました。

https://blog.jetbrains.com/kotlin/2021/11/kotlin-1-6-0-is-released/

個人的に Kotlin の[公式コーディング規約](https://kotlinlang.org/docs/coding-conventions.html)の日本語訳をまとめています。
3年ぶりに更新してみたところ、更新差分から3年間の Kotlin の変化が垣間見えました。
ちなみに、3年前というと、Kotlin [1.2.20](https://github.com/JetBrains/kotlin/releases/tag/v1.2.20) くらいのころです。
年の瀬に今年（3年分？）の Kotlin のまとめと振り返りということで、トピックを3つ取り上げてご紹介します。

## Kotlin Multi Platform

3年前のコーディング規約時点では、「Javaの推奨に従う」という記述がいくつか見られました。
現在では、この3年の間に推進された Kotlin Multi Platform に伴い、このような記述はより具体化されて置き換えられています。

Kotlin は Java との相互運用が容易であるというのがアピールポイントのひとつです。
3年前の時点ではベター Java としての側面が大きかったと思います。
Java バージョンの制約が厳しかった当時の Android 開発における有力な選択肢となり、現在では Android 公式が推奨する言語となっています。

以上の背景から、当時のコーディング規約においても、「Javaの推奨に従う」という文言が散見されていました。
Java との相互運用を念頭においているので、コーディング規約上も Java 文化に親しい人が読む想定だったのでしょう。

現在では Kotlin は Multi Platform を推進しています。
Kotlin/JVM だけでなく、 Kotlin/Native、 Kotlin/JS と拡大しています。
モバイルに限らず Web やデスクトップ、バックエンドなど広範な範囲をカバーする言語として進化しています。
現在でもベター Java という側面はありますが、それは当たり前の周知の事実です。
むしろ、Java 文化に親しいとは限らない、様々なバックグラウンドの人々が Kotlin を選択することが増えました。
結果、「Javaの推奨に従う」という記述はより具体的になりました。

## 末尾カンマ（trailing comma）

3年の間に様々な機能が Kotlin には追加されてきました。
多くの機能の中でも、コーディング規約に記載されるようなものは、Kotlin エンジニアが目にする機会が多い汎用的な機能と言えるでしょう。
そんな機能が 末尾カンマ（trailing comma）です。

末尾カンマは複数の要素を列挙する際に、最後の要素の後ろにもカンマを付けられる機能です。
[Kotlin 1.4](https://kotlinlang.org/docs/whatsnew14.html) で追加されました。
Javascript など他の言語にもありますね。

```kotlin
class Person(
    val firstName: String,
    val lastName: String,
    val age: Int, // trailing comma
)
```

上記の例では、 `age` の後ろにあるのが末尾カンマです。

末尾カンマの効用は規約上も[いくつか挙げられています](https://kotlinlang.org/docs/coding-conventions.html#trailing-commas)。

- バージョン管理での差分がきれいになる（末尾カンマがない場合、末尾に要素を足すと直前行の末尾にもカンマをつける必要があります）
- 要素の追加・順番の変更が簡単になる（末尾カンマがない場合、カンマをつけたり消したりする必要があります）
- コードの自動生成が容易になる（末尾の要素かどうかでカンマの有無を分岐する必要がありません）

個人的にも上記効用には同意するところで、この機能が追加されたときはとても嬉しかったです。
3年間の更新差分のうち、コーディング規約上にまとまった文章が追加されたのはこの機能だけでしたので、普段のコーディングで助けになる機能であることは間違いないでしょう。

一方でコーディング規約は、末尾カンマの利用を推奨してはいるものの、実際の利用は利用者の判断に委ねるとしています。
各々のチームで合意をとるとよいでしょう（IDEで設定することも可能です）。

## Scope functions

Kotlin の便利な標準ライブラリの関数がスコープ関数 - `let`、`also`、`apply`、`run`、`with` - です。
これらの関数は便利な一方で、むやみな使用はコードの可読性を下げる要因にもなります。
チームによっては特定のスコープ関数の利用を制限していることもあるかもしれません。

もともと、コーディング規約にもそれなりの分量でスコープ関数の利用指針が記載されていました。
時を経て、スコープ関数はそれ単体で記事が切り出されました。

https://kotlinlang.org/docs/scope-functions.html

この変遷はスコープ関数の存在感の大きさを示していると感じます。

現在は[大まかな選択指針](https://kotlinlang.org/docs/scope-functions.html#distinctions)と[それぞれの関数の利用方法](https://kotlinlang.org/docs/scope-functions.html#functions)が記載され、よりわかりやすくなりました。
いずれかの関数の利用が非推奨ということもありません。
みなさんも用法用量を守って、適切にご利用ください。

# 終わりに

コーディング規約の変遷から、大きなトピックと感じた3つについて紹介しました。

次回は 12/9 @macinjoke さんの Web フロントエンドについての記事です。
お楽しみに！
【React】 配列 に対して UseState を使用する

■前提
Reactの実行環境がある。
App.jsでsample.jsをimport及び呼びだすコードがある。

■以下前提のコード

```react:sample.js
import React, {useState} from 'react'
const sample= () => {
}
export default sample
```
■以下state(sampleobject)とstateを更新するための関数(setsampleobject)を定義する。
　また、値を追加していく変数（newsampleobject）も定義する。

```react:sample.js
import React, {useState} from 'react'

const sample= () => {
    const [sampleobject, setsampleobject] = useState([])
    const newsampleobject = () => {
        setsampleobject([...sampleobject,{
            id: sampleobject.length,
            name: "Hello"
        }])
    }
    return (
        <>
        </>
    )
}
```

■以下ボタンと配列の内容を展開する処理を追加。

```react:sample.js
import React, {useState} from 'react'

const sample= () => {
    // 以下オブジェクト（sampleobject, setsampleobject）を定義する。
    const [sampleobject, setsampleobject] = useState([])
    const newsampleobject = () => {
        setsampleobject([...sampleobject,{
            id: sampleobject.length,
            name: "Hello"
        }])
    }
    return (
        <div>
            <button onClick={newsampleobject}>Add New sampleobject</button>
            <ul>
                {sampleobject.map(sampleobject =>(
                    <li key={sampleobject.id}>{sampleobject.name} id: {sampleobject.id}</li>
                ))}
            </ul>

        </div>
    )
}
```
■結果
ボタンを押すと、Hello id: 連番　が表示される。