OmniAICreator/Qiita-1.07M huggingface dataset:
[Rails]投稿機能にyoutube動画の埋め込みを可能にする際にハマったこと。

ユーザーがポートフォリオに記事を投稿する際、youtubeの共有リンクを貼り付け動画を埋め込めるようにする機能を実装しようとして、手こずった事があったので備忘録として残しておきます。

#何にハマったのか
既にQiitaに同じような実装をされている方の記事が複数あったため、それを参考にすれば何ら問題なく実装できました。
しかしながら、参考記事は新規投稿に関するもので、投稿の編集（update）の場合については書かれていません。色々と試しましたが自力で実装ができませんでした。

###新規投稿の場合
createアクション（新規投稿）での実装方法はこのような感じです。

```ruby:posts_controller.rb
  def create
    @post = Post.new(post_params)
    url = params[:post][:youtube_url].last(11)
    @post.youtube_url = url
  end
```

なぜこのような手段を取っているのか等の詳細は割愛します。以下の記事がとてもわかりやすいです。

[railsアプリに投稿されたYouTubeURLを自動的に埋め込み表示させる方法~無理やり編~](https://qiita.com/Kairi_Yasunnde/items/8e931a4670549ba8237e)

###編集updateでやってみた（失敗）

新規投稿は上記の方法で実装できましたが、このままでは投稿の編集をする際、
例えば_**全く別の動画のURLを貼り付けて更新する**_と、"https://~~~"から始まる全ての文字列をデータベースに保存してしまいます。
当然このままではviewで表示した際に動画が正しく埋め込まれません。
「でも理屈は同じだから、updateアクションの前にURLを削ぎ落とす処理を足せばいいんじゃね？」と思って以下のようにやってみました。

```ruby:posts.controller.rb
※駄目な例です※
  def update
    @post = Post.find(params[:id])
    # ここから
    url = params[:post][:youtube_url].last(11)
    @post.youtube_url = url  # ここまで追加

    if @post.update(post_params)
      flash[:success] = '更新しました。'
      redirect_to @post
    else
      flash.now[:danger] = '更新に失敗しました。'
      render :edit
    end
  end
```

ただこれだと駄目でした。更新するとyoutube_urlのカラムにはURLがそのまま全部登録されてしまいます。何でや〜！！

#結果わからなかったので、「発想の転換」
情けない話ですが、解決できませんでした。
しかしながら、色々調べていく中で"before_save"というコールバック関数に目をつけました。
**「コントローラーじゃなく、モデル側でデータベースに保存する時に削ぎ落とせるのでは？」**

Railsチュートリアルにはbefore_saveが使われている？ようですね。私は通っていないので知りませんでした。
before_saveを使うと、saveのメソッドが実行される直前に、指定した処理を行う事ができるようです。
(ちなみにbefore_updateという関数もあり、この場合はupdateの場合のみに実行される為、個別に指定する事もできます)
今回はcreateでもupdateでも「URLを削ぎ落とす」という処理は同じなので、before_saveで一括することにしました。

##before_save
```ruby:post.rb
  class Post < ApplicationRecord
    before_save :slugify

    def slugify
      self.youtube_url = youtube_url.last(11)
    end
  end
```

slugify()というメソッドを定義し、その中身の処理としてURLを削ぎ落とす内容を記述しました。
(slugifyという言葉の使い方には誤りがあるかもしれないです。それっぽいワードが使いたかった)
ユーザーがformで入力した内容がsaveメソッドによりDBに保存されるまでは、パラメータとしてはyoutube_urlは"https://~~"の形で送られています。（これはターミナルにて確認できます。）
なので

```ruby
youtube_url.last(11)
```

として末尾の11文字だけを取り出し、self.youtube_urlへ再度代入します。
そして、"before_save"によってデータベースへの保存の直前にその関数が呼び出されるようにしました。

##不要な処理は削除します(create, updateアクション両方)

```ruby:posts_controller.rb
    url = params[:post][:youtube_url].last(11)
    @post.youtube_url = url
```
この処理はモデルファイルに書いたものと重複するので、削除します。

#できた！
無事にURLが削ぎ落とされて、埋め込みが可能になりました。



***
参考記事
[railsアプリに投稿されたYouTubeURLを自動的に埋め込み表示させる方法~無理やり編~](https://qiita.com/Kairi_Yasunnde/items/8e931a4670549ba8237e)
[苦しめられてやっと理解できたRailsコールバックの使い方](https://tech.kitchhike.com/entry/2018/06/30/232400)
sudo 脆弱性 CentOS・RHEL・Ubuntu・AmazoLinux系 対応方法  (CVE-2021-3156)

### 概要
sudo 脆弱性が発表されたので (CVE-2021-3156)
各OSでアップデート対応手順をまとめました。
実際の手順は検証してから作業お願いします。
私の場合はAWS環境で各OSのAMIで確認してます。

>対象となる製品とバージョンは次のとおりです。なお、各ディストリビューションにおける対象バージョンは、ディストリビュータの情報を参照ください。
>
- sudo バージョン 1.8.2 から 1.8.31p2
- sudo バージョン 1.9.0 から 1.9.5p1

>なお、本脆弱性を発見したQualys社は、"sudoedit -s /"コマンドを実行し、"sudoedit:"から始まるエラーが表示されると脆弱性の影響を受け、"usage:"から始まるエラーが表示されると影響を受けない、という情報を公開しています。
https://www.jpcert.or.jp/at/2021/at210005.html

参考:
https://www.jpcert.or.jp/at/2021/at210005.html
https://security.sios.com/vulnerability/sudo-security-vulnerability-20210127.html

### CentOS7・AmazonLlinux2・AmazonLlinux・RHEL8・RHEL7
```
sudo 脆弱性対応 手順書作成
■CentOS7・AmazonLlinux2・AmazonLlinux・RHEL8・RHEL7
- 作業前確認 (sudoedit:  ~ と表示される場合は対応が必要です。)
$ sudoedit -s /
----
sudoedit: /: 通常ファイルではありません
----
- パッケージアップデート
$ sudo yum update sudo
- 確認 (usage: ~ 始まれば対応完了です。)
$ sudoedit -s /
----
usage: sudoedit [-AknS] [-r role] [-t type] [-C num] [-g group] [-h host] [-p prompt] [-T timeout] [-u user] file ...
----
```

### ※サポート終了のOS (CensOS6とCentOS5)
```
■CentOS6
rpm -Fvh https://github.com/sudo-project/sudo/releases/download/SUDO_1_9_5p2/sudo-1.9.5-3.el6.x86_64.rpm
sudoedit -s /
----
usage: sudoedit . . .
----

■CentOS5
rpm -Fvh https://github.com/sudo-project/sudo/releases/download/SUDO_1_9_5p2/sudo-1.9.5-3.el5.x86_64.rpm
sudoedit -s /
----
usage: sudoedit . . .
----
```

### Ubuntu 16.4LTS 18.04LTS 20.04LTS
```
Ubuntu 16.4LTS 18.04LTS 20.04LTS
■バージョン確認
$ cat /etc/issue
----
Ubuntu 18.04.5 LTS \n \l
----
■対象か確認
$ sudoedit -s /
----
sudoedit: /: not a regular file
----
■パッケージリストを確認
dpkg -l sudo
----
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name                Version        Architecture   Description
+++-===================-==============-==============-===========================================
ii  sudo                1.8.21p2-3ubun amd64          Provide limited super user privileges to sp
----
■パッケージリストの更新
sudo apt update
■sudo パッケージ更新
sudo apt install sudo
■確認
sudoedit -s /
----
usage: sudoedit [-AknS] [-r role] [-t type] [-C num] [-g group] [-h host] [-p prompt] [-T timeout]
                [-u user] file ...
----
```
関連エンティティがあるときのJPQLの書き方

###環境
Spring boot


###参考にしたサイト
[Spring DATA JPAでデータ検索](https://dev.classmethod.jp/articles/spring-data-jpa_search/)
[JPQLの内部テーブル結合を試してみる](https://hermesian.hatenablog.com/entry/2013/09/30/185347)

###エラーメッセージ
MySQL server version for the right syntax to use near '' at line 1

もうこし長かったけど、構文エラーがあるよってエラー。


###原因
JPQLの書き方が間違っていた！というか、MySQLのNativeQueryとはちょっと書き方がちがうんだなぁ～くらいの認識でしたけど、結構違う感じでしたね。

特に`@OneToOne`とかの関連エンティティがある場合の扱い方が間違っていました。

外部キーで結合するので、`LEFT JOIN`とか書いていたけど、それが原因でした。

application.propertiesに次のように書いて、SQLを参考にしました。コンソールに大量に表示されるようになります。

```:application.properties
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
spring.jpa.show-sql=true
```

けど、MySQLのSQL文とはなんかが違うみたいですね。


###Hibernateってなに？
wikiによると
>
Java のためのオブジェクト関係マッピング (ORM) ライブラリであり、オブジェクト指向のドメインモデルを関係データベースにマッピングするためのフレームワークを提供する。


初心者には難しいですけど、多分の解釈でいうと、
`データベースから取得してきたデータを、オブジェクトとかインスタンスのフィールドに代入して、以降はオブジェクトとして扱えるようにするためにHibernateっていうのがよしなにやってくれる`

って認識で良さそうです。

PHPの学習をしているときには、
1. DB接続
2. レコード取得
3. カラムを取得
4. 配列に格納
5. DB切断

って言う流れをそのまま書いてましたね。オブジェクトとかクラスをまだ知らないときです。

Javaをやりだして、早速クラスを勉強して、便利さもわかってきたところでなんとデーブルをそのままクラスと対応させることができるということもできることを理解しだしたのが最近です。


###JPQLってなに？

>JPAでDB(正確にはエンティティ)からデータを取得するSQLをJPQLと言います。

RepositoryでJPAが出てきてたな。これでデータベースから取得してクラスに格納できるようになるんだなと、なんとなく理解。

Repositoryでも@Queryアノテーションを付けてfindBy~みたいなメソッドを定義したことあったけど、なんのこっちゃわかっていませんでした。

でも今日わかったことが。

```java
// 普通のSQL文を自分で書く
@Query(value="select * from なんちゃら～", nativeQuery = true)
```

```java
// これがJPQLで、テーブルと紐付けたエンティティでSQL文を書ける的な
@Query("select エイリアス from オブジェクト エイリアス ～")

```

確かにわかりやすい記述ができるから便利だな～


###エンティティの中に別のエンティティがあったらどうするの？


`spring.jpa.show-sql=true`としていると、
jpaで発行されたSQLがコンソールに出力されるので、それを見ると、結合しているテーブルがある場合は`left outer join`って書いてました。

ちょっと複雑な条件の場合は生のSQL文を書いて、結合の部分は`left outer join`って書けばいいんだなとあいまいに考えていましたが、ちゃいましたね。

@OneToOneや@OneToManyなどのアノテーションで関連を記述していたら、そのエンティティを含むオブジェクトをデータベースから取得する際にjpaが勝手に中のエンティティのデータも持ってきてくれる。


###イメージ

```java:Book.java

public class Book {
private Integer id;
private String name;

@OneToOne( fetch = FetchType.EAGER ,cascade = CascadeType.ALL)
@JoinColumn(name="buyer_id")
private Buyer buyer;

}

```

```java:Buyer.java
public class Buyer {
private name;
private address;
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/668402/a3e92e9c-57b9-0bc1-a936-d23cb17ecd07.png)

こんなイメージの関係性で、この場合は、

```java
@Query("select b from Book b")
```

とするだけで、Buyerもちゃんと取ってきてくれる。


###Joinとか書いてたら永遠に構文エラーが発生する

```java
@Query("select b from Book b JOIN Buyer")
```
って書いてたら永遠に構文エラーになります。

しかもどこがおかしいっていうメッセージも、なんか場所がちがうんですよね。

```
near '' at line 1
``

ってどこ？？`''`の中におかしいところがあるよってメッセージだけど、なんかちゃんと教えてくれませんでした。


###結論！

JPQLとSQLは違うよっていう明確な、強い意志と理念が必要！！
Raspberry Pi 4 をsambaサーバーにする

# これは何

Raspberry Pi 4のファイルを、Windows, Macからみえるようにするための設定です。

# 背景

Raspberry Piの gpio を制御する Python プログラムを書く際に、これまではMacとRaspberry Piで書いており、ファイルの共有はAFPを使っていました。
最近はWindowsからも作業することが多くなったので、Sambaを使うことにしました。

相変わらず、ファイルのパーミッションは700なのね。。。

# インストールから設定

ちゃちゃっといきます。

```sh
$ sudo apt-get install samba samba-common-bin
$ sudo smbpasswd -a pi
$ sudo cp -p /etc/samba/smb.conf /etc/samba/smb.conf.org
$ sudo service smbd restart
```

設定ファイルの編集

```sh
$ sudo vi /etc/samba/smb.conf
[pi]
   comment = Welcome to pi Server
   path = /home/pi/share
   browseable = yes
   wriable = yes
   read only = no
   guest ok = no
```

## Macからの接続

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191337/9e80ee18-1d38-1d5e-3609-89718178754a.png)

## Windows 10からの接続



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191337/30d626ab-4bb1-814f-2089-03897dbdb0b0.png)

エクスプローラーにRaspberry Piのアドレスを入力して

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191337/6492d711-d252-9d43-397c-afe92ca30b83.png)

先ほどのアカウントでログインします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191337/9893f69a-9731-31ab-d04e-2c2e1c77c857.png)


とても快適です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191337/7f08afe2-e860-4ec9-d823-fc50a2df1d5d.png)
アプリの一部をWebViewにするメリット・デメリット

## 前提条件

- iOSとAndroidの両方で同じアプリを開発する
- Webでも同じようなアプリを提供する

## メリット

- iOSとAndroidで共通のWebページが使える  
→アプリ側の工数と、アプリ側とWeb側を合計した全体の工数が減る
- Webページのコーディングを並行して別の人に振れる  
→スケジュールを短縮できる
- アプリよりWebエンジニアのほうが人を集めやすい

## デメリット

- Webページを実装する必要がある  
アプリ独自のWebページを作るのでなく、レスポンシブデザインにできるといい
- WebViewが多いとリジェクトされる（iOS）  
→プッシュ通知を付けるだけで通ることもあるよう
- スマホ固有の機能（カメラやNFC読み取りなど）はWebViewにしにくい
- 機能にもよるが、ネイティブのほうが使い勝手がいい
- 通信する分だけネイティブよりパフォーマンスが落ちる
- オフラインで使えない
- 認証周りを工夫する必要がある  
→ログインが必要なアプリの場合、Webページを開いたときにログイン状態になっていないといけない

## まとめ

WebView化は工数削減の手段になり、すでにWebアプリがあると特に有効です。

## 参考リンク

- https://twitter.com/mikkameee/status/1355075019978625031?s=20
Ceph(Octopus)の構築(設定編 cephFS/mds)


##__はじめに__
この記事では、タイトルのとおり現時点(2021.01)で最新である__ceph(octopus)__の構築を目的としています。
また、自分で構築した手順の備忘録を兼ねているので、細かいところで間違いなどあるかもしれません。

基本的には公式のDOCUMENTATIONが必要なことを全て網羅しているので一読しておくことをお勧めします。
Linuxの知識もある程度必要になるので他サイトや書籍などで事前に基本は押さえておくとよいでしょう。

準備編等は関連記事を参照してください。

##__関連記事__
[Ceph(Octopus)の構築(準備編 ハードウェア)](https://qiita.com/iriya_v00v/items/651eff2955d5ad7eadf6)
[Ceph(Octopus)の構築(準備編 ソフトウェア)](https://qiita.com/iriya_v00v/items/e3268fe75423ba0304b3)
[Ceph(Octopus)の構築(設定編 共通)](https://qiita.com/iriya_v00v/items/d7d9e439cf4159acae2c)
[Ceph(Octopus)の構築(設定編 ブートストラップ)](https://qiita.com/iriya_v00v/items/d7bcf4dfa6324bacd91a)
[Ceph(Octopus)の構築(設定編 mon/mgr/osd)](https://qiita.com/iriya_v00v/items/75eefdefb7ec61d24812)
Ceph(Octopus)の構築(設定編 cephFS/mds)　この記事
[Ceph(Octopus)の構築(設定編 Crush Map)](https://qiita.com/iriya_v00v/items/2a263a7817434e8b91ed)

##__cephFSボリュームの作成__
ここで作成するcephFSのボリューム名は「share」とします。作成自体はコマンド1つで完了です。

```
cephadm shell
　　ceph fs volume create share
```

##__mdsの自動展開を無効__
自動展開を無効にしておかないとノードに意図した役割を持たせることができません。(勝手にmdsが展開されます。)
自動でやってくれるのはありがたいのですが、今回はノード毎に役割を決めているので無効化しておきます。

```
cephadm shell
　　ceph orch apply mds share --unmanaged
```

##__mds daemonの数を指定__

```
cephadm shell
　　cceph fs set $shareName max_mds 3
```

##__mds daemonの追加__

```
cephadm shell
　　ceph orch daemon add mds share ceph-mds01
　　ceph orch daemon add mds share ceph-mds11
　　ceph orch daemon add mds share ceph-mds21
```

##__dashboardの確認(cephFSボリューム)__
dataとmetaのボリュームがあれば問題ありません。device_health_metricsは自動生成されました。
![01.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1033108/a0260c10-322f-4b3e-537a-0e9ee7298267.png)

##__dashboardの確認(mds)__
Ranksにあるmdsが稼働中のものです。StandbysはRanksにあるmdsが何らかの理由で止まった場合にアクティブになり、Ranksに入るようです。
![02.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1033108/743353aa-5adb-e2d3-9724-820c72f29546.png)

##__おわりに__
これでcephの設定は完了です。あとは作ったボリュームをsambaで公開すればwindows等からも使えるようになります。
WordPressの投稿者ページで記事一覧にカスタム投稿タイプも表示する

WordPressの投稿者ページにて、以下のようにして記事一覧を表示するようにしました。

```php
<?php if ( have_posts() ) : ?>
    <?php while ( have_posts() ) : the_post(); ?>
        ここに記事を表示するロジックを書く
    <?php endwhile; ?>
<?php endif; ?>
```

これで、記事一覧は表示されるのですが、デフォルトで表示されるのは「投稿」で書いている記事だけです。

## 記事の一覧にカスタム投稿タイプを表示する

僕が使用していたWordPressでは、投稿は使用していなく、カスタム投稿タイプを使用していたので、カスタム投稿タイプで書いた記事を一覧に表示するやり方です。

functions.phpに以下を追加します。
※column、caseという名前のカスタム投稿タイプを使用した例です

```php:functions.php
function author_search_filter($query) {
  if (!is_admin() && is_author() && $query->is_main_query() ) {
    $query->set('post_type', array( 'column', 'case'));
  }
}
add_action( 'pre_get_posts','author_search_filter' );
```

`is_author()`で、投稿者ページを表示する時のクエリに対して、投稿タイプにカスタム投稿タイプを設定するというのをやっています。

また、`!is_admin()`も加えて、管理画面のクエリは対象外とするようにします。

## is_author()は管理画面でtrueと判定される？

当初、上記のロジックには`!is_admin()`を入れていなかったのですが、以下のような不具合が発生していました。
管理画面でカスタム投稿タイプの一覧を見た時に、選択しているカスタム投稿タイプとは別のものが表示されてしまいました。

1. 新しくカスタム投稿タイプ（例、news）を追加する
1. 管理画面で新しく作ったカスタム投稿タイプの一覧を見た時、既存のカスタム投稿タイプ（例、column）の記事が一覧に表示されている

最初は原因が全く分からず苦労したのですが、プログラムを追っていくと、管理画面でカスタム投稿タイプの一覧を見た時に、`is_author()`がtrueになっていたので、上記のプログラムの条件を満たして、クエリが変わっていたのが原因でした。

`is_author()`は投稿者ページを判断する処理なのに、管理画面の関係ないところでtrueになるんですね。
ドキュメントも見てみましたが、結局よく分かりませんでした。

フロントで使うロジックには、`!is_admin()`の条件を入れたほうが良いということですね。
これは勉強になりました。
【Mac】Nodeインストール手順の備忘録


# はじめに
- Mac環境上で、Nodeの開発環境を構築する機会があったので、その備忘録です。
- Nodeの管理ツールとして、nodebrewを使用しました。

# Homebrewのインストール

```sh:zsh
# スクリプト実行
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# ログ
==> This script will install:
/usr/local/bin/brew
/usr/local/share/doc/homebrew
# ログイン時のPasswordを入力
Password:
==> /usr/bin/sudo /bin/chmod g+rwx /usr/local/bin
︙
Already up-to-date.
==> Installation successful!
# インストール確認
brew --version
# ログ
Homebrew 2.7.7
```

# nodebrewのインストール

```sh:zsh
# インストール実行
brew install nodebrew
# Shellの確認
echo $SHELL
# → /bin/zsh
# .zshrcが無い場合、作成
touch .zshrc
# ~/.zshrcにnodebrewのPATHを追記
% echo 'export PATH=$HOME/.nodebrew/current/bin:$PATH' >> ~/.zshrc
# ファイル読み込み
source ~/.zshrc
# インストール確認
nodebrew
# → nodebrew 1.0.1 
# セットアップ実行
nodebrew setup
```

# Node.jsのインストール
- インストール可能なバージョンを確認します。

```sh:zsh
# インストール可能なバージョンを表示
nodebrew ls-remote
# → v0.0.1 v0.0.2 ~
# → v15.0.0 v15.1.0 ~
# → io@v1.0.0 io@v2.0.0 ~ 
```

- バージョンを指定して、インストールします。

```sh:zsh
# v12.20.1をインストール
nodebrew install v12.20.1
```

- インストール済みバージョンを確認します。

```sh:zsh
nodebrew list
# → v12.20.1
```

- インストール済みバージョンを有効にします。

```sh:zsh
nodebrew use v12.20.1
node -v
# → v12.20.1
```

- 別バージョンをインストールして、切り替えます。

```sh:zsh
# v14.15.3をインストール
nodebrew install v14.15.3
# インストール済みバージョンを表示
nodebrew list
# → v12.20.1
# → v14.15.3
# v14.15.3を有効化
nodebrew use v14.15.3
node -v
# → v14.15.3 
```
日付関数と誕生日を用いて、年齢を算出する方法（PHP）

外部のAPIを叩いて、年齢を算出する処理を書く必要があったので、その時に実行した関数のことを記録しておく。

##答えのコード

```PHP:sample.php
date_default_timezone_set('Asia/Tokyo');
$currentDate = date('Y/m/d');  //2020-01-29
$birthday = "あなたの誕生日　例：1980-01-01";
$fc = (int)date('Ymd', strtotime($currentDate)); //20200129
$fb = (int)date('Ymd', strtotime($birthday));    // 19800101
$age = (int)(($fc - $fb) / 10000);  //40
```

##解説
まず、タイムゾーンの設定をして基準の時間を日本にします。

```
date_default_timezone_set('Asia/Tokyo');
```

次に、`date`関数で現在の日時の算出します。加えて、あなたの誕生日を入力してください。
`date`関数は第一引数で指定したフォーマットでその日時を出力します。
この時のデータ型は`string`です。

```
$currentDate = date('Y/m/d');
$birthday = "あなたの誕生日　例：1980-01-01";
```
次に、先ほどの`$currentDate`と`$birthday`を`strtotime`でタイムスタンプとして出力したものを`int`型に書き換えます。
この時`date`のフォーマットを`Ymd`に指定することで日付を数値として出力させることができます！
例えば、`1980-01-01`が`19800101`として変換されます。
加えて、`int`型に変換することで整数値かつ数値として変換されます。

```
$fc = (int)date('Ymd', strtotime($currentDate));
$fb = (int)date('Ymd', strtotime($birthday));
```
最後に、引き算をして10000で割ります。

引き算のフロー：　`20200129 - 19800101 = 400028`
10000でわる：　`400028 / 10000 = 40.0028`

つまり、西暦の足し算で年齢の`10000`倍算出して、それを`10000`で割ることで年齢だけを整数値で変数に納めています。


```
$age = (int)(($fc - $fb) / 10000);
```
テスト（初投稿＆備忘録）

プログラミング初学者です。

```
body {
  height: 1000px;
  width: 1000px;
  background-image: url("../images/cafe_2.jpeg");
  background-size: cover;
  background-attachment: fixed;
}
```
とコードを書いたら

![スクリーンショット 2021-01-29 16.50.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/935346/41947bc3-e2c3-b056-6f99-de8ae7e28996.png)

何故か左寄りになったので

```
body {
  height: 1000px;
  width: 1000px;
  background-image: url("../images/cafe_2.jpeg");
  background-size: cover;
  background-attachment: fixed;
  margin-right: auto;←追加
  margin-left: auto;←追加
}
```

としたら

![スクリーンショット 2021-01-29 16.54.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/935346/ba7655fd-79d3-4083-5443-daed25bc246e.png)

中央揃えになりましたw（何故かは理解しておりませんw誰かお暇な方よろしくお願いしますw）

自分はプログラミング歴1年半ですが今までほぼほぼインプットでしか学習して来ませんでした。
なので今後は９：１でアウトプットで学習していくつもりです。

よろしくです。
【Rails】パーシャル（部分テンプレート）の中身をアクションごとに変更する

##バージョン
+ Rails 6.0.3
+ Ruby 2.6.3

##やりたい事
ポートフォリオサイトのプロフィール画面をSPAっぽくしているのだが、現状値が入っていないと何も表示されないので画面が遷移しているのかが分かりづらい。



![変更前.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/677726/34daab21-a487-02e7-eb07-d1e187f03258.gif)

各アクション毎に表示されるメッセージを変えたいのだが、renderでパーシャル化している為、1つのファイル内でメッセージを分岐させなければいけない。



##方法
調べてみたところ、**action_name**でアクション名を取得する事で同じファイル内のviewを分岐できるそうです。


```
      <% if action_name == 'show' %> 
        <div class="text-center mt-5">投稿はありません</div>
      <% else %>
        <div class="text-center mt-5">いいねした投稿はありません</div>
      <% end %>
```
フォロー中、フォロワーで使用している部分テンプレートも同じような方法で書き換えました。



##結果

![変更後.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/677726/0f9e7fc1-3796-ac07-e5dc-90a2ba06a05c.gif)

アクション毎にそれぞれのメッセージが表示されるようになりました。
Puppeteerで使わなれないタブがあるのが気になる

Puppeteerで、よく以下のような書き方を見ます。

```javascript
const browser = await puppeteer.launch({ headless: false, });
const page = await browser.newPage();
await page.goto("https://www.google.com/");
```

このように書くと、以下のように新しいタブでURLが開かれます。
このとき、利用していない「about:blank」なタブがずっとあるのが気になっていました。(害はないんですが。)
Chromiumって起動時にタブを1個開いているんですよね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44717/6744bbab-4180-44c6-30ad-23ab94ac9b43.png)

Puppeteerのドキュメントを見ると、[browser.pages()](https://pptr.dev/#?product=Puppeteer&version=v5.5.0&show=api-browserpages)でページ一覧が取れるので、

```javascript
const browser = await puppeteer.launch({ headless: false, });
const page = (await browser.pages())[0];
await page.goto("https://www.google.com/");
```

こうすると、もとからあるタブを使ってくれました！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44717/3284d23a-db61-be45-9677-011bb1511c11.png)
【初学者】 SQLについて

##【背景】
 とある転職フェアにて企業様と楽しく歓談。
 最後に「SQLって分かる？」と質問頂くが、情弱知識の私はパニックって頭の中でコードや横文字が乱舞し、答えられず。
...(´・ω・｀)ｼｮﾎﾞﾝ
railsで体系的にプログラミングは勉強はしたけれど、これが現実かと実感したので、
落ち込む暇なく、まずは文章化してみようと決意！
（理解を深めるために、できるだけ噛み砕いた表現にしようと思います。）


##「SQLとはひとことで」
```
「データーベースを扱うための言語」 
　　　 アプリ（画面）とデータベースを繋ぐ役割がある。
```

現在、最も普及しているデータベース言語が「SQL」である。　
データーベース言語とは、コンピュータのデータベースを扱うためのコンピュータ言語である。 
データーベースと対話して、大量のデータの効率的な取得・追加・削除・更新ができる。
SQLはデータベース言語として、ISO（国際標準化機構）で規格化されいる。
そのため一つのデータベース用のSQLを覚えたら、そのほかのほとんどの「RDB」で同じように利用できる。

===================================================================
&emsp;SQL(Structured Query Language）
Structured = 構造化した。情報を容易に取り出すことができるような編成方式のこと
Query = 質問，疑問 (question より形式ばった語)

===================================================================


ん...？？
「RDB」？？

##SQLの理解を深める「２つのキーワード」
```
- RDB(Relational DataBase)/RDBMS
- データーベース
```

[データベースとは](https://qiita.com/pagk/items/5d69658a57a84da4a109)
[RDBとは](https://qiita.com/pagk/items/73770f45ea327c89f13a)



##どの場面で使われるのか
```
「データーベースを操作するとき」

例）
登録されているデータを画面に表示する時
画面から入力した値を、データベースに登録する時
画面から削除ボタンを押してデータを削除する時
```


##どんな風に使うのか
```
DBMS（データベース管理システム）上で、ユーザーやシステムからの命令を受けて
RDB（リレーショナルデータベース）にクエリ（問い合わせ）を行い、
結果を返す。
返ってきた結果はモニターなどに表示される。
```


##どんな環境で動かすのか
```
１）お手軽に 「Webサービスに登録」 して作る
２）実務に使えるように 「パソコンにインストール」 して作る
```

##最近の流行
```
「NoSQL」
```
これから主流になるかもしれない技術であり、新しいデータベース管理システム。
同時にデータを探すことが得意とし、それによって、大量のコンピューターを使って「同時に大量のデータを検索」したりできます。
「ビッグデータ」などの大量のデータを扱う場合に威力を発揮します。

##最後に
企業様から質問があった「SQL」。その企業様は某業界の経営コンサルティング会社でした。経営分析システムを開発されていることから、データベースの操作であるSQLは業務においては、必須であるため質問されたと理解した。（そりゃそうだ..)
プログラミングを体系的には学習したものの、今後はそれがどの場面でどのように使われるのかイメージしながら学習を進めると理解しやすく、入社してからのイメージがつきやすいと感じた。

##参考記事
関数とうまく付き合おう - マイグレーションにやさしい「データベースとのかかわり方」 
&emsp;https://qiita.com/e99h2121/items/efd3e12a526816775aab
【MySQL, SQL】データベースを扱う基本SQL一覧
&emsp;https://qiita.com/knife0125/items/bb095a85d1a5d3c8f706
データベースの開発をするなら　どのプログラミング
https://programming-gakkou.com/archives/993
rails モデル空の時エラーになるようにする(バリデーション)

# 1.モデルにvalidatesをかける
自分が空の入力だと困るもの、バリデーションをかけたいものにvalidetesをかける。そこにプラスしてpresence: trueを追加します。

```ruby:post.rb
  validates :nickname, presence: true
  validates :title,    presence: true
```

# 2.たくさんあるときの簡単な記述の仕方
このカラム自体の数が多い時、これを一つ一つ記述をするのはRubyの記述として綺麗ではないためwith_optionを用いて記述します。この記述で簡単にまとめることができます。

```ruby:post.rb
  with_options presence: true do
   validates :nickname
   validates :title
  end
```

# 3.最後に
このようにバリデーションを用いて空の記述を弾くようにします。また同じ記述をするときは一つにまとめることを意識して記述しましょう。
PostgreSQL のバージョンの違いを解消

RDS のバージョンと設定した PostgreSQL のバージョンが違っていたため、解消しました。
自分の設定ミスで起こったことなので、あまり皆さんに転用できないとは思いますが、解消まで苦労したので、よかったら見ていってください。
## 参考資料
- [【PostgreSQL】psql version 8.4, server version 9.5](https://mementoo.info/archives/2146)
- [Linuxの権限確認と変更(chmod)（超初心者向け） - Qiita](https://qiita.com/shisama/items/5f4c4fa768642aad9e06)
- [【CeontOS】「sudoers ファイル内にありません。この事象は記録・報告されます」というメッセージが出た時の対処](https://notepad-blog.com/content/112/)

では、下記より内容に入ります。

## RDS に接続した際にバージョンの違いに気づく
```bash
psql (9.2.24, サーバー 12.4)
注意： psql バージョン 9.2, サーバーバージョン 12.0.
         psql の機能の中で、動作しないものがあるかもしれません。
SSL 接続 (暗号化方式: ECDHE-RSA-AES256-GCM-SHA384, ビット長: 256)
"help" でヘルプを表示します.
```

手違いで違うバージョンをインストールしてしまっていたようなので、解消する。

[【PostgreSQL】psql version 8.4, server version 9.5](https://mementoo.info/archives/2146)

```bash
[〇〇@ip-10-0-0-87 ~]$ su postgres
パスワード:
bash-4.2$ find / -name psql 2>/dev/null
/usr/bin/psql
/usr/pgsql-12/bin/psql
bash-4.2$ mv /usr/bin/psql /usr/bin/psql.old
mv: `/usr/bin/psql' から `/usr/bin/psql.old' へ移動できません: Permission denied
```

mv コマンド実行できないエラー

## Permission dinied

[Linuxの権限確認と変更(chmod)（超初心者向け） - Qiita](https://qiita.com/shisama/items/5f4c4fa768642aad9e06)

```bash
bash-4.2$ ls -al /usr/bin/psql
-rwxr-xr-x 1 root root 445160  9月  7  2018 /usr/bin/psql
```

権限ない？以下コマンド実施

```bash
bash-4.2$ chmod 777 /usr/bin/psql
chmod: `/usr/bin/psql' のパーミッションを変更しています: Operation not permitted
```

sudo コマンドで強制変更

```bash
-bash-4.2$ sudo chmod 777 /usr/bin/psql
[sudo] password for postgres:
postgres is not in the sudoers file.  This incident will be reported.
```

postgres is not in the sudoers file.

なんやねんコレ。。。。

## sudoers ファイルについて

調べてみると sudo コマンドを使うためのユーザー設定が必要らしい。

[【CeontOS】「sudoers ファイル内にありません。この事象は記録・報告されます」というメッセージが出た時の対処](https://notepad-blog.com/content/112/)

```bash
[〇〇@ip-10-0-0-87 ~]$ sudo visudo
```

```bash
## Allows people in group wheel to run all commands
%wheel  ALL=(ALL)       ALL
postgres ALL=(ALL)      ALL  ## ここ追加
```

設定したら再度ログイン

```bash
[kouhei@ip-10-0-0-87 ~]$ su - postgres

-bash-4.2$ sudo mv /usr/bin/psql /usr/bin/psql.old

-bash-4.2$ sudo ln -s /usr/pgsql-12/bin/psql /usr/bin/psql
```

上記コマンド打ってエラーが出なかったので、一旦ログアウト

RDS の方に入ってみる。

```bash
psql (12.5、サーバ 12.4)
SSL 接続 (プロトコル: TLSv1.2、暗号化方式: ECDHE-RSA-AES256-GCM-SHA384、ビット長: 256、圧縮: オフ)
"help"でヘルプを表示します。
```

できた！

## 学んだこと

- 意味の分かっていないコマンドは打たない方が良い。

公式サイトや様々な記事を参考にしながら環境構築行っていましたが、途中から完全に迷子になってしまい、よくわからないままあれやこれやとコマンド打っていました。

こちらのエラーを解消していく中で、自分が何を設定したのか位置関係がなんとなく理解できました。

当たり前の話ですが、環境構築やってると自分が今どこにいて何をやってるのか把握しておくことが大事だと改めて思いました。
Gravio 4でLINENotifyやSlackのトークンを共用する

Gravioでは、LINE NotifyやSlackにメッセージを投稿する際のトークンを指定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41603/6cd5f1fd-111f-a253-97eb-67458e96ce09.png)

でも、いろんなアクションで通知を始めると、最初は自分ひとりで送っていたのをグループに送りたくなったりして、いちいち指定してらんないよねってなってくる。
そんなときにおすすめなのが**基本プロパティセット**です。

# 使用環境

* Windows 10 20H2 (19042.746)
* Gravio HubKit v4.1.4049.0
* Gravio Studio v4.1.5432.0

# 手順
## 基本プロパティセットを作成
基本プロパティセットは、「設定」-「基本プロパティセット」で管理します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41603/26b81a1e-196f-1728-a451-9710d4c17f06.png)

「追加」ボタンをクリックするとダイアログが表示されるので、わかりやすい名前をつけ、カテゴリーを選んで、設定を入力しましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41603/c5fbe6a8-ca49-4b0c-97af-4db82e18d12e.png)

各カテゴリで複数の情報を登録しておけるので、例えば、一つのGravioから複数のLINEグループにメッセージを送ったり、別々のSlackアプリのトークンを使い分けたりすることもできます。

## 基本プロパティセットを使う
基本プロパティセットを使うのは簡単です。コンポーネントのプロパティで選ぶだけ。
このように該当カテゴリーの基本プロパティセットがリストされます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41603/9bd27748-0c62-388c-48dc-a2eeba8e2ca7.png)

選択すると、トークンプロパティの方はこのように表示されて入力できなくなります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41603/eb9d5457-0657-66f2-8359-0057212d1cfe.png)

Slackでも同じですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41603/37d7535e-1e28-4caa-9c92-b1d195f00565.png)

# ポイント
* 複数のアクションで同じトークンなどの認証情報を使うときには、**基本プロパティセット**を使う
* 同じカテゴリのものを複数登録できるので使い分けるのも簡単

# 参考
* [Gravio][]
* [設定タブのヘルプ](https://doc.gravio.com/manuals/gravio4/1/ja/topic/settings-tab)
* [Slack Post Component](https://doc.gravio.com/manuals/gravio4/1/ja/topic/slackpostmessage-action-component)
* [LINE Notify Component](https://doc.gravio.com/manuals/gravio4/1/ja/topic/line-notify-action-component)

[Gravio]:https://www.gravio.com/jp
【Laravel】php artisanコマンドメモ（composerも少しだけあり）



**自分用のメモとして残します。**
3,4年前にメモしたものをqiitaに残すだけなので、未整理です。
もしかしたら、最新のLaravelバージョンでは使えないものもあるかも。

よく使うやつは整理するかもです。

##【基本】

###▼Eloquentモデル作成（単数形が公式推奨）

```shell
php artisan make:model テーブル名
```

###▼シーダー作成（ダミーデータ作成）

```shell
php artisan make:seeder テーブル名(アッパーキャメル)TableSeeder
```

###▼シーダー実行（database\seeds\DatabaseSeeder.phpに登録されているものが対象）

```shell
php artisan db:seed
```

###▼シーダー実行(単体)

```shell
php artisan db:seed --class=シーダークラス名
```


###▼ルーティング確認

```shell
php artisan route:list
```

###▼マイグレーション作成

```shell
php artisan make:マイグレーション名
```

```shell
例：php artisan make:migration create_users_table
```

###▼コントローラ作成（リソース（おまかせ）を使用する場合は-rを使う）

```shell
php artisan make:controller Admin/AdminUsersController
```

```shell
php artisan make:controller Admin/AdminUsersController -r
```

```shell
php artisan make:controller Admin/AdminUsersController --resource --model=Photo
```

###▼ページネーション作成

```shell
php artisan vendor:publish --tag=laravel-pagination
```

###▼バッチの作成

```shell
php artisan make:command バッチ名(アッパーキャメル)Command
```

##【その他】
###▼キャッシュ削除

```shell
php artisan cache:clear
```

```shell
php artisan config:clear
```

```shell
php artisan route:clear
```

```shell
php artisan view:clear
```

###▼DB初期化（マイグレート実行＆初期データ実行）

```shell
php artisan migrate:refresh --seed
```

###▼IDEヘルパー更新

```shell
php artisan ide-helper:generate
```

###▼最適化まとめ

```shell
composer dump-autoload
```

```shell
php artisan clear-compiled
```

```shell
php artisan optimize
```

```shell
php artisan config:cache
```
【Ruby】最小最大値を取得する　get.to_i .min .maxメソッド


【入力数値】
3 4 5

【コード】
n1 = gets.to_i
n2 = gets.to_i
n3 = gets.to_i

wrap = [n1, n2, n3]
puts wrap.min

【出力結果】
3

【解説】
test.rbファイルを作成し、gets.to_iメソッドで数値オブジェクトに変換した値を取得し、変数nに代入します。
配列wrapにn変数をそれぞれ格納し、puts wrap.minを実行すると、配列wrap内の最小値を取得することができます。
.minを.maxにすると最大値を取得することもできます。
windowsでsoファイルの中のシンボルを見る

androidのapkに含まれているsoファイルの中のシンボルの確認方法。
忘れて3か月のうちに2回も悩んだので備忘録。

# 方法
1. cygwinをインストール。起動。
2. apkを.zipに拡張子を変えて解凍→lib/armeabi-v7a/の下などに.soファイルがある
3. それに対してcygwinのターミナル上でreadelf -s を実行。

# 参考
https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q13143958248
https://pyopyopyo.hatenablog.com/entry/20070315/p1
【RDS】簡単に機能をまとめてみた

#はじめに
RDSについて、「AWSのデータベースのサービス」という認識しかなかったのですが、調べてみるとかなり色々な機能があることが分かりました。
本記事ではRDSについて僕が学んだことを書いていこうと思います。
もし誤った記載等があれば、コメントで優しく教えてください！

#RDSの概要
RDSは『マネージド型リレーショナルデータベース』です。
簡単に言うと、AWSがセキュリティ、バックアップ等を担ってくれるデータベースといったイメージです。

データベースエンジンは以下の6種類から選択可能です。

**【使用可能データベースエンジン】**

- Amazon Aurora
- MySQ
- MariaDB
- Oracle
- Microsoft SQL Server
- PostgreSQL 

#RDSの機能
それでは実際にRDSがどのように優れているのかを図示しながら記載していきます。
様々な機能はありますがまずは、以下の3つに絞って記載します。

1. マルチアベイラビリティゾーン
　複数のアベイラビリティゾーン（以下AZと記載）にRDSを配置します。
　このようにすることで、片方に障害が起きても、もう片方のRDSが稼働してくれるます。

2. Master-Slave構成
　異なるAZにSlaveのRDSを作成します。
　SlaveでMasterのバックアップの役割をしています。
　MasterとSlaveで異なるAZに配置しているため、障害にも強く、高い可用性が得られています。

3. リードレプリカ
　Master以外にReplicaを作成することができます。
　Replicaは読み取り専用です。データベースの更新はMasterで行います。
　このように役割を分けることで、片方のデータベースに負荷がかかることを防ぎます。
　※異なるAZ中にもリードレプリカを作成することは可能です。

![構成図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/799854/677f77b2-d3c7-57f1-2c4e-82dab56765d5.png)


その他のRDSの機能については、簡単に表にまとめます。

**【その他のRDSの機能】**

| 機能・特徴 | 簡単な説明 |
| :-- | :-- |
| エンドポイント通信 | RDSは起動するとエンドポイントが発行されます。エンドポイント通信により、障害が起きた時に、RDSの切り替えが容易になります。 | 
| 自動パッチ適用 | 常に最新のパッチが自動で適用されます。自分で条件等を指定することも可能です。 | 
| 簡単なストレージのスケーリング | サーバーを停止することなくスケールアップさせることが可能です。また自動でスケーリングをする設定もあります。 | 
| 自動スナップショット | 自動でS3にスナップショットを記録してくれます。保存期間も指定できます。 | 
| 保管中と転送中の暗号化 | AWS Key Management Service (KMS) で管理するキーを使うと、データベースを暗号化することができます。　| 
| 従量課金精度 | 使用した分のみ費用がかかります。ストレージの容量や種類等、設定によって金額は大きく変動します。 | 

「もっと詳しく知りたい！」という方は公式のURLも参考にしてみてください。
https://aws.amazon.com/jp/rds/features/

以上簡単では、ありますが、RDSについてまとめてみました。
これか実際に使用することで、より理解を深めていこうと思います。
もし、誤った記載等があればコメント等でご指摘いただけると幸いです。
最高のローカルネットワーク環境構築に必要なこと！！

# はじめに
こんにちは、
初めてこのサイトで書かせていただきます。なので
至らない点があるかもしれませんが、よろしくお願いします。

内容は、家庭や社内ネットワークのみのことを記述します。
＊大規模のものはまた別なので、

ちなみに
このトピックを書く理由は。友人がネットワーク環境のことについて
質問されたのがきっかけです。
# ネットワーク環境の構築の難しさ
最近、ネット上でも家のネットインフラ を改善する人（コロナが理由で）が多くなってきたような気がします。
また、家にいる時間が多いせいで、インターネット回線の質を気にする人も多くみられます。

ここで、よくある間違いを書いていこうかなと、
ネットの回線強化の一つのアイディアとして利用してくださったら
嬉しいです。


#具体例
まず、知人の例をもとに 話していきたいと思います。
```友人： 家のネット早くするためにNu○o １０G回線 契約したわ！```
最近、個人回線でも、10Gbp/s をだす 商品が増えてきました。
なので簡単に高速な回線を利用することができるのですが、まずここにポイントがあります。

よくあるのが、回線は高速でも ローカルネットワークの質の悪さが影響することが多いです。

例としていうと
宅内配線が 100Mbp/s or 1000Mbp/s の場合です。
これは、何を頑張っても、元のスペック通りに速度は出ません。

簡単な話。ローカルの回線速度が遅くてボトルネックになってることがあげられます。
友人も、
```友人： １０G回線 なのに ７００Mbp/s しかでない```
などと。いってました。

ただ現状、宅内などの配線で 10Gb/sをだすには それなりの投資が必要になります。
例
ルータ（業務用）
配線（cat 6a　以上）または、光通信（sfp+ コネクタ装備のもの）

長さや規模にもよりますが
数万〜数十万円ほどかかります。

また、Wi-Fi では現状 このスピードは出せません。
IEEE 802.11 ax の規格上は 9.6Gbp/s 出るようになっていますが、実効値と出てるものとしても
2〜４ Gbp/s ぐらいが多いのではないでしょうか？

もちろん、回線元が 10Gbp/s出してないことがほとんどなので、正直 ここまでの設備入らないのかなっておもっています。

あと、よくあるのが、
Wi-Fi のチャンネルの重複があげられます。
デフォルトだと 2.4GHz帯は、チャンネル １
5GHz帯は、チャンネル ３６ 
が選ばれていることが多いので
Wi-Fiの電波スキャナーなどで確認して
周りと干渉しない電波を使うことも大事です。

## 参考
私の自宅では、以下のような設備構成になっています。

```
光回線
|
小型ONU
YAMAHA NVR 510
|-----------------------------------------|----------------------|
Wi-Fiアクセスポイント(NEC WG2200HP)  Wi-Fiアクセスポイント(同上)   Wi-Fiアクセスポイント(同上)
```
構成の特徴は、安定した 1000Mb/s 環境の構築です。
まず、NVR 510 は家庭用として価格と質のバランスが取れていと思います。
アクセスポイントの台数は、それぞれの電波環境等で調整すればいいかと思います。
うちのケースですと、壁分厚いのと。平面に広いせいか 電波が届きづらく、三台使っています。

NVR 510 のいいところは、セッション数の多さ、動作安定性、VPN(IPsec)が使えるところです。

先ほどにも言わせていただきましたが、まだ個人宅の内部配線として１０Gbp/s 利用するには
はコストが高すぎるので １Gbp/s です。

もちろん Wi-Fiのチャンネル等もチューニングしています。

#まとめ
ネットワークの最適化は正直、色々な要因が関わるので
一言でこれをすれば早くなるとは言いづらいです。
ただキーになるのは、
1. 回線品質
2. ルータの性能
3. アクセスポイントの設定チューニング
4. 配線に使っている ケーブルのカテゴリ

ぐらいを確認すれば、いいのかなと

お金をかけずに、やるとなると
Wi-Fi アクセスポイントのチューニングと、ルータのチューニング が一番だと思います。
manimの作法 その32

#概要

manimの作法、調べてみた。
rate_func使ってみた。

#サンプルコード


```
from manimlib.imports import *

class test(GraphScene):
	CONFIG = {
		"x_labeled_nums" : [],
		"y_labeled_nums" : [],
		"x_axis_label" : "Temperature",
		"y_axis_label" : "Pressure",
		"graph_origin" : 2.5 * DOWN + 2 * LEFT,
		"corner_square_width" : 4,
		"example_point_coords" : (2, 5),
	}
	def construct(self):
		self.setup_axes()
		path = VMobject().set_points_smoothly([ORIGIN, 2 * UP + RIGHT, 2 * DOWN + RIGHT, 5 * RIGHT, 4 * RIGHT + UP, 3 * RIGHT + 2 * DOWN, DOWN + LEFT, 2 * RIGHT])
		point = self.coords_to_point(*self.example_point_coords)
		path.shift(point)
		path.set_color(GREEN)
		self.play(ShowCreation(path, run_time = 10, rate_func = linear))
		self.wait()
		self.remove(path)
		self.play(ShowCreation(path, run_time = 10, rate_func = there_and_back))
		self.wait()
		self.remove(path)
```

#生成した動画

https://www.youtube.com/watch?v=C6GRbNW-cyQ

以上。
AWS S3のパッケージインストール時に、composer require league/flysystem-aws-s3-v3を叩くと、Your requirements could not be resolved to an installable set of packages.とエラーが出るときの解決策。

# 前提条件
・macOS
・Laravel6
・初学者

# composer require league/flysystem-aws-s3-v3を叩いた結果

```
test@test laravel % composer require league/flysystem-aws-s3-v3

Using version ^2.0 for league/flysystem-aws-s3-v3
./composer.json has been updated
Running composer update league/flysystem-aws-s3-v3
Loading composer repositories with package information
Updating dependencies
Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - league/flysystem-aws-s3-v3[2.0.0, ..., 2.x-dev] require league/flysystem ^2.0.0 -> found league/flysystem[2.0.0-alpha.1, ..., 2.x-dev] but the package is fixed to 1.1.3 (lock file version) by a partial update and that version does not match. Make sure you list it as an argument for the update command.
    - league/flysystem-aws-s3-v3[2.0.0-alpha.1, ..., 2.0.0-alpha.2] require league/flysystem 2.0.0-alpha.1 -> found league/flysystem[2.0.0-alpha.1] but the package is fixed to 1.1.3 (lock file version) by a partial update and that version does not match. Make sure you list it as an argument for the update command.
    - league/flysystem-aws-s3-v3[2.0.0-alpha.4, ..., 2.0.0-beta.1] require league/flysystem 2.0.0-alpha.3 -> found league/flysystem[2.0.0-alpha.3] but the package is fixed to 1.1.3 (lock file version) by a partial update and that version does not match. Make sure you list it as an argument for the update command.
    - league/flysystem-aws-s3-v3[2.0.0-beta.2, ..., 2.0.0-beta.3] require league/flysystem ^2.0.0-beta.1 -> found league/flysystem[2.0.0-beta.1, ..., 2.x-dev] but the package is fixed to 1.1.3 (lock file version) by a partial update and that version does not match. Make sure you list it as an argument for the update command.
    - league/flysystem-aws-s3-v3 2.0.0-RC1 requires league/flysystem ^2.0.0-RC1 -> found league/flysystem[2.0.0-RC1, ..., 2.x-dev] but the package is fixed to 1.1.3 (lock file version) by a partial update and that version does not match. Make sure you list it as an argument for the update command.
    - Root composer.json requires league/flysystem-aws-s3-v3 ^2.0 -> satisfiable by league/flysystem-aws-s3-v3[2.0.0-alpha.1, ..., 2.x-dev].

Use the option --with-all-dependencies (-W) to allow upgrades, downgrades and removals for packages currently locked to specific versions.

Installation failed, reverting ./composer.json and ./composer.lock to their original content. 
```

# 解決方法
バージョンがあってないよ〜。と言われている気がしたので、

```
test@test laravel % composer require league/flysystem-aws-s3-v3 ^1.0
```

バージョン指定を入れることで解決できました。

# 参考記事
https://www.ritolab.com/entry/8
manimの作法 その31

#概要

manimの作法、調べてみた。
ValueTracker、 add_updater使ってみた。

#サンプルコード


```
from manimlib.imports import *

class test(Scene):
	def construct(self):
		t = ValueTracker(0)
		dec = DecimalNumber(0)
		dec.add_updater(lambda a: a.set_value(t.get_value()))
		self.add(dec)
		self.play(t.set_value, 2, rate_func = linear, run_time = 4)
		self.wait()


```

#生成した動画

https://www.youtube.com/watch?v=dqtyqwGwqEU

以上。
【Swift】 SpriteKit 入門 ③

SpriteKitの使い方を解説します。
[SpriteKit 入門 ②](https://qiita.com/tosssy/items/486492378fe1685c6524) で画像をドラッグして動かせるようになりました。今回は自機(画像)から弾を発射するようにしていきましょう。
（環境：Xcode12.1 　Swift5.3）

##弾を発射する
今回使用するのは

- `SKShapeNode`
- `SKAction`
- `TimeInterval`

の3つです。

弾などの図形を描画する際には`SKShapeNode`を使用します。`SKAction`で図形にアニメーションを追加することができます。一定時間毎に弾を発射させたいので、`TimeInterval`も使用しています。それではMyScene.swiftファイルにコードを追加していきましょう。

```swift:MyScene.swift
    var image: SKSpriteNode!
    var beforeDragPosition: CGPoint?
    var shoot: SKShapeNode? 
    var lastUpdateTime : TimeInterval = 0

    //省略

    func repeatShoots(){
        self.shoot = SKShapeNode.init(rectOf: CGSize.init(width: 30, height: 30), cornerRadius: 3)
        if let shoot = self.shoot {
            shoot.position = image.position
            shoot.fillColor = SKColor.red
            shoot.lineWidth = 3
            shoot.strokeColor = SKColor.white
            shoot.run(SKAction.repeatForever(SKAction.rotate(byAngle: CGFloat(Double.pi), duration: 1)))
            shoot.run(SKAction.sequence([SKAction.move(by: CGVector(dx: 0, dy: self.size.height), duration: 3),SKAction.removeFromParent()]))
            self.addChild(shoot)
        }
    }

    override func update(_ currentTime: TimeInterval) {
        if (self.lastUpdateTime == 0) {
            self.lastUpdateTime = currentTime
        }
        if (lastUpdateTime + 0.3 <= currentTime) {
            self.repeatShoots()
            lastUpdateTime = currentTime
        }
    }
```

`repeatShoots()`では時期から弾を発射させる処理を記述しています。図形の形を`SKShapeNode.init()`で設定します。ここでは四角にしていますが、円を描画する場合は次のように記述します。

```swift:
    self.shoot = SKShapeNode.init(circleOfRadius: 15)
```

以下の部分では弾のアニメーションを設定しています。アニメーションの設定には`SKAction`を使用します。複数のアニメーションは配列として追加することができます。

```swift:
    shoot.run(SKAction.repeatForever(SKAction.rotate(byAngle: CGFloat(Double.pi), duration: 1)))

    shoot.run(SKAction.sequence([SKAction.move(by: CGVector(dx: 0, dy: self.size.height), duration: 3),SKAction.removeFromParent()]))
```

また`update(_ currentTime: TimeInterval)`を override して一定時間毎に`repeatShoots()`を呼び出すようにしています。

```swift:
    override func update(_ currentTime: TimeInterval) {
        if (self.lastUpdateTime == 0) {
            self.lastUpdateTime = currentTime
        }
        if (lastUpdateTime + 0.3 <= currentTime) {
            //0.3秒毎にrepeatShoots()を呼び出す
            self.repeatShoots()
            lastUpdateTime = currentTime
        }
    }
```

実行結果はこのようになります。
<img width="300" alt="SK1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498332/6b784fdb-306a-670b-6f47-40cebfb4752a.png">

[次回](https://qiita.com/tosssy/items/86b854ec71f221ff08a7)は敵を表示させて衝突判定を実装していきましょう。

###参考

この記事は以下の情報を参考にして執筆しました。

- [[Swift] SpriteKitで一定間隔の処理を行う。](https://qiita.com/mochizukikotaro/items/6d3a7e445ea67e5b4643)
- [【Swift】SpriteKitの使い方。SKActionを使ってノードを移動、回転、拡大縮小する。](https://hajihaji-lemon.com/swift/spritekit_skaction/)
manimの作法 その30

#概要

manimの作法、調べてみた。
ValueTracker、 always_redraw使ってみた。

#サンプルコード


```
from manimlib.imports import *

class test(Scene):
	def construct(self):
		angle_tracker = ValueTracker(90 * DEGREES)
		get_angle = angle_tracker.get_value
		formula = always_redraw(lambda: self.get_sine_formula(get_angle()))
		self.add(formula)
		self.play(angle_tracker.set_value, 0, run_time = 5, )
		self.wait()
		self.play(angle_tracker.set_value, 90 * DEGREES, run_time = 5, )
		self.wait()
	def get_sine_formula(self, angle):
		sin, lp, rp = TexMobject("\\sin", "(", ") = ")
		input_part = Integer(angle / DEGREES, unit = "^\\circ", )
		input_part.set_color(YELLOW)
		output_part = DecimalNumber(np.sin(input_part.get_value() * DEGREES), num_decimal_places = 3, )
		result = VGroup(sin, lp, input_part, rp, output_part)
		result.arrange(RIGHT, buff = SMALL_BUFF)
		sin.scale(1.1, about_edge = DOWN)
		lp.align_to(rp, UP)
		return result


```

#生成した動画

https://www.youtube.com/watch?v=yq0aPkkQCAQ

以上。
Pythonで処理結果をファイルに保存

Matlabではsave/loadコマンドでmatファイルを作るみたいなことをpythonでもやりたい。

#pickle or joblib
Matlabのsaveでやるようなシリアライズをするのには、よくpickleというモジュールが使われるようだ。
（ちなみに複数形はpickles,つまりピクルスだ。酢漬けにして保存しとくイメージなのか）

pickleはかなりメジャーなモジュールのようだが、最近ではjoblibというのも使われているらしい。
joblibはそもそもは並列処理用のモジュールらしく、なぜそれがシリアライズにも使えるのかは知らないが
オプションを指定するだけでいい感じに圧縮できて、そこそこ速いっぽいので、joblibを使ってみる。

#書き込み　joblib.dump()
まずは処理をしてファイルに書き込む
例は何でも良かったのだけれど、巷で噂（？）のUMAP。

```python
import os
import joblib
import umap
from sklearn.datasets import load_digits

digits = load_digits()
reducer3d = umap.UMAP()
reducer3d.n_components = 3

reducer2d.fit(digits.data)
reducer3d.fit(digits.data)

joblib.dump((reducer2d, reducer3d), os.path.expanduser('~/Desktop/umap.joblib'), compress=True)
```
複数のインスタンスもタプルにして渡せばOKっぽい。
compressに1~9またはTrueを渡すと圧縮してくれる。（Trueはcompress=3と同じらしい）
数字は大きいほど高圧縮。

#読み込み　joblib.load()

```python
import os
import numpy as np
import joblib

red = joblib.load(os.path.expanduser('~/Desktop/uMap.joblib'))
(reducer2d, reducer3d) = red
```
読み込むときは（当然ながら）タプルに入っているので、読み出してから切り出す。
どの変数を何番目に入れたか覚えているなら、最初からアンパックして読み出してもOK

```python
(reducer2d, reducer3d) = joblib.load(os.path.expanduser('~/Desktop/uMap.joblib'))
```
いたってシンプル。

#おまけ
せっかくなので可視化しとく

```python
from sklearn.datasets import load_digits
import matplotlib.pyplot as plt

digits = load_digits()
embedding2d = reducer2d.transform(digits.data)
embedding3d = reducer3d.transform(digits.data)

fig = plt.figure(figsize=(12, 5), dpi=72)
ax = fig.add_subplot(1, 2, 1, title='n_components = 2')
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
sc = ax.scatter(embedding2d[:, 0], embedding2d[:, 1], c=digits.target, cmap='Spectral', s=5)
cb = fig.colorbar(sc, boundaries=np.arange(11) - 0.5, shrink=0.6)
cb.set_ticks(np.arange(10))

ax = fig.add_subplot(1, 2, 2, projection='3d', title='n_components = 3')
sc = ax.scatter(embedding3d[:, 0], embedding3d[:, 1], embedding3d[:, 2], c=digits.target, cmap='Spectral', s=5)
cb = fig.colorbar(sc, boundaries=np.arange(11) - 0.5, shrink=0.6)
cb.set_ticks(np.arange(10))
plt.show()
```

結果

![uMap-digit.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1063124/5dd8411d-51cb-3164-960e-e98351014996.png)
簡単！Rails6にBootStrap5を導入する

##はじめに
本記事は2021年9月時点の最新環境である、Rails6 に BootStrap5を導入する方法を紹介しています。
また、BootStrapに関してはsassで編集できるようにしています。


##gemfile
まずは、gemfileに以下の行を追加しましょう

```ruby:gemfile
gem 'bootstrap', '~> 5.0.0.alpha1'
gem 'jquery-rails'
```

ターミナル（コマンドプロンプト）にて 

``` text:ターミナル
bundle install
```
を実行しましょう。


##application.cssを変更

`app/stylesheets/ `の中にある
`application.css`を`application.scss`にファイルをリネームしましょう。
<br>
それができたら、`application.scss`に以下の文を追加して下さい。

```scss:app/stylesheets/application.scss
@import "bootstrap-sprockets";
@import "bootstrap";
```


以上でBootstrapの導入が完了しました。
ROSの勉強　第1弾：topicの配信と購読

# #プログラミング ROS< topicの配信と購読 >

##はじめに
いよいよROSの勉強にも本腰をいれていく．1つの参考書に沿って，ROS(Robot Operating System)を難なく扱えるようになることが目的である．もうすでに，今までにも勉強はしてきており，簡単なところはすこし理解しているが，ここでは改めて初めから学び，復習も兼ねながら学習を進めていくこととする．

##環境
#####仮想環境
|||
|:-:|:--|
|ソフト|VMware Workstation 15|
|実装RAM|2 GB|
|OS|Ubuntu 64 ビット|
|isoファイル|ubuntu-mate-20.04.1-desktop-amd64.iso|

#####コンピュータ
|||
|:-:|:--|
|デバイス|MSI|
|プロセッサ|Intel(R) Core(TM) i5-7300HQ CPU @ 2.50GHz 2.50GHz|
|実装RAM|8.00 GB (7.89 GB 使用可能)|
|OS|Windows (Windows 10 Home, バージョン：1909)|

#####ROS
|||
|:-:|:--|
|Distribution|noetic|
|プログラミング言語|Python 3.8.5|

##topic
**トピック(topic)**：ノード間での通信を行う最も一般的な方法
様々なノードにデータが散らばる分散システムにおけるデータ交換でよく使われる**配信/購読（publish/subscribe）型の通信メカニズム**を実装している．

#####＜流れ＞
[step1] **公開**: トピック名とおくるメッセージの型をアナウンス

[step2] **配信**: ノードが，トピックに実際のデータをつけて送信すること

[step3] **購読**: roscoreに要求し，あるトピックのメッセージを受け取ること

##topicの配信
公開の項目は設けていないが，配信のプログラムの中で公開が行われている．以下にソースコードを示す．

```python:topic_publisher.py
#! /usr/bin/env python3

import rospy	#ROSに必要な基本的な機能を読み込む

from std_msgs.msg import Int32	#トピックに送るメッセージの定義を読み込む



rospy.init_node('topic_publisher')	#'topic_publisher'という名前でノードを新規作成（初期化）

pub = rospy.Publisher('counter', Int32)	#'counter'という名前で，送るメッセージの型をInt32に設定  ←公開


#####ここまでで，トピックは公開される．以下はトピックを使って送るメッセージについて

rate = rospy.Rate(2)	#2Hz(1秒間に2回)でメッセージを送る

count = 0	#送るメッセージを格納する変数
while not rospy.is_shutdown():
	pub.publish(count)
	count += 1	#毎回1増やす（カウント）
	rate.sleep()	#指定したrate(いまは2Hz)で実行されるために十分な時間をスリープする
```

この時点で，本当に配信できているかは，``rostopic list``により見つけられる．さらに``rostopic echo /トピック名``とすれば，実際に送っているメッセージをターミナル(端末)上で見られる．
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/951300/fe84290f-8b5e-91cf-ecb7-e4e4c3a4bbd1.png)
このような感じである．注意点は，``topic_publisher.py``を実行時には，``roscore``を別のターミナル(端末)で入力し，立ち上げておかなければならない．仲介人が必要なのである．

##topicの購読
先ほどの手順で手動で配信メッセージを拝見できるが，この配信されているメッセージ内のデータを扱いたいときには購読する必要がある．以下にそのソースコードを示す．

```python:topic_subscriber.py
#! /usr/bin/env python3

import rospy	#ROSに必要な基本的な機能を読み込む

from std_msgs.msg import Int32	#トピックに送るメッセージの定義を読み込む


def callback(msg):
	""" callback関数：購読するときに実行させる関数
		
		引数にmsgとあるが，関数を指定するときは特に引数を渡すことはない．
		自動的に購読対象を引数とする．

	"""
	print(msg.data)	#購読したメッセージのdataという変数に格納されているものを表示


rospy.init_node('topic_subscriber')	#'topic_subscriber'という名前でノードを新規作成（初期化）


sub = rospy.Subscriber('counter', Int32, callback)	#'counter', Int32のトピックを購読し，実行させる関数をcallbackに設定

rospy.spin()	#継続して処理をさせる．while not is_shutdown()のショートカットといえる
```

``roscore``，``topic_publisher.py``を実行している状態で，``topic_subscriber.py``を実行する．そのときの``topic_subscriber.py``を実行しているターミナル(端末)を以下に示す．
![キャプチャ1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/951300/b341956f-a131-4762-99e9-74097cced988.png)
確かに，そのソーコードで示した指示通り，1ずつカウントされていることが分かる．

##感想
ROSは幾度も独学してきたがうまく整理ができていなかった．今回から，ここでまとめていくことで整理出来たらと思う．ROSは便利なツールである分，参考書も分厚く先は長そうだが，1~2か月でこの参考書1冊を終わらせたい思い出やっていく．

##参考文献
プログラミングROS Pythonによるロボットアプリケーション開発
　　　　　　　　Morgan Quigley, Brian Gerkey, William D.Smart 著
　　　　　　　　　　　　　　　　　　　　　　　河田　卓志　監訳
　　　　　　　　　　  　松田　晃一，福地　正樹，由谷　哲夫　訳
　　　　　　　　　　　　　　　　　　オイラリー・ジャパン　発行
超初心者向けLinuxの基礎（ファイル操作関連）

#Linuxとはなんぞや
オペレーティングシステムの一種で主にCUIで操作します。
###GUI
ユーザへの情報提供にグラフィックを多用
利点：直感的で操作性がよい
Windows,MacOS
###CUI
ターミナルと文字でのやりとり
利点：開発が楽、ネットワーク負荷低い、ファイルの細かい操作性機械学習と相性がよい（と思う）

#Linux基礎コマンド(ファイル操作関連）
####CD    ：ディレクトリの異動
####ls    ：ファイルやディレクトリの一覧出力
####mkdir ：ディレクトリの作成
####rm 名前　：指定したファイルを削除
####rmdir 名前　：指定した空のディレクトリを削除

#基本コマンド CDとディレクトリの概念
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/650007/1e59389d-5d31-96ec-5447-88760cd7d633.png)
CDを使ってディレクトリの移動を行います。図でのようにhomeの下のディレクトリにいるとします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/650007/1d9800c6-e40d-baf7-3c74-84dbdf988db8.png)

CD ../ と打つことで親ディレクトリ、つまりhomeに移動できます

####相対パス
現地点からの相対的な位置指定のこと
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/650007/1cfc8c89-b7a2-8a4c-2967-84f8d75fce94.png)
bbbに移動したいとき、cd ../aaa/bbb
####絶対パス
ルートディレクトリからの絶対的な位置指定
bbbに移動したいとき　cd /home/aaa/bbb

比較的近い位置に移動する場合は相対パス
絶対パスは今自分がどこにいるか関係なく飛べる利点がある
※自分が今どこにいるか迷子になった時絶対パスで返してくれるコマンド　pwd を使う

##基本コマンド　ls 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/650007/58eac95b-71f3-10dd-7cbb-f6ee6c0ab4a4.png)
参考URL:http://dogandrun.hatenablog.jp/entry/2013/11/30/181606
####ls-lで表示したファイルの中身について
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/650007/4c782cb3-9c7e-f1ba-24e1-c4a722184621.png)
ファイルもしくはディレクトリの所有者名
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/650007/e58a226c-fb0a-caae-e0a0-58357e912e93.png)
ファイルもしくはディレクトリの所有者名
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/650007/482e9da4-5e19-1253-2628-993414845a4f.png)
バイトサイズ、最終更新日時、名前
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/650007/25f9a63f-9eac-347a-ec61-0625327f0372.png)
一行目はファイルならば　- ディレクトリならd
以降はファイルへの権利
r:読む権利がある
w:書く権利がある
x:実行する権利がある
-：権利がない
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/650007/7e33745d-e5dd-9e2b-1f7f-fe1a9a34b759.png)

###その他知っておくと便利なこと
Linuxはファイルやディレクトリ名を指定するとき、途中まで入力した状態でTABキー押すと予測してくれる

#終わり
以上、超簡単なLinuxの説明になります。コマンドはオプション色々ありますが、今回は割愛。時間あったら詳しく書きます。また、その他基礎コマンドについても書いていきたいと思います～
初歩的なことなので書くのためらったのですが、誰かのお役に立てればと思い載せます。
暖かい目で見守ってください。ありがとうございました。
ゲーム理論入門3

## Sum of Combinatorial Games
複数のパイルを使ったNim等の**複数の独立した普遍ゲームの集まり**をSum of Combinatorial Gamesという。
各サブゲーム全てが終了条件を満たした状態をゲー ムの (disjunctive(離散的な)) sum という.

ゲームを構成するサブゲームのSprague-Grundy 関数が、sum の Sprague-Grundy 関数を求めるために使われる。

### Theorem
```
もし、gi が Gi(i = 1, ..., n) の Sprague-Grundy 関数なら、G = G1+, ..., +Gn は、g(x1) ⊕ ... ⊕ gn(xn) という Sprague-Grundy 関数を持つ。
```

<details><summary>Proof</summary><div>

証明)x = (x1, ..., xn) を X の任意の点とする。b = g1(x1) ⊕ ... ⊕ gn(xn) とする。関数 g(x1, ..., xn) について 以下の 2 つを示す。

1. 全ての非負整数 a < b に対して、g の値が a である (x1, ..., xn) の follower がある。 
2. g の値が b である (x1, ..., xn) の follower はない。

その follower の 1 つによって推測されない最小の SG 値である x の SG 値は、b でなければならない。 (1)を示すために、d=a⊕bとし、dの2進法の拡張での桁の数をkとする。よって2k−1 ≤d≤2k で、 d は、右から k 番目の場所に 1 がある。a < b から、b では k 番目の場所は 1 で、a ではそこは 0 である。 b = g1(x1) ⊕ ... ⊕ gn(xn) から、少なくとも 1 つの gi(xi) の 2 進法の拡張で、k 番目に 1 をもつ xi がある。

単純に i = 1 と考える。d ⊕ g1(x1) < g1(x1) なので、x1 から、g1(x1′ ) = d ⊕ g1(x1) となる x1′ への動作は存 在する。(x1, x2, ..., xn) から (x1′ , x2, ..., xn) への動作は、sum G のルールに従った動作であり、
g1(x1′ ) ⊕ g2(x2) ⊕ ... ⊕ gn(xn) = d ⊕ g1(x1) ⊕ g2(x2) ⊕ ... ⊕ gn(xn) = d ⊕ b = a

最後に (2) を示すために、(x1, ..., xn) は同じ g の値の follower を持つと仮定し、これが矛盾する事を示す。 (x1′ , x2, ..., xn) は、(x1, x2, ..., xn) の follower という事と、g1(x1′ )⊕g2(x2)⊕...⊕gn(xn) = g1(x1)⊕g2(x2)⊕...⊕gn(xn) という事を考える。消しあう法則によって、g1(x1′ ) = g1(x1) である。しかし、これは同じ SG 値の follower を持つ状態はないので矛盾。

この定理で 1 つ注意すべき点は、ゲームの sum で要素として考えると、全ての progressively bound で ある impartial game は、あたかも nim の積み重ねのように表せる。たとえ、他のどんな sum の要素があ ろうとも、適正なサイズ (Sprague-Grundy 値) の nim の積み重ねによって、結果が変わることなく置き換えられる。この注意は、全ての (progressively bounded である)impartial game は、いくつかの nim の積み 重ねと同値であるという事を言っている。 

</div></details>