OmniAICreator/Qiita-1.07M huggingface dataset:
【AWS】EC2インスタンスの認証方式

#プログラミング勉強日記
2021年5月17日

#EC2インスタンスの認証
　EC2インスタンスを立ち上げるときにキーペアを作成して、PEMファイルをダウンロードできる。メモ帳などのテキストでキーペアを見ることができ、キーペアはアルファベットや数字の羅列になっていて大量の文字がランダムに生成されている。キーペアは、作成したEC2インスタンスのサーバー内にアクセスするときに使う。

　作成したEC2インスタンスが自分のものであるという証明をするために、PEMという鍵を使用する。キーペアなので、EC2インスタンス側にもついになる鍵を持っている。(南京錠のように鍵と鍵穴があるイメージ)
　この認証方式を<b>公開鍵認証方式</b>という基本的な暗号方式。ダウンロードする鍵が秘密鍵で、EC2側に設定されているものが公開鍵になっている。EC2側に設定されている方は、AWS側で渡されていて公開されている(特に秘密にしていない・AWSと共有している)ので、公開鍵。ダウンロードするPEMファイルは、ダウンロードしたユーザしかしらないので秘密鍵となっている。秘密鍵は名前の通り、むやみに渡したりコピーしたりするのは良くない。

秘密鍵：自分自身が所有していて、そのデータやサーバーの領域が自分のものだと証明するための鍵
公開鍵：秘密鍵を利用する対象となる相手に共有することを目的として公開された鍵

　EC2のPEMキー(秘密鍵)1つで複数のEC2インスタンス用の鍵として利用することもできる。

#まとめ
　EC2インスタンスを起動するときにPEMという形式のファイルをダウンロードする。これを認証用のキーペアとして利用することでEC2インスタンスにアクセスできる。
　EC2インスタンスへの認証方式を公開鍵認証方式という。ダウンロードしたPEMは秘密鍵、EC2インスタンスには公開鍵が設定されている。
GASで特定の文字以降の文字列を削除する方法

gasで特定の文字以降が不要になったので、削除してしまいました。

```gas
const a = "abcdefghijk";
const b = "de";
const c = a.slice(0,a.indexOf(b))
```
sliceというメソッドを用いて、deの文字が見つかった場合にはそれ以降の文字は必要ないので削除します。
結果、"abc"を取得することができました。

文字列の、0から indexOfで合致した文字列の番号まで取得し削除する。という方法ですね。

これを使えば反対に、"de"より前の文字だけ削除することも可能かと思いますね。
gasは結構使うので、pythonとかで書かしてくれないかなぁ〜。


参考：
文字列削除する方法
https://teratail.com/questions/200062
indexof
https://tonari-it.com/gas-array-indexof-lastindexof/
slice
https://blog.8basetech.com/google-apps-script/gas-substring/
１カ月前から統計検定準一級を目指すお話[随時更新]

## モチベーション

一度は志してもいたデータサイエンス欲がむらむらと湧き出したから。
今の会社でもそういう役職の人がちらほらと出現し始め、準備運動はしときたいから。
単純に興味。統計や機械学習はそこそこ興味あるから。

この記事書いてるのは、単なる備忘録。



## バックグラウンド

大学院では金融工学を専攻。金融に関する解析・数学はある程度履修済み（と、信じたい）。時系列解析とかが得意（と、信じたい）。
1級は若気の至りでB3くらいで受験し、爆死。在学中に2級までは取得済み。
会社入ってからはよくわからないITをやってるので、数学はご無沙汰。



## 参考教材

- [公式サイト](https://www.toukei-kentei.jp/about/grade1semi/)

  最新の過去問とか見れる

- 公式テキスト

  1級の時に買って何言ってるのかわからんかったから排除

  ~~（ちなみにすこぶる評判は悪い）~~

- [統計学実践ワークブック](https://www.amazon.co.jp/%E6%97%A5%E6%9C%AC%E7%B5%B1%E8%A8%88%E5%AD%A6%E4%BC%9A%E5%85%AC%E5%BC%8F%E8%AA%8D%E5%AE%9A-%E7%B5%B1%E8%A8%88%E6%A4%9C%E5%AE%9A%E6%BA%961%E7%B4%9A%E5%AF%BE%E5%BF%9C-%E7%B5%B1%E8%A8%88%E5%AD%A6%E5%AE%9F%E8%B7%B5%E3%83%AF%E3%83%BC%E3%82%AF%E3%83%96%E3%83%83%E3%82%AF-%E6%97%A5%E6%9C%AC%E7%B5%B1%E8%A8%88%E5%AD%A6%E4%BC%9A/dp/478060852X/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&dchild=1&keywords=%E6%9C%AC%E7%B5%B1%E8%A8%88%E5%AD%A6%E4%BC%9A%E5%85%AC%E5%BC%8F%E8%AA%8D%E5%AE%9A+%E7%B5%B1%E8%A8%88%E6%A4%9C%E5%AE%9A%E6%BA%961%E7%B4%9A%E5%AF%BE%E5%BF%9C+%E7%B5%B1%E8%A8%88%E5%AD%A6%E5%AE%9F%E8%B7%B5%E3%83%AF%E3%83%BC%E3%82%AF%E3%83%96%E3%83%83%E3%82%AF&qid=1621252944&s=books&sr=1-1)

  学生時代にはなかったこのワークブックが良いという評判を聞き、これと過去問のみで挑む

## 更新履歴

なんか書いたらここにも張っていく所存。
とりあえず、今日（2021/5/17）からなので試験日（2021/6/20）までだいたい1か月がんばろ
【初心者でもわかる】某スケッチブック風の交互に2色ずつ背景色を指定する方法

#どうも7noteです。4等分して背景色を交互に2色ずつ指定する方法

某有名スケッチブック風の交互に背景色を指定して、少し斜めにしたものを作ります。

![sample.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661092/30de2146-07ca-363e-d067-fa394d165b4b.png)

## ソース

```inex.html
<div class="box">
  <div class="sketchbook"></div>
</div>
```

```style.css
.box {
  width: 100px;     /* 幅を100pxに指定 */
  height: 150px;    /* 高さを150pxに指定 */
  overflow: hidden; /* はみ出た部分を非表示にする */
}

.box .sketchbook {
  width: 200%;  /* 幅を倍のサイズにする */
  height: 200%; /* 高さを倍のサイズにする */
  background-image: linear-gradient(transparent 50%, #FCA428 50%),
    linear-gradient(#FCA428 50%, transparent 50%); /* 黄色の部分を背景に指定 */
  background-repeat: no-repeat; /* 繰り返しはさせない */
  background-size: 50% 100%;    /* 背景の幅を50%、高さを100%に指定 */
  background-position: 0 0, 100% 100%; /* 背景の位置表示を指定 */
  background-color: #0D1E19; /* 黒い(緑)背景を指定 */
  transform: translate(-25%, -20%) rotate(30deg); /* 中心位置を調整 ＆ 30度回転 */
}
```

![sample.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661092/d23ad532-96c8-1e1e-0b2a-071610badde2.png)


## まとめ

なかなかきれいに作れます。
サイト全体の背景として使うことも可能です。

![sample2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661092/3ded2710-3f5d-e429-6ba3-de20d0a78f7e.png)

見やすいかどうかは、、、気にしないほうがいいですね。
色合い調整すればきれいに見えるかもしれません。

#### おそまつ！
~ Qiitaで毎日投稿中!! ~
[【初心者向け】WEB制作のちょいテク詰め合わせ](https://qiita.com/7note)
調べ物と学習が捗る！オススメChrome拡張機能5選


あなたのブラウザ、拡張機能を使ってもっと便利にしてみませんか？
下記の拡張機能を使えば、毎日のブラウジングが捗ること間違いなしです！

1. [Video Speed Controller](#1video-speed-controller)
1. [Google翻訳](#2google翻訳)
1. [GetTabInfo](#3gettabinfo)
1. [Pasty](#4pasty)
1. [Adblock Plus](#5adblock-plus)
1. [拡張機能のショートカット設定](#おまけ-拡張機能のショートカット設定)

## 1.Video Speed Controller
[インストールページ](https://chrome.google.com/webstore/detail/video-speed-controller/nffaoalbilbmmfgbnbgppjihopabppdk?hl=ja)

動画の再生速度を簡単に切り替えることができるようになります。
ブラウザ上で再生できるほとんどの動画に対応していて、3倍速でも4倍速でも可能です。

そう、YouTubeの2倍速も限界突破できます。
動画学習が増えている今、自分にあった動画速度に調整することは大事ですよね。


⚙️設定
　1. 拡張機能アイコンをクリックし「Settings」を選択
　2. 任意のスピード調節機能に好きなキーを割り当てて「Save」
　3. ブラウザを更新

⚙️使い方
　動画再生中に設定したキーを押下する（下の画像は自分の設定例です）
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630487/e027bdd2-acc1-e9f1-65e9-cea4d0935493.png" width="800">

なお、YouTube視聴は[元から設定されているショートカット](https://support.google.com/youtube/answer/7631406?hl=ja)と組み合わせて使用するとなお捗ります。



## 2.Google翻訳
[インストールページ](https://chrome.google.com/webstore/detail/google-translate/aapbdbdomjkkjkaonfhkkikfgjllcleb?hl=ja)

拡張機能としてのGoogle翻訳です。
毎回翻訳ページを出さなくとも、ボタン1つで翻訳できるのでお手軽です。

英語が出てきたときに訳すスピードが格段に上がります。

⚙️使い方
　翻訳したい単語や文章をドラッグして拡張機能アイコンをクリック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630487/7f47202e-2c67-1ffe-e656-256ab88636f8.gif" width="800">


## 3.GetTabInfo
[インストールページ](https://chrome.google.com/webstore/detail/gettabinfo/iadhcoaabobddcebhmheikmbcjcigjhc?hl=ja)

現在Chrome上で開いているすべてのタブの、タイトルとURLをクリップボードに一気に保存してくれます。
どのようにクリップボードに保存するかも細かく設定できます。

- 後から整理したいので開いているURLを一旦全部保存しておきたい
- URLを保存するときに名前をいちいち設定するのが面倒だ

そんな方にオススメです。

後述の[Pasty](#4pasty)とのコンボが最高です。

⚙️使い方
　拡張機能アイコンをクリック。保存時の動きと設定は下記をご参考ください。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630487/53d21c15-044c-bdc8-4025-8c2ff287732d.gif" width="800">
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630487/f1e5bb83-8947-a6d6-6089-98edcde91b9d.png" width="800">


## 4.Pasty
[インストールページ](https://chrome.google.com/webstore/detail/pasty/hdjihnnclpjhfdbbinmgoiehhoehhlgf?hl=ja)

クリップボードにあるURLを、タブ別で一気に全部開いてくれます。

前述の[Get Tab Info](#3gettabinfo)と一緒に使用するためにあるような拡張機能です。
Get Tab Infoで保存したURLを、Pastyで一気に戻す。これが便利なのです。


⚙️使い方
　拡張機能アイコンをクリック。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630487/e43b4413-e6ac-b919-bd14-6eda2011632d.gif" width="800">




## 5.Adblock Plus
[インストールページ](https://chrome.google.com/webstore/detail/adblock-plus-free-ad-bloc/cfhdojbkjhnklbpkdaibdccddilifddb?hl=ja)

あらゆる広告をブロックできます。

YouTubeの動画再生中の広告も無効にできます。

ブロックが強力すぎて、Webページによっては表示できない部分がありますが、
そういったときは拡張機能アイコンをクリックし、そのサイトのブロックだけOFFにすればOKです。

⚙️使い方
　インストールするだけでOK


## おまけ 拡張機能のショートカット設定
クリックして使用するタイプの拡張機能はショートカットキーを割り当てて使用すると便利です！

⚙️設定方法
　1. ブラウザ右上のパズルマークから「拡張機能を管理」 をクリック
　2. 左上のハンバーガーメニュー(3本線)から「キーボードショートカット」クリック
　3. ショートカットを設定したい拡張機能の鉛筆マークを押下してキー入力
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630487/48a9b6cc-b714-61cc-d9aa-6edbbfc4b8b2.gif" width="800">

例えば「Google翻訳」の拡張機能に「Command + E」のショートカットキーを当てると、
「翻訳したい英文ドラッグ → Command + E」で実行できるようになります。


## おわりに

最後まで読んでいただきありがとうございます！
【React】リストのレンダリングでmap()を使う際にkeyが必要な理由

Reactでリストを表示する際、map()メソッドを使うときにkeyがないと以下のようなWarningがでます。
![スクリーンショット 2021-05-16 20.01.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569054/e30bbf25-2246-caba-d114-b2aa3133b9d0.png)
keyがないリストの例

```jsx
const ImageList = (props) => {
  const images = props.images.map((image) => {
    return (
      <img src={image.urls.regular} alt={image.description} /> //keyがない
    );
  });
  return <div>{images}</div>;
};
```

keyに適当な値を追加すればWarningは消えるのですが、なぜkeyが必要であるのかについては正直わかっていませんでした。
ということで、今回はReactでリストをつくる際に各要素にkeyが必要な理由についてまとめました。

Reactの理解が曖昧だと感じている方々の参考になれば幸いです。

#結論
Reactでリストをつくる際に各要素にkeyが必要な理由は、**keyがないとパフォーマンスに影響がでるため**です。

#説明
以下のように、複数アイテムのリストに新しいアイテムを追加したとき、どのようにレンダリングされるかを考えてみます。

既存のアイテム(アムロ、カミーユ、ジュドー)についてはすでにレンダリングされているため、DOMにすでに存在しています。
ここに新しいアイテム(バナージ)を追加したとき、React内部で新しくレンダリングするリストと既存(変更前)のDOMの比較を行いますが、**keyがないとどれが同じ要素であるのかどうかを判断することができません。**
そのため、**既存のアイテムを含む全ての要素をレンダリングすることになってしまいます。**
![スクリーンショット 2021-05-17 8.02.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569054/960fc6bd-ddc8-97c6-472f-445b39853e56.png)

一方、リストの各要素にユニークなkeyを加えてあげると、既存DOMと要素を比較する際に、**keyによって同じ要素であるかどうかを判断する事ができるようになります。**

したがって、**新しく追加した差分の要素のみをレンダリングするだけですむようになり、パフォーマンスが向上します。**
![スクリーンショット 2021-05-17 8.07.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569054/3cac5b5d-1578-3e6c-9b4d-d8a8d69ceac7.png)

#おわりに
Reactの表示パフォーマンスについても何個か記事を書いているので、参考になれば幸いです。・

https://qiita.com/suzuki0430/items/9c3c4c4f3b25da5fcdd6

https://qiita.com/suzuki0430/items/445ac1b38fa7ef383864

https://qiita.com/suzuki0430/items/8c242222c7903aa2a52d

#参考資料

https://watablogtravel.com/react-key-props/

https://qiita.com/official-events/b9ad63394fa2635dfca9
ActionSheetの実装の仕方[Xcode/Storyboard]

アプリを使っていると、カメラかアルバムを選択するシートをみたことがあるかと思います。
Xcode/Storyboardでどのように実装するかを簡単に実装して記事にしました。

#環境
・Mac Book Pro(macOS:BigSur)
・Xcode(ver:12.5)

#実装例
![Unknown-2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864623/445906f7-8783-d3ea-f41c-49e5dc866492.gif)

#コード例
```ruby:ViewController.swift
class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
    }


    @IBAction func showAlert(_ sender: Any) {
        
        let alertController = UIAlertController(title: "タイトル", message: "メッセージ", preferredStyle: .actionSheet)
        
        let action1 = UIAlertAction(title: "タイトル1", style: .default) { alert in
            print("Action1")
        }
        
        let action2 = UIAlertAction(title: "タイトル2", style: .default) { (alert) in
            print("Action2")
        }
        
        let action3 = UIAlertAction(title: "キャンセル", style: .cancel, handler: nil)
        
        alertController.addAction(action1)
        alertController.addAction(action2)
        alertController.addAction(action3)
        self.present(alertController, animated: true, completion: nil)
    }
}
```
data-URIのjpeg画像データをbase64でデコードする

画像読み込みを素早くするために、ブラウザ側でデコードする data-URI を使った画像を、ブラウザではなく ruby でデコードして画像ファイルにする。

```ruby
require 'base64'

bURL = 'data:image/jpg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD//gA7Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcgSl.......長い....もっと長い' #jpegのバイナリ

start = bURL.index(',') + 1
x = Base64.decode64 bURL[start .. -1]
k = 1
File.open("%04d.jpg" % k, 'wb') do |f|
    f.write x
end
```

結果

0001.jpg

のちほど python で同じことする場合を比較したい。

Rf.
https://developer.mozilla.org/ja/docs/Web/HTTP/Basics_of_HTTP/Data_URIs
はじめてのDjango〜既存の管理画面でDBを操作できるようにする〜

# はじめに
動画サイトなどで、いくつかアプリケーションを作成して慣れてきたので、オリジナルアプリを作成して色々勉強している最中です。一人だとここでつまずくなという部分を備忘録として残していきます。

#管理画面をDBで扱えるようにする
Djangoには、既存の管理画面が用意されており、自分でDBやユーザーを設定することで、簡単に管理画面内でデータの作成・編集・削除が可能るので、最初に設定していきます。

### 事前準備　(DBを作成する)
アプリケーションの作成にあたり、どんなDBを作成するか構想ができたら、まずはDBを作成していきます。DBの作成するにあたり、以下の記事を参考にしてデータ型を選定しました。ありがたや。ちなみに今回は、DBをSQLiteを使用して作成しました。

Django: モデルフィールドリファレンスの一覧
https://qiita.com/nachashin/items/f768f0d437e0042dd4b3

注意点ですが、DateField()を特に設定せずにマイグレーションすると、以下のとおりターミナルから色々言われます。これは、このままだとnullを受け付けられないので、どうしたいか1、2の中から選んでくださいというもの。特に問題なければ、1(デフォルト値の設定して、nullの場合は、任意の値を設定。)を選びます。

```terminal:ターミナル
You are trying to add a non-nullable field 'A項目' to xxxmodel without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
 1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
 2) Quit, and let me add a default in models.py
Select an option: 
```

その後、1を選んだ場合は、以下のとおり、nullの場合の値をどうするのか聞かれるので、今日の日付を設定する場合は、"timezone.now"と答えれば良いです。

```terminal:ターミナル
Please enter the default value now, as valid Python
The datetime and django.utils.timezone modules are available, so you can do e.g. timezone.now
Type 'exit' to exit this prompt 
```

### 管理画面に入るためのスーパーユーザーを作成する

http://127.0.0.1:8000/admin/ で管理画面のログイン画面に行くことは可能ですが、ログインするためのユーザーが作成していないため、今のままではログインできません。
そこで、ターミナルで以下のとおり打ってスーパーユーザーを作成します。ユーザー名、メールアドレス、パスワードの設定するように指示があるので、指示に従って入力すれば、作成されます。
※スーパーユーザーとは、システム管理に関するすべての権限をもつアカウントです。

```terminal:ターミナル
python manage.py createsuperuser
```

再度、http://127.0.0.1:8000/admin/ に入って、ログインして管理画面に入れば、以下のとおりに作成したDBを作成するためのメニューが表示されます。
ここまでくれば、管理画面のとおりに操作すれば簡単に追加•変更•削除は簡単に行えます。

![スクリーンショット 2021-05-17 20.30.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1226672/868b88e8-a926-3f7c-ee9a-da4bce8a0d17.png)

### おまけ

今の表示だと、idがタイトルになっているため、見分けにくい状態になっています。
※idは、DBを作成したタイミングで自動で項目に追加されます。

![スクリーンショット 2021-05-17 20.36.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1226672/5fe0ef5e-f1ca-e2ba-48c4-3d0748acb992.png)


そこで、以下のとおりにモデルクラスに以下の関数を設定すると、タイトルを変えることができます。

```python:models.py
def __str__(self):
        # タイトルを表示する。
        return self.●●(タイトルに表示したい項目)
```
![スクリーンショット 2021-05-17 20.46.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1226672/01bc7338-f50c-775c-7822-cd629c97c438.png)

## 参考資料

今回は、Udemyの以下の講座を参考にさせていただきました！
いつも助かっています！ありがとうございます。

【徹底的に解説！】Djangoの基礎をマスターして、3つのアプリを作ろう！
https://www.udemy.com/course/django-3app/
PHP 参照による変数への代入を自分的に理解してみた

# 目的

- PHPの参照による変数への代入が自分の中で理解に苦しんだので今一度わかりやすい方法で考えてみる（誰にでもわかる方法がいまいちわからなかったのでメモ的にまとめる）

# 情報

- 下記のサービスを用いてソースコードの動作を確認した
    - [https://paiza.io/ja](https://paiza.io/ja)

# 公式ドキュメントの記載

- PHPの公式ドキュメントの下記のページに参照による変数への代入の内容が記載されている。
    - [https://www.php.net/manual/ja/language.variables.basics.php](https://www.php.net/manual/ja/language.variables.basics.php)
- 下記のように記載されている。
    - `PHP には、変数に値の代入を行う別の方法も存在します。それは、 参照による代入 です。 この場合、新規の変数は元の変数を参照するだけです。 (言いかえると、元の変数の"エイリアスを作る"または元の変数を"指す") 新規の変数への代入は、元の変数に影響し、その逆も同様となります。 `

        ```php
        <?php
        $foo = 'Bob';              // 値'Bob'を$fooに代入する。
        $bar = &$foo;              // $fooを$barにより参照
        $bar = "My name is $bar";  // $barを変更...
        echo $bar;
        echo $foo;                 // $fooも変更される。
        ?>
        ```

    - 上記を実行すると下記のように出力される。

        ```
        My name is BobMy name is Bob
        ```

- 上記の内容は自分では理解しているんだけど何故か毎回、「参照の代入ってどういうことだっけ？？」ってなる。

# 自分なりの解釈

- 参照を用いた変数への代入は「任意のワードとかエクセルとかのファイルのショートカットアイコンをデスクトップに作る」感じと理解した。
- 先に記載したソースを使ってどういうことか説明する。
    - 下記の処理は変数の定義である。これをワードとかエクセルとかのファイルを作った時と考える。

        ```php
        $foo = 'Bob';
        ```

    - 下記の処理は参照を用いて値の代入を行っている。これをワードとかエクセルとかのファイルのショートカットをデスクトップに作成した時と考える。

        ```php
        $bar = &$foo;
        ```

    - 下記の処理は変数の値を用いて作成した文字列を自身時格納している。これは先に作成したショートカットからワードとかエクセルとかのファイルを開いて編集を加えた状態と考える。

        ```php
        $bar = "My name is $bar";
        ```

    - 下記の処理は変数の値を用いて作成した文字列を出力している。これは先に作成したショートカットからワードとかエクセルとかのファイルをショートカットを使って開き内部を閲覧している状態と考える。

        ```php
        echo $bar;
        ```

    - 下記の処理は参照を用いて代入した元の変数を出力している。これは先に作成したショートカットからワードとかエクセルとかのファイルを当該ファイルが格納されているフォルダまで移動して開き内部を閲覧している状態と考える。

         ```php
        echo $foo;
        ```
GitLabのCI/CDで作成されたArtifactsを削除する方法

# GitLabのCI/CDで作成されたArtifactsを削除する方法

## きっかけ
GitLabのCI/CD機能を利用すると、ビルド時に作成した実行ファイルやテスト結果等をArtifacts(成果物)として保存することが出来ます
ただ、この保存されたArtifactsって、どうやって削除されるのか気になったので調べた所、自動削除と手動削除の２つの方法があったので、本記事に記載します。

### 自動削除方法
.gitlab-ci.ymlファイル内のexpire_inパラメータで保存期間を指定することで、一定期間後に自動削除する。

```.gitlab-ci.yml
job:
  artifacts:
    expire_in: 1 week
    ^^^^^^^^^^^^^^^^^^
```

※指定しない場合には、GitLabインスタンス側で設定された期間(デフォルトでは30日間)保存されるようです。 

 https://docs.gitlab.com/ee/user/admin_area/settings/continuous_integration.html#default-artifacts-expiration


### 手動削除
CICDのjob結果画面から、ゴミ箱アイコンをクリックすることで削除することができる。

1. CI/CD->pipelineから、削除したいjobを選択
![スクリーンショット 2021-05-17 204135.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262207/08a93c25-b0aa-f025-7ee1-94c989faf156.png)

2. ゴミ箱アイコンをクリック
![スクリーンショット 2021-05-17 205108.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262207/a34fcf65-ce9d-cd58-97cd-b9c98f4f3a83.png)


3. jobの実行結果ログと共に、右側のDownloadが削除される
![スクリーンショット 2021-05-17 204733.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262207/3be4c888-983b-028e-3a64-3b7c599a8e7d.png)
ERP とは

## 勉強前イメージ

udemyで見てなんの略かわからなかったから調べる

## 調査

### ERP とは

Enterprise Resources Planning の略で、直訳すると企業資源計画。
ヒト・モノ・カネ・情報は、企業資源を指し、それらを一元管理し有効活用する考え方のことです。
最近では財務会計、生産管理、販売管理など基幹業務のサポートを行う業務システムのことをERPシステムということがあります。

### 元々の由来

元々企業活動で 会計、人事、生産、物流、販売の業務の管理は部門ごとに行っていましたが
企業全体の流れを見ると、それらの業務はすべてリンクしています。
ここで管理を行っているとデータの連携や入力の手間がかかっており間違いも起きやすかったので、
業務管理を連携させて効率的に運用を行っていこうとしたのがERPになります。

### 基幹システムとの違い

- 基幹システム

基幹システムは主要な業務を支えるシステムのことです。
業務ごとにそれぞれ独立したシステムで、異なる業務(部署)とのやり取りを行う際は連携が必要になります。

イメージとしては、以下になります。
それぞれDBを持っており、データのやり取りを行う際は連携が必要です。

![1# ERP とは - diagrams.net - Google Chrome 2021-05-17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129517/17a0f7d4-35bd-2599-634a-b875dfdaa9fc.png)

- ERP

ERPはイメージとしては基幹システムを一元管理を行うことが出来ます。

![2# ERP とは - diagrams.net - Google Chrome 2021-05-17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129517/685e515b-4727-c371-7809-8e600419701b.png)


## 勉強後イメージ

基幹システムとか聞いたことあったけどそもそもよくわかってなかったし、
ERPとかそもそもって感じだったけど、雰囲気わかったと思う。
問題文わからんのは難しい。

## 参考

- [ERPとは何かイマイチわからない人向け【ERP超入門ガイド】](https://www.oro.com/zac/blog/erp_guideline/)
- [ERPとは？基幹システムとの違いやERPパッケージを解説](https://www.grandit.jp/erp/)
Bootstrap4でボタンの見た目を文字リンクに合わせる

## 概要
Bootstrap4でボタンの見た目を文字リンクと同じにしたい場合がある。
定義済みクラス「btn-link」だけでは文字配置などがボタンのままなので、全体を文字リンクに合わせる方法を考えた。

## 実装方法
[Bootstrapの公式ドキュメント](https://getbootstrap.jp/docs/4.5/components/buttons/)が提示している「btn」と「btn-link」に加え、以下の3つのクラスを適用する。

```index.html
<button type="button" class="btn btn-link p-0 border-0 align-baseline">Link</button>
```

追加したクラスの効果は以下の通り。

| クラス名       | 効果                           | 備考                     |
|:---------------|:-------------------------------|:-------------------------|
| p-0            | paddingをゼロにする            | -                        |
| border-0       | 枠線を消す                     | 透明な1pxの線がある      |
| align-baseline | vertical-alignをbaselineにする | そのままだとmiddleになる |
2回目の　vuecli　環境構築

(npm install)→　たぶんしなくていい


インストール

```
npm install -g vue-cli
```

２回目以降はここから行う

プロジェクトの名前を付けて（今回はcompany）実際に作成する

```
vue init webpack company
```

ディレクトリを移動

```
cd company
```

ルーターをインストール

```
npm install vue-router
```

起動

```
npm run dev
```

毎回間違えて
npm install -g vue-cli
をしていたので、これを忘れないための備忘録
【AWS IAM】MFA認証の設定方法

# はじめに
本記事では「Google Authenticator」という認証アプリをiPhoneにインストールし、IAMユーザーにMFA認証を設定する手順を紹介します。
※Androidでも基本操作は同じですが、アプリ側の画面や表示に異なる点があるかもしれませんので、ご留意ください。

- **MFA認証とは**
Multi-Factor Authentication（多要素認証）のこと。
パスワード以外の要素を用いることで、セキュリティを高める認証方法です。

# 手順
1.MFAデバイスとして使用するiPhoneに「Google Authenticator」をインストールしておく
（アプリのインストール方法については本記事では割愛します。）

2.AWSマネジメントコンソールにサインイン、IAMの管理画面にアクセスし、MFA認証を設定したいユーザー名をクリック
![スクリーンショット (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494752/bf543c91-2b49-a3d4-4a0a-8122b7df3f49.png)

3.「認証情報」タブをクリック、「MFAデバイスの割り当て」欄にある「管理」をクリック
![スクリーンショット (2)_LI.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494752/65ae214e-7e90-9ad2-54fb-ed64d3afb630.jpeg)

4.「仮想MFAデバイス」を選択、「続行」をクリック
![スクリーンショット (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494752/6a24f2bd-4e5c-0e73-91df-a35b1fc0414e.png)

5.「QRコードの表示」をクリックし、QRコードを表示させる
![スクリーンショット (7).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494752/315d037c-cf02-2067-9dd2-91920246b2c9.png)

6.項番1でインストールした「Google Authenticator」を起動し、右下の「＋」マークをタップ
![20210517_065011002_iOS.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494752/8d59a9ed-b3a0-7594-6a13-1e14ac68a88b.jpeg)


7.「QRコードをスキャン」をタップ、項番5のQRコードを読み取る
![20210517_065011003_iOS.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494752/d1292283-4889-987e-d9ce-53417f39c14a.jpeg)


8.「Google Authenticator」に表示された6桁の数字をMFAコード1に入力、6桁の数字が変わるのを待ち（30秒毎に更新されます）MFAコード2に入力、「MFAの割り当て」をクリック
![スクリーンショット (8).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494752/ea458054-5e27-01e1-7e4c-76b1ec8a9a64.png)

9.以下の画面が表示されるのを確認、「閉じる」をクリック
![スクリーンショット (6).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494752/0a9fcb2e-3694-02a7-d633-9ffabd61d2df.png)

設定は以上です。

次回ログイン時から、パスワード入力後にMFAコードの入力が求められるようになります。
ちょっとした手順でアカウントのセキュリティを高められるので、ぜひ設定してみて下さい！
生体認証失敗時の「パスワードを入力」の選択肢を非表示にしたい

生体認証はこのような記事を参考に実装ができましたが、セキュリティ要件的にパスコードでの突破を無効にしたいという要望がありました。

https://qiita.com/teco_akaike/items/6b0363f8669717d980b1

パスコード無効自体は `.evaluatePolicy` を `.deviceOwnerAuthenticationWithBiometrics` に指定することで簡単に指定可能ですが、生体認証に失敗した後に「パスワードを入力」というアラートが出てしまい、ちぐはぐな状態となってしまいます。

その場合,このように `.localizedFallbackTitle` に空文字を指定することで生体認証失敗時のアラートでキャンセルボタンのみが表示されるようになりました。

```swift
let context = LAContext()
//パスコードの選択肢を表示させない
context.localizedFallbackTitle = ""
```


※ nilを指定するとダメでした。
`context.localizedFallbackTitle = nil`
3分 GitHub Actions

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107158/eaae3193-28b3-167d-0654-6da1a7cc4ac5.png)
[**GitHub Actions**](https://github.co.jp/features/actions) のワークフローを実行するために、
必要な準備は、[**GitHub**](https://github.co.jp/) リポジトリの作成だけです。

早速、基本的な動きをする
ワークフローを作成してみましょう。

今回のサンプルは、**GitHub Actions** が

- いつ、どこで自動実行されるのか
- どのようにリポジトリを操作するのか

を示しています。

## 最初のワークフロー作成
GitHub リポジトリから `.github/workflows` 
ディレクトリ以下に、[github-actions-demo.yml](https://gist.github.com/sk9tokyo/e19e0b5135a96931a8312dd0d32e01c4) という
設定ファイルを作成します。
![github-actions-demo.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107158/796ce3b8-b1f7-fe73-a028-74230c5f92f7.png)
ページ最下部までスクロールし、
`Create a new branch`を選択後、**Propose new file ( commit )** します。
![commit-new-file.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107158/cc802858-e646-0559-d4a9-68bca3815bee.png)

ワークフローファイル（[github-actions-demo.yml](https://gist.github.com/sk9tokyo/e19e0b5135a96931a8312dd0d32e01c4)）が
リポジトリのブランチに commit されると、**GitHub Actions** の
ワークフローが、自動的に実行されます。

## ワークフローの結果確認
**GitHub** リポジトリのメインページに移動し、
`Actions` タブをクリックします。
![actions.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107158/1f8b9660-3b6e-4b12-2fc3-7404bbceadd1.png)
左メニューから、自動実行されたワークフローを選択し、
メインコンテンツのワークフロー実行リストから、対象を選択します。
→ `Add GitHub Actions example`
![add-github-actions-example.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107158/81d737e8-55ee-a9b9-e410-7170743bb2f8.png)
ジョブ一覧から、`Explore-GitHub-Actions` をクリックします。
![Explorer-GitHub-Actions.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107158/510f1575-70c7-2095-2490-20e6976db8b4.png)
それぞれのプロセスの実行経過が、ログで確認できます。
各ステップを展開すると、より詳細情報が表示されます。
![Explore-GitHub-Actions.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107158/6001fbfc-2b92-6712-9b87-4762bfd962d1.png)
AWSアカウント間でRoleを引き渡す方法(assume Role)

#アカウントAの管理者ロールをアカウントBで引き受ける（assume)する方法
roleをassumeするとアカウントBからアカウントAへのリソースにアクセスすることができます。

基本的なやり方は、こちらを参考にします。

https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/tutorial_cross-account-with-roles.html

主な流れとしては

1.アカウントAの管理者がアカウントBがassumeするロールを作成

2.アカウントBにログインして、ロールの切り替えを行う。

の2ステップです。

#手順
アカウントAでアカウントBがassumeするロールを作成します。

1.IAMのAWSコンソール画面よりロールの作成を選択します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/659469/464e7408-3d3c-b656-45bc-144b5f2c8205.png)

2.別のAWSアカウントを選択しロールを作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/659469/f712e41d-7db9-c4ad-d6a3-c2f8890d5604.png)


この後は、アカウントBのIDを入力してアカウントBがassumeするロールを作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/659469/5638f05e-39ee-3591-a877-39d42c67af6c.png)

アカウントBのユーザーがロールの切り替えを行う際にこのリンクを使用できます。

#追記
アカウントAで作成したロールの信頼関係に、アカウントBのIAMユーザーarnを直接追加するだけと、アカウントB側では特に何も設定せずにロールの切り替えができる場合とできない場合がありました。下記のようなポリシーをアカウントB側でroleをassumeしたいユーザーが属しているユーザーグループのpermissionに追加すると確実です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/659469/c7182ca0-983b-8e5c-d5b5-53ddde8929db.png)



#補足(terraformで環境変数を使用してassumeroleでデプロイを行う方法）
以下が参考になりました。

https://stackoverflow.com/questions/55128348/execute-terraform-apply-with-aws-assume-role
iOSでAzure Storageを利用する方法

#何の記事？

iOSでAzure Storageとデータをやり取りするための紐付け方法です。
操作がやや煩雑なので、次するときのための備忘録です。

#開発環境
XCode 12.5

#方法

Azureの公式ドキュメントに従ってやります。
https://github.com/Azure/azure-storage-ios

## Cocoa Podsのインストール
ターミナルを起動して以下を入力していきます。

1  **ruby gemを最新にする**

```
sudo gem update --system
```

2  **Cocoapodsのインストール**
Cocoapodsは、swiftからObjectCのライブラリを使用するためのツールだそうです。

```
sudo gem install cocoapods
```

3  **Cocoapodsのセットアップ**

```
pod setup
```

これで準備ができました！

## Pod fileの作成
1  **Xcodeのプロジェクトファイルがあるフォルダのパスをコピー**
![スクリーンショット 2021-05-17 18.47.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620139/f382bf7b-ce9b-acbb-55a5-18d7b7c904d5.png)

2 **ターミナル上で該当するフォルダに移動**

```
cd /Users/***/Xcode/CorneaApp3
```

3  **ポッドファイルを作成**

```
pod init
```

4 **ファイルの中身を確認**

```
vi Podfile
```

こんな感じで表示されます。
iを押すと編集モードになります。（後にXCode上で編集しても可）

```java
# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'

target 'CorneaApp3' do
  # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
  use_frameworks!

  # Pods for CorneaAppp3
end
```

5 **公式ドキュメントに従ってpodfileを書き換える**

```java
# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'

target 'CorneaApp3' do
  # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
  use_frameworks!

  # Pods for CorneaApp3
  pod 'AZSClient'

end
```

入力が終わったら「esc」で編集モード終了。
「:wq」で保存。

7 **ライブラリのインストール**

```
pod install
```

8 **念の為アップデート**

```
pod update
```

##Bridging-Header.hファイルの作成
プロジェクトファイルの直下で、New File> Header Fileとして、ヘッダーファイルを作成。Bridging-Header.hと名前を付けます。

Bridging-Header.hに、以下の内容を書き込みます。

```java
// Include the following import statement to use blob APIs.
#import <AZSClient/AZSClient.h>
```

プロジェクトファイルのBuild Settingsから、Swift Compiler-Generalの項目を探します。上のタブをAllにしないと出てこないので注意。
"Objective-C Bridging Header"という項目の横をクリックして、Bridging-Header.hと書き込みます。

![スクリーンショット 2021-05-17 19.44.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620139/c4edfe2a-0df6-8768-4bf4-35260094065d.png)

#最後に

これで設定は終わりです。読み書きのサンプルコードは[公式のドキュメント](https://github.com/Azure/azure-storage-ios)をご参照下さい。
gemを使ったタグ付け機能の実装

##はじめに
今回はacts-as-taggable-onというgemを使用しました。
その実装過程を残します。

##導入

```ruby:Gemfile
gem 'acts-as-taggable-on'
```

bundle installするとマイグレーションファイルがいくつか自動生成されるので、
次にrails db:migrateを行うとエラーが出ます。

```ruby:
Mysql2::Error: Cannot drop index 'index_taggings_on_tag_id': needed in a foreign key constraint: DROP INDEX `index_taggings_on_tag_id` ON `taggings`
ActiveRecord::StatementInvalid: Mysql2::Error: Cannot drop index 'index_taggings_on_tag_id': needed in a foreign key constraint: DROP INDEX `index_taggings_on_tag_id` ON `taggings`
```
調べるとこれはgem自体の問題で、作成者が修正してない状態なのだとか。
ざっくり概要としては外部キーを設定しているにも関わらず、外部キーを削除せずにインデックスを削除しようとしているためエラーが出ているようです。

GitHubのissuesに不具合報告に修正案がありました。

```ruby:add_missing_unique_indices.acts_as_taggable_on_engine.rb
remove_index ActsAsTaggableOn.taggings_table, :tag_id if index_exists?(ActsAsTaggableOn.taggings_table, :tag_id) #削除
if index_exists?(ActsAsTaggableOn.taggings_table, :tag_id) #追加
  remove_foreign_key :taggings, :tags                      #追加
  remove_index ActsAsTaggableOn.taggings_table, :tag_id    #追加
end                                                        #追加 
```

これで通ったと思いきや今度はArgumentErrorが出ます。
しかしこれは一度目のmigrate実行時に最初のファイルだけ読み込んでいたからのようです。
全てrollbackをして、再度migrateを実行するとついに導入完了しました。
正直ここが一番時間かかった...笑

##モデル
続いてアソシエーションです。

```ruby:room.rb
acts_as_taggable   # acts_as_taggable_on :tags の省略
```

##コントローラー
ここでは2点。
１・登録のためにストロングパラメーターに追加
２・表示のために紐づくものを取得

```ruby:rooms_controller.rb
 def show
    @room = Room.find(params[:id])
    @tags = @room.tag_counts_on(:tags)  #追加
  end

  private
  def room_params
    params.require(:room).permit(:title, :psid, :tag_list, :member_id, :text).merge(user_id: current_user.id)  #追加
  end
```
tag_counts_onはgemに備わっているメソッドで、タグ一覧を取得できます。
今回はアソシエーションで@roomに紐づくタグを取得しています。

##ビュー
, (デフォルト)で区切ると、複数タグに分割してくれる。

```ruby:new.html.erb
<%= form.text_field :tag_list, value: @room.tag_list.join(',') %>
```

tag_listは配列なので、each文で取り出して表示する。

```ruby:show.html.erb
<% @tags.each do |tag| %>
  <%= "#{tag.name}(#{tag.taggings_count})" %>
<% end %>
```

##さいごに
今後はUIを整えたり、検索機能なども実装したいと思います。
普段何気なく使っている機能も、
いざ自分でやると大変なんだと常々思い知らされます...
teratermで本番環境とテスト環境の色を分ける方法 

##はじめに
teratermで作業をしているとき、今は本番環境なのかテスト環境なのかがひと目で分かるように、色を変えたい。

##参考にした記事
 [Tera Term マクロ、ログイン先指定で 自動ログインと背景色変更](http://qiita.com/backgroundcolor/items/df2ed5d40e8960e72ee4)
（こちらでは、マクロによる自動ログインをしていますが、当記事ではそこまではしてないです）

##概要
 + teratermのテスト環境設定ファイルと本番環境設定ファイルを作ります。
 + teratermのショートカットに、設定ファイルを紐付けます。

##手順
###テスト環境
インストールしたteratermを立ち上げます。
適当なサーバーに接続します。（画面表示を確認するためです）
上のメニューから、「設定」「ウィンドウ」を選んで、「カラー」の色を設定します。
「OK」ボタンを押すと、表示が変わるので、好みの色にします。
上のメニューから、「設定」「設定の保存」を選びます。（※これをしないと設定したものが消えてなくなります！！！）
保存ダイアログが出てくるので、名前を「TEST.INI」にして保存します。

「C:\Program Files (x86)\teraterm」にある「ttermpro.exe」のショートカットを任意の場所に作成します。
ショートカットを右クリックして、「プロパティ」を選びます。
「リンク先」の記述を以下のように変えます。
　「"[インストールフォルダ]\ttermpro.exe" /F=TEST.INI」
　※筆者の場合：「"C:\Program Files (x86)\teraterm\ttermpro.exe" /F=TEST.INI」

これで、このショートカットでteratermを開くとテスト環境設定のteratermが立ち上がってきます。

###本番環境
同様の手順で、「HONBAN.INI」を作成して保存する。
ショートカットのリンク先を「"[インストールフォルダ]\ttermpro.exe" /F=HONBAN.INI」にする。

##その他の対策
ショートカットのアイコンを変更しています。
「プロパティ」「アイコンの変更」から設定可能。

##注意点
 + テスト環境の設定でも本番につなぐことは普通にできます。
 + まちがえて接続したときは、設定ファイルの履歴を整理しています。
WINE 6.0 で Vulkan ray tracing を動かすメモ

## 背景

Linux メインで Vulkan ray tracing 開発している.

Windows でも動作するようにしたい(そのうちデバッグで Visual Studio 使いたいとか,  Visual Studio + NVSight とかでパフォーマンス解析できるように)

しかし Windows で開発するのに Windows 機立ち上げたりとか RDP ログインしてとかめんどい...

Linux だけで Vulkan ray tracing 開発完結したい.

## 環境

もともとそれなりに Vulkan 動きますが, wine 6.0 あたりでよりきちんと Vulkan サポートされたっぽいです.

* Ubuntu 20.04 x64 64bit
* Wine 6.0
  * `winecfg` で Windows バージョン 10 に設定 
* GPU: NVIDIA A6000(driver version 465.19) (or KHR ray tracing 拡張対応している GPU)

で動作確認しました.

### vulkaninfo

まずは vulkaninfo.exe 動かして環境みてみます.

```
...
        VK_KHR_pipeline_library                   : extension revision 1
        VK_KHR_push_descriptor                    : extension revision 2
        VK_KHR_ray_query                          : extension revision 1
        VK_KHR_ray_tracing_pipeline               : extension revision 1
        VK_KHR_relaxed_block_layout               : extension revision 1
        VK_KHR_sampler_mirror_clamp_to_edge       : extension revision 3
...
```

raytrace 拡張あります!

ただ vulkaninfo.exe は完走せずに途中で `00f4:fixme:console:GetConsoleProcessList ` で stuck してしまいました.

Sascha 先生の Vulkan サンプル動かしてみます.

https://github.com/SaschaWillems/Vulkan

llvm-mingw or clang-cl あたりで Linux クロスコンパイルするのが理想ですが, めんどそうなのでとりあえずビルドは Windows(Visual Studio)でやって, ファイルだけ Linux にコピって動かしました.

<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Running <a href="https://twitter.com/SaschaWillems2?ref_src=twsrc%5Etfw">@SaschaWillems2</a> &#39;s super awesome Win64 Vulkan ray tracing example through WINE 6.0 + Linux! 🎉🎉🎉🎉🎉🎉😍😍😍😍😍😍🥳🥳🥳🥳🥳 It works much well and runs fast!(no perf loss) Win64 Vulkan ray tracing development on pure Linux for the win!!!! 💪💪💪💪💪💪💪💪💪💪💪💪 <a href="https://t.co/a4Jip3sQ6v">pic.twitter.com/a4Jip3sQ6v</a></p>&mdash; Syoyo Fujita 🌸 レイトラ ® 🐯 3 周年 🎉 (@syoyo) <a href="https://twitter.com/syoyo/status/1394243000021049347?ref_src=twsrc%5Etfw">May 17, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> 

Voila!

(想定通り) Wine で動かすことによるパフォーマンスの低下は特にありませんでした.


Happy Vulkan ray tracing development!

## TODO

* [ ] llvm-mingw, clang-cl で Linux クロスコンパイルする仕組みを確立する(Vulkan API だけ使う場合は C API で特に考慮することはないのだが, Vulkan-loaders(インターフェイスは C だが内部実装は C++) など, C++(STL) を使う周辺のライブラリと組み合わせるときに考慮が必要.
ActiveAdmin の定義済みコールバックを使う際の注意点 ~ 保存に失敗しても after_save は実行される ~

## 前置き

ActiveAdminの定義済みコールバックに関しては以下の記事がわかりやすいです。
（参考にさせていただきました、ありがとうございます :bow: ）

https://qiita.com/SakaiYuki/items/c579f2a4578f4e878849

## 何が起きたか

### 状況

ActiveAdminにてデータを保存したあとに特定の処理を実行したかった。

```rb
ActiveAdmin.register User do
  after_save do |user|
    # 保存後に実行したい処理
  end
end
```

これで良さそう...？

### 問題

`after_save` 内の処理が、**バリデーションに引っかかり実際には保存されなかった場合にも実行される。**
`after_create` など他のコールバックも同様です。

## なぜなのか

ActiveSupport::Callback の `after_save` の場合、バリデーションに引っかかり保存できなかった場合には実行されません。
そのため、上記の仕様が不自然に（勝手に）感じました。

しかし、上記の参考記事やActiveAdminソース内にも記述がありますが、ActiveSupport のコールバックを使用している訳ではありません。
つまり、本件は完全に ActiveAdmin 独自の仕様のようです。

詳しくは ActiveAdmin のソースを見てみましょう。

https://github.com/activeadmin/activeadmin/blob/master/lib/active_admin/callbacks.rb

## 解決策

いろいろ方法はあると思いますが、私は以下のようにしました。


```rb
ActiveAdmin.register User do
  after_save do |user|
    if user.persisted?
      # 保存後に実行したい処理
    end
  end
end
```
AWS IoT Core 初級ハンズオンを実施してみて。

[AWS IOT CORE 初級ハンズオン](https://aws-iot-core-for-beginners.workshop.aws/)の感想

## 実施前に
- AWSの各種サービスの概要は少しでも知っておいた方が良い
- 主に cloud9、Kinesis、DynamoDB、MQTT などの用語の意味くらいは知っておく、でないとハンズオンがやっただけになってしまい、理解度が深まらない
- AWSに関連しないITの用語として ルート証明書、公開鍵、秘密鍵
- ハンズオン前に自身がAWSで知っていたこと
    - EC2 / cloud9 / Lambda / DynamoDB / API Gateway / RDS / Kinesis Data Stream / Elasticsearch など
- Pythonは知らなくても実施できる
- コマンド（ターミナル）相当の使い方は知っていること、cloud9の操作に必要。
- 使うリージョンはAWS IoT Coreが動くリージョンならば良い、バージニア、東京、オレゴンどれでも良い


## Elasticsearchについて
### 時間かかるときがある
- Elasticsearchのインスタンスが使えるようになるまでがめっちゃ時間かかる
    - ハンズオンの説明では10分程度の記載があるが、1時間以上かかっても使えるようにならなかった。`us-west2`（オレゴン）リージョンを使ったためかは不明。
- 過去に東京リージョンでインスタンス構築した時は確かに15分程度だったような記憶がある

### 課金・利用料
- Elasticsearchは停止できないため構築すると課金がずーっとされる、早くハンズオンを終え、確認したら消しましょう。t2microでも  $1/日　くらいかかります


## エッジデバイス側のデータ送信のプロセス
- エッジデバイス側としてのcloud9のpythonプロセスは起動しっぱななしか、何らか処理前に起動する
     - 実行しっぱななしは、ctrl+cでプロセスを終了する

## 各種用語
- デバイスシャドウ
reported , desired の意味を知っておく

|  項目  |  意味  |
| ---- | ---- |
|  reported  |  デバイス側の状態がreportedに格納される  |
|  desired  |  AWS クラウド側からの指示がdesiredに格納される  |
|  delta | reported , desiredが異なる場合に存在する |

## 動かない、エラーかなっと思ったら
### トピック名の誤り  ルールステートメント 
- デフォルト
```
SELECT * FROM 'iot/topic'
```
- 自身の設定に変更する
```
select * from 'data/sugimoto-device-202105'
```

### API Gatewayでリクエストすると500エラーになる
- API Gateway で「Lambda プロキシ統合の使用」にチェックONであること、チェック忘れると 500 エラー（パラメータの {deviceid} が取得できていない）。
- ブラウザでURLたたくと

    ```
    {"statusCode": 500, "headers": {"Access-Control-Allow-Origin": "*"}, "body": "Lambda error. check lambda log", "isBase64Encoded": false}
    ```
    になる。POSTで飛んでるのかも、postmanで試してみては？


### Elasticsearch Kibana 
- Kibanaのdiscoverの設定で、timestamp を入力するところで説明にもあるが、 「timestampが見つからないときはデータが届いていない」はcoud9 側でデータ送信を行う必要あり、cloud9（デバイス側） で以下を実行しっぱななしにしておいて Kibanaの設定をしてみる。

```
 $ cd dummy_client
 $ python3 device_main.py --device_name sugimoto-device-202105 --endpoint a2xxxxx.iot.us-west-2.amazonaws.com
device_name: sugimoto-device-202105
```
の実行する。
データが届いていると、
Index patternに `timestamp*` を入力すると
`Success! Your index pattern matches 1 index.` が表示されるようになっている


### Amazon Kinesis Data Firehos, S3への格納
- S3においた gzファイルが windowsの7zipだと解凍失敗する。原因未調査。サクラエディタで開くと見えた。gzなんだけど圧縮されずにテキストファイルとして存在していそう。
DatePeriodの罠

`2021-05-17` から `2021-05-21` を1日ずつループしたい
そんなときに便利(?)な [DatePeriod](https://www.php.net/manual/ja/class.dateperiod.php) というクラスがあります

`DatePeriod` は `Traversable` を実装しているのでオブジェクトのまま `foreach` でループできます
(ここだけは)素敵ですね！

しかし、なにも考えずに使うとはまってしまうので注意が必要です！

## まずはコード

```php
// 開始日
$startDateTime = new DateTime('2021-05-17');
// 終了日
$endDateTime = new DateTime('2021-05-21');
// 間隔(1日)
// 最初の文字は P 固定(これいる？)
// 1D は 1日
$interval = new DateInterval('P1D');
$period = new DatePeriod($startDateTime, $interval, $endDateTime);

foreach ($period as $date) {
  echo $date->format('Y-m-d'), PHP_EOL;
}
```

結果を見てみると `2021-05-21` が含まれていません

```
2021-05-17
2021-05-18
2021-05-19
2021-05-20
```

## 原因
`DatePeriod` は時分秒マイクロ秒まで見て 未満 で比較します
なので最後の日付が含まれません

## 解決方法
最後の日付を1秒ほど、ずらしてあげましょう

```diff_php
// 開始日
$startDateTime = new DateTime('2021-05-17');
// 終了日
- $endDateTime = new DateTime('2021-05-21');
+ $endDateTime = (new DateTime('2021-05-21'))->setTime(0, 0, 1); // 0時0分1秒にする
// 間隔(1日)
// 最初の文字は P 固定(これいる？)
// 1D は 1日
$interval = new DateInterval('P1D');
$period = new DatePeriod($startDateTime, $interval, $endDateTime);

foreach ($period as $date) {
  echo $date->format('Y-m-d'), PHP_EOL;
}
```

`2021-05-21` もでました！

```
2021-05-17
2021-05-18
2021-05-19
2021-05-20
2021-05-21
```

## おまけ

[Carbon](https://carbon.nesbot.com/docs/) は(本当に)便利です

```php
use Carbon\CarbonPeriod;
$period = CarbonPeriod::start('2021-05-17')->days(1)->end('2021-05-21');

foreach ($period as $date) {
  echo $date->format('Y-m-d'), PHP_EOL;
}
```

逆に最後の日付を含まないようにするには `end` の第2引数 `$inclusive` に `false` を渡してあげればOK

Carbon使おう！
Mac OS X Big SurでTelepresenceのインストールが出来ない問題の解消法

## 事象

```sh
$ brew install datawire/blackbird/telepresence
```

を実行すると、以下のようなエラーが出た

```
libfuse: Linux is required for this software.
Error: An unsatisfied requirement failed this build.
```

## 解消法

こちらにissueがあった
https://github.com/telepresenceio/telepresence/issues/1688

上記issue内にある[コメント](https://github.com/telepresenceio/telepresence/issues/1688#issuecomment-830466380)でmacFUSEとSSHFSをインストール後に以下で動作したとある

```
$ brew install datawire/blackbird/telepresence --ignore-dependencies
```

インストール出来、以下でバージョン確認も出来た

```sh
$ telepresence --version
```
ターミナル上で入力した文字が表示されなくなった時

cloud9のターミナルにて作業中に、突然文字が表示されなくなりました。
ただし画面上に表示されなくなっただけで、処理は行われます。
以下のような感じ。

```:ターミナル
$                     #←本当はrails cと入力しているけど、表示されない

>Running via Spring preloader in process 7447 #→処理は行われる
Loading development environment (Rails 5.2.6)
[1] pry(main)> 
```

このような現象が発生した場合は、以下コマンドを入力すれば表示されるようになると思います。

```
$ stty sane
```

ターミナルの特殊文字に変更が加わって、それが復元されない場合に発生するそうです。
突然発生して焦りましたが、次回からは焦らず対処しようと思いました。
Nuxt.jsでaxiosをpluginでラッピングしてApiクライアントを作成する（Typescript）

いちいち`this.$axios.get`とか書いてるのいけてないので、axiosをラッピングするようなAPIクライアントを作りたいと思います。

以下のページを参考にTypescriptでプラグインを追加します

https://typescript.nuxtjs.org/ja/cookbook/plugins/

```plugins/api-client.ts
import { Todo } from "~/types/todo";
import { Response } from "~/types/http";
import { Context, Plugin } from "@nuxt/types";
import Vue from "vue";

declare module "vue/types/vue" {
  interface Vue {
    $api: {
      getTodos: () => Promise<Response<Todo[]>>;
      addTodo: (todo: Todo) => Promise<Response<Todo>>;
      updateTodo: (todo: Todo) => Promise<Response<Todo>>;
      updatePertialTodo: (todo: Todo) => Promise<Response<Todo>>;
      deleteTodo: (todoId: number) => Promise<Response<void>>;
    };
  }
}

const BASE = "/api";
const API_TODO = `${BASE}/todos`;

const plugin: Plugin = (context: Context) => {
  Vue.prototype.$api = {
    getTodos: (): Promise<Response<Todo[]>> => context.$axios.get(API_TODO),
    addTodo: (todo: Todo): Promise<Response<Todo>> =>
      context.$axios.post(API_TODO, todo),
    updateTodo: (todo: Todo): Promise<Response<Todo>> =>
      context.$axios.put(`${API_TODO}/${todo.id}`, todo),
    updatePertialTodo: (todo: Todo): Promise<Response<Todo>> =>
      context.$axios.patch(`${API_TODO}/${todo.id}`, todo),
    deleteTodo: (todoId: number): Promise<Response<void>> =>
      context.$axios.delete(`${API_TODO}/${todoId}`)
  };
};

export default plugin;
```

`Vue.prototype.$api = {}`で`this.$api`が使えるようになります


```types/http.d.ts
export interface Response<T> {
  status: number;
  data: T;
}
```

```types/todo.d.ts
export interface Todo {
  id: number;
  contents: string;
  start: string;
  end: string;
  isCompleted: boolean;
}
```

```nuxt.config.js
  plugins: [
    ・・・
    '~/plugins/api-client.ts'
  ],
```

これで、`this.$api.getTodos()`のように呼び出すことができ、いちいちaxiosをしなくて良くなります

（2021/05/20 追記)

APIがOpenAPIに対応している場合はさらにシンプルにできるので以下のページをご参照ください

https://qiita.com/teracy55/items/4c6d475b98deaa23790b
google-servicesの4.3.6で「CustomMessageMissingMethodException」

Flutterにて、`build.gradle`に`'com.google.gms:google-services:4.3.6'`を追加して実行すると、以下のエラーが発生しました。

```build.gradle
dependencies {
        classpath 'com.android.tools.build:gradle:4.1.0'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath 'com.google.gms:google-services:4.3.6'
    }
```

```bash
* What went wrong:                                                      
A problem occurred evaluating root project 'android'.                   
> A problem occurred configuring project ':app'.                        
   > Failed to notify project evaluation listener.                      
      > org.gradle.internal.metaobject.AbstractDynamicObject$CustomMessageMissingMethodException: Could not find method setVariantDir() for arguments [debug] on task ':app:processDebugGoogleServices' of type com.google.gms.googleservices.GoogleServicesTask.
      > KotlinJvmAndroidCompilation with name 'debug' not found.        
                                                                        
* Try:                                                                  
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
```

## 対処法
`'com.google.gms:google-services:4.3.6'`を`4.3.5`にすると解決しました。
[Rails]検索フォームでの検索機能/複数カラムを対象とした検索機能の実装

# 記事の概要
　投稿された記事を文字列で検索し、検索された投稿記事を一覧表示する機能の実装方法をまとめた。テーブルの特定カラムを文字列検索対象としている。複数カラムを対象とした検策もできる。


# 検索の流れ
　　検索フォームから検索ワードを入力し送信する。
　→ 検索ワードが格納されたparamsをコントローラーで受取り、検索メソッドに渡される。
　→ 検索メソッドを実行、モデルから文字列検索結果を取得、コントローラでインスタンス変数に代入。
　→ ビューでインスタンス変数が展開されて表示。

# 実装手順
　実装手順は下記の通り。
　①ルーティングの設定
　②検索メソッドをモデルに定義
　③検索アクションをコントローラーに定義
　④検索フォームをビューに記述
　⑤検索結果の表示をビューに記述

### ①ルーティング設定
　検索表示機能はarticlesコントローラーのsearchアクションとして定義する。collectionメソッドで設定する。

```ruby:config/routes.rb
Rails.application.routes.draw do
  devise_for :users
  resources :articles do
    #以下、collectionでsearchアクションへのルーティング設定
    collection do
      get 'search'
    end
  end
end
```

### ②検索メソッドをモデルに定義
　投稿記事を扱うArticleモデルの中に検索メソッドを定義する。searchメソッドと命名。
whereメソッドとLIKE句を使用して、特定のレコードを取得できるようにする。ここでは、articlesテーブルにtextカラムがあるとして、これを検索対象カラムとしてwhereの引数部分に条件を指定する。

```ruby:app/models/article.rb
class Article < ApplicationRecord
  def self.search(search)
    if search != ""
      Article.where('text LIKE(?)', "%#{search}%") # 
    else
      Article.all
    end
  end
end
```
　なお、引数searchには下で実装する検索フォームから届けられるパラメータが入る。searchの中身が空だった場合の条件分岐もしておいた。

### ③searchアクションをコントローラーに定義
　articlesコントローラーにsearchアクションを定義する。

```ruby:app/controllers/articles_controller.rb
class ArticlesController < ApplicationController
  def search
    @articles = Article.search(params[:keyword])
  end
end
```
### ④検索フォームをビューに実装
　indexビューに検索フォームを実装することとする。下記の記述により、検索フォームから文字列を送信するとparams[:keyword]に格納されてsearchメソッドに渡され、Articleモデルに対して文字列検索、レコードの取得が実施される。

```app/views/articles/index.html.erb
<%= form_with(url: search_articles_path, local: true, method: :get ) do |form| %>
  <%= form.text_field :keyword %>
  <%= form.submit "検索" %>
<% end %>
```
### ⑤検索結果をビューに表示させる
　検索結果をsearchビューに表示させる。searchメソッドの結果取得されたレコードが格納されているインスタンス変数をeachメソッドで展開する。検索フォームも表示させたままとする。

```app/views/articles/search.html.erb
<%= form_with(url: search_articles_path, local: true, method: :get ) do |form| %>
  <%= form.text_field :keyword %>
  <%= form.submit "検索" %>
<% end %>

# 以下、検索結果の一覧表示の記述
<div>
  <% @articles.each do |article| %>
    <%= article.title %>
    <%= article.text %>
    # 省略
  <% end %>
</div>
```

# 一つの検索フォームで複数のカラムを対象に検索する
　上記ではarticlesテーブルのtextカラムを検索対象としていたが、例えばtitleカラムも検索対象としたいとする。複数のカラムを跨いで検索したい場合は以下のように記述する。

```ruby:app/models/article.rb
class Article < ApplicationRecord
  def self.search(search)
    if search != ""
      # where(['カラム名 LIKE(?) OR カラム名 LIKE(?)', "%#{search}%", "%#{search}%"])のように記述。
      # 検索対象カラムの数だけ"%#{search}%"を記述。
      Article.where(['text LIKE(?) OR title LIKE(?)',"%#{search}%","%#{search}%"])      
    end
    else
      Article.all
    end
  end
end
```
Rails5で検索ボックスのplaceholderにFontAwesome5のアイコンを表示したい!

# やりたかったこと

- ruby 2.6.3
- rails 5.2.6
- webpacker 5.3.0
- Font Awesome 5 (yarnでインストール)

で，こんな風にして，検索フォームにFont Awesome 5 の虫眼鏡マーク(Unicodeはf002)を出したかった。

```slim:index.html.slim
= form_with url: search_path, method: :get, local: true do |f|
  = f.text_field :search, class: 'fa_icon', placeholder: "\uf002 検索ワードを入力"
  = f.submit "検索"                                        # ↑ここ！
```

でも，表示してみると文字化けして□が出てきてしまう…


# 解決方法

以下の記事(Rails6でしたが)を参考に解決しました！

https://qiita.com/sasakura_870/items/7f72c80f89d66923f6f1


```scss:app/javascript/stylesheets/application.scss
@import "~bootstrap/scss/bootstrap";
@import "~@fortawesome/fontawesome-free/scss/fontawesome";
// 以下を追加しました。(追加したいアイコンはsolidだったので，これだけにしています。)
$fa-font-path: "~@fortawesome/fontawesome-free/webfonts";
@import "~@fortawesome/fontawesome-free/scss/solid";

// 中略

.fa_icon {
  font-family: "Font Awesome 5 Free";
  // weightは,使いたいフォントがSolidなら900,RegularやBrandsなら400,Lightなら300
  font-weight: 900;
}
```

ありがとうございました！
Webブラウザで使えるメモ帳アプリを作成してみよう#1〜独学でどこまで作れるのか〜

プログラミング初心者です。
開発の備忘録として書いています。

HTML・CSSを初めて勉強する人で何から手をつけていいかわからない方向けです。
私も初心者なので、間違っている点があると思いますが、ご了承ください。

#目標

メモ帳アプリを作ること。

最終的な全体のイメージ図は、まだ固まっていませんが、以下サイトを参考にする予定。
https://mimemo.io/m/new

#第1回目の完成度

![image01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/516799/919d3021-478d-a49c-9cd0-9626c5cbd971.png)

htmlのコードは下記です。

```memo.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>memo</title>
    <link rel="stylesheet" href="style01.css">
</head>
<body>
    <h1>memo</h1>
    <input type="text" placeholder="タイトル">
    <input type="text" placeholder="忘れないうちにメモる">
</body>
</html>
```

cssのコードは下記です。

```style01.css
@charset "UTF-8";

h1{
    font-size: 50px;
    color: coral;
}

input{
    font-size: 3em;
}
```

#学んだこと

###文字が入力できる枠を作る
```
 <input type="text">
```

###文字入力の枠内にグレーの文字を表示させる

placeholderタグを使用します。
placeholderタグの後には、表示させたい文字を入れます。

```
<input type="text" placeholder="タイトル">
```

###別ファイルのcssを読み込む

css用のファイルを作成。
拡張子を.cssで保存することでcssのファイルを作ることができます。

htmlファイル内に、

```
<link rel="stylesheet" href="style01.css">
```
と入力。

私の場合であれば、memo.html内に入力します。

hrefの後は、作成したcssファイル名を指定します。

###文字入力inputの枠を広げる

cssに

```
input{
    font-size: 3em;
}
```

と入力。

inputの場所は、変更したい場所を指定しています。

{}のカッコで囲って、font-sizeで枠を広げました。

#次回以降やりたいこと

・「忘れないうちにメモる」の枠を「タイトル」枠よりも大きくする
・入力した文字を太文字にしたり、箇条書きで入力できるようにする
Ubuntu20.04にvenvをセットアップする

# Ubuntu 20.04にpython3-devをインストールしようとすると次のdependencyエラーになる。

```
sudo apt install python3-dev
Reading package lists... Done
Building dependency tree
Reading state information... Done
Some packages could not be installed. This may mean that you have
requested an impossible situation or if you are using the unstable
distribution that some required packages have not yet been created
or been moved out of Incoming.
The following information may help to resolve the situation:

The following packages have unmet dependencies:
 python3-dev : Depends: libpython3-dev (= 3.8.2-0ubuntu2) but it is not going to be installed
               Depends: python3.8-dev (>= 3.8.2-1~) but it is not going to be installed
E: Unable to correct problems, you have held broken packages.
```

# 対処
次ぎの手順でUbuntu20.04にvenv環境を構築することができました。

1. sudo apt update
1. sudo apt install python3-pip
1. sudo apt install python3-venv
1. python3 -m venv ＜プロジェクト名＞
1. source ＜プロジェクト名＞/bin/activate
1. pip install -U pip
1. pip install wheel

flask環境を作成する場合はflaskとgunicornもインストール
7. pip install flask gunicorn


以上