OmniAICreator/Qiita-1.07M huggingface dataset:
【SwiftUI】カスタムダイアログの表示と管理

# 【SwiftUI】 Manage Custom Dialogs

## Goal

* カスタムViewを作成しそれをダイアログとして表示する
* 複数のダイアログを表示できるようにする

## Background

SwiftUIでは[Alert](https://developer.apple.com/documentation/swiftui/alert)を利用することで標準のアラートを表示することができます。
しかし、`UIKit`を用いて開発していたときのように独自のViewをダイアログとして表示したいことがあります。
また、1つの画面で複数パターンのダイアログを表示することもあるでしょう。
そのような要件を満たすものを紹介します。

## Demo

今回作成するものは次のようになります。
全体のコードは最後にありますので参考にして下さい。

![Simulator Screen Recording - iPhone 12 - 2021-05-25 at 17.32.12.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138735/95afb3ed-1560-e65a-64eb-888af18ec466.gif)


## Content Pattern

まず、カスタムダイアログViewを作成します。
（後でダイアログの背景を透過する処理を共通で入れるので、その部分は不要です）

`View`を継承したパーツです。

![carbon.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138735/dbcb6ed5-5aa0-1d0d-a024-d836e855719d.png)

そしてこれらをまとめた`Enum`を作成します。
こうすることでアプリ内でカスタムダイアログを利用するケースを一覧で見られるようになり、また特定のケースで`View`を差し替えることも容易です。

![carbon2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138735/5e617263-a74b-cfb5-53ec-e997667a1668.png)

（`case`の命名が`contentDetail01`のようになっていますが、実際にはより詳細な命名が良いと思います。簡単化のためにそうしています。）

## Manage Dialog Presentation

次にダイアログの表示を制御するクラスを作成します。

* 表示フラグの更新
* 表示するコンテンツの設定

を担います。

![carbon3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138735/d12e5752-b87a-c4dc-f863-4fad18a588d2.png)

ダイアログを表示する`View`からは`show`メソッドを利用して任意のコンテンツを表示します。

## Custom Dialog Modifier 

カスタムダイアログを`ViewModifier`を経由して表示します。
これは[こちらの記事: Custom View Dialog in SwiftUI | Swift UI recipes](https://swiftuirecipes.com/blog/custom-view-dialog-in-swiftui)を参考にしています。

* `ViewModifiew`で元のコンテンツの上にカスタムダイアログを表示する
* 画面全体を覆う、黒の透過色を配置することでダイアログ風のUIにする

というのが主な点です。

![carbon4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138735/2493b371-f4a2-6e7b-f7f7-27e07ab0403c.png)

## Set Up

以上で要素が揃いました。
`View`でダイアログを表示してみましょう。

![carbon5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138735/e9ece4ab-da25-d3e3-9613-e51c37153f0f.png)

`View`では`DialogPresentation`を保持します。

```swift
 dialogPresentataion.show(
                    content: .contentDetail01(isPresented: $dialogPresentataion.isPresented))
```

のようにしてダイアログを表示します。
ダイアログ側で閉じるボタンを押した時にフラグを更新するので、`isPresented`を渡しています。

## Summary

ダイアログ表示の責務を持つ管理クラスを作成することで、ダイアログを表示する際の処理を隠蔽し、また複数の表示パターンに対応することができました。

より良い方法、問題点等ありましたら気軽にコメント頂けると幸いです。

コード全体は[こちら](https://gist.github.com/yyokii/af6c75bdc9a76233108ad7f45d0f0c50)

## References

* [Custom View Dialog in SwiftUI | Swift UI recipes](https://swiftuirecipes.com/blog/custom-view-dialog-in-swiftui)
[Laravel6.x] controllerとmiddlewareの実行順番


## 結論

LaravelのMiddleware前後の実行順番。下記でした。

1. Controller::__construct
1. Middlewareのbefore
1. Controller::__invoke等 (実行アプリケーション)
1. Middlewareのafter

## 所感

Middleware は 実行アプリケーションの前後で実行する事はあってたけど、コンストラクタはそれより前に実行されました。
なのでController::__construct でabort() 何てことをすると Middleware は全て実行されません。

Laravel の Middleware を生かすなら、Controller::__construct でabort() するような処理は Middleware に移動した方がよいと思います。

当記事は実行順番について調べてみたけど、Controller::__construct と middleware の実行順を説明する記事が見当たらなかったため、記事化しました。
（記事がないのは、当たり前すぎる内容だからないのかもしれませんね💦）

また、Laravel6.x と書きましたが、Laravel5.5～でも同じかと思います。

参考になれば幸いです。
【Mac】Hammerspoonを使って左Cmdキーで英字、右Cmdキーで日本語へ入力切り替えできるようにする

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/290998/8cfb9ce1-2bc3-7da3-e8b5-f1942d65a4aa.png)

Hammerspoonを使って左Cmdキーで英字入力、右Cmdキーで日本語入力に切り替える設定方法です。

## Hammerspoonインストール

brewでインストールできます。

```sh
$ brew install hammerspoon --cask
```

## 入力モード切り替え設定

Hammerspoonの設定ファイルに以下入力します。
luaで記述します。

```lua:~/.hammerspoon/init.lua
local simpleCmd = false
local map = hs.keycodes.map

local function kanaSwitchEvent(event)
    local c = event:getKeyCode()
    local f = event:getFlags()
    if event:getType() == hs.eventtap.event.types.keyDown then
        if f['cmd'] then
            simpleCmd = true
        end
    elseif event:getType() == hs.eventtap.event.types.flagsChanged then
        if not f['cmd'] then
            if simpleCmd == false then
                if c == map['cmd'] then
                    hs.keycodes.setMethod('Romaji')
                elseif c == map['rightcmd'] then
                    hs.keycodes.setMethod('Hiragana')
                end
            end
            simpleCmd = false
        end
    end
end

kanaSwitcher = hs.eventtap.new(
  {hs.eventtap.event.types.keyDown, hs.eventtap.event.types.flagsChanged},
  kanaSwitchEvent
)
kanaSwitcher:start()
```

左右Cmdキーの入力を検知後に他のキーを押さずに離すと入力を切り替えます。
Cmd+C（コピー）とかの場合は切り替わりません。 


## Hammerspoonの設定ファイル再読み込み


「Reload Config」をクリックして設定変更を反映します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/290998/bb120b36-39d6-9525-f587-344f12f4c266.png)

## 設定完了！

これで左Cmdキーで英字、右Cmdキーで日本語入力に切り替えられるようになります。

## Karabiner-elementsでいいじゃん

たしかに、Karabiner-elements でもまったく同じことができます。

Karabiner-elementsはキーボード入力をもとに設定できるのに対して、HammerspoonではMacOSが認識できるイベントを元に設定できます。

> http://www.hammerspoon.org/
You can write Lua code that interacts with OS X APIs for applications, windows, mouse pointers, filesystem objects, audio devices, batteries, screens, low-level keyboard/mouse events, clipboards, location services, wifi, and more.

そのため、Hammerspoonの方が拡張性が高いです。

例えば、「Macがパリにいることを検知すると、iTunesが自動的に再生を開始する」みたいな設定でもなんでもできます。

Mac上のキーボードショートカット設定がHammerspoonアプリひとつで完結できるのでオススメです。

## 参考

http://www.hammerspoon.org/

https://karabiner-elements.pqrs.org/
pandas dataframeを.to_csvした際に、文字化け/encording errorが出た際の対処法



## はじめに

dataframeを.to_csvでcsvにし、そのデータをエクセルで開いた際に、
データの日本語部分が文字化け&enconding errorが出てしてしまったので、
その際の対処法備忘録として書いておきたいと思います。

環境: MacOS Catalina


## 通常のcsv書き出し(データに日本語が入っていない場合)

```.py
import pandas as pd

df = pd.DataFrame([
  ["1", "taro"],
  ["2", "hanako"]],
  columns=['id', 'name'])

# test.csvとして出力
df.to_csv("test.csv")
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227613/362856c8-043c-e8de-e6c1-f57299f10c6a.png)

もちろん出力されたファイルをエクセルで開いても文字化けしない。

##  文字化けしてしまう(データに日本語が入っている場合)
```.py
import pandas as pd

df = pd.DataFrame([
  ["1", "太郎"],
  ["2", "花子"]],
  columns=['id', '名前'])

# test.csvとして出力
df.to_csv("test.csv")
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227613/2c852c60-980d-d40d-2835-e756017654ae.png)

日本語のところのみ文字化け

### 文字化けした際の対策
```.py
import pandas as pd

df = pd.DataFrame([
  ["1", "太郎"],
  ["2", "花子"]],
  columns=['id', '名前'])

# test.csvとして出力 encodingに"shift-jis"を指定。
df.to_csv("test.csv",encoding="shift-jis")
```
encodingを何も設定しない場合は、自動的に "utf-8" という文字コードが設定されてしまうそう。
それをshift-jisにすることで文字化けが解消される!
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227613/3ef9b1cc-ab84-bdab-8bda-077f4e370666.png)


# 文字化けは解消されたが、enconding errorが出てしまった・・・
他のデータフレーム(Windowsで作成したエクセルを取り込んだもの)も同じように、取り込んで、色々処理をした後、
.to_csvを使って、csvにしてみたところ、以下のエラーが。

```.py
import pandas as pd

# エクセルが置いてあるファイルパスを指定
filepaths = glob('./*.xlsx')
# 読み込んだエクセルを読み込む。読み込んだエクセルには、\n、¥n、\u0020などエスケープシーケンスが入った文字が多く入っている。
df = pd.read_excel(filepaths[0],engine='openpyxl')

...dfに対しての色々な処理(省略)....

# test.csvとして出力 encodingに"shift-jis"を指定。上と同じ。
df.to_csv("test.csv",encoding="shift-jis")
```

発生したエラー

```
File "pandas/_libs/writers.pyx", line 49, in pandas._libs.writers.write_csv_rows
UnicodeEncodeError: 'shift_jis' codec can't encode character '\u2161' in position 54: illegal multibyte sequence
```

\u2161という文字が、encodingで指定した文字コード、今回はshift-jisでは
割り当てていない文字とのことで、エラーが出てしまいました。




その場合は、以下のように書くと解消されました。

```.py
    # 一度ファイルオブジェクトをエラー無視して、書き込みで開くようにする
    with open("./output/test.csv", mode="w", encoding="shift-jis", errors="ignore") as f:
        # ここでデータフレームを開いたファイルにcsvで書き込む
        df.to_csv(f)
```

`errors="ignore"`で無効なバイト列を無視するを指定。
`mode="w"`で書き込む(write)という指定をしています。
errorsのオプションは`replace(無効なバイト列を？に置き換える)`、
`backslashreplace(無効なバイト列にバックスラッシュを添える)`、
`surrogateescape(サロゲート領域の代理バイト列に置き換える)`などあるそうです。
Sublime Text 4 のアップグレードで、タブキーや一部ショートカットキーが使えなくなった場合の対処法

環境は Mac。キーバインディングのデフォルト設定ファイルを初期化することで解決した。ショートカットは、"Wrap Selection With Tag" が効かなくなっていた。

"/Users/ユーザー名/Library/Application Support/Sublime Text 3/Packages/Default/Default (OSX).sublime-keymap" を削除(カスタマイズしてる場合は要バックアップ)し再起動。これで表記の現象は解決した。

再起動しても削除した Default (OSX).sublime-keymap が無い状態だが、Prefarences > Key Bindings で設定ファイル開き、保存すれば上記の場所にファイルとして生成される。デフォルトでなく User 設定でこと足りるなら特に生成する必要はない。


## 参考記事

* [Reverting Sublime Text to Its Default Configuration - Sublime Text Community Documentation](https://docs.sublimetext.io/guide/extensibility/packages.html#merging-and-order-of-precedence#reverting-sublime-text-to-its-default-configuration)
* [公式から v4 落とすとキーバインド正常になるっぽいから… - Twitter](https://twitter.com/smrz201/status/1399547729374703619)
RIGOLのオシロスコープ MSO5074の波形をPCで取得する

RIGOLのオシロスコープMSO5074をPCと接続してPC画面上に波形を表示したり，オシロスコープを遠隔操作する方法です．MSO5074は，USBメモリを接続して単体で画面をキャプチャすることができますが，PCに接続することでPC上で波形を表示したり，設定を変更したりすることが可能です．ここではLANで接続する場合について説明します．

## LANケーブルでMSO5074とPCを接続
LAN接続の場合は，PC側に特にアプリケーションをインストールする必要はありません．ブラウザから波形を閲覧したり，オシロスコープを操作できます．まず，LANケーブルでMSO5074とPCをネットワーク接続します．

## MSO5074のIPアドレスの設定と確認
MSO5074の操作パネルにある`Utility`を押し，`IO`を選択後`LAN`を選択します．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1583159/b6e99864-bd30-968f-0cc6-aeaff3f76c28.png)


LANネットワーク上にDHCPサーバがあって，IPアドレスを取得できる場合は，`IP Config Type`から`DHCP`を選択してください．PCとダイレクトに接続している場合などDHCPサーバが存在しない場合は，`DHCP`をオフにして`Auto IP`をオンにしてください．この場合，169.256. * . * というアドレスが割り当てられるはずです．これは**リンクローカルアドレス**または**自己割り当てIPアドレス（Auto IP）**と言われ，DHCPサーバが無い環境で自動的に割り当てられるIPアドレスです．

また，上記画面のとおり，WebControlのuidとパスワードはデフォルトで，`admin`と`rigol`になっています．

## PCからの接続
先ほどのIPアドレスにブラウザからアクセスしてみます．ブラウザのアドレスバーにIPアドレスを入力すればOKです．うまく接続できれば下記のような画面が表示されるはずです．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1583159/0b473075-6616-6fa5-70e7-ab3fbf00ad8d.png)


左メニューから`Print Screen`を押して，`Print Screen`ボタンを押してみましょう．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1583159/a1b30bb5-6007-a4cb-8988-a95f7de1bee1.png)




ブラウザの画面上にMSO5074の画面がそのまま表示されます．（が，あくまでスクリーンショットなのでリアルタイムに更新されるわけではありません）

左メニューの`Web Control`をクリックして，先ほどのuidとパスワードを入力してみます．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1583159/61155ae3-e37d-d3ca-152d-ce7281ac1466.png)

今度は，MSO5074の画面がリアルタイム（1.3fps程度）で表示されます．この状態であれば，ブラウザ上からオシロスコープを遠隔操作することもできます．少し遠くにあるオシロスコープの波形を観察したり，操作したりする場合は便利です．
AnacondaでStreamlitの環境を構築する

# はじめに
StreamlitをローカルPCのAnacondaでセットアップする方法の覚書となります。
StreamlitはOSSで、Pythonだけで可視化用のWEBアプリを簡単に作れます。
個人的には、レガシーな業務アプリを駆逐できる一つ手段だと感じています。

[Streamlitのサイト](https://streamlit.io/)


# セットアップ手順

## Anaconda Promptを起動する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533960/54caa532-a983-0979-e683-e706584b8ebe.png)


## 仮想環境一覧を表示して、重複しない環境名称を考える。

```
conda info -e
```


## 仮想環境を構築する。

```
conda create -n streamlit
```
環境名をstreamlitとしました。


## 仮想環境に切り替える。

```
conda activate streamlit
```
作成した仮想環境名に適宜修正してください。

## ライブラリをインストールする。

```
conda install -c conda-forge streamlit -y
conda install -c conda-forge opencv -y
```
OpenCVで画像処理後の画像を確認するWEBアプリを作ろうと思います。
したがって、OpenCVのライブラリもインストールしておきます。


## Streamlitのサンプルを起動する。
 
```
streamlit hello
```
Anaconda Promptに下記が出てくれば構築完了です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533960/887b05ab-12e9-f54a-6193-2d5f4b8ffb00.png)

## ブラウザで確認する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533960/fa2b0cb3-a0c9-86ed-ff4c-3977ea4990b7.png)
ブラウザでデモアプリを確認することができます。

以上。
nullについて

##▼null
nullとは・・・オブジェクトの参照を持たないことを意味する値

**オブジェクトの参照**とはなんぞや？？
Kotlinでは値=オブジェクト。
値（オブジェクト）は、コンピュータのメモリに格納されることで保持できている。
ここに割り当てられてますよーという住所のようなものがオブジェクトごとに与えられてる。
この住所のようなものを「メモリアドレス」という。
メモリアドレスという一つの住所に、一つのオブジェクトが入っている状態をさす。

変数は、このメモリアドレスを参照して格納されてる値（オブジェクト）を引き出すための仕組みなので、
変数にオブジェクトの参照が設定されていない状態を「**null**」という

Kotlinでは原則、「<font color="Red">nullを許容しない(null禁止)</font>」設定になっているため、以下のようにfooにnullを代入しようとするとエラーが起こる

```kotlin
var foo:String = "foo"
foo = null  //エラー
```
逆にあえてnullを許容したいときには型の後ろに「?」をつけてあげる

```kotlin
var foo:String? = "foo"
foo = null
```
こういうnullを許容してあげることを「**nullable型（null許容型）**」という
※他の型でも使える


そもそもKotlinでnullを禁止にしたのは、nullがあることでエラーを起こす可能性が高まるから。
そのため、禁止になっているのに使えるようにする場合には注意点がある。

###●非null型をnullable型に代入するとボクシング（暗黙的な型変換）が起きる
例）変数aを非null型bとnullable型cにそれぞれ代入

補足：同じ値を持つことを**同値**、同じオブジェクトを持つことを**同一**といい、
同値の比較には「==」、同一の比較には「===」の演算子を使う

```kotlin
var a:Int = 1000
var b:Int = a
var c:Int? = a
println(a == b) //結果：true
println(a === b) //結果：true
println(a == c) //結果：true
println(a ==== c) //結果：false
```
この場合、aとbは同じ値で同じオブジェクトのため、trueになる。
（aとbの値は1000、aとbのオブジェクトはどちらも**非null型**）

だけど、cに代入した場合、値は同じ1000でtrueになっても、オブジェクトが違っている。
aのオブジェクトは非null型に対して、cはnullable型。
ここが違うため、オブジェクトはfalseになっている。

これは、非null型をnullable型に代入するとボクシング(暗黙的な型変換)が起こるという現象になっている。


###●nullable型を非null型に代入することはできない
例）非null型のStringにnullable型を代入してもエラーになるが、Any型ならどうなるか？

補足：Any型：すべての任意のデータ型を代入できる

```kotlin
var foo1:String? = "foo"
var foo2:String = foo1  //エラー
```
```kotlin
var a1:String? = "a"
var a2:Any = a1  //エラー
```

結果としては、Any型でもエラーになる。
Any型もnullを許容しないので、エラーになっている。
Any?として、nullable型に変更すればエラーはでない。

Any型は全ての任意のデータ型を代入できるが、詳しくいうと
「Any型を指定すると任意の**非null型**を代入できる」
また、「Any?型を指定すると、任意の**null型を含む型**を代入できる」

###●nullable型のメンバにアクセスする場合は、「?.(セーフコール演算子)」を使う

例）lengthプロパティにアクセスしたい

補足：
メンバ：オブジェクトに定義されているフィールド変数やメソッド
lengthプロパティ：文字列の長さや配列の要素数を取得する

```kotlin
var a:String? = "foo"
println(a?.length)   //結果：3
```
```kotlin
var b:String? = null
println(b?.length)   //結果：null
```

nullable型の変数をlengthプロパティにアクセスして表示させたい場合には、「**?.(セーフコール演算子)**」というものを使う。
これを使うことによって、エラーが起きることなくアクセスさせられる。

また、これでnullにアクセスした場合には、エラーとはならず、nullが返ってくる。
nullを返すのではなく、既定値を設定したい場合には、「**?:**」演算子を使う

```kotlin
var b:String? = null
println(b?.length ?: 0)   //結果：0
```

nullable型を強制的に非null型にしたいときは「**!!**」演算子を使う
※ただし、これはnullable型を非null型にするときにのみ利用するため、もしaが非null型であった場合にはエラーが発生するので注意！

```kotlin
var a:String? = "foo"
println(a!!.length)   //結果：3
```
Pythonの便利技と注意点（私的備忘録＆私的閲覧用）

個人的に「これは便利」と思ったものを個人的に備忘録的にメモしてるだけですが、よかったらご参考までに。少しずつ更新していきます。

※2022年8月26日、1記事にいくつも書くと編集が厳しいので、各項目ごとに記事を分けました
※当記事は各項目への目次に致しました

[■コードスタイル規約編](https://qiita.com/yuta-sanjyo/items/bae5d9f09dcdd6d31f88)
[■計算編](https://qiita.com/yuta-sanjyo/items/3b8318363dd9508ca899)
[■文字列編](https://qiita.com/yuta-sanjyo/items/5080db30d8fbdfaba8a2)
[■繰り返し編](https://qiita.com/yuta-sanjyo/items/d2eb194ec19665bad845)
[■条件編](https://qiita.com/yuta-sanjyo/items/6048fdca7cc36ea69863)
[■リスト編](https://qiita.com/yuta-sanjyo/items/10fa5faf6c72be5acca2)
[■タプル編](https://qiita.com/yuta-sanjyo/items/0ce5df67023d46bc1ff4)
[■辞書編](https://qiita.com/yuta-sanjyo/items/1e7d08eb38581968f29e)
[■format編](https://qiita.com/yuta-sanjyo/items/f1b6878b1232a48d2634)
[■関数編](https://qiita.com/yuta-sanjyo/items/e53d015bcbaed9fe5885)
[■Pandas編](https://qiita.com/yuta-sanjyo/items/fd7ca4a4bd8082e2adc7)
[■Jupyter編](https://qiita.com/yuta-sanjyo/items/4d0d937e97a05f4d01e5)
[■PyCharm編](https://qiita.com/Uta-san/items/1a47986aae653e50e761)
[■変数編](https://qiita.com/yuta-sanjyo/items/2a7a4115df3018af8d3a)
[■print編](https://qiita.com/yuta-sanjyo/items/f03321a06fdd81bfb6c3)
[■ファイル読み書き編](https://qiita.com/yuta-sanjyo/items/6fb3377f9051ae18040b)
【Rails】rack-corsで複数サブドメインからAPIリクエスト時のCORSエラーを回避する

# 別Originからリクエストを受けるときはCORS対応が必要
他OriginからAPIサーバへのリクエストを許可したいとき、[CORS](https://developer.mozilla.org/ja/docs/Web/HTTP/CORS)を意識する必要があります。
1つだけであれば[Access-Control-Allow-Origin](https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Access-Control-Allow-Origin)ヘッダにそのOriginを設定すれば良いです。

しかし、Access-Control-Allow-Originヘッダには一つのOriginしか設定できません。

https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
>`<origin>`
オリジンを指定します。1つのオリジンだけを指定することができます。
サーバーが複数のオリジンからのクライアントに対応している場合、リクエストを行った特定のクライアントのオリジンを返さなければなりません。

複数のOriginに対応する場合、リクエスト元のOriginをもとにAccess-Control-Allow-Originヘッダを設定する必要があります。

## rack-corsで複数Originからのリクエスト許可設定

Railsの場合は[rack-cors](https://github.com/cyu/rack-cors)を使用すると楽に実装できます。
許可Originに正規表現を使って設定できるので、特定のドメイン配下のサブドメイン全部でもなんでも設定できます。

以下、`example.com`のOriginから `/api/`配下のパスへのリクエストを許可する設定例です。

```rb:config/initializers/rack_cors.rb
use Rack::Cors do
  allow do
    origins /\Ahttps:\/\/.*.example.com\z/

    resource(
      '/api/*',
      headers: :any,
      methods: [:get, :post, :delete, :put, :patch, :options, :head],
    )
  end
end
```


[rack-corsのREADME](https://github.com/cyu/rack-cors#origin)にも書かれていますが、正規表現の設定に不備があるとセキュリティリスクになるのでくれぐれも慎重に。。

## 参考

https://github.com/cyu/rack-cors

https://developer.mozilla.org/ja/docs/Web/HTTP/CORS

https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
VBA エクセル　グラフシート作成　埋め込みグラフ作成

![1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1614609/f5489a14-dba4-b44d-cfde-2e30d61aa60e.jpeg)
![2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1614609/34df2563-5590-9133-97ea-31e1ab86a6dc.jpeg)

```vb
Sub グラフシートに作成()
'グラフシートにマーカー付折れ線グラフを作成
    With Charts.Add
        .ChartType = xlLineMarkers
        .SetSourceData Source:=Sheets("Sheet1").Range("A3:G8")
    End With
End Sub

```
![3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1614609/df536476-f921-f63a-5eed-ddb80b4cfbfe.jpeg)

```vb
Sub 埋め込みグラフを作成()
'横棒グラフの作成
    With ActiveSheet.ChartObjects.Add(10, 120, 400, 250).Chart
        .ChartType = 57
        .SetSourceData Source:=Range("A3:G8")
    End With
    'グラフタイトルの追加()
    With ActiveSheet.ChartObjects(1).Chart
        .HasTitle = True
        .ChartTitle.Characters.Text = "事業部別売上"
    '軸ラベルの追加()
        .Axes(xlCategory).HasTitle = True
        .Axes(xlCategory).AxisTitle.Characters.Text = "上半期"
        .Axes(xlValue).HasTitle = True
        .Axes(xlValue).AxisTitle.Characters.Text = "金額"
    '軸ラベルの書式設定()
    '項目軸ラベルの文字列を縦に
        .Axes(xlCategory).AxisTitle.Orientation = xlVertical
    'グラフタイトルの文字サイズ変更()
        .ChartTitle.Font.Size = 14
     End With
End Sub


```
Kotlinで$をエスケープ

Kotlinには以下のようなString templates﻿という変数を埋め込む機能があるが、

```kotlin
// kotlin の　String templatesサンプル
val language = "Japanese"
val test = "${language}"
println(test) // Japanese　と出力される
```

この機能では＄を利用するため、$にはエスケープが必要で少し特殊なエスケープ方法となっている。
具体的にはエスケープする文字を`${'$'}`とする必要がある。

以下サンプルコード

```kotlin
// kotlin の　「$」　のエスケープサンプル
val language = "Japanese"
val test = "${'$'}{${language}}"
println(test) // ${Japanese}　と出力される
```

参考
https://kotlinlang.org/docs/basic-types.html#string-templates
IntelliJ IDEAで「No suitable driver found for jdbc:postgresql」が出たときの対処法

# 環境
- IntelliJ IDEA community版 (2020.2.4)
- WSL2(Ubuntu 20.04)
- PostgreSQL 12.7
- PostgreSQLでテーブル作成が完了していること（テーブルの中身は任意）

# 目的
- JavaのプログラムからPostgreSQLで作成したテーブルを読みたい(selectしたい）
- JDBCを使いたい

# エラー内容

次のようなJavaプログラムをIntelliJ IDEAで実行しようとすると、
ビルド時に「No suitable driver found for jdbc:postgresql」というエラーが発生します。


```java:TestClass.c
import java.sql.*;


public class TestClass{
    public static void main(String[] args) {
        //接続文字列（ユーザ名とパスワードは各自の設定に合わせてください）
        String url = "jdbc:postgresql://localhost:5432/postgres";
        String user = "user";
        String password = "pass";

        try {
            //PostgreSQLへ接続
            Connection conn = DriverManager.getConnection(url, user, password);

            //自動コミットOFF
            conn.setAutoCommit(false);

            //SELECT文の実行
            String qry = "SELECT * FROM XXテーブル WHERE YY番号 = ?";
            PreparedStatement ps = conn.prepareStatement(qry);
            ps.setInt(1, Integer.parseInt(args[0]));

            // SQL文を実行した結果を受け取る
            ResultSet rset = ps.executeQuery();
            
            // 以降、省略

        } catch (SQLException throwable) {
            throwable.printStackTrace();
        }
    }
}
```

# 対処法

1. [こちら](https://jdbc.postgresql.org/download.html)からPostgreSQLのJDBCドライバ(4.2)をダウンロードします。
1. IntelliJ IDEAの [ファイル] - [プロジェクト構造]を選択します。
1. 表示されたプロジェクト構造ウインドウの左メニューにある「モジュール」を選択します。
1. プロジェクト構造ウインドウの右の方にある「＋」（追加）をクリックして、JARs ordirectoriesを選択します。
1. ダウンロードしたJDBCドライバの.jarファイルを選択します。
1. 適用をクリックします。
1. 再度ビルドを実行します。
1. 以上で、「No suitable driver found for jdbc:postgresql」のエラーが解消されます。

##
【javascript】TABLEのテキストを二次元配列で取得（結合セル対応）リベンジ

https://qiita.com/noenture/items/71ee266ec2a8a16a0fbe



#概要

|head1|head2|haed3|head4|head5|
|:--:|:--:|:--:|:--:|:--:|
|1-1|1-2|1-3|1-4|1-5|
|2-1|2-2|2-3|2-4|2-5|
|3-1|3-2|3-3|3-4|3-5|

こんな感じのテーブルを

```javascript
[
	['head1','head2', 'haed3', 'head4', 'head5'],
	['1-1', '1-2', '1-3', '1-4', '1-5'],
	['2-1', '2-2', '2-3', '2-4', '2-5'],
	['3-1', '3-2', '3-3', '3-4', '3-5']
]
```

二次元配列として取得します。
結合されたセルに対しては、結合元と同じテキストで埋めます。

#コード
コメントの指摘に対応できそうにないので
<details><summary>リベンジ失敗</summary><div>

```javascript:
const getTableTexts = table => {
	const result = [];
	const rows = table.rows;
	let y = rows.length;
	while (--y > -1) {	//各行のループ
		const rowResult = [];
		const cells = rows[y].cells;
		const m = cells.length;
		let colSum = 0;	//各行のcolspan合計
		let x = -1;
		while (++x < m) {	//行内セルのループ
			const cell = cells[x]
			const text = cell.textContent;
			const cs = cell.colSpan;
			let rs = cell.rowSpan - 1;
			if (cs===1) {
				rowResult.push(text);
				//結合セル[縦]対応
				while (--rs > -1) result[rs].splice(colSum, 0, text);
			} else {	//結合セル[横]対応
				const multi = Array(cs).fill(text);
				rowResult.push(...multi);
				//結合セル[縦]対応
				while (--rs > -1) result[rs].splice(colSum, 0, ...multi);
			}
			colSum += cs;
		}
		result.unshift(rowResult);
	}
	return result;
};

const tableTexts = getTableTexts(document.getElementsByTagName('table')[0]);
console.table(tableTexts);
```

</div></details>
リモートブランチを正として、ローカルブランチに反映させるGitコマンド

ローカルブランチの変更内容を捨てて、リモートブランチの内容をローカルに持ってくるには以下コマンドを実行します。

```bash
$ git fetch && git reset --hard origin/[ブランチ名]
```

## 参考

https://git-scm.com/docs/git-fetch

https://git-scm.com/docs/git-reset
ローカルの変更を取り消すGitコマンド

ローカルの変更を全て取り消すには以下コマンドを実行します。

```sh
$ git stash save -u && git stash drop
```

`stash save` に `-u` オプション指定でuntrackファイルも含めてstashします。
そのstashをdropすることで変更を取り消します。

## 参考

https://git-scm.com/docs/git-stash#Documentation/git-stash.txt-save-p--patch-k--no-keep-index-u--include-untracked-a--all-q--quietltmessagegt
リテラル表現

##▼リテラル表現
リテラルとは・・・ソースコードの中に直接書き込んである文字や数字のこと
リテラル表現とは・・・ソースコードの中の文字や数字の書き方や表現方法のこと


リテラル表現には、数値リテラルと文字列リテラルがある。

###●数値リテラル
数値リテラルとはその名のとおり、数字を書き込んでいるもの
主な数値リテラルは以下

```kotlin
var a = 100 //10進数
var b = 0x0F //16進数（「0x」で始める）
var c = 0b1010 //2進数（「0b、0B」で始める）
var d = 1.23 //浮動小数点
var e = 1.23e+5 //浮動小数点（指数）
```
※浮動小数点（指数）は、1.23に×10の５乗
<br>
桁区切り文字として「**_(アンダースコア)**」を利用することもできる

```kotlin
var a = 123_456_789
var b = 0xAA_BB_CC
```
「_」を使って書いても中身は同じになるので、見やすい方を使っていく。
<br>
**型サフィックス**を使ってデータ型を指定することもできる
サフィックスとは・・・文字や数字の後ろにつけて意味をつけること

```kotlin
var a = 10L //Long型
var b = 10f //float型
println(a::class)
println(b::class)

//結果
//class Kotlin.Long
//class Kotlin.float
```

※サフィックスは大文字小文字を区別しないから小文字で書いてもOKだが、「L」に関しては小文字だと1と区別しづらいので禁止されてる。

###●文字列リテラル
文字列リテラルには２種類ある
**Escaped String**：エスケープ文字を含む文字列
**Raw String**：改行やタブなど、任意の文字列を含む文字列

Escaped Stringでの書き方

```kotlin
var msg1 = "どうも。\nわたしはKotlinを学んでます。"
println(msg1)

//結果
//どうも。
//わたしはKotlinを学んでます。
```

Escaped Stringでは、改行を意味する「**\n**」を使っている。

Raw Stringでの書き方

```kotlin
var msg2 = """どうも。
わたしはKotlinを学んでます。"""
println(msg2)

//結果
//どうも。
//わたしはKotlinを学んでます。
```

Raw Stringでは、「**"(ダブルクォーテーション)**」を３つ使い、コード内で改行して表示している。

※Raw Stringでは、コード内で改行してあげると表示したときにズレることがある。
コードでも見やすく、表示でも見やすくするためには「<font color="Red">trimMargin()</font>」メソッドを使う。
この場合、改行した頭には「<font color="Red">|</font>」をつける。

```kotlin
var msg2 = """どうも。
           |わたしはKotlinを学んでます。""".trimMargin()
println(msg2)
```

<br>
また、Kotlinには、**文字列テンプレート**というのがある。
→任意の式を埋め込むことができる機能
コード内で文章を書くときなどによく使う「${}」は文字列テンプレート。
文字列テンプレートは任意の式を埋め込めるので、計算や配列を呼び出すことが可能になる

```kotlin
var data = arrayOf(1,2,3)
println("配列dataの頭は${data[0]}で、要素の数は${data.size}。")
println("1+1は${1+1}です。")

//結果
//配列dataの頭は1で、要素の数は3。
//1+1は2です。
```
Railsアプリケーションの削除（Rails db:drop）

## 結論
1) アプリケーションを削除する前にはralis db:dropを該当するアプリケーションディレクトリで実行する必要がある。
2) 既にファイルが存在しない、UP状態のマイグレーションファイルが存在する場合はrails db:migrate:resetを実行する必要がある。
## 環境
Ruby  2.6.5
Rails 6.0.0
## 発生したエラー
### 状況：
railsを学習するために同じアプリケーションをもう一度作成する際に発生しました。
一度目のアプリケーションはfinderから直接削除。
具体的には、2つ目のアプリケーションでテーブルを作成し、マイグレートしようとした際に発生しました。
### 原因：
直接の原因は、前回のアプリケーションのデータベースを削除していなかったことでした。
削除済みのマイグレーションファイルがUP、Nofileの状態で残っており、マイグレートを実行する際にエラーが起きていました。
### 解決方法：
下記のコードをアプリケーションのディレクトリで実行することで解決できました。Nofileのマイグレーションファイルの削除だけでなく、新しいマイグレーションファイルのマイグレートまで実行できるようです。

```
$ rails db:migrate:reset
```
### アプリケーションの削除：
アプリケーションの１つ上のディレクトリで、下記のコマンドを実行する。

```
$ rm -rf アプリ名
```
## 終わりに
ruby on railsの仕組みへの理解が浅かったためにレベルの低いミスをしてしまったと反省しています。
学習中もデータベースに起因するエラーが多いので、モデル部分も含めて理解を深めていきたいです。
PHP基礎メモその4

#$_GET
＄_GETはクエリ情報を受け取るのに用いる。＄_GETにはクエリ情報が連想配列として入っている。
よって、＄_GET['キー名']のように値をとりだすことができる。
>```php:index.php
<a href="shoe.php?name=CURRY">
  CURRY
</a>
```

href属性のnameがキー名でCURRYが値となる
>```php:show.php
echo $_GET['name'];
// キー名を指定して値を取り出す
```

結果
CURRY

>```php:$_GETの中身（連想配列）
array(
  'name'=>'CURRY'
  // キー名=>値
)
```

#return
returnには戻り値を指定するだけではなく、returnが呼ばれた部分で関数やメソッドの処理を終了させるという性質がある。
>```php
function getLargerNum($num1, $num2) {
  if($num > $num2) {
    echo '$num1は$num2より大きい';
    return $num;
  }
  // 上記のif文内のreturnが呼ばれると、この処理は実行されない
  echo '$num2は$num1より大きいか、$num1と同じ';
  return $num2;
}
```
```php
$result = getLargerNum(5, 1);
>
echo $result;
```

結果
＄num1は＄num2より大きい
5

例
>```php
class Menu {
  public static function findByName($menus, $name) {
    foreach($menus as $menu) {
      // インスタンスのnameプロパティの値と$nameの値が一致したら、そのインスタンスを返す
      if($menu->getName() == $name) {
        return $menu;
      }
    }
  }
}
```
【Android / Kotlin】URL から拡張子を取得する

# はじめに
Android の開発にて
uriの最後の拡張子に応じて処理をハンドリングしたい、という場面がありました。

そのときのコードのメモ

拡張子の例として ``xxx.html`` ``xxx.png`` ``xxx.jpg`` ``xxx.pdf`` ``xxx.zip`` などがあると思います。

### @sdkei さんにご指摘をいただき最後に補足をしております

# サンプルのURL
[港区役所](https://www.city.minato.tokyo.jp/shibamadochou/kurashi/todokede/juminhyo.html)のサイトURLを利用させていただきました。

今回で言うと、この最後の``html``の部分を取得したい。

```
https://www.city.minato.tokyo.jp/shibamadochou/kurashi/todokede/juminhyo.html
```

# パターン1
```kotlin
val url = Uri.parse("https://www.city.minato.tokyo.jp/shibamadochou/kurashi/todokede/juminhyo.html")

val extension1 = url.lastPathSegment?.split(".")?.lastOrNull()
println("extension1: $extension1") // => extension1: html
```

# パターン2
```kotlin
val url = Uri.parse("https://www.city.minato.tokyo.jp/shibamadochou/kurashi/todokede/juminhyo.html")
        
val extension2 = url.lastPathSegment?.let {
    it.substring(it.lastIndexOf(".") + 1)
}
println("extension2: $extension2") // => extension2: html
```

パターン１の方がスマートにかけている印象

# おまけ
``Uriクラス``がもつpathを取得するメソッドを使うとこんな感じに取得できる。

```
元となるURL
https://www.city.minato.tokyo.jp/shibamadochou/kurashi/todokede/juminhyo.html
```

```kotlin
println(url.path) // => /shibamadochou/kurashi/todokede/juminhyo.html
println(url.pathSegments) // => [shibamadochou, kurashi, todokede, juminhyo.html]
println(url.lastPathSegment) // => juminhyo.html
```

今回は``lastPathSegment``を利用

# 参考
https://developer.android.com/reference/android/net/Uri

ありがとうございました！！

# 最後に（補足）
@sdkei さんにご指摘をいただきました！感謝です！

``String``の拡張関数``substringAfterLast``で簡単に``"."``以降を取得できる！
便利すぎる…

勉強になりました！！


```kotlin
val urlStr = "https://www.city.minato.tokyo.jp/shibamadochou/kurashi/todokede/juminhyo.html"

val extension3 = urlStr.substringAfterLast(".")
println(extension3) // => html
```
文章を一部縦書きにしたい。

一部文章を縦書きにしたい場合があると思います。今回は例を　**ありがとう**　としたいと思います。

縦書きにするCSS

```
writing-mode: vertical-rl;
```

＊上記の場合、テキストを右から左に並べます。一般的な日本語の縦書きです。
ちなみに`vertical-lr`にした場合左から右に並べられます。

しかし、これだとただ９０度回転しただけなため、一般的な縦書きにはまだならないです。
そこで、縦書きにした際に文字を縦にするCSSを追加します。

```
text-orientation: upright;
```
*text-orientation　の場合ほかに　`sideways`,`mixed`という値があります。
`sideways`は`text-orientation`のプロパティを追加する前と変わらないです。
`mixed`は英語のみ文字が横のままになります。

これで以下のように文章を縦書きに出来ます。

```
あ
り
が
と
う
```
JavaScriptの顔検出ライブラリ「clmtrackr」は video タグの width と height を属性として指定しないと顔検出しない

## TL;DR
clmtrackr に読み込ませる video タグには width と height をスタイルではなく属性として指定するんだ！

## 解決方法
顔検出が成功する例と失敗する例を挙げておきます。

### 成功例
```html
<video id="video" width="400" height="300"></video>
```
### 失敗例
```html:失敗例①
<video id="video" width="100%" height="auto"></video>
```
```html:失敗例②
<video id="video" style="min-width: 100%"></video>
```

どうやら Element が作成されたタイミングで width と height が指定されていないといけないようです。
JavaScript で後付けで width プロパティと height プロパティに値を代入してみましたが、成功するようにはなりませんでした。

## ライブラリ紹介（clmtrackr）
auduno/clmtrackr： Javascript library for precise tracking of facial features via Constrained Local Models
https://github.com/auduno/clmtrackr
<a href="https://github.com/auduno/clmtrackr"><img src="https://github-link-card.s3.ap-northeast-1.amazonaws.com/auduno/clmtrackr.png" width="460px"></a>

JavaScript だけでブラウザ上で顔検出ができる。誰の顔かを特定することはできませんが、顔の向きや表情などが検出できます。
Web 会議ツールなどで見かけるようになったリアルタイムに猫耳を生やしたりするのに使えます。3D アバターと組み合わせて VR 的に利用されている方もいるようです。

どのように使用するかは GitHub のリポジトリの REAMDME が詳しいのでそちらをご確認ください。

## 顛末
このたび、JavaScript で顔検出ができるライブラリ「clmtrackr」を使っていたのですが、プロトタイプやサンプルコードではうまく顔検出するのに、個人開発作品に組み込んだとたん顔検出をしなくなりました。
原因究明のために徹夜することになったので、二の轍を踏まないように記事にしておきます。

## 応用
video タグのサイズが決まっていればよいので、大きな画面に映したいときは video タグのサイズを小さくしておいて、video タグの内容を描画する canvas に書き込む際に拡大して書き込み、video タグの映像は`displey: none`などにするのもよいかもしれません。（未確認）

## 要調査
minify 版（`clmtrackr.mini.js`）だと動作しないことがある?

## 参考サイト
表情認識で SNOW 的なアプリ - こくぶん研究室
https://kkblab.com/make/javascript/face.html
PHPコンテナからDBコンテナにmysqlコマンドを通す方法

# はじめに
PHPコンテナ内（のバッチ処理ロジックの中）でmysqlコマンドを使いたいと思ったのですが、いろいろつまずいたので調べたことを備忘録として残したいと思います。
他にも困った人がいた時に役立てば幸いです。


# 対象者
- Docker使用者
- PHPコンテナとDBコンテナが分かれている
- PHPコンテナ内でMySQLコマンドを直接使いたい（exec()関数の使用）

私の場合は、Laravelを普段使っていて、下記のucan様の記事をベースに自分用にカスタマイズしたものを使っています。

https://qiita.com/ucan-lab/items/5fc1281cd8076c8ac9f4

# 動作確認環境
- MySQL 8.0（mysql/mysql-server:8.0）
- PHP 8.0（php:8.0-fpm-buster）

# つまずきポイント
## コマンドがない
```bash
mysql -u {user_name} -h {コンテナ名} -p
```
↓

```bash
bash: mysql: command not found
```

PHPコンテナにはmysqlのコマンドがありませんでした。
なかったのでインストールします。

```bash
// 最新化
apt update

// インストールできる内容を表示
apt search mysql-client

// コマンドのインストール
apt install -y default-mysql-client-core
```

これでインストールできたはずなので、もう一度叩いてみます

```bash
mysql -u {user_name} -h {コンテナ名} -p
```
↓

```bash
Plugin caching_sha2_password could not be loaded: /usr/lib/x86_64-linux-gnu/mariadb19/plugin/caching_sha2_password.so: cannot open shared object file: No such file or directory
```

mysqlのコマンドは通ったようです。しかし認証まわりのエラーが発生しました。


## 認証エラー
調べた結果、上のエラーはMySQL8から導入された認証まわりの設定が原因であることが分かりました。
MySQL5.7までの認証プラグインはmysql_native_passwordというものが使われていたのが、8.0からはcaching_sha2_passwordというものに変わったようです。
しかしながらmysqlクライアント側が新しい認証にはまだ対応できていないため、認証を従来の形式に戻したいと思います。

DBコンテナに入り、以下のコマンドを実行することで該当ユーザーの認証を変更することができます。
なお、権限変更はrootユーザーなど、権限の強いユーザーで実行する必要があります。

```bash
// 現在の状況確認
SELECT User, Host, Plugin FROM mysql.user;

// 権限変更
ALTER USER {user_name} IDENTIFIED WITH mysql_native_password BY '{password}';

// 権限が変更されたことを確認
SELECT User, Host, Plugin FROM mysql.user;
```

## もう一度確認
権限が変更されたので、もう一度PHPコンテナに戻りmysqlコマンドを実行し通るか確認します。

```bash
mysql -u {user_name} -h {コンテナ名} -p
```
↓

```bash
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MySQL connection id is 36
Server version: 8.0.25 MySQL Community Server - GPL

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
```

無事にPHPコンテナからDBコンテナにmysqlコマンドが通りました！


# 補足
MySQL8ではcaching_sha2_passwordが推奨されていますので、mysqlクライアント側が8系に対応した場合にはもとに戻すようにしましょう。


# 調べた時に参考にした記事一覧
https://qiita.com/henrich/items/1b7ee2f3a72f8bb29cba

https://qiita.com/yensaki/items/9e453b7320ca2d0461c7

https://blog.s-style.co.jp/2018/05/1807/

https://qiita.com/tomo-IR/items/224d33f14561e759dd16

https://www.dbonline.jp/mysql/user/index9.html#section3
Jupyter notebook 実行中にPythonライブラリのバージョンを確認する

覚書です。
確認できたものを記載しておきます。

### 環境
OS: windows 10.0
python: 3.7.3
Anaconda: conda 4.10.1

### 実施日
2021/06/18

### コード
```
import sys
print("Python version:{}".format(sys.version))

import IPython
print("IPython version:{}".format(IPython.__version__))

import numpy as np
print("Numpy version:{}".format(np.__version__))

import scipy as sp
print("scipy version:{}".format(sp.__version__))

import pandas as pd
print("pandas version:{}".format(pd.__version__))

import matplotlib
print("matplotlib version:{}".format(matplotlib.__version__))

import seaborn as sns
print("seaborn version:{}".format(sns.__version__))

import sklearn
print("scikit-learn version:{}".format(sklearn.__version__))

import mglearn
print("mglearn version:{}".format(mglearn.__version__))

import networkx as nx
print("networkx version:{}".format(nx.__version__))

import cv2
print("opencv-python version:{}".format(cv2.__version__))

import dlib
print("Dlib version:{}".format(dlib.__version__))
```

### 結果
```
Python version:3.7.3 (default, Mar 27 2019, 17:13:21) [MSC v.1915 64 bit (AMD64)]
IPython version:7.22.0
Numpy version:1.20.2
scipy version:1.6.2
pandas version:1.2.4
matplotlib version:3.3.4
seaborn version:0.11.1
scikit-learn version:0.24.2
mglearn version:0.1.9
networkx version:2.5
opencv-python version:4.5.2
Dlib version:19.22.0
```
Docker DNSで詰まった話

#DockerのDNSのせいでapt updateできない
ひとまずなぐり書きです

Dockerのコンテナで一度は詰まった方いたであろうDNS問題。 
今回使用した環境 

* Nvidia Jetson nano
* JetPack
* Ubuntu 18.04
* Docker

こんなところです。 
いつもどおりdocker fileからbuildしようとすると。

```
# apt-get
Err:1 http://security.ubuntu.com/ubuntu bionic-security InRelease Temporary failure resolving 'security.ubuntu.com'
Err:2 http://archive.ubuntu.com/ubuntu bionic InRelease Temporary failure resolving 'archive.ubuntu.com'
Err:3 http://archive.ubuntu.com/ubuntu bionic-updates InRelease Temporary failure resolving 'archive.ubuntu.com'
Err:4 http://archive.ubuntu.com/ubuntu bionic-backports InRelease Temporary failure resolving 'archive.ubuntu.com'
```

直訳すると
erroネットつながってねーよバカアホカス目ついとんか
と怒られる。。。
調べるとDNSが問題みたい
Dockerfile上で

```
RUN echo 'nameserver 8.8.8.8' >> /etc/resolv.conf
```
でも良いがなんとなくブサイク
なので以下の方法で解決したよ
まずvimやらnanoやらで`/etc/systemd/system/multi-user.target.wants/docker.service`を開きます
そんでもって下の感じで`--dns`のオプションを追加して対応できたぞ

```
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --dns 8.8.8.8
```
twintを使ってTwitterからスクレイピング

twintを使ってTwitterからスクレイピングの例です。
twintとのページ
https://github.com/twintproject/twint

```
pip3 install --user --upgrade git+https://github.com/twintproject/twint.git@origin/master#egg=twint
```

```twitter.py
import twint

# Configure
c = twint.Config()

c.Search = ["野鳥"]
#c.Username = ""
#c.Get_replies = False
c.Since = "2020-05-01"
c.Until = "2021-05-19"
c.Store_csv = True
c.Output = "none.csv"
# Run
#c.Debug = True
#c.Retweets=False
#c.Hide_output = True
twint.run.Search(c)
```
youtubeから出力したsrtファイルを結合

srtフォルダにsrtファイルを置いてください。

この記事でsrtファイルが作れます。
https://qiita.com/saber72237/items/a62f2c035a8df820f987

srtフォルダに置いたsrtファイルが結合されて一つのテキストファイルで出力されます。

```srt.py
from bs4 import BeautifulSoup
import urllib.request
import re
from time import sleep
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.keys import Keys
import csv
import time
import datetime
import pandas as pd
from selenium.webdriver.common.action_chains import ActionChains
import glob

now = datetime.datetime.now()
filename = now.strftime('%Y%m%d_%H%M%S') + '.txt'
fa = open(filename,'a', encoding='cp932',errors='ignore')

for file in glob.glob('srt/*.srt'):
    with open(file, mode='rt', encoding='utf-8')  as f:
        for line in f:
            
            list=re.sub('\d{2}:\d{2}:\d{2}.+', '', line)
            list=re.sub('^\d+$', '', list)
            print(list.strip())
            fa.write(list.strip())

f.close()
```
youtubeのURLから字幕を生成

youtubeのURLから字幕を生成

https://qiita.com/saber72237/items/9528f5979b845a94f730
で取得したテキストファイル名をpathに入れる
path = '？？？？'
字幕ファイルは、クロームのダウンロードフォルダに保存される。

```jimaku.py
from bs4 import BeautifulSoup
import urllib.request
import re
from time import sleep
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.keys import Keys
import csv
import time
import datetime
import pandas as pd
from selenium.webdriver.common.action_chains import ActionChains

path = '？？？？'

#urlリストを定義
data = pd.read_table(path, encoding="utf-8")
urls = data["url"]

#クロームをヘッドレスモードにする
options = Options()
#options.add_argument('--headless')


#クロームドライバーの指定とオプション
driver = webdriver.Chrome(executable_path="C:\code\python\chromedriver.exe", chrome_options=options)
# ログインページを開く
driver.get("https://downsub.com/")

now = datetime.datetime.now()
filename = now.strftime('%Y%m%d_%H%M%S') + '.txt'
f = open(filename,'a', encoding='cp932',errors='ignore')

for url in urls:
#フォーム入力
    sleep(1)
    driver.switch_to.window(driver.window_handles[0])
    link=url
    sleep(1)
    driver.find_element_by_name("url").send_keys(Keys.CONTROL + "a")
    driver.find_element_by_name("url").send_keys(Keys.DELETE)
    driver.find_element_by_name("url").send_keys(url)
    sleep(1)
#ダウンロードクリック
    driver.find_element_by_xpath("//div[@class='v-input__append-outer']").click()
    sleep(1)
    try:
        driver.find_element_by_xpath("//button[@class='ma-1 download-button v-btn v-btn--depressed v-btn--flat v-btn--outlined theme--light v-size--default primary--text']").click()
    except:
        f.write(driver.current_url)
        f.write("\n")
    sleep(1)

f.close()
```
youtubeのチャンネルから全URLを取得

youtubeのチャンネルから全URLを取得
チャンネル名を入れるとURLを取得
c_name = "チャンネル名"

セレニウムで最下層までスクロールさせるのがポイント

```youtube.py
import os
from time import sleep
import pandas as pd
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys


c_name = "？？？？"

class YoutubeChannelVideoScraper(object):

    def __init__(self, user_name, csv_file_name):
        self.youtube_url = "https://www.youtube.com"
        self.user_name = user_name
        self.csv_file_name = csv_file_name
        self.csv_file_path = os.path.join(os.getcwd(), self.csv_file_name+'.csv')
        self.channel_videos_url = os.path.join(self.youtube_url, 'user', self.user_name, 'videos')
        self.titles = []
        self.video_urls = []

    def run(self):
        #ソースの取得
        self.get_page_source()
        #動画とURLの抽出
        self.parse_video_title_and_url()
        #データの保存
        self.save_as_csv_file()

    def get_page_source(self):
        '''
        YoutubeChannelページの
        最下部までスクロールしたページソースを取得
        '''
        # ブラウザ操作の準備
        self.driver = webdriver.Chrome()
        self.driver.get(self.channel_videos_url)
        self.current_html = self.driver.page_source

        # 動画一覧要素へ移動
        element = self.driver.find_element_by_xpath('//*[@class="style-scope ytd-page-manager"]')
        actions = ActionChains(self.driver)
        actions.move_to_element(element)
        actions.perform()
        actions.reset_actions()

        # 最下部までスクロールしたソースを取得
        while True:
            for j in range(100):
                actions.send_keys(Keys.PAGE_DOWN)
            actions.perform()
            sleep(3)
            html = self.driver.page_source
            if self.current_html != html:
                self.current_html=html
            else:
                break

    def parse_video_title_and_url(self):
        '''
        タイトルと動画URLを抽出
        '''
        soup = BeautifulSoup(self.current_html, 'html.parser')
        for i in soup.find_all("a"):
            title = (i.get("title"))
            url = (i.get("href"))
            if title is None:
                continue
            elif url is None:
                continue
            if "/watch?v=" in url:
                self.titles.append(title)
                url="https://www.youtube.com"+url
                self.video_urls.append(url)

    def save_as_csv_file(self):
        '''
        CSVファイルとして保存
        '''
        data = {
#         "title": self.titles,
         "url": self.video_urls
        }
        pd.DataFrame(data).to_csv(self.csv_file_path,index=False)


if __name__ == "__main__":
    scraper = YoutubeChannelVideoScraper(user_name=c_name, csv_file_name=c_name)
    scraper.run()
```
【AndroidStudio】Incorrect credentials insufficient scopes granted to token. を解決した 【GitHub】

##発生した事象
AndroidStudio（v 4.1.2）にて、GitHubとの連携中に発生したエラー。

##試したこと

###①ユーザー/パスワードでログインを試みる
結果：エラーが発生する
>Invalid authentication data. 404 not Found - Not Found

![20210618-015319.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463548/109f378b-d7cc-8245-e623-efcaee1b4ba7.png)

###②トークンでのログインを試みる
結果：エラーが発生する
>Incorrect credentials insufficient scopes granted to token

![ダウンロード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463548/ef1f97c1-3df5-472c-0482-9a424e259eb5.png)

[トークンの作成方法はこちら](https://docs.github.com/ja/github/authenticating-to-github/keeping-your-account-and-data-secure/creating-a-personal-access-token "個人アクセストークンを使用する - GitHub Docs")

##解決に至るまで

今回は、**トークン** でログインしてみます。

### ①トークンの設定の見直す
ログインできない理由のひとつとして、**トークンの設定が間違っている** 可能性があるようです。

↓下記画像の通りに設定しました

![20210618-015825.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463548/a3d5c0e5-8d01-efc3-dff3-e4018547fc07.png)

### ②serverを"https\://github.com/"に変更する

serverのデフォルト設定は"github.com"なのですが、そのままだとうまくいかないことがあるようです。
なので念のため、"https\://github.com"で設定しました。

![ダウンロード (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463548/f6a8dbc5-3e46-083e-d663-f7acb4bf6612.png)

### ③ログイン成功

なんとかログイン成功することができました。


![20210618-023059.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463548/1c1ea8dc-6532-094d-cc5e-cac70916e8bf.png)
M1 Macのターミナルでtmux + neovim + R (aarch64ネイティブ)を使うまで

tmux + neovimでターミナルからRを使いたいのですが、arm版のものを一式インストールするのが色々面倒でした。ということで、メモを書きます。すべての作業はarm64で動くターミナルでarm64のシェルから行います。

```
> uname -m
arm64
```

# Alacritty（ターミナル）

ソースからコンパイルしないとarm64ではなくx86_64で動いてしまいます（2021/06/15）。

https://github.com/alacritty/alacritty/blob/master/INSTALL.md


を参照にコンパイル。

# brew

https://brew.sh
を参照にインストール。
`/opt/homebrew/bin/`以下にインストールされていることを確認。arm64だと、このディレクトリにインストールされるようです。

```
> which brew
/opt/homebrew/bin/brew
```  
  

色々必要なものをインストール。

```
brew install tmux
brew install pandoc
```
   

など。
pythonはインストールしないほうが良いかもしれないです。今のとこ、https://github.com/randy3k/radian/issues/249 のようなold style callback関連のエラーがガンガンでます。

# Neovim

前述のようなエラーがでるので、pythonはシステムのものを使うと一応明示しておきます。

```
brew install neovim
/usr/bin/python3 -m pip install pynvim
```

エラーが起きないように、neovimで使うpythonのパスをneovimのconfigファイル（$HOME/config/nvim/init.vimなど）に指定。

```
let g:python3_host_prog="/usr/bin/python3"
```

# R

brewでインストール。

```{zsh}
brew install r
```

`~/.R/Makevars`にはc/c++コンパイラがarm64で動くように以下のようなことを書いておきます。これをしないとインストールできないパッケージが大量発生します。

```
CXX14FLAGS +=-O3 -mtune=native -arch arm64 -Wno-unused-variable -Wno-unused-function
CC=clang -arch arm64
CXX=clang++ -arch arm64 -ftemplate-depth-256
```

CXX14FLAGSのとこに-arch arm64が必要かどうかは、よくわかっていません。

# radian（Rのコンソール）
https://github.com/randy3k/radian


これもシステムのpythonを使ってインストール。

```
/usr/bin/python3 -m pip install radian
```
Symfony4でプロジェクトを立ち上げる

### 事前にやること

compsoerをインストールする
https://weblabo.oscasierra.net/php-composer-windows-install/


### コマンド実行

バージョンを指定してプロジェクトを作成する

```bash
$ composer create-project symfony/website-skeleton project_practice  4.4.*
```

プロジェクトを立ち上げる

```bash
$  php bin/console server:run
```

以下のようなエラーが出てくる場合の対象方法

```bash
$ php bin/console server:run

  Command "server:run" is not defined.

  Did you mean one of these?
      dbal:run-sql
      server:dump
      server:log

$ composer req server

```

以下のURLからアクセスを確認
http://127.0.0.1:8000
[CSS] 要素をきっかり3分割するCSSの書き方

CSSで要素を３分割する方法です。

例えば以下のように画像が3つの状態があるとします。

```
<div class="img-container">
 <img src="hoge1">
 <img src="hoge2">
 <img src="hoge3">
</div>
```

```
.img-container {
  display: flex;
}
.img-container img {
  width : 33.33333% ; 
}
```

また計算式を使える`calc`を使えばきっかり3分割に等分指定できます

```
.img-container {
  display: flex;
}
.img-container img {
  width: calc(100% / 3);
}

```
Androidでのアニメーション

# アニメーションチュートリアルで出来るサンプルアニメーション

https://developer.android.com/training/animation

## ドローアブル グラフィックをアニメーションにする

その１

## アニメーションを使用してビューの表示 / 非表示を切り替える

![2-1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/182351/9ab0e246-74dc-a84f-2668-27468b32944b.gif)

![2-2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/182351/6b6b06b6-79db-f2b5-2f21-4eb8f0fb905b.gif)

![2-3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/182351/518442fe-5962-d543-dfb0-2802578cf9aa.gif)

## アニメーションを使用してビューを移動する

![3-1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/182351/8489f925-d108-f3e1-e2e3-73f3ae12fbe8.gif)

## フリング アニメーションを使用してビューを移動する

![4-1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/182351/5a3a13ef-b66b-8360-8e1f-d7152107b509.gif)

## ズーム アニメーションを使用してビューを拡大する

![5-1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/182351/672e05ed-3842-e9af-1f49-cc1f30598a07.gif)

## ばねの物理的性質を利用して動きをアニメーションにする

![6-1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/182351/96763dd2-f0a6-bfe7-88e0-b4bfb2269ac2.gif)

## レイアウトの更新を自動でアニメーションにする

![7-1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/182351/d0082e02-5134-c35c-aa3d-f9a2c322d477.gif)

## 遷移を使用してレイアウト変更をアニメーションにする

![8-1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/182351/874d3e99-3fd7-5a9a-39e7-0635a9006d88.gif)
【PHP】トレイトを使用したサンプルソース

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954863/a566f7f9-e9cf-d17f-555d-0ee85cc1976b.png)


# トレイトとは、
##メソッドの実装をまとめたもの。

単体ではインスタンスを作成できず、いずれかのクラスにuseさせて利用する

# メインのファイル
## public/object_sample/trait_sample.php

```php
<?php
// 各クラスの読み込み
require_once 'classes/BattleRobot.php';
require_once 'classes/Cat.php';
 
$ann = new BattleRobot(100, 'アン');
$ann->introduce();
$ann->walk();
 
$taro = new Cat('太郎', 3);
$taro->introduce();
$taro->walk();
```

# 継承先のクラス
BattleRobotクラスはすでにRobotクラスを継承しているため、これ以上の継承はできない）
## public/object_sample/classes/BattleRobot.php
```php
<?php
require_once 'Robot.php';
// 継承するために最初に WalkingTrait の定義を読み込んでおく
require_once 'WalkingTrait.php';
 
class BattleRobot extends Robot {
  use WalkingTrait;
 
  // introduceメソッドをオーバーライド
  public function introduce(){
    // 最初に継承元（親）クラスのintroduceメソッドを呼び出しておく。
    parent::introduce();
    echo $this->name . 'は戦闘型ロボットだよ！<br>';
    echo '<br>';
  }
}
```

# 継承先のクラス
## public/object_sample/classes/Cat.php
```php
<?php
// 継承するために最初に WalkingTrait の定義を読み込んでおく
require_once 'WalkingTrait.php';
 
class Cat {
  use WalkingTrait;
 
  private $name;
  private $age;
 
  public function __construct($name, $age){
    $this->name = $name;
    $this->age = $age;
  }
 
  public function shout(){
    echo 'にゃー!<br>';
  }
 
  public function introduce(){
    echo '名前は' . $this->name . '、' . $this->age . '歳です';
    $this->shout();
  }
 
}
```


# 共通トレイト
## public/object_sample/classes/WalkingTrait.php
```php
<?php
trait WalkingTrait {
  public function walk(){
    echo 'テクテクテクテク...<br>';
  }
}
```
IaaS,PaaS,SaaS とは？

## 勉強前イメージ

クラウドサービスで、
OSまで面倒見てくれるのか、そもそも仮想サーバたてるところから自分でやるのかとかだったと思う。
SaaSはよくわかってない

## 調査

### IaaS,PaaS,SaaS とは

AWSやGCP,Azureなど様々なクラウドサービスがあります。
その中でクラウドサービス側がどのレイヤーまで提供してるのかによって違いがあり、
それがIaaS,PaaS,SaaSになります。

### IaaS

Infrastructure as a Service の略で、イアースと呼びます。
クラウドサービス側が仮想マシンを提供するサービス形態になります。
提供される仮想マシンはLinuxやwindowsなどクラウドサービス側によって変わります。
ユーザ側は仮想マシン上のミドルウェアやデータの管理が責任範疇としてあり、
クラウドサービス側は、OSやハードウェアの管理が責任範疇としてあります。
ハードウェアの管理をしなくてよいのがメリットになります。
AWSのサービスでは代表的なものとしてEC2になります。

![1# IaaS,PaaS,SaaS とは？ - diagrams.net - Google Chrom.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129517/92232a34-c963-a258-d40a-24868edb78c2.png)


### PaaS

Platform as a Service の略で、パースと呼びます。
クラウドサービス側がソフトウェアの実行環境を提供するサービス形態になります。
どのようなソフトウェアが提供されるかはクラウドサービス側のサービス形態によって変わります。
ユーザ側は、ソフトウェアの設定やデータの管理に責任があり、
クラウドサービス側は、OSやハードウェア、ソフトウェアについて責任があります。
OSを自らインストールしたり、ソフトウェアを入れたりする手間が省けます。
AWSのサービスでは、Lambdaがこちらに該当します。

![2# IaaS,PaaS,SaaS とは？ - diagrams.net - Google Chrom.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129517/eaa83d54-3d2c-e085-3e78-4b3cff762884.png)


### SaaS

Software as a Service の略で、サーズと呼びます。
クラウドサービス側がアプリケーションを提供するサービス形態になります。
ユーザ側は、ソフトウェアの設定について責任があり、
クラウドサービス側が、OSやハードウェア、ソフトウェアやアプリケーションについての責任があります。
ミドルウェアの管理や、アプリケーションの追従をしなくてよいのがメリットになります。
Gmailとかがこちらになります。


![3# IaaS,PaaS,SaaS とは？ - diagrams.net - Google Chrom.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129517/28185a3c-4257-ed25-eb93-71ba8aceee4a.png)


### まとめ

IaaS,PaaS,SaaS、それぞれありますが、基本的には以下のようになります。
クラウドサービスの提供側の責任範疇が狭い = 利用者の責任範疇が広い = 設定できる範囲が広く、カスタマイズ性が高い
クラウドサービスの提供側の責任範疇が広い = 利用者の責任範疇が狭い = 設定できる範囲が狭いので、カスタマイズ性が低い
目的に合わせてどの形態があっているかは見ないといけないです。

## 勉強後イメージ

Azure調べてた時に出てきた。
聞いたことはあったけど厳密にはわかってなかった。
ただAWSの責任範疇のかたにあてはまるなーっておもった。

## 参考

- [マネージドクラウドとは何か？](https://business.ntt-east.co.jp/content/cloudsolution/column-108.html#section-04-03)
- [クラウド入門！IaaS、PaaS、SaaSの違い](https://business.ntt-east.co.jp/content/cloudsolution/column-78.html)
- [図解でわかる！SaaS、PaaS、IaaSの違いとクラウドサービスとの関係性について](https://www.topgate.co.jp/saas-paas-iaas)