OmniAICreator/Qiita-1.07M huggingface dataset:
[RSpec]`data-confirm`のテストとき、削除の確認ダイアログでOKしたのにレコード数が減らないのは、「Ajaxが完了していなかった」から


ユーザーの質問と、解答の関連はこのような感じ。

```rb
class User
  has_many :questions
end

class Question
  has_many :answers
  belongs_to :user
end

class Answer
  belongs_to :question
  belongs_to :user
end
```

# 概要
- 質問に対する回答の削除ができるかテストしたい
- 削除確認ダイアログでOKは押せている
- でも、`Answer.count`が減っていない

## 削除確認ダイアログでOKを押す
Capybaraで`data-confirm`で表示されるダイアログ（JSの確認メッセージ）を操作する方法はこちらの記事で知りました。:clap:

- [【Rails】Selenium/RSpecでconfirmダイアログのテストをする \- Qiita](https://qiita.com/at-946/items/403d85d45cb02615c323)

# パスしないテストの例

このようなSystem Specを書いていたのですが、`expect {}.to change{ Answer.count }.by(-1)`が失敗しました。（Answer.countが減っていない）



```rb
describe 'Answer', type: :system do
  let!(:user) { create(:user) }
  let!(:user_other) { create(:user_other) }
  let!(:question_by_other) { create(:question, user: user_other) }
  let!(:answer) { create(:answer, user: user, question: question_by_other) }

  before do
    sign_in user
  end

  it '削除できる' do
    visit question_path(answer.question)

    within(:css, 'ul.answers > li') do
      click_on '削除' 
    end

    expect {
      expect(page.driver.browser.switch_to.alert.text).to eq "削除してよろしいですか？"
      page.driver.browser.switch_to.alert.accept
    }.to change{ Answer.count }.by(-1)
  end
end
```

# テストをパスするための変更点

- [sleepやリトライに頼らない安定した feature spec を書こう \- Qiita](https://qiita.com/shunichi/items/1cb7f7cfca74438513d3#%E4%BF%AE%E6%AD%A3%E6%96%B9%E6%B3%95%E3%81%9D%E3%81%AE%EF%BC%91)

> モデルを直接テストせず、ブラウザの表示をテストしましょう。
ブラウザのDOMに対するテストであれば capybara がデフォルトで2秒はリトライしてくれるので、重い処理でない限りは成功します。

今回の例も、Ajaxの処理が完了するまえに`Answer.count`をチェックしていたことが原因でした。
以下のコードを追加することで、ブラウザのDOMに対するテストがAjaxの完了を待ってくれるため、テストがパスするようになります。

```diff
    expect {
      expect(page.driver.browser.switch_to.alert.text).to eq "削除してよろしいですか？"
      page.driver.browser.switch_to.alert.accept
+     expect(page).to have_content 'コメントを削除しました'       
    }.to change{ Answer.count }.by(-1)
```
EC2のLaravel6.0環境でリレーションさせる　AWS/Laravel連載(12)

# はじめに

前回の記事でLaravel+Vueを使い、API経由で新規投稿を実装しました。

[EC2のLaravel6.0環境でVue+Rest APIを連携する　AWS/Laravel連載(11)](https://qiita.com/rf_p/items/77bb65607c121a94a2d4)

今回は投稿をユーザーIDに紐付けて、その投稿をどのユーザーがしたものかデータを紐付けます。

# migrationファイルを作る

```powershell
$ php artisan make:migration add_user_id_to_posts_table --table=posts
```

```php:database/migrations/xxxx_xx_xx_xxxxxx_add_user_id_to_posts_table.php
...
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('posts', function (Blueprint $table) {
            //
            $table->bigInteger('user_id')->unsigned();

            $table->foreign('user_id')
                  ->references('id')->on('users')
                  ->onDelete('cascade')
                  ->onUpdate('cascade');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('posts', function (Blueprint $table) {
            //
            $table->dropForeign('posts_user_id_foreign');

            $table->dropColumn('user_id');
        });
    }
...
```

user_idというカラムを作って、usersテーブルの外部キーにします。

downのdropForeignの書き方が特殊なので要注意！
いざという時にmigrate:resetが効かなくならないよう、必ずdownの挙動も確認しましょう。

```powershell
$ php artisan migrate
```

これでカラム追加ができました。

# Laravel上で関連付ける

```php:app/User.php
...
    /**
     * 投稿取得
     */
    public function posts()
    {
        return $this->hasMany('App\Post');
    }
...
```

これにより、コントローラー等でuserインスタンスからそのユーザーの投稿が取得できます。

```php:例
$user->posts()->first()->content; // そのユーザーが投稿した１件目のデータの本文を表示
```

```php:app/Post.php
...
    /**
     * ユーザーを取得
     */
    public function user()
    {
        return $this->belongsTo('App\User');
    }
...
```

これにより、postインスタンスからユーザー情報が取得できます。

```php:例
$post->user->name; // 投稿したユーザー名を表示
```

# 投稿保存処理でユーザー情報を紐付ける

本来は認証済みユーザーに紐付いた投稿にさせたいのですが、API化しているのでAPIで認証情報を取得する必要があります。
この方法は[次回記事](https://qiita.com/rf_p/items/a0195376519def710171)で紹介するので、今回はダミーでid:1のユーザーの投稿としてみなします。

```php:app/Http/Controllers/PostController.php
...
    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        $validatedData = $request->validate([
            'title' => 'required|max:255',
            'content' => 'required',
        ]);
        $user = \App\User::find(1); // ここ次回記事で直します。暫定的にid:1のユーザー投稿とみなす
        return $user->posts()->create($request->all());
    }
...
```
ASP .NET Core Tips - あるスキャフォールディングアイテムが表示されない

#概要
ASP .Net CoreでWebサービスを作る手順や作ってる際にハマったこととその解決策を
備忘録として書いています。
今回もタイトルの通り、とあるスキャフォールディングアイテムが表示されず困った話と
その解決策。

#環境
Windows 10
Visual Studio 2019
ASP .Net Core 2.2


#現象
プロジェクトテンプレート「ASP .NET Core Webアプリケーション」の
Webアプリケーション（モデル ビュー コントローラー）で作成したプロジェクトで
発生しました。

ソリューションエクスプローラを表示し、プロジェクトツリー内のControllersフォルダを
右クリックし、メニューから追加→新規スキャフォールディングアイテムを選択します。

以下のような画面が表示されるのですが・・・

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146789/969cb517-58c7-2f1f-e7e9-824d209c2e0e.png)

そう、「Entity Framework を使用したビューがある MVC コントローラー」の項目が
見当たらないんです。

#対処方法
Visual Studio本体なのか、Microsoft.VisualStudio.Web.CodeGeneration.Designのバグなのか
ちょっとよくわかりませんが、どうやら以前VS2017でも発生していたみたい。
https://stackoverflow.com/questions/55082446/vs2017-not-showing-mvc-controller-with-view-using-entity-framework

プロジェクトにPagesフォルダがあると、
なぜか「Entity Framework を使用したビューがある MVC コントローラー」が
表示されないとのこと。

確かに自分のプロジェクトにもPagesフォルダがあり、
このフォルダを削除したらアイテムが表示されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146789/bf2a2717-3cfd-4bca-6c17-2c19b6c1bf46.png)

スキャフォールディングアイテムの、
「Entity Frameworkを使用するRazoreページ（CRUD）」を追加すると、
Pagesフォルダが追加されるんですよね。

自分のプロジェクトにPagesフォルダがあったのは、
間違って「Entity Frameworkを使用するRazoreページ（CRUD）」を追加したためでした。

何か地味にハマる問題でした・・・。
VueCLI3で作ったプロジェクトで、グローバルなSASS変数を使えるようにする

scssファイルを用意。本記事ではsrc/stylesに配置する。

```src/scss/_variables.scss
$mainColor: #114514;
```

プロジェクト直下に`vue.config.js`を作成し以下を記載。

```vue.config.js
module.exports = {
  css: {
    loaderOptions: {
      sass: {
        prependData: `@import "@/styles/_variables.scss";`
      }
    }
  }
};
```

これで各コンポーネントでSASS変数を使うことができる。

```SomeComponent.vue
<template>
  <div class="hoge">
    text
  </div>
</template>
<style lang="scss">
.hoge {
  background-color: $mainColor;
}
</style>
```

いちいちimportをしなくて良いので、コードの見通しが良くなり実際便利。
めでたしめでたし😇😇
SQLで複雑なリレーションシップを検索する (Re: Laravelで複雑なリレーションシップの検索をシンプルにする)

SUKOHI 氏がご自身のブログでSQLを募集していたので、実装してみました。

## お題

Laravelで複雑なリレーションシップの検索をシンプルにする – console dot log
https://blog.capilano-fw.com/?p=4748

> ただ、そんな状況であってもこの間、「うーーーーーん・・・」が発生したことがありました。
> それは、例えば、以下のようなデータベースの検索です。

>> hasManyで結合した子テーブルにはデータが入っていないもの（ただし、バナナはカウントから除外する）を取得する

>> hasManyした子テーブルの「name」が「イチゴ」だけのもの（ただし、パイナップルはカウントから除外する）を取得する

> （中略）
> もし、SQL一発で実行可能な方法を知っていたら、ぜひお問い合わせフォームから教えてください！


## 動作確認環境

MySQL Online - Paiza.io
https://paiza.io/en/languages/mysql
`select version();` -> `5.7.26-0ubuntu0.18.04.1`

## テストデータの作成

```sql
CREATE TABLE `box` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(100) COLLATE utf8mb4_unicode_ci NULL COMMENT '箱名',
  PRIMARY KEY (`id`)
);

CREATE TABLE `box_detail` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `box_id` int(10) unsigned NOT NULL,
  `name` varchar(200) COLLATE utf8mb4_unicode_ci NULL COMMENT '品名',
  PRIMARY KEY (`id`)
);

INSERT INTO box (name) VALUES 
('箱１（空）')
,('箱２（バナナ）')
,('箱３（バナナりんご）')
,('箱４（NULL）')
,('箱５（いちご）')
,('箱６（いちごパイナップル）')
,('箱７（いちごパイナップルりんご）')
;

INSERT INTO box_detail (box_id,name) VALUES 
(2,'バナナ')
,(2,'バナナ')
,(3,'バナナ')
,(3,'バナナ')
,(3,'りんご')
,(4, NULL)
,(5,'いちご')
,(5,'いちご')
,(6,'いちご')
,(6,'パイナップル')
,(6,'いちご')
,(7,'いちご')
,(7,'パイナップル')
,(7,'りんご')
;

```
</details>


## 問１

> hasManyで結合した子テーブルにはデータが入っていないもの（ただし、バナナはカウントから除外する）を取得する

boxのレコードそれぞれに対して「バナナでないbox_detailの親box_id」をjoinして、box_detailの親box_idがない(nullである)ようなboxを選択する。

```sql

select
 box.name, box.id
 -- , t.box_id
from box
left outer join (select distinct box_id from box_detail where name is null or name <> 'バナナ') as t
on t.box_id = box.id
where t.box_id is null
order by box.id asc
;

```


## 問２

> hasManyした子テーブルの「name」が「イチゴ」だけのもの（ただし、パイナップルはカウントから除外する）を取得する


boxそれぞれに「いちごであるbox_detailの合計件数」と「パイナップル以外のbox_detailの合計件数」をjoinして、いちごdetail数＝パイナップル以外detail数＞＝１　であるようなboxを選択する。

```sql

select
 box.name, box.id
 -- , strb.box_id, strb.cnt
 -- , all_but_pna.box_id, all_but_pna.cnt
from box
left outer join 
(select box_id, count(*) as cnt from box_detail where name = 'いちご' group by box_id) as strb
on strb.box_id = box.id
left outer join
(select box_id, count(*) as cnt  from box_detail where name is null or name <> 'パイナップル' group by box_id) as all_but_pna
on all_but_pna.box_id = box.id
where coalesce(strb.cnt, 0) >= 1 and coalesce(strb.cnt, 0) = coalesce(all_but_pna.cnt, 0)
order by box.id
;

```

## 問２　別実装

```sql

select
 box.name, box.id
 -- , details.strb_cnt, details.all_but_pna_cnt
from box
left outer join 
(select
    box_id
    , sum(case when name = 'いちご' then 1 else 0 end) as strb_cnt
    , sum(case when name is null or name <> 'パイナップル' then 1 else 0 end) as all_but_pna_cnt
    from box_detail group by box_id
) as details
on details.box_id = box.id
where coalesce(details.strb_cnt, 0) > 0 and coalesce(details.strb_cnt, 0) = coalesce(details.all_but_pna_cnt, 0)
order by box.id
;

```




Hope this helps.
railsでサーバーサイドキャッシュ使うときに気をつけること

### 要約
- rails + elasticbeanstalk環境でデプロイ時にたまに`Errno::ENOSPC: No space left on device`になる
- diskはまだ空いている
- 結局、inodeが枯渇していた
- railsでキャッシュを使っていて、`:file_store`にしているとファイル数が多くなりすぎる

### 現象
- デプロイ時に`Errno::ENOSPC: No space left on device`になる

```shell
eb deploy xxx
...
rake aborted!
Errno::ENOSPC: No space left on device @ dir_s_mkdir - /var/app/ondeck/tmp/cache/assets
/opt/rubies/ruby-2.5.0/bin/bundle:23:in `load'
/opt/rubies/ruby-2.5.0/bin/bundle:23:in `<main>'
Tasks: TOP => assets:precompile
```

- disk容量はまだあるけど、[inode](https://qiita.com/kamihork/items/fbcd116a631324aae05d#i-nodeとは)が枯渇していた

```shell
> df -T -i
ファイルシス   タイプ   Iノード  I使用   I残り I使用% マウント位置
devtmpfs       devtmpfs 2052009    452 2051557     1% /dev
tmpfs          tmpfs    2054250      1 2054249     1% /dev/shm
/dev/xxxxx     ext4      524288 524286       2   100% /

```

- 各ディレクトリのinode数を見てみると、railsプロジェクト直下のtmpディレクトリのinodeが異様に多かった

```shell
> for dir in `find . -maxdepth 1 -type d`; do echo `find "${dir}" -true | wc -l` "${dir}"; done | sort -nr
210363 .
163091 ./tmp
43890 ./node_modules
1486 ./app
1266 ./public
261 ./spec
235 ./db
74 ./config
...
```
- tmpの中身を見てみると、railsの(サーバーサイド)キャッシュのファイルだった。[ファイルストア](https://railsguides.jp/caching_with_rails.html#activesupport-cache-filestore)にしていた

- キャッシュごとにファイルが作成されるので、運用していくと多くなりすぎて、inodeが足りなくなっていた

- キャッシュストアを[mem_cache_store](https://railsguides.jp/caching_with_rails.html#activesupport-cache-memcachestore)にして解決

```ruby
config.cache_store = :mem_cache_store, url, {namespace: "xxx"}
```
Ruby on Rails の特長【初心者】

#はじめに
###Ruby on Railsとは
Ruby on Railsというのは、Rubyの代表的なフレームワークです。

###フレームワークって何？
フレームワークとは、Webアプリケーションを簡単に開発できるようにする骨組みのことです。
フレームワークはよくカレーのルーに例えられます。

例えばカレーを作るとき、スパイスを一から揃えて作るとなると大変ですよね。
そんな時カレールーを使えば、そこに好きな具材を入れるだけで時間もかけずにスムーズにカレーを作ることが出来ます。
***

Railsは、最善の開発方法というものを1つに定めるという、判断に基いて設計されています。
最善の開発方法の支援に特化することで開発の生産性を飛躍的に向上させています。




#Ruby on Railsの特徴
###MVCアーキテクチャ
MVCとはそれぞれModel、View、Controllerの略です。
railsではWebシステムの機能をこの3つに分類して開発を進めていくスタイルを取っています。

・Modelはデータベースなど、永続化されたデータとビジネスロジックの処理
・Viewはユーザが操作する画面の入出力や描画
・Controllerは、ViewとModelの仲介をして、全体の制御

このように役割分担することで、どこに何を書けば良いのかが明確になり、効率よく開発ができるようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502115/f4a2b870-fcc6-1b04-3e66-33b1842c5570.png)
[引用元：Ruby on Rails チュートリアル 図 1.14: Model-View-Controller (MVC) アーキテクチャの概念図]

###DRY:Don't Repeat Yourself（同じことを繰り返すべからず）
>すべての知識はシステム内において、単一、かつ明確な、そして信頼できる表現になっていなければならない。

同じような処理が複数あった場合、修正するのが面倒になったり、可読性が下がるなどの弊害を招きやすくなります。
「DRYの原則」を守ることで、プログラムの可読性・保守性が高くなります。



###CoC:Convention over Configuration（設定より規約）
Ruby on Railsにはファイル名の規約やテーブル定義の規約など様々な規約があります。
あらかじめ用意された規約に従ってアプリケーションを開発することで、ソースコードの記述量を少なくすることができ、見やすいソースコードになります。

決まった規約に従うことで、自分で設定する必要がなくなり、効率よくアプリケーションを開発できます。

***

>引用元：Railsガイド
>https://railsguides.jp/getting_started.html
[Java] jsoupを使って、認証が必要なプロキシ経由でHTTPSアクセスする

# 概要
jsoupを使ってプロキシ経由でアクセスする必要があったのですが、思いのほか手こずりました。

ポイントは以下の二点です。

 * 認証が必要なプロキシ経由でHTTPSアクセスをできないように、デフォルトで設定されている（Java 8から）。
 * `Authenticator.setDefault()`で、プロキシサーバーのユーザーIDとパスワードを指定する必要がある。

# 環境
jsoup

```xml:pom.xml
<!-- https://mvnrepository.com/artifact/org.jsoup/jsoup -->
<dependency>
    <groupId>org.jsoup</groupId>
    <artifactId>jsoup</artifactId>
    <version>1.12.1</version>
</dependency>
```

Javaバージョン： 8

# OK例

```java
// 「認証が必要なプロキシ経由でのHTTPSアクセスを禁止」という設定を解除します。
// デフォルトではこのプロパティに"Basic"が指定されており、Basic認証が利用できないようになっていますので、"Basic"の設定を解除するため、空文字で上書きします。
System.setProperty("jdk.http.auth.tunneling.disabledSchemes", "");

// プロキシサーバーのID/パスワードをAuthenticator経由で渡すようにします。
Authenticator.setDefault(new Authenticator() {
    @Override
    protected PasswordAuthentication getPasswordAuthentication() {
        return new PasswordAuthentication("{プロキシサーバーのユーザーID}", "{プロキシサーバーのパスワード}".toCharArray());
    }
});

Jsoup.connect("{アクセスしたいURL}")
  .proxy("{プロキシサーバーのID or ホスト名}", {プロキシサーバーのポート番号})
  .get();
```

# NG例

```java
// Authorizationヘッダーを使うバージョン その1
Jsoup.connect("{アクセスしたいURL}")
  .header("Authorization", "Basic " + Base64.getEncoder().encodeToString("{プロキシサーバーのユーザーID}:{プロキシサーバーのパスワード}".getBytes()))
  .proxy("{プロキシサーバーのIPアドレス or ホスト名}", {プロキシサーバーのポート番号})
  .get();
```

```java
// Authorizationヘッダーを使うバージョン その2 （ヘッダーの値に"Basic "の文字列を指定しない）
Jsoup.connect("{アクセスしたいURL}")
  .header("Authorization", Base64.getEncoder().encodeToString("{プロキシサーバーのユーザーID}:{プロキシサーバーのパスワード}".getBytes()))
  .proxy("{プロキシサーバーのIPアドレス or ホスト名}", {プロキシサーバーのポート番号})
  .get();
```

```java
// Proxy-Authorizationヘッダーを使うバージョン その1
Jsoup.connect("{アクセスしたいURL}")
  .header("Proxy-Authorization", "Basic " + Base64.getEncoder().encodeToString("{プロキシサーバーのユーザーID}:{プロキシサーバーのパスワード}".getBytes()))
  .proxy("{プロキシサーバーのIPアドレス or ホスト名}", {プロキシサーバーのポート番号})
  .get();
```

```java
// Proxy-Authorizationヘッダーを使うバージョン その2 （ヘッダーの値に"Basic "の文字列を指定しない）
Jsoup.connect("{アクセスしたいURL}")
  .header("Proxy-Authorization", Base64.getEncoder().encodeToString("{プロキシサーバーのユーザーID}:{プロキシサーバーのパスワード}".getBytes()))
  .proxy("{プロキシサーバーのIPアドレス or ホスト名}", {プロキシサーバーのポート番号})
  .get();
```

```java
// 「jdk.http.auth.tunneling.disabledSchemes」の指定なし

Authenticator.setDefault(new Authenticator() {
    @Override
    protected PasswordAuthentication getPasswordAuthentication() {
        return new PasswordAuthentication("{プロキシサーバーのユーザーID}", "{プロキシサーバーのパスワード}".toCharArray());
    }
});

Jsoup.connect("{アクセスしたいURL}")
  .proxy("{プロキシサーバーのID or ホスト名}", {プロキシサーバーのポート番号})
  .get();
```

いずれの場合も、以下のとおりエラーとなりました。

```terminal
java.io.IOException: Unable to tunnel through proxy. Proxy returns "HTTP/1.1 407 Proxy Authentication Required"
```

# 参考（謝辞）
大変参考になりました！ありがとうございます！
https://qiita.com/kaakaa_hoe/items/d4fb11a3af035a287972
Kuberenetes Dashboard Upgradeとtoken pasteをスキップする方法

##背景
1. Tokenを毎回ペーストするのが面倒だなぁと感じてなんとかpbcopy/pbpasteでtokenをブラウザーにParseできないのか調べてたところ、同僚からStagingだしenable-skip-login & disable-settings-authorizerを使えばいいと言われてやり方を調べました。
2. dashboardのバージョンも上がってたのでついでにアップグレード。


##参考にした記事 
**Upgrade**
- https://docs.aws.amazon.com/eks/latest/userguide/dashboard-tutorial.html

**enable-skip-login & disable-settings-authorizer**
- https://devblogs.microsoft.com/premier-developer/bypassing-authentication-for-the-local-kubernetes-cluster-dashboard/

**pbcopy&pbpaste**
- https://gist.github.com/cmosh/d6559e663b615b11dc3d9f05b8f53a25

##v1.10.1 & v2.0.0-beta4のテスト

**v1.10.1**
metrics-server-amd64:v0.3.3
kubernetes-dashboard-amd64:v1.10.1


| Test1 [doesn’t work]      |       Test2 [Works] |    Test3 [doesn’t work]  |
|:-----------------|:------------------|:------------------|
| Just adding --enable-skip-login & --disable-settings-authorizer             |              adding --enable-skip-login & --disable-settings-authorizer & clusterrolebinding |        Adding just clusterrolebinding        |
|As of 1.7+ Dashboard no longer has full admin privileges granted by default.- |||


**v2.0.0-beta4** 
metrics-server-amd64:v0.3.4¥5
kubernetesui/metrics-scraper:v1.0.1
kubernetesui/dashboard:v2.0.0-beta4

|Test 4 [works]|Test 5 [doesn’t work]|Test 6 [works]|
|:-----------------|:------------------|:------------------|
|Deploy as it is|adding --enable-skip-login & --disable-settings-authorizer|adding --enable-skip-login & --disable-settings-authorizer + cluster-admin under roleRef|

**Test 6を採用**

 
##v1.10.1の気になる点
another thing to note for when we upgrade to kubernetes 1.16
https://github.com/kubernetes/dashboard/issues/4332
 
 
##見落としやすい点

|      |       v1.10.1 |    v2.0.0   |
|:-----------------|:------------------|:------------------|
| eks-admin-service-account.yaml             |            Namespace:  kube-system |        Namespace: kube-system        |
| kubernetes-dashboard.yaml           |            Namespace: kube-system |       Namespace: kubernetes-dashboard       |
|metrics-server/1.8+/ |Namespace: kube-system |Namespace: kube-system|
|URL |http://localhost:$PORT/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/ | http://localhost:$PORT/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/|




##学んだこと
- dashboard設定方法
- token
Kubernetes Cronjobs (lifecycle PostStart PreStop)+ Slack notification


#これを設定した背景
- 元々はDB BackupをS3にコピーするCronjobではhttps://github.com/benjamin-maynard/kubernetes-s3-mysql-backup を参考にSlack notifyできるようにしてた。
- 他のCronjobを設定したはいいがFail/Successしたか一々確認するのは面倒なので、Fail/Success結果をSlackで通知する方法を模索した。


##参考にした記事
- https://kubernetes.io/docs/tasks/configure-pod-container/attach-handler-lifecycle-event/
- https://kubernetes.io/docs/concepts/workloads/pods/pod/#termination-of-pods
- https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#hook-details
- https://www.cyberciti.biz/faq/linux-bash-exit-status-set-exit-statusin-bash/
- https://stackoverflow.com/questions/8903239/how-to-calculate-time-elapsed-in-bash-script/8903280


##最初に考えていた方法

lifecycleのPostStartとPreStopを使って

1. PostStart > JobA has started messageをslack
2. JobA
3. PreStop > JobA has completed messageをslack

これだとCronjobがFail/Successしたか確実ではない

##PreStopはこの用途に適していなかった
lifecycleのPreStop
A call to the preStop hook **fails** if the container is already in terminated or completed state. 
- https://github.com/kubernetes/kubernetes/issues/55807

##次に考えた方法

1. slack_start.sh > JobA has started messageをslack
2. JobA
3. slack_stop.sh > JobA has completed messageをslack

これだとCronjobがFail/Successしたか確実ではない

##最終的に使った方法
ConfigMapでwrapper.shをpodにつけてJobAをinputStream $1とする。
これだとCronjobがFail/Successしたか確実。

```
wrapper.sh JobA
```

wrapper.shはシンプルなもので

```
$cmd1
status=$?
```

- \$1 JobAがSuccess($status -eq 0)したらMSG_SUCCESSをslack
- \$1 JobAがFail(else)したらMSG_FAILをslack



ついでに各Cronjobが何秒かかったかもわかるようにした。

```
duration=$SECONDS
MSG_DURATION=$(echo "($(($duration / 60))m$(($duration % 60))s)")
```


##ハマったこと

- JobA内にvariableやmkdir -p /tmp/reportなどがある時

```
wrapper.sh "yesterday=`date -d 'yesterday' '+%F'` python_path=/usr/local/bin/python $python_path app.py mkdir -p /tmp/report"
```

- JobAがマルチラインの時　＞　&&を使うことで走るように
- defaultModeのjsonnetでの使い方

| jsonnet       |yaml (decimal)  |
|:-----------------|:-----------------|
| defaultMode: std.parseOctal('0755')             |defaultMode: 493        |


##学んだこと
- wrapper.sh
- configMap defaultMode
- lifecycleのPostStartとPreStop
- slack notification
Unity C# コルーチンの覚え書き

##コルーチンでクリック待ちできない？
Unity独習2週間くらい。
クリックorキー入力を待ってnGUIのテキストを変更したかったが、Updateメソッドで条件分けするのが面倒くさかった。
調べてみるとコルーチン（Coroutine）が使えそうとのことだったので試してみたがハマってしまった。

```sample.cs
void Hoge(){ //コルーチンを呼び出す側メソッド
    foo(); //任意の処理
    StartCoroutine("Fuga") //コルーチン呼び出し
    bar(); //任意の処理
}
IEnumerator Fuga(){ //コルーチン
    //マウス左クリックを待つ処理
    yield return new WaitUntil(() =>
    Input.GetMouseButtonDown(0))
}
```
上記コードを実行すると、foo()を実行後にコルーチンFuga()が呼び出されクリック待ち状態に移行。クリックすることでbar()が実行されるはず……と思っていた。
が、結果は違っていた。foo()の直後にクリック待ち状態に移行することなくbar()が実行されてしまう。どうにかfoo()とbar()の間にクリック待ちを仕込みたかったが、ハマってしまったというわけ。

##解決
どうやらプログラムがforkする（詳しくはないので正しい言葉かは分からない）ようで、処理と処理の間にクリック待ちを挟みたい場合は、すべてをコルーチンの中に記述するほかないらしい。

```sample02.cs
void Hoge(){ //コルーチンを呼び出す側メソッド
    StartCoroutine("Fuga") //コルーチン呼び出し
}
IEnumerator Fuga(){ //コルーチン
    foo(); //任意の処理
    //マウス左クリックを待つ処理
    yield return new WaitUntil(() =>
    Input.GetMouseButtonDown(0))
    bar(); //任意の処理
}
```
nGUIテキストをクリックするたびに変更する（たとえばADVのテキスト送りなど）場合、表示処理すべてをコルーチン内部に書くということなんかしら。
あんまりスマートな書き方ではない気がするね。ただ一応、ハマりからは脱出できたからよしとします。ヨシ！
【deno】denopkg.com経由でインストールしたモジュールを利用しようとすると、「An import path cannot end with a '. ts'extension.」のエラーが発生する

https://qiita.com/uki00a/items/817442b00dc8f3b5696d の続き。

deno.landからダウンロードしたモジュールについては、[deno_ls_plugin](https://github.com/kitsonk/deno_ls_plugin)を導入することで、「An import path cannot end with a '. ts'extension...」のエラーを回避できるようになった。

しかし、demを使用してdenopkg.comから[dinatra](https://github.com/syumai/dinatra)をインストールしようと試みたところ、上記ページと同様の事象が発生してしまった。

```sh
$ dem add https://denopkg.com/syumai/dinatra@v0.7.1
```

![Screenshot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240412/60ebc181-c2bc-1ae8-ac0d-3774e6954962.png)

## 前提

Vim等のエディタを利用する場合を想定しています。
vscodeを利用する場合は、[vscode-deno](https://marketplace.visualstudio.com/items?itemName=justjavac.vscode-deno)プラグインを導入することで解決すると思います。

## 解決策

[typescript-deno-plugin](https://github.com/justjavac/typescript-deno-plugin)を導入し、tsconfig.jsonで読み込むように設定することで解決する。

```sh
$ yarn add -D typescript-deno-plugin typescript
```

```json:tsconfig.json
{
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "baseUrl": ".",
    "paths": {
      "deno": ["./types/deno.d.ts"],
      "https://*": [
        "../../../.cache/deno/deps/https/*"
      ],
      "http://*": [
        "../../../.cache/deno/deps/http/*"
      ]
    },
   "plugins": [{ "name": "typescript-deno-plugin" }]
  }
}
```

導入後、以下のように型定義を解決できるようになった。

![Screenshot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240412/5b0582ec-7263-d1a8-0385-660a2d057542.png)

## 原因

demによって作成された`./vendor/https/denopkg.com/syumai/dinatra/mod.ts`を確認してみると、「An import path cannot end with a '. ts'extension...」のエラーが発生していた。

```typescript:./vendor/https/denopkg.com/syumai/dinatra/mod.ts
export * from 'https://denopkg.com/syumai/dinatra@0.7.1/mod.ts';
```

試しに、`~/.cache/deno/deps/https/denopkg.com/syumai/dinatra@0.7.1`ディレクトリを確認してみたところ、`mod.ts`というファイルは存在せず、代わりに`mod.ts.headers.json`というファイルが存在した。

内容は下記の通り。

```json:~/.cache/deno/deps/https/denopkg.com/syumai/dinatra@0.7.1/mod.ts.headers.json
{"redirect_to":"https://raw.githubusercontent.com/syumai/dinatra/0.7.1/mod.ts"}
```

この`mod.ts.headers.json`が正しく解決されていないことが原因であった。


typescript-deno-pluginは、`*.headers.json`ファイルが存在する場合、`redirect_to`の参照先に従って、型定義を解決する処理が行われているため、このプラグインを導入することで問題が解決した。
２つのリストを重複要素を排除して結合する

## Stream.concat()とdistinct()を組み合わせる
* 重複要素を排除しつつ２つのリストを結合したい場面に出くわし、StreamAPIを使って綺麗できないものだろうかと調べていたら[Stream.concat()](https://docs.oracle.com/en/java/javase/13/docs/api/java.base/java/util/stream/Stream.html#concat(java.util.stream.Stream,java.util.stream.Stream))という便利なモノがあったので、これと`distinct()`を組み合わせることで上手くできました。

```java
List<Integer> list1 = List.of(1, 2, 3, 4, 5);
List<Integer> list2 = List.of(0, 4, 5, 6, 7);
```

* 上のリスト`list1`と`list2`を重複要素を排除して結合

```java
List<Integer> result = Stream.concat(list1.stream(), list2.stream())
        .distinct()
        .sorted(Comparator.naturalOrder()) // 昇順でソート
        .collect(Collectors.toList());

result.forEach(System.out::println); // -> 0,1,2,3,4,5,6,7
```
脱出ゲームの作り方　２

###DrawerPanelで引き出しをクリックするとアイテムを取得できるようにする

◇ボタン
DrawerPanelの下に、RoomPanelで作成したボタンをコピペして作成する
TriggerButtonList-TriggerButton
ボタンは1つでいいので、右クリック-Unpack Prefabでプレファブを解除する
ボタンの位置とサイズを調節する（W200 H200）

:point_up:
プレファブを解除する理由
プレファブのままなら、プレファブをいじったときに勝手に変更されてしまうかもしれないから

◇表示するパネルの画像
DrawerPanelの下にUI-Imageを作成しLightBulbImageとする
電球の画像をセットする
SetNativeSizeボタンで、そのままでは大きすぎるので1/10位のサイズに調整する

◇テキスト
DrawerPanelの下にUI-Textを作成し、AlertTextとする

位置とサイズを調節する（W400 H50）
文字の中央寄せ
テキスト「電球を手に入れた」
フォントサイズ36

◇スクリプト
DrawerManagerスクリプトを作成し、DrawerPanelに張り付ける

電球の画像とテキストをGameObject型の変数として宣言する。

    [SerializeField] GameObject LightBulbPanel;
    [SerializeField] GameObject alertText;

※GameObjectはデータ型（Unity C#の）

:point_up:
**[SerializeField]**
Unityエディタから設定できるようにする
※参照　Udemy 「Unityゲーム開発入門」38. 別オブジェクトの操作方法
※publicとの違い
エディタから設定できるようになるところは共通
publicは、他のスクリプトでも操作できるようにする
（使える場所が広いが、エディタ以外で書き換えさせたくない場合は[SerializeField]を使うほうが安全）



 引き出しが押されたらアイテム取得画面を表示する
 1. 電球の画像をだす
 2. Textをだす

```csharp

public class DrawerManager : MonoBehaviour
{
    [SerializeField] GameObject LightBulbPanel;
    [SerializeField] GameObject alertText;

    void Start()
    {
        LightBulbPanel.SetActive(false);
        alertText.SetActive(false);
    }

    public void OnClickTrigger()
    {
        LightBulbPanel.SetActive(true);
        alertText.SetActive(true);
    }
}
```

◇変数にオブジェクトを設定

スクリプトに変数を宣言すると、
InspecterでDrawerPanelオブジェクトのDrawerManagerスクリプトに

LightBulbPanel
alertText

が出ているので、それぞれに電球画像とテキストをセットする

◇TriggerButtonを押したら電球パネルとテキストを表示
InspectorでTriggerButtonのButtonコンポーネントの On Click() にDrawerPanelオブジェクトをセットして、
DrawerManagerに表示される関数をからOnClickTrigger()を設定する






###元の画像に戻る

電球の画像をクリックするとアイテム取得画面を非表示にする
:point_up:
※戻るボタン、他のパネルを表示させるボタンも、自分以外の画像を表示/非表示させているだけで、構造は同じ

```csharp

    // 電球の画像をクリックすると電球画像を非表示にする
    public void OnClickImage()
    {
        LightBulbPanel.SetActive(false);
        alertText.SetActive(false);
    }
```
LightBulbImageにAdd CompornentでButtonを設定する
InspectorでLightBulbImageのButtonコンポーネントの On Click() にDrawerPanelオブジェクトをセットして、
DrawerManagerに表示される関数をからOnClickImage()を設定する




###アイテム取得画面（電球画像とテキスト）の表示・非表示を関数にする

```csharp

    void LightBulbSetActive(bool isShow)
    {
        lightBulbPanel.SetActive(isShow);
        alertText.SetActive(isShow);
    }
```

完成ソースコード

```csharp

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DrawerManager : MonoBehaviour
{
    [SerializeField] GameObject lightBulbPanel;
    [SerializeField] GameObject alertText;

    void Start()
    {
        LightBulbSetActive(false);
    }

    void LightBulbSetActive(bool isShow)
    {
        lightBulbPanel.SetActive(isShow);
        alertText.SetActive(isShow);
    }

    // 引き出しが押されたら
    // 1.電球の画像をだす
    // 2.Textをだす
    public void OnClickTrigger()
    {
        LightBulbSetActive(true);
    }

    // 電球の画像をクリックすると電球画像を非表示にする
    public void OnClickImage()
    {
        LightBulbSetActive(false);
    }
}

```


##教材
**Unityゲームスタジオ スタジオしまづ**
**【Unity】初心者からの脱出！？　脱出ゲームの作り方　その２**
https://youtu.be/wMd0gtzJARU
VS Code の Remote Development で X11 Forwarding する(Windows版)

English translation below.

VS Code の Remote Development，便利ですね．
VS Code のターミナルで作業してて GUI が使いたくなったとき，通常の手順で使おうとしたら使えなかったので，なんとかした記録です．


# 1. 前提と環境
- Windows 10
- VS Code 1.38.1
- Remote Development 0.39.6
- Xming 6.9.0.31
- Ubuntu 18.04 (WSL)
- OpenSSH_7.6p1 Ubuntu-4ubuntu0.3, OpenSSL 1.0.2n  7 Dec 2017 (WSL)

普段は WSL で DISPLAY 環境変数を設定して ssh すれば X Window が使えます．

``` bash
$ export DISPLAY=localhost:0.0
$ ssh server -X
$ xclock
```

ですが VS Code の Remote Development 上では DISPLAY 環境変数が設定されていないので，X 転送できません．

``` bash
$ xclock
Error: Can't open display:
```

# 2. x11 転送してくれる bat ファイルを作る

さて，なぜ VS Code のターミナルで X Window が使えないのかというと，VS Code はWSL 側では無く Windows 側の ssh コマンドを使って接続しているからです．なので Windows 側で DISPLAY を設定する必要があります．

しかし，Windows側の ssh コマンド(open ssh)では DISPLAY 環境変数を翻訳してくれる機能が無いので失敗してしまいます．今回は WSL の ssh コマンドを使って運用でカバーします．
WSL で DISPLAY 環境変数を設定して，ssh コマンドを叩くバッチファイルを作ります．

``` bat:x11ssh.bat
@wsl export DISPLAY=localhost:0.0; ssh %*
```

バッチファイルは実行するコマンドをそのまま echo する仕様なのですが，@から始まる行はされません．バグるのが怖いので付けます．
ここで一旦このバッチファイルで SSH, X11 転送ができるか確認してください．

``` bat:cmd
> x11ssh server -X
$ xclock
```
例えば `.ssh/config` を設定していて Remote Development に config を読み込ませている場合，Windows 側と WSL 側の config を揃えておく必要があります．例えば私は git で config を管理しているのでこのあたりの不整合は発生しません．

# 3. Remote Development の設定を変更
通常，Remote Development ではシステム標準の ssh コマンドを使いますが，このバッチファイルを変わりに使ってもらうようにします． `Ctrl + ,` で設定を開き， `Remote.SSH: Path` に先程のバッチファイルのパスを設定します．
> An absolute path to the SSH executable. When empty, it will use "ssh" on the path or in common install locations.

このとき，他のオプションによってはうまくいかない場合があります．例えば `Remote.SSH: Use Local Server` を有効にしたらうまくいきませんでした．私の環境では，デフォルト設定から `Path` のみを変えた状態ならば成功しました．

この状態で X11 アプリを叩いて開ければ成功です．

``` sh
$ xclock
```


#4. 最後に
うちではうまく行かなかったよ・更にこうしたらできたよとかあればコメントください．
あと役に立ったよ！ という場合はぜひ `いいね` して Twitter 等で広めていただけると嬉しいです．

#5. English TL;DR
Create a batch file for starting SSH using X11 and set it to `Remote.SSH: Path` of Remote Development.
Node.js のWebサーバーをWindowsで作る ・環境構築

#Node.jsのWebサーバーをwindows環境で作ってみた
Node.jsの知識が必要になったため、windowsでの環境構築の方法をまとめてみました。

今回はversion8系を使っていましたので以下のコードを参照しました。
最新版の11系においてもメソッドの変更等は無いようなので、
そのまま利用可能です。

https://nodejs.org/docs/latest-v8.x/api/synopsis.html

#Webサーバー
``` server.js
const http = require('http');

const hostname = '127.0.0.1'; 

const port = 3000;
//空いているポート番号を適当に

const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello, World!\n');
});

server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});
```


#サーバーを立ち上げる
server.jsの保存をしたらファイルを実行

``` terminal
node server.js
```

以下のように表示が出力されます。

```terminal
Server running at http://127.0.0.1:3000/
```

#ブラウザで動作確認
そうしたら、ブラウザで
http://127.0.0.1:3000/
にアクセスをすると、Hello World!が表示されるはずです。
C言語の復習(switch文）

switch文というと結構初心者の中でもわかりやすいような気がします。
if文が続いてるだけのイメージです。
例えば

```c
#include<stdio.h>

int main (void)
{
    int aa=8;

    if( aa %3 == 0){
        printf("３で割れる数字です。");
    }
    else if(aa %3 == 1){
        printf("３で割ると剰余は１です。");
    }
    else{
        printf("３で割った剰余は２です。");
    }
}
```
これをswitch文で直すと
aa % 3 == 2になれば良いわけですから、

```c
#include<stdio.h>
int main (void)
{
    int aa=8;

    switch(aa % 3){

        case 0 :
            printf("３で割れる数字です。");
            break;

        case 1 :
            printf("３で割ると剰余は１です。");
            break;

        case 2 :
            printf("３で割った剰余は２です。");
            break;
    }
}
```
という感じにしました。
switch文というのはcase の後は整数型じゃないとだめなので使い方次第なんだろうなと感じました。
IOTでのモーター制御などで使った覚えがあります。
また、触れる機会があればやりたいですね。switch文！
でわでわ、ばいばい。
cesiumpy 0.3.3 でビューワが表示されなかったので、URLを修正した


# 問題
環境はUbuntu18.04LTS、Miniconda3（Anaconda3でも同じです）、conda仮想環境にはpython3.6を指定。
CesiumJSをJupyter Notebookで使用したい。
PyPIで公開されている cesiumpy 0.3.3 を conda-buildでビルドして tar.bz2 パッケージにしてから、インストールした。
（結論として、ビルド・インストール手順は間違いなかった）
手順はざっくり以下のような感じ。

```console
(base) ~$ conda create -n build python=3.6
(base) ~$ conda activate build
(build) ~$ conda install conda-build
(build) ~$ mkdir work
(build) ~$ cd work
(build) ~/work$ conda skeleton pypi cesiumpy
(build) ~/work$ conda build cesiumpy
(build) ~/work$ cp $CONDA_PREFIX/pkgs/cesiumpy-0.3.3-py36_0.tar.bz2 ./
(build) ~/work$ conda deactivate
(base) ~/work$ conda create -n myenv python=3.6
(base) ~/work$ conda activate myenv
(myenv) ~/work$ conda install geopy traitlets six scipy shapely
(myenv) ~/work$ conda install ./cesiumpy-0.3.3-py36_0.tar.bz2 
(myenv) ~/work$ python -c "import cesiumpy"
/home/USERNAME/miniconda/envs/myenv/lib/python3.6/site-packages/cesiumpy/extension/geocode.py:12: UserWarning: Since July 2018 Google requires each request to have an API key. Pass a valid `api_key` to GoogleV3 geocoder to hide this warning. See https://developers.google.com/maps/documentation/geocoding/usage-and-billing
  _GEOCODER = GoogleV3()
```
ModuleNotFoundErrorではなく、UserWarningが出ているので、インストールはうまくいっていると判断。



```python
import cesiumpy
v = cesiumpy.Viewer()
v
```

何も表示されない。
> 去年、GitHubからcloneしたときは、そのまま使用できたのに・・・orz

# 原因
ブラウザの開発者ツールでコンソールを確認すると、Cesium.jsがダウンロードできないというエラーが発生している模様。
取り急ぎ、GitHubのIssuesを確認したところ、関連する内容がありました。

[Example from README gives Google warning and shows nothing #77](https://github.com/sinhrks/cesiumpy/issues/77)
[Unable to pull resources from cesiumjs.org due to CORS #8050](https://github.com/AnalyticalGraphicsInc/cesium/issues/8050)

# 対処
URLはbase.pyにハードコードされていました。
cesiumpyパッケージ内のbase.pyの_load_scripts()メソッドのURL（js変数とcss変数）を修正したら、表示されました。

修正前

```python
    @property
    def _load_scripts(self):
        js = """<script src="https://cesiumjs.org/Cesium/Build/Cesium/Cesium.js"></script>"""
        css = """<link rel="stylesheet" href="https://cesiumjs.org/Cesium/Build/Cesium/Widgets/widgets.css" type="text/css">"""

        return [js, css]
```

修正後

```python
    @property
    def _load_scripts(self):
        js = """<script src="https://cesium.com/downloads/cesiumjs/releases/1.62/Build/Cesium/Cesium.js"></script>"""
        css = """<link rel="stylesheet" href="http://cesium.com/downloads/cesiumjs/releases/1.62/Build/Cesium/Widgets/widgets.css" type="text/css">"""

        return [js, css]
```

> 2019/10/18 追記
> 修正対象のbase.pyファイルの場所は、findコマンドで検索してください。
> 
> ```console
> $ find $CONDA_PREFIX -name base.py | grep cesiumpy
> ```
makefile と build.ninja の比較。 make から ninja への移行検討メモ

# これは何

[GNU make](https://www.gnu.org/software/make/) から [ninja](https://ninja-build.org/) に移行を検討中のメモです。

# 想定読者

`makefile` を自分でかける人
`.PHONY: clean` を毎回書くのに飽き飽きした人
素の make の動作が遅いなぁと思う人
ninja 向けのメタビルドツールを作りたい人

# ninja って何?

https://mattn.kaoriya.net/software/ninja/20140121141906.htm こことか読んでください。

# hello.c のビルドを比較

hello world を出力する `hello` を `hello.c` でビルドする例を `makefile` と `build.ninja` で示します。
これを試すだけで ninja がいいなぁと思えてきました。

## makefile for gcc の場合

`makefile` の例を示します。デフォルトルールを全力で利用した場合、下記のようになると思います。
ninja との比較がしやすいように、暗黙的に定義されている変数だけを使用しています。

```makefile:makefile
CFLAGS = -Wall -Os -MMD -MP
CPPFLAGS = -DNDEBUG

.PHONY:clean
hello:hello.o
clean:
	$(RM) hello hello.o hello.d
-include hello.d
```

記述量は非常に少なく、簡潔です。
makefile の暗黙ルールに精通した人なら、こんなもんだなぁ程度に感じます。
makefile に精通していない人は、 `hello.o:hello.c` のような記述不要な依存関係とか書いたりして、余計な記述が増えがちです。
ビルド実施後、 `hello`, `hello.o`, `hello.d` の 3ファイルが生成されます。
`clean` ルールを書くのが面倒くさいです。

## ninja.build for gcc の場合

上記 makefile と同等の build.ninja を示します。 ninja は、暗黙のルールや変数を持ちません。
そのため、すべて明示的に定義しています。

```:build.ninja
cc = cc
cflags = -Wall -Os
cppflags = -DNDEBUG

rule compile
     deps    = gcc
     depfile = $out.d
     command = $cc -MMD -MP -MF $out.d $cflags $cppflags $target_arch -c -o $out $in

rule link
     command = $cc $ldflags $target_arch $in $loadlibes $ldlibs -o $out

build hello: link hello.o
build hello.o: compile hello.c
```

makefile に比べて記述量が増えていますが、何をやるのかがすべて記述されるのでわかりやすいです。
makefile の場合、暗黙ルールや変数を理解しないと何をやるのかが全くわからないものでしたが、ninja の場合は違います。

ビルド実施後、 `hello`, `hello.o`, `.ninja_deps`, `.ninja_log` の 4ファイルが作成されます。 `.d` ファイルは消え去ります。この、`.d` が残らないところがポイントです。 複数の `.d` ファイルを元に一つの `.ninja_deps` を作成し、依存情報を集約してくれています。ビルドを行う際、依存関係を捜査してどのファイルがリビルド必要かを調べますが、細かいファイルをたくさん開くよりも、一つの大きなファイルを開く方が実行時間が短くてすみます。これがいいところです。

ninja は、組み込みオプションで clean 操作ができます。 `ninja -t clean` です。 build 文によって生成されるファイル(ここでは `hello` と `hello.o`) が削除されます。make に比べて非常に気が利いていると感じます。

## ninja.build for msvc

Microsoft Visual Studio での例を示します。makefile の方は省略します。というか、調べる気が無くなったので。。。

```:ninja.build
msvc_deps_prefix = メモ: インクルード ファイル:
cflags = /Wall /Os
cppflags = /DNDEBUG

rule compile
     deps    = msvc
     command = cl /nologo /showIncludes $cflags $cppflags /c /Fo$out $in

rule link
     command = link /NOLOGO $ldflags $target_arch $loadlibes $ldlibs /OUT:$out $in

build hello.exe: link hello.obj
build hello.obj: compile hello.c
```

msvc_deps_prefix は、実行環境の codpage で変わります。この例は、932 です。
windows 環境に make をインストールしようとすると cygwin にするか msys にするか SFU にするかで迷いますが、 ninja だったら公式に `choco install ninja` で良いと示しているので迷うことがなくて気持ちがいいです。

# 感想

make は普段使用しない言語に対する暗黙ルールがたくさんあって、 `make -p` したときの変数リストを調べるのが面倒くさいと感じていました。ninja くらい割り切ってくれた方が、小さいプロジェクトだと書きやすくて良いと思った。
また、make の暗黙ルールじゃカバーできないようなビルドを実行したいとき、( .md から .pdf をビルドするような場合 ) ルールをすべて記述しなくちゃいけなくなるので、 build.ninja にすべてを記述することに違和感は特にない。

vpath や、 変数の置換展開とかといった便利な機能が ninja にはないので、 何かしらのスクリプトで build.ninja を生成する必要はある。もともとメタビルドツールの下回りを想定して設計しているので、当然といえば当然です。かなり仕様がシンプルなので、自前のスクリプトで build.ninja を作るのも楽そうではある。

# 参考リンク

[The Ninja build system](https://ninja-build.org/manual.html)
【Go】【React】GORMで検索機能を実装 

GoとReactで検索機能を実装しました。GORMとechoを使っています。
ECサイトのトップページでお客さんが商品検索をできるようなイメージです。
#React
```React:CustomerTop.js
class CustomerTop extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      products: [],
      search: '',
    };
  }

  componentDidMount() {
    this.getCustomerProducts();
  }

  getCustomerProducts(order) {
    axios
      .get(`/customer/products?request=${this.state.search}`)
      .then(response => {
        this.setState({ products: response.data });
      })
      .catch(function (error) {
        console.log(error);
      });
  }

  handleChange(e) {
    this.setState({ search: e.target.value });
  }

  handleSubmit(e) {
    e.preventDefault();
    this.getCustomerProducts();
  }

  render() {
    return(
      <div className="search-item">
        <form
          className="search-item__form"
          onSubmit={e => this.handleSubmit(e)}
        >
          <input
            value={this.state.search}
            type="text"
            className="search-item__item-search-field"
            onChange={e => this.handleChange(e)}
          />
          <div className="search-item__button">
            <span
              role="img"
              aria-label="search-mark"
              onClick={() => this.getCustomerProducts()}
            >
              🔍
            </span>
          </div>
       </form>
     </div>
  )}
}
```
パラメーターにrequestというキーをつけ、フォームに入力された文字をsetStateで更新して送ってあげます。
[【React】 FormでEnterキーを押した時にSubmitされるのを防ぐ](https://qiita.com/kibaa_go/items/eb903513b8cda60056d3)でも紹介していますが、フォームでEnterキーを押した時にSubmitされないようにhandleSubmitを作りました。

#GO
```Go:product.go
func (h *handler) getCustomerProducts(c echo.Context) error {
	var products []models.Product
	request := c.QueryParam("request")

	err = h.DB.Where("name LIKE ?", "%"+request+"%").Find(&products).Error
	if err != nil {
		return err
	}

	return c.JSON(http.StatusOK, products)
}
```

echoの[QueryParam](https://echo.labstack.com/guide/request)でパラメーターを見て、商品の名前に部分一致するものに絞り込んでreturnしてあげます。
以上です。
同じ端末上で Github のアカウントを複数使用するための設定

Github の練習でコンフリクト状態を発生させようと思い、当初は複数の Github アカウント使用を考えていましたが、実は通常できないことが分かりました。

調べて色々試した結果できるようになったので、メモとして残しておきます。

# ゴール

同じ端末(例えば同じノート PC)上で、複数の Github アカウントを使用できるようにします。

# 前提

既に 1 つの Github アカウントが使用できる状態であることとします。

# 環境

- OS ：Windows (ノート PC)
- Git：git version 2.20.1.windows.1

# やること概要

新しい Github アカウント取得時に使用するメールアドレス取得
　↓
新しい Github アカウント取得
　↓
SSH キー作成
　↓
公開鍵の内容を新しい Github アカウントに登録
　↓
「config」ファイル修正
　↓
Visual Studio Code のターミナルで情報登録
　↓
ファイルを push

# 例

あくまで例ですので、ご自分のアカウント、メールアドレスに置き換えてください。

- 作成する新しい Github アカウント　：　testb

- 新しい Github アカウント (testb) に紐づけられたメールアドレス　：　testb@gmail.com

- 作成する SSH キーのファイル　：　b_rsa

# やること詳細

(1)既に持っている Github アカウントに紐づけているメールアドレスとは異なるメールアドレスを取得します。
　⇒Google にて、例示している「testb@gmail.com」を取得します。
　　(取得方法については、今回の本筋から逸れるため、割愛します。)

(2)[Github サイト](https://github.co.jp/) にて、(1) で取得したメールアドレスを使用して新しいアカウントを取得します。
　⇒例示している「testb」を取得します。
　　(取得方法については、今回の本筋から逸れるため、割愛します。)

(3)最初に Git をインストールして使用できる「Git Bash」を起動し、SSH キーを作成します。
　
　`ssh-keygen -t rsa -b 4096 -C "testb@gmail.com" -f ~/.ssh/b_rsa`
　⇒例示している「b_rsa」で作成します。

　実行後、.ssh 配下に「b_rsa」と「b_rsa.pub」の 2 ファイルが作成されていることを確認します。

(4)「testb」で Github にログインし、「b_rsa.pub」の中身を登録します。
　
　1. Github 画面右上のユーザのマークをクリックし、「Settings」をクリックします。
　2. 画面左側の「Personal settings」の一覧の「SSH and GPG keys」をクリックします。
　3. 「SSH keys」の項目の「New SSH key」をクリックします。
　4. 「Title」に識別しやすい文字列、「Key」に「b_rsa.pub」の内容をコピペして、「Add SSH key」をクリックします。
　　⇒「SSH keys」の項目に登録した情報が表示されていることを確認します。

(5)「config」という名前のファイルに、以下の内容を追記して保存します。

Host の部分には、任意の文字列を指定します。


``` ~/.ssh/config(追記内容のみ記載)
Host b
HostName github.com
Identityfile ~/.ssh/b_rsa
Port 22
User git
```

(6)Visual Studio Code で push するデータが含まれるフォルダを開いて「Ctrl + Shift + @」でターミナルを表示し、以下を実行します。
　　
　　`git init`
　　`git remote add origin git@b:testb/test1.git`
　　`git config --global user.name "testb"`
　　`git config --global user.email testb@gmail.com`

　「git@b:testb/test1.git」の部分については、以下の通りです。
　　- b        ：(5) で config ファイルに追記した「Host」の部分と同じ内容
　　- testb    ：(2) で取得した Github アカウント名
　　- test1.git：作成済みのリポジトリ名

　　設定登録後は次のコマンドを実行し、「user.name」「user.email」「remote.origin.url」の項目から、正しい情報が登録されていることを確認します。
　　
　　`git config --list`

　なお、user.name と user.email については、操作する Github アカウントを変えるたびに実行し、その Github アカウントのものに変更する必要があります。

★★★★ここまででひと通りの設定は完了です。

(7)(6) で情報を登録後に、ファイルを push する場合は、以下のコマンドを実行します。

　　`git config --global user.name "testb"`
　　`git config --global user.email testb@gmail.com`
　　`git add .`
　　`git commit -m"コミットメッセージ"`
　　`git push origin master`

# 参考にした URL

- [複数アカウントを使い分ける方法](https://www.wakuwakubank.com/posts/380-git-multiple-account/)

- [GitHubで複数のアカウントを使う場合のSSHの設定](https://qiita.com/merrill/items/80a8d8a152e2483fa587)

- [複数のgitアカウントを使い分ける](https://qiita.com/0084ken/items/f4a8b0fbff135a987fea)

- [複数のgitアカウントを使用する場合](https://qiita.com/yamataku29/items/4744c9c70ad793c83b82)
for文を使わなくてすむ便利関数

#std::for_each関数とmem_funを使ってfor文を省略#

##std::for_each関数とは
【範囲の全ての要素に、指定された関数を適用する】と調べると書いてあります
おもに自分の使うタイミングはイテレータですかね

```ruby:before
for (auto it = m_objects.begin(); it != m_objects.end(); ) {
```

こうやってイテレータで最初と最後をfor文で動かすのではなく

```ruby:after
/*m_objectsの全ての要素にObje()関数を適用する*/
std::for_each(m_objects.begin(), m_objects.end(),Obje()）;
```

長さなどは変わらないことも多いけど入れ子が少なくなるのでいいと思う

##std::mem_fun関数とは

クラスのメンバ関数を呼び出すためのテンプレート関数です
ざっくり言いますと、間接的に、メンバ関数を呼び出すことができる
（自分も深くは知らない）:relaxed:

##本題
つまりこの二つを組み合わせれば

```ruby:qiita.rb
for (auto&& obj : m_objects) {obj->Draw3D();}
```
が

```ruby:qiita.rb
std::for_each(m_objects.begin(), m_objects.end(),std::mem_fun(&GameObject::Draw3D));
```
というようになります

 少しでもかっこよく見せたいならいいと思います。:thumbsup:
Azure API Managementのポリシーで複数の値をValidateする方法

※本記事は2019年10月17日時点での情報です。

#はじめに
API Managementのポリシーでは、様々なフィルターをかけることができるのでとても便利です。呼び出し元のIPアドレスフィルタや、Validate JWTなどエンタープライズでのユースケースに沿った機能が備わっています。

今回自分が悩んだのは、Validateしたい値が複数存在した時の管理方法です。例えばJWTのValidateをさせる際、認証されたユーザーのエイリアス情報を全てポリシーにハードコーディングするのは実用的ではないと思いました。値をどのように管理し、ポリシー側からはどのように呼び出したらいいのか考えましたので、アイデアを共有します。

#名前付きの値
API Managementのポリシー内で使える変数と値は、**名前付きの値**(英語名:Named values)で管理することが出来ます。
参照: https://docs.microsoft.com/ja-jp/azure/api-management/api-management-howto-properties

名前付きの値における変数名と値は1:1だと思い込んでいましたが、実際には1:多で登録を行うことができます。
(値は4096文字までとドキュメントに記載がありますので、ご注意ください。)

例えば、複数のIPアドレスを一つの変数として管理したい場合には、以下のようにカンマ区切りで登録をすることができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267543/c7c83da1-c7df-f7a0-cf1b-9cb7110e3462.png)

ポリシーに対してのハードコードでもこのカンマ区切りは作用しますが、今回は名前付きの値として登録をしました。

#ポリシーからの呼び出し
名前付きの値が設定出来たら、ポリシーから値を呼び出します。サンプルコードを以下に示します。

```
<choose>
 <when condition="@{
   if ("{{HogeSystemServer}}".Contains(context.Request.IpAddress))
   {
     return true; //リストとして登録したIPアドレスだけを許可する
   }
     return false; //その他からのアクセスは403を返す
   }" />
 <otherwise>
  <return-response>
    <set-status code="403" reason="Forbidden" />
  </return-response>
 </otherwise>
</choose>
```

choose, when, otherwiseは、C言語でいうところのif-else文やswitch文のイメージです。
参照: https://docs.microsoft.com/ja-jp/azure/api-management/api-management-advanced-policies#choose

これで一つの変数を用いて、複数の値をポリシーでValidateすることができます。

#テスト
実際にテストしてみます。

登録していないIPアドレスからのリクエストでは、以下のように403が返ってきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267543/dca39d76-0a58-0a6c-4072-0397d3f248f4.png)

許可されたIPアドレスからのリクエストは、200OKが返ってきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267543/1d1a41d4-1aa3-e4d0-0505-921125028e25.png)

#まとめ
API Managementを使い慣れている人からしたら当たり前のことなのかもしれませんが、個人的に少しハマったのでメモとして残すことにしました。上記関連でもその他でもTips等あったら教えて頂けますと幸いです。
レビュー反省会_html

# HTMLチュートリアル
- スペルミス
  - ` ×：heder  ○：header`
  - 単純なスペルミスに注意、必ずコーディングチェッカーにかけてエラーが出ていない確認すること
     - [Markup Validation Service](https://validator.w3.org/)

- pタグのmargin
  - pタグには**デフォルト**で上下方向のmarginが設定されている。
  - 勝手に余白が設定されるので、headerとfooterタグの内側でpタグを使用しないほうが良い

- インデント
  - 各行に入れるインデントは同じ階層であれば統一すること
初級者が覚えるべきGitコマンド５選

## はじめに
　Git（ギット）は、プログラムのソースコードなどの変更履歴を記録・追跡するための分散型バージョン管理システムである。 / [Wikipedia](https://ja.wikipedia.org/wiki/Git)より引用
　私はGitを使わない開発をしたことがないので、これが無かったら昔の人（今もかもしれないが）は一体全体どうやってバージョン管理をしていたのかと、まだまだペーペーのエンジニアですが愚考してしまいます。
　さて、この記事では私がチーム開発時によく使うGitコマンド5選を集めました。開発にはGitBucketやPyCharm、VSCodeを使っており、GUI操作で済ませた方が早いものは一般的に使われるコマンドでも載っていない事があるので、あくまで一例としてご参考ください。


## コマンド一覧
```terminal:terminal
git add .
```
①ステージ（バージョン管理の対象に追加）します。
個別にファイルを指定する事も出来ますが、面倒なので基本`.`で全て追加します。 

```terminal:terminal
git commit -m <変更内容等のコメント>
```
②コミット(その時のデータをバージョン管理の記録として保存)します。
コメントには、`FIX_`、`ADD_`、`DELETE_`等変更内容が分かるように接頭辞を付けたりしてます。
開発規模が大きい場合は、コミットの粒度を小さく明確にしておいた方が余計な躓きが減りそうです。
例）git commit -m ADD_顧客登録機能

```terminal:terminal
git push origin HEAD
```
③プッシュ（リモートリポジトリにローカルリポジトリのデータを反映）します。
これによってGitBucket上でも差分を確認できたり、プルリクが出来るようになります。

```terminal:terminal
git pull origin HEAD
```
④プル（リモートリポジトリのデータをローカルリポジトリに反映）します。
コンフリが発生したら、その箇所だけIDE上で修正してマージすれば最新のソースになっています。


```terminal:terminal
git checkout -b <新規作成するブランチ名>
```
⑤ブランチを新規作成して、ついでにそのブランチに移動します。
最新のソースを取ってから行いましょう。

## おわりに
使用頻度は高くないですが、余裕のある方はfetch, merge, revert, reset, show, log辺りを覚えておくと役に立つかもしれません。
それでは、よいGitライフを！
PostgreSQLに急に接続できなくなった時の対処法

# 問題
PythonからPostgreSQLにいつも通りにアクセスして作業しようと思ったらエラーで動かず。


```
OperationalError: could not connect to server: Connection refused
	Is the server running on host "localhost" (::1) and accepting
	TCP/IP connections on port 5432?
could not connect to server: Connection refused
	Is the server running on host "localhost" (127.0.0.1) and accepting
	TCP/IP connections on port 5432?
```
次にターミナルでPostgreSQLの中に入ろうとしたら今度は以下のようなエラーが。。。

```
~ $ psql hoge
psql: could not connect to server: No such file or directory
	Is the server running locally and accepting
	connections on Unix domain socket "/tmp/.s.PGSQL.5432"?
```

どうやらpostmaster.pidというファイルが原因らしいです。
postmaster.pidがどう悪さをしているのかはよくわからないです。
<img width="592" alt="スクリーンショット 2019-10-16 22.57.05.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515144/fa7056c1-38a5-a482-32b0-cf3405c3bed3.png">


# 解決法
上記のpostmaster.pidを取り除いてやります。
ターミナルで以下のコードを打って実行します。

```
$ rm -f /usr/local/var/postgres/postmaster.pid
$ brew services start postgres
```
PostgreSQLを再起動したら正常にstartできるようになりました。

ちなみにアラートを無視して強制的にファイルを削除するオプションの-fを付けずにremoveすると、errorもwarningも出ないので問題なく消せたように思えましたが、lsでディレクトリを見ると残っていました。postmaster.pidが無い状態でPostgreSQLを再起動する必要があり、どうしようかと。試しに-fを付けるとちゃんと消えました。

```
rm /usr/local/var/postgres/postmaster.pid
```
Rails6 を Heroku で動かす

以下は、rails6 でアプリを作ってからの作業

## Heroku でアカウント作成

- https://jp.heroku.com/

## Heroku CLI をインストール

- https://devcenter.heroku.com/articles/heroku-cli#download-and-install

## Heroku にログイン

```
$ heroku login
```

## DBのアドオンを導入
### Postgresql アドオン導入(クレジットカードの登録不要)

```sh
$ heroku addons:create heroku-postgresql
```

### Mysql アドオン導入(クレジットカードの登録が必要)

```sh
$ heroku addons:create cleardb:ignite
```

## 以降、コマンド実行

```sh
$ heroku create
$ git push heroku xxxx:master ← xxxxはブランチ名
$ heroku run rails db:migrate
$ heroku run rails db:seed
$ heroku open
```
pythonプログラム　EXE化【PyInstaller】

# 種類

pythonのEXE化では、以下のものがある

- pyinstaller
- py2exe
- cx_Freeze

がある。「py2exe」以外のライブラリの動作は確認しているが、「cx_Freeze」はsetupファイルが必要な上、tkinterによるバグがあり、setupファイルの作成方法にコツがいる。また、ライブラリの依存関係も気にする必要がある。「pyinstaller」はpip/condaで認識するライブラリ全てを引っ張ってきてexeファイルを作成する。下記に簡単に説明を追加する。

# pyinstallerの使い方

「--onefile」は「--noconsole」と一緒に使用すると、exeファイルは生成されるが、実行されない場合がある。tkinterを使用した場合、「--onefile」を使用した場合、実行までに時間がかかる（体感5s程度）。

所感であるが、「--onefile」は使用する必要がない気がする。また、私はAnacondaを使用しているが、pyinstallerはpip/condaで認識するライブラリ全てを引っ張ってきて、フォルダ/ファイルに詰め込むためか、不要なライブラリが入っている環境ではサイズが大きくなってしまう。そんため、コンパイル環境はしっかり別で用意すること。