OmniAICreator/Qiita-1.07M huggingface dataset:
ページ内リンクが固定ヘッダーに被るのを防ぐ

# 概要
fixedやstickyなどで作った固定ヘッダーがある場合、ページ内リンクへ飛んだ際にコンテンツと被ってしまいます。
これを解決する方法を紹介します。

# 解決方法
cssの `scroll-margin-top` を使います。
`scroll-margin-top` を使うとスクロールにmarginを追加する、みたいなことができるようになります。

イメージとしてはこんな感じになります。
これでページ内リンクへ飛んだ際に100px分多めにスクロールするので、ヘッダーと被らずコンテンツが表示されます。

```css
header {
  position: sticky;
  top: 0;
  width: 100%;
  height: 100px;
}

.anchor-item {
  scroll-margin-top: 100px;
}
```

# 対応ブラウザ
`scroll-margin-top` はIEには対応していません。
IEに対応するなら別の方法をとる必要があります。

# 参考リンク
https://developer.mozilla.org/ja/docs/Web/CSS/scroll-margin-top
Sequelizeでテーブルのカラム名を変更する際の手順

Sequelizeを利用していて、テーブル中のカラム名を変更した際のメモ・言語化です。

# 新しくmigrationファイルを作成する
```ruby:local
$ npx sequelize migration:create --name Users#(モデル名）
```

migrationsディレクトリに以下のようなmigarationファイルが生成されます。

```ruby:
'use strict';

module.exports = {
  up: async (queryInterface, Sequelize) => {
    /**
     * Add altering commands here.
     *
     await queryInterface.renameColumn( 'Users', 'name', 'brandName' ) 
     * Example:
     * await queryInterface.createTable('users', { id: Sequelize.INTEGER });
     */
  },

  down: async (queryInterface, Sequelize) => {
    /**
     * Add reverting commands here.
     *
     * Example:
     * await queryInterface.dropTable('users');
     */
  }
};
```

今回はカラム名変更なのでupにコードを記載します。

```ruby:1220....js
'use strict';

module.exports = {
  up: async (queryInterface, Sequelize) => {
    await queryInterface.renameColumn( 'Users', 'name', 'brandName' );#追記
  },

  down: async (queryInterface, Sequelize) => {
    /**
     * Add reverting commands here.
     *
     * Example:
     * await queryInterface.dropTable('users');
     */
  }
};

```

```ruby:
await queryInterface.renameColumn( 'Users'(モデル),'name'(変更前),'brandName'(変更後) );
```

最後に db:migrateします。

```ruby:local
$ npx sequelize db:migrate
Sequelize CLI [Node: 14.4.0, CLI: 6.2.0, ORM: 6.3.5]

Loaded configuration file "config/config.json".
Using environment "development".
== 20201220000000-Users: migrating =======
== 20201220000000-Users: migrated (0.024s)
```
```ruby:MySQL
mysql> SHOW COLUMNS FROM Users;
+--------------+--------------+------+-----+---------+----------------+
| Field        | Type         | Null | Key | Default | Extra          |
+--------------+--------------+------+-----+---------+----------------+
| id           | int          | NO   | PRI | NULL    | auto_increment |
| brandName    | varchar(255) | YES  |     | NULL    |                |
| createdAt    | datetime     | NO   |     | NULL    |                |
| updatedAt    | datetime     | NO   |     | NULL    |                |
+--------------+--------------+------+-----+---------+----------------+
8 rows in set (0.01 sec)
```
name→brandNameに変更されたことを確認できました。
M1 Macのdocker previewでWordPressを動かしてみた。

#docker previewが一般公開されたのでテストしたかった。

M1 Macのdocker previewが出たので早速テストしてみた。
普段はVPSのWordPressで開発を行なってるが、ローカルで動かしてみる。
なお、[localbyflywheel](https://localwp.com)が既にSilicon対応済みなので、
WordPressの開発だけであればそちらの方が楽だと思う。

dockerをDLした場所
https://www.docker.com/blog/download-and-try-the-tech-preview-of-docker-desktop-for-m1/

参考
https://docs.docker.jp/compose/wordpress.html


## まずは何も考えずにdocker-compose

docker-testというフォルダにdocker-compose.ymlを作って上記参考アドレスからコピペ

```docker-compose.yml
version: '3'

services:
   db:
     image: mysql:5.7
     volumes:
       - db_data:/var/lib/mysql
     restart: always
     environment:
       MYSQL_ROOT_PASSWORD: somewordpress
       MYSQL_DATABASE: wordpress
       MYSQL_USER: wordpress
       MYSQL_PASSWORD: wordpress

   wordpress:
     depends_on:
       - db
     image: wordpress:latest
     ports:
       - "8000:80"
     restart: always
     environment:
       WORDPRESS_DB_HOST: db:3306
       WORDPRESS_DB_USER: wordpress
       WORDPRESS_DB_PASSWORD: wordpress
volumes:
    db_data:
```


```
$ docker-compose up     
Creating network "docker-test_default" with the default driver
Pulling db (mysql:5.7)...
5.7: Pulling from library/mysql
ERROR: no matching manifest for linux/arm64/v8 in the manifest list entries
```
　
mysqlをpull中に ```ERROR: no matching manifest for linux/arm64/v8```　が出てる。

## docker-imageでもarm_64対応が必要らしい

docker hubの[mysql](https://hub.docker.com/_/mysql)を確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65643/e6db2311-8798-80c7-0828-79c86f54b4ad.png)

x86-64のみでarm64がないから動かないっぽい。

## mysqlからmariadbに変更

[mariadb](https://hub.docker.com/_/mariadb)を確認してみる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65643/e2c885b8-81c4-6b4a-cae8-a6a82b4df18a.png)

行けそう。docker-compose.ymlを一部変更

```docker-compose.yml
version: '3'

services:
   db:
     image: mariadb
     volumes:
       - db_data:/var/lib/mysql
     restart: always
     environment:
       MYSQL_ROOT_PASSWORD: somewordpress
       MYSQL_DATABASE: wordpress
       MYSQL_USER: wordpress
       MYSQL_PASSWORD: wordpress

   wordpress:
     depends_on:
       - db
     image: wordpress:latest
     ports:
       - "8000:80"
     restart: always
     environment:
       WORDPRESS_DB_HOST: db:3306
       WORDPRESS_DB_USER: wordpress
       WORDPRESS_DB_PASSWORD: wordpress
volumes:
    db_data:
```

db:imageの部分を```mysql:5.7```から```mariadb```に置き換えた


```
$ docker-compose up
```

エラー出なかったのでlocalhost:8000をブラウザで開く。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65643/9aae5db8-416b-965f-92ce-d8e1fd2d0e90.png)

動いた。ログインも問題なかったです。


#おまけ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65643/6ae8ef0f-c71f-36ad-488a-d51338210e89.png)

アクティビティモニタだと、Docker DesktopはintelでDockerコアのみappleになっている模様。
まだそれほど動かしてないけど、CPU使用率もメモリ使用率もそれほどでもない。
初回起動は少し時間がかかったが、ブラウザが爆速なので快適。
Raspberry Pi4の開発をApple Silicon (M1) MacBookでやろう。（aarch64編）

# 注意： 2021-10-28

macOS Monterey にアップデートしたら ACVM.app が起動しなくなりました。

![スクリーンショット 2021-10-28 10.21.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154910/d7088be7-eac2-db91-d386-e6e83dc0fab1.png)

# Introduction

Ubuntu (aarch64)をApple Silicon (M1) MacBook Air + QEMU上で動かして、Raspberry Pi4の開発に使おうというもの。

![スクリーンショット 2020-12-20 8.43.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154910/cef9e97d-21f4-4c28-4238-b6b93aa97d4a.png)

[M1でLinux仮想を動かす(QEMU)](https://qiita.com/bellx2/items/c06e1c00ad9de77a4fb9)に触発されました。(Windows10も動くらしいが私はやらない）

[Build OpenVINO-2021.1, OpenCV-4.5.1-pre on Raspberry Pi4 / Ubuntu 20.10 (aarch64)](https://qiita.com/kose3/items/5b390ef2e6d75fdac9e1)のようなビルドがApple Silicon (M1)上で時間短縮できます。

# Environment

- Apple Silicon (M1) MacBook Air
- [ACVM.app](https://github.com/KhaosT/ACVM/releases/) (QEMU)
- Raspberry Pi4 + Ubuntu (aarch64)
- [Resilio](https://www.resilio.com/individuals/) (file sync)

# setup Ubuntu (aarch64) on ACVM

1. https://github.com/KhaosT/ACVM/releases / ACVM.zip を使う。
2. ACVM.app/Contents/Resources/qemu-img create -f qcow2 disk.img 32G  でディスクイメージ作成
3. https://cdimage.ubuntu.com/focal/daily-live/current / focal-desktop-arm64.iso 
4. ACVM 起動。CPU 4、RAM 4G、Display virtio-gpu、Main Imageに disk.img を CD Image に focal-desktop-arm64.iso を D&D
5. start
6. Ubuntuを通常どおりにインストール
7. Resilio setup

Mac側でブリッジ設定などなどやりたくなかったのでfile syncソフトを使いました。
なんなら、Raspberry piのホームディレクトリ丸ごとsyncしても良いと思う。(ssh & rsync より運用が簡単）

# resilio-sync

aptで入れます。

```
echo "deb http://linux-packages.resilio.com/resilio-sync/deb resilio-sync non-free" | sudo tee /etc/apt/sources.list.d/resilio-sync.list
wget -qO - https://linux-packages.resilio.com/resilio-sync/key.asc | sudo apt-key add -
sudo apt update
sudo apt install resilio-sync
```

Run resilio-sync usermode. ユーザで起動した方が使い勝手が良いです。


```
sudo systemctl stop resilio-sync
systemctl start --user resilio-sync
```

http://localhost:8888/gui で共有ディレクトリの設定をやります。


# Reference

- [Resilio Syncをインストールする方法](https://kb.seeck.jp/archives/16081)

# TODO

armv7編 もやりたいかも。（必要にせまられてないのでやらないだろう。。。）
【Three.js】3Dオブジェクトのマウスオーバーを判定。

![text7.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276138/d4baeddc-0894-ca4c-c7b6-99aa7944761e.gif)
# マウスオーバーした3Dオブジェクトを回転させる

現時点で最新版のThree.js（r123）を使っています。
Three.jsと、以下のcodepenのjsコードさえあれば簡単に実装できます。

コード内に解説は詳しく書いたので、読んで、いじったりしてみてください。

<p class="codepen" data-height="665" data-theme-id="light" data-default-tab="js,result" data-user="yamkaz" data-slug-hash="bGwRXeV" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="ThreeJS: Box Geometry + MouseHover">
  <span>See the Pen <a href="https://codepen.io/yamkaz/pen/bGwRXeV">
  ThreeJS: Box Geometry + MouseHover</a> by やまかず / Kazuyuki Yamamoto (<a href="https://codepen.io/yamkaz">@yamkaz</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://production-assets.codepen.io/assets/embed/ei.js"></script>


情報源:
[Three.jsのRaycasterを使って、画面内のオブジェクトを得る](https://qiita.com/edo_m18/items/5aff5c5e4f421ddd97dc)
[Raycaster – three.js docs](https://threejs.org/docs/#api/en/core/Raycaster)
[WebGL開発に役立つベクトルの足し算・引き算 （Three.js編）](https://ics.media/entry/15043/)
[【Unity】RayCastを使いこなせ!判定や表示に使ってみよう](https://www.sejuku.net/blog/83620#:~:text=raycast%E3%81%A8%E3%81%AF%E6%8C%87%E5%AE%9A%E3%81%97%E3%81%9F,%E3%81%99%E3%82%8B%E6%A9%9F%E8%83%BD%E3%81%AE%E3%81%93%E3%81%A8%E3%81%A7%E3%81%99%E3%80%82)
supervisordを使用してコンテナ内でsshdをroot権限、JupyterLabをユーザー権限で動作させるためのDockerfileなど

# はじめに
記事の内容の概要を書く

# 目次
- 項目1
- 項目2
- 項目3

# 1. 項目1
## Dockerfile

```text:Dockerfile
FROM ubuntu:20.10

## define these environment variables for installing git silently
ENV TZ=Asia/Tokyo DEBIAN_FRONTEND=noninteractive

RUN apt-get update && apt-get upgrade -y && \
    apt-get install -y \
    git \
    imagemagick \
    libsm6 \
    libxext6 \
    libxrender-dev \
    libglib2.0-0 \
    openssh-server \
    sudo \
    supervisor \
    wget \
    vim


## customized bellow

ARG USER_ID
ARG USER_NAME

COPY supervisord.conf /etc/supervisor/conf.d/
RUN sed -i s/USERNAME/$USER_NAME/g /etc/supervisor/conf.d/supervisord.conf && \
    sed -i 's/#X11UseLocalhost yes/X11UseLocalhost no/' /etc/ssh/sshd_config && \
    mkdir -p /var/run/sshd /var/log/supervisor && \
    useradd -m -u $USER_ID -s /bin/bash $USER_NAME

#install miniconda ${USER_NAME} locally

# download miniconda package and install miniconda

# set path
ENV PATH /home/$USER_NAME/miniconda3/bin:$PATH

WORKDIR /home/$USER_NAME

USER ${USER_NAME}

# download & install Miniconda3-py38_4.9.2-Linux-x86_64.sh (2020/11/23)
RUN wget https://repo.anaconda.com/miniconda/Miniconda3-py38_4.9.2-Linux-x86_64.sh && \
    sh ./Miniconda3-py38_4.9.2-Linux-x86_64.sh -b -p /home/$USER_NAME/miniconda3 && \
    rm -f ./Miniconda3-py38_4.9.2-Linux-x86_64.sh && \
    echo "export PATH=/home/$USER_NAME/miniconda3/bin:${PATH}" >> /home/$USER_NAME/.bashrc && \
    conda update -n base -c defaults conda -y && \
    conda install numpy scipy pandas seaborn matplotlib jupyter jupyterlab pip -y && \
    conda install flake8 lightgbm -y && \
    conda install nodejs -y && \
    conda install jupytext xgboost optuna -c conda-forge -y && \
    jupyter lab build && \
    pip install --upgrade pip && \
    pip install opencv-python && \
    pip install nibabel \
    pip install japanize-matplotlib

WORKDIR /

USER root

CMD ["/usr/bin/supervisord"]
```
## supervisord.conf
```conf:supervisord.conf
[supervisord]
nodaemon=true

[program:sshd]
command=/usr/sbin/sshd -D

[program:jupyterlab]
command=/bin/bash -c "export PATH=/home/USERNAME/miniconda3/bin/:${PATH}; /home/USERNAME/miniconda3/bin/jupyter lab --ip=0.0.0.0 --allow-root --LabApp.token='' "
user=USERNAME
environment=HOME=/home/USERNAME, USER=USERNAME
```


## docker-compose.yml

```yaml:docker-compose.yml
version: '3'

services:
  base:
    build:
      context: .
      args:
        USER_ID: ${USER_ID}
        USER_NAME: ${USER}
    image: ${USER}/myimage
    ports:
      - '2022:22'
      - '8888:8888'
    volumes:
      - '~/.ssh:${HOME}/.ssh'
      - '~/src:${HOME}/src'
```



# 2.項目2

```text
```

# 3.項目3
- あれや
- これや
初心者２人がかりでGASに挑戦してみたら地獄を見た

前回の記事は @syk_nakayama  さんの[フィッシングメールが届いたので踏んでみた](https://qiita.com/syk_nakayama/items/78cf93da48b97f57f696) でした。
明日の記事は @arakawa_moriyuki  さんです。

**はじめに**
------
こんにちは、サービスデスクの@T_melですｍｍ
ユーザーさんのお困りごとを解決するために奮闘中の私達サービスデスクがアドベントカレンダーに初参戦です
超絶初心者のため表現などが分かりづらいと思いますが、温かい目で見守っていただけると幸いです！
協力者：伊禮氏、他サービスデスク沖縄メンバー

**さて何からはじめよう**
-----
とある業務にて、私が対応漏れを多発させたことをきっかけに、自動化しちゃおうぜ☆的な話が丁度あがったので
「GASだ！！SCRIPTだ！」となったわけですが、、、（SCRIPTが何なのかもよくわかっていない←）
スクリプトエディタも開いたことのない超初心者なのです。「エディタとやらはどこから開くのかしら…」から始まりました。
まずはゴールを決めないと作業も始められないので以下２点をこの記事を上げるまでに達成することに決定！
> ・マスタデータからの転記
　└理想は特定ワードに紐づく情報を転記
・スクリプト実行ボタンを作りたい

そして前提として、己の力のみでどこまで出来るか挑戦！ということです。
（ありがたいことに開発の方から”いつでも相談しておくれ”とのお声もいただき心揺れました。感謝！）

**まずはスクリプトエディタを触ってみる**
-----
入門書片手にお決まりの"Hello world"をやってみました。
![hello.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/886790/5254f0f8-6b84-47bd-fc4a-23eed02779b3.png)
結果↓
![hello_結果.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/886790/25a99b73-f6da-03c4-d899-470723dcdf1f.png)
ここまでは大丈夫。一通り入門編にも目を通したことだしマスタシートのコードを読んでみようとなったのですがエディタを開いた瞬間絶望。
メインを探すのに一苦労。私達の業務効率化はこういう地道な作業をしてくれている人の元成り立っているのだと
改めて感謝し、今回は時間がないので読み解くのは宿題とういうことになりました。

**シートに転記に挑戦**
-----
やっとここで転記作業に取り掛かかり、完成したのがこちら。
![転記.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/886790/927f1921-a628-ef1e-cc8d-1d6992c365a0.png)
力技でシートの指定まではなんとかできました。、
①ワークブックの取得
　└別のワークブックからデータを取得したかったのでIDで指定
②更に取得ワークブックの中からシートを指定
③セル範囲を取得する: getRange( rowIndex, colIndex, numRows, numCols )
④値を取得する: getValue

　```getRange```でセルの範囲を取得できることはなんとか分かったのですが、get●●●●,get●●●●sが複数あるためどの組み合わせが良いのか悩みました。複数のセルの情報を二次元配列で取得できるメソッドが書ければよかったのですがこちらも今後の課題です。

**ボタンを表示！**
-----
ここの作業はとても簡単！
入門書にも初歩の初歩で出てきます。書いたコードがこちら↓
![実行ボタン_coad.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/886790/e5a942ec-d540-e0c5-0462-cc074f29bbcf.png)
使用したのはSimple TriggersのonOpen(e)です。
onOpenでメニューを追加するとスプレットシートを開いたときに、カスタムメニューを追加することができます。
今回は読込み実行を押すと、先程のシートに転記のfunctionが実行されます。今回は一つだけですが、複数の実行指定ができるのでとても便利。
実際に追加されたのがこちら↓
![実行ボタン.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/886790/4bca8490-8c8b-17f8-b8f9-040644def102.png)
無事に表示されました～！！


**まとめ**
-----
たった10行ほどのコードを書くのにここまで苦労するとは思いもしませんでした。
実際にやってみて感じたのですが、サンプルコードなどネットで沢山見かけましたが、一つの結果を求めるにしても多種多様な
方法があるのでとても興味深かったです。これからの業務のためにもきちんと学んでいきたいと思います。
forやifを使って、情報の選別をして転記しようかなと奮闘中ですが、その前に二次元配列についても勉強せねばと思っております…。

読みにくい部分が多々あったと思いますが、最後までご拝読いただきありがとうございました！！


> **参考文献**


詳解! GoogleAppsScript完全入門 ~GoogleApps & G Suiteの最新プログラミングガイド~ (日本語) 
https://www.yukibnb.com/entry/gas_learn_getrange
https://uxmilk.jp/25841
https://fastclassinfo.com/entry/gas_data_tenki/
マンガでわかるシステムのおんぼろ煙突化アンチパターン

![1BE8DBFE-C460-480F-AF16-E44F799E3F43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/11525/e72b4c70-5922-2e39-0ca8-90d837921fdf.png)
http://wiki.c2.com/?StovepipeSystem

全社的おんぼろ煙突化と同様の問題が単独のシステム内で起きるのが、システムのおんぼろ煙突化です。レガシーシステムと呼ばれるものの多くは、おんぼろ煙突化が原因となっています。

古くから使われているシステムには、顧客の思いつきで不作法に作られたような箇所がいくつもあります。無作法というのは、修正スコープが閉じていないにもかかわらず、他の文脈を無視して、点々とある問題箇所だけに手を入れることで、ストーブパイプに共通する特徴です。このつぎはぎのせいで、結合が疎だったモジュールが、時間の経過とともに密になってしまうと、アーキテクチャのストーブパイプ化がひどくなり、コードも追跡困難なスパゲティになります。

一貫性のあるアーキテクチャの土台を設け、モジュール間の凝集度を最適に保ちましょう。必要に応じて、依存関係の逆転を適用するのも有効です。

ストーブパイプシステムになる原因は、アドホックな思いつきバイパスです。凝集度をないがしろにすると、比較的新しい技術を使ったモダンなシステムでありながら、ストーブパイプシステム化してしまうことはあります。私は個人的にこのパターンを「新たなレガシーを作ってしまったな」と言うことがあります。妥協や負債ではなく、単なる無知からリリース前にすでにレガシーになってしまうと、初手からマイナススタートっぷりがきついですね。
「localhost:5432 への接続が拒絶されました。ホスト名とポート番号が正しいことと、postmaster がTCP/IP接続を受け付けていることを確認してください。」で困った話

ポートフォリオを作成中リポジトリ名を変更したくて変更した後再度プロジェクトをデバッグにかけたら,
「localhost:5432 への接続が拒絶されました。ホスト名とポート番号が正しいことと、postmaster がTCP/IP接続を受け付けていることを確認してください。」
というエラーが出てしまいました。
これはどうやら、前回プロジェクトを終了したときに動いていたポストグレスSQLサーバーがまだ動いていることが原因のよう。

問題に対して以下のように対処したので備忘録として残しておきます。

参考にした[Youtube](https://www.youtube.com/watch?v=fRpZGN3rE_A)

1. PostgreSQLのアプリを開く。この時、「Stale postmaster.pid file」となっている ![スクリーンショット 2020-12-20 8.59.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/637360/230f4462-3f87-0a8c-dafa-b6525ef94a58.png)

2. [Server Settings]を押下
3. 「Data Directory」項目の「/Users/XXXXX/Library/Application Support/Postgres/var-12」を確認
4. 3.のディレクトリにcdで移動してlsコマンド実行
5. 「postmaster.pid」ファイルを見つける
6. rmコマンドで5.のファイルを削除する
 再度PostgreSQLアプリを立ち上げ、[Start]を押下して、「Running」になっていることを確認する![スクリーンショット 2020-12-20 8.50.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/637360/5f661fc7-ee9b-8470-e157-bb0e1a40d12e.png)
7. VScodeで再度デバッグ実行→正常！
コマンド1つでAmplify ConsoleからのSlack通知を設定する

# はじめに

この記事は AWS Amplify Advent Calendar 2020 の20日目の記事です。

昨年、同じ時期に [Amplify Consoleの通知をSlackに流す](https://qiita.com/fossamagna/items/70e4e399de59984ad3bb) という記事を書きました。
その記事では、タイトルの通り Amplify Consoleのビルド結果をSlackに通知する方法を紹介しました。
この記事では、昨年紹介した方法より楽にSlack通知を実現する方法を紹介します。

# 昨年のやりかた

詳しくは昨年書いた [Amplify Consoleの通知をSlackに流す](https://qiita.com/fossamagna/items/70e4e399de59984ad3bb) を読んでいただければわかりますが、ざっくり説明すると、Amplify Consoleのメール通知で利用するSNSでLambdaを呼び出してSlackにメッセージを送信するという方法でした。

ただ、この時利用するSNSトピックの作成はAmplify Consoleでメール通知を一旦有効するという手作業が必要で、プロジェクトや環境が増えると毎度その手作業が必要になり、煩雑でした。

## 便利な方法が発見される

今年の9月に昨年の記事に[次のようなコメント](https://qiita.com/fossamagna/items/70e4e399de59984ad3bb#comment-cb1b0725c3a24089a9ba)をいただきました。
![qiita-comment.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/98847/c9e0a66d-45ee-d52b-63df-29cf8b5e8054.png)

どうも、自動化する方法があるらしい :eyes: [コメントにかかれたリンク先](Amplify Console のビルド通知をSlackで受け取るためにやったこと) を読むと、今まで手動でやっていたSNSTopicの作成にあたる部分(とそこにイベントを送信する部分)がどのような仕組みになっているのかが詳しく書かれていました。

Amplify ConsoleからSlack通知までの流れは、以下のようになっていて、今まで手動でやっていたメール通知設定が`EventBridge(EventRule)`と`SNSTopic`というAWSリソースで実現されているというものでした。

```
Amplify Console -> EventBridge -> SNSTopic -> Lambda -> Slack
```

## amplify-category-console-notification の紹介

自動化のスライドを読んで、これならコード化できる :bulb: と思い、俄然作ってみたくなりました。
昨年の記事でも、メール通知を一旦有効するという手作業以外の部分をコード化して [Serverless Application Repositoryに公開](https://console.aws.amazon.com/lambda/home#/create/app?applicationId=arn:aws:serverlessrepo:us-east-1:296017205998:applications/amplify-console-notification) していました。これをベースにする方法も考えましたが、Amplify のappIdを調べたりするのは面倒かなという思いもあり、折角なのでamplify pluginにして簡単に追加できるようにしてみました。

今回作成したプラグインは npmレジストリにpublishしているので誰でもnpmでインストールして利用できます。
ソースコードもhttps://github.com/fossamagna/amplify-category-console-notification で公開しています。

このプラグイン使うには以下のようにnpmでインストールして、`amplify plugin scan`を実行してください。

```sh
$ npm install -g amplify-category-console-notification
$ amplify plugin scan
```

プラグインをインストールしたら以下のコマンドを実行すると Slackにメッセージを送信するLambdaのリソース名(好きな名前をつけてください)とSlackのWebhook URLを聞かれます。
これらの質問に答えると、Slack通知に必要なAWSリソースがローカルに追加されます。

```sh
$ amplify console-notification add
Using service: AmplifyConsoleNotification, provided by: awscloudformation
? Input function name in order to send message to Slack. Sender
? Input Web hook URL of Slack. https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX
Successfully added resource Sender locally
```

あとは`amplify push`を実行すれば完了です。
以下のようなメッセージがSlackに通知されます :rocket: 
![slack-messages.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/98847/71558f8d-6df0-617a-481d-20b38771c529.png)

## まとめ
- Amplify ConsoleのビルドのSlack通知を簡単に導入してみたいという方は是非使ってみてください。
- ソースコードは https://github.com/fossamagna/amplify-category-console-notification で公開しているので、IssueやPull Requestなど(スター :star: も)お待ちしています。

## あとがき

amplify pluginを作成する上で必要不可欠な、公式ドキュメントはプラグインのアーキテクチャや仕組みレベルを説明してくれています。しかし、実際にコードを書く上でamplifyがどういった機能を提供してくれていて、どのように実装すべきなのか（しないといけないのか）という情報はあまり見当たりませんでした。折角なので今回amplify pluginとして作成するために、調べたことやわかったことなどはどこかのタイミングで紹介したいなと思います。

## 謝辞

昨年の記事にコメントをくれて自動化の方法の存在に気づかせてくれた @hiroga さん、自動化の方法を紹介してくれた @youta1119 さん、ありがとうございます。
Nokogiriで使えるcssセレクタまとめ

##Nokogiriとは？
RubyでWebスクレイピングをするライブラリ。
Webスクレイピングは、ホームページから欲しいデータや文章を自動抽出する技術のことです。仕組みとしては、ホームページのhtml構造をみて、欲しいデータを特定できるhtmlタグや属性を指定することで、対象のデータを抽出します。

##基本的な使い方
スクレイピングをするコードの基本的な書き方は次のようになります。

```scraping.rb
require 'open-uri' #スクレイピングしたいページのurlを読み込むためのライブラリ
require 'nokogiri' #Nokogiriライブラリ

#urlを読み込む
url = URI.open('https://対象のページurl')

#url先のページのhtmlを読み込み、Nokogiri::HTML::Documentクラスへ変換
doc = Nokogiri::HTML(url)
```
このdocに対して様々な操作をすることで、html内の特定の箇所のデータだけ抽出することができます。

###cssとat_cssメソッド
次のようなページをスクレイピングしたいとします。

```html
<html>
  <head><title>お気に入り映画</title></head>
  <body>
    <h3>映画</h3>
    <div class="movies">
      <div>
        <h3 class="title">ショーシャンクの空に</h3>
        <p>ヒューマンドラマ</p>
        <p id="year">1994</p>
      </div>
    </div>
    <div class="movies">
      <div>
        <h3 class="title">スターウォーズ</h3>
        <p>SF</p>
        <p id="year">1977</p>
      </div>
    </div>
  </body>
</html>
```

cssメソッドは、Nokogiri::HTML::Documentクラスの持つメソッドで、引数にcssセレクタを与えることで、それを満たす要素を全て抽出します。複数ある場合、該当する要素が全て入った配列が得られます。（厳密には配列ではなくNokogiri::XML::NodeSetクラス）。
該当する要素が見つからなかった場合は、空の配列が返ってきます。

```rb
doc.css("h3") #タグで指定 
# >> [ <h3>映画</h3>, <h3 class="title">ショーシャンクの空に</h3>,  <h3 class="title">スターウォーズ</h3>]

doc.css(".title") #クラスで指定
# >> [<h3 class="title">ショーシャンクの空に</h3>, <h3 class="title">スターウォーズ</h3>]

doc.css("#year") #idで指定
# >> [<p id="year">1994</p>, <p id="year">1977</p>]

doc.css("h1") #ない要素を指定
# >> []
```
似たようなcssセレクタを用いる抽出用メソッドで、at_cssというものもあります。
こちらは、cssメソッドとは違って、複数該当するものがあっても一番最初に引っかかった要素のみを返します。
また、cssメソッドとは異なり、対象の要素が見つからなかった場合nilが返ってきます。

```rb
doc.at_css("h3") #タグで指定 
# >>  <h3>映画</h3>

doc.at_css(".title") #クラスで指定
# >> <h3 class="title">ショーシャンクの空に</h3>

doc.at_css("#year") #idで指定
# >> <p id="year">1994</p>

doc.at_css("h1") #ない要素を指定
# >> nil
```

##複雑なcssセレクタの指定方法
ページのhtml構造によっては、一つの指定では欲しいデータを特定できないこともあると思います。
その時は、次のようなセレクタ指定をとることもできます。

```rb
doc.css(".movies h3") #半角スペースで区切ると、.moviesクラスの配下にある全てのh3タグを抽出
# >> [<h3 class="title">ショーシャンクの空に</h3>, <h3 class="title">スターウォーズ</h3>]

doc.css(".movies > h3") # >で区切ると、.moviesクラスの直下にあるh3タグを抽出
# >> [<h3 class="title">ショーシャンクの空に</h3>, <h3 class="title">スターウォーズ</h3>]

doc.css("h3 + p") # +で区切ると、h3タグと並列な直後の要素pを抽出
# >> [<p>ヒューマンドラマ</p>, <p>SF</p>]

doc.css("h3 ~ p") # ~で区切ると、h3タグと並列なそれより後の要素pを抽出
# >> [<p>ヒューマンドラマ</p>,<p id="year">1994</p>, <p>SF</p>, <p id="year">1977</p>]
```
また、テキストで指定することもできます。

```rb
doc.css("h3:contains('スターウォーズ')") # :contains('文字列')を与えると、テキスト検索できる。
# >> <h3 class="title">スターウォーズ</h3>
```

##最後に
今回は説明していませんが、得られた1つの要素は、Nokogiri::XML::Elementクラスのオブジェクトで、ここからテキストを抽出したり、aタグで指定されているurlを取得したりできます。
対象のhtml構造や、どう言ったデータが欲しいかによってcssセレクタの指定方法が違うので、全てをパターン化して記事にするのは難しいです。
今回紹介した指定方法を組み合わせて、欲しいデータを抽出しましょう。
【第９回】Python で競馬予想してみる ~ モデルの実用化 ~

前回までに、競馬予想のモデルの骨格は完成なのだ

#モデルの実用化
実際に予想する際の作業も、基本的にはほぼ同じ。

- TARGET frontier JV の出馬表から、馬データおよび前走データも読込み、全データを CSV で出力し使用
- 機械学習時と同じ様にデータの前処理を実行（レース検索から得られるデータとカラム名などが微妙に違うので、若干の修正必要。ここで案外手間取る💦）
- トレーニングデータと検証データの時に行った時系列でのデータ分割。アンダーサンプリングは、当然しない
- 回収率用テーブルを修正して、レース毎、Proba順にソートしてグラフ化（下の表：proba は、標準化・正規化してグラフで見やすいように 1~100 に収まるように調整）

![2020-12-20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/895631/7c70e6f7-c78e-9852-15a7-533d9d93141b.png)

ｰ　レース毎に横棒グラフ化：コードとして適切かどうか分らんが、下記コードで成功

```python:build.ipynb
# グラフを降順に表示するには、元データを昇順にしなければならないらしい
rc_rslt_r = rc_rslt.sort_values(['レースID', 'proba'], ascending=[True, True]).reset_index(drop=True)
race_lists = rc_rslt_r['レースID'].unique()
for race_list in race_lists:
    ax = rc_rslt_r[rc_rslt_r['レースID']==race_list].reset_index(drop=True)
    plt.figure(figsize=(20,12))

    ax.plot(kind='barh', x='馬番', y='proba_std01')
    #rc_rslt.hist(column='proba_std01', by="レースID", range=(0,1), figsize=(12,3))

    race_corse = ax['場所'][0] + str(ax['Ｒ'][0]) + 'R' # もっとスマートな値の取得法ないかな？
    plt.title(race_corse, fontname='MS Gothic')
    plt.xlabel('proba')
    plt.ylabel('馬番', fontname='MS Gothic')
    plt.xlim([0,100])
    plt.grid(True)

    plt.show()

    plt.close('all')
```

※項目名の日本語表記は何とか出来たが、馬番ではなく馬名を表示したいのだが・・・
　良い方法あるのかな

ちなみに、2020年12月20日の朝日杯の予想はこんな感じ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/895631/38c4b7f6-e85d-3c0c-3fec-1c02a8ef58df.png)
【Swift】処理をコンマn秒止める（遅延処理）

# どういうことか

```swift
// 1秒止める
sleep(1)
```

上記のコードで処理を1秒止めることができるが、例えば `sleep(0.5)` と書くとエラーになる。
sleep関数の引数は **Uint32** で指定しなければならず、これは『**32ビット符号なし整数**』のことで……まあとにかく浮動小数点は指定できないのだ。

## Thread.sleep

これでいける。

```swift
// 0.5秒止める
Thread.sleep(forTimeInterval: 0.5)
```
Solverを使って、Creative Codingの関数に対応づけてHoudiniで作ってみる


# はじめに

Houdini Apperentice Advent Calender 19日目の記事です。遅れてごめんなさい。
openFrameworksというツールを使って、OpenGLを叩いてコードを用いた創作活動を行っています。
Solverの理解がちょっと深まったので、コードを書く際の関数に対応づけたノードを組んで、Creative Coding界隈の人がHoudiniを触り始める時の手掛かりになるような記事を書きたいと思います。

# 環境
Houdini Indie 18.5.351
# どんなものを作るか
Creative Codingでやりがちな表現をHoudiniに移植してみます。
## Houdini上での見ため
[![Image from Gyazo](https://i.gyazo.com/f61a3991455f0c740e25ad8dd472a374.gif)](https://gyazo.com/f61a3991455f0c740e25ad8dd472a374)

## oFでの見た目
[![Image from Gyazo](https://i.gyazo.com/064c996ea8d320870bb92a137debf1de.gif)](https://gyazo.com/064c996ea8d320870bb92a137debf1de)

大体同じ感じですね...!!

# oF側の実装
コードの方は長くなるので、Githubの方に乗っけておいてざっくりとだけ解説します
[ソースコード](https://github.com/yutaokuyama/cubes_HoudiniAdventCalender2020)
`setup`関数では起動時に一度だけ実行され、配列にランダムに生成した座標とサイズを格納していきます
`update`関数では描画前に毎フレーム実行され、座標とサイズに対して、ランダムで値を変更し、イージングをかけながら更新します
`draw`関数では、座標とサイズに従ってCubeを描画します。
という流れでレンダリングが行われます。

この各関数に当たるノードをHoudiniでつくっていきます。
## ノードの全体像
[![Image from Gyazo](https://i.gyazo.com/25d64c21590efdc42e7f3c50d5e3878f.png)](https://gyazo.com/25d64c21590efdc42e7f3c50d5e3878f)

ソースコードの各関数にどこが対応するかわかりやすいように色をつけてみました。
動きを決定するSolverの中をみてみると
[![Image from Gyazo](https://i.gyazo.com/b337ec6ddddb7364778cd5f5e532121d.png)](https://gyazo.com/b337ec6ddddb7364778cd5f5e532121d)
このようになっており、該当するoFの方のコードを眺めると、

```cpp
void ofApp::update(){
    updateDstPositions();
    updateDstSizes();
    for(int i=0;i<NUM;i++){
        positions[i] +=(dstPositions[i]-positions[i])/3.0;
        sizes[i] +=(dstSizes[i]-sizes[i])/3.0;
    }
}
```
ちょうど同じ名前の関数が同じ順番で呼ばれていることがわかります。
実際に作るときよりもかなり冗長に書きましたが、構造を似せて書くことができました。詳しくは[Githubにhipファイル](https://github.com/yutaokuyama/cubes_HoudiniAdventCalender2020/blob/main/cubes_AdventCalender2020.hiplc)をおいておきます。

# おわりに
もともとCreative Coding界隈の人だった私がHoudiniを始めてから、表現の幅が格段に広がっているのを感じていて、Houdiniはとてもいいものだな、と思っています。
書いているうちにこれはHoudiniのAdvent Calenderとして適切なのか自信がなくなってきました..
どなたかのHoudiniの学習の助けになれば幸いです
なでしこv3ブラウザ版 動画の自動再生問題

[前回](https://qiita.com/oza-jv/items/4bcc7dd2bef74d94f0b9)，プラグインが完成した！！と喜んでいたのですが，動画の自動再生がうまくいかないぞ？という問題が生じました。そこで，その悩んだことをメモします。

この記事は、なでしこのv3ブラウザ版で実行できるようにしています。

プログラム例は「なでしこ」部分のみ書いていますが，実際は拙作のテンプレートに貼り付けて書いているものとしてください。

# 動画の自動再生

## 動画が再生されない問題

まず，意気揚々とできあがった命令を使って，動画の自動再生を実行しようと思いました。

```sample1
ID=「video1」。
F=「test2.mp4」。
IDにFを動画読込。
IDを動画再生。
```

しかし，これでは動画が再生されません。

## video要素のmuted=falseだと再生されない

ボタンを押して再生させるような場合は問題無いのですが，そういったイベントを経由しないで再生する場合は，video要素のmuted属性をtrueに（つまり，音をミュートに）しておかないと，再生されないようです。これは，ブラウザ側の仕様のようです。

そのため，plubin_mediaも修正し，`動画読込`と`動画追加`の際に，muted=trueにするようにしました。

また，`<ID>の動画音オン`と`<ID>の動画音オフ`という命令も追加しました。

## mutedとの関係を調べてみた

じゃあ，どういう状態なら音が鳴って，映像も再生されるのか？を調べてみました。これは「なでしこ」の問題でもありますが，JavaScriptでも同様の問題になると思います。

```movietest
ID=「video1」。
F=「test2.mp4」。
IDにFを動画読込。

逐次実行
　　先に、「#1 読み込み直後：」＆（IDの音状態）を書く。  // #1 読み込み後はmuted=true
　　次に、１秒待機。

　　次に、IDを動画再生。
　　次に、「#2 再生中：」＆（IDの音状態）を書く。        // #2 muted=trueのままで音が出ない
　　次に、１秒待機。

　　次に、IDの動画音オン。
　　次に、「#3 動画音オン直後：」＆（IDの音状態）を書く。// #3 muted=falseにすると動画が止まる
　　次に、１秒待機。

　　次に、IDを動画再開。
　　次に、「#4 音オンのまま再開：」＆（IDの音状態）を書く。// #4 muted=falseのままでは再開されない
　　次に、１秒待機。

　　次に、IDの動画音オフ。
　　次に、IDを動画再開。
　　次に、「#5 音オフで再開：」＆（IDの音状態）を書く。  // #5 muted=trueにすると映像のみ再開
　　次に、１秒待機。

　　次に、再生テスト。
ここまで。

●(IDの)音状態とは
　　変数　フラグ＝「#{ID}」の「muted」をDOM属性取得。
　　もし、フラグ＝はいならば
　　　　「音オフ」を戻す。
　　違えば
　　　　「音オン」を戻す。
　　ここまで。
ここまで。

●再生テストとは
　　ボタン１＝「再生」のボタン作成。改行作成。
　　ボタン１をクリックした時には
　　　　逐次実行
　　　　　　先に、IDの動画音オン。
　　　　　　次に、IDを動画再生。
　　　　　　次に、「#6 ボタンで再生：」＆（IDの音状態）を書く。// #6 muted=falseで音が出る
　　　　　　次に、１秒待機。

　　　　　　次に、IDの動画音オフ。
　　　　　　次に、「#7 音オフ：」＆（IDの音状態）を書く。  // #7 muted=trueにしても映像は動く
　　　　　　次に、１秒待機。

　　　　　　次に、IDの動画音オン。
　　　　　　次に、「#8 音オン：」＆（IDの音状態）を書く。  // #8 muted=false
　　　　　　次に、１秒待機。
　　　　　　
　　　　　　次に、IDを動画停止。
　　　　ここまで。
　　ここまで。
ここまで。
```

実行サンプルは[こちら](https://oza-jv.github.io/movietest.html)にあります。動画の読み込みに時間がかかるので，リロードすると上手くいくと思います。

> 実行結果
![pic4.GIF](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/942750/d676fc8f-c066-db45-6b4c-1868507c3d6d.gif)

まず，**#2**で動画再生すると，映像は動きますが，音が出ません。
次に，**#3**で，動画音オン（muted=false）にすると映像が止まってしまいました。
**#4**で，動画音オン（muted=false）のまま動画を再生しようとしても，映像が動きません。
**#5**で，動画音オフ（muted=true）にしてから再生すると，映像が動きました。

なるほど。普通に再生しようと思った時は，音をミュートにしないとダメなんですね。

## ボタンで再生

じゃあボタンで再生したらどうなるんだ？と思い，試してみました。ちなみに，`動画再生`の命令は`video.play();`を実行しているだけなので，muted属性等は何もいじっていません。

**#6**で動画再生すると，**音が出て**映像も動きます！！　動くじゃん！
**#7**で動画音オフ（muted=true）にすると，映像が動いたままミュートされます。
**#8**で動画音オン（muted=false）にすると，映像が動いたまま音がちゃんと出ます。
そうそう，こういう動作を期待していたんです。

つまり「なでしこv3」に限らず，おそらくJavaScriptでも同様の問題が発生すると思いますが，

- ボタンクリック等のイベントを経由せずに動画を再生する場合は，muted=trueにする必要がある。
- ボタンクリック等によって動画を再生する場合は，音が出る。

ということになるようです。

## iOSでのインライン再生問題

ついでに，iOSのSafariでインライン再生するためには，`playsinline`属性を[明示的に記述する必要がある](https://qiita.com/tomoyukilabs/items/cb9dd1d3e7eb0cc7f58a)ようです。プラグイン内でも記述してあります。

## 最後に

「なでしこ」は日本語で分かりやすく，しかもシンプルなソースプログラムを書けるのが魅力だと思うんです。だからといって，ブラウザごとに動作に差がある部分を「なでしこ」で複雑に書こうとすると，日本語プログラム言語の魅力が半減するような気がします。プラグイン側を修正することで，日本語側のシンプルさを保てるといいなと思った次第です。

## 参考

- [まるログ](https://www.marukin-ad.co.jp/marulog/?p=2721)
- [モバイルブラウザのビデオ再生がいろいろ変わるので確かめてみた](https://qiita.com/tomoyukilabs/items/cb9dd1d3e7eb0cc7f58a)
【Vue.js】動的にクラス属性を切り替える方法

# はじめに

web アプリを作っている際、動的にクラス属性を切り替えたい場合があります。そのような場面で便利な Vue の`v-bind:class`について書きます。

# v-bind:class とは

Vueで使える`v-bindディレクティブ`の一つで、オブジェクトや配列を渡すことでそのデータプロパティの真偽値によってクラス属性の付与を切り替えることができます。

# 書き方

プロパティ値の真偽値が true のとき、v-bind:class で指定した html 要素にクラス名が付与さえます。逆に真偽値が false の場合はクラス名は付与されません。

```html
<div v-bind:class="{クラス名:プロパティ値}">AAA</div>
```

# 実装例

以下では、v-bind:classによってblueクラスとredクラスをtoggledプロパティの真偽値によって付与しています。
methodsで指定されているtoggle関数はtoggledの真偽値を逆にする処理を実行します。

<p class="codepen" data-height="265" data-theme-id="light" data-default-tab="html,result" data-user="tktaka" data-slug-hash="MWjoMEw" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="VueJS - Usage of v-bind:class">
  <span>See the Pen <a href="https://codepen.io/tktaka/pen/MWjoMEw">
  VueJS - Usage of v-bind:class</a> by TokioTakamiya (<a href="https://codepen.io/tktaka">@tktaka</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script></script>

# 参照
[Vue.js : Class and Style Bindings](https://vuejs.org/v2/guide/class-and-style.html)
顧客トラブルにおける理不尽なムチャぶりを全力回避したい

[理不尽なムチャぶりを全力で回避したいエンジニアのためのサバイバル術](https://qiita.com/shibayoh/items/05d2f0af578f56e4b327) への感想。

結論から書くと、結構「[HRT](https://qiita.com/e99h2121/items/85638c981cd92893fa41#%E5%8F%82%E8%80%83)」なのかな、と思った。私の場合「ムチャぶり」を食らう場面は圧倒的に顧客トラブル時。なので、主にその場面を考えたムチャぶり回避術だと理解した。


## 顧客トラブルにおけるムチャぶり回避術
### 原因
元記事の引用です。「バリューチェーン上開発が一番先頭に位置するため下流から理不尽が舞い込みやすいという構造上の問題」。それに対し、以下で対処する。

>1. 「ゴールってなんでしたっけ？」と空気を読まずに聞き続ける
1. 「やること」以上に、「やらないこと」を宣言する
1. エンジニア以外のチームへ、「やってほしいこと」をリクエストをする
1. 1つの手段にこだわらない
1. 具体的なものを見せながら話す
1. 納期を守る

ポイントは後半、5と6のほうだと私は考えた。この記事では逆順から見ていきたい。

## 納期を守る
今日中に解決したい、とか、明日中に、とか言われます。だからこそムチャぶりだなと思ってしまうのですが、その際に、今日のところはここまでやりますよ、という超短期スプリントを提示して、守るというのが大事。シンプルに約束を守るということは、信頼関係の第一歩だと思う。

## 具体的なものを見せながら話す
大体において、開発の言っていることは顧客担当や、お客様そのものには3割も伝わっていないのではと思う。開発側ができることをもっと工夫したい。図を書きながら話す、具体的なデータを元にする。例えば、このタイミングで何人が同時に接続しているから一人当たり◯MB必要であるとして◯GB必要ですね等など。これも伝えようという気持ちを開発側から持たないと出来ない。

## 1つの手段にこだわらない
私がまず確認するのは以下。

- 緊急回避が先か
- 原因解明をしてよいか

で、大きく方向づけて、そのなかで行える方法をいくつか提示して、選んでもらう。
1. 再起動する
2. 〇〇の系統をオフにする
3. ログインユーザを変えてみる
等など

## 「やってほしいこと」をリクエストをする
ログを取ってください
○○で回避してみてください 等
どちらかというとこの辺りは始めにFAQとして作っておく。

## 「やらないこと」を宣言する
これはできないし、仕様だということを伝える。
伝えられるようにこれも普段から、ドキュメントを揃えておけたら良いな。

## 結論：ムチャぶりとうまく付き合いたい
書いてみましたが、「顧客トラブル」というのは結局自分たちの仕込んだ不具合が原因だったりするわけで、「ムチャぶり」とは言い切れないのかもしれないですねえ。という意味で、完全回避は不可能と思いつつせめてうまく付き合おう、というのが結論です。

年末、IT屋さんにとってはムチャぶりと向き合わないといけないシーズンなのではと思っています。年末年始稼働の皆様は本当にお疲れさまです。結局、相手を尊重しつつ、労いながら、良い年を迎えたいです。以上！
HerokuでRails/Basic認証を導入する。

#初めに
本番環境でBasic認証を導入したいと思いやってみました。
AWSはしたことはあるがHerokuでしたことがなかったので今回の行ったことを記したいと思います。

#Basic認証とは
Webサイトにアクセス制限するにあたり、簡易的に制限をかけることができる方法として挙げられるのはベーシック認証（Basic認証）。
ベーシック認証（Basic認証）はWebサーバーに付随している機能の1つでファイルに数行の記述をするだけで簡単にアクセス制限をかけることが可能です。
![Basic認証](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.amazonaws.com%2F0%2F301628%2F397d6a0d-4840-7925-1a84-d786bdf99721.png?ixlib=rb-1.2.2&auto=format&gif-q=60&q=75&s=c5b1023ad6bb29ae709a42dd1363c9f0)
ベーシック認証（Basic認証）とはWebサイトの特定の領域、つまりページやファイルにアクセス制限をかけることができる認証方法の1つ。
ベーシック認証をかけると、認証をかけたWebサイトにアクセスしようとしたとき、上の画像のような認証ダイアログが立ち上がって、ユーザー名（ID）とパスワードの入力が求められる。

#Basic認証の特徴
##・メリット

###①ディレクトリ単位でのアクセス制限が可能
###②認証完了後はブラウザを閉じるまで有効
###③ブラウザがログイン情報を記憶

##・デメリット
###①セキュリティの脆弱性
　- ※引用 -
　ベーシック認証ではログイン情報を入力して送信する際に「Base64」という文字コードを用いて通信を行います。
　「Base64」は簡易的な通信を行う際の文字コードで、アルファベット・数字・特定の記号のみの64種類の文字が利用可能です。
　つまり、ベーシック認証で入力したログイン情報は、「Base64」の文字コードで表現できるアルファベット・数字・記号で通信されてしまいます。
　もし、ベーシック認証をかけたWebページが「https」ではなく、SSL対応がされていない「http」通信である場合合、外部からログイン情報が盗聴されやすくなっているため注意が必要です。

###②クローラーもアクセスできない

###③サーバーをまたいだ設定ができない

###④スマートフォンではログイン情報を保存できない

#Basic設定方法（Heroku上にデプロイする。）

全てのコントローラでBasic認証を行うためにapplication_controller.rbにコードを追記。
RailsにはBasic認証をするための以下のメソッドが用意されている。
「authenticate_or_request_with_http_basic」
これがRailsで簡単にBasic認証を実装してくれるメソッド。


```php:app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  before_action :basic_auth, if: :production?

  private

  def production?   #←本番環境かローカルを区別する。
    Rails.env.production?
  end

  def basic_auth
    authenticate_or_request_with_http_basic do |username, password|
      username == ENV['BASIC_AUTH_USER'] && password == ENV['BASIC_AUTH_PASSWORD']
    end
  end

end
```
#環境変数にUSERとPAASSWORDを追記する。
```php:ターミナル.
% vim ~/.bash_profile
  
#「i」を押してインサートモードにいく
#自分で設定したUSERとPASSWORDを以下の様に追記する。

export BASIC_AUTH_USER='USER'
export BASIC_AUTH_PASSWORD='PASSWORD'

#escキーを押し、「:wq」を押して保存

% sudo vim /etc/environment
Password:  #←手持ちPCのパスワード

#「i」を押してインサートモードにいく
#自分で設定したUSERとPASSWORDを以下の様に追記する。

BASIC_AUTH_USER='USER'
BASIC_AUTH_PASSWORD='PASSWORD'

#escキーを押し、「:wq」を押して保存

#heroku configにてHeroku上に反映されているか確認する。

% heroku config                             
=== アプリ名 Config Vars
BASIC_AUTH_USER:          'USER'
BASIC_AUTH_PASSWORD:      'PASSWORD'

```

username == ENV['BASIC_AUTH_USER'] && password == ENV['BASIC_AUTH_PASSWORD']は環境変数にする理由として、環境変数にせずGithubにコミットアップすると、パスワードが一目瞭然で分かるため。


#デプロイ動作確認
上記のやり方でBasic認証を設定できました。
【人類待望】年の瀬なので「ｳﾙﾄﾗｿｳｯ ＼ﾊｧｲ／」を練習するアプリを作った【ちょうど欲しかった】

本記事は[クソアプリ Advent Calendar 2020](https://qiita.com/advent-calendar/2020/kuso-app)の20日目の記事です。
19日目はampersandさんによる[ブラウザに弾幕を流して匿名チャットできるやつを作った](https://qiita.com/ampersand/items/02d14f06c7334010f355)でした。


## はじめに

年の瀬ですね。一年の締めくくりや大掃除をしている方も多いのではないでしょうか。
ところで、みなさんは年末には何を聴いて年を越しますか？

そうですね、**「ultra soul」**です。

そんな全人類の願望がこれです。

### <font color="Red">「ｳﾙﾄﾗｿｳｯ ＼ﾊｧｲ／」で年越ししたい。</font>

しかし、そのタイミングはシビアで、残念ながらチャンスは年に一度しか来ないのです。

そこで、私は来たる12月31日に向けて、**「ｳﾙﾄﾗｿｳｯ ＼ﾊｧｲ／」**を練習するためのアプリを作りました。


## [ｳﾙﾄﾗｿｳｯ ＼ﾊｧｲ／を練習するアプリ](https://aiandrox.github.io/ultra_timer/)

https://aiandrox.github.io/ultra_timer/

[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322882/77639746-a264-25ca-665a-111e227e733d.png)](https://aiandrox.github.io/ultra_timer/)


### 使い方

1. ページに表示されている時刻を見ながら、タイミングを合わせて「再生する」ボタンをクリック。
1. 格好いい稲葉さんと松本さんを眺めながら、この一年に思いを馳せます。
1. そして輝き始めたら準備をし、**「ｳﾙﾄﾗｿｳｯ　＼ﾊｧｲ／」**でテンションを上げて叫びます。
1. その瞬間に年を越せたらあなたはウルトラソウルです。

一応ランキングも付いています。


## 使用技術

**JavaScript**
本当はReactとかTSの勉強がてら使いたいとか考えていたのですが、YouTube Iframe周辺のあれがいまいちうまくいかなかったためこうなりました。
無限に広がるDOM操作で死ぬかと思いました。

**YouTube Iframe**
音楽サービスのAPI連携？知らねえ、YouTube埋め込みが一番安定だろ！という脳筋思想によってこうなりました。

**GitHub Pages**
毎度お世話になっております。静的サイトを５秒でホスティングできる。

**Google fonts**
おしゃれにしてみたかっただけです。


## こだわりポインツ

### カットイン

カットインって憧れじゃないですか？
本当は画像とかの方が「ぽさ」が出るのでしょうが、これで我慢してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322882/2b623712-a8a6-a2bb-2dcc-224382af29c0.png)
CSSの`@keyframes`を初めて使いました。CSSでいろんなことができるんだなあ、すごいなあ（小並感）という感じでした。


### ゴリ押しの動的OGP

動的OGPをしたかったのですが、そのためだけにバックエンド用意するのは「ないわぁ」って感じ。
ふと思いついたのが、**Twitter用のページを何種類か用意して、ルートページにJSでぶっとばせばええんじゃね？？**

https://aiandrox.github.io/ultra_timer/3_hodo

UXとか考えるとよろしくない設計だとは思いますが、今の私に怖いものはない……。


## ラグには勝てなかったよ……。

残念ながら、再生を押してから2秒ほどラグが出てしまいます。
だいぶ**致命的**な気がしますが、仕方ないですね。

YouTubeを介する限り、ラグからは逃れられません。
つまり、CDを買いましょう。
[Amazon \| ultra soul \| B’z, 稲葉浩志, 松本孝弘, 徳永暁人 \| J\-POP \| 音楽](https://www.amazon.co.jp/ultra-soul-B%E2%80%99z/dp/B00005HVFV/ref=sr_1_84?dchild=1&qid=1607958397&refinements=p_lbr_music_artists_browse-bin%3AB%E2%80%99z&s=music&sr=1-84)

もしくはこのギャンブル性を楽しみましょう。


## あとがき的な感想

最初はミニマムなアプリにしようと思ったのですが、UIにネタを仕込んでいくとどんどん膨張していきました。
生JSの勉強にしようと思っていたのに、結果的に`let`と`function`のゴリ押しになりました。

クラスとかいい感じにしたい思いはあった。思いだけだった。
自分でも見る気をなくすイカスミスパゲッティコードが鎮座しています。


### ちなみに

実は3月に思いついていたものの、モチベーションがもたずにお蔵入りしていました。
こういうボツを供養できるのもクソアプリアドベントカレンダーのいいところですね。

クソアプリカレンダーはずっと憧れだったので、この機会に参加できてよかったです。
明日は[KCさんの記事](https://qiita.com/kcpoipoi/items/238df3d0492c4631aa77)です。Tの波動を感じます。
Cloudianオブジェクトストレージ/マルチスレッドによるファイルのアップロード

今回は、Python(boto3) のサンプル編です


## マルチスレッドによるファイルのアップロード
指定したディレクトリ(このサンプルでは 「./log」)にある全てのファイルを、Cloudian上のバケット「logs」の中の実行日のフォルダ (YYYY-MM-DD)にアップロードする Python プログラムです。

アップロードするファイル毎にスレッドを作成して、マルチスレッドで Cloudianにファイルをアップロードします。アップロード時にファイルに対して、ACL に「private」を設定し、メタデータとしてアップロードした日付を付与し、AES256 のサーバーサイド暗号化を有効にしています。


```python:MultipartUpload.py
import os
import glob
import threading
import sys
from datetime import datetime

import boto3, botocore
from boto3.s3.transfer import S3Transfer
from boto3.s3.transfer import TransferConfig


######### マルチスレッド関数 ##########
def multithreads_upload(upfile):
    
    print("Thread %s is uploading file: %s" % (threading.current_thread(), upfile))
    
    transfer.upload_file(
    	upfile,
       bucket,
       today + '/' + os.path.basename(upfile),

       extra_args={
			'ACL': 'private',
			'Metadata': {'Stored': today},
			'ServerSideEncryption': 'AES256'
       }
    )
    
    print("Thread %s done uploading file: %s" % (threading.current_thread(), upfile))



########## メイン処理 ##########
# 変数セット
dir = './fileup/'

bucket = 'logs'
region = 'region1'
today = datetime.now().strftime('%Y-%m-%d')


# boto3オブジェクト作成
client = boto3.client(
    's3',
    endpoint_url='http://s3-region1.admin-tech.tokyo',

    # 認証情報の直接記述は推奨されない（テスト目的）
    aws_access_key_id='アクセスキーを記述',
    aws_secret_access_key='シークレットキーを記述'
)

# 転送オブジェクト作成
transfer = S3Transfer(client)



try:
    # バケットの存在確認
    client.head_bucket(Bucket = bucket)

except botocore.exceptions.ClientError:
    # バケットが存在しなければ、新規作成
    client.create_bucket(
        ACL='private',
        Bucket=bucket,
        CreateBucketConfiguration={
            'LocationConstraint': 'region1'
        }
)


# マルチスレッドによるファイルのアップロード
upfiles = [dir + file for file in os.listdir(dir) if os.path.isfile(dir + file)]
threads = []

for upfile in upfiles:
    t = threading.Thread(target=multithreads_upload, args=(upfile,))
    t.start()
    threads.append(t)

for t in threads:
    t.join()
```


プログラム実行の出力ログから、アップロードするファイルサイズにより各スレッドの開始と終了に差があることが分かります。
このサンプルでは各スレッドの終了を threading.join()を使って、全てのファイルのアップロードが終了するのを待機します。

下図はこのサンプルプログラムによりアップロードされたファイルを、CMC から確認した画面です

![4-2-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/962155/4b203bc4-84d1-f531-402c-cdb649d5b938.png "4-2-1.png")
Xdebug2の設定を3の設定に変換するやつ

・ヮ・）あ、おはようございまーす

みなさん Xdebug 使ってますか？
ステップ実行便利ですよね！

つい先日 PHP8 で開発環境を作っていたらエラーがでました

```
Xdebug: [Config] The setting 'xdebug.xxx' has been renamed, see the upgrading guide at
```

Xdebugさんバージョン3になったんですね（知らなかった
2 から 3 に バージョンアップするにあたって 設定方法がいくつか 変わったらしく エラーになってました
[Upgrading from Xdebug 2 to 3](https://xdebug.org/docs/upgrade_guide)

自分の環境はドキュメント読みつつ新しい設定に直したのですが
同僚やお友達から「設定を手伝っておくれ」と何回か言われて いちいち調べ直すのが面倒になり変換ツールを作りました

# [Xdebug2の設定を3の設定に変換するやつ](https://schrosis.github.io/xdebug-setting-2to3/)

↑ここから飛べます

## :warning: 注意事項

 - やっつけで雑に作ってしっかりテストしていません
 - メンテナンスをする気はありません
 - 自己責任でお使いください
 - ドキュメント読みましょう
 - CSSはお亡くなりになりました:innocent:

# 変換しきれない設定項目

Xdebug2 のときは 個別に設定できた項目が 1つにまとめられているものが いくつかあります
優先したい設定に合わせて選んでください


## [xdebug.start_with_requests](https://xdebug.org/docs/all_settings#start_with_request)

Xdebug2の設定が
`xdebug.auto_trace = true` もしくは `xdebug.remote_autostart = true`
のときは `xdebug.start_with_requests = yes`

Xdebug2の設定が
`xdebug.profiler_enable_trigger= true` もしくは `xdebug.trace_enable_trigger= true`
のときは `xdebug.start_with_requests = trigger`

`xdebug.start_with_requests`　はXdebug3 で新しく追加された設定項目です
ドキュメントを読んで設定しましょう

## [output_dirs](https://xdebug.org/docs/all_settings#output_dir)

`xdebug.gc_stats_output_dir` 、 `xdebug.profiler_output_dir` 、 `xdebug.trace_output_dir`
これらの設定が `xdebug.output_dirs` 1つになったようです
別々に設定されていた方はどれか一つ選んで設定する必要があります

## [xdebug.trigger_value](https://xdebug.org/docs/all_settings#trigger_value)

`xdebug.profiler_enable_trigger_value` 、 `xdebug.trace_enable_trigger_value`
これらの設定が `xdebug.trigger_value` 1つになったようです
別々に設定されていた方はどれか一つ選んで設定する必要があります

## 削除された項目

`xdebug.collect_includes`
`xdebug.collect_vars`
`xdebug.extended_info`
`xdebug.overload_var_dump`
`xdebug.remote_handler`
`xdebug.show_mem_delta`

これらの項目が削除されたようです
詳しくはドキュメントを読んでください

## サイレントで消えた項目？

アップグレードガイドには載ってないのですが Xdebug2 には存在していて Xdebug3 には存在しない項目がありました

`xdebug.manual_url`
`xdebug.profiler_aggregate`
`xdebug.remote_cookie_expire_time`

見落としだったらすみません
一応入力されたらそのままの値で出力するようにしました

# おまけ

`xdebug.mode = debug`
`xdebug.start_with_requests = yes`
の状態で IDEでステップ実行を開始せずに コマンドラインからPHPファイルを実行すると
タイムアウトして接続できなかった というエラーが表示されます

```
Xdebug: [Step Debug] Time-out connecting to debugging claited: 200 ms. Tried: ホスト (through xdebug.client_host/xdebug.client_-(
```

Laravel で artisan コマンドを実行するときなど 出てきます

対処方法は

```sh
# XDEBUG_MODE環境変数を使って一旦すべての機能をoffにする
export XDEBUG_MODE=off && php artisan xxx
```

もしくは

```ini
; log_levelを0にする
; logが出力されなくなるので注意(log見る人いる？
xdebug.log_level=0
```

するとエラーが表示されなくなります！
MagentoのWebサイトを維持するのにどれくらいの費用がかかりますか？

オープンソースのeコマースソリューションであるMagentoは、適切に管理し、可能な限り最高の結果を達成するために、多くのアクティビティを必要とします。また、Magentoストアの管理、さまざまなカスタマイズ、サードパーティの統合、サポートとメンテナンスなどの重要なアクションを忘れないでください。

ここでは、Magentoストアを運営するための価格に影響を与える主な要素に関する重要な情報を入手できます。

![Magento website](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705866/cf3ce6dc-edaa-5a08-171a-bab490221594.jpeg)

MagentoWebサイトを運営するための価格に影響を与える要素

![costs to develop a Magento website](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705866/8d076752-afd7-4c41-0543-b40315991979.png)

MagentoのWebサイト開発に関しては、価格の問題が重要です。したがって、何があなたを待っているのかを明確に把握することが重要です。

Magento2の価格についての質問に答えるために検討すべき側面は次のとおりです。

ホスティング
最も人気のある2つのホスティングプロバイダーであるA2HostingとSiteGroundに焦点を当てることをお勧めします。

ページ開発
Magento Webサイトの次のeコマースページ（ホームページ、製品ページ、カテゴリページ、チェックアウト）の開発を検討してください。

ウェブサイトデザイン
ここでは、既製のテーマを使用するか、完全にカスタム設計を実装するかによって異なります。

決済ソリューションの統合
現在までに最も人気のあるeコマース決済ソリューションはPayPal、Authorize.net、Stripeであり、これらを合わせると全体の市場シェアの75.6％以上を所有しています。

SEOとプロモーション
これは、eコマースWebサイトの見積もりを作成する際に注意すべきもう1つの側面です。その理由は、SEOがeコマースビジネスの重要なコンポーネントになっているためです。これは検索エンジン全体のファインダビリティに影響を与え、ユーザーエクスペリエンスを向上させ、最終的にSEOはWebサイトのプロモーションとして完全に機能します。

サポートとメンテナンス
Magento Webサイトを定期的に管理することは、最新の状態を維持するための重要な要素の1つです。

すべての代理店の管理の価格は、チームの経験、会社の専門知識、開発アプローチ、サービスの需要、および会社の場所によって異なります。

Magento Webサイトの開発にかかる費用の詳細については、[こちら](https://whidegroup.com/blog/the-true-cost-of-magento-support/)をご覧ください
Class化を学ぼう！



# 目次

今回はオブジェクト指向のキーとなる考え方である「隠蔽」「継承」「多形」を以下の手順で学ぶ．


# classとは

Classとは事前に型を用意しておき，必要に応じて値を変更して使用できる設計図のようなものらしい．

基本的な書き方は次のようになる．

    class クラス名
        def initialize
            // 初期化処理
        end
    end

クラス名は大文字から始めるルールになっているようだ．また，initializeを使用することで初期化処理を行うことができる．


# クラスを利用してみる

以前作成したhello.rbは以下の通り．

```ruby:hello.rb
def puts_hello name
    puts "Hello #{name}."
end

def gets_name
    name = ARGV[0] || 'world'
    return name
end

name = gets_name
puts_hello name
```

これをクラスを使って表現する．

```ruby:class.rb
class Hello
    def initialize #初期化
	    @name = gets_name
	    puts_hello
    end

    def puts_hello #salute
	    puts "Hello #{@name}."
    end

    def gets_name
	    name = ARGV[0] || 'world'
	    return name.capitalize
    end
end

Hello.new
```

こうすることで同様の結果が得られる．

動作としては，まずはじめにinitializeで初期化する．

次に@nameという変数にgets\_nameメソッドを呼び出すことで値を代入している．コマンドラインに何か入力されていればそれをnameに，何もなければ「world」を代入．

最後にputs\_helloメソッドを呼び出し出力している．

[目次へ](#目次)


# 継承

継承とは既に作成されているクラスの機能を残しつつ別の機能を追加し別のクラスを作成することである．

```ruby:inher.rb
class Hello
    def hello
	  p "Hello!"
    end
end

class CallName < Hello 
    def call
	   p "Hey! Bob!"
    end
end

hey = CallName.new
hey.hello
hey.call
```

このようにCallNameというクラスはHelloの中にあるメソッドを利用でき，さらにcallというメソッドを追加することができている．


# 参考

[クラスを継承する](https://www.javadrive.jp/ruby/inherit/index1.html)



------
 - **source** ~/prog/github/grad_members_20f/members/miyanagi/post/class.org
Slackの検索結果をTSVでExportする

## 概要

以下の理由により、Slackの検索結果エクスポートしたいなぁと思ってました。

- 日報入力のときに過去自分がどこで何を発言したかサマリで知りたい
- チームメンバーの過去の取り組みとかを一覧で見たい
- 過去のやり取りをまとめてテキストで保存しておきたい

都度Slackで検索してページをいったりきたりしても良いのですが、リンクをクリックしてしまったりすると検索のモーダルが解除されてしまって、もう一度検索し直さないといけないので結構面倒です。

そこで、Slackの検索結果に対して表示されているメッセージを全ページ分収集し、サマリをTSVで表示するスクリプトを作りました。

## 作ったもの

> xshoji/slack-search-result-exporter： Exports Slack messages as TSV from Search results.
> https://github.com/xshoji/slack-search-result-exporter

以下、デモです。
![demo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51707/a5a0fccd-9744-cccf-2aad-dadb6d762e2a.gif)

以下、使い方です。

* 20230425: 実行方法をbookmarklet方式に修正しました

## スクリプトをBookmarkletに登録する

1. https://github.com/xshoji/slack-search-result-exporter/blob/main/slack-search-result-exporter.user.js を開きます
1. スクリプトをコピーします
1. なにか適当なブックマークを編集します（Google.comとかでOK）
1. URLフォームに、 `javascript:` という文字を先頭につけたあと、コピーしたスクリプトを貼り付けます1. そのブックマークに名前をつけます（例 `slack-search-result-exporter`）

## Slackの検索結果をExportする

1. ブラウザでslackを開きます
1. 上部の検索窓から好きな条件でメッセージを検索します
1. 検索結果がでたら、↑で作ったBookmarkletをクリックして実行します。
1. すると、別窓で検索結果のメッセージがTSV形式で吐き出されます。

※最後のポップアップが出ない場合は、ブラウザにポップアップの許可を与えてください。

以上です。