OmniAICreator/Qiita-1.07M huggingface dataset:
BigQueryでWAUやMAUを求める

- 非エンジニアなので優しくしてください
- firebase&BigQuery環境です
- StandardSQLです

DAUとかは比較的簡単に求められるわりに、WAUとかMAUが地味に考えにくかった＆調べてもあんまり出てこなかったので書いておきます。

firebaseを見ればわかるっちゃわかるんですが、自分で書けるようにしておくと理解が深まる＆セグメントしたくなったときに扱いやすいので。

#やりたかったこと
WAU(weekly active user)はその名の通り「1週間のうちに起動したユーザーの数」。
今回は推移を出したかったので「ある時点から過去1週間のうちに起動したユーザーの数」としています。

このWAUを1週間ごとではなく、日ごとの推移(任意の日付からさかのぼって7日間)を出したい。

こんなイメージ

|日付|wau|
|:----------------:|:------------------:|
| 2019-12-01          |              10,000 |
| 2019-12-02          |            10,500 |
| 2019-12-03          |            11,000 |
| :          |            ： |

MAUの場合も同様

#実際のクエリ

firebaseの実際の数字と比べてみましたが、ほぼほぼ合ってる感じだったのでこれでできてるのではと思います。(間違ってたら指摘ください)

```sql
-- 日ごとに起動したユーザーのリストをつくる
with user_open as (
SELECT 
id
,date(timestamp_micros( event_timestamp ),"Asia/Tokyo") open_date
FROM `テーブル名_*` 
-- 過去35日間のデータを参照する（弊社の仕様）
where _table_suffix between format_date('%Y%m%d', date_sub(current_date("Asia/Tokyo"), interval 35 day)) and format_date('%Y%m%d', date_sub(current_date("Asia/Tokyo"), interval 1 day))
  and event_name = "session_start"
  group by id
,open_date
)

-- 集計に使う配列を生成する
,date_table as (
select 
date
from 
unnest(GENERATE_DATE_ARRAY(date_sub(current_date("Asia/Tokyo"),interval 28 day),date_sub(current_date("Asia/Tokyo"),interval 1 day))) date
)

-- 2つのテーブルを交差結合する
-- 邪魔な行をwhereで削っておく(差が7日以内になるように絞る)
,cross_table as (
select id
,open_date
,date
from user_open
cross join date_table
where date_diff(date,open_date,day) < 7
and date_diff(date,open_date,day) >= 0
)

-- dateでgroupしてidの個数を数えれば推移が出る
select 
date
,count(distinct id) wau
from cross_table
group by date
order by date asc
```
交差結合して全パターンの組み合わせを作り、7日の範囲でしぼっていくのがミソです。
これで日付のgroup byすればその日から7日以内に起動した人数が求まります。

MAUの場合は元データの抽出期間を伸ばし、参照範囲を変えれば同様にできます。
Swiftでクラロワのトッププレイヤーを取得する。

## はじめに
すき焼きうまし。
## 公式ドキュメント
- https://developer.clashroyale.com/#/
- https://docs.royaleapi.com/#/?id=documentation

## クラロワのAPI叩く手順
1. アカウント作る
2. APIKEY取得する
3. コード書く

## アカウント作る&APIKEY作る
https://qiita.com/takahirono7/items/4d76d727945b0edd0657#api-key%E3%81%AE%E4%BD%9C%E6%88%90
この方の記事がとても分かり易かったので参考にしましょう。

## コード書く
今回はエラー処理など書いてませんがご了承ください。
次回の記事でがっつりその辺も書きたいと思います。
とりあえず試しにAPI叩いてみたい人はどーぞ。
## User.swift
jsonで帰ってきたデータを格納します。
Decodableを継承してあげることでよしなにjsonをマッピングしてくれます。

```swift:User.swift
import Foundation
public struct User: Decodable {
    var name: String
    var tag: String
    var expLevel: Int
    var trophies: Int
    var rank: Int
    var previousRank: Int
    struct clan: Decodable {
        var tag: String
        var name: String
        struct badge: Decodable {
            var name: String
            var icon_swf: String
            var icon_export_name: String
            var vategory: String
            var id: Int
            var image: String
        }

    }
    struct arena: Decodable {
        var name: String
    }
}

```

## RequestAPI.swift
apikeyは各自が取ってきたものを使います。
今回使ったAPIは日本のトッププレイヤーを持ってくるというやつです。
URLの最後にJPとは言っていますがここを差し替えてあげると他の国のトッププレイヤーも取ってこれます。

```swift:RequestAPI.swift
import Foundation

class RequestAPI {
    let baseURL: String = "https://api.royaleapi.com/top/players/JP"
    let headers = [
        "Authorization": "apikey",//ここはapikeyを各自入れる
        "Cache-Control": "no-cache",
    ]
    func getTopUsers() {
        let request = NSMutableURLRequest(url: NSURL(string: baseURL )! as URL,
                                          cachePolicy: .useProtocolCachePolicy,
                                          timeoutInterval: 10.0)
        request.httpMethod = "GET"
        request.allHTTPHeaderFields = headers
        let decoder = JSONDecoder()
        let session = URLSession.shared
        let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
                do {
                    //Jsonをmodelにマッピング。modelにDecodableを継承させとく。
                    let users = try decoder.decode([User].self, from: data!)
                    for user in users {
                      print(user.name)      
                    }
                } catch {
                    print(error)
                }
            }
        )
        dataTask.resume()
    }
}
```

## 最後に
クラロワのAPIあるなんて意外でしたね。
ポケモンGOとかもAPI出してくれればいいのに。
クラロワは試合の勝ちが決定したらゴブリンスタンプを連打するのが楽しいですね。
他にもいろいろ習得できるっぽいので使ってみてください。
Revit Add-In Managerを使ってデバッグする方法

#Add-In Manager とは
Addinファイルなしで、外部コマンドを実行できるアドインツール。Visual Studio の[プロセスにアタッチ]と合わせて使うことで、ビルドのたびにRevitを起動し直すことなく、外部コマンドをデバッグすることができる。

アドインはRevit SDKに同梱されているので、そこからアドインをコピーし設定する。

[Add-In Manager Installation](https://knowledge.autodesk.com/support/revit-products/getting-started/caas/screencast/Main/Details/f62848c4-66fb-4ccd-8d74-0626e80c42d5.html)


#使ってみた
1. Revitを単独で起動する。
2. Visual Studioで[デバッグ]の[プロセスにアタッチ]で、起動したRevitプロセスを指定する。
3. Revit [アドイン]タブの[外部ツール]から[Add-in Manager (Manual Mode)]を選択する。
4. [Loaded Commands]タブの[Load]ボタンから、実行したい外部コマンドのアセンブリを登録する。
5. 表示された外部コマンドのうち、実行したい外部コマンドを指定し[Run]を押すと、コマンドが実行される。
6. 再度ソースコードを編集しデバッグする場合は、Visual Studioからデバッグを停止し、ソースコードを編集、ビルドし、再度[プロセスにアタッチ]でデバッグを再開する。
7. その後、Revit [アドイン]タブの[外部ツール]から[Add-in Manager (Manual Mode, Faceless)]を選択することで、再び外部コマンドが実行される。

※Addinファイルを使っていると、アセンブリをRevitプロセスに取り込んでしまうようで、再ビルドするためには、Revitを閉じる必要がある。**Addinファイルは外すこと。**
#なぜか外部アプリケーションの実行には使えなかった
上記の手順は、外部コマンドの実行の方法。
外部アプリケーションの実行の方法を探してみたが、[Loaded Applications]タブの[Run]ボタンが押すことがでず、結局わからなかった。

#参考

[The Building Coder: Debugging an Add-in Without Restarting Revit](https://thebuildingcoder.typepad.com/blog/2011/05/debugging-an-add-in-without-restarting-revit.html)
ExoPlayerで早送りと巻き戻しの秒数を設定する

定義しているlayoutファイルのViewに
<b>app:fastforward_incerment、app:rewind_increment</b>を追加する。
app:fastforwardは早送りの秒数、app:rewind_incrementは巻き戻しの秒数を表す。
msで指定しているので、3秒なら"3000"、10秒なら"10000"と記述すればOK。


```
<com.google.android.exoplayer2.ui.SimpleExoPlayerView
   android:id="@+id/video_view"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   app:fastforward_increment="30000"
   app:rewind_increment="30000"/>
```


参考記事（Exoplayerを丁寧に解説しているからとても分かりやすい）：
https://medium.com/fungjai/playing-video-by-exoplayer-b97903be0b33
.NetCore3.1向けC++/CLIを軽く試した感想


#記事の説明
　.net core 3.1がLTSになったので、以前から試してみたかったC++/CLIを軽く使っていました。
まだ少ししか使っていないので、文法はよく分からないのですが、なかなか良い感じの言語だと思いました。
　でも、思っていたよりイマイチ使いづらいと感じました。
　そう感じた理由を、メモ代わりに書いていきます。大半がVisual Studio 2019で検証したものです。
（間違いはあるかもしれません）

.net core 3.1関連リンク先は記事の一番下にあります

#.Net Core 3.1 向け C++/CLIの始め方
１・Visual Studio 2019 Ver 16.4.0 をインストールします

２・Visual Studio 2019のインストーラを起動し、
ワークロードから「C++によるデスクトップ開発」と
個別のコンポーネントから「v142 ビルドツール(14.24)のC++/CLIサポート」をチェックしてインストールします

３・Visual Studio 2019を起動し、
ファイル＞新規作成＞プロジェクトをクリック、プロジェクト一覧から「CLR 空のプロジェクト(.Net Core)」を
選択して、適当なパスにプロジェクトを作ります

#.Net Core 向けC++/CLIが思ったほど使いやすくないと感じた理由(本題)

##ビルドすると、ネイティブバイナリの「Ijwhost.dll」も出力される
　C++/CLIの実行に、Ijwhost.dllが必要な上、x86のIjwhost.dllとx64のIjwhost.dllとの
混同はできない。
　なので、32ビットOS用と64ビットOS用に実行ファイルを作る場合、別々のディレクトリに出力されるようにすること

##一度ビルドしないと、別プロジェクトのインテリセンスの候補が正しくならないし、エラー表示も正確な表示にならない
＊Visual Studio 2019 Ver 16.4.0 にてこの現象を確認＊

##C++/CLIだけだとDLLしか出力できない
　プロジェクト設定の構成を「ダイナミック ライブラリ (.dll)」以外にするとビルドが通らない
ので、C++/CLIから実行ファイル(exe)を作ることは不可能

　C#からC++/CLIのクラスを使うことはできるので、c#とC++/CLIを組み合わせると実行ファイルを作ることは可能
　こうする場合、C#から作るexeとC++/CLIで作るdllとのビット数設定が違うと実行時エラーが出るので、
C#の対象プラットフォーム設定は、Any CPUではなく、x86かx64の方がよい
また、C#側も.net core 3.1向けにする必要がある

（.net framework向けの場合なら、C++/CLIだけでも実行ファイルを出力可能なのに・・・）

##C++側からC++/CLI側の関数を呼べない？（逆は普通に可能）
C++/CLI側で定義した__declspec(dllexport)なグローバル関数は、C++側から呼ぶのができない？（どうやっても関数の未定義エラーが出る）ので、
C++側からC++/CLI側エントリポイント代わりの関数を呼ぶプログラムは作れない

##CC++/CLIのクラスを使うC#のコードをビルドする際、VisualStudioが必須？
　VisualStudioを使う場合、正しく設定等ができている時、普通にビルドが通ります。
しかし、コマンドラインからビルドするのは非常に厳しそう・・・

dotnetコマンドでは、C#のビルドはできてもC++/CLIのビルドはできないので・・・

#最後に
　C++/CLIの言語仕様じゃなくて、ツール周りに使いにくさを感じさせますね。
言語仕様にも、想像と違うって要素（非ネイティブ関数から関数ポインタ取って使えるかと思ってた、できない）があったりしたけどね。
　C++/CLI単体でexeを作ることができないという点だけでかなりマイナスになってる感じ・・・
　
　単純にC#とネイティブコードを連携させるなら、C#とC++を使ったほうがいいような・・・って。

　でもC++/CLIは良い感じなんですよね
ネイティブコードの混在が簡単で、
C#には不可能なテンプレート（ジェネリックではない）が使えて、C#より利便性が高そうなとこ
　C#よりできること多くて面白いので、C++/CLIの勉強しようかな・・・

#.Net Core 3.1のリンク先
・Download .NET Core 3.1
https://dotnet.microsoft.com/download/dotnet-core/3.1

・Announcing .NET Core 3.1
https://devblogs.microsoft.com/dotnet/announcing-net-core-3-1/
GitとGitHub　その1

今回はチームでの開発に大変有用なGitとGitHubについて
説明します。

# Git
セーブポイントを作るアプリケーション管理システムです。

Gitでアプリケーションを管理すると
それぞれの修正点でセーブポイントのようなものを記録して
時系列で管理してくれます。

セーブポイントとしてしっかり記録しているので、当然いざというときには遡ることも出来ます。

# GitHub
DropboxやGoogle Driveのようなクラウドサービスのようなものです。
一つのアプリケーションを更新、修正を共有することができます。

つまりGitHubを介して自分以外と簡単にコードのやり取りができます。
よって複数人でのアプリケーション開発が容易にできると言うことです。


# GitとGitHubの違い
Gitはアプリケーションなどのプロジェクトをバージョン管理してくれるシステム。
GitHubはそのGitの仕組みを用いて簡単に複数人での開発ができるようにしてくれるツールです。

# Gitの専門用語
専門用語が多くあるのでそれも説明します。

## リポジトリ
リポジトリとは、Gitの管理下にあるファイルやディレクトリの変更履歴を保管しておく入れ物です。

クラウド、または遠隔HDDと思ってください。

## ローカルリポジトリ
自分のPC上（ローカル環境）に置くリポジトリのことです。
自分のPC上にあるファイルやディレクトリのバージョン管理をしたい場合に用います。

## リモートリポジトリ
リモートリポジトリとは、外部のサーバなどのネットワーク上に置くリポジトリのことです。
ネットワーク上に置くことで複数人で管理下のファイルやディレクトリを共有することが出来ます。

Githubの肝となります。
Androidの実機でデバック中に配置エラーが出た場合の対処

メモ書きみたいなものですが、ちょっとハマったので書きます。

Xamarin Formsのアプリを作成中、実機をアップグレードしたら下記のエラーで配置できなくなった。エミュレータだと実行できる。

```Mono.AndroidTools.RequiresUninstallException: The installed package is incompatible. Please manually uninstall and try again.
```

まあ、手動でuninstallしろってことなんだけど、既に実機のアプリは削除してある。やり方がわからなくて調べた。

どうやらadbコマンドを使うらしい。

VS2019の「ツール」→「Android」→「Android Adb コマンドプロンプト」でAndroid Adb コマンドプロンプトを立ち上げる。

「よく使うadbのコマンド」を参照する。
https://qiita.com/t2low/items/cb37cec5f864c4748e14

アプリ名は「FileUploader」なので、
```adb shell pm list packages file```
で探すけど見つからない。

エミュレータの方で同じコマンドを打ち込むと、「com.xxxxxx.FileUploader」が引っ掛かった。

ちなみにパッケージ名は「AndroidManifest.xml」でも確認できる。

そこで、
```adb uninstall com.xxxxxx.FileUploader```
でアプリを消すことができた。

無事に配置実行までできた。
dyld: lazy symbol binding failed: Symbol not found

# はじめに
私は現在、高エネルギー物理学や放射線治療などのシミュレーションに使われるGeant4というtool kitを使っているのですが、プログラム実行時に動的ライブラリに関するエラーが出てしまったのでその解決法を書いていきます。

#エラー文
```shell-session:macOS
dyld: lazy symbol binding failed: Symbol not found: __ZN18G4OpenGLImmediateXC1Ev
  Referenced from: ~/Geant4Tutorial/UserWorkDir/P06/TestBench/../bin/Application_Main
  Expected in: /usr/local/lib/libG4OpenGL.dylib

dyld: Symbol not found: __ZN18G4OpenGLImmediateXC1Ev
  Referenced from: ~/Geant4Tutorial/UserWorkDir/P06/TestBench/../bin/Application_Main
  Expected in: /usr/local/lib/libG4OpenGL.dylib
```
このエラー文には「シンボルが見つかりません。/usr/local/lib/libG4OpenGL.dylibに欲しいライブラリがありますよ。」的なことが書いてあります。つまりプログラム実行中に欲しいライブラリのパスが通ってないということになります。


#dylibとは
.dylibがついているファイルは動的ライブラリ(dynamic library)と呼ばれるもので、プログラム実行中にリンクするライブラリのことです。Windowsでは.dll、Linuxでは.so、OSXだと.dylibが拡張子として付くそうです。
つまりエラー文は動的ライブラリのパスを通せと言い換えることができます。
動的ライブラリの作り方や使い方はこの[サイト](https://blog.katty.in/4346)にわかりやすく書いてありました。


#解決法１
.bash_profileや.zprofileなどの環境設定ファイルに動的ライブラリがある場所の検索パスを通します。

```shell-session:.bash_profile
export DYLD_LIBRARY_PATH=/usr/local/geant4/install/geant4.10.05.p01/lib
```
そのあとに追加した環境変数を`source`コマンドで反映させます。

```shell-session:
$ source ~/.bash_profile
```
これでエラー文は出なくなり、無事プログラムを実行することができました。

#解決法２
rpathと呼ばれる、プログラム実行中に参照する動的ライブラリの検索パスのリストがあります。
以下のコマンドでrpathに直接ライブラリを追加することができます。

```shell-session:
$ install_name_tool -id "@rpath/libG4OpenGL.dylib" libG4OpenGL.dylib
```
[参照サイト](https://codeday.me/jp/qa/20190301/328165.html)
システムエンジニアが今年読んで良かったと思った本大賞2019


#年の瀬には色々と振り返りしたくなりますよね
今年の良かったところ、反省したいところ、観た映画やエトセトラ。
私も何か振り返ろうと思い、行き着いたのが「今年読んで良かった本」についてだったのでこの場を借りて書かせていただきます。

掲題にも記載している通り、~~一応エンジニアなので~~技術書などが多いかもしれません。
また、これからご紹介する本の中で個人の考えが**だいぶ**入っているので、「ふ〜〜ん」程度にご覧ください！

# 「読んで良かった！」と思える良書　5選
それでは、書評も兼ねてさくっとまとめさせていただきます！

## 1.カイゼンジャーニー
日頃の業務で感じる「階段」。
お客様からの依頼だったり、会社からの話であったり・・・仕事をする上で多くの「階段」に出会います。
階段を登れる時もあれば、登れない時もあります。私がこの本と出会ったのは、階段を登れなかった時でした。
そもそもこれは「階段」なのか？何ならこの先「階段」なんて都度出てくるのに、そのリスク管理はできるようになるのか？

そんな時に、巡り合った本です。
「階段」を登るのが正しいのか？という方向性の正しさ、これらを考えること自体が「階段」を乗り越えると良い影響があるのか悪い影響があるのかは正直分かりません。
しかし、私の中では選択肢を見つけることができるのではと思い良書とさせていただきました。
[カイゼンジャーニー](https://www.amazon.co.jp/dp/4798153346/ref=cm_sw_em_r_mt_dp_U_Q666Db3WT1YGP)

## ２.リーダブル・コード
この本と出会ったのはもう宿命です。私みたいな~~ウンコード生産~~エンジニアが読むと思わず胃が痛くなる本です。
もうね、コードを読んだ時の「読みやすい、すごい」の源泉を垣間見せてくれます。

clm1とかvalとかしょっちゅう書いてます本当にごめんなさい。三項演算子を並べて「私天才かよ」とか思ってます本当に生まれてきてごめんなさい。
素晴らしきエンジニア達はこういうことに気をつけて書いてるんだなぁということを私みたいなやつにも分かる様に書いてくれていて、本当に素晴らしい本です。(当たり前ですが)

過去のウンコードをまっさらに書き直すことは出来ませんが・・・、これから書くコードは学んだことを最大限に活かして、コードを書きます。
[リーダブル・コード](https://www.amazon.co.jp/dp/4873115655/ref=cm_sw_em_r_mt_dp_U_l866DbP0MZ5HG)

## ３.アイデアのつくり方
エンジニアであっても営業であっても、**マジで誰にでもオススメできる本**です。
アイデアって「全く新しいものを生み出すもの」だと思っていたのですが・・・そんなことはありません。
むしろ、「これまで生み出されてきた様々なアイデアを組み合わせることで生み出されるもの」がアイデア。

これ、本当にしっくりきました。
資料集め、情報の整理など「そんなもの当たり前だろう！」と言われかねないのですが原点に返ってみると意外と身近なところに本質があったみたいなことが度々ありました。

ページ数も100ページくらいですし、お値段の割には良書なので読んだことがない方はぜひ一度ご覧ください！！
[アイデアのつくり方](https://www.amazon.co.jp/dp/4484881047/ref=cm_sw_em_r_mt_dp_U_n966DbC2J4Z2J)

## ４.勇者に学ぶ 難題に立ち向かう「戦略思考」――才能よりも努力よりも問題解決に必要なこと
行き詰まった時に、私の会社の上司が貸してくれた本です。

今まで「戦略」について知らなかったし、考えたこともなかったのですがこの本は《戦略づくり》について非常にわかりやすく書いてあります。
自分が解決したい問題や課題をしっかりと認識している方はぜひ読んでみて欲しいです。
（そもそも問題がなかったり、自身の課題がなければ戦略は必要ないのかな？と思いますが。）

しかし、この本を読んでいて思うのは戦略には制限時間というものが必ずあることと、時間軸の中で考えないといけないので
意外と時間の概念が忘れがちになるやもしれません。。
[勇者に学ぶ 難題に立ち向かう「戦略思考」――才能よりも努力よりも問題解決に必要なこと](https://www.amazon.co.jp/dp/4532322200/ref=cm_sw_em_r_mt_dp_U_2966DbAC901CE)
## ５.極主夫道
これ、ビジネス書でもなんでもないです。ただの漫画です。
でも絶対にオススメです。ただし電車で読んじゃダメ。**おばちゃんとの約束だゾ★**
アットホーム任侠コメディです。
###もう一度言います。アットホーム任侠コメディです。

完全に聞き慣れない。。しかも、見慣れないですよねええそうですよね。
そもそも鶴と亀くらい全く正反対な言葉であるアットホームとコメディの間に、何故**『任侠』**という字が入るのか。

その理由は、タイトルからも分かる通り主夫の道を選んだ男が**元・最凶ヤクザ**だから。
非常にアットホームです。
個人的には、第一巻のキャラ弁の件でグッと心を掴まれました。

オススメです。マジで何も考えずに読めます。
[極主夫道](https://www.amazon.co.jp/dp/4107721043/ref=cm_sw_em_r_mt_dp_U_3-66DbPDT9SSC)
# まとめ

いかがだったでしょうか？今回は、本について焦点を当ててみました。
~~というか、本を読む習慣が無いと人にオススメされなきゃ読まなくない？？~~

それでは、ここまで読んでくださりありがとうございました！！
DIをクッソ雑に説明

# この記事はOIC ITCreate Club Advent Calendar 2019の7日目の記事です。
https://adventar.org/calendars/4713

# まえがき
DIについて書いている優良な記事は沢山ありますが、
なんか難しいこと言ってんな〜って思った人向けの記事です。

例としてScalaを使用していますが、
デザインパターンの解説がメインなので
Scalaわかんないよって人でも大丈夫です。

## 読み方
**"でぃーあい"**と読みます。

## DIに必要なもの
以下の3つが必要なので用意します

1. Interface もしくは trait
1. 実装class
1. DIコンテナ

#### Interface もしくは trait
実装を持たない関数を定義します。
言語によってInterfaceだったりtraitだったりしますが、やってることは一緒です。
今回はScalaを使用しているのでtraitです。

例

```scala:Hoge.scala
trait Hoge {
  def hello()
}
```
#### 実装class
traitを継承し、関数の中身を実装したclassです。
class名は、**trait名 + Impl**になります。 (ImplはImplementの略！日本語で実装の意味！)

例

```scala:HogeImpl.scala
class HogeImpl extends Hoge {
  def hello() {
    println("こんにちは")
  }
}
```

#### DIコンテナ
DIをするライブラリのことです。
ここではHogeを使用したときに、HogeImplがHogeに注入されるようにする設定をしています。

今回はPlayframeworkに標準でついているguiceを使用しています。
ライブラリに応じた設定をしてください

```scala:module.scala
import play.api.inject.Module
import play.api.{Configuration, Environment}


class HogeModule extends Module {

  def bindings(environment: Environment, configuration: Configuration) =
    Seq(
      bind[Hoge].to[HogeImpl]  // ここで設定をしている
    )
}
```

## DIの説明
**HogeImpl**を使用するのではなく、**Hoge**を使用します。
えっ、Hogeは実装書いてないし動かなくない？って思いますが、
それをいい感じにしてるのがDIです。
<img width="364" alt="スクリーンショット 2019-12-07 22.14.23.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151730/8e8c7ee6-40e8-2173-dc40-07f9afbfd88a.png">

コンパイル時または実行時に、DIコンテナは設定されている通りに置き換えます。


<img width="552" alt="スクリーンショット 2019-12-07 22.32.07.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151730/18e023c5-e7b6-b0a2-edf7-086ab006b86e.png">


HogeImplに置き換わるので、
`Hoge.hello()`を実行すると、
`こんにちは`出力されます


**この置き換える仕組みがDIです。**


## あとがき
DIして何が嬉しいかとかは、他の優良記事を参考にしてください。
TypeScriptでFactorio Modを作る

# はじめに
Lua言語は、いろいろな組み込み系のプログラムや、ゲームのロジック部分、nginx内で完結できてしまうちょっとした処理など、様々な場所に使われています。

Factorioという工場を建設するゲームのMod作成にも、Lua言語が使われています。

自分でもいくつかModを作ったり修正していく中で、変数の型やエディタの補完をもっとしてくれたらうれしいなぁと思っていました。

そんななか、TypeScriptToLuaというパッケージを発見したので、作っていたCoastal Erosion(海岸浸食)というFactorioのModをTypeScriptで書き直してみました。

TypeScriptで書けるようにすること自体は簡単にできたので、導入のポイントと小ばなしを紹介します。

# ポイント
以下のリポジトリでTypeScript化したコードを公開しています。

:octocat: [Tei1988/factorio-coastal-erosion](https://github.com/Tei1988/factorio-coastal-erosion)

詳しくはリポジトリの中をみてもらうとして、FactorioのModをTypeScriptで書くためのポイントは二つです。
[package.json](https://github.com/Tei1988/factorio-coastal-erosion/blob/master/package.json)の `devDependencies` にある `typescript-to-lua` と、 `@types/factorio` です。

## typescript-to-lua

`typescript-to-lua` は、TypeScriptで書いたソースをLuaに変換してくれるトランスパイラです。このパッケージで入るtstlコマンドでLua言語に変換を行います。

:octocat: [TypeScriptToLua/TypeScriptToLua](https://github.com/TypeScriptToLua/TypeScriptToLua)

内部的にはTypeScriptからASTを構築して、それをLuaのASTに変換してLuaのコードとして出力する処理になっているようです。
また、一部のTypeScriptの標準ライブラリはLuaで使えるようにLua側でも実装されており、対応している物は使えるようになっています。

`package.json` の `scripts` に変換用のコマンドをあらかじめ定義しているので、 `npm run-script build` で変換できます。

FactorioのLuaは5.2のため、 `tsconfig.json` の `tstl` の項目に`"luaTarget": "5.2"`を指定しています。

## @types/factorio

`@types/factorio`は、FactorioのLuaのAPIの型定義を提供してくれるパッケージです。
この型定義のおかげで、とても書きやすくなります。

# 小ばなし
ここからは、実際にTypeScriptに書き直した時に詰まったところなどをいくつか紹介します。

## Mapが使えない
Coastal Erosionは、マップ上に存在する海岸（水に設置しているタイル）の座標を連想配列で保持しているのですが、これを `Map<number, Map<number, number>>` として置き換えたところ、ゲーム実行時にエラーになりました。
どうやら、クラスのMapはLuaで実装されていないようなので、Hashに置き換えました。

## オブジェクトが破壊できない
Coastal Erosionでは、陸地が浸食されてタイルが水没すると、その上に載っていたオブジェクトを破壊するようにしています。
TypeScriptに置き換えた後、そこでエラーが出るようになってしまい、小一時間悩んだのですが、よくよくコードを見ると、 `e.destory()` となっていました。型定義のほうが間違っていたという話でした。

## とりあえず
困ったら最終的に吐き出されたLuaをみましょう。

# おわりに
いかがでしたでしょうか。これでFactorioのModをTypeScriptで作れるようになったかと思います。

Modつくる人が増えたらいいな、と思います。
【個人メモ】間違えて違うディレクトリでgit init した時の対処法

間違えて違うディレクトリで```git init```した時は
再度正しいディレクトリで```git init```をすると、.gitが現れる。
その際、

```
Reinitialized existing Git repository in /hogehoge
```

となるが特にこれは問題なし。
参照
https://qiita.com/ironsand/items/ef26f8a93b735f6fac4b
[The Go Programming Language Specification] Rune

# Go
Golangのspecificationの日本語訳と、ちょっとした遊びぐらいのコードを載せていく感じで進めようと思うので、
すでにGolangでコードを書いている人にはつまらないかもしれないです

また、間違っている部分があればぜひご指摘いただけると嬉しいです🙇‍♂️

### 想定する読者層
- Golang初めてそこまで期間が経っていない
- 英語の公式読むの辛い
    - https://golang.org/ref/spec


## Rune literals
本記事は公式のドキュメントを参考にしています

- https://golang.org/ref/spec#Rune_literals

### rune とは？
Rune literal は int32 の alias で Unicodeを表す整数です
Rune はシングルクウォートで囲まれた１文字以上の文字で表されます
`x` とか `\n`です

例えば `'a'` の時、は1byteで `a` ,`U+0061`, `0x61` を表す
`ä` は2byteで、`0xc3` と `0xa4` (もしくは`U+00E4`, `0xe4`)を保持します

```golang
fmt.Println(rune('a')) // = 97
fmt.Println('\x61') // = 97
```

#### 余談
**runeでprintした時に表示される数字の意味とは？**

ここで不思議なのは `97` と `0(\)x61` だと思います

これらの数字は[ASCII](http://www9.plala.or.jp/sgwr-t/c_sub/ascii.html)と呼ばれる文字コードの対応表を見ると理解できます

`97`という数字はASCIIコード表では10進数で表現した時に`a`を意味します
`0x61`という数字はASCIIコード表では16進数で表現した時に`a`を意味します

ちなみに `0x` の x は 16進数を表す `hexadecimal` の3番目の文字からきているらしいです（不思議ですね）

これまでrubyやphpを触った時にruneという概念に出会ったことがなかったので、最初はとても戸惑いました
しかし、上記のことを理解するとruneのことが少し怖くなくなるのではないでしょうか

## runeの宣言方法
runeで変数を宣言と初期化は他の型と同様にする

```golang
var r rune
var r rune = 123
```

## サンプルプログラム

### 文字列をruneにしてみる

```golang
package main

import "fmt"

func main() {
	s := "astring"
	fmt.Println([]rune(s))
	for _, c := range s {
		fmt.Println(c)
	}

}
```
```text
[97 115 116 114 105 110 103]
97
115
116
114
105
110
103
```
https://play.golang.org/p/dLSdkCH4p5i


### runeで比較

```golang
package main

import "fmt"

func main() {
	hex := '\x61'
	fmt.Println(hex)
	if hex == 97 {
		fmt.Println(true)
	}
	if '\x61' == rune('a') {
		fmt.Println(true)
	}
	if rune('a') == 97 {
		fmt.Println(true)
	}
}
```
```text
97
true
true
true
```
https://play.golang.org/p/A0SLmXG8mkQ
FaceBook Group 「FreeBSD研究部」のご案内

FaceBook Groupに、「FreeBSD研究部」というのがあります。

2014年7月12日に開設しましたが
2019年12月7日現在　630人参加してくれてます。

「FreeBSDについて、日本語で情報交換する場が欲しくて作成しました。研究とついていますが、特になにかを、研究しようというわけではなく、単なるユーザコミュニティです。リードオンリー、質問オンリーも大歓迎です。また、FreeBSDを使ったサービスや製品の紹介など情報となる宣伝も歓迎します。ただ繰り返し連呼されると逆効果になるとおもいます。」

コアな話題から、ドジを踏んだ話まで多岐にわたります。

参加者の中には、FreeBSD界隈での著名人なども参加してくださっております。

FreeBSDは、Linuxとは違って、ライセンス的に、使用してる事を公言しなくても良いので、利用者が少なく見えます。

しかし、NetFlixが、FreeBSDでサービスしてると好評してます。

FreeNASというNAS用OSSがありますが、FreeBSDをベースにしています。

OPNsenseという、ファイアウォールも、FreeBSDです。


Linuxの、Dockerのおかげで,「コンテナ」が、話題ですが
FreeBSDでは、はるか昔から、Jailという、コンテナ類似の仕組みが実装されていて、安定稼働している実績もあります。

また、高機能ファイルシステムであるZFSも標準で搭載されています。

ラズベリーパイでも動きます。

macOSは、カーネルは、MACHというものですが、ユーザランドのコマンドなどは、FreeBSD由来のものを移植しています。

この記事をみて、すこしでも興味をもたれた方は是非、ご参加ください。
横に1行で並べるスクロール可能なリストをCSSのみで表現

# はじめに
横に1行で並べるリストは「カルーセル」が有名で、多数のパッケージやライブラリが存在します。
一方で、スマートフォンでの操作はスワイプになるので、単純にスクロールできるだけで良い場合もあります。

以下では、横にスクロールができるメニューを作る想定でサンプルを紹介します。

# リストを横に並べる
まず、リストを横に並べます。

```html
<ul class="horizontal-list__list">
  <li class="horizontal-list__item">item1</li>
  <li class="horizontal-list__item">item2</li>
  <li class="horizontal-list__item">item3</li>
  ...
</ul>
```

```scss
ul {
  /* reset ul */
  margin: 0;
  padding: 0;
}

.horizontal-list {
  &__list {
    display: flex;
  }
  &__item {
    display: block;
    padding: 10px 20px;
    font-size: 20px;
    line-height: 1.5;
  }
}

```

# 画面幅を超えない範囲で表示するようにする
このままメニューを増やしていくと、画面幅を超えた時に、 **ウィンドウ内で** スクロールが発生してしまいます。
はみ出ないようにして、このメニューリストの中だけでスクロールするように `overflow-x: scroll` のスタイルを追加します。

https://developer.mozilla.org/ja/docs/Web/CSS/overflow-x

また、iOS Safariはこのままだと、カクカクしたスクロールになるため、なめらかに動かせるように `-webkit-overflow-scrolling: touch;` も追加します。

https://developer.mozilla.org/ja/docs/Web/CSS/-webkit-overflow-scrolling

```scss
.horizontal-list {
  &__list {
    display: flex;
    overflow-x: scroll; /* 追加 */
    -webkit-overflow-scrolling: touch; /* 追加。 iOS Safariでスクロールに慣性をもたせる */
  }
  ...
}
```

# padding-bottomでスクロールバーの位置を調整する
`overflow-x: scroll` を追加したことで、ほぼ目的は達成できていますが、スクロールバーがリストの下部にかぶってしまいます。

~~下部にかb~~

見た目的に気になるので、リストに `padding-bottom` を設定してあげます。

```scss
.horizontal-list {
  &__list {
    display: flex;
    overflow-x: scroll;
    padding-bottom: 20px; /* 追加(デザインにもよるので値は適宜で) */
  }
  ...
}
```

# リストの高さと同じ高さを持ったDOMでwrapしスクロールバーを消す
これで、基本的には完成なのですが、そもそもスクロールバーがデザイン上不要というケースもあるかと思います(個人的には必要派ですが、ニーズとしてあります)。

その場合は、このリストをwrapするDOMを作り、リストと同じ高さでかつはみ出た部分は隠すようなスタイルをつけるとスクロールバーが消えます。

```html
<div class="horixontal-list__wrap"> <!-- 追加 -->
  <ul class="horizontal-list__list">
    <li class="horizontal-list__item">item1</li>
    <li class="horizontal-list__item">item2</li>
    <li class="horizontal-list__item">item3</li>
    ...
  </ul>
</div>
```

```scss

.horizontal-list {
  /* 追加 */
  &__wrap {
    height: 50px; /* 中の要素の高さと同じ高さにして */
    overflow: hidden; /* はみ出たpadding-bottom分は非表示にする */
  }
  ...
}

```

## PCも考慮する場合
今回はスマートフォンのスワイプ操作を想定していますが、PC(特にWindows)の場合は、スクロールバーがないとスクロールが直感的にできないので、PCまでレスポンシブで対応させる場合は、ブレイクポイント
を決めて、メディアクエリでPC用のスタイルを用意するか、JSでブラウザを検知して、左右のナビゲーションアイコンを実装するなど工夫が必要になります。


# さいごに
これまでの流れをもとに作ったサンプルは以下です。
https://codepen.io/aktuehr/pen/povjpXP

実際はリンクを設定したり、カルーセルのように画像が配置されたりと行った事がありますので、これをベースにDOMを変更し、スタイルをアップデートすると簡易的なカルーセルができるかと思います。
slackbot備忘録 ~正規表現を使ったリクエスト編~

# はじめに
pythonを使ってslackbotを作成した備忘録パート３

[前回][1]から、だいぶ時間がたってしまった…


皆さん、よくこんなサンプル見ませんか？

> @respond_to("^test\s+\S.*")

私は最初、「こういうものなんだ！」と何も考えずに使っていた

しかし、よくよく考えると（）内は正規表現だと気づいた（遅い）

ということで「こんな respond_to 作りたいなぁ」という悩みがあったので、正規表現で解決してみた！

今回はその正規表現をまとめてみた

お品書きは以下の通り

* そもそも正規表現って何？
* よく使う正規表現
* 「文頭（文末）の文字に反応してほしいなぁ」
* 「test 〇〇みたいにコマンド形式に反応してほしいなぁ」
* 「複数の言葉でも、１回だけ処理を実行してほしいなぁ」
* 「複数部、可変的にとりたいなぁ」
* おわりに

# そもそも正規表現って何？
*正規表現*とは、「文字列の集合を一つの文字列で表現する方法の一つ」である

PHP, Perl, Python, Ruby などで使用することができる

Python には正規表現を使用した検索や置換などの操作を行うライブラリ（[re][2]）がある
しかし、今回は使用しないため、説明は省く

もしよかったら私がまとめた[正規表現][3]も見てやってください|дﾟ)

# よく使う正規表現

# 「文頭や文末の文字に反応してほしいなぁ」

```python
@respond_to("^おはよう")  # 文頭
@respond_to("こんばんは。$")  # 文末
def respond_func(message):
    message.react("+1")
```


![sb_sample1.png][a]

文頭には **^**, 文末には **$** を使用する 
しっかりと対応しているのがわかりますね！

```python
@respond_to("^こんにちは$"):
def respond_func(message):
    mes = message.body["text"]
    message.send(mes)
```

![sb_sample2.png][b]

二つを組み合わせると、「完全一致」の正規表現となる
「こんにちは」という言葉にしか反応しませんね！

# 「test 〇〇みたいにコマンド形式に反応してほしいなぁ」

```python

@listen_to("^repeat\s+\S.*")
def repeat_func(message):
    rep_str = message.body["text"][7:]
    message.send(rep_str)
```

みんなが大好きな正規表現

```\s+``` スペース（タブ）が1文字以上
```\S``` スペース（タブ）以外が１文字
```.*``` 任意の文字が0文字以上

となっている
\S がないとスペース（タブ）が1文字だけでも反応してしまうので注意

![sb_sample3.png][c]
このようにコマンドラインのようにボットを動かすこともできる！

# 「複数の言葉でも、１回だけ処理を実行してほしいなぁ」 

私は、最初にこれを思いつきました
* 良くない例

```python
@listen_to("いいね")
@listen_to("グッド")
@listen_to("good")
def reaction_func(message):
    message.react("+1")
```

これの良くない点は「いいね！グッド！good！」みたいに入力すると三回動いてしまうのです

![sb_sample4.png][d]

もちろん同じリアクションを一人で何個も付けることができないので、エラー```already_reacted```を吐く

正規表現を使用すれば、難なくクリアできる！

* 良い例

```python
@listen_to("いいね|グッド|good")
def reaction_func(message):
    message.react("+1")
```

**|** は正規表現で「or」の意味でしたね( ˘ω˘ )

![sb_sample5.png][e]

このようにエラーを吐くことなく処理を完了しました！

# 「複数部、可変的にとりたいなぁ」
現在、謎のエラーが大量セールのため調査中です… <(_ _ >)

# おわりに
正規表現は抱えていた悩みをたくさん吹き飛ばしてくれた！
最近は、slackbot上だけでなく業務でも正規表現を多用するようになった

はやく正規表現マスターになりたいなぁと思う今日この頃でした…！

[1]:https://qiita.com/str32/items/124d1c51500c8f4df7bb
[2]:https://docs.python.org/ja/3/library/re.html
[3]:https://qiita.com/str32/items/a692073af32757618042
[a]:https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435504/714ca541-3297-5f6d-c201-189f25d02327.png
[b]:https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435504/cd0ed2ea-b8d0-dbdf-0426-650e0832962d.png
[c]:https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435504/02a0cdc3-f3dc-60c6-9ff0-28c7efe09a11.png
[d]:https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435504/fbc9f91d-04ba-03d2-519b-b5511af00dfb.png
[e]:https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435504/d988895c-7715-e059-834a-5f4638a44d65.png
Qiitaでメールアドレスの認証ができない

# Qiitaのメアド認証ができない
![スクリーンショット 2019-12-07 22.16.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547316/f739a0b4-c61c-e8d0-6289-b5499f4ab865.png)
こんなん。
は？やったやんけちくしょうってときは、
**最初に送られたメールの認証先で認証しないと上手くいく**

##余談
何通でも遅れるのにこの仕様はダメなんじゃ……
おそらく、最初に発行された認証期限が切れないとダメだと思われる。（24時間ではないと思うが）
最初のメールが確認できない人は下記の投稿を参考にするといいかも
https://qiita.com/Kawaguchi410/items/b60f40f3c261ea770877

最初の投稿です。よろしくおねがします。
Djangoインストールからアプリ作成までのチュートリアル

#ほぼ初心者の方へ、Djangoの始め方
**コチラの記事はかなりDjango初心者の方向けに、インストールからやってみようという方向けの記事として作成されています。**

DjangoはPythonのプログラミング言語を用いたアプリケーションフレームワークです。Python を知らない方はDjangoを聞くと「は？」となる方が多いです。

そのため、認知度は低いほうかと思います。
しかし、覚えるポイントが簡単で、慣れれば使いこなせること間違いなし。
Djangoから始めてみようと思った方は私と一緒な感覚をお持ちかと思います(^^)/
シンプルな言語でスラスラかけるように補助しますので、頑張りましょう。
きっとかけるようになります。こんなプログラミングが苦手な私でも扱えるのですから！

##やってみよう！DjangoはAnaconda3を使ってインストールをする
リンク先で各インストール方法が記載されているので参考にしてみてください。
パソコンに無料でDjangoのインストールを行います。
1.[Anaconda3のインストール](https://weblabo.oscasierra.net/python-anaconda-install-windows/)
2.完了したら、[Djangoのインストール](https://max999blog.com/python-anaconda-django-env/)

インストールしたら、ターミナルを開き、Djangoの導入確認をしてみましょう。
ターミナルの開き方
1.Anaconda3ディレクトリのなかのAnaconda Navigatorをクリック
![無題1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547305/a15e902f-e232-846d-afc3-4e80b73260f1.png)
2.Environments(仮想環境)を選択し。▶ボタンをクリック
![無題2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547305/e7d5ebc3-d703-8b8d-12eb-8ce6da957dce.png)

ターミナル（黒い画面）で使用するコマンドはこちら

```
$ python
>>>import django
>>>django.VERSION
2.0
```
##Pythonのインストール
Anaconda3のインストールで完了済みです。

##ターミナルで最初のプロジェクトを作成
さぁ最初のプロジェクトを立ち上げです。
名前はお好きなように決めましょう。
現在のディレクトリにプロジェクトファイルが作成されますので注意！

プロジェクト作成コマンド

```
$ django-admin startproject mysite
```
コマンドをたたくと勝手にファイルを作成してくれるイメージ。
「mysite」の部分を好きなように変えられます。

##アプリを作成する
先ほど作成した、例でいう「mysite」にディレクトリを移動します。
使用するコマンドはこちらです。

```
$ cd mysite
```

##manage.pyでページ表示するためにサーバー起動
このmanage.pyが含まれるディレクトリがメインの親ディレクトリとなります。
DBのテーブルを作成したり、サーバーを起動する際にこのディレクトリに移動してきます。
とりあえず、何かいろいろとDBのテーブル作成だったりサーバー開始をしてくれるファイルであるという認識で問題ありません。

サーバー起動コマンド

```
users/user/mysite$ python manage.py runserver
```

ポートを選択可能

```
users/user/mysite$ python manage.py runserver 8080
```

実行後、ターミナルのこのような文が表示されていたらOKです。

```
Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).
December 07, 2019 - 23:09:01
Django version 2.2.5, using settings 'myapp2.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.
```

こちらの`http://127.0.0.1:8000/`を用います。
IEやChromeなどのエクスプローラを開き、URLへコピペすると、ロケット画面が表示されます。
![無題3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547305/d421eea1-d0da-8c8a-fc3e-ce779fbd7976.png)
やりました！

##途中でうまくいかないとき
プログラミングよりはターミナルでコマンドをたたいたり、環境設定を行う回となりました。
うまくいかない方はソフトのインストール手順を絶対に間違えないこと、Anaconda3を用いたDjangoのインストールを行うことをお勧めします。
Anaconda3を用いるとPythonのインストールが不要です。

余裕があれば仮想環境の用途について調べてみるとよいかもしれませんね(^^
文字詰めの世界への誘い

こんにちは。

今回は、「文字詰め（カーニング）」の世界の扉へご案内します。

突然ですが、名刺やショップカードを頂いた時に、制作者がデザイン経験者と非経験者を見分けれる箇所があります。

それは「：」の位置です。



##【Befor】
まずは、調整前のこちらをご覧ください。
![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536874/16bd9657-bb47-f5af-0744-88bad8f0c665.png)

何も感じない、見えていない方もいらっしゃるでしょうか。
私には恐ろしい存在が見えています。
誤ってこのまま世に出してしまえば、しばらく悪夢にうなされることでしょう。

##【調整】
それでは、調整してみましょう。
![02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536874/21418a96-c072-54b9-642a-89ec127d7fd3.png)

「：」コロンの位置を上げるだけです。簡単！

##【After】

![03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536874/d63901e6-cac6-002d-3a41-24d0f27882a1.png)

同じく、電話番号を記載する時などに使われる「-（ハイフン）」もベースラインを上げると、すっきりと整います。

今までに、この「：」の位置に注目したことはありますでしょうか。
イラストレーターの初期設定では、「：」や「-」が下に寄っているので、手動で調整しないとならないのです。デザイナー1年生が入社して自分の名刺を作った際に、先輩に直されて初めて気づくことが多い部分でもあります。（私もそうでした）

デザイナーそれぞれに文字詰めへのこだわりがあるので、聞いてみるのも面白いです。
その他の文字詰めの基礎は長くなるので今回は割愛いたします。

サイト内のパーツはもちろん、名刺、ショップカード、冊子や看板など、「：」を使うシーンは多いので、ぜひ、自分でデザインを行う時は「：」の位置を意識してみてください。
amp-twitter

# 目的
　\<amp-twitter>というgoogleのweb-componentを使ってみる
 →upしたからいろいろみてみたら、AMPに関しては勉強不足なんであまり参考にしない方がいいだろう
どうも、angularはangular-elementを使いこなすのが王道みたいだなあ・・

# 内容
こんな感じになる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60225/ad524875-389c-a958-c8be-5b6970b78784.png)
　https:/github.com/hideume/ang-simple-twitter

 はangularで作成したtwitter-clientである。ここで自分で動かすことができる。

　通常のimageタグとかを使わないで、かってにtwitterライクに埋め込んでくれる。

# index.html
３のソースを追加する

```html:index.html
  <link rel="canonical" href="公開するサイト名（自分？）">
  <script async custom-element="amp-twitter" src="https://cdn.ampproject.org/v0/amp-twitter-0.1.js"></script>
  <script async src="https://cdn.ampproject.org/v0.js"></script>
```

# 利用法
ソースの中では、tweetidを取得して

```js:tweet.pipe.ts
          text = text.replace(url.url, `<amp-twitter data-tweetid="`+ans[2]+`" width="500" height="50" layout="fixed" dnt="true" cards="hidden"></amp-twitter>`);
```
 という感じでurlをタグに置き換えている。ans[2]は取得したtwitteridである。

# なんだかエラー
TypeError: Cannot read property 'name' of undefined
とか、いろんなエラーが出ている状態だが、まあいいか・分かったらまた更新しよう
汚い環境変数PATHを整える

#現在のPATHを確認
**再設定の際に使うのでPATHを整形して控えておく。**

```
$ echo $PATH
 /home/yourname/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:
```

# PATHを消す
```
unset PATH
```

# 新しいPATHを通す
```
$ export PATH=$PATH:/usr/local/bin/:/usr/bin/
```
# 永続化
ターミナルで実行しただけだとその実行したターミナル内でしか有効にならないので`~/.bashrc`等に記述する。

```:~/.bashrc
export PATH=$PATH:/usr/local/bin/:/usr/bin/
```
```:更新
source ~/.bashrc
```
Swift Network.framework Study 20191207「Server UDP」

# Study

Network.framework
Study：Server側

## 環境

Client：Java、NetBeans
Server：Swift、Xcode

# Client Source Java

```java
package example.java.network;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class ExampleClientUDP {
    public static void main(String[] args) {
        String sendData = "Send Data Example";
        try {
            DatagramSocket datagramSocket = new DatagramSocket();
            DatagramPacket datagramPacke = new DatagramPacket(sendData.getBytes(), sendData.getBytes().length, InetAddress.getByName("localhost"), 7777);
            datagramSocket.send(datagramPacke);
        }
        catch(Exception e) {
            System.out.println(e);
        }
    }
}
```

# Server Source Swift

NWListerを使用する
tcp版から「.udp」に変更するのみ。

## main.swift

```swift
import Foundation
import Network

var networkServer = NetworkServer()

networkServer.startListener()

while networkServer.running {
    sleep(1)
}
```

## NetworkServer.swift
```swift
import Foundation
import Network

class NetworkServer {
    public var running = true

    func startListener() {
        let myQueue = DispatchQueue(label: "ExampleNetwork")

        do {
            let nWListener = try NWListener(using: .udp, on: 7777)
            nWListener.newConnectionHandler = { (newConnection) in
                print("New Connection!!")
                newConnection.start(queue: myQueue)
                self.receive(nWConnection: newConnection)
            }
            nWListener.start(queue: myQueue)
            print("start")
        }
        catch {
            print(error)
        }
    }
    
    func receive(nWConnection:NWConnection) {
        nWConnection.receive(minimumIncompleteLength: 1, maximumLength: 5, completion: { (data, context, flag, error) in
            print("receiveMessage")
            if let data = data {
                let receiveData = [UInt8](data)
                print(receiveData)
                print(flag)
                if(flag == false) {
                    self.receive(nWConnection: nWConnection)
                }
            }
            else {
                print("receiveMessage data nil")
            }
        })
    }
    
}
```
YAMAHAルーターでL2MSを使ったL2スイッチの制御ができなくなった話

# 前提
SWX2200(SWX2200-8G, SWX2200-24G等)、およびWLXシリーズ

# 問題事象
ルーターのマニュアルには「ポートのVLAN動作モードの設定[^1]」として設定値は下表の3種がある。


|設定値|説明|
|---|---|
|access|アクセスポート|
|trunk|トランクポート|
|hybrid|ハイブリッドポート|

「ポートのVLAN動作モードの設定[^1]」のページにおいて注意書きはないので、仮にも以下のようにルーターとL2スイッチをつなぐポートのmodeをtrunkにしようものならL2スイッチがL2MSで制御不能になる。

```
switch select lan1:1
 switch control function set vlan-port-mode 1 trunk
 switch control function set vlan-trunk 1 100 join
 switch control function set vlan-trunk 2 100 join
```

制御不能というのはコマンドでルーターから操作できなくなるばかりか、(もちろん、と言うべきなのかもしれないが)Web GUIのLANマップからもL2スイッチが見えなくなる。

# 対策
## L2スイッチの初期化

うっかりL2スイッチの設定中にL2MSで制御できなくなったら初期化をするのがベター。SWX2200-8G/SWX2200-24Gの取扱説明書[^2]に記載の以下の通りで初期化できる。

> MODEボタンを押したまま本製品の電源ケーブルをコンセントに接続すると、本製品の設定を初期化できます。

L2スイッチを初期化するとルーターからも当該L2スイッチの設定は消えている(はず)。そのため、設定の再投入が必要となる。

## configの修正

よくよく探せばL2MSのドキュメント[^3]にL2MSスレーブの制限として以下の記載がある。

> SWX2200、およびWLXシリーズでVLANを使用する場合は、L2MSの通信が行われるポートはアクセスポート、またはハイブリッドポートに設定してください。トランクポートではL2MSの通信を行うことができません。

よって、この通りポートのmodeをhybridとすることで解決する。

```
switch select lan1:1
 switch control function set vlan-port-mode 1 hybrid
 switch control function set vlan-trunk 1 100 join
 switch control function set vlan-trunk 2 100 join
```

# あとがき
SWX2210シリーズではmodeがtrunkでも本事象は発生しないのであろうか..

[^1]: http://www.rtpro.yamaha.co.jp/RT/manual/rtcommon/swctl/swctl_fnc_vlan_port_mode.html
[^2]: http://www.rtpro.yamaha.co.jp/RT/manual/swx2200/Users.pdf
[^3]: http://www.rtpro.yamaha.co.jp/RT/docs/swctl/
IIF文の[]位置

プロパティ内IIF文の[]位置によるエラーについて。
下記は、2表をクエリで結合済み。IsNull以下の値がテーブルに存在していなければ
T_sampleのカラムを、存在していればT_sample_afterのカラムを
フォームに呼び出す。

例文
=IIf(IsNull([T_sample].[kDate]),[T_sample].[kDate],[T_sample_after].[kDate])
↑
これで試したところ、該当フォームにエラーが出てしまった。

=IIf(IsNull([T_sample.kDate]),[T_sample.kDate],[T_sample_after.kDate])
↑
正しくは、こう。
はじめ、テーブル名とカラム名は別々でくくらなければならないと考えてていたが、
どうやら一括でくくるのが正しいらしい。

以上
Windows10にAnsibleとTerraformの実行環境をつくる（Vagrantで）

Windos10をクライアント端末としてIaCの勉強をしたくなったので
Vagrantで実行環境を作成しました。

#環境
Windows10 Pro 1809
Vagrant 2.2.6
VirtualBox 6.0.14 
※VMのOSはCentOS7.6、とりあえずgitも入れてる

Vagrantを使用することでwindowsの環境を汚さないでいろいろ実験できます。

#Ansible実行環境のVagrantfile
公式ドキュメントのインストール方法
https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html

```
Vagrant.configure('2') do |config|
  config.vm.box = "bento/centos-7.6"
  config.vm.hostname = "ansible.local"
  config.vm.network "private_network",ip: "192.168.33.10"  
  config.vm.define 'ansible' do |host|
  end
  config.vm.provider "virtualbox" do |vb|
    vb.name = "ansible.local"
    vb.customize ["modifyvm", :id, "--memory", "2048"]
  end
  config.vm.provider "virtualbox" do |vb|
    config.vm.provision :shell, inline:"sudo yum  install  epel-release -y >/dev/null 2&1"
    config.vm.provision :shell, inline:"sudo yum  install  ansible git -y >/dev/null 2&1"
  end
end
```

#Terraform実行環境のVagrantfile
公式ドキュメント(Terraformは)
https://www.terraform.io/intro/index.html
※wgetとか環境変を入れる実行も自動化したかったが何故か何重にも実行されるのでVM作成後に泣く泣くコマンド投入してます。。。

Terraformを動かすVMを作成

```
Vagrant.configure('2') do |config|
    config.vm.box = "bento/centos-7.6"
    config.vm.hostname = "terraform.local"
    config.vm.network "private_network",ip: "192.168.33.11"  
    config.vm.define 'terraform' do |host|
    end
    config.vm.provider "virtualbox" do |vb|
      vb.name = "terraform.local"
      vb.customize ["modifyvm", :id, "--memory", "2048"]
      config.vm.provision :shell, :inline:"yum install  wget unzip python3 git -y  >/dev/null 2&1"
  end
end
```



vagrant up後、OSにログインしてawscliを実行できるようにする(Teraaformを実行する対象はAWSを想定)
https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/install-linux.html

```
#vagrant ssh
[vagrant@terraform ~]$ wget https://bootstrap.pypa.io/get-pip.py
[vagrant@terraform ~]$ python3 get-pip.py --user
[vagrant@terraform ~]$ pip3 install --upgrade --user awscli
```

Terraformをダウンロードし使えるようにする

```
[vagrant@terraform ~]$ wget https://releases.hashicorp.com/terraform/0.12.16/terraform_0.12.16_linux_386.zip
[vagrant@terraform ~]$ sudo unzip terraform_0.12.16_linux_386.zip -d /usr/local/bin/
```

あとはクレデンシャルを環境変数にいれるなりすればAWSに対してTerraformが使用できる
【Rails】Deviseの基礎

# 初めに
Deviseはrailsを扱ったことがある人なら誰もが一度は実装するであろう有名なgemです。
しかし、機能自体は実装できたとしてもいまいちどこが動いて実装しているのかわからなかったり、いまいちどんな仕組みなのか掴めていない人も多いのではないでしょうか。
そこで今回はdeviseの基礎基本を自分なりに書いてみました。

#主な機能
Deviseは主に10個のmoduleからなるgemです。
一つ一つのmoduleを組み合わせてみなさんが使っているようなDeviseの機能として機能します。
しかし、最初から全てが機能しているわけではなく、最初は一部のみ機能しています。

|module名|機能|
|:---|:---|
|Database Authenticatable|データベースに保存するパスワードを暗号化する|
|omniauthable|facebookやtwetterなどを利用したログイン新規登録の機能を実装する際に使う（https://github.com/omniauth/omniauth）|
|confirmable|サインインをした際に既にアカウントが登録されているかどうかを確認できる|
|recoverable|ユーザーのパスワードをリセットできる|
|registerable|新規登録ができる機能。この機能を実装することにより、編集削除機能が使えるようになる|
|rememberable|cookieを使用し、ユーザー情報を保持する|
|trackable|サインイン回数・時刻・IPアドレスを保存する|
|timeoutable|指定された時間使用しなかったセッションを期限切れにする|
|validatable|メールアドレスとパスワードにバリデーションをかける|
|lockable|指定された回数サインインを失敗するとアカウントをロックする|

このmoduleを使用するかしないかの記述はuser.rbに記述します。(userの部分はdeviseに対応したファイル名)

```ruby:user.rb
class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable, :omniauthable
```

devise: の後ろに続くものが指定されたmodule名です。

rails consoleで`Devise.mappings`と打つと下記のような表示が出ますが、この中のmodulesというところに縦並びになっているものが機能しているmoduleとなります。

```terminal
[1] pry(main)> Devise.mappings
=> {:user=>
  #<Devise::Mapping:0x00007fc1a1255ae8
 ~省略~
   @modules=
    [:database_authenticatable,
     :rememberable,
     :omniauthable,
     :recoverable,
     :registerable,
     :validatable],
```
#ルーティング

普段Deviseを使う際に`routes.rb`に`devise_for :users`という記述をするかと思います。
この`users`という部分はdevise内のコントローラで処理をする際に、スコープを設定するという処理をしており、ルートやuser_sign_in?などのメソッド名にも影響しています。
もしもcurrent_userなどのdeviseのメソッドを使いたいのであればdevise_forを設定する必要があります。

またルートをカスタマイズしたいとき、例えば/users/sign_inを/sign_inに変更したい場合はdevise_scopeを用います。

```ruby:routes.rb
devise_scope :user do
  get 'sign_in', to: 'devise/sessions#new'
end
```
###参考記事
https://github.com/plataformatec/devise#configuring-routes
https://qiita.com/ShinyaKato/items/a098a741a142616a753e

#最後に
ごく断片的な記事になってしまいましたが一つでも参考になれれば幸いです。
Page Visibility APIでウェブページを開いているかどうかを監視する

自動スライドのスライダーを自作したことのある方なら、一度はドツボにはまったことがあるかもしれません・・・

### 例えばこのような場合・・・
setIntervalで自動スライドを表示しているページをページAとします。
ページAを開いているときにページAは閉じずに別タブでページBを開きます。
ページAに戻ったとき、setIntervalが狂ったように処理されます。(スライダーがグルングルンします。)

### 【原因】
別タブを開いている間、setIntervalの関数の処理が実行されずにキューに溜まり、戻った時に溜まっていたキューが一気に実行される為。

### 【解決する方法】
ウェブページを開いているかどうかを監視する。
開いていない間はsetIntervalの処理を止める。(clearInterval の処理をする。)

ここまでで
( ; ´Д｀) ＜ ナニイッテンダ・・・
となっている方もいるかもしれないので、デモページを作成しました。

デモページでは

* setIntervalの処理を実行している間、1〜10を無限ループでカウントして表示
* setIntervalの処理を止めるとき(clearInterval)、「タイマー停止。」と表示

させています。
ブラウザのログも出していますので、検証ツールでコンソールログをご確認ください。

[デモページ](http://azure-eyed-cat.com/demo/2017/04/)

ウェブページを開いているかどうかを監視する為に「[Page Visibility API](https://developer.mozilla.org/ja/docs/Web/Guide/User_experience/Using_the_Page_Visibility_API)」を使用しています。

使用例の記述をそのままコピペして、必要な処理だけ書き換えればデモのように動かせます。
以下のような場合に使えますので、使い所は多そうかなと思われます。

* 別タブを見ている間は動画の再生を止める
* 別タブで見ている間はsetIntervalの関数の実行を止める
'wchar.h' file not found

# はじめに
macOS 10.14Mojaveでは`make`出来ていたのに10.15Catalinaにアップデートした後にエラーがでるようになったので、その解決法を書いていきます。
# エラー文
```shell-session:macOS
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/wchar.h:119:15: fatal error: 
      'wchar.h' file not found
#include_next <wchar.h>
              ^~~~~~~~~
```
wchar.hというヘッダーファイルが見つからなかったと書いてあります。
# 試したこと
エラー文を検索し、この[サイト](https://qiita.com/tamutamuta/items/0ad8a11fe5d195aaffcb)を参考にして

```
$ brew reinstall gcc
```

```
$ xcode-select --install
```

を実行してみましたが私のPCでは違う問題が起きているようで再度同じエラーが出てしまいました。
このエラーはmacOSをMojaveにアップデートしたときにも起こるらしく、その解決法はネット上に沢山載っていたのですが、Catalinaにアップデートしたときの解決策はほとんど見受けられませんでした。
ようやくエラーを消すコマンド

```
$ make SDKROOT=`xcrun --show-sdk-path` MACOSX_DEPLOYMENT_TARGET=
```
を探し当てることが出来ました。
この[サイト](https://stackoverflow.com/questions/52509602/cant-compile-c-program-on-a-mac-after-upgrade-to-mojave)のコメントの中に書いてあったのですが、私はまだコマンドの意味が理解できていないので、理解でき次第追記したいと思います。
Object.prototype.map()が欲しい！

いきなり思いついたから書いた記事なんで、詳しい説明はありませんが。

```js
Object.prototype.map=function(c){return Object.keys(this).map(k=>[k,c(this[k],k,this)]).reduce((a,e)=>(a[e[0]]=e[1],a),{})};

({
    foo: 1,
    bar: 2,
    baz: 4,
    qux: 6
}).map((item, key, object) => ++item);

/*\
|r| {
|e|     foo: 2,
|t|     bar: 3,
|u|     baz: 5,
|r|     qux: 7
|n| }
\*/
```

お役に立てれば幸いです。
初心者によるプログラミング学習ログ 178日目

# 100日チャレンジの178日目

twitterの100日チャレンジ#タグ、#100DaysOfCode実施中です。
すでに100日超えましたが、継続。

100日チャレンジは、ぱぺまぺの中ではプログラミングに限らず継続学習のために使っています。

178日目は

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">おはようございます<br>178日目<br><br>webサイトコーディング課題<br>ナビにシャドウを適用<br>フッター一部作成<br><br>もうちょい・・・かな<a href="https://twitter.com/hashtag/100DaysOfCode?src=hash&amp;ref_src=twsrc%5Etfw">#100DaysOfCode</a> <a href="https://twitter.com/hashtag/%E9%A7%86%E3%81%91%E5%87%BA%E3%81%97%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%A8%E7%B9%8B%E3%81%8C%E3%82%8A%E3%81%9F%E3%81%84?src=hash&amp;ref_src=twsrc%5Etfw">#駆け出しエンジニアと繋がりたい</a> <a href="https://twitter.com/hashtag/%E6%97%A9%E8%B5%B7%E3%81%8D%E3%83%81%E3%83%A3%E3%83%AC%E3%83%B3%E3%82%B8?src=hash&amp;ref_src=twsrc%5Etfw">#早起きチャレンジ</a></p>&mdash; ぱぺまぺ@webエンジニアを目指したい社畜 (@yudapinokio) <a href="https://twitter.com/yudapinokio/status/1203042189405634561?ref_src=twsrc%5Etfw">December 6, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
Laravel 全カラム重複チェックに専用カラム

備忘録。
DBに専用カラム作成。-> sum_md5

```php:xxxx_create_addresses_table.php
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateAddressesTable extends Migration
{
    {
        Schema::create('addresses', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('user_id');
            $table->string('zip', 7);
            $table->string('state', 4);
            $table->string('city', 50);
            $table->string('street', 50);
            $table->string('sum_md5', 35);
            $table->timestamp('created_at')->default(DB::raw('CURRENT_TIMESTAMP'));
            $table->timestamp('updated_at')->default(DB::raw('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'));
            $table->softDeletes();
        });
    }
    public function down()
    {
        Schema::dropIfExists('addresses');
    }
}
```
seedデータ例

```php:AddressTableSeeder.php
<?php
//住所は架空のものです。
use Illuminate\Database\Seeder;
use App\Address;
class AddressTableSeeder extends Seeder
{
    public function run()
    {
        $user_id = 4;
        $zip = '0100831';
        $state = '秋田県';
        $city = '秋田市';
        $street = '旭川清澄町';
        $sum_md5 = md5($user_id . $zip . $state . $city . $street);
        Address::create(compact('user_id', 'zip', 'state', 'city', 'street', 'sum_md5'));

        $user_id = 5;
        $zip = '4880840';
        $state = '愛知県';
        $city = '尾張旭市';
        $street = '印旛元町';
        $sum_md5 = md5($user_id . $zip . $state . $city . $street);
        Address::create(compact('user_id', 'zip', 'state', 'city', 'street', 'sum_md5'));
    }
}
```

```php:Address.php
//データのmd5化
private function md5Address($req) {
    $sum_md5 = md5(Auth::id() . $req->zip . $req->state . $req->city . $req->street);
    return $sum_md5;
}
//１カラムで検索
private function hasSameData($request) {
    $same_count = $this->where('sum_md5', $request->sum_md5)->count();
    if (0 < $same_count) {
        return true;
    }
    return false;
}
//同じデータが無ければ新規登録
public function addDb($request) {
    $address = new Address;
    $sum_md5 = $this->md5Address($request);
    $request->merge(['user_id' => Auth::id()]);
    $request->merge(['sum_md5' => $sum_md5]);
    if ($this->hasSameData($request)) {
        session()->flash('error', '同じお届け先が既に登録されています');
        return false;
    }
    $address->fill($request->all())->save();
    session()->flash('success', 'お届け先を登録しました');
    return true;
}
```
LGTMお願いします！
励みになります！
artisan up/downがファイル書き込み権限エラーになる

Laravelのメンテナンスモードを有効化無効化する`artisan up/down`コマンドだが、`storage`ディレクトリにApacheなどWebサーバの権限を与えてるとSSHユーザーでコマンドを実行したときに権限エラーになってしまう。

```
$ php artisan down
Failed to enter maintenance mode.
file_put_contents(/home/user/app/storage/framework/down): failed to open stream: Permission denied
```

`sudo chown -R 777 storage`で一時的に権限を変えて書き込めるようにしてもよいが、`su`でWebサーバーのユーザーに成り代わって書き込むこともできる。

```
$ sudo -u apache php artisan down
Application is now in maintenance mode.
$ sudo -u apache php artisan up
Application is now live.
```
Vagrantfileで指定してはいけないIPアドレス

# TL;DR
VagrantゲストOSとの接続をプライベートネットワークとするときに、指定してはいけないアドレスがあるという話

# 本文
TL;DRにある通りですが、指定してはいけないアドレスがあります。以前はまったことを思い出したので、メモしておきます。

## 前提
VagrantゲストOSとの間にプライベートネットワークを構築するときは、以下のようになります。(経験則上のものなので違ってたらごめんなさい・・・)
- ネットワークアドレス長は24
- ホストOSが持つIPアドレスの第4オクテットは固定で1

## 本題、指定してはいけないアドレス
### ホストOSが属しているネットワークと同じネットワークアドレスになるようなアドレス

うまいことやってくれないかなーと期待しましたが、だめでした。

- 条件
  - ローカルPCが属するネットワークは192.168.11
  - Vagrantfileの記述は `config.vm.network "private_network", ip: "192.168.11.50"`

vagrant upの結果はこちら

```
The specified host network collides with a non-hostonly network!
This will cause your specified IP to be inaccessible. Please change
the IP or name of your host only network so that it no longer matches that of
a bridged or non-hostonly network.

Bridged Network Address: '192.168.11.0'
Host-only Network 'Intel(R) Ethernet Connection I218-LM': '192.168.11.0'
```
メッセージを読んでみれば致命的なのは明らかですが、特に[ERROR]とかわかりやすい表示もなく、ひっそりとvagrant upが終了してしまうので、見落としてしまうとはまるかもしれません。

### 第4オクテットが1のアドレス
前述の「前提」にあるように、第4オクテット1は、ホストOSが使います。なのでだめです。
この場合、なんだかいびつな状況になります。

- vagrant ssh は通ります
- ゲストOSから外部ネットワークへの接続もなぜか可能です。
- ホストOS、ゲストOSともに、同一のIPアドレスが設定されています。(ぉぃ
- できないことは多分、ホストOSからゲストOSへsshクライアントで接続すること、くらいでしょうか。

私はこれをやって「ssh接続だけなぜかできないな・・・まあいいか」という状態で仮想OSをしばらく使ってました。その後偶然、IPアドレスの重複に気づきました。

## あとがき
見当たらなかったけど、VirtualboxかVagrantの資料のどこかに書いてあるのかなあ・・・
Pycharmのtypeshedを上書きする

python3.8からfunctoolsにcached_propertyが追加されているが、PyCharmで候補にでてこなかった。

- python 3.8
- PyCharm 2019.2.5

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/9063/019a9f10-4db9-3076-9448-b6566ae41a5c.png)


PyCharmはtypeshedのコピーを持っていて、それが古いのが理由


最新のtypeshedを反映させるためには、プロジェクトディレクトリにtypeshedをcloneしてきて、Source Rootに指定する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/9063/f8f68616-0295-d722-622a-c5c2252b0a5e.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/9063/01e8c4b2-de09-1dcd-a054-2d96024971bc.png)


OK


参考)

- https://github.com/python/typeshed
- https://www.jetbrains.com/help/pycharm/type-hinting-in-product.html#typeshed