OmniAICreator/Qiita-1.07M huggingface dataset:
【Android Java】パスワード管理アプリを作成

タイトルの通り、パスワード管理アプリを作成しました。

## リポジトリ
ソースコードが書かれたGitHubリポジトリは以下URLです。
https://github.com/NagaJun1/PasswordManager

現状、アプリストアで配信などはしていないので、Android Studio でビルドすれば、実機での動作が可能です。

## 使用方法
〇「パスワード生成」ボタン、もしくは、生成済みアイテムを押下
->「パスワード生成」時は、パスワードに紐づけるキーワードを入力
-> アプリ内のローカルディレクトリに、パスワードを保存
<img width="300" alt="Screenshot_2023-02-26-22-20-48-032_com.example.passwordmanager.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/762492/0fb6d306-1bdf-5a35-68a0-7590256fbac0.jpeg"><img width=300 alt="Screenshot_2023-02-26-22-21-00-231_com.example.passwordmanager.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/762492/85f54931-fb34-24bd-3b6e-8c0682584959.jpeg"><img width="300" alt="Screenshot_2023-02-26-22-21-12-454_com.example.passwordmanager.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/762492/b5e538b7-2643-2bd5-493c-2eb66dcb3e1b.jpeg">

〇一覧画面から、コピーしたいパスワードを選択
-> 「コピー」を押下
-> クリップボードに貼り付け
<img width="300" alt="コピー&paste.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/762492/eb97cf1d-8bec-5f1b-91c5-a14f2dcf5ca0.jpeg"><img alt="Screenshot_2023-02-26-22-33-47-932_com.example.passwordmanager.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/762492/e5008b0e-47fa-72f3-5ef1-51ba0017c8c7.jpeg" width="300">

## 仕様
・パスワードは、Java の UUID を使用して生成しています。
・生成したパスワードデータは、アプリ直下の専用ディレクトリに保存されるため、ダウンロードファイルの様にコピーすることはできません。
・専用ディレクトリに保存されているため、アプリのアンインストール時にデータはすべて破棄されます。（アプリ削除時にデータが飛ばないような、バックアップ機能が欲しいところですね。。。）
・リスト一覧の表示にある様に、パスワードデータはテキストファイルとして個別に保存されます。（デザイン性を考えるなら、拡張子は消すべき。。。）
・個別ファイルで保存している都合上、ファイル名が重複すると都合が悪いため、重複発生時には保存を回避する仕様になっています。

## 終わりに
完成品見て思ったけど、デザインがセンスねぇ～。。。
まあ、思い付きで二日程度で作ったこともあって、仕様はざっくりしていますが、機能としては事足りているでしょう。
パスワードはユニークだし、複雑な処理もしていないので、エラーでデータが飛ぶような場面も、今のところは出会っていないですし。
デザインに関しては、操作が複雑であるなら、操作をわかりやすくするようなデザインが望ましいですが、画面が二画面で、操作の選択肢も少ないので、改善の余地はあるにしても、大幅な変更は必要ない。。。ということにしておいてくださいm(_ _)m
「パスワードタグ一覧」と「パスワードのキーワード」で指しているものは同じなのに、言葉が一致していないので、今度いじるときには修正が必要ですね。

最近では、Android自身や、google chrome でパスワードを保存する機能があるので、あまり必要ないかと思われますが、ものによって、パスワードの自動保存ができないかったり、保存したパスワードがサイトに紐づいていなかったりという場面があり、不便に感じたため、今回のパスワード管理アプリを作成しました。
ローカルに保存し、ネットワークを経由するような処理は実装していないため、端末を物理的に操作されたりしないのであれば、セキュリティ的に問題ないと思っていますが、脆弱性に関わるような的がありましたら、教えていただけるとありがたいです。

この間、Kindle Appstore での配信方法について調べて、そんなに難しくなさそうだったので、時間があるときにアップロードしてみようかと思います。（そう言って、やらずに終わるのがオチなんですがね(笑)）
Djangoスタートアップ（エラー編）※随時追記

# 新しいモデルを追加すると以下の警告が表示されて、モデルの追加ができない(2023/02/28)
```shell:コマンドライン
It is impossible to add a non-nullable field 'text' to sentencedb without specifying a default. 
This is because the database needs something to populate existing rows.
```
## 説明
既存のレコードにはNULL禁止であるにも関わらず、NULLが入ってしまう。

そこで既存のレコードはどうするかを聞かれる
```shell:コマンドライン
1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
2) Quit, and let me add a default in models.py
```
2回目以降の`python mange.py makemigrations`で発生する可能性あり

## 解決策 
models.pyで定義したフィールドにdefault値を指定する

参考記事
https://noauto-nolife.com/post/django-non-nullable/

# `Template`で`{{% url 'portfolio_app:worksTemplate pk=work.pk %'}}`と記述したら、`NoReverseMatch at/`エラーが表示される(2023/04/15)
## 解決策
×`{{% url 'portfolio_app:worksTemplate pk=work.pk %'}}`
〇`{{% url 'portfolio_app:worksTemplate' pk=work.pk %}}`
`pk=`までシングルクォーテーションでくくる必要がなかった。

# `views.py`で`pk`を認識できない
## 解決策1
（関数ベースビューの場合）引数に`pk`を追加する
```python:views.py
#def worksTemplate(request):
def worksTemplate(request, pk):#引数にpkを追加
    works = get_object_or_404(Post, pk=pk)
    return render(request, 'portfolio_app/worksTemplate.html', {'works' : works})

```
ChromeOS の Linux アプリケーションで日本語入力する方法＆日本語入力できない場合の対処

## 記事作成の発端

- Chromebook の Linux 環境が汚れてきたので削除、再作成・・・
- したら、なんか日本語入力がうまくいかない。
- 何が原因かわからない。
- なんとかする。
- した。

相変わらず原因は不明なれど、似たような人が発生した場合を考えて、現在の手順を残しておこう。というのがモチベーションです。

## 手順

### 0. Linux 環境を削除してから、本体を再起動

- 削除 >> 再作成、とすると、失敗するケースが多かったため。
- 不要かもしれないけど、念のため。

### 1. パッケージインストールと fcitx-mozc の自動起動設定

```bash
sudo apt update && sudo apt upgrade -y
sudo apt install -y fcitx-mozc
echo "/usr/bin/fcitx-autostart" >> ~/.sommelierrc
```

### 2. 日本語フォントインストールとロケール設定

```bash
sudo apt install task-japanese locales-all fonts-ipafont -y
sudo localectl set-locale LANG=ja_JP.UTF-8 LANGUAGE="ja_JP:ja"
source /etc/default/locale
```

### 3. 環境変数の設定

- 以下のコマンドでファイルを作成＆編集画面に移行し、

```bash
sudo -e /etc/environment.d/fcitx.conf
```

- 以下の文字列を入力
- 入力ツールは`vi`が使用される。

```bash
GTK_IM_MODULE=fcitx
QT_IM_MODULE=fcitx
XMODIFIERS=@im=fcitx
GDK_BACKEND=x11
```

### 4. Linux シャットダウン＆IME コンフィグ設定

- ここで必ず Linux を終了させる。ターミナルアイコンの右クリックから『Linux をシャットダウン』
- シャットダウン後にターミナルを再度起動、IME 設定で fcitx を選択

```bash
im-config &
```

### 5. 再度 Linux シャットダウン＆ fcitx コンフィグ設定

- 念の為、ここでも Linux を終了させる。
- 再起動後、以下のコマンドで fcitx のコンフィグを起動、Mozcを追加

```bash
fcitx-configtool
```

### 6. 全て完了後、Linux アプリケーションで日本語入力を確認

- デフォルトの Linux ターミナルアプリは、現在だと何もしなくても日本語入力可能となっている。
- ので、`mate-terminal`などをインストール、起動して、IME 切り替えができるか確認する。

## 遭遇するかもしれない失敗パターン

### 1. IME 切り替えが有効化されない

- 全角・半角キーや`Ctrl+Space`を入力しても、IME が切り替えできない状態になる。
- このパターンは、fcitx-mozc のコンフィグ設定で、最初から Mozc が登録されている場合が多かった。
- 対処には Linux を削除して再インストールが必要

### 2. 正常に日本語入力できない

- 日本語入力をすると、変換候補が出現せずに一文字ずつ変換が確定されつつ入力されていく状態になる。
- 日本語化が正常ではない可能性もあるが、Linux アプリケーションが ChromeOS 上の Linux での日本語入力に対応していない可能性もある。
- `mate-terminal`であれば、確実に日本語入力に対応しているので、インストールして原因の切り分けを行う。
- `mate-terminal`でも日本語入力が正常ではない場合は再インストールが必要
Djangoスタートアップ その8 (フォーム編)

Djangoのフォームの良いところ
- フォームを０から定義可能
- フォームの結果をモデルに保存できる`ModelForm`を作ることが可能


### forms.pyの配置
```
blog
   └── forms.py
```

### モデルのためのフォームを作成
```python:appName/forms.py
from django import forms
from .models import DB★#models.pyで定義したDBを使用
class PostForm(forms.ModelForm):
    class Meta:★#どのモデルを使えばよいかを伝える
        model = DB
        fields = ('yourField',)★#()内部は','で終わる必要がある
```
### フォームのための新しいviewを作成
```html:appName/templates/appname/base.html
<html>
    <head>
        <title>Django Girls blog</title>
        <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
        <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css">
        <link href='//fonts.googleapis.com/css?family=Lobster&subset=latin,latin-ext' rel='stylesheet' type='text/css'>
        <link rel="stylesheet" href="{% static 'css/blog.css' %}">
    </head>
    <body>
        <div class="page-header">
            <a href="{% url 'post_new' %}" class="top-menu"><span class="glyphicon glyphicon-plus"></span></a>★urlにpost_newを追加
            <h1><a href="/">Django Girls Blog</a></h1>
        </div>
        <div class="content container">
            <div class="row">
                <div class="col-md-8">
                    {% block content %}
                    {% endblock %}
                </div>
            </div>
        </div>
    </body>
</html>
```

### post_newビューをviews.pyに記述
`POST`フォームを新規作成するには
1. `PostForm()`を呼び出す
2. テンプレート渡す

ビューで扱う二つのシチュエーション
1. 最初のページアクセスで空白のフォームが必要な場合
1. `form`タグから`POST`されて、リクエストが送信されたとき

```python:appName/views.py
from .forms import PostForm
(中略)
def post_new(request):
    form = PostForm()
    return render(request, 'blog/post_edit.html', {'form': form})
```
1,2のシチュエーションに応じて場合分けを行ったviews.pyファイルの内容
```python:appName/views.py
import django.shortcuts import render, redirect
    if request.method == "POST":
        form = PostForm(request.POST)
        if form.is_valid():
            post = form.save(commit=False)
#以降は実装によりけり
#            post.author = request.user
#            post.published_date = timezone.now()
            post.save()#★DBにセーブする
#            return redirect('post_detail', pk=post.pk)
    else:
        form = PostForm()
    return render(request, 'blog/post_edit.html', {'form': form})
```

参考記事
https://tutorial.djangogirls.org/ja/
javascriptメモ

初心者による自分用メモです
***

２以上の自然数の入力について、
入力値が素数ならtrueを、合成数ならfalseを返す関数
```javascript:primeChecker
let primeChecker = (num) => {
    for (let i=2; i<=parseInt(Math.sqrt(num)); i++) {
        if (num%i==0) {
            return false;
        }
    }
    return true;
}
```
___


２以上の自然数の入力について、
入力値が合成数なら０を、素数なら入力値を返す関数
```javascript:primeEmitter
let primeEmitter = (num) => {
    for (let i=2; i<=parseInt(Math.sqrt(num)); i++) {
        if (num%i==0) {
            return 0;
        }
    }
    return num;
}
```
___

インデックスが大、小の順で指定された場合、文字を反転して出力する関数
０以上のインデックスのみを想定しています。
```javascript:Slice
let Slice = (str, a, b) => {
    if (a <= b) {
        return str.slice(a, b);
    } else {
        let revStr = '';
        let list = [];
        for (let i=a-1; i>=b; i--) {
            revStr += str.charAt(i);
        }
        
        return revStr;
    }
};
```
Dockerでの環境構築　entrypoint.shの修正が反映されない

Dockerでの環境構築の時にハマったので備忘録として。

# 起こった問題・背景
`/usr/bin/entrypoint.sh: line 23: exec: rails: not found ERROR: 127`
と出たのでentrypoint.shをいじったりDockerfileをいじったりしていた。
（エラーの原因はrailsがインストールされてないことですが、この記事で書きたいこととは違うので無視します）

entrypoint.shを変更して内容が変わったたはずなのに、
同じ行でエラーが出ていたので「なんで？」と思った。

# 解決策
当時の環境構築行っていた際に生成されたDockerのimageを全部削除して再ビルドした

- 現状のイメージの確認
`docker images`
これを実行するイメージIDが出てくる

- イメージの削除
`docker rmi イメージID`
消したい対象のイメージIDをコピペして上記実行

# 原因
- あまり詳しくないけど、Dockerのimageが残っていたことが原因っぽい？
- `docker-compose down`してコンテナ消しても変わらなかったので、どこかでキャッシュされてるのだろうと予想していた

詳しい方いたらコメントでご教示いただけますと幸いですm(_ _)m
typescriptで一括importする方法

<h2>問題点</h2>

```typescript:app.ts
import Router from './core/router'
import Store from './store';
import newsFeedView from './page/news-feed-view'
import newsDetailView from './page/news-detail-view'

const store = new Store();
const router: Router = new Router();
const newsFeedView = new NewsFeedView('root', store);
const newsDetailView = new NewsDetailView('root', store);

router.setDefaultPage(newsFeedView);
router.addRoutePath('/page/', newsFeedView, /page\/(\d+)/);
router.addRoutePath('/show/', newsDetailView, /show\/(\d+)/);

router.route();
```
app.tsは、ニュースアプリへ最初にアクセスした時に、呼ばれるファイルです。
app.tsで、ニュースアプリに搭載されている機能（ニュース一覧、詳細ページ）のrouter情報を
addRoutePathにて、routerに追加しています。

アプリ機能のrouter情報に追加するために、./page以下の各moduleをimportしています。
import newsFeedVie from './page/news-feed-view'
import newsDetailView from './page/news-detail-view'

もし、サービスに色んな機能が追加し、./pageにmoduleが追加されましたら、
サービスの入り口であるapp.tsでrouterクラスに新機能のrouter情報を追加する必要があります。
./pageに何のmoduleが追加したか確認　→ app.tsにimportする必要があり、
都度./pageに何のpageが追加されたか確認しなければなりません。

<h2>解決策</h2>

'./page'にindex.tsを作って、その中にexportするpage配下のmoduleを定義しておくと、
app.tsでは以下のように１行でimportすることが可能になります。
＞import { newsFeedView, newsDetailView} from './page'
```typescript:/page/index.ts
export { default as NewsDetailView } from './news-detail-view'
export { default as NewsFeedView } from './news-feed-view'
```

```typescript:app.ts
import Router from './core/router'
import Store from './store';
import { newsFeedView, newsDetailView} from './page'

const store = new Store();
const router: Router = new Router();
const newsFeedView = new NewsFeedView('root', store);
const newsDetailView = new NewsDetailView('root', store);

router.setDefaultPage(newsFeedView);
router.addRoutePath('/page/', newsFeedView, /page\/(\d+)/);
router.addRoutePath('/show/', newsDetailView, /show\/(\d+)/);

router.route();
```
terraformが利用するhashicorp/go-hclog

Hashicorp製OSSのロガーとしては [hashicorp/logutils](https://github.com/hashicorp/logutils)が有名だが、
Terraformのコードリーディングをしていたらその内部では[hashicorp/go-hclog](https://github.com/hashicorp/go-hclog)を利用していることに気が付いた。
どちらもGo言語標準のlogに準拠したロガーだが、どうしてロガーを変更したのか気になったのでいろいろ調べてみた。

## hashicop/logutils
logutilsは非常にシンプルなロガー。
Go言語標準のlogと同一インタフェースを持ちつつ、ログメッセージ中にログレベルを埋め込むことでログレベルのフィルタリングが実現できる。
標準logと同一インタフェースを持つのでDebugメソッドやInfoメソッドなどは持たず、Printメソッドに渡すメッセージの先頭に`[DEBUG]`や`[INFO]`などの文字列を埋め込むことでログレベルを実現していることに結構驚く。

```go
func main() {
	filter := &logutils.LevelFilter{
		Levels: []logutils.LogLevel{"DEBUG", "WARN", "ERROR"},
		MinLevel: logutils.LogLevel("WARN"),
		Writer: os.Stderr,
	}
	log.SetOutput(filter)

	log.Print("[DEBUG] Debugging") // this will not print
	log.Print("[WARN] Warning") // this will
}
```

ちなみに本体100行未満なので簡単に実装を確認できる。

## hashicorp/go-hclog
[hclog](https://github.com/hashicorp/go-hclog)もシンプルなロガーではあるが、logutilsに比べより多くの機能を実装している。
logutilsと同じくPrintメソッドに渡すメッセージの冒頭にログレベル識別用の文字列を埋め込むことでログレベルを実現しつつ、オプションとして専用のInfoメソッドなども提供する。
それ以外にも、構造化ロギング、Key-Valueデータのロギング、など一般的なロギングに必要な機能が一通りそろっている。

```go
func main() {
	appLogger := hclog.New(&hclog.LoggerOptions{
		Name:  "my-app",
		Level: hclog.LevelFromString("INFO"),
	})

	appLogger.Debug("this message will not print")
	appLogger.Info("this message will print")
	appLogger.Info("message with key-value", "key", 42)
}

// $ go run main.go
// 2023-02-26T22:19:29.622+0900 [INFO]  my-app: this message will print
// 2023-02-26T22:19:29.622+0900 [INFO]  my-app: message with key-value: key=42
```

ちばみに、terraformではInfoメソッドなどのログレベル別メソッドなどの機能は利用しておらず、logutilsと同じように`log.Printf("[INFO] ...")`の形式でロギングしている。



## 参考: terraform-plugin-log (tflog)
terraformの実装にて利用しているロガーではないが、terraformがplugin向けに提供するロガーとして[terraform-plugin-log (tflog)](https://github.com/hashicorp/terraform-plugin-log)がある。
tflogはhclogのラッパーで、plugin毎にhclogのログ出力設定を行わなくてもよく、terraform本体の設定を引き継いで出力してくれる。


おそらく、terraformがlogutilsではなくhclogに移行した理由はtflogを実現するためであり、terraform本体とプラグインでより統一的な仕組みが必要だと判断したからではないかと思う。
[terraform pluginのロギング](https://developer.hashicorp.com/terraform/plugin/log/managing)では、出力するログレベルをterraform本体とプラグインで区別したり、特定プラグインのみログレベルを変更できたりする。例えばterraformはinfoレベルで出力し、terraform-provider-awsはdebugレベルで出力する、それ以外のpluginはログ出力しない、みたいなことが実現できる。
これを実現するためのフィルタリングをterraform本体で実装しようとするとかなり面倒そうで、そういった機能を提供するためにhclogおよびそのラッパーとしてのtflogを利用していると推測する。
proc macro not expandedエラーが出たときにやったこと

RustでWeb開発をしていたある日、朝起きてコードを書こうと思ったら次のようなエラーが出ていました。

`proc macro 'main' not expanded: Cannot create expander for ....`

![スクリーンショット 2023-02-26 17.48.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385478/99c9d354-6bec-8729-558f-2858d3dd979f.png)


# エラーの内容

自分はVSCodeにrust-analyzerを入れてRustのコードを書いています。
上記のエラーは手続きマクロ（procedural macro, proc macro）をrust-analyzerがうまく展開してくれないことに起因しているようです。

プログラムは問題なく動くのでおそらくrust-analyzer上での問題だと考えられます。

特にコードや設定を何も変えずに突如として出てきたエラーなので非常に困惑しました。。。

# ネットで調べた解決策

ネットで調べると次のようなものが出てくると思います。

## VSCodeのダウンロードし直し

https://stackoverflow.com/questions/72732296/error-proc-macro-main-not-expanded-cannot-create-expander-for

VSCodeをuniversal版でダウンロードし直せって言ってます。でも自分は元からuniversal版だったのであまり関係ないかなと。

## rust-analyzerをプレリリース版にスイッチ

https://www.reddit.com/r/rust/comments/vj2ghz/suddenly_proc_macro_main_not_expanded_proc_macro/

rust-analyzerをプレリリース版にしろって言ってます。でも自分は元からプレリリース版（`v0.4.1415`）だったのでこちらもあまり関係ないかなと。
ちなみにプレリリース版へのアップデートですが、VSCodeの [拡張機能] > [プレリリースバージョンへの切り替え]で簡単にできます。

## その他

https://github.com/rust-lang/rust-analyzer/issues/10894

https://github.com/rust-lang/rust-analyzer/issues/12610

https://users.rust-lang.org/t/proc-macro-task-not-expanded-no-proc-macro-dylib-present/87912

## 無理やりな解決策

そもそもrust-analyzerがなんか勘違いしてるっぽいので、rust-analyzerにこのエラーを無視させればいいわけです。
なので、設定から`rust-analyzer.diagnostics.disabled`に`unresolved-proc-macro`を追加して無視します。

![スクリーンショット 2023-02-26 17.45.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385478/1156d91a-f7ea-fd31-bc6b-30fefe911cbc.png)

ただ個人的には単純にエラーを無視しているだけで根本的な解決はしていないので、他の方法を取りたいです。


# 自分の解決方法

なんかrustupをupdateしたらエラーが解決しました。このコマンドによりRustは最新版に更新されます。

`$rustup update`

（これで解決した理由が分かったら追記）
（通信）プロトコルとその標準化

:::note info
この記事は [マスタリングTCP/IP　入門編（第6版）](https://amzn.asia/d/2qksld3)を読んだメモです。
:::

## 通信プロトコル
IP, TCP, HTTP, IPX, SPXなどなど。

```mermaid
%%{init:{'theme':'base','themeVariables':{'primaryColor':'#20b2aa','primaryTextColor':'white','primaryBorderColor':'#20b2aa','lineColor':'gray','textColor':'#6A7FABCC','fontSize':'20px'}}}%%

graph LR;
A-."通信".->C
A("コンピュータ")---B["ネットワーク"]---C("コンピュータ")
C-."通信".->A
```
これを滞りなく行うための約束事。
物理部分からソフトウェアまで、全てにおいて正しく守られないと、通信は成り立たない。

通信プロトコルを体系的にまとめたものが`ネットワークアーキテクチャ`。
TCP/IP以外にもめっちゃあるぞ。

## プロトコル標準化
通信ができるようになり始めた頃は、各々好きにやっていた。

体系化だけでもまず…というところから標準化が始まり、
広く通信したくなるにつれて徐々にベンダーロックインされるのは辛い、互換性がいるねとなりオープン化とマルチベンダ化が進んだ。

最初はISOが`OSI`を設定した。
今はこの参照モデルだけ活躍している。（[別記事](https://qiita.com/masaozi3/items/5f779b06715c34f74d89)参照）

TCP/IPの仕様はIETF。
Salesforce認定アソシエイト試験の公式練習問題解説してみた-07

こんにちは

Salesforce認定アソシエイト試験の公式練習問題があるのはご存じでしょうか。
Trailheadにフラッシュカードとして何度も解ける練習問題がございます。

今回は
認定資格試験の準備: Salesforce 認定アソシエイト＞
ナビゲーションについて知識を深める

の問題3問目を解説します

今回の内容は動画でも解説しています

https://www.youtube.com/watch?v=ZJHt2rso50A

<iframe width="560" height="315" src="https://www.youtube.com/embed/ZJHt2rso50A" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>


https://trailhead.salesforce.com/ja/content/learn/modules/cert-prep-salesforce-certified-associate/explore-navigation


![ログイン.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/fa791c8c-6586-ed23-7734-18fd1d72d02c.png)


正解はCです

ユーザからログイン履歴をたどることが可能です

Aのロールではロール階層の位置づけが確認が可能です

Bのプロファイルからはユーザの権限などの設定などを確認できます

## 他の認定アソシエイトの勉強方法について

他の勉強方法についてはこちらをご確認ください

https://qiita.com/Takaa/items/d35c9955fe8eb889d76b
コンピュータとネットワークの発展の歴史

:::note info
この記事は [マスタリングTCP/IP　入門編（第6版）](https://amzn.asia/d/2qksld3)を読んだメモです。
:::

# はじめにみたいな部分
初期のコンピュータはスタンドアロンだったのが、コンピュータネットワークが当たり前の世界になった。
そして個々にコンピュータ同士につないでいたのが、公共のネットワークとなり、インターネットに接続することが当たり前になった。

ネットワークはいわば神経みたいなもの。

# 発展の7段階
## 1. バッチ処理
スタンドアロンのコンピュータに対して、処理内容を持っていって読み込ませる。
1つの処理で1台のコンピュータを専有する時代。

言語的にはCOBOLやFORTRANの時代。

## 2. タイムシェアリングシステム(TSSD)
1つのマシンに複数の端末をつないでコンピュータをシェアするようになる。
```mermaid
%%{init:{'theme':'base','themeVariables':{'primaryColor':'#20b2aa','primaryTextColor':'white','primaryBorderColor':'#20b2aa','lineColor':'gray','textColor':'#6A7FABCC','fontSize':'20px'}}}%%

graph LR;
A(("‥<br>ｖ"))-->B("端末")-->C("コンピュータ")-->D["ネットワーク"]
A--"直接操作も"-->C
A2(("‥<br>ｖ"))-->B2("端末")-->C
A3(("‥<br>ｖ"))-->B3("端末")-->C

C-."X　ここはまだつながらない".-E("コンピュータ")
```
この頃にインタラクティブ操作が可能になった。
言語的にはBASIC。

1970年代に一般企業でも使えるレベルに。
そこでコンピュータ間の通信が生まれる。
そして分散処理も可能に。

## 3. 1980〜 コンピュータネットワーク
パケット交換が生まれる。
コンピュータのメーカーを問わずに通信できるようになる。

`ウィンドウシステム`の登場で同時に複数のプログラムを実行可能になった。
この頃はまだパーソナルコンピュータはなく、「ワークステーション」で作業をしていた。

## 4. 1990〜 インターネット普及
1人1台コンピュータ（パーソナルコンピュータ）の時代。
ダウンサイジングやマルチベンダ接続なんかが進んだ。

e-Mailやwwwを使って発信するブームが起きる。

LANシステムとしてはNetWareが主流だったが、
色々なマシンを繋ぐうえでTCP/IPもなかなかよくない？となってきた。

#### ダウンサイジング
これまでメインフレームとかでやっていたような処理を、PCとかに載せ替えること。
ハードウェアの進化によってでっかいコンピュータじゃなくてもできることが増えた。

## 5. インターネット中心に
`通信 = 電話網`だったのが`通信 = インターネット(IP網)`に。
コンピュータ以外の機器も色々インターネットに接続する時代になった。

IP網というベースの上に、電話、テレビ、コンピュータ通信、インターネット等色んなものが載っている感じ。

制御システム系でも閉域網を組んだりするのでIPは活躍する。
最近は遠隔管理なんかも増えて、閉域網ではなくインターネット接続が拡がっている。

#### ICT, IT, OT
こういう関係。ITもOTも両方TCP/IPが大事。
```mermaid
%%{init:{'theme':'base','themeVariables':{'primaryColor':'#20b2aa','primaryTextColor':'white','primaryBorderColor':'#20b2aa','lineColor':'gray','textColor':'#6A7FABCC','fontSize':'20px'},'flowchart':{'nodeSpacing':80}}}%%

graph TD;
subgraph ICT
    A("IT: 情報技術")　-. "＋" .- B("ネットワーク")
end
C["OT:制御技術"]

style ICT fill: white, stroke:#20b2aa
```

## 6. 安全につなぐ時代
便利になった分、ウイルスなど**問題**も出てきた。
相互通信ができるということは向こうからやってくることもあるということ。

これまではつながったわーいだったけど、つながるだけで何かしらの危険があるという時代になり
安全であることが重要になった。

## 7. 人→モノ→コト
もともとは生産性の向上で始まった技術たちが、コトを生み出す時代になった。
第4時産業革命といったりもする。
```mermaid
%%{init:{'theme':'base','themeVariables':{'primaryColor':'#20b2aa','primaryTextColor':'white','primaryBorderColor':'#20b2aa','lineColor':'gray','textColor':'#6A7FABCC','fontSize':'20px'},'flowchart':{'nodeSpacing':80}}}%%

graph LR;
subgraph IIoT["Industrial IoT"]
    D["@製造工場"]
    subgraph IoT
        A("モノ")--"接続"-->B("インターネット")--"創造"-->C("コト")
    end
end

style IIoT fill: white, stroke:#20b2aa
style IoT fill: white, stroke:#20b2aa
```

こういったことを実現するのがTCP/IPという通信プロトコル。
エンジニアの知的生産術を読んでみた。

# 目的
情報をインプットしてアウトプットする練習のため、毎週本を読み理解したことや気になったことをまとめてみようと思い、投稿します。

# やる気を維持する方法について

エンジニアのやる気が出ない原因の一つとして、タスクが１つに絞り切れていないことを挙げている。

確かに、実体験として何か作業をするときには、TODOリストのようなものを作り、一つずつ消化しようとするときには自然とやる気が出てきている気もする。

また、西尾氏はタスクを一つに絞るために、まずとにかく気になることを書き出すことが非常に有効であると主張している。

こうすることで、「情報を集めるフェーズ」と「考えるフェーズ」を分離することができ、人間のストレスを減らせるとのこと。

結論、やる気が無くなりそうな時は、付箋などを利用して気になることを書き出しながら、タスクを一つに絞るとよいらしい。





# 参考
[エンジニアの知的生産術](https://www.amazon.co.jp/%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%AE%E7%9F%A5%E7%9A%84%E7%94%9F%E7%94%A3%E8%A1%93-%E2%94%80%E2%94%80%E5%8A%B9%E7%8E%87%E7%9A%84%E3%81%AB%E5%AD%A6%E3%81%B3%E3%80%81%E6%95%B4%E7%90%86%E3%81%97%E3%80%81%E3%82%A2%E3%82%A6%E3%83%88%E3%83%97%E3%83%83%E3%83%88%E3%81%99%E3%82%8B-WEB-PRESS-plus%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA/dp/4774198765/ref=asc_df_4774198765/?tag=jpgo-22&linkCode=df0&hvadid=295681864682&hvpos=&hvnetw=g&hvrand=14160155844230337892&hvpone=&hvptwo=&hvqmt=&hvdev=c&hvdvcmdl=&hvlocint=&hvlocphy=1028853&hvtargid=pla-523919656467&psc=1&th=1&psc=1)
LaravelにReact + TypeScript の開発環境を構築②

## この記事の目的
- LaravelとReactでTodoアプリを作成したときの備忘録
- ルーティング設定について
- Laravel9を利用しています
- React+TypeScriptとScssを追加しています。
- ここでは簡単なルーティングのみ
- [LaravelにReactやその他ライブラリ等インストールについてはこちら](https://qiita.com/pikimaru/items/062533c3cba6dbfe8f42)

## ルーティング
#### フロー
- React側でTOP画面（home）と　usersというページを作成する
- Laravelのルートを修正する

### React側でTOP画面（home）と　usersというページを作成
tsディレクトリ配下に`Router.tsx`を作成
```resources/ts/Router.tsx
import { BrowserRouter, Routes, Route } from "react-router-dom";
import { Home } from "./Home";
import { Users } from "./Users";

export const Router = () => {
    return (
        <BrowserRouter>
            <Routes>
                <Route path={`/`} element={<Home />} />
                <Route path={`/Users/`} element={<Users />} />
            </Routes>
        </BrowserRouter>
    );
};
```
```resources/ts/Home.tsx
import { Link } from "react-router-dom";

export const Home = () => {
  return (
    <>
      <h1 className='text-red'>Laravel React+Typescript環境構築</h1>
      <div>
        ユーザー一覧はこちら<Link to={`/users/`}>こちら</Link>
      </div>
    </>
  );
};
```
```resources/ts/Users.tsx
import { Link } from "react-router-dom";

export const Users = () => {
    return (
        <>
        <h1>ユーザー一覧ページ</h1>
        <div>
            <Link to={`/`}>ホームに戻る</Link>
        </div>
        </>
    );
};
```
```resources/ts/App.tsx
import React from 'react';
import { Router } from "./router";

const App = () => {
    return (
        <Router />
    )
}

export default App
```
#### Laravelのルートを修正
現状だと各ページ遷移時にブラウザを再読み込みするとNOT Foundになるの。
直接アクセスしても読み込まれるように修正する。`/`以外のルートを設定していないため
```routes/web.php
//　どのURLにアクセスしても１つのページindex.phpがレンダリングされるように設定します。
Route::get('{any}', function () {
  retrun view('index');
})->where(['any' => '.*']);

```
- /{any}に合致した時に、index.phpがレンダリングされる。(つまり/の後に何が来ても)
- where('any', '.*')ですべてのURLでヒットするようになる。
Android版Chromeで新しいタブにブックマーク一覧を表示

タイトルが長いですが見ての通りです。

AndroidのChrome系ブラウザでは新しいタブを開く際に読み込むページを指定できます(当然他のブラウザも同じでしょうが)。この時に、ブックマーク一覧を表示できないでしょうか？（パソコンだと普通にブックマークツールバー使いますがAndroidでできましたっけ？）

というわけで、やり方です。
モバイルのブックマークのURLは、chrome-native://bookmarks/folder/3 です(kiwiも同じ)。これを指定することにより、新しいタブでブックマーク一覧が表示できるようです。
k8s の実験（その３：pod の作成・削除）

[k8s の実験（その２：環境構築２）](https://qiita.com/intrajp/items/f1e20c4647da7c242126)のつづき。

Docker では、コンテナを作成するコマンドは、以下のようでした。

```bash
$ docker run myweberser --image=nginx
```

k8s では、以下のようなコマンドになります。

```bash
$ kubectl run mywebserver --image=nginx
pod/mywebserver created
```

コンテナのことを、pod というみたいですね。
pod の存在を確かめてみます。

```bash
$ kubectl get pods
NAME          READY   STATUS    RESTARTS   AGE
mywebserver   1/1     Running   0          90s
```

では、pod の中に入るのは、どうしたらよいのでしょうか。

Docker では、以下のようでした。

```
$ docker exec -it mywebserver bash
```

k8s では、以下のようになります。

```bash
$ kubectl exec -it mywebserver -- bash
/#
/# exit
```

以下のコマンドを実行するとどうなるでしょうか。

```bash
$ kubectl exec -it mywebserver -- ls -l /
total 80
drwxr-xr-x   2 root root 4096 Feb  8 13:00 bin
drwxr-xr-x   2 root root 4096 Dec  9 19:15 boot
drwxr-xr-x   5 root root  360 Feb 26 12:19 dev
drwxr-xr-x   1 root root 4096 Feb  9 04:36 docker-entrypoint.d
-rwxrwxr-x   1 root root 1616 Feb  9 04:36 docker-entrypoint.sh
drwxr-xr-x   1 root root 4096 Feb 26 12:19 etc
drwxr-xr-x   2 root root 4096 Dec  9 19:15 home
drwxr-xr-x   1 root root 4096 Feb  8 13:00 lib
drwxr-xr-x   2 root root 4096 Feb  8 13:00 lib64
drwxr-xr-x   2 root root 4096 Feb  8 13:00 media
drwxr-xr-x   2 root root 4096 Feb  8 13:00 mnt
drwxr-xr-x   2 root root 4096 Feb  8 13:00 opt
dr-xr-xr-x 171 root root    0 Feb 26 12:19 proc
drwx------   1 root root 4096 Feb 26 12:25 root
drwxr-xr-x   1 root root 4096 Feb 26 12:19 run
drwxr-xr-x   2 root root 4096 Feb  8 13:00 sbin
drwxr-xr-x   2 root root 4096 Feb  8 13:00 srv
dr-xr-xr-x  13 root root    0 Feb 26 12:19 sys
drwxrwxrwt   1 root root 4096 Feb  9 04:36 tmp
drwxr-xr-x   1 root root 4096 Feb  8 13:00 usr
drwxr-xr-x   1 root root 4096 Feb  8 13:00 var
```

では、pod の削除はどうやってやるのでしょうか。

Docker では、以下のようでした。

```bash
$ docker stop mywebserver
$ docker rm mywebserver
```

k8s では、以下のようになります。
一度、pod の存在を確認してから、削除してみます。

```bash
$ kubectl get pods
NAME          READY   STATUS    RESTARTS   AGE
mywebserver   1/1     Running   0          11m
$ kubectl delete pod mywebserver 
pod "mywebserver" deleted
$ kubectl get pods
No resources found in default namespace.
```

上記のとおり、Docker では、一度コンテナを停止する必要がありますが、k8s では、pod が走っていても、削除することが出来ます。

[K8S の実験（その４：node pool のアップグレード）](https://qiita.com/intrajp/items/f8ab00c8659fa0e1df13)につづく。
GA4のタグエラーの解決方法 "タグが適切に設定されていることをご確認ください"

# GA4のタグエラーの解決方法

GA4を導入する際に、以下のエラーメッセージが表示された場合の解決方法について紹介します。

> タグを実装してから 48 時間以上経過している場合は、タグが適切に設定されていることをご確認ください。

このエラーが表示された場合は、以下の手順を実行してください。

1. ウェブサイトにGA4のタグが正しく実装されていることを確認する。（別アカウントのgoogle tagと間違えていないか確認する。）
2. タグが正しくロードされていることを、ブラウザの開発者ツール（F12）で確認する。
3. もしタグが正しくロードされているのにも関わらず上記エラーが表示される場合は、<strong>\<head>タグの直後ではなく、\</head>タグの直前にタグを配置する</strong>ことを試してみる。
4. タグを配置した後、数分待ってから再度確認する。
list型オブジェクト参照の動作確認

# はじめに
Pythonでは、プログラム実行時、生成されたデータにオブジェクトIDという識別子が割り振られます。
オブジェクトIDは、各オブジェクトを区別できるように一意な数値によって表現されます。

本記事では、Pythonで使用されるオブジェクトの中でも、リスト型オブジェクトに焦点を当てて、オブジェクト参照の動作を確認します。
※本記事の最後に疑問も記載しているのでぜひご覧ください。


# 確認
## 検証1
まず、リスト型変数を作成し、オブジェクトIDを確認します。
```python
lst1 = [1,2,3]
lst2 = [1,2,3]

# 出力
print(id(lst1))
print(id(lst2))
```
- 結果
```python
4562150912  # lst1のオブジェクトID
4562745728  # lst2のオブジェクトID
```
変数lst1と変数lst2は、同じ値こそ格納されているものの、オブジェクトとしては別ものであるため異なるIDが割り振られています。

## 検証2
それでは、リストそのものと、そのリストを格納した変数ではどうでしょうか？
```python
lst1 = [1,2,3]

# 出力
print(id([1,2,3]))
print(id(lst1))
```
- 結果
```python
4376885184  # [1,2,3]のオブジェクトID
4376307136  # lst1のオブジェクトID
```
こちらも、[1,2,3]と変数lst1は別オブジェクトとして扱われています。

## 検証3
次は、リスト型の変数を別の変数に格納した場合はどうでしょうか？
```python
lst1 = [1,2,3]
lst2 = lst1

# 出力
print(id(lst1))
print(id(lst2))
```
- 結果
```python
4440778240  # lst1のオブジェクトID
4440778240  # lst2のオブジェクトID
```
変数lst1と変数lst2のオブジェクトIDが等しくなりました。

## 検証4
では、同じオブジェクトIDを参照している変数の値を変更した場合はどのような処理になるでしょうか？
```python
#検証3の続き
lst1.append(4)

# 出力
print(id(lst1))
print(id(lst2))
```
- 結果
```python
4368066048  # lst1のオブジェクトID
4368066048  # lst2のオブジェクトID
```
両変数とも同じオブジェクトIDになりました。
即ち、値の出力も等しくなります。
```python
# 出力
print(lst1)
print(lst2)

# 結果
[1, 2, 3, 4]  # lst1の値
[1, 2, 3, 4]  # lst2の値
```

# まとめ
リスト型の変数は、リストそのものを代入した場合、新規のオブジェクトが生成されたものとして処理されます。
対して、リスト型変数を代入した場合、代入したリスト型変数を参照することになります。
　結果、両変数ともに同じオブジェクトとして扱われ、出力した際の値も等しくなります。

ちなみに、リスト型変数をコピーして異なるオブジェクトを生成したい場合、copy()メソッドを使用します。
```python
lst1 = [1,2,3]
lst2 = lst1.copy()

# 出力
print(id(lst1))
print(id(lst2))

# 結果
4567344576  # lst1のオブジェクトID
4567922624  # lst2のオブジェクトID
```

# 疑問
検証の総括として、各検証の内容をまとめて実行してみたところ、
```python
lst1 = [1,2,3]
lst2 = lst1

# 出力
print(id([1,2,3]))
print(id(lst1))
print(id(lst2))

# 結果
4546345344  # [1,2,3]のオブジェクトID
4545750528  # lst1のオブジェクトID
4545750528  # lst2のオブジェクトID

```
と想定通りの値になりました。
しかし、続けて以下を実行したところ、
```python
lst2 = [1,2,3]

# 出力
print(id(lst2))

# 結果
4546345344  # lst2のオブジェクトID
```
というように、[1,2,3]のオブジェクトIDと変数lst2のオブジェクトIDが等しくなりました。
これは、何回同じ処理を実行しても両オブジェクトIDが等しくなるという結果でした。

ためしに、つづけて以下を実行したところ、
```python
lst3 = [1,2,3]

# 出力
print(id(lst3))

# 結果
4546601280  # lst3のオブジェクトID
```
といったように、続けて生成した変数lst3では異なるオブジェクトIDが割り振られていました。

何らかの法則があるのでしょうか。。。
Queryのeachメソッドなどに使用するコールバック関数でアロー関数を使用するには注意が必要

jQueryで要素でeachメソッドを使用する際に、コールバック関数にアロー関数を使用していたら、問題があったので記事を書きたいと思います。
# アロー関数内では$(this)がwindow要素になってしまう
コールバック関数に`function(){}`を使用し、関数内で`$(this)`と書くと、順番に取り出す要素を取得することができる。
```html
<div>div1</div>
<div>div2</div>
<div>div3</div>
```
```javascript
$('div').each(function(){
    console.log($(this)); //div要素が一つづつ出力される
});
```
しかし、コールバック関数をアロー関数にした場合、`$(this)`がwindow要素になる。
```javascript
$('div').each(() => {
    console.log($(this)); //window要素が出力される
});
```

# なぜこうなるのか？
アロー関数は、callなどのメソッドを使用すると、thisの指定ができないようです。
参考: https://qiita.com/suin/items/a44825d253d023e31e4d

このことから、eachなどのメソッドでは、内部でcallなどのメソッドでthisに順番の要素を指定して、コールバック関数を使用しているため、コールバック関数をアロー関数で指定すると、thisが指定できず、グローバルに定義されたthisを使用してしまうために起きている........のかもしれない。
DeepL APIでGoogleスプレッドシートの日本語を英語に翻訳するスクリプト

# やりたいこと
A列に羅列した日本語をインプットとして、DeepL APIによる英語翻訳結果をB列に出力する。
C列はGoogle翻訳関数(GOOGLETRANSLATE)によるもの。これでもいいが、DeepLのほうがより自然な表現になるためDeepLを使いたい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228134/675a8c59-ec40-2916-3d5a-f498b8c66e2b.png)

# コード
```javascript:コード.gs
// DeepL APIで使用する認証キー
const apiKey = PropertiesService.getScriptProperties().getProperty('DEEPL_KEY');

/**
 * DeepL翻訳結果を出力する処理。
 * A列の日本語を翻訳し、B列へ英語で出力する。
 */
function translateDeepLja2en() {  
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  const numRows = sheet.getLastRow() - 1;
  const sourceRange = sheet.getRange(2, 1, numRows, 1);
  const targetRange = sheet.getRange(2, 2, numRows, 1);
  const sourceValues = sourceRange.getValues().flat();
  const targetValues = sourceValues.map(value => {
    if (value === "") {
      return "";
    } else {
      const translated = translateWithDeepL(value, "JA", "EN");
      return translated.text;
    }
  });

  targetRange.setValues(targetValues.map(value => [value]));
}

function translateWithDeepL(text, sourceLang, targetLang) {  
  const apiUrl = `https://api-free.deepl.com/v2/translate?auth_key=${apiKey}&text=${encodeURIComponent(text)}&source_lang=${sourceLang}&target_lang=${targetLang}`;
  const response = UrlFetchApp.fetch(apiUrl);
  const result = JSON.parse(response.getContentText());
  return result.translations[0];
}

```
# スクリプト以外の設定
`const apiKey = PropertiesService.getScriptProperties().getProperty('DEEPL_KEY');`で値を取れるようにスクリプトエディタのプロジェクトの設定にある「スクリプトプロパティ」へDeepL API の認証キーを設定する。
プロパティ名:DEEPL_KEY
値：[DeepLアカウントページの認証キー](https://www.deepl.com/ja/account/summary)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228134/f77f6ce2-b7b6-7a1a-80bd-eb0b4e0b4b4a.png)


# DeepL翻訳処理を自作関数にした場合の懸念事項
GOOGLETRANSLSTE関数のように、スプレッドシートで利用できる形の関数にすると想定以上にAPIを叩き、DeepL API Freeの上限値50万文字への到達が早まるため避けている。
画面更新やちょっとしたタイミングで画面が更新されるたびに関数が動作している。
自作関数版のコードはDeepLがリポジトリにて公開している。
https://github.com/DeepLcom/google-sheets-example
K8s の実験（その２：環境構築２）

[k8sの実験（その１：環境構築１）](https://qiita.com/intrajp/items/8f4841223436afe7772f)のつづき

Fedora がローカルマシンとなりますので、以下のページを参考にして、kubectl をインストールします。

（参考）
https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/

```bash
cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-\$basearch
enabled=1
gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
EOF
sudo yum install -y kubectl
```

kubectl コマンドが使えるかどうか、やってみます。

```bash
$ kubectl 
```

ヘルプが表示されたので、使えるようです。
以下のコマンドを実行してみます。

```bash
$ kubectl get nodes
The connection to the server localhost:8080 was refused - did you specify the right host or port?
```

DigitalOcean からダウンロードした、設定ファイルを読み込む必要があるようです。

```bash
$ kubectl --kubeconfig "<path to yaml file>" get nodes
NAME                        STATUS   ROLES    AGE   VERSION
xxxx-worker-node-qbbfo   Ready    <none>   34m   v1.25.4
```

いちいち、--kubeconfig オプションをつかうのも面倒です。
以下のようにすることで、オプションを追加しなくても node のじょうたいが確認できるようになります。

```
$ mkdir ~/.kube
$ cp ~/k8s/i<path to yaml file> ~/.kube/config
```

--kubeconfig オプションを追加せずにコマンドを実行してみます。

```bash
$ kubectl get nodes
NAME                        STATUS   ROLES    AGE   VERSION
xxxx-worker-node-qbbfo   Ready    <none>   40m   v1.25.4
```

[K8S の実験（その３：pod の作成・削除）](https://qiita.com/intrajp/items/d569d44e1635b5d29648)につづく。
【Android】MediaPlayerで音を鳴らす【Kotlin】

# はじめに
前回別の方法でアプリ内で音を鳴らす方法を記事にしているのでそちらも観ていってください

https://qiita.com/Tsubasa12/items/a8bec7f5be4ebce9d033

また、準備の方法はそちらと同じですので、割愛させていただきます

# ボタンを押したら音が鳴るようにする
上述の記事と同じようにボタンを押したら音が鳴るようにしていきます

```MainActivity.kt
        val button: Button = findViewById<Button>(R.id.button)　　// 1

        val mediaPlayer: MediaPlayer                        // 2

        mediaPlayer = MediaPlayer.create(this, R.raw.sound) // 3

        mediaPlayer.isLooping = true                        // 4
        mediaPlayer.seekTo(0)                               // 5

        button.setOnClickListener {                         // 6
            mediaPlayer.start()
        }

```
それぞれ解説していきます。
1.Buttonの ID を取得
2.MediaPlayerオブジェクトを作成
3.　.createで流したい音源のリソースを変数に詰める
4.ループの設定
5.再生位置を０に指定
6.ボタンを押された時の処理にmediaPlayer.start()することで　再生

# 参考

https://developer.android.com/guide/topics/media/mediaplayer?hl=ja

https://techbooster.org/android/application/267/

http://www.nakamura-shoten.com/software/androidmemo/mediaplayer.php
KiwiやAndroid版Chromeのタブレットモード

＊画像がないためだいぶわかりにくいかもしれませんが、文字で画面を思い浮かべてもらえばです。

Androidタブレットは使っているが長らくスマホを使っていなかった私です。スマホのChromeなどではタブが直接表示されず、数字の書いてあるボタンをタップによりタブ一覧が表示されますね(それを昨日知りましたｗ)。画面の小さいスマホなら確かにそれが最適解かもしれませんが、タブレットの場合はパソコンと同様に普通にタブが表示されていた方がいいのは想像できると思います。

最近さわったタブレット。Chromeがなんとスマホと同様のタブ表示形式、Kiwiも同様。拡張のつかえないブラウザはブラウザではないと思っている私なので、Kiwi Browserは必須なのです。あれ、kiwiってアプリの紹介にTablet Modeとか書いてタブがあるUIが表示されているような。どこをいじれば、そのタブレットモードってやつになるのか？
いろいろ調べた結果、答えは意外で、かつ単純でありました。

☆-☆-☆-☆-☆-☆-☆-☆-☆-☆-☆-☆-☆-☆-☆-☆-☆
(Android9の場合。他のバージョンでも似た感じか)
「　設定→ディスプレイ→詳細設定→表示サイズ→[アイテムのサイズをある程度小さくする]　」
なんとOS側の設定を変えることにより、KiwiやChrome等ブラウザ側がTablet/Phoneのモードを変えるという仕様である。
☆-☆-☆-☆-☆-☆-☆-☆-☆-☆-☆-☆-☆-☆-☆-☆-☆
.
.
.
.
.
.
.
.
.
.
これ、みんな知っていることなんでしょうか？AndroidとかChromeとかタブ表示されないとかタブレットモードとかいろいろ検索して全く該当する記事が現れなかったけど、こういうケースは稀なのかそれとも検索エンジンが超ｘ100糞なのかどっちなのでしょうか...？
JUnit5 + MockitoでCalendar.getInstance()をモックする

## 概要
JUnit5とMockitoを使った、Calendar.getInstance()のモックの仕方について、
日本語/英語両方で調べてもなかなかヒットしなかったので記事化&サンプル用のソースを書いておきました。

## 1. `pom.xml`を修正する

### 1-1. `<properties></properties>`配下に下記を追加します。
```xml
<mockito.version>4.11.0</mockito.version>
```

### 1-2. `<dependencies></dependencies>`の中に下記を入れます。

```xml
    <dependency>
      <groupId>org.mockito</groupId>
      <artifactId>mockito-core</artifactId>
      <version>${mockito.version}</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.mockito</groupId>
      <artifactId>mockito-inline</artifactId>
      <version>${mockito.version}</version>
      <scope>test</scope>
    </dependency>
```
https://github.com/NIRANKEN/calendar-get-instance-test/blob/main/pom.xml#L38-L49

## 2. 実際にテストコードを記載する

### 実装コード
```java
package com.example;

import java.text.SimpleDateFormat;
import java.util.Calendar;

public class DateGetter {
  public String get() {
    SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
    return sdf.format(Calendar.getInstance().getTime());
  }
}
```
https://github.com/NIRANKEN/calendar-get-instance-test/blob/main/src/main/java/com/example/DateGetter.java

### テスト用のコード
```java
package com.example;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mockStatic;

import java.util.Calendar;
import java.util.GregorianCalendar;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
import org.mockito.Mockito;

public class DateGetterTest {
  @DisplayName("Calendar.getInstance()をモックするテストだよ")
  @Test
  void testGet() {
    Calendar cal = new GregorianCalendar(2023, 1, 26, 11, 12, 13);
    try (MockedStatic<Calendar> mockedCalendar = mockStatic(Calendar.class, Mockito.CALLS_REAL_METHODS)) {
      // Arrange
      mockedCalendar.when(() -> Calendar.getInstance()).thenReturn(cal);
      // Act
      String result = new DateGetter().get();
      // Assert
      assertEquals("20230226111213", result, "日時の期待値と結果が間違ってるよ。");
    }
  }
}
```
https://github.com/NIRANKEN/calendar-get-instance-test/blob/main/src/test/java/com/example/DateGetterTest.java

### 実行結果キャプチャ
(左ペイン:実装)(右ペイン:テスト)で、テスト通ったことを確認しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171582/85e90377-f7c2-e1ba-a813-1e1d13aede68.png)
【Vue.js/Reactとは】 概要

# JSフレームワークのトレンド

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2784589/4d01bb66-2d23-3c5a-ed1f-4bebc3ba6f20.png)


# Vue.js

JSのフレームワーク
Ajax(非同期通信)リアルタイムで動く

### メリット

コンポーネント分割
&emsp;メンテしやすい

SPA
&emsp;ユーザビリティ向上。読み込みが速い。

プログレッシブ
&emsp;段階的に拡張できる
| 目的 |ページ構成 | 開発環境 |
| --- | --- | --- |
| jQueryの代わり | MPA(マルチページ) | CDN |
| SFC メンテしやすく| MPA | Data2-3 | VueCLI |
| ユーザビリティ| SPA(シングルページ) | VueCLI+VueRouter |
| ユーザビリティ+状態管理 | SPA | VueCLI+VueRouter+Vuex |

### バージョン

2014/02 Vue.js 0.8
2015/04 Laravelで採用
2016/10 Vue.js 2
        OptionsAPI
2020/09 Vue.js 3
        CompositionAPI(大規模対応 + TypeScript対応)
2021/08 Vue.js 3.2
        script setup(CompositionAPIをシンプルに)

# React
コンセプト「Single Source of Truth」
意味:データを保管、管理する場所は一つ。
一つのコンポーネントがデータを一元管理し、管理を容易にする。

Top-down Date Flow
コンセプトを実践するためのワークフロー。
S3でブロックパブリックアクセスをオフにしたが、確認できない時の対処法

タイトル通り、S3に保存した画像がブロックパブリックアクセスをオフにしたにも関わらず、以下のような事象となったのでメモを残します。

①公開しようとしたWordPress上で確認できない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823945/219d1561-bb6b-9397-a2ca-1865a2c08200.png)

②ブラウザから見れない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823945/9b318652-71b2-c860-1c46-1eef0372becc.png)

# 前提
・S3への保存はできており、IAMユーザーでは閲覧可能。
→IAMユーザー周りの権限問題ではない？
・ACLの有効化はしていなかった。
→【解決手順】の①で実施

# 原因
「ブロックパブリックアクセスをオフ」にするだけでは不十分。以下文言からも「可能」なだけで事実公開されているわけではない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823945/07f3bc36-de25-d3e4-dc08-25ee0c7024f3.png)

# 解決手順
①「オブジェクト所有者を編集」からACLの有効化（していない場合）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823945/e46f5916-7957-af45-d4be-fcea00b2ea00.png)
②公開したい「オブジェクト」をチェック→「アクション」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823945/e34168cd-d492-e5dc-a1d5-91cf54777b5d.png)
③「ACLを使用して公開する」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823945/17dcfe2e-4386-5199-a7dd-7c5565cdc357.png)
④「公開する」を押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823945/c5ac5fb3-8f1d-4d5a-1eb6-1e3da9229d06.png)

# 最後に
～オブジェクトは公開することができます～
→この言葉ややこしすぎる。。

・何か修正ありましたら、コメントください:open_hands:
Databricks SQL Connector for Pythonを試してみる

こちらのコネクターを実際に試してみます。

https://docs.databricks.com/dev-tools/python-sql-connector.html

[Databricks SQL Connector for Python](https://github.com/databricks/databricks-sql-python)はDatabricksクラスターやDatabricks SQLウェアハウスでSQLコマンドを実行するために、Pythonコードを使用できるPythonライブラリです。[pyodbc](https://docs.databricks.com/dev-tools/pyodbc.html)のようなPythonライブラリと同じように簡単にセットアップ、使用することができます。

# 要件

- Python >= 3.7、Python <=3.11が稼働している開発用マシン。
- 既存の[クラスター](https://qiita.com/taka_yayoi/items/c5d99cd77fe4bfcf69f0)あるいは[SQLウェアハウス](https://qiita.com/taka_yayoi/items/23d7789198c2dcd66381)。

# 準備

以下ではSQLウェアハウスを使用するケースを説明します。

1. SQLウェアハウスの**接続の詳細**で**サーバーのホスト名**と**HTTPパス**をコピーしておきます。
![Screenshot 2023-02-26 at 20.06.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/3b5bb36a-29c7-fd36-1333-817039d28fe9.png)
1. [パーソナルアクセストークン](https://qiita.com/taka_yayoi/items/f5493a4169e95e1a7a61#%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E3%81%AE%E3%83%91%E3%83%BC%E3%82%BD%E3%83%8A%E3%83%AB%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%83%88%E3%83%BC%E3%82%AF%E3%83%B3)をコピーしておきます。
1. 開発用マシンで`pip install databricks-sql-connector`を実行してコネクターをインストールします。

# コネクターによる接続

1. ターミナルで環境変数を設定します。

    ```bash:Bash
    export DATABRICKS_HOST=<Databricksワークスペースのホスト名>
    export DATABRICKS_HTTP_PATH=<上でコピーしたHTTPパス>
    export DATABRICKS_TOKEN=<上でコピーしたパーソナルアクセストークン>
    ```

1. VS Codeを起動します(Python実行環境であれば何でも構いません)。

    ```bash:Bash
    code .
    ```

1. 以下のPythonコードを実行します。

    ```py:Python
    import os
    from databricks import sql
    
    with sql.connect(server_hostname = os.getenv("DATABRICKS_HOST"),
                     http_path       = os.getenv("DATABRICKS_HTTP_PATH"),
                     access_token    = os.getenv("DATABRICKS_TOKEN")) as connection:
    
      with connection.cursor() as cursor:
        cursor.execute("SELECT * FROM default.diamonds LIMIT 5")
        result = cursor.fetchall()
    
        for row in result:
          print(row)
    ```

1. クエリー結果が表示されます。
![Screenshot 2023-02-26 at 20.12.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/451da3f8-b4b9-a872-079f-c8ca7e305871.png)

:::note
**注意**
`nodename nor servname provided, or not known`や`Error during request to server`のようなエラーが発生する場合には、環境変数`DATABRICKS_HOST`で指定したホスト名に`https://`や末尾の`/`が含まれていないことを確認してください。
:::

### Databricks 無料トライアル

[Databricks 無料トライアル](https://databricks.com/jp/try-databricks)
【GitHubActions】PR時にマージ元ブランチ名を利用してJobの実行を制御する

# やりたいこと
マージ元ブランチ（`headブランチ`）のブランチ名を元にGitHubActionsのJob制御を行いたい。
![Cursor.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146452/3f02ddad-2bda-2b10-8744-30d8112b2232.png)

# やり方
GithubActionsの[`if`式](https://docs.github.com/ja/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idif)を用いて、特定ブランチのみJobの実行有無を制御することが可能です。

下記、PR時のみ実施するWorkFlowの`test`Jobの実施をブランチ名で制御するサンプルです。

```
name: sample-job

on:
  pull_request:

jobs:
  test:
    if: |
      # PRが`release`,`test`以外の場合だけ、runs-on以下の処理を行う
      !startsWith(github.head_ref, 'release')
      && !startsWith(github.head_ref, 'test')
    runs-on: ubuntu-latest
    steps:
      - name: echo only PR
        run: echo "*** This is PR!! ***"
```

## `if`式を利用する際の注意点
`if`式内で利用する式は`${{}}`を省略可能です。
`&{{}}`を付与しても動作しますが、個人的には見通しが悪くなるので省略することをオススメします。
> `if` 条件の中で式を使う際には、式構文(`${{ }}`)を省略できます。これは、GitHub が `if` 条件を式として自動的に評価するためです。 詳細については、「式」を参照してください。
（出典: [Workflow syntax for GitHub Actions](https://docs.github.com/ja/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idif)）

また、if条件を複数設定する際は `|` を用いて複数行設定すると保守しやすくなるのでオススメです :smile: 

```
# 下記のifはどちらも同じ挙動になります

# 一行のif
if: !startsWith(github.head_ref, 'release') && !startsWith(github.head_ref, 'test')

# 複数行のif
if: |
  !startsWith(github.head_ref, 'release')
  && !startsWith(github.head_ref, 'test')
```

# やってみた所感
当初は `branches-ignore` を用いて特定ブランチでは処理を行わない処理を実現しようと思ったのですが、いくら `branches-ignore` の設定を行っても思った挙動にならず「これ、どうやってやんねん:angel:」と絶望していました。。。
一通り切り分けをした結果 `branches-ignore` の挙動が `baseブランチ` を対象としていることに気付き、 `if` 式を利用して `headブランチ` の名前を指定するアプローチに切り替えて、なんとかやりたいことが実現できました。 

何かを実現したいときは「何を」「どうしたいか」を考え、ドキュメントの文言を読み間違えないようにしなくてはならないと痛感しました。。。
-> 公式ドキュメントの「ブランチの除外」という文言ばかりを見ていて `branches-ignore` の本来の役割に気づけなかった

# 参考URL
- Actionsの挙動
    - [GitHub ActionsのWorkflow実行内でRef（Branch）名を取得する方法](https://dev.classmethod.jp/articles/how-to-get-a-ref-branch-within-a-workflow-execution-in-github-actions/)
    - [How to write multi-line condition in if](https://github.com/orgs/community/discussions/25641)
    - [Workflow syntax for GitHub Actions
 | `on.<pull_request|pull_request_target>.<branches|branches-ignore>`](https://docs.github.com/ja/actions/using-workflows/workflow-syntax-for-github-actions#onpull_requestpull_request_targetbranchesbranches-ignore)
- YAMLの設定
    - [YAMLで複数行テキストを書きたい時のあれこれ](https://qiita.com/jerrywdlee/items/d5d31c10617ec7342d56)
    - [What is the use of the pipe symbol in YAML?](https://stackoverflow.com/questions/15540635/what-is-the-use-of-the-pipe-symbol-in-yaml)
- 挙動のテストしてみたPR
    - [特定のブランチだけGitHubActionsを実施しない方法検証](https://github.com/watame/github_action_test/pull/8)
Laravel学習の個人的備忘録①

### Laravelで新しくレシピ保存サイトを作ろうとした話。

まず
環境はMAMP
第一歩として

htdocsディレクトリ内にrecipeディレクトリを作成した。
Composerを用いて
そのディレクトリの中にLaravelをインストールしようとしたが

composer require laravel/breeze --dev
と
composer require laravel/breezeの違いが分からず
違いについて調べていた。

### --devの有無は今後調べる。


breezeをインストールした後
フォントが崩れている原因：package.jsonには
Laravel-mixを指定しているが
Componentファイルでviteが使われているため。
### 具体的なその対策は
・layouts/app.blade.php
・layouts/guest.blade.phpファイルの

```php
<!-- Scripts -->
@vite(['resources/css/app.css', 'resources/js/app.js'])
```
の箇所を

```php
<!-- Styles -->
<link rel="stylesheet" href="{{ asset('css/app.css') }}">

<!-- Scripts -->
<script src="{{ asset('js/app.js') }}" defer></script>
```
に変更するとフォントが直った。
K8s の実験（その１：環境構築１）

Digital Ocean で契約をして、Singapore に worker node 1 でクラスタを作りました。

60 日間、200ドルのクレジットがついているようですし、せいぜい、12ドルだけの契約にしたので、安心です。

Paypal で、$5 だけ払って、契約完了です。

Resources タブをクリックすると、クラスタがつくられているようです。

Overview タブに戻ります。

Download Config File をクリックします。

yaml ファイルがダウンロードできました。

ここで、以下の行に注目します。

```bash
server: https://xxx.k8s.digitalocearn.com
token: xxxxxxxxxxxxxxx
```
[K8s の実験（その２：環境構築２）](https://qiita.com/intrajp/items/f1e20c4647da7c242126)につづく。
Gitで「.DS_Store」を無視する設定を行う

Gitの操作時に出てくる`.DS_Store`が出てこないようにする方法です。

 ~~1\. ホームディレクトリに移動~~
 ~~私のMacBookの場合、`/Users/me`になります。~~

 ~~2\. 以下のコマンドを実行~~
```
$ mkdir -p ~/.config/git
```

 ~~3\. 以下のコマンドを実行~~
```
echo '.DS_Store' >> ~/.config/git/ignore
```

 ~~4\. 以下のようになっていればOKです。~~

:::note
追記
誤りがあったので修正します。現在調査中です。
:::


 ~~これで、`git status`や`git add`したときに出てくる`modified:   .DS_Store`がなくなります。~~

### 参考サイト
[すべてのリポジトリで .DS_Store を gitignore する方法](https://zenn.dev/phi/articles/gitignore-global-ds-store)
AWS WAFについて

# はじめに
AWS WAFについて説明していきます。
結論だけ知りたい方は「まとめると」をご確認ください。

# そもそもWAFとは
AWS WAFの話をする前に一般的なWAF(Web Application Firewall)について説明します。
WAFとは、SQLインジェクションやXSS攻撃(クロスサイトスクリプティング)などの脅威から
Webアプリケーションを保護する働きがあります。

# AWS WAFとは
マネージド型のWebアプリケーションファイアウォールで、可用性低下、セキュリティ侵害、
リソース過剰消費や、一般的なWeb脆弱性などから**Webアプリケーションを保護**します。
OSI参照モデルでいうと、第7層（アプリケーション層）を防御します。さらに一般的なファイア
ウォールとは異なり、データの中身をアプリケーションレベルで解析できるのが特徴です。

また下記AWSサービスと組み合わせて使います。
- CloudFront
- ALB（Application Load Balancer）
- API Gateway

# ランニングコスト
ほかのWAF製品は初期費用で数百万円かかる場合もあるが、AWS WAFは初期費用がなく
ランニングコストも月20ドル程度で使用できるみたいです。

# 防御できる攻撃
下記脅威からWebアプリケーションを保護します。
- SQLインジェクション攻撃
- クロスサイトスクリプティング攻撃
- OSコマンドインジェクション攻撃
- DDoS攻撃

# WAF定義書について
AWS WAFは、最初からWAF定義が設定されている訳ではありません。
アプリケーションのトラフィック許可やブロックは、ユーザーで自身でWAFを定義する必要があります。
なのでWAF定義の経験がないユーザーは、サードパーティが提供しているWAF定義を利用することができます。

# AWS Shieldとの違い
AWS ShieldはDDoS攻撃に特化しておりL3&L4(スタンダードプラン)、L7(アドバンスプラン)で働きます。
AWS WAFの場合は、上記説明にもある通りL7を対象としており、SQLインジェクション、XXS攻撃等からアプリケーションを保護します。

AWS Shieldの詳細は、下記Qiita記事にてまとめたのでご参考ください。
https://qiita.com/mtn_kt/items/2fba83cd981cbefb58ae

# まとめると
- マネージド型のWebアプリケーションファイアウォール
- L7(アプリケーション層)を保護する
- SQLインジェクション、XXS、OSコマンドインジェクション攻撃、DDoS攻撃から保護する
- データの中身をアプリケーションレベルで解析できる
- ランニングコストが安い
- CloudFront、ALB、API Gatewayと組み合わせて使用する
- WAF定義は初期時未設定
- WAF定義はユーザー自身で定義する or サードパーティを利用する

# 最後に
つらつらとAWS WAFについてまとめました。
ご参考になれば幸いです。

# 参考サイト
[https://www.wafcharm.com/jp/blog/aws-waf-vs-aws-shield-for-beginners/](https://www.wafcharm.com/jp/blog/aws-waf-vs-aws-shield-for-beginners/)
[https://dev.classmethod.jp/articles/fully-understood-aws-waf-v2/](https://dev.classmethod.jp/articles/fully-understood-aws-waf-v2/)
[https://qiita.com/miyuki_samitani/items/995b449f012953a5e0d1](https://qiita.com/miyuki_samitani/items/995b449f012953a5e0d1)
whileループの(条件)で変数を宣言してもええんやで


```javascript
const regexp = RegExp('foo[a-z]*','g');
const str = 'table football, foosball';
let match;

while ((match = regexp.exec(str)) !== null) {
  console.log(`Found ${match[0]} start=${match.index} end=${regexp.lastIndex}.`);
  // expected output: "Found football start=6 end=14."
  // expected output: "Found foosball start=16 end=24."
}
```

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/matchAll

でも、whileループの(条件)で`var` `let` `const`は使えへん

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/2dddaa1f-915e-205e-49ff-9bedc5f80407.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/b2515906-0881-8970-1aec-f02772762eec.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/fa0f7ae7-19f2-2665-cf12-11235fa86aa7.png)
Djangoスタートアップ その7（テンプレート拡張編）

### base.htmlの作成
```
project
└───templates
    └───myApp
            base.html
            post_list.html
```
base.htmlはひな形
`{% block content %}`～`{% endblock %}`までをほかのtemplateファイルで実装する

```html:project/template/appName/base.html
<body>
    <div class="page-header">
        <h1><a href="/">Django Girls Blog</a></h1>
    </div>
    <div class="content container">
        <div class="row">
            <div class="col-md-8">
            {% block content %}
            {% endblock %}
            </div>
        </div>
    </div>
</body>
```


```html:project/template/appName/post_list.html
{% extends 'blog/base.html' %}★base.htmlを読み込み

{% block content %}★ひな形内のみ記述
    {% for post in posts %}
        <div class="post">
            <div class="date">
                {{ post.published_date }}
            </div>
            <h2><a href="">{{ post.title }}</a></h2>
            <p>{{ post.text|linebreaksbr }}</p>
        </div>
    {% endfor %}
{% endblock %}
```
### 参考記事
https://tutorial.djangogirls.org/ja