OmniAICreator/Qiita-1.07M huggingface dataset:
【Rails】HerokuでApplication error（エラーコードH10 (App crashed)）時の対処法【Ruby】

<h2>症状</h2>

<a href="https://railstutorial.jp/chapters/sign_up?version=6.0#sec-professional_grade_deployment">Railsチュートリアルの「第7章 プロのデプロイ」</a>を実施時に事象が発生。


rails sやrails testでアプリをローカル環境で動かしてアプリの動作では問題ないことを確認し、Herokuにデプロイした時の設定ミスなどに問題があると考えました。(Rails 6.0.3を使用)
![キャプチャ.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/927880/c5e7d8e7-bf0c-7a93-fde1-bf74248b60a2.jpeg)

画像通りheroku logs --tailを入力し、エラーコードにH10が表示されていることが分かりました。
「error code=H10 desc="App crashed"」

```
heroku logs --tail

#表示されたエラー
at=error code=H10 desc="App crashed" method=GET path="/" host=hidden-depths-37821.herokuapp.com request_id=b127bdcc-e0a9-4bad-a984-4d86ef49c725 fwd="61.215.149.134" dyno= connect= service= status=503 bytes= protocol=https
```

<a href="https://qiita.com/kents1002/items/e1b90c71897c55b8e870">この記事</a>を参考に、resetを行ったが効果はありませんでした。
どちらも「Couldn't find that app.」とアプリが見つからないと怒られています。

```
heroku restart -app

#結果
Restarting sample_app dynos on ⬢ pp... !
 ▸    Couldn't find that app.
```

もしくは

```
heroku restart -app application_name

#結果
Restarting sample_app dynos on ⬢ pp... !
 ▸    Couldn't find that app.
```

今度は<a href="https://qiita.com/at-946/items/ce4db1d80429d6984cfc">この記事</a>を見て、heroku appsを実行し、アプリ自体があることを確認しました。

```
heroku apps

#結果
=== メールアドレス　Apps
#heroku上のapp一覧が表示された
heroku-sample-1234
```



<h2>解決策</h2>
再度手順を見直し、puma.rbの記載を修正したら解決できました。
puma.rbの中身を<a href="https://railstutorial.jp/chapters/sign_up?version=6.0#code-production_webserver_config">Railsチュートリアルのリスト 7.35</a>のみに修正しました。

```
# Pumaの設定ファイル
max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count }
threads min_threads_count, max_threads_count
port        ENV.fetch("PORT") { 3000 }
environment ENV.fetch("RAILS_ENV") { ENV['RACK_ENV'] || "production" }
pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }
workers ENV.fetch("WEB_CONCURRENCY") { 2 }
preload_app!
plugin :tmp_restart
```

<h2>参考</h2>
Ruby on Rails チュートリアル　第7章
https://railstutorial.jp/chapters/sign_up?version=6.0#code-production_webserver_config

Herokuでデプロイした際にApplication error（エラーコードH10 (App crashed)）が出た時の対処法
https://qiita.com/kents1002/items/e1b90c71897c55b8e870

Heroku CLIで「 ▸ Couldn't find that app.」というエラーが出てきた時の対処メモ
https://qiita.com/at-946/items/ce4db1d80429d6984cfc

Heroku コマンド集
https://qiita.com/yu_eguchi/items/8cd53942b88b7ff2fecb#heroku-apps
よく使うブックマークレット集

## ブックマークレットひな形

```javascript
javascript: (function () {
  let input = prompt("何か入力してください。", "foo");
  input = input.replace('a', 'a');  // 通常版
  input = input.replace(/a/g, 'a'); // 正規表現版
  prompt("prompt", input);
})();
```

# よく使うJS部品

```javascript
/*数値ランダム4桁生成*/
let min = 1000;
let max = 9999;
let randomNumber = Math.floor(Math.random() * (max - min + 1)) + min;
```

```javascript
/*現在日付yyyymmdd生成*/
const newDate = new Date();
let y = newDate.getFullYear();
let m = ('00' + (newDate.getMonth()+1)).slice(-2);
let d = ('00' + newDate.getDate()).slice(-2);
date = y + '-' + m + '-' + d;
```

# テスト用メールアドレス生成ブックマークレット

```javascript
javascript: (function () {
    /*現在日付yyyymmdd生成*/
    const newDate = new Date();
    let y = newDate.getFullYear();
    let m = ('00' + (newDate.getMonth()+1)).slice(-2);
    let d = ('00' + newDate.getDate()).slice(-2);
    date = y + '-' + m + '-' + d;

    /*数値ランダム4桁生成*/
    let min = 1000;
    let max = 9999;
    let randomNumber = Math.floor(Math.random() * (max - min + 1)) + min;

    let email = date + "-" + randomNumber + "@co.jp"; /*2021-03-11-8349@co.jp*/
    prompt("prompt", email); 
})();
```

# DOM操作

```javascript
document.getElementById("hello").value = "foo";
document.getElementById("hello").onclick;
document.getElementsByClassName('hello').item(0).value = "foo";

let elements = document.getElementsByClassName('hoge');
let len = elements.length;
for (let i = 0; i < len; i++) {
    elements.item(i).style.border="2px solid #0000ff";
}
```

# JSのソースコードを確認する際によく使うサイト

JSソースのコンパイルを確かめるサイト
https://closure-compiler.appspot.com/home

JSソースを整形するサイト
https://lab.syncer.jp/Tool/JavaScript-PrettyPrint/
Qiita Daily Survey memo 2021.03.11

# Qiita Daily Survey memo 2021.03.11
Qiita の記事を可能な限り毎日読むために、読んだmemoを公開することでモチベーションを維持しようという試み。
今日は趣向を変えて、Trello について調べました。

## モチベーション
私は、タスク管理が非常に苦手です。
そのため、社会人になってからタスク管理で非常に苦労しています…。
もちろん克服のためにExcelで管理したり、VBAでスクリプト組んで管理してみたり、Webサーバ立てて管理してみたりといろいろやりましたが、続いているものがありません。

ただ、Qiita Survey を続けているうちに「みんなどうやってやってるんだろ？」と思って調べてみると、タスク管理は Trello を使っている方が多そうでした。（体感）
もちろん Trello を使ってタスク管理をしようとしたこともあります。（3敗）
もしかしたら、使い方が悪かったのかも？と思い、皆様の使い方を調べて真似することで、自分に合ったタスク管理ができるのでは…？と思い Survey しました。


## 使い方

### [小規模チームのタスクをTrelloで管理する](https://qiita.com/maimax/items/e81e7fa19b775fd817c0)
浪川 舞(maimax) さんの記事。
複数人でプロジェクトをされる際に、Trelloを使われたという記事になります。
個人利用を想定しているので、その部分では異なりますが、いくつかのプラグインを導入され、工数の可視化をされていることが私に刺さりました。
まさに、タスク管理と自分の時間の可視化をしたい私にピッタリの記事。
それぞれのアドインについて特徴とキャプチャで説明してくださっています。
また、使い方のフローも説明してくださっており、参考になりました。

### [Trelloと Qiita Team Power-Upを連携させて良いと感じたこと](https://zine.qiita.com/topics/trello-qiitateam-power-up/)
ぷぎえもん(pugiemonn) さんの記事。
Qiita Team と連携することで、Trello がもっと使いやすくなりました、という記事です。
Qiita Team については、この記事で初めて知りましたが、プロジェクト管理のために外部ツールと連携するというのが参考になりました。
GitHub にも似たようなプロジェクト管理の"何か"があった気がしますし、使ったこともあります。
また、Slack と連携するという話はよく耳にしていました。
特に Google Calender と連携して、予定の調整とかに使えると嬉しいなーと思いました。


### [【Trello】社内のタスク管理をTrello + Slackで効率化した時にやったこと](https://qiita.com/tktktktk/items/969d914f7a92bd16fe64)
Takeharu .K(tktktktk) さんの記事。
というわけで、 Trello + Slack について説明してくださっている記事を Survey しました。
本記事では、特にリストとしてこういうものを用意して運用したよ、というのを書いてくださっており、そこが特に参考になりました。


### [TrelloをButlerで自動化してより活用しよう](https://qiita.com/mm-001/items/a19836b95a83d3bce923)
mm-001 さんの記事。
Daily Task を自動生成したいなー…と調べていた時に参考させていただいた記事になります。
Trello には、 Power-Up という拡張機能群があり、その中の一つに Butler というのがあるよ、という記事です。
これを使うことにより、自動化したいタイミングと内容をGUIでお手軽に設定できる、というものです。
Power-Up について本記事で知り、すごくたくさんの拡張機能があることを知りました。
実際には、ここで Power-Up のことを知り、他の記事を参考にCard Repeater Power-UpsというPower-Upで自動生成の設定をしました。

### [Trello で定期的に発生するタスクをカード化したいときに便利な Card Repeater Power-Ups](https://qiita.com/tbpgr/items/04eeacabd0e33bc34f04)
てぃー びー(tbpgr) さんの記事。
Daily や Weekly 、Monthly のタスクを自動生成してもらうための Power-Up 「Card Repeater Power-Ups」をご紹介いただいている記事です。
使い方、設定方法がシンプルで分かりやすかったので、試しに使ってみようとなりました！


## API
### [py-trelloことはじめ](https://qiita.com/nozomale/items/c2c30fc2a8a89b37e921)
Nozomin(nozomale) さんの記事。
Daily Task の自動生成がしたかったので、拡張機能ではなくAPIで直接カード作れないかな、と調べていたら、まさにやりたいことを説明してくださっていた記事になります。
記事内ではカードの生成だけでなく、ボードの操作やリストの操作の説明も、分かりやすく記載してくださっています。


## つれづれ
「こういう風に Trello 使うとよかったよ！」の素晴らしい記事がたくさんあるので、もっともっと Survey していろいろ試してみます。
Windows10の「アンドゥ(CTRL+Z)」問題の恐ろしさを最近になって本当に理解できた！

## はじめに
みなさんは、「アンドゥ(CTRL+Z)」をしてみても「何も反応しなかった」という経験はありませんか？そんな時は**要注意**です！

その時、みなさんの大切なファイルが、１つ消滅したかもしれないのです。

## 昔のニュース
「Windows10で、エクスプローラ上でアンドゥ(CTRL+Z)すると、直前の操作が無警告で取り消される。」というニュースが何年も前に流れましたが、今になって、本当の恐ろしさに気がつきました。

当時は「ふーん」としか思わず、ほとんど記憶にも残りませんでした。

## アンドゥ(CTRL+Z)の作用
この動作は、エクスプローラの機能で実行した、「新規ファイルの作成」、「ファイル名のリネーム」、「ファイルの移動」、「ファイルの削除」などの操作が「取り消される」ことです。
他のアプリで作成したりコピーしたファイルには影響しません。

例えば「コマンドプロンプト」のコピー
> copy a.txt b.txt

などで複製したファイルが削除されることは無い（実際に試して確認しました）が、
エクスプローラ上で複製（ファイル選択→Ctrl+C → Ctrl+Vや、右クリック→コピー→右クリック→貼り付け）する操作とか、マウスドラッグで移動した操作などが無警告で取り消されます（複製したファイルが消滅したり、移動したファイルが移動先から移動元へ戻る。）。

## NASへの影響
ネットワークハードディスクへファイルやフォルダをコピーする操作も、アンドゥ(CTRL+Z)で取り消されました。（ネットワークハードディスクによっては、「trashbox」などのフォルダに移動される場合もあるでしょうが、気付かずその中身を削除してしまえば終わりです。）

## エクスプローラを閉じても
この動作は、エクスプローラを閉じても中断せず、デスクトップ上でアンドゥ(CTRL+Z)しても同じ結果になります。Windowsを再起動するまで、何度でも過去の操作履歴を遡って、アンドゥ(CTRL+Z)の動作がどんどん実行されます。

その結果、別のアプリで作成した最も新しいファィルは残っているのに、その前にエクスプローラでコピー（複製）したはずのファイルが消滅（ごみ箱にも残らない）したり、移動先のファイルが消滅（移動元に戻る）したり、作成したフォルダが消滅（ごみ箱にも残らない）したりします。

## ありそうな状況
ありそうな状況としては、普段、Windowsユーザーは、ブラウザとかテキストエディタとかエクスプローラとか、複数のアプリを同時に起動して、たくさんのウインドウが開いていることがよくあるでしょう。

そんな時、ふと、直前の操作を取り消そうとして「Ctrl+Z」を実行してみたら、「あれ？何も反応が無い...もう一度やってみるか...えいっ！...あれ？おかしいな？...もう一度、えいっ！...えいっ！えいっ！...」。

その直前には、ノートパソコンのタッチパッドにうっかり触れてしまっていたり、
プッシュ通知とかウイルスソフトの通知とかでウインドウのフォーカスがデスクトップに移動してしまっていて...

そんな時に、直前の操作を、意図せず取り消してしまっていることがよくあるのでは、と推測します。

## 警告を表示させる設定
なお、「Delete」キーでファイルを削除しようとした時に警告を表示させるよう設定することができるが、この警告は、アンドゥ(CTRL+Z)によるファイル削除には機能しません。

## 再起動しかない
つまり、Windowsをシャットダウンか再起動しない限り、何日前の操作でもアンドゥ(CTRL+Z)可能...なのだと思います。（試すのが恐いので試していないが、どなたか試してみてください。「休止状態」から復帰しただけでは、エクスプローラの操作履歴はクリアされず、複製しておいたテストファイルが消滅しました）

## 対策
Windowsでプログラミングや仕事している方は、自分が編集したファイルが行方不明になったり、編集前の状態に戻ってしまったりとかありませんか？
Windowsユーザーは、エクスプローラを使うたび、再起動するようにした方がいいかもしれません...
【フィッシングサイト探索Tips】似た構造のWebサイトを探す

#概要
フィッシングサイトの探索手法の1つとして、ある共通項を手掛かりに芋づる式に探すという手法があります。
具体的には

- IPアドレス ⇒ あるフィッシングサイトと同じIPアドレスに紐付く、別のフィッシングサイトを探す
- ドメインの文字列(企業名・サービス名等） ⇒ あるフィッシングサイトと類似したドメイン名を持つ、別のフィッシングサイトを探す

etc...

今回は備忘として「Webサイトの構造」を手掛かりに探索する手段を記述します。

###この手段を用いる理由
他の手掛かりによる探索手段と組み合わせることで、類似した構造のフィッシングサイトに対する探索効率向上が期待できます。

- 未知のIPアドレスと紐付くフィッシングサイトを発見できる。
- ランダム文字列や、企業名・サービス名と無関係な文字列のドメインによるフィッシングサイトを発見できる。

※ドメイン名を企業名・サービス名と無関係な文字列にする（企業名・サービス名をサブドメインなどに入れる）ことで、ドメイン検索による探索を回避しているフィッシングサイトも多い。

###有効性の根拠
多くのフィッシングサイトにみられる下記の傾向を利用します。

- フィッシングサイトはその目的を果たすために、視覚的に正規サイトと似せなければならない。
- 多くのフィッシングサイトは0ベースではなくツールによって構築されている。

⇒結果的に、同一の企業（サービス）を模倣したフィッシングサイトであれば構造は類似する傾向にある。

#結論
urlscan.io の similar 機能を使用します。
フィッシングサイトに限らず、異なるインフラにある同様の構造を持ったWebサイトを一覧化する機能です。
※試験的な機能との記載あり。

#操作方法
※業務で利用する際は組織のポリシーに従ってください。

1.対象とする企業・サービスのフィッシングサイトを1つピックアップする。（新しいほうが良い）
![pish01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/670024/5d9a7e8b-0b51-4e26-2ce0-695c592b7bdc.png)

2.当該フィッシングサイトのURLをurlscan.ioでスキャンする。
![pish02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/670024/c52cb89f-3d44-c5e7-93d6-fbb511b355d0.png)

3.スキャン結果画面より「similar」をクリックする。
![pish03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/670024/d72e049f-6b92-5909-9bbb-dcfbb6300310.png)

4.結果（詳細は後述）が表示される。
![pish04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/670024/6c93350a-0a30-f25f-f7d7-828003730e07.png)

##similar 機能の結果について
- domain：同一ドメイン上の類似Webサイト
- ASN but different domain：同一ASN上にある別ドメイン上の類似Webサイト
- IP but different domain：同一IPアドレスに紐づく別ドメイン上の類似Webサイト
- submitted URL：同一URLが送信先となっている類似Webサイト

#注意事項と免責
- 本記事で取り上げた機能はurlscan.io の仕様変更により使えなくなる可能性があります。
- urlscan.io はpublicモードのスキャン履歴が公開されるため、基本的にprivateモードでのスキャンを推奨します。
- 機微情報を含むURL、非公開コンテンツのURLはスキャン及び公開について十分なリスク評価を実施し、取り扱いに注意してください。
- 本手法によって読者各位が期待する効果を得られることの保証はしておりません。また、urlscan.io を使用した結果の責任は負いません。
Java学習　基礎編　~条件分岐 switch文 ~

Java学習の備忘録になります。
内容は初心者なので基礎的な部分となります。
Javaに興味がある方やJava学習初心者の参考になれば幸いです。

* * *
### 条件分岐
簡単にいうと、
『**特定の状況のときだけ、ある処理を行う**』
というプログラムのことを条件分岐と言う。

#### switch文

if文のほかに、条件分岐には、**switch文**があります。
「とある値が何であるか」で処理を分けたいとき(特にその分岐が多い時)、if文よりシンプルに書ける。

記述方法は下記になり、**条件の値がcaseの値と一致するとき、処理が実行される。**
( )の中の条件の値と、caseの値が「 == 」になるとき、処理が実行される。

######breakとは

記述中にあるbreakは、switch文を終了するための命令です。
breakがなかった場合、合致したcaseの処理を実行した後、その次の処理も実行してしまう。意図せぬ処理が起こってしまうので記述を忘れないよう注意しましょう。

######defaultとは

どのcaseとも一致しなかったときに実行する処理を、defaultに指定することができる。
こちらは、if文でいうelseに似ています。

```Main.java
switch (条件){
  case 値1:
    処理;
    break;
  case 値2:
    処理;
    break;
  case 値3:
    処理;
    break;
  default:
    処理;
    break;
}

//case、defaultの後ろは、(:) コロンになるので注意。
```

* * *
#### おわりに
結構使う機会が多いそうなので覚えておきましょう！
M1 MacBook Air にアプリケーションをインストール

# 概要

開発環境以外でも M1 MacBook Air を快適に使う為、インストールしているアプリケーションを紹介します。

まだまだ追記予定です。


# 参考 URL

参考にさせて頂いている先人の方々です。

https://note.com/sho7650/n/n84ce562fa00c

https://appleshinja.com/macfreeapps

M1 に対応しているか確認出来る便利なサイトです。

https://isapplesiliconready.com/



# インストールしたアプリケーション

## Google Chrome - M1 対応

これは外せない。
正直、M1 の性能をフルに引き出していると思われる Safari をメインにする予定でしたが、
色々、慣れが必要だな、と感じ。不便だな、と思い。
ページ丸ごと「日本語翻訳」する機能が決め手になり、
Chrome がメインに戻りました。


## Google Chrome Canary - M1 対応

仕事用の Intel MacBook Pro と使い方が逆ですが、
こちらを仕事用のブラウザにしています。
（仕事用の Mac は、Chrome を仕事用、Canary を個人用として使い分けています。）

別アプリとして Dock に配置出来るので便利！


## DeepL - M1 対応か不明

自然な日本語翻訳はこちらに軍配が上がるかな、とインストールしています。
まあ、あまり使う機会は無いですが。


## Slack - M1 対応

仕事用です。便利ですよね。


## TeamViewer - M1 対応

こちらも仕事用です。
主に使用する社内の Windows10 PC へ MacBook から使用するのは変な感じです。


## Bitwarden - M1 未対応（ Rosseta 2 対応）

個人用です。
iPad Air、iPhone、Windows PC と連携してメッチャ便利です。


## Microsoft To Do - M1 未対応（ Rosseta 2 対応）

個人用です。
家族との連携用に、仕方無くこれって感じです。


## LINE - M1 未対応（ Rosseta 2 対応）

個人用です。
複数 PC に同時とはいかないまでもログイン出来れば楽なのになぁ。
毎回 QR コードログインは結構面倒臭いです。


## FileZila - M1 未対応（ Rosseta 2 も未対応かな？）

FFFTP の代わりに、ライクなものを選択しました。
まだ、接続して満足しただけ。
実際には rsync コマンドとかでやりとりする事が多いと思います。


## iTerm2 - Universal 対応

Rosseta 2 用に。

https://iterm2.com/

https://orebibou.com/ja/home/201512/20151206_001/#:~:text=iTerm2%E3%81%A7%E3%81%AF%E3%80%81%E5%9F%BA%E6%9C%AC%E7%9A%84%E3%81%AB,%E3%82%A6%E3%82%A3%E3%83%B3%E3%83%89%E3%82%A6%E3%81%8C%E5%88%86%E5%89%B2%E3%81%95%E3%82%8C%E3%82%8B%E3%80%82

https://laugh-raku.com/archives/3127#:~:text=%E3%80%8Ccommand%20%2B%20shift%20%2B%20D%E3%80%8D,%E3%81%97%E3%81%9F%E3%81%84%E3%81%A8%E3%81%8D%E3%81%AB%E4%BE%BF%E5%88%A9%E3%81%A7%E3%81%99%E3%80%82

既存のターミナルも、

https://qiita.com/hmiyakoshi0803/items/78bd9075ce8af70225bf

によって screen ってのを入れると分割出来そうだけど、
癖がありそうなので一旦保留。


## CheatSheet - M1 対応

https://www.mediaatelier.com/CheatSheet/

んー、微妙に欲しい情報と違う様な感じ。
まあ、使わせて頂いて様子見。


## Clipy - M1 未対応（ Rosseta 2 対応）

https://clipy-app.com/

これまで、クリップボード系のアプリは使っていませんでしたが、
折角ですし、ガシガシカスタマイズしましょう。


## Automator - 既存アプリケーション

https://www.head-t.com/2017/11/2017-11-08.html#:~:text=%E3%82%B7%E3%83%A7%E3%83%BC%E3%83%88%E3%82%AB%E3%83%83%E3%83%88%E3%81%A7%E5%85%A5%E5%8A%9B%E3%81%A7%E3%81%8D%E3%82%8B%E3%82%88%E3%81%86,%E3%82%88%E3%81%86%E3%81%AB%E3%81%AA%E3%82%8A%E3%81%BE%E3%81%97%E3%81%9F%E3%80%82

https://shellscript.sunone.me/date.html

インストールしたのではありませんが、
最近、フォルダ名やスクショのファイル名を「20210311_0311」とか、
「YYYYMMDD_HHMM」形式で手入力する事が多かった為、
上記の記事を参考に「command+_」で一発出力される様にしました！（パチパチパチパチ

以上
Herokuにpushしようとしたら「 Failed to install gems via Bundler.」というエラーが出た


# 考えられる原因


調べたところ主な原因としては以下のものがあるっぽい

- bundle install をし忘れている
- gemのsplite3が本番環境で適用されている
- Herokuとローカルの bundler のバージョンが異なる


# 対応


###  bundle installをし忘れていた時


単純に bundle install すればいい

```
$ bundle install --without production
$ git commit -a -m "Update gemfile.lock for heroku"
$ git push heroku master
```


### splite3が本番環境で適用されている時


本番環境ではPostgresqlを用いるようにする

```:Gemfile

・
・
・

group :development, :test do
  gem 'sqlite3'

　・
　・
　・

end

・
・
・

group :production do
  gem 'pg'

　・
　・
　・

end
  
```


### Herokuとローカルのbundlerのバージョンが異なる時

ローカルに同じバージョンをインストール

```
% gem uninstall bundler #ローカルのbundlerをアンインストール
% gem install bundler --version '2.2.11' #デプロイ先のHerokuと同じversionのbundlerをローカルにインストール

% bundler -v #bundlerのversion確認
Bundler version 2.2.4 #意図してたバージョンと違う

% gem list bundler #ローカルにインストールされているbundlerのversionリストを表示

% rm gemfile.lock #Gemfile.lockを削除
% bundle _2.1.4_ install --without production　#version指定してbundle install

% git add -A
% git commit -m 'Change Bundler version 2.2.4 to 2.2.11'

% git push heroku master
```


## それでも治らない、、、


上の原因と対処法をやってみたがエラーは治らず。。。

上記以外に原因が？



エラーメッセージちゃんと読めば書いてた。

```
remote:        Your bundle only supports platforms ["x86_64-darwin-20"] but your local platform
remote:        is x86_64-linux. Add the current platform to the lockfile with `bundle lock
remote:        --add-platform x86_64-linux` and try again.
remote:        Bundler Output: Your bundle only supports platforms ["x86_64-darwin-20"] but your local platform
remote:        is x86_64-linux. Add the current platform to the lockfile with `bundle lock
remote:        --add-platform x86_64-linux` and try again.
```

指定された通りに

```
$ bundle lock　--add-platform x86_64-linux
```

を実行。

コミットも忘れずに

```
$ git add .
$ git commit -m 'Add platform'
```

すると、Herokuのプッシュに成功！

まじで長かった。。。


参考：
https://yumishin.com/heroku-push-error/#i-4
https://tex2e.github.io/blog/ruby/rails-on-heroku
Ubuntu 20.10のSteamでOneShotが起動しない問題

## 何？

Steamで購入した[OneShot](https://store.steampowered.com/app/420530/OneShot)をUbuntu20.10で起動しようとしたが起動ボタンを押しても起動しなかったので解決した。
結論として、OneShot自体はLinuxに対応こそしているがあまりメンテされていないようで、古いライブラリを整理するとうまく行った。

## 事象1

直接起動してエラー出力を読む。

```bash
$ cd　~/.local/share/Steam/steamapps/common/OneShot
# steam経由で開かないと正常に起動しない
$ steam steam://rungameid/420530
...
./oneshot: ~/.local/share/Steam/steamapps/common/OneShot/librt.so.1: undefined symbol: __clock_nanosleep, version GLIBC_PRIVATE
```

Steam Communityで検索すると先人たちが苦労している様子が見えた。
他のLinux系OSでも同様の問題が起こっているようだ。

- https://steamcommunity.com/app/420530/discussions/search/?q=+__clock_nanosleep%2C+version+GLIBC_PRIVATE&sort=time


ググると[ヒットした](https://www.reddit.com/r/archlinux/comments/ge38n6/game_on_steam_doesnt_launch_while_other_games_do/fwvxc2j?utm_source=share&utm_medium=web2x&context=3)記事より:

```bash
$ sudo find /usr/lib/x86_64-linux-gnu -name librt.so* | xargs ls -l
lrwxrwxrwx 1 root root 13 12月 14 14:45 /usr/lib/x86_64-linux-gnu/librt.so.1 -> librt-2.32.so
$ rm -rf librt.so.1
$ ln -s /usr/lib/x86_64-linux-gnu/librt-2.32.so librt.so.1
```

新しめの`librt`へのシンボリックリンクに差し替えた。

## 事象2

するとエラーが変わり:

```bash
$ steam steam://rungameid/420530
libGL error: MESA-LOADER: failed to open radeonsi (search paths /usr/lib/x86_64-linux-gnu/dri:\$${ORIGIN}/dri:/usr/lib/dri)
libGL error: failed to load driver: radeonsi
libGL error: MESA-LOADER: failed to open radeonsi (search paths /usr/lib/x86_64-linux-gnu/dri:\$${ORIGIN}/dri:/usr/lib/dri)
libGL error: failed to load driver: radeonsi
libGL error: MESA-LOADER: failed to open swrast (search paths /usr/lib/x86_64-linux-gnu/dri:\$${ORIGIN}/dri:/usr/lib/dri)
libGL error: failed to load driver: swrast
X Error of failed request:  GLXBadContext
  Major opcode of failed request:  152 (GLX)
  Minor opcode of failed request:  6 (X_GLXIsDirect)
  Serial number of failed request:  111
  Current serial number in output stream:  110
```

とlibGLエラーが出た。

このエラーに関してはSteam Communityに[スレがあり](https://steamcommunity.com/app/420530/discussions/1/1639794468037255621):

```bash
$ rm -rf libdrm.so.2 libGLdispatch.so.0 libstdc++.so.6
```

として再度起動すると、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278919/38a557bc-e591-db4f-2f77-8506eba3f40a.png)

うまく行った。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278919/7e3e06e7-b025-b4f6-4f6e-3a3cffc83c88.png)

日本語もOK。

## 結論

解決

## 他の解決法は？

[このスレッド](https://steamcommunity.com/app/420530/discussions/0/3112521650153028839/)によると、

```bash
$ cd ~/.local/share/Steam/steamapps/common/OneShot
$ rm -rf libgio-2.0.so.0 libglib-2.0.so.0 libsystemd.so.0 librt.so.1 libstdc++.so.6
```

で動作すると書かれているのでそちらを試しても良い。
ラズパイで作ったスマートスピーカーでGoogle Assistantのデモプログラムを実行したい,Segmentation fault

#Segmentation fault
RaspberryPiでGoogleのAssitantAPIでAIスマートスピーカーを自作し、Google Assistantのデモプログラムをgoogle-assistant-demoコマンドで実行したのですがSegmentation faultになってしまいました。（注：プログラム上()で囲まれたIDなどは、自分のIDと読み替えてください。）

```
(env)$google-assistant-demo --project-id (自分のプロジェクトID) \
> --device--model-id (デバイスモデルID)
Segmentation fault
```
#解決法
Assistant Libraryのバージョンが1.0.1から1.1.0にバージョンアップすると上手くいきました。

```
$python -m pip install --upgrade google-assitant-library==1.1.0
```
バージョアップ後に再度デモプログラムを実行しましたが上手くいかず、認証情報の登録をやり直すと上手くいきました。一応認証のプログラムを載せておきます。

```
$google-oauthlib-tool \
 --scope https://www.googleapis.com/auth/assistant-sdk-prototype \
 --scope https://www.gooogleapid.com/auth/gcm \
 --save --headless --client-secrets [クライアントIDのパス].json
```
#参考文献
吉田顕一「RaspberryPi＋AI電子工作超入門」ソーテック社、2019年
https://github.com/googlesamples/assistant-sdk-python/issues/314
git pushしてプルリクエストを送る前にすること

# 概要
　自分が与えれたタスクをいったん終わると`$ git push`してプルリクを送り、レビューを行ってもらうことが一般的な開発フローである。共同開発をしている場合、developブランチは更新される可能性があり、自身の作業ブランチに更新されたdevelopブランチを反映する必要がある。その際、自分が変更したソースコードに対して誰かが変更を加えていた場合、コンフリクトが生じる。自身のソースコートに対して、developブランチを反映し、コンフリクトが生じた場合、コンフリクトを解消して、プルリクを送る方法を考える。今回は、rebaseを用いてソースコードを反映する方法を考える。

# 想定の状況
- featureブランチを切った時（作業を開始する際）

```
      B' feature
     /
A---B develop
```

- プルリクエスト送る時（作業が終わった時）

```
      B'---C---D feature
     /
A---B---E---F develop
```


# 手順
## 1. リモート追跡ブランチの更新

```
$ git fetch
```

## 2. developブランチの変更箇所を自身のfeatureブランチに反映

```
$ git rebase origin/develop
```

## 3. コンフリクトが生じた場合（生じなければスキップ）
3.1 どちらのコードを採用するのかをしゅどうで選択する

```shell:コンフリクトが生じた該当ファイル
<<<<<<< HEAD
# featureブランチでの変更内容
・・・
=======
# developでの変更内容
・・・
>>>>>>> develop
```
この際、`<<<<<<< HEAD`,`======`,`>>>>>>>> develop`も手動で削除してもらっても大丈夫である。


3.2 `$ git add .`
3.3 `$ git rebase --continue`
ここで、コミットメッセージの編集する画面になるときがありますが、通常で特に変更する必要はないと思います。書き換える必要がある場合は適宜編集してください。

**コンフリクトがすべて解消されるまで3.1～3.2を繰り返す。**

すべてのコンフリクトがなくなるとコミット履歴は以下のようになる。

```
              C'---D' feature
             /
A---B---E---F develop
```

## 4. ローカルリポジトリをリモートリポジトリに反映

```
$ git push
```

## 5. プルリクエストの作成
　GitHub等でプルリクエストを作成します。

## 6. マージしてもらう
　プルリクエストが承認されマージされたら、コミット履歴は以下のようになる。

```             
A---B---E---F---C'---D' develop
```

# 最後に
　今回は、rebaseを用いてやる方法について述べた。
間違っている個所があればコメントしていただけると幸いです。

# 参考
https://qiita.com/KTakata/items/d33185fc0457c08654a5

https://frasco.io/why-you-should-stop-using-git-rebase-535fa30d7e25
GoでMySQLのリードレプリカ構成を実現する方針

# 前提

* MySQL
* ボイラーテンプレートで利用するSQL関連のパッケージ
  * sql-migrate https://github.com/rubenv/sql-migrate
  * sqlx https://github.com/jmoiron/sqlx

# 結論

* package:`go-mysql`を利用し、Go側でレプリケーションについての実装を行う

https://github.com/siddontang/go-mysql/


# 実装の注意点

* MySQLの対応バージョンは下記

```text
Tested MySQL versions for the client include:

5.5.x
5.6.x
5.7.x
8.0.x
```

# Replicationに関する実装例

```go
import (
	"github.com/siddontang/go-mysql/replication"
	"os"
)
// Create a binlog syncer with a unique server id, the server id must be different from other MySQL's. 
// flavor is mysql or mariadb
cfg := replication.BinlogSyncerConfig {
	ServerID: 100,
	Flavor:   "mysql",
	Host:     "127.0.0.1",
	Port:     3306,
	User:     "root",
	Password: "",
}
syncer := replication.NewBinlogSyncer(cfg)

// Start sync with specified binlog file and position
streamer, _ := syncer.StartSync(mysql.Position{binlogFile, binlogPos})

// or you can start a gtid replication like
// streamer, _ := syncer.StartSyncGTID(gtidSet)
// the mysql GTID set likes this "de278ad0-2106-11e4-9f8e-6edd0ca20947:1-2"
// the mariadb GTID set likes this "0-1-100"

for {
	ev, _ := streamer.GetEvent(context.Background())
	// Dump event
	ev.Dump(os.Stdout)
}

// or we can use a timeout context
for {
	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
	ev, err := s.GetEvent(ctx)
	cancel()

	if err == context.DeadlineExceeded {
		// meet timeout
		continue
	}

	ev.Dump(os.Stdout)
}
```
[go-mysqlのREADME#replicationより](https://github.com/siddontang/go-mysql/#replication)

例えば`binlog.go`というファイル名でプロジェクト直下に置くイメージです。

また、この実装例においてリードとレプリカの同期に必要な

* Server ID
* binlogFile
* binlogPos

は特定の値をいれます。


# 参考

例：
https://golang.hotexamples.com/examples/github.com.siddontang.go-mysql.replication/-/NewBinlogSyncer/golang-newbinlogsyncer-function-examples.html
【Rails】deviseの編集ページのform_forをform_withに書き換えるコード例

※2022年から技術系の記事は[個人ブログ](https://yamaday0u.net/category/programmer/)に投稿しております。ぜひこちらもご覧ください→[yamaday0u Blog](https://yamaday0u.net/category/programmer/)

Railsのgemであるdeviseであらかじめ用意されているビューを使ったとき、ユーザー登録のためのヘルパーメソッドはform_forによって実装されています。

Rails5.1以降、form_forではなくform_withの利用を推奨されているので、できるだけform_withへ書き換えたいところです。

そこで今回は`app/views/devise/registrations/edit.html.erb`について、form_forからform_withに置き換えてみます。

### 書き換え前
```erb:app/views/devise/registrations/edit.html.erb
 <%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
```

### 書き換え後
```erb:app/views/devise/registrations/edit.html.erb
<%= form_with model: @user, url: user_registration_path, local: true do |f| %>
```
`model: @user`でデータベースのusersテーブルに保存されているユーザー情報をあらかじめ入力フォームに入れてくれます。

ちなみに以下のように2行目以降の各フォームの値に`@user.カラム名`の記述をしなくてもデータが入ります。

```erb:app/views/devise/registrations/edit.html.erb
<%= form_with model: @user, url: user_registration_path, local: true do |f| %>
  <%= render "devise/shared/error_messages", resource: resource %>

  <div class="form-wrap">
  <div class="form-group">
    <%= f.label :name %><br />
    <%= f.text_field :name, autofocus: true %>
  </div>

  <div class="form-group">
    <%= f.label :email %><br />
    <%= f.email_field :email, autofocus: true, autocomplete: "email" %>
  </div>

  <% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
    <div>Currently waiting confirmation for: <%= resource.unconfirmed_email %></div>
  <% end %>

  <div class="form-group">
    <%= f.label :password %> <i>(leave blank if you don't want to change it)</i><br />
    <%= f.password_field :password, autocomplete: "new-password" %>
    <% if @minimum_password_length %>
      <br />
      <em><%= @minimum_password_length %> characters minimum</em>
    <% end %>
  </div>

  <div class="form-group">
    <%= f.label :password_confirmation %><br />
    <%= f.password_field :password_confirmation, autocomplete: "new-password" %>
  </div>

  <div class="form-group">
    <%= f.label :identity %><br />
    <%= f.text_field :identity, autocomplete: "current-password" %>
  </div>

  <div class="form-group">
    <%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br />
    <%= f.password_field :current_password, autocomplete: "current-password" %>
  </div>

  <div class="actions">
    <%= f.submit "Update", class: "sign-up-btn" %>
  </div>
  </div><%# end of "form-wrap" %>
<% end %>
```
### 実際のビュー
![スクリーンショット 2021-03-11 1.39.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/849306/ac476d9b-6cf3-7d44-e96e-452dbd615b6e.png)


## 参考資料
[フォーム(form) | Railsドキュメント](https://railsdoc.com/form)
[Django]form.is_valid()がTrueにならない

#はじめに
別記事の続きです｡
Djangoでカスタムユーザモデルを定義し使用しいざform.save()を使用したらform.is_valid()で躓きました｡

##事象
前回以下のようにカスタムフォームのインスタンスを作成しました｡

```app/views.py
from django.shortcuts import redirect,get_object_or_404

def update(request):
  user=get_object_or_404(User,email=request.user.email)
  if request.method=="POST":
    form=UserChangeForm(request.POST,instance=user)
    if form.is_valid():
        form.save()
        return redirect(hoge)
```
すると､form.is_valid()で常にFalseが返ってきます｡

##原因
UserChangeFormクラスの引数の定義に問題がありました｡

```app/forms.py
class UserChangeForm(ModelForm):
  def __init__(self, *args, **kwargs):
    ...
```
第一引数にselfを設定していました｡
views.pyのupdate関数内では第一引数にrequest.POSTを渡していることが原因でした｡

##解決策
以下のように､仮引数dataにrequest.POSTを設定することでform.is_valid()が正しく動作するようになりました｡

```app/views.py
  form=UserChangeForm(data=request.POST,instance=user)
```

##参考サイト
https://qiita.com/The-town/items/b99daefbf85c32f22852
MBP2015からM1 MBAにしたらフロントのビルド時間半分になった


ほぼタイトルで完結しているんですが、なにかの参考になれば

## Before: MacbookPro2015

```
MacBook Pro (Retina, 13-inch, Early 2015)
2.7 GHz Intel Core i5
8 GB 1867 MHz DDR3
Intel Iris Graphics 6100 1536 MB
```

## After: MacbookAir M1

```
MacBook Air (M1, 2020)
Apple M1
16 GB
```

## 計測対象

- 個人で開発している[Bizglue](https://bizglue.net/)のフロントエンドビルドの時間
  - `react-scripts build` の実行時間
- 開発環境は
    - [create-react-app](https://github.com/facebook/create-react-app)を ejectなしで利用
    - Typescript利用

## 計測結果

```
Before: Done in 126.48s.
After: Done in 59.01s.
```

## あとがき

フロントエンドは特にハマるポイントもなくすんなり移行できました。
サーバサイド(Python)は依存しているライブラリによってはうまくインストールできずに試行錯誤が必要になった感じでしたが、ググれば情報もある程度出てきますし、半日もかからず移行できたので、みなさんもM1いかがでしょうか？
[Django]unique制約を持つモデルを更新しようとしたら嵌ったときの手順

#はじめに
Djangoでユーザー登録をemailで行いたかったのでカスタムユーザモデルを定義しました｡
その後ユーザ情報を変更しデータベースを更新しようとしたらemailが重複して更新できない状態に陥り､手間取ったためここに解決手順を残します｡

##状況
 ```app/views.py
from django.shortcuts import redirect,get_object_or_404
  user=get_object_or_404(User,email=request.user.email)
  if request.method=="POST":
    form=UserChangeForm(request.POST)
    if form.is_valid():
        form.save()
        return redirect(hoge)
```
上記ではエラーが起きます｡
解決策は以下になります｡詳しくは参考サイトへ｡

UserChangeFormクラス生成時に引数としてrequest.POSTだけではなく仮引数instanceにユーザモデルのインスタンスを指定します｡

```app/views.py 
    form=UserChangeForm(request.POST,instance=user)
```
DjangoではモデルをデータベースへCRUDする関数がsave()しかありません｡
故に､既にモデルのインスタンスが存在することをDjangoフレームワークに伝えることでDjango側で新規/更新どちらで行うかを決めてくれるようです｡

##個人的メモ
この後､2つ嵌りました｡
1､form.is_valid()がTrueにならない
2､FormViewを継承してユーザ情報変更用viewを作った際の上記と同様の処理を行う際の処理

1に関してはUserChangeForm()の引数に問題がありました｡
これに関しては別で投稿します｡







##参考サイト
https://yuki.world/django-modelform-update-pitfall/
AWS Security Hub

#AWS Security Hub とは#

- AWS内のセキュリティの状態と、セキュリティ標準およびベストプラクティスに準拠しているかどうかを、包括的に把握できる。
- AWSのアカウント、サービス、サポート対象のサードパーティーパートナーの全体にわたってセキュリティの検出結果を一元化および優先順位を設定することで、セキュリティの傾向を分析し、最も重要なセキュリティの問題を特定してくれる。
- AWS Security Hubは多くの AWSサービスと連携している。

![スクリーンショット 2021-03-11 000752.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/0d67759b-d64c-fc61-7262-2a76b6fc34b5.png)


#セキュリティ基準#
ベストプラクティスや業界標準に基づいた、継続的なAWS環境の自動チェックが行えます。

- **AWS 基礎セキュリティのベストプラクティス v1.0.0**
AWS セキュリティの専門家によって定義されたものです。

- **CIS AWS Foundations Benchmark v1.2.0**
CIS 要件のサブセットに対するコンプライアンスの準備状況が自動的にチェックされます。

- **PCI DSS v3.2.1**
PCI DSS 要件のサブセットに対するコンプライアンスの準備状況が自動的にチェックされます。

AWS 基礎セキュリティのベストプラクティス v1.0.0 を 「有効化」にして見た。
![スクリーンショット 2021-03-11 001424.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/72d5a4fb-f08f-1b07-7697-74ae7dd94039.png)

今回はすべてが、"データなし"だったため該当するものは特になにもない。
![スクリーンショット 2021-03-11 002023.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/0f6c0faf-3392-c1a9-b611-ed90a5c601b8.png)

もし"失敗"したものがあれば、修復手順の情報が載ったページのリンクが表示されるので、修復してセキュリティスコアをあげ、セキュリティ基準を満たすように修正していく。AWS Security Hubが自動的に修正してくれるものではなく、自動修正するにはAWSサービスやパートナーソリューションで実装する必要がある。


#検出結果#
そのままのとおり、検出結果を検索することができます。

- CRITICAL 及び HIGH の検出結果から優先的に対応する。


#インサイト#
関連する検出結果を表示する保存されたフィルターです。

- AWSで予め用意されたマネージド型インサイトを利用することが可能。
- 自分でカスタムインサイトを作成することも可能.


#統合#
他の AWS のサービスまたはサードパーティーの統合からの結果を受け入れる。または、Security Hub の結果を一部の統合に送信する。
![スクリーンショット 2021-04-13 19.32.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/28063a6c-5f66-7fce-1b53-e0160e97ca66.png)


#カスタムアクション#
Security Hub のマネージメントコンソールから選択した Findings を手動で、CloudWatch Eventsへ送信できる機能であり、CloudWatch EventsからSNSで通知したり、修正を自動化するにはLambdaの実装が必要となる。
![スクリーンショット 2021-04-13 21.58.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/aaa0a42b-9db2-a3ae-6973-ad4ee9e122c6.png)


#参考#
- AWS CloudFormation テンプレートを使用して、自動的にデプロイできるサーバーレスアーキテクチャを提供。

https://aws.amazon.com/jp/solutions/implementations/aws-security-hub-automated-response-and-remediation/

- AWS Security Hub ワークフロー

https://security-hub-workshop.awssecworkshops.com/


#リンク#

[Security Hub → EventBridge → SNS → Chatbot → Slack](https://qiita.com/leomaro7/items/c936572726adb1d35229)
オードリーの出演・イベントをseleniumで取得する

# 技術
* python3
* selenium
* slackweb
* AWS Lambda（別で記事書きたい）

## コード
```python:明日の出演・イベント取得
import time
import slackweb
from selenium import webdriver
from datetime import datetime, timedelta, timezone

JST = timezone(timedelta(hours=+9), 'JST')
tomorrow = (datetime.now(JST)+timedelta(days=1)).strftime("%Y/%m/%d")

options = webdriver.ChromeOptions()
options.add_argument('--headless')
driver = webdriver.Chrome(options=options)

driver.get('http://www.kdashstage.jp/profile/archives/39')
time.sleep(3)
element = driver.find_element_by_class_name("Appearances")
h2 = element.find_element_by_tag_name("h2")

message = ""
list = element.find_element_by_class_name("psize")
for i in range(len(driver.find_elements_by_xpath('//*[@id="Profile"]/section[2]/div/dl'))):
    dl = driver.find_elements_by_xpath('//*[@id="Profile"]/section[2]/div/dl')[i]
    day = dl.find_element_by_class_name('day').text

    if day == tomorrow:
        time = dl.find_element_by_class_name('time').text
        contents = dl.find_element_by_tag_name('dd').text
        message += day + " " + time + " " + contents + "\n"

slack = slackweb.Slack(url="slackのwebhookURL")
attachments = []
attachment = {
    "title": "明日のオードリー出演・イベント予定",
    "pretext": "トゥース:point_up:",
    "text": message,
    "mrkdwn_in": ["text", "pretext"],
    "color": "#ffddff"
    }
attachments.append(attachment)
slack.notify(attachments=attachments, username="リトルトゥース", icon_emoji=":point_up")

driver.quit()

```
gcloud builds するときに、docker buildのoptionを渡したい

# はじめに

- [コンテナ イメージのビルド
](https://cloud.google.com/build/docs/building/build-containers?hl=ja) このへんのドキュメントを見ながら、 `gcloud builds` をしていると、ときにdocker buildのoptionを渡したくなるときがあると思います。
  - 個人的には `--build-arg` で外部から値をインジェクションしたくなりました。
- 結論から言うと、（これを書いた時点では）コマンドライン引数で指定はできないので、 `cloudbuild.yaml` を使います。
  - `cloudbuild.yaml` を使った例は [変数値の置換](https://cloud.google.com/build/docs/configuring-builds/substitute-variable-values?hl=ja) に記載があります。

# 具体例

当初のシンプルなコマンド

```bash
gcloud builds submit --tag gcr.io/PROJECT_ID/IMAGE_NAME
```
これに docker build `--build-arg` で変数を渡したい（そしてDockerfileの挙動を変えたい）。

どうするか

`cloudbuild.yaml` を作成

```cloudbuild.yaml
steps:
- name: 'gcr.io/cloud-builders/docker'
  args: ['build',
         '--build-arg',
         'FOO1=${_FOO1}',
         '--build-arg',
         '_FOO2=${_FOO2}',
         '-t',
         'gcr.io/$PROJECT_ID/FOOBAR_IMAGE',
         '.'
         ]
substitutions:

substitutions:
    _FOO1: foobar # default value
    _FOO2: foobar # default value
images: [
    'gcr.io/$PROJECT_ID/FOOBAR_IMAGE'
]
```

^ Dockerfileの `ARG FOO1` と `ARG FOO2` が置換される。

作成した `cloudbuild.yaml` を引数に指定して、以下のように `--substitutions` の指定も行う。

```bash
gcloud builds submit --config=cloudbuild.yaml \
    --substitutions=_FOO1="bar1",_FOO2="bar2"
```
AWS Firewall Manager とは

## 勉強前イメージ

firewallを一元管理する的な？

## 調査

### AWS Firewall Manager とは

一元的にfirewallのルールを設定・管理するセキュリティ管理サービスです。
以下のサービスとリソースを複数アカウント横断で管理します。

- AWS WAF Classic
- AWS Shield Advanced
- Amazon VPC セキュリティグループ

### 前提条件

Firewall Managerを利用する前に前提条件があります。

- AWS Organizations に参加する

AWS Organizationsは、複数のAWSアカウントを統合しポリシーベースで一元管理できるアカウント管理サービスです。
詳細は [こちら](https://qiita.com/miyuki_samitani/items/c34185fe04f6c4f35449) をご覧ください

- AWS Firewall Manager 管理者アカウントを設定する

Firewall Managerの管理アカウントを指定します。
AWS Organizationsのマスターアカウントである必要はありません。

- AWS Config を有効にする

AWS ConfigはAWSリソースの設定がモニタリングされ、ガイドラインに沿っているか など継続的に監査や評価を行うサービスです。
詳細は [こちら](https://qiita.com/miyuki_samitani/items/a19023d5e974c562a3bd) をご覧ください

### AWS Firewall Manager のメリット

- アカウント全体(AWS Organizationsで設定している)firewallのルールが全体で一元管理を行うことが出来る
- セキュリティポリシーを自動適用し、新しいリソースを検出することでコンプライアンスを確保できる
- アカウント全体に簡単に管理されたルールを利用可能にする

## 勉強後イメージ

AWS Organizationsを使用することで、複数アカウント横断してもなおセキュリティポリシーの一元管理できるのは会社全体でのポリシーを確認できるので
管理する方には最適かもしれない...
個人でどんなやり方かなーって試してみたいけど、AWS OrganizationsとかWAFとかハードルちょっと高い

## 参考

- [AWS Firewall Managerとは](https://www.acrovision.jp/service/aws/?p=1484)
- [Firewall ManagerでSecurity Groupを管理する](https://dev.classmethod.jp/articles/manage-security-group-by-firewall-manager/)
- [【新機能】AWS Firewall Managerを使ってみた](https://dev.classmethod.jp/articles/getstart-aws-firewall-manager/)
- [AWS Firewall Manager](https://aws.amazon.com/jp/firewall-manager/)
nuxt勉強用

#目的
全くvueがわからない人がnuxtを覚えてfirestoreと接続できるようになるまでの手順
を教えるときにここを見れば全部乗ってるよって言う感じにしたい

#手順

1 まずvs codeを入れてもらう

入ってたら次
EC2インスタンスを起動した時にnginxとtomcatをchkconfigで起動させる

こんにちは。
[Cycle](https://cycle.support)というCtoCの学習マッチングサービスでエンジニア兼プロマネをやっている小畑と言います。
基本は企画とかを進めていきたいけど、今はエンジニアが足りない！インフラ得意な人がいない！
ってことで学びつつインフラいじっている最中でございます。笑

今回は立ち上げたばかりのサービスでコストカットしたいってフェーズの事業に関わっている人こそ読んでもらいたい記事になります。
そんなに難しくないのでぜひ一読ください。

## ■ やりたいこと
EC2インスタンスを起動した時にnginxとtomvatを自動で起動させたい。

## ■ 背景
検証環境は昼間しか基本的には使わないので、深夜も起動しているのは勿体無いですよね。
（インフラの構成にもよりますが夜間バッチがあって、それの起動を確認したいのなら話は別です。）

なので、朝に自動でEC2を起動させて夜に自動で停止させます。
これはCloudWatchでAWSコンソール画面からパパッとできるのでこの記事では触れません。
ググればたくさん記事が出てくるのでそちらを参考に進めてみてください。

## ■ インスタンス起動時に実行してくれるchkconfigさん
でもどうやってやればいいんだ。ってかた向けの記事です。

さて、このchkconfigさんはインスタンスを立ち上げる時に実行してくれるやつです。
.bashrcとか.bash_profileとか今までいじってきましたよね？
そこの知識はある前提の話ですが、.bash_profileみたいなやつがchkconfigです。
なので、chkconfigに命令してあげると万事解決します。

### ▼ まずはnginxを自動で起動する。
以下のコマンドを実行するだけ！
簡単でしょ？

```
# sudo chkconfig --add nginx
# sudo chkconfig nginx on
```

### ▼ tomcatを自動で起動する。
まずtomcatを起動させるためのシェルを作成します。

```
# sudo vim /etc/init.d/tomcat
```

記載する内容はこんな感じです。

```
#!/bin/sh
# chkconfig: 0123456 99 10
# description: start tomcat.

sudo sh /opt/tomcat/bin/startup.sh ←任意に変更する
```

tomcatの起動の方法はそれぞれ異なると思うので、シェル実行の部分は任意に変更してください。

シェルファイルの権限を変更します。
そうしなければchkconfigが実行できません。

```
# sudo chmod 775 /etc/init.d/tomcat
```

そしてnginxの時と同様にchkconfigの設定を追加します。

```
# sudo chkconfig --add tomcat
# sudo chkconfig tomcat on
```

これで終わりです！
あとはEC2インスタンスを再起動してみましょう！

```
# sudo reboot
```

再起動が完了したらnginxとtomcatが起動しているか確認しましょう。
これで終わりです！
ね、簡単でしょ？

最後に宣伝です。
[Cycle](https://cycle.support)ではWeb制作を中心に教える側のメンターを募集しております！
ぜひ、無料て会員登録をしてプランを公開してみてください！
よろしくお願いします！
Docker環境のMySQLでダンプファイルをインポートする方法

こんにちは、JeffTechです。

# この記事で実現できること
- Docker環境のMySQLにダンプファイルをインポート
- Docker&Laravel環境でのDB接続

# 説明
今回はリモート接続しているDBからダンプしたダンプファイルを、自分のローカルのDocker環境でMySQLにインポートするときに、少し苦労したので備忘録程度で説明していきます。
なお、すでにdocker-compose.ymlやDockerfileなどは作られており、docker-comopse up -dが行える状態から説明します。

# 開発環境
- Laravel6
- MySQL 5.7
- Docker


# 実装の流れ
1. コンテナにダンプファイルをコピー
1. コンテナの起動とコンテナに入る
1. ダンプファイルをDBにインポート
1. .envの編集

# 実装
インポートをする前にリモートのDBからデータをダンプしてきてください。
私の場合Macを使っているのでSequel Aceという、データベースをCUI操作できるアプリケーションを使い、DBに接続してデータをダンプしてきました。

## コンテナにダンプファイルをコピー
それでは早速やってみます。
まずは、コンテナにダンプファイルをコピーしていきます。

```bash
$ docker cp ダンプファイルフルパス コンテナ名:/tmp/ダンプしたファイル名
```
わからない場合は、例として下記の場合も併せて見てみてください。
ダンプしてきたファイル名：dump.sql
ダンプしてきたファイルパス：/Users/username/Downloads/dump.sql
データベースのコンテナ名：db(docker-compose.ymlで記述されている)
の場合は下記のコマンドを実行してください。

```bash
// こちらは上記のコマンドの実例です
$ docker cp /Users/username/Downloads/dump.sql db:/tmp/dump.sql
```

## コンテナの起動とコンテナに入る
`docker-compose.yml`があるディレクトリ で、下記のコマンドを実行してください。

```bash
$ docker-compose up -d
```
これでコンテナの起動ができましたので、コンテナに入るために下記のコマンドを実行してください。

```bash
$ docker-compose exec コンテナ名 bash
```
`root@111abc2222de:/#`みたいな感じの画面になっていればOKです。
ここでコマンドを叩くことができます。
コンテナ名は、`docker-compose.yml`を見ていただければ、わかります。
ちなみに私のはこんな感じです。

```yml:docker-compose.yml
version: "3"
services:

  ー省略ー

  db:
      image: mysql:5.7
      container_name: db
      environment:
        MYSQL_ROOT_PASSWORD: root
        MYSQL_DATABASE: database
        MYSQL_USER: username
        MYSQL_PASSWORD: password
        TZ: 'Asia/Tokyo'

        ー省略ー
```
`container_name: db`となっているので、今回の例であればコンテナ名は`db`となります。

## ダンプファイルをDBにインポート
インポートは下記のコマンドをコンテナに入っている状態で実行してください。

```bash
$ mysql -u docker-compose.ymlで決めたユーザー名 -p データベース名 < /tmp/ダンプファイル名
```
パスワードを聞かれるので、`docker-compose.yml`で決めたパスワードを入力してエンターを押すと、ダンプファイルがインポートされます。
ちなみに、パスワード入力時はキーボードを叩いても何も表示されませんが、それで大丈夫です。

今回の例でいくと下記のようになります。

```bash
# こちらは上記のコマンドの実例です
$ mysql -u username -p database < /tmp/dump.sql
```

## .envの編集
最後にLaravelがインストールされているディレクトリ にある`.env`のDB設定のところを以下のように編集してください。

```
DB_CONNECTION=mysql
DB_HOST=docker-compose.ymlで決めたコンテナ名
DB_PORT=docker-compose.ymlで決めたポート番号
DB_DATABASE=docker-compose.ymlで決めたデータベース名
DB_USERNAME=docker-compose.ymlで決めた名前
DB_PASSWORD=docker-compse.ymlで決めたパスワード
```
今回は以下のような`docker-compose.yml`だと仮定していますので、

```yml:docker-compose.yml
version: "3"
services:

  ー省略ー

  db:
      image: mysql:5.7
      container_name: db
      environment:
        MYSQL_ROOT_PASSWORD: root
        MYSQL_DATABASE: database
        MYSQL_USER: username
        MYSQL_PASSWORD: password
        TZ: 'Asia/Tokyo'

        ー省略ー
```
これを例にした場合の.envはの下記のようになります。

```
DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=database
DB_USERNAME=username
DB_PASSWORD=password
```


# 最後に

なかなかMySQLにインポートできず困りましたが、これで簡単にインポートできるはずです。ぜひやってみてください。

少しでも役に立った！という時は、いいねをポチッとして
フォローしてくださると嬉しいです、、、笑

役に立たなかった時は、怒らないでコメント頂けますと幸いです笑

Twitterもやってますので、よかったら見てみてくださいね！
https://twitter.com/jefftechsaku
[Django] ①プロジェクト ~ アプリの作成

# 概要
1: プロジェクトの作成
2: アプリの作成

# 背景
Djangoを新しく学び始めたため、少しでも忘れないように使用したコマンドなどを備忘録として残しておくために記載

# 環境
OS：18.04.5 LTS
Python：3.6.9
Django: 3.1.7

# 方法

## 1: プロジェクトの作成

Djangoでは、１つのwebアプリケーションにつき1つのプロジェクトが作成されるらしい。
そのプロジェクトの中に機能単位でアプリが作成されるのが一般的とのこと。

いまいちイメージが湧かないが、とりあえずプロジェクトを作成してみる。
 
```
# プロジェクト作成
(venv_investment) ubuntu@ip-172-31-44-135:~$ django-admin startproject Investment

# 確認
(venv_investment) ubuntu@ip-172-31-44-135:~$ ls -la Investment/
total 16
drwxrwxr-x  3 ubuntu ubuntu 4096 Mar 10 15:10 .
drwxr-xr-x 28 ubuntu ubuntu 4096 Mar 10 15:10 ..
drwxrwxr-x  2 ubuntu ubuntu 4096 Mar 10 15:10 Investment
-rwxrwxr-x  1 ubuntu ubuntu  666 Mar 10 15:10 manage.py
```
プロジェクト作成後のディレクトリ内を確認してみると、プロジェクト名の <strong>Investment</strong> ディレクトリと <strong>manage.py</strong> が作成できていることが確認できた。

まだ、これらの使い方が分からないが、、、、とりあえずアプリを作成してみる。

アプリ作成には、<strong>manage.py</strong>を使用するらしい。
とりあえず、<strong>manage.py</strong>がある階層に移動して、アプリ作成。

## 2: アプリの作成

```
# アプリ作成
(venv_investment) ubuntu@ip-172-31-44-135:~/Investment$ python3 manage.py startapp stock

# 確認
(venv_investment) ubuntu@ip-172-31-44-135:~/Investment$ ls -la stock/
total 32
drwxrwxr-x 3 ubuntu ubuntu 4096 Mar 10 15:14 .
drwxrwxr-x 4 ubuntu ubuntu 4096 Mar 10 15:14 ..
-rw-rw-r-- 1 ubuntu ubuntu    0 Mar 10 15:14 __init__.py
-rw-rw-r-- 1 ubuntu ubuntu   63 Mar 10 15:14 admin.py
-rw-rw-r-- 1 ubuntu ubuntu   85 Mar 10 15:14 apps.py
drwxrwxr-x 2 ubuntu ubuntu 4096 Mar 10 15:14 migrations
-rw-rw-r-- 1 ubuntu ubuntu   57 Mar 10 15:14 models.py
-rw-rw-r-- 1 ubuntu ubuntu   60 Mar 10 15:14 tests.py
-rw-rw-r-- 1 ubuntu ubuntu   63 Mar 10 15:14 views.py
```
アプリ <strong> stock </strong>の中には、他のフレームワークでよく見るようなファイルが作成されたことを確認できた。
たぶん、これらの中を編集していくのだろう。。。。

これらの続きは、次回の記事に記載していこうかと思う。
symfony の twig で現在のURLを取得する方法

# はじめに

現在、表示するページのURLがほしい時が時たまある。
簡単そうなのを見つけたのでメモ

# TL;DR

```twig
{{ app.request.getUri }}
```

これで現在のURLが取得できる。

# 説明

SymfonyのTwigでは、グローバル変数が定義されている。

https://symfony.com/doc/current/templates.html#twig-app-variable

ここに`app.request`というのがある。

いろいろなリクエストデータが取得できるようになっています。
https://symfony.com/doc/current/components/http_foundation.html#accessing-request-data

```twig
{{ dump(app.request) }}
```

出力結果は、下記。もう、大体のものが読めます。

![2021-03-11_00h17_55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133291/5f40a890-a912-605b-7b48-ae4f8fe91612.png)

これで`requestUri`で、絶対パスが取得できますけど、ホスト名とかHTTPとかついていて欲しいわけです。

メソッドにある`getUri`を読み出すと、いい感じでフルURLが取得できます。

https://github.com/symfony/http-foundation/blob/30841d3da1c20642bc7caac6da8b49c742293588/Request.php#L1057
Dockerで起動したMySQLコンテナにSequel Aceなどで接続する方法

こんにちは、JeffTechです。

# この記事で実現できること
- Dockerで起動したMySQLコンテナにSequel Aceで接続する方法
- Dcokerで起動したMySQLコンテナにターミナルから直接接続する方法
- Dockerで起動したMySQLコンテナに入って接続する方法

# 説明
今回はDockerでMySQLを導入した際に、Sequel AceでMySQLに接続しようとしたらローカルのMySQLに繋がってしまったので、どうすればDockerで使っているMySQLにアクセスできるのかを説明していきます。

# 開発環境
- Docker
- macOS Catalina
- MySQL

# 実装の流れ
- docker-compose.ymlの編集
- Dockerで起動したMySQLコンテナにSequel Aceで接続する方法
- Dcokerで起動したMySQLコンテナにターミナルから直接接続する方法
- Dockerで起動したMySQLコンテナに入って接続する方法

# 実装
## docker-compose.ymlの編集

```yml:docker-compose.yml
version: "3"
services:
  db:
      image: mysql:5.7
      container_name: db [MySQLのコンテナ名]
      environment:
        MYSQL_DATABASE: database [データベース名]
        MYSQL_ROOT_PASSWORD: root [ルートユーザーのパスワード]
        MYSQL_USER: user [ユーザー名]
        MYSQL_PASSWORD: password [パスワード]
      ports:
      - 4306:3306
      volumes:
      - mysql-data:/var/lib/mysql
```
`ports:`が`4306:3306`になっています。これは、DockerのMySQLコンテナの3306番とローカルのポート番号4306番を繋ぐようにに設定しています。
元々私の場合`ports:- "3306:3306"`となっていたため、ローカルのMySQLと競合してしまい、接続できませんでした。

## Dockerで起動したMySQLコンテナにSequel Aceで接続する方法

```
TCP/IP
Name: docker-mysql [好きな名前で大丈夫です]
Host: 127.0.0.1
Username: user [docker-compose.ymlで設定したユーザー名]
Password: password [docker-compose.ymlで設定したパスワード]
Database: 
Port: 4306
```

## Dcokerで起動したMySQLコンテナにターミナルから直接接続する方法
まず、MySQLコンテナに入ってください。

```bash
$ docker-compose exec db bash
// dbはdocker-compose.ymlで設定したコンテナ名です。
```
`root@1abc11111d1e:/#`という感じになっていればコンテナ内に入れていますので、下記のコマンドでMySQLに接続しましょう。

```bash
$ mysql -u user -p
// userはdocker-compose.ymlで設定したユーザー名です。
```
パスワード入力を求められるので、`docker-compose.yml`で設定したパスワードを入力してください。
`mysql> `となっていれば成功です。

## Dockerで起動したMySQLコンテナに入って接続する方法

```bash
$ mysql -u user -p -h 127.0.0.1 -P 4306
// userはdocker-compose.ymlで設定したユーザー名です。
// 127.0.0.1は皆さん共通で、localhostとせずIPアドレスを直で入力します。
// ポート番号を指定するためには`-P`とpを大文字にしてください。
// 4306はdocker-compose.ymlで設定したポート番号です。
```


# 最後に
少しでも役に立った！という時は、いいねをポチッとして
フォローしてくださると嬉しいです、、、笑

役に立たなかった時は、怒らないでコメント頂けますと幸いです笑

Twitterもやってますので、よかったら見てみてくださいね！
https://twitter.com/jefftechsaku
Pycharm(Professional)上のDjangoでsassのコンパイルをする簡単な方法

# PyCharm(pro)でsassをcssにコンパイルする設定
1. staticファイルにsassディレクトリ、ファイルを作成
<img width="400" alt="pycharm testing.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1139369/731af7d1-62cc-67f0-d643-484bc802a0bb.png">
2. (初回はファイルの左上にアドバイスが出ているのでそこをクリック)
3. preferences(上のpycharm→preferences、`⌘`+`,`)からでも開けます
4. Tools→File Watchersで＋を押してok
　
<img width="400" alt="pycharm filewatcher.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1139369/acd6e566-0414-7244-4fec-4aa6f6bdf47d.png">

あとは勝手にコンパイルしてくれます
公式にはターミナルで`npm install -g sass`をするとあったので一応していました

linkの書き方は、testing.sassとするところをtesting.cssとするだけです
例：`<link href="{% static 'sass/testing.css' %}" rel="stylesheet" type="text/css">`

<a href="https://pleiades.io/help/pycharm/transpiling-sass-less-and-scss-to-css.html">pycharm公式</a>

https://pleiades.io/help/pycharm/transpiling-sass-less-and-scss-to-css.html

django sassで調べたらライブラリの方が多く出ましたが、このようなやり方もあるので投稿しました
もっとこうした方が良い等ありましたらコメントください！
Laravelでnpm installしたら、found 1 high severity vulnerabilityと怒られた話

こんにちは、JeffTechです。

# 開発環境
- OS：Windows
- Laravel：6.19
- npm：6.14.8
- node.js：v11.13.0

# 説明
`$ npm install`したらこんなエラーが、、、

```
45 packages are looking for funding
  run `npm fund` for details

found 1 high severity vulnerability
  run `npm audit fix` to fix them, or `npm audit` for details
```
重大な脆弱性が見つかったとのこと、、、
これはだめだと思ってなんとかこのエラーを解決してみましたので、同じエラーが出ている方は参考にしてください。

# 実装
とりあえず、上のエラー文を見てみると`$ npm audit`を実行してといわれているので実行してみる。

```
                       === npm audit security report ===

# Run  npm install --save-dev resolve-url-loader@3.1.2  to resolve 1 vulnera
SEMVER WARNING: Recommended action is a potentially breaking change

  High            Prototype Pollution

  Package         object-path <これが重大な貧弱性あるやつ>

  Dependency of   resolve-url-loader [dev]

  Path            resolve-url-loader > adjust-sourcemap-loader > object-path

  More info       https://npmjs.com/advisories/1573

found 1 high severity vulnerability in 1088 scanned packages
  1 vulnerability requires semver-major dependency updates.
```
よく見ると`object-path`というパッケージにて`Prototype Pollution`という脆弱性があるよと教えてくれてます。

さらによく見てみると、`npm install --save-dev resolve-url-loader@3.1.2`すれば解消できるよ！と言われているので、実行してみる。

```bash
$ npm install --save-dev resolve-url-loader@3.1.2
```

すると、下記のようになります。

```
  + resolve-url-loader@3.1.2
added 17 packages from 46 contributors, removed 17 packages, updated 2 packaited 1088 packages in 16.007s

45 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
```

おお～見事に脆弱性治りました。
これでエラーも何も出ないので大丈夫そうです。

npmで`found 〇 high severity vulnerability`と怒られたら、まずは`npm audit`をして、auditに言われた通りに実行してみましょう！


# 最後に
少しでも役に立った！という時は、いいねをポチッとして
フォローしてくださると嬉しいです、、、笑

役に立たなかった時は、怒らないでコメント頂けますと幸いです笑

Twitterもやってますので、よかったら見てみてくださいね！
https://twitter.com/jefftechsaku
Javaのコンパイル

Mavenを使用してjarファイルを作成する際の調べたことをまとめる。

# 1.Maven

## 1-1.build設定

```xml:pom.xml
	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.8.1</version>
				<configuration>
					<source>8</source>
					<target>8</target>
				</configuration>
			</plugin>
```

## 1-2.jar内のMANIFEST

1-1の設定で作成されたjarファイルのMANIFESTファイルは以下。

```text:MANIFEST.MF
Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Created-By: Apache Maven 3.6.3
Built-By: けろ
Build-Jdk: 11.0.7

```

Build-Jdkの値はどこから取得している？
Built-ByはWindows OSのログインユーザ名と同じ。

## 1-3.

# 2.Maven以外

## 2-1.jarファイルのjavaバージョン確認

jarファイルはただの圧縮ファイル。その中のクラスファイルを調べる必要がある。

以下のコマンドで確認できる。

```bat
javap -v クラスファイル.class | find "major"
```

### 2-1-1.majorバージョンとJDKのバージョン

45 = Java 1.1
46 = Java 1.2
47 = Java 1.3
48 = Java 1.4
49 = Java 5
50 = Java 6
51 = Java 7
52 = Java 8
53 = Java 9
54 = Java 10
55 = Java 11
56 = Java 12
57 = Java 13
58 = Java 14
https://en.wikipedia.org/wiki/Java_class_file#General_layout
【Python】for文がbreakされず要素すべて実行されたのかをfor-elseで判定する方法（備忘録）

自分用メモ

for文がbreakで途中で抜けたのか、breakされず要素すべて実行されたのか判定する方法。
他の言語のクセでbool型で途中で抜けたのかを判定しがちだったけどこれは便利。

# for-else
```python
weeklist =  ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
for day in weeklist:
    print('day:' + day)
    if day == 'April':
        break
else:
    print('最後までループしたよ')

print('for文が終了したよ')
```
```
day:Sunday
day:Monday
day:Tuesday
day:Wednesday
day:Thursday
day:Friday
最後までループしたよ
for文が終了したよ
```

# bool型での判定
よく書きがちだった方法

```python
weeklist =  ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
isBreak = False
for day in weeklist:
    print('day:' + day)
    if day == 'April':
        isBreak = True
        break
if not isBreak:
    print('最後までループしたよ')

print('for文が終了したよ')
```


以上