OmniAICreator/Qiita-1.07M huggingface dataset:
PHPでオブジェクト同士の関係を可視化する

# はじめに

オブジェクト同士の関係が複雑になってくると関係を楽に把握したくなります。
[BEAR.Sunday](https://bearsunday.github.io/) の生みの親である郡山さん([@koriym](https://twitter.com/koriym))が公開されている [print_o](https://github.com/koriym/print_o) を使用することでオブジェクト同士の関係を可視化できるので、関係の把握が楽にできるようになります。
使い方は簡単なのでReadmeを読めば理解できると思いますがやってみます。

# インストール

```sh
composer require --dev koriym/printo
```

# 可視化対象

```php
new A(
    new B(
        new E(
            new F(),
            new G(
                new H(
                    new L(),
                    new M(
                        new N()
                    )
                ),
                new I()
            ),
            new J(),
            new K()
        )
    ),
    new C(
        new D()
    )
);
```
# オブジェクトグラフ生成

```php
/** @var A $object */
$object = (new ObjectGraphService())->graph(); // 可視化対象を返す処理

$graph = (new Printo($object))
    ->setLinkDistance(200)
    ->setCharge(-2000);
 file_put_contents('/var/www/html/docs/graph.html', $graph);
```

# 可視化

出力された`html`を開きます。

![objectgraph.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/347252/2a5a954a-7292-7bf9-77da-6a4f969b0e74.png)

オブジェクト同士の関係が可視化できました。
複雑なオブジェクトの関係を可視化したい時に使ってみるとよさそうですね。
Watsonでチャットボット開発

#Watson でチャットボット開発
この記事では、IBM Cloudでチャットボットを開発する方法をご紹介します。

## IBM Cloud のアカウント取得
IBM Cloudのアカウントを所持されてない場合は、[こちらの記事](https://qiita.com/ayatokura/items/42d4bc728112c733c80d)を参考にアカウントを作成してください。
所要時間数分で、メールアドレス一つで、どなたでも簡単に登録することができます。
[『「IBM Cloudをはじめました」無料ではじめられるライト・アカウント登録方法』](https://qiita.com/ayatokura/items/42d4bc728112c733c80d)

## Watson Assistantのサービス追加
### リソースの作成
IBM Cloudのログイン画面後のダッシュボード画面で、右上のリソース作成を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/658425/f860cbee-d5b9-6147-1d17-2edbbfe49acf.png)

### Watson Assistant の選択
リソースの「カタログ検索....」に「Assistant」を入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/658425/68ff6b31-a69a-70d7-ea28-9427b51c59ba.png)

検索結果の一覧から「Watson Assisntant」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/658425/f6b7324f-a9d6-9ab4-8c34-8e907a28cce9.png)

### Watson Assistantの作成
リージョンや、プラン、サービス名を変更し、最後に作成ボタンを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/658425/040372df-f159-54f9-0c5d-a7563f654297.png)

### 完成
作成ボタンを選択後、自動的に作成されてたAssistantを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/658425/0d248656-9639-f71a-3780-5d51561eebec.png)
「This is the wrong package! Please install eslint-plugin-jsx-a11y」のエラー

## エラー内容
りあクト！の【II.React基礎編】で

```
$ yarn add -D @typescript-eslint/parser @typescript-eslint/eslint-plugin \                                                        
eslint-plugin-react eslint-plugin-react-hooks eslint-plugin-import \
eslint-plugin-jsx-ally eslint-config-airbnb
```
と入力したところ

```
error /.../hello-world/node_modules/eslint-plugin-jsx-ally: Command failed.
Exit code: 1
Command: node ./postinstall.js
Arguments: 
Directory: /.../hello-world/node_modules/eslint-plugin-jsx-ally
Output:
/.../hello-world/node_modules/eslint-plugin-jsx-ally/postinstall.js:1
throw new Error('This is the wrong package! Please install eslint-plugin-jsx-a11y')
```
のエラーが出ました

## 結論
タイポでした！
「eslint-plugin-jsx-a11y」の「a11y」は英字のLの小文字ではなく数字の11でした！

## 感想
恥ずかしいです。。。

他にも、りあクト！の【II.React基礎編】の少し前のページで

```
$ yarn eslint --init
```
でエラーが出て、解決のためにいろいろ調べてなんとか解決したところで、次の会話で柴崎さんが「なおコマンドがエラーで終わっても、とりあえずは気にしなくてもいいから」とおっしゃられていました。
恥ずかしいです。。。
【EFS】EFSとは

## EFSとは
**Amazon Elastic File System** の略
AWSクラウドサービス及びオンプレミスリソースから利用出来る拡張性・適応性のあるファイルストレージサービス
ファイルシステムを作成し、ファイルシステムをEC2インスタンスマウントし、ファイルシステムとの間でデータの読取り及び書込みを行うことが可能

- フルマネージド型のNFSサーバー
- ネットワークファイルシステムバージョン4（NFSv4.1及びNFSv4.0）プロトコルをサポート
- 作成時に容量を指定することなく、利用した容量分のみ拡張・課金される
- データ転送量・リクエスト数による料金は発生しない
- データは複数AZに保存されており、高耐久性・高可用性がある
- スタンダードアクセスと低頻度アクセスの2つのストレージクラスがある
- 1ファイルの最大容量48TB
- インターネットからの直接アクセスは不可

### ユースケース
- アプリケーションの共有ディレクトリ
- 複数インスタンスからの同時アクセスが必要（EBSでは実現不可）

## マウントターゲット
- ファイルシステムにアクセスするためにVPCに作成する
- EC2インスタンスからマウントターゲットを介して、AZ外にあるEFSにアクセス出来る
- 固定のDNS名とIPアドレスを有する

## パフォーマンスモード
### 1. 汎用モード
- 一般的な用途を想定したデフォルトのモード
- レイテンシーが低い
- 1秒あたりのファイルシステム操作を7,000に制限

### 2. 最大I/Oモード
- 何十から何千というクライアントからの同時アクセスが発生する大規模な構築に利用
- レイテンシーが多少長くなる
- 合計スループットを優先してスケールする

## その他ファイルストレージ
### Amazon FSx For Windows File Server
Windows File Server をAWSクラウド上で利用したい場合に使用するストレージ

- 最大数千台のコンピューティングインスタンスからアクセス可能

### Amazon FSx For Luster
高速コンピューティング処理を実現する分散・並列処理専用の超高性能ストレージ

- 最適容量3,600GB
- 最大数百GB/秒のスループット
- 数百万IOPSまでスケール可能
- S3とシームレスな統合により、データレイク型のビッグデータ処理や解析ソリューションに組み込む
chromebook IdeaPad Duet に VSCodeをインストール

# linuxのインストール
chromeOSの「設定」アプリを開き、「Linux(ベータ版)」より「オンにする」ボタンをタップします。
![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3339353930322f36613736386532662d393736642d316361372d613732392d3765363664356666306133612e706e67.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395902/fc6bb2ea-7958-322c-b00d-aa889a84516a.png)

linuxのインストールが終わるまで待ちます。

# VSCodeのダウンロード
chromeOSのウエブブラウザから[ここ](https://github.com/headmelted/codebuilds/releases)にアクセスします。
ビルド日付をタップ。
![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3339353930322f31376262333761642d666262342d356137622d633336302d3438303633663739653164302e706e67.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395902/8f1b8c95-7381-b60a-8558-db10f433ec8f.png)
`arm64.deb`のほうをダウンロード。
![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3339353930322f36613930333036362d316137352d313330352d346232392d6165336633623938636334622e706e67.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395902/d33fe5fb-0a97-80be-fcca-588066e2b592.png)

# VSCodeのインストール
chromeOSの「ファイル」アプリを開き、「マイファイル」→「ダウンロード」にあるdebファイルをタップ。
![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3339353930322f36383533653133632d653933662d626133622d316234342d3461313566313837653639362e706e67.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395902/03500323-feed-f76c-aed7-c6262cd76856.png)
インストールが終わると、デスクトップの「Linuxアプリ」にVSCodeのアイコンが追加されます。
![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3339353930322f63646637626432302d323066612d656332652d306361612d3461333432346232323866362e706e67.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395902/7e15ab50-9dfc-e878-c559-36ea5abee95b.png)

以上。
Mediator Pattern

<font color="#00f">MediatorはMediatorが管理するクラスインスタンスをフィールドに保持し、Mediatoに管理されるクラスはMediatorのインスタンスを保持し、Mediatorのメソッドを使わせる<br><br>Mediatorは管理するクラスのインスタンスからクラスの状態を取得し、状態に応じた処理を行う</font>

[Design Pattarm MENU](https://qiita.com/old_cat/items/852d980bedb9100dd7e3)

以下のクラス構成で確認します

|クラス|説明|
|-----|----|
|Mediator.class|管理するクラスのインスタンスを保持|
|menber.class|men1.class~men2.classのsuper<br>Mediatorクラスインタンスを持つ|
|user(Main.class)|動作確認|

＊user　他の開発者がこのパターンを利用する、という意味合いを含みます

```java:Mediator.class
class Mediator{
  menber men1 = new men1(),
         men2 = new men2();
  String check(menber menber){
         if(menber.str == men1.str){return "men1";}
         else{return "men2";}
  }
}
```
```java:menber.class
class menber{
  Mediator mediator;
  String   str;
  menber(String str){this.str =str;}
  void set(){this.mediator=new Mediator();}
}
```
```java:men.class
class men1 extends menber{ men1(){super("men1");}}
class men2 extends menber{ men2(){super("men2");}
```
```java:user(Main.class)
public static void main(String[] args){
    menber m1 = new men1();
    m1.set();
    String res = m1.mediator.check(m1);
    System.out.println(res);
}
```
Gitのバージョンアップで苦戦したのでまとめた

# はじめに
いつものように、GitHub上にプッシュを行おうとしたら出来ない･･･。

そいういえば、GitHubからこんなメールが来ていました。
> We have detected that you recently attempted to authenticate to GitHub using an older version of Git
for Windows. GitHub has changed how users authenticate when using Git for Windows, and now
requires the use of a web browser to authenticate to GitHub. To be able to login via web browser, users
need to update to the latest version of Git for Windows. You can download the latest version at:

まとめると、どうやら***Gitのバージョンが古いからGit for Windowsのバージョンアップをしてね***とのこと。

以前も2020/11/13以降GitHubはGit for windowsを使用する際のユーザーの認証方法を変更しますよーってメールが来ていた。
しかし、自分はその際にGit for windowsの更新をしたはず･･･。

少し躓いてしまったため、こちらにてまとめます。

# 結論
結論は、***「SourceTreeの内蔵gitのバージョンアップをしていなかった」***ことが原因でした。

ただGit for windowsのバージョンアップをすればいいと思っていたがSourceTreeでもバージョンアップする必要があったみたいです。

# やってみた
やるべきことはこちらです。

1. Git for windowsのバージョンアップ
2. SourceTreeの内蔵gitのバージョンアップ

### Git for windowsのバージョンアップ
バージョンアップは、GitHubから来たメールにリンクがあったためそちらからしました。
[Gitforwindowsダウンロード](https://gitforwindows.org/)

### SourceTreeの内部gitのバージョンアップ
バージョンアップは、SourceTreeの上部にある
`ツール > オプション > Git > Update Embedded`からできます。

しかし、上記より更新を行ってもなぜか更新ができませんでしたとエラーが出てしまいました。
調べてみたところ、どうやら`git_local`というファイルを削除することでできるとのこと。

git_localの場所は、下記です。
`C:\Users\ユーザー名\AppData\Local\Atlassian\SourceTree\git_local `

こちらを削除することで、無事SourceTree内部のgitのバージョンが出来ました！

### 参考記事
・[Sourcetreeの内部gitの更新方法](https://qiita.com/seeside/items/4ed5d1a8a6f9ae5b8435)
・[SourceTreeの内臓Gitのバージョンが上がらなかった話](https://qiita.com/haquxx/items/51ba84a548312c2710db)

# まとめ
今回はGit for windowsのバージョンアップの際に躓いたことについてまとめました。

参考になれば幸いです。
【備忘録】iOS 14 細かいTips  写真アクセス権限・バックボタン 

iOS 14のTipsを書いていこうと思います。


# 写真のアクセス権限の変更

iOS 13までは写真のアクセス権限の選択肢が`許可しない`・ `OK`の2択でしたが、
iOS 14からは写真のアクセス権限の選択肢が `写真を選択`・ `全ての写真へのアクセスを許可`・ `許可しない`の3択になりました。
iOS 14では写真個別にアクセス権限を与えれるようになりました。

**iOS 13ダイアログ**
![Screen Shot 2020-11-14 at 2.11.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80912/7f9c8f24-dd30-d3c0-e49d-f63778fa3b9c.png)

**iOS 14ダイアログ**

![Screen Shot 2020-11-14 at 2.14.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80912/4021246c-181b-89ba-c4e3-96f37b79fe1f.png)

写真のアクセス権限の呼び出しは以下のコードでOSに合わせてダイアログを表示します。

```Swift
PHPhotoLibrary.requestAuthorization { _ in
   //　省略
}
```

###iOS 14でも従来のダイアログを出すには？

アプリで写真を保存するだけの用途なら従来のダイアログで問題ないと思います。

まず、Info.plistに`Privacy - Photo Library Additions Usage Description (NSPhotoLibraryAddUsageDescription)`を設定して文言を追加します。

![スクリーンショット 2020-11-14 2.38.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80912/6466254f-32da-4e9a-54a7-515c2e5a1250.png)

なら以下のコードで大丈夫です。

```Swift
if #available(iOS 14, *) {
     PHPhotoLibrary.requestAuthorization(for: .addOnly) { _ in
        // 省略     
     }
} else {
     PHPhotoLibrary.requestAuthorization { _ in
        // 省略        
     }
}
```

`requestAuthorization`というメソッドで `写真のみ追加`もしくは `読み出し/書き込み`のどちらかで指定して呼び出しできるので `.addOnly`を指定すると従来のダイアログが出すことができます。

![Screen Shot 2020-11-14 at 2.40.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80912/452500e6-af25-b5b9-2977-4e344c026e6c.png)

# バックボタン

iOS 14からバックボタンを長押しすることで前の画面らをリストしたポップアップが表示され、一気に一番最初の画面に戻るなどできるようになりました。

例 設定アプリ
![Screen Shot 2020-11-14 at 15.09.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80912/8555a038-252d-fb68-f568-ffe9f64c76ed.png)

他にもバックボタンの見た目も制御できるようになり、UINavigationItemクラスに以下のプロパティが追加されました。

```Swift
var backButtonDisplayMode: UINavigationItem.BackButtonDisplayMode { get set }
```

見た目は3種類設定できます 

**`.default`**

前の画面タイトルがバックボタンに反映します 
※タイトルが入ってなければ `Back`になります

![Screen Shot 2020-11-14 at 15.26.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80912/b9f0a11f-ea3c-3ced-002c-ee9fd08d478e.png)

**`.generic`**

バックボタンが`Back`になります
![Screen Shot 2020-11-14 at 15.29.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80912/edced17e-75e6-b30f-0334-afc7cfd38ce4.png)

**`.minimal`**

バックボタンに名称が表示されず`<`だけになります
![Screen Shot 2020-11-14 at 15.30.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80912/52595c2b-26cf-c6ab-a5f6-ecfc49b3e9e0.png)

コード例

```Swift
if #available(iOS 14.0, *) {
    self.navigationItem.backButtonDisplayMode = .minimal
}
```

### 注意
バックボタンの見た目は制御できますが、長押しした際のリストは画面タイトル(`self.title`)もしくはバックボタン(`backButtonTitle`)の文言が表示されます。

もし何も文言を入れてないと空欄にまたは同じ文言を入れると、どこの画面に戻るかぱっと見でわからなくなってしまいます。

例　同じ文言
![Screen Shot 2020-11-14 at 15.37.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80912/c765ab16-aef0-dd70-054c-1e9f65c6e36b.png)

iOS 14のバックボタンの対応として長押しした際にどこの画面に戻るか分かる文言を設定してあげるといいです。
JavaScript基本文法【変数】

##はじめに

現在、JavaScriptの独学をしています。

復習を兼ねて、今回は変数についてまとめます。

私と同じようにJavaScript初心者の方の参考になればと思います。

##変数

変数の宣言方法は3種類あります。

```Javascript
const 変数名 = 初期値;
let 変数名 = 初期値;
var 変数名 = 初期値;
```

この3種類には以下のような違いがあります。

+ constの特徴
再代入できない、再定義できない。

+ letの特徴
再代入できる、再定義できない。

+ varの特徴
再代入できる、再定義できる。

基本はconstだけを使い、それだけでは対応できないときにletを使います。

varは再代入と再定義ができてしまい、不具合の原因になるので、使わないようにしましょう。

また、JavaScriptではキャメルケースで変数名をつけます。

```Javascript 
const constNumber = 100;
```

これはどの宣言方法でも同じです。
Next.js + MaterialUIでfontを指定する

# 手順

- 使用したいfontファイル(woff/otfなど)を`public/fonts`配下に設置
- `@font-face`を記載したcssファイルも同様に`public/fonts`配下に設置
- `_document.tsx`のheadタグにlinkタグ設置`<link rel="stylesheet" href="fonts/fonts.css" />`
- `_app.tsx`内でProviderに渡す`theme`を作成(`styles/theme.ts`に作成)
- 作成した`theme.ts`を`_app.tsx`で`import`する

# 実際のコード

```css:public/fonts/fonts.css
@font-face {
  font-family: 'fontname';
  font-weight: normal;
  font-style: normal;
  src: url('./fontname.woff');
}
```

```tsx:src/pages/_document.tsx
import React from 'react'
import NextDocument, { Head } from 'next/document'

return (
// 略
 <Head>
   <link rel="stylesheet" href="fonts/fonts.css" />
 </Head>
// 略
)
```

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

let theme = createMuiTheme({
  typography: {
    fontSize: 16,
    fontFamily: ['fontname'].join(',')
  }
})
export default theme
```


```tsx:src/pages/_app.tsx
import React, { useEffect } from 'react'
import {
  ThemeProvider as MaterialUIThemeProvider,
  StylesProvider
} from '@material-ui/styles'

import theme from '../../styles/theme'

const MyApp = ({ Component, pageProps }: any): JSX.Element => {

  return (
      <StylesProvider>
        <MaterialUIThemeProvider theme={theme}>
          <CssBaseline />
          <div>{pageProps.appData}</div>
          <Component {...pageProps} />
        </MaterialUIThemeProvider>
      </StylesProvider>
  )
}

export default MyApp
```
細かすぎて伝わらないSlackの文字入力時のショートカットキー

# モチベーション
* 最近Slackに入り浸っており、タッチパッドでの操作がだるくなってきた
* ショートカットを覚えようとしたらメッセージ入力用のショートカットがMacの標準と、なんか微妙に違う
* 勢いで調べてしまったのでもったいないから記事した


## 移動系

```
Ctrl+F 一文字前へ
Ctrl+B 一文字後へ
Ctrl+P 一行上へ
Ctrl+N 一行下へ
Ctrl+A 行頭
Ctrl+E 行末
Ctrl+V 文末（どこの文化圏？)
```

## 編集系
```
Ctrl+D Delete
Ctrl+H Backspace
Ctrl+K 行末まで削除
Ctrl+U 行頭まで削除…のはずだけど効かない❌
Ctrl+O カーソル行の上に1行挿入のはずだけど...一文字戻るだけ。謎。
```

## 変態向け
```
Ctrl+T カーソルの前後の文字を入れ替え
Ctrl+Y ヤンクペースト(Ctrl+Kで削除したものをペースト）
```

# おまけ
* 普通のSlackのショートカット一覧は`command + /`で出る (Thanx! [Kentaro](https://twitter.com/I0l0Ngm))
* メッセージ入力欄にカーソルがある状態で`上キー`を押すとフォーカスが移動するので`R`押すとリアクション用のダイアログが開き、カーソルで選択できるのだが、`Enter`で決定するとダイアログが閉じてしまうが、`Shift+Enter`にすると連続的にリアクションを付ける事ができる。（下記スクリーンキャスト参照）

![ezgif-5-b7b0291d5124.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26446/e6f22147-3096-74a1-65dd-6e0d1dd80924.gif)
Python Seleniumを使用してhtmlのカスタムデータ属性を要素として取得したい

HTML文書で、idは文書中で一意ですがclassはそうでないので、文書中に同一class名が複数ある場合はfind_elements_by_class_name()の結果を回す必要がある場合があります(elementにsがついてます)。
たとえば、属性を含めると一意になるのであれば、get_attribute()を使用して属性を取得し、自分の考えるものであれば、自分の行いたい処理（たとえばクリックとか）をすれば良いです（下記コード参照）。
そうでなければ、一意になる方法をその文書で考えて対応しなければならないと思います。
ブラウザの開発ツールで取得できるxpathやcssセレクターは一意になるので有効だと思うんですけどね。

```python

elems = driver.find_elements_by_class_name("クラス名(*1)") # *1:適切なクラス名を指定してください。
for elem in elems:
    attr = elem.get_attribute("属性名(*2)") # *2:適切な属性名を指定してください。
    if (attr == "自分が一致すると思われる属性値"):
        elem.click()
```
ブックマークレット でcookie情報をアラート

# この記事は
chrome のブックマークで、cookieの情報をalertする方法を解説します。
# なぜ？
cookie情報を確認する時、いちいちF12開発者ツールを起動して、目的のcookie を取得するのが面倒だったので、
ブックマークからササっと確認したかった。
# 環境
chrom 86.0.4240
# コード
"SID"という名前のcookieを取得する例です。

```javascript:コード
javascript:(function(){
    var cookieItem = document.cookie.split(";");
    for (i = 0; i < cookieItem.length; i++) {
      if (cookieItem[i].match(/SID/)) {
          alert(cookieItem[i]);
      }
    }
})();
```

# コード解説
```javascript:解説1
    var cookieItem = document.cookie.split(";");
```
document.cookieで、cookie情報をすべて取得します。
また、cookieは「A=a;B=b;C=c;」の形なので、「;」で分割して配列に格納します。

配列
-要素1:A=a;
-要素2:B=b;
-要素3:C=c;

```javascript:解説2
    for (i = 0; i < cookieItem.length; i++) {
      if (cookieItem[i].match(/SID/)) {
          alert(cookieItem[i]);
      }
```
さきほどの配列の中から、"SID"の文字列を探し、アラートします。

# 動かし方
1.ブックマークに登録
chromeのブックマーク機能で、「URL」欄に上記コードを入れます。「名前」は何でも構いません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/445755/483d0552-7d79-6360-17ba-a78e9f2e4f65.png)

2.ブックマークを選択

3.ダイアログがでてくれば成功です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/445755/773edf6f-7415-5540-776a-6a7829b99e90.png)




# まとめ
SIDの部分を書き換えて、web画面のテストなどにお使いください。
cookieを書き換える事もできるようなので、そちらを駆使すれば応用が広がるかもしれません。
OPcacheが有効になっているPHP-FPMをRead Onlyコンテナで動かす

# 環境

![PHP7.3](https://img.shields.io/badge/php-7.3-blue.svg) ![opcache](https://img.shields.io/badge/opcache-enable-blue.svg) ![Docker](https://img.shields.io/badge/docker-grey.svg) ![php-fpm](https://img.shields.io/badge/php_fpm-grey.svg)

# 前提

- OPcache
    - キャッシュ有効化
    - file_cache_onlyが無効
    - lockfile_pathが/tmp
- PHP-FPM
    - pidへのファイルパスなし
- Docker
    - Read Only mode

# 方法

opcacheのロックファイルが作成される/tmpにvolumeをマウントします。

```bash
docker run -d -p 9000:9000 --read-only -v $(pwd)/tmp:/tmp php:7.3-fpm-alpine3.12
```

# 解説

なぜ/tmpにvolumeをマウントさせるのかを説明します。
opcacheは共有メモリにキャッシュするためにロックファイルが必要です。
zend_shared_alloc_create_lock関数内で、mkstempをコールして/tmpにロックファイルを作成します。
作成失敗の場合は、`Unable to create lock file`というエラーメッセージを出力後に異常終了します。

```c:ロックファイルの作成関数
void zend_shared_alloc_create_lock(char *lockfile_path)
{
	int val;

#ifdef ZTS
    zts_lock = tsrm_mutex_alloc();
#endif

	snprintf(lockfile_name, sizeof(lockfile_name), "%s/%sXXXXXX", lockfile_path, SEM_FILENAME_PREFIX);
	lock_file = mkstemp(lockfile_name);
	fchmod(lock_file, 0666);

	if (lock_file == -1) {
		zend_accel_error(ACCEL_LOG_FATAL, "Unable to create lock file: %s (%d)", strerror(errno), errno);
	}
	val = fcntl(lock_file, F_GETFD, 0);
	val |= FD_CLOEXEC;
	fcntl(lock_file, F_SETFD, val);

	unlink(lockfile_name);
}
```

zend_shared_alloc_create_lockはzend_shared_alloc_startupからコールされ、実行時設定のlockfile_pathを引数として渡します。

```c:zend_shared_alloc_create_lockの呼び出し元
int zend_shared_alloc_startup(size_t requested_size)
{
/* 省略 */

#ifndef ZEND_WIN32
	zend_shared_alloc_create_lock(ZCG(accel_directives).lockfile_path);
#else
	zend_shared_alloc_create_lock();
#endif
```

# Reference

- https://www.php.net/manual/ja/opcache.configuration.php
- https://www.php.net/manual/ja/install.fpm.configuration.php
- https://github.com/php/php-src/blob/PHP-7.3/ext/opcache/zend_shared_alloc.c
【Rails】Bootstrapのtext-lightをlink_toメソッドに継承できないのは、メソッドに引数としてクラスを書いていないのが原因らしい

##はじめに
BootstrapをRails環境に導入し、きれいにしていくぞ～って思ったらいきなり躓いたので共有します。

##事象
どうしてもlink_toメソッドの要素に継承されない

###HTMLで記載したときはテキストに白色が適用されている
![image (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/499617/6c8607d2-5842-1699-7f3a-2b4005f04482.png)

```bash:index.html
<body> 
  <nav class="navbar navbar-expand-sm navbar-dark bg-dark"> 
    <ul class="navbar-nav mr-auto"> 
      <li class="nav-item"><a class="nav-link" href="">tweetApp</a></li> 
    </ul> 
  </nav>
```

###なぜかlink_toに置き換えると継承されない
navbar-darkクラスを設定してるので、文字色が白になるはずだが、青になっている。
![image (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/499617/3794a9f1-d1b3-3791-95d8-80cbf516da5a.png)

```bash:index.erb
<nav class="navbar navbar-expand-sm navbar-dark bg-dark"> 
    <ul class="navbar-nav mr-auto"> 
      <li class="nav-item"> 
        <a class="nav-link" href=""> 
          <%= link_to('tweetApp',"/") %> 
        </a> 
      </li> 
    </ul> 
  </nav>
```


##DevtoolでCSSを生成されたHTMLを見ると、、、
生成されたリンクがaタグから飛び出てる、、、

```bash:index.erb
<nav class="navbar navbar-expand-sm navbar-dark bg-dark"> 
    <ul class="navbar-nav mr-auto"> 
      <li class="nav-item"> 
        <a class="nav-link" href=""></a> 
        <a href="/">tweetApp</a> 
      </li> 
    </ul> 
  </nav>
```

##link_toメソッドにはクラスを指定するオプションが存在する模様

書式　`link_to(リンクテキスト, パス [, オプション, HTML属性 or イベント属性])`
classオプション　`class: "クラス名"`
参考　[Railsドキュメント-ビューについて](https://railsdoc.com/view)


##書式に従って記載してみる

```bash:index.erb
<nav class="navbar navbar-expand-sm navbar-dark bg-dark"> 
    <%= link_to("TweetApp","/",class: 'text-light')%> 
  </nav>
```

##結果、、、できた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/499617/74ba9b06-7a6d-4987-fd68-8c5ee1e26ed2.png)
現在時刻とnowという変数名を考える

ペアプロのときに現在時刻を取得する云々の処理があり、これを毎回伝えるのはしんどいのでメモがてら残したいと思います。

# nowとは何時なのだ？
個人的に現在時刻を格納するような変数名は原則nowを使うべきではないと思います。

理由はシンプルで、now（現在時刻）がいつの時刻でどう言った意図なのかわからないからです。

例えばバッチ処理を考えたときに

```ts
let now = Date.date.now();
console.log(`start: ${now}`)

// バッチ処理

now = Date.date.now();
console.log(`start: ${now}`)
```

（そもそもconst使えというのは置いておいて）この場合nowという単語に開始時刻、終了時刻という意味合いを含んでいます。
今回はコードの前後の見れば把握できますが、レイヤードアーキテクチャーのある層でnowとかの変数名が出てきたら、もはや意味がわかりません。

以上の理由から、少なくともnowではなく、就職する言葉を付けて変数を命名してくれといいます。

# nowが許されるとき
testの時かなと思います。
テストの場合はテストケースと意図が明確が書かれている + 現在時刻に依存している処理をしようとしているということなので、特にコードを読むときに迷うことはないと思います。

# 最後に
現在は、時刻を扱うライブラリとそれをモックするライブラリが充実しているため、テストが大変という感覚はなくなりました。
ただ、変数名はライブラリが幾ら進化しようと関係ないので、ここら辺は布教していきたいです。
データベース検索の基本まとめ(SQL)

## 前書き
RDB環境: MySQL 5.6.50
GUIツール: Sequel Pro
テーブル: users, shifts（seedファイルで予め用意した情報を読み込み済）

#### users
|カラム名|内容
|----- |--- |
|family_name | 苗字 |
|first_name|名前|
|age|年齢|
|prefecture|出身地|

##  検索方法
###### テーブルの全てのデータを検索する

```:クエリ
SELECT * FROM users
```

[![query_result](https://i.gyazo.com/39ae08a39305414507f2b0bfd62622c9.png)](https://gyazo.com/39ae08a39305414507f2b0bfd62622c9)


###### 条件にあったデータを取得する
* WHERE  
取得するレコードの条件を指定する。

```:クエリ
SELECT *
FROM users
WHERE family_name = "阿部"
```

[![query_result](https://i.gyazo.com/10fd894c4ea0bb8ae4651572c63393bb.png)](https://gyazo.com/10fd894c4ea0bb8ae4651572c63393bb)

* LIKE  
文字列検索を可能にする。  
曖昧検索には%を使う。

```:クエリ
SELECT *
FROM users
WHERE prefecture LIKE '%都'
```

[![query_result](https://i.gyazo.com/b06706b210ba475ac5e86f40706c475c.png)](https://gyazo.com/b06706b210ba475ac5e86f40706c475c)

* AND  
複数の条件を組み合わせる。  
全ての条件を満たせばtrueとなる。

```:クエリ
SELECT *
FROM users
WHERE prefecture LIKE '%都' AND age = 22
```

[![query_result](https://i.gyazo.com/4a87c4de56c6ed54540a325b6159c8f3.png)](https://gyazo.com/4a87c4de56c6ed54540a325b6159c8f3)

* OR  
複数の条件のうちいずれかを満たせばtrueとなる。  

```:クエリ
SELECT *
FROM users
WHERE age <= 20 OR prefecture = "東京都"
```

[![query_result](https://i.gyazo.com/af2731866e2ace4bdf0a8c5baa06d04e.png)](https://gyazo.com/af2731866e2ace4bdf0a8c5baa06d04e)  

* NOT  
条件に当てはまらないデータを取得する。

```:クエリ
SELECT *
FROM users
WHERE NOT prefecture = "東京都"
```  

[![query_result](https://i.gyazo.com/8ab4f170471f4b4c5adce5e5a2ed0f87.png)](https://gyazo.com/8ab4f170471f4b4c5adce5e5a2ed0f87)

* BETWEEN  
範囲指定した条件にあったデータを取得する。

```:クエリ
SELECT *
FROM users
WHERE age BETWEEN 21 AND 24
```

[![query_result](https://i.gyazo.com/1618cd618886c5883024016f74563b71.png)](https://gyazo.com/1618cd618886c5883024016f74563b71)

* IN  
特定の条件が含まれるデータを取得する。

```:クエリ
SELECT *
FROM users
WHERE prefecture IN ("東京都", "神奈川県")
```

[![query_result](https://i.gyazo.com/ce26064ee972ee363990a477eed1de50.png)](https://gyazo.com/ce26064ee972ee363990a477eed1de50)

## 要点整理
* WHEREとは、取得するデータを「条件」によって制限できる.
* LIKEとは、文字列検索を行う際に使用できる句のこと。
* AND演算子とは、複数の条件がすべて正しい場合に、正とすることができる演算子。
* OR演算子とは、複数の条件のうち、1つ以上を満たしたデータを取得する演算子。
* NOT演算子とは、条件が正しくない場合に正となり、言わば否定形の演算子。
* BETWEEN演算子とは、上限と下限を設定し、その範囲に含まれる場合は正となる演算子。
* IN演算子とは、1つのカラムに対しリストを指定して、カラムの値がそのリストに含まれるとき、その式は正になるという演算子。
【初心者必見】RailsアプリをHerokuに公開するのにrails_12factorは不要

表題の通りの記事です。

RailsアプリケーションをHerokuにデプロイする方法を説明した記事では、よく`rails_12factor` gemのインストールが手順に含まれていることがあります。
ですが、このgemはRails 5以降では不要になっています。

```ruby:Gemfile
group :production do
  # Rails 5以降ではrails_12factorは不要！！
  gem 'rails_12factor'
end
```

Rails 5がリリースされたのは2016年で、もう4年以上の月日が経っています。
Rails 6が最新版となっている2020年現在では、わざわざRails 4以前のRailsアプリを新たにデプロイしようとする人はごくわずかでしょう。
よって、このgemのインストールが必要な場面はもはやないと断言できます。

今のところ、Rails 5以降でこのgemをインストールしても問題は起きないようですが、最終リリース日が2014年10月14日になっていることから、gemのメンテナンスはすでに止まっていることが想像されます。（[参考](https://rubygems.org/gems/rails_12factor)）

![Screen Shot 2020-11-14 at 14.42.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7465/4b45c023-1ebe-8f02-c908-48c50b34ad76.png)

メンテナンスが止まっているので、今は問題が起きなくても、将来的にこのgemを使い続けることで、何か問題が発生する可能性も否定できません。
損することはあっても得することはないので、さっさとアンインストールすることをお勧めします。

## 余談：手軽な情報源よりも信頼できる情報源を

ここから下は余談です。

個人的な観測範囲では、`rails_12factor` gemのインストールを手順に含めた記事を書いている人は、プログラミング初心者が多い気がします。
そして、これも僕個人の推測ですが、そういう人はネットで見つけた日本語の記事を参考にして、Herokuのデプロイ手順を再生産している気がします。

こうなると、親ガメが子ガメを生み、子ガメが孫ガメを生み、孫ガメが・・・というように、どんどん古い内容の記事が再生産されていってしまいます。

たしかに、「ググって見つけた日本語の記事」を参考にするのはラクです。
ラクですが、その記事が正確で信頼できる情報とは限りません。
記事が書かれた当時は正しくても、時間が経った現在では使い物にならない情報になっている可能性もあります。

では、正確で信頼できる情報源は何でしょうか？
それは言語やライブラリ、プラットフォームの公式情報です。

Herokuへのデプロイ手順であれば、Heroku自身が公開している以下の記事がそれにあたります。
Herokuへのデプロイ手順を知りたいのであれば、この記事を一番に参照すべきです。

[Getting Started on Heroku with Rails 6\.x \| Heroku Dev Center](https://devcenter.heroku.com/articles/getting-started-with-rails6)

この記事の中では、「 `rails_12factor` はもういらない」ということがハッキリと明記されています。

> Previous versions of Rails required you to add a gem to your project rails_12factor to enable static asset serving and logging on Heroku. If you are deploying a new application, this gem is not needed. 

（筆者訳）

> Railsの以前のバージョンではHeroku上で静的なアセットとロギングを有効化するために rails_12factor gemを追加する必要がありました。新しいアプリケーションをデプロイする場合、このgemは必要ありません。

英語を読むのは大変かもしれませんが、これからエンジニアを目指す初心者のみなさんはこの先英語を避けて通れません。
プロのエンジニアを目指すなら「読むのはラクだけど不正確な情報」よりも、「多少しんどくても正確で信頼できる情報（＝多くの場合英語の公式情報）」を参照するようにしましょう。

`rails_12factor` gemをインストールしたぐらいであれば大きな問題は起きませんが、この先もしかすると不正確な情報を参考にしてしまったために、セキュリティ上の大きな不具合を抱えたアプリケーションを作ってしまうかもしれません。
そういった大きなミスを犯す前に、今から信頼できる情報源を参照するクセを付けることを強くお勧めします。
【DynamoDB】DynamoDBの 可用性 / 拡張性

## バックアップ
### オンデマンドバックアップ
- バックアップ操作を行った時点のテーブルデータを全て保存する
- バックアップは全てカタログ化され、検索が容易な状態で保たれる

### 連続的バックアップ
- 有効にした時点からDynamoDBのテーブルに対する全ての更新処理が記録される
- 最大35日間のバックアップを保存可能
- 保存されている期間内であればポイントインタイムリカバリが可能

## DynamoDBストリーム
DynamoDBに加えられた変更を24時間保存するサービス
**CDC（Change Data Capture）**と呼ばれる機能

- 有効にすると、DynamoDBストリーム専用のエンドポイントが提供される
- エンドポイントにアクセスすることで時系列データを取得出来る
- ほぼリアルタイムで変更内容が反映されるため、新規データ追加時にクライアントのモバイルにプッシュ通知するなどの用途に利用可能
- 24時間以内の削除・変更に関してはポイントインタイムリカバリを行わずに特定の項目の復旧が可能

## スループットキャパシティ
RCU（Read Capacity Unit）とWCU（Write Capacity Unit）のこと

### RCU（Read Capacity Unit）
読み込みのスループットキャパシティ

- 1RCUあたり **4KBまでの項目を1秒間に2回** 読み込み可能
- 強力な整合性の読み込みを行った場合はキャパシティを2倍消費する

### WCU（Write Capacity Unit）
書き込みのスループットキャパシティ

- 1WCUあたり **1KBまでの項目を1秒間に1回** 書き込み可能

### 設定方法
**1. プロビジョニングされたキャパシティ（Provisioned Capacity）**
スループットキャパシティの値として固定値を設定する方法
スループットキャパシティにはソフトリミットがかけられている

**2. Auto Scaling**
RCOとWCUにそれぞれ最小キャパシティユニット、最大キャパシティユニット、ターゲット使用率の値を設定し、リクエスト数によってスループットキャパシティを自動的に拡張・縮退する
スループットキャパシティは現在の使用率がターゲット使用率に近付くよう調整される

**3. リクエストごとの支払い（On-Demand）**
発生したリクエスト分だけキャパシティユニットを消費し、消費したキャパシティユニットの量に応じて料金が発生するため、スループットキャパシティの設定が不要

※ 設定の変更は無停止で行うことが可能

## DynamoDB Accelerator
DynamoDBのインメモリキャッシュサービス

- DynamoDBよりも高速な読み込みが必要な場合に使用する
- DAXを利用するアプリケーションは、DAXクライアントを使用してDAXに接続する

**結果整合性の読み込みクエリを実行した場合**：DAXはキャッシュを確認してキャッシュがあればそれをクライアントに返し、キャッシュが無かった場合DynamoDBからデータを取得してDAXにキャッシュとして格納し、クライアントにクエリの結果を返す（遅延読み込み）

**強力な整合性の読み込みクエリを実行した場合**：DAXは何もせずDyanmoDBにクエリを発行し、レスポンスをそのままクライアントに返す（キャッシュは格納されない）

**書き込みクエリを実行した場合**：DynamoDBに書き込みが行われ、書き込んだデータがDAXのキャッシュにも格納される（書き込みスルー）
【DynamoDB】DynamoDBとは

## DynamoDBとは
キーバリューストア型のデータストアのマネージドサービス

- NoSQLデータベース
- データは3つのAZに分散して格納される
- 格納容量に上限がない
- データ取得のレイテンシーが低いため、キャッシュの用途にも利用出来る
- ビッグデータ処理、大量データ処理が必要なアプリケーション、Web行動データ、ログ管理等に利用
- トランザクション機能は備えていない

## テーブル設計
- **テーブル**：データのコレクション
- **項目**：項目間で一意に識別可能な属性グループであり、テーブルを構成する要素
- **属性**：各項目を構成する要素

<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379501/8090d8ab-1c47-85d4-8243-5d0ab5d07cd4.png">

### プライマリーキー
ハッシュキーのみでユニーク、もしくはハッシュキー＆レンジキーの2つでユニークのいずれかのタイプが指定可能

**1. ハッシュキー**

- KVSにおけるキーに相当するデータを一意に特定するためのIDなどのこと
- テーブル作成時に1つの属性を選び、ハッシュキーとして宣言
- 単独での重複を許さない

**2. レンジキー**

- テーブル作成時に2つの属性を選び、1つをハッシュキー、もう1つをレンジキーとして宣言
- 2つの値の組み合わせによって1つの項目を特定
- 単独であれば重複が許される

### インデックス
**1. 暗黙的なキー**

- データを一意に特定するため特定するために暗黙的にキー（ハッシュキーやレンジキー）として宣言して検索に使用するインデックス
- 1テーブルに1つ宣言する

**2. 明示的なキー**

- **ローカル・セカンダリ・インデックス（LSI）**：プライマリキーのタイプが、ハッシュキー＆レンジキーの場合のみ設定可能で、別の規則でのインデックスを可能にする（テーブル作成時に作成）

- **グローバル・セカンダリ・インデックス（GSI）**：ハッシュキーの属性の代わりになり、ハッシュキーをまたいだ自由な検索を可能にする（テーブル作成後に作成）

## 読み込みの種類
以下2種類の読み込みはクエリ発行ごとに指定可能

**1. 結果整合性の読み込み**
・デフォルトの読み込み

**2. 強力な整合性の読み込み**
・書き込まれたデータが3つのAZに完全に保存されたデータのみを読み込む
・結果整合性の読み込みと比較してRCUを2倍消費する

※ 書き込みは少なくとも2つのAZでの書き込み完了が確認出来たら完了

## DynamoDB Local
DynamoDBのエンジンのみのライブラリ
AWS環境にアプリケーションをデプロイしなくてもローカル環境でDynamoDBとアプリケーションの連携テストを実行可能

## セキュリティ
### アクセス制御
- テーブルへのアクセス制御にはIAMポリシーを使用
- DynamoDBテーブルにアクセスする際は、アクセスを許可したIAMポリシーをアタッチしたIAMロールやIAMユーザーを使用する

### 暗号化
- KMSを利用してデータの暗号化が出来る
- 暗号化設定はテーブル作成時にのみ可能
- 使用するKMSのキーは全テーブル共通
- 暗号化されたテーブルへのアクセスには、KMSへのアクセス許可があるIAMポリシーが必要
【JavaScript】getElementsByTagNameの結果を配列にして配列のメソッドを使う方法

`getElementsByTagName`した結果をfindしたかったのですが、そのままでは使えないんですね。
HTMLCollectionオブジェクトが返ってきました。

sliceを使って、配列にしてみました。

```JavaScript
const tags = document.getElementsByTagName('script');
const targetTag = Array.prototype.slice.call(tags).find(c => c.src?.match(/test.com/)));
```

もしくは、Array.fromで、

```JavaScript
const tags = document.getElementsByTagName('script');
const targetTag = Array.from(tags).find(c => c.src?.match(/test.com/)));
```

もしくは、スプレッド演算で、

```JavaScript
const tags = document.getElementsByTagName('script');
const targetTag = [...tags].find(c => c.src?.match(/test.com/)));
```
polyglotを使ってpythonで形態素解析をする準備から品詞タグ付けまで


## 準備

polyglot ([ドキュメント](https://polyglot.readthedocs.io/en/latest/index.html)) を使っていく．

以下は Python 3.8.5 で動作を確認した．
まず，

```terminal
pip install numpy
pip install polyglot
pip install six
pip install pycld2
pip install morfessor
pip install pyicu
```

の順番でインストール．
ただし，ModuleNotFoundError で `icu` を入れろと言われた時は

```terminal
pip install icu
```
ではなく

```terminal
pip install pyicu
```
とする．`icu` をインストールして使おうとすると `cannot import name xxx` のエラーが出てくるはず．別物なので注意．

ここでうまくいかない時は，[Error installing pip pyicu](https://stackoverflow.com/questions/40940188/error-installing-pip-pyicu) を見る．

## 解析していく

公式の [Part of Speech Tagging](https://polyglot.readthedocs.io/en/latest/POS.html) を見て，品詞を調べてみる．

```Python3
from polyglot.text import Text

blob = "You never fail until you stop trying."
tokens = Text(blob)
print(tokens.pos_tags)
```

これで文章中の全ての単語の品詞がわかるはずだが，エラーが出るはず．

```
ValueError: This resource is available in the index but not downloaded, yet. Try to run

polyglot download embeddings2.en
```

というわけで

```
git clone https://github.com/web64/nlpserver.git
```
した後に，`nlpserver.py` の 14 行目に

```Python3
app.config['JSON_AS_ASCII'] = False
```
を追加した後に，

```
polyglot download embeddings2.en
polyglot download pos2.en
```

を入れる．この部分は，[Not able to pull polyglot files](https://github.com/web64/nlpserver/issues/1) に書いてあった．

これで英語の解析ができるようになったので，先ほどのコードは動き，

```Python3
from polyglot.text import Text

blob = "You never fail until you stop trying."
tokens = Text(blob)
print(tokens.pos_tags)
```
の結果として

```
[('You', 'PRON'), ('never', 'ADV'), ('fail', 'VERB'), ('until', 'SCONJ'), ('you', 'PRON'), ('stop', 'VERB'), ('trying', 'VERB'), ('.', 'PUNCT')]
```
が得られる．
結果が一行じゃ見にくいから，最後の行を `pprint` を使って

```Python3
import pprint
pprint.pprint(tokens.pos_tags)
```
とすることで

```
[('You', 'PRON'),
 ('never', 'ADV'),
 ('fail', 'VERB'),
 ('until', 'SCONJ'),
 ('you', 'PRON'),
 ('stop', 'VERB'),
 ('trying', 'VERB'),
 ('.', 'PUNCT')]
```
とする，など工夫しても良い．
品詞の名前は以下の通り．省略名と説明 (英語) の部分は [Part of Speech Tagging](https://polyglot.readthedocs.io/en/latest/POS.html) から持ってきた．

| 省略名 | 説明 (英語) | 説明 (日本語) |
| :--- | :--- | :--- |
| ADJ | adjective | 形容詞 |
| ADP | adposition | 接置詞 |
| ADV | adverb | 副詞 |
| AUX | auxiliary verb | 助動詞 |
| CONJ | coordinating conjunction | 等位接続詞 |
| DET | determiner | 限定詞 |
| INTJ | interjection | 間投詞 |
| NOUN | noun | 名詞 |
| NUM | numeral | 数詞 | 
| PART | particle | 不変化詞 |
| PRON | pronoun | 代名詞 |
| PROPN | proper noun | 固有名詞 |
| PUNCT | punctuation | 句読点 |
| SCONJ | subordinating conjunction | 従属接続し |
| SYM | symbol | 記号 |
| VERB | verb | 動詞 |
| X | other | そのほか |

## 参考

インストールの参考
https://qiita.com/sawada/items/528da0b22546045122b2

polyglot の特徴についての参考
http://lab.astamuse.co.jp/entry/try-polyglot
イーサリアム2.0について調べてみた

# はじめに
最近こんな記事を読みました。

[イーサリアム2.0への預け入れ、1週間で約25億円](https://www.coindeskjapan.com/87485/)
>新しいPoSネットワークのバリデーター（トランザクションの処理を行い、PoWネットワークのマイナーに相当する）になるためには、最低32イーサリアム（約150万円）をネットワークにステーキング（預け入れ）する。

約150万円かー。高いけど、誰でもバリデーターになれたらPoSが成り立たないから、これくらいが丁度いいんだろうなぁ。
>イーサリアム2.0が稼働すると、バリデーターは年間8～15%程度の報酬を得ることができるようになる。

年間8～15%程度の報酬って、株式投資とかより高利回りでなんか良さそう。

そんなことを思いながら、150万円投資する価値があるのか気になったのでいろいろ調べてみました。
# Ethereum 2.0
Ethereum 1.0から大きく変わるのは次の2点です。

1. 合意形成アルゴリズムがプルーフ・オブ・ワーク(PoW)からプルーフ・オブ・ステーク(PoS)に移行
2. シャーディングを導入

それぞれについて詳しく見ていきましょう。
## プルーフ・オブ・ステーク(PoS)
Ethereumをたくさん持っている人の方がブロックチェーンにブロックをつなぐ役割を得やすくなる仕組みです。攻撃者が攻撃をするためにはEthereumをたくさん持たなければならず、結果的に自分で自分を攻撃することになるので攻撃を抑止できるという理屈ですね。PoWと比較したPoSのメリットとデメリットは次の通りです。

メリット

- PoWで問題になっていたマイニングによる電力消費の問題がなくなるため、環境にやさしい。

デメリット

- バリデーターとしてEthereumを保有し続ける人が多くなるため、流動性が低くなる。

環境への配慮ができているのは時代の流れにもマッチしていますね！
## シャーディング
ブロックチェーンの弱点としてよく言われるのが「合意形成が必要なためスループットが低い。」という点です。シャーディングはこの問題に対する答えの一つで、ブロックチェーンにスケーラビリティをもたらします。そのため、Ethereum 2.0はBeacon Chainと呼ばれる全体を管理するブロックチェーンとShard Chainと呼ばれる実際にユーザーが使う複数のブロックチェーンから構成されます。
はじめの記事に出てきた「ジェネシスイベント」というのは、Beacon Chainを有効化するイベントのことを指しています。
# Ethereum 2.0への移行に向けた現在位置とこれから
Ethereum2.0への移行に向けた開発は次の4つの段階で構成されています。

1. 2015年7月～　フロンティア（Frontier）
2. 2016年3月～　ホームステッド（Homestead）
3. 2017年10月～　メトロポリス（Metropolis）
4. 2020年12月～　セレニティ（Serenity）

現在（2020年11月）はちょうど最終段階であるセレニティの幕開け直前となっています。そしてセレニティは更に次のフェーズから構成されています。

1. Phase0: Beacon Chainのみが稼働している状態
2. Phase1: Shard Chainが稼働している状態。ただし、データの記録のみで、スマートコントラクトは実行できない。
3. Phase2: Shard Chainでスマートコントラクトが実行できる状態。

つまり「ジェネシスイベント」によってBeacon Chainが有効化されると、そこからセレニティのPhase0が始まるということですね！Phase1とPhase2の開始時期は現時点ではまだ未定のようです。
# 最後に
Ethereumがこのまま予定通り2.0に移行し、スループットの問題も解決して流動性を保っていけるのかは現時点ではまだまだ不透明だと思います。その不透明性のリスクと年利8～15%を天秤にかけて投資するかどうかを決めるのでしょうが、純粋にリスクとリターンだけで考えるとまだ足踏みしてしまう人の方が多いのではないでしょうか？今はまだEthereumを支持する人たちが応援の意味を込めて投資している段階だと思いますが、この勢いが盛り上がって一般の投資家も巻き込んでいくようになると、明るい将来が待っていると思います。
これから先、どうなっていくのか楽しみですね！

#2020年11月25日追記
12月1日にジェネシスイベントが開始されることが決まりましたね！
[イーサリアム2.0、12月1日にフェーズ0がスタート──ジェネシス・ブロックを設定](https://www.coindeskjapan.com/89576/)
セッションIDの取得と再発行

##セッションID取得
`session_id()` = `現在のセッションIDを取得または設定する。`

```

<?php
$start = session_start();
?>
 
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<body>
 
<?php
if( $start === true ){　
  echo session_id(); // セッションスタートしていたら、セッションIDを取得して表示。
} else { 
  echo "セッションの作成に失敗しました！";  //セッションスタートされていなければ表示。
}

</body>
</html>
```

##セッションIDの再発行
`session_regenerate_id()` =  `現在のセッションIDを新しく生成したものと置き換える。`

ページを読み込む度にセッションIDは更新されます。
ユーザーがログインして機密性の高い情報を$_SESSIONに格納する時に、`新しいセッションIDを再発行することでセッションIDの漏洩によるデータの盗聴リスクを下げることができます。`

```
<?php
session_start();  // セッション開始
session_regenerate_id(); // セッションID再発行
echo session_id();  // 再発行されたセッションIDを表示
?>
```



参考元はこちら
セッションID取得：(https://webkaru.net/php/function-session-id/)
　　　　　　　　　(https://wepicks.net/phpref-session/#0)
セッション開始と削除

先ずは`セッション`について少しでも理解しておいた方がいいので、是非こちらの記事を参考にしてください。
セッション：https://qiita.com/yyy752/items/676cf3c3751c70aea7f2
クッキー：https://qiita.com/yyy752/items/9cc85104c3eba900ca3a

##セッション開始
`session_start()` = `新しいセッションを開始、あるいは既存のセッションを再開する。`

```
<?php
session_start();　
?>
```

##セッション削除
`session_destroy()` = `セッションに登録されたデータを全て破棄する。`
session_destroy()では変数「$_SESSION」のデータは削除されない為、
`$_SESSION = array();`で変数のデータも削除しましょう。`


```
<?php
session_start();　// セッション開始
?>
 
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<body>
 
<?php
$_SESSION['data'] = "こんにちは！";　// セッションにデータを格納
$_SESSION['name'] = "佐藤さん";
 
print_r($_SESSION); echo "<br />";　// $_SESSIONのデータ「こんにちは！佐藤さん」を表示
 
$_SESSION = array();　// $_SESSIONのデータを削除
 
session_destroy();　// セッションを破棄

?>
 
</body>
</html>

```

参考元はこちら
(https://webkaru.net/php/function-session-destroy/)
Security Hubを始めた時の｢Ensure AWS Config is enabled｣という警告の対応

# 問題の状況
![スクリーンショット 2020-11-14 12.50.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32839/1eb85a99-f596-e0d3-694d-09eb72af67ee.png)

という感じで、｢CIS AWS Foundations Benchmark v1.2.0｣の結果表示が出てこない。

# 対応

AWS Configの設定を見直す。

Configを有効にだけすればよいかと思って、
｢このリージョンでサポートされているすべてのリソースを記録します｣だけONにしていたけれど足りない様子。

｢グローバルリソース (AWS IAM リソースなど) を含める｣もONにすることで解消する。

![スクリーンショット 2020-11-14 13.34.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32839/f2930afc-bd06-3af7-0c8c-6e8b2e8faf15.png)

きっと、モニタリングする対象がグローバルリソースの中にもあるからなのでしょうね。
Laravelで日付を操作しよう

実務でLaravelを使って日付検索をしたことがあるので、ここで共有+アウトプットをしておく。

リクエストで文字列で渡ってきた日付を操作する必要があったのですが、簡単に調べてみるとdate関数とstrtotime関数を使えば簡単にできそう

###date関数とstrtotime関数とは
公式より引用[date関数](php.net/manual/ja/function.date.php)
公式より引用[strtotime関数](https://www.php.net/manual/ja/function.strtotime.php)

* date関数・・・ ローカルの日付/時刻を書式化する。
指定された引数 timestamp を、与えられた フォーマット文字列によりフォーマットし、日付文字列を返します。 タイムスタンプが与えられない場合は、現在の時刻が使われます。

```PHP
date ( string $format [, int $timestamp = time() ] ) : string
```

つまり第一引数のフォーマットにしたがって、第2引数のtimestampが日付文字列で変換される模様。




* strtotime関数・・・英文形式の日付を Unix タイムスタンプに変換する
この関数は英語の書式での日付を含む文字列が指定されることを期待しており、 now で与えられたその形式から Unix タイムスタンプ (1970 年 1 月 1 日 00:00:00 UTC からの経過秒数) への変換を試みます。 now が指定されていない場合は現在日時に変換します。

```PHP
strtotime ( string $datetime [, int $now = time() ] ) : int
```

こちらは文字列型の日付をint型の時間で返す模様。

ここの第1引数で様々な操作ができます。
月、週、日付、時間など
ここではある日にちを第一引数としたものを1日追加してみましょう

```PHP
$day = "2020-11-12";
echo strtotime($d . "+1 day"); //1605225600
```

という具合です。


なのでstrtotimeで文字列型の日付を一度操作して、date関数の第二引数に当てはめます。

```PHP
$day = "2020-11-12";
echo date( "Y-m-d", strtotime($d . "+1 day")); //2020-11-13
```


という感じでリクエストで渡ってきた日付の文字列を操作できました。

使うこともあるかと思うので、是非参考にしてみてください。
ここでは紹介しませんが`Carbon`ライブラリというのもあるみたいなので、そちらも調べてみるといいかもです。





最後まで読んでいただきありがとうございました。

###参考文献
[strtotime関数](https://www.php.net/manual/ja/function.strtotime.php)
[date関数](https://www.php.net/manual/ja/function.date.php)
[qiita記事](https://qiita.com/kohboh/items/0e255dc3bba067bc447c)
「コンピュータシステムの理論と実装」のシミュレータをセットアップする (macOS)

macOS 10.15.7 で「コンピュータシステムの理論と実装」のシミュレータをセットアップしたときのメモ。

## パッケージのダウンロード
https://www.nand2tetris.org/software の `Download the Nand2tetris Software Suite` からダウンロードする。

## java のインストール

JDK はインストールしてなかったので、Homebrew でインストールした。

```shell-session
$ brew install java

$ sudo ln -sfn /usr/local/opt/openjdk/libexec/openjdk.jdk \
  /Library/Java/JavaVirtualMachines/openjdk.jdk

$ java -version
openjdk version "15.0.1" 2020-10-20d
OpenJDK Runtime Environment (build 15.0.1+9)
OpenJDK 64-Bit Server VM (build 15.0.1+9, mixed mode, sharing)
```

`JAVA_HOME` は設定しなくても動いたので特にいじってない。

## 起動と動作確認

```
$ /bin/sh ./nand2tetris/tools/HardwareSimulator.sh
```

シミュレータが起動したら以下を読み込む。

- `File > Load Chip` で `nand2tetris/projects/demo/Xor.hdl`
- `File > Load Script` で `nand2tetris/projects/demo/Xor.tst`

でもって Run ボタンを押すとテストスクリプトの実行が始まる。

![スクリーンショット 2020-11-14 13.29.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/9549/2b0c43d4-22c1-4729-3e67-66ef7b8c8d3b.png)

本のサンプルだと子ウィンドウが開いて Output が確認出来るようになっているけど、手元だと開かなかった。HDL ファイルと同じディレクトリに Xor.out ができていてそれで確認出来るのでまあ良いやということにした。
Facade Pattern

<font color="#00f">多数のFacade配下のクラスの利用をコントロールする。userはFacadeを通じてFacade配下のクラスを利用する</font>

[Design Pattarm MENU](https://qiita.com/old_cat/items/852d980bedb9100dd7e3)

以下のクラス構成で確認します

|package|アクセス修飾子|クラス|説明|
|------|-----|-----|-----|
|sample|public|facade.class|facadeが管理する各クラスの呼び出し、利用をコントロール|
|sample|default|sam0.class～sam2.class|int値を戻す|
|default|public|user(Main.class)|facadeを利用してsam0.class～sam2.classを利用する|

＊user　他の開発者がこのパターンを利用する、という意味合いを含みます

```java:facade.class
package sample;
public  class facade{
    int res;
    public facade(int condition){
        switch(condition){
          case  0 : res = new sam0().get();break; 
          case  1 : res = new sam1().get();break;
          default : res = new sam2().get();break;
        }
        this.res = res;
    }
    public int get(){return this.res;}
} 
```
```java:sam01.class
package sample;
class sam0{ int get(){return 0;} }
class sam1{ int get(){return 1;} }
class sam2{ int get(){return 2;} }
```
```java:user(Main.class)
import sample.facade;
class  Main {
  public static void main(String[] args){
    facade fd = new facade(8);
    System.out.println(fd.get());
  }
}
```
canvasの画像データをblobに変換し、axiosでpost.する方法

トリミングした画像のアップロードで躓いていたので、自分へのメモとして書きました
##Blobに変換
```canvas.ts
const url: string = canvas.toDataURL("image/png");
const bin: string = atob(url.split(",")[1]);
const buffer: any = new Uint8Array(bin.length);
for (let i = 0; i < bin.length; i++) {
    buffer[i] = bin.charCodeAt(i);
}
const blob: Blob = new Blob([buffer.buffer], {type: "image/png"});
```
##axiosでpost
```axios.ts
const data = new FormData()
data.append("icon", blob, "image.png")
axios.post("url", data, {
    header: {
        "content-type": "multipart/form-data",
    }
})

```
##参考にした記事
[Canvasに描いた画像をpngなどの形式のBlobに変換する方法](https://blog.agektmr.com/2013/09/canvas-png-blob.html "Tender Surrender")
【webpack】cssファイルをインポートしたときのつまずき

# 解決したいこと
cssファイルをインポートしようとすると、下記のエラーが発生する。

```
Failed to compile.
./node_modules/css-loader/dist/cjs.js??ref--5-1!./node_modules/postcss-loader/lib??ref--5-2!./node_modules/element-ui/lib/theme-chalk/index.css
Module build failed: Error: No PostCSS Config found in: ほげほげ
```
# 環境
* npm
* webpack
* vue-cli

# やったこと
### ファイルを作成する
場所：ホームディレクトリ
ファイル名：postcss.config.js

### postcss.config.jsに下記を記述
```
module.exports = {};
```

### build
`npm run build`
pythonのopenでチルダ(~)で始まるパスを指定したら行方不明になった話


```python
path = '~/.config/remind_task/tasks.yml'
dir_name = os.path.dirname(path)
os.makedirs(dir_name, exist_ok=True) # 上位ディレクトリが存在しなければ掘る
with open(path, mode="w") as f:
    f.write("hoge")
```

このようにファイルを開きファイルを作成するとホームディレクトリの`.config/remind_task/tasks.yml`にファイルが作成されると思ってしまう。
上のコードを実行するとファイルは作成される。しかし無い。

```shell
> cat ~/.config/remind_task/tasks.yml
cat: /Users/atu/.config/remind_task/tasks.yml: No such file or directory
```

しかしファイルは作成されている。どこにあるのか探し回った結果、カレントディレクトリに作られていた。  
この場合は`/Users/atu/Documents/python/remind_task/~/.config/remind_task/tasks.yml`にあった。

```shell
> cat "/Users/atu/Documents/python/remind_task/~/.config/remind_task/tasks.yml"
hoge
```

チルダで始まるパスを扱う場合には以下のようにすればOKです。

```python
import pathlib
path = pathlib.Path("~/.config/remind_task/tasks.yml").expanduser()
print("path", path)
## path /Users/atu/.config/remind_task/tasks.yml
```
Cookieセッション管理におけるスティッキーセッションとそれ以外の方法

# 用語確認
## セッションとCookieについて
[Cookie周りの仕様および図解](https://qiita.com/SierSetup/items/f24ee02a942d8f6931a5)

## ロードバランサー（略称：LB）
サーバへの大量のリクエストを均等に分散すべく振り分ける機構。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87538/7be1443e-9631-1a59-c9a5-559ec73eedb2.png)


### 例
AWSならばELB（ALB、CLB、NLB）。

# スティッキーセッションとはなにか
この話題においては、サーバへの一連のアクセスには、クライアント、LB、サーバが存在する。

* リクエストを行ったクライアント
* LBから振り分けられたリクエストを受け付けたサーバ

この二者を常に紐付ける必要性があった。
その必要性とは、サーバ側にセッション情報を保持させていたためである。
つまり、サーバはメモリ上にセッション情報（＝ユーザの状態など）を持っている構造になっている。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87538/00b04926-a4b1-3fe2-4ed4-ada20df15e08.png)

## スティッキーセッションおよびCookieの構成
この構成では2つのCookieが存在する。

* サーバのセッション情報の識別情報（一般的にはセッションキー）
* LBにて付加する振り分け用の識別情報

# セッションをサーバから分離する構成
## キャッシュサーバでセッションを管理

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87538/6811794b-e919-c5e2-6424-a1e2e9603b9f.png)

## キャッシュサーバ例
* Redis
* Memchached

## この構成の特徴
責務が明確になる。リクエスト元を意識しなくなる。図上はあえて、色分けしてセッションを記載したが、この構成ではその区別はなくなる。

* LBはリクエスト分散に集中
* サーバは処理に集中
* キャッシュサーバはセッション管理に集中
よく理解していないまま使用していたもの一覧: Ruby編

#はじめに
この記事は私が勉強をしている中で「よくわからないまま用いていたもの」をまとめることで、私自身の理解を深めることが目的です。以下に一覧として記載いたします。

#Ruby編
###①文字コードの指定

Rubyなどのプログラムファイルにおいて、以下のようなコードを冒頭に書くことで文字コードを指定する場合があります。

```ruby:sample1.rb
 # -*- encoding: utf-8 -*-
```
これは**マジックコメント**と呼ばれるものです。私は毎回必要だと思って、挿入していました。しかし、**Ruby2.0以降ではデフォルトでUTF-8が使われる**ため、現在のRubyではわざわざUTF-8を指定する必要がないのです。

私が毎回マジックコメントを書いていた原因としては、Ruby2.0より前のものを使用していたコードを参考にしていたからだと考えられます。

###②rubygemsについて
Rubyのコードにおいて、たまにこのような行を見かけると思います。

```ruby:sample2.rb
 require "rubygems"
```

そもそもrubygemsとは、Rubyにおいてライブラリの作成や公開、インストールを助けるシステムです。以前のRubyでは、gemとしてインストールされるモジュールを使うプログラムを書く場合、まずrubygemsに対してrequireを実行する必要がありました。しかし**Ruby1.9以降、rubygemsモジュールが標準ライブラリの一部となった**ため、わざわざrubygemsをrequireする必要はなくなったのです。

私がこれを書いていた原因も、Ruby1.8以前のものを使用していたコードを参考にしていたからだと考えられます。

#まとめと感想
勉強のためにさまざまなコードを参考にする中で、実際は不要なのに使用していたものがあったことに気づきました。
言語のアップデートが理由で不要になったものがある、ということも学んだので、今後は載っているコードで使われている言語のバージョンなども意識して見ていこうと思います。
PHPのtrait上で任意のモデルを`$this`として参照する

## そもそもtraitとは  
PHPは仕様として多重継承をサポートしていません。そのためある基底クラスを既に継承している場合に共通の振る舞いを拡張するため継承を追加する、といったことが行えないのです。。
しかし、traitを利用することで共通の振る舞いを切り出し、再利用することが可能となります。  

>PHP 5.4.0 以降では、コードを再利用するための「トレイト」という仕組みが導入されました。

>トレイトは、PHP のような単一継承言語でコードを再利用するための仕組みのひとつです。 トレイトは、単一継承の制約を減らすために作られたもので、 いくつかのメソッド群を異なるクラス階層にある独立したクラスで再利用できるようにします。 トレイトとクラスを組み合わせた構文は複雑さを軽減させてくれ、 多重継承や Mixin に関連するありがちな問題を回避することもできます。

> トレイトはクラスと似ていますが、トレイトは単にいくつかの機能をまとめるためだけのものです。 トレイト自身のインスタンスを作成することはできません。 昔ながらの継承に機能を加えて、振る舞いを水平方向で構成できるようになります。 つまり、継承しなくてもクラスのメンバーに追加できるようになります。

[PHP: トレイト - Manual](https://www.php.net/manual/ja/language.oop5.traits.php)  
  
## 使い方
通常の継承のように`extend`するのではなく、traitを利用したいクラス内で`use`して参照します。 
 
```php
class HogeModel() {
  use HogeTrait;
  .....
}
```  
  
## traitから`$this`で呼び出し元を参照できない！？  
traitはその性質上、共通処理の重複を防ぐなどの理由で複数のクラスから利用されることを想定されていることも多いと思います。  
しかし、あるtraitが特定のクラスでのみ利用される設計のこともあると思います。
例えば弊社では設計にDDD（ドメイン駆動設計）を採用しているのですが、モデルの責務を超えてくるような責務についてはtraitに切り出し、モデル内から参照するようにしています（例えばFactoryパターンの実装などはtraitで行っています）。  
そのような場合には`$this`として呼び出し元のモデルを参照する処理を実装したい場合もあると思いますが、それをtrait上で行ってみると。。。  

```php
class HogeModel() {
  use HogeTrait;
  .....
  public function getString(): string {
    return 'echo me';
  }
}

trait HogeTrait {
  private function hogeFunction(): void {
    $this->echoHogeModelString($this);
  }

  private function echoHogeModelString(HogeModel $model): void {
    echo $model->getString();
  }
}
```

```
Expected parameter of type 'HogeModel', 'HogeTrait' provided 
```  
  
~~`hogeFunction`内で`echoHogeModelString($this)`として引き渡されている`$this`が`HogeTrait`として認識されてしまう結果、「`echoHogeModelString`の引数にはHogeModelを渡してね！」と注意されてしまう訳です。当然といえば当然ですね。
しかし、設計上単一のモデルからのみ参照されるtraitなのだから、`$this`で呼び出し元モデルを参照したい！ということもあると思います（僕はありました。。）。
ここでは二つの対応方法をご紹介します。~~

**2020/11/16追記**  
PHPの言語使用では[そもそもトレイのインスタンスは作れない](https://www.php.net/manual/ja/language.oop5.traits.php)ので、上記のようにtrait上で`$this`として呼び出し元のモデルを参照した場合でも PHP自体ではエラーや警告になりません。
今回の警告は静的解析でType compatabilityに対する警告が発出されていたために生じていたものでした。
内部仕様をきちんと理解してコーディングを行う重要性が身に染みました。。。  
ご指摘いただいた@rana_kualuさん、@sj-iさん、ご指導ご鞭撻をいただきまして、ありがとうございました。
以下の解説はPHPの言語そのものによる警告ではなく、IDE上での静的解析による警告の回避方法の一例としてご参照いただければと思います。  

  
## 1：phpdocの`@var`コメントで変数の型を指定する
下記のように`@var`コメントで型を指定することで`$this`参照を実現することができます。  

```php
trait HogeTrait {
  private function hogeFunction(): void {
    /** @var HogeModel $this */
    $this->echoHogeModelString($model);
  }
  .....
```

`$model`変数を`HogeModel`型であることを明示的に宣言することで、trait上でも警告なしで呼び出し元のモデルを直接参照することができます。  
  
## 2：`assert`することで`$this`の型を保証する  
下記のようにtrait上で型を保証する`assert`を記述することで`$this`参照を実現することができます。    

```php
trait HogeTrait {
  private function hogeFunction(): void {
    assert($this instanceof HogeModel)
    $this->echoHogeModelString($this);
  }
  .....
```

`$this`を`HogeModel`型であることを`assert`で明示的に保証することで、trait上でも警告なしで呼び出し元のモデルを直接参照することができます。  

## PHPでもやりようで型とは上手に付き合える（はず）  
インタプリタ言語であるPHPですが`declare(strict_types=1)`の設定をすることで型指定に基づいた実装を行うことができます。より適切な型の扱いや実装を行えるよう、精進していきたいと思います(静的言語も業務でやりたい。。)。  
お読みいただき、ありがとうございました。