OmniAICreator/Qiita-1.07M huggingface dataset:
GKE で NFS を自前で構築する

# はじめに
k8s に NFS サーバーを構築する話です。
Filestore のようなマネージドなものが高価で使えない方々に読んで欲しい話です。

# nfs が必要な理由
* Job 間でデータを引継ぎたい。
* オブジェクトストレージだと使いづらい。
* Read-Write-Many に扱いたい。

そこで、NFS の Pod(deployment) を構築したい。
参考にした投稿は、こちら。
[NFS Persistent Volumes with Kubernetes on GKE — A Case Study](https://medium.com/platformer-blog/nfs-persistent-volumes-with-kubernetes-a-case-study-ce1ed6e2c266)

これで、ハッピー。とはなりませんでした。
なぜか。
Pod は、node や　Pod の状態により、restart される。結果、`clusterIP` が新しく付与される。
これは、NFS として、運用しづらい。

# プラン A
Job(Pod) に pv/pvc をマウントする。
最初にトライした方法です。

```yaml:job.yaml
    volumes:
    - name: nfs
      persistentVolumeClaim:
        claimName: nfs-pvc

```

## pros
* `clusterIP` の定義が1回で済む。
* pv/pvc にすることで、疎結合に運用できる。

## cons
* nfs-pod(deployment) が restart されたとき、 `clusterIP` が新しく付与されるため、pv/pvc を再作成する必要がある。
* pv がマウントされていると、マウントが解除されるまで、新しい pv を作成できない。

# プラン B
Job(Pod) に NFS を `volumes` 直接に定義する

```yaml:job.yaml
    volumes:
    - name: nfs
      nfs:
        path: /
        server: 172.24.10.24  # nfs-pod の clusterIP
```

## pros
* Job に直接 `clusterIP` が付与されるため、他のリソースからロック（マウント）されない。

## cons
* `clusterIP` を定義している Resources すべてのマニフェストを修正する必要がある。

# 選んだのは
プラン B
Job のマニフェストに `clusterIP` を定義するのは、抵抗がありますが、pv/pvc の再作成やロックを考慮すると、この方法が運用し易いためです。
argo-workflow の yaml が複数あると、それぞれの `clusterIP` を変更してあげないといけない。
ここは、`sed` で置換してあげることで、`clusterIP` が変更されてもOK。

# まとめ
これがベストな選択ではないと思います。
聞くところによると、Read-Write-Many な PV がリリースされるという噂もあります。
今後も考察を続けたいと思います。

以上。

皆さんの参考になれば幸いです。
【新春企画】Web Developer Roadmap を真面目に勉強するまとめ【フロントエンド編】

##前提
現在、組み込み系エンジニアの私が、今後はウェブ業界に挑戦するにあたって
`「強みは技術力です！」`
とかっこいいことがちゃんと言えるようになりたいと思いこの企画をはじめました。
いつでもアクセス可能のように備忘も兼ねて書きます。

##これまで
事前にこちらの記事を勉強済みです。
↓↓↓
[Webエンジニアになりたい人に捧げる学習ロードマップ](https://note.com/gizumo_inc/n/nd435c11a4ef4)
>駆け出しフロントエンドエンジニアに求められるもの
1. HTML/CSSによるWebサイトコーディング経験（レスポンシブ対応含む）
2. JavaScriptの基礎構文理解
3. JavaScriptを使った動くUI(複数パターン)の実装経験
4. jQueryのプラグインやAjaxを使った実装経験
5. タスクランナー(gulp)やモジュールバンドラー(Webpack)の利用経験
6. Vue.jsもしくはReact.jsを使ったミニアプリの開発経験
7. 上記のスキルが証明できるポートフォリオサイトもしくはGitHubアカウントの提出


##記事の役割
この記事が本で言う【目次】という役割となりここから各項目へジャンプできるような構造になっています。

##どのように進めるのか
すでにあるロードマップ通りに学習していきます。
今回真面目に勉強するロードマップがこちら！！
↓↓↓
[Webエンジニアのためのロードマップ](https://github.com/kamranahmedse/developer-roadmap)
// 高校の同級生
// 出席番号が1つ前
// サッカー部の友人
// ありがとう

ロードマップの存在目的の中にこのようなメッセージが。
>The purpose of these roadmaps is to give you an idea about the landscape and to guide you if you are confused about what to learn next and not to encourage you to pick what is hip and trendy. You should grow some understanding of why one tool would be better suited for some cases than the other and remember hip and trendy never means best suited for the job.

>「迷ったり、流行に流されたりしないように活用してね」
「適材適所でどんな手段がなぜ良いのかを理解し、流行っているものがベストとは限らないよ」

と、どんな時代でも通用する本質を学べそうですね。

##何を学ぶのか
ひとまずその中でも、フロントエンドのスキルについて勉強していきたいと思います。
[ ]←チェックボックスが全部[x]になっていくイメージ
###1.Internet[ ]
- [ ] [How does the internet work?](https://qiita.com/edamamethebest/items/0e34f2accc5b0e00633f)
- [ ] Please wait...
- [ ] Please wait...

###2.HTML[ ]
- [ ] Please wait...
- [ ] Please wait...

###3.CSS[ ]
- [ ] Please wait...
- [ ] Please wait...

###4.Javascript[ ]
- [ ] Please wait...
- [ ] Please wait...
深さがバラバラの配列からスマートに値を取り出す。reduceで。[JavaScript]

#導入
こんな配列と取り出したいデータの場所を表す配列があったとします

```js
var arr=[
  [['000', '001', '002'], ['010', '011', '012'], ['020', '021', '022']],
  [['100', '101', '102'], ['110', '111', '112'], ['120', '121', '122']],
  [['200', '201', '202'], ['210', '211', '212'], ['220', '221', '222']]
];
var pos =[0,2,2],
    pos1=[1,0,2],
    pos2=[2,1,0];
```
多次元配列って呼ばれているやつです
データの場所を投げたら目的のデータが返ってくる関数が欲しいという設定です
この場合なら次の例が一番分かりやすいと思います

```js
const fx=x=>arr[x[0]][x[1]][x[2]];

console.log(fx(pos ));
console.log(fx(pos1));
console.log(fx(pos2));
// >> '022'
// >> '102'
// >> '201'
```
同じような状況で配列がこんな場合はどうでしょう

```js
arr=[
  [['000', '001'], '01', ['020', '021', ['0220', '0221']]],
  ['10', ['110', '111', '112'], '12'],
  [[['2000', '2001', '2002'], '201', ['2020', '2021']], ['210', '211']]
];
pos =[0,2,2,0];
pos1=[1,0];
pos2=[2,0,2,1];
```
先程の関数に通してみます

```js
console.log(fx(pos ));
console.log(fx(pos1));
console.log(fx(pos2));

// >> ['0220', '0221']
// >> undefined
// >> ['2020', '2021']
```
場所によって深さが違うことが原因のようです
そこでこんな関数を作ってみました

```js
const fx_=x=>x.reduce((a,c)=>a[c],arr);

console.log(fx_(pos ));
console.log(fx_(pos1));
console.log(fx_(pos2));

// >> '0220'
// >> '10'
// >> '2021'
```
便利。
#解説
そもそもreduceとは

[Array.prototype.reduce() MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce)

> ```arr.reduce(callback[, initialValue]);```

> - **arr** : 処理をしたい配列
- **callback** : コールバック関数 処理をここに書く 引数は以下の4つ
    - **accumulator** : 前の処理の戻り値 or 最初の要素 or initialValue
    - **currentValue** : 現在処理されている配列の要素
    - ***index*** : 現在処理している配列のインデックス 必須ではない
    - ***array*** : 処理している配列 必須ではない
- ***initialValue*** : 一番最初の処理でaccumulatorとして渡される値 必須ではない

配列全部の要素を使って何か一つの値を出すのに向いてます
よく挙げられる配列の全要素の合計を出す例で動作を見てみます

```js
var tmp=[1,2,3,4,5].reduce((a,c,i)=>{
  console.log(a,c,i);
  return a+c;
});
console.log(tmp);

// >> 1, 2, 1
// >> 3, 3, 2
// >> 6, 4, 3
// >> 10, 5, 4
// >> 15
```
注目して欲しいのがインデックス番号です
0からではなく1から始まっています
そして最初のaccumulatorに0番目の要素が使われています
initialValueを入れて実行してみます

```js
var tmp=[1,2,3,4,5].reduce((a,c,i)=>{
  console.log(a,c,i);
  return a+c;
},0);// initialValue=0
console.log(tmp);

// >> 0, 1, 0  ←処理が増えてる
// >> 1, 2, 1
// >> 3, 3, 2
// >> 6, 4, 3
// >> 10, 5, 4
// >> 15
```
0, 1, 0の出力があります
つまりinitialValueがないと
**本来initialValueとarr[0]で行われる処理がなくなる**
ということです

単純な数の演算ではない使い方をする場合は
恐らくこちらの方が都合が良いことが多いでしょう

冒頭ではこの仕様を使って配列からデータを取り出しています

```js
var arr=[
  [['000', '001'], '01', ['020', '021', ['0220', '0221']]],
  ['10', ['110', '111', '112'], '12'],
  [[['2000', '2001', '2002'], '201', ['2020', '2021']], ['210', '211']]
];
var pos =[0,2,2,0];

const fx_=x=>x.reduce((a,c)=>{
  console.log(a,c);
  return a[c];
},arr);// arrが最初のaccumilatorに渡される

console.log(fx_(pos));

// >> [[["000","001"],"01",["020","021",["0220","0221"]…, 0
// >> [["000","001"],"01",["020","021",["0220","0221"]]], 2
// >> ["020","021",["0220","0221"]], 2
// >> ["0220","0221"], 0
// >> "0220"
```
配列に一階層ずつ潜っていく様子がわかります

#さいごに
そもそもこんな複雑な配列を作るなら連想配列を使うべきだったと思います
反省してます…

最後まで読んでくださりありがとうございます。
【RxSwift】Reactive の Extension を作成する際にメモリリークが発生した

## 環境
- Xcode 12.3
- RxSwift 5.1.1

## 目的

- `TabTestViewController` の `self.viewDidLayoutSubviews()` 呼び出しを検知しその際の `self.index` を流す `Observable<Int>` を作成したい

```TabTestViewController.swift

// こんな感じで利用する currentIndexDidChange を Extension で実装
self.rx.currentIndexDidChange
    .subscribe(self.indexSubject)
    .disposed(by: self.disposeBag)
```

## 当初実装

- 以下のように実装するとメモリリークが発生する

```TabTestViewController+rx.swift

extension Reactive where Base: TabTestViewController {

    var currentIndexDidChange: Observable<Int> {
        
        // メモリリークが発生
        return sentMessage(#selector(base.viewDidLayoutSubviews))
            .map { _ in base.currentIndex }
            .distinctUntilChanged()
            .share(replay: 1)
    }
}
```

## 原因
- `base` がクロージャ内部で強参照されていることによる

## 間違い: `self` を弱参照しようとした

-  「クロージャの中では `self`を弱参照」と手癖で実装しようとしたところコンパイルエラー
    - `Reactive<Base>` は構造体のため `weak` が使えない

```TabTestViewController+rx.swift

extension Reactive where Base: TabTestViewController {
    
    var currentIndexDidChange: Observable<Int> {
        
        // 'weak' may only be applied to class and class-bound protocol types, not 'Reactive<Base>'
        return sentMessage(#selector(base.viewDidLayoutSubviews))
            .map { [weak self] _ in
                
                guard let self = self else { fatalError() }
                
                return self.base.currentIndex
            }
            .distinctUntilChanged()
            .share(replay: 1)
    }
}

```

## 解決: `base` を弱参照とする

- `TabTestViewController` はクラスのため `weak` で弱参照することができる

```TabTestViewController+rx.swift
extension Reactive where Base: TabTestViewController {
    
    var currentIndexDidChange: Observable<Int> {
        
        // viewDidLayoutSubviewsのタイミングでcurrentIndexの変化を検知する
        return sentMessage(#selector(base.viewDidLayoutSubviews))
            .map { [weak base] _ in
                
                guard let base = base else { fatalError() }
                
                return base.currentIndex
            }
            .distinctUntilChanged()
            .share(replay: 1)
    }
}
Java シリアルツール性能比較

# Java シリアルツール性能比較

本ページでは主にjavaのシリアルツールの性能比較を記載します。
コードと結果の部分があります。

###使用されたのdependency 

- Java原生方法
- XStream方式
- FastJson方式
- Hessian方式

### シリアルされたデータ

```java
@Data
public class User implements Serializable {
    private static final long serialVersionUID = -2564324657866843L;
    private String name;
    private int age;

    private void writeObject(java.io.ObjectOutputStream s) throws IOException {
        s.defaultWriteObject();
        s.writeObject(name);
    }

    private void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException {
        s.defaultReadObject();
        name=(String)s.readObject();
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
```

Userのデータをシリアル化されたデータのレングスに基づいて、ツール間の効率を検証します。

### 効率検証

1・ まずJava原生登場

   ```java
   ByteArrayOutputStream byteArrayOutputStream=
           new ByteArrayOutputStream();
   try {
       ObjectOutputStream outputStream=
               new ObjectOutputStream(byteArrayOutputStream);
   
       outputStream.writeObject(obj);
   
       return  byteArrayOutputStream.toByteArray();
   } catch (IOException e) {
       e.printStackTrace();
   }
   return new byte[0];
   ```

   データのレングスはどのぐらいですか？

   **byte.length:92**

   

2・ 次はXStreamですXMLにベースのツールです

   ```java
   XStream xStream=new XStream(new DomDriver());
   
   @Override
   public <T> byte[] serialize(T obj) {
   
       return xStream.toXML(obj).getBytes();
   }
   ```

   データのレングスはどのぐらいですか？

   **byte.length:221** やはりXMLですね～

   

3・ そしてFastJson登場、中国企業Alibaba 開発されたのツールです。

   ```java
   return JSON.toJSONString(obj).getBytes();
   ```

   書き方は安いですか？

   でデータのレングスはどのぐらいですか？

   **byte.length:23**　すごいのシリアルですね

4・ 最後にはHessianです

   ```java
   ByteArrayOutputStream outputStream=new ByteArrayOutputStream();
   HessianOutput hessianOutput=new HessianOutput(outputStream);
   try {
       hessianOutput.writeObject(obj);
       return outputStream.toByteArray();
   } catch (IOException e) {
       e.printStackTrace();
   }
   ```

   結果は以下です↓

   **byte.length:50**

### まとめ

比較してみると,fastjsonは最も効率的なツールです。でも他のツールが悪いわけではない。fastjsonは複数言語に対応できないので。皆さんは項目の内容に応じてシリアルツール使うしよう！
PostgreSQLでWITHのサブクエリをINで利用できなかった話

業務でSQLを書いていたときにかなり長い時間Syntax Errorということで悩んでいたことを書いていきます。

SQLでは条件を絞る際、カラムが指定値のいずれかであるかを判定することができます。

```SQL
SELECT *
  FROM table_a
 WHERE some_column IN (1, 2, 3);
```

これには直接指定する他、1カラムのみを返すサブクエリを指定することもできます。

```SQL
SELECT *
  FROM table_a
 WHERE some_column IN (
       SELECT other_column
         FROM table_b
        WHERE other_column > 10
);
```

またこれとは別の話で、サブクエリを`WITH`句を使ってクエリの外部に書くということもできます。

```SQL
WITH tmptable AS (
     SELECT max(other_column) as max_value -- ,...
       FROM table_a
      GROUP BY some_column
)
SELECT *
  FROM tmptable
 WHERE max_value = 20;
```

これらができるということで、私はこのようなクエリを書きました。

```SQL
-- 注意：Syntax Errorになります
WITH tmptable AS (
     SELECT other_column
       FROM table_b
      WHERE other_column > 10
)
SELECT *
  FROM table_a
 WHERE some_column IN tmptable;
```

このクエリの実行には失敗して、最終的にはサブクエリを直接`IN`の後に書いて動作するようにしました。(実際に書いていたクエリはかなり長かったので半分苦渋の決断でした)

(追記)
この記事を投稿した後、社内の方から対処法を教えてもらうことができました。

```SQL
-- 注意：Syntax Errorになります
WITH tmptable AS (
     SELECT other_column
       FROM table_b
      WHERE other_column > 10
)
SELECT *
  FROM table_a
 WHERE some_column IN (SELECT other_column FROM tmptable);
```

`IN`句の後に書くものは列挙かSELECT文でなければいけないようです。
【CSS】marginかpaddingどちらを使うか？（marginとpaddingの仕様の違い）

余白を追加したい場合にmarginかpaddingどちらを使うかがわからなかったので調べてみた。

##説明できますか？
ある要素（モジュール）の**上に24pxの余白を追加する場合、`margin-top`で24px指定するのと、`padding-top`で24px指定するのは何が違うか？**

そして、**どちらを使うべきか？**


<br>
##回答
推奨は**`margin`**。

理由は**marginの持つ相殺機能**のため。**marginを使えば意図した間隔を保つことができる**。

一方**paddingは上の要素の状況によって隙間が変動**してしまうため。


>上の要素（モジュール）に`margin-bottom`のようなプロパティが適用されていない場合はどちらを使っても見た目は同じ。
ただし、上の要素に`margin-bottom`が適用されていると挙動が変わってくるという話。




###padddingの場合
`padding-top`で隙間を作った場合、上の要素に`margin-bottom`が適用されていると、**２つの要素の間隔は合計値**になる。

例えば、上の要素が`margin-bottom: 24px`、下の要素が`padding-bottom: 24px`の場合、間隔は`48px`となる。

意図した24pxよりかなり大きくなってしまう、、


<br>
###marginの場合
marginの場合は大きい方の間隔が適用される。

例えば、上の要素が`margin-bottom: 24px`、下の要素が`margin-bottom: 24px`の場合、間隔は`24px`となる。

なので、意図した感覚を保つことができる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563526/fc2bc0bd-6664-b8ed-7f60-9fc019632745.png)


ちなみに上の要素の`margin-bottom`の値が下の要素の`margin-top`よりも大きければ、大きい方の値が優先される。
Laravel6でmorphToのリレーション先テーブルの参照するカラムを変更したい時

そもそもそんなテーブル設計は間違っているということはいったんさておき、表題の対応しなければいけないことがあったのでメモとして残す


```php
default_templates
 - template_id
 - name

user_created_templates
 - id
 - name

reports
 - id
 - templatable_id
 - templatable_type
```

運用者が頻繁に更新する自動採番IDを持たないテーブルと、ユーザーが自分でCURDするテーブルがあってそれらをポリモーフィックで呼び出したいというケース。

いずれのテーブルもプライマリキーがidという場合にはモデル内部で`morphTo`で参照すればいい。

今回のケースで言えば`templatable_type`に応じて参照するキーを動的に変更したいので下記のようにすると参照可能。

```php:Models/report.php
class report exteds Model
{
    public function templatable()
    {
        $ownerKey = $this->getAttribute('templatable_type') === 'App\Models\DefaultTemplate'
            ? 'template_id'
            : 'id';
        return $this->morphTo('templatable', null, null, $ownerKey);
    }
}
```
DRY原則・CoC原則とは


DRY（ドライ）原則、CoC原則について学習したので復習をかねてアウトプットします。

#DRY原則とは

Don't Repeat Yourselfの略で、「繰り返しを避けるという意味合いがあります。
つまり、別々の場所で同じものを書いてはいけないよと言うことです。
なぜならば、コーディングをする上で同じコードを複数の場所に書くことは、その分だけ管理する場所がどんどん増えていくことを意味し、それだけ手間や時間が削られて行くからです。
はじめは数箇所だけだったとしても作業を重ねていくうちに増え、１００箇所分すべて修正する事になった場合はどうでしょうか。
一箇所の修正だけならば早く解決できます。

手作業の修正ならばなおさらバグや変更が減り、作業効率を向上してくれるでしょう。

もちろん、必ずしなければいけないということではなく、今後仕事として依頼を受ける時に全部の箇所を覚えていくことは難しくできる限り修正箇所を増やさないためにも頭の片隅においておくといい考え方です。


#CoC原則とは

Convention over Configurationの略で、「設定よりも規約を優先する」という考え方です。
どういうことかと言いますと、例えばRuby on Railsではファイル名の規約・テーブル定義の規約など様々な規約がありますがこの規約通りに記述することで、コードの量を大幅に減らすことが出来ます。
それと同時に考える時間も大幅に減らすことが出来るので、作業効率、開発速度が向上します。
例えば、アソシエーション（テーブル同士の関係性）を示すhas_manyやbelongs_toなどすでに決まっている単語があります。これらは関連付けをする時に覚えておかないと関連付けが出来ません。
もちろん自分で設定することが出来るものもありますが、その都度考え、設定していったのでは物凄く時間をかけてしまいます。
Ruby on Railsには他にもたくさんの規約に則した単語があります。その一つ一つに意味（役割）があると思って覚えていくのが良いでしょう。



今回の記事は以上になります。色々と拙い部分があるかと思います。間違っている点、理解が不完全な点があればご指摘いただければ幸いです。





今回の記事は以上になります。
色々と拙い部分があるかと思います。
間違っている点、理解が不完全な点があればご指摘いただければ幸いです。
[Tableau] プライマリ グループの作り方

#こんなときに
特定のIDにつながるデータがいろいろなデータソースごとに存在する。それらをサクッとつなげたい。

#用意するもの

* データソース : サンプル - スーパーストア (Tableau に入っているサンプルです。)

#環境

* Tableau Desktop : 2020.3.0

#準備
* サンプル – スーパーストアをロードする (デフォルトは「注文」)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177920/ffb0c242-6cb8-3934-1637-e282c078d7d1.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177920/ba2a3dee-09d0-30b9-0536-fb7e6f05f38b.png)

#Step1(別のデータソースを接続）

* サンプル – スーパーストア を開いた状態で別のデータソースと接続する
  
サンプルの都合上 もう1回 同じスーパーストアを開きます。（頭の中では別のデータソースと思ってください）

* 右上の Tableau アイコンをクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177920/1b67a027-6ffb-a90d-2856-60aaf004d30c.png)

* 「準備」と同じように 接続のメニューが出てくるので、下の方の「サンプル –スーパーストア」を再度選択
* データの中に「サンプル - スーパーストア(２)」が出てくる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177920/6fd8cafa-fe55-6a44-d2a3-5bdde4a7752e.png)

* データソースのシートへ戻り、以下のように「サンプル – スーパーストア(2)」を選択

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177920/908757e0-50d0-02dc-462a-3218154d6afe.png)

* 今回は「関係者」をドラッグする。（通常は”注文”になってるが）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177920/48ee3921-976e-b9bc-3155-e70c4c9ae3ff.png)

* シートに戻ると データ が増えており、ディメンションも変わっているはず

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177920/e5276a7b-e9ce-7eb0-1ea8-aaebe8b14181.png)

* データを「サンプル – スーパーストア」へ切り替える

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177920/49c5c0ac-4410-7ca6-3746-013437b83221.png)

#Step2(プライマリグループの作成)

サンプル – スーパーストア の地域に その地域の担当マネージャー情報を紐づける

* 行に 地域を入れる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177920/9b34b29f-e154-59e6-4928-acc275ef6b4c.png)

* データを「サンプル – スーパーストア(2)」に切り替え、地域マネージャーを行に入れる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177920/c013957e-b980-fa47-8880-0568ee0c0adc.png)

* 地域マネージャーを右クリックし、「プライマリグループの作成」を選択

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177920/5a546767-29d1-9f7a-f7a3-85b0a31a374b.png)

* グループの編集が出てくるので、適当にグループ名をつける （ここではエリアマネージャー）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177920/b308a104-0ed0-6323-843c-33f4a69ea6f5.png)

これで データ「サンプル – スーパーストア」の方に“エリアマネージャ”というグループが作成される

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177920/ca1009cd-edd8-dfea-061b-cc098e16c759.png)

#完成

これで データソース 「サンプル – スーパーストア」 のみで地域の担当マネージャーの情報（”エリアマネージャー” として）を扱えるようになる。
紛らわしい「サンプル – スーパーストア(2)」は閉じても良い。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177920/0252d01f-71e2-b159-ae15-9eeda356af3e.png)


わりとお手軽にさくさくデータを連結できるのでおすすめです。

#参考文献

* [フィールドをプライマリ データ ソースに取り込む](https://help.tableau.com/current/pro/desktop/ja-jp/multipleconnections_create_primary_group.htm)
Javascriptのイテレータ

`.next()` ができるのがイテレータ。

```js
myList = [1,2,3]
(3) [1, 2, 3]

ite = myList.entries();
Array Iterator {}

typeof ite
"object"

ite.next().value;
(2) [0, 1]
ite.next().value;
(2) [1, 2]
ite.next().value;
(2) [2, 3]
ite.next().value;
undefined
```



```js
const iterator = Array.from('abcdefghij').entries()

iterator.next().value;
(2) [0, "a"]
iterator.next().value;
(2) [1, "b"]
iterator.next().value;
(2) [2, "c"]
iterator.next().value;
(2) [3, "d"]
iterator.next().value;
(2) [4, "e"]
iterator.next().value;
(2) [5, "f"]
iterator.next().value;
(2) [6, "g"]
iterator.next().value;
(2) [7, "h"]
iterator.next().value;
(2) [8, "i"]
iterator.next().value;
(2) [9, "j"]

```

ref
https://stackoverflow.com/questions/40639432/what-is-the-best-way-to-limit-concurrency-when-using-es6s-promise-all
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/for-await...of
Docker有償プラン(Pro)の申込方法

# はじめに
昨年(2020年)に一部を騒がせたDockerのフリープランでの各種制限の導入ですが、みなさんもイメージをプルする前にDockerにログインしておくなど、以前とは開発体験に変化があったのではないでしょうか？

ここでは、FreeプランからProプランへの移行申込方法についてご紹介します。入力等、画面を見ればあまりに自明だからなのか、Qiitaでも類似した記事を見つけられなかったので、書いてみました。

# FreeプランとProプランの違い
移行手続きに入る前に、FreeプランとProプランでできることにどの程度違いがあるのでしょうか？ 詳しくは、[Pricing & Subscriptions](https://www.docker.com/pricing)のページをご覧いただくのが早いのですが、今日(2021/01/22)現在では、こういった違いがあるようです。

## Freeプラン(無料)
- パブリックなリポジトリをいくつでも作成可能
- プライベートなリポジトリは1つのみ作成可能
- ロールベースのアクセス制限が可能なユーザ管理
- 1チーム、3チームメンバーまで登録可能
- コンテナイメージのプルリクエストは6時間200回まで(未ログインだとIPアドレスごとに6時間で100回まで)
- 2要素認証の設定可能

## Proプラン(7ドル/月, または60ドル/年)
- Freeプランでの提供内容(上述)プラス
- プライベートなリポジトリもいくつでも作成可能
- コンテナイメージのプルリクエスト回数は無制限
- 2パラレルビルド
- 1サービスアカウント
- Slack通知
- 300イメージ/月まで脆弱性スキャン
- プレミアムカスタマーサポート(メールベース)

得られる「開発者体験」が毎月7ドル(年払いなら5ドル)に見合うのであれば、Proプランを申し込みましょう！

# Proプラン申込手順

## 自アカウントにログイン、加入中プランを確認
[dockerhub](https://hub.docker.com)にアクセスし、自分のアカウントにログインします。

右上の指紋マークの左側にある自分のIDをクリックし、Billingをクリックすると、現在加入中のプランが表示されます。

![Free Repository Plan](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19248/fdf93478-03f6-ec7c-44e6-afc7284d9c10.png)

上の画面では、現在加入中のプランが *Free Repository Plan* である旨、表示されています。では、右側にある `Change Plan` ボタンをクリックします。

## アップグレードプランの内容・費用確認
先にご紹介したようなFreeプランとProプランの比較、ならびに費用が表示されていますので、確認の上、`Upgrade now`ボタンをクリックします。

![Change Plan](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19248/fcfdfe54-5192-7369-5b33-219a12955e36.png)

なお、Learn moreリンクをクリックすると、[Pricing & Subscriptions](https://www.docker.com/pricing)のページが表示され、FreeとProの他に、Teamプラン、Largeプランについての情報も提供されています。

## 支払方法の入力

さて、`Upgrade now`ボタンをクリックすると、Payment Method(支払方法)の入力画面になります。年払い(pay annually)か月払い(pay monthly)を選択の上、氏名、クレジットカード番号、有効期限、CNN、住所(CountryにJapanを指定すると郵便番号入力欄が表示されます)を入力し、`Purchase`(購入)ボタンをクリックします。

![Payment Method](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19248/3e237d03-a6e7-c449-6434-e356a17c53cb.png)

## アップグレード完了
`Purchase`ボタンをクリックすると、現在加入中のプランが改めて表示されます。先ほどはFree Repository Planだったのが、Pro Planに更新されているのがわかります。

![Pro Plan](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19248/072e67b9-1f0a-5cfd-87f0-3956cc1ebe72.png)

# おわりに
さて、Proプランであれば、Slack通知、および脆弱性プランの設定方法が気になるところです。別途、記事を起こして紹介させていただきます。
shopify GraphQLAPIで店舗の名前を取得する

# shopify GraphQLAPIで店舗の名前を取得する
## 前提
Postmanのインストール
shopifyで店舗開設済み
プライベートアプリ開設済み

## Postmanでプロジェクト作成
左上の+Newアイコンから新しくプロジェクトを作成
以下設定
1.HTTPメソッドをPOST設定
2.URLをhttps://{shopName}.myshopify.com./api/2020-10/graphqlに設定。（apiのバージョンはその時々に合わせてください）
3.Headersに2つパラメータ追加
　　X-Shopify-Storefront-Access-Token: 値にプライベートアプリのAPIキーのパスワード(shppaから始まる)
   Accept: 値にapplication/json
4.BodyをGraphqlに設定

以上で設定はOK
以下のようになる。
![スクリーンショット 2021-01-22 18.36.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1022774/a3c9d114-a528-89be-32a8-266d45fd72f8.png)
{shopName}とAPIKEY関しては各自で入力してください

## BodyにQueryを記述

```
query {
    shop {
        name
    }
}
```

sendを実行すると、Responseに以下のように返って来ると思います。

```
{
    "data": {
        "shop": {
            "name": "OrenoMise"
        }
    },
    "extensions": {
        "cost": {
            "requestedQueryCost": 1,
            "actualQueryCost": 1,
            "throttleStatus": {
                "maximumAvailable": 1000.0,
                "currentlyAvailable": 999,
                "restoreRate": 50.0
            }
        }
    }
}
```

shopNameを取得しただけですが、ShopifyGraphQLAPIの動作を感じていただければ幸いです。
Python による Microsoft Graph API を利用した全グループ情報を取得してみました

## 概要
Microsoft Graph API を利用してAzureActiveDirectoryから全グループ情報を取得するための Python プログラムです。
Access Token の取得については、[このプログラム](https://qiita.com/turupon/items/038b893712433ed23f0b) を使用しています。
全ユーザ情報の取得については [こちら](https://qiita.com/turupon/items/25b5d17601b9af9ba57f) を参照ください。

## 実行環境
macOS Big Sur 11.1 
python 3.8.3

## 実行プログラム

```python:GetAzureADGroups.py

import json
import requests
import argparse
import time
from GetAzureAccessToken import get_azure_access_token  # Azureアクセスのためのアクセストークンの取得オリジナル関数


# 全User情報の取得
def get_ad_all_groups(access_token):

    # Microsoft Graphを実行するためのヘッダ情報
    headers = {
        'Authorization': 'Bearer %s' % access_token
    }

	# 全グループの id, ddisplayName, mail の取得のURL
    UsersGet_URL = "https://graph.microsoft.com/v1.0/groups?$count=true&$select=id,displayName,mail&$orderby=displayName"

    # 全Users情報取得のGetリクエスト
    res1 = requests.get(
        UsersGet_URL,
        headers=headers
    )
    # requrest処理をクローズする
    res1.close

    # res1をjsonファイルに整形しユーザ情報の取得
    print("取得した全グループ情報：")
    for num, item in enumerate(res1.json()['value']):
        print(item)

    return num+1


if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='AzureActiveDirectoryの全Group情報の取得')
    args = parser.parse_args()

    start = time.time()
    access_token = get_azure_access_token()
    num = get_ad_all_groups(access_token)
    get_time = time.time() - start

    print("")
    print(f"全グループ数:{num}")
    print("取得時間:{0}".format(get_time) + " [sec]")
    print("")
```

## プログラムの実行
 
最初にヘルプを表示してみます。

```
$ python GetAzureADGroups.py -h
usage: GetAzureADGroups.py [-h]

AzureActiveDirectoryの全Group情報の取得

optional arguments:
  -h, --help  show this help message and exit
```


では、全グループ情報を取得してみます。

```
$ python GetAzureADGroups.py
取得した全グループ情報：
    中略
{'id': 'ae666666-9196-4586-8788-5521024bbbbb', 'displayName': 'PSG0', 'mail': None}
{'id': 'b8811111-2986-4615-8823-11bbdd56d000', 'displayName': 'PSG1', 'mail': None}
{'id': 'de999999-5059-4656-9512-7800bd514444', 'displayName': 'PSG2', 'mail': None}
    中略

全グループ数:28
取得時間:0.5144941806793213 [sec]
```

## 参考情報
以下の情報を参考にさせていただきました。感謝いたします。

[Azure AD ユーザーアカウントの棚卸しに便利なスクリプト](https://qiita.com/tetsuya-ooooo/items/02e66dd35a102792402c)

[Microsoft Graph を使ってみよう : Graph エクスプローラー](https://qiita.com/kenakamu/items/17905fe66345b8e3754b)
TeXShopでマジックコメント %! TEX program = LuaLaTeXが指定されている場合に-shell-escapeを有効にする方法

# tl;dr
`~/Library/TeXShop/Engines/LuaLaTeX.engine`のシェルスクリプトの`lualatex`呼び出しに`-shell-escape`を加えると良い。

# 概要
LaTeXにはいくつかの処理系がありますが（pdflatex、uplatex、lualatexなど）、たくさん文章を書いていると時期によって使う処理系が違ってくることがあります。
そんな時には、ソースファイルの先頭にマジックコメントを追加して、各ソースファイルに対して利用する処理系を指定してあげると、TeXShop系の対話的にソースファイルをタイプセットするエディタで上手くいくようになります。
具体的に、LuaLaTeXを指定したい場合は、以下のようなマジックコメントをソースファイルの先頭に追加します。

```tex
% !TEX program = LuaLaTeX
```

# -shell-escapeが必要になる場合
多くのソースファイルは上の設定を行うだけで、LuaLaTeXでタイプセットできるようになりますが、使用しているパッケージによっては`-shell-escape`が必要というエラーが出ることがあります。
`-shell-escape`とは処理系に任意の外部コマンドの実行を許可するオプションで、デフォルトではセキュリティのためオフになっていますが、外部のコマンドを使った高度な処理を行いたく、タイプセットする文章が自分で書いたなどの理由で信頼できる場合はオンにしたくなる場合があります。
`-shell-escape`を要求するパッケージとして、例えばPythonを利用して文章内ソースコードのシンタックスハイライトを行うmintedやgnuplotを利用して高度な計算を行うことができるpgfplotsなどが挙げられます。

mintedを利用しているのに`-shell-escape`を指定していない場合は以下のようなエラーが出力されます。

```
! Package minted Error: You must invoke LaTeX with the -shell-escape flag.
```

pgfplotsでgnuplotを利用するコードを書いているのに`-shell-escape`を指定していない場合は以下のようなエラーが出力されます。

```
! Package pgfplots Error: Sorry, the gnuplot-result file 'main.sin.table' could
 not be found. Maybe you need to enable the shell-escape feature? For pdflatex,
 this is '>> pdflatex -shell-escape'. You can also invoke '>> gnuplot <file>.gn
uplot' manually on the respective gnuplot file..
```

# -shell-escapeの指定の方法
TeXShopの環境設定には以下に示すように内部設定というものがあり、ここでタイプセットに関わるコマンドの設定を行うことができます。
![TeXShop-Internal.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35580/72c9b1bf-b78d-859b-b85a-f18b56a20767.png)

しかし、この設定はマジックコメントでLuaLaTeXを指定した場合は有効ではありません。
マジックコメントでLuaLaTeXを指定した場合は、`~/Library/TeXShop/Engines/LuaLaTeX.engine`というシェルスクリプトが呼び出されるようになっていて、環境設定で指定したコマンドは無視されます。
なので、このシェルスクリプトを編集して、`lualatex`コマンド呼び出し時に`-shell-escape`が渡されるようにします。

`~/Library/TeXShop/Engines/LuaLaTeX.engine`はデフォルトでは以下のような内容となっています。

```tcsh
#!/bin/tcsh

set path= ($path /Library/TeX/texbin /usr/texbin /usr/local/bin)
lualatex -file-line-error -synctex=1 "$1
```
これを次のように編集します。編集内容としては`lualatex`コマンドに追加で`-shell-escape`オプションを渡しているだけです。

```tcsh
#!/bin/tcsh

set path= ($path /Library/TeX/texbin /usr/texbin /usr/local/bin)
lualatex -file-line-error -synctex=1 -shell-escape "$1
```

これで、mintedやgnuplotを利用しているpgfplotsを使っている場合でも正常にタイプセットできるようになります。

もし、セキュリティ上のへ不安がある場合には、`~/Library/TeXShop/Engines/LuaLaTeX-shellescape.engine`というファイルを新規作成して、ソースファイルには`% !TEX program = LuaLaTeX-shellescape`を指定するようにすると良いでしょう。

# 結論
TeXShopでマジックコメントによる処理系の指定をしている場合は、`~/Library/TeXShop/Engines/*.engine`に`-shell-escape`を追加する必要があります。
これは、LuaLaTeX以外の処理系を指定している場合も同様なので、マジックコメントで処理系を指定したくて、`-shell-escape`を指定したい場合は、同様の手順を試してみてください。

# 参考
- [Stack Overflow - How to customize the default xelatex command in TexShop for OSX
](https://tex.stackexchange.com/questions/45648/how-to-customize-the-default-xelatex-command-in-texshop-for-osx)
[PowerPoint]ZoomでPowerPointの発表者ツールを使用する方法

# あらすじ
先日、イベントで登壇する機会があったのですが、このご時世のため`Zoom`でのオンライン開催でした。

`Zoom`で`PowerPoint`のスライドショーを画面共有しながら、いつもの`発表者ツール`でカンペを見たい・・・
でも、`発表者ツール`の状態で画面共有すると、そのままみんなに配信されてしまう・・・
印刷した紙を見ながら発表なんか嫌だ！

ということで、色々試してみました。
# やり方

1. あらかじめ、共有したい`PowerPoint`のファイルを開いておく
1. `Zoom`で`PowerPoint`のウィンドウを共有する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352434/0eb6bb16-6c8d-aa05-5f60-c99bf9b540ce.png)
1. 共有したら、スライドショーを開始する
1. `発表者ツール`を表示する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352434/b067297b-c4ac-20d8-fbc5-bc9e03b006c8.png)
1. 完了！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352434/6a7be4f3-4387-820e-ae2a-b033658f1148.png)
これで、
    - 自分の画面：`発表者ツール`
    - 他者の画面：`スライドショー`  
という状態になります。

# 結論
`PowerPoint`を **ウィンドウ共有した後に**、スライドショーを開始して、`発表者ツール`を開こう！
Dartユニットテスト：時刻処理をテストするために日付処理のモックを作成する


こんにちは。
人間ミスはつきものですね。
ミスを見つけるためにも、ある程度の規模や複雑性のあるコードを書いた場合、ユニットテストを書いたほうがいいと思っています。（実践できているかはさておき）。

今回、日付周りの処理を実装したのですが、この辺パターンが膨大になるのでテストを書きました。
その備忘録です。

## この記事で説明すること
* 既存機能（DateTime）を拡張する方法
* dartのユニットテストの基本的な方法
* ユニットテストで日付モックを使う方法（pluginなし）

## 既存機能（DateTime）を拡張する方法

他の言語にもありますが、dartにも既存機能を拡張する方法があります。

個人的には下記のことに気をつけています。

* 不用意に拡張しない
* 拡張したことがわかるように〇〇_estensionsという名前にしている

```dart:datetime_extensions.dart
extension DateTimeExtension on DateTime {
  // インスタンスメソッドの拡張
  // thisで自分自身（dateTimeインスタンス）にアクセス
  String get ymdJp => DateFormat("yyyy年M月d日", "ja_JP").format(this);

  // クラス変数
  static DateTime _customTime;
  static set customTime(DateTime customTime) {
    _customTime = customTime;
  }

  // クラスメソッドとして拡張
  static DateTime get current {
    return _customTime ?? DateTime.now();
  }
}
```

解説
* `extension Extension名 on もとのクラス名` でクラスを拡張する
* extensionの中に、拡張したい機能を追加する（インスタンスメソッド、クラスメソッドのどちらも拡張可能）

## 拡張したコードの呼び出し方法

こんな感じで呼び出せます。インスタンスメソッドはわかりやすいですね。
クラスメソッドは、クラスが変わっているので注意が必要です。

あと、extensionしたファイルをimportする必要があります。

```dart:sample_widget.dart
// importの場所は人によって異なるので注意してください
import 'package:cojicaji/extension/datetime_extension.dart';
import 'package:flutter/material.dart';

class SampleWidget extends StatelessWidget {
 
  @override
  Widget build(BuildContext context) {
    DateTime dateTime = DateTime.now();
    return Text(dateTime.ymdJp);
  }
}
```

```dart:review_logic.dart
import 'package:cojicaji/extension/datetime_extension.dart';

class ReviewLogic {
  /// レビュー依頼を表示するかどうかを判定するダミーロジック
  bool isShowReview() {
    // 前回のレビュー発火から28日以上立っているか？（標準ライブラリでNヶ月計算しにくいので日付換算）
    // Yes -> レビューだす / No -> レビュー依頼ださない
    
    // 本日の日付と最終レビュー依頼日付を取得する。最終レビュー日付依頼のコードはダミー
    DateTime today = DateTimeExtension.current;    
    DateTime lastReviewRequestDate = getLastReviewRequestDateTime();
      
    Duration difference = today.difference(lastReviewRequest);
    if (difference.inDays < 28) {
      return false; // noNeedReview;
    }
    
    return true;
  }

}
```

## 日付モックをUnitTestする方法

サンプルコードとざっくり解説します。

* `void main() {}`の中にテストを書く
* `group`を使ってテストコードをグルーピングできる。ネスト可能。
* `setUp()`は、`test()`の前に毎回走る処理。共通する初期化などを書く
* テストは無形関数を使って、`test('testケース', () {})`のように書く。日本語OK。
* `expect`を使って、結果を評価する


```dart:hoge_test.dart
import 'package:cojicaji/extension/datetime_extension.dart';

void main() {
  group('レビュー依頼の判定', () {
    group('28日以上経過してる場合', () {
      setUp(() {
        // テストが1つしかないなら、ここに書く必要は本当はないが、解説の都合で記載。
        // 日付のモック更新
        var currentUtcDateTimeMock = DateTime.utc(2021, 1, 28);
        DateTimeExtension.customTime = currentUtcDateTimeMock;
      });
    
      test('レビュー依頼がでること', () {
        var logic = new ReviewLogic();
        var result = logic.isShowReview();
        expect(result, true);
      });
```


## 参考文献
- https://stackoverflow.com/questions/53674027/is-there-a-way-to-fake-datetime-
terminals database is inaccessibleを解決した時のメモ

## 問題の概要

とあるDockerコンテナ内で`clear`コマンドを使ったら

```
terminals database is inaccessible
```

が出ました。コンテナはDebianベースの環境です。

## 解決法
まずterminfoをインストールします。

```shell
$ apt install ncurses-term
```

次に、`~/.profile`にterminfo関連の環境変数を設定します。

```shell:~/.profile
export TERMINFO=/usr/share/terminfo
export TERM=xterm+256color
```

編集後は`source ~/.profile`で変更を適用します。

`TERMINFO`にはterminfoファイルのあるパスを、`TERM`にはその中にあるterminfoファイルを指定します。指定すべき値は環境によって異なる場合があると思います。上記の例では`xterm+256color`のパスは`/usr/share/terminfo/x/xterm+256color`になります。

## 原因
エラーが出ている状態で`infocmp`コマンドを実行すると、下記に示すterminfoが見つからないというようなエラーが出ます。

```
$ infocmp
infocmp: couldn't open terminfo file xterm-256color.
```

これが原因です。つまり、terminfoを見つけらるようにすれば解決するということです。

## 参考文献
- [macos - I can't clear the terminal in Mac OS X Lion - "terminals database is inaccessible" - Super User](https://superuser.com/questions/319912/i-cant-clear-the-terminal-in-mac-os-x-lion-terminals-database-is-inaccessibl)
- [configure - Trouble opening Ncurses Examples in OS X - Stack Overflow](https://stackoverflow.com/questions/43130276/trouble-opening-ncurses-examples-in-os-x#answer-43130638)
- [ Ubuntuでxterm-256colorのterminfoがないと怒られた - 絶品ゆどうふのタレ](http://yudoufu.hatenablog.jp/entry/20100930/1285813510)
- [GNU screen内からsshした先にTERM=screen.xterm-256color等がない場合の対処法](https://rcmdnk.com/blog/2018/02/02/computer-bash-network/)
C#でAtCoder Beginners Selection（ABC085B - Kagami Mochi）

####準備
[C#でAtCoderデビューのための準備]
(https://qiita.com/azumabashi/items/7aa9e4b77c10970cc30a)
のあとで AtCoder Beginners Selection　をやってみました。

####問題文
ABC085B - Kagami Mochi
[https://atcoder.jp/contests/abs/tasks/abc085_b]
(https://atcoder.jp/contests/abs/tasks/abc085_b)

####提出結果

```
using System;
using System.Linq;

class Program
{
	static void Main(string[] args)
    {
        int n = int.Parse(Console.ReadLine());
        var d = Enumerable.Repeat(0, n).ToArray();

        for (int i = 0; i < n; i++)
        {
            d[i] = int.Parse(Console.ReadLine());
        }
        Array.Sort(d);
        int dan = 1;
        for (int i = 1; i < n; i++)
        {
            if (d[i] > d[i -1])
            {
                dan++;
            }
        }
        Console.WriteLine($"{dan}");
    }
}
```

####テスト実行
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/e8fb1126-b3a0-147a-32c6-061e1dcead28.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/a11069cf-b240-0ba8-b9f9-d681f9fddd5d.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/b580b74e-1da3-9f55-f606-260b2ced6c95.png)
Python による Microsoft Graph API を利用した全ユーザ情報を取得してみました

## 概要
Microsoft Graph API を利用してAzureActiveDirectoryから全ユーザ情報を取得するための Python プログラムです。
Access Token の取得については、[このプログラム](https://qiita.com/turupon/items/038b893712433ed23f0b) を使用しています。
全グループ情報の取得については [こちら](https://qiita.com/turupon/items/eb1d88120dbf41a3fa69) を参照ください。


## 実行環境
macOS Big Sur 11.1 
python 3.8.3

## 実行プログラム

```python:GetAzureADUsers.py

import json
import requests
import argparse
import time
from GetAzureAccessToken import get_azure_access_token  # Azureアクセスのためのアクセストークンの取得オリジナル関数

# 全User情報の取得
def get_ad_all_users(access_token):

    # Microsoft Graphを実行するためのヘッダ情報
    headers = {
        'Authorization': 'Bearer %s' % access_token
    }

	# 全メンバーの id, ddisplayName の取得のURL
    UsersGet_URL = "https://graph.microsoft.com/v1.0/users?$count=true&$select=id,displayName,mail&$orderby=displayName"

    # 全Users情報取得のGetリクエスト
    res1 = requests.get(
        UsersGet_URL,
        headers=headers
    )
    # requrest処理をクローズする
    res1.close

    # res1をjsonファイルに整形しユーザ情報の取得
    print("取得した全ユーザ情報：")
    for num, item in enumerate(res1.json()['value']):
        print(item)

    return num+1


if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='AzureActiveDirectoryの全User情報の取得')
    args = parser.parse_args()

    start = time.time()
    access_token = get_azure_access_token()     # Access_tokenの取得
    num = get_ad_all_users(access_token)        # 全ユーザ情報の取得
    get_time = time.time() - start

    print("")
    print(f"全ユーザ数:{num}")
    print("取得時間:{0}".format(get_time) + " [sec]")
    print("")
```

## プログラムの実行
 
最初にヘルプを表示してみます。

```
$ python GetAzureADUsers.py -h
usage: GetAzureADUsers.py [-h]

AzureActiveDirectoryの全User情報の取得

optional arguments:
  -h, --help  show this help message and exit
```


では、全ユーザ情報を取得してみます。

```
$ python GetAzureADUsers.py
取得した全ユーザ情報：
    中略
{'id': 'c3333333-e7e7-4949-8989-5539d465ffff', 'displayName': '山田 太郎', 'mail': 'yamada@hogehoge.com'}
{'id': '25999999-c8c8-4242-baab-e477b1990000', 'displayName': '鈴木 一郎', 'mail': 'suzuki@hogehoge.com'}
{'id': '3f666666-e5e5-4444-8558-0fe4ef0cceee', 'displayName': '木下 藤吉', 'mail': 'kinoshita@hogehoge.com'}
    中略

全ユーザ数:100
取得時間:0.7425880432128906 [sec]
```

## 参考情報
以下の情報を参考にさせていただきました。感謝いたします。
　　[Azure AD ユーザーアカウントの棚卸しに便利なスクリプト](https://qiita.com/tetsuya-ooooo/items/02e66dd35a102792402c)
　　[Microsoft Graph を使ってみよう : Graph エクスプローラー](https://qiita.com/kenakamu/items/17905fe66345b8e3754b)
Rails gem 'devise'でログアウトをコントローラから一発で呼ぶ方法

#Rails gem 'devise'でログアウトをコントローラから一発で呼ぶ方法
今日はrailsのコントローラで一発でログアウトさせるということで記事をかいきます！

結論としては
reset_session
これをコントローラーないに記述するだけでした笑

今回なぜこれを使ったのかと言いますと
現在ユーザ退会機能を作っておりまして、その退会処理の後にログアウトさせる
必要があったために使いました:relaxed:

これ便利なメソッドなので是非皆さんも使ってみてくださいね！！
【初心者メモ】冗長化して稼働率を高くするとは

ご覧いただきありがとうございます。
この記事は[こちら](https://hnnsk.hatenablog.com/entry/2021/06/26/113619)へ移動致しました。
お手数おかけしますが、よろしくお願いいたします。
BASIC認証とは

自分の備忘録用


<h1>Basic認証とは</h1>
ベーシック認証（Basic認証）とはWebサイトの特定の領域、つまりページやファイルにアクセス制限をかけることができる認証方法の1つ。ベーシック認証をかけると、認証をかけたWebサイトにアクセスしようとしたとき、認証ダイアログが立ち上がって、ユーザー名（ID）とパスワードの入力が求められる。

<h1>設定方法</h1>

まずトップページのコントローラーに before_action :basic_authを定義する。

「basic_auth」は変数名なので名前はこれじゃなくてもいい。

```ruby
class アプリ名Controller < ActionController::Base
  before_action :basic_auth


  private

  def basic_auth
    authenticate_or_request_with_http_basic do |username, password|
      username == 'ユーザー名' && password == '好きなパスワード'
    end
  end
end
```

ここに出てくる「authenticate_or_request_with_http_basic」と言うメソッドはRailsに用意されているメソッドで
Basic認証を使うときに必要、ブロックの中にusernameとpasswordを入れdo〜endの中にそれぞれ設定する

<h2>保守性</h2>
でもこのままだとパスワードが丸見えになるので環境変数を設定しその中にusernameとpasswordを代入する形を取る。
macOSがCatalina以降なら
俺はCatalinaなのでこっち

```terminal

% vim ~/.zshrc

# .zshrcを開いたら、「i」とタイプしてインサートモードに移行

# .zshrcの内部に次の記述を追加
export BASIC_AUTH_USER='ユーザー名'
export BASIC_AUTH_PASSWORD='好きなパスワード'
# 記述を追加したら、escキーを押してインサートモードを抜け、 「:wq」と入力して保存して終了する

# .zshrcを再読み込みし、定義した環境変数を有効にする
% source ~/.zshrc
```

macOSがMojave以前なら

```terminal
$ vim ~/.bash_profile

# .bash_profileを開いたら、「i」とタイプしてインサートモードに移行

# .bash_profileの内部に次の記述を追加
export BASIC_AUTH_USER='ユーザー名'
export BASIC_AUTH_PASSWORD='好きなパスワード'
# 記述を追加したら、escキーを押してインサートモードを抜け、 「:wq」と入力して保存して終了する

# .bash_profileを再読み込みし、定義した環境変数を有効にする
$ source ~/.bash_profile

```

設定できたらコントローラーに戻って以下に編集


```ruby

def basic_auth
    authenticate_or_request_with_http_basic do |username, password|
      username == ENV["BASIC_AUTH_USER"] && password == ENV["BASIC_AUTH_PASSWORD"]  # 環境変数を読み込む記述に変更
    end
  end
```


<h1>heroku上にも環境変数を反映させるには</h1>


```terminal
% heroku config:set BASIC_AUTH_USER="ユーザー名"
% heroku config:set BASIC_AUTH_PASSWORD="好きなパスワード"
```

設定できたかを確かめるコマンド⬇︎

```
% heroku config
```

設定したらデプロイを忘れない

```terminal
% git add .
% git commit -m "Basic認証を導入"
% git push heroku master
```


<h1>できたぁ！(悟空)</h1>
AWSでEFSをマウントしたときにFilesystemが127.0.0.1になる理由

AWS（Qiitaも）ド素人が勉強していて気になったので調べた結果を共有します。

## EFSマウントヘルパーを使用してマウントした場合

```console
[root@ip-hogehoge ~]# df -hP
Filesystem      Size  Used Avail Use% Mounted on
devtmpfs        482M     0  482M   0% /dev
tmpfs           492M     0  492M   0% /dev/shm
tmpfs           492M  524K  492M   1% /run
tmpfs           492M     0  492M   0% /sys/fs/cgroup
/dev/xvda1      8.0G  1.7G  6.4G  21% /
tmpfs            99M     0   99M   0% /run/user/1000
127.0.0.1:/     8.0E     0  8.0E   0% /home/ec2-user/efs　　←127.0.0.1:/ってなに？
tmpfs            99M     0   99M   0% /run/user/0
```
Filesystemが`127.0.0.1:/`ってなんぞ？
調べてもパッと出てこなかった・・・・
これが瞬時に理解できないの自分だけ？


## NFSクライアントを使用してマウントした場合

```console
[root@ip-hogehoge ~]# df -hP
Filesystem                                      Size  Used Avail Use% Mounted on
devtmpfs                                        482M     0  482M   0% /dev
tmpfs                                           492M     0  492M   0% /dev/shm
tmpfs                                           492M  472K  492M   1% /run
tmpfs                                           492M     0  492M   0% /sys/fs/cgroup
/dev/xvda1                                      8.0G  1.7G  6.4G  21% /
tmpfs                                            99M     0   99M   0% /run/user/1000
tmpfs                                            99M     0   99M   0% /run/user/0
fs-hogehoge.efs.ap-northeast-1.amazonaws.com:/  8.0E     0  8.0E   0% /home/ec2-user/efs
```
NFSクライアントを利用した場合は、NFSを利用する際に表示される見なれた形式（ホスト名）になっています。

## 調べてみた
### 結論
NFSクライアントはstunnelを利用しているから。

stunnelとは、Wikiより
> stunnel は、フリーなマルチプラットフォーム対応のプログラムであり、汎用TLS/SSLトンネリングサービスを提供する。
>stunnel は、TLSやSSLにネイティブで対応していないクライアントサーバシステムに安全な暗号化されたコネクションを提供するのに利用できる。

AWSのマニュアルを読んでもあまり記載が無かったが、PDFのユーザガイドには記載があった。
https://docs.aws.amazon.com/ja_jp/efs/latest/ug/efs-ug.pdf
のP.166、167あたり。

>転送中のデータの暗号化を使用する場合、NFS クライアント設定が変更されます。アクティブに
>マウントされたファイルシステムを検査する場合、次の例に示すように、localhost または 127.0.0.1 に
>マウントされたことが表示されます。
docker-composeのネットワークで名前解決できない

# 問題
docker-composeで定義されたコンテナ名と別のコンテナのサービス名が同じだと、Dockerネットワーク内での名前解決がコンテナ名でできなくなる

本家には報告ずみです。
https://github.com/docker/compose/issues/8056

#　検証
## docker-compose.yml
```yml
version: "3"
services:
  rest-client:
    container_name: curl
    image: tutum/curl
    command: sleep infinity

  web1:
    container_name: api1
    build: ./api1
    command: ruby main.rb -o 0.0.0.0

  api1:
    container_name: api2
    build: ./api2
    command: ruby main.rb -o 0.0.0.0

networks:
  default:
    name: net1
```
以上のようなケース、”api1”が異なるコンテナでそれぞれコンテナ名、サービス名で使われている場合だと、net1ネットワーク内だと名前解決の結果が混ざる。
嘘だろって思いますが、本当に混ざります。

##　api1コンテナ
```ruby
require 'sinatra'

get '/' do
  'This is app1 container!'
end
```
##　api2コンテナ
```ruby
require 'sinatra'

get '/' do
  'This is app2 container!'
end
```

これらをnet1内でアクセスするにはドメインにコンテナ名を使うことでURLアクセスできます。
つまり、以下の結果が期待できます。

```bash
#net1ネットワークに接続して、
$ curl "http://api1:4567/"
This is app1 container!
$ curl "http://api2:4567/"
This is app2 container!
```
ですが、`curl "http://api1:4567/"`の結果がランダムに変わります。

##　テスト
```bash
$ docker-compose up -d
$ docker exec -it curl bash
# curl "http://api1:4567/"
```
こうしてやると、半分ぐらいの確率で、`This is app2 container!`の結果が混ざって帰ってきます。。。

謎の404エラーなどで困っている方がいれば、それが別のコンテナに運ばれている可能性があります。お気をつけて。。。

##　手軽に試したい方へ
https://github.com/akihirof0005/Verification-defects
上記のリポジトリにテストケースを作成しました。
そして、協力してくれる方は、再現できたら教えてください。再現できなくても教えてください。。。。
【応用情報】文系出身が応用情報に合格するまでの勉強方法

matcho(@matchode_study)です。
2020年10月に応用情報技術者試験を受け、合格することができましたので、
自分がやった勉強方法を残したいと思います。

#目次
- バックグラウンド
- 勉強期間
- 使用した参考書/ウェブサイト/ツール
- 勉強方法
 - ステップ1（7月中旬~8月中旬）
 - ステップ2（8月中旬~9月末）
 - ステップ3（9月下旬~試験）
- まとめ

#バックグラウンド
情報系/非情報系のバックグラウンドで勉強方法が変わってくると思いますので、
まず自分のバックグラウンドから紹介したいと思います。

自分の場合は

- 新卒一年目（実務経験は乏しい）
- 大学は非情報系の文系学部出身

といったバックグラウンドです。

#勉強期間
勉強期間としては、7月中旬から約3か月間です。

- 平日は1~2h
- 土日祝は5~7h

全期間合計の勉強時間は
約400~450hだったかと思います。

#使用した参考書/ウェブサイト/ツール
使用した参考書/ウェブサイト/ツールは以下です。

- 過去問道場
https://www.ap-siken.com/apkakomon.php
- 『2020 応用情報技術者 午後問題の重点対策 (重点対策シリーズ) 』
https://www.amazon.co.jp/dp/4865752218/ref=cm_sw_r_tw_dp_8vLcGb221R6PZ?_encoding=UTF8&psc=1
- 『ニュースペックテキスト 応用情報技術者 2020年度 (情報処理技術者試験)』
https://www.amazon.co.jp/dp/4813295673/ref=cm_sw_em_r_mt_dp_-tLcGbPBZDJ9F?_encoding=UTF8&psc=1
- アルファベット暗記リスト（自作）

#勉強方法
以下、具体的な勉強方法をステップごとに分けて説明します。

###ステップ1（7月中旬~8月中旬）
まずは、応用情報で問われる知識を網羅し、体系化するために
『ニュースペックテキスト 応用情報技術者 2020年度 (情報処理技術者試験)』を1周しました。
各章を進めていく中で、章末問題がありましたので、それも解きつつ進めていきました。

並行して、午前問題対策のために「過去問道場」を用いて、上記参考書でインプットした知識をアウトプットしました。1日最低30問は解くことをノルマとし、間違えた問題は何度も解くような泥臭い勉強の仕方をしていました。1か月で500問以上を解き正答率は70％弱に到達しました。

###ステップ2（8月中旬~9月末）
午前問題がある程度できるようになったところで、午後対策を始めました。

午後問題は必須の「情報セキュリティ」に加え、その他10分野から4分野選択できます。
自分の場合は当日の問題の難易度の変動を考慮して6分野
（システムアーキテクチャ、ネットワーク、データベース、組込みシステム開発、プロジェクトマネジメント、システム監査）
に対応できるよう準備していました。

その準備に使用した参考書は『2020 応用情報技術者 午後問題の重点対策 (重点対策シリーズ)』です。
自分の場合は合計7分野の対策が必要ありましたので、対象の約30題を1か月強かけて解いていきました。

並行して、午前問題対策のために「過去問道場」を用いて知識の維持に努めました。
この期間ではステップ1で苦手問題として分類した問題をつぶしていくことを念頭に置いて解いていきました。

###ステップ3（9月下旬~試験）
最後の仕上げの期間に行ったことは以下です。

- 『2020 応用情報技術者 午後問題の重点対策 (重点対策シリーズ)』の苦手問題対策
- 「アルファベット暗記リスト」の暗記

『2021 応用情報技術者 午後問題の重点対策 (重点対策シリーズ)』については、
ステップ2で解いた問題の中で点数が低かったものを複数回解きました。

また、応用情報ではかなりの数のアルファベットの単語が出てくるため、その暗記が必要でした。
過去問道場や午後問題を解いていく中で紛らわしい単語が出てきた場合には、
アルファベット暗記リストに追記していき、最後の仕上げ期間に網羅的に暗記しました。
（試験会場ではこの単語リストを眺めていました。）


#まとめ
情報系のバックグラウンドがなくても合格できる試験だと思います。
上記勉強方法を継続できるかどうかが合格の鍵だと思います。
macOS のコマンドラインの備忘録

# はじめに
コマンドラインを良く使うようになって、どういうのがあるのかまとめたくなったので、まとめました(｀・ω・´)
参考文献そのままなので、参考文献は下に載せてます。
## コマンドライン クイックリファレンス
### macOSアプリケーションの実行と設定
* open：macOSアプリケーションの実行
* defaults：アプリケーション設定の一覧表示・操作

### マニュアルの閲覧hヘルプの表示（コマンド全般）
* man：マニュアルを表示/検索
* help：bashのビルトインコマンドの使い方を表示［bash］

### コマンドライン環境
* pwd：カレントディレクトリの表示
* cd：カレントディレクトリの移動
* alias：コマンドエイリアスを設定/表示
* unalias：コマンドエイリアスを削除
* history：ヒストリ（コマンド履歴）を表示
* fc：ヒストリ（コマンド履歴）を表示する、編集して実行する
* source：現在のシェルでファイルを実行
* eval：引数を連結してシェルで実行
* type：シェルが実行しているコマンドの検索
* which：コマンドの検索whence/where/which/typeシェルが実行しているコマンドの検索［zsh］
* hash：シェルが記憶しているコマンドのパスを確認、リセット

### 環境変数/シェル変数/シェルオプション
* echo：文字列の表示、変数の値の表示
* printenv：/env環境変数の表示/設定
* export：環境変数の設定
* set/setopt/unsetopt：シェルオプションの設定と表示［zsh］
* set/shopt：シェルオプションの設定と表示［bash］

### プロセス
* ps：実行中のプロセスの表示
* top：実行中のプロセスの監視/表示
* kill/killall：プロセスの終了/再起動
* halt/reboot/shutdown：システムの終了/再起動

### rootおよびユーザ関連
* sudo：コマンドをほかのユーザとして実行
* id/whoami/groups：ユーザの識別情報を表示

### ファイルシステム
* diskutil：ディスクの状況の確認/修復
* mount：ディスクをマウント
* umount：ディスクのマウントを解除
* df：ディスクの空き領域の確認
* du：ディレクトリのディスク使用量の確認
* dd：ブロック単位でファイルをコピー、変換

### ファイルの操作
#### 属性やパーミッションの表示と変更
* ls：ファイルリストの表示
* stat：属性の表示
* chflags：ファイルフラグの変更
* xattr：拡張属性の表示/変更
* chmod：パーミッションの変更
* chown：所有者/グループの変更
* chgrp：所有グループの変更
* touch：ファイルやディレクトリの最終更新日と最終アクセス日の変更
* file：ファイルの種類の確認

#### コピー、削除
* mkdir：ディレクトリの作成
* rmdir：空のディレクトリの削除
* rm：ファイルやディレクトリの削除
* mv：ファイルやディレクトリの移動/名前の変更
* cp：ファイルやディレクトリのコピー
* ln：シンボリックリンクの作成
* rsync：ディレクトリの同期

#### 検索
* find：ファイルの検索
* mdfind：Spotlightを利用したファイルの検索
* dot_clean：リソースフォークを削除する

#### 圧縮、展開
* zip：ZIP形式での圧縮
* unzip：ZIPファイルの展開
* tar：アーカイブの作成/展開
* gzip/gunzip：ファイルの圧縮/伸張

### フィルターとテキスト処理
* cat：ファイルの表示/複数ファイルの連結

## 参考文献

この記事は以下の情報を参考にして執筆しました。

- [macOS x コマンド入門](https://www.amazon.co.jp/%EF%BC%BB%E6%96%B0%E7%89%88-bash%E5%AF%BE%E5%BF%9C%EF%BC%BDmacOS%C3%97%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E5%85%A5%E9%96%80-%E2%94%80%E2%94%80%E3%82%BF%E3%83%BC%E3%83%9F%E3%83%8A%E3%83%AB%E3%81%A8%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%83%A9%E3%82%A4%E3%83%B3%E3%80%81%E5%9F%BA%E6%9C%AC%E3%81%AE%E5%8A%9B-PRESS-plus-ebook/dp/B087QK53C7/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=JVD8G1Q9MSQB&dchild=1&keywords=macos+%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E5%85%A5%E9%96%80)
EC-CUBE 4 の環境を、Windows + WSL2 + Docker で構築する

Windows 10 Pro 上に、新規に EC-CUBE の開発環境を構築する機会があったのでその手順メモです。

WSL2 + Docker を使って EC-CUBE 4.0 が起動するところまでをまとめます。

試した環境・バージョンは

- Windows 10 Pro (バージョン 1909)
- WSL 2 + Ubuntu 20.04LTS
- Docker v20.10.2
- EC-CUBE 4.0.5

# 1. Windows に WSL2 をインストール

まずは WSL2 (Windows Subsystem for Linux) のインストールから。

Microsoft の公式サイトに詳しいガイドがありますので、その手順どおりに進めていきます。(途中、再起動が必要な箇所もありました)

- [Windows Subsystem for Linux (WSL) を Windows 10 にインストールする | Microsoft Docs](https://docs.microsoft.com/ja-jp/windows/wsl/install-win10)

Linuxディストリビューションを選択してインストールする箇所では、今回は Ubuntu 20.04LTS を選んでいます。

# 2. Docker Desktop をインストール

以下から Docker Desktop をダウンロード、からのインストール。

- https://www.docker.com/products/docker-desktop

# 3. EC-CUBE をダウンロード

今回は [GitHub の EC-CUBE のリポジトリ](https://github.com/EC-CUBE/ec-cube)からクローンしてきます。

Ubuntu のターミナルを開き、適当なフォルダにて以下コマンドで。

```
git clone https://github.com/EC-CUBE/ec-cube.git
```

# 4. Docker のビルド

EC-CUBE のフォルダに移動して、docker build します。

```
cd path/to/ec-cube
docker build -t eccube4-php-apache .
```

# 5. Docker の初回起動

ローカルの EC-CUBE のディレクトリをマウントしつつ、Docker を起動します。

```
docker run --name ec-cube -p "8080:80" -p "4430:443" -v "$PWD/html:/var/www/html/html:cached" -v "$PWD/src:/var/www/html/src:cached" -v "$PWD/app:/var/www/html/app:cached" eccube4-php-apache
```

これで EC-CUBE が起動しました。

ブラウザで <http://localhost:8080/> にアクセスして、ストアの画面が表示されていれば成功です。

管理画面へのログインは <http://localhost:8080/admin/> にて、初期ID/パスワードは `admin` `password` です。

Docker の終了は `ctrl + c` で。

# 6. 2回目以降の起動

2回目以降の起動は、以下のコマンドでOKです。

```
docker start --attach ec-cube
```

# 参考

- [インストール方法 - &lt; for EC-CUBE 4.0 Developers /&gt;](https://doc4.ec-cube.net/quickstart_install)