OmniAICreator/Qiita-1.07M huggingface dataset:
ハイフンから始まる〇〇を✗✗したい

-r というファイルを削除したい、みたいな話です。

# 基本

- コマンドの引数に `--` が現れたら、それ以降は `-` から始まる列でもオプションとして解釈しなくなります
- ハイフンから始まるものがファイル名なら、パスを `./-hoge` と指定すればハイフンから始まらずに済みます

# 失敗する例

```
% echo hoge > -r
% ls
-r
% rm -r
rm: missing operand
Try 'rm --help' for more information.
```

この通り、ハイフンから始まる〇〇を何も考えずに扱うと、図らずもオプションとして解釈されて残念な結果になります。

# `--` 以降はオプションにならない

```
% ls
-r
% rm -- -r
% ls
```

`--` を前置してやれば、それ以降はオプションとして解釈されず、意図した動きをしてくれます。

# `-` が先頭に来ないように工夫する

```
% ls
-r
% rm ./-r
% ls
```

そもそもパス名なら、`./` を明示して相対パス指定すればハイフン始まりにならないので、そう書き換えるのも有効です。

# 両方とも知っておかないといけないという話
上に示したふたつの方式は、実は使い分けが必要な場合があります。

## `-` ディレクトリに `cd` したい

これは、「ハイフンから始まる」とは厳密には違う話ですが。

`cd ` コマンドには、`cd -` で直前のディレクトリに戻るという機能があります。なので、`-` というディレクトリに何も考えずに移動しようとすると、 

```
% pwd
/Users/hmwakasa/test
% mkdir test3
% cd test3
% mkdir -- -
% ls -F
-/
% cd -
~/test
% pwd
/Users/hmwakasa/test
```

移動できません。こういうときは `./` を明示した相対パスで指定するとよいです。

```
% ls -F
-/
% cd ./-
% pwd
/Users/hmwakasa/test/test3/-
```

`cd -` は何かオプションを指定しているわけではないので、`--` 前置では解決できません。

## `-` から始まる文字列を `grep` したい

`./` 明示指定法で歯が立たないものがあります。それは、`-` から始まるものがパスではない場合です。具体的には、`-` から始まる文字列を `grep` する場合です。

`grep` のヘルプメッセージから、`-P` オプションの意味を検索したいとします。

```
% grep --help | grep -F -P
grep: conflicting matchers specified
```

こういうときは `--` 前置するしかありません。

```
% grep --help | grep -F -- -P
  -P, --perl-regexp         PATTERNS are Perl regular expressions
```

# まとめ

最後の grep の例はともかく、そもそも記号から始まるファイルは作らないようにしよう。
S3 アクセスポイントのバケットスタイルエイリアスが超絶便利

## はじめに
2021/7/26 のアップデートで S3 アクセスポイントに対してバケットスタイルのエイリアスが自動生成されるようになりました。S3 バケット名のかわりにエイリアスを使用してアクセスポイント経由のデータ操作を行うことができます。

https://aws.amazon.com/jp/about-aws/whats-new/2021/07/amazon-s3-access-points-aliases-allow-application-requires-s3-bucket-name-easily-use-access-point/

新規のアクセスポイントだけではなく既存のアクセスポイントに対しても払い出されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125105/535c3b5f-ce70-9611-c118-8de0db3a7771.png)

## AWS CLI の例
通常の S3 バケットのように高レベルコマンドを使用してアクセスポイントを使用できます。

* エイリアスを使わない場合は API レベルコマンドを使用する必要がある

```shell-session
aws s3api get-object --key test.txt --bucket arn:aws:s3:ap-northeast-1:123456789012:accesspoint/access-point-test test.txt
```

* エイリアスを使用する場合は高レベルコマンドを利用可能

```shell-session
aws s3 cp s3://access-point-test-aqfqprnstn7aefdfbarligizwgyexample-s3alias/test.txt test.txt
```

## S3 アクセスポイントとは
1つの S3 バケットに対して複数のユーザーやアカウントからのアクセスが必要な場合、それぞれのアクセス許可レベルをコントロールする単一のバケットポリシーが必要です。アクセスするユーザーやアプリケーションが増えるにつれてバケットポリシーが複雑になり、テストや変更等が難しくなります。

S3 アクセスポイントは 1 つの S3 バケットに対し用途ごとのアクセスポイント作成し、個別にアクセスポイントポリシーを定義できる便利機能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125105/b7a9cbb3-4a53-044b-34d9-ff8be94a70d7.png)


## 何が嬉しいのか
S3 アクセスポイントの難点として、CLI や SDK 経由で接続する際にはアクセスポイントの ARN を指定する必要がありました。エイリアスを使用するとあたかも通常の S3 バケットのようにアクセスできるので、これまで以上に簡単にアクセスポイントを扱えるようになります。

冒頭の AWS CLI の例ですとちょっと効果がわかりにくいかもしれませんが、SDK を使用する独自アプリケーションや 3rd Party アプリケーションの場合、これまではアプリ側の改修が必要になる場合があり、アクセスポイントを正式にサポートしていないものも多かったと思います。エイリアスを使用することでこれらのアプリケーションでも特別な対応なしに S3 アクセスポイントが使用可能になります。

同様に EMR や Storage Gateway、Athena といった AWS サービスからのアクセスに対しても S3 アクセスポイントを使用できるようになります。

## 制限事項
以下は 2021/8/5 時点でドキュメントに記載のある S3 アクエスポイントエイリアスの制限事項です。

* ユーザー自身でエイリアスを作成することはできない
* 作成されたエイリアスを削除、変更、無効化することはできない
* [一部の S3 データプレーン操作](https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-points-usage-examples.html#access-points-service-api-support) に対してアクセスポイントエイリアスを使用することができる
* [S3 コントロールプレーンの操作](https://docs.aws.amazon.com/AmazonS3/latest/API/API_Operations_AWS_S3_Control.html)にアクセスポイントのエイリアス名を使用することはできない
* 以下のサービスでは使用できない
    * IAM ポリシー
    * S3 サーバーアクセスログの宛先
    * CloudTrail の宛先
    * SageMaker GroundTruth および SageMaker Feature Store
    * Redshift の UNLOAD コマンド
    

## Object Lambda アクセスポイントは？
S3 Object Lambda は S3 に対する GET リクエストをトリガーに Lambda 関数を起動し、データがアプリケーションに返されるときにデータの内容を変更および処理できる機能です。

https://aws.amazon.com/jp/about-aws/whats-new/2021/03/s3-object-lambda-allows-you-to-add-your-own-code-to-s3-get-requests-to-modify-and-process-data-as-it-is-returned-to-an-application/

S3 Object Lambda を使用するには 既存の S3 アクセスポイントを関連付けた Object Lambda アクセスポイントを使用する必要があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125105/5c40cfa0-69e6-5054-3132-07e14923cf57.png)

リクエストを行う際もバケット名ではなく、Object Lambda アクエスポイントの ARN を指定する必要があるため、同じようにエイリアスが使用できると非常に便利なわけですが、今回のリリースでは **Object Lambda アクセスポイントはサポート対象外** でした。Object Lambda アクセスポイントに対してはエイリアスは作成されません。



## 参考
* S3 アクセスポイントエイリアスのドキュメント

https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-points-alias.html



以上です。
参考になれば幸いです。
Dockerのイメージファイルが消えないとき

# はじめに

RHEL7で、古いバージョンのdockerをアンインストールして、新しいDockerをインストールした際に、イメージファイルが消えないことがありました。


```shell
docker rmi [イメージID] #消えない
docker image prune -a #消えない
docker system prune #消えない
```

# 原因と解決策


## 原因

イメージのファイルが下記に残っていた。

> /var/lib/docker/image/overlay2/imagedb/content/sha256/[イメージIDを含む文字列]

## 解決策

ファイルを削除する。

```
rm -f /var/lib/docker/image/overlay2/imagedb/content/sha256/[イメージIDを含む文字列]
```
Next.js + typescriptのプロジェクトにJest & React Testing Libraryを追加する


日本語の記事が見つからなかったため共有します。
このページのやり方が古くなっていたら教えてください。

# 設定方法

```shell:install
yarn add -D jest @testing-library/react @testing-library/jest-dom
```



```babel.config.js
module.exports = {
  presets: ["next/babel"],
};
```


```jest.config.js
module.exports = {
  testEnvironment: "jsdom",
  setupFilesAfterEnv: ["@testing-library/jest-dom"],
  testPathIgnorePatterns: ["<rootDir>/.next/", "<rootDir>/node_modules/"],
};
```

セットアップ用のファイルを作成してsetupFilesAfterEnvにファイルパスを記載する方法もあります。
CSSモジュールを使う場合はさらにmoduleNameMapperにidentity-obj-proxyを追加します。






## .spec.js(.test.js)をpagesディレクトリ内に置かない

pagesディレクトリ内のファイルに基づいてルーティングが行われるため、テスト用のファイルを一緒のディレクトリに入れるとエラーが発生します。

そのときに出てくる

- ReferenceError: expect is not defined
- ReferenceError: test is not defined

などでググると全く関係のない解決方法が出てきます。

解決方法としては

- testsディレクトリを作成して分ける
- pagesはルーティング用と割り切り、実体はcomponentsなどのディレクトリに置く

などがあると思います。



## おまけ：Module not found: Can't resolve 'fs'


getServerSidePropを使用する場合、fsでエラーが出ることがあると思いますがググると古い解決方法が上に出てきます。
Webpack5の場合はconfig.resolve.fallback.fsで設定できます。

```next.config.js
module.exports = {
  reactStrictMode: true,
  webpack: (config, { isServer }) => {
    if (!isServer) {
      config.resolve.fallback.fs = false;
    }
    return config;
  },
};
```
【Laravel】デフォルトで出力されない例外（HTTPエラー等）をログに出力する


#結論
`App\Exceptions\Handler.php`で`$internalDontReport`配列を、空の配列[]でオーバーライドする。

#説明
Laravelの例外はすべて`vendor\laravel\framework\src\Illuminate\Foundation\Exceptions\Handler`クラスでcatchされ、ログの出力とユーザへの表示を行います。

ログの出力は`report`メソッドが担当しています。

```php
    public function report(Exception $e)
    {
        if ($this->shouldntReport($e)) {
            return;
        }

        if (Reflector::isCallable($reportCallable = [$e, 'report'])) {
            if (($response = $this->container->call($reportCallable)) !== false) {
                return $response;
            }
        }

        try {
            $logger = $this->container->make(LoggerInterface::class);
        } catch (Exception $ex) {
            throw $e;
        }

        $logger->error(
            $e->getMessage(),
            array_merge(
                $this->exceptionContext($e),
                $this->context(),
                ['exception' => $e]
            )
        );
    }
```

catchしたすべての例外をログに吐き出すようになっていますが、`Handler`クラスでは「この例外のログは吐き出さなくていいよ」という指定ができます。それを指定するのが`$internalDontReport`配列で、デフォルトでは以下が指定されています。

```php
    /**
     * A list of the internal exception types that should not be reported.
     *
     * @var array
     */
    protected $internalDontReport = [
        AuthenticationException::class,         // 認証関連の例外
        AuthorizationException::class,          // 認可関連の例外
        HttpException::class,                   // HTTPリクエスト関連の例外
        HttpResponseException::class,           // HTTPレスポンス関連の例外
        ModelNotFoundException::class,          // モデルが見つからない例外
        SuspiciousOperationException::class,    // ユーザーがセキュリティの観点から疑わしいとみなされる操作を実行した場合に発生
        TokenMismatchException::class,          // 送信されたトークンとDBのトークンが一致しない例外
        ValidationException::class,             // バリデーション
    ];
```

`Handler`クラスはvendor配下だけではなく、アプリケーション作成時に`App\Exceptions\Handler.php`にも継承したクラスが作成されています。こちらに処理を記述することでvendor配下のプロパティ・メソッドをオーバーライドすることができます。

`App\Exceptions\Handler.php`に`$internalDontReport`を定義してあげることで、例外発生時に優先して参照されるのでvendor配下のコードを汚さずに例外出力の対象を変えることができました:v:

```php
    // App\Exceptions\Handler.phpに以下を追記すれば、すべての例外がログに出力される
    protected $internalDontReport = [
        // AuthenticationException::class,
        // AuthorizationException::class,
        // HttpException::class,
        // HttpResponseException::class,
        // ModelNotFoundException::class,
        // SuspiciousOperationException::class,
        // TokenMismatchException::class,
        // ValidationException::class,
    ];
```

参考：
https://readouble.com/laravel/7.x/ja/errors.html
[ASP.NET/Core]本番環境とローカルテスト環境で発行時にWeb.Configの一部を自動的に切り替える

#やりたいこと

ASP.NET無印、及びASP.NET Coreで発行プロファイルに応じてWeb.Configの設定値を書き変えて発行します。
発行プロファイルではDB接続文字列については個人単位に切り替えながら（*.pubxml.userを使って）運用できますが、それ以外の設定値も同様のやり方で自動的に切り替られればとても便利です。

また、個人用のテスト環境についての設定はgit管理から除外できると良いでしょう。

#前提
ASP.NETの発行プロファイルを切り替えて運用しているケースは多いかと思います。

- local_profile.pubxml（ローカルテスト用プロファイル）
- test_shared_profile.pubxml（共有テスト環境用プロファイル）
- production_profile.pubxml（本番環境用プロファイル）

ここで、ログインページに表示するサイト名をWeb.ConfigのappSettingsに保持しているとします。
（実際にはログ出力先やサービスの為のキー情報など、いろんな重要な情報を保持すると思いますが、ここではわかりやすさの為にサイト名を扱っています）

```xml:Web.Config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <appSettings>
    <add key="websitename" value="〇〇システム" />
  </appSettings>
</configuration>
```

これを発行プロファイルに応じて自動的に置き換えるには次のようにします。

#手順
## Web.<プロファイル名>.Config を作る
Web.Configと同じ場所に、Web.<プロファイル名>.Config というファイルを作ります。

```xml:Web.local_profile.Config
<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
    <appSettings>
      <add key="websitename"
        value="〇〇システム(ローカルテスト用）"
        xdt:Transform="SetAttributes" xdt:Locator="Match(key)"/>
    </appSettings>
</configuration>
```

```xml:Web.test_shared_profile.Config
<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
    <appSettings>
      <add key="websitename"
        value="〇〇システム(共用テスト環境）"
        xdt:Transform="SetAttributes" xdt:Locator="Match(key)"/>
    </appSettings>
</configuration>
```

```xml:Web.production_profile.Config
<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
    <appSettings>
      <add key="websitename"
        value="〇〇システム"
        xdt:Transform="SetAttributes" xdt:Locator="Match(key)"/>
    </appSettings>
</configuration>
```

上記のファイルの中身は「Config変換」と言われるものです。
https://docs.microsoft.com/ja-jp/aspnet/core/host-and-deploy/iis/transform-webconfig?view=aspnetcore-5.0#profile

いろんな方法がありますが、上記では「xdt:Transform="SetAttributes"」という指定によって属性値を置換する指示を行っています。
また、「xdt:Locator="Match(key)"」という指定によって、「key属性が一致する要素のみにこれを適用するよう指示しています。

ここでいう「key」とは、"websitename"のことです。このkeyが一致する要素について、属性を全て上書きするというものです。ここでは属性はvalueのみとなっています。

他にもいろんな変換指示方法があるようですが、とりあえず上記を知っていればほとんどの場面に対応可能かと思います。

あとは、プロファイルを選んで「発行」すれば、上記のConfig変換が行われた後のWeb.Configが発行されます。

ASP.NET Core 5.0用の説明ページに書かれていた内容ですが、ASP.NET 5無印でも動作しました。

##gitでWeb.local_profile.Configを除外

gitでローカル設定がリポジトリで共有されてしまうと、開発者ごとに毎回上書きされてしまって面倒になりますので、.gitignoreで除外しておきましょう。

共用テスト環境や本番環境のWeb.Configは固定のはずですから、リポジトリで管理すればよいと思います。

#おまけ：プログラムからの値の読み取り
```C#
using using System.Configuration;
　:
string value = ConfigurationManager.AppSettings["websitename"];
```
Pandasのgroupbyで階層構造を解消する

## 環境
Pandasのバージョンは1.1.3を使用

##やりたいこと
DataFrameを`groupby`で集約したときに、以下のようにindexとcolumnに階層構造ができてしまう

```Python
import pandas as pd
#データの設定
A = ['a', 'a', 'a', 'b', 'b']
B = ['c', 'd', 'c', 'd', 'c']
X = [1, 2, 3, 4, 5]
df = pd.DataFrame({'A':A, 'B':B, 'X':X})
df.groupby(['A', 'B']).agg({'X': {'mean', 'count'}})
```


今後の取り扱いのために全部バラバラな行や列になっていてほしい

##行の解消：`.reset_index()`

行側の階層構造は`groupby`の後ろに`reset_index()`をつけて解消することができる

```python
df.groupby(['A', 'B']).agg({'X': {'mean', 'count'}}).reset_index()
```

##列の解消：`pd.NamedAgg()`を使う
列側の階層構造を解消するには`agg`内を変更する
はじめに以下を実行したらエラーが出た

```python

df.groupby(['A', 'B']).agg({'X': {'X_mean':'mean', 'X_count':'count'}})

#-->error
#nested renamer is not supported
```

どうやらdict型でrename指定して渡すことが出来なくなってしまっているらしいので、別の方法を試した

```python
df.groupby(['A', 'B']).agg(X_mean=pd.NamedAgg(column='X', aggfunc='mean'),
                           X_count=pd.NamedAgg(column='X', aggfunc='count'))
```
これX_meanとX_countという列にわけることができた！
【AWS】S3をCloudFormationで作成してみました

#はじめに
S3をCloudFormationで簡単に作成してみました。
ざっくりでは下記が設定項目となっております。
S3のバケットポリシーなどは、今回は入れておりません。

|項目            | 設定 |
|:------------------|:------------------|
|デフォルトの暗号化(SSE-S3)|有効|
|バージョニング機能|有効|
|ブロックパブリックアクセス(バケット設定)|有効|

#テンプレート

CloudFormation のテンプレートは下記となります。
```BucketName```欄に、ご希望のS3バケット名を入れ替えて入力してください。

```yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: CloudFormation template for S3 Bucket
Resources:
  S3Bucket:
    Type: AWS::S3::Bucket
    Properties: 
      BucketName:  <バケット名>
      VersioningConfiguration:
        Status: Enabled
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256
      PublicAccessBlockConfiguration:
        BlockPublicAcls: True
        BlockPublicPolicy: True
        IgnorePublicAcls: True
        RestrictPublicBuckets: True
```

以上です。
PHP 配列の中にある空の要素のみを削除 array_diff()

`array_diff()`を用いることで、スマートに配列の中のからの要素のみを削除できる。
php公式サイト array_diff：https://www.php.net/manual/ja/function.array-diff.php)

```php:
$ar = [1 => "レッド", 2 => "", 3 => "ブルー", 4 => "グリーン", 5 => ""];
print_ra($ar);
// 実行結果
// Array(
//    [1] => レッド
//    [2] =>
//    [3] => ブルー
//    [4] => グリーン
//    [5] => 
//)

$ar = array_diff($ar, array(""));
print_ra($ar);
// 実行結果
// Array(
//    [1] => レッド
//    [3] => ブルー
//    [4] => グリーン
//)
```
Notes　インポート機能（Excel側レイアウト・メモ）

Notes![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1285004/3c5d3f50-d213-1b38-a45f-cc432af1ef21.png)
※インポート時におけるKeyサーチ用ビューのビュー名を		
指定します。Keyサーチの結果、当ビュー上でHitしなければ、		
文書が登録されます。Hitすれば、その文書に対する		
更新が行われます。		
		
※ExcelからNotesにデータをインポートする際の		
Notes側のデータ型を指定する必要があります。		
データ型	指定記号	
テキスト	t	
数値	s	
名前	n	
日付	h	
日付＋時刻	hj	
		
※1番目のフィールドは、必ず Key です。		
※複数の Key を指定する場合は、1番目～		
　N番目まで、連続してKeyに指定して		
　下さい。		
※Key は、必ずテキスト型である必要があります		
		
※Keyが「○」のものについて、「フィールド名」を「*」にすると、		
そのフィールドは、更新されません。		
（… Keyデータ自体を更新する必要は無い。）		
		
※Import時、「Data」シートの1行目は、ラベルとして認識するため、		
データとしては取り込まれません。		
		
※Import後、Importしたドキュメントに対して、@Command([ToolsRefreshSelectedDocs]);		
　を実行する必要があります。
Aiseesoft - 動画変換ツールを使ってみる

#Aiseesoftのインストール
https://www.aiseesoft.jp/free-video-converter/
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1845219/90d0378e-17d9-9158-e099-3219d2536fc3.png)

##使ってみる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1845219/b5621ec4-96e6-e268-cad1-a4f047cff49e.png)

ファイルを追加し、設定を開く
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1845219/f76d09f5-f10d-a5ff-4138-6e517300c6f7.png)

ビデオ設定を今回設定したいものにする
 - アスペクト比　4:3
 - 解像度　544×408
 - フレームレート　29.97fps
 - エンコーダー　mp4

##結果
 - 有料ツールっぽいので、試したあとにロゴとかが入ってしまう
 - そもそも4:3でない動画を4:3に変換しようとすると、動画を引き伸ばしたりせず、足りないところは黒背景になってしまう
 - 書き出し自体はうまくいってそう

#Aiseesoft 動画変換 Macのインストール
もう少し機能とコストを抑えた 動画変換に特化したツールがあったので試す
https://www.aiseesoft.jp/video-converter-for-mac/
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1845219/1a064659-d18a-160a-926d-a707c9915280.png)

##使ってみる
無料版の場合
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1845219/5fe3677f-7892-ffaa-39a7-c61d7bcc0d23.png)

ファイルを追加し、設定を開く
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1845219/bcb46c9a-2329-99d2-b3d6-279be8760e02.png)

ビデオ設定を今回設定したいものにする
 - アスペクト比　4:3
 - 解像度　544×408
 - フレームレート　29.97fps
 - エンコーダー　mp4

##結果
 - 有料ツールなので、購入アラートはでてくるが、ロゴなどは入ってなさそう
 - そもそも4:3でない動画を4:3に変換しようとすると、動画を引き伸ばしたりせず、足りないところは黒背景になってしまう
 - 書き出し自体はうまくいってそう
WSLから.exeを起動できない時の解決方法

# 環境
- WSL2
- Ubuntu 20.04.2 LTS

# 事象
いつものようにWSLを使っていて、フォルダをエクスプローラーで開こうと `explorer.exe .` を実行したら、次のようなエラーが出た。

```
run-detectors: unable to find an interpreter for /mnt/c/Windows/explorer.exe
```

`notepad.exe` や `code` でも同様のエラーが発生した。

# 解決方法
powershellから

```
wsl --shutdown
```

してから再びWSLを起動。[こちら](https://github.com/microsoft/WSL/issues/4567 "Can't open Windows app from WSL 2 anymore")を参考にした。[^1]

[^1]: `wsl --shutdown` で解決しないこともあるよう。その際は上記参考サイトにいくつか別の対処法が載っているので参照のこと。
UbuntuServer20.04.2のインストール画面をぺたぺた貼り付け

Windows2019 の Hyper-V に UbuntuServer20.04.2 をインストールしてみたので、画面を貼り付けておきます。
「English」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483166/3bc3191c-0702-aeb1-7467-420631fe76cd.png)
「Install Ubuntu Server」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483166/bbd62dce-29b9-3d72-09c9-fe0d7002f68b.png)
「English」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483166/022a891a-daa3-0d42-2515-84fca2c858e1.png)
キーボードレイアウトを「Japanese」に変更して「Done」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483166/d07c561d-8227-07c3-458d-a07e9305217d.png)
そのまま「Done」。
ここでIPアドレスをメモっておくと、後でsshするとき楽かも。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483166/ac9eadad-222f-54a5-a533-ad1c5d0c3d66.png)
そのまま「Done」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483166/2c54ca63-dd9a-f5e7-db97-8bd275ec9479.png)
そのまま「Done」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483166/11aaa4e3-5f77-cb24-c13b-32c4f5f65450.png)
Tabキーで「Done」まで指導して「Done」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483166/5bf4b903-0e67-6a19-6abf-cf6520b045d5.png)
そのまま「Done」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483166/e194d819-5dd9-8d0a-10a2-e0d504fa0d1b.png)
「Continue」選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483166/1563cc05-67e7-f95c-eb37-11b8ca045026.png)
「Your server's name」はWidnowsで言うコンピュータ名、適当でいい。
「Pick a username」はユーザー名、ログイン時に使うのでいつも使ってるユーザー名でいい。
「Choose a passowrd」はパスワード、無しは設定できない。
「Confirm your password」は同じパスワードを再入力。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483166/66402b26-0ddc-1f96-8eac-a57e027e3fa6.png)
私はssh使うので「Install OpenSSH server」を有効化します。sshってなんじゃ？って方は入れなくても動きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483166/d1771102-eea3-bd2a-fcb5-472d3afd63f9.png)
そのまま「Done」、ここでインストール始まります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483166/e4ddb7eb-900d-78cd-a79f-b73adf1420c2.png)
インストール中・・・。
待つだけです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483166/91084d58-be94-322b-0899-b14390749eb3.png)
インストール終わって、アップデート中。
さっさと使いたいので、アップデート止めて再起動します。キャンセルも時間かかる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483166/ed892192-35b9-d0aa-6aaf-e8ee74ccace6.png)
「Enter」押して再起動。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483166/f96b4884-8c22-3e83-786f-120d447188c1.png)
再起動後、いろいろメッセージが出てた場合「Enter」押すとログインメッセージが出てくる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483166/11eb8e1c-9c2e-568b-1906-f424bdf0624b.png)
ユーザー名とパスワード入れたらログインできる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483166/3db80e60-3c19-635f-fcc1-219f8e6ddc9b.png)
以上です。
Sublime TextにCarbonプラグインをいれて画像化

#Sublime TextにCarbonをインストール

1. ツール→Command Paletteをひらく
1. install Package Carbon と入力
1. Sublime Text→Preferences→Packages Settings→Settings
1. 左がデフォルトの設定なので、変更したいものを右に書く
1. コードを入力→⌘＋Shift＋P でCarbon Shareを選んでサイトにアップ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1845219/76fb1cc5-0c20-9573-cc09-8727b76544ff.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1845219/30485265-bb1b-5cba-6006-6b951d644d80.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1845219/dcbac0e9-43dc-6ef5-aaeb-aca55f9e9ee9.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1845219/d5f0189c-0ddb-501e-bcc6-ddfab4336f82.png)


##設定変更
theme、languageが変更しても変わらないので調査中。。

```perl:test_smple
{
  "default": {
    "paddingVertical": "0px",
    "paddingHorizontal": "0px",
    "backgroundImage": null,
    "backgroundImageSelection": null,
    "backgroundMode": "color",
    "backgroundColor": "#fff",
    "dropShadow": false,
    "dropShadowOffsetY": "0px",
    "dropShadowBlurRadius": "0px",
    "theme": "Base 16 (Light)",
    "windowTheme": "none",
    "language": "JavaScript",
    "fontFamily": "Hack",
    "fontSize": "14px",
    "lineHeight": "133%",
    "windowControls": false,
    "widthAdjustment": true,
    "lineNumbers": false,
    "firstLineNumber": 1,
    "exportSize": "1x",
    "watermark": false,
    "squaredImage": false,
    "hiddenCharacters": false,
    "name": "Shared directly from Sublime Text!",
    "width": 680
  }	
}
```
RDS for MySQLでマルチスレッドレプリケーションを有効にする

## はじめに

MySQL 5.7 からマルチスレッドレプリケーションを有効にすることで、レプリケーションの処理を並列に実行することができるようになります。この機能を使えば、更新処理が多いシステムでもレプリケーション遅延が発生しにくくなります。

マルチスレッドレプリケーションはデフォルトでは無効になっていて、有効にする場合も、いくつかのパラメーターも含めて変更しないとプライマリとレプリカで実行順序が異なることによるデータの不整合が起こる可能性があったり、特定のパラメーターを変更する場合、パラメーターグループから変更できないものもあるのでRDSで使用する場合はちょっとした工夫が必要だったります。

## MySQLのレプリケーションについて
下記の図はMySQLのレプリケーションを簡易的に示した図です。
![mysql-replication.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46847/d8aeb6a7-4b1d-1cf6-a404-a27f1ea0f9c9.png)

アプリケーションからの更新処理はデータ領域とバイナリログへ書き出されます。
バイナリログにに書き出した内容をレプリカ側のMySQLが取得してリレーログに書き込んだ後、データ領域へ更新を反映させます。

アプリケーション側からの更新処理を受け付けるプライマリ側の更新処理はパラレルで行われるのに対し、デフォルトではレプリカのリレーログからデータ領域への更新処理は単一のワーカーでシリアルに処理されるため、同時接続数が多く更新処理も多いシステムの場合、レプリカへの反映が遅れる（レプリケーション遅延が発生する）原因となっていました。


## マルチスレッドレプリケーションを有効にするパラメーター

MySQL 5.7以降では下記の3つのパラメーターを変更することでプライマリとのデータ整合性を保ちつつマルチスレッドレプリケーションを有効にすることができます。
（MySQL 8.0.26 以降は `slave_` で始まるパラメーター名の多くは `replica_` に名称が変更されているので注意が必要です）

#### `replica_parallel_type = LOGICAL_CLOCK`

MySQL8.0.26 未満は `slave_parallel_type`

デフォルト値の `DATABASE` から `LOGICAL_CLOCK` に変更します。デフォルト値の `DATABASE` では、異なるデータベースであれば並列して実行されますが、同一のデータベースではシリアルに実行されるため、単一のデータベースで運用している場合、並列度は上がりません。`LOGICAL_CLOCK` ではタイムスタンプによって依存関係が考慮されるようになり、単一のデータベース内でも並列して実行されるようになります。


#### `replica_parallel_workers = N`
MySQL8.0.26 未満は `slave_parallel_workers`

並列レプリケーションのスレッド数を指定します。デフォルトは `0` で、並列実行が無効になっているので `1` 以上の値を指定します。

#### `replica_preserve_commit_order = 1`
MySQL8.0.26未満は `slave_preserve_commit_order` 

デフォルトでは `0` ですが、マルチスレッドレプリケーションを行う場合は `1` に設定します。
`1` にすることで、リレーログと同じ順序でレプリカのデータ領域に反映されるようになります。

ただし、このパラメーターは `log_bin` と `log_slave_updates` が有効になっていないと以下のようなエラーが出てレプリケーションが実行されません。

```console
 [ERROR] /rdsdbbin/mysql/bin/mysqld: slave_preserve_commit_order is not supported unless both log_bin and log_slave_updates are enabled.
```

`log_slave_updates` はデフォルトで有効になっているので問題ないのですが、`log_bin` についてはパラメーターグループからは設定変更することができません。
![48B9F6DB-CF69-4C93-885A-156CB859EF6C.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46847/8ec9fb1a-83be-a520-9bc1-1a4e039baa7c.png)

RDSの場合、バックアップ保持期間が1日以上の場合に `log_bin` が有効になるようです。
レプリカをAWSのコンソールから追加した場合、デフォルトでは0日となっているため、追加後に改めてバックアップ保持期間を1日以上に変更する必要があります。

![55E5028A-6617-40DF-A43D-EB585DD3D37A.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46847/61ea8a72-ee50-84b9-c798-0957f421b3e6.png)
BigQueryのバックアップ方法(私のメモ)

#はじめに
メモ記事です。
[公式ドキュメント](https://cloud.google.com/bigquery/docs/table-snapshots-intro?hl=ja)に記載があるので、そちらを参照したほうが良いです。

#TL;DR
・ BigQueryのスナップショットと復元を調査
・ スナップショットデコレータはレガシーSQLのみ(今後なくなる？)
・ テーブルスナップショット(方法1)でスケジューラを回して対応

#内容
[BigQuery におけるコスト最適化の ベスト プラクティス](https://cloud.google.com/blog/ja/products/data-analytics/cost-optimization-best-practices-for-bigquery)を見てバックアップしようと思いました。

記載のリンクを辿りバックアップの方法をいくつか確認できました。


###方法1) テーブルスナップショットを取得してバックアップと復元
スナップショットを定期的に取得する方法。
[テーブル スナップショットの概要](https://cloud.google.com/bigquery/docs/table-snapshots-intro?hl=ja)
**(結論、シビれる復旧要件はないため、これを選択しました:sunny:)**

```sql
CREATE SNAPSHOT TABLE
`project.snapshot_dataset.snapshot_table`
clone `project.source_dataset.source_table`
```

復旧方法

```sql
create table `project.restore_dataset.restore_table`
clone `project.snapshot_dataset.snapshot_table`
```


###方法2) スナップショットデコレータによるバックアップと復元
変更履歴を7日間保持しているとのことです。
> Select COUNT(*) FROM [Project_ID:Dataset.Table@-3600000]

ただし、レガシーSQLです、、、。
[BigQueryのバックアップ機能（スナップショット デコレータ）を利用する方法](https://snowsystem.net/cloud/gcp/bigqury/snapshot-decorators/)

ですので、こんな感じのSQLで復旧できそう。

```sql:createtable.sql
create table `project.restore_dataset.restore_table`
as Select * FROM [project.snapshot_dataset.snapshot_table@-3600000]
```

※ レガシーのためsqlは未検証。


###方法3) データエクスポートによる方法
[データの障害復旧シナリオ](https://cloud.google.com/architecture/dr-scenarios-for-data)に記載のあるデータエクスポートでの対応。
めんどうくさい、、、。

##まとめ
BigQueryの障害でテーブルが消えたなんて聞かないので、人的ミスから復元する方法が必要かと思っております。
ですので、定期スナップショットをとって復元する方法が良いのかなと思いました。
(ただ数時間前に戻してーーーって時にスナップショットデコレータが必要なのかな、、、:disappointed_relieved:)
【Laravel】Mailableでメール件名にもBladeファイルを使いたい

この記事は移行しました！[最新の内容はこちら](https://naoqoo2.github.io/blog/Laravel-Mailable%E3%81%A7%E3%83%A1%E3%83%BC%E3%83%AB%E4%BB%B6%E5%90%8D%E3%81%AB%E3%82%82Blade%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E4%BD%BF%E3%81%84%E3%81%9F%E3%81%84/)をご覧ください😀


## なぜやりたいか

- 件名と本文を同じところに定義したい！
    - エンジニア以外でもパッとわかるように。
- 件名にも変数使いたいとき
    - 本文と同じようにbladeで処理を統一したい

## いままでは？

こんな感じでディレクトリ分かれがち。

- resources/lang/ja/hoge.php
- resources/views/emails/hoge.blade.php

```php
return $this
    ->subject(__('hoge.subject'))
    ->text('emails.hoge')
    ->with(['data' => $data]);
}
```


## 件名もBlade使う

フォルダを切って、件名と本文のファイルを用意。

- resources/views/emails/hoge/subject.blade.php
- resources/views/emails/hoge/body.blade.php

`subject()` 内で `view()` を使う。

```php
return $this
    ->subject(view('emails.hoge.subject'))
    ->text('emails.hoge.body')
    ->with(['data' => $data]);
}
```

## IDEが改行含みがち

IDE（VSCodeとか）がファイル保存時に改行保管してくれちゃったりする。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56789/80ca3f80-0685-17a0-e88f-922690ee8a46.png)

メール件名では改行取り除きたいので除去してあげる。

```php
return $this
    ->subject(str_replace(PHP_EOL, '', view('emails.hoge.subject')))
    ->text('emails.hoge.body')
    ->with(['data' => $data]);
}
```

## 件名でも変数使いたい場合はこちら

```php
return $this
    ->subject(str_replace(PHP_EOL, '', view('emails.hoge.subject')->with(['data' => $data])))
    ->text('emails.hoge.body')
    ->with(['data' => $data]);
}
```
『Angular Webアプリ開発 スタートブック 初版』を勉強中に躓いたこととその解決策

　『Angular Webアプリ開発 スタートブック 初版』を勉強中に躓いたこととその解決策を共有します。

# 躓きの原因
　一言で書いてしまうとバージョンの違いに尽きるかと思います。この書籍が出版された2018年4月時点でAngularのバージョンは5、一方で私の環境では12を使用しています。

```
> ng version

Angular CLI: 12.1.4
Node: 16.2.0 (Unsupported)
Package Manager: npm 7.13.0
OS: darwin x64

Angular: 12.1.4
... animations, cli, common, compiler, compiler-cli, core, forms
... platform-browser, platform-browser-dynamic, router

Package                         Version
---------------------------------------------------------
@angular-devkit/architect       0.1201.4
@angular-devkit/build-angular   12.1.4
@angular-devkit/core            12.1.4
@angular-devkit/schematics      12.1.4
@schematics/angular             12.1.4
rxjs                            6.6.7
typescript                      4.3.5

Warning: The current version of Node (16.2.0) is not supported by Angular.
```

# 頼れる先人

　[こちらのブログ](https://doeryaa.hatenablog.com/entry/2021/01/19/070000)でDoErrorさんという方がいくつかの躓きポイントを解説してくれてました。勉強中はかなり助けられました。

# 躓きポイント①　(property) SimpleFormComponent.text1: string
 simpleform.components.tsを作成中（108ページ）に遭遇したエラーです。書籍では、`text1: string;`となっていますが、`text1: string = "";`とすることで解決しました。

# 躓きポイント② Property 'checked' does not exist on type 'EventTarget'.
　第8章の内容です。以下の様にコードのマイナスがついている部分をプラスに置き換えることで解決しました。

```html:controls.component.html
- <input type = "checkbox" (change)="onCheckChanged(item, $event.target.checked)">
+ <input type = "checkbox" (change)="onCheckChanged(item, $event)">    
        
```

```typescript:controls.component.ts
- onCheckChanged(item: string, isChecked: boolean) {
-  let formArray = <FormArray>this.coffeeForm.controls.adds;
-  if (isChecked) {
-    formArray.push(new FormControl(item));
-  } else {
-    let index = formArray.controls.findIndex(elm => elm.value == item)
-    formArray.removeAt(index);
-  }

+ onCheckChanged(item: string, e: Event) {
+   const checkbox = e.target as HTMLInputElement;
+ 
+   let formArray = <FormArray>this.coffeeForm.controls.adds;
+   if (checkbox.checked) {
+     formArray.push(new FormControl(item));
+   } else {
+     let index = formArray.controls.findIndex(elm => elm.value == item)
+     formArray.removeAt(index);
+   }
```

# 躓きポイント③　HTTPサーバが起動しない
　第11章の内容です。`http-server --baseDir="dist/cookbook"`で起動しました。アドレスは127.0.0.1:8080ではない方を使用しました。

　以上です。最後までお読みいただきありがとうございました。
せっかくやし、Qiitaを使ってプレゼンしましょ

# 背景
- notionでのプレゼンが最近ちょっとうまくいってない。
- それなら別のツールで書きやすいのないかな？
  - 僕らがしょっちゅうお世話になってるQiita君がいるじゃないか！
- じゃぁ書いてみよう。

---

# 使ってみた所感
- めちゃ便利！
  - プレビューしながら記事が書けるのはもちろん
  - さらに、プレゼンモードまでついてる
    - そのプレゼンモードまでプレビューできちゃう！

---

# 記事のプレビューのキャプチャ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1841327/a10e47fe-57b4-d6db-29ed-40c2208608db.png)

---

# プレゼンのプレビューのキャプチャ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1841327/e6be85fe-69e7-264e-8de8-e62b84ae2128.png)

---

# 使い方
- markdownで書くので、markdown慣れしている人にはめちゃ簡単にかける
- スライドモードでの意識するポイントは `---`で仕切りを作成
    - 次のスライドに切り替えたいポイントだけ押さえとく

---

# 記事書く上で
- キャプチャを貼りたいときは、みんなのやりやすいやり方で良いと思う
- 個人的にはいつもつかってるchrome addonの[awesome screenshot](https://chrome.google.com/webstore/detail/awesome-screenshot-screen/nlipoenfbbikpbjkfpfillcgkoblgpmj?hl=ja)がおすすめ
  - ショートカット使って、全画面キャプチャはもちろん、部分キャプチャもショートカットで撮れて
      - ダウンロードいらんねんけど！っていうとき用にクリップボードコピーも用意してくれてます
            - `control + shift + e` で全画面キャプチャ
            - `control + shift + s` で部分キャプチャ

---

# プレゼン資料を意識することで
- 他者に伝える力が鍛えられるし
- 備忘録にもなるし
- 自分の考え方が社外の方からもフィードバックもらえるし
- 会社の広報にもなるし
- もろもろめちゃええやん！ってなりました。というお話でした。
    - 社外秘系ネタはご注意を。笑

---

# 参考記事
- これめちゃわかりやすいです。
    - https://qiita.com/Qiita/items/4ff5873776992f0511d6
JavaScript　テンプレートリテラル

JavaScriptの学習の備忘録と振り返りの記事です。
何かの参考になれば幸いです。
付け足しや訂正などある場合ご教授いただけると
大変嬉しく思います！！

#テンプレートレテラルとは
文字列の中に変数や定数を入れ込めるものです

:::note info
文字列は必ずバッククオテーションで囲う
:::
**宣言**
`${}`

```js
const I = "yuka";
let number = 5;

console.log(`${I} has ${number}`);
```
**出力結果**
yuka has 5
nextLine()ではまったワナ

# nextLine()すると勝手に空文字入力される

###こたえ
https://teratail.com/questions/106725

どうやら、`sc.nextInt()` のときの改行が残っているらしく、`sc.nextLine()`が実行されたタイミングで、その改行がユーザーの入力よりも先に入力→Enter実行されてしまうみたい。

`sc.next()`を使うとその症状は起こらない。
UnityAdmobSDK6.0でxcodeビルドした際に「"_GADURequestInterstitial", referenced from:       _Externs_GADURequestInterstitial_m7354DBBE6F0E4C60EFEE0EC733AAEC22D91E2B0C in GoogleMobileAds.iOS.o」」

## 環境
* Unity2019 2.12f1
* MacOS 11.4 Big Sur
* Xcode 12.5.1


## 事象

Unity2019 2.12f1 + Unity Admob SDK 6.0でiOSビルドしたアプリが、
下記`"_GADURequestInterstitial", referenced from:`というエラーでxcode上でビルドできなくなった。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37406/e3896008-48da-cab1-86fb-217934508b41.png)

```
Undefined symbols for architecture armv7:
  "_GADURequestInterstitial", referenced from:
      _Externs_GADURequestInterstitial_m7354DBBE6F0E4C60EFEE0EC733AAEC22D91E2B0C in GoogleMobileAds.iOS.o
     (maybe you meant: _Externs_GADURequestInterstitial_m7354DBBE6F0E4C60EFEE0EC733AAEC22D91E2B0C)
ld: symbol(s) not found for architecture armv7
clang: error: linker command failed with exit code 1 (use -v to see invocation)
```

https://develop.hateblo.jp/entry/admob-6-0-0-error
https://github.com/googleads/googleads-mobile-unity/issues/1616

上記サイト様を参考に、

Xcode上で、`Classes/Native/GoogleMobileAds.iOS.cpp`の

```cpp:GoogleMobileAds.iOS.cpp
reinterpret_cast<PInvokeFunc>(GADURequestInterstitial)(___interstitial0, ___request1);
```

上記部分をコメントアウトすると無事ビルドが通りました。。

ちょっと力技な感じがしますが、一応僕が触っているアプリでは、iPhone実機でadmob広告問題なく動いていました。
S3に独自ドメインでhttpsウェブサイト



教材
-
https://blog.serverworks.co.jp/s3-custom-domain-https


作業
-
以下番号順に実施しました
ほぼ教材通りで実現できました

① S3バケットを作成
-


（名前はURLと一致させる）
制的サイトホスティングは不要

②IAMロールを作成
-

AmazonS3ReadOnlyAccess をアタッチする

③APIGateway作成
-



REST API
そのまま作成

>アクション > メソッドの作成 > GET
統合タイプ：AWSサービス
AWSリージョン：S3バケットを作成したリージョンを指定
AWSサービス：Simple Storage Service（S3）
HTTPメソッド：GET
アクションの種類：パス上書きの使用
パス上書き：S3バケット名/格納したHTMLファイル名
実行ロール：作成したIAM Role ARN
コンテンツの処理：パススルー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178985/223f5486-bd92-367b-d55d-b34478902c23.png)

→

メソッドレスポンスのステータス200で返す本文を application/json から text/html に変更します

→

デプロイしてエンドポイントを確認します

→S3にhtmlファイルをアップ→公開する



④ACM作成
-

ACMの証明書はAPI Gatewayと同じリージョンで発行したものが対象になります
作成する際のドメイン名は Route53のレコードセットを作成する際のドメイン名と同じ にする必要があります

⑤APIマッピング
-

>
API：作成したAPI Gateway
ステージ：デプロイ時のステージを指定
パス：あれば（今回はないので設定は不要）

⑥Route53でレコード作成
-

>
対象のホストゾーンに対象のドメイン名でレコードセットを作成します
タイプ：A - IPv4アドレス
エイリアス：はい
エイリアス先：作成したAPI GatewayのAPI（カスタムドメインの設定後に表示される値）
RaspberrypiとFluentbitの連携

# Fluentbitの導入
以下を参考にしてください。OSのバージョンは間違えないように。

https://docs.fluentbit.io/manual/installation/linux/ubuntu


↓apt系統の利用リポジトリに以下を追加

```
echo "deb https://packages.fluentbit.io/ubuntu/bionic bionic main" | sudo tee /etc/apt/souces.list
```

#### メモ
- fluentbitの導入
    - https://docs.fluentbit.io/manual/installation/linux/ubuntu
- serviceは/etcに拡充されている
    - https://www.infraeye.com/study/linuxz56.html



# Fluentbitの設定ファイルにinput、output情報を記載


設定ファイルは以下に書き方等書いてあります

https://docs.fluentbit.io/manual/administration/configuring-fluent-bit/configuration-file

↓以下に内容が記載されています
/etc/td-agent-bit/td-agent-bit.conf


Inputはmqtt通信、OutputはTCP通信の場合

```
~~省略~~

[INPUT]
    name    mqtt
    name    mqttdata
    tag     DeviceToFluentd
    Listen  0.0.0.0
    Port    1883

[OUTPUT]
    name  forward
    match *
    HOST  <output address>
    PORT  24224
    tls   off

```


# Fluentbitの起動

①raspberrypiをrebootする
②以下でfluent-bitを起動

```
sudo service td-agent-bit start
```

③以下でfluent-bitの状態を確認

```
sudo service td-agent-bit status
```


④自動起動設定

```
sudo systemctl enable td-agent-bit
```
【React】Warning: Failed prop type: The prop `children` is marked as required in `ThemeProvider`, but its value is `null`.の対処法

<h2>症状</h2>
reactでMaterialUIのThemeProviderを使用したとき、下記warnが表示されました。
翻訳すると「警告：失敗した小道具タイプ：小道具 `children`は` ThemeProvider`で必須としてマークされていますが、その値は `null`です。」と表示されました。
ThemeProviderの子コンポーネントがnullになっているため、warnが出ているようです。

```terminal:warn
Warning: Failed prop type: The prop `children` is marked as required in `ThemeProvider`, but its value is `null`.
```

以下がwarnが出たソースです。

```react:Hoge.jsx
import React,{useState} from "react";
import { ThemeProvider } from '@material-ui/core/styles';
import MaterialUIPrivateHeader from "./component/MaterialUIPrivateHeader";
import MaterialUIGuestHeader from "./component/MaterialUIGuestHeader";
import {headerTheme} from "./theme";
export const Hoge= () => {
  
  const [login,setLogin] = useState(false)
  const [nowLocation,setLocation] = useState("HOME")

  function loginHandle () {
    setLogin(true);
    setLocation("index");
  }
  function logoutHandle () {
    setLogin(false);
    setLocation("logoutIndex");
  }
  function GotoHomeHandle () {
    setLogin(false);
    setLocation("logoutIndex");
  }
  return (
      <button onClick={loginHandle}></button>
      <button onClick={logoutHandle}></button>
      <button onClick={GotoHomeHandle}></button>
      {login}"中です"
      {nowLocation}"ページを開いています"
      <ThemeProvider theme={headerTheme}>
      <div></div>
      {
        nowLocation === "HOME"?
          login?
            <MaterialUIPrivateHeader></MaterialUIPrivateHeader>
          :
            <MaterialUIGuestHeader></MaterialUIGuestHeader>
        :
        //HOME画面の時、何も表示させたくないので、nullにしている
        null
      }
      </ThemeProvider>
  )
}
```

<h2>解決方法</h2>
ThemeProviderの要素の下のnullを空のdivタグすることで、warnが出なくなりました。
ThemeProviderの子要素がnullであるため、このようなwarnが出るようで、新設設計だなと思いました。

```react:Hoge.jsx
      <ThemeProvider theme={headerTheme}>
      {
        state.fetchSessionState === REQUEST_STATE.OK?
          state.isLogin?
            <MaterialUIPrivateHeader></MaterialUIPrivateHeader>
          :
            <MaterialUIGuestHeader></MaterialUIGuestHeader>
        :
        <div></div>
      }
      </ThemeProvider>
```


<h2>参考</h2>

https://stackoverflow.com/questions/46700478/failed-prop-type-the-prop-children-is-marked-as-required-in-e-but-its-valu/46700799
JavaScript　変数と定数の違い

JavaScriptの学習の備忘録と振り返りの記事です。
何かの参考になれば幸いです。
付け足しや訂正などある場合ご教授いただけると
大変嬉しく思います！！

##変数と定数の役割
・同じ値を繰り返し使えるようにする
・変更に対応しやす区する
・値の意味をわかりやすくする

:::note info
変数名は自由につけられます
:::

:::note warn
英単語で表記する
単語が二つ以上の場合大文字で単語を区切る
:::

:::note alert
・数字開始 1number
・ローマ字 bango
・日本語 番号
:::

##変数
一度定義した値でも上書きをすることができる。
**変数の宣言**
`let`

```js
let me = "yuka"
consle.log(me + "です")
```
**出力**
yukaです

#####変数値の更新
<details><summary>me = `me + "と君"` or `me =+ "と君"`</summary>
二つ目は省略型どちらも同じ内容

:::note info
後から付け足した変数値が更新内容になる。
:::
</details>

##定数
定数は一度定義した値を変えることはできない。

**変数の宣言**
`const`

```js
const me = "yuka"
console.log(me + "です")
```
**出力**
yukaです
メモ: CodePipelineでキックしたCodeBuildでgit submoduleを使う

タイトル通りのメモです。元ネタは[ここ](https://stackoverflow.com/questions/42712542/how-to-auto-deploying-git-repositories-with-submodules-on-aws#answer-64163023)です。

CodePipelineでCI/CDを組んでいて、CodeStar Connectionsを使ってCloneしたリポジトリの中のsubmoduleを後続のCodeBuildで使いたかったのですが、なかなか解決策にたどり着けませんでした。

結論から言うと、`env.git-credential-helper`を使ってごくシンプルに実現可能です。

https://docs.aws.amazon.com/codebuild/latest/userguide/build-spec-ref.html#build-spec.env.git-credential-helper

buildspecの例は以下です。

```yml
version: 0.2

env:
  git-credential-helper: yes

phases:
  pre_build:
    commands:
      - git submodule update --init --recursive
```

注意点としては、Output artifact formatをFull clone（CloudFormationでは `CODEBUILD_CLONE_REF`）を指定する必要があることが挙げられます。これを指定しないと`.git`フォルダが落ちて来ず、gitコマンドを使うことができません。

## 他の選択肢

この手法が使えない場合は、別のやり方を模索する必要があります。
CI用のユーザを新規に作成し、そのユーザのトークンをSSMパラメータ等を用いてCodeBuildに持ってくる方法などがあるようですが、やはりやや大仰に感じられますね。

https://medium.com/@cristiano.ventura/working-with-git-submodules-in-codepipeline-83e843e5d0a

また、CodeBuildには`GitSubmodulesConfig.FetchSubmodules`というオプションもあるのですが、こちらはPipelineでトリガーする場合には使えないようです。

>Git submodules config is not supported for CodePipeline source

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-codebuild-project-gitsubmodulesconfig.html
API エラー設計

## 概要
API設計するとき迷いませんか？
私はほぼ毎回エラーをどのような形式で返そうか悩んでいます(笑)
だから、今思う最良をフォーマットにしてみます。
もし、同じように悩む方がいらっしゃれば参考にしてみてください。
(今後も改良していきます)

## エラーレスポンス形式
まず、前提としてJSON形式です。


```json
{
  "error": {
    "code": "BadRequest",
    "message": "The API request is invalid or the API parameter value is incorrect.",
    "details": [
      {
        "field": "name",
        "message": "The name field is required."
      }
    ]
  }
}
```

**code** ： エラーコード
**message** ： エラーメッセージ
**details** ： エラーの詳細

## エラーコード
システムの要件に大きく左右されますが、セキュリティを第一として以下のように定めます。  
(エラーメッセージで原因を伝えたいけど、悪用はされたくないよ！という葛藤があります。)

| Code | HTTP Status | Message | 意味 |
|:-|:-:|:-|:-|
| BadRequest | 400 | The API request is invalid or the API parameter value is incorrect.  |  APIリクエストが無効であるか、APIパラメータ値が正しくありません。 |
| Unauthorized  |  401 | You do not have permission to make a request.  | リクエストを行う権限がありません。|
| AuthError  |  401 | The credentials specified in the request are invalid.  | リクエストで指定された認証情報が無効です。|
| Expired  |  401 | The credentials specified in the request have expired.  | リクエストで指定された認証情報が有効期限切れです。|
| Forbidden  | 403  |  The requested operation is prohibited. |  リクエストされた操作は禁止されています。 |
| NotFound  | 404  |  The resource associated with the request was not found. | リクエストに関連付けられたリソースが見つかりませんでした。  |
| InternalError  |  500 |  The request failed due to an internal error. | 内部エラーのためリクエストは失敗しました。 |

## 参考
- [WebAPIでエラーをどう表現すべき？15のサービスを調査してみた](https://qiita.com/suin/items/f7ac4de914e9f3f35884)
- [IBM Operation Decision Manager](https://www.ibm.com/docs/ja/odm/8.5.1?topic=api-rest-response-codes-error-messages)
- [Microsoft 一般的な REST API エラーコード](https://docs.microsoft.com/ja-jp/rest/api/storageservices/common-rest-api-error-codes)
- [キャンペーン マネージャー 360 API サポート](https://developers.google.com/doubleclick-advertisers/core_errors?hl=ja)
【SwiftUI】No image named '' found in asset catalog for 〜〜　のエラー内容とその対応

No image named '' found in asset catalog for　〜〜というエラーをググると英語か古い記事しかヒットしなかったので、備忘録としてエラー内容と対応を記しておきます。


## 結論
アセット（画像）がない。ただそれだけ!英語の原文のままです。

もう少し書きます。
SwiftUIの場合、以下のようなコードで画像を描写することを宣言しますが、Assets.xcassetsに宣言されたアセットがないためタイトルにあるエラーが出るよって話でした。

```swift
 Image("アセット名")
```

## 対応
Assets.xcassetsにアセット（画像とか）を登録してあげればよい。
タイポ起こりがちだから注意。

## 【余談】自分の場合は変数を使ってエラーになっていた
自分の場合はここに変数を代入していてエラーになっていた。
こんなかんじ↓

```swift
@State var hoge = "" 
Image(hoge)
```

なので、以下のような対応で回避した。

```swift
@State var hoge = "hoge" 

if hoge.isEmpty == false {
    Image(hoge)
}
```

または、以下のようにBoolを使う方法

```swift
@State var isHoge = true 

if isHoge {
    Image("hoge")
}
```
他にいい方法があるのかもですが、そのときはご指摘いただけると幸いです。

## 終わりに
エラーが出ていても画像が描写されないだけなのでアプリ自体は問題なく動く。

今後バグの原因になりそうなのと、他のエンジニアにとっても見落としなのかとも思われそうなので、しっかりエラー内容は理解して潰していきたい。そう思った今日このごろ。
Git LFS のリポジトリをcloneやpullしたときにどうなるのか


# はじめに
Git LFSを導入したときに他の人から見るとどうなるのか調べました。

pushする側は正しく設定されていると思うので、そちらはあまり説明せず、
リポジトリを共有しているお客さんなどの他人から見るとどう見えるかを軽く調べました。

# Git LFSを導入後 clone/pullする場合

特に何もしなくても正しく使えます。


下のURLなどを参考に`git-lfs`を入れたあとにcloneなどをする場合です

https://docs.github.com/ja/github/managing-large-files/versioning-large-files/installing-git-large-file-storage

brewが入っているとこれで大丈夫です。 

```bash
brew install git-lfs
git lfs install
```

`$HOME/.gitconfig` に項目が作られ、cloneやpullのときに`git-lfs` コマンドがある前提で正しく動きます。


`git lfs install` を忘れると`.gitconfig` が作られないので 「導入してないとき」と同じことになりますので
そこは気をつけてください。(brew install だけで達成感があるので忘れがちです）

# Git LFSを導入してないときに clone/pullする場合

こちらが問題です。
Git LFSを導入してなくても clone/pullをすることができ、しかもエラーになりません。

当該のファイルは メタデータのような参照の情報が入っている小さなファイルになっています。
ビルド時に初めて気づくことになったり、はたまた本番運用中に気づくということにもなりかねません。
なので周知力が必要です。
（gitデフォルトでサポートする時代になってほしいのですが）

こうなった場合あとから `brew install git-lfs` をしたり `git reset --hard`をしても何も変わりません。
（リポジトリcloneし直したり `git reset --hard HEAD^` などで戻してpullし直しても良いといえば良いです）

そのようになった場合、専用のサブコマンド

`git lfs pull`
でリポジトリ中のgit lfsのデータの取得することができます。

(実行前に `git lfs install` をすることを忘れずに）


# まとめ

「Git LFSを導入してるので対応お願いします」という周知力が必要なので、Git LFSを使う場合、その点は気をつけてください。



# 参考資料


https://medium.com/nttlabs/enabling-git-lfs-c907ca393ccb

https://mseeeen.msen.jp/skip-download-binary-files-with-git-lfs/
BOXのPythonSDKを使うとフォルダ内リスト取得APIのlimitが効かない

頼まれてBOX APIを使った簡単なプログラムを作ったんですが、そのときに？？？な事態が起こったんでメモ。

## 環境
- Python 3.9.6
- boxsdk 2.12.1

## 起こったこと
PythonSDKを使って、指定フォルダの中身を一覧化してexcel出力したい。
なので、↓このAPIを使うことにした。
https://ja.developer.box.com/reference/get-folders-id-items/

```
from boxsdk import OAuth2, Client
import pandas as pd
import numpy

CLIENT_ID = 'xxxxxxxxxxxxxxxxxxxxxxxx'
CLIENT_SECRET = 'yyyyyyyyyyyyyyyyyyyyyyyyy'

access_token = 'aaaaaaaaaaaaaaaaaaaaa' #あらかじめ取得しておいたtoken

oauth = OAuth2(
    client_id = CLIENT_ID,
    client_secret = CLIENT_SECRET,
    access_token=access_token
)

client = Client(oauth)

items = client.folder(folder_id=0).get_items(limit=1,offset=2,sort="name")
list_in_folder = []
for item in items:
    list_in_folder.append([format(item.type.capitalize()), item.name])

df = pd.DataFrame(list_in_folder)

df.to_excel('list.xlsx')
```

しかしいざSDKを使ってlimit, offsetを指定しても
「offset位置から残り全部を取ってくる」挙動になってしまい、limit指定が効いてない様子だった。

## 結論
公式への質問で指摘してるのがあった。
https://github.com/box/box-python-sdk/issues/366

これによると、APIに対してのlimit指定はできない。offset位置から全部取ってくる。
取ってきたうえでlimit指定した分だけプログラム上でページングできるみたいなことが書いてある。（多分）

ええ～～～～紛らわしい。

試しにcurlでAPI自体を叩いてみると期待通りの動きをしたので、SDKを使用せずAPIに直でアクセスするように修正した。

```
import pandas as pd
import requests

access_token = 'aaaaaaaaaaaaaaaaaaaaa' #あらかじめ取得しておいたtoken

url = "https://api.box.com/2.0/folders/0/items"
data = {"limit": "1", "offset":"2", "sort":"name"}
headers = {'Authorization': 'Bearer {}'.format(access_token)}

r = requests.get(url, headers=headers, params=data)
print('ステータスコード：{}'.format(r.status_code))

json_data = r.json();
items = json_data['entries']

print('総ファイル数：{}'.format(json_data['total_count']))

list_in_folder = []
for item in items:
    list_in_folder.append([item['type'], item['name']])

df = pd.DataFrame(list_in_folder)
df.to_excel('list.xlsx')
```
AMD StoreMIをインストールしたらPCが起動しなくなったので手動アンインストールした

# StoreMIとは？

AMD製のストレージ高速化テクノロジー。

HDDとSSDをペアに設定し、SSDの領域をまるまるキャッシュとして使うことで、HDDへのアクセスを高速化する。
SSHDをソフトウェア的に再現したもので、余りがちな小容量SSDを有効活用することができる。

StoreMIソフトウェアは、特定のAMD製CPU＋チップセットの組み合わせであれば使用できる。

[AMD StoreMI テクノロジー 公式ページ](https://www.amd.com/ja/technologies/store-mi)


# 環境

* AMD Ryzen 7 5800X
* ASUSTek B550M-PLUS (AMD B550 チップセット)
* Windows 10 Pro 21H1 19043.1151
* AMD StoreMI Ver2.1.0.191 (インストーラのバージョン)
 * HGST HDN724040ALE640 ＋ Transcend TS128GMTE110S の組み合わせで使っていた。起動ドライブではない。


# 何が起こったのか

StoreMIの以前のバージョン（バージョン不明）を問題なく使用していたが、
新しいバージョンが出たということで上書きインストールを行った。

インストールプロセスそのものは問題なく終わり、最後の再起動を行ったところ
Windows 10 起動時のくるくるアニメーションが止まり、ログイン画面までたどり着けなくなってしまった。

## 試したこと

### スタートアップ修復

正常に起動しない状態で何度かリセットを行うと、自動的にスタートアップ修復が行われる。
しかし何度行っても状況改善しなかった。

### 復元ポイントに戻す

AMD Installer 実行時の復元ポイントが残っていたので、そこに戻そうと試みたが
「復元できませんでした」と言われてしまう。

### セーフモードで起動する

通常起動と同じ現象（くるくるアニメーションが止まる）で起動しない。

### OSのクリーンインストール

OSのクリーンインストールを行い、環境の復元を行った。
StoreMIがない状態では問題なく起動したが、再度StoreMIをインストールしたところ現象が再発し、StoreMIが原因であることを確信する。
~~軽くキレた~~


# 復元の仕方

手動でドライバのアンインストールを行う必要がある。

このフォーラム投稿が大変参考になりました。

[AMD Community - System won't boot after installing storemi](https://community.amd.com/t5/drivers-software/system-won-t-boot-after-installing-storemi/m-p/368824)

## 1. Windows10のUSBブータブルメディアを用意する

Windows 10 のパッケージ版に付属しているUSBサムドライブを用意するか、
[Windows 10 Media Creation Tool](https://www.microsoft.com/ja-jp/software-download/windows10) を使用し、適当なUSBサムドライブをインストールメディアとする。


## 2. PCをWindows10のUSBブータブルメディアから起動する

Windows 10 のインストールメディアをPCに挿入し、インストールメディアより起動する。
起動手順はマザーボードの仕様により異なるが、UEFI設定画面に入り、Bootとかそういう感じのところで一時的に起動順序を変えられるものがある。
また、起動時にファンクションキーを押すことで起動デバイスを選択できるものもある。

## 3. コマンドプロンプトを起動する

「Windows Setup」画面が表示されたら、左下の「コンピューターの修復」をクリックする。
「トラブルシューティング」→「コマンドプロンプト」を選ぶ。

## 4. ローカルのWindowsインストールドライブへ移動する

起動時はブータブルメディアの「X:」ドライブを選択している。
ローカルのWindowsインストールドライブを選択する。
「C:」「D:」「E:」など順番に切り替えていき、「Windows」フォルダが存在するものを探す。

## 5. インストールされているドライバ一覧を表示する

`/image:` オプションには、ローカルのWindowsインストールドライブを与える。 

```msshell
dism /image:E:\ /get-drivers
```

```text:出力例
C:\> dism /image:E:\ /get-drivers

展開イメージのサービスと管理ツール
バージョン: 10.0.19041.844

イメージのバージョン: 10.0.19043.1151

ドライバー ストアからサード パーティのドライバーの一覧を取得しています...

ドライバー パッケージの一覧:

公開名 : oem0.inf
元のファイル名 : prnms009.inf
インボックス : いいえ
クラス名 : Printer
プロバイダー名 : Microsoft
日付 : 2006/06/21
バージョン : 10.0.19041.1

公開名 : oem1.inf
元のファイル名 : prnms001.inf
インボックス : いいえ
クラス名 : Printer
プロバイダー名 : Microsoft
日付 : 2006/06/21
バージョン : 10.0.19041.1

(後略)
```

## 6. StoreMIのドライバを削除する

ドライバ一覧の「元のファイル名」が次のものを探し、「公開名(oem99.infなど)」を控える。

* rccfg.inf
* rcbottom.inf
* rcraid.inf

下記コマンドで手動アンインストールする。
**`/driver:`オプションに与えるファイル名は、「元のファイル名」ではなく「公開名」で指定することに注意**

```msshell
dism /image:E:\ /remove-driver /driver:oem99.inf
```

## 7. 再起動

シェルを閉じ、PCを再起動する。
正常起動できたら、「アプリと機能」よりStoreMIソフトウェアをアンインストールする。



# おわりに

* ほかのドライバ周りのトラブルにも使えるかもしれない
* ちゃんと動けば速くて快適なんです…。AMDさん、改善よろしくお願いします
Gitでブランチ切る→マージ→mainに戻るまでの流れ（自分用メモ）

```
git checkout -b ブランチ名　
```

作業が終わったら、

```
git add .
git commit -m"コミット名"
```
下記コマンドでpush、mainに戻ってマージ、pushまでをすることができる。

```
git push origin HEAD && git checkout main && git merge - && git push origin HEAD
```
[Vue.js]子から親へ

HTML

```html
<div id="fruits-counter">
  <div v-for="fruit in fruits">
    {{fruit.name}}: <counter-button v-on:increment="incrementCartStatus()"></counter-button>
  </div>
  <p>合計: {{total}}</p>
</div>
```

Vue.js[子]

```js
var counterButton = Vue.extend({
  template: '<span>{{counter}}個<button v-on:click="addToCart">追加</button></span>',
  data: function () {
    return {
      counter: 0
    }
  },
  methods: {
    addToCart: function () {
      this.counter += 1
      this.$emit('increment') // incrementカスタムイベントの発火
    }
  },
})
```

Vue.js[親]

```js
new Vue({
  el: '#fruits-counter',
  components:{
    'counter-button': counterButton
  },
  data: {
    total: 0,
    fruits: [
      {name: '梨'},
      {name: 'イチゴ'}
    ]
  },
  methods: {
    incrementCartStatus: function () {
      this.total += 1
    }
  }
})
```

動作の流れ

①「子」addcart関数動作
②「子」自身のcounterに＋１
③$emitにより「親」incrementカスタムイベント発火
④incrementCartStatus関数動作
⑤「親」totalに＋１

親から子よりずいぶんわかりずらい、、、