OmniAICreator/Qiita-1.07M huggingface dataset:
ドラッグアンドドロップで複数ファイルをアップロード【jQuery/Laravel】

いまさらながら複数ファイルアップロードするやり方を忘れないようにメモ

## 実現イメージ
赤いところにファイルをドロップするとファイルが追加されて、送信を押すとまとめてアップロードする最低限のサンプル
![スクリーンショット 2021-06-04 14.25.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817/1eba16b6-ca57-9ed1-57a7-2f21312d537c.png)



## HTML
```html:upload.blade.php
    <div id="upload_files_area" style="background-color:red; height:300px; width:100%;"></div>
    <button id="send">送信</button>
```

## JavaScript
```Javascript:upload.js
    $(function(){
        //FormDataオブジェクトを作成
        var formData = new FormData();

        //ファイルがドロップされたときに呼ばれる
        $('#upload_files_area').on('drop', function(ev) {
            var files = ev.originalEvent.dataTransfer.files;
            for (var i = 0; i < files.length; i++) {
                //FormDataオブジェクトにファイルを追加
                //名前は'document_files[]'ってしてやる
                formData.append('document_files[]', files[i]);
            }
        });

        //送信
        $('#send').click(function(){
            $.ajax({
                url:'/upload_exec',
                type:'post',
                data: formData,
                processData: false,
                contentType: false,
                cache: false,
            });
        });
    });

```

## PHP
```php:UploadController
    public function uploadExec(Request $request)
    {
        $files = $request->file('document_files');
        foreach ($files as $file) {
            //ここではS3にアップロード
            Storage::disk('s3')->putFile('path', $file);
        }
    }

```

## まとめ
これだけだとファイルをドロップしても画面上になにも表示されないので、実際にはFormDataに追加されているファイルを表示したり、削除するような機能を追加する必要があると思う。FormDataに追加されているファイルは`formData.getAll('document_files[]');`で配列として取得できるので、それを適当に操作してやると良い。
関数定義する方法

### 関数定義
---
JavaScriptではfunctionを用いることで関数を定義することができます。注意点として引数がない場合にも()を記述する必要があります。

```
function 関数名(引数) {
  //処理
}
```

以下のコードをコンソールで記述し、実行。

```
function sayHello() {
 console.log("こんにちは")
}

sayHello()
```
以下のように表示されます。

```
VM2342:2 こんにちは
undefined
```
Golang net/httpメソッド忘備録

#Golang net/httpメソッド忘備録
Golangのnet/httpパッケージのメソット名と引数と軽い説明を随時、記録していきます。

##サーバー起動
```.go
http.ListenAndServe("", nil)

http.ListenAndServe(":8080", nil)
```
第1引数にはポート番号(string)を渡し
第2引数にはハンドラ(Handle型)を渡す
第1引数 を空に設定するとデフォルトでポート80が設定され、
第2引数は通常nilでデフォルトのDefaultServeMuxというハンドラが設定される。

##ハンドラとハンドラ関数
#####ハンドラ
ハンドラとは、クライアントから送られてきたHTTPリクエストを受け付け、処理をする。
また、HTMLテンプレートエンジンを呼び出し、HTTPレスポンスに組み込んでクライアントに返送できるようにする
MVCパターンでいう、コントローラーとモデルの役割を果たす。

Go言語におけるハンドラはServeHTTPというメソッドを持つインターフェースのことである。

```.go
type Handler interface {
  ServeHTTP(http.ResponseWriter, *http.Request)
}
```

全てServeHTTPのシグネチャ(関数やメソッドの名前、引数、データ型、返り値等の組み合わせ)を持つ。
※インターフェースは型のメソッドを集めた塊のイメージ

#####ハンドラ関数
ハンドラのように振る舞う関数のことであり、ハンドラと同じくServeHTTPのシグネチャを持つ。
単にハンドラを作成するのに便利な手段！

下記hello関数はHandlerFunc(hello)を通じてハンドラとしての振る舞いができるようになる。
HandlerFunc型にキャストするイメージが正しいのだろうか？

```.go
//ServeHTTPのシグネチャを持つhello関数
func hello(w http.ResponseWriter, r *http.Request) {
  fmt.Fprintf(w, "Hello!")
}

HandlerFunc型に変換(ハンドラとして使える)
helloHandler := HandlerFunc(hello)
```

#####混乱のもと、HandleFuncとHandlerFunc

HandleFunc・・・ハンドラ関数をDefaultServerMuxに登録する
HandlerFunc・・・型の名前

まだ途中です！
【WSL】クリップボードを使ってコピー & ペーストを行う

## はじめに

macOSの`pbcopy`, `pbpaste`と同じようなことをWSLでも行いたかったので、調べてみました。

## 結論

### クリップボードにコピー(pbcopy)

`clip.exe`を使います。

```sh
$ echo 'hogehoge' | clip.exe

# クリップボードに `hogehoge\n`が格納されている
```

### クリップボードからペースト(pbpaste)

`powershell.exe -command 'Get-Clipboard'`を使います。

```sh
$ powershell.exe -command 'Get-Clipboard' 
hogehoge

# 末尾で改行される
```

`pbcopy`, `pbpaste`と同じような形で使用した場合は、aliasに指定します。

```sh
alias pbcopy="clip.exe"
alias pbpaste="powershell.exe -command 'Get-Clipboard'"
```

## 補足

### 改行コードを取り除く

どうやら、`clip.exe`を使用すると、末尾に`\n`が入るようです。
クリップボードにコピーする際に改行コードを取り除くのは難しそうなので、
ペーストする際に取り除くようにします。

```sh
$ powershell.exe -command 'Get-Clipboard' | perl -pe 'chomp if eof'
hogehoge
# 末尾の改行が取り除かれる
```

## 参考

- [Copying and pasting from system clipboard using something like xclip · Issue #1069 · microsoft/WSL · GitHub](https://github.com/Microsoft/WSL/issues/1069#issuecomment-391968532)
- [ターミナルで標準出力をクリップボードにコピーする - Qiita](https://qiita.com/sasaplus1/items/137a70e8f51f97a6636f)
- [WSLでpbcopyを使う - Qiita](https://qiita.com/meihei/items/d1c4399b99e4f22eabab)
- [newline - Bash: Strip trailing linebreak from output - Stack Overflow](https://stackoverflow.com/questions/12524308/bash-strip-trailing-linebreak-from-output)
Signateの第10回_Beginner限定コンペの振り返り

![dda11fc13f6edf995b44ce6ab8b3dfc4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1006980/1b4c1e0e-aa24-9902-e064-32b781323344.png)
<h1>はじめに</h1>
<p>データ分析の勉強のために参戦した<a href='https://signate.jp/competitions/461' target='_blank'>SIGNATEの第10回_Beginner限定コンペ</a>が先日終了したので、振り返るために初めて記事を書くことにしました。文章は拙いと思われますが、よろしければ読んでみてください。</p>

<ul>
  <li><a href='#1'>分析環境</a></li>
  <li><a href='#2'>結果</a></li>
  <li><a href='#3'>コンペ内容</a></li>
  <li><a href='#4'>取り組み内容</a></li>
  <li><a href='#5'>今回の反省点</a></li>
  <li><a href='#6'>良かった点</a></li>
</ul>

<h1 id='1'>分析環境</h1>
<p>Google Colaboratory</p>

<h1 id='2'>結果</h1>
![dda11fc13f6edf995b44ce6ab8b3dfc4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1006980/81c43b83-e1dc-75aa-0a09-7358ea8ddca2.png)
<p>最終順位は2位(178人中)。使用モデルはLGBM(fold-out)。</p>


<h1 id='3'>コンペティション内容について</h1>
<h3>概要</h3>
<ul>
  <li>タスク<p>携帯電話のスペックから携帯電話価格帯を分類する多クラス分類</p></li>
  <li>データ<p>学習データ:1200、テストデータ:800のテーブルデータ</p></li>
  <li>評価指標<p>F1macro</p></li>
</ul>

<h1 id='4'>取り組みの大まかな流れ</h1>
<ul>
  <li>EDA<p>説明変数はすべて量的変数とされていたためカテゴリ変数になりうるものはカテゴリ変数化。</p><p>
shape、info、describe、headで全体の把握。</p><p>ヒストグラム、散布図、箱ひげ図、バイオリンプロットで全体の分布の把握。</p><p>カテゴリ変数は全体、クラス毎に相対度数確認。</p><p>最後にtargetとの相関関係を確認。</p></li>
  <li>特徴量作成<p>相関係数が極端に低い変数の削除。</p><p>カテゴリ変数を確認時、クラスごとに最頻の組み合わせがあったため「{}_{}_{}」という形でカテゴリ変数作成。</p><p>学習データ、テストデータを一度合わせて量的変数、カテゴリ変数でクラスターを作成。</p><p>カテゴリ変数をtarget encodingで数値化(<a href='https://towardsdatascience.com/target-encoding-for-multi-class-classification-c9a7bcb1a53'>https://towardsdatascience.com/target-encoding-for-multi-class-classification-c9a7bcb1a53</a>(multilabel化)の方法と通常の方法)。</p></li>
  <li>学習と予測<p>ロジスティック回帰、K近傍法、サポートベクターマシン、決定木、ランダムフォレスト、XGBoost、LightGBMでモデル構築(fold-out、crossvalidation)。</p><p>上記のモデルのアンサンブルの実施(バギング、スタッキング)</p></li>
</ul>
<h1 id='5'>今回の反省点</h1>
<ul>
  <li>githubを使用しなかった上、ファイルも一つで作業を行っていたため、無駄な動作が多くなってしまった。</li>
  <li>CVでtarget encodingする方法で躓いてしまったため、fold-outで強引に進めてしまった。</li>
  <li>Pytorchを理解していなかったため、TabNetは試すことができなかった。</li>
</ul>
<h1 id='6'>良かった点</h1>
<ul>
  <li>上記に書いてないことも含めていろいろ試すことができた。</li>
  <li>TabNetは使用するまでの把握ができなかったが、論文やYoutubeの解説動画を見て学ぶことができた。</li>
</ul>
<h1>今後について</h1>
<ul>
  <li>今回うまく行かなかったところを勉強し、使用できるようにする。</li>
  <li>Gitについて勉強する。</li>
  <li>kaggleのコンペに参加してみる。</li>
</ul>
<h1>最後に</h1>
<p>最後まで読んでいただきありがとうございました。次回の投稿時にはもう少し読みやすいようにしたいです。思考の文章化もできればなと思っています</p>
<h3>参考</h3>
<ul>
  <li>Kaggleで勝つデータ分析の技術(<a href='https://gihyo.jp/book/2019/978-4-297-10843-4'>https://gihyo.jp/book/2019/978-4-297-10843-4</a>)</li>
<li>前処理大全(<a href='https://gihyo.jp/book/2018/978-4-7741-9647-3'>https://gihyo.jp/book/2018/978-4-7741-9647-3</a>)</li>
<li>mechanisms-of-action-moa-tutorial(<a href='https://www.kaggle.com/sinamhd9/mechanisms-of-action-moa-tutorial'>https://www.kaggle.com/sinamhd9/mechanisms-of-action-moa-tutorial</a>)</li>
<li>Target Encoding For Multi-Class Classification(<a href='https://towardsdatascience.com/target-encoding-for-multi-class-classification-c9a7bcb1a53'>https://towardsdatascience.com/target-encoding-for-multi-class-classification-c9a7bcb1a53</a>)</li>
</ul>
VMware vSphere ESXi7.0 ARM版 で vSANを組んでみた on ラズパイ

## 概要
* ラズパイにインストールしたESXiでvSANを組みます。

## 前提
* ESXi7.0 ARM版をラズパイにインストールしていること
    * [ESXi ARM on Rasberry Pi 4B](https://qiita.com/BuckyBuckyBarnes/items/8e276636a12864672c68)を参照

* vCenterにESXiを登録してクラスタを組んでいること
    * [VMware vSphere ESXi 7.0 でラズパイ クラスタを組んでみた](https://qiita.com/BuckyBuckyBarnes/items/d32e37c15e434f15a93a)を参照
* vmkernelにvSANの役割を追加しておくこと

## 準備
* USBメモリ 64GB x 2
    * 容量は任意

## 手順
### USBメモリをラズパイへ接続
* 準備したUSBメモリをラズパイへ接続します。

### USBデバイスをフラッシュ(SSD)としてマークする
* 本設定をしないとUSBメモリがHDDとして認識されます。
    * vSANとして利用するために少なくとも、1つ以上のフラッシュ(SSD)が必要になります。

#### USBメモリのSSDマークの許可
* デフォルトでは、USBメモリはSSDとして利用できないように制限されているの許可をします。
    * 対象のESXi > 設定 > システムの詳細設定 > `Disk.AllowUsbClaimedAsSSD` を`0`から`1`へ修正
![before_usbenable.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/894039/44795b3e-2971-3410-b8f2-0134767608f6.png)

#### USBメモリをSSDとしてマーク
* 作業前
    * ドライブが`HDD`となっています。
    * 対象のUSBを選択して`フラッシュデバイスとしてマーク`をクリックします。
![before_device.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/894039/61521aae-2133-23b3-337c-8709a64c72be.png)

* 作業後
    * 上記が完了すると下記のようにドライブが`フラッシュ`として認識されます。
    * 今回は容量が57.30GB(64GBのUSBメモリ)の２つをフラッシュにしました。
![after_device.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/894039/4461f094-80cc-3ce9-596c-03f4578ad9dd.png)

### USBメモリのvSAN利用の許可
* デフォルトでは、USBメモリはvSANとして利用できないように制限されているので許可をします。
* ESXiへSSHまたはコンソールにてログインして下記のコマンドを実行してください。
    * 今までのようにwebUI経由では変更できないようでした。

```
# esxcli system settings advanced set -o /VSAN/AllowUsbDisks -i 1
```

### USBメモリのパーティションの消去
* USBメモリはデフォルトパーティションが作られてしまっているのでパーティションを消去します。
* 対象のUSBメモリを選択して`パーティションの消去`を実行します。
* 作業前
    * パーティションの詳細に`Win95 FAT32 LBA`と表示されています。
    * ![before_partition.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/894039/42de843e-2c75-5039-ec31-9c8f291f3598.png)

* 作業後
    * 上記の情報が消えました。
    * ![after_partition.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/894039/b67b5cbc-c744-037f-7ea1-be87d6957b8b.png)
* 対象となるUSBすべてで実行していきます。

### vSAN構成
* ここまででやっと準備ができたので、あと通常のvSANと同じです。
    * 対象のクラスタ > vSAN > 構成 で設定ができます。
* 今回は通常のvSAN(単一サイトクラスタ)を構成していきます。
    1. 構成タイプ
        ![1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/894039/2584ad41-44f0-0a47-4005-c695fe66c8c0.png)
    1. サービス
        ![2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/894039/d631443a-afb1-d285-4a5a-306d0aa41963.png)
    1. ディスクの要求
        * ここで準備したUSBメモリをキャッシュとキャパシティの両方に割り当てます。
        ![3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/894039/2e5d102f-8374-0984-a2fc-f2a016c2d78a.png)
    1. フォルトでメインの作成
        ![4.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/894039/8cbad8f3-e375-d2d3-c21b-90b6bc4807b5.png)
    1. 確認
        ![5.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/894039/fd94b689-1bf2-03b3-9ca8-8f84d0cfc326.png)

### 完成
* vSANクラスタができました。
    * USBメモリのためか情報の取得などでエラーは出ていますが、、、、利用はできそうです。
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/894039/cf3508af-d179-980a-3968-b2f16da2941f.png)
[Ruby]自作で破壊的メソッドを作ってみた

## はじめに
自作で破壊的メソッドを作ってみたので備忘録として残しておきます。

## 破壊的メソッドとは
結論から言うと、インスタンス自身の内容を変えてしまうものを破壊的メソッドと呼びます。

```
非破壊的メソッド「reject」
array = [1,2,3]
p array.reject {|item| item == 2} #=> [1, 3]
p array #=> [1, 2, 3]

破壊的メソッド「delete」
array = [1,2,3]
p array.delete(2) #=> [1, 3]
p array #=> [1, 3]
```

上記の例では「非破壊的メソッド」であるArrary#rejectを用いた場合にはarrayそのものの値は変更していないが、「破壊的メソッド」であるArray#deleteを用いた場合にはarrayそのものの値が変更されている事がわかるとおもいます。

##作ってみる
たとえば文字列の先頭に「foo」を付け足す破壊的メソッド「foo!」を定義する場合以下のようになります。

```
class String
　def foo!
  　self.replace("foo" + self)
　end
end
```

たったこれだけですが、以上を参考にいろいろな破壊的メソッドを作れそうです。

## 参考

https://qiita.com/tentom/items/0164b68dff94702e3880
ApacheでPythonを動かす

備忘録として、学校の授業でやったやつを残しておきます。

動作速度とかはまず考えないで、pythonをCGIとして動かします。
というわけで「httpd.conf」を編集。

## httpd.conf の編集
公開設定しているDirectory内で設定しているOptionsに
「ExecCGI」を追加。

```httpd.conf
<Directory "公開しているdirectoryのpath">
    Options ExecCGI 
    ...
</Directory>
```


次に .pyファイルをスクリプトとして認識させたいので、
「AddHandler cgi-script」に.pyファイルを追加。

```httpd.conf
<Directory "公開しているdirectoryのpath">
    Options ExecCGI
    AddHandler cgi-script .py
    ...
</Directory>
```

## pythonファイルの編集
pythonが読み込まれてないと動かないので
!/path/to/python　(シバン) にお使いのPythonのパスを記述。

```hello.py
#!/path/to/python
# -*- coding: utf-8 -*-
print("Content-Type: text/html")
print()
print("Hello!World") 
```

できたら、公開ファイルの直下に入れて、
Apacheを再起動。

localhost/hello.py にブラウザへアクセス!
「Hello! World」　と表示されればOK

###参考記事
http://tech-wiki.pomme-verte.net/?p=538
fishでもaws-cliのprofileを簡単に切り替えたい！！

# fishでもawsのprofileを簡単に切り替えたい！！
これ使ったら、fishでもaws-cliのprofileを簡単に切り替えられます！

## TL;DR
仕事でAWSを使うことになりました。
[AWS CLIのプロファイル切り替えをいい感じにする](https://qiita.com/crossroad0201/items/f84b3e2fece41750755b)でも紹介されいてるawspというコマンドでaws-cliのprofileを簡単に切り替えられるらしい！
しかし、インストールしても、fishは使えない様でした😭。(zshとbashでは使えるらしい。)

ソースコードを読み込んだら、fishでも手軽に実装できそうだったので、実装しちゃいました。
共有します。

## インストール
とりあえず、下記コマンドを実行すると`_awsp`コマンドが使える様になります。

```fish:fish
npm install -g awsp

# インストール完了後下記ファイルを作成。中身は次のブロックに記載。
nano ~/.config/fish/functions/awsp.fish

# 終わったら、再読み込みすると、使える様になります。
exit 
```

下記のように編集

```~/.config/fish/functions/awsp.fish
function awsp
    AWS_PROFILE="$AWS_PROFILE" _awsp_prompt
    set selected_profile (cat ~/.awsp)
    set -xU AWS_PROFILE $selected_profile
end
```

## 参考文献
- [AWS CLIのプロファイル切り替えをいい感じにする
](https://qiita.com/crossroad0201/items/f84b3e2fece41750755b)
Azure 従量課金ライセンス (Pay-As-You-Go) で Cost Alert を設定する方法

# はじめに
Azure 従量課金ライセンス (Pay-As-You-Go)  で __Cost Management > Cost Alert__ を設定する方法について手順をまとめておきます。以前、Azure Spatial Anchors のサンプルを試した際に新規作成したリソース ( Wep Apps ) を放置していたら1万5千円程度 Microsoft から請求書が届いて痛い目にあったので ( 個人アカウント )、、同じ過ちを繰り返さないように..

# Cost Alert とは
Cost Management > Cost Alert を設定すると、Azure 使用量と支出の監視を行うことができます。

Cost Alert は 3種類存在します。

- __Budget alerts / 予算アラート__
- Credit alerts / クレジットアラート
- Department spending quota alerts / 部署課金割当アラート

今回は __Budget alerts (予算アラート)__ を使用してアラートを設定する方法をご紹介します。

# Budget alerts 設定方法
__1. Azure Portal へログインします__

<img width="1280" alt="Azure Portal" src="https://img.esa.io/uploads/production/attachments/3505/2021/06/04/10862/ea1b1c8e-dcad-498b-b8f9-020dee11245a.png">

__2. Cost Management + Billing を開きます__

<img width="704" alt="image.png (151.6 kB)" src="https://img.esa.io/uploads/production/attachments/3505/2021/06/04/10862/9b63a2f8-5da2-4041-b070-ea7cd5525588.png">

__3. Cost Management を開きます__

<img width="1282" alt="image.png (132.0 kB)" src="https://img.esa.io/uploads/production/attachments/3505/2021/06/04/10862/3f9f57d9-b30e-4bbf-a149-bea32c506028.png">

__4. Cost alerts を開きます__

<img width="1282" alt="image.png (120.2 kB)" src="https://img.esa.io/uploads/production/attachments/3505/2021/06/04/10862/5e5784ea-50ff-4469-b28e-8895c18189b0.png">

__5. 追加 ( Add ) ボタンを押します__

<img width="1280" alt="image.png (120.3 kB)" src="https://img.esa.io/uploads/production/attachments/3505/2021/06/04/10862/fd300bd3-acc6-4df8-8e28-8950a7cb56fd.png">

__6. 予算の作成 ( Create a budget ) をします__

予算詳細( Budget Detail ) を設定します。

| 項目 | 概要 |
| --- | --- |
| Name (予算名) | 予算の名前 (一意) |
| Reset Period (リセット期間) | 累計課金額のリセットのタイミング |
| Creation date (開始日時) | 予算の開始日時 |
| Expriation date (終了日時) | 予算の終了日時 |

予算額 ( Budget Amount ) を入力します。

<img width="1874" alt="image.png (261.0 kB)" src="https://img.esa.io/uploads/production/attachments/3505/2021/06/04/10862/4604676a-9d98-453c-a5bd-94f686890a78.png">

__7. Set a alerts を設定します__

- Action Conditions ( アラート発令の条件 )
- Acition Recipients ( アラート受信者 )
- Launguage Prefarence (優先言語)

| Alert Condition | 概要 |
| --- | --- |
| Type | アラートの種類 (実際/予測の値)  |
| % of Budget | アラートを発令する金額 (予算に対する割合) を指定  |
| Action group | アラートの送信先  |

<img width="784" alt="image.png (137.8 kB)" src="https://img.esa.io/uploads/production/attachments/3505/2021/06/04/10862/aecfd1e0-41d9-4293-ab44-10d402b4438d.png">

__8. [Create] ボタンを押下する__

以上で Alert の作成は完了です。

# 作成した Budgets を確認する

作成した Budgets は __Cost Management > Budgets__ より編集することも可能です。

<img width="1282" alt="image.png (139.7 kB)" src="https://img.esa.io/uploads/production/attachments/3505/2021/06/04/10862/e56acd6e-95f3-4922-8271-11ac1e93b2f2.png">
100で割ってから100で掛けると元の数字に戻らないJSの数値の例

最近まで「JSの数値演算は誤差が...」的な話は自分には縁遠かったですが。。。

##  TL;DR;

```js
//左=元の数、右= 元の100で割ってから100掛けた結果（100以下の数の場合）
[ 7, 7.000000000000001 ]
[ 14, 14.000000000000002 ]
[ 28, 28.000000000000004 ]
[ 29, 28.999999999999996 ]
[ 55, 55.00000000000001 ]
[ 56, 56.00000000000001 ]
[ 57, 56.99999999999999 ]
[ 58, 57.99999999999999 ]
```

## 確認方法


```js
// 100で割って100で掛けると少数になる数を抽出
[...Array(100).keys()]
  .map(x => x++)
  .map(x => [x, (x / 100) * 100])
  .filter(x => !Number.isInteger(x[1]))
  .forEach(x => console.log(x));
```

## 対策

元の数より大きい場合、小さいい場合、`.000000000000001`大きい場合、`0.000000000000004`小さい場合、等々まちまち。少数点への演算は、`Math.floor()` , `Math.ceil()`の内部でのみ行うくらいしか思いつかず。
Node.jsでBigQueryを操作する

### この記事に関して
BigQuery + Lambda + CloudWatch を利用して、APIから取得したデータをBigQueryに保存するバッチを実装する機会があり、Node.jsでBigQueryのテーブル作成、テーブルにInsertする方法を書き残したいなと思います。

### 環境
node v12.18.4
TypeScript

### サービスアカウントを作成する
BigQueryへのアクセス権を取得するため、GCPのコンソールからサービスアカウントを作成します。
サービスアカウントのトークンを使用して、GCPのリソースとGoogleCloudAPIsへのアクセスが可能になります。
サービスアカウントのコンソールから秘密鍵を作成し、取得します。
※サービスアカウントとはリソースと同等なので、安全に管理できているか常に気をつける必要があります。
公式ドキュメントでサービスアカウント保護、使用と管理のベストプラクティスが公開されています。
[サービス アカウントの使用と管理のベスト プラクティス](https://cloud.google.com/iam/docs/best-practices-for-using-and-managing-service-accounts?hl=ja)
[サービス アカウントを保護するためのベスト プラクティス](https://cloud.google.com/iam/docs/best-practices-for-securing-service-accounts?hl=ja)

### Node.jsから `@google-cloud/bigquery` を使用する
```
npm install @google-cloud/bigquery
```

### 取得したサービスアカウントの秘密鍵を使用してBigQueryにアクセスする
```
import { BigQuery } from "@google-cloud/bigquery";
...
const bigQueryClient = new BigQuery({
        credentials: {
            private_key: your_service_account_private_key,
            client_email: your_service_account_client_email
        },
        projectId: your_gcp_project_id
    });
```

### 対象データセットに対してテーブルを作成
BigQueryはテーブルをパーティションしないとフルスキャンになるため、パフォーマンス向上のためパーティション分割テーブルを今回の実装では作成しました。

```
// テーブルの存在確認をして、存在しなかったら作成
const isTableExist = await bigQueryClient
        .dataset(dataSetId)
        .table(tableId)
        .exists();
const options = {
        schema: schema,
        location: your_locaiton,
        timePartitioning: {
            type: "DAY"
        }
    };
await bigQueryClient.dataset(dataSetId).createTable(tableId, options);
```
### 作成したテーブルに対してデータをインサートする
```
await bigQueryClient
        .dataset(dataSetId)
        .table(tableId)
        .insert(data);
```

### 注意した点
負荷を減らすため、APIからデータを取得するたびにテーブルにインサートするのではなく、APIからある程度まとまったデータセットを取得してからインサート処理を実行するようにし、インサート回数ができるだけ少なくなるよう注意しました。

参考文献
https://cloud.google.com/bigquery/docs/reference?hl=ja
https://cloud.google.com/bigquery/docs/partitioned-tables?hl=ja
https://github.com/googleapis/nodejs-bigquery
IBM Security Verify APIの非推奨ポリシーについて

# はじめに
IBM Security Verify では、新しいAPIがリリースされた場合、古いAPIは、非推奨 API という位置づけになります。
古いAPIはいつまで使えるのか、どのように通知があるのかについてご紹介します。

# 非推奨 APIについて

非推奨のAPIに関するポリシーは以下の通りです。

- 非推奨の期間は 12 カ月
- 非推奨APIの確認方法
    - Swagger（RESTAPI Documentation)では、deprecated として表示される。
    - マニュアルの「新機能」ページでも通知される。
    - マニュアルの「非推奨の API」ページには、非推奨のAPIと、代替のAPIがリストされる。

## Swagger（RESTAPI Documentation)での表示例

|![deprecated (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678692/02e6a54c-5d15-608c-c187-d16d96352487.png)
|:--|

## 新機能ページの通知例

|![deprecated (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678692/da058a57-1c0b-156d-9485-2e881ac0c0e5.png)
|:--|

## 「非推奨の API」ページの通知例

|![deprecated (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678692/b79f4a9b-ae1d-3faf-4c82-2740721e35fb.png)
|:--|


# 参考情報

- API 互換性ポリシーおよび非推奨ポリシー
    - https://www.ibm.com/docs/ja/security-verify?topic=apis-api-compatibility-policy-deprecation-policies

- 非推奨の API
    - https://www.ibm.com/docs/ja/security-verify?topic=policies-deprecated-apis
【Rails】カスタムバリデーションを作成してAncestyに階層制限をかける

## はじめに

現在、共同開発にてドキュメント作成アプリを開発中です。
その中でAncestryを用いた階層構造を実装しており、機能としてはドキュメント作成時にタイトル部分に`/` を入力して、文章を区切ることによりディレクトリが作成できるようになっています。

今回はディレクトリの階層を５階層までにしたかったので、バリデーションをかけようと思います。しかし、デフォルトのバリデーションオプションでは難しそうでした。

そこで色々調べていくと`ActiveModel::EachValidator`　を使うことで、独自のバリデーションを追加することが分かり便利だなと思ったため、備忘録として使い方を残しておきます。

## カスタムバリデーターの作成

### カスタムバリデーターとは

`ActiveModel::Validator`や`ActiveModel::EachValidator`　を使って自作のバリデーションを作成することです。

独自のバリデーションルールを追加しようとする時に、modelに書くと可読性が悪くなり、更には管理も大変になってしまいます。それを防ぐためにバリデートクラスと呼ばれる、バリデーションを自作するためのクラスを継承したクラスを作ります。

今回は使いやすいということで、`ActiveModel::EachValidator`　を継承したクラスを作成して、そこに独自のバリデーションルールを書いていきます。

### ファイルの作成

1. `app/`配下に`validators`ディレクトリを作成します。
2. `app/validators/<検証名>validator.rb`の形式でファイルを作成
3. `ActiveModel::EachValidator`　を継承したクラスを作成

```ruby:app/validators/ancestry_validator.rb
class AncestryValidator < ActiveModel::EachValidator
end
```

ここで指定したクラス名が、modelでカスタムバリデーターを呼び出す際に使われます。

これでカスタムバリデーションを実装する準備ができたため、後はこのファイルにロジックを書いてあげれば完了です。

## バリデーションルール作成

まずはカスタムバリデーション用にRailsが用意してくれている、`validate_each`メソッドを追加しましょう。

```ruby:app/validators/ancestry_validator.rb
class AncestryValidator < ActiveModel::EachValidator
	def validate_each(record, attribute, value)
	end
end
```

### `validate_each` メソッドの３つの引数

`validate_each` メソッドの3つの引数の中身にはそれぞれ、以下の値が入ります。

### record

ここにはオブジェクトが入ります。

### attribute

これには属性が入ります。
今回で言えば`:ancesty`が返ってきます。

### value

ユーザーが入力した値が入ります。
文字数検証などに使います。

以上のことを踏まえた上で、カスタムバリデーションを設定していきましょう！

### カスタムバリデーション設定

今回は5階層以降のディレクトリを作成したくないため、以下のように設定しました。

```ruby
class AncestryValidator < ActiveModel::EachValidator
	def validate_each(record, attribute, value)
		if value.count("/") > 3
      record.errors.add(attribute, "ディレクトリは6つ以上作成できません！")
    end
	end
end
```

`/` の数により何階層目かを判断して、3つ以上になると6階層目になるためバリデーションに引っかかるようにしています。

- `record.errors.add(属性, メッセージ)`

上記のようにすることでバリデーションを発生させて、メッセージを追加することができます。

属性を指定することで、今回なら「ancestryディレクトリは6つ以上作成できません！」と表示されるようになります。

## 呼び出し

最後に設定したバリデーションを使えるように、対象のモデルでカスタムバリデーションを呼び出す記述を追加しましょう！

```ruby
validates :ancestry, ancestry: true
```

この記述により、ancestryカラムに対してAncestryValidatorクラスのカスタムバリデーションを適応させることができます。

## まとめ

今回は`ActiveModel::EachValidator`　を使った、独自のバリデーションを作成する方法について紹介しました。

初めて自作のバリデーションを作成しましたが、これを使いこなせるようになれば何でも検証できて便利だなと思ったので、ぜひ使いこなせるようになりたいと思います！
hosts書かずにcurlでアクセスする方法

## まず普通にやってみる

- テキトーなファイル置いてます

```
# cat /var/www/html/index.html 
hello world
```

- localhostで接続

接続できました

```
# curl http://localhost/index.html
hello world
```

- hostsに適当なドメイン設定

一番下を追加

```
# cat /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost6 localhost6.localdomain6

127.0.0.1   xxxx.com
```

- xxxx.com で接続

接続できました！

```
# curl http://xxxx.com/index.html
hello world
```

## hosts書かずにやってみる

- hostsはもとに戻しました

```
# cat /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost6 localhost6.localdomain6
```

- xxxx.com で接続

hosts戻したから出来ない

```
# curl http://xxxx.com/index.html
curl: (6) Could not resolve host: xxxx.com
```

- hostsに書かずにxxxx.comで接続

`--resolve xxxx.com:80:127.0.0.1` を追加
接続できました！

```
# curl --resolve xxxx.com:80:127.0.0.1 http://xxxx.com/index.html
hello world
```

## 勉強後イメージ

ちょっとした確認するのに便利！！

## 参考

- [curlには名前解決を操作できるオプションがある](https://www.softel.co.jp/blogs/tech/archives/6081)
- [curlに名前解決を操作できるオプションがあって超絶便利だった話](http://racchai.hatenablog.com/entry/2016/06/05/070000)
広告IDを使用したパーソナライズがオプトアウトされると広告IDが使用できなくなる予定


タイトルの通りで、広告 ID を使用したパーソナライズがオプトアウトされると広告 ID が使用できなくなるというアナウンスがあった。

https://support.google.com/googleplay/android-developer/answer/6048248/advertising-id?hl=en&ref_topic=2364761

## 何が起きるのか
> As part of Google Play services update in late 2021, the advertising ID will be removed when a user opts out of personalization using advertising ID in Android Settings. Any attempts to access the identifier will receive a string of zeros instead of the identifier.

- ユーザーが設定で広告のパーソナライズをオプトアウトすると、広告 ID が削除される
- アプトアウトされた状態で広告 ID を取得しようとすると 0 の文字列が返ってくるようになる

## いつから起きるのか
> This Google Play services phased rollout will affect apps running on Android 12 devices starting late 2021 and will expand to affect apps running on devices that support Google Play in early 2022.

- 2021 年後半の Google Play サービス アップデートで段階的に適用される
    - 2021 年後半からは Android 12 デバイスが対象
    - 2022 年初頭には Google Play をサポートするデバイスが対象

## どう対応するのか

> In July, we will provide more details and an alternate solution to support essential use cases such as analytics and fraud prevention.

7 月により詳細な情報と、分析や不正防止などの必須ユースケースをサポートする代替ソリューションが出てくるらしい。
一意の識別子のベストプラクティスは [Best practices for unique identifiers](https://developer.android.com/training/articles/user-data-ids) を参考にとのこと。
[解決方法] cannot find a valid baseurl for repo base 7 x86_64 [CentOS 7]

# はじめに
VirtualBox上にCentOS環境を構築し、そのサーバー上でyum installしたらタイトルのエラーを吐いたので修正方法を記述しておく。

# 実行環境
```
ホストOS: Windows10
VirtualBox 6.1.22
ゲストOS: CentOS 7
接続構成
アダプター1: NAT, アダプター2: ホストオンリーアダプタ
```

# どういった状況だったのか
色々なサイトを調べた結果、以下のような手順を踏んだ。

1. とりあえず最初にping 8.8.8.8を実行し、インターネットに接続されているか確認する。

    ホストOS（Windows10）: ping 8.8.8.8 → 繋がる。
    ゲストOS（CentOS 7） : ping 8.8.8.8 → 繋がらない。

2. ファイアーウォールを切る。
    
    自分の場合はAnsibleで構成管理をしており、その際に事前にファイアウォールを無効化していた。
    → ホストOSは問題なさそう、VM上のネットワークの設定が間違っている可能性が高いという結論に辿り着く。

# 解決方法
ゲストOSを起動し、NATのイーサネット設定（enp0s3）を以下のコマンドで確認したら「ONBOOT=no」になっていました。（noに設定した記憶ないんですけどね...）vimコマンドでnoをyesに修正し、上書き保存する。

```
$ vi /etc/sysconfig/network-scripts/ifcfg-enp0s3
```

その後、以下のコマンドでネットワークを再起動したらping8.8.8.8に繋がるようになり、yum installもできるようになりました。

```
$ systemctl restart network
```
plunkerでvue その46

#概要

plunkerでvueやってみた。
練習問題、やってみた。

#練習問題
 
vuetifyとaxiosを使って、get,post,put,deleteを実装せよ。

#サンプルコード

```

new Vue({
  el: "#app",
  data() {
    return {
      dialog: false,
      isCreate: true,
      editedItem: {
        id: 0,
        name: '',
        email: 0
      },
      headers: [{ 
        text: 'ID', 
        value: 'id' 
      }, {
        text: '名前',
        value: 'name',
      }, { 
        text: 'メルアド', 
        value: 'email' 
      }, {
        text:'修正/削除',
        value:'delete',
        sortable:false
      }],
      serverDatas:[],
    }
  },
  computed: {
    formTitle() {
      return this.isCreate ? 'New Item' : 'Edit Item'
    }
  },
  watch: {
    dialog(val) {
      val || this.close()
    }
  },
  methods: {
    deleteItem(item) {
      confirm('削除しますか') && this.deleteUser(item)
    },
    editItem(item) {
      this.isCreate = false
      this.editedItem = item
      this.dialog = true
    },
    close() {
      this.dialog = false
    },
    save() {
      if (!this.isCreate) 
      {
        this.update()
      } 
      else 
      {
        this.create()
      }
      this.dialog = false
    },
    update() {
      axios.patch('https://jsonplaceholder.typicode.com/users/' + this.editedItem.id, {
        name: this.editedItem.name,
        email: this.editedItem.email
      }).then(response => this.users.unshift(response.data)).catch(error => conalert(error))
    },
    create() {
      axios.post('https://jsonplaceholder.typicode.com/users', {  
        name: this.editedItem.name,
        email: this.editedItem.email
      }).then(response => this.serverDatas.unshift(response.data)).catch(error => alert(error))     
    },
    deleteUser(item) {
      axios.delete('https://jsonplaceholder.typicode.com/users/' + item.id).then(response => console.log(response)).catch(error => alert(error)) 
      const index = this.serverDatas.indexOf(item)
      this.serverDatas.splice(index, 1)
    },
  },
  created() {
    axios.get('https://jsonplaceholder.typicode.com/users').then( res => {
      this.serverDatas = res.data
    }).catch(e => {
      alert(e)
    }).finally(()=>{
      //alert("通信完了")
    })
  }
})




```

#成果物

https://embed.plnkr.co/plunk/x2H6gNJvUmkyFXzi

以上。
開発からそのまま運用保守を担当することになった際の注意点

# 前提

当初のプロジェクト体制

PM　→　1名
PL　→　1名
メンバー　→　2名(自分も)

↓

保守の体制

PL　→　1名
メンバー　→　1名(自分)

# 保守体制を明確化する

お客様も誰を窓口として対応していいかわからないし、
保守側も誰に指示を仰げばいいかわからない。

この状態になると保守が後手後手になり、お客様の心象に悪い。

# 横文字禁止

自分はSalesforceをメインにプロジェクト参加しているが、
お客様はオブジェクトやレコードなどの単語は知らない。

ついプロジェクトメンバー間でも言葉を使ってしまうかもしれないが、
その言葉はお客様に伝わらないかもしれない。

お客様もプロジェクトに対応してくれていたので、
知っているだろう。と思って使うと伝わらない時もある。

お客様にはお客様の本業が有るのでわかりやすい言葉を使うように心がける。

# 文字だけは不自由と認識する

メラビアンの法則の通り、コミュニケーションの大半は以下。

視覚情報	見た目、しぐさ、表情、視線	55%
聴覚情報	声の質や大きさ、話す速さ、口調	38%
言語情報	言葉そのものの意味、会話の内容	7%

言語自体も人間として新しい分野なので伝わらない前提で対応する。

# キャプチャ多様

文字だけでは伝わらない。
認識の齟齬防止のため、キャプチャを使用すると〇。

さらにキャプチャ内に赤丸など付け足すと優しい。

# 文章を要約する

こちらの本業は保守対応でも、
お客様の本業はまた別にある可能性が高い。

長文を送ると読んでもらえない可能性があるので、要約した内容、見た目が重要。

# お客様に不要な項目は非表示に

更新対象のモジュール一覧や定義書の更新内容はお客様に不要。
保守をやり取りしているプラットフォームがカスタマイズ可能なら、
お客様用の項目、保守担当の項目と画面上に権限設定などで分けて出す。
MacでVBA　Dir関数を使う場合

#WHY
マクロ組む際、誰もがぶち当たるであろうDir関数(特にmac勢は、、、とどこかの記事でみました)
今回の学習で手こずったところがあるのでメモとして残しておく。

##Dir関数
ファイル操作の基礎中の基礎である「Dir関数」

```VBA.
ws = Dir("パス")
```
と記述することでファイルまたはフォルダ名の文字列の値を返す。
なにもない場合は空が返ってくる。

##パス

macの場合、区切りには「¥」ではなく「/」を使う。
詳しくはコードのどこかに

```VBA.
MsgBox ThisWorkbook.Path
```
とすればまあ書き方の参考にはなる。


##拡張子

ワイルドカードを使ってファイルの拡張子をしていするときは\*.xls*と書く。
macではワイルドカードが使えないという噂も聞いたが自分の場合特に問題はなかった。

##Application.PathSeparator

区切り文字「/」を返す。
「/」なのか「¥」なのか「:」なのか不安な場合はこれ書けばいいとおもう。

つまり、仮に(1,1)セルにパスを記述していた場合、

```VBA.
FileName = Dir(Cells(1, 1) & Application.PathSeparator & "*.xls*")
```

とすることでそのディレクトリ内の「xlsm」「xlsx」ファイル等が取得できる。

-----------
とりあえず何が返されているか不安な時はメッセージボックスで確認...
はやくWindowsがほしい。
Sony SPRESENSE での Adafruit のライブラリがビルドエラーになるときの対応方法

Adafruitのライブラリは各種センサーに対応しています。
自分も良く使っていて、特に新しい(使ったことのない)センサーのテストに良く利用しています。

SONY の Spresense でいくつかのAdafruitのライブラリでビルドエラーなってしまっていました。
エラーが出たライブラリは ssd1306、SGP30等です。

例えば
ssd1306 のサンプルプログラム ssd1306_128x64_i2c.ino をビルドすると以下のエラーが発生します。

```
C:\Users\user\Dropbox\Git\Arduino\libraries\Adafruit_BusIO\Adafruit_SPIDevice.cpp: In constructor 'Adafruit_SPIDevice::Adafruit_SPIDevice(int8_t, int8_t, int8_t, int8_t, uint32_t, BitOrder, uint8_t)':
C:\Users\user\Dropbox\Git\Arduino\libraries\Adafruit_BusIO\Adafruit_SPIDevice.cpp:51:70: error: 'digitalPinToPort' was not declared in this scope
   csPort = (BusIO_PortReg *)portOutputRegister(digitalPinToPort(cspin));
                                                                      ^
C:\Users\user\Dropbox\Git\Arduino\libraries\Adafruit_BusIO\Adafruit_SPIDevice.cpp:51:71: error: 'portOutputRegister' was not declared in this scope
   csPort = (BusIO_PortReg *)portOutputRegister(digitalPinToPort(cspin));
                                                                       ^
C:\Users\user\Dropbox\Git\Arduino\libraries\Adafruit_BusIO\Adafruit_SPIDevice.cpp:52:40: error: 'digitalPinToBitMask' was not declared in this scope
   csPinMask = digitalPinToBitMask(cspin);
                                        ^
C:\Users\user\Dropbox\Git\Arduino\libraries\Adafruit_BusIO\Adafruit_SPIDevice.cpp:58:76: error: 'portInputRegister' was not declared in this scope
     misoPort = (BusIO_PortReg *)portInputRegister(digitalPinToPort(misopin));
                                                                            ^
exit status 1
ボードSpresenseに対するコンパイル時にエラーが発生しました。
```

このエラーの対処方法は
Arduino\libraries\Adafruit_BusIO\Adafruit_SPIDevice.h
の51行目をコメントアウトします。
(ディレクトリはご自身の環境に合わせてください。)

```
50 #if not defined(__ASR6501__)
51 #define BUSIO_USE_FAST_PINIO
52 #endif
```
　↓　↓　↓　↓　↓

```
50 #if not defined(__ASR6501__)
51 // #define BUSIO_USE_FAST_PINIO
52 #endif
```

これでビルドエラーが無くなり、プログラムも問題なく動きます。
Adafruitのセンサーライブラリを使ったときに同じエラーが発生した場合は
この対策を施してください。

自分は Arduino ide で SONY Spresense だけでなく Arduino類、ESP32等でも使っていますのでSpresense でエラーが出ても他のボードではエラーが出ていなかったので原因の究明と対策を行っていませんでしたが、今回Spresenseの開発関係者の方からサポートをしていただき解決しました。

ありがとうございました。
作業用に切ったブランチに元ブランチ(masterやdevelop)の最新内容を取り込む

こんにちは、JeffTechです。

# 説明
今回は業務の中で、developブランチから切ったfeature/ticket369というブランチで作業していた際に、共同開発者がdevelopを更新し、その更新内容（最新の状態）をfeature/ticket130に取り込みたいということが発生いたしました。
その時に行った解決策をご紹介いたします。

# 方法
## ①feature/ticket130ブランチをstashで保存
feature/ticket130のブランチで何らかの作業をしていると思いますので、
stashでそれらを保存しておきましょう。
どのファイルも変更していなければ、こちらは飛ばしてください。

```bash
$ git stash -u
```
`-u`オプションを付けると、未追跡のファイルもstashしてくれます！便利！
ちなみに、普通にcommitして良い方は、stashではなく、commitでもOKです！
私の場合は、commitするとどこを編集しているのかがエディターで確認しにくいのと、無駄なコミットを作らないようにしたいのでstashでやってます！

## ②元ブランチ（develop）にチェックアウト

```bash
$ git checkout develop
```

stashやcommitで保存が保存が完了したら、
取り込みたいブランチにチェックアウトしましょう！

## ③developブランチの最新情報を取得

```bash
$ git pull origin develop
```

## ④作業用ブランチ（feature/ticket369）にチェックアウト

```bash
$ git checkout feature/ticket369
```

## ⑤developブランチの内容をリベースする

```bash
$ git rebase develop
```

## ⑥stashで保存していた内容を反映させる
もし①でstashしていた方は、内容を改めて反映させなければならないので、stash applyをしましょう。

```bash
$ git stash apply stash@{0} 
```

# 最後に
少しでも役に立った！という時は、いいねをポチッとして
フォローしてくださると嬉しいです、、、笑

役に立たなかった時は、怒らないでコメント頂けますと幸いです笑

Twitterもやってますので、よかったら見てみてくださいね！
https://twitter.com/jefftechsaku
Laravel&PHP&Carbonで時間の切り上げ、切り下げをする。（時間を丸める）

こんにちは、JeffTechです。

# 説明
今回は業務の中で、時刻を15分ごとの切り上げで表示する処理を実装したので、備忘録程度にまとめておきます。
おまけに、30分ごとの切り下げもやっていきます。

# この記事で実現できること
- 時刻を丸める

# 開発環境
- OS:MacOS
- PHP:7.3
- Laravel:6

# 実装
15分切り上げる処理
例：12:53:32 → 13:00:00
　　10:13:32 → 10:15:00

```php
// 切り上げる分数
$roundUp = 15;

// Carbonインスタンス作成
$dateRoundUp = new Carbon('2021-06-04 11:48:25');

// 15分切り上げ→12:00:00になる
$dateRoundUp = $dateRoundUp->addMinutes($roundUp - $dateRoundUp->minute % $roundUp)->format('Y-m-d H:i:00');
```

30分切り下げる処理
例：12:53:32 → 12:30:00
　　10:13:32 → 10:00:00

```php
// 切り下げる分数
$roundDown = 30;

// Carbonインスタンス作成
$dateRoundDown = new Carbon('2021-06-04 14:48:25');

// 30分切り上げ→14:30:00になる
$dateRoundDown = $dateRoundDown->subMinutes($dateRoundDown->minute % $roundDown)->format('Y-m-d H:i:00');
```

切り上げ、切り下げともにroundUpとroundDown変数を変えることで、10分の切り上げや切り下げなど臨機応変に対応できるようになります。


# 最後に
少しでも役に立った！という時は、いいねをポチッとして
フォローしてくださると嬉しいです、、、笑

役に立たなかった時は、怒らないでコメント頂けますと幸いです笑

Twitterもやってますので、よかったら見てみてくださいね！
https://twitter.com/jefftechsaku
Arduinoでスプレイヤーの自動調圧を作る

###まえがき
注意：実装テスト前です。
数値が出てきてリレーが動くまでは確認しています。しかし実機による動作チェックはしていません。

![IMG_7473.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181687/019b8ff0-d80b-38cf-135b-2c97ce2bf1b3.png)

###材料
・北海道の農業者のご家庭にごく一般的にある、自動調圧がなく、電動調圧が付いているスプレイヤー
・Arduino uno
・電気の知識
・可変抵抗 10kオーム（2個あるとテストが捗ります）
・圧力センサー
https://www.amazon.co.jp/gp/product/B08D6L82ZD/
耐久性等も考えると、ちゃんとした圧力センサーのほうが良さそうです。
https://www.monotaro.com/g/01985014/
・センサーに分岐する配管材料
センサーのネジは一般的にNPTネジですが、スプレイヤー側は国産のものだとPTネジ（Gネジ）の場合が多いので、注意して買わないと使わない部品だらけになります。
参考資料:https://www.torque-system.jp/items/pdf/mm_NPT-PT.pdf

・i2c接続のLCD
今回はたまたま転がっていた[こちら](https://akizukidenshi.com/catalog/g/gK-11354/)を使いましたが、本来はIO電圧3.3v用なので、[IO5v対応したもの](https://akizukidenshi.com/catalog/g/gK-08896/)を買う事をおすすめ。表示サイズも大きいですし。
・リレーモジュール
https://www.amazon.co.jp/gp/product/B00L11KL10/
・配線

###配線
A0-圧力センサー
A1-可変抵抗
リレーA-8
リレーB-9
その他、電源とGNDを繋ぎます。

###ソース
・toleranceで誤差範囲を決めています。
初期設定は±100ですが、調圧モータ速度、圧力のかかり具合、実際の圧力の反映速度にタイムラグがあると思うので、実機により要調整。

<details><summary>ソース</summary><div>

```
#include <MsTimer2.h>
#include <Wire.h>
#include <FaBoLCDmini_AQM0802A.h>

// initialize LCD
FaBoLCDmini_AQM0802A lcd;

int tolerance=100;

int sensorPin=A0;
int resistorPin=A1;
int upPin=8;
int downPin=9;

int sensorValue=0;
int pressureValue=0;
int pointValue=0;
int pos=0;

void setup() {
  pinMode(upPin,OUTPUT);
  digitalWrite(upPin,LOW);
  pinMode(downPin,OUTPUT);
  digitalWrite(downPin,LOW);
  Serial.begin(115200);
  
  MsTimer2::set(500,flash);
  MsTimer2::start();
  
  lcd.begin();
  //lcd.print("hello");

}

void loop() {
  Serial.println(pressureValue);
  Serial.println(pointValue);
  lcd.setCursor(0, 0);
  lcd.print("Set:");
  lcd.print(pointValue);
  lcd.setCursor(0, 1);
  lcd.print("P:");
  lcd.print(pressureValue);

  if (pressureValue<=(pointValue-tolerance)){
    digitalWrite(downPin,HIGH);
    digitalWrite(upPin,LOW);
    lcd.print("UP");
    delay(500);
    pos=1;
  }
  if (pressureValue>=(pointValue+tolerance)){
    digitalWrite(upPin,HIGH);
    digitalWrite(downPin,LOW);
    lcd.print("do");
    delay(500);
    pos=1;
  }
  if (pressureValue>=(pointValue-tolerance) or pressureValue<=(pointValue+tolerance)){
    digitalWrite(upPin,HIGH);
    digitalWrite(downPin,HIGH);
    if(pos==1){
    lcd.setCursor(0, 0);
    lcd.print("Set:");
    lcd.print(pointValue);
    lcd.setCursor(0, 1);
    lcd.print("Newtral ");
    delay(10);
    pos=0;
    }
  }
}

void flash(){
  sensorValue=analogRead(sensorPin);
  pressureValue=5000.0*sensorValue/1024;
  pointValue=5000.0*analogRead(resistorPin)/1024;
}

```
</div>
</details>
Anaconda「zshでコマンドプロンプトが効かない」

現在、pythonを勉強しようとしております。
本日はmacでAnnacondaをインストール後、zshで`conda`コマンドが効かない現象が起きたのでメモとして残しておきます。

# zshでcondaコマンドが効かない
なぜこの現象が起きたのかを見たところ、Anacondaをインストールした同時にパスを通す記述がされるのは`~/.bash_profile`だったことが原因なようでした。

```zsh:ターミナル
% conda info
zsh: command not found: conda
```

```zsh:ターミナル
% which python
/usr/bin/python #macのデフォルトのpythonのパス

% python --version
Python 2.7.16 #インストールしたのはpython 3.~なはず。。。
```


自分：「え！ダウンロードしたじゃん！condaコマンド使えるでしょ！おかしいよ！」
zshさん：「....そんなコマンドないし、読み込むパスないもん。」

---

# とりあえずbash_profileの中身を移して解決
```bash:ターミナル
% less ~/.bash_profile
# >>> conda initialize >>>
# !! Contents within this block are managed by 'conda init' !!

~(略)~

# <<< conda initialize <<<

```
上記の中にある`/Users/Owner/opt/anaconda3/bin/python`までをコピーしてzshファイルに記述する。

```zsh:ターミナル
% vi ~/.zshrc

iボタンを押してインサートモードにしてから

↓をペースト
/Users/Owner/opt/anaconda3/bin/python

escボタンを押し、:wqを入力する。

% source ~/.zshrc

一応ターミナルを再起動
```

### 実行後
```zsh:
% which python
/Users/Owner/opt/anaconda3/bin/python

% python --version
Python 3.8.5
```


こちらで一旦解決できました。
問題点などあれば、コメントいただけますと幸いです。
lwc 的js文件如何实现互相导入

lwc
module1
module1.html
module1.js
module1-extra.js
module2
module2.html
module2.js
How to import module1-extra.js into module2.js ?


lwc
// module2.js
import { foo } from 'c/module1';

// module1.js
export { foo } from './module1-extra';

// module1-extra.js
export const foo = 'bar';
Widgetクラスのプロパティはprivateじゃなくてもいいんじゃないかという考え

# はじめに
以下のようなコードを書いたとき

```dart:main.dart
void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}
```

```dart:my_home_page.dart
class MyHomePage extends StatelessWidget {
  const MyHomePage({required this.title});

  final String title;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
          ],
        ),
      ),
    );
  }
}
```

`MyHomePage`内の `title`は外部からアクセスできてしまいます。

```dart
    final myHomePage = const MyHomePage(title: 'hoge');
    debugPrint(myHomePage.title);
```

これはできるだけ外側に公開しないようにprivateにしたいです。

# privateなプロパティとして定義
Initializer listを使ってコンストラクタ引数を初期化するようにした場合、外部から `_title`へはアクセスできないです。
しかし、コンストラクタの書き方が先程と比べて煩雑になってしまいます。コンストラクタ引数が増えたときもcommaで改行していくので肥大化していきます。

```dart:main.dart
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final myHomePage = const MyHomePage(title: 'hoge');
    debugPrint(myHomePage._title); // 参照できない

    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}
```

```dart:my_home_page.dart
class MyHomePage extends StatelessWidget {
  const MyHomePage({required String title}) : _title = title;

  final String _title;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(_title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
          ],
        ),
      ),
    );
  }
}
```

# まとめ - プロパティをprivateにしたときのメリット・デメリット
Widgetをファイルで分けて定義すれば先程のような感じでプロパティをprivateにして外部に公開しないようにできますが、同一のファイル内で同じことを書いた場合、実はアクセスできてしまいます。

画面ごとなど大きな単位ではファイル分けして書いていくと思いますが、複雑なデザインをまとまりのあるセクションごとに作る場合などは、1つのファイル内にまとめてある一定のUIの塊のセクションごとにprivateなクラスとして切り出してそれらを組み合わせて1つのUIを作ることもあると思います。

その場合は、同一のファイル内にいるクラスとその中のプロパティなため、Initializer listを使った書き方をしてもファイル内の他のクラスからもアクセスできてしまいます。

これはあくまで個人的な考えですが、Widgetのクラスを定義するときのプロパティは無理にprivateにする必要はないんじゃないかなと考えています。

外からプロパティが見えたとしてもWidgetをインスタンス化させてプロパティにアクセスしようとすることはほとんどないと思います。
また仮にそうするケースがあったとしても、プロパティは `final`定義しているので、外部からは変更不可能です。

これらを回避するために、煩雑な書き方を選択するメリットよりもデメリットのほうが大きいんじゃないかと思っています
。
本当にこれは個人的な考えなので、「そんな考え方もあるな〜」程度で捉えて貰えればなと思います。
memo : kind

https://kind.sigs.k8s.io/docs/user/quick-start/

```sh
# kindコマンドをダウンロード
curl -Lo ~/bin/kind \
 "https://kind.sigs.k8s.io/dl/v0.11.0/kind-linux-amd64"

# kubectlコマンドをダウンロード
curl -LO \
 "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl"

```

```sh
# クラスターの作成 (2分はかかる)
# (メモリ2GBは必要。足りなければエラーになる)
kind create cluster

# クラスター一覧
kind get clusters

# クラスターの確認
kubectl cluster-info

# node一覧
kubectl get nodes

# 全情報
kubectl get all -A
```

```sh:デプロイ
wget "https://k8s.io/examples/service/access/hello-application.yaml"

# yamlの適用
kubectl apply -f hello-application.yaml

# デプロイ (少し時間がかかる)
kubectl expose deployment \
 hello-world \
 --type=NodePort \
 --name=example-service

# ポートフォワード

# http://localhost:8080 で待ち受け
kubectl port-forward svc/example-service 8080:8080 --address localhost
# もしくは 0.0.0.0:8080で待ち受け
kubectl port-forward svc/example-service 8080:8080 --address 0.0.0.0
```

* http://localhost:8080 にアクセスし応答があることを確認。

```sh:
# サービス一覧 (docker ps -aのようなもの)
kubectl get service
または
kubectl get svc
```

```sh:
# クラスタの削除
kind delete cluster --name kind
```
当たり前だけどJSXは<script type="text/babel">で読み込む！！

# やりたいこと
Reactだけを使ってHello, World!を出力したかった。
参考サイト：https://sbfl.net/blog/2019/02/20/react-only-tutorial/

# 起こったこと
JSXで文法はあってるのに`Uncaught SyntaxError: Unexpected token '<'`エラーが起きて詰んだ。

# 前提条件
ReactとbabelをCDNで読み込んでいる。

# 環境
react： v16.14.0
react-dom: v16.14.0
babel: v6.26.0
サーバー：Live Server v5.6.1（VScodeの拡張機能）

# 問題のCode
## HTML
```html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>孤独ったー</title>

    <!-- ReactをCDNで呼び出す -->
    <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>

    <!-- 自分で記述するスクリプト -->
    <script type="text/javascript" src="main.jsx"></script>
</head>
<body>
    <!-- React の描画対象を準備する -->
    <div id="app"></div>
</body>
</html>
```

## JSX
```jsx
function App() {
  return <div>Hello React!</div>;
}
const target = document.querySelector('#app');
ReactDOM.render(<App/>, target);
```

# 解決策
HTMLの自分で記述するスクリプトのtypeを間違って指定していた。
誤：`<script type="text/javascript">`
正：`<script type="text/babel">`

# なぜこのような事が起こるのか
私がまだReactとJSXの仕組みをよくわかってないことが原因なんですけど、つまりは以下のようになってるからなんですね〜

### JSXがレンダリングされる仕組み
[JSX]→[Babel]→[Javascript]→[HTML]

1. JSXがBabelによってJavascriptに翻訳される
2. 翻訳されたJavascriptがHTMLによって読み込まれる
3. 表示される

こういう事だったんですね。

# 最後に
そりゃtype間違えば正しく動かないのは理解できたけど。。。
エラー箇所と全く違うところをエラーポイントとして怒らないでほしいな！！！！！！！！！（怒）

# 参考サイトなど
https://sbfl.net/blog/2019/02/20/react-only-tutorial/

https://www.fenet.jp/dotnet/column/environment/7497/#i-2

https://qiita.com/koedamon/items/92c986456e4b9e845acd
VMware vSphere ESXi 7.0 でラズパイ クラスタを組んでみた

## 概要
* ラズパイにインストールしたvSphere ESXi7.0でvCenterに登録してみた。

## 前提
* ラズパイにESXiがインストールされていること。
* インストールはこちらを参照いただければと思います。
    * [ESXi ARM on Rasberry Pi 4B](https://qiita.com/BuckyBuckyBarnes/items/8e276636a12864672c68)


## 手順
* と言っても今までのx86と変わりはありませんでした。
* vCenterをデプロイしてESXiを登録するだけです。

![vcenter.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/894039/61bc68de-30fc-9774-efc1-cac3e78e7fc8.png)


## 注意
* ラズパイの仕様上NTPの時刻がずれています。
    * vCenterとESXiは時刻同期していることが要件になりますので、事前に修正をしましょう。

* vcsa7.0以降はvCLSというvappが自動的にデプロイされますが、arm版ESXiをクラスタに組み込んでいるとデプロイされないようです。
    * これによって、vcsa7.0u1までは警告が出ていたようですが、vcsa7.0u2では警告は表示されませんでした。
【Excel】#DIV/0!エラーを0に修正する方法

　Excelで会社の売上表などを作成していると、計算結果が「#DIV/0!」と表示されることがあります。
これは割り算の分母が[0]または空のセル(未入力)で除算された時に表示されるエラーメッセージになります。
※Divide(割る) /0 → 「分母が0なのに割ろうとしています」というエラー
今回はこのエラー表示を「0」や空白などに修正する方法について解説します。

#IFERROR関数を使用して「#DIV/0!」エラーを抑制する
※IFERROR関数はExcel2007から使用できる関数です。

　IFERROR関数内に除算演算を入れ子にすることで、「#DIV/0!」エラーを抑制することができます。 
 =IFERROR(B2/C2, 0)
やり方は下記の通りです。
１．#DIV/0!エラーが出ているセルを選択
２．先に入力されている数式があるようであれば削除
３．fxボタンから「関数の挿入」ウィンドウを表示。
４．「IFERROR」を選択。
　※関数名一覧に「IFERROR」が見当たらなければ、関数の分類を「すべて表示」にして検索する
５．「関数の引数」ウィンドウが表示されたら、「値」の欄に計算式を、「エラーの場合の値」として0を設定する
※「エラーの場合の値」に「""」（空欄）や「-」と設定することで表示結果を変えることができる
６．「OK」をクリック

これで計算結果にエラーが表示されることがなくなりました。

#まとめ
　今回は「#DIV/0!」エラーの表示を修正する方法について解説しました。エラー表示のままだと会社の売上表などを作成するときに正しい値が算出できないため、今回の記事を参考にして「#DIV/0!」エラーを修正する方法を覚えていただければ幸いです。
EC2へドメインでアクセスする方法

AWSのRoute53を利用しても同様のことができますが、こちらだと利用料金がかからないのと、複数のサービスを利用するの仕組みを理解しつつできるのでこちらの方法でアドレス解決しています。

#必要なプロセス
* ドメインを取得
* 動的に割り当てられるEC2のIPアドレスを、DDNSサービスに通知するようにsystemdを利用して設定
* DDNSサービスを利用して、動的に割り当てられるIPとドメイン名を紐づける。

インターネットからドメイン名でアクセスしようとする際に、アドレス解決（ドメイン名とIPアドレスの紐づけ）ができていないと、どこにアクセスしたらいいのか分かりません。
特に動的にIPを割り当てられるEC2では、自動でアドレス解決をしてくれる手段がないと面倒です。
ドメインにアクセスしようとする際の流れは、
1. ドメイン名でアクセス。
2. Freenomでアドレス解決のできるサーバー（ネームサーバー）を探します。（あらかじめ設定する必要あり）
3. ネームサーバーからアクセス元へIPアドレスを返す。（Aレコード）
4. アクセスできるようになる。


# ドメインを取得
[Freenom](https://my.freenom.com/clientarea.php?action=domaindetails)でドメインを取得。


# 動的に割り当てられるEC2のIPアドレスを、DDNSサービスに通知するようにsystemdを利用して設定
以下のスクリプトを実行することでMyDNSへ自分のIPアドレスを通知することができる。
(`/etc/rc.d/`配下に置いておいてね。)

```sh:/etc/rc.d/MyDNSNotification.sh
#!/bin/bash
#ID="mydnsのMasterID"
#PASS="mydnsのPassword"

#wget -o - 'https://$ID:$PASS@www.mydns.jp/login.html'
wget -o - 'https://{mydnsのMaterID}:{mydnsのPASS}@www.mydns.jp/login.html'
```
（3行コメントアウトにしているのは、なぜかうまくいかない為です。IDとPASSをベタ打ちにすればうまくいきます。）
しかし、起動の度にこれを実行させるのはさすがに手間がかかる。

その為、こちらのスクリプトを起動後に自動で実行してくれるように設定する。
ただ起動後に実行すればいいというわけではなく、インターネットに接続の確認後に上記スクリプトを実行しなければならないので`/etc/rc.local`や`~/.bashrc`に書いたり、`crontab -e`に追記すればいいわけではない。
これの実現方法として、daemon化したプロセスとして実行させる。具体的には、.serviceファイルを作り、適切に配置する。

.serviceファイルの書き方は以下。

```:MyDNSNotification.service
[Unit]
Description=Initialize environment variables.
After=network.target

[Service]
Type=oneshot
User=root
Group=root
ExecStart=/etc/rc.d/MyDNSNotification.sh

[Install]
WantedBy=default.target
```

こちらの.servieファイルを`/etc/systemd/system/`配下に置く。
そして、`chmod ugo+x`で実行権限を付与しておきます。

ここで、`sudo systemctl enable MyDNSNotification`で有効化し、`sudo systemctl start MyDNSNotification`でサービススタートすると、MyDNSに通知ができるようになっているはずです。


# DDNSサービスを利用して、動的に割り当てられるIPとドメイン名を紐づける。
DDNSサービスは、[MyDNS](https://www.mydns.jp/members/)を利用する。
取得したら、MyDNSのネームサーバーをドメイン取得したFreenomにて設定する。

Freenomにて、ServiceからMyDomainsを開く
![無題 (1).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418672/aa6994ef-449c-686b-93ea-8b5821335706.jpeg)


紐づけたいドメイン名の欄の右にあるManage Domainを開く。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418672/0990112c-085e-32e6-474b-8865489edf17.png)


Management Toolsの中のNameserversを開く。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418672/9c7ce9ab-83d2-d223-5725-34c9a9b3f711.png)



Use Custom Nameserversを選択し、Nameserver名を記入。（画像では、MyDNSのNameserver記入済み）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418672/502e17f2-9198-1a03-2b3c-c21f58a93db4.png)


MyDNSのNameserverの情報は、MyDNSのDOMAIN INFO内のある。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418672/141f60a6-907c-2343-c8cf-d2d8ba89e023.png)

以上の設定全て終了したら、EC2を再起動してMyDNSにログインし、IPアドレスが更新されていることを確認する。
それ以後、ドメイン名でEC2にアクセスできるようになる。