OmniAICreator/Qiita-1.07M huggingface dataset:
基本情報技術者のための副読本のススメ


# はじめに
令和3年春の基本情報技術者試験（CBT方式）に合格しました。
備忘録や情報共有を兼ねて、自身の学習方法を記事に残します。（主に読んだ書籍を紹介します）


# 試験結果

記事に説得力をもたせるため、試験結果も添えておきます。

### 午前試験
|ストラテジ系|マネジメント系|テクノロジ系|
|---|---|---|
|70%|100%|82%|

### 午後試験

|情報セキュリティ|データベース|ソフトウェア設計|データ構造及びアルゴリズム|ソフトウェア開発(Java)|
|---|---|---|---|---|
|85%|100%|86%|84%|76%|


# スキルセット
- 新卒1年目のエンジニア
- 学生時代、プログラミングを含むIT系の授業を受けた経験なし
- プライベートでJavaとJavaScript、MySQLの入門書籍を読み、簡単なTODOアプリを作成した経験あり



# 学習方法
試験に対する学習期間としては約7ヶ月。（新卒として入社したIT企業の新人研修3ヶ月を含む）


基本的には書籍からのインプットと、[基本情報技術者過去問道場](https://www.fe-siken.com/fekakomon.php)を利用したアウトプットです。

書籍の内容を実際にやってみる、というのもアウトプットに加えて良いかもしれません。
（実際にMySQLでSQLを入力してみる、丸め誤差を発生させてみる、DockerやVirtualBoxでLinuxを動かす、など）

書籍からのインプットというと、基本情報に特化した対策本をまず想像するかと思います。
しかし私の場合は対策本への依存度は低く、IT書籍であれば何にでも興味を持ち、目を通すようにしていました。
（注意：目を通しただけで、読みこなしたという意味ではない）

# 読んだ書籍
技術書から、読み物まで紹介します。

初心者向けの分かりやすい書籍は、深い内容まで問われない基本情報の試験と親和性が高いです。

それから、読み物も侮れません。
技術書の１ページだと中々覚えていられないのですが、読み物であれば『筆者の体験談として語られる技術の話』が意外と頭に残ります。

なので、この書籍に限らず、本当に興味の赴くままに手に取るのが良いと思います。

また、実際に基本情報に役に立つことはなかった、と感じる本は省略しています。



## 技術書

- イラスト図解式 この一冊で全部わかるサーバーの基本
- イラスト図解式 この一冊で全部わかるネットワークの基本
- イラスト図解式 この一冊で全部わかるクラウドの基本 第2版
- イラスト図解式 この一冊で全部わかるセキュリティの基本
- イラスト図解式 この一冊で全部わかるWeb技術の基本
- 暗号技術入門 第3版　秘密の国のアリス
- マスタリングTCP/IP 入門編
- スッキリわかるJava入門 第3版
- スッキリわかる Java入門 実践編 第2版
- 6日間で楽しく学ぶLinuxコマンドライン入門
- Linux標準教科書
- インフラエンジニアの教科書
- 改訂3版 基礎UML
- 仮想化の基本と技術 (仕組みが見えるゼロからわかる)
- 基礎からのMySQL
- スッキリわかるSQL入門 第2版

## 読み物
- SEの基本　この１冊ですべてわかる
- SEは死滅する 技術者に未来はあるか編
- 人月の神話
- みずほ銀行システム統合、苦闘の19年史　史上最大のITプロジェクト「3度目の正直」
- 窮地にいるエンジニアは、ズルい処世術で困難を突破する


# 書籍の入手元
上記の書籍以外にも10冊ほど目を通しています。
書籍に関してはとにかく数を読みましたが、自費でまかないきれるものではありません。
**近隣の大学図書館**、公立図書館、Kindle Unlimitedを積極的に利用していました。


ただし、図書館は古い書籍（=バージョンが古い）が多い、
Kindle Unlimitedは内容・質が玉石混交、といったデメリットが生じることも追記します。
Linux入門 2-4 read_only、PID、trapの使い方

[](参照ソース)
[Linux Professional Institute公式HP]:https://www.lpi.org/ja/our-certifications/lpic-1-overview
[Udemy]:https://udemy.benesse.co.jp/career/workstyle/lpic-interview-company.html
[Udemyの動画講座]:https://www.udemy.com/course/linuxlpic/?utm_source=bene-content-marketing&utm_campaign=normal&utm_content=story&utm_term=career&utm_medium=udemyads
[Linux入門 2-3]:https://qiita.com/hoglet/items/a4854983875d6e4731fe
[Linux入門 3-1]:

# はじめに
Linux初学者である自分向け用の記事です。[Udemyの動画講座]を参考にしました。
僕の勉強法は`動画を見る`→`実際に動かしてみる`→`問題演習`という流れです。

前回まで：[Linux入門 2-3]

***
#### 2. シェルスクリプト(問題、テスト、演習、発展問題)
##### 2-9. read_onlyの使い方
値を変更できないようにするためには、readonlyを用いる。

```
ファイルの中身
[test@ advance]$ cat ad2.sh 
#!/bin/bash
var=12
echo $var
readonly var
var=20
echo $var
```
```
実行結果
[test@ advance]$ ./ad2.sh 
12
./ad2.sh: line 5: var: readonly variable
12
```
関数におけるreadonlyのときは、オプション`-f`をつける。

```
ファイルの中身
[test@ advance]$ cat ad2-a.sh 
#!/bin/bash
function hello(){
  echo 'A'
}
hello
readonly -f hello
function hello(){
  echo 'B'
}
hello
```
```
実行結果
[test@ advance]$ ./ad2-a.sh 
A
./ad2-a.sh: line 9: hello: readonly function
A
```
##### 2-10. PID, trapの使い方
シェルスクリプト内で以下の場合にプロセスIDを用いることがある。
・特定のプロセスを落とす
・プロセスIDをファイルに記憶する

```
ファイルの中身
[test@ advance]$ cat ad3.sh 
#!/bin/bash
echo PID is $$
sleep 100
```
```
//実行結果
[test@ advance]$ ./ad3.sh 
PID is 625
//プロセスの確認
[test@ advance]$ ps -ef | grep 625
test         625     298  0 11:40 pts/1    00:00:00 /bin/bash ./ad3.sh
test         626     625  0 11:40 pts/1    00:00:00 sleep 100
test         629     605  0 11:41 pts/2    00:00:00 grep --color=auto 625
//プロセスキル
[test@ advance]$ kill -9 625
//反映結果
[test@ advance]$ ./ad3.sh 
PID is 625
Killed
```

###### trap
trapコマンドでプログラム終了時の挙動を設定します。

```
//プログラム終了時に実行されるコマンド
$ trap “echo exit command is detected” 0
//kill -15でのプロセス終了時に実行されるコマンド
$ trap “echo Exit “ 15
//終了時、割り込み時に実行される
$ trap “rm –f $file && echo file deleted” 0 2

1:再起動、2:割り込み(Ctrl+c)、9:強制停止(trapは設定できない)、15:プロセスの終了
```
```
ファイルの中身
[test@ advance]$ cat ad3.sh 
#!/bin/bash
echo PID is $$
trap "echo process end" 0
for i in `seq 1 1 10`;
do
  echo $i
done
```
```
実行結果
[test@ advance]$ ./ad3.sh 
PID is 631
1
2
3
4
5
6
7
8
9
10
process end
```
##### 2-11. DEBUGの方法

・デバッグモードで実行する方法(２つ)

```
1. $ bash –x ./hello.sh

2. ファイル内に記載
$ vi hello.sh
#!/bin/bash –x
...(省略)
```
```
ファイルの中身
[test@ advance]$ cat ad4.sh 
#!/bin/bash -x
echo 'hello world'
arg=$1
echo arg: $arg
```
```
実行結果
[test@ advance]$ ./ad4.sh ABC
+ echo 'hello world'
hello world
+ arg=ABC
+ echo arg: ABC
arg: ABC
```
・プログラム内で動的にデバッグにするか変更する方法

```
ファイル内に記載する
//デバッグモード
set –x
//元に戻す
set +x 
```
```
ファイルの中身
[test@ advance]$ cat ad4.sh 
#!/bin/bash
echo AAA
set -x
echo BBB
set +x
echo CCC
```
```
実行結果
[test@ advance]$ ./ad4.sh    
AAA
+ echo BBB
BBB
+ set +x
CCC
```
# シェルスクリプト講義を終えて...
ここまで学べばシェルスクリプトの文法に関してはマスターしたといってもいいと思います。（動画内解説参照）
次回から、LPICの問題編に突入です！!!

*Keep up the good work!*
[Linux入門 3-1]
***
Rによる数当てゲームの作成

#今年もあとわずか・・・
こんにちは。たいちゃんです。今年もあとわずかとなってきました。
今回は今迄と趣向を変えて、Rで簡単なゲームを作ったことを取り上げてみたいと思います。

#なぜこんなことをしようと思ったの?
実は昨年の秋頃よりぼちぼちとですが、『R』を学び始めております。その過程で乱数を扱う関数があることがわかりました。もうあれは30年ぐらい前、私が小学生の頃ですが、とあるゲームにミニゲームが3種類程ありました。そのミニゲームの1つが3桁の数字を10回位の間の回答数の内に当てるというものだったのです。『R』を学んで「このようなゲームなら私でもRで作ることが出来るのでは?」と思ったのがきっかけでした。

#ゲームのルール
- 0〜99迄の整数を当てるゲームです。
- チャンスは10回とします。
- 0〜99迄の整数を入力するたびに、『当たり』でなければそれぞれ『大きい』、『小さい』旨の表示をします。
- 10回迄に数を当てられればゲームクリア、当てられなければゲームオーバーとなります。
- 今回対象とするのは0〜99迄の整数なので、それ以外の数値や数値以外のものが入力されたらゲームを強制的に終了します。

#ゲームの仕様
- 一様乱数を生成させる関数『runif 』を使用して0〜1迄の乱数を生成します。
- その乱数に100を掛け、小数点以下を切り捨てるために関数『floor 』を使用します。
- 更にその値をxに代入します。(但しこの場合、参考文献によると大変低い確率ですが、100がxに代入される可能性があるようです。その為、仮にx=100の場合はxに0を代入し直します。)
- 今回対象とするのは0〜99迄の整数なので、それ以外の数値や数値以外のものが入力されたらゲームが終了するようにしておきます。
- 入力した数値と生成した乱数xとを比較してそれぞれ『小さいです。』、『大きいです。』と表示するようにします。
- 入力した数値がxと等しい場合、『おめでとうございます。正解です。』と表示してゲームを終了します。
- 10回目の入力が終わってもxと等しい値を入力できていない場合は『ゲームオーバーです。正解は以下の数値です。残念でした。』と表示して、xの値を表示します。


#今回作成したゲーム関数内のコード
```NumberQuiz.r
NumberQuiz <- function() {
    x <- floor(runif(1)*100)   #一様乱数を生成後100を掛けて小数点以下を切り捨て、xに代入します。
    if (x == 100) x <- 0       #もし、大変低い確率ながらx=100となっていた場合はxに0を代入します。
    for(i in 1:10) {           #ここから10回のループが始まります。
        input <- as.numeric(readline("0〜99迄の整数を入力して下さい。"))  #ここで入力の案内を出します。
		if (is.na(as.numeric(input))) {                                #入力された値が数値でなければ終了します。
            return("数値ではないので終了します。")
        } else if(input %% 1 != 0) {                                   #入力された値が整数でなければ終了します。
            return("整数ではないので終了します。")
        } else if (input < 0) {                                        #入力された値が負の数であれば終了します。
            return("負の数が入力されたので、終了します。")
        } else if (input > 99) {                                       #入力された値が99を超えた整数であれば終了します。
            return("99を超えた数が入力されたので、終了します。")
        } else if (x > input) {                                        #入力された値が小さいときの表示をします。
                print("小さいです。")
        } else if (x < input) {                                        #入力された値が大きいときの表示をします。
                print("大きいです。")
        } else {                                                       #正解であったときの表示です。
                 return("おめでとうございます。正解です。")
        }
    }
   print("ゲームオーバーです。正解は以下の数です。残念でした。" )           #10回目でも正解できなかった場合はゲームオーバーの表示をしてxの値を表示します。
   return(x)
}
```

#参考文献
The R Tips 第3 版 ―データ解析環境Rの基本技・グラフィックス活用編― 舟尾暢男 オーム社 2016/10/20 (PDF版)

#作成を終えて
やっぱり自分で考え、実際に手を動かしてプログラムを組むと、思っていた表示とは違ったりすることがありました。例えばゲームオーバー時『ゲームオーバーです。正解は以下の数値です。残念でした。』ではなく、『ゲームオーバーです。正解はx(この時のxの数値)です。残念でした。』としたかったのですが、私にはその解消法が見つけられませんでした。
一方で一度始めるとこの機能も載せたいというのが結構出てきて、自分の実力と相談してある程度で打ち切らないといつまでたっても完成出来ないということもありました。学ぶところは少なくなかったと思います。

最後迄お付き合い下さり、有難うございました。
p5.jsの関数まとめ part.7 randomGaussian()

この記事は Qiita p5js アドベントカレンダー8日目の記事です。

## これはなに
p5.jsが用意している関数について理解を深める記事です。
今回はMath、Random系に位置するrandomGaussian()について。

## randomGaussian()

### リファレンスより
> ガウス分布（正規分布）に当てはまる乱数を返します。理論的には、randomGaussian()が返す最小値や最大値はありません。むしろ、平均値から遠く離れた値が返される可能性は非常に低く、平均値に近い値が返される可能性は高いと言えます。0、1、2のいずれかの引数を取ります。
引数を取らない場合、平均値0、標準偏差1を返します。
引数が1つの場合、その引数は平均値です（標準偏差は1）。
引数が2つの場合は、1つ目が平均値、2つ目が標準偏差です。

まず`ガウス分布`が分からないので調べました。
[こちらの記事](https://ai-trend.jp/basic-study/normal-distribution/normal-distribution/)の説明がわかりやすかったです。
数学的な部分は**一切わかりません**が、「ガウス分布に当てはまる」とは次のことを指すのでしょう。以下記事の抜粋です。
>平均値と最頻値と中央値が一致する。
平均値を中心にして左右対称である。（直線𝑥=μに関して対称）
𝑥軸が漸近線である。
分散（標準偏差）が大きくなると、曲線の山は低くなり、左右に広がって平らになる。分散（標準偏差）が小さくなると、山は高くなり、よりとんがった形になる。

つまりrandomGaussian()を使えば、randomの結果をこのルールに乗せることできるというわけですね。

### Type
```typescript
randomGaussian(mean: number, sd: number): number;
```
引数
 - mean randomな数の平均値。ここが最も集合する箇所になる。
 - sd 標準偏差の数値。この値が高いほど、より分散する。

### どんな時に使えそうか
リファレンスを参考にして、次のコードを書いてみました。

```typescript
function setup() {
  createCanvas(600, 600);	
  frameRate(20)
}

function draw() {
	background(0);
    
  stroke('white')
  strokeWeight(1);
  for (let x = 0; x < 600; x++) {
    const y = randomGaussian(300, 50)
    line(x, 300, x, y)
  }
}
```
結果がこちら↓
![画面収録-2021-12-07-19.26.12.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358229/f7b52670-b419-bd60-697b-fcc58de13b42.gif)


白い線が中心の線から上下に伸びているように見えます。
`line`の第四引数がその上下に伸びる距離になるのですが、ここに`randomGaussian(300, 50)`の返り値が入ります。
引数は中央値はcanvasの真ん中が来るように300を置いていて、標準偏差は50を渡しています。

平均に対して標準偏差を少なめに設定したため、300から離れた数値が変える可能性は低くなります。
そのため中心のラインは真っ白、離れるにつれて隙間が目立つように描画されます。


## 参考
[p5.js reference | randomGaussian()](https://p5js.org/reference/#/p5/randomGaussian)
[Kotlin] 加速度センサーで歩数カウント

###はじめに
学校の卒業制作でjavaの歩数によってgifが変わるアプリを作ったので、kotlinでリメイクしました。
Androidには歩数計センサーもありますがAndroid10以上かつ使用できる端末が限られていたので加速度センサーを使用しました。

歩数計算の方法はこちらの記事を参考にさせていただきました。
[[Android]歩数計アプリを作ってみた。](https://qiita.com/TsubasaSato/items/f83778965ae179fd3baf)

##**歩数カウント**
Android端末には3軸の加速度センサーが存在します。
この3軸のセンサーから得られる加速度を合成した値の増減を利用し、歩数をカウントします。

**３軸の加速度の合計**
![無題78_20211207184705.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1520502/2727c345-cb77-971c-e05d-44a2bf3d56b0.png)

```
 val sumAcceleration = sqrt(value[0].toDouble().pow(2.0) + value[1].toDouble().pow(2.0) + value[2].toDouble().pow(2.0)).toFloat()
```

センサーから取得した生データにはノイズが含まれるため、ローパスフィルタというフィルタリング処理を行いデータを精査します。
[ローパスフィルタとは](https://okasho-engineer.com/first-order-filter/)

**ローパスフィルタ**

```
private var raw: Float = 0f         //計測値
private var lastRaw: Float = 0f     //前回の計測値
private var filter: Float = 0.6f    //フィルタリング係数 (0 < filter < 1)

lastRaw = filter * sumAcceleration + (1 - filter) * raw
```


**実際のコード**

```kotlin:StepCounterService.kt
class StepCounterService : Service(), SensorEventListener {
    private var first = true
    private var up = false
    private var raw: Float = 0f         //計測値
    private var lastRaw: Float = 0f     //前回の計測値
    private var filter: Float = 0.72f    //フィルタリング係数 (0 < filter < 1)

    override fun onCreate() {
        super.onCreate()
        val sensorManager = getSystemService(SENSOR_SERVICE) as SensorManager
        val sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
        sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_GAME)
    }

    override fun onBind(intent: Intent?): IBinder? {
        return null
    }

    override fun onSensorChanged(event: SensorEvent) {
        val value: FloatArray = event.values
        //3軸の加速度の合計
        val sumAcceleration = sqrt(value[0].toDouble().pow(2.0) + value[1].toDouble().pow(2.0) + value[2].toDouble().pow(2.0)).toFloat()

        if (first) {
            first = false
            up = true
            raw = filter * sumAcceleration
        } else {
            //ローパスフィルタリング 時系列の細かいデータを平滑化
            lastRaw = filter * sumAcceleration + (1 - filter) * raw
            if (up && lastRaw < raw) {
                up = false
                //ここで歩数がカウントされる
            } else if(!up && lastRaw > raw) {
                up = true
                raw = lastRaw
            }
        }
    }

    override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) { }
}
```

このソースではバックグラウンドで値を取るのにServiceを使用してしまっていますが、Android9以降受信されないようなので注意してください。
>Android 9（API レベル 28）以降を搭載するデバイスでは、バックグラウンドで実行されるアプリに次の制限があります。

>　・継続的報告モードを使用するセンサー（加速度計やジャイロスコープなど）では、イベントが受信されません。

##**完成したアプリ**
![無題79_20211207194609.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1520502/0f349ea7-ed21-2218-c1f5-65a1ab6bba0a.jpeg)

[実機動画(Twitter)](https://twitter.com/QnoteM/status/1468166515442995207?s=20)

歩数はスマホを持って10歩歩いて誤差+1でした。
検証が少ないですがスマホの状態にも大きく影響されやいので改良したいと思います。
歩数以外でも納得できる出来にはなっていないので改良を重ね、いつかストアに上げるまでできたらいいなと思います。
inode指定でファイルを削除するシェルスクリプト

# inode指定でファイルを削除するシェルスクリプト

FTPサーバで、ファイル名がSJISのままPUTされて、普通に削除できくなる場合があります。
対処として、inodeを指定して手作業で削除する方法はよく知られています。

cronで削除するため、シェルスクリプト化してみました。

/dataの配下でhogeユーザがオーナーのファイルのみ削除するサンプルです。
検証はCentOS 8.0で行いました。

```delinode.sh
#!/usr/bin/bash
for item in $(ls -i $(find /data -type f -user hoge) | awk '{print $1}') ; do
    find . -inum ${item} -exec rm -rf {} \;
done
```
【Ruby】map.with_indexとeach_with_indexの違い



## map.with_index
配列などの要素にindexを添えることができるメソッド

```ruby
[100, 200, 300].map.with_index do |n, idx|
  p [n, idx]
end

#=>  [[100, 0], [200, 1], [300, 2]]
```

- ```with_index(1)```で指定の数字からカウントできる

```ruby
[100, 200, 300].map.with_index(1) do |n, idx|
  p [n, idx]
end

#=>  [[100, 1], [200, 2], [300, 3]]
```


## each_with_index

```ruby
[100, 200, 300].each_with_index do |n, idx|
  p [n, idx]
end
# => [100, 0]
#    [200, 1]
#    [300, 2]
```

https://docs.ruby-lang.org/ja/latest/method/Enumerable/i/each_with_index.html
PDFKitでPDFの注釈を扱う

## はじめに

SwiftでPDFを表示・編集するために、PDFKitを初めて使う機会がありました。
その際に調べて利用したのが、PDFAnnotation（PDFの注釈機能）です。
もしPDFに編集などしたい、という方が他にいらっしゃった際の参考になれば幸いです。

PDFAnnotationを使うことで、PDFのページ毎に注釈を設定できます。
これにより、複数ページで構成されるPDFでページ間を移動しても、
注釈はページ毎の指定位置に設定されたままで、テキスト表示やハイライト、テキスト入力などが行えます。

また、タップしたPDFAnnotationはNotificationCenterで取得することができるので、
タップ時にハイライトにするなどの処理を行うこともできます。

ここでは、単純なPDFAnnotationの設定から、タップされた時の検知までを記載します。

## ①PDFに対してPDFAnnotationを設定する
注釈を設定したいPDFPageを指定して、定義したPDFAnnotationを設定します。
ここでは単純なテキスト表示を行うため、PDFAnnotationSubTypeにfreeTextを用いた例としています。
他にも様々な種類のPDFAnnotationSubTypeを指定して利用できます。
(参考: https://developer.apple.com/documentation/pdfkit/pdfannotationsubtype)

```swift
// PDFAnnotationの設定
let annotation = PDFAnnotation(bounds: CGRect(x: 200, y: 400, width: 200, height: 50), forType: .freeText, withProperties: nil)
annotation.contents = "PDFAnnotation"
annotation.font = .systemFont(ofSize: 14)
annotation.fontColor = .black
annotation.color = .clear

// 対象のPDFPageへPDFAnnotationを設定する
pdfView?.currentPage?.addAnnotation(annotation)
```

## ②PDF Annotationがタップされたかを監視、タップに対する処理を行う

次のようにNotificationCenterでPDFAnnotationのタップを検知できます。
ページ内に複数のPDFAnnotationがあっても、タップされたものを特定して個別の処理ができます。

```swift
//　PDFAnnotationがタップされたかを監視する
NotificationCenter.default.addObserver(self, selector: #selector(action(_:)), name: .PDFViewAnnotationHit, object: nil)

@objc func action(_ sender: Any) {
    // タップされたPDFAnnotationを取得する
    guard let notification = sender as? Notification,
          let annotation = notification.userInfo?["PDFAnnotationHit"] as? PDFAnnotation else {
        return
    }

    // タップされたPDFAnnotationに対する処理
}
```

## おわりに
PDFAnnotationはあくまでPDFの注釈ですが、うまく利用することでPDFへ直接テキストなどを埋め込んで編集する、などに応用できます。
このため、PDFAnnotationを利用することでPDFは意外と色々な編集ができることがわかりました。
何かの機会にPDF編集が必要だったら、この機能の利用を考えてみようと思います。
【Vim】現在の行からマッチした文字にジャンプする方法

⚠ 昔書いた記事の流用です。

やり方は簡単です．

① マッチしたい文字がある行に移動．
② `f` を押してから `マッチしたい文字` を入力．
③ 移動される．

です．

画像で解説します．今回は`Ruby`という文字の`R`に移動します．

これははじめの状態．
![はじめの状態](https://storage.googleapis.com/zenn-user-upload/b44a41fa78dcf1547c139600.png)

Rubyという文字列がある行に移動．
![その行に移動](https://storage.googleapis.com/zenn-user-upload/bbf25958ad1b1f01078a24a9.png)

`f` を押してから `Shift + r` を入力．（ノーマルモード）
![コマンド実行](https://storage.googleapis.com/zenn-user-upload/e10ecca180d88e6c0ed06e35.png)

はい．
AndroidのJavaで任意関数を一定間隔で実行する方法

⚠ 昔書いた記事の流用です。


```java
final int delayMilli = 10000; // 定期実行間隔をミリ秒で指定する．
final Handler handler = new Handler();
        final Runnable r = new Runnable() {
            @Override
            public void run() {
                // f(); 定期実行したい関数．
                // invalidate(); 再描画する場合は，これを有効にする．
                handler.postDelayed(this, delayMilli);
            }
        };
handler.post(r);
```
PyAEDT チートシート：導入編

# PyAEDTとは

PyAEDTは、外部からAnsys Electronics Desktop(AEDT)の既存のすべての機能を呼び出すことを可能にすることを<strong>目的</strong>としています
PyAEDTはMITライセンスです

PyAEDTは[Github](https://github.com/pyansys/pyaedt)で管理されています

PyAEDTを使用するには、下記いずれかの環境が必要です

- CPythonを使用
- IronPythonを使用
- AEDT内に含まれるIronPythonを使用

ドキュメント関連はこの辺りを参照 [Document](https://docs.pyansys.com/)
ライブラリや開発状況はこの辺りを参照 [Github](https://github.com/pyansys)

## CPythonnを使用したPyAEDTの環境構築

### Windows環境への導入

PyAEDTをインストールするためには、MSBiuld Tool 2015(Version14)とpythonが必要となります。
Visual Studioなどがインストールされている場合、MSBiuld Toolが含まれていますがバージョンが一致しているか確認が必要です。

- ダウンロード先
    - [MSBiuld Tool 2015(Version14)](https://www.microsoft.com/ja-JP/download/details.aspx?id=48159)
    - [python v3.7-v3.9](https://www.python.org/)

#### MSBild Tool 2015 のインストール

上記サイトよりインストーラーをダウンロードし、管理者権限でインストールします

#### CPython のインストール

ここではv3.9の最新版を使用します
上記サイトからpython v3.8.xのインストーラーをダウンロードしインストーラーを実行します
ここでは、C:\usr\Python\v308 にインストールします
インストール時にパスの設定を外した時は、環境設定などでPATHに下記を加える

- C:\usr\Python\v308
- C:\usr\Python\v308\Scripts


#### pyAEDT のインストール

pyAEDTを実行するためには、いくつかのパッケージをインストールしておく必要があります

<strong>pythonnet</strong>: .NETを呼び出し使用するためのパッケージ
<strong>pyWIN32</strong>: Windows APIを呼び出すためのパッケージ

まず、pyhtonのパッケージ管理ツールpipのアップグレードを実行します
既に、パッケージがインストールされている状態の場合は不要なので、最後のPyAEDTのインストールだけで良い

コマンドプロンプトを起動し以下を実行

```shell:pip-upgrade
> python -m pip isntall --upgrade pip
```

続けて、パッケージ管理で使用されている圧縮形式をサポートするためwheelのインストールとアップグレードを実行します

```shell:wheel-install-upgrede
> pip install wheel
> pip install -U wheel
```

pythonnetをインストールします

```shell:pythonnet-install
> pip install pythonnet
```

pywin32のインストールします

```shell:pywin32-install
> pip install pywin32
```

AEDTを呼び出すためのパッケージPyAEDTのインストールです

```shell:pyaedt-install
> pip install pyaedt
```

### Linux環境への導入

Linux環境にPyAEDTをインストールするためには、Monoとpythonが必要となります

<em>以下、調査中のた要確認</em>

#### Monoのインストール

[Mono Project](https://www.mono-project.com/)を参照し、monoをインストールする

インストールにあたり、以下のコマンドでリポジトリを追加しておく（上記サイトで確認）

```sh:CentOS7
rpmkeys --import "http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF"
su -c 'curl https://download.mono-project.com/repo/centos7-stable.repo | tee /etc/yum.repos.d/mono-centos7-stable.repo'
```

```sh:CentOS8
rpmkeys --import "http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF"
su -c 'curl https://download.mono-project.com/repo/centos8-stable.repo | tee /etc/yum.repos.d/mono-centos8-stable.repo'
```

リポジトリ追加後、yumでインストール

```sh:Command
# yum install mono-complete
```

#### CPythonのインストール



#### PyAEDTのインストール

## AEDTに含まれるIronPythonnを使用したPyAEDTの環境構築

### Windows環境への導入

### Linix環境への導入
NFTを独自コントラクトで発行してみた（plygonテストネット）

#参考にした記事
参考にした記事、というかほとんどがこの記事と同じ手順です。
[参考：「NFT完全に理解した！！になるために独自コントラクトでNFTを発行してみる方法の解説」](https://zenn.dev/razokulover/articles/7db2340f14c2cd)

というのも、上記記事は**Ethereum**のテストネット**Ropsten**でNFTを発行しているのですが、Ropsten内のテスト用Ethereumを取得するのに時間がかかる見込みがありました。（実際、Faucetでうまく取得できなかった）

そのため、テスト用トークンをすでに持っていた**polygon**のテストネット**Mumbai**にて発行をしてみました。

#開発準備、手順など
これは参考にした記事を読んでください（丸投げですみません！）

#テストネット用のガス代取得方法
以下のリンクから取得してください。
[取得先：polygon faucet](https://faucet.polygon.technology/)

下画像の赤矢印部分にて、ネットワークを**Mumbai**に選択し、受け取るためのウォレットアドレスを入力するだけです。
![nft2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2236744/b962fd25-f29d-4f18-3ca4-75700e5d9d5b.png)


#コードの変更点
コード内で**Ropsten**となっている箇所をすべて**Mumbai**に修正します。

それから、これは変更点ではありませんが自分が少しつまづいた箇所を共有しておきます。
デプロイ設定をする`hardhat.config.js`にて、自分のウォレットの秘密鍵は以下のように記入しました。
    
    //以下は元コードの抜粋です。
    //0x0000(略)の2か所は、自分のウォレットの秘密鍵を入力してください
    module.exports = {
      solidity: "0.8.4",
      networks: {
        mumbai: {
          url: "Alchemyで得たropstenのURL",
          accounts: ["0x000000000000000000000"], 
        },
        mainnet: {
          url: "Alchemyで得たEthereumのmainnetのURL",
          accounts: ["0x000000000000000000000"],
        },
      },
    };

#（補足）alckemyのVIEW KEYの取得場所
これも自分が探すのに一瞬手間取ったので念のため共有です。
参考記事にあるように、まずは適当にプロジェクトを作成します。
作成できたら**App**を開くと、以下画像の赤矢印部にて**VIEW KEY**を取得できます。

![nft1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2236744/6d63126f-9d61-8253-ba52-6893bfb44c5d.png)


#おわり
ブロックチェーンエンジニアを目指して勉強中ですが、ブロックチェーン開発についてはまだ情報が多くないため、この記事が少しでも誰かの参考になれば嬉しいです。

以上、NFTを独自コントラクトで発行する方法でした。
Edge が Chrome インストールを止めようとしてくるらしいので、Edge を使わず Chrome をインストールしてみた

Windows に標準で搭載されているブラウザ Microsoft Edge (Edge) は、よく Google Chrome (Chrome) をダウンロードするために使うブラウザと揶揄されます。

そんな Edge さんは最近、Google Chrome をインストールすると必死に引き止めてくる機能を実装するかもしれないそうです。

> GIGAZINE : Edgeに「Chromeのダウンロードを中止するように必死で促す新機能」が追加、実際の画面はこんな感じ
> https://gigazine.net/news/20211203-edge-chrome/

え。。。なにしてくれてんの。。。

でも、ちょっとまってください。
そもそも、Google Chrome をインストールするのに Edge や他のブラウザを使う必要はありません。

## ブラウザを使わずコマンドで Google Chrome インストール

PowerShell で下記コマンドを実行するだけです。
(PowerShell は管理者権限の必要ないです)

```powershell
winget install --id Google.Chrome --force --silent
```

インストールした Chrome は、通常の方法でインストールした Chrome と同じくアップデートやアンインストールが可能です。

### あれ？ winget コマンドがエラーになる

こんなエラーが出た場合。
(エラーは赤文字で表示されてるはず)

```
> winget install --id Google.Chrome --force --silent
winget : 用語 'winget' は、コマンドレット、関数、スクリプト ファイル、または操作可能なプログラムの名前として認識され
ません。名前が正しく記述されていることを確認し、パスが含まれている場合はそのパスが正しいことを確認してから、再試行して
ください。
```

winget は Windows 11 に標準搭載されている Microsoft 公式ツールです。
**Windows 10 でエラーが出た場合、winget をインストール**してください。
インストール方法について詳しくは別記事を参照ください。
winget 自体も PowerShell からコマンドでインストールできます。(できるようにしました。)



https://qiita.com/mainy/items/e204c8cac3324768b8e3

## 感想

Chromium ベースの Microsoft Edge は正直悪くはないと私は思います。
初心者が使っていても、IE や 旧 Edge のときのように乗り換えを薦めたりしません。
ただ、今回も含め反感を買うような方法はいただけないですね。

winget は Adobe Reader や Zoom などのアプリもインストールできます。
今回は Edge の不満からコマンドインストール方法をご紹介しましたが、こちらの方が簡単なんじゃないでしょうか？
社内 SE などしている方は、Infrastructure as Code の第一歩として winget からのアプリ導入をオススメします。
スクリーンショットたくさんの手順書作るより、コマンド1行実行するほうが絶対に楽です。

最後に、私は winget より Scoop 派、Chrome より Vivaldi 派です。
【Ruby】インクリメント++の代わりは+=

##インクリメント
変数の値を1増やす演算。


Rubyではインクリメント```++```がないので、代わりに```+=``` ```succ``` ```next```を使う。

```ruby
sum = 0
sum += 1
puts sum

#=> 1
```

```ruby
sum = 0
sum = sum.succ
puts sum

#=> 1
```

##デクリメント
変数の値を1減らす演算

Rubyではデインクリメント```--```がないので、代わりに```-=``` ```pred```を使う。

```ruby
sum = 0
sum -= 1
puts sum

#=> -1
```

```ruby
sum = 0
sum = sum.pred
puts sum

#=> -1
```
新人教育について コーディング

# はじめに

前回の記事に引き続き、コーディングに関する課題と対応を記載していきたいと思います。
他、指導対象も含め、以下記事と重複する為、省略。
https://qiita.com/junnishi/items/496b492d3bbc95ceaf4c

# 数人指導してみての共通課題と対応

1.変数が好き
2.メソッド単位でのやりたいことが遠い
3.自分が何を書いているかわからない

## 対応

先に対応を記載してしまいますと、以下の対応をしました。

ア）コーディングルールを先に読ませ、理解度を確認。
これをすることで後々なんで記述の仕方を変えるべきか？という指摘の根拠にしています。
例として以下はgoogle coding styleのJavascriptのURLです。
https://google.github.io/styleguide/jsguide.html

イ）コードレビューをする。
当たり前だろ！と思われるかもしれませんが、特に社内システムを扱っていたり、ビジネス用のWebアプリケーションを取り扱っているところでは、やっていないところも多いのではないでしょうか？（転活したときに聞いた感じより）
これをやらなかったシステムはかなり混沌を極め、いわゆる「レガシーシステム」に変貌していきます。
大ベテランが作ったものだろうが、何だろうが、PL等中心となって必ず実施すべきです。

大まかに私が見ている観点・課題は以下です。
※コーディング規約、ここは関数化すべきだろうなど基本的なことは除く

## 課題の詳細（1.変数が好き）

極端な例ですが、以下のような感じです。

```
let agreed = $("#agreed").val();
if(agreed){
 ...
}
以降「agreed」は出番なし
```
上記の場合、右辺がやや複雑で、意味を補完するためのものであれば変数を利用してよいと思いますが、

```
if($("#agreed").val()){
}
```
これで十分伝わると考えます。
こういった変数の使い過ぎというのは着目してレビューするようにしています。
特にもJavascriptの場合は「let」が出てきた段階で「本当かなぁ？」と思う次第です。

## 課題の詳細（2.メソッド単位でのやりたいことが遠い）

こちらも例で示しますとこんな感じです。
1の変数の使い過ぎも多少含んでいます。

```
const createOrderedTable = () => {
  // 値を取得するための準備処理
  const condition1 = $("#condition1").val();
  const condition2 = $("#condition2").val();
  const param = `condition1=${condition1}&condition2=${condition2}`
  
  // 前準備となるデータ群1を取得
  $.ajax({
    type: "GET",
    url: `xxxxx?${param}`,
    dataType: "json"
  }).done( ()
    data => {
        $.ajax({
        type: "GET",
        url: `xxxxx?${data.param}`,
        dataType: "json"
     }).then(
       data => {
         for(let i = 0;i< data)

       },
       error => {・・・}
     )},
    error => {・・・}
  );

}

```

ここでこの関数で最終的に表現したいことは

```
       data => {
         for(let i = 0;i< data)

       },
```
この部分だと思います。
この関数がやりたいことがパッと見でわからないというのはしばしば見られます。
自分が表現したいことがなんなのか？それを表現するまでに「自分の頭を整理するためのコードを書いていないか？」というのは常日頃から指摘事項として挙げることが多いです。
createOrderTableなのであれば可能な限り早くやりたいことに到達すべきと思います。


## 課題の詳細（3.自分が何を書いているかわからない）

Web分野では特にクラス定義を書くときに、よく見られます。
BootStrapなど使用していると公式記事から参照してパーツを作成するというのはよくあることかと思われます。
その際、使用しているクラスの特性を確認しないというのは多い印象を受けました。
「このクラス必要なの？」これに明確な答えがない場合は要注意です。
WSLにanyenvを入れてrbenvを使ってrubyを動かすまで

https://qiita.com/nomurasan/items/84674c0581380aa9acc8

のスピンアウト記事です。
軽い気持ちでやってみたら案外ハマったので別記事にしました。

## 前提
1. WSLが動いている
1. linuxbrewが使える
1. anyenvが使える

前提の手順については、上記記事をご参照ください。

## 1. rbenvをインストールする
```
anyenv install rbenv
```

超簡単！
うまく行かない場合はanyenvへのパスが通ってない可能性が高いと思います。

## 2. rubyをインストールする
私の環境ではここで問題が発生しました。

#### rbenvまでのパスも通したのに、`rbenv: no such command 'install'`と怒られる
これは`brew install ruby-build`で解決できます。gccでもbuild-essentialsでもないんですね。ハマりやすいので気をつけて！

#### BUILD FAILEDになる
これはバージョンにもよると思いますが、現行で最新の3.0.3を入れようとすると「パッケージが足りてないので入れてね」と怒られていました。
私の環境で足りなかったのは以下の通り。

- `sudo apt install -y zlib1g-dev`

これはエラーメッセージ内の`Try running 'apt-get install -y zlib1g-dev' to fetch missing dependencies.`を落ち着いて読めば大したことないです。
だいたい公式サイトか、anyenv等を使用した場合に必要なパッケージが別途githubなどに書いてあると思いますので、そちらを参照するのが一番良い方法と思います。

## 3.rubyを実行する
ここでもハマりました。

### インストールできたのにruby -vで`Command 'ruby' not found`になる
インストールが上手く行ってもパスを設定する必要があったりします。

```
echo PATH="$HOME/.rbenv/shims:$PATH" >>$HOME/.profile
exec $SHELL -l
ruby -v
```

anyenvを介さない場合、rbenvでinstallした状態でrubyにパスが通っているのですが、anyenvだとrbenvでrubyがインストールされるパスが異なるため？か、うまくいきません。
解決方法としては、anyenvのrbenvで入れたrubyのパスを指定してあげればいいです。

### それでもrubyが実行できない
rubyのインストールができたら、`rbenv global （バージョン）`もお忘れなく。

### それでもうまく行かない場合
どうしてもうまくいかないなら、インストールするバージョンは最新版に拘らず、古いものを使う方法も検討してみるのも良いかもしれません。

あるいは、個人開発と割り切ってapt install rubyとし、ディストリビューションで管理してしまう手もあります。

## 戻る

https://qiita.com/nomurasan/items/84674c0581380aa9acc8
経験半年学生がプロジェクトリーダーに初挑戦した話

# はじめに

**Web開発を学び始めて半年のひよっこ大学生**が，**未経験メンバーのみで構成されたチーム**のリーダーとして，あるプロジェクトを進めていくことになりました．

当然，初リーダーです．

「プロジェクト」とは言いましたが，納期や予算こそあるものの対価は発生しておらず，一般的なプロジェクトと比較して規模や責任感はかなり小さいと思います．

しかし，経験の浅い私には，それでも学びが多かったと感じています．

- **技術的不安要素は早めに着手する**
- **不安要素は足し算ではない**
- **手本となる実装をしておく**

他のプロジェクトでは通用しないものもあると思いますが，上記3つについて簡単に説明していきます．

# 学んだこと

## 技術的不安要素は早めに着手する

プロジェクトを進めていくには工数の見積りが必要ですが，今回はメンバーの誰も触れたことがない技術があり，その技術が関わる部分については全くイメージできませんでした．

今回は，そのようなタスクに関しては**早めに着手する**ことで対応しました．

**少しでも着手すれば工数のイメージの解像度が上がる**と思ったからです．

今回はこの施策が上手くはまり，技術的不安要素を含むタスクに関しても大幅な遅れをとることなく進めることができました．

あくまで目的は**工数見積りをより正確にすること**なので，優先度を上げて完了まで持っていく必要はないと思います．

実装前に環境構築をしておくのと同じイメージですね．


## 不安要素は足し算ではない

今回は自分の学習コストが最小になるような技術選定をしました．

理由としては，経験の少ない技術を使った場合，学習コストがかかるだけでなく，設計や見積もりの精度の低下や，環境構築やデバッグの速度の低下といった副作用が二次災害的に生じると考えられるためです．

また，今回は私のマネジメント経験がないだけでなく，メンバーが全員開発未経験であるため，私がある程度教えながらの開発になるであろうことが予想できました．

つまり，私の学習が進まない限り，メンバー全員の開発が進まないということであり，私の学習がほぼ全てのタスクに対するブロッキングタスクになっていたのです．

「慣れない技術を選定する」という**１つの選択だけで，不安要素が爆発的に増える可能性もある**ということですね．

不安要素は単純な足し算ではないようです．

あのとき慣れない技術を選定していたらと思うと恐ろしいです…


## 手本となる実装をしておく

これは未経験メンバーと開発する際にやってよかったと思ったことです．

コンポーネントやAPIの簡単な実装例を早い段階でしておくということです．

未経験の人でも，何かコードがあるだけで，それを真似しながら実装できたり，ググる手がかりにもなります．

また，変数名やコードの記法が自然と統一されるという利点もありました．

自分が実装するコスト以上のリターンがあったので，やってよかったなと思っています．


# 最後に

今回はなんちゃってプロジェクトのなんちゃってリーダーでしたが，この経験を活かして，実際の本格的なプロジェクトでも活躍していきたいです．

アドバイスなどあればコメントいただけると嬉しいです．
マインクラフトで馬の自動貸出をする

# 概要
CKBPluginは、Minecraftサーバ(SpigotMCサーバー)上で馬の自動貸出を行うプラグインです。
本記事では主にCKBPluginの技術概要について説明し、添付資料としてプラグインコードのGitHub情報を掲載する。

# 想定する読者
- Spigotプラグインの開発について理解を深めたい方
- 馬好きの方(？)

# プラグインの開発背景
以前、マイクラ内でのトロッコの自動運行に関する下記の記事を投稿しました。

https://qiita.com/CIB-MC/items/745864434e2ef4ce6e41

本プラグインはゲームプレイ上、鉄道以外に移動手段を補完する目的で開発されました。
今風に言えばマイクロモビリティです(？)

# プラグインの主な仕様
- 専用の馬(エンティティ)を右クリックすることで貸し出された馬に騎乗する
- 貸し出された馬から降りると、自動的に当該の馬をデスポーンさせる

# 貸出場所用の馬エンティティの仕様と実装
いや、トロッコと同じように専用の看板を右クリックでもいいんですよ？
でもなんかそれだと味気ないので下記仕様の馬を専用馬としました。

・馬につけられている名前が特定のもの(CKB Station)であること。
・AIが設定されていないこと ~~地味に恐ろしい仕様~~

貸出場所用の馬をスポーンさせる実装は下記の通りです。

``` 抜粋：CommandExe.java
// とりあえず馬をスポーンさせる
World world = player.getWorld();
Entity entity = world.spawnEntity(player.getLocation(), EntityType.HORSE);

// 馬がスポーンしたかチェックする (WorldGuradなどでスポーン禁止されている場合などを想定)
if (entity == null || !(entity instanceof Horse)) {
    player.sendMessage(ChatColor.RED + "[CKB] 馬の生成に失敗しました。");
    return;
}
Horse horse = (Horse)entity;

// 不死にする(デスポーン無効化含む)
horse.setInvulnerable(true);
horse.setRemoveWhenFarAway(false);

// AIを無効化する
horse.setAI(false);

// 飼いならした状態にする
horse.setTamed(true);

// 専用の名前をつける
horse.setCustomName("CKB Station");

// 成体でないと乗れないので、そうでなければ成体にする
if (!horse.isAdult()) {
    horse.setAdult();
}

// 鞍をつける
horse.getInventory().setSaddle(new ItemStack(Material.SADDLE, 1));
```

# 借りるときの処理

処理としては貸出場所用の馬をスポーンさせるときと同じところもありますが、移動速度や体力のパラメータを設定してイイ馬にしておきます。

``` 抜粋：EventListener.java
// とりあえずプレイヤーの位置に馬をスポーンさせる
Location loc = player.getLocation();

// スポーンしたかチェックする
Entity se = player.getWorld().spawnEntity(loc, EntityType.HORSE);
if (se == null || !(se instanceof Horse)) {
    return;
}
Horse pHorse = (Horse)se;

// 貸出用の名前をつけておく
pHorse.setCustomName("CKB Rental");

// AI無効化
pHorse.setAI(false);

// 成体化
pHorse.setAdult();

// 鞍を装備させる
pHorse.getInventory().setSaddle(new ItemStack(Material.SADDLE, 1));

// 各種パラメータを調整する
pHorse.getAttribute(Attribute.GENERIC_MAX_HEALTH).setBaseValue(30.0);
pHorse.setHealth(30.0);
pHorse.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).setBaseValue(0.45);

// 所有者をプレイヤーにする
pHorse.setOwner(player);

// 乗せ込み＋個別チャットメッセージ送信
pHorse.addPassenger(player);
player.sendMessage(ChatColor.GREEN + "[CKB]" + ChatColor.WHITE + " ご利用ありがとうございます。どうぞご安全に！");
```

# 降りるときの処理

降りた時点でレンタル終了とします。

``` 抜粋：EventListener.java
// 降りたのがプレイヤーか確認
Entity e = event.getExited();
if (!(e instanceof Player)) {
    return;
}
Player player = (Player)e;

// プレイヤーが降りたのが馬からか確認
Vehicle v = event.getVehicle();
if (!(v instanceof Horse)) {
    return;
}
Horse horse = (Horse)v;

// レンタル用の馬でなければreturn
if (!EventListener.isRentalHorse(horse)) return;

// 馬のデスポーン、個別チャットメッセージ送信
horse.remove();
player.sendMessage(ChatColor.GREEN + "[CKB]" + ChatColor.WHITE + " ご利用ありがとうございました。この後もご安全に！");
```

# その他の機能
- インベントリから鞍を盗まれないようにする対策
- 貸出場所用馬の移動モード(権限者のみ変更コマンドを実行可)

# プラグインソースコード(GitHub)
https://github.com/CIB-MC/CKBPlugin

# トリビア
プラグイン名の元ネタはFF14のチョコボポーターです。
~~本当のチョコボの綴りは "chocobo" なのは秘密。~~

# さいごに
楽しい乗馬ライフを！
RxJava概要メモ

■RxJavaの特徴

- Observerパターンをうまく拡張している
  - データの通知 + データストリームの完了の通知・エラー発生時の通知
- 非同期処理が行いやすい
  - Observable契約というガイドラインにしたがって実装している限り、直接的なスレッドの管理がなくなり実装もシンプルになる
  - 同期処理・非同期処理で実装方法が大きく変わらない
- 関数型プログラミングの影響を受けている
  - 処理の多くを関数型インターフェースを受け取るメソッドを使って実現している
  - 入力と結果のみ決めてあれば具体的な処理に関しては開発者に委ねられる
  - 関数型プログラミングの原則に従うことで、処理の影響範囲を狭めることができ非同期処理の複雑さを回避できる


■非同期処理

- RxJavaでは、開発者が直接スレッドを扱い管理をしなくて良いように、各処理の用途に合ったスレッド管理を行うSchedulerを用意している
- そのSchedulerを指定することで、スレッドの制御ができる

- Schedulerを指定できる箇所
  1.生産者（Observable）
  2.消費者（Subscriber）

- 注意点
  - 生産者から消費者までの処理を閉じた作りにする
  - 外部の変数を参照した処理を行った場合、整合性が取れなくなるリスクがあるため
Flowable vs Observable
- Flowableを使うケース
  - 大量のデータ（10000件以上とか）を扱う場合
  - ネットワークやDBなどのI/O処理を行う場合
- Observableを使うケース
  - GUIイベント
  - 少量のデータ（1000件以下とか）を扱う場合
  - データの処理が基本的には同期的でJava標準のStreamの代わりとして使う場合

- 補足
  - FlowableよりObservableの方がオーバーヘッドが少ない
    - 細かいレベルでのパフォーマンスが重要な場合はObservableの方が良さげ

■Single/Maybe/Completable

- 通知するデータが一件 or 一件未満の場合に利用するクラス
  - Single -> 通知するデータが一件だけ確実にあるクラス
  - Maybe -> 通知するデータが一件だけあるのかないのか不明なクラス
  - Completable -> データを通知せず完了だけを通知するクラス
- 処理中にエラーが発生した場合、エラーを通知する
- データの通知を持って完了を意味する（onNext(),onComplete()がない。onSuccess()のみ。）

■非同期処理

- subscribeOn()
  - 生産者が処理を実行するスレッドを指定
  - 一度しか設定できない
- observeOn()
  - 消費者が処理を実行するスレッドを指定
  - 指定したスレッドで以降の処理を実行する
  - 複数設定できる

- Scheduler
  - RxJavaで用意されているスレッドを管理するクラス
  - io用、毎回新スレッド建てる用などいろいろある

- flatMap()
  - 受け取ったデータを元に再度生産者を生成し、そこで通知されたデータを結果として通知するオペレータ
  - Singleだと関係ないが、Observableだと通知するデータが複数件あるため、出力順は保証されない
NumPyの*(乗算演算子)は、配列か行列かで挙動が変わる。

numpyでは、配列(`numpy.array`)と行列(`numpy.matrix`)を扱うことができ、両者間の演算であっても基本的にはスムーズに行うことができます。

しかし`*`(乗算演算子)では注意が必要です。

通常、配列同士の演算ではこの記号はアダマール積を表します。行列積を求めたい場合には`np.dot()`または`@`演算子を使用します。

しかし、`*`演算子で求まるのは常にアダマール積だと言う理解は危険で、行列同士の演算で`*`を用いた場合は、アダマール積ではなく行列積が求まることに注意が必要です。当然`@`で求まるのも行列積です。

また、一方が行列でもう一方が配列だった場合、自動的にどちらも行列にキャストされるため、求まるのは行列積であり、返り値の型も`numpy.matrix`になります。

演算によって得られる結果とその型を表にまとめると以下のようになります。

|                        |               `*`演算子               |            `@`演算子             |
| :--------------------: | :-----------------------------------: | :------------------------------: |
|       両方が配列       | **アダマール積**<br />(**配列**) | 行列積<br />(**配列**) |
|       両方が行列       |   行列積<br />(行列)    | 行列積<br />(行列) |
| 片方が配列で片方が行列 |   行列積<br />(行列)    | 行列積<br />(行列) |



```python
import numpy as np
a = [
     [1, 2, 3],
     [4, 5, 6],
     [7, 8, 9]
]
a_array = np.array(a)
a_matrix = np.matrix(a)

b = [
    [1, -1, 0],
    [1, -1, 0],
    [1, -1, 0]
]
b_array = np.array(b)
b_matrix = np.matrix(b)

# *演算子

# 配列 * 配列 -> アダマール積(配列)
c = a_array * b
print(c, type(c))
# [[ 1 -2  0]
#  [ 4 -5  0]
#  [ 7 -8  0]] <class 'numpy.ndarray'>

# 行列 * 行列 -> 行列積(行列)
c = a_matrix * b_matrix
print(c, type(c))
# [[  6  -6   0]
#  [ 15 -15   0]
#  [ 24 -24   0]] <class 'numpy.matrix'>

# 行列 * 配列 -> 行列積(行列)
c = a_matrix * b_array
print(c, type(c))
# [[  6  -6   0]
#  [ 15 -15   0]
#  [ 24 -24   0]] <class 'numpy.matrix'>

# @演算子

# 配列 @ 配列 -> 行列積(配列)
c = a_array @ b_array
print(c, type(c))
# [[  6  -6   0]
#  [ 15 -15   0]
#  [ 24 -24   0]] <class 'numpy.ndarray'>


# 行列 @ 配列 -> 行列積(行列)
c = a_matrix @ b_array
print(c, type(c))
# [[  6  -6   0]
#  [ 15 -15   0]
#  [ 24 -24   0]] <class 'numpy.matrix'>


```
Please make sure you have the correct access rights and the repository exists.の解決法

## 何をしたのか？
 インターン先から支給されたPCでGitに接続しようとしたところ上述のエラーに遭遇。研究室で新規PC購入時Gitに接続すつ際にたびたび出会っているのでこの際にまとめてみました。
 参考に載せますが、大変皆さんわかりやすい記事残していただいておりました！
 ぜひそちらも参考にしてみてください。


### 環境
- M1 Mac　Book Pro
- Big Sur 11.6


## 解決までのStep
**1. ssh keyを作成**
**2. 作成したものを新規にGitHub登録**
**3. 作成したssh key を参照するようにconfigを編集**
**4. 完成**


## Step1 ssh keyを作成

```bash
$ ssh-keygen -t rsa GitHubに登録しているメールアドレス
作成するディレクトリとファイル名を聞かれる。基本的に~/.ssh/id_rsaとなっていればOK
-------------------
Enter file in which to save the key (~/.ssh/id_rsa):
-------------------
パスフレーズは特に必要なければEnterでスキップ
-------------------
Enter passphrase (empty for no passphrase):
-------------------
もう一度同じパスフレーズを入力してくださいと聞かれるので、また何も入力てない場合enter
-------------------
Enter passphrase (empty for no passphrase):
-------------------

以下のコマンドで作成されたことを確認。以下のように表示されればOK
$ ls ~/.ssh/
-------------------
id_rsa id_rsa.pub 
-------------------
```

### ちなみに…

```bash
Enter file in which to save the key (~/.ssh/id_rsa)
```

の部分で好きな名前やディレクトリを入れた場合、後ほど設定する.ssh/configのIdentifyFileの部分の設定を変更する必要があります。

詳しくはStep3で...

## Step2 作成したSSH KeyをGit Hubに新規に登録

　新規に作成した公開鍵をGit Hubに登録します。

　クリップボードにcatやlessで表示させたり、下記のコマンドを使ってもコピーできます。

```bash
$ pbcopy < ~/.ssh/id_rsa.pub (Mac)
$ clip < ~/.ssh/id_rsa.pub (Windows)
```

　下記にアクセスして、右上のAdd SSH key から鍵を追加することができます。

[GitHubのSSHの設定画面](https://github.com/settings/ssh)

[公開鍵をgithubにアップする](https://qiita.com/shizuma/items/2b2f873a0034839e47ce#%E5%85%AC%E9%96%8B%E9%8D%B5%E3%82%92github%E3%81%AB%E3%82%A2%E3%83%83%E3%83%97%E3%81%99%E3%82%8B)が参考になります。


## Step3 作成したSSH Keyを参照するようにconfigを編集

　.ssh/configを編集して、作成したSSH Keyを参照するようにしていきます。

**vimを立ち上げて~/.ssh/configを編集**

```bash
$ vim ~/.ssh/config
何も表示されていない場合は、下記内容をコピペ
configファイルが既に存在する場合はHost名が被っていないことを確認して下記内容を追記
-------------------
Host github
  HostName github.com
  IdentityFile ~/.ssh/id_rsa
  User git
-------------------
# iでインサートモード
# インサートモードからescを押した後、:wqで保存して終了
```
:::note warn
この時に、Step1で

Enter file in which to save the key (~/.ssh/id_rsa)

の部分で好きな名前やディレクトリを入れた場合は、.ssh/configのIdentifyFileの部分を自分用に変更してください。
:::


個人的には、

```bash
ls -l | grep ^d
drwxr-xr-x 4 hogehoge staff  136  7  7 21:32 bitbucket
drwx------ 4 hogehoge staff  136  4 28 19:54 gitlab
drwxr-xr-x 4 hogehoge staff  136  7  7 21:33 github
drwxr-xr-x 5 hogehoge staff  170  7  6 14:21 AWS
```

みたいに.sshでディレクトリを作って、ディレクトリの中にそれぞれ秘密鍵と公開鍵が入るようにしているので、

```bash
Host GitHub
    HostName github.com(絶対これ)
    IdentityFile ~/.ssh/github/id_rsa
    TCPKeepAlive yes
    IdentitiesOnly yes
    User git(絶対これ)
```

というふうにしています。

## Step4 Pushしてみる

　ここまでで問題なく使えるようになっているはずです。確認したい場合は、適当にPushしてみるといいと思います。

```bash
$ git push -u origin --all
-------------------
Counting objects: hoge, done.
Compressing objects: 100% (hoge/hoge), done.
~~ 略 ~~
master from origin.
-------------------
```

### 参考
https://qiita.com/shizuma/items/2b2f873a0034839e47ce#%E5%85%AC%E9%96%8B%E9%8D%B5%E3%82%92github%E3%81%AB%E3%82%A2%E3%83%83%E3%83%97%E3%81%99%E3%82%8B

https://qiita.com/GakuNaitou/items/81dbbd3ea6211af71648

https://qiita.com/yoshidev523/items/b5e5923b2f658f09e0a6
tweepy + Twitter API V2でツイート

# はじめに

ホームページをクロールしてただツイートしたかっただけなのにハマったのでまとめた。

# 状況

ネットで検索すれば多数みつかる、以下のような`tweepy`を使用したプログラムを実行するとエラーメッセージが出てツイートできない

```sample_APIv1.1.py
import tweepy

# Twitter Deverloper Portalで取得
ck = 'あなたのAPI Key'
cs = 'あなたのAPI Key Secret'
at = 'あなたのAccess Token'
ats = 'あなたのAccess Token Secret'

auth = tweepy.OAuthHandler(ck, cs)
auth.set_access_token(at, ats)
api = tweepy.API(auth)

api.update_status("ツイート文")
```

```errormessage.log
tweepy.errors.Forbidden: 403 Forbidden
453 - You currently have Essential access which includes access to Twitter API v2 endpoints only. If you need access to this endpoint, you’ll need to apply for Elevated access via the Developer Portal. You can learn more here: https://developer.twitter.com/en/docs/twitter-api/getting-started/about-twitter-api#v2-access-leve
```
エラーメッセージの要点は以下2点

+ `Essential（エッセンシャル）`アクセスではTwiter API V2しか使用できない
+ このAPIを使用したい場合`Elevated（エレベイティッド）`アクセスを申請することが必要

# ハマった原因
Twitter社は1か月ほど前(2021/11/15)に開発者向けプラットフォーム（開発者向けプログラム）を更新した。
自分は数日前に開発者登録したので無料かつ登録のみで使用できる`Essential`レベルで登録したのだが、`Essential`レベルは`Twitter API V2`しか使用できずtweepyを使ってツイートするには別のやり方が必要だった。（ネットで見つかるサンプルはTwitter API V1.1向けが多いようだ）
なお、Twitter API V2を申請済みの以前からの開発者は上位の`Elevated`レベルに自動的に移行されて`Twitter API V2`と`Twitter API V1.1`の両方が利用できるようなので問題はないかもしれない。

# Twitter API V2に対応したプログラム

`tweepy.API()`ではなく`tweepy.Client()`を使用する。（tweepy V4.0.0以上が必要）

```sample_APIv2.py
import tweepy

# Twitter Deverloper Portalで取得
ck = 'あなたのAPI Key'
cs = 'あなたのAPI Key Secret'
at = 'あなたのAccess Token'
ats = 'あなたのAccess Token Secret'

client = tweepy.Client(consumer_key=ck, consumer_secret=cs, access_token=at, access_token_secret=ats)

#パラメータ名を省略したい場合
#client = tweepy.Client(None, ck, cs, at, ats)

client.create_tweet(text="ツイート文")
```
# その他の注意

ツイートするためには`App permissions`（アプリケーションレベルのパーミッション）が`Read and write`か`Read and write and Direct message`である必要がある。（初期値は`Read`)

[Developer Portal](https://developer.twitter.com/en/portal/dashboard)で`Access Token`と`Access Token Secret`を<font color="#ff0000">生成する前に</font>`app permissions`を`Read(初期値)`から`Read and write`か`Read and write and Direct message`に<font color="#ff0000">変更しておく</font>。
`App permissions`を`Read(初期値)`のまま`Access Token`と`Access Token Secret`を<font color="#ff0000">生成してしまった場合は</font>、`App permissions`を変更してから`Access Token`と`Access Token Secret`を<font color="#ff0000">再生成すればよい</font>。


# 参考

[Twitter Deverloper Portal](https://developer.twitter.com/ja)
[tweepy ドキュメント](https://docs.tweepy.org/en/stable/index.html)
[tweepy Twitter API v2 リファレンス](https://docs.tweepy.org/en/stable/client.html)
[tweepy Twitter API v2 サンプルプログラム（Create Tweet）](https://github.com/tweepy/tweepy/blob/master/examples/API_v2/create_tweet.py)
【Swift】actor（async/await）がシミュレータで想定通りの動きをしない

#注意
本記事にはシミュレータで想定通りの動きをさせる方法はありません。
詰まる前にシミュレータだけではなく実機でテストしましょうという注意喚起です。

#結論
シミュレータでは扱えるスレッド数が少ないようで、想定外の処理待ちが発生する可能性があるようです。
サブスレッド（actor）を２個以上同時に使用する場合は可能であれば実機でテストして下さい。

私はシミュレータで使用出来るスレッド数の変更方法は見つけられませんでした。

#シミュレータでの挙動について
##検証端末
* Mac mini 2018 （core-i3）
* M1 Mac Mini
* iPhone 11 Pro Max

##検証内容
actorのインスタンスを２つ用意し間を開けず順にsleepを実行します。
その際のsleepの次の処理が実行されるタイミングを確認します。

※あまりにも簡単なのでソースは割愛していますが、後日追記するかもしれません。

###sleepを用いる理由
sleepはスレッド１つ占有して止めることができます。
スレッド関連の待機処理では、待機中のスレッドとして他の処理にスレッド明け渡すものもあります。
その場合は待機中に他の処理が行われるため、今回の検証には適しません。

##検証結果
###実機　iPhone 11 Pro Max (想定通りの挙動)
２つのsleep処理は並行して処理され、sleepの次の処理はほぼ同時に行われます。

###シミュレータ Mac mini
２つのsleep処理は順に行われ、sleepの次の処理はsleep分の時間が空いて処理されます。

##考察
上記のことから、シミュレータではメインスレッドとサブスレッド１つまで割り当てられており、
処理上限に達した為スレッドが空くまで待機していると考えられます。

#総括
actor（async/await）がシミュレータが実機とは異なる動作を行うことが分かりました。
想定の動作が行われなかった場合に、ソースを見返して悩むだけではなく、
実機で確認するということも忘れずに行うようにして下さい。

またシミュレータの問題だけでなく、端末の性能差や状態によっても引き起こされる事に注意して下さい。
並列処理を行う上では常に付き纏う問題でもあります。

しかし、過度に気にしなければならない問題はありません。
actorは待機スレッド有効に活用してくれます。
今回sleepで止めたように、１スレッド占有し続けるような重い処理でなければ問題ありません。

#ブログ記事紹介
以下はactor、async、awaitに関する私のブログ記事です。
長くなりますし、他にも書いてる人は居そうなのでQiita版の記事を書くかは検討中です。

https://thwork.net/2021/09/30/swiftui_async-await/

https://thwork.net/2021/10/02/swiftui_actor/

https://thwork.net/2021/10/29/uikit_async-await/
MQTT とは

## 勉強前イメージ

あんま見たこともないーー

## 調査

### MQTT とは

Message Queueing Telemetry Transport の略で、
ブローカー型のメッセージ伝達プロトコルになり、機器同士の通信に使用されます。
ネットワークが不安定な場所でも動作するように設計されているのが特徴で、主にM2MやIoTなどに向いています。
基本的な仕組みとしては、
送信側 → ブローカー(処理サーバ) → 受信側 というふうに送られます。

### MQTT の特徴

- 軽量なプロトコル

固定長ヘッダが2Byteでオーバーヘッドが少ない仕様になっており、
通信量を減らしてバッテリーの消費を抑えることが出来ます。

- 非同期の双方向通信

送信側と受信側にブローカーのサーバを配置することで、一度確立した接続を再利用することが出来ます。

- 通信が切れる事態を想定した機能

不安定な稼働環境を想定してメッセージの到達の保証レベルを指定することがd系マス。

```
0 : メッセージを1回のみ送信(届かない可能性あり)
1 :    〃  を最低1回は届ける(何回も届いてしまう可能性あり)
2 :    〃  を必ず正確に1回だけ届ける
```

## 勉強後イメージ

そうか、IoTではできるだけ送受信が小さい方がいいのね、バッテリーの話もあって。
ということは結構IoTで使用されるプロトコルって普通のサーバと違うのかな？
あんまり関わったことないから知らなかった。。。

## 参考

- [MQTTとは](https://kfep.jp/solution/iot-mqtt/mqtt)
- [MQTT入門ガイド](https://www.advanet.co.jp/2020/10/14/mqtt-introduction/)
LINQでよく使うメソッド構文一覧(C#)

## はじめに

本記事は [エムティーアイ Advent Calendar 2021](https://qiita.com/advent-calendar/2021/mti) の5日目の記事です。
昨日は @uhooi で [議事録を書くコツとテンプレート](https://qiita.com/uhooi/items/dc862b3eaef154a35470) でした。

C#のLINQについて、よく使うメソッド構文のメソッドを紹介します。

## 「LINQ」とは？

「Language-Integrated Query」の略で、直訳すると「言語に統合されたクエリ」です。
ざっくりいうと「配列をかんたんに操作する便利機能」です。

## LINQの構文の種類

LINQにはクエリ構文とメソッド構文の2種類があります。

以下の例はどちらも同じ意味です。

```cs:クエリ構文
var scores = new int[] { 97, 92, 81, 60 };

IEnumerable<int> scoreQuery =
    from score in scores
    where score > 80
    select score;
```

```cs:メソッド構文
var scores = new int[] { 97, 92, 81, 60 };

IEnumerable<int> scoreQuery = scores
    .Where(score => score > 80);
```

クエリ構文はSQLに似ており、メソッド構文は関数型プログラミングに似ています。

2つの構文にパフォーマンスの違いはありません。

公式ドキュメントではできる限りクエリ構文を使うことが推奨されています。
しかし私はメソッド構文のほうが好きなので、本記事ではメソッド構文を紹介します。

Twitterでアンケートを取ったところ、僅差でクエリ構文を使っている人のほうが多かったです。

https://twitter.com/the_uhooi/status/1468152720863678474?s=20

## 環境

- IDE：Visual Studio Professional 2019 for Mac Version 8.10.14 (build 17)

## LINQのセットアップ

`System.Linq` を `using` するのみです。

```cs
using System.Linq;
```

## LINQでよく使うメソッド構文一覧

LINQでよく使う、`IEnumerable` に実装されているメソッド構文の一覧です。

私はSwiftが好きなので、似ている配列のメソッドを載せています。

|メソッド名|説明|Swift|
|:--|:--|:--|
|`.Select()`|要素を変換する|`.map()`|
|`.Select().Where(e => e is not null)`|要素を変換し、 `null` の要素を除外する|`.compactMap()`|
|`.Where()`|要素を指定した条件で絞り込む|`.filter()`|
|-|要素を順番に繰り返す|`.forEach()`|
|`.OrderBy()`|要素を昇順に並び替える|`.sorted()`|
|`.OrderByDescending()`|要素を降順に並び替える|`.sorted(by: >)`|
|`.Reverse()`|要素を逆順に並び替える|`.reversed()`|
|`.Any()`|指定した条件に一つでも合致する要素があるかどうか|`.contains()`|
|`.All()`|指定した条件に全要素が合致するかどうか|`.allSatisfy()`|
|`.Contains()`|指定した要素が含まれているか|`.contains()`|
|`.First()`|最初の要素を返す|`.first()`|
|`.Last()`|最後の要素を返す|`.last()`|
|`.Skip({数字})`|先頭から指定した数の要素をスキップしたリストを返す|`array[{数字}...]`|
|`.Take({数字})`|先頭から指定した数の要素を返す|`array[..<{数字}]`|
|`.Max()`|要素の最大値を返す|`.max()`|
|`.Min()`|要素の最小値を返す|`.min()`|
|`.Average()`|要素の平均値を返す|`array.reduce(.zero, +) / array.count`|
|`.Sum()`|要素の合計を返す|`.reduce(.zero, +)`|
|`.Count()`|要素数を返す|`.count`|
|`.Distinct()`|重複を除く|`Set(array)`|
|`.ToArray()`|配列に変換する|-|
|`.ToList()`|リストに変換する|-|

## おわりに

これでLINQを使って配列やリストをかんたんに操作できるようになりました :relaxed: 

以上 [エムティーアイ Advent Calendar 2021](https://qiita.com/advent-calendar/2021/mti) の5日目の記事でした。
明日は @rtok さんで [Protocol Oriented Programmingを使ってみて思ったこと](https://qiita.com/rtok/items/80dea6d3567627cf89f1) です。

## 参考リンク

- [Language Integrated Query (LINQ) in C# | Microsoft Docs](https://docs.microsoft.com/en-us/dotnet/csharp/linq/)
- [Enumerable Class (System.Linq) | Microsoft Docs](https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable?view=net-6.0)
PHPでスクレイピングのさわりをやってみる


スクレイピングといえばPythonやRubyを思い浮かべる人も多いが、なんかPHPでもできるらしいのでやってみる。

##今回やってみること
PHPによるWebページのスクレイピング、具体的には、
<a href="https://ugkajiwara.com">私のポートフォリオサイト</a>から、貼り付けているリンクを引っ張ってくるというものを作ろうかなと。
スクレイピングとかってサーバーへ与える負担だったり、法律面で規制されていることがあるので、今回は自分のサイトを使うことで他人へ迷惑をかけるリスクをなくしてやる。

```
$ php -version
PHP 7.3
```
とは言ってもライブラリが何個かあったのだが、調べて一番上に出てきたPHPQueryはなんか古いらしいので今回はphp-html-parserを使ってみる。
>https://github.com/paquettg/php-html-parser

##実際にやってみる
ということでcomposerを使って実行するファイルと同じ階層にインストールする。

```
$ composer require paquettg/php-html-parser
```
ここまでできたら外部ファイルの読み込みとクラスの参照及びに実際にコードを書いていく。

```php:scraper.php
<?php

require_once __DIR__ . '/vendor/autoload.php';

use PHPHtmlParser\Dom;

$url = 'https://ugkajiwara.com/'; //今回スクレイピングしていくのはこのサイト
$dom = new Dom();
$dom->loadFromUrl($url);
$links = $dom->find('a');

foreach($links as $link){
  echo $link->href."<br>";
}
?>
```
結果

```
#works
#profile
https://www.instagram.com/ug_ka
https://twitter.com/ijuyarawijak
https://model-seeker.com
https://github.com/ugkajiwara/ModelSeeker
https://futon-no-shinsei.com
https://qiita.com/ugkajiwara
https://github.com/ugkajiwara
https://twitter.com/ijuyarawijak
https://www.instagram.com/ug_ka/
```
と、こんな感じで情報が取り出せるわけだが、ページ内リンクだったり、urlが被っていたりするので、それらのコードを整理してもう一度出力するプログラムを組んでみる。

```php:scraper.php
<?php

require_once __DIR__ . '/vendor/autoload.php';

use PHPHtmlParser\Dom;

$url = 'https://ugkajiwara.com/'; //今回スクレイピングしていくのはこのサイト
$dom = new Dom();
$dom->loadFromUrl($url);
$links = $dom->find('a');

$hrefs = array();

foreach($links as $link){

  $href = $link->href; //ここでURLを取ってくる

  if(strpos($href,"http") === 0){ //httpが最初に出現する位置が一番最初、つまりhttpで始まるhrefかを識別する。
    $hrefs[] = $href;
  }
  
}

$hrefs = array_unique($hrefs); //配列内の被りを消す

foreach($hrefs as $href){
  echo $href."<br>";
}

?>

```

$linksからhrefだけのデータを取り出す方法がわからなかったから少し冗長になってしまったが、この結果が

```
https://www.instagram.com/ug_ka/
https://twitter.com/ijuyarawijak
https://model-seeker.com
https://github.com/ugkajiwara/ModelSeeker
https://futon-no-shinsei.com
https://qiita.com/ugkajiwara
https://github.com/ugkajiwara
```
と、こんな感じでうまく取り出せているのがわかる。
こんなんいくらでも応用効くやん世の中便利ぃ！
冬なので色んな雪を降らせてみる

#canvasを使った雪#
canvasを使った場合、描画位置によってボタンが押せなくなったり、描画範囲が決まっているのでスクロール時の再描画など気を付ける。
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="GRMZgPx" data-user="yu2mi" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/yu2mi/pen/GRMZgPx">
  Untitled</a> by yu2mi (<a href="https://codepen.io/yu2mi">@yu2mi</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

#Javascriptを使った雪#
<p class="codepen" data-height="300" data-default-tab="css,result" data-slug-hash="OJxNPYB" data-user="yu2mi" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/yu2mi/pen/OJxNPYB">
  JS雪</a> by yu2mi (<a href="https://codepen.io/yu2mi">@yu2mi</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

#CSSを使った雪#
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="VwMaYor" data-user="yu2mi" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/yu2mi/pen/VwMaYor">
  CSS雪</a> by yu2mi (<a href="https://codepen.io/yu2mi">@yu2mi</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>