OmniAICreator/Qiita-1.07M huggingface dataset:
Xcode 11でiOS9のプロジェクトの作成方法

# はじめに

iOS9以降をサポートするアプリを作ることになったので、最新のXcodeで新規プロジェクトを作ってからiOS9向けにダウングレードする方法について説明します。
（普通に作るとiOS13になる。自分への備忘録も兼ねて記載しておく）

# 執筆時点の環境

- macOS Catalina version 10.15.4
- Xcode version 11.4.1


## 1. Xcodeで新規プロジェクトを作成

では、Xcodeの操作を順に説明します。

![#1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/e2c0f873-031f-89e0-218e-29f229b8c30d.png)

File -> New -> Project で、新規プロジェクトを指定します。説明するまでもないですね。
![#2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/7a26094e-bd4b-d272-0b49-101afa846ae7.png)
Single View Appを選びましたが、他でも同じです。

![#3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/4788c70a-acba-0511-89cf-8f23d34a2ee4.png)
プロジェクト名とかは適当に付けます。


## 2. TargetにiOS9を指定する

<img width="1440" alt="#4.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/66ad052d-b399-875e-6a99-317cb0aae6d7.png">
当然ですが、ターゲットにiOS9を指定します。


## 3. InfoからSceneを消す

<img width="1512" alt="#5.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/19b6cee5-1964-1d67-d90c-fd4e96c066ff.png">
SceneはiOS13からサポートされた機能のため、上図の青で囲まれたScene関係の情報を削除します（４つの情報を下から順に(-)をクリック）。


## 4. SceneDelegate.swiftを削除

<img width="1512" alt="#6.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/8b858287-72ad-08f5-967f-6cef86dd3a5c.png">

使えませんので、SceneDelegate.swiftをプロジェクトから削除します。が、13行目のwindowの変数宣言をAppDelegate.swiftに移すので、コピーしておくとよいかも。


## 5. AppDelegate.swiftのコードの変更

<img width="1512" alt="#7.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/3c5491d0-c307-d12a-df35-d600392c42ac.png">
SceneDelegate.swiftを消したので、AppDelegate.swiftにコンパイルエラーがいくつか出てますが、まず、windowの変数宣言をここ(14行目)に入れます。
<img width="1512" alt="#8.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/0a368bd4-e2a3-6a07-323d-0d41b5b3cc1b.png">

<img width="1512" alt="#9.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/c6cde4f1-db31-a018-794c-5188a4c3e10e.png">
コンパイルエラーが出ている2つのメソッドをバッサリ削除します。
<img width="1512" alt="#10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/6c5007b8-5fd0-c546-7c2b-c564c91287da.png">

以上で、iOS9プロジェクトの出来あがりです。WarningもErrorもなくビルドできるはずです。シミュレータを起動すると、真っ白画面のアプリが立ち上がります。
（寂しいので中央にラベルを貼りました）
<img width="529" alt="#11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/0c6046cc-34ce-6013-ea78-f1894ab41fce.png">


# おわりに

自分はこの状態のプロジェクトをiOS9プロジェクトの雛型として保存してあります。必要な時にプロジェクトフォルダ一式をコピーしてiOS9アプリ開発時に利用します。　　以上
Flutter の firebase_admob Plugin の使い方を誤ってしまい、Google に怒られた話し

## 要約：
Flutter に admob をうまいこと扱ってくれる Plugin があるけど、間違った広告の呼び出し方をしてしまい、Google に怒られて収益が止まってしまった。
https://pub.dev/packages/firebase_admob

## 想定する読者の方：
- [x]  Flutter で firebase_admob を利用して広告収入を得ようとしている方

今回は日本で300人ぐらいしか対象者が居ないかもしれませんね。

## やらしたこと：

### 【正しい例】
・広告を表示するためのインスタンスを作成する(以降、作成したインスタンスを myInterstitial とする)

・広告を表示したいタイミングで、下記の処理を実行する

```
myInterstitial
  ..load()
  ..show(
    anchorType: AnchorType.bottom,
    anchorOffset: 0.0,
    horizontalCenterOffset: 0.0,
  );
```
  
###   【今回やらかしたこと】
  ・広告を表示するためのインスタンスを作成する(以降、作成したインスタンスを myInterstitial とする)
　→ここまでは同じ

・「なんか広告が表示されるの遅いな・・・。そうだ、アプリ起動時に一回広告をリクエストしとこう」と考え、アプリ起動時に下記のように load() のみを実行する

```
myInterstitial
  ..load()
```

  ・load() 実行後、実際に広告を表示するタイミングで下記処理を実行する

```
  myInterstitial
  ..load()
  ..show()
  // 以下略
  
```


  ・Google にこんな感じに怒られる
<img width="1009" alt="スクリーンショット 2020-06-16 18.11.51.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251675/95ac7eee-5705-f500-e069-c08056536f9d.png">

<img width="469" alt="スクリーンショット 2020-06-16 18.11.42.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251675/f869fabd-e8db-4c4f-a969-a277436147f8.png">



## 何が悪かったと思われるか：
Google はセキュリティ観点で何が悪かったか教えてくれないので推測だが、
  自分のアプリは実際はほぼ広告を表示しない(多分全体の1%程度)ので、load() の実行回数と show() の実行回数が合っていない=広告のリクエスト回数がものすごく多いのに、実際に表示されている回数が少ない！これはおかしい！と考えたのではないか。

## 対策：
・　..load() と ..show() を必ず一緒に呼ぶようにした


・１週間ほど様子見と言う名の放置をした後、正常に広告が表示されるようになった。

<img width="970" alt="スクリーンショット 2020-06-24 20.38.05.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251675/1efe2bc3-e2e6-5770-c80a-c50abf20f829.png">

<img width="487" alt="スクリーンショット 2020-06-24 20.37.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251675/2efd3e9c-7316-5e7e-5ae9-b19ccdb8caf3.png">

## まとめと最後に言いたいこと：
**..load() と ..show() を必ず一緒に呼ぼう！**
これだけです！
【Rails】CSVインポート機能の実装

# 目標

![ezgif.com-video-to-gif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579893/f912e2cb-07f7-b670-af6b-e35fe22e1ee8.gif)

# 開発環境
・Ruby: 2.5.7
・Rails: 5.2.4
・Vagrant: 2.2.7
・VirtualBox: 6.1
・OS: macOS Catalina

# 前提

下記実装済み。

・[Slim導入](https://qiita.com/matsubishi5/items/b639ffddecc626856039)
・[Bootstrap3導入](https://qiita.com/matsubishi5/items/b117c95f4dd71340cc80)
・[投稿機能実装](https://qiita.com/matsubishi5/items/1a5aeab651b5822d1f2c)

# 実装

## 1.Gemを導入

```ruby:Gemfile
# 追記
gem 'roo'
```

```terminal:ターミナル
$ bundle
```

## 2.`application.rb`を編集

```ruby:application.rb
require_relative 'boot'

require 'rails/all'
require 'csv' # 追記

Bundler.require(*Rails.groups)

module Bookers2Debug
  class Application < Rails::Application
    config.load_defaults 5.2
  end
end
```

## 3.モデル編集

```ruby:book.rb
def self.import(file)
  CSV.foreach(file.path, headers: true) do |row|
    book = find_by(id: row["id"]) || new
    book.attributes = row.to_hash.slice(*updatable_attributes)
    book.save!(validate: false)
  end
end

def self.updatable_attributes
  ['id', 'title', 'body']
end
```

### ① インポートするデータに同じIDが見つかればそのレコードを呼び出し、見つかれなければ新しく作成する。

```ruby
book = find_by(id: row["id"]) || new
```

### ② CSVファイルからデータを取得する。

```ruby
book.attributes = row.to_hash.slice(*updatable_attributes)
```

### ③ バリデーションを通さずに保存する。

```ruby
book.save!(validate: false)
```

### ④ CSVインポート時に受信するカラムを設定する。

```ruby
def self.updatable_attributes
  ['id', 'title', 'body']
end
```

## 4.コントローラーを編集

```ruby:books_controller.rb
def import
  Book.import(params[:file])
  redirect_to books_path
end
```

## 5.ルーティングを追加

```ruby:routes.rb
resources :books do
  collection { post :import }
end
```

## 6.ビューを編集

```slim:books/index.html.slim
= form_tag import_books_path, multipart: true do
  = file_field_tag :file
  br
  = submit_tag "インポート", class: 'btn btn-success'
```
【RDS】EC2とRDS(MySQL)間の接続を確立する

##目標
・EC2サーバとRDS(MySQL)間の接続を確立する。

##前提
・構築済みのEC2が存在すること。

##利用環境
**EC2**
OS（AMI）　:　**Amazon Linux 2 AMI (HVM), SSD Volume Type**
ソフトウェア： **mysql  Ver 14.14 Distrib 5.5.62, for Linux (x86_64) using readline 5.1**

**RDS**
データベースエンジン：　**MySQL(5.7.22)**

##参考AWSドキュメント
**MySQL DB インスタンスを作成して MySQL DB インスタンス上のデータベースに接続する**
https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/CHAP_GettingStarted.CreatingConnecting.MySQL.html

##作業の流れ
| 項番 | タイトル |
|:----:|:-------------|
| 1 | [RDSを作成する](#1rdsを作成する) |
| 2 | [MySQLクライアント接続](#2mysqlクライアント接続)|

##手順
###1.RDSを作成する
**①AWS マネジメントコンソールにサインインし、Amazon RDS コンソール (https://console.aws.amazon.com/rds/) を開く**
**②`データベースの作成`をクリック**
**③データベースの作成方法を選択**
以下のように、各値を投入してください。

`簡単作成`(データベースの詳細設定の多くをデフォルトで設定してくれます)
データベースエンジンは`MySQL`
![tempsnip.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647616/f8e99af7-a507-f84d-336e-c5da69c0cebb.png)

任意の`DBインスタンス識別子`と`マスターユーザ名`(MySQL接続時の認証等で利用されます)を入力
![tempsnip.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647616/054b0b67-6723-5bb0-f98b-8b1c0bdc9708.png)

`マスターパスワード`を入力（パスワード自動生成することも可能、MySQL接続時の認証で利用されます）
![tempsnip.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647616/9445a1f9-dc01-ffa7-c25f-82d76d741aec.png)

**④作成したRDSが`利用可能`になるまで待機**
![tempsnip.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647616/2ff46aff-fd5c-36d8-1aff-69b321670f76.png)

**⑤作成したRDSの`3306番ポート`を開く**
作成したRDSの詳細画面から`VPCセキュリティグループをクリック`（利用ポートが3306番であることも確認）
![tempsnip.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647616/a12b9ddb-ed6a-b018-0d69-236c6207dbc1.png)

`3306番ポート`を許可
![tempsnip.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647616/56ace861-dc09-c806-4d55-3ebbe217020d.png)


###2.MySQLクライアント接続
**①EC2にOSログイン**
**②MySQLクライアントインストール**
`sudo yum install mysql`実行

```bash

# Complete!と出力されること
[ec2-user@ip-172-31-32-13 ~]$ sudo yum install mysql
(中略)
Installed:
  mysql.noarch 0:5.5-1.6.amzn1

Dependency Installed:
  mysql-config.x86_64 0:5.5.62-1.23.amzn1 mysql55.x86_64 0:5.5.62-1.23.amzn1
  mysql55-libs.x86_64 0:5.5.62-1.23.amzn1

Complete!
```

**③MySQLログイン**
`mysql -h <RDSエンドポイント名> -P 3306 -u <マスターユーザ名> -p`実行

```bash

# マスターユーザのパスワードを入力し、正常にログイン出来ればOK
[ec2-user@ip-172-31-32-13 ~]$ mysql -h database-test.cgfjapta11py.ap-northeast-1.rds.amazonaws.com -P 3306 -u admin -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 15
Server version: 5.7.22-log Source distribution

Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>
```
wordpress学習(2020/06/24)

###wordpress ウィジェットの追加
ウィジェットとはパソコンのデスクトップやWebページなどで動作する小さなアプリケーションのこと。
外観のウィジェットで、追加したいサイドバーにウィジェットをドラッグして追加する。
初期に用意されているウィジェットではテキスト、検索、カテゴリがよく使われる。
プラグインを追加することで色々なウィジェットを追加することができる。


###wordpress メニュー
外観のメニューからメニューバーを作る。
メニューバーに固定ページなどのメニューアイテムを割り当て、最後に作成したメニューの位置を決める。
追加できる項目は固定ページ、投稿ページ、カスタムリンク、カテゴリー。
投稿は投稿の各ページをメニューバーに追加することができる。
カスタムリンクは任意のURLをメニューバーに追加することができる。
カテゴリーは投稿のカテゴリー一覧ページをメニューバーに追加することができる。
メニューに親子関係・階層をもたせたい場合には該当メニュー項目を一段ずらすと副項目になる。
GCPでJupiterLab（Python3.6）

~~[Google Colab](https://colab.research.google.com/)を活用して誰でも簡単に量子計算自動化できるようになる記事です。
Google Colabの使い方は[このサイト](https://future-chem.com/rdkit-google-colab/)がおすすめです。
psi4についての説明は[このサイト](https://future-chem.com/psi4-intro/)がおすすめです。~~


#GCPインスタンスの作成
Linux（Debian）で作成
外部IPを有効にする

#Jupyter-labの導入
SSHにて以下のコマンドを実行する。

```rb:jupyter-lab
# ミニコンダの実装
wget -c https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh
chmod +x Miniconda3-latest-Linux-x86_64.sh
bash ./Miniconda3-latest-Linux-x86_64.sh -b -f -p /usr/local

# Python3.6環境構築
conda create -n NAME python=3.6
conda activate NAME


# jupyterlabのインストール
conda install jupyter-lab
iptables -w -A INPUT -p tcp --dport 80 -j ACCEPT

sudo jupyter lab --port 80 --allow-root --ip=0.0.0.0 --notebook-dir='/'
```
#Jupyter-lab画面へ移動
外部IPをクリック



#終わりに
~~今回は「誰でも簡単に量子計算自動化（google colabでpsi4）」という記事を書きました．初心者にとってpythonの環境構築は挫折ポイントの1つですので，Google Colabを使うことで気軽に分析が始められる点は大きな利点だと思います．
[私のブログ](https://effichem.blogspot.com/)ではもっと詳細な情報や、化学系のグラフ作成方法など幅広く紹介しているので是非参考にしてみてください。
次回はGoogle ColobにRDKitとpsi4の両方を導入する方法について解説する予定です。~~

##参考
~~https://future-chem.com/rdkit-google-colab/ Google ColabでRDKit：ケモインフォマティクス用のpython環境を手軽に構築~~
https://effichem.blogspot.com/ 私のブログ
unityでも使える、３Ｄモデルが無料配布してるぞいって話


あのインディーゲーム　Everythingで有名な　デベロッパーさんが　

そのゲームで使われている　

３Ｄモデルを公開しているぞい。　

こちらのサイトから　ダウンロードできます。　

無料ですけど、寄付もできるようになってますね。

https://davidoreilly.itch.io/everything-library-animals






今回は　動物のモデルを公開しているが　

今後も新しいモデルを配布するみたいですね。

これだけのモデルを無料配布するなんて

太っ腹です。



unityに入れてみると　こんな感じ　

デフォルトだと目が怖いので、　そこは手直しが必要ですかね。　

こんだけ動物がいたら　動物の森　作れますね。

　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　







ＰＳ　

unity３Ｄゲームstandard講座も　好評発売中です。

NOTEとココナラとboothにて　販売してます。





![bandicam 2020-06-24 19-55-43-528.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295760/7c7c9883-9fed-a4fc-a6f1-00463aac1d78.jpeg)
uriライブラリ　簡易まとめ

### URI.scheme
スキームを文字列で返す。

### URI.host
ホストを文字列で返す。

### URI.port
ポート番号を文字列で返す。

### URI.query
クエリを文字列で返す。

### URI.path
パスを文字列で返す。
### URI.request_uri
path + '?' + queryを文字列で返す。 query が nil である場合は、自身の path を返す。

#### 実践

Qiitaでrubyを検索した結果画面のurlをURIオブジェクトにパースしてみましょう。

```ruby
require 'uri'

uri = URI.parse('https://qiita.com/search?q=ruby')
puts uri.schem
#=> https
puts uri.host
#=> qiita.com
puts uri.port
#=> 443
puts uri.path
#=> /search
puts uri.query
#=> q=ruby
puts uri.request_uri
#=> /search?q=ruby

```
### join
引数に渡した文字列(変数)を連結してURIオブジェクトを生成する。

### encode_www_form
引数で渡した値からURL-encoded form dataを生成する。
私値は配列やハッシュも可能。
GETでuriにパラメータを渡す時などに利用。

```ruby

uri = URI.join('https://qiita.com','/search')
puts uri
# => https://qiita.com/search
params = {
name: 'hogehoge',
email: 'hogehoge@hogehoge.com'
}
uri.query = URI.encode_www_form(params)
puts uri
# => https://qiita.com/search?name=hogehoge&email=hogehoge%40hogehoge.com
```
[baserCMS]固定ページのプレビュー時、編集領域での変更内容（保存ボタン押下前）が反映されないケースがある対策


## 結論

htaccessに以下を書いてみること。
※「+」のところが追加行箇所

```
RewriteEngine on
RewriteBase /

# プレビューのときはbaserCMSを優先し実フォルダ、ファイルをムシする
+ RewriteCond %{QUERY_STRING} (^|&)preview=([^&]+)($|&)
+ RewriteRule ^(.*)$ index.php [QSA,L]

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [QSA,L]
```


前提事項としては少し特殊なケースで、webrootをドキュメントルート直下配置しているケース。

- http://wiki.basercms.net/%E3%83%89%E3%82%AD%E3%83%A5%E3%83%A1%E3%83%B3%E3%83%88%E3%83%AB%E3%83%BC%E3%83%88%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6 の「ドキュメントルートに通常どおり静的ファイルを配置する」の状態
- コンテンツの構成がCMS側と静的ファイルが混在しているケース
    - CMS側の配置: コンテンツ内の直下に、フォルダ「directory」を持ち、中にindex固定ページを持つ
    - 実体となるフォルダ構成は以下の図となっている状態

```
.
├── index.php
├── lib
│   ├── Baser
│   └── Cake
├── directory（実体として設置。フォルダ内にindex.htmlがある。index.phpは存在しない）
└── theme
```

上記配置状態の際に、CMS管理側の /directory/index の編集画面から「プレビュー」を実行しても、編集領域の内容が反映されない、といったとき。

調べてみてわかった事柄としては以下の点。

- プレビューは、URLに「?preview=default」のパラメータをトリガーとして動作発生するもの
- 実ディレクトリが存在する場合、そちらへのアクセス処理が優先される、のは通常動作だが、挙げている配置構成の場合、プレビュー動作のために必要なパラメータが、プログラムの動作内ではなくなった状態となっているため動作しない。


### 環境
- PHP 5.6
- baserCMS 4.2.1


### 参考記事というか先生

- https://qiita.com/kaburk
Ubuntu 20.04にNginx mainline最新版をインストール（公式repository）

# はじめに

公式repositoryを利用してUbuntu 20.04にNginx mainline最新版をインストール
親記事：[Nginxの各種インストール方法とEOLまとめ](https://qiita.com/witchcraze/items/df4a0baaaad9c932ea30)
参考：[nginx: Linux packages](https://nginx.org/en/linux_packages.html#Ubuntu)

## サポート

本手法で導入した場合、nginxの開発が停止するまでサポートされると思われる。
特定のバージョンを指定しなければ、mainline最新版が常に提供されると思われる。

## LOG

### レポジトリ登録

```shell-session
# apt update; apt install -y curl gnupg2 ca-certificates lsb-release
# echo "deb http://nginx.org/packages/mainline/ubuntu `lsb_release -cs` nginx" | tee /etc/apt/sources.list.d/nginx.list
# curl -fsSL https://nginx.org/keys/nginx_signing.key | apt-key add -

# apt-key fingerprint ABF5BD827BD9BF62
pub   rsa2048 2011-08-19 [SC] [expires: 2024-06-14]
      573B FD6B 3D8F BC64 1079  A6AB ABF5 BD82 7BD9 BF62
uid           [ unknown] nginx signing key <signing-key@nginx.com>
```

### インストール

```shell-session
# cat /etc/os-release
NAME="Ubuntu"
VERSION="20.04 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04 LTS"
VERSION_ID="20.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal

# apt update; apt install -y nginx
... 略
```

### 各種確認

```shell-session
# which nginx
/usr/sbin/nginx

# nginx -v
nginx version: nginx/1.19.0

# apt show nginx
Package: nginx
Version: 1.19.0-1~focal
Priority: optional
Section: httpd
Maintainer: Sergey Budnevitch <sb@nginx.com>
Installed-Size: 3075 kB
Provides: httpd
Depends: libc6 (>= 2.28), libcrypt1 (>= 1:4.1.0), libpcre3, libssl1.1 (>= 1.1.1), zlib1g (>= 1:1.1.4), lsb-base (>= 3.0-6), adduser
Conflicts: nginx-common, nginx-core
Replaces: nginx-common, nginx-core
Homepage: http://nginx.org
Download-Size: 859 kB
APT-Manual-Installed: yes
APT-Sources: http://nginx.org/packages/mainline/ubuntu focal/nginx amd64 Packages
Description: high performance web server
 nginx [engine x] is an HTTP and reverse proxy server, as well as
 a mail proxy server.

N: There are 2 additional records. Please use the '-a' switch to see them.
```
Ubuntu 20.04にNginx stable最新版をインストール（公式repository）

# はじめに

公式repositoryを利用してUbuntu 20.04にNginx stable最新版をインストール
親記事：[Nginxの各種インストール方法とEOLまとめ](https://qiita.com/witchcraze/items/df4a0baaaad9c932ea30)
参考：[nginx: Linux packages](https://nginx.org/en/linux_packages.html#Ubuntu)

## サポート

本手法で導入した場合、nginxの開発が停止するまでサポートされると思われる。
特定のバージョンを指定しなければ、stable最新版が常に提供されると思われる。

## LOG

### レポジトリ登録

```shell-session
# apt update; apt install -y curl gnupg2 ca-certificates lsb-release
# echo "deb http://nginx.org/packages/ubuntu `lsb_release -cs` nginx" | tee /etc/apt/sources.list.d/nginx.list
# curl -fsSL https://nginx.org/keys/nginx_signing.key | apt-key add -

# apt-key fingerprint ABF5BD827BD9BF62
pub   rsa2048 2011-08-19 [SC] [expires: 2024-06-14]
      573B FD6B 3D8F BC64 1079  A6AB ABF5 BD82 7BD9 BF62
uid           [ unknown] nginx signing key <signing-key@nginx.com>
```

### インストール

```shell-session
# cat /etc/os-release
NAME="Ubuntu"
VERSION="20.04 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04 LTS"
VERSION_ID="20.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal

# apt update; apt install -y nginx
... 略
```

### 各種確認

```shell-session
# which nginx
/usr/sbin/nginx

# nginx -v
nginx version: nginx/1.18.0

# apt show nginx
Package: nginx
Version: 1.18.0-1~focal
Priority: optional
Section: httpd
Maintainer: Sergey Budnevitch <sb@nginx.com>
Installed-Size: 3058 kB
Provides: httpd
Depends: libc6 (>= 2.28), libcrypt1 (>= 1:4.1.0), libpcre3, libssl1.1 (>= 1.1.1), zlib1g (>= 1:1.1.4), lsb-base (>= 3.0-6), adduser
Conflicts: nginx-common, nginx-core
Replaces: nginx-common, nginx-core
Homepage: http://nginx.org
Download-Size: 857 kB
APT-Manual-Installed: yes
APT-Sources: http://nginx.org/packages/ubuntu focal/nginx amd64 Packages
Description: high performance web server
 nginx [engine x] is an HTTP and reverse proxy server, as well as
 a mail proxy server.

N: There is 1 additional record. Please use the '-a' switch to see it
```
ERROR! The server quit without updating PID file (/usr/local/var/mysql/***.local.pid).の解決方法

rails sでサーバーを起動。いざブラウザでアクセスすると以下のようなエラー。

```
ERROR! The server quit without updating PID file (/usr/local/var/mysql/***.local.pid).
```

####解決方法

mysqlに関するファイルを全て削除。mysqlもアンインストールしたら動いた。
＊データが消える恐れがあります。

```
$ sudo rm -fr /usr/local/var/mysql/
$ sudo rm -fr /usr/local/Cellar/mysql/
$ sudo rm -fr ./usr/local/Cellar/mysql/

まずはMysqlに関するファイルが保存されているディレクトリを削除。
```

既にインストール済みの場合はMysqlをアンインストールします。

```
$ brew uninstall mysql
```

次にインストール。

```
$ brew install mysql
```

起動の確認をする。

```
$ mysql.server start

Starting MySQL
 SUCCESS! 
```
参考記事
https://qiita.com/akiko-pusu/items/aef52b723da2cb5dc596
https://shikouno.hatenablog.com/entry/2017/06/22/210000
http://tech-outlines.hateblo.jp/entry/2015/03/24/180940
https://qiita.com/mogetarou/items/e34ca51d3756d55d7800
CentOS 7にRuby 2.7をインストール（SCL）

# はじめに

Software Collection(SCL)を利用してCentOS7にRuby 2.7をインストール
参考：[Quick Start — Software Collections](https://www.softwarecollections.org/en/docs/)

## サポート

本手法で導入した場合、[Red Hat Software Collections Product Life Cycle - Red Hat Customer Portal](https://access.redhat.com/support/policy/updates/rhscl)より、2023-05がEOLだと思われる。
それ以降に報告された脆弱性や不具合への対応は実施されない可能性がある。

## LOG

### レポジトリ登録

```shell-session
# yum install -y centos-release-scl
```

### インストール

```shell-session
# cat /etc/redhat-release
CentOS Linux release 7.8.2003 (Core)

# yum install -y rh-ruby27 which
# scl enable rh-ruby27 bash
... 略
```

### 各種確認

```shell-session
# which ruby
/opt/rh/rh-ruby27/root/usr/bin/ruby

# ruby -v
ruby 2.7.1p83 (2020-03-31 revision a0c7c23c9c) [x86_64-linux]

# yum info rh-ruby27
Loaded plugins: fastestmirror, ovl
Loading mirror speeds from cached hostfile
 * base: ty1.mirror.newmediaexpress.com
 * centos-sclo-rh: ty1.mirror.newmediaexpress.com
 * centos-sclo-sclo: ty1.mirror.newmediaexpress.com
 * extras: ty1.mirror.newmediaexpress.com
 * updates: ty1.mirror.newmediaexpress.com
Installed Packages
Name        : rh-ruby27
Arch        : x86_64
Version     : 2.7
Release     : 2.el7
Size        : 0.0
Repo        : installed
From repo   : centos-sclo-rh
Summary     : Package that installs rh-ruby27
License     : GPLv2+
Description : This is the main package for rh-ruby27 Software Collection.
```
CentOS 7にPython 3.8をインストール（SCL）

# はじめに

Software Collection(SCL)を利用してCentOS7にPython 3.8をインストール
参考：[Quick Start — Software Collections](https://www.softwarecollections.org/en/docs/)

## サポート

本手法で導入した場合、[Red Hat Software Collections Product Life Cycle - Red Hat Customer Portal](https://access.redhat.com/support/policy/updates/rhscl)より、~~2023-05~~ 2024-06がEOLだと思われる。
それ以降に報告された脆弱性や不具合への対応は実施されない可能性がある。

## LOG

### レポジトリ登録

```shell-session
# yum install -y centos-release-scl
```

### インストール

```shell-session
# cat /etc/redhat-release
CentOS Linux release 7.8.2003 (Core)

# yum install -y rh-python38 which
# scl enable rh-python38 bash
... 略
```

### 各種確認

```shell-session
# which python{,2,3}
/opt/rh/rh-python38/root/usr/bin/python
/usr/bin/python2
/opt/rh/rh-python38/root/usr/bin/python3

# ll /opt/rh/rh-python38/root/usr/bin/python*
lrwxrwxrwx. 1 root root     9 Jun 24 10:31 /opt/rh/rh-python38/root/usr/bin/python -> ./python3
lrwxrwxrwx. 1 root root     9 Jun 24 10:31 /opt/rh/rh-python38/root/usr/bin/python3 -> python3.8
-rwxr-xr-x. 1 root root 15280 May 28 09:39 /opt/rh/rh-python38/root/usr/bin/python3.8

# python -V
Python 3.8.0

# python3 -V
Python 3.8.0

# yum info rh-python38
Loaded plugins: fastestmirror, ovl
Loading mirror speeds from cached hostfile
 * base: ftp.riken.jp
 * centos-sclo-rh: ftp.riken.jp
 * centos-sclo-sclo: ftp.riken.jp
 * extras: ftp.riken.jp
 * updates: ftp.riken.jp
Installed Packages
Name        : rh-python38
Arch        : x86_64
Version     : 2.0
Release     : 4.el7
Size        : 0.0
Repo        : installed
From repo   : centos-sclo-rh
Summary     : Package that installs rh-python38
License     : GPLv2+
Description : This is the main package for rh-python38 Software Collection.
```
Macでスクリーンショットの余白を無くしたい！

# スクリーンショットってよく使いますよね笑
どうも、Macユーザーの皆さんこんにちは。MacでもiPhone同様`command + shift + 5`でスクリーンショットをよく使うんですが、まわりにできる余白と影がどうしても鬱陶しかったので今回はその余白をなくす方法を記述していきたいと思います。

## before / after
### before
<img width="1136" alt="スクリーンショット 2020-06-24 19.08.16.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563637/4c626acd-2123-6e91-b950-bdf01cb80eb8.png">

### after
<img width="1024" alt="スクリーンショット 2020-06-24 19.42.39.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563637/48e33012-3b71-513e-d5b4-bcf557b482f7.png">

一応デフォルトで周りの余白の背景くり抜きになっているので一見余白がないように見えますが、Twitterなどに投稿すると下記のようになってしまうんですよねぇ...

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">スクショの余白をなくす。 <a href="https://t.co/Mk2jOFQXoQ">pic.twitter.com/Mk2jOFQXoQ</a></p>&mdash; gabe (@gb_oo7) <a href="https://twitter.com/gb_oo7/status/1275735261402378240?ref_src=twsrc%5Etfw">June 24, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## やり方

```Terminal
defaults write com.apple.screencapture disable-shadow -bool true
```

```Terminal
killall SystemUIServer
```

この2行だけなんですよね（笑）コードを2行に分けているのでTerminalで実行するときは1行ずつ実行してくださいね！
非常に簡単にスクリーンショットの余白をなくすことができました！

**1回でやりたい！**って方は...

```Terminal
defaults write com.apple.screencapture disable-shadow -bool true; killall SystemUIServer
```

これで1行にまとめて実行できます。

## 戻し方

```Terminal
defaults write com.apple.screencapture disable-shadow -bool false; killall SystemUIServer
```

1行にまとめていますが、これで元に戻すことができます。

最後までご覧いただきありがとうございました〜:bow_tone2:
macOSでポートフォワーディングしようとしたらハマった話

## 結論

macOSではポートフォワーディングがデフォルトで許可されていないので、もししたいなら/etc/ssh/sshd_configの一部を修正する必要がある（下記のコメントアウトを解除して有効化する）。

```
#85行目
#AllowTcpForwarding yes
```

"#"を消してこの記述を有効にしましょう。

## 詳細

macOSでポートフォワーディングのためにsshコマンドで接続したのち、localhostの当該ポートにアクセスすると以下のようなエラーが発生する事がある。

```
channel 3: open failed: connect failed: No route to host
channel 3: open failed: connect failed: No route to host
```

ssh接続自体はできているのに…なぜだ…と調べていたら下記記事を発見。

https://qiita.com/isotai/items/f8ece84816f34eb515e5

> リモートサーバーで/etc/ssh/sshd_configにAllowTcpForwardingが許可されているか確認する。コメントアウトされていたらコメント外してyesにします。

これはリモートサーバーについての言及ですが、今回の話は、ローカルサーバーからリモートサーバーへのポートフォワーディングの話なので、ローカルサーバーがAllowTcpForwarding yesである必要があります。ということで/etc/ssh/sshd_configを確認、すると冒頭のようにコメントアウトされていた事が判明。

```
sudo vi sshd_config
```

でコメントアウトを消して保存、無事ポートフォワーディング出来ましたとさ。
Install Kepler.gl on Windows

English description comes below Japanese article.
This is translation of [Step-by-Step Install Kepler.gl di Windows](https://medium.com/@expan/step-by-step-instalasi-kepler-gl-pada-windows-12b021fd0c72) - Medium

# Kepler.glを入れよう
Kepler.glはUberのオサレな地図系BIサービスですが、ホストがUberが無料でやってくれるのは良いものの、ローカル環境に欲しい場合もあります。

gitから簡単にインストールできるので、気軽に高性能なヴィジュアリゼーションを使えるのですが、Windows向けのnpmパッケージは今一歩設定が難解のようで、まったく歯が立ちません。

# Windowsで使う

ネットだよりにいろいろ探しましたが、Medium上の[EXPANさん](https://medium.com/@expan)が懇切丁寧なステップバイステップの解説を挙げてくださっています。

[Step-by-Step Install Kepler.gl di Windows](https://medium.com/@expan/step-by-step-instalasi-kepler-gl-pada-windows-12b021fd0c72) - Medium

でもこれインドネシア語。。。語学力以前の問題で無理ですね。
母国語のオーディエンスには良いですが、インターネットでみつかる貴重な題材だけに、ローカル言語で書くのはもったいない。

ので、以下英語の記事にサマリーを翻訳しておいておきます。

# Prerequisites

- node. js (Download: [node.js](https://nodejs.org/en/download/))
- git (Download: [git](https://git-scm.com/))
- Text editor : to edit some configuration files
- Mapbox access key (inquire from [Mapbox](https://www.mapbox.com/))

To make access key as default, edit nodevars.bat (ex. C:\Program files\nodejs\...) batch file :

```
set "MapboxAccessToken=[your mapbox access token goes here]"
```

check your installation :

```
node -v
git --version
set
```

# Download

To clone latest kepler.gl image type :

```
git clone https://github.com/uber-common/vis-academy.git
```

Move to "starting-code" folder then install

```
cd vis-academy/src/demos/building-a-geospatial-app/starting-code
npm install
```

Try run current image but it will result to 

```
npm run start
```

Open localhost with :

http://localhost:8080/

but it will result to empty page.

# Adapt some scripts to Windows

In this folder, modify 2 files as example.

```
vis-academy\src\demos\kepler.gl\0-starting-code
```

## app.js

Download alternative file hear : github.com/supriyd/Embedding-Keppler.gl/[app.js](https://gist.githubusercontent.com/supriyd/c428d0505742e33c068a126453c302ec/raw/20f1a090444ba6db00b6fe98014c700655f6c880/app.js)

## reducers.js

Download alternative file hear : github.com/supriyd/Embedding-Keppler.gl/[reducers.js](https://gist.githubusercontent.com/supriyd/9f2dc721d00551bf3bc0f75a47c7d440/raw/03ab86505211328023e0ed297e68105a9de8244b/reducers.js)


## finally ...

Run alternative scripts with :

```
cd vis-academy/src/demos/kepler.gl/0-starting-code
npm install
npm run start
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146939/13fc4a65-02a2-0365-06b6-f7a26e56d3ca.png)
Ubuntu を長時間待機させるとSSDにアクセスできなくなる

解決方法がほぼ参照先のコピペみたいになったが，3日程悩んだので投稿する．

## 問題

あるSSD(今回は Transcend製SSD 256GB)では，一定時間操作がないとSSDにアクセスできなくなり，システムが停止する．

### 問題の起きた環境(抜粋)

+ Computer model : PRODESK 600 G5
+ OS : Ubuntu server 20.04 LTS
+ SSD model(入れ替えた) : TS256GMTE220S

### 具体的な症状

+ 日中はほとんど問題がない
+ システムを起動したまま翌日まで放っておくと SSH でログインができない
+ サーバにディスプレイを接続すると以下のエラーが大量に表示される
    +  ```systemd-journald[484]: Failed to write entry (xx items, xxx bytes), ignoring: Read-only file system```
    +  ```EXT4-fs error (device nvme0n1p2): ext4_find_entry:1463: inode #xxxxx: comm systemd-udevd: reading directory iblock 0```
+ サーバに直接キーボードを接続して Ctrl + Alt + Del キーを押してもシャットダウンできない

## 原因

+ APST（Autonomous Power State Transition）が特定の SSD に対してうまく動かないことがある

### 2021.4.5 追記

+ SSDを一度フォーマットし，OSを再インストールしたらこの問題が発生しなくなった．OSのインストール時に何らかのエラーが発生していた可能性がある
+ ここで使用したSSDは，OS稼働開始3ヶ月で読み書きのアクセスができなくなる不具合が発生した．もしかしたら何らかの初期不良を抱えていた可能性がある

## 対応方法

- nvme のインストール

  ```
  $ sudo apt install nvme-cli
  ```

- /etc/default/grub ファイルを編集

  ```
  $ sudo nano /etc/default/grub
  ```

- "GRUB_CMDLINE_LINUX_DEFAULT" で始まる行の "" 内に "nvme_core.default_ps_max_latency_us=0" を追記し，上書き保存

  例:

  ```
  GRUB_CMDLINE_LINUX_DEFAULT="nvme_core.default_ps_max_latency_us=0"
  ```

- GRUB2設定ファイルを更新

  ```
  $ sudo update-grub
  ```

## 所感

やはりサーバ機は正規のサーバ用マシンを使ったほうが安定するのだろうか．無闇にハードウェア構成をいじるとうまく行かないことがあるという勉強になった．

# 参考文献

+ [Ubuntu 17.04 その66 - 一部のSSDでボリュームが読み込み専用になってしまう現象](https://kledgeb.blogspot.com/2017/05/ubuntu-1704-66-ssd.html)
+ [18.04 and 18.10 fail to boot nvme0: failed to set APST feature (-19)](https://askubuntu.com/questions/1099048/18-04-and-18-10-fail-to-boot-nvme0-failed-to-set-apst-feature-19)
【※絶対に自動化してはいけない】自動化禁止サイトまとめ！

お久しぶりです！

最近仕事で社内向けにRPA研修を行い、
そこで自動化禁止サイトを少しだけ調べたので共有したいと思います。

自動化禁止サイトのまとめ記事がないのが意外でした...！

※注意：2020年6月24日時点の情報です！
※注意：本記事に掲載していないサイトでも利用規約で自動化を禁止しているサイトはたくさんあります。自動化する前に一度ご確認ください。

# 自動化禁止サイト

## Amazon

ロボットなどのデータ収集・抽出ツールによる利用は許可されていません。
利用規約に明記されています。

RPAだけでなくプログラミング言語によるスクレイピングもNGだと思われます。

[Amazon - 利用規約 -](https://www.amazon.co.jp/gp/help/customer/display.html/ref=jp_surl_conditions?nodeId=201909000)

> この利用許可には、アマゾンサービスまたはそのコンテンツの転売および商業目的での利用、製品リスト、解説、価格などの収集と利用、アマゾンサービスまたはそのコンテンツの二次的利用、第三者のために行うアカウント情報のダウンロードとコピーやその他の利用、データマイニング、ロボットなどのデータ収集・抽出ツールの使用は、一切含まれません。


## SNSはだいたいNG（例：Twitter, Facebook, Instagram）

[Twitterの利用規約](https://twitter.com/ja/tos)には以下のように記されています。

> Twitterによる事前の同意がないまま本サービスのスクレイピングをすることは明示的に禁止されています

Facebook, Instagramも同様に自動化はNGです。


## ファイナンス系はだいたいNG（例：Yahoo!ファイナンス）

[Yahoo!ファイナンス](https://support.yahoo-net.jp/PccFinance/s/article/H000011276)はヘルプで明記されていました。

> Yahoo!ファイナンスでは、Yahoo!ファイナンスに掲載している株価やその他のデータを、プログラム等を用いて機械的に取得する行為（スクレイピング等）について、システムに過度の負荷がかかり、安定したサービス提供に支障をきたす恐れがあることから禁止しています


理由までちゃんと書いてくれてありがたいですね。

だいたい自動化を禁止する理由は、「システムへの負荷」が多いように思います。

ファイナンス系のサイトで自動化できたら、みんな株の情報とか自動で取得しまくりますよね。それでサーバーがダウンしてサービス提供ができなくなると困るので、自動化は禁止していますよと。


## Wantedly

Wantedlyも利用規約を見たら分かりますけれども、自動化を禁止しています。
個人的に自動化しようと思うことがありましたが、規約的に無理でした（笑）

> ボット等の自動化プログラムを用いることによって、本サービスを不正に操作したり、他のお客様の自主的かつ合理的な選択を妨げたりする行為
1.9. 違反等に対する措置


## NewsPicks

ニュース系もスクレイピング需要が高いのでしょうか？
[NewsPicks](https://newspicks.com/policy/user-agreement-ja/)でも利用規約の禁止事項に明記されていました


> 自動化された手段(情報収集ボット、ロボット、スパイダー、スクレーパーなど)を使用して、本サービスにアカウント登録したり、アクセスしたりする行為。


# どうやって自動化禁止サイトをスマートに確認できるか？

基本的には利用規約を見ましょう。

私はだいたい「Ctrl + F」でページ内検索をかけて、「自動」「ボット」「スクレイピング」などで検索してヒットした部分しか読んでいません。

そして必ずしも検索でヒットしたからと言って、「このサイト自動化禁止してるやん！！」と思ったら時期尚早です。

ちゃんと文章読んでみてください。

難しそうに見えますが、利用規約はだれでも共通認識を持てる言葉で書かれているはずなので、きっと理解できます！

ちなみに利用規約はだいたいサイトのフッター部分にリンクがあることが多いです。


# おわりに

この記事にのっているのは一部で、他にも自動化を禁止しているサイトはたくさんあります。

良い子のみなさんは、利用規約で禁止されていることはやってはいけません:)
TypeScriptの型定義でmapっぽいことをする方法

# 概要
Objの中身をそれぞれ分解したObj2を作るにはどうすれば良いでしょうか。

```ts
type Obj = {
  foo: string;
  bar: number;
  baz: boolean;
};

type Obj2 = { foo: string } | { bar: number } | { baz: boolean };
```

これが型の外の世界であれば、多くの方は`map`を使うかと思います。　

```ts
const obj = {
   foo: 'string',
   bar: 100,
   baz: false
};

const obj2 = Object.keys(obj).map(key => ({ [key]: obj[key] }));
// obj2 = [{ foo: 'string' }, { bar: 100 }, { baz: false }];
```

この記事では、この`map`っぽいことを型の世界で行う方法について説明して行きます。

# やり方
## TypeScriptにおける`in`
TypeScriptにおける`in`は`true`か`false`を返すin演算子として説明されることが多いですが、もう1つの意味があります。
それはMapped typesです。

ref) [Mapped types](https://www.typescriptlang.org/docs/handbook/advanced-types.html#mapped-types)

これはまさに配列に対して`map`をかけるような処理となります。

```ts
const animals = ['dog', 'cat'];
const animalObject = animals.map(v => () => v);
// animalObject = {
//    dog: () => 'dog',
//    cat: () => 'cat',
// }

type Animal = 'dog' | 'cat';
type AnimalObject = { [V in Animal]: () => V };
// AnimalObject = {
//    dog: () => 'dog',
//    cat: () => 'cat',
// }
```

## keyofとMapped types組み合わせる
このMapped typesは、`keyof`と組み合わせることでオブジェクトの型それぞれに対して特定の処理を噛ませることができるようになります。

```ts
type User = {
  id: string;
  age: number;
  name: string;
}

type UserProps = keyof User;
// UserProps = 'id' | 'age' | 'name'

type UserReadonly = { readonly [P in UserProps]: User[P] };
// type UserReadonly = {
//   readonly id: string;
//   readonly age: number;
//   readonly name: string;
// }
```

これはUtility Typesの`Readonly<T>`がやっていることと同じですね。
`Partial<T>`や`Nullable<T>`など多くのUtility Typesが`in`と`keyof`を組み合わせて使っているように、これは覚えておくと非常に便利な書き方です。

## 結合した後バラす
さて、`|`で繋げられたそれぞれの型に対して特定の操作をしたいだけの場合はどうすれば良いでしょうか。
Mapped Typesを使うとそれぞれの型に対して操作ができます。
しかし結果は、1つのobjectとして結合されてしまいます。

```ts
type Animal = 'dog' | 'cat';
type AnimalObject = { [V in Animal]: () => V };
// AnimalObject = {
//    dog: () => 'dog',
//    cat: () => 'cat',
// }
```

そのため、Mapped Typesによって生成された結果を一段回掘ることで、元の次元に戻すことができます。

```ts
type AnimalFunctions = AnimalObject[Animal];
// type AnimalFunctions = () => 'dog' | () => 'cat';
```

これらを応用することで、様々な操作が可能となります。

## 回答

というわけで概要の問題については下記のように定義することができます。

```ts
type Obj = {
  foo: string;
  bar: number;
  baz: boolean;
}

type Obj2 = { [T in keyof Obj]: Record<T, Obj[T]> }[keyof Obj]
// Obj2 = { foo: string } | { bar: number } | { baz: boolean }
```

社内Slackで質問があったので、記事にしてみました。
[Python]Seleniumで動的に変化する属性をXPATH（またはCSSセレクタ）で指定する

スクレイピングをする際に属性が動的に変化する要素を指定する際のノウハウ。

#HTMLサンプル
```.html
<input id="sample_123456789">
```
このような要素を毎回指定したいケースはよくあると思いますがXPATHかCSSセレクタを使用すると動的に指定する事が出来ます。

#XPATHを使用する
```.py
element = driver.find_elements_by_xpath('//*[starts-with(@id,"sample_")]')
```

このように記述すると動的に指定する事が出来ます。

#CSSセレクタを使用する
```.py
element = driver.find_elements_by_css_selector("input[id^=sample_]")
element = driver.find_elements_by_css_selector("input[id*=sample_]")
```
CSSセレクタでも同様に指定出来るみたいです。

#参考リンク
[要素特定のテクニック](http://oss.infoscience.co.jp/seleniumhq/docs/appendix_locating_techniques.html)
[【Selenium】動的に変わるidの取得方法](https://www.dev-dev.net/entry/2018/10/14/204025)
[python selenium: iterate through radio buttons that have dynamic ids and select](https://stackoverrun.com/ja/q/11414207)
linuxでhost.docker.internalを使う 

# version 20.10.0以降（2021/02/02追記）

後述のissueのうち一つがリリースされたので記述が簡便になっています。

`docker-compose.override.yaml` に以下を記載

```yaml:docker-compose.override.yaml
version: "3.5" # docker-compose.yamlのバージョンと合わせる

services:
  app: # host.docker.internalを使用したいサービス名
    extra_hosts:
      - "host.docker.internal:host-gateway"
```


# version 20.10.0より古い場合

`docker-compose.override.yaml` に以下を記載

```yaml:docker-compose.override.yaml
version: "3.5" # docker-compose.yamlのバージョンと合わせる

services:
  app: # host.docker.internalを使用したいサービス名
    extra_hosts:
      - "host.docker.internal:172.101.0.1" # 下のsubnetの指定に合わせる

networks:
  default:
    driver: bridge
    ipam:
      config:
        - subnet: 172.101.0.0/16 # 他のnetworkと被らないように指定
```

# firewall設定

firewallが動いている場合は、上記subnetからのアクセスを許可する必要があるかもしれません。
firewalldのコマンド例を記載しておきます。

``` sh
sudo firewall-cmd --permanent --zone=trusted --add-source=172.101.0.0/16
```

# host.docker.internal

docker for Mac, docker for Windowsでサポートされている、コンテナからホストのネットワークにアクセスするための特殊なドメイン。
macが開発者の主流になっているので、気軽にプロジェクトで使われ、その度にlinuxユーザーは悩みを抱える。

[Support host.docker.internal DNS name to host](https://github.com/docker/for-linux/issues/264)
[Support host.docker.internal in dockerd on Linux](https://github.com/moby/moby/pull/40007)
[[RFD] add configuration option to add host.docker.internal by default](https://github.com/docker/cli/issues/2290)

これらのissueによって最終的にはlinuxでも `host.docker.internal` が使えるようになる予定ですが、リリースされるまでまだ少し掛かりそうなのでWorkaroundを記載しておきます。
というより、作業内容としては上述の通りなので、解説を書きます。

# docker-compose.override.yaml

このファイルはdocker-composeコマンドを実行した時に自動で読まれるので、レポジトリに含めたくない自分専用の設定などを書く際に重宝します。
ただし、-fオプションを使用する際は自動では読まれないので、その際にはこのファイルも一緒に指定する必要があります。

# [extra_hosts](https://docs.docker.com/compose/compose-file/#extra_hosts)

コンテナの `/etc/hosts` に内容を追記します。

# networks

全てのコンテナは特に設定をしなければdefaultという名前のnetworkに属するので、defaultという名前のネットワークに設定を書けば全てのコンテナに自動で反映されます。
ここで設定しているのは、default networkのCIDRです。普通であればnetworkのCIDRは、既存のnetworkと被らないように自動で選ばれますが、今回は固定したいため手動で設定します。
dockerホストは全てのdocker networkに自動的に追加され、そのIPは「CIDRのLSBを1にしたもの」になるようです。（実際に試してそうっぽいと言うだけでドキュメントにそういう記載を見つけたわけではないので、もしかしたらそうならないケースもあるかもしれません。）
なので、このIPをextra_hostsに指定すればドメインを割り当てられるというわけです。
競技プログラミング練習記 No.22【ABC146-D練習】

初回 -> [はじめに](https://qiita.com/easychoco/items/a9ae28aca97cfe47091f)

[ABC146 - D : Coloring Edges on Tree](https://atcoder.jp/contests/abc146/tasks/abc146_d)を解きました。
前は難しくて解けなかった問題です。

|問題|時間|アルゴリズム|実行時間
|:-:|:-:|:-:|:-:|
| D | 75min |深さ優先探索|115ms|

----

ABC146のA-C問題はこちら
→[競技プログラミング練習記 No.11【ABC146練習】](https://qiita.com/easychoco/items/429b49c9bf12613ca1fb)

## D - Coloring Edges on Tree


``` c++
using P = pair<int, int>;

bool visited[200005];
int max_color = 0;
vector<int> ans(200005, 0);
vector< vector<int> > edge(200005, vector<int>());
map< P, int > edges_pair;

void dfs(int now, int parent_color)
{
	if (visited[now]) return;
	visited[now] = true;

	int color = (parent_color + 1) % max_color;
	for(const auto& next : edge[now])
	{
		if (visited[next]) continue;
		P p = ((now < next) ? P(now, next) : P(next, now));
		ans[edges_pair[p]] = color + 1;
		dfs(next, color);
		color = (color + 1) % max_color;
	}
}

void solve()
{
	fill(visited, visited + 200005, false);
	int n, a ,b;
	cin >> n;

	for(int i = 0; i < n - 1; ++i)
	{
		cin >> a >> b;
		a--; b--;
		edge[a].emplace_back(b);
		edge[b].emplace_back(a);
		if (a > b) swap(a, b);
		edges_pair[P(a, b)] = i;
	}

	for(const auto& e : edge)
	{
		max_color = max(max_color, (int)e.size());
	}
	cout << max_color << endl;

	dfs(0, max_color - 1);
	for(int i = 0; i < n - 1; ++i)
	{
		cout << ans[i] << endl;
	}
}
```

使用する色については誘導問題みたいなものです。
頂点の最大次数がそのまま色の種類になりますね。

木について、頂点ではなく枝を探索します。BFSでもDFSでもいいのですが、今回はDFSを使いました。
DFSをしながら、親の方向にある枝とは違う色で自分を塗ります。

今回は時間との戦いでした。
`dfs()` 内の
`P p = ((now < next) ? P(now, next) : P(next, now));`
`ans[edges_pair[p]] = color + 1;`
で、枝から入力時の枝番号へ変換しているのですが、初めは`vector`の`find`を使っていました。
`vector`の`find`は`O(N)`かかります。それでやられました。
プログラムにあるように、`map`を使えば`O(log N)`で変換でき、時間も間に合いました。

ちなみに、`map`は[平衡二分探索木](https://www.google.com/search?q=%E5%B9%B3%E8%A1%A1%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%E6%9C%A8&oq=%E5%B9%B3%E8%A1%A1%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%E6%9C%A8)です。
要素のアクセス・要素の検索・要素の挿入・要素の削除がどれも`O(log N)`で実行されます。
`vector`の場合はアクセスが`O(1)`で非常に高速ですが、要素の検索に`O(N)`かかり非常に低速です。

今回は過去に解けていなかった問題を解きました。
[ABC170-E : Smart Infants](https://atcoder.jp/contests/abc170/tasks/abc170_e) が似た問題で解けていないので、次はこれを解きたいですね。

以上です。ありがとうございました。
[Python]BeautifulSoupで属性を前方一致検索で指定して要素を取得する

スクレイピングする際に属性の値が動的になっている要素を取得する際に少しハマったので共有。

#HTMLサンプル
```.html
<div class="hogehoge">
    <input type="hidden" id="sample_1" value="fugafuga">
    <input type="hidden" id="sample_2" value="fugafuga">
    <input type="hidden" id="sample_3" value="fugafuga">
    <input type="hidden" id="sample_4" value="fugafuga">
    <input type="hidden" id="sample_5" value="fugafuga">
    ・
    ・
    ・
</div>
```

このような形で要素数が不定で属性の値が動的になっている要素を取得したいとする。

#取得方法
**・lambda関数ver**

```.py
source = soup.find_all('input', id=lambda value: value and value.startswith('sample_'))
```
lambda関数を使用して前方一致検索で要素を取得出来る。

**・正規表現ver**

```.py
source = soup.find_all('input', id=re.compile('^sample_'))
```
正規表現で取得も可能。

**・CSSセレクタver**

```.py
source = soup.select('input[id^=sample_]')
```
CSSセレクタで指定する事も可能。

#参考リンク
[How to find all divs who's class starts with a string in BeautifulSoup?](https://stackoverflow.com/questions/35465182/how-to-find-all-divs-whos-class-starts-with-a-string-in-beautifulsoup)
Spotifyで再生した曲を、再生回数順に並べる

# はじめに
普段Spotifyで音楽を聞いていて、再生回数順に並べたいな〜と思うときがあるのですが、再生回数自体アプリでは見られないんですよね。

その代わりに、SpotifyのPC版サイト(https://www.spotify.com/jp/)
で、JSON形式のデータとして、視聴履歴などをダウンロードすることができます。

そこで、自分のデータをダウンロードして、Pythonでカウントして表示してみました。

**ダウンロードの手順**
プロフィール > プライバシー設定 > お客様のデータのダウンロードからボタンをクリック。
メールでダウンロードリンクが送られてきます。最長30日かかるらしいので、気長に待ちましょう。

標準ライブラリしか使ってないので、プログラミング分からない人でもPCにPythonさえ入っていれば、コピペして実行すれば使えると思います。

自分用に書いたので、動かなかったらすみません。


# コード
```count.py
import json
import collections

# jsonデータの読み込み
# file_pathには、自分のStreamingHistoryファイルを指定してください。
with open('file_path') as f:
    d = json.load(f)

list = []

print("全体検索しますか？ y/n")
search_all = str(input())

print("何回以上を表示しますか？")
count = int(input())

# 曲名の取り出し&リストに追加
# 全体検索の場合
if search_all == "y":
    for i in d:
        list.append(i['trackName'])
# 指定検索の場合
elif search_all == "n":
    print("アーティストを入力してください")
    artist = str(input())
    for i in d:
        if(i['artistName'] == artist):
            list.append(i['trackName'])

# 出現回数順に要素を取得
c = collections.Counter(list)
c_list = c.most_common()

print("------------")
print("曲名, 再生回数")

# 再生回数が一定以上のものを表示する
for i in c_list:
    if i[1] >= count:
        print(i)

```

# 表示結果
![スクリーンショット 2020-06-24 18.24.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206282/411285e7-3373-a0ab-9b07-4b2b4d8a0bb9.png)

Pythonはさくっと色々できて便利ですね。
【Blueprism】Excelの行を範囲指定してコレクションに格納する方法

# はじめに
オブジェクト「MS Excel VBO」には指定したセルの範囲に入力されている値をコレクションに格納する
「Get Worksheet Range As Collection」アクションがあらかじめ備わっています。
別のシートへ転記する際に便利です。

# １列のみ範囲に指定する場合
列方向のみを取得する場合は、赤く囲んだ部分のように取得開始と終了のセル位置を指定する事で取得が可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/660650/8896a373-4da3-738e-1bce-42e819513c18.png)


このシートから
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/660650/ff0dd85e-9c38-543f-c7b0-792632b23325.png)


指定した範囲でコレクションに格納する事が出来ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/660650/1f1b2d1a-3aad-ea5a-e6c4-bf8627fe5b01.png)


# 複数列を範囲に指定する場合
行方向も取得範囲に指定する場合は下記のように指定する必要があります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/660650/50c81c51-d732-a4c5-72fc-fa02e8569c6b.png)


1行で複数の列を選択して値を移動させる際に表示されるこの部分ですね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/660650/b5e1de3b-6d30-f718-bdda-6b48fe8437dc.png)


これで実行すると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/660650/b1e6291d-f5e5-89c7-2cb1-80fd78bb5da3.png)

このように複数列の指定してコレクションへの格納が可能になります！

# １行だけ範囲に指定する場合
逆に、１行だけ取得したい場合は取得開始と終了の範囲指定を同じにすると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/660650/fa7a5d03-2be0-4c1a-b641-8a4b3c6baa46.png)


このように１行だけ取得ができます！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/660650/009f988c-793c-4727-8ce7-c3f0e2aac700.png)
RustでtomlファイルをstructにDeserialzeする

# やりたかったこと
tomlファイルの内容を、structに追加したかった

# Cargo.toml
```toml
[dependencies]
toml = "0.5.6"
serde_derive = "1.0.113"
```

# 読み込むtoml
```toml
# ./config/local.toml
[mongo_db]
name = "hoge"
age = 120
```

# 実装

### ※コメントで頂いたコードのほうがいいので、そちらの方を参照してください！！

```rust
#[derive(Debug, Deserialize)]
pub struct Config {
    pub mongo_db: MongoDb,
}

// 適当なsturctなのでごめんなさい
#[derive(Debug, Deserialize)]
pub struct MongoDb {
    pub name: String,
    pub age: i32,
}

fn main() {
    let config = toml::deserial_toml_file::<Config>("./config/local.toml", &mut String::from(""))?;
    println!("config is {:?}", config);
}

// deserial_toml_file tomlのfileをstructにdeserializeする
pub fn deserial_toml_file<'a, T>(path: &'a str, file_str: &'a mut String) -> Result<T>
where
    T: Deserialize<'a>,
{
    *file_str = file::read_file(path)?;

    let obj = toml::from_str::<T>(file_str)?;

    Ok(obj)
}

```

# 感想

ジェネリクスで実装したらlifetimeのerrorが発生したため、  
file_strを無理やり引数に書きました、  
もっといい方法があればコメントもらいたいです...
Katacoda で Docker, Kubernetes, Ansible を体験

インフラとアプリケーションの境目がなくなってきつつあります。
新しい技術は過去の経験とのすり合わせができにくかったりして、本を読んでもイメージがつきにくいことがあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/2fbc7906-8a5b-92c6-da45-9235e7a87848.png)

どこから手をつけようか、そんなときに Katacoda が役にたちそうです。

Katacodaは様々なITテクノロジーをブラウザのハンズオン形式で学ぶことがができるツールです。わざわざ環境を準備しなくていいので、どこから手を付けたらいいかわからないときにお勧めです。

https://www.katacoda.com/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/138338f5-9e28-70a6-2084-1a94c39a99ef.png)

#Docker
Dockerについては数多くのコースが用意されていて、準備された環境の中でハードルが低い状態で学習することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/287b549e-3173-419c-e940-929f8425e074.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/87a40b6e-b148-ece3-7e07-cff99f2f9eb5.png)

終了したら褒めて貰えるのも嬉しいです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/a0f537db-ae3d-0f42-75e8-e1629b1c7535.png)

#Kubernetes
Kubernetesについても多くのコースが用意されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/7444c21d-8d95-8c05-c47c-06e11c3591c6.png)

コースの概要と難易度、所要時間が示されていたりするので、どれを選べばいいか迷わずにすみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/bfe6501e-8aa0-b754-8257-3f76751af7d5.png)

#Ansible
Ansibleについても現時点では公式のものが9コース用意されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/2ce52db8-0b38-c206-38d8-f60fc772f2cb.png)

ビギナー向けの15分コース Ansible Review をやってみましょう。
１度目で全てを理解できないにしても、経験できる環境があるということは有難いです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/3c3a439c-ca2b-542c-737c-e415f377028e.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/31a00482-54e6-2281-221d-9a695d60e106.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/9c83886e-38ac-aeac-3c3a-af6c5577f1dd.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/44ed2777-77a7-dcb0-bd0b-49363e6896d0.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/0c53bb13-fefb-1d21-bfc9-d4947d91f12c.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/43329cf8-e122-4539-7b51-7985dd64c22a.png)
[Python]BeautifulSoupでname属性を指定して要素を取得する

BeautifulSoupでhtml要素を取得する際にname属性を指定したい時のお話。

#基本的なfind
```.py
# 取得例
source = soup.find('div', class_='hogehoge')
```

基本はこのような形でsoup.find('タグ名', 属性名='値')と指定して取得する。
ですが、name属性でこの記述をするとエラーになる。

```.py
# 取得例
source = soup.find('input', name='hogehoge', type='hidden')
```

```:実行結果
TypeError: find() got multiple values for keyword argument 'name'
```

これはBeautifulSoupのfindメソッド内で既にnameという引数を定義している為エラーとなるらしい。

#name属性を指定する際の記述

```.py
source = soup.find('input', attrs={'name': 'hogehoge', 'type': 'hidden'})
```

attrsという引数に辞書型で値を渡してあげるとname属性を指定する事が出来るみたいなのでこれで指定する。

```.py
source = soup.find('input', {'name': 'hogehoge', 'type': 'hidden'})
```
引数を省略しても同じ結果が得られるので好きな方を選びましょう。

#参考リンク
[Parameters for find function](https://stackoverflow.com/questions/2877114/parameters-for-find-function)
[Python：BeautifulSoup-名前属性に基づいて属性値を取得します](https://www.it-swarm.dev/ja/python/python%EF%BC%9Abeautifulsoup%E5%90%8D%E5%89%8D%E5%B1%9E%E6%80%A7%E3%81%AB%E5%9F%BA%E3%81%A5%E3%81%84%E3%81%A6%E5%B1%9E%E6%80%A7%E5%80%A4%E3%82%92%E5%8F%96%E5%BE%97%E3%81%97%E3%81%BE%E3%81%99/1068412706/)