OmniAICreator/Qiita-1.07M huggingface dataset:
Java8とJava11が共存している環境下でSparkを使おうとしたときに出たエラーを解決

# Java8とJava11が共存している環境下でSparkを使おうとしたときに出たエラーを解決

## 概要

spark-shellからsparkを使ってもpysparkを実行しても以下のような同じエラーが出ていたので直した。

```
'Unsupported class file major version 55'
```

## 環境

Ubuntu18.04
Spark 2.4.3


## 解決方法(試行錯誤つき)

原因はJava11を使っていることらしい。使用しているJavaのバージョンを確認して、別のバージョンを選ぶために以下を実行。

```
$ sudo update-alternatives --config java
alternative java (/usr/bin/java を提供) には 3 個の選択肢があります。

  選択肢    パス                                          優先度  状態
------------------------------------------------------------
  0            /usr/lib/jvm/java-11-openjdk-amd64/bin/java      1101      自動モード
  1            /usr/lib/jvm/java-11-openjdk-amd64/bin/java      1101      手動モード
* 2            /usr/lib/jvm/java-11-oracle/bin/java             1091      手動モード
  3            /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java   1081      手動モード


現在の選択 [*] を保持するには <Enter>、さもなければ選択肢の番号のキーを押してください:3
```

これでJava8を使うようになるかと思ったのだけれど、以下のように、そうはならなかった。

```
$ java --version
openjdk 11.0.2 2019-01-15
OpenJDK Runtime Environment 18.9 (build 11.0.2+9)
OpenJDK 64-Bit Server VM 18.9 (build 11.0.2+9, mixed mode)
```

そもそもどこを見に行っているのか調べてみる。すると、

```
$ which java
/home/ksn/.sdkman/candidates/java/current/bin/java
```

となっておりJava(とKotlin)はSDKMANを使ってインストールした形跡があり。  

ここで、SDKMANでsparkをインストールできるらしいことを知ったのでそちらを試すことに。

```
$ sdk install spark
```

でインストールして`$spark-session`から動作確認を試みたが、やはり`'Unsupported class file major version 55'`のような同じエラーが出ている。

```
$ sdk list java
```

をしてSDKMANでJava8がインストール出来るのか見てみると、Javaは8以下はインストールできないっぽいことが判明。そうなるとこちらで解決しようというのは無理だということを判断。  

よって、以下でSDKMANで入れたjavaをアンインストール。

```
$ sdk uninstall java 11.0.2-open
```

これで、

```
$ java -version
openjdk version "1.8.0_212"
OpenJDK Runtime Environment (build 1.8.0_212-8u212-b03-0ubuntu1.18.04.1-b03)
OpenJDK 64-Bit Server VM (build 25.212-b03, mixed mode)

$ which java
/usr/bin/java
```

となり、`/usr/bin/`下のjavaを読んでくれることに。


`$ spark-shell`としてSDKMANでインストールしたsparkを立ち上げてみる。すると

```
$ spark-shell
...
scala> val textFile = spark.read.text("README.md")
textFile: org.apache.spark.sql.DataFrame = [value: string]

scala> textFile.count()
res0: Long = 109
```

となり、無事エラーがでなくなった。

調べた限りだと、SparkやHadoopと一緒にJava11を使うのはまだ早すぎでJava11を使いたければSpark3.xに期待しろとのことであった。これで[先日のHadoopを導入した際の問題](https://qiita.com/ksnt/items/b204d3fa30fb3cb86a06#fn1)も解決すると思われる。
Zend Framework v2からv3への移行

# 概要
>Zend Framework v2からv3は、段階的なアップグレードを目的としています。

# 移行における公式資料
[https://docs.zendframework.com/tutorials/migration/to-v3/components/](https://docs.zendframework.com/tutorials/migration/to-v3/components/)

# アプリケーションのアップグレード
>既存のZend Framework v2アプリケーションを使用していて、それを最新バージョンにアップデートしたい場合は、特別な考慮事項がいくつかあります。

### Zend Frameworkのアップグレード
> 2.5リリース以降、zendframeworkパッケージは基本的に「メタパッケージ」となり、コードを定義することなく、さまざまなコンポーネントパッケージへの依存関係のみを定義しています。つまり、インストールするzendframework/zendframeworkと、最新の2. *バージョンのコンポーネント一式が手に入ります。

### バージョン3のリリースでは、次のことをお勧めします。

>zendframework / zendframeworkパッケージを削除する。
zendframework / zend-component-installerパッケージをインストールする。
zendframework / zend-mvcパッケージをインストールする。
アプリケーションで実際に使用する各ZFコンポーネントパッケージをインストールします。
プロセスは次のようになります。

```vim
$ composer remove zendframework/zendframework
$ composer require zendframework/zend-component-installer
$ composer require zendframework/zend-mvc
```
>zend-mvcをインストールすると、コンポーネントの設定を追加するように促されます。application.config.phpまたはのいずれかをmodules.config.php選択し、他のすべてのパッケージに選択を再利用してください。この手順により、インストールされているさまざまなコンポーネント、および後で追加するニュースコンポーネントがアプリケーションに正しく設定されます。

>この方法では、実際に必要なものだけをインストールするようになります。例として、zend-barcode、zend-permissions-acl、またはzend-mailを使用していないのであれば、それらをインストールする必要はありません。

## ZFパッケージ補足
```vim
$ composer require zendframework/zend-component-installer "zendframework/zendframework:^3.0"
```
>一度にすべてのZend Frameworkコンポーネントの最新リリースにアップグレードできます。また、バージョン3の取り組みの一環として開発された新しいコンポーネントもインストールされます。

# 開発モード
>スケルトンアプリケーションのバージョン3では、zfcampus / zf-development-modeに要件が追加されてい ます。これは、開発に共通の設定をリポジトリに保存し、開発中にそれらを選択的に有効/無効にする方法を提供します。既存のアプリケーションからアップグレードする場合は、この機能をインストールできます。
[https://github.com/zfcampus/zf-development-mode](https://github.com/zfcampus/zf-development-mode)

```vim
$ composer require zfcampus/zf-development-mode
```

# 参考
[https://docs.zendframework.com/tutorials/migration/to-v3/application/](https://docs.zendframework.com/tutorials/migration/to-v3/application/)
dockerコマンドの補完を設定する

どうも、若松です。

dockerコマンドを使っていると、わかってるけど単語のスペルが出てこないなどで、サブコマンドやオプションをhelpで調べたり、ググる場面が多いかと思います。
そんなときにdockerにはコマンドを補完してくれる機能あるので、紹介したいと思います。

# 補完設定
実は公式にドキュメントも用意されています。
http://docs.docker.jp/compose/completion.html

私の環境がMac且つbashのため、以下はそれに合わせたコマンドとなります。

```bash
brew install bash-completion
curl -L https://raw.githubusercontent.com/docker/compose/$(docker-compose version --short)/contrib/completion/bash/docker-compose > /usr/local/etc/bash_completion.d/docker-compose
```

# 補完実行
補完を試すのは簡単です。

## サブコマンド
例えば、dockerのサブコマンドがわからなくなった場合、 `docker ` と打ってtabボタンを押すだけで以下のような結果が得られます。

```bash
$ docker
attach      deploy      images      logs        push        secret      tag
build       diff        import      network     rename      service     top
checkpoint  events      info        node        restart     stack       trust
commit      exec        inspect     pause       rm          start       unpause
config      export      kill        plugin      rmi         stats       update
container   help        load        port        run         stop        version
cp          history     login       ps          save        swarm       volume
create      image       logout      pull        search      system      wait
```

## オプション
例えば、 `docker images` のオプションがわからなくなった場合、 `docker images --` と打ってtabボタンを押すだけで以下のような結果が得られます。

```bash
$ docker images --
--all       --digests   --filter    --format    --help      --no-trunc  --quiet
```

# まとめ
dockerコマンドはサブコマンドやオプションが充実している分、覚えるのは難儀です。
ですので、補完をうまく使って、快適なdockerライフを送りましょう。
統計検定2級に合格した方法

# 受験動機
2019年の1月、機械学習エンジニアを志望し現在の開発会社に入社しました。
会社で機械学習を取り扱うということで、今後統計の知識も必要と思い挑戦しました。

これは民間の検定ですが、[求人サイトなどで「統計検定」](https://xn--pckua2a7gp15o89zb.com/%E7%B5%B1%E8%A8%88%E6%A4%9C%E5%AE%9A2%E7%B4%9A%E3%81%AE%E4%BB%95%E4%BA%8B-%E6%9D%B1%E4%BA%AC%E9%83%BD)で検索してみると、データサイエンティストやAIエンジニアの募集として「統計検定二級程度の知識」を「歓迎条件」や「尚可」とする企業もあり、場合によっては就活の一助になるでしょう。
どのみち統計についての勉強になったので、今となっては挑戦して良かったと思っています。


## 筆者の経歴
エンジニア歴1年。統計歴ほぼゼロ年。
勉強期間は約二ヶ月。

# 決まりごと
[統計検定の契約上](http://www.toukei-kentei.jp/non-discl/)、詳細に踏み込むことはできません。
ただ自分の学習した範囲と、学習しなかった範囲などをご紹介します。

# 持っていくもの
自分はいつでも受験できる(一週間前に申し込み必要でしたが)CBT方式で受験しましたが、
紙の試験とは違って、CBTで持ち込めるのは電卓だけです。
ボールペンなどはCBTの会場(自分の場合はとあるパソコン教室でしたか)で貸し出されました。
筆記用具も一応持っていきましたが使いませんでした。
当然ですがスマホもカバンにしまうように指示されます。

ちなみに[使用した電卓はこれを買いました](https://www.amazon.co.jp/dp/B000UZRNGY/)。 **関数電卓は使用できないのでご注意を。**

# 勉強に使用した教材
- 公式の過去問題集(2018年11月-2016年6月)
- [統計学の時間](https://bellcurve.jp/statistics/course/)
- [統計検定2級　模擬問題集](https://www.amazon.co.jp/dp/B07DNW5S5J/)

とりあえず過去問と統計WEBの[統計学の時間](https://bellcurve.jp/statistics/course/)２つを繰り返しました。
過去問は今後出るかも怪しい難問が必ずあるので、平均85%程度取れることを目指しました。
つまるところ、自分は過去問ですらちゃんと理解して解答できるのは85%程度です。
基本的に合格ライン(60点≠問題の60%)を超えてさえいればよかったので、全問理解することは諦めました。

擬似問題集は、自分がKindle Unlimitedの利用者なので全て実践してみました。
もしもKindle Unlimitedのメンバーなら力試しに挑戦したほうが良いと思います。


## 使用しなかった教材
逆に使用しなかった教材は、統計学の初学者本として有名な『心理統計学の基礎』です。
これは統計学の基本書としては役に立ちますが、統計検定二級の範囲を超えた内容も含むので今回は勉強するにあたって購入したものの意図的に放置しました。

もちろん副読本として読む余裕があるなら読んでもいいですし、合格する確率は高めるかもしれません。ただ自分の場合はほぼ読まずに受かることはできました。

その他統計学初学者向けの本が様々ありますが、その本を読むための時間を取りたくなかったので避けました。
こればかりはなかなか「やらなくてもいい」とは言い切れません。個人的には合格を確実にしたい場合はちゃんと読んだ方がいいと思います。



# やっておくべきもの
問題は検定主催者が用意した問題プールからランダムに出されるので、ここでなんとも言いにくいのですが、
過去問で出るような信頼区間、検定問題、確率、要約統計量や図表の読み取りなどは当然ですが、
最近の過去問ではほぼ出ていないような、母分散の推定、検定などもやっておくといいと思います。
一元配置分散分析とF検定関連も当然やっておいたほうが良いと思います。
(詰まる所、出題範囲はとりあえずやっておくべきということですね……)




# 後悔したこと
## 計算用紙が足りない
試験を受ける前に、計算用に使う用紙が渡されます。
ただ**全然足りません**。
自分はこの計算用の用紙の使い方をミスったため(あとで追加でもらえると勘違いしていた)、問題の後半は隅っこの方に小さく計算していました。精神的にこれは厳しかったです。

序盤の比較的簡単な問題は出来る限り紙幅を取らないように小さくメモっておいて、難問でも余裕を持って解けるようにしたほうがいいと思います。

## 時間が足らない
自宅で過去問を解いたときは60分ほどで解答していたので余裕かなと思っていたのですが、実際の試験では全問解いたのは87分ぐらいでした。残りの3分ではほぼ見直す余裕がありませんでした。
初見の問題と過去問とでは当然思考時間が違うのもあるのですが、本番ではPCの画面(若干その画面の位置が高かった)と手元の計算用紙を往復するため、思った以上に時間が取られると思います。


## もっと勉強しておけばよかった
七割程度とれて合格したから良かったものの、正直10問ほど分からずに勘で答えました。
問題文に知っている単語は使われているものの、解いたことのない問題が出たために解答できなかったというパターンが多かったです。
これは過去問を完璧にしたからといって解けたとは思えません。

直感的には最近の過去問よりも難しく感じたというのが本音です。僕自身が何度も過去問をやったためにそう感じるのかもしれませんが、**合格を確実にしたい場合は過去問集のみならず、もっと多様な問題に触れておく必要があった** と今は考えています。


では具体的にどの問題集かとなると自分自身分かっていませんが、ひとまず統計学の問題集として有名な**『統計学演習』**に挑戦してみると思います。
[著者の一人によって書籍の一部がネット上で公開](http://www.math.s.chiba-u.ac.jp/~yasuda/statEN2/statENSYU.html)されており、どんな内容か把握することができます。
問題の回答はないのでそこは書籍を購入する必要がありますが、「二級の問題で出そうな問題」だけ取捨選択して挑戦しておくと良いと思います。

また僕は直近の過去問(2019年発売)を使っていたので、古い過去問(2016年6月以前の問題を含んだ問題集)を古本で購入するのも手かもしれません。
(ただネット上の噂ではある時期から出題範囲が変わったような話も聞いたので、古い過去問を購入する際は出題される内容も理解した上で勉強したほうがいいかもしれません)


# 終わりに
およそ2ヶ月ほどの準備期間でしたが、どうにか合格できました。
今後統計検定に挑戦したいという方の一助になれば幸いです。
【Laravel】入力エラーのとき「ファイルをあげ直してね」メッセージを出すよう対応したよ

# まえがき
最近はLaravelを触ってます。

で、バリデーションまわりを触っていたのだけど、ファイルアップロードで困ったことが。
エラーがあって戻されたときに画像ファイルの情報が消し飛んでしまって何も分からない。。
「ファイル残してほしい」とは言わないけど、
せめてどこのファイルをあげようとしていたのか教えてほしいなぁ、と思ったので対応したよ。


# 前提
- PHP7.3.6
    - Laravel 5.5.45

# なぜ消えるのか
バリデーションエラーが発生した場合、自動で前ページに戻される。
その際に入力時のデータもセッション内に保存してくれているのだけど、この部分で意図的に消しているからだった。

## ExceptionHandler
正確には `Illuminate\Foundation\Exceptions\Handler` 。
ValidationException発生時、なにもしていなければこのクラスの `render` に入ってきて、
`convertValidationExceptionToResponse` からの `invalid` へ渡す。

この `invalid` で前ページに戻る処理をしているのだけど、
その際に渡す入力元データをリクエストを元に生成している。

## redirect
正確には `Illuminate\Http\RedirectResponse` 。
この中の `withInput` からの `removeFilesFromInput` で

```php:Illuminate\Http\RedirectResponse
    protected function removeFilesFromInput(array $input)
    {
        foreach ($input as $key => $value) {
            if (is_array($value)) {
                $input[$key] = $this->removeFilesFromInput($value);
            }

            if ($value instanceof SymfonyUploadedFile) {
                unset($input[$key]);
            }
        }

        return $input;
    }
```

`SymfonyUploadedFile` のインスタンスをバッサリ削除してた。
そりゃ何も取れない訳だ････('A`)


# SymfonyUploadedFileを消させない
こんな根っこから対応が入ってるんじゃ手を入れづらい････と思ったけど、そんなことはなく。

`ExceptionHandler::convertValidationExceptionToResponse` を見直す。

```php:Illuminate\Foundation\Exceptions\Handler
    protected function convertValidationExceptionToResponse(ValidationException $e, $request)
    {
        if ($e->response) {
            return $e->response;
        }

        return $request->expectsJson()
                    ? $this->invalidJson($request, $e)
                    : $this->invalid($request, $e);
    }
```

引数である `ValidationException $e` にレスポンスが入っていれば、それ以降の処理はせず、直接使う。
てことは、ここより前に `$e->response` をつけてやればいい。

```php:\App\Exceptions\Handler
    protected function convertValidationExceptionToResponse($e, $request)
    {
        $url = $exception->redirectTo ?? url()->previous();

        $inputs = $request->all();
        foreach ($inputs as $key => $value) {
            if (is_array($value)) {
                $inputs[$key] = $this->removeFilesFromInput($value);
            }

            if ($value instanceof SymfonyUploadedFile) {
                // 元ファイル名だけ返す
                $inputs[$key] = basename($value->getClientOriginalName());
            }
        }

        $e->response = redirect($url)
            ->withInput($inputs)
            ->withErrors(
                $e->errors(),
                $e->errorBag
            );

        return parent::convertValidationExceptionToResponse($e, $request);
    }
```

ファイル名くらいはあってもいいかな、と思って入れたけど、
別に「あげ直してね」ていうくらいならTRUE/FALSEでもいいね。。

```html:テンプレート
    <table>
      <th>画像ファイル</th>
      <td>
        {{ Form::file('image') }}
        @if ($errors->has('image'))
          <p>{{ $errors->first('image') }}</p>
        @elseif ($errors->any())
          <p>ファイルをあげ直してください: {{ old('image') }}</p>
        @endif
      </td>
    </table>
```

テンプレートが雑なのはご愛嬌。。
10個くらいフォーム作って出した方が分かりやすいかとは思ったんだけど、メンドかった(´・ω・｀)


# あとがき
ちょっと調べるのに時間がかかったのでメモ的に。
とはいえ、Laravel触り始めだから、基底クラスをめぐるちょうどいい機会ではあったかな(^-^)

まぁ、需要があるかは分からないけど。。。
コンテナにログインして内部を調査できるワンライナー

どうも、若松です。

コンテナイメージを作成するときはDocekerfileを作成すると思いますが、その前にベースイメージ内部を確認したいことが多いと思います。

そこで、ベースイメージをpullした状態からコンテナへログインするワンライナーをご紹介します。

# AmazonLinux2コンテナへログインするワンライナー
```bash
docker run -it amazonlinux:2 /bin/bash
```

# AlpineLinuxコンテナへログインするワンライナー
```bash
docker run -it alpine /bin/sh
```

# まとめ
ベースイメージにログインできるとDockerfileを作成するための材料が揃えやすいので、このワンライナーは有用かと思います。
WordPressのphpunitテストで is_front_page や is_ single() などのテスト方法メモ

テストコード内で

```
$this->go_to( 確認したいURL ); 
```
とか

```
$wp_query = new WP_Query(); 
```

でいける。

https://github.com/torounit/custom-post-type-permalinks/blob/master/tests/test-cptp-module-rewrite.php#L63-L64

https://github.com/vektor-inc/VK-All-in-One-Expansion-Unit/blob/5cd5feaf273a10e6814d55b37a89d8bc2c0d4b4c/tests/test-sns-title.php#L130-L131
IBM Cloud の Provisioning Script を Ubuntu で正常に完了させるには


# Provisioning Script とは

IBM Cloud の IaaS サーバーに起動スクリプトを指定できる機能です。
Github や Gist などを使って `https` の `URL` を公開することで、そのスクリプトを起動時にダウンロードし、IaaS サーバーでの初期作業を自動化することができます。

>[Provisioning scripts](https://cloud.ibm.com/docs/vsi?topic=virtual-servers-provisioning-scripts)

# Provisioning Script の実態
プロビジョニング過程の最終再起動後に Ubuntu の `systemd` を使って、以下のようなサービスが起動するように設定されています。
指定した Provisioning Script は、 `/root/install_complete.sh` に追記されて、 `install_complete.service` の `ExecStart` で実行されます。
`Type=oneshot` は、一度だけ指定のコマンドを実行するタイプのサービスにです。
`ExecStart` で指定された Provisioning Script を含むシェルスクリプトを実行して、それが完了したタイミングで起動完了（かつサービス終了）と判断します。


```
# cat install_complete.service 
[Unit]
Description=INSTALL_COMPLETE
After=network.target

[Service]
ExecStart=/root/install_complete.sh
Type=oneshot
TimeoutSec=0

[Install]
WantedBy=multi-user.target
```

# `systemd` のバグ
タイムアウト設定を無効 (`TimeoutSec=0`) にしている、または明示的に指定していない場合、100s 程度で強制終了するバグが確認されています。

>[server - Systemctl service timed out during start - Ask Ubuntu](https://askubuntu.com/questions/953920/systemctl-service-timed-out-during-start)
>[1446015 – systemd fails to start a service if TimeoutSec=infinity is used](https://bugzilla.redhat.com/show_bug.cgi?id=1446015)
>[systemd - Services timed out at boot but could start manually what could be the problem? - Unix & Linux Stack Exchange](https://unix.stackexchange.com/questions/412996/services-timed-out-at-boot-but-could-start-manually-what-could-be-the-problem/445586)

実際にこのような結果になりました。
ログは `journalctl` で確認可能です。
(他にも `journalctl | grep postinstall`, `journalctl -f` など)

```
Jul 03 13:02:50 khayama-mc.ibmcloud.com systemd[1]: install_complete.service: Start operation timed out. Terminating.
Jul 03 13:02:50 khayama-mc.ibmcloud.com systemd[1]: install_complete.service: Failed with result 'timeout'.
Jul 03 13:02:50 khayama-mc.ibmcloud.com systemd[1]: Failed to start install_complete.service.
Jul 03 13:02:50 khayama-mc.ibmcloud.com systemd[1]: Startup finished in 4.130s (kernel) + 1min 35.993s (userspace) = 1min 40.124s.
lines 4646-4675/4675 (END)
```

# バグを回避する方法
`Type` を別のものに変えるか、`TimeoutSec` を `0` 以外の値に明示的に指定することで回避可能です。
例として、 `Provisioning Script` の中で `TimeoutSec=5min` として `install_complete.service` を再作成するスクリプトを示します。
`install_complete.sh` に起動スクリプトの内容を書き込み、`systemd` をリロード後にリスタートさせることで 100s 以上時間がかかるスクリプトでも正常に完了されることができます。

```shell:ubuntu_provisioning_script.sh
#!/bin/bash

# Write down your provisioning script into this part
cat > /root/install_complete.sh <<EOF
#!/bin/bash
# update packages
DEBIAN_FRONTEND=noninteractive apt-get update
DEBIAN_FRONTEND=noninteractive apt-get upgrade -y
# reboot
reboot
EOF
chmod 755 /root/install_complete.sh

# You do not have to change this part
# set timeoutsec explicitly to prevent timeout fail
cat > /etc/systemd/system/install_complete.service <<EOF
[Unit]
Description=INSTALL_COMPLETE
After=network.target
[Service]
ExecStart=/root/install_complete.sh
Type=oneshot
TimeoutSec=5min
[Install]
WantedBy=multi-user.target
EOF
# run your script above without timeout fail bug
systemctl daemon-reload
systemctl restart install_complete.service
```
作成したLaravelコンテナを軽量化する

どうも、若松です。

前回はDockerでLaravelを起動するまでをまとめました。
https://qiita.com/t_wkm2/items/9b2011af9569627fee40

しかしながら、現在のコンテナイメージはお世辞にも軽量とは言えません。
コンテナイメージサイズはコンテナ起動時間に直結するため、できるだけ軽量化していきたいと思います。

# Dockerfile

```Dockerfile
FROM amazonlinux:2 as vender

# PHPインストール
RUN amazon-linux-extras install -y php7.3
RUN yum install -y php-pecl-zip php-mbstring php-dom

# Composerインストール
RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
RUN php -r "if (hash_file('sha384', 'composer-setup.php') === '48e3236262b34d30969dca3c37281b3b4bbe3221bda826ac6a9a62d6444cdb0dcd0615698a5cbe587c3f0fe57a54d8f5') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
RUN php composer-setup.php
RUN php -r "unlink('composer-setup.php');"
RUN mv composer.phar /usr/local/bin/composer

# 環境変数設定
ENV COMPOSER_ALLOW_SUPERUSER 1
ENV COMPOSER_HOME "/opt/composer"
ENV PATH "$PATH:/opt/composer/vendor/bin"

# Laravelインストール
RUN composer global require "laravel/installer"

# Laravelプロジェクト作成
WORKDIR /var/www
RUN composer create-project laravel/laravel laravel

FROM php:7.3-alpine

# ビルド用コンテナから必要なコンテンツをコピー
COPY --from=vender /var/www/ /var/www/

# ポートを公開
EXPOSE 8000

# Laravelサーバーを実行
WORKDIR /var/www/laravel
CMD ["php","artisan","serve","--host","0.0.0.0"]
```

# 軽量化に際して覚えておくこと
## マルチステージビルド
マルチステージビルドは、一般的にビルドに必要なコンテンツの生成フェーズと実行に必要なコンテンツに絞ってコンテナを固めるフェーズに分けてコンテナをビルドすることを指します。
ビルド時に必要だが実行時にには必要ない(一般的にDeveloperKitのような)ものを実行するコンテナから除外できるため、コンテナイメージの軽量化が期待できます。

## squashオプション
Dockerfileでビルドする際、Step毎にコンテナのレイヤーが生成され、最終的なコンテナはそのレイヤーを含むためにサイズが肥大化しがちです。
ビルド時にsquashオプションを用いると、最終的にレイヤー1つに集約してくれるため、コンテナイメージの軽量化が期待できます。

## Alpine Linux
詳細は割愛しますが、軽量OSとしてコンテナ界隈では有名です。
https://ja.wikipedia.org/wiki/Alpine_Linux

Alpine Linuxをベースとすることで、その他のイメージをベースとするよりも、コンテナイメージの軽量化が期待できます。

# Dockerfile詳細
## ビルド用イメージ

```Dockerfile
FROM amazonlinux:2 as vender
```
前回同様、AmazonLinux2をベースとしていますが、後段でしようするためにエイリアスとして `as vender` を付けています。

## 省略

```
# PHPインストール
# Composerインストール
# 環境変数設定
# Laravelインストール
# Laravelプロジェクト作成
# ポートを公開
# Laravelサーバーを実行
```
上記は前回と同じなため、解説を省略します。

## 実行用イメージ
```Dockerfile
FROM php:7.3-alpine
```
PHP公式から提供されているAlpineLinuxのイメージを使用します。
これによってAlpineLinux且つPHP7.3の環境を構築できます。

## ビルド用コンテナから必要なコンテンツをコピー
```Dockerfile
COPY --from=vender /opt/composer/vendor/ /opt/vender/
COPY --from=vender /var/www/ /var/www/
```
前段のビルド用コンテナから必要なコンテンツをコピーします。
ここで前段で用いた、 `as vender` 効力を発揮します。

# コンテナビルド
```bash
docker build -t laravel . --squash
```
ビルド時に `--squash` オプションを付加します。
これによってレイヤーを1つに集約し、計量化を図ります。

# 軽量化前と軽量化後の比較
## 軽量化前
```bash
docker images laravel
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
laravel         latest              xxxxxxxxxxxx        　xx seconds ago        748MB
```

## 軽量化後
```bash
docker images laravel
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
laravel         latest              xxxxxxxxxxxx        　xx seconds ago        117MB
```

# まとめ
少しの工夫でコンテナが軽量化できることがわかっていただけたと思います。
最初にも述べたように、コンテナイメージサイズはコンテナ起動時間に直結するため、積極的に軽量化を図っていきたいですね。
[初心者]Gitで過去の履歴(コミット)に戻る方法

最近、Gitを勉強しています。その過程で分かっていなかったことを理解できた？ので残しておきます。今回は、Block_Game.pyというファイルを例にしています。

#Gitで過去の履歴に戻りたい
まず、任意のブランチ上で、git logコマンドを入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440828/bc80be55-d079-93ae-844c-e9ddc5c6b419.png)
すると、現在のブランチ上でのコミットの履歴が出てきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440828/34766cd3-2648-1995-e579-dd7827ec97f4.png)
commitの後に続く cebb7・・・みたいな英数字の文字列がアドレス(履歴)になります。
今回は過去の履歴に戻りたいのでコミット1のアドレスをコピーします。(範囲選択して[Ctrl]+Cでコピーできる)。

この時点での最新のファイルの中身は以下のようになっています。(コメントアウトでコミット2と記述した)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440828/87f0e795-8c44-ce6d-50f1-796759502be0.png)
そして先ほどコピーした過去のコミット(コミット1時点)のアドレスをgit checkout [アドレス] [ファイル名]と叩くことで過去の履歴に戻ることができます。

[ファイル名]は指定した場合はそのファイルのみが過去の履歴に戻ります。また、指定しない場合はコミットした時のファイル全てが対象になります。
(アドレスはwindowsでは[Shift]+Insと打つと貼り付けができます。)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440828/54b0dfd5-1ebf-a394-5b2c-21d5c079e248.png)
その結果、ローカルリポジトリから過去の履歴を現在の作業ディレクトリにコピーできます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440828/0c3c7a14-409b-8ad7-dbfe-91efb05dcb18.png)
最後に、作業ディレクトリのファイルを開くとちゃんと過去の履歴に戻れていることが確認できました。

#最後に
調べてみると、checkoutをブランチを移動するものとして紹介しているサイトだったりが多く、過去の履歴に戻る方法として初心者向けに説明しているものが少なったので、自分の復習も兼ねてこの記事を書きました。
＊私も最近Gitを使い始めた初心者ですので理解が少しずれているかもしれません。
JavaのアプリをIBM Cloud Kubernetesサービス上にデプロイ

先日タイトルの内容でハンズオンやってと言われたので忘れないうちに手順を書いておきます。
やりたいことは持っているJavaアプリ(warファイルになっている）からOpenLibertyと一緒にDockerイメージを作ってそのイメージをIBM Cloud上でデプロイします。
　なお今回のは無料で作れるライトアカウントでもできるので初心者のかたも是非やってみてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59741/c5940101-c86c-b652-4303-535535368100.png)

手順は
1. IBM CloudにKubernetesクラスターを作成
2. ローカルのDockerDockerイメージを作成、Docker Hubにアップロード
3. IBM CloudのKubernetesサービス上にデプロイ

アプリ（サーブレット）は極めてシンプルなものですがきっと複雑なアプリもできるはず

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59741/25620ec4-c6ea-c61c-3d5c-45eb3551a3fc.png)

1. IBM CloudにKubernetesクラスターを作成
　これはこちらを参考に作りました。
https://cloud.ibm.com/docs/containers?topic=containers-cs_cluster_tutorial&locale=ja
ライトアカウントで作れる無料のクラスターでやりました。

2. ローカルのDockerDockerイメージを作成、Docker Hubにアップロード
PCかMACで以下のコマンドを実行Open Liberty のDocker イメージをダウンロード
$ docker image pull open-liberty

次に以下の内容でDockerfileを作成
------
FROM open-liberty
COPY ./book-deploy.war /config/dropins/book-deploy.war

------

同じフォルダーにwarファイルを配置して以下のコマンドでopenliberty-handsonのDockerイメージを作成。
$ docker build . openliberty-handson

できたらDocker Hubにアップローヂ
$ docker tag openliberty-handson <DockerHubのユーザー名>/openliberty-handson
$ docker push ユーザー名/openliberty-handson
アップロードされたのを確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59741/c85772c0-7d42-cfa5-13e6-56305e0c0bbe.png)

3. IBM CloudのKubernetesサービス上にデプロイ
 IBM cloudにログインしたのちに以下のコマンドでDeploymentの作成、サービスの作成を行ってください。
$ Kubectl run liberty --image=<ＤｏｃｋｅｒＨｕｂのユーザー名>/openliberty-handson
$ kubectl expose deployment liberty --type="NodePort" --port=9080

これでできました。次にIPアドレス、ポート番号を調べてブラウザーからアクセスします。
IPアドレスは
$ ibmcloud cs workers <クラスター名>
で出てきたパブリックアドレスです。
ポート番号は
$ kubectl get service liberty
ででてくるPort(s)の２番目の番号で30000番台の数字です。

ブラウザーでアクセスしてみましょう！
シノビリフレに学ぶ固定メニュー

# なんてことない土曜日の話
新しいサイトのレイアウトの参考にと、[にじいろクリップ](https://nijiiro-clip.com/)を眺めていた時のことでした。

> なんかこう、ビビッ!!とくるサイトないかなぁ……
そう、某「いつでも、どこでも、誰とでも」なハイブリッドゲーム機のHD振動みたいに
心の芯が揺さぶられるような……ん？

そう、見つけてしまったのです。[**シノビリフレ**](https://senrankagura.marv.jp/series/switch/)のサイトを！

> こ、こいつは……***下端固定メニュー***だと！？

そこに書かれていたのは、衝撃的な事実でした。

# なんと810円にプライスダウンされていた！

上端のメニューを一部だけ固定するのは比較的簡単にできます。

> body
　header
　nav
　div#body
　footer

といったタグ構成（header+navでヘッダー）の場合

```css
nav {
  position: sticky;
  top: 0;
}
```
だけで大体終わります。
一定位置までスクロールしたらfixedのnavを表示するとかは必要ありません。
IEユーザは文句を言う前に、対応ブラウザへ移行しましょう。

今回の下端固定メニューの場合も実際には、
> body
　header
　div#body
　nav
　footer

```css
nav {
  position: sticky;
  bottom: 0;
}
```
だけで済む話なんです。ええ。

それではシノビリフレのタグ構成を見てみましょう。
> body
　header
　div#body
　footer
　　nav
　　others (最下部にした時に表示されるもの)

そこに書かれていたのは、衝撃的な事実(タグ構成)でした。
ちなみにnavのみ表示されている時は、footerに`.fixed`が付いています。

さて、貴方ならどうやって実装しますか？ 少しだけ考えてみてください。

# 特定の条件を満たすと「裏オプション」も

どう実装されているかを確認するより、どう実装するかを考えた方が勉強になります。
というわけで、タグ構成はこのままでチャレンジしてみました。

## とりあえずCSSだけで頑張った

```css
footer.fixed {
  position: sticky;
  bottom: 0;
}
footer.fixed > :not(nav) {
  display: none;
}
```
見た目上と表示上はいい感じに再現されたものの、最下部に来るとスクロール領域が増えてスクロールバーがぴょこぴょこします。
シノビリフレはそんなことしない！

## 仕方なくjsでも手を加えた
ぴょこぴょこしない方法は分かっているのです。

```css
footer.fixed {
  position: sticky;
  bottom: XXXX;    // -(othersのheight)px
}
```
とすれば良いのですが、`XXXX`は決め打ち以外にcssで当てようがありません。
どうせ`.fixed`の着脱時にDOMやwindowのサイズを使用しているので、js側で直接footerにbottomだけstyle付与しました。
これで大体シノビリフレと同じ挙動になってくれます。
ところで、`.fixed`なのに`position: sticky;`ってどんな裏仕様ですか？

## 実際のところどうなのか
詳細までは見る気が起きなかったですが、以下の特徴を見るにサイズは決め打ちでしょうね。
> footerに`position:absolute;`
> footer.fixedに`position:fixed;`
> bodyにfooter用の`padding-bottom`指定

無駄に勉強させてもらった感じとなりました。

# CSSが思い通りに当たらない場合は、HTMLのタグ構成から見直すべき

途中にも書きましたが、stickyを使えば上端固定メニューも下端固定メニューも結構簡単に実装できます。
ですが、適当に書いたHTMLと、それを無理矢理デザインに寄せたCSSの場合は、大体うまく行かずにどこかが崩れます。そんな場合は、どんなに詳しくてもCSSだけで対処するのではなく、HTMLのタグ構成から見直してはどうでしょう？　それくらいサイトデザインとHTMLは密接な関係にあるんですよ！というお話でした。
あるいは全タグにidを振ってデザイン管理しましょう！(ﾏﾃ

体形を見ただけで３サイズを当てられる特技は無くてもいいですから、
適当なサイトを眺めるだけで、おおよそのタグ構成が想像できるようになると良いですよね！
開発メモ：プチコン4で大規模なプログラムを作成する

Nintendo SWITCH と「[プチコン4 SmileBASIC](https://www.petc4.smilebasic.com/)」をついに購入しました！

[プチコンmkIIやプチコン3号](https://qiita.com/yamachan360/items/bfea9f720afbd0fd168e) と比べて大きいのは、やはり個人的にはキーボードが繋げるようになったことですね。これで長いコードも怖くない！![IMG_6907.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193519/b44071c3-527a-ea0e-e230-27157c48873b.jpeg)
というわけで、SmileBASIC の復習を兼ねて、大規模なプログラムを作成するコツを整理してみます。

# マルチプログラム

プチコン3号の頃から、[マルチプログラム](http://smilebasic.com/spec/) という概念がありました。

> スロット0～スロット3の4スロットに、別個のプログラムを記憶・実行可能。

というものです。プチコン4にもこの機能は継承されており、ソフトキーボードを表示中に、トリガーを引くと切り替わるメニューの中に、スロットを操作するボタンが用意されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193519/c784111f-e52c-6073-dba8-2a8337c716aa.png)
ちなみにキーボードだと Ctrl+1～4 キーで切り替わるみたい。

通常のテキストエディタで例えると、4つのソースファイルを同時に開き、タブで切り替えながら編集できる感じでしょうか。大規模なプログラムをパーツ分けして開発するのに、適した機能です。

## ちょっとマニアックな機能？

通常の状態では、プチコンは `スロット0` を対象に動作しています。例えばプログラムを実行する際に `RUN` 命令を使用しますが、この命令の正式な記述方法は

```
RUN [プログラムスロット]
```

であり、どのスロットにあるプログラムを実行するか指定するようになっています。ただしこのプログラムスロットの初期値が 0 となっているので、指定しないと `スロット0` にあるプログラムを対象に実行します。

スロット1～スロット3 は知らなくても問題ない、中級者以上のために用意された機能なのです。

## マルチプログラム間の連携

さて、マルチプログラム間の連携について簡単にまとめてみます。

まず、各スロットは独立しています。基本的には他スロットの環境、変数や関数にはアクセスできません。変数名の衝突なども気にする必要は無い、という状況です。

そしてマルチプログラム間の連携のために用意されたキーワードが `COMMON` で、これを付けて定義された関数は他のスロットから認識され、呼び出すことができます。例えば以下のような簡単なサンプルプログラムが、SLOTTEST というファイル名で保存されているとします。

```vb:SLOTTEST
COMMON DEF SUB_ADD(A,B)
 RETURN A + B
END
```

この関数は以下のようにして利用できます。

```vb:MAIN
LOAD "SLOTTEST",1   'プログラムをスロット1に読み込む
EXEC 1              'スロット1を実行し定義を有効にする
PRINT SUB_ADD(2,3)  '定義された関数を利用する 
```

ただこの `COMMON` キーワードは関数定義だけのようです。例えばサブルーチンの場合は、以下のようにキーワード付けずに普通に定義しておいて、

```vb:SLOTTEST
END
@SUB_1
PRINT "ABC"
RETRUN
```

利用する側は以下のように `@SUB_1` ラベルを引用符 `"`で囲ったうえで、スロット番号を示す `1:` を付与したカタチで呼び出します。

```vb:MAIN
LOAD "SLOTTEST",1   'プログラムをスロット1に読み込む
EXEC 1              'スロット1を実行し定義を有効にする
GOSUB "1:@SUB_1"    '定義されたサブルーチンを呼び出す
```

※ 上記の1行目と2行目は EXEC "SLOTTEST" 1 と1行にまとめることもできます

## どう活用するか

個人的には、過去の経験から、大規模なプログラムを作成する際、スロットを以下のような感じで利用したいと考えています。

**スロット0:** メインロジックとデータモデル<br>　　　　　(例: 戦士の基本パラメータ、など)
**スロット1:** 目的ごとの処理ロジックを記述した上位ライブラリ<br>　　　　　(例: 戦闘ロジック、ダメージ計算処理など)
**スロット2:** 対象の種別に特化した下位ライブラリ<br>　　　　　(例: コマンド選択ウィンドウの表示ルーチン、など)
**スロット3:** 汎用のコアライブラリ<br>　　　　　(例: データ変換関数、など)

まあ、実際に実機で作ってみないとわかりませんが。

下位・コアライブラリは今後も使いまわしたいので、上位のプログラムを解析して、使われた関数だけをまとめて書き出すような、簡易的なパッケージツールなども作成できると、より楽ができそうです。

# というわけで

プチコン4 を使い始めるにあたり、これまで活用していなかったマルチプログラム/スロットの機能をざっとまとめてみました。

今後は機能の汎用化、ライブラリ化を並行して進めつつ、プチコン4のプログラムを書いていきたいとおもいます。いくつか書いてもう少し経験を積んだら、ここに追記しますね。

それではまた！
初心者のためのアルゴリズム〜ユークリッドの互除法編〜

今回は、ユークリッドの互除法をPythonで実行していきたいと思います。
プログラミングを始める前から「ユークリッドの互除法」という言葉自体は知ってた方も多いのではないでしょうか。
高校数学IAでやりましたよね。
まずはユークリッドの互除法の説明と、その数IAで習う問題を見てみましょう！

# ユークリッドの互除法とは
古代エジプトの数学者ユークリッドが記した『原論』に書かれている、世界最古のアルゴリズムとされている方法です。
2つの自然数 a, b (a ≧ b) について、a の b による剰余を r とすると、 a と b との最大公約数は b と r との最大公約数に等しいという性質が成り立つことを発見し、b を r で割った剰余、 除数 r をその剰余で割った剰余、と剰余を求める計算を逐次繰り返すと、剰余が 0 になった時の除数が a と b との最大公約数となることを明示しました。（[Wikipedia参考](https://ja.wikipedia.org/wiki/%E3%83%A6%E3%83%BC%E3%82%AF%E3%83%AA%E3%83%83%E3%83%89%E3%81%AE%E4%BA%92%E9%99%A4%E6%B3%95)）

# 数IA
Q.
2077と1829の最大公約数を求めよ。

A. 
2077 = 1829・1 + 248
1829 = 248・7 + 93
248 = 93・2 + 62
93 = 62・1 + 31
62 = 31・2
よって、最大公約数は31 

忘れていた人もこれをみたら思い出したのではないでしょうか？
機械的に解けるので、数IAの模試でこの手の問題が出たら喜んでいました。

# アルゴリズム
```Euclid.py
def euclid(a, b):
     r = a % b
     while(r != 0):
         a = b
         b = r
         r = a % b
     return b

print(euclid(2077, 1829))
```

実際にコードを書くと、このようになります。
これを実行すると、きっちり31が最大公約数として表示されました。
Pythonを利用することで、一瞬で最大公約数を求めることができるようになりました。


# まとめ
ユークリッドの互除法を理解することができたでしょうか。
コード自体は非常に簡単なので、一度書いてみるとより理解が深まるかもしれないですね。
iOS13時代のSVG表示設定方法

:::note info
Xcode 12以降を使用する場合はこちらをご覧ください。
:::

https://qiita.com/Hackenbacker/items/7d45657ad9249f62fd8a



# はじめに
デザイナーからアイコン素材としてSVGが納入される機会が出てきたこの頃。
WWDC2019の```Introducing SF Symbols```の中で **AVOID rasterizing!** と言ってるくらいなので、
![SS00003.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95033/f5f014fc-d11c-5cc8-2a83-33aa8e8612d4.png)
iOS13時代のアプリでSVGを扱う方法は何が最適か試行錯誤してみました。
(Xcode 11 beta3, Deployment Target = iOS 12.0)

**前提：**  [SVGKit](https://github.com/SVGKit/SVGKit)などのライブラリは使いません。

# SVGのサイズ
SVGは拡大しても大丈夫なはずなのですが、
:o:　SVGは**3x画像**のサイズに設定してください。
:x:　1x画像サイズにすると、2x画像、3x画像がギザギザになります。 (iOS12以下にて)

デザイナーへ発注するときにお願いするのが理想的ですが、
**「SVGは拡大してもギザギザにならないんだからサイズ指定するとかおかしいでしょ！」** と些細な事で揉めがちなので:cloud_rain:
検索すればフリーのツールやサイトを見つけることができます。

# SVGのファイル形式
:small_red_triangle:従来通りPDFに変換してください。
デザイナーへ発注するときにお願いするのが理想的ですが、
(略)
検索すればフリーのツールやサイトを見つけることができます。

# SVGの設定
1. Asset Catalogに```Image Set```を作成する。
2. Resizing ```Preserve Vector Data```にチェックする。
3. Scalesは ```Individual Scales```にセットする。
4. SVGを```1x```にセットする。(2x、3xは空欄)

:o:　SVGはコードで表示すること。

```Swift
imageView.image = UIImage(named: "svgSample")
```
:x:　Storyboardで画像を設定しただけではギザギザになります。

![S_SVG_IMAGE_SET.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95033/6cc7e546-e2d1-6954-9c75-602af6018e98.png)

# 比較
左からiOS13、iOS12(3xサイズSVGをセット)、iOS12(1xサイズSVGをセット)
![SS0001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95033/9f04114c-c668-51e4-df76-b6fe8c4d3c67.png)


# iOS13以降しかTargetにしないとき

:o:　SVGサイズは気にしなくていいです。
:small_red_triangle:PDFに変換してください。
:small_red_triangle:コードで表示してください。
1. Asset Catalogに```Image Set```を作成する。
2. Resizing ```Preserve Vector Data```にチェックする。
3. Scalesは ```Single Scale```にセットする。
4. SVGを```All```にセットする。
![SS0002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95033/cddb1744-7507-f523-134b-03c96a1da7d0.png)
:o:　2x、3xは空欄でいいの？とか3xサイズなのに1xにセットするの？とか気にしなくていい。

# 感想
iOS13のベクター画像の扱いが素晴らしくなっている。:clap:
早く変換なしでSVGをセットできるようにしてほしい。
iOS12以下を切ってしまいたい誘惑が〜:fire::jack_o_lantern::fire:

---
Xcode 11 beta3を元に作成しています。
日付処理でCarbonを使う時の注意ポイント

PHPで日付処理を行うのに便利なCarbonですが、いくつか注意した点があるので共有。
### 1.加減算処理は元の変数に結果が入る。
(※これはハマらない人の方が多いかも・・。)
**例：2019/05/01から、5日後と10日後の日をそれぞれ算出する**

```php:間違ったプログラム
$dt = Carbon::parse('2019/05/01');
// 5日後
$after_5_day = $dt->addDay(5); // <- この処理で$dtが、2019/05/06になる。
echo($after_5_day->format('Y/m/d'). "\n");
// 10日後
$after_10_day = $dt->addDay(10); <- 2019/05/06の10日後になる。
echo($after_10_day->format('Y/m/d'). "\n");
```
結果
2019/05/06
2019/05/16

```php:正解プログラム
$dt = Carbon::parse('2019/05/01');
// 5日後
$after_5_day = $dt->addDay(5);
echo($after_5_day->format('Y/m/d'). "\n");

$dt2 = Carbon::parse('2019/05/01'); // <- 基準日を再定義する。
// 10日後
$after_10_day = $dt2->addDay(10);
echo($after_10_day->format('Y/m/d'). "\n");
```
結果
2019/05/06
2019/05/11

###2.Xヶ月後は、addMonthではなく、addMonthsNoOverflowを使う。
**例：2019/01/01から1ヶ月後の2019/02/01を出したい**

```php
$dt = Carbon::parse('2019/01/01')->addMonth(1);
echo($dt->format('Y/m/d'). "\n");
```
結果
2019/02/01
この場合は、addMonthでOK。

**例：2019/01/31から1ヶ月後の2019/02/28を出したい**
1月末日から、2月末日を算出する時

```php
$dt = Carbon::parse('2019/01/31')->addMonth(1);
echo($dt->format('Y/m/d'). "\n");
```
結果
2019/03/03
addMonthだと、2019/02/29〜31までの値がないので、31日と28の差分で03/03となる。
上記の場合は、addMonthsNoOverflowを使う。

```php
$dt = Carbon::parse('2019/01/31')->addMonthsNoOverflow(1);
echo($dt->format('Y/m/d'). "\n");
```
結果
2019/02/28
subMonthも同様に、subMonthsNoOverflowを使う。

###3.日数の差分は、dと、daysを使い分ける。
**例：2019/04/05と、2019/05/10の差分を算出**

```php
$diff = Carbon::parse('2019/04/05')->diff(Carbon::parse('2019/05/10'));
echo($diff->d. "\n");    // 日数のみの差分
echo($diff->days. "\n"); // 年月を含めた差分
```
結果
5
35
よく使うGitコマンド一覧

個人的に覚えておいた方が良い、よく使うGitコマンドを記載してます。


```$ git add ファイル名```
ファイル名を指定して対象ファイルをステージングエリアに追加。

```$ git add *. ファイル形式```
指定した形式のファイルだけをステージングエリアに追加。

```$ git add -A```
git管理下にあるディレクトリの全ての「追加、変更、削除」をステージングエリアに追加。

```$ git status```
ローカルリポジトリ内のgitの対象ファイルのステータスを表示する。

```$ git status --short -branch```
表示結果を短縮して結果の一番上にbranch名を表示できる。

```$ git commit```
変更したファイルをすべてコミットする。

```$ git commit -m "コミットメッセージ"```
メッセージをつけてコミットする。

```$ git diff```
インデックスとワーキングツリーの差分を表示する。

```$ git diff -name-only```
差分があるファイルの名前だけを表示する。

```$ git diff -cached```
git addした内容と最新のコミットとの差分を表示する。

```$ git diff --word-diff```
文字レベルで差分を表示する。

```$ git push リモートリポジトリのパス ローカルのブランチ名 :リモートのブランチ名```
ローカルリポジトリの内容をリモートリポジトリにpushする。

```$ git push -f origin master```
コンフリクトが発生する場合でも強制的にプッシュを行い、
リモートリポジトリの内容を上書きする。

```$ git push --force-with-lease origin master```
ローカルの履歴がリモートよりも新しい時だけpushを行う。

```$ git push origin --delete ブランチ名```
指定したブランチを削除する。

```$ git push --all origin```
全てのブランチをpushする。

```$ git push --tags origin```
全てのタグをpushする。

```$ git clone クローンしたいリポジトリのアドレス```
指定したリポジトリを現在のディレクトリの直下に複製する。

```$ git clone クローンしたいリポジトリのアドレス　ディレクトリ```
現在いるディレクトリ内のディレクトリを指定してリポジトリをクローンする。
指定したディレクトリが存在しない場合は、
指定した名前のディレクトリを作成してリポジトリをクローンする。

```$ git clone -b ブランチ名 --single-branch リモートディレクトリ名```
リモートの特定のブランチを指定してクローンする。

```$ git fetch --all```
設定されているすべてのリモートから全履歴を取得する。

```$ git merge ブランチ名```
指定したブランチを現在のブランチにマージする。

```$ git merge --about```
コンフリクトが発生し、まだコミットが行われていない状態でマージを中止し、
git merge実行前の状態に戻します。

```$ git merge --continue```
コンフリクトが発生し、コードを編集して競合を解決した後にマージを完了するように指示する。

```$ git pull origin master```
リモートリポジトリのorigin masterから内容を取り込んで、ローカルの
masterブランチにマージを行う。

```$ git log```
過去のコミットログを表示する。

```$ git log ファイル名```
特定のファイルのログのみを表示する。

```$ git log ブランチ名```
特定のブランチのログを表示する。

```$ git log --numstat```
ファイル毎の削除、追加行数を表示する。

```$ git log --oneline```
ログを1行で表示する

```$ git log -3```
最新のログを任意の件数を指定して表示する（上記の場合は最新のコミット数を3表示する）

```$ git branch```
ローカルブランチの一覧を表示。

```$ git branch -a```
登録されているリモートブランチを含むすべてのブランチを表示する。

```$ git branch ブランチ名```
ブランチを新規作成する。

```$ git branch -d ブランチ名```
指定したブランチを削除する。

糸冬
MNCTF2019 情報漏洩Ⅱ

#問題

http://mnctf.info/mnctf2019/tasks.php

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/e8508751-5d62-d23b-5d63-fb5df3acdf54.png)

#解いてみた

前回の問題でbatファイルがどのような動きをするかはなんとなくわかりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/f1e9dc16-4e57-4576-fb2d-080cd3da4357.png)

見た感じ7行目がデコード失敗している感があります。
「%USERDOMAIN%」っていう変数を使用しているので、%がちょっとずれてしまってるんだと思います。

が、そこはあまり問題ではなくてほかの処理を簡単に見ると外部のIPアドレスにftp接続して、情報を取得する処理のようです。
これはそのまま実行させた方がラクそう。

すると実行した瞬間にcmdごと落ちてしまいました。
何が起きたのかよくわからないので、1行ずつpauseを入れて動かしてみます。
あと2行目の@echo offはいらないので消しておきます。

if文のところで落ちてしまっているようです。
先頭にechoを書いてif文の内容を表示させてみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/6a3d44fb-d2b5-cce2-3ed0-94d19853212c.png)

実行させてみると

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/6014a6c0-96f1-58c9-f3d5-18703ee5c1f6.png)

という感じになりました。マスクしている部分はこのPCのPC名です。
PC名の前後にAが入る仕組みになっているのでPC名がMACNIKIでない場合はここでcmdを終了するようになっているようです。

ということでこのif文はここでは必要ないので削除して、再度実行してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/af8e5fdd-ade0-cb16-4f56-8e98d1788e70.png)

んーftpで接続できてxlsを取得しようとしていますが、ファイルがないようです。。。
dirしてみます。lsでしたっけ？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/699e0eb3-a505-ee50-e9e0-5d442f58d53f.png)

ログインには成功しているんですが、中でコマンド打つのはできないみたいです。
ファイアウォールの設定っぽいですよね。
と思ってファイアウォールを変えてみたんですが、結果は変わらず。
ルータのせいでしょうか？

やむなくFTPソフトを入れます。
なつかしのFFFTP！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/7cf4fe53-392d-c612-26fc-390c9c9e68b9.png)

すばらしい。
下のExcelファイルをダウンロードして開きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/1aaf9446-6075-1105-859b-2164af5c4a3c.png)

タイトルありました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/82ceff18-864c-9174-1112-e33f39f34c6d.png)
Django Girls Tutorialを復習する（１０）〜アプリケーションを拡張しよう〜

注意事項はこちら。
https://qiita.com/K-Kazutaka/items/1a432bda4f723e6757d6
写経用の記事です。



```blog/templates/blog/post_list.html
{% extends 'blog/base.html' %}

{% block content %}
    {% for post in posts %}
        <div class="post">
            <div class="date">
                <p>published: {{ post.published_date }}</p>
            </div>
            <h1><a href="{% url 'post_detail' pk=post.pk %}">{{ post.title }}</a></h1>
            <p>{{ post.text|linebreaksbr }}</p>
        </div>
    {% endfor %}
{% endblock %}
```

```blog/urls.py
from django.urls import path
from . import views

urlpatterns = [
    path('', views.post_list, name='post_list'),
    path('post/<int:pk>/', views.post_detail, name='post_detail'),
]
```

```blog/views.py
from django.shortcuts import render
from django.utils import timezone
from .models import Post
from django.shortcuts import render, get_object_or_404

def post_list(request):
    posts = Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
    return render(request, 'blog/post_list.html', {'posts': posts})

def post_detail(request, pk):
    post = get_object_or_404(Post, pk=pk)
    return render(request, 'blog/post_detail.html', {'post': post})
```

`blog/templates/blogにpost_detail.htmlというファイルを作成`

```blog/templates/blog/post_detail.html
{% extends 'blog/base.html' %}

{% block content %}
    <div class="post">
        {% if post.published_date %}
            <div class="date">
                {{ post.published_date }}
            </div>
        {% endif %}
        <h1>{{ post.title }}</h1>
        <p>{{ post.text|linebreaksbr }}</p>
    </div>
{% endblock %}
```
sikuliXで資料の印刷自動化（１）

# やったこと
sikuliXをつかって、試しに印刷時の設定も含め、パワポ資料の印刷自動化をした。今回は、とりあえずあるフォルダ内の資料一つで実施。今後はフォルダ内の資料全部印刷する機能を加える。それと、各資料の印刷設定をCSVにいれて、これを読みこんで設定を変えるようにする。

※会社も自分自身もIT系の業種ではなく、仕事で大量の資料を印刷することがあります。。。（そんな業界のやつがそもそもQiitaに書くなと言われそうですが。。。）

```python
# coding: utf-8
import subprocess
Settings.MoveMouseDelay = 0

#パワポを開く。
PPTX = r"C:\Users\name\Desktop\test\日本語含むファイル名.pptx"
subprocess.Popen(['start', PPTX], shell=True)

#パワポの「ファイル」→「印刷」
click("1562409686954.png")
click("1562409808100.png")
click("1562409905812.png")

#基本　タブ
click("1562410293616.png")
type(Key.DOWN)
type(Key.ENTER)

#トレイ/排出　タブ
click("1562410852793.png")
click("1562410959517.png")

type(Key.DOWN)
type(Key.DOWN)
type(Key.ENTER)

#ENTERで印刷のプロパティ終了
type(Key.ENTER)

#部数入力
paste("1562411539093.png","2")

#印刷実行
click("1562411164932.png")
```
![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/250449/900c39df-c12f-488d-5830-051511eb2942.png)

#参考
ありがとうございます。
https://tonari-it.com/python-popen-start-folder/

#日本語を含むパスの開き方

日本語を含むパスのファイルを開くのに苦労した。パスに日本語を含まなければ↓のような感じで開けた。しかし、このやり方で日本語を含むパスを入れるとどうしてもエラーが出てしまった。u"C:\~~"とやってもできなかった。

```python
app = App.open(r'"C:\Program Files (x86)\Microsoft Office\Office15\WINWORD.EXE" "c:\folder1\test.doc"')
```
https://stackoverflow.com/questions/39076967/cant-open-word-file-with-space
S3にPutObjectするPythonプログラムをFargateに乗せるまでの道のり

簡単なPythonプログラムをFargateで実行するまでの道のりです。

```python:app.py
import os

import boto3

bucket = os.getenv('BUCKET_NAME', '')
key = 'HelloWorld.txt'
body = 'Hello, World!'

s3 = boto3.client('s3')
s3.put_object(Bucket=bucket, Key=key, Body=body)
```

環境変数で渡したバケットに固定文字列のファイルを出力するだけです。

試した環境は

1. Windows環境で実行
1. Docker環境で実行
1. Fargate環境で実行（1回だけ実行）
1. Fargate環境で実行（定期実行）

---
7/7 更新
S3エンドポイントは不要でしたので記述を削除しました。

---

# Windows環境で実行

## 環境

* Windows 10
* Python 3.6

## Python仮想環境の作成

```console
python -m venv .venv
.venv\Scripts\activate
```

## ライブラリーの取得

```console
pip install boto3 awscli
```

## AWS CLIの設定(認証情報の設定)

```console
aws configure
AWS Access Key ID [None]: [アクセスキー]
AWS Secret Access Key [None]: [シークレットアクセスキー]
Default region name [None]: [ap-northeast-1などのリージョン]
Default output format [None]:
```

## バケット名の指定（環境変数）

バケット名は環境変数から取得するようにしたので、環境変数にバケット名をセットします

```console
set BUCKET_NAME=[バケット名]
```

## 実行！

```console
python -m app
```

無事、S3にファイルが出力されました。

# Docker環境で実行

## ファイルの用意

`requirements.txt`と`Dockerfile`を用意し、`app.py`と同じフォルダーに格納します。

```text:requirements.txt
boto3==1.9.183
```

```dockerfile:Dockerfile
FROM python:alpine

WORKDIR /app
ADD . /app

RUN python3 -m pip install -r requirements.txt
CMD ["python3", "-m", "app"]
```

## Dockerイメージのビルド

```console
docker build -t [Dockerイメージのタグ名] .
```

## 実行！！

コンテナ内にはAWSの認証情報がないので、環境変数で渡します。バケット名も同様です。

```console
docker run -e AWS_ACCESS_KEY_ID=[アクセスキー] -e AWS_SECRET_ACCESS_KEY=[シークレットアクセスキー] -e BUCKET_NAME=[バケット名] [Dockerイメージのタグ名]
```

無事、S3にファイルが出力されました。

# Fargate環境で実行の準備

## 準備１：ECRへの登録

Fargateで実行するため、DockerイメージをECR(Elastic Container Registry)に登録します。

### リポジトリの作成

```console
aws ecr create-repository --repository-name [リポジトリ名]
```

### docker loginコマンドの取得と実行

```console
aws ecr get-login --no-include-email
```

コンソールに出力されるコマンドを実行します。

### リモートリポジトリに登録するローカルDockerイメージを指定する

```console
docker image tag [ローカルのDockerイメージのタグ名] [リポジトリ名]:[リモートのDockerイメージ名]
```

### Dockerイメージをリポジトリにプッシュする

```console
docker image push [リポジトリ名]:[リモートのDockerイメージ名]
```

## 準備２：ECSのクラスターの作成

マネジメントコンソールでECSの画面を表示。クラスターを作成する。

| 設定項目 | 設定内容 |
|---|---|
|クラスターテンプレートの選択|ネットワーキングのみ|
|クラスターの設定|このクラスター用の新しいVPCを作る| 

## 準備３：ECSのタスク定義の作成

マネジメントコンソールでECSの画面を表示。タスク定義を作成する。

| 設定項目 | 設定内容 |
|---|---|
|起動タイプの互換性の選択|FARGATE|
|タスクとコンテナの定義の設定|↓↓↓|
|タスク実行ロール|`AmazonECSTaskExecutionRolePolicy`の他にS3へのPutObject権限も必要|
|コンテナの定義|↓↓↓|
|イメージ|ECRのイメージ URI(マネジメントコンソールで確認する）|
|環境変数|`BUCKET_NAME`にバケット名を指定|


# Fargate環境で実行（1回だけ実行）

`タスク定義`から作成したものを選び、`アクション`の`タスクの実行`を行います。

| 設定項目 | 設定内容 |
|---|---|
|起動タイプ|FARGATE|
|クラスター|作成したもの|
|タスクの数|1|
|VPC|作成したもの|

## 実行！！！

ウィザードの最後の`タスクの実行`を押すと、実行されます。

# Fargate環境で実行（定期実行）

`クラスター`から作成したものを選び、画面下のタブにある`タスクのスケジューリング`の先の`作成`を選びます。

| 設定項目 | 設定内容 |
|---|---|
|スケジュールルールタイプ|お好みで|
|起動タイプ|FARGATE|
|タスク定義|作成したもの|
|タスクの数|1|
|クラスター VPC|作成したもの|

## 実行！！！！

ウィザードの最後の`作成`を押すと、指定したスケジュールに従って実行されます。
`固定された間隔で実行`の場合、初回起動は`作成`を押してから`固定された間隔`が経過したあとになるようです。

# まとめ

後半がかなり手抜きになりましたが、一応Fargateで動作するところまでできました。

# 参考サイト

[AWS ECS/Fargate 操作覚え書き](https://qiita.com/asato-san/items/a4bd69a6cd30f795201c)
Django Girls Tutorialを復習する（９）〜テンプレートを拡張しよう〜

注意事項はこちら。
https://qiita.com/K-Kazutaka/items/1a432bda4f723e6757d6
写経用の記事です。


blog/templates/blog/以下にbase.htmlファイルを作成する

```base.html
{% load static %}
<html>
    <head>
        <title>Django Girls blog</title>
        <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
        <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css">
        <link href='//fonts.googleapis.com/css?family=Lobster&subset=latin,latin-ext' rel='stylesheet' type='text/css'>
        <link rel="stylesheet" href="{% static 'css/blog.css' %}">
    </head>
    <body>
    <div class="page-header">
        <h1><a href="/">Django Girls Blog</a></h1>
    </div>
    <div class="content container">
        <div class="row">
            <div class="col-md-8">
            {% block content %}
            {% endblock %}
            </div>
        </div>
    </div>
    </body>
</html>
```

```post_list.html
{% extends 'blog/base.html' %}

{% block content %}
    {% for post in posts %}
        <div class="post">
            <div class="date">
                <p>published: {{ post.published_date }}</p>
            </div>
            <h1><a href="">{{ post.title }}</a></h1>
            <p>{{ post.text|linebreaksbr }}</p>
        </div>
    {% endfor %}
{% endblock %}
```
Chromeでスクリーンショットを取る方法が便利

## Chromeでスクリーンショットを取る方法が便利
この方法は、Chromeデベロッパーツールで画面サイズをスマホやタブレット状態にした時に、そのサイズで正確にスクリーンショットを撮れる方法です。
まずはChromeのデベロッパーコンソールを開いて、shift + command + Pを押します。
そして出てきたプロンプトに`screenshot`と入力します。
<img width="566" alt="Screen Shot 2019-07-06 at 23.26.40.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/250231/bd993654-a544-600c-06ca-9a99dc030b44.png">
そして一番下の`Capture screenshot`を選択することでスクリーンショットを取ることができます。

便利ですので、ぜひ試してみてください。
この記事が参考になれば幸いです。
## 終わりに
私は現在、Web3のサービスの開発をしています。詳しくはこちらの記事をご覧下さい。
        [無料でイーサリアムが当たる、Web3時代の寄付サイトを作った話](https://note.com/kenroda/n/n814347fbdcd7)
PySparkでGraphFramesのGraphFrameオブジェクトが作れない

## 環境
- OS Ubuntu 18.04
- Java

```terminal:terminal
$ java -version
openjdk version "1.8.0_212"
OpenJDK Runtime Environment (build 1.8.0_212-8u212-b03-0ubuntu1.18.04.1-b03)
OpenJDK 64-Bit Server VM (build 25.212-b03, mixed mode)
```
- 必要に応じて環境変数JAVA_HOMEやPYSPARK_PYTHONなどを正しく設定してください

## 生じた事象
```python:python
from graphframes import GraphFrame
nodes = #nodeを定義
edges = #edgeを定義
GraphFrame(nodes, edges)
```
このコードを走らせようとした際にGraphFrameのコンストラクタ内で以下のようなエラーを吐く.

```terminal:terminal
...
py4j.protocol.Py4JJavaError: An error occurred while calling o55.loadClass.
: java.lang.ClassNotFoundException: org.graphframes.GraphFramePythonAPI
    at ...
```

graphframesのjarライブラリが読み込めてないことに起因するのでこれを入れてあげれば解決します.

## 対応策
### 読み込み先の特定
`$SPARK_HOME/jars`が存在するならそこでOKです.
`$SPARK_HOME`が設定されていない場合,まずpysparkのあるディレクトリを特定します.
pipをお使いの方は`pip show pyspark`でLocationの欄を見ればOK.
あるいは次のようにして確認できます.

```python:python
import pyspark
print(pyspark.__path__)
# ['/usr/local/lib/python3.6/dist-packages/pyspark'] のような形式で返ってくる
```
特定が完了したらその`pyspark/jars`が読み込み先のディレクトリです.


###jarのダウンロード
[このサイト](https://spark-packages.org/package/graphframes/graphframes)からお手持ちのversionに対応したjarをダウンロードして先ほど特定したディレクトリの中に入れれば完了です.

何か正攻法が存在するなら教えていただければ幸いです.

## 参考サイト
https://stackoverflow.com/questions/39261370/unable-to-run-a-basic-graphframes-example
https://markhneedham.com/blog/2019/04/17/pyspark-class-not-found-exception-org-graphframes-graphframepythonapi/
Django Girls Tutorialを復習する（８）　〜CSSでカワイくしよう!〜

注意事項はこちら。
https://qiita.com/K-Kazutaka/items/1a432bda4f723e6757d6
写経用の記事です。


'blogアプリの中に staticというフォルダを作成する。
そのフォルダの中に、cssというフォルダを作成する。
そのフォルダの中に、blog.cssというファイルを作成する。'

djangogirls
└─── blog
     └─── static
          └─── css
               └─── blog.css


```blog.css
h1 a {
    color: #FCA205;
    font-family: 'Lobster';
}
body {
    padding-left: 15px;
}

.page-header {
    background-color: #ff9400;
    margin-top: 0;
    padding: 20px 20px 20px 40px;
}

.page-header h1, .page-header h1 a, .page-header h1 a:visited, .page-header h1 a:active {
    color: #ffffff;
    font-size: 36pt;
    text-decoration: none;
}

.content {
    margin-left: 40px;
}

h1, h2, h3, h4 {
    font-family: 'Lobster', cursive;
}

.date {
    color: #828282;
}

.save {
    float: right;
}

.post-form textarea, .post-form input {
    width: 100%;
}

.top-menu, .top-menu:hover, .top-menu:visited {
    color: #ffffff;
    float: right;
    font-size: 26pt;
    margin-right: 20px;
}

.post {
    margin-bottom: 70px;
}

.post h1 a, .post h1 a:visited {
    color: #000000;
}
```

```post_list.html
{% load static %}
<html>
    <head>
        <title>Django Girls blog</title>
        <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
        <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css">
        <link rel="stylesheet" href="{% static 'css/blog.css' %}">
        <link href="//fonts.googleapis.com/css?family=Lobster&subset=latin,latin-ext" rel="stylesheet" type="text/css">
    </head>
    <body>
        <div class="page-header">
            <h1><a href="/">Django Girls Blog</a></h1>
        </div>
        <div>

        <div class="content container">
    <div class="row">
        <div class="col-md-8">
            {% for post in posts %}
                <div class="post">
                    <div class="date">
                        <p>published: {{ post.published_date }}</p>
                    </div>
                    <h1><a href="">{{ post.title }}</a></h1>
                    <p>{{ post.text|linebreaksbr }}</p>
                </div>
            {% endfor %}
        </div>
    </div>
</div>   
    </body>
</html>
```
【Github】Github Pagesで独自ドメインの自分のWebページを10分で作る

#概要
Github Pagesを使って独自ドメインのWebページを10分で作る方法

最速でHPを公開したくなったので作った

#手順
1. Github PagesでWebサイトを作る
2. お名前.comでDNSの設定をする
3. Github Pagesの設定を変更する
4. 寝て待つ

##1. Github PagesでWebサイトを作る
新規リポジトリを作成して設定からGithub Pagesを有効にする
<img width="737" alt="スクリーンショット 2019-07-06 22.57.44.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390000/f6c9a808-723e-edc6-bc59-ca4f89f5e1b2.png">

適当にREADME.mdの中身を書いてコミット

以下のURLを適宜変更してアクセスすれば自分のWebページが確認できる

https://YOUR-USER-NAME.github.io/REPOSITORY

##2. お名前.comでDNSの設定をする
独自ドメインをお名前.comで取得後に、以下のページでDNSの設定を変更する
<img width="920" alt="スクリーンショット 2019-07-06 21.29.42.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390000/d00eb77e-3b12-4b47-0767-b04576d00361.png">

以下のように自分のGithubのサーバーと独自ドメインをリンクさせる
<img width="663" alt="スクリーンショット 2019-07-06 21.34.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390000/15bb1fe8-2087-4fd2-5212-b16cd799bd09.png">

##3. Github Pagesの設定を変更する
Githubの設定を再度開いて独自ドメインを設定する
<img width="736" alt="スクリーンショット 2019-07-06 23.09.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390000/ba70e0e8-4146-fa16-4831-6edcd164028f.png">

##4. 寝て待つ
しばらく待ってから独自ドメインにアクセスするとGithub Pagesの自分のWebページに飛べる

#Happy Hacking :sunglasses: !

#参考
https://pages.github.com/

https://help.github.com/en/articles/quick-start-setting-up-a-custom-domain