OmniAICreator/Qiita-1.07M huggingface dataset:
対応ブラウザをIEからChromeに変更する時の注意点その３(アドレスバーの非表示)

# 対応ブラウザをIEからChromeに変更する時の注意点その３(アドレスバーの非表示)

対応ブラウザをIEからChromeに変更する時の注意点について備忘録的に記載します。

# 発生問題点
IE表示時はアドレスバーを非表示としていたが（＊１）、Chromeではアドレスバーが表示されてしまう。

＊１：window.open()のオプションlocation=noで指定していた


# 環境
* <font color="Green">__OSはWindows10__</font>
	* バージョン：1803(OSビルド17134.407)

* <font color="Green">__Microsoft Internet Explorer__</font>
	* バージョン：11.407.17134.0
	* 更新バージョン：11.0.95(BK4466536)

* <font color="Green">__Google Chrome__</font>
	* バージョン：76.0.3809.100(Official Build) (64ビット)


# 解決方法
アプリケーションモードでChromeを起動する

```
Chrome.exe --app="対象URL"
```

のようにしてChrome.exeのパラメータに『--app=』を指定してアプリケーションモードで起動する。

この方法を試したところ、アドレスバーは非表示になったが、なぜかウィンドウのサイズが
小さくなることがあり、それにより表示が崩れることがあるためウィンドウサイズの調整が
必要となることがあった。

参考URL
https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q11198959366


# 補足
他の解決方法として対象URLのショートカットを作成してアプリ化する方法もあるが、
タイトルがショートカット作成時の名前になってしまう等あったため不採用とした。

参考URL
https://www.softantenna.com/wp/tips/chrome-app-mode/
git checkoutについて

#結論

リモート追跡ブランチに移動するコマンドは、<b>'git checkout origin/ブランチ名'</b>
ローカルの作業ブランチに移動するコマンドは、<b>'git checkout ブランチ名'</b>
######リモート追跡ブランチはローカルのブランチである。
※リモート追跡ブランチ＝トラッキングブランチ

#経緯

リモートブランチにcheckoutする際、originとブランチ名の間に<b>'/'</b>が必要か迷う事があった。

git checkoutするコマンドは<b>'/'</b>が必要で、git pushするコマンドは<b>'/'</b>が必要ない。


```
git checkout origin/ブランチ名
git push origin ブランチ名
```
####この'/'の有無はどういう意味？



#疑問
①<b>git checkout origin ブランチ名</b>だとリモートブランチにcheckoutできないの？
②<b>git push origin/ブランチ名</b>だとリモートブランチにpushできないの？
③<b>origin/</b>と<b>ブランチ名</b>がくっついているのに<b>origin/ブランチ名</b>を１つのブランチ名として認識されないの？

この疑問を解決するため、検証を実施します。

#検証

###①<b>'git checkout origin ブランチ名'</b>でcheckoutできるのか


develop/#2の状態から<b>git checkout origin develop/#1</b>を実行

```
masahiro@MacBook-Air project % git branch
  develop/#1
* develop/#2
  master
masahiro@MacBook-Air project % git checkout origin develop/#1
error: pathspec 'origin' did not match any file(s) known to git
error: pathspec 'develop/#1' did not match any file(s) known to git
```
→エラー発生


翻訳すると、
エラー：pathspec'origin'がgitで認識されているファイルと一致しませんでした
エラー：pathspec'develop/#1'はgitに認識されているどのファイルとも一致しませんでした

###②<b>'git push origin/ブランチ名'</b>でpushできるのか

develop/#1の状態から<b>'git push origin/develop/#1'</b>を実行

```
masahiro@MacBook-Air project % git branch
* develop/#1
  develop/#2
  master
masahiro@MacBook-Air project % git push origin/develop/#1
fatal: 'origin/develop/#1' does not appear to be a git repository
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
```
→エラー発生

翻訳すると、
致命的：'origin/develop/#1'はgitリポジトリではないようです
致命的：リモートリポジトリから読み取ることができませんでした

正しいアクセス権があることを確認してください
リポジトリが存在します。

####検証結果：①、②ともにエラーが発生し実行できませんでした。

#考察
①のエラーでは<b>'origin'</b>と<b>'develop/＃1'</b>がgitにありませんと認識している。
→疑問③の<b>'origin/ブランチ名'</b>を１つのブランチ名として認識されているのでは？

②のエラーでは<b>'origin/develop#1'</b>はリモートリポジトリから読み取れませんでした。
→リモートに存在しないということ？

まだ納得できないので納得できる記事を探しました。


#調査結果

下記の記事により納得することができました。

・git checkoutについて→https://www-creators.com/archives/1388#git_checkout
・git fetch,marge,pullについて→https://qiita.com/wann/items/688bc17460a457104d7d
・トラッキングブランチについて→https://yu8mada.com/2018/08/11/how-to-confirm-and-set-up-tracking-branches-in-git/#content-1

#まとめ

git の仕様上、作業ブランチをリモートブランチに切り替えて直接更新することはできない。
<b>'origin/ブランチ名'</b>はリモートブランチではなくリモート追跡ブランチであり、
リモート追跡ブランチ（トラッキングブランチ）はローカルブランチであることが分かりました。

git初心者の私は、<b>'git checkout origin/ブランチ名'</b>でリモートブランチに移動していると思っていたが、
リモートブランチではなく、実際はローカルに存在するリモート追跡ブランチでした。

この違いを知っていれば、コマンド実行時に'/'で悩まされなくて済むと思います。
そして今回、トラッキングブランチの存在ついても知る事ができました。
ここの知識も深めていく必要があると感じました。
メールが重複して送信される

メールが重複して送信される場合の対応
メール作成の状況によって確認方法が異なるようです。


#ワークフローの場合

 I set up a Workflow Action for email alert instead of field update and it was sending me the emails twice because I also had an email alert set up already as a workflow. 
フィールド更新の代わりに電子メールアラートのワークフローアクションを設定しましたが、ワークフローとしてすでに電子メールアラートが設定されていたため、電子メールが2回送信されていました。

https://trailblazers.salesforce.com/answers?id=9063A000000iRWtQAM


#取引先責任者への重複

重複したメールが連絡先/受信トレイに送信されるのはなぜですか？
https://help.salesforce.com/articleView?id=000325835&type=1&mode=1

#承認プロセスでも重複

承認プロセス：承認割り当てメールが 2 回送信される
https://help.salesforce.com/articleView?id=000332237&type=1&mode=1

#プロセスビルダーの場合
 Ensure that your process builder should not go to recursion
Ruby on Railsのconfig設定

この記事ではRails6.1のconfig設定をメモしています。

##config/application.rb

タイムゾーンをローカルに設定する

```ruby
config.time_zone = 'Tokyo'
config.active_record.default_timezone = :local
```

##config/puma.rb

developmentではlocalhost:3000、productionではunix socketを使用する

```ruby
if ENV.fetch("RAILS_ENV", "development") == 'production'
  bind "unix://#{Rails.root}/tmp/sockets/puma.sock"
else
  port ENV.fetch("PORT") { 3000 }
end
```

##config/environments/production.rb

キャッシュにredisを使用する

```ruby
  cache_servers = %w(redis://localhost:6379/1)
  config.cache_store = :redis_cache_store, {
    url: cache_servers,
    connect_timeout: 30,
    read_timeout: 0.5,
    write_timeout: 0.5,
    reconnect_attemps: 1,
    error_handler: -> (method:, returning:, exception:){
      Rails.logger.warn "exception: #{exception}, method: #{method}, returning: #{returning}"
    }
  }
```

セッションにredisを使用する

```ruby
  config.session_store :redis_store,
    servers: [{
      host: 'localhost',
      port: 6379,
      db: 0,
      namespace: 'sessions',
    }],
    key: "_session_name_",
    expire_after: 30.minutes
```

Railsでredisを使用するためGemfileにgemを追加する

```ruby:Gemfile
gem 'redis-rails'
```

##config/webpacker.yml

webpackを使用している場合はhtmlの変更も検知できるようにする？
ここの設定は検討が必要

```yaml
extensions:
...
  - .html
...
```
Anacondaを使わないpython環境構築

## Anacondaを使わないpython環境構築(jupyterlab(notebook)簡単起動付き)
・環境
-Windows10
### ----------↓手順↓-----------
#### 1.pythonをインストール

↓以下の記事最強↓
https://watlab-blog.com/2019/04/06/python-install/
Anacondaを使わない理由とかも述べてあります(商用利用禁止以外の理由)
インストールの際、「PATHを通す」にチェックボックスをつけるタイミングがあるので
つけてください

これでpythonインストールはできたかと。

## ！ここで確認！
「PATHを通す」にチェックをちゃんとしたか？
なんのこと？ってなったら、前に戻ってもう一度確認

次から、jupyter notebook や labをどう立ち上げていくかを述べます(やり方は何通りもあるはず)

#### 2.コマンドプロンプトの起動
起動のショートカット　→　［Windows］＋［R］キー　→　cmd  と入力しEnter


#### 3.必要モジュール等のインストール

とりあえず、jupyter lab と　juypter notebook

```python:jupyterlab
pip install jupyterlab
```

```python:jupyter-notebook
pip install jupyter notebook
```

#### 4.juyter Lab(notebook)の起動

```python:jupyterlab
jupyter lab
```

```python:jupyter-notebook
jupyter notebook
```

#### 5.BATファイルで簡単起動
Desktopに(場所はどこでもいいです)
新規作成でテキストファイルを作成します

ファイルの中に、Labであれば
jupyter Lab
とだけ入力して保存
(notebook なら jupyter notebook)

そしたら、拡張子をtxt→batに変更
そうすると、アイコンが変わり正常に変更できた事になります

そのBATファイルを開くだけで起動できるようになります

以上
Next.jsでSSRを簡単にするには  其の壱「旅立ち」

# Next.jsでSSRを簡単にするには  其の壱「旅立ち」

[こちら](https://ttis.croud.jp/?uuid=cde84249-0f46-44b5-9289-880bd074a3ea)に同じ内容を書いています

## 1. Next.jsでのSSRはApolloが優秀

　検索Botの性能が微妙な頃、SPAのWebシステムではSSRが重要な位置を占めていました。みんな必死にSSRを行うための取り組みを行いました。しかしクライアントで動くべき物をサーバで実行し、その結果を返すというのは、それなりの無理が生じます。無理を通しているが故に、開発コストに跳ね返ってしまうのです。

　コストを抑えつつSSRを導入しようとした場合、GraphQLとApollo導入が無難な流れとなります。Apolloのキャッシュ機能を利用すれば、サーバ側で生成したデータを短いステップでクライアントに引き継ぐことが出来るからです。一回手続を書いておけば、その他の部分ではクライアントとサーバのコードを別々に書く必要はありません。

　ではGraphQLを使わなかった場合はどうでしょう？選択肢を調べてみましたが、Apolloのようにサーバ側で生成したキャッシュをまとめて引き渡すような便利なライブラリが見つかりませんでした。大抵の場合、地道に部分部分で引き渡しコードを書いている形です。


### 2. Next.js上でSSRをする時に使う物

- _app.tsx上でApp.getInitialProps
- 各Page上でgetInitialProps
- 各Page上でgetServerSideProps

　現時点で推奨されているのは**getServerSideProps**です。サーバでしか実行されず、その実行結果はクライアント側に送られます。ただこれ、デフォルトだとSPAのページ切り替えごとにサーバにデータを取りに行きます。一応、*shallow*パラメータを設定すれば再ロードを回避することは可能なのですが、propsには古いデータが残ってしまい、キャッシュの更新判定が面倒なことになります。ぶっちゃけて言うと、キャッシュのことを考えずに、とにかくデータが受け取れれば良いという場合にしか使い道がありません。

　各Page上でgetInitialPropsの方も、ページを作るごとに個別に受け渡し処理を作成するのも面倒です。

　やはり理想はApolloの**App.getInitialProps**を使ったキャッシュ引き渡しです。Next.jsでのビルド時に、「推奨していない**App.getInitialProps**をまだ使ってるの？**getServerSideProps**使いなよ」と文句を言われますが、まともな選択肢が他にないのです。

### 3. useSWRを試してみる

　とりあえず上手いやり方は無いかと使い勝手が良いと話題のuseSWRを試してみました。fetchのURLをキーにして、取得データをキャッシュすることが出来ます。しかも取得したキャッシュに自由にアクセスが可能です。これはと思ったのもつかの間、以下の問題により断念しました。

- useSWRは適度なタイミングでデータをとりにいく事が目的で、必要ないときはデータをとらないという機能が無い
- dedupingIntervalに大きな値を設定すれば一応データを取りに行かなくなるけど、とらないフラグ付けて
- タイミングが色々指定できるし便利だけど、今欲しいのはそれじゃない
- そして最も重要なポイント、cacheで自由にキャッシュを書き換えることは出来た、確かに出来た。しかしfetchの戻り値を個別管理していて、次のターンで復元される

　useSWRのソースを眺めてみた結果、cacheにはアクセスできるけど、データの流れ的にfetchの戻り値をがっちり持っていて、根本を書き換えないと理想的な動作にならないことが判明。

### 4. useSWRのような使い勝手でApolloみたいなことをするには

　**結論**「自分で作るしかない」

　ということで願いを叶えるため、自前のuseSWRのHooksの構造とApolloキャッシュ構築方法をパクり、オレオレuseFetchを作りはじめした

　現在の進行状況(基本的な実装は完了)
　天気予報を取得しSSRしつつキャッシュを保持のサンプル
　<https://github.com/SoraKumo001/use-fetch-sample01>


次回 *Next.jsでSSRを簡単にするには  其の弐「流浪」*
【Java】DateクラスのcompareToメソッドの使い方

#compareToメソッドとは？
Dateクラスの日にちを比較するメソッドで、メソッドの呼び出し元の日付と引数の日付を比較します。

以下のように、引数と呼び出し元を比較し、値を返します
>メソッドの呼び出し元の値が、引数と等しい場合は0
>メソッドの呼び出し元の値が、引数より前の場合は-1
>メソッドの呼び出し元の値が、引数より後の場合は1

#使い方

```java
        SimpleDateFormat sdf  = new SimpleDateFormat("yyyyMMdd");
		Date date1,date2;
        date1 = sdf.parse("20210117");
	    date2 = sdf.parse("20210118");

        System.out.println(date1.compareTo(date2)); // -1 ->date1はdate2より前である
        System.out.println(date2.compareTo(date1)); // 1　->date2はdate1より後である
```

#参照
[クラス Date #compareTo](https://docs.oracle.com/javase/jp/6/api/java/util/Date.html#compareTo(java.util.Date))
困っている方必見！offsetTopで高さが取得できない時の対処法

cssにてpositionを使っているときに、``top``や``left``などを％で指定していると、使っている機種によって％の値が変わってきます。

これは厄介。。。

こんな時に役立つのが、Javascriptを使ってページトップからの高さを取得してしまえば、機種によって%の値を変える必要はありません！

結論から言うと、``getBoundingClientRect()``、``pageYOffset``の２つの関数を使います。

それでは使い方を見ていきましょう！！

<font color="red">※注意</font color> 要素の高さは普通offsetTopで取得できます。ただ、親要素に``position:relative``が設定してあると取得できない場合があるので、今回はそのやり方でやっていきます。

#要素を取得#

```index.js
const topToElement = document.getElementsByClassName('class-name')[0]
```

また、``document.getElementId``などで取得してください

#ページトップからの高さを取得#

```index.js
const topToElement = document.getElementsByClassName('class-name')[0]
const topToElementHeight = topToElement.getBoundingClientRect().top + window.pageYOffset
console.log(topToElementHeight)
```

このようにして高さを取得することができます！

また、これらはVue.jsで使う場合、DOM要素と紐づけられた後の``mounted``で行ってください。

``created``では取得できないのでご了承ください。

以上、「ページトップからある要素までの高さの取得方法」でした！

良かったら、LGTM、コメントお願いします。

また、何か間違っていることがあればご指摘頂けると幸いです。

他にも初心者さん向けに記事を投稿しているので、時間があれば他の記事も見て下さい！！

Thank you for reading
【ダメ。ゼッタイ】脱法ブランチ名やプッシュ乱用を防いでgitを治安維持する

運用規則やgitのベストプラクティスを知っててもmaster直修正しちゃいたい誘惑ってありますよね。ギリギリ踏みとどまっても今度はブランチ命名タスクが来て、次にコミット命名です。このgit運用を手抜きしたい誘惑は凄まじく、依存性もあり一度やってしまうと、もう元の生活には戻れず手抜きが横行します。

そこで、CodeCommitならばIAM絞ってとても柔軟にgit運用の統制を設定でき、社内のgit治安が良くなるという話をします。

Git Flow, Github Flowをベースに少し手を加えた以下の制約を導入したいとします。`beta`はカナリアリリース用の社内独自ブランチです

- 作成できるブランチ名の制限。`master`, `beta`, `feature/*`, `hotfix`のみ。**自分の名前のブランチ名とかダメ絶対。**
- `master`, `beta`は直コミット禁止し、プルリクのみが更新できる。
- プルリクのマージはマージコミット残し必須。Fast-Fowardは不可

以下のポリシーを`HogeCorporationGitFlowPolicy`とでも命名して作成し、全開発者に適用するようアタッチします。元々のCodeCommitへの操作権限を有するユーザーを前提にしています。初めて`StringNotLike`を使いました。

```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Deny",
      "Action": [
        "codecommit:*"
      ],
      "Resource": "*",
      "Condition": {
        "StringNotLike": {
          "codecommit:References": [
            "refs/heads/master",
            "refs/heads/beta",
            "refs/heads/feature/*",
            "refs/heads/hotfix"
          ]
        },
        "Null": {
          "codecommit:References": false
        }
      }
    },
    {
      "Effect": "Deny",
      "Action": [
        "codecommit:GitPush",
        "codecommit:DeleteBranch",
        "codecommit:PutFile",
        "codecommit:CreateCommit",
        "codecommit:MergeBranchesByFastForward",
        "codecommit:MergeBranchesBySquash",
        "codecommit:MergeBranchesByThreeWay",
        "codecommit:MergePullRequestByFastForward",
        "codecommit:MergePullRequestBySquash"
      ],
      "Resource": "*",
      "Condition": {
        "StringEqualsIfExists": {
          "codecommit:References": [
            "refs/heads/master",
            "refs/heads/beta"
          ]
        },
        "Null": {
          "codecommit:References": false
        }
      }
    }
  ]
}
```

もう少し拘って以下も設定したかったのですが、よく分かりませんでした。導入できたら記事更新します。  （教えて優しい人）

- masterへのプルリクはfeature系から禁止して、betaかhotfixからのみ可
- commit名にも命名規則としてprefix必須＆ホワイトリスト作成
- セルフマージ禁止（PRと承認の同一人物禁止）

参考

- https://docs.aws.amazon.com/service-authorization/latest/reference/list_awscodecommit.html
- https://docs.aws.amazon.com/codecommit/latest/userguide/how-to-conditional-branch.html
- https://dev.classmethod.jp/articles/codecommit-deny-push-mster-branch/
- https://blog.serverworks.co.jp/tech/2020/04/17/codecommit-branch/
- https://qiita.com/potyamaaaa/items/08c54072e0d9d0734ccd
- https://qiita.com/itosho/items/9565c6ad2ffc24c09364
- https://qiita.com/mint__/items/bfc58589b5b1e0a1856a
- https://qiita.com/KosukeSone/items/514dd24828b485c69a05
不正な config/master.key が原因でRailsの起動に失敗するケースとその対処方法

## 発生する問題

git cloneでローカルに持ってきたRailsアプリを、`rails s`や`rails c`で起動しようとすると以下のようなエラーが発生する。

```
$ rails s
=> Booting Puma
=> Rails 6.1.0 application starting in development 
=> Run `bin/rails server --help` for more startup options
Exiting
/Users/jnito/.rbenv/versions/3.0.0/lib/ruby/gems/3.0.0/gems/activesupport-6.1.0/lib/active_support/message_encryptor.rb:203:in `rescue in _decrypt': ActiveSupport::MessageEncryptor::InvalidMessage (ActiveSupport::MessageEncryptor::InvalidMessage)
```

## エラーの原因

`config/master.key` の鍵が `config/credentials.yml.enc` 用の鍵と一致していないため、例外が発生してRailsが起動しなくなった。

### もう少し詳しく

`config/master.key`は通常、`.gitignore`に追加してソースコード管理の対象外とするファイルである。そのため、git cloneしても`config/master.key`はローカルにはコピーされない。

その状態で「`credentials.yml.enc`を編集したい」と思って`EDITOR="vi" bin/rails credentials:edit`のようなコマンドを実行すると、以下のようなメッセージとともに、`config/master.key`が新規に作成されてしまう。（加えて、`credentials.yml.enc`の編集もできない）

```
$ EDITOR="vi" bin/rails credentials:edit
Adding config/master.key to store the encryption key: 6eb4ad(以下略)

Save this in a password manager your team can access.

If you lose the key, no one, including you, can access anything encrypted with it.

      create  config/master.key

Couldn't decrypt config/credentials.yml.enc. Perhaps you passed the wrong key?
```

ただし、新規に作られた`config/master.key`はgit cloneしてきた`config/credentials.yml.enc`の鍵ではないため、Rails起動時に復号化に失敗して例外（ActiveSupport::MessageEncryptor::InvalidMessage）が発生してしまう。

## 対処方法

状況によって対処方法は異なる。

### git cloneする前にcredentials.yml.encが使われていた場合

開発チーム内で鍵の共有方法が決められているはずなので、その運用ルールに従って適切な`config/master.key`を自分のローカルに配置する。

### credentials.yml.encが今まで使われていなかった場合

自動的に作られた`config/master.key`を削除すればRailsが起動するようになる。

今後も`credentials.yml.enc`を使わないのであれば、`config/credentials.yml.enc`ごと削除するのも一手。

逆に、これから`credentials.yml.enc`を使っていく（＝自分がチーム内で最初の利用者になる）場合は、新規に`config/credentials.yml.enc`を作り直した上で`credentials/master.key`をチーム内で適切に管理・共有する必要がある。
（ただし、どこかから適切な`config/master.key`を入手できれば新規に作り直す必要はない）

```
# 既存のcredentials.yml.encを削除
$ rm config/credentials.yml.enc

# credentials.yml.encとmaster.keyを新規に作成して編集する
$ EDITOR="vi" bin/rails credentials:edit
Adding config/master.key to store the encryption key: 917c31e316061bcdd909754a56897f61

Save this in a password manager your team can access.

If you lose the key, no one, including you, can access anything encrypted with it.

      create  config/master.key

File encrypted and saved.
```

## 動作確認環境

- Rails 6.1.0
SNS認証時のエラーについて

# 経緯
ウィザード形式のユーザー登録機能実装後、
SNS認証を追加するために
registrations_controller内に必要な記述をした。
(userモデルは記述済み。)

```ruby:controller
class Users::RegistrationsController < Devise::RegistrationsController

#一部省略

def create
    if params[:sns_auth] == 'true'
      pass = Devise.friendly_token
      params[:user][:password] = pass
      params[:user][:password_confirmation] = pass
    end
    super                               #ここまでがSNS認証実装に追記した記述
    @user = User.new(sign_up_params)    #ここからウィザード形式のための記述
      unless @user.valid?
        render :new and return
      end
      session["devise.regist_data"] = {user: @user.attributes}
      session["devise.regist_data"][:user]["password"] = params[:user][:password]
      @profile = @user.build_profile
      render :new_profile
  end

#一部省略

end
```

# エラー内容
新規登録を行ってみたところ下記のようなエラーメッセージが出る。

```
AbstractController::DoubleRenderError in Users::RegistrationsController#create
```
同一アクション内にrenderもしくはredirectが複数回使われていますよ！という内容。
renderの後にand returnで処理を終わらせているのになぜ？となる。。


# エラー原因
SNS認証を実装するために追記した記述の最後にある
superによるもの。
（superとは、継承元のクラスにある、superを記述したメソッドと同名のメソッドを呼び起こすことができる。）

呼び起こし先は下記である。
(https://github.com/heartcombo/devise/blob/master/app/controllers/devise/registrations_controller.rb) 参照元

```ruby:RegistrationsController
class Devise::RegistrationsController < DeviseController

# 一部省略

def create
    build_resource(sign_up_params)

    resource.save
    yield resource if block_given?
    if resource.persisted?
      if resource.active_for_authentication?
        set_flash_message! :notice, :signed_up
        sign_up(resource_name, resource)
        respond_with resource, location: after_sign_up_path_for(resource)
      else
        set_flash_message! :notice, :"signed_up_but_#{resource.inactive_message}"
        expire_data_after_sign_in!
        respond_with resource, location: after_inactive_sign_up_path_for(resource)
      end
    else
      clean_up_passwords resource
      set_minimum_password_length
      respond_with resource
    end
  end

# 一部省略

end

```
この中のrespond_withがどうやらエラーの原因みたい。
respond_withは、renderやredirectの役割を持っているため。
よってsuperで呼び起こしたメソッド内でrender or redilectしようとしたけど、その後の記述でまたrenderがあり
どっち？となりエラーが起きたと考えられる。
【超凡ミス】git push heroku masterしたら「error: failed to push some refs to 'https://git.heroku.com/******.git'」

# はじめに
ある教材のハンズオンをしてたらエラーが出たので記録しておきます。

※結論：超凡ミスでした

# 実行コマンドとエラー内容
作成したアプリケーションをHerokuにデプロイしようと以下のコマンドを実行すると

```
$ git push heroku master
error: src refspec master does not match any
error: failed to push some refs to 'https://git.heroku.com/******.git'
```

のエラーが...

# 原因と解決方法

GitHubのメインブランチが`master`ではなく`main`なのでそれに合わせて以下のコマンドが正解でした。

```
$ git push heroku main
```

実行結果

```
Enumerating objects: 779, done.
Counting objects: 100% (779/779), done.
Delta compression using up to 8 threads
Compressing objects: 100% (718/718), done.
Writing objects: 100% (779/779), 7.83 MiB | 426.00 KiB/s, done.
Total 779 (delta 234), reused 0 (delta 0), pack-reused 0
remote: Compressing source files... done.
remote: Building source:
...
（中略）
...
remote:        https://quiz-laravel-vuejs.herokuapp.com/ deployed to Heroku
remote:
remote: Verifying deploy... done.
To https://git.heroku.com/******.git
 * [new branch]      main -> main
```

無事pushできました。

# さいごに

2020年10月5日にGitHubのデフォルトブランチが`master`から`main`に変わりました。

それ以前に作成された教材で`Heroku`にデプロイする時は

```
$ git push heroku master
```

になっているので気をつけてください！

[GitHub、これから作成するリポジトリのデフォルトブランチ名が「main」に。「master」から「main」へ変更](https://www.publickey1.jp/blog/20/githubmainmastermain.html)
【Mac】grepとsedで単語として完全一致を行う正規表現

- 業務等でgrepやsedを利用する際に、単語一致での検索や置換処理は非常に多いです。
- その際に完全一致とならないケースは稀では無いです。
- 今回は、限りなく高い確率で完全一致で行うための正規表現記法を記録します。

## 結果
- 結果の記述は以下の通りです。
    - **※なおMacのBSD系のgrep及びsedで動作するものとなっています。**

```bash
# データ例
$ cat data

10,30,50,100,150,250,300,500

# データ例の中から50のみをgrep。
$ cat data | grep -o '[[:<:]]50[[:>:]]'

50

# データ例の中から50のみを"一致"へ置換。
$ cat data.txt | sed 's;[[:<:]]50[[:>:]];一致;g'

10,30,一致,100,150,250,300,500
```

## 内容
- 上記の結果例は、任意のデータに対して検索及び置換を行う処理です。
- こちらで利用している方法は、**どちらも単語を`[[:<:]]単語[[:>:]]`のように囲むということです**。

### grepでの単語指定
- そもそもgrepは単語のみではなく、行の抽出を行います。
- 単語のみの抽出には、optionを利用して、`grep -o 単語`とします。
- ただ上記のデータ例では以下のように部分一致となり、4つ抽出されます。

```bash
$ cat data | grep -o 50

50
50
50
50
```

- これらの事から以下の意味がある`[[:<:]]単語[[:>:]]`を利用します。
    - 単語の先頭及び末尾に一致するため、前後への文字列を認識しない。

### sedでの単語指定
- sedもgrep同様にそのまま置換文字列指定では、以下のように4つ置換されます。

```bash
$ cat data.txt | sed 's;50;一致;g'

10,30,一致,100,1一致,2一致,300,一致0
```

- これらの事からgrep同様に`[[:<:]]単語[[:>:]]`のように単語として認識させる必要があります。

## まとめ
- 上記のことから、データの重複性を意識して更なる正規表現の勉強を再認識しました。

## 参考
- https://dev.mysql.com/doc/refman/5.6/ja/regexp.html
pythonでextension methodを実装してみる


# extension method（拡張メソッド）とは

- [拡張メソッド (C# プログラミング ガイド)](https://docs.microsoft.com/ja-jp/dotnet/csharp/programming-guide/classes-and-structs/extension-methods)より

> 拡張メソッドを使用すると、新規の派生型の作成、再コンパイル、または元の型の変更を行うことなく既存の型にメソッドを "追加" できます。

# 実装してみる
C#のような拡張メソッドの実現は困難なので、ここでは拡張用クラスで対象型のインスタンスをラップして、オブジェクト指向的なメソッド実行が可能、もしくは、単なる関数として実行可能であることを目指します（継承ではなく、移譲によるプログラミング）。

[公式ドキュメント](https://docs.python.org/3/howto/descriptor.html#functions-and-methods)によると、`__get__`を実装することで、関数として振る舞うか、メソッドとして振る舞うか制御可能なので、ここに細工を入れます。

次のコードは、メソッドに渡される`self`を`self.__root__`に置換し、擬似的なextension methodを実現します。

``` python
from functools import wraps
from types import MethodType

class ExtensionMethod:
    def __init__(self, func):
        self.__func__ = func

    def __get__(self, obj, objtype=None):
        if obj is None:
            return self.__func__  # インスタンスなし時はそのまま関数を返す
        func = self.__func__

        @wraps(func)  # 関数の引数情報などを引き継ぎ
        def wrapper(self, *args, **kwargs):
            return func(getattr(self, "__root__"), *args, **kwargs)  # selfをself.__root__に置換

        return MethodType(wrapper, obj)  # インスタンスと関数をバインドしたメソッドを返す

class MyExtension:
  def __init__(self, __root__):
    self.__root__ = __root__

  @ExtensionMethod
  def add_one(self):
    return self + 1

print(MyExtension.add_one(0))  # => 1
obj = MyExtension(10)
print(obj.add_one()) # => 11
```

こんな感じでしょうか。
あんまり嬉しくないな（オイ

単純に継承した方が多くの場合で話が早いのですが、`__root__`のインターフェースに対してプログラムするので、継承せずに様々な型をオブジェクト的に扱えるのが利点ではあります。

mypyやpydanticのような型チェッカーと組み合わせることで、活路があるかもしれませんね。

# 注意
`ExtensionMethod`に対してデコレータを付与した場合、`ExtensionMethod`インスタンスに対してデコレータが動作します。

``` python
class MyExtension:
  def __init__(self, __root__):
    self.__root__ = __root__

  @your_decorator  # こういうの
  @ExtensionMethod
  def add_one(self):
    return self + 1
```

クラスからメソッドへのアクセス時は、`__get__`が動作して、関数かメソッドを返しますが、クラス生成中に直接アクセスしてはいけないということです。

関数として扱わせるには、`__call__`を実装したり、もうひと手間必要になります。（ここでは、コードが冗長になるので紹介しません。）

また、mypyなどの静的型チェッカーを利用すると、selfの型が自身の型と一致しないので、エラーを出しまくります。

``` python
@dataclass
class MyExtension:
  __root__: str

  @ExtensionMethod
  def add_one(self: str):  # mypyはselfをMyExtensionを想定するのでエラーとなる
    return self + 1
```

# アイデア
MyExtensionへの属性アクセス時に、ExtensionMethod以外の属性を`__root__`の属性にマップすれば、より拡張メソッドに近い振る舞いを実装できるかも。

# まとめ
あまり実用的じゃない。
AgregoreWeb を使ってみた (-01) p2p network 向け web browser  

AgregoreWeb を最近知りました。

以下の Live 配信 で 紹介されたのが切欠なのですが、
とても興味深い技術です。

Speakeasy JS - Using Standard Web APIs to Mix P2P Protocols (Mauve)
https://www.pscp.tv/feross/1BRJjBkdqLoJw?t=23m53s


# What is AgregoreWeb

AgregoreWeb は 分散Web用のブラウザーです。
AgregorWeb は https://github.com/AgregoreWeb/agregore-browser で　ソースが公開されてる OpenSource です。

公式サイトは以下になります。
https://agregore.mauve.moe/

# ドキュメントは以下

https://github.com/AgregoreWeb/agregore-browser/tree/master/docs



# 起動してみた

https://github.com/AgregoreWeb/agregore-browser/releases からダウンロードできます

![Screen Shot 2021-01-18 at 7.05.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54192/ff4a7fca-4c07-dc7f-eceb-aaa3aaae955a.png)


ブラウザーと同じですね!!

![Screen Shot 2021-01-18 at 7.09.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54192/98576598-b8a1-a7a2-f7ea-c649a2824175.png)

こんな感じでアクセスできます。
VSCodeでクロス開発してるときに出るIntelliSenseのエラーをなんとかしたい

## エラーの原因

VSCode でマイコンなどのコードを書いていると、既存のライブラリのincludeでIntelliSenseがエラーを出すことがあります。includePath が正しいにもかかわらず、です。

たとえば以下のようなヘッダファイルが問題になります。

```c
#ifdef __APPLE__
#include <DefinitionsForMac.h>  // ./configure で動的に生成されるファイルで、存在しない
#endif
```

gcc や clang は暗黙的にいくつかのマクロを定義します。この `__APPLE__` もその一つです。
そして IntelliSense は「VSCode を動かしているホストPCでコンパイルする」と想定して、これらのマクロを定義した状態でコードをスキャンします。

でもクロスビルド用のgccではそんなマクロは定義しないので、make の実行ではエラーになりません。
(`compilerPath` でちゃんとcross-gccを指定してるんだからそっち見てよという気持ちがなきにしもあらず)

## Workaround

以下のようにホストコンパイラの暗黙的マクロをundefしたヘッダファイルを作ります。

```
echo | clang -dM -E - | sed "s/^#define/#undef/" > .vscode/cross.h
echo | cross-gcc -dM -E - >> .vscode/cross.h
```

でもって`c_cpp_properties.json`で`forcedInclude`に指定します。

```
"forcedInclude": [ "${workspaceFolder}/.vscode/cross.h" ],
```

## VSCode 本体の修正
それなりに困っている人もいるようで、https://github.com/microsoft/vscode-cpptools/issues/1083 で議論されています。そのうち修正されるといいな。
Redmineでチケットをコピーした時は開始日と期日をそれぞれ+1日加算したい

#同じ開始日と期日でチケット作ることほぼ無いからね

RedmineをTODOっぽく使ってるマンです。
んで、使ってるうちにこんなことを思いました。

1. 今日のお掃除チケット終了！じゃあ明日用にチケットコピーしようジャマイカ。
2. あれ？コピーしたはずのチケットが見当たらない…。
3. あ、開始日と期日を **1日ずらすの忘れてた** 。
4. 面倒くさいなあ…。

ということで記事タイトルのようなことをやりました。

#ビューカスタマイズプラグイン使うよ

ビューカスタマイズプラグインのインストールまでは下記でやってるので、この記事ではハショリます。
[CentOS8にインストールしたRedmineにビューカスタマイズプラグイン導入](https://qiita.com/waokitsune/items/d08c96bf44b32000981e)

#設定はこんな感じ

**パスのパターン** で絞り込んでおくのが大事。
『このJSって別のページに悪影響あるかな？』を考えなくてよくなるです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/2109fc50-ff1f-1605-f15b-ab2a9e7ab66a.png)

```javascript:コード
$(function(){


	var start_val_ = $('#issue_start_date').val();
	var due_val_ = $('#issue_due_date').val();


	//コピー元の値を確認できた方がいいから。
	$('label[for="issue_start_date"]').text('開始日（元:' + start_val_.replace(/-/g, '/') + '）');
	$('label[for="issue_due_date"]').text('期日（元:' + due_val_.replace(/-/g, '/') + '）');


	var y_;
	var m_;
	var d_;


	//チケットコピーは日次のTODOが多いから開始日と期日を+1日加算。

	//開始日未設定のチケットをコピーすると、
	//開始日の値は現在日付が自動でセットされるので、
	//開始日の値が無い場合は考えないことにします。


	//開始日
	var start_date_ = new Date(start_val_);
	start_date_.setDate(start_date_.getDate() + 1);

	y_ = start_date_.getFullYear();
	m_ = ("00" + (start_date_.getMonth()+1)).slice(-2);
	d_ = ("00" + start_date_.getDate()).slice(-2);
	$('#issue_start_date').val(y_ + "-" + m_ + "-" + d_);


	//期日未設定のチケットをコピーした時に例外にならないように。
	if(due_val_ == '') return;


	//期日
	var due_date_ = new Date(due_val_);
	due_date_.setDate(due_date_.getDate() + 1);

	y_ = due_date_.getFullYear();
	m_ = ("00" + (due_date_.getMonth()+1)).slice(-2);
	d_ = ("00" + due_date_.getDate()).slice(-2);
	$('#issue_due_date').val(y_ + "-" + m_ + "-" + d_);


})
```

#有効にするとこんな感じ
年またぎと月またぎの時にちゃんと動作するか確認しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/61bf0445-5895-0b1f-4010-a0a4b1233ce4.png)


#蛇足

チケットを『日次』『週次』『月次』『年次』『不定期』に分類して、それぞれに対してチケットコピー時の加算日数を切り替えれば、もうちょっと便利になるかもです。

ビューカスタマイズプラグインはこういうプチ改良が手軽にできて便利です。

#バージョン
CentOS Linux release 8.3.2011
Redmine 4.0.6.stable
Chrome バージョン: 87.0.4280.141（Official Build） （64 ビット）
Material-UI でデフォルトテーマをカスタマイズする方法

# 概要

[React](https://reactjs.org/) とセットで使うことの多い [Material-UI](https://material-ui.com/) のテーマをカスタマイズする方法です。
デフォルトテーマは『[こちら](https://material-ui.com/customization/default-theme/)』を参照してください。

# テーマをカスタマイズ

ここでは`theme.js`というファイルを作成します。

```js:theme.js
import { createMuiTheme } from '@material-ui/core/styles';

// フォントを設定
const fontFamily = [
  'Noto Sans JP',
  'メイリオ',
  'ＭＳ Ｐゴシック',
  'sans-serif',
  // 使用したいフォントを以降に羅列してください
].join(',');

/*****************
 * テーマを設定
 *****************
 */
const theme = createMuiTheme({
  typography: {
    fontFamily: fontFamily,  // フォント
  },
  palette: {
    // Primaryカラーを設定
    primary: {
      light: '#54C527',
      main: '#ff9800',
      dark: '#b26a00',
      contrastText: '#000000',
      mainGradient: 'linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)',
    },
    // Secondaryカラーを設定
    secondary: {
      light: '#33eb91',
      main: '#00e676',
      dark: '#00a152',
      contrastText: '#ffffff',
    },
    type: 'dark', // ダークモードをON
  },
  mixins: {
    // ツールバーの高さ
    toolbar: {
      minHeight: 64,
    },
  },
  // 各パーツのスタイルをカスタマイズ
  props: {
    MuiCheckbox: {
      color: 'primary',
    },
    MuiList: {
      dense: true,
    },
    MuiTable: {
      size: 'small',
    },
    MuiTextField: {
      variant: 'outlined',
    },
  },
});

export default theme;

```

マテリアルデザイン仕様のカラーは『[こちら](https://material.io/resources/color/#!/?view.left=0&view.right=0)』で確認できます。

# テーマをコンポーネントに適用

以下の例は create-react-app で作成されたindex.jsに適用しています。
ポイントは`MuiThemeProvider`をimportしてコンポーネントに適用してあげることです。
パラメーターに先ほど作成したtheme.jsを渡してあげてください。

```jsx:index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
// カスタムしたテーマ(スタイル)を定義
import { MuiThemeProvider } from '@material-ui/core/styles';
import theme from './styles/theme';

ReactDOM.render(
  <React.StrictMode>
    <MuiThemeProvider theme={theme}>
      <App />
    </MuiThemeProvider>
  </React.StrictMode>,
  document.getElementById('root')
);

reportWebVitals();

```
CircleCI環境構築の時に超タメになった記事

# まずは公式ドキュメント
正直なんでも書いてある！
公式ドキュメント読めれば最強

https://circleci.com/docs/ja/2.0/getting-started/#section=getting-started

#CircleCI API v2で柔軟なCI/CD環境を構築したい！！
CircleCI v2.1で使えるようになった機能をふんだんに使っている
超ためになった

https://techblog.locoguide.co.jp/entry/2019/08/27/113844

# いまさらだけどCircleCIに入門したのでわかりやすくまとめてみた
基礎的なことが一から書いてある
入門したての頃はよく読んだ

https://qiita.com/gold-kou/items/4c7e62434af455e977c2
JavaScript で文字コードを加減算する方法

自分のサイトがあるのですが、そこを楽曲専用から汎用に大型アップデートしようと思いまして、
そこでリストの番号を

``` text:イメージ
  リスト
①text1
②text2
③text3
```

の様にしたかったんですね。数字が○で囲まれている文字です。
そこで、CSS で

``` CSS:合ってるかは知らないけどこんなの.css
ol li#list1:nth-child(1)::before {
    content: "①";
}
/*    :
      :    */
```

とか文字列配列作ってインデクスに応じて切り替えたり(？)で出来るんですが、
せっかくなら JavaScript で書きたくなったんですよ。
<span style="font-size: 0.7em;">~~そのままテキストで①、②…と書けばいいものを…~~</span>




#C/C++なら分かるぞ！
と思ったので一応書いておきます。C/C++ での実装の場合のイメージです。

``` cpp:C/C++の場合.cpp
std::string GetNumByCircle(int num)
{
    std::string res = '①' + num;
    return res;
}
```

``` plain:実行結果のイメージ(入力は3)
④
```

これで今回の主題は達成するのですが、JavaScript で同じ様に書いてみましょうか。

``` js:JavaScriptの場合.js
function getNumByCircle(num)
{
    var res = '①' + num;
    return res;
}
```

``` plain:実行結果のイメージ(入力は3)
①3
```

JavaScript では '...' も "..." も文字列で、+ は文字列結合演算子なので文字列結合が発生しました。
これでは、僕が実際に使おうとした方法でやると

``` text:他のバグもありますが、こうなりますよね。
...①6①5①4①3①2①1①0
```




#JavaScript で文字コードを加減算

では、JavaScript で「'①' + num」を考えてみましょう。
<br>
…分かりましたか？
では、僕が最終的に辿り着いた方法を紹介しましょう。

``` js:JavaScriptでのやり方.js
function getNumByCircle(num)
{
    var res = String.fromCharCode('①'.charCodeAt(0) + num);
    return res;
}
```

これで

``` plain:実行結果のイメージ(入力は3)
④
```

となります。長いなぁ…。




#解説
解説編です。


###何が起こっているか
といえば、

0. 文字コードを取得
0. 取得した値に num を加算
0. その値を文字コードとした文字を取得

とやっているだけです。
因みに C/C++ の場合は、

0. char 型の整数値(=文字コード)に num を加算

これだけです。


###1. 文字コードを取得

``` js:この部分.js
/*function getNumByCircle(int num)
{
    var res = String.fromCharCode(*/ '①'.charCodeAt(0) /*+ num);
    return res;
}*/
```

`文字列.charCodeAt(index: number)`
文字列の index 番目の文字の文字コードを取得するメソッドです。
これで 文字型から整数型に変換するようなことをしています。


###2.取得した値に num を加算

``` js:この部分.js
/*function getNumByCircle(int num)
{
    var res = String.fromCharCode(*/ '①'.charCodeAt(0) + num /*);
    return res;
}*/
```

`文字コード(整数値) + 整数値`
書くとすればこういうことになりますね。単純に整数値同士の加算です。
C/C++ の方では「1.char 型の整数値(=文字コード)に num を加算」にあたる式です。


###1. 文字コードを取得

``` js:この部分.js
/*function getNumByCircle(int num)
{
    var res = */String.fromCharCode('①'.charCodeAt(0) + num)/*;
    return res;
}*/
```

`String.fromCharCode(...codes: number[])`
文字コード配列に対応する文字列を取得するメソッドです。
これで 整数型配列から文字型配列に変換するようなことをしています。




#まとめ

``` js
String.fromCharCode(str.charCodeAt(idx) + num)
```
で `chr + num` の様な事は可能！
…書きながら思いましたが、 `str[idx] + num` の方が JS に忠実ですね。




#おわりに
記事を書いている最中にメソッド名で調べたんですが、
どうやら `String.charCodeAt(idx)` では値の範囲によっては上手く動かないようです(例えば "🐤" 等)。
その理由や、どのメソッドを使用すればいいのかは自分で調べてみて下さい。
因みに、 `String.fromCodePoint(codes)` の方はこれで良いのでしょうか…？

さてさて、執筆はこの辺にして、ちゃんと各 `<ol>` の `<li>:before` に配置されるように修正しないとね。
Rails 検索機能の実装

# Rails で検索機能を実装

## View に form_tag で検索窓を設置

```ruby
<div class="search_field">
    <p>検索：</p>
    <%= form_tag(posts_path, :method => 'get') do %>
      <%= text_field_tag :search, "",  {class: "search_field_type"}%>
      <%= submit_tag 'Search', :name => nil, class: "search_field_btn" %>
    <% end %>
  </div>
```

form_tag(posts_path, :method => 'get') の path の部分はクラス名によって任意に変更してください。

## Model に検索のためのメソッド search を設定

post.rb

```ruby
def self.search(search)
    if search
      Post.where(["title LIKE ?", "%#{search}%"])
    else
      Post.all
    end
  end
```

title カラムの中の一部でも検索した文字列が該当すればヒットするように設定。

詳しくは SQL の where 句を調べれば何となく設定している意味わかります。

[https://www.wakhok.ac.jp/biblion/1994/DB/subsection2.4.3.5.html](https://www.wakhok.ac.jp/biblion/1994/DB/subsection2.4.3.5.html)

## Controller の調整

posts_controller.rb

```ruby
def index
    @posts = Post.all.includes(:user).order(id: "DESC").search(params[:search])
  end
```

これで検索にヒットした記事が @posts に入る。

あとは View 側で一覧表示処理をすれば OK です。
VSCodeでフォルダが重複する原因と解決方法

#例

<img width="400" alt="スクリーンショット 2021-01-17 22.25.21.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1032677/b73f293a-436f-c91b-3fb7-242cf13a43bb.png">
画像のように、フォルダが簡略化され少し見づらいです（個人的に）。

初期設定でこの仕様になっているため、階層構造にするには設定を行う必要があります。

#原因

フォルダの中身（ファイル）がない場合に起こるみたいです。

#解決方法

左下の設定マークから設定を開く（または[⌘,]、windowsなら[ctrl,]）
↓
compact foldersと検索
↓
Explorer : Compact Foldersのチェックを外す
![スクリーンショット 2021-01-18 1.16.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1032677/b9e61331-187a-a0bc-a542-85eca167cbe9.png)

#参考URL
vscode エクスプローラのフォルダ階層をまとめないようにする
https://qiita.com/niceland/items/1d722800521ae185e780
[PowerShell]Active Directoryの設定情報取得コマンド

情報|コマンド 
:--:|:--:
ドメイン|get-ADDOmain             
ドメインコントローラー|get-ADDomainController 
フォレスト|get-ADForest              
サイト|get-ADReplicationSite     
サイトリンク|get-ADReplicationSiteLink 
サブネット|get-ADReplicationSubnet
Oracle Cloud [OCI]: Computeのcloud-initを使ってCentOS Streamインスタンスを作成する

Oracle CloudのComputeインスタンスには、様々なイメージが用意されていますが、
2021/1/17時点ではCentOS Streamのイメージが用意されていません。

そのため、CentOS8のComputeインスタンスを作成し、cloud-initでアップデートを行うことでCentOS Streamを使用します。
いつもComputeインスタンスを作成する時とほぼ変わらず、とても簡単に作成できました。

なお、OCIの初期設定をする際のcloud-initの使い方はこちらの記事がとてもわかりやすく、参考にさせていただきました。

■参考にさせて頂いた記事
<a href="https://qiita.com/yamada-hakase/items/ec141a6d40f1027582ac">cloud-initでOCI Computeの初期設定を済ませる
</a>

##作業手順
1.Computeインスタンス作成
　1-1.イメージ変更　CentOS8を選択
　1-2.ネットワーキングの構成
　1-3.cloud-initの設定
2.動作確認

###今回使用したサービスと技術
・OCI　Compute
・cloud-init
・CentOS Stream

###著者の環境
Mac OS X 10.15.7

##1.Computeインスタンスの作成
Computeインスタンスを作成します。
今回は「VM.Standard.E3.Flex　1コアOCPU、16 GBメモリー、1 Gbpsネットワーク帯域幅」にて作成しました。

###1-1.イメージの変更
デフォルトの「Oracle Linux 7.9」ではなく、「CentOS８」を選択します。

![cloud-init-centosstream1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/487835/39a8d87a-07b0-c5fb-f1d6-6d35267ca807.jpeg)

###1-2.ネットワーキングの構成
今回はあらかじめ登録してあるVCN,パブリック・サブネットを選択し、バプリックIPアドレスを付与しています。

###1-3.cloud-initの設定
「拡張オプションの表示」をクリックし、拡張オプションを表示します。

![cloud-init-centosstream2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/487835/d64cb9e9-ec1b-bdc7-99ea-06d3aa10d7ff.jpeg)


拡張オプションの「管理」タブにある「初期化スクリプト」の「Cloud-initスクリプトの貼付け」を選択します。
cloud-initスクリプトの入力欄に下記のスクリプトを貼り付けます。

cloud-initはroot権限で実行されるため、sudo無しで問題ありません。
コマンド実行中は途中で[Y/N]の入力を求められるため、全て[-y]オプションを付けています。

```cloud-init
#!/bin/bash
dnf install centos-release-stream -y
dnf swap centos-{linux,stream}-repos -y
dnf distro-sync -y
```
cloud-init入力後、「作成」をクリックし、インスタンスが作成されるまで待ちます。

![cloud-init-centosstream3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/487835/485d9911-469b-9211-0477-81eb5f356da9.jpeg)

##2.動作確認
インスタンスの状態が「起動中」になり、数分以上経過してから動作確認をしました。

sshで作成したインスタンスにログインします。
下記のコマンドを入力し、「CentOS Stream release 8」と表示されることを確認します。

```terminal
cat /etc/centos-release
CentOS Stream release 8
```

cloud-init実行時のログは下記に保存されています。

```terminal
/var/log/cloud-init-output.log
```

ログを確認すると、下記のログが出力されますが、
osmspluginはOracle Linux 6/7/8で使用するプラグインのため、影響はありません。
Failed loading plugin "osmsplugin": No module named 'librepo'

以下のような行が表示されると、cloud-initの処理完了です。

```terminal
Cloud-init v. 19.4 running 'modules:final' at Sun, 17 Jan 2021 14:54:04 +0000. Up 28.87 seconds.
Cloud-init v. 19.4 finished at Sun, 17 Jan 2021 15:00:08 +0000. Datasource DataSourceOracle.  Up 393.38 seconds
```

##参考

■cloud-init公式マニュアル
<a href="https://cloudinit.readthedocs.io/en/latest/">cloud-init Documentation</a>

###再掲
■参考にさせて頂いた記事
<a href="https://qiita.com/yamada-hakase/items/ec141a6d40f1027582ac">cloud-initでOCI Computeの初期設定を済ませる
</a>
リーダブルコード読んで意識していきたいことをまとめる part3

[前回](https://qiita.com/gal1996/items/7dc2b534a12154dcd084) の続きです。

# 7章　制御フローを読みやすくする
7章からはコードのロジックを見やすくすることに主眼をおいています。

## 条件式の引数の並び順は調査対象の値を左辺に置く
感覚的にはやってた気がするけど、意識はできてなかったので意識的にやっていきたい。
`if (10 >= length)` より `if (length >= 10)` のほうが読みやすいという話。脳内では「長さが10より大きければ」って解釈されるから後者の方が読みやすい。

## if/else ブロックの並び順
- 条件は否定系よりも肯定系を使う
- 単純な条件を先に書く
- 関心を引く条件や目立つ条件を先におく
これも感覚的にはやってた気がするけど、意識的にはできてなかった。特に3つめは関心がある条件を書き出したことを意識すると可読性が上がりそう。

## 関数から早く返す
いわゆる早期リターン（ガード節）というやつ。処理を終了する条件を先にチェックして行って当てはまればそこで処理を終わるようにする。こうするとムダに処理されないコードを読まなくて済む。とくにif分がネストしているような場合、終了条件を先に先にチェックしていくことでムダなネストを減らせるようになる。

今日は短いけどこのくらいで。
Dockerで作成したMySQLに接続できなかった時の解決方法

これまでDockerのMySQLイメージを使ったことがなかったのでプロジェクトが始まる前に個人的に環境を一から作成する練習をしていました。Pythonフレームワークのdjangoから接続を試みていたのですが、3日くらいずっと悩まされ続けたのがこれです。。

```
django.db.utils.OperationalError: (2005, "Unknown MySQL server host 'mysql' (11001)")
```

3日ほど調べた末に解決したので、その時に見つけた解決方法をまとめました。


## 環境

* Windows 10
* Docker for Windows


## 今回のディレクトリ構成

```
proj/
  ├ .docker/
  │   ├ nginx/
  │   │  └ default.conf
  │   └ python/
  │      ├ Dockerfile
  │      └ requirements.txt
  ├ django_proj (以下略)
  ├ docker-compose.yml
  └ manage.py
```


## 解決方法

docker-compose.ymlのmysqlの設定に注意！（それだけ！でした。笑）


```yml:docker-compose.yml
version: "3.9"
   
services:
  python:
    build: ./.docker/python
    command: gunicorn django_proj.wsgi:application --bind 0.0.0.0:8000 --reload
    volumes:
      - .:/code
    expose:
      - "8000"

  nginx:
    image: nginx:1.19
    volumes:
      - ./.docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
      - ./static:/etc/nginx/static
    ports:
      - "80:80"
    depends_on:
      - python

  mysql:
    image: mysql:5.6
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    volumes:
      - ./.docker/db/data:/var/lib/mysql
    expose:
      - "3306"
    environment:
      - MYSQL_ROOT_USER=root
      - MYSQL_ROOT_PASSWORD=root
      - MYSQL_ROOT_HOST=%           # この1行が今回のポイントでした
```


[MySQL公式ページ](https://dev.mysql.com/doc/mysql-installation-excerpt/8.0/en/docker-mysql-more-topics.html#docker_var_mysql-root-host)に以下の記載がありました。

> MYSQL_ROOT_HOST: By default, MySQL creates the 'root'@'localhost' account. This account can only be connected to from inside the container as described in Connecting to MySQL Server from within the Container. To allow root connections from other hosts, set this environment variable. For example, the value 172.17.0.1, which is the default Docker gateway IP, allows connections from the host machine that runs the container. The option accepts only one entry, but wildcards are allowed (for example, MYSQL_ROOT_HOST=172.*.*.* or MYSQL_ROOT_HOST=%).

デフォルトではroot@localhostでアカウントを作ってしまうので、rootユーザーとしてログインできるのはlocalhost、すなわち今回の場合はmysqlコンテナ内からのみとなってしまうようです。

なので、`MYSQL_ROOT_HOST=%`の記述を追加しておけば、どのIPアドレスからもrootユーザーとしてログインできるようになるので、違うコンテナからのログインも受け付けられるということなんだと思います。


## 参考
* [MySQL :: MySQL Installation Guide :: 7.6.2 More Topics on Deploying MySQL Server with Docker](https://dev.mysql.com/doc/mysql-installation-excerpt/8.0/en/docker-mysql-more-topics.html#docker_var_mysql-root-host)
UnityのAsyncOperation.isDoneでtrueになるやつとならないやつ

#前提
タイトルで、「trueになるやつとならないやつ」と書いていますが、結果的にはどちらもtrueになります。
しかし、trueになるタイミングが少し感覚と違うので、そこの違いをこの記事でははっきりさせたいと思います。

Unityの非同期ロード系の関数で、
- シーンを非同期でロードする、`SceneManager.LoadSceneAsync()`
- Resourcesのアセットを非同期で読み込む`Resources.LoadAsync<T>()`
みたいなのがあると思います。（AssetBundleは一旦無視で進行します）

そしてこの2つはともに、`UnityEngine.AsyncOperation`を返します。
※`Resources.LoadAsync<T>()`は`ResourceRequest`を返しますが、`AsyncOperation`を継承しているので実質同じ。

しかし、この2つの`AsyncOperation`は`AsyncOperation.isDone`をきちんと返してくれるのでしょうか？以前にそこで詰まって頭の中で個チャゴチャになっていたので、もう一度検証してみました。

#検証用コード
```c#
using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;

public class LoadAsyncTest : MonoBehaviour {
    void Start() {
        StartCoroutine(Verify_LoadSceneAsync("scenename"));
        StartCoroutine(Verify_LoadAsync("path"));
    }

    IEnumerator Verify_LoadSceneAsync(string name) {
        AsyncOperation operation = SceneManager.LoadSceneAsync(name);
        operation.allowSceneActivation = false;

        while (!operation.isDone) {
            Debug.Log(operation.progress * 100f + "%読み込み完了");
            yield return null;
        }

        yield return new WaitForSeconds(0.5f);
        operation.allowSceneActivation = true;
    }

    IEnumerator Verify_LoadAsync(string name) {
        ResourceRequest operation = Resources.LoadAsync(name);

        while (!operation.isDone) {
            Debug.Log(operation.progress * 100f + "%読み込み完了");
            yield return null;
        }

        yield return new WaitForSeconds(0.5f);
        Instantiate((GameObject) operation.asset); 
    }
}
```

`LoadLevelAsync()`ではシーンを非同期でロードして、whileでisDoneがtrueになるまで待っています。
`LoadAssetAsync()`ではResourcesのアセットを非同期でロードして、同様の処理を行っています。

#検証結果

|　|ScneneManager.LoadSceneAsync()|Resources.LoadAsync()|
|:--:|:--:|:--:|
|isDone|false|true|
|状態|isDoneが一生trueにならないのでスタック|きちんとtrueになり、インスタンス化も成功|

そうなんです。**LoadSceneAsync()のときのみ、isDoneがtrueにならずスタックします。**
同様に、コード内の`operation.progress`も0.9fで止まってしまいます。
この場合のisDoneは、シーン遷移が完了してからtrueになるのでロードした段階ではfalseです。

`Resources.LoadAsync()`は、ロード完了した段階でisDoneがtrueを返してくれるので、普通に使っても問題ないと思います。

検証は以上です。何か記事の中に問題がありましたら、コメントにてご指摘お願いします！
VPCと周辺知識についてまとめてみた

**※ 現在学習中で間違った内容を記載している可能性が大いにあります。もし間違いがありましたら、遠慮なくご指摘くださいませ。**

### VPCとは？
AWS アカウント内の仮想ネットワーク環境。1 アカウント、1 リージョンに 5 つまで VPC を作成可能。VPC 内部ではさらに細かくネットワークを分けて（サブネット）運用する。使用できるアドレスの範囲は/16~/28 となっている。つまり、第 3 オクテットと第 4 オクテットのはじめの 4 桁は自由に使える。

### サブネットとは？

VPC 内部にさらにネットワークを細かく分ける。具台的には、災害などで一つの AZ がダメになっても、他の AZ に分けておくことができれば対応できる。そのため、サブネットを同じ構成で複数の AZ に冗長的に設置する。また、サブネットは AZ を跨いで作成することはできない。

- パブリックサブネット

      - インターネット接続可（デフォルトゲートウェイにインターネット接続が設定されている）
      - 外部に公開しても良いインスタンス

- プライベートサブネット

      - インターネット接続不可（デフォルトゲートウェイにインターネット接続が設定されていない）
      - 外部に公開できないインスタンス（RDS などのデータベース）

### ルートテーブルとは？

サブネットに関連付けて使用するもので、サブネットから外に出る通信をどこ（ターゲットで表記）に向けて発信するか決めるルール。

- ターゲットが local な場合はその VPC 内全てに接続できる
- ターゲットが InternetGateway は外部に向けて接続できる/される

### インターネットゲートウェイとは（IGW）？

VPC 内の AWS リソース（EC2 など）とインターネットを繋げるもの。AWS 側が負荷分散などを自動でスケールしてくれるので、可用性が高い。


- 使い方
    - サブネットのルートテーブルのターゲットに設定して使用する。


### NATgateway とは？

プライベートサブネットからインターネット接続したい時に使用する。ただし、アウトバウンドはできるが、インバウンドはできない。（発信はできるが受信はできない）ちなみに、パブリックサブネットはデフォルトでインターネット接続が設定されているが、プライベートサブネットはデフォルトでインターネット接続が設定されていない。また、インターネットゲートウェイと同様に負荷が高まると自動で負荷分散してくれる。

- 使い方

    - プライベートサブネットのルートテーブルのターゲットに設定して使用する。（NATゲートウェイはプライベートIPをEIPに変換してインターネットゲートウェイに接続する）そのため、パブリックサブネットにアタッチする必要がある。

### ENI とは？

仮想ネットワークインターフェイス（NIC）のこと。そもそも NIC とは...

- 有線の LAN ケーブルを挿す場所のようなイメージ
- インターフェイス＝接点なので、パソコンがインターネット接続するための接点というイメージ（結構曖昧...）

それが仮想化されていて、それぞれ EC2 などにアタッチされており、IP アドレスを割り当てている。一つのインスタンスに複数の ENI を割り当てて IP を複数保持し、一つのインスタンスで複数サイトを運用したりもできる。ENI と IGW が繋がることで、インターネット接続可能となる

### パブリック IP、EIP とは？

外部のリソース同士が接続するためには、パブリック IP か EIP が必要。パブリック IP は、サブネットの設定で、パブリック IP の自動割当を有効にしていれば、インスタンス作成時に自動で割り当てられる。ただし、停止 → 起動で毎回パブリック IP が変わるので、EIP を設定することで、IP アドレス を固定できる。

ちなみに EC2 はプライベート IP で内部のインスタンスと接続し、パブリック IP で外部のインターネットなどと接続できる。

- 使い方
    - EIPをEC2などのインスタンスに紐付けることで使用できる。

### セキュリティグループとは？

AWS の仮想ファイアーウォールサービスのことで、EC2 レベルで設定できる。（厳密には EC2 の ENI 単位らしい）ホワイトリスト型で（許可したもの以外は受け付けない）、インバウンドとアウトバウンドの設定ができる。ステートフル型なので、戻りの通信許可設定は必要ない。

### ネットワーク ACL とは？

サブネット単位で設定するファイアーウォールのこと。ブラックリスト型でデフォルトでは、インバウンドもアウトバウンドも全て許可されているので、許可したくないものを設定する。ステートレス型なので、戻りの通信も許可する必要がある。（外部からの攻撃があった場合などに、EC2 単位でなくサブネット単位で IP を指定してブロックしたりする時に使う）
複雑なfor文(基礎)

# 複雑なfor文

### ❶初期化処理　❷繰り返し条件　❸繰り返し時処理の３つを工夫し、高度な繰り返しを実現
単に「◯◯回繰り返す」という単純な繰り返しではなく、下記のようにすれば少し高度な繰り返しが行える

```java
//ループ変数を1からスタートする
for (int i = 1; i < 10; i++){...}

//ループ変数を2ずつ増やす
for (int i = 0; i < 10; i += 2){...}

//ループ変数を10から1ずつ１まで減らしていく
for (int i = 10; i > 0; i--){...}

//ループ変数を初期化しない
for (; i < 10; i++){...}

//繰り返し時の処理を行わない
for (int i = 0; i < 10;){...}　
```
Shopify theme kitとBrowserSyncで、ショップテーマの開発環境を快適にする

Shopifyでは`Liquid`というテンプレート言語を使ってECサイトのテーマ(フロントエンド)開発・カスタマイズを行う。
Shopifyの管理画面上で`Liquid`を直接編集する事もできるが、ローカルPC環境でファイル更新し、git管理などを実現するためのツールが、[Shopify theme kit](https://shopify.github.io/themekit/)である。
※ GoogleAppScriptでいう、claspのようなもの

theme kitはShopify環境上とローカル環境のテーマファイルを同期でき、適切なgit管理を実現できるものであり、それだけで導入価値が高い。
ただ、以下の機能を利用する事で、開発時のトライ&エラーサイクルを早め、開発速度向上にもつながる

* `watch`コマンドによる、逐次修正
* BrowserSyncによるAutoReload 


# Shopify theme kitのインストール
Shopify theme kitのインストールについては、公式記事が充実している。
以下リンク参照のこと

[theme kit公式](https://shopify.github.io/themekit/#installation)
[Shopify日本語ブログ](https://www.shopify.jp/blog/partner-local-shopify-theme-setup-three-steps)


# `watch`コマンドについて
theme kitは`watch`機能が存在する。
https://shopify.github.io/themekit/commands/#watch

watchコマンドは、ローカル上で何らかのファイルを修正したら、ファイル修正を検知して逐次Shopify環境へアップロードしてくれる機能である。

都度`Deploy`する必要がなくなるため、ローカルで開発する際にはMustで利用すべき機能である。

# BrowserSyncによるAutoReload 
本稿のメインはこちらである。
前述の`watch`コマンドでは、`--notify`オプションで指定したファイルに変更通知する事ができる。この機能を使うことで、AutoReloadを実現する事が可能である。
以下、BrowserSyncを使ったAutoReloadの実現方法について記す。

## BrowserSyncのインストール

以下のコマンドで、ひとまずグローバルインストールしておく
`npm install -g browser-sync`

## `bs-config.js`の修正

watchコマンドとBrowserSyncを併用する場合、デフォルトでは各ツールが埋め込むタグが干渉しあう。
結果、以下のようにECサイト画面の上部に不要なタグが表示されてしまう。

![スクリーンショット 2021-01-17 23.42.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92331/0f06f24f-7245-9bd2-fd08-2f23bbd280a2.png)

これを解消するために、以下の手順で`bs-config.js`を修正する

__1. `bs-config.js`の生成__

以下のコマンドにて、`bs-config.js`を生成する
`browser-sync init`

__2. `bs-config.js`の修正__

以下のコードを、bs-config.jsに追加する。

```node.js
module.exports = {
    // ここから
    snippetOptions: {
      rule: {
        match: /<\/body>/i,
        fn: function (snippet, match) {
          return snippet + match;
        },
      },
    },
   // ここまで
}
```

## BrowserSyncと`watch`コマンドの起動

あとは、以下のコマンドでBrowserSyncと、`watch`をそれぞれ起動する

```shell
# BroserSync起動
browser-sync start --proxy "https://〇〇〇.myshopify.com/" --files "./temp" --reload-delay 1000 --config bs-config.js

# ※ "./temp" に対して、⇓ でwatch書き出し

# watchコマンド起動
theme watch --notify=temp --allow-live 
```




よきShopifyライフを
卒業研究でQiitaに自分のWebサービスを埋め込みたくなった

タイトルで落ちてる。

#そもそも
Qiitaではiframe要素の埋め込みとか、javascriptの実行とかは基本的にできない。
この辺に関しては[実験記事](https://qiita.com/StealthMinor/items/de6594b1f59963497907)を参照。

#というわけで
ユーザースクリプトで実装することにした。
Qiitaとかnoteとかは勝手にhtml要素を入れたり、あと属性付与したりできない。
付与した場合は勝手に消される。

リンクを張るのに必須のaタグ、その中でも絶対に必要な属性であるhref属性の値を検知させる。


###実際にリンクを張る
[これはWikipediaのリンク。](https://ja.wikipedia.org/wiki/%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%9A%E3%83%BC%E3%82%B8)

[これが卒研のwebサービス想定のリンク。](https://gyoubumasataka.github.io/sidecode_hub/redirect.html?https://gyoubumasataka.github.io/sidecode_hub/ExportedTest.html)


Chromeの拡張機能で実装したので、これを有効にすれば下のリンクにだけ埋め込みが発生する。
[予備] 不可視文字




特殊文字|	意味
-------|-----------------
\t     |タブ(0x09)
\n	|改行(0x0a)
\r	|復帰(0x0d)
\f	|改ページ(0x0f)
\b	|バックスペース(0x08)
\a	|ベル(0x07)
\e	|エスケープ(0x1b)
\s	|空白(0x20)
\v	|垂直タブ(0x0b)
\nnn	|８進数表記(nは0〜7)
\xnm	|16進数表記(nは0〜9,a〜f,A〜F)
\cx,\C-x|	[Contrl]+x
\M-x	|Mata+x
\M-x\C-x|	Mata+Control+x
\x	|文字xそのもの(xは上の文字以外)
\unnn	|Unicode文字の16進数表記(nは0〜9,a〜f,A〜F)
anyenvで〇〇envをまとめて管理

#anyenvとは
プロジェクト毎に使用する開発言語やそのバージョンが異なる場合に、〇〇env系を入れて対応していたが、まとめて管理したいと思い調べていたところ、anyenvが便利そうだったので入れてみた
https://github.com/anyenv/anyenv

※既に〇〇envをインストール済の場合は削除してから、anyenvを入れる必要がある
例（nodenv）：https://qiita.com/ucan-lab/items/a662532f1ce46f152c4e

#環境
- macOS Mojave 10.14.5
- Homebrew 2.7.0
- shell：zsh

#導入
[公式](https://github.com/anyenv/anyenv)を参考にインストール

```
% brew install anyenv
```
パスを通す

```zsh
% echo 'export PATH="$HOME/.anyenv/bin:$PATH"' >> ~/.zshrc
% echo 'eval "$(anyenv init -)"' >> ~/.zshrc
```
シェルを再起動

```zsh
% exec $SHELL -l
```
バージョンが表示されたらインストール完了

```zsh
% anyenv --version
anyenv 1.1.2
```

#〇〇envを入れる（例：nodenv）
はじめに〇〇envを入れるために必要なプラグイン入れる
```~/.config/anyenv/anyenv-install/```にインストールされる

```zsh
% anyenv install --init
```
インストールできる〇〇envを確認

```zsh
% anyenv install -l
  Renv
  crenv
  denv
  erlenv
  exenv
  goenv
  hsenv
  jenv
  jlenv
  luaenv
  nodenv
  phpenv
  plenv
  pyenv
  rbenv
  sbtenv
  scalaenv
  swiftenv
  tfenv
```
nodenvをインストール

```zsh
% anyenv install nodenv

# シェルを再起動
% exec $SHELL -l

# インストールするバージョンを確認
% nodenv install -l
0.1.14
0.1.15
0.1.16
...
...

# グローバルにインストール
% nodenv global 14.3.0

# 無事にインストール完了
% nodenv -v
v14.3.0
```

# プロジェクト毎にバージョンを指定してインストール
```zsh
# プロジェクトのディレクトリへ移動
% cd {プロジェクトのパス}

# 配下で実行
% nodenv local 13.11.0

% nodenv -v
v13.11.0
```
配下に```.node-version```が作成されそこにインストールしたバージョンが記載される

```:.node-version
13.11.0
```


これでプロジェクト毎にnodeのバージョンを切り替えて作業することができる👏