OmniAICreator/Qiita-1.07M huggingface dataset:
Chromeドライバー更新問題を解決

:::note info
**この記事によって実現できること**
Python SeleniumによるスクレイピングでChromeドライバー更新地獄から開放
:::

# はじめに
こういう悩みありませんか？
Python × Selenium × Chromeでブラウザ操作自動化をしてるけど、ブラウザバージョン更新のたびにChromeDriverを手動で更新するのが面倒。。。

```python:qiita.py
from selenium import webdriver
 
driver = webdriver.Chrome()
driver.get('https://google.com')
```
しかし、Google ChromeがアップデートされるたびにChromeDriverとのバージョン違いでエラーになってしまいます。（SessionNotCreatedEception）

```console
$ python qiita.py
Traceback (most recent call last):
File "/ファイルのパス/qiita.py", line 4, in <module>
driver = webdriver.Chrome()
File "/opt/anaconda3/lib/python3.7/site-packages/selenium/webdriver/chrome/webdriver.py", line XX, in __init__
〜省略〜
selenium.common.exceptions.SessionNotCreatedException: Message: session not created: This version of ChromeDriver only supports Chrome version XX
```
これが出るたびに下記作業をしなければなりません。
***
1. 現在のブラウザバージョンを確認
2. 現在のブラウザバージョンに合ったWebDriverをダウンロード/インストールする
***
実は、「webdriver_manager」というライブラリを使うことで面倒臭い手作業から永遠に開放されるんです！
しかも、すでに使用しているコードでもすぐに修正できちゃいます！

# ChromeDriver(WebDriver)を自動更新する「webdriver_manager」導入方法
:::note info
**やること**
①webdriver_managerをインストール
②コード編集
:::

## ①webdriver_managerをインストール
```console
$ pip install webdriver-manager
```
上記コードを打ち込んじゃいましょう。
```console
〜省略〜
Successfully installed　〜〜
```
が出てきたら完了です！

## ②コード編集
次にコードを書き換えましょう！

```python:before.py
from selenium import webdriver
 
driver = webdriver.Chrome()
driver.get('https://google.com')
```
↓
```python:after.py
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
 
driver = webdriver.Chrome(ChromeDriverManager().install())
driver.get('https://google.com')
```
たったこれだけなんです！

Chromeドライバー更新地獄からの脱出おめでとうございます！

:::note info
**この記事によって実現できること**
Python SeleniumによるスクレイピングでChronmeドライバー更新地獄から開放
:::
今年読んだお勧めの本！「エッセンシャル思考」「エフォートレス思考」の紹介

# 伝えたい事：
他人の思考を知ることで、自分の思考を俯瞰できる。
ついでに「身近なあの人」の思考に思いを馳せることができる！
多くの人の思考を知るのは大変だけど、本なら簡単に多くの人の思考を知ることができる。
また、本の続編には著者の人生が垣間見える。
----

**「エッセンシャル思考」著者：グレッグ・マーキュン、訳：高橋璃子**
**「エフォートレス思考」著者：グレッグ・マーキュン、訳：高橋璃子**

「エッセンシャル思考」は2014年11月に出版され世界でバカ売れした！
「エフォートレス思考」は「エッセンシャル思考」の第2弾として2021年12月に出版。


## 「エッセンシャル思考」の一部から

- 「何をあきらめる」ではなく、「何に全力を注ごうか？」と考える
- 「何でもできるが、全部はやらない」

この考え方は小さな違いだけど、積み重なると大きな違いになる。


###### 1 見極める
###### 2 捨てる
###### 3 しくみ化する

不要なものを捨てて人生をシンプルにする。

「何に全力を注ぐか？」

例えば
お客様に自分たちの価値を提供し続けることに全力を注ぐ場合
※「サービス」が価値で有れば「サービス」を提供し続ける

- 完璧を目指すより、終わらせろ
- 早く小さく始める
- 進歩を目に見える形にすること
- **今何が重要か？**
- 最小の時間で成果を最大にする


## 「エフォートレス思考」の一部から

「エッセンシャル思考」の思考を進化させた「エフォートレス思考」。
「必要不可欠」だけでも、バケツが溢れる状況が発生した。


### 「エフォートレス」の真意は？

グレッグ・マーキュンにとって「エッセンシャル思考」出版後に大きな変化があった。
娘の難病。
変わっていく娘を受け入れる。
考えてもどうにもならないこと、努力しても叶わないことを受け入れる必要があった。

人間にはどうにもならないことがある。
どうにもならないことを見極め、受け入れる。
「エフォートレス」は「現実を受け入れる」こと。
「現実を受け入れる」で見えることがある。
「エフォートレス」により物事で進めることがある。


# おわりに

自分のベースとなる家族という土台がぐらつく中、著者が行き着いた「エフォートレス思考」。
そんな背景を踏まえて再度「エッセンシャル思考」から「エフォートレス思考」への変化を読んでみると自己啓発本以上の気づきがあるかも。
親が子を想う気持ちが伝わってきて、翻訳本であるが言葉以上の「思い」を感じることが出来る。
MDR とは

## 勉強前イメージ

セキュリティ系のなにか？

## 調査

### MDR とは

Managed Detection and Response の略で、
EDRの運用やマルウェアの検知・解析、インシデントの初動対応を行うマネージドサービスのことを指します。

そもそもEDRとはパソコンなどで不審な挙動を検知して対応を支援するソフトウェアの総称です。
比較的新しい定義で常に監視して検出した際は管理者へ報告が行きます。
詳細は [こちら](https://qiita.com/miyuki_samitani/items/c3cf2961fcd72a2f86ae) をごらんください。

しかし、EDRを入れただけではだめでユーザ側がEDRを使いこなしたり専門知識を取得して
継続的にモニタリングや初動対応の体制を整える必要があります。
いつ発生するかわからない攻撃への対応について少人数であれば体制を整えるのも難しいかもしれません。
そこでそれを解決するのがMDRです。

MDRはマネージドサービスのEDRのことで、EDRをアウトソーシングすることができるものになります。

### MDRの種類について

MDRには2つの種類があります。

- セミマネージド型のMDR

検知や事象の分析はもちろん行いますが、インシデント対応の一部を請け負い最終判断はユーザに委ねる方法です。
一時的な対処は行いますが、今後どう進めていくかはユーザ側という分け方があります。
しかしこの分け方についてはベンダーごとに色々あります。

- フルマネージド型のMDR

検知や事象の分析はもちろん行いますが、脅威を封じ込めるための技術の対応も行う種類です。
ユーザと相談しながら技術対応を行います。

## 勉強後イメージ

もし社内にセキュリティ詳しい人いない・・・とかあればMDRも選択肢の一つってことですね。

## 参考

- [MDRとは？セキュリティ運用の重要性とSOCとの違いについて解説](https://www.gate02.ne.jp/media/it/column_91/)
- [https://www.nec-solutioninnovators.co.jp/ss/insider/security-words/60.html](https://www.nec-solutioninnovators.co.jp/ss/insider/security-words/60.html)
vimの設定メモ

vimの設定メモ。

# _vimrc

```
set ai
set nu
set sw=4
set ts=4
```

## 自動生成されるファイルの抑制

```
"アンドゥファイルを作成しない。
set noundofile
"バックアップファイルを作成しない。
set nobackup
"スワップファイルを作成しない。
set noswapfile
"viminfoファイルを作成しない。
set viminfo=
```

## 文字コード自動判別
```
"文字コード自動判別
set encoding=utf-8
set fileencodings=utf-8,sjis,euc-jp,iso-2022-jp
```

## 改行コードの自動認識
```
"改行コードの自動認識
set fileformats=unix,dos,mac
```

## ステータスバーを非表示にする。
```
"ステータスバーを非表示にする。
set laststatus=0
```

## 拡張子別に色テーマを設定
```
autocmd FileType text colorscheme morning
autocmd FileType markdown colorscheme darkblue
```

# _gvimrc

## フォント

```
set guifont=ＭＳ_ゴシック:h12
```
配列の上位k点のインデックスを取得する

# やりたいこと
題名の通り配列の上位k点のインデックスを取得する

##コード
[ChatGpt](https://chat.openai.com/chat)さんにお願いしたら書いてくれた
```python:test.py
import heapq

# 配列
arr = [2, 5, 3, 7, 1, 8, 4]

# 上位k個のインデックスを取得する
k = 3

# indices = heapq.nlargest(k, range(len(arr)), arr.__getitem__)
#上の方の式が元々出力されたものだったが私にはarr.__getitem__が馴染みなかったのでlambda式で置き換えた
indices = heapq.nlargest(k, range(len(arr)), key = lambda x: arr[x])

# 結果を表示
print(indices)  # [5, 3, 1]

```

##### 軽い説明
そもそもの`heapq.nlargest`は
>heapq.nlargest(n, iterable, key=None)
Return a list with the n largest elements from the dataset defined by iterable. key, if provided, specifies a function of one argument that is used to extract a comparison key from each element in the iterable: key=str.lower Equivalent to: sorted(iterable, key=key, reverse=True)[:n]

というふうに説明されていて
`heapq.nlargest(k, data, key)`
k: 取得したい値の個数
data: 対象
key: 比較するもの
となっている

今回は上位k点の値ではなくインデックスが欲しいので
`data=配列のインデックスの範囲`
`key=それぞれのインデックスにおける配列の値`
としている

他にもdic型であるkeyに対応するvalueで上位k点が欲しい時は
```python:dict.py
import heapq

# データ
data = [    {"name": "Alice", "age": 20},    {"name": "Bob", "age": 25},    {"name": "Charlie", "age": 30},]

# 上位k個の要素を取得する
k = 2
largest = heapq.nlargest(k, data, key=lambda x: x["age"])

# 結果を表示
print(largest)  # [{"name": "Charlie", "age": 30}, {"name": "Bob", "age": 25}]

```
というようにかける



### まとめ
ちょくちょく必要になるけど毎回忘れてしまう処理に関してまとめました
ChatGPTめちゃくちゃ便利なのでこれからも使っていきたいです
[初心者]Prophetを使った時系列データ学習の奮闘記

初心者がMeta（旧Facebook）が開発した機械学習ライブラリを使用して、時系列データの機械学習に取り組んだ記録をまとめました。参考になればと思います。

記事が乱立してしまったので、このページで一覧にしました。
段階別にまとめています。

■第一段階
Prophetの導入と試運転（ライブラリのインストールに一番てこずった…）
[Python初心者が時系列データの学習](https://kissshot-skup.github.io/webpage/aiskillup/)



■第二段階
応用編
気象庁の過去データから将来の気温予測してみた
[Python初心者が時系列データの学習2](https://kissshot-skup.github.io/webpage/aiskillup2/)

■第三段階
活用編
電化製品の販売台数の予測をしてみた（食洗器が欲しかったので...）
[食洗器の販売台数を機械学習で予測!](https://kissshot-skup.github.io/webpage/aiskillup3/)
![yosokukekka.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2639414/f538b5f9-33a8-d4ba-3819-4788bff2d332.png)

結果的に、食洗器はサブスクでリースすることにしました。
本当に使えるか試してみてからの方がよいよね。。。（笑）

閲覧ありがとうございました。
Javaのローカル変数の冗長について調べてみる

# はじめに
こんにちは、こんばんは、ココネ株式会社のサーバーを担当しています。
本ページではJavaを書いていてスタイルチェッカーで指摘されるローカル変数の冗長化について調べてみたことを書きます。

# Javaコード
以下のコードをまずは見てみます。
単に足し算するだけのaddtion methodがあるシンプルなコードです。

```Java
public class Calculation {
    public static void main(String[] args) {
        int x = 1;
        int y = 2;

        int answer = addition(x, y);
        System.out.println(answer);
    }

    public static int addition(int x, int y) {
        int answer = x + y;
        return answer;
    }
}
```

# コードチェッカーにローカル変数が冗長と注意されます

```Java
int answer = x + y;
return answer;
```
この部分は、answerに一度結果を格納してreturnしているのですが、チェッカーでは冗長と指摘されます。
以下のように修正できます。

```Java
return x + y;
```
answerに格納せずに直接returnする形です。
確かにすっきりします。
が、今回のSampleのように単純な足し算の式でしたらこれでもすぐに何を行っているのか理解はできます。
ただもっと複雑な処理や別の業務ロジックを行うmethodの呼び出しと組み合わせている場合は、一度ローカル変数に格納されてその変数名がわかりやすい名称であれば処理の内容が理解しやすいかもしれません。（このあたりは個人の好みやチームのコーディングルールが変わってくると思います）

# バイトコードはどのようになっているのか？
それぞれローカル変数に一度格納した場合、格納しなかった場合にわけてバイトコードを出力させてみました。

- ローカル変数に格納した場合
```
  public static int addition(int, int);
    Code:
       0: iload_0
       1: iload_1
       2: iadd
       3: istore_2
       4: iload_2
       5: ireturn

```

- ローカル変数に格納しなかった場合
```
  public static int addition(int, int);
    Code:
       0: iload_0
       1: iload_1
       2: iadd
       3: ireturn
```

ローカル変数に格納した場合は、
`2: iadd`で足し算を行った後に`3: istore_2`でスタックに一度、storeします。それを`4: iload_2`でloadしてreturnする処理です。

それに比べてローカル変数に格納しなかった場合の方が、処理数が減っています。
足し算を行った後にスタックに積まれている結果をすぐにreturnしています。
バイトコードを見ても後者の方が速そうです。

# 実際に複数回実行して速度を比較してみました
足し算するだけの単純な処理なので1000万回ループさせて、その結果10回の平均値を取ってみました。

| ローカル変数あり | ローカル変数なし |
|-----------:|------------:|
|       5.3ms|        4.6ms|

当たり前と言っては当たり前なのですが、ローカル変数なしの方が速い結果となります。

# まとめ
厳しいメモリ環境や少しでもステップ数を少なくコーディングしないといけない組み込み系ではあたりまえな考えなのかもしれませんが、普段JVMで動く言語のコーディングしているとバイトコードまで意識してコーディングすることは少ないかもしれません。ただちょっとした書き方の変更しだいで処理速度があがることを知っておくことは有効かと思いました。
自己紹介 ~たまご🥚から孵化して最強ピヨピヨ🐣になる予定系大学生~

# 自己紹介
初めまして。現在、情報系の大学に通っているだいちと言います。  
これから、そろぼちプログラミングを頑張ろうと思って登録しました。  
授業などでしかプログラミングに触れたことがなく、授業ではpython,C,javaを扱いました。しかし、本当に授業でしか触れたことがないので🥚よりも酷いレベルです。これから１年かけて頑張っていこうと思います。
よろしくお願いします。

# 年内までの目標
まずは何か成果物を作成してモチベーションを高めたい！！
実際にアプリケーションを一人で作ったことがないので
### 「Webアプリケーションを年内までに作る！！」
ということを目標に頑張っていこうかなと思います。
そのため、毎日どれくらい勉強をしたかを日記程度に書いていこうかなと思います。
とりあえず今後も授業や研究などで触りそうなpythonに触れながら頑張っていこうかなと思います。

# 最後に
これから自分の日記程度に進めていくともに、もし仮に自分みたいに飽き性かつプログラミング全くやったことない人の希望になれたらな思い、3日に1回のペースで書いていきたいなと思います。よろしくお願いします。
ハードフォーク とは

## 勉強前イメージ

フォークってgitでも同じ名前あるよね？
なんか一緒の意味なのかな・・・・

## 調査

### ハードフォークとは

システムの仕様変更が行われる新しい派生システムが作られる際に、旧システムと互換性がない形で行われることを指します。
ハードフォークが行われると、新旧別のシステムが共存することになります。

ちなみに、 `ソフトフォーク` もあり、こちらは派生システムが互換性を保ったまま作られることを指します。
違いは互換性の有無ですね。

ハードフォークと調べてビットコインが出てくるのは
ビットコインからのハードフォークでビットコインキャッシュが出てきたためである。

## 勉強後イメージ

調べた時いっぱいビットコイン出てきて関係あるんかと思ったら、そういうことじゃなかったのね。

## 参考

- [ハードフォーク](https://www.sophia-it.com/content/hard-fork)
Blender 自作シェーダー(OSL)で簡単なトゥーンシェーダー

BlenderでOSL(Open Shading Language)を使用して、簡単なトゥーンシェーダーを実装してみようと思います。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/368850/5b1e7396-8416-2e5b-5a40-b6a88d4496a7.png)
イメージとして以下の図のような感じです。
ベクトルのなす角(θ)が小さければモデルを明るくし、大きければ暗くします(サンプルは少し違いますが・・・・)。
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/368850/8eb73156-0429-070d-ee61-48be58f3db6f.png)


# シェーダー
```HLSL
shader toon_shader(
    //テクスチャ
    color texture_color = color(0.0,0.0,0.0),
    //法線
    normal n = N,
    //ライトの方向
    vector light_direction = vector(1.0,1.0,-1.0),
    //ライトの色
    color light_color = color(1.0,1.0,1.0),
    //最終的なカラー
    output color final_color  = color(0.0,0.0,0.0)
)
{
    final_color = texture_color;
    color light = color(0.0,0.0,0.0);
　　 //ライト方向を正規化。
    vector light_dir = normalize(light_direction);
    
    //法線とライトの方向からランバート拡散反射光を計算。
    float lambert = clamp(dot(-n,light_dir),0.0,1.0);
    lambert *= lambert;
    //値を一定値で分ける。
    if(lambert > 0.15)
    {
        lambert = 1.0;
    }
    else 
    {
        lambert = 0.3;
    }
    light += light_color * lambert;
    
    //計算したライティングの値を乗算。
    final_color *= light;
}
```

# ノード
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/368850/5a884775-4000-5552-5280-d1fe05721e68.png)
リプレイ攻撃 とは

## 勉強前イメージ

何回も何回も攻撃してくること？

## 調査

### リプレイ攻撃 とは

不正アクセスの一つで通常のログインユーザの通信を盗聴し
その情報を `そのまま` 使ってログインしてなりすます方法になります。

しかし、基本的にはログイン時に通信されるのは暗号化していることが多いです。
その際に盗聴したデータを平文に戻してログインするのは、よく考えるような不正アクセスの方法になります。
ですが、リプレイ攻撃というのは上記に書いたように `そのまま` 使用します。
暗号化されたデータを解析せずに、暗号化されたまま使用してログインするというものになります。

イメージとしては以下になります。
ログイン時に使われた情報を盗聴者は分からないが
同じ情報をつかってログインすることになります。

![12022-12-04 # リプレイ攻撃 とは - diagrams.net - Google Chr.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129517/887ae37f-4ba6-461c-ffa6-9adf7373b9cd.png)

### リプレイ攻撃 を防ぐには

リプレイ攻撃を防ぐためにはワンタイムパスワードやタイムスタンプなどを混ぜて
再度使おうとすると使えないようにするような対策が必要です。

## 勉強後イメージ

確かに、「そのまま」データを使ってログイン使用するってことか。

## 参考

- [反射攻撃【replay attack】リプレイアタック / 再生攻撃](https://e-words.jp/w/%E5%8F%8D%E5%B0%84%E6%94%BB%E6%92%83.html)
- [【入門】リプレイ攻撃と対策は？](https://www.mtioutput.com/entry/replay-attack-tutorial)
[Vagrant][VirtualBox] Vagrantが起動しない The guest machine entered an invalid state while waiting for it to boot 解決法





# 概要

Vagrant を経由してVirtualbox を使用すると
起動しないことがある


```
$ vagrant up
..

The guest machine entered an invalid state while waiting for it
to boot. Valid states are 'starting, running'. The machine is in the
'unknown' state. Please verify everything is configured
properly and try again.

If the provider you're using has a GUI that comes with it,
it is often helpful to open that and watch the machine, since the
GUI often has more helpful error messages than Vagrant can retrieve.
For example, if you're using VirtualBox, run `vagrant up` while the
VirtualBox GUI is open.

The primary issue for this error is that the provider you're using
is not properly configured. This is very rarely a Vagrant issue.
```


# 原因

Vagrant というVirtualbox VM側に問題があるため
Virtualbox managerを開いてVMの状態を確認

( VM単体というよりも
ファイル共有用のprocess とかVagrantで指定した+αのもので時間がかかっている気がする


# 解決法

自分の場合は、以下で動くことが多い

Virtualbox managerをGUIで開いて Runningとなっているのを 右click ->close ->`shutdown`

ようはVM自体 をshutdownしてrestart

( 念の為、timeout を伸ばしておく

```:Vagrantfile
Vagrant.configure("2") do |config|
    ...
    config.vm.boot_timeout = 1000 # timeout を伸ばす..
end
```

# 参考

https://stackoverflow.com/questions/19419563/vagrant-up-error-in-headless-ubuntu-the-guest-machine-entered-an-invalid-state
チーム開発におけるリファクタリング、基本のキ

[リファクタリングでシステムを安定化！日頃の取り組みや工夫を教えてください by カオナビ](https://qiita.com/advent-calendar/2022/kaonavi)カレンダー、4日目の記事になります。
今日あいていたので急遽寄稿させていただきます。

業務での開発におけるリファクタリングの基本について書こうと思います。

## リファクタリングとは

一応さらっと。

ソフトウェア開発における「リファクタリング」とは、外からのふるまいを変えずに、内部構造を変更（通常は改善）することを意味します。

上記カレンダーに記載のあるとおり、「可読性・変更容易性の向上、複雑度軽減、技術的負債解消、など」をさします。

注意しておきたいのは、 **何を「リファクタリング」と呼ぶかは個人差／チーム差がある** ということです。

というのも、厳密にいえば、外から見たふるまいを全く変えない変更というものは滅多にないからです。

配列をハッシュリストに変えれば処理速度に影響が出ます。
jsのバンドルサイズが変わればページのローディング時間に影響が出ます。
それを「ふるまいが変わっていない」と呼べるかどうかは、結局のところ個人の認知能力によります。

本記事では、おおむね **「ふるまいの変更ではなく、内部構造の変更を目的として行う改修」** くらいの位置づけでリファクタリングという言葉を使います。

## リファクタリングの王道

まずはリファクタリングを実施する際におさえるべきポイントです。

### まずテストを書く

リファクタリングの前後で挙動が変わっていないことを担保するため、まずはリファクタリング前の動作を検証するためのテストコードを書きましょう。

どの粒度のテスト（ユニットテスト／API テスト／E2Eテスト／スナップショット比較テスト）を書くかは、リファクタリングの深さによりケースバイケースだと思います。

「ここが変わっていなければ大丈夫なはず」というポイントを保証するためのテストを書きましょう。

### 機能の変更とリファクタリングはコミットを分ける

リファクタリングをする場合は、リファクタリングのみのコミットを残すようにし、他の機能追加やバグ修正を同じコミットに混ぜないようにしましょう。

コードレビューがしやすくなるだけでなく、後から何か問題が生じた場合に、リファクタリングのミスによるものかどうかの切り分けがしやすくなります。

### テスト済みのコードをリファクタリングしない

リファクタリングあるあるとして、コードに手を入れる本人は **「この修正で問題が起きるはずはない」という予測を過信しがち** です。

おおかたテストも終わり、リリースの直前になってから、どうしてもここの作りを直したいという衝動に駆られることもありますが、テスト済みのコードに対しては（再テストの工数を取れる場合でない限り）リファクタリングをしない、というルールを厳守すべきです。

リファクタリングによってバグが埋め込まれることは十分起こりうるということ、そうなったときは100%自分が悪く、誰も庇ってくれないということを肝に銘じましょう。

## その他Tips

実務の経験から、個人的に気にしたほうが良いと思うポイントを共有しておきます。

### 広範囲に手をつける前にコードレビューを依頼する

リファクタリングをする際は、コードの広範囲に手を入れることになる場合が多いでしょう。

全部終わってからコードレビューで「作りをこうしてしまうと問題がある」「こうやるよりこうしたほうがいい」という指摘を受けると、手戻りが大きく、無駄な作業が多く生じてしまいます。

リファクタリングに限らずですが、広範囲に手を入れる場合は、まず方針を決めた時点でチームメンバーにレビューを依頼し、認識をあわせておくのがベターです。

### 作業で競合が生じないことを確認しておく

リファクタリングで広範囲にコードの改修を行う場合、その影響範囲内で別の機能追加などを行おうとしているメンバーがいないことを十分に確認しておくべきです。

たとえ運用ルールとして、競合は後からプルリクエストを出した人が解消するものと定めていたとしても、自分が実装とテストを終えた箇所に対して、大きく作りが変わったので合わせてくださいと言われると精神的につらいものがあります。

あらかじめ、この範囲でリファクタリングをやりますので、影響しそうな箇所の改修は避けてくださいと伝えておくのをチーム仲のためにもおすすめします。

### リファクタリングに時間を使う承諾を得る

リファクタリングというのはエンジニア以外の人からの理解を得にくい作業のひとつです。

ユーザーから目に見える変更ではないと言われると、「本当にそれやる必要あるの？」「自己満足じゃないの？」という印象を受けられがちです。

ソフトウェアを運用・保守していく上で必要不可欠な作業であるということを理解してもらうため、日ごろから開発チーム外との意思疎通、もっというと開発目線での啓蒙活動が必要です。

また、局所的な改修だと思ったら、いざやろうとしたときに根本的なリファクタリングが必要なことに気づく、というケースも多々あります。
その際は、同じ開発チーム内であっても、あらかじめ「これを直そうと思ったら先にリファクタリングが必要で、それには○時間くらい必要そうだ」という情報を共有しておかないと、簡単な改修のはずなのに、なんでそんなに時間がかかってるんだ？と思われてしまうので注意が必要です。

### 他人のコードを直すときには根拠を明確にする

自分の書いたコードに対して、他の人から「リファクタリングしました」とだけ言われて書き直されていると気分のいいものではありません。

他の人が書いたコードをリファクタリングする場合には特に、なぜ今の作りだとだめで、なぜこう直すのか、というのを説明し、理解を得る努力をすべきです。

同じような問題のあるコードを再生産させないという意味でも必要な労力になります。

## 以上

用法・用量を守ってハッピー・リファクタリングを！
【JavaScript】JavaScript、はじめました。②変数と定数

※この記事は、プログラミング学習サイト「Progate」の学習内容に関するものです。

こんにちは、急に寒くなってきましたね。
ただ、電気代が上がりっぱなしなので、あまりエアコンを使いたいとは思えず･･･
<b><font color="skyblue">キンキンに冷えた冷蔵庫の中のビール</font></b>🍺のように冷えっ冷えにならないよう、
寒い部屋の中でダウンジャケットを着て、ヒートテックを上下着込んで、
プログラミング学習に今日も励んでおりますｗ

<font color="lightgray">･･･来年の今頃は、気兼ねなくエアコンを使えるようになりたいなぁ･･･（遠い目）</font>

さて、今日は第2回！ということで、
<b>【変数】と【定数】</b>についてまとめました。
自分が後から見直すとき、ピンポイントで探せるようにする意味でも、
小出し小出しで参りたいと思います。

<b>【変数と定数】</b>
<b>⑴　宣言のしかた</b>
　・変数 →　<b><font color="red">let</font> <font color="blue">【変数名】</font> = 【<font color="orange">文字列</font>・<font color=#0077ff>数値</font>】;</b> 
　・定数 →　<b><font color="red">const</font> <font color="blue">【定数名】</font> = 【<font color="orange">文字列</font>・<font color=#0077ff>数値</font>】;</b> 

変数・定数のどちらも、非常によく似ています。
･･･というか、<b><font color="red">let か const か</font></b> の違いしかありませんねｗ

<b>⑵　変数・定数を用いることで出来ること</b>
　①<b><font color="blue">【変数名】</font></b>または<b><font color="blue">【定数名】</font></b>に入力した文字列に対して、
 　　<b>【<font color="orange">文字列</font>・<font color=#0077ff>数値</font>】</b> に入力した文字列・数値を代入することができる
```:例①:
let name = "aogiri";
let number = 17;
```
```:例②:
const name = "aogiri";
const number = 17; 
```
　　※どちらも、<b><font color="orange">aogiri</font></b> は <b><font color="blue">name</font></b> に対して <b><font color="orange">文字列</font></b> として、
　　　 <b><font color=#0077ff>17</font></b> は <b><font color="blue">name</font></b> に対して <b><font color=#0077ff>数値</font></b> として、それぞれ代入されている

　② 上記を記入後、<b>console.log(<font color="blue">【変数名】</font>または<font color="blue">【定数名】</font>);</b> で、
　　<b><font color="blue">【変数名】</font></b>または<b><font color="blue">【定数名】</font></b>の文字列に代入された文字列・数値を、
　　　いつでも呼び出すことができる

```:例①:
　let name = "aogiri";
　console.log(name);

　→ コンソールに aogiri と出力
```
```:例②:
　const name = "aogiri";
　console.log(name);

　→ コンソールに aogiri と出力
```
　　※どちらも、1行目で <b><font color="blue">name</font></b> に文字列 <b><font color="orange">aogiri</font></b> を代入し、
　　　2行目で <b><font color="blue">name</font></b> に代入された文字列 <b><font color="orange">aogiri</font></b> を呼び出している

変数・定数のどちらも、非常によく似ています。
･･･というか、やはり <b><font color="red">let か const か</font></b> の違いしかありませんｗ

<b>⑶　変数・定数のちがい</b>
　・変数 ･･･ 代入した文字列・数値は、<b><font color="red">何度でも変更できる</font></b>
　　　　　　 → 値が何度も変わってよいものを扱うなら <b><font color="red">let</font></b> が適している
　・定数 ･･･ 代入した文字列・数値は、<b><font color="red">二度と変更できない</font></b>
　　　　　　 → 値が変わっては困るものを扱うなら <b><font color="red">const</font></b> が適している

ここで、<b><font color="red">何回でも代入ОK なのか 1回のみしかダメ なのか</font></b> という、
最大のちがいが出てきました。
<b><font color="red">let</font></b> と <b><font color="red">const</font></font></b>、書き方自体はほとんど違いがありませんが、
まちがいなく使い分けが必要です。

第2回はここまで！
次回は<b>【テンプレートリテラル】</b>について書いていきます！
ご覧いただき、ありがとうございました！
【GitHub Desktop】ブランチをマージする方法

### 初めに
作業ごとにブランチを分けようと思い、新しいブランチにしたら初めに書いたコードが反映されていなかったので解消法です。

### 実装方法
ブランチをマージするには「Branch」→「Merge into current branch」をクリックする。

![スクリーンショット 2022-12-04 15.05.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2958170/f4ed21ab-1952-3baf-a8d9-7b44034948c9.png)


マージしたいブランチを選択して「Marge CreatePrefabs main」をクリック。
![スクリーンショット 2022-12-04 15.09.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2958170/e75fddfe-1c59-c241-5ef0-35075f813191.png)


マージの完了です。
チャレンジレスポンス認証 とは

## 勉強前イメージ

主導的にレスポンスしにいくのかな？

## 調査

### チャレンジレスポンス認証 とは

認証を行う際にパスワードなどを直接やり取りせずに認証を行うことを言います。
主に [ワンタイムパスワード](https://qiita.com/miyuki_samitani/items/b64b50137ed9332a8783) などの手法で使われることがあります。

チャレンジレスポンス認証では、チャレンジとレスポンスというものがあり、詳細は以下です。

- チャレンジ

サーバ側で一回しか使わない乱数を生成。
クライアントに送る。

- レスポンス

チャレンジを受け取った利用者が、パスワードとチャレンジを使って生成するもの。
サーバ側でレスポンスを送る。

また、流れは以下のようになっています。

1. [クライアント → サーバ] アクセス要求
2. [サーバ] チャレンジを生成
3. [サーバ → クライアント] 生成したチャレンジをクライアントへ送る
4. [クライアント] クライアントは受け取ったチャレンジをパスワードを使ってレスポンスを生成
5. [クライアント → サーバ] 生成したレスポンスをサーバへ送る
6. [サーバ] サーバ側でもDBにあるパスワードを使ってレスポンスを作成
7. [サーバ] クライアントから送られてきたレスポンスと、サーバ側で作ったレスポンスを比べる
8. [サーバ → クライアント] 比較した結果をクライアントへ返す
9. [クライアント] 認証結果がOKであれば進められる

イメージとしては以下になります。

![12022-12-04 # チャレンジレスポンス認証 とは - diagrams.net - Goog.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129517/45309177-db25-d7a2-a69a-75b8684fb523.png)


### チャレンジレスポンスのメリット

- レスポンスが不可逆のためパスワードが解析されづらい

レスポンスは不可逆のため通信を盗聴されてレスポンスが覗かれたとしてもパスワードが解析されることは難しい

- チャレンジが古くなる

チャレンジは一度しか使われず、また一定期間経つと使えなくなるため使うことができなくなってしまう

## 勉強後イメージ

確かにワンタイムパスワード使うようになってきたところ多いよね。

## 参考

- [チャレンジ/レスポンス認証【challenge and response authentication】](https://e-words.jp/w/%E3%83%81%E3%83%A3%E3%83%AC%E3%83%B3%E3%82%B8-%E3%83%AC%E3%82%B9%E3%83%9D%E3%83%B3%E3%82%B9%E8%AA%8D%E8%A8%BC.html)
- [チャレンジレスポンス認証の仕組みと特徴を解説！](https://itmanabi.com/challenge-response/)
React プロジェクトに入れておきたい eslint-plugin-jsx-a11y

## アクセシビリティ何それ美味しの?
っていう人は以下のドキュメントを読んできてください
https://ja.reactjs.org/docs/accessibility.html

## eslint-plugin-jsx-a11y の紹介
Github: https://github.com/jsx-eslint/eslint-plugin-jsx-a11y
a11y を意識したマークアップをかけているかチェックしてくれる eslint plugin です。

Next.js を利用している場合、eslint-config-next に含まれているので追加で入れる必要はありません。

## 導入方法
(yarn ですでに eslint を導入している場合)

```
yarn add -D eslint-plugin-jsx-a11y 
```

```json
{
  "plugins": ["jsx-a11y"]
},
{
  "extends": ["plugin:jsx-a11y/recommended"]
}
```

細かい設定は他と同様 `rules` で設定できます。

## 主要なルール
recommended に含まれている主要なルールは以下 (それぞれの解説は整備中

### alt-text

### anchor-has-valid

React Router や Next.js `<Link>` の 直下に置いている場合、`#` などで回避できます
```tsx
<Link to="path/to/navigate">
  <a href="#" />
</Link>
```

### aria-props

### label-has-associated-control


## recommended では無効だけど有効にした方がいいもの

### control-has-associated-label
APIで、他者のSpotifyプレイリストをコピーする。

 APIで、Spotifyの他者のプレイリストを、コピーする。

非エンジニアですが、コピーしたかったため作りました。
メモで、記事にしています。

```
import spotipy
from spotipy.oauth2 import SpotifyClientCredentials
import spotipy
import sys
import spotipy.util as util
from datetime import datetime


day = datetime.now()
date = day.date()

username = 'ログインしているユーザー名'
client_id = "自身のclient_id"
client_secret = "自身のclient_secret"
redirect_uri = "設定した自身のredirect_uri"


client_credentials_manager = SpotifyClientCredentials(client_id=client_id, client_secret=client_secret)
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)


scope = 'playlist-modify-public playlist-modify-private'
token = util.prompt_for_user_token(username,scope, client_id=client_id,client_secret=client_secret,redirect_uri=redirect_uri)

sp = spotipy.Spotify(auth=token)


#本文関数

def clear_playlist(playlist_id):
    #指定した自分のプレイリストの取得
    my_playlist = sp.playlist(playlist_id)
    # 指定した自分のプレイリストを空にする
    sp.user_playlist_replace_tracks(user=my_playlist["owner"]["id"], playlist_id=playlist_id, tracks=[])
    print("指定したプレイリストを空にしました。")

    
def playlist_change_details(my_playlist_id):
    my_playlist = sp.playlist(my_playlist_id)
    description = "{}".format(date)
    sp.user_playlist_change_details(user=my_playlist["owner"]["id"], playlist_id=my_playlist_id, description=description)
    

#本文関数 main
def sync_playlists(other_playlist_id, my_playlist_id):
    #指定した他者のプレイリストのID
    Shother_playlist_id = other_playlist_id
    #指定した自分のプレイリストのID
    my_playlist_id = my_playlist_id 
    #指定した他者のプレイリストの取得
    other_playlist = sp.playlist(other_playlist_id)

    #指定した自分のプレイリストの取得
    my_playlist = sp.playlist(my_playlist_id)
    #指定した他者のプレイリストの曲目
    other_playlist_tracks = [track["track"]["id"] for track in other_playlist["tracks"]["items"]]
    #指定した自分のプレイリストの曲目
    my_playlist_tracks = [track["track"]["id"] for track in my_playlist["tracks"]["items"]]

    #指定した他者のプレイリストの曲数
    other_playlist_length = other_playlist["tracks"]["total"]
    #指定した自分のプレイリストの曲数
    my_playlist_length = my_playlist["tracks"]["total"]


    #同期実行
    if other_playlist_tracks == my_playlist_tracks and other_playlist_length == my_playlist_length:
        playlist_change_details(my_playlist_id)
        print("指定した他者のプレイリストと指定した自分のプレイリストが一致しました。処理を終了します。")
    else:
        #100曲以上の場合、sp.user_playlist_replace_tracksメソッドを使用できない（できるが100が上限なので100曲のプールしかできない）
        #そのため
        # 指定した自分のプレイリストを空にする
        #そして、置き換えではなく、追加にする
        clear_playlist(my_playlist_id)
        # 指定した他者のプレイリストの曲目を指定した自分のプレイリストに同期
        for i in range(0, other_playlist_length, 100):
            results = sp.playlist_tracks(playlist_id=other_playlist_id, fields=None, limit=100, offset=i)
            tracks = [t["track"]["id"] for t in results["items"]]
            sp.user_playlist_add_tracks(user=my_playlist["owner"]["id"], playlist_id=my_playlist_id, tracks=tracks)
        playlist_change_details(my_playlist_id)
        print("指定した他者のプレイリストと指定した自分のプレイリストが一致しました。処理を終了します。")

```

```
sync_playlists("コピーしたいコピー元のplaylistid","ペーストしたいご自身のplaylistid")
```
Railsアプリケーションの認証をdeviseからAuth0にリプレースした話

# はじめに
先日、弊社プロダクトのモチベーションクラウドのマイクロサービス化（認証基盤との接続）に成功しました！

今回は既存のRailsアプリケーションをマイクロサービス化するに当たってdeviseをリプレースした手順を記して、
是非みなさまのRailsアプリケーションのマイクロサービス化の助けになればと思います。

# deviseの削除
Railsのログイン機能といえばRailsチュートリアルにも出てくるdeviseを利用しているプロダクトが多いと思います。
https://github.com/heartcombo/devise

このdeviseはcookieで認証情報を保持して、都度認証を行っています。
そしてdeviseは幾つかヘルパーメソッドがあり、これらの置き換えがメインになると思います。
https://github.com/heartcombo/devise#controller-filters-and-helpers

まずはこのヘルパーメソッドが使われている箇所がないか？を確認して、それらの置き換えを検討しました。
その結果、主に大変だった以下3つの代替方法を述べます。
```
- authenticate_user!
- current_user
- sign_out
```

## authenticate_user!
認証してるユーザーかどうかを判定するバリデーションです。

今回認証基盤の移行に伴い、新しい認証方法として、Auth0を利用していますので、
公式が出しているドキュメントに則り、このメソッドを書き換えていきました。
※記載しているコードは公式のドキュメントの内容をそのまま持ってきています
https://auth0.com/docs/quickstart/backend/rails/01-authorization

```ruby
# app/controllers/concerns/secured.rb
# frozen_string_literal: true
module Secured
  extend ActiveSupport::Concern
  included do
    before_action :authenticate_request!
  end
  private
  def authenticate_request!
    auth_token
  rescue JWT::VerificationError, JWT::DecodeError
    render json: { errors: ['Not Authenticated'] }, status: :unauthorized
  end
  def http_token
    if request.headers['Authorization'].present?
      request.headers['Authorization'].split(' ').last
    end
  end
  def auth_token
    JsonWebToken.verify(http_token)
  end
end
```

## current_user
ログイン中のユーザーを取得するメソッドです。
これは先述のauthenticate_user!を呼んだ後に一意のユーザーを特定するidのようなものを
インスタンス変数で持っておいて、Userからfindする感じです。
こんなイメージ

```ruby
def current_user
  # current_userを取得する前ならデコード済みのidからUserを引く
  # access_tokenからデコードする処理は別で定義
  @current_user ||= id_by_access_token ? User.find(@id) : nil
end
```

## sign_out
Auth0のログアウトはFEから呼べるようになります。
こちらに関しても`auth0-spa-js`というパッケージがあり、
ここで紹介されている様にlogoutを呼べます。
https://github.com/auth0/auth0-spa-js/blob/master/EXAMPLES.md

※こちらも記載しているコードは公式のドキュメントの内容をそのまま持ってきています

```html
<button id="logout">Logout</button>
```

```javascript
document.getElementById('logout').addEventListener('click', () => {
  auth0.logout();
});
```

## RSpec
上記ヘルパーメソッドとは少し異なりますが、権限ごとのテストを行うべく、
- ユーザーAでログイン
- ユーザーAの権限では、○○ができる
- ログアウト
- ユーザーBでログイン
- ユーザーBの権限では、○○ができない

みたいなテストケースもあったので、これらも置き換えなければなりません。
それらに対してはスタブ化することで、解決しました。

# deviseをリプレースしてみて
deviseをリプレースして、他にも諸々対応を完了し、
認証基盤のマイクロサービス化したことで、弊社のプロダクト間のシングルサインオンが可能になりました。
いちいちログインしなくて良くなるのはとても素晴らしいことですね。

これからも沢山プロダクトを作っていく上で、
サービス間の組織や個人のデータを1つに集約できたのも、今後の可能性の広がりを感じます。

一方で辛かったことも同様にあり、よくマイクロサービスの課題として挙げられる
データ管理だったり、運用面は私たちも工夫が必要な点でした。

是非、自分のアプリケーションがどの構成に向いているのか？は一度吟味した上で、
マイクロサービスにするのか、モノリスで行くのかを決めると良いんじゃないかなって思います。
それではみなさん、良いお年を！！
簡単Elixirシリーズ ~ フォルダ配下にあるファイルリストの作成 ~

# 簡単Elixirシリーズ 
## ~ フォルダ配下にあるファイルリストの作成 ~

この記事は「[Elixir Advent Calendar 2022](https://qiita.com/advent-calendar/2022/elixir)」2日目の記事です
東京にいるけどFukuokaexのYOSUKEです。

簡単 Elixirシリーズでは小ネタをサクッと書いていこう。というコンセプトで作っていきます。

今回は、とあるフォルダ配下にあるファイルやフォルダ名を取得してリスト化したい。という小ネタ（そう、この記事はサクッとがコンセプトW）

まずはプロジェクトを作成する

```zsh
mix new get_list
```

プロジェクト作ったら、ls関数を作成 System.cmd を使えば、簡単。

```lib/get_list.ex
  def ls(path) do
    {str, 0 } = System.cmd("ls", ["#{path}"])
    str |> String.split("\n") |> List.delete_at(-1)
  end
```

早速、実行してみましょう。

```
iex()> GetList.ls("/get_list")
["README.md", "_build", "lib", "mix.exs", "test"]
```

ほら簡単。

意外と使いたい時ありますよね。
Rake is 何？

## Rakeって何？

RakeはRubyのタスクランナーです。```make```のRubyバージョンのようなものだと思います。

https://www.creatology.jp/unix/make.html

都度、実行する必要があるようなタスクをrakeを使って管理することができます。
Railsでマイグレーションを行う時には```rails db:migrate```を実行すると思いますが、```rake db:migrate```でも同様の結果を得られます。

## Ruby単体での使い方
```terminal
    gem install rake
    touch Rakefile
```

```Rakefile.rb
    task :sample do
      puts "sample"
    end
```
上記のように定義した場合、以下のように呼び出すことができます。
```
    rake sample
```
また、命名においてバッティングが起こる可能性があるため名前空間を使うことができます。
```Rakefile.rb
    namespace :animal do
      task :monkey do
        puts "サル"
      end
      task :elephant do
        puts "ゾウ"
      end
    end
```
名前空間を使った場合は```:```を使って表します。
```terminal
    rake animal:monkey
    # => サル
    rake animal:elephant
    # => ゾウ
```


## Railsでの使い方
Railsにはデフォルトの状態でRakeが入っています。
Rakeファイルを見てみると以下のようになっています。
```Rakefile.rb
    # Add your own tasks in files placed in lib/tasks ending in .rake,
    # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
    
    require_relative 'config/application'
    
    Rails.application.load_tasks
```
```lib/tasks```配下にrakeファイルを作成すると、Rakefileに読み込まれます。
```ruby
    Rails.application.singleton_class.instance_method(:load_tasks)
    => #<UnboundMethod: #<Class:#<App::Application:0x000056015a39d760>>#load_tasks(app=...) /usr/local/bundle/gems/railties-6.1.6/lib/rails/engine.rb:462>
```
https://github.com/rails/rails/blob/b8868d64985a5446affd9e5e34b90df9f0955933/railties/lib/rails/engine.rb#L462

総User数を表示するタスクを作ります。(Userモデルは既成)
```
    touch lib/tasks/user.rake
```
```lib/tasks/user.rake
    namespace :user do
        desc 'return all users count'
        task :count do
            puts User.all.count
        end
    end
```
上記の設定で```rake user:count```を実行すると```NameError: uninitialized constant User```エラーが表示されると思います。
通常の状態ではActiveRecordに対してアクセスできないため、```:environment```を追加する必要があります。
```lib/tasks/user.rake
    namespace :user do
        desc 'return all users count'
        task count: :environment do
            puts User.all.count
        end
    end
```


## 参考にした記事

https://www.rubyguides.com/2019/02/ruby-rake/

https://ruby.github.io/rake/doc/rakefile_rdoc.html

https://www.akshaykhot.com/accessing-rails-activerecord-models-inside-rake-tasks/
Unity　多次元のListがインスペクター上で表示されない 

# 問題
UnityEditorのインスペクターでは多次元のListが表示されなくListの状態を確認できません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/6a198a4f-bd25-3b8a-a8a8-d5024237878b.png)

# 開発環境
Unity:2021.3.9
IDE:Rider
OS:Window10
# 対処方法
TextMeshProコンポーネントのtextにListの内容を出力して対処します。
この方法の良いところはインスペクターの挙動を考慮しなくて済むことです。
欠点は読み取り専用で値の変更はできません。

``` sample.cs
using System;
using System.Collections.Generic;
using TMPro;
using UnityEngine;


public class Strings : MonoBehaviour
{
    // インスペクター上に表示されない
    [SerializeField] private List<Monster> monsterList = new List<Monster>();
    // インスペクター上に表示される。他にはbool型とかも
    [SerializeField] public int count = 0;
    // 文字出力用
    [SerializeField] private TextMeshProUGUI debugMonitor;
    
    // Update is called once per frame
    void Update()![ArrayImprovement.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/fcfd586f-0320-551e-8187-c11516287f94.gif)

    {
        displayByTextMeshPro();
    }
    
    
    private void displayByTextMeshPro()
    {
        debugMonitor.text = null;
        // ヘッダー
        debugMonitor.text = "Monster List \n hp ,name         \n";
        foreach (var monster in monsterList)
        {
            // -のときは左揃え、　-を外すと右揃え
            debugMonitor.text += string.Format("{0,-3:#} {1,-9:#} \n",  monster.Hp,monster.Name );
        }
    }
    /// <summary>
    ///  GameObjectをマウスクリックすると　monsterListにmonsterが追加されます。５回まで対応
    /// </summary>
    private void OnMouseDown()
    {
        if (count == 0)
        monsterList.Add(new Monster(10,"goblin"));
        if (count == 1)
            monsterList.Add(new Monster(20,"Orc"));
        if (count == 2)
            monsterList.Add(new Monster(30,"Giant"));
        if (count == 3)
            monsterList.Add(new Monster(50,"FireGiant"));
        if (count == 4)
            monsterList.Add(new Monster(70,"AncientGiant"));
        count++;
    }
}

class Monster
 {
     private int hp;
     private String name;

     public int Hp
     {
         get => hp;
         set => hp = value;
     }

     public string Name
     {
         get => name;
         set => name = value;
     }

     public Monster(int hp, string name)
     {
         Hp = hp;
         this.name = name;
     }

 }
```
# 実際の動き
下のgifアニメは実行したときの様子です。

![ArrayImprovement.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/b3c2fda3-764d-ecd5-2658-58a18560bf8c.gif)



# 参考

別の対処方法　
https://kan-kikuchi.hatenablog.com/entry/ValueListList

C# の文字揃え方法
https://ict119.com/alignment/
Elixir × GraphQLシリーズ① ~ サクッとGraphQLサーバーのセットアップ ~ 

# Elixir × GraphQLシリーズ  
## ~ Abshinthe Setup ~

この記事は「[Elixir Advent Calendar 2022](https://qiita.com/advent-calendar/2022/elixir)」8日目の記事です
東京にいるけどFukuokaexのYOSUKEです。

Graphqlのセットアップは以前も書いた事があるので、今回は 簡単に手順のみをシンプルにサクッと書いていこう。というコンセプトで作っていきます。

このシリーズは３部作で考えています。


```bash
mix phx.new open_data_ql
```


```
mix phx.gen.context Community Place places name:string location:string lat:float lon:float scale:integer
```

実行
```
mix ecto.create
mix ecto.migrate
```

依存関係の追加

```mix.exs
defp deps do
    [
    # 省略 #
      {:absinthe, "~> 1.7"},
      {:absinthe_plug, "~> 1.5"},
      {:absinthe_phoenix, "~> 2.0"}
    ]
end
```

実行

```zsh
mix deps.get
```

サンプルデータを準備する

```seeds.exs
alias OpenDataQl.Repo
alias OpenDataQl.Community.Place

%Place{
  name: "test1",
  location: "test1",
  lat: 123.45,
  lon: 67.89,
  scale: 1
} |> Repo.insert!

%Place{
  name: "test2",
  location: "test2",
  lat: 223.45,
  lon: 67.89,
  scale: 2
} |> Repo.insert!

%Place{
  name: "test3",
  location: "test3",
  lat: 323.45,
  lon: 67.89,
  scale: 3
} |> Repo.insert!
```

スキーマの作成

```schema/schema.ex

defmodule OpenDataQlWeb.Schema.Schema do
  use Absinthe.Schema

  object :place do
    field :id, non_null(:id)
    field :name, non_null(:string)
    field :location, non_null(:string)
    field :lat, non_null(:float)
    field :lon, non_null(:float)
    field :scale, non_null(:integer)
  end

  query do
    @desc "Get a list of places"
    field :places, list_of(:place) do
      resolve &OpenDataQlWeb.Resolvers.Community.places/3
    end

    @desc "Get a place by its id"
    field :place, :place do
      arg :id, non_null(:id)
      resolve &OpenDataQlWeb.Resolvers.Community.place/3
    end
  end

end

```

リゾルバの作成

```resolvers/community.ex
defmodule OpenDataQlWeb.Resolvers.Community do
  alias OpenDataQl.Community

  def places(_, _, _) do
    {:ok, Community.list_places()}
  end

  def place(_, %{id: id}, _) do
    {:ok, Community.get_place!(id)}
  end
end
```

routerに追記

```router.ex
defmodule OpenDataQlWeb.Router do
  use OpenDataQlWeb, :router

# 省略 #

  pipeline :api do
    plug :accepts, ["json"]
  end

  scope "/api" do
    pipe_through :api

    forward "/", Absinthe.Plug,
      schema: OpenDataQlWeb.Schema.Schema
  end

# 省略 #

  if Mix.env() == :dev do
    forward "/graphiql", Absinthe.Plug.GraphiQL,
      schema: OpenDataQlWeb.Schema.Schema,
      interface: :simple
  end
end
```

起動

```zsh
iex -S mix phx.server
```

アクセス

```http://localhost:4000/graphiql```

![スクリーンショット 2022-12-04 14.30.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72962/d3aa2795-5b62-0e51-0bbd-67695f8aac23.png)

さて、ここまで完成したので、次はクライアントもElixirで作っていきましょう。
Leetcode 2256. Minimum Average Difference

# 2256. Minimum Average Difference

https://leetcode.com/problems/minimum-average-difference/

## 難易度
### Medium

## アプローチ
### Prefix sum

```java
package com.leetcode.midium;

// import java.util.HashMap;
// import java.util.Map;

public class MinimumAverageDifference2256 {
    public static void main(String[] args) {
        System.out.println(minimumAverageDifference(new int[]{2, 5, 3, 9, 5, 3}));
        System.out.println(minimumAverageDifference(new int[]{1}));
        System.out.println(minimumAverageDifference(new int[]{1, 2, 3, 4, 5}));
    }

    public static int minimumAverageDifference(int[] nums) {
        int n = nums.length;
        int ans = -1;
        int minAvgDiff = Integer.MAX_VALUE;
        long currPrefixSum = 0;
        long totalSum = 0;

        for (int i = 0; i < nums.length; i++) {
            totalSum += nums[i];
        }


        for (int index = 0; index < nums.length; index++) {
            currPrefixSum += nums[index];
            long leftPartAverage = currPrefixSum;
            leftPartAverage /= (index + 1);

            long rightPartAverage = totalSum - currPrefixSum;
            if (index != n - 1) {
                rightPartAverage /= (n - index - 1);
            }

            int currDifferent = (int) Math.abs(leftPartAverage - rightPartAverage);
            if (currDifferent < minAvgDiff) {
                minAvgDiff = currDifferent;
                ans = index;
            }
        }

        return ans;
    }
/* TLE CODE
    public static int minimumAverageDifference1(int[] nums) {
        if (nums.length == 1) {
            return 0;
        }
        int index = 1;

        HashMap<Integer, Integer> hashMap = new HashMap<>();

        for (int i = 0; i < nums.length; i++) {
            int first = 0;
            int last = 0;

            int j = 0;
            for (; j < index; j++) {
                first += nums[j];
            }

            if (first != 0) {
                first /= index;
            }
            int z = index;
            for (; z < nums.length; z++) {
                last += nums[z];
            }
            if (last != 0) {
                last = last / (nums.length - (index));
            }
            int a = Math.abs(first - last);
            hashMap.put(index - 1, a);
            index++;
        }

        int result = hashMap.entrySet().stream().sorted((o1, o2) -> o1.getValue() - o2.getValue()).map(Map.Entry::getKey).findFirst().get();
        return result;
    }
*/

}
```

- [この](https://leetcode.com/problems/minimum-average-difference/solution/)解説を参考しました
syftを使ってCentOS 7のrpmdbを元にSPDX-JSON形式のSBOMを生成する

この記事はOpenChain Japan Advent Calendar 2022の12月8日分として投稿します。
https://qiita.com/advent-calendar/2022/openchainjapanwg

# はじめに

syftはコンテナイメージやファイルシステムを元にSBOM (Software Bill of Materials)を生成するためのCLIツールおよびGoライブラリです。
コンテナイメージはOCIやDocker、C,C++,Java,Python,Ruby,Debian,Red Hatなどの環境に対応しています。
詳しくはsyftのGitHubをご覧ください。
https://github.com/anchore/syft

今回はsyftを使ってCentOS 7のrpmdbを元にSPDX-JSON形式のSBOMを生成してみます。

# 環境情報

macOS上にDockerでCentOS 7のコンテナを立ち上げて、その中で作業をします。
今回の環境情報は以下です。

| コンポーネント | バージョン | 備考 |
|:-:|:-:|:-:|
| PC | M1 MacBook Pro  |   |
| OS | macOS Ventura 13.0.1  |   |
| Docker | 4.15.0 |   |
| CentOS | 7.9.2009  | |
| syft | v0.62.3 | |

# 手順

## CentOS 7のコンテナを作成

macOS上での作業です。

dockerイメージをpullし、コンテナを作成します。
```Bash
$ docker pull centos:centos7
$ docker run -it -d --name centos7 centos:centos7
```

ログインして、バージョンを確認します。
```bash
$ docker exec -it centos7 /bin/bash
# cat /etc/redhat-release 
CentOS Linux release 7.9.2009 (AltArch)
```

## syftをインストール

ここからはCentOS 7のコンテナで作業をしてください。

syftをインストールします。
```Bash
# curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin
# ls -l /usr/local/bin/syft 
-rwxr-xr-x 1 root root 55967744 Dec  4 09:50 /usr/local/bin/syft
```
## rpmdbからSPDX-JSON形式でSBOMを生成

```bash
syft /var/lib/rpm -o spdx-json > centos7_rpm.json
```

## 生成したSPDX-JSON形式のファイルを確認

生成したSPDX-JSON形式のファイルの内容を確認してみましょう。
以下はgrepパッケージに関する情報を抜粋したものです。
パッケージ名(name)やバージョン(versionInfo)は取得できているものの、ライセンスは取得できていないようです。

```json
  {
   "name": "grep",
   "SPDXID": "SPDXRef-Package-rpm-grep-e4d3c9df1ae7bd18",
   "versionInfo": "2.20-3.el7",
   "originator": "Organization: CentOS",
   "downloadLocation": "NOASSERTION",
   "sourceInfo": "acquired package info from RPM DB: Packages",
   "licenseConcluded": "NOASSERTION",
   "licenseDeclared": "NOASSERTION",
   "copyrightText": "NOASSERTION",
   "externalRefs": [
    {
     "referenceCategory": "SECURITY",
     "referenceType": "cpe23Type",
     "referenceLocator": "cpe:2.3:a:centos:grep:2.20-3.el7:*:*:*:*:*:*:*",
     "comment": ""
    },
    {
     "referenceCategory": "SECURITY",
     "referenceType": "cpe23Type",
     "referenceLocator": "cpe:2.3:a:grep:grep:2.20-3.el7:*:*:*:*:*:*:*",
     "comment": ""
    },
    {
     "referenceCategory": "PACKAGE-MANAGER",
     "referenceType": "purl",
     "referenceLocator": "pkg:rpm/grep@2.20-3.el7?arch=aarch64&upstream=grep-2.20-3.el7.src.rpm",
     "comment": ""
    }
   ]
  },
```

# まとめ

syftを使ってCentOS 7のrpmdbを元にSPDX-JSON形式でSBOMを生成することができました。
ざっとソースを確認したところライセンスを取得する処理は実装されてはいるものの、v0.62.3ではうまく動作していないようです。
v0.62.3ではパッケージ名やバージョンなどの情報はSPDXｰJSON形式で取得できるので、ソフトウェア管理に活用してみてはどうでしょうか。

# 参考情報

- syft
    - https://github.com/anchore/syft
- SPDX
    - https://spdx.dev/
- DockerでCentOS 7のイメージを利用してみよう
  - https://weblabo.oscasierra.net/docker-centos7/
アウトプットするんですか？　ならインプットをなんとかしないと！

# ごあいさつと自己紹介

こん/(にち|ばん)/わ、さいろすと申します。どうぞご贔屓に。
元々BASIC、C、アセンブラを駆使してゲームプログラマになりたい！という夢を持っていましたが、今となっては時々ゲームも何らかの形で（UnityとかUnrealEngineとか）作ったりしています。

というわけでもありませんが、早速当方のアウトプットのお話したいと思いますので、お付き合いのほどよろしくお願いいたします。

# いきなり結論

**インプット大事！**

…いや、冗談ではなくて。

# 結論に至る背景

実は、この記事を書く直前、何気なしnoteに記事を書きました。

https://note.com/cyross/n/n57ac7067b12c

「学び直し」というテーマに反応して、つらつらと書いた記事が思った以上に手応えのある記事となってしまい、短期間での反応も少ないながらもあったということで、印象に残った出来事となりました。

というのも、以前は質の高いアウトプットをしたいしたいと思っていても手応えは全くなし。
独学であれやこれやとやってみたのはみたのですが、効果無し。

こんなワテが本を出していた経験がある（もちろん絶版）のですから、なおさら焦っていたところでした。

# 啓示を受けたかのような瞬間

そんなこんなで悶々としていた日々を過ごしていたのですが、ある時、[樺沢本](https://amzn.asia/d/69uhSU1)に出会うわけです。
そこの文言で背中に電撃を浴びたような衝撃を受けました。

**「アウトプット前提のインプットをする」**

そりゃそうですよね。

有名な画家も、先人の有名な画家の絵を模写して画力を上げていきました。
有名な音楽家も、耳コピなどで音楽センスを鍛えたり、ノウハウを蓄積していました。
（まぁ、それが無くてもなぜか天才的な力を持っていた例外もいらっしゃいますが。ピカソとか）
何かしらの功績を持っている方々も、周りの人のサポート（これもインプットの一種と考えています）や勉強、研鑽の蓄積があればこそです。

結局物を言うのは経験とインプットの質の高さです。

もはや、これが良質なアウトプットへの王道だ！　と共感いたしました。
~~AZ(=アウトプット前提)とかいう超ド速球なダサダサ造語はおいといて~~

# アウトプットへの立ち回りの変化

この頃から、アウトプットを念頭に置いた情報収集をするように心がけました。
**そして、確実にアウトプットする**（これ大事！）。
文章のまとめ方とか、表現技法とか、これに比べたら霞んで見えます（大袈裟）。

アウトプットの粒度も大事だと考えています。**何が学びだったか、学びでなかったのか。** それをアウトプットするのも読者・視聴者にとってはかけがえのない情報になるのでは、と捉えるようになりました。

```text
余談ですが、今はサ終してしまったGeocitiesというフリーのホームページサービスがありました。

ここで扱われていたサイトでは、ファミコンとかのレトロゲームの操作方法や攻略法を
紹介しているものが多数ありました。

本当にリーチするのか考えていたどうかは作者のみぞ知るですが、少なくとも、
カセットだけのゲームだけをサルベージしていた当方にとっては非常に価値の高いアウトプットでした。
```

## 立ち回りの変化の例

例えば、先に紹介したnoteの記事では、余談として、樺島本を出しているサンクチュアリ出版の生い立ちが不明瞭だったために、ネット上の情報から独自に調べてみた経過を書いています。

本当に何に役立つかは当方もわかりませんが、疑問に思ったときには、何か書けるかもしれないという意識が芽生えて、情報を集めていました。
もちろん、そのままにはしておかず、それぞれの情報を線で繋いで関連性があるていどクリアになった時点で、余談として追記しました。

他には、とある講習を受ける際、何を得られそうなのかを予めメモしておいて、実際にどうだったのか、本当は想定とずれていたけど学びがあったことはまとめて書き出すようにしました（感想を話者や関係者に送ったり、ブログなどで広く見てもらうなど色々場面がありますが、それらに応じて細かい点を修正しておくのを忘れずに…）。

こうする形で、気になったことがあるときに、もとの情報の程度や濃淡の違いさえあれ、何かしらのアウトプットをしようというつもりで望む意識が習慣づいてきています。

# 立ち回りを変えた効果

アウトプットを念頭に置いた行動にシフトした結果、読書の捉え方や発表の聴き方など、**インプットの構え方**が著しく変わりました。

以前は、 `話を聴いているときに寝てしまう` 現象が頻繁に起こり、申し訳ない気持ちでいっぱいになり、相当つらい時期を過ごしていましたが、今は完全に解消されました。
これは、複数の原因が絡み合った結果ですが、他の原因と解決方法については、本筋と離れるので割愛いたします。
しっかりと頭の中身を整理して自分の言葉で話をすることが出来るようになりました。

続いて、**アウトプットの回し方** も色々考えられるようになりました。
この文章を書いているときでも、どうやってまとめようかスラスラと出てくるようになってきました。
また、最初に構成を建てて、それを形にできるようになったという、一種の副作用も良い効果です。

そして、一番大きな効果は「**アウトプットすることが楽しくなった**」ことです。
当方の中では「まごうことなきアウトプット」を実感できる機会が多くなったことから、だんだんと
楽しくないと、やはり継続が難しくなります。継続するためにはモチベーションが大事ですから、願ったり叶ったりです。

この効果が更に良いインプットを得ようとする意識に伝播し、まさに上昇気流に乗った感じです。

# さいごに

アウトプットをするためには、それ相応のインプットが肝要だということを書いてまいりました。
先にも書きましたが、アウトプットするためのテクニックは、インプットを形にする段階で否応なく蓄積されていくものです。
というわけで、長々と書いてしまいましたが、皆さんお疲れではないでしょうか。
この話はここで終わりにいたしますので、読み終えた際は頭をリフレッシュするなど、頭を切り替えて捉え方を見直してみることをお勧めいたします。

それでは、ごきげんよろしゅう。
Rubocop導入

### Rubocop導入
```Ruby:Gemfile
group :development do
  gem 'rubocop', require: false
end
```
```Terminal:ターミナル
bundle install
touch .rubocop.yml
```

```Ruby:.rubocop.yml
AllCops:
# 除外するディレクトリ（自動生成されたファイル）
# デフォルト設定にある"vendor/**/*"が無効化されないように記述
 Exclude:
   - "vendor/**/*" # rubocop config/default.yml
   - "db/**/*"
   - "config/**/*"
   - "bin/*"
   - "node_modules/**/*"
   - "Gemfile"


# 1行あたりの文字数をチェックする
Layout/LineLength:
 Max: 130
# 下記ファイルはチェックの対象から外す
 Exclude:
   - "Rakefile"
   - "spec/rails_helper.rb"
   - "spec/spec_helper.rb"

# RSpecは1つのブロックあたりの行数が多くなるため、チェックの除外から外す
# ブロック内の行数をチェックする
Metrics/BlockLength:
 Exclude:
   - "spec/**/*"

# Assignment: 変数への代入
# Branch: メソッド呼び出し
# Condition: 条件文
# 上記項目をRubocopが計算して基準値を超えると警告を出す（上記頭文字をとって'Abc'）
Metrics/AbcSize:
 Max: 50

# メソッドの中身が複雑になっていないか、Rubocopが計算して基準値を超えると警告を出す
Metrics/PerceivedComplexity:
 Max: 8

# 循環的複雑度が高すぎないかをチェック（ifやforなどを1メソッド内で使いすぎている）
Metrics/CyclomaticComplexity:
 Max: 10

# メソッドの行数が多すぎないかをチェック
Metrics/MethodLength:
 Max: 30

# ネストが深すぎないかをチェック（if文のネストもチェック）
Metrics/BlockNesting:
 Max: 5

# クラスの行数をチェック（無効）
Metrics/ClassLength:
 Enabled: false

# 空メソッドの場合に、1行のスタイルにしない　NG例：def style1; end
Style/EmptyMethod:
 EnforcedStyle: expanded

# クラス内にクラスが定義されていないかチェック（無効）
Style/ClassAndModuleChildren:
 Enabled: false

# 日本語でのコメントを許可
Style/AsciiComments:
 Enabled: false

# クラスやモジュール定義前に、それらの説明書きがあるかをチェック（無効）
Style/Documentation:
 Enabled: false

# ％i（）構文を使用していないシンボルで構成される配列リテラルをチェック（無効）
Style/SymbolArray:
 Enabled: false

# 文字列に値が代入されて変わっていないかチェック（無効）
Style/FrozenStringLiteralComment:
 Enabled: false

# メソッドパラメータ名の最小文字数を設定
Naming/MethodParameterName:
 MinNameLength: 1
```

### 実行
```Terminal:ターミナル
bundle exec rubocop
```
### 自動で修正させる場合
```Terminal:ターミナル
bundle exec rubocop -a
```
【WordPress】テーマをカスタマイズする

# 前回の記事

前回の記事では、WordPressのテーマをインストールしました。

https://qiita.com/raptony110/private/9cf113be4de4561ea1c1

今回は、インストールしたテーマを編集して、より完成に近づけていきましょう。

僕のAdvent Calendarを読み終わった人が、
「へぇ簡単なんだなぁ〜　自分もWordPress使ってサイト作ってみようかな〜」って思うあなたがそこにいたのなら、、、、
読むだけで、頭の中WordPress化しちゃったんだよッ！！！！

https://qiita.com/advent-calendar/2022/wordpress-output

# WordPressのツールバーを非表示にする
サイトを確認した時に、上部にWordPressのツールバーが表示されて鬱陶しい場合があります。
まずは、これを非表示にしましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1499675/52ca15c1-cceb-dc98-18db-29f0f516c808.png)
このようにツールバー表示されていると、細かいデザイン確認ができません。

ユーザー>プロフィール>ツールバー　のチェックボックスを外すと、ツールバーが表示されなくなります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1499675/86e4ad87-746e-9a15-81b2-2060924529f2.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1499675/f916ff69-97fd-5f99-faf4-1373893cc46e.png)
消えました。これでスッキリです。

# ロゴを設定する
## ロゴを作成する
今回は、[hatchful](https://www.shopify.com/jp/tools/logo-maker)で簡単にロゴを作成してみました。簡単にロゴが作成できました。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1499675/302bd00d-915b-42b2-d396-15172e7ef9f7.png" width='300px'>

WordPress管理メニュー外観>カスタマイズを開きます。カスタマイズできる項目は、テンプレートごとに違います。有料版のテンプレートを購入すると利用できるようになる場合がほとんどです。もしどうしても変更したい項目が有料版になる場合は、検討しましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1499675/49459f92-05aa-456f-a758-0c4f8c6dff7d.png)

ロゴが設定できるテーマの場合は、サイト基本情報（テンプレートによりメニュー名が異なります）を選択すると設定項目が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1499675/551939b3-967a-eeae-0cca-4e9a29b79f4d.png)

# サイトアイコンを設定する
いわゆるファビコンと呼ばれるものですね。
こちらもロゴを設定するメニューの近くにあると思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1499675/7864c0d6-d2a4-a728-e154-f4e401981507.png)

これでサイトタイトルとロゴに同じ画像を設定することができました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1499675/8aabe49d-3f38-b5a7-8586-eb2f8c10f0ef.png)

# メインカラーを決めよう
作成するサイトのテーマカラーを決めて、それを設定します。テーマごとにどこの色を変化させることができるのか確認しながら選ぶのが良いでしょう。
カスタマイズの色メニューから基本カラー設定に入ります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1499675/1c1c215e-dbe5-d2da-34bf-914787cee066.png)
これでだいぶサイト全体の雰囲気ができてきました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1499675/813497e3-965b-8572-a974-4c465832f1d2.png)


# おわりに
いかがでしたでしょうか。今回の記事では、サイトアイコンやロゴ、色を設定して、全体的な雰囲気を決めました。
テンプレートによっては、設定箇所が違ったりします。どの箇所を変更することができるのか色々試しながら、テンプレート選びに戻ったりなどして試行錯誤する時間になるかと思います。

次回は、ヘッダ画像などを変更していきましょう。