OmniAICreator/Qiita-1.07M huggingface dataset:
fish + peco の関数サンプル


# 履歴検索

```fish
# History search by peco
function peco_history
  history | peco --prompt="HISTORY>" | read select_hist
  commandline $select_hist
end
```

# GHQによるディレクトリ移動

```fish
# Change directory by peco + ghq
function peco_ghq
  ghq list | peco --prompt="GHQ>" | read select_dir
  if [ $select_dir ]
    cd (ghq root)/$select_dir
  end
end
```
# 下層のファイル探索

```fish
# Find by peco + (git ls-files or find)
function peco_find
  function source_files
    if git rev-parse 2> /dev/null
      git ls-files
    else
      find . -type f
    end
  end
  source_files | peco --prompt "FIND>" | read select_file
  commandline $select_file
end
```

# ショートカット登録

```fish
function fish_user_key_bindings
  bind \cr peco_history # ctrl + r
  bind \cg peco_ghq     # ctrl + g
  bind \cf peco_find    # ctrl + f
end
```
CRUDと7つのアクション

#CRUD
アプリケーションのデータ取り扱いに関して、基本的な処理の頭文字を並べたものです。
アプリケーションの機能は、この4つの処理を組み合わせながら実装します。

C（Create） |	R（Read） |U（Update）|D（Delete）
----------|-------------|--------|---------------
生成	  |読み取り	|更新	  |  削除


Railsでは、CRUDを7つのアクションに分割して、処理を実現します。

# 7つのアクション
CRUDを実現するためは、それぞれの処理を記述する必要があります。
Ruby on Railsには、それらのアクションの設定が慣習的に決められており、下記の表のようなアクションが存在します。

アクション名|	内容
-------- | -----------
index	 |一覧表示
new	 |生成
create	 |保存
show	 |詳細表示
edit	 |編集
update	 |更新
destroy	 |削除
これを本カリキュラムでは、「7つのアクション」と呼んでいます。
これらの7つのアクションのルーティングは、resourcesメソッドを使用することで一度に設定が可能です。

#resourcesメソッド
resourcesは、7つのアクションへのルーティングを自動生成するメソッドです。
resourcesの引数に、:articles というシンボルを指定すると/articlesのパスに対応するルーティングが生成されます。

【例】resourcesメソッドの使用例

```routes.rb
Rails.application.routes.draw do
  resources :articles
end
```
エンジニアに求めること

#管理者目線で
こういう人が欲しい、って要素を箇条書き。
逆に自分がそうであれるように意識したい。

##進捗 系
・進捗の報告が、ちゃんとした根拠があって的確
・あとどれくらいで終わるかの見積りが的確
・「作業」と「課題」のすみわけができる
・アラートが早い

##業務理解 系
・システムの全体像として、あるべき姿をわかっている
・システムの全体像として、現状をわかっている

##作業 系
・調査が早く漏れがない
・何をするでも、手を動かすスピードが速い
・ツールを使い、手作業によるミスがない
・わからないことに付き合わず、すぐに調べるor質問して解決
・(当たり前だが)動作確認に漏れがない
・分岐などに考慮漏れがない

##技術 系
・ツールを使いこなせる=作業が早い&ミスが少ない
・ITリテラルが高い
・言語の特徴を理解している
・実はこっちのが性能いい、みたいな細かいこといっぱい知ってる
・こういうとこエラーになりがち、みたいなのいっぱい知ってる

##その他 系
・素直
・ありのままを言ってくれる
・とにかく課題解決力が高い
・正攻法が無理ならすぐに諦めて別の方法模索
・普通に楽しく会話できる
・とにかく丁寧
・確認に漏れがない
・しっかりとした根拠があってyesという
・たぶんこう、で動くが、たぶんこう、では決定しない
Go 言語仕様2（関数）

## 概要
複数の言語を扱っていると仕様が混ざるので、まとめておく。

前回：
[Go 言語仕様1（変数、型）](https://qiita.com/R_R/items/df7058e4b92eb40968dc)

## 内容
- 関数

## 関数
- 基本的なところ

```GO
package main

import "fmt"

// NoReturn return値なし
func NoReturn(s string) {
	fmt.Println(s)
}

// Return return値あり
func Return(x int, y int) int {
	return x + y
}

// ReturnSome return値複数あり
func ReturnSome(x int, y int) (int, int) {
	plus := x + y
	minus := x - y

	return plus, minus
}

// Default returnの変数をデフォルトで宣言しておく
func Default(ss string) (result string) {
	// 関数内で宣言の必要なし
	result = "Hello, " + ss
	// return値も省略可
	return
}

func main() {
	NoReturn("Golang") // Golang

	sum := Return(10, 20)
	fmt.Println(sum) // 30

	p, m := ReturnSome(1000, 200)
	fmt.Println(p, m) // 1200 800

	fmt.Println(Default("Golang")) // Hello, Golang
}
```
　　

- 無名関数

```GO
package main

import "fmt"

func main() {
	// 関数名は付けない。関数を変数に格納するイメージ。
	f := func(x int, y int) int {
		return x + y
	}

	fmt.Println(f(20, 10)) // 30

	// 直接実行することもできる
	ff := func(x int, y int) int {
		return x + y
	}(20, 10)

	fmt.Println(ff) // 30
}
```
　　

- 引数、戻り値に関数を指定する

```GO
package main

import "fmt"

// Return 関数をreturnする
func Return() func() {
	return func() {
		fmt.Println("Golang")
	}
}

// Execute 引数で渡ってきた関数を実行する
func Execute(f func()) {
	f()
}

func main() {
	f := Return()
	f()

	Execute(f)
}
```
　　

- クロージャー

```GO
package main

import "fmt"

// LaterFunc クロージャー
func LaterFunc() func(int) int {
	var sum int
	// LaterFunc内で定義された無名関数は、LaterFunc内のローカル変数sumにアクセスできる
	return func(i int) int {
		result := sum
		sum = sum + i
		return result
	}
}

func main() {
	// 戻り値の無名関数も、LaterFunc内のローカル変数sumにアクセスできる
	f := LaterFunc()
	// さらに、ローカル変数sumの値は保持される
	fmt.Println(f(10)) // 0
	fmt.Println(f(10)) // 10
	fmt.Println(f(10)) // 20
	fmt.Println(f(10)) // 30
	fmt.Println(f(10)) // 40
}
```

## 次回
[Go 言語仕様3（エラーハンドリング、for文、型アサーション、switch文、型スイッチ）](https://qiita.com/R_R/items/30d85996de24c00ba79d)
【マニュアル】簡単名言botを自分で作る（Slack＋GAS編）その２

　さて今回私がご紹介するのは、[【マニュアル】簡単名言botを自分で作る（Slack＋GAS編）その１][1]の続編です。
[1]:https://https://qiita.com/takeC74/items/4122ba36ed92ebc781f4

　マニュアル画像を張り付けまくっていたら制限を超えたようなので、新しいページに書きます。<br>なので、このページは、その１をみてからご覧ください。
#▼以下、手順の続きです。（その１の最後の説明5から続けます）

5.実行」を押してテストしてみる。（認証を要求する画面が出てきたら、確認してよしなに進めてください。）<br>　
![15_gss_jikkou.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656547/64f8c339-cafe-6089-6974-1c1cdd6537fd.png)
ここで、図のように「実行完了」と表示されたら上手くいった証です。<br>Slackを開いて、指定したチャンネルを除いてみましょう。

6.slackのチャンネルを確認して名言botが投稿されているか確認する（**感動しますね！**）![16_slack_result.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656547/006dde3a-de4f-260f-9bee-b90da52d9ff4.png)

7.GASにもどり、タイマーで任意のスケジュールを設定する。<br>![17_gas_timer.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656547/ecb1e3e4-bf39-4016-1c85-21f868426789.png)<br>

![18_gas_timer_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656547/16e68af7-477e-3e71-93bf-f1ebf4332b47.png)<br>

![19_gas_timer_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656547/6f8bf3be-a20e-4e31-5e91-9e7f773e5512.png)<br>

![20_gas_timer_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656547/c2e9b775-e81c-19ab-231f-84c319c27675.png)<br>
こんな感じで、任意のスケジュールを設定すると、その時間帯にランダムでbotが投稿されます。
「保存」すると、登録した「トリガー」が表示されているので、スケジュールを変更したいときは、そのトリガーをメンテします。<br>
![21_gas_timer_5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656547/0580b6d3-62bb-ddf1-a2b1-562f0531996f.png)<br>

ちなみにGASを実行すると、GSSの「B列」にA列の名言が追記されていきますが、邪魔だったらときどき列ごと「クリア」しておきましょう。<br>最初にも書きましたが、B列には何も書いちゃいけません。GASの「ワーク用」として使用しています。<br>![22_gss_attention.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656547/c181fc55-fede-b35c-0bda-6d67380c065a.png)



#【マニュアル】簡単名言botを自分で作る（Slack＋GAS編）は以上です。
皆さん、いかがでしたでしょうか？　少しでも皆さんのご参考になれば幸いです。こちらを利用して、名言ではなくても、自分のお気に入りのフレーズを、自分なりのアイデアで活用したりしてみてくださいね。
よい活用例がありましたら、私にも教えてください。
<br>以上、最後までお読みいただきありがとうございました。
Google FontsをVue.jsで使用する

#Google Fontsとは
[Google Fonts](https://fonts.google.com/)

なぜか(日本語で)解説してる記事がほぼないので紹介します．
私の環境はvue-cliを用いてvue.jsを生成しています．

Google Fontsは，無料で使えるwebフォントです．基本的にwebサイトを作成するとフォントはブラウザー側で保持している任意のフォントで返します．なのでhtmlを読み込む際にwebフォントのパスを渡し，ブラウザにwebフォントをダウンロードしてもらうことで，どんな環境でも同一のフォントを表示させれるようになります．ちなみに様々な言語に対応しており，日本語フォントも十分にあります．

メリットは上記に述べたように，環境に依存しないフォントの表示を可能にすることですが，デメリットとして使用するフォントを増やせばそれだけウェブサイトの表示が遅くなります．この問題の解決として使用しない文字のデータの削除など様々な技術があるようですが，ここでは触れません．

ここからは，単純にVue.jsへのGoogle Fontsの導入を紹介します．

#導入

[Google Fonts Webpack Plugin](https://www.npmjs.com/package/google-fonts-webpack-plugin)
基本は上記に沿って行けば大丈夫ですが，英語なのでここで紹介してみます．
Google Fonts Webpackプラグインを使用します．

まずインストール

```
npm install google-fonts-webpack-plugin
```

そのあとに，/webpack.config.jsに以下をぶち込めば準備完了になります．

```javascript:webpack.config.js

const GoogleFontsPlugin = require("google-fonts-webpack-plugin")
 
module.exports = {
    "entry": "index.js",
    /* ... */
    plugins: [
        new GoogleFontsPlugin({
            fonts: [
                { family: "Source Sans Pro" },
                { family: "Roboto", variants: [ "400", "700italic" ] }
           /*ここにフォントを追加していく．もちろん上のRobotoとSourse sans proは消してよい*/
            ]
            /* ...options */
        })
    ]
}
```

使い方としては，上記のfontsオブジェクトに自分の使用したいフォントの名前をGoogle Fontsから持ってきて，貼り付ければいいです．
Variantsを指定すれば上記のように細かい指定もできるようになります．



あとはcss上でfont-familyで上記で登録したものを使えば，そのフォントがブラウザ上で使用されることになります．

Vue.jsでは，各々のコンポーネントで指定するのがめんどくさければ以下のように，App.vueで指定しまうのがいいと思います．

```vuejs:App.vue

<style>

template{margin:0px;}
#app {
  font-family: 'Source Sans Pro', sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}

</style>
```


使い方はかなり簡単ですね．注意点としては，フォントのライセンスがそれぞれ異なるため再配布や商用利用の場合はよく調べてください．
セキュリティ・キャンプ全国大会2020オンライン参加記録


## まえがき
2020/10/18～12/6の2ヶ月弱にわたり開催されたIPA主催のセキュリティ・キャンプ全国大会2020オンラインに参加しました。修了から少し時間は経ちましたが、参加の記録を綴っていきたいと思います。
##セキュリティ・キャンプとは
セキュリティキャンプはIPA(情報処理推進機構）が主催しています。IPAのサイトから引用すと以下のような説明になります。
>「セキュリティ・キャンプ」は、学生に対して情報セキュリティに関する高度な技術教育を実施し、次代を担う情報セキュリティ人材を発掘・育成する事業です。2004年に開始され、現在は全国大会を首都圏で毎年1回、2013年に開始された地方大会を毎年各地で10回程度開催しています。 全国大会、地方大会とも、参加するには応募課題を提出し、書類審査に通過する必要があります。

私の場合は、専門学校の先輩や先生の勧めでセキュリティキャンプの存在を知り、初めての応募で選考を通過し、参加できました。
例年は、合宿形式で開催されていましたが、今年は2ヶ月弱のオンライン形式で開催されました。
##応募課題について
私は、課題駆動トラック（トラックD）に応募しました。
課題は、6問ありその中から3問選択して回答するものでした。
回答したデータが残っていたので、私の回答を1問分載せます。
>####問3 ファイルを持たないマルウェア（いわゆるファイルレスマルウェア）が流行っていますが、対策が困難とされている理由を考察してください。
通常のウイルス対策ソフトは、シグネチャと呼ばれるウイルス定義データベースとマルウェアを照合して検出を行うが、ファイルレスマルウェアは、その名通り、ファイルをディスクに書き込まない、メモリ上にプログラムを展開する、OSにもともと備わった機能を使う攻撃であるため、シグネチャを用いた検出ができないことが対策が困難とっされる要因の一つと考えます。。
また、通常のウイルス対策ソフトのセキュリティ対策は侵入されないことを目指しているが、ファイルレスマルウェアは、どのようなウイルス対策ソフトでも100％侵入を止めることが現状、不可能なため、被害を最小限に食い止め、二次被害を食い止めることも必要とされている。被害を最小限に食い止めたとしても、ファイルを持たないランサムウェアが身代金を要求する場合等、さらに対策は困難なると考えられます。

私は、セキュリティに特化して勉強しているわけでもなかったので、ほとんどインターネット上の情報をもとに回答しました。
##キャンプの内容
私は、課題駆動トラック（トラックD）にエントリーしましたが、実際は、選択コースのすべての講義、自由に選択することができました。（人数制限の場合は、抽選）
ここでは、自分の中で一番記憶に残っている講義を紹介します。以下、公式サイトより引用
>####ファイルレスマルウェアの仕組みと防御
ファイルを持たない「ファイルレス」のマルウェアはニュースでも耳にする機会が増えてきました。ファイルを検査対象とするセキュリティ対策から見つからないようにするための攻撃手法となっています。本講義ではShinoBOT.ps1というファイルレスマルウェアシミュレータ―を用い、理解を深めた上で、攻撃者が用いる「ファイルレス」の実装手法を学習していきます。そして、セキュリティの観点で、それらのマルウェアが残す痕跡を元に検知手法を開発していきます。

ファイルレスマルウェアという言葉自体、応募課題で知った言葉だったので講義までついていけるか不安だったが、難読化されたコードの解読等とても面白い講義だった。
##最後に
今回のキャンプを通して得たものを主に2つあります。
###1.セキュリティへの興味
元々、セキュリティに特化して勉強していたわけではなかったが、セキュリティキャンプに参加することで、セキュリティへの興味が高まった。
セキュリティに関するニュースや記事を見て、調べたりするようになった。
自分がこの業界で何をしたいか考えるいい材料になった。
###2.学校外のイベントに積極的に参加しようと思う気持ち
私にとって初めての学校外のイベントへの参加だったが、同世代の同じ業界を志す人たちと2ヶ月弱にわたって切磋琢磨し、技術や知識を高められて良かった。
これからはCTFやコンテスト等のイベントにも積極的にしていきたいという気持ちになった。
###引用サイト
[セキュリティ・キャンプ公式](https://www.ipa.go.jp/jinzai/camp/index.html)
[ruby]eachの入れ子について

#初めに
eachの入れ子についてアウトプットさせてもらいます

#例題
この配列に対して

```ruby
big3 = [["man1",[100,120,140]], ["man2",[90,110,130]], ["man3",[120,180,160]]]
```

以下のように出力したいと思います

```ruby
man1のbig3の合計は360kgです！
man2のbig3の合計は330kgです！
man3のbig3の合計は460kgです！
```
＊big3とは"ベンチプレス","スクワット","デットリフト"のことです

```ruby:記述内容
big3 = [["man1",[100,120,140]], ["man2",[90,110,130]], ["man3",[120,180,160]]]

big3.each do |training|
  sum = 0
  training[1].each do |weight|
    sum += weight
  end
  puts "#{training[0]}のbig3の合計は#{sum}kgです！"
end
```

#training[1]とは
big3.each do |training|　で出力した配列のに1つ目に含まれる配列

1回目は"man1",[100,120,140]のことなので

training = "man1",[100,120,140]ことになります

trainingの０にはman、1には重量が入っていることになります

```ruby
training = "man1",[100,120,140]
             0          1
```

変数training[1]に対しeachメソッドを使用。[1]には重量が入っていることになり

この数字を順番に出してsumにたすことになります

big3合計を出したらeach分の1度目のループは終了です
以下終わるまでループします

#おわりに
簡単なアウトプットでした
cb.apply is not a function というエラーが出た時

nodistを使ってnodeのバージョンを切り替えてると以下のようなエラーが出ます。

```
cb.apply is not a function
```

いろいろ調べるとnodistやめてピュアにインストールしろなどのものがありますが、そもそもこのエラーが出るのは単にnpmがnodeとのバージョンで不整合がおきてるからです。
なので、npmを最新にしましょう！
…
と思っても

```
npm i -g npm
```

とアップデート作業しても、そもそもnpm iでエラーが出るのでできません。
悲しいけど無限ループ状態。
その場合は以下のようにnodist経由でnpmのバージョンを変更すると解決します。

```
nodist npm 6.14.11
```
【RubyonRails】uninitialized constant ●●Controllerの解消方法【progate】

<h2>uninitialized constant</h2>
progateでRailsでエラーにハマってしまったので、エラーを解消方法について記載します。

<h2>症状</h2>
ルーティングのURL自体はあっているものの、街頭のコントローラーのアクションに遷移しようとすると画像のようなエラーメッセージが出てくる模様。

エラーの文字は、
<B>「uninitialized constant LikesController」</B>

日本語訳すると
<B>「初期化されていない定数 LikesController」</B>

「RubyonRails道場IV 「いいね！」ボタンを作ろう」で発生

![railsエラー.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/927880/3fd93d67-dda4-0b2e-4e20-04ef7761d788.jpeg)


<h2>解消方法</h2>

対象のコントローラーのファイル名が単数形を複数形にすることで、エラーが解消されました。
コントローラー名が間違っていたようです。

<h2>原因</h2>
このエラーメッセージは「クラス名・ファイル名が間違っている場合」に表示されるようです。。

Rubyでは「LikesController」などのクラス名もRubyという言語内では定数らしく、日本語訳の「初期化されていない定数 LikesController」は今回の場合、ファイル名の「LikesController」を指していたみたいです。

ルーティングの問題かと思ってずっとルーティングの導線を確認していたので、かなりてこずりましたが、エラーの内容が分かればすぐに修正できました。

参考
【エラー】uninitialized constant ~~Controllerについて
https://teratail.com/questions/136606
Ubuntu16.04上でのpython3.7環境をdockerで構築する

# はじめに
ちょっと手こずったのでメモとして残しておきます。
間違っている部分や、もっと良い方法があればぜひ教えていただきたいです。

#Docker file
以下のDocker fileで構築。

```dockerfile:
FROM ubuntu:16.04
RUN apt-get update
RUN apt update
RUN apt install -y software-properties-common
RUN add-apt-repository ppa:deadsnakes/ppa
RUN apt update
RUN apt install -y python3.7
RUN apt-get install -y python3-pip
RUN apt install git -y
RUN python3.7 -m pip install --upgrade pip
RUN python3.7 -m pip install numpy
```

# 参考
https://mu-777.hatenablog.com/entry/2020/03/07/195833
ファイル名の一部を一括で変更したい

# 忙しい人向け

* PowerToysをインストール
    * https://github.com/microsoft/PowerToys/releases
* 変更したいファイルを右クリックしてPowerRenameをクリック


# はじめに

ちょいちょいファイル名の一部を一括で変更したい事があったのですが、方法が分からず、
頻度も高くないことから結構手作業でリネームをしていました。
でも今回、ついにそれだと生きるのが辛くなってしまったので良い方法が無いか調べました。

# 方法

* PowerToysをインストール
    * https://github.com/microsoft/PowerToys/releases
* 名前を変更したいファイルを選択し、右クリック
* その中の「PowerRename」をクリック
    * PowerToysをインストールすると追加される

取り敢えずGUI上だとこれで十分便利だったので暫くこれでいこうと思います。

# 他のやり方

## Linuxの場合

renameコマンドがあります。
manページにはこんな感じの例があります。

```shell
rename 's/\.bak$//' *.bak
```

正規表現が使えるのは便利ですね。

## Windowsのコマンドライン

RENコマンドがありますが…Linuxのrenameほど精度は良くないようです。
コマンドラインリファレンスを見ると

```bat
ren *.txt *.doc
```

で拡張子を「txt」から「doc」へ一括で変更出来る…らしいです。
(今だと色々違和感のある例ですが、docもテキストファイルだった頃からのヘルプなのかも知れません)
ただ、注意点があって
>Filename2のワイルドカード文字によって表される文字は、 filename1内の対応する文字と同じになります。

だそうです。
なので、拡張子の変更は例としては良くないと思います…。


# さいごに

PowerToysが懐かしすぎて…
正直その事でテンションが上がってそのままの勢いで書きました。

# 参考

* https://4thsight.xyz/16468
* https://4thsight.xyz/16373
* https://docs.microsoft.com/ja-jp/windows-server/administration/windows-commands/ren
AndroidStudio Debug署名を共有する方法

# 背景
社内開発の場合、デバッグ用端末をチームで使いまわしてデバッグ等行う事が多い。その際、他人のインストールしたデバッグアプリをアップデートインストールしようとすると、署名が違うと怒られる。いちいちクリーンしてからインストール。これが結構面倒だったので対応した。要は署名を共通化すればいい。

# build.gradle 設定

```
android {
   ...略...

   signingConfigs {
        debug {
            storeFile file("debug.keystore")
        }
   }
}
```
debug.keystoreはapp直下においてgit管理させれば良い。

# 余談
デフォルトのdebug.keystoreは以下に格納されており、PCごとに違う。
個人でやってた頃は、こちらのファイルをコピペすることによって、共通化させていた。

 * Win : `C:\Users\<username>\.android\`
 * Mac : `~/.android/`
footerをディスプレイ最下部に表示する

`body`のコンテンツが少ない場合にfooterの下に隙間ができる。
footerをディスプレイの最下部に表示する方法。
`body`の構成は`bulma v0.8.0`の基本的なもの。

```html
<html>
  <head>
  ...
  <head>
  <body>
    <nav>...</nav>
    <section class="section">...</section>
    <footer>...</footer>
  </body>
</html>
```

```scss
html {
  height: 100%;

  body {
    min-height: 100%;
    display: flex;
    flex-direction: column;

    section.section{
      flex: 1;
    }
  }
}
```

- [[CSS]フッタを最下部に表示する5つのテクニック\-コンテンツ量が少ない時は最下部に、多い時は成り行きに \| コリス](https://coliss.com/articles/build-websites/operation/css/css-sticky-footer.html)
rbenvの概要とインストール



## 前提

- macOS
- homebrewのインストール

## 一言で

　複数のRubyのバージョンを管理し、**プロジェクト毎にRubyのバージョンを指定して使うことを可能にするツール（パッケージ）** のこと。

## 概要

　プログラムにはバージョンという考え方があり、新機能の追加や、不要な機能の削除、仕様の変更などをした際に、プログラムのバージョンは上がっていきます。それはプログラミング言語も同じです。バージョンが違うことで、**使える機能が変わったり、元々あった機能が使えなくなることもあるため**、プロジェクトで利用するプログラムのバージョンを固定することはしばしば重要です。そのため、プログラムのバージョンを固定する必要があるわけですが、プログラミング言語はプロジェクト毎に利用したいバージョンが変わっている場合があります。

　例えば、プロジェクトAではv2.0を利用し、プロジェクトBではv3.0を利用したい、といった具合です。この時に、プロジェクト毎にバージョンを設定したりすることを**バージョン管理**といいます。そして、Rubyにおけるバージョン管理ツール、それが**rbenv**となります。

## インストールの手順

1. 必要なファイルの作成

    ```bash
    $ ls -a ~/

    #bashの場合、.bash_profileがなかったら
    $ touch ~/.bash_profile
  
    #zshの場合、.zprofile,zshrcがなかったら
    $ touch ~/.zprofile
    $ touch ~/.zshrc
    ```
    
    ＊bashかzshかは下図参照
    ![](https://i.imgur.com/dDXHqCc.jpg)

2. pathを通す

    ```bash
    #bashの場合
    $ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
    $ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
    $ source ~/.bash_profile

    #zshの場合
    $ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.zshrc
    $ echo 'eval "$(rbenv init -)"' >> ~/.zshrc
    $ source ~/.zshrc
    ```
    


3. rbenvのインストール

    ```bash
    $ brew update          #homebrewを最新の状態に
    $ brew install rbenv   #インストール
    $ rbenv --version      #インストールできてるかの確認
    ```

4. rubyのインストール

    ```bash
    $ rbenv install --list #どのバージョンのrubyがインストールできるかの確認
    $ rbenv install 2.7.1  #2.7.1をインストールしてみる
    $ rbenv versions       #現在のrubyのバージョンを確認(macでは標準で入ってる)
    $ ruby -v              #rubyのバージョンを確認
    $ rbenv global 2.7.1    #rubyのバージョンを変更
    $ ruby -v              #2.7.1になってることを確認
    ###変わらなかった場合
    $ rm ~/.ruby-version   #参照してしまうファイルを削除。その後ruby globalを試してみる
    ```

5. プロジェクトのバージョンを変えてみる

    ```bash
    $ rbenv install 2.6.6 #2.6.6をインストールしてみる
    $ cd                  #ホームディレクトリに戻る
    $ mkdir sample        #sampleディレクトリを作る
    $ cd sample           #sampleディレクトリに移動
    $ ruby -v             #2.7.1なことを確認
    $ rbenv local 2.6.6   #2.6.6に変更
    $ ruby -v             #2.6.6であることを確認
    $ cd                  #ホームディレクトリに戻る
    $ ruby -v             #2.7.1であることを確認
    ```

## まとめ

　今回で　

- rbenvのインストール
- rbenvによるプロジェクトごとのバージョン変更・管理

ができるようになりました。

　複数のプロジェクトに関わる時や、最新のRubyが出た時に重宝しますのでぜひご活用ください！
　よきRubyライフを！！
getopenfilename

getopenfilenameについて
##getopenfiename

複数の拡張子を使いたい場合は、FileFilterをうまく利用する。

```vb:'test.xlsm

Dim listfile As Variant

listfile = Application.GetOpenFilename(FileFilter:="CSVファイル,*.csv,xlsxファイル, _
*.xlsx", FilterIndex:=2, Title:="選択してください,")
    If VarType(listfile) = vbBoolean Then
        MsgBox "キャンセルされました"
        Exit Sub
    End If    
End Sub
```
Einstein Analytics セキュリティ述語について

## 概要
- SalesforceのEinstein Analytics（現Tableau CRM）のセキュリティ述語の使い方について解説します。

## 参考

### Analyticsセキュリティ実装ガイド
- https://resources.docs.salesforce.com/224/latest/ja-jp/sfdc/pdf/bi_admin_guide_security.pdf

## セキュリティ述語とは
- データセットへのアクセス権を持つAnalyticsユーザには、デフォルトでデータセット内のすべてのレコードへのアクセス権があります。
- レコードへのアクセスを制限するには、共有継承とセキュリティ述語を使用してデータセットに行レベルセキュリティを実装できます。
- セキュリティ述語は、データセット行のアクセスを定義する検索条件で、手動で割り当てることができます。
- 基本的には共有継承を使用し、バックアップとしてセキュリティ述語を利用するのが良い（らしい）


## 実装方法

### 作成済みのデータセットにセキュリティ述語を設定する方法
- [Analytics Studio] > [すべての項目] > [データセット]
- セキュリティ述語を設定したいデータセット右の「▼」 > [編集]
- セキュリティ述語の「✎」をクリック

### その他
- レシピ等で、データセット生成時にセキュリティ述語を設定することも可能です。


## セキュリティ述語の記述方法

### 基本構文
```
<dataset column> <operator> <value>
```

例

```
'UserId' == "$User.Id"
```

### dataset column
- データセットに含まれるカラム名を指定します
- 単一引用符で囲む必要があります
- カラム名に単一引用符が含まれている場合はバックスラッシュでエスケープします

### operator
- 以下の比較演算子、論理演算子が指定可能です
    - ==
    - !=
    - <, <=, >, >=（数値のみ）
    - in（選択リストのみ）
    - &&
    - ||

### value
- 文字列リテラル、数値リテラル、項目値(Salesforceオブジェクト)を指定できます
    - 文字列リテラルは二重引用符で囲む必要があります
    - 数値リテラルは引用符で囲む必要はありません
    - 項目値は二重引用符で囲み、$から始める必要があります
- 項目値はセキュリティユーザがアクセス可能なオブジェクトのみ指定できます
    - 必要があればプロファイルで項目レベルセキュリティを設定してください
    - String,Number,選択リスト項目のみアクセス可能です

### 考慮事項
- 大文字と小文字は区別されます
- セキュリティ述語は最大5000文字まで記述できます
- 論理演算子の前後には空白スペースが必要です

## 実装例

### 要件
- ログインしたユーザは自分の取引先に属するデータのみが見える
- システム管理者プロファイルのユーザはすべてのデータが見える

### 事前準備
- 対象データセット（SampleDataset）に取引先とシステム管理者のSFIDをもたせる
    - レシピで結合とかしてうまく作ってください

### セキュリティ述語例
```
'SampleDataset.Account__c' == "$User.AccountId" || 'SampleDataset.SysAdminSFID' == "$User.ProfileId"
```
- $Userを利用すれば、ログインユーザーの情報を取得できます。
【Python】Worksheet.insert_rowsで決まった間隔に空白行を挿入する。

pythonを使用してExcelファイルの操作を勉強しています。
本日の気づき(復習)は、行の挿入に関してです。
pythonでExcelを操作するため、openpyxlというパッケージを使用しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/927441/9ec2a4c6-5c43-aa8f-4909-be7c39ed9743.png)
上記のような表へ3行ごとに空白行を入れていきます。

# Worksheet.insert_rowsメソッド

```python
ws.insert_rows(行を挿入する位置)
```

このほかにもこの様なものがありました。

- ws.insert_row:行を挿入
- ws.insert_cols:列を挿入
- ws.delete_row:行を削除
- ws.delete_cols:列を削除

表の先頭から順番に行を追加(削除)していくと
追加(削除)した行数を考えながら次の位置を決めないといけず
私は挫折しました・・・。
ということで、最終行から順に行を入れていくことにしました。
上記の表だと行を挿入したい位置は「12行目」「9行目」「6行目」です。
先日勉強したWorksheet.max_row属性を使って

```python:insert_row.py
from openpyxl import load_workbook

wb = load_workbook('〇〇地区一覧.xlsx')
ws = wb.active

num = 3
start_row = 2
rast_row = ws.max_row - ((ws.max_row - start_row - 1) % num)
print(f'データ入力最終行番号は{ws.max_row}です')
print('挿入する行番号は')
for row_no in range(rast_row, num+start_row, -num):
    print(f'{row_no}')
    ws.insert_rows(row_no)

wb.save('〇〇地区一覧_行挿入.xlsx')
```

この様な記述にしてみました。
動作確認するためにprint関数を使ってチェックします。
この辺はしらかみゅ様に教えて頂いた部分です。ありがとうございます！
insert_row.pyを実行してみると・・・
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/927441/83a86eed-9df7-b226-0759-e970c1963f5f.png)

やった！ちゃんと動作してくれています。

動作確認しながらだとスムーズに記述が進みますね！ありがたい！

ちなみに、列で挿入する場合はこちらです。

```python:insert_col.py
from openpyxl import load_workbook

wb = load_workbook('○○地区一覧_横.xlsx')
ws = wb.active

num = 2
start_column = 2
rast_column = ws.max_column - ((ws.max_column - start_column - 1) % num)

print(f'データ入力最終列番号は{ws.max_column}です')
print('挿入する列名は')
for col_no in range(rast_column, num+start_column, -num):
    col_alphabet = ws.cell(row=1, column=col_no).column_letter
    print(f'{col_alphabet}列')
    ws.insert_cols(col_no)

wb.save('○○地区一覧_横_列挿入.xlsx')
```

挿入する列名が数字だと判りづらかったので表示だけアルファベット表記にしました。
Markdown 備忘録

# はじめに
Markdownを常用する環境にいれば、記法を忘れることもないであろうが、世の中そんな環境ばかりではない。社内公開ドキュメントはdocであり、表はxlsを利用する会社も当然ある。ふと、課内に向けた回覧レビュー用にMarkdownでドキュメントを作成すると愕然とする。前書いたはずなのにgoogle先生に聞く悔しさよ:cry:

# 目的
一回まとめときゃ忘れねぇだろの精神。
それ以外の目的はない。

# 最頻出記法一覧

|やりたいこと |記法 |ひとこと |
|---|---|---|
|段落 |`#` 複数可 |複数つけて段落建て<br>3つくらいから見た目は変わらなくなる |
|羅列 |`*` |`Tab` +`*` で階層わけ可能 |
|表|&#124;左寄せ&#124;中央寄せ&#124;右寄せ&#124;<br>&#124;-------&#124;:-------:&#124;-------:&#124;<br>&#124;あああ&#124;いいい&#124;ううう&#124;|要素ない改行`<br>`|
|中央そろえ|`<div style="text-align: center;">中央</div>`|`right`で右|
|表の幅調整|`&nbsp;`挿入|適当に入れて調整|
|仕切り線|`---`||
|コメント|<!-- コメント -->|xmlとかと同じ|
|リンク|`[title](https://xxx)`|[title](https://xxx)|
|pdfにしたときに改ページ|`<div style="page-break-before:always"></div>`|[Markdown PDF](https://github.com/yzane/vscode-markdown-pdf/)使用時|
|ファイル名入りコード|\```filename.file<br>code....<br> ```||
|太字 |`**テキスト**` |重要な箇所を強調する際に使用 |
|斜体 |`*テキスト*` |強調したい箇所を斜体で表示 |
|取り消し線 |`~~テキスト~~` |間違いを示すために使用 |
|水平線 |`---` or `___` |文章の区切りを明示するために使用 |
|引用 |`> 引用文` |引用文を表示する |
|コード表示(インライン) |`` `コード` `` |一部のテキストをコードとして表示する |
|コード表示(ブロック) |`<pre><code>コードブロック</code></pre>`|複数行のコードを表示する |
|番号付きリスト |`1. ` |順序を持ったリストを作成する |
|チェックリスト |`- [ ]` |やるべきことリストを作成する |
|チェックリスト(チェック済み) |`- [x]` |完了したことを示すチェックマークをつける
[Xcode12.4] [Swift] UIScrollViewのAutoLayoutの制約のかけかた・基本の使い方

#はじめに
UIScrollView を使おうと思ったら、AutoLayout の制約をかけるのにつまづいてしまいました。
ここでは、Xcode 12.4 の UIScrollView の AutoLayout の制約をかける方法をまとめてます。

###環境
Xcode 12.4
macOS Big Sur 11.1 M1チップ

#実践

###1. UIScrollView の AutoLayout の制約をかける

はじめに、Storyboard の ViewController の上に ScrollView を追加します。
![スクリーンショット 2021-02-12 18.53.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1104595/1e937172-935f-a512-0fd5-2a3b0577b322.png)
上下左右を 0 で固定しましょう。
固定する前に手動でいっぱいまで広げておくと見やすくなります。

上に固定のヘッダーがあるアプリをよく見るので、上に imageView を置いてみました（これで合ってる分からないですが、つけてみたかったので笑）。ない場合でもやることは同じです！

そうすると、下の画像のように赤いラインで表示されてしまいます。
ここで僕はつまづいてました。

![スクリーンショット 2021-02-12 18.54.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1104595/a3a12319-9b61-7415-9176-488236a7b25c.png)

次に、ScrollView が選択された状態で右の sizeページを開いて、
Content Layout Guides のチェックを外します。（画像見切れててすみません）
![スクリーンショット 2021-02-12 18.55.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1104595/b77d6444-3856-da0a-fd0d-fde9f92c0bdb.png)
チェックを外すと、左側の ScrollView の中の ContentLa...と FrameLay...が消えることが確認できます。


###2. Scrollview の上に View をのせる

ScrollView の中に View が入るように追加します。
![スクリーンショット 2021-02-12 18.56.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1104595/0f40cfa7-6331-1b52-79ce-11155d267595.png)
こちらも ScrollView と同じように上下左右を 0 で固定しましょう。
それと Height を表示したい長さにします。


親に同じ View という名前があるので、こちらの View は ContentView という名前をつけてます。

![スクリーンショット 2021-02-12 18.57.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1104595/f768290b-2347-fdc4-1d58-b37b328064e5.png)
次に、コントロール or 右クリック を押しながらドラッグドロップで
ContentView から View に引っ張ります。


![スクリーンショット 2021-02-12 18.57.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1104595/7dbfd9b9-1907-ef28-2c64-e5c0ee01e07c.png)

項目が表示されるので、Equal Widths を選択します。

![スクリーンショット 2021-02-12 18.57.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1104595/e5e31c06-0e8c-11b3-81bd-9950fbdf6729.png)

ここで赤のラインとエラーが消えれば OK です。

###3. ViewControllerのサイズを変える
これで最後です！
左の ViewController もしくは Storyboard上の上部バーのアイコンを選択して、右の sizeページにいきましょう。
![スクリーンショット 2021-02-12 19.00.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1104595/591a0bea-3a3c-ab88-06dc-50fd8bde702b.png)

SimulatedSize が Fixed になってるので Freeform にします。
するとHeight の項目が出てくるので、先ほど View を追加したときに設定した Height と同じ値を入れましょう。

これで ViewController が指定した長さになります。

###完成！

ラベルなどをつけて確認してみましょう。AutoLayout も忘れずに...
![スクリーンショット 2021-02-12 19.05.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1104595/7260989e-82c1-c334-5aaa-f5e967743497.png)

![スクリーンショット 2021-02-12 19.06.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1104595/b11d9195-3a67-fe66-1e10-0433a53efe37.png)

ちゃんと下まで動きました！
他の機種で実行しても問題なく表示されました。

上のヘッダーは ScrollView の中にはないので固定されてます。
あとは View の背景色を同じ色にすれば完璧ですね。

#最後に
いかがでしたでしょうか？

ContentLayoutGuide と FrameLayoutGuide を消すのはどうなのかなと、書いてて疑問に思いました。

それは使えない・もっと簡単な方法があるなどございましたら、教えていただけるとありがたいです！
初めての投稿なので分かりづらいところがあったかもしれません。こちらもご指摘いただければと思います。
Conflux のトランザクションを集計して税計算するメモ

Conflux, gas 代ゼロでいいですよね.

マイニングなり moonswap などでの DeFi など取引の税務を計算しましょう.

confluxscan がありますが, etherscan と異なり API アクセスは提供していなさそうです.
beautifulsoup などで web クロールで取得してもいいですがめんどいです.

bitquery がありました.

https://explorer.bitquery.io/conflux_tethys

API 対応(GraphQL?)もありそうですが, トランザクション数すくなければとりあえず Inflow, Outflow あたりを CSV エクスポートして処理すればいいでしょう!

## TODO

GraphQL on bitquery で詳細取得をためす.

https://bitquery.io/blog/conflux-blockchain-api

https://graphql.bitquery.io/

での

`Inflow / outflow for address` 

あたりのサンプルを参考にいじればよさそうです!

ついでに Eth のトランザクションも bitquery で取得してみる.
pillow で画像に図形を挿入

入力画像
![fujisan01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/989d527f-399e-b561-2e21-36819a9ae574.jpeg)

出力画像
![out01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/945c233b-98de-b943-5426-b77c135fae59.jpeg)

```py:draw_img_rect.py
#! /usr/bin/python
# -*- coding: utf-8 -*-
#
#	draw_img_rect.py
#
#						Feb/12/2021
#
# ------------------------------------------------------------------
import sys

import PIL.Image
import PIL.ImageDraw

# ------------------------------------------------------------------
sys.stderr.write("*** 開始 ***\n")
file_in = sys.argv[1]
file_out = sys.argv[2]
sys.stderr.write(file_in + "\n")
sys.stderr.write(file_out + "\n")
#
img_base = PIL.Image.open(file_in)
#

draw = PIL.ImageDraw.Draw(img_base)
xx = 50
yy = 50
delt_x = 100
delt_y = 100
draw.rectangle((xx,yy,xx + delt_x,yy + delt_y),fill=None,outline=(255,0,0),width=1)
xx = 200
draw.rectangle((xx,yy,xx + delt_x,yy + delt_y),fill=None,outline=(255,255,0),width=5)
xx = 350
draw.rectangle((xx,yy,xx + delt_x,yy + delt_y),fill=None,outline=(0,0,255),width=9)

xx=50
yy=200
draw.ellipse((xx, yy, xx+100, yy+100), fill=None, outline=(255,0,0),width=1)
xx=200
draw.ellipse((xx, yy, xx+100, yy+100), fill=None, outline=(255,255,0),width=5)
xx=350
draw.ellipse((xx, yy, xx+100, yy+100), fill=None, outline=(0,0,255),width=9)

img_base.show()

img_base.save(file_out)
sys.stderr.write("*** 終了 ***\n")
# ------------------------------------------------------------------
```

実行方法

```bash
./draw_img_rect.py fujisan01.jpg out01.jpg
```

関連ページ
[pillow で画像に文字を挿入](https://qiita.com/ekzemplaro/items/cd79d6a0fb4ff0a0f883)
jupytextで*.ipynbから*.pyに変換する[メモ]

## jupytextのメリット
jupyter notebookで使われる拡張子(.ipynb)のファイルを保存すると、自動でPythonデフォルトの拡張子(.py)のファイルが生成されるというもの。

- ファイル変換のメリット
    - gitにcommitする際にipynbだとjson形式になってファイルが重くなる。
    - ipynbだとセルの実行回数も記録されるのでgitの管理も難しい。
    - GitHubで公開すると表示に時間がかかる。

以上から.py形式で管理する方がいいと思う。

nbconvertを使ってもファイル変換はできる。

## 開発環境

OSはMacを使っています。
環境構築はpyenvのPython3.8.6

## 手順

#### pyenvで環境構築

今回はpyenvでjupyter notebookを開きます。

```Bash
$ pyenv virtualenv 3.8.6 hoge  #hogeという名前の環境を作る
$ pyenv local 3.8.6 hoge       #環境の切り替え
$ python --version             #切り替わっているかを確認
     // Python 3.8.6
$ pip install jupyterlab==2.2.8 #jupyterlabのインストール
$ jupyter lab                   #jupyterlabが立ち上がることを確認
```


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

jupytextはpipでインストールできます。

```
$ pip install jupytext
```
ここで注意するべきなのはこのGitHubのページでもある通り、jupytextとjupyterlabの互換性です。自分はここでつまずいて、解決するのに時間がかかったので注意してください。https://github.com/mwouts/jupytext

ここの文章を要約すると、
jupytextの最新版はJupyterLabのver3.0以降に対応しています。
JupyterLab2.Xで使用する場合は以下のインストールを行なってね。
とのことです。
以下のコマンドを実行してJupyterLabの拡張機能にjupytextをインストールしていきます。

```
$ jupyter labextension install jupyterlab-jupytext@1.2.2
```

#### jupytext.ymlファイルを作る

プロジェクトのルートディレクトリか、コンピュータのホームディレクトリの.configフォルダにjupytext.ymlファイルを作る。
jupytextは設定ファイルを作る必要があります。
vimで設定ファイルの作成を行います。
コマンドでjupytext.ymlを作って編集する。ファイル名はymlを使っていますがファイル名の頭に.をつけても大丈夫だと思います。
ターミナルから以下のコマンド

```Bash
$ vim ~/.config/jupytext.yml
```

jupytext.yml内に以下を記述する。

```yml
default_jupytext_formats: "ipynb,jupytext_py//py:percent"
default_notebook_metadata_filter: "-all"
default_cell_metadata_filter: "-all"
```

この後jupyter labのlocalhostを再起動することで、jupyter labのビルドを行うかという主旨のポップアップが出てくると思うので、Yesを選択すればjupytextが入ると思います。

もしビルドができなければターミナルから以下のコマンドでビルドできます。

```
$ jupyter lab build          #jupytextをビルド
$ jupyter labextension list  #ちゃんとビルドされたか確認
```

### おわりに
これでjupyter labでipynbファイルを作成したら同時にpythonファイルが作成されると思います。もし、間違いや質問があれば僕のTwitterの方にDMをもらえたらと思います。
railsアプリ作成手順【基礎の備忘録】

Ruby on Railsでのアプリ作成手順を、
復習も兼ねてまとめておく。

ターミナル

```
#railsで利用したいバージョンを指定。例は6.0.0 -dはデータベースを指定するオプションで、例ではmysqlを指定。
% rails _6.0.0_ new 作成するアプリ名 -d mysql 
% cd 上記アプリ名
# ※データベースを作成する前に、database.ymlを編集する。以下に詳細記載。必須設定ではないが、自身が学んだタイプと合わせるため記載。
% rails db:create　#データベースを作成
```

config/database.yml

```
default: &default
  adapter: mysql2
  encoding: utf8mb4 →ここをutf8に変更。データの保存形式を変更するため。
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password:
  socket: /tmp/mysql.sock
```

上記コマンドで、アプリの大枠のファイルが作られる。

その後は、
# 1、ルーティング設定
config/routes.rbに入力。
# 2、コントローラ作成・アクション入力
ターミナルにて

```
% rails g controller コントローラ名(複数形で名付ける)
```

# 3、ビューファイルの作成
app/views
コントローラやアクションの命名に合わせてファイルを作成する。
indexアクションに対応するビューファイルであれば、
index.html.erbファイルを作成。

# 4、モデルの作成
ターミナルにて

```
% rails g model モデル名(単数形で名付ける)
```

# 5、マイグレーションファイルの入力・実行
モデル作成を行うと、
db/migrate
こちらにマイグレーションファイルが作成される。
20xxxxxx_create_〇〇.rb と名がついたファイル。
ここに定義したいカラム名を入力。

```
class 〇〇 < ActiveRecord::Migration[6.0]
  def change
    create_table :〇〇 do |t|
      t.string     :name,      null: false
      t.text       :text,      null: false
      t.timestamps　→デフォルトではこの記載のみ。
    end
  end
end
```

カラムの型の指定はt.〇〇　この〇〇の部分に入力していく。
例では、
string→文字(短文)
text→文字(長文)
として型を指定しています。

入力完了後マイグレーションファイルの実行を行う。
ターミナルにて

```
% rails db:migrate
```

これで指定したカラムが入ったテーブルが作成される。

大枠の組み立てはこれで完成！
The server quit without updating PID fileというエラー

#はじめに

Railsを使っていて最初はspliteを使っていたのですが途中から
MySQL8.0に変えました。
インストールして、諸々の設定をして最初は問題なく使えていたのですが
途中からなぜかデータベースが読み込めなくなったので（原因はいまもわかりません）
MySQLをアンインストールして再度インストールしました。

すると

The server quit without updating PID file

というエラーが出てこいつになかなか悩まされました。

##解決法

PCを再起動しましょう。
僕の場合はこれで解決しました。
インストール後はPCの再起動が必要なようです。

非常に初歩的な話ではありますが、MySQLを扱うのが初めてなもので
どこに原因があるのかわからず再起動に行き着くまで
３時間ほど消費してしまいました。(笑)
Raspberry Pi 2B / 3B+ でWireGuardの性能を測ってみた

# 概要
こんな感じのネットワークでRaspberry PiでWireGuardの性能がどのぐらい出るのか測ってみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212876/d0ebdfe2-87b4-9cde-38ae-3d32e612f286.png)


# 測定環境
- 測定対象１
 - Raspberry Pi 2 Model B
- 測定対象２
 - Raspberry Pi 3 Model B+
- OS
 - Ubuntu 20.04 LTS
- 測定ソフト
 - iperf3

# 結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212876/08bf41f4-fba8-a0c7-32d6-c9ce595a2809.png)

# まとめ

- Raspberry Pi 2B はLANが100BASE-TXなので100Mbpsで頭打ちしています
- Raspberry Pi 3B+ はPC1<=>PC2間でパフォーマンスが大きく下がりました。これはRaspberry PiのLANが基盤内部でUSB2.0接続になっているためです
- CPUはWireGuardの暗号化/復号化処理を行っても余力がありそう。LAN側の性能に引きずられているみたいです
NameError の解決例

NameError in Posts#edit
undefined local variable or method 'post' for #<#<class○○○
Did you mean? @post

変数postaは定義されておらずnilとなっています。postではなく@postではないか？
という内容になっています。

```app/views/posts/deit.html.erb
<% form_with model:post,class::form,local:true dp |form| %>
```
form_withは、モデルとオプションを入力すると送信先の設定が自動でされます。
今回はpost(nilな変数)から送信先が推測できなかったことがエラー原因です。
したがってpostを@postに修正して下記の表記にします。

```app/views/posts/deit.html.erb
<% form_with model:@post,class::form,local:true dp |form| %>
```
Oculus Quest + Unity の開発で困った時の確認ポイントまとめ

# 概要
Oculus QuestアプリをUnityで開発している時、

* アプリが実機で立ち上がらない
* 立ち上げても画面が真っ暗
* エラーメッセージが出る
 
などのトラブルが起こった時の確認ポイントまとめです。

開発構成はOculus QuestとMacです。

# Unityのバージョンは適切か？
Unityのバージョンが古すぎると動作しないことがあるのでバージョンアップする。
その際、Android Build Supportのインストールも忘れずに。

参考 : [Oculus Quest 1 のアプリを作るため Unity のインストールを行ってハマったメモ 2021年1月版 – 1ft\-seabass\.jp\.MEMO](https://www.1ft-seabass.jp/memo/2021/01/05/oculus-quest-1-setup-memo-202101/)

# Oculus Integrationは最新版か？
以下のページの「最新版パッケージにアップグレードする」にそってOculus Integrationを最新版にアップグレードする。
古いパッケージの消し方がやや複雑なので注意。

[Import Oculus Integration Package \| Oculus Developers](https://developer.oculus.com/documentation/unity/unity-import/?locale=ja_JP)

# 各種Packageは最新版か？
Window > Package Managerを開き、各種パッケージが最新版になっているか確認する。
「Oculus XR Plugin」「XR Plugin Management」など。

# アプリIDは設定されているか？
Oculus > Platform > Edit Settingを開き、アプリIDが設定されているか確認する。
アプリIDは以下のページで「新しいアプリを作成」した時に付与されるのでコピペで設定する。

https://developer.oculus.com/manage/

# ビルド時に「Can not sign the application / Unable to sign the application; please provide passwords!」とエラーが出る
File > Build Settings > Player Settings > PlayerのAndroidタブ > Publishing SettingsのProject KeystoneとProject Keyのパスワードを設定しているかチェックする。

参考 : [【Unity】UnityException: Can not sign the application, Unable to sign the application; please provide passwords\! \- コガネブログ](https://baba-s.hatenablog.com/entry/2019/10/11/070000)

# AndroidManifest.xmlは適切に設定されているか？
なんらかのトラブルで複数のAndroidManifest.xmlが作成されているとエラーが出るので、
Oculus > Tools > Remove AndroidManifest.xmlを選択していったん削除する。
その後、 Oculus > Tools > Create store-compatible AndroidManifest.xmlを選択して作り直す。

AndroidManifest.xmlの設定方法は以下を参考に設定する。
[Application Manifests for Release Builds \| Oculus Developers](https://developer.oculus.com/distribute/publish-mobile-manifest/?locale=ja_JP)
サーブレットのrequestメソッドのgetAttributeとgetParameterの違い

サーブレットについて勉強しているときに
getParameterと間違ってgetAttributeを使っていて、
よくわからなかったのでメモ。


まずはフォームに入力した値を標準出力するjspを作ります。

```Test.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<form method="get" action="TestServlet1">
text<input type="text" name="str">
<button type="submit" value="send">send</button>
</form>
</body>

```

入力して実行します。
この例ではhelloと入力をします。

![20210212192227.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/694948/baf0da75-eab8-13d8-09ed-bea84502f351.png)

formの値を受け取ったTestServlet1のdoGetメソッドが
下記コードであるとすると


```TestServlet1.java
		String str = (String)request.getParameter("str");
		System.out.println(str);
```

コンソールには

```console.
hello
```

と出力されます。

ところがgetParameterをgetAttributeとしてしまうと
String型にキャストしたとしても

```TestServlet1_2.java
		String str = (String)request.getAttribute("str");
		System.out.println(str);
```

値はうけとれずnullになってしまいます

```console.
null
```

#じゃあgetAttributeはいつ使えるのか・・・？

という疑問がありました。
さきほどのTestServletのdoGetメソッドを下記のように書き換えてみます。

```TestServlet1.java
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String str = request.getParameter("str");
		System.out.println(str);
		request.setAttribute("str2", str);
		request.setAttribute("str3", str);
		RequestDispatcher rd = request.getRequestDispatcher("TestServlet2");
		rd.forward(request, response);
		rd = request.getRequestDispatcher("TestServlet3");
		rd.forward(request, response);
	}
```
これはフォームから受け取った値を
リクエストスコープにstr2,str3をセットするようにして
TestServlet2,TestServlet3にフォワード処理します。

このときリクエストスコープを通して
をサーブレットTestServlet2でstr2を,
サーブレットTestServlet3はstr3を受け取るようにします。

ただし、違うのは
TestServlet2ではgetAttributeで
TestServlet3ではgetParameterで
受け取るようにしているのがポイントです。

```TestServlet2.java
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String str = (String)request.getAttribute("str2");
		System.out.println(str+"2");
	}
```


```TestServlet3.java
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String str = (String)request.getParameter("str3");
		System.out.println(str+"3");
	}
```

これを実行すると実行すると
![20210212193727.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/694948/49b1812a-d7fe-78f5-58a3-24b4bdb0bd95.png)

TestServlet2のgetAttributeではスコープの値を受け取れましたが、
getParameterでは下記のような500エラーがでました。

![20210212194048.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/694948/86421916-a733-96b9-03cc-72ea40ee3c22.png)


#メモまとめ

まとめると、

jsp　→　servlet：getParameter
servlet →　servlet:getAttribute

という動作ですね。

とはいえ、私はtrl+spaceでコードしているとgetParameterのつもりが
いつのまにかgetAttributeしていることがあったりします・・・（－－；
【Java】Queue、Deque、Stackの関係

Deque（デック）は「double ended queue」（両端キュー）の略。
Queue、Deque、Stackのメソッドを比較できる図を作りました。（この図が意外と見つからなかった。）

- <font color="Red">挿入（要素を挿入する）</font>
- <font color="Blue">削除（要素を取得し削除する）</font>
- <font color="Purple">検査（要素を取得するが削除しない）</font>

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/422235/65090644-c102-bb07-0ce5-574acfe934ce.jpeg"  width=100%>

メソッドにはそれぞれ、2つの形式があります。
1つは操作が失敗したときに例外をスローし、もう1つは特殊な値（操作に応じてnullまたはfalseのいずれか）を返します。

## Queue
[Queue](https://docs.oracle.com/javase/jp/8/docs/api/java/util/Queue.html)

|操作|位置|メソッド|説明|
|---|---|---|---|
|<font color="Red">挿入</font>|末尾|boolean add(E e)|要素が追加されなかった場合は例外をスロー|
|||boolean offer(E e)|要素が追加されなかった場合はfalseを返す|
|<font color="Blue">削除</font>|先頭|E remove()|キューが空の場合はNoSuchElementExceptionをスロー |
|||E poll()|キューが空の場合はnullを返す |
|<font color="Purple">検査</font>|先頭|E element()|キューが空の場合はNoSuchElementExceptionをスロー|
|||E peek()|キューが空の場合はnullを返す|

## Deque
[Deque](https://docs.oracle.com/javase/jp/8/docs/api/java/util/Deque.html)

|操作|位置|メソッド|説明|
|---|---|---|---|
|<font color="Red">挿入</font>|末尾|boolean add(E e)|要素が追加されなかった場合は例外をスロー|
|||void addLast(E e)|〃|
|||boolean offer(E e)|要素が追加されなかった場合はfalseを返す|
|||boolean offerLast(E e)|〃|
||先頭|void push(E e)|要素が追加されなかった場合は例外をスロー|
|||void addFirst(E e)|〃|
|||boolean offerFirst(E e)|要素が追加されなかった場合はfalseを返す|
|<font color="Blue">削除</font>|末尾|E removeLast()|両端キューが空の場合はNoSuchElementExceptionをスロー|
|||E pollLast()|両端キューが空の場合はnullを返す|
||先頭|E remove()|両端キューが空の場合はNoSuchElementExceptionをスロー|
|||E removeFirst()|〃|
|||E poll()|両端キューが空の場合はnullを返す|
|||E pollFirst()|〃|
|<font color="Purple">検査</font>|末尾|E getLast()|両端キューが空の場合はNoSuchElementExceptionをスロー|
|||E peekLast()|両端キューが空の場合はnullを返す|
||先頭|E element()|両端キューが空の場合はNoSuchElementExceptionをスロー|
|||E getFirst()|〃|
|||E peek()|両端キューが空の場合はnullを返す|
|||E peekFirst()|〃|

## Stack
[Stack](https://docs.oracle.com/javase/jp/8/docs/api/java/util/Stack.html)

|操作|位置|メソッド|説明|
|---|---|---|---|
|<font color="Red">挿入</font>|先頭|E add(E e)|追加した要素を返す|
|<font color="Blue">削除</font>|先頭|E pop()|スタックが空の場合はEmptyStackExceptionをスロー|
|<font color="Purple">検査</font>|先頭|E peek()|スタックが空の場合はEmptyStackExceptionをスロー|

## クラス図
主要なクラスを掲載。

![alt](http://www.plantuml.com/plantuml/png/VOv12i8m44NtSufS83r1aIgw4Do8u3wcNorDKaqcYwBUNKb0KYbk0dapRtXDOEKvMaFNheM0lV4eBEm9Fj3MCVnPQOXzH4IzMOW7lQZWQzmBheqAGIozLsCvA8ML6NJVkSkSkEjSZ_RVnX6Q1_y33wnq_sMfLDHFANCSVTu4gYgNJQcKqoGgVrcRww9SaWxa06hWscZD6m00)

- BlockingDeque: 要素の取得時に両端キューが空でなくなるまで待機、または要素の挿入時に両端キューに空きが生じるまで待機するようなブロック操作をサポートするDeque。
AWS Systems Manager で時間のかかるAMI取得を待たずに次のステップに移行する

# 経緯など
最近はSystems Managerをこねこねしてます。
メンテナンスウィンドウを利用して、①AMIを取得(AWS-CreateImage のドキュメントを利用) → ②SSMAgentを更新 という一連のタスクの処理を設定していました。
しかし、EBSの容量が大きかったり、長い間AMIを取得していなかったりするとAMI取得にかなりの時間がかかる場合がありました。
インスタンスによってどのくらい時間がかかるのか分からないので、AMIの取得リクエストをしたら次のステップに移行したいという要望がありました。

# AWSに問い合わせた
AWSに問い合わせると「AWS-CreateImage の代わりにカスタムドキュメントを作成するときにaws:executeAwsApi を利用することでAMIの作成完了を待たずに結果を返すよ」という旨の返答をいただきました。

# aws:executeAwsApi を利用してAMIを作成するドキュメントを作成する
ドキュメント作成時にaws:executeAwsApi を利用するとAWS APIを呼び出して実行することができます。
実際にAMIを作成するドキュメントを作成するにはAWSコンソールの Systems Manager > ドキュメント で「オートメーションを作成する」から作成することができます。
![20210212_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61235/4e1bacae-56f6-4e36-69d6-2180f0a4f3f4.png)
オートメーション作成の画面にてエディタのタブから編集を選び、以下のyamlをエディタにコピペすれば作成することができます。
![20210212_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61235/6605e271-bfb8-4cbd-f42e-117ade15f620.png)

```yaml
description: ''
schemaVersion: '0.3'
outputs:
  - create_ami.ImageId
parameters:
  InstanceId:
    type: String
  NoReboot:
    type: Boolean
mainSteps:
  - name: create_ami
    action: 'aws:executeAwsApi'
    inputs:
      Service: ec2
      Api: CreateImage
      InstanceId: '{{ InstanceId }}'
      Name: '{{ InstanceId }}_{{automation:EXECUTION_ID}}'
      NoReboot: '{{ NoReboot }}'
    outputs:
      - Name: ImageId
        Selector: $.ImageId
```

このyamlではinputにインスタンスIDと再起動のフラグを入力できるようにできますが、AWS APIのドキュメントを参考にもっと細かく制御することもできます。
https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ec2.html#EC2.Client.create_image
オートメーション単体で実行すると、実行はすぐに終わり、AMIのステータスはPendingで作成中ということが分かります。
（対象のインスタンスに大きめのディスクを付けてダミーのデータを積んでから確認したほうが分かりやすいですが、ここでは割愛します。）
![20210212_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61235/eaccd0a6-5923-f58a-b165-e5ce72406c89.png)
![20210212_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61235/f5dcdecc-ad02-feb9-4fd2-be2415579427.png)
![20210212_5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61235/643fc089-24e9-86ea-18a9-79bbd166f4d9.png)
![20210212_6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61235/d30cedf6-d61b-0de8-245c-713226d0f64b.png)


# まとめ
aws:executeAwsApi を利用してAMIを取得するドキュメントの作成方法を紹介しました。
今回はAMIを取得の際にaws:executeAwsApi を利用しましたが、もしかしたら他にも結果を待たずに次のステップに移行することができる処理があるかもしれません。
今後も実行が終了するまで待つべきタスク・スキップしてもよいタスクを見極めて実装していけたらと思います。
asdfを使おう

nodenv使いからのanyenv使いになった皆様におかれましては、そろそろDenoでも触ってみるかといった頃合いかと思います。
anyenvにdenoあるやろーと思って`$ anyenv install -l`したところdenoenvないやん！！？ってめんどくさくなっていませんか？
asdfにはそれがあります！

ということでasdfを使ってみました。

# asdf？

https://github.com/asdf-vm/asdf

nodenvはnodeのバージョンを切り替えられるツール
環境変数をごにょごにょ切り替えてくれるもので、複数のプロジェクトを横断していたりすると重宝するものですよね。
anyenv, asdfはnodeだけでなくて対応している言語のバージョンを管理できるものです。

- anyenv, asdf で言語をローカルにインストールできる。
- 同一言語でも複数バージョン入れておける。
- プロジェクトディレクトリに.xxxversionのファイルを置いておくことで勝手に切り替えてくれる。


# インストール

こちら。簡単
https://asdf-vm.com/#/core-manage-asdf

`~/.bashrc` などに追記をお忘れなく。

# 使うコマンド

そんなにないっす。plugin＝言語のこと

## `$ asdf plugin list all` 対応している言語のリストを表示

いっぱいあります。

## `$ asdf plugin add <name>` 言語をインストール

例 `$ asdf plugin add nodejs`

## `$ asdf list all <name>` 言語のバージョン一覧

```
0.1.14
0.1.15
0.1.16
~~snip;
```


## `$ asdf install <name> <version>` 指定のバージョンを入れる

例: `$ asdf install nodejs 15.8.0`
ちなみにnodejsの場合はファイルのチェックサムを信用するためにPGPキーを事前に設定しておく必要があるってでる。 https://github.com/asdf-vm/asdf-nodejs

```
[derori@murata ~]$ asdf install nodejs 15.8.0
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  3811    0  3811    0     0  90738      0 --:--:-- --:--:-- --:--:-- 90738
Authenticity of checksum file can not be assured! Please be sure to check the README of asdf-nodejs in case you did not yet import the needed PGP keys. If you already did that then that is the point to become SUSPICIOUS! There must be a reason why this is failing. If you are installing an older NodeJS version you might need to import OpenPGP keys of previous release managers. Exiting.

[derori@murata ~]$ bash -c '${ASDF_DATA_DIR:=$HOME/.asdf}/plugins/nodejs/bin/import-release-team-keyring'
gpg: /home/derori/.gnupg/trustdb.gpg: trustdb created
gpg: key D7062848A1AB005C: public key "Beth Griggs <bgriggs@redhat.com>" imported
gpg: Total number processed: 1
gpg:               imported: 1
gpg: key 7434390BDBE9B9C5: public key "Colin Ihrig <cjihrig@gmail.com>" imported

~~snip;


[derori@murata ~]$ asdf install nodejs 15.8.0
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  3811    0  3811    0     0  82847      0 --:--:-- --:--:-- --:--:-- 84688
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 31.1M  100 31.1M    0     0  79.7M      0 --:--:-- --:--:-- --:--:-- 79.7M
node-v15.8.0-linux-x64.tar.gz: OK
[derori@murata ~]$ asdf list nodejs
  15.8.0
```

## `$ asdf [global|local] <name> <version>` 使うバージョン指定

global: そのユーザー全体
local: そのディレクトリ配下

.tool-versions ってファイルができて管理される。コミットしちゃっていい。.node-versionsとかと同じ。


## `$ asdf update` アップデート

たまアップデートしてあげて。


# まとめ

anyenvと共存はおかしくなるのでどっちかだけど、新しい環境はasdf使っていこうと思います！！！！

`$HOME/.asdfrc` に`legacy_version_file = yes` って書けば.node-versionsなどのファイルも見てくれるようです。https://asdf-vm.com/#/core-configuration?id=homeasdfrc

あ。denoは`$ asdf plugin add deno && asdf install deno latest` でおーけーよ。

ドキュメント
https://asdf-vm.com/#/core-manage-asdf
【Androidアプリ開発】初心者からの独学でのおすすめ勉強法

# はじめに
私は、現在大学院修士１回生で、研究をしながら趣味で楽しくサービス開発をしてきました。その中でここ1年半くらいの間は、特にAndroidの開発をメインに行ってきました。その際には基本的には独学で技術を学んできました。そこで、思い返してみると反省していることや、非常にやってよかったことなどが多くあると感じました。
　それを共有することで、__今からAndroidの分野に興味があるけど、どうやって勉強していいのかわからないという人__にとってためになる記事になればいいなと考えています。ちなみに、この記事ではKotlinやJavaでのネイティブアプリ開発についての話になります。

## 始めたてのころ
初めてまずやることのおすすめとしては、動画教材での学習です。よくありがちなのが、最初に大きい本を買って、訳もわからずに挫折してしまったり、なんか分かった気になったけど実際に作るイメージが湧かずあまり意味が無かったと感じてしまうことがあると思います。なので、この段階では実際に動くものを動画というイメージしやすい形で、講師の人と一緒に手を動かしてコードを書くというのが一番良いと思っています。個人的にも文字だけで説明されるよりもわかりやすいですし、多少聞き流しながらでもなんとなく理解できるので無理せず継続できるのではないかと思います。

##### おすすめの動画サイト
- [Udemy](https://www.udemy.com/) セール中なら破格の値段で良質な教材を購入することができます。ただ、日本語での教材が少ないのが悲しい…

## なんとなく分かってきたころ
動画での学習をこなして、画面にボタンやテキストを表示したり、RecyclerViewを使用してリスト表示がなんとなくできるようになってきたら、自分で簡単なアプリを作ってみることがおすすめです。どれだけ動画を見て知識をつけたとしても実際に自分で開発してみたら、思ったように動いてくれなかったりエラーが発生してしまういうことがほとんどだと思います。なので、結局実際に手を動かして作ってみないと技術的に成長できないと思います。なので個人開発でアプリを作ってみるというのがおすすめです。
ただ、いきなり一人で個人開発をすると右も左もわからず、つまずくことも非常に多いのでモチベーションを保つのも大変だと思います。なので、僕なりのおすすめの勉強方法を紹介します。

#### アーキテクチャを理解する
初心者の時に悩むこととしては、どのファイルをどの程度分割すればいいのか？、とか全部ActivityとかFragmentに書いていいのかとか？とか動画や書籍での説明が省略されがちなコードの書き方とかで悩む方は多いと思います。私も最初Androidアプリの個人開発を始めた時は、ほとんどの処理をActivityやFragmentに記述してしまっていて、コードを追加していけば行くほど処理を追いずらくなったし、どこに追加すればいいのかその都度頭を悩ませていました。そんな問題を解決するために、巷にはアーキテクチャというものがあります。ここでは詳しくは説明しませんが、それを理解することで、データベースにアクセスする部分はこう、UIにまつわる部分はこう記述するというように型にはめてアプリを作っていくことができます。色々な種類のアーキテクチャがありますが、まずは公式である[Googleの推奨アーキテクチャ](https://developer.android.com/jetpack/guide?hl=ja)が理解もしやすいので、はじめに勉強してみるのがおすすめです。
　実際の勉強方法としては、[Android Architecture Blueprints](https://github.com/android/architecture-samples)を読み込むのがおすすめです。これはGoogleが公開していて、Todoリストのアプリを様々な手法で実装したものです。このプロジェクトを読み込むことでかなりアーキテクチャに関する理解が深まると思います。また、[Android アプリ設計パターン入門](https://peaks.cc/books/architecture_patterns)という書籍も体系的にAndroidのアーキテクチャについてまとめられているので非常に勉強になりました。

#### よく利用されるライブラリを知る
Android開発において、ローカルデータベースへのアクセスができるRoomやAPI通信を行うためのRetrofitといった、どんなアプリでも利用されるようなライブラリというのがいくつかあります。そういった便利なライブラリを利用することで開発効率が格段にアップするはずです。そういったライブラリの存在を知るためにも、サンプルプロジェクトや公開されているソースコードを読むというのが非常に効果的です。また、技術カンファレンスの動画も公開されているものが多いので、それらを見るのも最新の動向を知る上で非常に参考になります。
存在を知った上で次にそのライブラリの一般的な使い方をどうやって理解するかですが、当然検索してQiita等で情報を集めるのもそうですが、それでいまいちわからなかった時は、英語が多いですがYoutubeで解説している動画をみることがおすすめです。無料でかなり有用な動画がたくさんあります。

##### おすすめの技術カンファレンス動画
- [DroidKaigi](https://www.youtube.com/channel/UCgK6L-PKx2OZBuhrQ6mmQZw)
- [Android Dev Summit](https://www.youtube.com/channel/UCVHFbqXqoYvEWM1Ddxl0QDg)

#### お手本にするコードを決めて、それを忠実に真似る
ただ、実際に学んできたアーキテクチャやライブラリを、ある程度複雑なアプリの中でどのようにして導入すればいいのかという疑問が出てくるかもしれません。そういう時は公開されていて、綺麗に書かれているコードを真似て、自分のアプリに応用するという手法がいいと思います。そうすることで、これまで曖昧だったコードの書き方が矯正されて分かりやすいコードを書く癖が生まれますし、実際にエンジニアとして働く場面を想定しても、それぞれの現場でアーキテクチャに合わせたコードを書くということが必要になってくると思うので、そういう点でも良いと思います。最後にお手本にするのに、おすすめのプロジェクトですが、私は[DroidKaigi 2020](https://github.com/DroidKaigi/conference-app-2020)が良いと思います。アーキテクチャも考えられていて、最新の技術が非常に多く採用されていますし、細かい部分まで非常に参考になるプロジェクトです。

# 最後に
やはり独学で勉強していく上では、自分でアプリを作ることが技術力をつける上で１番の近道だと思います。ただ私自身昔は、綺麗なコードでなくても、新しい技術を使わなくても、サービスを作ることができればある程度いいと考えていましたが、エンジニアになる上で避けては通れない部分だと思いますし、何よりも新しい技術を勉強するのが楽しいと思えるようになりました。なので、職業としてエンジニアを目指す方には作るだけでなく、その技術の動向を意識して筋道立てて少しずつ理解できる範囲を増やしていって欲しいと思っています。