OmniAICreator/Qiita-1.07M huggingface dataset:
Macの言語設定を英語にしていたらモリサワパスポートが起動しなかった

## 結論

Macの言語設定を英語にしているとモリサワのフォントインストーラが起動できない。
言語を日本語にすると直る。

## 環境

| | |
| - | - |
| OS | macOS Big Sur |
| バージョン | 11.2 |
| モリサワのライセンス | MORISAWA PASSPORT アカデミック版 |
| インストーラのバージョン | 2.1.4 |

## 起きた事象

1. MORISAWA PASSPORT アカデミック版が今年でライセンス切れになるためアップデートを試みる
1. インストーラを起動しようとしたところ`Failed to open the menu.`とだけ出て何も進めない

## 試したこと

- [公式で紹介されている「環境ファイルの再構築手順」](https://www.morisawa.co.jp/support/faq/4549)に沿って`/Applications/MORISAWA`を削除してインストーラを再インストールする
    - →効果無し
- インストールしたフォントファイル自体を移動してみる
    - デスクトップに避難して、デフォルトでインストールされるフォルダを空にする
    - フォルダ自体も削除してみる
    - →どちらも効果無し
- 今の言語設定は英語なものの、インストールしたとき設定は日本語だったのを思い出し、戻す
    - →起動できた
Java-トランザクション制御

### トランザクション
トランザクションとは、一連の処理を一つのまとまった処理として扱うための論理的な単位です。同一トランザクションに属するSQL処理が複数ある場合

- すべてが成功して初めて処理結果を確定する(コミット)
- 途中で失敗したら、トランザクション実行前の状態に戻す(ロールバック)

データベースの処理結果を確定させることをコミット(commit)、実行前の状態に戻すことをロールバック（rollback）といいます。

### トランザクションの利用
Javaでは、JBDC(Java DataBase Connectivity)というデータベース操作専用のAPIが提供されています。
JBDCを用いてトランザクション制御を指示するには、Connectionオブジェクトを使います。

#### 1. setAutoCommit()-接続が確立した直後
JBDCのデフォルトでは、SQLが一つ送信されるたびに自動的にコミットされるオートコミットモードになっています。以下の宣言を行うことで明示的にトランザクション制御をできます。

- con.setAutoCommit(false); : 自動コミットモードの解除  

そして、以下の宣言を行うことで自動的にコミットさレルオートコミットモードに戻すことができます。

- con.setAutoCommit(true); : 自動コミットモードの設定  

#### 2. commit-一連のSQLを全て送信し終わったとき
一連ののトランザクションに必要なSQL文を全て送信したら、commitを呼び出してコミットします。

- com.commit(); : 送信済みの処理要求の確定(コミット)

この呼び出しにより、前回のcommit()以降に送信された全てのSQL要求が一つのトランザクションとみなされ、実行結果が確定される。

#### 3.rollback()-途中で異常を検知したとき
複数のSQL要求を送信している途中で異常を検知したらり、何らかの理由で処理をキャンセルしたい場合、rollback()を使います。

- con.rollack(); : 送信済みの処理要求をキャンセル(ロールバック)

この呼び出しにより、commit()以降に送信されたすべてのSQl要求が全てロールバックされます。また、プログラム中で明示的にrollbackを呼び出さなくても、データベースの接続が途中で切断された場合やJavaプログラムまたはデータベースの強制終了によって最終的にcommit()が発行されない場合、データベースは自動的にロールバックを行います。

#### サンプルコード
```java
import java.sql.*;


public class Main {
    public static void main(String[] args) {

        try {
            // JDBCドライバーの有効化
            Class.forName("org.h2.Driver");
        } catch(ClassNotFoundException e) {
            e.printStackTrace();
        }

        Connection con = null;
        try {
            // データベースの接続
            con = DriverManager.getConnection("jdbc:j2:~/rpgdb");  // JDBC URLを指定
            // オートコミット解除
            con.setAutoCommit(false);
            
            /** SQL発行処理(省略) */

            // トランザクションのコミット
            con.commit();
            // SQLExceptionが発生した場合の処理
        } catch(SQLException e) {
            try {
                // トランザクションのロールバック
                con.rollback();
            } catch (SQLException e2) {
                // スタックトレースを出力
                e2.printStackTrace();
            }
        } finally {
            if(con != null) {
                try {
                    // オートコミット有効化
                    con.setAutoCommit(true);
                    // データベース接続の切断
                    con.close();
                } catch(SQLException e3) {
                    // スタックトレースを出力
                    e3.printStackTrace();
                }
            }
        }
    }
}



```
【AWS】CloudFront＋S3でコンテンツを即時反映する方法

# はじめに
静的および動的なウェブコンテンツ (.html、.css、.js、イメージファイルなど) を**Amazon S3**に低コストかつ安全に格納し、**Amazon CloudFront**を用いて効率よくコンテンツを配信するという設計は割と良くあるのではないでしょうか。
しかし、効率よくコンテンツを配信してくれる反面、即時差し替えたいファイルがあっても**「キャッシュのせいでなかなか反映されない」**ということが起こります。
AWSの公式にも下記のように記載されています。

>デフォルトでは、CloudFront は Amazon S3 からのレスポンスを 24 時間 (86,400 秒間のデフォルト TTL) キャッシュしています。リクエストが エッジロケーションに到着してから24 時間以内に Amazon S3 を提供した場合、Amazon S3 のコンテンツを更新したとしても、CloudFront はキャッシュされたレスポンスを使います。

この記事では、そんなキャッシュ問題を簡単に解消する方法を紹介します。

# 対処方法
即時差し替えたいファイルがあっても**「キャッシュのせいでなかなか反映されない」**・・・それならば**「CloudFrontのキャッシュを削除してしまえばいいじゃん」**という方法の紹介です。

早速キャッシュの削除方法を説明します。

## 手順１
マネージメントコンソールで **「CloudFront Distributes」**を開き、キャッシュを削除したいサイトの**「ID」**をクリックします（ディストリビューションの選択）。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1203022/62e70f98-4f32-8faa-1c2d-c094c25330ea.png)

## 手順２
**「Invalidations」**タブを選択し、**「Create Invalidation」**ボタンをクリックします。
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1203022/e439f831-6972-4fa7-5ed0-bfad2d698701.png)

## 手順３
モーダルが表示されるので、**「Object Paths」**のテキストボックスにキャッシュを削除したいファイルのパスを入力します。
私はまとめてキャッシュを削除したいので常に**「/\*」**（すべてのキャッシュを削除）と指定していますが、全削除はリスクがありそうなので「/css/\*」のように部分削除することをオススメします。
**「Invalidate」** ボタンをクリックするとキャッシュの再作成が開始されます。
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1203022/934b9c99-7e82-a8f7-8299-313a8ef4db27.png)

## 手順４
数分待ちます。
Statusが**「Completed」**となればキャッシュの再作成が完了しています。
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1203022/5b1f7201-aeb0-c07d-5570-5d16ef4b49b0.png)

以上です。
AWSの公式ドキュメントに別の対策が載っていたのでそちらもリンクを置いておきます。
（今回紹介したキャッシュの削除の方が簡単だとは思います。）
 [CloudFront が、Amazon S3 から古いコンテンツを提供し続けるのはなぜですか?](https://aws.amazon.com/jp/premiumsupport/knowledge-center/cloudfront-serving-outdated-content-s3/)
【Flutter】AppBarの戻るアイコン（leading）をカスタマイズしてみる

##本記事で行うこと。

1. 戻るアイコンを削除する
1. 戻るアイコンの代わりに、テキストボタンを設置する
1. テキストボタンのレイアウトを解消する

##1. 戻るボタンを削除する

Flutterのアプリは、画面遷移を行うとAppBarに戻るアイコンが自動的に設置されます。

![dd775447757511b2a00e3c6c22cdde24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463548/9db75894-027e-0554-4d2c-986a8c155ab2.png)

この自動的に設置された戻るアイコンを一番簡単に削除する方法は、
**automaticallyImplyLeading**を**false**に設定することみたいです。

### **automaticallyImplyLeading** とは？

AppBarの先頭がnullの場合、左矢印（戻るアイコン）を自動的に付与するよ。というものみたいです。
つまりleadingを設定してあげれば、**automaticallyImplyLeading** のパラメータは無効になる、ということだと思います。

[ソースはこちら](https://flutteropen.gitbook.io/flutter-widgets/widgets-07-or-appbar#automaticallyimplyleading)

### 実際に削除してみる

**automaticallyImplyLeading** を**false** に設定します。

```遷移先のスクリーン.dart
AppBar(
  automaticallyImplyLeading: false,
),
```

動作確認してみましょう。

![7ca13b2b468fc7507651abc3a0c93870.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463548/b15a0242-4e70-3888-0747-deda1a321084.png)

これで、戻るアイコンを削除することができました。


##2. 戻るアイコンの代わりに、テキストボタンを設置する

**automaticallyImplyLeading**とは？で確認しましたが、
leadingを設定してあげるとAppBarの先頭はnullではなくなり、代わりとなるウィジェットを設置することができます。

今回は、**"キャンセル"**というテキストのテキストボタンを、戻るアイコンの代わりに設置してみようと思います。

### まず、leadingを理解する

[Flutterの公式ドキュメント](https://api.flutter.dev/flutter/material/AppBar/leading.html)を見てみると、

「A widget to display before the toolbar's title.」

AppBarのタイトルより前にウェジェットを設定できるよ。的なことが書いてあるみたいです。
つまり、AppBarの一番左に何かを設置してあげたいときは、leadingを使うという認識で良いのかなと思っています。

### 実際にテキストボタンを設置してみる

```遷移先のスクリーン.dart
 AppBar(
   leading: TextButton(
      child: Text(
         'キャンセル',
         style: TextStyle(
           color: Colors.white,  //文字の色を白にする
           fontWeight: FontWeight.bold,  //文字を太字する
           fontSize: 12.0,  //文字のサイズを調整する
          ),
      ),
  onPressed: () => Navigator.of(context).pop(),
  ),
```

動作確認してみましょう。

![900751049660727aef6c38ccd6fb737c.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463548/385adb74-8816-f7fc-f5ef-20ff2f07f151.png)

無事、**"キャンセル"**のテキストボタンを表示することができました。
遷移の動作も問題ないようです。
ですが、キャンセルが不自然に改行されてしまい、レイアウトが崩れています。
次は、レイアウトを調整していきます。

##3. テキストボタンのレイアウトを解消する

このレイアウト崩れは、leadingのwidthが初期値より超えてしまったため、
折り返し表示されてしまっていることが原因だと思います。
leadingWidth を適切に設定することで、レイアウト崩れを解消することができました。

###  leadingのレイアウト崩れを解消する。 

```遷移先のスクリーン.dart
 AppBar(
   leadingWidth: 85,  //leadingWidthを設定する
   leading: TextButton(
      child: Text(
         'キャンセル',
         style: TextStyle(
           color: Colors.white,  //文字の色を白にする
           fontWeight: FontWeight.bold,  //文字を太字する
           fontSize: 12.0,  //文字のサイズを調整する
          ),
      ),
  onPressed: () => Navigator.of(context).pop(),
  ),
```

動作確認してみましょう。

![b15e83c8a2ba70472ce1d04b81c320f6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463548/82b3da2a-05a2-6c9a-9d33-28e33e90ee3a.png)

無事、レイアウト崩れが解消されました。
ElixirでURLを書く際に%URI{}を使う

`%URI{}`を使う。

```elixir
entry_id="1"

url =%URI{
  host: "subdomain.elixir.com",
  path: Path.join("/entries", entry_id),
  port: 4000,
  scheme: "http"
}
```

上述のように定義をする。
次に、文字列にしてみるとURLを確認することができる。

```elixir
iex()> url |> to_string()
"http://subdomain.elixir.com:4000/entries/1"
```

* 公式： https://hexdocs.pm/elixir/URI.html


# 補足

urlはこんな風になっている。

```elixir
iex(21)> url =%URI{
...(21)>   host: "subdomain.elixir.com",
...(21)>   path: Path.join("/entries", entry_id),
...(21)>   port: 4000,
...(21)>   scheme: "http"
...(21)> }
%URI{
  authority: nil,
  fragment: nil,
  host: "subdomain.elixir.com",
  path: "/entries/1",
  port: 4000,
  query: nil,
  scheme: "http",
  userinfo: nil
}
```
PHPをherokuでデプロイする！(3)データベースのインポート

#はじめに
PHPをherokuでデプロイする方法、今回はローカル環境で作ったデータベースの引継ぎとしてインポートする方法を書いていきます！

#データベースをインポートするための準備
まずはローカル環境で作ったデータベースを引き継ぐ形でデータベースを作成していきます。前回でcleardbのアドオンを用いてMySQLが利用できるようになっていると思います。PHPではPHPMyAdminでデータベースの作成や編集、データ内容の確認ができますが、あくまでこれはローカル環境のみとなっています。herokuでデータベースをインポートするために便利なのが、「MySQL Workbench」です。

##MySQL　Workbenchのインストール
MySQL WorkbenchはMySQLが公式に提供しているアプリで、GUIで操作しやすいのが特徴です。ダウンロードはこちらです。
https://www.mysql.com/jp/products/workbench/
「ダウンロードはこちら」ボタンを押し自分のOSを選んでダウンロードし、インストールを進めましょう。ダウンロードする前にユーザー登録を求められますが、「No thanks, just start my download.」が下に表示されているのでそれを押すとユーザー登録なしにダウンロードできます。

なお、最新バージョンだとインストールしたあとmacでは動作しないことがあったようです。その場合はArchivesボタンを押して、8.0.19をダウンロード、インストールすると確実に動作します。インストール後表示にしたがってアイコンをドラッグするとmacであればApplicationsフォルダーにコピーされます。

##MySQL Workbenchの設定
起動させると
![Work1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/891157/f9850c37-54bd-e0ff-5373-8b64719a18ba.png)
こんな画面になります。MySQLConnectionsの隣にある＋のボタンを押すとデータベースの作成ができます。

![work2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/891157/7632a655-303c-338d-968a-a1debcff09db.png)
ここで入力していくのはherokuのデータベースの情報です。(1)の中でも紹介した、herokuのデータベース情報を元に入力しましょう。herokuのデータベース情報はターミナルでデプロイしたいアプリにアクセスして以下を入力してください。

```
heroku config | grep CLEARDB_DATABASE_URL
```

ここで表示されるのは、CLEARDB_DATABASE_URL: mysql://ユーザー名:パスワード@ホスト名/データベース名?reconnect=trueとなります。
これに基づいて先ほどの画像の内容を入れていきましょう。

まず、「connection　name」ですがこれはこのデータベースを管理する上での名前なので、好きに名付けて構いません。「conecction Method」はそのままの設定で進めましょう。
Hostnameは、先ほどherokuconfigで確認したホスト名を、Usernameも確認したユーザー名を入れましょう。Portはそのままで構いません。
そしてパスワードは「Store in Key chain」ボタンをクリックすると入力できます。入力内容が確認できないので間違いないように気をつけてください。
「Default Schema」にはデータベース名を入れましょう。

全て入れたらTest conecctionボタンを押してみましょう。そうすると問題なければ「Successfully made the MySQL connection」と表示されます。もし問題がある場合は入力内容に間違いがないかみていきましょう。これで接続できていれば、データベースをインポートする準備ができています！

#データベースのエクスポート
次に、インポートするためにPHPMyAdminからデータをエクスポートします。
PHPMyAdminにアクセスし、エクスポートボタンを押して、エクスポート方法で詳細を押すと、データベースの選択ができるので、エクスポートしたいデータベースを選びましょう。
出力は必ず「出力をファイルに保存する」を選びましょう。これでないとインポートできません。その他はそのままで問題ないので、実行を押すとファイルがダウンロードされます。

#データベースのインポート
それでは、いよいよインポートの作業に入ります！MySQL workbenchを再び開くと、先ほど追加したデータベースが表示されていると思います。ボタンを押すと少し接続の待ち時間があり、その後画面が開きます。

![Work3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/891157/cec4cc11-b538-4370-4945-319c70d16b36.png)
このような画面になったら、Data Import/Restoreを開きましょう。

![work4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/891157/bff6c382-5e94-917f-805f-1291cb9356c5.png)
そうするとこんな感じの画面になるので、「Import from Self-Contained File」を選択し、先ほどエクスポートしたファイルを選びましょう。また「Default Target Schema」ではherokuのデータベース名を選択しましょう。
そして「Import progress」を選択し、「Start Import」を押せばインポート完了です！

##もしうまくいかない時は・・・
ちなみに、もしインポートできない場合は、データベース名をコメントアウトし、テーブル名をのみを残すような形で編集するとうまくいくことがあります！ちなみにエクスポートしたデータベースは右クリックで「このアプリケーションから開く」を選択し、VScodeなどプログラミング用のアプリケーションを開けば内容を見ることができます。

次回はいよいよ最終章として、デプロイに必要なcomposerのインストール、そしてデプロイの方法について書いていきます！
ポートフォリオ作成記録②（画面遷移図編）

前回の記事の続きです[作成記録①はこちら](https://qiita.com/engineer_PT/items/ee786e3b1267cc53acbc)

<h2>画面遷移図作成</h2>
今回は各画面の大まかなレイアウトを画面に落とし込みました。

ツールは[こちらのサイト](https://web-kanji.com/posts/wire-frame-tools)を参考に決定。

私は``AdobeXD``を採用。理由としては下記3つです。

<b>・共有が簡単</b>
<b>・無料で使える</b>
<b>・デザイナーさん達もよく使っている（らしい）</b>


さっそくXDを覚えるため本を買ったのですが、、全く使っていません。笑

画面遷移図作成に当たって最低限必要な操作はYouTubeの初心者用の講座で何とかなりました。

・参考にした動画（合計時間:２０分）

https://youtu.be/6crObxwpgrI

https://youtu.be/IPuOEPle7Nk


デザイナー志望の方であれば足りないですが、エンジニア志望の方が使うにはリンクの動画の内容で充分だと思います。

ちなみに私が作成した画面遷移図がこれ
![スクリーンショット 2021-03-15 0.39.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693783/1207d25c-d405-e9d0-5cd0-bf107e9a2210.png)


これは良くないですね。笑
プロジェクトだったらチームで画面遷移図は共有すると思いますが、これだと作成した本人以外どうなってるのかがわかりずらい…
一応、矢印はボタンを押した時にどこの画面に遷移するのかを示しています。

こちらに関しては実装後に要修正。
後半日記みたいになってしまいました。
今回はこれで終わりです。
AIには強いAIと弱いAIがある？！実現できてるAIとまだ困難なAIを解説

![cat-5496162_1280.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135794/bc03bd37-9f67-16f9-726b-01730ae0e994.jpeg)

(ブログ更新)

[AIには強いAIと弱いAIがある？！実現できてるAIとまだ困難なAIを解説](https://off.tokyo/blog/strong-ai-week-ai/)

こんにちわ。

人工知能(AI)と言えば昨今めちゃくちゃ話題になっていますよね。

ソフトバンクの孫正義さんはビジョンファンドと銘打ってAIカンパニーに特化したファンドをやっていますし、

テスラなどの自動運転の電気自動車が世界ではバカ売れしていたりしています。

でも、世の中には、まだ実現が不可能な状態にあるAIというのが存在します。

今日の記事では、実現出来ているAIと、まだ夢物語の途中にあるAIの違いを解説します。

## 弱いAIは既に実現され我々の社会の役に立っている


まず、弱いAIとは何かと申しますと、

例えば音声認識とか、画像認識による人工知能のことを言います。

自然言語を音声のまま受け取って解釈したりですとか、

カメラから人の顔や物体の特徴を見分けたりする技術です。

これらの人工知能の技術は、

例えば自動運転の車に応用されたり、スマホに導入されて声をかければ友達や家族に電話ができるとか、

その他には自動翻訳のソフトなんかにもなったりしています。

既に世の中で製品として実用化されて、我々も毎日使ってるテクノロジーもありますよね。

これらの人工知能が可能になったのは、

IT革命により無数のデータがインターネットに集まったことや、

ハードウェアの性能が爆発的に向上して安く多くの計算ができるようになったことがあるわけですが、

このような世界になっても、まだ実現ができないのが強いAIです。


## 強いAIとはまさしくドラえもんを作り出すこと


弱いAIは、専門用語では特化型AIと呼ばれているのですが、

一つの動作において様々なデータからパターンを自分で学習して、

(続きはブログで)


[AIには強いAIと弱いAIがある？！実現できてるAIとまだ困難なAIを解説](https://off.tokyo/blog/strong-ai-week-ai/)
Railsチュートリアル第3章　ざっくり何やったか備忘録

#経緯
Railsチュートリアルを1日１章分以上終わらすことを目標にしている
今回は第3章でざっくり何やったかを自分用に残しておく

#概要
ほぼ静的なページの作成を
新規プロジェクト「sample_app」を通して学習

Gemfile更新。``--without production``オプションを使って、
production環境でしか使わないgemはインストールしない。
Git初期化。READMEを書き換えてコミット。
sample_appのリモートリポジトリ作成し、push。
第1章や第2章と同様に、hello, world」の手順に従って
コミット、プッシュ。　herokuもcreate -> push!


静的なページの生成

```
$ git checkout -b static-pages
$ rails generate controller StaticPages home help
```
home アクションと helpアクションを生成した。

``` config/routes.rb
Rails.application.routes.draw do
  get  'static_pages/home'
  get  'static_pages/help'
  root 'application#hello'
end
```
###railsチュートリアル記載の短縮系一覧
| 完全なコマンド | 短縮形 |
|:-:|:-:|
| $ rails server  | $ rails s  |
| $ rails console  | $ rails c  |
| $ rails generate  | $ rails g  |
| $ rails test  | $ rails t  |
| $ bundle install  | $ bundle  |
| $ bundle destroy  | $ rails d  |


#テスト駆動開発のサイクル

- 失敗するテストを最初に書く
- 次にアプリケーションのコードを書いて成功させる（パスさせる）
- 必要ならリファクタリングするのように進む。

多くのテストツールでは、テストの失敗を``red``、成功したときを``green``で表す。

```test/controllers/static_pages_controller_test.rb
省略
  test "should get home" do
    get static_pages_home_url
    assert_response :success
  end
省略
```	
get -> GETリクエストをhomeアクションへ送信
response:success -> リクエストに対するレスポンスは［成功］になるはず

##RED

```
$ rails test
3 tests, 2 assertions, 0 f##ailures, 1 errors, 0 skips
```

##GREEN
```
$ rails test
3 tests, 3 assertions, 0 failures, 0 errors, 0 skips
```
【超超初心者向け】anacondaとVSCodeでPython勉強始める前の環境構築

# 概要

　**まずこの記事は、これからPythonの勉強を始めたい人向けの記事です。**

　VSCodeは既にインストールされている事を前提としています。


# anacondaをインストール

anacondaとはPython使用するにあたって必要なパッケージが色々含まれている仮想環境らしいです。

https://www.anaconda.com/products/individual

まずこちらからダウンロード。

パッケージがインストールされたら、画面に出てくる案内に沿ってインストール。



# インストールが終わったら

```
python
```

と打てば
　![スクリーンショット 2021-03-15 0.15.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567748/92f91fc6-b2df-23d0-1c23-c83a59f21ce8.png)


こんな感じでpythonが使用できる事が確認できました。


warningに出ている通りpython3にするためには

```
python3
```

と打てばメジャーバージョンが3が使用できました。

この辺りはPATHを通して好きなバージョンを使用してください。




# anaconda-Navigator

先程anacondaをインストールした時にアプリに勝手に追加されているので開く。



![スクリーンショット 2021-03-15 0.20.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567748/280a17c0-84c2-5d81-dba9-eff075175c0a.png)

キャプチャのようにcreateから好きな名前のプロジェクトを作成する。

また戻ってくるので開いたままにする。


# VSCodeの設定をする

拡張機能で`Python`は入れておきましょう！

VSCodeでworkspaceを作成するなりして、空のフォルダを作成する。


`Command + Shift + P`

をして上のバーに検索窓を出して

`workspace` と打つと



![スクリーンショット 2021-03-15 0.25.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567748/db0f03d8-b9c9-c0d7-3f0c-7109d69b4082.png)



workspaceのsettingが開けるので開いておく。



# anaconda-Navigatorに戻る

先程自分で作ったプロジェクトの名前の右側に矢印が出ているのでそこをクリック。


そうすると
![スクリーンショット 2021-03-15 0.27.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567748/ba2aa5e1-8ece-01f6-3937-9125008f8fa8.png)

こんな感じで表示されると思うので

`Open Terminal`をクリック



開かれたターミナル上で


![スクリーンショット 2021-03-15 0.30.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567748/3c7163b9-a98b-fc21-6926-58fd1cecefaf.png)

`conda info -e`

と打つ。


そうすると、作ったプロジェクト一覧のPATHが表示されます。


![スクリーンショット 2021-03-15 0.31.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567748/dd31a571-de2d-1fad-dc7a-81e86f12af2a.png)

この自分で作成したプロジェクトのPATHをコピーします。



# VSCodeに戻る


先程開いた`workspace.json`


```
"settings": {
　"python.pythonPath": "/Users/user_name/opt/anaconda3/envs/プロジェクト名"
}
```
と追加する。



これでめんどくさい系の設定は終わりです！



あとは先程作った空ディレクトリに

`sample.py`みたいに適当なpythonファイルを作成してあげます。


```
print('hello world')
```

と書いて、保存。


右クリックで
![スクリーンショット 2021-03-15 0.36.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567748/51aa0322-8021-4c43-6253-9a661cb320d6.png)

このファイルをターミナルで実行！
をクリック。


そうするとVSCodeのターミナルで
hello worldと出るはずです。

ちなみに、VSCodeの自分のプロジェクトのrootに入った状態のターミナルで

`python sample.py` or `python3 sample.py`

と打っても表示されます！




# さいごに

pycharmがPythonやるには簡単だし便利だとは思うけど有料なのが。。
とか
重い！
とか色々あると思います。

私は他の言語で開発するときもVSCodeヘビーユーザーなので、python開発時もあえてVSCodeを使用しています。


これを使わないといけない！！この言語には絶対これ！！！
なんて事はないので、自分の好きな環境で開発を楽しみましょう！
FuelPHPインストール

MacOS,MAMPを利用前提。
[MAMPのインストール方法](https://qiita.com/machiryu/items/64e863833205a7c45ccb)


# コマンドラインからのインストール

oilをインストールする。

```
$ curl https://get.fuelphp.com/oil | sh 
```
管理パスワードを聞かれるので、入力する。

ルートディレクトリで、早速oilコマンドを使ってプロジェクトを作成する。
初oil。

```
$ mkdir work
$ cd work
$ oil create myproject
composer create-project fuel/fuel myproject
Creating a "fuel/fuel" project at "./myproject"
Installing fuel/fuel (1.8.2)
:
:
:
31 package suggestions were added by new dependencies, use `composer suggest` to see details.
Generating autoload files
3 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
```
ApacheからインストールしたFuelPHPにアクセスできるようドキュメントルートにシンボリック設定する。

```
$ cd /Applications/MAMP/htdocs
$ ln -s ~/work/myproject/public myproject
```

完了後、`http://localhost/myproject`にアクセスし、下記画面が表示されればインストール完了。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1007978/902a719a-4149-d3bb-0f20-cb8fae3d1ede.png)

# 参考
https://mynavi-agent.jp/it/geekroid/2017/10/fuelphp2.html
【Webフォント】日本語Webフォントがすぐに表示されない場合の対処法

# はじめに
私たちが普段見ている様々なサイトでデザイン性を高めるために**「Webフォント」**が使用されています。
Webフォントを使用するメリットはたくさんあり、**「どのブラウザで見ても同じ表示になる」**や**「文字を画像で表示しないためSEOの効果を維持できる」**などがあげられます。
しかし、メリットの反面デメリットもあります。WEBフォントの読み込みが遅く、最悪の場合**「サイトが表示されてから数秒の間文字が表示されない」**なんていう事象が発生する可能性があるのです。
特に日本語は漢字・ひらがな・カタカナと英語圏のアルファベットに比べると桁違いに文字が多いため、フォントデータのサイズも大きくなってしまいます。
今回はWebフォントのメリットを享受しつつデメリットを打ち消す方法を紹介します。
※一般的な方法なので「そんなの当たり前じゃん」と思う方もいると思いますがご了承ください。

# 確認方法
「目視だとわからない・・・。」という方はGoogleのPageSpeed Insight(ページスピードイン)等のパフォーマンス測定サイトで確認してください。
※PageSpeed Insightの使用方法は割愛します。

以下のような表示になる場合は**「サイトが表示されてから数秒の間文字が表示されない」**可能性があります。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1203022/20053af4-13a8-ad16-b40c-3aadfb7b4989.png)

# 対処方法
**「Webフォントが読み込まれるまで、とりあえず通常のフォントで文字を表示させておく」**という設定をします。
基本的に**「font-display: swap;」**の指定をするだけで完了です。
では具体的に説明します。

## １.一般的なWebフォントの場合
font-face内に**「font-display: swap;」**の指定をするだけです。
※下記コードの一番下

```
@font-face {
  font-family: 'hogefont';
  font-style: normal;
  font-weight: 400;
  src: url(https://fonts.hoge.com/hoge/hoge/hoge.woff2) format('woff2');
  font-display: swap;
}
```
## ２.Googleフォントを使っている場合
Googleフォント（Google Fonts）はGoogleが提供しているWebフォントサービスです。
すべて無料で利用可能で、かつ商用利用にも対応しています。日本語フォントも豊富なため、Webフォントを利用する方はまずGoogleフォントを選択肢の一つに入れるのではないでしょうか。Googleフォントでの指定方法も紹介します。

Googleフォントを使っている場合は、埋め込みタグのURLに**「&display=swap」**を追加してください。

```
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@100&display=swap" rel="stylesheet">
```

デフォルトの埋め込みタグは下記図の赤枠のように**「&display=swap」**が付いた状態ですが、ブログ等で紹介されているタグには付いていないことも考えられるため注意してください。
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1203022/025e1587-8553-3edc-d8ff-469804bf7d64.png)

# 再度パフォーマンス測定サイトで確認
対応後にパフォーマンス測定サイトで確認し、以下の表示になっていることを確認してください。
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1203022/54c1a1e5-b088-2f9d-9ac7-9d6a5f5bb163.png)

先程は赤い三角印だったものが緑の丸になっています。
※GoogleのPageSpeed Insightで確認しています。

これでWebフォントのメリットを享受しつつデメリットを打ち消すことが出来ました。
VSCodeで拡張を改造してtypescriptとsvelteで分かったことのメモ

　少し前に作ったsvelteファイルのインスタントビュワーをもうちょっと改造することで、TypeScriptとか、svelteの動作なんかのことがちょっとわかったので、自分用のメモ書き。
　ちなみに、興味のある方にですが、前回作ったsvelteの簡易ビューは、改造して子コンポーネントも参照してスタイルもスコープが聞くようにしました。コンポーネント内の最後のタグしか表示しないバグも修正済みです。またエディターのコンテキストメニューにも追加して、そこから開いた場合はエディターの内容で作成し、ファイルエクスプローラーのコンテキストメニューから開いた場合はファイルの内容で表示する様にしました。

## TypeSriprtではrequireは使わない方がいい？
　まだ使い始めたばかりでよくわからないのですが、VSCodeで拡張機能を作っていると、importの場合はタイプセーフが強要され、インテリセンスも有効に働くのですが、requireだとany型になってしまってタイプセーフにならず、インテリセンスも動作しなくなります。requireは使わない方がよさそう。

## TypeScriptでimportを使うとjavascriptのパッケージはエラーになる
　拡張機能でDOM操作をしようとimportで「jsdom」を組み込んで使うと型宣言のエラーが出る。エラーメッセージに従って「@types/jsdom」をインストールすることで型定義のファイルがインストールされる。どうやらこれが基本のようですね。javascriptのパッケージを使うために多くのパッケージの型定義を@typesに集めてくれているみたいですね。これが無ければ自分で作るしかないみたいですし、ありがとうございます。

## VSCodeの拡張機能のデフォルトではDOMのライブラリが参照されていいない
　「@types/jsdom」のおかげで「jsdom」事態はタイプセーフになりインテリセンスも動作したのですが、DOM関連の型定義が参照されていない。これも「@types」シリーズかと思って探したけれど見つからない。結局「tsconfigjson」の「lib」に「dom」を追加することが必要だった。まあ、拡張機能の開発で基本はDOMの参照は不要なんでしょうけど、ネットで探してもなかなか見つからなかった。

## svelteのコンポーネントはスクリプトとスタイルシート以外の全てのタグだった
　これはチュートリアルをちゃんとやらなかった自分があほなだけ。拡張機能でビューに組み込むときにスクリプトとスタイルとそれ以外のタグが一つしかないと勘違いして作ってしまったので、複数ある時に最後の一つしか表示していなかった。おかげで作った拡張機能は最後のタグしか出ていない。あほじゃ！

## VSCodeではタスクの「watch」をうまく使うのがいいみたい
　Visual Studioで作っていると、あまり考えずにデバッグとすれば勝手にコンパイルしてサーバーを起動した上にブラウザを開いて初期ページの表示まで勝手にできてしまう。同じようにしようと考えたが、どうもVSCodeのデバッグではちょっと小細工する必要がありそう（とりあえず見つけたけど...）。それよりは、基本「watch」オプションを利用してデバッグはブラウザをラウンチするのがよさそう。少なくともscssの変換は変換タスクをwatchにしておけば、保存されたときに勝手に変換される。トランスパイルもそうした方がいいのだろうか。ただ、毎度トランスパイルする場合、規模が大きくなったらどうなるのか心配。
　ただ、トランスパイルをwatchしておけば、ファイルを変えてもすぐに表示できるし試しに作ってみた簡易表示は必要ないかなぁー。

## やっぱりjavascriptもtypescriptも環境構築からめんどくさい 
　正直VisualStudioでC#使ってると、初期の環境構築で悩むことがほとんどない。新しいテンプレートを試すときはさすがに色々と悩むけれど。やっぱりオープン系の開発はいろいろとめんどくさいなーと感じました。typescriptの型定義も、柔軟性に無理に対応するために記述が非常に複雑で面倒だと思う。クラスが動的に定義できる方が便利か、静的な片づけを基本とする方が扱いやすいのか、双方のメリットデメリットがあるなと思うのでした。まあ、web系ではインタフェースにいろいろな形式のデータをやり取りすることが多いので、静的に型定義をすることが大きなデメリットになるのはわかるんだけど...。

　まあ、フロントエンドと言われる部分の開発はまだあまり慣れていないので、これからもいろいろと試してみます。
CCNP取得のモチベーション

### CCNP3種取得をめざして　Day 0


初めまして。つよつよインフラエンジニアを目指している者です。

今回は"CCNP取得をめざして"シリーズ初回ということで、CCNP取得を志すに至った経緯をお話させて頂きます。


####1.給与があがる
シンプルに給料があがることが一番の動機です笑
生活費を支えるために少しでも給与がアップさせたい！というのが大きいです。

####2.市場価値を上げたい
私がネットワークの運用・保守の現場に携わる者ということもあり、エンジニアとしての市場価値を上げたい！が2番目にくる理由になっています。

####3.技術に興味がある
現在CCNAは取得しているのですが、CCNAの勉強をしている際に、より深くCiscoの機器やネットワーク構築に関する知識を知りたい！と興味を持ったことがきっかけです。

####4.目に見える成果が欲しい
自分が勉強したことや、努力したことを評価される形に落とし込みたい！という思いがあります。
何よりも実務経験が重んじられる業界ですが、持っていないより持っている方が良いとは思うので、取得を目指しています。


###まとめ
今回は私が「なぜCCNPの取得を目指すのか」というところをメインにお話しさせて頂きました。
動機はエンジニアとして不純なモノが多いかと思いますが、取得に向けて頑張っていきたいと思っています。


また、初めてのQiitaへの投稿というところもあり、至らぬ点も多いとは思いますが、少しずつ改善していけたらなと思います。


今後はCCNPの勉強内容をアウトプットしていく場として、Qiitaを使わせて頂こうかなと思います。

それでは失礼致します。。
【Ruby】クラスとインスタンス

# はじめに
クラスとインスタンスに苦手意識があり、復習を兼ねて記事に残しておこうと思い執筆しました。
飲み物を売っているお店を例にして、ターミナルで以下のように出力できるようにしたいと思います。

```:ターミナル
いらっしゃいませ！
水は100円です
コーラは150円です
モンスターは200円です
```


# クラスの定義
まずクラスを定義します。
クラスの定義は以下のように行います。

```Ruby
class クラス名

end
```

クラス名をDrinkとします。
大文字から始めるようにします。

```Ruby:drink.rb
# クラスの定義
class Drink

end
```
# インスタンスの生成
newメソッドを使ってインスタンスを生成します。

```Ruby
変数名 = クラス名.new
```

この後に定義するinitializeメソッドに情報を渡せるように引数も記述します。

```Ruby:drink.rb
# クラスの定義
class Drink

end

# インスタンスの生成
water = Drink.new("水", 100)
cola = Drink.new("コーラ", 150)
monster = Drink.new("モンスター", 200)
```

# initializeメソッドの定義
initializeメソッドを定義します。
newメソッドの引数を(name, price)で受け取り、＠nameと＠priceにそれぞれ代入しています。

```Ruby:drink.rb
# クラスの定義
class Drink

# initializeメソッドの定義
  def initialize(name, price)
    @name = name
    @price = price
  end

end

# インスタンスの生成
water = Drink.new("水", 100)
cola = Drink.new("コーラ", 150)
monster = Drink.new("モンスター", 200)
```

# クラスメソッドの定義
クラスメソッドの定義はクラスに以下のような記述をします。
メソッド名の前にself.を付けます。

```Ruby
def self.メソッド名

end
```

putsメソッドを使い、「いらっしゃいませ！」と出力できるようにします。

```Ruby:drink.rb
# クラスの定義
class Drink

# クラスメソッドの定義
  def self.welcome
    puts "いらっしゃいませ！"
  end

# initializeメソッドの定義
  def initialize(name, price)
    @name = name
    @price = price
  end

end

# インスタンスの生成
water = Drink.new("水", 100)
cola = Drink.new("コーラ", 150)
monster = Drink.new("モンスター", 200)
```

# インスタンスメソッドの定義
インスタンスメソッドの定義はクラスの中に以下のように記述します。

```Ruby
def メソッド名

end
```

各インスタンスに対して「【名前】は【価格】円です」と出力していきたいので、putsメソッドを使用します。

```Ruby:drink.rb
# クラスの定義
class Drink

# クラスメソッドの定義
  def self.welcome
    puts "いらっしゃいませ！"
  end

# initializeメソッドの定義
  def initialize(name, price)
    @name = name
    @price = price
  end

# インスタンスメソッドの定義
  def introduce
    puts "#{@name}は#{@price}円です"
  end

end

# インスタンスの生成
water = Drink.new("水", 100)
cola = Drink.new("コーラ", 150)
monster = Drink.new("モンスター", 200)
```

# クラスメソッドとインスタンスメソッドの呼び出し
最後に、定義したクラスメソッドとインスタンスメソッドを呼び出します。
書き方は以下の通りです。

```
# クラスメソッドの呼び出し
クラス名.メソッド名

# インスタンスメソッドの呼び出し
インスタンス名.メソッド名
```

```Ruby:drink.rb
# クラスの定義
class Drink

# クラスメソッドの定義
  def self.welcome
    puts "いらっしゃいませ！"
  end

# initializeメソッドの定義
  def initialize(name, price)
    @name = name
    @price = price
  end

# インスタンスメソッドの定義
  def introduce
    puts "#{@name}は#{@price}円です"
  end

end

# インスタンスの生成
water = Drink.new("水", 100)
cola = Drink.new("コーラ", 150)
monster = Drink.new("モンスター", 200)

# クラスメソッドの呼び出し
Drink.welcome

# インスタンスメソッドの呼び出し
water.introduce
cola.introduce
monster.introduce
```
ARC114 振り返りメモ (A問題まで)

#結果
0完で, レート変化は748→<font color="Maroon">695</font>(-53)

#A問題 ( [Not coprime](https://atcoder.jp/contests/arc114/tasks/arc114_a) )
###概要
> 2以上50以下のN個の自然数のどれとも互いに素にならない最小の自然数を求める.

###方針
X [ i ] と現状の答えと互いに素でなければ, X [ i ] の最小の素因数を現状の答えにかけていくという方針で解いたが, X = {15, 20} のような場合に, 12 と出力してしまったりするので, いい方針では無かった.
答えは必ず素数の積になるので, 全ての素数の積の組み合わせを全探索すれば良い.
また, その際にbit全探索を使う.

C++ での実装例は以下のようになる.

```cpp:a.cpp
#include <bits/stdc++.h>
using namespace std;
#define rep(i,n) for (long long i = 0; i < (n); i++)
using ll = long long;

const ll LINF = (1LL<<60)-1;

ll gcd(ll x, ll y) {
    if (x % y == 0) return y;
    else return gcd(y, x % y);
}

int main() {
    ll n; cin >> n;
    vector<ll> x(n);
    rep(i, n) cin >> x[i];
    vector<ll> p = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47};
    ll ans = LINF; // 答えは十分に大きい値で初期化
    for (ll bit = 0; bit < (1 << (ll)p.size()); bit++) {
        bool ok = true;
        ll sum = 1;
        rep(i, (ll)p.size()) {
            if (bit & (1 << i)) {
                sum *= p[i];
            }
        }
        for (auto x_val : x) {
            if (gcd(x_val, sum) == 1) {
                ok = false;
            }
        }
        if (ok) ans = min(ans, sum);
    }
    cout << ans << endl;
}
```
【JavaScript学習記録】Objectをsortしたい

　いつものように、.sort( )で並び替えをし、console.logで確認したところ、中身に変化がない・・・。
　どうやらObjectは、.sort( )では並び替えできないようです。
　どうしたら並び替えることができるのか調べましたので、自分用に記録しておきます。

　__・今回sortしたいデータ__

```
// {'entryNum': time}
finalGameResult = { '1': 870, '2': 855 };　
```
　__・これをタイムが早い順で並び替えしたい・・・__

　実現する為に、以下のサイトを参考にさせて頂きました:relaxed::tulip:
https://kinocolog.com/javascript_sort/

　同じように当てはめてみる。

```

let ranking = Object.keys(finalGameResult).map((k) => ({ entryNum: k, time: finalGameResult[k] }));
ranking.sort((a, b) => a.time - b.time);
```

```
console.log(ranking);
⇒　[ { entryNum: '2', time: 855 }, { entryNum: '1', time: 870 } ]
```
　__無事に並び替えることができました！__
ABC195 振り返りメモ(C問題まで)

#結果
ABCまでの3完で, レート変化は738→<font color="Maroon">748</font>(+10)

#[A問題 ( Health M Death )](https://atcoder.jp/contests/abc195/tasks/abc195_a)
###概要
> 倍数の判定.

###方針
H が M の倍数かどうかを判定すれば良い.

C++ での実装例は以下のようになる.

```cpp:a.cpp
#include <bits/stdc++.h>
using namespace std;

int main() {
  int M, H; cin >> M >> H;
  if (H % M == 0) cout << "Yes" << endl;
  else cout << "No" << endl;

} 
```

#[B問題 ( Many Oranges )](https://atcoder.jp/contests/abc195/tasks/abc195_b) 
###概要
> A g 以上, B g 以下のみかんがたくさんあるとき,  ( 重さは整数とは限らない ) その中からいくつか選んで重さの合計が W kg になるかどうかを判定する. もしある場合は, 合計が W kg になる最小の個数と最大の個数を求める.

### 方針
ちょうど W kg になることができるためには, 

>```math
AN \leq 1000W \leq BN
```

が成立すれば良い.
これが成立するかどうかを確かめるには, N = 1 ~ 1000000 まで全探索すれば良い.
また, 最小の個数は W / B を「切り上げ」た数で, 最大の個数は W / A を「切り捨て」た数である.
実装上の工夫としては, 切り上げは

```cpp
(W + B - 1) / B
```
とすると良い.

C++ での実装例は以下のようになる.

```cpp:b.cpp
#include <bits/stdc++.h>
using namespace std;
 
int main() {
    int A, B, W;
    cin >> A >> B >> W;
    W *= 1000; // 1kg = 1000g
    for (int i = 1; i <= 1000000; i++) {
        if (A * i <= W && W <= B * i) {
            cout << (W + B - 1) / B << " " << W / A << endl;
            return 0;
        }
    }
    cout << "UNSATISFIABLE" << endl;
    return 0;
} 
```

#[C問題 ( Comma )](https://atcoder.jp/contests/abc195/tasks/abc195_c)
###概要
> 1 ~ N までの数字を一回ずつ書くとき, 3桁ごとにカンマを書くとすると, 合計で何回カンマを書くことになるか求める.

### 方針
愚直に実装すれば良い.

C++ での実装例は以下のようになる.

```cpp:c.cpp
#include <bits/stdc++.h>
using namespace std;
using ll = long long;

int main() {
    ll n; cin >> n;
    ll ans = 0;
    if (n >= 1000) ans += n - 1000 + 1;
    if (n >= 1000000) ans += n - 1000000 + 1;
    if (n >= 1000000000) ans += n - 1000000000 + 1;
    if (n >= 1000000000000) ans += n - 1000000000000 + 1;
    if (n >= 1000000000000000) ans += n - 1000000000000000 + 1;
    cout << ans << endl;
} 
```
Kotlinのlazy（遅延処理）の仕組みを調べて自分で簡易に実装してみた

Kotlinでは以下コードのように `by lazy` を使って簡単に遅延評価処理が書けます。

```kotlin
class Person {
    val name by lazy {
        //重い処理が走る想定（例：DBからのデータ取得） 
        "@doyaaaaaken"
    }
}

fun main() {
    val person = Person() //この時点ではperson.nameはまだ評価されていない（＝遅延評価）
    println(person.name) //@doyaaaaaken
}
```

`by lazy` はKotlinの言語仕様っぽく見えるのですが、実はそうではなくKotlin標準ライブラリとKotlin言語仕様である委譲プロパティ（Delegated Properties）を使って実現されています。
その仕組みについて説明してみました。

# lazyを自前で実装してみる

実際にlazyを自分で簡易に実装してみることで仕組みについて見ていきます。
（簡易実装なので、マルチスレッドに対応していなかったりなどの不備があります。）

自前の関数は `myLazy` という名前にし、以下コードのように呼び出し側からは `by lazy` ではなく `by myLazy` で呼び出すものとしましょう。

```kotlin
class Person {
    val name by myLazy {
        //重い処理が走る想定（例：DBからのデータ取得）
        "@doyaaaaaken"
    }
}
```

`myLazy` はグローバルな関数として用意する必要があります。
遅延処理として変数を初期化する処理を `initializer` という名前の関数で引数として渡してやりましょう。
`MyLazy`というclassが作成されます。

```kotlin
fun <T> myLazy(initializer: () -> T): MyLazy<T> = MyLazy(initializer)
```

さて、ここで`by myLazy`の`by`句はKotlinの言語仕様である委譲プロパティという機能です。

詳細な説明は[公式ドキュメント](https://kotlinlang.org/docs/delegated-properties.html)を参考にしていただくとして、ここでは簡単な説明だけします。
委譲プロパティは、**変数のget, setに関わる共通処理をクラスとして切り出せる（＝委譲できる）機能**です
今回の場合、「任意の変数をget（＝値を取得）する際に遅延評価したい」という要求があり、それを`MyLazy`というクラスへと共通化し切り出す（＝委譲する）形です。

言語仕様としては、委譲先のクラス内に`getValue`という名前のメソッドを作ることで、`by myLazy`をつけた変数（今回の例だと`person.name`）の値が参照される度にその`getValue`の処理が毎回呼び出されるようになっています。
（`getValue`メソッド実装の際には、通常の`fun`を使うのではなく`operator fun`として宣言する必要があります。）

```kotlin
class MyLazy<out T>(private val initializer: () -> T) {
    private var _value: Any? = UNINITIALIZED_VALUE

    operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
        //CAUTION: not thread safe
        if (_value === UNINITIALIZED_VALUE) {
            _value = initializer()
        }
        return _value as T
    }
}
private object UNINITIALIZED_VALUE
```

# コード全文

ここまでで説明した諸々のコードの全文は以下のとおりになります。

```kotlin
import kotlin.reflect.KProperty

fun main() {
    val person = Person() //この時点ではperson.nameはまだ評価されていない（＝遅延評価）
    println(person.name) //@doyaaaaaken
}

class Person {
    val name by myLazy {
        //重い処理が走る想定（例：DBからのデータ取得）
        "@doyaaaaaken"
    }
}

fun <T> myLazy(initializer: () -> T): MyLazy<T> = MyLazy(initializer)

class MyLazy<out T>(private val initializer: () -> T) {
    private var _value: Any? = UNINITIALIZED_VALUE

    operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
        //CAUTION: not thread safe
        if (_value === UNINITIALIZED_VALUE) {
            _value = initializer()
        }
        return _value as T
    }
}
private object UNINITIALIZED_VALUE
```

# 参考：公式ドキュメント

* [委譲プロパティ（Delegated Properties）の説明](https://kotlinlang.org/docs/delegated-properties.html)
HTTPで立ち上げたWebSocketサーバに、HTTPSで接続するためのWeb Proxyの立ち上げ

以前、以下の記事で、ESP32内にWebSocketサーバを立ち上げました。
　[MMDダンスをM5Core2のディスプレイに表示する](https://qiita.com/poruruba/items/a2cd9606c630bea5f5bf)

しかしながら、ESP32内に立ち上げられるWebSocketサーバはHTTP接続のため、HTTPSで立ち上げたWebページのJavascriptからは「Mixed Content」となって接続できませんでした。

そこで、HTTP接続のWebSocketをHTTPSで接続できるようにするReverse Proxyサーバを立ち上げる手順を示しておきます。

こちらのページの設定を借用いたしました。

https://github.com/Links2004/arduinoWebSockets/blob/master/examples/Nginx/esp8266.ssl.reverse.proxy.conf

#Nginxのインストール

Reverse Proxyサーバは、Nginxで実現します。インストールされていな場合は、インストールしておきます。以下は、Ubuntuの場合です。
後者は、PC再起動時にも自動起動するためのものです。

```
# apt-get install nginx
# systemctl enable nginx.service
```

SSL証明書を取得します。Let’s Encryptを使うのが手っ取り早いでしょう。
（オレオレ証明書でも大丈夫な気がしますが、試していません）
いろんなサイトで紹介されているので、ここでは説明を省きます。

取得したSSL証明書のファイルは3つあるかと思います。

・SSL証明書(ファイル名例：cert.pem)
・SSL中間証明書(ファイル名例：chain.pem)
・秘密鍵(ファイル名例：privkey.pem)

SSL証明書とSSL中間証明書を結合します。例えば、ファイル名「cert_chain.pem」とします。

```
-----BEGIN CERTIFICATE-----
SSL証明書
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
SSL中間証明書
-----END CERTIFICATE-----
```

次に、```/etc/nginx/cert/``` に、cert_chain.pemとprivkey.pemを配置します。
そして、 ```/etc/nginx/site-enabled/default``` の最後に以下を追加します。

```
# websocket proxy
server {

    # general server parameters
    listen                      50081;
    server_name                 【SSL証明書作成時に入力したドメイン名】;

    # SSL configuration
    ssl                         on;
    ssl_certificate             /etc/nginx/cert/cert_chain.pem;
    ssl_certificate_key         /etc/nginx/cert/privkey.pem;
    ssl_session_cache           builtin:1000  shared:SSL:10m;
    ssl_protocols               TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers                 HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;
    ssl_prefer_server_ciphers   on;

    location /m5core2/ {

      # websocket upgrade tunnel configuration
      proxy_pass                    http://【転送先のIPアドレス】:81/;
      proxy_http_version            1.1;
      proxy_set_header Upgrade      $http_upgrade;
      proxy_set_header Connection   "Upgrade";
    }
}
```

nginxを再起動します。

```
# /etc/init.d/nginx restart
```

これで、Web Proxyサーバが立ち上がり、listenで指定したポート番号(50081)で待ちうけ、proxy_passで指定したURL(http://【転送先のIPアドレス】:81】)に転送されるようになります。

location を ```/m5core2``` としていますので、WebSocketサーバの接続先は以下のようになります。
　``` wss://【NginxサーバのIPアドレス】:50081/m5core2 ```
複数の転送先やポートを指定したい場合は、locationの名前を変えて複数指定してください。

#参考

　[SSL証明書を取得しよう](https://qiita.com/poruruba/items/59d6197166bb09049f53)


以上
M5Atomでpingに失敗したらLEDを光らす

# はじめに
pingに失敗するとM5AtomのLEDがゲーミングカラーに輝く、みたいな事がしたいなぁと思い作ってみた。

```ino:ping.ino
#include <WiFi.h>
#include <WiFiClient.h>
#include <ESPmDNS.h>
#include <ESP32Ping.h>
#include "M5Atom.h"

// wifi
const char* ssid = "ssid";
const char* password = "password";
IPAddress ip(xxx,xxx,xxx,xxx);
IPAddress gateway(xxx,xxx,xxx,xxx);
IPAddress subnet(xxx,xxx,xxx,xxx);
IPAddress DNS(xxx,xxx,xxx,xxx);

IPAddress pingip (xxx,xxx,xxx,xxx); // ping対象

boolean IsPingCheck = false; // ping成功可否

int LedPoint = 0; // LED点灯位置

// ランダムなLEDの値を返す
int RandomLedVal() {
  return random(1, 16777215);
}

// Pingが通る場合、LEDを1つ移動させながらランダムに点灯させる。
void PingSuccess() {
  LedOffAll();

  if(LedPoint > 25) {
    LedPoint = 0;
  }

  M5.dis.drawpix(LedPoint, RandomLedVal()); // LEDをランダムに光らせる
  ++LedPoint;
}

// Pingに失敗した場合、LEDをランダムに光らせる。
void PingFailure(){
  for (uint32_t i = 0; i < 25; i++)
  {
    M5.dis.drawpix(i, RandomLedVal());
  }
  M5.update();  
}

// LEDを全てOFFにする。
void LedOffAll(){
  for (uint32_t i = 0; i < 25; i++)
  {
    M5.dis.drawpix(i, 0x000000);
  }
  M5.update();  
}

void setup(void) {
  Serial.begin(115200);

  //wifi
  WiFi.config(ip, gateway, subnet, DNS);
  delay(10);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
  }

  // LED初期化
  M5.begin(true, false, true);
  delay(50);
}

void loop(void) {
 
  IsPingCheck = Ping.ping(pingip); // ping

  if(!IsPingCheck){
    PingFailure();
  }
  else{
    PingSuccess();
  }

  M5.update();
}
```

#
基本情報技術者試験メモ2021/3/14（アルゴリズム関連など）

#単語メモ（よく忘れるのでメモしておきます…）
<b>再帰</b>
　→　関数などの内部で自身を呼び出す

<b>添え字</b>
　→　配列の中の変数それぞれに割り振られた番号たち

<b>2分探索法</b>
　→　昇順または降順のデータに対する探索方法で、探索範囲を1/2に狭めることを繰り返して目的のデータをみつける

<b>XML</b>
　→　拡張可能なマークアップ言語（データ交換用の汎用データ形式、ユーザ独自タグあり）

<b>参照呼出し（pass by reference）</b>
 →　引数はポインタ（メモリーアドレス）（上書きすると元の変数も変わる）
<b>値呼出し（call by value）</b>
　→　引数は値のコピー（上書きしても元の変数は変わらない）

<b>待ち行列（キュー構造）</b>
　→　「先入れ先出し方式」のデータ構造

<b>再入可能（リエントラント）プログラム</b>
　→　複数のタスクから同時に呼び出されてもそれぞれに正しい値を返すことができる
mainブランチ変更


#手順1 ローカルブランチを改名
ブランチを改名する

```
# git branch -m (変更前のブランチ名) 変更後のブランチ名
　git branch -m master main
```
-mは--move、ブランチを移動する、すなわち改名するためのオプションです。
なお、現在チェックアウトしているブランチの名前を変える時は変更前のブランチ名は省略可能です。

#手順2 改名後のブランチをpush
ブランチをpushする

```
# git push -u origin 変更後のブランチ名
git push -u origin main
```
サーバー証明書(オレオレ証明書)を作ってhttps通信をできるようにした。

## サーバ証明書とは
そのサーバの実在証明や、通信内容の暗号化に使用するものです。
Digicertやグローバルサインといった認証局によって発行されております。
しかし、上記の認証局を利用すると金がかかるので、今回は自分のサーバでオレオレ証明書という証明書を作成します。

## オレオレ証明書とは
正規の認証局を通さず、自分自身のサーバーで発行したサーバー証明書です。
何の保証にもなっていませんが、今回は自宅内のサーバーとhttps通信したいだけなので問題ありません。

## ざっくりとした作業手順
1.htpps通信を行いたいサーバーで秘密鍵を作成する。
2.作成した秘密鍵を元に、CSRを作成する。
3.CSRを元にしてサーバー証明書を作成する
4.webサーバの設定を修正し、https通信を可能とする

## 秘密鍵を作成する
以下のコマンドを入力して秘密鍵を作成します。

```
openssl genrsa -des3 -out 秘密鍵のパス 2048
```

コマンド入力後、秘密鍵のパスワードを要求されるので適当なパスワードを入力してください。

```
Enter pass phrase for 秘密鍵のパス:
Verifying - Enter pass phrase for 秘密鍵のパス:
```

これで秘密鍵の完成です。この秘密鍵を元にしてCSRを作成します。

## CSRを作成する
CSRは、認証局にサーバー証明書を作成してもらうための申請書のようなものです。
以下のコマンドで作成することが可能です。

```
openssl req -new -key 秘密鍵のパス -out CSRのパス
```

コマンド実行後、以下のように色々と聞かれます。サーバー保有者や団体の情報を入力すれば完成です。

```
Country Name (2 letter code) [XX]:JP
State or Province Name (full name) []:tokyo
Locality Name (eg, city) [Default City]:hoge
Organization Name (eg, company) [Default Company Ltd]:company
Organizational Unit Name (eg, section) []:sales
Common Name (eg, your name or your server's hostname) []:www.test.com
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
```

## サーバー証明書の作成
本来ならば、CSRを認証局に提出してサーバー証明書を作成してもらうのですが、今回はオレオレ証明書なので自作します。

```
$ openssl x509 -in CSRのパス -days 365 -req -signkey 秘密鍵のパス -out 作成するサーバ証明書のパス
Signature ok
subject=/C=JP/ST=tokyo/L=hoge/O=company/OU=sales/CN=www.test.com
Getting Private key
```

## webサーバーの設定
今回はwebサーバーとしてNginxを使用しております。

```
server {
  # ポート番号は80から443に変更
  listen 443;

  # SSLの設定を追記
  ssl on;
  ssl_certificate オレオレ証明書のパス;
  ssl_certificate_key 秘密鍵のパス;
  ~中略~
}
```

## 実践
これでhttpsでアクセスできるはずなので、早速実践してみましょう。
こんな画面になりますが、自分で作ったサーバー証明書なので警告が出るのは仕方ないです。
ブラウザ上で「thisisunsafe」と入力すれば、ページにアクセスすることができます。
![dintPOIYUo4uzRP1615733137_1615733225.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/429077/5e099dcb-6026-0b81-08d8-1f73f3611e72.png)
アルゴリズムについて

今回は前から気になっていたアルゴリズムについて軽く調べてみた事を書いていきたいと思います。


#アルゴリズムとは
問題解決の為に手順通りにやると、誰がやっても同じ結果になる手続きや計算方法をアルゴリズムと言う。
`アルゴリズムは、プログラミングをする上で必要不可欠の概念。`

　　

・**良いアルゴリズム**と言うのは、結果に至るまでの方法が複数あるとき、同じ動きをするなら、速く、簡単に処理させる方法を採用すべきである。
そして汎用性が高く、効率的であり、問題解決をスムーズに行える。


　


・**ソートアルゴリズム**
データを昇順や降順で並び替える仕組みのこと。そのソート方法として、
**バブルソート**：とは横にある数の大きさを比較し、並べるソートのこと。
**クイックソート**：基準値を決めてそれよりも大きいか小さいかでグループ分けするソートのこと。
**マージソート**：配列を細かく分けて再配列するソートのこと。



　
###まとめ
奥が深すぎて難しい印象を受けました。
とにかくプログラミングにとってかなり重要な要素ということだけわかりました。
野菜の切り分け方がとても良い例で分かりやすく感じた。
**「途中経過は違えど、最終的には同じものなる」**という解釈で覚えておくとする。
アルゴリズムの原理を追求するのはまだまだ先になりそうです..。
MAMPインストール


# MAMPのダウンロード
以下のページからインストーラーをダウンロードする。
https://www.mamp.info/en/downloads/
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1007978/723b4dd0-cebe-e979-d304-22b0a0ac1313.png)

# MAMPのインストール
ダウンロードしたMAMP_MAMP_PRO_6.3.pkgをダブルクリックするとインストール画面が開く。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1007978/b83dc470-5deb-469b-245a-c8645ba4d007.png)
「続ける」を押す。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1007978/6286ce7e-32a0-4aff-ed5a-f30d75729623.png)
「続ける」を押す。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1007978/c1a8ea01-0ef8-9b14-6f5b-a8a293dd6ed1.png)
「続ける」を押す。と同意を求められる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1007978/8c749b2a-72d4-c26a-052b-c27d74836232.png)
「Agree」を押す。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1007978/f5a074d6-370a-0e39-9833-d37b19aa9d32.png)
「続ける」を押す。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1007978/04b51312-186b-627e-e68a-056812dac61a.png)
「インストール」を押す。とパスワードを聞かれる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1007978/eb077985-41c4-b594-c668-a37d9e444d94.png)
パスワードを入力し、「ソフトウェアをインストール」を押す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1007978/99321cb7-362e-9625-e096-c83c29b9fb17.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1007978/a417a584-d8a7-f346-1da6-72a03d388183.png)

この画面が出たら、インストール完了。

# MacOSのApacheの確認
MacにはApahceが標準搭載されているらしいので、競合しないように止めておく必要がある。
「システム環境設定」の「共有」でインターネット共有ににチェックがなければOK。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1007978/b6e9fe50-3860-2750-d569-503561c5fa9d.png)

# MAMP初期設定
MAMPを起動する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1007978/ce99d6b9-8ed2-4af0-6621-46b1a6ad01c0.png)
右上の「start」を押す。とWEBページに遷移する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1007978/3bdae6fc-9e05-8af7-58d3-eb35a83f9bee.png)
右上の「stop」が緑色になっていれば正常。

左上の「preferences」の「Ports」タブで、ポートを設定する。
初めは以下のようになっている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1007978/5176050d-e481-0b94-a1f6-76be0816d9df.png)
set Web & MySQL ports to:「80 & 3306」を選択すると、変わる。で「OK」を押す。
この設定で、ローカル環境でMAMPのApacheにアクセスするURLが、
`http://localhost:8888/`から`httt://localhost/`に変わる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1007978/6c52dfb4-acf8-d798-c011-c118c8035d6f.png)

終わり。

# 参考サイト
https://www.webdesignleaves.com/pr/plugins/mamp_installation.html
【学習メモ】AWS Lambda

#Lambda
サーバーレス。
FaaS（Functions as a Service）
AWS Lambdaはサーバーがなくても、コードを実行することで効率的なアーキテクチャを実現できるサービス。

##特徴
・実行基盤は全てAWSが管理
・AWSサービスと連携させることで簡単にイベントドリブンなアプリケーションを実装可能
・100ミリ秒単位でコード実行時間に対しての課金でありコスト効率が非常に高い
・オートスケール
・Python/Java/Node.js/C#/Go/Rubyで書かれたコードを実行

##仕組み
イベントの発生がトリガーとして、Lambdaコートが実行される。


##利用モデル
###Pushモデル
・AWSサービスとカスタムイベントが直接実行することによって、Lambdaへイベント通知して、コードを実行する。
※コード実行の順序は保証されない

###Pullモデル

・LambdaはDynamoDBとKinesisなどのデータ処理へポーリングを行い、コードを実行する。
※一度ストリームに入れることによって、イベントの順序を保つことができる

####パーミッション
Pullモデルの場合、ストリーム側 (invocation role) と、実行側 (excution role) の両方のパーミッションが必要。

◯Execution：
　・LambdaファンクションがAWSリソースにどういったアクションを実施させるかを決定する。
　・指定されたIAMロールに沿ってAWSのリソースへのアクセスが許可される。
◯Invocation：
　・Lambdaファンクションをどのリソースが実行できるかを決定する。
HostとContainerの繋がり

#【HostとContainerの繋がり】

かめさん いつもありがとうございます。
[米国AI開発者がゼロから教えるDocker講座](https://www.udemy.com/course/aidocker/)

・ファイルシステムの共有
・ファイルへのアクセス権限
・ポートを繋げる
・コンピュータリソースの上限

　→　$docker run コマンド時のオプションで設定

##ホストのファイルシステムをコンテナにマウント

<strong>-v < host/path >:< container/path >オプション</strong>

HostのファイルシステムにあるcodeをContainerにあるかのように扱える。
これによって、Containerのファイルが大きくならない。

$ cd ~/Documents
$ mkdir mounted_folder
$ touch mounted_folder/file_at_host
$ docker build .
$ docker run -it <strong>-v ~/Documents/mounted_folder:/new_dir</strong> < image > bash
$ ls /new_dir

##ユーザIDとグループIDを指定してコンテナをrunする

<strong>-u < user id >:< group id >オプション</strong>

Containerを起動する時にrootじゃなくて、指定したユーザIDとグループIDでrunをするようにする。
セキュリティを向上させる。

$ cd ~/Documents
$ docker build .
$ docker run -it <strong>-u 501:20 </strong>-v ~/Documents/mounted_folder:/created_in_run < image > bash
$ touch /created_in_Docker/sample_file
$ touch /created_in_run/sample_file

##ホストのポートをコンテナのポートに繋げる

<strong>-p < host_port >:< container_port >オプション</strong>

コンテナをWebサービスとして立てるといった使い方はよくさせる。
HostのポートからContainerのポートにアクセス（publish）するために繋げる必要がある。

$ docker run -it <strong> -p 8888:8888 </strong>--rm jupyter/datascience-notebook bash
$ jupyter notebook 

##コンテナがアクセスできる上限のCPU、メモリを設定

コンテナがアクセスできる上限のCPUを設定
　→　<strong>--cpus < # ofCPUs ></strong>

コンテナがアクセスできる上限のメモリを設定
　→　<strong>--memory < byte ></strong>

$ docker run -it --rm <strong>--cpus 4 --memory 2g </strong> ubuntu bash
$ docker ps
$ <strong>docker inspect < container ></strong>
　→　コンテナの詳細を表示する。
$ docker inspect < container > | grep -i < something >

##補足

1 K byte = 1024 byte
1 M byte = 1024 * 1024 byte
1 G byte = 1024 * 1024 * 1024 byte

※1024 = 2^10
Pytorch-LightningのCheckpointでLAN内のminio(S3互換ストレージ)へモデルを保存する方法

## 概要
現在のpytorch-lightning(ver.1.2.3)では、S3への保存を行う際にendpointを指定できないため、LAN内にあるS3互換ストレージなどへ保存を行うことが出来ない。
以下のsetup_endpointを実行することで、fsspecモジュールへ強引にモンキーパッチを当ててエンドポイントを指定する。

## 方法
- pytorch-lightning がクラウドストレージへのIOで使用している関数へモンキーパッチを当てEndpointを強引に指定する。
- 以下のコードをコピペして<b>setup_endpoint</b>を実行するだけで可能。

## コード
```python
from typing import Any
import gorilla
import fsspec

def apply_gorrila(function: Any, module: Any):
    patch = gorilla.Patch(
        module, 
        function.__name__, 
        function, 
        settings=gorilla.Settings(allow_hit=True))
    gorilla.apply(patch)

def setup_endpoint(endpoint_url: str):
    def filesystem(protocol, **storage_options):
        if protocol == "s3":
            storage_options["client_kwargs"] = {
                "endpoint_url": endpoint_url,
            }
        original = gorilla.get_original_attribute(fsspec, 'filesystem')
        return original(protocol, **storage_options)
    def open_files(*args, **kwargs):
        kwargs["client_kwargs"] = {
                "endpoint_url": endpoint_url,
        }
        original = gorilla.get_original_attribute(fsspec.core, 'open_files')
        return original(*args, **kwargs)
    apply_gorrila(filesystem, fsspec)
    apply_gorrila(open_files, fsspec.core)
```
JetBrains製の静的コード解析ツール Qodana をGitLab CIで使う

 
# TL;DR

設定してみたリポジトリはこちら。
- [h.yoshida / qodana-sample · GitLab](https://gitlab.com/hirokiyoshida837/qodana-sample)
  - 2021/03/14時点でうごく状態のものです。今後、Qodanaはまだearly access programのサービスですのQodanaのDocker Imageのバージョン更新、GitLab Runnerのバージョン更新により動作しない可能性があります。

.gitlab-ci.ymlは以下の通り。

```yaml

# 実際はstageを分けて使うのを推奨。
pages:
  stage: deploy
  image:
    name: jetbrains/qodana:2020.3-eap
    entrypoint: [""]
  script:
    - /opt/idea/bin/entrypoint --results-dir=$CI_PROJECT_DIR/qodana --save-report --report-dir=$CI_PROJECT_DIR/qodana/report
    - ls -la
    - mv qodana/report public
  artifacts:
    paths:
      - public
  only:
    - master
```

このような画面で解析結果が出ます。

![image2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407001/7ec260bf-74fe-e9d9-d9e6-ffd129e6751e.png)



# 1. about Qodana

`Qodana` は、JetBrains (Intellij IDEAなどの開発元)が、現在開発中の静的コード解析ツールです。

公式からDockerイメージが提供されており、このDockerイメージの中でIntellijによるコード解析が実行され、HTML形式でレポートが出力されるようになっています。

従来より、JavaではFindBugs、 SpotBugs、 PMD、 etc...のような静的チェックツールはありましたが、これらと比較すると以下のようなメリットがあると考えられます。

- Intellij IDEAユーザであれば、手元のコード検査環境と、CI/CDでの検査を同じレベルにできる。
- 非Intellij IDEAユーザーでも、Intellij IDEA相当のコード解析・チェックが可能。
- Dockerイメージで提供されているため、様々なCI/CD環境に組み込むことが可能。
- 開発言語を問わず、同じ解析ツールが使用できる (ようになる予定。現状はJava, Kotlin, PHPなどのみ対応)


# 2. 使い方

公式リポジトリに、各種CIサービスで使う為のサンプルが書いてあり、これに従えば動くはずです。
- [JetBrains/Qodana: Source repository of Qodana Help](https://github.com/JetBrains/Qodana)
- [Qodana/Docker at main · JetBrains/Qodana](https://github.com/JetBrains/Qodana/tree/main/Docker)

ただし、GitLab CIで動かす場合はlatestのDocker Imageでは動かないケースがあるようです。 (そのうちlatestに取り込まれるはず)
- [Make Qodana docker image more usable to use in GitLab CI : QD-638](https://youtrack.jetbrains.com/issue/QD-638)
- [GitLab CI does not work with 2021.1-eap : QD-728](https://youtrack.jetbrains.com/issue/QD-728)


# 設定してみた

以下のリポジトリにコード、設定ファイルを配置しました。
- [h.yoshida / qodana-sample · GitLab](https://gitlab.com/hirokiyoshida837/qodana-sample)

Qodanaによるチェック結果はこちらにDeployされています。
- [Qodana](https://hirokiyoshida837.gitlab.io/qodana-sample/?locationFilters=NoXSA&genericFilters=N4IgLg9hA2IFwG0QGEIBMCmACAkgOwGcAHDAYzAEsI8QBdAGhAIwDcMAnCsAT3iQAkKAcwAWdRqQCGYDEIjteiFOmwBbaQFdOPceG4k%2BIAKrMsEAGZYAytwIzVAOggawZ9tdv2HHdnQC%2BQA&orderedLevels=NoIgLg9hA2IDQgM4FMBuyBOBLMBPeIAxgIZjIDmEG%2BCeADsiALpA)

以下の注意点があります。
  - CI設定でキャッシュを設定していないので毎回時間がかかる。そのうち対応します。
  - GitLab CIで動かした際、上記の QD-638のIssueにある内容と同じような内容を踏んで、60分間Runnerが動き続けてTime Outで強制終了した事があったので、Time Outを15分に設定しています。
    - まだEAPなので動作が不安定になること可能性があるので、Runnerの稼働時間を気にする人は一応短めに設定しておいたほうがいいかもしれません。
    
    
# 3. 使ってみた感想、気になる点

デファクトスタンダードになるかはわかりませんが、Intellij IDEAユーザにとっては手元とCI側の検査レベルを同じにできるのがかなり良いのではないかと思います。

まだEAPなので、使用時はマニュアルと公式のYouTrackも確認しながら使う必要がありそうです

Qodana公式リポジトリ、およびJetBrainsのEAPに関する説明などは十分確認した上で使用をお願いします。

> By using Qodana, you agree to the JetBrains EAP user agreement and JetBrains privacy policy. [JetBrains/Qodana: Source repository of Qodana Help](https://github.com/JetBrains/Qodana#license)