OmniAICreator/Qiita-1.07M huggingface dataset:
TensorFlow Lite 実行環境を作る win/linux

実行するだけなら本来ランタイムだけでいいのですが、[windowsではTensorFlowLiteのruntimeはサポートされていない](https://www.tensorflow.org/lite/guide/python?hl=ja)ので、tenosrflowパッケージを丸々インストールします。

従って、同じ実行コードを使うなら、linux/winでimport文が変わります。
こんな風に書けばよしです。

```python
try:
    # linux
    import tflite_runtime.interpreter as tflite
except ImportError:
    # win
    from tensorflow import lite as tflite
```

バージョンによって問題が置きがち（特にnumpy, 組み込み向けのとき, 開発と実行環境が別のとき）なのでバージョン指定します。
`tensorflow`と`tflite-runtime`は同じバージョンNo.でよしです。

最終的には[Requirements File](https://pip.pypa.io/en/latest/reference/requirements-file-format/)をちゃんと書いてあげたいところです。

ほとんどの場合PILとnumpyが必要なので書いてあります。
他の必要なモジュールは追加してください。


# windowsでpipで

```powershell
py.exe -m pip install numpy==1.19.3
py.exe -m pip install pillow==9.0.1
py.exe -m pip install tensorflow==2.10.0
```

# linuxでpipで

```powershell
python -m pip install numpy==1.19.3
python -m pip install pillow==9.0.1
python -m pip install tflite-runtime==2.10.0
```

# pyenvするなら

それぞれ次のコマンド

始めるとき

```powershell
venv DIRNAME
.\DIRNAME\Scripts\activate
```

抜け出すとき

```powershell
deactivete
```

# pipがないとき

<https://pip.pypa.io/en/stable/installation/#get-pip-py>に従って

[get-pip.py](https://bootstrap.pypa.io/get-pip.py)をダウンロードして、これを
* win: `py get-pip.py`
* linux: `python get-pip.py`
Leetcode 231. Power of Two

# 231. Power of Two

https://leetcode.com/problems/power-of-two/description/

```java
class Solution {
    public boolean isPowerOfTwo(int n) {
        if(n == 0){
            return false;
        }
        if(n == 1){
            return true;
        }

        while(n != 1){
            if(n % 2 == 0){
                n /= 2;
            }else{
                return false;
            }
        }
        return true;
    }
}
```
WEB土方におくる、Figmaとフリーソフトを使い倒したUIデザインの全工程を公開

## 無職の友人を救う為、外道が立ち上がる

デベロッパーの皆さん、ご機嫌よう。
ここ最近、色々と環境の変化があり、プログラムとは関係のない職種に就職したりで、投稿の期間があいてしまいました。お待たせしました。**（誰も待っていない）**

先日長く無職の友人から、 **おい、ウェブサイトの作り方を教えてくれや** みたいな事をおりいって相談され、どうもWordPressサイトの更新作業とか、そういうフリーランス的な仕事の話があるらしく、まあ時間がある時でも教えてやるかと思い、初めから1on1で教えるのも、知り合い相手だとグダグダしてしまったりするといくら時間あっても足りないし、そもそもオレはボランティアで教えるわけであって、老い先短い貴重な時間をそういう無為な事に浪費したくないな等と色々と考えていたのですが、基本的な部分は動画を作ってやるか　という事で動画にする事にし、よく考えたらこいつ一人の為に動画を作るんだったら、YouTubeにでもあげたらもっと多くのウェブ初心者の役にたち、 **一人でも多くの無職やめたろうを作れるかも知れない** と思い立ち、また、最近ショップを持っている友人が、ウェブサイト制作を外注してボられたという話も聞いており、面倒臭いながらもYouTubeコンテンツ化するに至りました。

多くの失敗をし、人生に於いて特に何事も成し遂げられず、要所要所で道を踏み外してきた外道なオレでも、１人に役立つなら、１０人。１０人に役立つなら、１００人くらいには役に立つんではないだろうかと。多くの無職辞めたろうさんを作れるんじゃないかという希望を持ちつつ、最初のコンテンツを挙げてみました。結果、
 **２４時間経ちましたが、勿論登録者0、視聴数１桁** です。
連戦連勝のプログラマー諸先輩方には別に興味がない内容かとは存じますが、フロントのデザインに関するコンテンツはバックエンドのプログラマー諸氏にも多少役立つ部分があるんではないかと、あと、自分でショップを持っている人や、趣味のサイトを欲しい非プログラマの人達には役に立つんじゃないかという事で、とりあえずここで宣伝させて頂きます。
<br>

<iframe width="560" height="315" src="https://www.youtube.com/embed/6E0yCIVRsQ8" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

<br>
日本語でWordPress関係の動画を検索してみたら、うさんくさいアフィリ系のやつとかが大量に出てきたのですが、ちゃんとPHP/Laravel/SQLあたりから掘り下げたコンテンツがあると良いのになあと。<br>
WordPressサイトって、プログラマー界隈からは軽くみられている感じがしますが、世界のサイトの４割以上はWordPressサイトであり、今の時代、中小企業のサイトや、ショップ、趣味のページなどをわざわざ一からコードを書いて構築する阿呆はいないでしょう。<br>
というわけで、せっかくチャンネル化したのだから、おっさんがビールを飲みながらプログラミングをやるという体で、ReactやJavescript、Flutterなんかの個人的に学習している言語についてのコンテンツを、不定期でも備忘録がわりにあげていける場に出来ればなあとイメージしています。
【AWS】EBSボリュームタイプのGP2とGP3についてまとめる

## はじめに
EBSのボリュームタイプである GP2 と GP3 の違いについてご紹介します。

## GP2 と GP3 についての説明
### GP2とは？
- Amazon EC2 インスタンスのデフォルトの EBS ボリュームタイプ
- ボリュームはSSDを基盤としている

#### GP2の特徴
- 汎用 SSD (gp2) ボリュームのボリュームストレージの料金はプロビジョニングした容量 (GB/月) で決定される。
    - ストレージを解放するまで毎月料金が発生する。
- gp2ボリュームのプロビジョニング済みストレージは、 1秒 毎に課金される.
    - 最小課金時間は 60秒
- I/O はボリュームの料金に含まれている

##### 料金

|  ボリュームタイプ  |  料金  |
| ---- | ---- |
|  汎用SSD (gp2) ボリューム | 1ヶ月にプロビジョニングされたストレージ 1GB あたり 0.12USD  |

##### 詳細情報

|  項目  |  特徴  |
| ---- | ---- |
|  ボリュームタイプ  | EBS 汎用 SSD (gp2)  |
|  ユースケース  |  ブートボリューム、インタラクティブで低レイテンシーのアプリケーション、開発およびテスト環境  |
|  API名  |  gp2  |
|  ボリュームサイズ  |  1GB 〜 16TB  |
|  耐久性  |  99.8% 〜 99.9% の耐久性  |
|  最大IOPS/ボリューム  |  16,000  |
|  最大スループット/ボリューム   |  250 MB/秒  |
|  最大IOPS/インスタンス |  260,000  |
|  最大スループット/インスタンス  |  7,500 MB/秒  |
|  レイテンシー  |  1桁のミリ秒  |
|  料金  |  1月 あたり 0.10 USD/GB  |
|  主なパフォーマンス属性  |  IOPS |

### GP3とは？
- 最新世代の汎用 SSD ボリューム
- Amazon EC2 インスタンスのデフォルトの EBS ボリュームタイプ
- ボリュームはSSDを基盤としている

#### GP3の特徴
- 汎用 SSD (gp3) ボリュームのボリュームストレージの料金はプロビジョニングした容量 (GB/月) で決定される。
    - ストレージを解放するまで毎月料金が発生する。 (gp2 と同じ)
- 全てのgp3ボリュームには、以下が含まれる。
    - 3,000 のプロビジョンドIOPS(1秒あたりの入力/出力操作)の無料のベースラインパフォーマンス
    - 125 プロビジョンド MB/秒スループットが含まれる

##### GP3の料金

東京リージョンの料金になります。(2022/10/22時点)

|  ボリュームタイプ  |  料金  |
| ---- | ---- |
|  汎用SSD (gp3) | 0.096USD/GB 月  |
|  汎用 SSD (gp3) - IOPS  |  無料の 3,000 IOPS <br>および 3,000 を超えた分について 1ヶ月におけるプロビジョンド IOPS あたり 0.006 USD  |
|  汎用SSD (gp3) - スループット | 無料の 125 MB/秒<br>および 125 を超えた分について 1ヶ月におけるプロビジョンド MB/秒あたり 0.048USD  |

##### 詳細情報

|  項目  |  特徴  |
| ---- | ---- |
|  ボリュームタイプ  | EBS 汎用 SSD (gp3)  |
|  ユースケース  |  ・仮想デスクトップ<br>・MSFT SQL Server や OracleDB などの中規模のシングルインスタンスデータベース<br>・低レイテンシーのインタラクティブアプリ<br>・開発とテスト<br>・ブートボリューム  |
|  API名  |  gp3  |
|  ボリュームサイズ  |  1GB 〜 16TB  |
|  耐久性  |  99.8%〜99.9%の耐久性 |
|  最大IOPS/ボリューム  |  16,000  |
|  最大スループット/ボリューム   |  250 MB/秒  |
|  最大IOPS/インスタンス |  260,000  |
|  最大スループット/インスタンス  |  7,500 MB/秒  |
|  レイテンシー  |  1桁のミリ秒  |
|  料金  |  1月 あたり 0.10 USD/GB  |
|  主なパフォーマンス属性  |  IOPS |

## 参考

https://aws.amazon.com/jp/ebs/volume-types/

https://aws.amazon.com/jp/ebs/pricing/

https://blog.serverworks.co.jp/ebs-gp3-vs-gp2

https://aws.amazon.com/jp/ebs/pricing/
モデルが保持している特定の値だけ保存したい

フォームオブジェクト(ActiveModelをincludeしている)が保持している特定の値だけ、DBに保存したいというケースがあったので参考までにまとめてみます。
DetailFormというフォームオブジェクトそれぞれにa_type~d_typeまでの値が保持されている。また下記の内容を親フォームがdetailsというaccessor名で保持しているとする。

```ruby
[#<DetailForm:xxxxx
   @attributes=#<ActiveModel::AttributeSet:xxxxx @attributes={}>,
   @a_type="aaa_1",
   @b_type="bbb_1",
   @c_type="ccc_1"
   @d_type="ddd_1">,
  #<DetailForm:xxxxx
   @attributes=#<ActiveModel::AttributeSet:xxxxx @attributes={}>,
   @a_type="aaa_2",
   @b_type="bbb_2",
   @c_type="ccc_2",
   @d_type="ddd_2">]
```
これを今回は下記のような形で、d_typeを除く、a_type~c_typeまでの値を保存したいとする。
```
[
    {
        "a_type"=>"aaa_1",
        "b_type"=>"bbb_1",
        "c_type"=>"ccc_1"
    },
    {
        "a_type"=>"aaa_2",
        "b_type"=>"bbb_2",
        "c_type"=>"ccc_2"
    }
]
```

### 実装方法

```ruby
class DetailForm

  include ActiveModel::Model
  include ActiveModel::Callbacks
  include ActiveModel::Attributes
 
  define_model_callbacks :initialize

  attr_accessor :a_type
  attr_accessor :b_type
  attr_accessor :c_type
  attr_accessor :d_type

  def initialize(param)
    run_callbacks :initialize do
      self.a_type = param['a_type']
      self.b_type = param['b_type']
      self.c_type = param['c_type']
      self.d_type = param['d_type']
      super
    end
  end

  #
  # ハッシュ指定をして、DetailFormの保持しているa_type~c_typeまでの値を詰める
  #
  def attributes
    {
      'a_type' => a_type,
      'b_type' => b_type,
      'c_type' => c_type
    }
  end
end
```
attributesメソッド用意(関数名は何でも良い)してやって、各DetailFormインスタンスの保持している値を今回保存したい形式に合わせてセットする。最終的な呼び出しは以下のようになった。
```ruby
save_type = details.map(&:attributes)
```
detailsには最上部で話したように、各DetailFormオブジェクトのインスタンスを保持しているので、それぞれのインスタンスからattributesを呼び出して、mapしてそれぞれのインスタンスが保持している値をattributesを通してセットしてやるような流れができた。これでsave_typeには当初の保存したい形式で格納することができた。後はこれをsaveしてやるだけで完了。

## 終わりに
以上簡単ではありますが、今回のようなケースがあれば参考にして頂ければと思います。こうして後から見てみると難しいことはやってないのですが、ここに至るまでの発想には思ったより時間がかかったので、まだまだ勉強していかないとですね...
CHKOUT ,CHKIN コマンドで簡易的な排他をする

IFS上に存在するファイル（テキスト,ini,PHP,JS,etc...）を、**読み取り／複製** は可能だが、**変更／削除** をさせない状態にするコマンド、`CHKOUT/CHKIN` をご紹介。

## コマンドの使い所
何かの作業中（または常用的）に、開発者のミスで大事な設定(ini,conf)等を誤って変更／削除しない様にブロックさせる、簡易的な排他に使うなどなど。
例えば、PHPサーバー（CS^2、CP+など）のインストール作業中、後に、`/www/xxx/conf/httpd.conf` を変更をブロックしたいとする。

## 方法

### 使用するコマンド
- `CHKOUT`:排他ON [オブジェクトのチェックアウト  (CHKOUT)](https://www.ibm.com/docs/ja/i/7.5?topic=ssw_ibm_i_75/cl/chkout.html)
- `CHKIN` :排他OFF [オブジェクトのチェックイン  (CHKIN)](https://www.ibm.com/docs/ja/i/7.5?topic=ssw_ibm_i_75/cl/chkin.html)

`CHKOUT`コマンドでは、`CHKOUT` を実行したカレント・ユーザー以外は、**読み取り／複製** のみ可能となる。例え **ALLOBJ** のユーザーでも **変更／削除** は出来ない。


### 排他ON/OFF手順
1. 作業者と異なるユーザープロファイル（**HOGEUSER**）でサイオンする
2. 排他ON **HOGEUSER** が `CHKOUT OBJ('/www/cs2/conf/httpd.conf')` を実行する
3. ～～～ 何らかしらの作業　～～～ ※この間 **HOGEUSER** 以外変更不可
4. 排他OFF **HOGEUSER** が `CHKIN OBJ('/www/cs2/conf/httpd.conf')` を実行する

もし排他ONの状況で削除したりすると、以下の様になる。
![2022-11-11_142854.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100029/e264e286-ad95-eef0-622a-ca6c7c69161a.png)

## 使い方・その他
1. オプション `SUBTREE(*ALL)` サブディレクトリ配下のオブジェクトも対象。
2. オブジェクトパスの指定にパターンマッチが使用可能。
    - **(A)** `*` :任意の文字列 `CHKOUT OBJ('/home/ushiday/temp/a*')`
    - **(B)** `?` :任意の文字 `CHKOUT OBJ('/home/ushiday/temp/a00?0.txt')`

以下は、上記 **(A)**と**(B)** でマッチするオブジェクト例

```text
/home
　├ ushiday/
    　└ temp/
         ├── a.txt (A)
         ├── a001.txt (A)
         ├── a0020.txt (A)(B)
         ├── a0030.txt (A)(B)
         ├── b.txt
```

## 考慮点
- オブジェクト（ファイル）のみが排他され、ディレクトリは排他されない。
- 排他オブジェクトを含むディレクトリは、リネーム可能。削除は出来ない。
- `CHKOUT` 中にディレクトリ・リネームしたら、`CHKIN` はリネーム後のパスで行う。
- `CHKOUT` 可能なオブジェクトは限られている。※詳細は公式リンク参照
- `CHKOUT` 中の一覧が分からない（※今のところDSP系コマンド見つからず）
【livewire × FullCalendar】動的なスケジュールアプリを作ろう。Part2【ドラッグ&ドロップで予定移動】

前回

https://qiita.com/sgrs38/items/16434cc7f3b2b55d7c3d

# 予定一覧コンポーネントを改修

## LivewireAlert読み込み
``use LivewireAlert;``

```php:app/Http/Livewire/Schedule/Index.php
<?php

namespace App\Http\Livewire\Schedule;

use App\Models\Schedule;
use App\Models\User;
use Carbon\CarbonImmutable;
use Jantinnerezo\LivewireAlert\LivewireAlert;
use Livewire\Component;

class Index extends Component
{
    use LivewireAlert;
```

## コンポーネント:PHP側追記
```php:app/Http/Livewire/Schedule/Index.php
//予定の移動
public function moveEvent($info):void
{
	$startDateTime = (new CarbonImmutable($info['event']['start']));
	$endDateTime = (new CarbonImmutable($info['event']['end']));
	$schedule = Schedule::query()
	->find($info['event']['extendedProps']['schedule_id']);
	$schedule->day = $startDateTime->format('Y-m-d');
	$schedule->start = $startDateTime->format('H:i');
	$schedule->end = $endDateTime->format('H:i');
	if (!is_null($info['newResource'])) {
	    $schedule->user_id = $info['newResource']['id'];
	}
	$schedule->save();
	$this->alert('success', '移動完了');
	$this->refreshCalendar();
}

```
## コンポーネント:Blade側追記
FullCalendarの設定部分に追記します。

```js:resources/views/livewire/schedule/index.blade.php
//ドラッグなどでのイベント変更許可
editable:true,
//イベントをドロップした時の処理
eventDrop: function (info) {
    @this.moveEvent(info);
},
```

## こんな感じに動く
![](https://storage.googleapis.com/zenn-user-upload/97cf63735d52-20221111.gif)
Julius音素セグメンテーションキットを使うためのWAVファイルフォーマット変換

### Julius音素セグメンテーションキットとは
wavファイルとtxtファイルを用意してsegmentation-kitを実行することで、言葉の音素がどのタイミングで発せられているのかをミリ秒で出力してくれます。詳細は下記をご覧ください。

https://github.com/julius-speech/segmentation-kit

### WAVファイルのフォーマット次第では動かない
当初はとりあえずwav形式の音声ファイルならどんなものでも動くと思っていたのですが、たまに出力が空になる現象に遭遇しました。エラーなども出ていなかったため、少し詰まりました。しかしlabファイルと同時に生成されるlogファイルの中身をよく見てみると、`Error: adin_sndfile: invalid format`　といったエラーがはかれていました。ファイルのフォーマットが違うということで改めて[julius-speech/segmentation-kit](https://github.com/julius-speech/segmentation-kit)のREADMEを見に行くと、次の内容が記載されていました。

>音声ファイルは WAV形式で 16kHz, 16bit, PCM（無圧縮）形式である必要があり ます。テキストファイルはテキスト形式で、文字コードは UTF-8です。

つまり使えるフォーマットが決まっており、それに対応する必要があるということでした。ちゃんとドキュメントを熟読してから使わないと思わぬ時間を取られてしまうという例でした。

https://github.com/julius-speech/julius/blob/master/libsent/src/adin/adin_sndfile.c

### 変換コード
以上よりJuliusに対応するフォーマットにwavファイルを変換しましょう。変換後のwavファイルを用いて実行すれば問題なく動きます。`librosa.core.load`の`sr`はサンプリングレートのことであり、 `16000`Hzに指定します。そして出力の際に`subtype`を`PCM_16`とすることで量子化bit数を16bitにする事ができます。

```py
import librosa
import soundfile as sf

y, sr = librosa.core.load('sample.wav', sr=16000, mono=True)
sf.write("new_sample.wav", y, sr, subtype="PCM_16") 
```

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

- [julius-speech/segmentation-kit](https://github.com/julius-speech/segmentation-kit)
- [Python入門 (9) - wavのサンプリングレートの変更](https://note.com/npaka/n/n6f421b546024)
- [pythonでwavファイルのサンプリングビット数（量子化ビット数）を変換する](https://shirowanisan.com/entry/2020/11/29/141956)
rails resourcesメソッドの使い方

railsのresourcesメソッドを使う上で必要になった知識等を記録。

## 構文
```ruby:config/routes.rb
Rails.application.routes.draw do
  namespace :api do
    resources :events, only: %i[index create]
  end
end

```
ルーティングを`get user/index => user#index`みたいな感じじゃなくて、勝手にやってくれる。そのままだと全てのアクションにルーティングされるため`only`を使って使うアクションを限定する。

## :idを別の名前に変更する
resourcesでshowなどをルーティングすると末尾が必ず`:id`というURLでリクエストを送ることになる。このこれを変えたいときは
```ruby:config/routes.rb
Rails.application.routes.draw do
  namespace :api do
    resources :events, only: %i[show], param: :hashed_id
  end
end
```
と設定すると`api/events/:hashed_id`って感じでルーティングしてくれる。
## RESTful
HTTPリクエストを経由してフロントとバックエンドをしっかりと分けるときの設計思想。railsの開発は基本的にこの設計思想に基づいて行われているらしい。
この設計思想をルーティングに反映するためにちまちま`get api/index => api#index`みたいに書くんじゃなくてresourcesを使うことで簡単に反映させることができる。

## 実際のルーティンを確認するコマンド
```bash:terminal
rails routes
```
これで実際にrailsで行われているルーティングが確認できる


## 参考
https://zenn.dev/iloveomelette/articles/c3c5cbd280b901

https://pikawaka.com/rails/resources

https://qiita.com/KNR109/items/d3b6aa8803c62238d990#http%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89

https://qiita.com/NagaokaKenichi/items/6298eb8960570c7ad2e9

https://qiita.com/NagaokaKenichi/items/0647c30ef596cedf4bf2
direnvで設定された環境変数はVSCodeで反映されない!?と思っていたら初歩的なミスでした。


ここで参照する本は**Go言語でつくるインタプリタ**(ISBN: 978-4-87311-822-2)、(以下、猿本と言います)。
この本のソースコード群をダウンロードして使用しているので、ディレクトリ構成とかは本に従います。
***
大学の授業で猿本を教科書として使用しています。授業資料に従うがまま環境(`$GOPATH`、`$GOROOT`等の環境変数の設定など)を整え、Ubuntuのターミナル上でプログラムを実行させることはできたのですが、しかし、VSCode上では環境変数の設定が反映されていないようで、
```text:/01/src/monkey/main.go
could not import monkey/repl (cannot find package "monkey/repl" in any of 
	/usr/lib/go-1.18/src/monkey/repl (from $GOROOT)
	/home/***/go/src/monkey/repl (from $GOPATH))
```
とエラーが出ます。
どうやら`$GOROOT`と`$GOPATH`から辿った先には`monkey/repl`なんてパッケージは無いよーとのこと。
これは環境変数がうまく設定できてないことによります。なので、授業資料でやったdirenvとかの意味を理解することも兼ねて、設定をしていきたいと思います。
(以降`***`はユーザーネーム等、猿本によらないディレクトリ等です)

# 結論
設定をしていきたい…と思ったのですが、いろいろやっているうちに**direnvによって環境変数が設定された状態でVSCodeを起動**すればいいと気づきました。当たり前ですねぇ…
具体的には、

```terminal
***@***:~$ cd ***/waiig_code_1.4/01
direnv: loading ~/***/waiig_code_1.4/01/.envrc
direnv: export +GOPATH
***@***:~/***/waiig_code_1.4/01$ code .
```
こういうことです。

## 授業資料では何をしていたのか
授業資料では
1. direnvの設定
2. GO111MODULEの設定

をしています。
環境変数の設定にはdirenvが関わっているので、情報整理がてら何を設定していたのか見ていくとします。(GO111MODULEは、資料にあった通り言語のバージョンによるものなので今回は割愛です。)
### direnvとは
簡単に言うと[ディレクトリごとに環境変数を定義してくれる奴][1]で、`.envrc`が存在するディレクトリごとに環境変数を発行してくれるそうな。
猿本のソースコード群には章のディレクトリごとに下のような`.envrc`が用意されていて、`$GOPATH`はここにて設定されています。
```text:/01/.envrc
export GOPATH=$(pwd)
```
この中の`$(pwd)`は[ディレクトリのパスを返してくれるコマンド][2]。
direnvが正常にインストールされていれば、`.envrc`が存在するディレクトリに入ったら
```text
direnv: loading ~/***/waiig_code_1.4/01/.envrc
direnv: export +GOPATH
```
と出力されるので
direnvが`.envrc`を発見、ロードする->`.envrc`があるディレクトリのパスを`$GOPATH`として設定する
といった[流れ][3]が見えます。
何が言いたいのかというと、~~**VSCode側でも`.envrc`があるディレクトリのパスを`$GOPATH`として設定してやればいい**のです。~~
***
やりたかったこととしては、「`tasks.json`内で`export GOPATH=${一番近い階層の.envrcのパス}`を実行する」なんですけど、そもそもVSCodeのターミナル内で環境変数書き換えても反映されませんでした。
ターミナル上でechoすると確かに変わってるんですけど、書き換えてもエラーは消えないし、再起動して再確認するとそもそも書き変わってないです。権限的な問題かな？管理者権限で実行すれば行けるのかしら？
なんでだろうなーといろいろいじってたら、先の結論に至ったわけです。なんで今まで気づかなかったんだろう…

[1]:https://qiita.com/kompiro/items/5fc46089247a56243a62
[2]:https://ja.wikipedia.org/wiki/Pwd
[3]:https://github.com/direnv/direnv/blob/master/README.md#how-it-works
サービスの運用とファシリティマネジメント

# システム運用管理
日常の運用計画、障害発生時の運用を適切に行うための```計画、運用負荷低減のための改善計画```を作成する。さらに```キャパシティ管理```、```情報セキュリティ管理```、```可用性管理```の方針に基づいた運用も必要となる。

### スケジュール設計
```スケジュール運用設計の基本的な考え方、運用方式に関する設定```を行う。

### 障害時運用設計
データの回復や待機系への切替など、```障害時の運用方式に関する設計```を行う。

### 運用支援ツール
#### 監視ツール
```システムの運用や情報セキュリティの状況を監視し、異常を発見してレポート```するツール。
監視対象にはアプリケーションシステムやOSの稼働状況、CPU、メモリ、ディスクの使用率、ネットワークの利用率、サーバやファイルなどへのアクセス数などがある。

#### 診断ツール
監視ツールからの情報や運用状況などを統合し、```サービスマネジメントとしての意思決定支援を行うためのツール```。運用トラブル、セキュリティ侵害、SLAで合意したサービスレベルの達成状況を診断するための基礎数値を把握できる。

### バックアップ
障害時の復旧や再実行に備えて、```運用スケジュールに基づいた、計画的なバックアップを実施```する。バックアップは次のことに注意しよう。

* 業務処理とバックアップ処理の```時間帯が重ならないようにスケジュールを立てる```。
* 分散環境のファイルは、```すべての更新処理が終了した時点で行う```。
* バックアップデータは、```バックアップ元のデータと同一媒体に置かない```。
* ```同一媒体への上書きは行いわない```。再利用時は規定に従う。
* 差分バックアップは、バックアップ処理は短いが、```復旧処理は長くなる```。

# サービスデスク（ヘルプデスク）
サービスの利用者からの問い合わせに対して```単一の窓口機能を提供```し、```適切な部署への引き継ぎ```、```対応結果の記録```、```記録の管理```などを行う。サービスデスクのメリットは、窓口を一本化しておくことで、ユーザの利便性をはかり、問題解決に必要な情報を```統一的に収集できる```こと。障害発せ時の問い合わせに対して、```既知の対応策を蓄積しておくこと```で、```すぐに利用者に回答できることがある```。

### 中央サービスデスク
全ての利用者用に```単一の窓口を設ける```。

### ローカルサービスデスク
利用者の```拠点ごと(または地域ごと)に窓口を設ける```。

### バーチャルサービスデスク
いくつかのサービスデスクを```ネットワークなどで結び、単一の窓口として機能```させる。

### フォロー・ザ・サン
分散拠点のサービス要員を含めた全員を```中央で統括して管理し、統制のとれたサービスを提供```する。

# ファシリティマネジメント
```建物や設備が最適な状態になるように、監視し改善```する管理活動。障害や誤作動が起きると企業活動。
障害や誤作動が起きると企業活動や社会に重大な影響を及ぼす```ミッションクリティカルシステム(企業の基幹システムや社会システム、交通システム、金融システムなど）```に該当する場合、特性に合わせた```多重のバックアップ```となる。

### UPS:Uninterruptible Power Supply(無停電電源装置)/自家発電設備
```停電や瞬断に備えて、内部のバッテリを備えた装置```。
停電時に10数分間程度の電源が供給されるため、```システムを安全に停止させる```ことができる。また、災害などにより電力会社からの供給が途絶えたときに、エンジンやタービンを使って発電する設備が```自家発電設備で数十分〜数日に渡る発電```が可能だが、```供給はすぐに開始できないため、UPSなどと組み合わせて利用する```。

### 通信設備
ビルやマンションなどには、```複数の通信回線（電話回線、光回線など）を収容するMDF(Main Distribution Frame: 主配線盤）を設けることで、```通信配線を一元管理```できる。また、各階ごとには```IDF(Intermediate Distribution Frame : 中間配線盤）をおく。

### サージ保護デバイス（SPD:Surge Protective Device)
```落雷などによる過電流や過電圧からコンピュータや通信機器を守る装置```。家庭用から、大掛かりな設備用などがある。避雷器、アレスタなどとも呼ばれる。

#### アレスタとは？

https://www.yokogawa.co.jp/solutions/products-and-services/measurement/components-products/surge-arresters/#%E6%A6%82%E8%A6%81

だいたいこんなものなのか。知らなかった。

### インベントリ収集
企業で利用している```PCのハードウェアやソフトウェアなどの構成情報を集めてくる```ことを言います。
出典 https://www.qualitysoft.com/itmanagement_news/helpdesk/1085#:~:text=IT%E8%B3%87%E7%94%A3%E7%AE%A1%E7%90%86%E3%82%92%E3%81%99%E3%82%8B,%E3%81%8F%E3%82%8B%E3%81%93%E3%81%A8%E3%82%92%E8%A8%80%E3%81%84%E3%81%BE%E3%81%99%E3%80%82

### 稼働管理機能
#### 関連記事
https://ohnest.jp/images/ohnest/business/catalog/4_%E3%89%9DD007006_%E7%A8%BC%E5%8B%95%E7%AE%A1%E7%90%86%EF%BD%BC%EF%BD%BD%EF%BE%83%EF%BE%91.pdf

# 出典
https://gihyo.jp/book/2022/978-4-297-12375-8
【OutSystems】 テストデータを削除したい

## いろいろと試していたらぐちゃぐちゃしてきて一旦エンティティからデータを消したいとき![D1.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691264/65c033a9-7ab3-65bf-dbfd-b2915fc55332.jpeg)

上のテーブルを表示させているエンティティ
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691264/b7470489-4069-1b77-01de-6ce6afbb3955.png)

#### 1. サーバーアクションを作成する
アクション名はClearDataとしました。![3.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691264/94a34318-140e-f329-2d45-d096ab304b46.jpeg)

#### 2. SQLを追加する。![4.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691264/5e17e310-4c99-c99e-218d-5d10f75589a0.jpeg)

#### 3. 取得結果を格納する変数の型を設定
![6.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691264/9651fdc4-674a-325b-97bd-03f3f855d0d8.jpeg)
Output Entities / Structuresを右クリックし、「Categoryエンティティ」、「Taskエンティティ」を追加

SQLタブに以下を記載
``DELETE FROM {Task};``
``DELETE FROM {Category};``

最初にTaskエンティティからすべてのデータが削除され、次にCategoryエンティティからデータが削除される。
子エンティティ（別のエンティティを参照するエンティティ）のデータを削除してから、親エンティティのデータを削除する。
![5.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691264/88157f3c-92b6-4596-1076-5cfe81875c1e.jpeg)

#### 4. 画面を作成し、削除ボタンを作る
Interfaceタブ->MainFlowを右クリックし、AddScreenで画面を作成し、ボタンウィジェットを配置する。![D2.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691264/a5dbda72-6265-5c29-a76f-e6fca87504ab.jpeg)

#### 5. On ClickにNew Client Actionを設定する
![7.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691264/0347609c-bd90-fca9-b6a1-5ea63bc106a0.jpeg)
名前が自動的にDeleteOnClickになる。
1で作成したClearDataサーバーアクションをStartの次に配置する。
![8.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691264/a1167e26-7e23-c3e9-ee3d-f31ebdc10a9d.jpeg)

#### 6. メニューブロックに、4で作成した画面へのリンクをつける
![9.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691264/efec01b7-1700-dad3-8aa5-0e8f2ddc4ab8.jpeg)

#### 7. DeleteEntityDataをクリックし、データが全て消えることを確認

![10.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691264/395959a8-f5f9-8de6-2c46-8715c3285107.jpeg)
![11.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691264/ba3dd621-0159-f8c2-61a0-965442de04a3.jpeg)
![12.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691264/25013bca-e6ec-b52f-06ec-7a541cc3deb1.jpeg)
フォルダ毎削除するコマンド

コマンドでフォルダ毎削除したいときにコマンドを毎回調べるので備忘録として残しておきます。
フォルダ名を`delete_me`としております。

空のフォルダだったら下記のコマンドで削除可能です。
```terminal
$ rmdir delete_me
```

ただ､フォルダ内にファイルが存在すると下記のようなエラーがでます。

```terminal
$ rmdir delete\ me                                             ✘ 1 
rmdir: delete me: No such file or directory
```

フォルダ内にファイルが存在するときには下記のコマンドでまるごと削除可能です。
```terminal
$ rm -r delete_me
```

下記のように本当に削除していいのかと確認が入るときはyesと打ち込みましょう！
```terminal
$ rm -r delete_me
examine files in directory delete_me? yes
remove delete_me/index.html? yes
remove delete_me? yes
```
ECRにログインやDockerをpushするときにエラー＋複数ユーザーで使用したいとき(Error: Cannot perform an interactive login from a non TTY device)

# EC2サーバーでECRにログインするときのエラー
## 背景
Amazon ECRを使う場面でのことです。
ECRでは「プッシュコマンドの表示」があり、それ通りに行うことでレポジトリ内にあるimageをpushできます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/414468/12683115-0820-b3bd-d6ea-ff5e67400f95.png)


ある日新しいEC2サーバーでECRを使うため、新しいEC2にAWS CLIとDockerをインストールしました。図にしたのが以下です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/414468/3c3f1cf1-f32d-2713-84b7-38993d76b5a4.png)

この状態で、Dockerイメージを構築する前段階の処理（認証トークンを取得＋レジストリに対して Docker クライアントを認証）をするために下記赤枠コマンドをそのまま実行したところ、エラーが発生しました。

![2022-11-11_16h07_26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/414468/797a5ca3-50ba-910a-7d57-1ed5c568ef1e.png)


```
aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin 000000000000.dkr.ecr.ap-northeast-1.amazonaws.com
```
※0000…のところはアカウントID

## エラー内容
> An error occurred (AccessDeniedException) when calling the GetAuthorizationToken operation: User: arn:aws:sts::000000000000:assumed-role/ec2-role/i-0a241ere75e550e3dee4 is not authorized to perform: ecr:GetAuthorizationToken on resource: * because no identity-based policy allows the ecr:GetAuthorizationToken action
Error: Cannot perform an interactive login from a non TTY device

## 要因
aws のプロファイル情報が紐づけされていないため

## 解決策
AWSのドキュメントにのっていました。

https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-configure-files.html

以下のコードでプロファイルを設定できます。
```
aws configure
```

Access Key IDやSecret Access KeyはIAMから取得できます。

https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_credentials_access-keys.html#Using_CreateAccessKey


## 設定できたか確認
以下のコードで確認できます
```
aws configure list
```

![2022-11-11_16h17_39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/414468/e3b0caab-6946-06de-a1f8-1b2b016894fd.png)

冒頭にあったECRのプッシュコマンドを実行すると無事成功。

![2022-11-11_16h21_55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/414468/51b85881-56af-6372-e65c-47ee24db1705.png)


# 複数ユーザー（別ユーザー）が使うとき
## 背景
既にEC2サーバーにAWS CLIの情報がある場合、上記の手順で行うと情報を上書きしてしまいます。
そのため、以下手順でprofile名を指定することで別ユーザーでも操作することに成功しました。

## 解決策
--profileオプションをつけた上でプロファイル情報を設定します
```
aws configure --profile testadduser
```

※「testadduser」部分はプロファイル指定したい名前にする

## 設定できたか確認
上記と同様ですが、--profileをつけて確認します。
```
aws configure list --profile testadduser
```

最後に冒頭にあったECRのプッシュコマンドを実行します。
ただしそのままコピペだと実行できません。
コード内で `--profile test_add_user` とつけることで、指定したプロファイル情報を参考にログイン試行してくれます。
```
aws ecr get-login-password --region ap-northeast-1 --profile test_add_user | docker login --username AWS --password-stdin 000000000000.dkr.ecr.ap-northeast-1.amazonaws.com
```

![2022-11-11_16h32_21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/414468/77503368-efc6-4fbd-632d-f4e2a9db522f.png)
いつも使っている[weak self]について調べてみた

## [weak self]を使う場面
私が[weak self]に遭遇する場面はクロージャ内でselfを使いたい時です。

```swift
...{ [weak self] in
    self?.view?. ...
    }

```

## 循環参照について
循環参照は参照型同士で強参照しあうことでお互い解放されずメモリリークが起こってしまうことです。これは弱参照を用いることで解決します。

```swift
class User {
    var car: Car?
}

class Car {
    var user: User?
}
```

上記のコードではUserクラスとCarクラスがお互いに強参照し合っています。
解決策として
```swift
class User {
    var car: Car?
}

class Car {
    //弱参照
    weak var user: User?
}

```
とすれば循環参照を回避できます。



## クロージャの循環参照
クロージャも分類は参照型で循環参照を起こし得ます。

```swift

class ViewController: UIViewController {
    var closure: () -> Void = {}

    closure = {
        self.printHoge()
    }

    func printHoge() {
        print("hoge")
    }
}
```
クラスがクロージャを強参照しクロージャがクラスを強参照することで循環参照を起こしています。
そこで[weak self](または[unowned self])をもちいることで解決します。

```swift

class ViewController: UIViewController {
    var closure: () -> Void = {}

                //弱参照
    closure = { [weak self] in
        self?.printHoge()
    }

    func printHoge() {
        print("hoge")
    }
}
```



## 終わりに

なぜ[weak self]が必要かわかった気がします。

## 参考

https://qiita.com/1234224576/items/2241266f7d307cd25ba9

https://zenn.dev/yimajo/articles/b29025e90a212a
IKS(IBM Kubernetes Service) のBlock Storage for VPC アドオン更新

##### はじめに

気づかないうちにIBM Cloud 検証環境でアドオンのバージョンが古くなっていたので更新したログです。


---
##### 環境

IBM Kubernetes Service 1.24 (VPC 環境)
 - クラスター名：iks-vpc1

---
##### 確認

IKSクラスターのコンソール上でアドオンに重大が表示されていることに気づきました。

![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517421/55bc3206-f8fd-8fc4-2c56-98e0e97477e4.png)

使用しているアドオン Block Storage for VPC が対象です。

![図2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517421/9382c3d4-d6c3-54d1-899d-aaaf32148eae.png)

warning にある addon-state のリンクにアクセスします。

[クラスター・アドオンのデバッグ](https://cloud.ibm.com/docs/containers?topic=containers-debug_addons)


H1509 は、"Addon Unsupported" を指し、「アドオンがサポート対象外のバージョンを実行しているか、アドオンのバージョンがクラスターのバージョンではサポートされないバージョンです。」とのこと。



案内にある [マネージド・アドオンの更新](https://cloud.ibm.com/docs/containers?topic=containers-managed-addons#updating-managed-add-ons) を実施します。


```
$ ibmcloud ks cluster addon ls -c iks-vpc1
OK
名前                   バージョン           正常性の状態   正常性の状況
vpc-block-csi-driver   4.2* (4.4 default)   critical       Addon Unsupported. For more info: http://ibm.biz/addon-state (H1509)
$
```

やはりバージョンがデフォルトより低いことによるメッセージです。


---

##### アドオンの更新


[Block Storage for VPC アドオンの更新](https://cloud.ibm.com/docs/containers?topic=containers-vpc-block#vpc-addon-update) を実施します。

addon を disable にします。

```
$ ibmcloud ks cluster addon disable vpc-block-csi-driver --cluster iks-vpc1 -f
クラスター iks-vpc1 のアドオン vpc-block-csi-driver を無効にしています...
OK
$
```

確認：アドオンが解除されました。

```
$ ibmcloud ks cluster addon ls -c iks-vpc1
OK
名前   バージョン   正常性の状態   正常性の状況
$
```

バージョンを指定して enable にします。

```
$ ibmcloud ks cluster addon enable vpc-block-csi-driver --version 4.4 --cluster iks-vpc1
クラスター iks-vpc1 のアドオン vpc-block-csi-driver(4.4) を有効にしています...
アドオンのデプロイが完了して利用可能になるには数分かかる場合があります。
OK
$
```

確認：すぐに アドオンが追加されました。
状態は、Enabling で、GUIでは保留中が表示されています。

```
$ ibmcloud ks cluster addon ls -c iks-vpc1
OK
名前                   バージョン   正常性の状態   正常性の状況
vpc-block-csi-driver   4.4          -              Enabling
$
```

![スクリーンショット 2022-11-11 16.21.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517421/4744bff9-4ca5-7250-4580-289d1a178b88.png)


5分程度後に Addon Ready となりました。
GUIも通常状態です。

```
$ ibmcloud ks cluster addon ls -c iks-vpc1
OK
名前                   バージョン   正常性の状態   正常性の状況
vpc-block-csi-driver   4.4          normal         Addon Ready. For more info: http://ibm.biz/addon-state (H1500)
$
```

![スクリーンショット 2022-11-11 16.26.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517421/f28fc9e4-9bb3-c51f-8a18-f47deab8001c.png)

---

この環境ではカスタム・ストレージクラス等は作成していないので、設定変更等は不要でした。

[バージョン 4.2 への更新後のカスタム・ストレージ・クラスの再作成](https://cloud.ibm.com/docs/containers?topic=containers-vpc-block#recreate-sc-42)


---

##### おわりに


検証環境のため特に監視は追加しておらず、アドオン のバージョンが古くなった場合に気づくのが遅くなりました。
何か気付ける仕組みがあればと思います。
MetCom Pinnacleサービスで地上高を計ろう

2022年11月9日（119番の日）、MetCom Pinnacleサービスがスタートしました。
このサービスは、垂直（Z軸）測位サービスとも呼ばれ、気圧センサと何らかの通信手段があれば、今いる場所の「高さ」を取得できるサービスです。
サービスの詳細は、[MetCom社のホームページ](https://metcom.jp/service/pinnacle/)をご参照ください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172313/550e0555-5db4-1a82-f8b6-e3c690f5d9c8.png)

# Pinnacleサービスの背景
この技術は、米国[NextNav社](https://nextnav.com/)が北米で商用展開されているものですが、元々は、米国FCCが2019年11月、オフィスタワーや高層アパート、ホテルなど高層ビルから発信される緊急通報（911コール）に、垂直方向の位置情報を提供するよう、無線通信事業者に義務付けたことから始まりました。
その後、AT&T社がNextNav社技術の導入を決め、現在、北米の90%を超える高層ビルでの911コールに対応されています。
また、2021年にはFirstNetというPublich Safety（ざっくり言うと、警察・消防無線をLTE等でサービス）においても、同技術が採用されています。

# Pinnacle API
Pinnacle APIは、現在地点の緯度経度と気圧値があれば十分です。HTTPSで緯度経度や気圧値が含まれるJSONをPOSTすれば、高さ情報が返ってくるというRestfulなAPIサービスです。
Pinnacle APIのエンドポイントは、開発者向けにのみ公開されているため、ここでは、https://[pinnacle api end point]/get-live-heightとしておきます。

### API Request
|項目|説明|子要素|
|:-----|:------|:-----|
|appId|本APIを利用するユニークなアプリケーションID|-|
|deviceId|デバイスID。API内部で独自のキャリブレーションが入るため、気圧センサ毎にユニークなIDになる必要があります。|-|
|xyLocation|デバイスの緯度経度|latitude、longitude、accuracy(位置精度:誤差半径)|
|pressure|気圧値(Pa単位)。より正確な値を取得するため、10Hz(0.1秒間隔）で1秒(10サンプル)程度のセンサ値の平均、最大、最小、所得回数、偏差を入力することが推奨されます。|average、min、max、count、variance|
|timestamp|ミリ秒単位のUnixタイムスタンプ。この時刻がAPI通信時刻より5分以上遅れるとAPIはエラーを返します。|-|

### API Response
|項目|説明|子要素|
|:------|:-------|:--------|
|xyLocation|API Requestで送信したデバイス緯度経度|latitude、longitude、accuracy|
|hae|楕円体高（Height Above Ellipsoid）|value、accuracy（推定精度:m）|
|hat|地上高（Height Above Terrain）。地表面からの高さ|value、accuracy（推定精度:m）|
|barocalNeeded|デバイスの気圧センサのキャリブレーションが必要有無："Y"or"N"|-|
|timestamp|APIが高さ計算処理を行った時刻|-|

楕円体高については、[国土地理院:ジオイドを知る](https://www.gsi.go.jp/buturisokuchi/grageo_geoid.html)を参照ください。

# Pinnacle APIを使ってみる
お試しに、下記のようなJSONを送信します。ここでは、気圧値平均1015.2hPa、緯度経度は東京タワーにしておきます。
```input.json
{
    "appId": "kccs119",
    "deviceId": "mydevice001",
    "xyLocation": {
        "latitude": 35.6585026,
        "longitude": 139.745454,
        "accuracy": 10
    }, 
    "pressure": {
        "average": "101520.0", 
        "count": 10, 
        "min": "101515.0", 
        "max": "101525.0", 
        "variance": "0.5"
    }, 
    "timestamp": 1668134236236
}
```
API送信時のヘッダには、APIキー`x-api-key`を入力しておく必要があります。このAPIキーの取得方法については別途。

上記JSONを送信すると、下記の応答が得られました。
```response.json
{
    "status": 200,
    "result": {
        "xyLocation": {
            "latitude": 35.6585026,
            "longitude": 139.745454,
            "accuracy": 10.0
        },
        "hae": {
            "value": 129.4,
            "accuracy": 84.3
        },
        "hat": {
            "value": 74.4,
            "accuracy": 84.3
        },
        "barocalNeeded": "Y",
        "timestamp": 1668134254094
    }
}
```
さて、地上高（HAT）74.4mということで、まさにメインデッキに続くエレベータに乗っている状態であることがわかりました。
ただ、accuracyが84.3mと最悪。つまり、このデバイス。まったくもってキャリブレーションしていませんでした。barocalNeededもYになっていますね。
ここは、改めてキャリブレーション後に再チャレンジしてみます。
[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172313/d6ad10bc-75ba-8124-14d4-f144657c6473.png)](https://twitter.com/ghibi)
[MetCom HP](https://metcom.jp/)
[NextNav HP](https://nextnav.com/)
MFCからＳVGタグの追加と属性の追加

## SVGタグの追加

基本的にタグ要素を生成してタグ名 m_strName とタグの値 m_strValue を設定します。
例に挙げている title タグの追加は値が存在しますので値のない単独タグであることを示すフラグ m_bOne が "FALSE" となります。
階層は svg タグ内の宣言となりますので m_nDepth は "1" となります。

ヘッダは宣言の部分のみ
```diff_cpp:SvgImage.h
class SvgImage
{
public:
+   void AddTitle(LPCTSTR strTitle);
}
```
```cpp:SVGImage.cpp
void SvgImage::AddTitle(LPCTSTR strTitle)
{
	SvgTag* svgRoot = new SvgTag();
	svgRoot->m_strName = L"title";
	svgRoot->m_strValue = strTitle;
	svgRoot->m_nDepth = 1;
	svgRoot->m_bOne = FALSE;

	m_arrayTag.Add(svgRoot);
}
```

## 属性の追加
属性は指定された属性が既に登録済みであった場合のことも考慮して準備します。

ヘッダは宣言の部分のみ
```diff_cpp:SvgImage.h
class SvgImage
{
public:
+   void AddAttribute(LPCTSTR attrName, LPCTSTR attrValue, BOOL bOverwrite);
}
```
```cpp:SvgImage.cpp
void mdSvgImage::AddAttribute(LPCTSTR attrName, LPCTSTR attrValue, BOOL bOverwrite)
{
	SvgTag *svgTag = m_arrayTag.GetAt(m_arrayTag.GetSize() - 1);
	BOOL bFind = FALSE;
	for (int i = 0; i < svgTag->m_arrAttr.GetSize(); i++)
	{
		if (svgTag->m_arrAttr.GetAt(i).CompareNoCase(attrName) == 0)
		{
			CString strProp = svgTag->m_arrAttrValue.GetAt(i);
			strProp = bOverwrite ? attrValue : svgTag->m_arrAttrValue.GetAt(i) + attrValue;
			svgTag->m_arrAttrValue.SetAt(i, strProp);
			bFind = TRUE;
		}
	}
	if (bFind == FALSE)
	{
		svgTag->m_arrAttr.Add(attrName);
		svgTag->m_arrAttrValue.Add(attrValue);
	}
}
```

現在終端にあるタグが保持している属性全てに対してループをします。
bFind は追加したい属性名が重複していないか判定するためのフラグです。
FALSEのままであれば属性リストに追加する処理を行います。 
```cpp
	SvgTag *svgTag = m_arrayTag.GetAt(m_arrayTag.GetSize() - 1);
	BOOL bFind = FALSE;
	for (int i = 0; i < svgTag->m_arrAttr.GetSize(); i++)
	{
```
属性が重複しないかを調べます。
重複している場合は上書きか追記かを bOverwrite フラグから参照し、TRUE の場合は上書きし、FALSE の場合は追記を行います。
```cpp
		if (svgTag->m_arrAttr.GetAt(i).CompareNoCase(attrName) == 0)
		{
			CString strProp = svgTag->m_arrAttrValue.GetAt(i);
			strProp = bOverwrite ? attrValue : svgTag->m_arrAttrValue.GetAt(i) + attrValue;
			svgTag->m_arrAttrValue.SetAt(i, strProp);
			bFind = TRUE;
		}
```
属性リストで重複が見つからなければ（bFind == FALSE の場合）新規追加を行います。
```cpp
	if (bFind == FALSE)
	{
		svgTag->m_arrAttr.Add(attrName);
		svgTag->m_arrAttrValue.Add(attrValue);
	}
```

## MFC のカラーコードを考慮した属性の追加
SVG の fill や stroke 属性にはカラーコードかURLが必要となります。
MFC のカラーコードから SVG 画像のカラーコード（16進数テキスト）に変換して出力します。

カラーコードは上書きを指定しています。

ヘッダは宣言の部分のみ
```diff_cpp:SvgImage.h
class SvgImage
{
public:
+   void AddAttrColor(LPCTSTR attrName, COLORREF color);
}
```
```cpp:SvgImage
void SvgImage::AddAttrColor(LPCTSTR attrName, COLORREF color)
{
	CString strColor;
	strColor.Format(L"#%02x%02x%02x", GetRValue(color), GetGValue(color), GetBValue(color));
    AddAttribute(attrName, strColor, TRUE);
}
```
エンジニア年収アップ講座説明会 第二回を開催します！

第一回目が満員のため、第二回を12月6日19時から参加します。

12月1日が都合悪かったもご参加下さい。

CTO社数10社、技術顧問社数20社以上と数々のCTOを歴任してきた森川がエンジニアのキャリアパスを学べる講座を作りました。
エンジニア能力開発を網羅し、エンジニアとしてマネージメント能力開発まで含んだ内容になってます。

https://cto-can-be.hp.peraichi.com/
iOSアプリで端末のシリアル番号を取得する方法（MDM必須）

# そもそも可能？→普通はできない

iOSにおいて、アプリから端末のシリアル番号は取得できません。（UDIDも同様かと思います）
ただし、以下の場合はどうにかできます。

:::note info
MDMで管理されたデバイスで、Enterpriseアプリ等を使用する場合
:::

:::note alert
AppStoreで配布するアプリで一般公開する場合ではできません
:::

※MDMというのは企業・学校などが社員・学生用端末を管理するための管理プラットフォームです。
予め管理する端末をMDMに登録しておきます。
Apple Business Managerとか、Apple Configuratorとかで調べると情報があるかと思います。
ちなみに、この仕組でAppleのEnterpriseアプリを配布するには結構敷居が高いです。
（厳しい審査があり、100名以上の社員数などいろいろ条件があります）

過去に、Enterpriseアプリを不正利用した会社があるので仕方ないですね。
（Enterpriseアプリを一般公開・配布していた事件）

# どうするの？→アプリ管理設定プロファイル

MDMを使用し、**アプリ管理設定プロファイル**を用いて、任意の設定値を管理端末に投げ込むことができます。
その具体的な方法は、ご利用のMDMのHELP等に記載があるかと思います。
自分が使用しているMDMの場合は、設定値としてシリアル番号が選択できましたので、
serialという設定キーで、端末のシリアル番号を指定してプロファイルを作成し、
それを自動登録にしてしまえば、それでアプリから各端末のシリアル番号を取得できます。

:::note warn
他のMDMはしりませんが、もし、値をシリアル番号を指定できない場合は、端末毎に個別にシリアル番号を入れてあげる必要があるかもしれません。
恐らく自動でシリアル番号を投げる機能はどのMDMにもあるとは思いますが・・・。
:::

# アプリからどうやって取得するの？

UserDefaults（com.apple.configuration.managed）に格納されていますので、以下のように取得できます。

```swift
if let managedConf = UserDefaults.standard.object(forKey: "com.apple.configuration.managed") as? [String:Any?] {
    let deviceId = (managedConf["serial"] as? String)!
    // 端末のシリアル番号がdeviceIdに格納される
}
```
※アプリ管理設定プロファイルでキーを**serial**、値を**シリアル番号**にした場合。

# それで何ができるの？

MDMで管理する端末で業務アプリなどを運用している場合、別途管理サーバーを用いて認証などを行っていると思います。
ユーザーアカウントと端末を１：１で対応させたいこともあるでしょう。

:::note warn
MDMでユーザーIDを投げ込んでいる場合は特に問題ないでしょうが、一般的なID/パスワードのログイン画面を表示するような場合では、1つのユーザーアカウントで複数の端末にログインできることになります。
（もちろん、その端末は管理端末なので勝手に買ってきたiPadなどは使用できませんが）
:::

上記の方法で、**ユーザーIDに紐づけてシリアル番号を保持しておき、アプリでのログイン認証時にチェックする**ことができます。
まあ、だから何だという話かもしれませんが、実現しようとして調べてもあまり情報がなかったので書いておきます。
ステレオタイプを捨てよ！日本企業はVUCA時代に合わせたアジャイルな組織設計をすべき！

Meta、社員1万1000人解雇を正式発表　CEO「世界のオンライン移行、期待通りにならず」


これですよね。アメリカITの強さ。Twitterも同様に不要と思えば、瞬時に解雇できる。反対に必要とあれば、一気に採用して大きくアクセル踏めるのでビジネスが強い。VUCA時代にそった、アジャイルな動きが出来てます。

これ日本企業だと出来ません。解雇に時間も掛かるし大量だと裁判になったりお金を沢山払う必要があったり。

だから、顧問企業に、僕は常々言ってます。社員メインでなく業務委託やフリーランスを中心にした組織構築も視野に入れるべきと。社員も今の時代すぐに辞めていきます。転職に対して引き止めが難しいのが昨今。なのに未だに社員が良いって思ってる人多すぎです。完全なステレオタイプ

業務委託やフリーランスなら雇用もフレキシブルだし、相手はプロだから成果もはっきりしてるし、目標設定とかメンタルへのコストも低い。
VUCA時代に合わせた雇用を進めるべきだと思います。

https://www.itmedia.co.jp/news/articles/2211/09/news181.html
Insomniaの使い方

## この記事の目的
インターンでapi開発を行なっている際にInsomniaを使用した。使い方を忘れないようにメモを残しておく。
なんとなく理解している程度のため表現方法や理解がおかしいかもしれない。その際はコメント等で指摘してくれると助かります。

## Docker側の操作
```bash:terminal
rails s -b 0.0.0.0
```
IP`0.0.0.0`にバインドさせながらサーバーを起動させる。

## rails側のapi
### ソースコード
```ruby:event_controller.rb
class Api::EventsController < ApplicationController
  def index
    #binding.pry

    events = Event.all
    render json: events
  end

  def create
    @event = Event.new(event_params.merge({ hashed_url: invent_hash }))
    #binding.pry

    if @event.save
      render json: @event
    else
      render json: @event.errors
    end
  end

  def invent_hash
    #binding.pry

    root_str = event_params[:user_id].to_s + event_params[:category_id].to_s + event_params[:name]
    Digest::SHA256.hexdigest(root_str)
  end

  private

  def event_params
    params.require(:event).permit(
      :user_id,
      :category_id,
      :name,
      :is_public,
      :description,
      :delete_at
    )
  end
end
```
### ファイル構成
![スクリーンショット 2022-11-11 10.16.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/190374/46c1183c-fd65-3391-6799-d1aa725023b6.png)
### ルーティング
![スクリーンショット 2022-11-11 10.18.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/190374/861650d2-bb98-749a-442a-7c25e5d52ca2.png)



## insomniaの操作
![スクリーンショット 2022-11-11 10.14.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/190374/ed123a22-f33f-411d-bbbd-b95aca295431.png)
上記の写真のようにURLにするとgetリクエストが送れる。
![スクリーンショット 2022-11-11 16.01.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/190374/4e9b9f98-cf84-fc8d-22a9-0df2e28c70fa.png)
getではなくpostを送るとこのような返り値が来る。


## 気づき・気になったこと
- progateで学んだ書き方よりも抽象的な分、リクエストとはみたいな部分を意識するきっかけになった
-　リクエストをテンプレートとして保存して置けるのでapi開発の時に楽にデバックを行うことができる

## 参考
https://qiita.com/kamohicokamo/items/3ec26ccb8e16b8ba9adb

https://qiita.com/hirohero/items/64327f2023ff7b452d47
Colabでトークン等の秘密情報を気軽にいい感じに扱う

この記事は [ZOZO Advent Calendar 2022](https://qiita.com/advent-calendar/2022/zozo) のカレンダー4の9日目の記事です。

トークンなどの共有したくない情報を隠しつつ、うまいことメンバーにColabを共有し、メンバーごとにトークンを設定できるようにする。

１. 以下の内容をセルに記載する
以下のコードは `token` が空であればGoogle DriveをColabにマウントし、MyDrive直下にある `token.txt` の中身を `token` として読み込むようにしている。
また、Colabのフォーム機能を使って `#@param {type:"string"}` と指定することでコードを編集せずフォームとして編集できるようにしている。

``` python
#@markdown - token：個人ごとに違うトークンで共有はしたくない値。空欄の場合は/content/driver/MyDrive/token.txtを参照する
token = '' #@param {type:"string"}

if not token:
  from google.colab import drive
  with open('/content/drive/MyDrive/token.txt') as f:
    token = f.readline().replace('\n', '')
```

２. (Option) 右クリックして「フォーム」→「コードを非表示」にする

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16612/51e0d25f-4378-946f-9ea7-c74522664721.png)

３. フォームでtokenを入力するか、空欄にするかで挙動が変わる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16612/fa75ee7c-d050-a85f-8c63-2ccf8091da1f.png)

これで、普段はtokenを空にしておくことでトークンをコード内に書くことなくGoogle Driveに保存している値を参照しつつ、個人で使用する場合はフォームを使ってトークンを書いておくことでGoogle Driveをマウントする手間を減らすことができる。
shell scriptを理解したい vol.1

# はじめに

最近業務でshell scriptを使う様になってきたので本腰入れて理解を深めようと思っている今日この頃

基本的なところから始めて徐々に理解を深める構成で行きたい

# 基本的なところから...

多分基本、ってところを一個ずつ

> 参考は[【bash入門】bashシェルスクリプトの書き方](https://tech-blog.rakus.co.jp/entry/20210525/shellscript)

## shebang(シバン)

<font Color="Gray">これって名前あったんですね...(ぼそっ)</font>

shell scriptの1行目に書かれている、いわゆる"おまじない"の部分

```bash
#!/bin/bash
```

実行するshell scriptの[インタプリタ](https://e-words.jp/w/%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%97%E3%83%AA%E3%82%BF.html)を指定、意図しない挙動を避けるために記述

> `#!/bin/sh`でも大体いいらしいけど、若干挙動が違うとのこと、安牌は上記の様に書くこと

## Comment-out

これはわかりやすい

```bash
# echo "this is comment."
echo "this line is run."
```

頭に`#`をつけるだけ

## 変数定義

やり方がいくつかあるので分けて説明

### 値の代入
```bash
#!/bin/bash

num_var=12345
str_var=hogehoge
mes_var="hello world"

echo $num_var # 12345
echo $str_var # hogehoge
echo $mes_var # hello world
```
このとき`num_var␣=␣12345`とするとエラー出るので注意

### コマンドの実行結果を代入

<code>`</code>で囲ってあげるとできる。出力は各自で確認してみてね。

```bash
#!/bin/bash

echo `ls`
echo `printenv`
```

### スクリプト実行時の引数を代入

```bash
#!/bin/bash
# test.sh

num_var=${1}
str_var=${2}

echo "arg1 is ${num_var}, arg2 is ${str_var}."
```
実行時
```bash
$ sh test.sh 12345 value
arg1 is 12345, arg2 is value.
```

# とりあえず

このあたりが頻出なんだろうなと思うので一旦ここまで。

次はこちら→(さくせいちゅう)
指定した期間のイベントログを取得する

```bat:logger.bat
@echo off

set LINE[1]=     dBP    dBBBBP dBBBBb  dBBBBb  dBBBP dBBBBBb
set LINE[2]=           dBP.BP                            dBP
set LINE[3]=   dBP    dBP.BP dBBBB   dBBBB   dBBP    dBBBBK 
set LINE[4]=  dBP    dBP.BP dB  BB  dB  BB  dBP     dBP  BB 
set LINE[5]= dBBBBP dBBBBP dBBBBBB dBBBBBB dBBBBP  dBP  dB  

set SELF=%~n0
set HERE=%~dp0
set HERE=%HERE:~0,-1%

setlocal enabledelayedexpansion
  cd /d "%HERE%"
  
  echo.
  for /l %%i in (1, 1, 5) do (echo !LINE[%%i]!)
  echo.
  echo Gathering information, please wait ...
  
  :: 実行中の cmd.exe の権限レベルを確認
  for /f "tokens=*" %%i in ('whoami /groups ^| find "Mandatory"') do (set LINE=%%i)
  
  :: 権限レベルが High ではない場合、管理者権限で cmd.exe を起動
  (echo %LINE%) | findstr /l "High" || (
    @powershell -NoProfile -ExecutionPolicy unrestricted -Command "Start-Process %~f0 -Verb runas"
    exit
  )
  
  set Y=%DATE:~0,4%
  set M=%DATE:~5,2%
  
  :: システム時間を算出
  :: SystemTime は UTC で指定する必要があるため、月初の 00:00:00 および月末の 23:59:59 から時差（9 時間）を減算
  for /f "usebackq tokens=1,2 delims= " %%a in (`powershell -NoProfile -ExecutionPolicy Unrestricted -Command "& { $SYS_DAY = (Get-Date -Day 1).AddMonths(-1).AddDays(-1).ToString('yyyy-M-dd'); $SYS_DAY += ' ' + (Get-Date -Day 1).AddDays(-1).ToString('yyyy-M-dd'); return $SYS_DAY }"`) do (
    set FROM=%%a
    set TO=%%b
  )
  
  :: イベントログを取得
  wevtutil epl Security "%HERE%\%SELF%.%Y%-%M%.evtx" /q:"*[System[(TimeCreated[@SystemTime >= '%FROM%T15:00:00.000Z' and @SystemTime < '%TO%T15:00:00.000Z']) and (EventID = 4624 or EventID = 4625 or EventID = 4634 or EventID = 4647 or EventID = 4648 or EventID = 4675)]]"
  
  echo.
  set /p =Press any key to close this window. 
endlocal
```

実行結果は以下のとおりです。
![logger.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29814/c7ae1bfc-6a5a-2400-b3ba-c87f4826bf2c.png)
デイトラ「Web制作コース」　受講内容をアウトプット 5日目

学んだことをアウトプットしています。完全に自己満足ですので悪しからず。
以下の点を確実にアウトプット
①何で学んでるか
②日々の学習内容
③学びのポイント
④制作物
⑤+αで参考にした記事
⑥+αでやってみたこと

①デイトラ「Web制作コース初級編」
②ゼロからサイトを作ってみよう①
③今日得た新しい知識
 ・デベロッパーツールのコンソールでJavaScriptのエラー有無やメッセージの確認可能
 ・デベロッパーツールのネットワークで404や速度の確認が可能
 ・divタグとsectionタグの違い
　　→https://hiroshinakazato.com/wp/html5_section_or_div/
 ・line-heightは<body>に1.5入れておくと良い
 ・classの名前は親‐子のような名前が良い
 ・ctrl＋/でコメントアウト可能
 ・after要素が入る場所とその使い方
 ・classはできればタグごとに名前を付ける方が保守性が良い。紐づけでCSSを編集すると
　 親のclass名を変更した際にすべて変更する必要がある。
 ・floatはその名の通り浮き上がる意味があり、その下のスペースに下のブロックが入ってくる場合がある。
 　これをクリアするためにクリアプロパティが必要になる。
 ・after,beforeの疑似要素を使うときは、content: '';、display: block;も必要になることを覚えておく。

④header部分の作成
⑤特になし
⑥特になし
パスワードを定期的に変更しましょう ←なぜ？


若干釣り気味のタイトルです

#### 閲覧対象
ITに詳しくない方で、パパっと見たい方を想定しています。

#### スライド作成目的・目標
先日、情報処理安全確保支援士試験を受験し、学習のアウトプットとして本スライドを作成しました
「実際に、パスワードリスト攻撃のような攻撃手法があるから、使い回しは良くないね」と思っていただければ幸いです

<iframe src="https://docs.google.com/presentation/d/e/2PACX-1vRQ4Fz2SKV28D3kZ1BUdVBjgifrkLMsln9sCJuu4DsDC79gp_HjiltA8Vg-FR2UV0ysHSjVJ-Xrypy0/embed?start=false&loop=false&delayms=3000" frameborder="0" width="960" height="569" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true"></iframe>



内容に関して、誤りがありましたら教えて頂けると幸いです
今更だけどM1 Macにbrewをinstallする (2022.11.11)

# 手順

- https://brew.sh/index_ja
    - にアクセス

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

をコピーして、ターミナルアプリで実行。

この時点ではまだ、brewを使えない。

```
==> Next steps:
- Run these three commands in your terminal to add Homebrew to your PATH:
    echo '# Set PATH, MANPATH, etc., for Homebrew.' >> /Users/s01047/.profile
    echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> /Users/s01047/.profile
    eval "$(/opt/homebrew/bin/brew shellenv)"
```

と出るので

```
echo '# Set PATH, MANPATH, etc., for Homebrew.' >> /Users/s01047/.profile
echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> /Users/s01047/.profile
eval "$(/opt/homebrew/bin/brew shellenv)"
```
をそれぞれ実行

```
brew help
```
で確かめて


```
Example usage:
  brew search TEXT|/REGEX/
  brew info [FORMULA|CASK...]
  brew install FORMULA|CASK...
  brew update
  brew upgrade [FORMULA|CASK...]
  brew uninstall FORMULA|CASK...
  brew list [FORMULA|CASK...]
...
```

などと出れば成功！
dataコマンドでファイルのタイムスタンプを取得する　Mac＆CentOS

ファイルのタイムスタンプを変数に取得して、画面上に表示して、処理がすべて実行されたかを目視、将来的にはif文で確認したい

環境はMacOSとLinux(CentOS７)で同じことを実行したい

「dateコマンドでファイルのタイムスタンプ」と検索すると、
```
$ date '+%Y/%m/%d %H:%M' -r test.sh 
2022/11/11 11:27
```
と、わかった。

ふむふむ、これを検索したMac上で実行すると、エラーメッセージ
```
~$ date '+%Y/%m/%d %H:%M' -r test.sh 
date: illegal time format
usage: date [-jnRu] [-r seconds|file] [-v[+|-]val[ymwdHMS]]
            [-I[date | hours | minutes | seconds]]
            [-f fmt date | [[[mm]dd]HH]MM[[cc]yy][.ss]] [+format]
```

メッセージをよく読んでからオプションを変更して再実行
```
~$ date  -r test.sh  "+%Y%m%d"
20221111
```

Linux（CentOS）に戻ってMacOSで使った形式を実行すると、MacOSと同じ書き方でも実行できました。
```
[hoge ~]$ date  -r test.sh  "+%Y%m%d"
20221111
[hoge ~]$ date  "+%Y%m%d" -r test.sh  
20221111
```


ということで、MacOSでもLinuxでも、環境を意識せずに、
指定したファイルのタイムスタンプを取得して、変数に格納するにはこうすればいい、とわかりました
```
~$ filedate=`date -r test.sh  "+%Y%m%d"`
~$ echo $filedate
20221111
```
フォームのスパム対策について調べた

## 解決したいこと
- 会社のお問合せフォームから悪意のある内容が送信されてくる
    - その結果関係者にスパムメールとして送信される。

このまま放置してしまうと何かの拍子に悪意のあるurlを踏んでしまい
ウイルス感染なんてこともありえる。

## 前提
- reCAPTCHA(v2)は設置されている
- フォーム内容
    - name (必須)
    - kana (必須)
    - tel (必須)
    - email(必須)
    - comment(必須)
    
reCAPTCHA設置しているし必須項目も設置しているし困ったものです。
reCAPTCHA全然仕事していないなぁとか思いましたが
調べるとreCAPTCHA突破できるプログラムできるらしく仕方ないかという感じです。

## botの手法
botの手法を考えると
urlを無作為に叩いて
自動入力でプログラムに指定したinputタグに入力しでpostする
というのが相場かなと思います。

## 対策アイデア
調べたり、個人的にいいのでは?と思ったアイデア。

- reCAPTCHA v3にする
    - reCAPTCHA v3はbotと人間のWebサイトでの行動パターンを自動で学習し、今Webサイトに訪れているユーザーがbotか人間かを自動で判断します。そのため、ユーザー側からはreCAPTCHAが見えず、当然ながら一切の操作や手間が不要です。
        -  reCAPTCHAも進化しているのでこれに変えてみるのがオーソドックスな対応かもしれないですね。
- ipアクセス制限
    - ipを取得しておき悪意のあるユーザーを排除する
        - 毎度毎度やるのはあまりに手間がかかりそうですね。
- お問合せ内容に必須項目を設置する
    - チャックボックスを設置する方法ですね。例えばお問合せ内容を選択してもらうとか。
        - これは簡単でいいかもしれないですね。ただ仕様上必要ないのであればスパム対策という都合で入れるのは違うかもですね。
- リンクの送信を禁止する
    - お問合せ内容にリンクが入っている場合は弾くという対策方法ですね。
        - これは本当にリンクを送りたいひとに対してUXが悪くなりそうですね。
- 項目名の変更
    - これは別の項目名にするというものですね。nameとかtelとか自動入力しやすそうな項目なので捻りを加えようというものですね。
        - これはbotの手法が狙った項目に対して入力を行っている場合にのみ有効な対策ではあるが、そのロジックで動かしているのか確証がないので無駄足になりそうな気がしますね。
- 英名のチェック
    - 海外からの攻撃の場合大体が英語名で入力されるのでそれを判定します。
        - これは有効そうな対策ですね。攻撃された内容をみるとほぼ全てが英名での登録で、日本でのみビジネス展開している場合英名のお問合せはよっぽどないので有効と思う。
- 擬似フォームの設置
    - フォームを隠して設置しておき、このフォームに内容が入ってリクエストが来たら弾くというものですね。
        - botのプログラムが狙いの項目に対して自動入力するプログラムであればcontentとかいう項目名にしとけば、大体のプログラムに入ってそう。これもbotの手法が明確でない以上空振りになりそう。でも決まったら楽しそう

    
終わり。