OmniAICreator/Qiita-1.07M huggingface dataset:
[Python] Seleniumで各ブラウザのDriverを自動取得

# はじめに
seleniumを使っているとブラウザドライバーの設定が結構めんどくさく感じている方もいると思うので、自動でブラウザのバージョンにあったドライバーを取得してくれるライブラリをご紹介します。

# webdriver-manager
使い方はとても簡単です。

```bash:
pip install webdriver-manager
# seleniumをインストールしていない人は以下も
# pip install selenium
```

複数のブラウザドライバーをサポートしています。

```python:test_selenium.py
from selenium import webdriver

# Chromeを使う場合
from webdriver_manager.chrome import ChromeDriverManager
driver = webdriver.Chrome(ChromeDriverManager().install())

# Chromiumを使う場合
from webdriver_manager.chrome import ChromeDriverManager
from webdriver_manager.utils import ChromeType
driver = webdriver.Chrome(ChromeDriverManager(chrome_type=ChromeType.CHROMIUM).install())

# Firefoxを使う場合
from webdriver_manager.firefox import GeckoDriverManager
driver = webdriver.Firefox(executable_path=GeckoDriverManager().install())

# IEを使う場合
from webdriver_manager.microsoft import IEDriverManager
driver = webdriver.Ie(IEDriverManager().install())

# Edgeを使う場合
from webdriver_manager.microsoft import EdgeChromiumDriverManager
driver = webdriver.Edge(EdgeChromiumDriverManager().install())

# Operaを使う場合
from webdriver_manager.opera import OperaDriverManager
driver = webdriver.Opera(executable_path=OperaDriverManager().install())

# Opera browserが「C:/Program Files」あるいは「C:/Program Files (x86)」以外にインストールされている場合
from webdriver_manager.opera import OperaDriverManager
options = webdriver.ChromeOptions()
options.add_argument('allow-elevated-browser')
options.binary_location = "C:\\Users\\USERNAME\\FOLDERLOCATION\\Opera\\VERSION\\opera.exe"
driver = webdriver.Opera(executable_path=OperaDriverManager().install(), options=options)
```

## 設定

### GH_TOKEN
webdriver_managerはいくつかのドライバを公式のGithubリポジトリからダウンロードしているのですが、非認証ユーザーに対しては1時間に60リクエストまでといった制限がかかります。認証するために環境変数にgithub tokenを設定しておくことができます。

```bash:bash
$ export GH_TOKEN = your_access_token
```
あるいは

```python:test_selenium.py
import os
os.environ['GH_TOKEN'] = your_access_token
```

### WDM_LOG_LEVEL

webdriver_managerを使って実行するとコンソール上にwebdriverのダウンロードに関するログが出力されるのですが、出力を目障りな場合は出力されないようにします。

```python:test_selenium.py
import os
os.environ['WDM_LOG_LEVEL'] = '0'
```
あるいは

```python:test_selenium.py
ChromeDriverManager(log_level=0).install()
```

### WDM_PRINT_FIRST_LINE

webdriver_managerを使って実行するとコンソールの1行目にデフォルトで空行が入りますが、目障りな場合は消すことができます。

```python:test_selenium.py
import os
os.environ['WDM_PRINT_FIRST_LINE'] = 'False'
```
あるいは

```python:test_selenium.py
ChromeDriverManager(print_first_line=False).install()
```


### cache_valid_range

ドライバのcacheの有効期間はデフォルトで1日ですが、このパラメータを変更することができます。

```python:test_selenium.py
ChromeDriverManager(cache_valid_range=2).install()
```

# 参考
[webdriver-manager](https://pypi.org/project/webdriver-manager/)

# まとめ
以前までchromedriver_binaryを使用していたので、定期的にバージョンを手動で更新しなくてはなりませんでしたが、これがあると結構楽になりそうですね。
【Swift】UILabelの一部の文字のフォントサイズやテキストカラーを変更する

UILabelの一部の文字のフォントサイズやテキストカラーを変更する方法。

## 実装コード

すでにUILabel「`sampleLabel`」は宣言しているものとします。

```swift
let attributedText = NSMutableAttributedString(string: sampleUILabel.text!)
attributedText.addAttributes(
    [
        //一部の文字に反映させたい内容
        .font: UIFont.systemFont(ofSize: 20), //フォントサイズを変更
        .foregroundColor: UIColor.red // テキストカラーを変更
    ], 
    // sampleUILabelの0文字目から９文字目までに変更内容を反映させる
    range: NSMakeRange(0, 9)
) 
sampleUILabel.attributedText = attributedText
```
`addAttribute`メソッドを使うのがポイント。

`addAttribute`メソッドは以下のように宣言されています。

```swift
func addAttribute(_ name: NSAttributedString.Key, 
            value: Any, 
            range: NSRange)
```

## 参考

https://developer.apple.com/documentation/foundation/nsmutableattributedstring/1417080-addattribute

https://developer.apple.com/documentation/foundation/nsmutableattributedstring

https://www.yoheim.net/blog.php?q=20180301

## おすすめ情報

https://wagtechblog.com/programing/swift-iphone-application-school

https://wagtechblog.com/programing/swift-textbook.html
[Bukkit]実行用ファイル（.bat）をつくる

# はじめに
毎回コマンドプロンプトを開き、サーバーのパスをコピーして`cd`コマンドを打ち、`java -jar`で起動する...というのは面倒です。ここに`-Xmx`やら`-Xms`やらのサーバーパフォーマンス関連のフラグを追加するとなると余計に面倒ですね。
今回はコレを回避すべく、ダブルクリックでサーバーを開けるようにします。

注意点として、**Windowsでのみ実行できます**。
OSが違う場合は違う手段を取る必要があるので、適宜検索をかけてみて下さい。

# バッチファイルとは
難しそうな単語ですが。簡単に言えば「ダブルクリックで任意のWindowsコマンドを実行できるようにするファイル」です。
`.bat`という拡張子がついたファイルはコレに該当します。

今回はバッチファイルを用いてPaperMCのサーバーを開けるようにします。

# 手順
## batファイルを制作
jarファイルと同じパスに、新しいファイルを作成します。
今回は`start.bat`とします。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2175091/743ba96c-99a5-3e95-9227-c591e68d1777.png)

## 中身を編集
batファイルを実行した際に実行したいコマンドを設定していきます。

ファイルを右クリックし、「編集（E）」を押します。
![2021-12-10 (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2175091/a226443b-2cad-4fa0-c424-6f2a32d243eb.png)
」

Windows標準のメモ帳が起動すると思うので、ここに実行したいコマンドを記入します。
今回は`paper.jar`というjarファイルを動かしたいので、コマンドは`java -jar paper.jar`となります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2175091/5512efdb-8d3e-c22e-50e8-ed64c946a1eb.png)

記入したら`ctrl + S`を押して保存して下さい。

## 実行してみる
もう一度ファイルエクスプローラに戻り、`start.bat`をダブルクリックしてみます。
通常通りサーバーが起動すれば完成です。お疲れさまでした。

# トラブルシューティング
## 「このアプリはお使いのPCでは実行できません」と出る場合
記入したコマンドに間違いがある場合があります。

* 入力した後の保存を忘れている。
* 記述形式を間違えている。

以上のような理由が考えられます。再度確認してみて下さい。
RPA導入検討にGAS+freee APIで勝った話

freee APIアドカレには初めて投稿します。ネット広告専門の広告代理店のシステム開発部にて、普段は主にPHPでWebサービスや社内ツールを開発しています。

## 起きたこと

いつものようにPHPと戯れていたある日、管理部から質問を受けました。
「RPAで大量のPDFファイルの内容を読み取りたいんですけど、管理部でネット見ながらコピペとかで実現できるものですか？PRA業者に頼むとどれぐらいが相場ですかね？」
「!?」

弊社では、たくさんの広告主様に毎月運用手数料を請求させていただくのですが、その際freeeで定期作成された下書き請求書を印刷して、 各広告主様の担当コンサルタントに配布し、内容のチェックを受けてから正式な請求書を作り、送付するというフローになっていました。
昨今のリモートワーク化を受けて、物理的に紙の請求書を大量に印刷→担当者別に仕分け→配布→チェック結果をfreeeに入力…という物理的な紙を使う
フローをやめたい、というのが管理部の要望です。そのために、案件名・担当者名・金額…のような請求書の明細行に載っているデータをGoogleスプレッドシートのデータとして見たい、とのことでした。
よくよく聞いてみると、紙請求書のチェックは印刷→仕分け→チェック結果入力をする管理部が大変なだけでなく、各担当コンサルタントにとっても
紙と画面の突き合わせを毎月かなりの時間をかけて行う負担の大きい仕事であることがわかりました。

さて、やりたいことがわかったところで、問題はやり方です。PDFの読み取り…完全に守備範囲外です。うっすらOCRでできる気がする、という程度。なにせ単なるPHPerなので（笑）
ただ、私自身、過去に開発部向けの申請ツールを作ろうとして調べたことがあり、freeeにはAPIがあることは知っていました。そこで、「APIがあるなら、むしろPDFを経由しないほうが楽なのでは？」と思ったわけです。
「たぶんRPAでなくAPIでできると思うから作らせてくれ！」と言って、freee APIドキュメントを読み込み、スキマ時間で実装しました。毎月のデータ作成をいちいち開発部に依頼せずに管理部だけで完結できるよう、Google Apps Scriptを利用しました。（本当はSlackから起動させたかったんですが、GASがSlack側の規定時間内にレスポンスを返せず断念）

新しいフローは、【管理部がスプレッドシートを作成→スプレッドシートをコンサルティング部に共有→コンサルタントは自分の名前で絞り込んでデータチェック→管理部はスプレッドシート上のチェック結果を見てfreeeに入力】となりました。PDFを読み取るRPA導入検討は消滅しました :v:
Googleドライブの所定のフォルダに増えていくチェック用スプレッドシートを観察していたところ、印刷→仕分けという物理作業がいらない分、月に1回だけでなく何回かチェックもできるようになったようです。 :relaxed:

## 作ったもの

freee APIから所定の条件（弊社内で毎月チェックの対象になる）を満たす下書き状態の請求書データを取り出して、Googleスプレッドシートに一覧を書き出すGoogle Apps Scriptです。

freeeのInvoices APIからデータを取得し、必要な形に整形したうえで、当月チェック用のGoogleスプレッドシートファイルを作成して一覧を書き込みます。ほぼCSVのような装飾のないシートですが、エクセルで言うオートフィルタ機能を使って絞り込んだり並べ替えたりして活用されています。

### 工夫したところ1: リフレッシュトークンの扱い

私が普段触っている各広告媒体のAPIだと、OAuth認証して取得したリフレッシュトークンは1つのリフレッシュトークンから何度でも（敢えて無効化ボタンをポチしない限り）新しいアクセストークンを作れる仕様になっていることが多いです。
この仕様の場合、リフレッシュトークンだけ保存しておけば、アクセストークンは使い捨て可能です。（セキュリティ的には良くないですが）社内向けの小さなスクリプトでは1回取得したリフレッシュトークンをスクリプト内にハードコードしておくことができます。
しかし、freee APIではリフレッシュトークンは1回リフレッシュすると死んでしまい、今回取得したアクセストークンに付属してくる新たなリフレッシュトークンを次に備えて保持しないといけません。

今回、実行環境としてGoogle Apps Scriptを選択したため、このトークンの仕様には随分悩まされました。毎月のデータ作成を管理部だけで完結したい（いちいち開発部に依頼しなくてもデータ出せるようにしたい）ので、毎月トークン取得してスクリプトを編集する仕様はNGなのです。
結局、GoogleドライブにGoogleドキュメントの形でアクセストークンjsonを保存し、Google Apps Script側で実行時にGoogleドキュメントから読み取ったものをJSON.parse()して使うことで解決しました。


### 工夫したところ2（freee APIの仕様のおかげで工夫しなくてもよかったところ）: 明細行がほしいがN+1したくない 

最初にスクリプトの構成を考えたとき、Google Apps Scriptの実行時間制限の範囲内で、大量のAPIコール（N+1のAPIコール）は避けたいな、なにか方法はないかな？とぼんやり考えていました
ドキュメントを見るとfreee APIではInvoiceをGETすると明細行のコレクションが一気についてくるので、この心配はしなくて良いことがわかりました。

## おまけ

会社の規定上、開発部は会計freeeの請求書データを見る権限がなく請求データ上の金額が税抜か税込みか不明だったので、一旦管理部にそのままデータを渡したところ「全部1割引になってます！」という指摘を受けました。 :sweat_drops:
freee API ドキュメントに対しプルリクエストを出しました。 <https://github.com/freee/freee-api-schema/pull/122>
ImageView に画像データをいい感じに渡すカッコいいコード

with で Android エンジニアをしている @t2low です。

かなり前の話です。
自分では**カッコいい感じ**のコードが書けたと思ったのですが、その後活用されずに眠っているので供養のつもりで記事にします。
(※ 実際のコードとは異なる部分があります)

## コードを書いたきっかけ

ある画面で API から返された画像データ(URL)があれば読み込んで表示し、なければアプリ内の画像(drawable)を表示するという処理が必要になりました。
愚直に書くと次のようなコードになるかと思います。
(※ `fun ImageView.loadImage(url: URL)` という URL を渡すと画像を読み込む ImageView の拡張関数が生えてると思ってください)

```kotlin
if (iconUrl != null)
    iconImageView.loadImage(iconUrl)
else
    iconImageView.setImageResource(R.drawable.something)
```

この画像データの種類に応じて処理を分けなければいけない、というのがめんどうですよね？めんどうに決まっています。
そこでどのような種類のデータでも渡すことができる仕組みを考えました。

## 画像クラス

まずは画像データを表す `Image` クラスを作りました。
そもそも `ImageView` に `int` (Drawable の リソース ID) を渡したり、 `URL` を渡すのが間違いの元です。ナンセンスです。
やはり `ImageView` には `Image` を渡さなければいけません。
なぜなら `ImageView` は、`Image` の `View` だからです。

次のようなクラスを考えました。

```kotlin
sealed class Image {
    object NoData: Image()
    data class Resource(@DrawableRes resourceId: Int): Image()
    data class Url(url: URL): Image()
}
```

みんな大好き `sealed class` です。好きですよね？
(`sealed interface` も大好きだと思いますが、当時はまだありませんでした)

### 使用例

これでデータの種類が異なっても同じ Image クラスとして表すことができるようになりました。

```kotlin
val iconImage: Image = 
    if (iconUrl != null) Image.Url(iconUrl) 
    else Image.Resource(R.drawable.no_image)
```

かんぺきです(ﾄﾞﾔｧ)

## ImageView に画像を設定するための拡張関数

Image クラスができたので、今度はそれを ImageView に設定するためのコードを書きましょう。
次のような拡張関数を作りました。

```kotlin
fun ImageView.setImage(image: Image) {
    when (image) {
        is Image.NoData -> this.setImageDrawable(null)
        is Image.Resource -> this.setImageResource(image.resourceId)
        is Image.Url -> this.loadImage(image.url)
    }
}
```

みんな大好き拡張関数です。好きですよね？
やってることは単純に `when` で分岐させてそれぞれ処理しているだけです。
分岐していた処理を隠蔽することに成功したと言えるでしょう(ﾄﾞﾔｧ)

### 使用例

画像データの種類によって処理を変える必要がなくなりました。
どの種類の画像データでも、次のコードで画像を設定することができます。

```kotlin
val iconImage = 
    if (iconUrl != null) Image.Url(iconUrl) 
    else Image.Resource(R.drawable.no_image)
iconImageView.setImage(iconImage)
```

えー、すごーい、かっこいー。

## 供養

いい感じに書けたなー、と思ってはいるんですが、実際にはほとんど使われていません。
使われないコードということは、結局のところ大したコードではないのかもしれません。

ぶっちゃけ「 URL がなければ、 Drawable を表示する」というシチュエーションがほとんどありません。
大抵は URL が null になることなどなく、 `ImageView.loadImage(URL)` だけで済んでしまいます。
解決したかった問題が小さかったんですね。
安らかに眠っていてください(技術的負債にはなりませんように)。

## 最後に

大したことないコードを紹介しましたが、自分はこれをとても楽しく書いていたことを覚えています。
ドヤっていたと思います。今でも愛着のあるコードです。

上では冗談めかして書きましたが、 sealed class や、拡張関数など、 Kotlin には書いていて楽しい仕様が盛りだくさんです。
Kotlin でコードを書いていると、なぜか厨二心(ちゅうにごころ)をくすぐられます。
`infix` 関数とかどうにかして使いたいですよね。
無駄に読みにくくカッコだけはいいコードを書かないように必死に抑えている毎日です。

Kotlin な方も、 Kotlin ではない方も、皆さん楽しくプログラミングしましょう～
楽しいプログラミングライフを！ :wave:
俺的iPadプログラミング環境

# はじめに
ふとした時に、プログラミングをしたい！!コードを修正したいと思っても、パソコン今持ってないからプログラミングができない！！！イライラ！！!
そんなことを思ってしまう方ににお勧めです。ここではあくまでiPadだけでプログラミング！ではなくPCを持ち歩かなくてもiPadさえあればプログラミングができるのかについてを書きます。
# 俺的iPadプログラミング環境
iPadでプログラミングするために使っているもの。


iPad pro 2019 11インチ
iPadアプリ
termius (ssh接続用)
https://apps.apple.com/jp/app/termius-ssh-client/id549039908
openVPN (vpn接続用)
https://apps.apple.com/jp/app/openvpn-connect/id590379981
Texstatic (テキストエディタ)
https://apps.apple.com/jp/app/textastic-code-editor-9/id1049254261
working Copy(github用)
https://apps.apple.com/jp/app/working-copy-git-client/id896694807

適当なLinuxパソコン (Linux mint mate20)
導入ソフトウェア
openssh server
git 

asus ax3000(VPN対応ルータ)
https://www.amazon.co.jp/ASUS-%E6%97%A7%E3%83%A2%E3%83%87%E3%83%AB-WiFi-%E7%84%A1%E7%B7%9A-%E3%83%AB%E3%83%BC%E3%82%BF%E3%83%BCTUF-AX3000/dp/B0888CNTYM/ref=asc_df_B0888CNTYM/?tag=&linkCode=df0&hvadid=342439035822&hvpos=&hvnetw=g&hvrand=17867769617596035153&hvpone=&hvptwo=&hvqmt=&hvdev=c&hvdvcmdl=&hvlocint=&hvlocphy=1009501&hvtargid=pla-930929642575&ref=&adgrpid=71659040314&th=1




# linux serverが必要
そもそも論、iPad(iPad OS)には基本的にプログラミング言語を実行するためのコンパイラが提供されていません。一部アプリにはそれぞれの言語専用のコンパイラが提供されていますが、実際の開発に使えるレベルとは言えません。また、テキストエディタ(PC でいえば、Visual Studio codeやXcode)もあまり種類がなくPCとの互換性も低いです。そのため、iPad単体でプログラミングをするということはそもそも難しいです。そこで現れるのがLinux serverという存在です。Linuxというのはオープンソースで開発されているOSです。基本的に無料で使うことができ、ほとんどのハードウェアにも対応しています。LinuxにはUbuntu系,Read hat系など数え切れないほどのディストリビューションが存在しますが、各自自分のPCのスペックとOSの機能を見比べて選んでください。では本題であるLinux Serverですが、作り方はたくさんの記事があるので一部を紹介します。
(Linuxのインストール方法)
https://qiita.com/technopocket/items/0ff4dd2a09b0538b726c
(open ssh serverの立て方)
https://qiita.com/sango/items/816136188387221f05b3
(ルータのポートフォワーディング設定方法)
https://www.asus.com/jp/support/FAQ/114093/
# linux server + temiusで出来ること。
この二つがあれば、iPadはiPadの形をしたLinuxマシンとなります。なのでiPadがLInuxPCなったと考えて大丈夫です。基本的に処理はサーバー側だけで行い、iPadは通信と画面の表示だけを行うことになります。ではiPadがLinuxになりましたが、これはあくまでCLIのLinuxであり皆さんがいつもプログラミングを行っているGUIの画面ではありません。しかしiPadでプログラミングするときくらいCLIでつよつよエンジニアになった気分でプログラミングを楽しんでみてもいいじゃないですか？

# コードを編集する
一つ目の方法としてはtermiusを使いssh接続環境でviもしくはVimでコードを編集する。
もう一つは、Texstatic + Working copyを使い、ローカル環境でコードを編集する。

# 実行方法
termiusを用いて、Python や　C言語のファイルをデバッグ、実行する際は、Python qiita.pyなどで実行できます。また、各種jsを使ったwebページなどをローカルホストを立ててデバッグする際は、termius上で、いつも通りyarn serve(vue.js)を行い,自宅LAN環境にVPN接続し、ローカルホストが立てたページを参照することができます。

# 図解
![ローカルホスト.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1128363/213c95c4-0700-635a-159a-55eeacc23052.png)
![コード編集時.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1128363/767c2689-5d64-866e-54eb-53dddcb6f16c.png)


# 最後に
ここで紹介したのはあくまで俺的環境です。Windowsのリモートデスクトップを使いiPadでプログラミングをする方法などiPadの可能性は無限大です。その活用方法を自分で模索していくのが楽しいと思える人がやることであり、あくまでプログラミングをやるならPCだと私は考えています。またここに書いてあることはかなり雑で詳しい説明を省いています。iPadでごりごり開発したいと思ってしまったエンジニアならわかってくれるだろうと思い書いているので、何言ってんだこいつと思った方はぜひいろいろググっていただきネットワークやＰＣ、プログラミングについての知識を深めていただけると幸いです。
会社が許可したデバイスに限って LINE WORKS を利用する (Azure AD + Microsoft Intune 編)

LINE WORKS のシングル サインオンまわりのアップデートで、認証サービス側の追加機能が使いやすくなっています。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">先月の <a href="https://twitter.com/hashtag/LINEWORKS?src=hash&amp;ref_src=twsrc%5Etfw">#LINEWORKS</a> のアップデートで、ひっそりとシングル サインオンまわりの機能追加を行っています。<br><br>これによって、認証画面をデバイスの既定のブラウザで開くことが可能になっています。<a href="https://t.co/QqV77yARRW">https://t.co/QqV77yARRW</a></p>&mdash; iwaohig (@iwaohig) <a href="https://twitter.com/iwaohig/status/1469181829861494784?ref_src=twsrc%5Etfw">December 10, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

ここでは、Azure Active Directory でシングル サインオンを利用している場合に、デバイスが Microsoft Intune で設定したポリシーに準拠済みで登録されているデバイスに LINE WORKS の利用を許可する設定を行ってみました。

Azure ポータルで、条件付きアクセスの [アクセス制御]-[許可] で、[デバイスは準拠しているとしてマーク済みである必要があります] を [アクセス権の付与] の条件としています。

![l_1517737_1506_1639116389754.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/ca53274b-2c5e-ca0f-7c02-5167181cc05d.png)

LINE WORKS Developer Console で [Set External Browser] を有効にしています。
![l_1517737_1507_1639116636504.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/e73f74f8-e091-d3a7-11bd-b42aca5ede87.png)

これにより、アプリからのアクセス時に認証画面がデバイスの既定のブラウザで行われるようになります。

実際のログインの様子は以下です。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Intune で登録済みデバイスの条件つきアクセスで Windows アプリからログインしている様子です。<a href="https://twitter.com/hashtag/LINEWORKS?src=hash&amp;ref_src=twsrc%5Etfw">#LINEWORKS</a> アプリで ID 入力後に Edge が起動して Azure Active Directory の認証処理が行われています。 <a href="https://t.co/TUl3tr67KB">pic.twitter.com/TUl3tr67KB</a></p>&mdash; iwaohig (@iwaohig) <a href="https://twitter.com/iwaohig/status/1469194473792229379?ref_src=twsrc%5Etfw">December 10, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
[Python] 正規表現での文字列チェック

Pythonにおいての正規表現の使い方について簡単にまとめておく。
正規表現とは、特殊な文字や記号を使っていくつかの文字列を1つの文字列で表現する方法のこと。
正規表現で用いられる特殊文字については公式ドキュメントを参照。[公式ドキュメント](https://docs.python.org/ja/3/library/re.html#regular-expression-syntax)

# 正規表現の使い方
正規表現を使う方法には、以下の2パターンある。
① ```re```モジュールの関数を使用する。
② 正規表現オブジェクトのメソッドを使用する。
今回は***②正規表現オブジェクトを使った方法***を中心に扱う。

基本的な使い方の概要は以下となる。
1、 ```re```モジュールをインポート
2、 正規表現パターンから正規オブジェクトを作成
3、 正規表現オブジェクトのメソッドでマッチオブジェクトを作成

###正規表現オブジェクトの作成
正規表現オブジェクトは```compile()```を使用して作成できる。

```python
pattern = re.compile(<正規表現パターン>)
```

###マッチオブジェクトの作成
マッチオブジェクトを返すメソッドの中から2つ紹介する。その他のメソッドについては公式ドキュメントを参照。[公式ドキュメント](https://docs.python.org/ja/3/library/re.html#regular-expression-objects)
■　```match()```
文字列の先頭がパターンに一致するかチェックする。一致する文字がなければ```None```を返す。
■　```search()```
対象文字列の中すべてに対して、パターンに一致するかチェックする。一致する文字がなければ```None```を返す。

また、パターンに一致する全ての文字列を取得したい場合は、```findall()```を使用する。
これは、マッチオブジェクトではなく、一致した文字列の***リストが返される***ことに注意。

# 実装
例として、```name```に英字以外が含まれていないかチェックする場合、以下のように書いてみた。

```python
def validate_name(self, name):
    pattern = re.compile("[a-zA-Z]")
    
    if len(name) != len(re.findall(pattern, name)):
        print("名前に英字以外が含まれています。")
```
DockerがErrorで起動しない(Ports are not available: listen ～An attempt was made to access a socket in a way forbidden by its access permissions.)

# 症状

以前から、Dockerを使用していました。
久しぶりに使ったら、
"Error response from daemon: Ports are not available: listen tcp 0.0.0.0:3306: bind: An attempt was made to access a socket in a way forbidden by its access permissions."
エラーで使用できません。


環境は、windows(WSL2) + Docker Desktop

エラーが出る原因は複数あるようなので、それに合う解決策を行う必要があります。
参考のため、私が調査したことも解決策を記載しておきます。


# 原因調査

エラーによると、portが他で使用されているようです。

## 該当ポートを使っているアプリを確認

ターミナル(PowerShell)でポートの使用状況を調べる。

netstatコマンドでポートを使うプロセスを一覧表示し、それを今回はSelect-Stringで3306ポートで絞って表示する。

```powershell
netstat -ano | Select-String ":3306"
```

今回は違ったが、プロセスがある場合は下の画像のように表示されるのでコマンドやタスクマネージャーで終了させれば良い。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90529/630d313d-8278-d52b-6e53-fef4a6f32034.png)


```powershell:終了コマンド例
taskkill /F /PID 20344
```

## windowsを再起動してみる

たまに、アプリがポートを解放せずに終了することがあるようなので、windowsを再起動。
私の場合は改善しなかった。

## ファイアウォールを確認

Dockerで使用するport番号を変えてためしても同様のエラーが出た。
もしかして、docker全体がネットワークを使えないのではと考えた。

サードパーティーのファイアウォールを使っている場合は、ブロックする場合がある。
windows純正のファイアウォールで、"すべての通信をブロック" or "意図的にブロック"を行わない場合は、wslは通信許可されているようです。

# 解決方法

今回は、現在のバージョンのDockerのバグ(?)を踏んだようです。

該当issue
https://github.com/docker/for-win/issues/3171#issuecomment-739740248

windowsのNATドライバーを再起動することで解決しました。

管理者権限でpowershellを開き

```powershell:NAT再起動 (管理者権限で起動したPowerShel)
Restart-Service -Name winnat
```
( @fattonton1さんコメントの方が便利なので変更しました。ありがとうございます。)

これで、もう一度Dockerを立ち上げると解消されました。


# 症状が頻発する方は

@oedktyさんコメントで、"該当ポートを除外する"ことで問題を発生させない記事を教えて頂きました。

原因の究明記事↓

https://www.kaoriya.net/blog/2019/11/02/

簡単にポートを除外する方法の記事↓

https://qiita.com/phjg81/items/360a9e569179939f7878

記事では、"ポートを除外することはセキュリティ上、よろしくない"とありますが、
開発中に症状が頻発する方は、参考になると思います。


以上です。
error Command "dev" not found.

# 事象 : Nuxt.jsのプロジェクトを起動しようとしたら「devがみつからない」といわれた


```bash
$ yarn dev
yarn run v1.22.15
error Command "dev" not found.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
```

## 原因 : package.jsonに定義がないから
>
これらのコマンドは package.json に記述する必要があります:
>
```json
"scripts": {
  "dev": "nuxt",
  "build": "nuxt build",
  "start": "nuxt start",
  "generate": "nuxt generate"
}
```
次に yarn <command> または npm run <command> を介してコマンドを起動できます（例: yarn dev / npm run dev）。
[Nuxt - コマンドと開発](https://nuxtjs.org/ja/docs/get-started/commands/)
>

なるほど、確かに自分のpackage.jsonに定義がない

```json
{
  ; ...省略...
  "private": true,
  "scripts": {
    "build": "nuxt build",
    "start": "nuxt start",
    "generate": "nuxt generate",
  },
  "dependencies": {
  ; ...省略...
```

### 対応 : package.jsonに定義を追加する
```json
  ; ...省略...
  "scripts": {
    "dev": "nuxt",
  ; ...省略...
```

```bash:動いた！
$ yarn dev
yarn run v1.22.15
$ nuxt

 WARN  sass-loader@12.4.0 is installed but ^10.1.1 is expected                                                                                       06:26:04


   ╭───────────────────────────────────────╮
   │                                       │
   │   Nuxt @ v2.15.8                      │
   │                                       │
```
【Git】本当によく使う基本コマンド

##　はじめに
Gitのよく使う基本的なコマンドについて自分の備忘録兼ねて整理しました。
開発を行う上でも必須のコマンドばかりです。

### ローカルリポジトリの新規作成
.gitディレクトリを新規作成します。

```
git init
```

### リモートリポジトリをクローンする。

```
git clone リポジトリ名
```
### リモートリポジトリを登録する。
※originはリモート名。originという名前でリモートリポジトリを登録する。

```
git remote add origin URL
```

### 変更をステージする

```
//sample.htmlをステージする。
git add sample.html
//ワークツリーの変更分をすべてステージする。
git add .
```
### 変更を記録する（コミットする。）
ステージにあるファイルを記録します。

```
git commit
//コメント付きで記録する。
git commit -m "メッセージ"
//差分を確認する。
git commit -v 
```
### 現在の変更状況を確認する。

```
git status
```

### 変更差分を確認する。
※「git diff ファイル名」で特定のファイル名のみの指定も可能。

```
//ステージとワークツリーの比較
git diff
//ステージとリポジトリの比較
git diff --staged
```
### 変更履歴を確認する。

```
git log
//１行で表示する。
git log --oneline
//ファイルの変更差分を表示する。
git log -p index.html
//表示するコミット数を指定する。
git log -n 数字
```
### push（リモートリポジトリに送信）する。
originはリモート名
masterは送信するブランチ名

```
git push origin mater
```

###　コマンドにエイリアスを付ける
以下は「commit」に「co」というエイリアスを付けている。
以降、コミット時に「git co -m "エイリアスを付けました。"」のように省略して書くことができる。
また、「git config --list」で設定内容を確認することができる。

```
git config --global alias.co commit
```
expoでAndroid KeyStoreの生成に失敗した話

expoでandroid用のビルド申請をしようとしたところこんなエラーが…

```
Failed to generate Android Keystore, it will be generated on Expo servers during the build
keytool exited with non-zero code: 1
```
でも、よく見てみると…

```
The operation couldn’t be completed. Unable to locate a Java Runtime.
Please visit http://www.java.com for information on installing Java.
```
こんなことが書かれている。

お分かりいただけたでしょうか？
私のパソコンにJavaが入っていないだけでした。

てきとーにインストールしてみましたところうまくいきました！
https://java.com/ja/download/



対戦あざした。
Elementor Proでテンプレート挿入をするとinternal server errorになる場合の対処法

- Elementorのテンプレートを記事に挿入する際にinternal server errorになった

- エラーログは以下の通り


```

PHP: showing 5 of 5
PHP: 2021-11-28 16:08:57 [notice X 9][/home/xs886635/xs886635.xsrv.jp/public_html/develop/wp-content/plugins/elementor/core/common/modules/ajax/module.php::171] Undefined index: data [array (
  'trace' => '
#0: Elementor\Core\Logger\Manager -> shutdown()
',
)] 
```

##試したこと
- phpメモリ確認
    - 1GBと余裕あり
    - phpメモリ関連ならmemory limit errorが出力される
- 不要プラグインの停止
    - 機能拡張系プラグインを停止
        - 効果なし
- PHPバージョン変更（7.4→8.0）
    - 効果なし
- Elementorの再インストール
    - 効果なし
 
##解決法

同様のエラーで悩んでいる人が海外コミュニティーサイトで多く、
その中でElementorサポートから返答があったという以下の対応を行なったところ、無事解消した。

- アカウントの再アクティベート
    - ライセンス同期を一度無効にし、再度有効化（License Settings）

ライセンス認証が失敗していたのだと思う。
ただ根本解決にはなっていないので、hotfixなどの対応があるまでは、都度これで凌ぐのが良さそう

参考：
https://posimyth.ticksy.com/ticket/2248079/
https://www.pixelwars.org/forums/topic/cant-edit-with-elementor/
https://easymanual.site/elementor-500errer/
備忘録：Linuxコマンド ＆ ショートカット等

# はじめに
よく使うけ、ど忘れしてしまうLinux周りのコマンド集です。
※随時更新予定

# grepコマンドオプション
-e：複数指定
-E：拡張正規表現
-v：指定した以外を検索
-r：ディレクトリの中も検索
-i：大文字小文字を区別しない
-o：指定した文字のみ取り出し
-B：検索でヒットした前の行を出力 ex: grep test -B 10 test.txt
-A：後の行
-C：前後の
-c：検索でヒットした行数
-n：行番号を付け出力
-w：単語の完全一致検索
-l：ファイルのリストを出力
## gz形式などで圧縮されたファイルをgrepしたい場合
- zをgrepの先頭につけて実行します。
```
zgrep
```

# mkdir
-p 親ディレクトリも作成
-m パーミッション指定して作成

# awk
-F：区切り文字を指定
```
# 三項演算子 （条件 ? 条件が正の場合の値：条件が偽の場合の値）
$ seq 10 | awk '{print $1%2 ? "奇数":"偶数"}'
```
### 組み込み変数
- NR：処理中の行数を取得する
```bash

```
# sed
- 文字の置換する場合に使用
- -E：拡張正規表現（-rでも同じ使い方ができる）
```
# 特定の文字を入れ替える
$ echo teet | sed 's/ee/es/'
test

# 末尾にgを付けて、一致する全ての文字を置換
$ echo teet | sed 's/e/s/g'
tsst

# &で検索対象の文字を格納
$ echo test | sed 's/test/&&/'
testtest

# \1,\2,\数字で（）で指定した文字を参照する
echo test | sed -E 's/(te)(st)/\2\1/'
stte

# 末尾にpで前に指定した一致する行を出力する。
# -nオプションで各行を出力させない
$ sed -n '/\.txt$/p'

```
# xargs
- コマンドに引数を渡すときに使用
```
# 後ろにコマンドを指定しないとechoを実行する
$ seq 10 | xargs
1 2 3 4 5 6 7 8 9 10

# -n数字オプションで指定した数ずつコマンドに渡す
$ seq 10 | xargs -n5
1 2 3 4 5
6 7 8 9 10

# -I@ @にxargsが受け取ったものを1つずつ格納できる（複数のファイルを作成するときなどに便利）
$ seq 10 | xargs -I@ mkdir dir_@
$ ls
dir_1  dir_10  dir_2  dir_3  dir_4  dir_5  dir_6  dir_7  dir_8  dir_9

# -P数字で並列処理を行う
# PCのcpuが分からなければnprocで調べられる。
$ seq 10 | xargs -P2 -I@ mkdir dir_@
$ seq 10 | xargs -P$(nproc) -I@ mkdir dir_@

```
# cp
cp コピー元 コピー先
-i 上書きの場合、可否を確認
-r（R） ディレクトの中身ごとコピー
-p コピー元の日時を継承

```
ファイルのバックアップを取るときに下記の書き方をすればファイル名を追記せずにスマートにバックアップが取れる。
cp test.conf{,.202112bk}
```

# mv
mv 移動したいfiledir 移動先dir
mv 名前を変更したいfiledir 変更したい名前filedir
mv file file file dir/.
┗複数のファイルを移動
-f 移動先に同名ファイルがあれば強制的に移動
-i 確認

# rm
-r(R) ディレクトリを削除
-f 確認なしで削除

# su
ハイフン 環境変数を引き継かず、ユーザーのホームディレクトリに移る
-c "" ""内のコマンドを実行

# ssh-keygen
-t 暗号方式指定 デフォルトはrsa
-b ビット数を指定
-y OpenSSH形式の秘密鍵ファイルを読み出し、OpenSSH形式の公開鍵を標準出力に出力する
-f ファイルを指定

# read
ユーザーからの入力値を受け取り、変数に格納してそれを次の処理で使用したい場合に使用
-p コメント入力

# yumとrpmコマンド
インストールしたソフトウェアの一覧
yum list installed

yumリポジトリにソフトウェアがあるか確認
yum info

rpmパッケージ削除
rpm -evh soft

rpmパッケージの保存
wget xxxxx.rpm

rpmパッケージのインストール
rpm -ivh xxxx.rpm

インストールされているrpmパッケージを一覧表示
rpm -qa

パッケージからインストールされたファイルを一覧表示
rpm -ql

# ポートの確認
netstat -tnlp

# ssh接続コマンド
ssh -i passwd namae@domein

# ターミナルショートカット
shift + ctl + PgDn 1画面移動

# 正規表現
```
. 任意の1文字
+ 直前の文字の１回以上の繰り返し
* 直前の文字の０回以上の繰り返し
? 直前の文字が0か1か
^ 先頭
$ 後方
\ 正規表現ではないことを指定
[] 中の文字のどれか1文字
```

# ヒアドキュメント
```
cat >> test.txt << EOF
aa
aa
aa
EOF
```
上記の書き方でファイルに追記することができる。シェルスクリプト作成時に便利

# シェル関連
## クオートの違い
''は中の変数をただの文字列として認識
""は中の変数を変数として認識

# seq
```
-fオプションで数字を入れて出力ができる
%g(整数)
%f(小数)

seq -f 'echo %g個; sleep 1' 10 | bash
```

# IFS
区切り文字を指定することができる
IFS=,

# tee
標準入力から受け取った内容を、標準出力とファイルに書き出すコマンド
# VIM小技
## 複数の行末に文字の挿入
- 短形選択後に＄A
[ASP.NET Core] Razor構文のコメント文の違い

本題
--
ASP.NET Coreで作成するページはRazor構文で書かれ、コメントの書き方が2種類ある。

`<!-- -->`で括る方法と `@* *@`で括る方法だ。

```
<!-- コメント１ -->
```

```
@* コメント２ *@
```

どちらも実動作上は存在しないものとして解釈されるが、解釈されるタイミングが違う。
上記コメント１のほうは**ブラウザで解釈される**一方、
コメント２のほうはASP.NET Coreの**コンパイラーで解釈される**。
#
したがって前者はコンパイル後のHTMLに残り、後者はHTMLに残らない。
以下のようなソースコードをコンパイルして実行すると、

```Index.cshtml
<!-- とても愛想の良い表情を浮かべながら -->
<h2>太郎さんってモテそうですよね！</h2>
@* （嘘。絶対にない。生理的に無理。） *@
```

以下のようなHTMLコードが出力される。

``` Index.html
<!-- とても愛想の良い表情を浮かべながら -->
<h2>太郎さんってモテそうですよね！</h2>
```

したがって、`<!-- -->`で書いたコメントはブラウザのソースコードを表示する機能でばっちり見られる。
隠しておきたい本音とか、陰口とか、設計仕様などは `@* *@`でしたためるのがいいだろう。
スクリプト部分への適用
--

あと、`@* *@`のほうは.cshtmlファイル上のスクリプトにも有効。

``` MyScript.cshtml
<script>
  // これはブラウザに表示される
  @* これはブラウザに表示されない *@
  alert("生理的に無理！！！");
</script>
```
ショートカットキーについて
--
ちなみにVisual Studioのショートカットキーで、
 `Ctrl + k`,`Ctrl + c`と打つと現在の行または選択箇所がコメントアウトされるが、
.cshtmlの場合 `<!-- -->`になったり`@* *@`になったりする。

`@* *@`のコメントとそれ以外のものをまとめて範囲選択してショートカットキーでコメントアウトすると前者のコメントになり、それ以外の選択範囲だと後者のコメントになる
・・・ことが多い。詳しい条件は知らない（検証もしていない（する気もない））。
Rook/Ceph の mon を削除する方法

# 経緯

* 3 zone にワーカノードが配置された K8s クラスタがある。
* Rook/Ceph クラスタが動いている。
* mon の動作している zone に偏りがあるので、散らしたい。
* 当該 mon の Deployment を削除した。
* 削除した zone に同じ mon が登場する。移動してくれない。


確認をしたのは AKS だが、ブロックストレージが zone を超えられない環境なら同様の状況に陥ると思う。

# 結論

`kubectl delete deploy` の直後に mon が使っている PVC に対し `kubectl delete pvc` も行う。

# 理由(たぶん)

ソースコードは追っていないが、挙動から察する。
rook-ceph-operator は、PVC が残っていると、それを使って復旧を試みるらしい。
PVC がなければ、CephCluster CR にある affinity やらを参考にしてデプロイを行う。たぶん。

# 注意

mon を一気に全削除するとクラスタが死ぬリスクあり。
1 つ mon を消す毎に operator の reconcile が完了するのを待つ、くらいの用心さで良いかもしれない。
AWS でサブドメインを別アカウントに移行する際ハマったこと

セキュリティの考慮があって、もともと構築できていた STG 環境を別の AWS アカウントを作成しそちらに移行した際、いくつハマったことがあったので共有します。

## そもそもサブドメインを別の AWS アカウントに移譲する方法
こちらの記事を参考して移行できました。

[[Route 53] 別のAWSアカウントでサブドメインを使えるように権限移譲する](https://dev.classmethod.jp/articles/route53-transfer-hostedzones-2021/)

## 複数ドメインがある場合の命名方法
たとえ下記の３つのドメインがあるとします。

- stg.test.com：エンドユーザ用のドメイン
- stg-admin.test.com：管理者用のドメイン
- stg-api.test.com：APIのエンドポイント

今回移行するまで、上記でも困ってなかったが、今回の移行で下記の不便に気づきました。

- このやり方ですと３つのサブドメインを上記記事のように移譲する必要があります。
- ACM で証明書を管理する場合は、３つのドメインを全部明記して作成しないといけません。

よって、上記のやり方をやめて、更にぶら下げて全部１つのサブドメインにしました。

- stg.test.com：エンドユーザ用のドメイン
- admin.stg.test.com：管理者用のドメイン
- api.stg.test.com：APIのエンドポイント

こうしておけば、アカウント間の移行も１つのドメインで済みますし、ACM での証明書もワイルドドメインで１つで管理できるので、管理しやすいです。

## グローバルでユニーク値を持っているリソース
ほとんどのリソースはアカウント配下に属していますが、いくつの種類のリソースはグローバルでユニークの値である必要があります。

1. S3 のバケット名：全世界でユニークの名前でなければならないので、もとの環境から削除する必要がある
1. CloudFront に設定されている cname もドメイン関連しているので、もとの環境 CloudFront を削除しておく必要がある

## その他
移行とは関係ないが、AWS Secrets Manager に作成したものは、削除しても 7 日間の復旧期間が設けられているため、削除直後に同じ名前を再度作成できません。

ただしに削除したい場合、公式ドキュメント通りに、`aws secretsmanager delete-secret --force-delete-without-recovery` で削除できます。

[同じ名前の新しいシークレットを作成するために、Secrets Manager のシークレットを直ちに削除する方法を教えてください。](https://aws.amazon.com/jp/premiumsupport/knowledge-center/delete-secrets-manager-secret/)

```shell
aws secretsmanager delete-secret --secret-id your-secret --force-delete-without-recovery --region your-region
```

以上
varchar vs varchar2 in Oracle

oracleでは、基本varchar = varchar2 
ただ、varchar2の場合、桁数=Size
と先輩が行ってくれた 最初に？え。。そうなの。。？ずっと理解できなかったけど。
あ、桁数＝size -> NVARCHAR2
あ。。。とにかく調査してみたので整理しましょう

# nvarchar2 ★★日本語も巻き込まれたら★★これ使いましょう
- 桁数＝Size　
- varchar2 の全角の場合3バイトだっけ？それをもうする必要がない！
- 4000Bytes 可変長Unicode文字列 Variable-length Unicode character 
- size 指定が必要
- 最大のsizeは、各国語文字セット定義によって決定されます。

# varchar2 
- 4000Bytes の最大長さを持つ文字の可変長の文字列
- 4000Byteまで保存できる
- nullの場合は任意のスペースを占有しない

# varchar
- 可変長の文字列
- 最初の2つのバイト＝文字列の長さ
- 残りバイト＝文字列
- 2000Byteまで保存できる
- nullの場合、スペースを占有


### refer
ORACLE JP 19c
https://docs.oracle.com/cd/F19136_01/sqlrf/Data-Types.html#GUID-7B72E154-677A-4342-A1EA-C74C1EA928E6
ORACLE EN 19c
https://ora14.informatik.haw-hamburg.de/sqlrf/Data-Types.html#GUID-A3C0D836-BADB-44E5-A5D4-265BA5968483

https://www.generacodice.com/jp/articolo/340564/oracle%E3%81%A7varchar%E3%81%A8varchar2%E3%81%AE%E9%81%95%E3%81%84%E3%81%AF%E4%BD%95%E3%81%A7%E3%81%99%E3%81%8B%EF%BC%9F
Redash APIの要点、個人的まとめ

## APIキーの種類と取得方法
Redashには以下の2種類のAPIキーが存在する。
### Query API Key
1つのクエリごとに1つのAPIキーが割り当てられている。
**特に理由がなければ、このキーを使う**ことが推奨されている。
処理を作った人が退職したとしても、クエリが残っている限りAPIを叩き続けることができる。
![73d76d2e-b88d-4558-bb65-cb4a7bf7b848-1920x292r.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244893/67a56453-d578-5c32-0c42-f9b98f48c5fa.png)
![a89afb0b-3cc5-4166-bf4f-fec35d933a3a-1920x745r.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244893/fc778bf2-cb1e-78ed-506e-5b705aba3dfe.png)

### User API Key
1ユーザーごとに1つのAPIキーが割り当てられている。
**Refresh APIとか、一部のAPIはこのキーじゃないと叩けない**。
![0ce7bde5-ab62-4166-8baf-ade5de3a2b06-1920x384r.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244893/5186c85e-3632-61ed-48cd-3d796e7c6a18.png)
![e98e21da-b2cd-44f5-aeef-8c23cc5b89bd-1920x599r.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244893/54ff17ec-b79b-f141-2d9b-200c4876d18c.png)
![6413ab0c-7f5b-4335-8d8f-5f56237973ee-1920x862r.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244893/57aad45d-5bee-d884-b58d-8ec47c413a98.png)


## よく使いそうなクエリ
#### 特定のクエリの、最新の実行結果を取得
Redashに直近の実行結果がキャッシュされているので、その値を取得。
このAPIを叩くタイミングでクエリが走る訳ではない点に注意。

```
(GET) https://{YOUR_REDASH_HOST}/api/queries/{QUERY_ID}/results.json?api_key={ANY_API_KEY}
```

#### 特定のクエリを実行して、結果を最新にする(Refresh API)
```
(POST) http://{YOUR_REDASH_HOST}/api/queries/{QUERY_ID}/refresh?api_key={USER_API_KEY}
```

クエリ中にパラメーターがある場合、`p_{パラメーター名}={値}`の形でセットする

```
...?api_key={USER_API_KEY}&p_user_id=12345&p_limit=10
```

## 参考
https://redash.io/help/user-guide/integrations-and-api/api
https://qiita.com/meteoride/items/d6c11e2a96537bbb9dc3
Slackに日本語絵文字を大量に一括登録する方法

# はじめに

Slackのカスタム絵文字は便利ですよね。
日本語の文字絵文字があると、リアクションのバリエーションが増えて、簡単に気持ちを表現できるようになるのが良いですよね。

新しいSlackワークスペースを立ち上げたときに、カスタム絵文字を一括に登録できる方法があるといいのに、と思って探していました。
一発で登録できる最高なライブラリを見つけたので、ご紹介します。

# おすすめライブラリ: decomoji

ちょうどこんなカスタム絵文字を探していたんです。
![decomoji v5](https://github.com/decomoji/decomoji/raw/master/docs/images/ss_basic.png)

【良いところ】

* 日本語を絵文字にしているので使いやすい
* まとまった量がある
* 一括登録するツールが用意されている（エンジニア向け）
* 検索するサイトが用意されている
* メンテナンスされている（2021年8月時点）

decomojiの登録方法は、 [decomoji (おすすめ)](#decomoji-おすすめ) の章を見てください。

# 詳説: Slackにカスタム絵文字を登録する方法

Slackにカスタム絵文字を登録するには、いくつかの方法があります。

## 1つ1つ登録する

Slackに用意されている、カスタム絵文字を登録する画面を利用する方法です。
画像を1つ1つアップロードして、名前（＝ `:` と `:` でサンドイッチした文字列）を入力していきます。

https://ワークスペースのサブドメイン.slack.com/customize/emoji

好きな画像を登録できるのがメリットですが、たくさんの画像を登録するのには向いていません。

| 画像 | 手間 |
|-|-|
| ⭕️ 好きな画像が登録できる | ❌️ 手間がかかる |

## 絵文字パックを使う

Slackにはデフォルトで用意されている絵文字パックを追加することができます。
しかし、選択肢が少なくて残念な気持ちになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84173/2f144175-8475-ec12-3428-f245cd796c62.png)

| 画像 | 手間 |
|-|-|
| ❌️ 予め提供されているもので少ない | ⭕️ 楽ちん |

## Bulk Emoji Uploaderを使う

Google Chromeの拡張機能 [Neutral Face Emoji Tools](https://chrome.google.com/webstore/detail/neutral-face-emoji-tools/anchoacphlfbdomdlomnbbfhcmcdmjej) を使って一気にアップロードする方法です。

たくさんの画像を登録することができますが、画像自体は自分で用意する必要があります。

| 画像 | 手間 |
|-|-|
| ⭕️ 好きな画像が登録できる | ⭕️ 楽ちん |

## ツールを使う

### decomoji (おすすめ)

https://github.com/decomoji/decomoji

文字絵文字を、このプロジェクトでは「デコモジ」と言っています。
基本セットでも300個の絵文字がありますが、拡張パックを使うと25000個も登録されます。

これ、使うの？
どういうシーンで使うの？
何で思いついたの？

みたいなデコモジもあります。

| 画像 | 手間 |
|-|-|
| ⭕️ 文字絵文字が大量に用意されている | ⭕️ 割と楽な方 |

#### 適切な絵文字を探す方法

一覧で見れるサイトが用意されています。
さすがです。

https://finder.decomoji.dev/

#### インストール方法

ターミナルからコマンドを入力する必要があります。
`git` `node` `npm` がインストールされていると動きます。

```terminal
$ git clone git@github.com:decomoji/decomoji.git
$ cd decomoji
$ npm ci
$ node scripts/manager
```

詳細は、 [README.md](https://github.com/decomoji/decomoji#readme) に詳しく書いてあります。

### 番外編: emojipacks (メンテされてない）

https://github.com/lambtron/emojipacks

海外系の絵文字を中心に用意されていますが、サイトも止まってますし、悲しい感じです。

| 画像 | 手間 |
|-|-|
| ⭕️ 予め提供されているものもある<br>　 ＆好きな画像が登録できる | ❌️ 技術力が必要 |

#### インストール方法

```terminal
$ npm i -g emojipacks
$ emojipacks
Slack subdomain: workspace-subdomain
Email address login: your@mail.address
Password: *********
2FA Code: 123456  #  if 2FA is enabled
Path or URL of Emoji yaml file: https://raw.githubusercontent.com/lambtron/emojipacks/master/packs/slackmojis-facebook-reaction.yaml

$ npm rm -g emojipacks
```

すてきなSlackカスタム絵文字ライフをお過ごしください！
アルバイトのシフト自動作成 by PuLP

#1.はじめに

##１．１　背景
シフトはアルバイトリーダーや担当者が作成するのですが、シフト作成が遅れて予定が組めなかったりヒューマンエラーで作成ミスがあったりと面倒が多いです。シフトの希望を出したら自動で作成してくれるアプリがあったらなあと思いました。

シフト作成を調べても早番、遅番やシフト1、シフト2、シフト３・・・のように決められたシフト作成が多く汎用性がないです。大体1時間ごとで区切ってシフトを作成することが多いと思われます。例としては以下の通りです。


<img width="500" alt="paragraph_1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/931305/37a8f42c-d35e-3941-db73-0f609a73a0df.png">

となるとただプログラムを書くのは厳しそうです。

##１．２　今回のゴール
アプリケーションとして実装するのは時間がかかるのでJupyterで実装できる程度には仕上げます。以下の内容を動かせるように設計します。

①シフト希望の行列を入力する
②pulpで線形計画問題に持ち込む
③シフト一覧を出力する
MobX(ver6)のデコレーターが動かない。

reactのstate管理はreduxを使っていたのですが、新しい案件で気になっていたmobxを使ってみました。

https://mobx.js.org/README.html

日本語の情報ではデコレーターと呼ばれる`@observable`のような記法を使っている方が多く、それで試してみたら全く動きません。[babelならplubinを追加、typescriptのみならtsconfig.jsonに設定](https://mobx.js.org/enabling-decorators.html#typescript)をしないと動かないというのはみましたが、それをしても動きません。

どうやらver6からただデコレーター書いただけでは動かなくなったようです。

https://mobx.js.org/enabling-decorators.html
こちらに説明があります。

* デコレーター記法はESの標準化がなかなか進まず、実装が変わりそうなので互換性のためにver6では使わずに、代わりに`makeObservable / makeAutoObservable`を使いましょう。
* ただし、デコレーターとして使えるものは`makeObservable`のアノテーションとして残しました。

と言うことです。つまりコンストラクタで`makeObservable`を呼ぶ必要があると言うことです。

```js
import { makeObservable, observable, computed, action } from "mobx"

class Todo {
    id = Math.random()
    @observable title = ""
    @observable finished = false

    constructor() {
        makeObservable(this)
    }

    @action
    toggle() {
        this.finished = !finished
    }
}

class TodoList {
    @observable todos = []

    @computed
    get unfinishedTodoCount() {
        return this.todos.filter(todo => !todo.finished).length
    }

    constructor() {
        makeObservable(this)
    }
}
```

[本家のドキュメント](https://mobx.js.org/getting-started)見るとアノテーションすら使ってないんですよね。一応アノテーションは今後もサポートする「つもり」(We intend to continue to support decorators in this form)と書いてあるので大丈夫そうですけど、ドキュメントに習って使うのやめようかな〜。
Prime Videoのウォッチリストを空にする


- [ウォッチリスト](https://www.amazon.co.jp/gp/video/mystuff/watchlist)をブラウザで開く
- 開発者コンソールでこれを実行する

```
for(let i = 0;i<400;i++){
    document.getElementsByClassName('Gpyvwj _2Gk3g8')[i].click()
}
```
Pythonで監視対象のスクショを撮影して監視する

# こんな画像を自動で撮る
- 画像証跡は日本のSEの基本

![20211210_142034_0_shuumai.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/354194/447f098d-dda9-d273-7317-eac77690c9a6.png)

## 環境構築
- Seleniumを環境に合わせて構築する
- OCI無料枠でやる場合Oracle Linuxはゴミだったのでオススメしない

## コード

```python
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import time
from io import BytesIO
from datetime import datetime
import functools
from PIL import Image
import sys

# speedy log
print = functools.partial(print, flush=True)


def fanSarvice(accountName):
    # file name
    now = datetime.now()
    nowDate = now.strftime('%Y%m%d_%H%M%S')
    # selenium parametor
    options = Options()
    options.add_argument('--headless')
    options.add_argument('--window-size=1080,1920')
    # 環境に合わせてchromedriverとchrome.exeの位置を調整する
    # Linux/Mac
    # options.binary_location = '/usr/bin/google-chrome'
    # driver = webdriver.Chrome('chromedriver', options=options)
    # Windows
    options.binary_location = "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe"
    driver = webdriver.Chrome(
        options=options, executable_path="C:\\dev\\chromedriver.exe")
    # profile
    profile = f'https://twitter.com/{accountName}'
    # popular reply
    searchMore = f'https://twitter.com/search?q=to%3A{accountName}&src=typed_query'
    # recent reply
    recentSearch = f'https://twitter.com/search?q=to%3A{accountName}&src=typed_query&f=live'
    # image
    withImagesTweet = f'https://twitter.com/search?q=from%3A{accountName}%20filter%3Aimages&src=typed_query&f=live'
    getSereenShotList = [profile, searchMore, recentSearch, withImagesTweet]
    print(f'list is {getSereenShotList}')

    # main
    for i, j in enumerate(getSereenShotList):
        print(i, j)
        driver.get(j)
        time.sleep(10)
        im = Image.open(BytesIO(driver.get_screenshot_as_png()))
        crpim = im.crop((120, 0, 740, 1920))
        crpim.save(f'{nowDate}_{i}_{accountName}.png', quality=95)

    driver.quit()


if __name__ == "__main__":
    accountName = sys.argv[1]
    fanSarvice(accountName)

```

## 実行

```bash
python fanScreenShot.py shuumai 
```

## 今後
- サンプルのURLは悪意が強めなので、悪意を弱めたり、無くしたり、さらに強めたり、はたまたTwitter以外にしたてもっと縦長にしてたくさん撮る等の応用ができる
- 悪以外ではUIテスト等業務でも色々使いまわせる
GitホスティングサービスをGitHubに移行したお話

株式会社運動通信社でiOSエンジニアを務めております植田です。
現在、弊社では複数のGitホスティングサービスを利用している状況なのですが、
GitHubにまとめていきたく、他のGitホスティングサービスで管理しているリポジトリをGitHubに移行してみたので手順を残します。

## 移行の動機
* サービスによって複数のGitホスティングサービスを利用しているので統一したい！
* GitHub Actionsを使ってCI/CD環境を整えたい！

## 手順
### 移行前作業
 * 移行計画を各エンジニアに周知する。
     * 移行開始時に作業中のローカルブランチが無いよう注意。
 * 移行元のリモートブランチを断捨離しておくと移行後のリポジトリがスッキリします。

### 移行作業
#### 1. 移行元リポジトリのURLをコピー

#### 2. GitHub上で `Import repository` を選択

![select_import_repository.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/717966/1dd21406-fe3f-8161-15c0-081bcea6fa39.png)


#### 3. リポジトリ情報を記入のうえ、 `Begin import` 

![setting_import_repository.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/717966/385e64f6-4451-84b1-a122-2c698130347c.png)

#### 4. 移行元Gitへの閲覧権限を求められるので、アカウント情報を入力し、 `submit` 

![Github移行手順4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/717966/b5a0eb25-6269-d3da-b7bf-af434891940f.png)


#### 5. リポジトリのimport処理が行われます。

![preparing_repository.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/717966/99959aef-856d-05b5-99a8-cec0f6f0c497.png)

* ページ自体閉じても大丈夫です。

#### 6. 終了メールを確認

|![finisih_import_repository.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/717966/6bc51af7-b1c6-896d-0650-fd77f3555962.png)|
|:-:|

* GitHubアカウントに登録したメールアドレスに通知が来ます。
* ブランチ数150件程度のリポジトリ移行で25分程度かかりました。

### 移行後作業
* 移行元で `clone` して作成していたローカルファイルを退避。
* GitHubに新規作成したリポジトリから `clone` を行う。
*  `push` , `pull request` 等の動作確認を実施。

## 最後に
GitHubの `Import repository` を初めて使いましたが、リモートブランチなどのデータを丸ごと移行できる神機能でした。
 `commit` 、`push` のログも移行してくれるので過去分のコントリビューションを緑地化してくれます。

![2021_github_green.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/717966/dbe3e4be-ee5b-eb76-02b5-609a05d4092c.png)

機会は限られるとは思いますが、便利な機能なのでぜひ使ってみてください。
Node.js + TypeScript からC++のライブラリを呼び出す

# 目的
- Node.jsからC++のライブラリをコールしたい
- node-gypを使えばできるっぽいが、どのサンプルも動かない・・・（当方intel Mac / Big Sur）
- v8のAPIが色々変更してるっぽい。最新環境で動作確認できるサンプルが欲しい

# 成果物
とりあえず作ってみたサンプル一式は以下です。
https://github.com/swmokyun/sample-node-gyp

# 環境
- intel Mac
- macOS Big Sur (11.6)
- Node.js 14

# Cまわりのセットアップ
以下を参考にCをビルドできる環境を作っておく
https://github.com/nodejs/node-gyp#installation

# nodeまわりのセットアップ
- Node.js 14 を動作できるようにする。自分はnodebrewを使って切り替えています。
- 以下をyarnで追加
 
　"@types/node": "^16.11.12",
　"node-gyp": "^8.4.1",
　"ts-node-dev": "^1.1.8",
　"typescript": "^4.5.3"

# Cのサンプルコードとgypの設定を用意
```js:binding.gyp
{
    "targets": [
        {
            "target_name": "native_ext",
            "sources": ["native_ext.cc"]
        }
    ]
}
```

```c:native_ext.cc
#include <node/v8.h> // 自分の環境だとこのパスじゃないと動かなかった
#include <node/node.h>

using namespace node;
using namespace v8;

void Method(const v8::FunctionCallbackInfo<v8::Value> &args)
{
    v8::Isolate *isolate = args.GetIsolate();
    v8::HandleScope scope(isolate);
    v8::Local<v8::String> result;
    v8::MaybeLocal<v8::String> temp = String::NewFromUtf8(isolate, "Hello World");
    temp.ToLocal(&result);
    args.GetReturnValue().Set(result);
}

void Method2(const v8::FunctionCallbackInfo<v8::Value> &args)
{
    if (args.Length() != 2)
    {
        args.GetReturnValue().Set(-1);
        return;
    }

    v8::Isolate *isolate = args.GetIsolate();
    v8::HandleScope scope(isolate);
    v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();

    double p1 = args[0]->NumberValue(context).FromJust();
    double p2 = args[1]->NumberValue(context).FromJust();
    args.GetReturnValue().Set(p1 + p2);
}

void init(v8::Local<v8::Object> target)
{
    NODE_SET_METHOD(target, "hello", Method);
    NODE_SET_METHOD(target, "add", Method2);
}

NODE_MODULE(binding, init);
```

# ビルド

```
npx node-gyp configure
npx node-gyp build
```
これで build/Release/native_ext.node　が作成される

# 呼び出し側
上記で作成したnative_ext.nodeを呼び出す

```js:test.ts
var addon = require("./build/Release/native_ext.node")

const ret: string = addon.hello()
console.log(ret) // Hello World!

const ret2_1: number = addon.add()
console.log(ret2_1) // -1

const ret2_2: number = addon.add(1.1, 1.2)
console.log(ret2_2) // 2.3
```

# 実行
```
$ npx ts-node-dev test.ts 
[INFO] 10:57:24 ts-node-dev ver. 1.1.8 (using ts-node ver. 9.1.1, typescript ver. 4.5.3)
Hello World
-1
2.3
```
おおおお、動きました。

# 補足
以下のようなエラーがでたらNode.jsのバージョンが合っていない。
おとなしくnodebrewなどでNode.jsのバージョンを切り替える。
Node.jsのバージョン一覧はこちら https://nodejs.org/ja/download/releases/

```
[ERROR] 11:21:01 Error: The module '/xxx/xxx/sample-node-gyp/src/build/Release/native_ext.node'
was compiled against a different Node.js version using
NODE_MODULE_VERSION 83. This version of Node.js requires
NODE_MODULE_VERSION 93. Please try re-compiling or re-installing
the module (for instance, using `npm rebuild` or `npm install`).
```
Node.js + fastify + TypeScript + SwaggerでRESTサーバを構築する

# 概要
Node.js、fastify、TypeScript、Swaggerで簡単なサンプルを作ってみたので共有します。
サンプルコード: https://github.com/swmokyun/sample-fastify-typescript-swagger

# 目的
- とにかくラクにRESTサーバを作りたい
- pythonでもいいけどフロントエンドでNext.jsとかつかうからNode.jsで言語を統一したい
- TypeScriptで型の恩恵を受けたい
- SwaggerでRESTスキーマまわりのあれこれをラクしたい

# expressよりfastifyがいいらしい
Node.jsでサーバといえばexpressと思ってたけど、最近ではKoa.jsとかfastifyが有力候補らしい。fastifyの方がtypescriptまわりがいい感じにサポートされているっぽいのでこっちをチョイス。

https://www.fastify.io/docs/latest/Getting-Started/

# fastify-swaggerがいい感じ
調べた感じではfastify-swaggerを使うとtypescriptで型補完しながらスキーマ定義が記述できるっぽい。これは素晴らしい。
https://github.com/fastify/fastify-swagger

# typeboxでさらにいい感じ
typeboxを使うとfastifyでスキーマ定義と関数の型を共通化できる。これはさらに素晴らしい。
https://www.fastify.io/docs/latest/TypeScript/#json-schema

# サンプル
公式を参考にGETやqueryのサンプルを追加したのが以下になります。
また、各モジュールのバージョンは以下になっています。fastifyはバージョンがあがると結構APIが変わるっぽいので注意。

    "@sinclair/typebox": "^0.23.1",
    "fastify": "^3.24.1",
    "fastify-swagger": "^4.12.6"

```typescript
import { Static, Type } from "@sinclair/typebox"
import fastify, { FastifyInstance } from "fastify"
import fastifySwagger from "fastify-swagger"

const PORT = 9000

const server: FastifyInstance = fastify({ logger: true })

/**
 * swagger
 */
server.register(fastifySwagger, {
  routePrefix: "/docs",
  swagger: {
    info: {
      title: "Test swagger",
      description: "Testing the Fastify swagger API",
      version: "0.1.0",
    },
  },
  exposeRoute: true,
})

/**
 * test_post
 * https://www.fastify.io/docs/latest/TypeScript/#typebox
 */
const User = Type.Object({
  name: Type.String(),
  mail: Type.Optional(Type.String({ format: "email" })),
})
type UserType = Static<typeof User>

server.post<{ Body: UserType; Reply: UserType }>(
  "/test_post",
  {
    schema: {
      body: User,
      response: {
        200: User,
      },
    },
  },
  (req, rep) => {
    const { body: user } = req
    rep.status(200).send(user)
  }
)

/**
 * test get, querystring
 */
const ErrorResponse = Type.Object({
  msg: Type.String(),
})
type ErrorResponseType = Static<typeof ErrorResponse>

server.get<{ Querystring: UserType; Reply: UserType | ErrorResponseType }>(
  "/test_get",
  {
    schema: {
      querystring: User,
      response: {
        200: User,
        400: ErrorResponse,
      },
    },
  },
  (req, rep) => {
    const { query: user } = req
    if (user.name.length < 3) {
      rep.status(400).send({ msg: "name is too short" })
    } else {
      rep.status(200).send(user)
    }
  }
)

server.listen(PORT)
```

http://localhost:9000/docs　
でSwaggerからAPIの確認やJSONスキーマの出力が可能。とっても便利で開発が捗ります。

![](https://storage.googleapis.com/zenn-user-upload/4044c072366c-20211209.png)
プログラマ職への中途参入について語る

#なにをもって中途参入というか（定義）
他業種・多職種の経験者等、新卒じゃないけどプログラマになりてーよ、な人。
以下に分類される。
・ITぜひやりたい参入（少数。心情的にはこっちしか応援したくない。）
・現実逃避参入（大半がこっち。残念ながら中途参入者の評価を下げている。）

そうは言っても、「ぜひやりたい」人がいざやってみたら全然適性が無くて、
「現実逃避」の人が意外と適性があるなんてことも。

#潜在的な中途参入希望者、相当いる
ステレオタイプ
「あいつらろくに人と話さなくても給料もらってていいな～。私もなりたい」

ITのスクール的なものの広告、今すごいよね。客がいないとこうならないから。

#IT人材が不足しているという現実
しかし中途参入希望者はあまり期待されていない。
見返したる！って気合がないとむずいかもね。
Railsの思想



##COC（Convention over Configuration）
**「設定より規約」**
「設定がほとんどの場合で共通ならば、その設定をアプリケーションのデフォルトにすべきである」という考えに基づいている。

メリット

- 他言語のように多くの設定ファイルを書かなくて良い。
- 共通ルールに則ってエンジニア同士のコミュニケーションがスムーズになる。


####命名ルール
データベースのテーブル名はモデルのクラス名の複数形にする。

```
モデル / クラス |  テーブル / スキーマ
Article	      |  articles
LineItem	  |  line_items
Deer	      |  deers
```


####スキーマのルール
- 外部キー：カラムはテーブル名の```単数形_id```にする必要がある。
(例: ```item_id```、```order_id```)
- 主キー：デフォルトでは```id```という名前の```integer```カラムがテーブルの主キーに使われる(PostgreSQLやMySQLでは```bigint```、SQLiteでは```integer```)


##DRY(Don't Repeat Yourself)
**「同じことを繰り返さない」**

メリット

- 変更があったときに何箇所もコード修正をしなくて済むのでメンテナンス性が高まる。


##REST(Representational State Transfer)
**「すべてのリソースに一意となる識別子（URI）がある。」
「URIを通してリソースを操作する手段を提供する」**という考え方を基盤とする。

```
概念	                             RESTfulなメソッドとURL
記事を投稿する	                    POST /articles
記事(ID=1)にコメントを投稿する	        POST /articles/1/comments
記事(ID=1)を更新する	                PATCH /articles/1
記事(ID=1)のコメント(ID=1)を更新する	PATCH /articles/1/comments/1
記事(ID=1)を削除する	                DELETE /articles/1
ユーザ(ID=1)のパスワードを更新する	   PATCH /users/1/password
```



####RESTの反対はRPC
?の後ろに問い合わせを&でつないで表現する方法。
例：```http://example.com/index.php?action=prefecture_list&amp;id=1```

https://techracho.bpsinc.jp/baba/2020_11_18/15665



##参考

[パーフェクトRuby on Rails【増補改訂版】](https://gihyo.jp/book/2020/978-4-297-11462-6)

https://railsguides.jp/active_record_basics.html#active-record%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8Bcoc-convention-over-configuration

https://techracho.bpsinc.jp/baba/2020_11_18/15665