OmniAICreator/Qiita-1.07M huggingface dataset:
Zoomのミーティング入退出のwebhookをLambdaで受け取るAPIの下調べをした (1)

会社のハッカソンでZoomのAPIを使ったサービスを作ろうとしているので、その下調べを行った。

# Zoom API 認証

使えそうなものとして、JWT トークンか OAuth 2.0 が用意されている。
すぐに使えるJWTトークンは画面に表示されるものを使った。

会社のco.jp ドメインで登録されているzoomユーザーは、会社アカウント配下にあり、その場でJWTトークンを取得することができなかった（appの作成権限がなかった）ため、別途個人のGmailでユーザーを作って appを作成し、JWTトークンを入手している。


# Webhook のURLを用意する

お手軽に API Gateway ＋ Lambda のAPIを作る事ができるフレームワークである **Chalice** を選択した。手間のかかる権限周りの設定もAPI Gatewayの設定もほとんど意識することなく、関数を書いて deployコマンド一発で諸々をデプロイしてくれるのでとてもお手軽です。

Chalice
https://github.com/aws/chalice

デプロイされたら、REST API URL が表示されるので、zoom のapp管理画面から `Event notification endpoint URL` に登録します。
登録するのは REST API URL + 関数名 なので、こんな具合になりました。
`https://xxxxxxx.execute-api.ap-northeast-1.amazonaws.com/api/webhook`

zoomでは非常に多くのwebhookイベントを用意しているので、受け取りたいイベントにチェックを入れておきます。


# Postman でAPIの確認

webhookのURLが生きているか？をさっと確認しておきます。GETメソッドではすぐにレスポンスが返ってきたのですが、webhookはPOSTメソッドでアクセスされます。Chalice側でPOSTメソッドを受け取る指定をしておく必要があります。

```app.py
@app.route('/webhook', methods=['POST'])
def webhook():
    print('received event:')
    request = app.current_request
    app.log.debug(json.dumps(request.to_dict()));
    app.log.debug(json.dumps(request.json_body))
```


```sh
# デプロイ
chalice deploy --profile xxxxx

# ログを待ち受ける
chalice logs -f --profile xxxxx
```

こんなふうにログを待ち受けていて、Postman でリクエストを投げてみます。
2-3秒ほどで、ターミナルにログが流れてきました。

この時点で、zoomのミーティングを開始・終了 などを行うと、実際のwebhookを受け取ってログを出力できることもわかりました。postman同様に、2-3秒ほどでログが流れてくることから、ほぼ遅延無しで通知されているものと考えています。


次回は受け取った情報をもとにZoom APIを実行してみます。
SSHの第2要素にTOTPかYubico OTPを利用する

[家のサーバにTOTPでログインできるようにする](https://qiita.com/zunda/items/326f4084efda177a22d1)と、当然次はYubico OTPを利用して、YubiKeyをポチっと触るだけでログインできるようにしたくなります。`git push`するたびに6桁の数字を確認するのはちょっとたいへん。TOTPの前にYubico OTPを試すように設定してみました。

Ubuntu 18.04 LTSのserver版での作業記録です。作業前には、sshdでは公開鍵認証に加えて外からの接続ではTOTPを要求していました。外からは家庭用ルータのポート転送で接続されます。

## YubiKeyの用意
[YubiKey](https://www.yubico.com/products/)は[Yubico社](https://www.yubico.com/)のハードウェア認証デバイスで、種々の認証プロトコルに対応しています。今回はYubico OTPを利用します。この記事では、2020年7月に購入した[YubiKey 5 NFC](https://www.yubico.com/product/yubikey-5-nfc)を利用しています。この多くのモデルでYubico OTPを利用できますが、Yubico OTPを利用できないモデルもあるので購入の際には確認してください。

![YubiKey5NFC.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105088/f04dcdc9-d785-fdaa-8917-fbaf0eb9d38b.jpeg)

ログイン先に`~/.yubico/authorized_yubikeys`ファイルを下記のような内容で作成します。YubiKeyをUSBポートに挿入してタップするとデフォルトでは`cccc`で始まるYubico OTPが入力されます。その最初の12文字でYubiKeyを識別するようです。複数のYubiKeyを利用する場合には同じ行に`:`(コロン)で区切って12文字を追記します。

```
<ログイン先ユーザーID>:<YubiKeyをタップした時に入力される文字列の最初の12文字>
```

## sshdの設定
### Yubico API Keyの取得
メールアドレスとYubiKeyをYubicoに登録してクライアントIDとシークレットキーをもらいます。今回使うのはクライアントIDのみです。

https://developers.yubico.com/yubico-pam/ で必要事項を記入して、利用規約に同意します。

### Yubico PAMのインストール
Yubico CloudにYubiKeyを検証してもらうため、[Yubico PAM module](https://developers.yubico.com/yubico-pam/)に従ってPAMをインストールします。

```sh
sudo add-apt-repository ppa:yubico/stable
sudo apt update
sudo apt install libpam-yubico
```

手元では、`libpam-yubico`に加えて`libykclient3`、`libykpers-1-1`、`libyubikey0`がインストールされました。

### PAMの設定
`/etc/pam.d/sshd`を編集し、sshdが

1. まず、Yubico OTPでの認証を試し
1. 次に、TOTPでの認証を試す

よう、`common-auth`の行をコメントアウトして無効にして、直下の行を下記のように編集します。編集後のsshdの再起動は不要です。

```
#@include common-auth
auth       sufficient   pam_yubico.so id=<上記で取得したクライアントID>
auth       sufficient   pam_google_authenticator.so
```

`/etc/ssh/sshd_config`の内容はTOTPのみを有効にしていた時と同様、sshdが公開鍵に加えてPAM経由での認証を要求するよう、そして、ローカルなネットワーク(ここでは`192.168.0.0/16`)あるいはcronで利用するアカウント(ここでは`automation`と`backup`)への接続では公開鍵での認証で充分なようにしておきます。このファイルを編集した場合にはsshdの再起動が必要です。

```
ChallengeResponseAuthentication yes
AuthenticationMethods publickey,keyboard-interactive
Match Address 192.168.0.0/16,::1
       AuthenticationMethods publickey
Match User automation,backup
       AuthenticationMethods publickey
Match all
```

# ログインを試す
この状態でsshするとSSH鍵対での認証が成功してから、Yubikeyのタップを促されます:

```
Authenticated with partial success.
YubiKey for `<ログイン先ユーザーID>':
```

手元にYubiKeyが無い場合にはEnterを押すとTOTPを入力できるようになります:

```
Verification vode:
```
Reactの状態管理はReduxの独走状態、2位は大きく離れてswrとreact-queryが競り合い中・・

2021/09/24 追記
これまでは状態管理にReduxやVuexなどの状態管理用ライブラリを使いますが、Graphqlを採用した場合にApollo Clientを利用することでフロントエンドの状態管理の実装がかなり楽になります。

追記終了

2021/01/17 追記

2020年版
満足度ランキング
State of JS 2020: JavaScript Flavors
https://2020.stateofjs.com/

最近よく聞く状態管理
pmndrs/jotai: 👻 Primitive, flexible state management for React
https://github.com/pmndrs/jotai

追記終了

2020/12/20 追記
npm trendsで調べたところ

recoil vs swr vs react query vs redux | npm trends
https://www.npmtrends.com/recoil-vs-swr-vs-react-query-vs-redux

recoil vs swr vs react query | npm trends
https://www.npmtrends.com/recoil-vs-swr-vs-react-query

reduxが圧倒しています2位は大きく離れてswrです。reduxは使い難いことは確かなのですが、この順位は当分維持される模様です。

React界隈ではNext.jsが注目されていてその付随技術？でVercelやswrが同じ会社で開発されているのでswrの注目度が高まっているようです。

検索トレンド
Redux, recoil, swr, react-query - 調べる - Google トレンド
https://trends.google.co.jp/trends/explore?q=Redux,recoil,swr,react-query

Google検索のトレンドではswrが多く検索されています。
3倍近く差が開いており、次の状態管理はswrが来るかもしれません。
（3文字なのでなにかの略語として調べられているかもしれませんし、逆にreact-queryはreactという単語がかぶっているので検索結果に出にくくなっているかもしれません。）

2019年版
The State of JavaScript 2019
https://2019.stateofjs.com/

発表時期
Reduxは2015年の5月頃
swr, react-queryは発表が2019年後半のほぼ同じ頃
それから半年して
Recoilは2020年の5月頃

2020/09/24 追記
Rewriting Facebook's "Recoil" React library from scratch in 100 lines
https://bennetthardwick.com/blog/recoil-js-clone-from-scratch-in-100-lines/

(8) Recoil: State Management for Today's React - Dave McCabe aka @mcc_abe at @ReactEurope 2020 - YouTube
https://www.youtube.com/watch?v=_ISAA_Jt9kI

追記終了

### Recoil

~~グーグルトレンドで遊んでいると、RecoilがReduxを抜いてトップに躍り出ていました、差は僅かですがこれは大きな出来事だと思います。~~

[Redux, recoil, mobx, useContext - 調べる - Google トレンド]
(https://trends.google.co.jp/trends/explore?q=Redux,recoil,mobx,useContext)

![Recoil Redux.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44761/c7f59c4d-2396-01a8-c76e-99ca44f455ea.png)

ただし、日本国内ではReduxが難攻不落の要塞となっています。

Recoilについては
[Reactの実験的ステート管理ライブラリRecoilの基本的な使い方]
(https://sbfl.net/blog/2020/05/17/react-experimental-recoil-usage/)
この記事がわかりやすかったです。

# State of Frontend 2020
State of Frontend 2020 Report | TSH.io
https://tsh.io/state-of-frontend/#future-of-frontend

### State of Frontend 2021?

>However, in the frontend development community, the line between love and hate is very thin. And probably the best proof of that is what happened to Redux. A year or two ago, when you were working with React, Redux was also “the obvious choice”. But frontend developers got tired of the problems caused by using Redux and quickly jumped on the React hooks bandwagon. It’s summer 2020, already more people use hooks than Redux (see: Chapter 2) and as much as 34% of frontend devs believe that Redux will be gone in 3 years from now.

### DeepL翻訳

しかし、フロントエンド開発コミュニティでは、愛と憎しみの境界線は非常に薄いものです。そして、おそらくその一番の証拠は、Reduxに起こったことです。1年か2年前、Reactを使っていた頃は、Reduxも「当たり前の選択」でした。しかし、フロントエンド開発者たちはReduxを使うことによる問題に飽きてしまい、すぐにReactフックのバンドワゴンに飛び乗ってしまいました。今は2020年の夏で、すでにReduxよりも多くの人がフックを使うようになり（参照：第2章）、フロントエンド開発者の34%もの人が、今から3年後にはReduxがなくなると考えています。
Power Systems Virtual Server on IBM Cloud (AIX) ：追加モジュールのインストールについて（インストール・メディア と パッチ[FIX]）

# はじめに

IBM Cloudでは、Power Virtual Server のサービスで AIX を利用することが可能です。
AIXは初期導入された状態で引き渡されますので、「日本語の言語セットをインストールメディアから追加導入したい」といった話や「FIXを適用したい」といった追加ファイルセットを導入する機会があると思います。

この記事では以下の3種類の手順についてガイドいたします。
　1. インストール・メディアからのファイルセットの追加導入
　2. AIXパッチ(FIX)の入手
　参考. AIXのインストールDVDのISOイメージの取得

AIXの初期設定や主要なコマンド群については、以下の記事などをご参照ください。
・[Power Systems Virtual Server on IBM Cloud (AIX) で最初にやること](https://qiita.com/khayama/items/0590ac2dc5748087699b)
・[IBM Cloud: Power Systems Virtual Server(AIX)でよく利用するコマンド](https://qiita.com/testnin2/items/f24c27aa6cbf4c1e77c0)

# 1. インストール・メディアからのファイルセットの追加導入

インストール・メディアからのファイルセットの追加導入ですが、払い出されたAIX上の<b>「/usr/sys/inst.image」</b> のディレクトリにインストール・メディアのファイルセットがございます。

Smittyの画面のインストール・フォルダで、このディレクトリを指定すればインストールすることが可能です。
日本語設定のsmit画面をのせております。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239309/586054c9-f15a-5703-b51a-ea175591a9a6.png)


"/usr/sys/inst.images"のディレクトリ構成はこんな感じになります。

```
# cd /usr/sys/inst.images
# ls
RPMS        emgr        installp    ismp        license     lost+found
# ls -l
合計 8
drwxr-xr--    4 root     system          256 Jan 28 2020  RPMS
drwxr-xr--    3 root     system          256 Jan 28 2020  emgr
drwxr-xr--    3 root     system          256 Jan 28 2020  installp
drwxr-xr--    3 root     system          256 Jan 28 2020  ismp
drwxr-xr--    2 root     system         4096 Jan 28 2020  license
drwxr-xr-x    2 root     system          256 Jan 28 2020  lost+found
# cd installp
# ls
ppc
# cd ppc
# ls  
.toc                                 bos.msg.EN_US
ICU4C.adt                            bos.msg.ES_ES
ICU4C.rte                            bos.msg.FR_FR
Java7_64.docs                        bos.msg.HU_HU
Java7_64.jclsource                   bos.msg.IT_IT
Java7_64.jre                         bos.msg.JA_JP
Java7_64.msg.Ja_JP                   bos.msg.Ja_JP
Java7_64.msg.Zh_CN                   bos.msg.KO_KR
・・・
```

# 2. AIXパッチ(FIX)の入手

オンプレと同様に、[FIX Central](https://www.ibm.com/support/fixcentral?productGroup0=ibm~systemp&productGroup1=ibm~aix)からダウンロードして利用いたします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239309/5753eb97-719e-6a5e-b9b4-0be8caf5faae.png)

FIXをダウンロードする際に、<b>「マシンタイプ」と「シリアル番号」</b>を聞かれますが、
AIX上から <b>lsconf コマンド</b> などにより確認することが可能です。

```
# lsconf
システム・モデル: IBM,9009-22A
マシンのシリアル番号: 78842F0
プロセッサー・タイプ: PowerPC_POWER9
プロセッサー実装モード: POWER 9
プロセッサー・バージョン: PV_9_Compat
プロセッサーの数: 1
プロセッサーのクロック速度: 2500 MHz
CPU タイプ: 64-bit
カーネル・タイプ: 64-bit
LPAR 情報: 8 powerwdc-b79b4415-00003164
メモリー・サイズ: 2048 MB
適正なメモリー・サイズ: 2048 MB
プラットフォームのファームウェア・レベル: VL940_041
ファームウェア・バージョン: IBM,FW940.02 (VL940_041)
コンソール・ログイン: enable
自動再スタート: true
フル・コア: false
NX 暗号アクセラレーション: Capable and Enabled
メモリー内暗号アクセラレーション: Capable, but not Enabled
・・・
```


# 参考. AIXのインストールDVDのISOイメージの取得

参考情報として、AIX インストール DVD の ISO イメージをダウンロードもすることも可能です。
ここにはマニュアル(IBM doc)のリンクのみ掲載いたします。
https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-using-ess-iso&lang=jp

なお、ISOイメージを導入するためには、[ライセンス付きソフトウェア・サポート (ESS) Web サイト](https://www.ibm.com/servers/eserver/ess/ProtectedServlet.wss)への登録が必要になります。


以上となります。
GAS 基本文法 備忘録③【スプレッドシート】

## 備忘録です。

[GoogleAppsScript 完全入門](https://www.amazon.co.jp/dp/B07BNB1Z9L/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1)で学んだことを備忘録としてまとめていきます。

- 自分が知っていることや、解説、今は必要ないなと思ったことは省いています。
- 解説などは自分が分かりやすい言葉で書いているので厳密に違うこともあるかもしれません。

## スプレッドシートに関する主なクラス

| クラス | 説明 |
|:-----------------:|:------------------:|
| SpreadsheetApp| Spreadsheetのグローバルオブジェクト|
| Spreadsheet|Spreadsheetを操作する機能を提供|
| Sheet|シートを操作する機能を提供|
| Range|セル範囲を操作する機能を提供|

<img width="986" alt="無題のスプレッドシート_-_Google_スプレッドシート.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/646383/86bb48cf-c2d7-915a-d6fe-0933209ef514.png">

## スプレッドシートの取得

### 同スプレッドシート内に複数のシートがある場合
一度Google Appにアクセスしてシートを取得する。

```javascript:例
// アクティブなスプレッドシートを取得
function myFunction() {
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  Logger.log(spreadsheet.getName());
}

// URLでスプレッドシートを取得
var url = 'https://xxxxxxxxxxxxxxxxxxxxxxxxxxxxx/edit#gid=0'
spreadsheet = SpreadsheetApp.openByUrl(url);
Logger.log(spreadsheet.getName());

// 他にidで取得する方法もある
```

<img width="469" alt="スクリーンショット 2020-08-06 8.50.24.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/646383/680caa1e-4145-a5ab-3215-f40f46b5ff11.png">

### スプレッドシートのシートが1つの場合

getActiveSheetメソッドを使用しシートを取得する。
Google Appへのアクセスは実行時間が遅くなる傾向なので、できるだけこちらの方法でシートの取得を行う。

```javascript:例
function myFunction() {
  var sheet = SpreadsheetApp.getActiveSheet();
  Logger.log(sheet.getName());
}
```

<img width="373" alt="スクリーンショット 2020-08-06 9.11.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/646383/70a2f239-31a8-3ae0-c9ec-ffa8d6b64fc2.png">


## セルの範囲を取得する
Sheetクラスのメンバーを使用する。

```javascript:構文
// A1とかA1:A5(アドレス)で指定
Sheetオブジェクト.getRange(アドレス)

// 行番号、列番号、行数、列数で細かく指定
Sheetオブジェクト.getRange(行番号, 列番号, 行数, 列数)

// データが存在するところを自動で取得
Sheetオブジェクト.getDataRange()
```

## セルの範囲を操作する

Rangeクラスのメンバーを使用する。
下記のようなことができる。メンバーはめちゃくちゃたくさんあるので使う時に調べる。

- セルの値を取得
- セルに値や数値を追加する
- 書式の設定
- 並び替え


## その他メモ

シート上のデータは配列でまとめて取得、入力するとスプレッドシートへのアクセス回数(実行時間)の削減が可能になる。
django-rest-frameworkでのリクエストメソッドの制御

## はじめに
django-rest-frameworkをつかってAPI構築する際のリクエストメソッド制御方法に関してのメモ

## 環境
Mac 10.15.5
Python 3.8.1
Django 3.0.7
djangorestframework 3.11.0

## コード
こちらの記事のコードを参考にさせて頂きました
※ GET, POST, PUT, DELETE に絞って書きます。
https://qiita.com/kimihiro_n/items/86e0a9e619720e57ecd8


## 継承するクラスにより制御
リクエストメソッドの許可をコントロールしているのは views.py で定義するクラスで継承する基底クラス。
以下のコードの viewsets.ModelViewSetの部分。
インポートしたrest_frameworkで用意されているものです。

```py:blog/views.py
import django_filters
from rest_framework import viewsets
from rest_framework import filters

from .models import User
from .models import Entry
from .serializer import UserSerializer
from .serializer import EntrySerializer


class UserViewSet(viewsets.ModelViewSet): # <- コレ
    queryset = User.objects.all()
    serializer_class = UserSerializer


class EntryViewSet(viewsets.ModelViewSet): # <- コレ
    queryset = Entry.objects.all()
    serializer_class = EntrySerializer
    filter_fields = ('author', 'status')
```

## viewsets.ModelViewSetの中身

rest_framework内にあるviewsets.py というファイルで定義されています。
ModelViewSet を継承すれば GET, POST, PUT, DELETE が利用可能となり、継承するクラスをReadOnlyModelViewSet に変更すれば GET のみに制御することができるといった感じです。

### GET, POST, PUT, DELETE が利用可能

```py:rest_framework/viewsets.py
class ModelViewSet(mixins.CreateModelMixin,
                   mixins.RetrieveModelMixin,
                   mixins.UpdateModelMixin,
                   mixins.DestroyModelMixin,
                   mixins.ListModelMixin,
                   GenericViewSet):
    """
    A viewset that provides default `create()`, `retrieve()`, `update()`,
    `partial_update()`, `destroy()` and `list()` actions.
    """
    pass
```

### GET のみ利用可能

```py:rest_framework/viewsets.py
class ReadOnlyModelViewSet(mixins.RetrieveModelMixin,
                           mixins.ListModelMixin,
                           GenericViewSet):
    """
    A viewset that provides default `list()` and `retrieve()` actions.
    """
    pass
```

## PUT, DELETEを使う場合のリソースの指定

PUT や DELETE を使う場合は場合はプライマリキーまで指定する必要がある。
`/api/users/` -> `/api/users/1/`

```sh:ダメ
$ curl -X PUT -d name=yamada -d mail=yamada@gmail.com localhost:8000/api/users/
```

```sh:OK
$ curl -X PUT -d name=yamada -d mail=yamada@gmail.com localhost:8000/api/users/1/
```

これは DjangoRestFramework が更新・削除するオブジェクトを認識する必要があるため。
リストビュー(`/api/users/`)では認識できない。
こんなエラーが返ってくるかと思います。

```
{"detail":"Method \"DELETE\" not allowed."}

{"detail":"メソッド \"DELETE\" は許されていません。"}
```


## 参考

https://www.django-rest-framework.org/api-guide/viewsets/

https://stackoverflow.com/questions/26711975/django-drf-405-method-not-allowed-on-delete-operation/26714561#26714561
docker runに失敗したコンテナにログインして、デバッグする方法


docker runが失敗したコンテナの中身を確認したい場合、```docker commit```で失敗したコンテナをイメージ化して、ログインします。

```
docker commit <コンテナID or コンテナ名> debug && docker run --rm -it debug sh
```

- docker runに失敗したコンテナのコンテナIDは、```docker ps -a```で調べられます。
- "debug" がコンテナイメージ名となります。不要になったら、```docker rmi debug```で消しましょう。
VisualforceでQRコード作成してみた


　LWCでQRコードリーダのコンポーネントを作成できること(Beta版)を知りました。
そちらを試す前にVisualforce上でQRコードを作成する機能を作ってみました。

[LWCの開発者ガイド(Scan Barcodes)](https://developer.salesforce.com/docs/component-library/documentation/en/lwc/lwc.use_barcodescanner)

# 成果物
![ダウンロード (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394418/a9938688-da36-163f-57d2-2d04c10abead.gif)


※表示しているレコードはDevEditionに初期保存されている取引先責任者のレコードです。

オブジェクトのアクションをVisualforceページで作成しております。
Visualforce内のJavaScriptで現在のURLのQRコードを生成しています。
(オブジェクト固有のLightning Actionにするために拡張コントローラを指定していますが、コントローラ側では特に処理を行っていません。)
このページでは取引先責任者のレコードページのURLのQRコードを表示しています。

```CreateQRcode.vfp
<apex:page standardcontroller="Contact" extensions="CreateQRcodeController" docType="html-5.0" standardStylesheets="false"
  showheader="false" sidebar="false">
  <apex:includeScript value="https://code.jquery.com/jquery-3.4.1.min.js" />
  <apex:includeScript value="http://jeromeetienne.github.io/jquery-qrcode/src/jquery.qrcode.js" />
  <apex:includeScript value="http://jeromeetienne.github.io/jquery-qrcode/src/qrcode.js" />

  <h1>Create QR Code</h1>
  <div id="qrcode"></div>
  <script>

    $('#qrcode').qrcode(location.href);
  </script>
</apex:page>
```

　Visualforceで行いましたが、AuraでもLWCでも同様の機能を作成できると思います。
また、本番組織での実装の際は、jQueryのファイルを静的リソースにアップロードする方が良いと思われます。

# まとめ
　今回はVisualforceでQRコードを表示するだけの機能を作成しました。余裕があれば、AuraやLWCでの表示や、作成したQRコードを画像ファイルとしてレコードの添付ファイルに保存する機能を作成してみたいと思います。
Ambassadorのログの見方

毎回忘れちゃってリンク探すのに時間がかかるのでリンクを転機。
このサイト以上に特に説明することなし

https://blog.getambassador.io/understanding-envoy-proxy-and-ambassador-http-access-logs-fee7802a2ec5

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75573/c4bcd179-4cd6-5d2d-5afa-5b8582169a22.png)
JIRAのOpenプロジェクトをGoogle spreadsheetに自動転記する

# 社外 vs 社内のプロジェクト管理環境差をどうするか問題
クライアント側ではJIRAを使って管理をしているのですが、社内ではBacklogを使っています。これには幾つかの理由が絡み合っています。

- 案件に紐づけて売上金額やクライアントには見せたくないコメント（あいつクソ）等も一緒に管理したい
- プロジェクトにかかわるすべての人のJIRAアカウントは発行してくれない
- グローバルクライアントで全部英語（社内全員がスムーズに英語でJIRAでガツガツやれるわけではない）
- JIRAも本社のリージョンにあるせいなのかクソ重くて使い物にならない

なのでやっぱり表のようなものにJIRAの内容をまんま転記するのが漏れやミスもなくてよいのかと思い試してみました。

# やったこと
- JIRAのRest APIでOpenプロジェクトの取得
- 整形
- Google Spreadsheetに転記

いちおう重たい重たいJIRAで検索してコピペする、みたいな不毛な作業はなくなりました。
細かい運用改善はこれからです。

# 実装


```python:jira.py
import base64
import requests
from google.colab import files
import pandas as pd
from google.colab import auth
auth.authenticate_user()
import gspread
import gspread_dataframe as gs_df
from oauth2client.client import GoogleCredentials

gc = gspread.authorize(GoogleCredentials.get_application_default())

# Speradsheetファイル名を指定してシートを開く
worksheet = gc.open('ファイル名').worksheet('シート名')

base_url = 'https://jira.yourjira.com/'
authstr  = 'yourID:yourPW'
authkey  = base64.encodebytes(authstr.encode('utf-8')).decode('ascii')
auth_header = {'Content-Type':'application/json', 'Authorization':'Basic ' + repr(authkey)}

#トータル件数を見る
searchUrl=base_url+'/rest/api/2/search?jql=project+yourproject+AND+resolution+%3D+Unresolved'
result =requests.get(searchUrl, headers=auth_header)
result =result.json()
total=str(result['total'])
print('トータル案件数:'+total+'件')

#取得内容(Fields)を指定して全件取得
searchUrl=base_url+'/rest/api/2/search?maxResults='+total+'&fields=issuetype,summary,assignee&jql=project+%3D+yourproject+AND+resolution+%3D+Unresolved+ORDER+BY+updated+DESC'
result =requests.get(searchUrl, headers=auth_header)
result =result.json()
issues=result['issues']

#出力
with open('example.csv', 'w') as f:
  f.write("Type,URL,Summary,Assignee,Reporter,Duedate,Updated\n")
  for issue in issues:
    if issue['fields']['assignee'] is None:
      assignee=""
    else:
      assignee=issue['fields']['assignee']['displayName']
    if issue['fields']['duedate'] is None:
      duedate=""
    else:
      duedate=issue['fields']['duedate']
    f.write(issue['fields']['issuetype']['name']+',https://jira.yourjira.com/browse/'+issue['key']+',"'+issue['fields']['summary']+'",'+assignee+','+issue['fields']['reporter']['displayName']+','+duedate+','+issue['fields']['updated']+'\n')

#CSVで落とす場合
#files.download('example.csv')

#スプレッドシートに書き出す場合
df = pd.read_csv('example.csv')
gs_df.set_with_dataframe(worksheet, df)
```

できました。
<img width="350" alt="2020-08-06_08h44_51.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216609/690ae327-dab8-0f18-cf7b-7e5934a1ac52.png">

#まとめ
JIRAはページ開いて検索するよりAPIの方が速いですね。ページ読み込み・表示で何秒もかかるイラつきを押さえる観点でもよかったかもです。
Docker Vue Go 


##Docker

###Dockerマウントできないよ〜

```

ERROR: for nginx  Cannot start service nginx: OCI runtime create failed: container_linux.go:349: starting container process caused "process_linux.go:449: container init caused \"rootfs_linux.go:58: mounting \\\"/Users/ishidashogo/practice/goPractice/etc/nginx/nginx.conf\\\" to rootfs 
\\\"/var/lib/docker/overlay2/ac829670cc63c6bd9749802860c0b6dd9619d56f1883525650acc81db4dc4ee1/merged\\\" at \\\"/var/lib/docker/overlay2/ac829670cc63c6bd9749802860c0b6dd9619d56f1883525650acc81db4dc4ee1/merged/etc/nginx/nginx.conf\\\" caused \\\"not a directory\\\"\"": unknown: Are you trying to mount a directory onto a file (or vice-versa)? Check if the specified host path exists and is the expected type
```

マウントのディレクトリが違うみたいでした。
docker-compose.ymlファイル内で指定しているvolumeの場所に指定してある
欲しいファイルがないことによるエラーみたいでした。

https://qiita.com/hanakok/items/6bfcfbb8b7b4df877178
【pySerial】micro:bitにシリアル通信時「could not open port '/dev/cu.」エラーが出た時に考えられること

pySerialを使ってmicro:bitにシリアル通信した際に以下のようなエラーが出た時の対処法備忘録です。

>Traceback (most recent call last):
  File "/usr/local/lib/python3.8/site-packages/serial/serialposix.py", line 265, in open
    self.fd = os.open(self.portstr, os.O_RDWR | os.O_NOCTTY | os.O_NONBLOCK)
FileNotFoundError: [Errno 2] No such file or directory: '/dev/cu.usbmodem14302'
>
During handling of the above exception, another exception occurred:

>Traceback (most recent call last):
  File "testSerial.py", line 4, in <module>
    ser = serial.Serial(port,115200,timeout=None)
  File "/usr/local/lib/python3.8/site-packages/serial/serialutil.py", line 240, in __init__
    self.open()
  File "/usr/local/lib/python3.8/site-packages/serial/serialposix.py", line 268, in open
    raise SerialException(msg.errno, "could not open port {}: {}".format(self._port, msg))
serial.serialutil.SerialException: [Errno 2] could not open port /dev/cu.usbmodem14302: [Errno 2] No such file or directory: '/dev/cu.usbmodem14302'


## Arduinoのシリアルポートを開いているとエラー

エラーの`could not open port`という内容からUSBポートが使用中の可能性が考えられます。
僕の場合は**Arduinoのシリアルモニタを開いていたことが原因**でした。
※デバッグのために使っていました。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328771/ca401a97-c95c-4f06-eaef-026732c1b2ca.png" width=450 />

閉じたら正常にシリアル通信出来ました。

## 最後に

今回のエラーはArduinoのシリアルモニタのように、**シリアルポートを専有するような事をしていないか**という視点を持つことが対処法になりそうです。


### Python側

```testSerial.py
import serial

mac='/dev/cu.usbmodem14302'
ser = serial.Serial(port,115200,timeout = None)
ser.write(b'1')
time.sleep(1)
ser.close()
```

### micro:bit側(JavaScript)

```receiveSerial.js
serial.setBaudRate(BaudRate.BaudRate115200)
basic.forever(function () {
    str = serial.readString()
    if (str.indexOf("1") >= 0) {
        basic.showIcon(IconNames.Heart)
    }
})
```
JS 配列の一番最後以外の要素を返す

## lodashのinitial関数を作ってみた

[lodashのinitial関数](https://lodash.com/docs/4.17.15#initial)

~~~javascript
const initial = (array) => {
  const initialArray = []
  for (let i = 0; i < array.length - 1; i++) {
    initialArray.push(array[i])
  }
  return initialArray
}

console.log(initial([1, 2, 3, 4]))
// => [ 1, 2, 3, 4, 5 ]
~~~

###▼POPメゾッドを使うともっと簡潔に書けるみたいだった

~~~javascript
const initial = (array) => {
  const copedArray = [...array]

  //popメゾッドは末尾の要素を取り除く
  copedArray.pop()
  return copedArray
}

console.log(initial([1, 2, 3, 4]))
// => [ 1, 2, 3]
~~~

###▼1行で記述可能だった！

@il9437さん、ありがとうございます！

~~~javascript
console.log([1, 2, 3, 4].slice(0, -1))
// => [1, 2, 3]
~~~
初心者のためのseaborn基礎③散布図（jointplot）※ヒストグラム付き

#seabornとは
Pythonのグラフ描画のためのライブラリです。。最も有名なライブラであるmatplotlibのラッパー関数(内包プログラム)という位置づけ。簡単に見た目綺麗なグラフの描画が出来る他、一括での処理などの機能もある程度充実しています。細かく指定して描画するならmatplotlib、簡単に綺麗にならseabornのです。

#散布図（jointplot）
今回のテーマは散布図です。散布図作成には`jointplot`を使用します。
seabornの散布図では、散布図と同時にヒストグラムが表示されます。これがデータの把握にも便利ですし、それっぽく見えてなかなか良いです。

#準備
まずは、pipで`seaborn`のライブラリをインストールして下さい。pip?って方は[こちら]('https://qiita.com/Yanagawa_Yoshihisa/items/35e6f70a8411277282ce')。

ライブラリをインポートします。`seaborn`に`sns`という名前をつけて`import`します。

```python:
import seaborn as sns
```
サンプルはタイタニックのデータで試してみます。タイタニックがわからない人は｢kaggle タイタニック｣で調べて下さい。
pandasでデータフレームを作ります。

```python:
dataframe = pd.read_csv('train.csv')
```

#基本作成
散布図作成には`.jointplot`を使用します。基本的に設定するものは、X軸項目、Y軸項目、元データです。X軸にAge（年齢）、Y軸にFare（運賃）を表示させたグラフを例とします。
図のように、ヒストグラムがついているのがポイントです。

```python:
sns.jointplot('Age', 'Fare', data=dataframe)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/600679/d30a243b-1055-b556-04dd-b129a9ab6064.png)

調べてもらうとわかるのですが、いろいろオプションはあります。
`kind`に`'hex'`を指定すると、散布図がタイル上になり、オシャレになります。映えるのでお勧めです。
（元データがイマイチのため伝わりにくいですが。）

```python:
sns.jointplot('Age', 'Fare', data=dataframe, kind = 'hex')
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/600679/552dfd7c-f2d5-fc87-9ad4-8d7b4dd4acd0.png)

非常に簡単な構文ですが、詳しくない人にはそれっぽくみえて、やった感がでるのでお勧めです。

#最後に
初心者にもわかるように、Pythonで機械学習を実施する際の必要な知識を簡便に記事としてまとめております。
目次は[こちら](https://qiita.com/Yanagawa_Yoshihisa/items/a3fa521d89c471b3e71f)になりますので、他の記事も参考にして頂けると幸いです。
エディタからmicro:bitに直接ソースコードを転送するためにファームウェアの更新をする

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328771/afeb99e2-b539-a7ce-9747-e5c2fa80165d.png" width=450 />

いつの間にかオンラインエディタから**micro:bitに直接ソースコードが転送**できるようになっていました。しかし、**ファームウェアのアップデートが必要**だったため本記事ではファームウェアのアップデートの備忘録です。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328771/3e2ffa3c-9b18-176d-8877-3e9f3c9068c5.png" width=450 />
※micro:bitにファイル転送する際にファームウェアのバージョンアップが促される



## デバイスのバージョン確認

ファームウェアを更新する前にmicro:bitのファームウェアバージョンを確認します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328771/fc1c3881-6d3b-62e7-3a9b-16ede1e15c7f.png" width=450 />

USBでmicro:bitを接続後に表示されるMICROBITの中のDETAILS.TXTを確認します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328771/a324f6c2-207e-489a-0a6d-e8ff663d9ebe.png" width=450 />


`Interface Version`がファームウェアのバージョンです。

> If the version is 0234, 0241, 0243 you NEED to update the firmware on your micro:bit.

[公式](https://makecode.microbit.org/device/usb/webusb/troubleshoot)によると、バージョンが0234, 0241, 0243の場合はファームウェアをアップデートする必要があります。僕の手持ちのmicro:bitのファームウェアバージョンは0241でした。


## 最新ファームウェアのインストール

最新のファームウェアを[公式ページ](https://microbit.org/get-started/user-guide/firmware/)からダウンロードします。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328771/20aaea70-c9b2-0bba-60b2-c65d54e9eb7c.png" width=450 />

※2020.08.06時点で0253が最新バージョン

![](https://cdn.sanity.io/images/ajwvhvgo/production/0072895a40c9395af5ab7a123d63270eb910ae08-450x306.gif?q=80&fit=max&auto=format)
公式GIF動画の通り**リセットボタンを押しながら**USBでmicro:bitを接続します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328771/11d46241-e08a-f513-21ac-514fefc8b766.png" width=450 />

するとMAINTENANCEがマウントされるのでそこにファームウェアファイルをD&Dします。

ファイル転送が完了すると、勝手にUSB接続が解除され通常起動します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328771/ff5941b4-b039-e774-24d4-14869d71210e.png" width=450 />

更新されたDETAILS.TXTを確認してファームウェアのアップデートは完了です。

## 最後に

micro:bitに直接ソースコードを転送できるようになって超快適です。
ファームウェアアップデートしてよかったです。残りのmicro:bitもアップデートせねば。
[備忘録]学習中言語の構文比較

学習言語の構文を比較
理解の範囲での記載なので、理解が足りてない箇所がある可能性あり。
随時更新

|内容|C/C++[^1]|kotlin|javascript|
|---|---|---|---|
|変数宣言|int a=0;|var a:int = 0|let a = 0;|
|定数宣言|const int a=0;|val a:int = 0|const a = 0|
|型付け|静的(型推論なし)|静的(型推論あり)|動的|
|行末セミコロン|必須|冗長|任意|
|if文|if(条件)|if(条件)|if(条件)|
||else if(条件)|else if(条件)|else if(条件)|
||else|else|else|
|for文|for(int i=0; i < 10; i++)|for(i in 0..9)|for(let i=0; i < 10; i++ )|
|配列|int a[2]|？？|let a = []|
|要素追加|不可(vectorとか使う)|？？|a[2] = "要素"|


[^1]: たぶんC++98 or C++03基準。どっちなのかは不明
【Java】splitメソッド

splitメソッドは、
Stringで定義した区切り文字列を分割することで、
文字列の配列に分ける。
（文字列を指定された正規表現に一致する位置で分割する）


#サンプルコード
```java
String str = "りんご,レモン,すいか,ブドウ"

String[] fruit = str.split(",", 0);

/**
*結果：
*fruit[0] = "りんご"
*fruit[1] = "レモン"
*fruit[2] = "すいか"
*fruit[3] = "ブドウ"
*/
```
最後の0のところは、
**分割する回数**を指す。
負の値を指定すると制限なし。
jenkinsのサンプル集＜基本とGitのチェックアウトと認証情報＞

# jenkinsのサンプル集

# はじめに
いつもJekinsを書き始めるときに困るので、サンプルをまとめます。


# 基本の形

```
pipeline {
    agent any 
    stages {
        stage("test")
            steps {
                echo 'jenkins test'
            }
    }
}
```
agentは実行するサーバーを指定。anyだと特に指定せずに実行する。
stagesの中に処理を記載する。
stageが処理のひとかたまり、stepに処理を記載しする。

# Gitからのチェックアウト
```
    stage("clean up directory") {
        // /var/lib/jenkins/workspeace を削除
        steps {
            deleteDir()
            }
        }  
        
    stage('cheackout') {
        // Gitからチェックアウト
      steps { 
        // privateリポジトリを使う時は認証情報の記述が必要
        checkout([$class: 'GitSCM', 
          branches: [[name: '*/master']],
          doGenerateSubmoduleConfigurations: false,
          extensions: [], 
          submoduleCfg: [], 
          userRemoteConfigs: [[credentialsId: '<jenkinsで設定したcredential>', url: '<GitのURL>']]
        ])
      }
    }
```
余計なものを削除するため、チェックアウト前にdeleteDir()でディレクトリをきれいにしてから、チェックアウトする。
じゃないとコミット時に余計なものをコミットしてしまい。取り返しのつかない自体にもなりかねないため。
本例ではマスターからクローンを実施。

# Credentialsの指定
```
    stage('mysql login') {
        // vCenterにVMdeployのplaybookを実行
        steps {
            //　認証情報の取得
            withCredentials(
                // 認証情報
                [usernamePassword(credentialsId: '<jenkinsで設定したcredential>', usernameVariable: '<ユーザー名を格納する任意の変数名A>',passwordVariable: '<パスワードを格納する任意の変数名A>')]
                )
                {
                sh 'mysql -u <ユーザー名を格納する任意の変数名A> --password=<パスワードを格納する任意の変数名A>'         
            }    
        }
    }
```
withCredentialsを使用して、credentialsに登録しいる認証情報を変数として利用できる。
ログもマスクされて表示される。2つ指定する場合は配列で指定する。

* 2つ指定する場合

```
            withCredentials(
                // 認証情報A
                [usernamePassword(credentialsId: '<jenkinsで設定したcredential>', usernameVariable: '<ユーザー名を格納する任意の変数名A>',passwordVariable: '<パスワードを格納する任意の変数名A>'),
                // 認証情報B
                usernamePassword(credentialsId: '<jenkinsで設定したcredential>',usernameVariable: '<ユーザー名を格納する任意の変数名B>',passwordVariable: '<パスワードを格納する任意の変数名B>')]
                )
```


# 最後に
JenkisのPipelineって公式のサイトが個人的に読みにくいと感じる。
またプラグインが豊富にあるため、書き方が色々ある。
なので、もっと良い書き方がある場合は教えてください。
共同開発でのgithub操作手順



## 本当にサーバで初めてgitを立てる、初期設定

```
#git --version
gitインストールの確認

#git初期設定
git init

#リモートにあるブランチをローカルにも作る
git checkout -b develop

// リモートリポジトリとローカルつなげる
git remote add origin https://github.com/github.com/チーム名/リポジトリ名

//リモートリポジトリのurl変更、addでエラー起こるならこれ
git remote set-url origin https://github.com/github.com/チーム名/リポジトリ名

リモートブランチにある、ブランチをローカルにも作る
git checkout -b develop
git checkout -b master

//リモートリポジトリ確認コマンド
git remote -v

//現在のブランチとブランチリスト確認（add・コミットしないと見えない）
git branch -a

※以下のコマンドだと、ブランチが既にあると文句を言われる。
git checkout develop-a origin/develop-a

git -b develop-a origin/develop-a

git checkout -b origin/develop-a


デベロップブランチに戻す。
```


コミットしようとすると文句を言われるので以下のgitユーザ登録コマンド：
git config --global user.email "github使用のメールアドレス"
git config --global user.name "github使用のユーザ名"


再度コミット


### リモートへpushする手順

//セット中のリモリポ状況を見る
git remote -v

git remote rm [削除したいリモートリポジトリ名]

// リモートにアクセス
git remote add origin https://github.com/github.com/チーム名/リポジトリ名

//リモートリポジトリのurl変更、addでエラー起こるならこれ
git remote set-url origin https://github.com/github.com/チーム名/リポジトリ名



//リモートリポジトリへpushする（developは指定ブランチ）
git push origin develop


以下のようなエラーが出たら、
「git pull origin develop」してから
「git push origin develop」しよう。

```
int: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first merge the remote changes (e.g.,
hint: 'git pull') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
```

ステージングエリアが汚れてたら。
git reset

-------------------------------------------------------------------------------------------------------

## 更新があった際の操作手順

#### 前提

開発者がgithubでブランチを切ってpushしたらそのブランチを自分のローカルに作って、cloneしておく。
リモートでマージして、壊してしまっても復帰させるため。

#### 差分適応方法

developブランチは常に、更新されるので、自分が差分を追加する際は、
最新のdevelopブランチをcloneしてからそれに、rsyncなどで差分を適応する。
ローカルブランチに落として、マージでもよい。


(※)ブランチ状態を確認する。
git branch -a

(※)Aさんの更新をローカルに持ってきているのでそれをマージ
git merge develop-a


git checkout -b develop-a origin/develop-a

作ったnew新規ブランチ切り替え
git checkout develop-b



-------------------------------------------------------------------------------------------------------



### 続：

git cloneで落としたソースを、運用ソースと差し替えると、
パーミッションのズレが発生して、トラブルになることが多かった。
なので一部だけrsyncでアップデートする方法を取る。


--------------------------------
### rsyncでの更新手順：セットアップ


git cloneにてリポジトリ展開

git clone https://github.com/チーム名/リポジトリ名


初期スクリプト実施


ディレクトリ複製
cp -pr ./展開したフォルダ名 ./複製するフォルダ名



### rsyncでの更新手順：更新ある度

複製ディレクトリへgit pullし差分を適応


複製ディレクトリから運用ディレクトリにrsync


--------------------------------
オンライン研修でYoutube動画を再生するためのWEBアプリをつくった

#はじめに

コロナの影響で、オンラインで研修やセミナーを行うことが多くなりました。

その際、Youtubeにある動画の一部分をスマートに流したい。
プロとして再生に手間取るのはかっこわるい。
事前の準備で、再生の頭出しと終わりの事前設定をしておきたい。

そんな人のためのWEBアプリを作りました。


#つくりたいイメージ

オンライン研修で3本くらいYoutube動画の頭出しと終了の設定を事前に終えられて、かつ、誰でもその設定が簡単に変えられるものを作ろうと思いました。


#実際につくったもの

１つの動画の頭出しと終了の設定を、
コードの方の数字を変えるだけでできるようになりました。

詳細はこちらをご覧ください。
https://optimistic-ritchie-c5d29d.netlify.app/youtube05


ソースコードはこちら
https://gist.github.com/kaiser355/0a9e3a3a39407ee8b935b9cf93401a0b


ただし、動画の下にあるフォームを入力しても、
自動で計算はされるものの、それが動画の頭出しの設定には
変更できません。

ここはできるように改良していきます。


#設定の変え方

コード内のこの部分の数字を変更してください。
単位は秒で。

```Javascript
playerVars: {
            start: 2, // 動画再生の開始位置
            end: 8 // 動画再生の終了位置
```

つかったフレームワーク・ライブラリなど
・Youtube Player API
・Vue.js
・Bootstrap


#終わりに

つくりたいものをつくるために様々格闘しましたが、
・Youtube動画を複数設置すると動画が表示されなくなる
・フォームで計算したものを、再生開始時間のところに変数を代入してみるものの、
　うまく設定が変えられない
の課題がクリアできず、ひとまず、現状で公開します。

今後改善していきます。
Rails6でPG::ConnectionBadというエラーが出た原因と対応

## エラーが出た手順

`rails s`でWebサーバー起動
↓
`http://localhost:3000/` にアクセスすると
PG::ConnectionBadというエラーが出た
↓

|![3C20CC71-D23D-4497-A685-5704DA0F704A.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538652/41f55d93-6a23-5303-83fd-89a5758af273.png)|
|:---|

## 原因
db(PostgreSQL)のほうはdockerで立ち上げる構成だったのだけど
立ち上げ忘れていたので、dbに接続できない状態だった。

## 対応
`docker-compose up -d`でDBを起動する

## 確認
webページの再読み込み
↓
正常に表示された　OK!
【Mac】Vueカルーセルコンポーネント「Hooper」を使う

## ドキュメント
[https://baianat.github.io/hooper/getting-started.html](https://baianat.github.io/hooper/getting-started.html)

## インストール
```shell:Macターミナル
npm install hooper
```

## vueコンポーネント
```vuejs:HooperSample.vue
<template>
  <hooper>
    <slide>
      slide 1
    </slide>
    <slide>
      slide 2
    </slide>
    <slide>
      slide 3
    </slide>
    <slide>
      slide 4
    </slide>
    <hooper-progress slot="hooper-addons"></hooper-progress>
    <hooper-pagination slot="hooper-addons"></hooper-pagination>
  </hooper>
</template>

<script>
import 
    Hooper,
    Slide,
    Progress as HooperProgress,
    Pagination as HooperPagination,
} from 'hooper';
import 'hooper/dist/hooper.css';
 
export default {
    name: 'App',
    components: {
      Hooper,
      Slide,
      HooperProgress,
      HooperPagination,
    }
  };
</script>
```
node-sassを利用する

# node-sass
## package.jsonの準備
```shell:Macターミナル
npm init
```
package.jsonが作成される

## node-sassを追加
```shell:Macターミナル
npm install node-sass -D
```

## package.jsonのscriptに追記
```json:package.json
・・・

"scripts": {
    "sass": "node-sass assets/scss/ --output assets/stylesheets/ --output-style compressed --watch --source-map true"
},

・・・
```
scssファイルを`assets/scss`に、コンパイル後のcssファイルを`assets/stylesheets/`に配置することとする

## コンパイルと監視の実行
```shell:Macターミナル
npm run sass
```
Vue 省略記法

## :v-bind

```html
<a v-bind:href="url"> ... </a>
<a :href="url"> ... </a>
```

## :v-on
```html
<a v-on:click="func"> ... </a>
<a @click="func"> ... </a>
```

## :v-slot
```html
<template v-slot:title></>
<template #title></>
```
3本バー（グローバルナビのヤツ）の自分流実装

#動機
3本バーで呼び方があっているのかよくわからない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647892/13719395-9911-be81-d08b-f99cb947d994.png)
の棒三つの部分みたいなやつ。主にメニューを表示するトリガと使用されることが多いやつです。
起源はよくわからないのだけど、bootstrapが出てきたあたりでかなり使われるようになり今となっては別の表現を選ぶにはそれなりの理由がいるくらいにスタンダードになってしまった。
自分用スタイルガイドっぽいものを作っていて、3本バーも必須の表現だと思うので実装しなければならない。

#実装
手っ取り早く確認したい方は
[CodePen](https://codepen.io/mixgrill/pen/mdPdKZJ)
をどうぞ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647892/3723ef39-9374-3c31-f37e-68079fc17659.png)
↑こういうのができます。

```css:css
.threebar{
    position:relative;
    padding-top:100%;
    display:block;
    background-color:black;
}
.threebar__body{
    content:"";
    display:block;
    position:absolute;
    top:11.67%;
    left:0;
    width:100%;
    height:10%;
    background-color:white;
    border-radius:0.1em;
}
.threebar__body::before{
    content:"";
    display:block;
    position:absolute;
    top:333.33%;
    left:0;
    width:100%;
    height:100%;
    background-color:white;
    border-radius:0.1em;
}
.threebar__body::after{
    content:"";
    display:block;
    position:absolute;
    top:666.66%;
    left:0;
    width:100%;
    height:100%;
    background-color:white;
    border-radius:0.1em;
}
```
```html:html
<div style="width:50px;padding:10px;background-color: black;">
  <div class="threebar">
	  <a class="threebar__body" href="#"></a>
	</div>
</div>
```
#使い方
外側のdivにwidthを設定して、内側に.threebar .threebar__body を配置する。
border角の丸みを調整したいときは外側のdivのfont-sizeを適当にゴニョってくれい。
外側のdivの幅は10で割り切れるpxを指定したほうが線の太さが綺麗になります。

#説明
この3本バーの表現はいろんな実装方法があって、span3つにborderで表現しているパターンをよく見かけた気がするけど今回はその方法は使っていない。
まず、10%の高さのblock要素の背景色を設定し、バーとしている。
これだと1本線しか引けないため:before、:afterでも同じような要素を作成してabsoluteで配置する感じ。
%の指定が謎だと思うけど
threebarのpadding-top:100%は正方形にするおまじないで
:before,:after の top が100%超えとるやんけっていうのは、
親要素の高さが10%なので祖父母要素の大きさに対応するためには10倍する必要があったためです。

font-sizeを調整しないと角の丸みがうまく出ないのは理由があって、border-radiusに%指定すると楕円っぽいカーブになってしまうため、何かしら違う方法で値を設定してあげる必要がある。
じゃあ、font-sizeは親から引き継ぐんでemを利用すればいいんじゃね？ってことでfont-sizeの調整で対応することにしてます。

#まとめ
とりあえずできた。

この方法だといろんなサイズに対する3本バーをいろいろ書かなくていいかな（100px ｘ 100pxの3本バーとかもできる）とは思うんだけど、欠点についてはまだ評価できてない。

一応IE11でも動きそう。
【Mac】Vue cliでVuetifyを利用する

[クイックスタート](https://vuetifyjs.com/ja/getting-started/quick-start/)

## vueにvuetifyを追加
```shell:Macターミナル
vue add vuetify
```

## webpackインストール
```shell:Macターミナル
npm install sass sass-loader fibers deepmerge -D
```
自動でいろいろと生成される
→ この状態で利用可能

## 使い方
[ドキュメント](https://vuetifyjs.com/ja/)
【Mac】Vue cliでsassを利用する

[https://cli.vuejs.org/guide/css.html](https://cli.vuejs.org/guide/css.html)

## Pre-Processors
```shell:Macターミナル
# Sass
npm install -D sass-loader sass
```

## Automatic imports
[https://www.npmjs.com/package/vue-cli-plugin-style-resources-loader](https://www.npmjs.com/package/vue-cli-plugin-style-resources-loader)

```shell:Macターミナル
vue add style-resources-loader
```
### vue.config.jsを編集
```js:vue.config.js
const path = require('path')
module.exports = {
  pluginOptions: {
    'style-resources-loader': {
      preProcessor: 'scss',
      patterns: [
        path.resolve(__dirname, './src/styles/*.scss'),
      ]
    }
  }
}
```

### src/main.jsに追加
```js:main.js
import Vue from 'vue'
import App from './App.vue'
import "./styles/style.scss";//ここで読み込む

Vue.config.productionTip = false

new Vue({
  render: h => h(App),
}).$mount('#app')
```

## 自動で反映
```shell:Macターミナル
npm run serve
```
【Mac】Vue cli

##　vue cli インストール
```shell:Macターミナル
npm install -g @vue/cli
```

## vue cli　バージョン確認
```shell:Macターミナル
vue --version
```

## vueプロジェクトを作成
```shell:Macターミナル
vue create new-project
```

## 開発用サーバ起動
```shel:Macターミナル
cd new-project
npm run serve  
```
VSCode プロジェクト毎に色を分ける

## .vscode/settings.jsonを作成
プロジェクトルートに`.vscode/`ディレクトリを作成
`.vscode/`に`settings.json`を作成
## settings.jsonに記述
```json:settings.json
{
    "workbench.colorCustomizations": {
        "titleBar.activeBackground": "#FFFFFF",
        "titleBar.activeForeground": "#000000",
        "activityBar.background": "#FFFFFF",
        "activityBar.foreground": "#000000"
    }
}
```
HTML MediaElement で NightCore する😎

# TL;DR
```cs
(function()
{
  const media = document.getElementsByTagName("video")[0];
  media.mozPreservesPitch = false;
  media.playbackRate = 1.2;
})()
```

# 動機

昨今は、Youtubeなど大抵の動画サイトでは再生速度を調節する機能がついています。
しかしながら、これらの再生速度を変更すると、ピッチが自動で修正（見かけ上?…聴きかけ上?変わらないように）されてしまいます。
普通の動画であれば、この挙動の方がありがたいのですが、聞き慣れた音楽をピッチを維持って聞きたい時があります。
そうです`NightCore`です。

# 対応ブラウザについて

Firefoxで検証しました。
MDNのドキュメントを見る限りSafari（Webkit）でもサポートされているようです。この場合、Prefixが`moz`ではなく`webkit`になります。
ChromeではPrefixのつかないプロパティが実装されている的なことが書いてあったのですが、Prefix版でもそうでない版でも定義されていませんでした。🤔

# ブックマークレット

```js
javascript:
(function(){
  if(confirm("night core?")) document.getElementsByTagName("video")[0].mozPreservesPitch = false;
  document.getElementsByTagName("video")[0].playbackRate=parseFloat( prompt("speed", "1.8"));
})()
```

[これをぶくま！](javascript:javascript:(function(){if(confirm("night core?"))document.getElementsByTagName("video")[0].mozPreservesPitch=false;document.getElementsByTagName("video")[0].playbackRate=parseFloat(prompt("speed","1.8"))})();void(0);)

# 参考

[ナイトコア（Wikipedia）](https://ja.wikipedia.org/wiki/%E3%83%8A%E3%82%A4%E3%83%88%E3%82%B3%E3%82%A2)
[HTMLMediaElement（MDN）](https://developer.mozilla.org/ja/docs/Web/API/HTMLMediaElement)
[HTMLMediaElement.preservesPitch（Chrome Platform Status）](https://cr-status.appspot.com/features/5742134990733312)
バリデーションのエラーメッセージの個別表示

自分用です！！

バリデーションでのエラーメッセージをviewで表示していきます。

例えば、userを登録するときに、passwordとnameにpresence: trueのバリデーションをかけた、状態でパスワードとnameを空欄で登録すると、バリデーションに引っかかります。

railsのオブジェクトは、デフォルトでエラーオブジェクトを保持しているので、画像のようにエラーメッセージを取得できます。

ここでエラーメッセージが日本語化されているのは、i18nの働きによるものです。

さらに、full_messagesというメソッドを使用することで、エラーメッセージだけを取り出すことができます。


![スクリーンショット 2020-08-06 3.06.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675654/bde05ac4-a73b-c1d9-a229-fdab7a5d6aa7.png)

エラーメッセージは、色々な入力フォームで使いたいので、パーシャルを使います。

```ruby:_error_messages.html.erb
<% if object.errors.any? %>
  <% object.errors.full_messages.each do |message| %>
    <div class="alert alert-danger"><%= message %></div>
    <% end %>
<% end %>
```
個別で表示したいので、each文を使用。

objectを指定して、そのobjectのエラーメッセージを表示されるようにします。

```ruby:users/new.html.erb
<%= form_with model: @user, local: true do |f| %>
        <%= render 'shared/error_messages', object: f.object %>
        <div class="form-group">
          <%= f.label :first_name %>
          <%= f.text_field :first_name %>
<% end %>
```

このように、パーシャルを呼び出します。

object: f.objectでは、f.objectに@userが入っており、パーシャル側では、そのobjectのエラー文を表示してくれます。
String.split(separator:) で Xcode Previews がコケる

SwiftUIで画面を実装中していたらXcode Previewsで表示していたプレビューが突然できなくなった。

Diagnosticsを開くとこんなエラー

```
Compiling failed: global function '__designTimeString(_:fallback:)' requires that 'String.Element' (aka 'Character') conform to 'ExpressibleByStringLiteral'
```

エラーの行も表示されるので当該箇所を見たら大体こんな感じ

```swift
let str = ~
let array = str.split(separator: "\n") // ← ここでエラー発生
    .map(String.init)
```

どうやら`"\n"`(String Literal)がXcode Previews上だと`Character`として認識されないらしい（なぜ？）

# 解決策

Characterであることを明示すれば良い。

```swift
let array = str.split(separator: "\n" as Character)
// or
let array = str.split(separator: Character("\n"))
```

# 参考
https://developer.apple.com/forums/thread/125065

# 2020/09/21追記
Xcode12(Swift5.3)でも直っていない模様
Udemyのswiftコース（英語のやつ）でiOSアプリ開発を学ぶ　その３

勉強するコースはこれです:point_down:
https://www.udemy.com/course/ios-13-app-development-bootcamp/

##進捗
セクション4の途中まで終了（全部で36セクション）
Xcodeの使い方など開発環境について実際の操作を学び、アプリをつくった:grinning:

最初はただ表示するだけのアプリ。二つ目でタップしてサイコロの目を出すアプリを開発する（ようだ）。

##感想
前回の記事（[Udemyのswiftコース（英語のやつ）でiOSアプリ開発を学ぶ　その２](https://qiita.com/KitaDaro/items/197ee6f32611b5acb886)）から2週間以上も間があいてしまった…
提出期限とかないしコース視聴いつでもできるし、Angela（先生）の優しさに甘えてしまった（オンラインコースあるある）
**やはり絶対にこの曜日のこの時間にやるとか決まり事をつくって習慣化していかないとオンラインコースは続かないのだ（戒め）**

何はともあれアプリをつくって自分のiPhoneで表示させるのは実に気分が良い。
エンジニアとしてはちいさな一歩だが、初めて開発をした人にとってはおおきな一歩だとおもう。

コース内の小ネタとしては、スマホアプリ黎明期に「I AM rich.という画面を表示させるだけのアプリで高額課金させて儲けるという詐欺同然の方法で稼いだ人がいた」という話が実に興味深かった。
そのアプリ持っているだけで金持ちの象徴のようなことだしアプリの内容は間違っていない（？）

開発について説明中にちょくちょく小ボケがあったり興味深い話をしたり、飽きない工夫がされているので飽き性の自分でもなんとかできている気がする。

##今後の予定
日曜の夜23時頃と水曜の夜23時頃に記事を書くし、書けるようにコースを進める
（習慣化できるように具体的な予定を設定する:point_up:）
【Laravel】レート制限機能を使ってセキュリティを向上させる

ルート定義ファイル`routes/web.php`にレート制限をかけるミドルウェアを適応させて、セキュリティの向上を図りたいと思います。アクセスの回数制限を設定したい場合に有効です。

## レート制限の書き方

`Route::middleware`メソッドに`throttle`ミドルウェアを指定してください。この`throttle`ミドルウェアは「時間内に許す最大リクエスト数」と「時間」の２つを指定します。

```php:routes/web.php
Route::middleware('auth:api', 'throttle:60,1')->group(function () {
    Route::get('/user', function () {
        //
    });
});
```
上記の例のコードでは、1分間に60回のアクセスを許可するルートになります。

## 動的レート制限の書き方
もし、認証済みのモデルの中に、最大リクエスト属性がある場合には、その値を動的に最大リクエスト数に適応することもできます。

```php:routes/web.php
Route::middleware('auth:api', 'throttle:rate_limit,1')->group(function () {
    Route::get('/user', function () {
        //
    });
});
```
例えば、認証したモデルに`rate_limit`属性があり、値を持っている場合、その値が`throttle`ミドルウェアの`rate_limit`に渡されるという感じです。

参考文献：https://readouble.com/laravel/7.x/ja/routing.html
作成したLaravelアプリケーションにPosgresqlを接続する

## 前提条件

php7.2（brewでインストールしています）
Laravel
Postgres12.3(こちらもbrewでインストールしています。）
Laravelのトップページが開いているところからやります。
目標は、posgresqlに接続して、php aritisan migrateでDBを作るまで

## その１ .envファイルで指定したユーザーと同じユーザー（ロール）をpsql側で作る

```
# .env
DB_CONNECTION=pgsql
DB_HOST=127.0.0.1
DB_PORT=5432
DB_DATABASE=sample  #その2
DB_USERNAME=default #その1 このユーザーをpsql側で作成する
DB_PASSWORD=secret
```

```bash
$ createuser default
```

# その２　.envファイルで指定したDBと同じDBをpsql側で作る

```bash
$ createdb sample -O default
```

つくれたかチェックします。

```bash
$ psql -l
```

# 最終章、 Laravelプロジェクトのあるディレクトリに入り、php artisan migrateを実行します。

```bash
$ cd Laravelプロジェクト
$ php artisan migrate
Rolling back: 2020_05_29_072511_create_problems_table
Rolled back:  2020_05_29_072511_create_problems_table
Rolling back: 2020_05_22_023512_add_column_to_users_table
Rolled back:  2020_05_22_023512_add_column_to_users_table
Rolling back: 2020_05_07_115046_create_song_tag_table
Rolled back:  2020_05_07_115046_create_song_tag_table
Rolling back: 2020_04_19_234148_create_tags_table
Rolled back:  2020_04_19_234148_create_tags_table
```
Mackerelのロール紐付きを修正する

## 目的
インスタンスに対してmackerel-agentを登録する際にロールの指定が誤っており、対象のインスタンスが適切に探せない状態になっていました。
管理コンソールでは以下のようなイメージです。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252317/ea8095a0-e18f-3e35-8033-9776909caf4f.png" width=80%>

今回、正しいロールに紐づくようにagentを修正しました。

## 手順
対象のインスタンスにsshでログインし、ロールの設定を確認します。

```
$ cat /etc/mackerel-agent/mackerel-agent.conf | grep roles
roles = [ "誤ったロール名:ec2" ]
```
ロール名を修正した後、agentを再起動します。

```
$ cat /etc/mackerel-agent/mackerel-agent.conf | grep roles
roles = [ "正しいロール名:ec2" ]
$ sudo /etc/init.d/mackerel-agent reload
Reloading mackerel-agent:                                  [  OK  ]
```

## 結果

agentを修正したインスタンスが新しいロールに所属されていることが分かります。
ただ、このままだと新旧のロールに所属している状態となるため、誤ったロールは×ボタンで外します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252317/8a661c5d-d753-eef2-bac8-1c7a1222613f.png" width=80%>

誤ったロールを外しても、正しいロールで過去の全てのメトリクスは遡って確認可能です。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252317/9b6ab5cf-5cd0-747b-2a02-72c8fdaf1114.png" width=40%>


## 参考にした記事

[Mackerelのmackerel-agent設定とウェブ画面の設定優先度を確認した](https://dev.classmethod.jp/articles/mackerel_mackerel-agent_web_priority/)
Pythonでlist型をlen()しようとしたら  "TypeError: 'int' object is not callable"が出た話

Google Colabolatoryでデータを色々いじってグラフ書いたりしてたら、表題の様な事が起こりました。少しハマりましたが、原因は簡単でした。
もともとリスト型に入っている文字列の数を数えてその数を棒グラフにしたかったんですが、棒グラフのラベルを作るために以下のようなソースを実行しました。

```python:
datalabels=[]
for data in datalist:
  if data not in datalabels:
    datalabels.append(data)
print(len(datalabels))
```
すると、

```python
TypeError                                 Traceback (most recent call last)
<ipython-input-9-e9369466b8b1> in <module>()
      5   if data not in datalabels:
      6     datalabels.append(data)
----> 7 print(len(datalabels))
      8 print(len)
      9 

TypeError: 'int' object is not callable
```
が発生。ググるとビルトイン関数と同じ名前の変数名を使うとこれが起きるとのこと。datalabelsなんてビルトイン関数聞いたことないぞ！と憤っていたらよく見たら別のブロックでlenを使ってた。

なるほどな。lenは無警戒だったけど、そっちで出るのか。ひとつ勉強になりました。

lenという変数を急遽 _len に変えて再実行。
ふう、これでうまくいく。

と思ったらまだ同じエラーが出るじゃないか！！！なんだと！！！！

そうか。google colabolatoryだからランタイムをリセットしないと一度作った変数はソース上削除しても保持されるのか。多分jupyterでも同じこと起きるやつだ。

というわけでランタイムリセットして上からやり直したら無事成功。
一件落着。