OmniAICreator/Qiita-1.07M huggingface dataset:
pythonのクラスへの理解奮闘記(1)とりあえず動かしてみる

#クラスって概念難しくないすかね・・・？
クラスってなんぞや。インスタンス？メソッド？関数の宣言だよねそれ。て感じで多分1,2年前この分野で挫折してちょっとプログラミングの勉強から遠ざかっていた気がする。今回、pythonをもう一度学び直しのために勉強してようやくまたクラスの分野に戻ってきたところです。

##とりあえず触ってみる
概念とかインスタンスとかオブジェクト指向とかちょっと置いといて、どんなイメージなのか触りながらの手探りで学習スタート。ほかの方のクラスに関する記事を読んでみてイメージしたのは、会社で回ってくる稟議書とかに対して何かしらの処理をするとき便利そうじゃない？？ってイメージです。ひとまず理論とかオブジェクト指向とは何なのかというお勉強チックなことは次回に回してここでは自分のイメージしたクラスってこういうときに使ったら便利なんじゃね？というイメージを持って作ったコードを公開してみます。

##稟議書に対する処理
当方、文系でとある会社の経理部員です。毎日書類や勘定科目と戦っています。このような身分でクラスが利用できないかと思いついたのが稟議起こして購入する予定の資産に対する処理です。
すなわち、稟議ナンバー、稟議起案者、起案者所属部署、何の資産か、いくらの資産かという属性を持たせて
メール確認の処理、そしてエクセルへの転記で決算時の帳票として利用できるようにしておくことです。
稟議書は毎日ひっきりなしに回ってくるのでプログラム化して効率化するのがよさそう。
この着想をもとにpythonのクラスが使えるのではないかと以下のコードを作成した次第。

とりあえずプログラムにやってほしいこと
①メール文の作成
②エクセルへの転記

##そして作ったのが以下のクラスを交えたコーディング

```python:qiita.rb
import openpyxl
import datetime



class assets():
    def __init__(self,apdnum,apdmen,unitname,assetname,money):
        self.apdnum=apdnum
        self.apdmen=apdmen
        self.unitname=unitname
        self.assetname=assetname
        self.money=money

    #メールにPDFを添付する機能　担当者と担当部署から送り先メールアドレスを拾ってくる作業を追加予定
    def when_mail(self):
        mail=("{}{}様お疲れ様です。経理部の固定資産担当です。稟議書No{}の{}についてですが、\
            \n当月の状況について利用開始しているか教えてください。また請求書もあれば請求書の添付も\
            \nよろしくお願いいたします。".format(self.unitname,self.apdmen,self.apdnum,self.assetname))
        print(mail)

    def Insert_excel(self):
        wb=openpyxl.load_workbook("../data/発注固定資産管理表.xlsx")
        sh=wb.active
        for dt_row in range(2,50):
            if sh["A"+str(dt_row)].value!=None:
                continue
            else:
                sh["A"+str(dt_row)].value=self.apdnum
                sh["B"+str(dt_row)].value=self.unitname
                sh["C"+str(dt_row)].value=self.apdmen
                sh["D"+str(dt_row)].value=self.assetname
                sh["E"+str(dt_row)].value=self.money
                break
        wb.save("../data/発注固定資産管理表_{}_johannesrome作成.xlsx".format(datetime.date.today()))


#以下実行プログラム
print("新しい稟議書Noを入力してください")
apdnum_re=input()
print("稟議書の起票者を入力してください")
apdmen_re=input()
print("起票者の所属部署を入力してください")
unitname_re=input()
print("購入対象の名前を入力してください")
assetname_re=input()
print("予定調達価格を入力してください")
money_re=input()


m=assets(apdnum_re,apdmen_re,unitname_re,assetname_re,money_re)
m.when_mail()
m.Insert_excel()
```

##コードの詳細
コードとしては、assetクラスを作り、そこに5つの属性を持たせる。
①稟議ナンバー
②稟議起案者
②起案者所属部署
④購入予定資産の名称
⑤購入金額
プログラムを起動すると上記の5つのインプットを求められ、それに基づきインスタンスが作成。
そしてメール文の作成とエクセルへの転記が行われるという内容。

#個人的な総括
個人的にはこれでクラスのメリットを享受したプログラムになっているのではないかと思うのだけれど。
どのようなものだろうか。クラスの承継や多重承継なんかは使ってないけれど、クラスのメリット
使いきれてないよ~て意見があればぜひぜひコメントください（ ＾ω＾）。以上、第一回目でした！
UiPath　業務自動化を成功させるベストプラクティス

# UiPathとは
まず初めに、私が抱いているUiPathのイメージについてお話させていただきます。

UiPathとは、業務を自動化するためのRPAツールです。
できることとしては、PC操作の自動化やデータの加工が挙げられます。

私は、業務とは構築されたシステム間の相互的なデータ交換であると考えています。
下記のような在庫管理プロセスがあったとします。
1. 商品Aを1個購入する注文が入る
2. 在庫管理システムへ商品Aの在庫を問い合わせる
3. 在庫があれば、商品Aを1個発送する
4. 在庫管理システムから商品Aを1個引く

作業者は、在庫管理システムから「商品Aの在庫」というデータを受け取り、処理を行います。
そして、在庫管理システムへ「商品Aが1個減った」というデータを渡しています。

そのため、私が考えるUiPathとは、「構築されたシステム間の相互的なデータ交換」を自動化するためのツールと言えます。
この認識を元にベストプラクティスを書いていきます。

# #1 「作業」を自動化してもメリットはない
UiPathは「業務」を自動化するツールです。「作業」だけを自動化していては全くメリットがありません。

例えば、Aサイトからデータをスクレイピングしてきて、データをエクセルに貼り付けるといったものは「作業」です。
エクセルに貼り付けたあと、クライアントがエクセルのマクロを実行して、他部署へエクセルをメール送信していた場合、どうでしょう。
業務とは「データ交換」です。それを念頭に置くと、ここで挙げた例では「データの受け取り」と「データの加工」しか行っていませんので、「データを渡す」という作業が残っていることがすぐに分かります。

そして、クライアントのほとんどが「作業」と「業務」の区別をつけていません。
これが「作業」だけを自動化したワークフローが増えてしまう最も大きな原因です。

RPAの費用対効果を測る指標として、1日の削減時間と1日のワークフロー稼働時間があります。
1日の削減時間を1日のワークフロー稼働時間で割ってみてください。
10以下の場合、「作業」だけを自動化してしまっている可能性が高いです。
2以下の場合、UiPathを導入したメリットよりもコストの方が高くなっています。

「業務」を意識して自動化しているのに、10を下回る場合があります。
その場合は、もっと大きな規模の業務を自動化するべきです。

# #2 自動化依頼は合理的に判断する

自動化依頼は毎日のように届きます。
そのため、開発するかしないかを決めたり、優先順位を決める必要があります。

まず、「作業」の自動化依頼は拒否しましょう。
そして、削減時間が大きいものから選んでいきます。

そうすると、特定の部課にワークフローが偏ることがありますが、それでいいんです。
会社全体で見たとき、費用対効果が最も高くなります。

費用対効果が認められず、採算が取れないからとプロジェクトが中止になったら元も子もありません。
冷たいようですが、合理的に自動化依頼を判断したほうが結果は良くなります。

# #3 業務の手順は変わる
ある日、ワークフローがエラーを出して止まりました。
調査すると、ビジネス例外のようですが、要件にある内容と異なっています。

クライアントへ確認に行くと、きょとんとした顔でこんなことを言ってくるでしょう。
「今日から手順が一部変わりましたよ？　あー、UiPathってそういうのダメなんでしたっけ？」

こんな事態が起こった時に平静を保てるかどうかはワークフローの作り次第です。
ワークフローの修正範囲が狭ければいいですが、修正範囲が広ければ大混乱になります。

ワークフローを作成するときは、修正範囲を如何に狭く設計できるかを考えなければなりません。

# #4 業務の規模は拡大する
あなたは業務の自動化に成功しました。
クライアントは嬉しそうな顔をして、こんなことを言ってくるでしょう。
「次の工程も自動化してください」

ほとんどの場合、自動化依頼がくるのは大きな規模の業務の中のとても小さな規模の業務です。
その小さな業務が成功すれば、次は規模拡大というのは当たり前です。

ワークフローを正しく拡張できなければ、そのワークフローは将来的に「負の遺産」となり、
「メンテナンス性が悪いので、作り直しましょう」と言われることになります。
ワークフローを作成するときは、規模拡大があることを常に想定しなければなりません。

# #5 UiPathだけの知識でRPAは不可能である
多くのRPAエンジニアは以下のスキルセットを持っていますが、多くの場合は「〇〇が使えるだけ」です。

- UiPath（または別のRPAソフト）
- MSOffice Excel, Word, Access, PowerPoint
- VB.NET
- Excel VBA

UiPathに関して言うと、以下の知識がある人はごくごく少数です。

- セレクターとは、デスクトップをルートとしたGUI要素の位置情報（木構造）をXML文字列で表したものであり、[UiAutomation](https://docs.microsoft.com/ja-jp/dotnet/framework/ui-automation/ui-automation-overview)または[Microsoft Active Accessibility](https://en.wikipedia.org/wiki/Microsoft_Active_Accessibility)によって実現している。
- UiPathのワークフローとは、[Windows Workflow Foundation](https://docs.microsoft.com/ja-jp/dotnet/framework/windows-workflow-foundation/overview)にカスタムアクティビティを加えたものである。
- UiPathでVB.NETが使用できるのは、.NET Framework上でVisual Basic Runtimeをサポートする機能があるから。
- UiPathのログ出力は[NLog](https://nlog-project.org/)によって実現しており、NLog.configを編集すれば出力先や出力内容を変更できる。
【AWS/S3】C#でS3バケット内に特定のフォルダが存在するか確認する


## はじめに
### 開発環境
　- Windows10
　- VisualStudio2017
　- AWSSDK.S3のバージョンは3.3.104.39

### 開発言語
　- C#

### やりたかったこと
S3にファイルをアップロードする際に、既にディレクトリがアップロードされているものは警告を表示するようにしたかった。

### やり方
ソースコードは以下の通り。
既に存在するとtrue,存在しないとfalseが返ります。

```

 bool isDirExist(string Buketname ,string Path)
{
    basiccredentials = new BasicAWSCredentials(アクセスキーID,シークレットアクセスキー);

    using (var S3Client = new AmazonS3Client(basiccredentials, this.wwRegion))
    {
        ListObjectsRequest request = new ListObjectsRequest();
        request.BucketName = Buketname ;
        request.Prefix = Path;

        var response =S3Client.ListObjects(request);

        if (response.S3Objects.Count!=0) return true;
        else return false; // 存在なし

    }
}
```

 Buketname :S3バケット名
 Path：検索したいディレクトリのパス（ex. main/20200225/log1/ など）

ListObjectsのPrefix に確認したいディレクトリパスを指定しListObjectsを呼び出すと
指定したディレクトリパス配下に格納されているオブジェクトのリストを取得できます。

ディレクトリの中にファイルが存在しないのにディレクトリが作成されている・・・
という事は無いはずなので、このS3Objects.Countが0以外であればディレクトリパスが存在している　ということです。
多分だけど、初心者がオンライン勉強会を開くしかないよね、それも「教えてくれ勉強会」という話

最近パフォーマンス最適化オンライン勉強会で、パタヘネ本読書会を開いて教えてもらってます。
アセンブラやコンピュータアーキテクチャについてはあんまりわかってないです。
C#の初歩とか、Pythonの初歩とか勉強会開いたけど、まあ初心者向け勉強会をある程度知ってる人が開いてもあんまり盛り上がらない。「入門」と書いてあって意外と高度だったりするんだけど。
最近思うことが、「主催者が教えて欲しい勉強会」の方が盛り上がるということだ。まあ当たり前かもしれないけど、意外と気がつかない。
なので、プログラミングで入門して何もわからないという人は、まあ勉強したい本や分野をまず選んで、「教えてくださいオンライン勉強会」を開いた方がいいんじゃないかなーとは最近思っている。
パタヘネとかでも教えてくれる人は結構集まるので、C#とかPythonに関しては恐らくかなり集まる。
オンライン勉強会は、Skypeと画面共有を用いて行う。ひたすら本を読んでいって、適宜コードを実行する会だ。
勉強会の募集はもちろんconnpassを使う。日時と時間を指定して、SkypeリンクかDiscordリンクを貼る。

https://connpass.com/

誰でもアカウントを作れるし、イベントを作成できる。
正直な話、勉強会は主催している人が一番勉強になるので、ある程度知ってる人が初心者向け勉強会開いても意味は薄いんだよね。
重要なことは、決められた日と時間にPCをスタンバイしてオンラインでいること、教科書は持っていること。
少なくとも、スクールなんかに課金するより、「教えてくれ勉強会」を開いて実績を積み重ねていった方が就職もやりやすいと思う。
ちなみに僕はパタヘネ本の「教えてくれ勉強会」を今後も開き続けると思います。
以上です。

パフォーマンス最適化勉強会やってます。

https://performanceoptimization.connpass.com/

追記
もう一つ理由があって、「詳しい人」が管理するコミュニティに初心者が行って、かじりついて勉強ってどう考えてもきついんですよね。それよりは、勉強したい初心者が管理した方がいいんじゃないかと言う考えがある。どんな人も管理人に対しては立場が弱いし、どうしても教えられる側は立場が弱くなるので、これで対等になるんじゃないかなとは思う。
技術コミュニティ立ち上げって、危険なこともないし、荒らしも来ないし、簡単なので、これができないでアプリ作ったりコード変更とかもっと大変なことできるのかなとは思う。
さらに言うと、コミュニティの収容量には上限がある。大きなコミュニティが少数あるより、小さなコミュニティが多数あった方がどう考えてもいいんだよね。
Vue.js切り替えタブを、一つのコンポーネントに書く

#基礎から学ぶVue.jsの切り替えタブを、作り替えたい
###参考にするお手本

■基礎から学ぶVue.js　切り替えタブ実装例
https://cr-vue.mio3io.com/examples/tab.html#%E3%83%87%E3%83%A2

![Screen Shot 2020-02-25 at 16.10.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569715/8d7405c9-43aa-2f5b-578e-eeed8215fee5.png)

上記の実装例では、
・index.vueという親コンポーネント、
・TabItem.vueという子コンポーネント
の**２つ.vueファイル**に分けて切り替えタブを実装しています。

###しかし今回の目的は
**1つのファイル**にまとめて切り替えタブを作っていきます。
つまるところ、**index.vue**だけで済むように作り替えていきます。

#作り替えてみた、完成版

```vue:index.vue

<template>
  <div class="example">
    <div class="tabs">
      <template v-bind:value="currentId">
        <button
          v-for=" item in list"
          :key="item.id"
          @click="idClickHandler(item)"
          :class="[active(item.id), 'tab']"
        >{{ item.label }}</button>
      </template>
    </div>
    <div class="contents">
      <transition>
        <section class="item" :key="currentId">{{ current.content }}</section>
      </transition>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      currentId: 1,
      list: [
        { id: 1, label: "Tab1", content: "コンテンツ1" },
        { id: 2, label: "Tab2", content: "コンテンツ2" },
        { id: 3, label: "Tab3", content: "コンテンツ3" }
      ]
    };
  },
  computed: {
    active() {
      return function(id) {
        return this.currentId === id ? "active" : false;
      };
    },
    current() {
      return this.list.find(el => el.id === this.currentId) || {};
    }
  },
  methods: {
    idClickHandler(item) {
      return (this.currentId = item.id);
    }
  }
};
</script>

<style scoped>
.tab {
  border-radius: 2px 2px 0 0;
  background: #fff;
  color: #311d0a;
  line-height: 24px;
}
.tab:hover {
  background: #eeeeee;
}
.active {
  background: #f7c9c9;
}

.contents {
  position: relative;
  overflow: hidden;
  width: 280px;
  border: 2px solid #000;
}
.item {
  box-sizing: border-box;
  padding: 10px;
  width: 100%;
  transition: all 0.8s ease;
}
/* トランジション用スタイル */
.v-leave-active {
  position: absolute;
}
.v-enter {
  transform: translateX(-100%);
}
.v-leave-to {
  transform: translateX(100%);
}
</style>



```

#変更したところ


- （親）v-modelと（子）$emitを使ってイベントと値を渡していた　→　v-modelを廃止して、＠click後の処理をmethodsに書いた
- （子）で使えていた算出プロパティ（computed）内の、this.idを使ったactiveクラス　→　computedでは引数が使えないため、function関数をそのまま返す処理に変更して引数を使えるようにした



#気をつけるところ

computed内、methods内で使用する値は、当たり前ですが変更する箇所が多いです。
TabItem.vueで使用する際になぜ　this.値　と使えてたかというと、propsで値をもらっていたことでdataオプションのように使用できた為です。
そのため、index.vue内で　this.値　を使用したくても出来ません。
v-forで回したlist内のオブジェクトitemを選択しているよ〜と伝える必要があります。
それを常に引数で渡す！！ことを心がけると上手くいきます。
ちなみに、template(html)で指定する引数とscript内で指定する引数は名前が違っても構いません。が、分かりやすくはしてください。

#JSの機能か？Vueの機能か？

私は常にこの2つで迷って、正解を見つけ出すのに時間かかったりしてました。
Vue歴もJS歴も浅い時には、つねに2つのドキュメントを行き来するのではないかなと思います。
その中で迷ったことはこちらです。


・current()computedで使用するelは、何なんだろう。

■MDN　find()メソッド
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/find
![Screen Shot 2020-02-25 at 17.20.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569715/339e040a-c392-984c-556d-c74f69ba45a8.png)

なるほど、JSの機能なのですね。

#以上

ありがとうございました。
怠け者でも英単語を頭に叩き込んでもらえるツールを作った

## 概要
「translate.google.com」「alc.co.jp」「weblio.jp」で英和・和英検索したとき、自動的に単語とその翻訳を保存し、しばらく経ってから5択クイズを出題してくれるchrome拡張を作りました。
https://chrome.google.com/webstore/detail/jppkfnbedgcfpioamfidajjkoggmoeik

## 背景
数多くの便利な翻訳ツールがある中、なぜ単語の意味を覚えたいのか、以下に箇条書きで説明した。

- 翻訳ツールで全文翻訳する場合、まだまだ品質がいまひとつで、原文と比べながら読む必要があるように感じる。
- 翻訳ツールで単語・フレーズごとに翻訳する場合、逐一操作や視線移動が必要で疲れてしまう。
- 翻訳ツールを使い続けていると脳が記憶することをやめてしまい、同じ単語を繰り返し調べていて残念な気持ちになる。
- 翻訳ツールが使える環境は限定的である。

以上から、より幅広い環境でより高速に英語を読めるようになるためには、現状では頭に叩き込むしかないのかなと。
ただ勉強時間を確保するほど自分の中で優先度が高くなく、メールチェックくらいの負荷でササッとやれるくらいが丁度いいと感じていたため
日常的に検索した英単語を自動で出題してくれるやり方なら、続けられる学習方法なんじゃないかと考えて実装してみた。

## 使用方法
- [インストールする。](https://chrome.google.com/webstore/detail/jppkfnbedgcfpioamfidajjkoggmoeik)
- 「translate.google.com」か「alc.co.jp」か「weblio.jp」で英和・和英検索をすると自動で単語が登録される。

    - 登録時は以下のような通知が表示される。登録をキャンセルしたい場合は通知のボタンを押せばOK。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135411/696bbdbc-2ebc-d6ea-5eb1-2310e3243a34.png)

- しばらく（60分）待っていると、ブラウザ右上のプラグインアイコンに数字のバッジが現れる。これはクイズの出題準備ができたことを意味する（単語が出題キューに入った）。
    - 実際には同じ言語の翻訳が5つ以上登録されていることもクイズの出題条件。それらの翻訳をクイズの選択肢に使うため。
- プラグインアイコンをクリックするとポップアップが表示され、その中にクイズが出題される。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135411/4778393d-4526-fa41-0fc4-76829cfa1aae.png)
解説
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135411/356d8641-2bad-fad1-6627-1209da61095b.png)

- 選択肢のいずれかをクリックすると、正解不正解が表示される。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135411/63890037-459d-c406-9ed9-cc7682f4f6f4.png)
解説
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135411/9b5d2caf-8f8e-f62c-4ee8-4097d0165228.png)

- もう一度選択肢が描画されているエリアをクリックすると次のクイズに移動する。
    - 出題可能なクイズがまだない場合、それを示すメッセージが表示される。
- 正解した場合、以前より長い時間が経過した後、また出題される。
    - 出題キューに入るまでの間隔は`[60 * 2^正答回数]`分。

## オプション画面
ブラウザ拡張のオプションページを開くと登録されている単語と、出題キューを確認・操作できる。以下のパネルが各単語についてリストされている。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135411/c2f20a06-537b-bcbd-6aac-44f20ef3b51d.png)
解説
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135411/8717dbd7-2284-9fdd-0c1c-7d8a9bebe7ab.png)

- アラームとは出題キューに入るまでの時間を管理しているもののこと。アラームを停止すればずっと出題されなくなる。
- 翻訳の更新はプログラムがスクレイピングした翻訳が期待していたものと違ったときに便利である。

## 技術的な部分の軽い説明
- 使用言語はKotlin。コードの量は1000行くらい。
- 以下の図が単語の登録からクイズを出題して正解不正解を表示するまでの大きな流れを説明する。
    - 図を理解するにはchrome拡張の基本的な構成要素であるcontentscript, browseraction, backgroundを理解しておくことと、storage api, alarm apiがなんなのか知っておく必要がある。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135411/4d85c6c9-f06f-7f73-6901-9acdd41e7e61.png)

- ソースコードはこちら：https://github.com/konohiroaki/quiz-for-autogenerated-vocabulary-list

## 補足
* translate.google.comではカタカナにしただけのような翻訳がたくさん出てくるので、community verified translation（翻訳の隣にチェックアイコンが表示されるもの）のみを自動で登録するようにしている。
PowerShellでgitignoreが効かない


## はじめに

PowerShellでgitコマンド叩いてて、


```
git init
echo "close.txt" > .gitignore
```

としても`.gitignore` が有効にならないので相当ハマった。

同じことで悩んでいる人向けに情報共有

## 原因は文字コード

PowerShellのversion5以前ではリダイレクト処理の文字コードがBOM付きUTF16になる。これが原因で`.gitignore`が上手く機能していなかた。

## 解決法

PowerShellのversion確認は、`$PSVersionTable` コマンドを表示する。単にterminalにこの文字を打てばよい。version 5.XだったらUTF16が原因である可能性がある。

PowerShell core のversion 6以降をインストールする。もしくはgit bashなど別のbashシステムを使う。

## ※注意

WSLを使いたいところですが、ファイルIOが低速ゆえに、シェルスクリプト等を組んでgitコマンドを流すと、checkout系の切り替えに実際のディスク上のファイル変更が間に合わず、エラーになることがあります。しかもIOのタイミングで結果が変わってしまうので問題の再現性が見られず、相当悩みます。gitを使うのはWSL2まで待った方がよさそうです。
Google Coral産業ソリューション： スマート製造

高速、低遅延、高精度
工業生産ラインの品質管理から人間と機械の相互作用のセキュリティ監視に至るまで、業界のEdge AIのユースケースにはさまざまなものがあります。これらのアプリケーションでは、精度を犠牲にすることなく、高速で低遅延の推論が必要です。 

2021年までに、主要メーカーの20％がスマートな組み込みデバイスに依存するようになります。

![alt](https://blogimg.goo.ne.jp/user_image/31/93/0f57e00b15b0f55fdc5f69d8a6470ebe.jpg)

品質管理
特に高い精度が必要な場合、製造における品質管理は複雑になる可能性があります。一部のコンポーネントの欠陥は肉眼では見にくいか、まったく見えないため、品質検査のエラー率が非常に高くなります。 Coralコンピュータビジョン検査システムの助けを借りて、人間の視覚が届きにくいときに、生産ラインの故障や製品品質の問題を高精度で検出することができます。

業界のケーススタディ：LGがCoralを使用して生産品質の監視を完了する方法を学びます。

![alt](https://blogimg.goo.ne.jp/user_image/61/29/c59a69ef3839492e95dd67e3d596a439.jpg)

予知保全
生産ラインまたは重要な機械の故障は、生産効率の低下、高価なメンテナンスコスト、さらには壊滅的な生産事故につながる可能性があります。 Coralを使用すると、デバイスメーカーは、機能を組み合わせてマシンの動作を監視および分析し、今後の障害について早期警告情報を発行できます。予測メンテナンスは、生産ラインシステムに効果的な予測情報を提供して、突然の機械の故障による生産損失を回避できます。

業界のケーススタディ：Olea Edgeが水道会社の水道メーターの故障予測をどのように支援するかをご覧ください

![alt](https://blogimg.goo.ne.jp/user_image/51/dc/9f9a71790d6d956640b05b97a01ec9e6.jpg)

労働者の保護
多くの作業現場の負傷は、次のような予防可能な事故によって引き起こされます。労働者が転倒し、重機や機械を見ない。サンゴのカメラ対応機器やその他のローカルセンサーを使用して、現場を監視できます。オペレーターは、労働者と協力する際に機械と車両の安全性を効果的に保証できます。

Google Coral製品、および大量販売または大量販売（ボリュームディスカウント）の詳細に興味がある場合は、ようこそCoral 海外代理店 [Gravitylink](https://store.gravitylink.com/global)

![alt](https://blogimg.goo.ne.jp/user_image/7a/f6/b70c2d2c00080dd683412bbf4e047c39.jpg)
Git公開用に第２のブランチ(方法2)

## 今回の情報の対象


- 個人or社内開発のリポジトリはOnedriveや社内クラウドなどのクローズド環境に置いている（クローズドリポ）。
- 公開用ソースは、それとは別のリポジトリ(Github等)にしたい(パブリックリポ)。
- パブリックリポでは、公開するファイルを削りたい。
- 開発履歴コメントも、公開用に再整理したい。

ここで、今回の方法では、クローズドリポのコメントはある程度捨ててしまってよい場合や、むしろ捨ててしまって再編集したコメントだけ残したい場合を想定しています。

- コメントも公開用には奇麗で整えたものにしたい。
- 非公開の開発用コメントは、細かく、個人の癖のあるものだ(粒度の小さい)

という状況です。

## なんとか目的を達した方法

先に例題のコマンド載せます。私の冗長な文章よむよりもコマンド見た方が早いって人も多いと思うんで。クローズドブランチを`master`、パブリックブランチを`pub`とします。`close.txt`が公開したくないファイルで、`pub`ブランチからはそれを除きます。


```
mkdir gittest
cd gittest

#(1)prepare closed branch "master", and do commit 3 times.
git init
echo "bigdata" > .gitignore
git add .gitignore
git commit -a -m "master1"
echo "master close2" > close.txt
git add close.txt
git commit -a -m "master2"
echo "master open3" > open.txt
echo "master close3" > close.txt
git add open.txt
git commit -a -m "master3"

#(2)make public branch "pub"
#git checkout -b pub `git rev-list --reverse HEAD | head -1`
git checkout -b pub (master1のコミットID)
echo "/close.txt" >> .gitignore
echo "/.gitignore merge=ours" >> .gitattribute
git add .
git commit -a -m "1st pub"

#(3)merge by squash and reset to unstage ignored files
git merge --squash -Xtheirs master
#git reset `git ls-files --full-name -i --exclude-standard`
git reset 
git add .
git commit -m "pub3"

#(4)advance to develop on closed "master" branch
git checkout master
echo "master open4" > open.txt
echo "master close4" > close.txt
git commit -a -m "master4"
echo "master open5" > open.txt
echo "master close5" > close.txt
git commit -a -m "master5"

#(5) merge to pub same as (3)
git checkout pub
git merge --squash -Xtheirs master
#git reset `git ls-files --full-name -i --exclude-standard`
git reset 
git add .
git commit -m "pub5"


```

ここで、開発が進むたびに(4)から(5)が繰り返されます。

また、(1)の直後に、`.git/config`に以下を追加します。これで、`.gitignore`がmergeによって書き換わらなくなります。 


```
[merge "ours"]
	name = "Keep ours merge"
	driver = true
```

 ただし、mergeでは書き換わらないので、クローズドリポの方で.gitignoreに追記した場合には、手動で公開用リポの`.gitignore`も書き換えてやる必要があります。

初回以外は毎回手順(3)でマージすることになります。ここで、`merge --squash`でマージしますが、これだけだと公開リポでは無視したい`close.txt`もステージングされてしまっています。そこで、一旦`git reset`で全てのステージングを取り消し、再度`git add .`でステージングします。これによって、`.gitignore`で指定したファイルが公開用ブランチで正常に無視されます。この部分はコメントアウトした


```
git reset `git ls-files --full-name -i --exclude-standard`
```

でも代用できます。PowerShellではバッククォートによるコマンドが動かないので、今回はこのようにしました。

## 注意

Windows環境では、PowerShellなら問題ないですが、WSL(Windows10 1903)上で動かすと、ファイル操作が遅いためか時々おかしな動作になります。ファイルが消えていなかったり。消したはずのファイルが残っていたり。よって、上記コマンドの例題のコマンドも途中で失敗することがあります。特に`git checkout`で消したはずのファイルが消えてなかったりしてErrorになります。

## 別の方法

開発履歴とコメントもできるだけ残したい場合は、[前回の記事](https://qiita.com/pochman/items/3c8592a15e24ad295c89)を参考にどうぞ
SSHについて

#はじめに
デプロイに取りかかる前に、学んだことをoutput致します。
もうすでにご存知の方、省略の仕方等ご存知でしたら、ご教授願います。

#SSH(セキュアシェル)について
- 離れた場所にあるサーバの中で作業を行いたい場合に、暗号や認証の技術を利用して、安全にリモートコンピュータと通信するためのプロトコルのこと
- 暗号や認証の技術を利用して、安全にリモートコンピュータと通信するためのプロトコルのこと
  
##プロトコル
- データのやり取りも予め決められており、手順がある。

#SSHを利用するには
- リモートにSSHサーバ、ローカルにSSHクライアントというソフトウェアをインストールする必要がある。
- しかし、LinuxサーバやMac OSには標準でインストールされているのでインストールする必要ない。

→　必要なケースは調べてみます。
  
#SSHでログインする方法
- パスワード認証
- 公開鍵認証

##サーバーに入れる人を制限する
- 「秘密鍵」と「公開鍵」という2つのファイルを使う。
- ssh-keygen -t rsaというコマンドを入力することで、SSH通信で必要になる、公開鍵と秘密鍵の両方が生成される。

##鍵
- 公開鍵 : サーバへのSSHを始めるときに一緒に送る。
- 秘密鍵 : ローカル環境内に保存する。

通信を行う際は、サーバへのSSHを始めるときに一緒に送った公開鍵を元に暗号が生成され、ローカル環境ではサーバから送られてきた暗号を秘密鍵を基に解読する。このようにして、サーバーとローカル環境間の情報のやりとりが安全に行われる。

###公開鍵でのログインの手順
- 公開鍵認証でのログイン方法で行うこと次のは3つ

①公開鍵と秘密鍵を生成（ローカル環境側）
②公開鍵をサーバ側に設置（ローカル環境側→サーバ側）
③ 公開鍵認証でログインできるか確認

#さいごに
日々勉強中ですので、随時更新します。
皆様の復習にご活用頂けますと幸いです。
CANログ(.asc)から特定のCANIDのログデータのみ取り出す(Rust版)

Rustの勉強がてら、以前、bashで実装した下記記事のRust版を実装した。
([CANログから特定フレームだけを取り出す](https://qiita.com/sunadandy/items/310d304b5d5d03086fc4))

Rustのビルド環境が必要だが、約20万行のログファイルに対して、bash版の3分の1の時間で処理可能。

## 使用方法
下記コードをビルドしてできたexeファイルを、.ascファイルがあるディレトリに置き、実行するだけ。

## 実装
* Rust初コーディングだったので、おかしな点があれば指摘お願いします。
* Qiita投稿用にコードをアレンジしたので、もしかしたらおかしな点があるかもしれません。(cargo runは確認済み)

```rust
extern crate regex;

use std::fs;
use std::io::{BufRead, Write, BufReader, BufWriter};
use regex::Regex;

// 必要に応じて適切な条件を設定する
const CANID: &str = "XXX";  // CANID

fn main()
{
    // カレントディレクトリから.ascファイルを検索
    SeachAscFile();
}

// カレントディレクトリから.ascファイルを検索
fn SeachAscFile()
{
    let files = fs::read_dir("./").unwrap();
    for f in files
    {
        let filename = f.unwrap().path().display().to_string();
        if filename.find(".asc") != None
        {
            // .ascファイル読み込み
            ReadAscFile(&filename);
        }
    }
}

// .ascファイル読み込み
fn ReadAscFile(ascfilename: &String)
{
    // 出力ファイル名設定(拡張子置換で対応)
    let outfilename = ascfilename.to_string().replace(".asc", "_out.txt");
    // ログデータ格納変数
    let mut logdatabuffer = "".to_string();
    // ファイル出力用バッファ
    let mut writebuf = BufWriter::new(fs::File::create(outfilename).unwrap());

    // 1行ずつ読み込み
    let file = fs::File::open(ascfilename).unwrap();    // Ignore errors.
    for line in BufReader::new(file).lines()
    {
        let content: String = line.unwrap().to_string();   // 行データを文字列型に変換
        // 指定CANIDのログを抽出
        logdatabuffer = ExtractSpecificFrame(&content);
        // logdatabufferのサイズが0でなければ対象CANIDのデータが抽出されたことを意味する
        if logdatabuffer.len() != 0
        {
            writebuf.write_all(logdatabuffer.as_bytes());  // 出力データをバッファリング
            writebuf.write_all("\n".as_bytes());            // 改行コードを追加
        }
    }
    // ファイル出力
    writebuf.flush();
}

// 指定CANIDのログを抽出
fn ExtractSpecificFrame(content: &String) -> String
{
    let mut ret_str: String = "".to_string();

    let repattern = format!("{}", CANID);       // 正規表現のパターンを文字列リテラルの結合で設定
    let re = Regex::new(&repattern).unwrap();   // 正規表現パターン設定
    if re.is_match(&content) == true
    {
        ret_str = content.to_string();
    }

    return ret_str;
}
```
突然「シングルサインオン（ＳＳＯ）を検討して」と言われたら－第２回

# はじめに

### 前回までのあらすじ

本記事シリーズでは、SE様のようにシングルサインオン(SSO)を導入なさる側の皆様を意識し、
SSOのベース知識を得るための情報源となるべく執筆していきたいと思います。
もし記事をお読みくださったら、ベンダ候補として弊社も加えていただけますと嬉しいです。

* [第１回](https://qiita.com/hoshino_osstech/items/9a59bfd7b5722a8c3d33)
    * 本シングルサインオン解説シリーズの位置づけ
    * なぜシングルサインオン化すべきか

### 今回のお題

今回は、大まかな要件定義について書いていきたいと思います。


# シングルサインオン化のための大まかな要件定義

詳細な要件定義については、SSOサーバのベンダ(弊社のような！)を呼んでからの実施でも良いと思います。
しかしその前に、大まかな要件について予め確認できていると、以後の専門ベンダとの会話もスムーズになります。
（要件に合わないベンダを呼んでしまってお互い不幸な時間を過ごしてしまう、、なんていうリスクも減らせます。）

SSOの要件を検討するにあたっては、複数の要素が絡み合って、纏めることが難しい場合もあるかもしれません。
が、ここではひとまず大まかに要件を把握すると割り切り、「ユーザ」「認証方法」「アプリとの認証連携方法」という３つの視点に大別してざっくり検討する、という想定で書いてみます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316192/2fb4028a-96db-afd3-5bd0-90b6bed82c5e.png" width=70%>

### [1] ユーザ

「ユーザ」という視点の要件定義項目として、以下のようなものが考えられます。

| # | 項目 | 説明 | 備考 |
|:---|:---|:---|:---|
| 1-1 | ユーザの種類 | 「社内ユーザ／社外ユーザ」「ユーザの所属グループ」というようなユーザの種類のことです。<br>例えば、既存アプリ群でID体系が異なっている場合は、名寄せ後の制御などを検討する必要があります。また、ユーザの種類に応じて利用できるアプリが異なる場合は、認可制御を検討する必要があります。 | どのような制御が可能かはSSOサーバ製品毎に異なってきますので、まずは存在するユーザ種類を把握した上でSSOサーバのベンダと会話するのが良いです。 |
| 1-2 | アクティブユーザの人数 | 最大でどの程度の人数のユーザがログインする可能性があるのか、という点です。 | SSOサーバのメモリ容量といったサイジングに影響します。 |
| 1-3 | スループット | 最大でどの程度のスループットを処理できる必要があるのか、という点です。 | サーバのCPUやメモリ容量といったサイジングに影響します。 |


### [2] 認証方法

「認証方法」という視点の要件定義項目として、以下のようなものが考えられます。

| # | 項目 | 説明 |
|:---|:---|:---|
| 2-1 | 認証要素 | どのような要素を用いて認証を行うのか、という点です。<br>例えば、ID/PW認証、Windows認証(Desktop SSO)、二段階認証（ワンタイムパスワード、免許証やマイナンバーカード、FIDO2/WebAuthn、etc…）、独自の認証要素の開発…etc…、というようなものがあります。 |
| 2-2 | 他のSSOサーバとの連携 | 他のSSOサーバとの連携が必要であるか否か、という点です。<br>例えば、他の特定SSOサーバで認証済みであったら今回用意するSSO系でも認証済みとみなす、というようなことです。 |
| 2-3 | 認証要素の使い分け | ユーザやアプリケーションの種類によって認証方法を使い分けるか、という点です。 | 

SSOサーバ製品によってどのような認証方法を採れるかは異なってきます。
このため、ある程度要件をまとめた上で、SSOサーバの選定やSSOサーバベンダと相談する必要があります。


### [3] アプリとの認証連携方法

「アプリとの認証連携方法」という視点の要件定義項目として、以下のようなものが考えられます。

| # | 項目 | 説明 | 
|:---|:---|:---|
| 3-1 | 利用する標準仕様 | アプリとSSOサーバとの認証連携方法については、SAMLやOpenID Connectといった標準仕様があります。このため、各アプリが標準仕様に対応済みであるか調査しておきます。 | 
| 3-2 | 標準仕様未対応のアプリへの対応 | アプリが標準仕様に対応していない場合、現状の認証の姿やコード改修の可否など確認した上で、どのような方法で認証連携するかを検討します。 | 

SSOサーバ製品によってどのような認証方法を採れるかは異なってきます。
このため、ある程度要件をまとめた上で、SSOサーバの選定やSSOサーバベンダと相談する必要があります。

### [Others] その他

その他の項目として、セッション維持時間、サーバ多重化の有無…etc…などありますが、
詳細はSSOサーバのベンダと会話する段階で良いかと思います。


# おわりに

今回は、以下のことを記しました。
・シングルサインオン化のための大まかな要件定義

「SSOサーバのベンダと会話してみたものの、大枠の要件から合致せずに無為な時間を過ごしてしまった」というような不幸を起こさないよう、まずは大枠の要件定義をしておくことをお勧めします。

次回は、SSOの仕組みの大枠について書いていこうと思います。
（変更の可能性もあります。）
【Tips】VSCode のRemote-SSH が遅い！と思ったら（VMWare Player使用下）

Visual Studio Code Remote Development はコンテナやリモートマシン、WSL環境の開発をサポートしてくれる強力な拡張機能です。

しかし私の環境では「めちゃめちゃ動作が遅い」と思いながら使っていたところ偶然解消できたため、似たような事象に遭遇してる方向けTipsとして投稿。

結論としては**ネットワーク周りが原因**である可能性が非常に高いです。
※詳細な動作原理はよくわかっていない状況ですので参考までに。

# 事象

**Remote SSH** 接続した状態であらゆるアクションに対して**数秒～数十秒の遅延**または**タイムアウトする**という事象

例:

- "フォルダーを開く" 押下後のディレクトリスキャン
- 接続開始時のターミナル起動
- ターミナル、エディタ画面に文字入力してからのレスポンス
- 編集中ファイルの保存

# 環境

確認したのは**Remote SSH**を使う場合のみ。

- ホストOS: Windows 10 (192.168.0.1)
- 仮想環境: VMWare Player
- リモートサーバ: CentOS 8 (192.168.0.2)
  - ネットワーク: ブリッジアダプタ

```
Client ---(SSH)--> Remote Server(192.168.0.2)
```

# 対応策

2種類の対応によって動作が改善しました。
※私の環境では**どちらか一方の対応でOKでした**

## 1. ネットワークアダプタのインターネット共有許可

コントロールパネルから[ネットワーク接続]プロパティを開く

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154711/b10fa672-5f7f-a75b-a269-2de94ac54408.png)

プロパティを開き[共有]タブ＞[ネットワークのほかのユーザーに、このコンピューターのインターネット接続を通しての接続を許可する]にチェックを入れて、**VMWare Network Adapter VMNet8**を選択してOK

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154711/e23156a0-6ab3-feea-fddf-0fd9c24bca59.png)

使用しているネットワークアダプタに[共有]という印がついていることを確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154711/bf217201-86b6-5d20-e83c-35bb5af1ead5.png)


※ブリッジアダプタはホストの物理NICを使用するはずなんですが、なぜVMNet8 アダプタの設定をいじることで改善するのか謎...

## 2. ホストPCのポートフォワード経由で接続

リモートサーバのIPアドレスを直接指定してアクセスするのではなく、**一度ホストOSでポートフォワードしてから**リモートサーバへ接続する

つまり
↓こうだったのを

```
Client ---(SSH)--> Remote Server(192.168.0.2)
```

↓こうする（あまり正確な図ではないが）

```
Client ---(SSH)---> Host PC(127.0.0.1:22) ---(Forward)--> Remote Server(192.168.0.2)
```

コマンドプロンプトを開き、以下コマンドを実行

```powershell
netsh interface portproxy add v4tov4 listenport=22 listenaddr=127.0.0.1 connectport=22 connectaddress=192.168.0.2
```
一ヶ月間ポモドーロをキメてみた 

# はじめに
とある記事を読んでいてポモドーロ・テクニックというものを知り、用意するものも特にない上にツールも豊富なので試してみました。

### ポモドーロ・テクニックis何
有名ではあると思いますがやっておきます。[引用](http://d.hatena.ne.jp/keyword/%A5%DD%A5%E2%A5%C9%A1%BC%A5%ED%A5%C6%A5%AF%A5%CB%A5%C3%A5%AF)
> 
集中して仕事をこなすために、25分毎に時間を区切って仕事をする時間管理術。
Francesco Cirillo氏が1992年、自身の勉強効率を上げるために考案した。
1. 25分を1ポモドーロとし、やるべきタスクを1ポモドーロ刻み（25分毎）に分ける。 
2. 25分間は、他の事は一切やらず、タスクに集中する
3. 25分経てば、5分間の休憩を入れる
4. 4ポモドーロ毎（2時間毎）に30分程の長い休憩をとる
5. 後は上記を繰り返す

## さいしょのころ
ポモドーロを導入してまず最初に感じたことが、25分が短いということでした。
導入当初は、考え込んでいるときやノッているときにアラートが鳴って、作業の中断を強いられる印象だったので正直あんまり向いてないんじゃないかと思いました。(自分にもプログラミングにも)
ですがとりあえず1ヶ月続けてみようということでやってみた感想が下記になります。

## やってみてかわったこと
- マルチタスクをしなくなった
1ポモドーロ毎にタスクに向き合うため、マルチタスクをしなく(できなく)なりました。
横槍が入った際にも、緊急のもの以外はすぐに取り掛からず、まずは今行っているポモドーロを優先してから取り掛かるようにしました。

- 見積もり精度が上がった
1ポモドーロが25分ということで、どうしてもこのポモドーロではここまで進めようという意識が生まれます。
いままではほぼ時間単位でタスクの見積もりを行っていましたが、意識的に今回はここまで行おうと目標を立て、よりタスクの細分化を行うようになり、結果的に見積もりの精度の向上に繋がりました。
自分の場合はポモドーロ開始前、エディタにこのポモドーロ間に行うことの詳細をかんたんに記述してから作業に入りました。

- 集中できるようになった
上記のようなこともあって、ポモドーロ中はメールやチャットなどはチラ見程度にとどめ、特に問題のない限りタスクに集中するようになりました。
閲覧や返信はポモドーロ間の休憩時間に行うことで業務にメリハリをつけられるようになりました。

### 便利ツール
- [Tomato Clock](https://addons.mozilla.org/en-US/firefox/addon/tomato-clock/)(FireFox拡張)
    - 私はこれを使用しています。
- [マリナラ：Pomodoro アシスタント](https://chrome.google.com/webstore/detail/marinara-pomodoro%C2%AE-assist/lojgmehidjdhhbmpjfamhpkpodfcodef)(Chrome拡張)
- [Pomodoro Tracker](https://pomodoro-tracker.com/)(Webサイト)

## おわりに
導入してすぐはどうも合わないと思っていましたが、人間慣れるもので今となってはやってよかったと思いますし、これからも続けていこうと思います。
社内環境的にやりづらい方もいらっしゃると思いますが、1ポモドーロを50分にするなどして、完全にこのルールに従う必要はないと思います。(実際に私は業務時間中に30分の休憩は厳しいため、15分程度にして行っています。)
冒頭にも書いたように気軽に始められますので、もし興味を持たれたら是非試してみてください。
Kony Mobility Platformの概要

# 目次
1. はじめに
2. Konyとは？
3. プロジェクトの作成方法
4. 参考にしたサイト

# はじめに
ここでは、Konyの概要とKony Visualizerでのプロジェクトの作成方法について説明します。
# Konyとは？
Kony Visualizerは、単一のコード（Javascriptベース）から複数のOSに対応したアプリを開発できるモバイルアプリケーション開発プラットフォームです。
Kony Visualizerは、必要に応じてバックエンドサービスと統合する柔軟性を提供しながら、デジタルアプリを迅速に開発できるようにします。

#KonyVisualizerでのプロジェクトの作成方法
## 概要
Konyプロジェクトでは、Model-View-Controller（MVC）アーキテクチャに基づいた構造化されたモジュラーフレームワークを使用して、誰でも簡単にカスタムアプリケーションを作成ができます。

後述するフォームは、アプリのビューを表し、コントローラーは、ビューを操作しナビゲーションを処理する機能を持ちます。また、バックエンドサービスのKony Fabricと接続することによって、作成したアプリケーションをデータベースやAPIと接続することが可能です。

##作成手順
1. Konyを開き、"File"メニューをクリック  
![スクリーンショット 2020-02-25 18.13.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592264/9a34f0bb-847d-5dce-6784-ac985c0dfe68.png)

2. "New Project"をクリックして、下記ポップアップで"Create Custom App"を選択し、"Choose"をクリック  
![図3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592264/9eea72f9-34d5-1d2a-4896-21e82efae7e3.png)
3. Project Type画面が開く。"Project Name"テキストボックスに、アプリケーションプロジェクトの名前を入力する。
4. "Kony Reference Architecture"を選択
5. "Create"をクリックする
![図2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592264/6c8d4e3f-08b8-d092-3b69-f43fdac20625.png)
6. 完了するとプロジェクトが表示されるので、左メニューから、作成したいデバイスを開き、Formsを右クリック
7. "New Form"をクリックする
![スクリーンショット 2020-02-25 18.22.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592264/660d2408-6ef1-9b10-37e0-05efa0a4e12b.png)
8. フォームの作成完了。フォームを作成すると、同時にControllerが作成されるので、Controllerにその画面で設定したいアクションをコーディングすることができる。
![スクリーンショット 2020-02-25 18.24.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592264/10fae430-26b2-20de-9fe6-a0958815658c.png)
Contollerの記述例 ：フォーム表示時にその日の日時を表示するロジックを作成
![スクリーンショット 2020-02-25 18.28.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592264/929bd084-1ea0-10a8-b5c1-d632e231aa6b.png)

#参考にしたサイト
[Kony公式ガイド](https://docs.kony.com/konylibrary/visualizer/visualizer_user_guide/Content/TypesOfProjects.htm
)
SQLによる匿名加工サンプル

## SQLにおいて匿名加工を行う場合のサンプル
匿名加工の手法については
個人情報保護委員会のガイドラインが参考になる。
https://www.ppc.go.jp/personalinfo/legal/

### 1.個人識別符号(ID系の情報)の置き換え
```sql
--Mysql
select sha2(concat([columname],'soltkey'),256) form [tablename]:

--Mysql(例)
mysql> select '123456',sha2(concat('123456','moji'),256) as sha2 from dual;
+--------+------------------------------------------------------------------+
| 123456 | sha2                                                             |
+--------+------------------------------------------------------------------+
| 123456 | cd8d565e7a2d45c77d838c5b6c477c43d5822ad77c886d376eb2da306e1a0056 |
+--------+------------------------------------------------------------------+

--SQLServer
select HASHBYTES('SHA2_256',concat([columname],'soltkey')) as sha2;

--SQLServer(例)
select '123456',HASHBYTES('SHA2_256',concat('123456','moji')) as sha2;
(列名なし)	sha2
123456	0xCD8D565E7A2D45C77D838C5B6C477C43D5822AD77C886D376EB2DA306E1A0056
```
### 2.トップ(ボトム)コーディング
数値に対して、特に大きい値、小さい値をまとめること

```sql
--Mysql
select [number],(case when([number] > 90) then 90 else [number] end) as number_flg from dual;

--SQLServer
select [number],(case when([number] > 90) then 90 else [number] end) as number_flg;

--Mysql(例)
mysql> select 98,(case when(98 > 90) then 90 else 98 end) as number_flg from dual;
+----+------------+
| 98 | number_flg |
+----+------------+
| 98 |         90 |
+----+------------+
```
Django：MigrationでモデルがDBに反映されない

#反映されない
表題の通り、DjangoからマイグレーションしてもDBに反映されず苦しんだので記録しておきます。

#環境
・Windows10 Enterprise
・Docker Desktop for Windows：2.1.0.1
・MySQL：5.7.28（Docker上）
・Django：3.0（Docker上）

#経緯
models.pyに新モデル（**モデルA**とします）を追加してマイグレーションを行った所、DBに反映されず。
他モデルの変更は反映されるので、**モデルA**のみ問題と推定。

#色々やってみた
下記記事などを参考に色々やってみました。

[・DjangoでmigrateしてるのにDBに反映されない時の対処法【Djangoアウトプット】](http://115design.main.jp/django-output-3/)
[・DjangoでMigrationsのリセット方法（既存のデータベースを残したまま）](https://dot-blog.jp/news/how-to-reset-django-migrations/)
[・djangoでmigrateができない](https://teratail.com/questions/124096)
[・Djangoのmodels.pyの反映(python manage.py makemigrations/migrate)](https://teratail.com/questions/163521)
[・modelにカラムを追加したのにmigrationファイルに追加されない現象](https://qiita.com/_chi_craper_/items/4d4c20619b3ed0095797)
[・python manage.py migrationが効かない時の対処法 [Django]](https://www.ganbaruyo.net/details/django-migration-error/)

大体「python manage.py migrate --fake hoge zero」でマイグレーション履歴削除して、フォルダのファイルも削除後、makemigrationしてmigrateすれば反映されるでしょ、という事でしたが全滅。

#おまえだったのか
で、一旦DBドロップして再度マイグレーションしてみると…**モデルA**以外にもうひとつモデル（**モデルB**とします）が反映されていない。
「？」と思いよくよく「models.py」を読んでいるとこれら２つのモデルのみ「class Meta:」の中に「**managed = False**」の文字が。

```python:models.py
    class Meta:
        managed = False
        db_table = 'temp'
```

試しにこれを削除して再度マイグレーションしたら、出来ました。あっさりと。
基本的なところをよく理解していなかっただけでした。
**モデルB**はどこかからかコピーしてきた書式をペーストしていて、これをコピペして**モデルA**を作成したので今回のトラップにかかった様です。
「managed = False」と書く事でマイグレーションの管理対象外とするそうな。そりゃ反映されない筈だ。
(「経緯」で他モデルの変更は反映されたと書いていますが、**モデルB**では試していませんでした)


#という訳で
コピー元がなぜこれを含んでいたかは謎ですが、一先ず動いたので…
灯台下暗し。もう少し手前から調べてみようと思いました。
BERTなどの大規模のモデルの課題


# 自然言語処理の画期的なモデル - BERT
[BERT](https://arxiv.org/pdf/1810.04805.pdf) [Bidirectional Encoder Representations from Transformers] は、Googleのチームに2018年の秋に発表された。トランスフォーマーアーキテクチャを使って、大量のデータで非常に大きいネットワークを画期的な方法でモデルを学習した結果である。学習方法と精度について[この記事](https://qiita.com/kayamin/items/9e73c93b5e791ff57925)をご参照ください。

オープンソース・情報を自由に交換することを大事にしている機械学習のフィールドでは、新しいアイデアを [arxiv.org](https://arxiv.org/) で論文として公開し、github でモデルを共有することが基本的なやり方である。新しいアイデアが公開されたとたんに、世界の機械学習の研究者や開発チームが参考したり、再利用したりできる。

オープンソースの文化の結果、BERTが公開されて数か月たったら、
Open AI、Facebook、NVidia、BaiduなどのすべてのIT大企業がこの新しいアーキテクチャに基づいてモデルを作った。

2017年からの進化、特にBERTからの画期的な影響については、[このナイス図](https://www.analyticsvidhya.com/blog/2019/08/complete-list-important-frameworks-nlp/?utm_source=blog&utm_medium=demystifying-bert-groundbreaking-nlp-framework) をご参照ください。

#BERTよりデカイモデルが最近流行

BERTの精度向上の原因は、アーキテクチャや学習データの量だけではなく、パラメータ数でもある。
BERTが大きいです。でかい。というより、デカイ。BERTの「小さい」版は、一番単純なバージョンのパラメータ数は１億である。また、BERTに基づいたほかのモデルはさらに大きくきている。

- [Open AI のGPT-2](https://medium.com/syncedreview/openai-releases-1-5-billion-parameter-gpt-2-model-c34e97da56c0)：15 億
- [Nvidia の Megatron-ML](https://nv-adlr.github.io/MegatronLM)：83 億
[2020年に発表されたGoogleのチャットボット Meena ](https://ai.googleblog.com/2020/01/towards-conversational-agent-that-can.html)：26 億
- [Microsoft の T-NLG](https://towardsdatascience.com/microsoft-open-sources-zero-and-deepspeed-the-technologies-behind-the-biggest-language-model-in-5fc70e331b2d)：170 億



![モデルサイズの激増](https://miro.medium.com/max/1400/1*eR1J9JiXRY0-VEGo5y1Xbw.png)
出典：[Microsoft Open Sources ZeRO and DeepSpeed: The Technologies Behind the Biggest Language Model in History](https://towardsdatascience.com/microsoft-open-sources-zero-and-deepspeed-the-technologies-behind-the-biggest-language-model-in-5fc70e331b2d)


ディープラーニングでは、データ量とネットワークのサイズが上がることによって、精度もあがる。
ただし、このようのデカイネットワークには、いくつかの課題が発生する。


# 温暖化を防ぐには、転移学習の場合重みを固定したままにしよう
何億パラメータを大量のデータで学習するには、いくるかかったかは公開されていないが、電気代だでけでも何千万円かかったと考えられる。このようのモデルを自分の課題にカスタマイズするには、ゼロで学習させることは現実的ではない。グーグルやマイクロソフトじゃないと、転移学習でやるしかない。家のパソコンを使ってゼロから学習させたら、GPUが暖房の代わりになるでしょう。溶ける可能性もある。

学習はコストが当然かかるけど、Inference [モデルで特定なインプットに対してアウトプットを予測すること] もコストがかかる。最近話題になった AI Dungeon がこの課題を直接に感じて、[記事](https://medium.com/@aidungeon/how-we-scaled-ai-dungeon-2-to-support-over-1-000-000-users-d207d5623de9)も書いた。この規模のモデルのメモリ要件は数ギガバイト。また、処理にも時間がかかりますので、精度が高くても、スピードが大事な活用の場合では、適切なシステムではない。

まとめると、ITの大企業で最近開発された自然言語処理モデルの精度は確かに高いですが、学習・処理は大変である。クラウドで大変。エッジでさらに大変である。
[さらに読む](https://towardsdatascience.com/too-big-to-deploy-how-gpt-2-is-breaking-production-63ab29f0897c)

# 改善方法・解決方法

ハードウェア購入・クラウド型の無限な予算 - 稟議無しで無限な予算を取れたら、お気軽に数万個のTPUでいけると考えらる。グーグルの予算なかったら、どうやってこのようの精度を出すモデルを使えるでしょうか？

一つの解決方法として、DistilBERTのような縮小版のモデル。元のモデルに「教育」される小さ目なモデルを学習させる。この学習方法の結果、精度は元のモデルほどよくはないですが、サイズを何十倍も縮小することができる。「Knowledge Distillation」について、[この記事をご参照ください。](https://medium.com/huggingface/distilbert-8cf3380435b5)。
2020年2月の論文でも[アマゾンから発表された論文](https://arxiv.org/pdf/2002.06170.pdf)でトランスフォーマーアーキテクチャを縮小する方法が紹介された。

精度のニーズが常に上がることによって、このようの課題はなくならない。一般の会社でもこのようなモデルを利用できるように、ハードウェア進化、クラウド費やコスパがいいトランスフォーマーアーキテクチャが必要になる。
PHPer脳の人がJavaScriptでループを回す

毎回for文書くたびに調べてるので

# 配列のforeach

phpだとこんな感じのやつ

```php
$array = [1, 2, 3];

foreach($array as $a){
    echo $a;
}

// 1
// 2
// 3
```

jsだとこう

```javascript
const array = [1, 2, 3];

for(let a of array){
    console.log(a);
}

// 1
// 2
// 3
```

# 連想配列のforeach

phpだとこんな感じのやつ

```php
$array_assoc = [
    1 => 'one',
    2 => 'two',
    3 => 'three'
];

foreach($array_assoc as $k => $v){
    echo $k . ' is ' . $v . "\n";
}

// 1 is one
// 2 is two
// 3 is three
```

jsだとこう

```javascript
const array_assoc = {
    1 : 'one',
    2 : 'two',
    3 : 'three'
};

for(let [k, v] of Object.entries(array_assoc)){
    console.log(k + ' is ' + v + "\n");
}

// 1 is one
// 2 is two
// 3 is three
```
※まあ、jsのObjectは正確には連想配列ではないけど
error messageをgrepする

[^1]: pipeの使い方を知っていれば自明ですが, 直接的な情報が見つからなかったので書きました.
[^2]: redirect `2>` のように簡単にerrorのみを出力する方法はありません.
何らかのerror出力がうるさくてgrepしたい場合, よく使うpipe`|`はerror出力を渡さないため, 渡すように`|&`に変更する必要があります[^1].

```bash
./a.out |& grep "hoge"
```


#標準出力をgrepに渡したくない場合(error出力のみをgrepに渡したい場合)
`|&`は標準出力とerror出力の両方を渡すため, 標準出力の情報がerror出力の情報を汚染してしまう場合, 標準出力を捨てる必要があります[^2].

```bash
 (./a.out > /dev/null) |& grep "hoge" 
```

#参考
[パイプとリダイレクトでコマンドを組み合わせて実行しよう (4/4)](https://www.atmarkit.co.jp/ait/articles/1603/24/news018_4.html)
【Git】ファイルをcommitやaddした後に.gitignoreを反映する

すでにaddやcommitしたファイルに、`.gitignore`を反映させる方法が中々覚えられないので、アウトプットする。（先に入れとけ）
# 方法
`git add .gitignore`して、

```bash
git rm --cached `git ls-files --full-name -i --exclude-from=.gitignore`
```

## 参考
https://qiita.com/yuuAn/items/b1d1df2e810fd6b92574
[学習28日目]HTML基礎　フォーム実装

#inputタグのtypeの種類
``<input type="ここ!!!" name="xxx">``

「ここ！！！」の部分に入る形式名はこれ。
（意味は英語のまま。type="email"ならemail形式が入るし、numberなら数字以外は入らない。）

- email
- tel
- url
- number
- color
- date
- time
- datetime

#必須入力チェックはrequired属性を付与

``<input name="required" required>``

この最後の「required」を入れることで、
空欄でフォームを送信すると、「このフィールドを入力してください」という忠告がでるようになる。

#入力値の制限
###最小値・最大値
``<input type="number" name="max-min" ここ　>``

「ここ」という部分に
``min="5" max="10"``
と入れれば、入力値ｘは5≦ｘ≦10の範囲でしか入力できなくなる。

###文字数
``<input name="length" ここ >``

「ここ」という部分に
``minlength="5" maxlength="10"``
と入れれば、入力値の文字数yは5≦y≦10の範囲でしか入力できなくなる。

###正規表現を使う
``pattern``属性を使う。

「HTML5のみ有効」にしたければ
``pattern="HTML5"``を。

「先頭がaで始まる文字のみ有効」にしたければ
``pattern="^a.*"``とする。


#入力チェック結果によってスタイリングを変える
つまり、入力値が期待通りだったら、緑、
エラー値だったら赤、のようにチェック結果によって色などをかえることができる。

その方法はスタイルシートで、inputやformのクラス名のあとに
``:valid //正常``
``:invalid //エラー``
を追記する。

つまり、こんな感じに書く。

```style.css
input:invalid{
border:2px solid #139174;
background:#B3F5E6;
}
```

``:invalid``を追記したことで、
入力フォームに誤った値が入力された場合、
フォームが赤くなるようにできた。

####[参考]
逆に、入力チェック機能を無効にするには・・・
``<form>``要素に``novalidate``属性を付与する。
こんな感じ。
``<form novalidate>``
/* hogehoge */
``</form>``

#入力補助をつける
``<input name="xxx" ここ required>``

「ここ」の部分に``autocomplete="name"``という形式で書く。
``name``部分は他に
- email
- tel
- postal-code
- off

が入る

#その他新しい属性について
###読み取り専用にするには``readonly``を付与

###プレースホルダーはplaceholder属性を付与して、その値に表示する文字列を設定する

###ページ読み込み時にフォーカスを当てるには``autofocus``を付与

###スペルチェックや文法チェッを無効にするには``spellcheck=false``とする



#by CODEPREP
HTML基礎 フォーム実装編
C#でデリゲートを使って遊んだ

# C#でデリゲートやラムダ式など使い、いろいろ遊んでみました

```program.cs
using System;

namespace CsLamTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Func<int> addDelegate=(        //(1)
                ()=> {                     //(1-1)
                    Console.WriteLine("初期化の関数から出力");     //(1-2)
                    return 0; 
                    }
                );

            f(                             //(2)
                () => {                    //(2-1)
                    Console.WriteLine("ラムダ式から出力");      //(2-2)
                    return 5 * 5;
                    },
                ref addDelegate           //(2-3)
            );
            f(                             //(3)
                delegate () {              //(3-1)
                    Console.WriteLine("デリゲートから出力");     //(3-2)
                    return 3 * 3;
                    },
                ref addDelegate          //(3-3)
            );
        }

        static void f(Func<int> func, ref Func<int> addDelegate)  //(4)
        {
            addDelegate += func;            //(4-1)
            Console.WriteLine(addDelegate());     //(4-2)
        }
    }
}
```

出力結果は

```
初期化の関数から出力
ラムダ式から出力
25
初期化の関数から出力
ラムダ式から出力
デリゲートから出力
9
```

---

##解説

まずは（1）の部分

```program.cs
            Func<int> addDelegate=(        //(1)
                ()=> {                     //(1-1)
                    Console.WriteLine("初期化の関数から出力");     //(1-2)
                    return 0; 
                    }
                );
```

`(1)`の行は、`Func<int>`（引数を取らずint型を返す関数）型の`addDelegate`を定義しています。
`addDelegate`の初期化が`(1-1)`でラムダ式を用いて行われています。

---

次に（2）の部分

```program.cs
            f(                             //(2)
                () => {                    //(2-1)
                    Console.WriteLine("ラムダ式から出力");      //(2-2)
                    return 5 * 5;
                    },
                ref addDelegate           //(2-3)
            );
```

`(2)`で`(4)`の関数`f`を呼び出しています。
その第1引数`Func<int> func`に`(2-1)`で示されたラムダ式を渡しています。
第2引数` ref Func<int> addDelegate`に`(1)`の`addDelegate`を渡しています。・・・(2-3)の行。

`(3)`はラムダ式ではなく無名関数を渡しています。他は`(2)`と同じです。

---

次に（4）の部分

```program.cs
        static void f(Func<int> func, ref Func<int> addDelegate)  //(4)
        {
            addDelegate += func;            //(4-1)
            Console.WriteLine(addDelegate());     //(4-2)
        }
```

`(4-1)`で、第1引数で渡された`func`を、第2引数で渡された`addDelegate`に加えています。
デリゲートは、`+=`演算子を用いて、関数を連結できます。
連結された関数は、古いものから順番に実行されます。

##実行の流れ

1. まず`(2)`で関数`f`を呼び出し
2. `(4-1)`で`addDelegate`に`(2-1)`のラムダ式を加える
3. `(4-2)`で`addDelegate()`を実行
    1. `(1-2)`が出力される
    2. `(2-2)`が出力される
    3. `(2-1)`のラムダ式の戻り値が出力される。

4. 次に`(3)`で関数`f`を呼び出し
5. `(4-1)`で`addDelegate`に`(3-1)`のデリゲートを加える
6. 3．と同じ
    1. `(1-2)` `(2-2)` `(3-2)` が順番に出力される
    2. `(3-1)`のデリゲートの戻り値が出力される

##今回のC#いじりで知ったこと

`Func<int>`には、ラムダ式も無名関数も渡せる、代入できる。
`Console.WriteLine()`では、デリゲートに複数の関数が`+=`で連結されていても、最後に実行される関数の戻り値のみ表示する。
デリゲートは値型だった。なので、`ref`をつけています。
GoogleAppsScript 勉強中

#V8対応なのでクラス書いてみてハマった点

しばらくやらないとまた忘れそうなのでメモ的に書いてみる

1.ES6対応
そもそもGASでいっぱいやろうとしたらファイルが膨大になっちゃったので、クラス化したいな〜。と思ってたら、V8エンジンになってES6対応したそうな。詳しい記事はGAS V8でググると出てくる

２．ファイルを分割
GASのエディターでFile→New→スクリプト、で用途別にファイルを分割してた

3．クラスを分けて継承してみたらエラー
ベースのクラスをTXXというファイルに、派生クラスをCXXXファイルに書いたところリファレンスエラーが発生。


```javascript:TXX.js
class BaseClass {
  constructor(){
  }
}
```

```javascript: CXX.js
class ExtendedClass extend BaseClass {
  constructor(){
  }
}
```
>ReferenceError: BaseClass is not defined

ベースクラスを参照できてない模様。いろいろググると、

**関数はファイルの順番に参照される**
らしい。

この場合、ファイルの順番とは、「GASエディターの左にあるファイルのリスト」とあった。
しかし、ベースクラスのあるファイルTXXXは、エディターでは一番上。ハテ？

4．Claspを使っていた
参照した記事が間違いなのか、それ以外の要素があるのか。
・ベースクラスをいろんなファイルに移動した
・ファイル名をいろいろ変えてみた
が、原因もわからず途方にくれてた。
ふと、VSCodeのpushスクリプトの実行結果を見ると、なんか
**アルファベット順**
に並んでる。
上にもあるようにTXXXファイルだから順番はCXXXファイルの後ろになる。
とりあえず、AAXXXXファイルをつくってそこにベースのクラスを移すと、

**リファレンスエラーおこらず**

Claspでpushする順番がエディターのリストより優先されている仕様っぽい。
（あくまで現段階なので来週にかわってても驚かない）

5．.clasp.jsonというファイル
普段はクラスIDが入ってるだけのファイルと思ってたら、
`"filePushOrder": [    ]`

という設定項目があった。
こちらに順番を書いてみたらどうだろう、と

```.clasp.json
"filePushOrder": [
"TXX.js",
"CXX.js"
]
```

としたら、リファレンスエラーは出なくなった。  

マークダウンはしばらく書かないとさっぱり忘れるな〜
ec-cube本体に手を加える場合に修正するファイル

# はじめに
推奨されてはいませんが、ec-cube本体の機能を修正する必要がある場合、どの辺のファイルに手を加えるのかまとめました。

# 新規ページの追加
## URLを定義しているファイル
管理画面側、フロント側で下記のファイルにURLと実行されるクラス(メソッド)が定義されています。

- ECCUBEROOT\src\Eccube\ControllerProvider\AdminControllerProvider.php
- ECCUBEROOT\src\Eccube\ControllerProvider\FrontControllerProvider.php

## テンプレート(コントローラーを実行した結果表示するHTML)
`ECCUBEROOT\app\template\<Template Name>` に格納されているテンプレートを修正します。

新規ページを追加した場合、[dtb_page_layoutテーブルへのデータ登録が必要になります。](https://doc.ec-cube.net/plugin_tutorial-pageadd#dtb_page_layout%E3%81%B8%E3%81%AE%E3%83%87%E3%83%BC%E3%82%BF%E7%99%BB%E9%8C%B2)

```
INSERT INTO dtb_page_layout(
device_type_id,
page_name,
url,
edit_flg,
create_date,
update_date
) VALUES (
10,
'サンプルページ',
'customize_sample',
2,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP
);
```

# クエリの変更
## 既存のクエリの変更
データベースへの問い合わせ(SQL)を修正する場合、`ECCUBEROOT\src\Eccube\Repository\XXXRepository.php` ファイルを修正します。

例えば商品検索関連のクエリを変更する場合、下記のファイルを修正します。

``` php:ECCUBEROOT\src\Eccube\Repository\ProductRepository.php
class ProductRepository extends EntityRepository
{

    // 中略

    /**
     * get Product.
     *
     * @param  integer $productId
     * @return \Eccube\Entity\Product
     *
     * @throws NotFoundHttpException
     */
    public function get($productId)
    {
        // Product
        try {
            $qb = $this->createQueryBuilder('p');
            $qb->addSelect(array('pc', 'cc1', 'cc2', 'pi', 'ps'))
                ->innerJoin('p.ProductClasses', 'pc')
                ->leftJoin('pc.ClassCategory1', 'cc1')
                ->leftJoin('pc.ClassCategory2', 'cc2')
                ->leftJoin('p.ProductImage', 'pi')
                ->innerJoin('pc.ProductStock', 'ps')
                ->where('p.id = :id')
                ->orderBy('cc1.rank', 'DESC')
                ->addOrderBy('cc2.rank', 'DESC');

            $product = $qb
                ->getQuery()
                ->setParameters(array(
                    'id' => $productId,
                ))
                ->getSingleResult();
        } catch (NoResultException $e) {
            throw new NotFoundHttpException();
        }

        return $product;
    }

    // 以下、略
```

## 自分でSQLを組み立てて実行したい場合
Doctrine ORMで組み立てられるSQLが気に入らない、自分でSQLを組み立てたい場合があります。
参考になるのは `ECCUBEROOT\src\Eccube\Controller\Admin\AdminController.php` 辺りのコードになります。
下記、サンプルコードです。詳細は[Doctrineの公式サイト](https://www.doctrine-project.org/projects/doctrine-orm/en/2.5/reference/native-sql.html)も見たほうがいいかも。

``` php
$sql = 'select
          p.product_id,
          p.name
        from dtb_product p
        inner join dtb_product_category pc on p.product_id = pc.product_id
        inner join dtb_product_tag pt on p.product_id = pt.product_id
        where p.status = 1
        and pt.tag = :Tag';
$rsm = new ResultSetMapping();;
$rsm->addScalarResult('product_id', 'product_id');
$rsm->addScalarResult('name', 'name');
$query = $app['orm.em']->createNativeQuery($sql, $rsm);
$query->setParameter(':Tag', 'tag');
$result = $query->getResult();
foreach ($result as $row) {
    //$row['product_id']
    //$row['name'];
}
```
Xcodeに引数を渡す LaunchArg & Env Variables

## about

ネットには古いXcodeの情報しかなく、使い分けやコツをまとめた記事がなかったので記載します。

Xcodeでは2種類の方法で実行引数を受け取ることができます。

- Arguments Passed On Launch
- Environment Variables

Swiftのコード内で引数を使う方法を解説します。

### 環境
- Xcode11.x
- Swift4.x

## 設定方法

対象Scheme -> Edit Scheme -> Run -> Arguments

![scheme_argv.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275986/122e0124-89d1-dca9-ff62-2ce229526539.png)

それぞれスクショのようにAppendしてみます。

２種類の入力が可能なので以下でみていきます。

- Arguments Passed On Launch
- Environment Variables


## Arguments Passed On Launch

型：[String]

※ KeyとValueを対で渡すことはできません

### 取得方法

```swift
let argv: [String] = ProcessInfo.processInfo.arguments

argv[0] : 実行ファイルのパスが入る (ex: /Users/user/Library/Developer/CoreSimulator/Devices/3418A817-3034-4DFC-A030-32C90755376A/data/Containers/Bundle/Application/D6D1533B-B307-4C1B-9DE9-1DDD6744B503/test_develop.app/test_develop)
argv[1] : 設定した環境変数
argv[2] : 設定した環境変数2個目
.
.
.
```

### 注意点

次で解説するEnvVarのようにkeyを設定できないので、引数が増えたとき番号がずれる可能性があります。

例として、環境変数に`isTestMode`を渡して以下のような実装をしている場合

```swift
if ProcessInfo.processInfo.arguments[1] == "isTestMode" {
    print("test mode running")
}
```

以下のようにcontainsで含まれているか確認するのが良いでしょう

```swift
if arguments.contains("isTestMode") {}
```



## Environment Variables

型：[String : String]

Key(Name)とValueを対で設定することができます。

### 取得方法

スクショでは以下のようになります。

```swift
let value = ProcessInfo.processInfo.environment["mode"]
print(value) // develop
```

以下のようにswitch文で使うのが良いでしょう

```swift
switch ProcessInfo.processInfo.environment["mode"] {
    case "develop":
    case "production":
    defult:
}
```

## おわり

XCTestでの利用については以下に記載しました！

[XcodeのXCUITestで実行時に引数を渡す](https://qiita.com/kanari3/items/64bb39f6ea6437f09be8)