OmniAICreator/Qiita-1.07M huggingface dataset:
AWSハンズオン実践メモ  〜スケーラブルウェブサイト構築編〜

# はじめに
AWSでWeb三層モデルを体系的に構築した事が無かった為、AWS公式の[ハンズオン(スケーラブルウェブサイト構築編)](https://pages.awscloud.com/event_JAPAN_Hands-on-for-Beginners-Scalable_LP.html?trk=aws_introduction_page)を実践しました。
本記事は自身のハンズオン学習メモとして投稿します。
# 目次
- [ハンズオンの目的](#ハンズオンの目的)
- [本編](#本編)

- [おわりに](#おわりに)

# ハンズオンの目的
WordPressを具体例に、

- Amazon EC2
- Amazon Virtual Private Cloud (VPC)
- Amazon Relational Database Service (RDS)
- Elastic Load Balancing (ELB)

を利⽤し、スケーラブルなWebシステムを構築する。
>WordPressを使ったブログサイトの構築を通じて、スケーラブルな Web システム構築を学んでいただけるウェビナーシリーズです。主に取り扱う AWS サービスは Amazon EC2、Amazon RDS、ELB の3つです。また、作って終わりではなく、実際にEC2インスタンス１台を停止させ、その状態でもブログサイトにアクセスできることも確認します。  

![202004-handson-harada.9f9c1460b97c9eef660f9a881ea3c59f3c7ef7b7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/646352/3f717b51-1987-e095-03bc-dbc85f4a1d21.png)
(https://aws.amazon.com/jp/aws-jp-introduction/aws-jp-webinar-hands-on/?trk=aws_blog より引用)

# 本編
※全てマネジメントコンソールから実施。
### Amazon VPCの作成
- VPC作成
- Subnet作成(Private、PublicをAZ-A、AZ-Cに1つずつ)
- ルートテーブルの関連付け(PublicのデフォルトゲートウェイをIGWに設定)  

### Amazon EC2の作成
- PublicのAZ-AにEC2インスタンスを作成。ユーザーデータを利用しWordPressをインストール
- SecurityGroup作成・設定
- EC2にSSH(EC2 Instance Connect (ブラウザベースの SSH 接続)を利用)  

EC2 Instance Connectを使えばSSHの鍵を作成せずに接続出来るのか。。。
参考：[EC2のSSHアクセスをIAMで制御できるEC2 Instance Connectが発表されました](https://dev.classmethod.jp/articles/ec2-instance-connect/)

### Amazon RDSの作成
- SecurityGroup作成
- Subnetグループ作成
- RDS作成

### ELBの作成
- SecurityGroup作成
- ALB作成(ターゲットグループ作成、ヘルスチェック設定)
- DNS名で接続

### WordPress初期設定
初期設定を行い、アクセス。特筆すべき事はなし

### AMIの作成と、そのAMIから２つ⽬のEC2インスタンス作成
- AMI作成(既にデプロイしているEC2のAMIを作成)
- AMIからEC2作成
- ターゲットグループに新規EC2追加

### EC2(Web)とRDS(DB)のマルチAZ化
- RDSをマルチAZに変更

### 構築したアーキテクチャの可⽤性確認
- EC2のうち1台を停止し、Webページにアクセス。問題なくアクセス出来る事を確認
- RDSをフェールオーバーさせ、webページにアクセス。フェールオーバー中の数分はアクセス出来ないが、その後アクセス出来るようになる事を確認

### 作成した AWS リソースの削除
粛々と削除。特筆すべきことはなし。

#おわりに

AWSでweb三層モデルを体系的に構築したのは初めてだったので、いい経験になった。
また、AWSの資格勉強のおかげで、GUIで行うレベルの設定パラメータについては理解できている事が分かった。
sed, tr, awk でキャメルケースやスネークケースを変換する

シェルスクリプト中に変換したいことがあったのでちょっと書いてみました。
ちなみに、CamelCase などの言葉はこんな感じです。

- キャメルケース(Camel Case)
    - 最初の１単語は小文字、残りは先頭大文字で区切る。Javaなどの変数名で使う。 
    - e.g. `camelCaseString`
- パスカルケース(Pascal Case)
    - キャメルケースの最初の一文字が大文字。クラス名などで使う。
    - e.g. `PascalCaseString`
- スネークケース(Snake Case)
    - すべて小文字で単語の区切りがアンダースコア (`_`) 
    - e.g. `snake_case_string`
- ケバブケース(Kebab Case)
    - すべて小文字で単語の区切りがハイフン (`-`) 
    - e.g. `kebab-case-string`

ケバブケースは調べてて初めて名前を知。

## 前提条件

Macユーザーなので、 sed は BSD のものを使っています。
GNU sed の場合は読み替えてください。

## Camel(Pascal) to Snake(Kebab)

- 大文字区切りを見つけてアンダースコア(またはハイフン)を挿入
- 英字をすべて小文字に変換

```
sed -E 's/(.)([A-Z])/\1_\2/g' | tr '[A-Z]' '[a-z]'
```

ポイント: 大文字を検出する場所はその前に少なくとも１文字以上あることを条件にしているので、パスカルケースの場合の1文字目は対象外になる

## Snake(Kebab) to Pascal

`awk` の区切り文字をアンダースコア（またはハイフン）にして各フィールドごとに先頭を大文字にする

```
awk -F '_' '{ for(i=1; i<=NF; i++) {printf toupper(substr($i,1,1)) substr($i,2)}} END {print ""}'
```


## Snake(Kebab) to Camel

パスカルケースへの変換とほぼ同様だが、2単語目から大文字化する。

```
awk -F '_' '{ printf $1; for(i=2; i<=NF; i++) {printf toupper(substr($i,1,1)) substr($i,2)}} END {print ""}'
```
不意のエラーから気づいた（Salesforce Apexトランザクション）

Apexトランザクションの定義について、理解を深めるため、メモしておきます。

このエラーはさぞなく見覚えはあるでしょ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550974/7ee46a68-a2a4-75f5-0dc6-707327a563d2.png)
解釈：データ作成／更新する処理でCommit前に同期処理APIを呼び出すと、このエラーに引っかかる。
よって、「同一のトランザクション内にAPIコールする時、必ずcommitの後に実行する」とSFDCの制限がある。

Apex開発ガイドと覗いたら、こんな言葉があった。
”Apex トランザクションは、1 つの単位として実行される一連の操作を表します。トランザクションの実行には、すべての DML 操作が正常に完了することが求められます。”

データ作成／更新する処理でCommit前に同期処理APIは許されないが、非同期APIのコールがオッケー👌。
よって、仮設：非同期処理が新しいトランザクションを始まったから、エラーに引っかからなかった。

実際に試験すると、確かに、非同期処理のブロック中にApex制限がフラッシュされた。
【RSpec devise_token_auth 】ユーザー認証トークンを渡す方法

#はじめに
devise_token_authを使用してユーザー認証をrequest specに書く際に時間がかかったので、他に同じ様なエラーで詰まっている方のお役に立てれば幸いです。
#前提
Ruby：2.6.5
Rails：6.0.3.1

テストはRSpecを使用。
ユーザー認証に`devise_auth_token`を使用しています。

#失敗するspec
```ruby:shops_request_spec.rb
RSpec.describe "Api::V1::Shops", type: :request do
  describe "GET api/v1/shops" do
    let!(:shops) { create_list(:shop, 10) }
    context "認証済みのユーザーの場合" do
      it "一覧を表示できる" do
        get '/api/v1/shops'
        expect(response.status).to eq(200)
        expect(json.size).to eq(10)
      end
    end
 end
```
これだとユーザー認証ができずに**401**のエラーコードが出てテストがパスしません。

#ユーザー認証トークンの渡し方
`create_new_auth_token`でトークンを作り、get '/api/v1/shops'にheadersを追加します。
※因みにトークンの認証は`uid` `access-token` `client`をheadersに返してユーザー認証をしています。

```ruby:shops_request_spec.rb
RSpec.describe "Api::V1::Shops", type: :request do
  describe "GET api/v1/shops" do
    let!(:shops) { create_list(:shop, 10) }
    context "認証済みのユーザーの場合" do
      let(:auth_headers) { create(:user).create_new_auth_token }
      it "一覧を表示できる" do
        get '/api/v1/shops', headers: auth_headers
        expect(response.status).to eq(200)
        expect(json.size).to eq(10)
      end
    end
 end
```
この様にかけば、ユーザー認証が成功します！！
#参考記事
2番目の記事はやり方は違いますが、同じくdevise_auth_tokenでのユーザー認証のやり方を記載した記事なので、すごく参考になると思います！！
>https://tutorialmore.com/questions-2886025.htm

>https://qiita.com/mtoyopet/items/ed1bd4b9c1544d401880

#おわりに
今年駆け出したばかりのエンジニアなので、何か間違っている点あればコメント等お願いします。
Vuejsでリアルタイム検索

# 初めに
割と検索に苦手意識を持ってきたので実装を避けてきたのですが思ったより案外簡単にできたのでおいておきます。
環境

- Vuejs
- Bootstrap4
- Axios

# HTML

```vue

<input type="text" placeholder="検索..." v-model="keyword">
<p v-for="user in filterUsers">
 {{ user.name }}
</p>
```

#Vuejs

```javascript


export default {
 data() {
  return {
   keyword: '',
  }
 },
 created() {
  this.getItems()
 },
 computed: {
  filterData() {
   var users = [];
   for (var i in this.users) {
    var user = this.users[i]
    // 配列とkeywordを比較して一致したら...
    if(user.name.indexOf(this.keyword) !== -1) {
     //配列にpushする。
     users.push(user)
    }
   }
   return users;
  }
 },
 methods: {
  getItems: function () {
   axios.get('/api/users').then(res => {
     this.users = res.data
   })
  }
 }
}
```

#終わり
これで完成となっています。
ね？簡単でしょ？
リアルタイム検索なので前方、後方、部分、完全一致関係なく検索してくれます。
便利な世の中になった。
【Visual Studio】OpenCVでカメラ画像取得

#はじめに
######※これは、VC++ Visual Studioを利用する初心者向けの学習用記事です。
今回はVisual Studioを利用し、画像処理ライブラリOpenCVを用いてカメラ画像取得を利用する方法説明する。
OpenCV 4.0.0を利用しているが、本記事で説明する関数は、2.4.xx～4.xまで含まれているので利用できると思います。

#OpenCVでのカメラ画像取得の関数
OpenCVで簡単にカメラ画像を取得する方法は、以下の関数を利用する。

```cpp:
cv::VideoCapture::VideoCapture();
```

```cpp:カメラ映像の取得
cv::VideoCapture capture(0); 	//宣言時にカメラ番号0を指定して起動。

cv::VideoCapture capture; 		//先に変数のみの宣言を行う。
capture.open(0); 				//後から、カメラ番号0を指定してカメラを起動することも可能。
```

カメラ番号は、int型の数値を引数で与えることで、複数台カメラが接続されているPCで利用したいカメラを選択することができる。
０から順番にカメラ番号は設定されるため、番号を０から順に入れていくことで確認できる。

##カメラ映像取得のテストプログラム

```cpp:Camera_Test1.cpp
#include <opencv2/opencv.hpp>

#ifdef _DEBUG
#pragma comment(lib, "opencv_world400d.lib")
#else
#pragma comment(lib, "opencv_world400.lib")
#endif

using namespace std;
using namespace cv;

int main()
{
	VideoCapture capture(1);					//カメラ番号１を起動
	Mat frame;

	while (1) {
		capture >> frame;						//カメラ画像の取得。frameに格納
		imshow("カメラ画像", frame);			  //frameに格納されている画像を表示
		if (waitKey(1) == 27) break;			//ESCキーが入力されるまで実行
	}

	return 0;
}
```


#カメラ映像の情報取得・設定変更
カメラを起動したのち、正しく起動ができているか確認を行う関数がある。

```cpp:カメラの起動確認
bool cv::VideoCapture::isOpened();
```
isOpened()は、返戻値がbool型であり、Trueであれば起動状態。Falseでは起動できなかったと確認することが可能である。
画像が取得できない状態でのOpenCVの処理はAssertion failedの原因となるため、必ず起動確認を行ったほうが無難である。

```cpp:カメラ情報の取得
double cv::VideoCapture::get(int propID);
```
getでは、引数のpropIDを渡すことに様々なカメラ情報を取得することが可能である。propIDの一部抜粋を以下に表にします。

| propID       |       機能 |
|:-----------------|:------------------|
| CAP_PROP_FRAME_WIDTH| カメラのフレームの横幅 |
| CAP_PROP_FRAME_HEIGHT| カメラのフレームの縦幅 | 
| CAP_PROP_FPS             |  カメラのフレームレート  |


※このpropIDはOpenCVのversionで変わっている可能性があります。各versionのリファレンスで確認することをお勧めします。

##カメラ起動確認及びカメラ情報のテストプログラム

```cpp:Camera_Test2.cpp
#include <iostream>
#include <opencv2/opencv.hpp>

#ifdef _DEBUG
#pragma comment(lib, "opencv_world400d.lib")
#else
#pragma comment(lib, "opencv_world400.lib")
#endif

using namespace std;
using namespace cv;

int main()
{
	VideoCapture capture(1);											//カメラ番号１を起動

	if (!capture.isOpened()) {											//カメラ起動の確認
		cout << "Camera Not Opened!" << endl;							//起動できてない場合はエラー
		return -1;														//プログラム終了
	}

	int width = static_cast<int>(capture.get(CAP_PROP_FRAME_WIDTH));    //画像の幅を取得。幅は整数なのでキャスト。
	int height = static_cast<int>(capture.get(CAP_PROP_FRAME_HEIGHT));	//画像の高さを取得。高さは整数なのでキャスト。
	double fps = capture.get(CAP_PROP_FPS);								//fps(フレームレート)を取得

	cout << "width:" << width << " height:" << height << " fps:" << fps << endl;

	return 0;
}
```

```bash:出力結果
width:640 height:480 fps:30
```

#さいごに
今回はVisual Studioを利用し、画像処理ライブラリOpenCVを用いてカメラ画像取得する方法の説明を行った。
ちょっとした監視カメラやアプリのような顔認識して顔を弄るようなプログラムを自作できるようになるので、
写真の入力以上に利用できる内容が広がると思われる。
IMEが ENG になって あ゛あ゛あ゛あ゛あ゛ とならないようにする

<blockquote class="twitter-tweet" data-partner="tweetdeck"><p lang="ja" dir="ltr">よくIMEが &quot;ENG&quot; になってうっぜえええええってなってたのだけど、左Alt＋Shiftがホットキーになっているらしく、解除してとても快適になった。<br><br>「キーボードの詳細設定」→「入力言語のホットキー」→「入力言語を切り替える」の「キーシーケンスの変更」で「なし」にすればOK。</p>&mdash; 大上雅史｜Ohue M (@tonets) <a href="https://twitter.com/tonets/status/1275324615863091200?ref_src=twsrc%5Etfw">June 23, 2020</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

#これは何？
パソコンでShiftやAltを多用する作業（主にパワーポイントでの資料作りなど）をしていると、突然WindowsのIME（言語変換）のところに `ENG` と表示されてちゃんと入力できなくなることありますよね？無い？？？あります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57626/ccbf51c3-06de-5058-410e-70de32fb5589.png)
こんな感じの。 `ENG`。
こうなると、IMEをクリックして元に戻すまで、マトモに入力できません。つらい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57626/6376a9ce-cfb1-a68c-bdf6-13017de6f8dc.png)
いちいち元に戻さなきゃいけないのが面倒なので、なんとかして `ENG` にならないようにする、という記事です。

#どうやるの？
まずはWindowsのスタートメニュー上で、 **「キーボードの詳細設定」** と打って **「キーボードの詳細設定」** を開きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57626/27bd1e8e-de92-fefd-08f4-84b7458fb978.png)

キーボードの詳細設定を開いたら、 **入力言語のホットキー** をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57626/cbdfc4a4-fb22-7345-5efc-da5d065ab6e5.png)

**テキストサービスと入力言語** というウィンドウが出てくるので、 **入力言語を切り替える** をクリックして **キーシーケンスの変更** をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57626/6e4a76ef-10e7-a04d-4510-dd44e63b5337.png)

**キーシーケンスの変更** 画面で、入力言語の切り替えを **割り当てなし** に変更してOKします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57626/5e58a47f-bd92-2a12-0fbe-804a91309f2c.png)

おしまいです。もう `ENG` に悩まされることはありません。バンザイ。

#そもそも ENG の原因は？
さっきのウィンドウ（キーシーケンス）にも出てましたが、`ENG` の原因は、**左Alt＋Shiftの同時押し** でした。
パワポで図をうまくずらしたりうまく拡大縮小させるときにShiftやAltをめっちゃ使うのですが（使わない？パワポ便利機能ですよ！）、そのときに想定外に左Alt＋Shiftが押されてしまっていたわけですね。

これで忌々しい `ENG` に悩まされずに、タイピングができますね！めでたしめでたし。
VuePress でAPIを叩く時に気をつけたいこと - tihs.$ssrContext

長いこと疑問なのが、いつ VuePress は HTML 生成しているのか？ということです。

build した時に１度生成されます。しかし build して deploy すると、Theme に書き込んでおいた console.log が再度実行されています。

いまいまの理解というか、予想は、HTML, JavaScript ファイルをダウンロード後、恐らく再度 Theme が実行されて、差分があった箇所を更新する、ということをしているのかなと想定しています。

差分のある箇所というのは、例えば API からデータを取ってくるようなケースです。build 時にはわからないけど、実際にユーザがアクセスした場合は表示して欲しいです。逆に言えば、build 時には実行して欲しくないです。そういった場合は `this.$ssrContext` を使います。

```javascript
if (this.$ssrContext === undefined) {
  // ブラウザで実行して欲しい処理
}
```

この this.$ssrContext の存在は、以下の記事で初めて知りました。

> NOTE: The JSON-LD will not be shown in development build, but generated in production build.
>
> * [VuePress Add JSON-LD Structured Data (Rich Snippets) to Page](https://code.luasoftware.com/tutorials/vuepress/vuepress-add-json-structured-data-to-page/)

それまでは、なんか VuePress が build 時にワーニングを吐いてるけど、HTML を出力してくれているからヨシッ！って思っていたのですが、この条件分岐を入れることでワーニングが消えました。

いまにして思えば API と通信をしようとして弾き返されてワーニングが吐き出されていたのかなと思います。

this.$ssrContext をドキュメントに追加してよ、という issue が蹴られていたので、もしかしたら使ってはいけないプロパティなのかもしれませんが、いまは他に方法が思いつきません。

> This shouldn't be included and you should go: https://ssr.vuejs.org/en/head.html
> 
> * [build/dev env - document this.$ssrContext #420](https://github.com/vuejs/vuepress/issues/420)

場合分けするのが面倒な箇所は、２度同じことを計算させることになります。そういった手抜きをすると、結構冗長な処理なような気がしたのですが、以下の Evan You 氏のツイートを理解できてはいないのですが、この辺りの扱いは、かなり難しいそうな気配があるので、いま現在も手抜きのままでいます。

> This sounds obvious but it’s very hard to achieve with the right balance of perf gain and DX (thread)
>
> * [Evan You @youyuxi - Twitter](https://twitter.com/youyuxi/status/1274834280091389955)
【Angular】画像を読み込んで表示する

ファイルを選択して画像のプレビューを表示するサンプル
![スクリーンショット 2020-06-23 15.44.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607742/945da20d-d592-9f37-bc91-9703f80b9a1d.png)

##シンプルにinputボタン
```html
<!-- html -->
<div class="upload">
    <input type="file" accept="image/*" 
           (change)="onChangeFileInput($event)">
    <img [src]="imgSrc" alt="">
</div>
```
```typescript
import { Component, OnInit } from '@angular/core';

export class ImageUploadComponent implements OnInit {

  file: File = null;
  imgSrc: string | ArrayBuffer = "";

  constructor() { }

  ngOnInit() {}

  onChangeFileInput(event) {

    //fileが選択されていなければリセット
    if (event.target.files.length === 0) {
      this.file = null;
      this.imgSrc = "";
      return;
    }

    //ファイルの情報をfileとimgSrcに保存
    let reader = new FileReader();
    this.file = event.target.files[0];
    reader.onload = () => {
      this.imgSrc = reader.result;
    }
    reader.readAsDataURL(this.file);
  }
}
```

FileReaderについて…[MDN web docs](https://developer.mozilla.org/ja/docs/Web/API/FileReader)


##inputボタン以外をクリックして選択ウィンドウを表示したいとき
![スクリーンショット 2020-06-23 16.01.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607742/0be6d6f8-b013-e507-8276-c16747ad9e39.png)
Adivとか画像とか、input以外の要素をクリックしてウィンドウ表示させたいとき

```html
<div class="upload">
    <input 
      type="file"
      style="display: none;" <-追加
      #fileInput  <-追加
      accept="image/*"
      (change)="onChangeFileInput($event)"
    >
    <div class="div-upload" (click)="onClickFileInputButton()">アップロード</div> <-追加
    <img [src]="imgSrc" alt="">
</div>
```
```typescript
import { Component, OnInit, ViewChild, ElementRef } from '@angular/core';

export class ImageUploadComponent implements OnInit {

  @ViewChild("fileInput", { static: false }) fileInput: ElementRef; //追加
  file: File = null;
  imgSrc: string | ArrayBuffer = "";

  constructor() { }

  ngOnInit() {}

  onClickFileInputButton(): void { //追加
    this.fileInput.nativeElement.click();
  }

  onChangeFileInput(event) {
    //--- 変更なし ---
  }
}
```
ViewChildについて…[【Angular】@ViewChild / @ViewChildren を理解する【v6.x】](https://tkzo.jp/blog/angular6-view-child-view-children/)
inputは非表示にしつつ、ViewChildを使いts側からinputの操作をできるようにします。
ボタンにしたい要素をクリックした時に、inputに対しclick()を作動させてあげることで選択ウィンドウを開くことができます。
初めてのアプリ Swift UIでrealmからデータ変更があった時のUI更新

realmに保存したデータを削除した時にUIへうまく反映されない件（削除されたのに消えないDoneをクリックするとクラッシュ）、今日はコードを微調整したら新しい不具合がありました。Deleteをクリックすると、クラッシュします。

調べると、この記事を参照：https://qiita.com/chocoyama/items/af172b32f492b706c96d

なるほど。realmデータベースの中に保存したデータに変更があってもSwiftが検知できず、知らせて処理するよう書く必要がるなんだとわかりました。

Observeメソッドを使って実現できるらしいですが、自分の場合、まだうまくできませんでした。
またまた同じエラーでクラッシュ。
僕のAndroid学習参考資料

####※随時アップデート

#Google公式
[Android Developer](https://developer.android.com/index.html)
[API Reference](https://developer.android.com/reference/packages.html)
[Material Design](https://material.io/design/introduction#goals)

#おすすめサイト/本
[RayWenderRich](https://www.raywenderlich.com/)

[Androidアプリ開発 パーフェクトマスター](https://www.shuwasystem.co.jp/book/9784798041612.html)

[Android UI Cookbook for 4.0　ICS（Ice Cream Sandwich）アプリ開発術](https://www.amazon.co.jp/Android-Cookbook-ICS%EF%BC%88Ice-Cream-Sandwich%EF%BC%89%E3%82%A2%E3%83%97%E3%83%AA%E9%96%8B%E7%99%BA%E8%A1%93/dp/4844331744)

[Android Pattern Cookbook マーケットで埋もれないための差別化戦略](https://www.amazon.co.jp/Android-Pattern-Cookbook-%E3%83%9E%E3%83%BC%E3%82%B1%E3%83%83%E3%83%88%E3%81%A7%E5%9F%8B%E3%82%82%E3%82%8C%E3%81%AA%E3%81%84%E3%81%9F%E3%82%81%E3%81%AE%E5%B7%AE%E5%88%A5%E5%8C%96%E6%88%A6%E7%95%A5-%E3%81%82%E3%82%93%E3%81%96%E3%81%84%E3%82%86%E3%81%8D/dp/4844335650)
Present Modallyをdismissした時に遷移前の画面を更新する

#備忘録

ios13以降で画面遷移をPresent Modallyにした場合、dismissした時に遷移前の画面が更新されないので、対処法を残しておきます。
#対処法1

PresentationをfullScreenにする

<img width="256" alt="Screen Shot 2020-06-23 at 15.52.08.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529173/546610f4-d89b-bab4-2e45-4b575dc840ef.png">


#対処法2


```
extension 遷移前ViewControler: UIAdaptivePresentationControllerDelegate {
    func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
        tableView.reloadData()
    }
}
```

```
extension 遷移後ViewController {
    
    override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
        super.dismiss(animated: flag, completion: completion)
        guard let presentationController = presentationController else {
            return
        }
        presentationController.delegate?.presentationControllerDidDismiss?(presentationController)
    }

}
```

#最後に
初心者のため、間違っている可能性があります。
参考までによろしくお願いします。
"docker push"で"denied: requested access to the resource is denied"のエラーに遭遇したら

ググると、下記のサイトがヒットしますが…

- https://stackoverflow.com/questions/41984399/denied-requested-access-to-the-resource-is-denied-docker
- https://forums.docker.com/t/docker-push-error-requested-access-to-the-resource-is-denied/64468

いずれにも「`docker login`したらpushできる」と書いていますが、これで解決できない人が続出していて、いずれのスレッドにも終わりが見えない状況です。

この問題の解決方法ですが、**push先のディレクトリ・プロジェクトのpush権限を自分が持っていない**ことが考えられます。
私の場合は、adminからpush権限を付与してもらうことで、このエラーを解決できました。
iOSでステータスバーの背景色を変える拡張関数(Swift)

## はじめに

iOSでは、ステータスバーの背景色を単体でかんたんに変えることができません。
`UIViewController#view.backgroundColor` を指定するとステータスバーの背景色が変わりますが、同時にビュー全体の背景色も変わってしまいます。

いくつか方法はあるのですが、今回は「上左右をSuperviewに合わせ、下をSafe Areaの上に付けたビュー」を追加することで実現します。
Storyboardを作成するたびに手動でビューを追加するのは手間なので、呼び出すだけでステータスバーの背景色を変えられる拡張関数を実装しました。

## 環境

- OS：macOS Mojave 10.14.6
- Xcode：11.3.1 (11C504)
- Swift：5.1.3
- iOS：13.3

## 実装

`UIViewController` に拡張関数を追加します。

```swift:UIViewController+StatusBar.swift
import UIKit

extension UIViewController {
    private final class StatusBarView: UIView { }
    
    func setStatusBarBackgroundColor(_ color: UIColor?) {
        for subView in self.view.subviews where subView is StatusBarView {
            subView.removeFromSuperview()
        }
        guard let color = color else {
            return
        }
        let statusBarView = StatusBarView()
        statusBarView.backgroundColor = color
        self.view.addSubview(statusBarView)
        statusBarView.translatesAutoresizingMaskIntoConstraints = false
        statusBarView.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
        statusBarView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
        statusBarView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
        statusBarView.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor).isActive = true
    }
}
```

複数回呼ばれてもビューが重ならないよう、処理の最初で `StatusBarView` があったら剥がすようにしています。

## 使い方

`UIViewController` の `viewDidLoad()` で色を指定して呼び出すのみです。

```swift:FooViewController.swift
final class FooViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        configureView()
    }

    private func configureView() {
        setStatusBarBackgroundColor(.blue)
    }
}
```

ノッチの有無にかかわらず、ステータスバーの背景色が変わります。

|iPhone 8|iPhone 11 Pro Max|
|:--|:--|
|<img width="375" alt="Simulator Screen Shot - iPhone 8 - 2020-06-23 at 15.17.25.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138245/66e1209c-e25f-021c-82f0-972b6ca56ed0.png">|<img width="414" alt="Simulator Screen Shot - iPhone 11 Pro Max - 2020-06-23 at 15.27.39.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138245/64ecddf1-6c20-413d-0fc4-8093a0e77740.png">|

## 参考リンク

- https://twitter.com/hatakenokakashi/status/1271001822447063040?s=20
AtCoderBeginnerContest171復習＆まとめ（後半）

# AtCoder ABC171
2020-06-21(日)に行われたAtCoderBeginnerContest171の問題をA問題から順に考察も踏まえてまとめたものとなります．
後半ではDEの問題を扱います．[前半はこちら](https://qiita.com/takaito0423/items/d1da353c17e3acd9dd1c)．
問題は引用して記載していますが，詳しくはコンテストページの方で確認してください．
[コンテストページはこちら](https://atcoder.jp/contests/abc171)
[公式解説PDF](https://img.atcoder.jp/abc171/editorial.pdf)

## D問題　Replacing
> 問題文
> あなたは、$N$個の正整数$A_1,A_2,⋯,A_N$からなる数列$A$を持っています。
> あなたは、これから以下の操作を$Q$回、続けて行います。
>　・$i$回目の操作では、値が$B_i$である要素すべてを$C_i$に置き換えます。
> すべての$i(1 \leq i \leq Q)$に対して、$i$回目の操作が行われた後の数列$A$のすべての要素の和、$S_i$を求めてください。

毎回，和の計算をしていると時間が足りなくなってしまうと思ったので，操作ごとに差分を計算するようにしました．
数列$A$はdictで管理するようにしました．

```python:abc171d.py
n = int(input())
a_list = list(map(int, input().split()))
a_dict = {}
total = 0
for a in a_list:
    if a in a_dict:
        a_dict[a] += 1
    else:
        a_dict[a] = 1
    total += a

q = int(input())
for i in range(q):
    b, c = map(int, input().split())
    if b in a_dict:
        if c in a_dict:
            a_dict[c] += a_dict[b]
        else:
            a_dict[c] = a_dict[b]
        total -= a_dict[b] * b
        total += a_dict[b] * c
        a_dict[b] = 0
    print(total)
```

D問題までは順調に解けました．
しかし，次のE問題に躓き解けませんでした．

## E問題　Red Scarf
> 問題文
> 猫のすぬけくんが$N$(**偶数**)匹います。
> 各すぬけくんには$1,2,…,N$の番号が振られています。
> 各すぬけくんは首に赤いスカーフを巻いており、スカーフにはそのすぬけくんが一番好きな非負整数が$1$つ書き込まれています。
> すぬけくんたちは最近、整数の xor（排他的論理和）と呼ばれる演算を覚えました。
> 早速この演算を使いたくなったすぬけくんたちは、自分以外のすぬけくんのスカーフに書かれた整数の xor を計算することにしました。
> 番号$i$が振られたすぬけくんが計算した、自分以外のすぬけくんのスカーフに書かれた整数の xor が$a_i$であることが分かっています。 この情報を元に、各すぬけくんのスカーフに書かれた整数を特定してください。

4264人もE問題が解けてて，D解けた段階で2000位くらいだったのに，最終的に順位が目も当てられない結果になってしまいました．
偶数がポイントになってたんですね．
自分もノートにいろいろ式を計算したりしてみたのですが，答えを求めるための式を出せませんでした．
次はもう解けると思うので，勉強になったと割り切りたいと思います．

```python:abc171e.py
n = int(input())
a_list = list(map(int, input().split()))
y = 0
for a in a_list:
    y = y ^ a
for a in a_list:
    x = y ^ a
    print(x, end=" ")
```

F問題は，今週も忙しいので時間ができたときにでも追記できたらいいなと思ってます．

後半も最後まで読んでいただきありがとうございました．
AtCoderBeginnerContest171復習＆まとめ（前半）

# AtCoder ABC171
2020-06-21(日)に行われたAtCoderBeginnerContest171の問題をA問題から順に考察も踏まえてまとめたものとなります．
前半ではABCまでの問題を扱います．
問題は引用して記載していますが，詳しくはコンテストページの方で確認してください．
[コンテストページはこちら](https://atcoder.jp/contests/abc171)
[公式解説PDF](https://img.atcoder.jp/abc171/editorial.pdf)

## A問題　αlphabet
> 問題文
> 英大文字か英小文字のいずれか$1$文字$α$が入力されます。$α$が英大文字なら"A"、英小文字なら"a"と出力してください。

大文字か小文字か判定する方法はたくさんあるのですが，今回は```str.istitle()```を使って判定しました．

```python:abc171a.py
n = input()
if n.istitle():
    print("A")
else:
    print("a")
```

## B問題　Mix Juice
> 問題文
> ある店で$N$種類の果物、果物$1,…,N$が売られており、それぞれの価格は一個あたり$p_1,…,p_N$円です。
> この店で$K$種類の果物を一個ずつ買うとき、それらの合計価格として考えられる最小の金額を求めてください。

安いものから$k$種類の果物を購入すればいいので，価格をsortすれば簡単に解けました．

```python:abc171b.py
n, k = map(int, input().split())
p_list = list(map(int, input().split()))
p_list = sorted(p_list)
print(sum(p_list[:k]))
```

## C問題　One Quadrillion and One Dalmatians
> 問題文
> ロジャーは、彼のもとに突如現れた$1000000000000001$匹の犬をすべて飼うことを決意しました。犬たちにはもともと$1$から $1000000000000001$までの番号がふられていましたが、ロジャーは彼らに以下のルールで名前を授けました。
>　・$1,2,⋯,26$番の番号がついた犬はその順に a,b,...,z と命名されます。
>　・$27,28,29,⋯,701,702$番の番号がついた犬はその順に aa,ab,ac,...,zy,zz と命名されます。
>　・$703,704,705,⋯,18277,18278$番の番号がついた犬はその順に aaa,aab,aac,...,zzy,zzz と命名されます。
>　・$18279,18280,18281,⋯,475253,475254$番の番号がついた犬はその順に aaaa,aaab,aaac,...,zzzy,zzzz と命名されます。
>　・$475255,475256,⋯$番の番号がついた犬はその順に aaaaa,aaaab,... と命名されます。
>　・(以下省略)
> つまり、ロジャーが授けた名前を番号順に並べると:
> a,b,...,z,aa,ab,...,az,ba,bb,...,bz,...,za,zb,...,zz,aaa,aab,...,aaz,aba,abb,...,abz,...,zzz,aaaa,... のようになります。
> ロジャーはあなたに問題を出しました。
> 「番号$N$の犬の名前を答えよ。」

26進数的な考え方で解けると思って，実装したら通りました．

```python:abc171c.py
n = int(input())
n = n - 1
mozi_list = []
while True:
    k = n % 26
    n = n // 26 - 1
    chr_s = chr(97 + k)
    mozi_list.append(chr_s)
    if n == -1:
        break
for i in range(len(mozi_list)):
    print(mozi_list[len(mozi_list)-i-1], end="")
```

前半はここまでとなります．
今回，解説がとても丁寧に記述してあったので，詳しい解法はそちらを参考にしてもらえたらと思います．
前半の最後まで読んでいただきありがとうございました．

後半はDEF問題の解説となります．
[後半に続く](https://qiita.com/takaito0423/items/a76b01f1b7efcc0800de)．
個人的 Ubuntu & WSL2セットアップまとめ

# WSL2のセットアップ
https://qiita.com/momomo_rimoto/items/51d533ae9529872696ce

## GUI関係で必要なら
https://qiita.com/momomo_rimoto/items/2841f1f15d364c2377a1

# Chromeを入れる
https://qiita.com/develop/items/350f5487b4825d716d9d

```bash
sudo sh -c 'echo "deb http://dl.google.com/linux/chrome/deb/ stable main" >> 
/etc/apt/sources.list.d/google-chrome.list'
sudo wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add -
sudo apt update
sudo apt install google-chrome-stable
```

## 日本語化
wsl(2)のみ。シンボリックリンクはるという手段。
https://nakomii.hatenablog.com/entry/wsl_ubuntu

## アップデートするなら
Ubuntu共通

```bash
sudo apt update
sudo apt --only-upgrade install google-chrome-stable
```

```bash
sudo ln -s /mnt/c/Windows/Fonts /usr/share/fonts/windows
sudo fc-cache -fv
```

# GSuiteのGoogleドライブのマウント
https://qiita.com/cabbage_lettuce/items/c4544b3e5cd28caf04bc

```bash
sudo add-apt-repository ppa:alessandro-strada/ppa
sudo apt-get update
sudo apt-get install google-drive-ocamlfuse
```

```bash
-bash: add-apt-repository: コマンドが見つかりません
```
のときは

```bash
sudo apt install software-properties-common
```

認証。これまでにChromeかFirefoxなどをいれておく

```bash
google-drive-ocamlfuse
```

マウント

```bash
mkdir ~/google-drive
google-drive-ocamlfuse /home/ubuntu/google-drive
```

アンマウント

```bash
fusermount -u /home/ubuntu/google-drive
```

#Pythonを入れる
https://qiita.com/ysdyt/items/5008e607343b940b3480

```bash
git clone https://github.com/pyenv/pyenv.git ~/.pyenv

echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc
echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(pyenv init -)"' >> ~/.bashrc
source ~/.bashrc
```

(Anacondaを使うべき状況にいるので)

```bash
pyenv install anaconda3-hogehoge
```
Kotlin/JS で kotlinx.serialization を使う

Kotlin/JS + Gradle で kotlinx.serialization を使うメモ

```gradle:build.gradle
plugins {
    id 'org.jetbrains.kotlin.js' version '1.3.72'
    id 'org.jetbrains.kotlin.plugin.serialization' version '1.3.72'
}

// ...

dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib-js"
    implementation npm("kotlinx-serialization-kotlinx-serialization-runtime", "0.20.0")
    // implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.20.0"
    // ↑これだとダメ JVM用？
    testImplementation "org.jetbrains.kotlin:kotlin-test-js"
}

// ...
```
【Django】1対多の関係（ related_name,  _set.all() ）について

# はじめに
　Djangoにてモデル同士を紐づける際に用いるmodels.ForeignKey()の引数の中でrelated_nameというパラメータがあるが、いつ使われるのかが分からなかったので調べてみた。

# 前提
　今回は以下のように、CategoryモデルとPostモデルを作成して考える。

```python:apps/models.py
class Category(models.Model):
    name = models.CharField(max_length=100)
    slug = models.SlugField(unique=True)

    def __str__(self):
        return self.name

class Post(models.Model):
    category = models.ForeignKey(to=Category, on_delete=models.CASCADE)
    author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    title = models.CharField(max_length=100)
    content = models.TextField()

    def __str__(self):
        return self.title
```

　上のコードでcategoryオブジェクトを3つ、Postオブジェクトを6つ生成し、次の図の様な関係をもつとする。
<img width="800" alt="スクリーンショット 2020-06-23 14.55.56.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/646903/22be8d39-34c8-71e4-92db-98d24f36a395.png">

　以下2つの場合分けを行いそれぞれの方法を考える。

 * 二次関数（post.id=1）に紐づくcategoryを取得したい時《多→１の参照》
 * 社会（category.id=3）に紐づくpostをすべて取得したい時《1→多の参照》

## 多 → 1 への参照方法
　`オブジェクト.フィールド名`で取得可能

```
>>> post1 = Post.object.get(id=1)
>>> post1
<Post: 二次関数>
>>> post1.category
<Category: 数学>
```

## 1 → 多 への参照方法　【 _set.all() 】
　`オブジェクト.モデル名（小文字）_set.all()`で取得可能

```
>>> category3 = Category.object.get(id=3)
>>> category3
<Category: 社会>
>>> category3.post_set.all()
<QuerySet [<Post: 坂本龍馬>, <Post: 鎌倉幕府>]>
```
※ .all()の他に.filter()や.count()などを使って絞り込みやオブジェクト数をカウントしたりもできる。

## related_nameとは

* models.ForeignKeyの引数の一つで別になくても良い。
* related_nameを指定すると`モデル名（小文字）_set`に置き換えて使用可能となる。
* related_name=’posts’とすると先ほどの例では、  
`category3.post_set.all()` →→ `category3.posts.all()`  
となり、<u>より直感的に分かるようになる。</u>

#### 引数としてrelated_nameを追加
```python:apps/models.py
class Category(models.Model):
    name = models.CharField(max_length=100)
    slug = models.SlugField(unique=True)

class Post(models.Model):
    category = models.ForeignKey(to=Category, on_delete=models.CASCADE, related_name='posts') #追加
    author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    title = models.CharField(max_length=100)
    content = models.TextField()
```

#### related_nameを活用する

```
>>> category3 = Category.object.get(id=3)
>>> category3
<Category: 社会>
>>> category3.posts.all()　#変更
<QuerySet [<Post: 坂本龍馬>, <Post: 鎌倉幕府>]>　# ←結果は同じ
```
Xcode12のアップデート内容をまとめてみた。

# WWDC2020

今年中もiOS、iPadOS、MacOSなどの新しいOSバージョンと共にXcodeも12が発表されました。
早速、Xcode12のアップデート内容をまとめてみました！！

# Xcode12

WWDCでApple siliconの発表があったため、 Xcode 12 for macOS Universal Appsと言ったアプリケーションもBETA版として登場しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/470777/c52ad401-3ac7-5007-3a05-d863b6512c5f.png)


## 新機能

### ナビゲーションエリアのフォントサイズが３段階で変更できるようになった
- small
<img width="1440" alt="スクリーンショット 2020-06-25 18.12.51.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/470777/115216c8-135b-45fa-afd7-16e468dc5240.png">

- large
<img width="1440" alt="スクリーンショット 2020-06-25 18.13.02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/470777/801be04d-42fa-ee20-17c9-ec82d6c384f1.png">


### タブ表示が追加され、素早いファイルの移動が可能になった

以前にもタブ表示の機能はありましたが、新たに細かい階層でもタブ表示できるようになりました。
Optionキーを押すことで新しいタブが追加されます。
以前のタブよりもだいぶ切り替え表示されるスピードが早いので、かなり便利です。

<img width="1846" alt="スクリーンショット 2020-06-23 14.17.30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/470777/976562cd-5d1c-3159-88ea-11f48c6bd38d.png">

#### WidgetやAppClipなどの新しく登場したパッケージをサポート
iOS14やiPadOS14からのサポートになるので、早めにいじりたい方はBeta版をインストールしましょう。

#### 新規プロジェクトでLife Cycleという項目が追加
InterfaceでSwiftUIを選択するとLife Cycleで`SwiftUI App`が選択可能になります。
また、SwiftUIでの開発の仕方ががっつり変わりそうですね。

<img width="1404" alt="スクリーンショット 2020-06-23 14.53.11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/470777/bebe6c4c-e427-4eb8-0827-59880d61be5b.png">


### コード補完が高速に
毎回アップデートされていますね。
Xcode11ではSwiftUIの補完が微妙だったのでそこは期待。

### SVGがAssetのサポートに追加
やっと、正式にSVGがXcodeでサポートされましたね...
これでアイコンを追加するたびに３枚の画像を追加しなくて良くなります。

サポートOSはiOS13、iPadOS13以降です。

### ブレークポイントがドラッグ&ドロップで移動できるようになった
小さなアップデートですが、ありがたい...

### Xcodeとシミュレーターを並べて表示できるようになった

<img width="2559" alt="スクリーンショット 2020-06-23 14.41.43.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/470777/2bd1b81c-4899-010d-2015-bb439adfbaa3.png">


## Swift

### guard letのインデントが揃うようになった
```swift
guard let x = someOptional,
      let y = anotherOptional else {
  // ...
}
```

## Swift Packages

### リソースファイルをパッケージに含められるようになった
- [Bundling Resources with a Swift Package](https://developer.apple.com/documentation/swift_packages/bundling_resources_with_a_swift_package)

### バイナリファイルをパッケージに含められるようになった
ついにFirebaseなどのビルド済みフレームワークもSPM対応できそうですね。

- [Distributing Binary Frameworks as Swift Packages](https://developer.apple.com/documentation/swift_packages/distributing_binary_frameworks_as_swift_packages)

## SwiftUI

### 関数ビルダー内で`if let`や`switch`が利用可能になった
この機能はXcode11のときから付けて欲しかった...

```swift
struct ContentView: View {
    @State var username: String?

    var body: some View {
        Group {
            if let username = username {
                Text("Welcome, \(username)")
            } else {
                Image(systemName: "circle")
            }
        }
    }
}
```

## まとめ
まだ、登場したばかりのXcode12。
今回は開発者目線でバージョンアップしたとわかる箇所ピックアップしてまとめました。
MacOSのデザイン変更によりXcode全体やアイコンも変更されています。

まだまだ、正式リリースには時間があるのでBeta版がアップデートするたびにこの記事もアップデートしていこうと思っています。
読んでいただきありがとうございました。
選択されたチケットテンプレートに合わせて表示項目を変更する

# はじめに
ここ数カ月にredmineを使い始めて、少しずつカスタマイズすることが出てきたので、備忘用に残しておく。

* 「optgroup」が使われた場合、項目の値を取得する方法は「find("option:selected")」
* ViewCustomizePluginに「Type: JavaScript」って書いてあるけど、実際の記法はほぼ「jQuery」

# 前提条件
### 環境
* Redmine 3.4.11.stable
* view_customize 2.6.0
* redmine_issue_templates 0.2.2-dev

### 項目の内容
|項目|形式|内容|
|---|---|---|
|selector|チケットテンプレート|hoge, piyo|
|issue_custom_field_values_1|カスタムフィールド|hoge|
|issue_custom_field_values_2|カスタムフィールド|piyo|

# サンプルコード
~~~ java
/*
サンプルチケット編集画面
Path pattern: /issues/new
挿入位置：チケット入力欄の下
Type: JavaScript
*/
$(function(){
	hideAll();
	const selector1="hoge";
	const selector2="piyo";
	var selVal='';
	$("#issue_template").change(function(){
		selVal = $('#issue_template').find("option:selected").val();
// 「項目名」を取得したい場合は「text」を使う
//		selVal = $('#issue_template').find("option:selected").text();
		if(selVal == selector1) {
			showSelector1();
		} else if(selVal == selector2) {
			showSelector2();
		} else {
			hideAll();
		}
	});
});

function hideAll() {
	$('#issue_custom_field_values_1').parent().hide();
	$('#issue_custom_field_values_2').parent().hide();
}
function showSelector1() {
	$('#issue_custom_field_values_1').parent().show();
	$('#issue_custom_field_values_2').parent().hide();
};  	
function showSelector2() {
	$('#issue_custom_field_values_1').parent().hide();
	$('#issue_custom_field_values_2').parent().show();
};
~~~

初期表示時は全カスタムフィールドを非表示化。
チケットテンプレートの選択肢に合わせて、カスタムフィールドを表示させる。
カスタムフィールドの項目が多くなった場合に備えて、処理は関数化した。

# 参考
* jQuery でコンボボックスの選択されたオプションのテキストを取得する場合、optgroup を使っている場合は子孫選択でないと取得されないというお話 / find(子孫) と children(直近) の違い  
https://logicalerror.seesaa.net/article/422682236.html
初級エンジニアがHaskellを学ぶモチベーション

## この記事ってなに？

エンジニアとしてもう少しで1年となる私がQiitaデビューをしてみたい！から書いてます。
`TypeScript` `JavaScript`を触ってきた私が、表現力を身に着けるためにも関数型言語を学んでいく備忘録がわり。

## でモチベーションって？

表現力向上。

### 表現力とは？

`何を` `どのファイルに` `どう書くか` あたりをエンジニアの表現力と考えています。
私がエンジニアになって一番苦労しているのは `何を` `どのファイルに`書くのかです。

良く遭遇して悩むのが、

- 共通化できる処理はひとまとめにして、適切な場所に置く -> 適切な場所ってどこ？？？
- 再利用しないような処理もファイルが大きくなってきたら可読性を担保するためにファイルを分ける -> どのくらいのサイズで大きいと認識する？？？
- 関数や変数、ファイル名の命名がイケてない -> イケてないってなに???

といった抽象的な概念です。

アーキテクチャの勉強をしようにも、DDDも相当抽象的で私には全く理解できませんでした。

エンジニアリングの最適解は移り変わりの早いこの業界的には抽象的な概念として扱うほうが理にかなっているのかもしれません。

私の大好きな漫画 `王様達のヴァイキング`から引用すると `ハッカーはアーティストですよ`とのこと。

では初級エンジニアがどのように `何を` `どのファイルに`といった表現力を伸ばせるのか?
考えてもわからないので、まずは色々な言語、アーキテクチャに触れてみるべきかなと思いました。 `don't think, feel`です。

### そこでHaskell

Haskellのドキュメントをみてもわけがわからない。
モナド?カリー化？なにそれ

これだけわからないものに体当たりすれば何か得られるかも！
そんなモチベーションでやっていきます

## やっていこうと思っていること

個人プロジェクトで作成しているAPIをHaskellでかけたらと思っています。
そこでのchipsをちょこちょこ掲載していきたいと思います。
Pythonで salesforce API(Bulk API)経由でデータ取得しBigQueryにロードする

# 背景
Pythonを使ってSalesforceからデータを取得したい。
今回は [simple_salesforce](https://github.com/simple-salesforce/simple-salesforce) というライブラリを使用し、[Salsesorce APIのBulkAPI](https://developer.salesforce.com/docs/atlas.ja-jp.api_asynch.meta/api_asynch/asynch_api_intro.htm) を使ってデータを取得し、それをBigQueryにロードする。

# 認証周り
以下の3つを用意する

- username
- password
- security_token
  - security_tokenは管理画面の [私のセキュリティトークンのリセット] で発行されるものを用意する
     - 参考: [Step 3: Salesforce のセキュリティトークンの確認方法](https://support.miitel.jp/hc/ja/articles/360030487511-Step-3-Salesforce-%E3%81%AE%E3%82%BB%E3%82%AD%E3%83%A5%E3%83%AA%E3%83%86%E3%82%A3%E3%83%88%E3%83%BC%E3%82%AF%E3%83%B3%E3%81%AE%E7%A2%BA%E8%AA%8D%E6%96%B9%E6%B3%95)

# 実装例

```py

from google.cloud import bigquery
from simple_salesforce import Salesforce
import json
import os


class SalesforceAPI:
    def __init__(self, job_type):
        self.sf = Salesforce(
            username='USERNAME',
            password='PASSWORD',
            security_token='SECURITY_TOKEN'
        )

    def execute(self):
        self.dl_file()
        self.load_to_bq()

    def dl_file(self):
        res = self.sf.bulk.TABLE_NAME.query('SELECT column1, column2 FROM TABLE_NAME')
        with open('dl_file_name', mode='w') as f:
            for d in res:
                f.write(json.dumps(d, ensure_ascii=False) + "\n") # 日本語の文字化け対応

    def load_to_bq(self):
        client = bigquery.Client('project')
        filename = 'file_name'
        dataset_id = 'dataset'
        dataset_ref = client.dataset(dataset_id)
        table_id = 'table_name'
        table_ref = dataset_ref.table(table_id)

        job_config = bigquery.LoadJobConfig()
        job_config.source_format = bigquery.SourceFormat.NEWLINE_DELIMITED_JSON
        job_config.autodetect = True # 必要ならばschemaを指定

        with open(filename, "rb") as source_file:
            job = client.load_table_from_file(
                source_file, table_ref, job_config=job_config
            )
            job.result()
            print("Loaded {} rows into {}:{}.".format(
                job.output_rows, dataset_id, table_id))
```

# 参考
[俺が考えた最強のSOQL実行ツールを作りました](https://qiita.com/atskimura/items/b06a5ad4dc9e1905c29f)

- ここで紹介されているSOQL実行ツールが便利
- DL用のSOQLの作成はこれを使うといい
PHP 「??」 クエスチョンマークが二つの演算子

Googleで調べようとして少し時間がかかってしまったので、覚書として記す。

受け取ったパラメータがあるかないかを調べて、あるならそのままで、
無ければ何かしらの初期値を入れる処理というのは頻繁に書く。
そういった状況で使える演算子があることを知った。

以下「PHP マニュアル」より引用

```
<?php
// Null 合体演算子の使用例
$action = $_POST['action'] ?? 'default';

// 上の文は、この if/else 文と同じ意味です
if (isset($_POST['action'])) {
    $action = $_POST['action'];
} else {
    $action = 'default';
}

?>
```

今回の件、大事なのはマニュアルにきちんと辿り着くことだと思ったので、
「PHP 演算子」で検索→比較演算子→「??」でサイト内検索が正しい手順だったか。

参考：
PHP マニュアル 言語リファレンス 演算子
https://www.php.net/manual/ja/language.operators.comparison.php#language.operators.comparison.coalesce
【PHP】？？（クエスチョンマーク二つ）って何・・・？
https://tektektech.com/php-double-question/
rJavaをR3.6環境のLinuxにインストールする。

rJavaをR3.6環境のlinux にインストールする
というか、そういうDockerImageを作るDockerfileを書く必要があったが、
結構エラーがでて詰まった。
ネットを探してもドンピシャがなかなか出てこなかったで、メモ。

```
#rJavaインストールのための準備
RUN apt-get update && apt-get install -y openjdk-8-jdk
RUN R CMD javareconf

# install packages（DB接続用追加）
RUN R -e "install.packages(c(\
'rJava' \
), repos='https://cloud.r-project.org/')"
```
AWSにおける最適なDB選択指針

#本整理の目的
特に頭を使わず、DBならRDSでしょと考えてきた基盤エンジニア（5年目）が適材適所なDB選択を体系的に学びなおしたのでまとめる。
参考は2019年のAWS Summitのセッションより。
https://www.youtube.com/watch?v=h1r8AzOdlqo

# DBの歴史[要件の変化(2000年~)]
RDBMSだけでは様々な要件に対応できなくなり、KVSなど特性を持ったDBが誕生した。

|項目|従来要件|新要件|
|:--|:--:|:--:|
|ユーザ|~10万|100万+|
|データ量|~TB|PB-EB|
|範囲|社内|グローバル|
|パフォーマンス|秒|マイクロ秒|

# AWSにおけるデータカテゴリと選択指針
グラフ化や台帳といったカテゴリもあるが、本整理の範囲外。

|データカテゴリ|Relational|Key-value|Document|In-memory|
|:--|:--:|:--:|:--:|:--:|
|AWS サービス|RDS|DynamoDB|DocumentDB|ElastiCache|
|特徴|参照結合性、ACIDトランザクション|高スループット、低レイテンシー|ドキュメント保存し、高速クエリ|超低レイテンシ|
|選択指針|汎用的なDB、特に要件がなければ…|高スケーラビリティ/数ミリ秒のレスポンスタイム/シンプルなクエリでよい|スキーマを決められないデータの格納|ミリ秒未満のレスポンスタイム/キャッシュ利用したい|
いろんなフィボナッチ数列の関数作ってみた（Ruby）

## 単純な再帰で書く
絶対おそい（nが0or1の深さになるまで再帰するため）。

```rb
def fib(n)
    return n if n == 0 || n == 1
    return fib(n - 1) + fib(n - 2)
end
```


## ちょっと工夫した再帰
再帰だが、やってることはfor文と大して変わらない。
ただ再帰関数なので、超でかいnが渡されたらスタックオーバーフローするかも？

```rb
def fib(n, a, b)
    return a if n == 0
    return fib(n - 1, b, a + b)
end
```


## forで書く
再帰じゃないのでスタックオーバーフローが発生しない…はず。
分割代入使うとキレイに書ける。
分割代入をすこれ。

```rb
def fib(n)
    a, b = 0, 1
    n.times.each { a, b = b, a + b }
    a
end
```



## 動的計画法（メモ化）で書く
TODO 誰か書いてください。
クリックしたところがおしゃれに光るナビゲーションバー 8日目【WEBサイトを作る30日チャレンジ】

# ナビゲーションバーをクリックした箇所にスライドさせてグラデーションをかける

■ポイント
・CSSでグラデーションの処理（linear-gradientを使用）
・JavaScriptのdocument.querySelectorで要素を取得
・offsetLeftでクリックした対象要素の左からの幅をpx単位で（左）へ移動させる
・offsetWidthでクリックした対象要素のWidth（幅）を決定
（説明がわかりずらいかもしれません・・・検証ツールで幅の変化等を見て頂くとわかりやすいです）
offsetLeftの説明はこちらのサイト様を参考にいたしました（わかりやすかった、ありがとうございます）
https://syncer.jp/javascript-reference/element/offsetleft
念の為こちらも載せときます↓
https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetLeft
・addEventListenerでクリックされた場所に反応するように指定
・そしてトップバーだけじゃ寂しいのでビデオ背景載せてます

■出来たサイトの動き

![ezgif.com-video-to-gif (5).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540462/e5387fe1-261c-c776-395b-9731e4b2aa31.gif)

■コード

HTML

```html

<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>グラデーションナビバー</title>
    <link rel="stylesheet" href="30_8.css">
</head>
<body>
    <div class="nav-top">
        <nav>
            <div id="marker"></div>
            <a href="#">Home</a>
            <a href="#">Company</a>
            <a href="#">Work</a>
            <a href="#">Sample</a>
            <a href="#">Team</a>
            <a href="#">Contact</a>
        </nav>
    </div>
    <script type="text/javascript">
        const marker = document.querySelector('#marker');
        const item = document.querySelectorAll('nav a');

        function indicator(e){
            marker.style.left = e.offsetLeft+"px";
            marker.style.width = e.offsetWidth+"px";
        }

        item.forEach(link => {
            link.addEventListener('click', (e)=>{
                indicator(e.target);
            })
        })
    </script>

<video src="goomalling-storm.mp4" loop="" autoplay="" muted=""  width="100%" class="bgv"></video>
</body>
</html>

```

CSS

```css

*
{
	margin: 0;
	padding: 0;
	box-sizing: border-box;
}
.nav-top
{
	display: flex;
	justify-content: center;
	background-color:black;
}
nav
{
	position: relative;
	display: flex;
}
nav a
{
	position: relative;
	margin: 10px 20px;
	padding: 5px;
	font-size: 2em;
	color: white;
	text-decoration: none;
}
nav #marker
{
	position: absolute;
	left: 0;
	height: 100%;
	width: 0;
	opacity: 0.5;
	background: linear-gradient(
	black,
	rgb(128, 0, 113),
	blue,
	black);
	bottom: 0px;
	transition: 0.5s;
	border-radius: 4px;
}
```

■苦労した点
　・querySelectorとgetElementByIdの使い分け

■疑問点とやりたかったこと
　・レスポンシブ最適化までいけませんでした。
　・レスポンシブ最適化のため、少しいじりましたが、今の知識レベルでは時間がかかりそうだったため、タイミングを改めて実装してみようと思います。


以上となります。

ここは違う、ここはこうしたほうが良いかも？といったものございましたらご指摘いただけますと幸いです。
最後までみていただき、ありがとうございます。
laravelを勉強してて詰まったこと

#目的
この記事の目的は、Laravel開発の備忘録を作成することです。主に、うまくいかなかったことを書きます。自分のような初学者の助けになればいいなと思います。

#Databaseのmigrateが上手くいかない
php artisan migrateコマンドを入力すると以下のエラーが出力されました。
![migrate.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/372182/99587523-29fa-6fde-010e-14729b3cbe29.png)

デフォルトで設定されている「laravel」なんていう名前のDatabeseは無いよって言われているみたいです。

###解決策
composerでlaravel開発のためのディレクトリを作成したときに、「.env」っていう名前のファイルができていますよね。![migrate2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/372182/66d3c656-4822-c04e-c576-507dcb5a6983.png)

「.env」ファイルのDatabaseの設定を編集します。
![migrate23png.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/372182/642fd2e0-29cf-d4da-855c-921126f48e7c.png)

12行目にHomestead.yamlファイルに自分の使いたいDatabseの名前を書いて、14行目はパスワードを書きます。デフォルトでは何も書かれていいないです。
Databaseのパスワードはデフォルトでは「secret」に設定されていると思います。（この記事を書く前にいろいろいじってしまっているのでもしかしたら違うかも...）

###解決！
こんな画面がでれば解決です！
![migrate3png.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/372182/549580f9-0e73-3e4c-9c39-f970d16cb3f2.png)
Azure Synapse Analytics の共有メタデータ テーブルでサポートしているSparkテーブルの形式について

## 注意点

本情報は、2020年6月23日時点での情報であり、最新情報は、Microsoftドキュメントを参照してください。



## 概要

Qiitaの[別記事](https://qiita.com/ryoma-nagata/items/300ae6df431642bc9919)にて記述した本件ですが、下記記事についてややわかりにくい表現があり、誤解した同僚がいたので備忘録

>   Azure Synapse Analytics では、さまざまなワークスペース計算エンジンが、Spark プール (プレビュー) と SQL オンデマンド エンジン (プレビュー) の間でデータベースとテーブルを共有できます。

引用元：[Azure Synapse Analytics の共有メタデータ](https://docs.microsoft.com/ja-jp/azure/synapse-analytics/metadata/overview)



## 誤解した点

ドキュメントにて、下記の記載があっため、

>   SQL エンジンを使用して Parquet 形式でデータを格納するマネージドおよび外部 Spark テーブルのみが共有されます。

引用元：[SQL での Spark テーブルの公開](https://docs.microsoft.com/ja-jp/azure/synapse-analytics/metadata/table#exposing-a-spark-table-in-sql)



下記のように解釈されたようです。

-   Parquet 形式でデータを格納するマネージドテーブル
-   外部 Spark テーブル



ただ、英語のドキュメントに下記の記載があるため、

>    only shares managed and external Spark tables that store their data in Parquet format with the SQL engines. 

引用元：[Exposing a Spark table in SQL](https://docs.microsoft.com/en-us/azure/synapse-analytics/metadata/table#exposing-a-spark-table-in-sql)



正しくは下記の解釈となります。句読点があれば違ったかもしれませんね

-   Parquet 形式でデータを格納するマネージドテーブル
-   Parquet 形式でデータを格納する外部 Spark テーブル



## 所感

とりあえずdocsのほうはプルリクなげましたが、英語版のドキュメントも合わせて確認すべきであると再認識しました。
ターミナルからAWS EC2へ〜シャットダウンまで

こんにちは
今回からマークダウンも併用していこうと思います。
スライドの利点とマークダウンの利点をうまく使い分けしていきたいです。

今回も"触ってみた"系の記事なんですが、
**macターミナルからAWS EC2へ入って、起動中のEC2をシャットダウンする**
までの一連にトライしたので、そちらを記します。
今まで通り、自分がつまずいた箇所を明記しておきたいので、
そちらは***斜体太字***で記すようにしていきます。
また本記事は書籍`AWSをはじめよう　～AWSによる環境構築を1から10まで～`を参考にしています。

## EC2サーバを立てる＠AWSマネジメントコンソール
一連の作業は済んでますので、ざっくり手順ベースで振り返ります。
### 手順
1. IAMユーザでAWSマネジメントコンソールにサインイン
2. 「サービス」から「EC2」を選択
3. 「インスタンスの作成」を押下
4. 「Amazon Linux」を選択
5. 「t2.micro」を選択（無料利用枠を活用するので）
6. EBS/タグは活用しないのでスキップし、「SG」の設定
7. 「起動」
8. キーペアの作成（1度切り！）
9. 「Name」からインスタンスに命名
10. 「インスタンスの状態」が「runnning」であることを確認

上記の手順自体は恙無く進みましたが、気になっているのは***6.「SG」関連***です。
今回はすぐにシャットダウンするEC2インスタンスでしたので特に設定せず、
<img width="1491" alt="スクリーンショット 2020-06-23 11.50.32.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630283/749b9932-4805-5256-20e3-fb9ec5dd30d1.png">
上記メッセージが出てくる状態。SLA次第だとは思いますが、
***具体的に
・セキュリティの詳細設定の方法
・どんなセキュリティレベルをどういうサービスに設定するのか
を判断できるようになる必要があります。今後の課題です。***

あと***インスタンタイプ***も同じく、とりあえずt系（無料枠ですし）選んでますが
***なぜそのインスタンスタイプを選択するのかの判断ができる***よう、別途深堀ります。



## macターミナルからEC2に入る〜サーバ停止
こちらも手順ベースで。
### 手順
1. macにてターミナル起動
2. chmodで、キーペアファイルに対する読み書き制限の厳格化 `chmod 600 ~/(キーペアファイル格納場所)`
3. 対象EC2インスタンスをIPアドレスで指定しつつ「-iオプション」で利用する鍵を指定 `ssh ec2-user@(IPアドレス) -i ~/(キーペアファイル格納場所)`
4. 初回サーバ接続時の信頼性確認　`yes`を返す
5. シャットダウンコマンドの実行　`sudo shutdown -h now`
6. AWSマネジメントコンソールから、状態の「stop」を確認

<img width="601" alt="スクリーンショット 2020-06-23 13.47.33.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630283/697ace92-5cc8-512a-4c48-1ec29df31c49.png">
実際の画面がこちら。
ちょっと打鍵ミスしてやり直しましたけど手順自体は問題なく進みました。
課題になったのは***コマンド慣れしていないのでsudoや-i、-hなどを調べながら実施したこと***です。
`sudo　： rootユーザに成らなくてもrootユーザの権限で処理を実行できるコマンド`
オプションは調査中。その辺がわからないと自在にはできないかな。。。

##　あとがき
シャットダウンまでの一連の流れ自体で（打鍵ミス以外は）詰まるところもなく、流れました。
しかし、大事なのは途中***斜体太字***で書いているような「なぜ」の部分だと思いますので、
その辺り、もう少し掘っていきたいと思います。
mongooseを使って、dbを一括で消す方法

# 概要
```zsh
❯ mongo
MongoDB shell version v4.0.3
connecting to: mongodb://127.0.0.1:27017
WARNING: No implicit session: Logical Sessions are only supported on server versions 3.6 and greater.
Implicit session: dummy session
MongoDB server version: 3.4.20
WARNING: shell and server versions do not match
Server has startup warnings:
2020-06-23T01:59:36.690+0000 I STORAGE  [initandlisten]
2020-06-23T01:59:36.690+0000 I STORAGE  [initandlisten] ** WARNING: Using the XFS filesystem is strongly recommended with the WiredTiger storage engine
2020-06-23T01:59:36.690+0000 I STORAGE  [initandlisten] **          See http://dochub.mongodb.org/core/prodnotes-filesystem
2020-06-23T01:59:39.381+0000 I CONTROL  [initandlisten]
2020-06-23T01:59:39.381+0000 I CONTROL  [initandlisten] ** WARNING: Access control is not enabled for the database.
2020-06-23T01:59:39.381+0000 I CONTROL  [initandlisten] **          Read and write access to data and configuration is unrestricted.
2020-06-23T01:59:39.381+0000 I CONTROL  [initandlisten]
> show dbs
admin                                            0.000GB
my_db                                            0.881GB
my_db_test_4e95cefc_26c9_42ea_801e_872f86090ade  0.000GB
my_db_test_5e95cefc_26c9_42ea_801e_872f86090ade  0.000GB
my_db_test_6e95cefc_26c9_42ea_801e_872f86090ade  0.000GB
local                                            0.000GB
```

このように、 `my_db_hogehoge` のように、testを実行するたびにmongoにdbが作られてしまっていて困っていました。
この`my_db_hogehoge`を一括で削除するコマンドを作りました

# 実装
## 環境
```zsh
❯ node --version
v10.16.3
```

```zsh
❯ npm --version
6.9.0
```

```package.json
{
  "dependencies": {
    "mongodb": "2.2.10",
    "mongoose": "5.2.10",
  },
  "devDependencies": {
    "@types/mongodb": "2.2.x",
    "@types/mongoose": "5.2.x",
  },
}
```

## コード
```removeTestDB.js
'use strict';

const mongoose = require('mongoose');
const { execSync } = require('child_process');

const dbName = 'my_db_test';
mongoose.connect('mongodb://localhost:27017').then(async () => {
  mongoose.connection.db.admin().command({ listDatabases: 1 }, (err, result) => {
    if (err) {
      console.log(err);
      throw err;
    }
    const testDBs = result.databases.map(d => d.name).filter(d => d.includes(dbName));
    testDBs.forEach(d => {
      execSync(`mongo ${d} --eval "db.dropDatabase()"`);
      console.log(`${d} is deleted`);
    });
    console.log(`all ${dbName} is deleted`);
    mongoose.disconnect();
  });
}).catch(err => {
  console.log(err);
  throw err;
});
```

1. `mongoose.connection.db.admin().command({ listDatabases: 1 } (err, result) => {})`
    * こちらで、dbのリストを取得。(`show dbs` と同じ効果)
1. `execSync(mongo ${d} --eval "db.dropDatabase()");`
    * こちらで、`my_db_test`の名前を含むdbを削除 


# おわりに
限定的かつ実用性はあまりなさそうなコードですが、メモがてら。
`execSync`で実行しているのが少し微妙な気がするので、`mongoose`の機能で出来るならやりたいですね。