OmniAICreator/Qiita-1.07M huggingface dataset:
herokuにpushできなくてお困りのあなた。こちらをご覧ください。

昨日はできていたpush…

```
$ git push heroku
Username for 'https://git.heroku.com/~': 
Password for 'https://git.heroku.com/~': 
remote: !       WARNING:
remote: !       Do not authenticate with username and password using git.
remote: !       Run `heroku login` to update your credentials, then retry the git command.
remote: !       See documentation for details: https://devcenter.heroku.com/articles/git#http-git-authentication
fatal: Authentication failed for 'https://git.heroku.com/~'
```
なんか言ってんな

```
$ heroku login
heroku: Press any key to open up the browser to login or q to exit: 
Opening browser to https://cli-auth.heroku.com/auth/cli/browser/6df5e7bd-a36c-461d-8528-89c143af60e1?requestor=SFMyNTY.g2gDbQAAAA40NC4yMDIuMjAwLjIwNm4GAGCeUvx-AWIAAVGA.krM1IZ8bX-Unp_8P_XZiq9y0-ZP_WP6nuqoT6UnQL6E
 ›   Warning: Cannot open browser.
heroku: Waiting for login... ⢿
heroku: Waiting for login... ⣷
※繰り返されます
```
↑URLへアクセスするとログイン画面が出ますが。。。
```IP address mismatch```
こんな言葉しかかけてもらえません。

これらの記事を参考に

https://network-beginner.xyz/push_heroku_master_error

https://devcenter.heroku.com/ja/articles/authentication


APIトークン（何それ）を入力したら解決できるみたいですね。

```
$ heroku auth:token

 ›   Error: Invalid credentials provided.
 ›
 ›   Error ID: unauthorized

```
私の場合はこの方法ではないようです。

でもログインぽいんだよなー
ログインさえできれば…
本題です。


```
$ heroku login -i
heroku: Enter your login credentials
Email [アドレス]: 
Password: パスワード
Logged in as アドレス

```
これを叩くとターミナルからメールとパスワードを入力できて、```$ heroku push```することができました。

お試しください。

https://stackoverflow.com/questions/63363085/ip-address-mismatch-on-signing-into-heroku-cli



$ heroku login -i
$ heroku login --interactive
これらは同じです。

https://devcenter.heroku.com/ja/articles/heroku-cli-commands
PHP独学ノート　その5

<font color="green">定義済みの定数</font>
PHPの定数は自分で定義するばかりではなく、最初から用意された（定義済みの）定数が用意されている。

定義済みの定数はconst/defineで宣言することなく無条件に利用できる。

<font color="green">主な定義済み定数</font>

|定数|概要|
|:-:|:-:|
|\_\_FILE__|実行中のファイル名（絶対パス）|
|\_\_DIR__|実行中のファイルが存在するフォルダ|
|\_\_LINE__|実行中の行番号|
|\_\_FUNCTION__|実行中の関数名|
|\_\_CLASS__|実行中のクラス名（所属する名前空間を含む）|
|\_\_METHOD__|実行中のメソッド名|
|\_\_TRAIT__|実行中のトレイト名（所属する名前空間を含む）|
|\_\_NAMESPACE__|現在の名前空間|
|DIRECTORY_SEPARATOR|フォルダの区切り文字（Windows環境では「¥」、Mac OS環境では「/」）|
|PATH_SEPARATOR|パスの区切り文字（Windows環境では「;」、Mac OS環境では「:」）|
|PHP_VERSION|使用しているPHPのバージョン|

アンダースコアが前後に2つずつ連なっている定数もある為注意。

<font color="green">データ型</font>

データ型とはデータの種類のこと。
たとえば「abc」や「いろは」は文字列型、1や10は数値型、true（真）やfalse（偽）は真偽型に分類できる。
PHPは<font color="red">動的型付け言語</font>と呼ばれ、データ型に対して寛容で、最初に文字列を格納した変数に後から数値をセットしても良いし、その逆も可能。
変数（入れ物）の方が中身に応じて自動的に形を変えてくれる。
そのため次のスクリプトもPHPでは正しいコード。

```
$data = ‘今休憩中です。コーヒー飲みながらこの勉強をしております。’;

$data = 20220215;
（文字列が代入された変数に数値を代入）
```

ただし、開発者がデータ型を全く意識しなくて良いわけではない。
このあと、値を演算/比較する場面では、データ型によって挙動が変化するし、そもそもデータ型によって出来ることも変化する。
値の扱いが緩いというだけで、PHPでも型の理解は欠かせない。

<font color="green">PHPで扱える主なデータ型</font>

<font color="red">スカラー型</font>

<font color="blue">論理型（book）</font>
true（真）またはfalse（偽）

<font color="blue">整数型</font>
10進数、16進数（0xで始まる値）、8進数（0で始まる値）など。

<font color="blue">浮動小数点型（float、double」</font>
1.8×10の308乗が最大値（ただしプラットフォームに依存）

<font color="blue">文字列型（string）</font>
クォートで囲まれた0個以上の文字の集合。

<font color="red">複合型</font>

<font color="blue">配列型（array）</font>
データの集合。

<font color="blue">オブジェクト型（object）</font>
データと手続きの集合。

<font color="blue">コールバック型（callable）</font>
一連の処理（手続き）の集合。

<font color="red">特殊型</font>

<font color="blue">リソース型（resource）</font>
外部リソースへの参照。

<font color="blue">ヌル型（null）</font>
値が未定義であることを表す。

スカラー型とは、１つの変数（入れ物）で１つの値だけを扱う事ができるものを言う。
データ型の中で最も基本的なものである。

スカラー型と対照的なものが複合型で、この型は１つの変数で複数の値をまとめて扱える。

そして特殊型は、スカラー型/複合型のいずれにも分類できない特殊な値を表す型のこと。

また、これから出てくる<font color="red">リテラル</font>とは、変数に格納できる値そのもの、または値をスクリプトの中で表現する方法のことを言う。


<font color="green">論理リテラル（bool）</font>

論理型は、スカラー型の中でも最も単純な型で、真（正しい）か偽（間違い）のいずれかしか持たない。
それぞれtrue（真）、false（偽）と言うキーワードで表現できる。
大文字小文字は区別しないので書き方は自由。

なお、PHPでは、論理リテラルを必要とする状況で、次の値を自動的にfalseとみなす。

①空文字列、または文字列の0（ゼロ）

②整数リテラルの0、-0（ゼロ）

③浮動小数点数リテラルの0.0、-0.0（ゼロ）

④null（未定義値）

コードを書いていく中でこの性質を利用することはよくあるので、まずは「falseキーワードだけがfalseを表すわけではない」と言うことを覚えておく。

ここに表示したもの以外の値は全て<font color="red">true</font>であるとみなされる。


<font color="green">整数リテラル（int）</font>

整数リテラルは次のように分類できる。

|整数リテラル| |
|:-:|:-:|
|10進数リテラル|0, 3, -12|
|2進数リテラル|0b1111, 0b101|
|8進数リテラル|0777, 0644, 0600|
|16進数リテラル|0xFF, 0xAA00BB|

10進数リテラルは私たちが日常的に使っている最も一般的な再数の表現で、正数（10, +108）、負数（-1, -15）、ゼロ（0）を表現できる。

負数を表現するにはリテラルの頭にマイナス（-）符号をつける。

16進数は0〜9に加えてa〜f（A〜F）のアルファベット10〜15を表し、接頭辞には「0x」を付与する。

8進数は0〜7で値そのものを表し、接頭辞として「0」を付与する。

2進数は0/1で数値を表し、接頭辞は「0b」。

「x」は「heXabecimal」（16進数）
「b」は「Binary」（2進数）

の意味。

こちらも大文字小文字は区別しないのでそれぞれ「X」「B」でも良い。

いずれも利用できない数値を含んだ値—-2進数であれば「0b1<font color="red">2</font>0」のような値—-はエラーとなる。


<font color="green">その6は浮動小数点数リテラルから</font>
RLoginとFirefoxを使って簡単に大学内のサイトを利用

# 始まり
皆さんの中に、大学の無線LANサービス経由じゃないと学内限定サイトにアクセスできないと悩んだことがある人はいるでしょうか。
かくいう私はそんな人の一人で、ローカルPCにファイルをダウンロードしたいけど、家では学内限定サイトにつなぐことができないと悩んでおりました。
そこで、今回はSSH接続ソフトであるRLoginを用いた学内サイト接続を行い、学外からローカルPCでサイトに繋げられるようにしてみましたので、その方法をご紹介します。

# 前提
今回の方法に関して、いくつか前提があります。
1. 大学のIPアドレスと紐づけられたリモートサーバが存在すること
2. そのサーバにSSHでログインできること
上記の前提がある人に向けたやり方を紹介するため、それに該当しない方は、申し訳ないですがVPNを使わせてもらうなど別のやり方を試してみてください。

# 方法
それでは、設定を行なっていきます。
## RLoginの設定
まず、RLoginのソフトをインストールします。
次に、ソフトを起動して、以下のような画面が表示されると思うので、まずは[新規(N)]ボタンを選択してください。
![q_rlogin設定1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436205/2a07aa96-8856-9d9a-a03f-bc791530a113.png)

次に、新規の接続設定を作成する画面が表示されるので、以下のように各種設定を行ってください。また、TCPポートがデフォルト(22番)でない場合はその都度適切なポート番号に変えてください。
また、サーバによっては公開鍵方式やパスワード認証式など、認証システムの違いがあるので、それに応じた認証方法の設定を行ってください。
(筆者の場合は公開鍵認証だったので、[SSH認証鍵(K)]を選択し、公開鍵を登録しました)
![q_rlogin設定2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436205/d9f55439-7505-98e5-4b33-633e29a1c6e9.png)

以上の設定ができましたら、左メニューの[プロトコル]を選択してください。選択したら、右側の一覧に[ポートフォワード(P)]というボタンがあるのでそちらをクリックします。
![q_rlogin設定3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436205/a73bad5f-c567-c550-8ad4-39b39df49306.png)

すると、ポートフォワードの設定画面が表示されるので、表示された画面から、[新規(N)]ボタンをクリックします。
![q_rlogin設定4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436205/9c7fbd7d-9b17-a386-0453-f18f01cb587b.png)

新規設定できる画面が表示されるので、Local Socksを選択したのち、ローカルPCのアドレス(127.0.0.1 or localhost)をHostNameに設定し、適当なポート番号(今回は10080に設定)をします。
![q_rlogin設定5.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436205/61df3a7f-3f5e-73c1-b09d-145b75afa492.png)

以上の設定が終わりましたら、以下のように新しいポートフォワード設定が適応されていると思うので、一番下の[OK]ボタンを押して、次のServer Edit Entryウィンドウでも[OK]ボタンを押して設定を終了してください。
![q_rlogin設定6.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436205/ca5209c4-b689-1707-c5a9-d53abf8a3846.png)

以上の設定をして、いざ設定したEntryを選択した状態で右側の[OK]ボタンをクリックします。コンソールが表示されていれば無事に接続ができていると思います。

## ローカルのブラウザ設定
次に、ローカルのブラウザを設定します。
ブラウザからサイトに接続する際、Windowsの全体設定でプロキシを設定してもいいですが、それだとポートフォワードをしないときは設定を切る必要があり面倒なので、プロキシ設定を持つfirefoxにのみ限定的に学内サイトを閲覧できる機能を搭載します。

firefoxを開いたときに右上にあるメニューボタンを押し、その中の設定を選択します。
次に、右メニューの一番下にある[ネットワーク設定]タブの中にある[接続設定..(E)]をクリックします。
すると、以下のような画面が表示されると思うので[手動でプロキシーを設定する(M)]を選択します。
![q_プロキシ未設定.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436205/a1a6d26b-beb2-030c-2ed8-bbd85d69d720.png)

すると、下のフォームを編集できるようになるので、[SOCKSホスト(C)]にローカルIPを入力し、右のポートに先ほどRLoginで設定したポート番号を入力します。
![q_プロキシ設定.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436205/1c282322-ed46-b3c6-5232-21a061e7d67b.png)

以上の設定を終えて下の[OK]ボタンをクリックしてネットワーク設定を終了してください。

## 実行
上記設定を行うことで、学内のネットを介した学内限定サイトを閲覧できると思います。私の大学の場合、図書館が公開している論文調査サイトなどは学内IPからのみアクセスできるようになっているので、上記方法によりアクセスできるようになりました。

## ちなみに
これまでRLoginでやってきたことですが、超絶簡単に言うと以下の処理を行っただけ

```sh
ssh -D 10080 -p ポート番号 -i 鍵のパス ユーザ名@サーバのIPアドレス
```
この処理を行えば、ブラウザから接続できます、はい。

# 感想
設定を終えて思うこととして、この方法はそもそも「学内にグローバルIPアドレスを保持したサーバがありそれにSSH接続できること」が前提にあります。さらに言えば「そのサーバのIPアドレスが学内LANサービスのサブネットマスクと一致しているかどうか」も重要な前提でした。
以上のことが他の学生の役に立ってくれたらうれしいです。
haml導入から基本的な使い方

## gemを使いhamlを導入する

```ruby
gem 'haml-rails'
gem 'erb2haml' # 現在erbでファイルを作成していてhamlに書き換えたい場合はこちらをインストール
```

bundle install

## ※erb2hamlを使いerbファイルをhamlに書き換える場合

```ruby
rails haml:convert_erbs # erbファイルを残して新しく作り直す場合はこちらのコマンド
rails haml:replace_erbs # erb自体をhamlファイルに変更したい場合はこちらのコマンド
```

rails haml:convert_erbsを実行してみる。

画像上: 変更前(.erb)

画像下: 変更後(.haml)
![スクリーンショット 2022-02-15 9.39.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1623433/27b06a3e-8b2b-c8dc-e3fc-81368afbcd12.png)



また、画像ではerbファイルだけではなくhamlファイルもコードが色分けされていますがこちらはVScodeのプラグイン「Better Haml」を使用しています。

これでhamllを書ける準備ができました。

## hamlの基本文法

・タグの書き方が違う

HTMLでは、<タグ名></タグ名>と記述するするhamlでは%を使って表します。例えば、

```.html
<p>これはHTMLです</p>
```

と記述するところを

```.haml
%p これはhamlです
```

と記述します。なお、閉じタグを書く必要はありません。

・インデントに注意が必要

htmlではインデントがずれていたとしても影響せずに表示されますが、hamlではインデントがしっかりしていなとエラーとなり画面表示されません。例えば

```ruby
%ul
  %li
```

と書かなければいけないところを

```ruby
  %ul
%li
```

と書いてしまった場合（そんな書き方しないとは思いますが）

```ruby
Haml::SyntaxError
```

というエラーが発生します。しかし、エラーが出ないよう書いていけば自然とコードが綺麗になっていくとも捉えられるので綺麗なコードを書くための仕組みと思いたいです。

・クラス、IDの指定方法

クラスとIDの指定の仕方はCSSの書き方と同じです。

```ruby
<div class="huga" id="hoge"></div>
```

```.haml
%div.huga#hoge
```

のようにかけます。ちなみにクラスやIDを指定すると%divを省略することができます。

```.haml
.test#test
```

## Railsのコードの書き方

・<%= %> <% %>

```.erb
<% users.each do |user| %> 
  <%= user.name %> 
<% end %>
```

hamlだとこうなります。

```.haml
- @users.each do |user| # 表示しない場合は　-　で表す
  = user.name           # 表示する場合は = で表す
```

・if分

```.haml
- if x == y
	%p yes
- else
	%p no
```

・link

```ruby
= link_to 'hamlでlink_toを書いてみる', root_path, class: 'hoge', id: 'huga'
```
まだまだ勉強途中なので書き方どんどん追加していきます。
【Automation Anywhere】メッセージボックスを表示する　- はじめてのAA

# 今日はこれを覚えよう！

メッセージボックスを表示するBotを作りながら、Automation360でBotを開発する基本の流れを押さえましょう。

#メッセージボックスを表示するBot

こんなBotを作ります。

![メッセージボックス_動作イメージ.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587845/33c42fbe-6448-3d3a-c892-807a670dfb7d.gif)

## 作り方

[Botの作成画面を起動](https://qiita.com/IQ_Bocchi/items/27a23969bcb4917824ec)し、以下の手順でBotを作成します。

---

「アクションを検索」の入力欄をクリックし、「メッセージ」と入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587845/ec2b7579-dbd2-7660-e086-e53fc9ff1756.png)

---

絞り込まれたアクションの中から、「メッセージボックス」のアクションを開始と終了の間にドラッグします。
画面右側の「表示するメッセージを入力」欄に、任意のメッセージを入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587845/527fe87c-8f06-f6c5-13fb-d9367daea714.png)

---

「実行」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587845/d68983b8-341b-d077-1952-8d8c1acf3724.png)

---

メッセージボックスが表示されます。（これができれば、この演習の目的は達成！）
確認できたら、「閉じる」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587845/60d8774a-32d3-ed3f-aab5-82d1833289fd.png)

---

Botの正常終了を知らせる「キラキラ」が表示されるので、「閉じる」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587845/2d694335-9e5f-7a45-03b8-aef421ac9836.png)

---

メッセージボックスを表示させるBotの作り方は以上です。

# この演習で学んだこと

この演習では、「メッセージボックスを表示するBotの作り方」を通じて、Bot開発の基本的な流れを学びました。

Bot開発の基本的な流れは、

- 画面の左側にある「アクション」の一覧から部品を選ぶ
- 選んだ部品をフロー上にドラッグ＆ドロップする
- 画面の右側でアクションの詳細を設定する

この繰り返しです。

さまざまなアクションを組み合わせることで、より実践的な処理を行うBotを作ることができます。

# もっと知りたい！　学びたい！

この記事を読んで、「Automation 360 の使い方をもっと知りたい！」と思った方は、以下のシリーズをチェックしてみてください。

Automation360の基礎知識や使い方を、わかりやすくまとめたシリーズで、この記事もシリーズの１トピックとなっています。

https://qiita.com/IQ_Bocchi/items/8d28f12256037b5f9058

Automation Anywhere を使い始めたばかりの方はもちろん、これから使ってみようと思っている方や、ずっと使っているけど改めて基本を学びたい方などは、ぜひチェックしてみてください！
【備忘録】puppeteerでスクレイピングをしたのでページの情報ぶっこ抜くための最低限のソース

##前書き
お仕事で指定ページのライブラリのバージョンをすべて調べろとの命が下ったため、
Puppeteerを使用して対象ページをスクレイピングして調べた
その備忘録として最低限機能だけのソース諸々を書く

Puppeteer
https://github.com/puppeteer/puppeteer

###環境
Windows 10 pro 21H2
Puppeteer 13.3.1
node.js 16.14.0

###ソース

```puppeteer.js
const puppeteer = require('puppeteer');

//対象画面のURLリスト
let urls = [
  "http://example.com/",
  "http://example.com/",
  "http://example.com/"
];

(async () => {

  const browser = await puppeteer.launch();
  const page = await browser.newPage();

  for(let j=0;j<urls.length;j++){
    console.log("page url = "+urls[j]);
    await page.goto(urls[j], {waitUntil: 'domcontentloaded'});
    let result = await page.evaluate(async()=>{
        //ここにページ読み取り用のjs記載(例としてページのURL取得する)
        var url="";

        url = location.href;
        
        return url;
    });
    console.log(result);
  }
  await browser.close();
})();
```

結果自体はコンソールの実行結果をテキストファイルから書き出して対応

現状こちらのソースを改変して業務では
・jQueryのバージョンおよびjQuery本体ファイルっぽい（jsの名前にjqueryと入ってる）ファイルの抽出
・リダイレクトしているページのリダイレクト先の確認（ステータスコードの取得もできるはず）
などをおこなった。

もちろんこれ以外にも特定の要素の値をよみとったりなどの色々な使いみちがあるので、
これで色々できそうな気がする。

本来grepでやってしまいたかったが、SSIやjsによる要素の書き換えなどの諸々の諸々が諸々だったりしたので今回の方法で対応した。
一度用意してしまえばgrepでファイルを検索かけるよりも気軽にできる（気がする）ので調査が必要になったときはこいつの存在を思い出したい。

#ToDo
・スクリーンショットやベーシック認証の突破の方法などを覚えておけばなにかしらのときに楽ができそう。
・よく特定ページで読み込まれてる全リソースを洗い出せみたいな指示がくるので、これを利用して楽できる方法を考えたい
SPRESENSEのTensorflow対応Arduinoボードパッケージを公開してみた

少し前に開発した SPRESENSE の Tensorflow 対応 Arduinoボードパッケージ ですが、さすがに自前でボードパッケージを作るのは大変なので、かんたんに利用できるように Arduinoボードパッケージを公開しました。次の手順で、Tensorflow対応の Spresense Arduino Library を利用することができます。

# [Step1] ボードマネージャURLを追加
Arduino IDEの「環境設定」を開いて、「追加のボードマネージャのURL」に次のURLを追加します。
https://raw.githubusercontent.com/YoshinoTaro/spresense-arduino-tensorflow/main/package_spresense_tensorflow_index.json

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598183/2407b47e-d68b-9671-63e8-1940ec8fc14c.png" width="450"/>

# [Step2] Spresense Tensorflow ボードパッケージを追加
Arduino IDEのボードマネージャーを開いて、Spresense Tensorflow のボードパッケージをインストールします。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598183/4834a5ca-ccd5-fd40-af60-fa27679ebf8a.png" width="450"/>


# [Step3] Spresense Tensorflow ボードパッケージを選択
ボードパッケージのリストの中から Spresense Tensorflow を選択します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598183/8990871b-345c-17d4-0265-f7adb7810929.png" width="550"/>


# [Step4] サンプルスケッチで動作確認
GitHubにある [spresense_tf_helloworld](https://github.com/TE-YoshinoriOota/spresense-arduino-tensorflow/tree/main/examples/spresense_tf_helloworld) の spresense_tf_helloworld.ino と model.h をダウンロードして Spresenseにかきこみます。プロッターに正弦波が出力されていれば正常に動作しています。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598183/38220562-b94b-437e-2a6d-5c68c5f1b028.jpeg" width="550"/>



# 注意事項
このボードパッケージには Bootloader が含まれていません。Bootloader は、正規版のSpresense Arduino Library から行って下さい。~~対象バージョンは2.4.0になります。~~ 
~~Spresense SDK のバージョンへの追随はどうしようかな…~~
Spresense SDK ver 2.5.0 に対応しました！（2022/4/3）
監視系ワンライナー


監視系ワンライナーです。下記サイトを参考にしています。ログ監視系は新規作成しました。

https://4thsight.xyz/25908


環境に合わせて読み直してください。

■CPU使用率
```cat /proc/loadavg | cut -d ' ' -f 2 |while read i; do  if [ `echo "${i} >= 0.01" | bc` -eq 1 ]; then echo ${i}  ;fi ; done
```
■メモリ利用率
```free | grep Mem | awk '{ print ($2-$7)/$2*100 }' | while read i; do  if [ `echo "${i} >= 40" | bc` -eq 1 ]; then echo ${i}  ;fi ; done
```
■Disk使用率
```df / | tail -1 | /bin/sed 's/^.* \([0-9]*\)%.*$/\1/' |  while read i; do  if [ `echo "${i} >= 40" | bc` -eq 1 ]; then echo ${i}  ;fi ; done
```
■ログ監視系
AWKを利用した場合
```tail -n 0 -F /var/log/messages | awk '/error/ {system("date")}'
```Ctl+Cを行うまで監視継続

grepを利用した場合
```tail -n 0 -F  /var/log/messages | grep -q "error"  | if [ $? = "0" ]; then more test.txt  ;fi
```一回検知後にIF文終了とともにシェルも終了します。
AWS認定SAP(ソリューションアーキテクト-プロフェッショナル)試験に合格するまでにしたこと

## この記事について

2022/02/12にAWS認定SAP(ソリューションアーキテクト-プロフェッショナル)試験(以下SAP試験)を受験し、なんとか合格することができました。

この記事ではSAP試験合格に至るまでどのような試験対策を行ったかを紹介します。

:::note warn
AWS認定試験の規約により試験内容に関することを公開するのはNGとなっているため、試験内容については一切触れません
:::

## 前提

前提として、SAP受験前の私は以下のような感じでした。

- 2012年頃からAWSにさわり始めた
- アーキテクトとして5年以上AWSを業務で使用している
- 過去にオンプレミス環境も構築したことがある(CentOS, Debian)
    - 自宅でもUbuntuサーバーを構築している
- EC2やECS、Lambda、S3、RDS関連は業務でよく触っている
- オンプレミスとAWSを組み合わせたハイブリッド環境構築に関する業務経験はほぼ無し
- SAA(ソリューションアーキテクト-アソシエイト)とDVA(デベロッパー-アソシエイト)の認定を取得済み

## スケジュール

今回は以下のようなスケジュール感でSAP試験を受験しました。

- 2022/1/14 SAA試験有効期限1ヶ月前メールが届く
- 2022/1/XX SAP試験の模擬試験受験
- 2022/1/23 SAP試験申し込み
- 2022/1/23-2022/2/11 SAP試験対策
- 2022/2/12 SAP試験受験、合格

## SAP試験対策

試験対策として以下の3つを行いました。

### 1. AWS Skill BuilderでSAPの模擬試験を実施

以前は有料だった模擬試験が2021年11月18日から無料で受けられるようになったので、現在の自分の実力を測るためにまずは模擬試験にチャレンジしました。

https://explore.skillbuilder.aws/learn/course/external/view/elearning/9159/aws-certification-official-practice-question-sets-japanese

- 参考: [無料のクラウドスキルトレーニングを拡大。2025 年までに 2,900 万人のクラウドスキル育成支援に向けて
](https://prtimes.jp/main/html/rd/p/000001397.000004612.html)
- 参考: [ななななんと！AWS認定の模擬試験が無料になりました！！ | DevelopersIO](https://dev.classmethod.jp/articles/new-aws-official-practice-questions/)

模擬試験の結果は、20問中13問正解(65%)という状態でした。

これなら少し頑張ればいけそうかな？と思ったのでSAP試験の申し込みすることにしました。

### 2. SAP試験対策本に目を通す

闇雲に学習すると時間がいくらあっても足りなさそうな感じがしたので、Amazonで評判が良かった以下の電子書籍を購入し、一通り目を通すことにしました。

https://www.amazon.co.jp/gp/product/B08F9CQ6LT/

1〜3章までは試験の範囲や用語の説明だったので、軽く目を通しました。

4章〜8章は実際の試験のような問題文と選択肢があり、その後解説が書かれていたので、ここはしっかりと読み込み、解説でわからない部分がでたら都度Google検索で調べたり、YouTubeでAWSのオンラインセミナー等の動画を視聴したりしました。

また、実際にAWSマネジメントコンソールでAWSリソースを触りながら学習を進めていきました。

（なお、今回は時間が足りず9章の模擬試験部分はほとんど手を付けられませんでした）

### 3. YouTubeでひたすらAWS関連のセミナー動画を視聴する

文章だけだとなかなか入ってこない部分に関しては、YouTubeのAmazon Web Services Japan公式チャンネルで公開されているAWS関連のセミナー動画を活用しました。

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

AWSのセミナー動画は、1本辺り数十分と長めなので、再生速度を2倍速にして視聴することで多くの動画を観ていきました。

ちなみに、広告に邪魔されると集中力が途切れるため、YouTube Premiumに入ることをオススメします。
（YouTubeの回し者ではありません😎）

## 試験当日

試験会場は、テストセンターと自宅のどちらかを選べましたが、何かトラブルが起きるのが嫌だったので今回は自宅から近いテストセンターで試験を受けることにしました。

試験当日、会場には30分前には到着し受付を済ませた後は、時間までは試験対策をしていました。

そして試験開始。

SAP試験は180分で75問解く必要があります（1問あたり約2.4分）。

即答できる問題は全くなく、苦戦しながら75問回答入力し終わった時点で、残り時間20分。

見直しフラグも半分程ついていたので、これはなかなか厳しいかな〜、と思いつつ時間いっぱいまで見直しをしました。

そして、時間が来たので最後にアンケートを記入したあと、ドキドキしながら試験終了のボタンを押したところ、

**合格**

の文字が画面上に表示されました。

（正直自信は無かったので、これは本当に嬉しかったですね）

試験終了後は、内心テンションMAX状態で、試験会場を後にしました。

その後はTwitterでつぶやいたり、会社Slackで報告したりと、いろいろ過ごしながらスコアレポートが届くのを待ちました。

そして、当日の夜にスコアレポートも送られてきてきました（届くの早い！）。

内容を確認すると、点数は750点合格ラインで、1000点満点中798点でした（ギリギリセーフ！）。

しっかりと合格していることを確認してやっと一安心できました。

## AWS認定取得まとめ

これまで取得したAWS認定は以下の通りです。今回のSAPは3つ目となりました。

| 名称 | 取得日 | スコア | 
| --- | --- | -- |
| SAA (ソリューションアーキテクト-アソシエイト) | 2019-02-13 | 816 / 1000 |
| DVA (デベロッパー-アソシエイト) | 2019-10-31 | 831 / 1000 |
| SAP (ソリューションアーキテクト-プロフェッショナル) | 2022-02-12 | 798 / 1000 |

## さいごに

今回はだいぶ運が良かったと思います。

75問解き終わった時点で見直しフラグが半分程ついており、正直合格できる自信はありませんでした。

それでも、合格ラインを超えられたのは、本当にラッキーでした。

また、日常的にAWSを触る機会が多かったのも活きていたように思います。

今回初めてプロフェッショナル系のAWS認定試験を受験しましたが、試験の雰囲気をつかむことができたので、また時間を見つけて他のAWS認定試験もチャレンジしていきたいと思います。
メモ　githubとvscodeで開いたdocker container

gitはコンテナ外で使うの？
コンテナ内で使うの？
コンテナ内で良さそうです。（→sshで秘密鍵を使うと、コンテナ内からは見えなくてはまりました。）


gitの参考
https://qiita.com/Kenta-Okuda/items/c3dcd60a80a82147e1bf#3-%E5%88%9D%E6%9C%9F%E8%A8%AD%E5%AE%9A
https://qiita.com/shizuma/items/2b2f873a0034839e47ce
## インストール後のユーザー登録(githubのどこにpushするのか設定)

を参考にgithubのユーザー名とメアドを登録する。
コンテナに入る前の端末で操作。
git config --global user.name "名前"
git config --global user.email "メアド"

git config -l で設定情報の表示
user.name=
user.email=
が表示されることを確認する。
### コンテナ内でも
このあと、vscodeでコンテナ内の端末から
git config -l で確認。
ユーザー名等表示されることを確認。表示されなければ
コンテナをリビルドすると設定が反映されていた。
Dockerfileやdocker-compose.ymlにgitの記述をしていないので、vscodeかvscodeの拡張がいい具合に情報を渡していると思う。

コンテナ内で、gitの拡張を利用するならdevcontainer.jsonに記述する。
	"extensions": ["ms-python.python","mhutchie.git-graph"]

## コンテナ内で流用される、元環境
コンテナをビルドした際に、元環境の ~.gitconfigがコンテナの同位置にコピーされる。
~/.ssh フォルダは秘密鍵はコピーされずにknown_hostsだけがコピーされている。このため、sshアクセスは失敗する。httpsアクセスする必要がある。
コンテナ内でのフォルダの移動もVScodeのファイル－＞フォルダを開くから可能。

## 更新を無視するファイル
.gitignore というテキストファイルに*.jpgなど（複数時一行ごと）記載すれば、変更が無視され、アップロードも行われない。

## テキストファイルの文字コード
秀丸で作ったテキストファイルをpushしてgithubのHPで確認したら、文字化けしていた。UTF-8で保存することで文字化け解消。

## 認証情報
httpアクセスの場合、
パスワードの代わりのトークンをgithubのサイトで作成
さらに、以下を参考に.netrcを作成すれば毎回ユーザーIDとパスワードを聞かれなくてすむ。

https://qiita.com/azusanakano/items/8dc1d7e384b00239d4d9

```:~/.netrc
machine github.com
login username
password this_is_pass
```

machineって、何かと思ったけど、「リモートマシンの名前」らしい。
https://linuxjm.osdn.jp/html/netkit/man5/netrc.5.html
ちなみに.netrcには自動ログインの情報を記述できるようで、W&B(wandb)などのログイン情報を記述することもできる。
指定のフォルダ以下の必要なファイルをまるっとcopyしたい時[robocopy]

***指定のフォルダ以下の必要なファイルをまるっとcopyしたい時の***
***robocopyのコマンド例です。***
***取り急ぎ必要なファイルを､階層を保持したままコピーしたい時のtipsです。***

##■注意事項
・アクセス権や属性のコピー等､複雑な事は考慮していません。
・ファイル名､パス名に半角スペースを含む場合は、""で囲む必要があります。
・コピー先フォルダが存在しない場合は､自動的に作成されます。

##■指定した日付以降の更新ファイル全コピー(新しい)
例：2022/1/15以降の更新ファイル全部　[MAXAGE]

~~~
robocopy <コピー元フォルダ> <コピー先フォルダ> /S /MAXAGE:20220115
~~~

##■現在から〇日以内に更新されたファイル全コピー(新しい)
例：3日以内に更新されたファイル
　　＝3日前以降の更新ファイル全部　[MAXAGEで､1900以下の数字指定]

~~~
robocopy <コピー元フォルダ> <コピー先フォルダ> /S /MAXAGE:3
~~~

##■〇日以内に更新されていないファイルの全コピー(古いまま)
例：3日以内に更新されていない更新が古いファイル
　　＝現在から3日以前が更新日のファイル全部　[MINAGEで､1900以下の数字指定]

~~~
robocopy <コピー元フォルダ> <コピー先フォルダ> /S /MINAGE:3
~~~



##■指定したファイル名全部コピー[続けてファイル名指定]
例："\*.jpg" "*.png"　(.jpgと.png拡張子のファイルのみ指定)

~~~
robocopy <コピー元フォルダ> <コピー先フォルダ> /S "*.jpg" "*.png"
~~~

※↑ファイル名に半角スペースが入る場合のみ、""で囲む必要があります。
  この例の場合では、半角スペースは不要ではありません。
【JavaScript】オブジェクトにプロパティを追加・削除する方法

JavaScriptでオブジェクトにプロパティを追加・削除する方法をまとめておく。

# プロパティの追加
オブジェクトにプロパティを追加する方法は、````.````と```[]```を使う2つの書き方がある。
以下が各方法の基本的な書き方になる。

```javascript
<オブジェクト>.<プロパティ名> = <値>
<オブジェクト>["<プロパティ名>"] = <値>
```
これを使った簡単なサンプルが以下となる。

```javascript
const student = {
	id: 1,
	name: "ryota",
};

student.age = 17;
student["grade"] = 3;

console.log(student);    // { id: 1, name: 'ryota', age: 17, grade: 3 }
```

# プロパティの削除
オブジェクトのプロパティを削除する方法は、```delete```演算子を使用する。
```delete```演算子の後に記述するプロパティの指定の書き方は追加と同様に書ける。

```javascript
delete <オブジェクト>.<プロパティ名>
delete <オブジェクト>["<プロパティ名>"]
```

これを使った簡単なサンプルが以下となる。

```javascript
const student = {
	id: 1,
	name: "ryota",
	age: 17,
	grade: 3,
};

delete student.age;
delete student["grade"];

console.log(student);    // { id: 1, name: 'ryota' }
```
ここで、オブジェクトに存在しないプロパティを指定して削除しようとしてもエラーにはならず、オブジェクトの内容は変更されない。
ブラウザバック感知の備忘録

#はじめに

仕事でブラウザバック時のみ実行される JavaScript コードを作成したので、その際の知見を書き留めておきます。

#画面読み込み完了イベントの発火
ブラウザバック時はキャッシュから画面が読み込まれることも相まって、使用するブラウザによって画面読み込み完了イベントの発火の扱いが異なります。
いくつかあるイベントの種類の中でも、「**pageshow**」はメジャーなブラウザ（Google Chrome, Firefox, Safari, Edge）のいずれにおいてもキャッシュから読み込まれた場合でも発火します。

#ブラウザバックかどうかの見極め
ブラウザやキャッシュの状況によって反応が異なるので、併記した方が良い二つの判定方法を記載します。

## 1. PageTransitionEvent.persisted
**PageTransitionEvent.persisted** はキャッシュから読まれたかを boolean で返すプロパティです。

```javascript
window.addEventListener("pageshow", function(event){
    if (event.persisted) {
        // キャッシュから読み込まれた際の挙動
    }
});
```

といったように使います。

## 2. PerformanceNavigationTiming.type
**PerformanceNavigationTiming.type** は文書ナビゲーションがどのように読み込まれたかを示すプロパティであり、「**back_forward**」がブラウザの履歴から遷移した際の値です。

```javascript
window.addEventListener("pageshow", function(event){
    var entries = performance.getEntriesByType("navigation");
    entries.forEach(function(entry) {
        if(entry.type == 'back_forward') {
            // ブラウザの履歴から読み込まれた際の処理
        }
    });
});
```

といったように使います。

# 非推奨な判定方法
PerformanceNavigationTiming.type 以前に存在し、現在は非推奨となってる判定手法として **PerformanceNavigation.type** が存在します。
PerformanceNavigation.type は unsigned short のプロパティであり、**2** がブラウザの履歴から遷移した際の値です。

```javascript
var type = window.performance.navigation.type;
var type = performanceNavigation.type;
```

といった構文で値を取得できます。

PerformanceNavigation.type はブラウザバックへの対応手法を検索すると使用している記事が見つかることもありますが、現在（2022年2月）時点で使用が非推奨となっており、代わりに PerformanceNavigationTiming.type の使用を推奨しています。
サービスアカウントの認証を行う【CloudRun】

# やりたいこと
- サービスアカウントとしてCloudRunサービスを呼び出す時の、IAM認証を設定する。
- CloudRunサービスの設定で、「Cloud IAM を使用して承認ユーザーを管理します。」をオンにした場合の認証

# 手順
- CloudShell/ローカルターミナルにログインしているIAMユーザに、ロール「サービスアカウント トークン作成者」を付与する。
    - 「IAMと管理」>「IAM」> 該当のユーザの権限編集画面 >「サービスアカウント トークン作成者」を付与
    - サービスアカウントではないので注意

- 以下コマンドで、サービスアカウントのトークンを取得し、そのトークンをBearerに設定しCloudRunサービスを呼び出すことができる。
    - 「impersonate-service-account」オプションが、サービスアカウントとなりきって〜というものらしい。

```bash
PROJECT_ID=hoge
SERVICE_ACCOUNT=fuga@${PROJECT_ID}.iam.gserviceaccount.com
CLOUDRUN_URL=https://piyo.run.app        

token=$(gcloud auth print-identity-token --impersonate-service-account=${SERVICE_ACCOUNT} --audiences=${CLOUDRUN_URL})

curl -H "Authorization: Bearer ${token}" ${CLOUDRUN_URL}
```

# 参考
- [公式ドキュメント　gcloud authprint-identity-token 
](https://cloud.google.com/sdk/gcloud/reference/auth/print-identity-token)
- [公式ドキュメント　デベロッパーの認証](https://cloud.google.com/run/docs/authenticating/developers)
- [公式ドキュメント　サービス間認証](https://cloud.google.com/run/docs/authenticating/service-to-service)
- [サービスアカウントに直接成り代わって gcloud コマンドを実行する](https://qiita.com/Hikosaburou/items/44557cc3892174797b78)
- [【GCP】CloudRun のサービス間の認証 - Https](https://qiita.com/wwalpha/items/90a96cc6e5cd6d10c0a5)
- [Cloud Runのサービス間認証](https://qiita.com/takuuuum/items/7787b89be4a22d8f303e)
【超初学者向けGitHub】初回動作〜ローカルプロジェクトをリモートリポジトリにアップロードまで


OSをWindowsからMacに変更した際、初回動作〜アップロードまでの流れをすっかり忘れていたので備忘のためのメモです。
誤りや認識違いがあればご指摘くださると大変助かります…！また、初投稿のためいろいろ大目に見ていただけると助かります。。
参考にさせていただいた記事やページは本文下部に記載しています。

# 開発環境と前提
- MacOS M1
- gitはターミナルにインストール済み
- GitHubのアカウント登録済み

# 手順①初期設定
ターミナルで個人識別情報を設定する。

```
# ユーザー名を設定
git config --global user.name "ユーザー名"

# メールアドレスを設定
git config --global user.email "メールアドレス"

```
<!-- #設定ができてるか確認
git config --list -->

<!--確認コマンド打って以下行があればOK
- user.name=設定したユーザー名
- user.email=設定したメールアドレス　-->

# 手順②公開鍵情報をコピー

以下コマンドを実行しエンターを押す。

```
ssh-keygen -t rsa -C "メールアドレス"
```

次に以下コマンドを打つと「ssh-rsa」から始まり設定メールアドレスで終わる長い文が出てくる（これが公開鍵の中身）のでこれをコピーしておく。
※この画面は「:q」を押せば元の画面に戻れる。

```
less ~/.ssh/id_rsa.pub
```

# 手順③コピーした公開鍵情報をGitHubに登録
1. 画面右上の自身のアイコン→Setting
1. 左側の「SSH and GPG keys」を選択
1. 「New SSH key」をクリックし先程コピーした公開鍵情報を貼り付ける。※titleは使用端末がわかるような名前にしておくとわかりやすい。


# 手順④GitHub上にリポジトリーを作成
GitHubのマイページにある「Repository」タブ選択→「New」でリポジトリーを作成。
この時リポジトリー名とローカルプロジェクト名は一致させておく。
※リポジトリーとはデータの保管場所。

# 手順⑤GitHub上にデータアップロード
ここからまたターミナルの操作に戻ります。


※macの人は対象フォルダをターミナルにドラッグすればパスが反映される。

```
# アップロードしたいローカルプロジェクトのフォルダに移動。
cd / フォルダパス

# ローカルリポジトリの作成（この時点ではまだ空）
git init

# ファイルをインデックスに登録。インデックスとはコミットするファイルを登録しておく場所。
git add .

# ローカルリポジトリにファイルを反映
git commit -m "コメント入力"

# ローカルリポジトリをリモートリポジトリに反映　　 ※「git@〜」のURLはGitHubのリポジトリーからコピーしてくる
git remote add origin git@github.com:GitHubのユーザー名/リポジトリー名.git

# アップロード
git push -u origin master
```

アップロードに成功すると、GitHubのリポジトリー内にデータがアップロードされています。

<!-- もしここまでの動作でなんかしらのエラーが発生して詰まってしまったって人がいれば
自身がつまったエラーと解決法について別記事でまとめたので、よかったらこちらを参照してみてください。 -->

この手順の中でOSの変更によるエラーで弾かれたりして時間を食ったので、自身の備忘のためエラーと解決法一覧についても後日まとめたいと思っています。


# 参考記事

https://qiita.com/devzip8/items/28ac253ea295ad6c2b73


https://kray.jp/blog/expound-git-add/
L2通信について

#背景・目的
L2レベルの通信を調べる機会があったので、整理しておく。
今回の対象は、MPLS、PPP、イーサネットとする。

#内容
## MPLS
- Multi-Protocol Label Switchingの略。
- IPアドレスの代わりにラベルを使用する仕組み。ラベルを見てパケットの連携先を判断する。
- LSR（Label Switching Router）と言われるMPLS対応のルーターが必要。
- 挙動としては、ルーターがラベルを貼り付けて、このラベルに従って通信経路を決めていく。
- 4バイトのMPLSヘッダをパケットに付与するため、高速伝送が可能。（IPヘッダの場合は20バイト）

## PPP
- Point-to-Point Protocolの略。
- 電話回線などの通信回線を使用。１：１の通信で使用されるプロトコル。
- PPPは、NetWareなどTCP/IP以外のプロトコルにも対応するほか、伝送エラーの検出、アドレス情報の交換、接続相手の確認など機能を備えている。
- PPPoE（PPP over Ethernet）は、イーサネット上でPPPのデータをやりとりし、接続状態を管理するプロトコル。

## イーサネット
- 有線LANなどで用いられる通信規格。
- 主にパソコンなどの信号でやり取りに用いられている規格。
- イーサネット＝有線LANケーブルの規格として、広まっている。
- 工場などの産業用通信、家電、自動車に搭載されるコンピュータや通信機器を結ぶネットワークにも利用されている。

#参考

- https://wa3.i-3-i.info/word12054.html
- https://www.infraexpert.com/study/mpls1.html
- https://atmarkit.itmedia.co.jp/fnetwork/tokusyuu/11mpls/mpls04.html
- https://www.otsuka-shokai.co.jp/words/ppp.html
- https://milestone-of-se.nesuke.com/nw-basic/ppppppoe/ppp-summary/
- https://www.yupiteru.co.jp/yupista/article/ethernet.html
gitがhttpsのみ通信可(ssh接続不可)の時に、認証を自動化したい

 # 要旨
リモートリポジトリがssh通信を受け付けておらず、https接続のみ使える、という場合があったりすると思います。~~ポート変えてsshあけておいてほしいですよね~~ その場合、認証が毎回問われてめんどくさいので自動化したいという話です。

環境：Ubuntu-20.04(wsl, ローカル) EC2上のgitlab(リモート) 

 # 結論
https://florianwinkelbauer.com/posts/2021-05-27-git-gnome-keyring/

この方の通りにしてください。

# 元記事読むのが面倒な人向けに

```bash
$ sudo apt-get install make gcc libsecret-1-0 libsecret-1-dev
$ cd /usr/share/doc/git/contrib/credential/libsecret
$ sudo make
$ git config --global credential.helper /usr/share/doc/git/contrib/credential/libsecret/git-credential-libsecret
```

次に認証したら、以降はパスワードが暗号化されて保存され、自動認証してくれるので楽になると思います。

# 補足

ネットでいくらか検索するとlibgnome-keyring-devをインストールしろとかいろいろ出てくるのですが、Ubuntu-20.04からはdeprecatedになってパッケージがインストールできなくなってました。あとはシェルスクリプトを書いている記事( https://yaaamaaaguuu.hatenablog.com/entry/2017/08/22/223612 )もあり、もちろんそれでもいいのですが、パスワードが平文で環境変数に保存されてしまうこともあり、さすがに公式のツールでほかの方法が存在するだろう、と思って探してました。というか元記事によるとgitってパスワード認証やめとけって言ってるんですね。~~なおさらssh使っとけって話ですね~~
【JavaScript関数ドリル】を毎日やる【勉強用】その6　tail関数


 

#【JavaScript関数ドリル】初級編のtail関数の実装のアウトプット

       
```javascript:tail関数の挙動
_.tail([1, 2, 3]);
// => [2, 3]
```
先頭を取り除いたものを新たに出力する
##tail関数の課題内容

https://youtu.be/nxI082IC7Xs

##tail関数に取り組む前の状態
- 元の配列を変更しないよう気をつける

##tail関数に取り組んだ後の状態
- 数分で作成できた
- 変数名の付け方もnewばかりでなく、関数名を入れた方がわかりやすいと気づいた
- もっとサクッとfor文を使えるようになる


##tail関数の実装コード

```javascript:
const tail = (array) => {
    const newArray = array.slice();
    newArray.shift();
    return newArray;
};

console.log(tail([1, 2, 3]));
// =>[2,3]
```



##tail関数の解答コード

```javascript:
function tail(array) {
  const tailArray = [];
  for(let i = 1; i < array.length; i++) {
    tailArray.push( array[i] );
  }

  return tailArray;
}

console.log( tail([1, 2, 3]) );
// => [2, 3]
```
eslint-plugin-reactで未使用メソッドを検知：no-unused-class-component-methods

eslint-plugin-reactに正式に未使用メソッド検知が正式にサポートされるようになった。

```..eslintrc.json
"react/no-unused-class-component-methods": "warn",
```

## 検知できる内容
- 未使用のインスタンスメソッド：this.hoge()
- 未使用のインスタンス変数：this.varHoge
CSSやJSで画像リサイズ

フロント側で画像リサイズ方法を紹介します、取得した画像が大きすぎるため小さくして表示したい、送信したい場面に役立つかと思います。

## 画像をリサイズして表示する
表示するだけであれば、わざわざ容量を落とす必要もないためCSSで調整可能です。
新たなCSSプロパティであるobject-fitでのリサイズがオススメです。

### デモ
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="podWwPG" data-user="miyakezaka" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/miyakezaka/pen/podWwPG">
  Untitled</a> by miyakezaka (<a href="https://codepen.io/miyakezaka">@miyakezaka</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

object-fit: cover;でアスペクト比を維持したまま横幅と高さを自動で調節してくれます。

### CSS
```
img {
  object-fit: cover;
  width: 100px;  //任意の数値
  height: 100px; //任意の数値
}
```

値によってリサイズの種類を設定できます。
MDN object-fit
https://developer.mozilla.org/ja/docs/Web/CSS/object-fit

### IE対応
IEに対応する場合はポリフィルを読み込む必要があります。

### HTML
```
<script src="https://cdnjs.cloudflare.com/ajax/libs/object-fit-images/3.2.4/ofi.min.js"></script>
<script>
　objectFitImages();
</script>
```
### CSS
```
img {
	object-fit: cover;
	font-family: 'object-fit: cover;'; /*IE対策*/
}
```

## 画像本体をリサイズして送信する
送信する際は、見栄えだけではなく本体の容量を落とすケースが考えられます。
Canvasを使用してbase64形式でリサイズが可能です。

### デモ
https://secret-black-moji-5876.ssl-lolipop.jp/article/image-resize/
ディベロッパーツールで画像を確認すると画像がリサイズされているのがわかるかと思います。
※デモの画像だと元画像の大きさと大差がないので、base64のため容量は上がっています。

### JS
```
window.addEventListener('load', function(){
  const elemiImg = document.getElementById("img");
  // canvas要素を生成
  const cvs1 = document.createElement('canvas');
  const ctx1 = cvs1.getContext('2d');
  cvs1.width = elemiImg.width;
  cvs1.height = elemiImg.height;
  ctx1.drawImage(elemiImg, 0, 0);
  //　Base64を作成
  const base64_1 = cvs1.toDataURL("image/png");

  // 最大幅、最大高さを設定
  const maxWidth = 200, 
        maxHeight = 200;
  // Imageのインスタンス生成
  const img1 = new Image();
  // Imageインスタンスにbase64格納
  img1.src = base64_1;
  // img1.srcを読み込まれてから安全に実行
  img1.onload = function() {
    // 読み込み画像のアスペクト比調整
    let width, height;
    if(img1.width > img1.height){
      const ratio = img1.height/img1.width;
      width = maxWidth;
      height = maxWidth * ratio;
    } else {
      const ratio = img1.width/img1.height;
      width = maxHeight * ratio;
      height = maxHeight;
    };
    // canvasタグを生成
    const cvs2 = document.createElement('canvas');
    cvs2.width  = width;
    cvs2.height = height;
    
    // コンテキスト(canvasの描画に必要なもの、2Dグラフィックを描画するためのメソッド)を取得
    const ctx2 = cvs2.getContext('2d');

    // canvasに計算したアスペクト比で画像を描画する
    ctx2.drawImage(img1,
      0, 0, img1.width, img1.height,
      0, 0, width, height
    );
    // Canvasでリサイズしたbase64を取得
    const base64_2 = cvs2.toDataURL(img1);

    // 挿入用の画像を生成 〜 出力
    const img2 = new Image();
    img2.src = base64_2;
    const elemAfter = document.getElementById('after');
    elemAfter.appendChild(img2);
  };
});

```

送信する際はFileAPIで読み込むケースが多いかと思いますが、また別の機会に載せたいと思います。

最後までご覧戴き、ありがとうございました。
初めてgit patchを使った

あまり遭遇する人はいないだろうけど数年前に分岐したリポジトリA,BがあってAで開発進めていた内容を今回はBにも適用する必要があった。

`git patch` を使うと良さそうとのことだが聞いたことあるけど使ったことはなかったのでメモを残しておく。
 
### まずAで開発を進めていたコミットからパッチを作成する。

前提：Aでの開発はmasterからhogeというブランチで作業を進めていたとする。

最新のmasterをローカルにチェックアウト（既にチェックアウトしてるならpull等で最新に）
```bash
git checkout -b master origin/master
```

### パッチファイルの作成

`hoge` ブランチをチェックアウトしてパッチを作成。

```
git checkout hoge
git status
```

ここで指定するのはローカルのmasterブランチ

```
git format-patch master
```

実行すると以下のようなファイルが生成される。

```
0001-composer-92684.patch
0002-API-HogeClass-92791.patch
0003-API-93064.patch
0004-API-93124.patch
```

中身はいつも見てるコミットログのようなもの。

### 分岐してるリポジトリBで取り込む

Aリポジトリでさっき作成したパッチファイルをBリポジトリにコピー・移動する。

### 取り込み

```
git am -3 0001-composer-92684.patch
```

`-3` は3-way merge

成功すると以下のようにコミットログが表示される。

```
Applying: ほげほげほげ
```

### 失敗した場合

失敗する理由としては私の場合は以下のようなものだった。
・Bリポジトリに存在しないファイルの差分
・Bリポジトリでは中身が全然異なるファイルの差分
・Bリポジトリのファイルに対象の行がない
・ファイル名のリネーム

```
Patch failed at 0001 ほげほげ
```

このようなメッセージが表示された場合は残念ながらマージに失敗しているので差分を確認する。

差分は発生していないと思うので以下のコマンドで適用＆確認を行う。

```
git apply -v 0001-composer-92684.patch
```

ここで差分がでてるならコンフリクトを解消して以下のコマンドで次のパッチへ進む。

```
git am --continue
```

差分なんか出ないんだけどって時はパッチファイルを直接開いて原因を解決する。

あとはこれの繰り返し。
javascript 01_出力

出力用の文
1 警告フォームを出す
  alert();
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1067004/b524cc51-6ef0-71c2-51a7-8356c4891054.png)


2 Bodyの内容を書く
 document.write();
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1067004/d673d328-dad7-dee5-7caf-f5cf9a5350b0.png)

3 consoleで内容を書く
  console.log();
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1067004/1c04d127-ba18-19cc-bd03-9aac6cd16a69.png)
Python のあまり知られていない便利な言語構文3選

あまり知られていないけれど、便利なPythonの構文3つを紹介。どれもちょっとしたことだが、汎用的で使える場面が多い言語構文。他の言語には同等の機能がないことが多いから知られていないのだと思う。
ちなみにPython3のお話、Python2にあるのかは知らん。

# for-else、while-else 文
`for`の後ろに`else`句をつけると、ループの中で`break`しなかった場合のみ実行してくれる。`while`も同様。

```python
def for_else(id):
  ...
  for item in items:
    if item.id == id:
      break
  else:
    item = create_item()
    item.id = id

  something_to_work_with(item)
  ...
```

例えば上記は条件に合うアイテムをループで探して、見つかれば`break`でループを離脱、見つからなければ新しく作るというコード。他の言語だとこれをやるために別にフラグ変数を用意したりすることもあるが、Pythonではこのようにシンプルに書ける。
（これは例なので全く同じことをやりたいだけなら内包表記とかもっと良い書き方がある。）

# try-except-else 文
`try`や`except`の後ろに`else`句をつけると、`try`の中で例外が発生しなかった場合のみ実行してくれる。Pythonでは`except`が例外発生有りの場合、`else`が発生無しの場合、そして`finally`が発生の有無に関わらず実行という3種の処理を定義できることになる。

```python
def try_except_else():
  ...
  try:
    a = try_get_a()
  except SomeError:
    a = DEFAULT_A
  else:
    a = some_conversion(a)

  something_to_work_with(a)
  ...
```

例えば上記は`try_get_a()`が成功した場合のみ、その返り値に対し`some_conversion`を適用するコード。

一見以下と同じだが、以下とは異なり`try`の中が1行と最小限になっていてより優れたコードだと言える。なぜなら下記のコードだと`SomeError`が`try_get_a`で起きたのか`some_conversion`で起きたのか分からないから。設計上`some_conversion`では`SomeError`は発生しないとしても、バグにより実は発生していてその例外を握りつぶしていた、なんて事が起こりうるので一般に`try`の中は最小限にすべきである。

```python
try:
  a = try_get_a()
  a = some_conversion(a)
except SomeError:
  a = DEFAULT_A
```

特に、独自に定義した例外を`except`する場合はまだ良いが、Python標準の例外（`ValueError`、`KeyError`など）を`except`する場合、`try`の中は基本的には1行にした方が良い。標準の例外は様々な場所で発生しうるので、想定しない場所で発生した例外を意図せず握りつぶさないようにするためである。

# raise-from 文
`raise SomeError() from e`のように`raise`の後ろに`from`をつけると例外の原因となった例外を設定できる。この原因となった例外の連鎖はトレースバックにも表示されるようになる。

```python
class ItemNotFoundError(Exception):
    pass

items = { 'a': itema, 'b': itemb }
def get_item(id):
  try:
    return items[id]
  except KeyError as e:
    raise ItemNotFoundError() from e

get_item('c')
```

例えば以下のようなトレースバックが表示される。

```
Traceback (most recent call last):
  File "raise_from.py", line 11, in get_item
    return items[id]
KeyError: 'c'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "raise_from.py", line 26, in <module>
    get_item('c')
  File "raise_from.py", line 13, in get_item
    raise ItemNotFoundError() from e
__main__.ItemNotFoundError
```

`ItemNotFound`の原因となった`KeyError`の発生箇所までちゃんと表示してくれている。

例外の連鎖は例外の設計までちゃんと行なっていれば自然と必要になってくる。例えば上記のコードで`get_item`関数がtry-exceptを一切せずに、`ItemNotFoundError`ではなく`KeyError`を直接投げたらどうだろう？`get_item`が`dict`型を使ってIDの管理をしているという実装詳細が外に漏れている。例えば後々この部分がデータベースになったらまた別の例外が投げられることになり、せっかく`get_item`という名前で処理を抽象化しているのにそれが中途半端になってしまう。

例外の連鎖の鎖はデバッグの際のために記憶しておいた方が良い。鎖を記憶しておかないと一番上の例外の発生点からのスタックトレースしか得られず、デバッグがやりづらくなる。全ての鎖を記憶しておけば根本的な例外の発生原因にすぐにたどり着ける。

多くの言語では原因例外を例外のコンストラクタで渡すことで記憶することが多い（`throw SomeError("Message", e);`のような感じ）が、これにはデメリットがある。独自例外を定義する者はコンストラクタを定義するとき自分の責任で原因例外を渡せるようにしなければならないという点である。もし原因例外を渡せるような作りになっていなければ、使用者側ではどうしようもない。

例外の連鎖を例外システムの一部であると捉え言語構文として導入しているPythonはよく考えられていると思う。


# 感想
どれも超便利なので他の言語も真似して導入して欲しいのですが、全然真似してくれない...
互換性を崩さず簡単に導入できそうなんですけどねぇ。
【自分用メモ】GoogleドライブをWSL2にマウントする

#あらすじ
Googleドライブがある日急にWSLからアクセスできなくなった。mountコマンドでしのいだ。

## 「バックアップと同期」から「Googleドライブ」へ
以前は、GoogleドライブをWindowsにマウントする方法は「バックアップと同期」と「Googleドライブ」の両方あった。
移行期間だったらしいが、2022年1月半ばから？「バックアップと同期」が廃止され、「Googleドライブ」のみになった。

両者の違いは以下の通り。
「バックアップと同期」：最初の１アカウントは「C:\Users\ユーザー名\Googleドライブ」、２アカウント名以降は「C:\Users\ユーザー名\Googleドライブ（Googleアカウントのメールアドレス）」にマウントする

「Googleドライブ（アプリ）」：「H:\」、「I:\」のような仮想ドライブにマウントする

ぼくはWSL（Windows Subsystem on Linux）を使うと、前者は/mnt/c/Users/ユーザー名/Googleドライブのようにマウントされるが、後者は昔はアクセスできなかったので使わなかった。
（Linux側で何らかのサービスを起動したり、Windows側でSSHサーバーを起動したりするハックはあったが、手が出なかった）

今回、WindowsからはH:\などとしてアクセスできるけど、WSLがどうなるのか不安だったが、普通に/mnt/h/からアクセスできるようになっていた。
## ある日アクセスできなくなった

しばらく調子よく使っていたが、ある日アクセスできなくなった。

``` shell
$ cd /mnt/
```

とすると、

```
ls: 'h'にアクセスできません: 無効な引数です
```

と言われる。

```
$ cd h
```

と強行すると

```
　ls: '.'にアクセスできません: 無効な引数です
```

と言われる。
H:\がアンマウントされている状態だ。

調べたら、明示的にマウントしてやるといいことが分かった。
以下の記事を参考にした。

https://atmarkit.itmedia.co.jp/ait/articles/1806/08/news042.html

具体的には、

```
　$ sudo mount -t drvfs H: /mnt/h
```

とする。

ここでマウントポイントとなる/mnt/hはディレクトリーで、ない場合はmkdirしておく必要がある。
ぼくは上述の通り、WindowsかWSLが自動的に作っていたので不要だった。

なぜ急にアンマウントされたのかは不明。
明示的にアンマウントするには、umountを使えばいいらしいが、上記の記事では有料部分になっている。
とりあえずWSLで作業が続行できて助かった。

（この項終わり）
Unity URPでいきなり白黒になってしまったときの対処法

何気なく、エディタ作業をしていて、ふとした作業でいきなりこんな画面になる時がある。

![2022-02-15_14h40_19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72960/7b6090eb-2760-4648-c373-d708f4d76011.png)
（本当は色がついている画面が白黒になってしまっている）

画面をリロードしても、Unity再起動しても、Windowsを再起動しても、再インポートしても、
何をしても戻らない。

仕方ないので、Git でひとつ前のシーンに戻ってみたら、正常に戻れた。

![2022-02-15_14h40_36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72960/e20406ff-36f2-cf37-93b8-c8e29cb78e8e.png)

その後、シーンの差分を調べてみると、Lighting > Other Settings > Fog > Density にNaNが入っていた。
**何でNaNが！？**（これが言いたかった）

![2022-02-15_14h46_43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72960/220b4605-8b47-270b-7c44-39d785f06bef.png)

これを正常値にしたら元に戻った。

NaNだかなー…
Ruby で XML を rexml で パースする

# はじめに
移植やってます。
( from python 3.7 to ruby 2.7 )
# 概要
バイオインフォマティクスには色々な書式の元データがあります。
それを同じ形式にパースすれば、その後の処理が楽になります。
`activesupport`や`nokogiri`を使用する方法もありますが、ひとまず標準ライブラリの`rexml`でやりたいと思います。
# どうすRuby
```test.xml
<a>
    <b>
        <title>test</title>
        <value count="2">MS2</value>
    </b>
</a>
```
```ruby:main.rb
require 'rexml/document'

doc = REXML::Document.new(File.open("test.xml"))
puts doc.elements['a/b/title'].text
puts doc.elements['a/b/value'].attribute('count').value

# output
test
2
```
思ったより、簡単にできました。
rexmlの作者さん、ありがとうございます。

https://docs.ruby-lang.org/ja/latest/library/rexml=2fdocument.html
# メモ
+ Ruby の rexml を学習した
+ 百里を行く者は九十里を半ばとす
AWS クラウドプラクティショナー (CLF) 合格したけど思ったよりも難しかった件

#【2022年2月】AWS CLF 合格体験記

##まず

AWSの資格取得を指定されたので、というのもありますし去年一度挫折したAWSに再チャレンジということで入門と位置付けられるAWSクラウドプラクティショナーを受けてきました。結果は合格です。オンプレミスでの開発の経験しかなかったのでクラウドの基礎の基礎を勉強できた良い体験でした。継続して上位資格にも臨もうと思います。

**でもね**、、って話です。

##「 でも 」 とは？
クラウドプラクティショナー　合格　とかってググると
*文系新卒の私が1ヶ月で合格しました！
ITに疎い専務が2週間でAWS資格に合格！？
【確定版】3日で受かるAWS CLF勉強法*

こんなのがたくさん出てくるので勘違いしてました。

AWS CLFはIT業界での実務経験さえあればほぼノー勉でもいけるクラウドの一般教養的資格なのだと。

だから声を大にして言いたいです。

**舐めて勉強せずに受けると落ちますよ！マジで！**

IT業界での実務経験なしで2週間で受かった、みたいな話は割と毎日ちゃんと勉強時間を確保して土日はみっちりやりこんだ方のケースだと思います。

私はネットフリックスでゆるキャン△とか流しながら適当にテキスト読んで概要理解すれば受かるんでしょ？みたいに思って舐めプのまま模試解いたら40％くらいしかとれなくてめちゃくちゃ焦りました。

試験前日、もうこれ絶対受からないと焦り胃痛を我慢しながら模試を回しまくってなんとか滑り込んだわけです。もちろん私の勉強のやり方が要領悪く飲み込みも早い方ではないから、というのもあるのですが。

##確実に受かるために

上記で舐めプじゃ受からない難易度だということはお伝えできたかと思います。
じゃあちゃんと勉強しよう。そうなった時のおすすめの書籍やコンテンツをお伝えします。

1.公式の緑本

Amazonでクラウドプラクティショナーと調べると一番上に出てくる公式テキスト、通称緑本。これ、絶対読んだほうがいいです。やっぱり公式という信用は強みです。ただ、あの質素に専門用語を並べ立てる文体は最初に触れるべき書籍とは思えません。以下の勉強法でアレ？と思った時に頼れる公式書籍、くらいに思うのがいいと思います。

2.Youtube

話の上手な方が図を用いながらざっくりと説明してくれます。やっぱりスマホ眺めてるだけでちゃんと知識になっていくのはお手軽です。もちろん机に向かうのが一番だけど忙しいとなかなかできないですから妥協案としてアリです。

3.AWS しくみと技術がしっかりわかる教科書

Amazonで「AWS しっかり」などと検索するとでてくるオレンジ基調の表紙の書籍。これ、本当におすすめです。図が丁寧、言葉もわかりやすい、順序も体型立ててある、そして意外と細かいところまで網羅されてます。まずはこれ読んでみましょう。AWSがなぜ用いられるのか、そして全体的なサービス像が掴めると思います。分からなかったところ、もっと詳しく知りたいところはYoutubeなりGoogleなり調べるとさらに理解度が深まると思います。

4.Udemyの模試

オススメというよりは必須です。もう。必須。セールの時期に模試を買いましょう。2や3で基礎知識をつけたらすぐに模試を解きましょう。模試を買いましょう。模試は合格する必要はないです。Udemyの模試は本当に優秀で、解きながら知識をつけられる、しかも量も膨大なので模試は最後に取っておくみたいなことはせずガンガン解きましょう。模試を買いましょう。模試を買いましょう。

2022年2月時点では2つの模試のラーニングコースがありました。どちらも買いましたが一長一短でした。
「この問題だけで合格可能！」の方は解説しっかり、難易度も易〜難と網羅されており、最初にやる模試として。忙しければこっちだけでも十分だと思います。ただ難点は問題文が丁寧すぎること。実際のAWS認定試験の問題文はかなり文体がかたく、表現も独特です。丁寧な問題文に慣れすぎると本番で動揺するのでそれは頭に入れておきましょう。
もう一つの方は解説はかなり適当、というかAWS公式のコピペみたいな感じで不足はありましたが実際の難易度、問題文に近く念のためやる、というのはアリです。ただ私が買った時点では受講生(要は買った人？)が7人しかいませんでした。「この問題だけで合格可能！」の方は3万人くらいいるんですが...。

勉強法としては以上になります。私は公式模試は受けませんでした。

##本番

Udemyの模試を激推ししておいてなんですが、やはり本番と模試は違います。本番はかなり荒が目立つ試験だな、という印象でした。例えばですが課金に関する問い合わせ先にAWSコンシェルジュというチームがあると模試で学んだので"コンシェルジュ"というワードを頭にインプットしたのですが、本番で選択肢として出てきたのは"concierge"という英語でした。いや、英語ですらない。フランス語。

｢コンシェルジュないじゃん！！」

ってなりました。冷静にスペル読んでやっと気づけたからよかったですが。

結局自信を持って絶対に間違いないと思えた問題は半分程度でした。残りは選択肢を絞って捻り出した答えが割と当たっていたおかげで受かったんだと思います。

##最後に

やはり勉強法としては模試を解くのと教科書やYoutube、Googleで情報を補完するのとを交互に行き来するのが正攻法かと思います。

それから再三言いまずが舐めないようにしましょう。

舐めずにちゃんと勉強すれば確かに2週間での合格は割と標準的な範囲かと思いますし、クラウド技術に疎くても一ヶ月あれば大丈夫です。

実際に受かってみて難易度を少し軽視しすぎな風潮が感じられたのでこういった内容になりましたが、少々おおげさな部分もあるかと思いますのでご容赦ください。

ありがとうございました。
werkzeug.security（generated_pw_hash,checked_pw_hash)を読む

##はじめに

前々からwerkzeug.securityに興味があったので、
今回、表題の機能を調べてみることにしました。

### generated_pw_hashを見る

先ずは公式のドキュメントを見る。

[公式ドキュメントのリンク](https://werkzeug.palletsprojects.com/en/2.0.x/utils/#general-helpers)

>Security Helpers
Changelog
***werkzeug.security.generate_password_hash(password, method='pbkdf2:sha256', salt_length=16)***
Hash a password with the given method and salt with a string of the given length. The format of the string returned includes the method that was used so that check_password_hash() can check the hash.

>The format for the hashed string looks like this:
method$salt$hash

>If PBKDF2 is wanted it can be enabled by setting the method to pbkdf2:method:iterations where iterations is optional:

>pbkdf2:sha256:80000$salt$hash
**pbkdf2:sha256$salt$hash**

公式ドキュメントではこんな感じで記述されている。

flaskでコードを記述してみる。

```python:flask
from werkzeug.security import generate_password_hash, check_password_hash

@app.route('/pw')
def pw_check():
    pw = "password"
    i = generate_password_hash(pw)
    return i

```

```window:プラウザで確認(1回目)
pbkdf2:sha256:260000$rzFFNyrXBBvgZ7sU$c63910b234630df2c0376999c51b74e02484c35ae38845c47c464b38bac5fd47
```

プラウザにリロードをかけてみる。

```window:プラウザで確認(2回目)
pbkdf2:sha256:260000$IFAymxGymf80SRp1$abd4d4657dd8ae9fee49e7bedcf3d2053c5a1caba16008f0afaba1c6e310141f
```

１回目と2回目を比較すると、値が変わっていることがわかります。

先ず、文頭のpbkdf2:sha256
公式ドキュメントを見る感じでは、メソッドの部分に該当し、
260000はpbkdf2を反復させる回数。

間のIFAymxGymf80SRp1という文字列がsaltに該当する。
salt_length=16はどうやら文字列の長さを指しているらしい。
最後の長い文字列がhash（ハッシュ化された値）。

sha256
こちらはハッシュ関数。
与えられた文字列・数値を256ビットの値（固定長)に変換する。
SHA-2とSHA-1の二種類があり、こちらはSHA-2に分類される。
SHA-1はGoogleなどで脆弱性が報告されており、基本的にSHA-1は使わない。
どういう仕組みでハッシュ化しているのか、今度調べてみたいと思います。

###saltって何？
先程、画面をリロードしたときに値が変わりました。

この値を変えている要素がSaltです。

Saltはハッシュ化する際に元の文字列にランダムな文字列を付与することです。

password+saltの文字列をハッシュ化していたので、
同じpasswordでもhash化された値が変わっています。

一回目がpassword+Aとして、
二回目がpassword+Bでハッシュ化されているので、
値が変わってくるといった具合です。

Saltがないと何が問題なのか？
→ハッシュ関数がわかってしまうと、平文を解読されてしまうから。

**また、saltを付与することでハッシュ関数を解読されても、saltが付与された文字列で解読がされるので、パスワードの特定に繋がらない。**

###checked_password_hash

>***werkzeug.security.check_password_hash(pwhash, password)***
Check a password against a given salted and hashed password value. In order to support unsalted legacy passwords this method supports plain text passwords, md5 and sha1 hashes (both salted and unsalted).

>Returns True if the password matched, False otherwise.

>**Parameters**
>pwhash (str) – a hashed string like returned by generate_password_hash().

>password (str) – the plaintext password to compare against the hash.

>Return type
>bool

checked_password_hashはpwhashとpasswordの値を比較して、TrueかFalseを返す。

ドキュメントの説明文を見た感じだと、
saltも含まれる値で引数に渡されるらしい。

先程のreturnの返り値にはsaltも含まれていたので、
saltもわかっている状態で引数が渡されるから、saltを入れた上で
パスワードの認証ができるということなんでしょうか。
(ソースコードを見つけられなくて、予想にはなってしまいますが。。。）

###終わりに

何か間違った情報などあれば、ご指導ご鞭撻のほどお願いします。
（お手柔らかにお願いします）
docker-composeのビルドが通らず焦ってたらしょうもないオチに辿り着いた話

## はじめに

　エラーメッセージでググってこの記事に辿り着いた方は，まず他の記事を先に読んだ方がいいと思います．

## 本題

　いつも通りdocker使って開発環境建てようとしていたとき．

```
ERROR: Couldn't connect to Docker daemon at http+docker://localhost - is it running?

If it's at a non-standard location, specify the URL with the DOCKER_HOST environment variable.
```

というエラーが出た．
別のファイルでは変わらずビルドできてるのに...

## オチ

　docker-compose内でサービス名に大文字を使っていたのが原因だった．

```yaml
services:
  Hoge: ←こういうのがダメ
  ...
```

```shell
Building Hoge
invalid argument "Hoge" for "-t, --tag" flag: invalid reference format: repository name must be lowercase
See 'docker build --help'.
ERROR: Service 'Hoge' failed to build : Build failed
```

## 教訓

　上記のエラーメッセージでググると docker daemon がどうたらみたいな記事がたくさん出てきますが，全然関係ありませんでした．同じエラーでもめちゃくちゃマイナーな出方されると辛いよね...
mysqlコマンドが見つかりませんの解消方法

<h1>結論</h1>
'''mysql-client'''パッケージではなく'''default-mysql-client'''パッケージを使う。
<a href="https://qiita.com/henrich/items/1b7ee2f3a72f8bb29cba">ほぼこの記事通り</a>

<h1>なぜか</h1>
どうも私が使っているDebian 11 bullseyeでは'''mysql-client'''パッケージが存在しなく、現在使っているバージョンだとと使えないらしい（Debian9までは'''mysql-transition'''ソースパッケージが'''mysql-client'''バイナリパッケージを提供していた）なので、このバージョンではないらしい

<h1>対処方法</h1>
'''apt-get install default-mysql-client'''で'''default-mysql-client'''を使うように設定すればよい
PythonでOutlookの予定を登録できるようにした


## 困ってたこと
Microsoft365のTodoというアプリの扱いに慣れないので、
Outlookの予定表にて、タスクを終日の予定として管理しているが、
タスクの登録をGUIで操作するのが面倒だった。

## 解決策
Pythonのプログラムを作り、コマンドプロンプトから登録できるようにした。

## 環境
・Windows11
・Python

## 事前準備 
・Pythonのインストール（当たり前ですが）
・win32comのインストール
　コマンドプロンプトで次のコマンドを実行

```
pip install -U pypiwin32
``` 

## 動かすプログラム

```python:add_task.py
import win32com.client, sys, datetime, re

outlook = win32com.client.Dispatch("Outlook.Application")
item = outlook.CreateItem(1)

if (len(sys.argv) == 3):
    if (re.match('^\d+$', sys.argv[2]) == None):
        print('number format error')
        exit()
    else:
        item.start = datetime.datetime.today() + datetime.timedelta(days=int(sys.argv[2]))
else:
    item.start = datetime.datetime.today()

item.subject = sys.argv[1]
item.allDayEvent = True
item.reminderSet = False
item.Save()
print(item.start.strftime('%Y/%m/%d') + ":" + item.subject + " is added")
```

## コマンドでの使用
・引数1：タスク名
```
C:\Users\hoge>python add_task.py test
2022/02/15:test is added
```

・引数2：登録する日を今日から加算する日数（任意なので引数2がない場合は今日で登録）
```
C:\Users\hoge>python add_task.py test 1
2022/02/16:test is added
```


他により良い手段がありましたら、ぜひご教示ください。
gh コマンドで特定の PR のコミットハッシュをすべて取得する方法

# 取得方法
調べてもすぐに情報が出てこなかったので備忘録として残しておく。

```shell
gh pr view <PR_NUMBER> --json commits --jq .commits[].oid [--repo <USERNANE>/<REPONAME>]
```

# 例
たとえば [Pull Request #17516 · mastodon/mastodon](https://github.com/mastodon/mastodon/pull/17516) のコミットハッシュをすべて取得するコマンドを例に挙げる。

## リモートリポジトリに紐付いたリポジトリがローカルにない場合

```shell
gh pr view 17516 --json commits --jq .commits[].oid --repo mastodon/mastodon
```

```
d631b743c51a15994634314d6302fa33b9b49fef
d388a25dcddf93909d56f66872d48850e0194ca7
e2a97be470f3f4788dc850de4e352e85b5b567a7
```

## リモートリポジトリに紐付いたリポジトリがローカルにあり、そのディレクトリにいる場合
`--repo` を省略できる。

```shell
gh pr view 17516 --json commits --jq .commits[].oid
```

```
d631b743c51a15994634314d6302fa33b9b49fef
d388a25dcddf93909d56f66872d48850e0194ca7
e2a97be470f3f4788dc850de4e352e85b5b567a7
```

# 参考
* [Optionally show commit details as part of the PR details](https://github.com/cli/cli/issues/959#issuecomment-1034071623)
* [gh pr view | GitHub CLI](https://cli.github.com/manual/gh_pr_view)