OmniAICreator/Qiita-1.07M huggingface dataset:
Pythonでwebサイトの構築　Part1 Dockerを利用した環境構築

<h1>1 ,はじめに</h1>
<p>本記事では、Pythonを用いたwebサイトの実装を行っています。</p>
ローカル環境で簡単なブログサイトを作成することでサーバーサイドで行われていることや、フロントエンドへの反映など基本的な知識の紹介を行います。

ソースコードは[GitHub](https://github.com/TakuyaNakahara-prg/myblog/tree/master)に記載しています。

<h2>環境構築</h2>
<p>まず初めにするべきこととしてPython(Django)を正常に動作させるための環境をローカルに作成する必要があります。</p>
<h3>前提</h3>

```Python:実行OS
Windows11
・性能
CPU : Corei7-11世代
GPU : Intel iris(純正グラフィックス)
メモリ : 16GB
SSD : 512GB
※webサイト構築をプログラミングで行うには最低でもCore i5以上かつメモリ8GB以上が望ましいです。
```
```Python:環境構築
本記事ではDockerを利用して仮想環境で開発環境の構築をしました。
Dockerを使う理由としては実際の開発現場を想定して行いたかったからです。
※pythonを用いるため仮想環境venvやAnacondaを使ってもOKです。
```
<h3>Dockerを用いた環境構築</h3>
<p>ここから具体的なDockerを用いた構築を行います。</p>
<p>ここではDokerのインストールは行っているものとします。</p>
ディレクトリ構成は以下のようにします。

```Python:ディレクトリ構成
/Desktop/blog_app/

ここではDesktop内に今回作成するサイトのプログラムを書いていこうと思います。
そのためディレクトリに関しては任意の場所に作成してください。

作成したディレクトリ内に以下のファイルを作成、追加してください。
blog_app/
        ├ Dockerfile
        ├ docker-compose.yml
        └ requirements.txt
```
これらの3つのファイルの中身について見ていきます。

```Python:docker-compose.yml
version: '3'
services:
  db:
    image: postgres
    ports:
      - "5432:5432"
    volumes:
      - ./db_data:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=postgres
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
  web:
    build: .
    command: python3 manage.py runserver 0.0.0.0:8000
    volumes:
      - .:/code
    ports:
      - "8000:8000"
    depends_on:
      - db
```
※ここでは実験的にPsotgresqlの環境を構築していますがDajngoプロジェクト立ち上げ時にSQLite3というデータベースが自動で構築されるので今回はそちらを利用します。

```Python:Dockerfile
FROM python:3
ENV PYTHONUNBUFFERED 1
RUN mkdir /code
WORKDIR /code
COPY requirements.txt /code/
RUN pip install -r requirements.txt
COPY . /code/
```

```Python:requirements.txt
Django==2.2.17
django-bootstrap4==2.3.1
```
これらのファイル作成ができたら次はDjangoのプロジェクト、サーバーの開始です。

<h2>Djangoのプロジェクト作成</h2>

docker-composeコマンドを利用し上述したファイルの条件通りの環境(Docker コンテナ)を構築します。

```Python:ターミナル
docker-compose run web django-admin.py startproject [project_name] .
※本記事ではproject_nameをblogとします。
```
上記コマンドを実行するとblog_appディレクトリ内に以下のようなプロジェクトファイルが生成されます。

```Python:
blog_app/
        ├ manage.py
        └ blog(project_name)/
            ├ __init__.py
            ├ settings.py
            ├ urls.py
            ├ asgi.py
            └ wsgi.py
```
<p>ここまででコンテナの作成およびDjangoプロジェクトの作成は完了です。</p>
次はコンテナを起動しDjangoのスタートページを表示してみましょう。

<h2>Djangoサーバー開始</h2>
<p>blog_appディレクトリにおいてターミナルで以下のコマンドを実施し、コンテナを起動してください。</p>

```Python:ターミナル
docker-compose up
```
以下のようなログが表示されると成功です。

```Python:ターミナル
blog_app-web-1  | Django version 2.2.17, using settings 'blog.settings'
blog_app-web-1  | Starting development server at http://0.0.0.0:8000/
blog_app-web-1  | Quit the server with CONTROL-C.
```
下から２行目のhttp://0.0.0.0:8000 にブラウザからアクセスしてみましょう。
Djangoスタートページが表示されれば成功です。
![django31_welcome.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402159/ed78a835-403f-bfb4-99fe-9c122cf728af.png)

はじめは英語表記になっていますがsettings.pyを以下のように変更すれば日本語表記になります。

```Python:settings.py
#settings.pyの112行目あたりに記載
LANGUAGE_CODE = 'ja'#日本語表記

TIME_ZONE = 'Asia/Tokyo'#タームゾーンを東京に変更
```
ここまでが環境構築編になります。
[次回から実際にblogサイトの構築編](https://qiita.com/T_gdmuy/items/7dbde3dcd9388aab7d57)に入ります。
Android アプリが使える Amazon アプリストアを入れてみた（けどすぐ消した）

全然使えなかったのでメモ程度に。

# Windows11 で Android アプリが利用可能に

Windows11 で Android アプリが使えるようになったとニュースになってたので、使ってみようと思い Amazon アプリストアを入れてみました。
Microsoft ストアで「Amazonアプリストア」で検索すると出てきます。
インストールには、再起動が必要です。

# いつもの問題が

使える Android アプリがまだ全然ないので Android アプリの動作自体は試さなかったのですが、例によって VirtualBox が使えなくなりました。
Amazon アプリストアもバックボーンとして Windows Subsystem for Android というものが使われているようで、要するに Hyper-V が基盤として使われているんじゃないですかね。
昔からこれが厄介で、 VirtualBox や VMWare Player といった別の仮想化ソフトを入れていると動かなくなってしまいます。
WSL2 ではこの問題が解消したはずなのですが、 Amazon アプリストアではだめでした。

# アンインストールにもいつもの問題が

VirtualBox が使えないと困るので Amazon アプリストアをアンインストールしたのですが、これまた昔からおなじみ、アンインストールしても Hyper-V は消えないのでコントロールパネルから消さないといけません。
「コントロール パネル」→「プログラム」→「プログラムと機能」→「Windows の機能の有効化または無効化」から、「仮想マシン プラットフォーム」のチェックを外す必要があります。
これで直りました。

問題が早く無くなってくれるといいですね。
dockerでpython+seleniumのスクレイピング

## dockerを使ってスクレイピング環境構築

pythonを実行するコンテナに、自分でchromeやらドライバをインストールしたりするのは面倒なので、
あらかじめchromeがインストールされたdockerイメージを使いたかったので、環境構築メモ。

python実行環境とselenium実行環境を別のコンテナとして準備して使う。

selenium実行環境はdocker-seleniumのChromeがインストールされたstandaloneイメージを使う。
https://github.com/SeleniumHQ/docker-selenium

## docker-compose
```yml
version: "3"
services:
  selenium:
    image: selenium/standalone-chrome:4.1.4-20220427
    ports:
      - 4444:4444
      - 7900:7900
    volumes:
      - /dev/shm:/dev/shm
  app:
    build: .
    ports:
      - 8888:8888
    volumes:
      - .:/app
    environment:
      SELENIUM_URL: http://selenium:4444/wd/hub
    command: jupyter-notebook --port=8888 --ip=0.0.0.0 --allow-root --NotebookApp.token=''
    tty: true
```

seleniumコンテナのportで7900をマッピングしている。VNCクライアントをインストールしてなくても、`http://localhost:7900`でGUIが確認できる。
（接続の時に求められるパスワードはデフォルトで`secret`になっている。）

appコンテナ（python実行環境）の環境変数に`SELENIUM_URL`を指定。プログラムの中でこれを使うようにする。
command部分はjupyter-notebookを使うためなので、不要な人は不要。

### Dockerfile
```dockerfile
FROM python:3.8.10

ENV PYTHONIOENCODING utf-8
ENV TZ="Asia/Tokyo"
ENV LANG=C.UTF-8
ENV LANGUAGE=en_US:en_US

WORKDIR /app

COPY ./requirements.txt /tmp/requirements.txt

RUN pip install -r /tmp/requirements.txt
```
インストールするものは、requirements.txtに適当に記述。
#### requirements.txt
```txt
selenium
jupyter
requests
BeautifulSoup4
```

### テスト用のスクリプト
```py
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
import os
import time

url = "https://www.google.com"
keyword = "スクレイピング"

driver = webdriver.Remote(
    command_executor = os.environ["SELENIUM_URL"],
    options = webdriver.ChromeOptions()
)

driver.implicitly_wait(10)

driver.get(url)
driver.find_element(By.NAME, "q").send_keys(keyword + Keys.RETURN)

time.sleep(5)
driver.quit()
```

`webdriver.Remote`でseleniumコンテナを指定している。（ここでdocker-compose.ymlで設定している環境変数を使っている。）

あとは、
ブラウザで`http://localhost:7900`にアクセスした状態で、プログラムを実行すると、実際に動作している様子が確認できるかと！
初めてのOSSコントリビュート（Ruby gem）

# はじめに
先日 （超軽微ですが、、）初めてOSSコントリビュートしました :tada:
意外とgemにPRを送るまでの詳細な手順をまとめている記事が見つけられなかったのでまとめたいと思います。

# きっかけ
[gem recapthca](https://github.com/ambethia/recaptcha)の挙動を確認するためにコードを見ていると叩いているAPIのバージョンが古いことに気づきました。
OSSコントリビュートに興味があったのでこれならすぐ修正できる！と思いPRを送ることに。

# PRを送るまでの流れ
## ドキュメントを読んで、コントリビュート時の注意点を確認
Contributingについて記載がないか確認します。
例：Ruby
>See ["Contributing to Ruby"](https://docs.ruby-lang.org/en/master/contributing_md.html), which includes setup and build instructions.

## 既にある issues, PRを確認する
クローズされたものも含め関連するキーワードで検索をかけてissues, PRに目を通し、議論中であったり既にPRが作成されていないか確認します。
解決できないエラーの報告、新しい機能やアイデアの提案であればまずはissueをオープン、明らかなバグなどで自分で解決できる場合はPRを送るために次に進みます。

## リポジトリのフォーク、クローン
Forkボタンからリポジトリをフォーク（GitHub内でのリポジトリのコピー）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782027/600b2918-47ac-af7e-26c9-c26051792fb2.png)

次にフォークしたリポジトリをローカルに[クローン](https://docs.github.com/ja/repositories/creating-and-managing-repositories/cloning-a-repository)します
```
$ git clone {{git@github.com:yuh-pen/recaptcha.git}}
```

リモートリポジトリとして、オリジナルのリポジトリを `upstream` という名前で設定
```
$ git remote add upstream {{git@github.com:ambethia/recaptcha.git}}
```

## Rubyのバージョンを合わせる
gemspec の　`required_ruby_version`を確認してrubyのバージョンを合わせます。
```recaptcha.gemspec
  s.required_ruby_version = '>= 2.7.0'
```
```
$ rbenv local 3.0.1
```
[rbenvの使い方はこちら](https://qiita.com/hujuu/items/3d600f2b2384c145ad12)
```
$ bundle install
```
:::note info
#### bundle の --path について
最近はずっとdockerを使っていたのでローカルでrubyを動かすのが久しぶりだったのですが、そのまま `bundle install`したら　vendor/bundle　にインストールされ gitignore されていなかったため差分ファイルがすごいことになりました :sweat_drops:
pathの設定は必要ないと思ったので以下で削除しました
```
$ bundle config --delete path
```

[bundle install時に--path vendor/bundleを付ける必要性は本当にあるのか、もう一度よく考えてみよう](https://qiita.com/jnchito/items/99b1dbea1767a5095d85)
:::
## 修正（テスト追加）
ブランチを切って修正し、必要があればテストも追加します。
テストを実行して全て通ればOK:star:
```
$ ruby test/*
```

## PR作成
変更をpush
```
$ git push origin HEAD
```
以下のようにオリジナルのリポジトリに表示されているのでCompare & Pull reauestからPRを作成します
![スクリーンショット 2022-08-28 18.49.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782027/d14b5b90-2946-142d-8165-ba93b05c6ec9.png)
表示されていない場合は `New pull request` から以下の `compare across forks` をクリックするとフォークしたリポジトリも選択できるようになります:ok_hand_tone1:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782027/2fbc278b-2166-4e5d-a7d6-88cdb159f62b.png)

PRには関連するissueや関連するドキュメントのリンクを入れてできるだけわかりやすくします
(`Closes #37.`なども使う)

翻訳は[DeepL](https://www.deepl.com/ja/translator)が神！！これさえあれば怖くない！
同じリポジトリの他のPRなども参考にしてよしなにやりましょう:thumbsup_tone1:

## 果報を待つ
そのままマージされる場合もあれば、コメントで変更のリクエストをされる場合もあります。
必要であれば他の人に助けを求めるのもOKですが何かしらのリアクションはしましょう。

PRがマージされればあなたもOSSコントリビューターです :tada:

# おわりに
こちらが私の初OSSコントリビュートです。軽微な修正だったこともあり翌朝にはマージされていてとてもうれしかったです！

https://github.com/ambethia/recaptcha/pull/415

あまり堅苦しいこと抜きに、個人的にはマージされるとテンション上がるのでOSSコントリビュートおすすめです
この記事がOSSコントリビュートの手助けになれれば幸いです！

# 参考

[オープンソースガイドライン](https://opensource.guide/ja/)
[初めて ruby の gem にコントリビュートのコミットをしてプルリクエスト作ってみた](https://itoshk-development.hatenablog.jp/entry/2021/04/14/113905)
Qiitaの投稿方法を自分の初投稿でまとめる

# 挨拶
Qiitaを初めた大学生です。
自分の初投稿も兼ねて投稿方法についてまとめたいと思います。
# 初投稿
アカウントを作成し、早速投稿をしていきます。
「投稿する」をクリックするとこのような画面が出てきますね。左側で編集し、右側で確認するような形式となっています。僕は大学でTexを書くので似たような感じと思っています。![スクリーンショット 2022-08-28 18.15.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2819600/5b613177-227d-29ab-86f3-77d9761a318c.png)
本文の横にある、「# 良い記事を書くには」[良い記事を書くためのガイドライン](https://help.qiita.com/ja/articles/qiita-article-guideline)を最初に読むと良いでしょう。

# Markdown記法
QiitaはMarkdown記法が用いられるようです。Markdown記法...?となった方はまず公式のチートシートを参照すると良いでしょう。(かくいう僕も参照しながら書いています。)
[Markdown記法 チートシート](https://qiita.com/Qiita/items/c686397e4a0f4f11683d)
個人的にはこのチートシートの方が見やすいです。
[Qiita マークダウン記法 一覧表・チートシート](https://qiita.com/kamorits/items/6f342da395ad57468ae3)
## 基本中の基本の書き方
細かいところはチートシート等を見てもらうといいのですが、最初に使うものを抜粋してまとめたいと思います。
## 見出し

~~~title:書き方
# h1
## h2
### h3
#### h4
~~~
### 結果
# h1
## h2
### h3
#### h4
このように、#と半角スペースで見出しを設定できます。
## コードの記述
* 書き方
\`\`\`python:hello.py
print('Hello World!!')
\`\`\`
* 結果
```python:hello.py
print('Hello World!!')
```
このように、バックオートorチルダを3つ繋げることでコードを挿入できます。
# 記事を見ていて記法が気になったら
![スクリーンショット 2022-08-28 19.10.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2819600/0cfc208b-fc5d-5a8e-c9a6-68ef17207fa0.png)
このように、「...」を押すと「Markdownで本文を見る」でその記事のMarkdown記法が確認できます。実際にいいなと思った記事の記法を見ることで効率的に書き方が身に付くと思います！
### 感想
Qiita初心者なりに調べながら書いてみました。もちろんこのような初心者向けの記事はたくさんあるので役に立つような記事ではないかもしれませんが、自分の学習に合わせてアウトプットの場として今後も投稿していけたらいいなと考えているのでご了承をお願いします、、、
あなたは知っている？Rubocop に教えてもらった Ruby の小ネタ5つ

## はじめに
Ruby 2.7 以降に追加された新しめの文法を５つ紹介します。
業務で Ruby のアップデート、および rubocop のアップデートをしました。
その際に学んだことですので、rubocop 関連の記事を参考にしています。

## Rails/WhereExists　
**`where` してから `exists?` するのではなく、`exists?` 単体でOK**
~~~ruby
# bad
User.where(name: 'john').exists?

# good
User.exists?(name: 'john')
~~~

https://www.rubydoc.info/gems/rubocop-rails/2.8.1/RuboCop/Cop/Rails/WhereExists

## Performance/MapCompact
**`map.compact` は`filter_map`で書き換えられる⚠︎**
`compact` は自身から `nil` を取り除いた配列を生成して返します。 
`compact!` は自身から破壊的に `nil` を取り除き、変更が行われた場合は `self` を、そうでなければ `nil` を返します。
~~~ruby
# bad
ary.map(&:foo).compact
ary.collect(&:foo).compact

# good
ary.filter_map(&:foo)
# Enumerable#filter_map! というメソッドは存在しないので、以下のケースは例外となるので注意
ary.map(&:foo).compact!
~~~
⚠︎厳密には、置き換えられないケースもあります。
詳細は [konic さんの記事](https://koic.hatenablog.com/entry/rubocop-performance-1-11-has-been-released#:~:text=%E4%BB%A5%E4%B8%8B%E3%81%AE%E3%81%84%E3%81%9A%E3%82%8C%E3%81%AE%E3%82%B1%E3%83%BC%E3%82%B9%E3%82%82%20nil%20%E3%82%92%E9%99%A4%E5%A4%96%E3%81%99%E3%82%8B%E3%81%8C%E3%80%81filter_map%20%E3%81%AF%E5%8A%A0%E3%81%88%E3%81%A6%20false%20%E3%82%82%E9%99%A4%E5%A4%96%E3%81%99%E3%82%8B%E3%80%82%E3%81%93%E3%81%AE%E3%82%88%E3%81%86%E3%81%AB%20compact%20%E3%81%A8%20filter_map%20%E3%81%AF%E6%8C%AF%E3%82%8B%E8%88%9E%E3%81%84%E3%81%AB%E4%BA%92%E6%8F%9B%E6%80%A7%E3%81%8C%E3%81%AA%E3%81%84%E3%81%9F%E3%82%81%E3%80%81SafeAutoCorrect%3A%20false%20(rubocop%20%2DA%20%E3%81%A7%E9%81%A9%E7%94%A8)%20%E3%81%A8%E3%81%97%E3%81%A6%E3%81%84%E3%82%8B%E3%80%82)を参照ください。

## Performance/SelectMap
**`select.map` は `filter_map` で書き換えられる**
ただし、good ケースの可読性について賛否があるので使用時は注意。
~~~ruby
# bad
ary.select(&:foo).map(&:bar)
ary.filter(&:foo).map(&:bar)

# good
ary.filter_map { |o| o.bar if o.foo }
~~~
⚠︎単純な置き換えができない場合があります。


## Rails/RedundantPresenceValidationOnBelongsTo
**`presence validator`は自動的に追加され、明示的な`presence validation`は冗長**
~~~ruby
# bad
belongs_to :user
validates :user, presence: true

# good
belongs_to :user
~~~

## Style/HashSyntax: Omit the hash value
**ハッシュのキーと値が同じ場合は書かず、異なる (意図のある) 値は明示的に書く**
これは Ruby3.1 からの追加されています。
~~~ruby
# bad
{foo: foo, bar: bar}

# good
{foo:, bar:}
~~~

## さいごに
全て知っていましたか？
自分はエンジニアになって５ヶ月ほどなので知らないことばかりでした！
実用性はともかく、更新される文法を追っていくのも楽しいですね！


## 参考
https://koic.hatenablog.com
TeamGroup製メモリをAMD Ryzen 9 5950Xマシンに取り付けてみた

自作マシンのメモリ交換を行ったのですが、対象メモリのレビューがほとんど存在しなかったので書いてみます。
# 対象メモリ
型番：TLZRD432G3600HC18JDC01 
枚数：4枚 (16GB*2のセットを2つ購入)
TeamGroup社という比較的新しいメーカーのメモリです。(私の知識が古いだけかもしれませんが) 
PC4-28800(DDR4-3600)であるため、3600MHzで稼働するはずです。

[メーカーページ](https://www.teamgroupinc.com/jp/product/vulcan-z-ddr4) 
[価格comページ](https://kakaku.com/item/K0001461734/) 

赤色の TLZ**R**D432G3600HC18JDC01 を購入しましたが、
黒色の TLZ**G**D432G3600HC18JDC01 も中身は同じでないかと。


# 取付環境
マザーボード：ASUS ROG STRIX X570-E GAMING
CPU：AMD Ryzen 9 5950X


# 結論 
XMP値より若干オーバークロック気味の以下の設定で安定動作しました。

周波数：3600MHz
レイテンシ：CL16-20-20-38
電圧：1.37V (もう少し下げられるかも)
![Mainboard.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1024229/5e18e4ef-17b5-1a59-9e47-aaf382ba89af.png)
![Memory.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1024229/26ee992d-06f9-8c5d-b27e-76b3e128b417.png)
![SPD.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1024229/da56388d-b028-766e-e9c4-73f73db889a6.png)


# 検証経緯 
## ダウンクロック (JEDEC値) 
まず、4枚刺しでDualチャネルとして認識問題なしでした。
ただデフォルトの設定だと、オーバークロックの設定が読み込まれないため、
3200MHzと低い周波数になってしまいます。 

## 定格 (XMP値) 
次にXMPで設定されているオーバークロックの定格値wに設定してみました。
(XMPはIntel系の規格名なので、AMD & ASUSマザボ環境では、D.O.C.Pという設定になります。)
XMPには、"メーカーテスト済み"と掲示のものと同じ値が設定されていました。

周波数：3600MHz
レイテンシ：CL18-22-22-42
電圧：1.35V ⇒ 1.40V

テスト済みだし大丈夫と思いきや、ここでBIOS起動しなくなる問題発生。
周波数/レイテンシはそのままで、電圧だけ1.40Vまで上げると安定動作しました。


## オーバークロック 
XMP+電圧盛り気味で、レイテンシの調整をしたところ、以下の値まで短縮できました。

周波数：3600MHz
レイテンシ：CL16-20-20-38
電圧：1.40V ⇒ 1.35V

この状態から電圧がとこまで下げられるか調整したところ、
初回では起動しなかった1.35Vまで下げられました。何故だ、、
が安全策として結論で書いた1.37Vで運用しています。


# まとめ 
あまり聞かないメーカーで、口コミもほとんどない製品でしたが、
ちゃんと定格以上の設定で動いてくれました。

投稿時点で下記のキャンペーンもやってました。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">対象製品をご購入の先着100名様に！！<br>「メモリラバーキーホルダー」をプレゼント！🎁<br><br>弊社VulcanZ DDR4の可愛いキーホルダーですよ！！<br><br>車の鍵に付けるもヨシっ👉！<br>家の鍵に付けるもヨシっ👉！<br>お気に入りのメモリを常に持ち運びましょう💪💪💪<br><br>沢山のご応募お待ちしております🥰🥰🥰 <a href="https://t.co/ikgj6G9gw2">pic.twitter.com/ikgj6G9gw2</a></p>&mdash; ㈱TEAMジャパン【公式】🍤 (@TeamGroup_JP) <a href="https://twitter.com/TeamGroup_JP/status/1547876347305132033?ref_src=twsrc%5Etfw">July 15, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
python コルーチンについて

## コルーチンとは
一次処理を中断して再開できるもの。

### ジェネレーターで作るコルーチン
- ジェネレータの作成・活性化・値送信
```python

# ジェネレータを作成
def g_hello():
    r = yield
    yield r

g = g_hello() # ジェネレータオブジェクトを作成
print(next(g)) # ジェネレータオブジェクトを活性化
result = g.send('peanuts') # ジェネレータオブジェクトに値を送る
print(result)

>>> 
peanuts
```
- 受け取った値に対して処理(greet(r))を加えて返すことも可能
```python
def greet(r):
    return f'hello: {r}'

def g_hello():
    r = yield
    # yield r
    yield greet(r)

g = g_hello() # ジェネレータオブジェクトを作成
next(g) # ジェネレータオブジェクトを活性化
result = g.send('peanuts') # ジェネレータオブジェクトに値を送る
print(result)

>>>
hello: peanuts
```



- コルーチン
async def で定義した関数。

```python
import asyncio

async def coro_func():
    """coro_func()はコルーチン関数"""
    return 100
```

コルーチン関数を呼び出すと、コルーチンオブジェクトが返る。
コルーチン関数を実行するにはイベントループに登録する必要がある。

- コルーチンオブジェクトとは
    - イベントループに登録することで実行できるオブジェクト
```python
print(coro_func())
>>> 
<coroutine object coro_func at 0x0000018651E63DF0>
C:\work\study\python\python_programming\async_practice.py:7: RuntimeWarning: coroutine 'coro_func' was never awaited
  print(coro_func())
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
```

- イベントループの作成方法
```python
loop = asyncio.get_event_loop() # イベントループを作成
```

- イベントループへの登録方法
```python
task = loop.create_task(coro) # イベントループにコルーチンを登録しタスクオブジェクトを返す。
```

- タスクオブジェクト
    - コルーチンオブジェクトの実行状態を管理するオブジェクト
    - コルーチンオブジェクトをイベントループに登録することで、取得

- タスクオブジェクトの実行
    - task で指定したタスクオブジェクトが完了するまで、イベントループを実行し続けます。
```python
loop.run_until_complete(task)
```

- asyncio.run(coro)
    - あたらしくイベントループを作成して、非同期処理を開始するための関数
    - コルーチンオブジェクトをイベントループに登録し、タスクオブジェクトを作成します。
    - タスクオブジェクトが完了するまでイベントループを実行し続けます。

### ジェネレーターコルーチンの例
yield



##  クラス
NotImplementedError

ユーザ定義の基底クラスにおいて、抽象メソッドが派生クラスでオーバライドされることを要求する場合、この例外を送出しなくてはなりません。

絶対オバーライドしろよって場合には使えばよい

[参考:PythonのNotImplementedError](https://qiita.com/okuhiiro/items/3a23fc677169006d6075)
eksやるときの注意事項

eksctlのインストール

```
curl -L "https://github.com/weaveworks/eksctl/releases/latest/download/eksctl_$(uname -s)_amd64.tar.gz" | tar xz -C /tmp
sudo mv /tmp/eksctl /usr/local/bin
eksctl version
```
kubernetesのインストール
```
sudo curl -L -o /usr/local/bin/kubectl https://amazon-eks.s3.us-west-2.amazonaws.com/1.21.2/2021-07-05/bin/linux/amd64/kubectl
sudo chmod +x /usr/local/bin/kubectl

kubectl version --short --client
```

cluster作成
```
eksctl create cluster \
      --vpc-cidr 10.0.0.0/16 \
      --name eks-sample \
      --region ap-northeast-1 \
      --version 1.21 \
      --nodegroup-name sample-workers \
      --node-type t2.small \
      --nodes 1 \
      --nodes-min 1 \
      --nodes-max 3 \
      --managed
```

:::note warn
node-typeを設定しておかないとlargeとか容量が大きいclusterを構成されてしまうので注意
:::

EKSクラスタの削除
```
$ eksctl delete cluster \ke-
     --name eks-sample \
     --wait
```

```
teratermが途中で消えてしまう対処法
設定→TCP.IPの部分でkeep-aliveを30秒に変更、自動的にウィンドウを閉じるをoffにする。
設定→SSHの部分のハートビートを30秒にする。
```

:::note alert
あとはNAT gatewayの削除を忘れずに！！(EKSクラスタの削除では削除されなかったことがあり)
:::
Springのバリデーションで任意の順番(タイミング)で処理させる方法(@GroupSequence)

備忘です。苦労したのと色々よくわからないので。

例えば以下のように一つの項目にいくつかのバリデーションが設定されていたとします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2631579/7e7312f8-a7ea-d1d3-2feb-947959669ef1.png)

このプログラムを起動させ、何も入力せずに、処理を行おうとするとバリデーションが働いて以下のような赤文字のエラーが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2631579/773bdc66-4d18-80f4-ab5a-9d8d1a471591.png)

この社員番号ですが、何も入力していない場合は、「社員番号を入力してください(@NoBlank)」だけ表示させたい（「数字を入力してください」と「10文字以内で入力してください」は表示させない）場合の記事です。

以下方法。
こんな感じでインターフェースのファイルを用意。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2631579/d130dbe3-e1dc-0e3f-ef76-7b5d90c4b1ca.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2631579/700ee9e2-b1f3-d1d0-7656-18a7db91e3ed.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2631579/6984adce-0427-605d-2df8-636725eec2fb.png)


各フィールドのバリデーションにgroup属性をつける。
この場合Firstとつけている@NotBlankが最初に効くバリデーションになり、Secondとつけている@Pattern、@Sizeが次に効くバリデーションとなる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2631579/d9cb7d1e-0fec-dcb4-6bd3-7bbedbed8f9d.png)

この2つのインターフェースをまとめるのが、GroupOrderインターフェース内の@GroupSequenceである。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2631579/d7453db8-87fe-0c06-d5ae-7241883d4a68.png)

以下結果。
何も値を入力しない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2631579/f771b0e6-3d6b-7be1-994d-e4df4ad303ff.png)

何か値を入力する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2631579/8ce3f6c6-9073-6fd6-8338-6b6121a68d4f.png)
こんな感じでバリデーションを任意の順番(タイミング)で処理させることができる。

 **疑問点** 
社員番号に値を入れて、氏名は空欄する。
するとなぜか社員番号に「数字を入力してください」と「10文字以内で入力してください」が表示されない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2631579/e57081d1-76c5-dc4a-ef76-d2e9a5674f7d.png)

氏名に値を入れる。
そうすると社員番号に「数字を入力してください」と「10文字以内で入力してください」が表示される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2631579/03dfda12-ea6c-99bb-ef07-a7c4c7f6fc81.png)
これは仕様らしく、「社員番号」、「氏名」両方に設定されているFirstのバリデーションを満たさないとSecondバリデーションは効かないらしい。

※どなたか、この仕様を別のやり方で解消する方法があれば教えてください。。。
開放したポートを一撃で閉じたい

# やりたいこと

ポートフォワーディングなどをバックグラウンドで実行した際に、開放したポートを閉じる。

通常だと、「ポート開放で使っているプロセス番号を調べる」→「該当プロセスをkillする」の手順を踏むと思われるが、実行コマンドが複数だったり、プロセス番号を一時的に覚えておく必要があったりして不便なので、諸々の処理をパイプラインで結合したワンライナーのコマンドとして実現したい


# コマンド

環境: mac OSX 12, zsh

```
lsof -i:閉じたいポート番号 | tail -n +2 | sed -E "s/[ ]+/\t/g" | cut -f2 | uniq | xargs kill -9
```

## 個別のコマンド解説

|コマンド  |役割  |
|---|---|
|lsof -i:port  |対象ポートの情報(PIDを含む)を取得する  |
|tail -n +2  |lsof -i のヘッダを消す  |
|sed -E "s/[ ]+/\t/g"|連続空白をcutしやすい区切り文字(TAB)にする|
|cut -f2|PIDの列のみ取得する  |
|uniq  |PIDの重複をなくす  |
|xargs kill -9  |↑までで取得したPIDのプロセスを停止する  |


## 追記

コメントでよりシンプルな方法を教えていただきました。行ごとに処理をするawkを使って、PIDの抽出を行っています

```
lsof -i:閉じたいポート番号 | awk 'NR>1{print $2}' | uniq | xargs kill -9
```
(WSL2)Distrodを導入したCentOS7を再起動すると、ApacheとMySQLがエラーで起動しない場合の対応

## はじめに
CentOS7にDistrodを導入後、再起動するとApacheとMySQLが起動しませんでした。原因と対応方法を記載します。

## 原因と対策
* 原因
  * サービス`systemd-tmpfiles-setup`の設定ファイルが間違っており、起動時に必要なディレクトリが作成されないことが原因です(Distrodのバグっぽい)

* 対策
  * 別途、設定を上書きするためにファイルを作成し、そこに記載します
```
# mkdir /etc/systemd/system/systemd-tmpfiles-setup.service.d
# cat << EOF > /etc/systemd/system/systemd-tmpfiles-setup.service.d/exclude_wslg_sockets.conf
[Service]
ExecStart=systemd-tmpfiles --clean --exclude-prefix=/tmp/.X11-unix
EOF 
```


### 調査、対応手順

起動時にエラーとなっていたため、ログファイルでエラーを確認

Apacheのエラー(/var/log/httpd/error_log)
```
Failed to create shared memory segment on file /run/httpd/authdigest_shm.590
```

MySQLのエラー(/var/logmysqld.log)
```
[ERROR] [MY-011300] [Server] Plugin mysqlx reported: 'Setup of socket: '/var/run/mysqld/mysqlx.sock' failed, can't create lock file
```
* `/var/run`に必要なディレクトリが作成されてないためエラーとなっている模様

---

* `/var/run`のファイルシステムは`tmpfs`のため、再起動毎にクリアされるが、サービス`systemd-tmpfiles-setup`により、apacheやMySQLに必要なディレクトリは作成されるはず
  * 起動時にエラーが発生していたた
 
```bash
$ systemctl status systemd-tmpfiles-setup
● systemd-tmpfiles-setup.service - Create Volatile Files and Directories
Loaded: error (Reason: Invalid argument)
Drop-In: /run/systemd/system/systemd-tmpfiles-setup.service.d
└─exclude_wslg_sockets.conf
Active: inactive (dead)
Docs: man:tmpfiles.d(5)
man:systemd-tmpfiles(8)
```

* 'exclude_wslg_sockets.conf`ファイルを開いて内容を確認
  * `ExecStart=`行が不要と思われる

  
```
# This file is part of Distrod.
#
# Do not edit this file directly. This file can be overwritten when Distrod is updated.
# Instead, create /etc/systemd/system/systemd-tmpfiles-clean.service.d/exclude_wslg_sockets.conf,
# systemd will load it.

# avoid `/tmp/.X11-unix` to be cleaned up by systemd
[Service]
ExecStart=
ExecStart=systemd-tmpfiles --clean --exclude-prefix=/tmp/.X11-unix
```

* コメントに従い、直接修正するのではなく`/etc/systemd/system/systemd-tmpfiles-clean.service.d/exclude_wslg_sockets.conf`を作成してそこに記載する
```
# mkdir /etc/systemd/system/systemd-tmpfiles-setup.service.d
# cat << EOF > /etc/systemd/system/systemd-tmpfiles-setup.service.d/exclude_wslg_sockets.conf
[Service]
ExecStart=systemd-tmpfiles --clean --exclude-prefix=/tmp/.X11-unix
EOF 
```

OS再起動(wsl --shutdown)後、Apacheが起動していることを確認

```
$ systemctl status httpd
● httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled)
   Active: active (running) since Sun 2022-08-28 18:08:58 JST; 5min ago
```
Mac対応の画像ビューア(comic master)をつくった React+Electron(Vite, TailwindCSS)



## 成果物

[comic master](https://github.com/araera111/comic_master/releases "comic master")
※署名とかしていないので開発元を検証できません、と出る野良です。
Macの人はシステム環境設定→セキュリティとプライバシーの一番下から開いてもらえたら開けると思います。

## つくった理由

mac対応のまともな漫画ビューアが無料でなかったからです。windowsだと古くはmangameeya、いまはhoney viewなどあります。macの場合はComicViewerというソフトがありますが、いまいち使用感が好きではなかったので自分でつくりました。

## 操作方法

1. 画像ファイルの入ったフォルダか、zipをドラッグする
2. 左キー、右キーでページめくり
3. zキーで1ページ表示、右見開き表示を切り替え
4. aキーで1ページだけ送る、qキーで1ページだけ戻す

以上です。

マウスホイール、クリックでのページめくり、それからキーバインドの変更などはおいおいつくる予定です。

## 今後の更新予定

* 最後に開いたファイルを起動時に開く
* 見開きモード、1枚表示モードを記憶する機能
* 自動でページをめくる機能
* 5ページ飛ばし、10ページ飛ばし
* 3/12など全体のうちどこまで読んだのかを把握する機能
* 最後まで読んだらループせず、そこで止まる機能(オプション)
* マウスホイール、マウスクリックでページを送る機能

など。気が向いたときにつくっていきます。

ソースコードも置いておくので、お好みで調整してもらえれば良いかと思います。

## つくっていて詰まった点

### そもそも画像をアスペクト比を維持したまま中央表示にするのが難しい

これはtailwindcssを駆使して下記コードで解決しています。

```tsx
<div className="mx-auto bg-slate-800 text-white overflow-hidden">
  <img src={`${pageUrlList[page]}`} alt="" className="object-contain h-screen w-screen" />
</div>
```

wrapperのdivにoverflow-hiddenをつけて、中の画像にobject-contain, h-screen, w-screenをつけるといい感じに画面を小さくすれば比率を維持したまま画面をはみ出さずに小さくなってくれます。

2枚表示のときはこんな感じ……。

```tsx
<div className="flex justify-center">
  <div>
    <img src={`${pageUrlList[page + 1]}`} alt="" className="object-contain h-screen w-full" />
  </div>
  <div>
    <img src={`${pageUrlList[page]}`} alt="" className="object-contain h-screen w-full" />
  </div>
</div>
```

### 開発中にローカルの画像ファイルを読み込めない

electronで開発をしていると、ローカルの画像ファイルを読み込むことができません。正確にはbuildしたあとのexeでは読み込めるけれども、devでつくっているときには読み込みません。
対応策としてwebSecurityをfalseにすると動きます……ということで最初はそうしていたのですが、結局zipを解凍して読み込む部分をつくるときに、ローカルの画像パスを読み込むのではなく、readFileで読み込んだ画像をそのままURIにエンコードしています。

そのうちリファクタリングするぞ……と思いつつ書いてしまったコードがこちら。

```TypeScript
export const getDirectoryImageFiles = async (path: string): Promise<[string[], string[]]> => {
  /* ディレクトリのファイルを読み込む */
  const files = await readDirSync(path);

  /* jpgなどでfilterする */
  const filteredFiles = files
    .map((fileName) => `${path}\\${fileName}`)
    .filter(async (filePath) => {
      const extName = await nodeExtnum(filePath);
      return enableExtnames.includes(extName);
    });

  let urls: string[] = [];

  for (const path of filteredFiles) {
    const base64 = await nodeReadFileSync64(path);
    const url = `data:image/png;base64,${base64}`;
    urls = [...urls, url];
  }
  return [urls, filteredFiles];
};
```

そんな感じで自分用につくったソフトですが、転職活動も兼ねて一般公開することにしました。要望があれば気が向いたときに開発してみます。
Golang Generics について

# 概要
Golang での Generics に関する知見をまとめた記事になります。

## Generics とは？
> ジェネリック（総称あるいは汎用）プログラミング）は、具体的なデータ型に直接依存しない、抽象的かつ汎用的なコード記述を可能にするコンピュータプログラミング手法である。

Golang では[1.18](https://tip.golang.org/doc/go1.18#language)からGenericsを利用できるようになりました。


**引用元**
- [ジェネリックプログラミング](https://ja.wikipedia.org/wiki/%E3%82%B8%E3%82%A7%E3%83%8D%E3%83%AA%E3%83%83%E3%82%AF%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0)

# 比較
[公式のドキュメント](https://go.dev/doc/tutorial/generics)を元にGenerics有無のソースコードの比較と書き方を確認します

## Generics を利用しないソースコード
```main.go
package main

import "fmt"

func main() {
    // Initialize a map for the integer values
    ints := map[string]int64{
        "first":  34,
        "second": 12,
    }

    // Initialize a map for the float values
    floats := map[string]float64{
        "first":  35.98,
        "second": 26.99,
    }

    fmt.Printf("Non-Generic Sums: %v and %v\n",
        SumInts(ints),
        SumFloats(floats))
}

// SumInts adds together the values of m.
func SumInts(m map[string]int64) int64 {
    var s int64
    for _, v := range m {
        s += v
    }
    return s
}

// SumFloats adds together the values of m.
func SumFloats(m map[string]float64) float64 {
    var s float64
    for _, v := range m {
        s += v
    }
    return s
}
```
仮に`int64`, `float64`以外の型を追加する場合に新たな関数を追加する必要がある。
`Generics`を用いた場合、上記の問題を回避できる（汎用的な関数を作成できる）。

## Generics を利用したソースコード
```main.go
package main

import "fmt"

type Number interface {
    int64 | float64
}

func main() {
    // Initialize a map for the integer values
    ints := map[string]int64{
        "first": 34,
        "second": 12,
    }

    // Initialize a map for the float values
    floats := map[string]float64{
        "first": 35.98,
        "second": 26.99,
    }

    fmt.Printf("Generic Sums: %v and %v\n",
        SumIntsOrFloats[string, int64](ints),
        SumIntsOrFloats[string, float64](floats))

    fmt.Printf("Generic Sums, type parameters inferred: %v and %v\n",
        SumIntsOrFloats(ints),
        SumIntsOrFloats(floats))

    fmt.Printf("Generic Sums with Constraint: %v and %v\n",
        SumNumbers(ints),
        SumNumbers(floats))
}

// SumIntsOrFloats sums the values of map m. It supports both floats and integers
// as map values.
func SumIntsOrFloats[K comparable, V int64 | float64](m map[K]V) V {
    var s V
    for _, v := range m {
        s += v
    }
    return s
}

// SumNumbers sums the values of map m. Its supports both integers
// and floats as map values.
func SumNumbers[K comparable, V Number](m map[K]V) V {
    var s V
    for _, v := range m {
        s += v
    }
    return s
}
```

### Type Parameters
関数の引数の前に`[]`内に記述され、型を記述できます。
現状は`any`と`comparable`がビルドインされていて、上記のソースコードでは`comparable`が定義されています。
`comparable`とは、型の値に `==` および `!=` 演算子を使用できるようにする制約です。
参考：[Type parameters](https://go.dev/tour/generics/1)

### Type Sets
以下の様に方パラメータを制約したい時にインターフェースを定義することができる。
```
type Number interface {
    int64 | float64
}
```
`SumIntsOrFloats` と `SumNumbers`関数の引数は実質同じだと考えられるが、引数が多数存在する場合はインターフェースを定義した方が可読性が上がりそう。
Ubuntuの謎豹

# Ubuntuの謎豹とは

Ubuntuをインストールするとデフォルトの壁紙に設定されているこの動物である。
おそらくヒョウ的なマスコット的なサムシングかと思われる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/c05082b3-b6df-d6f4-f231-4b13427bc74e.png)

**こいつは一体何者なのか？**
**なぜ目からビームを出しているのか？**
**人類に対する何かの警告なのか？**

我々はさっそく **Ubuntu謎豹調査団** を結成（1人）。
現地（インターネット）へと飛んだ…。

# 名前はFelicity

（インターネットという名の）ジャングルをさまようこと15分。
我々はついに有力な情報を得ることに成功！
どうやら **Felicity** という名前らしい。

https://kledgeb.blogspot.com/2020/03/ubuntu-2004-15.html

## Felicityの意味とは

現地ガイド（翻訳サイト）によると **Felicity** は **適切さ** **幸福** を意味しているとのこと。

https://www.ei-navi.jp/dictionary/content/felicity/

なるほど、Ubuntuの精神をくみ取ったよいお名前である。

>Ubuntuは、アフリカの単語で「他者への思いやり」や「皆があっての私」といった意味を持ちます。LinuxディストリビューションであるUbuntuは、Ubuntuの精神をソフトウェアの世界に届けます。

https://www.ubuntulinux.jp/ubuntu

# Felicityちゃん

さらに調査を進めたところ、意外な事実が判明。
女の子だった。

>she is

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/4c9a02e5-8011-aa10-c065-65150d7b2db7.png)

https://discourse.ubuntu.com/t/focal-fossa-mascot-wallpapers/14621

調査団全員満場一致で、以後 **Felicityちゃん** と呼ぶことで決定。

# 目からビームの謎はとけず…

しかし調査はここで行き詰る。

なぜ目からビームを出しているのか… **コレガワカラナイ**

```Felicity Ubuntu "beam"```
```Felicity Ubuntu "eye"```
でググってもこれといった情報は得られず…。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/794b4fda-c5be-098e-537f-2dcf5aba8b4d.png)

この時、調査はすでに1時間という大台を超え、団員の疲労はすでにピークに達していた…。

さらには **「そもそも豹じゃなくてネコじゃね？」** という疑問まで出始める始末。

これ以上の深追いは危険と判断し、泣く泣く調査を中断。
（いろいろ調べたけど、なんで目からビーム出してるのか結局よく分かんなかったです(´・ω・`)）

* Felicityちゃんは豹なのかネコなのか、それともネコ科のサムシングなのか？
* なぜ目からビームを出しているのか？

**謎は深まるばかりである…。**
archlinuxを定期的に再起動する（録画中ならやめる）

# はじめに
この記事はarchlinuxを定期的に再起動（EPGStationが録画中ならやめる様に）する手順紹介（備忘録）です。
※元作業の関係上、基本的にルートユーザーで作業を行っています。

# やりたいこと
- （背景）archlinuxに[EPGStation](https://github.com/l3tnun/EPGStation/blob/master/Readme.md)（録画ソフト）を導入している
- PCを起動しっぱなしにしていると何かとトラブルが起きるため、週に1度再起動させたい
- 再起動時にEPGStationが録画中だったら再起動を待ってほしい

# 録画中か否かの情報取得
調査した結果以下のコマンドで録画中かどうかの判別ができることがわかりました。
録画中だと`records`の中にズラズラと情報が入っていて、録画中でなければ`records`が空っぽです。
```sh
curl http://localhost:8888/api/recording?isHalfWidth=true
```

# 定期的に再起動させる設定をする
#### jq、cronのインストール
curlの返り値は`JSON`形式なので、`JSON`を扱いやすくするために`jq`コマンドをインストールします。
また、「定期実行といえば`cron`！」ということで`cron`もインストールします。
```sh
# jqのインストール
pacman -S --noconfirm jq

# cronのインストール
pacman -S --noconfirm cronie

# cronの有効化・起動
systemctl enable cronie
systemctl start cronie
systemctl status cronie
```

#### cronの設定
毎週月曜日の朝3:37に再起動する様に設定しました。
設定時間が半端な理由は以下の2つです。
「この時間帯の番組を録画することは少ないだろう」
「この**半端**な時間が番組の切れ目になることは少ないだろう」

```sh
# 現在の設定確認（何もないはず）
crontab -l

# 週1再起動の設定
## 月曜日の朝3:37に再起動をする
### もしそのタイミングで録画中の場合は、その後5分ごとに様子を見て録画が終わっていたら再起動をする
crontab -e
>>> 以下の内容を記入する（操作はvi）
37 3 * * 1 while true; do if [[ $(curl http://localhost:8888/api/recording?isHalfWidth=true 2>/dev/null | jq '.records | length') -eq 0 ]]; then reboot; break; else sleep 300; fi done
<<< 以下の内容を記入する（操作はvi）
```

以上

# 関連記事
- [NASNEを自作してみた](https://qiita.com/hirmr/items/cde0baf51d82ca9de791)
録画サーバーのファイアーウォール設定

# はじめに
この記事は録画サーバー on archlinux でファイアーウォールの設定をする手順紹介（備忘録）です。
中身としては普通の`iptables`を使った設定手順です。
※元作業の関係上、基本的にルートユーザーで作業を行っています。

# やりたいこと
- 不正なアクセスを防ぐためにファイアーウォールを設定したい
- Mirakurun、EPGStation、SAMBA等のコンポーネントに関する通信は遮断したくない


# ファイアーウォールの設定
### iptablesの有効化・起動
```sh
# サービスの起動と自動起動の設定をする
systemctl start iptables
systemctl enable iptables
systemctl status iptables
```

### iptablesの設定
サーバーにssh接続している場合などは、sshの接続の許可を入れておかないと、諸々の設定を有効化した際に突然遮断される場合もあるので注意が必要です。（そうなってしまったら、サーバーに直に接続して作業しましょう）
```sh
# 現在の設定状況の確認→何も設定されてないはず
iptables -nvL --line-numbers

# ルールをリセットする（一応）
iptables -F

## 設定をする
# FORWARD チェインのデフォルトポリシーを ACCEPT から DROP に変更する（ルーターならACCEPTにするっぽい）
iptables -P FORWARD DROP

# ローカルからの通信を許可する
iptables -A INPUT -i lo -j ACCEPT

# sshの設定
iptables -A INPUT -p tcp --dport ssh -j ACCEPT
iptables -A OUTPUT -p tcp --dport ssh -j ACCEPT

# http, httpsの設定
iptables -A OUTPUT -p tcp -m state --state NEW --dport http -j ACCEPT
iptables -A OUTPUT -p tcp -m state --state NEW --dport https -j ACCEPT

# EPGStationが使っているポートを開ける
iptables -A INPUT -p tcp --dport 8888 -j ACCEPT

# Mirakurunが使っているポートを開ける
iptables -A INPUT -p tcp --dport 40772 -j ACCEPT

# SAMBAが使っているポートを開ける
iptables -A INPUT -p udp --dport 137 -j ACCEPT
iptables -A INPUT -p udp --dport 138 -j ACCEPT
iptables -A INPUT -p tcp --dport 139 -j ACCEPT
iptables -A INPUT -p tcp --dport 445 -j ACCEPT

# 任意へのDNSアクセスの戻りパケットを受け付ける
iptables -A INPUT -p udp --sport 53 -j ACCEPT

# 確立済みの通信は、ポート番号に関係なく許可する
iptables -A INPUT -p tcp -m state --state ESTABLISHED,RELATED -j ACCEPT

# icmp(ping)の設定
iptables -A INPUT -p icmp --icmp-type echo-request -m hashlimit --hashlimit-name t_icmp --hashlimit 1/m --hashlimit-burst 10 --hashlimit-mode srcip --hashlimit-htable-expire 120000 -j ACCEPT

# INPUT チェインのデフォルトポリシーも ACCEPT から DROP に変更する
iptables -P INPUT DROP

# ルールの確認
iptables -nvL --line-numbers


## 設定内容の反映
# 設定内容をファイルに書き出す
iptables-save > /etc/iptables/iptables.rules
# 有効化する
systemctl reload iptables
systemctl restart iptables
```

以上

# 関連記事
- [NASNEを自作してみた](https://qiita.com/hirmr/items/cde0baf51d82ca9de791)
archlinuxにSAMBAを導入してみた

# はじめに
この記事はarchlinuxにSAMBAを導入する手順紹介（備忘録）です。
SAMBAとはWindowsとの互換性を持ったファイル共有システムで、これによってWindowsPCからはもちろん、スマホからもアプリを使って共有ファイルにアクセスできる様になります。
※元作業の関係上、基本的にルートユーザーで作業を行っています。

# SAMBAの導入
#### 必要パッケージのインストール
```sh
# sambaパッケージのインストール
pacman -S --noconfirm samba

# その他インストールに必要なパッケージ
pacman -S --noconfirm wget
```

#### 共有するディレクトリの作成
```sh
# 共有ディレクトリ作成
mkdir -p /nas/samba

# ディレクトリの所有者の変更
chown arch:arch /nas/samba
```

#### ユーザーの追加
```sh
# sambaで接続するユーザーを追加する
pdbedit -a -u arch
（archユーザーのパスワード）
```

#### samba設定ファイルの設定
```sh
# samba.confのダウンロード
wget "https://git.samba.org/samba.git/?p=samba.git;a=blob_plain;f=examples/smb.conf.default;hb=HEAD" -O /etc/samba/smb.conf

# smb.confのバックアップ
cp -p /etc/samba/smb.conf /etc/samba/smb.conf.bkup

# smb.confの変更
vim /etc/samba/smb.conf
>>> smb.conf変更内容 >>>
# Global Settings > [global]ブロックの変更
## ログファイルの指定を以下に変更（55行目）
log file = /var/log/samba/%m.log
## プロトコルに関する設定を追加（110行目）
## （スマホから接続可能にするために必要だった）
server min protocol = LANMAN1

# Share Definitions > [homes]ブロックに以下を追加（117行目以降）
   valid users = %S

# Share Definitions 末尾に [share]ブロックを追加
[share]
path = /nas/samba
read only = no
browsable = yes
writable = yes
guest ok = yes
<<< smb.conf変更内容 <<<
```

#### sambaサービスの起動設定
```sh
# OS起動時に自動起動させる設定
systemctl enable smb
systemctl enable nmb

# サービスの起動
systemctl start smb
systemctl start nmb

# 起動確認
systemctl status smb
systemctl status nmb
```

#### 動作確認
- WindowsPCがあれば、エクスプローラーの上部ウィンドウにSambaを導入したPCのアドレス（プライベートIPアドレス）を入れる
    - ¥¥192.168.XXX.XXX¥share などで接続する
- スマホの場合、アプリ（AndroidならFile Commanderなど）をインストールして動作確認を行う
無事共有フォルダを開けたらOK！

**接続できない場合**
設定手順を間違えていないかを確認。
ファイアーウォールを設定している場合、SAMBAが使っている以下のポートを開けていないと接続できない場合がある。
UDP｜137, 138
TPC｜139, 445


以上

# 関連記事
- [NASNEを自作してみた](https://qiita.com/hirmr/items/cde0baf51d82ca9de791)
archlinuxにHDDを接続する

# はじめに
この記事はarchlinuxにHDD（SSD）を接続する手順紹介（備忘録）です。NAS用に10TBのHDDを接続しました。
HDDならではの点としては一定時間接続がない場合に回転を止める設定あたりかと思います。
※元作業の関係上、基本的にルートユーザーで作業を行っています。

# HDDのマウント
#### HHDを接続（物理的に）
PCにHDDを接続します。

#### 必要なパッケージのインストール
```sh
pacman -S --noconfirm gdisk parted arch-install-scripts
```

#### パーティションの作成
```sh
# ディスクパーティションの確認
fdisk -l
（外付けHDDのデバイス名を確認する。今回は/dev/sdb）

# ディスクパーティションの初期化
wipefs -a /dev/sdb

# ディスクパーティションの作成
gdisk /dev/sdb
>>> gdiskの対話的操作 >>>
n #新規作成
1 #パーティション番号
2048 #開始セクター
19532806143 #終了セクター（デフォルト値でOK）
8300 #パーティションの種類?を指定するらしい
w #上記の設定内容を保存する
Y #上書きますか？的なメッセージが出た場合Yes
<<< gdiskの対話的操作 <<<

# 再起動せずにパーティションテーブルの変更を読み込む
partprobe

# パーティションのフォーマット
mkfs.ext4 /dev/sdb1
```

#### マウント
```sh
# マウントポイントの作成
mkdir /nas

# 確認
ls -ld /nas

# マウントする
mount /dev/sdb1 /nas

# 確認
df -h
```

#### fstabの設定
fstabに設定すると、再起動しても自動的にマウントされる様になります。
```sh
# 現在のfstabの確認
cat -n /etc/fstab

# fstabのバックアップ
cp -p /etc/fstab /etc/fstab.bkup

# fstabに/nasのマウント状況を追記
genfstab -U /nas >> /etc/fstab

# fstabの確認
cat -n /etc/fstab

# fstabを修正する
vim /etc/fstab
>>> 修正後fstab >>>
# 5, 8, 11 行目はデバイス名だったのを用途に変更（分かりやすくするため）
# 12 行目はマウントポイントを / から /nas に変更
 1	# Static information about the filesystems.
 2	# See fstab(5) for details.
 3
 4	# <file system> <dir> <type> <options> <dump> <pass>
 5	# Default storage
 6	UUID=fbdefb39-48b7-4007-9cac-bf01154e2774	/         	ext4      	rw,relatime	0 1
 7
 8	# Boot storage
 9	UUID=9A98-0486      	/boot     	vfat      	rw,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=ascii,shortname=mixed,utf8,errors=remount-ro	0 2
10
11	# HDD 10TB
12	UUID=75be041d-e19d-4512-92fa-32b02aea004e	/nas         	ext4      	rw,relatime	0 1
13
<<< 修正後fstab <<<
```

#### 再起動してHDDが読み込まれることを確認する
```sh
# 再起動
reboot

# ファイルシステムに追加されていることを確認する
df -h
```

#### 一定時間でHDDをスリープ状態にする
設定しないと ウィーン とHDDが回りっぱなしだったので設定しました。

```sh
# hdparmをインストールする
pacman -S --noconfirm hdparm

# Advanced Power Managementの設定値を確認する
hdparm -B /dev/sdb

# 127に設定する
hdparm -B 127 /dev/sdb

# タイムアウトを設定する
hdparm -S 60 /dev/sdb

# 設定の永続化をする
vim /etc/udev/rules.d/50-hdparm.rules
>>>
# 5分間使用がなければOFFる様に設定（5秒 * 60 = 300秒 = 5分）
ACTION=="add", SUBSYSTEM=="block", KERNEL=="sdb", RUN+="/usr/bin/hdparm -B 127 -S 60 /dev/sdb"
<<<
```

以上

# 関連記事
- [NASNEを自作してみた](https://qiita.com/hirmr/items/cde0baf51d82ca9de791)
RubyからJavaに移行する時の考え方

# 主な違い
今までrubyを学習してきて、仕事でjavaを使うことになりました。
rubyと違うところがあったので、自分なりにまとめてみたいと思います。

`Java`コンパイラによってコンパイルされる静的型付け言語
`Ruby`インタプリタによって解釈されるスクリプト言語で、動的型付け言語

上記が一般的に説明されている説明となります。

自分の言葉で説明すると、
`Java`は型を宣言するのでコードが長くなるが、大規模開発などたくさんの人が関わる開発に向いている。習得の難易度は`Ruby`よりも高め。`Ruby`は、型を宣言する必要がなく短くて直感的にコードを書ける。アジャイル開発に向いている。習得の難易度が低いことや、日本語のドキュメントが充実しているので、プログラム初心者に向いている。

# システムの違い

サーバーやデータベースの違いについて、表を作りました。（下記）

[]()![JavaとRailsの比較最終-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661107/f5f88309-fa20-a8c8-5972-cb9cf7bec0d9.png)

|  | Ruby | Java |
|:-:|:-:|:-:|
|   |  Railsサーバー |  Tomcat |
|   |  Controller |  Controller, Service(ビジネスロジック) |
| | Model| DAO,DTO|
|| ERB| Thymeleaf|

**ServiceやDTO,DAOに関しては勉強中のため、認識に誤りがありましたらご指摘くださいませ。

二つの言語に違いがありますが、大まかな
「ユーザーから受けたリクエストをHTTPメソッドでサーバーに送ってデータベースと情報をやりとりしてレスポンスを返す」
という流れは同じでした。
大きく違いを感じたところとしては
- Rubyではクエリの発行はActiveRecordで自動的にやってくれていたが（Post.allと書くだけでできるみたいな感じ）、JavaではSQLを自分で書かないといけない
- HTMLを書いているときに、eclipseで書いていたのですが、毎回ビルドしないとブラウザに反映されない。
- Javaはとにかく記述量が多い！

## 具体的な書き方の違い
#### Javaは事前に型宣言が不要
```ruby:ruby
number = 1000
name = "Qiita"
```
```java:java
int number = 1000;
String name = "Qiita";
```

#### 変数展開
```ruby:ruby
"私の名前は#{name}です"
```
```java:java
"私の名前は" + name + "です"
```

#### if文
```ruby:ruby
 if A > B
   #処理A
　　elsif B == c
   #処理B
 else
   #処理C
 end
```
```java:java
if (A > B){
//処理A
} else if (B == C){
//処理B
} else {
//処理C
}
```

#### 配列
```ruby:ruby
nums = [1, 2, 3]
nums[0]
```
```java:java
int nums[] = {1, 2, 3};
nums[0];
```

#### メソッド
```ruby:ruby
def sum(a, b)
  return a + b
end

num = sum(1, 2)
```
```java:java
public static int sum(int a, int b){
  return a + b;
}
int num = sum(1, 2);
```

#### クラス
```ruby:ruby
class Car
  #処理
end

police_car = Car.new
```
```java:java
class Menu{
//処理
}

Car police_car = new Car();
```

# まとめ
RubyからJavaに切り替えて本当に思ったのは、

「Rubyってめっちゃ簡単なんだな！」ということ。

Rubyで考えていなかったこと（考えなくても良かったこと）をJavaではすごく考えないといけないので、

処理の流れだったり、型がどうなっているのか意識するようになりました。

これからはJavaで学んだこと、気づき、大変だったことなど投稿していこうと思います。
【情報処理安全確保支援士】午後対策

# Webサービス

## HTML

### 検索エンジンでの検索対象にしたくない

``` html
<meta name=”robots” content=”noindex” />
```

### 検索エンジンにリンクを辿れせない

``` html
<meta name=”robots” content=”noindex,nofollow” />
<meta name=”robots” content=”none” />
```
※上記２つは一緒

## DNS

## TTL（Time To Live）
生存時間、残存期間という意味の英語表現で、ITの分野ではデータの有効期限、破棄されるまでの残り時間などを表す。

## スマートフォンの管理

スマートフォンは、勝手に使われるではなく、盗まれるを前提に考える

## 不正アクセス可能な期間
実際に不正アクセスする準備が整って、不正アクセスを開始する直前タイミングからではなく、
理論上不正アクセス可能になっている期間

## 証明書へのパスフレーズの設定

記憶と保持の２要素認証のため


## XSS

```
javascript: ....
```
での攻撃もある。
この場合、タグがないのでサニタイジングは有効に機能しない。
それが、URLを入力するフィールドでも、URLエンコーディングはダメみたい。
http://,https:// から始まるものに限定しないといけないみたい。


## HTMLの属性設定

`Access-Control-Allow-Origin`とか`Content-Securtity-Policy ` とかの時に
うっかりドメインって書かない。オリジンって書く。

## Content-Security-Policy

```
Content-Security-Policy: script-src 'self' https://foobar.com
```

同一オリジンかhttps://foobar.comのオリジンのスクリプトのみを実行可能にする


## SIEM

シーム。
SIEM（Security Information and Event Management）とは、ファイアウォールやIDS／IPS、プロキシなどから出力されるログやデータを一元的に集約し、それらのデータを組み合わせて相関分析を行うことにより、ネットワークの監視やサイバー攻撃やマルウェア感染などのインシデントを検知することを目的とした仕組みです。

## リバースブルートフォース攻撃

IPアドレスを変えながらってかけばいい。
ボットネットとかIPスプーフィングとか書かなくていい

## FIDO

MITM攻撃に注意する
そのため、originの情報付与したディジタル署名を使う

## リスクベース認証

いつもの端末からのログインかのチェック

- IPアドレスから位置情報を算出
- Cookieの情報をチェック

## DHCPサーバ

IPアドレスが設定できない場合
- IPアドレスの枯渇

### 接続までの手続き

- CLIENT -> ALL:DHCP DISCOVER
    - 誰かIPわりあてて
- Server -> CLIENT:DHCP OFFER
    - これでどう？
- CLIENT -> Server:DHCP REQUEST
    - OK設定して
- Server -> CLINET ：DHCP ACKNOWLEDGE
    - OK設定した






ミラーポート

スイッチのパケットのはキャプチャする
Stable Diffusionで「桃太郎」を実写化してみた。

# 概要
いま流行りのStable Diffusionで「桃太郎」を実写化してみた。


# 実写化

## シーン１（最初に桃が流れてくるシーン）

### text
One huge peach washed up in a river in the forest.

### 画像
![One huge peach washed up in a river in the forest._0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/473789/7d82e1d6-f38f-4c8b-75df-24b5c47fe789.png)

### コメントなど

* いままさに、流れてはいないが、演出上、許容範囲か。（他のシーンの方が厳しい。） 

## シーン２（キビ団子を準備するシーン）

### text
I unfolded my straw bag and stuffed many dumplings into it.

### 画像
![I unfolded my straw bag and stuffed many dumplings into it._0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/473789/0b928ec5-7906-a584-d2c4-cd24607173a6.png)

### コメントなど

* 近代的なものが一応入っていないのでOKとした。30点ぐらい。

## シーン３（家来（動物）と鬼ヶ島に移動するシーン）
### text
In the heavy rain, I watched the back of the pheasant and the dog I placed on the bow of the wooden boat.
### 画像


![In the heavy rain, I watched the back of the pheasant and the dog I placed on the bow of the wooden boat._6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/473789/5e4373d5-de8e-d0ba-a646-b89eb1870adf.png)

### コメントなど

* 本当は、猿も必要だが、「Stable Diffusion」で、同時に3種類上手く集まってくれなかったので、シナリオを修正し、猿は後から合流にした。
* <font color="orange">演出のため、雨を降らした。</font>(参考記事をパクった。）





# 参考
↓　以下の記事の画像をみて、面白そうと思ってやってみた。

https://ai-de-seikei.hatenablog.com/entry/2022/08/27/235423

# 全体コメント
アドバイスや、コメントなどあれば、お願いします。

>テスト

>テスト
テスト
Android 指定した文字をクリップボードにコピーする

今回は指定した文字をクリップボードにコピーする方法です。

ボタンを押した後に、特定の文字をコピーさせたい。みたいな場合に使用することができます。


```MainActivity.kt
    /**
     * クリップボードにコピーする。
     *
     * @param context     コンテキスト
     * @param copyText     コピーする文字列
     */
    private fun copyClipboard(context: Context, copyText: String?) {
        val clipboardManager: ClipboardManager = context.getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
        clipboardManager.setPrimaryClip(ClipData.newPlainText("", copyText))
    }
```

こちらでcopyTextに渡した文字がコピーされます。

以上です。
【PowerApps/Dynamics】SharepointOnline連携ができない時

「Microsoft Dynamics 365 リスト コンポーネント がインストールされていません。」
と警告が出てSharepointOnline（SPO）とPowerAppsが連携できないやん！ってなったことがあります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2524942/e2d40b79-4a58-5362-9625-c1d60c631b28.png)
<img src="blob:chrome-untrusted://media-app/08add384-19cc-4873-9f79-b80beed86751" alt="Screenshot 2022-08-28 16.07.44.png"/>



結論としては手順が間違っています
上記の操作ではシェアポサイトとテーブルを結びつけるよって操作だが
そもそもシェアポサイトが有るってことを事前に登録しておく必要があります

その操作が下記です

https://qiita.com/sho-sun/items/36f160d72b878880a39f
【webpack】出力の管理

この記事では、ビルドされたファイルや、`index.html` ファイルの出力をカスタマイズする方法を紹介します。

なお、より詳しく知りたい場合は、[公式ドキュメント](https://webpack.js.org/guides/output-management/)を参照するのをおすすめします。

## 前提条件

以下手順を実施済み

[【webpack】webpack の導入](https://qiita.com/onkz/items/368535611379d1630c67)

## 複数のエントリポイント

webpack では、エントリポイントを追加することで、複数のバンドルを出力することが出来ます。

試しに `print.js` ファイルを作成して、エントリポイントを複数に分割してみます。

### 1. `print.js` の作成

`src` ディレクトリ直下に作成します。

```js:print.js
const print = () => {
  console.log('I get called from print.js!');
}

const btn = document.createElement('button');
btn.innerHTML = 'Click me and check the console!';
btn.onclick = print;

document.body.appendChild(btn);
```

### 2. `webpack.config.js` の修正

次に、設定ファイルを修正してエントリポイントごとにバンドルが出力されるようにします。

```js:webpack.config.js
const path = require('path');

module.exports = {
  entry: {
    index: './src/index.js',
    print: './src/print.js'
  },
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist'),
  }
};
```

:::note warn
`output` > `filename` > `'[name].bundle.js'` の `[name]` は、`entry` フィールドのキー名が使用されます。
:::

### 3. `index.html` の修正

読み込むJavaScriptファイルを修正します。

```html:index.html
...
<body>
  <script src="./index.bundle.js"></script>
  <script src="./print.bundle.js"></script>
</body>
...
```

### 4. ビルドの実行とテスト

ビルドコマンドを実行します。

```cmd
> npm run build
```

最後に、ブラウザで `index.html`  ファイルを開き、表示されたボタンをクリックしてコンソールを確認します。問題なければ、「I get called from print.js!」と表示されているはずです。

## `index.html` ファイルを動的に生成する

ここまでで、複数のエントリポイントを作成し、読み込むことが可能であることを確認しました。しかし、例えばエントリポイントを追加したり、出力されるファイルの名前を変更した場合、 `index.html` ファイルも手動で修正する必要があります。

この手順では、上記問題を解決する為、`HtmlWebpackPlugin` プラグインを使用して、webpack の設定を基に `index.html` ファイルを動的に生成する方法を紹介します。

### 1. プラグインのインストール

```cmd
> npm i -D html-webpack-plugin
```

### 2. `webpack.config.js` の修正

```js:webpack.config.js
...
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  ...,
  plugins: [
    new HtmlWebpackPlugin({
      title: 'Document'
    }),
  ],
	...
};
```

### ビルドの実行とテスト

ビルドコマンドを実行します。

```cmd
> npm run build
```

`index.html` をテキストエディタなどで開き、既存のファイルと異なるファイルが出力されていることが確認できれば成功です。

より詳しい設定オプションについては、[`html-webpack-plugin` のリポジトリ](https://github.com/jantimon/html-webpack-plugin#options)で確認できます。

## `dist` ディレクトリのクリーンアップ

`output` フィールドに `clean: true` オプションを追加することで、`dist` ディレクトリの中身が使用されるファイルのみとなるよう、`webpack.config.js` を修正します。

```js:webpack.config.js
...

module.exports = {
  ...,
  output: {
    ...,
    clean: true
  }
};
```

`npm run build` を実行して、不要なファイル（例えば `main.js` など）が削除されていれば成功です。