OmniAICreator/Qiita-1.07M huggingface dataset:
HTTPレスポンスをサービス内で処理すべきか（Angular）

# はじめに

Angular を学習しだして現在１ヶ月ほど。すでに作成されているアプリケーションに機能追加をするためにコード理解を進めているが、その中で**「HTTP によるバックエンドとの通信において、サービスにはどこまで処理をさせるべきなのか」**という疑問がわいた。調査してもあまり理解しきれなかったため、[Angular Japan User Group](https://angular-japan.discourse.group/) で質問したところとても丁寧に回答してもらえ、自分なりに納得できたためそれらをまとめる。ちなみに実際にした質問のリンクは[こちら](https://angular-japan.discourse.group/t/topic/327/13)。

[Angular Japan User Group](https://angular-japan.discourse.group/) には、質問をした当日に丁寧な回答をくださる方がたくさんいらっしゃり非常に助かったので、Angular でお困りのことがある人はぜひ相談してみるとよいと思います。

# 疑問

詳細に関しては[こちら](https://angular-japan.discourse.group/t/topic/327/13)の一連の流れを見てもらうこととし、疑問に関して簡単に説明する。

API からデータを取得するサービスにおいて、レスポンスの処理には以下2つのパターンが想定される。

1. サービスは HTTP リクエストを送って返ってきたレスポンスを渡すまでとし、**レスポンスの処理はコンポーネントで行う**
1. サービスは HTTP リクエストを送り、返ってきた**レスポンスの処理までサービスが行う**（コンポーネントは処理後のデータを受け取る）

私が読んでいたコードは上記 1 に相当しており、「1 は複数のコンポーネントで同一サービスを使用する際、似たような処理をそれぞれのコンポーネントで行う必要があるため冗長ではないか？**2 の方が適切ではないか？**」というのが私がもった疑問である。自分で軽く調査したり考えてみたものの、1 のパターンが肯定されるケース（1 のメリット）や 2 のパターンが否定されるケース（2 のデメリット）が自分で思いつかなかったため、Angular コミュニティに相談した、というのが一連の流れである。

ちなみに [Angular 日本語ドキュメンテーション - サービスの追加](https://angular.jp/tutorial/toh-pt4)では、以下記述があったことも疑問を強くした要因の一つである。

> コンポーネント内では直接データの取得や保存を行うべきではありません。もちろん、故意に仮のデータを渡してもいけません。 コンポーネントはデータの受け渡しに集中し、その他の処理はサービスクラスへ委譲するべきです。

# 結論

結論としては**「サービスで処理をすべき（※ただし複数考慮すべき点あり）」**である。誤解を多く招くと思うので、**考慮すべき点**というのを以下で述べる。

## 共通処理かどうか

「そのサービスの処理が各コンポーネントに対して共通処理であるか」を確認し、**共通であればサービス内で処理を行う。**たとえば、バックエンドから以下のようなデータ配列を取得する `UserService` というサービスを考えてみる。

```json
[
  user1: { age: 20, hobby: soccer },
  user2: { age: 55, hobby: traveling },
  ...
]
```

このとき、ユーザ一覧コンポーネントであれば欲しいデータは `[user1, user2, ...]` のようなユーザ一覧であり、ユーザ詳細コンポーネントであれば欲しいデータは `{ age: 20, hobby: soccer }` のような（あるユーザの）ユーザ詳細となる。この場合、サービスは共通処理とならないため、サービスでデータ加工などの処理まではすべきでない。（だからといって各コンポーネントで処理するのではなく、**サービスの分割によって別サービスとしてそれらの処理を行う方が望ましい**と考える。詳細は後述。）

## サービス名と責務の対応関係

「サービス名から想像がつく処理かどうか」を確認し、名前と責務が乖離していた場合は**対応するようにサービスを分離する。**上記の `UserService` の例だと、このサービスからユーザ一覧が得られるのか、それとも各ユーザの詳細情報が得られるのか、はたまたユーザデータ全体を得られるのかといったことが名前からわからない。もしユーザ一覧とユーザ詳細の2パターンの処理を行うのであれば、1つのサービスで処理すべきでなく、責務が名前からわかるようなサービスに分割する。たとえば、ユーザ一覧取得サービス `UserListService` とユーザ詳細取得サービス `UserDetailsService` のように分割して、それぞれのサービス内で処理をする。

またこの際、各サービスにて HTTP 通信の部分は共通するため、この部分はさらに `UserApiService` ようなサービスに分割してあげるとより見通しがよくなる。

# おわりに

サービスの処理に関して、Angular コミュニティにて質問した内容をまとめた。自力で調べたり考えたりする力はもちろん必要だが、このようなコミュニティの有識者の方に尋ねるとより高い視点からの意見をいただけるので、物怖じせずどんどん聞いていこうと思う。
GithubとVScodeの連携

#はじめに
コマンドを実行してGithubにpush、pullしていましたが、
Visual Studio Codeと連携することでクリックのみでGitの操作をする方が便利だと思いメモ。

#開発環境
Windows10
Gitにインストールや初期設定は完了している前提です。


#リポジトリの作成
今回作成するリポジトリ名は"testrepository"とします。

#リポジトリをクローン
先程作成したレポジトリ"testrepository"をローカルにクローンします。
Ⅰ.クローンするためのフォルダを新規に作成し、Vscodeで開きます。フォルダ名は"git"とします。
Ⅱ.Vscodeでターミナルを開き、下記コマンドを実行

```
$ git clone 作成したリポジトリのURl
```
Ⅲ.クローンに成功するとgitフォルダの中にtestrepositryがクローンされているのを確認出来る

#プッシュ
先程クローンしたtestrepositporyに変更を加え、Githubにプッシュしてみます。
Ⅰ.Vscodeで、testrepositporyは以下にindex.htmlを作成します。
Ⅱ.index.htmlを編集(中にtestと記載します。)
Ⅲ.下記のようにソース管理画面を開くと変更されたファイルが表示されるので、変更の横の＋ボタンを押して全ての変更をステージする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/805284/09757e20-b092-8111-6171-0b44a8a24df6.png)

Ⅳ. その上のメッセージを入力する欄で、コミット時のメッセージを入力(first commitなど)
Ⅵ.✓マークをクリックし、コミット、その横の・・・マークからプッシュをクリック
Ⅶ.リポジトリにプッシュされているのが確認出来る。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/805284/05726dc8-0bdf-221f-462d-8bbe5cc1bde1.png)
[iOS15 ベータ8]WKWebViewでデフォルトのテキストカラーが変更された

## 環境
iOS 15.0(19A5340a) ベータ8

## 発生した問題
WKWebView上で文字が表示されない。

|iOS14|iOS15|
| --- | --- |
|![text.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406531/035868f4-5618-d554-561a-d95cc2a2cea1.png)|![nonText.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406531/d51d7133-38c4-36e2-126b-966e1275bb20.png)|

## 先に結論
iOS15でWKWebViewのCSS初期設定に変更が入り、デフォルトのテキストカラーに白が指定されるようになった。

---

以下調べた過程

## 調査
[ネイティブアプリのWebViewをデバッグする方法](https://cpoint-lab.co.jp/article/202002/13846/)を参考にCSSを見てみます。
[ユーザーエージェントスタイルシート](https://snownotes.org/understanding-about-user-against-stylesheet-and-reset-css/)で指定されている箇所を見るとfont-familyがHelveticaからsystem-uiに変わってますね。
やはりWKWebViewにも色々修正が入っているようです。
CSSの初期設定周りに変更入ったものと推測。

|iOS14|iOS15|
| --- | --- |
|![ios14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406531/1605f64b-46b1-bdf3-309c-ebba292831f3.png)|![ios15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406531/d33a9e9a-9786-b800-ba20-b4018fe17dea.png)|

## 調査2
試しに開発ツールから背景色をblackに変更してみると表示されました。

|背景色の変更|変更後の表示|
| --- | --- |
|![change.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406531/59330494-d83b-85d6-ba1a-5d086a13fc21.png)|![blackBack.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406531/669aef82-c916-df62-6600-d9600a3e236c.png)|

## 結論
iOS15のWKWebViewではデフォルトのテキストカラーが白に変わったものと思われます。
~~現状ベータ8ですがこれはリリースまでに直るのでしょうか🤔~~
→ リセットCSSが適用されていないのがそもそもの問題ですね😅

## 参考
- [CSSのuser agent stylesheetとは - snownotes](https://snownotes.org/understanding-about-user-against-stylesheet-and-reset-css/)
- [【iOS】ネイティブアプリのWebViewをデバッグする方法 - 株式会社シーポイントラボ](https://cpoint-lab.co.jp/article/202002/13846/)
- [端末のWebViewの詳細を調べる方法(Safariインスペクタ) - Qiita](https://qiita.com/ikemai/items/e6bd5e388764443bd24c)
HTML要素を新たに追加するinsertBeforeの使い方~備忘録~

##子要素がHTML要素を持つ場合
以下のような構造のHTMLがあるとします。

```html
<div id='text'>
  <p id='p1'>テキスト1</p>
  <p id='p2'>テキスト2</p>
  <p id='p3'>テキスト3</p>
</div>
```

テキスト1の後に、新しい要素

```html
<p id='new'>新しいテキスト</p>
```

を追加したいとき。

```js
const textElement = document.getElementById('text') // 親要素の取得
const p1Element = document.getElementById('p1') // 基準とする要素の取得

const newElement = document.createElement('p') //　追加要素
newElement.id = 'new' // id属性
newElement.textContent = "新しいテキスト" //テキスト

textElement.insertBefore(newElement, p1Element)
```

##子要素がHTML要素を持たない場合
こんな状況あるのかな、、、
例えば、contenteditableな要素を操作する時に使えるのではないでしょうか。

以下のような構造のHTMLがあるとします。

```html
<div contenteditable='true' id='text'>
 insertBeforeの使い方
</div>
```

Enterキーを押した時に、

```html
<span style='color: red;'>Enterキーを押さないでください</span>
```
という要素を入力したテキストの後に追加したいとき。

```js
const textElement = document.getElementById('text') //親要素の取得

const newAlertElement = document.createElement('span') // 新しい追加したい要素
newAlertElement.style.color = 'red' // 文字色を赤にする
newAlertElement.textContent = "Enterキーを押さないでください" // テキスト

textElement.insertBefore(newAlertElement, textElement.childNodes[0])
```

textElement.childNodes[0]というのは親要素の下にある"insertBeforeの使い方"を指します。
【第１回】Confluent Platformのデモを試してみる

###はじめに
　最近Kafkaを機能拡張しているConfluent Platformの話を聞く機会が増えてきたのですが、話を聞くだけではよくわからない部分もあったのでConfluent社が提供するcp-demoというコンテンツがGitHub上にあったので、ひとつひとつの機能を実際に試してみることにしました。
参照：https://github.com/confluentinc/cp-demo

###内容
　このデモのユースケースは、実際のWikipediaページへのリアルタイム編集を処理するApacheKafka®イベントストリーミングアプリケーションとなっています。
![cp-demo.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/128268/fdb7e2c6-baf8-9b55-6e31-e0e664332c35.jpeg)
出典：https://docs.confluent.io/platform/current/tutorials/cp-demo/docs/overview.html

デモシナリオは次のとおりです。
ウィキペディアのイベントストリームは、実際のウィキィページで発生するリアルタイム編集の連続ストリームを公開しています。Kafkaソースコネクタのkafka-connect-sseはhttps://stream.wikimedia.org/v2/stream/recentchange からサーバー送信イベント（SSE）をストリーミングし、カスタムコネクトトランスフォームのkafka-connect-json-schemaがJSONを抽出します。
その後、これらのメッセージが、Kafkaクラスターに書き込まれます。このデモでは、ksqlDBとkafka Streamをデータ処理のために使用します。次に、Kafkaシンクコネクタのkafka-connect-elasticsearchがKafkaからデータをストリーミングし、分析のためにElasticsearchへデータを繋ぎKibanaで可視化します。すべてのデータはConfluentSchema RegistryとAvroを使用しており、CCC(Confluent Control Center)を管理と監視のために使用します。

###オンプレミスでクラスタ構築する
　それでは実際にオンプレミスで構築していきたいと思います。
今回はcp-demoというDocker環境を利用してそれぞれの機能の確認をしていきます。
使用するDocker環境は少なくとも8GBのメモリ、２つ以上のCPUコアが割り当てられている必要があります。
####設定
1.confluentinc / cp-demo GitHubリポジトリのクローンを作成します。

```sh
git clone https://github.com/confluentinc/cp-demo
````

2.cp-demoディレクトリに移動し最新リリースのブランチをチェックアウトします。

```sh
cd cp-demo
git checkout 6.2.0-post
````

####環境のセットアップ
cp-demoのディレクトリの中にはワークフローをエンドツーエンドで実行するスクリプトが用意されています。
それを使用してDockerコンテナを起動し、環境を構成します。
また、このスクリプトにはオプションの設定も可能となっております。
　・CLEAN：構築された状態で証明書とローカルに構築されたConnectイメージを再生成するかどうか制御できます。
　・C3＿KSQLDB_HTTPS:Confluent Control CenterとksqlDBサーバがHTTPかHTTPSのどちらを使用するか制御できます。
　・VIZ:ElasticsearchとKibanaの有効/無効を制御できます。
今回は、オプションを使用せずスクリプトを実行します。

```sh
./scripts/start.sh
````

環境にもよりますが、最初の実行時は必要なDockerイメージをすべてダウンロードするので約15分ほど時間がかかります。

####確認
ここでは環境が正しくセットアップされたか確認します。
１．Dockerコンテナの状態を確認します。

```sh
docker-compose ps
````

出力結果は以下のような内容になります。
![スクリーンショット 2021-09-02 13.40.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/128268/7a2b714f-5532-6846-0958-5ccdaf0de1f4.png)

２．http://localhost:5601/app/dashboards#/view/Overview をクリックし、Kibanaのダッシュボードを表示します。これが表示されればcp-demoのスクリプトが正常に完了しています。
![スクリーンショット 2021-09-02 13.47.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/128268/4a214d7a-2b6c-05f1-6438-64de956cb6f1.png)

３．cp-demoディレクトリ中のdocker-compose.ymlファイルがこのConfluentプラットフォームを構成しています。
https://github.com/confluentinc/cp-demo/blob/6.2.0-post/docker-compose.yml

次回は、この環境をもとにそれぞれの機能を見ていきたいと思います。
間違えてrails db:migrationをしてしまった時の戻し方

## マイグレーションしてしまったバージョンを調べる

```
hogehoge@MacBook-Pro room-api % rails db:version
Current version: 20210909002314
```

今回のバージョンは`20210909002314`なので、これをdownさせればいい

## 元に戻す

```
hogehoge@MacBook-Pro room-api % rails db:migrate:down VERSION=20210909002314 
== 20210909002314 AddCancelToSamples: reverting ==========================
-- remove_column(:samples, :cancel, :boolean)
   -> 0.0248s
== 20210909002314 AddCancelToSamples: reverted (0.0281s) ================= 
```
（個人メモ）pythonの可変長引数（**kwargs）にデフォルト変数を設定する方法


pythonの可変長引数（**kwargs）にデフォルト変数を設定するにはpopを使用する。

```py
def func(**kwargs):    
    key1=kwargs.pop('key1', 'default_key1')
    key2=kwargs.pop('key2', 'default_key2')
    print(key1)
    print(key2)    
    
if __name__=='__main__':
    kwd={'key1':1,
         'key2':2}
    func(**kwd)　
    
    kwd={}
    func(**kwd)   
```

出力

```
1
2
default_key1
default_key2
```
【初心者向け】BizRobo!でZipファイルをダウンロードして解凍する

#BizRoboでのZipファイルのダウンロードと解凍方法
PCでZipファイルを解凍する場合は、ダブルクリックだけで簡単に解凍ができますが、
DS上でZipファイルをダウンロードして、
解凍するには、変数に一旦Zipファイルを取り込み、「Write File」で一旦端末に保存し、
コマンドを使用してファイルを解凍する必要があります。

####①対象のWebサイトをロードし、保存したいダウンロードファイルをクリックする

####②アクションステップを作成し、「ページ読み込み　→　ソース抽出」を選択し、下記画像のようにデータの抽出先を「binary」に変更し、一旦DS上の変数にダウンロードファイルを取り込む
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1902544/48cf3c39-d212-0c7b-f366-1a5d7ca710bc.png)

####③アクションステップを作成し、「ファイルシステム　→　ファイル出力」を選択し、ファイル名に任意の場所を指定し、ファイルコンテンツを「binary」に変更する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1902544/eb11d863-e426-96a6-cbe1-422d5bddb7e5.png)

####④アクションステップを作成し、「その他　→　コマンドライン実行」を選択し、コマンドラインを「エクスプレッション」に変更し、以下のコマンドを入力する

【>>powershell Expand-Archive -Path "<<
+ "C:\\\\demo\\\\demo.zip"　　←③で指定した場所
+ >>" -DestinationPath "<<
+ "C:\\\\demo"
+ >>" -Force<<】 

※1 この際に出力値が正常に表示されていることを確認してください。
※2 2行目の"C:\\\\demo\\\\demo.zip"は③で出力した場所を指定します。
※3 4行目の"C:\\\\demo"はZipファイルの解凍先を指定します。
※4 ファイルパスの￥が2つ重なっているのは、￥が特殊文字になり、特殊文字の前に￥を付ける必要があるためです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1902544/bb62f7fc-808a-cf9b-538e-b77d50f9b2fb.png)

以上になります。
今後の開発の参考にして頂けると幸いです。
○○のインスタンス変数の情報の有無で条件分岐させたい時に使うメソッド

## はじめに
学習の備忘録です。
Ruby on Rails 6.0、MySQLでアプリケーションを開発しています。

## やりたいこと
あるモデルに登録されている情報を、トップページに表示する実装を学習。
モデルに情報が登録されている場合はモデル内の情報を一覧で表示できるようにし、
モデルに情報がない場合はダミーのデータ（後述の配置例では文字列）を表示するように実装します。

上記の通り、条件分岐の記述が必要になるので`if文`を使います。
まずトップページにモデルの情報を取得できるようにルーティングとアクションを設定します。

```routes.rb
Rails.application.routes.draw do
  resources :items, only: [:index, :new, :create]
end
```

```items_controller.rb
class ItemsController < ApplicationController
  def index
    @items = Item.all
  end
end
```

ここから`if文`を作成していきます。
上記でコントローラーに、`モデルの情報を全て取得できるように`設定したインスタンス変数を使い、情報を呼びだしつつ、
今回の条件である**モデルに情報がある場合どうするのか**を設定するためのメソッドを使います。
それが`present`メソッドです。

## presentメソッドとは
Railsにおいて、presentメソッドはオブジェクトであるレシーバーの値が存在すればtrue、存在しなければfalseを返すメソッドです。
下記のように`?`をつけて使用します。

```ruby
<% if インスタンス変数.present? %>
```

こう記述することにより、インスタンス変数に値が入っていればtrueを返し、
これに続く値が入っていた場合の処理を実行します。
値が入っていない、もしくはインスタンス変数そのものが存在しない場合はfalseを返し、
処理をしない、もしくは値が入っていない場合の処理を行います。
以上を踏まえて、ビューファイルに記述すると下記のようになります。

#### 配置例

```index.html.erb
<% if @items.present? %> 
  # ↓下記は取得した情報を並べて表示するための記述です↓
  <% @items.each do |item| %>
　　　　　　　　　　　　　　　　　　　中略
  # ↑上記は取得した情報を並べて表示するための記述です↑ 
  <% else %>
    アイテムはありません
  <% end %>
<% end %>
```

## おまけ

presentメソッドと似たような機能を持つメソッドがありますので紹介します。
（[Railsのpresentの使い方を現役エンジニアが解説【初心者向け】](https://techacademy.jp/magazine/20214)より抜粋）

#### nil?メソッド

```ruby
変数.nul?
```

このメソッドでtrueが返ってくる時は、レシーバーである変数そのものが存在しない時ということになります。

#### empty?メソッド

```ruby
変数.empty?
```

このメソッドでtrueが返ってくる時は、レシーバーである変数に値が何も入っていない時ということになります。

#### blank?メソッド

```ruby
変数.blank?
```

このメソッドでtrueが返ってくる時は、レシーバーである変数そのものが存在しないか、変数に値が何も入っていない時ということになります。
nul?メソッドとempty?メソッド両方の機能を併せ持つメソッドです。
また、present?メソッドと逆の機能を持っているとも言えます。


終わり
MQTTX の使いかた （クライアント）

Arch Linux でのインストール方法

```bash
yay mqttx-bin
```

Ubuntu でのインストール方法

```bash
wget https://www.emqx.com/ja/downloads/MQTTX/v1.11.1/MQTTX_1.11.1_amd64.deb
sudo dpkg -i MQTTX_1.11.1_amd64.deb
```

起動

```bash
mqttx
```

起動直後の画面
![mqttx_aa.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/f917c183-bb90-e282-1b49-2d9f0d10145c.png)

Name だけを入力してあとはディフォールトのままで接続。
broker.emqx.io　がプローカーになります。
![mqttx_bb.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/6f09a99d-9a9f-e829-c613-aa77d4654526.png)

Topic を入力して Publish
![mqttx_cc.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/cd7e4ff6-b186-8dea-9a38-e92d59d562d0.png)

mosquitto で同じブローカー、同じトピックスに接続していれば次のようになります。

```text
$ mosquitto_sub -h broker.emqx.io --topic sample/imageTopic
{
  "msg": "Hello"
}
```

Topic を入れて subscribe の用意
![mqttx_dd.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/c8604156-401e-bd1d-0524-4b111dbda739.png)

mosquitto で　publsish する。
サンプルのスクリプト

```bash:go_pub_mqtt.sh
BROKER="broker.emqx.io"
#
TOPIC="sample/imageTopic"
#
echo $BROKER
message='{"name": "sensor3", "temp": 26.3}'
echo ${message}
mosquitto_pub -d -t orz -m "${message}" -h $BROKER --topic $TOPIC
```

受信した状況
![mqttx_ee.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/cd829207-6cd5-b346-e223-a941a5825102.png)
【Ruby on Rails】link_toメソッドをリンクではなくボタンとして使う方法


#対象者

* link_toメソッドの使い方を知りたい方


#目的

* link_toメソッド使ってviewでボタンを表示する

#実際の手順と実例
###1.link_toメソッドの表示の違い

####a. 基本的な構文

````
<%=link_to　"表示する文字", "URL"　%>
````
上記の書き方だと**テキストリンク**になってしまう

####b. doとendで囲う方法

````
<%=　link_to URL do %>
　　　表示する文字
<%　end　%>
````

これでボタン化できます。

###2.　実際の使用例

下記サイトを参考に表示テキストがホバーすると変わるボタンを実装

https://coco-factory.jp/ugokuweb/move01/7-1-42/

上記記事のHTMLコードは下記の通り

````index.html
<a href="#" class="btntextchange">
  <span>About</span><span>私たちについて</span>
</a>
````

※CSSは省略します。class="btntextchange"に表示を切り替えるcssのコードが書かれています。

これをRailsのコードに置き換えて実験してみた

```index.html.erb
<a href="#" class="btntextchange">
  <span><%=link_to　"About", "about_path"　%></span>
  <span><%=link_to　"私達について", "about_path"　%></span>
</a>
```

上記の書き方だとボタン化できません。
原因としては、link_toメソッドを使用することでaタグのHTMLが作成され、二重に精製されてしまっていることが考えられます。


###3.例の解決方法

下記のようにボタン化して解決できます。

```index.html.erb
 <%= link_to about_path do %>
    <div class="btntextchange">
　　　　　　　　　　　　　<span>About</span>
　　　　　　　　　　　　　<span>私たちについて</span>
　　　　　　　　　</div>
 <% end %>
````

上記のようにHTMLコードを挟み込むことで、
ボタンとして活用できます！

#参照

[【Rails入門】link_toの使い方とオプションをわかりやすく解説！](sejuku.net/blog/13857)
[【Rails基礎】link_toメソッドをボタン化して使う方法](https://freesworder.net/rails-link-to-button/)
【Python】【Ruby】【Java】ビンゴカード作成問題！

　現在僕はPythonを学んでいます。Pythonを学び始めて1週間ほどが経過したので、過去にRubyやJavaで作成していたプログラムをPythonでも作ってみることにしました。

B：1～15のどれか
I：16～30のどれか
N：31～45のどれか
G：46～60のどれか
O：61～75のどれか

```
 B |  I |  N |  G |  O
13 | 22 | 32 | 48 | 61
 3 | 23 | 43 | 53 | 63
 4 | 19 |    | 60 | 65
12 | 16 | 44 | 50 | 75
 2 | 28 | 33 | 56 | 68
```

　上記のような出力結果を得るプログラムになります。


- Rubyの場合
- Javaの場合
- Pythonの場合

　以上の流れでコードを載せていきます。

## Rubyの場合

https://qiita.com/kim-shun/items/0c862ff71e61648cd346

```ruby
puts "  B |  I |  N |  G |  O"

b = (1..15).to_a.sample(5)
i = (16..30).to_a.sample(5)
n = (31..45).to_a.sample(5)
g = (46..60).to_a.sample(5)
o = (61..75).to_a.sample(5)

5.times do |count|
  printf("%3d", b[count])
  print " |"

  print " #{i[count]} |"
  if count == 2
    print "    |"
  else
    print " #{n[count]} |"
  end
  print " #{g[count]} |"
  print " #{o[count]}  "
  puts "\n"
end
```

　後半部分はもう少し綺麗な記述ができそうです。

## Javaの場合

https://qiita.com/kim-shun/items/fee32cf0cb3cc009756a

```java
package example;

import java.util.ArrayList;
import java.util.Collections;

public class Bingo {

	public static void main(String[] args) {
		ArrayList<ArrayList<Integer>> lists = new ArrayList<ArrayList<Integer>>();
		int num = 1;
		for (int i = 0; i < 5; i++) {
			ArrayList<Integer> list = new ArrayList<Integer>();
			for (int j = num; j < num+15; j++) {
				list.add(j);
			}
			Collections.shuffle(list);
			lists.add(list);
			num += 15;
		}
		
        System.out.println("  B |  I |  N |  G |  O");
		
		for (int k = 0; k < 5; k++) {
			System.out.printf("%3d%s",lists.get(0).get(k)," |");
			System.out.printf("%3d%s",lists.get(1).get(k)," |");
			if (k == 2) {
				System.out.printf("%5s","|");
			} else {
				System.out.printf("%3d%s",lists.get(2).get(k)," |");
			}
			System.out.printf("%3d%s",lists.get(3).get(k)," |");
			System.out.printf("%3d",lists.get(4).get(k));
			System.out.println();
		}	
	}
}
```

## Pythonの場合

　今回作ったPythonでのビンゴカード作成問題です。Rubyとほぼ同じやり方で解きました。Pythonの方がRubyよりもシンプルな記述が可能な印象です。
　「sample」のように、重複なしで特定の範囲から複数の値を取得できるメソッドがJavaでは見当たらなかったため、Javaの場合はその辺が少し複雑になっています。

```python
import random

b = random.sample(range(1,16),5)
i = random.sample(range(16,31),5)
n = random.sample(range(31,46),5)
g = random.sample(range(46,61),5)
o = random.sample(range(61,76),5)

print("  B |  I |  N |  G |  O ")
for j in range(5):
    print("%3d"  % b[j],end=" |")
    print("%3d"  % i[j],end=" |")
    if j == 2:
        print("   ",end=" |")
    else:
        print("%3d"  % n[j],end=" |")
    print("%3d"  % g[j],end=" |")
    print("%3d"  % o[j])
```

<br>

　ご意見いただけると非常に勉強になります。よろしくお願いいたします。

<br>
Bash でオセロゲームを作ったよ

3日間の夏休みがあったので、Bash でオセロゲームを作ってみました。

コンピュータと戦う方式にしてみたんですが、自分がやると、間違えない限り自分が勝ちます。
ロジック組んだの自分だからですね、たぶん。
強くするにはどうしたらいいかを考えたいです。
(追記)
バグとか、ロジックとか、直していってます。
コンピュータも、すこしは戦えるようになったと思いますが、序盤の作戦面が甘い気がします。

https://github.com/intrajp/CLI_Othello
(git) 指定したコミットが含まれるか確認する

# (git) 指定したコミットが含まれるか確認する

```
git merge-base --is-ancestor commitA commitB
```

## 引数の説明

commitA → このコミットが含まれるか確認する
commitB → このコミットを対象に commitA が含まれるか確認する。


## 結果

含まれる場合 → 終了コード 0
含まれない場合 → 終了コード 1

## 例

```
git merge-base --is-ancestor 7abcdef  HEAD
```

HEAD に `7abcdef` が含まれるか確認する。

## 参考

* [Given a commit id, how to determine if current branch contains the commit?](https://stackoverflow.com/questions/43535132/given-a-commit-id-how-to-determine-if-current-branch-contains-the-commit)
* ↑ の機械翻訳 [コミットIDを指定して、現在のブランチにコミットが含まれているかどうかを判断する方法](https://www.it-mure.jp.net/ja/git/%E3%82%B3%E3%83%9F%E3%83%83%E3%83%88id%E3%82%92%E6%8C%87%E5%AE%9A%E3%81%97%E3%81%A6%E3%80%81%E7%8F%BE%E5%9C%A8%E3%81%AE%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81%E3%81%AB%E3%82%B3%E3%83%9F%E3%83%83%E3%83%88%E3%81%8C%E5%90%AB%E3%81%BE%E3%82%8C%E3%81%A6%E3%81%84%E3%82%8B%E3%81%8B%E3%81%A9%E3%81%86%E3%81%8B%E3%82%92%E5%88%A4%E6%96%AD%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/830799632/)
jqコマンドで文字化けした時の対応方法


- 環境
    - Windows10 Pro バージョン21H1
    - GNU bash, version 4.4.23
    - jq-1.6

# 事象 : jqコマンドでJSONの中身を抜き出したら文字化けした
KintoneのRest APIでアプリの参照権限を取得して、「設定対象のコード」だけを抜き出したら文字化けした。
参考 : [アプリのアクセス権の取得 &ndash; cybozu developer network](https://developer.cybozu.io/hc/ja/articles/204529754)

```bash
$ curl -sS -X GET -H 'X-Cybozu-Authorization:パスワード認証;' https://サブドメイン.cybozu.com/k/v1/app/acl.json?app=172 | jq -r '.rights[].entity.code'
邂｡逅・・A7lIQe
蜿ら・閠・jUmF8o
everyone
```

「設定対象のコード」だけを抜き出す前の状態では文字化けしていなかった・・・。

```bash
$ curl -sS -X GET -H 'X-Cybozu-Authorization:パスワード認証;' https://サブドメイン.cybozu.com/k/v1/app/acl.json?app=172 | jq -r '.rights[]'
{
  "entity": {
    "type": "ORGANIZATION",
    "code": "管理者_A7lIQe"
#...省略...
    "code": "参照者_jUmF8o"
#...省略...
    "code": "everyone"
#...省略...
```

## 原因 : rオプションでダブルクォーテーションを消したから
```bash
# rオプションをつけている
$ curl ... | jq -r '.rights[]'
```

> --raw-output / -r:
> With this option, if the filter's result is a string then it will be written directly to standard output rather than being formatted as a JSON string with quotes. This can be useful for making jq filters talk to non-JSON-based systems.
> [jq Manual (development version)](https://stedolan.github.io/jq/manual/)
>
(ざっくり訳)フィルタの結果が文字列の場合、引用符付きのJSON文字列としてフォーマットされるのではなく、標準出力に直接書き込まれます。これは、jqフィルタが非JSONベースのシステムと通信するのに役立ちます。

「設定対象のコード」だけを抜き出す前の状態は、`-r`オプションをつけていてもダブルクォーテーションがついている。ということに気が付いた。

### 対応 : rオプションをやめる
ダブルクォーテーションがくっついてしまうけれど・・・文字化けするよりはマシ。
どなたかもっといい方法をご存じの方はご教授ください。

```bash
$ curl -sS -X GET -H 'X-Cybozu-Authorization:パスワード認証;' https://サブドメイン.cybozu.com/k/v1/app/acl.json?app=172 | jq '.rights[].entity.code'
"管理者_A7lIQe"
"参照者_jUmF8o"
"everyone"
```
時間、分、秒を標準入力で受け取り、HH:MM:SS形式に修正するPowershell

時間を、時間、分、秒を標準入力で受け取り、HH:MM:SS形式に修正するPowershellです

```powershell
##### 文字列テスト                                      ##########
##### Create Date     2021/9/9                         ##########
##### Create AUthor   乃木坂好きのITエンジニア           ##########
################################################################
#出力先ファイルの定義
$date = Get-Date -Format "yyyyMMddHHmmss"
$result_file = "C:\work\20210908\result\mojiretsu_test$date.txt"
#正解カウント
$count = 0
#30分以上を設定しているかカウント
$const_count = 0

#メイン処理
while ($true) {
    $count = 0
    $const_count=0
    Write-Host "0から24までの数字を入力してください"
    $hour = Read-Host
    $hour2 = $hour
    if (($hour -ge 0 ) -and ($hour -lt 10)) {
        $hour = "0" + $hour
        $count += 1
    } elseif ($hour -lt 24 ){
        $count += 1
    } else {
        Write-Host "NG"
    }
        
    Write-Host "0から59までの数字を入力してください"
    $minutes = Read-Host
    $minutes2 = $minutes
    if (($minutes -ge 0 ) -and ($minutes -lt 10)) {
        $minutes = "0" + $minutes
        $count += 1
    } elseif ( $minutes -lt 60 ) {
        $count += 1
    } else {
        Write-host "NG"
    }

    Write-Host "0から59までの数字を入力してください"
    $seconds = Read-Host 
    if (($seconds -ge 0 ) -and ($seconds -lt 10)) {
        $seconds = "0" + $seconds
        $count += 1 
    } elseif ( $seconds -lt 60 ) {
        $count += 1
    } else {
        Write-host "NG"
    }

    if (($hour2 -eq 0) -and ($minutes2 -lt 30 )){
        $const_count += 1
    }
    ##正しく判定されているかチェック処理
    if (($count -eq 3) -and ($const_count -eq 0)){
        $ans = $hour + ":" + $minutes + ":" + $seconds
        Write-Host $ans
        break
    }
}
VOICEVOX 0.5.0 以降における、wineを使った実行方法

https://voicevox.hiroshiba.jp/

VOICEVOXの「製品版」はバージョン0.5.0から、インストーラー形式で配布されるようになりました。
それに伴って従来提供されていた、単一のZIPファイルによる配布はなくなっています。
しかし以下のような、分割された7z形式アーカイブを取得して、結合すれば、以前と同じようにアーカイブの中身を得ることができます。

[voicevox/releases](https://github.com/Hiroshiba/voicevox/releases)

9月9日時点での最新は、0.5.1。その分割7zアーカイブは以下のようなファイル名です。

- voicevox-0.5.1-x64.nsis.7z.0
- voicevox-0.5.1-x64.nsis.7z.1
- voicevox-0.5.1-x64.nsis.7z.2

上記ファイルを展開するまでの一連の手順は、以下の通り（パス等適宜読み替えてください）

ここで説明する内容は、Ubuntuで実施した場合の例です。
たとえばWindowsのWSL（Ubuntu）や、他Linuxでも同様に実行できると思われます。
7zが未インストールであれば、別途インストールしておいてください。
```apt install p7zip-full```

```bash
mkdir voicevox-0.5.1
cd voicevox-0.5.1
# Download from https://github.com/Hiroshiba/voicevox/releases
cat voicevox-0.5.1-x64.nsis.7z.? > temp.7z
7z x temp.7z
rm temp.7z
```

あとは同様に
```wine64 run.exe [オプション]```
でエンジンを実行できます。

フロント側は変わらず。別途、git cloneして（適宜pullで最新に更新）
```npm run electron:serve```
です。

以前に書いた記事と重複する部分は端折って説明しました。
合わせて参照ください。

https://qiita.com/isnot_naoto/items/70341884b5dc7a3d7fb5
開発者としてアイディアを整理したり問題を解決したいときの「6色ハット」

アイデアを整理したり問題を解決したい時の ｢6色ハット発想法｣ というもの。これを開発者としてどう活用できるかをまとめた。

https://www.lifehacker.jp/2013/06/130622sixhats.html

https://ideakey.jp/sixhats/

というメソッドがあり、英語版Wikipediaでは以下のように説明されている。

https://en.wikipedia.org/wiki/Six_Thinking_Hats

> エドワード・デ・ボノ博士によって書かれた。
> 思考プロセスを詳細かつ首尾一貫した方法で計画するための手段であり、
> そうすることでより効果的に一緒に考えることができるもの

ということで、開発や日々の業務の中で、最も良い不具合の解決策はAだが、今のいま問題を回避するならB、せめてもう少し調査するならCが必要、などといった時に見方を変えてみることで思考を整理したい、などという時に使えるもの。

## それぞれの帽子の役割

### <font color="blue"> 青い帽子</font>

管理的な視点。
俯瞰で物事を見て、分析し、結論立てる。これにより会議自体の進行や調整、まとめを行う。

### <font color="black"> 白い帽子</font>

客観的な視点。実際のデータや数字から物事を考える。
ログを追ったり時系列を整理したり、自分の意見を出さずにデータを読む。

### <font color="red"> 赤い帽子</font>

直感的な視点。感情的、感覚的な面から考える。
それぞれのアイディアに対して思った気持ちを論理的にではなく、感情的に表現する。

### <font color="yellow">黄色い帽子</font>


肯定的な視点。全てを肯定的に捉える。
出てきたアイディアの良い面を見つけ出し、実現することでこんなプラスがある、などを語る。

### 黒い帽子

否定的な視点。否定的に捉えることで、不安材料を認識したり、注意喚起を起こしたりする。
アイディアの欠点やリスクを見つけ出す。

### <font color="green">緑の帽子</font>

創造的な視点。クリエイティブに考え、革新的なアイデアを提案する。



## 整理手順 (Wikipedia参考)

- すべての手順は、常に青い帽子で始まり、青い帽子で終わる。
- 1人でもグループでも行えるが、グループで行う場合は、どのように考えるかに合意し、次に考え、その結果を評価し、次に何をすべきかを考える。
- 各帽子は、通常、1回につき約2分間使用するが、プロセスの開始時には、全員が同じ理解に到達できるよう、白い帽子のセッションを延長するのが一般的。また、赤い帽子は、直感的に行うため、約30秒という非常に短い時間で使用することが推奨されている。

### ジャンル別に
| 場面 | 帽子をかぶる順 (2分ずつ) |
|:-:|:-:|
|最初のアイデア出し   |青→白→緑→青   |
|選択肢の選択時   |青→白→（緑）→黄→黒→赤→青   |
|解決策の特定時 |青→白→黒→緑→青|
|クイックフィードバック時 | 青→黒→緑→青|
|戦略的プランニング時 | 青→黄→黒→白→青→緑→青|
|プロセス改善時 | 青→白→白（他人の意見）→黄→黒→緑→赤→青|
|問題の解決時 | 青→白→緑→赤→黄→黒→緑→青|
|パフォーマンスレビュー時 | 青→赤→白→黄→黒→緑→青|

### 例えば

Q. お客様の特定の環境であるオペレーションを行うとエラーがたまに出る。必ずエラーとは限らない。根本解決にはプログラムを再適用する必要がありそう。

A. **解決策の特定時フロー**

> 青→白→黒→緑→青

つまり 

1. 青い帽子で俯瞰で物事を見て、分析し
2. 白い帽子で実際のデータや数字から物事を考える。ログを追ったり時系列を整理する。
3. 黒い帽子。批判的な目で原因をもちろん考えた上で、
4. 緑でクリエイティブに考え、革新的な問題解決のための修正アイディアが提案できないかは、検討してみる。
5. 最後に再度、青で俯瞰的にまとめる。


## まとめ

引用: [アイデアを整理したり問題を解決したい時の｢6色ハット発想法｣ | ライフハッカー［日本版］](https://www.lifehacker.jp/2013/06/130622sixhats.html)

> 結局のところ、6色ハット発想法を使ったところで、考え方が劇的に変わって、仕事がはかどるということはありません。しかし、発想法というのは、何かを考えたり、問題を解決しようとしている時に、違う視点や考え方を教えてくれます。

などと書かれているが、「黒」のあとには「緑」を使うなど悲観的な視点のまま終わらせないようにできる点が救われるかもしれない。などというところで、以上、参考になればさいわいです。
ホームページに雪や桜を降らせる「particles.js」に機能追加した話

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206742/b49f22b2-c826-e96e-4672-2f42c9d09260.png)

ホームページに桜を降らそう
どーも，だるだるし です
仕事をください（定型文）

## まずは答え

CodePenで [ここ](https://codepen.io/daldalshi/pen/eYdmBPz) 見て頂いたらどんなものかはわかると思います．

他のサンプルとして [こんなの](https://codepen.io/daldalshi/pen/KKgKjxv) もあります
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206742/0c7f1157-e01a-f630-db91-f989e84abe50.png)

要はパーティクルというもので，HPに雪を降らせたり火の粉を散らせたりという効果を付けるものです．

コードはGitHubで [ここ](https://github.com/KoTanukiKyoso/particles.jsWithRotateAndImageOpacity) に置いてます．

##「particles.js」とは

「[particles.js](https://vincentgarreau.com/particles.js/)」は多分どこかで見たことのある画面上のパーティクル効果を簡単に作成するライブラリ？です．

「[particles.js](https://vincentgarreau.com/particles.js/)」の使い方は参照先からGitHubに飛べると思いますのでそちらを参照してください．


## 何をしたか

で私が何をしたのかですが，「particles.js」は大変軽量で便利なのですが，「回転」機能と，「画像の透明度変更」が出来ません．
＊丸や四角形の透明度は変更できます

そこで，回転と，画像の透明度の変更ができるように改造したものが [これ](https://github.com/KoTanukiKyoso/particles.jsWithRotateAndImageOpacity) です

## 使い方

基本的には大本の「particles.js」に則ってますので同じように使用できますが，一応変更部分の使用方法を書いておきます．

「particlesJS（）」関数の第二引数にパラメータを渡しますが，回転させる場合はその中に以下のように「rotate」を記載します．
場所は「shape」や「color」と同格です．

```javascript
"rotate": {
  "value": 360,
  "random": true,
  "anim": {
    "enable": true,
    "speed": -10
  }
},
```

「value」が回転角度
「random」が「true」なら各パーティクル毎に「value」以下でランダムな角度になります
「anim」の「enable」が「true」なら回転アニメーションになります
「anim」の「speed」の絶対値が大きいほど回転速度は速くなります
「speed」がプラスなら右回転，マイナスなら左回転です


## おわりに

ちなみに [こんなの](https://particles.js.org/) もあります．これは非常に高機能ですが，正直重くてHP向けには実用的ではないと思いました．実用的なレベルでは今回作成したものくらいで上々と思ってます．

ずっと記事にしようと思っていたのがようやく果たせました．

npmなどは用意していないのでjsで読み込むことになりますが，よろしければご利用ください．
RHEL8 / Fedora34 (Wayland) で、VMwareの解像度自動調整機能が動作しないとき

自分の備忘録として。
RHEL9.xのベースとなるfedora34を触っていたら、VMwareの解像度自動調整機能が動作しなかったので、その解決策。

```
sudo cp -p /etc/vmware-tools/tools.conf.example /etc/vmware-tools/tools.conf
sudo sed -i -e 's/#enable=true/enable=true/' /etc/vmware-tools/tools.conf
sudo systemctl restart vmtoolsd
```

テストした環境

```
$ uname -a
Linux fedora 5.13.13-200.fc34.x86_64 #1 SMP Thu Aug 26 17:06:39 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux

$ rpm -qa | grep vm-tools
open-vm-tools-11.3.0-1.fc34.x86_64
open-vm-tools-desktop-11.3.0-1.fc34.x86_64
```
python基礎(continue, break,with)

# はじめに
Pytorchでディープラーニングの学習を[つくりながら学ぶ！PyTorchによる発展ディープラーニング](https://book.mynavi.jp/ec/products/detail/id=104855)を参考に進めているのですが、いざ学習のところでcontinueやwithが出てきてなんとなくの理解だったのでbreakとセットでまとめます。

# continue
for文での処理中に使用する。

continueを使うとそれ以降の処理をせずにfor文の先頭に戻って次の値から 繰り返し処理を再開する。

```python:例
for i in range(5):
    if i == 2:
        continue
    print(i)
```

```:実行結果
0
1
3
4
```

iに0~4までの整数値を代入していき、それを表示する処理。
if文でiが2の時はcontinueとすることで、printされない。

Pytorchでは、epochが0の時は学習を省略するなどの例がある。

# break

breakもfor文の中で使い、それ以降の処理を行わず、for文の繰り返し処理も中断する。

```python:例
for i in range(5):
    if i == 3:
        break
    print(i)
```

```:実行結果
0
1
2
```

iに0から4までの整数値を代入していく。iが3の時にbreakとなっているので、そこで以降の処理は行わず、for文の繰り返し処理も中止となりiに4を代入することなく終了。

Pytorchの例で考えれば、学習結果があまり変化ない時に強制的に学習を中断するとかで活用できるのかな。

# with

開始と終了がセットになる処理においてwithを使うと終了の処理を書かなくても、自動的に終了してくれるもの。

```python:例
with open('sample.txt', 'r') as f:
    print(f.read())
```

ファイルを開いた場合、必ず閉じる必要があるが、with文を使えばf.close()という閉じる処理を書かなくて済む・書き忘れてエラーになることがない・コードが短くなるなどのメリットが。

Pytorchの例だと、trainモードの時には損失を必ず計算して、evalモードの時にはしないなどで活用する。



# まとめ
こういう基礎も怠らず、理解していきたい。
【Ruby】配列を制するものはRailsを制す。

Rubyの配列の基本についてまとめます。

実際にRailsでアプリを実装するときなどには、配列は頻繁に扱うことになります。
配列をうまく扱うことができれば実装力が増すことは間違いありません！


#配列の作り方

普通に`[]`でくくればできますが、それ以外の方法を簡単に見ておきましょう。


###Array.new

```ruby
array = Array.new(3, 'ok')
p array

#["ok", "ok", "ok"]
```

###splitメソッド

```rb
string = 'taro jiro saburo'
array = string.split(' ')
p array

#["taro", "jiro", "saburo"]
```

#要素を取り出す・置き換える・挿入する

###要素を取り出す

```ruby
array = ["taro", "jiro", "saburo"]
new_array = array[1..2]

#["jiro", "saburo"]
```


###要素を置き換える

```ruby
array = ["taro", "jiro", "saburo"]
array[0] = "me"
#["me", "jiro", "saburo"]

array[0..1] = ["me", "my brother"]
#["me", "my brother", "saburo"]
```


###要素を挿入する

要素を挿入する場合は`array[n, 0] = 挿入したい要素`と書きます。
nの直前に要素を挿入します。

```ruby
array = ["taro", "jiro", "saburo"]
array[1, 0] = "hanako"

#["me", "hanako", "jiro", "saburo"]
```


###複数のインデックスを指定して配列をつくる

```ruby
array = ["taro", "jiro", "saburo"]
new_array = array.values_at(0, 2)

#["taro", "saburo"]
```


#集合としての配列

数学で集合を学習したことを覚えているでしょうか。
配列を１つのまとまりとして捉えることもできるわけですね。

###共通集合

２つの集合のどちらにも含まれている要素を取り出す。

```ruby
array1 = [1,3,5,7,9]
array2 = [1,2,5,6,9,10]

new_array = array1 & array2
#[1, 5, 9]
```


###和集合

どちらか一方にでもある要素を集める。

```ruby
array1 = [1,3,5,7,9]
array2 = [1,2,5,6,9,10]

new_array = array1 | array2
#[1, 3, 5, 7, 9, 2, 6, 10]
```

###集合の差

```ruby
array1 = [1,3,5,7,9]
array2 = [1,2,5,6,9,10]

new_array = array1 - array2
#[3, 7]
```

###集合の和

和集合とのちがいは、重複する要素があっても全部足し合わせます。
（重複しているものを除きたい場合は`|`を使います。）

```ruby
array1 = [1,3,5,7,9]
array2 = [1,2,5,6,9,10]

new_array = array1 + array2
#[1, 3, 5, 7, 9, 1, 2, 5, 6, 9, 10]
```


#まとめ

Rubyの配列の基本について見てきました。

ここで見てきたものをしっかりマスターしておくだけでも配列の扱いが容易になると思います。
Railsなどの開発にも生きてくると思います。

今回は以上です！
SESで独自ドメインのnoreplyメールアドレスを作る

# はじめに
メールマガジンの送信元メールアドレスとしてよくみる`noreply@custom.domain.example.com`などのメールアドレスがあります。
SESからメールを送信する時に、送信元メールアドレスに、このような独自ドメインのメールアドレスを設定する方法です。

ドメインの取得は行ってあり、Route53に登録済みの前提です。


# 受信用メールアドレスを作る
SES経由でメールを送信するとき、送信元メールアドレスに指定できるのは、SESで認証されたメールアドレスのみです。
メールアドレスの認証は、SESからメールを送信し、届いたメールアドレス内のリンクをクリックすることで行います。
なので、まずはSESから送信される認証メールを受け取れる「受信用メールアドレス」を作ります。

## SESにドメインを登録する
AWSコンソールにログインし、SESを開きます。
その後、リージョンを「米国東部 (バージニア北部)us-east-1」にしてください。東京リージョンでは後続の「受信設定」が行えませんので、注意をしてください。

左メニューに「domains」という項目があるのでクリックし、出てきた画面の「Verify New Domain」ボタンをクリックします。

<img width="500px" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614264/46969a2e-9561-850b-605d-a4c4a4329891.png">


出てきたポップアップに、メールアドレスのドメインする値を入力し、「Verify This Domein」ボタンをクリックします。
※ 「Generate DKIM Settings」のチェックボックスは`DKIM`レコードを生成する場合チェックをつけてください。このレコードを登録すると、送信元のメールがなりすましでないことをクライアントへ証明することができる。らしいです。

すると、DNSへ登録するためのレコード情報が出てきます。Route53を使っている場合は「Use Route53」ボタンをクリックするだけで自動で登録ができます。

ドメインの「Verification Status」が`verified`に変わったらドメイン登録は完了です。

## 受信設定を行う

次に受信用メールアドレスの設定を行います。受信用メールアドレスといっても、メールクライアントなどでメールの内容を見たりはできません。今回は、送られてきたメールをテキストのままS3へ保存する設定を行います。

左メニューの「Rule Sets」をクリックし、出てきた画面の「Create Receipt Rule」ボタンをクリックします。

<img width="500px" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614264/d33bcba5-c16f-fe3c-7ef2-e1db44445e25.png">

出てきた画面のフォームに、受信用メールアドレスとして設定したいメールアドレスを入力し、「Add Receipt」ボタンをクリックします。この時に入力するメールアドレスのドメインは、先ほど認証したドメインにしてください。
入力が終わったら、右下の「Next Step」ボタンを押します。

出てきたページのセレクトボックスで「S3」を選択します。

<img width="500px" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614264/ab3706a8-f3b8-55a7-949b-8f31509e2685.png">

すると、S3のバケット設定入力画面になるので、受信したeメールを保存するバケットを選択します。受信用メールアドレスを複数作るなどで、メールアドレスごとに保存先をフォルダ分けしたい場合は`Object key prefix`を設定することをお勧めします。`Encrypt Message`、`SNS topic`は無しで大丈夫です。

以上で、受信設定は完了です。

# 送信元メールアドレスの認証を行う

続いて、先ほど作った受信用メールアドレスに認証メールを送って、送信元メールアドレスとして使えるようにします。

まず、「米国東部 (バージニア北部)us-east-1」になっているリージョンを、実際にSESを使ってメールを送信したいリージョンに変更します。

そして、左メニューの「Email Addresses」をクリックして、出てきた画面の「Verify a new Email Address」ボタンをクリックします。

<img width="500px" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614264/c071f78e-cd7d-8483-96c0-0dc65db6e52b.png">

出てきたポップアップに、先ほどの受信設定で設定したメールアドレスを入力し、「Verify This Email Address」ボタンをクリックします。
すると、「Verification Status」が`pending verification`の状態で、メールアドレス一覧にメールアドレスが追加されます。

続いて、受信設定で設定したS3バケットを開きます。
「AMAZON_SES_SETUP_NOTIFICATION」と「ランダム文字列のファイル」の二つがあると思います。このうち、ランダム文字列のファイルが送信された認証メールになります。
こちらをダウンロードし、テキストエディタなどで開きます。このメールの最後の方に、認証用のURLが書いてあるので、コピーして、ブラウザなどでアクセスします。SESの紹介ページへリダイレクトされればOKです。（なんでもっとわかりやすいページにリダイレクトさせないんだろう。）

SESのメールアドレス一覧に戻り、「Verification Status」が`verified`に変わっていれば認証は成功です。

これでめでたく、設定したメールアドレスを送信元メールアドレスとして使用することができます！
Gitで使う単語一覧

#Gitで使う単語一覧
今回は、株式会社サポータズ様の『【エンジニア向け勉強会】Git&GitHubハンズオン！~ステップアップ編~』に参加せていただいた際に、出てきた用語を自分なりに調べたりしてまとめました。
※順番などバラバラなのですがご容赦頂けるとありがたいです、、、

- ワークツリー　
Gitの管理下に置かれた、実際に作業しているディレクトリのこと

- ワークツリーの仕組み　
Gitでは、コミットを実行したときにワークツリーから直接リポジトリ内に状態を記録するのではなく、その間に設けられているインデックスの設定された状態を記録するようになっています。

- HEAD　
リポジトリの最新コミットを示す識別子のこと

- インデックス（ステージ）　
コミットを実行する前に更新内容を一時的に保存する場所のこと
Ex)
インデックスに保存することをインデックスに登録する、addする、ステージングするとも言います。
一回一回コミットするとコミット数が大幅に増えてしまうので、インデックス（ステージ）で確認してからまとめてコミットするためです。

#### 追記　add commitは何のため？
Addは、ステージ（インデックス）でのコミット前の最終確認するための動作
Commitは、gitに変更し内容を登録すること

- コード書いた人の区分わけ
Comitter　コミットをした人
Author　オリジナルのコードを書いた人
→分ける理由はrebaseなどで歴史を改変できてしまうため

- デフォルトブランチ　
プルリクエストやコードのコミットを行う基点となるブランチのこと

- Init　
init（初期化）によるローカルリポジトリの作成→ワークツリーの作成

- オペレーション　
業務の目標達成のため、物事を運営・推進していく手順を定めること。また、それに沿って実施していく一連の作業、実務のこと

- ステータス　
gitでは、ディレクトリでの具体的な状態のこと
Ex)
ファイルの追加や修正、addでインデックスに登録など

- Log　
gitでのlogは、既存のリポジトリのコミット履歴のことです。

- Diff　
gitでのdiffは、二つのファイルの差分を確認すること

- Switch　
gitでのswitchは作業しているbranchを切り替えること

- Restore 
gitでのrestoreは特定のファイルを主にファイルの変更をリセットする場合に使います
お問い合わせフォーム　メール送信機能の作成

##はじめに
備忘録として、自作アプリに組み入れたお問い合わせフォーをどの様にして作成したのかを記述

##環境

⚫︎OS : macOS Catalina 10.15.7
⚫︎Androidsutdio : 4.2.1
⚫︎Kotlin : 1.5.21


![スクリーンショット 2021-09-09 0.34.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704865/fe79af2b-bcf3-4983-0fb8-7d4004914e45.png)

画像の送信ボタンを押すと、
![スクリーンショット 2021-09-09 0.41.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704865/e127f697-e956-20bd-06fa-67fc6be8eeef.png)


gmailの方でタイトルと本文を受け継ぐ処理をしていきます
※本来、メールの送信先のアドレスも受け渡しますが、個人情報保護の為画面のTo項目からは消してます。

##実装




```Kotlin

class OptionsInquiryActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_options_inquiry)

        supportActionBar?.setDisplayHomeAsUpEnabled(true)
    }

    fun onInquiryClickButton(view: View){

        //件名を取得
        val etSubject = findViewById<EditText>(R.id.etSubject)
        //入力された件名を取得
        val subject = etSubject.text.toString()

        //メール本文を取得
        val etComment = findViewById<EditText>(R.id.etComment)
        //入力された件名を取得
        val comment = etComment.text.toString()

        val mailerIntent = Intent()

        mailerIntent.action = Intent.ACTION_SEND
        mailerIntent.type = "message/rfc822"
        mailerIntent.putExtra(Intent.EXTRA_EMAIL , arrayOf(送信先のメールアドレスを記入))
        mailerIntent.putExtra(Intent.EXTRA_SUBJECT , subject)
        mailerIntent.putExtra(Intent.EXTRA_TEXT , comment)

        startActivity(mailerIntent)

        finish()


    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        //戻り値用の変数を初期値trueで用意
        var returnVal = true
        //選択されたメニューが[戻る]の場合、アクティビティ終了
        if(item.itemId==android.R.id.home){
            finish()
        }
        //それ以外
        else{
            //親クラスの同盟メソッドを呼び出し、その戻り値をreturnValとする
            returnVal = super.onOptionsItemSelected(item)
        }
        return returnVal
    }
}
```

Main画面から遷移しているので、バーに戻るボタンを追記しています。


##さいごに
メール画面に遷移するのにあれだけの記述で値を渡しながら遷移できるのは驚き、、
pybind11 で ImportError: dynamic module does not define init function

## 概要
pybond11でc++で自作したclassをbuildしてpythonでimportしたところ、
`ImportError: dynamic module does not define init function`というエラーが出てきた。

## 原因
なんてことはない。。
`PYBIND11_MODULE(モジュール名, m) `　が間違ってた。コンパイルされた`.cpython-39-darwin.so `ファイル名と一致させて解決。
PandasのデータフレームをRに読み込ませる

# やりたいこと
rpy2やpyperでPythonからRを呼び出せることは知っていた。しかし，Pythonで整形したデータフレームをRが読み込んでRStudio上などで解析するやり方が探せなかったので，以下にやり方を残しておく。

# やり方
確認した実行環境

- Python 3.9.0
- R 4.1.1
- pandas 1.2.5
- PypeR 1.1.2

```{python:converter.py}
import pyper
import pandas as pd
from pathlib import Path, PosixPath
from typing import Union

def save_rds(df: pd.core.frame.DataFrame, file: Union[str, PosixPath]) -> bool:
    strfile = str(file)
    pathfile = Path(file)
    # datetime型があると変換エラーが起こるのでstrにする
    df = pd.concat([df.select_dtypes('datetime').astype(str), df.select_dtypes(exclude='datetime')], axis=1)
    # PosixPathがあると変換エラーが起こるのでstrにする
    df = pd.concat([df.select_dtypes('object').astype(str), df.select_dtypes(exclude='object')], axis=1)
    r = pyper.R(use_pandas='True')
    r.assign("df", df)
    r(f'saveRDS(df, file="{strfile}")')
    ret = r.get(f'readRDS("{strfile}")')
    if ret is None:
        print('Conversion failed')
        pathfile.unlink()
        return False
    else:
        return True
```

## 解説
なんということはなく，pyperなどでデータフレームをR側に渡して，`saveRDS()`でシリアライズしているだけである。
自分がつまづいた点としては，

1. Pandasにdatetime型があると変換に失敗する
1. Pandasのobject型の中にPosixPathがあると変換に失敗する (自分はファイルの解析をする際にパス情報としてよく入れている)
1. 日本語が入っていると変換に失敗する

があり，1, 2の対策は関数の中に実装した。他にもいろいろあると思うので`saveRDS()` の後に`readRDS()`でバリデーションしている。Conversion failedが出たら適宜対策を入れてほしい。

あとはR側で`readRDS()`してもらえればよい。余談ではあるが，`str`に変換した`datetime`はR側では`as.Posixlt()`すれば時間として扱うことができる。

以上
Flask+スクレイピングで記事一覧画面を作ろう①

<h2>概要</h2>
・Yahoo!ニュースの記事一覧からトピックス一覧を取得
・取得したものを、FlaskでWebアプリ化
<h2>スクレイピングをしてデータを取得しよう</h2>
Flaskでアプリを構築する前に、取得したいデータをスクレイピングで取ってきます( jupyterなどで実行すると良い！)
必要なライブラリをインポートします

```python
import requests
from bs4 import BeautifulSoup
```
requests: URLにアクセスします
BeautifulSoup: ページのhtmlタグから情報を取得します

では早速情報を取ってきましょう。今回は[トピック一覧-Yahoo!ニュース](https://news.yahoo.co.jp/topics)から情報を取得します。
欲しいデータは、
　1. 国内、国際、経済、エンタメ、スポーツ、ITなどのカテゴリ
　2. カテゴリごとのURL
　3. カテゴリごとのトップ8個の記事
　4. 3のURL
まず、requestsとBeautifulSoupの準備を行いましょう。

```python
# urlは今回ターゲットとなるURL
url = 'https://news.yahoo.co.jp/topics'
# requests.getでurlにアクセス
r = requests.get(url)
# htmlからのデータ取得を可能にする
soup = BeautifulSoup(r.text, 'html.parser')
```


これで準備が完了したので、カテゴリ名とURLを取っていきます。

```python
# pタグで、クラス名が"sc-hqyNC iOQlXg"となっている部分にカテゴリの情報が存在する
categories = soup.find_all('p', class_='sc-hqyNC iOQlXg')
# カテゴリ名を格納するリスト
category_names = []
for category in categories:
    print(category.get_text())
    # category_namesに、カテゴリ名を追加(append)する
    category_names.append(category.get_text()) # get_text()とすることで、htmlタグの表示を削除できます
```
同じ容量でカテゴリに対応するURLも取得していきます。

```python
# カテゴリのURLを格納するリスト
category_links = []
for category in categories:
    # aタグからは/categories/{カテゴリ名}しか入手できないため、
    # 'https://news.yahoo.co.jp'と結合することで、URLを作成する
    category_link = 'https://news.yahoo.co.jp' + category.find('a').get('href')
    category_links.append(category_link)
```
続いて、記事を取得します。[トピック一覧-Yahoo!ニュース](https://news.yahoo.co.jp/topics)を見て貰えば分かりますが、本来ならカテゴリごとに8件づつ記事が表示されています。
しかし、取得する際にはカテゴリ関係なく記事を取得してしまいます。
これに関しては、アプリを構築する際に解決するので、とりあえずデータを全部取ってきましょう。

```python
# liタグで、クラス名が"sc-ksYbfQ gSBRIC"となっている部分に記事情報が存在する
li_lists = soup.find_all('li', class_="sc-ksYbfQ gSBRIC")
# 記事の名前を格納するリスト
article_names = []
for li_list in li_lists:
    article_name = li_list.find('a').get_text()
    article_names.append(article_name)
```
同じ容量で記事に対応するURLも取得していきます。

```python
# 記事のURLを格納するリスト
article_links = []
for li_list in li_lists:
    article_link = li_list.find('a').get('href')
    article_links.append(article_link)
```
以上で必要な情報は全て取得できました！
では実際にこれまでのデータを整理して表示してみましょう。
少し複雑なコードですが、表示させたいだけなので説明は省きます。

```python
# カテゴリごとの記事を8件ずつ表示するため、startとendで範囲を指定する
start = 0
end = 8
for (category_list, category_link) in zip(category_names, category_links):
    print(category_list, f'({category_link})\n')
    
    for index in range(start, end):
        print('　', article_names[index], f'({article_links[index]})\n')

    # startとendの更新
    start += 8
    end += 8
    print('\n')
```

以上で下準備は完了しました！
コードは、説明のためにfor文を分けましたが、適宜対応してください。
次回からFlaskで実装をしていきます。
ありがとうございました🙇‍♂️
[Flask+スクレイピングで記事一覧画面を作ろう② - Qiita](https://qiita.com/Yuthon/items/4c9754b0d14b40122165)
【Kotlin】valiktorでカスタムのバリデーションを作成する

## 概要
Kotlinでは、オブジェクトのバリデーションを行うライブラリで`valiktor`というものがあります。概要は[valiktorを使ってVO値のバリデーションを行う](https://qiita.com/Takuyaaaa/items/32cca66d57a5a5934b26)の記事をご参照頂ければと思いますが、バリデーションをシンプルに実装出来て、いい感じはします。
さて、今回はこのvaliktorでカスタムのバリデーションを実装したい場合、どうすれば良いかというのを書きます。

## 対応
ドキュメントの[Creating a custom validation](https://github.com/valiktor/valiktor#creating-a-custom-validation)に方法が書いてあります。バリデーション用のconstraintクラスと拡張関数を別途作成する必要があります。

## 実装サンプル
文字列で入力されたURLのフォーマットチェックを、URLオブジェクトを用いて行う実装を例にします。

**　【カスタムバリデーションの定義】**


```kotlin
import org.valiktor.Constraint
import org.valiktor.Validator
import java.net.URL

class UrlValidator : Constraint

fun <E> Validator<E>.Property<String?>.checkUrlFormat() =
    this.validate(UrlValidator()) {
        if (it != null) {
            try {
                URL(it.toString()).toURI();
            } catch(ex: Exception) {
                return@validate false
            }
            // URLオブジェクトのパースに成功したらtrue
            return@validate true
        } else {
            return@validate false
        }
    }

```

**【カスタムバリデーションの使用箇所】**

```kotlin
import com.sample.validator.checkUrlFormat

import org.valiktor.functions.isNotBlank
import org.valiktor.validate

data class SampleRequest(val title: String = "", val url: String = "") {
    init {
        validation()
    }

    private fun validation() {
        validate(this) {
            validate(SampleRequest::title)
                .isNotBlank()
            // ここがカスタムバリデーションの使用箇所
            validate(SampleRequest::url)
                .checkUrlFormat()
        }
    }
}

```
GASでエラーが発生した際にエラーメールを送信する方法

GASの自動化処理でエラーが発生した場合、自分宛てにメールを送信してみようと思った時のメモ。

# ソースコード
関数名とか変数名とかファイル名はこだわらないタイプです。

```gas:error.gs
// わざとエラーを出す関数
function getErrorValue() {
  // 現在のシートを取得
  const Sheet = SpreadsheetApp.getActiveSheet();

  try {
    // A0のセルを取得→A0セルは存在しないため、エラーが発生する
    Sheet.getRange("A0").getValue();
  } catch (e) {
    // エラー発生時にメールを送信
    sendErrorMail(e);
  }
}

// エラーメールを送信
function sendErrorMail(Error) {
  GmailApp.sendEmail(
    "**********@gmail.com", //←宛先アドレス
    "自動化の処理でエラーが発生しました", //←タイトル
    getMailBody(Error), //←メール本文
    {
      name: "自動返信アカウント"
    }
  );
}

// メール送信時の本文を作成
function getMailBody(Error) {
  // 今日の日付
  const DateObj = new Date();
  const Today = Utilities.formatDate(DateObj, 'Asia/Tokyo', 'yyyy年MM月dd日 hh時mm分ss秒');

  return Body = `
  自動化スクリプトでエラーが発生しました。
  担当者の方は至急確認をお願いします。

  〇エラー内容
  ${Error}

  〇エラー発生時刻
  ${Today}

  以上です。
  `
}
```

関数の流れは
①`getErrorValue()`を実行
②スプレッドシートのA0セルの値を取得
③A0セルは存在しないので、エラーが発生
④エラーをcatch!!!
⑤`sendErrorMail(Error)`を実行する。この時エラー分を引数に渡す
⑥`GmailApp.sendEmail`で宛先、タイトル、本文を決める
※nameはなくても良いので省略
⑦`getMailBody(Error)`でメール本文をreturn
⑧送信完了 

実際は`Sheet.getRange("A0").getValue();`の中にメイン処理を入れる。
また、catchの後ろに`finally`を入れることで、エラーの有無に関わらず実行する処理を追加できる。
今回はメール本文を`getMailBody()`で取得しているが、スプレッドシートにエラー分を定義しておいてそれを取得してくるのも良い気がする。何故なら、発生したエラー毎にメール本文を分岐で選択しやすくなるから。

# 実行結果
メールが届いた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1955768/4083d3db-e647-6f00-b79e-729256ed13f9.png)

メール本文も普通だった。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1955768/2e1a4f00-a25a-e3a5-3132-ef89921fcfd5.png)
【laravel】Auth::loginでログインできたと思ったらできていなかった問題

とある機能の実装をしていまして、

`Auth::login`メソッドを使ったログインが必要になったのですが、、、、

ハマってしまった。。。

ありのままに起こったことを話そうと思います。


# 現象

ユーザのオブジェクトを入力してログイン認証を進めてくれる`Auth::login`メソッド。

期待通り、ログインが成功して、期待通り、ログイン後の画面遷移が行われるはずだったのですが....

まさかの 401 unauthorized エラー

# 原因

どうやらログインそのものはできていたものの、セッションが保持されていなかったようです。

なので、セッションを保持させる解決策が必要。。。。

# 解決方法

`app/Http/Kernel.php`の設定をいじる必要があったようです。

設定ファイル内の`$middleware`に`\Illuminate\Session\Middleware\StartSession::class`を追加

```php:app/Http/Kernel.php
protected $middleware = [
        ...,
        \Illuminate\Session\Middleware\StartSession::class
    ];
```

アタイ、こんなこと聞いてへん！って感じですが、これでセッションも維持されるようです。

ここら辺の認証まわり、知見がまだまだなので、もっとこういうやり方あるよ！だったり、アドバイスあればぜひお聞かせ願いたいです。

参考URL：
https://www.it-mure.jp.net/ja/php/laravel-auth%EF%BC%9Aattempt%EF%BC%88%EF%BC%89%E3%81%AF%E3%83%AD%E3%82%B0%E3%82%A4%E3%83%B3%E3%82%92%E4%BF%9D%E6%8C%81%E3%81%97%E3%81%BE%E3%81%9B%E3%82%93/1043686939/
railsチュートリアル第４章 クラス継承

クラスについて学ぶとき、superclassメソッドを使ってクラス階層を調べてみるとよくわかります。

```rb
>> s = String.new("foobar")
=> "foobar"
>> s.class                        # 変数sのクラスを調べる
=> String
>> s.class.superclass             # Stringクラスの親クラスを調べる
=> Object
>> s.class.superclass.superclass  # Ruby 1.9からBasicObjectが導入
=> BasicObject
>> s.class.superclass.superclass.superclass
=> nil
```
StringクラスのスーパークラスはObjectクラス
ObjectクラスのスーパークラスはBasicObjectクラス
BasicObjectクラスはスーパークラスを持たないことがわかる。
この図式は、すべての Ruby のオブジェクトにおいて成り立ちます
クラス階層をたどっていくと、 
```Rubyにおけるすべてのクラスは最終的にスーパークラスを持たないBasicObjectクラスを継承```する。
"Rubyではあらゆるものがオブジェクトである" ということの技術的な意味になる。
```BasicObject```
　　↑
```Object```
　　↑
```String```

```rb
>> class Word
>>   def palindrome?(string)
>>     string == string.reverse
>>   end
>> end
=> :palindrome?
```

```rb
>> w = Word.new              # Wordオブジェクトを作成する
=> #<Word:0x22d0b20>
>> w.palindrome?("foobar")
=> false
>> w.palindrome?("level")
=> true
```
少し不自然に思えるならば、勘が鋭い
文字列を引数に取るメソッドを作るためだけに、わざわざ新しいクラスを作るのは変
Wordクラスは Stringクラスを継承するのが自然

######コンソールでWordクラスを定義する。
```rb
>> class Word < String             # WordクラスはStringクラスを継承する
>>   # 文字列が回文であればtrueを返す
>>   def palindrome?
>>     self == self.reverse        # selfは文字列自身を表します
>>   end
>> end
=> :palindrome?
```
継承のためのRubyの Word < String 記法

```rb
>> s = Word.new("level")    # 新しいWordを作成し、"level" で初期化する
=> "level"
>> s.palindrome?            # Wordが回文かどうかを調べるメソッド
=> true
>> s.length                 # WordはStringで扱える全てのメソッドを継承している
=> 5
```
WordクラスはStringクラスを継承しているので、コンソールを使ってクラス階層

```rb
>> s.class
=> Word
>> s.class.superclass
=> String
>> s.class.superclass.superclass
=> Object
```
階層
```　BasicObject　```
↑
```Object ```
↑
```String ```
↑
```Word ```
となっている。

Wordクラスの中から自分自身が持つ単語にアクセスすることで行なっていることにご注目
```Wordクラスの中では、selfはオブジェクト自身を指します。```

```rb
self == self.reverse
```

```rb
self == reverse
```

####演習
1.Range,Hash,Symbolクラスの継承階層を調べろ。

```rb
>> s = Range.new(1, 5)
=> 1..5
>> s.class
=> Range
>> s.class.superclass
=> Object
>> s.class.superclass.superclass
=> BasicObject
>> s.class.superclass.superclass.superclass
=> nil

>> s = {"a" => "b", "c" => "d", "e" => "f" }                               
=> {"a"=>"b", "c"=>"d", "e"=>"f"}
>> s.class
=> Hash
>> s.class.superclass
=> Object
>> s.class.superclass.superclass
=> BasicObject
>> s.class.superclass.superclass.superclass
=> nil

>> s = :symbol
=> :symbol
>> s.class
=> Symbol
>> s.class.superclass
=> Object
>> s.class.superclass.superclass
=> BasicObject
>> s.class.superclass.superclass.superclass
=> nil
```
全てBasicObjectクラスに繋がっている。

2.self.reverseのselfを省略し、reverseと書いて動くことを確認しろ。

```rb
>> class Word < String
>>   def palindrome?
>>     self == reverse
>>   end
>> end
=> :palindrome?

>> s = Word.new("level")
=> "level"
>> s.palindrome?
=> true
```
a要素とclass要素の合体コーディング！！

◾️ 普通a要素とclass要素を同時に使う際、下記のような　書き方になる。

https://gyazo.com/8765b32c61c8bb8be8e76523af0f14da

最初にclass要素が来て、その後にa要素が付く感じだが、コードが見難いと密かに思っていた :frowning2:

◾️ 下記のようなコードの書き方なら簡潔で、見易くなる。

https://gyazo.com/577ff0b1ad7427cfa9a5caed8215112e

このような書き方にすることで、a要素とclass要素を合体できる！:relaxed:

今日の投稿は以上です。是非この学びを頭にマージしていきましょう！

wagaでした！