OmniAICreator/Qiita-1.07M huggingface dataset:
Macでrmtrashの代替とLinuxでのrmの置き換え

# rmtrashがHomebrewでインストールできなくなった

ライセンスが不透明で作者のレスポンスがないのでHomebrewから最近外されたらしい．
https://github.com/Homebrew/homebrew-core/pull/65438

別のrmtrashの登録が検討されているらしいが，今（2020年12月14日）は使えないので代替を考える．


## 代替候補

Macではコマンドラインからシステムのゴミ箱に捨てられるものが欲しい．

1. Homebrewにある[trash](https://hasseg.org/trash/)
2. [[macOS] コマンドラインからゴミ箱へ削除するスクリプトを書きました](https://qiita.com/h-matsuo/items/55e1f768498421dde469)
3. [Go 言語で rm 用ごみ箱ツール gomi を作った](https://qiita.com/b4b4r07/items/3a790fe7e925b4ba14f3)

1のtrashはrmtrashとほぼ一緒．Homebrewでインストールできるのは楽．でもFinderで開いたゴミ箱から削除したファイルを戻すことはできなかった．（rmtrashがゴミ箱から戻すことができたかどうかは忘れた．）

<font color="red">
---------- 2021年10月29日　コメントを参考に追記
trash -F
を使えばゴミ箱から戻すこともできる。
Homebrewでインストールできるのでこれが一番楽。
下の方に設定も追記した。
---------- 追記終了
</font>




2はスクリプトをダウンロードする必要があるが，Finderで開いたゴミ箱から削除したファイルを戻すことができる．

3は高機能だが，最近のバージョンではシステムのゴミ箱に捨てる機能がなくなったらしい．



~~とりあえず2のtrashというスクリプトが良さそうなのでしばらく使ってみる．~~

## Homebrewのtrash （2021/10/29 追記）
### インストール
``` zsh
$ brew install trash
```

### 設定
`rm`にaliasしておく。`trash -F`で削除後、ゴミ箱から戻せる。ファイルもディレクトリも削除可能。
`.zshrc`等に下記のように書いておく

``` zsh
if type trash > /dev/null 2>&1; then
    alias rm='trash -F'
fi
```

## 上記2のtrashの設定

<font color="red">
---------- 2021年10月29日
これはもう使ってない。Homebrewのtrashを使用している
---------- 追記終了
</font>

https://github.com/h-matsuo/macOS-trash
ここからスクリプトをダウンロードかコピペして，パスが通ったところに実行権限をつけて置いておけばいい．

rmにエイリアスしておいた．ディレクトリも削除できるように`-r`オプションもつけた．

``` zsh
if type trash > /dev/null 2>&1; then
    alias rm='trash -r'
fi
```

# Linuxでrmを置き換え

スパコンなど，サーバー上のLinuxでは自分でゴミ箱となるディレクトリ（~/.Trash）を作って，rmを使わずに，そこにファイルをmvで一旦移動させるようにしている．

ディレクトリは自分で好きなところに作れるので，`/work` をよく使うサーバーでは `/work` 以下に作るようにしている．

エイリアスの設定．

``` zsh
if [ -d ${HOME}/.Trash ]
then
    alias rm='mv --backup=numbered --target-directory=${HOME}/.Trash'
fi
```

`--backup=numbered`オプションを指定すると、移動先に同じファイル名があった場合に上書きではなく，ファイル名に番号をつけて移動してくれる．

`--target-directory`オプションであらかじめ指定したディレクトリにファイルを移動できる．


自分で作ったゴミ箱ディレクトリの中身を空にするスクリプトも作っておいて，pathが通った場所に実行権限をつけておいておく．

``` zsh
#!/bin/sh

rm -rf ~/.Trash/*

exit
```
webpackでアセットをバンドルする



# webpackにコンパイルやバンドルしたいものを記述する

```webpack.mix.js
/*
 mix.js(出力元、出力先（出力名は元のが引き継がれる）
 app.jsにまとめたい場合、resources/js/app.jsにて import "hoge.js"を記載
*/

　　//この場合、指定したjsはそれぞれコンパイルされ、public下にそれぞれ出力される。
mix.js('resources/js/app.js', 'public/js')
    .js('resources/js/dropify.js', 'public/js')
    .js('resources/js/dropify.min.js', 'public/js')

　　//この場合、指定したcssはそれぞれコンパイルされ、public下にall.cssとしてまとめて出力される。
    .styles([
        'resources/css/AAAA.css',
        'resources/css/AAAA_phone.css'
    ], 'public/css/all.css')


    .autoload({
        "jquery": ['$', 'window.jQuery']
      })

    .postCss('resources/css/app.css', 'public/css', [
        //
    ]);

```

#アセットコンパイルする
npm run dev を実行します。

```
npm run dev

```

#適宜読み込み、使用する

```.html
    <head>
        <meta charset="utf-8">
        <title>TEST</title>
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css">
        assetは、public以下のファイルを参照する
        <link rel="stylesheet" href="{{ asset('/css/all.css') }}">

    </head>
    
    -
    -
    -

    <script src="{{ asset('/js/dropify.js') }}"></script>
    <script src="{{ asset('/js/dropify.min.js') }}"></script>
    <script src="{{ asset('/js/app.js') }}"></script>

```
AWS AmplifyのAuthenticatorでのSignUp時にPhone Numberを非表示にしたい

## やりたいこと

- AmplifyAuthenticatorコンポーネントからのSignUp時、
  - EメールアドレスをUser名として利用したい
  - 電話番号フィールドを非表示にしたい

デフォルトではこのようになっている。


![amplify-auth.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8607/84c98240-6a85-8ea3-9674-0c2ab1432eac.jpeg "amplify-auth.jpg")



## やること

- `formFields`でSign Upフォームに表示するカラムを指定する
- `username-alias` にてEメールアドレスを usernameとして登録できるようにする
  -  (注意事項) `amplify add auth`時にEメールでの登録を有効にしておく必要がある


最終的なコードは以下のとおり。

```vue
<template>
  <amplify-authenticator>
    <amplify-sign-out></amplify-sign-out>
    <amplify-sign-up
      slot="sign-up"
      username-alias="email"
      :form-fields.prop="formFields"
    ></amplify-sign-up>
  </amplify-authenticator>
</template>

<script>
export default {
  name: 'Auth',
  data() {
    return {
      formFields: [
        { type: "email" },
        { type: "password" },
      ]
    }
  }
}
</script>
```


![amplify-auth.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8607/0158ded9-1c95-8331-c97c-ffee0783fa42.jpeg "amplify-auth.jpg")

## 参考

ここにまとめたものは公式ドキュメントの以下のページにて解説されています。

#### Authenticate with email or phone number
https://docs.amplify.aws/ui/auth/authenticator/q/framework/vue#manage-auth-state-and-conditional-app-rendering

#### Hiding form fields
https://docs.amplify.aws/ui/auth/authenticator/q/framework/vue#hiding-form-fields
PHPからODFドキュメントを書き換えてみた

PHPの学習し直しの一貫としてPHPからODFドキュメントの書き換えに挑戦してみました。
#作成したもの
##ドキュメントアップロード用フォーム

```html:form.html
<!DOCTYPE html>
<html lang="ja" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title>てすと</title>
  </head>
  <body>
てすとです
<form enctype="multipart/form-data"  method="post" action="rsv.php">
  <input type="file" name="filetest" size="20"/>
  <input type="submit" value="送信する">
</form>
  </body>
</html>

```
##ファイル受け取って置換え機能へ渡す

```PHP:rsv.php
<?php
ini_set('display_errors', "On");

//置換え機能をインクルード
include "libOdfReplace.php";

$uploaddir  = "./upload/";
$uploadfile = $uploaddir.basename($_FILES['filetest']['name']);
move_uploaded_file($_FILES['filetest']['tmp_name'],$uploadfile);
//置換え指定を配列に格納
$replaceArray [1]["target"]   = "[name]";
$replaceArray [1]["replace"]  =  "会津太郎";
$replaceArray [2]["target"]   = "[address]";
$replaceArray [2]["replace"]  =  "会津若松市東栄町99-99";
$replaceArray [3]["target"]   = "[birthymd]";
$replaceArray [3]["replace"]  =  "令和2年12月13日";

//置換え機能へドキュメントのパスと置換え指定配列を渡す
$odftext = odf_replace($uploadfile,$replaceArray);
 ?>
```
##rsv.phpから渡されたファイル中の所定の文字列を置換え

```PHP:libOdfReplace.php
<?php
function odf_replace($filename,$replaceArray) {
echo $filename;
    $dataFile = "content.xml";

    //ZIP archive オブジェクトを作成
    $zip = new ZipArchive;
    // ドキュメントをアーカイブとして開く
    if (true === $zip->open($filename)) {
        // アーカイブ内からcontent.xmlのインデックスを取得
        if (($index = $zip->locateName($dataFile)) !== false) {
            // インデックスからファイルの内容を取得
            $text = $zip->getFromIndex($index);
           //　指定の文字列の置換え
            foreach ($replaceArray as $repkey) {
              $text = str_replace($repkey["target"],$repkey["replace"],$text);
            }
            $zip->deleteIndex($index);
            $zip->addFromString($dataFile,$text);
        }
        //アーカイブを閉じる
        $zip->close();
    }
}
 ?>

```
##元のドキュメント「template.odt」
置換え対象の文字列として以下の３つが挿入されています。
[name]
[address]
[birthymd]


![template.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104361/140e3b92-7b74-db21-8937-88a79506db99.png)

#実行！
##form.htmlにアクセスしてファイルをアップロード

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104361/20c4614d-29ff-243e-d49d-0f1ab07c185c.png)

##ドキュメントが出力されました
果たして上手く変換できているんでしょうか。

![Screenshot from 2020-12-14 00-38-23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104361/ad0597b9-3d53-ecc7-9d1a-e58fe20cfce5.png)

##開いてみる
うまくいきました！

![template_out.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104361/eb9343da-fe0d-4a78-4573-3c5b1495b8bc.png)


#解説
処理内容は簡単。
ODFは各種関連ファイルをZIPとして固めたものです。
そこで、アップロードしたドキュメントをZIPとして開き、アーカイブ内の"content.xml"を指定した文字列で置換えるというものです。
応用すると色々便利に使えそうですね！
Docker build時にargの指定忘れに気付きたい

今日も今日とてDocker buildでargを指定し忘れる。
しかも基底のDockerイメージだから複数のコンテナイメージをbuildをやりなおさなきゃ。。

そんな、私と同じ経験をしている方へ。
Docker buildするときにエラーになるようにしましょう。

■方法 Dockerfile
ARG MY_VARIABLE
RUN test -n "$MY_VARIABLE"　←　このようにMY_VARIABLEの長さが0ならコマンド失敗するようにする。

■備考
無駄なレイヤが増えちゃいます
できればDockerのビルドで公式にエラーにできるオプションが欲しい。

■参考
https://stackoverflow.com/questions/38438933/how-to-make-a-build-arg-mandatory-during-docker-build
https://www.atmarkit.co.jp/ait/articles/1807/05/news041.html
【Ruby on Rails】bundlerについて（初学者用）

#はじめに
bundlerとbundlerコマンドについて自分用にまとめておく。
・bundle install
・bundle update

#bundlerとは
・bunlerとは、**gem**を管理するツール。
・bunler自体も**gem**の一種。
・**Gemfile**と**Gemfile.lock**を利用して、gemを管理する。

###gemとは
・gemとはライブラリのこと。
・便利な機能をひとまとめにしたもの。
・gemをインストールすることで、自分で一からコードを書かなくても様々な機能
・gemの種類は多数ある。（ユーザー登録機能だったり、認証機能だったり）

###Gemfileとは
Gemfileは、アプリで使用するgemが記載されている。
コマンド打つことで、記載されているgemをインストールすることができる。
インストールする際は、gemのバージョンを指定することが可能で指定しなかった場合は最新のバージョンでインストールされる。

```ruby:Gemfile
gem 'bootstrap-sass', '3.4.1'

```

###Gemfile.lockとは
実際にインストールされたgemが記載されている。
また、Gemfileでインストールしたgemと依存関係のあるgemも表示されている。

```ruby:Gemfile.lock
    bootsnap (1.5.1)
      msgpack (~> 1.0)
    bootstrap-sass (3.4.1)
      autoprefixer-rails (>= 5.2.1)
      sassc (>= 2.0.0)
    builder (3.2.4)
```


###bundlerインストール方法
ターミナルで以下コマンドを入力する。

```terminal
------ % gem install bundler
```
以下コマンドでbundlerのバージョンを確認するとともに、
bundlerがインストールされているかも確認する。

```terminal
------ % bundle -v
Bundler version 1.17.2
```

#bundle install
Gemfileに書かれているgemをインストールする。
<font color="Red">Gemfile.lockにないgemをGemfileから探し、見つけたgemをinstallする。</font>
コマンド実行後、インストールされているgemが下に表示される。
※「bundle」と省略も可能。

```terminal
------ % bundle install
The dependency tzinfo-data (>= 0) will be unused by any of the platforms 
Bundler is installing for. Bundler is installing for ruby but the dependency is 
only for x86-mingw32, x86-mswin32,x64-mingw32, java. To add those platforms to 
the bundle, run `bundle lock --add-platform x86-mingw32 x86-mswin32 x64-mingw32 
java`.
Using rake 13.0.1
Using concurrent-ruby 1.1.7
Using i18n 1.8.5
Using minitest 5.14.2
Using thread_safe 0.3.6
...
...
...
Bundle complete! 20 Gemfile dependencies, 78 gems now installed.
Gems in the group production were not installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.

```

#bundle update
<font color="Red">Gemfile.lockに書かれている内容は無視し、Gemfileに書かれているgemを全てインストールするコマンド。</font>
実行後の挙動は、bundle installと同様。

```terminal
------ % bundle update
The dependency tzinfo-data (>= 0) will be unused by any of the platforms 
Bundler is installing for. Bundler is installing for ruby but the dependency is 
only for x86-mingw32, x86-mswin32,x64-mingw32, java. To add those platforms to 
the bundle, run `bundle lock --add-platform x86-mingw32 x86-mswin32 x64-mingw32 
java`.
Using rake 13.0.1
Using concurrent-ruby 1.1.7
Using i18n 1.8.5
Using minitest 5.14.2
Using thread_safe 0.3.6
...
...
...
Bundle updated!
Gems in the group production were not installed.
```


#bundle installとbundle updateの使い分けについて
基本的には 「bundle install」 を使った方がいいっぽい。
依存関係などでエラーが出た際に 「bundle update」 を使用してあげると良い。
本番環境で 「bundle update」 使用すると開発環境やテスト環境とgemの構成が変わり、思わぬ不具合が発生することがあるので注意が必要らいしいです。
Adversarial Validation De 特徴量選択

# はじめに

機械学習は大前提として、学習データとテストデータの分布が同じである必要があります。

練習時の的が、テスト時には違うところにおいてあっては的に当てることはできません。

そこで Adversarial Validation を利用しデータ分布が異なる特徴量を炙り出すことで上記の的の位置を揃えることができます。

今回はそんな特徴量選択しての Adversarial Validation を紹介します。

# Adversarial Validation

Adversarial Validation について説明します。

### 手順

1. 学習データに0、テストデータに1とそれぞれ適当なラベルをつけ、一つのデータに連結
2. 上記データセットを学習
3. 学習済みモデルから重要度を算出
4. 重要度の高い特徴量を削除

このとき、重要度が高い変数とは

学習とテストを分けることができるデータ
→ 学習とテストで分布が明らかに違うデータとしてみなすことができます。
このような変数を取り除くことで学習データとテストデータの分布を寄せようという特徴量選択方法になります。

# 実験

今回はタイタニックデータに人口的な分布の異なる特徴量を加えて効果を実験していきたいと思います。
https://www.kaggle.com/c/titanic/overview

前処理は以下を参照しました。
https://www.kaggle.com/arthurtok/introduction-to-ensembling-stacking-in-python

### 人口データの作成

今回は特に学習データとテストデータの分布が異なる特徴量 `feature_1` を作成しました。

![feature_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298787/c9498432-b7b7-5d22-0b6e-8a0cebd893bd.png)

### Adversarial Validation

以下は人口的な特徴量の作成とテストスプリットになります。
今回は簡易的に hold-out でスプリットしますが、データ分布に強く依存するため，K-Fold  cross validation をした方がより正確な評価が出ると思います．

```python

# 人口データ作成
train['feature_1'] = np.random.normal(loc=0, scale=1, size=len(train))
test['feature_1'] = np.random.normal(loc=3, scale=1, size=len(test))

# ラベル作成
train['test'] = 0
test['test'] = 1

# シャッフル
df = pd.concat([train, test]).drop(['Survived'], axis=1)
df = df.sample(frac=1, random_state=9).reset_index(drop=True)

# テストスプリット
split = int(len(df)* 9/10)
train = df.iloc[:split]
test = df.iloc[split:]
```

このデータを LightGBM で学習させます．

```
roc_auc : 0.9643574297188755
```

と，かなりの精度で学習データとテストデータが判別できてしまっています．

ここで `gain` による重要度をみてみましょう

![download.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298787/b42776d3-798f-de86-2768-59d78c14488a.png)

学習データとテストデータでは上記のように `feature_1` を見れば大まかに予測できてしまっているようです．

このように， Adversarial Validation では，学習データとテストデータの分布が大きく異なる特徴量をあぶり出すことができます．

この `feature_1` を除いてもう一度，学習データとテストデータを分類してみます．

```
roc_auc : 0.5670180722891566
```

このようにテストデータと学習データが十分に割り振れていないため，学習データとテストデータの分布が同じ事がわかります．

`gain` 重要度

![download-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298787/a544246f-0b87-fd33-3b69-14ba2eee9972.png)

# おわりに

今回は Adversarial Validation を用いた特徴量削減を行いました．

注意点としては以下です．
- 重要度にバイアスがかかる場合がある https://aotamasaki.hatenablog.com/entry/bias_in_feature_importances
- 時系列データでは値が削除されすぎてしまう

頭がいい特徴量削減だなと思いました．

# 参照

https://upura.hatenablog.com/entry/2019/10/27/211137

https://www.kaggle.com/c/titanic/overview

https://www.kaggle.com/arthurtok/introduction-to-ensembling-stacking-in-python

https://aotamasaki.hatenablog.com/entry/bias_in_feature_importances
PowerShell起動時に毎回同じ設定を読み込む設定（プロファイルの設定）

#この記事は？
- powershellでログを自動で取りたい
- 毎回同じエイリアス、関数、および変数を使いたい
- プロンプトを改造したい

上記を叶えるためには、PowerShellプロファイルを作成することで解決できます。

# 前提
## 環境
- Windows PowerShell 5.1
- PowerShell 7.0.3

## プロファイルとは
Powershellが起動した際に読み込む定義ファイルです。
プロファイルは4つ定義できます。下記表の上から順に実行されます。

|No|プロファイルのパス||
|:-:|:--|:--|
|1|%windir%\system32\WindowsPowerShell\v1.0\profile.ps1|すべてのユーザーおよびすべてのシェルに適用|
|2|%windir%\system32\WindowsPowerShell\v1.0\ Microsoft.PowerShell_profile.ps1|すべてのユーザーに適用されますが、Microsoft.PowerShell シェルのみに適用|
|3|%UserProfile%\My Documents\WindowsPowerShell\profile.ps1|現在のユーザーのみに適用され、すべてのシェルに適用|
|4|%UserProfile%\My Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1|現在のユーザーと Microsoft.PowerShell シェルのみに適用|

## プロファイルの作成と編集
プロファイルのパスは下記で確認できます。
なおデフォルトでは「プロファイルとは」の表のNo4の場所が設定されています。

```powershell
$profile
```

プロファイルはデフォルトでありません。作成されているかどうかは下記コマンドで確認できます。
「True」なら作成済み、「False」なら未作成です。

```powershell
test-path $profile
```

プロファイルを作成する場合下記コマンドで作成できます。
なお「プロファイルとは」の表のNo4以外のプロファイルを作成する場合、「\$profile」の部分を「\$env:[プロファイルのパス]」に置き換えましょう。

```powershell
# 「プロファイルとは」の表のNo4
new-item -path $profile -itemtype file -force
# 「プロファイルとは」の表のNo3
new-item -path $env:UserProfile\My Documents\WindowsPowerShell\profile.ps1 -itemtype file -force
```

プロファイルができたら、編集しましょう。


```powershell
#メモ帳で開く
notepad $profile
#VisualStadio Codeで開く
code $profile
```

__Tips__ : profileファイルはBOM付きUTF-8で編集するとエラーに悩まされなくて良きです。

# プロファイル
## 結論
私は下記のプロファイルを利用している

```powershell:profile.ps1
# ウィンドウタイトル
(Get-Host).UI.RawUI.WindowTitle = "WindowsPowerShell ( ᐢ˙꒳​˙ᐢ )" + $pwd

# 日付
$Date = Get-Date -UFormat "%Y/%m/%d %H:%M:%S"
# 実行権限
$ExecutionPolicy = Get-ExecutionPolicy
# ログディレクトリ
$Logdir = join-path ([Environment]::GetFolderPath("MyDocuments")) "\WindowsPowerShell\logs"
# ログファイル
$FileName = (Get-Date).ToString("yyyyMMdd_HHmmss") + ".log"
$Logfiledir = join-path $logdir $filename


# ログ取得
if ( Test-Path $logdir ) {
    Start-Transcript $logfiledir -append | Out-Null
} else {
    Write-Host ("No Such Directory : " + $logdir)
}

# 現在のプロパティ
Write-Host "Date           : " $Date
Write-Host "Your Policy    : " $ExecutionPolicy
Write-Host "Logs Directory : " $Logdir
Write-Host "Profile        :  Current Users, All Shell"
Get-ChildItem

# プロンプト
function Prompt {
    if ($?) {
        (Get-Host).UI.RawUI.WindowTitle = "WindowsPowerShell ( ᐢ˙꒳​˙ᐢ )：" + $pwd
        Write-Host "(*'-')" -NoNewLine -ForegroundColor "Green"
        return ">"
    } else {
        (Get-Host).UI.RawUI.WindowTitle = "WindowsPowerShell ( ᐢ˙꒳​˙ᐢ )：" + $pwd
        Write-Host "(*;-;)" -NoNewLine -ForegroundColor "Red"
        return ">"
    }
}


```

## 解説
- ログ取得
- 起動時に現在のプロパティを表示
- ウィンドウタイトルとプロンプトを可愛く



# 参考
- [Windows PowerShell プロファイル](https://forsenergy.com/ja-jp/windowspowershellhelp/html/9c82251c-6f0d-416a-9c3c-77838218531b.htm)
- [かわいい PowerShell プロンプト](https://qiita.com/cd01/items/40ae04b8643a84c9dc08)
- [PowerShellのprofile.ps1自分用設定](https://qiita.com/tomoko523/items/87ccaec05a433b02f67e)
- [Windows PowerShellでコンソールログ出力](https://qiita.com/rjegg/items/3f10228c780769dd553c)
マンガでわかる地雷原ミニアンチパターン

![F4F585DE-ACFF-46EA-92C2-61DEFFD08E8B.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/11525/5d7f07c2-38cf-4e9a-0c5a-d703f221ac63.png)
http://wiki.c2.com/?WalkingThroughaMineField

まだ知見の少ない新しい技術を使うことは、バグの地雷原を徒歩で突破するようなものです。地雷に例えるのは、どこに仕掛けられているかわからないため、発生を予見することができないことを表しています。(しかも仕掛けた本人でさえ意識せず)

リリース後に何度も問題を起こしては修正され、あるいは問題回避方法が広く知られ、ある意味「枯れた」技術を使うことで、地雷を踏むリスクは下がります。エンドユーザーなら、ある程度こなれた製品を選べばよいのですが、開発者がそればかりでは、先進的な技術にチャレンジして競争力を高めることができません。

比較的安全な最新地雷原の抜け方は、使おうとしているソフトウェアが、リリース前によくテストされているか、開発者の思想が信頼できるかを評価できる目を養うことだと思います。当時はテストを重視と言われていましたが、現在では当時よりはるかに単体テスト品質が上がり、単体テストの積み上げによる信頼確保は当然となりました。しかし、ベンダーの開発者が、うわべの「ことになっている」でそれっぽく振る舞っているだけか、本当に本質を見極めようと考えたうえで行動しているかの違いは、歴然としてあるように感じます。

余談のようで関係あるジョークとして、個人的にパターン解説中のこの一文を気に入ってます:

> Sometimes this problem is caused by a MicrosoftCertifiedSolitaireExpert using MineSweeper too much.

この問題はマインスイーパを過剰に利用するマイクロソフト認定ソリティアエキスパートによって引き起こされることがあります。
Qiita学習記録　HTML/CSS #4

<h1>Bootstrapの使い方
<p>世の中には読み込むだけですぐに使える『CSSフレームワーク』</p>
</h1>

Bootstrapは既に用意されたスタイルシートを読み込む

```html:index.html
<h1 class="text-primary text-center font-weight-bold">Hello, world!</h1>
    <h1 class="text-secondary text-center font-weight-bold">Hello, world!</h1>
    <h1 class="text-success text-center font-weight-bold">Hello, world!</h1>

    <h1 class="text-white bg-primary text-center font-weight-bold">Hello, world!</h1>
    <h1 class="text-white bg-secondary text-center font-weight-bold">Hello, world!</h1>
    <h1 class="text-white bg-success text-center font-weight-bold">Hello, world!</h1>
```
HTMLのみでフォントカラー、背景色、等の簡単な編集ができる。

<h2>Gridレイアウト</h2>
Bootstrapでは12本のグリッドが存在する。
グリッドシステムを支える3つのCSSクラスが以下の画像。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/898926/71c7b133-90bc-d4a8-4209-cd3efa87e0cb.png"width=70%>
Bootstrapのグリッドシステムはホントによくできています。この3つのクラスを理解しておけば、複雑なレイアウトもレスポンシブも余裕です。
.container
.row
.col
それぞれの使い方を見ていきます。
<h3>.container</h3>
>コンテナに与えるクラスです。コンテナは格納庫という意味です。上の画像を見ると、.containerは.rowと.colを格納していることがわかります。
.containerは決められた幅を持ちます。レスポンシブデザインは、スマホ、タブレット、パソコンなど異なる画面幅に合わせてレイアウトを切り替えますよね。Bootstrapでは、閲覧側の画面幅を「極小から特大」までの5種類を想定し、.containerの幅も5段階に分け用意されてます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/898926/aebf9958-c967-bb0c-a468-3fdd804a2acf.png"width-70%>

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/898926/6c750d91-521b-94bc-7963-69e713155aa8.png"width=70%>
Extra small ／ 画面幅 極小（544px未満）
Small ／ 画面幅 小（544px以上 768px未満）
Medium ／ 画面幅 中 （768px以上 992px未満）
large ／ 画面幅 大 （992px以上 1200px未満）
Extra large ／ 画面幅 特大 （1200px以上）
この5種類の画面幅に対して、.containerの幅も5段階あります。

<h3>.row</h3>
>行に与えるクラスです。.rowはコンテナを水平に分割し上から下へと並びます。.rowの中に.colを定義しレイアウトを組みます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/898926/73de3709-8a45-a2a8-b8d1-24e60bfdbd73.png"width=70%>

<h3>.col</h3>
>列を表すクラスです。ウェブデザイナーにとっては、カラムという呼び方のほうが親しみがあるかも。.colは.rowを縦に割り左から右へ並びます。
.colのあとに-（ハイフン）で文字列をつなぐことで、「この画面では、この個数のグリッド」ということを指定します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/898926/92e08b20-42d9-e0c2-43ee-235b013e1913.png"width=70%>

<h2>マルチカーソル使い方</h2>
option+カーソルで洗濯した範囲を一気に変更することが可能。
＜範囲選択＞Shift+option+Fでデントの整形。
Rubyのネイティブ拡張をRustで作成する最小構成（今の所Macのみ）

現在、RustでRubyのネイティブ拡張を書く場合、[rutie](https://github.com/danielpclark/rutie)を使うことが一般的だと思われる。（[helix](https://github.com/tildeio/helix)や[ruru](https://github.com/d-unseductable/ruru)は保守されていない。）
しかし、下記の理由で個人的に好ましくなかったため、ライブラリに頼らずRubyのネイティブ拡張を作る方法を調べた。

* 古いRustコンパイラをサポートするが、MaybeUninit等の、より安全なライブラリが利用されていない。
* unsafeに対する価値観が私と異なり、完全に安全とは言えない関数であってもunsafeとマークされていない。

下記のコードは `HelloRust` モジュールをRust側で定義しているサンプルである。

Windows, Linux で動かす場合は[続き](https://qiita.com/irxground/items/f9119282585535629c47)を参考。

## ソースコードベタ貼り

```ruby:run.rb
require __dir__ + "/hello_rust"

if defined?(HelloRust)
  puts "HelloRust is defined"
else
  puts "HelloRust is not defined"
end
```

```rust:src/lib.rs
use std::ffi;

#[repr(transparent)]
pub struct Value(usize);

#[link(name = "ruby")]
extern "C" {
  fn rb_define_module(name: *const i8) -> Value;
}

fn define_module(name: &ffi::CStr) -> Value {
  unsafe { rb_define_module(name.as_ptr()) }
}

#[export_name = "Init_hello_rust"]
pub extern "C" fn init() {
  let s = ffi::CString::new("HelloRust").unwrap();
  define_module(&s);
}
```

```rust:build.rs
use std::process::Command;

fn libdir() -> String {
  let output = Command::new("ruby")
    .args(&["-e", "print RbConfig::CONFIG['libdir']"])
    .output()
    .expect("failed run ruby");

  return String::from_utf8(output.stdout).unwrap();
}

fn main() {
  println!("cargo:rustc-link-search={}", libdir());
}
```

```toml:Cargo.toml
[package]
name = "hello_rust"
version = "0.1.0"
authors = ["irxground"]
edition = "2018"

[lib]
crate-type = ["cdylib"]
```

```make:Makefile
.PHONY: build
build: hello_rust.bundle

hello_rust.bundle: cargo_build
	cp -a target/release/libhello_rust.dylib $@

.PHONY: cargo_build
cargo_build:
	cargo build --release

.PHONY: run
run: clean build
	ruby run.rb

.PHONY: clean
clean:
	rm *.bundle
	cargo clean
```

## 実行結果

```terminal
$ make run
rm *.bundle
cargo clean
cargo build --release
   Compiling hello_rust v0.1.0 (/Users/user/work/private/ruby_rust/minimam_rust_example)
    Finished release [optimized] target(s) in 0.75s
cp target/release/libhello_rust.dylib hello_rust.bundle
ruby run.rb
HelloRust is defined
```
12日目：チュロスから学ぶオブジェクトの生成と削除(前編)

この記事はアドベントカレンダー「[【VCI】テーマパーク を作ろう](https://adventar.org/calendars/5855) 」の12日目の記事です。

# 今回の内容
今回はチュロスを作りながらオブジェクトの生成と削除について学んで行きます。
~~2日 ~~3日に分けての説明となります。今回は以下の内容を学びます。
　・VCIにおける生成と削除の概念
　・オブジェクトの生成方法

# VCIにおける生成と削除
Vキャスでは純粋な意味で**オブジェクトの生成や削除をコードから行うことはできません**。そのため、生成・削除しようとするタイミングで変わりに表示・非表示する処理を行うことで擬似的に再現しています。
非表示にする方法は「透明にする」・「サイズを0にする」・「見えないくらい遠くに置く」などがあります。
今回は「見えないくらい遠くに置く」の方法で作成していきます。

具体的には以下のルールで作成します
　・非表示のオブジェクトはy座標が-500の場所に置いておく。
　・ｙ座標が-100以上の場合は出現状態、-100以下の場合は非表示の状態として扱う。
　　(境界値が-100であることに深い意味はないです。0～-500ならどこでもいいと思います)
　・ボタンを押すと非表示状態のチュロスを出現させる。全て出現状態の場合はコンソールにメッセージを出す。
　・チュロスを食べたら手元から消えて非表示の状態に戻る。(こちらは明日作成分)


# Unityでの設定
まずは出現対象となるチュロスを作り複製します。今回は6個としました。
(チュロスは持ち運べるようにしたいためSubItmeコンポーネント付きで作成します。）
これらのチュロスは最初は非表示の状態としたいため、y座標を-500に設定します。

次にチュロスを出現させるためのボタンと出現ポイントの設定をします。
出現ポイントは以下の画像のように出現させたい場所に空オブジェクトを置くことで実現しています。
(出現位置をコードで計算して決めることも可能ですが、こちらの方が直感的にわかりやすいと思います。)
![20201213-220355.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64877/16ce9153-06f2-4d88-5058-7b76bb2dec5e.png)

Unityの設定は以上です。

# コード作成
ここからはVキャス及びエディタでの作業となります。

**※今回のコードだけでは複数人で扱った場合、正しく動作しません。
次の記事に対策方法を書く予定ですので合わせてお読み下さい。**

チュロスを出現させる際は出現中のチュロスはではなく、非表示状態のものを取ってくる必要があります。
そのため、まずはチュロスの座標をチェックして出現対象となるチュロスを探してくる関数を作成します。
対象となるチュロスがない(全て出現された状態)の場合はnil(空)を返すようにします。

``` lua
--出現対象とするチュロスを探す。
function fetchChurros()
  --出現対象となるチュロス。はじめはnilを入れておく。
  local targetChurros = nil
  
  -- チュロスオブジェクトが取得できなくなるまでずっとループ
  local no = 1
  while(true) do
    --チュロスオブジェクト取得
    local churros =  vci.assets.GetTransform("Churros_"..no)
    if churros then
      --取得したオブジェクトのY座標が-100以下ならそれをターゲットに定めループを抜ける。
      if churros.GetPosition().y < -100 then
        targetChurros =  churros
        break
      end
    else
      --オブジェクトが取得できなくなったらループを抜ける
      break
    end
    no = no + 1
  end
  --取得したチュロスを返す。なければnilの状態のままなのでnilが返る。
  return targetChurros
end
```


次にボタンを押した際に上記関数を呼び出し、対象となるチュロスを出現させる処理を作成します。

``` lua
---[SubItemの所有権&Use状態]アイテムをグラッブしてグリップボタンを押すと呼ばれる。
---@param use string @押されたアイテムのSubItem名
function onUse(use)
  --今回作成したボタン「Button_Appear_Churros」が押されたときのみ実行される
  if use == "Button_Appear_Churros" then
    local churros = fetchChurros()
    if churros then
      --対象のオブジェクトを出現ポイントの位置に移動させる
      local appearPoint = vci.assets.GetTransform("Churros_AppearPoint")
      churros.SetPosition(appearPoint.GetPosition())
      churros.SetRotation(appearPoint.GetRotation())
    else
      --対象となるチュロスがなかった場合
      print("チュロスは完売しました。")
    end
  end
end
```

以上でコード作成は完了です。
以下の画像のように、チュロスがある場合はチュロスが出現し、ない場合はコンソールにメッセージが出るようになりました。
(分かりづらいですがcubeのボタンを何回か押しています)
![churros.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64877/3a9a074b-f952-549d-067d-13c4c5ed7496.gif)



# 終わりに 
いかがでしたでしょうか？
今回作成したコードでは**まだマルチ未対応の不完全状態**ですので、明日は今回のコードの問題点・解決策の説明およびオブジェクトの消失の処理について学んでいきます。
Javaでpublic/privateではなくsetter/getterを使う理由

## 動機
先日なんとなくHatenaの匿名日記を読んでいたのですが、そこに「Javaでpublic/privateで内部のメンバ変数のアクセスをコントロールするのではなくsetter/getterを使うのはなぜか？」という疑問が書いてありました。私もなんとなく習慣的にgetter/setterを書く（あるいはlombokを使う）ことが多かったのですが、そう言えばなぜpublic/privateでメンバ変数へのアクセスをコントロールせず、メンバ変数を一律private変数にしてgetter/settterからアクセスする方式にしているんだろうと思いました。C#, PHPだとJavaほどきっちりgetter/setterを書かないような気がしました。

## stackoverflowで調べてみた
検索してみたところこのページ（[stackoverflow](https://stackoverflow.com/questions/1568091/why-use-getters-and-setters-accessors#:~:text=Allowing%20the%20getter%2Fsetter%20to,the%20set%20could%20be%20protected.)）がヒットしました。このページではgetter/setterを使う理由として以下が挙げられていました。

1. メンバ変数へのアクセス（get/set）処理のカプセル化。メンバ変数のget/set時にget/set以外のことをしたい場合にも対応できるし、その処理をこのクラスを使用する側から隠蔽できる。
2. getter/setter越しにアクセスする内部のメンバ変数を、このクラスを使用する側から隠蔽できるので、get〇〇という名前で実際は△△というメンバ変数を返すという処理ができるようになるし、3.のような変更も可能になる。
3. このクラスを使用する側のコードを変えずにgetter/setter越しにアクセスされるメンバ変数を（後から）変更できる。
4. そのメンバ変数のメモリ管理・ライフタイム管理（特にメモリ破棄の部分）の明確化。
5. ランタイム時に内部のメンバ変数にアクセスするという処理に対してブレイクポイントを置けるようになるのでgetter/setterがあったほうがメンバ変数へのアクセス処理に対するデバッグがやりやすい。
6. Mocking、Serializationなど、メンバ変数へのgetter/setterの存在を前提としている処理を外部ライブラリから呼び出す場合、素直にgetter/setterを使っていたほうが便利。
7. メンバ変数へのgetter/setterが定義されたクラスを継承する子クラスを作る場合、子クラス側でメンバ変数へのアクセス処理（getter/setter関数）を変更することができる。
8. ラムダ式でそのクラスから値を渡すのではなくgetter/setterを渡すということができる。
9. getter/setter間で違うアクセスレベルが持てる。例えばgetterはpublicだけどsetterのみprotectedなど。
10. プロパティのLazy load, Copy on writeができるようになる。

あとは以下のような回答もありました。
実装から2週間後（2か月後・2年後でもいいけど）、publicなメンバ変数で実装を済ませたけど後から実はメンバ変数への値のセットだけじゃ駄目で、値のセット時にそれ以上のことをする必要があることが判明したとする。いざその変更を実装しようと思ったら、そのメンバ変数が既に238個の外部クラスから参照されていたりすると、（どう修正するか）途方にくれることになるからね。

## C#, PHPの場合
C#は自動プロパティ初期化機能があるのでgetter/setterをクラス内に書かなくてもgetter/setterを介したやりとりができるみたいですね。

PHPもIDEによっては自動でgetter/setter関数の作成ができるみたいですが、パフォーマンスの観点からは[ナイーブなsetter/getterは避けるべき](https://web.archive.org/web/20140625191431/https://developers.google.com/speed/articles/optimizing-php)ということになっていたようです（[stackoverflow](https://stackoverflow.com/questions/4478661/getter-and-setter)）。ただこれが書かれたのがphp5当時っぽく、その後に出たphp7, php8は当時と比較してかなりパフォーマンスが向上しているはずなので現在はsetter/getterを使用したほうがいいのではないかと思いました。

stackoverflowでもPHPでsetter/getterを使うべき理由として以下のようなケースを挙げていました。setterを定義すれば（後からでも）バリデーション処理を追加できますね。

```php
class Foo {
   public $bar; // 本当はinteger型であることを期待している
}
$foo = new Foo;
$foo->bar = "string"; // 動的型付なのでstring型でもいれることができてしまう。
```

## setter/getterはアンチパターン？
Readabilityの観点からは（ナイーブなgetter/setterは）望ましくないという意見もありました。lombokを使用したりしてgetter/setter関数で溢れるという事態は避けるのが良さそうです。
[純粋なOOPではgetter/setterはアンチパターンだという主張](https://www.yegor256.com/2014/09/16/getters-and-setters-are-evil.html)をしている人もいました。ちゃんと読んではいないのですが（！！）、かわりにpublicなメンバ変数を使えと言っているのではなくそもそもオブジェクトをデータストラクチャとして使うな、OOPらしい関数を定義しろと言っている気がします。

## 結論
普段なんとなくでやっていることの意味を振り返るきっかけになってよかったです。
ExUnitの`assert`でパターンマッチを用いて複雑なデータ構造をテストする

Elixirの特徴のひとつとして、柔軟なパターンマッチが挙げられます。本記事では、[ExUnit](https://hexdocs.pm/ex_unit/ExUnit.html)を用いたテストにおいて、複雑なデータ構造をパターンマッチを用いて効率的にテストする方法を見ていきます[^1]。

## ExUnitの`assert`について

[ExUnit.Assertionsのassert/1のマニュアル](https://hexdocs.pm/ex_unit/ExUnit.Assertions.html#assert/1)にもある通り、`assert`では`truthy`/`falsy`をテストするだけでなく、パターンマッチもテストできます。

> Similarly, if a match expression is given, it will report any failure in terms of that match. Given
> 
> ```elixir
> assert [1] = [2]
> ```
> 
> you'll see:
> 
> ```elixir
> match (=) failed
> code:  assert [1] = [2]
> left: [1]
> right: [2]
> ```

これを使って、複雑なデータ構造をテストしてみます。

## 複雑なデータ構造のテスト

たとえば、SlackのAPIで取得できるような、ユーザを表すデータ構造をテストしたいとします。以下は、[SlackのAPIドキュメント](https://api.slack.com/types/user)を参考にして例を作りました。

```elixir
ExUnit.start()

defmodule UserTest do
  use ExUnit.Case, async: true

  setup_all do
    %{
      id: 123_456,
      name: "あんちぽ",
      profile: %{
        real_name: "栗林健太郎",
        image: %{
          original: "https://0.gravatar.com/avatar/23f4d5d797a91b6d17d627b90b5a42d9?s=1000",
          thumbnail: "https://0.gravatar.com/avatar/23f4d5d797a91b6d17d627b90b5a42d9?s=24"
        }
      }
    }
  end

  test "`user`のデータ構造をテストする", user do
    assert %{id: _, name: "あんちぽ", profile: profile} = user
    assert %{real_name: "栗林健太郎", image: image} = profile
    assert %{original: _, thumbnail: _} = image
  end
end
```

`setup_all`にあるのは、テストしたいデータ構造です。その下の`test`マクロ内で、実際のテストを行っています。テストしたいデータは、APIから返ってきたJSONをElixirのマップにデコードしたものだとおもってください。

このデータは三階層になっています。このような深いデータ構造をテストしようと思うと、階層ひとつひとつをマップのキーを使って参照したり、別の変数に1行ずつ束縛したりしながらテストしていくみたいな感じにもなりそうです。

上記のコードから、アサーションの部分のみを抜粋します。

```elixir
test "`user`のデータ構造をテストする", user do
  assert %{id: _, name: "あんちぽ", profile: profile} = user
  assert %{real_name: "栗林健太郎", image: image} = profile
  assert %{original: _, thumbnail: _} = image
end
```

こうやって書いていくと、パターンマッチにより構造をテストしつつ、下位の階層を変数に束縛して次のアサーションに用いるということで、少ない記述でとてもわかりやすく複雑なデータ構造のテストが実現できていますね。

## おわりに

本記事で書いた内容は、Elixirに慣れたひとや、関数型言語的なパターンマッチに詳しいひとからすると当たり前かもしれませんが、個人的に感心した内容だったので、書いておきました。

[^1]: この記事で書いている方法は、[pelemay/analyzer_test.exs at master · zeam-vm/pelemay](https://github.com/zeam-vm/pelemay/blob/master/test/analyzer_test.exs)のコードを見ていて、そんな書き方があるのかと知りました。
【JavaScript】JavaScriptの 「this」とは 2 (thisの問題点と解決策)

※当方駆け出しエンジニアのため、間違っていることも多々あると思いますので、ご了承ください。また、間違いに気付いた方はご一報いただけると幸いです。

こちらは、
[【JavaScript】JavaScriptの 「 this」とは](https://qiita.com/sho_U/items/edb7c897a2bab0f86345)
の記事の続きとなります。

##thisの問題点について

メソッドを、関数化して、実行したらベースオブジェクトがなくなってしまいthisがundeifinedとなる。

どういうことかといいますと。

```js
"use strict";

const person = {
  name: "Taro",
  sayName: function () {
    return this.name;
  }
};
console.log(person.sayName());
```
sayNameは呼び出し元のnameプロパティの値を返すメソッドです。

今、このメソッドを変数に格納して、実行してみます。

```js
const say = person.sayName;
console.log(say());

//TypeError: Cannot read property 'name' of undefined
```

nameというプロパティーなど定義されていない。と返却されます。これは、呼び出し元がグローバルオブジェクトとなったため、グローバルオブジェクトにnameというプロパティーが定義されていないためです。

thisは定義したときではなく実行したときに決定されます。 そのため、関数にthisを含んでいる場合、その関数は意図した呼ばれ方がされないと間違った結果が発生してしまします。

##この問題の対処法

###メソッドを関数として呼ばない。
そもそも、メソッドとして定義している関数を、関数として呼び出さなければ、この問題は生じません。

###call,applyでthisを指定して呼び出し。

```js
"use strict";
const person = {
  name: "Taro",
  sayName: function () {
    return this.name;
  }
};
const say = person.sayName;
console.log(say.call(person));

//Taro
```
call,applyメソッドについては、こちらをご覧ください。
[【JavaScript】JavaScriptの 「 this」とは](https://qiita.com/sho_U/items/edb7c897a2bab0f86345)

###bindでthisを固定した関数を作り、呼び出す。
bindメソッドはthisの値を束縛（bind）した新しい関数を作成します。

```js
"use strict";
const person = {
  name: "Taro",
  sayName: function () {
    return this.name;
  }
};
const say = person.sayName.bind(person);
//bindでthisをpersonオブジェクトに固定
console.log(say());

//Taro
```

##thisの問題点について 2

コールバック関数の中でthisを参照すると問題となる場合があります。

下記のように、mapメソッドを用いて、配列の各要素に the-という接頭語をつけて、新たな配列を作ることを意図したプログラムがあるとします。

```js
"use strict";
const prefix = {
  pre: "the",
  addPre(strings) {
    return strings.map(function (str) {
      return this.pre + "-" + str;
    });
  }
};
prefix.addPre(["a", "b", "c"]); 

// =>TypeError: Cannot read property 'pre' of undefined
```

このように、preは定義されていないとなります。

これは、コールバック関数は、prefixオブジェクトのプロパティーとして呼び出されている訳ではなく、単純に、strings.mapの引数に匿名関数として呼び出されているからです。

##この問題の対処法

###thisを一時変数へ代入する。

```js
"use strict";
const prefix = {
  pre: "the",
  addPre(strings) {
    let that = this; //thisをthatに一時格納する。
    return strings.map(function (str) {
      return that.pre + "-" + str; //thatを参照する。
    });
  }
};
let result = prefix.addPre(["a", "b", "c"]);
console.log(result);

//[ 'the-a', 'the-b', 'the-c' ]
```

一時的に、addPre内で 変数thatにthisを格納します。

```js
prefix.addPre();
```
が実行された際、addPreの呼び出し元はprefixオブジェクトとなるため、thisは当然、呼び出し元であるprefixオブジェクトが格納されています。

```js
return that.pre + "-" + str; 
```
が実行された際、thatはスコプーチェーンによりaddPre関数配下のthatを参照します。
↓  スコープチェーンについては、こちらをご覧ください。
[【JavaScript】JavaScriptにおけるクロージャーとは](https://qiita.com/sho_U/items/1d58d5fb7cb11030f24b)

先ほども、述べた様にthatにはthis(prefixオブジェクト)が格納されているので、that.preで"the"が参照できる訳です。

###アロー関数をコールバック関数で使う。

これについては、少々長くなりそうなので別記事で。

[【JavaScript】JavaScriptの 「this」とは ３　(thisの問題点とアロー関数による解決)](https://qiita.com/sho_U/items/c5fd529824f13dcf4441)
【Jenkins：Mac】slack通知

# 概要

Jenkinsのビルドが終了した時にslackで通知したい
意外と簡単にできます

Jenkins側の設定をメインに記載するので、slack側のアプリ管理は省略します
ググったら結構記事でてきます
ので、「Jenkins CI」を設定済み前提で進めます

Jenkinsバージョン：2.270
Slack Notification Plugin：2.45
※Jenkinsとプラグインのバージョンが異なると動作しない可能性があります

# 1. プラグイン追加

まず最初に
Jenkinsの管理 > プラグインの管理 > 「利用可能」タブ
から「Slack Notification Plugin」を探してインストールしてください
再起動は不要だと思うので「install without restart」でインストール

# 2. スクリプト作成

Pipelineで作成します
適当にジョブ作ってPipelineScriptに下記を記述

```:コード
node
{
    SLACK_URL = "https://sample.slack.com/services/hooks/jenkins-ci/"
    SLACK_TOKEN = "XXXXXXXXXXXXXXXXXXXXXXXX"
    SLACK_CHANNEL = "sample"
    MESSAGE = "sample"
    
    stage ("slack")
    {
        slackSend(baseUrl: SLACK_URL, token: SLACK_TOKEN, channel: SLACK_CHANNEL, message: """Build Success: #${env.BUILD_NUMBER} ${env.JOB_NAME}\n${MESSAGE}""", color: "good")
    }
}
```

定数は例として記載してるのでパラメータに出すなりして汎用的に使えるようにしてもいいかと思います

引数を１つずつ解説していくと

**baseUrl**
コード例の「sample.slack.com」の部分を通知を飛ばしたいslackのワークスペース名を指定してください

**token**
Jenkins CIに記載されてるトークンを指定してください

**channel**
通知を飛ばしたいチャンネル名を指定してください

**message**
通知のメッセージです
なんでもいいです
「\n」で改行できます
「`@here`」とかでメンション付けれます
「`@<XXXXX>`」で個人にメンション付けれます
「XXXXX」にはslackのメンバーIDを指定します
slackのメンバーIDはslackの個人のプロフィール「その他」から確認できます

**color**
通知時のカラー設定ができます
good,warning,dangerで状態のカラーを設定できます
`#XXX`とかカラーコード指定もできます
ビルドの結果（成功失敗）でカラーを変えるとわかりやすいかと思います

他にも設定項目は色々あるので公式の方で確認してみてください
https://plugins.jenkins.io/slack/

# 3. ビルド

ビルドボタンを押すと…
![jenkins_slack01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216261/03bd4fb5-51a1-b3ef-8efc-abb001628e06.png)
連絡ありがとうおじさん
salesforceでのあれやこれやを色々書いていく（今後も追加予定）

こんにちは！
株式アクシスのアドベントカレンダー14日目担当山内です！

2回目の投稿ということで何を書こうか迷っていましたが、最近は案件でsalesforceを触っているので、[salesforce](https://www.salesforce.com/jp/)について色々書いていこうと思います。

色々とはいいましたが、特に過去のエラーなどを書き溜めたりしていないので汗、思い出しつつ、これからも追記しつつやっていこうと思います。

## already output

先日こんなエラーと（厳密にはデバッグログ）に出会いました。

```
DEBUG|{-1.00=(-1.00), 1.00=(already output), 1.50=(already output), 1.75=(already output)}
```

お、おーるれでぃあうとぷっと！？
まったくもって意味不明でした。

発生した状況としてはこんなイメージ。

```java
Map<String, List<String>> map = new Map<String, List<String>>();
List<String> list = new List<String>();

for(Integer i = 0; i < 10; i++) {
    list.add(i);
    map.put("hoge", list);
    list.clear();
}
```

これの何がいけないかと言うと、for文の中の最終行、`list.clear()`がNG。
これが`list = new List<String>`ならOK。

公式ドキュメントによると
> 循環参照で使用する場合、出力は無限再帰を防ぐために切り捨てられます。大きなコレクションに使用する場合、合計ヒープサイズと最大 CPU 時間を超えないように出力が切り捨てられます。
コレクションごとに最大 10 項目が出力に含まれ、その後に省略記号 (…) が続きます。
同じオブジェクトがコレクションに複数回含まれている場合、そのオブジェクトは出力に 1 回のみ表示されます。後続の参照は (already output) と表示されます。

引用：[Mapクラス](https://developer.salesforce.com/docs/atlas.ja-jp.apexcode.meta/apexcode/apex_methods_system_map.htm)

最後の方に書いてますが、一つのオブジェクトをputで詰めていいのは一回までのようです。
調べれば結構する出てきたんですが、「ん、なんだ？」ってソースコードを眺めていたので、混乱しましたｗ


## visualforceでの連動項目

salesforceのオブジェクトには選択リストというものがあります。
この選択リストは他の選択リストと連動関係になれます。まあ、いわゆる親子みたいな。
たとえば親フィールドが`Parents__c`、子フィールドが`Child__c`だとします。
それをvisualforceで以下のように書きます。

```
<apex:inputField value="{!Parent__c}">
<apex:inputField value="{!Child__c}">
```

こう書くだけで、それぞれがセレクトボックスで表示されます。
そして親を選択すると、その親に紐づく子のみが選択できる状態になります。
親に紐づく子がいない場合は、子のセレクトボックスは`disabled`になります。
すばらしい！


## サポートされていないカスタム項目のデータ型を変換しようとしました。 

これは変更されたオブジェクト定義のメタファイルをデプロイしようとしたときに発生したエラ－です。
今回僕がこのエラーに遭遇したケースは、管理者がオブジェクトのデータ型を変更して、その変更した状況に合わせようとして、オブジェクト定義のメタファイルを更新した。という状況です。
コード上でそのデータを使用している場合は基本的に型の変更ができないようです（使用としたらエラー出た）。
なのでその管理者も、一つ一つコメントアウトしていってからデータの型を変更したそうなので、まあ、とくにかく大変です。。。

## 選択リストの値を取得する

選択リストの値を一覧で取得したいってことはあると思うし、なんか簡単に取れると思うんですが、ほんのちょっとだけ面倒なんですよね。
例えばさっきの`Parent__c`を例に取ると、この`Parent__c`はFamilyというオブジェクトのフィールドだとすると、
`Family__c.Parent__c.getDescribe().getPicklistValues();`こうすると`PicklistEntry`クラスというListが取得できて、その`PicklistEntry`クラスの`getLabel`メソッドと`getValue`メソッドで選択リストのlabelとvalueが取得できる。
んー、なんかスッテプが多いんだよなぁ。


## 全角数字を半角数字に

まあsalesforceうんぬんの話ではないですが、apexでこう書いたよってのを備忘録的に記載。

```java
public static String replaceFullToHalf(String str) {
    List<Integer> codePointList = new List<Integer>();

    for (integer i = 0; i < str.length(); i++) {
        // 文字のコードポイント取得
        Integer codePoint = str.codePointAt(i);

        // 1～9(全角)
        if (65296 <= codePoint && codePoint <= 65305) {
            // 全角数値を半角数値に変換してリストに追加
            codePoint -= 65248;
            codePointList.add(codePoint);
        } else {
            // 半角数値以外はそのままリストに追加
            codePointList.add(codePoint);
        }
    }

    return String.fromCharArray(codePointList);
}
```

思考停止のコピペで動くはずです。

## 随時追加してきたい

とりあえずこのくらいです。
思い出したら追記していって、モリモリにしていこうと思います。
あとどれくらいsalesforceしているかはわかりませんが。。。ｗ
結構便利なとこがあったり、「んんんんーっっ！！？」って思うとこもあったり、結構毎日新しいことがあるので、結構楽しくsalesforceを触ってます。

結論：型推論のない静的型付け言語は面倒くさい。
WSL2 のインストール時に WslRegisterDistribution failed with error: 0xc03a001a で失敗するときの対処法

# WSL2のインストールに失敗

公式 [Windows 10 用 Windows Subsystem for Linux のインストール ガイド](https://docs.microsoft.com/ja-jp/windows/wsl/install-win10)
こちらの手順に従ってWSL2を用いてUbuntu20.04を使おうとしたところ、下記のエラーでインストールに失敗しました。

```
Installing, this may take a few minutes...
WslRegisterDistribution failed with error: 0xc03a001a
Error: 0xc03a001a ???????????????????????????????????????????????????
```

## 対処法

私は下記の方法で無事にインストールに成功するようになりました。

1. C:\Users\user name\AppData\Local\Packages を開く。（無ければおそらく隠しフォルダになっています）
2. Packageディレクトリで `ubuntu`など、利用しているディストリビューションの文字列でサブディレクトリを検索。(このとき、見つけたサブディレクトリの右上に青い矢印が付いていると思われます)
3. サブディレクトリを見つけたら、プロパティ > 詳細設定 > 内容を圧縮してディスク領域を節約する のチェックをオフにする。
4. 青い矢印が消えたことを確認。
5. WSL2を起動。うまくいけばインストールが始まります。


## 参考元

https://github.com/microsoft/WSL/issues/5325
https://github.com/microsoft/WSL/issues/5325#issuecomment-654463010

公式リポジトリのIssue。
このようなコメントがあります。
> NTFS has this feature that compresses directories to save space. If some or all of your icons are marked by 2 opposing blue arrows, that's your sign that said feature is indeed on. Now, because of this, the directory that hosts your Store downloads (in this case Ubuntu) might also have the same issue.
Go to C:\Users\user name\AppData\Local\Packages folder. If not apparent, it's probably hidden. Once inside directory, search subdirectory with 'ubuntu' string/keyword. Once located, right click the directory > Advanced > uncheck the compression > Apply. Now the ubuntu directory should have the arrows removed, which means you should have a better chance at actually running the distro install.

ディレクトリの容量を節約するために圧縮する機能があってそれが悪さをしていると。。。

## 余談 - WSL1をWSL2に変換しようとすると失敗

上記エラーを解決した後、

```powershell
wsl --set-version Ubuntu 2
```
のコマンドを利用して、もともと利用していたUbuntuをWSL2に変換しようとしました。
そうすると、

```
変換中です。この処理には数分かかることがあります...
WSL2との主な違いについては、https://aka.ms/wsl2 を参照してください
仮想ディスクシステムの制限により、要求された操作を完了できませんでした。仮想ハードディスクファイルの圧縮と暗号化が解除されている必要があります。また、仮想ハードディスクファイルをスパースに設定することはできません。
```

とのエラーメッセージが。

https://github.com/microsoft/WSL/issues/4103
こちらのIssueでも議論されていますが、上記エラーと同じく該当ディレクトリの圧縮を解除することでWSL2への変換ができるようになりました。

## さいごに

以上、お困りの皆様の助けになれば幸いです。
AWS用語集第三回(VPCのネットワークコンポーネントについて)

# はじめに
<a href="https://qiita.com/shuntagami23/items/a4665a08d33ecfa023ea">第二回の記事</a>ではVPCの概念とサブネットへのIPアドレスの割り当てについて説明しました。今回はそのVPCがインターネット（外の世界）と通信する方法についてみていきたいと思います！

# サーバー
インターネットと接続するには`サーバー`をサブネットの中に設置する必要があります。サーバーはよく「画面のないパソコン」と例えられますが、要はコンピュータに「Linux」や「Windows Server」などサーバー用のOSをインストールすればそれはサーバーになります。さらにそこに`Nginx`をインストールすれば`webサーバー`になるし、`mysql`をインストールすれば`データベースサーバー`になるといった具合です。AWSでは`Amazon Elastic Compute Cloud(Amazon EC2もしくはEC2)`というサービスを使って、`サーバー`を作ることができます。ここで作った`サーバー`のことを`EC2インスタンス`と呼びます。

# インターネットゲートウェイ
インターネットゲートウェイとは、各サブネットがインテーネットと通信するために、VPCにアタッチされるものです。サブネットのルートテーブルにインターネットゲートウェイへのルーティングを設定することによってサブネット内のサーバーはインターネットゲートウェイと接続できる訳です。ただし、サブネットの`ルートテーブル`に`インターネットゲートウェイ`へのルーティングがないと接続できません。

# ルートテーブル
サブネットに関連づけて使用されサブネットから外に出る通信をどこに向けて発信するか決めるルールのことです。コンソール上では以下の様に表示されます。
![スクリーンショット 2020-12-13 22.01.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/694973/82278a6d-0093-21b3-ff15-1ec6328c19e9.png)
送信先`10.0.0/21`、ターゲット`local`で表されたルートはVPC内部でのルーティングを表し、デフォルトで設定されています。送信先`0.0.0/0`で表されたルートが`インターネットゲートウェイ`へのルーティングです。ルーティングを設定しただけでは`EC2`がインターネットと接続することはできません。コンピュータが外部と接続するためにはその住所の役割を果たす`IPアドレス`が必要になるからです。このインターネット接続用の`IPアドレス`の種類として、`Public IP address`と`Elastic IP address`があります。

# Public IP addressとElastic IP address
この二つは`EC2`がインターネットと接続するための`IPアドレス`という機能は同じですが、性質が異なります.インスタンスの作成時の設定で`Public IP address`を割り当てることができますが、これは起動／停止のたびに開放される`動的IPアドレス`です。これを固定したい場合に`静的IPアドレス`である`Elastic IP address`を割り当てることができます。

# NIC(Network Intarface Card)
AWSの話からそれますが,コンピュータをネットワークに接続するための拡張カードが`NIC`です。何をしているかというと、データを電気信号に変換してケーブル上に流すこと、そして受け取ることです。文字通りパソコンとネットワークの「接点」となっているわけです。なぜこの話をしたかというとAWSにおいてもこれに該当するサービスがあり、それが`ENI(Elastic Network Intarface)`です。先ほどの`IPアドレス`を割り当て、`EC2インスタンス`にアタッチして使用されます。つまり、この`ENI`がインターネットゲートウェイとつながることにより、`EC2`はインターネット接続ができます。

# まとめ
用語の数が多くなってしまったが、結局は仮想空間の中にサーバーがあり、インターネットと接続するために`IPアドレス`やルーティング、その他部品が組み合わさっているということになります！
TechFeedとかいうTL(布教)

# はじめに
この記事は[限界開発鯖 Advent Calendar 2020](https://qiita.com/advent-calendar/2020/approvers)の記事、の予定でした、はい。
遅刻しました大変申し訳ありません(土下座)。

そしてこの記事が、コミュニティガイドラインにおける宣伝・広告に当たるのかしばらく悩みました。
ダメそうなら場所を移すのでコメントなどで教えて欲しいです。

# TechFeedについて
ネタが思いつかなかったので著者が便利に使ってるTechFeed Proというサイトについて紹介したいと思います。
[TechFeed Pro](https://techfeed.io/)(https://techfeed.io/) とは、エンジニア向けの情報をまとめて配信してくれる、いわゆるまとめサイトのようなものです。
個人的なイメージとしては、エンジニア向けの情報だけが流れてくるTwitterのタイムラインのようなものと思っています。

![スクリーンショット 2020-12-13 23.42.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/484856/23446401-7813-628a-8439-b1a6a2c9d0c7.png)

##  特徴
###  チャンネルが存在する
チャンネルが存在して、それぞれの分野ごとに流れてくる情報を絞ることが出来ます。
上記の写真では、`Kotlin`、`Amazon Web Service`、 `Linux`などといったチャンネルをフォローしています。
また、チャンネルごとのフォローの度合いとして`トレンドモード`と`エキスパートモード`があり、流れてくる情報の量を自分で管理することが出来ます。

### 自分で記事を共有することが出来る
自分が読んだ記事を自分のフォロワーへ共有することが出来ます。
フォロワー以外への共有はフォロワーがシェアするぐらいしかないように思っているのですが、ほかになんらか手段があれば教えて欲しいです。

### 読みたい記事が流れてくる
主観です。「あーそうそうそう、そういうのをもっと見つけたかった」みたいな記事がバンバン流れてくるのたのしい。既読がつくので読んだ記事が見分け付きます。モダンなRSSリーダーみたいな使い方が出来るので、合う人には合うと思います。

## デメリット
たいして見当たりません。強いていえばチャンネルが存在しないジャンル・言語などは運営に要望するしかないという点です。
ほかにあれば教えて欲しいです。

# 最後に
内容が薄くて申し訳ありません、後々追記とかすると思います。
読んでいただきありがとうございます。
Storybook(ver.6系)でNext.jsの絶対パスインポートに対応する

## 経緯
Storybookのバージョン５系から６系へのアップデートは、主に設定ファイル周りでの大きな変更が含まれていました。
今回はNext.jsのプロジェクトに新たにStorybookを追加するにあたり、[こちらのStorybook６系に対応した記事](https://qiita.com/keitakn/items/982d7e6cdfc294c82a95)を参考に導入を進めました。

##発生した問題
上記の通り導入後Storybookを起動すると、以下のようなエラーに遭遇しました

``` bash:error
ERROR in ./components/common/AppInput/index.tsx
Module not found: Error: Can't resolve 'styles/colors' in '/Users/＊＊＊/Projects/＊＊＊/components/common/AppInput'
```

どうやらNext.jsのデフォルトで解決される絶対Pathの設定がStorybookにされていないため、一部の依存ファイルが読み込めていないようです。
（この場合は絶対パスで指定した`styles/color`が読み込めていません）

## 解決方法
Storybookの設定ファイル(ver6系からは`.storybook/main.js`に統一)に絶対パス解決の設定を記述します。

```javascript:main.js
// ↓↓↓ここから追記↓↓↓
const path = require('path')
//↑↑↑ここまで↑↑↑

module.exports = {
  stories: ['../components/**/*.stories.@(tsx|mdx)'],
  addons: [
    '@storybook/addon-links',
    '@storybook/addon-actions',
    '@storybook/addon-knobs',
    '@storybook/addon-docs',
    '@storybook/addon-a11y',
  ],
  // ↓↓↓ここから追記↓↓↓
  webpackFinal: async (baseConfig) => {
    baseConfig.resolve.modules = [
      ...(baseConfig.resolve.modules || []),
      path.resolve(__dirname, '../'),
    ]
    return baseConfig
  },
  //↑↑↑ここまで↑↑↑
}

```

これでデフォルトの設定に加えて絶対パスの解決設定がWebpachにロードされるので無事ビルドされます！
選択したメソッドを右クリックからphp日本語マニュアルで開けるようにする

# はじめに
2020年度XTechグループアドベントカレンダーの14日目の記事です。

エキサイト株式会社、新卒１年目の荒井です。
今回はMacで右クリックをすると表示されるメニューに「php日本語マニュアルで開く機能」という自作機能を追加していきます。

完成形としては下記画像の様な形になります。

![github上で右クリック](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272109/d4e3d0b9-858f-adc5-24fb-3fb3289ae976.png)

右クリックした後に表示される「phpマニュアルで開く」という項目をクリックするとブラウザが新規のタブでphp日本語マニュアルを開きます。

下記の例ではarray_intersect_keyですので
https://www.php.net/manual/ja/function.array-intersect-key.php
が開かれます。

Github上でのコードレビュー時や他の技術ブログの記事を読んでいるときに役立てばいいなと思います。

# 環境
機種：MacbookPro 16
OS: macOS Catalina 10.15.4

# 作り方
Macの右クリックしたあとのメニューに表示される項目は「サービス」と呼ばれるみたいです。

このサービスメニューを作成するにはAutomatorという標準アプリを使用します。
![Automator](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272109/118f5d05-80b5-b35e-8489-ba55b8004e28.png)

## Automatorとは
AutomatorではMacでできる様々な機能を組合わせてタスクを作成することができます。

- 画像からPDFを作成
- URLをダウンロード
- イメージのサイズ調整

などMacに標準で入っていて便利な機能をライブラリのように扱えるためよく調べておくと日頃の業務に活かせるかもしれません。
今回はそのなかでエンジニア的には一番便利なのではないかと思われる
- シェルスクリプトを実行
というものを使用していきます。

## サービス作成までの流れ
それでは実際にAutomatorを使いサービスを作っていきます。
### 下準備
まずAutomatorを開くの下記画像のようになりますので「クイックアクション」を選択します。
![Automator下準備](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272109/c039fb64-3c95-897c-27e2-73d6a86d6456.png)

すると下記画像のように
- ワークフローが受け取る: 現在の項目（テキスト）
- 検索対象: すべてのアプリケーション

となっていればここまでは大丈夫です。
このようにすることで選択したテキスト（今回でいうとphpのメソッド名）を受け取ることができます。
![Automator下準備](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272109/2c8b8570-1284-986d-2e3d-4953e5237f28.png)

### シェルスクリプトに選択した文字列を渡す
次に受け取ったphpのメソッド名をもとにphpの日本語マニュアルのページを開く機能を作っていきます。

検索窓から「シェルスクリプトを実行」を探しドラッグ＆ドロップしてください。
その後、入力の引き渡し方法の部分を「stdin」から「引数として」に変更します。
下記画像のようになれば大丈夫です。
![シェルスクリプトを実行](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272109/93881658-19ee-83ac-6f26-78dcb79fc33f.png)

ここまででシェルスクリプトの引数にユーザーが選択したテキスト（phpのメソッド名）を渡すことができるようになりました。
今回はブラウザで特定のURLを開ければ良いので、下記のスクリプトをコピーして貼り付けてください。

```zsh:phpマニュアルを開く
replacedMethodName=${1//_/-}
open "https://www.php.net/manual/ja/function.${replacedMethodName}.php"
```
php日本語マニュアルではメソッド名にアンダースコアがある場合にURLではハイフンに置き換わっているようですので置換処理がしてあります。
（いまのところ上記の処理だけで動いているのですが、もしほかの規則が見つかった場合は書き加える必要があります。）

ここまで完了したら保存してブラウザを再起動すればサービスとして追加されていると思います。

# デバッグ方法
今回は２行しか書いてないですが、もし複雑なスクリプトを書きたい場合はなんどか実行してデバッグをしたいということがあるかと思います。

今回の機能でいう「ユーザーが選択したテキスト」という部分をシェルスクリプトに渡すため__スタブ的なものを一時的に__ 置く必要があります。
検索窓から「指定されたテキストを取得」を探し「シェルスクリプトを実行」の前に置きます。
すると下記画像のように指定したテキストをシェルスクリプトに渡すことができます。

![Automatorのデバッグ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272109/097c0b59-20e7-acbc-d5fc-5392805ca70f.png)

# 最後に
最近Automatorを使い始めたのですが、Macの便利な機能を自分のスクリプトに組み込むことができる点はすごく面白いと思います。
特定のディレクトリ以下の画像を再帰的にサイズ調整する、みたいな処理をしたいとなったときに言語のライブラリを調べるのも良いですが、MacのAutomatorから呼び出してみるのも良いかなと思いました。

採用情報はこちら↓
https://www.wantedly.com/companies/excite