OmniAICreator/Qiita-1.07M huggingface dataset:
YouTubeでAI・Pythonを学ぼう！

![qiita_header_005.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1667780/d3ba2240-a7fa-14c7-7d8d-098b8d199874.jpeg)
ありがたいことに、YouTubeにはたくさんの学べるコンテンツがあります。AIやPythonに関するコンテンツもどんどん増えてきており、学習中の身としてはありがたい限りです。寝食以外はほぼYouTubeを視聴しているかもしれない私が、AIやPythonを学べるチャンネルおよび動画を紹介していきます。

## いまにゅのプログラミング塾
私が受講しているキカガクの元講師の方がやられているチャンネルです。分かりやすい語り口とハンズオン形式で理解しやすい点が特長です。動画内で使用される画像や効果音がポップで少し未来感があるので、最先端技術を学ぶ意欲をかき立ててくれます。

https://www.youtube.com/c/%E3%81%84%E3%81%BE%E3%81%AB%E3%82%85%E3%81%AE%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E5%A1%BE


## キノコード / プログラミング学習チャンネル
単回帰分析などの数学やPythonによる作業効率化などを紹介しています。ガッツリ学べるコンテンツと「毎日Python」などのプチコンテンツがあり、幅広いニーズに応えてくれているので重宝しています。あまり余談がなく、シンプルな構成でまとめられています。「冗談はいらないから、知識だけちょうだい！」という方にもオススメです（笑）

https://www.youtube.com/c/kinocode

## 予備校のノリで学ぶ「大学の数学・物理」
「予備校のノリで」という名前の通り、面白い先生に教えてもらっている感覚で学べるチャンネルです。黒板やホワイトボードに書きながら講義をするので、順を追って理解することができます。例え話や余談も交え、堅苦しさがないのでリラックスして視聴することができます。

https://www.youtube.com/c/yobinori


## Neural Network Console
数式をあまり使用せず、図解で理解を深めてくれます。動画に使われている色や書体、図もクオリティが高く、腰を据えて機械学習を"味わう"ように学ぶことができます。分かりやすい説明、聞き取りやすく心地よい声が、より一層学ぶことを楽しくしてくれます。

https://www.youtube.com/c/NeuralNetworkConsole


## AIcia Solid Project
チャンネルを見る前は、正直萌系（？）の声でディープラーニングを紹介するかと思っていました。普通に男性の声で驚きましたが、内容はとても分かりやすいです。言葉も簡単なものを選んで話されているので、勉強に疲れた時も、友人と話しているようなリラックス感で視聴することができます。かなり広い機械学習を紹介しているので、いろいろな技術をつまみ食いするのも良いかもしれません。

https://www.youtube.com/channel/UC2lJYodMaAfFeFQrGUwhlaQ


## こいこいの人工知能研究室
「人工知能で遊んでいる」という表現が合うチャンネルだと思います。短編動画が多いため、隙間時間に視聴することができます。個人的にGANに興味があるので、カワウソや新ポケモンを生成する動画が特に楽しめました。細かくコードを紹介しているわけではないので、実装する際は別途自分で調べる必要がありますが、いろいろな技術を楽しく学びたい方におすすめです。

https://www.youtube.com/channel/UC6M7Qk2It63qD0jhiKgLWZA

## 競馬予想で始めるデータ分析・機械学習
正直言うと最初は「ギャンブルに興味ないなぁ」と思い、すぐには視聴しませんでした。しかし、競馬はあくまでお題で（当たり前ですが...）、競馬予想を通してディープラーニングを学ぶことができます。ときには手書きを用いながら、実際にコードを書いて説明してくれます。個人的に、タイピングの音でも勉強意欲が沸くタイプなので、ライブコーディングのように進めてくれるチャンネルはありがたいです。

https://www.youtube.com/channel/UCDzwXAWu1zIfJuPTTZyWthw

## ウマたん
ウマ続きです（笑） 数学・機械学習・プログラミングを一通り学べます。各動画が短いので隙間時間に視聴することができます。線画イラストで説明してくれるので、流れるように知識をインプットできます。膨大な動画数ゆえ、もう少し再生リストが細かく分かれていると、目当ての動画に辿り着きやすいなぁと感じました。逆に言うと、それほどボリューミーなコンテンツを提供してくれています。

https://www.youtube.com/channel/UC0J7Yk_O3g1-x-xD7xxAE8Q/playlists

## はやたす / Pythonチャンネル
語弊があるかもしれないですが、これまで紹介したチャンネルに比べると動画自体には特徴があまりないです（笑） しかし、特徴がないがために視聴しやすく、一歩一歩学習していくことができます。（マリオ的な存在？） Pythonに基本のほか、Webスクレイピングやデータサイエンスなども紹介しており、知識の補完にとても役立ちました。個人的に動画のタイトル画面がシンプルかつ可愛らしくて好きです。

https://www.youtube.com/c/hayatasuuu/videos


## データサイエンス塾
10〜20分程度の動画数点が再生リストにまとまっています。1つの分野を順を追ってしっかり学ぶことができます。コードを書きながら進めていくので、実際に手元でも同じように進めることができます。動画が整理されているので、復習する際も学びたい動画に辿り着きやすいです。

https://www.youtube.com/c/nishimaki/playlists


## AI教室 AIRS-Lab
毎週月曜日にライブ講義を行っているチャンネル。講師の方は「はじめてのディープラーニング」などの書籍を出していたり、Udemyで動画を提供しています。講師の方が説明しているだけあって、今まで紹介したチャンネルとはまた違った分かりやすさがあります。個人的にはPyTorchを使用している点も気に入っています。1つ注意なのは、完成まで紹介していると思ったら、途中までだったという動画もある点です。途中からUdemyの有料動画を視聴する必要があるので、その点だけ確認しておきましょう。

https://www.youtube.com/c/SAILab/featured

***

海外に比べて、日本のAIに関する文献は少ないと聞きますが、YouTubeだけでもかなり学べると感じています。足りない部分はネット記事や書籍で補完する手もあります。ただ、やはりさらに高度な技術のコードなどを知りたい場合は頑張って海外の記事やGitHubを読むことになると思います。私も知識を蓄えて、先人たちのように分かりやすくAIを紹介するコンテンツが作れるよう頑張ります。
【GitHub】Gitコマンド初心者の備忘録

## 概要
普段はTortoiseGitユーザーで、Gitコマンドがさっぱり覚えられないので備忘録として残しておきます。
本当に基礎的なところのみ。。。。

## リポジトリ作成
GitHub公式から右上の緑色ボタンをポチっとして、リポジトリ名を入力。
ここからは自由だが、ReadMeにチェック。

## クローン
```bash:bash
git clone {URL}
```

# ステータス確認
```bash:bash
git status
```

## ファイル構成変更
```bash:bash
git mv {変更前パス} {変更後パス}
```

## ユーザ名確認・変更
```bash:bash
git config --global user.name
git config --global user.name {ユーザ名}
```

## ファイル追加
```bash:bash
git add {ファイルパス}
```

## コミット
```bash:bash
git commit -m {メッセージ}
```

## プッシュ
```bash:bash
git push
```

## 削除
反映させるには、削除後にコミットとプッシュが必要。

```bash:bash
git rm {ファイルパス}
```


## トークン取得
コミット時に聞かれるパスワード認証はサポート終了のため、トークンをいちいち取得しなければならなくなった。

トークン取得方法は[公式](https://docs.github.com/ja/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token)を参照
Apache POIを利用している際にA1形式でセルを取得したい

Excelではセルの位置を示すにあたって、A1形式を利用することが一般的だと思います。Apache POIを利用している際にA1形式でセルを取得したい場合、`CellReference`を利用するとよいです。

たとえば、以下はAB15のセルを取得するサンプルコードです。

```java
CellReference cellReference = new CellReference("AB15");
Row row = sheet.getRow(cellReference.getRow());
if (row != null) {
    Cell cell = row.getCell(cellReference.getCol());
    if (cell != null) {
        doSomething(cell);
    }
}
```

あるいは`CellUtil`を利用することもできます。

```java
Cell cell = CellUtil.getCell(CellUtil.getRow(cellReference.getRow(), sheet), cellReference.getCol());
doSomething(cell);
```

**環境情報 (pom.xmlの抜粋)**

```xml
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>5.0.0</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>5.0.0</version>
</dependency>
```
pythonが好きなjavascript使いが喜びそうなat()メソッド

最近、気づいたんですが`.at()`というメソッドが追加されたみたいです。
できることは、整数値をパラメーターとして受け取って、インデックスにある要素を返すというメソッドです。タイトルのpython好きなの部分に響きそうなのは、整数値なので、負の値が使えるということです。
何が嬉しいかというと、配列の最後の要素からカウントバックができるという事です。


多分、下記を見ていただくのが分かりやすいと思います。
### 例
```py
arr = [1,2,3,4,5,6]
print(arr[-1]) # 6
```

Javascriptの場合だと、最後の要素

```js
// without .at()
const arr = [1,2,3,4,5,6];

console.log(arr[arr.length-1]); // undefined
console.log(arr.slice(-1)[0]); // 6
```

```js
// with .at()
const arr = [1,2,3,4,5,6];
console.log(arr.at(-1)); // 6
```

ちなみに、小数点を渡してもエラーにはならず、小数点以下は切り捨てみたいです。

```js
const arr = [1,2,3,4,5,6];
console.log(arr.at(-1.5)); // 6
console.log(arr.at(2.5)); // 3
console.log(arr.at(4.1)); // 5
```

#### codepen
https://codepen.io/sleepy_coder/pen/xxLXqme?editors=0011


#### mdn at() method
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/at

ちなみに、どれくらい使えるのかcaniuse.comで確認すると、69%なので、ちょっとまだプロダクトで使うのは早いのかなぁという感じがします。ちなみに、map()は82.28
![Screen Shot 2021-10-31 at 7.32.21 AM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24723/764663d2-68a9-90cb-9ab4-1e9a9d0af254.png)
人生の羅針盤を形作る本

# 背景

良かった本の記録をしてなかったなぁと思い、記憶を呼び戻しつつ残せたらなぁ・・と

# 妄想する頭　思考する手
https://www.kinokuniya.co.jp/f/dsg-01-9784396617486

## 著者の発明例
- スマートスキン
    - ２０年前に二本指での操作を発明。アップルがiPhone で取り入れて今ではスマフォの標準操作
- [Traxion](https://lab.rekimoto.org/projects/traxion/)
    - 引っ張られる感覚を疑似体験できる。3D触力覚技術として発展中？

## 中身でいいなと思ったところ
- 「天使度」と「悪魔度」で考える
- 「やりたい事＝クレーム」は一行で書き切る
    - 仮説であって、事実ではない
    - What/Why は言語化で
    - How は視覚化で
    - 妄想を言語化し、掘り下げる
- あらすじを書く
    - 課題は何か？誰にとって必要なものか？
    - なぜ、難しい？ 面白いのか？
    - どう解決するのか？（≒一行クレームが多い？）
    - どう立証するか？
    - 効果と、発展性
- 検証は最短パスで。
    - プロトタイプ：まずはやってみる。デザイン思考的に
- ブレストはワークしない
    - 多数決や場を考えたりバランスを大切にしてしまうから
    - 個人の責任での孤独なプロセスを含有出来るれば効くかも
    - 創造とは既知の組み合わせだからこそ、引き出しを増やすことが大切
    - 故に、皆が知らなさそうな事を共有するなら、日々の行動も変えられていいね
- 試行錯誤は神との会話
    - 試行して失敗する事で課題が見えてくる
    - 手を動かし続けられるのも才能
    - 試行錯誤を続けると神の一言が舞い降りる（閃き）
- ピボット（方向転換）が生む意外性
    - 自分のアイディアはかわいく見えるという認知バイアスを認識しよう
    - 環境が整わない場合は、一旦眠らせておく
    - 「そもそもの目的」に立ち返る：デザイン思考でのDefineへ
    - イナーシャ（慣性）が無駄な「こだわり」を生む。いつでも心機一転！
- 人間拡張という妄想
    - 色々な拡張例が記載。入学試験を道具を利用した矯正学力で、というのは大賛成
- イノベーションの源泉を枯らさない社会へ
    - 最初にばかげたように見えないアイディアには見込みがない（アインシュタイン）
    - 選択と集中だけでは未来に対応出来ない
    - ルールを絶対視して妄想を潰す日本社会
    - 妄想型の人間を評価できる社会：グーグル２０％システムみたいに

# あとがき
AIによる仕事の置換が進み、人に望まれるのはエンターテインメントって時代になるからこそ
益々、人と違うことが賞賛されやすくなってていいですよね。
Apache POIを使って、シートをソートしたい

Excelにはシートをソートする機能は標準で用意されていません。通常はVBAを利用するのですが、VBAにはソート関数がなく、これを自前を用意するのは面倒。そもそもVBAが苦手ということもあり、JavaとApache POIで処理したことがこの記事を書いたきっかけになります。

前置きはさておき、以下は「**src.xlsxのシートをシート名でソートしたものをdst.xlsxに書き出す**」というものです。

```java
try (Workbook srcWorkBook = WorkbookFactory.create(Files.newInputStream(Paths.get("src.xlsx")));
     OutputStream dstWorkBook = Files.newOutputStream(Paths.get("dst.xlsx"))) {
    
    List<String> sheetNames = new ArrayList<>();
    for (Sheet sheet : srcWorkBook) {
        sheetNames.add(sheet.getSheetName());
    }
    
    Collections.sort(sheetNames);
    for (int i = 0, len = sheetNames.size(); i < len; i++) {
        srcWorkBook.setSheetOrder(sheetNames.get(i), i);
    }
    
    srcWorkBook.write(dstWorkBook);
} catch (IOException e) {
    throw new UncheckedIOException(e);
}
```

**環境情報 (pom.xmlの抜粋)**

```xml
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>5.0.0</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>5.0.0</version>
</dependency>
```
AWS Cloud9で環境を作成しようとした際のエラーたち


#### AWS Cloud9で環境を作成しようとした際のエラーです

ある日、Cloud9で新規環境を作成しようとすると、下記のエラーが出ました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565397/c667e51d-d7e8-a160-7bdc-1ea2fa667812.png)

素直に、CloudFormationが原因と考えて、色々調べたところ下記の検索結果がヒントになりました
https://aws.amazon.com/jp/premiumsupport/knowledge-center/cloudformation-stack-delete-failed/

URLにある記事のとおり、下記の画面で「削除」を実行します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565397/929e2889-51c1-4db9-9d90-1f7f8990ecc1.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565397/89ac74b9-83ff-8bef-bedf-f4ec284847a1.png)

で、再度Cloud9で環境を新規作成していきます。
これで解決かと思いきや、もう１つエラーが出ました。下記は「AWS Cloud9 > Environments」の詳細画面で見たエラー詳細です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565397/2c2058db-4f63-c59d-0b4d-ba1002de8473.png)

これも検索していくと、下記の説明が目にとまりました。
https://ja.confluence.atlassian.com/jirakb/aws-quickstart-template-leads-to-the-following-resource-s-failed-to-create-vpcstack-rollback-requested-by-user-error-966662213.html

地域選択を大阪にしていたことを即思い出し、「アジアパシフィック（東京）」に再度選択し直します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565397/0ab66b76-91a9-c3c5-1fc0-4453f82e1a0e.png)

すると、今度は、無事Cloud9環境を作成。Welcome画面に辿り着きました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565397/d98df9a7-a90f-9099-0ac4-5126e5e1fafa.png)

結果、どんだけ大阪が好きやねんという結末ですが、AWSはリージョン設定によっては使えなくなる機能があるというのはいい教訓ですね。
はじめて携わるaws Amplify チュートリアル（準備編）

aws Amplify チュートリアルをやる前の準備

#準備

## ローカル環境確認
node -v
npm -v
create-react-app --version
amplify --version

## アカウント取得
Githubアカウント取得
awsのアカウントを取得
Reactのローカル環境を構築


# ローカル環境構築

##参考
M1macでReactの環境構築をやってみた
https://www.mitsurog.com/opinion/m1macbook-react/

###Reactの環境構築に必要なファイルをインストールする

- homebrewのインストール
- nodebrewのインストール
- nodeのインストール
- npmのインストール
- yarnのインストール
- crea-react-appのインストール


amplifyのインストール

```
npm install -g @aws-amplify/cli
```


# アカウント取得
・Githubアカウント取得
・awsのアカウントを取得

## Githubアカウント取得

GitHubアカウント作成とリポジトリの作成手順
https://qiita.com/kooohei/items/361da3c9dbb6e0c7946b

## awsのアカウントを取得

プロが教えるAWSアカウント作成方法 ～ルートユーザアカウント作成編～
https://www.cloudsolution.tokai-com.co.jp/white-paper/2021/0604-238.html

住所を英語表記に変換
https://kimini.jp/

## Reactのローカル環境を構築
M1macでReactの環境構築をやってみた
https://www.mitsurog.com/opinion/m1macbook-react/
▼Reactの環境構築に必要
homebrew(ホームブリュー)
nodebrew(ノードブリュー
node(ノード)
npm(エヌピーエム)
yarn(ヤーン)
crea-react-app(クリエイト-リアクト-アップ)
putsメソッド、printメソッド、pメソッドの違い


| メソッド | 出力後の改行 | メソッド自体の戻り値 | 改行文字を含めた場合 | 配列を出力した場合 | 呼び出すメソッド |
| ---- | ---- | ---- | ---- | ---- | ---- |
| puts |改行を加えて出力する。|nil|改行される|配列の[]を含まず各要素ごとに改行される|to_s |
|print|改行を加えない。|nil|改行される|配列の[]を含め改行なし|to_s|
|p|改行を加えて出力する。|ただし文字列を出力するとその文字列がダブルクオートで囲まれる。|引数のオブジェクトそのものが改行されずに/nのまま表示される|配列の[]を含め改行なし|inspect|

``putsメソッド``と``printメソッド``は内部的に引数で渡されたオブジェクトに対して``to_sメソッド``を呼び出して**文字列に変換**している。

``pメソッド``は``to_sメソッド``ではなく``inspectメソッド``を呼び出す。
文字列が出力後にダブルクオート付きになっていた理由として**内部的にStringクラスのinspectメソッドが呼び出され値が出力されている**。


<font color=red>inspectメソッドは開発者にとって役立つ情報が含まれている。</font>
違いについて実際に検証した結果👇
-
![qiita1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1447987/6e1d52a7-dab6-dc94-55ff-578a98f15bfe.png)
モジュール名が実行結果として出力。
対象がクラスの場合、``#<クラス名:オブジェクトid インスタンス変数>``が実行結果として出力。

![qiita2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1447987/ddb477bd-7eef-08c4-4fd4-6bd292054002.png)

クラスについて``to_sメソッド``と比べると
``inspectメソッド``では**クラス名**と**オブジェクトid**と**インスタンス変数**を出力、
``to_sメソッド``は**クラス名**と**オブジェクトid**のみ出力し_インスタンス変数は出力しない。_

![qiita3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1447987/856e970d-c654-1f56-e71b-92ab7f0a9099.png)

配列・ハッシュともに値がそのままの形で表示される。

![qiita6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1447987/bdd9f745-887e-d213-3e02-5450182b8027.png)


文字列に関してto_sと比べると**ダブルクオートで囲まれているか・いないか**の違いがある。

![qiita5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1447987/8fa3d400-6c87-7521-f112-0a0206c1b81f.png)
``nil``に関しては``to_s``で出力した場合は実行結果として表示されない。
MESH×kintoneで入退出記録を取る

どうもこんにちは。非エンジニアのしもむーです。
今回はMESHとkintoneで、事務所への入退出記録を取る機能を作ってみました。
ほぼ参考記事のままですが、すこし変更した箇所があり応用が利くかな（ノーコーダー達が喜ぶかも？）と思い記事にしました。

##経緯
会社でISO取得に伴い、施錠記録を取る必要があるらしく、kintoneで入退室の記録を取るアプリを事務さんが作ってくれたんですが
「一番最初に来た人、最後に帰るはkintoneでレコード登録をしてください」というもの。
レコード登録くらい手間ないんですが・・・忘れちゃうんだなコレが。。。
そのうち事務さんに怒られそうだし、なんとか自動で登録できんかと思った矢先、こんな素敵な記事があったので拝借させてもらうことにしました。

▼MESHボタンで来場者の人数を集計しよう
https://developer.cybozu.io/hc/ja/articles/115005313923
ありがとうサイボウズさん。。。


##構成
今回利用するのは以下２つ。

**①MESHのボタン**
https://meshprj.com/jp/products/blocks/MESH-100BU.html
※人感センサーでも良かったけど、２番目に来た人も記録されるのでゴミデータが増えちゃうのでボタン式を採用。
**・１回ボタン押す→解錠**
**・ボタン長押し→施錠**
ボタンのMESHを入口に張り付けて、朝来たら１回ボタン押す。最後に帰る人はボタン長押しする。
という運用でとりあえず様子を見たいと思います。

**②kintone**
https://kintone.cybozu.co.jp/
毎度おなじみ。非エンジニアの強い味方、お世話になってます。
事務さんが作ってくれた「事務所の開・施錠記録」というアプリがあるので、それを利用します。
***■フィールド構成***
- ステータス（解錠or施錠のラジオボタン）
- 日付（登録した日時が自動登録される日時フィールド）
- 解・施錠者（これは一旦無視で）
- メモ備考
![スクリーンショット 2021-10-31 185855.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129605/47509a31-b7a5-ae52-2ce4-72ad3966eba7.png)


この２つを使って、以下のような動作を実現したいと思います。
***・MESH：１回ボタン押す　→　kintoneの「事務所の開・施錠記録」アプリで、ステータス：解錠のレコードを追加
・MESH：ボタン長押し　　→　kintoneの「事務所の開・施錠記録」アプリで、ステータス：施錠のレコードを追加***

##参考記事との違い
上記の記事では、
> MESHボタンを押したら、kintoneのアプリにレコードを登録します。
> ボタンを１回押す：カウントを＋１
> ボタンを長押しする：カウントをー１
> カウントのマイナスもできるので、間違って押したときも安心！
> アプリのレコードには、人数カウント用のフィールドのほかにイベント名、日付、時刻フィールドを用意しておきます。
> これで、「どのイベント」で「何時」に「何人」きたのかがわかりますね♪

となっているので、今回と少し用途が違います。
***①イベント名→いらない
②人数→カウントを＋１ではなく、[施錠/解除]の値をセットしたい***
この部分を少し改修して実装してみました。

##修正内容
おおむね内容は一緒なので、一旦記事通りに設定を進めます。
※ただし、kintoneのフィールド設定は必要ないので行いません。
最後まで設定できたら、MESH SDKを開き、設定内容を修正していきます。

###①イベント名の削除
今回はイベント名は登録不要なので、設定内容を削除していきます。
１）Property内にある「イベント名」の横にある”Delete"をクリックし要素自体を削除
![MESH-SDK1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129605/f602305e-9585-30ff-c950-8be9839a6ee4.png)

２） ”Code”の”Execute”タブを開き、１０行目にある「var eventName = properties.EventName;」を削除
![MESH-SDK2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129605/5c267d11-3b26-a4df-3157-edb5481030ca.png)

３） 同じく２３行目から２６行目にある
`"EventName": {
	"value": eventName
},`
を削除
![MESH-SDK3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129605/36f18139-ed26-7664-67fc-864587f5a5e1.png)


###②人数カウントを施錠/解錠に置き換える
１）kintone側でラジオボタン：解錠／施錠フィールドを設定。
※フィールドコードはstatus
![MESH-SDK4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129605/c1515d60-7a65-c3bf-efc7-dfc1d749102d.png)

２）MESH　SDKで”Code”の”Execute”タブを開き、15行目、17行目を編集
```if (receiveValue == 0 ) {
	var cntValue = 1;
} else {
	var cntValue = -1;
}
```
を
```if (receiveValue == 0 ) {
	var cntValue = "解錠";
} else {
	var cntValue = "施錠";
}```
に修正

２７行目の”Count”を”status”（kintoneの設定したラジオボタンのフィールドコード）に変更
![MESH-SDK5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129605/f0db460f-0079-caaf-1056-ccb975af386e.png)


変更箇所は以上。
左上の「Save」を押して、MESHのレシピ画面へ戻ります。
追加しているSDKをクリックすると、ブロック情報画面が開くので「アップデートを確認する」をクリックすると、変更したものが反映されます。


これでボタンによる入退室の記録ができました！
変更箇所さえ分かれば、色んな応用が利くと思うので、色々工夫してkintoneを活用していきたいと思います。

ほな！
djangoのcleaned_dataについてまとめてみた

今回のお題
-
今回はdjangoに用意されているcleaned_dataという変数についてまとめます。

この記事を書くに至った理由はCustomUserの実装にあたってcleaned_dataが必要だったからであり、基本的には自分用のメモとして残します。

cleaned_dataとは
-

まず、cleaned_dataとは何かというと、「あるオブジェクトの属性値の中でバリデーションをクリアしたものだけを辞書形式で格納したもの」になります。

具体的にみていきましょう(ソースコードのimport部分は省略しています）。

```python
class Hoge(models.Model):
  name = models.CharField(null=False, max_length=20)
  age = IntegerField()

hoge = Hoge()
hoge.name = "hoge"
hoge.age = "30"

print(hoge.cleaned_data)
# 結果：{}
# バリデーション前なのでcleaned_dataは空

hoge.is_valid()

print(hoge.cleaned_data)
# 結果：{ "name": "hoge" }
# バリデーションをクリアしたnameのみが格納されている。
```
上記の例ではHogeクラスのインスタンスを作り、そこに対してバリデーションを実行しています。
ageはIntegerFieldであるにもかかわらず文字列"30"が代入されたためにcleaned_dataからはじかれています。

また、is_valid()関数が呼び出される前の時点ではcleaned_dataは空であることに気をつけてください。

終わりに
-
以上でcleaned_dataの解説を終わります。

この知識はCustom Userの実装過程でsaveメソッドを上書きするために必要です。

そちらについても近々まとめるのでよろしければお読みください。
【サンプル】SQLのコーディング規約

:::note info
PJでコーディング規約がない時に使用してください。
:::
##コーディングルール
* 予約語：大文字
* 予約語以外：大文字（開発コストを抑えるためにテーブル定義書に合わせる）
* インデント：半角スペース4個(コードチェックツールでタブが禁止されている場合がある)
* `カンマ ,` を使用する箇所の先頭列は、インデントを半角スペース6個（サンプルのSELECT句参照）
* SELECT句にコメントでカラム論理名をつける(障害・保守対応コスト削減)
* FROM句にコメントでカラム論理名をつける(障害・保守対応コスト削減)
* ORDER BY句は必須でつける(テストツールのテスト結果において、取得順序が変わる可能性がある)
* `カンマ ,` と `半角カッコ ()` の付け方はサンプルを参考
* `半角カッコ開始 (` は行末尾につける
* `半角カッコ終了 )` は改行してつける

##禁止事項
* `アスタリスク *` 禁止（カラム名変更の際の調査が大変）
* RIGHT JOIN禁止（出来る限りLEFT JOINを使用する）
* OUTER禁止（検索しやすいようOUTERを不使用で統一）

#サンプル
```sql:sample.sql

SELECT
      USER_INFO.ID    # ユーザID
    , USER_INFO.NAME  # ユーザ名
    , SALE.DATE       # 販売日
FROM
    USER_INFO       # ユーザ情報
    LEFT JOIN SALE  # 販売情報
    ON USER_INFO.ID = SALE.USERID
WHERE (
      USER_INFO.ID = 'ID0001'
  AND SALE.PRODUCT_ID = 'A0001'
  AND SALE.DELETE_FLG <> '1'
)
OR (
      USER_INFO.ID = 'ID0002'
  AND SALE.PRODUCT_ID = 'A0002'
  AND SALE.DELETE_FLG <> '1'
)
GROUP BY
    SALE.DATE
ORDER BY
      USER_INFO.ID
    , SALE.DATE DESC
```
まったく知らない人のためのキャッシュ

#キャッシュとは

キャッシュとは、ブラウザで一度表示したwebページのデータ（画像やHTMLなど）を保存し、再度そのページを表示する際、保存したデータを取得することで一度目より早く表示される仕組みです。


画像が多いページとかだと表示に時間がかかることがあるので、キャッシュにより表示速度があがると表示を待つ時間が軽減されます。


#キャッシュの種類


##ブラウザキャッシュ
(Google Chrome、Mozilla Firefoxなどの)ブラウザで、webサイトにアクセスした際の情報を保存し、再度アクセスする際にそのデータを取得することで高速表示化させる機能。

##サーバーキャッシュ
アクセスしたサイトデータをサーバーに一時的に保存し、再度アクセス時にサーバーからデータを読み込み、高速表示させる機能。



#キャッシュのメリット・デメリット

##メリット

###表示速度が速くなる
最初でも述べたように、再度同じページにアクセスした際、前回より早く表示されることです。

##デメリット

###webページの内容が更新された際、即時反映されない場合がある
webページに修正が加わったり、画像が変更されたりしても、キャッシュの持っている古いデータが読み込まれて以前のページが表示されてしまいます。この場合、「スーパーリロード」もしくはキャッシュを削除すれば解決します（後ほど方法を記載）。

###キャッシュがたまりすぎると動作が遅くなってしまう
キャッシュもデータなので保存容量があり、あまり溜まりすぎると容量を圧迫して動作が遅くなることがあります。
ブラウザなど遅いと感じたら、キャッシュの影響を受けているかもしれませんのでキャッシュを削除してみるのもありです。

##キャッシュのデメリットの対処法

###スーパーリロード

「スーパーリロード」とは、ブラウザのキャッシュを無視して強制的にwebページのデータを読み込むもので「フルリロード」「強制再読み込み」ともいいます。
（ちなみに通常のリロードはキャッシュのデータを利用して再読み込みします）

####windowsの場合
→Google Chrome / Firefox
Ctrl + Shift + R


####Macの場合
→Google Chrome / Firefox
Command + Shift + R


###キャッシュの削除

####PC版GoogleChromeの場合


画面右上の「Google Chromeの設定」アイコンをクリック。
次に「設定」をクリックする。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1237088/b48e0027-67e0-8dcb-e9fc-7a3ff78274a7.png)

左の「プライバシーとセキュリティ」をクリック。
その後右側に表示される「閲覧履歴データの削除」をクリック。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1237088/73a84507-aeae-ec80-a4b8-89cd7c56e856.png)


モーダルが表示されるので削除したい期間を選択（画像では1時間以内を選択）。
次に「キャッシュされた画像とファイル」にチェックをいれます。
最後に右下「データを削除」をクリック。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1237088/904eeaa1-b564-724f-9480-347ed65e9aea.png)

#補足

Google Chrome のキャッシュデータはどこにあるのか気になり調べましたが、下記記事が参考になります。

参考: [Google Chrome のキャッシュの場所を確認する](https://www.tipsfound.com/chrome/01001)
テックキャンプの夜間を卒業してコレだけは言いたいこと

# これからプログラミングを学ぶ人にコレだけは伝えたいこと
### Macの購入は絶対にIntelのMacを買っておけ
発売当初のM1 Macbookを購入してテックキャンプを初めたワケなんですが、
実際の現場ってJAVAの案件が相当多いんですよ。
しかもJAVAの開発環境はWindowsが大半。

IntelのMacだったらBootcampでWindows使えるし、パラレルズでもネイティブのWindowsが使える。
M1だとArm版のWindowsになるので、開発環境としてはNGなんですよね。
結局、以前持っていた性能低めなノートパソコンからVPN経由で自宅のデスクトップを遠隔操作することで今はなんとか繋いでいます。
今後、動画編集とか写真ガシガシいじったりとかするときにMacbookは活躍してくれる、ハズ。

### 金かけてもやるのは自分
100万円近い金をぶっこむので機体するのはわかりますが、
残念ながら自分を管理できるのは自分しかいません。
他の人のカリキュラム進捗とか見られれば違ったかもしれないけど、
基本規定の進捗から見て「規定より進んでいるから今日は休もう」とか「やっべ遅れてるじゃん頑張ろう」って感じでした。

そもそも、プログラミングの勉強初めて目覚めた人はカリキュラムとは別に自分でJAVAとかSQLとかAWSの勉強してたりするので、
カリキュラムさえ進めるって考え方自体、実はあまり良くないんじゃないかと思います。

### 下記自分語りとテックキャンプの感想になります。
----------------------------------------------------------


# 2020年の12月からテックキャンプの夜間に通い始めた
前職では総務だかシステム課だか庶務課だか、よくわからない状態で業務が積み上がりまくっていて、
給与が上がる見込みもなかったので心機一転として、失業保険受け取りつつプログラミング学びたいなってことで通い始めました。

2021年の10月に、去年スタートしたばっかりというSESの会社に拾ってもらい、
11月から飛ばされた先のお仕事を開始する感じです。

# テックキャンプ夜間を選んだ理由と良かったこと
私事ですが、1型糖尿病を2年前に患っていて、作業に集中して食事が疎かになるのが絶対にNGだったんです。
そんなわけで、時間はかかるけど食事の時間を調整できる半年間のカリキュラムである夜間を選択しました。

通って良かった事としては、勉強の仕方と管理能力が身に付いたこと。

基本、なろうの小説とか実況動画などでダラダラ過ごすのが好きなもので、
学習に対する切り替えが全く出来ていませんでした。
仕事に関しても職場に行かないと切り替えが出来ないって人は居るんじゃないかなぁ。

んで、００：００（フォーゼロ）とポモドーロ併用で学習垂れ流してみたり、
喫茶店やコワーキング借りてやってみたりして、
なんとか学習時間が確保できるようになったって次第です。

# テックキャンプ夜間を選んで後悔していること
まず、やっぱり高いです。
カリキュラム卒業して就職まで行っても、高いなと思うのは変わりません。

次に、カリキュラム受講中にコミュニケーション取れるエンジニアの人との交流をしなかったこと。
compassの「もくもく会」は参加しときゃよかったなと思っています。

最後に、実はプログラミングがそこまで好きではなく、現在苦痛に感じていること。
社内業務改善とか、自分で欲しいサービスの構想とかはありますが、明確に結びつくワケでもありません。

# これからの心境
プログラミングが好きではないという話とも繋がるのですが、
頭の中の思考を少しでもプログラミング的に考えられるようにする訓練と考えています。

明確に「JAVAのシルバー取った」とかではないので、ゴールがあるかもわかりませんが、
人に何かを説明するのがめっちゃ苦手と現職の講習で身に沁みました。
なので、理屈をつけて思想・思考を落とし込んで設計した後に、サービスを作りローンチするという流れを意識して、
今後の学習も続けて行かなきゃなと自分に言い聞かせています。
dockerignoreの書き方

.dockerignore に記載のあるファイルはコンテキスト(docker イメージ構築に必要な素材・内容物)から除外されます。

## ルール

"#"で始まる行はコメントとみなされます。
除外したいファイルやディレクトリの名前を書きます。

```Docker
# この行はコメント

# root以下のあらゆるサブディレクトリ内でtempで始まる名前やファイルの除外
# ex. /somedir/temporary.txt, /somedir/tempを除外
*/temp*

# rootから2階層以下のサブディレクトリ内で、 temp で始まる名前のファイルやディレクトリを除外
# ex. /somedir/subdir/temporary.txt を除外
*/*/temp*

# ルートディレクトリ内でtempと1文字が一致する名前のファイルやディレクトリを除外
# ex. /tempa,/tembを除外
temp?
```

### 例外

"!"で始まる行は除外対象の例外として指定されます。
ただし、他の行をみて矛盾がある場合には最終行のほうが優先されます。

- 例 1

```Docker
!README*.md
README-secret.md
```

README-secret.md が!README\*.md より後にあるので、README-secret.md は除外対象となり、README で始まる md ファイルは除外対象にはなりません。

- 例 2

```Docker
README-secret.md
!README*.md
```

!README\*.md が README-secret.md より後にあるので、README-secret.md も含む README で始まる md ファイルはすべて除外対象となりません。

.dockerignore ファイルを使うと Dockerfile と.dockerignore ファイルも除外対象にすることができます。除外設定しても、構築処理で必要なためデーモンに送信されますがADD命令とCOPY命令でイメージにコピーされません。

## 参考

https://docs.docker.jp/engine/reference/builder.html?highlight=dockerignore#dockerignore
【Ruby silver】範囲式 フリップフロップ演算子

 次のコードを実行するとどうなりますか。　
- 

```
10.times{|d| print d == 3..d == 5 ? "T" : "F" }
```

解説文
---
d == 3..d == 5の部分は条件式に範囲式を記述しています。
この式は、フリップフロップ回路のように一時的に真偽を保持するような挙動をとります。
詳細は、Rubyリファレンスに詳しい説明がありますのでそちらを参照してください。
<li>https://docs.ruby-lang.org/ja/latest/class/Range.html</li>
<br>
初めて見た時に混乱しました。
どうゆう順番で評価するか整理して考える必要があったのでまとめます。
<br>


**⑴Rangeの復習**
-
```ruby
# ..の場合
a = (1..5).to_a
=> [1, 2, 3, 4, 5]

# ...の場合
a = (1...5).to_a
=> [1, 2, 3, 4]
```
👆
..の場合は5を含む1〜5の範囲になる。
...の場合は4.9999...までは対象になるが5は範囲に含まない。整数で考えると1〜4が範囲になる。


**ひとつずつ崩して考えて理解する**
``10.times``
``{|d| print d == 3..d == 5 ? "T" : "F" }``

``10.times``
0..9の範囲を考える　=>  0123456789

``(d == 3)..(d == 5)``
dが3〜5の時に(わかりやすく括弧で囲いました。)

``? "T" : "F"``
条件式：trueの場合"T"を出力、falseの場合は"F"を出力。
**【補足】**
三項演算子：　``条件式 A ? 式 B : 式 C``
条件式 A が真の時は式 B が実行され、偽の時は式 C が実行される。


012`345`6789
345がTrueのためTが出力される


**結果としてFFFTTTFFFFが出力される**


<li>
ソニックガーデンjnchitoさんの記事：https://qiita.com/jnchito/items/e7aa147e340311e94a4d
その他参考解説：https://www.yokoyan.net/entry/2019/07/26/224946
</li>
[競プロ][Max Subarray] 和がkとなるような部分配列の最大長を求める

和がkとなるような部分配列の最大長を求める

## 解法1 (要素が0または正数のみの場合)

条件を絞って要素が正数のみの場合だとしゃくとり法を利用できる。
詳細は[しゃくとり法の解説](https://qiita.com/awesam/items/75b4aae59916ad6b291a)を参照

下記コードは和がkになるような部分配列の最大長を求めるコード

```c++
int sum = 0;
int len = 0;
for (int left=0; left<n; left++) {
    while (right < n && sum < k) {
        sum += nums[right];
        right++;
    }
    if (sum == k) {
        len = max(len, right - left);
    }
    sum -= nums[left];
}
cout << len << endl;
```

## 解法1 (要素に負数も含む場合)

この場合は上記のしゃくとり法が使えない
累積和をMapに格納しておき、現在の累積和とkとの差分を探す手法を使う。

```c++
unordered_map<int,int> mp;
int len = 0;
int psum = 0;
for (int i=0; i<n; i++) {
    psum += nums[i]; // 累積和を取っていく
    if (psum == k) {
        len = i + 1;
    } else if (mp.count(psum-k) > 0) {
        len = max(len, i - mp[psum-k]);
    }
    
    if (mp.count(psum) == 0) mp[psum] = i; // 次ループのために累積和を格納
}
cout << len << endl;
```

## 関連問題
[325. Maximum Size Subarray Sum Equals k](https://leetcode.com/problems/maximum-size-subarray-sum-equals-k/)
[1658. Minimum Operations to Reduce X to Zero](https://leetcode.com/problems/minimum-operations-to-reduce-x-to-zero/solution/)
Laravel 更新処理の違い(save, update, create, associate, attach, detach)

# はじめに
データの登録や更新に用いる各メソッドを記載しています。主に違いが分かるように記載しています。
シンプルに書いてますので、実際に業務で使用する際は若干書き方が違うと思います。
詳しい説明は別の記事を参照して下さい。

# 目次
<!-- タイトルとアンカー名を編集 -->
1. [save](#save)
2. [update](#update)
2. [create](#create)
3. [associate](#associate)
4. [attach / detach](#attachとdetach)

<!-- 各チャプター -->
# save
インスタンスを作成して、データを挿入後、save( )で保存する。

```
$user = new User();
$user->name = $request->name;
$user->save();
```

# update

saveとほぼ同じですが、違いは以下の通りです。

__save( )__
nameカラムの内容を更新する際に、挿入されるデータが更新前と同じものであれば、<font color="blue">updated_atのカラムが更新されない。</font>

__update( )__
nameカラムの内容を更新する際に必ず<font color="blue">updated_atのカラムが更新される。</font>

```
$user = new User();
$user->name = $request->name;
$user->update();
```

# create

こちらはインスタンス化からデータ保存を一括で実行できます。

```
$user = App\Model\User::create(['name' => $request->name]);
```

# associate
そのユーザーに紐ずく、postsテーブルのuser_idカラムを更新する。一対多のリレーションで使用する。
※この場合、Postモデル内にあるbelongsToの第二引数であるuser_idを更新する。

```
// $userの部分は、レコードではなく、user_id(idの数字)を入れるだけでもいけると思います・・・たぶん
$user = User::find(1);
$post->user()->associate($user)->save();
```

```
// Post.phpファイル
public function user()
{
 return $this->belongsTo('App\Models\User', 'user_id');
}
```

# attachとdetach
__attach( )__
<font color="blue">中間テーブルに一括で登録</font>できる。
この場合は「ユーザー」に紐ずく「複数の趣味」を一括でDBに保存出来る。

```
$user->hobbies()->attach($request->hobbies);
```

__detach( )__
<font color="blue">中間テーブルを一括で削除</font>できる。
引数を指定しない場合は、その「ユーザー」に紐ずく「全ての趣味」が中間テーブルから削除される。

```
$user->hobbies()->detach();
```

※中間テーブルの更新は他sync( )やupdateExistingPivot等がありますが、ここでは説明を割愛します。
【Vue / Nuxt】inputコンポーネントにenterでフォーカス移動する

input内でenterを押下した際に次のinputにフォーカスさせる処理、よくありますよね。
フォーカスしたいinputがコンポーネントの時に悩んだので備忘録です。

#子コンポーネントの書き方

```Input.vue
<template>
  <div>
    <input
      ref="input"
      :value="value"
      :type="type"
      :placeholder="placeholder"
      @keydown="event=>$emit('focus', event)" />
  </div>
</template>
<script>
export default {
    name: 'Input',
    props: {
        type: {
        type: String,
        required: false,
        default: 'text'
        },
        value: {
        type: String,
        required: false,
        default: ''
        },
        placeholder: {
        type: String,
        required: false,
        default: ''
        }
    },
    methods: {
        focus () {
          this.$refs.input.focus()
        }
    }
}
</script>
```

#親コンポーネントの書き方
コンポーネントのinput -> 通常input -> コンポーネントのinputの順でフォーカス移動するサンプルにしました。

```index.vue
<template>
<div>
  <Input
    :value="value"
    type="text"
    placeholder="name"
    @focus="event=>nextFocus(event,'emailRef')"/> 
  <input
    ref="emailRef"
    :value="value"
    type="text"
    placeholder="email"
    @keydown="event=>nextFocus(event,'passwordRef')"/> 
  <Input
    ref="passwordRef"
    :value="value"
    type="text"
    placeholder="password"/> 
</div>
</template>

<script>
import Input from '@/components/Input.vue'
export default {
  components: { Input },
  data() {
    return {
    value: ''
    }
  },
  methods: {
    nextFocus(event, refName) {
      if (event.keyCode != 13) {return}
       this.$refs[refName].focus()
    }
  }
}
</script>
```

![6FA4092A-6C30-4394-9106-779E8F4D2E12_1_102_a.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550109/bc2df8e8-386f-a4fa-269d-d5386cf1c264.jpeg)


#解説

```Input.vue
    <input
      ref="input"
      :value="value"
      :type="type"
      :placeholder="placeholder"
      @keydown="event=>$emit('focus', event)" />
```
子コンポーネント側の`@keydown="event=>$emit('focus', event)" `で、何かしらキーが押下されるたびにeventを渡す`focus`メソッドを読んでいます。

このeventを元にフォーカス処理をするために`@focus="event=>nextFocus(event,'ref名')"`でメソッドを呼びます。
通常のinputの場合は直接`@keydown`で問題ありません。
　　　　　


```index.vue
    nextFocus(event, refName) {
      if (event.keyCode != 13) {return}
       this.$refs[refName].focus()
    }
```

`nextFocus`メソッドでイベントと対象のref名をもらいます。今回はenterの場合に移動したいので、`keyCode`が１３（enter）の時以外はなにも処理しません。
`this.$refs[refName].focus()`で受け取ったref名に対して　focus処理をしています。
　　　　


```Input.vue
        focus () {
          this.$refs.input.focus()
        }
```
フォーカス先がコンポーネントの場合、**コンポーネント（Input）のrefではなく、コンポーネント内に実際に書かれている`input`要素にフォーカスする**必要があります。
そのため実際にフォーカスしたいコンポーネント内の`input`に対するフォーカスのメソッドが必要になります（説明が下手ですみません）

私はこれを書かなかったことにより`focus() is undefined `になり原因解明に時間がかかってしまいました。。。


#最後に
他にもっといい書き方がありそうな気がしますが、フォーカス移動付きコンポーネントに関する記事が全く見つからなかったので私にはこれが限界でした。。。

今の現場では`$listeners`を使用する方法で記述していましたが、vue3では廃止されているようなので自分で考えて書いてみました。ものすごく時間がかかった。。。
もっといい書き方があるよ〜とか、俺ならこう書くぜ！などコメントいただけると大変嬉しいです。

最後まで読んでいただきありがとうございます！
自動テストの分類について

## はじめに

対象のプログラムに対し、その挙動を検証する専用のテストプログラムを記述し実行することで、プログラムにプログラムを検証させる、いわゆる自動テストもかなり普及してきたと思います。

Tcl言語の標準ライブラリであるtcllibではライブラリの登録に自動テストの記述が必須となっていますし、他のライブラリやフレームワークでもそういった体制になっている所も多いのではないでしょうか。

しかし、あなたがお仕事で、あるいは趣味で新しいプログラムを実装した場合、自動テストをこれから実装するなんてこともあるでしょう。

本記事では自動テストのいくつかの考え方、分類を解説します。あなたのプログラムにどういう自動テストが必要なのか、そのヒントになれば幸いです。

## 自動テストの分類

- **単体テスト**
  - 最も単純かつ基本的なテストです。オブジェクト指向言語ならクラス単位、手続き型言語や関数型言語なら関数単位で別のプログラムから対象のクラスや関数を呼び出し、その処理結果を検証することでクラスや関数の挙動の整合性を保証します。いわゆるユニットテストといえばこの形式のテストを指します。
  - 単体テストでは対象のクラスや関数のみがテスト対象です。したがって、テストの対象が他のクラスや関数を呼び出している場合、それら対象外のプログラムについては実際のプログラムは使用せず、テスト用に挙動を定義したクラスや関数に差し替えることになります。こういった差し替え対象となる一時的なクラスや関数のことをモックアップと呼びます。大抵のUnitTestのフレームワークにはモックアップの機構が付属しています。
- **結合テスト**
  - 単体テストの次に有力となるテストです。対象のクラスや関数について、モックアップで差し替えることなしにそのまま実行します。当然ながら本番環境でそのまま動かすわけにはいきませんので、データベースやネットワーク環境などは自動テスト専用に作成することになります
  - 機能テストでは機能の実行の結果、データベースの書き換えなどの副作用が発生しますので、テストを実行するたびに、データベースのデータを固定の値に書き戻す事が必要となります。この初期データのことをフィクスチャー(fixture)と呼びます。
- **機能テスト**
  - 対象プログラムのクラスや関数単位ではなく、システム全体の各機能について、プログラム自体を外部から実行し、検証する方式のテストです。WebAPIならば実際にAPIを実行して副作用や戻り値を確認しますし、ウェブサービスならばページごとに出力されたHTMLの内容を確認します。
  - SeleniumやPostmanなど、対象システムの分野ごとにプログラムで自動化可能なクライアントが存在し、そのフレームワーク上でテスト内容をプログラムや設定ファイルとして記述することになります。

## 特徴まとめ

|テストの種類 | フレームワーク | モックアップ | DB、テスト環境 | 実行速度 |
|----- |----- |----- |----- |----- |----- |----- |
|単体テスト | UnitTest処理系 | あり | なし | 高速 |
|結合テスト | UnitTest処理系 | 原則なし | あり | 低速 |
|機能テスト | 各種検証ツール | なし | あり | 非常に<br>低速 |

- **UnitTest処理系**
  - 各言語ごとに存在します。PHPだとPHPUnitがデファクトですし、JavaならばJunitがあります。
- **各種検証ツール**
  - ここで言う検証ツールとは、システムのプログラムの外部からそのシステムにアクセスし、実行結果を取得できるツールのことを指します。クライアントツールの一種で、スクリプトによりツールのアクセスや処理結果の自動的な検証が可能となるものを指します。

## 単体テストの利点、欠点

-  単体テストの利点
  - テストとしては最も低レベル
  - 対象システムと同じプログラミング言語で実装できる
  - 対象のクラスや関数と１対１対応するため検証内容がわかりやすい
  - テスト実施のために記述したテストプログラム自体が一種の開発者ドキュメントとなる
  - 処理が高速(通常ミリ秒単位)
-  単体テストの欠点
  - モックアップの作成が非常に煩雑
  - フィクスチャーの概念がないため、初期データ自体もモックアップとして与える必要がある
  - 対象のクラスや関数を単体テスト可能な形で予め実装する必要がある
  - 単体テストを記述が困難または不可能な場合がある。そういった事態に陥らないように気をつけながら実装する必要がある。

単体テストを記述できる条件について、詳しくは以下の記事をご覧ください。

- [単体テストを記述できる条件(PHP)](https://qiita.com/kanryu/items/785f414147af9c74fcc0)


## 結合テストの利点、欠点

- 結合テストの利点
  - 単体テストに比べ、より本来の仕様に近い形でテストの実施が可能
  - 対象システムと同じプログラミング言語で実装できる
  - 対象のクラスや関数と１対１対応するため検証内容がわかりやすい
  - テスト実施のために記述したテストプログラム自体が一種の開発者ドキュメントとなる
  - システム自体と同じ権限で実行できるため、テスト実行後に対象DBへのアクセスが可能
- 結合テストの欠点
  - テスト専用の環境、DBの整備が必要
  - テスト実施ごとにDBの初期化が必要
  - フィクスチャーデータの作成が必要。テストが大規模化していくにつれ、フィクスチャー自体の整合性を維持することが難しくなる
  - 単体テストに比べ処理速度が遅い(数十～数百ミリ秒単位)

## 機能テストの利点、欠点

- 結合テストの利点
  - システムの機能自体を検証しており、最もユーザー目線に近い
  - システムを外部から検証するため、システムの実装言語に依存しない
- 機能テストの欠点
  - 結合テストの欠点全て
  - 処理速度が非常に遅い(数百～数秒単位)
  - テストの実施範囲に限界がある(外部から見えない値や結果は検証できない)
  - 仕様変更に弱い(仕様上複数のページや複数の工程を減る必要があり、途中の工程の仕様が変わるとその後全てのテストが実施不能になる)
  - 検証ツールからのDBアクセスは原則不可能


以上。
Flutter Firebase 追加時のエラーメモ


備忘録

# インストール

```
flutter pub add firebase_core
```

# エラー事象

```
CocoaPods could not find compatible versions for pod "Firebase/Analytics"
```


# 対処

## その1

```
flutter clean 
```

## その2

```
cd ios
pod install --repo-update
flutter clean 
```

## その3

```
cd ios
sudo gem install cocoapods
pod install --repo-update
flutter clean 
```

## その４

Xcodeから iOS Deployment Target 11.0以上に

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37624/e3632f6b-dc53-1322-f7b7-1c10aa326039.png)

その1を実行

## その5

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37624/f3f7265e-038e-8b4d-7fda-d78edf69b5d8.png)

その1を実行


# ダメな時

```
flutter pub remove firebase_core
```
いつも忘れてしまうCanvas ScalerのUI Scale Modeでテキストをワールドに出すメモ

# こういうことよ、という画像

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/c7984494-f049-85d6-2c58-38ec1c44272a.png)

# ワールドのなかにテキストを固定で設置したいとき
## 手順メモ
### Textオブジェクトを追加
- ここはふだんどおり


### Canvasオブジェクトの設定を変更
#### Canvas Scalerコンポーネントの設定を変更
- 「UI Scale Mode」を「Wolrd」に設定する。
- 「Dynamic Pixels Per うにゃにゃ」の数値を変更する。


### Textコンポーネントの設定を変更
- フォントサイズは小さくなる
- Width、Heightは任意で
- Pos系も任意で

# 総括
- clusterでけっこうお世話になる設定なので、残しました。
JuliaでMPIのScatter使った計算

[前回](https://qiita.com/ishigaki/items/905128d899ae847d825b)に引き続き，JuliaでMPI使った計算です。Scatterでデータをばらまきます。rank 0から他のランクのプロセスにデータを送る例です。

# Scatter!
Aallという配列のデータの等分割したデータをランク０から他のランクに送ります。Scatter!の場合は，送るデータのサイズは全部同じである必要があります。

```julia
using MPI

function test()
    MPI.Init() # MPI初期化
    comm = MPI.COMM_WORLD
    nprocs = MPI.Comm_size(comm)
    myrank = MPI.Comm_rank(comm)

    nmax=10
    ista, iend = parallel_range(1, nmax, nprocs, myrank)

    A = Array{Int}(undef, iend-ista+1)

    if myrank == 0
        Aall = ones(Int, nmax)
        for i = 1:nmax
            Aall[i] = i
        end
    end

    if myrank == 0
        MPI.Scatter!(UBuffer(Aall, iend-ista+1), A, 0, comm)
    else
        MPI.Scatter!(nothing, A, 0, comm)
    end

    println("A, myrank", A, ", ", myrank)

    MPI.Finalize()
end

function parallel_range(n1, n2, nprocs, irank)
    nb = div(n2-n1+1, nprocs)
    nm = (n2-n1+1)%nprocs
    ista = irank*nb+n1 + min(irank, nm)
    iend = ista+nb-1 
    if nm > irank
        iend = iend+1
    end
    return ista, iend
end

@time test()
```

10要素の配列を2分割して，データを送るのでrank 0には1から5，rank 1には6から10が入ります。

```bash
$ mpirun -n 2 julia MPI-scatter.jl 
A, myrankA, myrank[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], 0
1
  0.244625 seconds (273.49 k allocations: 15.826 MiB, 76.19% compilation time)
  0.239508 seconds (273.49 k allocations: 15.826 MiB, 80.11% compilation time)
```

# Scatterv!
Scatterv!は異なる要素数のデータを送れます。Scatterv!を実行する前に送信するデータのサイズを計算します。下記ではsizesに送るデータの数を入れてます。

```julia
using MPI

function test()
    MPI.Init() # MPI初期化
    comm = MPI.COMM_WORLD
    nprocs = MPI.Comm_size(comm)
    myrank = MPI.Comm_rank(comm)

    jmax=11
    imax = 100
    sizes = zeros(Int64, nprocs)
    if myrank == 0
        for j=0:nprocs-1
            jsta, jend = parallel_range(1, jmax, nprocs, j)
            sizes[j+1] = imax*(jend-jsta+1)
        end
        println("sizes=", sizes, ", ", sum(sizes))
    end
    ista, iend = parallel_range(1, jmax, nprocs, myrank)

    A = Array{Int}(undef, imax, iend-ista+1)

    #println("A, myrank", A, ", ", myrank)
    if myrank == 0
        Aall = ones(Int, imax, jmax)
        for j=1:jmax
            for i = 1:imax
                Aall[i, j] = j
            end
        end
    end

    if myrank == 0
        MPI.Scatterv!(VBuffer(Aall, sizes), A, 0, comm)
    else
        MPI.Scatterv!(nothing, A, 0, comm)
    end

    println("A, myrank", A[1,:], ", ", myrank)

    MPI.Finalize()
end

function parallel_range(n1, n2, nprocs, irank)
    nb = div(n2-n1+1, nprocs)
    nm = (n2-n1+1)%nprocs
    ista = irank*nb+n1 + min(irank, nm)
    iend = ista+nb-1 
    if nm > irank
        iend = iend+1
    end
    return ista, iend
end

@time test()
```

実行結果。rank 0には600要素，rank 1には500要素入っています。

```bash
$ mpirun -n 2 julia MPI-scatterv.jl 
sizes=[600, 500], 1100
A, myrank[1, 2, 3, 4, 5, 6], 0
A, myrank[7, 8, 9, 10, 11], 1
  0.340811 seconds (273.49 k allocations: 15.830 MiB, 53.23% compilation time)
  0.358422 seconds (273.54 k allocations: 15.841 MiB, 50.95% compilation time)
```
Next.jsで実装 SPAでキャッシュ更新の時に便利な方法

SWRで十分な場面もありますが、今回僕はSWRが認証トークンの関係上使えなくて、そしてデプロイ後に更新した分が反映されなくて困った時にうまくいったので載せようと思います。

`next.config.js`に以下を追記

```js
  generateBuildId: async () => {
    const date = new Date()
    const Y = date.getFullYear()
    const M = ('00' + (date.getMonth() + 1)).slice(-2)
    const D = ('00' + date.getDate()).slice(-2)
    const h = ('00' + date.getHours()).slice(-2)
    const m = ('00' + date.getMinutes()).slice(-2)
    const s = ('00' + date.getSeconds()).slice(-2)
    return Y + M + D + h + m + s
  },
```
こうすることで、ビルドした時のディレクトリにビルドした時のDateを入れることができますので、のちに生きてきます。

続いて、

JSファイルを作って、ビルド時のコマンドに＆＆で繋げて実行します

```js
require('dotenv').config()

var fs = require('fs')
const date = new Date()
const Y = date.getFullYear()
const M = ('00' + (date.getMonth() + 1)).slice(-2)
const D = ('00' + date.getDate()).slice(-2)
const h = ('00' + date.getHours()).slice(-2)
const m = ('00' + date.getMinutes()).slice(-2)
const s = ('00' + date.getSeconds()).slice(-2)

var jsonData = {
  deploy: Y + M + D + h + m + s,
}
// ファイルの書き込み関数
function writeFile(path, data) {
  const jsonStr = JSON.stringify(data)
  fs.writeFile(path, jsonStr, (err) => {
    if (!err) {
      console.log('更新成功')
      console.log(data)
    }
  })
}

function main(path, input) {
  writeFile(path, input)
}

//実行例
main(`build/deploytimestamp.json`, jsonData)
main(`public/deploytimestamp.json`, jsonData)

```
dotenvは.envを使うためにインストールしておきましょう。

あとは、`deploytimestamp.json`のファイルをfetchしていきます。
その際にとても大事なのはfetchしているファイルへのキャッシュを更新させることです。

```js
    const hash = new Date().getTime()
    fetch('/deploytimestamp.json?' + hash) //ここです
      .then((res) => res.json())
      .then(
        (result) => {
          // JSONの内容が受け取れる
        },
        (error) => {
          console.log(error)
        }
      )

```
イメージは上記のようにqueryにDateを合体させていただければできるかと思います。

同じ悩みを持った方のアイデアの力に慣れたら嬉しいです。
【学習記録⑭】transition-groupを用いてリストのトランジションを実装する！

# はじめに
Vue.jsを最近勉強し始めたので学んだ文法などを備忘録としてメモしていこうと思います。
今回は`transition-group`を用いて`v-for`等の複数のタグが作成される場面でトランジションを実装していきたいと思います。

## transition-group
`transition-group`は`v-for`属性等を用いて複数のタグが作られる際にそれらに対してまとめてトランジションを適用したい場合に付けます。
例えば以下の場合、`transition`タグで囲っても正常にトランジションは動作しません。

```vue:example.vue
<li v-for="number in numbers" :key="number">
  {{ number }}
</li>
```

https://v3.ja.vuejs.org/guide/transitions-list.html

また、`transaction-group`タグを用いる際は必ず`key`属性を付ける必要があります。

https://v3.ja.vuejs.org/guide/migration/key-attribute.html

## 以上を用いてサンプルを作ってみる
以上を用いてサンプルを作ってみます。
内容としては、初期状態で画面上に数字の「1,2,3」があり、数字追加ボタンをクリックすると4以降の数字が順番に追加され、対象の数字にカーソルをあててクリックするとその数字が削除されるというものとなっています。

```vue:App.vue
<template>
  <numbers></numbers>
</template>

<script>
import Numbers from "./components/Numbers.vue";

export default {
  components: {
    Numbers
  },
};
</script>
```

```vue:Numbers.vue
<template>
  <button @click="addNumber">数字追加</button>
  <transition-group name="fade">
    <li v-for="(number, index) in numbers" :key="number" @click="remove(index)">
      {{ number }}
    </li>
  </transition-group>
</template>

<script>
export default {
  data() {
    return {
      numbers: [1, 2, 3],
      nextNumber: 4,
    };
  },
  methods: {
    addNumber() {
      this.numbers.splice(this.numbers.length, 0, this.nextNumber++);
    },
    remove(index) {
      this.numbers.splice(index, 1);
    },
  },
};
</script>

<style scoped>
.fade-enter-from {
  opacity: 0;
}
.fade-enter-active {
  transition: opacity 0.5s;
}
.fade-enter-to {
  opacity: 1;
}
.fade-leave-from {
  opacity: 1;
}
.fade-leave-active {
  transition: opacity 0.5s;
}
.fade-leave-to {
  opacity: 0;
}
</style>
```

## 結果
以下のようにボタンをクリックしたら数字が追加され、数字をクリックしたらその数字が消えることが分かります。
![Videotogif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538249/5a41588d-ab6d-a3f4-6ca3-b62c3552078d.gif)

# おわりに
`transition-group`を用いてv-for属性がセットされた要素に対してまとめてレンダリングをすることが出来ました。
`transition`は結構難しいですがしっかり理解していきたいと思います。
ABC225　チャレンジ結果

ABC225結果：AB(3)C3完
今回から後半問題の取り組みも期待してC++でやってみた...が手にまだ馴染んでないようで途中からPythonに切り替えたりとてんやわんやであった.

A：ちょっとした高校数学. 3! = 6 or 3!/2! = 3 or 3!/3! = 1のいずれか.

```c++:Distinct_Strings.cpp
#include <iostream>
#include <vector>
#include <algorithm>
#include <set>

using namespace std;

int main(){
    set<char> L;
    string S;
    cin >> S;
    
    for (int i=0;i<3;i++){
        L.insert(S[i]);
    }
    
    int sz = L.size();
    //cout << sz;
    if (sz == 3)
        cout << 6;
    if (sz == 2)
        cout << 3;
    if (sz == 1)
        cout << 1;
}
```

B：入力されたタイミングでその情報を格納すれば瞬殺だった. だが入力を愚直にvectorに入れ, vectorの要素の重複個数を数え, それがN-1になったとき...とやってるとTLEを喰らいました. B問題でかつC++で書いてTLEは焦りを隠せなかった.

```c++:Star_or_Not.cpp
#include <iostream>
#include <vector>
#include <algorithm>
#include <set>
#include <map>

using namespace std;

int main(){
    int N;
    cin >> N;

    vector<int> a;
    map<int, int> T;
    for (int i=0;i<N-1;i++){
        int ai, bi;
        cin >> ai >> bi;
        T[ai]++;
        T[bi]++;

        //a.push_back(ai);
        //a.push_back(bi);    
    }

    for (int i=1;i<=N;i++){
        if (T[i] == N-1){
            cout << "Yes" << endl;
            break;
        }
        else if (T[i] >= 2){
            cout << "No" << endl;
            break;
        }
    }
}
```

C：Bで焦ってC問題は馴染んでるPythonでやることに. やっぱPythonすんげえ楽

```python:Calendar_Validator.py
N, M = list(map(int, input().split()))
B = []
for i in range(N):
    X = list(map(int, input().split()))
    B.append(X)

O = B[0][0]
n = (O - 1) // 7 + 1
m = (O - 1) % 7 + 1

flag = True
C = []
if m + M > 8:
    flag = False
    print("No")

else:
    for i in range(N):
        Y = [O + 7 * i + j for j in range(M)]
        if Y != B[i]:
            flag = False
            print("No")
            break
    
if flag == True:
    print("Yes")
```

Dは連結リストの考え方そのままやん！！と思いながらもコードに落とせず無念.
レートはちょっと上がってギリギリ茶色になりました.
最近停滞気味なので次こそは！
Macで競プロの環境構築(C++)する

競プロをやってみたいなと思ったので、macで競プロをやるためにC++の環境構築をしてみます。

まず、競プロのC++のコンパイラにはClang系とgcc系の二つがあるらしく、macではデフォルトのC++のコンパイラとしてClang系が標準で搭載されています。

しかし、競プロ視点からClang系とgcc系のコンパイラどっちが良いかというとgcc系のコンパイラの方が良いそうです。

理由はgccにのみstdc++.hというC++の標準ライブラリの集合体が入っており、#include <bits/stdc++.h>一行書くと、必要なライブラリがだいたい揃う。からだそうです。

そのため、今回は
Macにgcc系のC++のコンパイラを入れることを目標にやっていきます。

# gccをインストールします。
以下のコマンドでインストールすることができます。

````terminal
brew install gcc
````
インストールすると、/usr/local/下に、g++-11というファイルができます。

![Screen Shot 2021-10-31 at 16.49.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656522/b918077d-7b0e-26fd-6ac4-101f5690c199.png)

# pathの設定
gccをインストールすると、mac上にはclangと、gccが同居している状態になります。
clang => /usr/bin/g++
gcc => /usr/local/bin/g++-11

この状態でg++コマンドを打つとclangの方が呼び出されます。

````terminal
$ which g++
/usr/bin/g++
``

gccの方を呼び出せるようにしたいので、以下のコマンドを入力します。

````terminal
$ ln -s /usr/local/bin/g++-11 /usr/local/bin/g++
````

このコマンドは/usr/local/bin/にg++(gcc)のシンボリックリンクを作成するためのコマンドです。

lnコマンドについては[こちら](https://qiita.com/jinnai73/items/3fdb841465cf200dda87)の記事が大変わかりやすかったです
少しこちらの記事でも解説をすると、lnコマンドとは、同じiノードをもったファイル(リンク)を作成するためのコマンドです。
iノードとは、ファイルとディスク上に存在するファイルの実体データを対応させる番号のことです。

lnの-sのオプションを付けるとシンボリックリンクというものを作成することができ、リンクを作成するというとシンボリックリンクを指すことが多いです。

ハードリンクはiノード番号をリンクさせるのに対して、シンボリックリンクはフォルダのリンクを作成することができます。
こちらの違いを詳しく知りたい人は、[こちら](https://penpen-dev.com/blog/symbolic-link-hardlink-tigai/)の記事を参考にするのが良いと思います。(自分には少し難しかったです。。)

シンボリックリンクを作成した後に、ターミナルを再起動するとg++コマンドを叩いた時にgccの方を呼び出すことができるようになります！

````terminal
$ which g++
/usr/local/bin/g++
````

元に戻したい場合は

````terminal
$ rm /usr/local/bin/g++
````

というコマンドを打つと元に戻ることができます。

**※なぜ、`$ ln -s /usr/local/bin/g++-11 /usr/local/bin/g++`のコマンドを打つとg++の呼び出す方がgccに変わるのか?**

答えは`$PATH`の優先順位が`/usr/bin`よりも`/usr/local/bin`の方が高いからです。

`$PATH`の優先順位は

````terminal
$ echo $PATH
````

で見ることができます。

先にあるパスの方が優先的に呼び出されます。

今回で言うと、
`/usr/local/bin/g++`と`/usr/bin/g++`

この二つのパスでは`/usr/local/bin/g++`のパスの方が優先順位が高いのでg++コマンドを打つと`/usr/local/bin/g++`が呼び出されます。

これでコンパイルの設定は終わったので、次はvscodeに移動します。

# code-runnerという拡張子をインストールする
vscodeのcode-runnerという拡張子をインストールしてください。
インストールしvscodeを再起動したら、vscodeの設定も完了です。

# 動作確認をする
最後にうまく行くかの動作確認を行いましょう。
vscodeでmain.cppというファイルを作り、以下コードをコピペしてください

````main.cpp
#include <bits/stdc++.h>
using namespace std;
int main(){
    int a, b;
    cin >> a;
    cin >> b;
    cout << a + b << endl;
}
````

そして、`control + option + n`コマンドを叩くと、
![Screen Shot 2021-10-31 at 17.56.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656522/2cd61130-eee9-9860-8f88-db1801f5cf1e.png)

画像のように自動でコンパイルしてくれて、正しく動いていることが確認できると思います！

これで環境構築の完成です！！

# おまけ
vscodeでc++を書くときは**C/C++**という拡張子も入れておきましょう！
この拡張子を入れると
コードフォーマットと、自動補完をしてくれます。
AWS boto3サンプルコード

# はじめに
boto3でAWSリソースにアクセスするサンプルコードの覚書きです。
随時更新予定

# S3
S3のサンプルコード集
## KeyObjectの全取得
指定バケットのすべてのObjectをListで取得します。
取得する方法としてresourceとclientの2通りあります。resourceのほうが記述がシンプルで処理が高速とのこと。
### resource
バケット内のファイルオブジェクトをListで取得します。
取得するオブジェクトにはフォルダオブジェクトが含まれるため末尾が`/`であることを判定して除外しています。

```python：sample.py
from typing import List
import boto3
s3_resource = boto3.resource("s3")
def get_bucket_keys(bucket: str, key_prefix: str = "", **kwargs) -> List[str]:
    params = {"Prefix": key_prefix}
    params.update(kwargs)
    objects = s3_resource.Bucket(bucket).objects.filter(**params)
    return [o.key for o in objects if not o.key.endswith("/")]
```
詳細はドキュメント参照：
https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html#S3.Bucket.objects

### client
list_objects_v2は一度に最大1000件まで取得するので、バケット内のObjectをすべて取得するにはTokenで制御する必要があります。

```python：sample.py
from typing import List
import boto3
s3_client= boto3.client("s3")
def get_s3_objects(bucket: str, key_prefix: str = "", **kwargs) -> List[dict]:
    result: list = []
    params: dict = {"Bucket": bucket, "Prefix": key_prefix}
    params.update(kwargs)
    while True:
        response = s3_client.list_objects_v2(**params)
        if "Contents" in response:
            result.extend(response["Contents"])
        if "NextContinuationToken" in response:
            params["ContinuationToken"] = response["NextContinuationToken"]
        else:
            break
    return result
```
Contentsには、ObjectKey名のほかSizeなどが含まれます。
Contentsの内容は公式ドキュメント参照：
https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html#S3.Client.list_objects_v2

#### KeyObjectの全取得(応用)
clientで得た結果をファイル名とファイルサイズに整形するサンプル。
結果にはフォルダタイプのオブジェクトが含まれているので除外し、ファイルサイズは人読みやすいようにマネジメントコンソール画面での表記(ex: 12.3 KB)でフォーマットします。

```python：sample.py
def get_s3_files_size(bucket: str, key_prefix: str = "", **kwargs) -> dict:
    objects = get_s3_objects(bucket, key_prefix, **kwargs)
    # Remove objects end with "/", means not file.
    return {
        o["Key"]: set_number_unit(o["Size"])
        for o in objects
        if not o["Key"].endswith("/")
    }

def set_number_unit(num: int) -> str:
    units = {
        "TB": 1024 ** 4,
        "GB": 1024 ** 3,
        "MB": 1024 ** 2,
        "KB": 1024,
        "B": 1,
    }
    for unit, size in units.items():
        if num >= size:
            return f"{(num/size):.1f} {unit}"
    else:
        return f"{num} B"
```
LINE Message API でメッセージするテスト

タイトルの通りですが、初めてやったので、メモです。

##LINE Developerの登録　→　チャネル作成
いろんなところに記事がありますので、省略しますが、
ログイン後、「プロバイダ」を作り、「チャネル」（BOTですね）を作ります。

###アクセストークンの取得
「Message API」タブの下のほうで、「チャネルアクセストークン（長期）」を取得しておきます。
また、
「チャネル基本設定」タブの下の方の「あなたのユーザID」を控えておきます。


##メッセージするプログラム
今回は、Pythonで作ってみました。
Macで作ったんですが、ちょっと手間取りました。

###ライブラリのインストール
line-bot-sdkをインストールします。

```
% pip install line-bot-sdk
% pip show line-bot-sdk
```

###ソース
「line-push.py」として保存しました。

```
import sys
sys.path.append('/Users/[ほげほげユーザー]/Library/Python/3.8/lib/python/site-packages')

from linebot import LineBotApi
from linebot.models import TextSendMessage
from linebot.exceptions import LineBotApiError
 
LINE_ACCESS_TOKEN= "アクセストークン"
LINE_USER_ID= "自分のチャネルのUser_id"
 
line_bot_api = LineBotApi(LINE_ACCESS_TOKEN)
 
text_message ="テストでメッセージを送るのです。"
try:
    # User_idは配列で指定します。
    line_bot_api.multicast(['送りたい人のUser_id'], TextSendMessage(text=text_message)
)
except LineBotApiError as e:
    # エラーのとき
    print(e)

```

最初、１−２行目がなかったんですが、動かなくって、いろいろググった結果、前項の ``% pip show line-bot-sdk`` コマンドで確認したパスを、行頭に付け足すことで改善しました。

「送りたい人のUser_id」　には、別投稿で取得したUser_idを入れます。


##実行

```
% python3 line-push.py
```

送信できました！　やったー。
おしまい。
Next JS での TypeError: Failed to construct 'URL': Invalid URL

# エラーメッセージ
TypeError: Failed to construct 'URL': Invalid URL nextjs

``` 

import Image from "next/Image";

...
...
    <Image
        className={stack.landingImage}
        src="/images/hoge.jpg"
        alt="hoge"
        layout="fill"
        objectFit="cover"
        objectPosition="center"
     />
```

next/Imageでのエラー。

## 原因

不明。
いくら検索してもパッケージにまつわる話しか出てこなく、また、特に該当ソースやコンフィグファイルをいじっていないに関わらず例外を投げられるようになったため、パッケージマネージャー関連の問題と予想。

## 解決

結局。プロジェクト全体を作り直して解決した。

やはりパッケージのバージョンの依存関連だろう。