OmniAICreator/Qiita-1.07M huggingface dataset:
IQ Botのカスタムロジック：数値だけ／英数字だけを取り出す


IQ Botのカスタムロジックで、[シンプルな置換処理](https://qiita.com/IQBotter/items/b1e7a75439fede2171e6)の次くらいによく使うのが、「読み取った値の数値部分だけを取り出す」という処理です。

#数値だけ取り出す処理

他の処理と同様、こちらもフィールド項目の場合とテーブル項目の場合でやりかたが違います。

##フィールド項目の場合
```python:フィールド項目の場合
import re
field_value = re.sub("\\D", "", field_value)
```

`"\\D"`の部分が、正規表現で「数値以外の文字」を表します。
つまり「数値以外の文字が混じっていたら、一律除外してください」という処理です。

なお、上記のコードをIQ Botのカスタムロジックにコピペすると、
バックスラッシュ(\)で表示されている部分が円マーク(&yen;)になると思います。

両者はただのフォントの違いで同じ意味なので、どちらでも問題なく動きます。

##テーブル項目の場合

上記と同じことをテーブル項目に対してやる場合は、以下の要領で行います。

```python:テーブル項目の場合
df['列名'] = df['列名'].str.replace("\\D", "")
```

テーブル項目に対して処理を行う場合は、
最初と最後に[おまじないコード](https://qiita.com/IQBotter/items/67694b1b0d1376ede7e7#%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E9%A0%85%E7%9B%AE%E3%81%AE%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%A0%E3%83%AD%E3%82%B8%E3%83%83%E3%82%AF%E3%81%AF%E3%81%A9%E3%81%86%E6%9B%B8%E3%81%8F)を入れるのを忘れないように！

テーブル項目の列名については[こちら](https://qiita.com/IQBotter/items/b1e7a75439fede2171e6#%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E9%A0%85%E7%9B%AE%E3%81%AB%E5%AF%BE%E3%81%99%E3%82%8B%E7%BD%AE%E6%8F%9B%E5%87%A6%E7%90%86)を参照。


#数値だけ取り出す処理の使い道

数値だけ取り出す処理の使い道は、主に２つです。
業務で使う割合でいうと、前者が２割：後者が８割くらいでしょうか（扱っている帳票によると思いますが）。

##文章やラベルとくっついている読み取り結果から、数値部分だけを取り出す

合計金額などの数値項目が帳票上に「今月の請求金額は123,456円となります」みたいに文章で表記されている場合や、
銀行名～支店名～口座番号がずらっと並んだ中から口座番号だけを取り出したい場合などに使います。

##数値項目から予測不能なノイズを除外

[こちらの記事](https://qiita.com/IQBotter/items/b1e7a75439fede2171e6)で置換を使ったノイズの除外について説明していますが、
実業務では、どういう形でノイズが混入してくるか予測がつかないケースがほとんどだと思います。

「この項目には数値しか入って来ない」とあらかじめわかっている場合は、
「数値以外の文字が混入していたら一律除外」というこの処理を使っておくと効率がいいです。

その際、当たり前ですが、**ゼロをオーと読んでしまう・イチをI（アイ）やl（エル）と呼んでしまうなどのパターンが決まった誤読についてはあらかじめ処理をしてから**この処理をかけましょう。

```python:実際の使用例（フィールド項目の場合）

#パターンの決まった誤読にまず対処

#Replace アイ、エル、パイプラインを１に
field_value = field_value.replace("I","1")
field_value = field_value.replace("l","1")
field_value = field_value.replace("|","1")

#Replace オーと〇をゼロに
field_value = field_value.replace("O","0")
field_value = field_value.replace("〇","0")

#その上で、数値以外の文字を除外

import re
field_value = re.sub("\\D", "", field_value)
```
#応用編

正規表現を使った表現で、数字以外にもさまざまな条件で抽出したい文字の種類を指定できます。

フィールド項目の場合は、各処理の前に `import re` を置く必要がありますが、テーブル項目の場合は不要です。

##数字＋英字（大文字）だけを残したいとき

フィールド項目の場合
`field_value = re.sub(r"[^0-9A-Z]","",field_value)`

テーブル項目の場合
`df['列名'] = df['列名'].str.replace(r"[^0-9A-Z]", "")`

##数字＋英字（大文字、小文字両方）を残したいとき

フィールド項目の場合
`field_value = re.sub(r"[^0-9a-zA-Z]","",field_value)` 

テーブル項目の場合
`df['列名'] = df['列名'].str.replace(r"[^0-9a-zA-Z]", "")`

##数字＋小数点だけを残したいとき

フィールド項目の場合
`field_value = re.sub(r"[^.0-9]","",field_value)` 

テーブル項目の場合
`df['列名'] = df['列名'].str.replace(r"[^.0-9]", "")`

##より複雑なパターンの抽出

```python:（例）血液型の後に、2桁-4桁-4桁の数字が続く文字列を抽出（フィールド項目の場合）
import re
mobj = re.search(r"(A|B|O|AB)型[0-9]{2}-[0-9]{4}-[0-9]{4}",field_value)   
field_value = mobj.group(0)
```

#検索用：数字のみ／数値のみ／数字だけ
Kubernetes 1.18: SIG-Network の変更内容

[Kubernetes v1.18](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.18.md) の SIG-Network の変更内容をまとめました。

## What's New (新情報)

- IPv6 が Kubernetes v1.18 でベータになりました。新しい CI のジョブでテストカバレッジが大きく増加しています。
- Node Local DNSCache が GA になりました([#1351](https://github.com/kubernetes/enhancements/pull/1351))。この機能は DNS キャッシュの Pod を DaemonSet として動かし、クラスタの DNS のパフォーマンスと 信頼性を大きく上げるアドオンです。この機能は 1.13 のリリースから Alpha でした。

:memo: Kubernetes の DNS は Conntrack の[競合](https://github.com/kubernetes/kubernetes/issues/56903)や、テーブル溢れが起きやすく障害点になりやすいコンポーネントです。Node Local DNSCache は DaemonSet で各ノードでキャッシュ用の CoreDNS を立ち上げることで、この問題を改善するものです。

## Changes by Kind
### kube-proxy
- `-healthz-port` と `--metrics-port` フラグが廃止予定となりました。代わりに `--healthz-bind-address` と `--metrics-bind-address` を利用してください。[#88512](https://github.com/kubernetes/kubernetes/pull/88512)
- `--ipvs-tcp-timeout`, `--ipvs-tcpfin-timeout`, `--ipvs-udp-timeout` が追加され、IPVS コネクションのタイムアウトを設定できるようになりました [#85517](https://github.com/kubernetes/kubernetes/pull/85517)
- オプショナルの `--detect-local-mode`  フラグが追加されました。有効な値は "ClusterCIDR" (現在の挙動) と "NodeCIDR" です。[#87748](https://github.com/kubernetes/kubernetes/pull/87748)
- kube-controller-manager に新しく追加された `--endpointslice-updates-batch-period` フラグで、Pod の変更によって発生する、EndpointSlice の更新回数を減らすことができるようになりました。 [#88745](https://github.com/kubernetes/kubernetes/pull/88745)
- kube-proxy, kubelet, kube-controller-manager, kube-scheduler に新しく追加された `--show-hidden-metrics-for-version` フラグで、前回のマイナーリリースで廃止予定となり非表示となったメトリクスを再表示できるようになりました。[#85279](https://github.com/kubernetes/kubernetes/pull/85279)
- iptables proxier が IPv4/IPv6 の dual-stack をサポートするようになりました。[#82462](https://github.com/kubernetes/kubernetes/pull/82462)
- `--node-ip ::` の指定で、IPv6 のアドレスを自動検出しノードのプライマリアドレスとして使用することができるようになりました。[#85850](https://github.com/kubernetes/kubernetes/pull/85850)

### Ingress
- より適切な Ingress の設定を行うため、IngressClass リソースが新規に追加されました。[#88509](https://github.com/kubernetes/kubernetes/pull/88509)
- 廃止予定の `kubernetes.io/ingress.class` アノテーションは `spec.ingressClassName` で置き換えられます。これは Ingress オブジェクトを特定のコントローラーに紐付けるものです。
- パスの定義に `pathType` が追加され、パスをどのようにマッチさせるかを明示できるようになりました。有効な値は `Exact`, `Prefix`, `ImplementationSpecific` です。
    - :memo: `Prefix` は単純な前方一致ではなく、`/` で分割した際の一致となります。たとえば Prefix `/foo/bar` は `/foo/bar/baz` に一致しますが、`/foo/barbaz` には一致しません。

### その他
- アルファ機能の `ServiceAppProtocol` は ServicePort と EndpointPort の定義で `appProtocol` フィールドの設定を有効にできます。[#88503](https://github.com/kubernetes/kubernetes/pull/88503)
- EndpointSlices がデフォルトで有効になりました。新しい EndpointSliceProxying フィーチャーゲートによって kube-proxy が EndpointSlice を使用するかが決まるようになります。[#86137](https://github.com/kubernetes/kubernetes/pull/86137)
- CNI のバージョンが v0.8.5 にアップデートしました [#78819](https://github.com/kubernetes/kubernetes/pull/78819)
javascript jQuery スクロール禁止、解除


###スクロール禁止
```javascript
$('html *').css('overflow','hidden');
$(window).on('touchmove.noScroll', function(e) {
    e.preventDefault();
});
```

###解除
```javascript
    $('html *').css('overflow','visible');
    $(window).off('.noScroll');
```

できました。スマホ対応です。
Google spreadsheet を wget でダウンロードしたい

# はじめに

- ``Google Spreadsheet``はとても便利
- ただし、データ分析に使う時にブラウザからダウンロードするのがめんどくさい
- コマンドラインでダウンロードできれば、ますます便利なのではないか

# 検索 & 要約

- ``google spreadsheet wget``でぐぐったら、以下の Stack Overflow がヒットした
  - [Download unpublished Google spreadsheet as CSV](https://stackoverflow.com/questions/10730712/download-unpublished-google-spreadsheet-as-csv)
- 上記の回答を読んで、最終的に以下のコマンドでよいことが分かった

```bash
wget -O {FILENAME} 'https://docs.google.com/spreadsheets/d/{KEY}/export?gid={GID}&format={FORMAT}'
```

- ``--no-check-certificate``オプションはつけなくてもOK
- ``-O {FILENAME}`` でファイル名を指定
  - 拡張子はダウンロード形式に合わせる
- ``{KEY}``はスプレッドシートのID
  - シートのURLを上記のフォーマットと見比べる（見ればわかるはず）
- ``{GID}``はスプレッドシート内のシートID
  - 一番最初に作ったシートは``gid=0``
  - 別のシートを指定する場合は、そのシートのURLを確認すると``gid=NNN``（ランダムな数字）となっている


# ダウンロード用のスクリプトを書いた

- ``Python3``の``subprocess``モジュールを使ってみた
- ``wget``したファイルは``downloads/snapshot.xlsx``といった名前で保存することにした
  - エラーがでないように``downloads``のディレクトリを作っておく（``$ mkdir downloads``）

```python
import subprocess

def gsheet_url(key, fmt, gid):
    '''
    key : スプレッドシートのID
    fmt : ダウンロード形式
    gid : シートのID
    '''
    path = f'https://docs.google.com/spreadsheets/d/{key}/export'
    query = f'format={fmt}'
    if not gid is None:
        query += f'&gid={gid}'
    url = f'{path}?{query}'
    return url

def gsheet_wget(key, fmt, gid=None):
    '''
    snapshot.{fmt} というファイル名で、downloads/ に保存する
    '''
    ofn = f'snapshot.{fmt}'
    url = gsheet_url(key, fmt, gid)
    cmd = ['wget', '-O', fname, url]
    subprocess.run(cmd, cwd='downloads')
    return cmd
```

# テストしてみた

- テスト用のスプレッドシートを用意した
  - [1NbSH0rSCLkElG4UcNVuIhmg5EfjAk3t8TxiBERf6kBM](https://docs.google.com/spreadsheets/d/1NbSH0rSCLkElG4UcNVuIhmg5EfjAk3t8TxiBERf6kBM/edit?usp=sharing)（閲覧のみ）


## 全部の形式でダウンロードしてみた

```python
formats = ['xlsx', 'ods', 'pdf', 'zip', 'csv', 'tsv']
key = '1NbSH0rSCLkElG4UcNVuIhmg5EfjAk3t8TxiBERf6kBM'  # テスト用の公開シート

for fmt in formats:
    print(f'ダウンロード形式 : {fmt}')
    cmd = gsheet_wget(key, fmt)
```

- ``zip``：中身はシート別の``html``ファイルとレイアウト用の``CSS``ファイル
- ``csv``：``シート1``（=``gid=0``）だけになる
- ``tsv``：``シート1``（=``gid=0``）だけになる

## ``シート2``だけを指定してダウンロードしてみた

- ``gid``を指定する

```python
formats = ['xlsx', 'ods', 'pdf', 'zip', 'csv', 'tsv']
key = '1NbSH0rSCLkElG4UcNVuIhmg5EfjAk3t8TxiBERf6kBM'  # テスト用に作った公開シート
gid = 1772074296  # シート2のID

for fmt in formats:
    print(f'ダウンロード形式 : {fmt}')
    cmd = gsheet_wget(key, fmt, gid)
```

# まとめ

- ``Google spreadsheet`` を ``wget`` できるようになった
- これで [pandas.read_csv](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.read_csv.html) とか [pandas.read_excel](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.read_excel.html) とかで読み込み放題
ペットのカメさんが「ゆで亀🐢」にならないように考えたIoTソリューション

記事をご覧くださりありがとうございます！
初めまして。AI/IoT分野のプロフェッショナルを目指して修行中の、のぶたんです。🐉
今回は、**ペットととして飼っているカメ🐢さんがゆで亀にならないソリューション**を紹介します😃
仕様は以下の通り。
##仕様
①水槽の温度が30℃以上になったら、温度調節を促すメール通知
②水槽の温度が25℃以下になったら、温度調節を促すメール通知
③水位レベルが低くなったら、水を継ぎ足すことを促すメール通知


#システム構成
![ESaJUNgVAAA-HVy.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580405/40887d90-c195-91dc-e0b3-cb31ca8fb5ee.png)
![MVIMG_20200406_115028.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580405/a374e556-2f55-d816-abe0-f81cc237b089.jpeg)
→画像は実際に、水温センサと水位レベルセンサを接続したESP32ボードです。

![MVIMG_20200406_120325_3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580405/70829c54-6ba5-8972-5e89-51f9778813ca.jpeg)
→内側の水温センサはペットボトルにくっつけています。
![MVIMG_20200406_120452_2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580405/7f1ad714-07b7-d84a-a5b4-c18ff7ede520.jpeg)
→外側の水温センサはヒータの近くに入れています。
![MVIMG_20200406_120641.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580405/2f660a5a-6f0d-1625-90b6-f8ac135e3610.jpeg)
→水槽の外の判別したい高さに水位レベルセンサをつけています。
#実際のメール通知
![mail1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580405/58c579ae-069d-74d8-7d72-f08d9b46672e.png)
→水槽の水がセンサの取り付けたレベルより少なくなったら、指定のアドレスにメールが送られます。
![mail2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580405/a55e8a33-204c-ae1c-c76e-f877ce846a05.png)
→ゆで亀🐢にならないように水槽の温度が30℃を超えると、指定のアドレスにメールが送られます。

#ソースコード
今後、githubに乗っけます。

#最後に
せっかくなので自動化させるべく自動餌やり機構も試作中です。
![MVIMG_20200322_111923.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580405/c508861c-9fa0-64a4-99ea-2357f0347db0.jpeg)
→仕組みはシンプルで、サーボモータに3Dプリンタで自作したエサ入れを取り付けています。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">カメの餌やり🐢 <a href="https://t.co/8lZSaSykQ2">pic.twitter.com/8lZSaSykQ2</a></p>&mdash; りゅう@腐ったひつじ（23）🐑 (@Y9PUzhtJ2XRihIX) <a href="https://twitter.com/Y9PUzhtJ2XRihIX/status/1247016119543595008?ref_src=twsrc%5Etfw">April 6, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> 
→動画の通り、3Dプリンタで餌入れを作りましたが、一回に餌が多く出てくる量が多いので小さな穴に変更することと、取り付け部品なども造形したいと思います。　
　

この記事をご覧になった方。
今回は**ESP32ボードを用いた温度と水位を管理するカメ監視サーバ**を作りました。
IoTシステムは基本、3要素で構成されており、このシステムはセンサーデータ取得処理、その値を判別する処理、メールを送信する処理のすべてをIoTデバイス側(端末:ESP32)で行い、まさに**エッジコンピューティング**の考え方で実装しています✌
![プロトタイピング プレゼンテーション.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580405/ff2c0dc5-518f-3024-bd9b-be26f0049ecf.jpeg)

エッジコンピューティングが可能なのは、マイコンは処理性能が向上したのが背景にあります。
さすが、ESP32のはじめとするSoCチップ！！！

※**エッジコンピューティング**とは・・・**センサーやデバイスなどからのデータを、発生した現場に近い場所（エッジ）で処理する技術や考え方**

これからも、IoTソリューションを考え、自作し、発信していきます。
皆さんも、安価で便利なIoTソリューションを自作してみてはいかがでしょうか？
それでは✋
5G基盤の為のOPNFV構築

## 目的
5G基盤となるを構築可能なオープンソースOAI(OpenAirInterafce)を使用するための基盤を、OPNFV-apexにより構築する。
その際の備忘録　※5G部分は本記事にはでてこない

## OPNFVとは
簡単に、NFV関連のPoCに最適なOSS達を一括で構築し、ほとんど編集しなくても、ある程度の連携まで設定してくれるインストーラ
中ではRDO,TripleOとかが動いている。

参考: 
[RDOの公式ページ](http://rdoproject.org/ "RDO")
[TripleOの公式ページ](https://wiki.openstack.org/wiki/TripleO "TripleO")

## ハードウェアリソース
構成にもよるがOAIを動かすためには、それなりにメモリは必要。
今回はnoHA構成とした。

## カーネル・OSバージョン
カーネル 3.10.0-957.5.1.el7.x86_64
CentOS Linux release 7.6.1810


##　前提
- インターネット接続
- systemd　無効化 
    * NetworkManager 
    * Firewall 
    * Postfix
- Selinux 無効化 

## パッケージ収集
opnfv-apexの最新版は安定しないしドキュメントも中途半端なため、安定verであるfraserを使用

```
yum clean

yum -y groupinstall "Virtualization Host"

yum install -y epel-release screen

yum install -y https://repos.fedorapeople.org/repos/openstack/openstack-pike/rdo-release-pike-1.noarch.rpm

curl -o /etc/yum.repos.d/opnfv-apex.repo http://artifacts.opnfv.org/apex/fraser/opnfv-apex.repo

wget http://artifacts.opnfv.org/apex/fraser/opnfv-apex{,-undercloud,-python34}-6.2.noarch.rpm

mkdir -p images && wget -q -O-https://git.opnfv.org/functest/plain/functest/ci/download_images.sh?h=stable/fraser | bash -s --images && ls -1 images/*

yum install -y opnfv-apex{,-undercloud,-python34}-6.2.noarch.rpm

curl -sSL https://get.docker.com/ | sh
systemctl enable docker#
systemctl start docker
```
## 構築
デプロイファイル編集

```
# cp /etc/opnfv-apex/network_settings.yaml ~/network.yaml
# cp  /etc/opnfv-apex/os-nosdn-nofeature-ha.yaml ~/deploy.yaml
```
デプロイ

```
# opnfv-deploy -v -n ./network.yaml -d ./deploy.yaml --virtual-compute-ram 32 --virtual-default-ram 32 --virtual-cpus 12 

１時間近くかかる。。

2019-02-28 12:08:54,488 INFO: PLAY RECAP *********************************************************************
192.0.2.9                  : ok=4    changed=3    unreachable=0    failed=0

~~
正常終了したらこんな感じ↓
2019-02-28 12:08:54,536 INFO: Post Deploy Overcloud Configuration Complete for node overcloud-novacompute-0
2019-02-28 12:08:54,536 INFO: Apex deployment complete
2019-02-28 12:08:54,536 INFO: Undercloud IP: 192.168.122.40, please connect by doing 'opnfv-util undercloud'

```

途中失敗したらopnfv-clean後に再度実行
基本的にパッケージ関連なので、何かおきたらyum周りを見直して、力技でぶっこむ。

※リソースが足りないとSegvでコアダンプ吐き出して強制終了する。



## openstack
デフォルトのセキュリティグループでSSH接続を有効にする設定を追加する必要がある。
多分Neutron,Nove,Keystoneあたりの連携の設定。（インスタンスに鍵は登録されている）

```
# openstack security group rule create --protocol icmp --ingress default
```
インスタンス同士を繋ぐ

```
# sudo echo "192.168.37.207  ran" >> /etc/hosts
# sudo echo "192.168.37.204  cn" >> /etc/hosts

# ssh ubuntu@ran

ubuntu@ran:~$
sudo -s

or

# ssh ubuntu@cn

ubuntu@cn:~$
```

ひとまず、OpenStackを構築し、インスタンス同士の接続を確認。
OpenStackのところ雑すぎる。。
また更新します。
あと、誰かOPNFVの最新版とか動いたって人がいたら簡単な構成教えていただけると幸いです。
## 参考
https://docs.opnfv.org/en/stable-gambia/release/installation.introduction.html
https://www.server-world.info/query?os=CentOS_7&p=openstack_ocata&f=13
メールのフッター文章を変える-OctoberCMS-

#概要
![2020-04-03 (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/589658/fc7269bc-739f-bd07-3b59-9e7948996263.png)
初期状態では上記画像のようになっている。
この「October CMS」部分を自分の名前にしたい。

#方法
データベースをいじる。
OctoberCMSインストール時に生成された
「system_mail_layouts」テーブルの「content_html」。
この中の一部を変更することで変えられる。

今回触るのはidが「1」、nameが「Default layout」の中身を触る。

##html
以下全文。

```html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
    <style type="text/css" media="screen">
        {{ brandCss|raw }}
        {{ css|raw }}
    </style>

    <table class="wrapper layout-default" width="100%" cellpadding="0" cellspacing="0">

        <!-- Header -->
        {% partial 'header' body %}
            {{ subject|raw }}
        {% endpartial %}

        <tr>
            <td align="center">
                <table class="content" width="100%" cellpadding="0" cellspacing="0">
                    <!-- Email Body -->
                    <tr>
                        <td class="body" width="100%" cellpadding="0" cellspacing="0">
                            <table class="inner-body" align="center" width="570" cellpadding="0" cellspacing="0">
                                <!-- Body content -->
                                <tr>
                                    <td class="content-cell">
                                        {{ content|raw }}
                                    </td>
                                </tr>
                            </table>
                        </td>
                    </tr>
                </table>
            </td>
        </tr>

        <!-- Footer -->
        {% partial 'footer' body %}
            &copy; {{ "now"|date("Y") }} {{ appName }}. All rights reserved.
        {% endpartial %}

    </table>

</body>
</html>
```

＜/table＞の直前部分を触る。



```html
&copy; {{ "now"|date("Y") }} {{ appName }}. All rights reserved.
```
これを、


```html
&copy; {{ "now"|date("Y") }} Orito. All rights reserved.
```
こう。

#結果
![2020-04-06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/589658/d6eee684-318a-3234-ca0a-d4132d252d2b.png)
【RSpec】テスト実行結果を見やすくする。

#問題
 RSpecを使っていると、テスト実行結果が、

>$ bundle exec rspec
 <font color="LimeGreen">.....</font>

>Finished in 4.05 seconds (files took 5.14 seconds to load)
 <font color="LimeGreen">5 examples, 0 failures</font>

このように表示される、この.....が各テストをパスした、という表示だが、使い初めから、違和感があった。
分かりづらい、見ずらい、、

#原因、解決
その後、RSpecについて調べている中で、
.rspecに
>--format documentation

を追加。

そうすると、出力結果が、

>$ bundle exec rspec

>TestHelper
  test_method
    <font color="LimeGreen">is expected to eq "rspecでhelperをテスト"</font>

>Products
  GET #show
   <font color="LimeGreen"> リクエストに成功する
    商品名が含まれる
    商品詳細が含まれる
    商品価格が含まれる</font>

>Finished in 4.14 seconds (files took 5.31 seconds to load)
5 examples, 0 failures

このように変わり、パスしたテスト名が表示されるようになり、見やすくなった。
これが標準でもいいのでは無いかと思うレベルだが、テストの数が多くなるに伴い出力が多くなる為、後々は元に戻したくなるのかな、とも感じた。

# 終わりに
転職の為、未経験の状態からRailsを学習しております。正しい知識を着実に身に着け、実力のあるエンジニアになりたいと考えています。継続して投稿していく中で、その為のインプットも必然的に増え、成長に繋がるかと考えています。
今現在、初心者だからといって言い訳はできないですが、投稿の内容に間違っているところや、付け加えるべきところが多々あるかと思いますので、ご指摘頂けると幸いです。この記事を読んで下さりありがとうございます。
Elmで個人的によく使うModelの書き方パターン

## type alias(レコード)
elm-guideでも掲載されてるよくあるパターン。
基本これで充分。

```elm
type alias Model =
    { title : String
    }
```


## type(カスタム型)
elm-guideを卒業すると出てくるパターン。
初見はやられるが、使ってみると、状態によって保持するプロパティを変えることができるため、かなり便利。

例えば、下記コードはタイトル画面とコンテンツ画面が切り替わるようなページを表現している。

```elm
type Model
    = TitleView String
    | ContentsView String Int (List String)

type Msg
    = GotTitle
    | GotContent

update: Msg -> Model -> (Model, Cmd Msg)
update msg model =
    case (msg, model) of
        -- MsgとModelの状態で処理を振り分けることが多い。
        -- もちろん、MsgだけでもOK。
        (GotTitle, ContentView title contentNum contents) ->
            ... -- 何かしらの処理
            (TitleView title, Cmd.none) -- カスタム型として再度Modelを作ることで値を更新する
        (GotContent, TitleView title) -->
            ... -- 何かしらの処理
            (ContentsView title 3 ["aaa", "bbb", "ccc"], Cmd.none)

        (_, _) ->
            -- 上記パターン以外は何もしない
            (model, Cmd.none)         

view: Model -> Html Msg
view model =
    -- viewもパターンマッチで各ケースごとに画面を表示できるのでわかりやすい
    case model of
        TitleView title ->
            ...

        ContentsView title contentNum contents ->
            ...

```

## type(カスタム型) + type alias(レコード)
前述の２つを組み合わせたパターン。
カスタム型でModel表現をするパターンで、1パラメータの取り扱いが多くなってきた時に使うと良い。

```elm
-- Before
-- String多すぎて何が何かわからぬ
type Model
    = ContentsView String String String String String String

-- After
-- type aliasでまとめることでスッキリ！
type alias Contents =
    { title: String
    , content1: String
    , content2: String
    , content3: String
    , content4: String
    , content5: String
    }

type Model
    = ContentsView Contents
```

共通の値と、状態によって値が分かれるときは、レコードの中にカスタム型を入れるのも良い。

```elm
-- Before
-- ひとつのAPIから得られるレスポンスとしてgotResultsとgotErrorを定義している。
-- APIの成否結果として、一方の値が存在しているときにはもう一方の値は存在しない。
type alias Model =
    { title: String
    , gotResults: List String
    , gotError: String
    }

-- After
-- APIからの結果をGotResultというカスタム型で表現することで、どちらか一方しか存在しないことが保証できる。
type alias Model =
    { title: String
    , gotResult: GotResult
    }

type GotResult
    = Success (List String)
    | Failure String
```
apollo_upload_serverでActiveStorageにそのままファイルがアップロードできない

Rails + graphql-rubyでapollo_upload_serverを使ってファイルアップロード→activeStorageへ登録を試してみていて
ApolloUploadServer::Upload型の入力データを
modelにattachしてみたらエラーがでました

入力データの定義

```ruby
module Types
  class UserInputObject < Types::BaseInputObject
    argument :avatar, ApolloUploadServer::Upload, "user profile picture", required: false
  end
end
```

エラー内容

```
Could not find or build blob: expected attachable, got #<ActionDispatch::Http::UploadedFile:0x000055d4a2a41240
```

これを解決するまでのメモです。


### 結論

こちらissueのコメントを参考に
ApolloUploadServer::Upload型を使うのをやめて、
自分でscalar型を宣言することで解決しました。
https://github.com/jetruby/apollo_upload_server-ruby/issues/10#issuecomment-394729475

こんな感じです。

```ruby:image_file.rb
module Types
  class ImageFile < Types::BaseScalar

    description "upload file type"

    def self.coerce_input(file, context)
        file
    end

end
```

### 経緯

ActionDispatch::Http::UploadedFileではないのかと確認してみる

```
p input.avatar.class
```

結果→`ApolloUploadServer::Wrappers::UploadedFile`
調べてみるとActionDispatch::Http::UploadedFileのwrapperクラスであることがわかる

↓

mutationのresolverで
ApolloUploadServer::Wrappers::UploadedFileから
ActionDispatch::Http::UploadedFileのインスタンスを取得できないかと考える

↓

ソースを確認し、簡単には無理そうだなと理解

https://github.com/jetruby/apollo_upload_server-ruby/blob/master/lib/apollo_upload_server/wrappers/uploaded_file.rb


```ruby:uploaded_file.rb
# frozen_string_literal: true

require 'delegate'
require 'action_dispatch/http/upload'

module ApolloUploadServer
  module Wrappers
    class UploadedFile < DelegateClass(::ActionDispatch::Http::UploadedFile)
      def initialize(wrapped_foo)
        super
      end

      def as_json(options = nil)
        instance_values.except('tempfile').as_json(options)
      end
    end
  end
end
```

↓

検索し、公式のissueでこの問題について議論しているページを発見
https://github.com/jetruby/apollo_upload_server-ruby/issues/10

↓

いくつか解決方法が掲載されているけど
返却するとき（coerce_result）にも独自にscalar型を定義してactive_storageから
public_urlを取得する処理があったので
受け取る際の処理（coerce_input）に処理を書くかと結論の方法を採用



もし他にいい方法があるよ！って場合はご教授いただけると
ありがたいです。
よろしくお願いします！
CSSだけで数値をカウントする

サンプルはこちら。

<p class="codepen" data-height="430" data-theme-id="5973" data-default-tab="css,result" data-user="KazuyoshiGoto" data-slug-hash="RGxWPz" style="height: 430px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="counter-increment test">
  <span>See the Pen <a href="https://codepen.io/KazuyoshiGoto/pen/RGxWPz">
  counter-increment test</a> by Kazuyoshi Goto (<a href="https://codepen.io/KazuyoshiGoto">@KazuyoshiGoto</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

HTMLにもCSSにも数値は書いておらず、連番リスト（ol）も使っていません。

## 変数をカウントする

```css
h2 {
  counter-increment: x;
  counter-reset: y;
}
h3 {
  counter-increment: y;
}
```

h2,h3 の見出しに ```counter-increment``` というプロパティを使っています。

このプロパティはCSS内で変数を定義すると同時に、その変数を+1します。
上記の場合は h2 ごとに ```x``` が、h3ごとに ```y``` が1つ増える宣言をしています。

また h2 には ```counter-reset: y``` も宣言しています。
これは指定した変数を0に戻すプロパティです。

h3 ごとに増える ```y``` をリセットすることで、大見出し(h2)ごとに小見出し(h3)の番号を1から振り直す形になります。

ちなみに ```counter-increment: x y;``` という形で複数の変数を同時にカウントすることもできます。


## 変数を表示する

```css
h2:before {
  content: "Part" counter(x) " : ";
}
h3:before {
  content: counter(x) "-" counter(y) " : ";
}
```

変数の表示ですが、現在 ```counter-increment``` で作った変数は疑似要素 ```:before``` か ```:after``` の、 ```content``` でしか表示できません。

疑似要素に ```content: counter(x)``` で変数を表示することができますが、サンプルのように前後に文字を入れたり、複数の変数も表示できます。

「X章Y条」のように長い条項が続く文章も番号を意識せず作れますし、ほかにも連番が必要な時にプログラムに頼らず表示することができます。
PowerPoint プレゼンテーションでリアルタイム字幕を付ける

関連記事は[**「Microsoft Teams の授業での活用」**](https://qiita.com/hisaho/items/12837a169bd6f1d90d5c)をご参照ください。

#プレゼンテーショントランスレータ とは

[プレゼンテーショントランスレータ](https://www.microsoft.com/ja-jp/translator/apps/presentation-translator/) は、PowerPoint プレゼンテーション時にリアルタイムで字幕を付けたりすることができるプラグインです。

#主な機能

- PowerPoint プレゼンテーション時のリアルタイム字幕表示
- 自分のデバイスで自分の選択した言語で字幕が見れる
-  スライドの翻訳

# アプリのダウンロード
- [PowerPointのためのPresentation Translator](https://www.microsoft.com/download/details.aspx?id=55024)

# プレゼンテーショントランスレータの使い方

- PowerPoint のメニューから**[スライドショー]**を選びます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78535/b765ee7d-dc6b-cc07-562d-a0a5f0f43a09.png)

-  **[字幕の設定]**をクリックし、**話し手の言語**、**字幕の言語**を設定します。
 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78535/3aad4071-7bf9-4d73-4e31-bd6d09ddb62e.png)

- **サブタイトルをスタートする**をクリックすると下記の画面が表示されますので、**[サブタイトルをスタートする]**をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78535/d5e5008c-77d5-418c-3f12-4999dacda020.png)

- プレゼンテーションの最初に以下の画面が表示されます。視聴者は自分のスマートフォンでQRコードを読み込みます。
 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78535/e17f5a92-fac5-3c05-db34-052986a4e9e8.png)

- TranslatorのWebページが表示されますので、言語を選択し**[参加する]**をクリックしてください。
 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78535/17b721fe-6087-5107-04ae-5b72acda6ca0.png)
CloudflareのDNSサービス「1.1.1.1 for Families」でアダルトサイトがフィルタリングされるか

Cloudflare のDNSサービスに、「1.1.1.1 for Families」という機能が加わり、家庭向けフィルタリングができるようです。

https://blog.cloudflare.com/introducing-1-1-1-1-for-families/

1.1.1.2 というDNSサーバーがマルウェアを排除してくれて、 1.1.1.3 というDNSサーバーが、マルウェアに加えてアダルトサイトをフィルタリングしてくれるそうです。

実際に試してみましょう。DNSサーバーを指定してドメインからIPアドレスを引くのは、dig コマンドを使います。まずはフィルタリングなしの1.1.1.1のDNSに対して、FANZAのドメインを指定します。

```
$ dig www.dmm.co.jp @1.1.1.1

; <<>> DiG 9.11.3-1ubuntu1.1-Ubuntu <<>> www.dmm.co.jp @1.1.1.1
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 14512
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1452
;; QUESTION SECTION:
;www.dmm.co.jp.                 IN      A

;; ANSWER SECTION:
www.dmm.co.jp.          6       IN      A       202.6.246.29
www.dmm.co.jp.          6       IN      A       157.112.85.173

;; Query time: 11 msec
;; SERVER: 1.1.1.1#53(1.1.1.1)
;; WHEN: Mon Apr 06 12:53:09 JST 2020
;; MSG SIZE  rcvd: 74

```

ANSWER SECTION に記載されているIPアドレスが、DNSが返してきたIPアドレスです、複数のサーバに分散させていることがわかります。

次に、アダルトフィルタリングつきの 1.1.1.3をDNSとしてFANZAのIPアドレスを取得してみましょう。

```
# dig www.dmm.co.jp @1.1.1.3

; <<>> DiG 9.11.3-1ubuntu1.1-Ubuntu <<>> www.dmm.co.jp @1.1.1.3
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 60439
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1452
;; QUESTION SECTION:
;www.dmm.co.jp.                 IN      A

;; ANSWER SECTION:
www.dmm.co.jp.          60      IN      A       0.0.0.0

;; Query time: 23 msec
;; SERVER: 1.1.1.3#53(1.1.1.3)
;; WHEN: Mon Apr 06 12:55:51 JST 2020
;; MSG SIZE  rcvd: 71
```

ANSWER SECTION をみると0.0.0.0となっているので、FANZAはアダルトサイト扱いのようですね。

本物のフィルタリングソフトに比べると、ざっくりのフィルタリングですが、大半のフィルタリング需要には応えれて、なおかつ無料のはすごいことです。
enum、scopeのロジック

##enum
enumはint型、boolean型で定義されたカラムを、文字列で表現できるようにする機能です。
【例】

```
class Drink < AppricationRecord
# Drinkモデルのkindrカラムのenumを定義する
# DBに保存されている値が0の時はtea, 1の時はcoffee、2の時はbeerを意味する
  enum kind: [:tea, :coffee, :beer]
end
```
【例】

```
@drink = Drink.new(kind: 1)
@drink.kind
# => 'coffee'
# 数字ではなくenumで定義したキーワードが返ってくる
```
enumを利用すると、数字と対応した文字列を返り値として出力できるようになります。
##scope
scopeはモデルに対する絞り込みの条件に名前をつけて、メソッドのように呼び出し可能にする機能です。よく使う検索ロジックはscopeにしておくことによって、後から簡単に再利用できるようになります。
【例】今回はTaskモデルに「incoming」という名前でscopeを定義します。

```app/models/task.rb
class Task < ApplicationRecord
  enum kind: { individual: 0, work: 1, others: 2 }

  scope :incoming,  -> { where('start_at > ?', Time.zone.now) }
end
```
定義したscopeを使って@tasksを再定義します。

```app/controllers/tasks_controller.rb
class TasksController < ApplicationController

  def index
    @task = Task.new
    # モデルに定義したscopeはメソッドのように呼び出せる
    @tasks = Task.incoming.order(start_at: :asc)
  end

# 以下省略
```
##参考リンク
[enumリファレンス(英語)](http://api.rubyonrails.org/v5.1/classes/ActiveRecord/Enum.html)
[enum_help Githubリポジトリ](https://github.com/zmbacker/enum_help)
[Rails ModelのScope（スコープ）の使い方]
(http://ruby-rails.hatenadiary.com/entry/20140814/1407994568)
Jakarta EE＋Payara server＋NetBeansで開発しよう！

（その１）
　JavaEEからJakartaEEへ、大きな変化のために、開発環境も激変しました。これから、数回にわたり、今後のJakartaEE用の開発環境の構築について解説します。なお、前後しますが、NetBeansのインストール＋日本語化は、次回です。

#NetBeansのプロジェクト

まず、大きな問題の1つは、最新のApache NetBeansでは、従来のNetBeansのプロジェクトがそのままでは動かないことです。 「ファイル」⇒「新規プロジェクト」から、 「Java with ant」の中の「Java web」⇒「web Application with Existing Sources」と選択して、新しいプロジェクトに移すことができるのですが、面倒な手順を踏んで、ようやく完成しても、いざ実行してみると、見事にエラーになって止まります。なんてこったい！

結局、新しくプロジェクトを新規作成してソースコードを移せばよいと思い、「 web Application with Existing Sources」 の代わりに、「 web Application 」を選んで、ソースコードをコピーしたり、必要な設定ファイルを追加したりしました。し、しかし、ですね。これはやはり、面倒すぎます。

そもそも、Maven プロジェクトが主流ですよね。どうせ移すなら、そう、Gradleとまでいかなくても、せめて、 antじゃなく Mavenでやりたい。しかし、見ると 「Maven」⇒「Webアプリケーション」 という選択肢があるじゃないですか！

#Mavenプロジェクト

結論から言いましょう。できたのは、REST開発用のプロジェクトでした。マイクロサービスのために、サーバーサイドを作るのなら、これでOKですが、残念ながらJSF用ではありません。index.xhtmlファイルを作り、不要なフォルダを消したりすると、JSF用になるのですが、毎回では、面倒すぎます。

そこで、もう少し探してみると、「Maven」⇒「原型からのプロジェクト」というのがありました。ネットで「JakartaEE用のarchetypeを作った」という記事を見かけますが、それを利用するプロジェクトです。あらかじめたくさんのarchetypeが登録されています。

"JakartaEE" で検索すると、16個も登録されているので、使えそうなものを全部試してみました。しかし、REST用のものは立派なのがたくさんあるのですが、JSF用は、これと言えるほどのものは・・・

#プロジェクトビルダー

「ええい、こうなったら自分でarchetypeを作ってしまおう」とそう思ったのでした。で、いろいろ調べてみたのですが、仕組みは以外と簡単なもので、内部にひな形のプロジェクトを持っていて、使用時に必要な箇所だけ書き換えてプロジェクトを出力できるというものです。それでも、Mavenの文法がいろいろあり、わかりづらいことはありますが。

「うーん、これだったら、Javaでも作れるのでは？」
そう思ったので、あまり後先も考えす、JavaSEのMavenプロジェクトを作って、プログラムを書きました。半日ほど、作業して、70行程度の小さなクラス、"ProjectBuilder" ができました。使ってみたらかなり便利でした。

ProjectBuilderを実行して、プロジェクト名を入力するだけで、新規のJakartEEプロジェクト（JSF用）ができます。後はそれを開いて使うだけ。簡単です。

**ProjectBuilderは、[《ここ》](https://k-webs.jp/JavaEE/download/builder.zip)からダウンロードできます。**解凍するとbuilderというプロジェクトフォルダができるので、仕事用のプロジェクトを入れるフォルダの中にコピーしておきます。それをNetBeansで開いて、実行すると、次の図のように、"プロジェクト名＞" というプロンプトがでるので、作成したいプロジェクトの名前（ここではsample）を入力します。

![009.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60058/978e21a9-8495-9cfa-d4b3-8d407be9cb3a.png)

これだけで、sampleというプロジェクトがカレントディレクトリにできているので、後は「ファイル」⇒「プロジェクトを開く」で、それを開きます。次の図のようなプロジェクトが生成されていることがわかります。

![008.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60058/29b75acd-a7ce-27c6-dccf-037977f63001.png)

必要と思われる設定ファイルはすべて、最初から入っています。persistence.xmlも、jdbc/mydb というデータソースを使う設定で作成済です。データソース名を変えたいときは、その部分だけ変更します。
　後は、 beansパッケージにバッキングビーンを作成するだけです。 なお、configパッケージには、JSF2.3で必要になる「JSFのバージョンを指定するためのクラス」が入っています。これは設定ファイルのようなものなので、一切触る必要はありません。

#次回のために

当面、もっといいJSF用のarchetypeが出てくるまでは、ProjectBuilderでいいと思います。やってることは同じですからね。

たくさんの古いプロジェクトを、新しいMavenに一括変換するConverterというクラスもつくりました。これは、そのうち、お話しますね。次回は、JDK、NetBeans、Payara serverのインストールと、データベースを利用するための、「データソース」の作り方などを解説します。
AtCoder Beginner Contest 161の復習, E問まで(Python)

競プロ初心者の復習用記事です。

ここで書く解は解説や他の人の提出を見ながら書いたものです。自分が実際に提出したものとは限りません。

# A - ABC Swap

三つの箱の中身を決まった操作で入れ替える問題です。
最初から入れ替え操作の位置は決まっているので、x, y, zをz, x, yと順番を変えて出力するだけです。

```python
x, y, z = map(int, input().split())
print(z, x, y)
```
# B - Popular Vote

N種類の商品内に一定以上の投票数を得た商品がM個以上あるかを探す問題です。

与えられた得票数をソートし、M番目の商品が条件を満たしているか調べました。これで通りました。

```python
N, M = map(int, input().split())
A = list(map(int, input().split()))
A.sort(reverse = True)
if A[M-1] >= sum(A) / (4 * M):
  print('Yes')
else: print('No')
```

# C - Replacing Integer
与えられたNからKを引き続けると最小値はいくらになるか答える問題です。

与えられた数字から引き続けて最後に残る数字...というのは余剰項を求める計算に相当します。一個多く引いた場合、というのはその余剰項からKを引いた値(のマイナス)になります。

以下のコードで実装しました。

```python
N, K = map(int, input().split())
print(min(N%K, K-N%K))
```

# D - Lunlun Number

ルンルン数という条件を満たしているK番目の数字を求める問題です。

パッと見の条件は簡単そうに見えるのですが、K番目の数を効率よく求める方法が全くわからず諦めました。

解説を見ました。この問題では一度使った数の右端にもう一つ条件を満たす数字をつけていくことで高速で求めていくことができます。解説ではキューを使用することでこれを行っていました。

キューにまず1~9までの数字を入れる。左端を取り出し、その値を$x$とする。$x$の1の位を$r$とする。$r$が「0」なら$10x, 10x+1$を計算し、それぞれ再びキューに入れる。同様に$r$が「1~8」なら$10x+(r-1), 10x + r, 10x+(r+1)$、rが「9」なら$10x - 1, 10x$を計算し、再びキューへ。

これを繰り返して、k回目に取り出した値が求める数字です。

というのをそのまま実装してみました。

```python
K = int(input())
Q = [i for i in range(1, 10)]
for _ in range(K):
  x = Q.pop(0)
  r = x%10
  if r != 0: Q.append(x*10 + r - 1)
  Q.append(x*10 + r)
  if r != 9: Q.append(x*10 + r + 1)
print(x)
```
これだとTLE。pop()の速度が遅いようです。取り出す処理はいらないとみて、全て配列のまま保持してforで回してみます。

```python
K = int(input())
Q = [i for i in range(1, 10)]
k = 0
for q in Q:
  if k >= K:
    break
  r = q%10
  if r != 0:
    Q.append(q*10 + r - 1)
    k += 1
  Q.append(q*10 + r)
  k += 1
  if r != 9:
    Q.append(q*10 + r + 1)
    k += 1
print(Q[K-1])
```
これで通りました。

#### 追記

コメントで指摘を受けました。キューを扱う時はちゃんとライブラリを使用しましょう。

pythonでは`collections.deque()`クラスを用いることで、キューを扱うことができます。`append()`, `appendleft()`, `pop()`, `popleft()`などの関数があります。

```python
import collections

K = int(input())
Q = collections.deque([i for i in range(1, 10)])
for _ in range(K):
  x = Q.popleft()
  r = x%10
  if r != 0: Q.append(x*10 + r - 1)
  Q.append(x*10 + r)
  if r != 9: Q.append(x*10 + r + 1)
print(x)
```

# E - Yutori

一定のルールで働く日と働かない日を決めたとき、必ず働く日はどれか答える問題です。

諦めて解説を見ました。

まず、働くことができる日数がノルマに対して余裕ができる場合、もしくはノルマに足りない場合は無条件でアウトになります。

というわけでギリギリまで働く日数を埋めた場合を考えます。まず右端から順番に働ける日を数えた配列Rを作成。この配列には、「$x$回目に働く日は$R[x]$以前である」という情報が含まれます。同様に左端から順番に働く日を数えた配列Lの場合、「$x$回目に働く日は$L[x]$以降である」という情報が含まれます。よって$L[x]$と$R[x]$が一致する時が必ず働く日だといえます。

これを実装したのが以下のコード。これで通りました。

```python
N, K, C = map(int, input().split())
S = input()

L = []
R = []
holiday = 0

for i in range(N):
  if holiday:
    holiday -= 1
  elif S[i] == 'o':
    L.append(i)
    holiday = C
holiday = 0
for i in range(N-1, -1, -1):
  if holiday:
    holiday -= 1
  elif S[i] == 'o':
    R.append(i)
    holiday = C
R = R[::-1]
if len(L) == K:
  for l, r in zip(L, R):
    if l == r: print(l+1)
```
この記事はここまでとします。
タイマー

指定時間後に実行されます

```py
import logging
import threading
import time

logging.basicConfig(level=logging.DEBUG, format='%(threadName)s: %(message)s')

def worker(x, y=1):
    logging.debug('start')
    logging.debug(x)
    logging.debug(y)
    time.sleep(2)
    logging.debug('end')


if __name__ == '__main__':
    t = threading.Timer(3, worker, args=(100,), kwargs={'y': 200})
    t.start()
```

```txt
Thread-1: start
Thread-1: 100
Thread-1: 200
Thread-1: end
```
threading.enumerate

threading.enumerateで生存中のThreadオブジェクト全てのリストを取得できます。

```py
import logging
import threading
import time

logging.basicConfig(level=logging.DEBUG, format='%(threadName)s: %(message)s')


def worker1():
    logging.debug('start')
    time.sleep(5)
    logging.debug('end')

if __name__ == '__main__':
    #threads = []
    for _ in range(5):
        t = threading.Thread(target=worker1)
        t.setDaemon(True)
        t.start()
        #threads.append(t)

    for thread in threading.enumerate():
        if thread is threading.currentThread():
            print(thread)
            continue
        thread.join()
```

```txt
Thread-1: start
Thread-2: start
Thread-3: start
Thread-4: start
Thread-5: start
<_MainThread(MainThread, started 4599717312)>
Thread-1: end
Thread-2: end
Thread-5: end
Thread-4: end
Thread-3: end
```
IQ Botのカスタムロジック：パターンの決まった文字化けの補正、空欄埋め、形式変換、ノイズの除外（置換処理）

IQ Botのカスタムロジックの概要について、先日以下の記事でご紹介しました。

https://qiita.com/IQBotter/items/67694b1b0d1376ede7e7

カスタムロジックはPythonというプログラミング言語そのものではあるんですが、
プログラミングの知識がないと使いこなせないかというと、そんなことはありません。

この記事では、コード自体は簡単ですが実際に業務で使う８～９割を占める
「置換」の処理について、コードと使用例をご紹介していきます。

上記の記事でもご紹介したとおり、
フィールド項目とテーブル項目で若干考え方が違うので、それぞれ紹介します。

#フィールド項目に対する置換処理

まずはより基本編となるフィールド項目から。

置換のロジックはめちゃ簡単ですが、実際に業務で使うカスタムロジックの８～９割はこれです。

##基本のコード

```python:フィールド項目に対する置換の処理
field_value = field_value.replace("置換前の文字列","置換後の文字列")
```

以下のように改行して、同じ項目に対して複数の置換処理を定義することが可能です。

```python:改行すれば複数の定義OK
field_value = field_value.replace("置換前の文字列１","置換後の文字列１")
field_value = field_value.replace("置換前の文字列２","置換後の文字列２")
```

たったこれだけのコードですが、以下のようにいろいろ応用できます。

##置換処理の使い道いろいろ

- 空欄を埋める

`field_value.replace(" ","")`で、空欄を埋められます。

余談ですが、IQ Botは改行ありの値を読み込んだ場合に、仕様として改行部分が空欄に変換されます。

- オーと読まれた文字をゼロに変換（パターンの決まった文字化けの補正）

`field_value.replace("O","0")`で、オーをゼロに変換できます。

同じ要領で、

l（エル）やI（アイ）や|（パイプライン）を1（いち）に置き換えたり、
棘を東京に置き換えたり、
▲で表記されたマイナスをマイナス符号に置き換えたりなど、

いろいろできます。

- 形式の変換

「2020年4月6日」を「2020/4/6」のような形式に直したい場合も、置換で対応できます。

```python:日付の形式変換の例
field_value = field_value.replace("年","/") 
field_value = field_value.replace("月","/") 
field_value = field_value.replace("日","") 
```

- ノイズの除外

OCRで帳票を処理すると、紙の汚れや人がボールペンでチェックしたマークなどが、
ピリオド、カンマ、コロン、セミコロン、スラッシュ、クオーテーション、ダブルクオーテーション 等々の
ノイズとして読み込まれてしまうケースが多々あります。

そうした記号が不要な項目であれば、`field_value.replace("除外したいノイズ","")`でノイズの除外ができます。

なお、置換前の文字列や置換後の文字列は、
ダブルクオーテーション（"）かシングルクオーテーション（'）のどちらかで囲まれていれば大丈夫です。

除外したいノイズ自体にダブルクオーテーションやシングルクオーテーションが入っている場合は、
以下のように定義すれば大丈夫です。

```python:除外したいノイズじゃない方のクオーテーションで囲む

#シングルクオーテーションを除外する場合は、ダブルクオーテーションで囲む
field_value = field_value.replace("'","") 

#ダブルクオーテーションを除外する場合は、シングルクオーテーションで囲む
field_value = field_value.replace('"',"") 
```

#テーブル項目に対する置換処理

テーブル項目の場合は、ちょっと書き方が変わりますが、それでも簡単です。

[こちら](https://qiita.com/IQBotter/items/67694b1b0d1376ede7e7#%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E9%A0%85%E7%9B%AE%E3%81%AE%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%A0%E3%83%AD%E3%82%B8%E3%83%83%E3%82%AF%E3%81%AF%E3%81%A9%E3%81%86%E6%9B%B8%E3%81%8F)で説明した「おまじないコード」の間に・・・

このように↓書きます。

```python:テーブル項目に対する置換の処理
df['列名'] = df['列名'].str.replace('置換前の文字列', '置換後の文字列')
```

列名はIQ Botで帳票設定するときに定義したこちら↓の列名をそのまま使います。

![Qiita用.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587845/959b84bb-4b95-f4df-788c-39868e0c54e1.jpeg)

日本語の列名でも普通に動きますが、
列名にスペースが含まれている場合は、スペースはアンスコ(_)に置き換えます。

例えば上記の「金額」と「金額 税込」の列から、「円」という単位を除外したい場合は以下のように処理します。

```python:フィールド項目に対する置換の処理
df['金額'] = df['金額'].str.replace('円', '')
df['金額_税込'] = df['金額_税込'].str.replace('円', '')
```

#まとめ

- 置換の処理は簡単だけど、業務で使うカスタムロジックのほとんどはこれだよ
- 置換処理の仕組みを使って、パターンの決まった文字化け補正や空欄埋め、ノイズの除外などいろいろできるよ
- テーブルの場合は列名を指定するよ
- テーブルの列名にスペースが含まれている場合は、アンスコ(_)に置き換えるよ

いかがでしたか？

置換処理を適切に使うと、簡単にインプットデータの質を上げられて自動化がしやすくなるので、ぜひ試してみてください！
Gitpod上でtexを書く

VS Codeでtexを書きたいけどローカルにtexliveをインストールするのは面倒。
かといって既存のクラウドサービスだとVS Codeが使えない、という人は結構いるはず。
そこでVS Codeと同等のUIを持つクラウドIDEである Gitpod上でtexliveを動かしてみました（以下のスクリーンショット）。
<img width="1400" alt="スクリーンショット 2020-04-06 9.25.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241781/067e0cd8-5ffa-254f-bc84-f3164a909813.png">

まずはローカル(VS Code) と latexのクラウドサービスを比較してみます。

### ローカル (VS Code)
- メリット
 - 最強のエディタであるVS Codeが使える (筆者の感想)
 - latex workshopなどの強力なプラグイン
- デメリット
 - texliveのインストールが面倒

### Texクラウドサービス
- メリット
    - texliveのインストール不要
- デメリット
    - 好きなエディタが使えない
   

ストレスの溜まりがちな論文執筆において、お気にいりのエディタを使えることは快適な執筆のために重要でしょう
特にVS Codeはプラグインによる強力な補完機能の恩恵を受けることができます。
一方で[CloudLatex](https://cloudlatex.io/)や[Overleaf](https://overleaf.com/)などのクラウドサービスはアカウントを作成するだけですぐに使える一方、補完機能などの面でやや劣るといえるでしょう。
そこで[Theia](https://theia-ide.org/)というエディタのクラウド版であるGitpod上でtexliveを動かします。Gitpodはベータ機能ながらVS Codeのプラグインをインストールして使うことができます。

## Gitpodでtex環境構築
TheiaはVS Codeに非常によく似たUIを持ち、ローカルアプリとWebアプリの両方で動くことを念頭に開発されているようです。
Gitpodは以下のように`#`のあとにgithubなどのレポジトリを指定して簡単にプロジェクトを立ち上げることができます。


https://gitpod.io/#https://github.com/moritanian/gitpod-latex

`.gitpod.yml`という設定ファイルによってdockerファイルを指定してそこから立ち上げることが可能です。
そこで、texliveの含まれるdockerイメージを指定することでGitpod上でlatexコマンドを使えるようにします。
今回は[こちら](https://github.com/Paperist/docker-alpine-texlive-ja)の最小限のtexliveの構成のものを利用しましたが必要によってはフルバージョンのtexliveを利用すればよいでしょう。
上記のURLの#以降のレポジトリが今回用意したテンプレートプロジェクトです。
上記URLからgitpodでプロジェクトを立ち上げることができます。
プロジェクトではターミナルからlatexコマンドが使えます。
また、LatexWorkshopプラグインにより補完機能やオートコンパイルも可能です。

## 評価
ローカルへのtexliveのインストールなしでVS Codeと同等の補完機能や自動コンパイルを行うことができました。
しかしながら現時点ではsynctexなど一部の機能を使うことができませんでした。
また、Gitpodは無料枠だと月50時間までしか動かせなかったりと制限が大きいようです。
常用使いは厳しいという印象ですが、tex環境を模索中の人は試しに使ってみるのはいかがでしょうか？
Firestoreで条件を絞ってデータを削除する


SQLではよくある、 `DELETE FROM [テーブル名]　WHERE [条件];` をFirestoreで実現する方法について書いてみようと思う。


## そもそも `DELETE FROM [テーブル名]　WHERE [条件];` はFirestoreには用意されていない。

そもそも `DELETE FROM [テーブル名]　WHERE [条件];` はFirestoreでは実行できません。

なので、  **whereで消したいデータを取得してそれを一件一件削除していくという実装** になる。


## 実装

実装方法は下記になる。今回はサンプルコードではTypeScriptを使っているが、適宜読み変えてください。


```typescript

const query: FirebaseFirestore.QuerySnapshot = await db
    .collection("timeline")
    .where("uid", "==", followUserId)
    .get();

query.docs.forEach(async doc => {
    await doc.ref.delete();
});

```

以上です。
Laravelのroutingでprefixにパラメーターを入れる事ができる

LaravelでRestAPIライクなURLを設定する時には、prefix内にパラメーターを設定すると子のroute側でパラメーターが受け取れます。

# 例
/posts/{id}/comments
/posts/{id}/recommends

というようなAPIを作成するとします。

以下のようにしてRouteのところにidを入れてURLを指定することも出来ますが、

```api.php
Route::prefix('posts')->group(function () {
    Route::get('/{id}/comments', 'PostController@comments');
    Route::get('/{id}/recommends', 'PostController@recommends');
});
```

以下のようにprefixにパラメーターを入れる形でもControllerのメソッド側でidをパラメーターとして受け取ることが出来ます。

```api.php
Route::prefix('posts/{id}')->group(function () {
    Route::get('/comments', 'PostController@comments');
    Route::get('/recommends', 'PostController@recommends');
});
```
Rails 日付、時間入力のヘルパーメソッド ６種類

# 環境
・OS
　Vagrant + Ubuntu 16.04.5 LTS

・言語
　Rails 5.2.4.2
　Ruby 2.5.1p57

・gem
　Bootstrap4
　slim

# 紹介
Railsで用意されている、日付、時間入力に関するヘルパーメソッドを６種類の紹介。
大きく、**xxxx_select**と、**xxxx_field**と２種類あります。

## ○ xxxx_select
**xxxx_select**は、年、月、日と各項目ごとにテキストフィールドが分割されます。また、カレンダー入力はできなく、プルダウンメニューから選択する事になります。

### data_select
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94029/f5be009d-e08d-6b61-b3c9-9253e75e305b.png)

```
    .form-group
        = f.label :created_at, class: 'control-label'
        = f.date_select :created_at, class: 'form-control'
```

### time_select
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94029/c4309e5c-8f6b-6fe9-350e-e1d273ff932a.png)

```    .form-group
        = f.label :created_at, class: 'control-label'
        = f.time_select :created_at, class: 'form-control'
```
### datetime_select

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94029/664d8a9d-a847-506f-998d-7f2e0cd31a2d.png)

```
    .form-group
        = f.label :created_at, class: 'control-label'
        = f.datetime_select :created_at, class: 'form-control'
```

## ○ xxxx_field
**xxxx_field**は、年、月、日等のテキストフィールドが１つにまとまっており、カレンダー入力ができるようになっています。こっちの方がモダン？

### date_field
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94029/b74fc613-5431-d7af-ae4d-a482bdb0ea26.png)

```
    .form-group
        = f.label :created_at, class: 'control-label'
        = f.date_field :created_at, class: 'form-control'
```

### time_field
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94029/85e4d5d9-ff3a-bcba-ebd0-320c628ea522.png)

```
    .form-group
        = f.label :created_at, class: 'control-label'
        = f.time_field :created_at, class: 'form-control'
```

### datetime_field
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94029/7970cef9-d87b-d078-2c18-ecb6ab853a47.png)

```
    .form-group
        = f.label :created_at, class: 'control-label'
        = f.datetime_field :created_at, class: 'form-control'
```
# 補足
横並びにしたい場合は、**.form-inline**をつけます。**.text-left**をつけると左寄りになって、ラベル位置が上下の項目と揃います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94029/d947db90-cf98-fd60-f1df-576d9b66ec6d.png)

```
    .form-inline.text-left
        .form-group
            = f.label :created_at, '登録日　', class: 'control-label'
            = f.date_field :created_at, class: 'form-control'

        .form-group
            = f.label :created_at, '　　登録時間　', class: 'control-label'
            = f.time_field :created_at, class: 'form-control'
```
便利なdiffコマンド使い方

## ファイルを比較する
```
diff {ファイルA} {ファイルB}
```

## 差分に!をつけて比較する
```
diff -c {ファイルA} {ファイルB}
```

## 大文字と小文字を区別せずに比較する
```
diff -i {ファイルA} {ファイルB}
```

## ファイルが同一の場合、同一と表示する
```
diff -s {ファイルA} {ファイルB}
```

## ファイルの中身が異なる場合、中身を表示せずに異なると表示する
```
diff -q {ファイルA} {ファイルB}
```

## 空白を無視してファイルを比較する
```
diff -w {ファイルA} {ファイルB}
```

## ディレクトリごと比較する
```
diff -r {ディレクトリA} {ディレクトリB}
```

## 中身を表示せずにディレクトリごと比較する
```
diff -rq {ディレクトリA} {ディレクトリB}
```
SlackClient(python)のWEB Hometab機能を書いてみた。

##　概要
SlackAPI v2から追加された、[HOME TAB機能](https://api.slack.com/surfaces/tabs)について、python-slackclientで使えるクラスを書いてみた。
プルリクする自信がないのでここにメモする。

```python

class HomeTab(JsonObject):
   """Create Home Tab JsonObject

   https://api.slack.com/surfaces/tabs/using#publishing

   Args:
      blocks: ホームタブを構成するブロック要素
   """
   attributes = {"view"}

   def __init__(self, *, blocks: Optional[List[blocks.Block]] = None):
      self.subtype = "home"
      self.blocks = blocks

   def to_dict(self):
      json = super().to_dict()
      json["type"] = self.subtype
      json["blocks"] = extract_json(self.blocks)
      return json
```
競プロのライブラリ整理~Union-Find木~

Union-Find木の解説は[こちらの記事](https://qiita.com/ofutonfuton/items/c17dfd33fc542c222396)などを参照してください。バグや利便性を高められる余地などがあればコメントで教えていただけるとありがたいです。
また、マクロやFOR文の略記を使用しているので、[こちらの記事](https://qiita.com/DaikiSuyama/items/9dba963ba74396b9b7fd)の競プロ用のテンプレートと併せて使用してください。

###修正(2020/08/27)
grouping関数で親ごとで素集合に分割する際に任意の頂点で経路圧縮を行う必要があるのを忘れていたため、バグが発生していました。
また、コード中のコメントアウトを一部修正しました。

###追記(2020/09/24)
要素数をメンバ変数に加えました。
また、素集合系を使い回すためにclear関数を導入しました。
後、気が向いたらtemplate引数に書き直そうと思います。



```c++:unionfind.cc
//以下、素集合と木は同じものを表す
class UnionFind{
public:
    vector<ll> parent; //parent[i]はiの親
    vector<ll> siz; //素集合のサイズを表す配列(1で初期化)
    map<ll,vector<ll>> group; //集合ごとに管理する(key:集合の代表元、value:集合の要素の配列)
    ll n; //要素数

    //コンストラクタ
    UnionFind(ll n_):n(n_),parent(n_),siz(n_,1){ 
        //全ての要素の根が自身であるとして初期化
        for(ll i=0;i<n;i++){parent[i]=i;}
    }
    
    //データxの属する木の根を取得(経路圧縮も行う)
    ll root(ll x){
        if(parent[x]==x) return x;
        return parent[x]=root(parent[x]);//代入式の値は代入した変数の値なので、経路圧縮できる
    }
    
    //xとyの木を併合
    void unite(ll x,ll y){
        ll rx=root(x);//xの根
        ll ry=root(y);//yの根
        if(rx==ry) return;//同じ木にある時
        //小さい集合を大きい集合へと併合(ry→rxへ併合)
        if(siz[rx]<siz[ry]) swap(rx,ry);
        siz[rx]+=siz[ry];
        parent[ry]=rx;//xとyが同じ木にない時はyの根ryをxの根rxにつける
    }

    //xとyが属する木が同じかを判定
    bool same(ll x,ll y){
        ll rx=root(x);
        ll ry=root(y);
        return rx==ry;
    }

    //xの素集合のサイズを取得
    ll size(ll x){
        return siz[root(x)];
    }
    
    //素集合をそれぞれグループ化
    void grouping(){
        //経路圧縮を先に行う
        REP(i,n)root(i);
        //mapで管理する(デフォルト構築を利用)
        REP(i,n)group[parent[i]].PB(i);
    }

    //素集合系を削除して初期化
    void clear(){
        REP(i,n){parent[i]=i;}
        siz=vector<ll>(n,1);
        group.clear();
    }
};
```
並列化

```py
import logging
import threading
import time

logging.basicConfig(level=logging.DEBUG, format='%(threadName)s: %(message)s')


def worker1():
    logging.debug('start')
    time.sleep(5)
    logging.debug('end')


def worker2(x, y=1):
    logging.debug('start')
    logging.debug(x)
    logging.debug(y)
    time.sleep(2)
    logging.debug('end')


if __name__ == '__main__':
    t1 = threading.Thread(name='rename worker', target=worker1)
    t1.setDaemon(True) 
    t2 = threading.Thread(target=worker2, args=(100,), kwargs={'y': 200})
    t1.start()
    t2.start()
    print('started')
    t1.join() #worker1の処理が終わるまで待つ。これがないと先のt2が終了した時点でプログラムが終了してしまう
    t2.join() #デーモン化していないので書かなくてもいい
```

```txt:出力
rename worker: start
Thread-1: start
Thread-1: 100
Thread-1: 200
started
Thread-1: end
rename worker: end
```