OmniAICreator/Qiita-1.07M huggingface dataset:
IKやPBDでの角度制限用の拘束条件

※自分用メモです

IKやPBDでは、間接の角度制限を実装するための拘束条件を設定するために、各関節の位置を変更した際の勾配を式として与える必要があります。
論文だとサラッと流されちゃうんですけど、この式を得るのは数式と日常的に格闘しているわけではない一般人感覚からすると結構面倒です。
なので導出も含めて覚書を残しておきます。

---
### §1. ３つの点が成す角度
まず単純化して、三つの点が成す角度について考えてみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1697816/b9947169-df1c-91b0-193e-8d62ecd2a5fd.png)
このとき、角度θは
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1697816/f5e0fadf-be86-b1d1-6e1f-7b7012a6bedf.png)
と表せられます。
これを各変数について偏微分すると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1697816/2f78d0db-287b-0abe-a7d0-917faeeab960.png)
こうなります。
これでこの単純なモデルでは、各関節についての∇が計算できそうです。

### §2. 多関節モデルへの適応

実際には上記のような単純なモデルではないので、これをもとに多関節＆初期姿勢のあるモデルを考えてみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1697816/7062c2bc-aeb5-c5c5-8c6d-e6fb650572be.png)
A(親)からB(子)へ向かって親子付けがされた関節だとします。
このモデルでは初期姿勢を考慮するので、各関節ごとに現在位置と安定位置（初期姿勢の位置）があります。
ここからどれだけ変位しているかをθとすることで、上図のように表すことができます。
３次元でも変位の方向は必ず二次元化できるので同様に考えることができます。

ただし実際にはSを直接動かすことはできず、Sを動かすにはAの親 C を動かす必要があります。
これを表現するために、θではなくφを使用して次のように考えます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1697816/627c6647-fa45-bc92-1b5f-e23582c0c2dc.png)
C-A-B が成す角度を φ 　安定角度を φ0 とします。
３次元の場合は、回転平面 A-B-S が成す平面上に射影した位置をCとして考えます。

こうすると§1の式がそのまま使えて
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1697816/73200f07-e7ed-60b0-4df3-09b248064994.png)
こうなります。
見やすくするために新たにP,Qを定義しました。

さらにT,Rを定義して整理すると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1697816/0b9e5865-96f9-29d5-371c-8c4ef8df26a6.png)
こうなります。
大分シンプルになりました。

### §3. ３次元での一般的な形

§2で得た式から、３次元で使用する場合のより一般的な形を考えます。
まず§2で使用したこの図の
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1697816/627c6647-fa45-bc92-1b5f-e23582c0c2dc.png)
A,B,C,S のそれぞれの三次元上での位置を A3,B3,C3,S3 とすると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1697816/3bcc4903-35c6-8ffa-5cfb-eea80a9991c0.png)
となる。
U,V は、この回転平面を構築する座標軸です。

### §4. PBDでの拘束条件
ではこれを用いた拘束条件の例として、[PBD](https://matthias-research.github.io/pages/publications/posBasedDyn.pdf) での角度制限を考えてみます。

拘束条件 Cj は φ が φ0 であることなので、§2,§3の式を使用して
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1697816/25146820-19fe-d8d0-b11a-8bb56a48e18e.png)
勾配は
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1697816/b7e3389a-8135-f922-e527-145a978d09fc.png)
となる。


---
### 追加メモ
微積を計算するときは[WolframAlpha](https://www.wolframalpha.com/)
数式や図を描くときは[Mathcha](https://www.mathcha.io/editor)
を使用すると便利です。

PBDの論文はこちらです
PBDの論文:https://matthias-research.github.io/pages/publications/posBasedDyn.pdf
XPBDの論文:https://matthias-research.github.io/pages/publications/XPBD.pdf
XPBDの和訳をされている記事：https://raw.githubusercontent.com/nobuo-nakagawa/xpbd_jp/master/XPBDjp.pdf
PBDの剛体表現について:https://matthias-research.github.io/pages/publications/PBDBodies.pdf
ISUCON11予選参加でubuntu、nginx、mysqlの知識がほぼ0の人がインフラ担当をやろうとした話

## ISUCON11に参加してきました
会社の同僚2人とISUCON11に参加したので雑記
普段全くインフラを触らず、ubuntu、nginx、mysqlの知識もないけどインフラやるぞ、となった人がどういう所でつまづくのかが書いてあるかも

## 当日まで
* ISUCON9予選をまっさらなubuntuでbench叩ける状態にした
* appとdbのサーバーを分けられるようにした
* 計測に必要そうなツールを調べておいた
    * nginx.confとmysql.confの辺りは少し見ておいた

## 当日の自分の動き方
* みんなで[予選当日マニュアル](https://gist.github.com/ockie1729/53589a0e8c979198b6231d8599153c70)と[アプリケーションマニュアル](https://gist.github.com/ockie1729/fcb41ade9cb9d2166dd3f53e5179e8a9)の読み合わせをしつつAWSにインスタンスを立てる
* trelloにあらかじめ作っておいたTODOリストを確認し誰がどれをやるをざっくり決める
* インスタンスにgitを入れてpush
* mysqlでスロークエリを吐き出してメモ
* シンボリックリンクを `/etc/mysql/mariadb.conf.d/50-server.cnf` につけてgitで見れるようにした
* mysql.confの `bind-address` を `0.0.0.0` にしてどこからでも接続できるようにした(コメントアウトするだけでいいらしい)
* appとdbのインスタンスに分ける
    * main.goとsql/init.sh、env.shの`MYSQL_HOST`をinstanceのpublic IPを指定して嵌る
    * SSH接続のPORT転送を使ってmysqlの接続権限の確認をしたり、↑で設定したものが反映されているか確認するが原因分からず
    * AWSのコンソールをぼーっと眺めていたら、ふとセキュリティ的にpublic IPではなくprivate IPじゃないとダメなのではと気付き修正して無事接続できた
* ベンチが「ユーザーは増えませんでした」「評判が悪化してユーザーが増えなくなりました」のような悲しいコメントを吐いていたので対応せねばという気持ちになり調査したが原因分からず
* ベンチ叩きながらhtopでインスタンスの状態を見てappかdbのインスタンスどちらを増やすか悩んでいたがどちらもCPU使用率が同じぐらいだったのでappを2台にしようとnginxの設定をいじる
    * nginxの設定をガチャガチャ弄っていたが全然反映されず心が折れる(後で気づくがhttp(80)の設定を弄っていた)
    * nginx.confが他にもあって優先順位的に上書きされているのではと思い調べていくとhttps(443)の設定がされているファイルを発見して編集 (17:50くらい)
    * locationとserverとupstreamの書く位置が間違っておりハマった
    * 最初設定してインスタンス再起動、ベンチ叩くで動作確認していたが`sudo nginx -t`でvalidationチェックできることがわかり↑のミスに気付く
    * ISUCONの終了時間が45分遅くなりギリギリapp×2とdb×1の編成で23696が出る
* 使用していないprocessが走らない設定を入れたり、謎processを`kill -9 PID`でお掃除
    * うっかりappのbenchから指定していたappのインスタンスのnginx processをkillしてベンチを回し0点を吐き出しメンバー全員が青ざめる
    * `sudo lsof -i -P -n`で確認して↑の通りnginxを殺したことが発覚、nginxを起動し無事競技中の最高スコア27892を出し終了
![Screen Shot 2021-08-22 at 3.39.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1031136/4b54f64a-e58c-5b3e-e8fa-91a84c66a5d4.png)

残り時間後5分ちょいで0点を出すと頭が真っ白になりますね…

## 練習と本番の違いで苦しんだこと
* AWSのサーバのセキュリティグループの設定をガバガバで実装していた為、private IP使わないといけないことに気づくのに時間溶けた
* 起動時にgoを自動で走らせており、どこにログが吐かれているのか分からずデバッグができなかった
    * killして手動で実行しようとしようとしたがENVが読み込めず

## 感想
去年はイスを温める人になっていたので今年は貢献できて嬉しい。
ISUCONは青春ですね。夏を感じました。
PHP8 で phpQuery を使う

### すぐ出るエラー おそらくPHP7以上 の対応

```
Compile Error - Array and string offset access syntax with curly braces is no longer supported in APPPATH/vendor/phpQuery-onefile.php on line 2156
```

エラーの通りソースコードを修正
2156行と2171行のエラーを修正 {数値} を [数値] へ
修正前

```php
// 2156行
if ($param{0} == 'n')

// 2171行
else if (mb_strlen($param) > 1 && $param{1} == 'n')
```

修正後

```php
// 2156行
if ($param[0] == 'n')

// 2171行
else if (mb_strlen($param) > 1 && $param[1] == 'n')
```

## この後に出るエラー

修正してもこういうエラーが出ます。

```
phpQuery-onefile.php(327): DOMDocument->loadHTML()
phpQuery-onefile.php(244): DOMDocumentWrapper->loadMarkupHTML()
phpQuery-onefile.php(191): DOMDocumentWrapper->loadMarkup()
phpQuery-onefile.php(177): DOMDocumentWrapper->load()
phpQuery-onefile.php(4857): DOMDocumentWrapper->__construct()
phpQuery-onefile.php(4631): phpQuery::createDocumentWrapper()

```

この対策はこう。　phpQuery::newDocumentの前後にこんな記述を入れます。

```php
$url = "https://xxxx.com";
$html = file_get_contents($url);

libxml_use_internal_errors( true );  // 追加
$html = \phpQuery::newDocument($html);
libxml_clear_errors();  // 追加
```

これで phpQuery が利用できます。
プログラミング学習を継続するためのコツ

#プログラミング学習の挫折率
プログラミング学習***挫折率はなんと約9割***です。
こん何も高い挫折率となっています。

#どいうい人が挫折する？
挫折する人の特徴

***1 いきなり本でやる***

***2 教えてもらえる人がいない***

***3 1人で学習すること***

これらが考えられます。

#解決策
解決策としては

***1 本でやらず動画教材や初心者向きの学習サービスを利用する。***

***2 質問に答えてもらえるメンターをつける***

***3 エンジニア向きのコミュニティなどに参加して勉強仲間を作る。***

この辺がいいと思います。

#解決策を実行しても継続できない人
上の３つを実行しても***継続できない人はやはりいます。***
じゃあどうすればいいでしょうか。

#継続するためのコツ
継続のコツは***他人にコミットして約束します***。***学習したことをアウトプットを他人にします。***
こうするとやらなければならないとなり時間が経てば習慣となっていきます。
***他人との約束があると強制力が働きます。***
Pythonの変数にてCSVデータを定義する際のインデントを削除する方法

## 概要
Databricksにてテストを実施する際などに、Pythonの変数にてCSVデータを定義するのですが、その変数からインデントを削除する方法を共有します。

変数にインデントを実施すると、そのままでは変数にインデント（スペース等）が含まれてしまいます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/b3cc8515-af28-868e-def1-c6f1aac94c17.png)

そのインデントを、inspectにあるcleandocメソッドにより除去できるようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/fada95df-618a-d345-7b36-2089f9a03976.png)
引用元：[inspect --- 活動中のオブジェクトの情報を取得する — Python 3.9.4 ドキュメント​​​​​​​](https://docs.python.org/ja/3/library/inspect.html#inspect.cleandoc)

inspectにあるcleandocメソッドを利用すると下記のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/1103583d-b6e4-de41-77c0-34d049fb02f7.png)


## コード
### 1. データを準備
```python
# データを定義
class sample:
    csv_data = """
    id,name,mail,weight, height
    1,"AAA","AAA@test.com",53.5,180
    2,"BBB","BBB@test.com",53.5,180
    3,"CCC","CCC@test.com",53.5,180
    """

print(sample.csv_data)
```

### 2. インデント等の情報を除去

```python
import inspect
print(inspect.cleandoc(sample.csv_data))
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/13d7124d-7218-1639-c2b7-ead9c4d3b217.png)

## その他の方法
### textwrap.dedentでも可能
textwrap.dedentによる方法を教えていただいたので、記載しておきます。

```python
import textwrap
print(textwrap.dedent(sample.csv_data)[1:-1])
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/8077aadc-2291-2e86-30f9-7630eca46512.png)
git push後、コミットメッセージを修正する方法

Gitでpush後、コミットメッセージが間違えていることに気づいたので、修正しました。
備忘録として記載しておきます。

```:ターミナル
$ git log
```
commitしたログが出てきます。
これで修正したいcommitの　一つ前の　commitのIDをコピーしておきます。

q　を入力で抜けます。

続いて

```:ターミナル
$ git reset --soft 【commit ID】
```

したあと、通常の流れで

```:ターミナル
$ git add .
$ git commit -m"修正したいコミットメッセージを入力"
```

これで通常通りpushしたところ、エラーが出ました。
どうやら、リモートリポジトリは最新なのに、ローカルリポジトリは元に戻していることで、
内容に相違があるためエラーになってしまうようです。

なので強制でpushします。

```:ターミナル
$ git push -f origin main
```

これでpush成功しました！



## 参考サイト
[git reset の使い方と、主要オプション](https://www-creators.com/archives/1069)
東大生に教えてわかったことと強強CTOから教わったこと(プログラミング学習のスピードが速い人と遅い人の思考)

# 概要
この記事の内容はエンジニア教育のプロでもあり、
現役のCTOの方から教わった内容です。(ここのメンターの方からです。)

https://wonderful-wife.net/w_code/

後自分の実体験をベースに解説していきます。


# プログラミング学習が遅い人の特徴

プログラミング学習が遅い人は***１つのことを学んだら１つのことしか考えない人***です。

ex)
railsの学習でコントローラーを学んだ。へーそうなんだで終わってしまう。
コントローラーがrailsでどのような役割をしているか考えられていない人です。

これだと***点と点がつながらず***ポートフォリオ作成でも共同開発でも
***今自分が何をやっているのかがわからなくなってしまいます。***

これだとかなり効率が悪いです。

# プログラミング学習が速い人の特徴(強強CTOから学んだこと)
反対に
***プログラミング学習が速い人は1つのことを学んだら
いろいろ考えを連想させて知識と知識などを繋げることができる人です。***

ex)
プログラミングに暗記は必要ないと言われたら
「暗記必要ないんだ。なんで必要ないの? 何が必要なんだ? 具体的に何をすればいいんだ?」
みたいな感じです。

こんな感じで疑問を持って、***色々知識を繋げていくことができる人***です。
***1の情報を受け取ったら3から5考えるような人***です。

実際に学習当時強強CTOの方から指摘されたことです。

# 東大生に教えてわかった東大生が学ぶ時の頭の使い方
実際にインターンの東大生に開発のことを教えている時に、***東大生が勉強している時の頭の使い方が、
プログラミング学習のスピードが速い人とほぼ同じ***だと感じました。

Gitを教えている時のことです。
Gitでプルリクエストまでの流れを教えました。よくあるのは、この流れを教えても「へーそーなんだ」で終わるのですが、東大生は違います。***自分が教えていなことまでも疑問持ってどんどん質問してきます***。
***1考えたら3考えて勉強しているイメージ***です。

東大の入試問題見たことあるのですが、ざっくりとこんな感じです。

「関ヶ原の戦いはなぜ起きて、この戦いが後世にどう影響与えたのか」
みたいな感じです。この問題が出たわけではないですが、こういう感じです。
普通の受験生は「関ヶ原の戦いは1600年に起きた、なるほど」で終わってしまいますが、
東大生は「なんで戦い起きた？誰と誰がやった？これをやったことでどうなるの？」みたいなことを
当たり前のように考えて勉強しているんだなと感じました。
上の問題もこういうふうに考えないと「何書いていいかわからん」ってなってしまいますよね。



# 実際に日本のTopのメガベンチャーの人物像にも当てはまる
メルカリはメガベンチャーのTopですが、ここの会社に社員として受かるには以下の2点だそうです。

1.技術力がぶっち切りで凄い人

2.```ミッションドリブンが呼吸するようにできる人(経営者が1考えたら10考えて動ける人)```
これなんか東大生の考え方に当てはまっていまよね。
これができるような人はエンジニアに限らず優良企業で働くことができるんだと思います。

# やらないことを決める
プログラミング学習で時間がかかってしまう人の特徴として、
***やらなくてもいいことに時間を使ってしまうのは、よくあるパターン***です。
***受験や資格の勉強でも成績が伸びない人のパターンとして、ゴールが逆算してやるべきこと***

現役の方なら先輩に、未経験の方は、メンター(結果を出している現役エンジニア)にレビューをもらってください。

この動画も参考にしてください‼︎

[【勉強術】医師免許とりながら2億稼いだ経営者の勉強法がエグい](https://www.youtube.com/watch?v=exqG5aT5eNU)

# 考えではなく実践する方法
自分も上記のことがまだできているとは言えないです。自分もまだ挑戦中です。
以下は考えよりアクションです。```アウトプットする場を作って```ください。あくまで一例です。

1. ***自分はQiitaやZennなどでドキュメントを書いてアウトプット***していきました。
```頭で考えていることややりたいことを文字にしてみる(言語化)```と理解が上がります。

2. ***何か作ってアウトプットする***
自分は共同開発やOJTプランなどを使ってアウトプットして実際にどう使われるのかを体で覚えるようにしました。

***本物の実務案件で経験を積めますし、職務経歴書に書けます***。僕もここを利用しました。

https://zero2hero.jp/

自分は受講していないですが、評判はいいみたいです。

https://yanbaru-expert.com/

こちらの方も***共同開発について言及***されています。

https://www.youtube.com/@YukihiroLaravel


# プログラミングを身につけるにはアウトプットがいい
こちらのブログを書かれている方が言及されてましたが、
***CRUD処理と認証機能などを実際に自力で作れば***、実務でも何をやっているのかわからなく
なる現象はなくなります。

実際に共同開発を経験してから実務案件に入ったのである程度は実装することはできました。
共同開発が難しい場合はCRUD処理と認証機能を使ったToDOアプリがいいみたいです。
実際自分も共同開発でCRUDと認証機能を実装してから見違えるほど成長しました。

https://read-engineer.com/2020/12/11/react/#index_id5

https://www.youtube.com/watch?app=desktop&v=LGKK1jAunKc


# 最後に
***プログラミング学習が遅い人の特徴のままだと言われたことしかできない人***になってしまいます。
エンジニアの仕事で求められるのは***決まっていないことを決めていくこと***だったりします。
タスクをロボットみたいに捌くのではなく、この***タスクの意図、役割は何だ？と考えていかなければいけません***し、***タスクを作った人が間違える場合***もあります。

プログラミング学習が速い人の特徴になるには頭の良さではなく
***普段からの習慣***です。普段からトレーニングをしていきましょう。

以前自分が教わっていたCTOの方からは「***自問自答すること***」と教わりました。

ex) 
この記事有益だけど、バージョン古いのかな？　誰が書いた？
動いたけどこの動作は適切かな？　この機能よりもっといい方法あるんじゃないかな？

など
tensorflow エラー　 No algorithm worked!

### エラー

```
 No algorithm worked!
```
このエラーの原因は、CUDAなどのグラフィックボードに関係していることは、分かったんだが、あまりわからなかった。


###解決法

これを書き込んで実行すると正常にうごいた。

```py

from tensorflow.compat.v1 import ConfigProto
from tensorflow.compat.v1 import InteractiveSession

config = ConfigProto()
config.gpu_options.allow_growth = True
session = InteractiveSession(config=config)

```
未経験エンジニアと若手エンジニア必読❗️エンジニアは自分の言葉で説明するようにする言語化が必須❗️

# 概要
実務で何をしたいのか言語化ができず苦戦してしまうことがありました。

# 最初に誰から教わった
こちらは現役のCTOの方から教わったことです。

こちらのスクールのメンターです。

https://wonderful-wife.net/w_code/

# 言語化について　
エンジニアの仕事は***知らない言葉を自分の言葉にする力***が必要になります。
実務では知らない言葉ばかりが出てくるので「知らない、わかりません」
は通用しません。

例えば
わかるように説明してほしいと言われてできていない、
つまり、自分への問いかけがかなり少ない　または　自分がわかっていないの
どちらかです。

毎回これだと仕事にならなくなります。

# 言語化のトレーニング方法
具体的に以下のことを教わりました。

具体的に***日常からトレーニングをする***といいと思います。

1番は小学5年生くらいに説明するイメージです。
1年生が理想ですが５年生で十分だと思います。
大人はある程度は理解してくれますが小学生だとちゃんとわかるまで説明しないと
なんでーって聞いてきます。
***小学生にもわかりそうな言葉で説明するイメージ***です。

そのためには***難しい言葉を説明できる***ように言い換える練習を普段からする必要があります。

# 現場で実践してみたこと
これから***コードを書く時に１つ1つの処理をコメントで書いて実装していくこと***にしました。

```rb
def index
    # ログイン中のユーザーに関連する投稿を取得
    posts = current_user.posts
    # 取得した投稿をJSON形式でクライアントに返す
    render json: posts, status: :ok
end
```
これだと小学生にはわかりづらいですが、***コードの説明をしながら書くことがコツ***です。
誰が読んでもわかるコードはコメントで残すことは不要ですが、
***今何の処理をしているのかを説明しながら書くと言う意味ではいいやり方***かもしれないです。

# 言語化ができないと質問が的外れになる
言語化がうまくできないがために質問が的外れになってしまい、うまくタスクが進まなくなることがあります。
対策としては***ドキュメントを毎日書くこと、先輩エンジニア、スクールなら現役エンジニアからフィードバックをもらう***のがいいと思います。

https://zenn.dev/norihashimo/articles/3bd51cee75cdf8
zeitwerkとは

#Zeitwerkとは
***Railsのライブラリなどを読み込むための機能です。***

ちなみに
***⚫︎ライブラリとは***
便利な機能を使えるようになるアプリです。

#zeitwerkエラー
***zeitwerkエラー***とうエラーが発生する場合があります。

例えば
ルーティングをapi/v1をエンドポイントにしているのにもかかわらず
全く関係ないconcernフォルダにあってうまく読み込みができない

このように***うまく読み込みができず発生する場合があります。***
【TidalCycles】指定したサイクル数のときのみの処理を実行

# はじめに

TidalCyclesは、Haskellライクなコードによってリズムパターンを生成できるソフトウェアです。
個人的にTidalCyclesで作曲していて、記事も書いているのでこちらもぜひみてください！

https://qiita.com/s2hap/items/620082b82a4bbe475823

# ある条件のサイクル数のときに処理を実行する

公式のドキュメントにいろいろな方法が紹介されています。

http://tidalcycles.org/docs/reference/conditions/

## every

`every`関数を用いると`every n 処理`とした場合に、`nの倍数サイクル`ごとに処理が適用されます。

たとえば以下の例だと`0, 3, 6, 9, 12,...`サイクル目に`rev`が適用されます

```haskell
d1 $ every 3 rev $ n "0 1 [~ 2] 3" # sound "arpy"
```

## every'

`every`関数では`nの倍数サイクル`ごとに処理されましたが、`every'`を用いることで、`(nの倍数 + m)サイクル`ごとの処理が可能になります。

たとえば以下の例だと`1, 4, 7, 10, 13,...`サイクル目に`rev`が適用されます

```haskell
d1 $ every' 3 1 rev $ n "0 1 [~ 2] 3" # sound "arpy"
```

## when

`when`関数では`when 条件　処理`としたときに、`条件がTrueの場合`のみ処理が適用されます。

ちなみにwhen関数のドキュメントにおける使用例が最初みたときにすぐ理解できなかったため、これは別記事に詳細にかきました。

https://qiita.com/s2hap/items/ad23595151d069f5b463

when関数の型定義は以下です。

```haskell
Type: when :: (Int -> Bool) -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a
```

この(Int -> Bool)部分は、Intを引数としてBoolを返す関数を設定してあげればいいので、たとえば`>=2`などが使えます。ちなみにこのIntとはサイクル数のことを指しているので`>=2`と設定すると「サイクル数が2以上のとき」という意味になります。

そのためたとえば

```haskell
d1 $ when (>=2) (|> speed 2) $ s "notes:2*2 house:5*3"
```

のようにすれば、サイクル数が2以上になると、speedが2となるので音程が1オクターブあがるのがわかると思います。


## whenmod

`whenmod`関数を用いると、`whenmod n m 処理`とした場合に、nサイクル中のmサイクル以降のみ処理が適用されます。

たとえば以下の例だと、`fast 2`が適用されるのは`4,5,6,7,12,13,14,15,...`サイクル目です。

```haskell
d1 $ whenmod 8 4 (fast 2) (sound "notes:2*2 house:5*3")
```

# 具体的なサイクル数を指定して処理を実行

まず今回の処理はわかりやすいように0サイクル目からスタートさせたいので`resetCyclesTo`関数を定義します。

```haskell
import qualified Sound.Tidal.Tempo as T

resetCyclesTo n = T.changeTempo (sTempoMV tidal) (\t tempo -> tempo {T.atTime = t, T.atCycle = n})
```

resetCyclesTo関数についてはこちらの記事をご覧ください。

https://qiita.com/s2hap/items/88ab4ebb45882f7b339d

上で紹介した`when`関数を用いれば、「4サイクル目のみ`fast 2`させたい」ということも実現できます。

```haskell
do
  resetCyclesTo (-0.05)
  d2 $ when (==4) (fast 2) $ sound "notes:2*2 house:5*3"
```

もう少し変わった要件として、「1, 2, 5, 6サイクル目のみ`fast 2`させたい」というときには以下のように実現できます。

```haskell
do
  resetCyclesTo (-0.05)
  let
    elem' xs x = elem x xs
  d2 $ when (elem' [1,2,5,6]) (fast 2) $ sound "notes:2*2 house:5*3"
```

条件を「`[1,2,5,6]`にサイクル数が含まれているとき」としたいので、`elem`関数の第一引数と第二引数を入れ替えた`elem'`関数を定義しています。
Databricksにてクラス定義時にノートブックのセル内の行数が多くなることで動作が重くなる事象への対応方法

## 注意事項
本記事での記載内容は、検証中であるために、何かしらの不具合が発生する可能性があります。
よりよい方法がご存知の方はご教授ください。

## 概要
Databricksにてクラス定義時にノートブックのセル内の行数が多くなることで動作が重くなる事象への対応方法として、複数に分けたクラスを継承した1つのクラスを定義する方法を共有します。

クラス定義を実施した際にDatabricksにて1セルの行数が1000を超えてしまったため、動作が重くなり開発に支障がでるようになってしまいました。

そこで、下記のような対応を実施しました。

1. 複数のクラスに分割して、それらを継承したクラスを定義すること
1. メソッド外で利用するクラス変数（メソッドのデフォルト値等）を最初のクラスで定義すること
1. メソッド内で利用するクラス変数を継承したクラスで定義すること


詳細は下記のGithub pagesのページをご確認ください。

https://manabian-.github.io/databricks_tecks_for_qiita/#fixed_cell_lengthening_when_defining_a_class/fixed_cell_lengthening_when_defining_a_class.html

コードを実行したい方は、下記のdbcファイルを取り込んでください。

```URL
https://github.com/manabian-/databricks_tecks_for_qiita/blob/main/tecks/fixed_cell_lengthening_when_defining_a_class/fixed_cell_lengthening_when_defining_a_class.dbc
```

## 手順
### 1. メソッド外で利用するクラス変数（メソッドのデフォルト値等）を保持したクラスを定義

```python
class _VariableTest00:
    _RETURN = None
```

### 2. メソッドを保持した２つのクラスを定義

```python
class _VariableTest01: 
    @staticmethod
    def print_test() -> _VariableTest00._RETURN:
        print(VariableTest._test)
```

```python
class _VariableTest02:
    @staticmethod
    def print_test_2() -> _VariableTest00._RETURN:
        print(VariableTest._test)
```

### 3.メソッド内で利用するクラス変数（VariableTest._test）と２つのクラスを継承したクラスを定義

```python
class VariableTest(
    _VariableTest01,
    _VariableTest02,
):
    _test = "AAA"
```

### 4. 継承したクラスのメソッドを利用

```python
# _VariableTest01のメソッドを利用
VariableTest.print_test()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/96aa3e08-9ff1-1496-bdc3-7ebc0c29da26.png)


```python
# _VariableTest02のメソッドを利用
VariableTest.print_test_2()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/15c293ac-7534-9a3a-05e1-8948757e6616.png)

### 5. クラス変数（VariableTest._test）を変更してメソッドを利用

```python
# VarableTestにクラス変数を定義しているため、クラス変数を修正可能
VariableTest._test = 'test'
VariableTest.print_test()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/efdd9eec-a5a6-012c-c797-ec562e8af70a.png)
docopt (python)で型チェックしよう

pythonを使っていると型チェックして欲しいなーと思う場面に時々出逢う。`docopt`を使用しているときにもそう感じてしまった。引数は`int`のはずなのにうっかりテキストを入れちゃって、ジャングルの奥深くに着いた時にエラーになるのは勘弁して欲しい。そこでジャングルの入り口で毎回型チェックを書くわけだが、同じことを毎回書いているといいヘルーパークラスが朧げながら思い浮かんできたんです。今日はそんなやつを紹介する。

以下はコード。

```python
#! /usr/bin/env python3.9
# encoding: utf-8

"""{f}\n
Usage:
    {f}
    {f} <str> <int> <path> <list>...
    {f} -h | --help

Options:
    <str>                    str arg
    <int>                    int arg
    <path>                   path arg
    <list>                   list[int] arg
    -h --help                Show this screen and exit.
"""
from docopt import docopt
from pathlib import Path
from typing import TypeVar, get_args


class DocArgs:
    A = TypeVar("A", str, Path, int, float, bool, list)

    def __init__(self, **kwargs):
        self.argd = docopt(__doc__.format(f=__file__), **kwargs)

    def __call__(self, value_type: A, flag: str) -> A:
        """
        transformer from docopt option string to another class
        :param value_type: ex) int, float32, etc
        :param flag:
        :return:
        """
        try:
            arg = value_type(self.argd[flag])
            if isinstance(arg, list):
                inner_type = get_args(value_type)[0]
                arg = [inner_type(z) for z in arg]
            return arg
        except ValueError as e:
            print("check your args")
            raise e
    
    def __str__(self) -> str:
        return self.argd.__str__()
    

if __name__ == "__main__":
    args = DocArgs(version='0.0.1')
    print(args)
    arg_str = args(str, "<str>")
    arg_int = args(int, "<int>")
    arg_path = args(Path, "<path>")
    arg_list = args(list[int], "<list>")
    print(arg_str)
    print(arg_int)
    print(arg_path)
    print(arg_list)
```
使い方は簡単で、いつも

```python
ori_args = docopt(__doc__.format(f=__file__))
```
としているところを

```
new_args = DocArgs()
```
とするだけだ。短くなったが、ここはコピペするところだからあんまり関係ないだろう。
引数の展開はこうだ。

```python
arg = ori_args["<test>"] # オリジナル
arg = int(ori_args["<test>"] # 型変換するときはこう
arg = new_args(int, "<test>") # DocArgsはこう
```
型変換を入れた元のバージョンと文字数は変わらない(スペースは無視しよう)ので、コーディングの負担は変わらない。何が嬉しいのかというと二つある。

- 型を必ず入れないと引数を取り出せない
- `list`の中身も型変換をしてくれる

1個目は横着しないようにするというくらいだが、二つ目の`list`の中まで型変換するのは毎回内包表記で書き換えていたので、これを使うとスッキリするだろう。`list`の中は全て同じ型が入ることを想定しているので、`list`の中に複数の型を入れようとしてる人がいるなら(いるのか?)これは使えない。

この肝は`list`の型ヒントの中の型をとってこれるかどうかというところである。`list`の型ヒントは中に別の型が入るわけだが、その取り出し方が情報がなかなか見つからなくて苦労した。`list`の型は`list`だが、`list[int]`のように中に型を入れると、型が`types.GenericAlias`となる。ここから中に入れている型を取り出す方法を見つけるのに苦労したが、最終的に`typing.get_args()`でとってこれるということがわかって、ジャングルから抜け出せた。
最初は`__args__`を使ってたけど、`typing.get_args()`の方がいいみたい。
Linuxについての忘却録

##Linuxの概念
Linuxには広義のLinuxと狭義のLinuxが存在します。
それらについて詳しく説明していきたいと思います。

##狭義のLinux
Linuxは狭義では**Linuxカーネル**のことを指します。

Linuxカーネルとは
→OSの核となる部分でOSの基本機能の役割を担うソフトウェアのことで
実際にはCPU、メモリなどのハードウェアの管理（制御など）・入力したコマンドの実行を処理するためのプロセス管理を行います。

そのため、Linuxカーネル内にカスタマイズしたい内容を折り込むのではなく、カーネルの外部を**シェル**というもので包むようにして、そこを自分好みにカスタマイズすることで操作を行います。

##プロセス管理とは
多くのOSでは、複数のプログラムを同時に並行しながら実行できるマルチタスク機能が搭載されており、Linuxも対応しています。

ここで肝心なのは、Linuxカーネルはあくまでもコンピューターのハードウェアの制御を行うソフトウェアであって、Linux全体の実際のツールやアプリケーションは含まれていないという点である。



##広義のLinux
広義のLinuxとはLinuxカーネル（狭義のLinux）に加えて基本的なコマンド群やアプリケーションなどユーザーがそのまま利用できるように包装化（パッケージング）したものも含まれている。
このようなものを**Linuxディストリビューション**といい、広義のLinuxとなる。

##LinuxとUNIX思想
またLinuxは
・小さいことはいいこと
・一つのことをうまくやる
・すべてはファイルで構成されている

という点でUNIXの思想が深く織り込まれています。

##まとめ
これらをまとめると
狭義のLinux
→コンピューターのハードウェアの制御を行うソフトウェアであるLinuxカーネル

広義のLinux
→Linuxカーネル＋基本的なコマンド群・アプリケーションを含んだもの
これらをまとめたものがLinuxディストリビューション


#Linuxコマンドについて
Linuxには様々なコマンド（命令するもの）が存在する
→コマンドによって様々な処理をおこなうことができる
→また目的の処理を行うコマンドがない際には、単純なコマンドを組み合わせることによって複雑な処理を行うというのもLinuxの特徴である

エラーメッセージが表示された時は成長するチャンスであり、そのメッセージの内容を理解し、一つずつ対処していくことが大事である

###Linux内のコマンドが実行される仕組み
Linux内で次のようなコマンド入力をしてみたとする。

```
[ryutake@localhost ~]$echo Hello,World!
```
するとその結果として、

```
Hello,World!
```
と表示される。

実際にコマンド入力したらシンプルかもしれない。
しかし、この中にでは様々な処理が行われているのである

この仕組みで出てくるもの
・ディスプレイ（パソコンの画面）
・キーボード（入力用途）
・Linux内部

**仕組み**

```
echo Hello,World!
```
①キーボードから入力された文字列（echo Hello,World!）をLinuxが受け取る

```
echo 
```
②その文字列に対応したコマンド（実行したい処理の依頼→ここではecho）を探す（Linux内）

③Linux内で見つけたコマンドを実行する（**Linuxカーネルが行う**）

```
Hello,World!
```
④処理結果がディスプレイに表示される(Hello,World!)
pythonでグラフを作ろう 第1回 -まずは取り敢えずプロットしてみる-

#はじめに
この記事はpythonで取り敢えずそれっぽいグラフを作りたい人向けの記事です。pythonの基本的な知識は習得済みとします。

#取り敢えずグラフを作ってみよう
　まずは習うより慣れろの精神で以下のプログラムを実行してみてください。

```python
#############################################
####### begin import libraries ##############
import numpy as np
import matplotlib.pyplot as plt
####### end import libraries ###############
############################################


#############################################
####### begin make data #####################
x = np.linspace(-np.pi, np.pi, 100)
y = np.sin(x)
####### end make data #######################
#############################################


#############################################
####### begin plot ##########################
plt.plot(x,y)
plt.savefig('sin.png')
plt.show()
####### end plot ############################
#############################################
```
新しいウィンドウが立ち上がり以下の画像が表示されればOKですので、ウィンドウは閉じてください。画像が"sin.png"という名前で保存されていますので確認してください。
![sin.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1920250/9f00c367-5718-308e-8193-0e4b0c6eb941.png)

#解説
 プログラムの中身を説明します。1つ目のブロックは必要なライブラリのimportをしています。ここでは数値計算ライブラリである**numpy**と可視化ライブラリである**matplotlib**をimportしています。numpyは可視化するためのライブラリではないですが、そもそも可視化するためのデータが無いとどうしようもないので、今回はデータ作成のためにnumpyをimportしています。

 2つ目のブロックでは可視化するデータをnumpyを用いて作成しています。**np.linspace**は等差数列を作成するための関数で今後よく使うと思うので使い方を確認しておきます。1つ目の引数は等差数列の初項、2つ目の引数は等差数列の最終項、3つ目の引数は項数を表しています(公差は自動的に決められます)。ここでは初項$-\pi$、最終項$\pi$、項数100の等差数列を作成し、$x$に格納しています。そして**np.sin**を用いて$\sin x$を計算し、$y$に格納しています。

3つ目のブロックがグラフ作成の部分です。**plt.plot**は折線グラフを作成する関数であり、今回のメインです。見たままですが、1つ目の引数に$x$軸の値を入れ、2つ目の引数に$y$軸の値を入れています。**plt.savefig**が作成したグラフを保存する関数であり、引数には出力する画像ファイル名を指定します。最後の**plt.show**が作成したグラフを表示する関数です。**plt.show**は無くても特に問題はないですが、毎回画像ファイルを開いてグラフを確認するのが面倒なので入れています。**plt.savefigとplt.showの順番が逆になると画像がうまく出力されないので注意してください。**
AWSのRDSサービスでPostgreSQL(+PostGIS)を構築

## はじめに
QGISサーバーの構築について色々と試しているのだが、その際にローカルで作成したQGISプロジェクトファイルをアップロードして、QGISのWebClientでも問題なく表示できるか試そうとしている。
しかし、QGISプロジェクトファイルが参照しているデータ先を共通の宛先にしないと表示確認が面倒なので、別途外部からの接続が可能なDBサーバーを用意しようと考えている。
EC2の様にインスタンスを立てて普通にPostgreSQLを入れればできるのだが、せっかくなのでRDSを使ってみて、楽さを実感しようと思った。記事にする様な内容でもないかもしれないが、時間もかからないので一応メモとして残すことにした。


## メモの内容

１．AWSサービスのRDSよりPostgreSQL構築
２．外部から接続するための設定追加


## １．AWSサービスのRDSよりPostgreSQL構築

RDS for PostgreSQL バージョンに同梱されている PostGISのバージョンはこちらのサイトに記載があるので、今回はこれを見て、**"PostGIS2.5.2"** のバージョンが同梱されているPostgreSQLのバージョンを選択。

https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/Appendix.PostgreSQL.CommonDBATasks.PostGIS.html

AWSサービスの中から『RDS』を選択し、『データベース』から **"データベースの作成"**をクリック。
![Qiita-no052_img1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654767/6bbbd2ee-59e2-708c-bac5-08d6125b399d.jpeg)

設定は下図を参考に。
![Qiita-no052_img2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654767/154408e9-a8dd-2efe-e79f-5bc160fd2335.jpeg)
※今回はPostGIS2.5.2のバージョンが同梱されている、PostgreSQLのバージョンを選択。

![Qiita-no052_img3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654767/2cf974bd-8df1-7457-6b3a-87642fe473cd.jpeg)

ローカルPCやGCP上のVMインスタンスから接続をしたいので、パブリックアクセスは有りにし、通常のパスワード認証を使用。（後にIPフィルタは設定する予定）
![Qiita-no052_img4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654767/95b11369-c5b2-b38b-1a93-64b331c7ac01.jpeg)
![Qiita-no052_img5.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654767/024a30fd-8894-1d75-edca-73ec8fefd700.jpeg)

**最後に右下の方にある『データベースを作成』をクリックすれば、選択したエンジンが搭載されたインスタンスが立ち上がる。（1分もかからず構築できた）**


## ２．外部から接続するための設定追加
**ローカルとGCP上のインスタンスから接続できる様に、インバウンド設定にIPアドレス[許可]を追加する。**

『データベース』一覧の画面から、db名をクリック。
![Qiita-no052_img6.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654767/7188a6e9-169e-6769-d215-e41794981d57.jpeg)

『セキュリティグループのルール』をクリック。
![Qiita-no052_img7.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654767/1ee202a6-66e5-4610-390c-50ff36ecf4e0.jpeg)
　※青枠のエンドポイントは、外部から接続する際のホスト名。


インバウンドルールの中の 『Edit inbound rules』をクリックする。
次の画面で新しいルールを追加でき、そこで許可IPアドレスの追加などができる。
![Qiita-no052_img8.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654767/f2d28ab9-907c-5fab-0f5e-a000ea545e94.jpeg)
（デフォルトで自分のグローバルIPが入っていてビックリした！DB作成時にAWSコンソールに接続している端末は、インバウンド許可ルールに追加されるっぽい。）

**`pgAdmin` などで試しに接続してみて、スキーマやテーブルを作成できればOK！（GISの拡張機能を有効にしたい場合は、有効にしたいDB内で`CREATE EXTENSION postgis;` を実行すればよい）**
Git コマンドにエイリアスをつける


##エイリアスの付け方
Gitコマンドにエイリアスをつける場合、下記のように設定します。

```
git config --global alias.エイリアス名 コマンド名
```

##使用例
例えば、git statusというコマンドのエイリアスをstとして登録したい場合、下記のように設定します。

```
git config --global alias.st status
```

登録したコマンドを使ってみます。

```
git st
On branch master
Your branch is up to date with 'origin/master'.
```

普段、何度も使用するコマンドは登録しておくと開発効率が上がりますね。
Androidエミュレータで、ホーム画面からSettingしようとするとブラックアウトする問題

# 目次
[1.現象](#1現象)
[2.解決法](#2解決法)

# 1.現象
エミュレータのホーム画面のSettingsから設定しようとするとブラックアウトしてしまいます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630191/dd482a67-ef0a-638f-e548-8d889325a23c.png)

# 2.解決法
Android Studioの右上にあるAVD Managerを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630191/698ad14b-ef09-b864-9016-58036cacd330.png)
<hr>
直したいエミュレータのプルダウンからWipe Dataを選択し、Yesを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630191/64666bb6-f902-9b55-9472-13912dae385e.png)
RPMパッケージを使用してOracle19cをインストール

# はじめに
Oracle Database18c以降では、RPMパッケージを使用してインストールが可能です。
今回はRPMパッケージを使用してOracle19cをインストールする手順を記載します。

# 前提

| 項目 | 内容 |
|:-:|:-:|
| OS  | CentOS7  |

# 準備
１. rootユーザーでログインします。

２. Oracle Databaseインストールの前提条件を整えるため、Oracle Database Preinstallation RPMをダウンロードしてインストールします。

```:ダウンロード
# curl -o oracle-database-preinstall-19c-1.0-1.el7.x86_64.rpm https://yum.oracle.com/repo/OracleLinux/OL7/latest/x86_64/getPackage/oracle-database-preinstall-19c-1.0-1.el7.x86_64.rpm
```

```:インストール
# yum -y localinstall oracle-database-preinstall-19c-1.0-1.el7.x86_64.rpm
```

３. インストール成功後、ダウンロードしたRPMファイルを削除します。

```:RPMファイル削除
# rm oracle-database-preinstall-19c-1.0-1.el7.x86_64.rpm
```
# RPMのダウンロード
下記から「oracle-database-ee-19c-1.0-1.x86_64.rpm」をダウンロードします。
https://www.oracle.com/database/technologies/oracle-database-software-downloads.html
![RPMダウンロード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1798422/58bd6080-f683-becc-0a33-88aa3c12943e.png)

# RPMのアップロード
ダウンロードしたRPMをLinuxの任意の場所にアップロードします。
ここでは/tmpにアップロード。

```:RPMファイルアップロード
# scp コピー元ファイルパス ユーザ名@コピー先IPアドレス:/コピー先のパス
# scp C:\oracle-database-ee-19c-1.0-1.x86_64.rpm root@192.168.34.12:/tmp
```

```:確認
# cd /tmp
# ll oracle-database-ee-19c-1.0-1.x86_64.rpm
-rw-r--r-- 1 root root 2694664264 21. Aug 09:05 oracle-database-ee-19c-1.0-1.x86_64.rpm
```

# インストール
yum localinstallコマンドを使用してインストールします。

```:インストール
# cd /tmp
# yum -y localinstall oracle-database-ee-19c-1.0-1.x86_64.rpm
```

# 参考
https://docs.oracle.com/cd/F19136_01/ladbi/running-rpm-packages-to-install-oracle-database.html#GUID-BB7C11E3-D385-4A2F-9EAF-75F4F0AACF02
コードレビューの基本

#コードレビューとは？

コードレビューとは、ソフトウェア開発活動の中の一つで、色々な目的ながあります。
もっとも一般的な目的は、コードを自分の目で確認して不具合等が入り込んでいないかを確かめることです。
自分の描いたコードを他の開発者が確認したり、他の開発者が書いたコードを自分で確認したりします。

そのほかの目的として、他のメンバーのコードを理解して、自分のコードとの間で齟齬がないかを確認したり、問題がある部分の代替案を考えたりする場合もあります。1回のレビューでこれらすべてを目的にすることはあまりなく、1回目のレビューでは欠陥がないかを確かめ、2回目のレビューでは代替案がないかを確かめる、といった具合に使い分けるのが一般的です。

#コードレビュー時に必要なスキル

レビューのスキルには大きく分けて以下の２つが存在します。
①問題を見つけるスキル
②見つけた問題をうまく指摘するスキル

どちからがかけていると、問題がわかっているものの相手になかなか意味が汲み取ってもらえず、問題からさらなる問題を引き起こす場合もあります。
またそれをちゃんと伝えるためのコミュニケーションコストがさらに発生してしまうこともあり得ます。

#コードレビューの読み進め方

基本的には以下の２つになるかと思います。
①バグが潜んでいないか
②可読性があるか

１つ目は、そのままなのですが期待している処理通りに進むようなコードになっているのか？
２つ目は、将来コードを拡張する際に、コードを読む人を勘違いさせやすいコードです。コードを読む人にとって、紛らわしい書き方をしていないかどうかを確認するための読み進め方を紹介します。


基本的にはこれらのポイントを念頭に読み進めていくことが大事だと思います。
Linuxとは？Linuxの特徴・Linuxがもたらすものについて

##Linuxとは？
LinuxとはOSの１つである。
サーバー用・組み込み機器用（ある特定の目的を果たすことに着目した機器）・学習用など様々な場面で使用される。

####OSとは
OS→Operating System（直訳：命令するシステム・機構）の略。
コンピュータを操作するための基本ソフトフェア（コンピューターなどに命令を出すためのコンピュータープログラム）のことを言う

###Linuxの一番の特徴
Linuxの一番の特徴、それは**オープンソース**であることある。
オープンソースとは直訳すると源が開放されている状態のことである。

ここでいう源とは何だろうか？
→それがソースコードである。
ソースコード：ソフトウェアを構成しているプログラムのこと

つまりソースコードがオープンな状態、つまり無償で公開されているのである。

ここでのポイントはオープンな状態というところにある。
オープンな状態ということは隠れている部分がないということである
→どのように処理が行われているのか、エラーがどのようにして生じているのかなど全ての部分を確認することができるので色々とカスタマイズすることができる。

※他のOSの場合、全てがオープンになっていなかったり、無償で後悔されているものもないので、制約がかかってしまう。しかし、Linuxは全てが無償で解放されているので、**カスタマイズの振り幅が大きい**という特徴を持っています。

###サーバーとしてのLinuxの特徴
Linuxは様々な場面で使用されると明記したが、恩恵としてLinuxが無償で提供されているという点がサーバーでは生きるというものがあると思う。その特徴について説明していきたいと思う。

アプリケーションおよびミドルウェアを動かすのにはOSが必要となってくる。
→コスト的に無料の方が良くない？
→Linuxディストリビューションを使用しよう。

####webシステムに必要なサーバーとしては
サーバーは役割ごとに様々なサーバーに分かれています。
例えば、メールの送受信を円滑にしたいのであればメールサーバーを、ブラウザの表示を行いたいのであればwebサーバーをしようしたりします。

webシステムに必要なサーバーとしては
・webサーバー
・アプリケーションのサーバー
・データベースサーバー

などがあり、こちらにLinuxを使用することが多く、サーバーへもたらす恩恵は大きいと言える。
The service is unavailable. で EBS ボリュームを変更できないタイミングがある

Amazon EBS ボリュームはホスト側のメンテナンスにより変更操作ができないタイミングがあります。

## エラー内容
EBS のボリューム変更操作を行うと以下のようなメッセージで変更操作に失敗する場合があります。

```
The service is unavailable. Please try again shortly.
```

AWS 側の障害かな？と思いましたが、[Service Health Dashboard](https://status.aws.amazon.com/) では特に異常は報告されていません。

## 原因
エラー発生後に、Personal Health Dashboard で以下の通知を受け取りました。


> Your volume can’t be modified at present due to an operational activity that is being performed on the systems hosting your volume. Your volume is in a healthy state. The operational activity does not impact the volume performance or availability and you may continue to read/write data normally. We will send an update as soon as the operational activity is complete, and your volume can be modified.
This operational activity may last for up to 48 hours. If you urgently need to modify your volume, we recommend creating a new volume with your desired size/performance and restoring the data from the snapshot of your existing volume. Please refer to https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-restoring-volume.html for restoring an Amazon EBS volume from a snapshot. If you don’t have a snapshot of the volume, we recommend that you first create a snapshot by following the directions outlined in https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-creating-snapshot.html.
We apologize for the inconvenience that this may have caused you. If you have any questions or concerns, you may contact AWS support at: http://aws.amazon.com/support.

以下のようなことが記載されています。

* ボリュームがホストされているシステムで実行されている運用活動のため、一時的にボリュームを変更できない
* ボリューム自体の可用性への影響はなく、読み取り、書き込みは通常通り行うことができる
* 運用活動は最大で 48 時間続くことがある

## 対応
### 完了まで待つ
運用活動の完了通知も Personal Health Dashboard で受け取ることができます。
この時は EBS ボリュームの拡張時にエラーを受け取りましたが、急ぎではなかったため、システムの運用活動完了後に再度拡張を実施しました。

### スナップショットから復元する
上記の通知内容にも記載がありますが、運用活動の完了まで待つことができない場合はボリュームのスナップショットを取得し、データをリストアすることが推奨されています。

https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-creating-snapshot.html

https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-restoring-volume.html


簡単ですが、以上です。
データ分析も大事だけど、それと同等、いやそれ以上に大事かもしれないこと

## はじめに

自分は、以下の本にあるような、大学で学ぶ統計学の知識を修めています。

https://www.amazon.co.jp/dp/4130420658/

ですが、「あるロジックの改善をして欲しい」と頼まれて、現状把握のためデータ分析しようとするも、価値のある（儲かる）活用ができていませんでした。

次のアクションにつながる提案ができませんでした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14191/093d0db7-e081-da7e-6949-6409fe69c693.png)

なぜだ。。。？

そこで、振り返りました。

- 改めて「データ分析」の価値はなにか？
    - どう使えば良かったのか？
- 統計学の知識があったのに、なぜ役に立たなかったのか？
- これから行動を改善すればいいか？

を、書いていこうと思います。

## 「データ分析」の価値とは

シンプルに価値とは、**データ分析はビジネスにおいて、より良い決定を下すために役立つ手段**だと思っています。

例えば

- 最初に、AかBかどちらかを選択する場合（意思決定の精度）
- 次にまた成功しやすい行動を行うための意思決定の精度を向上させる（再現性ある結果を得る）手段

だと思っています。

## 振り返り「統計学の知識があったのに、なぜ役に立たなかったのか？」

結論から言うと、**データを見たりグラフ化する作業をまず先にやってしまったのが問題でした。**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14191/21d8bf67-192d-ae45-3798-95219987b093.png)

自分は、まずデータを手に入れて、そこから何が言えるかを考えようとしてしまいました。これが間違いでした。

### なぜか？

**表面上起きていること、またはそのデータの表現が、とくべき問題を直接表現しているとは限らないから**です。

データそのものや、グラフは事実データです。

そこからインサイトを得ようとすると思考回数が多くなり、非効率でした。

事実、私は、仮説なしに生データを眺めてもそこからは成果につながるアクションには繋がりませんでした。

（実際、自分は、ある最適なロジックを組み立てる際、まず、現状の生データを見て、データ加工をしたりグラフ化して、そこからインサイトが得られないかなどをして、10時間以上かけたりしていました。考えることが苦手なので、データの中に絶対的な正解や心理を見つけようという心理があると思ってしまったのかもしれません。）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14191/a3f2ca4b-50bb-7ebb-b7da-9ce19b3aacc6.png)

## どうすれば、効率的に効果的なアクションにつながる示唆をデータ分析から得られるか

当たり前に言われることですが

まず、主張（これを行うことで、どうビジネスが改善に向かうかのストーリー）を明確にすることが大切だと思いました。

具体的にいうと、最初に以下を定義することが大切だと思いました（もちろん、これでも正解に近づけるかは保証はしていません）。

- 目的の設定
    - なんのためにしたいのか？
    - 何を知りたいのか？
        - という目的
- 問題の定義
    - 何が問題なのか？を明らかをまず明確にすること
        - 何が問題で、何を解決したいのか？

この方法だと、少なくとも目的設定や、問題定義をしない場合よりも早くにアクションにつながっていたと思います。

また、データだけ眺めてても、解決策はたぶん見出せないと思います。

自分は、考えることが苦手で、データ処理が得意な故、それに頼ったことが今回の原因だと認識しました。

### 具体的なとるべきアクションとは？

- まず生データを用意する癖を止める
- 次に、問題の設定と目的をあきらかにする

### 統計を知っているだけでは、ビジネスの役には立たなかった

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14191/35361de6-bb80-1be2-9378-1d8be095d0f4.png)

（こういうと、統計学にも失礼ですね）

成果を出すために、データを活用するプロセスは、以下のフェーズを順番に行うのがいいと思いました。

1. 目的の設定や問題を定義するフェーズ（考える時間）
2. ツールを使ったり、統計学をもちいて分析するフェーズ（作業する時間）
3. 結果から考察し論理を構築するフェーズ（考える時間）

![サンプル図フェーズ (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14191/3c766f46-9d51-8e98-fb98-eaa247525a12.png)

自分はいきなり、フェーズ2を行ってしまいました。

なるほど、成果を出すために、データを活用するプロセスが整理できたら、以下の原因がわかりました。

- 目的や問題がなかったので、結論も曖昧になる
    - というか迷走して出せない
- 無駄にグラフや表が増えてしまうのこと

つまり原因は、目的の設定や問題を定義していないからです。

この経験から、以下のことがわかりました。

## データ分析と同じくらい大事なこと

データ分析も大事だけど、それと同等、いやそれ以上に大事かもしれないこと

それは、**データをどう活用するかのプロセス**です。

私は、データから新しいインサイトを得ることばかり考えてしまい、データ分析の手段だけ実施して、ビジネスを成功させる狙いがありませんでした。

P値を1%精度向上させることよりも、有意差を出すことよりも、まず正しくデータを活用することが大事だと学びました。

## 最後に

**データをどう活用するかのプロセス**に関するノウハウ本があったので自分のアクションにするため、書評をかねてアウトプットします。

https://www.amazon.co.jp/dp/B07WP4YPW8/

## アウトプット100本ノック実施中

https://qiita.com/ryosuketter/items/713474dbd009870e4103
【React】useRefを用いて値を取得しようとしたらundefinedと言われた。~備忘録~

React HooksのuseRefを用いて、contenteditableにしたdivタグの値を取得するときに躓いたので備忘録として。

```react
import React, { useRef } from 'react'

function InputWithDivTag() {
        const refContainer = useRef('')
        
        console.log(refContainer.current.value)

        return (
             <div
                  contentEditable="true"
                  ref={refContainer}
                  data-placeholder="入力してください"
             />
        )
}

export default InputWithDivTag
```

いざ、値を入力してコンソールログの結果を見ると、、、

```
undefined
```

何でだろう。
めげません。頑張るのです。

とりあえず、

```react
console.log(refContainer.current.value)
```
を

```react
console.log(refContainer.current)
```
に変更しました。
すると、コンソールログの結果は

```html
<div contenteditable="true" data-placeholder="入力してください">a</div>
```

refContainerが空っぽなわけではなさそうです。
考えます。
そもそも、参考にしたコードではcurrent.valueはinputタグに使われていた。
同じ入力でも、contenteditableによって入力可能となったdivタグとinputタグでは何かが違うのでは。
ググろう。
let me google it!

```react
console.log(refContainer.current.innerText)
```

これで思ったように値を取得できました。
valueではなくinnerTextを使えば良かったのですね。
今更聞けないビットDP(ABC 215 E問題)

動的計画法の次のステップとしてビットDPというものがあります.

## 1. そもそもビットDPって何？

普通の動的計画法は

a. dpの設定
b. 初期値の設定
c. 更新方法の設定
d. 出力の設定

を行います.
(例: [フィボナッチ数列(今更聞けない) by making111 アクセス日 2021/08/22](https://qiita.com/making111/items/380d993a3c25e90cb748))

[ビットDP(bit DP)の考え方 ~集合に対する動的計画法~, 
アルゴリズムロジック アクセス日 2021/08/21](https://algo-logic.info/bit-dp/)によると,
ビットDPも基本的な動作はdpと変わらないみたいです.

しかし,ビットDPの変わった点として dpの設定を

```math
\begin{align}
𝑑𝑝[𝑆]:=&{\rm 集合} S {\rm に対しての}{何かしらの値}
\end{align}
```
と定義することにあります.

これの何がbitかというと集合が0-1bitで表現されていることにあります.
(ex. 0010 -> {1}, 1110->{3,2,1} など)

では,[AtCoder Beginner Contest 215 E問題 アクセス日 2021/08/21](https://atcoder.jp/contests/abc215/tasks/abc215_e)に当てはめて,考えてみましょう(問題概要はページを参照してください).

## 2. 例題の解説

私でも理解できるように,
[公式解説 accessed 2021/08/21](https://atcoder.jp/contests/abc215/editorial/2483)を噛み砕いていこうと思います.

今回の答えは解説にある通り以下のようにbitDPを実装します(10種類を$K$種類として表す).

a. dpの定義

```math
\begin{align}
dp[i][P_i][k]:=&i{\rm 回目までの大会のうち,参加したコンテスト集合が}P_i{\rm で}\\&{\rm 最後に参加したコンテストの種類が}k{\rm であるような場合の組み合わせの数}
\end{align}
```

b. 初期値の設定

```math
\forall i\in [0,N], \forall U,\forall k\in [K], dp[i][U][k]=0
```

c. 更新方法の設定

```math
\begin{align}
{\rm for} \ i &\in {[0,N-1]}:\\
&{\rm Step1. \ \ }\forall U,\forall k\in [K], dp[i+1][U][k]+=dp[i][U][k] \\
&{\rm Step2. \ \ } {\rm if} \ S_i=k: dp[i+1][U][k]+=dp[i][U][k] \\
&{\rm Step3. \ \ }\forall U{\rm (which\ doesn't\ include\ }S_i{\rm )},\forall k\in [K],\\
&\ \ \ \ \ \ \ \ \ \ \ \ \ \ \  dp[i+1][U\cup \{S_i\}][S_i]+=dp[i][U][k]\\
&{\rm Step4. \ \ } dp[i+1][\{S_i\}][S_i]+=1
\end{align}
```
(意味は,
1. i+1回目の大会は参加しないパターンを追加
2. i+1回目の大会に参加しても,参加したコンテスト集合が変化しない場合
3. i+1回目の大会に参加できるが,参加したコンテスト集合が変化する場合
4. 今まで何も参加していない場合を,初期値の設定上,追加する必要がある)

d. 出力の設定

```math 
\sum_{U,k} dp[N][U][k]
```

以上のように設定すれば良いです(ほとんど解説の通りです).

このように例を見ると,いかに集合をbitとして扱うのが革新的かわかる.

また,計算量に関しては,
各$i$に対して,$O(K2^K)$であり,$O(NK2^K)\simeq 10^7$で
制限時間が2秒のため問題なく実行できます.

##3. 実行コード参考を読むのに必要な知識

今回は,本コンテストにおいてE問題をPythonで最も早く解いた
[shotoyoo様](https://atcoder.jp/users/shotoyoo)の[コード](https://atcoder.jp/contests/abc215/submissions/25209259)(アクセス日 2021/08/22)を参考にさせていただきます.

このコードを読む知識を簡単にまとめておきます.

```python
>>> 1<<0
1
>>> 1<<1
2
>>> ord('a')
97
>>> 1&5
1
>>> 1|10
11
>>> 4|2
6
>>> 4>>2
1
>>> 4>>1
2
>>> 6>>3
0
```

この辺りがわかればあとは実装できると思います！


##4. 結論

bitで集合扱うことで計算量の短縮にも貢献できることがわかりました.
(過去にpythonのbit処理をまとめてあるのでそちらもよければ参照ください
[Python 論理積と右シフト by making　アクセス日 2021/08/22](https://qiita.com/making111/items/2a5872aad89cd6224694))

bitDPの類題を今後解いていきたいと思います.
Python Requestsを使ってmultipart/form-dataをin-memoryで送る方法

# 概要
Python Requestsを使って、`multipart/form-data`を送る場合、`open`で開いたファイルを送る仕様となっている。
Pythonの辞書形式のデータをJSONファイルとして送る場合、一時的にJSONファイルを作成せずに送る方法が分からなかった。
Python Requestsを使ってmultipart/form-dataをin-memoryで送る方法を記す。

# Python Requestsの仕様

Python Requestsを使って、`multipart/form-data`を送る場合、`open`で開いたファイルを送る仕様となっている。
https://requests-docs-ja.readthedocs.io/en/latest/user/quickstart/#id7 

```python
import requests

url = "https://example.com"
headers = {
  "Content-Type": "multipart/form-data",
}
files = {
  'file': ('report.xls', open('report.xls', 'rb'))
}
response = requests.post(url, headers=headers, files=files)
```

# 解決方法
JSON(辞書データ)を送りたい場合

```python
from io import BytesIO
import json
import requests

url = "https://example.com"
data = {"hoge":"hoge"}
headers = {
  "Content-Type": "multipart/form-data",
}

binary_stream = BytesIO(json.dumps(data).encode('utf-8'))
files = {
  "file": ("filename.json", binary_stream),
}
response = requests.post(url, headers=headers, files=files)
```

# 解説
`open` で何を呼び出しているかというと、バイナリストリームのオブジェクトである。
`io`のリファレンスを読むと以下のように書いてある。
https://docs.python.org/ja/3/library/io.html#module-io 
> バイナリー I/O (buffered I/O とも呼ばれます) は bytes-like オブジェクト を受け取り bytes オブジェクトを生成します。エンコード、デコード、改行文字変換は一切行いません。このカテゴリのストリームは全ての非テキストデータや、テキストデータの扱いを手動で管理したい場合に利用することができます。

> バイナリーストリームを生成する一番簡単な方法は、 open() の mode 文字列に 'b' を指定することです:

> ``` f = open("myfile.jpg", "rb") ```
> BytesIO はインメモリーのバイナリストリームです:

> ``` f = io.BytesIO(b"some initial binary data: \x00\x01") ```
> バイナリーストリーム API は BufferedIOBase のドキュメントで詳しく解説します。

ということで、`open()`でファイルからバイナリストリームオブジェクトを生成する代わりに、`io.BytesIO()`でインメモリのバイナリストリームを生成する。

辞書データからバイナリストリームまでの道のり

```python
from io import BytesIO
import json

# 元なる辞書
data = {"hoge":"hoge"} 
# JSONとして、Stringに変換
string_data = json.dumps(data) 
# utf-8形式でバイトに変換、
bytes_data = string_data.encode('utf-8')
# バイトデータをバイナリストリームに変換 
binary_stream = BytesIO(bytes_data)
```

もちろん、JSON以外にCSVやXMLなどもインメモリで作成し、そのまま `requests` で`multipart/form-data`として送ることが可能。

# 参考記事
辞書データをJSONに変換し、BytesIOオブジェクトにする方法の参考にした。
https://stackoverflow.com/questions/53118672/what-is-correct-way-to-load-json-file-stored-in-the-bytesio-object 
`open` と `BytesIO` オブジェクトの違いについて参考にした。
https://stackoverflow.com/questions/42800250/difference-between-open-and-io-bytesio-in-binary-streams
LayoutInflater.inflateのattachToRootとは何か？

##はじめに
Fragment等を扱うときなどにおまじないとして書いていたLayoutInflaterのinflateメソッドの第3引数attachToRootの意味がよくわからなかったので調べてみました。

##LayoutInflaterについて
LayoutInflaterとはxmlをViewオブジェクトに変換するものです。ドキュメントを確認したところLayoutInflater内のinflateメソッドは色々種類がありましたが、多分一番多く使われているのが

```kotlin
open fun inflate(resource: Int, root: ViewGroup?, attachToRoot: Boolean): View!
```
のタイプだと思います。これの第一引数ではViewに変換したいlayoutのxmlを指定します。第二引数についてはドキュメントの説明をdeepLで翻訳すると
>ViewGroup。オプションで、生成された階層の親となるビュー（attachToRootがtrueの場合）、または単に、返された階層のルートのLayoutParams値のセットを提供するオブジェクト（attachToRootがfalseの場合）。

となっています。これは生成するViewをセットする親のViewGroupを指定するということだと思います。

##attachToRoot
まずはドキュメントのattachToRootの説明を読んでみます。
>attachToRoot	Boolean: Whether the inflated hierarchy should be attached to the root parameter? If false, root is only used to create the correct subclass of LayoutParams for the root view in the XML.

やっぱりよく意味がわかりません。ここの部分の解説として[stack overflowの記事](https://stackoverflow.com/questions/12567578/what-does-the-layoutinflater-attachtoroot-parameter-mean)が見つかりました。ざっくりいうと、作成したViewを、inflateの第二引数で渡したViewGroupにセットするのを、自動でするかか手動でするかということを指定できるみたいです。なので上のstack overflow内の説明とほぼ同じになってしまいますが、

```kotlin
val view = LayoutInflater.inflate({"xmlのlayoutリソースID"},parent,false)
parent.addView(view)   
```
```kotlin
LayoutInflater.inflate({"xmlのlayoutリソースID"},parent,true)
```
上の二つが同じ意味になるということです。

それぞれのinflateの引数の意味がわかったところでもう少し掘り下げてみます。attachToRootはBooleanですが僕はここをtrueにしたことがありません。なぜいつもfalseなのかも調べてみました。


僕がこのLayoutInflaterを記述していたのは大抵FragmentのonCreateViewやRecyclerViewのAdapterのonCreateViewHolder等でした。これらのようなタイミングではLayoutInflater.inflateでViewを作成するタイミングでさらにそれを親のViewGroupにセットする必要がありません。なぜならFragmentを作成するときはfragmentManager、RecyclerViewの場合はAdapterが代わりにその役割を果たしてくれているからです。なのでonCreateViewやonCreateViewHolderの内部でLayoutInflater.inflateをする時にattachToRootをtrueにしてしまうと、親ViewGroupに同じViewを二つセットすることになってしまいIllegalStateExceptionが起きてしまいます。なのでfalseをセットしないといけないらしいです。

##感想
Androidの勉強を始めた初期の頃からおまじないとして使っていたコードの意味を前より理解できるようになったのでよかったです。

##参考文献
https://developer.android.com/reference/kotlin/android/view/LayoutInflater#inflate(kotlin.Int,%20android.view.ViewGroup,%20kotlin.Boolean)

https://stackoverflow.com/questions/12567578/what-does-the-layoutinflater-attachtoroot-parameter-mean
AtCoder Beginner Contest 215 参戦記

# AtCoder Beginner Contest 215 参戦記

## [ABC215A - Your First Judge](https://atcoder.jp/contests/abc215/tasks/abc215_a)

2分で突破. 書くだけ.

```python
S = input()

if S == 'Hello,World!':
    print('AC')
else:
    print('WA')
```

## [ABC215B - log2(N)](https://atcoder.jp/contests/abc215/tasks/abc215_b)

2分で突破. log を取って、誤差を考慮してその近辺をチェックするのでもいいんだけど、素直にシングルループ回しても64回くらいなので、素直に行った.

```python
N = int(input())

for k in range(100):
    if 2 ** k <= N:
        continue
    result = k - 1
    break
print(result)
```

## [ABC215C - One More aab aba baa](https://atcoder.jp/contests/abc215/tasks/abc215_c)

4分で突破. |*S*|≤8 だから全部生成しても大丈夫なので全部生成した.

```python
from itertools import permutations

S, K = input().split()
K = int(K)

print(sorted(set(''.join(p) for p in permutations(S)))[K - 1])
```

## [ABC215D - Coprime 2](https://atcoder.jp/contests/abc215/tasks/abc215_d)

8分で突破. TLE1、RE1. *A*の最小公倍数と*k*の最大公約数が1かどうかなだけじゃんと思って TLE した(馬鹿). *A*の最小公倍数なんてでかいに決まってるじゃん. *A*の最小公倍数に含まれる素数の集合と*k*を素因数分解した素数の集合の積集合が空かどうか.

```python
def make_prime_table(n):
    sieve = list(range(n + 1))
    sieve[0] = -1
    sieve[1] = -1
    for i in range(4, n + 1, 2):
        sieve[i] = 2
    for i in range(3, int(n ** 0.5) + 1, 2):
        if sieve[i] != i:
            continue
        for j in range(i * i, n + 1, i * 2):
            if sieve[j] == j:
                sieve[j] = i
    return sieve


def prime_factorize(n):
    result = []
    while n != 1:
        p = prime_table[n]
        e = 0
        while n % p == 0:
            n //= p
            e += 1
        result.append((p, e))
    return result


N, M, *A = map(int, open(0).read().split())

prime_table = make_prime_table(10 ** 5)

s = set()
for a in A:
    for p, _ in prime_factorize(a):
        s.add(p)

result = []
for k in range(1, M + 1):
    if any(p in s for p, _ in prime_factorize(k)):
        continue
    result.append(k)
print(len(result))
print(*result, sep='\n')
```

## [ABC215E - Chain Contestant](https://atcoder.jp/contests/abc215/tasks/abc215_e)

53分で突破. TLE1. 最後に選択した文字と、これまでに選択した文字集合の組に対する選び方の数を使って DP をすれば良い. サラッとは言っているけど、とんまなバグを埋め込んで直すのに時間がかかってしまった…….

```python
m = 998244353

N = int(input())
S = input()


def conv(current, used):
    return current + (used << 5)


def deconv(x):
    return x & 31, x >> 5


a = {conv(0, 0): 1}
for x in [ord(c) - ord('A') + 1 for c in S]:
    b = {}
    for y in a:
        c, u = deconv(y)
        if c == x:
            b.setdefault(y, 0)
            b[y] += a[y]
            b[y] %= m
        elif u & (1 << x) == 0:
            t = conv(x, u + (1 << x))
            b.setdefault(t, 0)
            b[t] += a[y]
            b[t] %= m
        b.setdefault(y, 0)
        b[y] += a[y]
        b[y] %= m
    a = b

result = 0
for k in a:
    if k == conv(0, 0):
        continue
    result += a[k]
    result %= m
print(result)
```
UIScrollView スクロール検知 復習

#今回の内容

* 今日、使用したものについて簡単に書きます
* UIScrollViewをスクロールした時に、検知をします。

#コードと簡単解説

##スクロールが開始された時に呼ばれる

```Swift:

   func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {

   //処理

   }

``` 

## スクロールの最中に呼ばれる
```Swift:

   func scrollViewDidScroll(_ scrollView: UIScrollView) {
  
   //処理

   }

``` 

## スクロール中に画面から指などが離れた時にUITableViewなどが動いている状態で呼ばれる （慣性で動いてる状態）

```Swift:

   func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
  
   //処理

   }

``` 

## スクロールが完全に終了した時に呼ばれる （スクロールが停止した時）

```Swift:

   func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {

   //処理

   }

``` 

#終わり
ご指摘、ご質問などありましたら、コメントまでお願い致します。