OmniAICreator/Qiita-1.07M huggingface dataset:
新型Macに搭載されているアップルシリコンについて(11月17日更新)

#目次
>前書き
Applesiliconについて
<font color = "Red">Applesiliconの具体的なスペック</font>
新発売されたMacBookAirとMacBookProとMacminiの価格
まとめ

#前書き
11月の11日にあったアップルの発表会を見てその内容をざっくりまとめたものとなります。
かならずしもすべて正しいとは限らないことを踏まえて読んでいただけると幸いです。


#Applesiliconについて
今回搭載されたチップの名前は<font color = "Red"><b>M1</font></b>となります。
###M1チップの概要
><b>8CoreのCPU
8CoreのGPU
16CoreのNeural Engine
その他


が入っています。
今回紹介するのはCPUとGPUです。

#追記Applesiliconの具体的なスペックについて
今回搭載された、M1チップの性能が明らかになったのでそれを紹介します。
はい！今回のM1チップの性能はずばり！こんな感じです！
![スクリーンショット 2020-11-17 184034.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/866543/b0e36558-06fc-3524-715c-f5366debc842.png)
で、これだけではわからないので、比較用として
![スクリーンショット 2020-11-17 184018.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/866543/e84e613d-1b1a-7ba0-eac4-5a12e749323f.png)
![スクリーンショット 2020-11-17 183957.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/866543/3961694f-9bda-e35d-5fe7-101b997a1bcf.png)


そうなんですよ今回のM1チップ前回(結構前に書いたとき)書いたときにi9に匹敵するといいましたが、i9を超えているんですよ！
ですが、ソフト側の相性問題などを含めたら、実際どこまで動くかわかりませんが、数値的にはこれが正しければ、
i9以上のスペックを持っているということになります。


###CPU
今回搭載されているCPUはARMとなっており、一世代前の13インチMacBookProの基準値を大幅に超える性能となっています。

####CPUの概要
>4つの高性能コア
4つの高効率コア

が搭載されています。
![スクリーンショット 2020-11-11 203838.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/866543/c0bc5142-9f9a-04a8-909c-8628e742fdce.png)

上記の画像の通り
XCodeのの場合<font color = "Red">2.8倍</font>となっており、そのほかにも1.8倍から3倍近くの性能アップがされています。
具体的な数値はわかりませんが、一世代前のCPUと比較した数値で出してみると、Corei7以上もしくはi9に匹敵する性能だと思います。

###GPU
今回のGPUは一世代前のCPUより飛躍的に性能が上がりました。
![スクリーンショット 2020-11-11 204929.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/866543/fc5721da-f82d-cff4-e177-665ff30a26b7.png)
上記の画像の通りFinal Cut Proでは<font color = "Red">6倍</font>近く性能が上がり、UnityEditorの場合は3倍も性能が上がっています。
過去のMacBookPro13インチのGPUと比較して数値を出してみると、場合によっては<font color = "red">GTX1650ti</font>に迫る性能となっています。(本当にそうかはわからない)

#新発売されたMacの価格
><b>MacBookAir  104800円~ 209,800円
<b>MacBookPro   134800円~ 234,800円
<b>Macmini      72800円 ~ 172,800円

となっています(すべて税別価格)
コスパを優先するならMacminiが狙いどころだと思います。

#まとめ
今回はざっくりながらもApplesilicon搭載Macに触れてみました。まだ実際に触ったり数値が出たりもしていないので、わかりませんが
私なりに調べて書いてみたので是非参考にしてみてください。
私も実際に買ってその感想を発信していこうと思います。
最後によければ、TwitterのフォローとBoothで3Dモデルの販売などをしているので良ければ
買ってみてください。
##SNS
Twitter  https://twitter.com/uho19003
Booth　　https://upon.booth.pm/

##参考資料
AppleHP  https://www.apple.com/jp/
.bashrcに環境変数PS1を記載して、ターミナルを見やすくしよう

# はじめに
ターミナルが単色だったりすると見づらく、作業効率が落ちるため、```.bashrc```に環境変数```PS1```を追記して、色を変更します。

# サンプル

**1. .bashrcを直接編集する**

```sh:.bashrc
SERVERNAME=aws-akane
export PS1='\[\e[1;36m\][\e[1;33m\]\u@\[\e[1;32m\]${SERVERNAME} \w\[\e[1;36m\]]$\[\e[00m\] '
```

**２. EC2のユーザーデータを利用する**

```sh:EC2のユーザーデータ
#!/bin/bash
yum update -y
cat <<EOS | sudo tee -a /home/ec2-user/.bashrc
SERVERNAME=aws-akane
export PS1='\[\e[1;36m\][\e[1;33m\]\u@\[\e[1;32m\]${SERVERNAME} \w\[\e[1;36m\]]$\[\e[00m\] '
EOS
```
IaaS/PaaS/SaaSとはなんぞや【メモ】

# ○aaS
Web業界について勉強していると、「○aaS」という言葉をよく目にします。
違いをよく忘れるので、簡単にメモしておくことにしました。

## IaaS
- 読みは「**イアース**」
- **Infrastructure as a Service**の略称
- サーバやストレージ、ネットワークなど、**アプリケーション開発に必要なインフラをクラウド上で提供するサービス**のこと。
- **AWS**や**GCP**のサービスの大部分が該当。

## PaaS
- 読みは「**パース**」
- **Platform as a Service**の略称
- **アプリケーションの実行環境（プラットフォーム）をクラウド上で提供するサービス**のこと。  
OSやミドルウェア、各種ライブラリをインストールすることなく、アプリケーションをデプロイして公開することができる。IaaSと似ているが、インフラの各種パーツを個別に提供するのがIaaSで、パーツを組み合わせた完成品がPaaSという感じか。PCで言うなら自作とBTOの違い。
- **Heroku**や**GAE**が該当。

## SaaS
- 読みは「**サース**」
- **Software as a Service**の略称
- **利用者のパソコンやサーバにソフトウェアを直接インストールするのではなく、インターネットでその機能を提供するサービス**のこと。
- 従来は専門のソフトウェア企業が開発し、パッケージソフトとして個別に配布されるのが主流であったが、ブラウザやスマホアプリなどのWebサービスとしての提供に移行している。  
~~年賀状ソフトとかって電器屋行ったらまだ売ってるん？~~

# 他の○aaS
## FaaS
- 読みは「**ファース**」
- **Function as a Service**の略称
- **サーバレスサービス**のこと。  
＊サーバレス  
　**サーバの管理を、それを提供するクラウドベンダー側に完全に委託してしまうこと。**クライアントが呼び出した回数や処理の実行時間などに対して料金が発生する。サーバが存在しないということではない。**サーバ管理にかかる工数を削減できる、運用コストが低いなどのメリット**がある。
- AWSの**Lambda**が該当。

## mBaaS
- 読みは「**エムバース**」
- **mobile Backend as a Service**の略称
- **モバイルアプリの開発に必要なバックエンドの機能をクラウド上で提供するサービス**のこと。
- 認証やログイン、データベース、ストレージなどの**バックエンド側の機能を、バックエンドエンジニアやインフラエンジニアなしでも簡単に実装**できる。  
とはいえ万能ではなく、様々な制約もあるため、機能要件・非機能要件が簡単なアプリケーションの開発に用いられる。
- モバイルとあるが、バックエンドやフロントエンドでも使用される。
- Googleの**FireBase**が該当。
次来るかもしれない！？『TypeScript』について　~JavaScriptの上位互換~ ※tsconfig.jsonもメモ

JavaScriptの需要とともに型、オブジェクト指向を持つTypeScriptの人気が上がってきています。
今回は『次来るかもしれない！？TypeScript』について語っちゃいますmm

![7b234c88d715caf1e3063f5b88a25909.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684145/78bbb566-8035-7768-d038-0f075e97629e.png)




#TypeScriptとは
TypeScriptは型やオブジェクト指向を持つJavaScript言語のようなものです。
TypeScriptのコード拡張子は「.ts」です。「.ts」ファイルを直接実行することはできないため、これをトランスコンパイルし、JavaScriptファイルである「.js」に変換します。

２度変換するのは少々面倒ですよね(笑)

#TypeScriptは2種類の目的が存在する
TypeScriptは2種類のトランスコンパイラ方法があります。

>❶ブラウザで動作させるJavaScriptファイルを生成するため
❷node.jsで動作させるJavaScriptファイルを生成するため

ブラウザでのJavaScriptで有名な命令でwindows.alertがあります。
これを実行するとブラウザ上でアラート(警告)が表示されます。

しかし、node.jsはブラウザを介せず、
PC上で動作するためwindows.alertコマンドは理解できません。

TypeScriptを利用する場合は実行環境が『ブラウザ』か『node.js』なのか理解しておく必要があります。


#Typescriptメリット
<b>JavaScriptは現代のアセンブラと呼ばれるほど難解な言語</b>です。

原因は型指定が存在しないことにあります。

変数に整数型、文字型、オブジェクト型、変数まで何でも入っちゃうんですよね(笑)。

変数にパラメータを渡すときにも
>・何を渡せばよいのか
・必須変数は何なのか
『API仕様書を読む』か『無ければコードを読む』しかありません。

しかしTypeScriptにより型を明確にすることにより、
それらの無駄な作業時間がなくなります。

また型が正確に指定していると、VS Codeなどでコーディングする際に補完機能が働きタイプミスやパラメータミスなど初歩的なバグを無くす事ができ、開発効率も上がります。

メリットを一言でいうならば<b>「開発効率が超絶UP」</b>につきます。

環境構築が必要な分、スロースターターですが、それに有り余るほどの見返りがあります。


#tsconfig.jsonのメモ
```json
{
  "compilerOptions": {
  "target": "ES2019",        /* ECMAScriptのターゲットバージョンを指定します: 'ES3'（デフォルト）, 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018'または 'ESNEXT' */
  "module": "commonjs",      /* モジュールコード生成: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015',または 'ESNext'を指定します。 */
  "strict": true,            /* すべての厳密な型チェックオプションを有効にします。 */
  "noImplicitAny": true,     /* 暗黙の 'any'型で式と宣言のエラーを発生させます。 */
  "strictNullChecks": true,  /* 厳密なヌルチェックを有効にします。 */
  "noImplicitThis": true,    /* 暗黙の 'any'型で 'this'式のエラーを発生させます。 */
  "esModuleInterop": true    /* デフォルトのエクスポートがないモジュールからのデフォルトのインポートを許可します。これはコードの出力には影響しません。型検査だけです。 */
  }
}
```
[Rails]いいね数順でランキングかつページネーション

以前このような記事を書きました。
[[Rails]いいね数順でランキング](https://qiita.com/Kazuhiro_Mimaki/items/1f8e851b957f511c88e9)

この内容に加え、ページネーションを実装したのでメモとして残しておきます。
今回はいいね数順で並び替えた投稿を1ページに5つ表示させるページネーションの実装を目指します。

# 前提
- 投稿のテーブルは `posts`、 ユーザーのテーブルは `users` とする。
- いいね機能に必要な中間テーブルは `likes` とする。
- `posts`・`users`・`likes` それぞれのテーブルはいずれも作成済みとする。
- ページネーションは`Kaminari`というgemを使用して実装

# 手順

## モデルにアソシエーションを定義

```post.rb
class Post < ApplicationRecord
    belongs_to :user
    has_many :likes, dependent: :destroy
    has_many :liked_users, through: :likes, source: :user
end
```

```user.rb
class User < ApplicationRecord
  has_many :posts,dependent: :destroy
  has_many :likes, dependent: :destroy
  has_many :liked_posts, through: :likes, source: :post
end
```

```like.rb
class Like < ApplicationRecord
  belongs_to :post
  belongs_to :user
end
```

## `Kaminari` をGemfileに追記し, `bundle install`

```ruby:Gemfile
gem 'kaminari', '~> 0.17.0'
```

```zsh
$ bundle install
```

## コントローラーをいじる

```app/controller/posts_controller.rb
def index
  posts = Post.includes(:liked_users).sort {|a,b| b.liked_users.size <=> a.liked_users.size}
  @posts = Kaminari.paginate_array(posts).page(params[:page]).per(5)
end
```

ここでは `sort` というrubyのメソッドを使って順序を操作している。
=> [sortに関してはこちらを参照](https://docs.ruby-lang.org/ja/latest/method/Array/i/sort.html)

`a.liked_users.size`、`b.liked_users.size` が表しているのはそれぞれ各投稿のいいね数。
すなわち、各投稿のいいね数を比較して昇順で並び替えている。

`sort`メソッドによって生成される`posts`という変数は配列のデータなので、`paginate_array`というメソッドを使用している。



## ビューで表示させる
あとはビューで表示させるだけ。

```app/view/posts/index.html
<% @posts.each do |post| %>

  #省略

<% end %>
<%= paginate @posts %>
```
まだまだ知らないメソッドたちはたくさんあるなぁ。

# 参考
- [Array#sort (Ruby 2.7.0 リファレンスマニュアル)](https://docs.ruby-lang.org/ja/latest/method/Array/i/sort.html)
- [[rails]kaminariを使ってページネーションを作る](https://qiita.com/you8/items/df68aaee3010e282d1ae)
- [kaminariを使って配列に対してのページャーを作成する](https://blog.konboi.com/post/2013/03/31/224939/)
[Objective-C]定数配列の定義・使い方

#はじめに
業務にて、とある返却値のコードだったら処理A、他だったら処理Bみたいなことがしたかったので
定数配列でコードを定義する必要がありました。

##定数配列の書き方
ヘッダーファイルにはこんな感じ。

```objectivec:sample.h
extern NSString * const HOGEHOGE[];//定数配列 クラス外で使う場合はexternつける
```

中身はこんな感じ

```objectivec:sample.m
NSString * const HOGEHOGE[@"カレー",@"すし",@"ラーメン"];//宣言と同時に中身定義
```

### 実用例
とある処理の返却値が上で定義した配列の要素の中にあったら処理A、なかったら処理Bとしたい場合

```objectivec:sample.m
NSString * const HOGEHOGE[] = {@"カレー",@"すし",@"ラーメン"};//宣言と同時に中身定義
NSUInteger * const HOGEHOGESIZE = 3//配列のサイズ

# 省略

NSMutableArray * array =[[NSMutebleArray alloc] init];//別の配列用意
for(int i =0;i < HOGEHOGESIZE;i++){
    [array addOblect:HOGEHOGE[i]];//用意した配列に定数配列の要素追加
}

if([array containsObject:@"カレー"]){//
    //定数配列に含まれていたら処理Aを行う
}else{
    //定数配列に含まれていなかったら処理Bを行う
}
```

#最後に
Swiftではどのように書くのか調べてみよう
s3でURLリダイレクトするときの設定まとめ

## 設定方法
1. s3をホスティングしたいドメイン名で作成する
2. Route53でs3エイリアスレコードを作成し、s3のドメイン名と紐付ける
3. s3のパブリックアクセスを許可してインターネット上に公開する
4. プロパティ-静的ウェブサイトホスティングを有効にして、リダイレクトルールも設定する
5. ブラウザやcurlでアクセスして動作をみてみる

## ホスティングの設定
- インデックスドキュメント、エラードキュメントは指定するが、ファイル自体はなくても大丈夫
- s3のみの場合、httpでしかアクセスできないため、httpsも利用したい場合はCloudFrontを利用する必要がある
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293481/e13590d5-8d05-a19a-2fa8-e46f205b6a94.png)

## リダイレクトルール

### メモ

- ホストするURLが`example.com`
- https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/how-to-page-redirect.html
- 上記URLではXML形式で案内されているけど、いまはjsonで書かないといけないみたい
- 上のルールからConditionブロックをなめていき、ヒットしたらそのセクションのRedirectルールが発動
    - ApacheのRedirect処理と同じ感じ
- `ReplaceKeyWith`と`ReplaceKeyPrefixWith`の設定に違いがあることにたどり着くまで半日かかりました、、、

### 各種設定値

#### Conditionブロック
- Condition
    - ディレクトリ、ファイル、エラーコードを指定し、ヒットした場合にRedirect内のルールが処理される
- KeyPrefixEquals
    - `/aaa`のようにリダイレクトしたいときのパス、ディレクトリを指定する

#### Redirectブロック
- Redirect
    - Conditionとセットで設定
- HostName
    - s3バケット内ではなくて、別のドメインへリダイレクトする場合に指定する
- Protocol
    - リダイレクト後のプロトコルを指定する。 http or https
- ReplaceKeyWith
    - 置き換えられるパス（クエリ）
    - リクエストされたドメイン移行のクエリは破棄される
    - `example.com/aaaaa` でリクエストが合った場合、 `https://vamdemicsystem.black/blog-and-news/`になる
- ReplaceKeyPrefixWith
    - 置き換えられるパス（クエリ）
    - リクエストされたドメイン移行のクエリは維持される
    - `example.com/aaaaa` でリクエストが合った場合、 `https://vamdemicsystem.black/blog-and-news/aaaaa`になる

```json
[
    {
        "Condition": {
            "HttpErrorCodeReturnedEquals": "404"
        },
        "Redirect": {
            "HostName": "vamdemicsystem.black",
            "Protocol": "https",
            "ReplaceKeyWith": "blog-and-news/"
        }
    }
]
```

#### 複数のルールを書くとき

```json
[
    {
        "Condition": {
            "KeyPrefixEquals": "test/"
        },
        "Redirect": {
            "HostName": "vamdemicsystem.black",
            "Protocol": "https",
            "ReplaceKeyWith": "blog-and-news/"
        }
    },
    {
        "Condition": {
            "HttpErrorCodeReturnedEquals": "404"
        },
        "Redirect": {
            "HostName": "vamdemicsystem.black",
            "Protocol": "https",
            "ReplaceKeyWith": "blog-and-news/"
        }
    }
]
```
他ユーザーの投稿編集画面に行けないようにする

#環境
 ・Rails 5
・deviceを用いてログイン機能を実装済み

#ログインしていないユーザーを投稿編集画面に行けないようにする

ログインしている時としていない時で表示画面を変える

```view.rb
<% if user_signed_in? %>
```

ログインしていない場合ログイン画面に飛ぶ

```controller.rb
before_action :authenticate_user!
```
#他ユーザーの投稿編集画面に行けないようにする
view側だけに記述した場合だと、urlを直接打つと変更できてしまうのでcontroller側にも記述する。

```controller.rb
@book = Book.find(params[:id])
  if @book.user == current_user
    render "edit"
  else
    redirect_to books_path
  end
```
```view.rb
<% if @book.user == current_user %>
　　〜〜〜〜〜
<% end %>
```


違う方法

```controller.rb
  before_action :ensure_correct_user, only: [:edit, :update]

  def ensure_correct_user
    unless @user == current_user
      redirect_to user_path(current_user)
    end
  end
```

```if文          → もしも、評価が真(true)であれば○○する```
```unless文 → もしも、評価が偽(false)であれば○○する```

#最後に

筆者は初学者なので間違っている部分や説明不足などあると思います。その際には指摘していただけると幸いです。

#参考文献
https://qiita.com/tobita0000/items/866de191635e6d74e392
Visual C++でC++のバージョンを取得する方法

# はじめに

筆者は、まだまだC++を学び始めて半年程度で、最近デザインパターンなどを意識し始めた、脱初心者レベルである。
また、本記事の執筆の際には、「Microsoft Visual Studio Community 2019 Version 16.6.5」環境で検証している。

# マクロ「__cplusplus」がおかしい件

C++のバージョンをC++コード側で取得しようと思い、マクロ「__cplusplus」を使ってみた。

~~~cpp
long version = __cplusplus;
std::cout << "C++ Version : " << version << "\n";

// 実行結果：C++ Version : 199711
~~~

この199711Lは、C++98を示すバージョンのようで、明らかに不正確である。
(shared_ptrとかclampとか使えてるからC++17以上でないとおかしい) 

> C++バージョンに応じた、マクロ__cplusplusの値は、こちらを参照。
[https://cpprefjp.github.io/international-standard.html#list-of-iso-cpp](https://cpprefjp.github.io/international-standard.html#list-of-iso-cpp)

プロジェクトプロパティのC++バージョンをC++14やC++17に指定しても同様であった。
どうやら、これはVisual C++固有の仕様であるっぽい。
**※追記：このマクロを有効化する手段あり(詳細は後述)**

# Visual C++でC++のバージョンを取得する方法

色々と調べてみたところ、C++のバージョン(と思われるもの)を記したマクロ「_MSVC_LANG」があるようで、充分代用が効きそうであった。

~~~cpp
long version = _MSVC_LANG;
std::cout << "Visual C++ Version : " << version << "\n";

// プロパティオプションがC++14の実行結果：Visual C++ Version : 201402
// プロパティオプションがC++17の実行結果：Visual C++ Version : 201703
~~~

なるほど、凄く分かりやすい。
これを使って、良い感じに自作マクロ定義してあげると、Visual Studioにも対応したC++バージョンに応じた実装が可能になりそう。
勉強になった。

# 追記：Visual C++での「__cplusplus」 マクロの有効化

uemurajさんにコメントで教えて頂いたやり方が、もっと良さげだったので追記しておく。(素晴らしい情報提供ありがとうございます。)

1. プロジェクトの [プロパティ ページ]を開く
2. [構成プロパティ] > [C/C++] > [コマンド ライン]まで移動
3. [追加オプション] ウィンドウに以下の2つのどちらかを追加し、適用。(筆者は前者を使用)

~~~
/Zc:__cplusplus
/Zc:__cplusplus-
~~~

参考：[/Zc:__cplusplus (更新された __cplusplus マクロの有効化) | Microsoft Docs](https://docs.microsoft.com/ja-jp/cpp/build/reference/zc-cplusplus?view=msvc-160&viewFallbackFrom=vs-2019)

この設定を適用した状態で、以下の内容で実行した結果、望ましい結果が得られた。

~~~cpp
// マクロ「__cplusplus」を有効化したうえで使用した場合
long lCppVersion = __cplusplus;
std::cout << "マクロ「__cplusplus」 : " << lCppVersion << "\n";

// マクロ「_MSVC_LANG」を使用した場合
long lVCppVersion = _MSVC_LANG;
std::cout << "マクロ「_MSVC_LANG」 : " << lVCppVersion << "\n";

// プロジェクトプロパティでC++14を指定時の実行結果
// マクロ「__cplusplus」 : 201402
// マクロ「_MSVC_LANG」 : 201402
~~~

# 参考にしたサイト

* マクロ「__cplusplus」で取得できるバージョンについて  
[C++国際標準規格 - cpprefjp C++日本語リファレンス](https://cpprefjp.github.io/international-standard.html#list-of-iso-cpp)
* マクロ「_MSVC_LANG」で取得できるバージョンについて  
[処理系 - cpprefjp C++日本語リファレンス](https://cpprefjp.github.io/implementation.html#visual_cpp_ver)
* マクロ「_cplusplus」をVisual C++で有効化する方法について  
[/Zc:__cplusplus (更新された __cplusplus マクロの有効化) | Microsoft Docs](https://docs.microsoft.com/ja-jp/cpp/build/reference/zc-cplusplus?view=msvc-160&viewFallbackFrom=vs-2019)
BootstrapのRubyへの導入方法

#BootstrapのRubyへの導入方法
過去に作っていたECサイトのコーディングをしようと思いbootstrapの導入を行ったがてこづったので、メモとして投稿しておく。

##Gemfile

>gem 'bootstrap-sass', '~> 3.3.6'
>gem 'jquery-rails'

を記述し、bundle installを実行
bootstrap-sassのバージョンは以下のページにてご自身の環境に合うようにご確認ください。
https://rubygems.org/gems/bootstrap-sass/versions/3.4.1?locale=ja

##application.css
application.cssをapplication.scssに変更し、application.scssに

>@import "bootstrap-sprockets"; 
>@import "bootstrap"; 

##application.js

>//= require jquery
>//= require bootstrap-sprockets

を追加で記入

これでBootstrapを思いの儘に使えます。
Gemfileにbootstrapの記述を書いて満足して、scssファイルやjsファイルへの記述忘れがちですね。
Rails Boolean型の活用

#はじめに
オリジナルアプリを制作していて、初めてBoolean型を使用しました。使用方法や注意点を備忘録として書き記します。状態判定に使用するカラム(カラム名：status、テーブル名：suggestions)の型をbooleanとしました。

**開発環境**
ruby 2.6.5
Rails 6.0.3.4

#目次
1.マイグレーションファイル
2.モデル
3.データの保存

#1.マイグレーションファイル
カラムの型を「boolean」にする。空のカラムは許可しないようnull: falseによるNOT NULL制約を実施すること。

```ruby:2020***********_create_○○.rb
    create_table :suggestions do |t|
      t.boolean :status, null: false
      t.timestamps
    end
```

#2.モデル
バリデーションをモデルに記述する。カラムと空のバリデーションの記述が異なることに注意。


```ruby:○○.rb
validates :text, presence: true #<=他カラムの記述
validates :status, inclusion: { in: [true, false] }
```

#3.データの保存
trueもしくはfalseによって保存する。

```ruby
@suggestion.status = true 
```

参考ページ
[Railsでboolean型のカラムのvalidationを行い型が異なる場合エラーとして返す方法](https://qiita.com/k-shimoji/items/13c51b4719cf1eb1f117)
以上
TD CLIの環境変更を簡単にする方法 for mac


# TD Toolbelt
Treasure Dataには、コマンドラインツールTD Toolbeltがあります。
最初にtd accountコマンドで認証情報を設定すれば、あまり変更することはないと思いますが、環境を切り替えるのがめんどくさい人とかいるかもしれません、知らんけど。
本記事は、[envchain](https://github.com/sorah/envchain)を使ったTD環境の切替方法をまとめました。
envchainを使えば暗号化されるので、ある程度安全にAPIキーを保持できます（保証はしません）し、そんなに使い勝手も悪くないと思います。

## 前提
- Treasure Dataをご利用。
- macを使用している。（catalina 10.15.7で確認)

## envchainのインストール
envchainのインストール方法は、たくさん文献があると思いますが一応記載します。homebrewを使用してインストールします。

```
% brew install envchain
```

## APIキー、APIサーバーの登録

APIキーは、TDコンソールのMy Profileにある「API Keys」を参照することで確認できます。
envchainの登録は、次のコマンドを入力します。

`envchain --set td-us TD_API_KEY TD_API_SERVER`

その後、TD_API_KEYとTD_API_SERVERの入力を促されます。
例えば、envchainの登録名をtd-usとして、USリージョンの設定をする場合はこんな感じです。

```
% envchain --set td-us TD_API_KEY TD_API_SERVER
td-us.TD_API_KEY: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
td-us.TD_API_SERVER: https://api.treasuredata.com
```

ちなみに、東京リージョンはこんな感じです。（envchainの登録名は自由）

```
% envchain --set td-tk TD_API_KEY TD_API_SERVER
td-tk.TD_API_KEY: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
td-tk.TD_API_SERVER: https://api.treasuredata.co.jp
```

登録されたキーチェーンは、macOSの「キーチェーンアクセス」アプリケーションで確認できます。（なんとなく要らないところはマスクしてます）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237667/37fb1db1-061c-bcbc-e8d3-3bd1cd04d1b3.png)


## envchainの使い方

### envchainの登録をリスト表示
envchainコマンドで登録したもののリスト表示が可能です。

```
 % envchain --list
```

### envchainに登録したキーを削除
envchainに削除コマンドが見当たらないので、「キーチェーンアクセス」アプリケーション上で削除するしかなさそうです。

## tdコマンドの実行
実行するtdコマンドのアタマに`envchain <登録名>`を付けるだけです。
例として、先ほどのUSリージョンで実行したい場合はこんな感じです。（これはconnectorのリストを表示するコマンドです。）

```
% envchain td-us td connector:list
```

# 参考URL

API Key and API Server Search Order Reference
https://tddocs.atlassian.net/wiki/spaces/PD/pages/1082090/API+Key+and+API+Server+Search+Order+Reference
Magenta インストール Windows版 更新情報 2020.11.11

【2020.11.11 Magenta更新情報】

WindowsでのMagentaインストールにつきまして。
Google側の修正が行われた模様で（もしくはTensorFlowなど依存ライブラリのアップデートにより）2020.08.12の様な対策インストール

https://qiita.com/ys23/items/01c9ca27e315f0b03fca

は不要となりました。

特に特別な設定は不要で通常通り

pip install magenta

でインストールが完了し問題なく動作する事を確認しております。
なお2020年11月11日現在はMagentaは2.1.2がインストールされます。


Macはこれまで通り特に留意点はございません。
SDWebImage: 特定UIImageViewのキャッシュをクリアする方法

## はじめに
画像キャッシュライブラリとして広く利用されている[SDWebImage](https://github.com/SDWebImage/SDWebImage)ですが、
キャッシュをクリアする際のメソッドとして主に以下のメソッドを利用するシーンが多いと思います。

```Swift
SDImageCache.sharedImageCache().clearMemory()
SDImageCache.sharedImageCache().clearDisk()
```
しかし特定のUIImageViewのキャッシュをクリアしたい場合には、
いちいちすべてのキャッシュをクリアしてしまうのはコストが高いので、
特定のUIImageViewのキャッシュクリアの方法を調べてみました。

### 特定のUIImageViewのキャッシュクリア

以下のメソッドを利用することで実現できます。

```Swift
SDImageCache.shared.removeImageFromDisk(forKey: String)
SDImageCache.shared.removeImageFromDisk(forKey: String)
```

引数の`forKey`（cacheKey）とは、そのUIImageViewにセットされているURLのようです。
[▼公式ドキュメント](https://github.com/SDWebImage/SDWebImage/blob/master/Docs/HowToUse.md#using-asynchronous-image-caching-independently)
> The cache key is an application unique identifier for the image to cache. 
> It is generally the absolute URL of the image.

`generally`が若干気になりますが笑（おそらくキャッシュ時にkeyを指定できるから？）
以下の通り実装することでキャッシュクリアできました。

```Swift
if let cacheKey = uiimageView.sd_imageURL?.absoluteString {
    SDImageCache.shared.removeImageFromDisk(forKey: cacheKey)
    SDImageCache.shared.removeImageFromDisk(forKey: cacheKey)
}
```
Android10(API29)対応



# Android 10 でデバイス ID の権限が変更された件 
すべてのデバイス ID が 、READ_PRIVILEGED_PHONE_STATE という権限によって保護される事に。
**この権限は、サードパーティーアプリには付与することができましぇん。(怒)**
###### 制限を受けるメソッド
以下、公式。
https://developer.android.com/about/versions/10/privacy/changes?hl=ja#non-resettable-device-ids
制限されるのは以下のメソッド。

```対象.java
Buildクラス
 getSerial()
TelephonyManagerクラス
 getImei()
 getDeviceId()
 getMeid()
 getSimSerialNumber()
 getSubscriberId()
```

###### READ_PRIVILEGED_PHONE_STATE権限ってどうやって与えるのさ
リクエストパーミッションなどの通常の権限付与ではなく、
端末に存在する設定ファイルの該当アプリ箇所に、直接許可を記載する必要がある。
以下の記事が参考になった。
https://qiita.com/hiesiea/items/6a2deb479958a3b44707#read_privileged_phone_state%E3%82%92%E3%83%9B%E3%83%AF%E3%82%A4%E3%83%88%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AB%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B

ただしこの権限を付与できるのは、
プリインストールアプリや、携帯キャリアが配信するアプリに限る。
###結論
普通にPlayストアに出すようなアプリは、
デバイスに紐づけられているIDを取得できなくなった。
(端末にプリインストールされているアプリや、
携帯キャリアが提供するアプリはできる)

### 感想
対象範囲別ストレージによる直パスアクセスの禁止といい、
API29からは、端末内へのアクセスをどんどん制限してますね。
(やりすぎてAPI30で緩和されるのですが…)
####参考
https://source.android.com/devices/tech/config/device-identifiers
jwtの期限が絡んだテストをする際、jwtの中身を明示的に示す必要が出てきた場合のテスト方法

## テストについて
jsonwebtokenモジュールを使ってjwtを生成したり検証したりする。

テストコードの中で上記モジュールのsign()を使ってjwtを生成してそのjwtを使えば当然テストは成功する。
が、テストコードの中のテストケースごとに前提条件や期待結果をコメントアウトで書く場合、
使うパラメータを具体的に書くのが適切だったりする(それが必ず正解とは限らない)。

その場合、jwtのsing()は実行のたびに別の文字列になってしまうので、コメントアウトには
「実行ごとに固定とならないjwt」みたいな変なコメントを書かなきゃいけなくなる。

## 方法
それを回避するには、sign()でjwtを生成する際、有効期限を99yearsにして、テストコードを実行してjwtをいったん生成する。その後にjwtをメモっておいて、そのjwtを直接変数に文字列として代入してテストで使えばいい。

**■まず、99年間期限が切れないjwtを仮に生成。**

```typescript:anime-suko.ts
  const SECRET_KEY = '任意の文字列'
  const payload = {
    hogeID: 'hogehoge-111',
  }
  const option = {
    expiresIn: '99years',//異常な値だがテストのためだからまあ仕方ない
  }
  const token = jwt.sign(payload, SECRET_KEY, option)

```


**■その後に、生成されたjwtをコピって変数に直接入れる(以下のjwtはあくまで例なので、手入力で目を閉じてキーボード乱れうちしたものです)。その変数をテスト実行時に関数の引数にする**

```typescript:anime-suko.ts
   const token = "lkafdkfajdsjd78fd89a7f8979fa798fas6s5d76a5d67safasfasfsafa"
```

**■テストコードでのテストケースに書くコメント**

```typescript:anime-suko.ts
/*
 * 【正常系】：jwtに〜を含む←(「〜」にはペイロードにセットしたデータ)を利用してhogeテスト
 * 【前提条件】：hogeがhogeである場合。
 * jwtが、「lkafdkfajdsjd78fd89a7f8979fa798fas6s5d76a5d67safasfasfsafa」である場合。
 * 【期待結果】：AがBであること
 */
```

## 感想
関係ないけど、テストコードって機能実装よりも大変ですよね。。。
テストケースが多かったりして一人で数千行のテストコードを書いたりした
超初心者がNuxt.js×Firebaseでログイン画面を実装するまで

#前提
以下を参考(ほぼ丸パクリ)して作成し､初心者すぎてわからない点をまとめています｡
参考サイト:
https://www.metrocode.co/blog/post/firebase-authentication-nuxt-vuejs
※著作権的にNGであれば教えて下さい・・・｡

#教訓
######■教訓1:参考サイトは検索方法と比較工夫して厳選すべし
・ちょっと古い記事だと書いてること通用しないこと多々。2017年が境目な感覚。
・npmをyarnに変えてやったらいいやで進めたら後でエラー辿れなくなる
・UIフレームワークもそっくりそのまま参考にしないとエラー辿れなくなる
・各moduleのバージョンもそっくりそのまま以下同文

######■教訓2:amplifyやらfirebaseの認証部分も飛ばさず進めるべし
・後で「こんなはずじゃなかったのに！」ってなる｡(なった｡)
・まだ上手くログインページの見た目すらできてないからかもしれないが…途中までイケてたのに！となりそう。それも勉強か。

######■教訓3:何のコマンドなのか理解しながら進むべし
・内容全部理解してなくてもエラー切り分けできるレベルでの状況理解は必要、逆にそれができればググればなんとかなる

#追加でやったこと
上述の[参考サイト](https://www.metrocode.co/blog/post/firebase-authentication-nuxt-vuejs "参考サイト")に加え､以下を実施｡

####①firebaseとの連携用にdotenvモジュール追加のため､nuxt.config.jsに以下を記載｡
```nuxt.config.js
 modules: [
    // https://go.nuxtjs.dev/axios
    '@nuxtjs/axios',
    '@nuxtjs/dotenv',
  ],
```

####②何のためかはわかってないけどnuxt.config.jsに以下記載｡
```nuxt.config.js
  build: {
     extend (config,ctx){
     }
  },
```

#createPersistedState from 'vuex-persistedstate'のsessionStorageでブラウザ切断後ログアウトしたい

こいつが難関です｡上述の[参考サイト](https://www.metrocode.co/blog/post/firebase-authentication-nuxt-vuejs "参考サイト")でもこれの完成までは記載してなく､これと戦う｡

###参考サイト記載部分まで
早速以下のエラーに遭遇｡
> ReferenceError: window is not defined

以下参照して直す｡
https://ja.nuxtjs.org/faq/window-document-undefined/
>サーバーサイドのレンダリングに起因します。 
クライアントサイドでのみリソースをインポートしたい時は process.client 変数を使用する必要があります。
例えば .vue ファイルに次のように書きます:
if (process.client) {
  require('external_library')
}

ふむふむ｡俺はクライアントサイドでのみインポートしたいの？サーバーサイドでもインポートしちゃだめなの？
SSRやらSPAとかの話だな､以下を参考に改めて理解する｡
https://qiita.com/nishinoshake/items/f42e2f03663b00b5886d

あれ？むしろSPAを作成しようとしてたんだから､クライアントサイドでのみインポートしたいんだよね｡
SSRはサーバー必要だから今の状況では不可｡
上記公式に乗っ取って修正する｡
→と思ったら､既にprocess.clientあるじゃん｡｡｡なんでだめなの｡
>       if (process.client) {
 
######ソースコード見直してみる｡
あああ､とんでもない間違いだった・・・｡★部分を追加してしまってたからだ・・・｡
nuxt.config.jsのpluginsセクションに読み込むように追記してあげる､をmodulesも追加しちゃった｡
コメントアウトして､動作を確認｡

```nuxt.config.js
  modules: [
    // https://go.nuxtjs.dev/axios
    '@nuxtjs/axios',
    // https://yarnpkg.com/package/dotenv
    '@nuxtjs/dotenv',
    // https://yarnpkg.com/package/vuex-persistedstate★
    'vuex-persistedstate',★
  ],
```

※modulesに追加すべきはどういうときなんだ？
→調べる→わからなかった｡
axiosとdotenvはmodulesで呼ぶのに､なぜvuex-persistedstateは呼ばないんだー｡

###参考サイトを乗り越える
動作も､コンパイルはできたけど､ブラウザ閉じてもログイン保持されたままだ｡
>                storage: window.sessionStorage

が空になってない｡理由は？

#おまけ
#####modeを途中から変更したい場合
nuxt.config.jsに
ssr: true でuniversal mode
ssr: false でspa mode
mode:'spa'は以前の書き方で､以下のように廃止されている｡
>WARN  mode option is deprecated. Please use ssr: true for universal mode or ssr: false for spa mode and remove mode from nuxt.config
HerokuでPythonのjson.loads()がstrを返す問題

## はじめに

Herokuって便利ですよね。とりあえず動かすだけなら、初心者でもできますし。
そんなHerokuでDiscord botをHerokuで動かそうとしたときにハマったお話です。

## 問題点

Pythonの`json.loads()`は`json.dumps()`などで文字列化した辞書型 (連想配列) をもとの辞書型に直す関数です。
当然、返り値は辞書型です。

localやGCP上では問題なく使えていたのですが、herokuで同じように動かすと、なぜかstring型が返されていました。`json.dumps()`を誤って使っていたというオチではありません。

```Python:Heroku
## 文字列をjson.loadsで解凍
loaded_dict = json.loads(dumped_string)

## printしてもそれっぽい出力
print(loaded_dict)
# {"key1":"value1", "key2":{"v2k1":"v2v1"}}

## しかし、stringになっている
print(loaded_dict["key1"])
# TypeError: string indices must be integers
for k, v in loaded_dict.items():
    ...
# AttributeError: 'str' object has no attribute 'items'
print(type(loaded_dict["key1"]))
# <class 'str'>
```

## 解決方法

Herokuの検索妨害力が強すぎて「Heroku使ってみた」みたいな記事ばかりヒットして、うまく根本的な問題原因が見つけられませんでした。
しかし`print(loaded_dict)`の表示自体はおかしくなかったので、`eval()`で解決させました。

```Python:Heroku
## evalをかませる
loaded_dict = eval(json.loads(dumped_string))
## 解決！
print(loaded_dict["key1"])
# "value1"
```
cicleci configの書き方

あとでまとめる

■cicleci configの書き方
orbs：外部アプリとの連携
executors：実行する環境を定義（Docker Image）
jobs：実行処理をまとめて一意の名前を付けて定義
※workflowsを指定する場合は、そちらが実行される。
workflows: 複数のジョブをグループ化してワークフロー名を付けて定義。
特定のブランチで実行。
filters:
　branches:
　only: staging

ジョブはデフォルトだと並行して実行される。
ジョブ名による依存関係を明示的に要求する必要があります
- deployStaging:
          requires:
            - generateStaging
          filters:
            branches:
              only: staging
IQ Bot：OCRが日付の/（スラッシュ）を1と読んでしまう問題への対応

[IQ Bot](https://qiita.com/IQ_Bocchi/items/fab5f59230ff38a98bbd)では、処理するOCRエンジンを自由に選択することができます。

選択可能なOCRエンジンの特徴やクセを[こちらの記事](https://qiita.com/IQ_Bocchi/items/8ad6ec8f5a6afd3c98a1)にまとめていますが、エンジンによっては、「YYYY/MM/DD」形式の日付の「/」（スラッシュ）を「1」と読んでしまうケースが見られました。

例：2020/11/11と書いてあるのを、2020111111と読んでしまう　等

もちろん、このような場合は日付（date）型を指定しておくことで[誤り検知](https://qiita.com/IQ_Bocchi/items/4e220a9bd6e337de4508)をするのが一般的な対応ですが、カスタムロジックを使ってある程度正しい形に補正してから誤り検知をかけた方が効率的です。

そんなわけで、標記の問題に対して筆者が作成したカスタムロジックを公開してみます。

いろいろ場合分けしていたらけっこうな行数になってしまいました。
もっとシンプルなやり方を思いついた方はぜひコメントください。

##日付のスラッシュを1と読んでしまった場合に使えるカスタムロジック

```python:1と読まれてしまった日付のスラッシュをスラッシュに戻す

# スラッシュが入るべき位置に1があった場合、その文字をスラッシュに置き換える関数
def slashConvert(x,index):
    if x[index] == "1":
        x = x[:index] + "/" + x[index + 1:]
    return x

# スラッシュが入るべき位置を特定し、かつ変換をかける関数
# x = もとの値、y = 年の桁数(YYYY/MM/DDなら4,YY/MM/DDなら2)を渡す
def date1toSlash(x,y):
    
    # すでにスラッシュが2つ以上含まれていたらそのままreturn
    if "/" in x:
        if len(x.split("/")) >= 3:
            return x
    
    # 年の数字以降は最低/M/Dで4文字以上あるはず
    # それに満たなければそのままreturn (=検証で検知)
    if len(x) < y + 4:
        return x
    
    # 年と月の間にスラッシュを入れる
    x = slashConvert(x,y)
    
    # 月と日の間にスラッシュを入れるために、どの桁にスラッシュが入るかを求める
    # 不明の場合はそのままreturn → すると日付として不完全な値が返るので、IQ Bot側の検証で検知できるという仕組み
    if len(x) == y + 6:        # 年以外が6桁 = /MM/DD = 月日ともに2桁 = おしりから3桁目がスラッシュ
        mdIndex = -3
    elif len(x) == y + 5:      # 年以外が5桁 = /M/DD or /MM/D ←　いずれかを見極める必要あり
        if 2 <= int(x[y+1]) <= 9:      # 年の次の桁が2～9なら、2月～9月=1桁月なので、M/DD = おしりから3桁目がスラッシュ
            mdIndex = -3
        elif x[y+1] == "0":            # 年の次の桁がゼロ = MM/D？　でも月だけゼロ埋めしてあるのは怪しいのでそのままreturn
            return x
        elif x[-3:-1] == "11":         # おしりから3桁目＆おしりから2桁目の並びが「11」（つまり最後の4桁が?11?）の場合
            if x[-4:] == "1110":       # 1110なら1/10に決まりだが……
                mdIndex = -3
            else:                      # 上記以外（1111など）は1/11なのか11/1なのか判断できないのでそのままreturn
                return x
        elif (x[-3] == "1") and (x[-2] != "1"):   #月日部分が1120なら1/20に決まる
            mdIndex = -3
        elif (x[-2] == "1") and (x[-3] != "1"):   #月日部分が1211なら12/1に決まる
            mdIndex = -2
        else:                  # 上記以外のパターンは想定なし
            return x
    else:                      # else に来るのは年以外が4桁のパターン = /M/Dなのでおしりから2桁目がスラッシュ
        mdIndex = -2
        
    x = slashConvert(x,mdIndex)
    
    return x

#フィールド項目に対して適用する場合で、年の桁数が4桁の場合
field_value = date1toSlash(field_value,4)

#テーブル項目に対して適用する場合で、年の桁数が2桁の場合
df['列名'] = df['列名'].apply(date1toSlash,y=2)

```

上記のテーブルに対して適用する場合のコードは、[おまじないコード](https://qiita.com/IQ_Bocchi/items/68d3260c8afed7d27902)の間にはさんでいる前提です。
rvmとpostgresqlで環境構築まとめ

```
rvm install "ruby-2.3.0"
rvm list
rvm use 2.3.0
ruby -v
rvm gemset create hogehoge
rvm gemset list
rvm gemset use hogehoge
brew search postgresql
brew install バージョン
brew services start postgresql@9.6
vi /usr/local/var/postgresql@9.6/postgresql.confでポート番号変更(5435)
rails db:create
psql -l -p番号
(ダンプファイル入れる)
psql -p ポート番号 database名 < backup_file名
```
アプリケーション.dmgダウンロード時のカスタムdmgの作り方

## 目的
・アプリケーション.dmgをダウンロードした際のカスタムdmgを作成する。
## 手順
・前準備として背景素材を用意する。これは独自に用意する必要があり、自分はパワーポイントを使って作成した。背景を単色で埋める場合はある程度大きな画像を用意する必要がある。今回は1024×720の画像を用意した。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698633/fbdfe650-80df-3df3-82b2-7c62af88f291.png)
*図１：サンプルの背景画像（パワーポイントで作成）*

・dmgの中には背景画像とアプリ本体、フォルダエイリアスしか入らないので、「Drag and drop」等の説明文は画像に予め埋め込む必要がある。

・完成したアプリケーションをArchive → Export → Export as a Mac Applicationより.appファイルを作成する。

・完成したアプリケーションを入れるApplicationsフォルダのエイリアスを作成する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698633/f2bb2a11-b17c-b908-c4f9-c91883ff88b0.png)
*図２：Applicationsフォルダのエイリアスを作成*

・エイリアスを作成した後、デスクトップにフォルダを移動し、フォルダ名をApplicationsにリネームする。これで下準備は終わり。

**ここからdmgを作成する。**

・OS標準ディスクユーティリティアプリケーションを起動して空のディスクイメージを作成する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698633/bce01848-64da-ec0a-fcf4-ed52efb90527.png)
*図３：空のディスクイメージを作成*

・イメージを作成したら、特に変更点はないので名前だけ変更し、場所をデスクトップに指定して保存する。

・作成されたdmgは自動的にマウントされるので、マウントされたディスクに下準備で用意した背景素材・アプリケーション本体・Applicationsエイリアスをドラッグアンドドロップする。その際、背景素材はbackgroundフォルダに格納しておく。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698633/6fc96494-9a2a-a135-3857-7e17ed0a5a43.png)
*図４：各素材をディスクにドラッグアンドドロップする。（図のアプリや背景素材と今回の完成品の素材は別物）*

・背景フォルダは使用しないため、隠しフォルダとして表示する。隠しフォルダの作成はターミナルを使用して行う。以下のコマンドを実行する。

<font color="Blue">cd /Volumes/(作成したdmgファイル名)
mv background .background</font>

これで、backgroundフォルダは隠しフォルダになる。隠しフォルダ内の画像は後で使用するため、
<font color="Blue"> cd .background/ 
open ./</font>
これを順に実行し、フォルダは開いておく。

・あとはそれぞれのサイズを調整する。サイズの変更は変更するフォルダを右クリックし、「表示オプションを表示」から行う。今回は128×128にした。

・背景の変更は「背景」→「ピクチャ」で先ほどの隠しフォルダから画像をドラッグアンドドロップする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698633/13549dbd-9cd3-5282-2afd-a87d129d70e4.png)
*図５：このような画面になる*

ここまで完成したら、自分が表示しようとしているサイズまで拡大・縮小を行い完成！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698633/89eecbd2-88e5-6c93-68ce-2fb9fbbff8c1.png)
##補足
図４のキャプションでも説明した通り今回の完成品に用いたサンプルアプリや背景画像と図4に写っているアプリや背景画像は異なるので注意が必要...
Hugo で立ち上げたブログの記事をカッコよく管理する

## :bulb: まとめ

- Hugo でブログを立ち上げたとき、ブログの記事は別リポジトリで管理するとコミットログが汚くならない
- CI/CD を使ってブログ記事のリポジトリをクローン・ビルドするパイプラインを組んでおけば、ブログ本体のソースを触る必要がなくなる

## :seedling: 背景

先日、 [`Hugo`](https://gohugo.io/) を使用したポートフォリオサイトを作り、その中にブログを併設しました。

[Fairy Select - My Portfolio](https://portfolio.fairy-select.com)

ソースコードを管理する際に Git を使用するわけですが、そうすると、ブログ記事を追加するためだけにコミットログを積まなければならなく、コミットログが非常に汚くなってしまいます。

記事を 3 回加筆修正しただけでこんなにコミットログが積まれます:cry:

![commit-log.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/486784/5a51e681-9e4c-a146-4bc3-4a4e1c2dbb18.png)

そこで考えたのが...

> ブログ記事だけ別リポジトリにすればいいんじゃね？

です。

## :thinking_face: 考えた方法

「ブログ記事だけ別リポジトリに」した後を考えます。

#### サブモジュール化する

Git にはサブモジュールという便利な機能があって、これを使うと少なくともブログ記事のコミットログは別で管理できます。

ところが、サブモジュールに関する [ある記事](https://qiita.com/sotarok/items/0d525e568a6088f6f6bb) を読んだところ、サブモジュールの更新があった場合に自分で更新を読み込まなければいけないようです。

結局は `Update submodule: posts` のようなコミットログを積まないといけないことになるので、面倒というよりはブログ記事のように<mark>更新頻度の高いコンテンツをサブモジュール化するのはあまり向いていない</mark>と感じました。

そんなこんなで採用したのが次の方法です。

#### ブログ記事をクローン・ビルドするパイプラインを組む

`.gitlab-ci.yml` を以下のように書いて CI/CD を設定しました。（実際はもっといろんな処理を書いていますが、概略はこんな感じです）

```yaml
image: registry.gitlab.com/pages/hugo:latest

variables:
  GIT_SUBMODULE_STRATEGY: recursive

pages:
  script:
    - apk update && apk --no-cache add git
    - git clone ${ブログ記事の URL}
    - git clone ${ブログ記事画像の URL}
    - hugo
  artifacts:
    paths:
      - public
  only:
    - master
```

これで、 `master` ブランチに何かをプッシュするだけでパイプラインが実行され、記事の更新が可能となります！:smile:

> - パイプライン上で `git clone` しますので、ビルド成果物に `.git` が含まれないように注意しましょう。
>
> - GitLab においてプライベートリポジトリを HTTPS 経由でクローンする場合は、ユーザー名・パスワードの記載が必要です。二段階認証を利用している場合は、アクセストークンが必要です。これらは GitLab 上の環境変数に設定して参照するようにし、スクリプトに直接書かないようにしましょう。

GitLab における環境変数は、リポジトリのページから 「Settings → CI / CD → Variables」 と進むと設定できます。

詳しくは [こちら](https://docs.gitlab.com/ee/ci/variables/README.html#custom-environment-variables)

![gitlab-environment-variables.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/486784/e27289e3-4a0d-6679-bf34-16a9dd9aa00e.png)

## :clock4: 定期実行も設定する

GitLab にはパイプラインを定期実行してくれる便利な機能があります。

せっかくなので設定してみようと思います。

リポジトリのページから 「CI / CD → Schedules → New schedule」と進み、日本時間毎朝 4 時にパイプラインを実行するように設定してみます。

![schedule-a-new-pipeline.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/486784/8e7dfe66-0fde-22b2-8ed3-e88f351babf6.png)

これで定期実行も完成です。

ちゃんと実行できるかどうか心配な場合は一覧画面から手動実行することもできます。

---

最後まで読んでいただきありがとうございました！:wink:
Strategy Pattern

<font color="#00f">アルゴリズムの切り替えパターン<br></font>

[Design Pattarm MENU](https://qiita.com/old_cat/items/852d980bedb9100dd7e3)

サンプルコードは
二つのクラスインスタンスを比較し
比較結果をint値で戻すというクラスを
Strategy継承クラスで作成します

アルゴリズムを切換えてはいませんが
戻り値のint値をアルゴリズムとして表現しています

以下のクラス構成で確認します

|クラス|説明|
|-----|----|
|interface Strategy|切替えアルゴリズムのメソッドを定義<br>メソッドはsam.classの2つのインスタンスを比較し、比較結果をint値として戻す|
|compare.class|Strategyを実装する|
|useStrategy.class|userが利用し、切替アルゴリズムを実行する
|sam.class|比較される対象クラス|
|user(Main.class)|動作確認|
＊user　他の開発者がこのパターンを利用する、という意味合いを含みます

```java:interface_Strategy
interface Strategy{int compare(sam s1,sam s2);}
```
```java:compare.class
class compare implements Strategy{
  public int compare(sam s1,sam s2){
    if(s1.i <  s2.i){return 1;}else
    if(s1.i == s2.i){return 0;}else{
       return -1;
    }
  }
}
```
```java:useStrategy.class
class useStrategy{
  Strategy strategy = null;
  useStrategy(Strategy st)  {this.strategy=st;}
  int compare(sam s1,sam s2){return strategy.compare(s1,s2);}
}
```
```java:sam.class
class sam{
      String str;
      int i;
      sam(String str,int i){
          this.str = str;
          this.i   = i;
      }
}
```
```java:user(Main.class)
public static void main(String[] args){
  sam sam1 = new sam("s1",3);
  sam sam2 = new sam("s2",2);
  compare     com = new compare();
  useStrategy us  = new useStrategy(com);
  System.out.println(us.compare(sam1,sam2));
}}
```
【Vagrant】現在のOSイメージをvagrantのboxとして保存して他のエンジニアに共有する。

メモとして残します。

なんやかんやで案件用にチューンしたLAMP環境等を他のエンジニアにも共有する際、同じ手順を踏んでもらっても、完全に同じ環境を構築することはできません。
そのため、オリジナルのboxとして保存して、出来上がったboxを元にvagrant upしてもらうのが良いため、その方法をメモとして残します。

#やり方
##1共有する側
###1-1)Box化するvagrantプロジェクトを用意
なんやかんやで特定の案件や、システム用にチューンしたイメージを用意する。
（＝virtualbox等に登録した状態にする。）

###1-2)イメージをVagrantのBOX化する
BOX化したいVagrantfileの場所まで移動してから、下記のコマンドでbox化する。

```shell

vagrant package
```
成功すると`package.box`というファイルが作成されている。
##2共有される側
###2-1)package.boxを自身のVagrantBOXに登録
1-2でpackage.boxを任意のフォルダに設置。
その後、設置したフォルダ上でbash等を起動して下記を実行。

```shell
vagrant box add [任意のbox名] package.box
```

追加後下記のコマンドで`[任意のbox名]`で登録したboxが表示されれば成功。

```shell
vagrant box list
```

###2-2)追加したBOXを元にVagrantUPまでする。

```shell
vagrant init [2-1で登録したbox名]
```
`Vagrant`ファイルが生成されるので、そのままvagrant up

```shell
vagrant up
```

以上。
CakePHPのSQLインジェクション対策(between使用時にハマった)


## ハマったこと
- getパラメータで受け取った値を、SQLの検索条件に使いたかった。（緯度・経度から、近くのお店を表示する機能）
- でも`$q->between('パラメータを使った計算式', 0, 1)`って書くと、エスケープされないことに気づいた。

## 原因
cakeのORMを使うと、左辺はエスケープされないみたい。

## 対策
いろいろ考えましたが、良い感じにエスケープするのは出来ませんでした。
その代わりに、パラメータを変数に入れるときに正規表現でチェックをしました。

`$latitude = preg_match('パターン', $query['latitude']) ? $query['latitude'] : '';`

$query['latitude']に`delete ~~~`みたいな恐ろしいことを書かれても、とりあえず大丈夫だと思う。

もっと良い方法があったら教えて下さい。
Snort 3.0.3はルールセットv3.0と互換性がない

Snort 3.0.2を使いましょう。

## 問題

OSSのNIDSであるSnortを[公式のドキュメント](https://snort-org-site.s3.amazonaws.com/production/document_files/files/000/000/251/original/Snort_3_on_Ubuntu.pdf)通りにUbuntu 18.04で動かそうとしたが失敗。

具体的にはRegisteredのルールセットを使ったところ`snort -c /usr/local/etc/snort/snort.lua`で`undefined variable name: RULE_PATH`などとエラーが出る。おそらく[この記事](https://gato.intaa.net/archives/12485)の症状と同じだろう。

## 原因

Snortのコード（masterの[最新](https://github.com/snort3/snort3/tree/8feb44ee29178472832302ba976fbb59799b7b7c)）を見ると、`src/parser/vars.cc`の`VarSearch()`で変数の名前解決が行われているようだ。

変数のテーブルとしては、`get_ips_policy()`で得られた`IpsPolicy`から以下の3つが参照されている。

- `var_table`
- `portVarTable`
- `ip_vartable`

最も一般的らしき`var_table`について探ると、同じファイルの`ParsePathVar()`で値を設定している。これは`IpsModule::set`だけが呼んでいいて、設定ファイルのipsブロック下の`variables.paths`内で定義されたものが渡されているようだ。

実際、`snort.lua`の`ips`へ以下のように`variables`を追加すると`RULE_PATH`のエラーは解消された。

```lua
ips =
{
    variables = {
        paths = {
            RULE_PATH = '../',
        }
    },
    rules = [[
        -- ...
    ]]
}
```

`lua`ディレクトリ下のファイルを見ても`RULE_PATH`などをグローバル変数ではなくこのように設定していて、3.0.3で変更が加えられている。

一方でSnort 3.0.2-6のコードを見ると、`src/managers/module_manager.cc`の`set_string()`などがLuaでの変数定義を処理している（`finalize.lua`でLua側から各グローバル変数についてこうした関数を呼んでいるようだ）。

ここから`set_value() -> set_var() -> SetVar()`と流れて、`RULE_PATH`の場合は`PATH`のサフィックスにより`AddVarToTable() -> VarDefine()`となって`var_table`へ追加されるのが確認できる。
マルチスケール特論 第8回

![ruby-2.7.1p83](<https://img.shields.io/badge/ruby-2.7.1p83-brightgreen>) 

# Rake

> make, ant のruby版

-   [GNU Make](https://www.gnu.org/software/make/)
    -   よくつかう
-   [Apache Ant](http://ant.apache.org/)
    -   make の Java 版らしい

------
 - **source** ~/ghq/github.com/TeamNishitani/grad_members_20f/members/syasin-5d/8th.org
MS Excelを使用せずにAIXやLinuxのnmonデータをグラフ表示

# nmonchartを使うことで、MAC上でもAIXやLinuxのnmonデータをグラフ表示可能

## 背景
nmonは、AIXやLinuxのパフォーマンス情報や構成情報を収集、表示するOSSユーティリティ。各種Linuxに対応。AIXには同梱される。
CUI全画面モードとデータを収集するモードがある。

- http://nmon.sourceforge.net/pmwiki.php
- 【nmon】LinuxのOS性能取得ツール nmon 試してみたら便利だった
    - https://jimatomo.hatenablog.com/entry/2019/12/26/000702


nmonで収集したデータをMS Excel上でグラフ表示するユーティリティとしてnmon analyserが存在するが、MAC上のExcelでは現時点で動作が確認できなかった。

## ソリューション
nmonchartを使うことで、MAC上などでもExcelを使用することなく、nmonデータからパフォーマンス情報などのグラフ表示が可能。

## 参照

http://nmon.sourceforge.net/pmwiki.php?n=Site.Nmonchart

グラフ表示の例(上のサイトに含まれる)

- http://nmon.sourceforge.net/docs/sampleC31.html
- http://nmon.sourceforge.net/docs/sampleD.html
    - いずれも、上部のボタンを押すと該当するグラフが表示される

https://github.com/aguther/nmonchart

## MAC上での導入、使用イメージ

### Linux, AIXなどで情報収集

```
# nmon -f -s 10 -c 120 -t
```

10秒おきに120回分の情報を./<ノード名>\_<日時>.nmonテキストファイルに出力
以下、データファイルをp8126a_201111_1529.nmonとする。


### MAC上でのhtml作成、表示イメージ

要ksh

```
## nmonchartスクリプトを含むgitリポジトリーを入手
$ git clone --depth 1 git@github.com:aguther/nmonchart.git

## 対象マシンからnmonデータをローカルにcopy
$ scp p8126a:p8126a_201111_1529.nmon . 

## スクリプトを実行し、htmlファイルを作成
$ ksh nmonchart/nmonchart p8126a_201111_1529.nmon

## 作成したファイルをsafariで表示
$ open -a /Applications/Safari.app p8126a_201111_1529.nmon.html
```

バージョンは上のサイトからtarで落とした方が新しいので注意。

nmonchartスクリプトの内容を確認すると、AIXもしくはLinux上での実行を想定しているので、MAC上での実行に問題が出る様であれば、nmon対象ノード上でhtml化することで回避できる可能性がある。
「Failed to notify project evaluation listener.」のエラーを解決する

# 症状

Android のプロジェクトをビルドしようとすると、下記のエラーが出た。

```
A problem occurred configuring project ':app'.
> Failed to notify project evaluation listener.
   > org.gradle.api.file.ProjectLayout.fileProperty(Lorg/gradle/api/provider/Provider;)Lorg/gradle/api/file/RegularFileProperty;
```

# 解決方法

(Android 初心者のあてずっぽう解決法です)

## 1. 新しいプロジェクトを作る

新しい Android の空プロジェクトを作り、ビルドする。
次以降のステップで、ここの設定を基準にしていく。

## 2. build.gradle を編集する

{root}/build.gradle の gradle のバージョンを、**1.** で作った動いているものに揃える。

```
この部分を合わせる
classpath 'com.android.tools.build:gradle:{x.x.x}'
```

```gradle
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:4.1.0'
        

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        google()
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}
```

すると、新しく下記のようなエラーが出た。

```
Minimum supported Gradle version is 6.5. Current version is 6.1.1. If using the gradle wrapper, try editing the distributionUrl
```

## 3. gradle-wrapper.properties を作成する

**1.** で作ったプロジェクトの下記ファイルを同じ位置にコピーしてくる。

- **{root}/gradle/wrapper/gradle-wrapper.properties**
- **{root}/gradle/wrapper/gradle-wrapper.jar**

## 4. クリーンビルド

クリーンビルド、それができなければ Android Studio 再起動
これで動くようになった。

# 参考

https://qiita.com/nobuoka/items/09cbdcd4716b930abdc4
https://qiita.com/izuki_y/items/26e5735a26a3494b4833#errorminimum-supported-gradle-version-is
【TypeScript】型ガードと型アサーションでunknown型を使い勝手良くする

こんにちは、フロントエンドエンジニアの[てりー](https://twitter.com/teriteri_code)です。
僕の詳しいプロフィールは[こちら](https://terrblog.com/about/)

TypwScriptを仕事で使いこなしたい人、TypeScriptの知識に不安がある人に向けて、具体的な勉強方法のロードマップをまとめました。

https://terrblog.com/react-typescript-how-to-master/

# はじめに
TypeScript3.0から登場のunknown型。
any型から進化し、型安全は保証されていますが、
型を特定する処理を加えないと、コンパイルを通してくれません。

そこで今回はunknown型と併用して型を特定してあげる役割を持っている「型アサーション」と「型ガード」についてみていきます。

**ちなみにunknownとの抱き合わせの本命は「型ガード」で、「型アサーション」はオマケ程度！って認識でOKです。**


# 型アサーション（as）について
型アサーションとは、型定義の上書き機能です。
「アサーション＝断定」の意味通り、型推論を押しのけて、型定義を上書きできるので、unknown型を上書きしてコンパイルを通すのですね。

書き方は``as``の後に上書きしたい型を書きます。


```ts
type Foo {
    bar: number;
    bas: string;
}

const foo = {} as Foo;
foo.bar = 123;
foo.bas = 'hello';

```
普通ならfooは空のオブジェクトとして生成されているので、``foo.bar、foo.bas``は存在せずコンパイルエラーになります。

しかし、型アサーションでFoo型を上書きしているので、エラーにならない訳です。

## 型アサーションの危険性
大前提として、型アサーションはあまり使わない方が良いです！！！

**型アサーションを使えば、任意のタイミングで型を上書きできる
→型安全性が全く保証されない**

となるからです。

## 型アサーションの使い所
unknown型との抱き合わせは、基本的に型ガードを使う事が推奨されています。

型アサーションの使い道として、多くのコンパイルエラーをとりあえず消したい時などが有効です。
例えばJsなど型定義がないコードから、Tsへの移行時などで、型がまだちゃんと敷かれていない時などの応急処置に使うイメージですね。

# 型ガードについて
型ガードを使う事で、ブロック内のオブジェクトの型を制限出来ます。
そうすることで、unknown型のままではコンパイルエラーになっていた処理を安全に通す事ができます。

## typeofでプリミティブ型を扱う
まず、プリミティブ型の型ガードにはtypeofを用います。

```ts

function doSomething(x: unknown) {
    if (typeof x === 'string') {

         //型ガードにより、xがstring型と判断されている為、substr()が使える
        console.log(x.substr(1)); 
    }
    //unknownのままだと、string型とは特定できないのでエラーになる
    x.substr(1);
}

```

## instanceofでクラスインスタンスを扱う

クラスの場合はinstanceofを使います。
使い方はtypeofの時と、ほとんど一緒です。

```ts

class Base { common = 'common'; }
class Foo extends Base { foo = () => { console.log('foo'); } }
class Bar extends Base { bar = () => { console.log('bar'); } }

const doDivide = (arg: Foo | Bar) => {

  if (arg instanceof Foo) {
    arg.foo();  
    arg.bar(); //Fooの場合は、barはないのでエラー

   //instanceofはeif文の様にlseを使うことも可能
  } else {
    arg.bar();  
    arg.foo(); //Barの場合は、fooはないのでエラー
  }
  console.log(arg.common);
};
doDivide(new Foo());
doDivide(new Bar());

```

## ユーザー定義の型ガード（is）
プリミティブ型やクラスインスタンス型と違い、オブジェクト型などに対応する型ガードはTypeScriptには用意がありません。そこで自分たちで型ガードを作る必要が出てきます。

「is」は型ガードの条件式を切り出す事ができ、ユーザー定義の型ガードと呼ばれます。

関数の返り値を引数`` is T``と定義すると、
「その関数がtrueを返す場合は引数はTであり、falseを返す場合はTではない」という型ガードの条件式になります。

```ts

const bar = (arg: number | string) => {
  const isNumber = (arg: number | string): arg is number =>

    //戻り値でtrueを返しているので、argはnumber型になる
    typeof arg === "number";
};
```
ユーザー定義の型ガード(is)も、コンパイラに型を開発者が押し付ける事ができるという点では、
型アサーション(as)と危険度があまり変わらない為、実行時のエラーが出ない様に漏れを無くしましょう。

# まとめ
any型からの反動で、とりあえず全てをコンパイルエラーしているレベルのunknown型ですが、
型アサーションと型ガードを使いこなす事で、実際に使い勝手よく書く事ができます。

## 独学でフロントエンドエンジニアを目指している人へ

フロントエンドの仕事を得るまでにどんな勉強をしたら良いのかをまとめました！！

興味ある方は是非ご覧ください。

https://terrblog.com/how-to-get-front-end-job/
ハッシュタグの書き方を統一させるためにバリデーション組んでみた

#はじめに
##やる理由
- ハッシュタグに「Rails6」、「Rails６」みたいに乱立したら嫌だなぁ…

#手順
- 全角数字をはじくバリデーション
- 全角ハッシュをはじくバリデーション

特定文字を認めないバリデーションなのでwithoutオプションで記述します。

## 全角数字をはじくバリデーション
ハッシュタグをinputさせるモデルに記述

```ruby:models/item.rb
validates :tagbody, format: { without: /[０-９]/, message: 'の数字は半角で入力してください' }
```

## 全角ハッシュをはじくバリデーション
ついでに全角のハッシュもその後の処理が面倒なのではじくことに

```ruby:models/item.rb
validates :tagbody, format: { without: /＃/, message: ' # は半角で入力してください' }
```


#おわりに
今回はバリデーションではじくことにしましたが、変換して保存する方がフレンドリーな設計かもしれません。私は技術力的にあきらめ…
あとはインクルメンタルサーチにする方法もGoodと思いますが、JavaScriptをいじるのがめんど…

余裕ができたら挑戦したいなと思います。

✔︎
python3: bottle の使い方 (その 2)

こちらにあるスニペットを実行できる形にしました。
ログインのサンプルになります。
[Docs » チュートリアル](https://bottl-translate-ja.readthedocs.io/en/latest/01_1_tutorial.html)

```py:login.py
#! /usr/bin/python
#
#	login.py
#
#						Nov/11/2020
# ------------------------------------------------------------------
from bottle import get, post, request, run
#
def check_login(name,password):
	rvalue = True
	if name != password:
		rvalue = False
	return rvalue
#
# ------------------------------------------------------------------
@get('/login') # or @route('/login')
def login_form():
	str_out =  '<form method="POST" action="/login">'
	str_out += '<input name="name"	 type="text" />'
	str_out += '<input name="password" type="password" />'
	str_out += '<input type="submit" />'
	str_out += '</form>'

	return str_out
#
# ------------------------------------------------------------------
@post('/login') # or @route('/login', method='POST')
def login_submit():
	name	 = request.forms.get('name')
	password = request.forms.get('password')
	if check_login(name, password):
		return "<p>*** Your login was correct ***</p>"
	else:
		return "<p>*** Login failed ***</p>"
#
# ------------------------------------------------------------------
run(host='localhost', port=8080, debug=True)
#
# ------------------------------------------------------------------
```

サーバーの実行

```text
$ ./login.py 
Bottle v0.12.19 server starting up (using WSGIRefServer())...
Listening on http://localhost:8080/
Hit Ctrl-C to quit.

<frozen importlib._bootstrap>:914: ImportWarning: _ImportRedirect.find_spec() not found; falling back to find_module()
```

ブラウザーで、http://localhost:8080/login
にアクセス
![login.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/657a794b-6db4-af9a-052f-d103d73cd692.png)
ScalaのMapの+ methodはkeyが同じ場合に上書きする

## 動作確認コード

```scala
import org.scalatest.matchers.should.Matchers
import org.scalatest.wordspec.AnyWordSpec

class ScalaMapAddPriorityTest extends AnyWordSpec with Matchers {
  "map の + method" when {
    "keyが重複" should {
      "追加したvalueで上書きされる" in {
        (Map("a" -> 1) + ("a" -> 99)).apply("a") should be(99)
      }
    }
  }

  "map の ++ method" when {
    "keyが重複" should {
      "右側のvalueで上書きされる" in {
        (Map("a" -> 1) ++ Map("a" -> 99)).apply("a") should be(99)

        (Map("a" -> 99) ++ Map("a" -> 1)).apply("a") should be(1)

        (Map("a" -> 1) ++ Map("a" -> 99) ++ Map("a" -> 555))
          .apply("a") should be(555)
      }
    }
  }
}
```

[scala-sandbox/ScalaMapAddPriorityTest.scala at da8969f860192bf26c242aa38c4849eb9271ec21 · tksugimoto/scala-sandbox](https://github.com/tksugimoto/scala-sandbox/blob/da8969f860192bf26c242aa38c4849eb9271ec21/src/test/scala/io/github/tksugimoto/scala/map/ScalaMapAddPriorityTest.scala)

## Scaladoc
優先順位は書かれていなかった

### `+`
```Scala
  /** Add a key/value pair to this map.
   *  @param    key the key
   *  @param    value the value
   *  @return   A new map with the new binding added to this map
   */
  override def updated [V1 >: V](key: K, value: V1): Map[K, V1]
  def + [V1 >: V](kv: (K, V1)): Map[K, V1]
```

### `++`
```scala
  /** Adds a number of elements provided by a traversable object
   *  and returns a new collection with the added elements.
   *
   *  @param xs      the traversable object consisting of key-value pairs.
   *  @return        a new immutable map with the bindings of this map and those from `xs`.
   */
  override def ++[V1 >: V](xs: GenTraversableOnce[(K, V1)]): immutable.Map[K, V1] =
    ((repr: immutable.Map[K, V1]) /: xs.seq) (_ + _)
```

`+` が呼ばれているので、`+` 依存

※ `/:` は `foldLeft`

```scala
  def /:[B](z: B)(op: (B, A) => B): B = foldLeft(z)(op)
```

## 未確認事項
- 具体的な `+` 実装
    - Map の実装によるのかもしれない