OmniAICreator/Qiita-1.07M huggingface dataset:
FirebaseとHasuraの連携

firebaseとHASURAの連携の勉強の一環としてメモを記載する。

## Cloud Function for firebaseとは？
Cloud Functions for firebaseはGoogleが提供するクラウドサービスです。そのため、サーバーの構築や保守をすることなくプログラムを実行することができます。

## firebase cloud function設定
※事前準備として、firebaseのプロジェクトを従量課金制に変更する必要がある。firebaseに必要なパッケージ、初期化設定を実施した後を記載
[https://firebase.google.com/docs/cli?hl=ja](https://firebase.google.com/docs/cli?hl=ja)

### firebaseの初期化


``` 
firebase init
```

###functionの設定
1.Functionsを選択
2.Use an existing project
3.firebaseのプロジェクト名を選択
4.Typescript
5.eslint => y
6.dependencies => y

functionsが作成される事を確認。

## HASURAの環境構成変数を設定

```
firebase functions:config:set hasura.url="HASURAのURL" hasura.admin_secret="パスワード"
```

[https://firebase.google.com/docs/functions/config-env?hl=ja](https://firebase.google.com/docs/functions/config-env?hl=ja)

## functionsの中身
概要として、firebaseのAuthenticationでユーザーが新規作成の時JWTトークン作成し返してくれる仕組みである。
functionsとしてやりたい事は、HASURAのエンドポイントの認証に必要な情報をJWTトークンの内容に埋め込む作業である。

```
import * as functions from 'firebase-functions'
import * as admin from 'firebase-admin'

//初期化
admin.initializeApp()
```

##firebaseの新規作成時の処理
```
// HASURAのエンドポイントの内容を
export const setCustomClaims = functions.auth.user().onCreate(async (user) => {  
　　const customClaims = {
    'https://hasura.io/jwt/claims': {
      'x-hasura-default-role': 'loginUser',
      'x-hasura-allowed-roles': ['loginUser'],
      'x-hasura-user-id': user.uid,
    },
  }
    //ログイン時にカスタムクレームを追加する処理
  try {
    await admin.auth().setCustomUserClaims(user.uid, customClaims)
    await admin.firestore().collection('user_meta').doc(user.uid).create({
      refreshTime: admin.firestore.FieldValue.serverTimestamp(),
    })
  } catch (e) {
    // エラー処理 ...省略
  }
})
```

HASURAの設定方法下記参照
[https://hasura.io/docs/latest/graphql/core/auth/authentication/jwt.html](https://hasura.io/docs/latest/graphql/core/auth/authentication/jwt.html)

## firebase deploy

```
firebase deploy --only functions
```
riverpodのProvider, Stateを整理する

Riverpodを状態管理に使おうとしてて、何種類のProviderとStateやらを整理したい。

## 基本的の使い方
セットで使う

| State | Provider | 公式document |
| ---- | ---- | ---- |
| `String`や`int`などシンプルなもの | `StateProvider` | [リンク](https://pub.dev/documentation/riverpod/latest/riverpod/StateProvider-class.html) |
| `StateNotifierProvider`（状態をいじる、`ChangeNotifier`に相当） | `StateNotifierProvider` | [リンク](https://pub.dev/documentation/riverpod/latest/riverpod/StateNotifierProvider-class.html) |
重要なアイデア

[まとめページに戻る](https://qiita.com/Keiji_otsubo/items/60afc2a8d211b6f7d89f)

# 気になったアイデアをまとめておきます。

+ ['None' showing for required picklist values - Lightning Experience](https://ideas.salesforce.com/s/idea/a0B8W00000Gdi0yUAB/none-showing-for-required-picklist-values-lightning-experience)
+ [Lightning - Remove Change Owner from List Views Quick Action](https://ideas.salesforce.com/s/idea/a0B8W00000GdcWAUAZ/lightning-remove-change-owner-from-list-views-quick-action)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/7d00ff74-b2ce-6d16-4a91-8a370470f467.png)

+ [ソーシャルプロフィール写真だけでなく、カスタムの連絡先写真とアカウントロゴを許可する](https://ideas.salesforce.com/s/idea/a0B8W00000GdkF6UAJ/allow-custom-contact-photos-and-account-logos-not-just-social-profile-photos)
+ [「ファイルとコンテンツ」レポートには、アクセスできるすべてのファイルが表示されます。](https://ideas.salesforce.com/s/idea/a0B8W00000GdjMUUAZ/file-and-content-report-should-display-all-files-we-have-access-to)
+ [各権限セットで参照可能なオブジェクトのリスト化について](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000FUmrNSAT)
+ [グループが使用されている場所を確認するにはどうすればよいですか](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000FwlNg)
+ [salesforce Platformユーザーは、アカウントと連絡先のすべてのレポートを実行および表示できますか？](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000FxVzQ)
+ [ゲストユーザをアンケートで認証なしで実行する方法](https://qiita.com/Keiji_otsubo/items/bd2d273f88bdea57d02f)
+ [ホーム画面のリストビューで昇順降順を指定したい](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007Usn65)

:::note
アイデアに上がっていますね。対応するみたいでロードマップにはあるとのことです。

https://ideas.salesforce.com/s/idea/a0B8W00000GdlwEUAR/list-view-default-sort-order
:::
えっ、まだvim以外のアプリでメモ書いてるの？

# All we need is memo
メモ。
人によっては魔力がなんちゃらとかいいますが、お仕事をする上で至極大事な習慣だと思います。
しかしどうやってそのメモを「取る」「保存する」「後から参照する」のか？
適当な方法では、結局ゴミ溜めのような何かが出来上がってしまい、重要な情報が地下深く埋められていってしまうでしょう・・・。
一貫していて、かつ生産性のある手法が必要になります。
**しかし、こういった生産性に関するトピックは、エンジニアにとって簡単に解決できることではないです。**
某rebuild.fmに出現する方々のように、詰めすぎて完全に目的と手段が逆転する(手段構築のためにかけた時間が、どう見てもpayしていない)ことは、ままあるのではないかと思います。
こだわりたいのです。0.5秒削減することで全能感を得たいのです。。。

残念なニュースですが、我々人間の時間は有限です。
特に自分のようなまだまだ駆け出しのエンジニアは、時間の使い方には最新の注意を払わなければなりません。
~~間違ってもmacosの開発環境構築をコマンド一発でできるように週末をまるまるつぶしたり、いけてるascii artを要所で打ち出すのためにwebサービスを吟味するなどあってはならないのです・・・(戒め~~


**「生産性高くメモを取ることはできないか？」**
これは自分の長年の課題でした。

解決することを決心しました。
解決するために、まず問題を以下に細分化しました:

1. メモとして文章を書く手段
1. 書いたメモを保存/管理する手段
1. 過去のメモを検索/参照する手段

# Oh yes, we want to write memos with vim

課題の1番は解決するまでもありません。解決方法は自明です。
**vimで書けば良いのです。**
「メモを取る」「文章を書く」といった時、全てのエンジニアはvimでそれを達成したいはずです。
他に手段などないはずです。

vimはあらゆるモノカキ効率化の手段を提供してくれます:
- Normal/Insertモードの各種キーバインドによる高速かつ効率的な編集
- Visualモードによる効率的な編集
- 的確なシンタックスハイライト
- 気軽なwindow分割 (ソースコードを横に置くとか、同じファイルでも違う箇所を並べるとか)

はい、課題の１番は解決しました。
残るはメモを「保存/管理する手段」と「検索/参照する手段」です。

# 「It's time, Doctor Vim plugin.」 「ｵｰｹｲ」

前置き長くなりましたが、本題です。ドクター○須の力も借りつつ進めていきます。
「メモの保存と管理(一瞬で、どこかに迷惑かけることなく)」と、「それらのメモを検索/参照する方法」を行う手段を得るため、ちっちゃいプラグインを作りました。 (すいません作成自体は数年前です)

https://github.com/eiji03aero/quick-notes

使い方は至ってシンプルです。

## 使い方

### メモを作成する
メモを作成します。
このプラグインは特定のフォルダ内にメモを作成/保存します。 (指定のファイルパスにeditコマンドを流すだけです)
作成できるメモは3種類あり、それぞれよきように保存の面倒を見てくれます。

```vimscript
" Create new note. Will be prompted to input file name.
" Path can contain `/` to create file under directories.
:call QuickNotesNew()

" Create new note named with current date
:call QuickNotesNewDiary()

" Create new note with git's `[repository name]/[branch name]`
" Needs tpope/vim-fugitive
:call QuickNotesNewGitBranch()
```

個人的にはgitのrepositoryとbranchを元に作成してくれる3点目が誠に便利だと思っています。
Todoを書き出したり、MRで共有したい情報を忘れないためにメモしておいたり。

### メモを検索/参照する
作成されたメモを検索/参照します。
一応filerとfzfの両方を手段として用意していますが、圧倒的にfzfの方が使いやすいです。


```vimscript
" Open notes directory.
:call QuickNotesLsNotes()

" Open diaries directory.
:call QuickNotesLsDiary()

" Open notes in fzf.
" Needs fzf and fzf.vim
:call QuickNotesFzf()
```

# 縁もたけなわ
非常にざっくりですが、自分の課題を解決するために作成したvim pluginの紹介でした。
「こうしたらもっといいよ」「こういう機能あるといいんじゃない」などのご意見はいただけるとすごく喜びます。
読んでいただきありがとうございました！


# CrowdLog is hiring!
自分の所属する、CrowdLogチームでは、一緒に事業の成長に熱くコミットしてくれる仲間を募集しています！
(個人的にはvimを熱く語る仲間も募集しています。たぶんいまのところvimmerは僕一人です)

https://crowdworks.co.jp/careers/
DataflowのストリーミングJOBをデプロイするときの無限ループの回避

Apache BeamのJobをCloud Dataflowにデプロイするために、以下のようなコマンドを使うことができます。

```sh
python -m apache_beam.examples.wordcount --input gs://dataflow-samples/shakespeare/kinglear.txt \
                                         --output gs://<your-gcs-bucket>/counts \
                                         --runner DataflowRunner \
                                         --project your-gcp-project \
                                         --region your-gcp-region \
                                         --temp_location gs://<your-gcs-bucket>/tmp/
```

出典:

https://beam.apache.org/get-started/quickstart-py/#execute-a-pipeline

なお、ここで使っている `apache_beam.examples.wordcount` の実体は以下のファイルに書かれています。

https://github.com/apache/beam/blob/master/sdks/python/apache_beam/examples/wordcount.py

上記のPythonコマンドを実行すると、JOBが完了するまでブロッキングされ、完了のタイミングでshellに戻ってきます。
これは直ぐに終わるバッチJOBであれば特に問題ない挙動です。
ですが、ストリーミングJOBを動かす場合は問題になることが多いです。
ストリーミングJOBはUnboundデータを扱うために、「全てのデータを処理し終わる」という概念がありません。
そのため、JOBの完了待ちをすると、無限ループに陥ってしまいます。

# 解決策
JOBの完了待ちを行っている処理は、DataflowPipelineResultクラスのwait_until_finishメソッドなので、このメソッドにモンキーパッチを当てます。

https://github.com/apache/beam/blob/master/sdks/python/apache_beam/runners/dataflow/dataflow_runner.py

```py
if __name__ == '__main__':
  DataflowPipelineResult.wait_until_finish = lambda duration=None: PipelineState.DONE
  run()
```

これで、JOBが生成されたら即座にshellに戻すことができます。
OpenpyxlでExcelシートのセル幅を自動調整させる[日本語対応,フォントサイズ対応](1)

#Openpyxlでエクセルの個別セルを自動調整
友達からエクセル表示をセルの中身に合わせて幅を整理(印刷)したいと要望受けたので、エクセルのセル幅を自動調整するマクロを作ってみました。
サイトを調べると、単純なセル文字数だけをカウントしてセル幅を調整するサンプルしかなかったので下記を考慮したマクロを作ってみました
(文字の長さを単純にカウントすると、半角文字も全角文字も1文字としてカウントされてしまいます)
・日本語(全角文字列)を考慮する
・フォントサイズを考慮する
・フォント自体のピクセルサイズ

例えば↓のようなエクセルがあり、セル幅を自動調整してくれます。

元ファイル(width_before.xlsx)
![before.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506495/71f9b813-95ef-96fc-73d3-199796cab7ef.png)

変換結果ファイル(width_result.xlsx)
![result.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506495/3eff7c01-3eed-6a23-4d87-2df3b26d824e.png)

###作ったプログラム

```adjust_width.py
import openpyxl
from unicodedata import east_asian_width

width_dict = {
  'F': 2,   # Fullwidth
  'H': 1,   # Halfwidth
  'W': 2,   # Wide
  'Na': 1,  # Narrow
  'A': 2,   # Ambiguous
  'N': 1    # Neutral
}

Font_depend = 1.2

def sheet_adjusted_width(ws):
    # set column width
    for col in ws.columns:
        max_length= 1
        max_diameter = 1
        column= col[1].column_letter # Get the column name
        for cell in col:
            diameter = (cell.font.size*Font_depend)/10
            if diameter > max_diameter:
                max_diameter = diameter
            try:
                if(cell.value == None) : continue
                chars = [char for char in str(cell.value)]
                east_asian_width_list = [east_asian_width(char) for char in chars]
                width_list = [width_dict[east_asian_width] for east_asian_width in east_asian_width_list]
                if sum(width_list) > max_length:
                    max_length= sum(width_list)
            except:
                pass
            ws.column_dimensions[column].width= max_length*max_diameter + 1.2

if __name__ == "__main__":
    wb = openpyxl.load_workbook("width_before.xlsx")
    ws = wb["Sheet1"]
    sheet_adjusted_width(ws)
    wb.save("width_result.xlsx")
```

課題点として
・フォントは固定でセル毎にフォントが異なると対応できない
・セルの中にある文字毎にフォントサイズが異なる場合に対応できない
・セルの中に改行があった場合に対応できない

次は改行があった場合の改造を入れてみたいと思います。

プログラムに参考にした記事
https://qiita.com/github-nakasho/items/62eaba26d5ee4f13a8ac
https://gist.github.com/harhogefoo/db69351789dfa2f60e9c5832eef24b13
Python タプル

#はじめに
基礎から定着させていこうということでタプルについてまとめました。
Python 3.8.2

#タプルの作成
```python:tuple.py
t = (1,2,3,4,5)

print("t is",type(t))
print(t)
```

```:出力結果
t is <class 'tuple'>
(1, 2, 3, 4, 5)
```

要素が一つでもタプルは作成できるが、「,」を忘れずに

```python:tuple.py
t1 = (1,)
t2 = 1,

print("t1 is",type(t1))
print(t1)
print("t2 is",type(t2))
print(t2)
```

```:出力結果
t1 is <class 'tuple'>
(1,)
t2 is <class 'tuple'>
(1,)
```

#タプルの要素の追加
```python:tuple.py
t = (1,2,3,4,5)
print(t[0])
t[0] = 10
```

タプルに要素を追加しようとするとエラーが発生する

```:出力結果
1
Traceback (most recent call last):
  File "tuple.py", line 15, in <module>
    t[0] = 10
TypeError: 'tuple' object does not support item assignment
```


#タプルのスライス
```python:tuple.py
print(t[1:4])
```

```:出力結果
(2, 3, 4)
```

#タプルの結合
```python:tuple.py
t = (1,2,3) + (4,5,6)
print(t)
```
要素を追加したければ新しいタプルを作成する

```:出力結果
(1, 2, 3, 4, 5, 6)
```

#タプルのアンパック
```python:tuple.py
t = (1,2,3)

x,y,z = t
print(x,y,z)
print("x is",type(x))
```

```:出力結果
1 2 3
x is <class 'int'>
```

#タプルを使った入れ替え
```python:tuple.py
a = 1
b = 2
a,b = b,a
print(a,b)
```

```:出力結果
2 1
```

詳しく見てみる

```python:tuple.py
a = 1
b = 2

print("a is",type(a))
print("b is",type(b))
#b,aとすることでタプルにしている
n = b,a
print("n is",type(n))
a,b = n
print(a,b)
```

```:出力結果
a is <class 'int'>
b is <class 'int'>
n is <class 'tuple'>
2 1
```
以上
Singularityの中でCUDAのバージョンがホストのものになる問題の解決 (singularity 3.9以降の新機能)

## Singularityとは
Dockerなどより気軽に使えるコンテナのキットです。root権限やrootを使わないときもUID周りの煩雑な設定が不要であったり、homeがすでに共有されていたりと便利なことが多く、使っている人も多いと思います。
今まででもGPUのサポートがあったのですが、CUDAなどのバージョンがホスト固有のものになってしまう問題が最近解決されそうで、ますます使いやすくなってきています。この記事ではその新機能について紹介します！

## Singularityでコンテナを使うときのCUDAについて
デフォルトでは、Singularityはnvidia-container-runtimeを使わないため **CUDAのバージョンがホスト固有のバージョンに固定** されています。
なので、例えばコンテナ内でCUDA11.2でたとえコンテナ内にCUDAが入っていたとしてもホストがバージョン11.4の場合はホストのCUDAが利用されるためバージョン違いでコンテナ内でアプリケーションが動かないということがあります。

Singularity 3.9からnvidia-container-cliの機能がサポートされたことによりこの問題は解決されそうになっています（2021年12月4日現在ベータ機能）従来のレガシーな方法だとCUDAを複数バージョンホストに入れる必要があり、ホストのCUDAを複数バージョン管理するのはコストが高かったです。

これは画期的なことです。コンテナに含まれているCUDAを使えるベータ機能を使ってみます。

## 解決法、導入方法
Singularity 3.9以降で実装されたcuda-container-cliの機能を有効化して、コンテナ内でCUDAを参照できるようにします。
今回はUbuntu上でVMを立ててGPUパススルーをして、その中でRocky Linuxで導入しましたが、どの環境でも同じように使えると思います。A100のDGX-Station（デスクトップ）で導入しています。

1. あらかじめnvidia-container-runtimeをホストにインストールしておきます。
1. バージョンが3.9以降のソースコードやrpmを取ってきて、インストールします。
1. nvidia-container-cliのpathを通します。ここでのpathは検索パスではなく、実際のバイナリまで記述します。`/etc/singularity/singularity.conf` の中で、設定を見つけて追記しておきます。パスが通ってないと起動時にエラーが出ます。
1. 起動するとき、この機能はデフォルトでは無効なので `--nvccli` のフラグと一緒に起動します。
    補足で `singularity.conf` ファイルを書き換えればデフォルトで有効にすることもできます。

この方法はベータ機能ですが、待ちに待った昨日というか、ないと困りますよね？
正式な機能になったらこのフラグをデフォルトにして運用してもいいかもしれませんね。

## 参考ドキュメント
Singularity 3.9のGPU周りのドキュメント：https://sylabs.io/guides/3.9/user-guide/gpu.html

では快適なSingularity生活を。
neosでlogix その15

# 概要

neosでlogixやってみる。
練習問題やってみた。

# 練習問題

fizzbuzzを求めよ。

# 写真

![2021-12-04 02.13.06.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/9ee3fa7c-a33d-f7c1-3328-3085bd4dca33.jpeg)


以上。
「React」はUMDグローバルを指しますが、現在のファイルはモジュールです　の解決


## 背景
以下のサイトでreact, typescriptでのテンプレートを作成したところ、タイトルにもある
「「React」はUMDグローバルを指しますが、現在のファイルはモジュールです」
が表示されていたので、色々調べた。
https://ics.media/entry/16329/#webpack-ts-react


## 解決策
参考にあげるサイトで
>このエラーメッセージはTypeScriptコンパイラからのものです。 React 17の新しいjsxトランスフォームは、現在Typescript 4.0ではサポートされておらず、4.1でサポートされる予定

>typescript 少なくともバージョン4.1のバージョン
react そして react-dom 少なくともバージョン17の
tsconfig.json 持っている必要があります jsx のcompilerOption react-jsx または react-jsxdev

ということで

```
// tsconfig.json
{
  "compilerOptions": {
    ...
    "jsx": "react-jsx"
    ...
  },
}

```
としたら解決した


### 参考
https://www.fixes.pub/program/192440.html
Qiitaの体験最大化を目指した組織体制の紹介

この記事は[Qiita株式会社 Advent Calendar 2021](https://qiita.com/advent-calendar/2021/qiita)の 5 日目の記事です！
Qiita株式会社 プロダクト開発グループの@getty104が担当します

## この記事は何
Qiita株式会社は9月に、Qiitaの価値を今まで以上に高めるための組織を作るため、体制の見直しを行いました。
この記事では、現在Qiita株式会社がどのような組織体制でQiitaの運営をおこなっているのかの紹介を行います。

## 組織体制の紹介

現在Qiitaは主に以下の組織で運営されています。

- プロダクト開発グループ
- CX向上グループ
- プロダクトマーケティンググループ
- セールスグループ

これらの組織について説明を行なっていきます。

### プロダクト開発グループ
プロダクト開発グループは、Qiita株式会社のミッション「エンジニアを最高に幸せにする」に基づき、QiitaやQiita Jobsの新機能開発やQiita株式会社として行っていきたい施策や開発を行っている組織です。
メンバーはエンジニアとデザイナーで構成されています。

最近では以下のようなアップデートを手がけていました。

- [Qiitaアドベントカレンダーのリニューアル](https://qiita.com/advent-calendar/2021)
- [Qiitaのトップページのアップデート](https://blog.qiita.com/qiita-toppage-202110-beta/)

### CX向上グループ
CX向上グループもプロダクト開発グループと同じくQiitaの開発と改善を行っています。
プロダクト開発グループと大きく異なる点は名前の通り「顧客体験」にフォーカスし、ユーザーからの信頼を得られるプロダクトを目指した行動を行っている点です。
CX向上グループは基本的にユーザーに求められているものや機能自体の使い心地などをユーザーのフィードバック起点で行っています。
また、ユーザーとのコミュニケーションを積極的に行えるような場づくりや発信を行なっています。

最近では以下のようなアップデートを手がけていました。

- [GitHub Discussionsの運営](https://blog.qiita.com/qiita-discussions-public-beta/)
- TwitterでのQiita公式アカウントを用いたユーザーとのコミュニケーション
- [リリースノートに記載の改善](https://qiita.com/release-notes)

### プロダクトマーケティンググループ
プロダクトマーケティンググループは、プロダクト開発グループとともに、Qiitaの価値向上や事業成長を目指した施策を実行している組織です。
プロダクトマーケティンググループはビジネスメンバーで構成されています。

最近では以下のような施策を行っていました

- [11/1に行ったQiita Advent Calendar 2021 キックオフLIVE](https://increments.connpass.com/event/227412/)
- [トップコントリビューターとコラボしたQiita主催カレンダー](https://qiita.com/advent-calendar/2021/categories/qiita_official)
- [Qiitan巨大化キャンペーン](https://qiita.com/advent-calendar/2021/campaign)


### セールスグループ
セールスグループは「企業とユーザーを繋げる」ことを目的とした組織です。企業とユーザーをつなげ、双方にとって価値のある体験づくりを行っています。基本的にスポンサーとして協賛いただいているようなイベントはセールスグループが手がけています。

最近では以下のようなイベント等を手がけていました。

- 企業様協賛の記事投稿キャンペーン
- [プレゼントカレンダー](https://qiita.com/advent-calendar/2021/present-calendar)


## このような組織体制になった背景
このような組織体制になる前は、Qiitaの運営は

- プロダクト開発グループ
- セールスグループ

のみで行っていました。
しかしこの体制にはいくつかの課題がありました。
課題とは以下の通りです。

- ユーザーとの対話と事業成長を天秤にかけながら優先順位づけ、開発をおこなければならない
- プロダクトを成長させる、ユーザー体験を高めるための施策を回す組織が存在しない

そのため、新しい体制では行えているようなユーザーコミュニケーションをとった開発と事業成長を目指した開発を一緒に回していくことや、ユーザーが楽しむためのイベント運営やキャンペーンなどを行うことができませんでした。
そのため、以下のような現象が起こっていました。

- 事業成長を目指した開発を行っているときに、ユーザー体験向上を目指した開発が行えない→その期間運営がプロダクトを放置しているように見えてしまう
- ユーザーとのコミュニケーションをとる機会が少ない→運営が不透明になり、不信感が強まる

Qiitaはプロダクトを信頼し、共感をしてくれる人が集まることで成り立つサービス、コミュニティです。
本来であればユーザーとのコミュニケーションや発信は絶えず行っていく必要があります。
ユーザーにとって価値を感じ続けてもらうプロダクトづくりを行うためにも、組織体制を大きく見直し運営を行っていくことを決めました。

## 体制変更後の変化
体制を変えて間もないですが、すでにいくつかの変化がありました。
変化は以下の通りです。

- ユーザーとの対話を常に行える体制になった
- プロダクト成長を目指した開発に対しても、「ユーザー目線」としてのCX向上グループからフィードバックをもらうことができるようになった
    - 作っているものがユーザーにとって価値のあるものになっているか
    - 不信感のあるコミュニケーションをとっていないか
- プロダクト自体の成長のために、コミットできるビジネスメンバーが増え、開発にとどまらない企画や施策を行えるようになった
    - アドベントカレンダーのイベントやキャンペーンなど

## まとめ
このようにQiitaの運営は新しい体制で、運営を行っています。
書いている内容についてより詳しく聞きたいと思った方は、↓からカジュアル面談を申し込んでいただくと、より色々お話しできると思います！

https://meety.net/articles/t2--h6croouig1ma


Qiita Advent Calendar 2021 の 6 日目は、
Qiita株式会社プロダクトマーケティングGの中泉（@zumi0）が担当します！
CLIでツイートするだけのgemを作った

本記事はエイチームフィナジーアドベントカレンダー4日目の投稿です。
ちいさいgemを作ってはじめて公開したお話になります。

# ツイートするだけのシンプルなツールが欲しかった

普段プライベートで開発や調べ物をしてるときに、作業内容をメモがてらTwitterにつぶやいたりしています。そういうときはだいたいターミナルを開いて作業してるので、いちいちTwitterクライアントに切り替えるのがめんどくさいです。なのでターミナルから使えるCLIのクライアントをいくつか使ってるのですが、たいてい高機能で個人的にほぼ使わない機能がいっぱいあって、もっとシンプルなのが欲しいなと常々思っていました。

# gemを作って公開してみたかった

業務でRailsアプリをメンテしてたりプライベートでRails製の個人サイトを運用してたり、普段からRubyによく触れています。当然gemの導入やコードを読むこともありますが、gemを作って公開したことはありませんでした。
ちょうどいいのでgemとしてリリースしてみることにしました。

# 作ったgem「twee」

tweeというgemを作りました。

https://rubygems.org/gems/twee

`gem install`して、`twee`を実行して出力されるURLにブラウザでアクセスして、表示されるPINコードをコピーして貼り付ければ設定完了です。

```shell
$ gem install twee
$ twee
Please access this URL      : https://twitter.com/oauth/authorize?oauth_token=xxxxxxxxxxxxxxxx
Please enter the PIN code   : 
```

# できるのはツイートだけ

`twee`に文字列を渡すと、それがそのままツイートされます。

```
$ twee おなかすいた
200
```

もし文字列がスペースや改行を含む場合は`"`で囲むなどしてください。
コマンド実行時に表示される数字はTwitter APIからのレスポンスコードです。`200`ならツイート成功です。それ以外の場合はツイートできていないと思われるので、文字列を修正したりして再度実行してみてください。どうにもならない場合はよろしければGithubのIssuesまでご報告ください :pray: 

https://github.com/okonomi/twee

# gemの作成と公開はかんたん

gemの作成と公開で躓くところはとくにありませんでした。
`bundle gem`で生成される雛形を編集して`bundle exec rake release`でrubygems.orgに公開完了です。
雛形でGithub Actionsのワークフローも生成してくれるのは、そのへん不慣れな自分には助かりました。

あえて言えばgemの名前を考えるのが一番難しかったです。

# おわりに

CLIでツイートするだけのgemを作って公開したお話でした。
今回はじめてgemを公開できて、個人的にgem公開の心理的ハードルが下がったのがよかったです。
まだリリース手順など小慣れてないところがあるので、tweeをメンテしつつ理解を深めたいと思います。
[pytorch / Colaboratory] "RuntimeError: Deterministic behavior was enabled with either ..." 発生

# Summary

ColaboratoryのGPU環境を使っている際に、pytorch(pytorch lightning)で`pytorch_lightning.Trainer(.. , deterministic=True, ..)`を実行したところ、次のようなRuntimeErrorが発生した。

```bash
RuntimeError: Deterministic behavior was enabled with either 
`torch.use_deterministic_algorithms(True)` or `at::Context::setDeterministicAlgorithms(true)`,
but this operation is not deterministic
because it uses CuBLAS and you have CUDA >= 10.2.

To enable deterministic behavior in this case,
you must set an environment variable before running your PyTorch application:
CUBLAS_WORKSPACE_CONFIG=:4096:8 or CUBLAS_WORKSPACE_CONFIG=:16:8.

For more information, go to https://docs.nvidia.com/cuda/cublas/index.html#cublasApi_reproducibility
```

これに対処する。

ちなみに、ColaboratroyのGPU環境というのは、この設定をすることで使えるよ。

![2021-12-04_10h58_23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327407/a8fc1f7d-a55e-200d-1e40-ed42185eeaf7.png)


# Resolution

## 0. エラーメッセージを読む

> To enable deterministic behavior in this case,
you must set an environment variable before running your PyTorch application:
CUBLAS_WORKSPACE_CONFIG=:4096:8 or CUBLAS_WORKSPACE_CONFIG=:16:8.

「この場合に `deterministic behavior` を有効化するためには、PyTorchを実行する前に環境変数:`CUBLAS_WORKSPACE_CONFIG=:4096:8` 又は ` CUBLAS_WORKSPACE_CONFIG=:16:8`を設定する必要があるよ。」

## 1. 環境変数の設定

というわけで、環境変数を設定してみよう。
この記事の通りにやってみる。

https://qiita.com/sakaia/items/c8367e75d9c8fd38e7bf#%E7%92%B0%E5%A2%83%E5%A4%89%E6%95%B0%E3%81%AE%E3%83%81%E3%82%A7%E3%83%83%E3%82%AF%E3%82%84%E5%A4%89%E6%9B%B4

> 環境変数のパラメータ追加
>
> ```
> %env PATH=xxxxx:yyyy:zzzz
> ```

この `%env` というのを使えば設定できる模様なので、実行してみる。

```python
%env CUBLAS_WORKSPACE_CONFIG=:4096:8

# セルの下に以下のような結果が表示される
env: CUBLAS_WORKSPACE_CONFIG=:4096:8

# 本当に設定できたか確認しよう
%env

{'CLICOLOR': '1',
 'CLOUDSDK_CONFIG': '/content/.config',
 'CLOUDSDK_PYTHON': 'python3',
 'COLAB_GPU': '1',
 'CUBLAS_WORKSPACE_CONFIG': ':4096:8',  # 出来てた！(((o(*ﾟ▽ﾟ*)o)))
 'CUDA_DEVICE_ORDER': 'PCI_BUS_ID',
 'CUDA_VERSION': '11.1.1',
 'CUDNN_VERSION': '8.0.5.39',
```

ただ、このままもう一度`pytorch_lightning.Trainer(.. , deterministic=True, ..)`を実行してもエラーが発生してしまった。
なぜかはわからない。

ただの勘だけど、多分、色々読み込んだ後に環境変数を設定しても遅いんじゃないかな( ˘·ω·˘ ).。oஇ

## 2. Colaboratoryランタイム初期化

というわけで、最初からやり直してみよう。

Colaboratoryメニューの、「ランタイム」「ランタイムを再起動」をクリック。

![2021-12-04_10h57_35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327407/8eae2db9-ed23-632b-cf2f-605c45388e15.png)

すると、この部分に「再起動中」と表示される。

![2021-12-04_11h17_31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327407/e9db6ddf-3fef-cbb1-609c-c8f67c9b5cba.png)

次のように、緑色のチェックマークが出るまで待とう。

![2021-12-04_11h17_37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327407/82b9c56c-6a1b-0849-fc3d-83771cd754b1.png)

この後、先に環境変数を設定してからpythonパッケージのインポートやソースコードを実行したところ、無事エラーを回避できた( \*˙︶˙\*)وｸﾞｯ!

# 関連記事

あんまり関係ないけど、`deterministic`に関してはこの記事が詳しそう。

https://qiita.com/north_redwing/items/1e153139125d37829d2d

ちゃんと理解したくなったら読んでみようと思う。
AirflowでもYAMLでDAGを書きたい

AirflowでDAGを定義するためには、通常はPythonを使って以下のように書きます。
Pythonの機能を使うことができ柔軟性が高いですが、一方簡単なDAGを書くだけであればもう少しシンプルに書くことができると嬉しいです。

```py
# taskの定義
t1 = BashOperator(
    task_id='task_1',
    bash_command='echo 1',
)

t2 = BashOperator(
    task_id='task_2',
    bash_command='echo 2',
)

t3 = BashOperator(
    task_id='task_3',
    bash_command='echo 3',
)

t1 >> t2
t2 >> t3
```

dag-factoryというライブラリを利用すると、YAMLを使ってシンプルにDAGを記述することができます。

https://github.com/ajbosco/dag-factory

上でpythonを使って書いたDAGをdag-factoryを使って書くと以下のようになります。

```yaml
  tasks:
    task_1:
      operator: airflow.operators.bash_operator.BashOperator
      bash_command: 'echo 1'
    task_2:
      operator: airflow.operators.bash_operator.BashOperator
      bash_command: 'echo 2'
      dependencies: [task_1]
    task_3:
      operator: airflow.operators.bash_operator.BashOperator
      bash_command: 'echo 3'
      dependencies: [task_1]
```

DAGのプロパティもYAMLで設定できます。

```yaml
example_dag1:
  default_args:
    owner: 'example_owner'
    start_date: 2018-01-01
    end_date: 2018-01-05
    retries: 1
    retry_delay_sec: 300
  schedule_interval: '0 3 * * *'
```

最後に以下のPythonファイルをdagsディレクトリに配置すれば、YAMLからDAGが生成されます。

```py
from airflow import DAG
import dagfactory

dag_factory = dagfactory.DagFactory("/path/to/dags/config_file.yml")

dag_factory.clean_dags(globals())
dag_factory.generate_dags(globals())
```
【実用編】指定した個数と面数のダイスを振る

## 前書き
前々から、TRPGに少し興味があり、ダイス機能を作ってみたいと思ったので作ってみたいと思います。

## どのようなものか
コマンドで、何回振るか、そのダイスは何面あるか。を指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1940116/0a2a6c32-55b1-9705-c423-64ab6db6d20e.png)
上記は**6面**のダイスを**4回**振った時の例です。

## どういう感じなのか（概要）
どういう動作をするのかの概要を説明します。

1. ユーザーから2つの引数を受け取る（回数・ダイスの面数）
1. Discordの最大文字数は2000なので、上の引数が大きすぎたら無視する（任意で大丈夫です）
1. それぞれのダイスの目の合計数とそれぞれの目のリストの変数を初期化しておく
1. 「1」で受け取った回数の引数分繰り返し処理をする
1. 繰り返し処理の中に「1」で受け取ったダイスの面数の中を乱数で出す
1. その目をリストに追加しながら、足し続けて、合計数の変数に代入。

このような感じのコードを組み立てていきたいと思います。

## コーディング
上記の概要をコードにするとこのような感じになります。
「times」と「side」は引数として受け取るようにしてください。
このコードを自分の合うように調整していけば行けると思います。

```javascript:dice.js
		//変数の初期化
		let total = 0;
		const list = [];

		for (let i = 0; i < times; i++) { //指定された回数分繰り返し処理
			const num = Math.floor(Math.random() * side) + 1; //指定された面数の乱数
			total += num; //合計に足していく
			list.push(num); //リストに入れる
		}
```

私の開発環境では以下のようになりました。画像と全く同じ動作をさせるならばこちらになります。

```javascript:dice.js
const { SlashCommandBuilder } = require('@discordjs/builders');

module.exports = {
	data: new SlashCommandBuilder()
		.setName('dice')
		.setDescription('ダイスを振ります。')
		.addNumberOption(option => option.setName('回数').setDescription('何回降りますか'))
		.addNumberOption(option => option.setName('面数').setDescription('何面ですか')),
	async execute(interaction) {
		const times = interaction.options.getNumber('回数');
		const side = interaction.options.getNumber('面数');
		if (times > 500 && side > 10 || side > 10000 || times > 200 && side > 1000) return await interaction.reply('数字が大きすぎます。');
		let total = 0;
		const list = [];
		for (let i = 0; i < times; i++) {
			const num = Math.floor(Math.random() * side) + 1;
			total += num;
			list.push(num);
		}
		await interaction.reply(`${times.toString()}d${side.toString()} >> **${total.toString()}** *\`(${list})\`*`);
	},
};
```
以上で今回は終わりです。お疲れさまでした！
Kotlin basicタイプで初回起動時にやらないとビルドエラーになること

# 起きた問題

## One or more issues found when checking AAR metadata values:

こんなエラー文が表示されます。

```
The minCompileSdk (31) specified in a
dependency's AAR metadata (META-INF/com/android/build/gradle/aar-metadata.properties)
is greater than this module's compileSdkVersion (android-30).
Dependency: androidx.core:core-ktx:1.7.0.
AAR metadata file: /***/.gradle/caches/transforms-3/43709c06b605244e4fcdef6e5a127101/transformed/jetified-core-ktx-1.7.0/META-INF/com/android/build/gradle/aar-metadata.properties.
```

## 解決策


build.gradleのcompileSdkのレベルを31までにします。

```gradle
android {
    compileSdk 31

    defaultConfig {
        applicationId "com.****.***"
        minSdk 21
        targetSdk 31
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
```

参考:
[API レベルとバージョン対応一覧と主なトピック](https://feel-log.net/android/developer/api-level/)
M1 MacでSQL Serverを使いたい

# azure-sql-edge

(注) Dockerを使うので先にDocker for Macのインストールをして下さい。

MacでSQL Serverを使うにはMicrosoftが提供するLinux版のSQL Serverイメージを使うのが良いらしいのですが、M1 Macだとこんな感じのエラーが出て使えませんでした。

```
2019-latest: Pulling from mssql/server
Digest: sha256:a098c9ff6fbb8e1c9608ad7511fa42dba8d22e0d50b48302761717840ccc26af
Status: Image is up to date for mcr.microsoft.com/mssql/server:2019-latest
mcr.microsoft.com/mssql/server:2019-latest
WARNING: The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested
```
ググってみると、azure-sql-edgeというイメージがあることが分かったのでこちらを使ってみます。

```
docker pull mcr.microsoft.com/azure-sql-edge
```

pullが成功したらこんな感じでコンテナを走らせます。
（パスワードのところは記号付きの強力なパスワードに変更してください）

```
docker run -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=yourStrong(!)Password’ -p 1433:1433 --name sqledge -d mcr.microsoft.com/azure-sql-edge
```
docker psでこんな感じで動作していることを確認できます。

```
% docker ps
CONTAINER ID   IMAGE                              COMMAND                  CREATED          STATUS          PORTS                                                 NAMES
79b5010697ab   mcr.microsoft.com/azure-sql-edge   "/opt/mssql/bin/perm…"   53 seconds ago   Up 52 seconds   1401/tcp, 0.0.0.0:1433->1433/tcp, :::1433->1433/tcp   sqledge
```

##Azure Data Studioで動作確認

WindowsだとManagement Studioとかいう管理ツールがあるのですが、Macだと使えないので[Azure Data Studio](https://docs.microsoft.com/ja-jp/sql/azure-data-studio/what-is-azure-data-studio?view=sql-server-ver15)というものを使ってみます。こちらはLinuxやMacでも動きます。

[Azure Data Studio のダウンロードとインストール](https://docs.microsoft.com/ja-jp/sql/azure-data-studio/download-azure-data-studio?view=sql-server-ver15)

Mac版はzipファイルで提供されているので、解凍してできる Azure Data Studio.appをアプリケーションフォルダに移動します。
Azure Data Studioを起動するとこんな感じです。

![スクリーンショット 2021-12-04 10.18.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160271/10f4ebbe-edeb-d2eb-a16a-bdea9d08f94a.png)

StartのところのNew connectionをクリックすると以下の画面になるので、Serverに「localhost」、Usernameに「sa」、Passwordはコンテナ実行時に指定したパスワードを入れます。

![スクリーンショット 2021-12-04 10.31.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160271/ffcd3c05-3efb-ff75-76cf-830469cb5a0a.png)


DBの作成などはGUIで出来なさそうなので、以下のページなどを参考にしてみると良いかと思います。

[クイック スタート:Azure Data Studio を使用して、SQL Server に接続してクエリを実行する](https://docs.microsoft.com/ja-jp/sql/azure-data-studio/quickstart-sql-server?view=sql-server-ver15)

とりあえずチュートリアルそのままですが、DBの作成、テーブルの作成、データのインサートも無事できました。
![スクリーンショット 2021-12-04 10.42.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160271/af900bc5-b0fb-b059-2d12-b890196da770.png)


次はVisual Studio for Macを入れて、C#からLINQでDBアクセスにチャレンジする予定です。
HUAWEI Band 6（スマートウォッチ）でAndroidのLINE着信通知を受け取る方法

:::note info
当方はHUAWEI Band 6(Ver 11.1.2.40)とPixel 4a(Ver 12)の連携の紹介記事です。
:::

# 課題
HUAWEI Band 6でLINEの着信通知を受け取れないこと。
厳密には全く通知を受け取れないわけではなく、コール終了時の不在着信通知が届く。

<img width="480" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507537/f995d5df-16b3-d4d7-358f-8403cef053ae.jpeg">

不在着信通知を見て電話を折り返せば問題ないのかもしれない。
でも不在着信の通知を見るたびに相手の時間を30秒ほど無駄にしてしまったことに罪悪感が残る。（**自分にとって最大の課題はこの罪悪感だった**）

# 結論
標準設定ではHUAWEI Band 6で**LINEの着信通知を受け取ることができない**ので、LINE着信でMacroDroidの通知を発火して**MacroDroidの通知を受け取る。**

https://play.google.com/store/apps/details?id=com.arlosoft.macrodroid&hl=ja&gl=US


# 手順詳細
- MacroDroidアプリでマクロを作成する
<img width="480" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507537/54d6cdf6-243d-cf87-d9f0-7f3e6ff92be6.png">

1. LINE着信でマクロ実行
1. MacroDroidのオリジナル通知を表示
1. 10秒待機
1. MacroDroidのオリジナル通知を再表示

上記の流れでLINE着信中にHUAWEI Band 6に通知が2回届くようになる。
途中10秒待機しているのは10秒未満の再通知だとHUAWEI Band 6に2回目の通知が届かない為。

:::note warn
トリガー設定をする際には「常駐表示の通知は除外する」をオフにすることに注意（下画像参照）
:::
<img width="480" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507537/5dfeac9b-8251-5815-f14a-1a50e7ac5181.png">

:::note info
LINEの通知タイトルに相手の名前が入っているので活用すると便利（下画像参照）
:::
<img width="480" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507537/1191e7b8-9635-900d-7041-ddf270f73fac.png">
notification_titleの略かな。

- HUAWEI Band 6でMacroDroidの通知を受け取る設定をする
<img width="480" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507537/10ab7d31-8a76-12a8-e03f-65d5479400e8.png">

以上を設定することでLINE着信中にHUAWEI Band 6で通知を受け取ることができる。
<img width="480" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507537/b4ee18d2-536a-a27a-f8a3-987c804aad9b.jpeg">

:::note warn
バージョンによってはMacroDroidがLINEの通知を受け取れないかもしれません。
執筆時のMacroDroid(Ver 5.19.9)とLINE(Ver 11.20.0)では記事の通り挙動しております。
:::

# 参考
価格.comのクチコミ投稿を参考にした。
https://bbs.kakaku.com/bbs/J0000035633/SortID=24190399

# 余談
HUAWEI Band 6はフル充電すると半月ほどバッテリーが持つのでオススメ。

https://www.amazon.co.jp/dp/B08ZD2QNC1/ref=sspa_dk_detail_1?psc=1&pd_rd_i=B08ZD2QNC1&pd_rd_w=alvMj&pf_rd_p=86d545e6-51ff-428d-9903-b93b364247df&pd_rd_wg=DztcN&pf_rd_r=X4ZVYAFPAHJWWMGV0JD0&pd_rd_r=2461b01b-3c23-46c3-ba53-f09f4d290387&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUEyVDJMU1IxSUVGWUw5JmVuY3J5cHRlZElkPUEwNTQwNjc5WjEzOTAyUlZHTU1EJmVuY3J5cHRlZEFkSWQ9QVpDUUxaUkRDSzdWUiZ3aWRnZXROYW1lPXNwX2RldGFpbCZhY3Rpb249Y2xpY2tSZWRpcmVjdCZkb05vdExvZ0NsaWNrPXRydWU=
dxlibでjoyconを使う　その2

アドベントカレンダーに投稿する2つ目の記事です。
前回の続きとして、両手持ちさせるための関数を作りたいと思います。
前回の次回予告？ではクラスを作ると書きましたが、クラスにする意味がなさそうだったので関数群となっています。

# 前提条件
　前回と同じくjoyconを使うには、あらかじめPCとペアリングという作業をする必要があります。ネットで調べれば接続方法はたくさん出てきます。

# プログラム
　以下のプログラムを作成しました。本当はよくないのですが、掲示板の管理人さんにGetJoypadType関数を教えてもらってプログラムを修正した後にタイミング悪くjoyconのLがパソコンと正常に接続できなくなって実行確認ができていません。もし実行確認ができた人がいたら教えてください。まあ管理人さんに教えてもらう前に、無理やりjoyconがどの番号なのか手動で指定したときに問題なかったのでたぶん大丈夫だとは思います。ゲームのメインループの直前にLoadJoycon関数を使ってさえいれば後はdxlibにある関数であるGetJoypadDirectInputState関数の第一引数が無いだけで使いかたは同じです。検証もGetJoypadDirectInputState関数のサンプルをちょっと改造しただけのもので行いました。

```c++:dxlibjoycon.h
#pragma once
#include <string.h>
#include "dxlib.h"

int joyconL = 0;
int joyconR = 0;

//joyconを探す。返り値としてjoyconの数を返す。ただしLとR以外の組み合わせだとバグる。joyconを3つ以上つないでもバグる。
int LoadJoycon() {
	int num = 0;
	for (int i = 1; i < GetJoypadNum(); i++) {
		if (GetJoypadType(i) == DX_PADTYPE_SWITCH_JOY_CON_L) {
			joyconL = i;
			num++;
		}else if (GetJoypadType(i) == DX_PADTYPE_SWITCH_JOY_CON_R) {
			joyconR = i;
			num++;
		}
	}
	return num;
}

int GetJoyconDirectInputState(DINPUT_JOYSTATE *DInputState) {
	if (joyconR*joyconL == 0) return -1;
	int stateR = GetJoypadDirectInputState(joyconR, DInputState);
	if (stateR == -1) return -2;
	DINPUT_JOYSTATE DInputStateL;
	int stateL = GetJoypadDirectInputState(joyconL, &DInputStateL);
	if (stateL == -1) return -3;
	if (DInputState->POV[0] != -1) {
		DInputState->POV[0] = ((DInputState->POV[0]) + 27000) % 36000;
	}
	if (DInputStateL.POV[0] != -1) {
		DInputState->POV[1] = ((DInputStateL.POV[0]) + 9000) % 36000;
	}
	else {
		DInputState->POV[1] = DInputStateL.POV[0];
	}
	DInputState->Buttons[4] = DInputStateL.Buttons[14];
	DInputState->Buttons[5] = DInputState->Buttons[14];
	DInputState->Buttons[8] = DInputStateL.Buttons[8];
	DInputState->Buttons[10] = DInputStateL.Buttons[10];
	DInputState->Buttons[13] = DInputStateL.Buttons[13];
	DInputState->Buttons[14] = DInputStateL.Buttons[15];
	return 0;
}
```
ちなみにボタンと構造体の対応は以下となっています。
POVが

|インデックス|対応するスティック|
|:-----------|:-----------|
|0|右スティック|
|1|左スティック|
buttons配列が、

|定数|対応するボタン|
|:-----------|:-----------|
|PAD_INPUT_1|A|
|PAD_INPUT_2|X|
|PAD_INPUT_3|B|
|PAD_INPUT_4|Y|
|PAD_INPUT_5|L|
|PAD_INPUT_6|R|
|PAD_INPUT_9|-|
|PAD_INPUT_10|+|
|PAD_INPUT_11|ジョイスティック押し込み左|
|PAD_INPUT_12|ジョイスティック押し込み右|
|PAD_INPUT_13|HOME|
|PAD_INPUT_14|キャプチャーボタン|
|PAD_INPUT_15|ZL|
|PAD_INPUT_16|ZR|
それ以外は変化ありません。POVの向きはきちんと両手持ちのときの向きに修正してあります。両手持ちしたときの左のjoyconの４つのボタンは取得できませんが多分あんまり使わないかなと思い対応させてません。

# まとめ
　これで両手持ちに対応させることができます。次の記事はどうしましょうか。特に決めてないですが、もともとはjoyconの機能（ジャイロセンサや加速度センサ、IRカメラ）を使うためにdxlibの関数を使わずに自力で操作を取得するのに挑戦しようとは考えてたんですけどいうほどdxlibに関係が無いというアドベントカレンダーに追加するにはちょっと無理があることに気が付きました。一応まったく考えが無いわけではないのでちょっと色々試したいと思います。joyconのLが正常につながらない状態で試せるかはわかりませんが。
VisualStudioのPythonエディターで「行コメントの切り替え」をしたい

この記事はちょっとしたツール紹介です。

#はじめに
以前Pythonの開発はGoogleColaboratoryやVSCodeを利用しており、「行コメントアウトの切り替え」を「Ctrl + /」で行っていました。
ただ最近はVisualStudio2019で開発しているのですが、「行コメントアウトの切り替え」ができないことに気が付きました。

「編集」-「詳細」からコメントアウトなどに関連する項目があるのですが、Pythonのファイル表示時には「行コメントアウトの切り替え」がありません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/581889/57a1e605-c7ed-a69a-ee94-24744cc2ec80.png)

Pythonのファイル表示中に、デフォルトで割り当たっている「Ctrl + K, Ctrl + /」を押すと、以下のエラーとなってしまいます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/581889/a7d45597-cef4-7c08-70c3-9345f2ab3100.png)

#ツール「[Toggle Comment](https://marketplace.visualstudio.com/items?itemName=munyabe.ToggleComment)」
「拡張機能」-「拡張機能の管理」から「Toggle Comment」をインストールしてVisualStudioを再起動します。
そうすると、VisualStudioでのPython開発時でも「Ctrl + /」で「行コメントの切り替え」ができるようになります！

デフォルトで「Ctrl + /」にショートカットキーが割り当たっています。
以下からショートカットキーの変更もできます。
「ツール」-「オプション」-「環境」-「キーボード」-「編集.ToggleComment」
javascript演習　〜22日目/３０日

覚えたこと

ホバーで白い背景を作る方法
まず背景の要素を作って、

```javascript

const highlight = document.createElement('span');
highlight.classList.add('highlight');
document.body.append(highlight);

```

ホバーするa要素を取得する

```javascript
const triggers = document.querySelectorAll('a');
triggers.forEach(a => a.addEventListener('mouseenter',hightlightLink))

```

ホバーのターゲットの位置を取得して、スタイルに当てる

```javascript
function hightlightLink(){
const linkCoords = this.getBoundingClientRect();
const coords = {
        width:linkCoords.width,
        height:linkCoords.height,
        top:linkCoords.top + window.scrollY,
        left:linkCoords.left + window.scrollX
};

highlight.style.width = `${coords.width}px`;
highlight.style.height = `${coords.height}px`;
highlight.style.transform = `translate(${coords.left}px,${coords.top}px)`;
}

```



参考

https://developer.mozilla.org/ja/docs/Web/API/Document/createElement

https://qiita.com/makoto1219/items/9d5b71a792025703cdea
個人的に覚えておきたい用語集

あれなんて言うんだっけ？これどういう意味だっけ？ってのが個人的によくある用語集。

## フォントの'M'と'P'
`M`：monospacedの頭文字。等幅フォント。ex）MS P ゴシック、Migu 1M
`P`：proportionalの頭文字。等幅じゃない方のフォント。ex）MigMix 1P
WS.LEDでナイトライダー

# ナイトライダーとは？

LEDを横一列に並べ、光る位置を左右に往復させるやつ。

# ナイトライダー(デアゴスティーニ)とは？

[週刊 ナイトライダー | シリーズトップ](https://deagostini.jp/kit/)

カーアクションドラマらしい。
紹介映像の中に、光の点灯位置が左右に動く表現がみられる。
なお、よくみられるナイトライダー[要出典]とは異なり、複数の光が同時に点灯している。

# 今回作るもの

IchigoJam 1.4 から追加された、WS2812B系のLEDを光らせる`WS.LED`コマンドを用い、
LEDの点灯位置を左右に往復させる。
複数の光の同時点灯に対応する。
今回は、2個目以降の光の明るさ設定を線形に減らすことにした。

# 実装

ちょうど[今日解いた](https://atcoder.jp/contests/cpsco2019-s4/submissions/27678689)問題 [A - Swimming](https://atcoder.jp/contests/cpsco2019-s4/tasks/cpsco2019_s4_a) の解き方を応用した。
現在何ステップ目かを変数`P`で管理し、光の位置`X`を求める。
変数`I`を用い、最後尾から先頭の順に光の位置を求めていく。

参考資料：[LEDテープを光らせよう - ledtape.pdf](http://www.white.umic.jp/jypc/files/ledtape.pdf)

以下の項目を設定できる。

* `N`：光らせるLED全部の数
* `M`：同時に光らせるLEDの数
* `T`：光を動かす時間間隔 (1/60秒単位)
* `B`：設定する最大の明るさ

```
10 ' ﾅｲﾄﾗｲﾀﾞｰ
20 CLV:N=8:M=3:T=3:B=100
30 FORI=0TON-1:[I*3+1]=0:NEXT
40 Y=N-1:FOR I=1 TO M
50 X=P+I-1
60 IFX%(Y*2)<YX=X%YELSEX=Y-X%Y
70 [X*3+1]=B*I/M
80 NEXT:WS.LED N
90 P=(P+1)%(Y*2)
100 IF TICK()<T GOTO 100
110 CLT:GOTO 30
```

# 実行結果

今回は、IchigoKamuy (IchigoJam BASIC 1.4.1) で実行した。
LEDモジュールのDINは、SDAがある側の端子の一番USBコネクタから遠いところに接続すると、光らせることができた。

<iframe width="560" height="315" src="https://www.youtube.com/embed/reqfcsM7Vc0" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

# おわりに

* IchigoJamはjig.jpの登録商標です。
* IchigoKamuyは株式会社syushuの登録商標です。
[Kotlin]JetpackComposeでスクロール表示のリストを作る

# 概要
Kotlinでは従来、XML形式でUIを作成していましたが、JetpackComposeを使えばコード上でUIを表記する事ができます。
今回はそのJetpackComposeでスクロールさせることの出来るリストを作ってみました。

JetpackComposeに慣れている方は＠Composable以降を既存コードへコピペして確認してみてください。

# 本文
新規のKotlinファイルを作ります。テンプレートはEmptyComposeActivityを選んでください。
![スクリーンショット 2021-12-04 9.17.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/f72f35b3-78c2-13d0-4478-ff1c909ac617.png)

最初に表示されるMainActivity.ktを書き換えます。


```kotlin
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            ScrollBoxes()
        }
    }
}

@Composable
fun ScrollBoxes() {
    Column(
        modifier = Modifier
            .fillMaxWidth()
            .fillMaxHeight(0.3f)
            .verticalScroll(rememberScrollState())
            .background(Color.Blue)
            .padding(15.dp,0.dp),

    ) {
        repeat(30) {
            Text(
                text = "リスト項目: $it",
                fontSize = 22.sp,
                color = Color.White,
                modifier = Modifier.clickable {
                    // 項目が押された時の処理
                }
            )
        }
    }
}
```

実行するとリストが表示されます。
![スクリーンショット 2021-12-04 9.48.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/01a20584-30ba-45c4-11ec-ac6e16aec8e8.png)


# 補足
デザイン用に余分な項目も加えていますが、ポイントは

```kotlin
modifier = Modifier.verticalScroll(rememberScrollState())
```
の部分だけです。
BastilleBSDでローカルパッケージ

Broadcomなどの古いmips socをベアーメタルで利用するためのgcc4のreviewを出しているのですが、誰も見てくれないうちにpatchが当たらなくなっています。

https://reviews.freebsd.org/D29804

このportsはdevel/arm-none-eabi-gcc492を親にしていてこれのMakefileが変更されてしまっているのでpatchがrejectされています。

仕方ないので、ハンドパワーでpatchを当ててビルドしてみます。

これを利用するmruby on YABMのBCMポートはBastilleBSDのjailでビルドするつもりなのですが、このportsのビルド自体もBastilleBSDのjailの中で行います。ユーザーアカウントでビルドするので依存のパッケージはbastille pkgでインストールします。

makeしてビルドが通ったらmake packageします。そうするとwork/pkgのディレクトリにpkgファイルが出来上がるので、それを/tmpにコピーしておきます。

FreeBSDのパッケージシステムはFreeBSD 10くらいで入れ替わったのですが、入れ替わった時はパッケージファイルの拡張子はtgzからtxzに変わっていたと思います。それがいつの間にかpkgに変わっていました。

ホストに戻り

```
% sudo bastille pkg vnetjail add /tmp/mips-gcc492-4.9.2_5.pkg
```

します。

~~レビュー誰か見てくださいって、直さんとダメだけど、Phabricator詳しくないので、上げなおしたほうが早いような気もします。~~ 諦めました。
mini_racerのインストールが、依存関係にあるlibv8で失敗する

## mini_racerのインストールで失敗する
Railsあるある
依存関係にあるlibv8のインストールで失敗しているみたい。
(mini_racerのgemアップデートも同じこと起きやすいです)

```
An error occurred while installing libv8 (8.4.255.0), and Bundler cannot continue.
Make sure that `gem install libv8 -v '8.4.255.0' --source 'https://rubygems.org/'` succeeds before bundling.

In Gemfile:
  mini_racer was resolved to 0.3.1, which depends on
    libv8

```

エラーログを見ていくと以下辺りが怪しそう。

```
Error: Command 'vpython third_party/depot_tools/update_depot_tools_toggle.py --disable' returned non-zero exit
```

```
could not resolve options: failed to resolve Python script: stat
```

issueも挙がっていた！
https://github.com/rubyjs/libv8/issues/310

## 試したことはbundlerのアップデート
issueを見る限り、bundlerのバージョンが〜〜と書いてあったので、
bundlerのバージョンを上げてみる。
自分が使っていたbundlerのバージョンは2.1.4だった。

```
% bundler -v
Bundler version 2.1.4
```

最新版のbundlerをインストールする。
（自分の場合は、他プロジェクトに合わせたかったので、最新版ではなくバージョン指定でインストールしました。基本的には最新のもので良いと思います）

```
% gem install bundler -v 2.2.8
Fetching bundler-2.2.8.gem
Successfully installed bundler-2.2.8
Parsing documentation for bundler-2.2.8
Installing ri documentation for bundler-2.2.8
Done installing documentation for bundler after 13 seconds
1 gem installed
```

インストールされたことを確認

```
gem list bundler

*** LOCAL GEMS ***

bundler (2.2.8, 2.1.4, default: 1.17.2)
```

デフォルトは最新のものになるみたい

```
% bundler -v
Bundler version 2.2.8
```
早速、mini_racerをアップデートしてみる

```
Using launchy 2.5.0
Installing libv8-node 16.10.0.0 with native extensions
Using xpath 3.2.0
Using rubocop-ast 1.14
```

インストールできた！
(コンパイラが動くので結構時間かかりました)

## 結論
自分の場合は、bundlerのバージョンが原因だった。

めちゃくちゃ苦しめられたエラーだったので、突破できてよかったです。
3分de名著 / 設計書・仕様書レビューに関するJIS規格

##はじめに
2021年11月22日に経済産業省でシステム開発において重要な設計書・仕様書のレビュー工程のJIS規格が制定された。

https://www.itmedia.co.jp/news/articles/2111/22/news148.html

[JISC公式HP](https://www.jisc.go.jp/index.html)にてユーザー登録してJIS規格番号:JISX20246で検索すれば誰でも規格原文を読むことも可能です。
PDFにして40ページ程度なので苦労しないと読めないような代物ではありませんが、この記事では当該の原文を斜め読みした気分になれる概説を書いていこうと思います。

##概説

####序文
レビューの主な目的は要検討事項の検出・代替案の評価・組織及び個人のプロセス・作業生産物の改善である。
ソフトウェア開発において現場ごとに多種多様な開発手法やプロセスが採用されているが、そのような現場に対しても導入・適用が可能なレビューに関する汎用的なフレームワークについてこの規格で規定している。

######1.適用範囲、2.引用規格、3.用語及び定義、4.適合性は省略

####5.作業生産物レビュー
一般にレビューは作業生産物の欠陥を早期に検出することを主目的とし、参加者数やその役割・レビュー回数などのレビュー属性に応じて最適なレビュー種別を選択する。

※レビュー種別例

<dl>
  <dt>執筆者確認</dt>
  <dd>作業生産物の執筆者によって実施する非形式的レビュー<br>執筆者・レビュアによって要検討事項の検出と開発リスクの低減を目的とする</dd>
  <dt>相棒確認</dt>
  <dd>執筆者の同僚によって独立して実施する非形式的レビュー<br>執筆者・レビュア・レビューリーダーによって要検討事項の検出と新規アイデアの発見を目的とする</dd>
  <dt>インスペクション</dt>
  <dd>チームの役割を定義した上で行う形式的レビュー<br>執筆者・レビュア・レビューリーダー・進行役・読み上げ係・記録係によって要検討事項の検出や品質評価、改善の動機付けを目的とする</dd>
</dl>

####6.作業生産物レビュープロセス
基本のプロセスは下記の流れで進める。　

<dl>
  <dt>計画作業</dt>
  <dd>レビュー目的・対象・終了基準・重点領域などを定義</dd>
  <dt>レビューの立ち上げ</dt>
  <dd>レビューリーダーからレビュー参加者にレビュー範囲・特性・役割を説明<br>執筆者が作業生産物を説明</dd>
  <dt>個々人のレビュー</dt>
  <dd>各レビュアが作業生産物の要検討事項を識別するためのレビューを実施</dd>
  <dt>要検討事項の共有及び分析</dt>
  <dd>識別された要検討事項を伝達<br>伝達内容が要修正か修正不要かを分析<br>要検討事項をチーム内で割り当て</dd>
  <dt>修正作業及び報告作業</dt>
  <dd>修正を必要とする要検討事項に関するインシデント報告書を作成・チーム内に伝達<br>執筆者が要検討事項を対処<br>レビュー処置の完了を報告・確認</dd>
</dl>

####7.レビュー手法
先述の個々人のレビューにおける手法は多岐にわたる。

**●アドホックレビュー作業**
進め方や指針を全く構造化・形式化していないレビュー手法で非常に一般的な手法である。
作業生産物を読み進めながら各レビュアがあらゆる種類の要検討事項を可能な限り見つけることが期待されているため、**レビュアのスキルに大きく依存したり要検討事項の指摘内容が重複したりする。**

**●確認項目一覧に基づくレビュー作業**
各レビュアに確認項目を割り当てて作業生産物を網羅的にレビューする手法である。
指摘内容の重複を防げる一方で、**レビュー対象の検討が確認項目一覧で挙げた内容に終始する傾向になるためその他の潜在的な要検討事項を見落とす可能性があり、**レビュアが確認項目のみに従ってレビューするのではなくより広くチェックする自覚を持つ必要がある。
また、確認項目が古くなり要検討事項の発見が少なくなる(見逃す)リスクもあるため、定期的に確認項目を更新する必要がある。

**●シナリオに基づくレビュー作業**
単純な確認項目一覧よりも詳細な欠陥検出のため読み取り指針をレビュアに周知させた上で、レビュアが対象の作業生産物を予想される使用法に基づいて予行演習し要検討事項を検出する手法である。
必要な機能そのものがレビュー対象に含まれていないなどシナリオによっては特に標的とされない部分の欠陥を見落とす可能性がある。

##まとめ
* ハウトゥーではなくあくまで規格なので、特定のやり方を薦めるのではなく淡々と列挙している。
* 型張った文章なので明確な理解がしづらかった。
* レビューを通しての本来の目的・ゴールの意識を持つ重要性が繰り返し説かれている。
* 現場の人数やスキル・開発期間などの要因から厳密に規格に則ったやり方を粛々と進めるのはやはり難しそう。定義された内容のいいとこ取りするために規格を利用するくらいの意識がちょうど良さそう。
GitHub Actions にタイムアウトを設定しておいた方が良い

#はじめに
こちらの記事は [GitHub Actions Advent Calendar 2021](https://qiita.com/advent-calendar/2021/github-actions) の11日目の記事です。他の皆様の投稿もぜひご覧ください！

この記事では、GitHub Actions のジョブのタイムアウトの設定の仕方を紹介していきます。

#ジョブのタイムアウトのデフォルト
GitHub Actions のジョブのタイムアウトの時間は、デフォルトで**6時間**です。

>Job execution time - Each job in a workflow can run for up to 6 hours of execution time. If a job reaches this limit, the job is terminated and fails to complete.

参考: https://docs.github.com/ja/actions/learn-github-actions/usage-limits-billing-and-administration#usage-limits

なんらかの原因でワークフローの実行が失敗もせずに止まってしまうことはどうしても起こると思うのですが、その際に気づかなかった場合(&タイムアウトの時間がデフォルトのままだった場合)、6時間も時間を消費してしまいます。

夜中に動かしているものだとなかなか気付きませんよね。私はタイムアウトのデフォルトが6時間ということを認識しておらず、朝ワークフローが失敗しているログを見て「360 minutes !?」となりました・・・。

#タイムアウトの設定方法
ジョブに対してと、各step個別に対しての、2つの方法でタイムアウトを設定できます。

### ジョブに対して
参考: https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions#jobsjob_idtimeout-minutes

```yml
jobs:
  my-job:
    runs-on: ubuntu-latest
    timeout-minutes: 60
    steps:
      - name: print log
        run: echo "Hello, GitHub Actions"
```

###stepに対して
参考: https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions#jobsjob_idstepstimeout-minutes

```yml
jobs:
  my-job:
    runs-on: ubuntu-latest
    steps:
      - name: print log
        run: echo "Hello, GitHub Actions"
        timeout-minutes: 5
      - name: print log 2
        run: echo "Hello, GitHub Actions 2"
        timeout-minutes: 10
```

#最後に
まずはジョブ毎に普段の実行時間 + α でつければ良いだけなので、まだつけていないという方はつけるのをおすすめします。
matlabで9軸IMUのWT901のデータを利用して3D表示する

　アマゾンで購入できる9軸IMUのWT901ボードをPCにつないで、Quaternion出力を使って3D表示をします。

###WT901
　アマゾンで入手しました。

　　[WITMOTION WT901 高精度 9 アクシス AHRS MPU9250 TTL 加速度 センサー、ジャイロ + 加速度計 + 磁力計（最大 200HZ）電子 コンパス 振動 傾斜計 モジュール Arduino とプロジェクト など 用](https://www.amazon.co.jp/gp/product/B07S21VG3G/ref=ppx_yo_dt_b_asin_title_o02_s00?ie=UTF8&psc=1)

　PCとCOMポートで接続するためにUSB-シリアル変換ボードもアマゾンで入手しました。
　　[HiLetgo 2個セット CP2102 マイクロ USB転UART TTL モジュール 6ピン シリアル コンバーター STC FT232を置換でき 並行輸入品](https://www.amazon.co.jp/gp/product/B01LXHQIF0/ref=ppx_yo_dt_b_asin_title_o01_s00?ie=UTF8&psc=1)

###接続
　上記のボードを接続します。
![wt901.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/64bfd264-636b-f013-66ca-d7c7ae7f0ee0.png)

　TXとRXはクロスします。
###クオータニオンの出力を有効にする
　デフォルトでは、ACCELERATION、MAGNETIC FILED(uT)、PRESSURE（Tempratur）、Angleの値が送られています。Windowsのソフト「Standard Software for Windows PC」をダウンロードし、設定を変更します。

　　GitHub　https://github.com/WITMOTION/WT901
　　Googleドライブ　https://drive.google.com/drive/folders/1dWvJU2Ug7MpcwTPWoARw2KJI8oYbuVEW


　Contentの設定で、全部のチェックを外し、Quaternionだけにチェックを入れます。
![wat101.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/1fcc384d-f45b-00dd-313c-0d89ec200da0.png)

###プログラム

```matlab
clear
close all;
instrreset;
s = serialport('COM3', 9600);

Q=[0 0 0 0];
figure;
while (1)
    Head = read(s,2,'uint8');
    if (Head(1)~=uint8(0x55))
        continue;
    end 
    if (Head(2) == uint8(0x59))
        Q = (read(s,4,'int16')/32768);
        %fprintf("%.4f ",Q);
    
        poseplot(quaternion([Q(4) Q(1) Q(2) Q(3)]), MeshFileName="plane3.stl",scaleFactor=0.3);
        view([50 50 -10]);

        pause(0.1);  
    end
end
```
　実行中の様子です。3Dの画像は、Windows10の中に入っているのをWebでstl形式に変換したのを使っています。
![2021-12-04 (6).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/e39bf937-1a90-57d7-8b84-baca110ce32b.png)

　この表示には、Sensor Fusion and Tracking ToolboxもしくはNavigation Toolboxが必要です。ホーム・ライセンスではNavigation Toolboxが購入できます。
AWS SAA 学習の記録 (IT未経験から1発合格、勉強ノートあり、たぶん最安)

# 概要
SAA-C02合格したのでその記録です。
僕のレベルとしては掛け値なしの初学者です。
ITの勉強を始めて3ヶ月半、ようやくブラインドタッチができるようになっていました。
[SAP-C01](https://qiita.com/hoooriiii/items/d918bc5c1b1348cea83f)にも合格しました！

# 結論
真の初心者がやるにはなかなか時間がかかります。
僕の場合は1ヶ月半かけました、1日2時間かそれ以下で途中やってない日も含んでいます。
ネットの何時間で受かる系は前提知識がある人だから参考になりませんでした。

# 使用教材
公式：無料
模擬試験（udemy）：1610円
[【SAA-C02版】AWS 認定ソリューションアーキテクト アソシエイト模擬試験問題集（6回分390問）](https://www.udemy.com/course/aws-knan/)
*本試験：15000円

# 勉強方法
とりあえず模擬試験をやりました、全6回分を極力忘却曲線に沿って復習しています。
各回につき5度ずつ解いています。
*合格点は72点以上です。

|第n回|1度目|2度目|3度目|4度目|5度目|
|:-:|:-:|:-:|:-:|:-:|:-:|
| 1 |50| 87 |100  | 89 |95 |
| 2 | 46 | 93 | 100 | 83 | 98 |
| 3 | 40 | 100|   | 80 |95 |
| 4 | 53 |100 |   | 87| 95 |
| 5 | 53|89 |  100|  93 | 95  |
| 6 | 60  |  81 | 96  | 98  |  95 |

1日目：第一回模試、1度目、点数の低さに打ちひしがれます。
2〜4日目：出てきた内容を全て公式見ながらまとめます。
[勉強ノート](https://better-queen-915.notion.site/AWS-SAA-473b1d609bab4edeb534ca7bfe0727a3)
（体系的にまとめていないのは本番対策です、間違いがあれば編集してくださると嬉しいです。
　無理に1行に書いているので読みにくいかも知れません、ご自由に編集してください。）
5日目：2度目、一度解いて復習したので満点を目指します、取れません。
6日目：3度目、ようやくほぼ満点が取れます、そして一旦忘れます。
7〜36日目：第二〜六回まで同じように繰り返します。
37〜42日目：第一〜六回、4度目、想定通り忘れて点数が下がります、あくまで想定通りです。
43〜45日目：第一〜六回、5度目、満点が取れず詰めが甘いですが、記憶の定着を確認します。
試験前日〜当日朝：くろかわこうへいさんの想定問題を解き、問題文の形式の違いに焦ります。

# 試験

どの模試、想定問題よりも問題文が長く、最初の15分くらい何も解けずに次へをクリックし続けます。
途中から復帰しましたが試験時間2時間近く使ってしまいました、模試を解いている時は平均40分くらいで解いていました。

# 感想
ネットには強い人がたくさんいて、その人たちと比較しても意味がないことを再確認しました。
試験勉強においては、教材を絞って精度を上げることが大切だなと感じました。
僕の観測範囲においては、試験に強い人はたいてい参考書がボロボロになるまでやり込んでいるように思います。