OmniAICreator/Qiita-1.07M huggingface dataset:
Pythonの超基本文法カンニング用プログラム_フロー制御文ver

仕事でプログラミングをしないが趣味でpythonを始めた私自身のためのチートシート。初学者の方は「思い出す」作業にどうぞお使いください。

超基本文法について理解しているものの、python独特の書き方をすぐ忘れるのでカンニング用プログラム。

確認環境：Python3.7.6

#フロー制御①  if文
```python:01_if.py
#末尾の：忘れがち。
print('あなたの名前を入力してください。Alice,usagi,etc...')
name = input()
if name =='Alice':
  print('やぁ、Alice.')
elif name == 'usagi':
  print('どうも白うさぎさん')
else:
  print('初めまして、' + name  + '.')
```

```python:出力例(Aliceと入力すると)
あなたの名前を入力してください。Alice,usagi,etc...
Alice
やぁ、Alice.
```

#フロー制御②  whileループ
```python:02_while.py
#無限ループになったらCtrl+C
spam = 0
while spam < 5:
  print('Hello,world.')
  spam = spam +1
```

```python:出力結果
Hello,world.
Hello,world.
Hello,world.
Hello,world.
Hello,world.
```

```python:03_while_break.py
#breakはループを抜ける処理
while True:
  print('あなたの名前を入力してください。')
  name = input()
  if name == 'あなたの名前':
    break
print('どうも！')
```

```python:出力例(「あなたの名前」と入力すればループが終わる。)
あなたの名前を入力してください。
alice
あなたの名前を入力してください。
Aceli
あなたの名前を入力してください。
Alice
あなたの名前を入力してください。
あなたの名前                  
どうも！
```


```python:04_while_continue.py
#continueはループの最初に戻る処理。
while True:
  print('Alice,あなたは何歳？')
  age = input()
  if age != '15':
    continue
  print('そう、あなたは15歳。ここはどこ？')
  world = input()
  if world == '不思議の国':
    break
print('そう、ここは不思議の国。')
```
```python:出力例(「15」「不思議の国」と入力すればループが終わる。)
Alice,あなたは何歳？
15
そう、あなたは15歳。ここはどこ？
日本
Alice,あなたは何歳？
14
Alice,あなたは何歳？
15
そう、あなたは15歳。ここはどこ？
不思議の国
そう、ここは不思議の国。
```

#フロー制御③  forループとrange()
```python:05_for_range.py
#回数を指定してループ
#rangeの数字は0からスタート。
print('うらめしやー')
for i in range(6):
  print('お皿が、' + str(i) + '枚、、、')
print('キャーーーーー！')
```

```python:出力結果
うらめしやー
お皿が、0枚、、、
お皿が、1枚、、、
お皿が、2枚、、、
お皿が、3枚、、、
お皿が、4枚、、、
お皿が、5枚、、、
キャーーーーー！
```

```python:06_for_range_from_to.py
#開始値と終了値をrangeに指定
print('うらめしやー')
for i in range(1,8):
  print('お皿が、' + str(i) + '枚、、、')
print('どわーーーーーーーーー！')
```

```python:出力結果
うらめしやー
お皿が、1枚、、、
お皿が、2枚、、、
お皿が、3枚、、、
お皿が、4枚、、、
お皿が、5枚、、、
お皿が、6枚、、、
お皿が、7枚、、、
どわーーーーーーーーー！
```

```python:07_for_range_from_to_step.py
#開始値と終了値と増加値をrangeに指定
print('うらめしやー')
for i in range(1,15,3):
  print('お皿が、' + str(i) + '枚、、、')
print('めんどくさいので3枚ずつ数えてみましたわ。ウフフ')
```

```python:出力結果
うらめしやー
お皿が、1枚、、、
お皿が、4枚、、、
お皿が、7枚、、、
お皿が、10枚、、、
お皿が、13枚、、、
めんどくさいので3枚ずつ数えてみましたわ。ウフフ
```

#フロー制御④  sys.exit()
```python:08_exit.py
#import sysが必要
import sys

while True:
  print('終了するにはexitと入力してください')
  response = input()
  if response == 'exit':
    sys.exit()
  print(response + 'と入力されました。')
```

```python:出力結果
終了するにはexitと入力してください
a
aと入力されました。
終了するにはexitと入力してください
i
iと入力されました。
終了するにはexitと入力してください
exit
```
WordPress の移行をしてみた

WordPress の管理画面にアクセスすると「PHP のバージョンを上げなさい」とか出てくるようになった。AWS 上で動かしているのだが bitnami-wordpress-4.9.2-0-r02-linux-ubuntu-16.04-x86 でベースも Ubuntu 16.04。そろそろベースのディストリビューション含めてアップグレードが必要そうだ・・・。今回は bitnami-wordpress-5.4.2-0-linux-debian-10-x86 への移行を試みた。手順が怪しいけど一応移行後も動いてはいますw ほぼ自分用のメモです。

# WordPress ってどうやってバックアップ取るの？

[ここ](https://docs.bitnami.com/aws/apps/wordpress/administration/backup-restore/) を見ると /opt/bitnami を全部取れば良さそうだが、バックアップスクリプトを作っている人とか見ると wordpress ディレクトリと MySQL のバックアップだけでも良さそう。[Migration ツール](https://docs.bitnami.com/aws/how-to/migrate-wordpress/) や有料の JetPack というのもあるらしい。手段が一杯あって逆に迷う感じ。

最低 wp-content と MySQL のバックアップがあれば[行けそう](https://www.effata.jp/blog/1682)な気もするが、今回は wordpress ディレクトリをまるごとコピーしてみた。

# 私がやった手順

1 移行元で WordPress を停止

```
# sudo /opt/bitnami/ctlscript.sh stop
```

2 tar で wordpress ディレクトリをバックアップ

```
# tar cfvz wordpress.tar.gz /opt/bitnami/apps/wordpress/
```

3 MySQL のバックアップ

```
# mysqldump -A -u bn_wordpress -p > backup.sql
```

ちなみにユーザーとパスワードは以下のコマンドで確認。

```
# egrep -i user /opt/bitnami/apps/wordpress/htdocs/wp-config.php
# egrep -i pass /opt/bitnami/apps/wordpress/htdocs/wp-config.php
```

4 移行先の WordPress のインスタンスを AWS 上でデプロイ

5 移行元で WordPress を停止

```
# sudo /opt/bitnami/ctlscript.sh stop
```

6 移行先で MySQL をリストア。

```
# mysql -u bn_wordpress -p < ./backup.sql
```

やはりパスワードは以下のコマンドで確認。パスワードはあとで使うのでメモ。

```
# egrep -i pass /opt/bitnami/apps/wordpress/htdocs/wp-config.php
```

7 wordpress ディレクトリを /opt/bitnami/apps ディレクトリにコピー

```
# mv /opt/bitnami/apps/wordpress/ /opt/bitnami/apps/wordpress_backup
# sudo tar -pczvf wordpress.tar.gz -C /
```
8 /opt/bitnami/apps/wordpress/htdocs/wp-config.php の以下の行を 6. で確認した移行先のパスワードに変更。

```
define('DB_PASSWORD', 'XXXXXXXXXX');
```

9 SSL 証明書に Let's Encrypt を使っているのでここらへんのファイルを使用。(詳しくメモ取り忘れ・・・。)

```
$ sudo ls /opt/bitnami/letsencrypt/scripts
generate-certificate.sh  renew-certificate.sh
```

10 移行元で WordPress を開始

```
# sudo /opt/bitnami/ctlscript.sh start
```

renew-certificate.sh は[ここ](https://docs.bitnami.com/aws/how-to/generate-install-lets-encrypt-ssl/)を参照。とりえあずしばらく動かしてみて問題があればまた文章をアップデートします。。
Qiitaをユニバーサルデザイン化したいから簡単な拡張機能を作ろうとした時に得た知見

#はじめに
Qiitaって色が一様で見にくいと思ったことはありませんか?
私は親の遺伝で遠視がきつく、背景色と似た色の文字を見ようとするとピントを合わせるのに目を酷使して疲れます。
これは自分に限った話ではなく、例えば色盲の方なら色の区別がつきにくかったりします。
そのため、Web開発をする際は**ユニバーサルデザイン**に気を付けようという心がけがあります。
しかし、Qiitaには色の変換ならまだしも、文字の大きさを変更することすら出来ません。
ここで、拡張機能を作った時に得た知見を記そうと思います。

あまりデザインセンスには自信が無いということをまず言っておきます..

#作ろうとした際に思ったこと
##リンクが見にくい
###問題例
例えばこの最初のページ。普通に見る分には全然問題ありません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234613/d50b9242-7465-7d27-6c15-10f5b8e71dbe.png)
しかしながら...
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234613/646983db-471c-5395-9c62-c7e01ce6a8e2.png)
この二つのリンク。記事を見たリンクは灰色に、見ていないリンクは黒色で表示しています。
確かにデザイン的には合っているのかもしれませんが、遠目で見ると違いがわかりにくいです。

検索した場合のリンクは、青と紫という初期色になっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234613/0d407c59-b7a5-5975-c8e1-e8adb970c49e.png)
これはただただデザインを優先したのか、一貫性が無いのかわかりませんが分かりやすい色で統一するのがよさそうです。

###解決例
例で、記事を見たリンクを深緑で表示してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234613/c5f5cbd7-0889-c357-ac57-9d848a384893.png)
個人的にはこちらの方が数倍見やすいです。(個人差あり)
しかしながら違う色の方が見やすい場合があります。これは拡張機能で補うことは出来ますが、スマホ等では出来ません。
これはQiita側でテーマ的なものを開発してもらうのを待つしかありません。(緑主体なのはわかっていますが...)
せめて暗めのテーマが欲しいのは私だけでしょうか。

##誰が書いたかわかりにくい
###問題例
これも最初のページなのですが
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234613/abff5bb3-9b73-a82a-f09d-eb6276a3299d.png)
拡大したらそうでもないかもしれませんが、byとユーザーネームが引っ付いて見えます。
また、一列全て色が同じです。
###解決例
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234613/648ae36d-dedd-d3d9-54e8-96c8bbaadd26.png)
ユーザーネームの色を変え、Qiitaお気に入りのLGTMの色をテーマカラーにしました。こうすると何日前かがわかりにくいので何かしらイイ感じに色をつけていきたいですね。

#簡単に拡張機能を作ってみた
サクッと上記の問題を解決するような拡張機能を作りました。chrome限定です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234613/e8dd0a1d-6ef5-f2e3-0403-f8c940d684f8.png)
本当にわずかですが、ここで色を変えることが出来ます。
[GitHub](https://github.com/Akatsuki1910/qiitaExtension)にもあげておきますので誰か完成までもっていってほしいな。

#作っていて思ったこと
chromeの拡張機能は少ししか触ったことが無いのですが、ページのcssを動的に変えようとすると凄く大変です。
ましてやQiitaではclass名で取得することが難しく、今後デザイン変更された時にclass名が変更されるとまた一から変えるはめになります。
それはとても大変なので、Qiita様が直々にユニバーサルデザイン化して頂く必要があります。
緑が基調なのはよーくわかっております。しかしながらユニバーサルデザイン化をして頂きたい所存でございます。

と、いったことが思ったことです。色変更だけでも大変なんじゃ...

#まとめ
Qiitaを便利にするには機能追加もいいのですが、元を見やすくしてみるのもありだと思って考えました。
フロントエンドを主にしているので、ユニバーサルデザインは人よりかは重要視しています。(自分もその一部だからね)
万人に便利かと言われると微妙ですが、一部の人はすごく便利になると思うので是非とも公式で開発を進めてほしいです。
flutterのwebview_flutterでリンクをアプリ内ブラウザで開きたい場合の注意点

# 概要
webview_flutterで特定リンクをアプリ内ブラウザで開く場合に、ホワイトリストやブラックリストを作って、アプリ内ブラウザを開く開かないの対応をすると思います。
その際に意図しないURLまでアプリ内ブラウザで開いてしまったので、その際に対応した内容を記載します。

アプリ内ブラウザを開く際にはurl_launcherを利用しています。

# 環境
```bash
> flutter doctor                                                                           
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, v1.17.5, on Mac OS X 10.15.5 19F101, locale ja-JP)
[!] Android toolchain - develop for Android devices (Android SDK version 29.0.3)
    ✗ Android license status unknown.
      Try re-installing or updating your Android SDK Manager.
      See https://developer.android.com/studio/#downloads or visit visit https://flutter.dev/docs/get-started/install/macos#android-setup for detailed instructions.
[✓] Xcode - develop for iOS and macOS (Xcode 11.5)
[✓] Android Studio (version 3.6)
[✓] VS Code (version 1.46.1)
```
- webview_flutter: ^0.3.21
- url_launcher: ^5.4.7

# 実装内容
不要な部分は省略しています
### main.dart
```dart:main.dart
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: SafeArea(
            child: WebView(
          navigationDelegate:
              // providerを使用しています
              context.watch<WebViewViewmodel>().onNavigationDelegate,
        )),
        bottomNavigationBar: BottomNavigationWidget());
  }
```
### WebViewViewmodelの実装内容
```dart:WebViewViewmodel.dart
  NavigationDecision onNavigationDelegate(NavigationRequest request) {
    // request.urlに遷移先のURLが入ってくる
    if (request.url == 'アプリ内ブラウザで開きたくない対象のURL') {
      // navigateで通常のwebview内で遷移
      return NavigationDecision.navigate;
    } else {
      log(request.url);
      // アプリ内ブラウザで開きたい場合はurl_launcherを利用する
      _launchBrowser(request.url);
      return NavigationDecision.prevent;
    }
  }

  // 詳細はurl_launcherの実装方法を参照
  Future<void> _launchBrowser(String url) async {
    if (await canLaunch(url)) {
      await launch(url);
    } else {
      throw ArgumentError('Could not launch $url');
    }
  }
```

# 問題点
実はこれだと問題がでてきます。
それはiframeやlink rel="xxx"で指定されるURLも判定対象になるためです。
iframeのURLやCSSのlink relの要素も`navigationDelegate`の処理に入ってきます。
そのため、意図しないURLもアプリ内ブラウザで開いてしまう可能性があります。

# 解決策
`request.isForMainFrame`を利用します

```dart:WebViewViewmodel.dart
  NavigationDecision onNavigationDelegate(NavigationRequest request) {
    // request.isForMainFrameではない場合はwebviewでの遷移として扱う
    if (!request.isForMainFrame) return NavigationDecision.navigate;
    // ...略
  }
```
名前の通り、isForMainFrameは遷移先のメインURLかどうかを判定してくれます。
iframeやlink relなどのURLの場合は`false`が入るのでこれで対応できました。

---

皆さんの参考になれば幸いです。
GETとPOST（GET以外）で同じコード、でも挙動が違う

ちゃんと調査しないと気付かなかったのでメモがてら、誰かが同じ問題に直面したときの助けになれば。

# 概要
ある日、GETとPOSTで挙動が違うという話が。
コードを見てみたら、コントローラーの同じアクションにGETとPOSTがルーティングされていました。
どう見ても同じ処理。そこに差異は無いので挙動ベースでデバッグしてみることに。
テストコードでは上手く動いていました。でも直接APIを叩いてみると、たしかに違う挙動。

最終的に気付いたのが、問題のあるリクエストではCSRFトークンが渡ってきていないことでした。
アクション内ではsessionが使われており、CSRFトークンが渡されていないことでリクエストは空のsessionに対して処理されていました。これは元々のsessionとは別のものとして扱われ、その結果挙動が変わってしまっていました。

# 詳細
例としてこのようなコントローラがあるとします。
（POSTの代わりにDELETEにしていますが、挙動は同様です）

```ruby:app/controllers/session_controller.rb
class SessionsController < ApplicationController
  def destroy
    session.delete(:user_id)
  end
end
```

そしてこのようにルーティングされています。

```ruby:config/routes.rb
match 'logout', to: 'sessions#destroy', via: [:get, :delete]
```

前提として `session[:user_id]` には既に値が格納されているとします。
このとき、以下の２つはどのように動作するでしょうか？

- `GET /sessions/destroy` へのAPIリクエスト
- `DELETE /sessions/destroy` へのAPIリクエスト

コードだけ見ると、明らかにどちらも `session[:user_id]` が削除されそうです。疑いようがありません。ただし、 これはCSRFトークンがリクエストに追加されているか否かで挙動が変わります。

２つともCSRFトークンが追加されていない場合、答えはこうです。

- `GET /sessions/destroy` へのAPIリクエストは `session[:user_id]` が**削除される**
- `DELETE /sessions/destroy` へのAPIリクエスト `session[:user_id]` が**削除されない**

なぜか？
ここで `ApplicationController` を覗いてみましょう。

```ruby:app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  protect_from_forgery with: :null_session
end
```

おっと、なにやら `protect_from_forgery` というコードが。
※ApplicationControllerに書かれているかは各プロダクトごとに異なります

この`protect_from_forgery with: :null_session` が関係しています。
[ドキュメント](https://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection.html)には以下の記述があります。
> CSRF protection is turned on with the protect_from_forgery method. By default protect_from_forgery protects your session with :null_session method, which provides an empty session during request.
CSRF保護は、protect_from_forgeryメソッドでオンになります。デフォルトでは、protect_from_forgeryは、リクエスト中に空のセッションを提供する：null_sessionメソッドでセッションを保護します。
(Google翻訳)

この仕様によって、CSRFトークンによる検証が正しくない場合に `session` の中身が空の状態で、かつ別物として処理されます。また、GETではそもそもCSRFトークンの検証がされないため、`session` の中身は本来の状態で動作します。
その結果、消したはずの `session[:user_id]` が消えていないという挙動になります。

# 振り返り
## なぜちゃんと調査しなければ気付かなかったか？
上記の例ではもしかすると気づけたかもしれません。ですが、 `protect_from_forgery` は `ApplicationController` 側に書かれていたり、それによって普段はあまり意識しなかったりします。これが自分で書いたコードでなければ尚更です。一度経験すればおそらく以後は気付けると思うので、良い経験になりました。

## そもそもなぜGETとPOST（GET以外）を同じアクションにルーティングしているのか？
これについては経緯が不明でした。（実際のコードにはコメントがありお気持ちだけは受け止めました）
Railsガイドにも[このような記載](https://railsguides.jp/routing.html#http%E5%8B%95%E8%A9%9E%E3%82%92%E5%88%B6%E9%99%90%E3%81%99%E3%82%8B)があります。
>1つのアクションにGETリクエストとPOSTリクエストを両方ルーティングすると、セキュリティに影響する可能性があります。本当に必要な理由がない限り、1つのアクションにすべてのHTTP動詞をルーティングすることは避けてください。

GETとPOSTはRFCで定義された仕様としても別物なので、同じアクションにルーティングするのは避けるべきかなと思います。

# さいごに
おそらく今回のものはかなりレアケースかなぁと思います。とはいえどこかの誰かがハマってしまうと悲しいのと、この記事に目を触れた誰かが同様のルーティングをしない、またはルーティングを考える時に注意できる種になればと思います。

お気づきの点があれば気軽にコメントお願いします。些細なことでも歓迎です :tada:
AWSマネージメントコンソールでスイッチロールしてから時間が経った後の操作にはご注意を

## はじめに

本記事では、AWSマネージメントコンソールの挙動によって生じた一見不可解な現象について紹介します。

自分は原因が分かるまでちょっとハマってしまいましたので、もし似たような事象に遭遇した方のお役に立てればと思い、投稿いたしました。

## 何が起こったのか

ACMで発行した証明書を更新するため、検証用Eメールの再送信コマンドを実行しました。実行すると以下の画面が表示されたので、成功して検証メールが送信されたものと思っていました。
![ACM-成功.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176862/7ca8150c-ff10-1e44-c29f-4917d9092d53.png)
ところが、実際には検証メールは送信されていませんでした。

このドメインは自己保有ではなく、サブドメインを移譲してもらって運用していたため、検証メールも移譲元のドメイン宛てに送信され、先方で承認してもらう事になります。そのため、メールが実際に送信されていたかどうかはこちらでは確認出来ない状況でした。

証明書のステータスを確認してもなかなか検証済みにならないので、先方に問い合わせたところ、メールが届いていなかった事が判明しました。

## 原因

メールが送信されなかった原因は、マネージメントコンソールのセッションの期限切れでした。

当時は作業の1時間以上前にログインしてからACMの画面を開いたままにしていました。その状態で検証メールの再送信を実行すると前述の成功画面が表示されたのですが、実際にはロールセッションの持続時間（1時間）を超えていたため操作は失敗していました。

セッションが切れた状態でコマンドが実行でき、かつ実行出来ていないにも関わらず結果が成功と表示されてしまう挙動のため、なかなか原因にたどり着くことが出来ませんでした。

## 対策

今回の経験から、マネージメントコンソールでサインインやスイッチロールしてから時間が経過した後に重要な作業をする場合は、一旦サインインし直すかロールを切り替えて戻すなどして、セッションの持続時間を更新しておくのが無難だと思いました。

また、マネージメントコンソールの代わりにAWS CLIを使うのも良い対策だと思います。AWS CLIであれば、セッション切れの場合は自動的に認証情報を更新してくれるので、セッション切れのままコマンドが実行されてしまう（しかも成功したように見える）事はありません。

## 補足（原因調査〜再現まで）

原因解明に至る過程などを補足しておきます。

ACMの画面だけでは検証メールが実際に送信されたかどうか判断がつかなかったので、CloudTrailからイベント履歴を調査しました。すると、検証メールを再送信した場合に記録されるはずの`ResendValidationEmail`イベントが記録されていませんでした。従って、検証メールは送信されていなかった事が分かりました。

さらに履歴を読み進めると、画面上で再送信を実行してからしばらく後の時刻に`RenewRole`イベントが記録されているのがわかり、これが原因解明の鍵となりました。

このCloudTrailの記録と自分の記憶を頼りに、今回の現象を再現することが出来ました。

1. マネージメントコンソールにログインし、スイッチロールしてACMの画面を開く
*このまま1時間以上放置してセッションが切れるようにします*

2. 検証メールの再送信を実行
![ACM-再送信.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176862/33a3cc79-2847-5d0a-7a84-8465067009d4.png)
*この時点ですでにセッションが切れていますが、画面上では分かりません*

3. 再送信が成功したように見える
![ACM-成功、更新.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176862/a3c244dc-c9cb-854d-1b26-288d044cdf46.png)
*実際にはResendValidationEmailリクエストは行われていません*

4. 最新のステータスを確認するため更新
![ACM-更新中.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176862/872789f4-db3e-8345-ca09-0558c25d1255.png)
*更新中のまま進行しません*

5. 更新が終わらないのでブラウザのタブごとリロード
![ACM-更新後.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176862/b4aa5c06-8537-7ed4-4ec8-25076b50de13.png)
*このリロードによってセッション情報が更新されたようです*

再現手順の4.〜5.がハマリポイントで、4の更新ボタンで画面が固まった事によりセッション切れを示すポップアップが出ない状態となり、5でタブごとリロードした事によって意識せずにセッションが更新されています。以降は普通に操作が出来るようになりますので、セッション切れが生じていたことに気が付きませんでした。

もし3の段階で更新ボタンを押さずにしばらく待っていれば、以下の画面が出てセッション切れに気がつく事ができていました。
![ACM-セッション切れ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176862/c06806f6-23ea-9471-c51e-5b58d1236b9d.png)

以上のように、結果を待たずに成功メッセージが画面に表示される事と、更新ボタンでセッション切れのポップアップが出なくなる事とが組み合わさった結果、「一見成功したように見えて、実際には処理が実行されていない」状態が発生したのでした。

## さいごに

原因が分かってしまえば何でも無い内容でしたが、遭遇した時には訳が分からず困惑しました。
最後までお読み頂きありがとうございました。
Gitでcheckoutできない現象を解消した

gitでcheckoutしようとすると以下のようなエラーが。。。

```
$ git checkout develop
error: Your local changes to the following files would be overwritten by checkout:
	xxx/__pycache__/urls.cpython-37.pyc
	xxx/__pycache__/views.cpython-37.pyc
	xxx/__pycache__/urls.cpython-37.pyc
Please commit your changes or stash them before you switch branches.
Aborting
```

よくわからないままstashを実行。

```
$ git stash
```

なんかできてそう。

とりあえずpullだな。

```
$ git pull
From https://github.com/xxxxx/xxxxx
 * branch            master     -> FETCH_HEAD
Already up to date.
```

これは。。。

```
$ git checkout
Switched to branch 'develop'
```
おおおおおおお！
なんで直ったかわからんができた。

これをやる前にも
`.git/index.lock`を削除するなどいろいろやったので原因がわからない。
python selenium

#ページ全体のスクリーンショット

```python:
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.chrome.options import Options

# ブラウザーを起動
options = Options()
options.add_argument('--headless')
driver = webdriver.Chrome('/Desktop/selenium/chromedriver',  options=options)

driver.get("https://www.yahoo.co.jp/")

w = driver.execute_script('return document.body.scrollWidth')
h = driver.execute_script('return document.body.scrollHeight')
driver.set_window_size(w, h)
driver.save_screenshot('{保存先path}')

# ブラウザを終了する。
driver.close()
```


### setup
```
$ pip install selenium
$ brew install chromedriver
$ pip install webdriver_manager
```


[options一覧]('https://docs.python.org/ja/3/library/argparse.html')
[selenium API検索]('https://www.seleniumqref.com/api/webdriver_gyaku.html')
シェルスクリプトでログローテートの世代管理を行う。

３世代残したい場合は、下記のスクリプトワンライナーでいけます。
（考え方としては、３世代残す→ファイル全部から残したい３世代以外のものを消すと読み替える）

(時間的に古いものから消す場合)
ls -1rt | head -n -3 | xargs rm -rf

（ログの文字列たとえばtestlog20200701等の日付の古いものから消す場合）
ls -1 | head -n -3 | xargs rm -rf

----------------------------
説明（ログの文字列から判断して古いものを消す場合）
1.ダミーのログを配置
 # touch testlog2020070{1..9}

2.確認
 # ls -la
-rw-r--r--.  1 root root    0  5月 17 16:40 testlog20200701
-rw-r--r--.  1 root root    0  5月 17 16:40 testlog20200702
-rw-r--r--.  1 root root    0  5月 17 16:40 testlog20200703
-rw-r--r--.  1 root root    0  5月 17 16:40 testlog20200704
-rw-r--r--.  1 root root    0  5月 17 16:40 testlog20200705
-rw-r--r--.  1 root root    0  5月 17 16:40 testlog20200706
-rw-r--r--.  1 root root    0  5月 17 16:40 testlog20200707
-rw-r--r--.  1 root root    0  5月 17 16:40 testlog20200708
-rw-r--r--.  1 root root    0  5月 17 16:40 testlog20200709

3.削除対象の抽出
20200707から20200709を残したい→（testlog20200701から20200706を削除したいと読み替える）
 # ls -1 | head -n -3
testlog20200701
testlog20200702
testlog20200703
testlog20200704
testlog20200705
testlog20200706

4.抽出したログを削除
 # ls -1 | head -n -3 | xargs rm -rf
確認
 # ls -la
testlog20200707
testlog20200708
testlog20200709

目的の３世代を残せました。

※）(時間的に古いものから消す場合)については、ls -1rtにて行うことで実現している。
オプションt 時間順番で並び替える
オプションr　逆に並べ替える

---------------------------
ログのローテートそのものは、Linux標準のlogrotate.dを使用して行い、削除部分のみをシェルスクリプトにて行うことを想定しています。
（logrotate.dの削除スクリプトはｘ日前という形で処理してあり、削除スクリプトがなんらかの理由で動かなかった場合にログが残ってしまう場合があるため）
CSSで背景を2色使う方法

# プログラミングの勉強日記
2020年7月2日　Progate Lv.148
ポートフォリオ作成中
背景で2色使う方法を調べたが、この方法を用いることでグラデーションもできる。

##目標物
　下のように背景の色を2色使いたい。
<img width="948" alt="0630.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642821/9ac0c6f1-1fcf-354f-e1bc-feaf3ce0308b.png">

##コード
　CSSの`backgrouund`プロパティに`linear-gradient`を指定することでできる。この方法を用いることで、グラデーションも作成できる。
　`background:linear-gradient(色を変える方向,色　位置,色　位置,...);`で指定する。

色を変える方向は以下のキーワードまたは角度を指定する。

| キーワード | 角度 | グラデーションの向き  |
|:-----------------:|:------------------:|:------------------:|
| to top | 0deg | 下から上 |
| to right | 90deg |左から右 |
| to bottom | 180deg | 上から下 |
| to left | 270deg | 右から左 |

```css
/* 左から50％まで青、右から50％まで赤 */
background:linear-gradient(to right,blue 0%,blue 50%,red 50%,red 100%);

/* 青から赤のグラデーション */
background:linear-gradient(to right, blue 0%, red 100%);
```
<img width="853" alt="0702.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642821/370687cd-da36-52d8-cb8b-9adc18a45817.png">

<img width="854" alt="0702-1.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642821/d06e7fec-c81d-cc89-2267-7909c5a91860.png">

　位置は「最初の色」から「次の色」のグラデーションのパーセンテージを表している。
　上の例で1つ目の例では、0%から50％までは青から青のグラデーション（＝ずっと青）を、50%から100%までは赤から赤のグラデーション（＝ずっと赤）を表している。
　なので、2つ目の例では、0~100%まで青から赤のグラデーションを表している。

 角度を変えると下のように斜めで色を区切ることもできる。

```css
background: linear-gradient(45deg, blue 0%, blue 50%, red 50%, red 100%);
```
<img width="856" alt="0702-2.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642821/2826c36e-4b6f-63b4-163d-302377c442c2.png">


##サンプルコード
　目標物になるようにするには以下のコードを利用した。

```css:CSSファイル
.skill{
background:linear-gradient(to right,rgb(227, 246, 245) 0%,rgb(227, 246, 245) 60%,rgb(255, 246, 199) 60%,rgb(255, 246, 199) 100%);
}
```
【Laravel】配列のバリデーション

フォームのフィールドが配列の場合のバリデーションについてのメモです。
###ドット記法
配列に対してバリデーションを行うためにはドット記法を使い、`.`で配列の階層を表します。また`*`で配列内すべてを表します。

```php
//photos[profile]フィールドを指定
$validator = Validator::make($request->all(), [
    'photos.profile' => 'required|image',
]);

//keywordフィールドすべてを指定
$validator = Validator::make($request->all(), [
    'keyword.*' => 'required|max:20',
]);
```
####エラーメッセージの取得

```
Illuminate\Support\ViewErrorBag {
  #bags: array:1 [
    "default" => Illuminate\Support\MessageBag {
      #messages: array:2 [
        "keyword.0" => array:1 [
          0 => "キーワードは、20文字以下で指定してください。"
        ]
        "keyword.1" => array:1 [
          0 => "キーワードは、20文字以下で指定してください。"
        ]
        "keyword.2" => array:1 [
          0 => "キーワードは、20文字以下で指定してください。"
        ]
      ]
      #format: ":message"
    }
  ]
}
```
配列にバリデーションを設定した場合、エラーメッセージも配列で返ってくるため、取得もドット記法で行います。

```php
foreach ($errors->get('keyword.*') as $messages) {
    foreach ($messages as $message){
       //
    }
}
```
globで複数のエクセルを一挙取得する（ボートレース機械学習予測結果　6月分の確認）

# はじめに
※本記事のコード解説自体は、pythonプログラミング初心者向けとなっております。

ボートレース３連単予測サイト「[きょう、ていの良い予想は当たるだろうか](https://youhaveniceboat.pythonanywhere.com)」では毎日のレース予想の的中率や回収率をつつみ隠さず公開しているのですが、月に一度は毎日の予想結果を１つにまとめておきたいなと思い、表題のような処理をしようと考えました。


# 私の状況
ボートレースの試合結果と機械学習による予想を整理し、"result_2020mmdd.csv" といった形式で毎日保存しています。月に一度はこれらのファイルをまとめて、結果を可視化したい..。

そして下図にあるような、ところどころ混ざっているresult_202006.. **_test** .csv のようなファイルはテスト用なので省きたい..。

<img width="404" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635959/993c612c-ad18-f716-f54f-a65d12de0c2d.png">


# コードはこんな感じ。
とてもシンプルです。

```python

import pandas as pd
import glob

csv_files = glob.glob("predict/result/result_202006??.csv")
filelist = []
for file in csv_files:
    filelist.append(pd.read_csv(file))

df = pd.concat(filelist)
```
globでパス名を取得する際にresult_202006 **??** .csvとしています。1つの?で任意の一文字分を担当してくれます。

csv_filesにはいい感じにファイル+パス名が一式格納されています。
<img width="626" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635959/ee6c2cfa-b0c3-c8c7-9f54-66189b19f48b.png">

for文でひとつずつappendしていき、最後はDataFrame化して完成！です。

# ちなみに6月の結果はどうだったのか..

先ほどつくったデータフレームを使って、結果を確認しました。
３連単的中率は設計通り10%を記録しましたが、回収率が80%強です..。（とはいっても、その他の無料予想を見ていると、現時点でも割と戦える感じかもしれない。）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635959/b8bce1bb-317a-04a9-7374-9946dcdf9c42.png)

まとめた後にpivot_tableで整理した結果がこちらです。
**当たりやすい競艇場と全然あたらない競艇場がはっきりしているのが面白いです。**　
今月は当たりやすい競艇場だけ買ってみようかな..

| Site | Hit | Miss | Payoff | Return_ratio |
|:--|--:|--:|--:|--:|
| 丸亀 | 5 | 26 | 5480 | 176.77 |
| 蒲郡 | 3 | 21 | 3990 | 166.25 |
| 徳山 | 9 | 33 | 6800 | 161.9 |
| 琵琶湖 | 9 | 31 | 5810 | 145.25 |
| 浜名湖 | 8 | 43 | 6030 | 118.24 |
| 戸田 | 4 | 46 | 5470 | 109.4 |
| 江戸川 | 3 | 24 | 2740 | 101.48 |
| 鳴門 | 6 | 44 | 5060 | 101.2 |
| 常滑 | 4 | 38 | 4190 | 99.76 |
| 児島 | 5 | 58 | 6230 | 98.89 |
| 住之江 | 2 | 33 | 3340 | 95.43 |
| 福岡 | 2 | 14 | 1460 | 91.25 |
| 芦屋 | 6 | 46 | 4540 | 87.31 |
| 大村 | 8 | 51 | 4770 | 80.85 |
| 唐津 | 3 | 30 | 2600 | 78.79 |
| 尼崎 | 5 | 52 | 4270 | 74.91 |
| 宮島 | 5 | 36 | 2400 | 58.54 |
| 平和島 | 3 | 40 | 2510 | 58.37 |
| 多摩川 | 3 | 32 | 1850 | 52.86 |
| 下関 | 3 | 54 | 2760 | 48.42 |
| 三国 | 5 | 58 | 3030 | 48.1 |
| 若松 | 4 | 56 | 1780 | 29.67 |
| 桐生 | 1 | 47 | 1190 | 24.79 |
| 津 | 3 | 67 | 1290 | 18.43 |
C++における構造体とクラスの違い

#構造体とクラスの違い
本来、構造体とクラスは概念的には別物であるが、c++においてはアクセス制限の違いだけである.
・structのデフォルトはprivate
・classのデフォルトはpublic
と言う違い。基本的にはclassを用いればいい.
ざっくりSpark+AI Summit 2020 - 1日目 -

自分用にメモ。英語聞くのしんどい・・・。

## 1: Wednesday morning keynote

* Al Ghodsi(Databricks)
    * データ分析はチームスポーツ。複数のチーム間のデータ連携が重要になってきた
    * 祝Spark10周年
* Matei Zaharia(Databricks)
    * PySpark利用が全体の7割
    * Spark3.0出たよ
        * 3,400くらいパッチをあてた。約半分がSparkSQL
        * Adaptive Query Execution(AQE)追加した。動的にreducer/join最適化。TPC-DS 1TBで最大8倍ほど速くなった
        * Dynamic partition pruning追加した。TPC-DS 1TBで2〜18倍速くなった。TPC-DS 30TBでざっくり倍速くなった
        * Apache Arrowを呼ぶようにした。SparkRは40倍早くなる。PySparkは若干
    * Koalas頑張ってる。PandasのAPI8割ほどカバーした
    * Project Zen: 今後PySparkのエラー出力簡素化する。Koalasバックポートする
* Al Ghodsi(Databricks)
    * LakeHouseアプローチがイケてるのでその辺カバーする
    * DeltaLakeの上にDeltaEngineというやつを作った
* Reynold Xin(Databricks)
    * Delta EngineはQuery Optimizer、Native Execution Engine, Cachingでできてる。Apache Spark 3.0の上に作っている。SQL, Spark DataFrameを高速化できる。
    * Query Optimizerでスタースキーマのケースでは18倍高速化できる
    * Cachingでscanを5倍高速化できる
    * Native Execution Engine(Photon)はC++で書いててSIMD使ってるのでネイティブで速度が出せる。使いたかったらDataBricksに連絡してね(つまり有償？)
* Al Ghodsi(Databricks)
    * Delta Lake内部にオートローダー作ってDelta Lakeだけでデータソースから取り込めるようにした
    * アクセス制御いろいろ追加した
    * ReDashがDataBricksに参加したよ
    * Starbucksの事例を紹介するよ
* Vish Subramanian(Starbucks)
    * Azure+Azure DataBricksで作ったよ。いろいろ頑張った。エンジニア募集中！

## 2: Wednesday afternoon keynote

* Dr. Phillip Atiba Goff
    * Black Lives Matterに関する運動は、最初はとある一地域で起きた黒人に対するリンチのようであったが、時間が立つに連れて州をまたいだ大きな運動になった。それを予測できなかったのは現在の課題を計測できていなかったからだ。
    * データサイエンティストは眼の前の課題に集中しがちだが、外に出て何が起きているのかを見てほしい。そして計測してほしい。例えば子供の成長を背の高さを計測することで認識するように。計測することの必要性は強調するまでもないと思う。世の中には報道されていないことが数多くある。データサイエンティストが地元で活動することに大きな意味がある。
    * 基礎的な社会投資が少なくなっていることも影響しているかもしれない。それはめぐりめぐって様々なことに影響を及ぼしているかもしれない。警察予算を削減しようという意見もあるが、それが本当に問題を解決するのか？教育予算、公共予算も同様だ。
    * USに警察組織は18,000あるが、使用されているシステムは相互にデータを融通することができない。これが何を意味するか想像できると思う。データサイエンティストは現状でも貢献できることはあるはずだ。
    * 今本当に取り組むべき問題が表出しているときだと思う。オタク、データオタク、正義オタクが活躍できる時代だと思う。ぜひ自分の周りに目を向けて、活動してほしい。
* Jennifer Chayes(UC Berkeley)
    * Berkeleyでデータサイエンスを活用して社会課題に取り組む組織ができた。最近できた組織でいろいろ部署があるけどPublic Healthの分野でCOVID-19パンデミックが起きてさっそくフル稼働することになってしまった
    * 最初にやったのは今後7日でどの病院がどの程度負荷を受けるかの予測。20個のデータセットを使ったがそれぞれフォーマットが違ってた。フェイスシールドをどこに配送すべきかの予測も行った。
    * 次にやったのがCOVID-19の影響でどこがどの程度経済的な影響を受けて飢餓や餓死者が出るかの予測。ナイジェリア、トーゴ、ウガンダ、バングラデシュに影響が出ることがかなりの精度で予測された。これも衛星画像や電話の通話記録などぜんぜん違うデータセットを組み合わせた。これらの国で2.5億人の人が飢餓に苦しむことが予測できた。
    * イタリアの死亡率の正確性の検証もやった。最初に言われてたものよりぜんぜん死亡率は高いことがわかった。年代による死亡率の変化も計測、可視化することができた。
    * 世界中の約80,000のCOVID-19論文をクロールして関連性を調べたり、どのような手段が試されているかなどを可視化した
    * MLでワクチンのドラッグデザインを行った
    * スマホの陽性者接触アプリのデータを収集してる。もちろん個人情報は収集していない
    * いろんなデータソースを繋げるのにSparkの上にアプリを作った。今までのものと比べて20倍〜100倍早い
* Nate Silver(FiveThirtyEight.com)
    * 90%のデータはこの2年で生成されている。コロナウイルス、大統領選挙、(日本で起きた)大きな地震、など
    * データが多くなるほど議論の余地、解釈の余地が大きくなる傾向がある。そこに「見たいものを見たい」という認知バイアスが入る余地が出てきてしまう。Zoomの会議でも参加人数が多くなると混沌となり、無意識のうちに情報を選択する状態と似ている。
    * 2つのルートを見てみる。なぜドライバーは最短ルートを通らないのか。GPSで捉えられない情報がある。最適値以外をエラーとして切り捨てる危険性。
    * 確率的な要素に注意しよう。堤防の水位を予測して警報を出す場合に、予測値にはプラスマイナスの誤差が含まれていることを忘れてはいけない。予測された水位が堤防以下でも、誤差を考慮すると溢れてしまうという確率がある。不確実性に注意し、伝えるようにしよう。台風の予測進路のグラフィックは参考になると思う。
    * グループがどのような特徴やバックグラウンドを持っているのかに着目しよう。あるグループは必ずしもあなたが考えるような行動をとらないかもしれない。
    * (ここはわからなかった)
SDKMAN でインストールした java のバージョンをディレクトリ移動時に切り替える


.sdkmanrc を使うと、direnv のようにディレクトリ移動時に SDKMAN でインストールした java, scala などのバージョンを切り替えることができる。
比較的最近追加されたので、利用するには SDKMAN を最新（執筆時点では 5.8.3）にアップデートしておく。

## .sdkmanrc を生成
バージョンを指定したいディレクトリで `sdk env init` を実行する。

```sh
$ cd sdkenv-test/
$ sdk env init
.sdkmanrc created.
```

.sdkmanrc が生成され、次のようになっている。

```sh
$ cat .sdkmanrc
# Enable auto-env through the sdkman_auto_env config
# Add key=value pairs of SDKs to use below
java=8.0.202.j9-adpt
```

## 設定

生成された .sdkmanrc に使用したいバージョンを指定する。

```sh
# Enable auto-env through the sdkman_auto_env config
# Add key=value pairs of SDKs to use below
java=13.0.2.j9-adpt
```

~/.sdkman/etc/config で `sdkman_auto_env=true` に設定する。
`sdkman_auto_env=true` とすることで direnv のようにディレクトリに移動したときに自動的に切り替わる。

シェルをリスタートする。

```sh
$ exec $SHELL -l
```

## 実行例

```sh
$ cd sdkenv-test/

Using java version 13.0.2.j9-adpt in this shell.
```

## sdkman_auto_env=false の場合は手動で切り替える必要がある
`sdkman_auto_env=false` に設定されていると、.sdkmanrc のあるディレクトリに移動しても自動では切り替わらない。
`sdk env` を実行して切り替えないといけない。

```sh
$ cd sdkenv-test/
$ java --version
openjdk 14.0.1 2020-04-14
OpenJDK Runtime Environment AdoptOpenJDK (build 14.0.1+7)
Eclipse OpenJ9 VM AdoptOpenJDK (build openj9-0.20.0, JRE 14 Linux amd64-64-Bit Compressed References 20200416_44 (JIT enabled, AOT enabled)
OpenJ9   - 05fa2d361
OMR      - d4365f371
JCL      - 5757187cae based on jdk-14.0.1+7)
$ sdk env

Using java version 13.0.2.j9-adpt in this shell.
```
MacでMysql構築で手間取ったので備忘録

# MacでMysql使いたいけどうまくログインができない
インストールして`mysql -uroot`しても
エラー起きるううう！！！！何でだあぁぁあぁぁぁぁぁぁぁ（z会）

となりませんか？　私はなりました。

## MACでのデータベース作成について 
何はともあれインストールしてない人はインストールしましょう。
初めてのインストールの場合は以下の　`--skip-grant-tables` のオプションをつけて起動してください。

``` zsh.コマンド
brew install mysql
mysql.server start --skip-grant-tables
```

これで上手くいくはずです。

#ERRORが起きる場合
### もし、既にインストールされていた場合は上記のコマンドを打つと、下記のように「既に存在してるんじゃバカたれ」と怒られてしまいます
---

``` zsh.コマンド
2020-07-01T13:47:46.6NZ mysqld_safe A mysqld process already exists
```

と出た場合は

```
brew services stop mysql
mysql.server start --skip-grant-tables
```

を行ってください。　もしダメなら全て消して大丈夫な場合は`brew uninstall mysql`　を行なってから一番上のものを試してください

**このようなことに陥る理由としてはおそらく**

```
mysql.server start --skip-grant-tables
```

をする前に

```
mysql.server start
```

を行なっている可能性があります。

## 最後に

データベース使いたいと思っても何らかのエラーが出てしまって困りますよね（経験談）
【コピペOK】hoverしたら動き出すCSSボタンアニメーション３０選

[<img width="660" alt="スクリーンショット 2020-07-02 0.34.31.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643410/0d8e7c68-8557-5286-037f-698c21e708a1.png">
](https://www.twinzlabo.com)

**コピペだけで作れるボタンアニメーションを30個**を紹介いたします。

box-shadow, filter, transformなどをふんだんに使っており、transitionで滑らかな動きが表されています

コードには説明もわかりやすく書いてあるのでかなり参考になります

Webデザイン初心者の方はもちろんですが、バックエンドエンジニアの方にもとても助かる内容になっています


## CSSボタンアニメーション30選

### 1. transitionを使いこなすボタンアニメーション9選

transitionを使ってボタンにアニメーションを効かせおり、WebサイトやWebアプリケーションで使えるボタンエフェクトとなっています

box-shadowやborder-radiusをエフェクトで使用して見た目のデザインもいい感じです

[![hover-button-animation-color.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643410/66cc0873-a5e5-187d-2c4e-7151c8dfa598.png)
]

**↓参考記事は下の記事です↓**

[<img width="581" alt="button-effects1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643410/1340a5c7-a871-d1f8-d8d8-7b49247c7467.png">
]


### 2. filterが網羅できるCSSボタンアニメーション15選

filterを使ってボタンにエフェクトを効かせおり、特にデザインの見た目をカッコよくしたい場合に非常に使えます

filterエフェクトを全種類使っているので永久保存版としても重宝できそうなまとめ記事になっています

勉強にもフロント開発でも役立つと思います

[![hover-button-animation-filter.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643410/c256f0a6-de10-0e95-4443-a8010f39bff6.png)]



### 3. scaleでオシャレなCSSボタンアニメーション3選

transform:scaleを使ってボタンにエフェクトを効かせおり、オシャレでかっこいいボタンになっています

ボタンの背景が滑らかにスライドしたり、フワッと出てきたりするのでみているだけで面白いです

[![css-animation-button-diagonal.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643410/9b2d5bd2-f185-f8b6-1daa-4e5fd66fc8b1.png)
]

**↓参考記事は下の記事です↓**

[<img width="584" alt="button-effects3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643410/065216b8-db09-4bf4-fc43-42a1e8fd895c.png">
]


### 4. ボタンでつくる回転アニメーション9選

transitionを使ってボタンが自然に回転します

ボタンが回転するって純粋に興味ありませんか？

回転扉みたいに動くんです

[![hover-animation-button-explain3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643410/602b2e14-733b-fd07-142f-8be38c6d94f8.png)
]
nimとpythonを繋ぐ素敵なnimporter

# さいつよのnim + pythonを繋ぐモジュール
nimporterというモジュールが感動的だったので紹介します。
いや、紹介自体はn番煎じかもだけど、あんま知られてないっぽいので。
https://github.com/Pebaz/Nimporter
要するに、nimの超高速コードをpythonでインタプリタっぽく動かす奴です。

公式の例を抜粋しますが、nimのコードを下記のように

```nim
import nimpy

proc add(a: int, b: int): int {.exportpy.} =
    return a + b
```

pythonのコードを下記のように

```python
# Nimporter is needed prior to importing any Nim code
import nimporter, nim_math

print(nim_math.add(2, 4))  # 6
```

書けば、**コンパイルが自動的になされてimportされます**。
いや、マジで実質インタプリタ言語じゃねえか！ってなります。

# お約束の速さ比較
敢えておっそい再帰でフィボナッチ数列の計算をさせてみます。
nimのコードは下記。

```nim:fibnim.nim
import nimpy
proc fib(n: int): float {.exportpy.}=
    if n == 1:
        return 0
    elif n == 2:
        return 1
    else:
        return fib(n - 1) + fib(n - 2)
```

pythonの方は下記。

```python:fibpy.py
def fib(n: int) -> float:    
    if n == 1:
        return 0.
    elif n == 2:
        return 1.
    else:
        return fib(n - 1) + fib(n - 2)
```

...にしても、クッソ似てますね。
この2つをpythonでimportして比べてみましょう。

```python
import fibpy
import nimporter, fibnim
from time import time
cycle = 36
t = time()
print(fibnim.fib(cycle))
print('Time of nim is {} sec'.format(str(time() - t)))
t = time()
print(fibpy.fib(cycle))
print('Time of python is {} sec'.format(str(time() - t)))

>>> 9227465.0
>>> Time of nim is 0.026133298873901367 sec
>>> 9227465.0
>>> Time of python is 3.1436727046966553 sec
```
1回目はコンパイルの時間がかかるのですが、二回目以降は順当に100倍以上ですね。

# そもそもcythonじゃダメなん？
ダメではない。むしろ筆頭候補。cythonも最近はかなり使いやすくなっていて
型ヒント付きpythonをpurepythonモードに食わせるとpythonから変更無しで移行できそうなレベルです。[^ikou]

[^ikou]: 実際はチューニング頑張らないと速くならなかったりする

```python
import pyximport
pyximport.install()
```

ってな感じでサクッとインポートできます、優秀です。
(追記。ここ、pyximportの事書いてなくてcythonizeしないとだから面倒いよねって書いてました。間違いです、すみません。)
ただ、cythonは一部でpythonを使う事があるので、
カツカツに最適化する時にprofiling使ってチューニングしていかないといけないので
意外と面倒…という時が無くもない気がします。
その点がnimの強みでしょう。
メモリの動的確保の注意 malloc, calloc C言語

# はじめに
C言語だとメモリを動的確保する際に、mallocやcallocといったメモリを確保する関数を使うと思います。そのときの注意です。

基本的な使い方に関しては[こちら](http://www9.plala.or.jp/sgwr-t/lib/calloc.html)

callocの返り値は**アドレス**

```:環境
gcc -v
Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/4.2.1
Apple clang version 11.0.3 (clang-1103.0.32.59)
Target: x86_64-apple-darwin19.5.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
```

# 本文
## 「stdlib.hを必ずインクルードすること」

mallocを使うためには、`#include <stdlib.h>`を魔法のように唱えると思います。

では唱えなかった場合はどうなるでしょうか。普通ならコンパイル（プリプロセス）の段階で落ちるはずです。ですがmallocに関してはwarningを吐くだけでコンパイルはできてしまいます。

この時のデメリットとして、**返り値がint型になる**ことが挙げられます

「想定した動作では64bitのlong*（long型ポインタ）として 返したいにもかかわらず、32bitのint型が返ってしまう。」というようなバグが起こるわけです。

[参考：mallocのwiki > C言語での動的メモリアロケーション](https://ja.wikipedia.org/wiki/Malloc)

## 「要素数 0 でcallocを呼ばないこと」

callocは通常、配列などの複数要素を動的に確保するために使用するケースが多いです。なので、本来要素数を0で呼ぶことは考えられないのですが、呼んでしまった場合どうなるでしょう

メモリ確保に失敗したとしてNULLポインタが返って...くるわけではありません。

実際には処理系定義ですが、返せる領域があればNULLポインタではなくアドレスが返ってくる場合が存在します。

その場合、NULLだと思って処理を進めるとバグを生む可能性があります。

[参考：C 標準 [ISO/IEC 9899:2011] セクション 7.22.3 抜粋ページ](https://www.jpcert.or.jp/sc-rules/c-mem04-c.html)

## 「確保した要素数以上へのアクセスはできてしまう」

先ほどに引き続き、callocは複数要素を動的に確保するために使用するケースが多いです。なのでint型の配列で3要素欲しければ`(int*)calloc(3, sizeof(int))`をint* の変数に代入するわけです。

配列の宣言として`int array[3]`としたとき`array[3]`にアクセスするとどうなるかもちろん参照外アクセスで落ちますね。
ではcalloc関数の場合は？

```C
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char const *argv[]){

    int* ap;
    
    ap = calloc(3, sizeof(int));
    
    ap[2] = 1;
    ap[3] = 1;
    printf("%p\n", &ap[2]);   // アドレスを表示
    printf("%p\n", &ap[3]);
    printf("%p\n", &ap[4]);
    printf("%d\n", ap[2]);
    printf("%d\n", ap[3]);
    printf("%d\n", ap[4]);

    free(ap);    
    return 0;
}
```
```:出力結果
0x7fe2d3c05848
0x7fe2d3c0584c
0x7fe2d3c05850
1
1
0
```

普通にアクセスできるですね（ドン引き）。しかもコンパイラはwarning出しませんでした。

ここからは予想ですが、callocは起点となるアドレス(ar[0])を返すだけですから、連続領域として確保した要素数以上のところもアクセスできてしまうんですかね(謎)

いずれにしても、こういう想定外のことはバグの原因になるので注意しましょう。
WindowsからCentOSへのリモートデスクトップ接続がつながった瞬間切断する

# WindowsからCentOSへのRDPがつながった瞬間切断してしまう
## 環境
- Centos7
- Windows10

## 問題
- Centos上でxrdpサービスで起動, Windowsからリモートデスクトップで接続し, アカウントとパスワードを入力すると, 何のエラーも表示されずに画面が閉じてしまう. 
- rootでは接続できるが, 一般userだと上記のような現象が起きて接続できない.
- ```/var/log/xrdp.log```も```/var/log/xrdp-sesman.log```も特にエラーなし
- xrdpの設定は例えば[ここ](https://qiita.com/SkyLaptor/items/56c9b5f5784f19cac225)に書いてあるような環境構築をしてあります。

## 原因
- ```~/.bashrc```でconda環境に```$PATH```を通していたことが原因
- 本来接続の過程で```/bin/dbus-daemon```が呼ばれるはずが, ```anaconda3/bin```にPATHが通っていたため```anaconda3/bin/dbus-daemon```が呼ばれてしまいそれがエラーを引き起こしているらしい
    - https://forums.centos.org/viewtopic.php?t=66886

## 改善策
- とりあえず```~/.bashrc```の
```
export PATH=/home/<yourname>/anaconda3/bin:${PATH}
```
をコメントアウトすれば繋げた
- 普段はSSHで接続するので, せめてその時は起動時にconda環境を呼び出したい. 苦肉の策で```~/.bashrc```の該当行を以下のように変更

```
if [ -v $XRDP_SESSION ]; then
    export PATH="/home/<yourname>/env/anaconda3/bin:${PATH}"
fi
```
【初心者向け】1pxのズレもなくコーディングするための便利ツール

# どうも、7noteです。今回は必ずいれてほしいgoogleの拡張機能を紹介

どうも7noteです。
この記事は以下へ引っ越しました。

https://naruweb.com/tool/perfectpixel/
Javaの配列

##はじめに
順次進行、繰り返し、条件分岐でだいたい作れるって言われても全然作れんわッッ！！（本投稿に関係はない）

##配列
**変数は1つの値**しか入れられないが、**配列は複数の値**をまとめて入れれる。
1列のものを**一次元配列**、2列以上は**多次元配列**という。
ひとつひとつを**要素**といい、その数を**要素数**という

```kane.java
データ型[] 配列変数名;
配列変数名 = new データ型[要素数];

String[] banana;
banana = new string[3];

banana[0] = "Cavendish"
banana[1] = "Lakatan"
banana[2] = "GrosMichel"
```

上記は宣言と代入を別に記述
下記は宣言と代入を同時に

```kane.java
データ型[] 配列変数名 = {要素１,要素２,...};

String[] banana = {"Cavendish", "Lakatan", "GrosMichel"}

```
[]はデータ型の後くっつけて書く（**int[],String[]**のように）

**要素の上書きは、配列変数名[インデックス番号] = "新しい要素"**

各要素は、**配列名[インデックス番号]で取得**できる。

```kane.java
String[] banana = {"Cavendish", "Lakatan", "GrosMichel"};

banana[1] = "LadyFinger" //要素の上書き

System.out.println(banana[1]);

//実行結果　LadyFinger
```
##多次元配列
エクセルの表計算ソフト的な



|banana|0|1|
|:--|:--|:--|:--|
|0|Cavendish|Lakatan|
|1|GrosMichel|LadyFinger|  



```kane.java
データ型[][] 配列変数名;
配列変数名 = new データ型[要素数][要素数];

String[][] banana;
banana = new string[2][2];

banana[0][0] = "Cavendish"
banana[0][1] = "Lakatan"
banana[1][0] = "GrosMichel"
banana[1][1] = "LadyFinger"

System.out.println(banana[1][0]);

//実行結果　GrosMichel

```
これも省略できる

```kane.java
String[][] banana = {{"Cavendish", "Lakatan"},{"GrosMichel","LadyFinger"}};

System.out.println(banana[0][0]);

//実行結果 Cavendish
```

##終わりに
多次元配列って便利なのはわかるが自分の頭が一次元だからパンクする
Rubyを2行でセグフォらせる

流行ってると聞いたのでRubyでもやってみました

```ruby
require 'fiddle'
Fiddle::Pointer[0].ptr
```

ワンライナー

```sh
ruby -r fiddle -e 'Fiddle::Pointer[0].ptr'
```

なんでこれでセグフォるのかはあんまり理解していません…。
Rails 　テーブル作成、カラムの追加や削除

## はじめに
よく忘れるので、メモ

## モデル作成 テーブル作成

railsでモデルを作成する際に、テーブルを作成するためのマイグレーションファイルが同時に作られます。
↓モデル作成コマンド

```
$ rails generate model [モデル名] [属性名:データ型 属性名:データ型・・・] [オプション]

省略版
$ rails g model [モデル名] [属性名:データ型 属性名:データ型・・・] [オプション]
```
-コマンドを実行すると、自動で作られるファイル

　①モデルのクラスファイル
　②マイグレーションファイル
　③モデルの自動テスト
　④モデルの自動テストで使うfictureファイル

```
例　$　rails g model User name:string email:string
上のコマンドで作ると下のマイグレーションができる。

class CreateUsers < ActiveRecord::Migration[5.2]
  def change
    create_table :users do |t|
      t.string :name
      t.string :email

      t.timestamps
    end
  end
end
```

そしたら、マイグレーションをする。

```
$ rails db:migrate
```

終わり

## テーブル削除 カラム追加・削除

※クラス名はAddXXXToYYY、またはRemoveXXXFromYYYとします。
「XXX」にはテーブル名、YYYにはカラム名（複数のカラムを変更したい場合などがあるのでカラム名ではなくても大丈夫）

### **カラム追加のマイグレーション作成**
**※memo（text型）のカラムを追加する場合**

```
例　$ rails g migration AddMemoToUsers memo:text
```

作成されたら**$ rails db:migrate**を実行し反映させます。


### **カラム削除のマイグレーション作成**
**※name(string型)のカラムを削除したい場合**

```
例　$ rails g migration RemoveNameFromUsers name:string
```

作成されたら**$ rails db:migrate**を実行し反映させます。

### **テーブルの削除**

マイグレーションファイルの作成
本当は**users**としたかったところを**userss**としてしまい。テーブルを削除することに。なので、マイグレーションファイルを作成する。

```
例 $ rails g migration userss
```
マイグレーションファイル編集
消したいテーブルを指定して、drop_table :userssと記述する。

```
例　class DeleteUserss < ActiveRecord::Migration[6.0]
  def change
    drop_table :userss
  end
end
```

下記のコマンドを叩くと、データベースから削除される。

**$ rails db:migrate**

## ファイルの削除
ファイルツリーから直接消さずに、コマンドを実行してファイルを削除しましょう。

```
$ rails destroy migration クラス名

省略
$ rails d migration クラス名

```

```
例　$rails d migration AddMemoToUsers
```
Excel　一覧・詳細シートの相互リンクを関数で実現する

テーブル定義書とか課題管理とかをExcelでやろうとすると

![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/663051/0bcccd7f-83f5-71e0-5931-f4af14a5561c.png)

のようにシートを作るのだが、シートが増えると行き来がとても面倒。
なので、関数を使ってリンクボタンを作成するので、覚書もかねて。

# 一覧から設定したシート名に飛ぶリンク
単純に、「セル」の部分に、シート名が入力されているセルを指定することで、そのシートのA1に移動するハイパーリンクを作成するというもの。

```vb:sample
=IF(セル<>"",HYPERLINK("#'" & セル &"'!A1","■"),"")
```

# 一覧に戻る場合の固定リンク
前項の「一覧から設定したシート名に飛ぶリンク」と仕組みは同じで、「一覧」のシートのA1へのハイパーリンクを作成する。

```vb:sample
=HYPERLINK("#'一覧'!A1","一覧に戻る")
```
Apple APNsでのPUSH通知のテストスクリプト

# はじめに
Firebase Cloud Messaging でPUSH通知の実装していましたが、なぜか、iosでPUSH通知されなくなっていました。何が原因なのかを切り分けるために、AppleのPUSH通知サービス(APNs)でPUSHが送信されるか試すことにしました。

APNsでの認証ですが、以前使われていた「APNs 証明書」と最近使われている「APNs 認証キー」の２つがあります。「APNs 認証キー」を使ったPUSH通知のスクリプトを記載します。このスクリプトは、macで動かしています。おそらく、curlとopensslがある環境であれば動くと思います。

パラメータは、Firebaseから取得するように書いていますが、APNsのパラメータを使えばPUSH通知できるので、Firebaseを使っていない場合もこのスクリプトでテストできます。

# 準備
以下のシェルスクリプトで記載する`キーID`、`チームID`、`アプリのバンドルID`は、Firebase Consoleの以下で確認できます。`設定`の`クラウドメッセージング`から`iosアプリ設定`の項目を確認します。図の赤で囲っている部分に、上記の3つのIDが記載されています。
`APNs認証キーのファイル`は、Firebaseのここの設定をした時に保存していると思いますので、そのファイルを使います。

<img width="700" alt="cachepolicy" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404406/fdd8a820-de44-f20d-e9be-0fd7a26cfc9b.png">

<img width="700" alt="cachepolicy" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404406/e6fc2a1b-3922-1ab7-8d89-dc8cd2b3a8c7.png">

# PUSH通知のシェルスクリプト
 以下のシェルスクリプトの`設定項目`以下の5行のパラメータを自分のアプリのパラメータに設定して、シェルスクリプトを動かすとiPhoneへのPUSH通知ができます。
`デバイストークン`は、PUSH通知を送信したいiPhoneのデバイストークンを指定してください。

```
#!/bin/sh

# ------ 設定項目
deviceToken=1234567890abcdefghij  # デバイストークン
authKey="./AuthKey_AZ8N4W9YYC.p8" # APNs 認証キーのファイルを指定
authKeyId=AB8C4D9EFG              # キー ID
teamId=ABCD12EFGH                 # チーム ID
bundleId=com.example.appbundleId  # アプリのバンドルID
# ------ 設定項目終了

endpoint=https://api.development.Push.Apple.com

read -r -d '' payload <<-'EOF'
{
   "aps": {
      "alert": {
         "title": "notification title",
         "subtitle": "notification subtitle",
         "body": "notification body "
      }
   }
}
EOF

base64() {
   openssl base64 -e -A | tr -- '+/' '-_' | tr -d =
}

sign() {
   printf "$1"| openssl dgst -binary -sha256 -sign "$authKey" | base64
}

time=$(date +%s)
header=$(printf '{ "alg": "ES256", "kid": "%s" }' "$authKeyId" | base64)
claims=$(printf '{ "iss": "%s", "iat": %d }' "$teamId" "$time" | base64)
jwt="$header.$claims.$(sign $header.$claims)"

curl --verbose \
   --header "content-type: application/json" \
   --header "authorization: bearer $jwt" \
   --header "apns-topic: $bundleId" \
   --data "$payload" \
   $endpoint/3/device/$deviceToken
```
Javascript クラスの書き方

## Update: 進化版をこちら：
[https://qiita.com/koryo/items/06a5959684372dca4c6f](https://qiita.com/koryo/items/06a5959684372dca4c6f)

### Javascript クラスの書き方。
```js
var Foo = (function(name) {
    var privates = new WeakMap();
 
    function Foo(name) {
        privates.set(this, {});
 
        privates.get(this).prop = 1;
        privates.get(this).name = name;
    }
    Foo.prototype._share = 'share';
    Foo.prototype.changeShare = function(newValue) { Foo.prototype._share = newValue; };
    Foo.prototype.method = function() { return privates.get(this).prop; };
    Foo.prototype.say = function() { console.log(privates.get(this).name); };
 
    return Foo;
})();

var foo1 = new Foo('aaa');
var foo2 = new Foo('bbb');
foo1.say(); // aaa
foo2.say(); // bbb
console.log(foo1.name); // undefined
console.log(foo1.say === foo2.say); // true
console.log(foo1._share === foo2._share); // true
console.log(foo1._share); // share
console.log(foo2._share); // share

/*foo1.share = 'change';*/
foo1.changeShare('change!');
console.log(foo1._share); // change!
console.log(foo2._share); // change!

console.log(foo1.hasOwnProperty("_share")); // false
console.log(foo2.hasOwnProperty("_share")); // false
```

1. private 変数ができる。
2. 共通の変数ができる。(_share)
3. 外から無理プチこんだら終わりだが、js はそんなもんなので、どうしようもない。

参考元：[https://webkatu.com/archives/private-property/](https://webkatu.com/archives/private-property/)

以上。
ObservableをSubscribeした時にハマったこと

## HttpClientのGETメソッドから値をsubscribeする
Angularでとあるデータをバックエンドから呼び出し、それをフロントエンドで処理して描画する必要があったのですが、

ユーザーが条件入力 $\Rightarrow$ データをAPIから呼び出す　$\Rightarrow$ 　データを処理して描画する

という流れから、データを処理するためにはデータのロードが終わっていなければいけませんでした。じゃあどこなら確実にロードが終わっているのか？という疑問の答えを探すのに苦労しました。

##Subscribeの流れ
例えばこんな感じのGETメソッドをsubscribeするとします。

```
//get-dataService.ts

getAll(): Observable<DataObject> {
    return this.http.get('somegreatURL');
  }
```

```
ngOnInit(): void {

    this.getDataService.getAll().subscribe(datas =>{
      this.datas = datas;
    });

　　//ここでconsole.log(this.data);をしてもthis.datasを初期化していなければundefined, していれば初期値が返ってくる
}
```

コード内のコメントの通り、subscribeの直後にデータを受け取るはずの変数を確認しても、ロードが完了していません。では何が順番におきるのか？

1. コンポーネントが初期化をして、getDataServiceのgetAll()を呼び出します
2. getAll()はObservableを返します
3. 返ってきたObservableに対してsubscribeをコールします
4. その後初めてリクエストがサーバーへ送られます
5. ngOnInit()の実行が完了

ここでお気づきかと思いますが、まだリクエストを送っただけなのでデータが返ってきてません。データが返ってくるときの処理を見ましょう。
上記の流れの後に、サーバーの処理が終わったら次の処理が行われます。

1.getAll()にデータが返されます
2.コンポーネントのsubscribe内のdatasに値が送られます
3.コンポーネント内で宣言したthis.datasにデータを格納します

つまりデータが確実に格納されるのはthis.datas=dataの行の後ということになので、簡単に同期的処理をさせるのであればそこで処理を行えば少なくとも予期してない処理を行わなくて済みます。

ただし基本的に非同期処理のメリットを潰すことになりますので、データのローディングを他の処理は待たなければなりません。他に良い方法があればコメントいただければ幸いです。


#####参考にしたサイト
https://stackoverflow.com/questions/46769042/subscribe-to-observable-is-returning-undefined
EUのデジタル法令作成支援システム LEOSを立ち上げてみた

# 法令作成の苦労

コロナ禍で明らかになったように、日本の社会は未だにハンコと紙、FAXで業務を進めており、大企業や政府、官庁は特にその傾向が強い。
例えば、次のような記事がある。

[働くママが終止符を打った霞が関の“伝統芸能](https://business.nikkei.com/atcl/opinion/15/221102/071800496/)

法令の作成は、多くが手作業で行われた。改め文や新旧対照表の作成も人手で行っていたが、プログラムを開発することで、人手で30時間かかった作業を、10秒に短縮した。


> 改め文や新旧対照表の作成は官僚の間で「霞が関の伝統芸能」と揶揄されていたのだ。このルールは見た目の美しさを追及する意味があったとみられるが、若手の官僚にとっては実質的な利点が理解し難い代物になっていた。

> 　ところが、新しいデータベースは、プログラム言語の変更により、改正部分を旧法令と自動で照合して、資料を自動作成してくれるようになったのだ。以前は30時間ほどかかることもあった作業が10秒程度で完了する。

# EUでは、LEOSという法律作成支援システムを作った

法令の作成現場では、上に上げたような人手に依存する作業が多く残っている。その苦労は海外でも同じようで、EUでは法令の作成を支援する、[LEOS](https://joinup.ec.europa.eu/solution/leos-open-source-software-editing-legislation)というシステムを作ったそうだ。

LEOSのドラフトのプレゼンテーションPDFでは、法律を作る際の苦労として

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26986/b3e9ba82-b3d2-9d03-c9a2-09dd17c6159c.png)

- 複雑なプロセス
- 数多くのステークホルダー
- 紙とデジタル両方の媒体の作成
- バージョン管理

を上げている。これは、日本の官庁でも同じ苦労をしているのだろう。

# LEOSを手元で立ち上げてみる。

LEOSを触ることで、本邦で法令作成支援システムを作るとしたらどのような機能が必要か一つの準拠軸になるんじゃなかろうかと考え、ローカルのマシンで立ち上げて触ってみることにする。

LEOS自体は、オープンソースで配られており、windowsで動くことを想定している。今回は最新の、`LEOS pilot 3.0.0` を手元で動かしてい見ることにする。LEOSはjavaで書かれている。

## LEOSのダウンロード

LEOSは[こちら](https://joinup.ec.europa.eu/solution/leos-open-source-software-editing-legislation/releases)でダウンロードできる。今回は最新の、 LEOS Pilot 3.0.0 をダウンロードした。

## LEOSの動かし方

LEOSの動かし方は、ダウンロードした、`LEOS Pilot 3.0.0.zip` の中に、 `README.txt` にあるように、` run-all.bat.` を起動すれば、4つのプロセスが立ち上がり、 http://localhost:8080/leos-pilot/ui へアクセスすれば、このような画面が見られる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26986/83f02815-3573-d291-7962-32083f8c92bf.png)

とかけば簡単そうだが、実際は色々苦労したのでその苦労した点を書いていく。

## LEOSを動かす上での注意点

### CPUは4コア以上

プロセスが立ち上がる前にコンパイルするため、CPUは4コア以上あると良い。２コアだと、遅かった。

### javaのバージョン

javaのバージョンは1.8固定になっている。java13で起動しようとしたらエラーで落ちた。

### JREのパスに注意

途中で
```
No compiler is provided in this environment. Perhaps you are running on a JRE rather than a JDK?
```

というエラーが出る場合は、JREのpathがJDK似同封のJREになっていないので、JDK付属のJREに切り替える。
oracleのインストーラーが  `commonpath` みたいなpathを勝手に追加するのでそれは、環境変数から削除する。
JAVA_HOMEの設定はなしでも行けた。

詳しくはこちら。

https://qiita.com/yuji38kwmt/items/658eeb02c596d252c30f
JREのパスは、JDKの中のパスにする。
https://qiita.com/takaaki4cards/items/639b4cd7544944d5e5c4


### mavenのライブラリにダウンロードに時間がかかる

mavenでのライブラリダウンロードに時間がかかるのでサービスがタイム・アウトする場合は何回か試す。

### jettyのタイムアウト

LEOS-pilot の起動時に、

```
Java.lang.Exception: Timeout scanning annotations
```
というエラーが出る場合には、

./modules/web/src/etc/jetty/jetty.xmlの

```
    <Call name="setProperty" class="java.lang.System">
        <Arg>org.eclipse.jetty.annotations.maxWait</Arg>
        <Arg>120</Arg>
    </Call>
```
maxWaitを120->240にしたら、timeoutせずに起動した。

### GCPのポートを開けるとともに、windowsのfirewallのポートも開ける。

外部から参照する場合、GCPのポートは、ヴァーチャルネットワークのファイアウォールルールに追加すればよいが、それと同時に、windows defered firewall のポートも開けないと外部からつながらない。普段linuxばかり触っていたので、windows defered firewallは盲点だった。

## デジタルの肩の上に乗る

法令作成は、大変な作業だ。ただでさえ大変なのに、改め文の作成なども人間がやるのはとても大変だ。せっかく、デジタル環境が進化したので、その肩の上に乗るのはとても大事だ。
flutter testで全体のカバレッジが正しく出力されない場合の直し方

flutterでテストを書いて`flutter test --coverage`でテスト実行して`genhtml`やcodecovでカバレッジを見たら「1ファイルしかテスト書いてないのに100%どういうこと!!???」というときの対処方法です。

# 原因
flutter（というかdart?)のcoverage生成のオプションではテストファイルから読み込んだテスト対象ファイルしかカバレッジの母数に含めてくれない様子。たぶん。


# 解決策
こちらのrepoにあるbashをclone, chmodしてproject rootで実行してから`flutter test --coverage`すれば万事OK。コマンドも丁寧にReadmeに書いてあります。
https://github.com/priezz/dart_full_coverage


もしlib配下のdartファイルを増やしたらもう一度シェルを叩く必要があります。

# スクリプトの仕組み
上記のbashスクリプトは `test/coverate_test.dart`というファイルを作り、その中に全てのlib配下のdartファイルを全てimportしてくれています。そして`main()`の中身を空にすることで「`coverage_test.dart`ではテストはしないが、テストファイルからいったんlib配下のdartファイルを全部読み込むことでカバレッジの母数に含めさせる」という状態を一発で作ってくれます。

具体的には以下のようなファイルが出来上がります。

````dart
(略)
import 'package:myapp/bloc/aaa_bloc.dart';
import 'package:myapp/bloc/bbb_bloc.dart';
import 'package:myapp/bloc/ccc_bloc.dart';
(略)
import 'package:myapp/widgets/aaa_page.dart';
import 'package:myapp/widgets/bbb_page.dart';
import 'package:myapp/widgets/ccc_page.dart';
(略)

void main() {}
```

たったこれだけですが、ちゃんとカバレッジがlib配下全体に対するデータになります。

以上、これで疑心暗鬼なままテストを書く心配が無くなりますね。