OmniAICreator/Qiita-1.07M huggingface dataset:
Youtubeの広告を簡単にスキップするChrome拡張 - YoutubeAdSkipper

:::note alert
(2024/01/04 追記)
2023秋ごろがら行われたYoutube playerの仕様変更により、本拡張は機能しなくなりました。もろもろの事情により(詳細は後述)、本拡張のUpdateは断念し、公開は中止します。
:::
自分用として作って、特に拡散することもしてなかったので、ほかに使っていた方がいたのかもわかりませんが、もしいらっしゃったら申し訳ございません。

# 2023秋以降のYoutube Player仕様変更について
本拡張が最初に動かなくなった10月くらいだったでしょうか。そのときはSkipボタンのclass名が変更になったことが判明してすぐに修正したのですが、その後さらに動かなくなりました。原因は不明のままManifestがv2のままのせいかとも考えて、v3へのUpdateと併せて年始のお休み中に修正を試みました。
結果、v3へのUpdateはできたのですが、やはり動きません。Skipボタンに対するclick()を実行していることは確認したのですが、なぜか広告がSkipできません。いろいろネットを調べて行き当たったのがこちらのサイト。
[YouTubeの「広告ブロッカーブロック機能」が出ると、それを回避する広告スキップ拡張が公開されるという無限イタチごっこ](https://note.com/tokuriki/n/n2a89c5839a78)
なんか、私の知らないところで広告ブロッカーとYoutube側の暗闘が行われたみたいですね。厳密には私の拡張は広告をブロックするのではなく、ユーザーに許される範囲で自動でスキップする(あえてWait時間をいれたりしています)機能なんですが、どうもその戦いのあおりを食らったようです。
Chromeストアには、まだ広告ブロックを謳う拡張もあるようですが、すでに機能しないのか、なんらかの逃げ道を見つけているのかわかりません。ま、Web系のアプリに関しては素人な私には手に負えそうにないし、上記のリンクになるようなYoutubeの利用規約にも抵触する恐れがあるので、対応を断念した次第です。

# 開発の動機
Youtubeをながら見しているとき、表示される広告をスキップするのが面倒くさくなるときありませんか? 私は、いちいちマウスを操作してクリックするのが面倒くさくて、せめてキーボードショートカットでも、と思って、いろいろ探してみたんですが、Chrome拡張にも見当たらず、いっそのこと作ってみるかというのが始まりです。ショートカットキーだけでは寂しいので、自動でスキップする機能も実装することにしました。

# 機能
* Youtube playerに表示される広告を自動でスキップします。
* 手動で直ちに広告をスキップするショートカットキーを追加します。

# インストール方法
YoutubeAdSkipperはまだパッケージ化していません。githubのレポジトリから直接ダウンロードして、インストールしてください。
1. 以下のレポジトリにアクセスして、ZIPファイルをダウンロードします。 
 ~~h ttps://github.com/oyajizap/YoutubeAdSkipper~~
2. ダウンロードしたZIPファイルを、ローカルストレージの適当なフォルダに解凍します。
3. Chromeの拡張機能設定画面を開き(アドレスバーに"chrome://extensions"と入力します)、デベロッパーモードを有効にします。
4. 「パッケージ化されていない拡張機能を読み込む」をクリックし、先ほど解凍したフォルダを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1464597/f33abbc5-a8cb-b13e-702f-fe626a301abd.png)

必須ではありませんが、拡張機能のアイコンをクリックして、本拡張機能のアイコンを「固定」しておくことをお勧めします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1464597/801913d4-3808-bc18-84ad-95f23b98b054.png)

# 使用方法
auto skipモードが有効の間は、スキップ可能な広告が表示されてから指定された時間の経過後、自動でスキップします。また、以下のショートカットキーが使用可能です。

* 's' キー :: auto/manualモードの両方で、直ちに広告をスキップします。
* 'Shift+s'キー :: auto/manualモードをトグルします。モードのトグルは、マウス右クリックで表示されるコンテキストメニューからも可能です。

デフォルトのモードと、自動スキップでのタイマーは、本拡張の設定画面で変更可能です。

# 注意事項
この拡張は、Youtube.comでしか機能しません。ほかのサイト上での、組み込みYoutubeプレーヤーでは機能しません。

動画の最初にアンケート形式の広告が表示されることがありますが、その形式はサポートしていません。

本拡張のアイコンの作成には、以下のサイトを利用して作成させていただきました。なかなかおしゃれなアイコンを、解像度や色を自由自在に変更して作成できるので、とても使いやすいです。

https://icooon-mono.com/

# その他もろもろ 
Youtubeの広告による収益モデルを尊重して、あえて一定期間は広告を表示するようにしています。もっと短いほうが良い方は、設定でタイマーの値を変更してください。
Chromeウェブストアへの公開は現在保留中です。ある程度需要があるようなら公開したいと思っています(デベロッパー登録料は大した金額ではないんですが、お金払って誰も使ってくれないと悲しいので…)。
何分にもChrome拡張を作るのも初めてなら、JavaScript自体もほぼ初めて触る感じなので、お見苦しい点もあるかもしれませんが、なにとぞご容赦ください。要望や改善点など教えていただければ大変助かります。
pi picoでmicropython その27

#概要

picoでmicropythonやってみた。
pioasmでLチカやってみた。
osr 使ってみた。

#サンプルコード

```

import time
from machine import Pin
from rp2 import PIO, StateMachine, asm_pio
@asm_pio(set_init = PIO.OUT_LOW)
def tic():
   pull()
   set(pins, 1)
   mov(x, osr)
   label("loop0")
   nop()
   jmp(x_dec, "loop0")
   set(pins, 0)
   set(x, 31)
   label("loop1")
   nop()
   jmp(x_dec, "loop1")
sm = StateMachine(0, tic, freq = 1000, set_base = Pin(25))
sm.active(1)
while True:
   sm.put(10)
   time.sleep(0.5)
   sm.put(20)
   time.sleep(0.5)
   sm.put(40)
   time.sleep(0.5)
   print(".")


```


以上。
【Laravel】Laravelでプロジェクトを作成する手順

Laravelでプロジェクトを作成し開発を進めていく手順をまとめておきます。
諸々のインストール手順などは割愛します。

###  laravelプロジェクトの作成
```
$ compoaser create-project laravel/laravel app
```
このコマンドでプロジェクトの作成ができる。

```
$ php artisan serve
```
このコマンドでlocalhostでサーバーが起動される。
![スクリーンショット 2021-05-16 16.17.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/628093/1783229d-fa54-29e2-6385-454f3526bd9b.png)
OctoberCMS 管理画面実装テク：シンプルなリソースの権限管理を実装する

# 概要
先日[こちらの記事](https://qiita.com/pikanji/items/968b1b95481fe58b7aef)でLaravel Authorization Policyを使った管理画面におけるリソースアクセス制限について書きましたが、シンプルな権限管理であればモデルのイベントフックの方がよっぽどシンプルに実装できたのでメモ。`Backend.Behaviors.FormController`を実装しているコントローラを対象とします。

# やり方
## モデルイベントをフック

下記の例ではProductというモデルデータがロードされたタイミング（`model.afterFetch`イベント）で

```php
Product::extend(function ($model) use ($user) {
   $model->bindEvent('model.afterFetch', function () use ($model, $user) {
       if (/* $modelと$userをつかって権限チェックをするロジックをここに記述 */) {
           // アクセス権がないときにtrueになるようにして、アクセス権なしだと例外を投げる
           throw new NoAccessRightToResourceException("アクセス権がありません");
       }
   });
});
```

ドキュメントではモデルのイベントフック登録は基本的に `Plugin::boot()` に記述すると書かれているが、結局は使用される前に登録されていればよい。本記事の場合、管理画面でのみ使用したいので、管理画面のコントローラのコンストラクタに記述すれば十分間に合う。

そして、権限がなかった時の処理を例外ハンドラとして登録する。こちらも同様にコンストラクタに記述するので十分。

```php
App::error(function (NoAccessRightToResourceException $exception) {
    // アクセス権がない時の処理
    Flash::error($exception->getMessage());
});
```

基本的にはこれだけなのだが、これだけだと例外が上記で登録した例外ハンドラまで届かない場合がある。ここが落とし穴。

`\Backend\Behaviors\FormController::update` を見ると `catch (Exception $ex)` で全ての例外がキャッチされて`$this->controller->handleError($ex);` でハンドルされてしまっている。つまり、このままだと上記のようにApp::errorで登録したハンドラまで例外が届かない。なので、このhandleErrorメソッドをオーバーライドしてハンドラに登録した例外の場合はthrowし直すようにする。

```php
public function handleError($exception){
    if ($exception instanceof NoAccessRightToResourceException) {
        // 例外を投げ直してApp::errorで登録したハンドラでハンドルさせる
        throw $exception;
    } else {
        parent::handleError($exception);
    }
}
```

以上
Mysql2::Error: Unknown column 'create_at' in 'order clause' の解決法


ミニアプリ製作中。一通りの実装を終えてlocalhout:3000を立ち上げるとタイトル文のエラーに。’create_at’なんて知らないよと仰られてるご様子。投稿を降順に設定した際に以下のように記述していました。

```
def index
    @tweets = Tweet.all.order(create_at: :desc)
    
  end
```

正しくは

```
def index
    @tweets = Tweet.all.order(created_at: :desc)
    
  end
```

でした。
ZipBombと疑われるExcelの圧縮率はどれくらいなのか試してみた

###ZipBombとは
https://ja.wikipedia.org/wiki/%E9%AB%98%E5%9C%A7%E7%B8%AE%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E7%88%86%E5%BC%BE

こういうものらしい。

>
高圧縮ファイル爆弾（こうあっしゅくファイルばくだん）とは、それを読み込んだプログラムやシステムをクラッシュさせる、あるいは負荷により使用不能とするために作られた悪意のある圧縮ファイルである。

###Apache POIでは圧縮率や最大サイズ（4GB）をチェックしてるらしい
ドキュメントより
https://poi.apache.org/apidocs/4.1/
Class ZipSecureFile



>
setMinInflateRatio
public static void setMinInflateRatio(double ratio)
Sets the ratio between de- and inflated bytes to detect zipbomb. It defaults to 1% (= 0.01d), i.e. when the compression is better than 1% for any given read package part, the parsing will fail indicating a Zip-Bomb.


>
setMaxEntrySize
public static void setMaxEntrySize(long maxEntrySize)
Sets the maximum file size of a single zip entry. It defaults to 4GB, i.e. the 32-bit zip format maximum. This can be used to limit memory consumption and protect against security vulnerabilities when documents are provided by users.


ということで、

* 圧縮率 １％以上はZip-Bomb
* ４GB以上はメモリを食うからダメ

これがデフォルトの設定になっているらしいです。

###許容する圧縮率を上げる

```java
// エクセルを開く前に
ZipSecureFile.setMinInflateRatio(0.001);

try(エクセルファイルを読むこむコード){

...

}

// 処理が終わったら戻しておく
ZipSecureFile.setMinInflateRatio(0.01);

```

これでエクセルファイルがPOIで開いて扱えるようになります。


###圧縮率ってどんなもの？

|ファイル・フォルダ名|サイズ|
|----|----|
|適当な文字列.xlsx|0.42MB|
|適当な文字列|4.98MB|
|適当な文字列(関数あり).xlsx|1.08MB|
|適当な文字列(関数あり)|13.5MB|

1. .xlsxで保存
1. 拡張子をZipに変更
1. Zipファイルを展開

この手順でファイルサイズ、フォルダサイズがどうなるか調べました。


この結果だけ見ると、0.01（１％）まで圧縮されていない感じがしますね。

仕事で扱ったものについてはまだ検証していないのでですが、今回の結果では0.08~0.06ぐらいの圧縮率のようです。

とりあえずログに

```
Zip bomb detected!
```


が出力されていれば、圧縮率の問題なので、

```
ZipSecureFile.setMinInflateRatio(0.01);
```

これをエクセルを開く前に実行すれば開けるはず！

###参考にしたサイト
https://www.ne.jp/asahi/hishidama/home/tech/apache/poi/workbook.html
Seleniumでクリック前に要素にスクロールさせる

Selenium(Python)で要素をクリックする直前に、毎回要素までスクロールさせる処理を行うためのコードです。
このGoogle検索でスクロール処理させる必要は本来ないはずですが、例として書いています。

```python:test.py
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.support.events import EventFiringWebDriver, AbstractEventListener

#要素をクリックする直前の処理を定義
class CustomListener(AbstractEventListener):
    def before_click(self, element, driver):
        # 要素までスクロールさせる
        driver.execute_script('arguments[0].scrollIntoView({behavior: "smooth", block: "center"});', element)

# Webdriver ManagerでChromeDriverを取得
base_driver = webdriver.Chrome(ChromeDriverManager().install())
driver = EventFiringWebDriver(base_driver, CustomListener())

# Google検索で「Selenium」の検索結果を1〜10ページ目まで表示
driver.get('https://www.google.com/search?q=selenium')
for i in range(2, 11):
    driver.find_element_by_xpath("//a[@aria-label='Page " + str(i) +"']").click()

driver.close()
driver.quit()
```

### 参考
- [あまり知られてなさそうなメソッド element.scrollIntoView()](https://qiita.com/amamamaou/items/728d571d508347b2bc82)
- [Element.scrollIntoView() | MDN](https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView)
- [【Python】before_click/after_click・・・要素がクリックされる直前/直後の処理を実施する | Selenium クイックリファレンス](https://www.seleniumqref.com/api/python/event/Python_after_click.html)
Herokuコマンドでいちいちアプリ名を入力するのが面倒、アプリ名を省略したいとき

前提
Heroku CLIがインストールされている。
Herokuでデプロイしているアプリのディレクトリにいる。


コマンドでHerokuを操作する際に

```
heroku config
```

上記のようなコマンドを入力すると

```
 »   Error: Missing required flag:
 »     -a, --app APP  app to run command against
 »   See more help with --help
```

ターミナルで -a YOURAPPNAMEもしくは --app YOURAPPNAME をつけてコマンドを入力してと言われる。

毎回アプリ名をコマンドと一緒に入力するのは面倒。

これが起きる原因はおそらくgitのリモートリポジトリにHerokuが追加されていないから。
もしSoucetreeを使っているなら
リモートにHerokuがないはず。

![スクリーンショット (25).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/990603/1bbc889e-7254-23a6-6489-9f75085c8fd3.png)

アプリ名を入力しなくて済むようにするには次のコマンドを実行。

```
heroku git:remote -a YOURAPPNAME
```

参考になった記事

https://qiita.com/kenose0328/items/6e89f1f20e7b5cfda6d9
非マネジメントのパッケージエンジニアが考える製品の設計思想について

長らく保守し続けられているパッケージの開発に従事していると、
当時のレビューでどんな議論がされたのか分からず、
また担当のエンジニアがどういう思想や状況で開発したのかが理解できないことがよくある。

この点に関して、非マネジメントである私のようなエンジニアが、
パッケージを長く保守し続けていくうえで重要だと考えていることについて考えていることをアウトプットしてみる。

<a href="//af.moshimo.com/af/c/click?a_id=2607720&p_id=2898&pc_id=6652&pl_id=37289&guid=ON" rel="nofollow" referrerpolicy="no-referrer-when-downgrade"><img src="//image.moshimo.com/af-img/0697/000000037289.png" width="668" height="60" style="border:none;"></a><img src="//i.moshimo.com/af/i/impression?a_id=2607720&p_id=2898&pc_id=6652&pl_id=37289" width="1" height="1" style="border:none;">

# 老舗パッケージのジレンマ

たびたび**「このサブシステムのXXXという機能なのですが、YYYのように動きます。なぜですか？ZZZという理由により不要な仕様に見えます」**のような質問をされることがある。
10年、20年保守開発をしているプロダクトにはよくある話かもしれない。
しかし、現在担当しているエンジニアは即答できない場合が多い。

その理由として以下3点が考えられる（少なくとも私が即答できない理由）

- 1つ目は、今現在、そのサブシステムは問題なく運用されているので、YYYという動きの存在意義（なぜこういう設計になっているか）がわからないこと
- 2つ目は、実装された当時の「判断」と「根拠」がどこにも残っていないこと
- 3つ目は、そのプロダクトのその機能の仕様がわかりにくく複雑であること

# 当時の設計思想がわからない


スタートアップのプロダクトではない老舗パッケージは、
設計開発したエンジニアがすでに退職しており、
ドキュメントもまともに残っておらず、
**ソースコードがすべて**ということがよくあると思う。

ゆえに、保守担当のエンジニアは、
自分なりにサブシステムの役割や使われ方を理解し、学び、
そこから仕様を推定するしかない。

それゆえ「どういう意図でこうなっているの？」と質問されたら、
**「XXXXという業務で、YYYYのように使われているという想定なので、こうなっていると思われます」**
という回答で終わる。

だから、自分が生み出すのにかかわったサブシステムや機能以外は
フロントのメンバーにはいつもこのように回答している。

これは変えられない過去をいくら議論しても無理なので、
これからこうならないように変えていこうと努力している。


# 当時のレビューの議事録が残っていない

議事録を取る文化は重要だし尊重されるべきだ。理想は一言一句。
その議事録を見れば、レビューの情景が思い浮かび、何年も前のレビューに自分が参加しているかのような体験ができる。

しかし、往々にして、出荷フローに乗らない議論は残っていないことが多い。
そして、そこにこそエンジニアの考えや、思想、メンバー間の議論があり、最も残しておくべき情報であると考える。

出荷プロセスの中で、エンジニアは何度もレビューを重ねることが多い。
ルールとして定められているレビューも複数存在する。
しかしそれはほとんどが「進捗報告」「決定事項の説明」であって、
「議論」の余地はほとんどない。
それ故に

- 「設計レビュー」
- 「修正内容レビュー」
- 「テストケースレビュー」

などと名前がつくものは
**「完成品お披露目の場」** であり、 **「途中の試行錯誤」** は適度に省かれていることも多い。

このレビューの議事録があったところで、「そんなのは仕様書見返せばわかるよ」となる。

私が考えているのは

- 当時どんな紆余曲折があり、今の仕様に決定されたのか
- ボツ案は何個あって、どんな内容だったのか

そっちのほうが、実は興味深く、知っておくべき製品の背景である。

 

# プロダクトの成長と、当時の最適解は必ずしも一致しない


20年以上の大規模老舗パッケージともなると、
内部構造は当然のことながら、
機能コンセプトも時代に沿わなくなってくる。

当然時代にあわせて機能追加、機能改善をすべきである。

「出荷当時こうだったから、こうで行きます」
「出荷当時こうだったから、こうなっているので納得してください」
「基盤がこうだから、こうで行きます」

のような議論は時代とともに見直すべきである。

弊社のプロダクトは業務カバー率を売りにしてきたが
それ故に、UI/UXがおろそかにされてきた面がある。

今の時代「機能網羅性」よりも、「UI/UX」が洗練されていて、「すぐに使える」ほうが時代に沿っていると思う。


例えば、
入力負荷の軽減が**「2回以上入力させない」** から **「音声認識」「画像認識」**に変わっているように、
当たり前は見直していく必要がある。

入力項目が大量に並んでいて、保存ボタンがついている画面よりも、
画像読み込みのアイコンやマイクアイコンだけのほうが良かったりする。
複雑でもやりたいことができるんだから設定頑張れ！ではいずれ追っ手に追いつかれる。


BtoBでもリーディングカンパニーを目指す以上、
BtoCのモダンな技術に追従すべく、当たり前や常識はアップデートしていかなくてはならない。
そのためにも常に情報を集め、学び、常識を疑う姿勢がエンジニアには大切な点であると考える。

※だからと言って機能網羅性を下げてまで、モダンを追いかけなければならないか？というと、
弊社は1度それで失敗を経験しているので、即実行というよりは、各自が意識しながら設計することが重要ではないか？ということ。

#最後に

私が日々感じていることを雑な文章ながらアウトプットしてみた。
エンジニアとして、

- 顧客の価値を創造する
- 価値創造の速度を高速にする
- 時代の変化に柔軟に対応する

これらを意識し続けることで、
ただの保守開発業務ではなく価値あるエンジニアとしての業務に変わっていくと考えている。

そのためにも、設計思想という面で

- コードは重要だが、コードだけではだめ
- プロセスは重要だが、プロセスをこなすことが重要なわけではない
- 複雑な機能群で難解な仕様は10年前はウケたが、今はウケない

あたりは、意識していきたいところである。
千葉工大上田先生のロボットシステム学講義 youtube 動画リンク

#千葉工大上田先生のロボットシステム学講義 youtube 動画リンク

- [第１回：ロボットシステム開発の変化](https://www.youtube.com/watch?v=twM88vv21LM)
- [第２回：vimtutorとmanを日本語に](https://www.youtube.com/watch?v=8HGNC9Vt96s)
- [第３回：gitとgithub](https://www.youtube.com/watch?v=iXrgyrix0U4)
- [第４回：Unix前後の歴史とOS／オープンソースの役割](https://www.youtube.com/watch?v=DeE7M2wQIic)
- [第５回：プロセスなどLinuxの仕組みについて](https://www.youtube.com/watch?v=twBoOez02w0)
- [第６回：ファイルシステムとデバイスドライバ](https://www.youtube.com/watch?v=IvtRPzEa6JI)
- [第７回：デバイスドライバの作成](https://www.youtube.com/watch?v=xQW8-FNuboo)
- [第８回：ネットワーク](https://www.youtube.com/watch?v=vMeJOdH6UyY)
- [第９回：ソフトウェアライセンス](https://www.youtube.com/watch?v=scg0kewfA74)
- [第１０回：ROS](https://www.youtube.com/watch?v=PL85Pw_zQH0&t=2s)
- [第１０回（補足）：ローンチファイル](https://www.youtube.com/watch?v=MDCQ4oH6Dlc)
- [第１１回：ROS2](https://www.youtube.com/watch?v=QmRhucWxhac)
- [第１２回：Docker](https://www.youtube.com/watch?v=Utvf4YmMJpk)
Laravelで作成したAPIをフロントエンドで受け取り画面へ描画する

## 前提
今回はaxiosを利用して下記URLで作成した一覧取得のapiを受け取って表示するまでを行います。
[LaravelでAPIを作成](https://qiita.com/yu_ku/items/1069290f0cbed2010647)

axiosとは...
バックエンドとのデータのやり取りを簡単にできるライブラリです。

下記コマンドで取得するAPIのパスを確認する

```
php artisan route:list
```

## axiosを利用してみる
tsxファイルに下記を記述する。

```
import React, { useEffect, useState } from "react"
import axios from "axios"

# 型を定義する
type Hoge = {
  id: number
  hoge: string
  fuga: boolean
  created_at: Date
  updated_at: Date
}

const HogePage: React.VFC = () => {
  const [hoges, setHoges] = useState<Hoge[]>([])

  # 確認したAPIを叩いて、データを取得する
  const getHoges = async () =>  {
    const { data } = await axios.get<Hoge[]>('api/hoges')
    console.log(data)
    setHoges(data)
  }

  # ページにアクセスしたら実行する
  useEffect(() => {
    getHoges
  })
}

return (
<>
  <div clasName="inner">
    # 取得したデータを描画する
    <ul className="hoge-list">
      {hoges.map(hoge => (
        <li key={hoge.id}>
          <label className="checkbox-label">
            <input type="checkbox" className="checkbox-input" />
          </label>
          <div><span>{hoge.title}</span</div>
        </li>
      )) }
    </ul>
  </div>
<>
```

下記の記事のようにreactRouterのルーティングになっている前提でlocalhost:8000//hogesへアクセスすると...
Laravelで作成した投稿一覧APIを取得して画面に描画することができました！

[Laravel環境でreactRouterのルーティングを使用できるようにする](https://qiita.com/yu_ku/items/7fa1a372ea29e3d1be93)
【TypeScript】TypeScript の Generics 制約

#Generics型の制約

* Genericsの型引数が、どんな構造の引数でも受け取れてしまう状態では、型によって特定の処理を実行したい場合に暗黙的に失敗してしまいます・・

```ts
//この関数はエラー（Genericsの型が曖昧で、lengthが使えません）
function countAndDescribe<T>(element: T) {
    let descriptionText = '値がありません！';
    if (element.length > 0) { // Property 'length' does not exist on type 'T'.
        descriptionText = '値は' + element.length + '個です';
    }
    return [element, descriptionText];
}
```

* そこで、インターフェースを用意し、インターフェースをextendsして指定したプロパティ(length)を持っていることを保証します
* これで、安全に関数を呼べることになります(^o^)
* extendsキーワードで制約を課すことで、特定の型を気にする必要はなく、特定のプロパティを持つ制約は課すことができます

```ts
interface Lengthy {
    length: number;
}

// Lengthyをextendsしてlengthを持っていることを保証する
function countAndDescribe<T extends Lengthy>(element: T) { // (string | T )[] を返すと推論する
    let descriptionText = '値がありません！';
    if (element.length > 0) {
        descriptionText = '値は' + element.length + '個です';
    }
    return [element, descriptionText];
}

console.log( countAndDescribe('今日もいい天気') ); //安全に関数を呼べる
// ["今日もいい天気", "値は7個です"]

```

```ts
//タプルで戻り値の型を指定することも可能

function countAndDescribe<T extends Lengthy>(element: T)  :  [ T, string ]{ //文字列とその文字の数
    let descriptionText = '値がありません！';
    if (element.length > 0) {
        descriptionText = '値は' + element.length + '個です。';
    }
    return [element, descriptionText];
}

console.log(countAndDescribe(['kitten', 'pawPads']));
// [Array(2), "値は2個です。"]
// 0: (2) ["kitten", "pawPads"]
// 1: "値は2個です。"
```


#keyofによる制約
* `keyof` キーワードでは、オブジェクトのプロパティ名から、 ユニオン型を取得できます

```ts
// obj に keyのパラメータが存在するかどうか不明なので、エラー
function extractAndConvert( obj: object, key: string) {
  return 'Value: ' + obj[key]; //オブジェクトのプロパティにアクセス
}
```
* そこで、`keyof` を使うことで、1個目の型のプロパティに存在するという制約を課せます
    * `U extends keyof T`
    *  = UのプロパティにTが存在
* これで、正しい構造のオブジェクトを受け取ることを保証できます
* 存在しないプロパティにアクセスすることを防ぎます

```ts
// keyofで制約を課す
function extractAndConvert<T extends object, U extends keyof T>(
    obj: T,
    key: U,
) {
    return 'Value: ' + obj[key]; //オブジェクトのプロパティにアクセス
}

//エラーが表示される！
//extractAndConvert({ }, 'name');

// OK
const extractAndConvertedObj = extractAndConvert({ name: 'Neko' }, 'name');
console.log(extractAndConvertedObj) // Value: Neko

```
Laravel環境でreactRouterのルーティングを使用できるようにする

## 前提
reactRouterとTypeScriptで使用するための定義ファイルのライブラリをインストールする。

```
$ npm i -D react-router-dom @types/react-router-dom
```

### reactRouterの定義ファイルを作成する
touch resources/ts/router.tsx

```
import React from 'react'
import {
    BrowserRouter,
    Switch,
    Route,
    Link
} from "react-router-dom"
import TaskPage from './pages/hoges'

const Router = () => {
  return (
    <BrowserRouter>
      <Switch>
        <Route path="/">
          <HogePage />
        </Route>
      </Switch>
    </BrowserRouter>
  );
}

export default Router
```

### resources/ts/index.tsxへ下記を追記する

```
import Router from "./router"

ReactDom.render(
  <Router />
  document.getElementById('app')
)
```

### 現在LaravelのRouterと競合してhomeディレクトリへ遷移してもreactRouterのRouteが反映されないのでweb.phpを下記のように編集する

```
Route::get('{all}', function () {
    return view('index');
})->where(['all' => '.*']);
```

reactRouterで遷移できるようになりました！
Vuetify 文字色変更、サイズ、左寄せ、右寄せ指定

Vuetify でのテキストの色、サイズ、配置場所の変更について、よく忘れてしまうのでメモ。
（公式に書いてあることばかりですが...）

## テキストの色の指定

`class="色名--text"` で色名の変更、
`class="text--{darken/lighten}-番号"`で明暗の指定ができる。
darkenは番号が大きくなると、より暗くなり、
lightenは番号が大きくなると、より明るくなる。

### サンプル

```.vue
          <p>通常</p>
          <p class="indigo--text text--darken-3">indigo--text text--darken-3</p>
          <p class="indigo--text text--darken-2">indigo--text text--darken-2</p>
          <p class="indigo--text text--darken-1">indigo--text text--darken-1</p>
          <p class="indigo--text text--lighten-1">indigo--text text--lighten-1</p>
          <p class="indigo--text text--lighten-1">indigo--text text--lighten-2</p>
          <p class="indigo--text text--lighten-1">indigo--text text--lighten-3</p>
```

![スクリーンショット 2021-05-16 14.44.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147821/21187fcf-9b87-24a2-727b-f694a63cb5e6.png)

色の一覧はこちら
https://vuetifyjs.com/ja/styles/colors/#section-30de30c630ea30a230eb30ab30e930fc


## テキストのサイズの指定

`class="text-value"`
valueの部分に以下のいずれかを入れる。

- h1
- h2
- h3
- h4
- h5
- h6
- subtitle-1
- subtitle-2
- body-1
- body-2
- button
- caption
- overline


### サンプル

```.vue
          <p class="text-h1">text-h1</p>
          <p class="text-h2">text-h2</p>
          <p class="text-h3">text-h3</p>
          <p class="text-h4">text-h4</p>
          <p class="text-h5">text-h5</p>
          <p class="text-h6">text-h6</p>
          <p class="text-subtitle-1">text-subtitle-1</p>
          <p class="text-subtitle-1">text-subtitle-1</p>
          <p class="text-body-1">text-body-1</p>
          <p class="text-body-2">text-body-2</p>
          <p class="text-button">text-button</p>
          <p class="text-caption">text-caption</p>
          <p class="text-overline">text-overline</p>
```

![スクリーンショット 2021-05-16 15.09.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147821/f9cd5744-5ac6-57a6-5960-9a220a2b1890.png)

`text-overline`と`text-button`は大文字になってますね。そういうものなのでしょうか。

## テキストの配置場所

`class="text-場所"`で指定できます。

### サンプル

```.vue
  <p class="text-left">左寄せ</p>
  <p class="text-center">中央</p>
  <p class="text-right">右寄せ</p>
```
![スクリーンショット 2021-05-16 15.15.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147821/f8b1b6f5-cc64-08b9-e375-6f052d0ffc15.png)
Stripe CLIを利用して、Webhookを試す（Laravel版）

homebrewでstripe cliをインストール。

```
brew install stripe/stripe-cli/stripe
```

ログインする。

```
stripe login
```

初回時は下記が表示されるので、エンターを押す。

```
Press Enter to open the browser (^C to quit)
```

ブラウザが開くので、そちらで許可する。

次に`stripe listen`を実行。`localhost:8000/hooks`はエンドポイントのURLを指定。

```
stripe listen --forward-to localhost:8000/hooks --latest
```

>ちなみにイベントをLaravel側に転送したくない場合は、`stripe listen`だけで実行すればログだけ確認できて便利だよ~~~

ターミナルの別タブでAPIリクエストを発行。

```
stripe payment_intents create --amount=100 --currency=jpy
```

ちなみに簡易的にしたいイベントをトリガーしたい場合は下記の方法もあり。

```
stripe trigger payment_intent.created
```

これで、リッスンしてる側でログが出力される。

csrf保護を外す必要があるので、下記のように記述。

```php:app/Http/Middleware/VerifyCsrfToken.php
protected $except = [
        'stripe/*',
    ];
```
JAWS-UG朝会 #20で登壇した振り返り

## はじめに

みなさんこんにちは！
ハンズラボのサムです！

色々とあって記事にするまでに時間がかかってしまい申し訳ありません。
今回の記事は4月22日に参加したJAWS-UG朝会で登壇した時の振り返りです。

## 登壇の経緯

直近登壇したイベントの主催者である山下さんからの紹介で、
JAWS-UG朝会主催者の小倉さんを紹介して頂き登壇することになりました！
こうやって色々な方とつながっていけるのはいいですね！

※前回の登壇のお話

https://qiita.com/sam_eng3336/items/108dd6c3ff138b7a7ea2

## 登壇内容と反省会

テーマ：「AWS Transfer Familyを触ってみた !」
というテーマで5分のLT枠で登壇させていただきました。

こちらが当日使用したパワポです

https://speakerdeck.com/anakagawa/20210422-jaws-ugzhao-hui-zhong-chuan-hao-hong

パワポを作ってる段階ですでに気がついたのですが致命的なミスに気が付きました。
どう考えても５分のLTで終わる内容ではなかったのです・・・。
自己紹介端折っても、パワポの内容端折っても辛うじて5分といった内容でした。

そもそもJAWS-UG朝会では
・5分間のLT
・20分間のセッション
という形で選べたのですが、20分喋れる自信がなかったので5分のLTを選択したのですが完全に失敗でした...
※次回からはサービスの紹介なんかは20分枠にしたいです

時間に内容が縛られてしまった感じはあるので、リベンジするなら20分間AWS Transfer Familyについて語りたいですね！

## まとめ

朝活に登壇するとすごく朝から充実した気分になるので楽しかったです！
今の御時世どこか場所をかりて勉強会なんてのは少なくなったと思うのですが、
逆にオンラインになったお陰で登壇の敷居も下がったのかな？なんて考えたり。
対面とオンラインはそれぞれに良い点悪い点があるので一概には言えませんが、
いつかまた実地での勉強会なんかも参加できるような世の中になればなと思いました！

イベントの主催者様、他登壇者様、見てくださった方有難うございました！
5月は用事があるので厳しいですが翌月以降リベンジしたいです！
DynamoDB describe-tableからテーブル一覧CSVを作る

既存テーブル一覧の情報を表形式に出力したかったため、そのネタを作るためのワンライナーです。

この手順では以下のコマンドを利用します。
必要に応じてインストールしてください。

- aws
- jq

## 既存のテーブルリストから各テーブルに関する情報を取得する

適当な作業用ディレクトリを用意して実行してください。
リージョン、プロファイルは任意です。

```bash
aws dynamodb list-tables --region ap-northeast-1 --profile default \
| jq -r '.TableNames[]' \
| xargs -L 1 -I @ sh -c \
'aws dynamodb describe-table --region ap-northeast-1 --profile default --table-name @ | jq ".Table"> @.json'
```

## 既存のテーブル情報からCSV形式で一覧を作成する

上で取得したJSONファイルを元に以下の加工を行います。
あとは出来上がったCSVをエクセルなりなんなりにコピペで出来上がりです。

- 列定義は以下
    - テーブル物理名
    - AttributeDefinitions
        - データ型 | 名称
        - １属性毎に改行表示
    - HASH
    - RANNGE
    - BillingMode
        - `BillingModeSummary`キーが存在しないことを考慮し、RCU/WCUが０の場合は`PAY_PER_REQUEST`、以外は`PROVISIONED`に設定
    - RCU
    - WCU
    - GSI
        - [インデックス名]\nHASH | RANGE
    - LSI
        - [インデックス名]\nHASH | RANGE
    - StreamViewType


```bash
find ./ -name \*.json -maxdepth 1 -type f \
| xargs -L 1 -I @ cat @ \
| jq -r '
[.TableName]
+ [[.AttributeDefinitions[]? | [.AttributeType, .AttributeName] | join(" | ") ] | join("\n")]
+ [.KeySchema[0] | .AttributeName]
+ [.KeySchema[1] | .AttributeName]
+ [if has("BillingMode") then .BillingMode else (. | if has("ProvisionedThroughput") and .ProvisionedThroughput.ReadCapacityUnits == 0 and .ProvisionedThroughput.WriteCapacityUnits == 0 then "PAY_PER_REQUEST" else "PROVISIONED" end) end]
+ [.ProvisionedThroughput? | .ReadCapacityUnits, .WriteCapacityUnits]
+ [[.GlobalSecondaryIndexes[]? | ("[" + .IndexName + "]\n" + ([.KeySchema[]?.AttributeName] | join(" | ")) )] | join("\n")]
+ [[.LocalSecondaryIndexes[]?  | ("[" + .IndexName + "]\n" + ([.KeySchema[]?.AttributeName] | join(" | ")) )] | join("\n")]
+ [if has("StreamSpecification") and .StreamSpecification.StreamEnabled == true then .StreamSpecification.StreamViewType else "" end]
| @csv'
```
[Android] PicassoとGoogleAPIでfaviconを取得する

# はじめに
<ul>
<li>URLを取得したときにわかりやすくアイコンを取得したかった</li>
<li>WebViewを使って取得するのは難しかった。</li>
<li>かんたんに完結にfaviconを取得したかった。</li>
</ul>

というわけで、PicassoとGoogleAPIを組み合わせてfaviconを取得しよう！！

## 準備（Gradle モジュール）
Picassoを使用するために、Gradleに以下の文を加筆する。

```gradle

dependencies {

    implementation 'com.squareup.picasso:picasso:2.71828'
}

```

## 準備（AndroidManifest）
インターネットに接続して、画像を取得するため、ユーザーパーミッションの以下の文も加筆しておく。

```xml

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

```

## URLからGoogleAPIを使用して、faviconを取得する。
正式名称がわからないため、GoogleAPIであっているかもわかりませんが、このURLを使用すれば、faviconを取得できるらしい。

<a href = "https://www.google.com/s2/favicons?domain=youtube.com"> https://www.google.com/s2/favicons?domain=youtube.com</a>

https://www.google.com/s2/favicons?domain={ドメイン}
ドメインの部分を変えればそのサイトのfaviconがPNG形式で取得できる

## Picassoを使って画像を取得する。
Picassoを使用して、画像を取得することができる。

```kotlin
//MainActivity.kt
//OnCreate内

val domein = youtube.com

Picasso.get()
            //画像が乗っているURL
            .load("https://www.google.com/s2/favicons?domain=$domein")
            .resize(300, 300) //表示サイズ指定
            .centerCrop() //resizeで指定した範囲になるよう中央から切り出し
            .into(findViewById<ImageView>(R.id.imageView)) //imageViewに流し込み


```

## ソースコード
```kotlin
package それぞれ合わせてください。

import android.os.Bundle
import android.widget.ImageView
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import com.squareup.picasso.Picasso
import java.net.URI


class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        var text = "https://twitter.com/home"


        findViewById<TextView>(R.id.textView).text = text

//      ドメインの取得
        val domein = URI(text).rawAuthority


        findViewById<TextView>(R.id.textView2).text = domein


        Picasso.get()
            //画像が乗っているURL
            .load("https://www.google.com/s2/favicons?domain=$domein")
            .resize(300, 300) //表示サイズ指定
            .centerCrop() //resizeで指定した範囲になるよう中央から切り出し
            .into(findViewById<ImageView>(R.id.imageView)) //imageViewに流し込み


    }
}
```

# まとめ
今回faviconのAndroidでの取得の仕方をまとめてみました。
利点としてはとても簡潔なプログラムで完成してよかったです。
難点としては取得した画像の画質が悪いことですかね。



# 参考文献
https://qiita.com/hotchemi/items/33ebd5faa42d2d05c2b6

https://wrongwrong163377.hatenablog.com/entry/2018/09/09/165250

https://llcc.hatenablog.com/entry/2016/04/03/214231


# github
今回部分部分で紹介していましたのでしっかりとプロジェクトとして作られているものも作りました。
ぜひ使ってみてください。

https://github.com/harutiro/FaviconGet

# 変更履歴
##### 2022/4/25更新
・「Picasa」になっている部分がありましたので「Picasso」に変更しました。
・ドメインの取得を、自作関数から、javaの「java.net.URI」に変更した。
Ruby で解く AtCoder ABC 201 D

# はじめに
*[AtCoder Problems](https://kenkoooo.com/atcoder/#/)* の Recommendation を利用して、過去の問題を解いています。
AtCoder さん、AtCoder Problems さん、ありがとうございます。

# 今回のお題
*[AtCoder Beginner Contest D - Game in Momotetsu World](https://atcoder.jp/contests/abc201/tasks/abc201_d)*
<font color="lightblue">Difficulty: 1317</font>

今回のテーマ、ミニマックス法

本番中に分からなかったのですが、座標の和の奇遇`(x + y) % 2`で先手後手が定まることを利用して解いていきます。
# ユーザ解説
```user.rb
def dp(x, y)
  return @memo[y][x] if @memo[y][x]

  if (x + y) % 2 == 0
    @memo[y][x] = -10000
    if y < @h - 1
      if @memo[y][x] < dp(x, y + 1) + @a[y + 1][x]
        @memo[y][x] = dp(x, y + 1) + @a[y + 1][x]
      end
    end
    if x < @w - 1
      if @memo[y][x] < dp(x + 1, y) + @a[y][x + 1]
        @memo[y][x] = dp(x + 1, y) + @a[y][x + 1]
      end
    end
  else
    @memo[y][x] = 10000
    if y < @h - 1
      if @memo[y][x] > dp(x, y + 1) - @a[y + 1][x]
        @memo[y][x] = dp(x, y + 1) - @a[y + 1][x]
      end
    end
    if x < @w - 1
      if @memo[y][x] > dp(x + 1, y) - @a[y][x + 1]
        @memo[y][x] = dp(x + 1, y) - @a[y][x + 1]
      end
    end
  end
  @memo[y][x]
end
@h, @w = gets.split.map(&:to_i)
@a = Array.new(@h){ gets.chomp.bytes.map{ _1 == 43 ? 1 : -1 } }
@memo = Array.new(@h){ [nil] * @w }
@memo[@h - 1][@w - 1] = 0

opt = dp(0, 0)
if 0 < opt
  puts 'Takahashi'
elsif opt == 0
  puts 'Draw'
else
  puts 'Aoki'
end

```
[ユーザ解説](https://blog.hamayanhamayan.com/entry/2021/05/15/235741) を参考にしたコードです。

```memo.rb
  if (x + y) % 2 == 0
    @memo[y][x] = -10000
    if y < @h - 1
      if @memo[y][x] < dp(x, y + 1) + @a[y + 1][x]
        @memo[y][x] = dp(x, y + 1) + @a[y + 1][x]
      end
    end
```
`(x + y) % 2`が`0`なので先手の手番になります。
`dp(x, y + 1)`の`y + 1`は下方向の移動を意味しています。

```bytes.rb
@a = Array.new(@h){ gets.chomp.bytes.map{ _1 == 43 ? 1 : -1 } }
```
`43`は`+`の文字コードを表す整数です。
文字同士の比較より高速に動作します、といいますかこの問題は`Ruby`にとって実行時間が厳しい問題ですね。

```ord.rb
p "+".ord   # => 43
```
# Qiitaユーザ解説
```user.rb
h, w = gets.split.map(&:to_i)
grid = Array.new(h){ gets.chomp.chars.map{ _1 == '+' ? 1 : -1 } }
dp = Array.new(h){ [0] * w }
dp[-1][-1] = 0
(h - 1).downto(0) do |row|
  (w - 1).downto(0) do |col|
    next if row == h - 1 && col == w - 1
    if (row + col) % 2 == 0
      s1 = -10000
      s2 = -10000
      s1 = dp[row + 1][col] + grid[row + 1][col] if row < h - 1
      s2 = dp[row][col + 1] + grid[row][col + 1] if col < w - 1
      dp[row][col] = [s1, s2].max
    else
      s1 = 10000
      s2 = 10000
      s1 = dp[row + 1][col] - grid[row + 1][col] if row < h - 1
      s2 = dp[row][col + 1] - grid[row][col + 1] if col < w - 1
      dp[row][col] = [s1, s2].min
    end
  end
end
x = dp[0][0]
if x == 0
  puts 'Draw'
elsif x > 0
  puts 'Takahashi'
else
  puts 'Aoki'
end
```
@u2dayo さんの[【AtCoder解説】PythonでABC201のA,B,C,D問題を制する！](https://qiita.com/u2dayo/items/468e9a859df3be2ef29c#d%E5%95%8F%E9%A1%8Cgame-in-momotetsu-world) を参考にしたコードです。
ユーザ解説は再帰でしたが、こちらはループで解きます。

||RubyU|RubyQ|
|:--:|:--:|:--:|
|コード長 (Byte)|999|805|
|実行時間 (ms)|1750|1510|
|メモリ (KB)|84476|77924|
# まとめ
+ ABC 201 D を解いた
+ hamayanhamayan さんありがとう
+ u2dayo さんありがとう
C++で配列を並び替えて逆順にする方法

C++で配列を昇順に並び替え、降順に並び替えて、3人の身長の差を求めるプログラムです。

```C++
#include <bits/stdc++.h>
using namespace std;

int main() {
  //3人の身長を定義するフィールド
  int A, B, C;
  //身長の差を計算するフィールド
  int ans = 0;
  //3人の身長を入力する
  cin >> A >> B >> C;
  //配列vecの定義
  vector<int> vec(3);
  //3人の身長データを配列に格納する
  vec={A,B,C};
  //昇順で並び替える
  sort(vec.begin(),vec.end());
  //降順に並び替える
  reverse(vec.begin(),vec.end());
  //最大身長差を求め、標準出力に出力する。
  ans = vec.at(0) - vec.at(2);
  cout << ans <<endl;
  return 0;
}
```


配列とsort、reverse関数を使うと簡単に並び替えできます。是非マスターしてください。
NestJS+TypeORM Cannot use import statement outside a moduleエラー distディレクトリが原因だった

# 状況

NestJS+TypeORM構成で、マイグレーションなど諸々実行した後に開発を始めようと`nest start`すると以下のエラーが発生。


```
../src/db/migrations/1621141317805-init.ts:1
import {MigrationInterface, QueryRunner} from "typeorm";
^^^^^^

SyntaxError: Cannot use import statement outside a module
    at wrapSafe (internal/modules/cjs/loader.js:992:16)
    at Module._compile (internal/modules/cjs/loader.js:1040:27)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1097:10)
    at Module.load (internal/modules/cjs/loader.js:941:32)
    at Function.Module._load (internal/modules/cjs/loader.js:782:14)
    at Module.require (internal/modules/cjs/loader.js:965:19)
    at require (internal/modules/cjs/helpers.js:88:18)
    at .../node_modules/typeorm/util/DirectoryExportedClassesLoader.js:41:39
    at Array.map (<anonymous>)
    at Object.importClassesFromDirectories (.../node_modules/typeorm/util/DirectoryExportedClassesLoader.js:41:10)
```

ちなみに`ormconfig`ファイルは`ts`ファイルにしていて、`entity`, `migration`, `factory`, `seed`など諸々`ts`ファイルにしている。
設定ファイルのファイル読み込みはこんな感じ

```ts:ormconfig.ts
entities: ['src/db/entities/**/*{.ts,.js}'],
migrations: ['src/db/migrations/**/*{.ts,.js}'],
```

以下を参考に`jsを読み込ませるように〜`, `__dirnameをつかって〜`など、色々試したが設定ファイル(`ormconfig`)云々で解決する感じはなかった。


https://github.com/nestjs/nest/issues/4283



# 結論

```terminal
$ rm -rf dist
```

`dist`ディレクトリに過去の`migration`情報がたくさん残っていて、これらが影響を与えていたらしい。

自分がサーバー起動前にdbを初期化するときに`migration`ディレクトリごと毎回`rm -rf ...`で削除してたので`dist`に過去の`migration`ファイルが溜まり続けていることに気づかなかった。

```terminal:db_init
$ yarn typeorm schema:drop;
$ rm -rf src/db/migrations/*;
$ yarn yarn typeorm migration:generate -n init;
$ yarn yarn typeorm migration:run;
```

`typeorm`周りの整備で`ormconfig.ts`に拡張子変えてみたり、関連ファイルいじりまくったりしていて過去の`migration`ファイルがよくわかんない状態で残っていたのだと思う。
Raspberry4(Ubuntu21.04)にMongoDB4.4導入

# MongoDB4.4 インストール

MongoDBは標準パッケージにはないのでMongoDBの公式リポジトリを追加する

作業は[The MongoDB 4.4 Manual](https://docs.mongodb.com/manual/)を読みながら進めるといい。

* 公開鍵の登録

```
$ wget -O - https://www.mongodb.org/static/pgp/server-4.4.asc | sudo apt-key add -
```

* ソースリストへ追加

```
$ echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/4.4 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.4.list
```

* パッケージの再読み込み
 
```
$ sudo apt-get update
```


正しくできていると、MongoDBが追加されてるのが確認できる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1477929/4e4d3aa7-a838-f7e2-3800-c5d241243e75.png)

4. パッケージインストール

```
$ sudo apt-get install mongodb-org
```

* インストール確認

```
$ mongo -version
```
以下のように表示されていれば正しくインストールできてる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1477929/6f80eeca-ccd9-1ed9-c113-0d84c6fe8621.png)


* 自動起動追加

```
$ sudo systemctl enable mongod
```

* MongoDB起動、状態確認

```
$ sudo systemctl start mongod
$ sudo systemctl status mongod
```
動作していれば以下のようになっている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1477929/fc580f31-327f-8340-e1e1-a0736723f456.png)



##外部接続許可
Raspberry4だけで完結するだけならここまででよいが、リモートからもアクセスしたりしたいので設定を変えて外部からアクセスできるするために ``/etc/mongod.conf`` を編集する。

設定できるのは、``127.0.0.1``か``0.0.0.0``のみみたいで、ほかのアドレスいれて、やってみたらエラーがでた。これは公式マニュアルの [Configuration File Options](https://docs.mongodb.com/manual/reference/configuration-options/)の net.bindIp の項に書いてある。

```
 5月 15 19:08:30 raspberrypi4 systemd[1]: Started MongoDB Database Server.
 5月 15 19:08:30 raspberrypi4 systemd[1]: mongod.service: Main process exited, code=exited, status=48/n/a
 5月 15 19:08:30 raspberrypi4 systemd[1]: mongod.service: Failed with result 'exit-code'.
```

自分で使う分には何も問題ないので、``0.0.0.0``で設定しておく

```/etc/mongod.conf
# network interfaces
net:
  port: 27017
  bindIp: 0.0.0.0
```
DynamoDB describe-tableからcreate-tableに渡すJSONファイルを作る

ローカルで環境構築するにあたりJSONファイルで管理したかったため、そのネタを作るためのワンライナーです

この手順では以下のコマンドを利用します。
必要に応じてインストールしてください。

- aws
- jq

## 既存のテーブルリストから各テーブルに関する情報を取得する

適当な作業用ディレクトリを用意して実行してください。
リージョン、プロファイルは任意です。

```bash
aws dynamodb list-tables --region ap-northeast-1 --profile default \
| jq -r '.TableNames[]' \
| xargs -L 1 -I @ sh -c \
'aws dynamodb describe-table --region ap-northeast-1 --profile default --table-name @ | jq ".Table"> @.json'
```

## 既存のテーブル情報からcreate-table用のJSONファイルを作る

上で取得したJSONファイルを元に以下の加工を行います。

- `BillingMode`キーの追加
    - `BillingModeSummary`キーが存在しないことを考慮し、RCU/WCUが０の場合は`PAY_PER_REQUEST`、以外は`PROVISIONED`に設定
- 不要なキーの削除
- `BillingMode`が`PAY_PER_REQUEST`の場合、GSI/LSIの`ProvisionedThroughputキーを削除
- 任意のタグを追加

```bash
mkdir -p ./definitions && \
for filename in $(find . -type f -name \*.json -maxdepth 1); do jq . ${filename} |
jq "if has(\"BillingModeSummary\") then . + { BillingMode: .BillingModeSummary.BillingMode} else . + { BillingMode: (if has(\"ProvisionedThroughput\") and .ProvisionedThroughput.ReadCapacityUnits == 0 and .ProvisionedThroughput.WriteCapacityUnits == 0 then \"PAY_PER_REQUEST\" else \"PROVISIONED\" end)} end" |
jq "del(
    .TableStatus
    , .CreationDateTime
    , (.ProvisionedThroughput? | .NumberOfDecreasesToday, .LastIncreaseDateTime, .LastDecreaseDateTime)
    , .TableSizeBytes
    , .ItemCount
    , .TableArn
    , .TableId
    , (.GlobalSecondaryIndexes[]? | .IndexStatus, .IndexSizeBytes, .ItemCount, .IndexArn, (.ProvisionedThroughput? | .NumberOfDecreasesToday, .LastIncreaseDateTime, .LastDecreaseDateTime))
    , (.LocalSecondaryIndexes[]? | .IndexStatus, .IndexSizeBytes, .ItemCount, .IndexArn, (.ProvisionedThroughput? | .NumberOfDecreasesToday, .LastIncreaseDateTime, .LastDecreaseDateTime))
    , .LatestStreamLabel
    , .LatestStreamArn
    , .BillingModeSummary
)" |
jq "if .BillingMode == \"PAY_PER_REQUEST\" then del(.ProvisionedThroughput, .GlobalSecondaryIndexes[]?.ProvisionedThroughput, .LocalSecondaryIndexes[]?.ProvisionedThroughput) else . end" |
jq ". + { Tags: [ { Key: \"Name\", Value: .TableName }, { Key: \"Env\", Value: \"local\" } ]}" \
> definitions/${filename} ; done
```
vscodeでPrettierを導入し、自動整形する

# 概要
　エディタを使用してソースコードを書く際、フォーマッターを導入することは必須になる。フォーマッターとしてよく利用される一つとして、Prettierがある。今回は、自動フォーマッタとしてPrettierを使用し、それをVScodeにて保存時に自動整形するまでの一連の流れをまとめて記事にする。

# 1. Prettier for vscodeプラグインをインストール
VScodeの拡張機能追加で`Prettier - Code formatter`を導入する。

# 2. デフォルトフォーマッターを設定
VScodeの設定を開く。（mac: command + , windows: ctrl + ,)
検索で、「defaultformatter」を検索。
「None」から「Prettier for vscode」へ変更する。

# 3. 保存時にフォーマッターをかけるように設定
設定の検索で「save」を検索。
「Format on Save」にチェックマークを入れる。

# 4. フォーマット設定ファイル作成
プロジェクトの中に`.prettierrc`ファイルを作成し、設定をJSON型で記述する。
`.prettierrc`には各プロジェクトに応じて同フォーマットするかの設定を記述する。
以下は例を示す。

```.prettierrc:json
{
  "printWidth": 120,
  "trailingComma": "es5",
  "tabWidth": 2,
  "semi": true,
  "singleQuote": true,
  "endOfLine": "lf"
}
```

# 5. 設定を反映
mac: command + shift + P  windows: ctrl + shift + P　を押し、reload windowを検索し、クリックすることで設定を反映させる。

これで、ファイルを保存するとフォマットが自動でかかっている。
.netCore + Angular環境をDockerで構築

# はじめに
バックエンド：.NetCore、フロントエンド：Angular で開発する機会があったのでどうせならDockerで作ろうと思いました。
そこそこネット上に情報あるのですが、実際にやってみたら結構手間取ったので手順を残しておきます。
（Docker自体はもともと入れていたので省略）

# 概要
やること

* .NetCoreのimageを取得
* imageからコンテナを作成
* プロジェクト作成
* いろいろ入れる
* サーバ起動

# 作業
## .NetCoreのimageを取得
[Microsoft公式のDockerHub](https://hub.docker.com/_/microsoft-dotnet)からimageを取得しました
どれを入れれば良いのか迷いましたが dotnet/sdk で問題なさそうです。
docker pullでimageを取得します。

```
docker pull dotnet/sdk
```

## imageからコンテナを作成
（知識不足もあって）ここでだいぶ嵌りました。。後工程でサーバ起動時にポート問題でホスト側からアクセスできず。
.NetCore起動時にhttp:5000, https:5001のポートを使っていてhttpsに自動的にリダイレクトするようです。
コンテナ作成時に5000と5001両方使えるようにしました。

```
docker run --name dotnet -it --mount type=bind,src=$(pwd)/dotnet,dst=/vol -p 5000:5000 -p 5001:5001 mcr.microsoft.com/dotnet/sdk
```

mountとかnameとかはお好みで

## プロジェクト作成
適当にディレクトリ切って.NetCoreプロジェクトを作成します。
new の後にangularといれるとangular用のテンプレートプロジェクトが作成されます。
参考：https://docs.microsoft.com/ja-jp/aspnet/core/client-side/spa/angular?view=aspnetcore-5.0&tabs=visual-studio

```
dotnet new angular
```

## いろいろ入れる
### node
angularの実行にnode.jsが必須のためインストールします。
使用したimageはDebian環境でそのままnodeのインストールができなかったので下記参考にインストールしました。
参考：https://qiita.com/naoyukiyama/items/29054cff00923f9543ce

```
curl -sL https://deb.nodesource.com/setup_10.x | bash
apt install -y nodejs
```

### Angular
入れていない状態でもAngular用プロジェクト作成はできるようです。
AngularCliのバージョンは使いたいものがあれば指定しておいた方が良いです。
（後からバージョンアップはできるがダウングレードは入れ直しになってしまうので）

```
npm install -g @angular/cli@11.1.0
```

## サーバ起動
これで起動できるのですが、ホストから接続するためにもうひと手間
開発環境では.NetCore側でlocalhostからのアクセスしか許容していないのでそこを解放します。
参考：https://mseeeen.msen.jp/asp-net-core-3-allow-access-to-kestrel-from-outside-in-development-mode/

appsettings.jsonに「"urls": "http://*:5000;https://*:5001",」を追加

```
{
  "urls": "http://*:5000;https://*:5001",
  "Logging": {
      "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
      }
    },
"AllowedHosts": "*"
}
```

起動します。

```
dotnet run
```

実行時に下記のようにlistenできていればOK
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587356/b8c79e80-4057-082b-f42f-1d37eecaa199.png)
ホスト側ブラウザからアクセス
http://localhost:5000

HelloWorld画面が表示されれば環境構築完了です！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587356/13458449-eecf-5a46-d8e9-7c5e3b522d8d.png)
正規表現を用いたreplaceメソッドの使い方

※プログラミング学習中の私がアップロードしてます。理解が浅いです。
この記事は厳密な仕様に関するものではなく、考え方理解のまとめとして受け取ってください。

正規表現を用いたreplaceメソッドの使い方
-

replaceメソッドにおける正規表現では、検索する文字列を『/（スラッシュ）』で囲み、末尾にフラグを付与します。 オプションのフラグを幾つかを列挙します。

|フラグ|フラグの意味合い|
|--|--|
|g|グローバルマッチ|
|i|大文字と小文字の違いを無視する|
|m|複数行を越えたマッチ|


|文字|説明|正規表現の例|マッチする例|
|--|--|--|--|
|^|直後の文字が行の先頭にある場合にマッチします。|^google|google...|
|$|直前の文字が行の末尾にある場合にマッチします。|google$|...google|

つまり直後の文字で始まるってこと


testメソッドとは
-

testメソッドは文字列を正規表現でチェックするために使います。
指定した文字列が正規表現のパターンにマッチすれば「true」を返し、マッチしなければ「false」を返します。

testメソッドの使い方
-
ここでは、「test」を使った検索方法を解説します。
testは正規表現のパターンから呼び出し、引数にチェックする文字列を指定します。

このJavascriptの表現はパスの中にitemsがあり、transactionsが含まれておりparamsの中に１から９の数字か０だけでできているということ。\/は\が直後の文字をメタ文字（正規表現で使う記号）として扱わないという意味で’/’を文字のまま扱ってパスの区切りスラッシュを全て除くということ。

if (path.includes("items") && path.includes("transactions") && /^([1-9]\d*|0)$/.test(params))
Atomic Kotlinの誤記載：Functions/Task1.kt

[intelliJIdeaのプラグイン（Edu Tools）](https://www.jetbrains.com/help/education/install-edutools-plugin.html)で[Atomic Kotlin](https://stepik.org/lesson/171437/step/1?unit=146116)というコースで学ぶ中で、明らかにコース作成者側のミスと思われるものを見かけたので、他の学習者のために残す。
この記事はエクササイズ：NumberTypes/Task4.ktについて。
目次は[こちら](https://qiita.com/Amairo/items/c80a7d04e26c7eb92ab2)

Functions/Task1.kt
## 課題内容
（写真は解答済みの画面です。既に課題を解いてしまい、またデフォルトの状態までファイルを戻せませんでした。）
![Functions_Task1.kt.01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1501375/2ff830f1-5065-96d3-a53c-c69376b13911.jpeg)

タイプがIntのパラメーターを入力することで、その二乗を返す、`squareInt()`というファンクションを作成してね、とのこと。

## 問題点
右サイドの説明では、`squareInt()`という名前のファンクションを作れ、とあるけど、左サイドのコードを見てわかる通り、`getSquare`という名前でないと、正答と認識されない。一度【check】をしてから、解答例（右サイド下のPeek Solution）を見れば、すぐに分かるが、このコース（Atomic Kotlin）で学び始めた段階では、コース自体にこんなエラーが存在するとは分からないので、非常に混乱する。

##解決策
上述の通り、作成するファンクションの名前を`getSquare`にする。

##その他
直後のエクササイズ（Functions/Task1.kt）でも、同様の誤記載がある。
右サイドで指示しているファンクションの名前が間違っている。
Raspberry Pi Picoでモータを動かす⑦（PIOで動かす⑤）

[前回](https://qiita.com/fmax/items/4a187d3b8c1b70553b10)では結局CWとCCWを切り替えることが出来なかった。
色々やってみたのだが、1step単位で指定してCW/CCWを切り替えるコードはとりあえず不可能という結論に至った。
理由は次の2つ

* スクラッチレジスタが不足する
　上記機能を実現するためには残りstep数、CW/CCWのフラグ、現在のstep位置の3つのレジスタが必要であるが
　スクラッチレジスタはx,yの2つしかなく、ビット演算ができないためx,yを分割して使うことも不可能であるためレジスタが不足する

* インストラクションメモリが不足する
　スクラッチレジスタを使わずにjmpだけで無理やり実装することもインストラクションメモリが無限であれば不可能ではない
　(前回のように各step毎にpull,outを使って現在のstep数とプログラムカウンタを結びつける)
　しかし、実際実装するとインストラクションメモリが全く足りない（2～3倍程度あればいけそう）

諦めて何もしないというのも癪なので、4step単位での指示でやってみる。

```
from rp2 import PIO, StateMachine, asm_pio
import time
from machine import Pin

@asm_pio(set_init=(PIO.OUT_LOW, PIO.OUT_LOW, PIO.OUT_LOW, PIO.OUT_LOW), out_shiftdir=PIO.SHIFT_LEFT, autopull=False)
def cw_ccw():
    wrap_target()
    
    pull()
    out(y, 1)
    out(x, 31)
    label("continue")
    jmp(not_y, "cw")
    jmp("ccw")
    label("return")
    jmp(x_dec, "continue")
    
    wrap()
    
    label("cw")
    set(pins, 0b1001)[3]
    set(pins, 0b0011)[3]
    set(pins, 0b0110)[3]
    set(pins, 0b1100)[3]
    jmp("return")
    
    label("ccw")
    set(pins, 0b1100)[3]
    set(pins, 0b0110)[3]
    set(pins, 0b0011)[3]
    set(pins, 0b1001)[3]
    jmp("return")

cw_ccw = StateMachine(0, cw_ccw, freq=2000, set_base=Pin(2))
cw_ccw.active(1)
cw_ccw.put(0x100) # CW
time.sleep(5)
cw_ccw.put((0b1 << 31) + 0x100) # CCW
time.sleep(5)
cw_ccw.active(0)
```

最上位ビットをyに割り当ててCW/CCWフラグとしている。

これで下（ステートマシン）に指示を丸投げして自分（CPU）は寝ている、しかも部下の仕事が終わったことに起きるまで気づかないという**ダメ上司ムーブ**が完成した。
**指示が適当**(分解能1/4)なところや報告させずに**進捗管理をしない**というところもダメさを表していて~~憎らしい~~かわいいやつである。

次回はこのダメ上司をちょっとはマシにしてみようかと思う。
pi picoでmicropython その26

#概要

picoでmicropythonやってみた。
pioasmでLチカやってみた。
pull, put, out 使ってみた。

#サンプルコード

```

import time
from machine import Pin
from rp2 import PIO, StateMachine, asm_pio
@asm_pio(out_init = PIO.OUT_LOW, out_shiftdir = PIO.SHIFT_RIGHT)
def tic():
   pull()
   out(pins, 1)
sm = StateMachine(0, tic, freq = 1000, out_base = Pin(25))
sm.active(1)
while True:
   sm.put(bytes((1, )))
   time.sleep(0.5)
   sm.put(bytes((0, )))
   time.sleep(0.5)
   print(".")

```

以上。
備忘録 flutter開発で音声入力したいけど speech_to_text がうまく作動しない。

# 課題

下記リファレンスを参考にspeech_to_text でマイクから音声を拾って文章に文字起こしをしたいがうまく作動しない。

https://pub.dev/packages/speech_to_text/example

下記のようなコードを組んで問題点を調査したところ"The user has denied the use of speech recognition."が呼ばれた。どうやらspeech_to_textをインスタンス化するところで失敗している模様。

```

    var hasSpeech = await speech.initialize(
        onError: errorListener,
        onStatus: statusListener,
        debugLogging: true,
        finalTimeout: Duration(milliseconds: 0));

    if (hasSpeech) {
      _localeNames = await speech.locales();
      print('_localeNames');
      print(_localeNames);

      var systemLocale = await speech.systemLocale();
      _currentLocaleId = systemLocale.localeId;

      speech.listen( onResult: resultListener );
    } else {
      print("The user has denied the use of speech recognition.");
    }

```

#解決策
app/src/main の　Android Manifest に　uses-permissionのタグ二つとqueriesを追加する。
これによってアプリ起動時にマイクへのアクセスが求められる様になり、音声入力が可能となる。


```

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.higuuu.job_interview">
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.INTERNET" />
    <queries>
        <intent>
            <action android:name="android.speech.RecognitionService" />
        </intent>
    </queries>


```
pi picoでmicropython その25

#概要

picoでmicropythonやってみた。
pioasmでLチカやってみた。

#明るい

```
from machine import Pin
from rp2 import PIO, StateMachine, asm_pio
@asm_pio(set_init = PIO.OUT_LOW)
def tic():
   set(pins, 1)
sm = StateMachine(0, tic, freq = 1000, set_base = Pin(25))
sm.active(1)


```

#少し暗い

```
from machine import Pin
from rp2 import PIO, StateMachine, asm_pio
@asm_pio(set_init = PIO.OUT_LOW)
def tic():
   set(pins, 1)
   set(pins, 0) 
sm = StateMachine(0, tic, freq = 1000, set_base = Pin(25))
sm.active(1)


```

#暗い

```
from machine import Pin
from rp2 import PIO, StateMachine, asm_pio
@asm_pio(set_init = PIO.OUT_LOW)
def tic():
   set(pins, 1)
   set(pins, 0) [10]
sm = StateMachine(0, tic, freq = 1000, set_base = Pin(25))
sm.active(1)


```

以上。
PHPで1~15までの数字を繰り返し表示する

###for文を使う

```
for($i=1;$i<=15;$++){
    print($i."\n");
}
```
###while文を使う
```
$i=1;
while($i<=15){
    print($i);
    print("\n");
    $i ++;
}
```

###foreachを使う
```
foreach(range(1,15) as $i){
   echo $i.'<br>';
}
```

繰り返しの範囲が最初から決められているのならばforeachでrangeで書くのが一番簡単かも。
Laravelで作成したAPIをテストする

## 前提
下記に対してPHPUnitでテストを作成していきます。
[LaravelでAPIを作成する](https://qiita.com/yu_ku/items/1069290f0cbed2010647)

## テストの設定
phpunit.xmlの設定

```
<server name="DB_DATABASE" value="TodoApp_testing"/>
```

上記のように記述されているため下記コマンドでテスト用の.envファイルを作成する

```
cp .env .env.testing
```

.env.testingに下記を記述する。（テスト用のデータベースを設定する）

```
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=HogeApp_testing
DB_USERNAME=root
DB_PASSWORD=
```

## テストの作成
テストディレクトリには以下の２つがあるが今回はAPIのテストなので①のテストを作成する
①Feature...一つのリクエストから始まる一連の流れをテスト
②Unit...クラスや関数の機能テスト


 ```
<?php

namespace Tests\Feature;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
use App\Models\Hoge;

class HogeTest extends TestCase
{
    use RefreshDatabase;  // データのキャッシュを消す
    /**
     * @test
     * 上記のように記述することでメソッド名にtestを付けなくて良い
     */
    public function CanGetAList()
    {
        $hoges = Hoge::factory()->count(10)->create();

        $response = $this->getJson('api/hoges');

        $response
            ->assertOk()
            ->assertJsonCount($hoges->count());
    }

    /**
     * @test
     */
    public function CanRegister()
    {
        $data = [
            'title' => 'テスト投稿'
        ];

        $response = $this->postJson('api/hoges', $data);
        $response
            ->assertCreated()
            ->assertJsonFragment($data);
    }

    /**
     * @test
     */
    public function CanBeUpdated()
    {
        $hoge = Hoge::factory()->create();
        $hoge->title = '書き換え';

        $response = $this->patchJson("api/hoges/{$hoge->id}", $hoge->toArray());
        $response
            ->assertOk()
            ->assertJsonFragment($hoge->toArray());
    }

    /**
     * @test
     */
    public function CanBeDeleted()
    {
        $hoges = Hoge::factory()->count(10)->create();
        $response = $this->deleteJson("api/hoges/1");
        $response->assertOk();

        $response = $this->getJson("api/hoges");
        $response->assertJsonCount($hoges->count() -1);
    }
}
```


テストは下記のコマンドで実行する

```
./vendor/bin/phpunit tests/Feature/【テストファイル名】
```

実行するとpassしているのが分かります!
（もし全体のテストを実行してpassしなかった場合は１メソッドずつに分割して試してみてください。）