OmniAICreator/Qiita-1.07M huggingface dataset:
AWS CLIの振り返り ~SNS入門編~

#本記事の目的
JAWS-UG CLI オンラインハンズオンの復習として、ハンズオンで取り上げられたAWSサービスに関する用語と、使用したAWS CLI コマンドを箇条書きでまとめる。
今回はSNS入門編を取り上げる。

#主なAWSサービス用語
####トピック
通知チャネルとしての機能を持つ論理アクセスポイント。

####パブリッシュ
メッセージを発行し、トピックに送信する事。メッセージを送信するアプリケーション及びシステムは、**パブリッシャー**と呼ばれる。

####サブスクライブ
トピックからメッセージを受信する事。メッセージを受信するアプリケーション及びシステムは、**サブスクライバー**と呼ばれる。

####通知プロトコル
メッセージのサブスクライブ手段。HTTP,SMS,Email,AWS Lambda等の種類がある。

####通知先エンドポイント
サブスクライブする端末を識別するためのデータ。通知プロトコルによってデータ形式が異なる。

####サブスクリプション
トピックと通知先エンドポイントを紐づけるデータ。


#主なAWS CLI コマンド一覧
####トピックの作成
```
aws sns create-topic \
  --name ${SNS_TOPIC_NAME}
```
|オプション|引数|必須/任意|備考|
|---|---|---|---|
|--name|トピックの名前|必須||

####トピックの一覧表示
```
aws sns list-topics 
```

####トピックの削除
```
aws sns delete-topic \  
  --topic-arn ${SNS_TOPIC_ARN}
```
|オプション|引数|必須/任意|備考|
|---|---|---|---|
|--topic-arn|トピックのARN|必須||

####エンドポイントの登録
```
aws sns subscribe \
  --topic-arn ${SNS_TOPIC_ARN} \
  --protocol ${SNS_SUBSCRIPTION_PROTOCOL} \
  --notification-endpoint ${SNS_SUBSCRIPTION_ENDPOINT}
```
|オプション|引数|必須/任意|備考|
|---|---|---|---|
|--topic-arn|トピックのARN|必須||
|--protocol|通知プロトコル|必須|通知プロトコルの例：email|
|--notification-endpoint|通知先エンドポイント|必須|通知先エンドポイントの例：メールアドレス(xxxxxxxxx@xxxxxx.xxx)|

####エンドポイントの表示
```
aws sns list-subscriptions-by-topic \
  --topic-arn ${SNS_TOPIC_ARN}
```

####エンドポイントの解除
```
aws sns unsubscribe \
  --subscription-arn ${SNS_SUBSCRIPTION_ARN}
```
|オプション|引数|必須/任意|備考|
|---|---|---|---|
|--subscription-arn|サブスクリプションのARN|必須||

####メッセージの送信
```
aws sns publish \
  --topic-arn ${SNS_TOPIC_ARN} \
  --message ${SNS_MESSAGE_BODY} \
  --subject ${SNS_MESSAGE_SUBJECT}
```
|オプション|引数|必須/任意|備考|
|---|---|---|---|
|--topic-arn|トピックのARN|必須||
|--message|メッセージ内容|必須||
|--subject|題名|必須||


#参考文献
- AWSCLIコマンドリファレンス:[sns](https://docs.aws.amazon.com/cli/latest/reference/sns/index.html)
- JAWS-UG CLI専門支部：[ハンズオン(簡易版): SNS入門](http://prototype-handson-cli.s3-website-ap-northeast-1.amazonaws.com/handson_light-aws_service/handson_light-aws_service-sns/index.html)
Git操作:デフォルトブランチ名の変更

【[自分とこの環境下におけるGit & GitLabレクチャー](https://qiita.com/NeK/items/dee76f411cf2488b6873)】

# 概要
GitLab 14.0からブランチ名が変わります．その作業自体もすっごい大変でしたが，これは更新作業が終わった後の話．

# 既存プロジェクトの扱い
## 既存プロジェクトのブランチ名
GitLab 14.04以前に作成したプロジェクトのデフォルトブランチ名はmasterのままです．

## 既存プロジェクトのブランチ名をmainに変更する方法
流れとしては以下の通り．

1. ローカルのgitコマンドでブランチ名をmasterからmainに変更
1. ローカルでpush
1. GitLabでデフォルトブランチをmainに変更し，masterを削除
    * 対象のプロジェクトにて
        * 設定
            * リポジトリ
                * デフォルトブランチをmasterからmainに
                * Protected branchesをmasterと同じに
        * リポジトリ
            * ブランチ
                * 削除したいブランチ名にある「ゴミ箱」のボタンをクリック
                    * 手順通りに削除

```shell:ブランチ名の変更とpush
$ git branch -m master main
$ git push -u origin main
```

# 新規プロジェクト
自動的にmainになっている．

## gitの扱い
GitLabはmainであるが，コマンドであるgitは設定しないといけない．
以下のコマンドでデフォルトブランチを指定

```shell
$ git config --global init.defaultBranch main
```
Vue.js,Railsで画像プレビュー機能を作成


##完成図
![スクリーンショット 2021-06-14 22.03.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635864/c80cbd99-63d3-ec36-aca6-3e701a9b830f.png)

参考：https://blog.capilano-fw.com/?p=1189


##やりたい事
ユーザーのプロフィール編集機能を作成するにあたって
・プロフィール画像を画像を選択したらそれを即時に反映させる
・デフォルトのラジオボタンはデザインがダサいのでカスタマイズする
・アクセスした時点ではでは既に設定されているアイコンを表示する


###全体コード

````ruby:edit.html.erb（一部）

<div class="field">
 <%= f.label :image, "プロフィール画像" %><br />
  <div id="img_field" @change="onFileChange($event)">
   <img :src="imageData" v-if="imageData" class="edit-preview-image">
   <img src=<%= current_user.image %> v-else class="edit-preview-image">
   <label for="file-input" class="input-file-button">
    ファイルを選択
   </label>
  <%= f.file_field :image, id: "file-input", accept: "image/*" %>
 </div>
</div>
````

````image_upload_vue.js

import Vue from 'vue/dist/vue.esm'
import App from '../app.vue'

document.addEventListener('DOMContentLoaded', () => {
  const app = new Vue({
    el: '#img_field',
    data: {
      imageData: ''
    },
    methods: {
      onFileChange(e) {
  
        const files = e.target.files;

        if(files.length > 0) {
    
            const file = files[0];
            const reader = new FileReader();
            reader.onload = (e) => {
    
                this.imageData = e.target.result;
    
            };
            reader.readAsDataURL(file);
        }
      }
    },
    components: { App }
  })
})

````

###デフォルトのラジオボタンをカスタマイズする

````ruby:edit.html.erb

<label for="file-input" class="input-file-button">
  ファイルを選択
</label>
<%= f.file_field :image, id: "file-input", accept: "image/*" %>
````

````application.scss

#img_field > input
{
    display: none;
}

.input-file-button {
  cursor: pointer;
  background: #636;
  color: white;
  padding: 5px 10px;
  border-radius: 5px;
  width: 100%;
  text-align: center;
}
````

デフォルトのラジオボタンはidを付与してdisplay:none;で非表示にし、それに対応するlabelタグにcssを当てる事でオリジナルのボタンを作成できる

###v-ifを使って画像プレビュー機能を作成

````ruby:edit.html.erb

<div id="img_field" @change="onFileChange($event)">
   <img :src="imageData" v-if="imageData" class="edit-preview-image">
   <img src=<%= current_user.image %> v-else class="edit-preview-image">
・・・

````

````application.scss
.edit-preview-image {
  width: 120px;
  height: 120px;
  border-radius: 50%;
  border: 1px solid #eee;
  // 縦横比を変えないままトリミング
  object-fit: cover;
  display: block;
  margin: 10px auto;
}

````

imageDataに値が挿入されていれば上のimgタグ(新しく選択した画像)が表示され画像を選択していない場合はしたのimgタグ(現在設定しているアイコン)が表示される

思っていたよりもrails✖︎vueの記事が無かったので苦戦しました(SPA作る系のやつならたくさんあったのですが)
でもVue.jsの学習の一環としてこの機能はVueで実装してみたかったので粘った甲斐があったと思います。
じゃんけんの結果

コーディングテストにて、じゃんけんを扱う問題に出会ったので、その内容と学びをまとめる。

## 問題内容

テスト内容は、じゃんけんの結果を出力するもの。
出力する内容は、

1. 勝者が存在する場合は、その勝者の手の種類
2. 引き分けの場合は、"draw"

入力内容は、
1行目に参加人数、その下に参加者の手の種類を参加人数分続ける。

## 入出力例

```ruby
入力例
3 # 参加人数
rock # 1人目のじゃんけんの手
scissors # 2人目のじゃんけんの手
paper # 3人目のじゃんけんの手

出力例
draw # 引き分けの場合

入力例
4 # 参加人数
rock # 1人目のじゃんけんの手
scissors # 2人目のじゃんけんの手
rock # 3人目のじゃんけんの手
scissors # 4人目のじゃんけんの手

出力例
rock # 勝者の手を出力する
```

## 回答

```ruby
input_lines = readlines.map { _1.chomp }
choices = input_lines[1..input_lines[0].to_i].uniq
if choices.count == 3
    puts "draw"
elsif choices.include?("rock") && choices.include?("scissors")
    puts  "rock"
elsif choices.include?("scissors") && choices.include?("paper")
    puts  "scissors"
elsif choices.include?("paper") && choices.include?("rock")
    puts  "paper"
end
```

## 回答（リファクタリング

```ruby
input_lines = readlines.map { _1.chomp }
choices = input_lines[1..input_lines[0].to_i].uniq
if choices.count == 3
    puts "draw"
elsif (["rock", "scissors"] - choices).empty?
    puts  "rock"
elsif (["scissors", "paper"] - choices).empty?
    puts  "scissors"
elsif (["paper", "rock"] - choices).empty?
    puts  "paper"
end
```

## 学び

### uniq

配列の要素の中から重複しているものを除外し、要素が一意な配列を生成しなおす。

```ruby
["rock", "scissors", "rock", "scissors"].uniq
# => ["rock", "scissors"]
```

### include?

配列内に、引数で与えられた要素が含まれている場合にtrueを返す。ただし、引数は一つ。

```ruby
["rock", "scissors"].include?("rock")
# => true
["rock", "scissors"].include?("paper")
# => false
```

### 引数が複数の場合のinclude?

https://oshiete.goo.ne.jp/qa/7042610.html

こちらを参考に。小数点が存在する場合は、注意が必要であるらしい。

```ruby
list = ["rock", "scissors"]
choices = ["rock", "scissors", "rock", "scissors"]
(list - choices).empty?
# => true
```
パスコンキーボード記号

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225536/c1a6f213-c10e-9ee2-821c-34356770d6ef.png)
記号	読み方
!	ビックリマーク
"	ダブルクォーテーション
#	シャープ
$	"ドル
ダラ－"
%	"パーセント
パー"
&	アンド
'	シングルクオーテーション
(	始め括弧
)	終わり括弧
=	イコール
~	チルダ
|	"垂直バー
縦線
縦棒
パイプ"
-	"マイナス
負符号
ハイフン
引く"
^	"キャロット
カレット
やま
アクサンシルコンフレックス"
¥	"円記号
円"
	
キーボード2段目	
{	"始め中括弧
始め波括弧
ブレース
カール
"
@	アットマーク
［	"始め大括弧
始め角括弧
左ブラケット
"
キーボード3段目	
+	プラス
*	"アスタリスク
掛ける"
}	"終わり中括弧
終わり波括弧
ブレースカール
"
:	コロン
;	セミコロン
]	"始め大括弧
始め角括弧
左ブラケット
"
キーボード4段目	
	
<	"不等号
小なり"
>	"不等号
大なり"
?	クエスチョンマーク
	"はてな
疑問符
"
_	"アンダーバー
下線
アンダーライン
"
,	"コンマ
カンマ
セディユ
"
.	"ピリオド
終止符
点
ぽち
"
/	"スラッシュ
斜線
スラ
"
\	バックスラッシュ
dockerの入力補完を行う(zsh)

## 概要

[Dockerの日本語ドキュメント](https://docs.docker.jp/compose/completion.html)の説明では、docker-composeの補完スクリプトの説明しか見つけられませんでした。
[公式github](https://github.com/docker/cli/blob/master/contrib/completion/zsh/_docker)に補完スクリプトがあります。

## 参考

[zshにgitとdockerの入力補完を実装する](https://hodalog.com/docker-and-git-commands-auto-completion-in-mac-os-catalina/)

## 手順

### 補完スクリプトの保存場所を作成する

zsh保存先のcompletionディレクトリや、`~/.zsh/completion`に保存するのが普通のようです。
以下、`~/.zsh/completion`に保存する場合を例に説明します。

```zsh
mkdir -p ~/.zsh/completion
```

### スクリプトをダウンロードする

```zsh
curl -o ~/.zsh/completion/_docker https://raw.githubusercontent.com/docker/cli/master/contrib/completion/zsh/_docker
```

### .zshrcに追記する

`~/`直下の`.zshrc`ファイルに以下を追記する。
(`.zshrc`が無い場合は作成する。)

```zsh:.zshrc
# FPATHに`~/.zsh/completion`を追加
fpath=(~/.zsh/completion $fpath)

# シェル関数`compinit`の自動読み込み
autoload -Uz compinit && compinit -I
```

### シェルの再読み込みを行う

以下のコマンドを実行するか、シェルを開き治す。

```zsh
exec $SHELL -l
```

以上。
E資格2021#2実装演習レポート：機械学習

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1643448/e2fd91e1-9b0b-bd96-b7c9-3cb742b1419b.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1643448/d87740f5-6f9f-2355-4d6c-8900ca41c455.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1643448/6c2c4dbb-7967-cd58-cf84-6575bcf2b9c1.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1643448/7d1c4da4-86d9-6097-4147-322e44fe5f98.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1643448/eee8ae05-0123-5317-db7a-86ca324bcb3a.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1643448/34241975-630b-cc89-b9d9-a8b865ba2b38.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1643448/70a1093a-e642-fe88-1283-707ee92b183e.png)
【未経験開発 React / Firebase】本・映画・アニメを記録するウェブアプリを作りました。



本記事では、**React で個人開発をする際に使用した技術**を紹介いたします。


# 開発アプリ概要


読書・映画鑑賞の管理、記録をすることができるウェブアプリです。


<br>
<img class="size-medium wp-image-3811 aligncenter" src="https://poland-it-blog.com/wp-content/uploads/2021/05/eb22bf7a906b7f73af3d68cd620dade7.png" alt="" width="500" height="281" />
<img class="size-medium wp-image-3811 aligncenter" src="https://poland-it-blog.com/wp-content/uploads/2021/05/0e4aae38a1f5494592124a884058f7cb.png" alt="" width="500" height="281" />

# アピールポイント
+ タイトル、著者名の他にもメモの内容からでも検索可能
+ データのエクスポート
+ 読んだ本、見た映画の本数が分かるグラフ機能付き。年・月ごとのデータを確認することができます。例えば劇場で見た映画・旧作別の年間本数が一目で分かります。
+ 懐かしい図書貸出カード風に登録データを表示


# 使用技術
 React ( create-react-app / Custom Hooks/ Material-UI / eslint&prettier)
 Firebase ( Authenication/ Firestore / Functions/ Hosting)
 各種API　( The Movie Database (TMDb) / Rakuten Books Total Search API )

# 機能一覧
**ユーザー機能**

+ 新規登録、サインイン、サインアウト、テストユーザーサインイン機能
+ 登録情報編集
+ アカウント削除
+ パスワードリセット機能（ベータ版では無し）


**検索機能**

+ APIを使用し本、映画を検索


**その他**

+ カテゴリーの追加、削除、編集
+ タグの追加、削除、編集
+ メモ機能
+ グラフ機能
+ 画面のスクロール位置に応じて必要な分だけ画像を表示
+ お問い合わせフォーム (reCAPTCHA 導入)
+ 図書貸出カード風に登録データを表示
+ 物理演算ライブラリを使用して、データを表示
+ csv ファイルでデータをエクスポート
+ レスポンシブ対応(スマホ、PC)


推奨ブラウザは **Chrome** です。

# 技術スタック




こちらがインフラ構成です。
<br>
![代替テキスト](https://poland-it-blog.com/wp-content/uploads/2021/05/Hosting.png)

##Front-end

フロントエンドは React.js 。Redux は使わずに、Context と Hooks を使用しています。


## 主要ライブラリ

+ create-react-app
+ Material-UI: UI コンポーネントライブラリ
+ react-photo-gallery: イメージギャラリーコンポネント
+ eslint & prettier: コード整形
+ EmailJs: JavaScript からメール送信
+ ChartJs: グラフを表示できるライブラリ
+ Matter.js: 物理演算ライブラリ
+ Algolia: 全文検索サービス

## Back-end

バックエンド・インフラ周りは すべてFirebaseで完結しています。デプロイもFirebase。

+ Authentication: ユーザー認証
+ Firestore: データ管理
+ Functions: 設定したトリガーでバックエンド処理を自動的に実行
+ Hosting: デプロイ

<br>


無料プランではなく、従量制の Blaze プランを使用。



<br>


## API

API は書籍に関しては、[Rakuten Books Total Search API](https://webservice.rakuten.co.jp/api/bookstotalsearch/)、映画・テレビドラマに関しては[The Movie Database (TMDb)](https://developers.themoviedb.org/3/search/search-movies) を使用しています。


## デザイン

Material-UI というUIコンポーネントライブラリを使っています。



# 最後に

このアプリは完璧な趣味プロダクトです。

休日を使ってコツコツと作りました。


<br>

サイト作りに関しては以前から**ブクログ**や**フィルマークス**といったウェブサービスを使っていたのでこの２つのサイトを主に参考にしています。




あとYouTubeチャンネルのシネマンションの動画も参考にしてサイトにどんな機能を付けようか考えてました。

<br>

<iframe width="560" height="315" src="https://www.youtube.com/embed/s4tPkuS6lvI" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
Webページの表示速度を向上するために、画像のファイルサイズを考えなければならない

##はじめに
若干通信速度が遅い環境で自身のサイトを確認したときに、画像がゆっくり表示され「表示が遅い」と感じました。
ですが、他のサイトはそこまで遅くはなかったので、画像のファイルサイズが大きすぎるのではないかと思い、画像の適正なファイルサイズについて調べてみました。


##画像の適正なファイルサイズ
こちらのサイトに目安が書かれていました。


>実際に色んなサイトやブログを調べてみればわかると思いますが、だいたい一つの画像サイズの目安は15KB〜80KBです。あとは画像の大きさと画質とのバランスで決めることになります。

>引用元：
[ウェブサイトを作る上で欠かせない画像の圧縮。ベストな方法は？](https://www.16channel.com/create/post-587-crest-and-edit/)


ちなみに私が遅いと感じた画像は概ね200KBでした。



##画像比較
15KB〜80KBということであれば画像のリサイズや、画質を落とすことはほぼ必須となります。
Webサイトに合う大きさにリサイズするのであれば問題ありませんが、画質を落とした場合は、どのくらい影響が出るのか気になったので、illustratorでサンプル画像を作成しました。

個人的には、写真よりも文字の方が影響を受けている気がしたので、文字だけの画像になります。

画質はillustratorの書き出し時にクイック選択できる5パターン（100%, 80%, 60%, 30%, 10%）と、画質50%を合わせた6パターンで比較します。
なお、「画質」の項目からは0~100で細かく設定できます。

---

最高画質（画質:100%）
![最高画質.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1325744/ed85da51-0962-2a12-badc-62c819278e9c.jpeg)

---
高画質（画質:80%）
![高画質.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1325744/48a526c5-da15-0583-7455-85aad20b9f84.jpeg)

---
やや高画質（画質:60%）
![やや高画質.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1325744/c03d23b7-7daa-04db-97ab-b1d6abfd9ca5.jpeg)

---
（画質:50%）
![50％.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1325744/0fa10970-d5b3-4609-340e-77c7de17c045.jpeg)

---
中画質（画質:30%）
![中画質.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1325744/282263d3-0639-24c5-b5c5-92f602bf1460.jpeg)

---
低画質（画質:10%）
![低画質.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1325744/30f9ba27-dc6b-0f3f-7d09-d8d6c8e35910.jpeg)




##画質とファイルサイズ
Illustratorで書き出した時の画質とファイルサイズは以下の通り。
画像の大きさはすべて、高さ200px・幅900px。すべてJPEGファイルです。

|画質  |ファイルサイズ  |
|---|---|
|最高画質 (100%)  |103.2 KB|
|高画質 (80%)  |66.0 KB|
|やや高画質 (60%)  |44.3 KB|
|(50%)  |34.0 KB|
|中画質(30%)  |25.1 KB|
|低画質(10%)  |17.5 KB|

##あとがき
個人的な感想になりますが、画質100%・80%・60%はあまり区別がつきませんでした。目に見える画質の劣化は50%くらいから始まるような気がします。
これからは画像のリサイズと、画質を60%くらいに落としてファイルサイズを確認し、様子を見て調整するようにしようと思います。

##参考
[ウェブサイトを作る上で欠かせない画像の圧縮。ベストな方法は？](https://www.16channel.com/create/post-587-crest-and-edit/)
PCくんは闇落ちしない


私のセキュリティに関するお恥ずかしい認識違いを忘れない為の忘備録。

# 想像
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1110799/c2b0418f-bcff-cae2-d4d6-95caf7dc825d.png" width=50%>

悪いやつが青人間くんのPCを攻撃して自分のPCを乗っ取って闇落ちさせる！

# 実際は闇落ちしない
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1110799/817fef18-03ae-e9d3-4a4f-433f2690f338.png" width=50%>

青人間くんのPCは闇落ちしたわけじゃなくて、愚直に指示を実行していただけ。
罠サイトの処理も、正常な処理も指示された内容を間違えずにこなしていただけで、PCくんは悪いとか悪くないとか設定しないと分かんない。

罠サイトや攻撃は「こういう攻撃は通しちゃだめだよ～」と明記されていれば、サイトが弾いたり、エスケープして防いでくれる。(攻撃失敗パターン)

逆に、明記されていない場合、攻撃だったとしても実行しちゃう。(攻撃成功パターン)

chromeとかも、レスポンスを見て、「むむ！怪しい！」と思ったら警告を出してくれたり、ブロックしてくれたりする(すごい)。

SQLインジェクションとかは紫人間くんが直接サイトを攻撃してサイトが弾かないとやられるタイプだから、誰かを介する必要が無いし、やりやすそう(勝手には絶対にやっちゃだめ！)

# 愚直にこなす道のり（例）
![スクリーンショット 2021-06-14 215725.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1110799/e52fff32-a323-27da-c08f-3316e1a8b070.png)

①青人間くんが間違えて罠サイトを閲覧してしまう。
②罠サイトが罠レスポンスを返す。
③青人間くんのPCがそれを実行し、サイトにリクエストを送る
④サイトはリクエストを素直に実行しレスポンスを返す(本当はここで弾いてほしい！)

# まとめ

脆弱性を見つけるのは「どっかに攻撃できる抜け道ないかな～」と愚直に探していく地味な作業
リクエストとレスポンスみるの大事！
AWS CLIの振り返り ~SQS入門編~

#本記事の目的
JAWS-UG CLI オンラインハンズオンの復習として、ハンズオンで取り上げられたAWSサービスに関する用語と、使用したAWS CLI コマンドを箇条書きでまとめる。
今回はSQS入門編を取り上げる。

#主なAWSサービス用語
####プロデューサー
メッセージを送信するアプリケーション及びシステム。

####コンシューマー
メッセージを受信するアプリケーション及びシステム。

####(メッセージ)キュー
プロデューサーとコンシューマーの間に入り、プロデューサーから送られてきたメッセージを一時的に預かり、指定したタイミングでコンシューマーに送るためのデータ保管領域。

####可視性タイムアウト
キューに入ったメッセージについて、あるコンシューマーが受信した直後に、他のコンシューマーが誤ってメッセージを重複して受信しないようにするために、一時的に他の消費者が対象のメッセージを受信できないようにする期間。

####受信ハンドル
メッセージを識別するための特定の文字列。主にメッセージの削除に必要となる。

#主なAWS CLIコマンド一覧
####キューの作成
```
aws sqs create-queue \
  --queue-name ${SQS_QUEUE_NAME} 
```

|オプション|引数|必須/任意|備考|
|---|---|---|---|
|--queue-name|キューの名前|必須||

####キューの一覧表示
```
aws sqs list-queues \
  --queue-name-prefix ${SQS_QUEUE_NAME}　
```
|オプション|引数|必須/任意|備考|
|---|---|---|---|
|--queue-name-prefix|キューの名前|任意|特定のキュー情報を取得可能|

####キューのURL取得
```
aws sqs get-queue-url \
  --queue-name ${SQS_QUEUE_NAME}
```
|オプション|引数|必須/任意|備考|
|---|---|---|---|
|--queue-name|キューの名前|必須||

####キューの属性の更新
```
aws sqs set-queue-attributes \
  --queue-url ${SQS_QUEUE_URL}　\　
  --attributes　${SQS_QUEUE_ATTRIBUTE_NAME}=${SQS_QUEUE_ATTRIBUTE_VALUE}
```
|オプション|引数|必須/任意|備考|
|---|---|---|---|
|--queue-url|キューのURL|必須||
|--attributes|キューの属性名=キューの属性値|必須|キューの属性名の例：VisibilityTimeout(可視性タイムアウト)|

####キューの属性の表示
```
aws sqs get-queue-attributes \
  --queue-url ${SQS_QUEUE_URL}　\
  --attribute-names ${SQS_QUEUE_ATTRIBUTE_NAME}
```
|オプション|引数|必須/任意|備考|
|---|---|---|---|
|--queue-url|キューのURL|必須||
|--attributes|キューの属性名|必須|キューの属性名の例：ApproximateNumberOfMessages(メッセージ総数)|

####キューの削除
```
aws sqs delete-queue \
  --queue-url ${SQS_QUEUE_URL}　
```
|オプション|引数|必須/任意|備考|
|---|---|---|---|
|--queue-url|キューのURL|必須||

####メッセージの送信
```
aws sqs send-message \
  --queue-url ${SQS_QUEUE_URL}　\
　　 --message-body ${SQS_MESSAGE_BODY}
```
|オプション|引数|必須/任意|備考|
|---|---|---|---|
|--queue-url|キューのURL|必須||
|--message-body|メッセージ内容|必須||

####メッセージの受信
```
aws sqs receive-message \
  --queue-url ${SQS_QUEUE_URL}
```
|オプション|引数|必須/任意|備考|
|---|---|---|---|
|--queue-url|キューのURL|必須||

####メッセージの削除
```
aws sqs delete-message \
  --queue-url ${SQS_QUEUE_URL} \　
  --receipt-handle ${SQS_MESSAGE_RECEIPT_HANDLE}　
```
|オプション|引数|必須/任意|備考|
|---|---|---|---|
|--queue-url|キューのURL|必須||
|--receipt-handle|受信ハンドル|必須||

#参考文献
- AWSCLIコマンドリファレンス:[sqs](https://docs.aws.amazon.com/cli/latest/reference/sqs/index.html)
- JAWS-UG CLI専門支部：[ハンズオン(簡易版): SQS入門](http://prototype-handson-cli.s3-website-ap-northeast-1.amazonaws.com/handson_light-aws_service/handson_light-aws_service-sqs/index.html)
AtCoder Beginner Contest 205のD問題の自分用解説、兼メモ

ABC205のD問題が解けなかったので解答を見て作成(ほぼ参考サイトの写経)

完全なるノンオリジナル
以下自分用に整理したもの

#問題
https://atcoder.jp/contests/abc205/tasks/abc205_d

#参考記事(パクリ元)

興味がある人はこの記事じゃなくて⏬のリンク先をみるべき
- [Pythonで二分探索を書く]
(https://qiita.com/simonritchie/items/0bedeb260f88dc04454e)
- [二分探索とABC205 D](https://qiita.com/snhrhdt/items/378de323285f6ce46afa)

##要約

肝となるのは2点

1.
$A = [A_1, A_2,  ... ,A_n]$のいずれとも異なる正の整数の数をリストに記録しておく
by [D - Kth Excluded 解説 by KoD]
(https://atcoder.jp/contests/abc205/editorial/2050)

2.
２分探索を使う

答えとなる出力は３通りに分けられる
($K_i$と数列Aの値から判断)
①Aの最大値  <  $K_i$
②Aの最小値  >  $K_i$
③Aの最小値  ≦  $K_i$  ≦  Aの最大値　

それぞれを考えて③は２分探索を使う

#解答
```
# 2分探索の関数
def binary_search(B,K):

#右端と左端のインデックス
  left_index = 0
  right_index = len(B) - 1

#中間のインデックスで２分して値を探す
  while right_index - left_index > 1:
    middle_index = (left_index + right_index) // 2
    middle_value = B[middle_index]

#最大値がK以上の場合は２分したインデックスを右端にする        
    if middle_value >= K:
      right_index = middle_index

#最大値がKより大きい場合は２分したインデックスを右端にする        
    else:
      left_index = middle_index
  
  return right_index

          
#標準入力
N, Q =map(int, input().split())

#数列Aを昇順ソート
A = sorted([int(x) for x in input().split()])

#A[i]の時点でA[i]以下、且つ数列Aに含まれない数字の数をリストへ(=リストS)
#要素数Aの列を作ってから、加工して作成
S = [0 for i in range(len(A))]

#最初の数字はA[0]-1
S[0] = A[0] -1

#次からの数字=[Sの前の数字+A[i]とA[-1]にない数]
#A[i]とA[-1]の差が1だと連続した数字になってしまうため-1をする
for i in range(1,len(A)):
  S[i] = S[i-1] + (A[i] - A[i-1]-1)

#Kの処理  
for j in range(Q):
  K = int(input())
  
#①KがAの最大値より大きい場合の解答=[Aの最大値+(K-Sの最大値)]    
  if K > S[-1]:
    ans = A[-1] + (K - S[-1])
    print(ans)

#②KがAの最小値未満の場合の解答=[K]
#S[0]は(A[0]-1)なので>=で判定
  elif S[0] >= K:
    ans = K
    print(ans)

#③Aの間にKがある場合の解答=[２分探索した結果の値]
  else:
    X = binary_search(S, K)
    ans = (A[X] - 1) - (S[X] - K)
    print(ans)
```

以上
Python3.9でL4Tを使ったバックアップが失敗する

# Python3.9でバックアップ用のスクリプトがエラー終了
いつもの通り`flash.sh`でバックアップを取ろうとすると、
`AttributeError: 'ElementTree' object has no attribute 'getiterator'`
のエラーが出て完了できなかった。

## 解決策
ぐぐったらPython3.6の公式ドキュメントに、3.2から`ElementTree.getiterator()`がdeplecatedになっていると書いてあった。
どうやら新しく環境を作ったときにバージョン指定してなかったらPython3.9になって、それまでdeplecatedだった`getiterator()`が削除されていた？らしい。
呼び出し箇所（手元だとtegraflash_internal.pyの2109行目）を、`iter()`にしてあげると無事に通った。

最新のL4Tを落としてくれば修正されているのかもしれないが、容量が大きいので時間がかかるし……とりあえず動いたみたいなのでこのままバックアップが成功したら良しとしておこう。
【レポート】3つ以上のオブジェクトを跨ぐレポートを作成する方法


## はじめに

### 自己紹介
Webエンジニア&Salesforce開発者として勤務しております。@[株式会社ダイアログ](https://www.dialog-inc.com/)
Salescloudはまだ触り始めたばかりなのですが、AppExchangeに公開しているアプリケーションを開発しておりまして、その過程でSalescloudを触り始めたので、記事を書いてみたいと思いまとめました。

間違いなどがあるかもしれませんが、その時は後学のため、他の方のためにもご指摘いただけますと幸いです。
よろしくお願いします。

### 背景
Salescloud内の「サービス」アプリケーションの項目で「レポート」という機能があります。

参照項目を持っているオブジェクト同士なら`hogehogeに関連するfugafugaのレポート`という感じでレポートを作成できるのですが、3つ以上のオブジェクトが関連する場合、どうすればいいのか悩み、解決したためまとめます。

### 記事の対象者
- Salescloudの用語の知識がある方
- レポートで3つ以上のオブジェクトが関連するレポートを作成したい方
- 参照関係を持たせる方法自体は知っている方

## 方法

### 先に結論
①オブジェクト同士に参照項目を持たせる
②カスタムレポートを作成してから、レポートの作成を試みる

順を追って説明します。

### 具体的な説明

現状の課題は、以下の画面に作成したい**3つ以上のオブジェクトが紐づいたレポート**が出てこないことです。
![スクリーンショット 2021-06-14 22.00.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557847/5b6e9f8a-2281-95a3-1111-2a9a7a843a87.png)

まず、オブジェクト同士に参照関係を持たせます。
こちらに関しては記事の対象者の方は知っている前提なので、申し訳ありませんが割愛します。
3つのオブジェクトで参照関係を結んでください。

---

次に、設定＞レポートタイプより、カスタムレポートタイプを開きます。
![スクリーンショット 2021-06-14 22.02.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557847/7958dcf3-6718-d92e-0987-70424dd0359a.png)

初回は上記のページが出るので、次へを選択してください。

そうすると「新規カスタムレポート」というボタンが表示されるのでそこをクリック。

![スクリーンショット 2021-06-14 22.08.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557847/77f9b18e-353a-3d4c-c061-4bbcbdb68a2d.png)

項目を埋めていきます。
主オブジェクトに関しては、レポートにしたい項目のうち一番メインとなるものを選択しましょう。

今回カテゴリは、その他のレポートに追加しました。

では、次へをクリックします。

---

ここがポイントです。オブジェクト同士を関連させるページが出てきてくれます！
ここで、参照関係を持たせていれば3つ以上のオブジェクトを選択することができます。
![スクリーンショット 2021-06-14 22.08.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557847/34d6ee45-1cb6-2d58-7fd0-d4ddbbb681b4.png)

保存したら、サービス＞レポートを開いて、「その他のレポート」を選択してみましょう...
![スクリーンショット 2021-06-14 22.11.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557847/38ba0d99-35d0-adba-5cb9-61d723dd2dd3.png)

バッチリ表示されていますね！選択して作成してみると...
![スクリーンショット 2021-06-14 22.11.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557847/48067e2b-1f59-b60d-0177-ba711fc12287.png)

注文、注文フィード、commentsのオブジェクト3つが表示されています。
以上、3つ以上のオブジェクトが関連するレポートの作成方法でした。

#### おまけ
Twitterにいるので、ぜひ情報交換したいです！
お気軽にご連絡ください。[yuki](https://twitter.com/yuki82511988)
[WWDC 2021] App Privacy Report メモ

[WWDC 2021] Apple’s privacy pillars in focus の中でもとりわけ重要そうだった App Privacy Report のメモを先に残しておきますので、皆様の参考になれば幸いです。

[Apple’s privacy pillars in focus - WWDC 2021 - Videos - Apple Developer](https://developer.apple.com/videos/play/wwdc2021/10085/?time=884)

App Privacy Report はビデオの 14:44 ~ 18:54 で紹介されてます。

---
# 概要
* New section in Settings
	* 設定アプリのプライバシーから App Privacy Report を確認出来るようになる
	* 使用履歴はクリアすることもできる
* Shows app accesses to data
	* アプリがどのユーザデータにアクセスしたのか一覧表示される
* Shows app contacts to domains
	* アプリがデータを共有した可能性のあるドメインが一覧表示される**（サードパーティSDKも含めて）**
* Comings in an update to iOS15
	* 今後iOS15へのアップデートで利用可能になる

---
# Record App Activity

**重要：
Record App Activity 画面でアプリのアクティビティを記録できるようになるので（ユーザから問い合わせが入る前に）早めに確認した方がよさそう。**

（もうサードパーティSDK側では動き出しているのだろうか？）

[15:33]あたり原文まま

> In iOS 15, Record App Activity provides export functionality for you to better understand your apps' behaviors. So, you'll want to grab the iOS 15 beta and turn on Record App Activity to get a head start on what people will see for your app in the App Privacy Report feature. Then, when you select Save App Activity, iOS will produce a JSON file. You should review the content of this JSON file to confirm your app behaves as expected.
> 
> iOS 15では、アプリアクティビティの記録により、アプリの動作をよりよく理解するためのエクスポート機能が提供されます。 そのため、iOS 15ベータ版を入手し、[アプリアクティビティの記録]をオンにして、アプリのプライバシーレポート機能でアプリのユーザーに表示される内容をすぐに確認することをお勧めします。 次に、[アプリアクティビティの保存]を選択すると、iOSはJSONファイルを生成します。 このJSONファイルの内容を確認して、アプリが期待どおりに動作することを確認する必要があります。

---
# JSONの確認方法

上記 [Save App Activity] で保存したJSONでアプリが connect したドメインを確認する方法

[16:34]あたり原文まま

> To see all the domains you've contacted, look below the section marker in JSON: there's a final dictionary. This uses bundle IDs for keys, so there's one dictionary for each of your app's executables. From there, you can see all domain contacts, when they were initiated, and if they were app or user-initiated.
>
> 連絡したすべてのドメインを確認するには、JSONのセクションマーカーの下を見てください。最終的な辞書があります。 これはキーにバンドルIDを使用するため、アプリの実行可能ファイルごとに1つの辞書があります。 そこから、すべてのドメイン連絡先、それらがいつ開始されたか、およびそれらがアプリまたはユーザーによって開始されたかどうかを確認できます。

---
# アプリによる接続とWebサイトによる接続の違い
* SafariViewController と ASWebAuthenticationSessions で作成された接続はWebサイトによる接続として自動的にタグづけされる
	* （それ以外はどうなるのか不明）

---
# 手動でのタグづけ方法
* アプリ内でのWebアクセス時に手動でタグづけするための列挙型が追加された（指定しない場合はアプリのトラフィックとしてマークされるらしいがタグづけとどう違うのかよく分からない）
	* NSMutableURLRequests
	* NWConnection
	* sockets
* WKWebView にはタグづけするための新しいメソッドが追加されたらしい
	* 詳細は [Explore WKWebView additions - WWDC 2021 - Videos - Apple Developer](https://developer.apple.com/videos/play/wwdc2021/10032/)

（詳細はまだ確認出来ていないが、これはアプリ側のタグづけ対応とSDK側のタグづけ対応が必要になるということだろうか？おそらくSDK側にはタグづけしてもらわないとアプリ側では判別できない気がする。誰かご存知 or 試した方がいらしたら記事にしてください！）

---
**感想：**
App Privacy Report の説明の最後の方で「アプリはユーザが期待するデータと時間にのみアクセスする必要がある」と言っているように、アプリ開発者はサードパーティSDKが何をしているのか（どのドメインにいつアクセスしているのかも）明確に責任を持つということになる。確かに前からそのようなアナウンスはされていたが、まさかここまで明確になるとは思っていなかった。
今年もまたプライバシー周り、特にサードパーティSDK周りで振り回されることになるのかな。

不慣れな英語を翻訳しながらまとめているため、誤訳や認識違いがあるかもしれないのでご注意ください。
python set型

#python set型

pythonのset型とは、集合を扱うための型
リスト型のように、set型も同じく複数の値を格納できる型

**リスト型との違い**
・重複した要素を持たない
・要素に順番がない

**set型の基本的な使い方**
set_1 = {1, 2, 3, 4}
print(set_1)
list_a = [1, 2, 4, 6, 8]
set_2 = set(list_a)
print(set_2)

**メソッド**
add : setに要素を追加する。
remove : setから要素を取り除く。指定した要素が無いときはエラーが出る。
discard : 指定した要素がsetに含まれている場合、それを取り除く。要素が含まれていなかったときはスルーする。


set.add
set.remove
set.discard
【PHP】staticプロパティを使用したサンプルソース

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954863/725adff9-b67b-8d4f-130c-b15a95b91e43.png)

```php
<?php
class Cat {
  public static $count = 0;
  public $name;
  public $age;

  public function __construct($name, $age){
    $this->name = $name;
    $this->age = $age;
    self::$count++;
  }
  public function shout(){
    echo 'にゃー!'.PHP_EOL;
  }
  public function introduce(){
    echo '名前は' . $this->name . '、' . $this->age . '歳です'.PHP_EOL;
    $this->shout();
  }
}

$cats = [];
$taro = new Cat('太郎', 3);
$cats[] = $taro;

$mike = new Cat('ミケ', 5);
$cats[] = $mike;

$tama = new Cat('タマ', 4);
$cats[] = $tama;

foreach($cats as $cat){
  $cat->shout();
  $cat->introduce();
}

echo '今までに作成したCatインスタンスの数: ' . Cat::$count;
```
WinSCP AWS S3と接続する

新しいセッションを開きます。転送プロトコルで「Amazon S3」を選択します。アクセスキーIDとシークレットアクセスキーを入力します。ログインをクリックします。通信プロトコル SFTP ではなく HTTPS です。

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/26604218-b77d-9184-b050-715714f585cd.png)

設定をクリックすると高度な設定ができます。今回はTLSバージョンの設定をしました。ただし、TLS1.3には対応していないようです。エラーになりました。

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/6fcb9cb2-845a-ac22-fb75-5f54d85fd9e0.png)

接続するとバケット一覧が表示されます。WinSCPではここがルートです。

![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/36d605b3-cc35-113a-46f0-bb184948fe4e.png)

バケット内に入るとファイルを見ることができます。見慣れた光景です
。

![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/50fe708a-6256-92e1-7603-b81b72066ce4.png)

ファイル転送もドラッグアンドドロップで一発です。CLIよりも非常に簡単です。

![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/be2c52bc-6d23-d8c5-5878-21c92fab4e74.png)

ログの設定はこちらからできます。

![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/20abe7c9-b9e5-c4bf-e210-4a4aeb246043.png)

ファイルをダウンロードしたログが残っています。監査に使えそうです。

```
. 2021-06-14 22:02:43.949 Transfer done: '/account-a-bucket-0525/sample.txt' => 'C:\Users\user\Documents\AWS\S3 WinSCP\sample.txt' [5]
```

TLSバージョン、暗号化スイートも確認できました。

```
. 2021-06-14 21:27:22.517 Using TLSv1.2, cipher TLSv1.2: ECDHE-RSA-AES128-GCM-SHA256, 2048 bit RSA
```

WinSCPすごいです。
これでVPN接続もできたら最高なのですが・・・
踏み台は立てたくないですし。
ご存知の方がいらっしゃいましたらご教示いただけますと幸いです。

# 参考記事

https://winscp.net/eng/docs/guide_amazon_s3
関数型インターフェースについて

# 関数型インターフェースについて

JavaSilverSE11の勉強中、関数型インターフェースに関する問題を解いて、色々特徴があってややこしいと感じたので関数型インターフェースについて調べてまとめてみました。
<br>
<br>


<a id="#Chapter1"></a>
# 関数型インターフェースとは？
関数型インターフェースは抽象メソッドが一つだけ定義されているインターフェースのことです。

なお、staticメソッドやデフォルメメソッドが含まれていても抽象メソッドが一つだけあれば関数型インターフェースとなります。
<br>
<br>

<a id="#Chapter2"></a>
# 主な関数型インターフェース
主な関数型インターフェースは以下の4つとなります。
これらはjava.util.functionパッケージとして提供されています。

|関数型インターフェース | メソッド | 説明 | 
| --- | --- | --- | 
|Consumer＜T＞|void accept(T)|引数を受け取って処理をするが、結果を戻さない。引数の「消費者」と呼ばれる。| 
|Suppleier＜T＞|T get()|何も受け取らずに結果だけを戻すため、引数の「供給者」と呼ばれる。| 
|Predicate＜T＞|boolean test(T)|引数を受け取ってそれを評価するため、「断定」と呼ばれる。| 
|Function＜T,R＞|R apply(T)|引数を受け取って指定された型(R)の結果を戻すため、「処理」と呼ばれる。| 

<a id="#Chapter3"></a>
# まとめ
上記であげた4つの関数型インターフェースはそれぞれ特徴を覚えるのがややこしいと思いますが、

以下の点を覚えておけば判別がつきやすいと思います。

・Function＜T,R＞は4つの関数型インターフェースの中で唯一、`複数の引数を受け取ることができる`。

・Predicate＜T＞は、`引数で受け取った値を判定する`。

・Consumer＜T＞は、`結果を戻さない`。

・Suppleier＜T＞は、引数など`何も受け取らない`。

<br>
<br>

<a id="#reference"></a>
# 参考文献
- [https://www.yoheim.net/blog.php?q=20160410]

- [https://itsakura.com/java-function]
Vue.js(+TypeScript)で外部jsonファイルを直接importする方法

##1.そのままimportしてみる

```hoge.vue
import jsonData from '@/assets/hoge.json'
```

すると、エラーが。

```
Module '@/assets/hoge.json' was resolved 'hogehoge/src/assets/hoge.json', but '--resolveJsonModule' is not used.
```

##2.結論

``tsconfig.json`` の ``compilerOptions`` に ``resolveJsonModule`` を追加する

```tsconfig.json
{
  "compilerOptions":
    "resolveJsonModule": true,
・・・後略
```

##3.後記

コンソールを見ればそう書いてあるのに、なかなか気づかないというのも自分の問題ですね・・・
v4l2デバイスをGUIから設定

普通のUSBカメラはubuntuにv4l2デバイスとして認識されます。
そしてカメラの内部設定はv4l2のコマンドから設定することができます。
この設定をGUIからできるアプリケーション```v4l2ucp```を使ってみます。

```bash:環境
ubuntu 18.04
```

```bash:install
sudo apt-get install v4l2ucp
```

```bash:実行
v4l2ucp {v4l2デバイス名}

例.
v4l2ucp /dev/video2
```
実行すると次のようなGUIが表示され、カメラの内部設定を変更することができます。
![Screenshot from 2021-06-14 21-56-32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/589906/4d251ed8-c0f4-570b-3e05-89fc9e294707.png)

# こっちのほうが細かい設定できそう???

https://github.com/azeam/camset

## install

```
sudo apt-get install python3 python3-pip v4l-utils pkg-config
pip3 install camset
echo 'export PATH="$PATH:$HOME/.local/bin"' >> ~/.bashrc
```

## 実行

```
camset
```

![Screenshot from 2022-02-01 17-58-55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/589906/545b7682-78ac-2730-63c9-2d91f425981a.png)
NULLをテキストファイルに書き込む方法

# NULLをテキストファイルに書き込む方法

rubyを使っています。

レビューで目撃したのでメモ

```
ruby -e 'print "\000"' | cat -e
```


## シェルのみで書き込む方法

コメントで教えてもらいました。追記します。2021/06/20
シェルだけでやりたいと思っていたので、感謝。

```
printf '\0' | cat -e
```
【初心者でもわかる】aタグによく使う属性たち一覧

#どうも7noteです。aタグによく使う・使える属性をまとめました

**「aタグ`<a hrf=""></a>`」** → リンクを設置するための要素

## href属性(リンク先の指定)

```html
<a href="https://hogehoge.com"></a>
```
aタグの属性の中で主役となる**「href属性」**ですね。
これがなくてはaタグの属性の話は始まりません。

初心者のうちはimgタグにつかう属性のsrc属性と混合してしまう方もいるので間違えないように注意しましょう。

またhrefの値に#を使うことで、指定したID名の要素の位置までスクロールさせることができます。

例）id名hogeまでスクロールする

```html
<a href="#hoge"></a>
```

## target属性(リンク先の表示方法を指定)

```html
<a href="https://hogehoge.com" target="_blank"></a>
```

hrefと合わせて次に使うことが多いのがこの**「target属性」**。
特に`target="_blank"`として使うことが多いです。

`target="_blank"`は**別ウィンドウで開く**表示方法になります。
`_blank`以外にも、`_self`や`_parent`などがあります。

## rel属性(リンク先との関係性を明示)

```html
<a href="https://hogehoge.com" rel="nofollow"></a>
```

rel属性は**指定したリンク先との関係性**を表すことができます。
その中でも使う頻度が高いのが、`rel="nofollow"`。

これは「リンク先にはこのホームページのSEOの評価を渡さないよ」という意味になります。
SEO（検索エンジン最適化）において、ページの評価はとても重要です。
googleで検索上位に入りたいサイトなどであれば、自分のサイト以外へのリンクには`rel="nofollow"`を入れておいたほうが良いとされています。

※あくまでSEO対策の1つとして言われていることのため、これだけで検索順位が上がる事は保証できませんのであしからず。

他にもrelには前後のページであることを示す`next`、`prev`などがあります。

詳しくは以下の記事が見やすかったのでご覧ください。
https://reference.hyper-text.org/html5/attribute/rel/

## 他の属性

他にも、`name`や`charset`、`tabindex`などいくつかありますが、通常のWEBページを作る上では上の3つがあればだいたいなんとかなるかと思います。

もっと知りたい方は以下より。
https://www.tagindex.com/html_tag/elements/a.html

## おまけ(aタグをクリックしたときにjavascriptを起動させる)

aタグをクリックした際にjavasriptを起動させるために`onClick=""`を指定する方法がありますが、それよりは以下の方法がオススメです。

```html
<a href="javascript:OnLinkClick();"></a>
```

## まとめ

aタグといっても、単にリンクを設置するだけではなく、どうリンク先を開くのか、そのリンク先との関係性はどうなのかを確認しながら設置する必要があります。

ただ**教本にはhref以外の属性についてはあまり触れていなかったり、webで属性を調べると逆に情報が多すぎて混乱してしまうので、実践で実用的なものを紹介しました。**

inputなどのフォーム系のタグや、link、metaタグの次に属性が使われやすいタグかなと思ったので記事としてまとめてみました。
私個人が使っていないだけで、この属性もこんなふうに使いますよなどがあればぜひコメントください。

参考：
https://www.ipentec.com/document/javascript-exec-javascript-on-hyperlink-click
https://www.tagindex.com/html_tag/elements/a.html
https://reference.hyper-text.org/html5/attribute/rel/



#### おそまつ！
~ Qiitaで毎日投稿中!! ~
[【初心者向け】WEB制作のちょいテク詰め合わせ](https://qiita.com/7note)
コード品質を構成する要素②【カプセル化】

[コード品質を構成する要素 【凝集性・疎結合】](https://qiita.com/Jazuma/items/e9bb3eda401bfd29a3d9)に続いて保守性の高いコードを書くための知識を整理します。

今回はカプセル化を扱います。


## カプセル化

(入門用の教材でよく言われているように)カプセル化 = プロパティやメソッドを非公開にすること ではないようです。 ではカプセル化とは何かと言うと**「何をやっているか(ふるまい)ということと、どうやっているか(実装)を切り離す」**ことと定義されています。

具体例を出して考えてみます。

Personクラスが次のように定義されている場合、外部からPersonオブジェクトのフルネームを取得するにはどうすればよいでしょうか。

```java:Person.java

private String firstName;
private String lastName;

public String getFirstName() {
  return this.firstName;
}

public String getlastName() {
  return this.lastName;
}
```

パッと思いつくのは下記のようなコードではないでしょうか？(クラス定義など不要な箇所は省略)

```java:hoge.java

public String getPersonName(Person person) {
  return person.getFirstName() + person.getLastName();
}
```

一見問題ないように思えます。しかし、例えば外国籍のユーザが増えてフルネームにミドルネームを含めるように変更された場合に問題が発生します。

・ PersonクラスにmiddleNameプロパティとmiddleNameのgetter setterを追加する
・ hogeクラス内のgetPersonNameメソッドでmiddleNameを含めて値を返すように変更する

というように2つのクラスを変更しなければなりません。 この程度の短いコードであれば大きな問題にはなりませんが、プロダクトの規模が大きくなると変更コストが莫大なものになります。

ではどうすれば変更コストを小さくできるかと言うと、

・ Personクラス内でフルネームを取得するgetterを定義する
・ hogeクラスはそのgetterを呼び出す

というようにすると良いでしょう。具体的なコードは以下のようになるでしょうか。


```java:Person.java

private String firstName;
private String lastName;

public String getFirstName() {
  return this.firstName;
}

public String getlastName() {
  return this.lastName;
}

// フルネーム取得
public String getFullName() {
  return this.getFirstName() + this.getLastName();
```



```java:hoge.java

// Personオブジェクトの実装に依存せず、単にフルネームを返す
public String getPersonName(Person person) {
  return person.getFullName();
}
```

この例では**「Personオブジェクトのフルネームを取得するというふるまいと、どうやってフルネームを取得するのかという実装」** を分離することができています。 ミドルネームがあろうとなかろうと外部からgetPersonNameメソッドを呼び出せばフルネームを取得できるわけです。


2つ目の例には以下のようなメリットがあります。

- 仕様変更時の改修コストが小さい(例： PersonクラスにmiddleNameプロパティを追加する場合に変更箇所が1か所で済む)

- Personオブジェクトの情報はPersonクラス内で保持・管理するのでクラスごとの責任範囲が明確になる。


カプセル化によりモジュールごとの役割が明確になり、メンテナンスしやすいプログラムになると言えるでしょう。
binding.pry 様様

#はじめに#
投稿機能を実装し、投稿ボタンを押してるのに投稿できない！エラー文も何も出ない！（涙）
原因はわからないがとりあえずMVCの流れに沿って考えてみよう！！

#予想#
おそらくリクエストを送っているビューか、受け取っているコントローラーが問題となっていそうです。
どちらが原因となっているか判断するために、コントローラーにbinding.pryを記述し確認してみよう！

#実際にやってみよう#

```app/controllers/posts_controllers.rb
def create
    binding.pry
    @poststag = PostsTag.new(post_params)
    if @poststag.valid?
      @poststag.save
      return redirect_to root_path
    else
      render "new"
    end
  end
```


```ターミナル.
[2] pry(#<PostsController>)> post_params
=> <ActionController::Parameters {"title"=>"test", "name"=>"testtag", "user_id"=>1} permitted: true>
```
今回保存したいカラムは"title","text","name","user_id"なのにpost_paramsの中に"text"が入ってない！！！

#原因#

```app/views/posts/new.html.erb
<div class="message-field">
      <%= f.label :title,  "タイトル" %>
      <%= f.text_area :title, class:"input-message" %>
    </div>
    <div class="message-field">
      <%= f.label :title,  "本文" %>
      <%= f.text_area :title, class:"input-message" %>
    </div>
    <div class="tag-field", id='tag-field'>
      <%= f.label :name, "タグ" %>
      <%= f.text_field :name, class:"input-tag" %>
    </div>
```
今回はビューに問題があり"title"が重複していることがわかりました。

```app/views/posts/new.html.erb
<div class="message-field">
      <%= f.label :title,  "タイトル" %>
      <%= f.text_area :title, class:"input-message" %>
    </div>
    <div class="message-field">
      <%= f.label :text,  "本文" %>
      <%= f.text_area :text, class:"input-message" %>
    </div>
    <div class="tag-field", id='tag-field'>
      <%= f.label :name, "タグ" %>
      <%= f.text_field :name, class:"input-tag" %>
    </div>
```

真ん中の本文の部分を"text"に変え無事に投稿できました

#諦めない#
今回デバッグの処理の仕方を復習することができなぜ任意の処理ができないのか？どこが原因なのか？を深く考えることができました。
エラーが出ても俺なら絶対にできるという諦めない
見れば絶対受かる！LPIC 全試験受かったので細かく解説

※youtubeに動画で解説してます
-
https://www.youtube.com/watch?v=knv-yCyrouY

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/924512/8d2f719d-9aaa-51e9-5230-5cc1b194f5c0.png)
John the ripperでハッシュ解析してパスワードクラック

※youtubeに動画で解説してます
-
https://www.youtube.com/watch?v=1599LzaWL1M

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/924512/c22e1253-2149-2c3e-cbba-3d0b443113af.png)
クロージャって何？？

##クロージャとは
クロージャとはスコープ内の変数や定数を保持した再利用可能なひとまとまりの処理のこと。
関数がクロージャの一種であることから、クロージャと関数は共通する点が多い。

## 定義方法
関数はfuncキーワードによる定義が必要だが、クロージャはクロージャ式という定義方法で定義する。

```　swift:
{ (引数名1: 型, 引数名2: 型...) -> 戻り値の型 in
	処理
	...
	return 戻り値
}
```

## 実行方法
クロージャの呼び出し方は、クロージャが代入されている変数や定数の末尾に()をつけて呼び出す。

``` swift:
// 定義したクロージャを定数に代入
let sumFunction = { (x: Int, y: Int) -> Int in
    return x + y
}

// クロージャを代入した定数名の末尾に()をつけて呼び出す
let result = sumFunction(1, 2)  // 3
```

## クロージャの特徴
### 変数と定数のキャプチャ
クロージャはクロージャ自身が定義されたスコープ内の変数や定数への参照を保持するキャプチャ機能がある。通常ローカルスコープで定義された変数や定数はローカルスコープ内でしか使用することはできないが、クロージャはキャプチャ機能により、ローカルスコープ外でクロージャが実行されても変数や定数を利用することができる。

``` swift:
let double: (Int) -> Int
do {
    let two = 2
    double = { num in
        return num * two
    }
}

// ローカルスコープ外でクロージャgreetingを実行しても
// ローカル変数symbolを利用することができる
double(3)  // 6
```

また、クロージャによるキャプチャの対象は、変数や定数に格納されている値ではなく、その変数や定数自身をキャプチャしている。そのため、キャプチャしている変数や定数の値の変更はクロージャ実行時に反映される。

``` swift:
let exponentialGrowth: () -> Int
do {
    var count = 1
    exponentialGrowth = {
        count *= 2
        return count
    }
}

exponentialGrowth()  // count == 2

// 前回実行時の変数countへの変更が反映されている
exponentialGrowth()  // count == 4
exponentialGrowth()  // count == 8
```

## 参考資料

https://gihyo.jp/book/2020/978-4-297-11213-4
nuxtjs/composition-apiでクエリ(URLパラメータ)を取得して、ページ遷移する

### nuxtjs/composition-apiでクエリ文字列を取得する
```js

<script lang="ts">
import { defineComponent, useRoute, computed } from '@nuxtjs/composition-api'

export default defineComponent({
  setup () {
    const route = useRoute()
    const query = computed(() => route.value.query)
  }
})
</script>
```

useRouteをimportして、`route.value.query`にアクセスすれば取得できる

### nuxtjs/composition-apiで他のルートに遷移する

```js

<script lang="ts">
import { defineComponent, useRouter, computed } from '@nuxtjs/composition-api'

export default defineComponent({
  setup () {
    const router = useRouter()
    router.push('/')
  }
})
</script>
```

今度は`useRouter`をimportして、`router.push('/')`と記述すればトップページに遷移する
medusaで辞書攻撃によるパスワードクラック

※youtubeに動画で解説してます
-
https://www.youtube.com/watch?v=fXtRRi1Sxu8&t=217s

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/924512/255d2792-844c-2928-172d-37ac8588e363.png)
Hinemosを超絶分かりやすく設定していく

※youtubeに動画で解説してます
-
https://www.youtube.com/watch?v=3Zuu_68hB8Q

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/924512/666c9448-13d0-f443-1737-6b263179ead2.png)
Hinemosを超絶分かりやすく構築していく

※youtubeに動画で解説してます
-
https://www.youtube.com/watch?v=iFsZWXD8jbc&t=220s

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/924512/5bc751e8-9a2a-d25f-bdb5-054b6d79591b.png)
MySQLのデータ保存先を変更して使えるようにする

# 概要
Macでデータの保存先をハードディスクなどにした状態でMySQLに接続できるようにします。

# やること
以下を記述する

```shell:/usr/local/etc/my.cnf 
datadir=/Volumes/SSD_dsk/mysql
```

mysqlのデータを移す

```
$ cp -prf /usr/local/var/mysql/ /Volumes/SSD_dsk/mysql

$ mysql -u root

show variables like 'datadir';
+---------------+-------------------------+
| Variable_name | Value                   |
+---------------+-------------------------+
| datadir       | /Volumes/SSD_dsk/mysql/ |
+---------------+-------------------------+
```

もし動かない場合は

```
$ mysql.server restart
```

または、アクティベートする。

```
$ source activate base
$ mysql.server start
```

## 参考サイト
http://tukaikta.blog135.fc2.com/blog-entry-197.html
Laravel textarea 改行反映

#はじめに
投稿するテキストエリア内で改行したのに表示される画面だと改行が反映されてない。
割と簡単にできたのメモ。
Laravelのbladeテンプレート使います

```Article.blade.php
<p>{{$post->body}}</p>
```

Laravelの二重中括弧は、htmlspecialchars()関数を通した表示になっています。
XSS対策を初めからやってくれてるんですね。

つまり`{{$post->body}}`　= `echo htmlspecialchars($post->body)`てことです。
これを踏まえて、改行を表示していく。

#PHPの nl2br()関数
この関数を使えば 改行がある位置に改行を示すHTMLタグを挿入することができる。
なので
`nl2br(htmlspecialchars($post->body))`
これでいける！と思いきやこれだとうまくいきません。
二重括弧に入れているのでエスケープ処理が実施されてしまって
ただの文字列として表示されちゃう。

bladeテンプレートエンジンでは、エスケープ処理をしないデータ表示の構文がある。
`{!! !!}`
これで囲んじゃえばいいだけです！

#まとめ
以上から
`{!! nl2br(htmlspecialchars($post->body)) !!}`
これOk。
【CPUの動作原理】基本情報技術者試験のためのコンピュータの構成

※この記事は
「栢木先生の基本情報技術者教室」を参考に学んだことをまとめた記事です。

* **レジスタ** とはCPUに内臓されている高速な記憶装置のこと
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/965248/b230d070-0a3b-660a-ecb5-d13edd7d8c5e.png)

* **命令語** とは「1」と「0」の機械語のこと
* 機械語の命令後は、「命令部」と「アドレス部(オペランド部)」で構成されている
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/965248/f09bb8f2-c7ee-a978-c84d-0cb33af83486.png)

* **命令実行サイクル** は
「命令の取り出し」⇨「命令の解読」⇨「実行アドレス計算」⇨「オペランドの取り出し」⇨「命令の実行」⇨「演算結果の格納」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/965248/a703c219-7891-8d58-090b-87ab7a89595f.png)

**①命令の取り出し**
命令アドレスレジスタを参照、命令が格納されているアドレスの取得。取得したアドレスから命令を取り出し(**命令フェッチ**)、命令レジスタに格納

**②命令の解読**
命令レジスタの命令部がデコーダ(解読器)で解読される

**③実効アドレス計算**
命令レジスタのアドレス部の値はアドレスレジスタに送られ、処理対象データが格納されているアドレス(実効アドレス)を計算する

**④オペランドの取り出し**
処理対象のデータを取り出し、演算装置に送る

**⑤命令の実行**
演算装置で演算実行

**⑥演算結果の格納**
演算結果を格納する

* **アドレス指定方式** とは、命令アドレス部の値から処理対象データが格納されている実効アドレスを求める方式
* アドレス指定方式は6種類(即値・直接・間接・相対・指標・基底アドレス方式)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/965248/3db35d7b-b78b-238c-0b21-6f58b866dfeb.png)
Pandas df操作(欠損値/行列名変更・取得/csv出力/行・列の除去/結合)

# 項目
1. 欠損値に対する処理
2. 行・列名の変更
3. 行・列名の取得
4. dfをcsvとして出力
5. 行・列の除去
6. dfの結合


# 1.欠損値に対する処理
## 欠損値の除外
```python:python
#全ての値が欠損しているものの除外
#how = "all"
#欠損値を含む行の削除
df.dropna(how = "all")

#欠損値を含む列の削除
df.dropna(how = "all", axis = 1)

#行、列共に削除したい場合はそれぞれ適用する
df.dropna(how='all').dropna(how='all', axis=1)

#-----------------------------------
#欠損値が一つでも含まれるものの処理
#how = "any"
#行の削除
df.dropna(how = "any")

#欠損値を含む列の削除
df.dropna(how = "any", axis = 1)
```

## 欠損値の置き換え
```python:python
#欠損値の置き換え
#fillna()
#共通の値に置き換え
df.fillna("num")

#列ごとに異なる値で置き換え
#引数で辞書を使う
df.fillna({"id":0, "name":"null"})

#-----------------------------------

#平均値、中央値、最頻値での置き換え
#平均値
#下記の場合は全てを平均値で、列ごとは列指定で
df.fillna(df.mean())

#中央値で
df.fillna(df.median())

#最頻値で
df.fillna(df.mode().iloc[0])

#前後の値で置き換え
#前の値をいれる
df.fillna(method='ffill')

#後ろの値をいれる
df.fillna(method='bfill')
```

## 欠損値があるものの抽出
```python:python
#欠損値がある列や行を取り出す
#isnull()
#欠損値の含まれているレコード
df[df['カラム'].isnull()]

#特定の行の欠損値があるカラム
df.iloc[0].isnull()

#欠損値が一つでも含まれる行・列
#isnull().any()
#axis=1で行、axis=0で列
df2.isnull().any(axis=1)
```

# 2.行・列名の変更
## 任意の行・列名変更
```python:python
#dfが再発行される
#カラムの変更
#rename(columns={"元の名前":"変更後の名前})
#レコードの変更
#rename(index={"元の名前":"変更後の名前})
df.rename(columns={'A': 'new_A'}, index={'ONE': 'new_one'})
```

## 複数の行・列名変更
```python:python
#複数の変更
df.rename(columns={'A': 'new_A', 'C': 'new_one'})
```

# 3.行・列名の取得
## カラム名
リストで取得

```python:python
df.columns.values()
```

## 行名
```python:python
df.index.values()
```

# 4.dfをcsvとして出力
```python:python
#to_csv("ファイル名", sep="区切り文字", index="True or False"(行名を出すか、Trueなら出力), encoding="文字コード")
df.to_csv("csvファイル名", sep=",")
```

# 5.行・列の除去
## カラム・レコードが除去された新しいdfを出力
```python:python
#drop("カラム名", axis=1)
#またはdrop(columnns=["~~~"], index=["~~~"])
df_new = df.drop("column", axis=1)

#複数の場合は引数を行列に
df_new = df.drop(["column","column_2"], axis=1)
```

## 元となるdfから直接除去
```python:python
#del df["~~~"]
del df[["column","cplumn_2"]]
```

# 6.dfの結合
## 内部結合
```python:python
#pd.merge(df_1, df_2, on="keyのカラム")
pd.merge(df_1, df_2, on="id")

#カラム名が違う場合
pd.merge(df_1, df_2, left_on='id', right_on='id_2')
#これでやるとkeyにした二つのカラムがそのまま残るので、この後にdropなどで除去しておく
#こんな感じで一気にやってもOK
pd.merge(df_1, df_2, left_on='id', right_on='id_2').drop(columns='id_2')

#-----------------------------------

#引数にしたいカラムが複数ある場合
pd.merge(df_1, df_2, on=["id","name"])

#複数かつ違う場合
pd.merge(df_1, df_2, left_on=["id","name"], right_on=["id_2","name_2"]).drop(columns=["id_2","name_2"])
```

## 結合方法の指定
```python:python
#内部結合
#how="inner"
pd.merge(df_1, df_2, on="id", how="inner")

#外部結合
#how="outer"
#値が存在しない場合はNaNになる
pd.merge(df_1, df_2, on="id", how="outer")
```
SIPとは？

## 勉強前イメージ

RTPを調べてるときに一緒に出てきたから
なにかのプロトコル？なのかな？

## 調査

### SIPとは

Session Initiation Protocol の略で、
相手との通信経路(セッション)の確立・切断を行うプロトコルで、リアルタイム通信でよく使用されており、IP電話やVoIPなどが有名です。
セッションの生成、変更、切断を行うのみのプロトコルで、その上のデータについては定められていないですが
電話などの音声通信が多く見られます。

### SIPの通信方法

そもそもSIPはUser Agent(UA)と呼ばれる端末同士が直接通信できるようにするものです。

端末AからSIPサーバへ自分の電話番号・IPアドレスなどを含んだ情報を送り、
SIPサーバはそれをDBに登録します。
端末Bは接続先の端末Aの情報を記したメッセージをSIPサーバに送信、
するとSIPサーバはDBの中を見て一致した電話番号からIPアドレスを確認し、端末Aに発信メッセージを送ります。
端末Aは応答メッセージを送るとSIPサーバはそのまま端末Bに転送します。
晴れてお互いのIPアドレスを知ったので、後は [RTP](https://qiita.com/miyuki_samitani/items/d06e0e7505c6d42da397) で直接通話します。

下記の端末A,Bには `SIP URI(SIP Uniform Resource Identifier)` と呼ばれるアドレスが付けられています。

![1# SIPとは？ -.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129517/600cb06b-0b29-7d2b-f978-1874fc279d94.png)

## 勉強後イメージ

セッションの確立まで面倒を見る役割の人。
今回はセッションの確立までしか見てないけど.....
あまり触れたことないこと勉強できたかも？

## 参考

- [IP Telephony - SIP](https://www.infraexpert.com/study/telephony4.html)
- [5分で絶対に分かるSIP](https://www.atmarkit.co.jp/ait/articles/0711/16/news146_2.html)
VSCodeでRubyを気軽に実行する環境を作る(デバッガ付き

Ruby Debug プラグインのドキュメントに書いてあるのそのままですが・・・

* Rubyはrbenvでもなんでもいいのでインストール済みとする
* VScodeもインストール済みとする

##### Ruby : gemのreadaptをインストール
```
$ gem install readapt
```

##### VScode : Ruby プラグインをインストール
![r.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61393/7bd07454-5b51-7839-5431-bcca616d9248.png)


##### VScode : Ruby Debug プラグインをインストール
![rd.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61393/e5055625-69a0-fd07-ab7a-f00bcb08f997.png)


##### VScode : .vscode/lunch.jsonを追加して以下を記載

```
{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "ruby-debug",
            "request": "launch",
            "name": "Launch File",
            "program": "${file}",
            "programArgs": [],
            "useBundler": false
        }
    ]
}
```
これで、今開いているファイルをサクッと実行できます。
ブレークポイントなんかも効くので超便利

##### 注意

ブレークポイントで実行を止めている状態でVSCodeを終了するなど、readaptのプロセスが変な形で実行し続けてしまうとまともに動かなくなるのでその時はプロセスkillするかPC再起動で。