OmniAICreator/Qiita-1.07M huggingface dataset:
【Ruby on Rails】railsコマンドでsyntax errorが出る原因

エラー自体はよくある記述ミス。ただ、routes.rbの文法エラーがデータベースの作成時に出たのが気になったので記事にしました。

#エラー文とその原因
##エラー文
``` /Users/hiro_miyagi/projects/pictweet/config/routes.rb:12: syntax error, unexpected end (SyntaxError)
```

##エラーが出た状況
ルーティングの設定を行った後に、ターミナル上でrails db:createコマンドを実行したら上記エラーが出た。

##原因
config/routes.rbに文法ミスがあった。
###間違った記述
```ruby
resources :users, only: :show,
```
###正しい記述
```ruby
resources :users, only: :show
```

#疑問点と回答
##疑問点：なぜrails db:createコマンドを実行するとroutes.rbの文法エラーが出る？
データベースの作成コマンドであるrails db:createを実行したときに、routes.rbのエラーが出たことが疑問だった。

##回答：railsコマンドを実行すると、configディレクトリ内のファイルを全て読み取ってから処理を実行しているから
configディレクトリはアプリケーションの設定が記述されているファイルが格納されている。
そのため、railsコマンドを実行すると

1.　configディレクトリ内の設定を全て読み込む
2.　処理を実行（今回の場合はデータベースの作成）

という順番で処理が行われている。
なのでconfigディレクトリ内に文法エラーがあると、上記1.でsyntax errorが出る。

#結論
railsコマンドで文法エラーが発生したらconfigディレクトリのファイル（特にroutes.rb）の記述を見直そう！
暗号化とハッシュ化の違い

## 勉強前イメージ

似たような感じな気がする...けど、暗号化は元に戻せるけどハッシュ化は戻せない的な？

## 調査

### 暗号化とは

元のデータを暗号化アルゴリズムに従って、鍵を使うことで復号化できる値にすること

わかりやすいのは、共通鍵暗号方式で
AさんからBさんにデータを送る際に暗号化しますが、暗号する鍵と復号する鍵が一緒の暗号化方式です。

![共通鍵暗号Untitled Diagram.drawio - diagrams.net - Google Ch.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129517/1e7c9ddd-7a8d-6b1a-2815-5d593a0aef9b.png)


### ハッシュ化とは

元のデータをハッシュアルゴリズムに従って、不可逆変換すること
不可逆変換とは、元に戻せない状態にすることになります。
何度も同じ値をハッシュ化しても同じハッシュ値になります。

よく使われるのは、ログインの際にDBに登録しているパスワードのハッシュ値 と入力されたパスワードをハッシュ化した値を比較したりします。

![ハッシュ化Untitled Diagram.drawio - diagrams.net - Google Ch.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129517/59a9ab50-280a-f685-f803-46acb8e35629.png)


### 暗号化とハッシュ化の違い

- 暗号化 : 復号化できる(元に戻せる)
- ハッシュ化 : 不可逆変換(元に戻せない)

## 勉強後イメージ

ほぼ想像してたのと同じだった。
暗号化は戻せないといけないけど、ハッシュ化は戻さない。

## 参考

- [[セキュリティ] ハッシュ化と暗号化は違いますよ！！](https://www.marineroad.com/staff-blog/17723.html)
- [ハッシュ化とは？暗号化との違いや利用シーンを詳しく解説！](https://it-trend.jp/encryption/article/64-0065)
- [【基礎知識】暗号化とは？ハッシュ化とは？パスワードの漏洩を防ぐには？](https://qiita.com/bayasist/items/da4be3a90a97b8cf38fe)
- [パスワードを安全に保管する方法 | 暗号化とハッシュ化の違い](https://medium-company.com/%E3%83%91%E3%82%B9%E3%83%AF%E3%83%BC%E3%83%89%E6%9A%97%E5%8F%B7%E5%8C%96%E3%81%A8%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E5%8C%96/)
とりあえずJavaで納品されたwarファイルをDockerで動かす

# 背景
他社で開発された `.war` ファイルを動かすことをしており、
現状EBのTomcatを利用して立ち上げていたがローカルでのさっとした動作確認やスケーリングのしやすさを考慮してDocker化したいお気持ちだけあった。

# さっくりと動かすぞぃ
ゴールはDockerfileを書いてさっとローカルのDockerfileを完成させることです。

## Dockerfileを書いていく
```docker
FROM tomcat:8.5-jdk15-openjdk-slim

ENV CATALINA_HOME /usr/local/tomcat
ENV PATH $CATALINA_HOME/bin:$PATH
WORKDIR $CATALINA_HOME

COPY sample.war webapps/sample.war
```

tomcatのバージョンは現行で利用している8.5系でひとまず立ち上げ。
tomcatではwebapps配下にwarファイルを配備すると自動で展開をしてくれるのでtomcatのセットアップをしてwarファイルをCOPYするだけ。

## 起動する
あとは適当にタグ打ってコンテナ起動

```sh
$ docker build . -t sample:0.1
$ docker container run --name sample-container -p 80:8080 sample:0.1
```

あとはwarファイルが展開されているので `http://localhost/{warファイル名}/` にアクセス
Go.modの使い方

GOPATHを使っているとimport出来ないライブラリとか出てきて変なエラーが出てくる事があると思います。
GoModulesのgo.modを使えば解決するかもしれないので記載しておきます。

<h1>【環境】</h1>
windows10
VScode

<br>
<h3>ターミナルでgo envと打って設定を確認します</h3>
VScodeからターミナル→新しいターミナルで開いてgo envと打ち込みます。
ずらーっと色々設定が並んでくると思いますがその中の
``` GO111MODULE=```
これがデフォルトだとonになっていないので設定をonにします。

<h3> GO111MODULE=をonにする</h3>
ターミナルで
```go env -w GO111MODULE=on```
と打ち込みましょう。
もう一度go envと打って確認すると
set GO111MODULE=onとなっているはずです。
<b>※筆者はこの時、なぜかonにならず原因が分からなかったので
一度Go言語を再インストールしたところうまくいきました。</b>

<h3>go.modを配置する</h3>
プロジェクトのルートディレクトリにcdで移動して、
```go mod init example.com/m```
と打ちます。
すると、ルートディレクトリにgo.modが作成されます。
go.modが作成されてから、go build と打ち込んで
ビルドするとimportに書かれているライブラリが自動でダウンロードされます。
ダウンロードされたライブラリがgo.modに書き込まれていきます。
こういう感じで↓

```[go.mod]
module example.com

go 1.15

require github.com/labstack/echo/v4 v4.1.17
```


go.modはプロジェクト毎に作成して使います。
go.sumというファイルも自動生成されますが気にしなくて大丈夫です！

moduleの部分についての説明は<a href=https://qiita.com/flymywife/items/a871f96726805e04e212>こちら</a>
Oracle Multitenant 6 PDB作成

事前にPDBシードのファイルパスを確認

```
SQL>  alter session set container=PDB$SEED;

Session altered.

SQL> select file_name from dba_data_files;
FILE_NAME
/opt/oracle/oradata/ORCLCDB/pdbseed/system01.dbf
/opt/oracle/oradata/ORCLCDB/pdbseed/sysaux01.dbf
/opt/oracle/oradata/ORCLCDB/pdbseed/undotbs01.dbf
```

PDBシードからファイルネームコンバートをコマンドで指定して作成

```
SQL> create pluggable database orclpdb1
  2    admin user adminuser identified by password
  3    file_name_convert = (
  4    '/opt/oracle/oradata/ORCLCDB/pdbseed/'
  5  , '/opt/oracle/oradata/ORCLCDB/orclpdb1/'
  6  );

Pluggable database created.
```

初期状態

```
SQL> show pdbs
  CON_ID CON_NAME   OPEN MODE   RESTRICTED
       2 PDB$SEED   READ ONLY   NO
       3 ORCLPDB1   MOUNTED
```

起動、自動起動ON

```
SQL> alter pluggable database orclpdb1 open;

Pluggable database altered.

SQL> alter pluggable database orclpdb1 save state;

Pluggable database altered.

SQL> show pdbs
  CON_ID CON_NAME   OPEN MODE    RESTRICTED
       2 PDB$SEED   READ ONLY    NO
       3 ORCLPDB1   READ WRITE   NO
```

PDBに直接接続

```
# sql adminuser/password@orclpdb1
SQL> 
```

PDB作成時に指定する管理者ユーザにはユーザー作成権限がないらしい

```
SQL> create user scott identified by tiger;

create user scott identified by tiger
 *
ERROR at line 1:
ORA-01031: insufficient privileges
```

sysで接続
users表領域がないので作成
消したっけ

```
SQL> create tablespace users datafile '/opt/oracle/oradata/ORCLCDB/orclpdb1/users.dbf' size 10m autoextend on maxsize unlimited;
Tablespace created.
```

sysでユーザー作成
デフォルト表領域にusersを指定

```
# sql sys/password@orclpdb1 as sysdba
SQL> create user scott identified by tiger default tablespace users;

User created.

SQL> grant create session to scott;

Grant succeeded.

SQL> grant create table to scott;

Grant succeeded.

SQL> grant unlimited tablespace to scott;

Grant succeeded.
```

ユーザーで接続してテーブル作成
権限OK

```
SQL> create table test(col number);

Table created.

SQL> drop table test;

Table dropped.
```
繰り返し処理

##繰り返し処理とは
１０回同じ処理をするのに１０回同じコードを書いていたら大変で見づらいコードになってしまいます。書くのも大変だし修正があったときはめんどくさいです。
そうならないために同じ処理を何回も繰り返したい時に使う処理です。

###timesメソッド
同じ処理を複数回繰り返したい時に使うメソッド

```
数値.times do
  # 繰り返す処理
end
```

例えば

```
5.times do
  puts "hello"
end

hello
hello
hello
hello
hello

と出力される
```



##ブロック変数
メソッドの中だけで使用できる変数を||で囲うブロックを使うことで違う処理が実行できます。
ブロックで囲まれた変数をブロック変数と呼ぶ。

timesメソッドのブロック変数には、繰り返し処理が1回実行されるごとに、0から1ずつ増加する数値が代入されます。

```
数値.times do |ブロック変数|　  #繰り返すたびに 0から１ずつ増えていく
  # 繰り返す処理
end
```

例えば

```
5.times do |i| #ブロック変数としてiを定義
  puts i + 2
end

2
3
4
5
6

と出力される。
```

##eachメソッド
配列の中に入っている要素ひとつひとつに対して、要素の数だけ繰り返し処理が行なわれるメソッドです。

```
配列.each do |item|
  # 処理
end
```
eachに続けてdoとendの間に繰り返したい処理を記述します。
ブロック変数には配列の要素が入り、繰り返すたびに置き換えられます。

例えば

```
animals = ["cat","dog","rabbit"] 　　##配列を定義

animals.each do |animal|
  puts "動物:#{animal}"
end

動物:cat
動物:dog
動物:rabbit

と出力される。
```
以上です。
PHP 変数が空かどうか判定する

# 目的

- PHPで変数が空かどうか判定する方法をメモ的にまとめる

# 情報

- 下記サービスを用いて本記事の内容を検証した。
    - [https://paiza.io/ja](https://paiza.io/ja)

# 方法

- empty()関数を用いて変数が空かどうかを判定する。empty()関数は空の場合trueを返す。
- 下記を実行すると変数`$str`は空のため「Empty data」の文字列が出力される。

    ```php
    <?php

    $str = '';

    if (empty($str)) {
        echo 'Empty data';
    }
    ```

# 参考文献

- [https://www.php.net/manual/ja/function.empty.php](https://www.php.net/manual/ja/function.empty.php)
Redmineでチケット新規作成する時は期限日=開始日にしたいなあ

#何がしたいん？

あたいの場合はRedmineをTODOアプリ的に使ってます。

んでもって、チケットの **期日** は開始日と同じなことが多いです。

でも新規作成画面はいつも空欄なので、いちいちマウスでポチポチしないといけないです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/6deeb0ac-c09c-f4be-98a2-273e08dfcc81.png)
面倒くさいし入力漏れして見逃しとかしちゃいそう…。
ということで期日の初期値を設定します。

#ビューカスタマイズプラグインで実現しますです

必殺技 **『目につく設定項目をとにかく全部見て回る』** をやってみたけどRedmineには期日の初期値設定みたいなのは無さそうだった…。
ということで **ビューカスタマイズプラグイン** をRedmineにインストールしてJavaScriptをちょろちょろっと書くことにしました。

ビューカスタマイズプラグインってなんぞや？って時は下記ね。
[CentOS8にインストールしたRedmineにビューカスタマイズプラグイン導入](https://qiita.com/waokitsune/items/d08c96bf44b32000981e)

#設定はこんな感じ

RedmineにはJQueryがデフォルトで搭載されてるから、JQueryで書いちゃうのがお手軽かなって思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/83a9098f-5f65-6f2b-ed6f-846ebc637da2.png)

↓コピペ用

```javascript:
$(function(){
	var val_ = $('#issue_start_date').val();
	$('#issue_due_date').val(val_);
})
```

#蛇足

次カスタマイズするとしたらこんな感じかな…。

* チケットをコピーした時は開始日と期日をそれぞれ+1日加算！（日次のルーチン入力するのが楽になる）
* 『期日を今週末に』『期日を今月末に』的なボタンを設置して期日をワンクリックで設定できるように！

『担当者のデフォルトをログインしているユーザーに』っていうこともできそうだなあ。


#バージョン
CentOS Linux release 8.3.2011
Redmine 4.0.6.stable
Windows10(20H2)で、外部ツールなしでDvorak配列を使う

# 概要
Dvorakという素晴らしいキー配列があるのですが、Windowsでは設定が面倒です。今まで私は外部ツールを使ってDvorakに対応していたのですが、Windows Updateで20H2に上げたところ外部ツールがうまく動かなくなってしまいました。
色々試しましたが、結局外部ツールなしでレジストリ書き換えで対応することに落ち着きました。

# 設定内容
「regedit」を開き、以下の通り設定して再起動します。**レジストリを直接編集しますので、参考にする場合はちゃんとバックアップをとった上で自己責任でお願いします。**

* `HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layouts\00000411` の `Layout File` の設定値を「KBDDV.DLL」に変更する
* `HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\i8042prt\Parameters` の `LayerDriver JPN` の設定値を「kbddv.dll」に変更する

# 補足
* 大文字小文字は参考サイトのままになっているので統一されてないです
* 以前は上の変更だけでよかったのですが、今は両方やらないとダメみたいです。また何かの拍子に変わっちゃうかもしれないので、あくまでも記事執筆時点での情報ということになります
* 「半角/全角キー」を押すと、切り替わらずバッククオートが入力されてしまいます。入力切り替えしたい場合は「Altキー」を押しながら「半角/全角キー」を押します。何か設定で変えられるのだろうか
* ショートカットキーのために「CtrlやWinキーを押している間だけQwertyに戻す」とかはやり方がわかりません。私はもう諦めてますけど

# 参考
* https://qiita.com/dvorak__/items/025f22faacab402facf9
* https://ja.wikipedia.org/wiki/Dvorak%E9%85%8D%E5%88%97#Windows
中学3年生がコロナで暇なので本気で茶コーダーを目指す【競プロ】~1日目~

#シリーズ
**中学3年生がコロナで暇なので本気で茶コーダーを目指す**
[第二話(1/17)](https://qiita.com/hyugo/items/2335f6e6fc12b1f3b305)
[第三話(1/18)](https://qiita.com/hyugo/items/12463805791bb4d45ce4)

※お願い(1/18追記)
数学に関して色々読み進めているうちに色々自分だけではどうしてもわからない部分が出てきていて、、
数学や技術知識を皆様にご教授いただきたいです

Qiitaのコメント欄だけではどうしても限界が出てくる
ということで、Atcorder教えてもらう専用のdiscordサーバーを作成しました。
[こちらの招待リンク](https://discord.gg/YEyxKxCAHq)から参加していただき、
`一言` というスレッドに一言いただけたら助かります。

皆さんの想像を超えるくらい数学ができないので、初歩的な質問をすることになりますが、温かい目で見守っていただけたら助かります。


#自己紹介/競プロを始めようと思ったきっかけ
名前:Hyugo
年齢:15
扱えるプログラミング言語:Python/JavaScript/Ruby
普段やっていること:自然言語処理で遊ぶ/GANを構築して画像などを学習させる

##きっかけ
上にもある通り普段はGANで生産された画像が毎日綺麗になっていくのを感じることを
たまごっち感覚で楽しんでいます。
ですが、これ以外に楽しむことがなく、もっと有効な使い道はないかと思い、競プロを始めました。

ただ単に、競技プログラミングをしても、つまらないな、、、ということでQiitaを漁っていたところ、
[この記事](https://qiita.com/RubyLrving/items/0d51d2550669cbddb8fa)をみつけ、
この記事を参考にC++を学んで、茶コーダーを目指そうと思いました。

#1日目(1/16)にやったこと
[APG4b](https://atcoder.jp/contests/apg4b)の内容をノートに取りながら読み進めました。
![IMG_0244.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/921821/6eff2b85-470c-a44e-2b98-bc1ea005bc28.jpeg)


とりあえず、1日目は1.1.2まで読み進め、もともと知っていましたが、全く手を付けていなかった
[AIZU ONLINE JUDGE](http://judge.u-aizu.ac.jp/onlinejudge/index.jsp)を
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/921821/b0001e25-1ba7-53cc-268f-93a03fae1a21.png)

この辺までクリアしました、

C++をやってて面白いなぁって思ったことは

```
N
A B
```
のような値を受け取るとき、
Pythonでは、`split()` や `map()` などの組み込み関数を使わなきゃいけないと思うんですが、
C++では

```c++
#include <bits/stdc++.h>
using namespace std;

int main() {
  int n,a,b;
  cin >> n >> a >> b;
}
```
で受け取れること。

逆にめんどくさいなぁって思ったのは
変数の宣言が必要なことぐらいです。

cinだけで、値の受け取りが完結する点とかも、C++が競プロで強いって言われる理由の1つなんですかね

#これからの課題
そもそも、根本になってしまうんですが、自分数Ⅰの成績が10段階評価で1なので、そこをどうにかしようって思います。

あとは、3日坊主になることがないように勉強し続け、(この記事はモチベ維持用でもある)
ゴールまで頑張ります。

#これからやること
1/23の ABCに参加して実力試しをしてみようと思います。
WSLのネットワークアダプターが無い現象

結論から言うとWSL2じゃなかった。

HTML開発環境を整えようとした過程の話。
とりあえずIPがどうなってるか調べたら意外と面倒だった。

既にWSL1は廃れた感じでWSL2の記事しか見当たらない。
WSL2では仮想ネットワークアダプターがWindows側に出るようだ。

確認してみる。当然のようにない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76720/015274b5-d321-f5aa-ccc5-07d56329115d.png)
という事でWSLのバージョン確認。
```
C:\Users\****>wsl --list --verbose
NAME STATE VERSION
* Ubuntu-18.04 Running 1
```
WSL2がリリースされてからインストールしたはずだけどなー。と思いつつ、WSL2へのバージョン変更。

１．windowsのバージョンも一応確認。winverコマンドは覚えやすくて大変良い。2004だからWSL2対応しているはず。
２．WSLの開始、停止、再起動
https://qiita.com/quzq/items/6b9785f65705b27455ed
３．WSL バージョンを変更する方法 | SEECK.JP サポート
https://kb.seeck.jp/archives/16950

バージョン変更する方法はエラーも含め懇切丁寧に書いてあった。当環境ではカーネル更新とWindowsの機能追加が必要でした。

WSL2へのバージョン変更がなかなか終わらないので一旦風呂。そして風呂上がってきても終わっていない！
　→Enter押したら終わりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76720/3de942ba-2bd1-55a7-b7fd-60126c7f68fb.png)
無事現れました。
LISPでGPGPU(2)  組み込み関数の拡張

#はじめに
自作LISPにGPGPU機能を追加しています。

#フロート専用配列
Deep-Learningで必要とされるのはfloat型の配列です。それをもとに行列積の計算、畳み込み演算などを行います。ISLispスタンダードで規定されている配列はその要素としてあらゆる型をとります。これをそのまま使うとDeep-Learningではメモリ効率が悪いです。そこでフロート専用の配列を用意しました。

```
#2f((1.0 2.0)(3.0 4.0))

```

#create-array組込み関数の拡張
ISLispスタンダードにあるcreate-arrayは次のようになっています。

```
(create-array dimension initial-value)

(create-array '(3 3) 2)

```

これに次ぎの拡張を加えました。

```
(create-array dimension initial-value 'float)

(create-array '(3 3) 0.1 'float)

(create-array '(3 3) 'rand 'float)

```

第3引数にシンボルfloatを与えるとfloat型の配列を生成します。
初期値にシンボルrandを与えると初期値を０～１の乱数とします。

#ベンチマーク
GTX1650 でのベンチマークです。

```
$ ./eisl
Easy-ISLisp Ver1.70
> (defglobal a (create-array '(3000 3000) 'rand 'float))
A
> (gpu-mult a a)
#2f(float-element)
> (time (gpu-mult a a))
Elapsed Time(second)=0.087010
<undef>
> (time (gpu-mult a a))
Elapsed Time(second)=0.064966
<undef>
> 

```
【自分用メモ】Firestore、前と1個もコード変わってないのになぜかアプリが動かない時

#久々にアプリをビルドすると何故か動かん
前とコードいっこも変わってへんのに...！！！！
ナンデダヨォォォ！！！！

まずは冷静になりましょう。
Firebase周りで日付が関係する部分はこちら。
`Firestore > ルール` の部分↓

```
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if
          request.time < timestamp.date(2021, 12, 1);
    }
  }
}
```
`timestamp.date()`の中の日付が過去の日付になっている時、アプリがビルドできなくなります。

#対処法
とりあえず未来の日付に打ち直す。直接いじっていいです。

# おまけ
こんなところで躓くこともあるのかぁと思いました。忘れちゃいそうなので一応メモ。
これで上手くいかない場合はSHA1を登録し直すとかしてみよう。
scikit-learnのroc_auc_score関数に関する軽微なメモ

#はじめに
大した話ではないのだがメモ。理由の掘り下げはしていない。

#環境
- sklearn 0.22.2.post1

#scikit-learnでのrocaucの計算方法

以下のように実行する。tには正解値、yには予測値を与える

```py
from sklearn import metrics
t = [0,1,0]
y = [1,0,0]
rocauc = metrics.roc_auc_score(t, y)
print(rocauc)
```

#メモ
## 正解値に3値以上が含まれるとエラーとなる。
```py
from sklearn import metrics
t = [0,1,3]
y = [1,0,0]
rocauc = metrics.roc_auc_score(t, y)
print(rocauc)
```
multi_classの指定をすればでないらしい。

エラー内容
```ValueError: multi_class must be in ('ovo', 'ovr')```


## 正解値に1値しかない場合エラーとなる。

```py
from sklearn import metrics
t = [0,0,0]
y = [1,0,0]
rocauc = metrics.roc_auc_score(t, y)
print(rocauc)
```

エラー内容
```ValueError: Only one class present in y_true. ROC AUC score is not defined in that case.```


## 予測値は必ずしも0～1の確率でなくてもよく、スコアでも構わない
どういう計算になるかは、また機会があれば。。
Reactで作るタブ

Reactで作る理解のしやすいタブのテンプレが、Qiitaに置いてあればと思い書きました。
基本的には[こちら](https://medium.com/weekly-webtips/create-basic-tabs-component-react-typescript-231a2327f7b6)の記事を元に作成させていただきましたが、一部修正しています。

## 環境
- react 18.2.0
- typescript 4.7.4

## ディレクトリ構成

```
src/
├── components
│   ├── Tab.tsx
│   ├── TabTitle.tsx
│   └── Tabs.tsx
└── index.tsx
```

## 完成はこんな感じ
Lemonをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517223/1604617f-ec41-fe26-9f07-fe4b96834339.png)

Strawberryをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517223/512a5cae-ca37-14cc-cbca-0d4e0c2e8a35.png)

Pearをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517223/4cf3e817-ff4e-d131-2711-e22283b05357.png)

## Tabs.tsx

```tsx:Tabs.tsx
import { FC, ReactNode, useState } from 'react';
import TabTitle from './TabTitle';

interface Props {
  children: ReactNode;
};

const Tabs: FC<Props> = ({ children }) => {
  const [selectedTab, setSelectedTab] = useState(0);

  return (
    <div>
      <ul>
        {children.map((item, index) => (
          <TabTitle
            key={index}
            title={item.props.title}
            index={index}
            setSelectedTab={setSelectedTab}
          />
        ))}
      </ul>
      {children[selectedTab]}
    </div>
  );
};

export default Tabs;
```

## TabTitle.tsx

```tsx:TabTitle.tsx
import { FC, useCallback } from 'react';

type Props = {
  title: string;
  index: number;
  setSelectedTab: (index: number) => void;
};

const TabTitle: FC<Props> = ({ title, index, setSelectedTab }) => {
  const onClick = useCallback(() => {
    setSelectedTab(index);
  }, [setSelectedTab, index]);

  return (
    <li>
      <button onClick={onClick}>{title}</button>
    </li>
  );
};

export default TabTitle;
```

## Tab.tsx

```tsx:Tab.tsx
import { FC, ReactNode } from 'react';

type Props = {
  title: string;
  children: ReactNode;
};

const Tab: FC<Props> = ({ children }) => {
  return <div>{children}</div>;
};

export default Tab;
```
## index.tsx

```index.tsx
import { FC } from 'react';
import Tab from '../components/Tabs/Tab';
import Tabs from '../components/Tabs/Tabs';

const index: FC = () => {
  return (
    <Tabs>
      <Tab title='Lemon'>Lemon is yellow</Tab>
      <Tab title='Strawberry'>Strawberry is red</Tab>
      <Tab title='Pear'>Pear is green</Tab>
    </Tabs>
  );
};

export default index;
```
CentOS8にインストールしたRedmineにビューカスタマイズプラグイン導入

#/var/lib/にRedmineをインストールした前提です

下記の記事の続きって感じです。
[CentOS8にプロジェクト管理ツール『Redmine』をインストール（データベースはPostgreね）](https://qiita.com/waokitsune/items/522ab56519235e7fef87)

どこにインストールしたかは、 git clone や bundle のフォルダーパスに影響します。


#プラグインのインストール方法

ビューカスタマイズのソースコードを頂きます。

```sh:
git clone https://github.com/onozaty/redmine-view-customize.git /var/lib/redmine/plugins/view_customize
```

ビューカスタマイズが動くように環境を整えます。
（必要なモジュールのインストールやデータベースの設定など）

```sh:
cd /var/lib/redmine
bundle install --without development test
bundle exec rake redmine:plugins:migrate RAILS_ENV=production
```

WEBサーバーを再起動してインストール完了です。

```sh:
systemctl restart httpd
```

#動作確認してみようじゃん！

**管理** ページに **表示のカスタマイズ** が追加されてます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/1d6ed801-28ec-3ec9-6652-32b6b9ebe4e1.png)

**新しい表示のカスタマイズ** へ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/09db39e9-28ad-699d-dc54-1d87614b4831.png)

ひとまずこんな感じで。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/04f95c44-ec75-1d15-9e40-133182954d35.png)

どのページを開いても ~~うざい~~ 親切なダイアログが出てくれるようになりました！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/d2f18edc-99c2-8541-6968-395df788e8b8.png)

#蛇足

ちょっと使い勝手を良くするレベルならオリジナルテーマ作るよりビューカスタマイズプラグインの方がいいかもね。

#参考サイトさん

https://blog.katsubemakito.net/redmine/install-viewcustomize

#バージョン

CentOS Linux release 8.3.2011
Redmine 4.0.6.stable
CCNA備忘録　OSI参照モデル・ TCP/IPモデル

#はじめに

重要だと思うところ、理解に時間がかかったところを中心に、忘れるに備えるという意味で備忘録として残しています。

#OSI参照モデル

異なるベンダーの機器間でも通信をできるようにISO（国際標準化機構）によって定められたもの。

なお、インターネットの普及によって事実上TCP/IPモデルが標準となっており、実際には利用されていない。

![OSI参照.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1017955/2a28b4a7-c7b7-948a-06f1-b64f5a0f24d0.png)

通信を行うための機能を７つの階層に分け、それぞれの役割を定めている。
送信元からデータを送る際には、上の層から順番に、通信に必要な情報が付加される。

###カプセル化と非カプセル化

通信を行う際、上の階層から下の階層にデータが渡されていき、最終的に物理層で電気信号に変換されてケーブル上に送信される。
このとき、各階層でデータを送信するために必要な情報は、ヘッダという形でデータの先頭に付与される。

各階層でヘッダを作成し、上の階層から渡されたヘッダ＋データをデータとして、新たにヘッダを付加して通信データを作成する。

このことを**カプセル化**という。

一方、**非カプセル化**とは、受信側で下位層のデータからその階層のヘッダを取り除き、データを上位層に渡すことをいう。

#TCP/IPモデル

現在のインターネット通信および、イントラネット通信において最も利用されている通信プロトコル。

![TCP・IP.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1017955/3f43aeda-023f-63ee-a6c3-00c4721c30e0.png)

























![TCP.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1017955/ad0ce549-232d-793d-6022-2b5741f7565f.png)

###アプリケーション層

webサイトや電子メールなど、インターネット上で提供されている各種サービスとデータのやり取りをする階層

![アプリ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1017955/63ca8eb5-4c0e-47fb-b999-fccb67983866.png)

###トランスポート層

アプリケーション層で利用されているプロトコル間での通信を制御する。

トランスポート層では、上位層のプロトコル間通信の橋渡し役として主に***TCP***または***UDP***を利用します。

![TCP UDP.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1017955/a5755878-17a5-a569-f0af-be31cc46b461.png)

###インターネット層

エンドーツーエンドの通信を制御する。
![インターネット.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1017955/728a1751-942c-b5d2-0be6-17ec341e04d1.png)

###リンク層

直接接続されている機器同士の通信を制御する。![リンク.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1017955/467153c5-e5fa-4b6b-a1dc-127ab0aacbef.png)
Cloud9でWordPress環境を構築 3

WordPressの学習＆AWSに触れるのを目的として
AWS Cloud9でWordPress環境を構築するまでの備忘録。環境構築完了。

#ここまでやったこと
- Cloud9環境立ち上げ
- MySQLセットアップ
- Apache、MySQLサービス起動
- スナップショット作成

#この記事の目次
 - WordPressセットアップ
  - 前準備
  - インストール

基本これに従う。
https://docs.aws.amazon.com/ja_jp/cloud9/latest/user-guide/sample-wordpress.html

#WordPressセットアップ
##前準備

WordPressをダウンロード＆展開する。

~~~
wget http://wordpress.org/latest.tar.gz
tar -xzvf latest.tar.gz
~~~

`wp-config-sample.php`を`wp-config.php`に名前変更して利用する。

~~~
cd wordpress
mv wp-config-sample.php wp-config.php
~~~

`wp-config.php`内の3箇所をMySQLで作成したデータベースに合わせる。

~~~
define( 'DB_NAME', 'データベース名' );
define( 'DB_USER', 'ユーザ名' );
define( 'DB_PASSWORD', 'パスワード' );
~~~

Amazonのサイトに記載はないが、セキュリティ的な対応をしておく。
次の値をサイトでランダムに生成して書き換える。
https://api.wordpress.org/secret-key/1.1/salt/ 

~~~
define('AUTH_KEY', 'XXXXX');
define('SECURE_AUTH_KEY', 'XXXXX');
define('LOGGED_IN_KEY', 'XXXX');
define('NONCE_KEY', 'XXXX');
define('AUTH_SALT', 'XXXX');
define('SECURE_AUTH_SALT', 'XXXX');
define('LOGGED_IN_SALT',   'XXXX');
define('NONCE_SALT', 'XXXX');
~~~

##インストール

`index.php`をエディタで開いてメインメニューバーからRunを実行する。
メインメニューバーのPreview > Preview Running Application を実行する。
Not Foundのエラー画面が出る。これは正常。
![スクリーンショット 2021-01-17 10.07.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1031177/d0cce8ec-f8aa-56c8-1800-a42dde49117d.png)

ブラウザのパスに`/wordpress/`を追加する。
これでインストール画面が出るらしいが、ずっとぐるぐるして画面が表示されない。
![スクリーンショット 2021-01-17 10.07.31のコピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1031177/f8fb388e-1d42-8833-b17d-3f96cda8b306.png)

追加するURLを`/wordpress/readme.html`に変更する。画面が表示される。
(ここが分からず、色々いじって何回かCloud9の環境を作成しなおした……)
![スクリーンショット 2021-01-17 10.29.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1031177/42faf600-5e2d-08c4-4ba8-a67ae70f5020.png)



`install.php`へのリンクをクリックしてインストールを進める。
![スクリーンショット 2021-01-17 10.41.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1031177/918c893b-2da1-4a92-0fdc-5894a49b3a21.png)

ようやくWordPressのインストールまで完了した。
AWSの用語が分からなかったり、プリインストールのMySQLが動かなかったりで
結構時間がかかってしまった……。

今後はこの環境を使ってWordPressの学習を進める。

前の記事へのリンク
[Cloud9でWordPress環境を構築 1](https://qiita.com/ttyoku/items/cd033bc3185d5fa05422)
[Cloud9でWordPress環境を構築 2](https://qiita.com/ttyoku/items/f7b5c763cbe5ff80eed4)
Ruby　チェリー本復習

# なにこれ
筆者がチェリー本を読んだ時のメモをまとめた記事です。

## ぼっち演算子「&.」
変数（レシーバー）がnilだった場合はnilを返して、nilじゃなければ右辺の処理を実行する
変数に値がある or nilか確定できない時に使うと簡潔に書ける。

```rb
user = ‘suga’
p user&.upcase #=> SUGA

user = nil
p user&.upcase #=> nil
```

ちなみにそのままnilにupcaseメソッドを使うと下記のエラーが出る

```rb
user = nil
p usesr.upcase

undefined method `upcase' for nil:NilClass (NoMethodError)
# NoMethodError：NilClassのnilオブジェクトにupcaseメソッドは定義されてません
```

## rubyは配列の最後にカンマをつける文化らしい
jsonとかとは違って厳密に管理しないから、配列の最後にカンマをつけるみたい。
「カンマつけるかどっちでも良い＝じゃあつけよう！」みたいな感じですかね。

```rb
array = [
  'hoge',
  'fuga',
  'piyo',
]
```

## **でハッシュを展開する

```
h={hoge: 'hoge', piyo: 'piyo'}
p a = { fuga: 'fuga', **h } #=> {:fuga=>"fuga", :hoge=>"hoge", :piyo=>"piyo"}
```

## 配列を順番に処理する時、「&:method」を使う
内部にprocをつかうことで引数にブロックを取れる

```rb
a = ['a','b','c']
p a.map(&:upcase)
```

## nilが渡される可能性のある配列は、Array(users)みたいにArrayクラスを定義して、引数に変数を渡せば処理できる。nilの場合は`[ ]`が返る

## ||=
railsとかのソースコードでよく見るこれ。毎回忘れるので備忘録として書きます。
下記は全て同じ意味。省略して書けるのがメリットです。

```rb
test = nil
p test ||= 'hoge' #=> ‘hoge’

p obj.foo #=> nil
p obj.foo || (obj.foo = true) #=> true

test = nil
if test.nil?
  p 'hoge'
else
  p test
end #=> ‘hoge’
```

```rb
test = 'fugaaaaaaaaaaaa’
p test ||= 'hoge’ #=> ‘fugaaaaaaaaaaaa’

test = 'fugaaaaaaaaaaaa’
if test.nil?
  p 'hoge'
else
  p test
end #=> ‘fugaaaaaaaaaaaa’
```

## any?メソッド
一つ以上条件が満たせばtrueを返す

```rb
array_and_nil = [1, 2, nil, nil, 5]
p array_and_nil.any?(&:nil?) #=> true
```

```rb
require 'active_support/all'

hoge = nil
def piyo(hoge)
  hoge || return
end
piyo(hoge) #=> nil
```

## 2重for文を避けられる。でも使い所が難しそう

```rb
tx = %w(1 2 3 4 5)
ty = %w(a b c d e)

for point in tx.product(ty)
  p(point)
end
```


## &:
下記みたいなコード。渡すブロックを省略できる。

これができる条件
1．ブロック引数が1個だけ
2．ブロックの中で呼び出すメソッドには引数がない
3．ブロック引数にメソッドを1回呼び出す以外の処理がない

```rb
n=[1,2,3,4,5,6]
n2=n.select(&:even?)
```

## attr_accessor
呼び方は、個人的にアトリビュートアクセッサーって読んでる。
周りの人はアクセッサーって言ってるかも

役割は、端的に言うと下記のコードを1行で書ける

```rb
  def name
    @name
  end

  def name=(name)
    @name = name
  end
```

上の6行のコードが次の1行になる

```rb
  attr_accessor :name
```

## インスタンスからクラスメソッドを呼び出す方法
`self.class.【クラスメソッド】`すればおk

```rb
class User
  def self.self_
    p 'self'
  end
  def instance_
    self.class.self_
  end
end
a = User.new
a.instance_ #=> 'self'
```

既存のメソッドのエイリアスを作成した後にメソッドを上書き➡️prepend?

特定のオブジェクトだけに結びつくのが、特異メソッド（シングルトンオブジェクトとも言う）

```rb
hoge = 'hoge'
def hoge.hello
  p 'hoge!'
end
hoge.hello #=> 'hoge!'
```

includeはモジュールのメソッドをインスタンスから呼べるようにする。
extendはクラスメソッドにする
大規模分散処理のフレームワーク：Hadoop／Spark

データ分析基盤の理解を深めるために、[ビッグデータを支える技術](https://amzn.to/3q6n5kY)を学習中。
今回は、分散処理フレームワークの**Hadoop/Spark**について。

# データ構造化のパイプライン

非構造化データを、構造化データへと変換することで他のデータと同様に分析できるようにする。
![datastructure.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/991759/8494f6e0-0cad-b9c3-5a92-3df745854aa8.png)
Webサーバーのログファイルや、業務用マスターテーブルなどのデータソースを、分散ストレージに格納し、分散データ処理をし、構造化データに変換する。

分散データ処理フレームワークにHadoopやSparkなどがある。

# Hadoop
Hadoopは単体のソフトウェアではなく、分散システムを構成する多数のソフトウェアからなる集合体。
![apacheproject.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/991759/1aaaec0f-b859-e8e6-e5a4-142a34e0b842.png)

|機能 |説明 |
|:--|:--|
|分散ファイルシステム   |ネットワーク接続されたファイルサーバーのような存在。多数のコンピュータにファイルをコピーすることで冗長性を高める特徴。   |
|リソースマネージャ   |CPUやメモリなどの計算リソースを管理。   |
|分散データ処理   |MapReduceは任意のJavaプログラムを走らせることができるため、非構造化データを加工するのに適している。SQLなどのクエリ言語によるデータ集計が目的であれば、そのために設計されたクエリエンジン（Apache Sparkなど）を利用する。   |
|クエリエンジン   |対話型のクエリ実行だけに特化したクエリエンジン。瞬間最大速度を上げるためにあらゆるオーバーヘッドが排除されており、使えるリソースを最大限に活用してクエリ実行。   |

Hadopの基本となるコンポーネントは、**分散ファイルシステム**である**HDFS**、**リソースマネージャ**である**YARN**、**分散データ処理**の基盤である**MapReduce**の3つ。

それ以外のプロジェクトはHadoop本体とは独立して開発されており、Hadoopを利用する分散アプリケーションとして動作。多様なアプリケーションを組み合わせて、自分に合ったシステムを組み上げるのが、Hadoopを中心とするデータ処理の特徴。


# Spark
SparkはHadoopを置き換えるものではなく、MapReduceを置き換える存在。大量のメモリを活用して高速化を実現することが特徴。MapReduceが開発された時代は、少ないメモリしか使えなかったため、MapReduceの処理の大半はディスクの読み書きに費やしていた。

Sparkは大規模なバッチ処理だけでなく、SQLによる対話的なクエリ実行や、リアルタイムのストリーム処理にまで広く利用されている。

|機能 |説明 |
|:--|:--|
|Spark SQL   |SQLでクエリを実行   |
|Spark Streaming   |ストリーム処理を実行   |
プログラマーが周りを驚かせたワイヤーフレームの作り方

# プログラマーが周りを驚かせたワイヤーフレームの作り方

センスなんて入りません、そうBalsamiq Wireframes を使えばね！

Balsamiq Wireframes（以降Balsamiq） はWebやアプリのデザインの設計図を描くためのツール
直感的に使えるので学習なしですぐに始められる。

[Balsamiq Wireframes for Desktop](https://balsamiq.com/wireframes/desktop/#) からダウンロード

## サイトマップ作成

ヘッダーメニューからSiteMapを選択してドラッグアンドドロップするとサイトマップが作成される。
![Balsamiq_Tutorial_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59264/d9a19199-47bb-3112-ca7c-6eae5e5f87e1.png)

サイトマップをダブルクリックすると編集モードになり編集するとサイトマップが更新される。
![Balsamiq_Tutorial_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59264/8b05649d-7867-2e00-0a00-59fc568c67e0.png)
![Balsamiq_Tutorial_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59264/5e6e11ae-f053-a851-3af5-1f6b08513263.png)

## ワイヤーフレーム作成

ヘッダーメニューからアイテムを選択してドラッグアンドドロップして組み立てる。
WEB、アプリに必要なアイテムは大体揃っている。
下のは一例、かなり直感的に作れるのでガンガントライアンドエラーする。
![Balsamiq_Tutorial_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59264/b715d441-9a4e-44a7-6682-248f7576687b.png)

## エクスポート
メニュー -> File -> ExportにてPNG、PDF形式でエクスポートできる。
![Balsamiq_Tutorial_5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59264/d5c07feb-2cd5-9146-d75f-d073535e5626.png)

## その他
Balsamiq のデフォルトでは見た目がSketchっぽいレイアウトだが
Project Informationより見た目をスッキリしたものに変更できる。
個人的にはSketchの方が味があって好きだ。
![Balsamiq_Tutorial_6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59264/76f3e882-43d0-4a5b-d215-0f5a8903e5c7.png)
Power BI DAXで日付テーブルを作成する


以下のYoutubeビデオで、カレンダーテーブルの作成について詳しく紹介されていましたので、カレンダーテーブルを作ったことがない方はぜひご覧ください。

https://www.youtube.com/watch?v=AieQMS6rGvM

　また、この記事より @ishiayaya さんの記事の方が役に立ちます。

https://qiita.com/ishiayaya/items/a24fb8952389bf65de7b


```
DateTable = 
// 日付を指定するか、CALENDARAUTOに任せるか
// VAR BaseCalendar = CALENDAR( DATE(2016,1,1), DATE(2018,12,31) )
VAR BaseCalendar = CALENDARAUTO()
RETURN
    GENERATE(
        BaseCalendar,
        VAR BaseDate = [Date]
        VAR DayNumber = DAY( basedate )
        VAR YearDate = YEAR( BaseDate )
        VAR MonthNumber = MONTH( BaseDate )
        VAR YearMonthName = FORMAT( BaseDate, "yyyymm" )
        VAR YearMonthNumber = YearDate * 12 + MonthNumber - 1
        VAR YearMonthDayName = FORMAT( BaseDate, "yyyymmdd" )
        VAR DayOfWeekName = FORMAT( BaseDate, "aaa", "ja-JP" )
        // // 月曜スタート
        // VAR DayOfWeekNumber = WEEKDAY( BaseDate, 3 )
        // VAR StartOfWeek = BaseDate - DayOfWeekNumber
        // 日曜スタート
        VAR DayOfWeekNumber = WEEKDAY( BaseDate, 1 )
        VAR StartOfWeek = BaseDate - DayOfWeekNumber - 1
        //
        VAR YearWeekNumber = WEEKNUM( BaseDate )
        VAR EndDate = EOMONTH( BaseDate, 0 )
        VAR DaysOfMonth = DATEDIFF( BaseDate, EDATE( BaseDate , 1 ), DAY )
        RETURN ROW (
            // English
            "Year", YearDate,
            "Month", MonthNumber,
            "Day", DayNumber,
            "YearMonth_Number", YearMonthNumber,
            "YearMonth", YearMonthName,
            "YearMonthDay", YearMonthDayName,
            "Week", DayOfWeekName,
            "WeekNumber", DayOfWeekNumber,
            "YearWeekNumber", YearWeekNumber,
            "WeekStartDate", StartOfWeek,
            "EndOfMonth", EndDate,
            "Days of Month", DaysOfMonth
            // // Japanese
            // "年", YearDate,
            // "月", MonthNumber,
            // "日", DayNumber,
            // "年月_番号", YearMonthNumber,
            // "年月", YearMonthName,
            // "年月日", YearMonthDayName,
            // "曜日", DayOfWeekName,
            // "曜日_番号", DayOfWeekNumber,
            // "年曜日_番号", YearWeekNumber,
            // "週開始日", StartOfWeek,
            // "月末日", EndDate,
            // "月日数", DaysOfMonth
        )
    )
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/a38071cf-13f5-24a8-5741-56ce458cf1fc.png)
ゼロからサイトを作る①

#デイトラWeb制作コース　初級編DAY5の学び

# 【この記事に書いてあること】
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">プログラミング学習5日目⏩<br><br>目標:Web制作コース 初級編DAY5💻<br><br>学習時間:2h27min⏳<br><br>学習内容:ゼロからサイトを作る✏<br><br>学び📚<br>・リセットCSSの下にスタイルシートを記述する<br>・クラス名は基本「親要素の名前＋用途」にする<br>・floatさせたら親要素の高さが0になってズレる<br>→解決方法あり<a href="https://twitter.com/hashtag/%E3%83%87%E3%82%A4%E3%83%88%E3%83%A9?src=hash&amp;ref_src=twsrc%5Etfw">#デイトラ</a> <a href="https://t.co/CxqZzAfEYa">pic.twitter.com/CxqZzAfEYa</a></p>&mdash; ふりっく💻トリプルゼロの（これから）Webマーケター (@FuRiC_twi) <a href="https://twitter.com/FuRiC_twi/status/1350311265894281219?ref_src=twsrc%5Etfw">January 16, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

#　【学習時間】

2時間27分

#　【学び】

1.Emmentを使ったdescriptionの簡略化

``` index.html
meta:desc　→　<meta name="description" content="">
```
2.command＋方向キーで行を入れ替えることができた

3.リセットCSSの下にスタイルシートを記述する
　リセットCSSの上にスタイルシートが来るとそれもリセットされてしまうから

```style.css
    <link rel="stylesheet" href="css/reset.css">リセットCSS
    <link rel="stylesheet" href="css/style.css">スタイルCSS
```

4.クラス名は基本「親要素の名前＋用途」にする

```index.html
<body>
  <header>
    <div class="container clear">
      <div class="header-left">
        <h1 class="header-title">30DAYSトライアル</h1>
```

5.・floatさせたら親要素の高さが0になってズレる→.clear::after を使う

```style.css
.clear::after { /*clearのクラスをつけた要素の後ろ（after)を変更したい*/
    content: ""; /*afterとbeforeの疑似要素にはcontentが必要*/
    clear: both; /*空白を作る*/
    display: block;
}   /*これらはセットで覚える！*/
```

6.思い通りの見た目にならない時の☑チェックリスト
①　コロン（:）とセミコロン（;）を間違えていないか
②　全角スペースが入っていないか
③　つなげる文字を書き忘れてないか。例えば、アンダーバー（_)　ハイフン(-)　ドット（.）など
④　「閉じタグ」の数が不足してないか
⑤　classを定義するときに「ドット（.）」を書き忘れてないか
⑥　単純なスペルミス
[Rails]テーブルから無作為で1つレコードが欲しい時 .sample使えた。

#課題と結論
テーブルから無作為にレコードが欲しいと思ったら普通に .sample使えました。

```irb:
irb(main):005:0> User.all.sample(1)
=> [#<User id: 5, name: 'aho'>]
```

地味に知らなかった基礎。

#参考情報
ActiveRecord::Relationとは一体なんなのか
https://doruby.jp/users/whale/entries/ActiveRecord--Relation%E3%81%A8%E3%81%AF%E4%B8%80%E4%BD%93%E3%81%AA%E3%82%93%E3%81%AA%E3%81%AE%E3%81%8B
PyTorchでバッチノーマライズをやってみた(＋注意点）

#はじめに
バッチノーマライズがよくわからなかったのでPyTorchでやってみた。
その結果、入力データについて列単位で平均0、分散1に揃えるものだと理解した。
また動かしてみて気が付いた注意点があるのでメモっておく。

#やってみる

まずはインポート

```py
import torch
import torch.nn.functional as F
from torch import nn
```

入力データサイズを決めて、適当に値を生成

```py
input_samples = 100
input_features = 10 
x = torch.rand((input_samples,input_features)) * 10
```

あまりばらけてはいないが、各列平均と分散が異なるデータが生成される。

平均

```
torch.mean(x, 0)
tensor([5.0644, 5.0873, 5.0446, 5.3872, 5.2406, 5.3518, 5.3203, 4.9909, 5.0590,
        5.2169])
```

分散

```
torch.var(x, 0)
tensor([ 9.4876,  8.6519,  8.4050,  9.8280, 10.0146,  8.6054,  7.0800,  8.6111,
         7.7851,  8.5604])
```

バッチノーマライズをかけてみよう

```py
batch_norm=nn.BatchNorm1d(input_features)
y = batch_norm(x)
```

平均

```
torch.mean(y, 0)
tensor([ 1.9073e-08,  5.2452e-08, -4.7684e-09,  3.8743e-08, -3.8147e-08,
         4.1723e-08, -7.8678e-08, -5.9605e-08,  5.7220e-08,  4.2915e-08],
       grad_fn=<MeanBackward1>)
```

⇒　ほぼ0だ。

分散

```
torch.var(y, 0)
tensor([1.0101, 1.0101, 1.0101, 1.0101, 1.0101, 1.0101, 1.0101, 1.0101, 1.0101,
        1.0101], grad_fn=<VarBackward1>)
```

⇒　ほぼ1だ。

#注意点
入力を色々変えて動作させて気づいた注意点を列挙する。

## 入力データが1件の場合は計算エラーとなる
1件の場合は以下のエラーが出力される。

```　
ValueError: Expected more than 1 value per channel when training, got input size torch.Size([1, 10])
```
そもそも1件の場合は、平均はそのデータ自身であり、分散は0になるため、計算する意味はない。


## 列のデータが全て同じ場合は、当然分散は0になる。
平均0にするために、列内の値は全て0になり、その結果当然ながら分散も1ではなく0になる。

##入力データが少ない場合は分散が1にならない
データが3件の場合は```1.5```、10件の場合は```1.111```　などデータサイズが大きくなるにつれ1になる。詳しく掘り下げてはいないが、計算式によるものだと思われるのでドキュメントを見てほしい。

#その他
入力直後にバッチノーマライズをやれば、入力データの正規化に使えるのでは？と思って調べたところ以下のQ&Aが見つかった

https://www.366service.com/jp/qa/9a05f9f614c8ca449ef8693928b7921c

サンプル全体の平均と分散を一度計算する方が簡単で効率的とあるが、確かにその通りである。
確かにその通りだが面倒なんだモン！
【Salesforce】ある桁数まで入力したら自動で検索してほしい

# 動作確認

## 未入力の状態
![何も入力してない.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492812/83cbcde2-1189-1aff-7399-3694010a29fc.jpeg)

## 4桁入れて自動検索した状態

![スクリーンショット 2021-01-17 101243.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492812/b19f1055-ac60-f89f-5f98-4c9383bce746.jpeg)

# 実現方法

```Java:test.cls
public String name { get; set; }

public void getAccount(){
    this.targetAccList = [
        SELECT
            Id
            ,Name
        FROM Account
        WHERE
            Name = :name
    ];
}
```

```JavaScript:test.js
function checkName(input) {
    // apex:actionFunctionタグで設定しているgetAccountメソッドを呼び出す
    if(input.value.length == 4){
        getAccount();
    }
}
```

```HTML:test.page
<apex:form>
    <apex:actionFunction name="getAccount" action="{!getAccount}"/>
    <apex:pageBlock title="取引先検索">
        <apex:outputLabel value="取引先名" for="name"/>
        <!-- onkeyup属性を使用し、入力したらJavaScriptのcheckNameメソッドを呼び出します -->
        <apex:inputText id="name" value="{!name}" html-placeholder="取引先名" html-autofocus="true" onkeyup="checkName(this);"/>
    </apex:pageBlock>
    <apex:pageBlock>
        <table>
            <thead>
                <tr>
                    <th>取引先名</th>
                </tr>
            </thead>
            <apex:repeat value="{!targetAccList}" var="acc">
                <tbody>
                    <tr>
                        <td>
                            <apex:outputField value="{!acc.Name}"/>
                        </td>
                    </tr>
                </tbody>
            </apex:repeat>
        </table>
    </apex:pageBlock>
</apex:form>
```

# 参考リンク

[apex:inputText](https://developer.salesforce.com/docs/atlas.ja-jp.pages.meta/pages/pages_compref_inputText.htm)

[apex:actionFunction](https://developer.salesforce.com/docs/atlas.ja-jp.pages.meta/pages/pages_compref_actionFunction.htm)
VSCodeの環境構築・検証機能を知る


#デイトラWeb制作コース初級編DAY4の学び
 # 【この記事に書いてあること】
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">プログラミング学習4日目⏩<br><br>目標:Web制作コース　初級編　DAY4　💻<br><br>学習時間:2h15min⏳<br><br>学習内容:VSCodeの環境構築・検証機能✏<br><br>学び📚<br>・Live Serverは変更がリアルタイムで反映される<br>・検証で変更したソースコードは保存できる<br>・Emmentを使えばコーディングスピードが上がる<a href="https://twitter.com/hashtag/%E3%83%87%E3%82%A4%E3%83%88%E3%83%A9?src=hash&amp;ref_src=twsrc%5Etfw">#デイトラ</a> <a href="https://t.co/UX0al6tQOh">pic.twitter.com/UX0al6tQOh</a></p>&mdash; ふりっく💻トリプルゼロの（これから）Webマーケター (@FuRiC_twi) <a href="https://twitter.com/FuRiC_twi/status/1349963513868021761?ref_src=twsrc%5Etfw">January 15, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

#　【学習時間】

2時間15分

#　【学び】
1. Live Serverは変更がリアルタイムで反映されるから便利

2. 要素「hover」はその要素の上にカーソルが乗っている場合の見え方を変更する

3. プロパティ「opacity」は透明度を変更する
　1だとそのままで、0に近づくほど完全な透明になっていく

4. コーディングするときは検証画面を開いて確認しながら進める

5. Chromeの検証で変更したソースコードは、そのままファイルにして保存できる
   ＜方法＞
・変更する
・sourceタブを開く
・変更したファイルを右クリックし、「save as」
・保存完了

6. Emmentを使えばコーディングスピードが上がる！
参考サイト: [Emmetの使い方とよく使うパターン集](https://haniwaman.com/emmet/ "Emmetの使い方とよく使うパターン集")
新規事業開発してみた

現在も、アプリを開発しつつユーザー獲得に向けて頑張っている途中ですが、ここまでの経験をまとめてみたいと思い今回の記事を書くとこにしました。

#きっかけ
大学の先輩で仲良くさせていただいてた方から、声をかけていただきました。
その時は、先輩がNoCodeでプロトタイプで実証実験をしている段階で、本格的な開発自体はスタートしておらず、まさにこれからというところでした。

その先輩はすごく素敵な方で、行動力もコミュニケーション能力も高く、数々のビジネスコンテストで優勝している方で、ビジネス視点でも技術視点でもたくさんのことを学ぶことができると感じたので、すぐにエンジニアとしてチームに参加させていただくことにしました。
僕が最後のメンバーとなり、事業開発チーム２人、エンジニアチーム３人でもう一度走り出しました。

#アプリについて
このアプリは、大学という一つのコミュニティにおいて、人との出会いにより生まれるなにかへの挑戦のきっかけをイベント起点で作ろうというアプリである。
解決できる課題としては、ユーザー側にとって趣味や志向、勉強している分野が同じ人などとつながることができるのである。団体代表者にとっては、自団体主催のイベントなどで集客に問題を抱えている場合が多い。
また、そのような状態になっている原因が、学生の個人サイトにて発信されているニュース欄をほとんど確認しなかったり、確認していたとしても、どんどん流れてくるため、特定の情報を見逃してしますケースが多いのである。そのため、ある意味新たな情報受発信プラットフォーム的な立ち位置も請け負う可能性もあります。
　　
具体的には、大学に所属するコミュニティ（サークル・学生団体）や、大学主催のイベントを一覧で確認できたり、コミュニティを探すことができるようになるアプリである。また、他にも同じような趣味や志向、同じ目標があるよう人とも繋がれるのである。団体側にとっては、自団体主催のイベントでの集客に使えたり、自団体メンバーの集客に使えたりというものである。


#技術的な視点に関して
スマホアプリというのは、決定していたので、Swift + Kotolin　もしくは、Flutter　のどちらで開発を進めるのか迷っていましたが、エンジニアチームの方で１人Flutterで個人アプリをリリースしている方がいたことなどもあり、Flutterで開発することが決定しました。

いきなり本格的に開発するのは効率が悪いと思い、事前にYoutubeのFlutter大学さんなどで基礎中の基礎を学んでおきました。実際に開発がスタートしてからは、バトルの中で成長する某少年ジャンプ系の主人公的な感じでした。

チーム開発の中で特に難しいと感じた部分は、それぞれのメンバーが本業（大学・大学院）や本業意外でもいろんな活動をしている人ばかりで、なかなか思っているよりもコミットできないことでした。ただ、ここはチームとして開発するときはするし、しないときはまったくしないというメリハリをつけることで、チームとして気持ちを楽に進めることができるようになりました。

技術的な面では、主に２画面のUI実装と、

#ビジネス視点に関して
こちらに関しては、主に事業開発チームがメインにはなるので、大きく関わっているわけではないのですが、やはり新規事業開発において、難しいと感じたのは以下の3つです。


`・ニーズとの擦り合わせ（PMF）`
`・ユーザー獲得の具体的な施策`
`・マネタイズ`

まぁ、当たり前なんですけど、やってみて実際にすごく痛感しました。

この中で、やはり一番最最初の壁になるのが、`PMF`ですよね。
当たり前ですが、そんな事も実際にやり始めてみないとわからないんですよ。
ここはもうニーズの仮説を立てて、MVPを作って、検証するの繰り返しでやっていくしかないですよね。地に足つけて地道にニーズの検証を重ねましょう。


`ユーザー獲得の具体的な施策`に関しても、チームの中で結構議論しました。ただ、ここは話会うよりも実際にいろんな方法で試してみるしかないと思いました。いくら机上の空論を重ねても答えはでないので、それならやってみようと。

`マネタイズ`に関しては、これまた非常に難しいなと感じました。そもそもチームとして、ガッツリマネタイズを狙うのか、あくまで課題解決がメインなのでマネタイズはオプション程度なのか、様々な経験豊富な方のお話を聞くたびに方針がブレてしまっていて、なかなか定まりませんでした。

#おわり
最後にただ、これまでの経験を振り返った感想を書いている程度ですが、これからどんどん追記していきたいと思います。

ご覧いただきありがとうございました。
Kubuntu20.10をiPXE iSCSIブート、おまけでGPUパススルーバグ暫定回避策


#Kubuntu20.10をiPXE iSCSIブート

標準のインストーラではiSCSI LUNを認識してくれず直接インストールできないようです。
一旦、KVMでiSCSIのLUNを物理ディスクと認識させて普通にインストールしたあと。

```shell:iSCSIのイニシエータの設定
	# apt install open-iscsi
	# vi  /etc/iscsi/initiatorname.iscsi
		InitiatorName=iqn.xxx

	# vi /etc/iscsi/iscsi.initramfs
		ISCSI_AUTO=true

	# vi /etc/iscsi/iscsid.conf
		node.startup = automatic	#有効にする
		# node.startup = manual		#無効にする
```
```shell-session:initramfsのアップデート
	# update-initramfs -u
```
あとは、iPXEで、

```ipxe:boot.ipxeの設定
	set initiator-iqn iqn.xxx
	set root-path     iscsi:xx.xx.xx.xx::::iqn.xxx
	set keep-san      1
	sanboot           ${root-path}
	exit
```

##(ここからが本題)

もともとKubuntu20.04をAMD B450+2000G上で動かしていました。そのときは上記でいけてました。
AMD B550+4000Gに買い換えたところ、、、
　　`KVMゲストがオンボードのNICを認識しなくなりました。`
Kubuntu20.10のKernel5.8だと直っているようだったので、バージョンアップしたところ、、、

initramfsでIPが降ってくる前に、iSCSIのrootボリュームをマウントしに行こうとして、
　　`iscsistart initiator reported error (15 - session exists)`
でBusyBoxに落ちちゃうようになりました。
うちの環境ではDHCPの反応が遅い(?)せいかな。

で、initramfs内のiSCSIスクリプトに適当にパッチをあててみたらうまく行きました。

```bash:iSCSI接続スクリプト
	# cp -rp /usr/share/initramfs-tools/scripts/local-top/iscsi /etc/initramfs-tools/scripts/local-top
	# vi /etc/initramfs-tools/scripts/local-top/iscsi
		:
		if ! [ -e /run/initramfs/open-iscsi.interface ] ; then
			:
		fi

		# ここから：追加(220行目あたり)
		/usr/bin/ip link set  ${DEVICE} up
		busybox sleep 30		# 適当にsleepを入れる
		# ここまで：追加

		modprobe iscsi_tcp
		modprobe crc32c
		:
```
('21/01/24.追記、ここから)
Kernel5.8.0.40.44、にバージョンアップすると起動時エラーがでるように、、、
> mdadm: error opening /dev/md?*: No such file or directory

RAID使っていないので除外すればいいだけのようです。

```bash:RAID設定
	# vi /etc/mdadm/mdadm.conf i
		:
		# 末尾に追加
		ARRAY <ignore>  devices=/dev/sdX
```

('21/01/24.追記、ここまで)

```shell-session:initramfsのアップデート
	# update-initramfs -u
```

これで行けるかも。
あまり情報なかったのでここに書いてみました。

##(20.10でのGPUパススルーバグ暫定回避策の話)
別記事にしようと思ったのですが、30分ほど待てといわれた。
これは調べたらすぐわかることなので、関連しているので一つにまとめてもいいかなと思いここへ。

5.8でKVMパススルーすると仮想マシンが起動しなかったです。
　　`WARNING: CPU: 7 PID: 2524 at fs/eventfd.c:74 eventfd_signal+0x88/0xa0`
バグのようです。https://bugzilla.kernel.org/show_bug.cgi?id=209253

暫定回避策も上記に書かれていますが、オプションを追加するだけ。

```shell-session:仮想マシン起動オプションの追加
	# virt-xml "machine_name" --edit --confirm --qemu-commandline '-global vfio-pci.x-no-vfio-ioeventfd=on'
```
```xml:追加される情報
  <qemu:commandline>
    <qemu:arg value='-global'/>
    <qemu:arg value='vfio-pci.x-no-vfio-ioeventfd=on'/>
  </qemu:commandline>
```

まだたまに落ちますが、、、
CSSの基本的な書き方とルールを覚える

#デイトラWeb制作コース初級編DAY3の学び

# 【この記事に書いてあること】
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">プログラミング学習３日目⏩<br><br>目標:デイトラDAY３💻<br><br>学習時間:３時間１６分⏳<br><br>学習内容：CSSの基本的な書き方とルール✏<br><br>学び📚<br>①CSSファイルは相対パスで指定するのが一般的<br>②セレクタ・プロパティ・バリューという三つの要素<br>③特定の箇所のスタイルを変更する場合はclassを活用<a href="https://twitter.com/hashtag/%E3%83%87%E3%82%A4%E3%83%88%E3%83%A9?src=hash&amp;ref_src=twsrc%5Etfw">#デイトラ</a> <a href="https://t.co/enwhlBvzJj">pic.twitter.com/enwhlBvzJj</a></p>&mdash; ふりっく💻トリプルゼロの（これから）Webマーケター (@FuRiC_twi) <a href="https://twitter.com/FuRiC_twi/status/1347364572576014336?ref_src=twsrc%5Etfw">January 8, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

#　【学習時間】

**3時間16分**

#　【学び】
1.
CSSファイルは相対パスで指定するのが一般的
絶対パスだと作業しているフォルダを動かしたときやサーバーにアップしたときなどにパスがズレてリンクが切れてしまう
なので相対パスを使うようにする

2.
セレクタ・プロパティ・バリューという三つの要素
セレクタ { プロパティ: バリュー; }
どこの→セレクタ
何を→プロパティ
どうするか→バリュー
よくある間違いとして、プロパティの右は：（コロン）、値の右は；（セミコロン）であることに注意する

3.
特定の箇所のスタイルを変更する場合はclassを活用

4.
「 > 」で繋げて書くことで、直属の子孫要素だけを指定することができる

5.
font-sizeの値は
px・%・ em　がある
font-size 16pxを倍の大きさにしたいときは
32px ・200%・ 2em と書く

6.
 **CSSでよく使うプロパティ**

・fontの基本「プロパティ」
```font-size:文字の大きさ```
```font-weight：文字の太さ```
```color：文字の色```
```font-family：文字のフォント```

・テキストの基本「プロパティ」
```line-height：行間
text-align：水平位置
vertical-align：垂直位置
text-decoration：テキストの装飾
letter-spacing：文字間のスペース```

・背景の基本「プロパティ」
```background-image：背景画像
background-size：背景画像のサイズ
background-repeat：背景画像の繰り返し
background-attachment：背景画像の固定・移動
background-color：背景の色```

・positionの基本「バリュー」
```fixed：スクロールしたらひっついて来る
relative＋方向指定：本来表示される位置からどのくらい動かすか
absolute：親要素からどのくらい動かすか```
　　　　　　```absoluteとrelativeはセットで使う```
TensorFlowにおける画像の正規化


#この記事について

kerasの`ImageDataGenerator`で画素値をリスケーリングする際に`rescale`を用いていたのですが、[-1 ~ 1]の範囲で正規化したいときに使用できなかったで調べたことをメモとして残しておきます。

# 引数 - rescale 

一般的に

```.py
from tensorflow.keras.preprocessing.image import ImageDataGenerator, load_img, img_to_array
datagen = ImageDataGenerator(rescale=1./255)
```

のように使うことが多いかと思います。元の画素値とrescaleに与えられた値の積をとります。[0 ~ 255]を[0 ~ 1]に正規化する際に便利です。ImageDataGeneratorでは、他の変換(augmentation)を行う前にこの関数が適用されます。


# 引数 - preprocessing_function

まずは、使い方から確認してみます。


```.py
from tensorflow.keras.preprocessing.image import ImageDataGenerator, load_img, img_to_array
datagen = ImageDataGenerator(
    preprocessing_function=preprocess_input,
    )
```

`preprocess_fucntion` : 各入力に適用される関数。この関数は他の変更が行われる前に実行される。この関数は３次元のNumpyテンソルを引数にとり、同じshapeのテンソルを出力するように定義する必要あり。

`tf.keras.applications`のモデルを使用する際は、モデルによって[0 ~ 1] or [-1 ~ 1]など正規化の値の範囲が決まっています。[-1 ~ 1]の範囲なのに[0 ~ 1]で学習させても学習は上手くいくことが多いです(あまりよろしくはないが、、、、)。

そこで、各モデルに`preprocess_input`という便利な関数があります。
以下は、mobilenetv2の例です。


```.py
from tensorflow.keras.applications.mobilenet_v2 import preprocess_input
datagen = ImageDataGenerator(
    preprocessing_function=preprocess_input,
    )
```

このように記述することで、モデルに適した値に正規化してくれます。
単体でも使用できます。変換前と変換後の値が以下のコードで確認可能です。

```.py
import numpy as np
import tensorflow as tf 
from tensorflow.keras.applications.mobilenet_v2 import preprocess_input
from tensorflow.keras.preprocessing import image
 
model = tf.keras.applications.MobileNetV2()
 
img_path = 'XXXXX.jpg'
img = image.load_img(img_path, target_size=(224, 224))
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)
print(x.max())
print(x.min())
x = preprocess_input(x)
print(x.max())
print(x.min())
```


# tf.keras.layers.experimental.preprocessing.Rescaling()


別の正規化の方法として、`tf.keras.layers.experimental.preprocessing.Rescaling()`があります。
引数として、`scale`と`offset`があります。scaleの値は、入力値にかける。offsetの値は、足すイメージです。

[0, 255]->[-1, 1]のときは、**Rescaling(scale=1./127.5, offset=-1)**でokayです。

```.py


base_model = tf.keras.applications.MobileNetV2(input_shape=IMG_SHAPE,
                                          include_top=False,
                                          weights='imagenet')
        
model = tf.keras.models.Sequential([
        tf.keras.layers.experimental.preprocessing.Rescaling(scale=1./127.5, offset=-1),
        base_model,
        tf.keras.layers.GlobalAveragePooling2D(),
        tf.keras.layers.Dense(2, activation='softmax'),
        ])


```

#終わりに

普段、TFを使用しないので知らないことが多いなと思いました。あとは、作成したモデルに対して画像を入力際はどの値の範囲に正規化すべきかシビアになりましょう。正規化の範囲が違う場合は、予測がかなり変わってしまいます。webのアプリケーションとかにAIモデルを組み込む際は特に注意が必要ですね。

#参考文献

- [TensorFlow](https://www.tensorflow.org/api_docs/python/tf/keras/preprocessing/image/ImageDataGenerator)
【Salesforce】対象ブロックの上下に横に動くスクロールバーを設置したい

# 動作確認

検索結果を表示した際にブロックからはみ出ていたので、上下にスクロールバーを設置したい

![はみ出てる.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492812/b6bb8996-bc0e-57dc-2cb1-e81e6e239e9c.jpeg)

# 実現方法

```CSS:test.page
.wrapper1, .wrapper2 {
    width: 100%;
    overflow-x: scroll;
    overflow-y:hidden;
}

.wrapper1 {height: 20px; }
.wrapper2 {height: 100%; }

.div1 {
    /* ここのwidthを表示したい対象とdiv2のwidthに合わせる */
    width: 1000px;
    height: 20px;
}

.div2 {
    /* ここのwidthを表示したい対象とdiv1のwidthに合わせる */
    width: 1000px;
    height: 100%;
    overflow: auto;
}
```

```Javascript:test.js
// 上下のスクロールバーの位置を合わせる
$(function(){
    $(".wrapper1").scroll(function(){
        $(".wrapper2").scrollLeft($(".wrapper1").scrollLeft());
    });
    $(".wrapper2").scroll(function(){
        $(".wrapper1").scrollLeft($(".wrapper2").scrollLeft());
    });
});
```

```HTML:test.page
<!-- jQueryを使用する -->
<apex:includeScript value="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js" />

<div class="wrapper1">
    <div class="div1"></div>
</div>
<div class="wrapper2">
    <div class="div2">
        <!-- ここにスクロールしたい対象を設定する：今回は検索結果のようなテーブル -->
    </div>
</div>
```

以下のように横スライドのスクロールバーが表示されます。

![動くように作成１.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492812/0b969d76-31fe-2599-ddbb-24858a33acc0.jpeg)

![動くように作成2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492812/86dc3df1-e4e8-30c6-7699-02c5aa89d18f.jpeg)

# 参考リンク

[テーブルの上下にある水平スクロールバー](https://www.it-swarm-ja.tech/ja/javascript/%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%81%AE%E4%B8%8A%E4%B8%8B%E3%81%AB%E3%81%82%E3%82%8B%E6%B0%B4%E5%B9%B3%E3%82%B9%E3%82%AF%E3%83%AD%E3%83%BC%E3%83%AB%E3%83%90%E3%83%BC/970615983/)
SlackにPythonからメッセージを送る

時間がかかるPythonプログラムの最後に、ジョブが終わったよなど、slackに通知する。

[slack-python-webhook](https://github.com/satoshi03/slack-python-webhook)を使用する。

```python:my_tool.py
import slackweb
def message_to_slack(message):
    slack = slackweb.Slack(url="MY_SLACK_URL")
    slack.notify(text=message)
```

My_URLの部分は[incoming webhook](https://jamstec-iprc.slack.com/apps/new/A0F7XDUAZ--incoming-webhook-)から取得する。

使う時は

```python
from my_tool import message_to_slack
message_to_slack("Job Completed!")
```

などとする。
fastAPI sqlalchemyでプレースホルダを使う

sqlalchemy.text を使ってパラメータ名をクエリに埋め込む

```
from sqlalchemy import create_engine, text

DATABASE = f'mysql://{user_name}:{password}@{host}/{database_name}?charset=utf8mb4'

engine = create_engine(
    DATABASE,
    echo=True
)

results = engine.execute('SELECT * FROM posts')

for row in results:
    print((row['id'], row['content']))

```