OmniAICreator/Qiita-1.07M huggingface dataset:
無料でAndroidアプリのパフォーマンスをテストする方法の紹介

現在のAndroid端末では、主にGoogleモバイルサービス（GMS）搭載のAndroid端末とHUAWEIモバイルサービス（HMS）搭載のAndroid端末が存在しています。

一般的にアプリをリリースする前に、アプリの品質を確保するために、テストを行います。このテストでは、アプリにバグがあるかどうか、クラッシュするかどうかだけでなく、アプリの安定性や、速度、リソース消費など、見えにくい部分もテストします。このテストを人でやると、非常に時間も手間もかかるので、テスト自動化でやらないと、コストが莫大になります。

ここで、GMSのAndroid端末とHMSのAndroid端末における、無料なパフォーマンステストの方法を紹介します。

# Googleモバイルサービス（GMS）搭載のAndroid端末
Firebase Test Labの無料プランを使います。

### 手順
(1) Firebase consoleを開きます。
https://console.firebase.google.com/

(2) プロジェクトを作成します。
![firebase01.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704548/f5cd1620-5120-7ae2-fcdc-d3b6b444062d.png)

(3) Test Labを開き、APKをアップロードします。
![firebase02.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704548/eb01546f-5843-7695-a894-4ce70eeb87cb.png)

### テスト結果
テストが完了したら、テストレポートが表示されます。

![firebase03.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704548/2204f094-5f9f-6b07-f10b-c43071af67f3.png)

![firebase04.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704548/e2678253-5beb-d845-4825-7f4f9b87b79c.png)


# HUAWEIモバイルサービス（HMS）搭載のAndroid端末
AppGallery ConnectのCloud Testingを使います。

### 手順
(1) AppGallery Connectを開きます。
https://developer.huawei.com/consumer/en/console

(2) Cloud Testingを開きます。
![image01.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704548/24df4139-60f9-af3c-73c5-78b9eb582fb2.png)

(3) APKをアップロードします。
![image03.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704548/e1798038-7e3d-2c01-285f-e3199d19c63d.png)

(4) テストの種類を選び、次に進みます。
![image02.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704548/543efed2-6ba2-120e-5031-586b0101e8a5.png)
![image04.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704548/9b5b5dbf-ca6e-1fba-82ed-f3e35ea48c2a.png)

(5) テストに使うデバイスを選び、テストを実行します。
![image05.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704548/f6ff2361-94ea-8dfe-dfbf-e614f4d49719.png)

### テスト結果
テストが完了したら、テストレポートが表示されます。

![image09.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704548/5b8b4508-6073-22f2-f52d-65c03cb73c25.png)
![image10.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704548/b3ebb8ce-47ee-7bc8-e98a-83e4a8e07220.png)

# 参考
* HMS：[https://developer.huawei.com/consumer/jp/](https://developer.huawei.com/consumer/jp/)
* Cloud Testingの紹介：[https://developer.huawei.com/consumer/jp/agconnect/cloud-test](https://developer.huawei.com/consumer/jp/agconnect/cloud-test)
* Cloud Testingのドキュメント：[https://developer.huawei.com/consumer/en/doc/development/AppGallery-connect-Guides/agc-cloudtest-introduction-0000001083002880](https://developer.huawei.com/consumer/en/doc/development/AppGallery-connect-Guides/agc-cloudtest-introduction-0000001083002880)
* Huawei Developers：[https://forums.developer.huawei.com/forumPortal/en/home](https://forums.developer.huawei.com/forumPortal/en/home)
* Facebook Huawei Developersグループ：[https://www.facebook.com/Huaweidevs/](https://www.facebook.com/Huaweidevs/)
v-file-inputでファイル選択をキャンセルするとv-modelが空になってしまう問題に対処してみる

v-file-inputでファイル選択後にもう一度選択画面を開き、「キャンセル」をクリックするとmodelが空になってしまう問題に諸般の事情で対処してみた。

```vue
<template>
  <v-file-input
    label="ファイル選択"
    @change="loadFile"
    :clearable = false
    v-model="fileName"
  ></v-file-input>
</template>
<script>
  data () {
    return {
      fileName: null,
    }
  },
  methods: {
    loadFile(e) {
      if(e != null && e != undefined){
        const file = e
        let reader = new FileReader()
        reader.readAsText(file)
        reader.onload = () => {
          this.loadedFunction(reader.result)
        }
      } 
    },
    loadedFunction () {
      //ロード後の処理
    }
  }
</script>
```

だいたい上記のような実装になると思う。
これにキャンセル対策を施してみる。

```vue
<template>\
  <v-file-input
    label="ファイル選択"
    @change="loadFile"
    :clearable = false
    v-model="fileData"
  ></v-file-input>
</template>
<script>
  data () {
    return {
      fileData: null,
      //退避させる変数を用意
      prevFileData: null,
    }
  },
  methods: {
    loadFile(e) {
      if(e != null && e != undefined){
        const file = e
        let reader = new FileReader()
        reader.readAsText(file)
        reader.onload = () => {
          // 正常に読み込まれた場合、そのデータを保存しておく
          this.prevFileData = e
          this.loadedFunction(reader.result)
        }
      } else {
        //キャンセルされたときの処理
        let reader = new FileReader()
        //保存しておいたFileオブジェクトからBlobに変換、Fileオブジェクトにすることで参照渡しではなくコピーする
        reader.readAsDataURL(this.prevFileData)
        reader.onload = () => {
          let blob = this.dataURItoBlob(reader.result)
          let file = new File([blob], this.prevFileData.name, { type:this.prevFileData.type, lastModified:this.prevFileData.lastModified })
          //v-modelへ反映する
          this.fileData= file

        }
      }
    },
    loadedFunction () {
      //ロード後の処理
    }
    //dataURIをBlobに変換する関数
    dataURItoBlob(dataURI) {
      let byteString = atob(dataURI.split(',')[1])

      let mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];

      let ab = new ArrayBuffer(byteString.length);
      let ia = new Uint8Array(ab);
      for (let i = 0; i < byteString.length; i++) {
          ia[i] = byteString.charCodeAt(i);
      }
      return new Blob([ab], {type: mimeString});
    },
  }

</script>
```

要はv-model以外に退避させておいてキャンセルだったらv-modelに退避させておいたデータを反映させるというやり方。
なんだかリソース食うなーという感じ。

これが正しいのかどうかわかりませんけど一応。
[オンラインセミナー開催] Zoom Developer Platform 最新アップデートについて


#[オンラインセミナー開催] Zoom Developer Platform 最新アップデートについて</b>
2021年11月18日(木) 18:00-19:00
アジェンダ：
・Developer Platform とは
・Web Meeting SDK
・Video SDK React Native
・Video SDK API
・実装に関わる注意事項
参加対象： ZoomのAPIやSDKについて詳しく知りたい方
申込方法： https://bit.ly/zoomdevupdate_11-18-2021
テスト自動化は人間の心を癒してくれる

#はじめに
主にE2Eでのゲームアプリのテスト自動化の導入にあたり、
内々で時折相談を受けることがあるが、
どういうわけか**全テストケースの自動化が可能**で、
**簡単に工数削減ができる**と認識している状態で相談を受ける。
テスト自動化ツールは人間の代わりを務めることは難しい。
以下、理由を挙げていく。


#自動テストは人間の代わりにならない
日本国内でテストの標準になりつつあるJSTQBでのFLシラバスでは、
以下の主な活動がテスト実行として記載されている。
>• テストアイテムまたはテスト対象、テストツール、テストウェアの ID とバージョンを記録する。
• 手動で、またはテスト実行ツールを使用してテストを実行する。
• 実行結果と期待結果を比較する。
• 不正を分析して、可能性のある原因を特定する（故障はコード内の欠陥によって発生する可能性があるが、偽陽性が発生することもある。
• 故障を観察し、観察に基づいて欠陥を報告する。
• テスト実行の結果（合格、不合格、ブロックなど）を記録する。
• 不正への対応の結果、または計画したテストの一環として、テスト活動を繰り返す（修正したテストケースによるテスト、確認テスト、および/またはリグレッションテストの実行）。
• テストベース、テスト条件、テストケース、テスト手順、テスト結果の間で双方向のトレーサビリティを検証し更新する。

活動としては「記録」「テスト実行」「結果比較」「不正を分析」「故障を観察」「報告」「トレーサビリティを検証し更新」といったところ。
普段テスターは上記活動を行いソフトウェアを検証している。

テスト自動化ツールは「記録」「テスト実行」「報告」は滞りなく実装出来るとは思う。
以下の機能についてはかなり工夫入れていかなければ以下のようになる。

「結果比較」は単純なパラメータ、値が一致しているかの確認しかできないし、
「報告」もまた成功・失敗程度の報告しかできない。
「不正を分析」「故障を観察」「トレーサビリティを検証し更新」を行おうとすると、
膨大な工数を割いて実装するためやはり現実的ではない。

2021年現在、テスト自動化ツールは一部分の活動でのみ支援することが可能であるが、
人間のテスト活動と同様の働きを見せることは難しいことが想定される。

#自動テストはそんな簡単に作れない
昨今テスト自動化ツールでは、ノーコード、ローコードで扱うことができ、
「誰でも簡単に自動ツールで動作確認・検証を作成・実行が出来る」と
謳われている時がある。
確かに一般的なWebサイトなら有用に扱えるだろうと思う。

しかし、他のコンテンツを例を挙げるとゲームアプリのようなオーダーメイドな
仕様が当たり前のアプリケーションにローコード・ノーコードツールはほぼ通用しない。

例えばスマホゲームでは標準的な実装がされていると思われる「最も単純な機能」である
「ガチャ機能」の確認を例にするだけでも以下の分岐が思いつく。
異常系・通信周りは除く。
>・無償か有償か
・回数限定か無制限か
・ガチャを回す時、演出上で操作を挟むか
・高レアリティ排出時に演出が挟むか
・ガチャ結果画面の有無
・続けて回す機能の有無
・ガチャを回した際のオマケのプレゼントがあるか
・天井回数分ガチャを回した時、交換画面に遷移するか

上記分岐する機能を考慮しつつ実装することになるが、
この機能群をノーコード・ローコードツールで簡単に実装できるのだろうか。
「簡単に作れます」なんて営業トークか驕らない限り中々言い切れない。
「(時間をかけ、条件を満たせば比較的)簡単に作れます」かもしれないが…


#手動でのテストの効率化の先に自動化がある
それではテスト自動化ツールを導入し、
自動テストを十全に扱おうとする場合どうしたらいいか？となる。
その答えは至極単純なもので「**最適化されたテストケース上でテスト自動化ツールが長時間動いても安定するものが自動化しやすいケース**」になる。

テストケース中、人間が読み取ると解釈が変わるようなテストケースや、
1つのテストケースなのに2つ以上の期待結果があるようなテストケースがある場合は、
「**テスト自動化をする前**」に手動でのテストの効率化の余地が大きくある。
なので手動テスト効率化を先に着手しても全く遅くはない。
むしろ手動テストと向き合う機会が来たと喜ぶべきだ。
品質は一歩にしてならず、品質というものに向き合い続け、
テストが成熟して初めて自動化に出会える。


#先に手動テストを効率化しても遅くない
なぜ手動テスト効率化を先に着手することを勧めるかというと、
手動テストの工数を効率化するのが比較的して容易であるのと、
自動テストを導入する際にテストケースを精査して
自動テストに向くか精査する工程があるため。

自動テストが手動で実施する場合のコストを確実に下回る状況を見極め、
適用して実装しようとする場合、
現状況では自動化エンジニアはテストケース・アプリを触らざるを得ない。

結局、最適化をするのであれば手動テストも最適化した後に、
自動化を導入することを検討する方がコスト・無駄が少なくなる。
勿論並行して行うという形でも個人的には良いと思う。


#テスト自動化ツールは人間以上になる時は限定的
テスト自動化ツール、万能ではないところばかり述べてきたが、
設定さえすれば勝手に動くツールなので、人間以上のパフォーマンスが出る時もある。

人間は休みなくして働き続けるのは困難だが、長時間稼働しても基本的に問題ない。
また、単調なテストにもエラーを吐かない限り文句ひとつ言わずに動いてくれる。

**従業員の精神衛生の改善**のための自動テスト導入は強くお勧めができます。
自動テスト導入により、テストエンジニアのストレス状況は改善され、
気持ちよくテストを行い、綺麗なバグ票が開発に送られる。よって現場のストレスは減る。
そしてより良い品質に製品が提供できるようになる。
ビジネスとしての結果は自然と後からついてくる。

#最後に
**テスト自動化は人間の心を癒してくれる**
テスト効率化を行おうとする導入が出来るということは、
テストの効率化が測れているということなので、
テスト環境を計る指標としては便利ではあるし、
テストツールに単調なテストを任せ、
テスターはクリエイティブなテストを行うことができ精神衛生上で良好な環境になる。

自動テスト導入を人が足らなくて…コスト減らしたくて…等、
金銭・時間など消極的な理由で検討するのではなく、
より良いテストを行い、良質なソフトを提供するための自動テストの導入はどうだろうか。
WEBデザイナーがWordPressに別れを告げようと思ったらJavaScriptを勉強することになったポエム

##始めに
MovableTypeがライセンス問題でもめた（実際は元々商用利用は有料だったのに、オープンソースとして勝手に広まっていたため、MT側が警告を出したら反発をくらった）2000年代後半あたりで 「再構築がいらないCMS」として爆発的に人気が盛り上がったWordPressに移り10年以上。いくつものサイトをWordPressで構築してきた。

小規模サイト、いわゆるトップページ、お知らせ、会社概要、お問い合わせフォームを基本としたサイトでは静的HTMLで十分なページすらも PHP（テンプレート）で作成しなければならない点に疑問を感じつつも、

**公開後のお知らせの更新は自分たちでやりたい**

というクライアントは多く、それを最もローコストで実現できるのはWordPressだったのだ。

##WordPressに別れを告げたいと思った理由
そんな愛してやまないWordPress。
しかし

**やっぱり、静的なHTMLで事足りるページまでWordPressで作るのって、非効率では？**

という思いがずっとくすぶっていた。
素のHTMLの方が表示の速度を早くできる気がするし、ソースも無駄がない気がする。

**お知らせ部分だけをWordPressで作り、静的HTMLに埋め込むようなことはできないか？**

と夢を抱いたのが事の始まり。
（この時点では夢であり、現実として小規模サイトにとってどうなのか、はまた別の機会に。）

##WP REST APIの存在に気づく

**投稿のデータをjsonで取れないのかな。取れたら色々できそうなのに。**

そう探したら、正にドンピシャなそれがすぐに見つかった。WP REST APIである。
なーんだ、あるじゃないか。しかもWordPress公式から2016年にリリースされているとは。きっと私だけが知らなかったのだ。（勉強不足）
いやちらっと見た気がするがスルーしてた・・・。

早速試そう！

##まずはJavaScriptを勉強すること。話はそれからだ

WP REST APIを調べていくうちに、Reactというキーワードにぶつかる。
なんとなく、便利なライブラリーってやつでしょ？くらいは知っていたけど、WordPressっ子のご多分に漏れずjQueryを愛用し（だってWordPressの中に入ってるじゃない。そりゃ使うじゃない。）、事足りてきてしまったので、目を背けて来た典型的なダメパターン。

このWP REST APIを料理するには、Reactを勉強する必要がありそうだ。

さらに調べていくと、

**Reactは手ごわそう**

ということだけは私にも分かった。
さらにReactはきっちりモダンJavaScriptを勉強してからでないと門を叩けない硬派な存在であることも分かった。

jQueryはJavaScriptを知らなくても扱えてそれが魅力だったけど、Reactは許してくれないので、勉強するしかない。

これを機にJavaScriptについて、断片的ではないまとまりがある知識を得ていきたいと思う。
ターミナル再起動するたびに「node: command not found」となる

# ターミナル再起動するたびにパスが通っていなくて「node: command not found」となる
nodebrewのバージョンは、表示されるのにnodeのバージョンが表示されない
困った。

```
$nodebrew ls 
v16.13.0

current: v16.13.0

$node -v
zsh: command not found: node
```
↓
だが、source ~/.bash_profileを実行するとnodeのバージョンが表示される。
毎回パス反映を実行するのだるいじゃん。

```
$source ~/.bash_profile
$node -v               
v16.13.0
```
↓
ターミナルのシェルに種類があるらしい（zsh・bashなど）
下記でbashに切り替える（パスワード入力）ターミナルを再起動

```
$chsh -s /bin/bash; 
```
↓
ターミナル再起動後にnodeバージョン確認を実行、確認できた。
シェルの違いやパス反映を実行しなくてもよくなった理由については、後で追記予定。
今知りたい方は、調べてください。または補足を

```
$node -v               
v16.13.0
```

## 最後に
環境構築終わったー！と思った次の日動かなくなって焦ったら、シェルの種類だった。インストール手順の下の方に注意書きしておいてほしかった。
C# ファイルの移動方法

```C#:Form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;

private void button1_Click(object sender, EventArgs e)
{
     string path1 = @"C:\Users\○○\Documents\for文test1\for文test1.txt";
     string path2 = @"C:\Users\○○\Desktop\for文test2\for文test1.txt";

     File.Move(path1, path2);
}
```

参考サイト
https://itsakura.com/csharp-file-create
なぜRustを学ぶのか

楽しいから

# 一般的な理由

## 実行速度が速い
https://github.com/ixy-languages/ixy-languages/blob/master/img/batches-3.3.png

CやC++に代わるような言語を目指している
このため、Pythonなどのスクリプト言語よりずっと速い

## メモリ管理が厳しく、安全である

CやC++だと配列などのメモリ管理をプログラマが注意する必要がある ([例](https://bi.biopapyrus.jp/cpp/syntax/malloc.html))
不正なメモリアクセスをすると、よくて Null Pointer Exception、悪い時は未定義動作により、アプリケーションが壊れる
しかも実行時にならないと、エラーが分からないこともある

Rustはライフタイムや所有権や借用という仕組みおよび、メモリの使い方をコンパイル時にチェックすることにより、安全なメモリ管理がしやすい

また、変数を宣言、代入するときにきちんと型を指定する必要があり、これも安全性と速度に貢献している
(ある程度は型を推論してくれる)

こんな感じ
変数の宣言は `let` を使う
行末はセミコロンで終わる
(初めてPythonに触った時、改行とインデントで制御しているのに驚いた...)

```Rust
let a: i32 = 32;
let b: f64 = 0.64;
```

## 並列処理をしやすい

並列処理をしやすいように設計されている
また、上記メモリ管理のため、並列処理時にもデータが不用意に変更されたり、消されたりしない
とはいえ、正直この辺りは触ったことがないのでよく分からない

https://qiita.com/nirasan/items/97263103f076bd525a7b

# Rustの特徴

一般的な理由の部分で述べた通り

keenさんの分かりやすいスライド
https://keens.github.io/slide/anzennagengorust/

- 実行速度が速い
- メモリ管理が厳しく安全である
- 並列処理をしやすい
- rustupによりRustの管理が容易
- cargoにより実行コードやライブラリの管理、テストが容易

## 上記の事情から人気

StackOverflowではずっと人気上位

https://insights.stackoverflow.com/survey/2021#most-loved-dreaded-and-wanted-language-love-dread

https://qiita.com/elipmoc101/items/3c8b6d8332a9019e578c

# 個人的な動機

- 学生時代にCでシミュレーションを書いていた
- [この記事](https://jp.techcrunch.com/2017/07/17/20170716death-to-c/) が面白く、CやC++に代わる言語として興味があった
- 書きっぷりが割と気持ちいい
- コンパイラに引っかかることは多いが、エラーメッセージが親切
- システムに近いような言語を触ってみたかった

# データサイエンティストとしてのメリット

- データ量が多かったり、速度が求められるサービスを作ったりするときに有用
- PythonやRとは設計思想の違う言語を学ぶことで、技術の幅が広がる
- データ分析系のクレートも多数存在している ([ばんくしさんの記事](https://vaaaaaanquish.hatenablog.com/entry/2021/01/23/233113))

# どう学ぶか

Rust by Exampleをやった後に、竸プロの問題をやるのがとっつきやすいかと

- [Rust by Example](https://doc.rust-lang.org/stable/rust-by-example/)
- [The Book](https://doc.rust-lang.org/book/)
- [Rust初心者はまず競プロから始めたら良さそうって話 ](https://speakerdeck.com/fnwiya/competitive-programming-by-rust)
- [AtCoder に登録したら解くべき精選過去問 10 問を Rust で解いてみた](https://qiita.com/tubo28/items/e6076e9040da57368845)
git commit できず苦戦（Controller.phpにActionを追加しただけ）

# はじめに
＜自己紹介＞
こんにちは、この記事が初投稿になります。
某SES企業に所属しています。現在は、非ITのクライアントに常駐しながら開発案件を目指して日々奮闘中です！
日々の学習のアウトプットのために活用させていただきます。

# ＜エラー概要＞
◉Laravel学習初日
Admin/ProfileControllerに、add、create、edit、updateそれぞれのActionを追加しターミナル上でgit commitを入力したが

:::note warn
" On branch master　Initial commit　nothing to commit "
:::
と出力されうまく実行できない。

#＜仮説／試したこと＞

◉ masterブランチ上で操作しているのでブランチを切ってくださいと怒られている
→ブランチを一度削除しやり直し
◉ そもそも指定しているディレクトリが違う
→確認、問題なし。
◉ VScodeとの接続がうまくできていない
→```git add/git remote -v``` で確認、問題なし

あらゆることを試しましたが全然うまくいかなかったのであらゆるものを削除して一からやり直してみようと下記実行
#＜原因／結果＞
 ```git remote rm origin```
でリモートリポジトリを削除
🔻
```git add``` →```git commit　```
🔻
**無事成功！**

### 


# 感想
正直、原因を詳細に解説することはできませんが仮説が尽きた際は全体を俯瞰して見てから
やり直しが効く箇所は削除して再度やり直してみることで新しい気づきがあることを学びました。

最後まで読んでいただきありがとうございます！
認識が誤っている箇所、追記事項あればご教授いただければ幸いです。
よろしくお願い致します。
<br>
<br>
【Ruby】初心者むけ！オブジェクト指向とは？

#オブジェクト指向とは？

Rubyはオブジェクト指向のプログラミング言語と言われています。

いろんな説明をみてもよくわからないかと思う人が多いと思います...

わたしも

『オブジェクト指向...とは...？』

こんな感じでしたの安心してくださいね！

##オブジェクト指向

オブジェクト指向というのは、モノと操作に分けて考える
考え方のことを言います。

リモコンの例をだしますと、リモコンのハードの部分と実際に操作するプログラムで
わけることができますね！

ものと操作を分けて組み立てていくので
効率良く開発できるのもオブジェクト指向の特徴です。

##オブジェクト指向で覚えておきたいワード

オブジェクト指向を勉強する上でしっておかないといけない
オブジェクト指向の特徴を解説していきます！

・カプセル化
・継承
・抽象化
・ポリモオフィズム

この４つはしっかりを把握しておきましょう！

##カプセル化

カプセル化というのは、共通して使用したい部分については
他のプログラムから変更できないようにする考え方のこと。

例えば、ボタンを作るコードがあるとしまう
そのボタンのデザインの部分は共通して使うので
他のプログラムから変更できないようにします。

これがカプセル化です。

##継承

プログラムを書いていく上で継承はとても重要です。
継承というのは、同じプログラムを何回も書かなくても
一回書けばそれを継承していける機能のこと。

Rubyの例であれば、一度メソッドを書いてしまえば
そのメソッドを使いまわしていくことができます。

更新するメソッドがあるとして一度作ってしまったら
それを他でも使っていくことができるんですね！

##抽象化

これは開発をしていく上で、必ず必要になってくる箇所のことを指します。

例えば、Railでアプリケーションを開発していくと
必ずmodelファイル、コントローラー、viewファイル等が
必要となってきます。

もっと簡単な例でいうと、車の製造を行う際は
必ずドアが必要になる、ハンドルが必要と車を製造する上で
必ず必要となってくる部分の考え方を抽象化といいます。

##ポリモーフィズム

これは似たようなプログラムの一部を変更して
他でも使いまわせるようにする考え方です。

Ruby on railsの例でいうと、
rubyで書いたコードを共通化して一部だけ
違う色にしたりすることで何度も同じコードを
書いたりする手間を省くことができます。

つまり使いまわして一部だけ変更して使うことができるんですね！

##まとめ

いかがでしたでしょうか？

オブジェクト指向について理解できましたでしょうか？

最初は説明をみても？？と思いますが
プログラムを書いていって全体の流れを把握できると

オブジェクト指向ってあそこの機能で使われてたんだ！

と理解しやすくなると思いますので
なんとなく最初の時点では覚えておけばOKです！

オブジェクト指向のプログラミング言語で
webアプリを作成しているうちに理解できてくるはずです！

それでは、また次の記事でお会いしましょう！

チャオ！
【AWS】【ハンズオン】各10分くらいで、Serverless Architecture（Lambda、API Gatway）＋RDSを触ってみる

だいぶご無沙汰しています。
どーも、のぶこふです。

「あれ、タイトルがAWSだけど、Blockchain関連じゃなかったんかワレ」と思った方、鋭いですね。

今年から弊社はAWSにも注力していて、ご多分に漏れず私もAWSを触る機会がが増えてきました。
最近、社内向け勉強会（現地とZoomのハイブリット開催）にて、資料を作成したので、こちらにも投稿します。

各詳細は、[Github](https://github.com/nobkovskii/aws_handson/tree/main/01_serverless-architecture)を参照していただくとして、Qiitaでは寄り道に逸れた内容とか勉強会の振り返りを書いていこうと思います。

あ、Blockchain（Cordaとか）はBlockchainで、EKS上にNode立てたりしてますので、遠からず。

```
　　　　　　　　　　　　　　　　　　　　　　(ﾟ∀ﾟ)ｱﾋｬ
```

### 全体像
構成図としては、下記の通りです。
Serverlessな構成としては、RDSを使っていることを除けば、ごくごく一般的な内容です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306608/1ffc2977-abb1-b5c4-4b22-c3751953a494.png)


### API Gatway
今回は、RESTを使用しています。

本当は、HTTPのほうが良いなー思ったのですが、時間の関係もあり無難なRESTを選択。

### Lambda
Java8で書いてます。
Q：なんでJavaつかってるの？
A：社内向けと考えたときに、馴染みがあるのがJavaだったというだけや


最初、Java17とかで書いていて、Lambdaさんから怒られたりしました。
一番のハマりどころとしては、「FatJarにしないと、Lambda実行時に他Jarを読み取れなかった」ということでした。

今回の例でいうと、Jackson使うとか、そういうところです。

あと、社内ハンズオンをやるにあたり、「Javaのバージョンが揃っていない」「そもそもJavaが入っていない」みたいなケースがあったので、CloudShellにJDKを入れて、そちらでBuildをするようにしています。
Cloud9とかで環境を整えてあげるのも良かったのですが、そこまでコードを書いてもらうつもりはなかったので、CloudShellでBuildが完結したのは良かったところだと思います。

あとあと、LambdaへのUploadも、CloudShellからCLI叩いているのもミソですね。
画面から操作してもらうよりも、コピペしてコマンドを叩いてもらうほうが、ミスも少ないですし。
反面、「これ、なにしてるんだっけ？」というコメントも頂いたので、そういうところは補足する必要はありそうです。



### RDS
Q：なんでRDSつかってるの？
A：社内向けと考えたときに、馴染みがあるのがRDB（＝RDS）だったというだけや

いや、まぁ、ほんと、ただそれだけの理由なんですよね。
DynamoDBにしようかとも思いましたが、NoSQLの説明するのも面倒だったので、RDSを使ってます。
のちのち、RDS Proxyとか使ってみたいです

### 全体を通して
何もつまずくことがなければ、それぞれ10分ずつくらいで終わる分量だと思ってましたが、やはりつまずく人はつまずく。
ただ、手順は大分細かく書いていたので、遅れたりとか、後から来た人でもキャッチアップ出来たし、なんなら当日来れなかった人でも実施することが出来たのは良かったかなぁ、と。

進行とかの関係上、時々「どうですかー？」とか声掛けするんですが、オンライン側からの反応が薄かったので、進んでよいのかどうか迷う時がよくありました。
ここらへんは、どうにか変えていきたいなーと思っています。良い案は浮かんでませんが。

今回は、Inputに「-nyan」をつけて返すAPIの作成だったので、Inputを「nyan」にすれば「nyan-nyan」になるし、「Jiba」にすれば、あれになるので、そういうネタみたいなのも組み込んでいて楽しかったです。

### おわりに
今後も定期的にハンズオンを開催予定なので、実施したらQiitaに後日談的な感じで投稿していこうと思います。

今回は以上です。
ありがとうございました。
「なでしこ3」でCSVファイルを読む

バッチ処理で使う多くの場面で、CSVが利用されます。経理処理から機械学習まで、CSVはデータ処理の基本です。そこで、なでしこ3PC版(Node.js)版で、CSVファイルを読む方法をまとめてみます。

# まずは結論から

日本で流通する多くのCSVファイルはShift_JIS形式です。そこで、`SJISファイル読む`を使って、Shift_JISのファイルを読み込み、`CSV取得`でなでしこの配列形式に直して何か処理を行って`表CSV変換`でCSVに戻して`SJISファイル保存`でファイルに保存します。

```CSV処理.nako3
!「plugin_csv」を取り込む。
# CSVファイルを読み込む
「入力_sjis.csv」をSJISファイル読んで、CSV取得して、データに代入。
# 何かしらの処理 - ここでは抽出
データの0から「ケーキ」を表ピックアップして抽出データに代入。
# CSVファイルへ保存
抽出データを表CSV変換して、「出力_sjis.csv」へSJISファイル保存。
```

## それぞれの命令の使い方

上記で使った命令の意味と、マニュアルへのリンクを以下に列挙します。

 - [SJISファイル読む](https://nadesi.com/v3/doc/index.php?plugin_node%2FSJIS%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E8%AA%AD&show) --- Shift_JISのファイルを読む
 - [SJISファイル保存](https://nadesi.com/v3/doc/index.php?plugin_node%2FSJIS%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E4%BF%9D%E5%AD%98&show) --- Shift_JISでファイルへ書き込む
 - [CSV取得](https://nadesi.com/v3/doc/index.php?plugin_csv%2FCSV%E5%8F%96%E5%BE%97&show) --- テキストデータをCSV形式と見なして、二次元配列(表)に変換する
 - [表CSV変換](https://nadesi.com/v3/doc/index.php?plugin_csv%2F%E8%A1%A8CSV%E5%A4%89%E6%8F%9B&show) --- 二次元配列(表)をCSV形式のテキストに変換する

# CSV処理に関して - CSV取得と反復の組み合わせ

CSVに対して何か処理したい場合、列ごとに処理を行うことになります。例えば、先頭列に顧客の名前が書かれており「様」を付けたい場合などは、以下のように書けるでしょう。

```様追加.nako3
CSV=「加藤,300
佐藤,200
田中, 250」
Ｏ＝CSVをCSV取得
Ｏを反復
　　対象[0]=対象[0]&「様」
ここまで。
Ｏを表CSV変換して表示。
```

上記を実行すると以下のような結果が得られます。

```
加藤様,300
佐藤様,200
田中様,250
```


# バリエーション - SJISファイルの読み込みに関して

なお、`SJISファイル読む`を使わずに、`バイナリ読む`を使ってファイルを読み込み、`SJIS取得`でShift_JISの文字列をなでしこの内部形式Unicodeに変換できます。

 - [バイナリ読む](https://nadesi.com/v3/doc/index.php?plugin_node%2F%E3%83%90%E3%82%A4%E3%83%8A%E3%83%AA%E8%AA%AD&show)

```SJISデータ読む.nako3
「test_sjis.txt」をバイナリ読んで、SJIS取得して、Sに代入。
Sを表示。
```

# まとめ

CSVファイルの読み書きは、バッチ処理の基本の基本なので、しっかり押さえておきましょう！
Windows.FormsのリッチテキストにNlogの出力を表示させる為に必要な手順

#1回しかやらないからすぐ忘れる問題

1回実現させて忘れた。おそらく次にソリューション作る際も忘れているので手順を書き残す。
まっさらなソリューションからWindowsFormsをまだ使うことを想定する。

##1.NLogをソリューションに取り込む
パッケージマネージャから以下を入れる。
・NLog
・NLog.Config ⇒ 自動でNLog.Schemaが入る
・NLog.Winfows.Forms

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/345260/d0de5f68-44bd-0d20-b1e9-af7292252939.png)

#2.Formにリッチテキストを貼り付け、再初期化コードをFormの初期化の後に入れる。
私が参考にしたのはこのオフィシャル
https://nlog-project.org/2015/12/28/nlog-windows-forms-4-2-has-been-released.html


###2.1普通のRichTextBoxをFormにGUIで貼り付け。
NLog.Winfows.Formsを入れたからといって特別なRichTextBoxが増えるわけではない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/345260/7245ece6-7613-1322-9d21-bab53931b1aa.png)

貼り付けたら名前を確認する。こいつは「richTextBox1」君
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/345260/fa522bb2-6740-5442-3665-5c44a966f8a9.png)


###2.2 フォームにコードを追記する
usingにNLog.Windows.Formsを追加してInitializeComponentの後に再初期化コードを追加する

```c#:Form1.cs
using NLog.Windows.Forms;

namespace 素敵なプロジェクト
{
    public partial class Form1 : Form
    {

        public Form1()
        {
            InitializeComponent();

            //NLog用処理
            RichTextBoxTarget.ReInitializeAllTextboxes(this);
        }
    }
}
```

##3.NLog.conigを設定する
###3.1 出力ディレクトリ設定が書き換えたらコピーされることを確認する。
出力ディレクトリーにコピーの設定を確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/345260/3a575f2c-f920-2d6d-9d87-2f3e3f3c03c7.png)


###3.2 設定へ追記
2つのタグの間に設定を追加する。

####targetsタグ
重要なのはformName="Form1" controlName="richTextBox1"を実際の名前と同じにすること。

```xml:NLog.config
  <targets>
    <!-- ログファイル設定 -->
    <target name="logRichTextBox" xsi:type="RichTextBox" allowAccessoryFormCreation="false" formName="Form1" controlName="richTextBox1"  maxLines="100" supportLinks="true" autoScroll="true" useDefaultRowColoringRules="true" layout="${longdate} ${uppercase:${level}} ${message}"/>
  </targets>
```

####rulesタグ
targetsタグのnameにすること

```xml:NLog.config
 <rules>
    <logger name="*" minlevel="Trace" writeTo="logRichTextBox" />
  </rules>
```

#結果
こんな感じでログが表示される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/345260/0d81dbb6-421e-0e8c-efa3-62ee4125a5bf.png)
Helmチャート(Go Template)のループの中で上位スコープの変数を参照する方法

# 概要

ループの手前で変数を定義し、それを参照します。

# 例

まずvalues.yamlの変数を定義

```yaml
repository:
  username: craftsman-software
  name: focas

branches:
  - name: main
    project: focas
    service: web
    environment: prod
  - name: prototype
    project: focas
    service: web
    environment: prototype
```

```yaml
# ループの前で変数定義
{{ $repositoryFullName := printf "%s/%s" .Values.repository.username .Values.repository.name }}

apiVersion: triggers.tekton.dev/v1alpha1
kind: EventListener
metadata:
  name: eventlistener-focas
  namespace: focas
spec:
  serviceAccountName: focas-pipeline-sa
  triggers:
    {{- range .Values.branches }}
    - name: github-push-listener-for-{{ .name }}
      interceptors:
        - name: "only when specified branch"
          ref:
            name: cel
          params:
            - name: filter
              # ループないで事前に定義した変数を参照
              value: "body.repository.full_name in ['{{ $repositoryFullName }}']"
            - name: filter
              value: "body.ref in ['refs/heads/{{ .name }}']"
      bindings:
        - ref: pipelinebinding-focas-for-{{ .name }}
      template:
        ref: triggertemplate-focas
      {{- end }}
```
[Python] range()の使い方

Pythonにおいて、for文で***range()***を使用したので、使い方をまとめておく。

# range()の使い方
***range()***は、引数で指定された条件に沿った数値リストを持つ、range型のオブジェクトが作成される。***range()***の書式は以下のようになる。

```python
# 書き方
range(<開始値>,<終了値>,<変化量>)

# 例
data = range(3,15,3)
print(list(data))     # [3, 6, 9, 12]
```
***range()***の引数の開始値と変化量は省略することができ、この場合は```開始値 = 0```、```変化量 = 1```として実行される。
また、rangeオブジェクトを表示する際は、直接```print()```の引数に指定しても表示されず、list型のオブジェクトを作成して表示させる必要がある。

#　for文での使用
***range()***を使用してfor文を記述すると以下のようになる。

```python
# 例：3, 6, 9, 12を順番に表示する
for i in range(3,15,3):
    print(i)

# 例：apple,grape,orangeを順に表示する
fruits = ['apple','grape','orange']
for name in fruits:
    print(name)
本番環境でSQL文を叩きまくった話

この記事は [赤ちゃんは25日でアプリの設計から開発まで遂行できるのか][1]の11日目の記事です。
（本番環境でやらかしちゃってますが、本番環境でやらかしちゃった人カレンダーとは関係ありません）

今日は作業お休みDayなので箸休めがてら、3年前、私が前職でプログラマ新生児だった頃にやらかして永遠に心の傷となっていた事件を供養しようと思います。

[1]:https://qiita.com/advent-calendar/2021/baby-challenge

## 何をやらかしたのか

###やらかしの土台

* 自分が新卒で入社して半年（OJT明け）かつ<b>案件に参画した直後</b>
* 入った案件は5年以上自社で請け負っており、<b>チームメンバーもほぼ固定</b>で半ば<b>属人化していた</b>
* 自分に<b>指示を出していた上司はこの案件のメインメンバーではなく</b>、尚且つ複数案件を掛け持ちしていたため案件に対して特別詳しいわけではなかった

### 自分に与えられたタスク

具体名は伏せますが、案件はよくある販売者側の販売物管理と購入者側の事後サポートを行うWEBサイトでした。
サイトはフロントが販売者側と購入者側で2種類あるのに対し、管理画面は共通という仕組みです。

自分はその中で、
最初に、購入者側サイトでユーザーの登録地域ごとに提携銀行などのバナーが変わるデザイン改修作業を、
次に、販売者側の明細がPDF出力のみだったのをスマホ向けにとしてPDFを介さずサイト画面からで直接見れるようにするための改修作業を振られていました。

1つ目のタスクでレビューが無事通り、自分の変更をステージングに上げてもらい、単体テストとして<b>「購入者側のDBサーバー接続情報が書かれたExcelファイルとパスワード」</b>を教えてもらい、ダミーユーザーの登録地域を書き換えて各地域ごとに正しいデザインが表示できたのでこちらのタスクは無事完了しました。
(こちらも名前は伏せますが、MySQLではなくWEBサイト上でDB操作するツールを使用していました)

### そして起こったやらかし

2つ目のタスクがある程度終わり、「じゃあ赤ちゃんさん、テストをお願いします」と言われた時に事件は起こりました。

1つ目のタスクで私がDB接続のために確認したファイル名は「buyer_bd_stg.exe」(仮名)でした。
エクセルファイルの中に他のシートも無く、私は同じ階層にあった「seller_bd.exe」(仮名)を迷いなく開き、<b>buyerと同じパスワード</b>でファイルを開いてそこに記載されていたDBに接続しました。

まずユーザーの登録情報を変更したかったのでダミーユーザーでUPDATEを叩きますが、該当データがないということでエラーが出ます。
誰も登録していなかったのかと思いながらINSERTを叩きますが、ここでも再びエラーが。
おかしいなと思いながらも既存でデータが入っていたようなので、それを覗き見た瞬間血の気が引きました。

私が叩きまくっていたのは、本番サーバーの顧客DBでした。

## 二度と惨劇を起こさないためにどうしたか

### 自分が本番にアクセスしてしまった原因

* 「buyer_db_stg.exe」が販売者、購入者<b>共通のSTGサーバーと伝えられていなかった</b>
* ファイルやサーバーを<b>見ただけでは共通とわからず</b>、<b>ファイル名も紛らわしい</b>物になっていた
* 本番環境にアクセスするファイルとステージング環境のファイルで<b>同じパスワードを使い回し</b>ていた
* 1回目、2回目のタスク共に<b>新人が1人でDBを操作</b>する環境にあった

### 行った対策

* STGサーバーも販売者、購入者で分けた。ファイル名も「stg_seller_db.exe」「stg_buyer._db.exe」に変更。
* 本番のアクセス情報が入ったエクセルの配置階層をパスワード付きのフォルダへ移動させて2重パスワードにした。ファイル名も「honban_seller_db.exe」「honban_buyer.exe」に変更。
* 本番のエクセルのパスワードを変更し、<b>マネージャー以上の人間だけが知る情報とした</b>
* 本番、STGでExcelに注釈を入れ、DBサーバー側のサイトヘッダーを変更した
* 初めてDBを触る場合、案件に<b>一定の見識がある人間とペアで作業する</b>ルールを設けた


### さいごに

~~INSERTが出来なかった理由は、ダミーユーザーのユーザーIDがマイナス値(実際の運用では存在しない値)で弾かれていたためでした。~~
追記：当時の記憶を知る人から、DBから直登録したデータの削除対応をしたような記憶がある、という情報をもらいました。
どちらにせよ実際の顧客データには紐付かなかったそうで、影響が出てなくて本当に良かったです。


振り返ってみれば仮に自分が回避できたとしてもいずれ誰かが踏みかねない地雷だったので、入社半年で会議室に呼び出され案件の偉い人全員VS自分の構図で半泣きで必死に弁明し、後釜を根絶やしにできたことは本当に良かったです。
ServiceNowによるシステム管理（概要）

#課題：
ServiceNow ITOMによりシステムの各要素から情報を取得することは可能になるが実際のシステム運用はシステムの各要素を連動して設定する必要がある。
例えば新規にWebサイトを作成する場合はWebサイト用に新規にvmを作成、通信できるようにスイッチ／ファイアウォールを設定した後にWebサイトを監視ツールに登録したりサイトをバックアップするような設定が必要になる。ServiceNow ITOMはそれらの設定情報を取得することはできるが、各機器及びvm環境を設定する機能は未実装である。そのため機器及びサービス毎に設定する必要がある。
これらの設定を一括で行えるようにすることでシステム管理／運用を作業を効率的に行えるようにできる。

#システム構成：
システム管理／運用を自動化するには次のようなサービスが必要である：
1. ジョブ管理（例：Jenkins) - 各ジョブを実行する。
1. 監視サービス（ネットワークモニター） -　サービスが正しく動作しているか監視する。問題が発生した場合は管理者に通達する
1. コミュニケーションサービス（例：Slack） - 監視サービスやユーザからの問い合わせを担当者に連絡をする 
1. バックアップサービス - 各機器及びサービスのバックアップを取得する
1. ファイルのバージョン管理サービス（例：GitLab） - 各機器／サービスの設定ファイルを保管する。バージョン管理されていると設定の変更が分かりやすくなり設定を戻せるようになる。
1.仮想環境（例：VMware）
1.インフラ管理サービス - ①各機器／サービスの設定に乖離があるかチェック、②各機器／サービスを設定


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698027/b5a040df-a8ca-d6d5-a768-48221a9dff37.png)

その他に次のサービスもあると便利である：
1. ログサービス
1. 認証基盤（例：Azure AD/LDAP）
1.ユーザからの問い合わせフォーム

#システム要件の例
1.Intuneのグループに登録された機器はインフラネットワークに接続できるようにする（Radiusに登録する）
1.すべてのvmにファイアウォール、自動セキュリティパッチ、ログ、ntpの設定を行う。定期的に設定をチェックする
1.すべてのサービスデータのバックアップを取得する
1.すべてのネットワーク機器の設定をバックアップする
1.停電など保守時間を設定できる（保守前後の設定を比較、該当監視センサを停止／再開、バックアップの取得、回避設定の確認、サービスのシャットダウン／再開設定（可能な場合））
1.機器／サービス毎の設定に管理があるかのチェック

#実装
「バックアップサービス」と「インフラ管理サービス」を開発する必要がある。
開発言語はPythonにした。多くのネットワーク機器はPython用のモジュールで接続できる。また、インフラ管理サービスはバグが発見されるとシステムを停止しなくて短時間で修正する必要がある。Javaのような言語を利用した場合はビルドする必要があるので時間が掛かる。
機器／サービスから提供されるAPIで機能が実装できない場合はnetmiko/paramiko/telnetなどで接続する。それでも対応が不十分な場合はheadlessブラウザやpyautoguiを利用してWebブラウザから設定を行えるようにした。

以上
TypeScriptとは何者なのか

TypeScriptととは何者なのか？
超簡単にどういうものかをまとめておく。

## JavaScriptにコンパイルされる
JavaScriptが動く環境であればTypeScriptは動作するらしい。

## JavaScriptの上位集合である
JavaScriptで書いたものは全部TypeScriptともいえる。
datetimeオブジェクトのnaiveとaware

はじめに
-
pythonにおいて時刻を扱う`datetiem.datetime`と`datetime.time`オブジェクトには`naive`と`aware`という概念があります。

これは、生成されたオブジェクトがタイムゾーンの情報を持っているかどうかを示す属性値であり、タイムゾーンの情報を持っていれば`aware`, なければ`naive`になります。

このawareとnaiveという部分で躓くことが個人的に多かったので、知識を整理する意味でまとめておこうと思います。

概要〜naiveとawareとは
-
naiveとawareの区別自体は上記の通りで、タイムゾーンの情報を含んでいるかどうかによる。

タイムゾーン情報を含んでいるインスタンスを出力した場合には、`+-xx:yy`のような形式で世界標準時との差異が表示される。

なお、naive型とaware型の組み合わせに対しては、等号・不等号での比較ができない（naive同士・aware同士なら比較可能）。

```python
# 変数now_naiveがnaive型の場合
print(now_naive)
>> 2021-11-16 10:05:46.268496

# 変数now_awareがaware型の場合
print(now_aware)
>> 2021-11-16 10:05:46.268704+09:00
```

タイムゾーン情報の取得
-
aware型のインスタンスは`tzinfo`という属性値を持っており、この値を参照することでタイムゾーンを取得することができる。

```python
print(now_aware.tzinfo)
>> JST
# JSTは日本標準時の意味

# naive型のtzinfoはNoneになる
print(now_naive)
>> None
```

作成されるインスタンスのタイムゾーンの有無
-
`datetime.datetime.now()`で生成されるインスタンスは基本的に`naive`型になるが、now()の引数としてtimezoneインスタンス（後述）を指定することでタイムゾーン情報を持った`aware`なインスタンスを作成することができる。

```python
import datetime
naive = datetime.datetime.now()
print(naive)
>> 2021-11-16 10:27:22.231630
print(naive.tzinfo)
>> None

aware_utc = datetime.datetime.now(dateteme.timezone.utc)
# datetime.datetime.utcは世界標準時の情報を持ったitmezoneインスタンス
print(aware_utc)
>> 2021-11-16 01:27:56.635804+00:00
print(aware_utc.tzinfo)
>> UTC
```
naive型のインスタンスの時刻は世界標準時ではなく現地時刻に合わせたものになることに注意。

例えばこの記事は日本で書いているので、naive型の変数の時刻は`tzinofo="JST"`のものと同じになる（もちろんtimezone情報は持っていないが）。

タイムゾーンの指定方法
-
awareなインスタンスを作る方法の一つとして上記のように`datetime.timezone.utc`をnow()の引数にする方法があるが、これでは世界標準時に基づくインスタンスしか作成できない。

タイムゾーンを任意のものに変更するための方法として、世界標準時から変換する、datetime()の引数として指定する、now()の引数として指定する、の３種類がある。

### 世界標準時から変更する
`astimezone()`メソッドを用いることで、ローカルのタイムゾーンに変更することができる。

```python
now_utc = datetime.datetime.now(datetime.timezone.utc)
print(utc_now)
>> 2021-11-16 01:27:56.635804+00:00

now_jst = now_utc.astimezone()
print(now_jst)
>> 2021-11-16 01:27:56.635804+09:00
```
世界標準時との差異は`+00:00`から`+09:00`に変更されているものの、時刻自体は`2021-11-16 01:27:56.635804`で変更されていないことに注意。

### datetime()の引数として指定する
datetime()の引数として年月日や時刻などとともにタイムゾーンの情報を与えることで、awareなインスタンスが作成される。

```python
import datetime
from zoneinfo import Zoneinfo
now_jst = datetime.datetime(2020, 1, 1, tzinfo=Zoneinfo("Asia/Tokyo"))
# タイムゾーン情報はキーワード引数の形式で設定
print(now_jst)
>> 2020-01-01 00:00:00+09:00
print(now_jst.tzinfo)
>> Asia/Tokyo
```

### nowの引数として設定する
now()はdatetime.timezone.utc以外にも、datetime.timezoneオブジェクトを引数として受け取ることが可能。

`utc`以外の引数に関しては地名や記号を用いるのではなく、以下のように`datetime.timedelta`オブジェクトを用いて世界標準時からの差異を指定する。

```python
now_jst = datetime.datetime.now(datetime.timezone(datetime.timedelta(hours=9)))
print(now_jst)
>> 2020-01-01 00:00:00+09:00
print(now_jst.tzinfo)
>> UTC+09:00
```
不足しているオプションの dSYM をアップロードする(iOS)(Firebase)

# 不足しているオプションのdSYMをアップロードする

## はじめに
自分は「dSYMをアップロードする」で警告が出て失敗したのでこの記事を書いています。
Firebaseのドキュメントに詳しい内容は載っていますので、他に気になることがあるときはドキュメントをご覧ください。
[Firebase Crashlytics SDK を使用して難読化解除されたクラッシュ レポートを取得する](https://firebase.google.com/docs/crashlytics/get-deobfuscated-reports?platform=ios&authuser=0)

## 失敗原因
ドキュメントからコピペしたコードを使用してターミナルを操作したため、失敗した。
フォントが違っていたっぽい。

## 解決方法
ファイルをドラッグアンドドロップで絶対パスを入力
オプションはしっかりキーボードで入力
で解決できました。

## dSYM を見つける
dSYMを見つける方法として二つの方法があります。
1. App Store からビットコードの dSYM をダウンロードする
2. ローカルマシン上で dSYM を見つける
今回、自分は 1. の方法を使いました。

### App Store からビットコードの dSYM をダウンロードする
1. App Store Connectにログイン
1. マイAppを選択
1. Appを選択
1. TestFlightを選択
1. バージョン◯.◯の中にあるビルドの数字を選択
1. ビルドのメタデータを選択
1. シンボルを含む　はい | dSYMをダウンロードからdSYMをダウンロード

ダウンロードのディレクトリにappDsymsがダウンロードされていれば成功です。
chromeでAppConnectを開いているとうまくダウンロードされないので、Safariで実行してください。

## dSYMをアップロードする
dSYMをアップロードする方法として二つの方法があります。
1.　ビルドプロセスに次の行を含める。

```
find dSYM_directory -name "*.dSYM" | xargs -I \{\} $PODS_ROOT/FirebaseCrashlytics/upload-symbols -gsp /path/to/GoogleService-Info.plist -p platform \{\}
```

2.　ターミナルからスクリプトを直接実行する。

```
/path/to/pods/directory/FirebaseCrashlytics/upload-symbols -gsp /path/to/GoogleService-Info.plist -p ios /path/to/dSYMs
```

今回、自分は2. の方法を使いました。
### ターミナルからスクリプトを直接実行する。
1. ターミナルを開く
1. 「upload-symbols」をターミナルにドラッグアンドドロップ　
（プロジェクトのディレクトリ/Pods/FirebaseCrashlytics/upload-symbolsにあります。）
1. "␣-gsp␣"を入力
1. 「GoogleService-Info.plist」をドラッグアンドドロップ
1. "␣-p␣ios␣"を入力
1. appDsymsをドラッグアンドドロップ
1. Enter

警告が出ずに成功が表示されれば成功です。
私の場合、Firebaseのドキュメントからコードをコピペして実行したら、警告が出ました。
警告が出た原因はフォントの違いだと思います。
FirebaseのドキュメントからコピーしたコードはTimesでした。
一方ドラッグアンドドロップしたコードはMenloでした。
この違いだけでめちゃくちゃ時間を無駄にしてしまったので、同じ失敗をしないように気をつけてください。

## 参考文献
[Firebase Crashlytics: Upload missing dSYMs to see crashes from 1 versions.(iOS)
](https://stackoverflow.com/questions/48296774/firebase-crashlytics-upload-missing-dsyms-to-see-crashes-from-1-versions-ios)
12. 電力スマートメータの情報をNode.jsで取得するライブラリ

電力スマートメータとの通信をする機能が単体で利用できるものを，npmライブラリを開発・公開したので使い方を説明します。

## パッケージ情報
https://www.npmjs.com/package/e-smartmeter-echonet-lite?activeTab=readme

基本的な使い方はこのREADMEに書いてありますが，一応こちらでも記事にしてみます。

## 事前準備

1. **Bルート認証ID設定とBルート認証パスワード設定の準備：**
お住まいの管轄の電力会社に連絡して**Bルート認証ID設定とBルート認証パスワード設定**をもらってください。
小口契約（ドコモ電気とかそういうやつ）ではなく，最終的な電力会社（東京電力とか，そういう日本に11社くらいある大きいところ）です。電力メータの管理者にあたります。
そこそこ時間がかかります。
2. **Wi-SUNドングルの購入：**
スマートメータはWifiとかBluetoothとかではなくて，Wi-SUNという電波規格で通信します。普通のパソコンにはこの機能がないので，USBタイプのドングルを購入しましょう。このライブラリでは下記の2種類のデバイスでテストしているので，好きなほうを購入して使ってください。

- TESSERA RL7023
(https://www.tessera.co.jp/rl7023stick-d_ips.html)
- ROHM BP35C2
(https://www.rohm.co.jp/products/wireless-communication/specified-low-power-radio-modules/bp35c2-product#productDetail)

(なお，このメーカー様と私は一切関わりがありません。デバイスに関する技術的な事の質疑は出来ませんし，これを使用したことによる責任や保証は私にはできません。また，私の記事やライブラリの利用についてメーカー様に質問しても何もご回答いただけないと思われます。常識と思いますが，一応。)

## インストール方法

このコマンドでインストールします。

```bash
npm i e-smartmeter-echonet-lite
```

## サンプルプログラム

```javascript:app.js
//////////////////////////////////////////////////////////////////////
let eSM = require('e-smartmeter-echonet-lite');


////////////////////////////////////////////////////////////////////////////
// config
let config = {
  donglePass: 'COM3',  // ドングルのシリアルポート
  dongleType: 'ROHM',  // 'ROHM' or 'TESSERA'，使ったメーカー
  id:'01234567890QWERTYUIOPASDFGHJKLZX',   // Bルート認証ID設定, Your B route ID.
  password:'123456789ABC',   // Bルート認証パスワード設定, Your B route password.
  observationEPCs: ['80','81','82','88','8A','8D','97','98','9D','9E','9F',
                    'D3','D7','E0','E1','E2','E3','E4','E5','E7','E8','EA','EB','EC','ED']
}

// 初回起動のみ実施するためのフラグ, flag for first connection
let connected = false;

// 初期化, initializing
eSM.initialize( config, ( sm, rinfo, els, err) => {
	try{
		// 初回接続時, first connection
		if( !connected && sm.state == 'available' ) {
			connected = true;
			// config.observationEPCsのEPCを定期的にGetする
			eSM.startObservation( 60 * 1000 );
		}
	}catch(e){
		console.error(e);
	}
});


// 機器情報の変化の監視, observation for changing facilities
eSM.setObserveFacilities( 3 * 60 * 1000, () => {
	console.log( '## == onChanged', (new Date()).toLocaleString(), '== ##' );
	console.dir( eSM.facilities );
	console.log( '## ============= ##' );
});
```

## プログラム解説

この行で，スマートメータ通信ライブラリを使うことを宣言します。

```javascript:宣言部分
let eSM = require('e-smartmeter-echonet-lite');
```

このconfig変数に，ユーザ毎の設定をしましょう。

```javascript:ユーザ設定部分
let config = { ... }
```

この関数で，初期化，通信開始，受信したときの処理を書きます。

```javascript:初期化，通信開始，受信データの処理
eSM.initialize( ... );
```

上の関数のところで，通信成功（初めての受信成功）したら定期的な監視をする設定をしています。
何をしてるかというと，60秒毎に**observationEPCs**に設定したEPCに対してgetし続けるという設定です。**スマートメータへのポーリング設定**です。

```javascript:定期的な監視（スマメのポーリング）
eSM.startObservation( 60 * 1000 );
```

もう一つ，定期的な監視の設定をしています。ライブラリ内部でスマートメータの全体情報を常に保持しているのでその変化を3分毎に監視しています。

```javascript:定期的な状態監視（ライブラリ内部データのポーリング）
eSM.setObserveFacilities( ... );
```
Unity Input System VRコントローラーを使う


# 環境
os : windows10pro
unity : 2020.3.21f1
VR : OculusQuest2

# コントローラー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555658/95891ddd-464f-1f54-c6d2-446906833d9f.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555658/079968f0-63ba-e480-e781-aa76f4902e51.png)
参考）https://jmpelletier.com/ja/unity%E3%81%AE%E6%96%B0%E3%81%97%E3%81%84input-system%E3%81%A7oculus%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B/

# 手順
１)InputSystemのインストール
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555658/6c0f5cf0-9f2e-e828-98d2-7229ab3102e4.png)

2) PlayerSetting - Other Setting
[Other Settings]-[Configuration]-[Api Compatibility Level]をNET4

[Other Settings]-[Configuration]-[Active Input Handling]をBothにする。

Unity再起動を行う。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555658/0cdd5f0c-9926-0bc5-7294-49aa660c27ff.png)

3) PlayerSetting- XR Plug-in Management
インストールしてOculusにチェックを入れる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555658/80e67270-a6ce-3c1d-221d-465a45e5da70.png)

4）Input Actionsの作成
Input Actionsを作成して、開く。<font color="DeepPink">名前は”DefaultAction”とする</font>


<img width="50%" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555658/6a730366-d8e1-6aed-4bd7-d1034f95c7af.png">

左からActionMaps,Actions,Propertiesを作成、選択をする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555658/f2f53b87-dffe-96df-83e7-b4df87ada912.png)

5. アクションを受ける側を作る。Cube
Cubeを作成して、PlayerInputアタッチする。
PlayerInputから、DefalutActionを選択する。

6. アクションを受けとるスクリプトを作成

上記で、ActionsのインスタンスDropを作成したので、受信するハンドラはOnDrop()となる。これをCUBEにアタッチする。

```
public class ObjectDrop : MonoBehaviour {

    // ここにアクションに反応するメソッドを書きます。
    void OnDrop()
    {
        gameObject.AddComponent<Rigidbody>();
    }
}

```

7.実行
実行して、コントローラーの当該ボタンを押すとCUBEが落下する。
変化ないならキーボードの”A”を押す。落ちる場合はVR系の設定が漏れているので確認を行う。
自キ活をまとめる

この記事は
>キーボード #2 Advent Calendar 2021（Adventar）
https://adventar.org/calendars/6280

12/23、23日目の記事です

年間のまとめになります

#1~3月
前バイトで心をすり減らしながらもフランケンをいろいろいじる
GMK NoelのExtraを待つも、完全にタイミングしくじってしまい、逃す　絶望
GBに参加しなかったことを悔やみながら、NP PBT Blankを染める

IKKI68 Aurora mizuに参加する
Brass Weightを買い忘れ、PnCでも忘れる
Extraは忘れないようにしないと

#4~6月
専門学校へ上がり、時間的、金銭的余裕ができる
バイト先が変わり、肉体的苦痛が一気に減少
バイト先のおかげでさらに自キに溺れるようになる
キースイッチいじいじ
追いTOFU

#7~9月
NoelにサイレントなExtraが来たので買った
<blockquote class="twitter-tweet" data-width="300" data-cards="hidden"><p lang="ja" dir="ltr">キタキタキタキタキタキタキタキタ<br>ExtraのNoel来た<br>thx <a href="https://twitter.com/yushakobo?ref_src=twsrc%5Etfw">@yushakobo</a> <a href="https://t.co/33zAkl3Nhn">pic.twitter.com/33zAkl3Nhn</a></p>&mdash; LaPh (@checkLa1n) <a href="https://twitter.com/checkLa1n/status/1426421299010621446?ref_src=twsrc%5Etfw">August 14, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


https://twitter.com/checkLa1n/status/1427300036124176385

こんなことを言っていた
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Equinoxほしいけど、3U×2か7Uしか選択肢ないのでgg</p>&mdash; LaPh (@checkLa1n) <a href="https://twitter.com/checkLa1n/status/1427459908518088706?ref_src=twsrc%5Etfw">August 17, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
が、結局買っている()
この時Thera75のGBもあり、どちらもプレートレスなガスケットだったので迷っていた
なんでよりによって50% or 75%の選択肢しかないのだろうか

サリチル酸のBezelケース(試作のマットブラック めちゃくちゃ貴重なので大切にしたい)...を買いました
ちょうど遊舎工房にてMekanisk Fjellの販売があって迷っていましたが、汎用性と価格を考えてコチラになりました
2kgの重キボボうれしいですね

現在は弟の手にわたり、大事に使ってもらってます
そのうちPoker互換なPCB設計したときにでも使うと思います

#10~12月
設計を進めていますが、絶望的なまでにセンスがなく、発注する手前でいつもあきらめてます
果てにはなぜか自分の苦手なレイアウトのキーボードまで作ろうとしてますし
[Bakenko60](https://mazurka.booth.pm/items/3205645)を注文しました
通常のガスケットマウントには若干の飽きが来ていたのと、以前からOTD356 miniが気になっていたのもあり、物欲が極めていたので買ってしまった
ハーフプレートも注文しようと思ったのですが、こちらはBakeneko60の設計者さんがハーフプレートのdxfデータを持っていたので、お借りして真鍮で発注しようと思っています

これを書いている11/14もIKKI68 Aurora R2も来ていて物欲が刺激されます
泣きたい　おそらくNavyに突っ込むと思います(苦学生に何たる仕打ち)
R1のMizuに乗せ換えようとしていて、アドオンに突っ込んだんですが、普通にもう1つ買ったほうがマシレベルだったので諦めます
BERTについての簡単な解説と使い方

# 概要
BERTについての簡単な解説と、実装方法をまとめてみました。
解説については、簡単な概要と入出力のみ説明します。もっと良く知りたい方は、元の論文や他の記事を参考にしてください。
論文：https://arxiv.org/abs/1810.04805

# BERTの解説
### 概要
BERT(Bidirectional Encoder Representations from Transformers)とは何か。
簡単に述べると、自然言語処理の分野で使われるもので、入力として与えられた文を機械学習しやすい形に変換してくれるものです（こういったものを**Encoder**と言います）。

機械学習を行うためには、どのようなタスクであろうとモデルのへの入力は数値ベクトルでなければなりません。この役割をBERTが担ってくれるわけです。

文を数値ベクトルに変換してくれるものにはDoc2Vecなど他のモデルもありますが、BERTは今のところ最も優れたEncoderだと言われています。
また、Doc2Vecは同じ入力であれば同じベクトルを出力するのに対し、BERTは使うデータやタスクに応じて**ファインチューニング**というパラメーター調整を行うことで自分だけのEncoderに変えることができます。

### 入出力
![スクリーンショット 2021-11-16 14.04.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2090368/0dc33835-af7b-60b2-e90c-c3c6afff3ed6.png)
この図は、論文に載ってる図です。
BERTモデル自体としては[CLS], Tok1, ..., TokNが入力となりますが、これらのトークンを作成するために、元の文をトークン化する処理が必要となります。
また、[SEP]というトークンを挿入することで、2つの文を入力とすることもできます。

出力は、入力トークンと同じ数のトークンとなります。[CLS]に対応する出力Cは入力した文全体の情報を持っていると考えられており、文の分類タスクなどで使うことができます。

# 実装
BERTを使う方法を紹介します。PyTorch自体の使い方などはここでは紹介しません。

### 作業環境
|項目|バージョン等|
|--|--|
|OS|mac Mojave|
|python|3.8.2|
|pyenv|1.2.26|
|transformers|4.12.2|

### 必要ライブラリのインストール
```
pip install transformers[ja]
```
これで今回必要なライブラリをインストールできます。

### ソースコード
```
#必要ライブラリのインポート
from transformers import BertJapaneseTokenizer, BertModel

#入力する文
INPUT = "我輩は猫である。"

#事前学習済みモデルの選択
pretrained = 'cl-tohoku/bert-base-japanese-whole-word-masking'
tokenizer = BertJapaneseTokenizer.from_pretrained(pretrained)
bert = BertModel.from_pretrained(pretrained)

#入力文のトークン化
input_token = tokenizer.encode_plus(
    INPUT,
    add_special_tokens = True,
    truncation = True,
    padding = "max_length",
    return_tensors = "pt"
    )
ids = input_token["input_ids"]
mask = input_token["attention_mask"]

#トークンをBERTに通した結果
output = bert(ids, mask)

print(output)
```

出力↓

```
BaseModelOutputWithPoolingAndCrossAttentions(last_hidden_state=tensor([[[-0.3607,  0.1658,  0.0195,  ..., -0.1120, -0.3533,  0.0227],
         [ 0.8294,  0.4226,  0.4477,  ..., -0.6203, -0.4340, -0.4595],
         [ 0.2881,  0.4584, -0.1200,  ..., -0.4955,  0.2524, -0.5762],
         ...,
         [-0.0026,  0.1373,  0.2016,  ..., -0.3130, -0.1559, -0.2415],
         [-0.0509,  0.4031,  0.0790,  ..., -0.2865, -0.1257, -0.2302],
         [-0.0594,  0.1091, -0.0197,  ..., -0.2351, -0.1172, -0.2040]]],
       grad_fn=<NativeLayerNormBackward0>), pooler_output=tensor([[ 8.3770e-01,  9.5697e-02, -2.9548e-01, -3.1350e-01,  4.1436e-01,
（略）
```
こんな感じで出力は辞書型で出てきます。
last_hidden_stateは上で述べた出力トークン全ての情報を、pooler_outputは出力トークンのうちCの情報を持っています。

また、次のように書くことで辞書型ではなく、タプルで返すこともできます。

```
bert = BertModel.from_pretrained(pretrained)
↓
bert = BertModel.from_pretrained(pretrained, return_dict=False)


output = bert(ids, mask)
↓
last_hidden_state, pooler_output = bert(ids, mask)
```
macの買い替えとともにgoの再インストール

## SHELLの確認
macOSがCatalina以後はデフォルトシェルが「zsh」に変わる

Catalina以前

```
$ echo $SHELL
/bin/bash
```

Catalina以後

```
$ echo $SHELL
/bin/zsh
```

## [goenv/INSTALL.md](https://github.com/syndbg/goenv/blob/master/INSTALL.md)の手順通りにコマンド実行

```
$ git clone https://github.com/syndbg/goenv.git ~/.goenv
```


## ~/.zshrcに追記

vi　とかで適当に開いて下記を追記

```
export GOENV_ROOT=$HOME/.goenv
export PATH=$GOENV_ROOT/bin:$PATH
eval "$(goenv init -)"
```

## インストール出来るGoのバージョンを確認

```
$ goenv install -l
Available versions:
  1.2.2
  1.3.0
  1.3.1
  1.3.2
  1.3.3
  1.4.0
  1.4.1
  1.4.2
  1.4.3
  1.5.0
  1.5.1
  1.5.2
  1.5.3
  1.5.4
  1.6.0
  1.6.1
  1.6.2
  1.6.3
  1.6.4
  1.7.0
  1.7.1
  1.7.3
  1.7.4
  1.7.5
  1.8.0
  1.8.1
  1.8.3
  1.8.4
  1.8.5
  1.8.7
  1.9.0
  1.9.1
  1.9.2
  1.9.3
  1.9.4
  1.9.5
  1.9.6
  1.9.7
  1.10.0
  1.10beta2
  1.10rc1
  1.10rc2
  1.10.1
  1.10.2
  1.10.3
  1.10.4
  1.10.5
  1.10.6
  1.10.7
  1.10.8
  1.11.0
  1.11beta2
  1.11beta3
  1.11rc1
  1.11rc2
  1.11.1
  1.11.2
  1.11.3
  1.11.4
  1.11.5
  1.11.6
  1.11.7
  1.11.8
  1.11.9
  1.11.10
  1.11.11
  1.11.12
  1.11.13
  1.12.0
  1.12beta1
  1.12beta2
  1.12rc1
  1.12.1
  1.12.2
  1.12.3
  1.12.4
  1.12.5
  1.12.6
  1.12.7
  1.12.8
  1.12.9
  1.12.10
  1.12.11
  1.12.12
  1.12.13
  1.12.14
  1.12.15
  1.12.16
  1.12.17
  1.13.0
  1.13beta1
  1.13rc1
  1.13rc2
  1.13.1
  1.13.2
  1.13.3
  1.13.4
  1.13.5
  1.13.6
  1.13.7
  1.13.8
  1.13.9
  1.13.10
  1.13.11
  1.13.12
  1.13.13
  1.13.14
  1.13.15
  1.14.0
  1.14beta1
  1.14rc1
  1.14.1
  1.14.2
  1.14.3
  1.14.4
  1.14.5
  1.14.6
  1.14.7
  1.14.8
  1.14.9
  1.14.10
  1.14.11
  1.14.12
  1.14.13
  1.14.14
  1.14.15
  1.15.0
  1.15beta1
  1.15rc2
  1.15.1
  1.15.2
  1.15.3
  1.15.4
  1.15.5
  1.15.6
  1.15.7
  1.15.8
  1.15.9
  1.15.10
  1.15.11
  1.15.12
  1.15.13
  1.15.14
  1.15.15
  1.16.0
  1.16beta1
  1.16.1
  1.16.2
  1.16.3
  1.16.4
  1.16.5
  1.16.6
  1.16.7
  1.16.8
  1.16.9
  1.16.10
  1.17.0
  1.17beta1
  1.17rc1
  1.17rc2
  1.17.1
  1.17.2
  1.17.3
```

## あとは自分の開発する環境にあったバージョンをインストール

```
$ goenv install 1.16.10
```

## ワークスペース作成

```
$ mkdir -p $HOME/go/{bin,src}
```

~/.zshrc に追記
```
export GOPATH=$HOME/go
PATH=$PATH:$GOPATH/bin
```

反映

```
$ source ~/.zshrc
```
【Keras】エラー AttributeError: module 'tensorflow.compat.v2' has no attribute '__internal__'について

2021年の9月10月あたりからタイトルのエラーをよく見るようになった。
というのもインストールしているKerasとtensorflowのバージョンが食い違っているのが問題なのだが
バージョン指定をしてインストールしてもエラーが出てしまっているようだ。

備忘録も兼ねて以下に記していく。

# 発生箇所
今回エラーが起きている環境では本来以下のバージョンのライブラリを利用する。

* Tensorflow:1.14.0
* Keras:2.3.1

また細かい環境としては以下のとおりである。 

* windows10
* python3.7.3

ライブラリはコマンドプロンプトでpipコマンドを使ってインストールしている。

~~~
ex) pip install tensorflow==1.14.0
ex) pip install keras==2.3.1
~~~

原因としてはtensorflowが1.x環境、kerasが2.4以上?のバージョンがインストールされていると
誘発してしまうエラーのようだ。
特筆すべきはtensorflowをインストールすると自動でkerasの最新バージョン(現在は2.7)がインストールされてしまうようで
その後にインストールしているkeras==2.3.1が無効化されてしまっているようでプログラムを実行した際にエラーが発生してしまっている。

またこの時に[別記事](https://qiita.com/Hiroki-Fujimoto/items/b078bfb680fb710c38c1)で取り上げたh5pyモジュールも最新バージョンがインストールされてしまうので注意が必要である。

# 対処

簡単な対処方法としてはtensorflowをインストールした後に、kerasを一度アンインストールして
再度バージョン指定をしてkerasをインストールするのが確実である。

コマンドでのインストール
(以下ではpipを用いているが環境によってコマンドは変更する)

~~~
# まずはtensorflow,kerasのバージョンを確認
pip list

# アンインストール
pip uninstall keras

# バージョン指定をして再インストール
pip install kerass==2.3.1
~~~

tensorflowとkerasのインストール順を変えても発生するようなので
上記の手順で確実にインストールするのが早いだろう。

### 参考
以下の内容で利用していたところエラーに遭遇した。
https://afrel-shop.com/shopdetail/000000000528/ct249/page1/recommend/
https://ai.afrel.co.jp/tensor-spike/
Kubernetesで特定のnamespaceにあるPodsが全てreadyになるまで待つ方法

シェルスクリプトなどで待つ必要があったり、全部完了するまで待って通知を出したい時などに使えます。

```bash
kubectl wait --for=condition=ready --all pods -n {ご所望のnamespace}
```
ネットワーク構築課題〜リンクアグリゲーション〜

## 課題

L2SWを2つ用意してリンクアグリゲーションを構築する
VLAN100と200を作成して、それぞれのスイッチに配置する
クライアント端末を4台用意して、各L2SWのVLANに接続する

## 回答

```
●L2SW-01
enable
conf t
hostname L2SW-01
vlan 100
vlan 200
exit
interface range fa0/23-24
channel-group 1 mode active
exit
interface po1
switchport mode trunk
switchport trunk allowed vlan 100,200
exit
interface fa0/1
switchport access vlan 100
exit
interface fa0/2
switchport access vlan 200 

●L2SW-02
enable
conf t
hostname L2SW-02
vlan 100
vlan 200
exit
interface range fa0/23-24
channel-group 1 mode active
exit
interface po1
switchport mode trunk
switchport trunk allowed vlan 100,200
exit
interface fa0/1
switchport access vlan 100
exit
interface fa0/2
switchport access vlan 200 
```

## ポイント
一つの論理ポートに2つのVLANを接続するため、Trunkモードで設定をすること

## 苦労した点
show vlanで確認しようとしたが、確認できなかった
Trunkモードなので

```
show interfaces ポート番号 switchport
```

で確認する必要がある
【slack】incoming webhookの通知が「このコンテンツは表示できません。」になるときのTips

# 経緯

社内のチャットツールがchatworkからslackに移行するにあたり、
来客の受付を電話ではなく、slackの通知で受けられないか、と上司から相談があった。
incoming webhookで実装できそうだったので対応を進めたが、
メッセージを送るところまでは容易に実装出来るものの、通知が以下のようになった。

![スクリーンショット 2021-11-15 16.47.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54392/dd2e7c92-cf4d-914c-1acd-e8cb3c8e7795.png)

とりあえず通知は出来るので、~~臭いものにフタをした~~優先度を下げていたのだが、
いよいよお披露目目前となり、さすがに対処しよう、と重い腰をやっと上げた。

# 原因

当初、メッセージのpayload内にblocksだけを含んだ状態でPOSTしていた。
これが良くなかった。以下payloadを定義した部分。

```javascript
const payload = {
      blocks: [
        {
          type: 'section',
          text: {
            type: 'mrkdwn',
            text: '<!channel>',
          },
        },
        {
          type: 'context',
          elements: [
            {
              type: 'image',
              image_url:
                'https://a.slack-edge.com/production-standard-emoji-assets/13.0/apple-medium/1f481-200d-2642-fe0f@2x.png',
              alt_text: 'reception',
            },
            {
              type: 'mrkdwn',
              text: '*エントランスにお客様がいらっしゃっています。*',
            },
          ],
        },
    }
```

# 結論

blocksはメッセージの内容を定義しているだけで、通知メッセージは`text`をblocksに併記する必要があるようだ。
以下が修正したpayloadの定義部分。

```javascript
const payload = {
      text: ':man-tipping-hand:エントランスにお客様がいらっしゃっています。',
      blocks: [
        {
          type: 'section',
          text: {
            type: 'mrkdwn',
            text: '<!channel>',
          },
        },
        {
          type: 'context',
          elements: [
            {
              type: 'image',
              image_url:
                'https://a.slack-edge.com/production-standard-emoji-assets/13.0/apple-medium/1f481-200d-2642-fe0f@2x.png',
              alt_text: 'reception',
            },
            {
              type: 'mrkdwn',
              text: '*エントランスにお客様がいらっしゃっています。*',
            },
          ],
        },
      ],
    }
```

結果、無事に通知にもメッセージが表示されるようになった。
![スクリーンショット 2021-11-16 14.43.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54392/e03589bc-4aea-2311-6653-af1c788b7aa4.png)

## 参考URL

- https://api.slack.com/reference/messaging/payload
    - 上記リファレンスのtextの説明にも、blocksがあればそれが本文、textが通知欄のテキストになる、とある。一次情報とても大事。