OmniAICreator/Qiita-1.07M huggingface dataset:
BeautifulSoupでドメイン内リンクを列挙する。

#実行環境
・macOS High Sierra 10.13.6
・Python 3.8
・**urllib3**　1.26.4
・**beautifulsoup4** 4.9.3
・エディタ Atom
　・AtomはデフォルトでPythonの実行をサポートしていないので、必要なパッケージをダウンロードする必要がある

#はじめに
:::note alert
クローリングしようとしているサイトが、クローリングを許可しているか、禁止しているかについては十分な注意を払うべきである。
:::

あなたは、自社のWebサイトに使用している写真をすべて改めるよう上司の指示を受け、とりあえずのところは、自社Webサイトのリンクをいくつも辿ってドメイン内を東奔西走し、どんな写真が使われていて、あるいは複数のページに重複して使用されている写真がどれだけあって、それぞれ何度使用されているか数えなければならなくなった。
その判断が正しいとして写真のチェックミスがないように、まずは**ドメイン内のすべてのページをもれなく列挙しよう！** と思い立った。

URLを直打ちしないとローマ経由でも辿り着けないような離れ小島のページは考慮に入れないとして、**6次の隔たり**ってわけでもないけどリンクを辿り続けることでドメイン内のすべてのページに辿り着くことができるとするなら、
**1.indexページ（ドメインのトップレベルのページ）のURLを与える
2.HTMLの中からリンクを見つけてリストに追加する
3.リストの1つ目のリンクを辿った先のHTMLの中から、まだリストに追加されていないリンクを見つける
4.2-3を繰り返す**
と、なんとなく再帰的に使えそうなコードを書けば良さそうだな。と方針が見えてくる。

#まずはHTMLを取得するコードから

```getHTML.py
#モジュールのインポート
from urllib.request import urlopen
from urllib.error import HTTPError

def getHTML(url):
    try:
        html = urlopen('https://www.▲▲▲.com{}'.format(url))
    except HTTPError as e:
        return None
    return html.read()

ret = getHTML('')
if ret == None:
    print('Returned None')
else:
    print(ret)

```
まずはここまで。
作った関数を後で再帰的に使いたいので、

```.py
getHTML('')
```
とやっているように、あえて空文字列を渡しておく。
確認のためにhtmlが可読可能な状態で表示されたらOK。

#BeautifulSoupを利用してHTMLをパースする

```getPages.py
#モジュールのインポート
from urllib.request import urlopen
from urllib.error import HTTPError
from bs4 import BeautifulSoup
import re

def getPages(url):
    global pages
    try:
        html = urlopen('https://www.▲▲▲.com{}'.format(url))
    except HTTPError as e:
        return None
    try:
        bs = BeautifulSoup(html.read(), 'html.parser')
        #ここで正規表現を用いて、画像リンクやcssを排除
        for link in bs.find_all('a',href=re.compile('適当な正規表現')):
            if 'href' in link.attrs:
                if link.attrs['href'] not in pages:
                    newPage = link.attrs['href']
                    pages.add(newPage)
                    getPages(newPage)
    except AttributeError as e:
        return None
    return pages

pages = set()
ret = getPages('')
if ret == None:
    print('Returned None')
else:
    print(ret)
```

ドメイン内を巡って集めたリンクを格納するために

```.py
peges = set()
```
として集合を作っておく。
まずはBeautifulSoupオブジェクトを作りたいので、

```.py
bs = BeautifulSoup(html.read(), 'html.parser')
```
とする。BeautifulSoupオブジェクトの中から
・a（リンク）タグ
・href属性が内部リンクであるもの
をイテレートしてlinkという変数へ入れるため、

```.py
for link in bs.find_all('a',href=re.compile('正規表現')):
```
というコードを書く。
一度、正規表現による条件を設けずに、1つ目の（ドメイントップの）ページからリンクをすべて書き出す処理を書いて、もしくはブラウザのデベロッパーツールから内部リンクを探せば、条件として書くべき正規表現の検討がつくはずである。

あとは、抽出したリンクからhref属性を取り出して、リンクの集合の中になければそれを集合へ追加し、またそのリンク先を再帰的に調べるということを繰り返す。
belongs_toをbelong_toと書いていたこと

#  belongs_toをbelong_toと書いて、作業が止まってしまった。
かなり初歩的なミスですが、学習中にbelongs_toをbelong_toと書いて、この間違いを探し出せず作業が止まってしまいました。

```ruby:ruby
belong_to #belongsの　ｓ　が抜けており、このままだとエラーが出ます。
```

```ruby:ruby
belongｓ_to #なので、このように忘れずにbelongsと書きます。
```
# さいごに
このミスは、「記述ミスが一つでもあると動かなくなる。」ということが改めて分かったことでもあります。この記事は自身のミスに常に目を光らせておくという戒めとして書きました。今後は自分のミスにいち早く気づけるようにしていきたいです。
Reactを勉強するなら関数コンポーネントから始めよう！クラスで書かれているものは必要に迫られるまで読まない

Reactを勉強しようと思ったとき、初学者を惑わす1つの要因が、関数コンポーネントとクラスコンポーネントの存在だと思います。

例えば、textに渡した文字列を表示するコンポーネントを実装する場合、下記のようにfunctionでもClassでも書くことができます。
書き方は違いますが両方とも同じ動作をします。
functionで書かれているものを関数コンポーネント、Classで書かれているものをクラスコンポーネントと呼びます。

```react:Hoge.tsx
export default function Hoge({ text }: { hoge: string }) {
  return (
    <div>{text}</div>
  );
}
```

```react:HogeClass.tsx
import React from "react";

export default class HogeClass extends React.Component<{ text: string }, {}> {
  render() {
    return (
      <div>{this.props.text}</div>
    );
  }
}
```

Reactをこれから始める場合、公式ページのチュートリアルをやる人が多いと思います。

https://ja.reactjs.org/tutorial/tutorial.html

こちらのチュートリアルはClassコンポーネントで書かれているので、最初にチュートリアルをした人はClassコンポーネントを使う方が良いのかな？と思う方も多いと思います。

ただ、タイトルに書いた通り、最初は関数コンポーネントを中心に勉強しましょう。
私はReactを使い始めて1年半ほど経ちますが、関数コンポーネントだけで全て実装できています。
Classコンポーネントは、既存のClassで書かれているコンポーネントを触らないといけない場合など、必要になってから学べば良いです。

# 関数コンポーネントが良い理由

関数コンポーネントが良い理由はクラスよりシンプルに書けるなどの理由もありますが、最大の理由はHooksを使えることです。
Hooksの説明は省きますが、状態管理やデータ通信などの非同期通信を反映などをシンプルに実装することができる仕組みで、動的なページを作る際は必須機能と言って良いほど重要な仕組みです。

詳細は下記、公式ドキュメントをご覧ください。

https://ja.reactjs.org/docs/hooks-intro.html

# 何から学び始めれば良いか？

公式ドキュメントのチュートリアルはクラスコンポーネントで書かれているのですが、Getting Startedは関数コンポーネントを中心に記載されています。
こちらから始めることをオススメします。

https://ja.reactjs.org/docs/getting-started.html

公式ページ以外にもReactについて書かれている記事はネット上に大量にありますが、Hooks登場前後で全然世界が違うので、読み始める前にいつ頃書かれたものかを確認するようにしてください。
Hooksは2019年2月にリリースされたので、2019年を境にHooks＋関数コンポーネントの記事が書かれ始めていると思います。

また、Reactに慣れるまでは、クラスコンポーネントで書かれている記事は古い（可能性が高い）というように雑に覚えておくだけで古い情報に惑わされる可能性が減ると思います。
safariだけimgのonloadイベントが走らないパターン

# 背景
画像と、その他のコンテンツが動的に切り替わっていく画面で、画像が見えてから他のコンテンツを表示させたいという要件があり、対象の画像のimageのonloadで他のコンテンツを表示、またタグごと取り換えると遅いということで、imageタグ内のsrc属性を書き換えていくような実装をしていました。
その際2連続で同じ画像を出した時にiphoneユーザーだけうまく動かず、その調査の備忘録です。

# 実験
こんなスクリプトをブラウザのコンソールに読ませます。これによりページのimgタグの最初の1つに、onload時にコンソールにメッセージが出るイベントが付与されます。

```js
const img = document.getElementsByTagName("img")[0]

img.addEventListener('load', function() {
  console.log('load!')
}, false);
```

これを適当なimgタグのあるサイトで流したあと、さらにこのスクリプトを2回流します。imgに適当な画像のurlを埋め込んでいます。

```js
// googleのロゴ
img.src = "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png"; 
```

この時、2回目でload!と出力されるかを各ブラウザで調べました。

## 結果
| ブラウザ |  OS  | 結果 |
| ---- | ---- | ---- |
|chrome 92.0.4515.159|windows 10 21H1|2回表示|
|Firefox 90.0.2|windows 10 21H1|2回表示|
|Edge 92.0.902.84|windows 10 21H1|2回表示|
|chrome 91.0.4472.114|mac Catalina 10.15.2|2回表示|
|Firefox 89.0|mac Catalina 10.15.2|2回表示|
|safari13.0.4 (15608.4.9.1.3)|mac Catalina 10.15.2|__1回表示__|

# 結論
__safariではimgのsrcに元と同じurlを与えたときに、onloadイベントが発火してくれない。__ということがわかりました。対策としてはurlを与える前に空文字をあたえる処理を挟むなどすると良いです。ブラウザ依存でアプリケーションがうまく動かないパターンは開発者泣かせなので、なんとなく記憶の片隅においていただけると良いかもしれません。
【Ruby on Rails】時間表示に関する記事いつも検索するからまとめてみた


#対象者

* 時間の表示に関して調べている方

#目的

* 時間表示の方法を１つの記事にまとめて整頓する

#実際の手順と実例
###1.タイムゾーン

タイムゾーンを日本時間にする方法を下記の記事を参考にさせて頂きました。

https://qiita.com/katsutakashima/items/1453ed0c97a818ddd731

````config/application.rb
module App
  class Application < Rails::Application
    # Settings in config/environments/* take precedence over those specified here.
    # Application configuration should go into files in config/initializers
    # -- all .rb files in that directory are automatically loaded.
    config.time_zone = 'Tokyo'
  end
end
````

サーバー再起動で時間表示が日本時間にできます。


###2.strftimeに関して

よく使うstrftimeは下記の記事をよく参考にさせて頂いております。

https://qiita.com/annyamonnya/items/97c5cb0cfa414b3592d7

下記記事もまとまってて、使えそう

https://docs.ruby-lang.org/ja/latest/method/Time/i/strftime.html


###3.よく使うstrftimeテンプレート

「2021年08月30日　08:09:49」と表現するとき

`````ruby
time = Time.current
time.strftime("%Y年%m月%d日 %H:%M:%S")
`````


「2021/08/30(月)」

`````ruby
wd = ["日", "月", "火", "水", "木", "金", "土"]
time = Time.current
time.strftime("%Y/%m/%d(#{wd[time.wday]})")
`````

![スクリーンショット 2021-08-30 8.17.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1681213/6a80d63b-1d3b-fb5d-4584-1f50c42c0ba6.png)

wdayは曜日を０（日曜日）から6（土曜日）の整数で返してくれます。

>[Time#wday (Ruby 3.0.0 リファレンスマニュアル)](https://docs.ruby-lang.org/ja/latest/method/Time/i/wday.html)


よく使う時間表示あったらまた更新します！


####投稿者コメント
今日は自分用に時間に関する表示方法をまとめてみました。
これで毎度検索する手間をカットできそう


####My Profile
プログラミング学習歴３ヶ月目のアカウントです！
プログラミングスクールで学んだ内容や自分が躓いた箇所等のアウトプットの為に発信しています。
また、プログラミング初学者の方にわかりやすく、簡潔にまとめて情報共有できればと考えています。
もし、投稿した記事の中に誤り等ございましたら、コメント欄でご教授いただけると幸いです。
【AWS】Amazon CloudWatch

#はじめに
AWS認定試験取得に向けてAWSの知識を整理するためのまとめです。
今回はAmazon CloudWatchについてまとめます。

#CloudWatchとは
AWSサービスのモニタリングに関するさまざまな機能が提供されています。
メトリクスに応じてアクションを実行したり、ログを可視化したりなど。

#CloudWatchの特徴
## CloudWatch Metrics
メトリクスとはシステムのパフォーマンスに関するデータのことです。
デフォルトである程度メトリクスが用意されています。（標準メトリクス）

EC2の場合だと
CPUUtilization：CPU使用率
DiskReadBytes：読み込みバイト数
など。他にもさまざまなメトリクスがあります。

また、標準メトリクス以外にメトリクスを追加したい場合は、カスタムメトリクスが利用できます。

基本5分間隔でモニタリングを実施し、詳細モニタリングで1分毎にモニタリング可能

## CloudWatch Alarms
CloudWatchメトリクスを監視し、異常と判定した場合に、指定したアクションを実行します。
例：EC2のCPU使用率が90%を超えたとき、アラートメールを通知するなど

アラームの状態は3種類あります。
・OK：正常です。（定義された閾値を下回っている状態）
・ALARM：異常です。（定義された閾値を上回っている状態）
・INSUFFICIENT_DATA：判定不能（データ不足のため状態を判定できない）

Alermsを使用するユースケースとしては、
CPUの閾値を超えたらAutoScalingを実施してインスタンス台数を増減する。などがあります。

## CloudWatch Logs
AWSサービスおよびユーザが保有しているシステムのログファイルの監視、保存、アクセスを提供します。
ログデータの保存期間は1日〜永久保存で設定可能です。
ログデータはS3へエクスポートが可能です。

さらにそのログに対しては、Amazon CloudWatch Logs Insightsを利用して解析することが可能です。

#料金
従量課金制になります。
無料枠としては
標準メトリクスのモニタリング、ダッシュボード、10件のアラーム、ログは5GBなどです。
それ以上のもの、カスタムメトリクスなどは有料枠となります。


#参考サイト
https://aws.amazon.com/jp/cloudwatch/
https://d1.awsstatic.com/webinars/jp/pdf/services/20190326_AWS-BlackBelt_CloudWatch.pdf
Android Studioの手動アンインストール

# はじめに
Windows環境でAndroid Studioをコントロールパネルからアンインストールしようとしたが、**uninstall.exeがありません**と表示されたので、手動でアンインストールしたときのメモ  

# 手順  
1. インストールしたユーザーのホームフォルダに移動し、.android,.m2,.grandleフォルダを削除する  
1. [user]>[AppData]>[Local]>[Google]のフォルダに移動し、Android Studioに関連するフォルダを削除する  
1. [user]>[AppData]>[Roaming]>[Google]に移動し、Android Studioに関連するフォルダーを削除する。
1. [Program files]に移動し、AndoridStudioのフォルダを削除する
1. Windows+Rを押して、`regedit`と入力し、レジストリエディターを開き、[HKEY_LOCAL_MACHINE]>[SOFTWARE]を開き、AndroidStudioを削除する
多分91日後に基礎情報技術者を受けるFラン私大文系既卒(2日目)

# フラグメンテーション
* フラグメンテーションとは?
* ファイルがあちこちに記録され、断片化している状態

# デフラグメンテーション
* デフラグメンテーションとは?
 * 断片化したファイルのデータを、まとまるように並べ直すこと

# リムーバブルメディア
* リムーバブルメディアとは?
 * 駆動装置から記憶媒体を簡単に取り出せる装置のこと

# VRAM(Video RAM)
* VRAMとは?
 * コンピュータが画像を出力する内容を保持するメモリ

# CPS(Character Per Second)
* CPSとは?
 * 一秒間に何文字印字できるかを示す値

# PPM(Print Per Minute)
* PPMとは?
 * 一分間に何ページ印刷できるかを示す値

# IDE(Integrated Drive Electronics)
* IDEとは?
 * 内蔵用ハードディスクを接続するための企画として使われたインターフェース

# EIDE(Enchanted IDE)
* EIDEとは?
 * IDEのCD-ROMにも対応したバージョン
 * 4台の機器と接続することができる

# SCSI(Small Computer System Interface)
* SCSIとは?
 * ハードディスクやCD-ROM、MOドライブ、イメージスキャナなど、さまざまな周辺機器の接続に使われていたインターフェース

# IEEE1394
* IEEE1394とは?
 * ハードディスクレコーダやデジタルビデオカメラなどに使われるインターフェース

# IrDA(Interface Data Association)
* IrDAとは?
 * 赤外線を使って無線通信を行う規格

# スプーリング
* スプーリングとは?
 * 低速な装置とのやりとりを高そうな磁気ディスクを通して、行うことで処理効率を高める方法
 *
Go の testing つかってみた

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244948/33861726-5e11-ea12-40b9-56bb55084939.png)

## TDD
[エアテスト駆動飲み会](https://tddrinking.connpass.com/)で Golang をはじめて触ったので記録のこします

* 同イベントでは過去に [bash も TDD が簡単に出来る](/kfjt/items/eaf5e2749802a950dd76) を書きました

## 環境
* [Replit](https://replit.com/) を使うことで、実行環境を作る時間を省略し、ブラウザ越しに参加者同士でコードを共有します
* Golang を普段さわってる人はゼロ

## 分かった事
* `xxx_test.go` というファイル名にする
* `go test` で実行できる
* `package main` だと何か不都合らしい
* 関数 `Testxxx` を用意する
* `t *testing.T` をパラメータに受ける
* アサーションは無い
* 条件式を書き `t.Errorf()` を呼ぶ
* ここまで分かったら FizzBuzz くらいなら TDD できる

## 最小構成サンプル
```golang:main.go
package a
import "strconv"

func a(i int) string {
  return strconv.Itoa(i)
}
```

```golang:main_test.go
package a
import "testing"

func TestA(t *testing.T) {
  actual := a(1)
  expected := "1"
  if actual != expected {
    t.Errorf("1のとき文字列1になる")
  }
}
```

## そのうち調べること
* なぜ package main はダメなんだろう
* アサーション無しの理由が気に入ったので他言語でも似たようなことできるかな
    * python の unittest で pandas.DataFrame 扱えないみたいなこと
    * assert_frame_equal があるのは知ってるけど、じゃあほかの任意のオブジェクトはどうよ？みたいな
    * java なら Object の equals をオーバーライドしとけばいいじゃん、みたいな事なのかな？

おしまい
Docker Desktop for Windows 3.6.0 (67351) アップデート後に起動エラー

# エラー内容

```
System.ServiceProcess.TimeoutException: タイムアウトが時間切れになりました。操作は完了していません。
   場所 System.ServiceProcess.ServiceController.WaitForStatus(ServiceControllerStatus desiredStatus, TimeSpan timeout)
   場所 Docker.Backend.Processes.WindowsDockerDaemon.TryToStartService(Settings settings, String args, Dictionary`2 env) 場所 C:\workspaces\master-merge\src\github.com\docker\pinata\win\src\Docker.Backend\Processes\WindowsDockerDaemon.cs:行 208
   場所 System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass6_1.<GetExecutor>b__0(Object instance, Object[] methodParameters)
   場所 System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary`2 arguments, CancellationToken cancellationToken)
...
```

# 解消方法

1. ~~[コンテナー内のオブジェクトを列挙…アクセスが拒否…権限エラー対策 | アメリカビーバーがSEですか](https://se-abeaver.com/acl-modify-error/) の方法で「C:\ProgramData\Docker」フォルダのアクセス許可にEveryOneフルコントロールを追加~~
1. 「C:\ProgramData\Docker」フォルダにある「panic.log」「panic.log.old」をリネーム
1. Docker Desktopを起動して4.0.0にバージョンアップ

# 参考

* [16.11.1 possibly breaks Docker Desktop startup with Windows containers and WSL 2 - Visual Studio Feedback](https://developercommunity.visualstudio.com/t/16111-possibly-breaks-docker-desktop-startup-with/1506061)
* [Crash while switching from Linux to Windows containers · Issue #11899 · docker/for-win](https://github.com/docker/for-win/issues/11899)
* [Docker Engine failed to start - Fix](https://bala.one/docker-engine-failed-to-start-fix/)
順序回路の作法 その2

# 概要

順序回路を理解する。
フリップフロップのタイミングチャートを書いてみた。

# 写真

![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/0616c7cd-f410-6355-22f0-47b22d431772.jpeg)


# 成果物

https://embed.plnkr.co/plunk/ygnX2oMyX0IpXTwF


以上。
Windows VSCode+WSL2+Docker 開発環境構築

# はじめに
普段はMacで開発をしているのですが某ゲームを遊ぶためにWindowsを買ったので
Macに近い開発環境のために諸々調べて設定しました。その備忘録として記事を残します。

# WSL 2とDocker for Desctopの導入
参考1: [Windows 10 Home で WSL 2 + Docker を使う](https://qiita.com/KoKeCross/items/a6365af2594a102a817b)
参考2: [Windows Subsystem for Linux Installation Guide for Windows 10(Microsoft公式)](https://docs.microsoft.com/en-us/windows/wsl/install-win10)

コマンド一発でWSLを有効化できる `Simplified install` は執筆時点ではオススメしません。少なくともPSO2 NGSは遊べなくなります。

## Enable Virtualization
- Task Managerを起動。 `Performance` > `CPU` で `Virtualization: Enabled` を確認
- もしEnabledになっていない場合は BIOSを開いて `CPU Configuration` > `Intel (AMD) Virtualization Technology: Enabled` に設定する
  - BIOSの開き方はPCによって異なるため説明書などで調べてください

## Enable Windows Feature
- 管理者モードの Windows PowerShell で以下を実行

```ps
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
# `y` を入力することで、設定の有効化のためPCを再起動してください
```

## Install WSL 2 kernel
[Step 4 - Download the Linux kernel update package | Microsoft Docs](https://docs.microsoft.com/en-us/windows/wsl/install-win10#step-4---download-the-linux-kernel-update-package)  
`WSL2 Linux kernel update package for x64 machines` のリンクからInstallerをダウンロードして実行

## Install Ubuntu (Linux OS)
- Microsoft Store で `Ubuntu` を検索
- `Ubuntu 20.04 LTS` をインストール（最新バージョンは時期によって変わっている可能性があります）
- インストールした `Ubuntu` を実行
- 初回実行時、新たに作成するユーザー名とパスワードの入力を求められます
- この手順では以下の値として進めます（オススメ）
  - ユーザー名: `ubuntu`
  - パスワード: `password`

## WSL 2 の設定と実行確認
Command Prompt (cmd) で以下を実行

```cmd
wsl --set-default-version 2
wsl --set-version Ubuntu-20.04 2
wsl -l -v # 設定を確認
```

## Install Docker Desktop
- [Docker Desktop](https://www.docker.com/products/docker-desktop) にアクセス
- Installerをダウンロードして実行
  - `Enable WSL 2 Windows Features` のチェックを外さないこと
- Docker for Desctopを実行し、上の歯車マークでSettingを開く
- 以下の設定を確認し、チェックがOFFの場合はONにする
  - `General` > `Use the WSL 2 based engine`
  - `Resource` > `WSL INTEGRATION` > `Enable integration with my default WSL distro`
    - その下の `Enable integration with additional distro:` は無視でOK

## localhostへのフォワーディング設定を追加
- `C¥Users¥{User名}` ファルダの中に `.wslconfig` ファイルを作成
- メモ帳で開いて、以下の内容を記入して保存してください

```.wslconfig
localhostForwarding=True
```

この設定はDockerで起動したアプリをWindowsのlocalhostにバインドするために必要です。
**保存したらWindowsを再起動してください。**

## VSCodeをインストールし、WSL 2をデフォルトシェルにする
- [Visual Studio Code](https://azure.microsoft.com/ja-jp/products/visual-studio-code/) にアクセス
- Installerをダウンロードし、実行
- VSCodeを実行する
- 起動したら `Ctrl + Shift + X` で拡張機能を開く
- 拡張機能の検索に `wsl` と入力し `Remote - WSL` をインストール
- `Ctrl + Shift + P` -> `reload` と打ち `Reload Window` を選択
- `Ctrl + Shift + P` -> `terminal` と打ち `Terminal: Select Default Profile` で `wsl` を選択
- 一度VSCodeを終了する。タスクバーから右クリック→閉じるのが良い
- VSCodeを起動し `Ctrl + Shift + @` でTerminalを表示する
- シェルが `bash` で、ユーザーが `ubuntu` になっていることを確認する

## DockerからlocalhostへPortForwardingされていることを確認する
VSCodeのbash(wsl shell)で以下を実行。

```sl
docker run --rm -it -p 80:80 yeasy/simple-web:latest
# ブラウザで `http://localhost` にアクセスし、画面が表示されればOK
```

# おわりに
WindowsでMac相当の開発体験を得るためには、キーボードの設定等まだまだたくさんやることがありますが、
これでひとまずは同じアプリを開発できるようになりました。めでたしめでたし。
【Vue.js】【Nuxt.js】ハマったにも関わらず気づくと一瞬で直せた凡ミスまとめ

`Vue.js`を開発で使うことがありますが、
予期せぬエラーで数時間溶かすことがあります。

ハマって数時間を溶かしてしまったにも関わらず、気づくとすぐ直った凡ミスについて紹介します。
同じ犠牲者を出さないためにも。
居ないかもしれませんが。

## TypeError: ~~~~ is not a function

メソッドはちゃんと定義しているのに、無いと怒られます。
例えばこんな感じに書いていました。

```vuejs:sample1.vue
<script>
export default {
    created() {
      this.sampleFunc();
    }
    method: {
      sampleFunc() {
        console.log('sample code.');
      }
    }
  }
</script>
```

`sampleFunc`はしっかり定義しているのに何故か定義されてない、と怒られます。

慣れている方ならすぐ分かりますね。

**メソッドを定義は`method`ではなく`methods`という場所に記載します。**

https://jp.vuejs.org/v2/api/index.html#methods

というわけで、修正します。一瞬です。

```vuejs:sample1.vue(修正)
<script>
export default {
    created() {
      this.sampleFunc();
    }
    methods: { // 修正
      sampleFunc() {
        console.log('sample code.');
      }
    }
  }
</script>
```

## Invalid component name: "0".

コンポーネント名「0」は無効。
初見でまったく意味不明です。

もちろんそんなふざけた名前のコンポーネントなんか登録していません。
こんな感じのコードです。

```vuejs:sample2.vue
<script>
import StatsCard from '@/components/Cards/StatsCard';

export default {
  components: [
    StatsCard,
  ]
}
// (省略)
</script>
```

これはダメダメですね。
`components`のところが配列になっています。

コンポーネントのローカル登録はオブジェクトで登録しないといけません。

https://jp.vuejs.org/v2/guide/components-registration.html#%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E7%99%BB%E9%8C%B2

修正します。

```vuejs:sample2.vue(修正)
<script>
import StatsCard from '@/components/Cards/StatsCard';

export default {
  // オブジェクトに
  components: {
    StatsCard,
  }
}
// (省略)
</script>
```

## This relative module was not found:
これはビルド時にエラーが発生しました。

```
ERROR  Failed to compile with 1 errors
This relative module was not found:
...
* ./Sample.vue?vue&amp;type=style&amp;index=0&amp;id=0dd86077&amp;lang=scss&amp;scoped=true&amp; in ./components/Sample.vue
» Updated components\Sample.vue
```

単純に`sass`がインストールされてなかったのが原因だったようです。
インストール実行してあげて完了です。

```
$ npm install sass-loader node-sass
```
or

```
$ yarn add --dev sass
```

## まとめ

凡ミスで時間を溶かす人が減ることを願います。
輸出統計のデータ加工

from dash_url.customs2 import trade_stat_set_for_hs_code2
import pandas as pd
from glob import glob

PATH=r"C:\Users\....\customs\ik-300h*.csv"

hs_code=str(hs_code)
paths=glob(PATH)
path=paths[0]

df=pd.read_csv(path)
months=[s.replace('Value-','') for s in
        df.columns[df.columns.str.contains('Value-')]]
months=[s for s in months if s!='Year' ]

li=[s for s in df.columns]
value_start_from=li.index('Quantity1-Year')

month=months[0]
line[line.index.str.contains(month)]+df.iloc[0,:value_start_from]
[05] オンプレ環境で VM 2台を使って 1マスタ・1ノードの kubernetes を構築してみる (ノードをクラスタへ参加させる)

# 概要

下表の構成で、オンプレ上に k8s を構築したときの記録である.
本記事では「**k8sノードをクラスタへ参加させる手順**」を記す.

基本的には、https://github.com/takara9/vagrant-kubernetes にて
Ansible で実行していた処理を、手動で実行しているのみです.
(若干、マニフェストを変更しています)

|No|用途|ノード名|形態|公開IP|内部IP|OS|備考|
|:--|:--|:--|:--|:--|:--|:--|:--|
|1|k8sマスタ|master01|VM|192.168.1.91|172.24.20.11|Ubuntu18.04||
|2|k8sノード|node01|VM|192.168.1.92|172.24.20.12|Ubuntu18.04||


# 参考にしたサイトおよび書籍

|URL|備考|
|:--|:--|
|[実践 Vagrant](https://www.oreilly.co.jp/books/9784873116655/)||
|[15Stepで習得 Dockerから入るKubernetes](http://www.ric.co.jp/book/contents/book_1161.html)|K8s だけでなく、Ansible, Vagrant, GlusterFS のことなども学べる.|
|https://github.com/takara9/vagrant-k8s|[『15Stepで習得 Dockerから入るKubernetes』](http://www.ric.co.jp/book/contents/book_1161.html)の著者が公開されている GitHub.<br/>Vagrant や Ansible コードを公開してくださっている.|
|https://github.com/takara9/vagrant-kubernetes|同上|
|https://github.com/takara9/codes_for_lessons|同上|
|https://nextpublishing.jp/book/12197.html|『解体kubeadm　フェーズから読み解くKubernetesクラスタ構築ツールの全貌』を参考にして 1マスタ・1ノードを構築した.|



# 環境

## 物理PC および 仮想PC の OS

```bash
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=18.04
DISTRIB_CODENAME=bionic
DISTRIB_DESCRIPTION="Ubuntu 18.04.4 LTS"
```

## 物理PC

下記ソフトを導入済みであること.

- Vagrant 
- VirtualBox



# 手順

## 1. k8s 設定を初期化する

物理ホストから node01 へ ssh ログインする

```bash
$ vagrant ssh node01
```

```bash
vagrant@node01:~$ sudo kubeadm reset -f
```

## 2. クラスタへ参加させる

[[02] VM 2台を使って 1マスタ・1ノードの kubernetes を構築してみる (kubeadmによるマスタ構築)](https://qiita.com/robozushi10/items/9ac8b8a40446f51aad80) 
で kubeadm の初期化をしたときに表示されるコマンドを実行すれば良い.

```bash
vagrant@node01:~$ kubeadm join 10.0.2.15:6443 --token qu104b.66ff4kkrma3chyqd \
    --discovery-token-ca-cert-hash sha256:3be8f04fd648a22f247203b5c7a87fb0e242b84f6a066f6c393f13cde56b9f52 
```

## 3. kubelet が参照する DNS の IP を変更する

```bash
vagrant@node01:~$ sudo cp /var/lib/kubelet/config.yaml /var/lib/kubelet/config.yaml.ORIG
vagrant@node01:~$ sudo sed -i 's/10.96.0.10/10.32.0.10/g' /var/lib/kubelet/config.yaml
```

## 4. kubelet を再起動させる

```bash
vagrant@node01:~$ sudo systemctl daemon-reload
vagrant@node01:~$ sudo systemctl restart kubelet
```

　

以上.
ブートストラップ(bootstrap)でフッター(footer)のpopupを上にする方法

#スマホ用にfooterのpopupを上にしようとした時に参考にした記事です。

https://stackoverflow.com/questions/17581352/how-to-get-a-bootstrap-dropdown-submenu-to-dropup

#方法

```html:index.html
 <ul class="dropdown-menu dropup" role="menu" aria-labelledby="dLabel">
```

classにdropupと記載するだけです。

下記のように表示されます。

![スクリーンショット 2021-08-30 12.24.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670485/0df1fa76-7ee6-2955-5157-a6fbf1681e98.png)


#感想

すごくシンプルでした。

見切れてしまう場合にはCSSでleftもしくはrightで調整してみてください
Google Doorbellで自分を認識したら自動でSesame3を解錠させてみた(Python初挑戦)

#やりたかったこと
Google Doorbellが発売されたので、カメラが自分の姿を認識したときにSesame3を自動で解錠させたかった

#困ったこと
・Sesame3がいまだにIFTTT連携してくれない(2021年8月現在)
⇒Python使ったことないのにpysesame3を使う羽目になった

#やろうとしたこと
・GoogleDoorbellが認識済みの人物をとらえると、Homeアプリから人物名入りの通知が届く
・Homeアプリから飛んできた「人物」入りの通知をトリガーとして、MacrodroidからTasker実行
・pysesame3を使ったpythonプログラムを実行してSesame3を解錠

#困ったこと2
・Android上でPythonを動かす環境の選択肢に最初に上がったのが下の2つ
###Pydroid
・プログラムは作れたものの、Taskerから実行させる方法がなかった
・Macrodroid経由でアプリを起動することはできるが、それならSesameアプリからでも同じ
###QPython
・なんか知らんけどpipからpysesame3をインストールできない
※ 正確にはPycryptodomeのインストールができない
⇒仕方ないのでWindowsにPython環境をインストールして、Pycryptodomeのディレクトリを移植
⇒それでも起動しない
※ 原因は、Windowsにインストールしたときにできるファイルがpyd(windowsDll)になってること
※ 当然WindowsDllなので、Androidにコピーしたところで動くわけがない

#解決策
・Termuxを使用(Taskerプラグインも使える)

#手順
1.AndroidにTermux、Taskerプラグインをインストール

2.TermuxにPythonをインストール
(参照：<a href="https://chayarokurokuro.hatenablog.com/entry/2019/05/09/Android%E3%82%B9%E3%83%9E%E3%83%9B%E3%81%ABtermux%E3%81%8B%E3%82%89python%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%99%E3%82%8B">Androidスマホにtermuxからpythonをインストールする</a>)

```cmm
apt update
apt upgrade
apt install python
```

3.pipも自動でインストールされてるので、pysesame3をインストール

```cmm
pip pysesame3
```

4.pysesame3を使って解錠するスクリプトを作成、ルートディレクトリに保存(unlock.pyとかにしました)
(参照：<a href="https://zenn.dev/key3/articles/6c1c2841d7a8a2">Sesame 3 APIを使う</a>)

5.Termuxからルートディレクトリにアクセスするためのシンボリックリンクを作成
(参照:<a href="https://www.lisz-works.com/entry/termux-init">AndroidでLinuxターミナル！Termuxの初期設定</a>)

```cmm
termux-setup-storage
```

※ この時点で、以下のコマンドから解錠できます。

```cmm
python storage/shared/unlock.py
```

6.TermuxでTaskerを使うためのディレクトリとシェルスクリプトを作成
(参照：<a href="https://blog.goo.ne.jp/oprsfr3saku/e/de1b28f9a40d70b031c278e64557ae39">【RPA】【MacroDroid】Termux の Tasker プラグインをMacrodroidで使う</a>

```cmm
mkdir -p ~/.termux/tasker
cd .termux
cd tasker
echo -n > unlock.sh
```

※ シェルスクリプトの編集はviを使いますが、なんかこの時点ではviが存在しなかったので、
エラーメッセージ通りにコマンド打てばインストールできました。
詳しい編集は上の参照記事から。中身自体は「python storage/shared/unlock.py」だけでいいと思います。

7.Macrodroidでマクロ作成
・トリガーに「通知が表示されたとき」、アプリは「Home」、テキストコンテンツに「含む」(人名)、を指定
・アクションに「アプリ」⇒「Taskerプラグイン」⇒「Termux:Tasker」⇒unlock.shを指定⇒使用変数は全部空白でOK

#成功した
Sesame3は早くIFTTTに対応しろ

#おまけ
pysesame3を作る記事の中の"MyScript"の部分が履歴の中身に表示されるので、

```python
import sys #1行目に追加

device.unlock(history_tag=sys.argv[1])
```

Termux:Taskerでshを指定する時の引数に「hoge」を追加し、
unlock.shの中身を

```cmm
python storage/shared/unlock.py $1
```

にすると、引数を順次読み込んで、Sesame3の履歴のほうに「hoge」が表示されます。
家族の名前ごとにトリガーしておくと、誰が帰ってきたのかわかるね！

#免責
どう考えてもセキュリティはガバガバなので責任は取りません。

#追記
sesame3の秘密鍵とUUIDの取得がちょっと面倒だったのでその手順(pythonインストール後)

1. QRコードからテキストを取得
2.クエリ部分をコピー(具体的にはUI?以降の部分すべて)
3.以下のコマンドでクエリ復号

```cmm
$ python　//pythonモードに移行

>>>import urllib.parse
>>>urllib.parse.parse_qs('<copied_string>') //<>は不要

//出力されたもののうち、[sk]:の部分をコピー
```

4.以下のコマンドで秘密鍵とUUIDをそれぞれ取得

```cmm
//pythonモード

>>> import base64
>>> base64.b64decode('<copied_string>')[1:17].hex() //出力されたものが「秘密鍵」
>>> base64.b64decode('<copied_string>')[83:99].hex() //出力されたものが「UUID」

```
ログイン前にトップページを表示させる方法

# 内容
アプリを作成するにあたり、ログインする前でもトップページが表示されるように設定しました。
# 解決法

deviseを使用してログイン機能をつけた場合、

```application_controller.rb
before_action :authenticate_user!
```

を記述することで全てのコントローラーでアクションが動く前にログインしているかしていないかを判断され、ログインしていなければログインページにリダイレクトされるようになります。

```routes.rb
root "tops#index"
```
この状態では、root_pathにトップページを指定してもログインページに飛ばされてしまいます。

どうにかしてtopsコントローラーでは before_action :authenticate_user! を無効化したいですね。
そんな時は、skip_before_action を使います。

```tops_controller.rb
class TopsController < ApplicationController
  skip_before_action :authenticate_user!, only: %i[index]
end
```

これによって、topsコントローラーでは authenticate_user! が無効化されます。
さらに、only: %i[アクション名] でそのアクションでだけ無効化することもできます。

これで、未ログインでもトップページに遷移することができます。
.ps1の拡張子のファイルが実行できなくなったときの話


###転んだところ

PowerShell で デジタル署名されていないため実行できなかった。。

変更手順をまとめると、下記な感じ。[参考](https://noitalog.tokyo/pssecurity-exception/)
①windowsのクイックリンクメニューからWindows PowerShell（管理者）を起動する。
②Power Shell が起動するので下記コマンドを投入する。
③実行ポリシーの変更を行う。

実行環境
---

```
PS > $PSVersionTable

Name                           Value
----                           -----
PSVersion                      5.1.19041.1151
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.19041.1151
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
```

詳細手順
---
①windowsのクイックリンクメニューからWindows PowerShell（管理者）を起動する。
　・「windows」キーを押しながら「X」キーを押す
　・「A」キーを押す
　・このアプリがデバイスに変更することを許可しますか？とホップアップ表示されるので、「はい」を選択

②Power Shell が起動するので下記コマンドを投入する。
　現在のセッションに影響を与えるすべての実行ポリシーを取得し、優先順位で表示するコマンドなので(showみたいなもの)心配はいらない。

```PowerShell
Get-ExecutionPolicy -List
```
　返り値が下記になっていれば問題ないのだが。。(「CurrentUser」が「RemoteSigned」になってないんじゃない？)

```
PS > Get-ExecutionPolicy -List

        Scope ExecutionPolicy
        ----- ---------------
MachinePolicy       Undefined
   UserPolicy       Undefined
      Process       Undefined
  CurrentUser    RemoteSigned
 LocalMachine       AllSigned
```

③実行ポリシーの変更を行う。
　詳しいオフィシャルな情報は[こちら](https://docs.microsoft.com/ja-jp/powershell/module/microsoft.powershell.core/about/about_execution_policies?view=powershell-7.1)

:::note warn
警告
変更コマンドのため、実行の際は注意。「CurrentUser」を「RemoteSigned」にするコマンドです。
:::

```PowerShell
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
```

　実行すると、下記のようなポリシー変更の注意が出るはず。問題なければ「Y」を入力して「Enter」を入力。
規定値は「N」のため、そのまま「Enter」を入力すればキャンセル可能です。

```PowerShell
PS > Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

実行ポリシーの変更
実行ポリシーは、信頼されていないスクリプトからの保護に役立ちます。実行ポリシーを変更すると、about_Execution_Policies
のヘルプ トピック (https://go.microsoft.com/fwlink/?LinkID=135170)
で説明されているセキュリティ上の危険にさらされる可能性があります。実行ポリシーを変更しますか?
[Y] はい(Y)  [A] すべて続行(A)  [N] いいえ(N)  [L] すべて無視(L)  [S] 中断(S)  [?] ヘルプ (既定値は "N"): Y
```

　下記のように「CurrentUser」を「RemoteSigned」へのポリシー変更が確認できたらOK、スクリプトが実行できるはず。

```PowerShell
PS C:\Windows\system32> Get-ExecutionPolicy -Scope CurrentUser
RemoteSigned
```

戻し手順
---

:::note info
いろいろな設定を変更して、元の状態がわからなくなる。
私はやりがちですが、運用上よくないので。
:::

　変更前の状態に戻したい場合のコマンドは下記。実行のち「Y」の入力を忘れずに。

```PowerShell
Set-ExecutionPolicy -ExecutionPolicy Undefined -Scope CurrentUser
```
【Kotlin】Exposedで1行だけSelectしたい場合の対応

## 概要
ExposedはKotlinで使用できるO/Rマッパーです。ざっくりどんな雰囲気かというのは、[ExposedのDSL/DAOサンプル集](https://qiita.com/shima23/items/5984f7f8c9a866a8011c)を参照頂ければと思います。
今回は1行だけSelectしたい場合どうするのか、というのをメモ書きします。例えば、IDとか指定してSelectし返ってくるのが1行か0行かという場合、どう書くのが良いかということですね。（listとして取得し、行数を判定しても良いと言えば良いのですが）

## 対応
どう対応すれば良いかは、stackoverflowの記事[Kotlin Exposed SELECT single record](https://stackoverflow.com/questions/65142397/kotlin-exposed-select-single-record)が参考になります。
対応としてまずは、`limit(1)`で取得するレコードを1行に限定した上で、`single()`メソッドを呼び出せば実現できそうです。
ただ、`single()`はレコードがなかった場合exceptionが発生するので、[【Kotlin】find, firstOrNull, singleOrNullの違いは？調べてみました！](https://qiita.com/tkhskt/items/fb15c6b9d9cf30f4ea26)の記事に紹介されている、`firstOrNull`や`singleOrNull`を使った方が良さそうですね。

## 実装サンプル
DSLでの実装を前提としています。

```kotlin
transaction {
    // 作成したユーザテーブルにidの値でSelectをかける想定
    Users.select { Users.id.eq(id) }
        .limit(1).firstOrNull()?.also {
            // 取得できた場合の処理をここに書く
        } ?: run {
            // 取得できなかった場合の処理をここに書く
        }
}
```
Could not cast value of type 'UIViewController'が出た時の対処法　

##　Could not cast value of type 'UIViewController'の対処
自分がエラーを起こして、画面遷移ができなかった時の原因と対処を記録として残します。

コードはこんな感じでした。

```swift
@IBAction func tappedDontHaveAccountBottun(_ sender: Any) {
        let storyBoard = UIStoryboard(name: "Login", bundle: nil)
        let homeViewController = storyBoard.instantiateViewController(identifier: "LoginViewController") as! LoginViewController
        navigationController?.pushViewController(homeViewController, animated: true)
    }
```

###　エラーの原因
このコードでのidentifierのところがエラーになっていました。
エラーから自分は単純に,Custom class, Module, Storyboard IDなどがうち間違っているのかと推測

###　エラーの対処
なので、コードとCustom class, Module, Storyboard IDの相違がないように、コピペして再リロードすると改善しました。

この使っているメソッドは、instantiateViewController(identifier:)です。
つまり、このメソッドは識別されたidentifierを持つViewControllerを作成し、Storyboardでのデータを持ってインスタンスを初期化するメソッドなので、homeViewControllerを、インスタンスを初期化したLoginViewControllerとして作成しているのだと思います。（初心者なりの理解ですので間違っているかもしれません。申し訳ないです、、、）
Ansible の使用例


# 概要

Ansible を使用した記事です.

|コンテンツ|実践時期|一言|
|:--|:--|:--|
|[[01] VM 2台を使って 1マスタ・1ノードの kubernetes を構築してみる (VM構築)](https://qiita.com/robozushi10/items/82482e4fdcfb8d2639d1)|2021/05|Vagrant の Ansible によるプロビジョニング機能の使用例|
resourceとresourcesの違いについて

# はじめに
本記事では、resourceとresourcesの違いについて記述します。

# resources
`resources`とは、
7つのアクションへのルーティングを自動生成するメソッドです。

resourcesの引数に、:itemsなどという+シンボルで指定すると/usersのパスに対応するルーティングが生成されます。

```
% rails routes

GET          /items(.:format)                   items#index
POST         /items(.:format)                   items#create
GET          /items/new(.:format)               items#new
GET          /items/:id/edit(.:format)          items#edit
GET          /items/:id(.:format)               items#show
PATCH        /items/:id(.:format)               items#update
PUT          /items/:id(.:format)               items#update
DELETE       /items/:id(.:format)               items#destroy
```

# resource
`resource`とは、
7つのアクションへのルーティングを自動生成するメソッドですが、
`index`と`idが付いている`パスが生成されません。

```
% rails routes

POST         /items(.:format)                   items#create
GET          /items/new(.:format)               items#new
GET          /items/edit(.:format)              items#edit
GET          /items(.:format)                   items#show
PATCH        /items(.:format)                   items#update
PUT          /items(.:format)                   items#update
DELETE       /items(.:format)                   items#destroy
```

# 使い分け
「user」や「item」など、そのアプリケーションに複数存在ようなものについては、
「id」は存在し、resourcesを使う必要があると思います。

しかし、そのアプリケーション上に１つしか存在しないものについては、
「id」は必要ないため、resourceでも良いと思います。

# 終わりに
簡単ですが、過去にひっかかってしまったところでしたので、記事にしました。
知ってそうで知らないものはまだまだありそうです...。

以下参考記事です。
[resourcesとresourceの違いについて！](https://qiita.com/wacker8818/items/1ba526fcbc73e065a511)
[resourceとresourcesの違い](https://qiita.com/ryuuuuuuuuuu/items/e5960c7fecad4ef1301b)

明日も頑張ります！！
【GitHub】ジョブ・ステップ間でパラメータを受け渡す【Actions】


## step 間でパラメータを受け渡す

``set-output``を使用する。
https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-output-parameter

```yaml
name: parameter

jobs:
  parameter:
    name: My Checkout Job
    runs-on: ubuntu-latest
    steps:
      - name: Set parameter
        id: random-number-generator
        run: echo "::set-output name=random-number::$(echo $RANDOM)"
        shell: bash
      - name: Result env
        run: >
          echo output parameter is ${{ steps.random-number-generator.outputs.random-number }}
```

## job 間でパラメータを受け渡す

受け渡す側の job で``outputs``を宣言して、受け取る側の job で``needs``を使用する。
https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#example-8

```yaml
name: Parameter Job
on: [workflow_dispatch]

jobs:
  job1:
    runs-on: ubuntu-latest
    # Map a step output to a job output
    outputs:
      output1: ${{ steps.step1.outputs.test }}
      output2: ${{ steps.step2.outputs.test }}
    steps:
      - id: step1
        run: echo "::set-output name=test::hello"
      - id: step2
        run: echo "::set-output name=test::world"
  job2:
    runs-on: ubuntu-latest
    needs: job1
    steps:
      - run: echo ${{needs.job1.outputs.output1}} ${{needs.job1.outputs.output2}}
```
[シリーズ] [k8s]オンプレでのプロビジョニング(NFS)


# 概要

オンプレ上で k8s を使ってプロビジョニングを実践したときの記録である

|コンテンツ|実践時期|
|:--|:--|
|[[01] [k8s]オンプレで動的プロビジョニングを実践してみる (NFS環境)](https://qiita.com/robozushi10/items/f6cd1a299271d5bc7190)|2021/06|
|[[02] [k8s]オンプレで静的プロビジョニングを実践してみる (NFS環境)](https://qiita.com/robozushi10/items/e16edc8db5d86c84b696)|2021/06|
新卒一年目に学んだ７つの教訓

## はじめに

都内の某SIerに勤める新人プログラマーです。PJ配属から三ヶ月が経ったのですが、学んだことを整理しないとあっという間に忘れてしまいます…
今回は、現場の仕事を通じて学んだ教訓を７つご紹介したいと思います。

## 第一の教訓「数字を提示する」


テスト観点が想定より多く必要で、上司にリスケの相談をしたときのことです。

自分は「どんなテスト観点があるのか」をつらつら述べることで、時間がかかることを伝えてしまいました。当然、状況をあまり理解してもらえません。

仕切り直して「テスト観点は細かく分けると〇〇件です。なので、想定より時間がかかりそうです。」とシンプルに数字を出したところ、話がスムーズに進みました。

## 第二の教訓「質問内容によって聞くタイミングを変える」


「すぐ聞け」vs「それくらい自分で考えろ」のダブルバインド問題は、いつの時代も新人を悩ませます。

上司の言う「すぐ聞け系」は、基本的に社内用語や社内特有のフォーマット、ルールに関してです。それ以外の質問は自分なりの考え、選択肢を用意してからにしましょう。

社内用語の判別はググればある程度わかります。社内特有のフォーマット、ルールに関しては常に存在を意識し、まずはあるかどうかの確認を早めに取りましょう。

## 第三の教訓「基本を今のうちに固める」


ショートカットキー、マクロ、自動化、チケットの書き方、話し方、文書の書き方、コメントアウトの書き方などなど。基本的なスキルは新人のうちに固めましょう。

## 第四の教訓「端的に喋る」

ある時、報告を受ける側を体験して分かったのですが、「報告を受ける側は、細かい話に興味がない」ものです。できたのか、できないのか、できないなら何が問題で、次どうするのかが分かれば満腹になります。

## 第五の教訓「他人との比較は何も生まない」

性格によりけりですが、自分は特に周りと比べて焦りがちです。ですが、他人と比較して戦っても、同じ軸で競い合う以上ユニーク性が乏しくなり貴重な人材からは遠のくでしょう。

仕事の基礎能力以外は、自分だけの長所を伸ばした方がチームに貢献できます。

## 第六の教訓「上司の仕事をとことん減らす」

上司も忙しいので、あなたの仕事の全てを見ることはできません。最終判断以外は基本自分でやりましょう。

具体的には、現状を把握し、次のアクションの選択肢を出し、どれを取るべきか、なぜそれなのか、そこまで自分で考えて上司に最終判断だけ仰ぐ状態にしましょう。

## 第七の教訓「既存を疑う意識を持つ」

新人は、例えば文書作成一つ取っても書き方が分からないもので、何かと既存のものを参考にします。その結果、的外れな成果物になることは避けられますが、だんだん真似するだけの思考停止状態に陥りがちです。

明らかに既存を踏襲しない方がいい部分に対して、ちゃんと違和感を感じれるように、常に既存を疑う意識は持ちましょう。


## 最後に

当たり前なことをいつも当たり前にやるって本当に難しいですね…
【2章】コマンドラインを学ぼう

今回の記事では前章（【1章】コマンドラインを学ぼう）に引き続き、ファイルやディレクトリを移動や名前変更、コピーや削除に関する操作をコマンドを使って行っていきたいと思います。
自身のアウトプットの場となりますので、よろしくお願いいたします！

#ファイルやディレクトリを操作する
ファイルの移動やコピー、削除といった様々な操作をコマンドで行う方法を学んでいきたいと思います。

#ファイルを移動させる

まずは、ファイルを移動させるコマンドを見ていきます。ファイルを移動させるには、**mvコマンド**を使います。
**「mv ファイル名 ディレクトリ名」**とすることで指定したディレクトリにファイルを移動させることができます。

```ruby:ターミナル
 $ mv 移動させたいファイル名 移動先のディレクトリ名
```

mvコマンドでは、ファイル1つずつだけでなくディレクトリごと移動させることもできます。
**「mv ディレクトリ名 移動先のディレクトリ名」**とすることで、そのディレクトリ以下のファイルやディレクトリも一緒に移動します。

##ファイル名を変更する

ファイルやディレクトリの移動に使ったmvコマンドは、ファイル名を変更することにも使えます。
**「mv ファイル名 新しいファイル名」**とすることでファイル名を変更できます。

```ruby:ターミナル
 #ファイル名を変更する場合
 $ mv 現在のファイル名 新しいファイル名

 #ディレクトリ名を変更する場合
 $ mv 現在のディレクトリ名 新しいディレクトリ名
```

##ファイル・ディレクトリのコピー

次に、ファイルのコピーについて見ていきます。ファイルをコピーするには**cpコマンド**を使います。
**「cp コピーするファイル名 新しいファイル名」**とすることでコピーすることができます。

```ruby:ターミナル
 $ cp コピーするファイル名 新しいファイル名
```

cpコマンドでは**「-r」**を付けることで、ファイルだけでなくディレクトリもコピーすることができます。
**「cp -r コピーするディレクトリ名 新しいディレクトリ名」**とすることでコピーできます。

```ruby:ターミナル
 $ cp -r コピーするディレクトリ名 新しいディレクトリ名
```

##ファイル・ディレクトリの削除
次は、ファイルの削除について見ていきます。ファイルを削除するには**rmコマンド**を使います。**「rm ファイル名」**とすることで削除できます。

```ruby:ターミナル
 $ rm 削除するファイル名
```

rmコマンドは**「-r」**を付けることでディレクトリも削除することができます。**「rm -r ディレクトリ」**とすることでディレクトリを削除できます。

```ruby:ターミナル
 $ rm -r 削除するディレクトリ名
```

##コマンドの履歴

コマンドラインでは、過去に実行したコマンドを**上矢印キー「↑」**で入力することができます。少し前に実行したコマンドを使いたいときには、とても便利ですので覚えておきましょう。

以上がコマンドラインに関する基礎になります。
最後までご覧いただきまして、ありがとうございます！
SeleniumでWebサイトをPDFとして保存するとき、デフォルトの保存先を変更する方法（chromedirver）（Python）

# 概要
タイトルの通り、SeleniumでWebサイトをPDFとして保存するとき、デフォルトの保存先を変更する方法を解説します。日本語で調べて出てくる情報が、私の調べた限りだと、上手いことできずに少しつまづいたので共有しようと思いました。なお、WebDriverはChrome用のものを公式サイトからダウンロードして使用しています。言語はPythonですが、ChromeDriverを使っていて同じような状況の場合は言語に関わらず有用な情報だと思います。

# 前置き
Seleniumを使って、WebサイトをPDFとしてダウンロードする方法が知りたい方はこちらのサイトを参考にしてください。

https://degitalization.hatenablog.jp/entry/2021/03/13/102805

ただし、こちらのサイトには<font color="DeepPink">デフォルトの保存先の変更方法に関して間違いがあり</font>、それに関する解説が本記事の目的です。

# 本題

まず、結論から書くと、ページの印刷用（WebサイトをPDFとして保存する用）のデフォルトフォルダを変更するには、ChromeDriverのoptionsで`savefile.default_directory`に保存先のフォルダへのパスを設定するだけです。

以下がサンプルコードです。

```python:sample.py
import json
from selenium import webdriver

# 印刷用の設定
appState = {
    "recentDestinations": [
        {
            "id": "Save as PDF",
            "origin": "local",
            "account": ""
        }
    ],
    "selectedDestinationId": "Save as PDF",
    "version": 2
}

profile = {'printing.print_preview_sticky_settings.appState': json.dumps(appState),
           'savefile.default_directory': 'path/to/dir/'} # ここでデフォルトの保存先を設定

chrome_options = webdriver.ChromeOptions()
chrome_options.add_experimental_option('prefs', profile)
chrome_options.add_argument('--kiosk-printing')  #　印刷用のプロンプトが表示された時、自動的に印刷ボタンが押される

driver = webdriver.Chrome(options=chrome_options)  # webdriverを設定
driver.get(url) # urlへアクセス
driver.execute_script('window.print();')  # javascriptを実行して印刷用のプロンプトを表示
```

ポイントは以下のコードの２行目にある`savefile.default_directory`の値を任意の保存先フォルダへのパスに変更することです。

``` python:sample.py
profile = {'printing.print_preview_sticky_settings.appState': json.dumps(appState),
           'savefile.default_directory': 'path/to/dir/'} # ここでWebサイトをPDFとして保存する時の保存先を設定する
```
補足：保存先フォルダの指定には相対パスではなくフルパスが推奨されています

### 少しだけ詳しく解説
上のサンプルコードは主に、Seleniumを使ってWebサイトをPDFとして保存する際に必要なChromeDriverの設定となっています。

各設定に関する説明は[一番最初に貼った記事](https://degitalization.hatenablog.jp/entry/2021/03/13/102805)がわかりやすくまとめているのでそちらに譲りますが、デフォルトの保存先に関しての情報が少し間違っていました。

記事では、デフォルトの保存先のフォルダの変更を、`download.default_directory`の値を変更することで実現しようとしています。しかし、Chromeにおいて「ダウンロードするファイル」の扱いと、「印刷用のプロンプトから保存されるPDF」の扱いは異なり、後者の場合は`savefile.default_directory`の値を変更する必要があります。

`download.default_directory`で設定された値（フォルダの場所）は、Chromeの`設定＞詳細設定＞ダウンロード＞保存先`に反映されています。しかし、実際に試してみればわかりますが、たとえここの設定がデスクトップに変更されていたとしても、印刷用のプロンプトからPDFとして保存する場合、デフォルトの保存先はデスクトップになっていません。つまり、その設定の変更はPDFとして保存する場合には反映されていないのです。

そして、Chromeの場合、その設定の変更は`savefile.default_directory`に値をセットすることで実現できます。

# あとがき
私の調べ方が悪いのか、あるいは以前まではそうだったのか。なぜか日本語では前述の記事以外にも、PDFとして保存する場合のデフォルト保存先は`download.default_directory`の値を変更することで実現できると解説している記事ばかり見つかります。

おかげで、デフォルトの保存先が変更されない理由を特定するのにかなり難航してしまい、ようやくStackOverflowで`savefile.default_directory`に関する解説があった時はずいぶん嬉しかったものでその勢いのままこの記事を書きました。

あまり需要のない情報だからか、日本語で調べてもそれに関する情報が出てこないため、今後同じ状況の人が同じ場所で躓かなければ幸いです。
ユーザー認証の種類

#ユーザー認証とは
リクエストした相手がユーザーであることを確認すること

⚫︎ユーザー認証の方法
ユーザー認証の方法として2つがあります。

1 パスワード認証
2 OpenIDconnect

⚫︎参考資料
https://applis.io/posts/how-to-authenticate-user

#ユーザー認証の種類
代表的なものだと主に3つあります。

1　JWT認証　　JSON Web Token
お互いに情報のやり取りをする時、JSON形式にしたものです。
ジョットとよびます。本人かどうかを確認するときに使います。


2 cookieとsession
cookieとはサーバーなどにどこのpcから送られてきたのかを確認するためのものです。
sessionはクライアントもしくはbブラウザからサーバーに送るときの間の処理みたいなものです。

3 トークン認証
ワンタイムパスワードを生成する機能です。
スマートフォンまたは携帯電話をトークンとして利用するための手続きのことをトークン発行と言うみたいです。
わかりづらい文字列を作り、文字列が合っているか合っていないかを認証したりします。

⚫︎参考資料
https://saitoxu.io/2017/06/rails-spa-authentication
https://ponsuke-tarou.hatenablog.com/entry/2020/09/14/225825
https://www.ibm.com/docs/ja/sva/9.0.4?topic=servers-user-session-management-concepts
(達人)DB設計①

開発業務の中で、DBの設計を一部取り扱うことになった際に参考書で学習(下に文献として記載)。
基本的なこともoutputしておく。（主観で）

##DBの代表
＊RDB
一般的に普及しているDB
＊OODB
javaとかC＋＋とか用のオブジェクト保持用DB
＊XML DB
web上の情報をデータとして扱える
＊KVS
キーとバリューで繋ぐDB

##主要DBMS
*Oracle(有料)
*SQLserver（有料）
*DB2（有料）
*Postgre（無料）
*MySQL（無料）

##設計モデル
*ウォーターフォール
一連の流れで開発を一方通行で進めていく
*プロトタイピング
試作品を使って少しずつ作っていく
*アジャイル
常に進化を続ける

##３層スキーマ
###DBの段階
*外部スキーマ
ユーザーとかから見える
*概念スキーマ
開発者が使う。外部と内部を繋ぐ。
内部にでかいのが入ってて外部では部分的に使いたいよね。
*内部スキーマ
ファイルとか
##参考文献
[達人に学ぶDB設計 徹底指南書 初級者で終わりたくないあなたへ](https://www.amazon.co.jp/%E9%81%94%E4%BA%BA%E3%81%AB%E5%AD%A6%E3%81%B6DB%E8%A8%AD%E8%A8%88-%E5%BE%B9%E5%BA%95%E6%8C%87%E5%8D%97%E6%9B%B8-%E5%88%9D%E7%B4%9A%E8%80%85%E3%81%A7%E7%B5%82%E3%82%8F%E3%82%8A%E3%81%9F%E3%81%8F%E3%81%AA%E3%81%84%E3%81%82%E3%81%AA%E3%81%9F%E3%81%B8-%E3%83%9F%E3%83%83%E3%82%AF/dp/4798124702/ref=as_li_ss_tl?ie=UTF8&qid=1528359416&sr=8-1&keywords=%E9%81%94%E4%BA%BA%E3%81%AB%E5%AD%A6%E3%81%B6db%E8%A8%AD%E8%A8%88&linkCode=sl1&tag=cyclehub-22&linkId=52fe8c80049ae63696c4c6678353365b)
Insomniaの基本的な使い方


#Insomniaについて

APIサーバーにHTTPリクエストを送って、そのレスポンス内容を確認できるAPIクライアントです。


公式：https://insomnia.rest/


#使い方

###基本画面

基本画面は以下の通りです。

![Cursor_と_APIの動作確認やデバッグに便利なInsomniaの使い方.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234233/f6ec25e8-0c15-2cbf-98f1-d8db40b0f1b8.png)

###Request Collection

Insomniaでは「Request Collection」毎にAPIリクエストとレスポンスをまとめることができます。
以下は作成済みの「Request Collection」等が表示されるDashboardの画面です。
右上に表示されている「Create」から「Request Collection」を作成することができます。


![Cursor_と_Insomnia.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234233/25b191d8-26e5-f9f4-bf83-551878c78fb0.png)

###HTTPリクエストの作成方法

HTTPリクエストを作成する際は以下の画面より作成することができます。

![Cursor_と_Test.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234233/f814a15a-3a48-875f-4612-6c776f38cd2a.png)

###認証付きのHTTPリクエストを作成方法

以下のように「Auth」タブをクリックすると、APIサーバの認証方法を選択できます。
自分の行いたい内容の認証方法にそって「メニュー」から選択しHTTPリクエストを作成します。

![Cursor_と_Test_–_Auth_Request.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234233/30fe847b-7db8-1a1c-84e9-6232230e20aa.png)
PHPでFizzBuzz

###概要
FizzBuzz問題を解く機会があったので、PHPで書いてみました。

## ルール
1〜100までで
3で割り切れる時は、「Fizz」を表示。
5で割り切れる時は、「Buzz」を表示。
3と5で割り切れる時は、「FizzBuzz」を表示。
その他は、数字を表示する。

## コード
```index.php
<?php
for ($i = 1; $i <= 100; $i++){
    if ($i % 3 == 0 && $i % 5 == 0){
        echo "FizzBuzz";
    } elseif ($i % 3 == 0){
        echo "Fizz";
    } elseif ($i % 5 == 0){
        echo "Buzz";
    } else {
        echo $i;
    }
    echo "\n";
}
?>
```
## 結果
```
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
16
17
Fizz
19
Buzz
Fizz
22
23
Fizz
Buzz
26
Fizz
28
29
FizzBuzz
31
32
Fizz
34
Buzz
Fizz
37
38
Fizz
Buzz
41
Fizz
43
44
FizzBuzz
46
47
Fizz
49
Buzz
Fizz
52
53
Fizz
Buzz
56
Fizz
58
59
FizzBuzz
61
62
Fizz
64
Buzz
Fizz
67
68
Fizz
Buzz
71
Fizz
73
74
FizzBuzz
76
77
Fizz
79
Buzz
Fizz
82
83
Fizz
Buzz
86
Fizz
88
89
FizzBuzz
91
92
Fizz
94
Buzz
Fizz
97
98
Fizz
Buzz
```
sagemathをインストールして起動するとModuleNotFoundErrorが出た場合の対処法

# 環境
* Ubuntu 20.04
* anacondaインストール済み

# 起きたこと
```bash
(base) hoge@hogehoge:~$ sudo apt-get install sagemath
```

でsagemathをインストールして

```bash
(base) hoge@hogehoge:~$ sage
```

で起動しようとすると以下のエラーが起きた。

```bash
Traceback (most recent call last):
  File "/usr/share/sagemath/bin/sage-ipython", line 9, in <module>
    from sage.misc.banner import banner
ModuleNotFoundError: No module named 'sage'
```

# 結論
anaconda-base環境を

```bash
(base) hoge@hogehoge:~$ conda deactivate
```

で終了させた上でsageを打つとエラーが起きずに起動した。ターミナルを起動した瞬間からsageが動く環境にしたい場合、.bashrcのanacondaがパスを通している部分を消す([こちら](https://ask.sagemath.org/question/34416/importerror-no-module-named-sage/)を参考)。
私の場合はanaconda環境でも使えるようにしたかったので、(念の為sagemath用の仮想環境を作って起動した上で)

```bash
conda install -c conda-forge sage
```

でsageをインストールすることで使えるようにした。今の所それで使えているが問題が起きたら追記する。

# 原因
[こちら](https://doc.sagemath.org/html/ja/tutorial/introduction.html#installation)に書いてある通りsagemathをインストールするとsagemathを使うのに必要なものがまとめてインストールされる。このときpythonにもsageというモジュールがインストールされるのだが、それがインストールされるpython環境がanacondaではなく内部にもともとあるpython環境（何と呼ぶのかわからない...）にインストールされるため、anaconda-base環境が起動している状態では動かないのだと思われる。
[Flutter] 絵文字やマテリアルアイコンからImageデータを取り出す

ちょっとしたアプリを作るだけなのに画像リソースとか用意するのは面倒なので、Flutterでお手軽にアイコンっぽいものを表示するのに、Textウィジェットで絵文字とかIconウィジェットの定義済アイコンを使ってます。

だいたいウィジェットそのままで間に合うのですが、WebViewに定義済のマテリアルアイコン貼り付けたいとか、ListViewのアイコンに絵文字を使いたいとかで、絵文字やマテリアルアイコンからImageデータを取り出したいときがあります。それの簡単な方法を思いついたのでメモしました。もっとちゃんとした方法があるような気がしますが。（誰か教えてください）

###Imageロード失敗時の代替指定を使う
ImageクラスのイメージはassetかFileかnetかmemoryから読み出すのですが、読み出しに失敗したときに表示する代替ウィジェットをerrorBuilderパラメータで指定できます。わざとロードできないファイルでイメージ構築して、errorBuilderで使いたい絵文字を表示するTextウィジェットとかIconウィジェットを指定するわけです。簡単でしょ。

```dart:マテリアルアイコン
Image texticon = Image.file(File(""), 
  errorBuilder: (BuildContext context, Object exception, StackTrace? stackTrace) { 
    return const Icon(Icons.text_snippet_outlined);
});
```
```dart:絵文字
Image sadicon = Image.file(File(""), 
  errorBuilder: (BuildContext context, Object exception, StackTrace? stackTrace) { 
    return const Text('😢');
});
```

ListViewで使うと次のようになります。一番上が Icon( Icons.text_snippet_outlined ) で、下２つは絵文字の「😢📁」です。
![icons.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114010/f865fdf2-2389-9d43-089c-b3adf9349b82.png)
ただし欠点もあって、まずロードに失敗するので、デバッグすると本筋と関係ないところで例外起こして止まります。Image.file()だとロード結果がキャッシュされるのか停止は一回で済みますが、Image.asset()で同じことをやると何度も止まってうっとおしい。本来の使い方でないことは確かですね。

いいところはawait指定が不要なので、Widget buildやコンストラクタなど好きなとこに書けるとこです。
React 入門道場　~JSX　基礎文法~

# はじめに
Reactを学習していてJSXについて理解が浅かったので今回簡単ににまとめてみました。


https://qiita.com/kinoshitaken123/items/d28d1ad3dc1a11f19cfe

JSXって、そもそも何なのと思った人はこちらから参照ください。

# JSX基礎文法　壱

__①Reactライブラリをimportする__

```js
import React from 'react';
```

__②return文の中がJSX構文__

```jsx
import React from 'react';

const BlueButton = () => {
   return (
    <button className={'btn-blue'}>
      Click me!
    </button>
  )
}

export default BlueButton;
```

基本的にはHTMLと同じ構文。class要素はclassNameに変わる:point_up:
JSXの見た目はHTMLですが、実際Javascriptで注意が必要！！！！
classと記載してしまうとオブジェクトのclassと認識してしまうので、明示的にclassNameと分けるためにclassNameとついている。その後にクラス命を記載する必要がある。

# JSX基礎文法　弍

```jsx
import React from 'react';

const Thumbnail = () => {
   const caption = 'sample写真'
   const imagePath = '/img/sample.png'

   return (
　　　　　　　 <div>
      <p>{caption}</p>
      <img src={samplePath} alt={'sample写真'} />
    </div>
  )
}

export default Thumbnail;
```

1.キャメルケースで記述

imagePath

２.{}で変数を扱える

{}を使うとJavascriptの世界だと明示的に使用することができる。
const caption = 'sample写真'
Pタグで{caption}を使うと最終的な出力として「sample写真」の文章が出力される。

同様に、
  <img src={}にsamplePathを渡すと/img/sample.pngが出力されます。

 __{　}をJSXの世界になる__
3.閉じタグが必要

/>　閉じタグがないとエラーになるので記載するようにしましょう！
【React】JSX attributes must only be assigned a non-empty expressionの対処法

<h2>症状</h2>
Reactでコンポーネントを作成していた時、以下のエラーが発生しました。
翻訳すると、「JSX属性には、空でない式のみを割り当てる必要があります」でした。

```react:error
SyntaxError: 絶対パス JSX attributes must only be assigned a non-empty expression
```

該当のソースは以下です。

```react:Hoge.jsx
export function Hoge () {
　function submitHandle() {
    return "Hoge"
  }

  return (
    <buttom onClick={}></buttom>
  )
} 
```

<h2>解決方法</h2>
buttomの中のonClickイベントの中身を指定することで解決しました。
エラー内容そのままで、jsx要素であるreturn内部のbuttomに何も指定されていなかったため、エラーが出ていたようです。

```react:Hoge.jsx
export function Hoge () {
　function submitHandle() {
    return "Hoge"
  }

  return (
    <buttom onClick={() => submitHandle}></buttom>
  )
} ​
```

<h2></h2>