OmniAICreator/Qiita-1.07M huggingface dataset:
OnsenUIのtabbarで固定ページを差し込む

# 課題
onsenuiにはtabbarでページを簡単にタブ表示できるようになっている。ただ、ページ全体が切り替わるため、切り替わりに関わらず、固定の共通的なページを表示したい場合は一工夫必要となる。
１時間悩んだので、備忘として残す。


# やりたいことイメージ
tab1↔tab2での画面遷移でも共通ページはそのまま表示させておく。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/158138/4038b92d-e3e5-c125-6029-f74f9dddce46.png)



# 実現方法
まず、共通ページをどう出すか？
OnsenUIの一般的なつくりとして、ons-toolbarとons-tabbarの組み合わせがあるので、ons-toolbarに共通ページとするコンテンツを差し込んだ。

```html
<ons-toolbar>
 <!-- 共通ページコンテンツ -->
</ons-toolbar>
```
ただ、このままだと、複数行が必要なコンテンツの場合はtoolbarのスタイルで高さが足りないため、高さ指定をしてやる必要がある。

```html
<ons-toolbar style="height: 40%" >
 <!-- 共通ページコンテンツ -->
</ons-toolbar>
```

次にtabbarだが、ここでtabbarを差し込むとページが崩れてしまう。
そこで以下のように、toolbar側でdisplay:blockを指定してやる。
 OnsenUIでhtml展開されたものを開発者モードで確認した際に、displayがflex設定されており、そこで影響が出ているように見えていたため、displayを強制的に変更させた。

tabbar側は、margin-top指定でどこからtabbarを表示させるかを設定してやる。

```html
<ons-toolbar style="height: 40%;display:block" >
 <!-- 共通ページコンテンツ -->
</ons-toolbar>
<ons-tabbar position="top" style="margin-top:45%">
</ons-tabbar>
```

おわり
テスト28

```vb

'ファイルの存在と開かれているかのチェック
Sub File()

Dim F_Path() As Variant
Dim fso As Variant
Dim ExName As String

Set fso = CreateObject("Scripting.FileSystemObject")

ReDim Preserve F_Path(2)

'拡張子を格納
ExName = fso.GetExtensionName(FilePath)

'各パスを格納
With ThisWorkbook.Sheets("Sheet6")

    F_Path(0) = .Cells(1, 1).Value
    F_Path(1) = .Cells(2, 1).Value
    F_Path(2) = .Cells(3, 1).Value
    
End With


For i = LBound(F_Path) To UBound(F_Path)

ExName = fso.GetExtensionName(F_Path(i))

    If ExName <> "" Then
        'パスがファイル(拡張子がある場合)の時はファイルチェック
        Call File_Check(F_Path(i))
        
    Else
        'パスがフォルダ(拡張子がない場合)の時はファイルチェック
        Call Folder_Check(F_Path(i))
        
    End If
    
    ExName = ""
    
Next i


MsgBox "問題ありません", vbCritical



End Sub

Sub File_Check(ByVal strPath As String)

'ファイルチェック
Dim fso As Variant
Dim s As String

Set fso = CreateObject("Scripting.FileSystemObject")

' ファイル名と拡張子(パス上にファイルがなくてもファイル名が取得できる)
s = fso.GetFileName(strPath)

'ファイルの存在チェック
If Dir(strPath) = "" Then
    '問題なければ何もしない

    MsgBox s & "が存在しません。もう一度確認してください。", vbCritical
    End
    
End If

'-------------------------------------------------------------
'ファイルが開かれているかのチェック(ファイルの場合に処理を実行する)
On Error Resume Next

Open strPath For Append As #1
Close #1

If Err.Number > 0 Then

    MsgBox s & "がすでに開かれています。もう一度確認してください。", vbCritical
    End
    
Else
    '問題がなければ何もしない
    On Error GoTo 0

End If

End Sub

Sub Folder_Check(ByVal strPath As String)

'フォルダチェック

Set fso = CreateObject("Scripting.FileSystemObject")

' ファイル名と拡張子(パス上にファイルがなくてもファイル名が取得できる)
s = fso.GetBaseName(strPath)


If Dir(strPath, vbDirectory) = "" Then
    '問題なければ何もしない

    MsgBox s & "フォルダが存在しません。もう一度確認してください。", vbCritical
    End
    
End If
    
End Sub
コーディング開始。headの中身大すぎ問題【プログラミング日記~ポートフォリオ③~】#4

今回からついにコーディングしていきますすす‼
まずはheadタグから埋めていきます‼
今後もいろんなサイトで使うと思うのでコピーしといたら便利だと思います!!!
#実際のコード

```html:index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
     <!-- 古いバージョンのIE向けの最適化 -->
    <meta name="description" content="">
    <!-- 古いバージョンのIE向けの最適化 -->
    <meta http-equiv="X-UA-compatible" content="IE=edge"> 
    <!-- スマホに対応させる -->
    <meta name="viewpoint" content="width=device-width, initial-scale=1">
    <!-- SNSシェア時のurl,title,description,imageの指定 -->
    <meta property='og:type' content='website'>
    <meta property="og:url" content="">
    <meta property="og:title" content="">
    <meta property="og:description" content="">
    <meta property="og:image" content="">
    <!-- ブラウザのタブの表示 -->
    <title></title>
　　<!-- css -->
    <link rel="stylesheet" href="/css/stylesheet.css">
    <!-- フォントオーサムのインスト―ル -->
    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css">
  </head>
  <body>  </body>
</html>
    
```

#おわりに
こんなにコード書いたのにheadタグなのでブラウザにはまだ何も表示されていません!!!
次回からbodyの中を埋めていくのでどんなサイトが完成するか楽しみです:ghost:
slack→AWS chatbotでlambda実行しようとしたらRegionDisabledExceptionに悩まされた話

# 実現したかった方式
slack→AWS chatbot→lambda関数の呼び出し

こちらについては多くの方が既に記事にされていますし、下記ドキュメントを参考いただければ簡単にセットアップできます。
https://docs.aws.amazon.com/ja_jp/chatbot/latest/adminguide/getting-started.html

# 実際にコマンド打ってみる
lambdaのlist-functionsを打って、権限周りの疎通を実施してみたところ、下記エラーメッセージが…
![エラーメッセージ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640480/34325a55-e3f0-a64a-ed9f-a8ab0b6cbf19.png)

Security Token Serviceを必要なリージョンで有効化しろとのこと。
https://docs.aws.amazon.com/ja_jp/chatbot/latest/adminguide/security-iam.html#security-iam-other-policies

IAMのSTS設定を確認してみると、画像の状態でした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640480/a6b44759-1b4d-d049-6735-b4d68aedf60e.png)

うーん。slackだし、とりあえず米国のエンドポイント有効化してみよー。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640480/2856c1d1-b8e1-565d-96bd-c40951c4137b.png)

再度コマンド実行！
![成功.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640480/176361f5-0709-d2e9-eaa2-04f9c755af3a.png)

なんかうまくいった…！


# 結論
正確な情報がまだ分かってませんが、Slack→chatbotを連携させる際にはSlack側のリージョンのSTSが有効化されていないといけない模様です。
デフォルトで有効化されていることも多いようですが、組織によって意図的に無効化されている可能性があるので、同様のエラー発生時にはこちらを試してみていただくのも良いかもしれません。

ちなみに、オハイオ（us-east-2）を有効化しておけばコマンド実行できることを確認できました！
IBM Cloud API Gateway経由で既存のAPIを呼び出す

# はじめに
[前回](https://qiita.com/rinaxsumomo/items/350ca64160ac41a8f77f)の記事では、IBM Cloud Functionsにデプロイしたサービスを、API Gateway経由で呼び出してみました。
今回は外部で提供されているAPIをAPI Gateway経由で呼び出してみます。

# 前提
[前回の手順1](https://qiita.com/rinaxsumomo/items/350ca64160ac41a8f77f#%E6%89%8B%E9%A0%86)に記載されているように、API Gateway Serviceはデプロイ済みとします。

# 手順
1. Create an API Proxyをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129662/ac70797c-5726-0cda-208b-542ddc1d6eca.png)
2. API名、パス、呼び出し先外部APIを指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129662/4a481216-8260-a04c-8369-51ef1fd151b6.png)
3. APIキーで保護します。ここではデフォルトのX-IBM-Client-IDからX-API-Keyに変更します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129662/343cbc4a-b9b4-e956-6715-e188c4348663.png)
4. 流量制御を設定し、OAuth 2.0は使わず、CORSはOnにしておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129662/70fa5dae-b4eb-5970-e3b9-5c95766ade63.png)
5. 作成済みのAPI Gatewayとリージョンを選択してCreateをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129662/de1b8858-1f91-ad78-482d-f5a598caf526.png)
6. APIが作成されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129662/bfd961a3-06d4-baf6-ef5c-770b971fa3c5.png)
7. APIキーを作成します。Manage sharing and keysからCreate API Keyをクリックして、APIキーを生成します。自動生成でもいいですし、好きな文字列をいれるCustom keyも可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129662/c26c5569-0568-aeb4-5c68-06db0620f0cb.png)
8. APIキーができたことを確認します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129662/c5aebd4b-b49e-5d8c-818f-048634c526ab.png)
9. Review and TestからAPIドキュメントを確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129662/138b5355-2827-1725-f435-35d4250c697d.png)
10. 上記から試し打ちも可能ですが、今回は直接Postmanから試してみます。APIドキュメントで確認したエンドポイントをURLに入れ、メソッドはGET、ヘッダーにX-API-Keyと値を指定して呼ぶと、IBM Cloud API Gateway Service経由でビットコイン関連情報のレスポンスが取得できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129662/108fe0d3-589d-0c42-57d9-055c3859a3f5.png)
11. リクエスト数が流量制御の上限を超えると429エラーを返します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129662/d0acb8f3-fde8-90a2-e214-aacc1f234d01.png)
12. APIキー外すと401エラーを返します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129662/64464eae-7f7b-d221-d1f4-998927973ead.png)


# まとめ
今回はIBM Cloud外のサービスをIBM Cloud API Gateway Serviceを経由して呼び出してみました。本来でしたら、ここで呼び出す外部サービスは自社のAPI対応したサービスのエンドポイントなどになりますが、ここでは利便性のため外部サービスはAPIキーがなくても呼び出せるAPIを使って、IBM Cloud API Gateway Serviceが簡単に使えることを試してみました。

# 参考
- APIキーがなくても呼べるAPI一覧
    - https://mixedanalytics.com/blog/list-actually-free-open-no-auth-needed-apis/
- IBM Cloud API Management
    - https://cloud.ibm.com/apis/overview
    - https://cloud.ibm.com/docs/api-gateway?topic=api-gateway-whatis_apigw
UbuntuでChromeをダークモードにする方法

## 環境
- Ubuntu 20.04.2 (GNOME 3.36.8)
- Google Chrome 88.0.4324.96

## TL;DR
`/opt/google/chrome/google-chrome`の最終行を下記のように変更する。

```bash
exec -a "$0" "$HERE/chrome" "--enable-features=WebUIDarkMode" "--force-dark-mode" "$@"
```

## 問題
UbuntuでGoogle Chromeを開くとコンテキストメニューやChrome関連のページがライトテーマになる（ダークテーマに切り替えられない）。

## 解決策
起動する際、引数に`--enable-features=WebUIDarkMode`と`--force-dark-mode`を付ければ良い。

ただ、これだけでは

- 毎回この引数をつけて起動するっていうのは面倒。
- GNOMEアプリとして起動する時に適用できない。

そのため、`/opt/google/chrome/google-chrome`自体をいじる。

`/opt/google/chrome/google-chrome`の一番下のexec文の引数に`--enable-features=WebUIDarkMode`と`--force-dark-mode`を追加する。
私は`"$@"`の前に追加した。

```bash
# gEdit
sudo gedit /opt/google/chrome/google-chrome
# Vim
sudo vim /opt/google/chrome/google-chrome
```

```bash
#　 〜〜省略〜〜

# Note: exec -a below is a bashism.
exec -a "$0" "$HERE/chrome" "--enable-features=WebUIDarkMode" "--force-dark-mode" "$@"
```

タブの色などアプリテーマ自体がライトテーマのままな場合は「新しいタブ」の右下にあるカスタマイズの色とテーマから黒色を選択すればダークテーマになります。

## 引数の解説
`--enable-features=WebUIDarkMode`では設定画面や履歴画面などChrome関連のページをダークモードにします。
`--force-dark-mode`ではコンテキストメニューなどをダークモードにします。

## 非推奨の解決策
元々は`/usr/share/applications/google-chrome.desktop`を弄って直していたのですが、この場合Chromeを開く前にChromeアプリ (YouTube Musicなど)を開いた時にライトテーマで起動してしまう。
これも直せはするのだが、工程が多いため面倒かつ非効率的。

## 参考にしたサイト
[Enable dark mode on chrome's internal pages - Ask Ubuntu](https://askubuntu.com/questions/1159741/enable-dark-mode-on-chromes-internal-pages)
【初心者向け】PHP フォームの入力値をGoogleスプレッドシートに自動で書き込むざっくり手順と私がつまづいたこと（Google Sheet API & Google APIs Client Library for PHP）

#経緯
サイトで使用しているPHPフォームからの送信内容をgoogleスプレッドシートに反映したいという依頼があった。
初めての作業だったので色々調べまくって時間がかかったため備忘録。
私のような初心者向けの内容です。

#かかった時間
3〜4時間ぐらい
慣れれば1時間ぐらいでできそう

#参考にしたページなど
- [問い合わせフォームの入力値をGoogleスプレッドシートに自動で書き込む](https://aw1.jp/web/%E5%95%8F%E3%81%84%E5%90%88%E3%82%8F%E3%81%9B%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0%E3%81%AE%E5%85%A5%E5%8A%9B%E5%80%A4%E3%82%92google%E3%82%B9%E3%83%97%E3%83%AC%E3%83%83%E3%83%89%E3%82%B7%E3%83%BC/)
- [実装しているphpメールフォーム](https://gray-code.com/php/make-the-form-introduction/)


#非常にざっくりとした手順
1. Googleスプレッドシートをつくる
2. [Google API](https://console.cloud.google.com/apis/library?hl=ja)でGoogle Sheet APIを有効化（認証情報とかも作る）（参考サイト見てね）
3. Googleスプレッドシートの「編集者」に[2]で作ったメールアドレス追加
4. Google APIs Client Library for PHPをサイトにインストール（私はFTPでアップしました）
5. [1]でDLした鍵jsonを[2]でインストールしたディレクトリにアップ（このとき「credentials.json」と改名
6. PHPフォームの送信後アクションの{}内に下記追記

```php:送信後アクション
if (!empty($clean['btn_submit'])) {　この中に下記を追記 }
```

```php:追記するPHP（★のところは直してね)
//googleスプレッドシート連携
    require_once __DIR__ . '/★ディレクトリ相対パス/vendor/autoload.php';
    define('APPLICATION_NAME', 'test');
    define('CLIENT_SECRET_PATH', './★ディレクトリ相対パス/credentials.json');
    // スコープの設定
    define('SCOPES', implode(
        ' ',
        array(
            Google_Service_Sheets::SPREADSHEETS
        )
    ));
    // アカウント認証情報インスタンスを作成
    $client = new Google_Client();
    $client->setScopes(SCOPES);
    $client->setAuthConfig(CLIENT_SECRET_PATH);
    /// シートのインスタンスを生成
    $service = new Google_Service_Sheets($client);
    try {
        $spreadsheetId = '★スプレッドシートID入れてね（英数字混じってるめっちゃ長いやつ）';
        $range = '★シート名入れてね';
        $values = array(
            array(
//連携したスプレッドシートの最終行に「A列（一番左）」から順に追記されるよ
                date('Y-m-d'),//★日付
                $clean['XXXX'],//★フォームの入力値の取得（複数ある場合は増やしてね）
            ),
        );

        $appendBody = new Google_Service_Sheets_ValueRange([
            'values' => $values
        ]);

        $params = [
            'valueInputOption' => 'USER_ENTERED'
        ];
        $result = $service->spreadsheets_values->append($spreadsheetId, $range, $appendBody, $params);
        echo $result->getUpdates()->getUpdatedCells();
    } catch (Google_Exception $e) {
        $errors = json_decode($e->getMessage(), true);
        $err = "code : " . $errors["error"]["code"] . "\r\n";
        $err .= "message : " . $errors["error"]["message"];
        echo "Google_Exception" . $err;
    }
```

#私がつまずいたポイントと解決策
参考サイト通りにやってうまいことできないときは下記を確認すると幸せになれるかも知れません。

##FTP経由で「Google APIs Client Library for PHP」をアップしたい
GithubのファイルだとどれをUPすればいいのか私はよくわからなかったので、下記からDLしてサーバーにUPしました。※サーバーのPHPバージョンを確認してください。
https://github.com/googleapis/google-api-php-client/releases

##google 400 redirect_uri_mismatch... みたいなエラー文が出る
スプレッドシートは「.xlsx」形式になっていませんか？
.xlsxの場合連携がうまくいきません。
googleスプレッドシート形式に変換してください。

##スプレッドシートが更新されない
仮にGoogleスプレッドシートのURLが下記だとしたら
https://docs.google.com/spreadsheets/d/XXXXXXXXXXXX-XXXXXXXX-XX/edit#gid=00000000
$spreadsheetId に入力するのはXXXXXXXXXXXX-XXXXXXXX-XXの方です。
gulp エラー：[object Object] is not a PostCSS plugin

## エラーが発生した状況

npm で autoprefixer, gulp-sourcemaps, gulp-postcss をインストールした状態で、npm 公式サイトの [autoprefixer のサンプルコード](https://github.com/postcss/autoprefixer)を実行

```gulpfile.babel.js
gulp.task('autoprefixer', () => {
  const autoprefixer = require('autoprefixer')
  const sourcemaps = require('gulp-sourcemaps')
  const postcss = require('gulp-postcss')

  return gulp.src('./src/*.css')
    .pipe(sourcemaps.init())
    .pipe(postcss([ autoprefixer() ]))
    .pipe(sourcemaps.write('.'))
    .pipe(gulp.dest('./dest'))
})
```

## 解決方法

postcss をインストール
`npm i -d postcss`

## 参考記事

* [gulp - PostCSS error: [object Object] is not a PostCSS plugin - Stack Overflow](https://stackoverflow.com/questions/40090111/postcss-error-object-object-is-not-a-postcss-plugin)
SentdexさんのPython機械学習の説明ビデオがすごい

これ
https://nnfs.io/neural_network_animations

**Sentdex**さん(Harrison Kinsley)とは、Python機械学習のテック系ユーチューバーです。テック系、それも機械学習系なのに、100万人ものフォロワーもいます。

軽快な語り口調で、お茶目なとこもあり、自然な英語を話しますのでリスリングの勉強にもなります。

機械学習をTensorFlowなどのライブラリを使用せずに、[わかりやすく説明しています。](https://www.youtube.com/watch?v=Wo5dMEP_BbI&list=PLQVvvaa0QuDcjD5BAw2DxE6OF2tius3V3)

書籍も販売しています。

チュートリアルビデオでは、数式をアニメーションでわかりやすく解説しています。これは、[3b1bmanim](https://github.com/3b1b/manim)というライブラリをベースに作成しているようです。
Git/Github復習

ポートフォリオ作成に向けて、1月中に基礎学習を終わらせます。
HTML/CSS、JavaScript、Ruby、RDB/SQLの復習を終わらせたので、
次にGit/Githubの復習をUdemyの動画「<a href="https://www.udemy.com/course/intro_git/">Git：はじめてのGitとGitHub</a>」で行っていきます。
なお、記述する内容は自分が忘れがちな所、苦手な所です。
HTML/CSS編、JavaScript編、Ruby編、RDB/SQL編同様、
自分用の備忘録的に投稿していくので(箇条書きで)、
読みづらいor間違えていることを書いている可能性もあるので、悪しからず。
(できるだけ他の方が見てもためになれば良いなとは思って投稿しますが・・・)
箇条書きで書いたことに関して、新たな発見、学び、気づき等あれば、
それぞれ個々に詳細を記述していこうと思います。


<h1>Gitとは</h1>
バージョン管理システムである。「どのファイルの何を」、「誰が」、「いつ」、「何のために」変更したのかを
記録として残すことができる。

<h1>Gitの仕組み</h1>

変更履歴を順々に記録する。
記録する際はメッセージを付ける。

<h4>開発の流れ(個人)</h4>

個人ファイル(ファイル変更)→個人リポジトリ→共有リポジトリ

リポジトリ・・・ 変更履歴を記録する場所
commit・・・ 個人リポジトリに変更履歴を記録すること。(個人ファイル→個人リポジトリ)
push・・・ 共有リポジトリに変更を共有すること。(個人リポジトリ→共有リポジトリ)
pull・・・ 共有リポジトリの情報を同期すること (共有リポジトリ→個人リポジトリ)

<h1>Githubとは</h1>
Gitリポジトリ(コード)のホスティングサービスである。
代表的なものは、GithubやBitbucketなどがある。
プルリクエストによるコラボレーションができ、
世界中のチームがGithub上で開発を行っている。

<h1>基本的なワークフロー</h1>

ローカルリポジトリの新規作成→個人ファイル(ファイル変更)→ステージングエリア→ローカルリポジトリ→リモートリポジトリ

ステージングエリア・・・ ファイルの控え室のようなもの

①ローカルリポジトリの新規作成 
git init でリポジトリを新規作成する
②ファイルの変更をステージングエリアへ追加する(個人ファイル→ステージングエリア)
git add
③ローカルリポジトリにコミットする(ステージングエリア→ローカルリポジトリ)
git commit
④リモートリポジトリにプッシュする(ローカルリポジトリ→リモートリポジトリ)
git push

<h1>git commit</h1>

git addでステージングエリアに追加したら、git commitと命令する。
commitメッセージを入力する画面が現れる(デフォルトではVimというエディタが出現)

<h4>Vimの操作</h4>

半角英数字に切り替える→iを入力(書き込みができる)→コメントを残す→escを押す→
:wqを入力後、enterキーを押す

<h4>Github上にリポジトリ新規作成</h4>

Githubにpushするために、Github上でリポジトリを新規作成する(New repository)

<h1>変更をコミットする流れ</h1>

①ステージングエリアに変更を追加する
git add [ファイル名]
git add . ←変更したファイルが全て追加される
②リポジトリに変更を記録する
*一つの作業ごとに1コミット
git commit 
③分かりやすいコミットメッセージを書く
1行目: 変更内容の要約
2行目: 空行
3行目: 変更した理由
④escを押して、:wq、enterキー

<h4>git log</h4>
git logでcommitできたかどうか確認できる

git log --oneline #1行で表示する
git log -p ファイル名 #ファイルの差分を表示する
git log -n 表示したいログ数 #表示するログ数を指定する

<h1>色々な変更をコミットできる</h1>
ファイルの新規作成、ファイルの削除、複数ファイルの変更など

<h4>削除したファイルをステージングエリアに追加する</h4>
git rm 削除したファイル で削除したファイルをステージングエリアに追加できる

<h4>現在の状況を確認する</h4>
git statusコマンドで現在の状況を確認できる

<h1>変更差分を確認する</h1>
git diffコマンドで変更差分を確認することができる。
git diff HEAD  #最新コミットとの差分を表示できる

<h1>Githubにプッシュする</h1>

①リモートリポジトリに登録する
git remote addコマンドでローカルリポジトリをリモートリポジトリに登録できる
(例)git remote add origin https://github.com.....
②リモートリポジトリへ送信する
masterブランチへの送信
→git push origin master
master以外のブランチへの送信(例:featureブランチへの送信)
→git push origin feature

<h1>バージョン管理からファイルを外す</h1>

.gitignoreファイルに指定する
→ファイルをGitの管理から外すことができる。
(自動生成されるファイルやパスワードが記載されているファイルなどを外す)

<h4>.gitignoreファイルの書き方</h4>
・ #から始まる行はコメント
・ 指定したファイルを除外できる
・ ルートディレクトリを指定できる
・ ディレクトリ以下を除外できる

<h1>コミットしてしまったファイルを管理から外す</h1>

<h4>ファイルごとGitの管理から削除する</h4>
git rm [ファイル名] #ファイルも一緒に削除される
git rm -r [ディレクトリ名] #ディレクトリも一緒に削除される

<h4>ファイル本体は残す場合</h4>
git rm --cached [ファイル名]
*commitされないように、.gitignoreに追記するのを忘れない

<h5>Git/Github復習以上</h5>
In-App Review API 試してみる

## In-App Review APIとは
レビュー処理をアプリ内で完結させられるAPI。このAPIを利用することでストアに遷移せずともレビューを行うことができるようになる

## 実装
### ライブラリの追加

```(app)builld.gradle
dependencies {
  implementation "com.google.android.play:review-ktx:2.0.0"
}
```

### API呼び出し
```kotlin
    ...
    val manager = ReviewManagerFactory.create(requireContext())
    val request = manager.requestReviewFlow()
    request.addOnCompleteListener { task: Task<ReviewInfo?> ->
        when {
            task.isSuccessful -> {
                val reviewInfo = task.result
                val flow = manager.launchReviewFlow(requireActivity(), reviewInfo)
                flow.addOnCompleteListener { task1: Task<Void?>? ->
                    // The flow has finished.  
                }
            }
            else -> {
                // error or something
            }
        }
    }
    ...
```

実装としてはこれだけだが、ローカルでビルドし実機インストールして動作させても何も起こらない

## 動作確認方法
Developer Console で `内部テスト` もしくは [`Internal app sharing`](https://play.google.com/console/internal-app-sharing) にアプリをアップロードし、テスターを追加して検証する必要がある。バージョンコードを上げてアップロードする必要があり若干手間が掛かる
また、レビュー済みのテスターで動作確認するとAPIを呼び出しても何も起こらないので注意が必要である

## 注意事項
### アプリ内レビューをリクエストするタイミング
公式: https://developer.android.com/guide/playcore/in-app-review?hl=ja#when-to-request
> アプリ内レビューをリクエストするタイミング
> ユーザーにアプリ内レビューをリクエストするタイミングを決める際は、次のガイドラインに従ってください。
>
> ...
>
>評価ボタンや評価カードを表示する前または表示中に質問をしない（「アプリを気に入りましたか？」といったユーザーの意見に関する質問や、「このアプリを 5 つ星と評価していただけますか？」といった予断を与える質問）。

とあり、事前に「星５つレビューをお願いします」などのメッセージを表示するのは推奨されないもよう

### 割り当て
公式: https://developer.android.com/guide/playcore/in-app-review?hl=ja#quotas
> 割り当ては変更される可能性があります。そのため、独自のロジックを適用し、可能な限り最適なタイミングをターゲットとして審査をリクエストすることが重要です。たとえば、API をトリガーするよう「行動を促す」オプション（ボタンなど）を設けないでください。ユーザーの割り当てがすでになくなっていて、フローが表示されず、ユーザー エクスペリエンスが破綻する可能性があるためです。このユースケースでは、代わりにユーザーを Play ストアにリダイレクトします。

とあり、「レビューする」ボタンを設置してそこから In-App Review API を呼び出すのも推奨されないもよう

## まとめ
In-App Review API を実装し動作確認まで試してみた
動作確認を行うのに Developer Console にアプリをアップロードしないといけないのは検証がしにくいと思った
事前にレビュー済みかどうかをチェックする方法が現時点でなく、レビュー済みユーザーが「レビューする」ボタンをタップすると何も起こらずバグっぽい挙動になってしまうのはいまいちだと感じた
API呼び出しで表示されるレビューシートはデザインのカスタマイズはできず、選択された星の数によって条件分岐させることもできない
事前に何らかのメッセージを表示してからレビューを促すような使い方も推奨されないとのことで、何らかのタイミングでいきなり表示するような使い方を想定しているようで使いづらさを感じた
AWS CLIでGlueJobのruns-statusとcloudwatchのログを良い感じでゲットするシェルを作ってみた

####はじめに
どうも、肉と糖質が大好きなおじさんです。
仕事でAWSを使ってますが、マネコンからログを取得するのに
限界を感じたので良い感じのシェルを作りました。
しっかり解説入れようと下書きしていたけど
うっかり消しちゃったのでサクッとシェルだけ投稿します。
あーうっかりうっかり（泣）

####・実行ID、ゲットだぜ！
JOBIDを指定して、良い感じの実行状態を取得するシェルです。
JSONを加工してCSVにしてます。
時間もUTCからJSTに変換します。

引数には、JOBIDを指定してください。

```bash:statusget.sh
#!/bin/bash
#--- 引数チェック
if [ $# -gt 1 ]; then
	echo "エラー:引数が多すぎます。"
	exit 1;
fi

#--- tittle print
echo "AWS GlueJobs Run Status Check"
echo ""

#--- 引数がなしなら入力プロンプト
if [ $# -eq 1 ]; then
	INPUT_JOBID=$1;
else
	echo "取得するJOBIDを入力してください。"
	read -p ":" INPUT_JOBID
fi

if test -z $INPUT_JOBID; then
	echo "エラー：JOBIDを入力してください。"
	exit 1;
fi

filename=$INPUT_JOBID"_result.csv"

echo "JobName,JobId,Status,StartedOn,CompetedOn,ExecutionTime" > $filename

aws glue get-job-runs --job-name $INPUT_JOBID | jq -r '.JobRuns[] | [.JobName, .Id, .JobRunState, (.StartedOn |tonumber|.+32400|todate), (.CompletedOn |tonumber|.+32400|todate), (.ExecutionTime|tonumber)]| @csv' >> $filename

echo "Finish. output --> " $filename
exit 0;
```

####・ログストリーム、ゲットだぜ！
「行けぇ、ピ※ち※※！！aws cli get-log-events!!
「ぴかぁ…。

引数には上記シェルで取得した、実行IDを指定してください。

```bash:logget.sh
#!/bin/bash

#---- ロググループは環境に応じて変更してください！！
LOG_GROUP=/aws-glue/jobs/＃＃＃＃＃＃＃＃＃

#--- 引数チェック
if [ $# -gt 1 ]; then
	echo "エラー:引数が多すぎます。"
	exit 1;
fi

#--- tittle print
echo "AWS GlueJobs Log Getter Ver1.0"
echo ""

#--- 引数がなしなら入力プロンプト
if [ $# -eq 1 ]; then
	INPUT_RUNID=$1;
else
	echo "取得する実行IDを入力してください。"
	read -p ":" INPUT_RUNID
fi

if test -z $INPUT_RUNID; then
	echo "エラー：実行IDを入力してください。"
	exit 1;
fi

filename=`date "+%Y%m%d_%H%M%S_"`$INPUT_RUNID".log"

aws logs get-log-events --log-group-name $LOG_GROUP --log-stream-name $INPUT_RUNID --query "events[].[message]" --output text > $filename

echo "Finish. output --> " $filename
exit 0;
```
出力されるファイル名は、タイムスタンプ＋実行ID.log です。

####・おしまいに
シェルの改変などは、ご自由にどうぞ。
AWSのマネコンがもっと使い易くてレスポンスも速くなったら
こんなツールは必要ないんですが、まぁ当分先かなぁ…。

「チラ裏」
M1のMBA最近、買いました。
スッゲー速くて良い感じ。
サイコーです。
あははははは！
ではまた。
ゲーミングノートでLifespan Age Transformation Synthesisを動作させてみた

#  ゲーミングノートでLifespan Age Transformation Synthesisを動作させたときのメモ

先日、ITmediaのページ [赤ちゃんから老人の顔まで、1枚の顔写真で合成　深層学習で加齢変化を予測](https://www.itmedia.co.jp/news/articles/2101/28/news072.html)　を読んで、おっ面白そうだな自宅PCで動作するかな？と思いつき試してみたときのメモになります。
なお、この合成予測技術の内容はわたしさっぱり分かりません。（笑）

本家のページ[Lifespan Age Transformation Synthesis](http://grail.cs.washington.edu/projects/lifespan_age_transformation_synthesis/) 中のCode Lifespan Age Transformation Synthesis (Github)という[リンク先](https://github.com/royorel/Lifespan_Age_Transformation_Synthesis)を見てみます。まず「You must have a GPU with CUDA support in order to run the code.」と書かれていることを確認しました。

## 用意したもの

* NVIDIAのグラフィックチップが載ったPC（今回はHP OMENというRTX2070が搭載されたWindowsゲーミングノートを使用)
* [CUDA Toolkit 11.2](https://developer.nvidia.com/cuda-downloads)
* [Anaconda](https://www.anaconda.com/products/individual#Downloads)
* [Visual Studio 2019 Community](https://visualstudio.microsoft.com/ja/downloads/)版

---

## 環境の準備

### 1.上記のソフトウェアをインストールします。  
VS2019については「C++によるデスクトップ開発」を選択しておきます。これdlibのためだけです・・・

### 2.Anacondaでそれ用の環境を一つ作成してその環境のコマンドプロンプト(or PS)を開いておきます。

---

## 必要なもののインストール

[本家Githubページ](https://github.com/royorel/Lifespan_Age_Transformation_Synthesis)のPre-Requisits（前提条件）というところに必要なものが記載されていますので、これらをインストールしていきます。
### 1.本体  
GithubからPCの適当なところにcloneします。コマンドでもDownload Zipでもお好きな方法で。

### 2.Pytorch  
[ダウンロードページ](https://pytorch.org/get-started/locally/)で、Stable,Windows,Conda,Python,11.0 を選択してRun this Command欄に出ているコマンド`conda install pytorch torchvision torchaudio cudatoolkit=11.0 -c pytorch`を、先に作ったAnaconda環境のコマンドプロンプトに貼り付けてインストールします。バージョンが11.0とあって先にCUDA ToolKitダウンロードで指定していた11.2ではありませんが動作はしました。

### 3.その他　　
Pre-Requisits（前提条件）に記載の各パッケージをconda install何々でインストールしていきます。condaでできないものは仕方ないのでpip(pip3だったかも)でインストールしていきます。ここで、dlibがインストールできない場合は先にpip install cmakeだったかVS2019インストールで出来る「x64 Native Tools Command Prompt for VS 2019（コンパイラへのpathが通っている）」中からactivate 何々と環境切り替えたあとだったかで導入できたはず（うろ覚え）。  

## 実行
Quick Demo - Running locally欄以下に記載のあるように、本体ディレクトリの下にrun_scriptsというのがあるので、そこの中のスクリプトを適当にパラメータを変更し、また変化させたい顔写真画像を指定して実行します。
例えばin_the_wild.batだと顔変化が動画ファイルで\test_latest\traversalに出力されます。確かに顔の特徴を保ったまま年代変化していって面白いです。

顔写真画像についての注意事項はUsing your own images欄に書かれています。カラー画像、正面で等々。試しに織田信長公の有名な絵の顔部分を入力してみましたがこれは微妙だった・・ｗ

データセットはcloneしたdatasetディレクトリ中には少ししかなく出力結果もいまいち以下なので、それなりのを入手するのにはTraining/Testing on FFHQ-Aging欄で書かれています。が、とりあえず動かすのであれば「Download pretrained models (Optional)」でダウンロードされる学習済みモデルのファイルを使ったほうが早いのではと思います。顔写真画像ダウンロード、途中で何度もダウンロードが中断してしまいましたし。

あとQuick Demo欄の最後に以下の文があります。  
If you get a CUDA out of memory error, slightly increase the --interp_step parameter until it fits your GPU. This parameter controls the number of interpolated frames between every 2 anchor classes. Increasing it will reduce the length of the output video.
動作させようとしたRTX2070では専用メモリ8GBです。in_the_wild.bat中に予め書かれていた--interp_step値は0.05だったのですがこれでは実行に失敗し、0.08ぐらいだと動作しました。

以上になります。
いろいろ適当に作った環境ながら何とか動かせてよかったです。ざっと出力出来て満足できた感もありますが（笑）
STM32G031J6M6のArduinoでOLED,OLED096UNO-AでABC defgを表示

STM32G031J6M6のArduinoでOLED,OLED096UNO-AでABC defgを表示

X何らかの方法でArduinoを起動出来る様にしておく。

1.u8g2ライブラリーをインストール

2.ソースの例から16x16Fontを選択

3.まるまるを選択

4.コンパイル

5.ABC defgが表示される

6.おわり

おまけ
ここまでわかるまでに1カ月以上掛った。
mbedの方が環境構築が簡単だつた。
わからないところは、自力で解決してね!!
約24kバイトぐらい使用する

![l_ay_1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/83732d5e-c771-229e-e28c-16ccea286aa8.jpeg)

![l_ay_2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/81530d19-abdd-5db9-ee98-af1c1be15d89.jpeg)

![l_ay_3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/9dae4813-5b16-2c47-3790-e8f1565bbcbd.jpeg)

![l_ay_4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/ae303167-d778-56a6-ca40-c9868fe7c03c.jpeg)

![stm32_oled_d_1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/4cb4ccc6-7e67-c239-f5d4-e01672d40fdb.jpeg)
OpenCVを使って画像の輪郭を抽出したい。


#画像の輪郭を抽出したい。
```ruby:qiita.rb
import cv2
from PIL import Image
import matplotlib.pyplot as plt
import numpy as np
#画像を読み込み
im = cv2.imread('MRJ.jpg')
im_gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
retval, im_bw = cv2.threshold(im_gray, 100, 255, cv2.THRESH_BINARY)

# 輪郭の検出
contours, hierarchy = cv2.findContours(im_bw, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)

# 全ての輪郭を書き込んで出力
im_con = im.copy()
cv2.drawContours(im_con, contours, -1, (255,0,255), 2)
cv2.imwrite('result2.jpg', im_con)

im_result = Image.open("result2.jpg")

fig=plt.figure(figsize=(20,10))
#画像をarrayに変換
im_list = np.asarray(im_result)
#貼り付け
plt.imshow(im_list)
#表示
plt.show()

#im_result.show()
```
#画像に輪郭線が書き込まれた画像
![result2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1069967/e23e8814-d890-44e1-2f9b-6183d74a6716.jpeg)

#画像を2値化したい。
```ruby:qiita.rb
import cv2
from PIL import Image
import matplotlib.pyplot as plt
import numpy as np

im = cv2.imread('foot.jpg')
im_gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
retval, im_bw = cv2.threshold(im_gray, 70, 255, cv2.THRESH_BINARY)
cv2.imwrite('foot_test.jpg', im_bw)
imshow(im_bw)
```
![foot_test.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1069967/76855eb3-b203-09ce-60de-c470a4371e24.jpeg)
【Swift/SwiftUIとFirebase】no such module ‘Firebase’/Could not build Objective-C module ‘Firebase’になるときの対応(M1チップ?)

## 本日のテーマ
SwiftUIとFirebaseで実装していて、困った対応です！
(最新版はAppDelegate.swiftがないんですね。。。)

### 開発環境
Xcode 14.4
SwiftUI
M1チップ


## 解決方法

podfileの最後にこちらを追加するだけです！

```
post_install do |installer|
     installer.pods_project.targets.each do |target|
         target.build_configurations.each do |config|
             config.build_settings['EXCLUDED_ARCHS[sdk=iphonesimulator*]'] = 'arm64'
             config.build_settings['EXCLUDED_ARCHS[sdk=watchsimulator*]'] = 'arm64'
             config.build_settings['EXCLUDED_ARCHS[sdk=appletvsimulator*]'] = 'arm64'
             config.build_settings.delete 'IPHONEOS_DEPLOYMENT_TARGET'
             config.build_settings['ENABLE_BITCODE'] = 'NO'
         end
     end
 end
```

arm64というCPUアーキテクチャにするとうまくいきそうです〜〜
本日探していて、数時間かかったので参考程度にまとめておきます。
Arduino鉄道模型コントローラ（ワンハンドル型）

![DSC_0257.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/219051/c05a3561-7691-8715-42d6-0e6d072357c6.jpeg)

##概要
 - Arduinoで鉄道模型コントローラを作成しました。ワンハンドルで操作します。
 - モジュールの組み合わせで作成できるので、回路は簡単です（多少はんだ付けあり）。

##機能
 - ワンハンドルで進行方向・速度を操作します（ハンドルを押すと非常停止）。
 - 液晶画面に現在の進行方向と速度を表示します。
 - 速度は8段階（ノッチ）に調整可能です。
 - ゆっくりと加減速します。
 - 停止時も車両の室内灯が点灯します。

##使用部品
 - Arduino ProMini(5v)
 - 1602 LCDディスプレイモジュール
 - L298N デュアルHブリッジ DCステップ モーター 
 - ロータリーエンコーダ（押しボタンつき）
 - つまみ
 - DCジャック
 - 100均はがきケース
 - 12V ACアダプタ（1A）

##回路図
![N_controller_ブレッドボード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/219051/ffef1140-4314-7ac3-af69-fa5e686982b8.png)

- L298Nには12VのACアダプタを接続（ArduinoはL298Nから給電）

|部品名 |部品ピン  |Arduino|
|---|---|---|
|ロータリーエンコーダ |+  |VCC  |
|ロータリーエンコーダ  |GND  |GND  |
|ロータリーエンコーダ  |SW  |D4 |
|ロータリーエンコーダ  |DT  |D2  |
|ロータリーエンコーダ  |CLK  |D3  |
|LCD|+  |VCC  |
|LCD|GND  |GND  |
|LCD|SDA|A4 |
|LCD|SCL|A5  |
|L298N|IN1|D10|
|L298N|IN2|D9|
|L298N|ENA|D11 |
|L298N|5V|RAW|
|L298N|GND|GND |

##ソースコード
[https://github.com/type89/arduino_N_controller_L298N/blob/main/N_controller_L298N.ino](https://github.com/type89/arduino_N_controller_L298N/blob/main/N_controller_L298N.ino)

##動作デモ
[![](http://img.youtube.com/vi/DNPDb-Xv3PQ/maxresdefault.jpg)](https://youtu.be/DNPDb-Xv3PQ0)

 - 液晶画面が見づらく申し訳ありません。。。

##詰まったところ・工夫したところ
 - 電源を入れてから操作可能になるまでに、電車が暴走しました。setupでシリアル通信がない間は何もしない、というロジックを加えて、動かないようになりました。
 - 車両によってモーターのパワーが違うので、速度調整を細かくして、どの車両でも操作できるようにしました。
 - デューティー比が低い時はモーターの動きが不安定（電圧も7Vくらいに下がる）です。そこで低いノッチのときは、最初の一瞬だけ高いデューティー比を入れています。
 - ロータリーエンコーダをゆっくり回さないと、誤動作します。

##参考にしたサイト
 - [Pro Microによりフルブリッジドライバ「L298N」を動作させる](https://tomosoft.jp/design/?p=15863)
 - [L298N Dual H-Bridge Motor Controller moduleを使ってみた。](https://analogicintelligence.blogspot.com/2016/09/l298n-dual-h-bridge-motor-controller.html)
web.xml書き方


```
<web-app>
	<servlet>
		<servlet-name>サーブレット名</servlet-name>
		<servlet-class>パッケージ.クラス名</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>サーブレット名</servlet-name>
		<url-pattern>/URLパス</url-pattern>
	</servlet-mapping>
</web-app>
```
【Go】関数のスライスをつくる

## はじめに
Youtubeで見た、「元に戻す」機能を合成関数を使って実装・解説している動画[^1]が大変勉強になりましたので、Goでもやってみました！

## JavaScriptの場合
関数の配列は以下のように作れます。

```javascript
// 1を加算する
function hoge(p) { return p+1; }
// 2乗する
function fuga(p) { return p**2; }

// 関数を配列に格納
let arr = [ hoge, fuga ];

let result = 1;
// 以下の計算をします
// fuga(hoge(1)) -> fuga(2) -> 4
for ( let i = 0; i < arr.length; i++ ) { 
    result = arr[i](result);
}
console.log(`result is ${result}`);
// result is 4
```
動作としてはループの中で一回ずつ関数を呼び出して変数に値を格納しています。

## Goの場合

参考動画[^1]と同じように、「倉庫番」のコードに合わせてます。

```golang:mapstatus.go
type MapStatus struct {
	pX, pY int // プレイヤー座標
	bX, bY int // 荷物座標
	mX, mY int // マーク座標

}

// MoveFunc func(*MapStatus)型
type MoveFunc func(*MapStatus)

// Union 空レシーバ
func (m MoveFunc) Union() {}

// Command 抽象コマンド
type Command interface {
	Union()
}

// move プレイヤーの移動
func (m *MapStatus) move(x, y int) {

	m.pX += x
	m.pY += y

    // プレイヤーとかぶったら荷物をずらす
	if m.pX == m.bX && m.pY == m.bY {
		m.bX += x
		m.bY += y
	}
}

// Right 右へ進む
func Right(m *MapStatus) {
	m.move(1, 0)
}

// Down 下へ進む
func Down(m *MapStatus) {
	m.move(0, 1)
}
```

```golang:main.go
func main() {
	var cmds []Command

	m := NewMapStatus()

	fmt.Println("before:", m) // before: &{1 0 3 1 5 1}

	cmds = append(cmds, MoveFunc(Right))
	cmds = append(cmds, MoveFunc(Down))
	cmds = append(cmds, MoveFunc(Right))
	cmds = append(cmds, MoveFunc(Right))

	cmds = cmds[:len(cmds)-1] // １つ戻る

	for _, cmd := range cmds {
		switch t := cmd.(type) {
		case MoveFunc:
			t(m)
		}
	}

	fmt.Println("after:", m) // after: &{3 1 4 1 5 1}
}
```

## まとめ

動画でも紹介されていますが、「元に戻す」のような機能を関数の配列（スライス）で表現できるところが簡潔でいいなと思いました。

Goで実装した関数のスライスを作るのはそのまま移植した感が否めないので、他のやり方があれば是非コメントで教えていただければ幸いです！
（Goの書き方についてもツッコミありましたらお願いします）

[^1]: 参考動画：[「元に戻す」のしくみ 【ゲーム・プログラミング】【JavaScriptサンプル】](https://youtu.be/XmS9NNX_59I)
HTTP 通信

# 勉強の記録
HTTP 通信 1/31
## 勉強した内容
- HTTPはHTMLなどの情報をやりとりする
- HTTPとHTTPSとの違い。暗号化されている。
- DNSとはドメイン名をIPアドレスに変換してくれる。

## 何をベースに勉強してるか
- [N予備校 プログラミング入門](https://www.nnn.ed.nico/courses/668/chapters/9515)

## 内容の詳細
- HTTP　通信

### わかったことについて
- ドメイン名をIPアドレスに変換できるって知らなかった。
- peercasatの配信設定ってほぼこれだなって思いました。

### むずかしかったよ
- 今回は特になし

## 次回やる予定のこと
- 通信をするボット…！？。
highlight.jsとcheerioのバンドルサイズを削減した時の備忘録


本記事は、[highlight.js](https://highlightjs.org/)と[cheerio](https://github.com/cheeriojs/cheerio)を使用した際に`バンドルサイズ`が思ったより膨れ上がり、ダイエットさせた時の備忘録。

![スクリーンショット 2021-01-31 14.37.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/397734/de9481ae-8850-1595-8d88-099940a11a43.png)
## 膨れ上がった原因その１　
- `highlight.js`をそのままimportしていた。

```js
import hljs from 'highlight.js'; 
...
```

この場合、`highlight.js`が対応する各言語のモジュールが全てインポートされてしまう。

### 対応

特定の言語のみ記述・ハイライトすれば良いので、ニッチな言語のモジュールはバンドル対象外となるように必要な言語分だけインポートさせていく。


以下は、例として`Javascript`のみモジュールをインポートした時のコード。

```js
import hljs from 'highlight.js/lib/core';
import javascript from 'highlight.js/lib/languages/javascript';

hljs.registerLanguage('javascript', javascript);
```
以下、特定言語(15種類ほど)のみインポートした時の、バンドルサイズを対応前と比較したレポート。

|-|対応前|対応後|差|
|:---:|:---:|:---:|:---:|
|size(Gzipped)|265.84kb|133.91kb|-131.93kb|
|analyze|![スクリーンショット 2021-01-31 15.00.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/397734/67246918-2144-3bb2-0713-3415f004ac28.png)|![スクリーンショット 2021-01-31 15.01.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/397734/47b1dd4f-6438-fd46-385f-15167933f0ae.png)|-|

- 参考記事
  - https://blog.mitsuruog.info/2017/12/how-bundle-size-makes-smaller
  - https://bjacobel.com/2016/12/04/highlight-bundle-size/


## 膨れ上がった原因その２　
- `cheerio`使ってハイライト箇所を抽出していた

マークダウン形式のhtml情報から、コード箇所を抽出するために、以下のように`cherrio`を使用して、html要素を書き変える実装をしていた。

```js
const $ = cheerio.load(article.body);
$('pre code').each((_, elm) => {
    const result = hljs.highlightAuto($(elm).text());
    $(elm).html(result.value);
    $(elm).addClass('hljs');
});

body = $.html();
```

### 対応

`highlight.js`の機能である`initHighlighting()`をクライアント側でhtmlのレンダリング時に、実行されておけば`cherrio`を使う必要がなかった。

そのため、こちらは削減というより`cherrio`ごと削除して対応した。

> initHighlighting( )は、ページ内の全ての\<pre>\<code>ブロックをハイライトする機能。

- 参考記事
  - https://microcms.io/blog/syntax-highlighting-on-server-side/
  - https://doitu.info/blog/5a9fe5e3ab60b20097abdb7d
Windows10 Arduinoインストール

とりあえず自分なりに書いてみました。

1.Microsoft Stoteを起動

2.Arduinoをインストール

3.メニューからArduinoを起動

4.終わり

![l_ar_1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/3a274d4a-5c4c-a7ef-f55b-b083d7619f29.jpeg)

![l_ar_2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/d4704805-c5ca-81b5-46a2-c566a9c048cc.jpeg)

![l_ar_3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/cfc39a1e-fddf-db82-834c-652546835fa8.jpeg)

![l_ar_4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/cda25378-f193-3b96-d273-4caaf0bb3d28.jpeg)

![l_ar_5.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/433b7cda-366c-224d-a01b-42d97182250e.jpeg)
ROSのCvBridgeをPython3で使う

# はじめに
ROSで画像をMessageとしてPub/Subしたい場合は，CvBridgeを使うのが一般的だと思います．
しかし，Python3からCvBridgeを使おうとするとエラーになります．
（[前回](https://qiita.com/Yukimura127/items/7ca6affbf32353914b70)，ROSノードをPython3で動かす方法を紹介しました）

CvBridge自体はPython2用にインストールされていて，Python3でROSノードを動かすとPython3でCvBridgeを動かすことになるので，エラーになります．
そこでCvBridgeをPython3用にビルドするのですが，ネットの記事だとエラーになったので，解決策を備忘録的に残します．

# 環境構築
Pythonはビルドイン・仮想環境どちらでも問題ないです．
（どちらかというと仮想環境向けです）

```bash
$ mkdir -p ~/cvbridge_build_ws/src
$ cd ~/cvbridge_build_ws/src
$ git clone -b melodic https://github.com/ros-perception/vision_opencv.git
$ cd vision_opencv
$ git checkout 578af4d6c7846876b3fc64512b1cc92a54894483
$ cd ../..
$ source /opt/ros/melodic/setup.bash
$ catkin config \
    -DCMAKE_BUILD_TYPE=Release \
    -DSETUPTOOLS_DEB_LAYOUT=OFF\
    -DPYTHON_EXECUTABLE={Pythonのパス} \
    -DPYTHON_LIBRARY={Pythonのlibパス} \
    -DPYTHON_INCLUDE_DIR={Pythonのincludeパス}
$ catkin config --install
$ catkin build cv_bridge
$ source install/setup.bash --extend

ex)
$ catkin config \
    -DCMAKE_BUILD_TYPE=Release \
    -DSETUPTOOLS_DEB_LAYOUT=OFF\
    -DPYTHON_EXECUTABLE=~/.anyenv/envs/pyenv/versions/3.9.1/bin/python \
    -DPYTHON_LIBRARY=~/.anyenv/envs/pyenv/versions/3.9.1/lib/libpython.3.9.so \
    -DPYTHON_INCLUDE_DIR=~/.anyenv/envs/pyenv/versions/3.9.1/include/python3.9
```

Checkoutしてバージョンを戻していますが，最新でも問題ないと思います．

# 開発の際の注意点
元々入っているPython2のCvBridgeを削除しない場合，
PYTHONPATHの順番に注意しないとビルドしたCvBridgeが使われません．

ROS本体の順番が先だとPython2のCvBrdigeが使われます．

```bash
この順番だとダメ（root直下にワークスペースを作ってるので以下のようになっているので，順番だけ見てください）
$ echo $PYTHONPATH
/opt/ros/melodic/lib/python2.7/dist-packages:/cvbridge_build_ws/install/lib/python3.9/site-packages
```

解決策としては，以下．

1. PYTHONPATHの先頭に明示的に追加する
2. sourceの順番を変える

### 1.PYTHONPATHの先頭に明示的に追加する
こちらは2回記述されてすっきりしないのと，site-packagesまで記載しないといけないので面倒です．

```bash
$ export PYTHONPATH=~/cvbridge_build_ws/install/lib/python3.9/site-packages/$PYTHONPATH
```

### 2.sourceの順番を変える
ROS（関連）のsetup.shの中を見ると，自身のPYTHONPATHをPYTHONPATHの先頭に追加しています．
なので，ROS本体のsetup.bash（sh）より後にCvBridgeのsetup.bash（sh）を実行すれば解決します．

Dockerfileで環境を作っている場合は，
bashrcに記載するかentrypointで順番をコントロールすれば面倒はないかと思います．

# まとめ
CvBridgeをPython3から使う方法を紹介しました．
ご参考になれば幸いです．
【初心者】ローカルのブランチを最新に更新して反映するまで【初心者】

ローカルとリモート(origin)にmainの情報がある
#ローカルのmasterを最新に更新する方法

以下の2つのステップを踏む必要がある。
1,更新
2,反映
# それを一括でやるやり方がこれ

上の二つのコマンドを一発でやってくれるのが以下

```shell 
$ git pull origin main
```

##丁寧なやり方
```shell 
$ git fetch -p
```

##そのローカルのmaster情報を最新に更新したものをローカルのmasterに反映
[参考](https://qiita.com/takakuda/items/2123e37733445f69f0ff)


```shell 
$ git merge origin/main
```
WebAPIを使用した簡易アプリ作成（rails）

## APIとは

APIとは「Application Programming Interface（アプリケーション・プログラミング・インターフェイス）」の略語であり、「ある1つの機能に特化したプログラムで共有可能なもの」や「ソフトウェアの機能を共有する仕組み」のことです。

Web APIの場合、プログラムはWeb上に公開され、外部から呼び出して利用します。
https://www.internetacademy.jp/it/programming/javascript/how-to-use-web-api.html

## 今回行ったこと

rails学習もまだ浅いので、アプリ作成の練習をかねて以下の事を行いました。
→ユーザーが住んでいるコロナの情報を１つのページの表示する
・ユーザー情報登録（名前、メアド、お住まいの都道府県）
・ユーザーの登録されているの都道府県のコロナの情報をapiを使って1つのページに表示する

## 使用したAPIに関する記事
Google News ↓ コロナのニュース取得に使用
https://qiita.com/KMD/items/872d8f4eed5d6ebf5df1

都道府県別 PCR 検査実施人数
https://coronavirus-esrijapan-ej.hub.arcgis.com/datasets/全期間・検査陽性者の状況別集計（ポイント版・都道府県別）

日本の都道府県ごとのCOVID-19（コロナウイルス）情報を取得するためのWeb API
https://github.com/ryo-ma/covid19-japan-web-api/blob/master/README.ja.md

※数値は正確ではない可能性がありますので、正しくは公的機関からのレポートを参照してください。
## 開発（API部分）
```
class HomeController < ApplicationController
  require 'net/http'
  require 'uri'
  require 'json'
  require 'open-uri'
  def index
    # ログインしているユーザーのお住まいの都道府県を取得↓
    prefecture_name =current_user.prefecture_name

    uri_encode = URI.encode "https://services.arcgis.com/wlVTGRSYTzAbjjiC/arcgis/rest/services/all_patient_v2_prefecture_point_view/FeatureServer/0/query?where=name='#{prefecture_name}'&outFields=*&outSR=4327&from=20&size=20&f=json"
    uri_parse = URI.parse(uri_encode)
    uri_prefectures = Net::HTTP.get(uri_parse)
    @prefecture_info = JSON.parse(uri_prefectures)

  end
end
```

## 概要

お住まい（東京で登録されている場合）↓東京のコロナ情報を出す様にしています。
![スクリーンショット 2021-01-31 14.43.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/681037/29e06d51-3696-64aa-e46f-eda66cdcf30a.png)


## 作成したAPP

http://prefectures-covid.herokuapp.com/

## 環境
Rails 6.1.1
ruby 2.7.2p137
Mac Big Sur 11.1

##　後書き、反省点

機能をもっと増やしたかったが、APIの精査や、herokuでのメール設定など、機能に関する開発に時間をかけられなかったので、次回はこの辺に時間を取られないようにしたい。
Instance Normalizationについて解説


## はじめに
正規化手法に関する調査の２回目です。

１．[Group Normalizationについて](https://qiita.com/sho12333/items/0f0a26ff40f3d86d5a9d)
２．[Instance Normalizationについて<--今回] (https://qiita.com/sho12333/items/0f0a26ff40f3d86d5a9d)


## Instance Normalizationとは

インスタンスの正規化は、グループのサイズがチャネルサイズ（または軸のサイズ）と同じサイズであるグループ正規化の特殊なケースです。

実験結果は、バッチ正規化を置き換える場合、インスタンスの正規化がスタイル転送でうまく機能することを示しています。最近、インスタンスの正規化は、GANのバッチ正規化の代わりとしても使用されています。
> https://www.tensorflow.org/addons/tutorials/layers_normalizations


## 正規化の種類

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/837628/97292e9b-5cba-3773-a552-83a0557f1787.png)


各サブプロットは、入力テンソルを示しています。Nはバッチ軸、Cはチャネル軸、（H、W）は空間軸（画像の高さと幅など）です。青のピクセルは、これらのピクセルの値を集計することによって計算された、同じ平均と分散によって正規化されます。
>https://www.tensorflow.org/addons/tutorials/layers_normalizations

## Instance Normを導入すると


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/837628/61b2532c-be01-a24a-f730-2a33a78c2c01.png)

1行目：Gatys et al.の手法を用いた
原画像（左）、スタイル画像（中）、変換後の画像（右）。
2行目：Ulyanov et al. (2016)の高速スタイル化手法を用いて反復回数を多く学習した場合の典型的なスタイル化結果：パディングをゼロにした場合（左）、より良いパディング手法を用いた場合（中）、<font color="red"><b>パディングをゼロにしてInstance Normを行った場合（右）。<b>


<br>
Gatys et al. (2016) methodは有名な画像のスタイル変換で用いられている手法です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/837628/37be7ee3-ba69-0688-67ff-a7494b79f309.png)


###  Stylizationの結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/837628/de31f10d-cb27-31b6-19b7-d1b2dd8faa86.png)


提案手法を用いたStylizationの例．
1列目：スタイル画像、2列目：オリジナル画像とそのスタイル化されたバージョン。

かなりリアルに生成できていることが分かる。


##まとめ
バッチ正規化をインスタンス正規化に置き換えることで、画像生成のためのある種のディープニューラルネットワークの性能を劇的に向上させることが可能であることを示している。

今後画像識別にも適応していきたい。




## 参考文献
https://arxiv.org/pdf/1607.08022.pdf
AWS DevOps Engineer Professional合格するまでに行ったこと

#この記事について
2021年1月にAWS DevOps Engineer Professional(以下、DOPと略)に合格できたため、その合格で行った勉強方法をご紹介します。
この勉強方法は、他のAWSの試験(Solution Architect Associate,Professionalなど)でも通用する方法だと思うので、是非、AWS資格勉強の方針決め等の参考になっていただけると幸いです。

#前提
筆者がDOPに向けて勉強し始めた段階でのAWSへの知識レベルは、AWS Solution Architect Associateに合格したレベルとなります。
(主要なAWSサービス(EC2,Lambda,S3などなど)の概要と機能はある程度知っており、可用性やコスト効率等の観点でそれらを組み合わせて設計できるレベル)
そのため、以下の勉強方法の実践はAWS Solution Architect Associateに合格できるレベルの方に推奨する方法となります。

#合格するまでに取り組んだこと
実践した勉強方法は以下の通りで、勉強しない休みの期間を入れるとなんだかんだで半年程かかりました。
ただ、集中勉強する期間があれば、1,2か月程でこなせると思います。

### 1.udemyの講座でDevOps合格で最低限必要な知識を知る
関連しそうなAWSのBlackbeltやWhitePaperを隅々まで読むのもメンドクサソウだなと思った筆者は以下の講座を購入し、勉強しました。

●[AWS Certified DevOps Engineer Professional 2021 - Hands On!](https://www.udemy.com/course/aws-certified-devops-engineer-professional-hands-on/)
※音声・テキストは英語

筆者は英語ができませんが、以下の講座では試験に出てくる要点を1スライドにまとめられているため、それを翻訳してメモを取ったり、ハンズオンでは画面と音声から何となく何をやっているかを把握することで要点をメモしました。
英語をあまり知らなくても、この講座は大体DOP合格に必要となる知識を把握できるため、オススメです。

### 2.問題集を徹底的に解く
udemyの講座でDOPに大体必要な知識が身につくと思うので、後は細かなAWSサービスの仕様などを以下の問題集を解くことで、身に着けていきました。
なお、以下の2つの問題集に関して、実際のDOPの本試験でそっくりそのまま出た問題は1割程度だったため、丸暗記では通用しないと思いますが、問題集の解答でよくわからない所があれば、適宜、AWSのBlackbeltやWhitePaperを読んで知識の補完を行うことで応用が利く様になるため、確実に合格へ近づけると思います。

●[AWS Web問題集を解こう](https://aws.koiwaclub.com/)
DOPだけでなく、他のAWS資格の問題集も取り扱っているサイトです。
筆者の場合は、DOPに自信を持って合格するために、以下の目標を立てて、実践・クリアし、試験に臨みました。
①DOPの全問題集を正答率85%となるように何週もひたすら解く
②同サイトの「AWS認定本試験モード」を使用して、試験結果のスコアがDOPの合格水準を超える様になる

●[AWS認定 DevOpsエンジニア – プロフェッショナル (DOP-C01) 模擬試験 (2021年試験対応版)](https://www.udemy.com/course/aws-devops-dop-c01-2020/)
DOPの模擬試験の問題集です。実際のDOPの本試験に近い問題が4試験分あります。
こちらも、4試験分全て正答率85%となるように何週もひたすらに解きました。
nuxt.jsのFull Static Generationで開発

###Full Static Generationとは

公式ブログ
https://nuxtjs.org/blog/going-full-static

・バージョン2.14から使える機能です。
　バージョンアップデートは
　①package.jsonのnuxtバージョンを2.14以上に設定
　②yarn.lockとnode.modulesファイルを削除
　③yarn installを実行する
　でできます。

・完全に静的なサイトを作成する為、ページ遷移時のAPI通信も発生しない（＝APIサーバが落ちても動く）

・ページ遷移が早い

###さっそく設定
package.json内で下記の様に実行内容を書きます。

```json:package.json
  "scripts": {
    "dev": "nuxt",
    "generate": "nuxt generate",
    "start": "nuxt start",
  }
```

###nuxt.config.jsにstaticを設定
```javascript:nuxt.config.js
export default {
  target: "static",
}
```

###開発中は"dev": "nuxt"を実行
```javascript:command
yarn dev
```

###開発が完了したら"generate": "nuxt generate"を実行して静的ファイルを作成
```javascript:command
yarn generate
```
実行すると、distフォルダが作成されます。

本来であれば別途HTTPサーバをおいてホスティングする必要がありましたが、

"start": "nuxt start"を実行することで、ローカル環境でそのまま実行して確認する事ができます。

```javascript:command
yarn start
```
実行すると下記の様にサーバサイドでレンダリングしてくれます。
![nuxtstatic.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/566832/b3666752-fda4-10e0-49bc-104f822d0076.png)
http-serverなどのライブラリなど使わなくても確認できて便利でした。
Linux文件目录操作

| 命令 | 作用 |
|:--|:--|
| ls  | 查看当前目录下的内容  |
| pwd  | 查看当前所在的目录  |
| cd [目录名] | 切换目录  |
| mkdir [目录名] | 创建目录  |
| touch [文件名] | 创建文件  |
| rm [文件名]  | 删除文件  |
|mv [文件名/目录名]|重命名或移动|
|clear|清屏|
僕のポートフォリオ

簡単にポートフォリオみたいなのを作ってみました．
今は貧相だけどこれから立派にしていけたらと思います．


#Androidアプリ①
日向坂46の斉藤京子さんの特技であるばび語を翻訳するアプリを作りました．
使用ツール
Android Studio, kotlin, photoshop

https://play.google.com/store/apps/details?id=chanshizu.github.io.babigtranslater&hl=ja&gl=US

#Androidアプリ②
左右の移動とジャンプを組み合わせて頂上を目指すゲームをつくりました．
[Unityの教科書]([Google先生](https://www.google.co.jp/))を参考にしました．
使用ツール
Android Studio, Unity, photoshop

https://play.google.com/store/apps/details?id=com.KoichiroShizuya.ClimbCloud

#予約ホーム
僕との遊びの予約をするための入力フォームを作成しました．
使用ツール
PHP, html, MySQL，AWS(S3),bootstrap,heroku,etc...

https://pleasebookme.herokuapp.com/index_test.php

#資格関係
機械学習やAIに関する資格であるJDLA G検定を取得しました．

#PAIZA
PAIZAという競技プログラミング学習サイトでBランクを取得しています．
[Django][Python]FormViewのテスト作成

# FormViewとは
以下とか、
https://qiita.com/box16/items/23f78e1014f6dc8f849e
以下を参照してください
https://docs.djangoproject.com/en/3.1/ref/class-based-views/generic-editing/#django.views.generic.edit.FormView

# FormViewのテスト
FormViewは、formに入力された値をチェックし、validならsuccess_urlに**リダイレクト**する

このリダイレクトがテスト作成において結構厄介だったので備忘録的に対処方法を描いてみる

まず、どんなアプリを想定しているかというと、以下
https://sample-apps.box16.site/morpholy/
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1023362/374c8d9f-cb29-e1c3-e2d8-d129270ae0d2.png)  

入力文字列を形態素解析するというアプリ

実際に文字を入力し、出力項目を選択する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1023362/d1fbe99a-6ec2-9211-677c-015e68108965.png)

すると次のような結果が得られる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1023362/afed8d36-0652-78ae-0f79-be9f09f2ecf0.png)

これをテストするには以下のようにテストケースを作る

```tests.py
from django.test import TestCase
from django.urls import reverse


class IndexViewTests(TestCase):
    def test_full_post(self):
        url = reverse('morpholy:index')
        post_data = {
            "text": "大きな男の人に声をかける、素早い女の人",
            "select_part": ["名詞",
                            "動詞",
                            "形容詞"]}

        response = self.client.post(
            url, post_data, follow=True) # follow=Trueが重要

        self.assertContains(response, "名詞")
        self.assertContains(response, "声")

        self.assertContains(response, "動詞")
        self.assertContains(response, "かける")

        self.assertContains(response, "形容詞")
        self.assertContains(response, "素早い")
```
まず、フォームと、フォームに入力する内容をディクショナリとして定義する
それを、postメソッドでpostする

FormViewはpostするとリダイレクトして、responseはリダイレクトの結果が入る
(例えば、status_codeが200ではなく307が返ってくるとか)

postメソッドで、follow=Trueとすると、リダイレクト先の結果が入る
(status_codeは200でresultviewの結果が出る)

後は、仕様に合わせてテストする
pythonでk-meansを使ってクラスタリング

#目的
下図のようななんとなく数が３つに別れているデータを、３つに分類しその分類毎の平均値を出したかったので、ソフトを書いてみました。
![クラスタリング.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/915299/ab1a7ee8-3f87-dae5-a432-dfdd89309e13.png)


#コード
sklearn のKMeansを用いると色々考えなくて良さそう（[参考ページ](https://qiita.com/maskot1977/items/34158d044711231c4292)。こちらのほうが素晴らしい)

```python

from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
import pandas as pd

#close all figure
plt.close('all')

#read Initial Data
Data = pd.read_excel('kmeanData.xlsx')

plt.figure()
plt.plot(Data.x,Data.y,'bo')


#k-meansによる分類
kmeans_model = KMeans(n_clusters=3, random_state=10).fit(Data.iloc[:, 1:])

labels = kmeans_model.labels_
#重心取得
center = kmeans_model.cluster_centers_

# 描画して確認
# それぞれに与える色を決める。
color_codes = {0:'#00FF00', 1:'#FF0000', 2:'#0000FF'}

# サンプル毎に色を与える。
colors = [color_codes[x] for x in labels]

# 色分けした Scatter Matrix を描く。
plt.figure()
plt.scatter(Data.x,Data.y,color=colors)
```

#結果
Kmeansの出した結果と元データにしたExcelを手動分けした実平均を比較した。順番が違うだけでほぼ同じ結果が得られている。すごい。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/915299/db66bc82-0cec-5d3e-2ea7-bf4b6db6cb9f.png)



#その他
KMeans の　random_state=10　のパラメータが何をしているか調べてもわからなかった。　
初期クラスター位置のランダム生成に関わるパラメータなのでしょうか？
とりあえず参考にしたURLを真似ましたが、設定の考え方がわかる方がいらっしゃったら教えてほしいです。
LaTeXで著者のファーストネームを省略したい

plainを使って

```
\bibliographystyle{plain}
```

としているとします．
"plain bst"で検索するとplain.bstの中身が得られます [1]．
その中身を新たなbibファイルに貼り付けます．

```
\bibliographystyle{myplain}
```

command + Fで文字列の検索画面を出し，"name"と入力します．

```
FUNCTION{format.names}
```

が見つかるまでエンターを押します．

```
s nameptr "{ff~}{vv~}{ll{{, jj}" format.name$ 't:=
```

を

```
s nameptr "{f.~}{v.~}{ll{{, jj}" format.name$ 't:=
```

に変えます [2]．

###参考文献
[1] plain.bst - Stanford Computer Science and Electrical ...
http://ftp.cs.stanford.edu/pub/tex/bibtex/plain.bst, (参照2021-01-31)
[2] Manabu Sassano. "LaTeXで参考文献の著者名のファーストネームをイニシャルに." Manabu Sassano's Site. 2021-01-02. 
https://tfidf.net/memos/bibtex-bst-first-name-initial.htm, (参照2021-01-31)