OmniAICreator/Qiita-1.07M huggingface dataset:
Figmaの使い方

おはようございます。
今回はUIデザインをやる機会が増え、最近はFigma触りっぱなしなので備忘録として書いていきます

### この記事の目的
XDなど軽く触った事がある向けにFigmaの使い方についてまとめていきます
最後まで読めば簡単な画面ぐらいはできる可能性が・・・！

最初に基本的な使い方の説明、最後に気を付けるポイントを書いてますので目的に沿って飛んでください

#### 始め方
Figmaはブラウザ上で操作できますのでまずはアカウントを発行します　
[Figma公式](https://www.figma.com/)
ログインを求められるのでgoogle等のアカウントを利用して登録しましょう

これで使い始めれるようになります。

### 基本操作
#### フレーム作成まで
ログイン後、以下の＋アイコンをクリックすると編集画面に遷移します。
![新規作成.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149466/62ff71de-0fe1-9471-4c20-543857b7efc7.gif)

遷移後はこんな感じ
![スクリーンショット 2020-08-19 13.28.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149466/8dbe58d3-c811-4c8c-d73a-468296f12550.png)

あとはお絵かきタイム
以下のハイライト部分をクリックして編集箇所をドラック&ドロップするとFlameが作成できます
画面枠や、モーダルの画面枠を作成するときはフレームで作成するのがオススメです
![枠.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149466/b71185af-b959-6776-2dce-e0121141d2bd.gif)

もしくは右ナビゲーションバーに以下の項目が表示されるので該当箇所をクリックすると生成されます
![スクリーンショット 2020-08-19 13.36.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149466/1a4788bd-8259-df5d-ce52-18184fde0ce4.png)

#### 要素作成
枠が作成できたので要素を作っていきます
以下のハイライト部分をクリックして編集箇所をドラック&ドロップすると灰色で塗り潰された四角が作成できます
![枠.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149466/1de7b376-ed0c-b470-0baf-2d992b6176ee.gif)

一本線を引きたい場合は∨をクリックするとセレクト要素として色々でてくるので一本線をクリックして編集画面で操作すると引けます
※Shiftを押しながら引くと四角は正方形、一本線は25°間隔で線を引けます
![一本線.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149466/0d9238f6-c5ec-ac5e-a8f1-0842fded53b3.gif)

#### 要素編集
右側のメニューでは塗りつぶし、線の太さ・色などを設定出来ます
※四角要素は枠の丸みを設定出来ます
![css.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149466/20f46388-930c-2ee5-183f-b8c58526aae8.gif)

### Frame・Group・Component使い分け
ここからは似てるようで違うFrame・Group・Componentの使い分けについて書きます
上の概念は全て要素をまとめる時に使用します
しかし、微秒に使い勝手が違うので一つ一つ解説します

#### Group
これは大事な概念で、一般的なフォルダの使い方でOKです。
操作方法：対象をクリックして右クリック、Group selection
![グループ.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149466/facaf963-7427-4566-13e4-0de45ca33310.gif)

#### Frame
これも大事な概念で、Groupの上位版です。
Frameにすると
・別要素をドラッグ&ドロップすると自動的にFrame内の括りになる
![フレーム.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149466/ec4c62e4-246e-59bc-92d2-2951c6f8586e.gif)
・cssの基準点は画面全体からFlameになる（CSSとか使用する予定がある、設計図の反映するときはオススメ）
操作方法：対象をクリックして右クリック、Frame selection

#### Component
実はこれが一番大事な概念。親要素と同期機能
コピー元を編集すると、コピー先の対象要素も自動で変更されます。
大きいComponentで括ると部分変更しづらくなってしまうので、程よい単位で括るのが重要
操作方法：対象をクリックして右クリック、Create Component
![コンポーネント.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149466/8208e10f-403b-9167-a36d-a8b88a54adc6.gif)

### AutoLayout
これも多分大事な概念？
割と最近追加された機能で↓のgifの通り、子の要素を監視して自動で良い感じで調整してくれる機能です。（左右上下マージンの設定できます）
操作方法：対象をクリックして右クリック、 Add Auto Layout
![オートレイアウト.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149466/1a7bb5fc-d9d3-a737-531d-46c0014febd1.gif)

### 画面遷移図に便利なプラグイン
arrow autoというプラグインをいれると遷移図で必要な線が引けます。
使い方は簡単で、対象の要素二つを選択してLinkボタンを押すと線を引いてくれます。
Update Positionsをオンにすると要素を移動しても自動で線が追従してくれます。
![あろーオート.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149466/0304b56c-2c77-4075-f751-d7aa6957571a.gif)
【Gatsby】Typography.jsでNoto Sans JP(Google Fonts)を使う

## はじめに

gatsby-starter-blogをテンプレートに選ぶと、フォント系の情報は`src/utils/Typography.js`に保存されます。

```Typography.js
import Typography from "typography"
import Wordpress2016 from "typography-theme-wordpress-2016"

Wordpress2016.overrideThemeStyles = () => {
  return {
    "a.gatsby-resp-image-link": {
      boxShadow: `none`,
    },
  }
}

delete Wordpress2016.googleFonts

const typography = new Typography(Wordpress2016)

// Hot reload typography in development.
if (process.env.NODE_ENV !== `production`) {
  typography.injectStyles()
}

export default typography
export const rhythm = typography.rhythm
export const scale = typography.scale
```

これを改修して、Google Fontsを使えるようにしてみましょう。

## 1. モジュールのインストール

必要なモジュールをインストールします。

```bash
yarn add typography-theme-github
```

## 2. テーマを追加する

Wordpress2016を削除して、追加したモジュールを利用するようにします。

```Typography.js
import Typography from "typography"
import theme from "typography-theme-github"

const typography = new Typography(theme)

// Hot reload typography in development.
if (process.env.NODE_ENV !== `production`) {
  typography.injectStyles()
}

export default typography
export const rhythm = typography.rhythm
export const scale = typography.scale
```

## 3. テーマにNoto Sans JPを追加する

テーマがGoogle FontsのNoto Sans JPを扱えるように、`theme.googleFonts`を指定します。

```Typography.js
// importは省略

theme.googleFonts = [
  {
    name: "Noto+Sans+JP",
    styles: ["400"],
  }
]

const typography = new Typography(theme)
// 以下省略
```

このようにすることで、ブログでNoto Sans JPが使えるようになります。

## 4. ヘッダー、ボディそれぞれにNoto Sans JPを指定する

最後に追加したNoto Sans JPを適用しましょう。

```Typography.js
// importは省略

theme.googleFonts = [
  {
    name: "Noto+Sans+JP",
    styles: ["400"],
  }
]

theme.headerFontFamily = ["Noto Sans JP"]
theme.bodyFontFamily = ["Noto Sans JP"]

const typography = new Typography(theme)
// 以下省略
```

これでフォントを指定することができました。

## 備考

Typography.jsをもう少しちゃんと知ろうとする場合は、[Typography.jsによるフォントスタイルの設定まとめ](https://qiita.com/MikihiroSaito/items/1ab9d5eeea66a163648b#typography)がよいかと思います。

たとえばheaderとbodyそれぞれに異なるフォントを指定することも可能です。

```Typography.js
import Typography from "typography"
import theme from "typography-theme-github"

theme.headerFontFamily = ["M PLUS 1P"]
theme.bodyFontFamily = ["hannari"]
theme.googleFonts = [
  {
    name: "M+PLUS+1p",
    styles: ["400"],
  },
  { name: "hannari", styles: ["400"] },
]

const typography = new Typography(theme)

// Hot reload typography in development.
if (process.env.NODE_ENV !== `production`) {
  typography.injectStyles()
}

export default typography
export const rhythm = typography.rhythm
export const scale = typography.scale
```

Google Fontsの種類については、日本語であれば[Google Fonts + 日本語](https://googlefonts.github.io/japanese/)で確認できます。
【Flutter/ Dart】flutter build apk --release で生成した.apkをインストール＆起動すると直後に動作を停止してしまう現象への対応

## 概要

デバッグビルド`flutter build apk --debug`で生成した.apkは正常に動作するのに、リリースビルド`flutter build apk --release`で生成した.apkは起動直後にクラッシュしてしまう現象にしばらくの間悩まされていました。
一つ解決策を見つけたので、備忘と共有のために記します。

## 解決策

`android/app/build.gradle`に以下の設定を追加することで解消できました。

```.gradle:build.gradle
buildTypes {
   release {
      // ...
      shrinkResources false // 追加
      minifyEnabled false // 追加
   }
}
```

`shrinkResources`はリソースの圧縮で、`minifyEnabled`はR8によるコードの圧縮（実行の際に不要と判断したコードを削除するプロセス）のことです。それぞれを無効にすることで解決しました。


## 原因（と思われるもの）
R8によるコードの圧縮の際に本来は必要なコードまで削除されてしまい、起動直後にアプリが停止してしまっていたのではないかと推察しています。

## 副作用
コードやリソースが圧縮されなくなってしまうため、注意が必要です。

## 参考
[developer.android.com](https://developer.android.com/studio/build/shrink-code?hl=ja)
【ClarisConnect】FileMakerからGoogleカレンダーにスケジュール登録する（イベントidの保存編）

[前回の記事](https://qiita.com/Pepo_Yama/items/f84708ba5327eba764a9)も参照してください。

#この記事でできること
FileMakerからClarisConnectをつかってGoogleカレンダーに新規イベントを作成した際、Googleカレンダーのイベントidを取得しFileMakerへ保存する。
（イベントidが保存できれば、その後の削除・変更もカンタン）


#使ったもの
FileMaker Pro Advanced 18
FileMaker Server 18
ClarisConnect
GoogleCalender

#できたもの
### （操作）FileMakerから新規登録
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316038/1ce36c8a-524e-6d82-2915-81f2df41efc6.png)

### （結果１）Googleカレンダーにスケジュール登録される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316038/2dcacbdc-a099-9ea5-a33a-1ebb012f0cbc.png)

### （結果２）FileMakerにイベントidが保存される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316038/5948c1f6-aaf8-e7ee-5c62-a7bfb824f803.png)


#Connectで作ったフロー
１つのプロジェクト内に、登録・削除・更新の３フローを作成しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316038/5dcaf814-aeac-c39d-abdb-9274aa22bacd.png)
本記事では、登録のみ記載します。（削除・更新はまた別途まとめます）


##イベントの新規作成
[前回の記事](https://qiita.com/Pepo_Yama/items/f84708ba5327eba764a9)を参照してください。
本記事では、作成した後に更新・削除を行うためのイベントidを取得・保存方法のみ記載します。

###【FileMaker】前回作成したスクリプトに引数を追加する
####イベントidのフィールドを用意
ConnectGoogleイベントのidを記録するためのフィールドを用意。
値は新規作成時にConnectから入力します。フィールドはレイアウト上に配置する必要があります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316038/2054eef4-247b-b1e1-0643-0352dae5a884.png)

####Connectへ渡す引数（$$JSONdata）にイベントidを追加
[前回の記事](https://qiita.com/Pepo_Yama/items/f84708ba5327eba764a9)で作成したスクリプトの$$JSONdataに、必要な項目を追加します。

```ruby:qiita.rb
JSONSetElement ( "{}" ; 
["action" ; "script" ; JSONString] ;
["start" ;  Substitute ( 顧客::打合せ日 ; "/" ; "-" ) & "T" & 顧客::打合せ時刻 & "+0900" ; JSONString] ; 
["end" ; Substitute ( 顧客::打合せ日 ; "/" ; "-" ) & "T" & 顧客::打合せ終了時刻 & "+0900"  ; JSONString] ; 
["shinrou" ; 顧客::新郎氏名 ; JSONString] ; 
["shinpu" ; 顧客::新婦氏名 ; JSONString] ;
["calid" ; 顧客::Gカレid_打合せ ; JSONString] ; 
["flg" ; $flg ; JSONString] ;  /*登録・削除・更新*/
["id" ; Get ( レコード ID ) ; JSONString] ; 
["layout" ; Get ( レイアウト名 ) ; JSONString ]
 )
```
（今回は結婚式の打ち合わせスケジュールを登録するので、新郎新婦の名前になっています）

###【Connect】FileMakerへイベントidを保存する
[前回の記事](https://qiita.com/Pepo_Yama/items/f84708ba5327eba764a9)で作成した新規イベント作成のフローに、FileMakerのレコード編集をするアクションを追加。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316038/911da3fd-3b1d-178b-46b0-54bef999b7ce.png)

アカウントはDataAPI用のアカウントを作るのが吉。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316038/81eb9154-4e90-a5d4-3b72-ccb49b8f7faf.png)

レイアウト：選択すると、レイアウト上のフィールド名をひろって自動的に表示してくれます。※DataAPI用のレイアウトを用意しておくとよいです。
レコードID：　FileMakerの関数 Get(レコードID) で取得できるIDをセット。（UUIDや自分で設定したIDではないので注意）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316038/f18f6128-ed14-3106-1e07-b4b50d634e65.png)

Googleイベント作成のステップからイベントidを取得できるので、前項でFileMakerに作成したイベントid用のフィールドにセット。


#感想・メモ
Connectのレイアウト選択で候補が出てこない場合：正しいアカウントでログインできていない可能性あり。再度アカウント指定しなおしてみましょう。
FileMakerServerのコールバックURL：Connectのプロジェクトに対して１つのコールバックURLが発行されます。
イベントidさえFileMakerに保存できれば、削除・更新も同じ要領でフロー作成できます！
phpUnitで配列の値を順不同で比較したい時

assertSameだと順不同で比較してくれない。
そういう時はassertEqualsCanonicalizingを使えば解決。
phpUnit7.5以降のversionで使用することができます。

```php5:使用例
//成功例。配列を順不同で比較してくれる。
$this->assertEqualsCanonicalizing([1,2,3,4],[4,1,3,2]);

//失敗例。他の関数と同じく第３引数でコメントしてくれる
$this->assertEqualsCanonicalizing([1,2,3,4],[4,1,3,3],"失敗しました");

```

参考:https://www.geeksforgeeks.org/phpunit-assertequalscanonicalizing-function/
外部組織のユーザーでAzure DevOps の Organizaion を作成する。

# はじめに

Azure DevOps の Organizaion や Project には、当該環境を作成したサブスクリプション上の Azure AD ユーザーだけでなく外部組織の Azure AD ユーザーも参加させることが可能です。仕組みとしてはシンプルで Azure AD B2B の機能によって外部ユーザーを招待しているだけですが、課金や権限管理を外部組織のパートナーも含めて一元化できるため非常に便利です。

また、Organizaion の Owner はいつでも変更でき外部ユーザーに設定することも可能であるため、プロジェクトの特定期間のみ外部組織のメンバーを Owner にアサインするといった運用も可能ですし、これらに派生した話として **はじめの Organizaion の作成から外部ユーザーが実施することも可能** です。今回はこの点について解説したいと思います。

# 実施環境と前提条件

今回やりたいことを図示すると、以下のイメージになります。
![20200817_devops_organization_01_image.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/685288/b31db676-02fd-7156-1625-17f5dce40ca3.jpeg)

作業をするための前提として、Organizaion を作成する側のサブスクリプション(Azure AD)に対して事前に外部ユーザーを招待しておきます。ユーザー招待の細かな手順は割愛しますが、以下の通り実施しておけば問題ないです。

[Azure Portal で Azure Active Directory B2B コラボレーション ユーザーを追加する](https://docs.microsoft.com/ja-jp/azure/active-directory/external-identities/add-users-administrator)

# 外部ユーザーによる Organizaion の作成

ここから本題となる、Organizaion の作成に入ります。作業は全て招待された外部ユーザーで実施します。

Azure Portal で devops を検索し、画面下部の「My Azure DevOps Organizations」をクリック。
![20200817_devops_organization_02_organization.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/685288/4f0466fd-a5b5-df05-b152-c0f112ddb350.jpeg)

何度か画面遷移すると以下が表示されますが、この画面における **「Switch directory」** というところがポイントです。ここをクリックすると、該当ユーザーがアクセス可能な Azure AD のディレクトリ一覧が表示されるので、先ほど招待されたディレクトリを選択します。これによって、選択した Azure AD のディレクトリ上で Organizaion が作成されます。
![20200817_devops_organization_03_organization.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/685288/8b8f76db-30d0-268d-5aaa-ca233dadcb51.jpeg)

後は、Organizaion の名称を設定すれば完了です。https://dev.azure.com/{Organizaion名称} で作成したOrganizaionにアクセスできますし、「Organization Settings」-「Azure Active Directory」から、対象のディレクトリ上に正しく作成されたことが確認できます。
![20200817_devops_organization_04_organization.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/685288/8432f19c-c04c-ec8b-fea5-46126215f427.jpeg)

# まとめ

外部組織の Azure AD ユーザーで Azure DevOps の Organizaion を作成する手順をご紹介しました。私は SIer に勤めておりまして、お客様や引き入れるパートナー様とどのような作業分担・責任分解でスキームを組むかはプロジェクト毎の契約内容により細部が変わってくるため、Azure AD の仕組みの応用でそれらが柔軟に調整できる Azure DevOps というサービスは非常に魅力的に感じました。

今回は検証作業であったため招待した外部ユーザーにはサブスクリプションに対して強めの権限を与えましたが、細かく制御すれば Azure DevOps 関係のロールだけでも問題ないかもしれません。この辺りは、時間のある時に別途検証してみたいと思います。

# 参考 URL

[Create an organization or project collection](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/create-organization?toc=%2Fazure%2Fdevops%2Fget-started%2Ftoc.json&bc=%2Fazure%2Fdevops%2Fget-started%2Fbreadcrumb%2Ftoc.json&view=azure-devops)
JSONを楽にJavaScriptObjectへ変換する

JSONファイルを読み取って, JavaScript Objectへ変換する関数を実装しようとしました.
行き詰まっていたところ, teratailで質問をするとすぐに回答が付きました.  便利な世の中になりましたね.
https://teratail.com/questions/285284


以下ソースコードです.  jQuery依存コードです.

```js
const readjson = path => {
    let jsondata;
    $.ajaxSetup({ async: false }); // Ajax通信を同期通信にする
    $.getJSON(path, data => {
        jsondata = data;
    })
    $.ajaxSetup({ async: true }); // Ajax通信を非同期通信に戻す
    return jsondata;
};
```

使うときは, `[const/let] [変数名] = readjson([jsonのパス])`を記述します.
プログラムを書くときの注意点：その１

【概要】
----------------------------------------
<b>1.結論</b>
<b>2.SOLID原則とは何か</b>
<b>3.単一責任の原則はどう使うのか</b>
<b>4.なぜ単一責任の原則が必要か</b>
<b>5.ここから学んだこと</b>
<br>

1.結論
----------------------------------------
<b>単一責任の原則にも従う！
<br>

2.SOLID原則とは何か
----------------------------------------
●SOLID原則とは、
i)<b>単一責任の原則</b>:1つのclassに1つの役割を
ii)<b>オープン/クローズドの原則</b>:追加機能はOK,ただ修正はせずに
iii)<b>リスコフの置換原則</b>:親クラスは子クラスと同じ動きに
iv)<b>インターフェース分離の原則</b>:利用用途に応じた最小限の動きに
v)<b>逆依存性の原則</b>:破壊的変更をさせるな

の英語名の頭文字を取ったものです！
（ここでは分かり易く書きたいため、英語名は省略しています）
<br>


3.単一責任の原則はどう使うのか
----------------------------------------
あくまで原則なので、基本的な考え方の部分になります。
なので例を交えての紹介になります。

例えばご紹介した、（”3つの値の正誤を確かめる条件式~演算子,論理積~
”）https://qiita.com/taka_no_okapi/items/dd92ab3f74cd28d3b364
のプログラムの”マシーン”に”人がお金を投入する”というプログラムをさせたいとします。

```ruby:user1.rb
class User1
  def initialize(many_money)
    @money = many_money
  end

  def money
    @money
  end

  def choose_drink
    gets.to_i
  end
end

```

上記のプログラムをマシーンが書いてあるファイルに一気に書いてもいいですが、それですとマシーンが同じ数字を書く機能を持ちつつ人がお金を投入するシステムまで導入し１つのclassに２つの役割が入ってしまいます。
であれば”class Machine” “class user1”で
マシーン（クラス）は１つの役割、ユーザー（クラス）は１つの役割
にした方が保守性・拡張性・可読性が飛躍的に高まります。
 <br>

4.なぜ単一責任の原則が必要か
----------------------------------------
結論としては、プログラミングを書く際の要は以下の
3つに集約されると思っています。

Ⅰ）保守性：修正（エラー発見のしやすさ）・管理のしやすさ
Ⅱ）拡張性：追加機能実装のしやすさ
Ⅲ）可読性：記述のわかりやすさ
が必要だと考えております。

上記3つのことは自分が他の4つの原則を説明する際に
同じことを言うので、５つの原則のうちどれかを読んでいただくと
結論はすべてこの３つに収まります。

つまり、上の3つを叶えるには
<b>単一責任の原則に”も（他の４つの原則もあるので）”従う！！</b>
 <br>

5.ここから学んだこと
----------------------------------------
i)単一性の原則は非常に理解しやすく、すぐに適応できるので
意識するだけでプログラムの考えを受け入れやすかったです！

ii)物体ごと（上記の例ですと、user1とMachine)だけではなく
機能ごと（Machineであれば同じ数字を揃える意外に、景品を選んでくれる機能など）でも分けたほうがプログラムしやすいです！
<br>
【iOSアプリ内課金のテスト】サブスクリプション自動更新時間の進み方


サブスクリプションの課金テスト時に、毎回調べてしまうのでメモ＆Tipsです。

## 定期購読更新の時間は早回しで進む

Sandbox環境下では、サブスクリプション更新期間の時間は早回しで進みます。

表でまとめると以下になります。

### 更新期間の比較

|本番|Sandbox|
|:--|:--|
|7日|3分|
|1ヶ月|5分|
|2ヶ月|10分|
|3ヶ月|15分|
|6ヶ月|30分|
|1年|60分|

## 自動更新は６回まで

- **Sandbox環境では６回しか自動更新されない**

例えば、1ヶ月更新のプランだと、半年で自動更新が終了します。

テスト環境での時間を計算すると

**```5分(1ヶ月)×６回更新＝30分```**

で自動更新が切れるので

プラン購入から30分後に、**ユーザが更新継続しなかったパターンをテスト**する事が出来ます。

なお、本番環境では設定アプリから「購読の停止」がいつでも行えますが

Sandbox環境ではその設定が無く、手動で停止する事が出来ません。(自動更新切れを待つしかない)


## 無料トライアルを設定している場合

定期購読プランに**「最初の1週間は無料！」**みたいなお試しオファーを設定している場合は、その分を加味して計算します。

例）**1週間の初回無料トライアル付き、1ヶ月プラン**のケース

**```3分+(5分×6回更新)=33分```**

33分後に自動更新が終了します。


---

参考：
[自動購読課金について【iOS編】 \| サイバーエージェント 公式エンジニアブログ](https://ameblo.jp/principia-ca/entry-12071724382.html)
docker-composeでDeviseを導入

Device
ログイン機能やユーザー登録機能をとても簡単に実装することができるgem。

参考にした記事
https://qiita.com/Orangina1050/items/a16e655519a60f35b394

下準備
コントローラーの作成 ついでにアクションとビューを作成する

```terminal:terminal
$ docker-compose run web bin/rails g controller comments index 
```

導入編
Gemfileに、deviseを追加する。

```terminal:terminal
$ docker-compose run web bundle install #deviseをインストールする
$ docker-compose build #構築する。
```

終わったら、 deviseの設定ファイルを作成する

```terminal:terminal
$ docker-compose run web bin/rails g devise:install
```

ログイン機能用のモデル作成を行い(1)、を行いマイグレーション(2)
その後、ログイン機能に必要なビューファイルをまとめて作成(3)

```terminal:terminal
$ docker-compose run web bin/rails g devise user #・・・（１）
$ docker-compose run web rake db:migrate #・・・（２）
$ docker-compose run web bin/rails g devise:views  #・・・（３）
```
views/comments/index.html.erbを編集し、下記を加える

```Ruby:index.html.erb
  <div class="field">
    <%= f.label :name %> <br />
    <%= f.text_field :name %>
  </div>
```

ちなみに、私はここで、
NoMethodError in Devise::Sessions#new
エラーが発生した。

一度、コンテナを止めて(1)、削除し(2)、再度コンテナを構築したら(3)、解決した。
（理由をわかっていないので宿題ですね）

```terminal:terminal
$ docker ps -a
$ docker stop (コンテナ名） #・・・(1)
$ docker rm （コンテナ名） #・・・（２）
$ docker-compose build #・・・(3)
```

新規登録時に名前を入力できるようにする
usersテーブルにnameカラムをstring型で追加するマイグレーションファイルを作成

```terminal:terminal
$ docker-compose run web bin/rails g migration AddNameToUsers name:string $ rake db:migrate
```

ここでもまた、エラーが発生する場合は、再起動すると直る場合あり！

DBに名前を格納できるように変更する
deviseは初期の状態では、strong parameterが新規登録時のメールアドレスとパスワードのみ受け取るように設定されている。
しかし、deviseのstrong parameterはgem内のため、いじることができない。
なので、deviseが提供しているconfigure_permitted_parametersメソッドを利用する

configure_permitterd_parametersとは・・・
>deviseのstrong parameterを追加することができるメソッド
>application_controllerに記述する

```Ruby:controllers/application_controller.erb
 
  before_action :configure_permitted_parameters, if: :devise_controller?
  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up, keys: [:name]) # 新規登録時(sign_up時)にnameというキーのパラメーターを追加で許可する
  end
```
Flask-paginateの表示文言の日本語化

# 概要
Flaskで簡単にページング機能を実装しようとした際、Flask-paginateが便利です。
しかし、Flask-paginateで表示した場合、表示される文言が英語で表示されてしまう為、
日本語のアプリを作る際にそのままでは使用できません。
今回は、Flask-paginateでの表示文言の日本語化方法を記載します。

## 前提条件
- Flask
- Flask-paginate

## 方法
- Paginateクラスをインスタンス化する際にdisplay_msgを引数に設定する

```sample.py
from flask import Flask, Response, render_template, request
from flask_bootstrap import Bootstrap
from flask_paginate import Pagination, get_page_parameter

@app.route('/index')
def index():

    page_disp_msg = '表示範囲 <b>{start}件 - {end}件 </b> 合計：<b>{total}</b>件'

    result = get_index()

    page = request.args.get(get_page_parameter(), type=int, default=1)
    res = result[(page - 1)*pagination_page: page*pagination_page]
    pagination = Pagination(page=page, total=len(
        result), per_page=pagination_page, css_framework='bootstrap4', display_msg=page_disp_msg)

    return render_template('index.html', data=res, pagination=pagination)
```

### 表示結果
![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/600531/e4f79ea9-90bd-d22e-4ffd-314e280cfa83.png)

### 参考
- [flask-paginate](https://github.com/lixxu/flask-paginate)
- [FlaskのページネーションはFlask-paginateを使うと簡単に実装できる](https://www.ravness.com/2019/07/flaskpaginate/)
byobuでkeybindingsが使えなくなった時の対処法メモ

##はじめに
byobuを初めて使おうと思った時にkeybindingsが使えなかったり、その後もたまにkeybindingsが無効になってしまっていたので、メモ程度に記事にします。
多分byobuを日常的に使っている人にとっては当たり前かもしれませんが、私は結構詰まりました。

##環境
* byobu
* windows

##Shift+F12
shift+F12を押すだけでkeybindnsのオンとオフが切り替わります。
注意点として、ファンクションキーが有効になっていると、そちらが優先されてしまうので、Fnを押して無効にしなければなりません。

##byobu-keybindings
```
byobu-keybindings
```
byobu上でコマンドを打ち込むことでkeybidingsが有効になります。





##参考
[Byobuでファンクションキーを再度有効にする方法](https://www.it-swarm.dev/ja/byobu/byobu%E3%81%A7%E3%83%95%E3%82%A1%E3%83%B3%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%AD%E3%83%BC%E3%82%92%E5%86%8D%E5%BA%A6%E6%9C%89%E5%8A%B9%E3%81%AB%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/957232321/)
GitHubのcontributionsを画像にしたい〜privateリポジトリのcontributionsは何処へ〜

# 前置き
転職しようかなぁと思った時、明示的に何かを示すにはどうしよう？と最近思いました。
GitHubに何か作っておいたり、ポートフォリオを提示するのもありですが、とりあえずエンジニア（腕前は置いておいて）です。って明示できる何か、ああ、あれがある・・・そう、contributionsならね。

って事でGitHubのAPI使えばさくっとそれっぽい情報取れてかつライブラリ使えば画像出力出来るのでは？と思い手を付けようと思った矢先の事でした。

## 本題
調べ始めたんです、以下を使ってよしなにすればなんとかなりそうだよね。

GitHub-API
https://developer.github.com/v4/interface/contribution/

でも、こんな事絶対先人やってるし、下手すればライブラリとかもあったりするし、無駄な労働力は使いたくないのでなんかないかとググったら・・・ありました。

GrassGraph
https://grass-graph.moshimo.works/

あ、これ思ってたやつやん。
ただ若干GitHubの設定弄らないといけませんでしたが・・・

before
TODO:画像取得失敗につきあとで更新

あれ、全然草生えてない・・・これじゃGitHub使う一般人。
っと思って調べました。

GitHub右上 > settings > Contributions > Include private contributions on my profileにチェックを入れなければ外部の人が見た場合、privateリポジトリのcontributeは見えない状態（publicでcommitしてなければ真っ白になるはず）これは頂けない。

after
![スクリーンショット 2020-08-17 16.43.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241708/7d3771a1-0821-cb9a-e7b5-ce2d45de21f6.png)

草生えました、先人に感謝。

# 後書き
もし先人が残してくれた遺産が使える様なら使っちゃうスタンス。
同じものを作るくらいなら他にカロリーを回した方がいいんじゃないかと自分は思います。
Javaのnull合体演算子

Javaにnull合体演算子が無いのでイケてないなあと思いつつ
Util関数を用意する次第

名称を`coalesce`として大体SQLの関数と同じ感じで使えるかなと

```java
public final class Utils {
    @SafeVarargs
    public static <T> T coalesce(T... value) {
        for (T v : value) {
            if (v != null) {
                return v;
            }
        }
        return null;
    }
}
```
```java
    public static void main() {
        String foo = null;
        String bar = null;
        String hoge = Utils.coalesce(foo, bar, "huga");
        System.out.println(hoge);
    }
```


でも正直なところC#のような`??`演算子が使いたいのです。
GISを扱うための環境づくり　arcGIS proとそれに付随するpythonのインストールの記録

買い替えたばかりのPCにGISデータとpythonを扱うための関連ソフトを入れていきます。ArcGISはすでに所有しているBasicアカウントを使用。
**PCの環境**
・windows10(x64)
・intel corei7, メモリ16GB, 256GB SSD

**入手するソフト**
・ArcGIS　Pro 2.5　Esri製品サポートサイトから。　ArcMAPとの違いがいまだによく分かっていません。
・Atom　テキストエディタは基本的にこれを使う。

**作業手順の記録**　
・まずArcGISをインストール。ファイルの抽出先フォルダにOneDriveのフォルダが勝手に選ばれていたが普通のローカルフォルダにおいてほしいと思いCドライブのユーザーディレクトリに変更しました。OneDriveを避けて展開する方法がわからず、ひとまずは必要ないからとOneDriveごとアンインストール。そのあとはセットアップツールの指示にそのまま従ってセットアップが終了しました。
・ArcGIS Proのインストールと同時に付随してPython環境が自動的に導入されました。

```
C:\Users\hoge\AppData\Local\Programs\ArcGIS\Pro\bin\Python\envs\arcgispro-py3
```

この「arcgispro-py3」がArcGISをインストールした際に自動的に作られるanacondaによる仮想環境と思われます。

・ArcGISで扱うことのできるジオプロセシングをpythonスクリプトから実行できるパッケージのarcpyも標準で入りました。その他、データ分析に便利だというjupyter notebookも一緒にインストールされました。aidemyで使用したときに非常に便利だったので、今後もjupyterを使っていきたいと思います。

**ArcGISとpythonについてのメモ**

なぜかここでインストールされるpythonはバージョンがやや古いようです。一緒にインストールされた「pythonコマンドプロンプト」(コマンドプロンプトはPCにもともと備わっているものでなくこれを主体に使っていくつもりです)でバージョンを確認すると以下の情報が表示されました。

```python3
(arcgispro-py3) C:\Users\hoge\AppData\Local\Programs\ArcGIS\Pro\bin\Python\envs\arcgispro-py3>python -V
Python 3.6.9 :: Anaconda, Inc.
```
自分が知る限りは、すでに色々なパッケージがインストールされた状態でpythonのアップデートを行おうとすると、ファイルの依存関係が壊れてしまって不具合を起こすかもしれないということです。もしも新しいバージョンのpythonを使いたい場合は上記arcgispro-py3以外の環境を新しく作る必要があると思っています。
もしかすると新しいバージョンでしかインストールすることのできないパッケージがあるのかもしれないと思うと困りますが、arcpyは基本的にArcGIS系ソフトの導入によってしか得ることができないようなので、arcpyを使いたい場合はこの環境を使う必要があるのだと思います。

ArcGISに付属するpythonは、ArcMAPではpython2系、その後継にあたるらしいArcGIS Proではpython3系になるようです。arcpyはどちらにもインストールされ、Proでも使えるようなので安心です。

これで自分のPCにArcGIS Pro 2.5とAnaconda環境ができました。
Ancondaといいつつ、Anacondaのダウンロードページから入手してインストールした結果の環境ではないので、ところどころにAnaconda3?から抜けているものもあるのではないかと思います。
パッケージの管理は基本的にcondaのみを使いたいと思います。
2つのCloud Foundry on Kubernetes

今回はCloud Foundryのパッケージについてメモを残したいと思います。

Cloud FoundryはもともとVMwareベースでDiegoというスケジューラーを使用しておりました。SUSEが中心となって開発されCNCFに寄贈されたKubeCFにより商用パッケージでCloud Fouondry on Kubernetesの利用が可能となりました。並行してVMwareが中心となっているプロジェクトにcf-for-k8sがあります。

cf-for-k8sは次世代のCFARコンポーネントによりパッケージ化され、BOSHリリースが不要となり、より制約が少なくなる見込みです。具体的には、
- Eirini
- Kpack
- Paketo buildpacks
- Istio
が構成の核となります（個々のコンポーネントについては他の方の記事をご参照いただければと思います）。

今回、伝えたいメッセージとしてはKubeCF vs. CF-for-K8sではないということです。KubeCFは完全なCFARを提供し、テスト済のCNCF認定済商用リリースです。また先に挙げた新しいコンポーネントは順次KubeCF側でも採用し統合されていく予定です。VMwareのTanzuも大幅に機能強化されて市場にリリースされると思われます。重要なことは、パッケージは違えど同じCloud Foundryである、開発者の方からどちらも同じプラットフォームであるということです。周囲のエコシステムや規模、費用感などで柔軟に選択肢があるというのはオープンソースならではだと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636313/a355bda0-032d-2aa5-bb82-143438b18c48.png)

いくつかご質問を頂きましたので言葉を借りてメモを残させていただきました。お読みいただきありがとうございました。

（半分ほどはQiitaで書いている内容ですが...）もしお時間あればCNDT2020のセッションにてお会いしましょう
それではまた。
Happy coding!
NUXTのstore(vuex)でAPIからデータを取得して表示するまで

いままで各vueファイルでaxiosを使ってデータ取得してたけど、これで処理を共通化したけどかなり詰まったのでめも。
ひとまず表示はできるようになったとこまで。

actionsの書き方が悪かったっぽく、stateを取得しても[]としか表示されなくて困った。
公式をちゃんと見れば動いた。
https://ja.nuxtjs.org/api/pages-fetch/

vuexってなんぞやはここが参考になった。
https://qiita.com/aya02/items/933c6c55b8e4801f150a

#store
参考
https://qrunch.net/@itahana/entries/RV6zu252J67FJpkl?ref=qrunch

```js:store>getjson.js
import axios from 'axios'

export const state = () => ({
  items: []
})

export const mutations = {
  setItems (state, items) {
    state.items = items
  }
}

export const actions = {
  async nuxtServerInit({ commit }) {
    const { data } = await axios.get('APIの取得URL', {withCredentials: true})
    commit('setItems', data)
  }
}

export const getters = {
  getItems: (state) => state.items
}

```

#pages
```pages.vue
<template>
  <div>
    <p>{{ data }}</p>
  </div>
</template>

<script>
import { mapState, mapActions } from 'vuex'

export default {
  created(){
    this.$store.dispatch("nuxtServerInit")
  },
  computed:{
    ...mapGetters({
      jsonData: 'getItems'
    })
  },
}
</script>
既存のLaravel/VueCLIプロジェクトにVuetifyを導入する

# 環境
- Laravel 7.25
- PostgreSQL 12.3
- vueCLI 4.4.1

# やりたいこと
- 既存のLaravel+VueCLIプロジェクトに、後からVuetifyを導入する
- 公式サイトのインストール方法（https://vuetifyjs.com/ja/getting-started/quick-start/) がわかりにくい

# 手順
### コマンド
- 公式サイトにはいろいろあるけど、この場合はこの２つでOK

```
npm install vuetify
npm install sass sass-loader fibers deepmerge -D
```

- mdiアイコンを使うとき

```
npm install @mdi/font -D
```

### resources/js/app.js
- ★がついた部分が加筆部分

```js
/**
 * First we will load all of this project's JavaScript dependencies which
 * includes Vue and other libraries. It is a great starting point when
 * building robust, powerful web applications using Vue and Laravel.
 */

require('./bootstrap');

window.Vue = require('vue');

/**
 * The following block of code may be used to automatically register your
 * Vue components. It will recursively scan this directory for the Vue
 * components and automatically register them with their "basename".
 *
 * Eg. ./components/ExampleComponent.vue -> <example-component></example-component>
 */

const files = require.context('./', true, /\.vue$/i)
files.keys().map(key => Vue.component(key.split('/').pop().split('.')[0], files(key).default))



import Vue from 'vue';
import Vuetify from 'vuetify'; //★
import 'vuetify/dist/vuetify.min.css'; //★
import '@mdi/font/css/materialdesignicons.css'; //★

Vue.use(Vuetify); //★

/**
 * Next, we will create a fresh Vue application instance and attach it to
 * the page. Then, you may begin adding components to this application
 * or customize the JavaScript scaffolding to fit your unique needs.
 */

// ★
export default new Vuetify({
    icons: {
        iconfont: 'mdi'
    },
    theme: {
        dark: true,
    }
})

const app = new Vue({
    el: '#app',
    vuetify: new Vuetify(), //★
});

```
GitHubでWebページを公開しちゃおう

# はじめに
GitHubは聞いたことあるけど詳しくは触ってない！ということで少し触ってみた。

# GitHubの準備
* GitHubのアカウントを作成する。
    * 公式ページ（https://github.com/ ）からアカウントを作成する。
* Gitをインストールする。
    * 公式ページ（https://git-scm.com/downloads ）からインストールする。

# 手順
* リポジトリを作成する。
![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533672/762196a0-6112-19a9-36f7-9987f10df695.png)
* HTMLファイルを作成する。
    * 今回はテンプレート（https://prog-8.com/docs/github-pages ）使用した。
* GitHubへHTMLファイルを格納する。
![図2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533672/83f27371-bd97-8dea-a0df-37e79c01f051.png)
* Web上で公開されているかチェックする。
    * 「https://アカウント名.github.io/リポジトリ名/」を開く。
    * 今回作成したWebページ：https://takamasasaito.github.io/webtest/

# お世話になった参考URL
* 【GitHub超初心者入門】この前初めてGitHubを使い始めたエンジニア見習いが書くGitHubの使い方と実践～とりあえず一緒に動かしてみようぜ！～
    * https://qiita.com/nnahito/items/565f8755e70c51532459
* Windows10にGitをインストールして初期設定する
    * https://qiita.com/taketakekaho/items/75161e1273dca98cb4e1
* 自分で作ったWebページをインターネット上に公開しよう！
    * https://prog-8.com/docs/github-pages
* 無料レスポンシブウェブデザインHTMLテンプレート
    * https://f-tpl.com/category/HTML%E3%83%86%E3%83%B3%E3%83%97%E3%83%AC%E3%83%BC%E3%83%88/
resourcesメソッド以外のアクションを行いたい場合

【概要】
----------------------------------------
<b>1.結論</b>
<b>2.collection,memberメソッドとは何か</b>
<b>3.どのように使うか</b>
<b>4.なぜcollection,memberメソッドが必要か</b>
<b>5.ここから学んだこと</b>
<br>

1.結論
----------------------------------------
<b>member,collectionメソッドを使う!</b>
<br>

2.collection,memberメソッドとは何か
----------------------------------------
簡単に言いますと、
<b>member</b>:resourcesメソッド以外のアクション（特定のデータあり）
<b>collection</b>:resourcesメソッド以外のアクション（特定のデータなし）


特定のデータとは”:id”のことを指し、
“member”はAというUserに紐づいているものしか
見れない（＝特定の人が特定の情報しかみれない）アクションをしたい場合に使用できます！例えばお気に入り登録を見たい場合です。
“collection”は、全てのデータを対象とします。例えば検索機能を追加したい場合です。
 <br>


3.どのように使うか
----------------------------------------
member,collectionも使い方は同じで、

```ruby:routes.rb
collection do
 get ‘*****(入れたい任意のアクション名）’
```

で使用できます！

もちろんmember,collectionを使用せずその他のアクションを設定す流方法があります。

memberメソッドですと

```ruby:routes.rb
 get ‘users/:id/(任意のアクション名)’, to ‘users#(任意のアクション名)’
```

colletionメソッドですと

```ruby:routes.rb
 get ‘users/(任意のアクション名)’, to ‘users#(任意のアクション名)’
```

になります。

ただ注意点としてはprefixが自動生成されないので
冗長な表現になりかねないです。簡単にかけるものは簡潔にプログラムしないと、保守性・拡張性・可読性が損なわれます！
 <br>

4.なぜcollection,memberメソッドが必要か
----------------------------------------
結論としては、resourcesメソッド以外のアクションを行いたいからです。
つまり、<b>member,collectionメソッドを使う！</b>ということです。

 <br>

5.ここから学んだこと
----------------------------------------
I)7つのアクション以外に設定できるアクションがあることをしり、ユーザーがが求めるユーティリティーへの対応幅が広がりました！

ii)わざわざURLを指定してアクションを設定しないといけない手間が省け
プログラムを見やすく書きやすくできる手段を知りました！
 <br>
vim ver8.1 -8.2 9.1のインストールとconfigure

MacOS
vim 7.3〜8.1、8.2、9.1で使える。

#1.前提条件

gitが使えること。
/usr/local/bin/luaがインストール済み

ソースディレクトリで
mkdir vim91
cd vim91
などとしておく。

#2.vimのダウンロード

候補１
git clone https://github.com/vim/vim.git

候補２
Index of /BLFS/vim
http://anduin.linuxfromscratch.org/BLFS/vim/

#３．ビルド

$ cd vim

configure用の.shファイルを作成し、実行。

```（好きなファイル名）.sh
cd vim
echo $PWD
date
sleep 2
make distclean clean && ./configure \
--prefix=/usr/local/stow/vim \
--enable-multibyte \
--enable-nls \
--enable-perlinterp -with-perl-command=/usr/bin/perl \
--with-python3-command=/usr/bin/python3 \
--enable-rubyinterp --with-ruby-command=/usr/local/stow/ruby/bin/ruby \
--enable-fail-if-missing=yes \
--with-features=huge \
--without-x \
--disable-xim \
--disable-gui \
--disable-sysmouse \
--disable-netbeans \
--disable-xsmp \
# CC=`which clang`
# --with-ruby-command=/usr/local/bin/ruby \
# --enable-cscope \
# --enable-python3interp=dynamic \
# --enable-tclinterp --with-tclsh=/opt/local/bin/tclsh \
# --with-luajit \
date
echo $PWD
```

./（好きなファイル名）.shを実行。
後は
gitでダウンロードしたディレクトリ内で
make
make install

#３．vim --version で確認。

上記のconfigureスクリプトは8.0〜8.2、9.1.446で動作する。

2020年3月12日　8.2追記
2020年8月??日　stow関連ディレクトリ変更
2020年9月11日　version 8.2.1656
2024年6月　version 9.1.446

以上

参考リンク

macOSでvim8.1をlua付きでソースからビルドする #Mac - Qiita
https://qiita.com/zurazurataicho/items/491a460a1842037db13c

Ubuntuのvimで :python と :python3 を同時に有効にする（リベンジ） - Blank File
http://h-miyako.hatenablog.com/entry/2014/11/11/070536

VimとPythonのバージョン — KaoriYa
https://www.kaoriya.net/blog/2013/01/30/

vimエディタが（勝手に）作成する、一見、不要に見えるファイルが何をしているか — 名無しのvim使い
https://nanasi.jp/articles/howto/file/seemingly-unneeded-file.html#id15
Kubernetes入門 その１

##概要
チュートリアルに記載されていることを自分なりの解釈で書いていこうと思います。
少しでも参考になれば幸いです。
※認識誤り等ありましたら、ご指摘いただけると助かります。

##チュートリアルで学べること
 - コンテナ化されたアプリケーションをクラスターにデプロイ
 - [Deployment](https://www.redhat.com/ja/topics/containers/what-is-kubernetes-deployment)のスケーリング
 - 新しいソフトウェアのバージョンでコンテナ化されたアプリケーションをアップデート
 - コンテナ化されたアプリケーションのデバッグ

##[Minikubeを使ったクラスターの作成](https://kubernetes.io/ja/docs/tutorials/kubernetes-basics/create-cluster/cluster-intro/)

以下が目標です。

 - Kubernetesクラスターとは何かを学ぶ
 - Minikubeとは何かを学ぶ
 - Kubernetesクラスターを、オンラインのターミナルを使って動かす

##Kubernetesクラスターとは?

>Kubernetesは、単一のユニットとして機能するように接続された、
>可用性の高いコンピュータのクラスターをまとめあげます。

コンピュータをまとめ上げるものだと理解。

>Kubernetesの抽象化により、コンテナ化されたアプリケーションを
>個々のマシンに特に結び付けることなくクラスターにデプロイできます。

コンテナをクラスター内にデプロイできると理解。

>この新しいデプロイモデルを利用するには、
>アプリケーションを個々のホストから切り離す方法でアプリケーションを
>パッケージ化(つまり、コンテナ化)する必要があります。

アプリケーションをコンテナ化して、クラスター内にデプロイするということだと理解。

>コンテナ化されたアプリケーションは、アプリケーションがホストに深く統合されたパッケージとして特定のマシンに直接インストールされていた従来のデプロイモデルよりも柔軟で、より迅速に利用可能です。

ふむふむ。

>Kubernetesはより効率的な方法で、クラスター全体のアプリケーションコンテナの配布とスケジューリングを自動化します。

ありがとうございます。

##Kubernetesクラスター構成

 - マスターがクラスターを管理する
 - ノードがアプリケーションを動かすワーカーとなる

※以下URLより抜粋
https://kubernetes.io/ja/docs/tutorials/kubernetes-basics/create-cluster/cluster-intro/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114409/9578d2b3-15a1-444d-e894-d2276262b3d3.png)

>マスターはクラスターの管理を担当します。マスターは、アプリケーションのスケジューリング、望ましい状態の維持、アプリケーションのスケーリング、新しい更新のロールアウトなど、クラスター内のすべての動作をまとめあげます。

まとめると

 - マスター

→クラスターの管理（クラスター内のすべての動作をまとめあげる）
　→アプリケーションのスケジューリング
　→望ましい状態の維持
　→アプリケーションのスケーリング
　→新しい更新のロールアウト
などなど

>ノードは、Kubernetesクラスターのワーカーマシンとして機能するVMまたは物理マシンです。

ノードは、Virtual Machine or 物理マシン。

>各ノードにはKubeletがあり、これはノードを管理し、Kubernetesマスターと通信するためのエージェントです。

kubeletは、ノード管理、Kubernetesマスターと通信するためのエージェント。


>Kubernetesにアプリケーションをデプロイするときは、マスターにアプリケーションコンテナを起動するように指示します。マスターはコンテナがクラスターのノードで実行されるようにスケジュールします。ノードは、マスターが公開しているKubernetes APIを使用してマスターと通信します。エンドユーザーは、Kubernetes APIを直接使用して対話することもできます。

まとめると、

1．Kubernetesマスタにアプリケーションコンテナ起動指示を出す
2．Kubernetesマスタがコンテナがクラスターのノードで実行されるようにスケジューリングする
3．ノードが、Kubernetesマスタが公開しているAPIを使用して、疎通を取りに行く。

##Minikubeとは？

>ローカルマシン上にVMを作成し、1つのノードのみを含む単純なクラスターをデプロイする軽量なKubernetes実装です。

自身のPCでKubernetesを使うのであれば、Minikubeを使用する流れになるということですね。

>Minikubeは、Linux、macOS、およびWindowsシステムで利用可能です。Minikube CLIは、起動、停止、ステータス、削除など、クラスターを操作するための基本的なブートストラップ操作を提供します。

なるほど。

##対話型チュートリアル - クラスターの作成

用意されているコマンドをローカル環境で実行していきます。
※すでにMinikubeのインストールが完了していること前提です。
※そのまま対話側チュートリアルを進めていただいても問題ありません。

```bash:ターミナル

#minikubeバージョン確認
minikube version

→バージョン情報が出力されること

#minikube起動
minikube start

#kubectlのバージョン確認
kubectl version

#クラスター情報確認
kubectl cluster-info

#ノード情報確認
kubectl get nodes
```

##まとめ
対話型チュートリアルはここまでです。

次回、「kubectlを使ったDeploymentの作成」を見ていきます。
WSL2  のディレクトリ移動したかったニャ

## これは？

Wsl2 のディレクトリを移動したかった。
ググった。
StackDriverに書いてあった ＞  [Can I move the linux subsystem to a different drive?](https://superuser.com/questions/1113906/can-i-move-the-linux-subsystem-to-a-different-drive)


## 移動

stackdriver のまんま

```Powershell
# check linux
C:\WINDOWS\system32> wsl -l -v
  NAME            STATE           VERSION
* Ubuntu-18.04    Stopped         1
  Ubuntu-20.04    Stopped         1

# export
C:\WINDOWS\system32> wsl.exe --export Ubuntu D:\data\wsl-images\ubuntu.tar

# change drive and folder
C:\WINDOWS\system32> D:
D:> cd D:\data\wsl-images

# remove
D:> wsl --unregister Ubuntu-20.04

# import
D:> cd dev\wsl-images
D:\data\wsl-images>mkdir ubuntu20
D:\data\wsl-images>wsl --import Ubuntu-20.4 .\ubuntu20   ubuntu20.tar
```

## 起動

```Powhershell
wsl -d Ubuntu-20.4 -u xxxx
```
Laravel7でDB接続エラー / SQLSTATE[HY000] [2002] Connection refused

# 環境
- Laravel 7.25
- PostgreSQL 12.3

# つまづいたこと
- migration実行後、Laravel認証画面でユーザー新規登録をしようとしたらこのエラー

```
SQLSTATE[HY000] [2002] Connection refused  (SQL: select * from ~~.tables where ~~~)
```

# 前提
- DBは作成してある
- `.env`ファイルはPostgres用に修正してある

```
DB_CONNECTION=pgsql
DB_HOST=127.0.0.1
DB_PORT=5432
DB_DATABASE=sample
DB_USERNAME=sample_app
DB_PASSWORD=
```
- migration実行済み
- モデル作成済み

# 解決方法
- サーバーを一度落としてつなぎ直す
- `env.`ファイルなど、設定に関係するファイルを変更した場合はサーバーをつなぎ直す必要がある
たくさんのAWS Glue Jobを実行している環境で実行履歴を一覧表示するPythonスクリプト

Glue Jobの実行履歴をコマンドラインのワンライナーで見る方法を以前にブログに書きました。

- [たくさんのAWS Glue Jobを実行している環境で実行履歴をまとめて見るワンライナー](https://suzuki-navi.hatenablog.com/entry/2020/06/14/121717)

が、日時の表示がイケてなくて、使いづらかったので、Pythonのスクリプトで書き直しました。

```python
import sys
import boto3

profile = "default"
# コマンドラインパラメータがあれば、default以外のprofileに設定
if len(sys.argv) > 1:
    profile = sys.argv[1]

session = boto3.session.Session(profile_name = profile)

client = session.client("glue")

jobs = client.get_jobs()

header = [
    "started",
    "completed",
    "executionTime",
    "status",
    "name",
    "allocatedCapacity",
    "maxCapacity",
    "glueVersion",
    "errorMessage",
]

result = []

for job in jobs["Jobs"]:
    name = job["Name"]
    history = client.get_job_runs(JobName = name)
    for run in history["JobRuns"]:
        started = run["StartedOn"].strftime("%Y-%m-%d %H:%M:%S")
        if "CompletedOn" in run:
            completed = run["CompletedOn"].strftime("%Y-%m-%d %H:%M:%S")
        else:
            completed = ""
        executionTime = str(run["ExecutionTime"])
        if executionTime == "0":
            executionTime = ""
        status = run["JobRunState"]
        if "ErrorMessage" in run:
            errorMessage = run["ErrorMessage"]
        else:
            errorMessage = ""
        allocatedCapacity = str(run["AllocatedCapacity"])
        maxCapacity = str(run["MaxCapacity"])
        glueVersion = str(run["GlueVersion"])
        result.append([
            started,
            completed,
            executionTime,
            status,
            name,
            allocatedCapacity,
            maxCapacity,
            glueVersion,
            errorMessage,
        ])

# 起動時間でソート
result.sort(key = lambda r: r[0])

# タブ区切りで出力
print("\t".join(header))
for r in result:
    print("\t".join(r))
```

起動時刻と終了時刻を表示しますが、環境変数 `TZ` に依存したローカルタイムで表示されるようです。


2021/02/27追記
GitHubにアップしました。
https://github.com/suzuki-navi/aws-glue-job-history
herokuのDBをローカルのDBにリストアする方法

##概要
ほんと毎回忘れるので、herokuのpostgreSQLのDBのデータをローカルのDBにリストアする手順をメモしておきます。

##バックアップを確認
herokuのpostgreSQLのダッシュボードの「Durability」より、
リストアしたいDBのバックアップデータのNameを確認します。

![スクリーンショット 2020-08-17 14.04.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253667/4d3f3167-e4f0-6e5a-f948-294193e48eb4.png)

以下のように、コマンドラインからバックアップデータを確認することもできます。

```CUI
heroku pg:backups -a AppName

=== Backups
ID    Created at                 Status                               Size      Database
────  ─────────────────────────  ───────────────────────────────────  ────────  ────────
a015  2020-08-16 10:15:24 +0000  Completed 2020-08-16 10:17:34 +0000  162.97MB  JADE
a014  2020-08-15 10:17:05 +0000  Completed 2020-08-15 11:06:57 +0000  162.38MB  JADE
a013  2020-08-14 10:15:18 +0000  Completed 2020-08-14 10:17:34 +0000  161.75MB  JADE
a012  2020-08-13 10:15:23 +0000  Completed 2020-08-13 10:17:55 +0000  161.11MB  JADE
a011  2020-08-12 10:18:41 +0000  Completed 2020-08-12 10:21:24 +0000  160.56MB  JADE

```


今回は「a015」をローカルにリストアします。


##バックアップデータをダウンロード

ローカルにリストアするバックアップデータをダウンロードします。

```CUI
heroku pg:backups:download a015 -a AppName（アプリ名）
```

ルートディレクトリに「latest.dump」がダウンロードされれば成功です。

![スクリーンショット 2020-08-17 15.36.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253667/bf6257cb-0e2a-17b4-a202-35ae517c7f76.png)



##ローカルのDBにデータをリストアする

コマンドラインで以下のように入力することで、latest.dumpをローカルのDBに流し込むことができます。

```CUI
pg_restore --verbose --clean --no-acl --no-owner -h localhost -d booqs_development（DB名） latest.dump
```

成功例：
![スクリーンショット 2020-08-17 15.40.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253667/8b9e5b4d-f960-99ae-ad36-4de88b12da29.png)


## Dockerのコンテナにリストアする場合
```CUI
docker exec -i booqs_db_1（コンテナ名） pg_restore -U admin（ユーザー名） -v -d booqs_development（DB名） < ./latest.dump
```

以上です。

参考にさせていただいた記事：

[HerokuのDBをバックアップ / 別DBにリストアしたいんだけど...](https://qiita.com/akiko-pusu/items/3847deb103c9e8346c89)
[Heroku PostgresのDBをローカルにコピーする方法](https://qiita.com/tarot/items/c14d9ddb60412a3fd99e)
[pg_restore in postgres docker container](https://stackoverflow.com/questions/39267377/pg-restore-in-postgres-docker-container)

## 追記：herokuの中の人に聞いた裏技「heroku pg:pull」

herokuで働いている方から教えていただいたことなのですが、
こんな面倒なことせずとも、 `heroku pg:pull` をするだけで、直接productionのDBからローカルのDBにデータをコピーできるそうです。

```CUI
heroku pg:pull HEROKU_POSTGRESQL_MAGENTA（herokuのDB名） booqs_development（作成するDB名） --app AppName（アプリ名）
```

公式ドキュメント： https://devcenter.heroku.com/articles/heroku-postgresql#pg-push-and-pg-pull

注意点としては、最初に紹介した`pg_restore --clean`では、DBの中身を削除してデータを流し込みますが、
`heroku pg:pull` では、ローカルに新規データベースを作成するということです。
コマンドの第二引数が、作成されるDB名になります。
そのため、もしすでにローカルにbooqs_developmentという名前のDBが存在した場合は、上記のコマンドでは
>createdb: error: database creation failed: ERROR:  database "booqs_development" already exists

という具合にエラーが出ます。

なのでローカルのメインDBを上書きするような、`pg_restore --clean`と同じ働きをさせたい場合には、`pg:pull`の前に一度ローカルのDBを削除する必要があります。

（ 中の人曰く、`database.yml`  を書き換えずに対象のデータベースの中身だけを書き換えたい場合、 `pg:pull` の前に一度 `rails db:drop `をしてあげる必要があるとの事でした。
ただデバッグのユースケースを考えると、 `pg:pull` 時には別のDB名をつけてあげて、 Rails の場合、 `database.yml` を一時的に書き換えて、メインDBを切り替える方が健全だそうです。 ）
gpgでHTTP fetch errorが出て鍵が取得できないエラーの対処

# TL;DR

- hkpのポートは通常11371
- `gpg --keyserver hkp://keyserver.ubuntu.com:80` のように利用出来るポートを指定するといい

## 状況
社内仮想ホスト上のcentos7にpritunlをインストールしようとした際、下記のようなエラーが出ました

```shell
$ gpg --keyserver hkp://keyserver.ubuntu.com --recv-keys CF8E292A
gpg: 鍵CF8E292Aをhkpからサーバkeyserver.ubuntu.comに要求
gpgkeys: HTTP fetch error 56: Recv failure: Connection reset by peer
gpg: 有効なOpenPGPデータが見つかりません。
```

hkpのポートは通常11371を利用します。今回利用した仮想ホストはセキュリティ設定によりアウトバウンドの11371が許可されていなかった為エラーになっていました。

```shell
$ cat /etc/services | grep hkp
pgpkeyserver    11371/tcp       hkp             # PGP/GPG public keyserver
pgpkeyserver    11371/udp       hkp             # PGP/GPG public keyserver
```

yum出来る環境であれば80番等使えると思うので、:80を指定。

```shell
$ gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys CF8E292A
gpg: 鍵CF8E292Aをhkpからサーバkeyserver.ubuntu.comに要求
gpg: 鍵CF8E292A: 公開鍵"Pritunl <contact@pritunl.com>"をインポートしました
gpg:         処理数の合計: 1
gpg:           インポート: 1  (RSA: 1)
```

上手くいきました
GCEでselenium standalone-chromeを動かす

## 現象
selenium/standalone-chromeのcontainerをGCEでしばらく使っていたらsshに接続できなくなった。
ローカルのMacbookでは発生していなかった。
メモリ関連が原因だと考え調査したところ、Out Of Memoryが発生していた。

https://hub.docker.com/r/selenium/standalone-chrome/

```
docker run -d -p 4444:4444 --shm-size=2g selenium/standalone-chrome:latest
```

## 解決策
VMのメモリを監視しswap領域を追加した。
(お金のある人はメモリがたくさん乗ったインスタンスを使うのが理想的です。)

## swapの追加方法
```bash
sudo dd if=/dev/zero of=/swapfile bs=1M count=3000
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
```

swapが追加されていることを確認する

```bash
free -m
```
```
             total        used        free      shared  buff/cache   available
Mem:          ****        ***        ***         ***         ***         ***
Swap:         2999        ***        ***
```

次回起動時に自動でmountできるように `/etc/fstab`に追記する。

```bash
# /etc/fstab
/swapfile none swap sw 0 0
```

## 現象の究明
### メモリ状態を監視する
stackdriver-agentを導入し、Cloud Monitoring にメモリのグラフが出るようにした。
https://cloud.google.com/monitoring/agent/installation?hl=ja

### Out Of Memoryが起きたときの状態
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253883/293b88c5-0b51-8350-398d-dc2560c0b352.png)

* Timeoutしてssh接続できない
* Cloud Monitoring でメモリ状態を監視したところ、徐々にFreeが減少し、最終的にVMは起動しているがグラフが出ない状態になる。

## swapの容量
* メモリ3Gのインスタンスを使っていたので3Gを設定

https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/8/html/managing_storage_devices/recommended-system-swap-space_getting-started-with-swap

|システム内の RAM の容量 |	推奨されるスワップ領域 | 	ハイバネートを許可する場合に推奨されるスワップ領域 |
|--------|------|---|
| ⩽ 2 GB | RAM 容量の 2 倍 | RAM 容量の 3 倍 |
| 2 GB ~ 8 GB  | RAM 容量と同じ | RAM 容量の 2 倍  |
| 8 GB ~ 64 GB | 最低 4GB |  RAM 容量の 1.5 倍 |
| 64GB 未満 | 最低 4GB |  ハイバネートは推奨されない |

※ ハイバネートはwindowsのsleepみたいなやつで、メモリの状態を一時的にHDDに保存する機能です。
tar -zxvfで解凍できなかったのに弄りまくっていたらいつの間にか解凍できた話（謎）

今回の対象ファイルの権限
-rw-rw-r--　XXX tar.gz
（中にはバッチログが入っており、それをcatしたい。）

実行その①
最初に試したコマンド
tar -zxvf XXX tar.gz
batch_1.log
batch_1.log:open 不能：読み込み専用ファイルシステムです。
batch_2.log
batch_2.log:open 不能：読み込み専用ファイルシステムです。
：
cat batch_1.logしても見れません、
解凍できないので頭を抱える。
以下あれこれやる


その② どうしてtar -xvfコマンドを打ったのか記憶にありません
tar -xvf XXX tar.gz
batch_1.log
batch_1.log:open 不能：読み込み専用ファイルシステムです。
batch_2.log
batch_2.log:open 不能：読み込み専用ファイルシステムです。
：

その③　パーミッションを変えてみる
chmod -v 777 XXX tar.gz
XXX tar.gzのパーミッションを変更しています：読み込み専用ファイルシステムです
XXX tar.gzを0664(rw-rw-r--)から0777(rwxrwxrwx)へ変更できませんでした。


その④　wを追加してみる??
chmod +w XXX tar.gz
XXX tar.gzのパーミッションを変更しています：読み込み専用ファイルシステムです

パーミッション確認
ls -ltr XXX tar.gz
-rw-rw-r--　XXX tar.gz
特に変わりなし・・・・・・・

その⑤　764に変更してみよう（意味不明）
chmod 764　XXX tar.gz
XXX tar.gzのパーミッションを変更しています：読み込み専用ファイルシステムです

パーミッション確認
ls -ltr XXX tar.gz
-rw-rw-r--　XXX tar.gz
特に変わりなし・・・・・・・


ここで疲れたのでダメ元でtar.gz　を打ち込んだら
tar -zxvf XXX 
batch_1.log
batch_2.log
batch_3.log
：

え、なんか解凍できたっぽい

普通にcatできました。

何が原因で解凍できなくて何が功を奏して解凍できたのか全くさっぱりわかりません。
ROS noeticでImportError: No module named rospkgを解決する

# ImportError: No module named rospkg
いつもどおり
`rosrun rqt_topic rqt_topic`
したら何故かこのエラーが出たので、同じ目に合った人のためにメモを遺す
# 原因
Ubuntu 20.04.1だとpythonコマンドはpython2系をまだ指しているので、何もしないでrosrunするとこっちが動いてしまう。しかしROS noeticはPython3で動くように作り直されているのでPython2では動かない。
# 解決法
update-alternativesでデフォルトを置き換えてやればいい。一応2系に戻せるようにそっちも登録しておく。
```sudo update-alternatives --install /usr/bin/python python /usr/bin/python2.7 1
sudo update-alternatives --install /usr/bin/python python /usr/bin/python3.8 2```
私の手元の環境に合わせて決め打ちしたが、マイナーバージョン一個ぐらいはそのうち変わるかもしれないのでそこは適宜合わせてほしい。
EXCEL VBA：ファイルの保存場所がローカルディスクかどうか判別する

ファイルの保存場所をチェックするマクロのメモ書きです。

    Option Explicit
    '動作テスト用
    Sub CallCheckLocalDisk()
    
        Dim filePath As String: filePath = ThisWorkbook.Path
        Dim isLocalDrive As Boolean: isLocalDrive = CheckLocalDisk(a_filePath:=filePath)
        
        If isLocalDrive Then
            MsgBox ("ファイルの保存場所はローカルディスクです。")
        Else
            MsgBox ("ファイルの保存場所はローカルディスクではありません。")
        End If
        
    End Sub
    
    'ファイルの保存されている場所がローカルディスクかどうか判別してbool値を返す。
    Function CheckLocalDisk(ByVal a_filePath As String) As Boolean
        
        Dim fso As Object: Set fso = CreateObject("Scripting.FileSystemObject")
        Dim driveName As String: driveName = fso.GetDriveName(a_filePath)
        Dim driveType As Long
            
        'ドライブの種類を判別
        If driveName = "" Then
            driveType = 0 '不明
        Else
            driveType = fso.GetDrive(driveName).driveType
        End If
        
        'ローカルディスクの場合True、それ以外はFalseを返す
        Select Case driveType
            Case 1: CheckLocalDisk = True 'リムーバブルディスク
            Case 2: CheckLocalDisk = True 'ハードディスク
            Case Else: CheckLocalDisk = False '不明、ネットワークドライブ、CDドライブなど
        End Select
            
    End Function
React Context APIでメディアクエリを共通化

# 概要

レスポンシブ対応で利用するメディアクエリをReact Context APIを使って共有・取得をシンプル実装した

## Context APIについて

簡単に言うとpropsで渡さなくても、コンポーネント間で共有する方法を提供しているAPIになります。  
詳しくはReactの公式を確認いただければと思います！
https://reactjs.org/docs/context.html

## メディアクエリについて

今回、ブレークポイントの設定・取得は「react-responsive」を使います。  
Hookになっているので使いやすいです。
https://github.com/contra/react-responsive

そして、ブレークポイントはこちらになります。

- 560px未満をスマホと設定
- 960px未満をタブレットと設定

https://hashimotosan.hatenablog.jp/entry/2019/05/28/164834

## さっそく実装を見てみましょう

```tsx:MediaQuery.tsx
import React, { useContext } from 'react'
import { useMediaQuery } from 'react-responsive'

const MediaQueryContext = React.createContext({
  isSmartPhone: false,
  isTablet: false,
  isMobile: false,
  isPc: false
})

export const MediaQueryProvider: React.FC = ({ children }) => {
  const isSmartPhone = useMediaQuery({ maxWidth: 559 })
  const isTablet = useMediaQuery({
    minWidth: 560,
    maxWidth: 959
  })
  const isMobile = isSmartPhone || isTablet
  const isPc = !isMobile

  return (
    <MediaQueryContext.Provider
      value={{ isSmartPhone, isTablet, isMobile, isPc }}
    >
      {children}
    </MediaQueryContext.Provider>
  )
}

export const useDeviceType = () => useContext(MediaQueryContext)
```

まずは`Context`と`Provider`、`useContext`でメディアクエリを取得するための関数を作成します。  
`Context`は`export`せずに隠蔽します。  
また、`MediaQueryProvider`はFunctionComponentで定義して`useMediaQuery`にてブレークポイントを設定します。

これでほぼ実装はお終いです。

```tsx:App.tsx
import { MediaQueryProvider } from './MediaQuery'

render(
  <MediaQueryProvider>
    <App />
  </MediaQueryProvider>,
  document.querySelector('#app')
)
```

さきほどの`MediaQueryProvider`でアプリケーションを囲います。  
これでどのコンポーネントでも利用できるようになります。

```tsx:HogePage.tsx
import { useDeviceType } from './MediaQuery'

const HogePage: React.FC = () => {
  const { isSmartPhone, isTablet, isMobile, isPc } = useDeviceType()

  return (
    ︙
  )
}

export default HogePage
```

コンポーネントで`useDeviceType`を利用してメディアクエリを取得して完了です！

## まとめ

最初の実装はCustom Hookで作成していましたが、コンポーネント間でもっと簡単に共有したいと思いContext APIを利用しました。  
他にも色々な用途（認証、翻訳等）でReact Context APIは利用できそうです。