OmniAICreator/Qiita-1.07M huggingface dataset:
Rspecにおける画像検証の方法


画像がちゃんと表示されているか検証するテストを書いている時にやり方がわからずハマってしまったので登録のやり方から検証方法までを書いていく。

## letで画像を登録する

テストで使用するディレクトリに画像ファイルを置き（例では/spec/factoriesに”image_1.jpg”という画像ファイルを置いている）File.new("#{Rails.root}/画像のパス)でデータを登録する

```ruby
let!(:user) { create(:user, name: 'user_1', image: File.new("#{Rails.root}/spec/factories/image_1.jpg")) }
```

## フォームに画像を入力する

“attach_file”を使い画像登録の状況を再現する。name属性、ファイルのパス（上の例と同じディレクトリにあるファイルを指定している）を指定することで画像の投稿を再現することができる

```ruby
attach_file 'フォームのname属性', "#{Rails.root}/spec/factories/image_1.jpg"
```

## 画像がimgタグを使って表示されている場合

 ユーザーのサムネイル画像などがimgタグでそのまま表示されている場合

```ruby
expect(page).to have_selector("img[src$='hoge_image.jpg']")
```

## クラスを指定してそのbackground-imageのURLを指定する

画像そのものがimgタグではなくbackground-imageとして表示されている場合の検証方法
```ruby
expect(page).to have_selector ".class_name[style='background-image: url(#{hoge.image})']"
```
【GCP】Cloud ShellからGCP APIの有効化を試しました

# GCPのAPI有効化について
GCPコンソール画面から「APIとサービス」をクリックし、必要なAPIを選択して、有効化することができます。
一方で、GCPのCloud ShellからもAPIを有効化することができます。

# Cloud Shellコマンド
利用したコマンドは下記になります。
```
$ gcloud services enable SERVICE_NAME
```

# Cloud ShellコマンドからAPIを有効化
コマンドを実行する前に、「Cloud Vision API」は無効であることを確認できております。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/865613/1d73ed37-4efa-50a2-3899-8da77c24f93a.png)

試しで「Cloud Vision API」のAPIをCloud Shellから叩きました。
```
$ gcloud services enable vision.googleapis.com
Operation "operations/acat.p2-XXXXXXXXXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" finished successfully.
```

すると、「APIとサービス」に「Cloud Vision API」が有効化していることを確認できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/865613/56a7fb54-9b48-80bc-dccc-88a8bfa342d2.png)


# 参考資料：

https://cloud.google.com/sdk/gcloud/reference/services/enable

https://cloud.google.com/endpoints/docs/openapi/enable-api#gcloud

https://cloud.google.com/vision/docs/reference/rest
費用対効果が一番高いテストは？単体テスト vs 統合テスト vs エンドツーエンド（E2E）テスト

![1067678.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2633992/de8c7626-c5c7-10e8-d396-816db5af5208.jpeg)
テストを実施する際には、どこまでするかでコストや品質などが大きく変わってくる。
しかし、もちろんシステム開発には納期や予算というものがあり、どれだけ時間やコストをかけてもいいものではありません。
では、どのテストを重視すれば、費用対効果がよいのでしょうか。

このようなことを前提にまとめてみました。

![img_623c8e4bbc328.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2633992/fbe1aa2a-3f4d-4c4a-44d8-d7ad01a66c4f.png)
【テストピラミッド（提供：[CoderPad](https://coderpad.io/blog/development/integration-tests-vs-unit-tests-integration-matters-more/)）】

有名なマーティン・ファウラーさんのテストピラミッドである。
この図は、コストが上がるとテストのスピードが落ちる傾向があることを示しており、そのために多くの開発者がエンドツーエンド（E2E）テストを最小限に抑え、単体テストを最も行っています。

では、単体テストが一番重要なのでしょうか？
焦らずに次の情報をみてみましょう。

CoderPadは2022年3月29日（米国時間）、エンドツーエンドテスト、統合テスト、単体テスト、静的テストを比較し、統合テストの重要性を解説した[ブログ記事](https://coderpad.io/blog/development/integration-tests-vs-unit-tests-integration-matters-more/)には、各テストにおいてのコストと品質における効果（信頼性）を数値として出しています。

|テスト方法|コスト|信頼性|
|:---:|:---:|:---:|
|単体テスト|2|2|
|静的テスト|2|2|
|統合テスト|3|3|
|エンドツーエンド（E2E）テスト|4|4|

これを見る限りでは、単体テストと静的テスト、統合テスト、エンドツーエンド（E2E）テストの順で効果が高くなっています。
同時にコストも効果と同様に高くなっていますね。

こちらの情報から考えるとどうも単体テストが一番ではないようですね。

![img_623c8e4d68668.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2633992/8127ef4b-6e8b-190f-6a76-3c2680e7a9e0.png)
【テストトロフィー（提供：[CoderPad](https://coderpad.io/blog/development/integration-tests-vs-unit-tests-integration-matters-more/)）】

次は有名なKent C. Doddsさんのテストトロフィーである。
Kent C. Doddsさんいわく、

「一般的な考え方は、静的解析ツールと統合テストによって、かけたコストに対して素晴らしい価値が得られる。
そして単体テストとE2Eテストによって、良い価値が得られる。」

とのことです。
統合テストは、E2Eテストと同じようにユーザーの行動をテストできる。
そして統合テストは、特定のロジックの入力と出力をテストするだけの単体テストと比べて、テスト結果の信頼性が高く、素晴らしい価値が得られる。
Kent C. Doddsさんも、

「統合テストは、信頼性とスピード／コストを素晴らしく両立させている。
このため、大部分の労力をそこに費やすことが推奨される」

結論としては、費用対効果が一番高い『 統合テスト 』を一番重視することである。
テストフレームワークとしても、全体の一部として統合テストを重視するのが現在のトレンドでもあるほど統合テストが重視されている。

さらに品質を高めたいのであれば、4種類のテストを組み合わせて使用することを検討することをお勧めします。

https://www.esprit-fort.co.jp/

https://www.esprit-fort.co.jp/recruit/
microエディタ (メモ帳のような操作感のターミナル用)

* https://github.com/zyedidia/micro/releases

## 基本的な操作

| キー | 説明 |
|:--|:--|
| ctrl + q | 終了 |
| ctrl + s | 保存 |
| ctrl + z | undo |
| ctrl + y | redo |
| ctrl + o | ファイルを開く |


| キー | 説明 |
|:--|:--|
| Alt + g | ショートカットキー表示 |

## タブ切り替え

| キー | 説明 |
|:--|:--|
| ctrl + t | 新規タブ |
| ctrl + < | タブ切り替え（左） |
| ctrl + > | タブ切り替え（右） |

## マクロ

| キー | 説明 |
|:--|:--|
| ctrl + u | マクロの記録開始、終了 |
| ctrl + j | マクロの再生 |
| ctrl + b | 端末でコマンド実行 |
三項演算子についての備忘録

# 三項演算子なるもの


## 三項演算子とは
・JavaScriptにおいて3つのオペランドを持つ演算子

式は以下
**条件式** ? **条件式がtrueの時に返す値** : **条件式がfalseの時に返す値**

#### 記述例
```
let test = "hoge";
console.log((test = "hoge") ? "yes" : "no");
```

#### 記述例解説
1行目　test に 文字列 "hoge" を代入。
2行目　console.log();関数で三項演算子の結果をコンソールに表示

三項演算子では
(test = "hoge")? →　testが"hoge"であるかを true か false　で判断
true の場合　→　"yes"　がコンソールに表示される
false の場合　→　"no" がコンソールに表示される

## 所感
if文を簡的に記述できるようにしたようなものと思っている。
現段階だと、if文内で複数処理をするようなことがなければ三項演算子で事足りそうだと思っている。

## 終わりに
備忘録のため参考までに。
何か指摘点があれば遠慮なくお伝えいただければ嬉しいです。
TypeScript学習のアウトプット1

# はじめに
<!-- 発端や概要を記載 -->
はじめまして。
本記事は私が実務でTypeScriptを導入するにあたり、学習のログを記録しておくための記事になります。

私の経歴は、昨年未経験からフロントエンドエンジニアに転職したばかりで、実務歴は1年ほどになります。

現状TypeScriptの知見はなく、これから学習する方へ本記事が少しでも参考になれば幸いです。

# 目次
<!-- タイトルとアンカー名を編集 -->
1. [TypeScriptとは](#1)
1. [TypeScriptのメリット](#TypeScriptのメリット)
1. [記述方法](#reference)

<!-- 各チャプター -->
# TypeScriptとは

* Microsoft社によって開発されているプログラミング言語
* 特徴として**静的型システム**を備えている
→ tscと呼ばれる**コンパイラ**(*)があり、これによりTypeScriptが型チェックを行う。

＊コンパイラ：プログラミング言語をコンピューターが理解できる「機械語」に翻訳するプログラムのこと

```TypeScript:記述例
const x: string = 'hello';
```
↓
```TypeScript:コンパイル後
const x = 'hello';
```

<a id="#TypeScriptのメリット"></a>
# TypeScriptのメリット
* 型安全性
* ドキュメント化

#### 型安全性
先程の記述例を参考にします。仮に以下のような記述で構文に誤りがあると**コンパイルエラー**となります。

```TypeScript:記述例
const x: number = 'hello';
```

この``コンパイルエラー``のおかげでミスがすぐに発見できる可能性が高まり、バグを残してしまうリスクを少なくできます。

#### ドキュメント化
コード読解の際に役立ちます。

```TypeScript:例
function repeatHello(count: number): string {
  return "hello".repeat(count);
}
```

上記より、関数repeatHelloがnumber型の引数を受け取り、string型の返り値を返すことが一瞬で分かります。

<a id="#reference"></a>
# 参考文献
- [プロを目指す人のためのTypeScript入門 安全なコードの書き方から高度な型の使い方まで](https://www.amazon.co.jp/%E3%83%97%E3%83%AD%E3%82%92%E7%9B%AE%E6%8C%87%E3%81%99%E4%BA%BA%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AETypeScript%E5%85%A5%E9%96%80-%E5%AE%89%E5%85%A8%E3%81%AA%E3%82%B3%E3%83%BC%E3%83%89%E3%81%AE%E6%9B%B8%E3%81%8D%E6%96%B9%E3%81%8B%E3%82%89%E9%AB%98%E5%BA%A6%E3%81%AA%E5%9E%8B%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9%E3%81%BE%E3%81%A7-Software-Design-plus/dp/4297127474)
↑まだ読んでいる途中ですが非常に分かりやすいです。
M5Stack Core2で降水確率を表示する

アウトプットは大事
雨が降っても基本傘はささないタイプなので雨はあまり気にしない

## 天気予報を取得して降水確率を表示する
::: note info
気象庁のHPからJsonデータを取得して
M5StackCore2に表示したい
天気予報ではなく、降水確率を知りたい
:::

今回も様々なページを参考にさせていただきました。
「UIFLOW　JSON」とかで検索してね。
（M5Stackキーワードで調べちゃうと、ArudinoのほうがメインなのでUIFLOWで検索したほうがヒットしやすいことに気が付きました）

### つまづきまくったスタート、デバッグも試行錯誤
Wifiを接続して、HTTPブロックでJson取得はできている。
参考ページの通りに作ってみたけど、表示されない。
ひとつづつ分解しながら確認していっています。

GetDataは内容がラベル表示されました。
変数JsonDataにGetDataを代入、ラベル表示させるとなにも表示されない。。
リストの空チェックブロックを追加したらFalseと表示されたので、中身は入っているということですね。。

UIFLOWでのデバッグの仕方もわからない:tired_face:
ラベルに表示させるにしても表示されなかったり失敗してしまう…もはや中身がわからないから解決のヒントが思いつかない。
（表示させる変数が違ったかもしれない。そういうケアレスミス多すぎ）

グラフィックのテキスト表示ブロックを使ってJSON形式に変換して変数の表示させると中身が確認できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2660324/826bc017-58c6-4ba2-f69f-a9986bfa7f86.png)
リストとして取得できているデータを確認しながら、抽出、整形していきました。

### 問題解決、降水確率だけ表示できた
+ リスト化
+ リストの中から必要KeyのValueを抽出

を必要な項目にぶち当たるまで繰り返す。

VSCodeでJsonを一度表示させて、何番目のデータか確認しながらやるとはかどりました。
緑がリストの処理で、ピンクがマップで処理しているところ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2660324/f8c04a2d-3327-a7f8-eb7f-46767d74bf6f.png)
紫の数値が降水確率なのですが。
気象庁の降水確率は以下の内容でした
+ 当日、翌日が表示されている
+ 6時間ごとの％
+ すでに経過した時間帯はJsonから削除されていて、HTML上では”－”での表記
+ ％はMAXで8個、MINで5個

コード的にはよろしくないと思いますが、％をMAXの8個になるまで項目数を追加して
当日分だけの4個になるよう後ろから削除していくというループブロックを付けました。

関数ブロックでHTTPからラベル更新までを定義して、ボタンを押したら再取得するようにしました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2660324/ff483f87-75b3-c9b8-a0dd-048348c3e728.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2660324/07014be8-6856-143b-88fd-91107c8274d3.png)
色がやばい
本当はもっと市町村まで狭めた予報をGETしたかった。
Rspecを書くときに注意していること

Rspecを書くときの自分なりの決まり事、というかこうした方が読みやすくなるんではなかろうかということをメモがわりに書いてく。これからもちょいちょい足していく & これ違うなと思う部分は修正していく。

## 戻り値を明確にする

```ruby
let!(:hoge) do
  huga = create(:hoge, name: 'name', user: user)
  hoge.update(updated_at: Date.new(2018, 7, 1))
  hoge # 戻り値
end
```

最後のhogeがなく、hoge.updateで終わってしまうと戻り値が何なのかが判断しづらいので「hoge」を最後に記述し戻り値を明確にする

## 凡庸的なクラス属性を指定するときは「within(’.someClass’) do」を使い対象を絞る

```ruby
page.all('.btn')[1].click
# 対象が広すぎるのでページに新いbtnクラスが追加されたときにテストが通らなくなる恐れがある

within(page.all('.shops')[1]) { page.all('.btn')[1].click }
# withinで対象となる範囲を狭くすることで対象が明確になり後に不具合が起きにくくなる
```

## 適切な箇所に空行を入れ可読性を良くする

```ruby
describe 'hogehoge' do
  let(:super_admin) { create(:super_admin) }
  let(:hoge) { create(:hoge) }
  # 空行

  before do
    as_page_domain
    login_as super_admin, scope: :admin
    visit hoge_path
  end
  # 空行

  specify 'hugahuga' do
    fill_in :text, with: 'test'
    # 空行

    expect {
      click_button('保存する')
    }.to change(Fuga, :count).by(1)
    # 空行

    expect(page.body).to have_content '登録しました'
  end
end
```

値をセットする部分やチェックする部分の間に空行を入れて構造的に見やすくするとコードがリーダブルになる

## ヒアドキュメントにクォーテションは要らない

```ruby
tsv_text = <<~"TSV_TEXT"
  shop_id
  #{shop_1.id}
TSV_TEXT

# クォーテションを使わなくても書ける
tsv_text = <<~TSV_TEXT
  shop_id 
  #shop_1.id}
TSV_TEXT
```

## テストデータを作るとき画面操作をわざわざする必要はない

```ruby
# 画面操作そのものをテストするわけではないのにseleniumを経由するとそれだけ遅くなる
before do
  tsv_text = <<~"TSV_TEXT"
    shop_id
    #{shop_1.id}
  TSV_TEXT
  fill_in :shop_item_tsv_text, with: tsv_text

  click_button('保存する')
end
  
# 事前に必要なデータであれば let, beforeで最初に作成しておく
before do
  ShopItem.create(shop: shop_1)
end
```

## データのreloadは独立させて書く

```ruby
# リロードとデータの検証を同時にしてしまっているので読みにくい
expect(hoge.reload.position).to eq prev_hoge_position

# reloadと検証を別々にする(reloadとexpectはセットのようなものなので間に空行入れない)
hoge.reload
expect(hoge.position).to eq prev_hoge_position
```
【標準入力】ユークリッドの互除法で最大公約数をもとめる【python3】

# ユークリッドの互除法とは
2つの自然数の最大公約数を求める方法の1つ

## 使いどころ

https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1212456512

# 互除法のやり方
「割り切るまで二つの自然数を割り続ける」やり方を説明する。
①「2つの自然数のうち大きい数÷小さい数」する。
②前の手順の除数(最初は「2つの自然数のうち小さい数」)を前の手順の余りで割る。
③以上の手順を余りが0になるまで繰り返す。
余りが0のときの除数が最大公約数である。

※最大公約数とは余りが0になる上に一番大きな「割り切る整数(約数)」で一番大きな「割る方も割られる方も割ることが出来る数(公約数)」
※除数は割る方の数の事である。a÷bのbの方。

正式な言い方は調べると出ます。
私が噛み砕いて理解する分には上記の※の文章になります。

# pythonで表現するユークリッドの互除法
```python
a,b=(int(x) for x in input().split())#数字にするため。input(),input()だと判定が駄目みたい

#再帰関数(自分自身を呼び出す関数)
def gcd(a, b):#gcdは最大公約数(greatest common divisor)の略
    if b == 0:#このifは二つの自然数aとbが最初から余り0を導き出すことができるもの。
        return a
    else:
        return gcd(b, a%b)#ifのようにa,bの段階で0が出せない時の処理をこれにしている。
print gcd(a,b)
```

# ちなみに：最小公倍数
上記の方法で2つの自然数の最小公倍数も求めることができる。
あくまで、最大公約数を求めるためのユークリッドの互除法を「最小公倍数を求めること」にも使えるという方法であることを認識してほしい。

```python
a,b=(int(x) for x in input().split())#数字にするため。input(),input()だと判定が駄目みたい

#再帰関数(自分自身を呼び出す関数)
def gcd(a, b):#gcdは最大公約数(greatest common divisor)の略
    if b == 0:#このifは二つの自然数aとbが最初から余り0を導き出すことができるもの。
        return a
    else:
        return gcd(b, a%b)#ifのようにa,bの段階で0が出せない時の処理をこれにしている。

print a*b/gcd(a,b)
```
【プログラミングだけじゃない！】未経験エンジニアに求められるスキル３選

エンジニアとして仕事をする上で、プログラミング以外に求められるスキルについて考えてみました。

# 読んでほしい方
* 未経験からエンジニア転職を考えている社会人
* エンジニア職に興味のある学生

# なぜ、プログラミング以外のスキルが求められるのか？
* 現時点での技術力はそこまで求められていないケースが多い
* 未経験の段階で高められる技術力に限界がある

ためであります。

# 未経験時は、どんなエンジニアを目指すべきか？
エンジニアを雑に分類すると以下の４タイプに分けられるかと思います。
　① 技術力が高く、仕事ができるエンジニア
　② 技術力は高いが、仕事ができないエンジニア
　③ 技術力は低いが、仕事ができるエンジニア
　④ 技術力が低く、仕事ができないエンジニア

未経験の段階では、上記③のエンジニアを目指すのが「吉」であります。

今回は、仕事ができるエンジニアになるために必要な**３つのスキル**を紹介します。


## スキル１　業務遂行能力
例えば、こんなエンジニアは、**業務遂行能力が低い**という烙印を押されてしまいます。
* タスクの進め方を自分で組み立てられない
* 求められている成果物と違うものを持ってくる
* レスが遅い

「成果物の内容を具体的にイメージし、事前に共有する」ことで手戻りをなくせると良いです。
2,3割ほど完成したタイミングでフィードバックをもらうというの有効です。


## スキル２　ドキュメントを読む能力
特に**公式ドキュメント**を読む能力です。
プログラミング言語ごとにドキュメントはありますし、各種サービスにも公式ドキュメントがあります。

ブログ記事などの方が読みやすいというメリットがありますが、下記のようなデメリットもあります。
* 信頼性がない（間違った情報が蔓延している）
* 情報が古い


一次情報を読む習慣や能力がないと、他の人から教えてもらわないと対応できないエンジニアになってしまいます。
訳の問題で、日本語のドキュメントは読みにくいけど、英語に切り替えると読みやすくなる時もあったりします。


## スキル３　質問能力
大事です。とても大事です。
タスクの確認、エラー発生時、ハマったときなど、質問するタイミングはたくさんあります。

質問した相手に「**結局何を聞きたいのか良く分からない**」と思われてしまうと、どうなるでしょうか？

　→ コミュニケーションコストが高くなる
　　→ 回答待ちの時間が増える
　　　→ タスクが進まなくなる

こんな状況にならないためには、質問力が大事になります。

**質問する際のポイント**は下記になります。
### ①解決したい課題を明確にする
例
×「InvalidParameterExceptionって何ですか？ / どういう意味ですか？」
◯「コマンドでxxxと実行したところInvalidParameterExceptionが発生し、処理が終了しました。どうしたら良いですか？」

### ②状況を正確に共有する
例
×「https\://xxx.yyy.zzzにPOSTしてもエラーになります。どうしたら良いですか？」
◯「https\://xxx.yyy.zzzにPOSTしたところ、40xエラーになりました。bodyに使ったデータはhogeです。解決策を教えて下さい」

### ③経緯を共有する
例
×「Aのエラーが出たので色々試したんですがうまくいきません。どうしたら良いですか？」
◯「Aのエラーが出て、Fugaのサイトの手順を試したのですが、Bのエラーが発生します。どうしたら良いですか？」



# まとめ
いかがでしたでしょうか。
エンジニアは技術職のため、ついつい技術のことに意識が向きがちですが、
上記のようなスキルの重要性を考えるきっかけになれば幸いです。

弊社は未経験からエンジニアになった方が活躍している会社です。
未経験者の新卒・中途採用も実施していますので、ご興味ある方は[こちら](https://www.recruit.nuco.co.jp/)より。
エンジニアになるためのメンター探しのすゝめ

## はじめに


プログラミングの勉強を始める人にとって、効率的な学習のために重要なものはなんでしょうか？

教材？ハイスペックPC？それらを確保する費用？

これらはもちろんあればあるほど良いでしょう。また独学が難しければ、スクールに入って規定のカリキュラムで勉強する選択肢も悪くないと思います。

本記事では、特にエンジニア就職・転職を目指す人にとって一番効率的に学習を進められる手段について、自分の体験も踏まえて考えてみました。

## 読んでほしい人

- 独学でプログラミングの勉強を始めようとしている、またはすでに始めている人
- 始めたは良いが、何を目指せば良いかわからない人
- 自分の学習内容や進め方に自信がない人

※本内容は、あくまで筆者の経験と主観に基づくものであり、万人に当てはまるものではない旨、ご了承願います。
※筆者は自分自身が未経験からエンジニア転職しており、現在採用活動も行っています。

## 一番重要なのは、「エンジニアとして活躍しているメンターの存在」

結論から言うと、現在進行系で活躍しているメンターを見つけるのが一番手っ取り早いです。

「メンター」というとちょっと堅苦しく感じるかもしれませんが、勉強内容を相談したり、質問したりできる人、だと考えてもらって差し支えありません。

なぜそのようなメンターを見つけることが重要なのか、以下に述べていきます。

### 教材や学習ツールには困らない時代だからこそ、「何のために学習するか」が大事

プログラミング学習自体は、今や誰でも簡単に始められるようになりました。

Web上には無料の学習コンテンツが山のようにありますし、PCのスペックが多少低くても、ブラウザ上でコードが書けるサービスもあります。

インターネット回線さえ準備できれば、いつでも学習をスタートさせられると考えて良いでしょう。

ただ、教材・ツールが溢れているからといって、闇雲に学習しても仕方がありません。

- 自分はプログラミング学習を通して、何を達成したいのか
- そのためには、今の勉強の進め方で良いのか

これらは自分で考えても、中々明確にならない人も多いでしょう。

無料で得られる情報が多すぎるのも、判断しづらくなる要因の一つだと思います。

### メンターを見つけるメリット①：勉強の方向性を見失いづらい

職業エンジニアになるための勉強内容については、実際に働いているエンジニアの人に相談するのが一番です。

当たり前のように思えるかもしれませんが、意外とそういう相談ができる人がいない、という人は多いです。
（「どうすればエンジニアになれますか？」とTwitterで投げかけている人とか、結構見ます。）

筆者自身、未経験の方と採用面談することもありますが、多くの方が迷いながら勉強されている印象です。

実際に活躍している人から、「一緒に働くエンジニアに求めるもの」を教えてもらえるのは非常に重要ですし、今の自分のスキルセットを客観的に評価してもらえるチャンスでもあります。

### メンターを見つけるメリット②：メンターのキャリアをそのまま自分の目標にできる

「エンジニアになる」という目標は持っていても、「どんなエンジニアキャリアを歩みたいか」を考えている人は少ないんじゃないでしょうか。

エンジニアになることはゴールではなくスタートです。

実際に働いているエンジニアの人と接する中で、その人の歩んでいるキャリアを知り、自分の目標とすることができると、エンジニアになった先のこともイメージしやすいと思います。

そんな、「目標にしたい人」と出会える、勉強にもより一層身が入りますよね。

## メンターと出会うには？

以上、メンターを見つける重要性について説明してきましたが、そういった人にはどうやって出逢えば良いのでしょうか。

考えられるパターンをいくつかピックアップしてみます。

### まずは友人・知人から探してみよう

身の回りで見つけられるのならば、これほど心強いことはありません。

「エンジニアをやってる人」という観点で、自分の人間関係を見直してると良いでしょう。

また直接でなくても、友人・知人から紹介してもらえるならば、それも良いです。

全く無縁の人とつながることと比べると、安心感は段違いです。

注意としては、元々繋がりがあるからこそ、甘えない・依存しないことが挙げられると思います。

相手も断りにくいと思うので、節度を守ったコミュニケーションを心がけたいところです。
（このケースに限ったことではありませんが...。）

### メンターとマッチングできるサービスを使ってみる

[Menta](https://menta.work)や[Yenta!](https://page.yenta-app.com/jp)などのマッチングサービスを活用するのも手だと思います。

有料/無料、エンジニア特化/非特化などの差異はありますので、いくつか横断的に見極めながら、使いやすいものを使ってみましょう。

他の利用者からのレビュー機能があるものもありますので、良い人を探しやすいかもしれません。

このケースで特に気をつけたいのは、所謂カモにされる可能性です。

あらゆるオンラインマッチングで気をつけたい点ですね。

相手も何か目的があってサービスに登録しているはずなので、いいように利用されないよう、しっかり見極めながら活動できると良いですね。

### もくもく会などのイベントに参加してみる

[connpass](https://connpass.com/)といった勉強支援プラットフォームでは、もくもく会（勉強会）がよく企画されています。

初心者から職業エンジニアの方まで広く参加しているケースもあるので、継続的に参加していると、良い出会いがあるかもしれません。

筆者が採用面談させてもらった中でも、このケースで相談できる人を見つけている方がいらっしゃいました。

このケースの注意点は、集団イベントなので節度を持って参加しましょう、という点でしょうか。

皆さん勉強するために集まってますので、話しかけて良いタイミングか、などはしっかり判断したいですね。


## おわりに

実際に質問に答えてくれる・相談にのってもらえる人には、最大限の敬意と感謝を持って臨みたいところです。

これからプログラミング学習を始める人・エンジニア就職を目指す人への一助となれば幸いです。


弊社では、経験の有無を問わず、社員やインターン生の採用を行っています。
興味のある方は[こちら](https://www.recruit.nuco.co.jp/)をご覧ください。
Databricks SQL CLIを試してみる

本日Databricks SQLのCLI(コマンドラインインタフェース)が公開されました。

https://pypi.org/project/databricks-sql-cli/

インストール・設定を行うことで、ローカルマシンからDatabricks SQLに対してクエリーを実行することができるようになります。

# インストール

ローカルマシンのターミナルで以下を実行します。

```bash:Bash
pip install databricks-sql-cli
```

# 設定

インストール後、ターミナルで`dbsqlcli`を実行するとホームディレクトリ配下の`~/.dbsqlcli/dbsqlclirc`に設定ファイルが作成されます。

```bash:Bash
(base) yayoi@Ganesha ~ % dbsqlcli                      

        Welcome to DBSQL CLI!

        It seems this is your first time to run dbsqlcli,
        we generated a default config file for you
            ~/.dbsqlcli/dbsqlclirc
        Please change it accordingly, and run dbsqlcli again.
```

こちらで接続先の情報を指定しますので、設定に必要な情報を取得します。

1. 接続先のDatabricks環境のサイドメニューのペルソナスイッチャーで**SQL**を選択します。
1. **SQLエンドポイント**にアクセスし、使用するSQLエンドポイントの**接続の詳細**を表示します。
1. ここで表示される**サーバーのホスト名**と**HTTPパス**をメモしておきます。
![Screen Shot 2022-05-13 at 16.36.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/bf793d06-4b16-9cbb-7027-ff2d2c9a2547.png)
1. パーソナルアクセストークンを発行します。サイドメニューの**設定 > ユーザー設定**にアクセスします。
1. **Personal access tokens**タブをクリックします。
1. **新規トークンを生成**をクリックします。
![Screen Shot 2022-05-13 at 16.39.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/7d279fda-68bb-c72c-5a49-22acda18da1a.png)
1. コメントと存続期間を指定して**生成**をクリックします。一度しか表示されないので、注意してこれをコピーしておきます。
![Screen Shot 2022-05-13 at 16.40.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/ce6bb561-5308-90af-d8db-74b82d4d8e21.png)

:::note warn
**重要！**
パーソナルアクセストークンは発行したユーザーの権限でのDatabricksの操作を可能にする非常に重要な情報です。第三者に共有しないでください。厳密に管理してください。
:::

ローカルマシンのターミナルで設定ファイル`~/.dbsqlcli/dbsqlclirc`を編集します。

```bash:Bash
vi ~/.dbsqlcli/dbsqlclirc
```

コマンドラインの引数にパラメーターとして認証情報指定することもできますが、ここでは設定ファイルの最後に以下の設定を追加します。

```
[credentials]
host_name = "サーバーのホスト名"
http_path = "HTTPパス"
access_token = "パーソナルアクセストークン"
```

ファイルを保存します。

# クエリーの実行

ローカルマシンのターミナルで再度`dbsqlcli`を実行します。引数にSQLを指定することもできますが、何も指定しない場合はREPLが起動します。インタラクティブにクエリーを実行することができます。

```bash:Bash
(base) yayoi@Ganesha ~ % dbsqlcli                 
ホスト名:default> select * from test_table;
+----------+----------+-----------+-----------+---------+
| PersonID | LastName | FirstName | Address   | City    |
+----------+----------+-----------+-----------+---------+
| 1        | Yayoi    | Polka     | Mito      | Ibaraki |
| 1        | Yayoi    | Ume       | Shinagawa | Tokyo   |
| 1        | Yayoi    | Yuki      | Shinagawa | Tokyo   |
| 1        | Yayoi    | Taka      | Shinagawa | Tokyo   |
+----------+----------+-----------+-----------+---------+
4 rows in set
Time: 17.554s
ホスト名:default>
```

引数としてクエリーを指定するには以下のようにします。

```bash:Bash
dbsqlcli -e 'select id, name from minifigs LIMIT 10'
```

ファイルを指定する場合にはこちら。

```bash:Bash
dbsqlcli -e query.sql
```

ちなみに、REPLではオートコンプリートもサポートされています。

![Screen Shot 2022-05-13 at 16.46.41.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/25f1017d-3a65-ef37-3c16-b0a757bac523.jpeg)

### Databricks 無料トライアル

[Databricks 無料トライアル](https://databricks.com/jp/try-databricks)
python3の私がよく忘れる演算子

`//`：整数除算。小数を切り捨てする除算。
`**`：べき乗「αの何乗」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1822331/4c3d7cd2-95b8-4d1f-b0a6-6601aab689e2.png)
 のことを「a のべき乗」という
rails5 progate　整理メモ

# ログイン失敗時のメッセージを表示させる
送信されたパラメータにあうユーザーがない場合にメッセージを表示させる。
その時にお題のメッセージを表示させる
## どうやってエラーメッセージを表示させるのか忘れた。
ちょっと答えを見た。
```users_controller.rb
def login
    .
    .
    .
    else 
      @error_messeage = "メールアドレスまたはパスワードが間違っています"
      render("login")
    end
  end
```
loginページに行く前にインスタンス変数に代入しておく。そうすることで中身を入れることができる。
```rb
<% if @error_messeage %>
```
@error_messeageに中身があれば表示されるようにする。

```login.html
        <% if @error_messeage%>
          <div class="form-error">
            <!-- 以下の<%= %>を用いてエラーメッセージを表示してください -->
            <%= @error_messeage %>
          </div>
        <% end %>
```
これで表示された。

# ログインに失敗した場合にフォームに初期値が入るようにしましょう。
送信されたパラメータが保存されるようにする
ログインした時にどういうことをやっていたかを振り返る。
```users_controller.rb
def login
    @user = User.find_by(
      email: params[:email],
      password: params[:password])
    if @user
      session[:user_id] = @user.id
      flash[:notice] = "ログインしました"
      redirect_to("/posts/index")
    else
      @email = params[:email]
      @password = params[:email]
      @error_messeage = "メールアドレスまたはパスワードが間違っています"
      render("login")
    end
  end
```
多分```else```以下にしたのはその時だけ実行させるため、余計なことをさせないためだと思う。
インスタンス変数に送信されたパラメータを代入させる
```rb
@email = params[:email]
```
どうやって文字列を表示させるか
```
<input ... value= <%= "@email" %>>
```
これを使う。

# ログインに失敗した場合に、メールアドレスが初期値としてフォームに表示されていません
この原因はよくわからなかった。
思い当たるところとしては
```routes.rb
  get "login" => "users#login"
  post "login" => "users#login"
```
ビューのアクションとログインさせるアクションを合わせていたからだと思っている。
```routes.rb
  get "login" => "users#login_form"
  post "login" => "users#login"
```
他にあると思うが今は思いつかない。
あの時焦らずに調べながら直していければよかった。

# ユーザー登録時にログイン状態にしよう
```user_controller.rb
  def create
    @user = User.new(
      name: params[:name],
      email: params[:email],
      password: params[:password],
      image_name: "default_user.jpg"
      )
    if @user.save
      session[:user_id] = @user.id
      flash[:notice] = "ユーザー登録が完了しました"
      redirect_to("/users/#{@user.id}")
    else
      @password = params[:password]
      render("users/new")
    end
  end
```
新規登録ページ
```new.html
.
.
.
        <%= form_tag("/users/create") do %>
          <p>ユーザー名</p>
          <input name="name" value="<%= @user.name %>">
          <p>メールアドレス</p>
          <input name="email" value="<%= @user.email %>">
          <p>パスワード</p>
          <input type="password" name="password" value="<%= @user.password %>">
          <input type="submit" value="新規登録">
        <% end %>
.
.
.
```
答えでは
```user_controller.rb
@password = params[:password]
```
を書かずに
```new.html
<input type="password" name="password" value="<%= @user.password %>">
```
と@userのパスワード属性を呼んでた。
そのほうが1行書かずに済むからだろう。
それを真似した。

まだまだrailsの旅は続く！
terraformでGCPをはじめる


## サービスアカウントを追加

### 追加

名前を決める
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293481/bca48ae1-4799-0c8c-f086-3f64bb9372f2.png)

権限を決める
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293481/1b706763-a1be-f9e4-4c26-8d2254311cde.png)


鍵を生成する（ローカルにjsonファイルがダウンロードされる）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293481/eafb84e0-7289-3587-ccd6-646167e3bfd9.png)

ダウンロードされたファイルを`~/CREDENTIALS_FILE.json`で配置する


## terraformを書く
```terraform
provider "google" {
  credentials = file("~/CREDENTIALS_FILE.json")
  project = "golang-302004"
  region  = "asia-northeast1"
}

# Create a single Compute Engine instance
resource "google_compute_instance" "default" {
  name         = "flask-vm"
  machine_type = "f1-micro"
  zone         = "us-west1-a"
  tags         = ["ssh"]

  metadata = {
    enable-oslogin = "TRUE"
  }
  boot_disk {
    initialize_params {
      image = "debian-cloud/debian-9"
    }
  }

  # Install Flask
  metadata_startup_script = "sudo apt-get update; sudo apt-get install -yq build-essential python-pip rsync; pip install flask"

  network_interface {
    network = "default"

    access_config {
      # Include this section to give the VM an external IP address
    }
  }
}
```

```bash
terraform init
terraform apply
```

VMが作られた
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293481/f3a3645a-ce39-222f-bc04-12a98fb468a0.png)
【基本情報技術者】システムの性能評価

基本情報技術者試験の分野「システムの性能評価」についてご紹介いたします。

## システムの性能指標
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2655909/9e918ed9-77ab-8ba1-54e5-b712e1d0b2a2.png)
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2655909/403d751a-009a-871c-16e7-fffb85497535.png)

## ベンチマークテスト
システムの使用目的に合った**標準的な実行プログラムを実行させ、その測定数値から処理性能を想定的に評価**する方法。
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2655909/66c5a75a-6912-7605-a230-bccab5b5a8c0.png)

## MIPS
MIPSとは. **M**illion **I**nstructions **P**er **S**econd（100万命令/秒）の略。コンピューターの処理速度を表す単位で、**1秒間に何百万個の命令が実行できるかを表す。**
### 命令ミックス
コンピュータの処理能力を測定する際に用いる命令の組み合わせのことです。よく使う標準的な命令をひとつのセットにしたものです。
### 命令ミックスからMIPS値を求める
「基本情報技術者平成30年秋期 午前問9」のMIPS値を求める問題を解いてみる。
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2655909/3a5814f6-bcb1-b000-dd41-c4603bc1d09d.png)

最初に命令の種別ごとに出現率(%)を割合計算のために小数点に置き換え、必要なクロック数と掛け算し、加重平均を使って、平均命令クロックを求める。
・レジスタ間演算：4×0.3
・メモリ・レジスタ間演算：8×0.6
・無条件分岐：10×0.1
　**(4×0.3)＋(8×0.6)＋(10×0.1)＝1.2＋4.8＋1.0＝7.0**
この計算結果から、1命令に必要な平均クロック数は**7クロック**であるとわかります。

問題からこのCPUの動作クロック数が700**M**Hz　※**M**（メガ)＝1,000,000＝10⁶
**700×10⁶**と表せる。

CPUの動作クロック数÷1命令に必要な平均クロック数
　**700×10⁶÷7＝100×10⁶回**

MIPSは1秒間に実行できる命令数を百万単位で表す指標なので、10⁶＝M（メガ)
**100×10⁶→100M**
このCPUの性能は**100MIPS**になります。
LEGO SPIKE Primeでデイジーチェーン(Hub to Hub communication)

## はじめに
EV3には本体同士を接続してポート数を増やす「デイジーチェーン(Daisy Chain)」という機能がありました。残念ながらこれに相当する機能は2022年5/2時点で**SPIKE Primeにはありません**。
しかし、[Robot Inventor 51515](https://www.lego.com/ja-jp/product/robot-inventor-51515)にはハブ間での通信を可能にする「**Hub to Hub communication**」という機能があります。
Robot Inventor 51515はハードウェア的にはSPIKE Primeと全く同じ(色は緑色の)製品です。残念ながら現在日本での正規代理店からの販売はありません。~~ただし、2022年の6月から日本でも販売が始まるそうです。~~[販売が始まりました](https://www.lego.com/ja-jp/product/robot-inventor-51515)。
<img width="800" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2449798/704bac4f-bce7-6d7f-1e5c-029e6f34e73b.png">

## SPIKE PrimeをRobot Inventorに変身させる
※Robot Inventorをお持ちの方は*方法の5*まで飛ばしてください。
先述の通りRobot Inventorは色が違うだけでSPIKE Primeとハードウェア的はに全く同じ製品です。
つまり、**ソフトウェア-HubOSをRobot Inventorのものに書き換えてしまえば、それはRobot Inventor**なのです。

### 方法
1.  まずはマインドストームのアプリをインストールします。※日本語非対応です。
Windows: https://www.microsoft.com/ja-jp/p/lego-mindstorms-robot-inventor/9mtq0n7w1d6x?activetab=pivot:overviewtab 
Android: https://play.google.com/store/apps/details?id=com.lego.retail.mindstorms 
iOS&Mac: https://apps.apple.com/jp/app/lego-mindstorms-inventor/id1515448947

2. SPIKE Primeを接続します。
2. HubOSを更新するというメッセージが表示されます。ボタンを押して更新しましょう。更新には少し時間がかかります。※この段階でHub内のプログラムなどが消去されるかもしれないので気をつけてください。
2. HubOSの更新が終わると、モータの更新画面が表示されます。
2. プログラム画面左下の＋から「HUB TO HUB COMMUNICATION」を追加(ADD)する。<img width="500" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2449798/4b36840d-f0ee-cd78-b291-2140c474555f.png"><img width="600" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2449798/76b32786-0460-6fcb-2e2c-379ad3a206d9.png">
2. するとブロック一覧の一番下に以下の写真のようなものが追加されたら完了です。<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2449798/15751c6e-471b-12a9-5c63-9bafb2f49352.png">

## 使い方
※MindstormsアプリのHelpをそのまま和訳しています。いくらか間違いがあるかもしれません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2449798/8dc70512-3656-356e-fff0-5615280a2a5a.png)

## デイジーチェーンとの違い
* デイジーチェーンはマスターとなるEV3がスレーブのEV3を1つのプログラムで動かすことができますが、1つ1つのHubはHub to Hubにおいてあくまでも独立しており、あるHubの発信した信号を他のHubが読み取る方法であるため、プログラムはHubの数だけ必要になります。

* デイジーチェーンはUSB接続やBluetooth接続で互いを認識する必要がありました、ですがHub to Hubにおいて、あるHubの発信した信号はそのの名前さえわかれば誰のどのHubでも読み取ることができます。
* 信号に載せて送ることのできる情報は変数などの値に限られるため、デイジーチェーンのように他のHubを柔軟に容易に制御することは難しくなります。
* デイジーチェーンは最大4台まで接続が可能でしたが、Hub to Hubでは理論上無限のHubと通信をすることができます。

## 注意点
* Hub to HubはEV3のデイジーチェーンとは違い、ハブ間でお互いを認識する必要がなく、発信された信号はどのハブでも受け取ることができます。つまり、同じ名前の信号を使っているチームが近くにいた場合、違うチームのハブからの信号を受け取ってしまいます。信号の名前を被りにくいものにする(例えば末尾に数字を付ける)ことが必須です。

* Hub to HubにはBluetoothのみを使うことができ、USBは恐らく使えません。ロボカップジュニアのように無線通信の一切を禁じている大会ではHub to Hubの使用が制限されるかもしれません。実際にEV3においてデイジーチェーンをBluetoothで行うことは禁じられています。

## 参考文献
https://nxt.typepad.jp/robojoy/2021/09/mindstorms51515.html

https://youtu.be/47cTxxz1TQg

https://youtu.be/Mq_mLQF1dZ4
pyedflibでEDFファイルを上書きする

# はじめに
pyedflibの使い方やedfファイルの読み込み方については既に@tchkwkzkさんの記事があるためそちらを参照ください。

https://qiita.com/tchkwkzk/items/0e4e6cb1e29436c843c9

# EDFファイルの上書き
EDFファイルに書き込むこと自体は`pyedflib.EdfWriter`で可能ですが、EdfWriterは元のファイルを初期化してから書き込むため上書きできません。
対策としてedfファイルを複製し、複製したファイルに上書きします。


```python
import pyedflib
#-----------------
def get_all_signals(edf:pyedflib.EdfReader):
    """
    edfファイルから全チャンネルの波形を取得して返します。
    """
    ewavs = []
    for idx,_ in enumerate(edf.getSignalLabels()):
        ewavs.append(edf.readSignal(idx))
    return ewavs

def copy(redf:pyedflib.EdfReader,copy_path:str,copied_func = None):
    """
    redfの内容をコピーパスへコピーします。
    copied_funcの第一引数にredf,第二引数にwedfを返します。
    """
    ch = len(redf.getSignalHeaders())
    with pyedflib.EdfWriter(copy_path,ch) as wedf:
        header = redf.getHeader()
        #header["birthdate"] = "" 元のedfファイルが日付フォーマットのルールに従っていない場合フォーマットエラーが出るため birthdateを空文字に置き換えて回避します。
        annos = redf.readAnnotations()
        wedf.setHeader(header)
        wedf.setSignalHeaders(redf.getSignalHeaders())
        wedf.writeSamples(get_all_signals(redf))
        for i,_ in enumerate(annos[0]):
            wedf.writeAnnotation(annos[0][i],annos[1][i],annos[2][i])
        if not (copied_func is None):
            copied_func(redf,wedf)
        wedf.close()
    return ch
```
ヘッダー情報のbirthdateが適当に設定されているファイルだとエラーが出る可能性があります。その場合コメントアウトしている部分を利用してください。

使うとき(例:アノテーションを追加する)
```python 
EDF_PATH = "*****"
OUT_EDF_PATH = "*****"
edf_reader = pyedflib.EdfReader(EDF_PATH)
def copied_func(redf:pyedflib.EdfReader,wedf:pyedflib.EdfWriter):
    wedf.writeAnnotation(ot,-1,"action") #アノテーションを設定

copy(edf_reader,OUT_EDF_PATH,copied_func)
```

# おわりに
もしコピーできていない項目があればコメントで教えていただけると幸いです。

また、pyedflibの使い方をまとめてくださった@tchkwkzkさんに感謝します。
Cloudflare R2 Open Beta を試した

## はじめに

2022.5.13 クレジットカード情報を登録する必要があるのだけれど、R2 の利用申請手順のながれだと、決済が完了しない挙動になるケースがある。

アカウント情報から、クレジットカード情報を先に登録しておいて、R2 利用申請すれば大丈夫だった。

## S3 互換 そしてなにより 転送料が無料

https://developers.cloudflare.com/r2/

ためしてみた。

いくつか対応していない APIもたくさんあるみたいだけれど、転送料が無料というのがありがたい。

ただファイルごとのアクセス課金はある。2系統。

1系統は、ファイルをGET/PUTしてくるカウント

GET は安くて。
PUT は高い。

https://developers.cloudflare.com/r2/platform/pricing/#class-b-operations


もうひとつは、GET 操作などを RESTちっくにすすめるなら、Cloudflare Workers 利用が必須だから。
1ファイルを操作するたびに、こちらも従量課金が発生する。

ということで、そこそこ大き目のファイルをホスティングするなどには、とても向いている。
少量多数のファイルだと、こまかく課金されるから、塵も積もれば山となる。それでも S3 にくらべたら転送料がかからないぶん安心安全感はある。
Ubuntuにgcloudコマンドをインストールする



## インストール
```
sudo apt-get install apt-transport-https ca-certificates gnupg
echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" | sudo tee -a /etc/apt/sources.list.d/google-cloud-sdk.list
curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key --keyring /usr/share/keyrings/cloud.google.gpg add -
sudo apt-get update && sudo apt-get install google-cloud-sdk
```


## プロジェクトの選択

```
gcloud init
```

```
Welcome! This command will take you through the configuration of gcloud.

Settings from your current configuration [default] are:
core:
  account: gat.x131.calamity.orga@gmail.com
  disable_usage_reporting: 'True'
  project: meat-vela-349000

Pick configuration to use:
 [1] Re-initialize this configuration [default] with new settings
 [2] Create a new configuration
Please enter your numeric choice:  1

Your current configuration has been set to: [default]

You can skip diagnostics next time by using the following flag:
  gcloud init --skip-diagnostics

Network diagnostic detects and fixes local network connection issues.
Checking network connection...done.
Reachability Check passed.
Network diagnostic passed (1/1 checks passed).

Choose the account you would like to use to perform operations for this configuration:
 [1] gat.x131.calamity.orga@gmail.com
 [2] Log in with a new account
Please enter your numeric choice:  1

You are logged in as: [gat.x131.calamity.orga@gmail.com].

Pick cloud project to use:
 [1] bamboo-reason-336609
 [2] golang-302004
 [3] meat-vela-349000
 [4] Enter a project ID
 [5] Create a new project
Please enter numeric choice or text value (must exactly match list item):  2

Your current project has been set to: [golang-302004].

Not setting default zone/region (this feature makes it easier to use
[gcloud compute] by setting an appropriate default value for the
--zone and --region flag).
See https://cloud.google.com/compute/docs/gcloud-compute section on how to set
default compute region and zone manually. If you would like [gcloud init] to be
able to do this for you the next time you run it, make sure the
Compute Engine API is enabled for your project on the
https://console.developers.google.com/apis page.

Your Google Cloud SDK is configured and ready to use!

* Commands that require authentication will use gat.x131.calamity.orga@gmail.com by default
* Commands will reference project `golang-302004` by default
Run `gcloud help config` to learn how to change individual settings

This gcloud configuration is called [default]. You can create additional configurations if you work with multiple accounts and/or projects.
Run `gcloud topic configurations` to learn more.

Some things to try next:

* Run `gcloud --help` to see the Cloud Platform services you can interact with. And run `gcloud help COMMAND` to get help on any gcloud command.
* Run `gcloud topic --help` to learn about advanced features of the SDK like arg files and output formatting
* Run `gcloud cheat-sheet` to see a roster of go-to `gcloud` commands.

```


## 公式サイト
https://cloud.google.com/sdk/docs/install?hl=ja
じけい💫れつ

Kaggle本
時系列データの扱い3.10
時系列データのバリデーション手法5.3

以下の観点から捉える。
1.時間情報を持つ変数があるかどうか
2.学習データ、テストデータが時系列で分かれているかどうか
3.ユーザーや店舗といった系列ごとに時系列の目的変数があり、ラグ特徴量が取れる形式であるかどうか

ケース１（１に当てはまる場合）
・ユーザーの属性や過去の行動ログが与えられる、
・予測対象は１ヶ月以内に解約するかどうか
・ある時点のユーザーを分割して、学習データテストデータが作成されている。
ケース２（１と２に当てはまる場合）（自分のバイトはこれ）
・ユーザーの属性や過去の行動ログが与えられる
・予測対象は１ヶ月以内に解約するかどうか
・テストデータはある時点のユーザ全体で、学習データとして、過去の各月ごとに月初ごとに存在するユーザーとその月内に退会したかどうかが与えられる。
ケース３（１、２、３に当てはまる場合）
・ユーザーの属性や過去の行動ログの他に、ユーザー過去の利用時間が日毎に与えられる。
・予測対象は日毎の利用時間
・テストデータはある時点のユーザー全体と将来の一定期間の各日の組み合わせで、ユーザーの過去の利用時間から学習データが作成できる。

時系列データをクリーンに扱うには予測する時点より過去の情報のみを使う制約を守って特徴量の作成やバリデーションを行う必要がある。（データが不足しているときなどは例外に使用することもあるが）

ロングフォーマット、ワイドフォーマットを使い分ける。
ワイドフォーマットは時系列的な変化が見やすく、また後述のラグ特徴量を取るときに扱いやすい。一方で、学習を行うときはユーザーごとに目的変数を持つロングフォーマットにする。
ワイド→ロングはDataFramaのstackメソッド
ロング→ワイドはDataFrameのpivotメソッド

3.10.4　ラグ特徴量
店舗、日付、目的変数という形式のデータがあり、将来の各店舗の売上を予測するようなタスクを考える。
直近が単純かつ最も効果の大きい特徴量になるのに加え、周期にしたがってラグを取るのも有効。
ex 顧客の行動が曜日の影響を受け、１週間単位で周期があることが考えられるので１週間前の売り上げ、２週間前の売り上げ、、のようにラグ特徴量を作ることができる。
ex shift関数、移動平均、
リード特徴量（将来の値、天気など）

3.10.5 時点と紐づいた特徴量を作る。
過去の情報のみを使う制約を守ったまま学習、予測を行うために時点と紐づいた特徴量を作り、時点をキーとして学習データと統合する。
ex.不定期にイベントを開催しているときに、イベントの新鮮味や継続して人気のあるイベントかを反映するためにその日が何回目の出現かを特徴量とする。
ex.ログデータをもとに、各ユーザーの過去１週間のサービス利用回数を特徴量とすることを考える。

3.10.6 予測に使えるデータの期間
テストデータのレコードの時点ごとに使える過去の期間が異なる場合に注意する。
ex.テスト期間が１週間の場合
テストデータの期間が分割時点から何期先であるかによって個別にモデルを作成する。

5.3 時系列データのバリデーション手法
5.3.1
テストデータに最も近い期間をバリデーションデータとする、時系列にそったhold-out法(周期性を持つ場合は注意する）
バリデーションで求めた最適な特徴量やパラメータをそのまま使い、バリデーションデータも含めて再学習してモデルを作成する。
（学習データを最初からとする場合、学習データの期間の長さを揃える場合）
古すぎるデータをバリデーションデータとすると余り参考にならないのでどこかで打ち切る必要はある。
時間的な前後関係が余り気にする必要がない場合は単純に時間的に区切って分割する方法をとる。
Velocytoを動かす

Velocytoはいけてるsingle cell解析ツールで、2018年にNatureにでたあと、瞬く間に流行った解析手法。
https://www.nature.com/articles/s41586-018-0414-6
細胞分化の軌跡などをみるときには、monocleなどのツールよりも直感的に分かりやすい(個人的な感想)。

### インストール

[installation guide](http://velocyto.org/velocyto.py/install/index.html#install)を参考に進める。
環境は、python>=3.6が推奨のようなので、とりあえず3.8で作る。

```sh:環境作り
conda create -n velocyto_env python=3.8
```
そのあとで、指定のライブラリーとvelocytoをインストール。samtoolsも必須なので、なければいれる。
```sh:install
conda activate velocyto_env
conda install numpy scipy cython numba matplotlib scikit-learn h5py click samtools
pip install velocyto
```

### cellranger
これで準備オッケーなので、まずは、cellrangerの処理から。
--include-intronsのオプションをつけ忘れないようにする。
```sh:cellranger
cellranger count --id=test --transcriptome=refdata-gex-mm10-2020-A --fastq=fastq --sample=sample --include-intron
```
--idは、出力のフォルダ名。
--transcriptomeは、10Xのサイトからダウンロードできるリファレンスデータ。今回はマウス。
--fastqは、fastqファイルが入っているフォルダ。
--sampleは、fastqファイルの名前のパターン。　sample_S1_L000_のsampleの部分。

あとはぼーっと待つ。

### velocyto
次に、cellrangerの出力を使って、velocytoを動かす。
```sh:velocyto
velocyto run10x -m mm10_rmsk.gtf test/ refdata-gex-mm10-2020-A/genes/genes.gtf
```
run10xのxが小文字なことに注意！
これに気づかず30分ぐらいむしゃくしゃした。
velocyto run10x -m mask.gtf [cellrangerで出力されるoutsの直上のフォルダ] [cellrangerで使ったリファレンス]

-mは　mm10のゲノムのリピート配列をマスクしたgtfファイル。
[maskfileのダウンロードはここ](https://genome.ucsc.edu/cgi-bin/hgTables?hgsid=611454127_NtvlaW6xBSIRYJEBI0iRDEWisITa&clade=mammal&org=Mouse&db=mm10&hgta_group=allTracks&hgta_track=rmsk&hgta_table=0&hgta_regionType=genome&position=chr12%3A56694976-56714605&hgta_outputType=primaryTable&hgta_outputType=gff&hgta_outFileName=mm10_rmsk.gtf)からダウンロードできる。
[outsの直上のフォルダ]は、今回は、testという名前。
[リファレンス]は、 10xの公式からダウンロードしたリファレンスデータの中に入っているので、それを指定。

その後、さらにぼーっと待っていると、testディレクトリの中に、velocytoという新しいディレクトリができ、その中に.loomファイルができている。

次は、Rかpythonの作業。
また次の機会に。
[Electron] C++ addon (Native Node Module) を他PCに展開したとき、"Specified module could not be found" で動かない

# 前段

ぼく「Electronでアプリ作ったよ！」
とも「module not found とか言われて動かないよ〜」
ぼく「はっ！？」

と、なったときの対処方法です。

# チェック項目

## :white_check_mark: 対象Nodeモジュール(hogehoge.node)は、ちゃんと存在している？ 

対象Nodeモジュールが存在しないときは、Webpackに失敗しているのかも。

*.nodeを読み込むルールを確認します。

```json:webpack.config.js
{
  module: {
    rules: [
      {
        test: /\.node$/,
        loader: "node-loader",
        options: {
          name: "[name].[ext]"
        }
      }
    ]
  }
}
```


## :white_check_mark: 対象Nodeモジュール(hogehoge.node)に必要なDLLは入ってる？

`dumpbin /dependents hogehoge.node` として、必要なDLLをチェックします。

```
    kernel32.dll
    bcrypt.dll
    user32.dll
    advapi32.dll
    VCRUNTIME140.dll
    VCRUNTIME140_1.dll
    api-ms-win-crt-math-l1-1-0.dll
    api-ms-win-crt-string-l1-1-0.dll
    api-ms-win-crt-runtime-l1-1-0.dll
    api-ms-win-crt-convert-l1-1-0.dll
    api-ms-win-crt-stdio-l1-1-0.dll
    api-ms-win-crt-heap-l1-1-0.dll
    api-ms-win-crt-utility-l1-1-0.dll
    api-ms-win-crt-locale-l1-1-0.dll
    api-ms-win-crt-environment-l1-1-0.dll
    api-ms-win-crt-conio-l1-1-0.dll
```

`VCRUNTIME140.dll` は、VC++再頒布可能パッケージをインストールしないといけないやつです。

ビルドしたPCの `%VCToolsRedistDir%` の下に vc_redist.*.exe というファイルがあるので、実行するPCへインストールします。
ReactiveWebAppを作成する

1.	リアクティブWebアプリを作成し、名前を付け、初期色を選択します。
2.	Excelからデータをインポートして、データベースモデルを自動的に作成します。
3.	データベースのデータをリスト表示する画面を作成します。
4.	レコードの追加と更新を行う画面を作成します。
5.	レコードを削除する機能を実装します。
6.	ブラウザでアプリケーションをテストします。
Service Studioで、［New Application］をクリックして［Reactive Web App］を選択します。［Next］をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1209998/4599ae78-69fc-5dca-14a0-71e80ca6654a.png)
2［Create app］をクリックして次の手順に進みます。

アプリケーションのプロパティの画面で、［Choose module type］に［Reactive Web App］が選択されていることを確認します。［Create module］をクリックしてモジュールを作成し、編集のために開きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1209998/a552797c-c5d1-d439-8c07-ff3fd77bde59.png)
Excelファイルからデータベーステーブルを作成する
ToDoモジュールで、右上の［Data］タブを開きます。Entitiesフォルダを右クリックして［Import New Entities from Excel］を選択し、デフォルトで使用可能なサンプルファイルTasks.xlsxを選択します。ダイアログの［Import］をクリックして確定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1209998/3e061a88-ce81-314e-1cc1-7d9e314aaffd.png)

タスクを表示する画面を作成する

右上の［Interface］タブを開き、［UI Flows］の下にある［MainFlow］をダブルクリックします。次に、ツールボックスから［Main Editor］ウィンドウの空いている領域に Screenをドラッグします。Emptyテンプレートを選択し、Tasksという画面名を付け、［Create Screen］をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1209998/5fb0ac46-1d96-743d-af0a-3b5c7cdd8883.png)

Taskエンティティを、［Data］タブから［Main Editor］ウィンドウの画面の［Content］プレースホルダにドラッグします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1209998/8436e5e5-af25-12ab-5160-8de9341a1023.png)

これにより、ページネーションをサポートするテーブルが自動的に作成されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1209998/6477f26a-81fa-600b-72e3-a04554e62b99.png)
タスクを編集する画面を作成する
レコードを編集する画面の作成は、テーブルの作成と同じくらいすばやくできます。
行内の最初のタスクのタイトルを右クリックし、［Link to > (New Screen)］をクリックします。Emptyテンプレートを選択し、「TaskDetail」という画面名を付け、［Create Screen］をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1209998/30d0f46c-4159-98f5-3c88-c344ef0e0aa3.png)

これにより、タスクのタイトルが新しく作成された画面にリンクされます。この新しい画面を使用してタスクを編集しますが、そのためにはフォームが必要です。
1.	Formウィジェットを、ツールボックスから［TaskDetail］画面の［Content］プレースホルダにドラッグします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1209998/ad309d9a-b371-2495-adfc-6ee131da2c6a.png)

Data］タブにあるTaskエンティティを、事前に作成したFormにドラッグします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1209998/df48b97c-5fed-0b97-f28a-e4ba21edcccb.png)

この段階でリアクティブWebアプリをテストします。［1-click publish］ボタンをクリックし、ご利用の環境にアプリケーションをパブリッシュします。アプリケーションがデプロイされたら、［［ ］ボタンをクリックして、アプリケーションをブラウザでテストします。
JavaScriptのDate.toLocaleStringで日付をフォーマットして表示する方法


```js
// 現在のlocaleを確認する
console.log(Intl.NumberFormat().resolvedOptions().locale);
> ja-JP

// timeZoneも含めて表示する
console.log(new Date().toLocaleString('ja-JP', {timeZone: 'Asia/Tokyo'}));
> 2022/5/13 15:14:09

// 【Node.jsの場合】timeZoneは環境変数で指定して、localのみ指定する（ここだけ、コマンドです。）
env TZ=Asia/Tokyo node -e 'console.log(new Date().toLocaleString("ja-JP"));'
> 2022/5/13 15:14:09

// 和暦で出してみる
console.log(new Date().toLocaleString('ja-JP-u-ca-japanese'));
> R4/5/13 15:00:57
```

JavaScriptには、日付をフォーマットする関数が標準ライブラリに無いため、一般的な表示で出したい場合には、上記を使うと良いかと思います。

## ja-JPの部分の由来

下記の仕様で決まっているようです。

* 先頭の小文字２文字: ISO-639
  * [ISO-639](https://www.loc.gov/standards/iso639-2/ISO-639-2_8859-1.txt)
* 後方の大文字２文字 or ３文字: ISO-3166
  * [ISO-3166](https://www.iso.org/obp/ui/#search)

下記サイトのほうが１つで見れて良いかもしれません。
https://www.fincher.org/Utilities/CountryLanguageList.shtml
WearOSにおけるWi-Fiを使ったデバッグ

## スマートウォッチで開発者向けオプションを有効にする
スマートウォッチでデバッグを行うには、開発者向けオプションを有効にする必要があります。この操作は 1 回だけ行う必要があります。開発者向けオプションは、無効にするまで有効なままになります。

## スマートウォッチの [設定] を開きます。
[システム] > [デバイス情報] をタップします。
[ビルド番号] までスクロールし、ビルド番号を 7 回タップします。
デベロッパーであることを確認するダイアログが表示されます。
Wi-Fi 経由でデバッグする
デバッグを開始する前に、スマートウォッチで開発者向けオプションが有効になっていることを確認します。

スマートウォッチを Wi-Fi ネットワークに接続する
スマートウォッチの [設定] を開きます。
[接続] > [Wi-Fi] をタップします。
ネットワークを選択し、必要に応じてそのパスワードを入力します。
注: スマートウォッチと開発マシンが同じネットワークに接続されている必要があります。すべてのアクセス ポイントを使用できるわけではないことにご注意ください。場合によっては、ファイアウォールが adb をサポートするように適切に設定されているアクセス ポイントを使用する必要があります。

### Wi-Fi 経由のデバッグを有効にする
スマートウォッチの [設定] を開きます。
[開発者向けオプション] > [Wi-Fi 経由でデバッグ] をタップします。
しばらくすると、画面にスマートウォッチの IP アドレスが表示されます（例: 192.168.1.100）。次のステップでこの IP アドレスが必要になるので、メモしておきます。
### デバッガをスマートウォッチに接続する
スマートウォッチと開発マシンが同じネットワークに接続されていることを確認します。
スマートウォッチの IP アドレスを使用してデバッガをスマートウォッチに接続します。たとえば、IP アドレスが 192.168.1.100 の場合、adb 接続コマンドとそのレスポンスは次のようになります（ポート番号 5555 がアドレスに追加されています）。


    adb connect 192.168.1.100:5555
    connected to 192.168.1.100:5555
    
これでスマートウォッチがデバッガに接続されたため、デバッグを開始できます。-s フラグを使用して adb コマンドをスマートウォッチに送信し、スマートウォッチの IP アドレス（ポート番号を含む）を指定します。


    adb -s 192.168.1.100:5555 <command>
    
エミュレータを使用しておらず、デバッグ用に接続されているデバイスが 1 台のみの場合は、アドレスの指定は不要です。


    adb <command>


https://developer.android.com/training/wearables/apps/debugging?hl=ja
5.1 (標準) 標準偏差の期待値

## 方針

標準偏差の期待値は，「標本分散がカイ二乗分布に従う」という事実を使って求める．

## 答案

![5.-2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1702786/ce5b11d5-f31c-69ab-092d-4a120a3d4521.jpeg)



## 参考文献

- 『[現代数理統計学の基礎](https://www.kyoritsu-pub.co.jp/bookdetail/9784320111660)』(久保川達也　著)
stepfunctionsでのDynamoDBを使用した多重実行制御

# はじめに
AWSのEventBridgeを使用して定期実行などを行う際、最低１回の実行が保証されている（[参照](https://docs.aws.amazon.com/ja_jp/eventbridge/latest/userguide/eb-troubleshooting.html)）。
しかし、処理によっては多重実行が望まれないものもある。
そこで今回は、DynamoDBを用いて、stepfunctionsの多重実行を制御する方法を考えた。

# 実装
今回は、日次で１回のみ行う処理をイメージした。ステートマシンの構造は以下の通りである。

- DynamoDBに実行日を表す値(yyyymmdd)を入れる
- 上の処理が正常に動作したらメインの処理が走る、エラーが起こったらステートマシンを終了する

## DynamoDBのテーブル作成
今回はtestというテーブル名で、パーティションキーをyyyymmddとするテーブルを作成した。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1675618/7b75b8b4-6c76-a4ec-baae-46cdc7010fcd.png)

## ステートマシンの作成
以下のようなイメージのステートマシンを作成した。
なお、今回は、多重実行が制御できれば良いので、メインの処理はmainという名のpassステートで代用してある。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1675618/dc4335c9-4750-26a0-bfcd-fc8f0bf9f126.png)



```
{
  "Comment": "A description of my state machine",
  "StartAt": "PutItem",
  "States": {
    "PutItem": {
      "Type": "Task",
      "Resource": "arn:aws:states:::dynamodb:putItem",
      "Parameters": {
        "TableName": "test",
        "ConditionExpression": "attribute_not_exists(yyyymmdd)",
        "Item": {
          "yyyymmdd": {
            "S.$": "$.yyyymmdd"
          }
        }
      },
      "ResultPath": null,
      "Catch": [
        {
          "ErrorEquals": [
            "DynamoDB.ConditionalCheckFailedException"
          ],
          "Next": "Already put"
        }
      ],
      "Next": "main"
    },
    "Already put": {
      "Type": "Pass",
      "End": true
    },
    "main": {
      "Type": "Pass",
      "End": true
    }
  }
}
```

### パラメータ説明

`putItem`
[Request Parameterに関するドキュメント](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/APIReference/API_PutItem.html#API_PutItem_RequestSyntax)
- "parameters"内の"ConditionExpression"を"attribute_not_exsits(yyyymmdd)"とすることで、指定したyyyymmddが既に存在しているかどうかを判定する（[参照](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html)）。
- 既にDynamoDBに値が存在している場合、"DynamoDB.ConditionalCheckFailedException"が返却されるので、これを"Catch"で受け取っている。

# 動作検証
### DynamoDBに値が入っていない場合
以下の条件でステートマシンを実行した。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1675618/38985c6c-45b9-fe7d-bb1d-c1ea79d59a82.png)

#### 実行結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1675618/669f1fbd-dbc7-e9b7-8fad-6d423d3183a7.png)

期待通り、ステートマシン上ではPutItemの次にmain処理を走らせることに成功した。
ちなみにこのとき、以下のようにDynamoDBに20220101の値が入っていることが確認できる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1675618/64b25690-37e2-4ea7-6339-96ac6c2cab72.png)

### DynamoDBに既に値が入っている場合
上の状態から、再度同じ条件でステートマシンを実行した。

#### 実行結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1675618/51c2218e-1fe9-c61e-318a-146b1d3d3177.png)

期待通り、PutItemで起こったERRORをCatchし、main処理が走ることなく、Already putステートに処理が移った。

# まとめ
今回実装したPutItemステートを多重実行制御したいステートマシンに入れることにより、簡単に多重実行制御ができることがわかった。実行ログの記録としての役割も同時にDynamoDBは果たすことができるので、DynamoDBに入れる値も工夫の余地があると考えられる。
[TypeScript]タプル型で可変長とオプショナルの併用はできない

小ネタです。

@uhyoさんの[TypeScriptの型入門](https://qiita.com/uhyo/items/e2fdef2d3236b9bfe74a)のタプル型の説明を拝見して試した内容のメモです。

## 可変長のタプル型の宣言

```TS

//uhyoさんのサンプルコード
type NumAndStrings = [number, ...string[]];
type StrsAndNumber = [...string[], number];

//可変長を間に挟めるか確認(OK)
type NumAndStringsAndNum = [number, ...string[], number];

//代入式
const a1: NumAndStrings = [3, 'foo', 'bar'];
const a2: StrsAndNumber = ['foo', 'bar', 3];
const a3: NumAndStringsAndNum = [1, 'foo', 'bar', 3];

```

## オプショナルのタプル型の宣言

```TS

//uhyoさんのサンプルコード
type T = [string, number?];

const t1: T = ['foo'];
const t2: T = ['foo', 3];

//オプショナルを複数宣言(OK)
//　→オプショナルが末尾に固まっていれば良い
type U = [string, number?, string?, number?];

const u1: U = ['文字列', 1];
const u2: U = ['文字列', 1, '文字列2'];
const u3: U = ['文字列', '文字列2']; //NG
  //Type 'string' is not assignable to type 'number'.(2322)
  //中間(2個めのnumber?)の省略はできない。

```

## 本題：可変長とオプショナルを併用したタプル型の宣言(NG)

```TS

//可変長とオプショナルを併用したタプル型の宣言は...
type NumAndStringsWithOptionalNumber = [number, ...string[], number?];
  //An optional element cannot follow a rest element.(1266)
  //...と言われてしまう(number?部分)

//なので、こういう事はできない
const a1: NumAndStringsWithOptionalNumber = [3, 'foo', 'bar'];
const a2: NumAndStringsWithOptionalNumber = [3, 'foo', 'bar', 10];

```

**可変長を間に挟み込めるなら行けるかも！？**...と思いましたがダメでした。
「**いるか！？**」って聞かれると...私は使う機会はなさそうです(^^;

**以上、現場からお伝えしました！**
Ubuntu導入後～GPU(CUDA等)+PyTorchの環境構築【簡単】メモ WSL対応

# 目標,本記事の特徴
機械学習/深層学習用の環境を構築する。
PytorchがしっかりGPU上で動作するようにする。
なぜか他の記事より少ない手順でそれが実現できてしまった。

# 手法

nvidiaドライバー導入
WSLの場合不要(windowsのほうにnvidia driverが入っていればOK)
```
sudo apt-get install ubuntu-drivers-common
ubuntu-drivers devices
sudo apt-get update
sudo ubuntu-drivers autoinstall
sudo reboot
```
動作確認表が出力されればOK
```
nvidia-smi 
```
anacondaに合わせてgitも一応入れておく
```
sudo apt-get install git
wget https://repo.anaconda.com/archive/Anaconda3-2019.07-Linux-x86_64.sh
bash Anaconda3-2019.07-Linux-x86_64.sh
```
仮想環境上にpytorchもろもろを導入(仮想じゃなくてもいいけど)
conda installは以下のページ参照
pipがいいならpipのを以下のページからとってくればいい
https://pytorch.org/get-started/previous-versions/
```
conda create -n testenv python=3.7.3
conda activate testenv
conda install pytorch==1.10.0 torchvision==0.11.0 torchaudio==0.10.0 cudatoolkit=11.3 -c pytorch -c conda-forge
```

WSLの場合これも実行
```
echo "export PATH=~/anaconda3/bin:\$PATH" >> ~/.bashrc
source ~/.bashrc
```

動作確認トレーニングがしっかりGPUを利用して使われていたらOK(nvidia-smiでGPU使用率が確認できる)
```
git clone https://github.com/pytorch/examples.git
cd examples/vae/
python main.py
```
# 実証環境
ubuntu 18.4
Intel(R) Core(TM) i9-7920X CPU @ 2.90GHz
NVIDIA RTX A5000
mem:32GB
※Ampereアーキテクチャではcuda11.x以上でないと動かないらしい

# 謎
通常どの記事もcondaからとは別でnvidia driver->cuda->cudnnといったように導入するように紹介しているが、そうしなくてもしっかり動いた。(逆にそうすると自分の環境だと行き詰ってしまう)
だれかそうする理由知っていたら教えてください。自分が知らないだけかもしれないので。

間違えている可能性があるので一応気を付けてください
[Drupal]PHPの設定を変更する

PHPのメモリ容量などphp.iniに書かれている情報はsettings.phpに以下のような行を追加することで編集できます。
```php
ini_set('memory_limit', '256M');
```

他には
- php.ini
- .user.ini
- .htaccess
を編集する方法もあります。詳しくはこちらをご覧ください。

https://www.drupal.org/docs/7/managing-site-performance-and-scalability/changing-php-memory-limits