OmniAICreator/Qiita-1.07M huggingface dataset:
CakePHP4でブログを作るチュートリアル（動画版）

CakePHP4でブログを作るチュートリアルを動画（Youtube）で作成しました。
いろいろ安定していない感ありますが、よろしかったらぜひ！

# 第1回 インストール＆初期設定
CakePHPのインストールから初期設定までを行なっています。

[![第1回 インストール＆初期設定](http://img.youtube.com/vi/JrZPBRcJ5hs/0.jpg)](http://www.youtube.com/watch?v=JrZPBRcJ5hs)

# 第2回 静的ファイルとコントローラーアクション
静的ファイルの置き場所やコントローラーのアクションについて解説をしてます。

[![第2回 静的ファイルとコントローラーアクション](http://img.youtube.com/vi/YhalZPLU380/0.jpg)](http://www.youtube.com/watch?v=YhalZPLU380)

# 第3回 ビューとレイアウト
ビューとレイアウトについて解説をしてます。

[![第3回 ビューとレイアウト](http://img.youtube.com/vi/KCEfrgrSCBY/0.jpg)](http://www.youtube.com/watch?v=KCEfrgrSCBY)

# 第4回 データベースの構築
マイグレーションを使用してデータベースの構築を行います。

[![第4回 データベースの構築](http://img.youtube.com/vi/k-2rUbJsT0o/0.jpg)](http://www.youtube.com/watch?v=k-2rUbJsT0o)

# 第5回 モデルの作り方とMVCのデータの流れ
モデルの作り方とMVCのデータの流れを解説しています。

[![第5回 モデルの作り方とMVCのデータの流れ](http://img.youtube.com/vi/C5vLPaI84tc/0.jpg)](http://www.youtube.com/watch?v=C5vLPaI84tc)

# 第6回 QueryBuilderの使い方〜色々な条件で検索してみよう〜
QueryBuilderを使ってさまざまな条件で検索してみます。
詳細ページ用のルーティングやモデルバイディングの解説もしてます。

[![第6回 QueryBuilderの使い方〜色々な条件で検索してみよう〜](http://img.youtube.com/vi/-LyFncAywLM/0.jpg)](http://www.youtube.com/watch?v=-LyFncAywLM)

# 第7回 ビューの開発を便利にするヘルパーの使い方
ビューの開発を便利にするヘルパーとページネーションのご紹介します。

[![第7回 ビューの開発を便利にするヘルパーの使い方](http://img.youtube.com/vi/aFZEmwCU2NE/0.jpg)](http://www.youtube.com/watch?v=aFZEmwCU2NE)

# 第8回 Bakeで管理画面をさくっと作る方法
Bakeを使って簡単に管理画面（CRUD）を構築する方法をご紹介します。

[![第8回 Bakeで管理画面をさくっと作る方法](http://img.youtube.com/vi/hlO85wNp1po/0.jpg)](http://www.youtube.com/watch?v=hlO85wNp1po)

# 第9回 ユーザー認証機能の実装
Authenticationプラグインを使用して、管理画面にログイン制限をかけます。
その他、ログイン画面や、管理画面とフロントのレイアウト変更方法など解説をします。

[![第9回 ユーザー認証機能の実装](http://img.youtube.com/vi/gWo1BGIEaXs/0.jpg)](http://www.youtube.com/watch?v=gWo1BGIEaXs)

# 第10回 多言語化設定（ローカライゼーション）
多言語化設定（ローカライゼーション）方法をご紹介します。

[![第10回 多言語化設定（ローカライゼーション）](http://img.youtube.com/vi/uqHS8BZu6H4/0.jpg)](http://www.youtube.com/watch?v=uqHS8BZu6H4)

# 第11回 一対多のアソシエーション〜投稿とユーザーの関連付け
モデル同士の連携を行うアソシエーションを利用して、投稿とユーザーの関連付けを行います。

[![第11回 一対多のアソシエーション〜投稿とユーザーの関連付け](http://img.youtube.com/vi/M73R4rRNWtg/0.jpg)](http://www.youtube.com/watch?v=M73R4rRNWtg)

# 第12・13回 多対多のアソシエーション〜投稿のタグ機能の実装（フロント編）
モデル同士の連携を行うアソシエーションを利用して、投稿とタグの関連付けを行い投稿にグループ分けができるようにします。

[![第12回 多対多のアソシエーション〜投稿のタグ機能の実装（フロント編）](http://img.youtube.com/vi/NarB-kZHYNE/0.jpg)](http://www.youtube.com/watch?v=NarB-kZHYNE)

[![第13回 多対多のアソシエーション〜投稿のタグ機能の実装（管理画面編）](http://img.youtube.com/vi/lL0lE8B7nBQ/0.jpg)](http://www.youtube.com/watch?v=lL0lE8B7nBQ)
掃除スケジュール管理をkintoneで作ってみた

#1.お題：掃除のスケジュール管理
お掃除は「いつ」「何を」「どのように」「どこまで」「誰が」やるかの認識相違でトラブルになりやすい
なのでkintoneでスケジュール管理を作ってみました

#2.材料：この二つを準備
- お掃除マスタ：「何を」「どのように」「どこまで」「誰が」やるかはこちらに記述
- お掃除スケジュール：「いつ」やるかはこちらに記述（マスタ情報をルックアップにしておく）

#3.組み立て
お掃除マスタ側のアクションでお掃除スケジュールにコピペして「いつ」情報を付ける
お掃除スケジュール側のプロセス管理でステータス情報を付ける
カレンダー表示の一覧を作って完成

#4.工夫：スケジュール作成を楽に
アプリを分けたのでスケジュールを作成する時に二つの間を行ったり来たりするのがメンドクサイ…
という訳で一工夫
マスタとスケジュール双方の一覧からボタンで飛べるようにしました
ベースとして使ったのはcybozu developer networkのチュートリアルよりこちら
 > [第2回 レコード一覧画面にボタンを置いてみよう！
](https://developer.cybozu.io/hc/ja/articles/201767270-%E7%AC%AC2%E5%9B%9E-%E3%83%AC%E3%82%B3%E3%83%BC%E3%83%89%E4%B8%80%E8%A6%A7%E7%94%BB%E9%9D%A2%E3%81%AB%E3%83%9C%E3%82%BF%E3%83%B3%E3%82%92%E7%BD%AE%E3%81%84%E3%81%A6%E3%81%BF%E3%82%88%E3%81%86-)

```ruby:
(function() {
    "use strict";
    kintone.events.on('app.record.index.show', function(event) {
        if (document.getElementById('my_index_button') !== null) {
            return;
        }

        var myIndexButton = document.createElement('button');
        myIndexButton.id = 'my_index_button';
        myIndexButton.innerText = 'お掃除マスタへ';

        // ボタンクリック時の処理
        myIndexButton.onclick = function() {
            location.href="URL";
        };

        kintone.app.getHeaderMenuSpaceElement().appendChild(myIndexButton);
    });
})();
```

インナーテキストとボタンクリック時の処理を変更
ボタンクリック時に他方の一覧へ遷移するためにlocation.href="URL"に差し替えました
これでスケジュール作成もすいすい
[Rails]No route matches [GET] "/users/sign_out”の対処法

## はじめに
ログアウトを実行するとルーティングエラーが発生したのでアウトプット

## 環境
Rails 5.0.7.2
ruby 2.5.1
devise

## 問題点
deviseのアカウント編集機能を実装し、ログアウトをリクエストすると、
**No route matches [GET] "/users/sign_out”**とエラー発生

## 原因
sign_out時のメソッドが**DELETE**から**GET**に変更されているので（いつなったのかは把握できていない）、変更すれば解決しそう。

## 対処方法
config/initializers/devise.rbを編集▼

```devise.rb
#省略
  config.sign_out_via = :delete
#省略
```

上記の記述を**get**に変更▼

```devise.rb
#省略
  config.sign_out_via = :get
#省略
```

サーバーを再起動して、**rake routes**をターミナルにて実行すると▼

```
 destroy_user_session GET    /users/sign_out(.:format)      devise/sessions#destroy
```

**get**メソッドに変化しているので再度ログアウトを実行すると想定通りの動作をするはず！
参考にしてください！
EC2へのssh接続コマンドを短縮したい(エイリアス、関数)

#sshコマンドが地味に長い

MacのターミナルからAWS EC2に接続する際にsshコマンドを打ちますが、
毎回このコマンドを全部打つのが面倒に感じることはないでしょうか？
ちなみに、sshコマンドは以下のような書き方になります。
(Amazon Linux2に接続する場合）

```
$ ssh -i < キーペアのパス > ec2-user@< EC2のipアドレス >
```


なので今回は、以下のようにコマンドを短縮していきたいと思います。
#####短縮版sshコマンド

```
$ sshec2 < EC2のipアドレス >
```

だいぶ短くなりましたね！
接続したいEC2のIPアドレスを調べて、「sshec2」の後にスペースを入れてコピペするだけで
接続できるようになります。
※この「sshec2」は任意のコマンド名になりますので、ご自身で自由に設定できます
※使用するキーペアは固定化されます

#コマンド短縮の設定方法

ホームディレクトリにある、「.bashrcファイル」を編集して、関数を追加します。
エイリアスじゃダメなの？と思う方もいるかもしれませんが、実は関数でないと不具合が発生してしまいます。
理由は後ほどご説明します。

```
$ vi ~/.bashrc
```

.bashrcをvimエディタで開いたら、以下のコードを記述します。

```

function sshec2() {
  command ssh -i < キーペアのパス > ec2-user@$1
}
```
※関数名は「sshec2」でなくても、任意で設定できます

コードを追加したら、ファイルを保存して閉じ、
以下のコマンドで設定を反映させます。

```
$ source ~/.bashrc
```
これで設定は完了です！
sshec2のコマンドでssh接続ができるようになります。

###おまけ）エイリアスで設定できない理由

もし以下のようにエイリアスを作成してみるとどうなるでしょうか？

```
alias sshec2='ssh -i < キーペアのパス > ec2-user@$1'
```
エイリアスでコマンドを打ってみます。

```
$ sshec2 < キーペアのパス >
```
するとエラーが発生してしまします。

原因として、エイリアスの場合
以下のように@と引数の間にスペースが入ってしまうからなのでした。

```
                                    //引数($1)
$ ssh -i < キーペアのパス > ec2-user@  < EC2のipアドレス >
　　　　　　　　　　　　　　　　　　　　 ↑
```

<br>
【参考サイト】
[bashで引数つきのエイリアスを設定する](https://hacknote.jp/archives/8043/)
【jQuery】スクロールでテキスト出現させる

#サンプル
![BAbbLhb6bO68,6568,688,85.8,5.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536974/4fae88cd-dbe3-eb44-44d6-3d1a0ee704f8.gif)

#コード
```sample.html
  <div class = "p-about-letter">
    <p class = "p-about-letter__word">ああああああああああああああああああああああああ</p>
    <p class = "p-about-letter__word">ああああああああああああああああああああああああ</p>
    <p class = "p-about-letter__word">ああああああああああああああああああああああああ</p>
    <p class = "p-about-letter__word">ああああああああああああああああああああああああ</p>
    <p class = "p-about-letter__word">ああああああああああああああああああああああああ</p>
    <p class = "p-about-letter__word">ああああああああああああああああああああああああ</p>
  </div>
```

```sample.css
.p-about-letter__word {
  opacity : 0;
  transform : translate(0, 100px); /* translate(X方向の距離, Y方向の距離) */
  transition : all 0.5s;
}

.text_visible{
  opacity : 1;
  transform : translate(0, 0);
}
```

・```.text_visible```：jQuelyのaddClassで後でクラス付加する。

```sample.js
  $(function(){
    $(window).scroll(function (){
      $('.p-about-letter__word').each(function(){
        var textPosition = $(this).offset().top;
        var scroll = $(window).scrollTop();
        var windowHeight = $(window).height();
        if (scroll > textPosition - windowHeight + 100){
          $(this).addClass('text_visible');
        }
      });
    });
  });
```

#jQueryのコードの説明

###①スクロール後の処理
```sample.js
$(window).scroll(function () {
  //処理
});
```

「windowがスクロールされたら以下の処理を実行する」

###②要素ごとの処理
```sample.js
$('.p-about-letter__word').each(function(){
  //処理
});
```

・```.p-about-letter__word```がついた要素一つ一つに処理を行うことを指定する。

※class名では無く、id指定ではこの処理は行えない。

###③ポジションの所得

```sample.js
var textPosition = $(this).offset().top;
```

・```offset().top```：windowの最上部から、```.p-about-letter__word```のついたクラスまでの距離。

###④スクロール位置の所得

```sample.js
var scroll = $(window).scrollTop();
```

・```jQueryオブジェクト.scrollTop();```：オブジェクトからのスクロール位置を所得。
・```$(window).scrollTop()```：windowでブラウザ全体のスクロール位置を取得

###⑤ウィンドウの高さ取得

```sample.js
var windowHeight = $(window).height();
```

見たまんま、ウィンドウの高さを取得

###⑥addClassを行う位置の指定

```sample.js
if (scroll > textPosition - windowHeight + 100){
   $(this).addClass('text_visible');
}
```

最後に、```scroll > textPosition - windowHeight```は、
スクロール量  > 「ページトップ〜指定要素の距離」-「ウィンドウの高さ」
を表している。

そして、``` + 100```で高さの調節をしています。


#参考記事
[スクロールして可視範囲に入ったら要素を表示するアニメーション【jQuery】](https://linkage-design.net/jquery-scroll-fadein)
rails s すると Could not find a JavaScript runtime

#問題
`rails s` を実行すると

```
/Users/username/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/execjs-2.7.0/lib/execjs/runtimes.rb:58:in `autodetect': 
Could not find a JavaScript runtime.
https://github.com/rails/execjs for a list of available runtimes.
```

となり、実行できない

rubyからjavascriptを呼び出せていない

#解決
Gemfileにある

```ruby
# gem 'therubyracer', platforms: :ruby
```

のコメントアウトを解除する。

`therubyracer`はjavascriptのv8エンジンを使用して、javascriptを有効にできるGem
[therubyracer参考](http://kz-engineer-scrap.hatenablog.com/entry/2016/05/10/005411)
[v8エンジン参考](https://ja.wikipedia.org/wiki/V8_(JavaScript%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%B3))
だからパスワードを定期的に変えないほうがいいとあれほど。。。

#やりたいこと

「パスワードって昔は定期的に変えたほうがいいって言ってたよね」
「今は変えなくていいというけどほんとに大丈夫？」

をはっきりさせる。

#前提

###パスワードポリシー
- 4文字固定(短いですね。。でもここは本質ではないので！)
- 小文字と数字のみ（つまり３６文字）
- アカウントロックアウトはない（攻撃者の試行回数は無制限）

###攻撃者
- 全パターンを片っ端から施行（BF：ブルートフォース）
- 一周して見つからなかったら最初から
    - 見つかるまで繰り返す

###ユーザーA（パスワード変えないマン）
- 初期パスワードをランダムに生成

###ユーザーB（パスワードを定期的に変えるマン）
- 初期パスワードをランダムに生成
- 攻撃者が1000回施行するごとにパスワードをランダムに再生成

### やってみよう

コードはこんな感じ

```js

const chars = "0123456789abcdefghijklmnopqrstuvwxyz".split("");
const next = (str) =>  {
  if(!str) return '0000';
  let newStr = str;
  for(let i = str.length-1; i >= 0; i--) {
    const c = str[i];
    if(c == chars[chars.length-1]) {
      newStr = newStr.slice(0,i) + chars[0] + newStr.slice(i+1);
    } else {
      newStr = newStr.slice(0,i) + chars[chars.indexOf(c)+1] + newStr.slice(i+1);
      return newStr;
    }
  }
  return null;
}
const creatPass = (len) => {
  const array = [];
  for(let i = 0; i < len; i++){
    array.push(chars[ Math.floor( Math.random() * chars.length)]);
  }
  return array.join("");

}
/* パスワード変えないマンの場合　*/
const tryDo =() => {
    const pass = creatPass(5);
    let tryString = null;
    let tryNum = 0;

    while(true) {
      tryNum++;
      tryString = next(tryString);
      if(tryString == pass) {
        return tryNum;
      }
    }
}

/* パスワードが見つかるまでの試行回数の平均(N=3000)を出す */
const NUM = 1000;
let sum = 0;
for(let i = 0; i<=NUM; i++) {
  const res = tryDo();
  sum += res;
}
/* 結果 */
console.log(sum/NUM);


```


#結果

|      |平均試行回数(N=3000)    |
|:-----------------|:------------------:|
| パスワードを変えない場合            |851494.327|
| パスワードを定期的に変えた場合|       1694579.233|

###約二倍
#なぜ定期変更は不要なの？
- ブルートフォースによるパスワードクラックにおいて、2倍程度の試行回数であることは"十分な攻撃困難性"を保証できない
- 定期変更させるとユーザーの記憶コストが上がり以下のことが起こる可能性がある
    - 安易なパスワードをつける
    - 連番でパスワードをつける(Password1 → Password2 →　Password3)
    - 付箋等で書いたものをPCなどに張り付けている

#でも・・・
###パスワードの定期変更って、漏洩したときの対策でしょ？
一般的にはそうですが、漏洩した場合はすぐ施行される可能性があるので、数か月に１度のパスワード変更がどれぐらい効果があるのか・・・
また、現在は昔ほど生のパスワードが漏洩することは考えにくく、パスワード漏洩からの不正ログインは攻撃者にとって現実的ではない。（場合による)

###まだまだ定期変更をポリシーにしてるサービスあるよね

あります。これには

- ビジネス上の理由（顧客からの要求など。とくにBtoB)

なども理由としてはあると思います。

#結局
定期変更によりランダムな文字列を高頻度で変えればクラック成功までに試行回数を増やすことはできたが、
ほとんどの利用者はランダムな文字列にしているわけではなく、攻撃者はより効率的なアルゴリズムを用いてクラックしてきます。
例えば、辞書攻撃などは、攻撃対象の情報（名前、ペットの名前、誕生日、車の番号など）を組み込んだリストの組み合わせを行うものもあります。
また、安易な類似文字変換（o →　0, s→$ など）も行うツールもあります(John the Ripperなど）
なので、"セキュリティ強化"のためのパスワード定期変更の強制は不要だと思っています。

#一般的な対策

- 安易なパスワードをつけさせない
    - DropBoxが出してるパスワード強度チェックOSS
        - https://github.com/dropbox/zxcvbn
- ハッシュ時にソルトをつける
    - パスワードを使いまわすユーザーにおいては、他サービスへの被害拡大を防ぐのも重要です
- パスワードは文字種を増やすより文字数を長くする
    - BFに対して数学的に安全です。
    - 最近では複数の単語をハイフンつなぎで繋げたパスワードが良いとされています。
        - 例:soccer-daihuku-apple など(6単語ぐらいを目安）
        - 日本語の単語を入れるといいらしいが、まあ小手先の対策だと思います。複雑さより長さのほうが大切
【Git】自分のアカウントだけでプルリクの練習をしてみよう(pull request)

#はじめに
Pull Requestについて「プルリクを送る相手側のアカウントも必要」だと思っていませんか？
__プルリクは自分のGitHubのアカウントだけで手軽に行なえます。__
5分程度で終わるので「プルリクが分からないから怖い」という方は是非やってみて下さい。

##対象ユーザ
- gitを始めてばかりの人
- はじめてPull Requestをする/したい人
- 仕事やインターンでする必要が出た人
- その他、gitを使っている人など

#準備
Githubのアカウントがなければできないので[こちら](https://github.com)から作成してください。
gitの導入などは他サイトを参照してください。

##リポジトリを作成する
https://github.com/[ユーザー名]?tab=repositories
から右上のNEWを押下。
Create a new poresitory で新しくリポジトリを生成します。
__この時、Initialize this repository with README にチェックを入れて下さい。__
__今回はこれを編集して「自分で自分にプルリクを送って、自分で承認してマージする」という手順を踏みます。__
![pullreq_6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317812/493fa695-cc36-3fc8-55c4-3fe12bd6f329.png)

自分のリポジトリに「自分のユーザ名/[自分できめた名前。ここではAtCoder]」というリポジトリができたと思います。

以下、スクショに従ってやっていきます。

##1.README．MDの編集
README.mdの編集[鉛筆マーク]をクリック
![pullreq_7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317812/8bc8e07e-f581-044e-02d8-4d745b2d8a77.png)

##2.編集を保存してプルリク用のブランチを生成
README.mdの中身を編集して、Commit directory to the master branch.の方ではなく
__Create a new branch for this commit and start pull request.のラジオボタンをチェック。__
__ここで[ユーザー名]-patch-1というbranchが生成されます。__
Propose changes を押下。
![pullreq_0-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317812/4c2196aa-6fe1-56e9-37a7-8584b685f45d.png)

##3.自分宛てにプルリクエストを生成
マスターブランチに対して、
base:master ← compare:[ユーザー名]-patch-1
というブランチの内容を送るから、確認してマージして下さい～という依頼を生成します。
適切なタイトルと詳細を書いた後、Create pull requestボタンを押下。
※変更点は下部に書いてあります。
![pullreq_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317812/571666f7-99e2-a8b7-e99b-56bda8919f5e.png)

##4.相手からプルリクが送られてきました。
__相手からプルリクエストが送られてきた画面__に遷移します。
上のタブを見ると、Pull requests 1 となっているのが分かりますね。
This branch has no conflicts with the base branch.となっているので、
今回は直接マージしても問題ありませんよ、と言う意味になります。
Merge pull requestを押下。
![pullreq_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317812/901c3847-dcd5-3801-c9a4-9d526a1c6d5b.png)

##5.相手のプルリクの内容を確認してマージの確認
プルリクしてきた相手の内容を確認して、現在のリポジトリに変更点があるbranchをマージするかどうか判断します。
今回は自分でやっていて問題ありませんのでConfirm Mergeを押下。
![pullreq_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317812/6d6c06f8-34b5-5d4b-3688-cad6a09b2910.png)

##6.相手のプルリクを承認してリクエストを取り込んでマージ成功
これで、相手からリクエストが来たマージが成功した画面に遷移します。
Pull request successfully merged and closed の右側に Delete branch ボタンがあります。
今回は相手のbranchを残す必要がないのでDelete branchを押下。
![pullreq_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317812/e5949d5c-6b07-4329-d185-9921ff74c909.png)

##7.完了
README．MDが新たに変更されているのが分かります。これで
・相手にプルリクを送る
・相手から来たプルリクを承認してマージする
双方の作業が完了しました！
![pullreq_5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317812/f8686da0-92cd-6fb4-8df5-5d1f7f6f0988.png)

# おわりに
何か改善点などあればコメントにてご教授お願いします！
Ruby on Rails seeds.rbファイルを使って、コマンド1つでレコードを大量作成

# seeds.rbとは？
app/db ディレクトリにあるファイルで、レコードの作成に使うファイル。

レコードを作成する際に手作業で1つ1つデータを登録しなくても、
seeds.rbを使用すると大量のレコードをコマンド1つで作成することができる。
# seeds.rbを使用したレコード作成方法
1. seeds.rb ファイルにレコード作成の処理を記述
2. rails db:seed を実行
3. seeds.rb ファイルの処理が実行される

## 例：usersテーブルに100人分の名前とメールアドレスを登録
app/db/seeds.rb に以下のように記述し、

```ruby:seeds.rb 
100.times do |n|
  User.create(name: "name#{n}", email: "mail#{n}@gmail.com")
end
```

**rails db:seed** を実行すると、
users テーブルには name, email の値がそれぞれ

"name0, mail0@gmail.com", 
"name1, mail1@gmail.com",
・
・
・
"name99, mail99@gmail.com"

のようにレコードが100件登録される。
WordPressでオリジナルテーマを作ろう #5: フッターの作成

![wordpress.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665011/05107c40-8525-2b07-a052-09fd731541f6.png)

[前回](https://qiita.com/takahashitakuya031126/items/6fb95302f9c9dafa477b)の続きです。

####フッター要素の追加

管理画面＞外観＞メニューに進み、フッター用のメニューを作成します。

フッターナビゲーションにチェックを入れてください。

![img1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665011/75ac7679-4583-31be-f32e-a7cfb972be89.png)

次にfooter.phpにコードを追加します。

```PHP:footer.php
<footer id="footer" class="footer">
    <div class="footer-inner">
        <!--ここから-->
        <div class="footer-nav-wrap">
            <?php wp_nav_menu( array(
                'theme_location' => 'footer-nav',
                'container' => 'nav',
                'container_class' => 'footer-nav',
                'container_id' => 'footer-nav',
                'fallback_cb' => ''
            ) ); ?>
        </div>

        <div class="copyright">
            <p>&copy; 2020 <?php bloginfo( 'name' ); ?></p>
        </div>
        <!--ここまで-->
    </div>
</footer>
<?php wp_footer(); ?>
</body>
</html>
```

ブラウザを確認します。

![img2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665011/fb29c9b1-f2d4-1528-6fe9-3cd75f53c19b.png)

きちんと表示できたら、次はデザインを整えていきます。

####デザインの調整

まず、レイアウト確認用に記述した部分を削除します。

```CSS:style.css
footer {
  background-color: #777;
}
.footer-inner{
  background-color: #ddd;
  height: 250px;
}
```

次にPC用のデザインをstyle.cssに記述します。

```CSS:style.css
.footer {
  background-color: #007bff;
}

.footer-nav,
.copyright {
  text-align: center;
}

.footer-nav {
  font-size: 0;
  margin-bottom: 3rem;
}

.footer-nav li {
  font-size: 1rem;
  display: inline-block;
  margin-right: 1.5rem;
}

.footer-nav li a {
  text-decoration: none;
  color: #fff;
}

.footer-nav li a:hover {
  opacity: .6;
}

.copyright p {
  font-size: 1rem;
  color: #fff;
}
```

ブラウザを更新します。（更新しても変化がない場合は、デベロッパーツールを開いた状態でリロードボタンを右クリックし、「キャッシュの消去とハード再読み込み」をクリックしてください）

![img3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665011/523e508e-42b4-45a9-5eba-40c7ddc2a194.png)

上のような画面が表示されれば、PC用のデザインは出来上がりです。

同じように、タブレット用とスマートフォン用のデザインも記述していきます。

```CSS:style.css
// @media(max-width: 600px)内に追記
.footer-nav {
  margin-bottom: 1.5rem;
}

.footer-nav ul {
  text-align: left;
}

.footer-nav li {
  width: 48%;
  margin-right: 4%;
  margin-bottom: 1rem;
}

.footer-nav li:nth-of-type(2n) {
  margin-right: 0;
}
```

タブレットやスマートフォンでは、メニューが横2列で並ぶようにしました。

![img4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665011/9a864c01-d727-ebc5-d43d-565510bc9d86.png)

以上でフッターの作成は完了です。

次回はサイドバーを作成していきます。

[WordPressでオリジナルテーマを作ろう #6: サイドバーの作成](https://qiita.com/takahashitakuya031126/items/60a2425cd7408dab6d59)
SNSでサイトを共有するとクリックしたくなるような画像がでてくるアレ

# なんのこと？？
コレです。
サイトのURLを共有したとき、クリックしたくなるような画像が貼られているコレです。

<img width="590" alt="ogp.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520523/8634cb3b-2a76-d85a-c3ba-b6ae7e3c633d.png">

(この記事読むより実際に[コード](https://github.com/taiga248/TwitterCard)見た方が早いかもしれない。。)

# 背景
- 記事をSNSで共有した
- 冗長なURLの文字列情報だけ並んでいるものと、画像付のものがあることに気が付いた
- なんでだ？ 調べる => OGPという存在を知った
- 当たり前にSNSライフに溶け込んでいたので意識すらしていなかった技術

OGP : 上の画像の様に、SNS共有の見栄えを良くするもの

# やること

- 画像の用意
- metaタグの挿入
- 動作確認(今回はTwitterのみ)

## 画像の用意
とりあえずはなんでも良いです
サイズ等はアイキャッチ画像が表示ができてからにしましょう

パス指定では画像を表示できないので、ネット上に置いておかなければいけません
それを参照するようにして表示します
今回はGitHub上に置いてあるものを参照しています

この[サイト](https://picsum.photos)のを使っても良いかも
## metaタグの挿入
HTMLのheadタグの中に下記のコードを追加します
表示される情報を書きます。

```html
<head>
   ...
  <meta name="twitter:card" content="summary_large_image" />  
  <meta name="twitter:title" content="Twitter Card Test" /> 
  <meta name="twitter:description" content="タイトルの下に出てくる文章" />
  <meta name="twitter:image" content="https://raw.githubusercontent.com/taiga248/TwitterCard/master/img/knowder.png" />
   ...
</head>
```

１つ目のmetaタグは表示される画像の大きさを指定します。

- summary
- summary_large_image
- app 
- player 

と言った種類がある。


## 動作確認
[このサイト](https://cards-dev.twitter.com/validator)でURLを入力すると、どのように表示されるかを確認できます

<img width="1017" alt="ogp-demo.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520523/35c14218-95a7-6a27-b54d-55b2f781fcce.png">


*localhost*では確認できないのでサイトが公開されている必要アリ(多分)
公開していない場合はngrokでトンネリングして確認するといけるかも

今回はGitHubPagesで公開されているサイトに導入しました

#おわり

[コード例](https://github.com/taiga248/TwitterCard)
windowsでiverilog その56

#概要

windowsでiverilogやってみた。
polyphonyで浮動小数点やってみる。
sigmoid関数書いてみた。

#計算手順

①符号、指数、仮数に分ける。
②指数部から、整数化の指数を求める。
③仮数に掛ける。（２進数のシフト）
④テーブルから引く。
⑤32bitで返す。

#サンプルコード


```
import polyphony
from polyphony import testbench, module, is_worker_running
from polyphony.io import Port
from polyphony.typing import bit, bit32, bit23, bit24, bit25

@module
class sigmoid:
	def __init__(self):
		self.a = Port(bit32, 'in')
		self.b = Port(bit32, 'in')
		self.c = Port(bit32, 'out')
		self.t = [
			0x3d29ac09,
			0x3d4f341f,
			0x3d7c80d6,
			0x3d997663,
			0x3db9f86f,
			0x3de08c65,
			0x3e06fc01,
			0x3e217985,
			0x3e400a67,
			0x3e62dee1,
			0x3e84ffbc,
			0x3e9aa0af,
			0x3eb21ee3,
			0x3ecb2768,
			0x3ee54a10,
			0x3f000000,
			0x3f0d5af8,
			0x3f1a6c4c,
			0x3f26f08e,
			0x3f32afa8,
			0x3f3d8022,
			0x3f474848,
			0x3f4ffd66,
			0x3f57a19f,
			0x3f5e4100,
			0x3f63ee73,
			0x3f68c0f2,
			0x3f6cd134,
			0x3f7037f3,
			0x3f730cbe,
			0x3f75653f
		]
		self.append_worker(self.worker)
	def float2b(self, a:bit32):
		a_sig:bit = (a >> 31) & 0x1
		a_exp:bit8 = (a >> 23) & 0xff
		a_fra:bit24 = a & 0x7fffff | 0x800000
		return (a_sig, a_exp, a_fra)
	def b2float(self, a_sig:bit32, a_exp:bit32, a_fra:bit32):
		return (a_sig << 31) | (a_exp << 23) | a_fra
	def worker(self):
		while is_worker_running():
			b0:bit32 = self.b.rd()
			(b_sig, b_exp, b_fra) = self.float2b(b0)
			b_exp = 127 - b_exp + 23
			b_exp = b_exp & 0xff
			frac:bit48 = b_fra
			frac = frac >> b_exp
			frac = frac & 0xffffff
			if (frac < 31):
				frac = self.t[frac]
			c0:bit32 = frac
			self.c(c0)

m = sigmoid()

@testbench
def test(m):
	m.b.wr(0x3f800000)
	print ("1.0")
	c = m.c.rd()
	print('{:08x}'.format(c))
	m.b.wr(0x40800000)
	print ("4.0")
	c = m.c.rd()
	print('{:08x}'.format(c))

test(m)





```

#実行結果


```

1.0
3d4f341f
4.0
3db9f86f

```


以上。
gitlab-ciで無料枠で効率的にci する技３つ (無料枠消費を減らす工夫)

# 概要

[GitLab CI](https://docs.gitlab.com/ee/ci/) は大変便利。高機能。
2,000分/月もの無料枠がある。

だが、2,000分もあっても、愚直に組むと、意外とあっさり超えてしまう。

１回あたりのレスポンスを早める記事はいろいろ見かけたが、実行時間を短くする記事はあまりなかったので書くことに。

# 今回 GitLab CI でやること/やらないこと

やること: lint, test
やらないこと: deploy, 生成物の artifact 化

# GitLab CI を使う上での注意点

- **無料枠** は **アカウント単位** である (リポジトリごとじゃない)

# 技1: Docker Image は alpine を使う

apline は余分な機能をそぎ落とした最小の Docker Image。
たとえば、下記を

```yaml:約40秒かかる
image: node:12.18.2
```

を下記に書き換えることで apline を使える。

```yaml:約15秒かかる
image: node:12.18.2-alpine
```

これだけで１コンテナあたり 25 秒も節約できる！

# 技2: Job(コンテナ)を分けない

これは一般的なベストプラクティスとは逆行している。

Job(コンテナ)を分けるのは並列させて **待ち時間を短縮** するためだが、その分 **無料枠は消費** される。

コンテナ起動してキャッシュを読み込むとそれだけで１回あたり、30秒～60秒くらい消費する。
Jobを複数並列で起動する場合は、それごとにかかる。

なので、無料枠を考えると、Job１つでやったほうが効率的なのである。
Job１つならキャッシュ保存/読込のオーバーヘッドも要らない。

# 技3: lint と test を両方必ず走らせたい

通常、どちらかが失敗すると、その場で Job は終了してしまう。
なので、`script` に複数並べても、両方のエラー常に出力できない。

そこで下記のようにする。

```yaml
script:
  # && true をつけることで強制終了しなくなる。
  # これは -e は条件式の場合、最後の句がエラーだった場合に強制終了する仕様だが、
  # 差分アリの場合、ショートサーキットで最後(true)が実行されないためである。
  # 差分ナシの場合は、true (結局何もしない) が実行される。
  # &? は同じ行にないと正しく取れないので注意
  - 'npm run lint && true; EXIT1=&?'
  - 'npm run test && true; EXIT2=&?'
  # まとめてエラー判定 (実は exit 1 は無くても同様に動くが、可読性のため)
  - 'echo EXIT1=[${EXIT1}], EXIT2=[${EXIT2}]'
  - '[ "${EXIT1}" -eq 0 -a "${EXIT2}" -eq 0 ] || exit 1'
```

# .gitlab-ci 全体

```yaml
image: node:12.18.2-alpine

workflow:
  rules:
    # マージリクエストで起動
    - if: $CI_MERGE_REQUEST_ID

stages:
  - test

test:
  stage: test
  before_script:
    # package.json が変わったときに備えて ci で行う
    - time npm ci
  script:
    # サーバ起動のオーバーヘッドを減らすため lint と test を同じインスタンスでやる
    # && true をつけることで強制終了しなくなる。
    # これは -e は条件式の場合、最後の句がエラーだった場合に強制終了する仕様だが、
    # 差分アリの場合、ショートサーキットで最後(true)が実行されないためである。
    # 差分ナシの場合は、true (結局何もしない) が実行される。
    # &? は同じ行にないと正しく取れないので注意
    - 'time npm run lint && true; EXIT1=&?'
    - 'time npx rub test && true; EXIT2=&?'
    # 条件句が偽の場合もまた終了コード1をもたらすので注意(必ずPASSを真として判定する必要あり)
    - 'echo EXIT1=[${EXIT1}], EXIT2=[${EXIT2}]'
    - '[ "${EXIT1}" -eq 0 -a "${EXIT2}" -eq 0 ] || exit 1'
```


# 参考

- [Bashメモ](https://qiita.com/waterada/items/406c6c55b77249f56778)
windowsでiverilog その55

#概要

windowsでiverilogやってみた。
polyphonyで浮動小数点やってみる。
tanh関数書いてみた。

#計算手順

①符号、指数、仮数に分ける。
②指数部から、整数化の指数を求める。
③仮数に掛ける。（２進数のシフト）
④テーブルから引く。
⑤32bitで返す。

#サンプルコード


```
import polyphony
from polyphony import testbench, module, is_worker_running
from polyphony.io import Port
from polyphony.typing import bit, bit32, bit23, bit24, bit25

@module
class tanh:
	def __init__(self):
		self.a = Port(bit32, 'in')
		self.b = Port(bit32, 'in')
		self.c = Port(bit32, 'out')
		self.t = [
			0xbf7f0bb0,
			0xbf7e8cf1,
			0xbf7dccba,
			0xbf7ca996,
			0xbf7af177,
			0xbf785a09,
			0xbf747658,
			0xbf6ea9b9,
			0xbf66197c,
			0xbf59a267,
			0xbf47dce7,
			0xbf2f433d,
			0xbf0e908f,
			0xbecabea1,
			0xbe536260,
			0xa6000000,
			0x3e536260,
			0x3ecabea1,
			0x3f0e908f,
			0x3f2f433d,
			0x3f47dce7,
			0x3f59a267,
			0x3f66197c,
			0x3f6ea9b9,
			0x3f747658,
			0x3f785a09,
			0x3f7af177,
			0x3f7ca996,
			0x3f7dccba,
			0x3f7e8cf1,
			0x3f7f0bb0
		]
		self.append_worker(self.worker)
	def float2b(self, a:bit32):
		a_sig:bit = (a >> 31) & 0x1
		a_exp:bit8 = (a >> 23) & 0xff
		a_fra:bit24 = a & 0x7fffff | 0x800000
		return (a_sig, a_exp, a_fra)
	def b2float(self, a_sig:bit32, a_exp:bit32, a_fra:bit32):
		return (a_sig << 31) | (a_exp << 23) | a_fra
	def worker(self):
		while is_worker_running():
			b0:bit32 = self.b.rd()
			(b_sig, b_exp, b_fra) = self.float2b(b0)
			b_exp = 127 - b_exp + 23
			b_exp = b_exp & 0xff
			frac:bit48 = b_fra
			frac = frac >> b_exp
			frac = frac & 0xffffff
			if (frac < 31):
				frac = self.t[frac]
			c0:bit32 = frac
			self.c(c0)

m = tanh()

@testbench
def test(m):
	m.b.wr(0x3f800000)
	print ("1.0")
	c = m.c.rd()
	print('{:08x}'.format(c))
	m.b.wr(0x40800000)
	print ("4.0")
	c = m.c.rd()
	print('{:08x}'.format(c))

test(m)





```

#python実行結果


```


1.0
bf7e8cf1
4.0
bf7af177


```

以上。
windowsでiverilog その54

#概要

windowsでiverilogやってみた。
polyphonyで浮動小数点やってみる。
sin関数書いてみた。

#計算手順

①符号、指数、仮数に分ける。
②指数部から、整数化の指数を求める。
③仮数に掛ける。（２進数のシフト）
④テーブルから引く。
⑤32bitで返す。

#サンプルコード


```
import polyphony
from polyphony import testbench, module, is_worker_running
from polyphony.io import Port
from polyphony.typing import bit, bit32, bit23, bit24, bit25

@module
class sin:
	def __init__(self):
		self.a = Port(bit32, 'in')
		self.b = Port(bit32, 'in')
		self.c = Port(bit32, 'out')
		self.t = [
			0x00000000,
			0x3d565e3a,
			0x3dd61305,
			0x3e20305b,
			0x3e54e6cd,
			0x3e8483ee,
			0x3e9e377a,
			0x3eb77c01,
			0x3ed03fc9,
			0x3ee87171,
			0x3f000000,
			0x3f0b6d77,
			0x3f167918,
			0x3f211b24,
			0x3f2b4c25,
			0x3f3504f3,
			0x3f3e3ebd,
			0x3f46f30a,
			0x3f4f1bbd,
			0x3f56b31d,
			0x3f5db3d7,
			0x3f641901,
			0x3f69de1d,
			0x3f6eff20,
			0x3f737871,
			0x3f7746ea,
			0x3f7a67e2,
			0x3f7cd925,
			0x3f7e98fd,
			0x3f7fa62f,
			0x3f800000
		]
		self.append_worker(self.worker)
	def float2b(self, a:bit32):
		a_sig:bit = (a >> 31) & 0x1
		a_exp:bit8 = (a >> 23) & 0xff
		a_fra:bit24 = a & 0x7fffff | 0x800000
		return (a_sig, a_exp, a_fra)
	def b2float(self, a_sig:bit32, a_exp:bit32, a_fra:bit32):
		return (a_sig << 31) | (a_exp << 23) | a_fra
	def worker(self):
		while is_worker_running():
			b0:bit32 = self.b.rd()
			(b_sig, b_exp, b_fra) = self.float2b(b0)
			b_exp = 127 - b_exp + 23
			b_exp = b_exp & 0xff
			frac:bit48 = b_fra
			frac = frac >> b_exp
			frac = frac & 0xffffff
			if (frac < 31):
				frac = self.t[frac]
			c0:bit32 = frac
			self.c(c0)

m = sin()

@testbench
def test(m):
	m.b.wr(0x3f800000)
	print ("1.0")
	c = m.c.rd()
	print('{:08x}'.format(c))
	m.b.wr(0x40800000)
	print ("4.0")
	c = m.c.rd()
	print('{:08x}'.format(c))

test(m)





```

#python実行結果


```


1.0
3d565e3a
4.0
3e54e6cd


```

以上。
Discordのテキストをローカルのきりたんに読み上げてもらう

## 概要
Discordをローカルのきりたんに読み上げて欲しいのでbotを作りました。
東北きりたん＋SeikaCenter＋このbotを動作させる状態になります。
ローカルでの発声が不要なら[喋太郎](https://www.dayaman.work/syabetaro/info)botがオススメです。

## 環境
 Windows 10
 python 3.7 for windows / VOICEROID＋ 東北きりたん EX / [SeikaCenter](https://hgotoh.jp/wiki/doku.php/documents/voiceroid/seikacenter/seikacenter-001)
## 用意
1. 証明書インストール
Windowsでdiscord.pyを使うと証明書エラーが出る場合があるので
[こちらの記事](https://qiita.com/KjumanEnobikto/items/73258a94119ce8e5e3eb)を参考にDiscordの証明書をあらかじめインストールします

2. Botの登録
[Pythonで簡単なDiscord Botの作り方](https://qiita.com/PinappleHunter/items/af4ccdbb04727437477f)を参考にBotを作成して動作テストします

3. seikasayの配置
[SeikaCenter](https://hgotoh.jp/wiki/doku.php/documents/voiceroid/seikacenter/seikacenter-001)に付属のseikasay.exeを動作テスト後、botと同じ場所にコピーします

## botからSeicaCenterの呼出し、発話
botのメッセージ処理部分で以下のように発話させます。
元のきりたん音声では小さいので -volume 2.0 （最大値）にしています

```python
import subprocess

async def on_message(message):
    # メッセージ送信者がBotだった場合は無視する
    if message.author.bot:
        return
    # メッセージ送信元チャンネルが特定のチャンネルidだった場合
    # seikasayできりたんに喋らせる
    if message.channel.id == 581983733384621 :
        cmd = 'seikasay -cid 1700  -volume 2.0 -t '+ message.content
        returncode = subprocess.Popen(cmd)
```

### おまけ：ショートカット作成
コマンドプロンプトから起動するのは使い勝手が悪いので
新しいショートカットを作成して「リンク先」に
`cmd.exe /c python よみあげきりたん.py`
のように記入して作成します。
ショートカットからフォントやサイズをいじっておくと使いやすいと思います。
![imoge.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223386/93f33003-c780-8f70-0884-7fa43adab16f.png)
@nuxt/contentでmarkdownにテキスト処理をしたい

## TL;DR

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">@ nuxt/content でmarkdownに前処理したいときどうしたらいいんだろうと思ってたんですけど、ソース読んで無理なことを理解したので、ローカルremarkプラグインで強引にテキストとして前処理するってのをやりました</p>&mdash; ねぎまぐろ (@kume_negitoro) <a href="https://twitter.com/kume_negitoro/status/1282009595167178752?ref_src=twsrc%5Etfw">July 11, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## はじめに

こんにちは、ねぎまぐろです。

突然ですが最近追加された **@nuxt/content** かなりイイですよね。表示用のコンポーネントを作っておけば **markdown** ごとにページを作って表示してくれるのでとっても便利です。ですが多少不満があります。markdownに対してテキスト処理をしたい場面があると思うのですが、残念なことに **@nuxt/content** ではそういう機能は(見た感じ)付いていません。
どこかに元のファイルを置いておいて、 **gulp** か何かで処理した後に `content/` に吐き出すというのも考えましたが、せっかく **Nuxt.js** を使っているのに泥臭い感じがあまりよくありません。


## remark

しかしながら代わりに **remarkプラグイン** (とrehypeプラグイン)を使うことができます。[remark](https://github.com/remarkjs/remark)というのはmarkdownをastにして処理できるパッケージです。ということはつまり、remarkプラグインとはastに対して何か追加で処理できるパッケージということになります。
ちなみにどんなプラグインがあるのかというと、`:emoji:`みたいな[テキストをUTF-8の絵文字に置き換えてくれるプラグイン](https://github.com/rhysd/remark-emoji)などがあります。これはなかなか便利そうですね。

ですが求めているのは普通のテキスト処理です。そういうのはできないでしょうか？


## remarkプラグインを作る

よく考えてみるとremarkプラグインというのは **astを受け取ってastを返す** 関数です。それさえ満たしていればちゃんと実行してくれるはずなので、astを一度テキストに変換してしまえばテキスト処理ができますよね。
自分でプラグインを作れないでしょうか。答えはイエスです。 **@nuxt/content** ではローカルのプラグインも指定できるようになっています。

早速取り掛かってみましょう！

### 依存パッケージ

markdownのastをmarkdown文字列に変換したり、その逆をするためにはremarkをインストールします。

`$ yarn add -D remark`


### 本体を作る

インストールできたらプラグイン用のファイルを作ります。

```~/remarkPlugins/myPlugin.js
const remark = require('remark')()

const process = (text) => {
    return text.replace(/きのこ/g, 'たけのこ')
}

module.exports = () => (tree) => remark.parse(process(remark.stringify(tree)))
```

特に難しいことはしていません。`remark.stringify`はastをmarkdown文字列に変換する関数です。それに自前のprocess関数を適用して、最後に`remark.parse`でastに戻して返却する関数をexportしています。
一応、astを受け取ってastを返すというremarkプラグインの条件は満たしていますね。
markdownをastにして、そこからまたmarkdownにしたりastにしたりしているので非常に無駄な感じがしますが、この際あまり気にしないことにします。


## nuxt.config.js の設定

あとはこれをプラグインとして設定してあげれば良いですね。こんな感じで記述します。

```nuxt.config.js
{
  content: {
    markdown: {
      remarkPlugins: ['~/remarkPlugins/myPlugin.js'],
    },
  },
}
```

このあたりの設定は[公式のドキュメント](https://content.nuxtjs.org/configuration/)に載っているので、一度見ておくと良いかと思います。


## 確認してみる

ではちゃんと動くか確認してみます。次のmarkdownを表示させてみましょう(**@nuxt/content** でのmarkdownの表示方法については別の記事にお譲りします)。

```test.md
---
title: アンケート
---

# あなたはどちら派ですか？
私はどちらかというときのこが好きです。あなたはどちらが好きですか？

1. きのこ
2. たけのこ

なるほど、あなたはきのこ派ですね！
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401575/c1f0e3da-6f0c-b51d-31f8-9acc8056cc73.png)


無事成功しました！


## 終わりに

今回は **@nuxt/content** で **markdown** テキストに前処理をする方法を試してみました。実際のところ、これより良い方法があるかもしれませんので参考までに、ということでよろしくお願いします...。 もし良い方法があったら教えてもらえると嬉しいです。
$GOPATH/pkg/mod配下のファイルが消せない

# `$GOPATH`を変更した話

Goのインストール時に`$GOPATH`を`~/workspace/go`な感じにしたら扱いにくかったのでデフォルト`~`に戻して、元のディレクトリを`rm`しようとしたときに消せなかったのでメモ

```sh:terminal
$ echo $GOPATH #変更後
/Users/usr/go

$ rm -rf ~/workspace/go
rm: cannot remove '/Users/usr/workspace/go/pkg/mod/golang.org/x/crypto@v0.0.0-20190308221718-c2843e01d9a2/internal/subtle/aliasing.go': Permission denied
rm: cannot remove '/Users/usr/workspace/go/pkg/mod/golang.org/x/crypto@v0.0.0-20190308221718-c2843e01d9a2/internal/subtle/aliasing_test.go': Permission denied
rm: cannot remove '/Users/usr/workspace/go/pkg/mod/golang.org/x/crypto@v0.0.0-20190308221718-c2843e01d9a2/internal/subtle/aliasing_appengine.go': Permission denied
rm: cannot remove '/Users/usr/workspace/go/pkg/mod/golang.org/x/crypto@v0.0.0-20190308221718-c2843e01d9a2/internal/chacha20/chacha_s390x.s': Permission denied
[...]
```

## パーミッションがREAD_ONLY
ゴミプロセスが掴んでるのかと思ったら仕様らしい

## 解決策
`go mod`は以下で消せとのこと。

```sh:terminal
$ go clean -modcache
```

めんどくさいので`w`パーミッションつけて消しました。

```sh:terminal
$ find ~/workspace/go/pkg/mod -exec chmod u+w {} \;
$ rm -rf ~/workspace/go
```

めでたし、めでたし。

## Links
https://github.com/golang/go/issues/35615
all_month が気になって ActiveSupport DateAndTime::Calculations を読んでみた

# これ何
先輩にレビュー中に、 all_month 使った方がいいんじゃない？と言われたので、気になって調べてみた。
ActiveSupport の [DateAndTime::Calculations](https://api.rubyonrails.org/v5.1/classes/DateAndTime/Calculations.html) に定義されていたので、周りのmethodも読んでみる

# 範囲指定のmethod
all_monthの内部実装を眺めてみた。rails/railsの内部実装だが、読めるコードでわかる。

```ruby
def all_month
  beginning_of_month..end_of_month
end
```
ref: [activesupport/lib/active_support/core_ext/date_and_time/calculations.rb](https://github.com/rails/rails/blob/fc72d6815ad6ed447f1aea2dd98579305ea1cca4/activesupport/lib/active_support/core_ext/date_and_time/calculations.rb#L309)

同じファイルの中を見てみるとall_month 以外にも all_xxx methodが存在した。対象範囲が変わるだけで、使えそうなmethodが多い。

- all_day
- all_month
- all_quarter：3ヶ月ごとの日時情報が取れる
- all_week：週の開始日を決めることができる
- all_year

# 気づき 1. future?, past?
未来・過去かを判定するmethodが存在する！再定義しなくても、rails/railsであるものを使える！！気づき。

```ruby
Date.yesterday.past?
=> true
Date.yesterday.future?
=> false
Date.tomorrow.future?
=> true
Date.tomorrow.past?
=> false
```
- [past?](https://api.rubyonrails.org/v5.1/classes/DateAndTime/Calculations.html#method-i-past-3F)
- [future?](https://api.rubyonrails.org/v5.1/classes/DateAndTime/Calculations.html#method-i-past-3F)

# 気づき 2. all_xxxと同様にnext_xxx, prev_xxxも存在する

next_xxx, prev_xxx が定義されている。 prev_xxx は last_xxx にaliasされている。

```ruby
Date.current
=> Sun, 11 Jul 2020
Date.current.next_week
=> Mon, 13 Jul 2020
Date.current.prev_week
=> Mon, 29 Jun 2020
Date.current.last_week
=> Mon, 29 Jun 2020
```

# 参考文献
- [DateAndTime::Calculations](https://api.rubyonrails.org/v5.1/classes/DateAndTime/Calculations.html)
- [【知らずに損した】ActiveSupportの期間指定メソッドall_day, all_week, all_month, all_year](https://qiita.com/terufumi1122/items/3aa21c20eeacbce33b93)
- [ActiveSupportで時間や日付を簡単に表現する](https://qiita.com/toyoshi/items/f41f9a37e7f5a1cc50d5)
データローダでコンテンツアップロードするときはバッチサイズ設定をしよう


初心者:hatching_chick:のころの下書きが残っていた…。

というわけで、`データローダつまづき日記`と思ってください。
（解説ではなく失敗談的な）

やろうとしたのは、万単位の画像ファイルをコンテンツとしてデータローダでUPすること。
というのもAというAppExchengeからBというAppExchangeへデータ移行をしたくて
Aのレコードに紐づいていた画像は添付ファイルだったのですが
Bのレコードで受け付けている形式はコンテンツでした…と。
よって、一度エクスポートしたデータの再Insertを試みました。

##バッチサイズは分割しよう

~~若気の至りといいますか、~~
まずは何も考えずにN千件の画像をデータローダで上げようとしまして。

 >データローダを使用したコンテンツのアップロード 
 https://help.salesforce.com/articleView?id=loader_content.htm&type=5

ちゃんとヘルプ記載通りにCSVも作ったし、
試しに1件アップして問題なさそうだなーというところで
いざ本番:arrow_forward:

・・・のっけから、JavaHeapエラーでつまづく
Failed Create Batchも出る。
「そりゃ重いよネー」ということでCSVファイル分割。
半分にして、
半分にして、
半分にして、
1000件まで分割するも、まだまだ同じエラー。

やってられん！

と、おもったら設定でそもそもバッチサイズが分割できると知しました。
アホですね…。よいこはマネしないように:no_good_tone1:

 >【SFDC】DataLoaderを使っているときに heap space エラーが出る場合の対処 
http://rulumomo.ddo.jp/blognplus/archives/1859#1DataLoader

Settingで100まで落としてリベンジ

250件くらい中途半端に入ったとところで、行ロックでこける。
`UNABLE_TO_LOCK_ROW:unable to obtain exclusive access to this record or 1 records`

なぜロックする・・・

> 行をロックできない - 「レコードは現在利用できません」エラー 
https://help.salesforce.com/articleView?id=000229525&language=ja&type=1

どうもパラレル処理のせいらしい。
とはいえ、Insertなんだけど・・・
コンテンツだから親レコードとかない・・・よね？:thinking:

おそらく原因はこれ ↓

>c. Bulk API
>Bulk API を介したレコードの Insert/Update は同じ親レコード上に一度に複数の Update が生じる可能性があります。なぜなら、バッチは並列に処理されるためです。例えば、同じタイミングで 2 つのバッチが処理されており、それらが同じ親レコードを指し示すレコードを含んでいる場合、バッチのひとつは 10 秒以内にロックすることができなかった場合に、他のバッチが「unable to lock row」エラーを惹き起こす可能性のある親レコードをロックしようと試みます。


##シリアルモードを使おう
>これを防ぐために、次のいずれかを実施することができます:
バッチサイズを削減します。
パラレルモードの代わりにシリアルモードでレコードを処理します。バッチのこの方法は同時に処理されます。
パラレルモードの使用時に、異なるバッチで (同じ親の) 異なる子レコードが生じることを避けるため、親レコードに基づくメインレコードをソートします。



とりま、シリアルモードにし、バッチサイズも50にダウン。
これで時間こそかかれども、放っておくだけ・・・

と思いきや950件で止まる・・・:moyai::moyai::moyai:

エラー内容はこちら
`Not processed due to batch error: InvalidBatch : You cannot have more than 1000 file entries in your zip`

なんだとおおおおおおお
そんな制限あるなんてー！と思ってたが、
よくよく見たら、実行をクリックする前にダイアログ出てた。
（見てないだけでした）
1000行以上だとちゃんと分割考慮してどこで止まるか出してくれてますのでご安心を:sweat_smile:

999件を目指すなら3の倍数で入れるのがいいのかな笑

###おまけ
コマンドラインからアップすればBatファイルで一括アップのような動きにできます。

データローダのコマンドラインの概要
https://help.salesforce.com/articleView?id=command_line_intro.htm&type=5

データローダをバッチモードで使用する際の設定手順
https://help.salesforce.com/articleView?id=000182363&language=ja&type=1

ワンクリックであとはお任せ～♪
Elixir Ecto で bigint を使う方法（MyXQLアダプタ）

## 背景
references で外部キー設定したくないけど、bigint型にはしたいなーと思ってドキュメント探してみたら `:integer` しかない・・・！どうすれば！？
※なおMyXQLアダプタを使っています

## 方法

Ectoのドキュメントでは見つけられませんでしたが `:bigint` というアトムが使えるみたいですね
https://stackoverflow.com/questions/45400665/ecto-or-elixir-datatype-that-maps-to-mysql-bigint

```elixir
  def change do
    create table(:characters) do
      add :name, :string
      add :movie_id, :bigint
    end
  end
```

```sql
CREATE TABLE `characters` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `movie_id` bigint(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
```

## おまけ
migration で作られるsqlを出したい場合以下のコマンドで出せるので参考にどうぞ

```bash
mysqldump -uroot --compact -d データベース名 | sed -e '/\/\*/d'
```
Azure認定資格 AZ-900を取得しました

Azureの認定資格 [ロードマップ](https://query.prod.cms.rt.microsoft.com/cms/api/am/binary/RE2PjDI) のうち、[AZ-900](https://docs.microsoft.com/ja-jp/learn/certifications/exams/az-900) を取得しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180335/db59cfd7-f099-3441-1cf7-74276388ddaf.png)

私は既にAssociateやExpertの資格を持っているのですが、Azure教育をするにあたり、Associateと比較したFundamentalsの内容やレベルを把握するために受験しました。
他の資格体験も書いていますので良ければご覧ください。

* [Azure認定資格 AZ-203を取得しました](https://qiita.com/shingo_kawahara/items/551ac6b880a4a59e4291)
* [Azure認定資格 AZ-300を取得しました](https://qiita.com/shingo_kawahara/items/7d1c217e2588c5a232e3)
* [Azure認定資格 AZ-301を取得しました](https://qiita.com/shingo_kawahara/items/5e5c1febeb773a95b6af)

# 試験の傾向は？
* 問題：34問
これまで受けたAssociateやExpertの試験とは少し違って、ケーススタディは出題されませんでした。実技もなしで、1問1答のみです。
他の試験だと前のセクションに戻れなかったりしますが、Fundamentalsは全問見直しが可能でした。

* 時間：60分
申込みは90分になっていますが、そのうち30分は事前の同意書などの時間なので実際は60分です。このあたりは他の試験と同様ですね。

* 合格ライン：700点
1000点満点なのかな？今回の試験は880点で合格でした。

# 試験範囲
* クラウドの概念について説明する (15-20%)
* Azure のコアサービスについて説明する (30-35%)
* セキュリティ、プライバシー、コンプライアンス、信頼について説明する (25-30%)
* Azure の価格サービス レベル アグリーメントとライフサイクルについて説明する(20-25%)

IaaSやPaaSといった基本的なサービスもそうですが、Azure自体のセキュリティやSLAなどのほうが比率は高そうですね。

# 学習方法
Fundamental用の [Microsoft Learn](https://docs.microsoft.com/ja-jp/learn/paths/azure-fundamentals/) が用意されているのでこれを一通り理解できていれば問題なく取得できると思います。
実案件だとAzureの各種サービスを触ることはあっても、Azure自体のセキュリティやSLAや信頼性、アカウントやサブスクリプションなどは把握できていないということはあると思います。そのあたりも含めて知識として網羅できればよいのではと思います。

# まとめ
60分のうち、20分くらいで終わったので時間は余裕です。ゆっくり見直しできます。
AZ-900はAzureの入門編のような位置付けですが、Azure学習のとっかかりとしてはとてもよい試験だという印象を持ちました。
AZ-900の学習を進めることで、Azure VMやApp Serviceなどのサービス以外のAzure自体の概要が見に付くのはとてもよいです。特にパブリッククラウドは誰でもいつでも始められるので、基礎からきちんと理解しておかないと思わぬセキュリティ事故を起こしかねません。
Azureリージョンの可用性やアカウントをどう守るかといった知識を抑えて、AssociateやExpertと進んでいくのがよいですね！
C++ での NaN のメモ



# NaN のビット定義

exponential bit が全部 1 で,

qNaN : mantissa 最上位(sign ビットの方向を上位とする)のビットが 1
sNaN : mantissa 最上位のビットが 0 で, それ以外どれかの mantissa bit が立っている
(inf: mantissa ビットが全部ゼロ)

したがって sign bit も入れて 2**24 - 1 通りの何かを NaN 値に埋め込むことができる.

http://tanakahx.hatenablog.com/entry/2015/07/29/003757

NaN boxing などで使われている.

## NaN の生成

`std::numeric_limits<float>::quet_NaN()`
`std::numeric_limits<float>::signaling_NaN()`

で生成できる.

## 例外

https://en.cppreference.com/w/cpp/types/numeric_limits/signaling_NaN

qNaN は例外ビットを立てない(はず).

## std::isnan

std::isnan では sNaN か qNaN かの判定まではできない(std::fpclassify でも不可).
やるなら自前でビット演算でチェック?


## min/max 演算

_mm_min_ps/_mm_max_ps は IEEE-754-2008 の振る舞いをする

C++11 では fmin/fmax 

min/max あたりは, NaN の扱いが少し特殊なので注意しましょう.
Vue.jsのcomputedプロパティで引数を受け取る

# そもそも引数とは
プログラムや関数に渡す値のこと。値を渡すことによってその値によってif文を書いたり必要な情報をプログラム内で使用することができる。最初のうちは引数を利用することは結構少ないかも。

# HTMLからScriptに引数を渡す
### method内での引数の渡し方
ブラウザに設置されたボタンをクリックしたら`event`っていう関数が実行される文を書きました。引数には文字列を含ませてあります。

```html:html
<template>
  <div>
    <button @click="event('引数だよ！')">
    </button>
  </div>
</template>
```

文字列の引数に`value`という名前で引数の情報を受け取ります。
ちゃんと受け取れていれば`value`の中には`引数だよ！`っていう文字列が入っているはずです。

```javascript:vue.js
<script>
export default {
  methods: {
    event (value) {
      console.log(value)
    }
  }
}
</script>
```

![スクリーンショット 2020-07-12 1.31.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/518141/4032c5ae-7dcc-08fa-d1f8-c805df7ec232.png)

ボタンを押した時の結果です。ちゃんと文字列が受け取れています。

# computedプロパティないで引数を受け取る方法
methodsの時とおなじ要領でcomputed内で引数を受け取ろうとすると次の様な値が返ってきます。
この値も必要になるときは来るのですが、現段階で欲しい情報は文字列です。
![スクリーンショット 2020-07-12 1.37.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/518141/8f3a92f0-c7a7-559f-c941-58cc1ac92e6a.png)

### じゃあどうするか
computed内に記載した関数の返り値に別の関数を定義し別の関数内で引数を受け取ることによって欲しい情報を取得することができます。

```javascript:vue.js
<script>
export default {
  computed: {
    event () {
      return function (value) {
        return console.log(value)
      }
    }
  }
}
</script>
```

![スクリーンショット 2020-07-12 1.42.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/518141/f5d5c840-54c1-8837-34ff-1ed8f45bacb1.png)

この様にしてcomputed内でも欲しい引数を取得することができました。
リモートブランチを確認するために、リモートブランチにgit switchしたい

# なぜ`git switch`を使うか？
オシャレだからです

# 結論

以下コマンドを打ちます。
`origin`などのリモートブランチを指定しないのがポイントです。

```shell
$ git fetch
$ git switch feature/branch01
```


# 何をしたか

`feature/branch01`というブランチで、(例えば)GitHub上にプルリクが作られています。
そのプルリクのレビューをするために、手元(ローカル)で色々確認したいとします。

```shell
$ git fetch  #まずはリモートから取得
$ git switch origin/feature/branch01  #そのリモートブランチにswitchしたい
fatal: a branch is expected, got remote branch 'origin/feature/branch01'
```

え、何このエラー
試しに`git checkout`の方でやります

```shell
$ git checkout origin/feature/branch01
Note: switching to 'origin/feature/branch01'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:

  git switch -c <new-branch-name>

Or undo this operation with:

  git switch -

Turn off this advice by setting config variable advice.detachedHead to false
```

チェックアウトできたけど、よく見ると「`HEAD`がdetached状態だよ」と警告されてますね

参考: [detached HEAD から脱出する方法を git の内部構造から探る](https://qiita.com/Kuniwak/items/4e5d55d6888e5f6411fe)

# 調べた

そもそも、検索した限りでこの方法でリモートブランチを確認する人間はいなかったです。笑

- この方法ではリモートの`origin/feature/branch01`にあるコミットを直接参照している
- よって、トラッキングもattachもされていない
- よって、この中で例えば変更を行うと、リモートブランチへの反映は面倒
- <B>よって、普通はこの方法ではなくローカルブランチにトラッキング・attachさせる方法を使う(推測)</B>
- よって、`git switch`ではこの方法でのチェックアウトは想定されていない(推測)
- よって、エラーとなった

のようです。

それで、普通はどう行うのかというと、以下の方法です。

```shell
$ git branch feature/branch01 origin/feature/branch01  #リモートブランチからattachさせたローカルブランチを作成し、
$ git checkout feature/branch01  #そのローカルブランチにチェックアウトします(`git switch`でも可能)
```

ただ、こんな面倒なコマンドを打たないためのショートカットはいろいろあります。
下記のサイトが参考になりました。

参考: [git checkout -t でちょっと幸せになれる](https://qiita.com/tommy_aka_jps/items/6ce68f564cb3802ca9b0)

結論としては、リモートブランチを(`origin`)を指定せずに`git checkout`してしまえば良いみたいです。


# やってみた

```shell
$ git checkout master  #一回masterに戻り、
$ git branch -D feature/branch01  #前項目で作ったブランチを一度消します
$ git checkout feature/branch01  #attachされたローカルブランチを作って、さらにチェックアウトします
Updating files: 100% (123/123), done.
Branch 'feature/branch01' set up to track remote branch 'feature/branch01' from 'origin'.
Switched to a new branch 'feature/branch01'
```

できました。
ちなみに`git switch`でやっても同じ結果でした。

```shell
$ git switch master
$ git branch -D feature/branch01
$ git switch feature/branch01
Updating files: 100% (123/123), done.
Branch 'feature/branch01' set up to track remote branch 'feature/branch01' from 'origin'.
Switched to a new branch 'feature/branch01'
```

# (再度)結論

以下コマンドを打ちます。
`origin`などのリモートブランチを指定しないのがポイントです。

```shell
$ git fetch
$ git switch feature/branch01
```

## 感想

個人的には、確認したいだけなのにローカルブランチが作られるのは微妙じゃないか？と思ってます。
レビューが終わった後にいちいちローカルブランチ消すの面倒だし・・・
ご指摘お待ちしております。

## 参考

```shell
fatal: a branch is expected, got remote branch 'origin/feature/branch01'
```

このエラーで調べると下記質問が出てきました。やはり`-c`オプションでattachさせるやり方を推奨しています。
https://stackoverflow.com/questions/58124219/how-can-i-use-the-new-git-switch-syntax-to-create-a-new-branch
convert-svg-to-pngをVercel上で動かした。

convert-svg-to-pngがVercel上で動いてくれない。
=====
先日、convert-svg-to-pngを用いてOGPに対応したWebアプリを作りました。
しかしいざVercel上にデプロイしてみると、Internal Errorを吐いてしまいました…

Puppeteerからchrome-aws-lambdaを起動するようにすればおｋ
=====
どうやらVercelのServerless FunctionsはAWS Lambdaを使っているらしく、Puppeteerは標準でそれに対応していないようでした。
そのため、Lambdaに対応したChromeを入れてあげれば動くようになります。

```bash:chrome-aws-lambdaをインストール
yarn add chrome-aws-lambda
```

```typescript:ソースへ適応
import chrome from 'chrome-aws-lambda'
import { convert } from 'convert-svg-to-png'

convert('ここにSVGがはいる', {
    {
        args: chrome.args,
        executablePath: await chrome.executablePath,
        headless: chrome.headless,
    }
})
```

参考
=====
- [Vercel上でPuppeteerを動かす](https://qiita.com/n0bisuke/items/d3b45cb33351e68d9c86)
Python: アンパック代入に対応したクラスを作る

ふとアンパック代入ってどうやって実現されているんだろう、と試行錯誤してみた結果をメモしておきます。

## `__getitem__()` を実装する

```python
>>> class MyTuple:
...     def __getitem__(self, key):
...         print(key)
...         if key < 3:
...             return str(key)
...         else:
...             raise IndexError
...
```

アンパック代入には `__getitem__()` メソッドが利用されるようです [^1]。
キーとしてインデックス番号が渡されます。

[^1]: ドキュメントを探してみたのだけど、ぱっと出てこなかったので実験して調べました。

### 普通の代入の場合

`__getitem__()` は呼び出されません。

```python
>>> x = MyTuple()
>>> x
<__main__.MyTuple object at 0x10a6bd850>
```

### 要素が少ないアンパック代入の場合

左辺の要素の数 + 1 回分、`__getitem__()` が呼び出されます。
いずれの呼び出しでも `IndexError` が発生しない場合、右辺の要素が多いとみなし、`ValueError` が発生します。

```python
>>> x, y = MyTuple()
0
1
2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: too many values to unpack (expected 2)
```

### 要素の数が一致するアンパック代入の場合

左辺の要素の数 + 1 回分、`__getitem__()` が呼び出されます。
最後の呼び出しで `IndexError` が発生した場合、左辺の要素と右辺の要素が一致しているとみなし、代入が成功します。

```python
>>> x, y, z = MyTuple()
0
1
2
3
>>> x, y, z
('0', '1', '2')
```

### 要素が多いアンパック代入の場合

左辺の要素の数 + 1 回分、`__getitem__()` が呼び出されます。
呼び出しの途中で `IndexError` が発生した場合、右辺の要素が不足しているとみなし、代入が失敗します。

```python
>>> v, x, y, z = MyTuple()
0
1
2
3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: not enough values to unpack (expected 4, got 3)
```

### `*` 付きのアンパック代入の場合

左辺に `*` 付きの要素がある場合、`IndexError` が発生するまで `__getitem__()` が呼び出されます [^2]。
その結果を左辺の変数にいい感じに代入します。

[^2]: いい感じ is [PEP 3132 -- Extended Iterable Unpacking](https://www.python.org/dev/peps/pep-3132/) です。

```python
>>> a, *b = MyTuple()
0
1
2
3
>>> a, b
('0', ['1', '2'])
```

いい感じの例

```python
>>> *a, b = MyTuple()
0
1
2
3
>>> a, b
(['0', '1'], '2')
```

ひとつぐらい要素が足りなくてもいい感じにしてくれます。

```python
>>> *w, x, y, z = MyTuple()
0
1
2
3
>>> w, x, y, z
([], '0', '1', '2')
```
```python
>>> w, *x, y, z = MyTuple()
0
1
2
3
>>> w, x, y, z
('0', [], '1', '2')
```
```python
>>> w, x, *y, z = MyTuple()
0
1
2
3
>>> w, x, y, z
('0', '1', [], '2')
```
```python
>>> w, x, y, *z = MyTuple()
0
1
2
3
>>> w, x, y, z
('0', '1', '2', [])
```

でも、ふたつ足りない場合はダメです。

```python
>>> *v, w, x, y, z = MyTuple()
0
1
2
3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: not enough values to unpack (expected at least 4, got 3)
```

## `__iter__()` を実装する

`__getitem__()` の代わりに `__iter__()` を実装してもアンパック代入できます。

```python
>>> class MyTuple2():
...     def __iter__(self):
...         return iter([1, 2, 3])
...
```

実装はかなり端折っていますが、3 つの要素を持つ配列のイテレータを返しています。
ちゃんと動きます。

```python
>>> x, y, z = MyTuple2()
>>> x, y, z
(1, 2, 3)
```

## まとめ

`__getitem__()` でも `__iter__()` のどちらでもよいということはつまり、[iterable](https://docs.python.org/ja/3/glossary.html#term-iterable) であればアンパック代入可能と言い換えることができますね。

>反復可能オブジェクトの例には、(list, str, tuple といった) 全てのシーケンス型や、 dict や ファイルオブジェクト といった幾つかの非シーケンス型、 あるいは Sequence 意味論を実装した `__iter__()` メソッドか `__getitem__()` メソッドを持つ任意のクラスのインスタンスが含まれます。