OmniAICreator/Qiita-1.07M huggingface dataset:
Delta Live Tables(DLT)でロジックをpyファイルにモジュール化して共通化する

宣言型ETLを活用して信頼性が高く、運用が容易なデータパイプラインを構築できる[Delta Live Tables(DLT)](https://qiita.com/taka_yayoi/items/7fe8ed2c2f95fd53cc3d)ですが、実際の運用で活用しようとすると色々な悩みに直面するかと思います。

例えば、複雑な処理を必要とするデータパイプラインを構築したい、データソースへのアクセスロジックを共通化したいというケースでは、ソースコードのモジュール化が重要となります。

しかしながら、DLTでソースコードのモジュール化をするには若干工夫が必要となります。

現時点では以下のアプローチがあります。

1. **[Repos](https://qiita.com/taka_yayoi/items/b89f199ff0d3a4c16140)**の**[Files in Repos](https://qiita.com/taka_yayoi/items/b89f199ff0d3a4c16140#pythonr%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%88)**機能を用いて、pyファイルをimportする。
2. DLTパイプラインを定義するノートブックを[複数に分割](https://qiita.com/taka_yayoi/items/834b56b30849d63b52d0#%E3%83%91%E3%82%A4%E3%83%97%E3%83%A9%E3%82%A4%E3%83%B3%E3%81%AE%E8%A4%87%E6%95%B0%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%88%E3%83%96%E3%83%83%E3%82%AF%E3%81%AE%E8%A8%AD%E5%AE%9A)する。
3. Sparkの[UDF(ユーザー定義関数)](https://qiita.com/taka_yayoi/items/123347aa8323b4a90730)としてロジックを定義する。

1の方法は以下の記事でも説明されていますが、本記事ではDLTの文脈での利用方法を説明します。

https://qiita.com/maroon-db/items/7b06db3af52796033a06

# 準備

Admin ConsoleでRepos配下の**Files in Repos**を[有効化](https://qiita.com/taka_yayoi/items/b89f199ff0d3a4c16140#files-in-repos%E3%81%AE%E6%9C%89%E5%8A%B9%E5%8C%96)します。
![Screen Shot 2022-02-09 at 10.26.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/b6db0905-bbd0-f515-db9e-4757762f8155.png)

Databricksのサイドバーから**Repos**にアクセスして、[リポジトリを作成](https://qiita.com/taka_yayoi/items/b89f199ff0d3a4c16140#%E3%83%AA%E3%83%A2%E3%83%BC%E3%83%88git%E3%83%AA%E3%83%9D%E3%82%B8%E3%83%88%E3%83%AA%E3%81%AE%E3%82%AF%E3%83%AD%E3%83%BC%E3%83%B3)しておきます。

# ロジックの定義

1. Databricksのサイドバーから**Repos**にアクセスします。
1. 上で作成したリポジトリにアクセスします。ここでは`project-test`というリポジトリとします。
1. ロジックを記述するpyファイルを[作成](https://qiita.com/taka_yayoi/items/b89f199ff0d3a4c16140#%E6%96%B0%E8%A6%8F%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E4%BD%9C%E6%88%90)します。
1. 作成したいフォルダの右にある下向き矢印をクリックし、メニューから**Create > File**を選択します。
1. ここではファイル名を`func.py`とします。
1. シンプルなロジックを記述しています。

    ```py:Python
def test():
  print("test")
    ```
![Screen Shot 2022-02-09 at 10.39.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/cb69fa64-33ef-559e-1e0c-2475c09ac5df.png)

# DLTパイプラインの定義

1. DLTパイプラインを定義するノートブックを作成しオープンします。
1. Reposへのパスを追加します。

    ```py:Python
import sys
sys.path.append("/Workspace/Repos/takaaki.yayoi@databricks.com/project-test")
    ```

    カスタムモジュールをimportします。

    ```py:Python
import func
    ```

1. パイプラインのロジックから`.py`ファイルの関数を呼び出します。

```py:Python
json_path = "/databricks-datasets/wikipedia-datasets/data-001/clickstream/raw-uncompressed-json/2015_2_clickstream.json"

@dlt.table(
  comment="関数呼び出し元テーブル"
)

def caller():
  func.test()
  return (spark.read.json(json_path))
```

# Delta Live Tablesの動作確認

上記パイプラインのロジックを記述しているノートブックを実行して、動作を確認します。
![Screen Shot 2022-02-09 at 10.45.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/86e60e20-0335-5df9-7253-bffb19c2f50d.png)

### Databricks 無料トライアル

[Databricks 無料トライアル](https://databricks.com/jp/try-databricks)
2月8日のコースレビュー

6.コレクションのトラバーサル方法はどのような目的で使用されますか？
普通for：添え字の値によると、通常のコレクションの操作に問題はありません。
強化for：下にあるレイヤーはイテレーターです。 コードは少なくなりますが、コレクションを操作することはできません
イテレータ：コレクションをトラバースするための公式に提供されたメソッドであり、操作することはできません

8.通常のクラス、抽象クラス、インターフェースはどのような目的で使用されますか？
通常のクラス：定数と変数、通常のメソッド、静的メソッド、コンストラクターがあります
抽象クラス：定数と変数、通常のメソッド、静的メソッド、コンストラクター、抽象メソッドがあります
インターフェース：定数、抽象メソッドがあります

16.異常したを挙げてください
nullポインタ
範囲外の配列添え字
型変換異常
Moodleの"サイトアップロード上限"を変更する。



標準では2MBが最大なのだが、バックアップファイルのサイズは2MBを超えることもある。Moodleだけでは最大値は変更できないので、php-fpm側の設定を変更する。

# 環境

- Ubuntu 18.04
- Moodle 3.10
- php-fpm 7.2
- nginx 1.14.0 (Ubuntu)

# 設定

以下では、最大サイズを8MBに設定している。

```php:/etc/php/7.2/fpm/php.ini
post_max_size = 8M
upload_max_filesize = 8M
max_execution_time = 600
```

```:/etc/nginx/sites-enabled/default
   location ~ [^/]\.php(/|$) {
      client_max_body_size 8m;
   }
```

# 再起動

```
sudo systemctl restart php7.2-fpm
sudo systemctl restart nginx
```

# 結果

![size - コピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2059/57a82c97-4772-40ec-80d7-9db6928e09c8.png)
python3小技

## フォルダの作成
cv2.imwriteなど、フォルダが存在しないファイルを作成してくれない。
以下により、フォルダが無い場合だけ作成する。

```
import os 
os.makedirs( path, exist_ok=True)
```

## パイソンファイルの場所
pyファイルと同じフォルダに計算データを保存したい時。実行したターミナルの場所とpyファイルの場所が異なる時があるので、＿file＿で指定した方が確実。

```
import os

print('getcwd:      ', os.getcwd())
print('__file__:    ', __file__)

print('basename:    ', os.path.basename(__file__))
print('dirname:     ', os.path.dirname(__file__))
```

getcwd:       /home/user　実行したターミナルの現在位置
__file__:     /code/src_notebook_26_4category/save_path_test.py
basename:     save_path_test.py
dirname:      /code/src_notebook_26_4category
## ファイルのパス
image_fileの場所を知りたいとき
フルパス
os.path.split(image_file)[0]

直上のフォルダ名
os.path.basename(os.path.dirname(image_file))
CM6206にSPDIFを付けてみた

かなり前に秋葉原の外れの中古屋さんで500円で買った、USBオーディオモジュールを改造してみました。

モジュールは安いモジュールで良く使われるC-MediaのCM6206というチップを使っていました。

SPDIFの端子があるモジュールも販売されていますが、このモジュールには端子がなかったので付けてみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/14968abe-1667-65fd-6845-7657ae0c1fd2.png)

48pinがSPDIFのOUTでピンを半田ごてで温めて、カッターの刃でピンを跳ね上げました。

![IMG_20220209_101755.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/f7246c5d-f9cb-2c66-dc34-46007416a169.jpeg)

[トスリンクコネクタ](https://qiita.com/yamori813/items/4e6eaf0137ca7499148e)は廃棄したCSチューナから取り出したものです。おそらくシャープ製で1pinがGNDで2pinがVCCで3pinがSPDIFでした。5Vのタイプなのですが、CM6206の信号レベルはひょっとすると3.3Vかもしれませんが、ちゃんと使えています。

ONKYOのミニコンポにつないで[mpg123でWBGOを聞いて](https://qiita.com/yamori813/items/822ef2403813ffb1aa71)います。結構良い音だと思います。


電源を安定させるためにnichiconの100uFを付けてみました。

![IMG_20220210_132116.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/35f180cd-596d-ea8f-2abc-10ba24994acf.jpeg)

再生中はLEDが点滅するのですが、LEDは結構電流が流れるので外したほうが電源が安定して、音が良くなるかもしれません。

以前はデジタルで光にすれば音が良くなると勘違いしてましたが、終段のDACしだいだと思います。クロックをDAIとDAC側で別々に持つので、共通のクロックを使うI2Sと比べると、複雑になり音にも影響があると思う。ただSPDIFがいいのはコンピュータ側とオーディオ側で完全に電気的に切り離せるという事があります。コンピューターは電気的にはノイズ発生器のようなものでライン接続だとGNDが共通になり、ノイズがオーディオ側に伝播すると思われます。

このモジュールはなんらかセットで納品する案件で作られたのではないかと思われます。モジュールの下には磁石シートが貼ってあり、コンピュータに貼り付けて使っていたのかもしれません。おそらくあまり基板設計をした事がない人が作ったものではないでしょうか。マイクロのコネクタを標準に変換する右側の部分はわざわざ基板に乗せる意味はないと思います。あとコンデンサーを後付しましたが、電源系の安定のためのコンデンサーがありません。つねにUSBが安定している事を前提にした設計と見えます。案件がうまくいかず、流れてきたものかもしれません。

[設定プログラム](https://qiita.com/yamori813/items/b8952e293db86bc76c59)作ってみました。
【Unity】GameObjectを非アクティブにする処理で、同時に流すSEが鳴らない問題解決メモ

少し詰まったので備忘録として残しておきます。

ボタン押下時に、対象のGameObjectを非アクティブにする処理で、
ボタンのSEが鳴らない問題がありました。

原因としては、対象のGameObjectにAudioSourceが紐づいていたので、
非アクティブにすると音が鳴らなくなってしまうということでした。

##解決策

```C#
[SerializeField] AudioClip onButtonSE;
AudioSource audioSource;

void Start()
{
    audioSource = GetComponent<AudioSource>();
}
```

それ自体で音を鳴らすのではなく、別で用意したGameObjectにて音を鳴らすことで解決できました。


```C#
[SerializeField] AudioClip onButtonSE;
AudioSource audioSource;

void Start()
{
    audioSource = GameObject.Find("Speaker").GetComponent<AudioSource>();
}
ブラウザでリンクをクリック時にPDFを表示とダウンロードを同時にする


PDFファイルをタブで開くのとダウンロードするのと同時に実施したいという依頼があったので試してみます。

`<a>`要素タグに`downloadという属性を付与するとリンク先のドキュメントをダウンロードしてくれます。
[MDN アンカー要素 download属性](https://developer.mozilla.org/ja/docs/Web/HTML/Element/a#attr-download)

同時にこの要素をクリック時に`window.open`で新たなウィンドウ（タブ）を開きます。
DOMで要素を取得して`onclick`で動く関数を設定します。
[MDN Window.open()](https://developer.mozilla.org/ja/docs/Web/API/Window/open)

この2つがどう相互に作用するか実際に試したところ、問題なく動きました。
以下がサンプルコードです。

```html:HTML
<a href="document.pdf" download id="document-link">PDFはこちら</a>
```

```javascript:JavaScript
document.getElementById('document-link').onclick = () => {
  window.open('random.pdf', '_blank')
}
```

Vue3でやるなら以下の形です。

```vuejs:Vue
<template>
  <a href="random.pdf" download @click="openPage()">PDFはこちら</a>
</template>

<script>
export default {
  methods: {
    openPage() {
      window.open('random.pdf', '_blank')
    }
  }
}
</script>
```

利用ケースはそんなになさそうですが、ユーザーに確実に保存して欲しい時とかは良いかもですね。
send_keysが急にエラーになった

#今まで問題なく動いていたスクレイピングの処理がエラーになったので備忘録
スクレイピングプログラムが今まで問題なく動いていたのに、ある日突然send_keysでエラーになったので情報共有します。

エラーになったソースとメッセージはこれ。

```python:hoge.py
email = test_test@hoge.com
driver.find_element(By.ID, "ID").send_keys(email)
```

```python:mesasge
selenium.common.exceptions.WebDriverException: Message: unknown error: Cannot construct KeyEvent from non-typeable key
  (Session info: headless chrome=98.0.4758.80)
```

原因をしらべてみると、chromedriverの問題らしい。
chromedirverバージョン98には、send_keysでアンダースコア(_)を使っているとエラーになるバグが存在するようです。
↓詳細はこのサイトを見てください

https://github.com/SeleniumHQ/selenium/issues/10318



バージョンを戻して対応する方法もあるようだけど、私はchromeのバージョンアップを行なっているのでプログラム実行時にchromedriver_autoinstallerを使ってchromedriverも最新を使用しています。
そのため、send_keysの代わりにexecute_scriptの命令を使用してエラー回避

```python:hoge.py
email = test_test@hoge.com
driver.execute_script('document.getElementById( "ID").value="%s";' % email)
```

これで問題なく動くようになりました。

execute_scriptにすることによる問題点とか理解していないので、
詳しい方、コメント欄で教えてください。
rubyでの改行

rubyで、\nのようにして改行する方法は知っていたのですが、ほかにも改行するやり方があったので、それを紹介しようとおもいます。

##+を使った際の改行
```
p (2+
1)
=> 3

p (2\
+1)
=> 3

p(2
  .+1)
=> 3
```

##文字列とシンボル、そして数値を改行する

```
p "ho\
ge"
=> "hoge"

#\の直後にスペースが入っている
p "hoge\ 
ge"
=> "hoge \nge"

p :"ho\
ge"
=> "hoge"

p 10\
1
=>SyntaxError
```

##ピリオドによる改行

```
p 3.
  to_s
=> "3"

p 3
  .to_s
=> "3"
```
ピリオドの場合は、ピリオドが改行前にあるか、改行後にあるかは関係ないんですね。

##メソッドを使うときの改行

```
def hoge(a);
  p "hoge:#{a}"
end

hoge(1)
=> "hoge:1"

hoge(
    1)
=> "hoge:1"

hoge\
(1)
=> "hoge:1"

hoge\
1
=> "hoge:1"
```
##実際に問題を解いてみる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485775/112a60b7-258c-0e7c-cbc0-ca1f6da264fd.png)

###選択肢➀
ピリオドでメソッドを区切っているパターンです。上に書いたように、ピリオドは前に書いてもあとに書いてもオッケーなので、この選択肢は正解になります。
このコードはirbなどのコンソールから打つとエラーを吐きますが、ファイルに書いてやるとエラーは起きないです。

###選択肢➁
選択肢➀と同じ理由からこの選択肢も正解になります。

###選択肢➂
バックスラッシュで区切る問題です。上に似たようなものが書いてありますが、行の末尾にバックスラッシュをいれることで、1行のコードとみなされるんです。そのため、この選択肢も正解になります。

###選択肢➃
この問題はも正解となります。選択肢➀、➁が正解な理由と同じです。

まさかの全選択肢正解です笑イジワルですね笑
以上です。何か間違いがございましたら、ご教示いただけますと幸いです。

【参考資料】

https://qiita.com/Nabetani/items/66da23a83b65aba4dc20
AWS上にプロキシーサーバを構築してみた

#はじめに
AWS上にsquidを利用したプロキシーサーバを構築して、
プライベートサブネットからパブリックサブネットにあるプロキシを経由して、
インターネットにアクセスする。ということをやってみました。

#構成図
こんな感じのシンプルな構成図
![proxy.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/575134/d7bd072c-1eda-8f56-7cab-d30a0d601cf3.png)


#前提
・以下、プライベートサブネットのインスタンスをprivate、
パブリックサブネットのインスタンスをpublicと呼びます。
・privateとpublicの通信はセキュリティグループで許可しています。
・プライベートサブネットのルートテーブルは、「10.0.0.0/16 local」　のみ
パブリックサブネットのルートテーブルは「10.0.0.0/16 local」と
インターネットに出るため「0.0.0.0/0 igw-(インターネットゲートウェイ)」を記述
・publicにのみEIP(GIP)をつけています。

#作業前の確認
publicからはgoogleにアクセスできるけど、
privateからはアクセスできないことを確認

```
[ec2-user@public ~]$ curl -I https://www.google.com
HTTP/2 200
content-type: text/html; charset=ISO-8859-1
・・・
[ec2-user@public ~]$
```
publicからは200が出ているからアクセスできてる。

```
[ec2-user@private ~]$ curl -I https://www.google.com
curl: (28) Failed to connect to www.google.com port 443 after 131159 ms: Connection timed out
[ec2-user@private ~]$
```
privateからはそもそもインターネットに出れないのでタイムアウトする。

#squidの設定
```
[ec2-user@public ~]$ sudo yum install -y squid
```
squidをインストールする

```
[ec2-user@public ~]$ squid -v
Squid Cache: Version 3.5.20
Service Name: squid
・・・
```
インストールできたか確認。


/etc/squid/squid.conf 以下の内容で設定する。

```
#　接続元IPアドレス範囲
acl localnet src 10.0.0.0/16

# 接続先ポートの設定
acl SSL_ports port 443
acl Safe_ports port 80          # http
acl Safe_ports port 443         # https
acl CONNECT method CONNECT
http_access deny !Safe_ports
http_access deny CONNECT !Safe_ports

# ホワイトリストを使ったアクセス制限
acl whitelist dstdomain "/etc/squid/whitelist"

http_access deny !localnet
http_access allow whitelist
http_access deny all

# squidの使用ポート
http_port 8080

# キャッシュは用いない
no_cache deny all

# coredump出力先を設定
coredump_dir /var/spool/squid

# ホスト名を非表示
visible_hostname unknown

# 内部のIPアドレスの秘匿
forwarded_for off
```

ホワイトリスト形式にして、指定した先のURLのみに接続できるようにするため
/etc/squid/whitelist に .goole.comを追加して、内容を確認。
 
```
[ec2-user@public ~]$ cat /etc/squid/whitelist
.google.com
``` 

squidを起動させる。

```
[ec2-user@public ~]$ sudo systemctl start squid
```

#アクセスできるか確認
設定したpublicのプロキシ経由で
ホワイトリストに追加したgoogleにはアクセスできるけど、
youtubeにはアクセスできないことを確認。

```
[ec2-user@private ~]$ curl -I -x http://10.0.10.61:8080 https://www.google.com
HTTP/1.1 200 Connection established

HTTP/2 200
content-type: text/html; charset=ISO-8859-1
・・・
[ec2-user@private ~]$
```


```
[ec2-user@private ~]$ curl -I -x http://10.0.10.61:8080 https://www.youtube.com
HTTP/1.1 403 Forbidden
・・・
[ec2-user@private ~]$
```

せっかくなので環境変数にプロキシを設定

```
[ec2-user@private ~]$ export HTTPS_PROXY=http://10.0.10.61:8080
```

curlのときにプロキシを設定しなくてもアクセスできる。

```
[ec2-user@private ~]$ curl -I https://www.google.com
HTTP/1.1 200 Connection established

HTTP/2 200
content-type: text/html; charset=ISO-8859-1
・・・
[ec2-user@private ~]$
```

#まとめ
AWS環境だったらNatGateway使えばよくね？とはなりますが、
インターネットに出ていく先を制限したいことも多々あると思うので
こういったプロキシ設定もさくっとできるようになれれば良いなと思いました！

#引用
https://blog.serverworks.co.jp/squid
ネットワーク

自分用の学習メモです。

■プロトコルとは？

・通信のためのルール

・コンピュータは0か1の世界。どっちが何を意味するか決める必要がある

・OSI参照モデルの第1層から順に解釈していく


■MACアドレスとは？（OSI参照モデル第2層の話）

・どのパソコンとデータのやり取りをするか、識別するために誕生したのがMACアドレス

・MACアドレスは48bit、16進数で表す
例：12:34:56:78:9a:bc

・MACアドレスはPCを製造した段階で割り当てられる

・MACアドレスの前半24bitはベンダー、後半の24bitは機器ごとに割り当てる
よってMACアドレスを見れば製造元が判別できる


■IPアドレスとは？（OSI参照モデル第3層の話）

・IPアドレスは住所、MACアドレスは個人情報

・サブネットマスクはIPアドレスをどこで区切るか表すもの
区切られたIPアドレスの前半をネットワークアドレス、後半をホストアドレスと表現
「0」の前で区切られる

・同じネットワーク内のやりとりはARPというプロトコルが使われる

・ARPはIPアドレスとMACアドレスの紐づけをする


■ポート番号

・1つのPCに0~65535のポート番号が存在する

・PC内のプログラムを識別するための番号
pythonで親クラスの任意のメソッド実行前後に特定の処理を行う方法

# 背景.

例えば、「テーブルはレコードのリストであり、レコードは辞書(連想配列)である」(=テーブルとは辞書のリストである)という考え方に基づいて`Table`型を作るとしよう。
この考え方に基づいて早速

```python3
class Table(list):
    def __init__(self, columns):
        self.__columns = columns
    def to_excel(self): ...
    def to_pd_df(self): ...
    def to_numpy(self): ...
    
    @classmethod
    def from_excel(Table, excel_path): ...
    @classmethod
    def from_pd_df(Table, df): ...
    @classmethod
    def from_numpy(Table, arr2d): ...
```

と書いたとする。
後は`list`と同じように辞書を`append`, `clear`, `pop`等、リストに対するすべての操作が利用可能である。
(なのでリスト内法表記などを用いてテーブルを自由自在にフィルタ出来るというわけだ)

ところで、`append`, `+=` など、任意の操作をした際に、「中身がすべて辞書`d`であって、かつ`set(d.keys())`が`set(self.__columns)`と一致するか」の検査を行いたいとしよう。

この場合はどうしたらよいか。


# 解決.

```python3
class Table(list):
    def __getattribute__(self, method_name):
        if hasattr(list, method_name): # 親クラスで定義されたメソッドの場合
            def closure(*a, **ka):
                # 親メソッド呼び出し前の処理をここにかく
                rtn = object.__getattribute__(self, method_name) # 親メソッド呼び出し
                self.__raise_error_if_illegal_component_found() # 親メソッド呼び出し後の処理をここに書く
                return rtn
            return closure
        # 親クラスにないメソッドの場合
        return object.__getattribute__(self, method_name)

    def ...
```

`__getattr__`の場合は「存在しないメンバを参照されたときに動く」のに対し、
`__getattribute__`は「メンバの存在の有無にかかわらず直ちに呼び出される」強力なものとなっている。
そのため、`__getattribute__`内で`self.hoge`のように自オブジェクトのメンバを呼ぼうものなら、(再帰処理などを意図して書いた者でない限り)無限ループに陥ってしまう。
この無限ループを回避するために、`object.__getattribute__`を利用する。
「自クラスの`__getattribute__`とは別物だから循環参照にならない」というわけだ。
Terminalでエイリアスを作る

# Terminalのディレクトリ移動（cd)を楽にしたい
Gitのフォルダに移動したい時いちいち

```
cd ディレクトリパス
```
で移動するのが面倒でした。
windowsのショートカットみたいにすぐディレクトリ移動できる方法を探していたところ
Terminalでも設定できるとのことでした。


# .bashrcを編集する
エイリアスをすぐ作りたいと思いますが、その設定ファイル(.bashrc)はホームディレクトリに存在します。

```
cd $home
```
でホームに移動しましょう。

そこで

```
vi ~/.bashrc
```

を実行して.bashrcを編集します。
`「i」`キーで編集モードになります。

```
alias aliasname='cd mydirectory'
```
↑のように、`「alias エイリアス名='実行したいコマンド'」`を入力します。
編集が終わったら`esc`を押して編集モードから抜けて、
`:wq`で保存して終了してください。

#.bash_profileに読んでもらう

そのままではターミナル起動時に先ほどのエイリアスを読み込んでくれないので、
ターミナルの起動時に読み込まれる.bash_profileを編集しましょう。

```
vi ~/.bash_profile
```
書き込むのはこちら
先ほどと同じように`i`で編集、`esc`で編集を抜けてください。

```
source ~/.bashrc
```

これを`:wq`で保存してターミナルを再起動してください。

# 実行します
ターミナルを便利に使って勉強効率を上げましょう！

## 参考

https://qiita.com/YusukeHigaki/items/67a17995c8a4e1329d11

https://qiita.com/ryo2132/items/b7e312b0eb50fc449841

https://qiita.com/yutat93/items/b5bb9c0366f21bcbea62

https://qiita.com/hide/items/5bfe5b322872c61a6896
PythonでPDFのページを画像に保存する方法

# はじめに

個人の備忘録としてのメモです

# 方法

## PyMuPDF

```python
import fitz

with fitz.open("test.pdf") as doc:
    for i, page in enumerate(doc):
        image = page.get_pixmap()
        file_name = f"{i+1}.jpg"
        image.save(file_name)
```

## pikepdf + pdf2image

```python
from pdf2image import convert_from_path
from pikepdf import Pdf

with Pdf.open(source_path) as pdf:
    for i, page in enumerate(pdf.pages):
        page_size = page.MediaBox
        temp_pdf_file = f"temp_{i+1}.pdf"
        temp_pdf = Pdf.new()
        temp_pdf.pages.append(page)
        temp_pdf.save(temp_pdf_file)
        image_file_path = convert_from_path(
            temp_pdf_file,
            fmt="jpeg",
            paths_only=True,
            size=(page_size[2], page_size[3]), # デフォルトだと別のサイズになってしまうので、ここでページのサイズを指定している
        )
```

## PyPDF2 + pdf2image

基本的に、PDFを読み込むのを `PyPDF2` に変えただけ。

```python
from pdf2image import convert_from_path
from PyPDF2 import PdfFileReader, PdfFileWriter

with open(source_path, "rb") as file:
    pdf = PdfFileReader(file)
    page_count = pdf.getNumPages()
    for i in range(0, page_count):
        page = pdf.getPage(i)
        page_size = page.mediaBox
        temp_pdf_file = f"temp_{i+1}.pdf"
        temp_pdf = PdfFileWriter()
        temp_pdf.addPage(page)
        with open(temp_pdf_file, "wb") as new_file:
            temp_pdf.write(new_file)
        image_file_path = convert_from_path(
            temp_pdf_file,
            fmt="jpeg",
            paths_only=True,
            size=(page_size.upperRight[0], page_size.upperRight[1]),
        )
```

# おまけ

2022/02/08時点で、 `pikepdf` を AWS Lambda の Arm64 のインスタンスでインストールしようとすると、
`qpdf` 関連のエラーでインストールできないので、その場合は `PyPDF2` が良さそう。
それ以外（x86）では、 `pikepdf` が良さそう。（メイン処理が C++ で実装されているので、そちらが高速だと思われる）
NeurIPS2021の枝刈り論文 (2)

# 概要
この記事では、NeurIPS2021の枝刈り論文をまとめます。[^1]

[^1]: 画像や数式は論文から引用しています。

# CHIP: CHannel Independence-based Pruning for Compact Neural Networks

https://arxiv.org/abs/2110.13981

概要：CHIP. Filter pruningで、チャネル間の情報に基づいて刈るフィルタを選ぶ方法の1つ。
新規性：チャネル間の相関であるチャネルの独立性 (Channel Independence) によって刈るフィルタを選ぶ。
キモ：あるチャネルの独立性を、その特徴があるときとないときの行列ノルムの差で定義し、小さい方から刈る。Softな情報を持たせるために、行列ノルムはnuclear normを使う。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2448931/0af26855-da78-86e7-2a2f-d20a81acdcc4.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2448931/065d6d1c-9eb7-b760-554a-1b80248218d2.png)

評価：ResNet, VGG, CIFAR-100, ImageNetで実験した。


# Revisiting Discriminator in GAN Compression: A Generator-discriminator Cooperative Compression Scheme

https://arxiv.org/abs/2110.14439

概要：GCC. GAN向けモデル圧縮技術
研究機関：ByteDance
新規性：Discriminatorを圧縮に使う初めての方法。
キモ：Discriminatorに係数$\alpha_{ij}$をかけ、その$\alpha_{ij}$をSTEで最適化する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2448931/4268475a-9809-4f30-eb03-37d225e345c1.png)
$\alpha_{ij}$の値によって、そのフィルタを使うかどうかを決める。
蒸留で学習する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2448931/6b1ff189-d796-f821-28cb-d3505a82de50.png)
評価：SAGAN, CelebA等で実験した。CPUで4倍高速化。


# Chasing Sparsity in Vision Transformers: An End-to-End Exploration

https://arxiv.org/abs/2106.04533

概要：SViTE。ViTを刈りながら学習する。
研究機関：Microsoft
新規性：
(1) ViTを動的にスパース化しながら学習する方法を提案した。
(2) Structuredな枝刈りで(1)を行う方法を提案した。
キモ：ViTで刈りながら学習する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2448931/578c50f7-3b92-c7cf-5c45-ce206925808b.png)
刈る時はこの式の小さいHeadを選ぶ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2448931/3781961f-0d94-4b2f-d032-c3d4a08a67b1.png)
評価：ImageNetでDeiTと比較した。DeiT-Smallと比べると精度も速度も良かった。


# Channel Permutations for N:M Sparsity

https://proceedings.neurips.cc/paper/2021/hash/6e8404c3b93a9527c8db241a1846599a-Abstract.html

概要：Ampareアーキテクチャの[2:4 Sparsity](https://qiita.com/kyad/items/35b4fb8e550db32d6bd5)などで使われているチャンネルの並べ替えの解説
研究機関：NVIDIA
新規性：N:M Sparsityで(M個毎にN個取る)で情報を落とさないようにチャンネルを並び替える効率的なアルゴリズムを提案した。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2448931/e6b5c258-8210-c1e2-3536-85734f4be712.png)
キモ：アルゴリズムを、Greedyに良い順列を探して時々局所解から出るように作っている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2448931/1d15f375-8a93-d471-28e6-6bbee834c629.png)
評価：MobileNetやResNetに2:4 Sparsityを適用し、並び替えの有無による精度改善を確認した。


# Powerpropagation: A sparsity inducing weight reparameterisation

https://arxiv.org/abs/2110.00296

概要：PowerPropagation. Sparse Training (枝刈りではなく、学習中に枝刈りやスパース化する) の手法。
研究機関：Google
新規性：Sparse Trainingで、$L_0$正則化ベースの方法ではなく、勾配法で、大きな重みは解きたいタスクの特徴を学習し、小さい重みは解きたいタスクと無関係の特徴を学習するようにする。
キモ：
Powerprop. $\alpha - 1 (\alpha > 1)$乗の項によって、パラメータの値が大きいほど、勾配が大きくなるようにする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2448931/c5f60966-a742-2488-e48f-968b99a4faa6.png)
Catastrophic Forgettingを防ぐために、複数タスクで学習する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2448931/7abef898-6412-2f29-54c6-9a7240ba680e.png)
評価：ResNet, CIFAR, ImageNet等で実験した。
windowsでのraspipicoの開発環境の構築 その2

### windowsでのraspipicoの開発（続）

#### 汎用的なプロジェクト構成を構築

下記の記事で行った環境を使って、より汎用的なプロジェクト構成を構築する。

https://elehobby.hatenablog.jp/entry/2022/01/17/234156

pico-sdkをサブモジュールとして追加し、クローンする。

一つのプロジェクトで完結して構成するため、よりプロジェクト全体を理解しやすくなる。

git submoduleの説明は下記の記事を参考にした。
端的に言うと下記の通り。

> 外部の git リポジトリを、自分の git リポジトリのサブディレクトリとして登録し、特定の commit を参照する仕組みです。

https://qiita.com/sotarok/items/0d525e568a6088f6f6bb

また、ビルド結果は「out of source ビルド」の考えをもとにbinフォルダに生成する。

https://qiita.com/osamu0329/items/7de2b190df3cfb4ad0ca

生成ファルダとソースフォルダを分離することで、管理しやすくする。

下記がその作成したリポジトリとなる。

https://github.com/ikimon-dev/ledblink

このリポジトリには、サブモジュールが含まれているため、クローンするには、下記のコマンドを使用する。

```sh
git clone --recursive https://github.com/ikimon-dev/ledblink.git
```

もし、** --recursive **をつけ忘れてクローンした場合、下記のリンクを参考に`git submodule update --init --recursive`で
サブモジュールもクローン出来る。

https://karoten512.hatenablog.com/entry/2017/11/09/013845

クローンすると、下記の通りとなる。

```sh
~/src/repo/ledblink$ tree -L 3
.
├── CMakeLists.txt
├── src
│   └── ledblink
│       ├── CMakeLists.txt
│       └── main.c
└── third_party
    └── pico-sdk
        ├── CMakeLists.txt
        ├── CONTRIBUTING.md
        ├── LICENSE.TXT
        ├── README.md
        ├── cmake
        ├── docs
        ├── external
        ├── lib
        ├── pico_sdk_init.cmake
        ├── pico_sdk_version.cmake
        ├── src
        ├── test
        └── tools
```

ビルドを行うと、buildフォルダが作られ、`~/build/src/pico-display/pico_display.elf`が生成される。

https://qiita.com/4580TAT/items/313759d5a1e32a25944f

https://qiita.com/4580TAT/items/1a756a8f83b8000c119e
SWRとSSG,SSRではローディング機能はいらないのかもしれないという話

理解している人はこの事実が当たり前だと思うのでこの記事を読み飛ばしていただいて構いません。

## 【結論】SSG、SSRの時にはデータを既に取得してレンダリングが行われるためSWRのuseSWRを用いているファイルではローディングが行えない

### すごく盲点でした...

## [SWR](https://swr.vercel.app/ja)とは？

- **データ取得のための React Hooks ライブラリ**

### [公式のコード](https://swr.vercel.app/ja/docs/with-nextjs)を例に言語化してみる

**Page(親コンポーネント)**

親コンポーネントでSWRを用いたデータのフェッチを`getStaticProps`メソッドで行なっている。
子コンポーネントであるArticleに取得したデータを流している。

>```
export default function Page({ fallback }) {
  // `SWRConfig` の範囲内の SWR フックは、設定の値を使用します。
  return (
    <SWRConfig value={{ fallback }}>
      <Article />
    </SWRConfig>
  )
}

>export async function getStaticProps () {
  // `getStaticProps` はサーバー側で実行されます
  const article = await getArticleFromAPI()
  return {
    props: {
      fallback: {
        '/api/article': article
      }
    }
  }
}
```

**Article(子コンポーネント)**
親から取得したデータであるarticleをuseSWRを用いて取得しています。
親のコンポーネントから既にデータがある状態で受け取るためdataが存在しないということはなくなります。
そのため下記の`!data`による表示がされません。

>```
function Article() {
  // `data` は `fallback` を利用して常に利用可能です。
  const { data } = useSWR('/api/article')
  if(!data) return <div>loading...</div>  ←ここが役割を果たさない
  return <h1>{data.title}</h1>
}
```

今回の記事は以上になります。

他に手段を考えればloadingできるかもしれません。
そのため、何かご存知の方がいらっしゃいましたらご意見いただけると助かります。
Go言語におけるエラー型の生成方法 | erros.Newとfmt.Errorf

## Go言語のコードを書いている時に意図的にエラー型を生成したい時がある

例えば、os.Openやos.Createの関数などはerrorを返す関数になっています。このようなerrorが自然に発生する場合にはerrorを意図的に生成する必要がありません。

しかし、コードを書いていると、errorを意図的に生成したいタイミングがあります。

### エラーが自然に発生しないパターンの例

- string型の引数が空文字の場合、errorを返したい時

▼サンプルコード

```go
func exampleFunc(str string) error{
	if str == "" {
		panic("empty string") //本当はerrorを返したい！
	}
	return nil
}
```

- switch文のdefaultでpanicではなく、errorを返したい時

▼サンプルコード

```go
func exampleFunc(flag int) error{
	switch(flag) {
	case 1:
		fmt.Println("case 1")
	case 2:
		fmt.Println("case 2")
	case 3:
		fmt.Println("case 3")
	default:
		panic("invalid flag") //本当はエラーを返したい！
	}
	return nil
}
```

## そもそもerror型とは何か？

error型とはそもそもどんな型なのかをまずは整理します。

- error型はビルトインのインターフェース型の一つ。

▼定義

```go
type error interface {
    Error() string
}
```

- よく使われている「error」はerrorsパッケージにて実装されたerrorString構造体

```go
type errorString struct {
    s string
}

func (e *errorString) Error() string {
    return e.s
}
```

- インターフェースであるため、このインターフェースを実装する構造体を定義すれば、独自定義のエラーを実装することも可能。

▼サンプルコード

```go
// 構造体を定義
type MyError struct {
	message string
	code string
}

// Errorメソッドを実装。（Error型で決められたインターフェースを実装、満たす）
func (m MyError)Error() string {
	return m.code + " : " + m.message
}

// 実際に独自定義したMyErrorを呼び出してみる
func exampleFunc(str string) error{

	var err MyError

	if str == "" {
		err.code = "500"
		err.message = "internal server error"
		fmt.Println("check Error():", err.Error())
		return err
	}

	fmt.Println("str:", str)

	return nil
}
```

## エラー型を意図的に生成する方法

エラー変数を意図的に生成する主な方法は下記2つあるようです。それぞれメリットについてもまとめてみました。

### 方法１：errors.New()関数を利用する

- errors.New()は引数にエラーメッセージとなる文字列を受け取り、エラー型を返す
- エラーメッセージをカスタマイズしたい場合は、事前にエラーメッセージとなる文字列を作っておく必要がある

```go
package main

import (
	"errors"
	"fmt"
	"log"
)

func exampleFunc(str string) error{
	if str == "" {
		err := errors.New("エラーです")
		return err
	}
	return nil
}

func main(){
	emptyStr := ""
	err := exampleFunc(emptyStr)
	if err != nil {
		log.Fatal(err)　//出力例：2022/xx/xx xx:xx:xx エラーです
	}
	fmt.Println("success")
}
```

▼メリット

- 既にエラー出力したい文字列が用意されている時には便利
- シンプルなエラーを生成したい時に便利

### 方法２：fmt.Errorf()関数を利用する

- fmt.Errorf()はfmt.Sprintf()のようにフォーマットを指定したエラーメッセージを持つerror型を生成する。

```go
package main

import (
	"fmt"
	"log"
)

func exampleFunc(str string) error{
	if str == "" {
		err := fmt.Errorf("%s", "エラーです")
		return err
	}
	return nil
}

func main(){
	emptyStr := ""
	err := exampleFunc(emptyStr)
	if err != nil {
		log.Fatal(err) //出力例：2022/xx/xx xx:xx:xx エラーです
	}
	fmt.Println("success")
}
```

▼メリット

- やはりフォーマット指定でエラー文字列をカスタマイズできること。fmt.Sprintfと同じような感覚で利用できる。
- 記述量は少なくできるかも。

### 結論：errors.New()とfmt.Errorf()はどちらがいい？

正直、あまり変わらない印象なので、どちらでもご自身がしっくりくる方でいいと思います！

記述量を少なくしたい場合は、fmt.Errorf()の方が少なくなりそうです。

## 参考文献

[https://astaxie.gitbooks.io/build-web-application-with-golang/content/ja/11.1.html](https://astaxie.gitbooks.io/build-web-application-with-golang/content/ja/11.1.html)

[https://qiita.com/haazime/items/88ae8426a3e61b824b1d](https://qiita.com/haazime/items/88ae8426a3e61b824b1d)
模擬面接での反省：オブジェクト指向の基礎を説明できなかった

　今回の模擬面接の結果、自分は最近学んだ知識をちゃんと身につけられないと感じられました。先生からの質問は簡単でしたけど、すぐにはっきり答えられなくて、脳内で混乱しました。自分は上手くプログラミングできなくて、基礎的知識すらはっきり理解できていません。今回の模擬面接の中で一番印象的な質問は、普通クラス、抽象クラス、インタフェースの区別。面接後すぐに関連知識を調べました。以下はその区別内容です。

###　普通クラス、抽象クラス、インタフェースの区別

- 普通クラス：インスタンス化できます。
- 抽象クラス：インスタンス化できません。一部に未実装の規則（抽象メソッド）が存在する。
- インタフェース：規則のみ。インスタンス化できません。
2022/2/9主にITとかセキュリティの記事

政府、大会関係者に北京五輪公式アプリ利用で注意喚起 - 期間中の攻撃にも警戒を
https://www.security-next.com/133965

Fortinet製WAF「FortiWeb」に複数脆弱性 - アップデートで修正
https://www.security-next.com/133961

防災システムへの不正アクセス、スパム約31万件が送信される - 新潟県
https://www.security-next.com/133972

福井県ブランド課のTwitterアカウントが乗っ取り被害 - フォロー解除を
https://www.security-next.com/133974

【独自】国家機密の管理は国産クラウドで…技術開発を後押し、２３年度の運用目指す(2/7)
https://www.yomiuri.co.jp/economy/20220206-OYT1T50208/

ダークウェブで売買されている日本のクレジットカード情報の価格は平均4905.89円(2/6)
https://dime.jp/genre/1314978/

【独自】国家機密の管理は国産クラウドで…技術開発を後押し、２３年度の運用目指す(2/7)
https://www.yomiuri.co.jp/economy/20220206-OYT1T50208/

重要性が増すデジタル遺品への備え(2/7)
https://www.nli-research.co.jp/report/detail/id=70143?site=nli

ドコモ障害、1.8万人に影響　IPアドレス方式変更が原因(2/7)
https://www.nikkei.com/article/DGXZQOUC070W30X00C22A2000000/

犯罪者が違法送金にコンピューターゲームを利用(2/7)
https://jp.sputniknews.com/20220207/10113474.html

注意！ハッカーがメールアドレスを悪用してできる７つのこと/予防方法は？(2/7)
https://www.appps.jp/361913/

日本政府、北京五輪アプリを帰国後すぐに削除するよう選手に呼びかけ(2/6)
https://iphone-mania.jp/news-436573/

米国財務省：NFTはマネーロンダリングに使用できる(2/7)
https://nextmoney.jp/?p=48027

モネロ訴訟の敗訴後、日本の警察は暗号資産採掘についての警告を削除(2/7)
https://vc.morningstar.co.jp/010279.html

【2/7の話題】三井物産のジパングコインがWP公開、広瀬すず写真集未公開カットがNFTになど（音声ニュース）(2/7)
https://www.neweconomy.jp/posts/189159

米財務省、自己管理型ウォレットの規制案を再検討(2/7)
https://hedge.guide/news/fincen-re-examine-wallet-regulation-bc202202.html

ドコモ、1日朝の通信障害は「IPv6シングルスタック」導入の影響(2/7)
https://news.mynavi.jp/article/20220207-2266743/

金融庁＆日経新聞主催「FIN/SUM 2022」が3月29日～31日に開催、ピッチコンテストの参加企業も募集中
https://internet.watch.impress.co.jp/docs/news/1386117.html

IPAの「情報漏えい対策ツール」、Windows 11では使用不可(2/6)
https://news.mynavi.jp/techplus/article/20220206-2264774/

PowerPointファイルを悪用して実行可能ファイルを配布する攻撃手法とは(2/7)
https://news.mynavi.jp/techplus/article/20220207-2265095/

三菱UFJ信託、デジタル証券を即時決済　独自に電子通貨(2/7)
https://www.nikkei.com/article/DGXZQOGD26EAK0W2A120C2000000/

【本日の材料と銘柄】北朝鮮、サイバー攻撃で暗号資産盗む(2/7)
https://m.finance.yahoo.co.jp/news/detail/20220207-00935705-fisf-stocks

googlemeetの画面共有方法を解説! 注意点や共有できない場合の対処法まで(2/7)
https://news.mynavi.jp/article/20220207-2251614/

Xiaomi、IoTデバイスのセキュリティについて世界標準ガイドラインを策定(2/7)
https://pc.watch.impress.co.jp/docs/news/1386431.html

ドコモ、2月1日に発生した通信障害の原因を発表--約1万8000人に影響(2/7)
https://gunosy.com/articles/elXFJ

「NFT」ブームの行方は？「メタバース」は大衆化するのか？ 有識者が解説
「インターネット白書2022」発刊、副題は「デジタルツイン実現への道」(2/7)
https://internet.watch.impress.co.jp/docs/news/1386380.html

Emotet感染報告、国内企業から相次ぐ　ライオン、テスコムなど(2/7)
https://news.nicovideo.jp/watch/nw10499074

健康管理システム導入時に絶対チェックしたい情報セキュリティの3要素(2/7)
https://news.doctor-trust.co.jp/?p=50918

積水ハウスや和歌山県から届いたメールはなりすまし？国内でEmotet感染被害続く(2/8)
https://xtech.nikkei.com/atcl/nxt/column/18/00598/121500151/
スクレイピングの豆知識

内容的に読ませる気ないので読みづらい形式で書いてます。ごめんなさい。
当方、php-webdriver（Selenium）とGuzzle愛用者です。
Guzzleはxhtml非対応なので自前で変換処理が必要。（ヒント：DOCTYPE宣言を変更したりiconvで文字コード変換するなど。）

スクレイピング対策が強いサイトでは、プロキシを通していても同じタイミングでブロックされることがある。外部からの観測した結果の憶測にはなるが、IPアドレスとクライアント側の内部データ（Cookieやlocalstorage等）が紐付けされて、同一人物として検出されている様子だ。（ブラウザ操作をする場合だけのお話。Guzzle等では基本的には該当しない。）

AというIPアドレスと、
BというIPアドレスでアクセスした場合、内部データが残っていると AとBを Cookieやlocalstorage等のデータを元に芋づる式に紐付いてしまうようだ。とあるサイトではこの効果は強力で1つブロック対象になると、ほぼ同タイミングで一瞬にしてプロキシリストのほぼ全てが使い物にならなくなる。

完全な回避は難しいけれども、アクセスする前にブラウザの内部データを全て削除した上で実行すると結構長い間ブロックされずに使える。（経験則）

`すべてのウィンドウを閉じるときに cookie とサイトデータを削除する` というオプションが何気に便利な気がする。個人的には不安なので `chrome://settings/clearBrowserData?search=cookie` で全期間にしてデータを削除をJSからclick()して実行もしている。

低コストで大量スクレイピングのヒント（部分的にJS処理が必要でJS処理結果とCookieが紐付いているサイト等で使える）：
1. Seleniumで各IPアドレスのCookieデータを集めてDBに保存（一時的に複数マシンを立ち上げて実行。完了したらマシン捨てればOK）
2. DBに保存したCookieを用いてDockerコンテナで Guzzle を使ってスクレイピング。

VPSの1GBマシンでも15コンテナぐらい同時に動かせる。
月5,000円程度で150プロセスを同時に動かせるぐらい。（こんなんsleepしてないのと同じなんですけどね...。建前的sleepだね。）
誰とも情報交換したことないので、これが安いかどうかは分かりません。

- Vultr
- Linode
- DigitalOcean

あたりのVPSがおすすめ。
自由に作って自由に捨てれる。

プロキシは WebShare が安価で安定してていい感じ。（良質で安価なプロキシあったら知りたいのでコメントください。）プロキシのベーシック認証はExtensionを生成して通す形で実現。ググれば余裕で出てくるので割愛。Selenium使うときは画像リソースを受け付けないブラウザ設定にするのを忘れずに。帯域制限引っかかって死んじゃう。

---

節度あるスクレイピングライフを！
単発のスクレイピングは簡単。継続的なスクレイピングは難しい。
Scopedなcss/scss環境における簡略化MindBEMdingなCSS設計の提案

# MindBEMdingってScopedだと冗長じゃね！？！？！？！？

・・・っておもったので考えてみました。

# というわけで
## そもそも、MindBEMdingとは
「Block」「Element」「Modifier」の略で、
コンポーネントをこの構造に分けてみよう、という考え方のこと。
なお、それぞれ

- Block
    - コンポーネントの大枠のこと
- Element
    - コンポーネントに付随する子要素のこと
- Modifier
    - コンポーネントに付与されることで、状態を変化させる要素のこと

たとえば以下のようなボタンがあったとします（画像作れないのでAAで）

```
[いいね❤️]
```

その場合

```
[　　　　]　←Block
　　　　❤️　　←Element
(いいね❤️)　←Modifier
[いいね♡]　←ElementのModifier
```

という解釈になります。

## CSSの一般的記法
Elementは「__」（アンダースコア2つ）、
Modifierは「--」（ハイフン2つ）
で表現されることが多いです。

たとえば上記ボタンはMindBEMdingだと以下のように表現されます。

```css
.button
.button__heart
.button--round
.button__heart--blank
```

# こうすれば良いのではないか
## 適当なコンポーネントの集まりをMindBEMdingで作ってみた
たとえば、タイトルとディスクリプションを有する一覧があったとします。
このリストをMindBEMding的な命名を適当にするとこんな感じになるはず。

```html
<section class="o-someArticles">
  <div class="o-someArticles__inner--top">
    <article class="m-someArticle">
      <h2 class="m-someArticle__title">なんかタイトル</h3>
      <p class="m-someArticle__desc">なんか説明</p>
    </article>
  </div>
  <div class="o-someArticles__inner">
    <article class="m-someArticle">
      <h2 class="m-someArticle__title">なんかタイトル</h3>
      <p class="m-someArticle__desc">なんか説明</p>
    </article>
  </div>
  <div class="o-someArticles__inner">
    <article class="m-someArticle">
      <h2 class="m-someArticle__title">なんかタイトル</h3>
      <p class="m-someArticle__desc">なんか説明</p>
    </article>
  </div>
  <div class="o-someArticles__inner">
    <article class="m-someArticle">
      <h2 class="m-someArticle__title">なんかタイトル</h3>
      <p class="m-someArticle__desc">なんか説明</p>
    </article>
  </div>
</section>
```

## コンポーネントとして分割する
上記コンポーネントは、リストコンポーネントと記事コンポーネントに分割することができる。
たとえば分割すると以下のようになる。

```html
<section class="o-someArticles">
  <div class="o-someArticles__inner--top">
    <m-someArticle>
  </div>
  <div class="o-someArticles__inner">
    <m-someArticle>
  </div>
  <div class="o-someArticles__inner">
    <m-someArticle>
  </div>
  <div class="o-someArticles__inner">
    <m-someArticle>
  </div>
</section>
```

```html
<article class="m-someArticle">
  <h2 class="m-someArticle__title">なんかタイトル</h3>
  <p class="m-someArticle__desc">なんか説明</p>
</article>
```

## Scopedである場合、ここまで簡略化できるのではないかの提案
上記のようにコンポーネントが分割された場合は、
そのコンポーネントファイルに**記載されているエレメント**が
Scopedの範囲となる。

つまり、クラス名についてはBlockを事前に明記せず、
コンポーネントのScope内ならばクラス名からBlockを排除し、
ElementとModifierのみの表記で表現することができる。

```html
<section class="o-someArticles">
  <div class="__inner --top">
    <m-someArticle>
  </div>
  <div class="__inner">
    <m-someArticle>
  </div>
  <div class="__inner">
    <m-someArticle>
  </div>
  <div class="__inner">
    <m-someArticle>
  </div>
</section>
```

```html
<article class="m-someArticle">
  <h2 class="__title">なんかタイトル</h3>
  <p class="__desc">なんか説明</p>
</article>
```

## 注意点
ただし、以下のようなCSSがあったとする。
\<m-someArticles>の影響範囲はその**コンポーネントが読み込まれている頭まで**であり、
完全に外部の影響を受けない、というわけではないことを注意しないといけない。

```scss:m-someArticles
.m-someArticles .--new {} // ←☆とする
```

```scss:m-someArticle
.m-someArticle.--new {} // ←☆の影響を受ける
.m-someArticle .--new {} // ←☆の影響を受けない
```

なので、以下のようにModifierについてはある程度詳細に記述する必要がある。

```scss:m-someArticles
.m-someArticles .__inner.--new {}
```
【Laravel】中間テーブルをsycnメソッドでお手軽に保存する

# 概要

`sync`メソッドを利用することで関連テーブルのデータ更新を簡単に行ってみた

https://readouble.com/laravel/8.x/ja/eloquent-relationships.html

# リレーションの定義

```php:User.php
class Users extends Model
{
    /**
     * モデルと関連しているテーブル
     *
     * @var string
     */
    protected $table = 'users';

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'id', 'name'
    ];

    public function user_roles(): \Illuminate\Database\Eloquent\Relations\BelongsToMany
    {
        return $this->belongsToMany(UserRoles::class, 'user_roles', 'user_id', 'role_id');
    }
```

# `sync（）`ロジックを定義する

```php:UserService.php
public function store(array $postData, $id = null)
{
    $user = User::query()->updateOrCreate(
        ['id' => $id],
        $request
    );

    return $user-> user_roles()->sync($postData['role_id'] ?? []),
}
```

# 最後に

読んでいただきありがとうございます。
今回の記事はいかがでしたか？
・こういう記事が読みたい
・こういうところが良かった
・こうした方が良いのではないか
などなど、率直なご意見を募集しております。
【React】CSSのあて方

## はじめに
　本記事は、プログラミング初学者が、学習を進めていて疑問に思った点について調べた結果を備忘録も兼ねてまとめたものです。
　そのため、記事の内容に誤りが含まれている可能性があります。ご容赦ください。
　間違いを見つけた方は、お手数ですが、ご指摘いただけますと幸いです。

##ReactでのCSSのあて方

### Inline Style
React標準のCSSのあて方

```.jsx:InlineStyle

export const InlineStyle = () => {
  // オブジェクトでそれぞれのスタイルを定義
  const containerStyle = {
    border: "solid 4px #ff7f50",
    borderRadius: "20px",
    padding: "8px",
    margin: "10px",
    display: "flex",
    justifyContent: "center",
  };
  const titleStyle = {
    margin: 0,
    color: "#ff7f50",
  };
  const buttonStyle ={
    backgroundColor: "#ff7f50",
    border: "none",
    padding: "8px",
    borderRadius: "8px",
  };
  
  return (
    // 各要素にstyle={}を記述し適用していく 
    <div style={containerStyle}>
      <p style={titleStyle}>Inline Styleの練習</p>
      <button style={buttonStyle}>TEST</button>
    </div>
  );
};

```
【Laravel】updateOrCreateメソッドを利用して登録・更新ロジックを共通化

# 概要

`updateOrCreate`メソッドを利用することで登録・更新処理をシンプルにしてみた

https://laravel.com/docs/8.x/eloquent#upserts


# 変更前のロジック

- 更新時は`save()`・登録時は`create()`メソッドを実行している

```php
<?php
/**
 * 登録・更新
 * @param array $request
 * @param int|null $id
 * @return bool|Builder|Model
 */
public function store(array $request, ?int $id = null)
{
    $isEdit = !is_null($id);

    if ($isEdit) {
        return (User::query()->findOrFail($id))->fill($request)->save();
    }

    return GoodsCategories::query()->create($request);
}
```

# 変更後のロジック

`updateOrCreate(array 検索対象のカラム=>レコード, array 登録・更新データ)` を利用することで、更新時・登録時の処理を共通化することができます

```php
/**
 * 登録・更新
 * @param array $request
 * @param $id
 * @return array
 */
public function store(array $request, $id = null)
{
    //　登録ずみIDがあれば更新・なければ登録
    return User::query()->updateOrCreate(
        ['id' => $id],
        $request
    );
}
```

# 最後に

読んでいただきありがとうございます。
今回の記事はいかがでしたか？
・こういう記事が読みたい
・こういうところが良かった
・こうした方が良いのではないか
などなど、率直なご意見を募集しております。
【Pyhon】tweepy で Twitter API V2を使おうとしたらつまずいたのでメモ





##参考ページ
https://research-labo.com/howto-twitterapi-getkeys/

https://qiita.com/penguinprogrammer/items/b220be0c203eaaad015a


## トラブル1
###tweepyのバージョンが自動で最新にならない
pip review --auto ではなぜかtweepy==3.9.0にしかならず、tweepy.Client()が使えなかった

### 解決

https://pypi.org/project/tweepy/

pypiのページに行って、最新リリースのバージョンを調べ、バージョン指定してpip install する

```
pip install tweepy==4.5.0
```

## トラブル2
###Developer Portalに「App permissions」のボタンが見つからない
初期状態では「App permissions」が「read」になっているため、読み込み以外のことをしようとすると「 403 Forbidden」のエラーが出てしまう


### 解決
「OAuth 1.0a」を有効化することで、「App permissions」の選択ボタンが表示される

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563188/d2d5c300-ee51-f8be-0db1-64a535c094e6.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563188/af2e34b4-371b-237b-6180-4672ace00454.png)

###おまけ：複数画像ツイートのサンプルコード
```python
import tweepy

CK = '**********'
CS = '**********'
AT = '********************'
AS = '********************'

auth = tweepy.OAuthHandler(CK, CS)
auth.set_access_token(AT, AS)

api = tweepy.API(auth)


# このリスト内の画像を添付（上限4枚）
listImages = ["test_img.png","test_img.png","test_img.png","test_img.png"]

media_ids = []
for image in listImages:
    img = api.media_upload(image)
    media_ids.append(img.media_id)

api.update_status(status="ツイート文", media_ids=media_ids)
```
Nuxt.jsにおけるFLOCSSとAtomicDesignの比較及び相互変換

# なんでこんな記事書いたか

社内ではFEとBEの間をウロチョロしていて、
そこまでhtmlコーディングをしない私。

社内のガチFEさんたちがhtmlで静的ファイルを作る場合は
FLOCSSが多く、んじゃあ今後Nuxtのコーディングルールもそっちに合わせよか
とやり出してはみたものの、**まったく**しっくりいかず。

やはり思想的には個人的にAtomicDesignのほうがしっくりくるので、
AtomicDesignと柴犬でもわかるFLOCSSを読み直しながら
相互対応表を作り、今後他のエンジニアがNuxtプロジェクトに関わるときに
コンポーネント設計に迷いが出ないようにしようとおもったわけですさ。

# FLOCSSかAtomicDesignか

Nuxtにおけるコンポーネント設計におけるディレクトリ構造が
FLOCSSよりはAtomicDesignの方がシンプルかつわかりやすいもの
であるため、今後**Nuxt.jsにおける開発**に限っては、
 AtomicDesignの思想でコンポーネントを分類する方が良いと感じている。

````
└── nuxt-sample //プロジェクトディレクトリ
    ├── nuxt.config.js
    ├── src
    │   ├── assets
    │   ├── components 
    │   │   ├──  atoms
    │   │   ├──  molecules
    │   │   ├──  organisms
    │   │   └──  templates
    │   ├── layouts
    │   ├── pages
    │   ├── plugins
    │   ├── static
    │   ├── store
    │   └── types
    ├── storybook
    └── test
````

## 理由
Nuxt.jsの基本ディレクトリは以下のようになっている。

```
    └── src
        ├── assets
        ├── components 
        ├── layouts
        └── pages
```

そこに、FLOCSSのディレクトリ基準を当て込むと以下のような状態になる。

```
    └── src
        ├── assets //元からあるディレクトリ
        ├── components //元からあるディレクトリ
        │   ├── layout
        │   └── object
        │       ├── component
        │       ├── project
        │       └── utility
        ├── layouts //元からあるディレクトリ
        └── pages //元からあるディレクトリ
```

この状態だと、layoutが複数あったり、pagesとprojectの違いが分かりづらいなどの問題が発生する。

## 対策、FLOCSSからAtomicDesignsに乗り換える場合の分類目安

| FLOCSS | AtomicDesign | 備考|
| --- | --- | --- |
| Foundation | assets/css | scssとして用意し、あらかじめロードする。 |
| Object/Utility | 該当なし | Tailwind CSSで代用する。Tailwind CSSを利用しない場合は、scssファイルにまとめた上で、assets/cssに格納する。 | 
| Object/Componentのなかでもより原始的なもの | component/atoms | h2やbuttonなどのよりプリミティブなコンポーネント。他のコンポーネントに依存することがあってはならない。  |
| Object/ComponentのなかでもComponentを含むもの | component/molecules | atomsが複数連なってなるコンポーネント。独立したコンポーネントというよりは、OrganismsやLayout内の一要素となるもの。 |
| Object/Project | component/organisms | moleculesやatomsを含む、プロジェクト固有のパターンであり、汎用性が低いもの。 |
| Layout | component/templates | 大小問わず、レイアウトテンプレートは全てここに格納する。|
| 該当なし | pages | ページのルーティング。|


````
└── nuxt-sample //プロジェクトディレクトリ
    ├── nuxt.config.js
    ├── src
    │   ├── assets
    │   │   └──  css //Foundation
    │   ├── components 
    │   │   ├──  atoms //Object/Component
    │   │   ├──  molecules //Object/Component
    │   │   ├──  organisms  //Object/Project
    │   │   └──  templates //Layout
    │   ├── layouts
    │   ├── pages
    │   ├── plugins
    │   ├── static
    │   ├── store
    │   └── types
    ├── storybook
    └── test
````

# 参考書籍

[Atomic Design ～堅牢で使いやすいUIを効率良く設計する](https://www.amazon.co.jp/dp/B07CJ5TLK2/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1)
[柴犬でもわかるFLOCSS](https://booth.pm/ja/items/1033385)
RxSwiftでUITextViewからハッシュタグを抽出する

##前提

　UITextViewに入力されたものから新しく入力されてハッシュタグを抽出するのをRxSwfitでやってみました。ReplaySubjectはあまり話題に上がらないので、こういう使い方ができるのを知っていただければと思います。

##手順

- UITextView.textとReplaySubjectをバインドする。

``` Swift
  let differenceTxtSubject = ReplaySubject<String>.create(bufferSize: 1)
  txtView.rx.text
    .debounce(.milliseconds(300), scheduler: MainScheduler.instance)
    .bind(to: differenceTxtSubject)
    .dispose(by: disposeBag)
```

　ReplaySubjectはバッファされた分だけ遡ることができる。この場合はバッファサイズは１なので、１個前に流れてきたものと現在のものを比べることができる。

- 前回のものと今回のものを配列化し、今回の配列の中で前回の配列に入ってない要素を抽出するObservableを用意する。


```Swift
 var searchingQuery: Observable<String> {
        
        return Observable.zip(differenceTxtSubject, differenceTxtSubject.skip(1)) { previous, current in
            
            var previousNoHashTagArr = previous.components(separatedBy: "#").filter { $0 != "" }
            previousNoHashTagArr = previousNoHashTagArr.map { $0.filter { char in
                
                return char != " "
                
            } }
            
            var currentNoHashTagArr = current.components(separatedBy: "#").filter { $0 != "" }
            currentNoHashTagArr = currentNoHashTagArr.map { $0.filter { char in
                
                return char != " "
                
            } }
            
            let compareArr = zip(previousNoHashTagArr, currentNoHashTagArr)
            
            if let query = compareArr.first(where: { $0.0 != $0.1 })?.1 {
                
                return query
            }
            
            return ""
        }
        
    }
```


　このObservableをviewdidloadなどでsubscribeすれば、textViewに入力される度にハッシュタグを抽出できる。
　私の場合、抽出されるたびにハッシュタグを検索して予測変換的な機能を実装しています。
【Java】paizaでの学習を通して学んだJavaメソッドのチートシート

#はじめに
はじめまして！初投稿をさせていただきますヨシカワです！
大学でpaizaラーニングについての紹介があり、興味を持って取り組み始めました。
その際に、知らなかった便利なJavaメソッドを知れたので記事にしようと思いました。
間違いや補足があればご指摘お願いします。

#目次
[文字列aの長さを取り出す](#文字列aの長さを取り出す)
[文字列aに特定の文字列sが含まれているかどうか](#文字列aに特定の文字列sが含まれているかどうか)
[文字列aからn-m番目の文字列を取り出す](#文字列aからn-m番目の文字列を取り出す)
[文字列aを分割し分割した文字列を配列として格納する](#文字列aを分割し分割した文字列を配列として格納する)
[文字列aを数値へ変換する](#文字列aを数値へ変換する)
[数値iを文字列に変換する](#数値iを文字列に変換する)
[数値aの絶対値を求める](#数値aの絶対値を求める)
[参考にさせていただいたページ](#参考にさせていただいたページ)

##文字列aの長さを取り出す
```java:
a.length()
```
半角、全角関係なく返してくれます。

```java:例
    String str = "white";
    String str2 = "白";

    System.out.println(str.length()); // 5
    System.out.println(str2.length()); // 1
```

##文字列aに特定の文字列sが含まれているかどうか
```java
a.contains(s)
```
指定の文字列sが含まれていたらtrueを返します。

```java:例
    String str = "Hello";
    String str2 = "Thanks";

    System.out.println(str.contains("H")); // true
    System.out.println(str2.contains("a")); // false
```

##文字列aからn-m番目の文字列を取り出す
```java
a.substring(n,m);
```
文字列の一番先頭の文字を0番目として数えます。
(n,m)と書かれていますが実際はnからm-1までの範囲の文字列を取り出します。

```java:例
    String msg = "こんにちはお元気ですか？";

    System.out.println(msg.substring(5,11));  // お元気ですか
```
`こんにちはお元気ですか？`の`こ`を0番目とすると`お`は5番目なので開始インデックスnは5です。
`か`は10番目なので終了インデックスmは11です。

##文字列aを分割し分割した文字列を配列として格納する
```java:
a.split(区切りたい文字列,分割後の要素数)
```
```java:例
    String str = "a,b,c,d,e";
    String [] strArray = str.split(",");

    for(int i = 0 ; i < strArray.length ; i ++) {
	    	System.out.println(strArray[i]);
	}
    // a
    // b
    // c
    // d
    // e
```

##文字列aを数値へ変換する
```java:
Integer.parseInt(a)
```
先頭の文字列が0の場合、その先頭の0を削除する｢0埋め｣が行われます。

```java:例
    String str = "123";
    String str2 = "0567";
    
    int n = Integer.parseInt(str);
    int m = Integer.parseInt(str2);

    System.out.println(n); // 123
    System.out.println(m); // 567
```

##数値iを文字列に変換する
```java:
Integer.toString(i)
```

```java:例
    int n = 123;
    int m = 789;

    String str = Integer.toString(n);
    String str2 = Integer.toString(m);

    System.out.println(str); // 123
    System.out.println(str2); // 789
    System.out.println(str + str2); // 123789 ←str,str2がint型だと912が出力される
```
##数値aの絶対値を求める
```java
Math.abs(a)
```
if文を使って絶対値を求めることはできますが、コードをスリムにしたい方におすすめです。

```java:例
    int n = 234;
    int m = -456;

    System.out.println(Math.abs(n)); //234
    System.out.println(Math.abs(m)); //456
```
#参考にさせていただいたページ
今回、この記事を書くにあたり以下のページを参考にさせていただきました。ありがとうございました。

[【Java】length()とlengthを使って文字列、配列の長さを取得！](https://flytech.work/blog/11725/#length-2)
[【速習Java】Stringのcontainsで文字列を含むか知る方法](https://www.sejuku.net/blog/19257)
[文字列から開始と終了インデックスを指定して部分文字列を取得する](https://www.javadrive.jp/start/string/index7.html)
[Javaのsplitの使い方を現役エンジニアが解説](https://techacademy.jp/magazine/25947)
[あえて言うほどではない 数値 ⇔ 文字列変換 Java編](https://www.techscore.com/blog/2012/11/28/%E6%95%B0%E5%80%A4-%E2%87%94-%E6%96%87%E5%AD%97%E5%88%97%E5%A4%89%E6%8F%9B-java%E7%B7%A8/)
[ Let'sプログラミング　絶対値を取得する](https://www.javadrive.jp/start/math/index1.html)
100日でSQLの達人になる@LeetCode! Day7 <long to wide, sum(case when...)>

##1179. Reformat Department Table （問題レベル: Easy）
今日の問題はこれ。
long形式のテーブルをwide形式にする基本問題。

```case when 条件式 値 else null end```を使うことはすぐに分かったのだが、不正解！。

ポイントは```sum(case when 条件式 値 else null end)```と```sum() group by id```を使うこと。
sumしないと、long形式の一行、一行に条件を当てはめているだけなので、同じidがlong形式と同じ行数並んでしまう！
sumでid毎にまとめないと駄目！

この問題はSolutionが準備されていなかったがDiscussionで高評価の投稿を見るとズバリポイントが記載されていました！

* [LeetCode](https://leetcode.com/)の問題は、MS SQL Serverで解いています。
[Swift]SwiftMessagesで色を変更する

# はじめに
Qiita初投稿です。

SwiftMessagesを利用して、ポップアップを表示しようとしたときに、背景色の変え方で少し躓いたのでまとめます。

## 公式ドキュメント
https://github.com/SwiftKickMobile/SwiftMessages

## 初期状態
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1795015/e2fe0599-6921-32df-ec08-78b51458fdfa.png" width=50%>

```Swift
config.presentationStyle = .center
```
で中央に表示しています。他の色などはいじっていません。
## 画面全体の色
```Swift
config.dimMode = .color(color: .systemRed, interactive: true)
```
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1795015/b5cbf495-50b9-af15-a9df-96833a0e0f05.png" width=50%>



## ポップアップの周りの色
```Swift
view.backgroundColor = .systemRed
```
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1795015/6d20b1f6-1195-8cec-0429-76efcd6f481e.png" width=50%>

## ポップアップ自体の色
```Swift
view.backgroundView.backgroundColor = .systemRed
```
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1795015/917e0a1c-c304-2e68-8278-dc35e54caa48.png" width=50%>


# おまけ

## デフォルトアイコンの色
```Swift
view.iconImageView?.tintColor = .systemRed
```
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1795015/ee7ad557-4495-0078-3952-753b08ce6451.png" width=50%>
デフォルトアイコンを利用するには

```Swift
view.configureContent(title: "title", body: "body")
```
のようにiconTextを消去しましょう。
## titleの色
```Swift
view.titleLabel?.textColor = .systemRed
```
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1795015/ecf28374-e33a-774c-d6b2-a733a4d4531f.png" width=50%>
## bodyの色
```Swift
view.bodyLabel?.textColor = .systemRed
```
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1795015/a9c35626-e0ac-dcbe-f040-9b64696e1027.png" width=50%>

## 終わりに
間違いなどありましたらご指摘お願いします。